b6290941f5180e9f9df0a50f56307bbd5496f4ea
[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>
46 /* package headers */
47 #include <ti/ipc/Std.h>
48 #include <ti/ipc/Ipc.h>
49 #include <ti/ipc/NameServer.h>
51 /* User side headers */
52 #include <ladclient.h>
54 /* IPC startup/shutdown stuff: */
55 #include <ti/ipc/MultiProc.h>
56 #include <GateHWSpinlock.h>
57 #include <_GateMP.h>
58 #include <_MultiProc.h>
59 #include <_MessageQ.h>
60 #include <_NameServer.h>
62 /* module definition */
63 typedef struct {
64     Int                         refCount;
65     pthread_mutex_t             gate;
66     Ipc_TransportFactoryFxns   *transportFactory;
67 } Ipc_Module;
70 /* =============================================================================
71  *  Globals
72  * =============================================================================
73  */
74 static Ipc_Module Ipc_module = {
75     .refCount           = 0,
76     .gate               = PTHREAD_MUTEX_INITIALIZER,
77     .transportFactory   = NULL
78 };
80 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
81 static LAD_ClientHandle ladHandle;
84 /** ============================================================================
85  *  Functions
86  *  ============================================================================
87  */
88 static void cleanup(int arg);
91 /*
92  *  ======== Ipc_start ========
93  */
94 Int Ipc_start(Void)
95 {
96     MessageQ_Config         msgqCfg;
97     MultiProc_Config        mpCfg;
98 #if defined(GATEMP_SUPPORT)
99     GateHWSpinlock_Config   gateHWCfg;
100 #endif
101     Int         status;
102     LAD_Status  ladStatus;
104     /* function must be serialized */
105     pthread_mutex_lock(&Ipc_module.gate);
107     /* ensure only first thread performs startup procedure */
108     if (++Ipc_module.refCount > 1) {
109         status = Ipc_S_ALREADYSETUP;
110         goto exit;
111     }
113     /* make sure transport factory has been configured */
114     if (Ipc_module.transportFactory == NULL) {
115         status = Ipc_E_INVALIDSTATE;
116         goto exit;
117     }
119     /* Catch ctrl-C, and cleanup: */
120     (void) signal(SIGINT, cleanup);
122     if (getenv("IPC_DEBUG") != NULL) {
123         /* turn on tracing */
124         if (getenv("IPC_DEBUG")[0] == '1') {
125             /* level 1 enables typical user API tracing */
126             _MessageQ_verbose = TRUE;
127             _MultiProc_verbose = TRUE;
128             _NameServer_verbose = TRUE;
129 #if defined(GATEMP_SUPPORT)
130             _GateMP_verbose = TRUE;
132             _GateHWSpinlock_verbose = TRUE;
133 #endif
134         }
135         else if ((getenv("IPC_DEBUG")[0] == '2') ||
136                 (getenv("IPC_DEBUG")[0] == '3')) {
137             /* levels 2 and 3 add socket and LAD client tracing */
138             _MessageQ_verbose = TRUE;
139             _MultiProc_verbose = TRUE;
140             _NameServer_verbose = TRUE;
142 #if defined(GATEMP_SUPPORT)
143             _GateMP_verbose = TRUE;
145             _GateHWSpinlock_verbose = TRUE;
146 #endif
148             /* internals - should be declared in respective _*.h files */
149             extern Bool _SocketFxns_verbose;
150             extern Bool _LAD_Client_verbose;
152             _SocketFxns_verbose = TRUE;
153             _LAD_Client_verbose = TRUE;
154         }
155     }
157     ladStatus = LAD_connect(&ladHandle);
158     if (ladStatus != LAD_SUCCESS) {
159         printf("Ipc_start: LAD_connect() failed: %d\n", ladStatus);
160         status = Ipc_E_FAIL;
161         goto exit;
162     }
164     /*  Get MultiProc configuration from LAD and initialize local
165      *  MultiProc config structure.
166      */
167     MultiProc_getConfig(&mpCfg);
168     _MultiProc_initCfg(&mpCfg);
170     status = NameServer_setup();
172     if (status >= 0) {
173         MessageQ_getConfig(&msgqCfg);
174         MessageQ_setup(&msgqCfg);
176         /* invoke the transport factory create method */
177         status = Ipc_module.transportFactory->createFxn();
179         if (status < 0) {
180             goto exit;
181         }
182     }
183     else {
184         printf("Ipc_start: NameServer_setup() failed: %d\n", status);
185         status = Ipc_E_FAIL;
186     }
188     /* Start GateMP only if device has support */
189 #if defined(GATEMP_SUPPORT)
190     if (GateMP_isSetup()) {
191         /*
192          * Get HWSpinlock base address and size from LAD and
193          * initialize the local config structure.
194          */
195         GateHWSpinlock_getConfig(&gateHWCfg);
196         _GateHWSpinlock_cfgParams = gateHWCfg;
198         status = GateHWSpinlock_start();
199         if (status < 0) {
200             printf("Ipc_start: GateHWSpinlock_start failed: %d\n",
201                 status);
202             status = Ipc_E_FAIL;
203             goto gatehwspinlockstart_fail;
204         }
205         else {
206             status = GateMP_start();
207             if (status < 0) {
208                 printf("Ipc_start: GateMP_start failed: %d\n",
209                 status);
210                 status = Ipc_E_FAIL;
211                 goto gatempstart_fail;
212             }
213         }
214     }
215 #endif
216     /* Success */
217     goto exit;
218 #if defined(GATEMP_SUPPORT)
219 gatempstart_fail:
220     GateHWSpinlock_stop();
221 gatehwspinlockstart_fail:
222 #if 0
223     for (procId = procId - 1; (procId > 0) && (status >= 0); procId--) {
224         MessageQ_detach(procId);
225     }
226 #endif
227 #endif
229 exit:
230     /* if error, must decrement reference count */
231     if (status < 0) {
232         Ipc_module.refCount--;
233     }
235     pthread_mutex_unlock(&Ipc_module.gate);
237     return (status);
240 /*
241  *  ======== Ipc_stop ========
242  */
243 Int Ipc_stop(Void)
245     Int32       status = Ipc_S_SUCCESS;
246     LAD_Status  ladStatus;
247     Int         i;
248     UInt16      procId;
249     UInt16      clusterSize;
250     UInt16      clusterBase;
252     /* function must be serialized */
253     pthread_mutex_lock(&Ipc_module.gate);
255     /* ensure only last thread performs stop procedure */
256     if (--Ipc_module.refCount > 0) {
257         goto exit;
258     }
260     /* invoke the transport factory delete method */
261     Ipc_module.transportFactory->deleteFxn();
263     /* needed to enumerate processors in cluster */
264     clusterSize = MultiProc_getNumProcsInCluster();
265     clusterBase = MultiProc_getBaseIdOfCluster();
267     /* detach from all remote processors, assuming they are up */
268     for (i = 0, procId = clusterBase; i < clusterSize; i++, procId++) {
270         /*  no need to detach from myself */
271         if (MultiProc_self() == procId) {
272             continue;
273         }
274 #if 0
275         status = MessageQ_detach(procId);
276         if (status < 0) {
277             printf("Ipc_stop: MessageQ_detach(%d) failed: %d\n",
278                 procId, status);
279             status = Ipc_E_FAIL;
280             goto exit;
281        }
282 #endif
283     }
285     status = MessageQ_destroy();
286     if (status < 0) {
287         printf("Ipc_stop: MessageQ_destroy() failed: %d\n", status);
288         status = Ipc_E_FAIL;
289         goto exit;
290     }
292     status = NameServer_destroy();
293     if (status < 0) {
294         printf("Ipc_stop: NameServer_destroy() failed: %d\n", status);
295         status = Ipc_E_FAIL;
296         goto exit;
297     }
299     ladStatus = LAD_disconnect(ladHandle);
300     if (ladStatus != LAD_SUCCESS) {
301         printf("LAD_disconnect() failed: %d\n", ladStatus);
302         status = Ipc_E_FAIL;
303         goto exit;
304     }
306 exit:
307     pthread_mutex_unlock(&Ipc_module.gate);
309     return (status);
312 /*
313  *  ======== Ipc_transportConfig ========
314  */
315 Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
317     Int status = Ipc_S_SUCCESS;
319     pthread_mutex_lock(&Ipc_module.gate);
321     /*  Only the first caller can actually set the transport factory.
322      *  Subsequent callers (e.g. multi-threaded application) must be
323      *  using the same factory. Otherwise, it is an error.
324      */
325     if (Ipc_module.transportFactory == NULL) {
326         Ipc_module.transportFactory = factory;
327     }
328     else if (Ipc_module.transportFactory != factory) {
329         status = Ipc_E_INVALIDARG;
330         goto exit;
331     }
333 exit:
334     pthread_mutex_unlock(&Ipc_module.gate);
336     return (status);
339 static void cleanup(int arg)
341     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
342     Ipc_stop();
343     exit(0);