1 /*
2 * Copyright (c) 2012-2019 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 /* check to see if there are more messages */
108 msg = (MessageQ_Msg)ListMP_getHead((ListMP_Handle)obj->localList);
109 }
110 }
112 /*
113 *************************************************************************
114 * Instance functions
115 *************************************************************************
116 */
118 /*
119 * ======== TransportShm_Instance_init ========
120 */
121 Int TransportShm_Instance_init(TransportShm_Object *obj,
122 UInt16 procId, const TransportShm_Params *params,
123 Error_Block *eb)
124 {
125 Int localIndex;
126 Int remoteIndex;
127 Int status;
128 Bool flag;
129 UInt32 minAlign;
130 ListMP_Params listMPParams[2];
131 Swi_Handle swiHandle;
132 Swi_Params swiParams;
133 Ptr localAddr;
135 swiHandle = TransportShm_Instance_State_swiObj(obj);
137 /*
138 * Determine who gets the '0' slot in shared memory and who gets
139 * the '1' slot. The '0' slot is given to the lower MultiProc id.
140 */
141 if (MultiProc_self() < procId) {
142 localIndex = 0;
143 remoteIndex = 1;
144 }
145 else {
146 localIndex = 1;
147 remoteIndex = 0;
148 }
150 if (params->openFlag) {
151 /* Open by sharedAddr */
152 obj->objType = ti_sdo_ipc_Ipc_ObjType_OPENDYNAMIC;
153 obj->self = (TransportShm_Attrs *)params->sharedAddr;
154 obj->regionId = SharedRegion_getId(params->sharedAddr);
155 obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
157 localAddr = SharedRegion_getPtr(obj->self->gateMPAddr);
158 if (localAddr == NULL) {
159 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
160 return(1);
161 }
163 status = GateMP_openByAddr(localAddr, (GateMP_Handle *)&obj->gate);
164 if (status < 0) {
165 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
166 return(1);
167 }
168 }
169 else {
170 /* init the gate for ListMP create below */
171 if (params->gate != NULL) {
172 obj->gate = params->gate;
173 }
174 else {
175 obj->gate = (ti_sdo_ipc_GateMP_Handle)GateMP_getDefaultRemote();
176 }
178 /* Creating using sharedAddr */
179 obj->regionId = SharedRegion_getId(params->sharedAddr);
181 /* Assert that the buffer is in a valid shared region */
182 Assert_isTrue(obj->regionId != SharedRegion_INVALIDREGIONID,
183 ti_sdo_ipc_Ipc_A_addrNotInSharedRegion);
185 /* Assert that sharedAddr is cache aligned */
186 Assert_isTrue(SharedRegion_getCacheLineSize(obj->regionId) == 0 ||
187 ((UArg)params->sharedAddr %
188 SharedRegion_getCacheLineSize(obj->regionId) == 0),
189 ti_sdo_ipc_Ipc_A_addrNotCacheAligned);
191 /* set object's cacheEnabled, type, self */
192 obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
193 obj->objType = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC;
194 obj->self = (TransportShm_Attrs *)params->sharedAddr;
195 }
197 /* determine the minimum alignment to align to */
198 minAlign = Memory_getMaxDefaultTypeAlign();
199 if (SharedRegion_getCacheLineSize(obj->regionId) > minAlign) {
200 minAlign = SharedRegion_getCacheLineSize(obj->regionId);
201 }
203 /*
204 * Carve up the shared memory.
205 * If cache is enabled, these need to be on separate cache lines.
206 * This is done with minAlign and _Ipc_roundup function.
207 */
208 obj->other = (TransportShm_Attrs *)((UArg)(obj->self) +
209 (_Ipc_roundup(sizeof(TransportShm_Attrs), minAlign)));
211 ListMP_Params_init(&(listMPParams[0]));
212 listMPParams[0].gate = (GateMP_Handle)obj->gate;
213 listMPParams[0].sharedAddr = (UInt32 *)((UArg)(obj->other) +
214 (_Ipc_roundup(sizeof(TransportShm_Attrs), minAlign)));
216 ListMP_Params_init(&listMPParams[1]);
217 listMPParams[1].gate = (GateMP_Handle)obj->gate;
218 listMPParams[1].sharedAddr = (UInt32 *)((UArg)(listMPParams[0].sharedAddr)
219 + ListMP_sharedMemReq(&listMPParams[0]));
221 obj->priority = params->priority;
222 obj->remoteProcId = procId;
224 Swi_Params_init(&swiParams);
225 swiParams.arg0 = (UArg)obj;
226 Swi_construct(Swi_struct(swiHandle),
227 (Swi_FuncPtr)TransportShm_swiFxn,
228 &swiParams, eb);
230 if (params->openFlag == FALSE) {
231 obj->localList = (ti_sdo_ipc_ListMP_Handle)
232 ListMP_create(&(listMPParams[localIndex]));
233 if (obj->localList == NULL) {
234 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
235 return (2);
236 }
238 obj->remoteList = (ti_sdo_ipc_ListMP_Handle)
239 ListMP_create(&(listMPParams[remoteIndex]));
240 if (obj->localList == NULL) {
241 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
242 return (2);
243 }
244 }
245 else {
246 /* Open the local ListMP instance */
247 status = ListMP_openByAddr(listMPParams[localIndex].sharedAddr,
248 (ListMP_Handle *)&(obj->localList));
250 if (status < 0) {
251 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
252 return (2);
253 }
255 /* Open the remote ListMP instance */
256 status = ListMP_openByAddr(listMPParams[remoteIndex].sharedAddr,
257 (ListMP_Handle *)&(obj->remoteList));
259 if (status < 0) {
260 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
261 return (2);
262 }
263 }
265 /* register the event with Notify */
266 status = Notify_registerEventSingle(
267 procId, /* remoteProcId */
268 0, /* lineId */
269 TransportShm_notifyEventId,
270 (Notify_FnNotifyCbck)TransportShm_notifyFxn,
271 (UArg)swiHandle);
272 if (status < 0) {
273 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
274 return (3);
275 }
277 /* Register the transport with MessageQ */
278 flag = ti_sdo_ipc_MessageQ_registerTransport(
279 TransportShm_Handle_upCast(obj), procId, params->priority);
280 if (flag == FALSE) {
281 Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
282 return (4);
283 }
285 if (params->openFlag == FALSE) {
286 obj->self->creatorProcId = MultiProc_self();
287 obj->self->notifyEventId = TransportShm_notifyEventId;
288 obj->self->priority = obj->priority;
290 /* Store the GateMP sharedAddr in the Attrs */
291 obj->self->gateMPAddr = ti_sdo_ipc_GateMP_getSharedAddr(obj->gate);
292 obj->self->flag = TransportShm_UP;
294 if (obj->cacheEnabled) {
295 Cache_wbInv(obj->self, sizeof(TransportShm_Attrs),
296 Cache_Type_ALL, TRUE);
297 }
298 }
299 else {
300 obj->other->flag = TransportShm_UP;
301 if (obj->cacheEnabled) {
302 Cache_wbInv(&(obj->other->flag), minAlign, Cache_Type_ALL, TRUE);
303 }
304 }
306 obj->status = TransportShm_UP;
308 return (0);
309 }
311 /*
312 * ======== TransportShm_Instance_finalize ========
313 */
314 Void TransportShm_Instance_finalize(TransportShm_Object* obj, Int status)
315 {
316 Swi_Handle swiHandle;
318 if (obj->objType == ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC) {
319 /* clear the self flag */
320 obj->self->flag = 0;
322 if (obj->cacheEnabled) {
323 Cache_wbInv(&(obj->self->flag),
324 SharedRegion_getCacheLineSize(obj->regionId), Cache_Type_ALL,
325 TRUE);
326 }
328 if (obj->localList != NULL) {
329 ListMP_delete((ListMP_Handle *)&(obj->localList));
330 }
332 if (obj->remoteList != NULL) {
333 ListMP_delete((ListMP_Handle *)&(obj->remoteList));
334 }
335 }
336 else {
337 /* other flag was set by remote proc */
338 obj->other->flag = 0;
340 if (obj->cacheEnabled) {
341 Cache_wbInv(&(obj->other->flag),
342 SharedRegion_getCacheLineSize(obj->regionId), Cache_Type_ALL,
343 TRUE);
344 }
346 if (obj->gate != NULL) {
347 GateMP_close((GateMP_Handle *)&(obj->gate));
348 }
350 if (obj->localList != NULL) {
351 ListMP_close((ListMP_Handle *)&(obj->localList));
352 }
354 if (obj->remoteList != NULL) {
355 ListMP_close((ListMP_Handle *)&(obj->remoteList));
356 }
357 }
359 switch(status) {
360 case 0:
361 /* MessageQ_registerTransport succeeded */
362 ti_sdo_ipc_MessageQ_unregisterTransport(obj->remoteProcId, obj->priority);
363 /* OK to fall through */
364 case 1: /* GateMP open failed */
365 case 2: /* ListMP create/open failed */
366 case 3: /* Notify_registerEventSingle failed */
367 case 4: /* MessageQ_registerTransport failed */
368 Notify_unregisterEventSingle(
369 obj->remoteProcId,
370 0,
371 TransportShm_notifyEventId);
372 break;
373 }
375 /* Destruct the swi */
376 swiHandle = TransportShm_Instance_State_swiObj(obj);
377 if (swiHandle != NULL) {
378 Swi_destruct(Swi_struct(swiHandle));
379 }
380 }
382 /*
383 * ======== TransportShm_put ========
384 * Assuming MessageQ_put is making sure that the arguments are ok
385 */
386 Bool TransportShm_put(TransportShm_Object *obj, Ptr msg)
387 {
388 Int32 status;
389 Bool retval = TRUE;
390 IArg key;
391 UInt16 id = SharedRegion_getId(msg);
393 /* This transport only deals with messages allocated from SR's */
394 Assert_isTrue(id != SharedRegion_INVALIDREGIONID,
395 ti_sdo_ipc_SharedRegion_A_regionInvalid);
397 /* writeback invalidate the message */
398 if (SharedRegion_isCacheEnabled(id)) {
399 Cache_wbInv(msg, ((MessageQ_Msg)(msg))->msgSize, Cache_Type_ALL,
400 TRUE);
401 }
403 /* make sure ListMP_put and sendEvent are done before remote executes */
404 key = GateMP_enter((GateMP_Handle)obj->gate);
406 /* Put the message on the remoteList */
407 ListMP_putTail((ListMP_Handle)obj->remoteList, (ListMP_Elem *)msg);
409 /* Notify the remote processor */
410 status = Notify_sendEvent(obj->remoteProcId, 0, TransportShm_notifyEventId,
411 0, FALSE);
413 /* check the status of the sendEvent */
414 if (status < 0) {
415 /* remove the message from the List and return 'FALSE' */
416 ListMP_remove((ListMP_Handle)obj->remoteList, (ListMP_Elem *)msg);
417 retval = FALSE;
418 }
420 /* leave the gate */
421 GateMP_leave((GateMP_Handle)obj->gate, key);
423 return (retval);
424 }
426 /*
427 * ======== TransportShm_control ========
428 */
429 Bool TransportShm_control(TransportShm_Object *obj, UInt cmd, UArg cmdArg)
430 {
431 return (FALSE);
432 }
434 /*
435 * ======== TransportShm_getStatus ========
436 */
437 Int TransportShm_getStatus(TransportShm_Object *obj)
438 {
439 return (obj->status);
440 }
442 /*
443 *************************************************************************
444 * Module functions
445 *************************************************************************
446 */
448 /*
449 * ======== TransportShm_close ========
450 */
451 Void TransportShm_close(TransportShm_Handle *handle)
452 {
453 TransportShm_delete(handle);
454 }
456 /*
457 * ======== TransportShm_openByAddr ========
458 */
459 Int TransportShm_openByAddr(Ptr sharedAddr,
460 TransportShm_Handle *handlePtr,
461 Error_Block *eb)
462 {
463 TransportShm_Params params;
464 TransportShm_Attrs *attrs;
465 Int status;
466 UInt16 id;
468 if (sharedAddr == NULL) {
469 return (MessageQ_E_FAIL);
470 }
472 TransportShm_Params_init(¶ms);
474 /* Tell Instance_init() that we're opening */
475 params.openFlag = TRUE;
477 attrs = (TransportShm_Attrs *)sharedAddr;
478 id = SharedRegion_getId(sharedAddr);
480 /* Assert that the region is valid */
481 Assert_isTrue(id != SharedRegion_INVALIDREGIONID,
482 ti_sdo_ipc_Ipc_A_addrNotInSharedRegion);
484 /* invalidate the attrs before using it */
485 if (SharedRegion_isCacheEnabled(id)) {
486 Cache_inv(attrs, sizeof(TransportShm_Attrs), Cache_Type_ALL, TRUE);
487 }
489 /* set params field */
490 params.sharedAddr = sharedAddr;
491 params.priority = attrs->priority;
493 if (attrs->flag != TransportShm_UP) {
494 /* make sure transport is up */
495 *handlePtr = NULL;
496 status = MessageQ_E_NOTFOUND;
497 }
498 else {
499 /* Create the object */
500 *handlePtr = TransportShm_create(attrs->creatorProcId, ¶ms, eb);
501 if (*handlePtr == NULL) {
502 status = MessageQ_E_FAIL;
503 }
504 else {
505 status = MessageQ_S_SUCCESS;
506 }
507 }
509 return (status);
510 }
512 /*
513 * ======== TransportShm_sharedMemReq ========
514 */
515 SizeT TransportShm_sharedMemReq(const TransportShm_Params *params)
516 {
517 SizeT memReq, minAlign;
518 UInt16 regionId;
519 ListMP_Params listMPParams;
521 regionId = SharedRegion_getId(params->sharedAddr);
523 minAlign = Memory_getMaxDefaultTypeAlign();
524 if (SharedRegion_getCacheLineSize(regionId) > minAlign) {
525 minAlign = SharedRegion_getCacheLineSize(regionId);
526 }
528 /* for the Attrs structure */
529 memReq = _Ipc_roundup(sizeof(TransportShm_Attrs), minAlign);
531 /* for the second Attrs structure */
532 memReq += _Ipc_roundup(sizeof(TransportShm_Attrs), minAlign);
534 ListMP_Params_init(&listMPParams);
535 listMPParams.regionId = regionId;
537 /* for localListMP */
538 memReq += ListMP_sharedMemReq(&listMPParams);
540 /* for remoteListMP */
541 memReq += ListMP_sharedMemReq(&listMPParams);
543 return(memReq);
544 }
546 /*
547 * ======== TransportShm_setErrFxn ========
548 */
549 Void TransportShm_setErrFxn(TransportShm_ErrFxn errFxn)
550 {
551 /* Ignore errFxn */
552 }