SDOCM00115768 Incorrect check for invalid pointer in Ipc_detach
[ipc/ipcdev.git] / packages / ti / sdo / ipc / Ipc.c
1 /*
2  * Copyright (c) 2012-2015 Texas Instruments Incorporated - http://www.ti.com
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.c ========
34  */
36 #include <string.h>     /* for memcpy() */
38 #include <xdc/std.h>
40 #include <xdc/runtime/Error.h>
41 #include <xdc/runtime/Assert.h>
42 #include <xdc/runtime/Memory.h>
43 #include <xdc/runtime/Startup.h>
45 #include <ti/sysbios/BIOS.h>
46 #include <ti/sysbios/hal/Cache.h>
47 #include <ti/sysbios/hal/Hwi.h>
49 #include <ti/sdo/ipc/_Ipc.h>
50 #include <ti/sdo/ipc/_Notify.h>
51 #include <ti/sdo/ipc/_GateMP.h>
52 #include <ti/sdo/ipc/_SharedRegion.h>
53 #include <ti/sdo/utils/_MultiProc.h>
54 #include <ti/sdo/utils/_NameServer.h>
55 #include <ti/sdo/ipc/_MessageQ.h>
57 #include "package/internal/Ipc.xdc.h"
59 #ifdef __ti__
60     #pragma FUNC_EXT_CALLED(Ipc_attach);
61     #pragma FUNC_EXT_CALLED(Ipc_clusterConfig);
62     #pragma FUNC_EXT_CALLED(Ipc_detach);
63     #pragma FUNC_EXT_CALLED(Ipc_isAttached);
64     #pragma FUNC_EXT_CALLED(Ipc_readConfig);
65     #pragma FUNC_EXT_CALLED(Ipc_start);
66     #pragma FUNC_EXT_CALLED(Ipc_stop);
67     #pragma FUNC_EXT_CALLED(Ipc_writeConfig);
68 #endif
70 /*
71  *  For no MMU case, it should be set to TRUE always.
72  *  For MMU, it would be set by IPC link between local and HOST processors.
73  */
74 extern __FAR__ Bits32 Ipc_sr0MemorySetup;
76 /*
77  *************************************************************************
78  *                       Common Header Functions
79  *************************************************************************
80  */
82 /*
83  *  ======== Ipc_attach ========
84  */
85 Int Ipc_attach(UInt16 remoteProcId)
86 {
87     Int i;
88     Ptr sharedAddr;
89     SizeT memReq;
90     volatile ti_sdo_ipc_Ipc_Reserved *slave;
91     ti_sdo_ipc_Ipc_ProcEntry *ipc;
92     Error_Block eb;
93     SharedRegion_Entry entry;
94     SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
95     Bool cacheEnabled = SharedRegion_isCacheEnabled(0);
96     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
97     Int status;
98     UInt hwiKey;
100     /* Assert remoteProcId is in our cluster and isn't our own */
101     Assert_isTrue(clusterId < ti_sdo_utils_MultiProc_numProcsInCluster,
102                   ti_sdo_utils_MultiProc_A_invalidMultiProcId);
103     Assert_isTrue(remoteProcId != MultiProc_self(),
104                   ti_sdo_ipc_Ipc_A_invArgument);
106     /* Check whether Ipc_start has been called.  If not, fail. */
107     if (Ipc_module->ipcSharedAddr == NULL) {
108         return (Ipc_E_FAIL);
109     }
111     /* for checking and incrementing attached below */
112     hwiKey = Hwi_disable();
114     /* Make sure its not already attached */
115     if (Ipc_module->procEntry[clusterId].attached) {
116         Ipc_module->procEntry[clusterId].attached++;
117         /* restore interrupts and return */
118         Hwi_restore(hwiKey);
119         return (Ipc_S_ALREADYSETUP);
120     }
122     /* restore interrupts */
123     Hwi_restore(hwiKey);
125     /* get region 0 information */
126     SharedRegion_getEntry(0, &entry);
128     /* Make sure we've attached to owner of SR0 if we're not owner */
129     if ((MultiProc_self() != entry.ownerProcId) &&
130         (remoteProcId != entry.ownerProcId) &&
131         !(Ipc_module->procEntry[ti_sdo_utils_MultiProc_getClusterId(
132             entry.ownerProcId)].attached)) {
133         return (Ipc_E_FAIL);
134     }
136     /* Init error block */
137     Error_init(&eb);
139     /* determine the slave's slot */
140     slave = Ipc_getSlaveAddr(remoteProcId, Ipc_module->ipcSharedAddr);
142     if (cacheEnabled) {
143         Cache_inv((Ptr)slave, reservedSize, Cache_Type_ALL, TRUE);
144     }
146     /* Synchronize the processors. */
147     status = Ipc_procSyncStart(remoteProcId, Ipc_module->ipcSharedAddr);
148     if (status < 0) {
149         return (status);
150     }
152     /* must be called before SharedRegion_attach */
153     status = ti_sdo_ipc_GateMP_attach(remoteProcId,
154             Ipc_module->gateMPSharedAddr);
155     if (status < 0) {
156         return (status);
157     }
159     /* retrieves the SharedRegion Heap handles */
160     status = ti_sdo_ipc_SharedRegion_attach(remoteProcId);
161     if (status < 0) {
162         return (status);
163     }
165     /* get the attach parameters associated with remoteProcId */
166     ipc = &(Ipc_module->procEntry[clusterId]);
168     /* attach Notify if not yet attached and specified to set internal setup */
169     if (!(Notify_intLineRegistered(remoteProcId, 0)) &&
170         (ipc->entry.setupNotify)) {
171         /* call Notify_attach */
172         memReq = Notify_sharedMemReq(remoteProcId, Ipc_module->ipcSharedAddr);
173         if (memReq != 0) {
174             if (MultiProc_self() < remoteProcId) {
175                 /*
176                  *  calloc required here due to race condition.  Its possible
177                  *  that the slave, who creates the instance, tries a sendEvent
178                  *  before the master has created its instance because the
179                  *  state of memory was enabled from a previous run.
180                  */
181                 sharedAddr = Memory_calloc(SharedRegion_getHeap(0),
182                                        memReq,
183                                        SharedRegion_getCacheLineSize(0),
184                                        &eb);
186                 /* make sure alloc did not fail */
187                 if (sharedAddr == NULL) {
188                     return (Ipc_E_MEMORY);
189                 }
191                 /* if cache enabled, wbInv the calloc above */
192                 if (cacheEnabled) {
193                     Cache_wbInv(sharedAddr, memReq, Cache_Type_ALL, TRUE);
194                 }
196                 /* set the notify SRPtr */
197                 slave->notifySRPtr = SharedRegion_getSRPtr(sharedAddr, 0);
198             }
199             else {
200                 /* get the notify SRPtr */
201                 sharedAddr = SharedRegion_getPtr(slave->notifySRPtr);
202             }
203         }
204         else {
205             sharedAddr = NULL;
206             if (MultiProc_self() < remoteProcId) {
207                 slave->notifySRPtr = SharedRegion_invalidSRPtr();
208             }
209         }
211         /* call attach to remote processor */
212         status = Notify_attach(remoteProcId, sharedAddr);
214         if (status < 0) {
215             if (MultiProc_self() < remoteProcId && sharedAddr != NULL) {
216                 /* free the memory back to SharedRegion 0 heap */
217                 Memory_free(SharedRegion_getHeap(0), sharedAddr, memReq);
218             }
220             return (Ipc_E_FAIL);
221         }
222     }
224     /* Must come after GateMP_start because depends on default GateMP */
225     if (!(ti_sdo_utils_NameServer_isRegistered(remoteProcId)) &&
226         (ipc->entry.setupNotify)) {
227         memReq = ti_sdo_utils_NameServer_SetupProxy_sharedMemReq(
228             Ipc_module->ipcSharedAddr);
229         if (memReq != 0) {
230             if (MultiProc_self() < remoteProcId) {
231                 sharedAddr = Memory_alloc(SharedRegion_getHeap(0),
232                                      memReq,
233                                      SharedRegion_getCacheLineSize(0),
234                                      &eb);
236                 /* make sure alloc did not fail */
237                 if (sharedAddr == NULL) {
238                     return (Ipc_E_MEMORY);
239                 }
241                 /* set the NSRN SRPtr */
242                 slave->nsrnSRPtr = SharedRegion_getSRPtr(sharedAddr, 0);
243             }
244             else {
245                 /* get the NSRN SRPtr */
246                 sharedAddr = SharedRegion_getPtr(slave->nsrnSRPtr);
247             }
248         }
249         else {
250             sharedAddr = NULL;
251             if (MultiProc_self() < remoteProcId) {
252                 slave->nsrnSRPtr = SharedRegion_invalidSRPtr();
253             }
254         }
256         /* call attach to remote processor */
257         status = ti_sdo_utils_NameServer_SetupProxy_attach(remoteProcId,
258                                                            sharedAddr);
260         if (status < 0) {
261             if (MultiProc_self() < remoteProcId && sharedAddr != NULL) {
262                 /* free the memory back to SharedRegion 0 heap */
263                 Memory_free(SharedRegion_getHeap(0), sharedAddr, memReq);
264             }
266             return (Ipc_E_FAIL);
267         }
268     }
270     /* Must come after GateMP_start because depends on default GateMP */
271     if (!(ti_sdo_ipc_MessageQ_SetupTransportProxy_isRegistered(remoteProcId)) &&
272         (ipc->entry.setupMessageQ)) {
273         memReq = ti_sdo_ipc_MessageQ_SetupTransportProxy_sharedMemReq(
274             Ipc_module->ipcSharedAddr);
276         if (memReq != 0) {
277             if (MultiProc_self() < remoteProcId) {
278                 sharedAddr = Memory_alloc(SharedRegion_getHeap(0),
279                     memReq, SharedRegion_getCacheLineSize(0), &eb);
281                 /* make sure alloc did not fail */
282                 if (sharedAddr == NULL) {
283                     return (Ipc_E_MEMORY);
284                 }
286                 /* set the transport SRPtr */
287                 slave->transportSRPtr = SharedRegion_getSRPtr(sharedAddr, 0);
288             }
289             else {
290                 /* get the transport SRPtr */
291                 sharedAddr = SharedRegion_getPtr(slave->transportSRPtr);
292             }
293         }
294         else {
295             sharedAddr = NULL;
296             if (MultiProc_self() < remoteProcId) {
297                 slave->transportSRPtr = SharedRegion_invalidSRPtr();
298             }
299         }
301         /* call attach to remote processor */
302         status = ti_sdo_ipc_MessageQ_SetupTransportProxy_attach(remoteProcId,
303             sharedAddr);
305         if (status < 0) {
306             if (MultiProc_self() < remoteProcId && sharedAddr != NULL) {
307                 /* free the memory back to SharedRegion 0 heap */
308                 Memory_free(SharedRegion_getHeap(0), sharedAddr, memReq);
309             }
311             return (Ipc_E_FAIL);
312         }
313     }
315     /* writeback invalidate slave's shared memory if cache enabled */
316     if (cacheEnabled) {
317         if (MultiProc_self() < remoteProcId) {
318             Cache_wbInv((Ptr)slave, reservedSize, Cache_Type_ALL, TRUE);
319         }
320     }
322     /* Call user attach fxns */
323     for (i = 0; i < ti_sdo_ipc_Ipc_numUserFxns; i++) {
324         if (ti_sdo_ipc_Ipc_userFxns[i].userFxn.attach) {
325             status = ti_sdo_ipc_Ipc_userFxns[i].userFxn.attach(
326                 ti_sdo_ipc_Ipc_userFxns[i].arg, remoteProcId);
328             if (status < 0) {
329                 return (status);
330             }
331         }
332     }
334     /* Finish the processor synchronization */
335     status = ti_sdo_ipc_Ipc_procSyncFinish(remoteProcId,
336         Ipc_module->ipcSharedAddr);
338     if (status < 0) {
339         return (status);
340     }
342     /* for atomically incrementing attached */
343     hwiKey = Hwi_disable();
345     /* now attached to remote processor */
346     Ipc_module->procEntry[clusterId].attached++;
348     /* restore interrupts */
349     Hwi_restore(hwiKey);
351     return (status);
354 /*
355  *  ======== Ipc_clusterConfig ========
356  */
357 Int Ipc_clusterConfig(Void)
359     UInt16 *procIdPtr;
360     UInt16 numProcs;
361     UInt16 baseId;
362     UInt16 i;
365     /* sanity check the cluster baseId */
366     baseId = MultiProc_getBaseIdOfCluster();
368     if (baseId == MultiProc_INVALIDID) {
369         return (Ipc_E_INVALIDSTATE);
370     }
372     /* initialize the MultiProc.clusterProcList array */
373     numProcs = MultiProc_getNumProcsInCluster();
374     procIdPtr = MultiProc_getClusterProcList();
376     for (i = 0; i < numProcs; i++) {
377         *procIdPtr++ = baseId + i;
378     }
380     /* update the Ipc.procEntry[] array with valid procIds */
381     for (i = 0; i < numProcs; i++) {
382         Ipc_module->procEntry[i].entry.remoteProcId = baseId + i;
383     }
385     return (Ipc_S_SUCCESS);
388 /*
389  *  ======== Ipc_isAttached ========
390  */
391 Bool Ipc_isAttached(UInt16 remoteProcId)
393     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
395     /* Assert remoteProcId is in our cluster */
396     Assert_isTrue(clusterId < ti_sdo_utils_MultiProc_numProcsInCluster,
397                   ti_sdo_utils_MultiProc_A_invalidMultiProcId);
399     if (remoteProcId == MultiProc_self()) {
400         return (FALSE);
401     }
402     else {
403         return (Ipc_module->procEntry[clusterId].attached);
404     }
407 /*
408  *  ======== Ipc_detach ========
409  */
410 Int Ipc_detach(UInt16 remoteProcId)
412     Int i;
413     UInt16 baseId = MultiProc_getBaseIdOfCluster();
414     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
415     Ptr notifySharedAddr;
416     Ptr nsrnSharedAddr;
417     Ptr msgqSharedAddr;
418     volatile ti_sdo_ipc_Ipc_Reserved *slave, *master;
419     SharedRegion_Entry entry;
420     ti_sdo_ipc_Ipc_ProcEntry *ipc;
421     SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
422     Bool cacheEnabled = SharedRegion_isCacheEnabled(0);
423     Int status = Ipc_S_SUCCESS;
424     UInt hwiKey;
426     /* Assert remoteProcId is in our cluster and isn't our own */
427     Assert_isTrue(clusterId < ti_sdo_utils_MultiProc_numProcsInCluster,
428                   ti_sdo_utils_MultiProc_A_invalidMultiProcId);
429     Assert_isTrue(remoteProcId != MultiProc_self(),
430                   ti_sdo_ipc_Ipc_A_invArgument);
432     /* for checking and incrementing attached below */
433     hwiKey = Hwi_disable();
435     if (Ipc_module->procEntry[clusterId].attached > 1) {
436         /* only detach if attach count reaches 1 */
437         Ipc_module->procEntry[clusterId].attached--;
438         Hwi_restore(hwiKey);
439         return (Ipc_S_BUSY);
440     }
441     else if (Ipc_module->procEntry[clusterId].attached == 0) {
442         /* already detached, restore interrupts and return success */
443         Hwi_restore(hwiKey);
444         return (Ipc_S_SUCCESS);
445     }
447     /* restore interrupts */
448     Hwi_restore(hwiKey);
450     /* get region 0 information */
451     SharedRegion_getEntry(0, &entry);
453     /*
454      *  Make sure we detach from all other procs in cluster before
455      *  detaching from owner of SR 0.
456      */
457     if (remoteProcId == entry.ownerProcId) {
458         for (i = 0; i < ti_sdo_utils_MultiProc_numProcsInCluster; i++, baseId++) {
459             if ((baseId != MultiProc_self()) && (baseId != entry.ownerProcId) &&
460                 (Ipc_module->procEntry[i].attached)) {
461                 return (Ipc_E_FAIL);
462             }
463         }
464     }
466     /* get the paramters associated with remoteProcId */
467     ipc = &(Ipc_module->procEntry[clusterId]);
469     /* determine the slave's slot */
470     slave = Ipc_getSlaveAddr(remoteProcId, Ipc_module->ipcSharedAddr);
472     /* determine the master's slot */
473     master = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId,
474         Ipc_module->ipcSharedAddr);
476     if (cacheEnabled) {
477         Cache_inv((Ptr)slave, reservedSize, Cache_Type_ALL, TRUE);
478         Cache_inv((Ptr)master, reservedSize, Cache_Type_ALL, TRUE);
479     }
481     if (MultiProc_self() < remoteProcId) {
482         /* check to make sure master is not trying to attach */
483         if (master->startedKey == ti_sdo_ipc_Ipc_PROCSYNCSTART) {
484             return (Ipc_E_NOTREADY);
485         }
486     }
487     else {
488         /* check to make sure slave is not trying to attach */
489         if (slave->startedKey == ti_sdo_ipc_Ipc_PROCSYNCSTART) {
490             return (Ipc_E_NOTREADY);
491         }
492     }
494     /* The slave processor waits for master to finish its detach sequence */
495     if (MultiProc_self() < remoteProcId) {
496         if (master->startedKey != ti_sdo_ipc_Ipc_PROCSYNCDETACH) {
497             return (Ipc_E_NOTREADY);
498         }
499     }
501     /* Call user detach fxns */
502     for (i = 0; i < ti_sdo_ipc_Ipc_numUserFxns; i++) {
503         if (ti_sdo_ipc_Ipc_userFxns[i].userFxn.detach) {
504             status = ti_sdo_ipc_Ipc_userFxns[i].userFxn.detach(
505                 ti_sdo_ipc_Ipc_userFxns[i].arg, remoteProcId);
507             if (status < 0) {
508                 return (status);
509             }
510         }
511     }
513     if ((ipc->entry.setupMessageQ) &&
514        (ti_sdo_ipc_MessageQ_SetupTransportProxy_isRegistered(remoteProcId))) {
515         /* call MessageQ_detach for remote processor */
516         status = ti_sdo_ipc_MessageQ_SetupTransportProxy_detach(remoteProcId);
517         if (status < 0) {
518             return (Ipc_E_FAIL);
519         }
521         if (slave->transportSRPtr != SharedRegion_invalidSRPtr()) {
522             /* free the memory if slave processor */
523             if (MultiProc_self() < remoteProcId) {
524                 /* get the pointer to MessageQ transport instance */
525                 msgqSharedAddr = SharedRegion_getPtr(slave->transportSRPtr);
527                 /* free the memory back to SharedRegion 0 heap */
528                 Memory_free(SharedRegion_getHeap(0),
529                     msgqSharedAddr,
530                     ti_sdo_ipc_MessageQ_SetupTransportProxy_sharedMemReq(
531                         msgqSharedAddr));
533                 /* set pointer for MessageQ transport instance to INVALID */
534                 slave->transportSRPtr = SharedRegion_invalidSRPtr();
535             }
536         }
537     }
539     if ((ipc->entry.setupNotify) &&
540         (ti_sdo_utils_NameServer_isRegistered(remoteProcId))) {
541         /* call NameServer_SetupProxy_detach for remote processor */
542         status = ti_sdo_utils_NameServer_SetupProxy_detach(remoteProcId);
543         if (status < 0) {
544             return (Ipc_E_FAIL);
545         }
547         if (slave->nsrnSRPtr != SharedRegion_invalidSRPtr()) {
548             /* free the memory if slave processor */
549             if (MultiProc_self() < remoteProcId) {
550                 /* get the pointer to NSRN instance */
551                 nsrnSharedAddr = SharedRegion_getPtr(slave->nsrnSRPtr);
553                 /* free the memory back to SharedRegion 0 heap */
554                 Memory_free(SharedRegion_getHeap(0),
555                             nsrnSharedAddr,
556                             ti_sdo_utils_NameServer_SetupProxy_sharedMemReq(
557                                 nsrnSharedAddr));
559                 /* set pointer for NSRN instance to INVALID */
560                 slave->nsrnSRPtr = SharedRegion_invalidSRPtr();
561             }
562         }
563     }
565     if ((ipc->entry.setupNotify) &&
566         (Notify_intLineRegistered(remoteProcId, 0))) {
567         /* call Notify_detach for remote processor */
568         status = ti_sdo_ipc_Notify_detach(remoteProcId);
569         if (status < 0) {
570             return (Ipc_E_FAIL);
571         }
573         if (slave->notifySRPtr != SharedRegion_invalidSRPtr()) {
574             /* free the memory if slave processor */
575             if (MultiProc_self() < remoteProcId) {
576                 /* get the pointer to Notify instance */
577                 notifySharedAddr = SharedRegion_getPtr(slave->notifySRPtr);
579                 /* free the memory back to SharedRegion 0 heap */
580                 Memory_free(SharedRegion_getHeap(0),
581                             notifySharedAddr,
582                             Notify_sharedMemReq(remoteProcId, notifySharedAddr));
584                 /* set pointer for Notify instance to INVALID */
585                 slave->notifySRPtr = SharedRegion_invalidSRPtr();
586             }
587         }
588     }
590     /* close any HeapMemMP which may have been opened */
591     status = ti_sdo_ipc_SharedRegion_detach(remoteProcId);
592     if (status < 0) {
593         return (status);
594     }
596     /* close any GateMP which may have been opened */
597     status = ti_sdo_ipc_GateMP_detach(remoteProcId);
598     if (status < 0) {
599         return (status);
600     }
602     if (MultiProc_self() < remoteProcId) {
603         slave->configListHead = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
604         slave->startedKey = ti_sdo_ipc_Ipc_PROCSYNCDETACH;
605         if (cacheEnabled) {
606             Cache_wbInv((Ptr)slave, reservedSize, Cache_Type_ALL, TRUE);
607         }
608     }
609     else {
610         master->configListHead = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
611         master->startedKey = ti_sdo_ipc_Ipc_PROCSYNCDETACH;
612         if (cacheEnabled) {
613             Cache_wbInv((Ptr)master, reservedSize, Cache_Type_ALL, TRUE);
614         }
615     }
617     /* attached must be decremented atomically */
618     hwiKey = Hwi_disable();
620     /* now detached from remote processor */
621     Ipc_module->procEntry[clusterId].attached--;
623     /* restore interrupts */
624     Hwi_restore(hwiKey);
626     return (status);
629 /*
630  *  ======== Ipc_readConfig ========
631  */
632 Int Ipc_readConfig(UInt16 remoteProcId, UInt32 tag, Ptr cfg, SizeT size)
634     Int status = Ipc_E_FAIL;
635     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
636     volatile ti_sdo_ipc_Ipc_ConfigEntry *entry;
637     Bool cacheEnabled = SharedRegion_isCacheEnabled(0);
639     /* Assert that the remoteProc in our cluster and isn't our own */
640     Assert_isTrue(clusterId < ti_sdo_utils_MultiProc_numProcsInCluster,
641                   ti_sdo_utils_MultiProc_A_invalidMultiProcId);
643     if (cacheEnabled) {
644         Cache_inv(Ipc_module->procEntry[clusterId].remoteConfigList,
645                   SharedRegion_getCacheLineSize(0),
646                   Cache_Type_ALL,
647                   TRUE);
648     }
650     entry = (ti_sdo_ipc_Ipc_ConfigEntry *)
651             *Ipc_module->procEntry[clusterId].remoteConfigList;
653     while ((SharedRegion_SRPtr)entry != ti_sdo_ipc_SharedRegion_INVALIDSRPTR) {
654         entry = (ti_sdo_ipc_Ipc_ConfigEntry *)
655                 SharedRegion_getPtr((SharedRegion_SRPtr)entry);
657         /* Traverse the list to find the tag */
658         if (cacheEnabled) {
659             Cache_inv((Ptr)entry,
660                       size + sizeof(ti_sdo_ipc_Ipc_ConfigEntry),
661                       Cache_Type_ALL,
662                       TRUE);
663         }
665         if ((entry->remoteProcId == MultiProc_self()) &&
666             (entry->localProcId == remoteProcId) &&
667             (entry->tag == tag)) {
669             if (size == entry->size) {
670                 memcpy(cfg, (Ptr)((UInt32)entry + sizeof(ti_sdo_ipc_Ipc_ConfigEntry)),
671                         entry->size);
672                 return (Ipc_S_SUCCESS);
673             }
674             else {
675                 return (Ipc_E_FAIL);
676             }
677         }
679         entry = (ti_sdo_ipc_Ipc_ConfigEntry *)entry->next;
680     }
682     return (status);
685 /*
686  *  ======== Ipc_start ========
687  */
688 Int Ipc_start()
690     Int i;
691     UInt16 baseId = MultiProc_getBaseIdOfCluster();
692     SharedRegion_Entry entry;
693     Ptr ipcSharedAddr;
694     Ptr gateMPSharedAddr;
695     GateMP_Params gateMPParams;
696     Int status;
698     /* Check whether Ipc_start has been called.  If so, succeed. */
699     if (Ipc_module->ipcSharedAddr != NULL) {
700         return (Ipc_S_ALREADYSETUP);
701     }
703     if (ti_sdo_ipc_Ipc_generateSlaveDataForHost) {
704         /* get Ipc_sr0MemorySetup out of the cache */
705         Cache_inv(&Ipc_sr0MemorySetup,
706               sizeof(Ipc_sr0MemorySetup),
707               Cache_Type_ALL,
708               TRUE);
710         /* check Ipc_sr0MemorySetup variable */
711         if (Ipc_sr0MemorySetup == 0x0) {
712             return (Ipc_E_NOTREADY);
713         }
714     }
716     /* get region 0 information */
717     SharedRegion_getEntry(0, &entry);
719     /* if entry is not valid then return */
720     if (entry.isValid == FALSE) {
721         return (Ipc_E_NOTREADY);
722     }
724     /*
725      *  Need to reserve memory in region 0 for processor synchronization.
726      *  This must done before SharedRegion_start().
727      */
728     ipcSharedAddr = ti_sdo_ipc_SharedRegion_reserveMemory(
729             0, Ipc_getRegion0ReservedSize());
731     /* must reserve memory for GateMP before SharedRegion_start() */
732     gateMPSharedAddr = ti_sdo_ipc_SharedRegion_reserveMemory(0,
733             ti_sdo_ipc_GateMP_getRegion0ReservedSize());
735     /* Init params for default gate (must match those in GateMP_start()) */
736     GateMP_Params_init(&gateMPParams);
737     gateMPParams.localProtect  = GateMP_LocalProtect_TASKLET;
739     if (ti_sdo_utils_MultiProc_numProcessors > 1) {
740         gateMPParams.remoteProtect = GateMP_RemoteProtect_SYSTEM;
741     }
742     else {
743         gateMPParams.remoteProtect = GateMP_RemoteProtect_NONE;
744     }
746     /* reserve memory for default gate before SharedRegion_start() */
747     ti_sdo_ipc_SharedRegion_reserveMemory(0, GateMP_sharedMemReq(&gateMPParams));
749     /* clear the reserved memory */
750     ti_sdo_ipc_SharedRegion_clearReservedMemory();
752     /* Set shared addresses */
753     Ipc_module->ipcSharedAddr = ipcSharedAddr;
754     Ipc_module->gateMPSharedAddr = gateMPSharedAddr;
756     /* create default GateMP, must be called before SharedRegion start */
757     status = ti_sdo_ipc_GateMP_start(Ipc_module->gateMPSharedAddr);
758     if (status < 0) {
759         return (status);
760     }
762     /* create HeapMemMP in each SharedRegion */
763     status = ti_sdo_ipc_SharedRegion_start();
764     if (status < 0) {
765         return (status);
766     }
768     /* Call attach for all procs if procSync is ALL */
769     if (ti_sdo_ipc_Ipc_procSync == ti_sdo_ipc_Ipc_ProcSync_ALL) {
770         /* Must attach to owner first to get default GateMP and HeapMemMP */
771         if (MultiProc_self() != entry.ownerProcId) {
772             do {
773                 status = Ipc_attach(entry.ownerProcId);
774             } while (status == Ipc_E_NOTREADY);
776             if (status < 0) {
777                 /* Ipc_attach failed. Get out of Ipc_start */
778                 return (status);
779             }
780         }
782         /* Loop to attach to all other processors in cluster */
783         for (i = 0; i < ti_sdo_utils_MultiProc_numProcsInCluster; i++, baseId++) {
784             if ((baseId == MultiProc_self()) || (baseId == entry.ownerProcId)) {
785                 continue;
786             }
788             /* Skip the processor if there are no interrupt lines to it */
789             if (Notify_numIntLines(baseId) == 0) {
790                 continue;
791             }
793             /* call Ipc_attach for every remote processor */
794             do {
795                 status = Ipc_attach(baseId);
796             } while (status == Ipc_E_NOTREADY);
798             if (status < 0) {
799                 /* Ipc_attach failed. Get out of Ipc_start */
800                 return (status);
801             }
802         }
803     }
805     return (status);
808 /*
809  *  ======== Ipc_stop ========
810  */
811 Int Ipc_stop()
813     Int status;
815     /* clear local module state */
816     Ipc_module->gateMPSharedAddr = NULL;
817     Ipc_module->ipcSharedAddr = NULL;
819     /* reset Shared Region 0 reservedSize and heap handle */
820     ti_sdo_ipc_SharedRegion_resetInternalFields(0);
822     /* delete any HeapMemMP created by owner of SR0 */
823     status = ti_sdo_ipc_SharedRegion_stop();
824     if (status < 0) {
825         return (status);
826     }
828     /* delete default GateMP created by owner of SR0 */
829     status = ti_sdo_ipc_GateMP_stop();
830     if (status < 0) {
831         return (status);
832     }
834     /* set sr0MemorySetup back to 0 if needed by Host */
835     if ((ti_sdo_ipc_Ipc_generateSlaveDataForHost) &&
836         !(ti_sdo_ipc_Ipc_sr0MemorySetup)) {
837         Ipc_sr0MemorySetup = 0;
838         Cache_wbInv(&Ipc_sr0MemorySetup,
839               sizeof(Ipc_sr0MemorySetup),
840               Cache_Type_ALL,
841               TRUE);
842     }
844     return (Ipc_S_SUCCESS);
847 /*
848  *  ======== Ipc_writeConfig ========
849  */
850 Int Ipc_writeConfig(UInt16 remoteProcId, UInt32 tag, Ptr cfg, SizeT size)
852     Int status = Ipc_S_SUCCESS;
853     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
854     SharedRegion_SRPtr curSRPtr, *prevSRPtr;
855     ti_sdo_ipc_Ipc_ConfigEntry *entry;
856     Error_Block eb;
857     Bool cacheEnabled = SharedRegion_isCacheEnabled(0);
859     /* Assert that the remoteProc in our cluster */
860     Assert_isTrue(clusterId < ti_sdo_utils_MultiProc_numProcsInCluster,
861                   ti_sdo_utils_MultiProc_A_invalidMultiProcId);
863     Error_init(&eb);
865     if (cfg == NULL) {
866         status = Ipc_E_FAIL;
868         /* get head of local config list and set prevSRPtr to it */
869         prevSRPtr = (Ipc_module->procEntry[clusterId].localConfigList);
871         /*
872          *  When cfg is NULL, the last memory allocated from a previous
873          *  Ipc_writeConfig call with the same remoteProcId, tag, and size
874          *  is freed.
875          */
876         curSRPtr = *prevSRPtr;
878         /* loop through list of config entries until matching entry is found */
879         while (curSRPtr != ti_sdo_ipc_SharedRegion_INVALIDSRPTR) {
880             /* convert Ptr associated with curSRPtr */
881             entry = (ti_sdo_ipc_Ipc_ConfigEntry *)
882                     (SharedRegion_getPtr(curSRPtr));
884             /* make sure entry matches remoteProcId, tag, and size */
885             if ((entry->remoteProcId == remoteProcId) &&
886                 (entry->tag == tag) &&
887                 (entry->size == size)) {
888                 /* Update the 'prev' next ptr */
889                 *prevSRPtr = (SharedRegion_SRPtr)entry->next;
891                 /* writeback the 'prev' ptr */
892                 if (cacheEnabled) {
893                     Cache_wb(prevSRPtr,
894                         sizeof(ti_sdo_ipc_Ipc_ConfigEntry),
895                         Cache_Type_ALL,
896                         FALSE);
897                 }
899                 /* free entry's memory back to shared heap */
900                 Memory_free(SharedRegion_getHeap(0),
901                     entry,
902                     size + sizeof(ti_sdo_ipc_Ipc_ConfigEntry));
904                 /* set the status to success */
905                 status = Ipc_S_SUCCESS;
906                 break;
907             }
909             /* set the 'prev' to the 'cur' SRPtr */
910             prevSRPtr = (SharedRegion_SRPtr *)(&entry->next);
912             /* point to next config entry */
913             curSRPtr = (SharedRegion_SRPtr)entry->next;
914         }
916         /* return that status */
917         return (status);
918     }
920     /* Allocate memory from the shared heap (System Heap) */
921     entry = Memory_alloc(SharedRegion_getHeap(0),
922                          size + sizeof(ti_sdo_ipc_Ipc_ConfigEntry),
923                          SharedRegion_getCacheLineSize(0),
924                          &eb);
926     if (entry == NULL) {
927         return (Ipc_E_FAIL);
928     }
930     /* set the entry */
931     entry->remoteProcId = remoteProcId;
932     entry->localProcId = MultiProc_self();
933     entry->tag = tag;
934     entry->size = size;
935     memcpy((Ptr)((UInt32)entry + sizeof(ti_sdo_ipc_Ipc_ConfigEntry)), cfg,
936                   size);
938     /* point the entry's next to the first entry in the list */
939     entry->next = *Ipc_module->procEntry[clusterId].localConfigList;
941     /* first write-back the entry if cache is enabled */
942     if (cacheEnabled) {
943         Cache_wb(entry, size + sizeof(ti_sdo_ipc_Ipc_ConfigEntry),
944                  Cache_Type_ALL,
945                  FALSE);
946     }
948     /* set the entry as the new first in the list */
949     *Ipc_module->procEntry[clusterId].localConfigList =
950         SharedRegion_getSRPtr(entry, 0);
952     /* write-back the config list */
953     if (cacheEnabled) {
954         Cache_wb(Ipc_module->procEntry[clusterId].localConfigList,
955                  SharedRegion_getCacheLineSize(0),
956                  Cache_Type_ALL,
957                  FALSE);
958     }
960     return (status);
963 /*
964  *************************************************************************
965  *                       Module Functions
966  *************************************************************************
967  */
969 /*
970  *  ======== ti_sdo_ipc_Ipc_dummy ========
971  */
972 Void ti_sdo_ipc_Ipc_dummy()
976 /*
977  *  ======== ti_sdo_ipc_Ipc_getEntry ========
978  */
979 Void ti_sdo_ipc_Ipc_getEntry(ti_sdo_ipc_Ipc_Entry *entry)
981     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(entry->remoteProcId);
983     /* Assert remoteProcId is in our cluster */
984     Assert_isTrue(clusterId < ti_sdo_utils_MultiProc_numProcsInCluster,
985                   ti_sdo_utils_MultiProc_A_invalidMultiProcId);
987     /* Get the setupNotify flag */
988     entry->setupNotify =
989         Ipc_module->procEntry[clusterId].entry.setupNotify;
991     /* Get the setupMessageQ flag */
992     entry->setupMessageQ =
993         Ipc_module->procEntry[clusterId].entry.setupMessageQ;
996 /*
997  *  ======== ti_sdo_ipc_Ipc_setEntry ========
998  */
999 Void ti_sdo_ipc_Ipc_setEntry(ti_sdo_ipc_Ipc_Entry *entry)
1001     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(entry->remoteProcId);
1003     /* Set the setupNotify flag */
1004     Ipc_module->procEntry[clusterId].entry.setupNotify =
1005         entry->setupNotify;
1007     /* Set the setupMessageQ flag */
1008     Ipc_module->procEntry[clusterId].entry.setupMessageQ =
1009         entry->setupMessageQ;
1012 /*
1013  *************************************************************************
1014  *                       Internal Functions
1015  *************************************************************************
1016  */
1018 /*
1019  *  ======== ti_sdo_ipc_Ipc_getMasterAddr ========
1020  */
1021 Ptr ti_sdo_ipc_Ipc_getMasterAddr(UInt16 remoteProcId, Ptr sharedAddr)
1023     Int slot;
1024     UInt16 masterId;
1025     volatile ti_sdo_ipc_Ipc_Reserved *master;
1026     SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
1028     /* determine the master's procId and slot */
1029     if (MultiProc_self() < remoteProcId) {
1030         masterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
1031         slot = ti_sdo_utils_MultiProc_getClusterId(MultiProc_self());
1032     }
1033     else {
1034         masterId = ti_sdo_utils_MultiProc_getClusterId(MultiProc_self());
1035         slot = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
1036     }
1038     /* determine the reserve address for master between self and remote */
1039     master = (ti_sdo_ipc_Ipc_Reserved *)((UInt32)sharedAddr +
1040              ((masterId * reservedSize) +
1041              (slot * sizeof(ti_sdo_ipc_Ipc_Reserved))));
1043     return ((Ptr)master);
1046 /*
1047  *  ======== ti_sdo_ipc_Ipc_getRegion0ReservedSize ========
1048  */
1049 SizeT ti_sdo_ipc_Ipc_getRegion0ReservedSize(Void)
1051     SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
1053     /* Calculate the total amount to reserve */
1054     reservedSize = reservedSize * ti_sdo_utils_MultiProc_numProcsInCluster;
1056     return (reservedSize);
1059 /*
1060  *  ======== ti_sdo_ipc_Ipc_getSlaveAddr ========
1061  */
1062 Ptr ti_sdo_ipc_Ipc_getSlaveAddr(UInt16 remoteProcId, Ptr sharedAddr)
1064     Int slot;
1065     UInt16 slaveId;
1066     volatile ti_sdo_ipc_Ipc_Reserved *slave;
1067     SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
1069     /* determine the slave's procId and slot */
1070     if (MultiProc_self() < remoteProcId) {
1071         slaveId = ti_sdo_utils_MultiProc_getClusterId(MultiProc_self());
1072         slot = ti_sdo_utils_MultiProc_getClusterId(remoteProcId) - 1;
1073     }
1074     else {
1075         slaveId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
1076         slot = ti_sdo_utils_MultiProc_getClusterId(MultiProc_self()) - 1;
1077     }
1079     /* determine the reserve address for slave between self and remote */
1080     slave = (ti_sdo_ipc_Ipc_Reserved *)((UInt32)sharedAddr +
1081             ((slaveId * reservedSize) +
1082             (slot * sizeof(ti_sdo_ipc_Ipc_Reserved))));
1084     return ((Ptr)slave);
1087 /*
1088  *  ======== ti_sdo_ipc_Ipc_procSyncStart ========
1089  *  The owner of SharedRegion 0 writes to its reserve memory address
1090  *  in region 0 to let the other processors know it has started.
1091  *  It then spins until the other processors start.
1092  *  The other processors write their reserve memory address in
1093  *  region 0 to let the owner processor know they've started.
1094  *  The other processors then spin until the owner processor writes
1095  *  to let them know that its finished the process of synchronization
1096  *  before continuing.
1097  */
1098 Int ti_sdo_ipc_Ipc_procSyncStart(UInt16 remoteProcId, Ptr sharedAddr)
1100     volatile ti_sdo_ipc_Ipc_Reserved *self, *remote;
1101     ti_sdo_ipc_Ipc_ProcEntry *ipc;
1102     UInt16 clusterId = ti_sdo_utils_MultiProc_getClusterId(remoteProcId);
1103     SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
1104     Bool cacheEnabled = SharedRegion_isCacheEnabled(0);
1106     /* don't do any synchronization if procSync is NONE */
1107     if (ti_sdo_ipc_Ipc_procSync == ti_sdo_ipc_Ipc_ProcSync_NONE) {
1108         return (Ipc_S_SUCCESS);
1109     }
1111     /* determine self and remote pointers */
1112     if (MultiProc_self() < remoteProcId) {
1113         self = Ipc_getSlaveAddr(remoteProcId, sharedAddr);
1114         remote = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId, sharedAddr);
1115     }
1116     else {
1117         self = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId, sharedAddr);
1118         remote = Ipc_getSlaveAddr(remoteProcId, sharedAddr);
1119     }
1121     /* construct the config list */
1122     ipc = &(Ipc_module->procEntry[clusterId]);
1124     ipc->localConfigList = (Ptr)&self->configListHead;
1125     ipc->remoteConfigList = (Ptr)&remote->configListHead;
1127     *ipc->localConfigList = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
1129     if (cacheEnabled) {
1130         Cache_wbInv(ipc->localConfigList, reservedSize, Cache_Type_ALL, TRUE);
1131     }
1133     if (MultiProc_self() < remoteProcId) {
1134         /* set my processor's reserved key to start */
1135         self->startedKey = ti_sdo_ipc_Ipc_PROCSYNCSTART;
1137         /* write back my processor's reserve key */
1138         if (cacheEnabled) {
1139             Cache_wbInv((Ptr)self, reservedSize, Cache_Type_ALL, TRUE);
1140         }
1142         /* wait for remote processor to start */
1143         if (cacheEnabled) {
1144             Cache_inv((Ptr)remote, reservedSize, Cache_Type_ALL, TRUE);
1145         }
1147         if (remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCSTART) {
1148             return (Ipc_E_NOTREADY);
1149         }
1150     }
1151     else {
1152         /*  wait for remote processor to start */
1153         if (cacheEnabled) {
1154             Cache_inv((Ptr)remote, reservedSize, Cache_Type_ALL, TRUE);
1155         }
1157         if ((self->startedKey != ti_sdo_ipc_Ipc_PROCSYNCSTART) &&
1158             (remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCSTART)) {
1159             return (Ipc_E_NOTREADY);
1160         }
1162         /* set my processor's reserved key to start */
1163         self->startedKey = ti_sdo_ipc_Ipc_PROCSYNCSTART;
1165         /* write my processor's reserve key back */
1166         if (cacheEnabled) {
1167             Cache_wbInv((Ptr)self, reservedSize, Cache_Type_ALL, TRUE);
1169             /* wait for remote processor to finish */
1170             Cache_inv((Ptr)remote, reservedSize, Cache_Type_ALL, TRUE);
1171         }
1173         if (remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCFINISH) {
1174             return (Ipc_E_NOTREADY);
1175         }
1176     }
1178     return (Ipc_S_SUCCESS);
1181 /*
1182  *  ======== ti_sdo_ipc_Ipc_procSyncFinish ========
1183  *  Each processor writes its reserve memory address in SharedRegion 0
1184  *  to let the other processors know its finished the process of
1185  *  synchronization.
1186  */
1187 Int ti_sdo_ipc_Ipc_procSyncFinish(UInt16 remoteProcId, Ptr sharedAddr)
1189     volatile ti_sdo_ipc_Ipc_Reserved *self, *remote;
1190     SizeT reservedSize = ti_sdo_ipc_Ipc_reservedSizePerProc();
1191     Bool cacheEnabled = SharedRegion_isCacheEnabled(0);
1193     /* don't do any synchronization if procSync is NONE */
1194     if (ti_sdo_ipc_Ipc_procSync == ti_sdo_ipc_Ipc_ProcSync_NONE) {
1195         return (Ipc_S_SUCCESS);
1196     }
1198     /* determine self and remote pointers */
1199     if (MultiProc_self() < remoteProcId) {
1200         self = Ipc_getSlaveAddr(remoteProcId, sharedAddr);
1201         remote = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId, sharedAddr);
1202     }
1203     else {
1204         self = ti_sdo_ipc_Ipc_getMasterAddr(remoteProcId, sharedAddr);
1205         remote = Ipc_getSlaveAddr(remoteProcId, sharedAddr);
1206     }
1208     /* set my processor's reserved key to finish */
1209     self->startedKey = ti_sdo_ipc_Ipc_PROCSYNCFINISH;
1211     /* write back my processor's reserve key */
1212     if (cacheEnabled) {
1213         Cache_wbInv((Ptr)self, reservedSize, Cache_Type_ALL, TRUE);
1214     }
1216     /* if slave processor, wait for remote to finish sync */
1217     if (MultiProc_self() < remoteProcId) {
1219         /* wait for remote processor to finish */
1220         while (remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCFINISH &&
1221                 remote->startedKey != ti_sdo_ipc_Ipc_PROCSYNCDETACH) {
1223             if (cacheEnabled) {
1224                 Cache_inv((Ptr)remote, reservedSize, Cache_Type_ALL, TRUE);
1225             }
1226         }
1227     }
1229     return (Ipc_S_SUCCESS);
1232 /*
1233  *  ======== ti_sdo_ipc_Ipc_reservedSizePerProc ========
1234  */
1235 SizeT ti_sdo_ipc_Ipc_reservedSizePerProc(Void)
1237     SizeT reservedSize = sizeof(ti_sdo_ipc_Ipc_Reserved) *
1238             ti_sdo_utils_MultiProc_numProcsInCluster;
1239     SizeT cacheLineSize = SharedRegion_getCacheLineSize(0);
1241     /* Calculate amount to reserve per processor */
1242     if (cacheLineSize > reservedSize) {
1243         /* Use cacheLineSize if larger than reservedSize */
1244         reservedSize = cacheLineSize;
1245     }
1246     else {
1247         /* Round reservedSize to cacheLineSize */
1248         reservedSize = _Ipc_roundup(reservedSize, cacheLineSize);
1249     }
1251     return (reservedSize);