66AK2G: Linux: Add support for K2G
[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>
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)
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             fprintf(stderr, "Ipc_start: GateMP_start failed: %d\n", status);
276             status = Ipc_E_FAIL;
277             GateHWSpinlock_stop();
278             goto exit;
279         }
280     }
281 #endif
283     /* getting here means we have successfully started */
284     Ipc_module.refCount++;
286 exit:
287     pthread_mutex_unlock(&Ipc_module.gate);
289     return (status);
292 /*
293  *  ======== Ipc_stop ========
294  */
295 Int Ipc_stop(Void)
297     Int32       status = Ipc_S_SUCCESS;
298     LAD_Status  ladStatus;
299     UInt16      procId;
300     UInt16      clusterSize;
301     UInt16      baseId;
302     UInt16      clusterId;
304     /* function must be serialized */
305     pthread_mutex_lock(&Ipc_module.gate);
307     if (Ipc_module.refCount == 0) {
308         status = Ipc_E_INVALIDSTATE;
309         goto exit;
310     }
312     /* ensure only last thread performs stop procedure */
313     if (--Ipc_module.refCount > 0) {
314         goto exit;
315     }
317     /* if using ProcSync_ALL, then detach from all processors in the cluster */
318     if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
319         clusterSize = MultiProc_getNumProcsInCluster();
320         baseId = MultiProc_getBaseIdOfCluster();
322         for (clusterId = 0; clusterId < clusterSize; clusterId++) {
323             procId = baseId + clusterId;
325             if (MultiProc_self() == procId) {
326                 continue;
327             }
329             /*  For backward compatibility, we might not be attached to
330              *  all cluster members. Skip unattached processors.
331              */
332             if (!Ipc_isAttached(procId)) {
333                 continue;
334             }
336             status = Ipc_detach(procId);
338             if (status < 0) {
339                 /* Should we keep going or stop? */
340             }
341         }
342     }
344     Ipc_module.transportFactory->deleteFxn();
346     /* unregister the standard heap */
347     MessageQ_unregisterHeap(Ipc_module.config.idHeapStd);
349     status = MessageQ_destroy();
350     if (status < 0) {
351         fprintf(stderr, "Ipc_stop: MessageQ_destroy() failed: %d\n", status);
352         status = Ipc_E_FAIL;
353         goto exit;
354     }
356     status = NameServer_destroy();
357     if (status < 0) {
358         fprintf(stderr, "Ipc_stop: NameServer_destroy() failed: %d\n", status);
359         status = Ipc_E_FAIL;
360         goto exit;
361     }
363     ladStatus = LAD_disconnect(ladHandle);
364     if (ladStatus != LAD_SUCCESS) {
365         fprintf(stderr, "LAD_disconnect() failed: %d\n", ladStatus);
366         status = Ipc_E_FAIL;
367         goto exit;
368     }
370 exit:
371     pthread_mutex_unlock(&Ipc_module.gate);
373     return (status);
376 /*
377  *  ======== Ipc_transportConfig ========
378  */
379 Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
381     Int status = Ipc_S_SUCCESS;
383     pthread_mutex_lock(&Ipc_module.gate);
385     /*  Only the first caller can actually set the transport factory.
386      *  Subsequent callers (e.g. multi-threaded application) must be
387      *  using the same factory. Otherwise, it is an error.
388      */
389     if (Ipc_module.transportFactory == NULL) {
390         Ipc_module.transportFactory = factory;
391     }
392     else if (Ipc_module.transportFactory != factory) {
393         status = Ipc_E_INVALIDARG;
394         goto exit;
395     }
397 exit:
398     pthread_mutex_unlock(&Ipc_module.gate);
400     return (status);
403 static void cleanup(int arg)
405     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
406     Ipc_stop();
407     exit(0);
410 /*
411  *  ======== Ipc_attach ========
412  */
413 Int Ipc_attach(UInt16 procId)
415     Int status = Ipc_S_SUCCESS;
416     UInt16 clusterId;
417 #if defined(GATEMP_SUPPORT)
418     Int ret;
419 #endif
421     /* cannot attach to yourself */
422     if (MultiProc_self() == procId) {
423         status =  Ipc_E_INVALIDARG;
424         goto done;
425     }
427     /* processor must be a member of the cluster */
428     clusterId = procId - MultiProc_getBaseIdOfCluster();
430     if (clusterId >= MultiProc_getNumProcsInCluster()) {
431         status =  Ipc_E_INVALIDARG;
432         goto done;
433     }
435     /* function must be serialized */
436     pthread_mutex_lock(&Ipc_module.gate);
438     /* if already attached, just increment reference count */
439     if (Ipc_module.attached[clusterId] > 0) {
440         Ipc_module.attached[clusterId]++;
441         goto done;
442     }
444     /* establish name server connection to remote processor */
445     status = NameServer_attach(procId);
447     if (status < 0) {
448         status = Ipc_E_FAIL;
449         goto done;
450     }
452     /* attach the transport to remote processor */
453     status = Ipc_module.transportFactory->attachFxn(procId);
455     if (status < 0) {
456         status = Ipc_E_FAIL;
457         goto done;
458     }
460     /* hack: bind all existing message queues to remote processor */
461     MessageQ_bind(procId);
463 #if defined(GATEMP_SUPPORT)
464     if (GateMP_isSetup()) {
465         /* establish GateMP connection to remote processor */
466         ret = GateMP_attach(procId);
468         if (ret < 0) {
469             PRINTVERBOSE1("Ipc_attach: failed to GateMP_attach to procId %d\n",
470                           procId);
471         }
472     }
473 #endif
475     /* getting here means we have successfully attached */
476     Ipc_module.attached[clusterId]++;
478 done:
479     pthread_mutex_unlock(&Ipc_module.gate);
481     return (status);
484 /*
485  *  ======== Ipc_detach ========
486  */
487 Int Ipc_detach(UInt16 procId)
489     Int status = Ipc_S_SUCCESS;
490     UInt16 clusterId;
491 #if defined(GATEMP_SUPPORT)
492     Int ret;
493 #endif
495     /* cannot detach from yourself */
496     if (MultiProc_self() == procId) {
497         status =  Ipc_E_INVALIDARG;
498         goto done;
499     }
501     /* processor must be a member of the cluster */
502     clusterId = procId - MultiProc_getBaseIdOfCluster();
504     if (clusterId >= MultiProc_getNumProcsInCluster()) {
505         status =  Ipc_E_INVALIDARG;
506         goto done;
507     }
509     /* function must be serialized */
510     pthread_mutex_lock(&Ipc_module.gate);
512     if (Ipc_module.attached[clusterId] == 0) {
513         status = Ipc_E_INVALIDSTATE;
514         goto done;
515     }
517     if (--Ipc_module.attached[clusterId] > 0) {
518         goto done;
519     }
521 #if defined(GATEMP_SUPPORT)
522     if (GateMP_isSetup()) {
523         /* establish GateMP connection to remote processor */
524         ret = GateMP_detach(procId);
526         if (ret < 0) {
527             PRINTVERBOSE1("Ipc_detach: failed to GateMP_detach from procId %d\n",
528                           procId);
529         }
530     }
531 #endif
533     /* hack: unbind all existing message queues from remote processor */
534     MessageQ_unbind(procId);
536     /* detach transport from remote processor */
537     status = Ipc_module.transportFactory->detachFxn(procId);
539     if (status < 0) {
540         status = Ipc_E_FAIL;
541         /* report the error */
542         goto done;
543     }
545     /* remove connection to remote processor */
546     status = NameServer_detach(procId);
548     if (status < 0) {
549         status = Ipc_E_FAIL;
550         /* report the error */
551         goto done;
552     }
554 done:
555     if (status < 0) {
556         /* report error */
557         fprintf(stderr, "Ipc_detach: Error %d, procId %d\n", status, procId);
558     }
559     pthread_mutex_unlock(&Ipc_module.gate);
561     return (status);
564 /*
565  *  ======== Ipc_isAttached ========
566  */
567 Bool Ipc_isAttached(UInt16 procId)
569     Bool attached;
570     UInt16 clusterId;
572     /* cannot be attached to yourself */
573     if (MultiProc_self() == procId) {
574         return (FALSE);
575     }
577     /* processor must be a member of the cluster */
578     clusterId = procId - MultiProc_getBaseIdOfCluster();
580     if (clusterId >= MultiProc_getNumProcsInCluster()) {
581         return (FALSE);
582     }
584     attached = (Ipc_module.attached[clusterId] > 0 ? TRUE : FALSE);
585     return (attached);
588 /*
589  *  ======== Ipc_getConfig ========
590  *  Get the run-time configuration for the Ipc module
591  *
592  *  This is an IPC internal function. It is used to acquire
593  *  the global Ipc module configuration values from LAD.
594  */
595 Void Ipc_getConfig(Ipc_Config *cfg)
597     Int status;
598     LAD_ClientHandle handle;
599     struct LAD_CommandObj cmd;
600     union LAD_ResponseObj rsp;
602     handle = LAD_findHandle();
603     if (handle == LAD_MAXNUMCLIENTS) {
604         PRINTVERBOSE0("Ipc_getConfig: no connection to LAD\n");
605         return;
606     }
608     cmd.cmd = LAD_IPC_GETCONFIG;
609     cmd.clientId = handle;
611     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
612         PRINTVERBOSE1("Ipc_getConfig: sending LAD command failed, "
613                 "status=%d\n", status);
614         return;
615     }
617     if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
618         PRINTVERBOSE1("Ipc_getConfig: no LAD response, status=%d\n", status);
619         return;
620     }
622     memcpy(cfg, &rsp.ipcConfig, sizeof(Ipc_Config));
623     return;