1    /* --COPYRIGHT--,BSD
     2     * Copyright (c) $(CPYYEAR), Texas Instruments Incorporated
     3     * All rights reserved.
     4     *
     5     * Redistribution and use in source and binary forms, with or without
     6     * modification, are permitted provided that the following conditions
     7     * are met:
     8     *
     9     * *  Redistributions of source code must retain the above copyright
    10     *    notice, this list of conditions and the following disclaimer.
    11     *
    12     * *  Redistributions in binary form must reproduce the above copyright
    13     *    notice, this list of conditions and the following disclaimer in the
    14     *    documentation and/or other materials provided with the distribution.
    15     *
    16     * *  Neither the name of Texas Instruments Incorporated nor the names of
    17     *    its contributors may be used to endorse or promote products derived
    18     *    from this software without specific prior written permission.
    19     *
    20     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    23     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    27     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    28     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    29     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    30     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31     * --/COPYRIGHT--*/
    32    /*
    33     *  ======== Stream.xdc ========
    34     *
    35     *! Revision History
    36     *! ================
    37     *! 28-Apr-2008 nitya   review update
    38     */
    39    
    40    import xdc.rov.ViewInfo;
    41    
    42    import xdc.runtime.Error;
    43    import xdc.runtime.Assert;
    44    import xdc.runtime.IHeap;
    45    import xdc.runtime.IGateProvider;
    46    import ti.sdo.utils.List;
    47    import ti.sdo.utils.NameServer;
    48    import xdc.runtime.knl.Sync;
    49    import xdc.runtime.knl.ISync;
    50    
    51    /*!
    52     *  ======== Stream ========
    53     *
    54     *  Module to stream data to/from a driver.
    55     *
    56     *  This module offers both the issue/reclaim model and the read/write model to 
    57     *  send and receive data from drivers. 
    58     *
    59     *  In the issue/reclaim model, the client calls {@link #issue} when he has
    60     *  a buffer of data. issue() is non-blocking and returns. The buffer 
    61     *  has been issued for IO. To get the buffer back the client has to call 
    62     *  {@link #reclaim}. A call to reclaim() can block. Upon return from reclaim(),
    63     *  the client can re-use his buffer. 
    64     *
    65     *  The client can issue many buffers before reclaiming them.
    66     *  Buffers are always reclaimed in the order that they were issued.
    67     *  The client can optionally pass a user argument to issue().
    68     *
    69     *  In the read/write model, clients will call {@link #read} or {@link #write}
    70     *  to send/receive data. Here the client may block until buffer is ready or 
    71     *  a timeout occurs.
    72     *
    73     *  Stream also provides {@link #control} to send down driver specific control 
    74     *  commands. There is {@link #abort} function to abort the stream.
    75     *
    76     *  Stream also maintains a name table of {@link IConverter} handles. 
    77     *  This table is used by Stream to create an IO stack. The name passed to
    78     *  {@link #create} is usually of the form "/scale/uart". This name may
    79     *  correspond to the following IO stack.
    80     *
    81     *         Stream Instance
    82     *
    83     *                 |
    84    
    85     *                 V
    86     *
    87     *         IConverter Instance (/scale)
    88     *
    89     *                 |
    90     *
    91     *                 V
    92     *
    93     *         IDriver Instance (/uart)
    94     *
    95     *  In this case the Stream requires "/scale" to be in its IConverter table 
    96     *  and "/uart" to be in {@link DriverTable}. The IConverter table associates
    97     *  a name with an IConverter Handle. Note that these names have to be of the
    98     *  form "/name1".
    99     *
   100     *  This module uses {@link ti.sdo.utils.NameServer} to maintain its IConverter
   101     *  table
   102     *
   103     *  Stream uses the {@link xdc.runtime.knl.Sync} module for synchronization.
   104     *  Stream will call {@link xdc.runtime.knl.Sync#signal} when IO completes and
   105     *  {@link xdc.runtime.knl.Sync#wait} to wait for IO completion.
   106     *
   107     *  Stream will create a Sync.Handle passing NULL for ISync 
   108     *  handle to {@link #create}. 
   109     */
   110    
   111    @InstanceFinalize
   112    @InstanceInitError
   113    @ModuleStartup
   114    
   115    module Stream 
   116    {
   117        const UInt INPUT = 0;       /*! mode for input */
   118        const UInt OUTPUT = 1;      /*! mode for output */
   119        const UInt INOUT = 2;       /*! mode for input & output */
   120        
   121        /*! 
   122         *  Error raised when name not found in IConverter Table and DriverTable.
   123         */
   124        config Error.Id E_notFound  = {
   125            msg: "E_notFound: %s name not found"
   126        };
   127        
   128        /*! 
   129         *  Error raised when there are no packets for IO
   130         */
   131        config Error.Id E_noPackets  = {
   132            msg: "E_noPackets: No packets available. maxIssues is %d"
   133        };
   134    
   135        /*! 
   136         *  Error raised when reclaim called but no outstanding buffers issued
   137         *
   138         *  Clients can check for this error while calling {@link #reclaim} to make 
   139         *  sure they got all their buffers back.
   140         *  @p(code)
   141         *  #include <xdc/runtime/Error.h>
   142         *  #include <ti/sdo/io/Stream.h>
   143         *
   144         *  Error_Block eb;
   145         *  Stream_Handle streamHdl;
   146         *  SizeT len;
   147         *  Ptr *bufp;
   148         *  
   149         *  Error_init(&eb); 
   150         *  
   151         *  do {
   152         *      len = Stream_reclaim(streamHdl, bufp, NULL, &eb); 
   153         *  }while (!Error_check(&eb));
   154         *  
   155         *  if (Error_getId == Stream_E_noBuffersIssued) {
   156         *      ....all issues buffers have been reclaimed
   157         *  }
   158         *  @p
   159         *  
   160         */
   161        config Error.Id E_noBuffersIssued  = {
   162            msg: "E_noBuffersIssued: No outstanding buffers"
   163        };
   164    
   165        /*! 
   166         *  Error raised when a timeout occurs during reclaim
   167         */
   168        config Error.Id E_timeout  = {
   169            msg: "E_timeout: Timeout"
   170        };    
   171    
   172        /*! 
   173         *  Assert when {@link #read} or {@link #write} on wrong channel
   174         *
   175         *  Assert when {@link #read} is called and mode = {@link #OUTPUT} or
   176         *  when {@link #write} is called and mode = {@link #INPUT}
   177         */
   178        config Assert.Id A_badMode  = {
   179            msg: "A_badMode: Bad Mode"
   180        };
   181    
   182        /*! 
   183         *  Assert when there are more packets to be reclaimed
   184         */
   185        config Assert.Id A_pendingReclaims  = {
   186            msg: "A_pendingReclaims: Packets issued but not reclaimed"
   187        };
   188    
   189        /*! 
   190         *  Assert when ISync is non-blocking but Stream_read/write called
   191         */
   192        config Assert.Id A_syncNonBlocking  = {
   193            msg: "A_syncNonBlocking: ISync should have blocking quality"
   194        };
   195    
   196        /*! 
   197         *  Max entries that can be added at runtime
   198         *
   199         *  This module requires total number of converters that need
   200         *  to be added at runtime to be identified at configuration time.
   201         */
   202        config UInt maxRuntimeEntries = 0;
   203    
   204        /*! 
   205         *  For making the table thread safe.
   206         */
   207        config IGateProvider.Handle gate = null;
   208        
   209        /*! 
   210         *  Length, in MAUs, of the name field in the table.
   211         */
   212        config UInt maxNameLen = 16;
   213    
   214        /*! 
   215         *  Section name used to place the IConverter table.
   216         */
   217        metaonly config String tableSection = null;
   218        
   219        metaonly struct BasicView {
   220            String              label;
   221            UInt                maxIssues;
   222            UInt                issued;
   223            UInt                ready;
   224            String              mode;
   225            Bool                userSuppliedSync;
   226            //List.Object        abortList;      /* reclaimed abort packets */
   227        }
   228        
   229        @Facet
   230        metaonly config ViewInfo.Instance rovViewInfo = 
   231            ViewInfo.create({
   232                viewMap: [
   233                    ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}],
   234                ]
   235            });
   236    
   237        /*!
   238         *  ======== add ========
   239         *  Add to IConverter table at runtime.
   240         *
   241         *  This API is not thread safe. Set {@link #gate} parameter
   242         *  to protect table if called from multiple threads.
   243         *
   244         *  @param(name)    Name of entry
   245         *  @param(handle)  IConverter handle
   246         *  @param(eb)      Error Block
   247         */
   248        Void add(String name, IConverter.Handle handle,  Error.Block *eb);
   249    
   250        /*!
   251         *  ======== addMeta ========
   252         *  Add to IConverter table at configuration time.
   253         *
   254         *  @param(name)            name of entry
   255         *  @param(handle)          IConverter handle
   256         */
   257        metaonly Void addMeta(String name, IConverter.Handle handle);
   258    
   259        /*!
   260         *  ======== remove ========
   261         *  Remove entry from IConverter table at runtime.
   262         *
   263         *  This API is not thread safe. Set {@link #gate} parameter
   264         *  to protect table if called from multiple threads.
   265         *
   266         *  @param(name)    name of entry
   267         *  @param(eb)      error block
   268         */
   269        Void remove(String name, Error.Block *eb);
   270    
   271        /*! 
   272         * @_nodoc
   273         * Match a name to name in IConverter table. return length matched. 
   274         */
   275        Int match(String name, IConverter.Handle *handle, Error.Block *eb);    
   276    
   277        /*! 
   278         *  @_nodoc
   279         *  io completed log functions called by DriverAdapter 
   280         */
   281        Void completedLog(UArg buf, UArg size, UArg arg);
   282        
   283    instance:
   284    
   285        /*! Max outstanding issues */
   286        config UInt maxIssues = 2;
   287    
   288        /*!  Heap used to allocate {@link DriverTypes#Packet} in dynamic create */
   289        config IHeap.Handle packetHeap = null;
   290        
   291        /*!
   292         *  Section name used to place {@link DriverTypes#Packet}
   293         * 
   294         *  Default of null results in no explicit section placement.
   295         */
   296        metaonly config String packetSection = null;
   297    
   298        /*! ISync handle used to signal IO completion */
   299        config ISync.Handle sync = null;
   300    
   301        /*! Channel params for driver if present in IO stack */
   302        config UArg chanParams = null;
   303        
   304        /*!
   305         *  ======== create ========
   306         *  Create a Stream Instance.
   307         *
   308         *  Creates a new Stream instance and sets up the IO stack specified by 
   309         *  name.
   310         *  The name is usually of the following form "/scale/uart".
   311         *  The mode is either {@link #INPUT} or {@link #OUTPUT}.
   312         *
   313         *  @param(name)    name that identifies the IO stack
   314         *  @param(mode)    mode of channel.
   315         */
   316        create(String name, UInt mode);
   317    
   318        /*!
   319         *  ======== issue ========
   320         *  Issue a buffer to the stream.
   321         *
   322         *  This function issues a buffer to the stream for IO. This API is
   323         *  non-blocking.
   324         *
   325         *  Failure of issue() indicates that the stream was not able to accept the
   326         *  buffer being issued or that there was a error from the underlying
   327         *  IConverter or IDriver. Note that the error could be driver specific.
   328         *  If issue() fails because of an underlying driver problem
   329         *  {@link #abort} should be called before attempting more I/O through the 
   330         *  stream.
   331         *
   332         *  The interpretation of the logical size of a buffer, is 
   333         *  direction dependent.
   334         *  For a stream opened in {@link DriverTypes#OUTPUT} mode, the logical size
   335         *  of the buffer indicates the number of minimum addressable units of of 
   336         *  data it contains. 
   337         *
   338         *  For a stream opened in {@link DriverTypes#INPUT} mode, the logical size 
   339         *  of a buffer indicates the number of minimum addressable units being 
   340         *  requested by the client. In either case, the logical size of the buffer 
   341         *  must be less than or equal to the physical size of the buffer.
   342         *
   343         *  issue() is used in conjunction with {@link #reclaim}. The issue() call 
   344         *  sends a buffer to a stream, and reclaim() retrieves a buffer 
   345         *  from a stream. In normal operation each issue() call is followed by an 
   346         *  reclaim() call.
   347         *
   348         *  Short bursts of multiple issue() calls can be made without an
   349         *  intervening reclaim() call followed by short bursts of reclaim() calls, 
   350         *  but over the life of the stream issue() and reclaim() must be called 
   351         *  the same number of times. The number of issue() calls can exceed the 
   352         *  number of reclaim() calls by {@link #maxIssues}.
   353         *
   354         *  The client argument is not interpreted by Stream or the underlying 
   355         *  modules, but is offered as a service to the stream client. All compliant
   356         *  device drivers preserve the value of arg and maintain its association 
   357         *  with the data that it was issued with. arg provides a method for a 
   358         *  client to associate additional information with a particular buffer of 
   359         *  data. The arg is returned during reclaim().
   360         *
   361         *  @param(buf)    buffer pointer
   362         *  @param(size)    size of buffer
   363         *  @param(arg)     app arg
   364         *  @param(eb)      error block
   365         *  
   366         */
   367        Void issue(Ptr buf, SizeT size, UArg arg, Error.Block *eb);
   368    
   369        /*!
   370         *  ======== reclaim ========
   371         *  Reclaim a buffer that was previously issued by calling {@link #issue}.
   372         *
   373         *  reclaim() is used to request a buffer back from a stream. 
   374         *
   375         *  If a stream was created in {@link DriverTypes#OUTPUT} mode, then 
   376         *  reclaim() returns a processed buffer, and size is zero.
   377         *  If a stream was opened in {@link DriverTypes#INPUT} mode, reclaim() 
   378         *  returns a full buffer, and size is the number of minimum addressable 
   379         *  units of data in the buffer.
   380         *
   381         *  reclaim() blocks until a buffer can be returned to the caller, or until 
   382         *  a timeout occurs.
   383         *
   384         *  Failure of reclaim() indicates that no buffer was returned to 
   385         *  the  client. Therefore, if reclaim() fails, the client should 
   386         *  not attempt to de-reference pbufp, since it is not guaranteed to contain
   387         *  a valid buffer pointer.
   388         *
   389         *  reclaim() is used in conjunction with {@link #issue} to operate 
   390         *  a stream. The issue() call sends a buffer to a stream, and 
   391         *  reclaim() retrieves a  buffer from a stream. In normal operation
   392         *  each issue call is followed by an reclaim call.
   393         *
   394         *  Short bursts of multiple issue() calls can be made without an
   395         *  intervening reclaim() call followed by short bursts of reclaim() calls, 
   396         *  but over the life of the stream issue() and reclaim() must be called 
   397         *  the same number of times. The number of issue() calls can exceed the 
   398         *  number of reclaim() calls by {@link #maxIssues}.
   399         *
   400         *  A reclaim() call should not be made without at least one 
   401         *  outstanding issue() call. Calling reclaim() with no 
   402         *  outstanding issue() calls results in an error {@link #E_noBuffersIssued}
   403         *
   404         *  reclaim() only returns buffers that were passed in using issue(). It 
   405         *  also returns the buffers in the same order that they were issued.
   406         *
   407         *  reclaim() returns the size transferred in case of success.
   408         *  It returns zero when an error is caught. In case of timeout, the error 
   409         *  is {@link #E_timeout}.
   410         *
   411         *  @param(pbufp)       returned buffer pointer
   412         *  @param(timeout)     timeout in microseconds
   413         *  @param(parg)        pointer to client arg. Can be null.
   414         *  @param(eb)          error block
   415         *  @b(returns)         size transferred
   416         *  
   417         */
   418        SizeT reclaim(Ptr *pbufp, UInt timeout, UArg *parg, Error.Block *eb);
   419    
   420        /*!
   421         *  ======== read ========
   422         *  Read data from a stream.
   423         *
   424         *  Equivalent to an issue/reclaim pair for a instance with 
   425         *  mode = DriverTypes.INPUT. This call is synchronous and the buffer
   426         *  has data upon return from this API.
   427         *
   428         *  @param(bufp)        buffer pointer
   429         *  @param(size)        size of buffer
   430         *  @param(timeout)     timeout in microseconds
   431         *  @param(eb)          error block
   432         *  @b(returns)         size transferred
   433         */
   434        SizeT read (Ptr bufp, SizeT size, UInt timeout, Error.Block *eb);  
   435    
   436        /*!
   437         *  ======== write ========
   438         *  Write data to a stream
   439         *
   440         *  Equivalent to an issue/reclaim pair for a instance with 
   441         *  mode = DriverTypes.OUTPUT.
   442         *  This call is synchronous and the driver has finished processing the
   443         *  buffer upon return from this API.
   444         *
   445         *  @param(bufp)    buffer pointer
   446         *  @param(size)    size of buffer
   447         *  @param(timeout) timeout in microseconds
   448         *  @param(eb)      error block
   449         *  @b(returns)     size transferred
   450         */
   451        SizeT write (Ptr bufp, SizeT size, UInt timeout, Error.Block *eb);  
   452    
   453        /*!
   454         *  ======== submit ========
   455         *  @_nodoc
   456         *  Convenience API to send driver specific command.
   457         *
   458         *  Equivalent to an issue/reclaim pair for a instance with 
   459         *  driver specific command.
   460         *
   461         *  @param(bufp)    buffer pointer
   462         *  @param(size)    size of buffer
   463         *  @param(cmd)     driver specific packet command
   464         *  @param(timeout) timeout in microseconds
   465         *  @param(eb)      error block
   466         *  @b(returns)     size transferred
   467         */
   468        SizeT submit (Ptr bufp, SizeT size, DriverTypes.PacketCmd cmd, UInt timeout, Error.Block *eb); 
   469        
   470        /*!
   471         *  ======== control ========
   472         *  Send a control command to the driver.
   473         *
   474         *  @param(cmd)     device specific command
   475         *  @param(cmdArg)  command specific arg
   476         *  @param(eb)      error block
   477         */
   478        Void control(DriverTypes.ControlCmd cmd, UArg cmdArg, Error.Block *eb);
   479      
   480        /*!
   481         *  ======== abort ========
   482         *  Abort all pending IO.
   483         *
   484         *  The underlying device connected to stream is idled as a result of 
   485         *  calling abort and all buffers are ready for reclaim().
   486         *
   487         *  The client still needs to call {@link #reclaim} to get back his
   488         *  buffers. However the client will NOT block when calling reclaim()
   489         *  after an abort().
   490         *
   491         *  @param(eb)              error block
   492         *  @b(returns)             number of buffers aborted
   493         */
   494        UInt abort(Error.Block *eb);
   495    
   496        /*!
   497         *  ======== prime ========
   498         *  Prime an {@link #OUTPUT} stream instance.
   499         *
   500         *  This API facilitates buffering of an output channel. Consider a
   501         *  task that constantly gets data from input channel and sends to an 
   502         *  output channel. To start with it may want to issue buffers to the 
   503         *  input channel and output channel to enable double buffering.
   504         *  For an input channel there is no problem. For an output channel however
   505         *  the buffer data is sent out through the peripheral and in the case of a
   506         *  heterogenous system, the data will be sent to the other processor.
   507         *
   508         *  In such cases where the driver cannot handle dummy buffers, 
   509         *  Stream_prime can be used to make buffers available instantly for 
   510         *  reclaim without actually sending the buffers to the driver. 
   511         *  This API is non-blocking.
   512         *
   513         *  The primary use of prime() is used when applications want to prime
   514         *  an output channel at startup, without sending data to the driver.
   515         *  This allows them to reclaim and issue in their task.
   516         *  
   517         *  Failure of prime() indicates that the stream was not able to accept the
   518         *  buffer being issued  due to un-avaibailibity of IO packets.
   519         *
   520         *  The client argument is not interpreted by Stream.
   521         *
   522         *  @param(buf)     buffer pointer
   523         *  @param(arg)     app arg
   524         *  @param(eb)      error block
   525         */
   526        Void prime(Ptr buf, UArg arg, Error.Block *eb);
   527    
   528    internal:
   529    
   530        /*!
   531         *  Structure of entry in IConverter Table
   532         *
   533         *  @field(name)
   534         *  Name of table entry.
   535         *
   536         *  @field(handle)
   537         *  {@link IConverter#Handle} instance to be used in the IO stack
   538         *
   539         */
   540        struct Entry {
   541            String              name;
   542            IConverter.Handle   handle;
   543        };
   544        
   545        /*! 
   546         *  Array for all statically configured IConverter table entries 
   547         */
   548        metaonly config Entry staticEntries[];
   549            
   550        /*! callback for lower layer */
   551        Void internalCallback(UArg arg);
   552    
   553        /*! instance postInit */
   554        Int postInit(Object *obj, Error.Block *eb);
   555       
   556        /*! extension to pass down driver specific command */
   557        Void issueX(Object *obj, Ptr bufp, SizeT size, UArg arg, 
   558            DriverTypes.PacketCmd cmd, Error.Block *eb);
   559       
   560        /* -------- Internal Structures -------- */
   561        struct Instance_State {
   562            String              name;           /* name used to create inst */
   563            UArg                chanParams;     /* used to open IConverter */
   564            Bool                drvAdapHdl;     /* Created DriverAdapter */
   565            DriverTypes.Packet  packets[];      /* used only in static create */
   566            UInt                maxIssues;      /* used only in static create */
   567            UInt                issued;         /* # bufs issued */
   568            UInt                ready;          /* # bufs ready for reclaim */
   569            UInt                mode;           /* input or output */
   570            IHeap.Handle        packetHeap;     /* heap used to alloc packets */
   571            ISync.Handle        complete;       /* completion sync */
   572            Bool                userSync;       /* user supplied sync handle*/
   573            IConverter.Handle   convHandle;     /* handle to IConverter below */
   574            List.Object         freeList;       /* free packets */
   575        };
   576    
   577        /* -------- Internal Structures -------- */
   578        struct Module_State {
   579            NameServer.Handle   convTable;    /* IConverter table */
   580        };
   581    }