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)
108 {
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);
274 }
276 /*
277 * ======== Ipc_stop ========
278 */
279 Int Ipc_stop(Void)
280 {
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);
355 }
357 /*
358 * ======== Ipc_transportConfig ========
359 */
360 Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
361 {
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);
382 }
384 static void cleanup(int arg)
385 {
386 printf("Ipc: Caught SIGINT, calling Ipc_stop...\n");
387 Ipc_stop();
388 exit(0);
389 }
391 /*
392 * ======== Ipc_attach ========
393 */
394 Int Ipc_attach(UInt16 procId)
395 {
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);
445 }
447 /*
448 * ======== Ipc_detach ========
449 */
450 Int Ipc_detach(UInt16 procId)
451 {
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);
507 }
509 /*
510 * ======== Ipc_isAttached ========
511 */
512 Bool Ipc_isAttached(UInt16 procId)
513 {
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);
531 }
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)
541 {
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;
569 }