Merge pull request #17 in PROCESSOR-SDK/pdk from PRSDK-7323 to master
[processor-sdk/pdk.git] / packages / ti / drv / ipc / src / ipc_api.c
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
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
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
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
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
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
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)
232     return (((RPMessage_Object**)(p))[(e)]);
235 inline void RPMessage_assignEndpt(void* p, uint32_t e, RPMessage_Object* obj)
237     (((RPMessage_Object**)(p))[(e)] = (obj));
240 inline void UNUSED(const uint32_t* x)
242     (void)(x);
245 inline uint8_t is_aligned(const void* ptr, uint32_t byteCnt)
247     uint8_t retVal;
248     uint32_t bufAddr = (uint32_t)(uintptr_t)ptr;
249     retVal = (0 == (bufAddr%byteCnt)) ? TRUE : FALSE;
250     return retVal;
255 int32_t RPMessageParams_init(RPMessage_Params *params)
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);
274 uint32_t RPMessage_getMessageBufferSize(void)
276     return MSGBUFFERSIZE;
279 uint32_t RPMessage_getObjMemRequired(void)
281     uint32_t objSize = sizeof(RPMessage_Object);
282     objSize = ((objSize + HEAPALIGNMENT-1) & ~(HEAPALIGNMENT-1));
283     return objSize;
287 RPMessage_Object*  RPMessage_allocObject(void)
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;
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)
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;
386 /**
387  * \brief RPMessage SWI function to talk to Linux
388  */
389 static void RPMessage_swiLinuxFxn(uintptr_t arg0, uintptr_t arg1)
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     }
414 /**
415  * \brief RPMessage SWI function
416  */
417 static void RPMessage_swiFxn(uintptr_t arg0, uintptr_t arg1)
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     }
432 /**
433  *  \brief virtio_callback - This function executes in HWI context
434  */
435 static void virtio_callback(uint32_t* priv)
437     RPMessage_CallbackData *cbdata = (RPMessage_CallbackData*)priv;
439     if (NULL != cbdata)
440     {
441         gIpcObject.initPrms.osalPrms.postHIsr(&cbdata->swi);
442     }
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)
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;
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)
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     }
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)
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;
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)
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;
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)
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     }
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)
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     }
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)
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;
843 #endif /* IPC_EXCLUDE_CTRL_TASKS */
845 static RPMessage_Object* RPMessage_rawCreate(
846         RPMessage_Params *params,
847         RPMessage_EndptPool* pool,
848         uint32_t *endPt)
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);
948 int32_t RPMessage_lateInit(uint32_t proc)
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;
994 /**
995  *  \brief RPMessage_init : Initializing the framework
996  */
997 int32_t RPMessage_init(RPMessage_Params *params)
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;
1086 /*
1087  *  ======== RPMessage_create ========
1088  */
1089 RPMessage_Handle RPMessage_create(RPMessage_Params *params, uint32_t *endPt)
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;
1112 /**
1113  *  \brief RPMessage_deinit : Tear down the module
1114  */
1115 void RPMessage_deInit(void)
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     }
1130 /*
1131  *  ======== RPMessage_delete ========
1132  */
1133 int32_t RPMessage_delete(RPMessage_Handle *handlePtr)
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);
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)
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 */
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)
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);
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)
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);
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)
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;
1415 /*
1416  *  ======== RPMessage_unblock ========
1417  */
1418 void RPMessage_unblock(RPMessage_Handle handle)
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     }
1431 #ifndef IPC_EXCLUDE_INIT_PARAMS_INIT
1432 void IpcInitPrms_init(uint32_t instId, Ipc_InitPrms *initPrms)
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;
1447 #endif /* IPC_EXCLUDE_INIT_PARAMS_INIT */
1449 Ipc_Object *getIpcObjInst(uint32_t instId)
1451     return &gIpcObject;
1454 int32_t Ipc_init(Ipc_InitPrms *cfg)
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);
1495 int32_t Ipc_deinit(void)
1497     int32_t  retVal = IPC_SOK;
1499     return (retVal);
1502 void Ipc_newMessageIsr(uint32_t srcProcId)
1504 #ifdef IPC_EXCLUDE_INTERRUPT_REG
1505     Ipc_mailboxIsr(srcProcId);
1506 #endif /* IPC_EXCLUDE_INTERRUPT_REG */
1508     return;