diff --git a/linux/src/api/Ipc.c b/linux/src/api/Ipc.c
index ebd6c470f46ae483d12dc0e30f1cc439b185583e..96804660ab401ba5489188d970224552f6f49794 100644 (file)
--- a/linux/src/api/Ipc.c
+++ b/linux/src/api/Ipc.c
/*
- * Copyright (c) 2012-2013, Texas Instruments Incorporated
+ * Copyright (c) 2012-2015 Texas Instruments Incorporated - http://www.ti.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* @brief Starts and stops user side Ipc
* All setup/destroy APIs on user side will be call from this
* module.
- *
- * @ver 0002
- *
*/
-/* Standard headers */
+/* standard headers */
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
+#include <string.h>
-/* Common IPC headers: */
+/* package headers */
#include <ti/ipc/Std.h>
#include <ti/ipc/Ipc.h>
#include <ti/ipc/NameServer.h>
/* IPC startup/shutdown stuff: */
#include <ti/ipc/MultiProc.h>
+#include <GateHWSpinlock.h>
+#include <_GateMP.h>
+#include <_Ipc.h>
+#include <_MultiProc.h>
#include <_MessageQ.h>
#include <_NameServer.h>
-MultiProc_Config _MultiProc_cfg;
+/* module definition */
+typedef struct {
+ Int refCount;
+ pthread_mutex_t gate;
+ Ipc_TransportFactoryFxns *transportFactory;
+ Ipc_Config config;
+ Int attached[MultiProc_MAXPROCESSORS];
+} Ipc_Module;
+
+/* =============================================================================
+ * Globals
+ * =============================================================================
+ */
+static Ipc_Module Ipc_module = {
+ .refCount = 0,
+#if defined(IPC_BUILDOS_ANDROID)
+ .gate = PTHREAD_RECURSIVE_MUTEX_INITIALIZER,
+#else
+// only _NP (non-portable) type available in CG tools which we're using
+ .gate = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+#endif
+ .transportFactory = NULL,
+ .config.procSync = Ipc_ProcSync_NONE
+};
+
+GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
static LAD_ClientHandle ladHandle;
-static void cleanup(int arg);
+/* traces in this file are controlled via _Ipc_verbose */
+Bool _Ipc_verbose = FALSE;
+#define verbose _Ipc_verbose
/** ============================================================================
* Functions
* ============================================================================
*/
-/* Function to start Ipc */
-Int Ipc_start (Void)
+static void cleanup(int arg);
+
+
+/*
+ * ======== Ipc_start ========
+ */
+Int Ipc_start(Void)
{
- MessageQ_Config msgqCfg;
- MultiProc_Config mpCfg;
- Int32 status = Ipc_S_SUCCESS;
- LAD_Status ladStatus;
- UInt16 rprocId;
+ MessageQ_Config msgqCfg;
+ MultiProc_Config mpCfg;
+#if defined(GATEMP_SUPPORT)
+ GateHWSpinlock_Config gateHWCfg;
+#endif
+ Int status;
+ LAD_Status ladStatus;
+ UInt16 procId;
+ UInt16 clusterSize;
+ UInt16 baseId;
+ UInt16 clusterId;
+ Int i;
+
+ /* function must be serialized */
+ pthread_mutex_lock(&Ipc_module.gate);
+
+ /* ensure only first thread performs startup procedure */
+ if (Ipc_module.refCount >= 1) {
+ Ipc_module.refCount++;
+ status = Ipc_S_ALREADYSETUP;
+ goto exit;
+ }
+
+ /* make sure transport factory has been configured */
+ if (Ipc_module.transportFactory == NULL) {
+ status = Ipc_E_INVALIDSTATE;
+ goto exit;
+ }
+
+ /* initialize module object */
+ for (i = 0; i < MultiProc_MAXPROCESSORS; i++) {
+ Ipc_module.attached[i] = 0;
+ }
/* Catch ctrl-C, and cleanup: */
(void) signal(SIGINT, cleanup);
+ if (getenv("IPC_DEBUG") != NULL) {
+ /* turn on tracing */
+ if (getenv("IPC_DEBUG")[0] == '1') {
+ /* level 1 enables typical user API tracing */
+ _MessageQ_verbose = TRUE;
+ _MultiProc_verbose = TRUE;
+ _NameServer_verbose = TRUE;
+#if defined(GATEMP_SUPPORT)
+ _GateMP_verbose = TRUE;
+
+ _GateHWSpinlock_verbose = TRUE;
+#endif
+ }
+ else if ((getenv("IPC_DEBUG")[0] == '2') ||
+ (getenv("IPC_DEBUG")[0] == '3')) {
+ /* levels 2 and 3 add socket and LAD client tracing */
+ _MessageQ_verbose = TRUE;
+ _MultiProc_verbose = TRUE;
+ _NameServer_verbose = TRUE;
+
+#if defined(GATEMP_SUPPORT)
+ _GateMP_verbose = TRUE;
+
+ _GateHWSpinlock_verbose = TRUE;
+#endif
+
+ /* internals - should be declared in respective _*.h files */
+ extern Bool _SocketFxns_verbose;
+ extern Bool _LAD_Client_verbose;
+
+ _SocketFxns_verbose = TRUE;
+ _LAD_Client_verbose = TRUE;
+ }
+ }
+
+ /* establish a communication link to the LAD daemon */
ladStatus = LAD_connect(&ladHandle);
+
if (ladStatus != LAD_SUCCESS) {
printf("Ipc_start: LAD_connect() failed: %d\n", ladStatus);
status = Ipc_E_FAIL;
goto exit;
}
- /* Setup and get MultiProc configuration from LAD */
+ /* get global configuration from LAD */
+ Ipc_getConfig(&Ipc_module.config);
+
+ /* get global configuration from LAD */
MultiProc_getConfig(&mpCfg);
- _MultiProc_cfg = mpCfg;
+ _MultiProc_initCfg(&mpCfg);
+ /* setup name server thread in LAD daemon */
status = NameServer_setup();
- if (status >= 0) {
- MessageQ_getConfig(&msgqCfg);
- MessageQ_setup(&msgqCfg);
-
- /* Now attach to all remote processors, assuming they are up. */
- for (rprocId = 0;
- (rprocId < MultiProc_getNumProcessors()) && (status >= 0);
- rprocId++) {
- if (0 == rprocId) {
- /* Skip host, which should always be 0th entry. */
- continue;
- }
- status = MessageQ_attach (rprocId, NULL);
- if (status < 0) {
- printf("Ipc_start: MessageQ_attach(%d) failed: %d\n",
- rprocId, status);
- status = Ipc_E_FAIL;
- }
- }
- }
- else {
+
+ if (status < 0) {
printf("Ipc_start: NameServer_setup() failed: %d\n", status);
status = Ipc_E_FAIL;
+ goto exit;
}
-exit:
- return (status);
-}
+ /* get global configuration from LAD */
+ MessageQ_getConfig(&msgqCfg);
+ MessageQ_setup(&msgqCfg);
+ /* invoke the transport factory create method */
+ status = Ipc_module.transportFactory->createFxn();
-/* Function to stop Ipc */
-Int Ipc_stop (Void)
-{
- Int32 status = Ipc_S_SUCCESS;
- LAD_Status ladStatus;
- UInt16 rprocId;
-
- /* Now detach from all remote processors, assuming they are up. */
- for (rprocId = 0;
- (rprocId < MultiProc_getNumProcessors()) && (status >= 0);
- rprocId++) {
- if (0 == rprocId) {
- /* Skip host, which should always be 0th entry. */
- continue;
+ if (status < 0) {
+ goto exit;
+ }
+
+ /* if using ProcSync_ALL, then attach to all processors in the cluster */
+ if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
+ clusterSize = MultiProc_getNumProcsInCluster();
+ baseId = MultiProc_getBaseIdOfCluster();
+
+ for (clusterId = 0; clusterId < clusterSize; clusterId++) {
+ procId = baseId + clusterId;
+
+ if (procId == MultiProc_self()) {
+ continue;
+ }
+
+ status = Ipc_attach(procId);
+
+ /* For backward compatibility, it is okay for attach to fail.
+ * We don't expect all remote processors to be running.
+ */
+ if (status < 0) {
+ status = 0;
+ /* do nothing */
+ }
+ }
+ }
+
+ /* Start GateMP only if device has support */
+#if defined(GATEMP_SUPPORT)
+ if (GateMP_isSetup()) {
+ /*
+ * Get HWSpinlock base address and size from LAD and
+ * initialize the local config structure.
+ */
+ GateHWSpinlock_getConfig(&gateHWCfg);
+ _GateHWSpinlock_cfgParams = gateHWCfg;
+
+ status = GateHWSpinlock_start();
+ if (status < 0) {
+ printf("Ipc_start: GateHWSpinlock_start failed: %d\n", status);
+ status = Ipc_E_FAIL;
+ goto exit;
}
- status = MessageQ_detach(rprocId);
+
+ status = GateMP_start();
if (status < 0) {
- printf("Ipc_stop: MessageQ_detach(%d) failed: %d\n",
- rprocId, status);
+ printf("Ipc_start: GateMP_start failed: %d\n", status);
status = Ipc_E_FAIL;
+ GateHWSpinlock_stop();
goto exit;
- }
+ }
}
+#endif
+
+ /* getting here means we have successfully started */
+ Ipc_module.refCount++;
+
+exit:
+ pthread_mutex_unlock(&Ipc_module.gate);
+
+ return (status);
+}
+
+/*
+ * ======== Ipc_stop ========
+ */
+Int Ipc_stop(Void)
+{
+ Int32 status = Ipc_S_SUCCESS;
+ LAD_Status ladStatus;
+ UInt16 procId;
+ UInt16 clusterSize;
+ UInt16 baseId;
+ UInt16 clusterId;
+
+ /* function must be serialized */
+ pthread_mutex_lock(&Ipc_module.gate);
+
+ if (Ipc_module.refCount == 0) {
+ status = Ipc_E_INVALIDSTATE;
+ goto exit;
+ }
+
+ /* ensure only last thread performs stop procedure */
+ if (--Ipc_module.refCount > 0) {
+ goto exit;
+ }
+
+ /* if using ProcSync_ALL, then detach from all processors in the cluster */
+ if (Ipc_module.config.procSync == Ipc_ProcSync_ALL) {
+ clusterSize = MultiProc_getNumProcsInCluster();
+ baseId = MultiProc_getBaseIdOfCluster();
+
+ for (clusterId = 0; clusterId < clusterSize; clusterId++) {
+ procId = baseId + clusterId;
+
+ if (MultiProc_self() == procId) {
+ continue;
+ }
+
+ /* For backward compatibility, we might not be attached to
+ * all cluster members. Skip unattached processors.
+ */
+ if (!Ipc_isAttached(procId)) {
+ continue;
+ }
+
+ status = Ipc_detach(procId);
+
+ if (status < 0) {
+ /* Should we keep going or stop? */
+ }
+ }
+ }
+
+ Ipc_module.transportFactory->deleteFxn();
status = MessageQ_destroy();
if (status < 0) {
}
exit:
+ pthread_mutex_unlock(&Ipc_module.gate);
+
+ return (status);
+}
+
+/*
+ * ======== Ipc_transportConfig ========
+ */
+Int Ipc_transportConfig(Ipc_TransportFactoryFxns *factory)
+{
+ Int status = Ipc_S_SUCCESS;
+
+ pthread_mutex_lock(&Ipc_module.gate);
+
+ /* Only the first caller can actually set the transport factory.
+ * Subsequent callers (e.g. multi-threaded application) must be
+ * using the same factory. Otherwise, it is an error.
+ */
+ if (Ipc_module.transportFactory == NULL) {
+ Ipc_module.transportFactory = factory;
+ }
+ else if (Ipc_module.transportFactory != factory) {
+ status = Ipc_E_INVALIDARG;
+ goto exit;
+ }
+
+exit:
+ pthread_mutex_unlock(&Ipc_module.gate);
+
return (status);
}
Ipc_stop();
exit(0);
}
+
+/*
+ * ======== Ipc_attach ========
+ */
+Int Ipc_attach(UInt16 procId)
+{
+ Int status = Ipc_S_SUCCESS;
+ UInt16 clusterId;
+
+ /* cannot attach to yourself */
+ if (MultiProc_self() == procId) {
+ status = Ipc_E_INVALIDARG;
+ goto done;
+ }
+
+ /* processor must be a member of the cluster */
+ clusterId = procId - MultiProc_getBaseIdOfCluster();
+
+ if (clusterId >= MultiProc_getNumProcsInCluster()) {
+ status = Ipc_E_INVALIDARG;
+ goto done;
+ }
+
+ /* function must be serialized */
+ pthread_mutex_lock(&Ipc_module.gate);
+
+ /* if already attached, just increment reference count */
+ if (Ipc_module.attached[clusterId] > 0) {
+ Ipc_module.attached[clusterId]++;
+ goto done;
+ }
+
+ /* establish name server connection to remote processor */
+ status = NameServer_attach(procId);
+
+ if (status < 0) {
+ status = Ipc_E_FAIL;
+ goto done;
+ }
+
+ /* attach the transport to remote processor */
+ status = Ipc_module.transportFactory->attachFxn(procId);
+
+ if (status < 0) {
+ status = Ipc_E_FAIL;
+ goto done;
+ }
+
+ /* getting here means we have successfully attached */
+ Ipc_module.attached[clusterId]++;
+
+done:
+ pthread_mutex_unlock(&Ipc_module.gate);
+
+ return (status);
+}
+
+/*
+ * ======== Ipc_detach ========
+ */
+Int Ipc_detach(UInt16 procId)
+{
+ Int status = Ipc_S_SUCCESS;
+ UInt16 clusterId;
+
+ /* cannot detach from yourself */
+ if (MultiProc_self() == procId) {
+ status = Ipc_E_INVALIDARG;
+ goto done;
+ }
+
+ /* processor must be a member of the cluster */
+ clusterId = procId - MultiProc_getBaseIdOfCluster();
+
+ if (clusterId >= MultiProc_getNumProcsInCluster()) {
+ status = Ipc_E_INVALIDARG;
+ goto done;
+ }
+
+ /* function must be serialized */
+ pthread_mutex_lock(&Ipc_module.gate);
+
+ if (Ipc_module.attached[clusterId] == 0) {
+ status = Ipc_E_INVALIDSTATE;
+ goto done;
+ }
+
+ if (--Ipc_module.attached[clusterId] > 0) {
+ goto done;
+ }
+
+ /* detach transport from remote processor */
+ status = Ipc_module.transportFactory->detachFxn(procId);
+
+ if (status < 0) {
+ status = Ipc_E_FAIL;
+ /* report the error */
+ goto done;
+ }
+
+ /* remove connection to remote processor */
+ status = NameServer_detach(procId);
+
+ if (status < 0) {
+ status = Ipc_E_FAIL;
+ /* report the error */
+ goto done;
+ }
+
+done:
+ if (status < 0) {
+ /* report error */
+ printf("Ipc_detach: Error %d, procId %d\n", status, procId);
+ }
+ pthread_mutex_unlock(&Ipc_module.gate);
+
+ return (status);
+}
+
+/*
+ * ======== Ipc_isAttached ========
+ */
+Bool Ipc_isAttached(UInt16 procId)
+{
+ Bool attached;
+ UInt16 clusterId;
+
+ /* cannot be attached to yourself */
+ if (MultiProc_self() == procId) {
+ return (FALSE);
+ }
+
+ /* processor must be a member of the cluster */
+ clusterId = procId - MultiProc_getBaseIdOfCluster();
+
+ if (clusterId >= MultiProc_getNumProcsInCluster()) {
+ return (FALSE);
+ }
+
+ attached = (Ipc_module.attached[clusterId] > 0 ? TRUE : FALSE);
+ return (attached);
+}
+
+/*
+ * ======== Ipc_getConfig ========
+ * Get the run-time configuration for the Ipc module
+ *
+ * This is an IPC internal function. It is used to acquire
+ * the global Ipc module configuration values from LAD.
+ */
+Void Ipc_getConfig(Ipc_Config *cfg)
+{
+ Int status;
+ LAD_ClientHandle handle;
+ struct LAD_CommandObj cmd;
+ union LAD_ResponseObj rsp;
+
+ handle = LAD_findHandle();
+ if (handle == LAD_MAXNUMCLIENTS) {
+ PRINTVERBOSE0("Ipc_getConfig: no connection to LAD\n");
+ return;
+ }
+
+ cmd.cmd = LAD_IPC_GETCONFIG;
+ cmd.clientId = handle;
+
+ if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
+ PRINTVERBOSE1("Ipc_getConfig: sending LAD command failed, "
+ "status=%d\n", status);
+ return;
+ }
+
+ if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
+ PRINTVERBOSE1("Ipc_getConfig: no LAD response, status=%d\n", status);
+ return;
+ }
+
+ memcpy(cfg, &rsp.ipcConfig, sizeof(Ipc_Config));
+ return;
+}