Remove DSP2 from invalid list and improve error handling for non-existing core
[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                 /* do nothing */
236             }
237         }
238     }
240     /* Start GateMP only if device has support */
241 #if defined(GATEMP_SUPPORT)
242     if (GateMP_isSetup()) {
243         /*
244          * Get HWSpinlock base address and size from LAD and
245          * initialize the local config structure.
246          */
247         GateHWSpinlock_getConfig(&gateHWCfg);
248         _GateHWSpinlock_cfgParams = gateHWCfg;
250         status = GateHWSpinlock_start();
251         if (status < 0) {
252             printf("Ipc_start: GateHWSpinlock_start failed: %d\n", status);
253             status = Ipc_E_FAIL;
254             goto exit;
255         }
257         status = GateMP_start();
258         if (status < 0) {
259             printf("Ipc_start: GateMP_start failed: %d\n", status);
260             status = Ipc_E_FAIL;
261             GateHWSpinlock_stop();
262             goto exit;
263         }
264     }
265 #endif
267     /* getting here means we have successfully started */
268     Ipc_module.refCount++;
270 exit:
271     pthread_mutex_unlock(&Ipc_module.gate);
273     return (status);
276 /*
277  *  ======== Ipc_stop ========
278  */
279 Int Ipc_stop(Void)
281     Int32       status = Ipc_S_SUCCESS;
282     LAD_Status  ladStatus;
283     UInt16      procId;
284     UInt16      clusterSize;
285     UInt16      baseId;
286     UInt16      clusterId;
288     /* function must be serialized */
289     pthread_mutex_lock(&Ipc_module.gate);
291     if (Ipc_module.refCount == 0) {
292         status = Ipc_E_INVALIDSTATE;
293         goto exit;
294     }
296     /* ensure only last thread performs stop procedure */
297     if (--Ipc_module.refCount > 0) {
298         goto exit;
299     }
301     /* if using ProcSync_ALL, then detach from all processors in the cluster */
302     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
303         clusterSize = MultiProc_getNumProcsInCluster();
304         baseId = MultiProc_getBaseIdOfCluster();
306         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
307             procId = baseId + clusterId;
309             if (MultiProc_self() == procId) {
310                 continue;
311             }
313             /*  For backward compatibility, we might not be attached to
314              *  all cluster members. Skip unattached processors.
315              */
316             if (!Ipc_isAttached(procId)) {
317                 continue;
318             }
320             status = Ipc_detach(procId);
322             if (status < 0) {
323                 /* Should we keep going or stop? */
324             }
325         }
326     }
328     Ipc_module.transportFactory->deleteFxn();
330     status = MessageQ_destroy();
331     if (status < 0) {
332         printf("Ipc_stop: MessageQ_destroy() failed: %d\n", status);
333         status = Ipc_E_FAIL;
334         goto exit;
335     }
337     status = NameServer_destroy();
338     if (status < 0) {
339         printf("Ipc_stop: NameServer_destroy() failed: %d\n", status);
340         status = Ipc_E_FAIL;
341         goto exit;
342     }
344     ladStatus = LAD_disconnect(ladHandle);
345     if (ladStatus != LAD_SUCCESS) {
346         printf("LAD_disconnect() failed: %d\n", ladStatus);
347         status = Ipc_E_FAIL;
348         goto exit;
349     }
351 exit:
352     pthread_mutex_unlock(&Ipc_module.gate);
354     return (status);
357 /*
358  *  ======== Ipc_transportConfig ========
359  */
360 Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
362     Int status = Ipc_S_SUCCESS;
364     pthread_mutex_lock(&Ipc_module.gate);
366     /*  Only the first caller can actually set the transport factory.
367      *  Subsequent callers (e.g. multi-threaded application) must be
368      *  using the same factory. Otherwise, it is an error.
369      */
370     if (Ipc_module.transportFactory == NULL) {
371         Ipc_module.transportFactory = factory;
372     }
373     else if (Ipc_module.transportFactory != factory) {
374         status = Ipc_E_INVALIDARG;
375         goto exit;
376     }
378 exit:
379     pthread_mutex_unlock(&Ipc_module.gate);
381     return (status);
384 static void cleanup(int arg)
386     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
387     Ipc_stop();
388     exit(0);
391 /*
392  *  ======== Ipc_attach ========
393  */
394 Int Ipc_attach(UInt16 procId)
396     Int status = Ipc_S_SUCCESS;
397     UInt16 clusterId;
399     /* cannot attach to yourself */
400     if (MultiProc_self() == procId) {
401         status =  Ipc_E_INVALIDARG;
402         goto done;
403     }
405     /* processor must be a member of the cluster */
406     clusterId = procId - MultiProc_getBaseIdOfCluster();
408     if (clusterId >= MultiProc_getNumProcsInCluster()) {
409         status =  Ipc_E_INVALIDARG;
410         goto done;
411     }
413     /* function must be serialized */
414     pthread_mutex_lock(&Ipc_module.gate);
416     /* if already attached, just increment reference count */
417     if (Ipc_module.attached[clusterId] > 0) {
418         Ipc_module.attached[clusterId]++;
419         goto done;
420     }
422     /* establish name server connection to remote processor */
423     status = NameServer_attach(procId);
425     if (status < 0) {
426         status = Ipc_E_FAIL;
427         goto done;
428     }
430     /* attach the transport to remote processor */
431     status = Ipc_module.transportFactory->attachFxn(procId);
433     if (status < 0) {
434         status = Ipc_E_FAIL;
435         goto done;
436     }
438     /* getting here means we have successfully attached */
439     Ipc_module.attached[clusterId]++;
441 done:
442     pthread_mutex_unlock(&Ipc_module.gate);
444     return (status);
447 /*
448  *  ======== Ipc_detach ========
449  */
450 Int Ipc_detach(UInt16 procId)
452     Int status = Ipc_S_SUCCESS;
453     UInt16 clusterId;
455     /* cannot detach from yourself */
456     if (MultiProc_self() == procId) {
457         status =  Ipc_E_INVALIDARG;
458         goto done;
459     }
461     /* processor must be a member of the cluster */
462     clusterId = procId - MultiProc_getBaseIdOfCluster();
464     if (clusterId >= MultiProc_getNumProcsInCluster()) {
465         status =  Ipc_E_INVALIDARG;
466         goto done;
467     }
469     /* function must be serialized */
470     pthread_mutex_lock(&Ipc_module.gate);
472     if (Ipc_module.attached[clusterId] == 0) {
473         status = Ipc_E_INVALIDSTATE;
474         goto done;
475     }
477     if (--Ipc_module.attached[clusterId] > 0) {
478         goto done;
479     }
481     /* detach transport from remote processor */
482     status = Ipc_module.transportFactory->detachFxn(procId);
484     if (status < 0) {
485         status = Ipc_E_FAIL;
486         /* report the error */
487         goto done;
488     }
490     /* remove connection to remote processor */
491     status = NameServer_detach(procId);
493     if (status < 0) {
494         status = Ipc_E_FAIL;
495         /* report the error */
496         goto done;
497     }
499 done:
500     if (status < 0) {
501         /* report error */
502         printf("Ipc_detach: Error %d, procId %d\n", status, procId);
503     }
504     pthread_mutex_unlock(&Ipc_module.gate);
506     return (status);
509 /*
510  *  ======== Ipc_isAttached ========
511  */
512 Bool Ipc_isAttached(UInt16 procId)
514     Bool attached;
515     UInt16 clusterId;
517     /* cannot be attached to yourself */
518     if (MultiProc_self() == procId) {
519         return (FALSE);
520     }
522     /* processor must be a member of the cluster */
523     clusterId = procId - MultiProc_getBaseIdOfCluster();
525     if (clusterId >= MultiProc_getNumProcsInCluster()) {
526         return (FALSE);
527     }
529     attached = (Ipc_module.attached[clusterId] > 0 ? TRUE : FALSE);
530     return (attached);
533 /*
534  *  ======== Ipc_getConfig ========
535  *  Get the run-time configuration for the Ipc module
536  *
537  *  This is an IPC internal function. It is used to acquire
538  *  the global Ipc module configuration values from LAD.
539  */
540 Void Ipc_getConfig(Ipc_Config *cfg)
542     Int status;
543     LAD_ClientHandle handle;
544     struct LAD_CommandObj cmd;
545     union LAD_ResponseObj rsp;
547     handle = LAD_findHandle();
548     if (handle == LAD_MAXNUMCLIENTS) {
549         PRINTVERBOSE0("Ipc_getConfig: no connection to LAD\n");
550         return;
551     }
553     cmd.cmd = LAD_IPC_GETCONFIG;
554     cmd.clientId = handle;
556     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
557         PRINTVERBOSE1("Ipc_getConfig: sending LAD command failed, "
558                 "status=%d\n", status);
559         return;
560     }
562     if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
563         PRINTVERBOSE1("Ipc_getConfig: no LAD response, status=%d\n", status);
564         return;
565     }
567     memcpy(cfg, &rsp.ipcConfig, sizeof(Ipc_Config));
568     return;