Ignore cluster members which are not running
[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;
74 /* =============================================================================
75  *  Globals
76  * =============================================================================
77  */
78 static Ipc_Module Ipc_module = {
79     .refCount           = 0,
80 #if defined(IPC_BUILDOS_ANDROID)
81     .gate               = PTHREAD_RECURSIVE_MUTEX_INITIALIZER,
82 #else
83 // only _NP (non-portable) type available in CG tools which we're using
84     .gate               = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
85 #endif
86     .transportFactory   = NULL,
87     .config.procSync    = Ipc_ProcSync_NONE
88 };
90 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
91 static LAD_ClientHandle ladHandle;
93 /* traces in this file are controlled via _Ipc_verbose */
94 Bool _Ipc_verbose = FALSE;
95 #define verbose _Ipc_verbose
97 /** ============================================================================
98  *  Functions
99  *  ============================================================================
100  */
101 static void cleanup(int arg);
104 /*
105  *  ======== Ipc_start ========
106  */
107 Int Ipc_start(Void)
109     MessageQ_Config         msgqCfg;
110     MultiProc_Config        mpCfg;
111 #if defined(GATEMP_SUPPORT)
112     GateHWSpinlock_Config   gateHWCfg;
113 #endif
114     Int         status;
115     LAD_Status  ladStatus;
116     UInt16      procId;
117     UInt16      clusterSize;
118     UInt16      baseId;
119     UInt16      clusterId;
120     Int         i;
122     /* function must be serialized */
123     pthread_mutex_lock(&Ipc_module.gate);
125     /* ensure only first thread performs startup procedure */
126     if (Ipc_module.refCount >= 1) {
127         Ipc_module.refCount++;
128         status = Ipc_S_ALREADYSETUP;
129         goto exit;
130     }
132     /* make sure transport factory has been configured */
133     if (Ipc_module.transportFactory == NULL) {
134         status = Ipc_E_INVALIDSTATE;
135         goto exit;
136     }
138     /* initialize module object */
139     for (i = 0; i < MultiProc_MAXPROCESSORS; i++) {
140         Ipc_module.attached[i] = 0;
141     }
143     /* Catch ctrl-C, and cleanup: */
144     (void) signal(SIGINT, cleanup);
146     if (getenv("IPC_DEBUG") != NULL) {
147         /* turn on tracing */
148         if (getenv("IPC_DEBUG")[0] == '1') {
149             /* level 1 enables typical user API tracing */
150             _MessageQ_verbose = TRUE;
151             _MultiProc_verbose = TRUE;
152             _NameServer_verbose = TRUE;
153 #if defined(GATEMP_SUPPORT)
154             _GateMP_verbose = TRUE;
156             _GateHWSpinlock_verbose = TRUE;
157 #endif
158         }
159         else if ((getenv("IPC_DEBUG")[0] == '2') ||
160                 (getenv("IPC_DEBUG")[0] == '3')) {
161             /* levels 2 and 3 add socket and LAD client tracing */
162             _MessageQ_verbose = TRUE;
163             _MultiProc_verbose = TRUE;
164             _NameServer_verbose = TRUE;
166 #if defined(GATEMP_SUPPORT)
167             _GateMP_verbose = TRUE;
169             _GateHWSpinlock_verbose = TRUE;
170 #endif
172             /* internals - should be declared in respective _*.h files */
173             extern Bool _SocketFxns_verbose;
174             extern Bool _LAD_Client_verbose;
176             _SocketFxns_verbose = TRUE;
177             _LAD_Client_verbose = TRUE;
178         }
179     }
181     /* establish a communication link to the LAD daemon */
182     ladStatus = LAD_connect(&ladHandle);
184     if (ladStatus != LAD_SUCCESS) {
185         printf("Ipc_start: LAD_connect() failed: %d\n", ladStatus);
186         status = Ipc_E_FAIL;
187         goto exit;
188     }
190     /* get global configuration from LAD */
191     Ipc_getConfig(&Ipc_module.config);
193     /* get global configuration from LAD */
194     MultiProc_getConfig(&mpCfg);
195     _MultiProc_initCfg(&mpCfg);
197     /* setup name server thread in LAD daemon */
198     status = NameServer_setup();
200     if (status < 0) {
201         printf("Ipc_start: NameServer_setup() failed: %d\n", status);
202         status = Ipc_E_FAIL;
203         goto exit;
204     }
206     /* get global configuration from LAD */
207     MessageQ_getConfig(&msgqCfg);
208     MessageQ_setup(&msgqCfg);
210     /* invoke the transport factory create method */
211     status = Ipc_module.transportFactory->createFxn();
213     if (status < 0) {
214         goto exit;
215     }
217     /* if using ProcSync_ALL, then attach to all processors in the cluster */
218     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
219         clusterSize = MultiProc_getNumProcsInCluster();
220         baseId = MultiProc_getBaseIdOfCluster();
222         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
223             procId = baseId + clusterId;
225             if (procId == MultiProc_self()) {
226                 continue;
227             }
229             status = Ipc_attach(procId);
231             /*  For backward compatibility, it is okay for attach to fail.
232              *  We don't expect all remote processors to be running.
233              */
234             if (status < 0) {
235                 status = 0;
236                 /* do nothing */
237             }
238         }
239     }
241     /* Start GateMP only if device has support */
242 #if defined(GATEMP_SUPPORT)
243     if (GateMP_isSetup()) {
244         /*
245          * Get HWSpinlock base address and size from LAD and
246          * initialize the local config structure.
247          */
248         GateHWSpinlock_getConfig(&gateHWCfg);
249         _GateHWSpinlock_cfgParams = gateHWCfg;
251         status = GateHWSpinlock_start();
252         if (status < 0) {
253             printf("Ipc_start: GateHWSpinlock_start failed: %d\n", status);
254             status = Ipc_E_FAIL;
255             goto exit;
256         }
258         status = GateMP_start();
259         if (status < 0) {
260             printf("Ipc_start: GateMP_start failed: %d\n", status);
261             status = Ipc_E_FAIL;
262             GateHWSpinlock_stop();
263             goto exit;
264         }
265     }
266 #endif
268     /* getting here means we have successfully started */
269     Ipc_module.refCount++;
271 exit:
272     pthread_mutex_unlock(&Ipc_module.gate);
274     return (status);
277 /*
278  *  ======== Ipc_stop ========
279  */
280 Int Ipc_stop(Void)
282     Int32       status = Ipc_S_SUCCESS;
283     LAD_Status  ladStatus;
284     UInt16      procId;
285     UInt16      clusterSize;
286     UInt16      baseId;
287     UInt16      clusterId;
289     /* function must be serialized */
290     pthread_mutex_lock(&Ipc_module.gate);
292     if (Ipc_module.refCount == 0) {
293         status = Ipc_E_INVALIDSTATE;
294         goto exit;
295     }
297     /* ensure only last thread performs stop procedure */
298     if (--Ipc_module.refCount > 0) {
299         goto exit;
300     }
302     /* if using ProcSync_ALL, then detach from all processors in the cluster */
303     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
304         clusterSize = MultiProc_getNumProcsInCluster();
305         baseId = MultiProc_getBaseIdOfCluster();
307         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
308             procId = baseId + clusterId;
310             if (MultiProc_self() == procId) {
311                 continue;
312             }
314             /*  For backward compatibility, we might not be attached to
315              *  all cluster members. Skip unattached processors.
316              */
317             if (!Ipc_isAttached(procId)) {
318                 continue;
319             }
321             status = Ipc_detach(procId);
323             if (status < 0) {
324                 /* Should we keep going or stop? */
325             }
326         }
327     }
329     Ipc_module.transportFactory->deleteFxn();
331     status = MessageQ_destroy();
332     if (status < 0) {
333         printf("Ipc_stop: MessageQ_destroy() failed: %d\n", status);
334         status = Ipc_E_FAIL;
335         goto exit;
336     }
338     status = NameServer_destroy();
339     if (status < 0) {
340         printf("Ipc_stop: NameServer_destroy() failed: %d\n", status);
341         status = Ipc_E_FAIL;
342         goto exit;
343     }
345     ladStatus = LAD_disconnect(ladHandle);
346     if (ladStatus != LAD_SUCCESS) {
347         printf("LAD_disconnect() failed: %d\n", ladStatus);
348         status = Ipc_E_FAIL;
349         goto exit;
350     }
352 exit:
353     pthread_mutex_unlock(&Ipc_module.gate);
355     return (status);
358 /*
359  *  ======== Ipc_transportConfig ========
360  */
361 Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
363     Int status = Ipc_S_SUCCESS;
365     pthread_mutex_lock(&Ipc_module.gate);
367     /*  Only the first caller can actually set the transport factory.
368      *  Subsequent callers (e.g. multi-threaded application) must be
369      *  using the same factory. Otherwise, it is an error.
370      */
371     if (Ipc_module.transportFactory == NULL) {
372         Ipc_module.transportFactory = factory;
373     }
374     else if (Ipc_module.transportFactory != factory) {
375         status = Ipc_E_INVALIDARG;
376         goto exit;
377     }
379 exit:
380     pthread_mutex_unlock(&Ipc_module.gate);
382     return (status);
385 static void cleanup(int arg)
387     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
388     Ipc_stop();
389     exit(0);
392 /*
393  *  ======== Ipc_attach ========
394  */
395 Int Ipc_attach(UInt16 procId)
397     Int status = Ipc_S_SUCCESS;
398     UInt16 clusterId;
400     /* cannot attach to yourself */
401     if (MultiProc_self() == procId) {
402         status =  Ipc_E_INVALIDARG;
403         goto done;
404     }
406     /* processor must be a member of the cluster */
407     clusterId = procId - MultiProc_getBaseIdOfCluster();
409     if (clusterId >= MultiProc_getNumProcsInCluster()) {
410         status =  Ipc_E_INVALIDARG;
411         goto done;
412     }
414     /* function must be serialized */
415     pthread_mutex_lock(&Ipc_module.gate);
417     /* if already attached, just increment reference count */
418     if (Ipc_module.attached[clusterId] > 0) {
419         Ipc_module.attached[clusterId]++;
420         goto done;
421     }
423     /* establish name server connection to remote processor */
424     status = NameServer_attach(procId);
426     if (status < 0) {
427         status = Ipc_E_FAIL;
428         goto done;
429     }
431     /* attach the transport to remote processor */
432     status = Ipc_module.transportFactory->attachFxn(procId);
434     if (status < 0) {
435         status = Ipc_E_FAIL;
436         goto done;
437     }
439     /* getting here means we have successfully attached */
440     Ipc_module.attached[clusterId]++;
442 done:
443     pthread_mutex_unlock(&Ipc_module.gate);
445     return (status);
448 /*
449  *  ======== Ipc_detach ========
450  */
451 Int Ipc_detach(UInt16 procId)
453     Int status = Ipc_S_SUCCESS;
454     UInt16 clusterId;
456     /* cannot detach from yourself */
457     if (MultiProc_self() == procId) {
458         status =  Ipc_E_INVALIDARG;
459         goto done;
460     }
462     /* processor must be a member of the cluster */
463     clusterId = procId - MultiProc_getBaseIdOfCluster();
465     if (clusterId >= MultiProc_getNumProcsInCluster()) {
466         status =  Ipc_E_INVALIDARG;
467         goto done;
468     }
470     /* function must be serialized */
471     pthread_mutex_lock(&Ipc_module.gate);
473     if (Ipc_module.attached[clusterId] == 0) {
474         status = Ipc_E_INVALIDSTATE;
475         goto done;
476     }
478     if (--Ipc_module.attached[clusterId] > 0) {
479         goto done;
480     }
482     /* detach transport from remote processor */
483     status = Ipc_module.transportFactory->detachFxn(procId);
485     if (status < 0) {
486         status = Ipc_E_FAIL;
487         /* report the error */
488         goto done;
489     }
491     /* remove connection to remote processor */
492     status = NameServer_detach(procId);
494     if (status < 0) {
495         status = Ipc_E_FAIL;
496         /* report the error */
497         goto done;
498     }
500 done:
501     if (status < 0) {
502         /* report error */
503         printf("Ipc_detach: Error %d, procId %d\n", status, procId);
504     }
505     pthread_mutex_unlock(&Ipc_module.gate);
507     return (status);
510 /*
511  *  ======== Ipc_isAttached ========
512  */
513 Bool Ipc_isAttached(UInt16 procId)
515     Bool attached;
516     UInt16 clusterId;
518     /* cannot be attached to yourself */
519     if (MultiProc_self() == procId) {
520         return (FALSE);
521     }
523     /* processor must be a member of the cluster */
524     clusterId = procId - MultiProc_getBaseIdOfCluster();
526     if (clusterId >= MultiProc_getNumProcsInCluster()) {
527         return (FALSE);
528     }
530     attached = (Ipc_module.attached[clusterId] > 0 ? TRUE : FALSE);
531     return (attached);
534 /*
535  *  ======== Ipc_getConfig ========
536  *  Get the run-time configuration for the Ipc module
537  *
538  *  This is an IPC internal function. It is used to acquire
539  *  the global Ipc module configuration values from LAD.
540  */
541 Void Ipc_getConfig(Ipc_Config *cfg)
543     Int status;
544     LAD_ClientHandle handle;
545     struct LAD_CommandObj cmd;
546     union LAD_ResponseObj rsp;
548     handle = LAD_findHandle();
549     if (handle == LAD_MAXNUMCLIENTS) {
550         PRINTVERBOSE0("Ipc_getConfig: no connection to LAD\n");
551         return;
552     }
554     cmd.cmd = LAD_IPC_GETCONFIG;
555     cmd.clientId = handle;
557     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
558         PRINTVERBOSE1("Ipc_getConfig: sending LAD command failed, "
559                 "status=%d\n", status);
560         return;
561     }
563     if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
564         PRINTVERBOSE1("Ipc_getConfig: no LAD response, status=%d\n", status);
565         return;
566     }
568     memcpy(cfg, &rsp.ipcConfig, sizeof(Ipc_Config));
569     return;