SrvMgr: Initialize ServiceMgr only once
[gstreamer-omap:sysbios-rpmsg.git] / src / ti / srvmgr / ServiceMgr.c
1 /*
2  * Copyright (c) 2011-2012, 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  *  ======== ServiceMgr.c ========
34  *  Simple server that handles requests to create threads (services) by name
35  *  and provide an endpoint to the new thread.
36  *
37  */
38
39 #include <xdc/std.h>
40 #include <xdc/cfg/global.h>
41 #include <xdc/runtime/System.h>
42
43 #include <ti/ipc/MultiProc.h>
44 #include <ti/sysbios/knl/Semaphore.h>
45 #include <ti/sysbios/BIOS.h>
46 #include <ti/sysbios/knl/Task.h>
47
48 #include <ti/grcm/RcmTypes.h>
49 #include <ti/grcm/RcmServer.h>
50
51 #include <stdio.h>
52 #include <string.h>
53 #include <stdlib.h>
54
55
56 #include <ti/ipc/rpmsg/MessageQCopy.h>
57 #include <ti/ipc/rpmsg/VirtQueue.h>
58 #include "rpmsg_omx.h"
59 #include "NameMap.h"
60 #include "ServiceMgr.h"
61
62 /* Hard coded to match Host side, but can be moved into the BIOS resource tbl */
63 #define  SERVICE_MGR_PORT   60
64
65 #define  MAX_NAMELEN       64
66
67 /* This artificially limits the number of service instances on this core: */
68 #define  MAX_TUPLES        256
69 #define  FREE_TUPLE_KEY    0xFFFFFFFF
70
71 /* ServiceMgr disconnect hook function */
72 static ServiceMgr_disconnectFuncPtr ServiceMgr_disconnectUserFxn = NULL;
73
74 struct ServiceDef {
75     Char                   name[MAX_NAMELEN];
76     RcmServer_Params       rcmServerParams;
77     Bool                   taken;
78 };
79
80 struct ServiceDef serviceDefs[ServiceMgr_NUMSERVICETYPES];
81
82 struct Tuple {
83     UInt32   key;
84     UInt32   value;
85 };
86 struct Tuple Tuples[MAX_TUPLES];
87
88
89 void serviceMgrTaskFxn(UArg arg0, UArg arg1);
90
91 Void ServiceMgr_init()
92 {
93     static Int  curInit = 0;
94     Task_Params params;
95     UInt        i;
96
97     if (curInit++ != 0) {
98         return; /* module already initialized */
99     }
100
101     RcmServer_init();
102
103     for (i = 0; i < ServiceMgr_NUMSERVICETYPES; i++) {
104        serviceDefs[i].taken = FALSE;
105     }
106
107     for (i = 0; i < MAX_TUPLES; i++) {
108        Tuples[i].key = FREE_TUPLE_KEY;
109     }
110
111     /* Create our ServiceMgr Thread: */
112     Task_Params_init(&params);
113     params.instance->name = "ServiceMgr";
114     params.priority = 1;   /* Lowest priority thread */
115     Task_create(serviceMgrTaskFxn, &params, NULL);
116 }
117
118 Bool ServiceMgr_register(String name, RcmServer_Params  *rcmServerParams)
119 {
120     UInt              i;
121     Bool              found = FALSE;
122     struct ServiceDef *sd;
123
124     if (strlen(name) >= MAX_NAMELEN) {
125         System_printf("ServiceMgr_register: service name longer than %d\n",
126                        MAX_NAMELEN );
127     }
128     else {
129         /* Search the array for a free slot: */
130         for (i = 0; (i < ServiceMgr_NUMSERVICETYPES) && (found == FALSE); i++) {
131             if (!serviceDefs[i].taken) {
132                 sd = &serviceDefs[i];
133                 strcpy(sd->name, name);
134                 sd->rcmServerParams = *rcmServerParams;
135                 sd->taken = TRUE;
136                 found = TRUE;
137                 break;
138             }
139         }
140     }
141
142     return(found);
143 }
144
145 Void ServiceMgr_send(Service_Handle srvc, Ptr data, UInt16 len)
146 {
147     UInt32 local;
148     UInt32 remote;
149     struct omx_msg_hdr * hdr = (struct omx_msg_hdr *)data;
150     UInt16 dstProc;
151
152     /* Get reply endpoint and local address for sending: */
153     remote  = RcmServer_getRemoteAddress(srvc);
154     dstProc = RcmServer_getRemoteProc(srvc);
155     local   = RcmServer_getLocalAddress(srvc);
156
157     /* Set special rpmsg_omx header so Linux side can strip it off: */
158     hdr->type    = OMX_RAW_MSG;
159     hdr->len     = len;
160     hdr->flags   = 0;
161
162     /* Send it off (and no response expected): */
163     MessageQCopy_send(dstProc, remote, local, data, HDRSIZE+len);
164 }
165
166 Bool ServiceMgr_registerDisconnectFxn(Service_Handle srvc, Ptr data,
167                                       ServiceMgr_disconnectFuncPtr func)
168 {
169     if (func == NULL) {
170         System_printf("ServiceMgr_registerDisconnectFxn: Invalid function.\n");
171         return FALSE;
172     }
173
174     /* Register the user-supplied function */
175     if (!ServiceMgr_disconnectUserFxn) {
176         ServiceMgr_disconnectUserFxn = func;
177     }
178     return TRUE;
179 }
180
181 /* Tuple store/retrieve fxns:  */
182
183 static Bool storeTuple(UInt32 key, UInt32 value)
184 {
185     UInt              i;
186     Bool              stored = FALSE;
187
188     if (key == FREE_TUPLE_KEY) {
189         System_printf("storeTuple: reserved key %d\n", key);
190     }
191     else {
192         /* Search the array for a free slot: */
193         for (i = 0; (i < MAX_TUPLES) && (stored == FALSE); i++) {
194            if (Tuples[i].key == FREE_TUPLE_KEY) {
195                Tuples[i].key = key;
196                Tuples[i].value = value;
197                stored = TRUE;
198                break;
199            }
200         }
201     }
202
203     return(stored);
204 }
205
206 static Bool removeTuple(UInt32 key, UInt32 * value)
207 {
208     UInt              i;
209     Bool              found = FALSE;
210
211     /* Search the array for tuple matching key: */
212     for (i = 0; (i < MAX_TUPLES) && (found == FALSE); i++) {
213        if (Tuples[i].key == key) {
214            found = TRUE;
215            *value = Tuples[i].value;
216            /* and free it... */
217            Tuples[i].value = 0;
218            Tuples[i].key = FREE_TUPLE_KEY;
219            break;
220        }
221     }
222
223     return(found);
224 }
225
226 static UInt32 createService(Char * name, UInt32 * endpt)
227 {
228     Int i;
229     Int status = 0;
230     struct ServiceDef *sd;
231     RcmServer_Handle  rcmSrvHandle;
232
233     for (i = 0; i < ServiceMgr_NUMSERVICETYPES; i++) {
234        if (!strcmp(name, serviceDefs[i].name)) {
235            sd = &serviceDefs[i];
236            break;
237        }
238     }
239
240     if (i >= ServiceMgr_NUMSERVICETYPES) {
241        System_printf("createService: unrecognized service name: %s\n", name);
242        return OMX_NOTSUPP;
243     }
244
245     /* Create the RcmServer instance. */
246 #if 0
247     System_printf("createService: Calling RcmServer_create with name = %s\n"
248                   "priority = %d\n"
249                   "osPriority = %d\n"
250                   "rcmServerParams.fxns.length = %d\n",
251                   sd->name, sd->rcmServerParams.priority,
252                   sd->rcmServerParams.osPriority,
253                   sd->rcmServerParams.fxns.length);
254 #endif
255     status = RcmServer_create(sd->name, &sd->rcmServerParams, &rcmSrvHandle);
256
257     if (status < 0) {
258         System_printf("createService: RcmServer_create() returned error %d\n",
259                        status);
260         return OMX_FAIL;
261     }
262
263     /* Get endpoint allowing clients to send messages to this new server: */
264     *endpt = RcmServer_getLocalAddress(rcmSrvHandle);
265
266     /* Store Server's endpoint with handle so we can cleanup on disconnect: */
267     if (!storeTuple(*endpt, (UInt32)rcmSrvHandle))  {
268         System_printf("createService: Limit reached on max instances!\n");
269         RcmServer_delete(&rcmSrvHandle);
270         return OMX_FAIL;
271     }
272
273     /* start the server */
274     RcmServer_start(rcmSrvHandle);
275
276     System_printf("createService: new OMX Service at endpoint: %d\n", *endpt);
277
278     return OMX_SUCCESS;
279 }
280
281
282 static UInt32 deleteService(UInt32 addr)
283 {
284     Int status = 0;
285     RcmServer_Handle  rcmSrvHandle;
286
287     if (!removeTuple(addr, (UInt32 *)&rcmSrvHandle))  {
288        System_printf("deleteService: could not find service instance at"
289                      " address: 0x%x\n", addr);
290        return OMX_FAIL;
291     }
292
293     /* Notify a ServiceMgr client of disconnection.
294      * rcmSrvHandle is same as the ServiceMgr handle
295      */
296     if (ServiceMgr_disconnectUserFxn) {
297         /* Pass NULL data for the moment */
298         ServiceMgr_disconnectUserFxn(rcmSrvHandle, NULL);
299     }
300
301     /* Destroy the RcmServer instance. */
302     status = RcmServer_delete(&rcmSrvHandle);
303     if (status < 0) {
304         System_printf("deleteService: RcmServer_delete() returned error %d\n",
305                        status);
306         return OMX_FAIL;
307     }
308
309     System_printf("deleteService: removed RcmServer at endpoint: %d\n", addr);
310
311     return OMX_SUCCESS;
312 }
313
314 void serviceMgrTaskFxn(UArg arg0, UArg arg1)
315 {
316     MessageQCopy_Handle msgq;
317     UInt32 local;
318     UInt32 remote;
319     Char msg[HDRSIZE + sizeof(struct omx_connect_req)];
320     struct omx_msg_hdr * hdr = (struct omx_msg_hdr *)msg;
321     struct omx_connect_rsp * rsp = (struct omx_connect_rsp *)hdr->data;
322     struct omx_connect_req * req = (struct omx_connect_req *)hdr->data;
323     struct omx_disc_req * disc_req = (struct omx_disc_req *)hdr->data;
324     struct omx_disc_rsp * disc_rsp = (struct omx_disc_rsp *)hdr->data;
325     UInt16 dstProc;
326     UInt16 len;
327     UInt32 newAddr = 0;
328
329
330 #ifdef BIOS_ONLY_TEST
331     dstProc = MultiProc_self();
332 #else
333     dstProc = MultiProc_getId("HOST");
334 #endif
335
336     MessageQCopy_init(dstProc);
337
338     msgq = MessageQCopy_create(SERVICE_MGR_PORT, &local);
339
340     System_printf("serviceMgr: started on port: %d\n", SERVICE_MGR_PORT);
341
342     if (MultiProc_self() == MultiProc_getId("CORE0")) {
343         NameMap_register("rpmsg-omx0", SERVICE_MGR_PORT);
344     }
345     if (MultiProc_self() == MultiProc_getId("CORE1")) {
346         NameMap_register("rpmsg-omx1", SERVICE_MGR_PORT);
347     }
348     if (MultiProc_self() == MultiProc_getId("DSP")) {
349         NameMap_register("rpmsg-omx2", SERVICE_MGR_PORT);
350     }
351
352     if ((MultiProc_self() == MultiProc_getId("CORE1")) ||
353         (MultiProc_self() == MultiProc_getId("DSP"))) {
354         System_printf("serviceMgr: Proc#%d sending BOOTINIT_DONE\n",
355                         MultiProc_self());
356         VirtQueue_postInitDone();
357     }
358
359     while (1) {
360        MessageQCopy_recv(msgq, (Ptr)msg, &len, &remote, MessageQCopy_FOREVER);
361        System_printf("serviceMgr: received msg type: %d from addr: %d\n",
362                       hdr->type, remote);
363        switch (hdr->type) {
364            case OMX_CONN_REQ:
365             /* This is a request to create a new service, and return
366              * it's connection endpoint.
367              */
368             System_printf("serviceMgr: CONN_REQ: len: %d, name: %s\n",
369                  hdr->len, req->name);
370
371             rsp->status = createService(req->name, &newAddr);
372
373             hdr->type = OMX_CONN_RSP;
374             rsp->addr = newAddr;
375             hdr->len = sizeof(struct omx_connect_rsp);
376             len = HDRSIZE + hdr->len;
377             break;
378
379            case OMX_DISC_REQ:
380             /* Destroy the service instance at given service addr: */
381             System_printf("serviceMgr: OMX_DISCONNECT: len %d, addr: %d\n",
382                  hdr->len, disc_req->addr);
383
384             disc_rsp->status = deleteService(disc_req->addr);
385
386             /* currently, no response expected from rpmsg_omx: */
387             continue;
388 #if 0       // rpmsg_omx is not listening for this ... yet.
389             hdr->type = OMX_DISC_RSP;
390             hdr->len = sizeof(struct omx_disc_rsp);
391             len = HDRSIZE + hdr->len;
392             break;
393 #endif
394
395            default:
396             System_printf("unexpected msg type: %d\n", hdr->type);
397             hdr->type = OMX_NOTSUPP;
398             break;
399        }
400
401        System_printf("serviceMgr: Replying with msg type: %d to addr: %d "
402                       " from: %d\n",
403                       hdr->type, remote, local);
404        MessageQCopy_send(dstProc, remote, local, msg, len);
405     }
406 }