1 /*
2 * Copyright (c) Texas Instruments Incorporated 2018
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
15 * distribution.
16 *
17 * Neither the name of Texas Instruments Incorporated nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
34 /**
35 * \file ipc_api.c
36 *
37 * \brief File containing the IPC driver APIs.
38 *
39 */
41 /* ========================================================================== */
42 /* Include Files */
43 /* ========================================================================== */
44 #include <ti/drv/ipc/ipc.h>
45 #include <string.h>
47 #ifndef IPC_EXCLUDE_CTRL_TASKS
48 #include <ti/osal/osal.h>
49 #include <ti/osal/TaskP.h>
50 #endif
52 #include "ipc_priv.h"
53 #include "ipc_virtioPrivate.h"
54 #include "ipc_osal.h"
55 #include "ipc_utils.h"
56 #include "ipc_mailbox.h"
58 /* ========================================================================== */
59 /* Macros & Typedefs */
60 /* ========================================================================== */
61 #define MAXCALLBACKS IPC_MAX_PROCS
63 #define MSGBUFFERSIZE 512U
64 #define SERVICENAMELEN 32U
65 #define HEAPALIGNMENT 8U
67 struct RPMessage_Object_s;
68 typedef struct RPMessage_Object_s* RPMessage_EndptPool[MAXENDPOINTS];
70 /* ========================================================================== */
71 /* Structure Declarations */
72 /* ========================================================================== */
74 #define CNTRLMSG_ANNOUNCE (0x00000000U)
76 /* Message Header: Must match mp_msg_hdr in virtio_rp_msg.h on Linux side. */
77 typedef struct RPMessage_MsgHeader_s
78 {
79 uint32_t srcAddr; /* source endpoint addr */
80 uint32_t dstAddr; /* destination endpoint addr */
81 uint32_t srcProcId; /* reserved */
82 uint16_t dataLen; /* data length */
83 uint16_t flags; /* bitmask of different flags */
84 uint8_t payload[]; /* Data payload */
85 }RPMessage_MsgHeader;
88 /* common fields of a control message */
89 typedef struct RPMessage_CntrlMsg_s
90 {
91 uint32_t type;
92 }RPMessage_CntrlMsg;
94 /* announcement message */
95 typedef struct RPMessage_Announcement_s
96 {
97 char name[SERVICENAMELEN];
98 uint32_t endPt;
99 RPMessage_CntrlMsg ctrl;
100 } RPMessage_Announcement;
103 /* list element for the announcedEndpts list */
104 typedef struct RPMessage_NameEntry_s
105 {
106 IpcUtils_QElem elem;
107 uint32_t procId;
108 uint32_t endPt;
109 char name[SERVICENAMELEN];
110 } RPMessage_NameEntry;
113 /* list element for the waitingTasks list */
114 typedef struct RPMessage_Waiter_s
115 {
116 IpcUtils_QElem elem;
117 void *semHandle;
118 uint32_t procId;
119 uint32_t endPt;
120 char name[SERVICENAMELEN];
121 } RPMessage_Waiter;
122 /**
123 * \brief Element to hold payload copied onto receiver's queue.
124 */
125 typedef struct RPMessage_MsgElem_s
126 {
127 IpcUtils_QElem elem; /**< Allow list linking. */
128 uint32_t len; /**< Length of data */
129 uint32_t src; /**< Src address/endPt of the msg */
130 uint32_t procId; /**< Processor sending the msg */
131 uint8_t data[]; /**< payload begins here */
132 } RPMessage_MsgElem;
134 /* The RPMessage Object */
135 typedef struct RPMessage_Object_s
136 {
137 uint32_t endPt; /**< Unique id (procId | queueIndex) */
138 void *semHandle; /**< I/O Completion */
139 RPMessage_Callback cb; /**< RPMessage Callback */
140 void* arg; /**< Callback argument */
141 IpcUtils_QHandle queue; /**< Queue of pending messages */
142 uint8_t unblocked; /**< Use with signal to unblock _receive() */
143 IpcUtils_HeapParams heapParams; /* Save the heapBuf params to delete Heap */
144 IpcUtils_HeapHandle heap; /* Heap from which to allocate free messages */
145 RPMessage_EndptPool *pool; /**< track associated pool for cleanup */
146 void* recv_buffer; /**< Application buffer from RPMessage_recv() */
147 RPMessage_MsgElem payload; /**< Message info for RPMessage_recv() */
148 } RPMessage_Object;
150 /**
151 * \brief This struct is used as private data supplied to the VQ
152 * callback function. It is also passed to the SWI
153 * functions through arg0. */
154 typedef struct RPMessage_CallbackData_s
155 {
156 Virtio_Handle vq;
157 RPMessage_EndptPool *pool;
158 Ipc_OsalHIsrHandle swi;
159 } RPMessage_CallbackData;
161 /**
162 * \brief Module_State
163 */
164 typedef struct RPMessage_Module_s
165 {
166 /* Instance gate: */
167 Ipc_OsalHIsrGateHandle gateSwi;
169 /* Lookup VQ handle from procId for sending messages. */
170 /* Array indexed by procId. */
171 Virtio_Handle tx_VQs[IPC_MAX_PROCS];
173 /* Array of callback structs. Used only for RX VirtQueues */
174 RPMessage_CallbackData VQ_callbacks[MAXCALLBACKS];
176 uint32_t numCallbacks;
178 /* Global endpoint pool */
179 RPMessage_EndptPool globalPool;
181 /* Lookup endpoint pool from procId. Array indexed by procId. */
182 /* RPMessage_EndptPool pools[MAXREMOTEPROCS]; */
184 /* Queue to track announcements from other processors */
185 IpcUtils_QHandle announcedEndpts;
187 /* Queue to hold the semaphores of waiting tasks */
188 IpcUtils_QHandle waitingTasks;
190 /* Array of RPMessage Object, memory supplied by application */
191 RPMessage_Object* objArry;
193 /* Current object Count */
194 uint16_t objCnt;
196 /* NameEntry count */
197 uint16_t nameEntryCnt;
199 RPMessage_NameEntry nameEntry[IPC_MAX_PROCS];
201 } RPMessage_Module;
203 /* ========================================================================== */
204 /* Function Declarations */
205 /* ========================================================================== */
207 static RPMessage_Object* RPMessage_rawCreate(RPMessage_Params *params,
208 RPMessage_EndptPool* pool, uint32_t *endPt);
211 /* ========================================================================== */
212 /* Global Variables */
213 /* ========================================================================== */
215 static RPMessage_Module module;
217 static Ipc_Object gIpcObject;
218 /**< IPC Object */
219 /* ========================================================================== */
220 /* Function Definitions */
221 /* ========================================================================== */
223 RPMessage_Object* RPMessage_lookupEndpt(void* p, uint32_t e);
224 void RPMessage_assignEndpt(void* p, uint32_t e, RPMessage_Object* obj);
225 void UNUSED(const uint32_t* x);
226 uint8_t is_aligned(const void* ptr, uint32_t byteCnt);
227 RPMessage_Object* RPMessage_allocObject(void);
230 inline RPMessage_Object* RPMessage_lookupEndpt(void* p, uint32_t e)
231 {
232 return (((RPMessage_Object**)(p))[(e)]);
233 }
235 inline void RPMessage_assignEndpt(void* p, uint32_t e, RPMessage_Object* obj)
236 {
237 (((RPMessage_Object**)(p))[(e)] = (obj));
238 }
240 inline void UNUSED(const uint32_t* x)
241 {
242 (void)(x);
243 }
245 inline uint8_t is_aligned(const void* ptr, uint32_t byteCnt)
246 {
247 uint8_t retVal;
248 uint32_t bufAddr = (uint32_t)(uintptr_t)ptr;
249 retVal = (0 == (bufAddr%byteCnt)) ? TRUE : FALSE;
250 return retVal;
251 }
255 int32_t RPMessageParams_init(RPMessage_Params *params)
256 {
257 int32_t retVal = IPC_SOK;
259 if(params == NULL)
260 {
261 retVal = IPC_EBADARGS;
262 }
263 else
264 {
265 params->requestedEndpt = RPMESSAGE_ANY;
266 params->numBufs = RPMessage_Buffer_Count_Default;
267 params->stackBuffer = NULL;
268 params->stackSize = 0U;
269 }
271 return (retVal);
272 }
274 uint32_t RPMessage_getMessageBufferSize(void)
275 {
276 return MSGBUFFERSIZE;
277 }
279 uint32_t RPMessage_getObjMemRequired(void)
280 {
281 uint32_t objSize = sizeof(RPMessage_Object);
282 objSize = ((objSize + HEAPALIGNMENT-1) & ~(HEAPALIGNMENT-1));
283 return objSize;
284 }
287 RPMessage_Object* RPMessage_allocObject(void)
288 {
289 RPMessage_Object* obj = NULL;
291 if(module.objArry != NULL)
292 {
293 obj = (RPMessage_Object*)&(module.objArry[module.objCnt]);
294 module.objCnt++;
295 }
297 return obj;
298 }
300 /*
301 * ======== RPMessage_enqueMsg ========
302 */
303 /* Always assumed to be called in SWI context */
304 static int32_t RPMessage_enqueMsg(RPMessage_EndptPool *pool, RPMessage_MsgHeader *msg)
305 {
306 int32_t status = IPC_SOK;
307 int32_t key;
308 uint32_t size;
309 RPMessage_MsgElem *payload;
310 RPMessage_Object *obj = NULL;
311 Ipc_OsalPrms *pOsalPrms = &gIpcObject.initPrms.osalPrms;
313 /* Protect from RPMessage_delete */
314 if (NULL != pOsalPrms)
315 {
316 if ((NULL != pOsalPrms->lockHIsrGate) &&
317 (NULL != pOsalPrms->unLockHIsrGate))
318 {
319 key = pOsalPrms->lockHIsrGate(module.gateSwi);
320 obj = RPMessage_lookupEndpt(pool, msg->dstAddr);
321 pOsalPrms->unLockHIsrGate(module.gateSwi, key);
322 }
323 }
325 if (NULL != obj)
326 {
327 if(NULL != obj->recv_buffer)
328 {
329 memcpy(obj->recv_buffer, msg->payload, msg->dataLen);
330 obj->recv_buffer = NULL;
331 obj->payload.len = msg->dataLen;
332 obj->payload.src = msg->srcAddr;
333 obj->payload.procId = msg->srcProcId;
335 if (NULL != gIpcObject.initPrms.newMsgFxn)
336 {
337 gIpcObject.initPrms.newMsgFxn(msg->srcAddr, msg->srcProcId);
338 }
340 if (NULL != pOsalPrms->unlockMutex)
341 {
342 pOsalPrms->unlockMutex(obj->semHandle);
343 }
344 }
345 else
346 {
347 /* Allocate a buffer to copy the payload: */
348 size = msg->dataLen + sizeof(RPMessage_MsgElem);
350 /* HeapBuf_alloc() is non-blocking, so needs protection: */
351 key = pOsalPrms->disableAllIntr();
352 payload = (RPMessage_MsgElem *)IpcUtils_HeapAlloc(&obj->heap, size, 0);
354 if (payload != NULL)
355 {
356 memcpy(payload->data, msg->payload, msg->dataLen);
357 payload->len = msg->dataLen;
358 payload->src = msg->srcAddr;
359 payload->procId = msg->srcProcId;
361 IpcUtils_Qput(&obj->queue, &payload->elem, (void *)payload);
363 pOsalPrms->restoreAllIntr(key);
365 if (NULL != gIpcObject.initPrms.newMsgFxn)
366 {
367 gIpcObject.initPrms.newMsgFxn(msg->srcAddr, msg->srcProcId);
368 }
370 if (NULL != pOsalPrms->unlockMutex)
371 {
372 pOsalPrms->unlockMutex(obj->semHandle);
373 }
374 }
375 else
376 {
377 pOsalPrms->restoreAllIntr(key);
378 status = IPC_EFAIL;
379 }
380 }
381 }
383 return status;
384 }
386 /**
387 * \brief RPMessage SWI function to talk to Linux
388 */
389 static void RPMessage_swiLinuxFxn(uintptr_t arg0, uintptr_t arg1)
390 {
391 RPMessage_CallbackData *cbdata = (RPMessage_CallbackData*)arg0;
392 RPMessage_MsgHeader *msg;
393 Int16 token;
394 int32_t len;
395 uint8_t usedBufAdded = FALSE;
397 /* Process all available buffers: */
398 while ((token = Virtio_getAvailBuf(cbdata->vq, (void **)&msg, &len)) >= 0)
399 {
400 /* Pass to desitination queue (which is on this proc): */
401 RPMessage_enqueMsg(cbdata->pool, msg);
403 Virtio_addUsedBuf(cbdata->vq, token, MSGBUFFERSIZE);
404 usedBufAdded = TRUE;
405 }
407 if (TRUE == usedBufAdded)
408 {
409 /* Tell host we've processed the buffers: */
410 Virtio_kick(cbdata->vq);
411 }
412 }
414 /**
415 * \brief RPMessage SWI function
416 */
417 static void RPMessage_swiFxn(uintptr_t arg0, uintptr_t arg1)
418 {
419 RPMessage_CallbackData *cbdata = (RPMessage_CallbackData*)arg0;
420 RPMessage_MsgHeader *msg;
422 /* Process all available buffers: */
423 while ((msg = (RPMessage_MsgHeader *) Virtio_getUsedBuf(cbdata->vq)) != NULL)
424 {
425 /* Pass to desitination queue (which is on this proc): */
426 RPMessage_enqueMsg(cbdata->pool, msg);
428 Virtio_addAvailBuf(cbdata->vq, msg);
429 }
430 }
432 /**
433 * \brief virtio_callback - This function executes in HWI context
434 */
435 static void virtio_callback(uint32_t* priv)
436 {
437 RPMessage_CallbackData *cbdata = (RPMessage_CallbackData*)priv;
439 if (NULL != cbdata)
440 {
441 gIpcObject.initPrms.osalPrms.postHIsr(&cbdata->swi);
442 }
443 }
445 /**
446 * \brief RPMessage_announce : Announces the availabilty of an
447 * endpoint to all processors or only one.
448 */
449 int32_t RPMessage_announce(uint32_t remoteProcId, uint32_t endPt, const char* name)
450 {
451 RPMessage_EndptPool *pool = &module.globalPool;
452 RPMessage_Announcement msg;
453 Virtio_Handle vq;
454 uint32_t c;
455 uint32_t procId;
456 int32_t status = IPC_SOK;
457 uint32_t namelen;
459 #if DEBUG_PRINT
460 SystemP_printf("RPMessage_announce : remote %d, endpt %d, name %s\n",
461 remoteProcId, endPt, name);
462 #endif
464 namelen = strlen(name);
465 if(namelen >= SERVICENAMELEN || namelen == 0)
466 {
467 status = IPC_EFAIL;
468 }
470 if(IPC_EFAIL != status)
471 {
472 msg.ctrl.type = CNTRLMSG_ANNOUNCE;
473 msg.endPt = endPt;
474 strncpy(msg.name, name, SERVICENAMELEN-1);
475 msg.name[SERVICENAMELEN-1] = '\0';
477 if(remoteProcId == RPMESSAGE_ALL)
478 {
479 for(c = 0; c < module.numCallbacks; c++)
480 {
481 /* Find callback for RX VQs that have matching pool. */
482 if(module.VQ_callbacks[c].pool == pool)
483 {
484 vq = module.VQ_callbacks[c].vq;
485 procId = Virtio_getProcId(vq);
486 #if DEBUG_PRINT
487 SystemP_printf("RPMessage_announce.....c%d ProcId %d\n", c, procId);
488 #endif
489 status = RPMessage_send(NULL, procId, IPC_CTRL_ENDPOINT_ID,
490 IPC_CTRL_ENDPOINT_ID, &msg, sizeof(msg));
491 if (status != IPC_SOK)
492 {
493 SystemP_printf("RPMessage_announce.....failed to send c %d (%s)\n", c, Ipc_mpGetName(procId));
494 /* even if failed to annouce to one CPU continue to other CPUs */
495 continue;
496 }
497 }
498 }
499 }
500 else
501 {
502 status = RPMessage_send(NULL, remoteProcId, IPC_CTRL_ENDPOINT_ID,
503 IPC_CTRL_ENDPOINT_ID, &msg, sizeof(msg));
504 if (status != IPC_SOK)
505 {
506 SystemP_printf("RPMessage_announce.....failed to send\n");
507 }
508 }
509 }
511 return status;
512 }
514 #ifndef IPC_EXCLUDE_CTRL_TASKS
515 /**
516 * \brief RPMessage_processAnnounceMsg : Handle an endpoint annoucement
517 * message from another processor
518 */
519 static void RPMessage_processAnnounceMsg(RPMessage_Announcement *amsg, uint32_t procId)
520 {
521 int32_t key;
522 RPMessage_NameEntry *p;
523 RPMessage_Waiter *w;
524 IpcUtils_QElem *elem, *head;
525 int32_t rtnVal = IPC_SOK;
526 Ipc_OsalPrms *pOsalPrms = &gIpcObject.initPrms.osalPrms;
528 #if DEBUG_PRINT
529 SystemP_printf("RPMessage_processAnnounceMsg : announcement from %d for endPt %d\n",
530 procId, amsg->endPt );
531 #endif
533 if (NULL != pOsalPrms)
534 {
535 if (((NULL == pOsalPrms->lockHIsrGate) ||
536 (NULL == pOsalPrms->unLockHIsrGate)) ||
537 (NULL == pOsalPrms->unlockMutex))
538 {
539 rtnVal = IPC_EFAIL;
540 }
541 }
543 if (IPC_SOK == rtnVal)
544 {
545 key = pOsalPrms->lockHIsrGate(module.gateSwi);
547 /* Save the annoucement for future calls to */
548 /* RPMessage_peerIsReady(). */
549 if(module.nameEntryCnt == IPC_MAX_PROCS-1)
550 {
551 pOsalPrms->unLockHIsrGate(module.gateSwi, key);
552 SystemP_printf("RPMessage_processAnnounceMsg : all remote core done\n");
553 rtnVal = IPC_EFAIL;
554 }
556 if(rtnVal != IPC_EFAIL)
557 {
558 p = &module.nameEntry[module.nameEntryCnt];
559 p->endPt = amsg->endPt;
560 p->procId = procId;
561 strncpy(p->name, amsg->name, SERVICENAMELEN-1);
562 p->name[SERVICENAMELEN-1] = '\0';
563 module.nameEntryCnt++;
565 /* No interrupt / SWI protection, required here again.
566 We are already in SWI protected region */
567 IpcUtils_Qput(&module.announcedEndpts, &p->elem, (void *)p);
569 /* Wakeup all the tasks that are waiting on the */
570 /* announced name. */
571 if (!IpcUtils_QisEmpty(&module.waitingTasks))
572 {
573 /* No interrupt / SWI protection, required here again.
574 We are already in SWI protected region */
575 elem = head = (IpcUtils_QElem *) IpcUtils_QgetHeadNode(&module.waitingTasks);
576 do
577 {
578 w = (RPMessage_Waiter*)elem;
579 if( (NULL != w) &&
580 (strncmp(w->name, amsg->name, SERVICENAMELEN-1) == 0) &&
581 (w->procId == procId || w->procId == RPMESSAGE_ANY))
582 {
583 /* Update the waiter's entry with actual */
584 /* announcement values. */
585 w->procId = procId;
586 w->endPt = amsg->endPt;
587 #if DEBUG_PRINT
588 SystemP_printf("RPMessage_processAnnounceMsg :Semphore Handle 0x%x\n",
589 (uint32_t)w->semHandle);
590 #endif
592 pOsalPrms->unlockMutex(w->semHandle);
593 }
594 elem = (IpcUtils_QElem *) IpcUtils_Qnext(elem);
595 } while (elem != head);
596 }
597 pOsalPrms->unLockHIsrGate(module.gateSwi, key);
598 }
599 }
600 }
602 #endif /* IPC_EXCLUDE_CTRL_TASKS */
604 /**
605 * \brief RPMessage_lookupName : Checks if an announcement has already been
606 * received.
607 * non-blocking query - must be protected by caller
608 */
609 static uint8_t RPMessage_lookupName(uint32_t procId, const char* name, uint32_t *remoteProcId,
610 uint32_t *remoteEndPt)
611 {
612 uint8_t found = FALSE;
613 RPMessage_NameEntry *p;
614 IpcUtils_QElem *elem, *head;
616 if (FALSE == IpcUtils_QisEmpty(&module.announcedEndpts))
617 {
618 elem = head = (IpcUtils_QElem *) IpcUtils_QgetHeadNode(&module.announcedEndpts);
619 do
620 {
621 p = (RPMessage_NameEntry*)elem;
622 if( (NULL != p) &&
623 (strncmp(p->name, name, SERVICENAMELEN) == 0) &&
624 (p->procId == procId || procId == RPMESSAGE_ANY))
625 {
626 found = TRUE;
627 *remoteEndPt = p->endPt;
628 *remoteProcId = p->procId;
629 #if DEBUG_PRINT
630 SystemP_printf("RPMessage_lookupName found endpoint %d, remote %d\n",
631 *remoteEndPt, *remoteProcId);
632 #endif
633 break;
634 }
635 elem = (IpcUtils_QElem *) IpcUtils_Qnext(elem);
636 } while (elem != head);
637 }
638 return found;
639 }
641 /**
642 * \brief RPMessage_waitForProc
643 */
644 int32_t RPMessage_getRemoteEndPt(uint32_t selfProcId, const char* name, uint32_t *remoteProcId,
645 uint32_t *remoteEndPt, uint32_t timeout)
646 {
647 int32_t key;
648 uint8_t lookupStatus = FALSE;
649 int32_t rtnVal = IPC_SOK;
650 void *semHandle;
651 RPMessage_Waiter taskWaiter;
652 uint32_t namelen;
653 Ipc_OsalPrms *pOsalPrms = &gIpcObject.initPrms.osalPrms;
655 namelen = strlen(name);
656 if ((namelen >= SERVICENAMELEN || namelen == 0))
657 {
658 rtnVal = IPC_EFAIL;
659 }
661 if (NULL != pOsalPrms)
662 {
663 if ((NULL == pOsalPrms->createMutex ||
664 NULL == pOsalPrms->lockMutex) ||
665 (NULL == pOsalPrms->deleteMutex))
666 {
667 rtnVal = IPC_EFAIL;
668 }
669 if ((NULL == pOsalPrms->lockHIsrGate) ||
670 (NULL == pOsalPrms->unLockHIsrGate))
671 {
672 rtnVal = IPC_EFAIL;
673 }
674 }
676 if (IPC_SOK == rtnVal)
677 {
678 semHandle = pOsalPrms->createMutex();
679 taskWaiter.semHandle = semHandle;
680 strncpy(taskWaiter.name, name, SERVICENAMELEN-1);
681 taskWaiter.name[SERVICENAMELEN-1] = '\0';
682 taskWaiter.procId = selfProcId;
683 taskWaiter.endPt = 0;
685 /* The order of steps is critical here. There must
686 * not be an unprotected time between calling
687 * RPMessage_lookupName() and the IpcUtils_Qput().
688 */
689 key = pOsalPrms->disableAllIntr();
690 lookupStatus = RPMessage_lookupName(selfProcId, name,
691 remoteProcId, remoteEndPt);
692 if(FALSE == lookupStatus)
693 {
694 IpcUtils_Qput(&module.waitingTasks, &taskWaiter.elem,
695 (void *)&taskWaiter);
696 }
697 pOsalPrms->restoreAllIntr(key);
699 if(FALSE == lookupStatus)
700 {
701 rtnVal = pOsalPrms->lockMutex(semHandle, timeout);
702 if(rtnVal == IPC_SOK)
703 {
704 /* The endPt and procId in taskWaiter is assigned
705 * by RPMessage_processAnnounceMsg() when it
706 * wakes up this task.
707 */
708 *remoteEndPt = taskWaiter.endPt;
709 *remoteProcId = taskWaiter.procId;
710 }
711 key = pOsalPrms->lockHIsrGate(module.gateSwi);
712 IpcUtils_Qremove((IpcUtils_QElem*)&taskWaiter.elem);
713 pOsalPrms->unLockHIsrGate(module.gateSwi, key);
714 }
716 pOsalPrms->deleteMutex(semHandle);
717 }
719 return rtnVal;
720 }
722 #ifndef IPC_EXCLUDE_CTRL_TASKS
724 /**
725 * \brief RPMessage_checkForMessages : This function checks for
726 * messages in all virtio that are associated with a endpoint
727 * pool. This operation has the side effect that it may find
728 * messages for end points that do not yet have an endpoint
729 * created for them. Those messages will be dropped.
730 */
731 static void RPMessage_checkForMessages(RPMessage_EndptPool *pool)
732 {
733 uint32_t c;
734 int32_t key;
736 for(c = 0; c < module.numCallbacks; c++)
737 {
738 /* Find callback for RX VQs that have matching pool. */
739 if(module.VQ_callbacks[c].pool == pool)
740 {
741 if(TRUE == Virtio_isReady(module.VQ_callbacks[c].vq))
742 {
743 key = gIpcObject.initPrms.osalPrms.lockHIsrGate(module.gateSwi);
744 RPMessage_swiFxn((uintptr_t)&module.VQ_callbacks[c], 0);
745 gIpcObject.initPrms.osalPrms.unLockHIsrGate(module.gateSwi, key);
746 }
747 }
748 }
749 }
750 #endif /* IPC_EXCLUDE_CTRL_TASKS */
752 #ifndef IPC_EXCLUDE_CTRL_TASKS
754 /**
755 * \brief RPMessage_ctrlMsgTask : Create an endpoint to receive
756 * control messages and dispatch any control messages
757 * received.
758 * This function runs in its own task.
759 */
760 static void RPMessage_ctrlMsgTask(uint32_t* arg0, uint32_t* arg1)
761 {
762 RPMessage_Object *obj = (RPMessage_Object *)arg0;
763 uint32_t remoteEndpoint;
764 uint32_t remoteProcId;
765 int32_t status;
766 uint16_t len = MSGBUFFERSIZE;
767 uint32_t buffer[MSGBUFFERSIZE/sizeof(uint32_t)]; /* alignment */
768 RPMessage_Announcement *amsg = (RPMessage_Announcement*)&buffer;
770 UNUSED(arg1);
772 while(1)
773 {
774 status = RPMessage_recv((RPMessage_Handle)obj, (void*)amsg, &len,
775 &remoteEndpoint, &remoteProcId,
776 IPC_RPMESSAGE_TIMEOUT_FOREVER);
777 if(status != IPC_SOK)
778 {
779 SystemP_printf("RPMessage_recv failed with code %d for endPt %d\n"
780 "RPMessage_ctrlMsgTask terminating early",
781 status, obj->endPt);
782 break;
783 }
785 if(amsg->ctrl.type == CNTRLMSG_ANNOUNCE)
786 {
787 #if DEBUG_PRINT
788 SystemP_printf("RPMessage_ctrlMsgTask ...CNTRLMSG_ANNOUNCE\n");
789 #endif
790 RPMessage_processAnnounceMsg((RPMessage_Announcement*)amsg,
791 remoteProcId);
792 }
793 else
794 {
795 SystemP_printf("Invalid cntrl msg type 0x%x from procId %d\n",
796 amsg->ctrl.type, remoteProcId);
797 }
798 }
799 }
801 /**
802 * \brief Kick off the control message task.
803 * Typically this is called from Main context.
804 * It is best to call this before setting the
805 * VQ callbacks to avoid dropping cntrl messages.
806 */
807 static int32_t RPMessage_startCtrlMsgTask(RPMessage_Params *params)
808 {
809 TaskP_Params tparams;
810 RPMessage_Object *obj;
811 uint32_t myEndpoint = 0;
812 int32_t retVal = IPC_SOK;
813 TaskP_Handle tskHandle = NULL;
815 /* Create the endpoint to receive control messages.
816 * This is done as early as possible to avoid missing
817 * any control messages.
818 */
819 params->requestedEndpt = IPC_CTRL_ENDPOINT_ID;
820 obj = RPMessage_rawCreate(params, &module.globalPool, &myEndpoint);
821 if(NULL != obj)
822 {
823 TaskP_Params_init(&tparams);
824 tparams.priority = 10;
825 tparams.arg0 = (uint32_t*)obj;
826 tparams.stacksize = params->stackSize;
827 tparams.stack = params->stackBuffer;
828 tskHandle = TaskP_create((void *) RPMessage_ctrlMsgTask, &tparams);
829 if(tskHandle == NULL)
830 {
831 retVal = IPC_EFAIL;
832 }
833 }
834 else
835 {
836 SystemP_printf("Failed to create control endpoint.\n");
837 retVal = IPC_EFAIL;
838 }
840 return retVal;
841 }
843 #endif /* IPC_EXCLUDE_CTRL_TASKS */
845 static RPMessage_Object* RPMessage_rawCreate(
846 RPMessage_Params *params,
847 RPMessage_EndptPool* pool,
848 uint32_t *endPt)
849 {
850 RPMessage_Object *obj = NULL;
851 uint8_t found = FALSE;
852 int32_t i;
853 uint16_t queueIndex = 0;
854 int32_t key;
855 uint32_t objSize = RPMessage_getObjMemRequired();
856 Ipc_OsalPrms *pOsalPrms = &gIpcObject.initPrms.osalPrms;
857 int32_t status = IPC_SOK;
859 /* Returning NULL, here Fix ME TBD
860 This function error checks would require an overhaul */
861 if ( (NULL == pOsalPrms) ||
862 (NULL == pOsalPrms->lockHIsrGate) ||
863 (NULL == pOsalPrms->unLockHIsrGate))
864 {
865 status = IPC_EFAIL;
866 }
868 if(IPC_SOK == status)
869 {
870 key = pOsalPrms->lockHIsrGate(module.gateSwi);
872 /* Allocate the endPt */
873 if (params->requestedEndpt == RPMESSAGE_ANY)
874 {
875 /* Search the array for a free slot above reserved: */
876 for (i = RPMessage_MAX_RESERVED_ENDPOINT + 1;
877 (i < MAXENDPOINTS) && (found == 0U); i++)
878 {
879 if (RPMessage_lookupEndpt(pool, i) == NULL)
880 {
881 queueIndex = i;
882 found = TRUE;
883 break;
884 }
885 }
886 }
887 else if (params->requestedEndpt <= RPMessage_MAX_RESERVED_ENDPOINT)
888 {
889 if (RPMessage_lookupEndpt(pool, params->requestedEndpt) == NULL)
890 {
891 queueIndex = params->requestedEndpt;
892 found = TRUE;
893 }
894 }
895 }
897 if ((FALSE == found) ||
898 (params->numBufs < 1) ||
899 (params->bufSize < ((params->numBufs * MSGBUFFERSIZE) + objSize)))
900 {
901 status = IPC_EFAIL;
902 }
904 if(IPC_SOK == status)
905 {
906 obj = (RPMessage_Object *) params->buf;
907 if (NULL != obj)
908 {
909 obj->heapParams.blockSize = MSGBUFFERSIZE;
910 obj->heapParams.numBlocks = params->numBufs;
911 obj->heapParams.buf = (void*)((uintptr_t)params->buf + objSize);
912 obj->heapParams.bufSize = params->bufSize - objSize ;
913 obj->heapParams.align = HEAPALIGNMENT;
914 status = IpcUtils_HeapCreate(&obj->heap, &obj->heapParams);
915 if (IPC_SOK == status)
916 {
917 /* Allocate a semaphore to signal when messages received: */
918 if (NULL != pOsalPrms->createMutex)
919 {
920 obj->semHandle = pOsalPrms->createMutex();
921 }
923 /* Create our queue of to be received messages: */
924 IpcUtils_Qcreate(&obj->queue);
926 /* Store our endPt, and object: */
927 obj->endPt = queueIndex;
928 RPMessage_assignEndpt(pool, queueIndex, obj);
930 /* See RPMessage_unblock() */
931 obj->unblocked = FALSE;
932 obj->pool = pool;
933 obj->recv_buffer = NULL;
934 *endPt = queueIndex;
935 }
936 else
937 {
938 obj = NULL;
939 }
941 pOsalPrms->unLockHIsrGate(module.gateSwi, key);
942 }
943 }
945 return (obj);
946 }
948 int32_t RPMessage_lateInit(uint32_t proc)
949 {
950 uint32_t c;
951 uint32_t tx_vqId, rx_vqId;
952 int32_t retVal = IPC_SOK;
953 Ipc_OsalPrms *pOsalPrms = &gIpcObject.initPrms.osalPrms;
955 if(TRUE == VirtioIPC_getVirtQueues(VIRTIOIPC_RPMSG, proc, 0, &tx_vqId, &rx_vqId))
956 {
957 uintptr_t arg0;
958 c = module.numCallbacks;
959 module.numCallbacks++;
961 /* setup the receiving path */
962 module.VQ_callbacks[c].pool = &module.globalPool;
963 module.VQ_callbacks[c].vq = Virtio_getHandle(proc, VIRTIO_RX);
965 arg0 = (uintptr_t)&module.VQ_callbacks[c];
966 if (TRUE == Virtio_isRemoteLinux(proc))
967 {
968 pOsalPrms->createHIsr(&module.VQ_callbacks[c].swi,
969 &RPMessage_swiLinuxFxn, (void *)arg0);
970 }
971 else
972 {
973 pOsalPrms->createHIsr(&module.VQ_callbacks[c].swi,
974 &RPMessage_swiFxn, (void *)arg0);
975 }
976 Virtio_setCallback(proc, virtio_callback, (uint32_t *)&module.VQ_callbacks[c]);
978 /* setup the sending path */
979 module.tx_VQs[proc] = Virtio_getHandle(proc, VIRTIO_TX);
980 }
981 else
982 {
983 retVal = IPC_EFAIL;
984 }
986 #ifndef IPC_EXCLUDE_CTRL_TASKS
987 if(retVal == IPC_SOK)
988 RPMessage_checkForMessages(&module.globalPool);
989 #endif /* IPC_EXCLUDE_CTRL_TASKS */
991 return retVal;
992 }
994 /**
995 * \brief RPMessage_init : Initializing the framework
996 */
997 int32_t RPMessage_init(RPMessage_Params *params)
998 {
999 uint32_t p;
1000 uint32_t c;
1001 uint32_t tx_vqId, rx_vqId;
1002 int32_t retVal = IPC_SOK;
1003 Ipc_OsalPrms *pOsalPrms = &gIpcObject.initPrms.osalPrms;
1005 /* Clear module state */
1006 memset(&module, 0, sizeof(module));
1008 /* Gate to protect module object and lists: */
1009 if ((1U == is_aligned(params->buf,HEAPALIGNMENT)) &&
1010 (NULL != pOsalPrms->createHIsrGate) &&
1011 (NULL != pOsalPrms->createHIsr))
1012 {
1013 module.gateSwi = pOsalPrms->createHIsrGate();
1014 }
1015 else
1016 {
1017 retVal = IPC_EFAIL;
1018 SystemP_printf("RPMessage_init : Memory misalignment or invalid HIstGate fxn\n");
1019 }
1021 if( retVal != IPC_EFAIL)
1022 {
1023 IpcUtils_Qcreate(&module.announcedEndpts);
1024 IpcUtils_Qcreate(&module.waitingTasks);
1026 #ifndef IPC_EXCLUDE_CTRL_TASKS
1027 /* Call startCtrlMsgTask() before setting the VQ
1028 * callbacks to avoid dropping control messages.
1029 */
1030 retVal = RPMessage_startCtrlMsgTask(params);
1031 #endif /* IPC_EXCLUDE_CTRL_TASKS */
1033 /* Connect to the VQs by setting the VQ callbacks and
1034 * creating the assocated SWIs. Once the callbacks
1035 * are installed is it possilbe to drop messages if
1036 * the dest endpoint has not yet been created.
1037 */
1038 for(p = 0; ((p < IPC_MAX_PROCS) && (IPC_SOK == retVal)); p++)
1039 {
1040 if(TRUE == VirtioIPC_getVirtQueues(VIRTIOIPC_RPMSG, p, 0, &tx_vqId, &rx_vqId))
1041 {
1042 uintptr_t arg0;
1043 c = module.numCallbacks;
1044 module.numCallbacks++;
1046 /* setup the receiving path */
1047 module.VQ_callbacks[c].pool = &module.globalPool;
1048 module.VQ_callbacks[c].vq = Virtio_getHandle(p, VIRTIO_RX);
1050 arg0 = (uintptr_t)&module.VQ_callbacks[c];
1051 if (TRUE == Virtio_isRemoteLinux(p))
1052 {
1053 pOsalPrms->createHIsr(&module.VQ_callbacks[c].swi,
1054 &RPMessage_swiLinuxFxn, (void *)arg0);
1055 }
1056 else
1057 {
1058 pOsalPrms->createHIsr(&module.VQ_callbacks[c].swi,
1059 &RPMessage_swiFxn, (void *)arg0);
1060 }
1061 Virtio_setCallback(p, virtio_callback, (uint32_t *)&module.VQ_callbacks[c]);
1063 /* setup the sending path */
1064 module.tx_VQs[p] = Virtio_getHandle(p, VIRTIO_TX);
1065 }
1066 else
1067 {
1068 module.tx_VQs[p] = NULL;
1069 }
1070 }
1072 #ifndef IPC_EXCLUDE_CTRL_TASKS
1073 /*
1074 * At this point, the control end point would not have been created.
1075 * Let apps, decide when to process pending messages
1076 */
1077 RPMessage_checkForMessages(&module.globalPool);
1079 #endif /* IPC_EXCLUDE_CTRL_TASKS */
1080 }
1082 return retVal;
1083 }
1086 /*
1087 * ======== RPMessage_create ========
1088 */
1089 RPMessage_Handle RPMessage_create(RPMessage_Params *params, uint32_t *endPt)
1090 {
1091 RPMessage_Object *obj = NULL;
1092 RPMessage_Params defaultParams;
1094 if(params == NULL)
1095 {
1096 params = &defaultParams;
1097 RPMessageParams_init(params);
1098 }
1100 if( 0U == is_aligned(params->buf,HEAPALIGNMENT))
1101 {
1102 SystemP_printf("RPMessage_create : Memory alignment failed\n");
1103 }
1104 else
1105 {
1106 obj = RPMessage_rawCreate(params, &module.globalPool, endPt);
1107 }
1109 return (RPMessage_Handle)obj;
1110 }
1112 /**
1113 * \brief RPMessage_deinit : Tear down the module
1114 */
1115 void RPMessage_deInit(void)
1116 {
1117 uint32_t c;
1119 for(c = 0; c < module.numCallbacks; c++)
1120 {
1121 gIpcObject.initPrms.osalPrms.deleteHIsr(&(module.VQ_callbacks[c].swi));
1122 }
1124 if (NULL != gIpcObject.initPrms.osalPrms.deleteHIsrGate)
1125 {
1126 gIpcObject.initPrms.osalPrms.deleteHIsrGate(&module.gateSwi);
1127 }
1128 }
1130 /*
1131 * ======== RPMessage_delete ========
1132 */
1133 int32_t RPMessage_delete(RPMessage_Handle *handlePtr)
1134 {
1135 int32_t status = IPC_EFAIL;
1136 RPMessage_Object *obj;
1137 RPMessage_MsgElem *payload;
1138 int32_t key;
1139 Ipc_OsalPrms *pOsalPrms = &gIpcObject.initPrms.osalPrms;
1141 if (NULL != pOsalPrms)
1142 {
1143 if ((NULL != pOsalPrms->lockHIsrGate) &&
1144 (NULL != pOsalPrms->unLockHIsrGate))
1145 {
1146 status = IPC_SOK;
1147 }
1148 }
1149 if ((handlePtr && (obj = (RPMessage_Object *)(*handlePtr))) &&
1150 (IPC_SOK == status))
1151 {
1152 /* Null out our slot in the endpoint pool. */
1153 key = pOsalPrms->lockHIsrGate(module.gateSwi);
1154 RPMessage_assignEndpt(obj->pool, obj->endPt, NULL);
1155 obj->pool = NULL;
1156 pOsalPrms->unLockHIsrGate(module.gateSwi, key);
1158 if (NULL != pOsalPrms->deleteMutex)
1159 {
1160 pOsalPrms->deleteMutex(obj->semHandle);
1161 }
1163 key = gIpcObject.initPrms.osalPrms.disableAllIntr();
1165 /* Free/discard all queued message buffers: */
1166 while (0U == IpcUtils_QisEmpty(&obj->queue))
1167 {
1168 payload = (RPMessage_MsgElem *)IpcUtils_QgetHead(&obj->queue);
1169 if(NULL != payload)
1170 {
1171 IpcUtils_HeapFree(&obj->heap, (void *)payload, MSGBUFFERSIZE);
1172 }
1173 }
1175 gIpcObject.initPrms.osalPrms.restoreAllIntr(key);
1177 IpcUtils_HeapDelete(&obj->heap);
1179 IpcUtils_Qdelete(&(obj->queue));
1181 *handlePtr = NULL;
1182 }
1184 return(status);
1185 }
1187 /*
1188 * ======== RPMessage_recv ========
1189 */
1190 int32_t RPMessage_recv(RPMessage_Handle handle, void* data, uint16_t *len,
1191 uint32_t *rplyEndPt, uint32_t *rplyProcId, uint32_t timeout)
1192 {
1193 #ifndef IPC_EXCLUDE_BLOCKING_RX
1194 int32_t status = IPC_SOK;
1195 RPMessage_Object *obj = (RPMessage_Object *)handle;
1196 int32_t semStatus;
1197 uint8_t skiplist = FALSE;
1198 RPMessage_MsgElem *payload;
1199 uint32_t key;
1200 /* Fix ME TBD, skipping the null tests, as this function check's/error
1201 handling would require an overhaul */
1202 Ipc_OsalPrms *pOsalPrms = &gIpcObject.initPrms.osalPrms;
1204 key = pOsalPrms->lockHIsrGate(module.gateSwi);
1205 if (TRUE == IpcUtils_QisEmpty(&obj->queue))
1206 {
1207 obj->recv_buffer = data;
1208 skiplist = TRUE;
1209 }
1210 pOsalPrms->unLockHIsrGate(module.gateSwi, key);
1212 /* Block until notified. */
1213 semStatus = IPC_SOK;
1214 semStatus = pOsalPrms->lockMutex(obj->semHandle, timeout);
1216 if (semStatus == IPC_ETIMEOUT)
1217 {
1218 status = IPC_ETIMEOUT;
1219 }
1220 else if (TRUE == obj->unblocked)
1221 {
1222 status = IPC_E_UNBLOCKED;
1223 }
1224 else if(TRUE == skiplist)
1225 {
1226 *len = obj->payload.len;
1227 *rplyEndPt = obj->payload.src;
1228 *rplyProcId = obj->payload.procId;
1229 }
1230 else
1231 {
1232 key = gIpcObject.initPrms.osalPrms.disableAllIntr();
1234 payload = (RPMessage_MsgElem *)IpcUtils_QgetHead(&obj->queue);
1235 if ( (NULL == payload) ||
1236 (payload == (RPMessage_MsgElem *)&obj->queue))
1237 {
1238 status = IPC_EFAIL;
1239 }
1241 if(status != IPC_EFAIL)
1242 {
1243 /* Now, copy payload to client and free our internal msg */
1244 memcpy(data, payload->data, payload->len);
1245 *len = payload->len;
1246 *rplyEndPt = payload->src;
1247 *rplyProcId = payload->procId;
1248 IpcUtils_HeapFree(&obj->heap, (void *)payload,
1249 (payload->len + sizeof(RPMessage_MsgElem)));
1250 gIpcObject.initPrms.osalPrms.restoreAllIntr(key);
1251 }
1252 }
1254 return (status);
1255 #else
1257 return (IPC_EUNSUPPORTED);
1259 #endif /* IPC_EXCLUDE_BLOCKING_RX */
1260 }
1262 /*
1263 * ======== RPMessage_recvNb ========
1264 */
1265 int32_t RPMessage_recvNb(RPMessage_Handle handle, void* data, uint16_t *len,
1266 uint32_t *rplyEndPt, uint32_t *rplyProcId)
1267 {
1268 RPMessage_Object *obj;
1269 RPMessage_MsgElem *payload;
1270 uint32_t key;
1271 int32_t status = IPC_EBADARGS;
1273 if (((NULL != data) && (NULL != len)) &&
1274 ((NULL != rplyEndPt) && (NULL != rplyProcId)))
1275 {
1276 obj = (RPMessage_Object *)handle;
1277 status = IPC_ETIMEOUT;
1278 if (FALSE == IpcUtils_QisEmpty(&obj->queue))
1279 {
1280 key = gIpcObject.initPrms.osalPrms.disableAllIntr();
1282 payload = (RPMessage_MsgElem *)IpcUtils_QgetHead(&obj->queue);
1283 if (payload != (RPMessage_MsgElem *)&obj->queue)
1284 {
1285 /* Now, copy payload to client and free our internal msg */
1286 memcpy(data, payload->data, payload->len);
1287 *len = payload->len;
1288 *rplyEndPt = payload->src;
1289 *rplyProcId = payload->procId;
1291 IpcUtils_HeapFree(&obj->heap, (void *)payload,
1292 (payload->len + sizeof(RPMessage_MsgElem)));
1294 status = IPC_SOK;
1295 }
1296 else
1297 {
1298 /* No elements in the queue, but why? */
1299 status = IPC_EFAIL;
1300 }
1301 gIpcObject.initPrms.osalPrms.restoreAllIntr(key);
1302 }
1303 }
1305 return (status);
1306 }
1309 /*
1310 * ======== RPMessage_rawSend ========
1311 */
1312 static int32_t RPMessage_rawSend(Virtio_Handle vq,
1313 uint32_t dstEndPt,
1314 uint32_t srcEndPt,
1315 void* data,
1316 uint16_t len)
1317 {
1318 int32_t status = IPC_SOK;
1319 int32_t token = 0;
1320 int32_t key;
1321 int32_t length = 0;
1322 uint32_t bufSize;
1323 RPMessage_MsgHeader* msg = NULL;
1324 Ipc_OsalPrms *pOsalPrms = &gIpcObject.initPrms.osalPrms;
1326 bufSize = sizeof(RPMessage_MsgHeader) + len;
1328 if (NULL != pOsalPrms)
1329 {
1330 if ((NULL != pOsalPrms->lockHIsrGate) &&
1331 (NULL != pOsalPrms->unLockHIsrGate))
1332 {
1333 /* Send to remote processor: */
1334 key = pOsalPrms->lockHIsrGate(module.gateSwi);
1335 token = Virtio_getAvailBuf(vq, (void **)&msg, &length);
1336 pOsalPrms->unLockHIsrGate(module.gateSwi, key);
1337 }
1338 }
1339 if(!msg)
1340 {
1341 SystemP_printf("RPMessage_rawSend ...NULL MsgHdr\n");
1342 status = IPC_EFAIL;
1343 }
1344 if(length < bufSize)
1345 {
1346 SystemP_printf("RPMessage_rawSend ...length %d, reqrd %d\n", length, bufSize);
1347 status = IPC_EFAIL;
1348 }
1349 if(status != IPC_EFAIL)
1350 {
1351 if (token >= 0)
1352 {
1353 /* Copy the payload and set message header: */
1354 memcpy(msg->payload, data, len);
1355 msg->dataLen = len;
1356 msg->dstAddr = dstEndPt;
1357 msg->srcAddr = srcEndPt;
1358 msg->flags = 0;
1359 msg->srcProcId = Ipc_mpGetSelfId();
1361 key = pOsalPrms->lockHIsrGate(module.gateSwi);
1362 Virtio_addUsedBuf(vq, token, bufSize);
1363 Virtio_kick(vq);
1364 pOsalPrms->unLockHIsrGate(module.gateSwi, key);
1365 }
1366 else
1367 {
1368 SystemP_printf("RPMessage_rawSend ...Invalid token %d\n", token);
1369 status = IPC_EFAIL;
1370 }
1371 }
1373 return (status);
1374 }
1376 /*
1377 * ======== RPMessage_send ========
1378 */
1379 int32_t RPMessage_send(RPMessage_Handle handle, uint32_t procId, uint32_t dstEndPt,
1380 uint32_t srcEndPt, void* data, uint16_t len)
1381 {
1382 Virtio_Handle vq;
1383 uint32_t endPt;
1384 int32_t status = IPC_SOK;
1386 if(procId >= IPC_MAX_PROCS)
1387 {
1388 status = IPC_EFAIL;
1389 }
1391 if(procId == Ipc_mpGetSelfId())
1392 {
1393 status = IPC_EFAIL;
1394 }
1396 if(status != IPC_EFAIL)
1397 {
1398 vq = module.tx_VQs[procId];
1399 if(NULL == vq)
1400 {
1401 SystemP_printf("RPMessage_send ...NULL vq\n");
1402 status = IPC_EFAIL;
1403 }
1404 else
1405 {
1406 endPt = (handle == NULL) ? srcEndPt : handle->endPt;
1407 status = RPMessage_rawSend(vq, dstEndPt, endPt, data, len);
1408 }
1409 }
1411 return status;
1412 }
1415 /*
1416 * ======== RPMessage_unblock ========
1417 */
1418 void RPMessage_unblock(RPMessage_Handle handle)
1419 {
1420 RPMessage_Object *obj = (RPMessage_Object *)handle;
1422 /* Set instance to 'unblocked' state, and post */
1423 obj->unblocked = TRUE;
1425 if (NULL != gIpcObject.initPrms.osalPrms.unlockMutex)
1426 {
1427 gIpcObject.initPrms.osalPrms.unlockMutex(obj->semHandle);
1428 }
1429 }
1431 #ifndef IPC_EXCLUDE_INIT_PARAMS_INIT
1432 void IpcInitPrms_init(uint32_t instId, Ipc_InitPrms *initPrms)
1433 {
1434 if(NULL != initPrms)
1435 {
1436 memset(initPrms, 0, sizeof(*initPrms));
1437 initPrms->instId = instId;
1439 initPrms->virtToPhyFxn = NULL;
1440 initPrms->phyToVirtFxn = NULL;
1442 IpcOsalPrms_init(&initPrms->osalPrms);
1443 }
1445 return;
1446 }
1447 #endif /* IPC_EXCLUDE_INIT_PARAMS_INIT */
1449 Ipc_Object *getIpcObjInst(uint32_t instId)
1450 {
1451 return &gIpcObject;
1452 }
1454 int32_t Ipc_init(Ipc_InitPrms *cfg)
1455 {
1456 int32_t retVal = IPC_EINVALID_PARAMS;
1458 memset(&gIpcObject, 0, sizeof(gIpcObject));
1460 #ifndef IPC_EXCLUDE_INIT_PARAMS_INIT
1461 if (NULL == cfg)
1462 {
1463 IpcInitPrms_init(0U, &gIpcObject.initPrms);
1465 Ipc_mailboxModuleStartup();
1467 retVal = IPC_SOK;
1468 }
1469 else
1470 #endif /* IPC_EXCLUDE_INIT_PARAMS_INIT */
1471 {
1472 if (0U == cfg->instId)
1473 {
1474 if ((NULL == cfg->osalPrms.disableAllIntr) ||
1475 (NULL == cfg->osalPrms.restoreAllIntr))
1476 {
1477 retVal = IPC_EINVALID_PARAMS;
1478 }
1479 else
1480 {
1481 memcpy(&gIpcObject.initPrms, cfg, sizeof(gIpcObject.initPrms));
1482 retVal = IPC_SOK;
1483 }
1484 }
1485 }
1486 if (IPC_SOK == retVal)
1487 {
1488 IpcUtils_Init(&gIpcObject.initPrms.osalPrms);
1489 }
1490 gIpcObject.instId = 0U;
1492 return (retVal);
1493 }
1495 int32_t Ipc_deinit(void)
1496 {
1497 int32_t retVal = IPC_SOK;
1499 return (retVal);
1500 }
1502 void Ipc_newMessageIsr(uint32_t srcProcId)
1503 {
1504 #ifdef IPC_EXCLUDE_INTERRUPT_REG
1505 Ipc_mailboxIsr(srcProcId);
1506 #endif /* IPC_EXCLUDE_INTERRUPT_REG */
1508 return;
1509 }