SDOCM00114391 IPC cluster support is missing on Linux
[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>
50 #include <IMessageQTransport.h>
51 #include <TransportRpmsg.h>
53 /* User side headers */
54 #include <ladclient.h>
56 /* IPC startup/shutdown stuff: */
57 #include <ti/ipc/MultiProc.h>
58 #include <GateHWSpinlock.h>
59 #include <_GateMP.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_Module;
71 /* =============================================================================
72  *  Globals
73  * =============================================================================
74  */
75 static Ipc_Module Ipc_module = {
76     .refCount   = 0,
77     .gate       = PTHREAD_MUTEX_INITIALIZER
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     TransportRpmsg_Handle  transport;
97     TransportRpmsg_Params  params;
98     IMessageQTransport_Handle iMsgQTrans;
99     MessageQ_Config        msgqCfg;
100     MultiProc_Config       mpCfg;
101 #if defined(GATEMP_SUPPORT)
102     GateHWSpinlock_Config  gateHWCfg;
103 #endif
104     Int                    attachStatus;
105     Int32                  status;
106     LAD_Status             ladStatus;
107     Int                    i;
108     UInt16                 procId;
109     Int32                  attachedAny;
110     UInt16                 clusterSize;
111     UInt16                 clusterBase;
113     /* function must be serialized */
114     pthread_mutex_lock(&Ipc_module.gate);
116     /* ensure only first thread performs startup procedure */
117     if (++Ipc_module.refCount > 1) {
118         status = Ipc_S_ALREADYSETUP;
119         goto exit;
120     }
122     /* Catch ctrl-C, and cleanup: */
123     (void) signal(SIGINT, cleanup);
125     if (getenv("IPC_DEBUG") != NULL) {
126         /* turn on tracing */
127         if (getenv("IPC_DEBUG")[0] == '1') {
128             /* level 1 enables typical user API tracing */
129             _MessageQ_verbose = TRUE;
130             _MultiProc_verbose = TRUE;
131             _NameServer_verbose = TRUE;
132 #if defined(GATEMP_SUPPORT)
133             _GateMP_verbose = TRUE;
135             _GateHWSpinlock_verbose = TRUE;
136 #endif
137         }
138         else if ((getenv("IPC_DEBUG")[0] == '2') ||
139                 (getenv("IPC_DEBUG")[0] == '3')) {
140             /* levels 2 and 3 add socket and LAD client tracing */
141             _MessageQ_verbose = TRUE;
142             _MultiProc_verbose = TRUE;
143             _NameServer_verbose = TRUE;
145 #if defined(GATEMP_SUPPORT)
146             _GateMP_verbose = TRUE;
148             _GateHWSpinlock_verbose = TRUE;
149 #endif
151             /* internals - should be declared in respective _*.h files */
152             extern Bool _SocketFxns_verbose;
153             extern Bool _LAD_Client_verbose;
155             _SocketFxns_verbose = TRUE;
156             _LAD_Client_verbose = TRUE;
157         }
158     }
160     ladStatus = LAD_connect(&ladHandle);
161     if (ladStatus != LAD_SUCCESS) {
162         printf("Ipc_start: LAD_connect() failed: %d\n", ladStatus);
163         status = Ipc_E_FAIL;
164         goto exit;
165     }
167     /*  Get MultiProc configuration from LAD and initialize local
168      *  MultiProc config structure.
169      */
170     MultiProc_getConfig(&mpCfg);
171     _MultiProc_initCfg(&mpCfg);
173     status = NameServer_setup();
175     if (status >= 0) {
176         MessageQ_getConfig(&msgqCfg);
177         MessageQ_setup(&msgqCfg);
179         /*  Attach to all remote processors. For now, must attach to
180          *  at least one to tolerate MessageQ_E_RESOURCE failures.
181          */
182         status = Ipc_S_SUCCESS;
183         attachedAny = FALSE;
185         /* needed to enumerate processors in cluster */
186         clusterSize = MultiProc_getNumProcsInCluster();
187         clusterBase = MultiProc_getBaseIdOfCluster();
189         for (i = 0, procId = clusterBase; i < clusterSize; i++, procId++) {
191             if (MultiProc_self() == procId) {
192                 continue;
193             }
195             params.rprocId = procId;
196             transport = TransportRpmsg_create(&params, &attachStatus);
198             if (transport) {
199                 iMsgQTrans = TransportRpmsg_upCast(transport);
200                 MessageQ_registerTransport(iMsgQTrans, procId, 0);
201                 attachedAny = TRUE;
202             }
203             else {
204                 if (attachStatus == MessageQ_E_RESOURCE) {
205                     continue;
206                 }
207                 printf("Ipc_start: failed to attach to procId=%d status=%d\n",
208                        procId, attachStatus);
209                 status = Ipc_E_FAIL;
210                 break;
211             }
212         }
213         if (!attachedAny) {
214             status = Ipc_E_FAIL;
215         }
216     }
217     else {
218         printf("Ipc_start: NameServer_setup() failed: %d\n", status);
219         status = Ipc_E_FAIL;
220     }
222     /* Start GateMP only if device has support */
223 #if defined(GATEMP_SUPPORT)
224     if (GateMP_isSetup()) {
225         /*
226          * Get HWSpinlock base address and size from LAD and
227          * initialize the local config structure.
228          */
229         GateHWSpinlock_getConfig(&gateHWCfg);
230         _GateHWSpinlock_cfgParams = gateHWCfg;
232         status = GateHWSpinlock_start();
233         if (status < 0) {
234             printf("Ipc_start: GateHWSpinlock_start failed: %d\n",
235                 status);
236             status = Ipc_E_FAIL;
237             goto gatehwspinlockstart_fail;
238         }
239         else {
240             status = GateMP_start();
241             if (status < 0) {
242                 printf("Ipc_start: GateMP_start failed: %d\n",
243                 status);
244                 status = Ipc_E_FAIL;
245                 goto gatempstart_fail;
246             }
247         }
248     }
249 #endif
250     /* Success */
251     goto exit;
252 #if defined(GATEMP_SUPPORT)
253 gatempstart_fail:
254     GateHWSpinlock_stop();
255 gatehwspinlockstart_fail:
256 #if 0
257     for (procId = procId - 1; (procId > 0) && (status >= 0); procId--) {
258         MessageQ_detach(procId);
259     }
260 #endif
261 #endif
263 exit:
264     /* if error, must decrement reference count */
265     if (status < 0) {
266         Ipc_module.refCount--;
267     }
269     pthread_mutex_unlock(&Ipc_module.gate);
271     return (status);
274 /*
275  *  ======== Ipc_stop ========
276  */
277 Int Ipc_stop(Void)
279     Int32       status = Ipc_S_SUCCESS;
280     LAD_Status  ladStatus;
281     Int         i;
282     UInt16      procId;
283     UInt16      clusterSize;
284     UInt16      clusterBase;
286     /* function must be serialized */
287     pthread_mutex_lock(&Ipc_module.gate);
289     /* ensure only last thread performs stop procedure */
290     if (--Ipc_module.refCount > 0) {
291         goto exit;
292     }
294     /* needed to enumerate processors in cluster */
295     clusterSize = MultiProc_getNumProcsInCluster();
296     clusterBase = MultiProc_getBaseIdOfCluster();
298     /* detach from all remote processors, assuming they are up */
299     for (i = 0, procId = clusterBase; i < clusterSize; i++, procId++) {
301         /*  no need to detach from myself */
302         if (MultiProc_self() == procId) {
303             continue;
304         }
305 #if 0
306         status = MessageQ_detach(procId);
307         if (status < 0) {
308             printf("Ipc_stop: MessageQ_detach(%d) failed: %d\n",
309                 procId, status);
310             status = Ipc_E_FAIL;
311             goto exit;
312        }
313 #endif
314     }
316     status = MessageQ_destroy();
317     if (status < 0) {
318         printf("Ipc_stop: MessageQ_destroy() failed: %d\n", status);
319         status = Ipc_E_FAIL;
320         goto exit;
321     }
323     status = NameServer_destroy();
324     if (status < 0) {
325         printf("Ipc_stop: NameServer_destroy() failed: %d\n", status);
326         status = Ipc_E_FAIL;
327         goto exit;
328     }
330     ladStatus = LAD_disconnect(ladHandle);
331     if (ladStatus != LAD_SUCCESS) {
332         printf("LAD_disconnect() failed: %d\n", ladStatus);
333         status = Ipc_E_FAIL;
334         goto exit;
335     }
337 exit:
338     pthread_mutex_unlock(&Ipc_module.gate);
340     return (status);
343 static void cleanup(int arg)
345     printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
346     Ipc_stop();
347     exit(0);