Merge branch '3.36' into ipc-next
[ipc/ipcdev.git] / linux / src / api / Ipc.c
1 /*
2  * Copyright (c) 2012-2015 Texas Instruments Incorporated - http://www.ti.com
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  *  @file       Ipc.c
34  *
35  *  @brief      Starts and stops user side Ipc
36  *              All setup/destroy APIs on user side will be call from this
37  *              module.
38  */
40 /* standard headers */
41 #include <pthread.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <signal.h>
45 #include <string.h>
47 /* package headers */
48 #include <ti/ipc/Std.h>
49 #include <ti/ipc/Ipc.h>
50 #include <ti/ipc/NameServer.h>
52 /* User side headers */
53 #include <ladclient.h>
55 /* IPC startup/shutdown stuff: */
56 #include <ti/ipc/MultiProc.h>
57 #include <GateHWSpinlock.h>
58 #include <_GateMP.h>
59 #include <_Ipc.h>
60 #include <_MultiProc.h>
61 #include <_MessageQ.h>
62 #include <_NameServer.h>
64 /* module definition */
65 typedef struct {
66     Int                         refCount;
67     pthread_mutex_t             gate;
68     Ipc_TransportFactoryFxns   *transportFactory;
69     Ipc_Config                  config;
70     Int                         attached[MultiProc_MAXPROCESSORS];
71 } Ipc_Module;
73 /* hack: rpmsgproto driver work around */
74 Void MessageQ_bind(UInt16 procId);
75 Void MessageQ_unbind(UInt16 procId);
78 /* =============================================================================
79  *  Globals
80  * =============================================================================
81  */
82 static Ipc_Module Ipc_module = {
83     .refCount           = 0,
84 #if defined(IPC_BUILDOS_ANDROID)
85     .gate               = PTHREAD_RECURSIVE_MUTEX_INITIALIZER,
86 #else
87 // only _NP (non-portable) type available in CG tools which we're using
88     .gate               = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
89 #endif
90     .transportFactory   = NULL,
91     .config.procSync    = Ipc_ProcSync_NONE
92 };
94 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
95 static LAD_ClientHandle ladHandle;
97 /* traces in this file are controlled via _Ipc_verbose */
98 Bool _Ipc_verbose = FALSE;
99 #define verbose _Ipc_verbose
101 /** ============================================================================
102  *  Functions
103  *  ============================================================================
104  */
105 static void cleanup(int arg);
108 /*
109  *  ======== Ipc_start ========
110  */
111 Int Ipc_start(Void)
113     MessageQ_Config         msgqCfg;
114     MultiProc_Config        mpCfg;
115 #if defined(GATEMP_SUPPORT)
116     GateHWSpinlock_Config   gateHWCfg;
117 #endif
118     Int         status;
119     LAD_Status  ladStatus;
120     UInt16      procId;
121     UInt16      clusterSize;
122     UInt16      baseId;
123     UInt16      clusterId;
124     Int         i;
126     /* function must be serialized */
127     pthread_mutex_lock(&Ipc_module.gate);
129     /* ensure only first thread performs startup procedure */
130     if (Ipc_module.refCount >= 1) {
131         Ipc_module.refCount++;
132         status = Ipc_S_ALREADYSETUP;
133         goto exit;
134     }
136     /* make sure transport factory has been configured */
137     if (Ipc_module.transportFactory == NULL) {
138         status = Ipc_E_INVALIDSTATE;
139         goto exit;
140     }
142     /* initialize module object */
143     for (i = 0; i < MultiProc_MAXPROCESSORS; i++) {
144         Ipc_module.attached[i] = 0;
145     }
147     /* Catch ctrl-C, and cleanup: */
148     (void) signal(SIGINT, cleanup);
150     if (getenv("IPC_DEBUG") != NULL) {
151         /* turn on tracing */
152         if (getenv("IPC_DEBUG")[0] == '1') {
153             /* level 1 enables typical user API tracing */
154             _MessageQ_verbose = TRUE;
155             _MultiProc_verbose = TRUE;
156             _NameServer_verbose = TRUE;
157 #if defined(GATEMP_SUPPORT)
158             _GateMP_verbose = TRUE;
160             _GateHWSpinlock_verbose = TRUE;
161 #endif
162         }
163         else if ((getenv("IPC_DEBUG")[0] == '2') ||
164                 (getenv("IPC_DEBUG")[0] == '3')) {
165             /* levels 2 and 3 add socket and LAD client tracing */
166             _MessageQ_verbose = TRUE;
167             _MultiProc_verbose = TRUE;
168             _NameServer_verbose = TRUE;
170 #if defined(GATEMP_SUPPORT)
171             _GateMP_verbose = TRUE;
173             _GateHWSpinlock_verbose = TRUE;
174 #endif
176             /* internals - should be declared in respective _*.h files */
177             extern Bool _SocketFxns_verbose;
178             extern Bool _LAD_Client_verbose;
180             _SocketFxns_verbose = TRUE;
181             _LAD_Client_verbose = TRUE;
182         }
183     }
185     /* establish a communication link to the LAD daemon */
186     ladStatus = LAD_connect(&ladHandle);
188     if (ladStatus != LAD_SUCCESS) {
189         printf("Ipc_start: LAD_connect() failed: %d\n", ladStatus);
190         status = Ipc_E_FAIL;
191         goto exit;
192     }
194     /* get global configuration from LAD */
195     Ipc_getConfig(&Ipc_module.config);
197     /* get global configuration from LAD */
198     MultiProc_getConfig(&mpCfg);
199     _MultiProc_initCfg(&mpCfg);
201     /* setup name server thread in LAD daemon */
202     status = NameServer_setup();
204     if (status < 0) {
205         printf("Ipc_start: NameServer_setup() failed: %d\n", status);
206         status = Ipc_E_FAIL;
207         goto exit;
208     }
210     /* get global configuration from LAD */
211     MessageQ_getConfig(&msgqCfg);
212     MessageQ_setup(&msgqCfg);
214     /* invoke the transport factory create method */
215     status = Ipc_module.transportFactory->createFxn();
217     if (status < 0) {
218         goto exit;
219     }
221     /* if using ProcSync_ALL, then attach to all processors in the cluster */
222     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
223         clusterSize = MultiProc_getNumProcsInCluster();
224         baseId = MultiProc_getBaseIdOfCluster();
226         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
227             procId = baseId + clusterId;
229             if (procId == MultiProc_self()) {
230                 continue;
231             }
233             status = Ipc_attach(procId);
235             /*  For backward compatibility, it is okay for attach to fail.
236              *  We don't expect all remote processors to be running.
237              */
238             if (status < 0) {
239                 status = 0;
240                 /* do nothing */
241             }
242         }
243     }
245     /* Start GateMP only if device has support */
246 #if defined(GATEMP_SUPPORT)
247     if (GateMP_isSetup()) {
248         /*
249          * Get HWSpinlock base address and size from LAD and
250          * initialize the local config structure.
251          */
252         GateHWSpinlock_getConfig(&gateHWCfg);
253         _GateHWSpinlock_cfgParams = gateHWCfg;
255         status = GateHWSpinlock_start();
256         if (status < 0) {
257             printf("Ipc_start: GateHWSpinlock_start failed: %d\n", status);
258             status = Ipc_E_FAIL;
259             goto exit;
260         }
262         status = GateMP_start();
263         if (status < 0) {
264             printf("Ipc_start: GateMP_start failed: %d\n", status);
265             status = Ipc_E_FAIL;
266             GateHWSpinlock_stop();
267             goto exit;
268         }
269     }
270 #endif
272     /* getting here means we have successfully started */
273     Ipc_module.refCount++;
275 exit:
276     pthread_mutex_unlock(&Ipc_module.gate);
278     return (status);
281 /*
282  *  ======== Ipc_stop ========
283  */
284 Int Ipc_stop(Void)
286     Int32       status = Ipc_S_SUCCESS;
287     LAD_Status  ladStatus;
288     UInt16      procId;
289     UInt16      clusterSize;
290     UInt16      baseId;
291     UInt16      clusterId;
293     /* function must be serialized */
294     pthread_mutex_lock(&Ipc_module.gate);
296     if (Ipc_module.refCount == 0) {
297         status = Ipc_E_INVALIDSTATE;
298         goto exit;
299     }
301     /* ensure only last thread performs stop procedure */
302     if (--Ipc_module.refCount > 0) {
303         goto exit;
304     }
306     /* if using ProcSync_ALL, then detach from all processors in the cluster */
307     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
308         clusterSize = MultiProc_getNumProcsInCluster();
309         baseId = MultiProc_getBaseIdOfCluster();
311         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
312             procId = baseId + clusterId;
314             if (MultiProc_self() == procId) {
315                 continue;
316             }
318             /*  For backward compatibility, we might not be attached to
319              *  all cluster members. Skip unattached processors.
320              */
321             if (!Ipc_isAttached(procId)) {
322                 continue;
323             }
325             status = Ipc_detach(procId);
327             if (status < 0) {
328                 /* Should we keep going or stop? */
329             }
330         }
331     }
333     Ipc_module.transportFactory->deleteFxn();
335     status = MessageQ_destroy();
336     if (status < 0) {
337         printf("Ipc_stop: MessageQ_destroy() failed: %d\n", status);
338         status = Ipc_E_FAIL;
339         goto exit;
340     }
342     status = NameServer_destroy();
343     if (status < 0) {
344         printf("Ipc_stop: NameServer_destroy() failed: %d\n", status);
345         status = Ipc_E_FAIL;
346         goto exit;
347     }
349     ladStatus = LAD_disconnect(ladHandle);
350     if (ladStatus != LAD_SUCCESS) {
351         printf("LAD_disconnect() failed: %d\n", ladStatus);
352         status = Ipc_E_FAIL;
353         goto exit;
354     }
356 exit:
357     pthread_mutex_unlock(&Ipc_module.gate);
359     return (status);
362 /*
363  *  ======== Ipc_transportConfig ========
364  */
365 Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
367     Int status = Ipc_S_SUCCESS;
369     pthread_mutex_lock(&Ipc_module.gate);
371     /*  Only the first caller can actually set the transport factory.
372      *  Subsequent callers (e.g. multi-threaded application) must be
373      *  using the same factory. Otherwise, it is an error.
374      */
375     if (Ipc_module.transportFactory == NULL) {
376         Ipc_module.transportFactory = factory;
377     }
378     else if (Ipc_module.transportFactory != factory) {
379         status = Ipc_E_INVALIDARG;
380         goto exit;
381     }
383 exit:
384     pthread_mutex_unlock(&Ipc_module.gate);
386     return (status);
389 static void cleanup(int arg)
391     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
392     Ipc_stop();
393     exit(0);
396 /*
397  *  ======== Ipc_attach ========
398  */
399 Int Ipc_attach(UInt16 procId)
401     Int status = Ipc_S_SUCCESS;
402     UInt16 clusterId;
403 #if defined(GATEMP_SUPPORT)
404     Int ret;
405 #endif
407     /* cannot attach to yourself */
408     if (MultiProc_self() == procId) {
409         status =  Ipc_E_INVALIDARG;
410         goto done;
411     }
413     /* processor must be a member of the cluster */
414     clusterId = procId - MultiProc_getBaseIdOfCluster();
416     if (clusterId >= MultiProc_getNumProcsInCluster()) {
417         status =  Ipc_E_INVALIDARG;
418         goto done;
419     }
421     /* function must be serialized */
422     pthread_mutex_lock(&Ipc_module.gate);
424     /* if already attached, just increment reference count */
425     if (Ipc_module.attached[clusterId] > 0) {
426         Ipc_module.attached[clusterId]++;
427         goto done;
428     }
430     /* establish name server connection to remote processor */
431     status = NameServer_attach(procId);
433     if (status < 0) {
434         status = Ipc_E_FAIL;
435         goto done;
436     }
438     /* attach the transport to remote processor */
439     status = Ipc_module.transportFactory->attachFxn(procId);
441     if (status < 0) {
442         status = Ipc_E_FAIL;
443         goto done;
444     }
446     /* hack: bind all existing message queues to remote processor */
447     MessageQ_bind(procId);
449 #if defined(GATEMP_SUPPORT)
450     if (GateMP_isSetup()) {
451         /* establish GateMP connection to remote processor */
452         ret = GateMP_attach(procId);
454         if (ret < 0) {
455             PRINTVERBOSE1("Ipc_attach: failed to GateMP_attach to procId %d\n",
456                           procId);
457         }
458     }
459 #endif
461     /* getting here means we have successfully attached */
462     Ipc_module.attached[clusterId]++;
464 done:
465     pthread_mutex_unlock(&Ipc_module.gate);
467     return (status);
470 /*
471  *  ======== Ipc_detach ========
472  */
473 Int Ipc_detach(UInt16 procId)
475     Int status = Ipc_S_SUCCESS;
476     UInt16 clusterId;
477 #if defined(GATEMP_SUPPORT)
478     Int ret;
479 #endif
481     /* cannot detach from yourself */
482     if (MultiProc_self() == procId) {
483         status =  Ipc_E_INVALIDARG;
484         goto done;
485     }
487     /* processor must be a member of the cluster */
488     clusterId = procId - MultiProc_getBaseIdOfCluster();
490     if (clusterId >= MultiProc_getNumProcsInCluster()) {
491         status =  Ipc_E_INVALIDARG;
492         goto done;
493     }
495     /* function must be serialized */
496     pthread_mutex_lock(&Ipc_module.gate);
498     if (Ipc_module.attached[clusterId] == 0) {
499         status = Ipc_E_INVALIDSTATE;
500         goto done;
501     }
503     if (--Ipc_module.attached[clusterId] > 0) {
504         goto done;
505     }
507 #if defined(GATEMP_SUPPORT)
508     if (GateMP_isSetup()) {
509         /* establish GateMP connection to remote processor */
510         ret = GateMP_detach(procId);
512         if (ret < 0) {
513             PRINTVERBOSE1("Ipc_detach: failed to GateMP_detach from procId %d\n",
514                           procId);
515         }
516     }
517 #endif
519     /* hack: unbind all existing message queues from remote processor */
520     MessageQ_unbind(procId);
522     /* detach transport from remote processor */
523     status = Ipc_module.transportFactory->detachFxn(procId);
525     if (status < 0) {
526         status = Ipc_E_FAIL;
527         /* report the error */
528         goto done;
529     }
531     /* remove connection to remote processor */
532     status = NameServer_detach(procId);
534     if (status < 0) {
535         status = Ipc_E_FAIL;
536         /* report the error */
537         goto done;
538     }
540 done:
541     if (status < 0) {
542         /* report error */
543         printf("Ipc_detach: Error %d, procId %d\n", status, procId);
544     }
545     pthread_mutex_unlock(&Ipc_module.gate);
547     return (status);
550 /*
551  *  ======== Ipc_isAttached ========
552  */
553 Bool Ipc_isAttached(UInt16 procId)
555     Bool attached;
556     UInt16 clusterId;
558     /* cannot be attached to yourself */
559     if (MultiProc_self() == procId) {
560         return (FALSE);
561     }
563     /* processor must be a member of the cluster */
564     clusterId = procId - MultiProc_getBaseIdOfCluster();
566     if (clusterId >= MultiProc_getNumProcsInCluster()) {
567         return (FALSE);
568     }
570     attached = (Ipc_module.attached[clusterId] > 0 ? TRUE : FALSE);
571     return (attached);
574 /*
575  *  ======== Ipc_getConfig ========
576  *  Get the run-time configuration for the Ipc module
577  *
578  *  This is an IPC internal function. It is used to acquire
579  *  the global Ipc module configuration values from LAD.
580  */
581 Void Ipc_getConfig(Ipc_Config *cfg)
583     Int status;
584     LAD_ClientHandle handle;
585     struct LAD_CommandObj cmd;
586     union LAD_ResponseObj rsp;
588     handle = LAD_findHandle();
589     if (handle == LAD_MAXNUMCLIENTS) {
590         PRINTVERBOSE0("Ipc_getConfig: no connection to LAD\n");
591         return;
592     }
594     cmd.cmd = LAD_IPC_GETCONFIG;
595     cmd.clientId = handle;
597     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
598         PRINTVERBOSE1("Ipc_getConfig: sending LAD command failed, "
599                 "status=%d\n", status);
600         return;
601     }
603     if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
604         PRINTVERBOSE1("Ipc_getConfig: no LAD response, status=%d\n", status);
605         return;
606     }
608     memcpy(cfg, &rsp.ipcConfig, sizeof(Ipc_Config));
609     return;