]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/performance-audio-sr.git/blob - ipc_3_43_00_00_eng/linux/src/api/Ipc.c
Add IPC 3.34.00.00 eng release
[processor-sdk/performance-audio-sr.git] / ipc_3_43_00_00_eng / linux / src / api / Ipc.c
1 /*
2  * Copyright (c) 2012-2016 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>
51 #include <ti/ipc/heaps/HeapStd.h>
52 #include <ti/ipc/interfaces/IHeap.h>
54 /* User side headers */
55 #include <ladclient.h>
57 /* IPC startup/shutdown stuff: */
58 #include <ti/ipc/MultiProc.h>
59 #include <GateHWSpinlock.h>
60 #include <_GateMP.h>
61 #include <_Ipc.h>
62 #include <_MultiProc.h>
63 #include <_MessageQ.h>
64 #include <_NameServer.h>
66 /* module definition */
67 typedef struct {
68     Int                         refCount;
69     pthread_mutex_t             gate;
70     Ipc_TransportFactoryFxns   *transportFactory;
71     Ipc_Config                  config;
72     Int                         attached[MultiProc_MAXPROCESSORS];
73 } Ipc_Module;
75 /* hack: rpmsgproto driver work around */
76 Void MessageQ_bind(UInt16 procId);
77 Void MessageQ_unbind(UInt16 procId);
80 /* =============================================================================
81  *  Globals
82  * =============================================================================
83  */
84 static Ipc_Module Ipc_module = {
85     .refCount           = 0,
86 #if defined(IPC_BUILDOS_ANDROID) && (PLATFORM_SDK_VERSION < 23)
87     .gate               = PTHREAD_RECURSIVE_MUTEX_INITIALIZER,
88 #else
89 // only _NP (non-portable) type available in CG tools which we're using
90     .gate               = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
91 #endif
92     .transportFactory   = NULL,
93     .config.procSync    = Ipc_ProcSync_NONE,
94     .config.idHeapStd   = 0
95 };
97 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
98 static LAD_ClientHandle ladHandle;
100 /* traces in this file are controlled via _Ipc_verbose */
101 Bool _Ipc_verbose = FALSE;
102 #define verbose _Ipc_verbose
104 /** ============================================================================
105  *  Functions
106  *  ============================================================================
107  */
108 static void cleanup(int arg);
111 /*
112  *  ======== Ipc_start ========
113  */
114 Int Ipc_start(Void)
116     MessageQ_Config         msgqCfg;
117     MultiProc_Config        mpCfg;
118 #if defined(GATEMP_SUPPORT)
119     GateHWSpinlock_Config   gateHWCfg;
120 #endif
121     Int         status;
122     LAD_Status  ladStatus;
123     UInt16      procId;
124     UInt16      clusterSize;
125     UInt16      baseId;
126     UInt16      clusterId;
127     Int         i;
128     HeapStd_Handle heap;
129     IHeap_Handle iheap;
131     /* function must be serialized */
132     pthread_mutex_lock(&Ipc_module.gate);
134     /* ensure only first thread performs startup procedure */
135     if (Ipc_module.refCount >= 1) {
136         Ipc_module.refCount++;
137         status = Ipc_S_ALREADYSETUP;
138         goto exit;
139     }
141     /* make sure transport factory has been configured */
142     if (Ipc_module.transportFactory == NULL) {
143         status = Ipc_E_INVALIDSTATE;
144         goto exit;
145     }
147     /* initialize module object */
148     for (i = 0; i < MultiProc_MAXPROCESSORS; i++) {
149         Ipc_module.attached[i] = 0;
150     }
152     /* Catch ctrl-C, and cleanup: */
153     (void) signal(SIGINT, cleanup);
155     if (getenv("IPC_DEBUG") != NULL) {
156         /* turn on tracing */
157         if (getenv("IPC_DEBUG")[0] == '1') {
158             /* level 1 enables typical user API tracing */
159             _MessageQ_verbose = TRUE;
160             _MultiProc_verbose = TRUE;
161             _NameServer_verbose = TRUE;
162 #if defined(GATEMP_SUPPORT)
163             _GateMP_verbose = TRUE;
165             _GateHWSpinlock_verbose = TRUE;
166 #endif
167         }
168         else if ((getenv("IPC_DEBUG")[0] == '2') ||
169                 (getenv("IPC_DEBUG")[0] == '3')) {
170             /* levels 2 and 3 add socket and LAD client tracing */
171             _MessageQ_verbose = TRUE;
172             _MultiProc_verbose = TRUE;
173             _NameServer_verbose = TRUE;
175 #if defined(GATEMP_SUPPORT)
176             _GateMP_verbose = TRUE;
178             _GateHWSpinlock_verbose = TRUE;
179 #endif
181             /* internals - should be declared in respective _*.h files */
182             extern Bool _SocketFxns_verbose;
183             extern Bool _LAD_Client_verbose;
185             _SocketFxns_verbose = TRUE;
186             _LAD_Client_verbose = TRUE;
187         }
188     }
190     /* establish a communication link to the LAD daemon */
191     ladStatus = LAD_connect(&ladHandle);
193     if (ladStatus != LAD_SUCCESS) {
194         fprintf(stderr, "Ipc_start: LAD_connect() failed: %d\n", ladStatus);
195         status = Ipc_E_FAIL;
196         goto exit;
197     }
199     /* get global configuration from LAD */
200     Ipc_getConfig(&Ipc_module.config);
202     /* get global configuration from LAD */
203     MultiProc_getConfig(&mpCfg);
204     _MultiProc_initCfg(&mpCfg);
206     /* setup name server thread in LAD daemon */
207     status = NameServer_setup();
209     if (status < 0) {
210         fprintf(stderr, "Ipc_start: NameServer_setup() failed: %d\n", status);
211         status = Ipc_E_FAIL;
212         goto exit;
213     }
215     /* get global configuration from LAD */
216     MessageQ_getConfig(&msgqCfg);
217     MessageQ_setup(&msgqCfg);
219     /* register the standard heap */
220     heap = HeapStd_handle();
221     iheap = HeapStd_upCast(heap);
222     MessageQ_registerHeap((Ptr)iheap, Ipc_module.config.idHeapStd);
224     /* invoke the transport factory create method */
225     status = Ipc_module.transportFactory->createFxn();
227     if (status < 0) {
228         goto exit;
229     }
231     /* if using ProcSync_ALL, then attach to all processors in the cluster */
232     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
233         clusterSize = MultiProc_getNumProcsInCluster();
234         baseId = MultiProc_getBaseIdOfCluster();
236         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
237             procId = baseId + clusterId;
239             if (procId == MultiProc_self()) {
240                 continue;
241             }
243             status = Ipc_attach(procId);
245             /*  For backward compatibility, it is okay for attach to fail.
246              *  We don't expect all remote processors to be running.
247              */
248             if (status < 0) {
249                 status = 0;
250                 /* do nothing */
251             }
252         }
253     }
255     /* Start GateMP only if device has support */
256 #if defined(GATEMP_SUPPORT)
257     if (GateMP_isSetup()) {
258         /*
259          * Get HWSpinlock base address and size from LAD and
260          * initialize the local config structure.
261          */
262         GateHWSpinlock_getConfig(&gateHWCfg);
263         _GateHWSpinlock_cfgParams = gateHWCfg;
265         status = GateHWSpinlock_start();
266         if (status < 0) {
267             fprintf(stderr, "Ipc_start: GateHWSpinlock_start failed: %d\n",
268                     status);
269             status = Ipc_E_FAIL;
270             goto exit;
271         }
273         status = GateMP_start();
274         if (status < 0) {
275             if (status == GateMP_E_NOTFOUND) {
276                 fprintf(stderr, "Ipc_start: GateMP_start failed: not found %d\n",
277                     status);
278                 status = 0;
279             } else {
280                 fprintf(stderr, "Ipc_start: GateMP_start failed: %d\n", status);
281                 status = Ipc_E_FAIL;
282                 GateHWSpinlock_stop();
283                 goto exit;
284             }
285         }
286     }
287 #endif
289     /* getting here means we have successfully started */
290     Ipc_module.refCount++;
292 exit:
293     pthread_mutex_unlock(&Ipc_module.gate);
295     return (status);
298 /*
299  *  ======== Ipc_stop ========
300  */
301 Int Ipc_stop(Void)
303     Int32       status = Ipc_S_SUCCESS;
304     LAD_Status  ladStatus;
305     UInt16      procId;
306     UInt16      clusterSize;
307     UInt16      baseId;
308     UInt16      clusterId;
310     /* function must be serialized */
311     pthread_mutex_lock(&Ipc_module.gate);
313     if (Ipc_module.refCount == 0) {
314         status = Ipc_E_INVALIDSTATE;
315         goto exit;
316     }
318     /* ensure only last thread performs stop procedure */
319     if (--Ipc_module.refCount > 0) {
320         goto exit;
321     }
323     /* if using ProcSync_ALL, then detach from all processors in the cluster */
324     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
325         clusterSize = MultiProc_getNumProcsInCluster();
326         baseId = MultiProc_getBaseIdOfCluster();
328         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
329             procId = baseId + clusterId;
331             if (MultiProc_self() == procId) {
332                 continue;
333             }
335             /*  For backward compatibility, we might not be attached to
336              *  all cluster members. Skip unattached processors.
337              */
338             if (!Ipc_isAttached(procId)) {
339                 continue;
340             }
342             status = Ipc_detach(procId);
344             if (status < 0) {
345                 /* Should we keep going or stop? */
346             }
347         }
348     }
350     Ipc_module.transportFactory->deleteFxn();
352     /* unregister the standard heap */
353     MessageQ_unregisterHeap(Ipc_module.config.idHeapStd);
355     status = MessageQ_destroy();
356     if (status < 0) {
357         fprintf(stderr, "Ipc_stop: MessageQ_destroy() failed: %d\n", status);
358         status = Ipc_E_FAIL;
359         goto exit;
360     }
362     status = NameServer_destroy();
363     if (status < 0) {
364         fprintf(stderr, "Ipc_stop: NameServer_destroy() failed: %d\n", status);
365         status = Ipc_E_FAIL;
366         goto exit;
367     }
369     ladStatus = LAD_disconnect(ladHandle);
370     if (ladStatus != LAD_SUCCESS) {
371         fprintf(stderr, "LAD_disconnect() failed: %d\n", ladStatus);
372         status = Ipc_E_FAIL;
373         goto exit;
374     }
376 exit:
377     pthread_mutex_unlock(&Ipc_module.gate);
379     return (status);
382 /*
383  *  ======== Ipc_transportConfig ========
384  */
385 Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
387     Int status = Ipc_S_SUCCESS;
389     pthread_mutex_lock(&Ipc_module.gate);
391     /*  Only the first caller can actually set the transport factory.
392      *  Subsequent callers (e.g. multi-threaded application) must be
393      *  using the same factory. Otherwise, it is an error.
394      */
395     if (Ipc_module.transportFactory == NULL) {
396         Ipc_module.transportFactory = factory;
397     }
398     else if (Ipc_module.transportFactory != factory) {
399         status = Ipc_E_INVALIDARG;
400         goto exit;
401     }
403 exit:
404     pthread_mutex_unlock(&Ipc_module.gate);
406     return (status);
409 static void cleanup(int arg)
411     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
412     Ipc_stop();
413     exit(0);
416 /*
417  *  ======== Ipc_attach ========
418  */
419 Int Ipc_attach(UInt16 procId)
421     Int status = Ipc_S_SUCCESS;
422     UInt16 clusterId;
423 #if defined(GATEMP_SUPPORT)
424     Int ret;
425 #endif
427     /* cannot attach to yourself */
428     if (MultiProc_self() == procId) {
429         status =  Ipc_E_INVALIDARG;
430         goto done;
431     }
433     /* processor must be a member of the cluster */
434     clusterId = procId - MultiProc_getBaseIdOfCluster();
436     if (clusterId >= MultiProc_getNumProcsInCluster()) {
437         status =  Ipc_E_INVALIDARG;
438         goto done;
439     }
441     /* function must be serialized */
442     pthread_mutex_lock(&Ipc_module.gate);
444     /* if already attached, just increment reference count */
445     if (Ipc_module.attached[clusterId] > 0) {
446         Ipc_module.attached[clusterId]++;
447         goto done;
448     }
450     /* establish name server connection to remote processor */
451     status = NameServer_attach(procId);
453     if (status < 0) {
454         status = Ipc_E_FAIL;
455         goto done;
456     }
458     /* attach the transport to remote processor */
459     status = Ipc_module.transportFactory->attachFxn(procId);
461     if (status < 0) {
462         NameServer_detach(procId);
463         status = Ipc_E_FAIL;
464         goto done;
465     }
467     /* hack: bind all existing message queues to remote processor */
468     MessageQ_bind(procId);
470 #if defined(GATEMP_SUPPORT)
471     if (GateMP_isSetup()) {
472         /* establish GateMP connection to remote processor */
473         ret = GateMP_attach(procId);
475         if (ret < 0) {
476             PRINTVERBOSE1("Ipc_attach: failed to GateMP_attach to procId %d\n",
477                           procId);
478         }
479     }
480 #endif
482     /* getting here means we have successfully attached */
483     Ipc_module.attached[clusterId]++;
485 done:
486     pthread_mutex_unlock(&Ipc_module.gate);
488     return (status);
491 /*
492  *  ======== Ipc_detach ========
493  */
494 Int Ipc_detach(UInt16 procId)
496     Int status = Ipc_S_SUCCESS;
497     UInt16 clusterId;
498 #if defined(GATEMP_SUPPORT)
499     Int ret;
500 #endif
502     /* cannot detach from yourself */
503     if (MultiProc_self() == procId) {
504         status =  Ipc_E_INVALIDARG;
505         goto done;
506     }
508     /* processor must be a member of the cluster */
509     clusterId = procId - MultiProc_getBaseIdOfCluster();
511     if (clusterId >= MultiProc_getNumProcsInCluster()) {
512         status =  Ipc_E_INVALIDARG;
513         goto done;
514     }
516     /* function must be serialized */
517     pthread_mutex_lock(&Ipc_module.gate);
519     if (Ipc_module.attached[clusterId] == 0) {
520         status = Ipc_E_INVALIDSTATE;
521         goto done;
522     }
524     if (--Ipc_module.attached[clusterId] > 0) {
525         goto done;
526     }
528 #if defined(GATEMP_SUPPORT)
529     if (GateMP_isSetup()) {
530         /* establish GateMP connection to remote processor */
531         ret = GateMP_detach(procId);
533         if (ret < 0) {
534             PRINTVERBOSE1("Ipc_detach: failed to GateMP_detach from procId %d\n",
535                           procId);
536         }
537     }
538 #endif
540     /* hack: unbind all existing message queues from remote processor */
541     MessageQ_unbind(procId);
543     /* detach transport from remote processor */
544     status = Ipc_module.transportFactory->detachFxn(procId);
546     if (status < 0) {
547         status = Ipc_E_FAIL;
548         /* report the error */
549         goto done;
550     }
552     /* remove connection to remote processor */
553     status = NameServer_detach(procId);
555     if (status < 0) {
556         status = Ipc_E_FAIL;
557         /* report the error */
558         goto done;
559     }
561 done:
562     if (status < 0) {
563         /* report error */
564         fprintf(stderr, "Ipc_detach: Error %d, procId %d\n", status, procId);
565     }
566     pthread_mutex_unlock(&Ipc_module.gate);
568     return (status);
571 /*
572  *  ======== Ipc_isAttached ========
573  */
574 Bool Ipc_isAttached(UInt16 procId)
576     Bool attached;
577     UInt16 clusterId;
579     /* cannot be attached to yourself */
580     if (MultiProc_self() == procId) {
581         return (FALSE);
582     }
584     /* processor must be a member of the cluster */
585     clusterId = procId - MultiProc_getBaseIdOfCluster();
587     if (clusterId >= MultiProc_getNumProcsInCluster()) {
588         return (FALSE);
589     }
591     attached = (Ipc_module.attached[clusterId] > 0 ? TRUE : FALSE);
592     return (attached);
595 /*
596  *  ======== Ipc_getConfig ========
597  *  Get the run-time configuration for the Ipc module
598  *
599  *  This is an IPC internal function. It is used to acquire
600  *  the global Ipc module configuration values from LAD.
601  */
602 Void Ipc_getConfig(Ipc_Config *cfg)
604     Int status;
605     LAD_ClientHandle handle;
606     struct LAD_CommandObj cmd;
607     union LAD_ResponseObj rsp;
609     handle = LAD_findHandle();
610     if (handle == LAD_MAXNUMCLIENTS) {
611         PRINTVERBOSE0("Ipc_getConfig: no connection to LAD\n");
612         return;
613     }
615     cmd.cmd = LAD_IPC_GETCONFIG;
616     cmd.clientId = handle;
618     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
619         PRINTVERBOSE1("Ipc_getConfig: sending LAD command failed, "
620                 "status=%d\n", status);
621         return;
622     }
624     if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
625         PRINTVERBOSE1("Ipc_getConfig: no LAD response, status=%d\n", status);
626         return;
627     }
629     memcpy(cfg, &rsp.ipcConfig, sizeof(Ipc_Config));
630     return;