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);
352 }
354 /*
355 * ======== Ipc_clusterConfig ========
356 */
357 Int Ipc_clusterConfig(Void)
358 {
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);
386 }
388 /*
389 * ======== Ipc_isAttached ========
390 */
391 Bool Ipc_isAttached(UInt16 remoteProcId)
392 {
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 }
405 }
407 /*
408 * ======== Ipc_detach ========
409 */
410 Int Ipc_detach(UInt16 remoteProcId)
411 {
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);
627 }
629 /*
630 * ======== Ipc_readConfig ========
631 */
632 Int Ipc_readConfig(UInt16 remoteProcId, UInt32 tag, Ptr cfg, SizeT size)
633 {
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);
683 }
685 /*
686 * ======== Ipc_start ========
687 */
688 Int Ipc_start()
689 {
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);
806 }
808 /*
809 * ======== Ipc_stop ========
810 */
811 Int Ipc_stop()
812 {
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);
845 }
847 /*
848 * ======== Ipc_writeConfig ========
849 */
850 Int Ipc_writeConfig(UInt16 remoteProcId, UInt32 tag, Ptr cfg, SizeT size)
851 {
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);
961 }
963 /*
964 *************************************************************************
965 * Module Functions
966 *************************************************************************
967 */
969 /*
970 * ======== ti_sdo_ipc_Ipc_dummy ========
971 */
972 Void ti_sdo_ipc_Ipc_dummy()
973 {
974 }
976 /*
977 * ======== ti_sdo_ipc_Ipc_getEntry ========
978 */
979 Void ti_sdo_ipc_Ipc_getEntry(ti_sdo_ipc_Ipc_Entry *entry)
980 {
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;
994 }
996 /*
997 * ======== ti_sdo_ipc_Ipc_setEntry ========
998 */
999 Void ti_sdo_ipc_Ipc_setEntry(ti_sdo_ipc_Ipc_Entry *entry)
1000 {
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;
1010 }
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)
1022 {
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);
1044 }
1046 /*
1047 * ======== ti_sdo_ipc_Ipc_getRegion0ReservedSize ========
1048 */
1049 SizeT ti_sdo_ipc_Ipc_getRegion0ReservedSize(Void)
1050 {
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);
1057 }
1059 /*
1060 * ======== ti_sdo_ipc_Ipc_getSlaveAddr ========
1061 */
1062 Ptr ti_sdo_ipc_Ipc_getSlaveAddr(UInt16 remoteProcId, Ptr sharedAddr)
1063 {
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);
1085 }
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)
1099 {
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);
1179 }
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)
1188 {
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);
1230 }
1232 /*
1233 * ======== ti_sdo_ipc_Ipc_reservedSizePerProc ========
1234 */
1235 SizeT ti_sdo_ipc_Ipc_reservedSizePerProc(Void)
1236 {
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);
1252 }