f1545cfa4dbc974011c76b1f08c26e234d2cde3f
[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / ipc / hlos / knl / Ipc.c
1 /*
2  *  Copyright (c) 2008-2013, Texas Instruments Incorporated
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions
6  *  are met:
7  *
8  *  *  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *  *  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *  *  Neither the name of Texas Instruments Incorporated nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
33 /*  ----------------------------------- Standard headers   */
34 #include <ti/syslink/Std.h>
36 /*  ----------------------------------- SysLink IPC module Headers   */
37 #include <ti/ipc/Ipc.h>
38 #include <_Ipc.h>
39 #include <IpcKnl.h>
40 #include <Platform.h>
41 #include <Bitops.h>
42 #include <RscTable.h>
43 #include <_MessageQCopy.h>
44 #include <ti/ipc/MessageQCopy.h>
46 /*  ----------------------------------- SysLink utils Headers   */
47 #include <ti/syslink/inc/_MultiProc.h>
48 #include <ti/ipc/MultiProc.h>
49 #include <ti/syslink/utils/Gate.h>
50 #include <ti/syslink/utils/Trace.h>
51 #include <ti/syslink/utils/Cache.h>
52 #include <ti/syslink/utils/Memory.h>
54 #if defined(SYSLINK_USE_IPU_PM)
55 #include <ipu_pm.h>
56 #endif
58 #if defined  (__cplusplus)
59 extern "C" {
60 #endif
63 /* =============================================================================
64  * Macros
65  * =============================================================================
66  */
67 /* Macro to make a correct module magic number with refCount */
68 #define Ipc_MAKE_MAGICSTAMP(x) ((SharedRegion_MODULEID << 16u) | (x))
71 /* =============================================================================
72  * Enums & Structures
73  * =============================================================================
74  */
76 /* The structure used for reserving memory in SharedRegion */
77 typedef struct Ipc_Reserved {
78     volatile Bits32    startedKey;
79 //    SharedRegion_SRPtr ipu_pm_sr_ptr; //Ramesh: Port from WinCe.
80 } Ipc_Reserved;
83 /*!
84  *  head of the config list
85  */
86 typedef struct Ipc_ConfigHead {
87     volatile Bits32 first;
88     /* Address of first config entry */
89 } Ipc_ConfigHead;
92 /*!
93  *   This structure captures Configuration details of a module/instance
94  *   written by a slave to synchornize with a remote slave/HOST
95  */
96 typedef struct Ipc_ConfigEntry {
97     volatile Bits32 remoteProcId;
98     /* Remote processor identifier */
99     volatile Bits32 localProcId;
100     /* Config Entry owner processor identifier */
101     volatile Bits32 tag;
102     /* Unique tag to distinguish config from other config entries */
103     volatile Bits32 size;
104     /* Size of the config pointer */
105     volatile Bits32 next;
106     /* Address of next config entry  (In SRPtr format) */
107 } Ipc_ConfigEntry;
109 /*
110  *  This structure defines the fields that are to be configured
111  *  between the executing processor and a remote processor.
112  */
113 typedef struct Ipc_Entry {
114     UInt16 remoteProcId;            /* the remote processor id   */
115     Bool    setup_ipu_pm;          //Ramesh: port from WinCE
116 } Ipc_Entry;
118 /*!
119  *   Ipc instance structure.
120  */
121 typedef struct Ipc_ProcEntry {
122     Ptr        localConfigList;
123     Ptr        remoteConfigList;
124     Ptr        userObj;
125     Bool       slave;
126     Ipc_Entry  entry;
127     Bool       isAttached;
128 } Ipc_ProcEntry;
131 /*!
132  *  Module state structure
133  */
134 typedef struct Ipc_Module_State {
135     Int32         refCount;
136     Ipc_Config    cfg;
137     Ipc_ProcEntry procEntry [MultiProc_MAXPROCESSORS];
138 } Ipc_Module_State;
141 /* =============================================================================
142  * Globals
143  * =============================================================================
144  */
145 static Ipc_Module_State Ipc_module_state = {
146                                              .refCount = 0,
147                                            };
148 static Ipc_Module_State * Ipc_module = &Ipc_module_state;
151 /* =============================================================================
152  * APIs
153  * =============================================================================
154  */
156 /* attaches to a remote processor */
157 Int Ipc_attach (UInt16 remoteProcId)
159     Int                     status = 0;
160     IArg                    key;
161     UInt32                  numVrings = 0;
162     UInt32                  vringAddr = 0;
163     ProcMgr_Handle          procHandle = NULL;
165     GT_1trace (curTrace, GT_ENTER, "Ipc_attach", remoteProcId);
167     GT_assert(curTrace,remoteProcId < MultiProc_INVALIDID);
168     GT_assert(curTrace,remoteProcId != MultiProc_self());
170     key = Gate_enterSystem ();
171    /* Make sure its not already attached */
172     if (Ipc_module->procEntry[remoteProcId].isAttached) {
173         Ipc_module->procEntry[remoteProcId].isAttached++;
174         Gate_leaveSystem (key);
175         status = Ipc_S_ALREADYSETUP;
176     }
177     else {
178         Gate_leaveSystem (key);
180         status = ProcMgr_open(&procHandle, remoteProcId);
181         if (status >= 0) {
182             status = RscTable_update(remoteProcId, procHandle);
183             if (status >= 0) {
184                 /* get IPC VRING information */
185                 status = RscTable_getInfo(remoteProcId, TYPE_VDEV, 0, NULL,
186                                           NULL,&numVrings);
187                 if (status >= 0) {
188                     status = RscTable_getInfo(remoteProcId, TYPE_VDEV, 1,
189                                               &vringAddr, NULL, NULL);
190                     if (status >= 0) {
191                         status = MessageQCopy_attach(remoteProcId,
192                                                      (Ptr)vringAddr, 0);
193                     }
194                 }
195             }
196             ProcMgr_close(&procHandle);
197         }
199 #if defined(SYSLINK_USE_IPU_PM)
200         if (status >= 0) {
201             status = ipu_pm_attach(remoteProcId);
202             if (status < 0) {
203                 MessageQCopy_detach(remoteProcId);
204             }
205         }
206 #endif
208         if (status >= 0) {
209             key = Gate_enterSystem ();
210             Ipc_module->procEntry[remoteProcId].isAttached++;
211             Gate_leaveSystem (key);
212         }
213     }
214     GT_1trace (curTrace, GT_LEAVE, "Ipc_attach", status);
216     return  (status);
220 /* detaches from a remote processor */
221 Int Ipc_detach (UInt16 remoteProcId)
223     Int                     status = 0;
224     IArg                    key;
225     GT_1trace (curTrace, GT_ENTER, "Ipc_detach", remoteProcId);
227     key = Gate_enterSystem ();
228     if (Ipc_module->procEntry[remoteProcId].isAttached > 1) {
229         /* Only detach if attach count reaches 1 */
230         Ipc_module->procEntry[remoteProcId].isAttached--;
231         Gate_leaveSystem (key);
232         status = Ipc_S_BUSY;
233     }
234     else if (Ipc_module->procEntry[remoteProcId].isAttached == 0) {
235         /* If already detached, then return fail */
236         Gate_leaveSystem (key);
237         status = Ipc_E_FAIL;
238     }
239     else {
240         Gate_leaveSystem (key);
242 #if defined(SYSLINK_USE_IPU_PM)
243         status = ipu_pm_detach (remoteProcId);
244 #endif
246         status = MessageQCopy_detach (remoteProcId);
248         key = Gate_enterSystem ();
249         Ipc_module->procEntry[remoteProcId].isAttached--;
250         Gate_leaveSystem (key);
251     }
253     GT_1trace (curTrace, GT_LEAVE, "Ipc_detach", status);
255     return  (status);
258 /*
259  *  ======== Ipc_getConfig ========
260  */
261 Void Ipc_getConfig (Ipc_Config * cfgParams)
263     IArg key;
265     GT_1trace (curTrace, GT_ENTER, "Ipc_getConfig", cfgParams);
267     GT_assert (curTrace, (cfgParams != NULL));
269 #if !defined(SYSLINK_BUILD_OPTIMIZE)
270     if (cfgParams == NULL) {
271         /* No retVal since this is a Void function. */
272         GT_setFailureReason (curTrace,
273                              GT_4CLASS,
274                              "Ipc_getConfig",
275                              Ipc_E_INVALIDARG,
276                              "Argument of type (Ipc_Config *) passed "
277                              "is null!");
278     }
279     else {
280 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
281         key = Gate_enterSystem ();
282         if (Ipc_module->refCount != 0) {
283             Memory_copy ((Ptr) cfgParams,
284                          (Ptr) &Ipc_module->cfg,
285                          sizeof (Ipc_Config));
286         }
287         Gate_leaveSystem (key);
288 #if !defined(SYSLINK_BUILD_OPTIMIZE)
289     }
290 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
292     GT_0trace (curTrace, GT_LEAVE, "Ipc_getConfig");
296 /* Sets up Ipc for this processor. */
297 Int Ipc_setup (const Ipc_Config * cfg)
299     Int             status = Ipc_S_SUCCESS;
300     Ipc_Config      tmpCfg;
301     IArg            key;
302     Int             i;
304     GT_1trace (curTrace, GT_ENTER, "Ipc_setup", cfg);
306     key = Gate_enterSystem ();
307     Ipc_module->refCount++;
309     /* This sets the refCount variable is not initialized, upper 16 bits is
310      * written with module Id to ensure correctness of refCount variable.
311      */
312     if (Ipc_module->refCount > 1) {
313         status = Ipc_S_ALREADYSETUP;
314         GT_0trace (curTrace,
315                    GT_2CLASS,
316                    "Ipc Module already initialized!");
317         Gate_leaveSystem (key);
318     }
319     else {
320         Gate_leaveSystem (key);
321         if (cfg == NULL) {
322             Ipc_getConfig (&tmpCfg);
323             cfg = &tmpCfg;
324         }
326         /* Copy the cfg */
327         Memory_copy ((Ptr) &Ipc_module->cfg,
328                      (Ptr) cfg,
329                      sizeof (Ipc_Config));
331         status = Platform_setup ((Ipc_Config *)cfg);
332         if (status < 0) {
333             key = Gate_enterSystem ();
334             Ipc_module->refCount--;
335             Gate_leaveSystem (key);
336             status = Ipc_E_FAIL;
337             GT_setFailureReason (curTrace,
338                                  GT_4CLASS,
339                                  "Ipc_setup",
340                                  status,
341                                  "Platform_setup failed!");
342         }
344         /* Following can be done regardless of status */
345         for (i = 0; i < MultiProc_getNumProcessors (); i++) {
346             Ipc_module->procEntry [i].isAttached = FALSE;
347         }
348     }
350     GT_1trace (curTrace, GT_LEAVE, "Ipc_setup", status);
352     /*! @retval Ipc_S_SUCCESS Operation successful */
353     return status;
357 /* Destroys Ipc for this processor. */
358 Int
359 Ipc_destroy (Void)
361     Int status = Ipc_S_SUCCESS;
362     IArg  key;
364     GT_0trace (curTrace, GT_ENTER, "Ipc_destroy");
366     key = Gate_enterSystem ();
367     Ipc_module->refCount--;
368 #if !defined(SYSLINK_BUILD_OPTIMIZE)
369     if (Ipc_module->refCount < 0) {
370         Gate_leaveSystem (key);
371         /*! @retval Ipc_E_INVALIDSTATE Module was not initialized */
372         status = Ipc_E_INVALIDSTATE;
373         GT_setFailureReason (curTrace,
374                              GT_4CLASS,
375                              "Ipc_destroy",
376                              status,
377                              "Module was not initialized!");
378     }
379     else {
380 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
381         if (Ipc_module->refCount == 0) {
382             Gate_leaveSystem (key);
383             status = Platform_destroy ();
384             if (status < 0) {
385                 status = Ipc_E_FAIL;
386                 GT_setFailureReason (curTrace,
387                                      GT_4CLASS,
388                                      "Ipc_destroy",
389                                      status,
390                                      "Platform_destroy failed!");
391             }
392         }
393         else {
394             Gate_leaveSystem (key);
395         }
396 #if !defined(SYSLINK_BUILD_OPTIMIZE)
397     }
398 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
400     GT_1trace (curTrace, GT_LEAVE, "Ipc_destroy", status);
402     /*! @retval Ipc_S_SUCCESS Operation successful */
403     return status;
407 #if defined (__cplusplus)
409 #endif /* defined (__cplusplus) */