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 * ======== TransportRpmsg.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/_RPMessage.h>
59 #include <ti/ipc/rpmsg/RPMessage.h>
61 #include <ti/ipc/namesrv/_NameServerRemoteRpmsg.h>
63 #include "_TransportRpmsg.h"
64 #include "package/internal/TransportRpmsg.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(RPMessage_Handle msgq, UArg arg, Ptr data,
76 UInt16 dataLen, UInt32 srcAddr);
78 /*
79 *************************************************************************
80 * Instance functions
81 *************************************************************************
82 */
84 /*
85 * ======== TransportRpmsg_Instance_init ========
86 *
87 */
88 #define FXNN "TransportRpmsg_Instance_init"
89 Int TransportRpmsg_Instance_init(TransportRpmsg_Object *obj,
90 UInt16 remoteProcId, const TransportRpmsg_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 RPMessage_init(remoteProcId);
102 /* set object fields */
103 obj->priority = params->priority;
104 obj->remoteProcId = remoteProcId;
106 /* Announce our "MessageQ" service to the HOST: */
107 #ifdef RPMSG_NS_2_0
108 NameMap_register(RPMSG_SOCKET_NAME, RPMSG_SOCKET_NAME, RPMSG_MESSAGEQ_PORT);
109 #else
110 NameMap_register(RPMSG_SOCKET_NAME, RPMSG_MESSAGEQ_PORT);
111 #endif
113 /* Associate incomming messages with this transport's callback fxn: */
114 obj->msgqHandle = RPMessage_create(RPMSG_MESSAGEQ_PORT,
115 transportCallbackFxn,
116 (UArg)obj,
117 &myEndpoint);
119 /*
120 * TBD: The following should be set via a ns_announcement from Linux side.
121 * Setting this now will cause NameServer requests from BIOS side to
122 * timeout (benignly), if the app calls MessageQ_open() in a loop.
123 * Ideally, a NameMap module needs to allow registration for announcements.
124 */
125 NameServerRemote_SetNameServerPort(NAME_SERVER_RPMSG_ADDR);
127 if (obj->msgqHandle) {
128 /* Register the transport with MessageQ */
129 flag = ti_sdo_ipc_MessageQ_registerTransport(
130 TransportRpmsg_Handle_upCast(obj), remoteProcId, params->priority);
131 }
133 if (flag == FALSE) {
134 return (2);
135 }
137 return (0);
138 }
139 #undef FXNN
141 /*
142 * ======== TransportRpmsg_Instance_finalize ========
143 */
144 #define FXNN "TransportRpmsg_Instance_finalize"
145 Void TransportRpmsg_Instance_finalize(TransportRpmsg_Object *obj, Int status)
146 {
147 Log_print0(Diags_ENTRY, "--> "FXNN);
149 /* Announce our "MessageQ" service is going away: */
150 #ifdef RPMSG_NS_2_0
151 NameMap_unregister(RPMSG_SOCKET_NAME, RPMSG_SOCKET_NAME,
152 RPMSG_MESSAGEQ_PORT);
153 #else
154 NameMap_unregister(RPMSG_SOCKET_NAME, RPMSG_MESSAGEQ_PORT);
155 #endif
157 switch(status) {
158 case 0: /* MessageQ_registerTransport succeeded */
159 ti_sdo_ipc_MessageQ_unregisterTransport(obj->remoteProcId,
160 obj->priority);
161 /* fall thru OK */
162 case 1: /* NOT USED: Notify_registerEventSingle failed */
163 case 2: /* MessageQ_registerTransport failed */
164 break;
165 }
167 RPMessage_finalize();
169 #undef FXNN
170 }
172 /*
173 * ======== TransportRpmsg_put ========
174 *
175 * Notes: In keeping with the semantics of IMessageQTransport_put(), we
176 * simply return FALSE if the remote proc has made no buffers available in the
177 * vring.
178 * Otherwise, we could block here, waiting for the remote proc to add a buffer.
179 * This implies that the remote proc must always have buffers available in the
180 * vring in order for this side to send without failing!
181 *
182 * Also, this is a copy-transport, to match the Linux side rpmsg.
183 */
184 #define FXNN "TransportRpmsg_put"
185 Bool TransportRpmsg_put(TransportRpmsg_Object *obj, Ptr msg)
186 {
187 Int status;
188 UInt msgSize;
189 UInt16 dstAddr;
191 /* Send to remote processor: */
192 /* Assert msg->msgSize <= vring's max fixed buffer size */
193 msgSize = MessageQ_getMsgSize(msg);
194 Assert_isTrue(msgSize <= MAX_PAYLOAD, NULL);
195 dstAddr = (((MessageQ_Msg)msg)->dstId & 0x0000FFFF);
197 Log_print3(Diags_INFO, FXNN": sending msg from: %d, to: %d, dataLen: %d",
198 (IArg)RPMSG_MESSAGEQ_PORT, (IArg)dstAddr, (IArg)msgSize);
199 status = RPMessage_send(obj->remoteProcId, dstAddr, RPMSG_MESSAGEQ_PORT,
200 msg, msgSize);
202 /* free the app's message */
203 if (((MessageQ_Msg)msg)->heapId != ti_sdo_ipc_MessageQ_STATICMSG) {
204 MessageQ_free(msg);
205 }
207 return (status == RPMessage_S_SUCCESS? TRUE: FALSE);
208 }
209 #undef FXNN
211 /*
212 * ======== TransportRpmsg_control ========
213 */
214 Bool TransportRpmsg_control(TransportRpmsg_Object *obj, UInt cmd,
215 UArg cmdArg)
216 {
217 return (FALSE);
218 }
220 /*
221 * ======== TransportRpmsg_getStatus ========
222 */
223 Int TransportRpmsg_getStatus(TransportRpmsg_Object *obj)
224 {
225 return (0);
226 }
228 /*
229 *************************************************************************
230 * Module functions
231 *************************************************************************
232 */
234 /*
235 * ======== transportCallbackFxn ========
236 *
237 */
238 #define FXNN "transportCallbackFxn"
239 static Void transportCallbackFxn(RPMessage_Handle msgq, UArg arg, Ptr data,
240 UInt16 dataLen, UInt32 srcAddr)
241 {
242 UInt32 queueId;
243 MessageQ_Msg msg;
244 MessageQ_Msg buf = NULL;
245 UInt msgSize;
246 NameServerRemote_Msg * nsrMsg; /* Name Server Message */
248 Log_print0(Diags_ENTRY, "--> "FXNN);
250 Log_print3(Diags_INFO, FXNN": Received data: 0x%x from: %d, dataLen: %d",
251 (IArg)data, (IArg)srcAddr, (IArg)dataLen);
252 #if 0
253 /* TBD: This logic needs to be put in a callback from the name service endpt: */
254 {
255 Int nsPort = NAME_SERVER_PORT_INVALID;
257 /* See if this is an rpmsg ns announcment... : */
258 if (rpMsg->dstAddr != RPMSG_MESSAGEQ_PORT) {
259 if (rpMsg->dstAddr == RPMSG_NAMESERVICE_PORT) {
260 nsMsg = (Rpmsg_NsMsg *)rpMsg->payload;
261 Log_print3(Diags_USER1, FXNN": ns announcement "
262 "from %d: %s, flag: %s\n",
263 nsMsg->addr, (IArg)nsMsg->name,
264 (IArg)(nsMsg->flags == RPMSG_NS_CREATE? "create":"destroy"));
265 /* ... and if it is from our rpmsg-proto socket, save
266 * the rpmsg src address as the NameServer reply address:
267 */
268 if (!strcmp(nsMsg->name, RPMSG_SOCKET_NAME) &&
269 rpMsg->srcAddr == NAME_SERVER_RPMSG_ADDR) {
270 if (nsMsg->flags == RPMSG_NS_CREATE) {
271 nsPort = NAME_SERVER_RPMSG_ADDR;
272 }
273 else if (nsMsg->flags == RPMSG_NS_DESTROY) {
274 nsPort = NAME_SERVER_PORT_INVALID;
275 }
276 NameServerRemote_SetNameServerPort(nsPort);
277 }
278 }
279 goto skip;
280 }
281 }
282 #endif
283 if(srcAddr >= RPMSG_RESERVED_ADDRESSES) {
284 /*
285 * This could either be a NameServer request or a MessageQ.
286 * Check the NameServerRemote_Msg reserved field to distinguish.
287 */
288 nsrMsg = (NameServerRemote_Msg *)data;
289 if (nsrMsg->reserved == NAMESERVER_MSG_TOKEN) {
290 /* Process the NameServer request/reply message: */
291 NameServerRemote_processMessage(nsrMsg);
292 goto exit;
293 }
294 }
296 /* Convert Rpmsg payload into a MessageQ_Msg: */
297 msg = (MessageQ_Msg)data;
299 Log_print4(Diags_INFO, FXNN": \n\tmsg->heapId: %d, "
300 "msg->msgSize: %d, msg->dstId: %d, msg->msgId: %d\n",
301 msg->heapId, msg->msgSize, msg->dstId, msg->msgId);
303 /* Alloc a message from msg->heapId to copy the msg */
304 msgSize = MessageQ_getMsgSize(msg);
305 buf = MessageQ_alloc(msg->heapId, msgSize);
307 /* Make sure buf is not NULL */
308 Assert_isTrue(buf != NULL, NULL);
310 /* copy the message to the buffer allocated. */
311 memcpy((Ptr)buf, (Ptr)msg, msgSize);
313 /*
314 * If the message received was statically allocated, reset the
315 * heapId, so the app can free it.
316 */
317 if (msg->heapId == ti_sdo_ipc_MessageQ_STATICMSG) {
318 msg->heapId = 0; /* for a copy transport, heap id is 0. */
319 }
321 /* get the queue id */
322 queueId = MessageQ_getDstQueue(msg);
324 /* Pass to desitination queue: */
325 MessageQ_put(queueId, buf);
327 exit:
328 Log_print0(Diags_EXIT, "<-- "FXNN);
329 }
331 /*
332 * ======== TransportRpmsg_setErrFxn ========
333 */
334 Void TransportRpmsg_setErrFxn(TransportRpmsg_ErrFxn errFxn)
335 {
336 /* Ignore the errFxn */
337 }