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 * ======== TransportShm.c ========
34 */
36 #include <xdc/std.h>
37 #include <xdc/runtime/Assert.h>
38 #include <xdc/runtime/Error.h>
39 #include <xdc/runtime/Gate.h>
40 #include <xdc/runtime/Memory.h>
42 #include <ti/sysbios/hal/Cache.h>
43 #include <ti/sysbios/knl/Swi.h>
45 #include "package/internal/TransportShm.xdc.h"
47 #include <ti/sdo/ipc/_Ipc.h>
48 #include <ti/sdo/utils/_MultiProc.h>
49 #include <ti/sdo/ipc/_SharedRegion.h>
50 #include <ti/sdo/ipc/_Notify.h>
51 #include <ti/sdo/ipc/_GateMP.h>
52 #include <ti/sdo/ipc/_ListMP.h>
53 #include <ti/sdo/ipc/_MessageQ.h>
55 /* Need to use reserved notify events */
56 #undef TransportShm_notifyEventId
57 #define TransportShm_notifyEventId \
58 ti_sdo_ipc_transports_TransportShm_notifyEventId + \
59 (UInt32)((UInt32)Notify_SYSTEMKEY << 16)
61 /*
62 *************************************************************************
63 * Module functions
64 *************************************************************************
65 */
68 /*
69 * ======== TransportShm_notifyFxn ========
70 */
71 Void TransportShm_notifyFxn(UInt16 procId,
72 UInt16 lineId,
73 UInt32 eventId,
74 UArg arg,
75 UInt32 payload)
76 {
77 Swi_Handle swiHandle;
79 /* Swi_Handle was passed as arg in register */
80 swiHandle = (Swi_Handle)arg;
82 /* post the Swi */
83 Swi_post(swiHandle);
84 }
86 /*
87 * ======== TransportShm_swiFxn ========
88 */
89 Void TransportShm_swiFxn(UArg arg)
90 {
91 UInt32 queueId;
92 TransportShm_Object *obj = (TransportShm_Object *)arg;
93 MessageQ_Msg msg = NULL;
95 /*
96 * While there are messages, get them out and send them to
97 * their final destination.
98 */
99 msg = (MessageQ_Msg)ListMP_getHead((ListMP_Handle)obj->localList);
100 while (msg != NULL) {
101 /* Get the destination message queue Id */
102 queueId = MessageQ_getDstQueue(msg);
104 /* put the message to the destination queue */
105 MessageQ_put(queueId, msg);
107 #if defined(gnu_targets_STD_) && defined (xdc_target__isaCompatible_v7A)
108 __asm__ __volatile__ (
109 "dmb"
110 ::: "memory"
111 );
112 #endif
114 /* check to see if there are more messages */
115 msg = (MessageQ_Msg)ListMP_getHead((ListMP_Handle)obj->localList);
116 }
117 }
119 /*
120 *************************************************************************
121 * Instance functions
122 *************************************************************************
123 */
125 /*
126 * ======== TransportShm_Instance_init ========
127 */
128 Int TransportShm_Instance_init(TransportShm_Object *obj,
129 UInt16 procId, const TransportShm_Params *params,
130 Error_Block *eb)
131 {
132 Int localIndex;
133 Int remoteIndex;
134 Int status;
135 Bool flag;
136 UInt32 minAlign;
137 ListMP_Params listMPParams[2];
138 Swi_Handle swiHandle;
139 Swi_Params swiParams;
140 Ptr localAddr;
142 swiHandle = TransportShm_Instance_State_swiObj(obj);
144 /*
145 * Determine who gets the '0' slot in shared memory and who gets
146 * the '1' slot. The '0' slot is given to the lower MultiProc id.
147 */
148 if (MultiProc_self() < procId) {
149 localIndex = 0;
150 remoteIndex = 1;
151 }
152 else {
153 localIndex = 1;
154 remoteIndex = 0;
155 }
157 if (params->openFlag) {
158 /* Open by sharedAddr */
159 obj->objType = ti_sdo_ipc_Ipc_ObjType_OPENDYNAMIC;
160 obj->self = (TransportShm_Attrs *)params->sharedAddr;
161 obj->regionId = SharedRegion_getId(params->sharedAddr);
162 obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
164 localAddr = SharedRegion_getPtr(obj->self->gateMPAddr);
165 status = GateMP_openByAddr(localAddr, (GateMP_Handle *)&obj->gate);
166 if (status < 0) {
167 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
168 return(1);
169 }
170 }
171 else {
172 /* init the gate for ListMP create below */
173 if (params->gate != NULL) {
174 obj->gate = params->gate;
175 }
176 else {
177 obj->gate = (ti_sdo_ipc_GateMP_Handle)GateMP_getDefaultRemote();
178 }
180 /* Creating using sharedAddr */
181 obj->regionId = SharedRegion_getId(params->sharedAddr);
183 /* Assert that the buffer is in a valid shared region */
184 Assert_isTrue(obj->regionId != SharedRegion_INVALIDREGIONID,
185 ti_sdo_ipc_Ipc_A_addrNotInSharedRegion);
187 /* Assert that sharedAddr is cache aligned */
188 Assert_isTrue(((UInt32)params->sharedAddr %
189 SharedRegion_getCacheLineSize(obj->regionId) == 0),
190 ti_sdo_ipc_Ipc_A_addrNotCacheAligned);
192 /* set object's cacheEnabled, type, self */
193 obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
194 obj->objType = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC;
195 obj->self = (TransportShm_Attrs *)params->sharedAddr;
196 }
198 /* determine the minimum alignment to align to */
199 minAlign = Memory_getMaxDefaultTypeAlign();
200 if (SharedRegion_getCacheLineSize(obj->regionId) > minAlign) {
201 minAlign = SharedRegion_getCacheLineSize(obj->regionId);
202 }
204 /*
205 * Carve up the shared memory.
206 * If cache is enabled, these need to be on separate cache lines.
207 * This is done with minAlign and _Ipc_roundup function.
208 */
209 obj->other = (TransportShm_Attrs *)((UInt32)(obj->self) +
210 (_Ipc_roundup(sizeof(TransportShm_Attrs), minAlign)));
212 ListMP_Params_init(&(listMPParams[0]));
213 listMPParams[0].gate = (GateMP_Handle)obj->gate;
214 listMPParams[0].sharedAddr = (UInt32 *)((UInt32)(obj->other) +
215 (_Ipc_roundup(sizeof(TransportShm_Attrs), minAlign)));
217 ListMP_Params_init(&listMPParams[1]);
218 listMPParams[1].gate = (GateMP_Handle)obj->gate;
219 listMPParams[1].sharedAddr = (UInt32 *)((UInt32)(listMPParams[0].sharedAddr)
220 + ListMP_sharedMemReq(&listMPParams[0]));
222 obj->priority = params->priority;
223 obj->remoteProcId = procId;
225 Swi_Params_init(&swiParams);
226 swiParams.arg0 = (UArg)obj;
227 Swi_construct(Swi_struct(swiHandle),
228 (Swi_FuncPtr)TransportShm_swiFxn,
229 &swiParams, eb);
231 if (params->openFlag == FALSE) {
232 obj->localList = (ti_sdo_ipc_ListMP_Handle)
233 ListMP_create(&(listMPParams[localIndex]));
234 if (obj->localList == NULL) {
235 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
236 return (2);
237 }
239 obj->remoteList = (ti_sdo_ipc_ListMP_Handle)
240 ListMP_create(&(listMPParams[remoteIndex]));
241 if (obj->localList == NULL) {
242 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
243 return (2);
244 }
245 }
246 else {
247 /* Open the local ListMP instance */
248 status = ListMP_openByAddr(listMPParams[localIndex].sharedAddr,
249 (ListMP_Handle *)&(obj->localList));
251 if (status < 0) {
252 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
253 return (2);
254 }
256 /* Open the remote ListMP instance */
257 status = ListMP_openByAddr(listMPParams[remoteIndex].sharedAddr,
258 (ListMP_Handle *)&(obj->remoteList));
260 if (status < 0) {
261 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
262 return (2);
263 }
264 }
266 /* register the event with Notify */
267 status = Notify_registerEventSingle(
268 procId, /* remoteProcId */
269 0, /* lineId */
270 TransportShm_notifyEventId,
271 (Notify_FnNotifyCbck)TransportShm_notifyFxn,
272 (UArg)swiHandle);
273 if (status < 0) {
274 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
275 return (3);
276 }
278 /* Register the transport with MessageQ */
279 flag = ti_sdo_ipc_MessageQ_registerTransport(
280 TransportShm_Handle_upCast(obj), procId, params->priority);
281 if (flag == FALSE) {
282 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
283 return (4);
284 }
286 if (params->openFlag == FALSE) {
287 obj->self->creatorProcId = MultiProc_self();
288 obj->self->notifyEventId = TransportShm_notifyEventId;
289 obj->self->priority = obj->priority;
291 /* Store the GateMP sharedAddr in the Attrs */
292 obj->self->gateMPAddr = ti_sdo_ipc_GateMP_getSharedAddr(obj->gate);
293 obj->self->flag = TransportShm_UP;
295 if (obj->cacheEnabled) {
296 Cache_wbInv(obj->self, sizeof(TransportShm_Attrs),
297 Cache_Type_ALL, TRUE);
298 }
299 }
300 else {
301 obj->other->flag = TransportShm_UP;
302 if (obj->cacheEnabled) {
303 Cache_wbInv(&(obj->other->flag), minAlign, Cache_Type_ALL, TRUE);
304 }
305 }
307 obj->status = TransportShm_UP;
309 return (0);
310 }
312 /*
313 * ======== TransportShm_Instance_finalize ========
314 */
315 Void TransportShm_Instance_finalize(TransportShm_Object* obj, Int status)
316 {
317 Swi_Handle swiHandle;
319 if (obj->objType == ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC) {
320 /* clear the self flag */
321 obj->self->flag = 0;
323 if (obj->cacheEnabled) {
324 Cache_wbInv(&(obj->self->flag),
325 SharedRegion_getCacheLineSize(obj->regionId), Cache_Type_ALL,
326 TRUE);
327 }
329 if (obj->localList != NULL) {
330 ListMP_delete((ListMP_Handle *)&(obj->localList));
331 }
333 if (obj->remoteList != NULL) {
334 ListMP_delete((ListMP_Handle *)&(obj->remoteList));
335 }
336 }
337 else {
338 /* other flag was set by remote proc */
339 obj->other->flag = 0;
341 if (obj->cacheEnabled) {
342 Cache_wbInv(&(obj->other->flag),
343 SharedRegion_getCacheLineSize(obj->regionId), Cache_Type_ALL,
344 TRUE);
345 }
347 if (obj->gate != NULL) {
348 GateMP_close((GateMP_Handle *)&(obj->gate));
349 }
351 if (obj->localList != NULL) {
352 ListMP_close((ListMP_Handle *)&(obj->localList));
353 }
355 if (obj->remoteList != NULL) {
356 ListMP_close((ListMP_Handle *)&(obj->remoteList));
357 }
358 }
360 switch(status) {
361 case 0:
362 /* MessageQ_registerTransport succeeded */
363 ti_sdo_ipc_MessageQ_unregisterTransport(obj->remoteProcId, obj->priority);
364 /* OK to fall through */
365 case 1: /* GateMP open failed */
366 case 2: /* ListMP create/open failed */
367 case 3: /* Notify_registerEventSingle failed */
368 case 4: /* MessageQ_registerTransport failed */
369 Notify_unregisterEventSingle(
370 obj->remoteProcId,
371 0,
372 TransportShm_notifyEventId);
373 break;
374 }
376 /* Destruct the swi */
377 swiHandle = TransportShm_Instance_State_swiObj(obj);
378 if (swiHandle != NULL) {
379 Swi_destruct(Swi_struct(swiHandle));
380 }
381 }
383 /*
384 * ======== TransportShm_put ========
385 * Assuming MessageQ_put is making sure that the arguments are ok
386 */
387 Bool TransportShm_put(TransportShm_Object *obj, Ptr msg)
388 {
389 Int32 status;
390 Bool retval = TRUE;
391 IArg key;
392 UInt16 id = SharedRegion_getId(msg);
394 /* This transport only deals with messages allocated from SR's */
395 Assert_isTrue(id != SharedRegion_INVALIDREGIONID,
396 ti_sdo_ipc_SharedRegion_A_regionInvalid);
398 /* writeback invalidate the message */
399 if (SharedRegion_isCacheEnabled(id)) {
400 Cache_wbInv(msg, ((MessageQ_Msg)(msg))->msgSize, Cache_Type_ALL,
401 TRUE);
402 }
404 /* make sure ListMP_put and sendEvent are done before remote executes */
405 key = GateMP_enter((GateMP_Handle)obj->gate);
407 /* Put the message on the remoteList */
408 ListMP_putTail((ListMP_Handle)obj->remoteList, (ListMP_Elem *)msg);
410 /* Notify the remote processor */
411 status = Notify_sendEvent(obj->remoteProcId, 0, TransportShm_notifyEventId,
412 0, FALSE);
414 /* check the status of the sendEvent */
415 if (status < 0) {
416 /* remove the message from the List and return 'FALSE' */
417 ListMP_remove((ListMP_Handle)obj->remoteList, (ListMP_Elem *)msg);
418 retval = FALSE;
419 }
421 /* leave the gate */
422 GateMP_leave((GateMP_Handle)obj->gate, key);
424 return (retval);
425 }
427 /*
428 * ======== TransportShm_control ========
429 */
430 Bool TransportShm_control(TransportShm_Object *obj, UInt cmd, UArg cmdArg)
431 {
432 return (FALSE);
433 }
435 /*
436 * ======== TransportShm_getStatus ========
437 */
438 Int TransportShm_getStatus(TransportShm_Object *obj)
439 {
440 return (obj->status);
441 }
443 /*
444 *************************************************************************
445 * Module functions
446 *************************************************************************
447 */
449 /*
450 * ======== TransportShm_close ========
451 */
452 Void TransportShm_close(TransportShm_Handle *handle)
453 {
454 TransportShm_delete(handle);
455 }
457 /*
458 * ======== TransportShm_openByAddr ========
459 */
460 Int TransportShm_openByAddr(Ptr sharedAddr,
461 TransportShm_Handle *handlePtr,
462 Error_Block *eb)
463 {
464 TransportShm_Params params;
465 TransportShm_Attrs *attrs;
466 Int status;
467 UInt16 id;
469 if (sharedAddr == NULL) {
470 return (MessageQ_E_FAIL);
471 }
473 TransportShm_Params_init(¶ms);
475 /* Tell Instance_init() that we're opening */
476 params.openFlag = TRUE;
478 attrs = (TransportShm_Attrs *)sharedAddr;
479 id = SharedRegion_getId(sharedAddr);
481 /* Assert that the region is valid */
482 Assert_isTrue(id != SharedRegion_INVALIDREGIONID,
483 ti_sdo_ipc_Ipc_A_addrNotInSharedRegion);
485 /* invalidate the attrs before using it */
486 if (SharedRegion_isCacheEnabled(id)) {
487 Cache_inv(attrs, sizeof(TransportShm_Attrs), Cache_Type_ALL, TRUE);
488 }
490 /* set params field */
491 params.sharedAddr = sharedAddr;
492 params.priority = attrs->priority;
494 if (attrs->flag != TransportShm_UP) {
495 /* make sure transport is up */
496 *handlePtr = NULL;
497 status = MessageQ_E_NOTFOUND;
498 }
499 else {
500 /* Create the object */
501 *handlePtr = TransportShm_create(attrs->creatorProcId, ¶ms, eb);
502 if (*handlePtr == NULL) {
503 status = MessageQ_E_FAIL;
504 }
505 else {
506 status = MessageQ_S_SUCCESS;
507 }
508 }
510 return (status);
511 }
513 /*
514 * ======== TransportShm_sharedMemReq ========
515 */
516 SizeT TransportShm_sharedMemReq(const TransportShm_Params *params)
517 {
518 SizeT memReq, minAlign;
519 UInt16 regionId;
520 ListMP_Params listMPParams;
522 regionId = SharedRegion_getId(params->sharedAddr);
524 minAlign = Memory_getMaxDefaultTypeAlign();
525 if (SharedRegion_getCacheLineSize(regionId) > minAlign) {
526 minAlign = SharedRegion_getCacheLineSize(regionId);
527 }
529 /* for the Attrs structure */
530 memReq = _Ipc_roundup(sizeof(TransportShm_Attrs), minAlign);
532 /* for the second Attrs structure */
533 memReq += _Ipc_roundup(sizeof(TransportShm_Attrs), minAlign);
535 ListMP_Params_init(&listMPParams);
536 listMPParams.regionId = regionId;
538 /* for localListMP */
539 memReq += ListMP_sharedMemReq(&listMPParams);
541 /* for remoteListMP */
542 memReq += ListMP_sharedMemReq(&listMPParams);
544 return(memReq);
545 }
547 /*
548 * ======== TransportShm_setErrFxn ========
549 */
550 Void TransportShm_setErrFxn(TransportShm_ErrFxn errFxn)
551 {
552 /* Ignore errFxn */
553 }