Merge remote-tracking branch 'origin/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         fprintf(stderr, "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         fprintf(stderr, "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             fprintf(stderr, "Ipc_start: GateHWSpinlock_start failed: %d\n",
258                     status);
259             status = Ipc_E_FAIL;
260             goto exit;
261         }
263         status = GateMP_start();
264         if (status < 0) {
265             fprintf(stderr, "Ipc_start: GateMP_start failed: %d\n", status);
266             status = Ipc_E_FAIL;
267             GateHWSpinlock_stop();
268             goto exit;
269         }
270     }
271 #endif
273     /* getting here means we have successfully started */
274     Ipc_module.refCount++;
276 exit:
277     pthread_mutex_unlock(&Ipc_module.gate);
279     return (status);
282 /*
283  *  ======== Ipc_stop ========
284  */
285 Int Ipc_stop(Void)
287     Int32       status = Ipc_S_SUCCESS;
288     LAD_Status  ladStatus;
289     UInt16      procId;
290     UInt16      clusterSize;
291     UInt16      baseId;
292     UInt16      clusterId;
294     /* function must be serialized */
295     pthread_mutex_lock(&Ipc_module.gate);
297     if (Ipc_module.refCount == 0) {
298         status = Ipc_E_INVALIDSTATE;
299         goto exit;
300     }
302     /* ensure only last thread performs stop procedure */
303     if (--Ipc_module.refCount > 0) {
304         goto exit;
305     }
307     /* if using ProcSync_ALL, then detach from all processors in the cluster */
308     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
309         clusterSize = MultiProc_getNumProcsInCluster();
310         baseId = MultiProc_getBaseIdOfCluster();
312         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
313             procId = baseId + clusterId;
315             if (MultiProc_self() == procId) {
316                 continue;
317             }
319             /*  For backward compatibility, we might not be attached to
320              *  all cluster members. Skip unattached processors.
321              */
322             if (!Ipc_isAttached(procId)) {
323                 continue;
324             }
326             status = Ipc_detach(procId);
328             if (status < 0) {
329                 /* Should we keep going or stop? */
330             }
331         }
332     }
334     Ipc_module.transportFactory->deleteFxn();
336     status = MessageQ_destroy();
337     if (status < 0) {
338         fprintf(stderr, "Ipc_stop: MessageQ_destroy() failed: %d\n", status);
339         status = Ipc_E_FAIL;
340         goto exit;
341     }
343     status = NameServer_destroy();
344     if (status < 0) {
345         fprintf(stderr, "Ipc_stop: NameServer_destroy() failed: %d\n", status);
346         status = Ipc_E_FAIL;
347         goto exit;
348     }
350     ladStatus = LAD_disconnect(ladHandle);
351     if (ladStatus != LAD_SUCCESS) {
352         fprintf(stderr, "LAD_disconnect() failed: %d\n", ladStatus);
353         status = Ipc_E_FAIL;
354         goto exit;
355     }
357 exit:
358     pthread_mutex_unlock(&Ipc_module.gate);
360     return (status);
363 /*
364  *  ======== Ipc_transportConfig ========
365  */
366 Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
368     Int status = Ipc_S_SUCCESS;
370     pthread_mutex_lock(&Ipc_module.gate);
372     /*  Only the first caller can actually set the transport factory.
373      *  Subsequent callers (e.g. multi-threaded application) must be
374      *  using the same factory. Otherwise, it is an error.
375      */
376     if (Ipc_module.transportFactory == NULL) {
377         Ipc_module.transportFactory = factory;
378     }
379     else if (Ipc_module.transportFactory != factory) {
380         status = Ipc_E_INVALIDARG;
381         goto exit;
382     }
384 exit:
385     pthread_mutex_unlock(&Ipc_module.gate);
387     return (status);
390 static void cleanup(int arg)
392     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
393     Ipc_stop();
394     exit(0);
397 /*
398  *  ======== Ipc_attach ========
399  */
400 Int Ipc_attach(UInt16 procId)
402     Int status = Ipc_S_SUCCESS;
403     UInt16 clusterId;
404 #if defined(GATEMP_SUPPORT)
405     Int ret;
406 #endif
408     /* cannot attach to yourself */
409     if (MultiProc_self() == procId) {
410         status =  Ipc_E_INVALIDARG;
411         goto done;
412     }
414     /* processor must be a member of the cluster */
415     clusterId = procId - MultiProc_getBaseIdOfCluster();
417     if (clusterId >= MultiProc_getNumProcsInCluster()) {
418         status =  Ipc_E_INVALIDARG;
419         goto done;
420     }
422     /* function must be serialized */
423     pthread_mutex_lock(&Ipc_module.gate);
425     /* if already attached, just increment reference count */
426     if (Ipc_module.attached[clusterId] > 0) {
427         Ipc_module.attached[clusterId]++;
428         goto done;
429     }
431     /* establish name server connection to remote processor */
432     status = NameServer_attach(procId);
434     if (status < 0) {
435         status = Ipc_E_FAIL;
436         goto done;
437     }
439     /* attach the transport to remote processor */
440     status = Ipc_module.transportFactory->attachFxn(procId);
442     if (status < 0) {
443         status = Ipc_E_FAIL;
444         goto done;
445     }
447     /* hack: bind all existing message queues to remote processor */
448     MessageQ_bind(procId);
450 #if defined(GATEMP_SUPPORT)
451     if (GateMP_isSetup()) {
452         /* establish GateMP connection to remote processor */
453         ret = GateMP_attach(procId);
455         if (ret < 0) {
456             PRINTVERBOSE1("Ipc_attach: failed to GateMP_attach to procId %d\n",
457                           procId);
458         }
459     }
460 #endif
462     /* getting here means we have successfully attached */
463     Ipc_module.attached[clusterId]++;
465 done:
466     pthread_mutex_unlock(&Ipc_module.gate);
468     return (status);
471 /*
472  *  ======== Ipc_detach ========
473  */
474 Int Ipc_detach(UInt16 procId)
476     Int status = Ipc_S_SUCCESS;
477     UInt16 clusterId;
478 #if defined(GATEMP_SUPPORT)
479     Int ret;
480 #endif
482     /* cannot detach from yourself */
483     if (MultiProc_self() == procId) {
484         status =  Ipc_E_INVALIDARG;
485         goto done;
486     }
488     /* processor must be a member of the cluster */
489     clusterId = procId - MultiProc_getBaseIdOfCluster();
491     if (clusterId >= MultiProc_getNumProcsInCluster()) {
492         status =  Ipc_E_INVALIDARG;
493         goto done;
494     }
496     /* function must be serialized */
497     pthread_mutex_lock(&Ipc_module.gate);
499     if (Ipc_module.attached[clusterId] == 0) {
500         status = Ipc_E_INVALIDSTATE;
501         goto done;
502     }
504     if (--Ipc_module.attached[clusterId] > 0) {
505         goto done;
506     }
508 #if defined(GATEMP_SUPPORT)
509     if (GateMP_isSetup()) {
510         /* establish GateMP connection to remote processor */
511         ret = GateMP_detach(procId);
513         if (ret < 0) {
514             PRINTVERBOSE1("Ipc_detach: failed to GateMP_detach from procId %d\n",
515                           procId);
516         }
517     }
518 #endif
520     /* hack: unbind all existing message queues from remote processor */
521     MessageQ_unbind(procId);
523     /* detach transport from remote processor */
524     status = Ipc_module.transportFactory->detachFxn(procId);
526     if (status < 0) {
527         status = Ipc_E_FAIL;
528         /* report the error */
529         goto done;
530     }
532     /* remove connection to remote processor */
533     status = NameServer_detach(procId);
535     if (status < 0) {
536         status = Ipc_E_FAIL;
537         /* report the error */
538         goto done;
539     }
541 done:
542     if (status < 0) {
543         /* report error */
544         fprintf(stderr, "Ipc_detach: Error %d, procId %d\n", status, procId);
545     }
546     pthread_mutex_unlock(&Ipc_module.gate);
548     return (status);
551 /*
552  *  ======== Ipc_isAttached ========
553  */
554 Bool Ipc_isAttached(UInt16 procId)
556     Bool attached;
557     UInt16 clusterId;
559     /* cannot be attached to yourself */
560     if (MultiProc_self() == procId) {
561         return (FALSE);
562     }
564     /* processor must be a member of the cluster */
565     clusterId = procId - MultiProc_getBaseIdOfCluster();
567     if (clusterId >= MultiProc_getNumProcsInCluster()) {
568         return (FALSE);
569     }
571     attached = (Ipc_module.attached[clusterId] > 0 ? TRUE : FALSE);
572     return (attached);
575 /*
576  *  ======== Ipc_getConfig ========
577  *  Get the run-time configuration for the Ipc module
578  *
579  *  This is an IPC internal function. It is used to acquire
580  *  the global Ipc module configuration values from LAD.
581  */
582 Void Ipc_getConfig(Ipc_Config *cfg)
584     Int status;
585     LAD_ClientHandle handle;
586     struct LAD_CommandObj cmd;
587     union LAD_ResponseObj rsp;
589     handle = LAD_findHandle();
590     if (handle == LAD_MAXNUMCLIENTS) {
591         PRINTVERBOSE0("Ipc_getConfig: no connection to LAD\n");
592         return;
593     }
595     cmd.cmd = LAD_IPC_GETCONFIG;
596     cmd.clientId = handle;
598     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
599         PRINTVERBOSE1("Ipc_getConfig: sending LAD command failed, "
600                 "status=%d\n", status);
601         return;
602     }
604     if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
605         PRINTVERBOSE1("Ipc_getConfig: no LAD response, status=%d\n", status);
606         return;
607     }
609     memcpy(cfg, &rsp.ipcConfig, sizeof(Ipc_Config));
610     return;