]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blobdiff - linux/src/api/Ipc.c
Ignore cluster members which are not running
[ipc/ipcdev.git] / linux / src / api / Ipc.c
index 214c6264612627943c5e500607488ba11093372d..96804660ab401ba5489188d970224552f6f49794 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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>
 
+/* 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;
-    LAD_Status        ladStatus;
-    UInt16            rprocId;
-    Int32             attachedAny = 0;
+    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;
     }
 
-    /* 
-     * Get MultiProc configuration from LAD and initialize local MultiProc
-     * config structure.
-     */
+    /* get global configuration from LAD */
+    Ipc_getConfig(&Ipc_module.config);
+
+    /* get global configuration from LAD */
     MultiProc_getConfig(&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(); rprocId++) {
-            if (0 == rprocId) {
-                /* Skip host, which should always be 0th entry. */
-                continue;
-            }
-            status = MessageQ_attach(rprocId, NULL);
-            if (status == MessageQ_E_RESOURCE) {
+
+    if (status < 0) {
+        printf("Ipc_start: NameServer_setup() failed: %d\n", status);
+        status = Ipc_E_FAIL;
+        goto exit;
+    }
+
+    /* get global configuration from LAD */
+    MessageQ_getConfig(&msgqCfg);
+    MessageQ_setup(&msgqCfg);
+
+    /* invoke the transport factory create method */
+    status = Ipc_module.transportFactory->createFxn();
+
+    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;
             }
-            if (status < 0) {
-                printf("Ipc_start: MessageQ_attach(%d) failed: %d\n",
-                       rprocId, status);
-                status = Ipc_E_FAIL;
 
-                break;
-            }
-            else {
-                attachedAny = 1;
+            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 */
             }
         }
-        if (attachedAny) {
-            status = Ipc_S_SUCCESS;
-        }
     }
-    else {
-        printf("Ipc_start: NameServer_setup() failed: %d\n", status);
-        status = Ipc_E_FAIL;
+
+    /* 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 = GateMP_start();
+        if (status < 0) {
+            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);
 }
 
-
-/* Function to stop Ipc */
-Int Ipc_stop (Void)
+/*
+ *  ======== Ipc_stop ========
+ */
+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;
+    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? */
+            }
         }
-        status = MessageQ_detach(rprocId);
-        if (status < 0) {
-            printf("Ipc_stop: MessageQ_detach(%d) failed: %d\n",
-                rprocId, status);
-            status = Ipc_E_FAIL;
-            goto exit;
-       }
     }
 
+    Ipc_module.transportFactory->deleteFxn();
+
     status = MessageQ_destroy();
     if (status < 0) {
         printf("Ipc_stop: MessageQ_destroy() failed: %d\n", status);
@@ -180,6 +350,35 @@ Int Ipc_stop (Void)
     }
 
 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);
 }
 
@@ -189,3 +388,183 @@ static void cleanup(int arg)
     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;
+}