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     *  ======== Ipc.xdc ========
    34     *
    35     *! Revision History
    36     *! ================
    37     *! 23-Jul-2010 jv      Fix 68467: Need detach() to handshake with remote core
    38     *! 19-May-2010 jv      Fix 67183: Ipc_attach should cleanly fail. Add ROV view.
    39     *!                     Fix 66692: Add getEntry() and setEntry().
    40     *! 22-Mar-2010 jv      Added Ipc.generateSlaveDataForHost.
    41     *! 19-Mar-2010 skp     Added Ipc_dummy
    42     *! 18-Mar-2010 skp     cdoc cleanup
    43     *! 12-Mar-2010 jv      hostProcId needs to be settable.
    44     *! 11-Sep-2009 skp     getObjTypeStr$view added
    45     *! 22-May-2009 skp     added GateSpinLock code; updated cdoc
    46     *! 29-Jan-2009 jv      added SharedRegion codes
    47     *! 15-Jan-2009 skp     added GatePeterson codes
    48     *! 13-Jan-2009 jv      created
    49     *!
    50     */
    51     
    52    import xdc.runtime.Error;
    53    import xdc.runtime.Assert;
    54    import xdc.rov.ViewInfo;
    55    import ti.sdo.utils.MultiProc;
    56    
    57    /*!
    58     *  ======== Ipc ========
    59     *  IPC Master Manager
    60     * 
    61     *  @p(html)
    62     *  This module has a common header that can be found in the {@link ti.ipc}
    63     *  package.  Application code should include the common header file (not the 
    64     *  RTSC-generated one):
    65     *
    66     *  <PRE>#include &lt;ti/ipc/Ipc.h&gt;</PRE>
    67     *   
    68     *  The RTSC module must be used in the application's RTSC configuration file 
    69     *  (.cfg):
    70     *  
    71     *  <PRE>Ipc = xdc.useModule('ti.sdo.ipc.Ipc');</PRE>
    72     *
    73     *  Documentation for all runtime APIs, instance configuration parameters, 
    74     *  error codes macros and type definitions available to the application 
    75     *  integrator can be found in the 
    76     *  <A HREF="../../../../doxygen/html/files.html">Doxygen documenation</A>
    77     *  for the IPC product.  However, the documentation presented on this page 
    78     *  should be referred to for information specific to the RTSC module, such as
    79     *  module configuration, Errors, and Asserts.
    80     *  @p
    81     *
    82     *  The most common static configuration that is required of the Ipc module
    83     *  is the {@link #procSync} configuration that affects the behavior of the
    84     *  Ipc_start and Ipc_attach runtime APIs.
    85     * 
    86     *  Additionally, certain subsystems of IPC (such as Notify and MessageQ) can
    87     *  be disabled to save resources on a per-connection basis by configuring Ipc
    88     *  using {@link #setEntryMeta}.
    89     *  
    90     */
    91    
    92    @Template ("./Ipc.xdt")
    93    module Ipc
    94    {
    95        /*!
    96         *  ======== ModuleView ========
    97         *  @_nodoc
    98         */
    99        metaonly struct ModuleView {
   100            UInt16  remoteProcId;
   101            Bool    attached;
   102            Bool    setupNotify;
   103            Bool    setupMessageQ;
   104        };
   105        
   106        /*!
   107         *  ======== rovViewInfo ========
   108         *  @_nodoc
   109         */
   110        @Facet
   111        metaonly config xdc.rov.ViewInfo.Instance rovViewInfo = 
   112            xdc.rov.ViewInfo.create({
   113                viewMap: [
   114                    ['Module',
   115                        {
   116                            type: xdc.rov.ViewInfo.MODULE_DATA,
   117                            viewInitFxn: 'viewInitModule',
   118                            structName: 'ModuleView'
   119                        }
   120                    ],
   121                ]
   122            });
   123            
   124        /*!     
   125         *  Various configuration options for {@link #procSync}
   126         *  
   127         *  The values in this enum affect the behavior of the Ipc_start and
   128         *  Ipc_attach runtime APIs. 
   129         * 
   130         *  ProcSync_ALL:  Calling Ipc_start will also internally Ipc_attach to 
   131         *  each remote processor.  The application should never call Ipc_attach.
   132         *  This type of startup and synchronization should be used if all IPC
   133         *  processors on a device start up at the same time and connections should 
   134         *  be established between every possible pair of processors.
   135         *  
   136         *  ProcSync_PAIR (default):  Calling Ipc_start will perform system-wide IPC
   137         *  initialization required on all processor, but connections to remote 
   138         *  processors will not be established (i.e. Ipc_attach will never be 
   139         *  called).  This configuration should be chosen if synchronization is
   140         *  required and some/all these conditions are true:
   141         *  @p(blist)
   142         *  - It is necessary to control when synchronization with each remote
   143         *    processor occurs
   144         *  - Useful work can be done while trying to synchronize with a remote
   145         *    processor by yielding a thread after each attempt to Ipc_attach
   146         *    to the processor.
   147         *  - Connections to all remote processors are unnecessary and connections
   148         *    should selectively be made to save memory
   149         *  @p
   150         *  NOTE: A connection should be made to the owner of region 0 (usually the
   151         *  processor with id = 0) before any connection to any other remote 
   152         *  processor can be made. For example, if there are three processors 
   153         *  configured with MultiProc, #1 should attach to #0 before it can attach
   154         *  to #2.
   155         *
   156         *  ProcSync_NONE:  This should be selected with caution.  Ipc_start will 
   157         *  work exactly as it does with ProcSync_PAIR.  However, Ipc_attach will
   158         *  not synchronize with the remote processor.  Callers of Ipc_attach are
   159         *  bound by the same restrictions imposed by using ProcSync_PAIR. 
   160         *  Additionally, an Ipc_attach to a remote processor whose id is less than
   161         *  our own has to occur *after* the corresponding remote processor has 
   162         *  called attach to the original processor.  For example, processor #2
   163         *  can call 
   164         *  @p(code)
   165         *  Ipc_attach(1); 
   166         *  @p
   167         *  only after processor #1 has called:
   168         *  @p(code)
   169         *  Ipc_attach(2); 
   170         *  @p
   171         *
   172         */
   173        enum ProcSync {
   174            ProcSync_NONE,          /*! ProcSync_PAIR with no synchronization   */
   175            ProcSync_PAIR,          /*! Ipc_start does not Ipc_attach           */
   176            ProcSync_ALL            /*! Ipc_start attach to all remote procs    */
   177        };
   178    
   179        /*!
   180         *  Struct used for configuration via {@link #setEntryMeta}
   181         * 
   182         *  This structure defines the fields that are to be configured
   183         *  between the executing processor and a remote processor.
   184         */
   185        struct Entry {
   186            UInt16 remoteProcId;    /*! Remote processor id                     */
   187            Bool   setupNotify;     /*! Whether to setup Notify                 */
   188            Bool   setupMessageQ;   /*! Whether to setup MessageQ               */
   189        };
   190    
   191        /*! struct for attach/detach plugs. */
   192        struct UserFxn {
   193            Int (*attach)(UArg, UInt16);
   194            Int (*detach)(UArg, UInt16);
   195        };
   196    
   197        /*
   198         *************************************************************************
   199         *                       Generic IPC Errors/Asserts
   200         *************************************************************************
   201         */
   202        
   203        /*!
   204         *  ======== A_addrNotInSharedRegion ========
   205         *  Assert raised when an address lies outside all known shared regions
   206         */
   207        config Assert.Id A_addrNotInSharedRegion  = {
   208            msg: "A_addrNotInSharedRegion: Address not in any shared region"
   209        };
   210    
   211        /*!
   212         *  ======== A_addrNotCacheAligned ========
   213         *  Assert raised when an address is not cache-aligned
   214         */
   215        config Assert.Id A_addrNotCacheAligned  = {
   216            msg: "A_addrNotCacheAligned: Address is not cache aligned"
   217        };
   218    
   219        /*!
   220         *  ======== A_nullArgument ========
   221         *  Assert raised when a required argument is null
   222         */
   223        config Assert.Id A_nullArgument  = {
   224            msg: "A_nullArgument: Required argument is null"
   225        };
   226    
   227        /*!
   228         *  ======== A_nullPointer ========
   229         *  Assert raised when a pointer is null
   230         */
   231        config Assert.Id A_nullPointer  = {
   232            msg: "A_nullPointer: Pointer is null"
   233        };
   234    
   235        /*!
   236         *  ======== A_invArgument ========
   237         *  Assert raised when an argument is invalid
   238         */
   239        config Assert.Id A_invArgument  = {
   240            msg: "A_invArgument: Invalid argument supplied"
   241        };
   242        
   243        /*!
   244         *  ======== A_invParam ========
   245         *  Assert raised when a parameter is invalid
   246         */
   247        config Assert.Id A_invParam  = {
   248            msg: "A_invParam: Invalid configuration parameter supplied"
   249        };
   250    
   251        /*!
   252         *  ======== A_internal ========
   253         *  Assert raised when an internal error is encountered
   254         */
   255        config Assert.Id A_internal = {
   256            msg: "A_internal: An internal error has occurred"
   257        };
   258    
   259        /*!
   260         *  ======== E_nameFailed ========
   261         *  Error raised when a name failed to be added to the NameServer
   262         * 
   263         *  Error raised in a create call when a name fails to be added
   264         *  to the NameServer table.  This can be because the name already
   265         *  exists, the table has reached its max length, or out of memory.
   266         */
   267        config Error.Id E_nameFailed  = {
   268            msg: "E_nameFailed: '%s' name failed to be added to NameServer"
   269        };
   270    
   271        /*!
   272         *  ======== E_internal ========
   273         *  Error raised when an internal error occured
   274         */
   275        config Error.Id E_internal  = {
   276            msg: "E_internal: An internal error occurred"
   277        };
   278    
   279        /*!
   280         *  ======== E_versionMismatch ========
   281         *  Error raised when a version mismatch occurs
   282         * 
   283         *  Error raised in an open call because there is
   284         *  a version mismatch between the opener and the creator
   285         */
   286        config Error.Id E_versionMismatch  = {
   287            msg: "E_versionMismatch: IPC Module version mismatch: creator: %d, opener: %d"
   288        };
   289    
   290        /*
   291         *************************************************************************
   292         *                       Module-wide Config Parameters
   293         *************************************************************************
   294         */
   295    
   296        /*!
   297         *  ======== sr0MemorySetup ========
   298         *  Whether Shared Region 0 memory is accessible
   299         * 
   300         *  Certain devices have a slave MMU that needs to be configured by the
   301         *  host core before the slave core can access shared region 0.  If
   302         *  the host core is also running BIOS, it is necessary to set this 
   303         *  configuration to 'true', otherwise {@link #start} will always fail.
   304         *
   305         *  This configuration should not be used for devices that don't have 
   306         *  a slave MMU and don't run Linux.
   307         */
   308        metaonly config Bool sr0MemorySetup;
   309        
   310        /*! @_nodoc
   311         *  ======== hostProcId ========
   312         *  Host processor identifier.
   313         *  
   314         *  Used to specify the host processor's id.  This parameter is only used 
   315         *  in a Syslink system.
   316         */
   317        metaonly config UInt16 hostProcId = MultiProc.INVALIDID;
   318    
   319        /*!
   320         *  ======== procSync ========
   321         *  Affects how Ipc_start and Ipc_attach behave
   322         *
   323         *  Refer to the documentation for the {@link #ProcSync} enum for 
   324         *  information about the various ProcSync options.
   325         */
   326        config ProcSync procSync = Ipc.ProcSync_PAIR;
   327    
   328        /*! @_nodoc
   329         *  ======== generateSlaveDataForHost ========
   330         *  generates the slave's data into a section for the host.
   331         */
   332        config Bool generateSlaveDataForHost;
   333    
   334        /*!@_nodoc
   335         *  ======== userFxn ========
   336         *  Attach and Detach hooks.
   337         */
   338        config UserFxn userFxn;
   339    
   340        /*
   341         *************************************************************************
   342         *                       IPC Functions
   343         *************************************************************************
   344         */
   345    
   346         /*!
   347         *  ======== addUserFxn ========
   348         *  Add a function that gets called during Ipc_attach/detach.
   349         *
   350         *  The user added functions must be non-blocking and must run
   351         *  to completion. The functions need to check to make sure it
   352         *  is not called multiple times when more than one thread calls
   353         *  Ipc_attach() for the same processor.  It is safe to use IPC
   354         *  APIs in a user function as long as the IPC APIs satisfy these
   355         *  requirements.
   356         *
   357         *  @p(code)
   358         *      var Ipc = xdc.useModule('ti.sdo.ipc.Ipc');
   359         *      var fxn = new Ipc.UserFxn;
   360         *      fxn.attach = '&userAttachFxn';
   361         *      fxn.detach = '&userDetachFxn';
   362         *      Ipc.addUserFxn(fxn, arg);
   363         *  @p
   364         *
   365         *  @param(fxn)     The user function to call during attach/detach.
   366         *  @param(arg)     The argument to the function.
   367         */
   368        metaonly Void addUserFxn(UserFxn fxn, UArg arg);
   369         
   370         /*!
   371         *  ======== getEntry ========
   372         *  Gets the properties for attaching to a remote processor.
   373         *
   374         *  This function must be called before Ipc_attach().  The
   375         *  parameter entry->remoteProcId field must be set prior to calling
   376         *  the function.
   377         *
   378         *  @param(entry)       Properties between a pair of processors.
   379         */
   380        Void getEntry(Entry *entry);
   381    
   382        /*!
   383         *  ======== setEntryMeta ========
   384         *  Statically sets the properties for attaching to a remote processor.
   385         *
   386         *  This function allows the user to configure whether Notify and/or
   387         *  MessageQ is setup during Ipc_attach().  If 'setupNotify' is set
   388         *  to 'false', neither the Notify or NameServerRemoteNotify instances
   389         *  are created.  If 'setupMessageQ' is set to 'false', the MessageQ
   390         *  transport instances are not created.  By default, both flags are
   391         *  set to 'true'.
   392         *
   393         *  Note: For any pair of processors, the flags must be the same
   394         *
   395         *  @param(entry)       Properties between a pair of processors.
   396         */
   397        metaonly Void setEntryMeta(Entry entry);
   398    
   399        /*!
   400         *  ======== setEntry ========
   401         *  Sets the properties for attaching to a remote processor.
   402         *
   403         *  This function must be called before Ipc_attach().  It allows
   404         *  the user to configure whether Notify and/or MessageQ is setup
   405         *  during Ipc_attach().  If 'setupNotify' is set to 'FALSE',
   406         *  neither the Notify or NameServerRemoteNotify instances are
   407         *  created.  If 'setupMessageQ' is set to 'FALSE', the MessageQ
   408         *  transport instances are not created.  By default, both flags are
   409         *  set to 'TRUE'.
   410         *
   411         *  Note: For any pair of processors, the flags must be the same
   412         *
   413         *  @param(entry)       Properties between a pair of processors.
   414         */
   415        Void setEntry(Entry *entry);
   416    
   417        /*! @_nodoc
   418         *  This is needed to prevent the Ipc module from being optimized away
   419         *  during the whole_program[_debug] partial link.
   420         */
   421        Void dummy();
   422    
   423    
   424    internal:    
   425        
   426        /* flag for starting processor synchronization */
   427        const UInt32 PROCSYNCSTART  = 1;
   428        
   429        /* flag for finishing processor synchronization */
   430        const UInt32 PROCSYNCFINISH = 2;
   431        
   432        /* flag for detaching */
   433        const UInt32 PROCSYNCDETACH = 3;
   434    
   435        /* Type of Ipc object. Each value needs to be a power of two. */
   436        enum ObjType {
   437            ObjType_CREATESTATIC            = 0x1,
   438            ObjType_CREATESTATIC_REGION     = 0x2,
   439            ObjType_CREATEDYNAMIC           = 0x4,  /* Created by sharedAddr      */
   440            ObjType_CREATEDYNAMIC_REGION    = 0x8,  /* Created by regionId        */
   441            ObjType_OPENDYNAMIC             = 0x10, /* Opened instance            */
   442            ObjType_LOCAL                   = 0x20  /* Local-only instance        */
   443        };
   444    
   445        /*
   446         *  This structure captures Configuration details of a module/instance
   447         *  written by a slave to synchornize with a remote slave/HOST
   448         */
   449        struct ConfigEntry {
   450            Bits32 remoteProcId;
   451            Bits32 localProcId;
   452            Bits32 tag;
   453            Bits32 size;
   454            Bits32 next;
   455        };
   456    
   457        /*!
   458         *  head of the config list 
   459         */
   460        struct ConfigHead {
   461            volatile Bits32 first;
   462        };    
   463    
   464        struct ProcEntry {
   465            Ptr    localConfigList;
   466            Ptr    remoteConfigList;
   467            UInt   attached;
   468            Entry  entry;
   469        };
   470    
   471        /* The structure used for reserving memory in SharedRegion */
   472        struct Reserved {
   473            volatile Bits32    startedKey;
   474            SharedRegion.SRPtr notifySRPtr;
   475            SharedRegion.SRPtr nsrnSRPtr;
   476            SharedRegion.SRPtr transportSRPtr;
   477            SharedRegion.SRPtr configListHead;
   478        };    
   479    
   480        /* The structure used for reserving memory in SharedRegion */
   481        struct UserFxnAndArg {
   482            UserFxn userFxn;
   483            UArg    arg;
   484        };
   485    
   486        /* Storage for setup of processors */
   487        metaonly config Entry entry[];
   488    
   489        config UInt numUserFxns = 0;
   490        
   491        /*!
   492         *  ======== userFxns ========
   493         *  Attach and Detach hooks.
   494         */
   495        config UserFxnAndArg userFxns[] = [];
   496    
   497        /*!
   498         *  ======== getMasterAddr() ========
   499         */
   500        Ptr getMasterAddr(UInt16 remoteProcId, Ptr sharedAddr);
   501        
   502        /*!
   503         *  ======== getRegion0ReservedSize ========
   504         *  Returns the amount of memory to be reserved for Ipc in SharedRegion 0.
   505         *
   506         *  This is used for synchronizing processors.
   507         */
   508        SizeT getRegion0ReservedSize();
   509        
   510        /*!
   511         *  ======== getSlaveAddr() ========
   512         */
   513        Ptr getSlaveAddr(UInt16 remoteProcId, Ptr sharedAddr);
   514    
   515        /*!
   516         *  ======== procSyncStart ========
   517         *  Starts the process of synchronizing processors.
   518         *
   519         *  Shared memory in region 0 will be used.  The processor which owns 
   520         *  SharedRegion 0 writes its reserve memory address in region 0
   521         *  to let the other processors know it has started.  It then spins
   522         *  until the other processors start.  The other processors write their
   523         *  reserve memory address in region 0 to let the owner processor
   524         *  know they've started.  The other processors then spin until the
   525         *  owner processor writes to let them know its finished the process
   526         *  of synchronization before continuing.
   527         */
   528        Int procSyncStart(UInt16 remoteProcId, Ptr sharedAddr);
   529    
   530        /*!
   531         *  ======== procSyncFinish ========
   532         *  Finishes the process of synchronizing processors.
   533         *
   534         *  Each processor writes its reserve memory address in SharedRegion 0
   535         *  to let the other processors know its finished the process of
   536         *  synchronization.     
   537         */
   538        Int procSyncFinish(UInt16 remoteProcId, Ptr sharedAddr);
   539    
   540        /*!
   541         *  ======== reservedSizePerProc ========
   542         *  The amount of memory required to be reserved per processor.
   543         */
   544        SizeT reservedSizePerProc();
   545        
   546        /*! Used for populated the 'objType' field in ROV views*/
   547        metaonly String getObjTypeStr$view(ObjType type);
   548    
   549        /* Module state */
   550        struct Module_State {
   551            Ptr       ipcSharedAddr;
   552            Ptr       gateMPSharedAddr;
   553            ProcEntry procEntry[];
   554        };
   555    }