7015f7b5ccdbe7bc5158a8875b1c84c27d4b1c5b
[ipc/ipcdev.git] / packages / ti / ipc / transports / TransportVirtio.c
1 /*
2  * Copyright (c) 2012-2013, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== TransportVirtio.c ========
34  */
36 #include <string.h>
38 #include <xdc/std.h>
40 #include <xdc/runtime/System.h>
41 #include <xdc/runtime/Assert.h>
42 #include <xdc/runtime/Error.h>
43 #include <xdc/runtime/Memory.h>
44 #include <xdc/runtime/Main.h>
45 #include <xdc/runtime/Registry.h>
46 #include <xdc/runtime/Log.h>
47 #include <xdc/runtime/Diags.h>
50 #include <ti/sdo/utils/_MultiProc.h>
51 #include <ti/sdo/ipc/_MessageQ.h>
53 #include <ti/ipc/rpmsg/virtio_ring.h>
54 #include <ti/ipc/rpmsg/_VirtQueue.h>
55 #include <ti/ipc/rpmsg/Rpmsg.h>
56 #include <ti/ipc/rpmsg/NameMap.h>
58 #include <ti/ipc/rpmsg/_MessageQCopy.h>
59 #include <ti/ipc/rpmsg/MessageQCopy.h>
61 #include <ti/ipc/namesrv/_NameServerRemoteRpmsg.h>
63 #include "_TransportVirtio.h"
64 #include "package/internal/TransportVirtio.xdc.h"
66 /* Maximum RPMSG payload: */
67 #define MAX_PAYLOAD (RPMSG_BUF_SIZE - sizeof(Rpmsg_Header))
69 /* Addresses below this are assumed to be bound to MessageQ objects: */
70 #define RPMSG_RESERVED_ADDRESSES     (1024)
72 /* Name of the rpmsg socket on host: */
73 #define RPMSG_SOCKET_NAME  "rpmsg-proto"
75 static Void transportCallbackFxn(MessageQCopy_Handle msgq, UArg arg, Ptr data,
76                                       UInt16 dataLen, UInt32 srcAddr);
78 /*
79  *************************************************************************
80  *                       Instance functions
81  *************************************************************************
82  */
84 /*
85  *  ======== TransportVirtio_Instance_init ========
86  *
87  */
88 #define FXNN "TransportVirtio_Instance_init"
89 Int TransportVirtio_Instance_init(TransportVirtio_Object *obj,
90         UInt16 remoteProcId, const TransportVirtio_Params *params,
91         Error_Block *eb)
92 {
93     Bool        flag = FALSE;
94     UInt32      myEndpoint = 0;
96     Log_print1(Diags_INFO, FXNN": remoteProc: %d\n", remoteProcId);
98     /* This MessageQ Transport over RPMSG only talks to the "HOST" for now: */
99     Assert_isTrue(remoteProcId == MultiProc_getId("HOST"), NULL);
100     MessageQCopy_init(remoteProcId);
102     /* set object fields */
103     obj->priority     = params->priority;
104     obj->remoteProcId = remoteProcId;
106     /* Announce our "MessageQ" service to the HOST: */
107     NameMap_register(RPMSG_SOCKET_NAME, RPMSG_SOCKET_NAME, RPMSG_MESSAGEQ_PORT);
109     /* Associate incomming messages with this transport's callback fxn: */
110     obj->msgqHandle = MessageQCopy_create(RPMSG_MESSAGEQ_PORT,
111                                           transportCallbackFxn,
112                                           (UArg)obj,
113                                           &myEndpoint);
115     /*
116      * TBD: The following should be set via a ns_announcement from Linux side.
117      * Setting this now will cause NameServer requests from BIOS side to
118      * timeout (benignly), if the app calls MessageQ_open() in a loop.
119      * Ideally, a NameMap module needs to allow registration for announcements.
120      */
121     NameServerRemote_SetNameServerPort(NAME_SERVER_RPMSG_ADDR);
123     if (obj->msgqHandle) {
124         /* Register the transport with MessageQ */
125         flag = ti_sdo_ipc_MessageQ_registerTransport(
126             TransportVirtio_Handle_upCast(obj), remoteProcId, params->priority);
127     }
129     if (flag == FALSE) {
130         return (2);
131     }
133     return (0);
135 #undef FXNN
137 /*
138  *  ======== TransportVirtio_Instance_finalize ========
139  */
140 #define FXNN "TransportVirtio_Instance_finalize"
141 Void TransportVirtio_Instance_finalize(TransportVirtio_Object *obj, Int status)
143     Log_print0(Diags_ENTRY, "--> "FXNN);
145     /* Announce our "MessageQ" service is going away: */
146     NameMap_unregister(RPMSG_SOCKET_NAME, RPMSG_SOCKET_NAME,
147             RPMSG_MESSAGEQ_PORT);
149     switch(status) {
150         case 0: /* MessageQ_registerTransport succeeded */
151             ti_sdo_ipc_MessageQ_unregisterTransport(obj->remoteProcId,
152                 obj->priority);
153             /* fall thru OK */
154         case 1: /* NOT USED: Notify_registerEventSingle failed */
155         case 2: /* MessageQ_registerTransport failed */
156             break;
157     }
159     MessageQCopy_finalize();
161 #undef FXNN
164 /*
165  *  ======== TransportVirtio_put ========
166  *
167  *  Notes: In keeping with the semantics of IMessageQTransport_put(), we
168  *  simply return FALSE if the remote proc has made no buffers available in the
169  *  vring.
170  *  Otherwise, we could block here, waiting for the remote proc to add a buffer.
171  *  This implies that the remote proc must always have buffers available in the
172  *  vring in order for this side to send without failing!
173  *
174  *  Also, this is a copy-transport, to match the Linux side rpmsg.
175  */
176 #define FXNN "TransportVirtio_put"
177 Bool TransportVirtio_put(TransportVirtio_Object *obj, Ptr msg)
179     Int          status;
180     UInt         msgSize;
181     UInt16       dstAddr;
183     /* Send to remote processor: */
184     /* Assert msg->msgSize <= vring's max fixed buffer size */
185     msgSize = MessageQ_getMsgSize(msg);
186     Assert_isTrue(msgSize <= MAX_PAYLOAD, NULL);
187     dstAddr  = (((MessageQ_Msg)msg)->dstId & 0x0000FFFF);
189     Log_print3(Diags_INFO, FXNN": sending msg from: %d, to: %d, dataLen: %d",
190                   (IArg)RPMSG_MESSAGEQ_PORT, (IArg)dstAddr, (IArg)msgSize);
191     status = MessageQCopy_send(obj->remoteProcId, dstAddr, RPMSG_MESSAGEQ_PORT,
192                       msg, msgSize);
194     /* free the app's message */
195     if (((MessageQ_Msg)msg)->heapId != ti_sdo_ipc_MessageQ_STATICMSG) {
196        MessageQ_free(msg);
197     }
199     return (status == MessageQCopy_S_SUCCESS? TRUE: FALSE);
201 #undef FXNN
203 /*
204  *  ======== TransportVirtio_control ========
205  */
206 Bool TransportVirtio_control(TransportVirtio_Object *obj, UInt cmd,
207     UArg cmdArg)
209     return (FALSE);
212 /*
213  *  ======== TransportVirtio_getStatus ========
214  */
215 Int TransportVirtio_getStatus(TransportVirtio_Object *obj)
217     return (0);
220 /*
221  *************************************************************************
222  *                       Module functions
223  *************************************************************************
224  */
226 /*
227  *  ======== transportCallbackFxn ========
228  *
229  */
230 #define FXNN "transportCallbackFxn"
231 static Void transportCallbackFxn(MessageQCopy_Handle msgq, UArg arg, Ptr data,
232                                       UInt16 dataLen, UInt32 srcAddr)
234     UInt32            queueId;
235     MessageQ_Msg      msg;
236     MessageQ_Msg      buf = NULL;
237     UInt              msgSize;
238     NameServerRemote_Msg * nsrMsg;  /* Name Server Message */
240     Log_print0(Diags_ENTRY, "--> "FXNN);
242     Log_print3(Diags_INFO, FXNN": Received data: 0x%x from: %d, dataLen: %d",
243                   (IArg)data, (IArg)srcAddr, (IArg)dataLen);
244 #if 0
245 /* TBD: This logic needs to be put in a callback from the name service endpt: */
246     {
247         Int               nsPort = NAME_SERVER_PORT_INVALID;
249         /* See if this is an rpmsg ns announcment... : */
250         if (rpMsg->dstAddr != RPMSG_MESSAGEQ_PORT) {
251             if (rpMsg->dstAddr == RPMSG_NAMESERVICE_PORT) {
252                 nsMsg = (Rpmsg_NsMsg *)rpMsg->payload;
253                 Log_print3(Diags_USER1, FXNN": ns announcement "
254                   "from %d: %s, flag: %s\n",
255                   nsMsg->addr, (IArg)nsMsg->name,
256                   (IArg)(nsMsg->flags == RPMSG_NS_CREATE? "create":"destroy"));
257                 /* ... and if it is from our rpmsg-proto socket, save
258                  * the rpmsg src address as the NameServer reply address:
259                  */
260                 if (!strcmp(nsMsg->name, RPMSG_SOCKET_NAME) &&
261                     rpMsg->srcAddr == NAME_SERVER_RPMSG_ADDR) {
262                     if (nsMsg->flags == RPMSG_NS_CREATE) {
263                         nsPort = NAME_SERVER_RPMSG_ADDR;
264                     }
265                     else if (nsMsg->flags  == RPMSG_NS_DESTROY) {
266                         nsPort = NAME_SERVER_PORT_INVALID;
267                     }
268                     NameServerRemote_SetNameServerPort(nsPort);
269                 }
270             }
271             goto skip;
272         }
273     }
274 #endif
275     if(srcAddr >= RPMSG_RESERVED_ADDRESSES) {
276         /*
277          * This could either be a NameServer request or a MessageQ.
278          * Check the NameServerRemote_Msg reserved field to distinguish.
279          */
280         nsrMsg = (NameServerRemote_Msg *)data;
281         if (nsrMsg->reserved == NAMESERVER_MSG_TOKEN) {
282             /* Process the NameServer request/reply message: */
283             NameServerRemote_processMessage(nsrMsg);
284             goto exit;
285         }
286     }
288     /* Convert Rpmsg payload into a MessageQ_Msg: */
289     msg = (MessageQ_Msg)data;
291     Log_print4(Diags_INFO, FXNN": \n\tmsg->heapId: %d, "
292                "msg->msgSize: %d, msg->dstId: %d, msg->msgId: %d\n",
293                msg->heapId, msg->msgSize, msg->dstId, msg->msgId);
295     /* Alloc a message from msg->heapId to copy the msg */
296     msgSize = MessageQ_getMsgSize(msg);
297     buf = MessageQ_alloc(msg->heapId, msgSize);
299     /* Make sure buf is not NULL */
300     Assert_isTrue(buf != NULL, NULL);
302     /* copy the message to the buffer allocated. */
303     memcpy((Ptr)buf, (Ptr)msg, msgSize);
305     /*
306      * If the message received was statically allocated, reset the
307      * heapId, so the app can free it.
308      */
309     if (msg->heapId == ti_sdo_ipc_MessageQ_STATICMSG)  {
310         msg->heapId = 0;  /* for a copy transport, heap id is 0. */
311     }
313     /* get the queue id */
314     queueId = MessageQ_getDstQueue(msg);
316     /* Pass to desitination queue: */
317     MessageQ_put(queueId, buf);
319 exit:
320     Log_print0(Diags_EXIT, "<-- "FXNN);
323 /*
324  *  ======== TransportVirtio_setErrFxn ========
325  */
326 Void TransportVirtio_setErrFxn(TransportVirtio_ErrFxn errFxn)
328     /* Ignore the errFxn */