1    /*
     2     * Copyright (c) 2012-2013, 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        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        struct ProcEntry {
   443            SharedRegion.SRPtr *localConfigList;
   444            SharedRegion.SRPtr *remoteConfigList;
   445            UInt   attached;
   446            Entry  entry;
   447        };
   448    
   449        /* The structure used for reserving memory in SharedRegion */
   450        struct Reserved {
   451            volatile Bits32    startedKey;
   452            SharedRegion.SRPtr notifySRPtr;
   453            SharedRegion.SRPtr nsrnSRPtr;
   454            SharedRegion.SRPtr transportSRPtr;
   455            SharedRegion.SRPtr configListHead;
   456        };
   457    
   458        /* The structure used for reserving memory in SharedRegion */
   459        struct UserFxnAndArg {
   460            UserFxn userFxn;
   461            UArg    arg;
   462        };
   463    
   464        /* Storage for setup of processors */
   465        metaonly config Entry entry[];
   466    
   467        config UInt numUserFxns = 0;
   468    
   469        /*!
   470         *  ======== userFxns ========
   471         *  Attach and Detach hooks.
   472         */
   473        config UserFxnAndArg userFxns[] = [];
   474    
   475        /*!
   476         *  ======== getMasterAddr() ========
   477         */
   478        Ptr getMasterAddr(UInt16 remoteProcId, Ptr sharedAddr);
   479    
   480        /*!
   481         *  ======== getRegion0ReservedSize ========
   482         *  Returns the amount of memory to be reserved for Ipc in SharedRegion 0.
   483         *
   484         *  This is used for synchronizing processors.
   485         */
   486        SizeT getRegion0ReservedSize();
   487    
   488        /*!
   489         *  ======== getSlaveAddr() ========
   490         */
   491        Ptr getSlaveAddr(UInt16 remoteProcId, Ptr sharedAddr);
   492    
   493        /*!
   494         *  ======== procSyncStart ========
   495         *  Starts the process of synchronizing processors.
   496         *
   497         *  Shared memory in region 0 will be used.  The processor which owns
   498         *  SharedRegion 0 writes its reserve memory address in region 0
   499         *  to let the other processors know it has started.  It then spins
   500         *  until the other processors start.  The other processors write their
   501         *  reserve memory address in region 0 to let the owner processor
   502         *  know they've started.  The other processors then spin until the
   503         *  owner processor writes to let them know its finished the process
   504         *  of synchronization before continuing.
   505         */
   506        Int procSyncStart(UInt16 remoteProcId, Ptr sharedAddr);
   507    
   508        /*!
   509         *  ======== procSyncFinish ========
   510         *  Finishes the process of synchronizing processors.
   511         *
   512         *  Each processor writes its reserve memory address in SharedRegion 0
   513         *  to let the other processors know its finished the process of
   514         *  synchronization.
   515         */
   516        Int procSyncFinish(UInt16 remoteProcId, Ptr sharedAddr);
   517    
   518        /*!
   519         *  ======== reservedSizePerProc ========
   520         *  The amount of memory required to be reserved per processor.
   521         */
   522        SizeT reservedSizePerProc();
   523    
   524        /*! Used for populated the 'objType' field in ROV views*/
   525        metaonly String getObjTypeStr$view(ObjType type);
   526    
   527        /* Module state */
   528        struct Module_State {
   529            Ptr       ipcSharedAddr;
   530            Ptr       gateMPSharedAddr;
   531            ProcEntry procEntry[];
   532        };
   533    }