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