]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blobdiff - packages/ti/ipc/family/tci6638/VirtQueue.c
am65xx: Remove dependence on DEVMEM entry
[ipc/ipcdev.git] / packages / ti / ipc / family / tci6638 / VirtQueue.c
index 05671464f852574d4583596745b7471d3fb084ff..804bf48059e1e10d4964ece36726761a8528a72b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * Copyright (c) 2011-2019 Texas Instruments Incorporated - http://www.ti.com
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 /** ============================================================================
  *  @file       VirtQueue.c
  *
  *  @brief      Virtio Queue implementation for BIOS
  *
  *  Differences between BIOS version and Linux kernel (include/linux/virtio.h):
- *  - Renamed module from virtio.h to VirtQueue_Object.h to match the API prefixes;
- *  - BIOS (XDC) types and CamelCasing used;
- *  - virtio_device concept removed (i.e, assumes no containing device);
- *  - simplified scatterlist from Linux version;
- *  - VirtQueue_Objects are created statically here, so just added a VirtQueue_Object_init()
- *    fxn to take the place of the Virtio vring_new_virtqueue() API;
+ *  - Renamed module from virtio.h to VirtQueue.h to match the API prefixes
+ *  - XDC Standard Types and CamelCasing used
+ *  - virtio_device concept removed (i.e, assumes no containing device)
+ *  - simplified scatterlist from Linux version
+ *  - VirtQueue objects are created statically, added VirtQueue_Instance_init()
+ *    fxn to take the place of the Virtio vring_new_virtqueue() API
  *  - The notify function is implicit in the implementation, and not provided
- *    by the client, as it is in Linux virtio.
+ *    by the client, as it is in Linux virtio
  *
  *  All VirtQueue operations can be called in any context.
- *
- *  The virtio header should be included in an application as follows:
- *  @code
- *  #include <ti/ipc/rpmsg/VirtQueue.h>
- *  @endcode
- *
  */
 
 #include <xdc/std.h>
 #include <xdc/runtime/Memory.h>
 #include <xdc/runtime/Log.h>
 #include <xdc/runtime/Diags.h>
-#include <xdc/runtime/SysMin.h>
+#include <ti/sysbios/gates/GateAll.h>
 
 #include <ti/sysbios/knl/Clock.h>
 #include <ti/sysbios/family/c66/Cache.h>
 #include <ti/sysbios/knl/Swi.h>
 
-#include <ti/sdo/ipc/notifyDrivers/IInterrupt.h>
-#include <ti/ipc/family/tci6638/Interrupt.h>
 #include <ti/ipc/remoteproc/Resource.h>
 
 #include <ti/ipc/MultiProc.h>
 #include <ti/ipc/rpmsg/virtio_ring.h>
 
 /* Used for defining the size of the virtqueue registry */
-#define NUM_QUEUES                      2
+#define NUM_QUEUES 2
 
 #define DIV_ROUND_UP(n,d)   (((n) + (d) - 1) / (d))
 #define RP_MSG_BUFS_SPACE   (VirtQueue_RP_MSG_NUM_BUFS * RPMSG_BUF_SIZE * 2)
 
 /* With 256 buffers, our vring will occupy 3 pages */
-#define RP_MSG_RING_SIZE    ((DIV_ROUND_UP(vring_size(VirtQueue_RP_MSG_NUM_BUFS, \
-                            VirtQueue_RP_MSG_VRING_ALIGN), VirtQueue_PAGE_SIZE)) * VirtQueue_PAGE_SIZE)
+#define RP_MSG_RING_SIZE    \
+        ((DIV_ROUND_UP(vring_size(VirtQueue_RP_MSG_NUM_BUFS, \
+        VirtQueue_RP_MSG_VRING_ALIGN), \
+        VirtQueue_PAGE_SIZE)) * VirtQueue_PAGE_SIZE)
 
 /* The total IPC space needed to communicate with a remote processor */
 #define RPMSG_IPC_MEM   (RP_MSG_BUFS_SPACE + 2 * RP_MSG_RING_SIZE)
 
-#define ID_DSP_TO_A9      0
-#define ID_A9_TO_DSP      1
+#define ID_SELF_TO_HOST 0
+#define ID_HOST_TO_SELF 1
 
-extern volatile cregister Uns DNUM;
+extern volatile cregister UInt DNUM;
 
 static VirtQueue_Object *queueRegistry[NUM_QUEUES] = {NULL};
 
@@ -115,38 +110,52 @@ static inline UInt mapVAtoPA(Void * va)
 Void VirtQueue_init()
 {
     extern cregister volatile UInt DNUM;
+    UInt16 clusterId;
     UInt16 procId;
 
-    /*
-     * VirtQueue_init() must be called before MultiProcSetup_init().
-     * (Check the xdc_runtime_Startup_firstFxns__A in the XDC generated code)
-     * Abort if the procId has already been set.  We must set it!
+    /*  VirtQueue_init() must be called before MultiProcSetup_init().
+     *  Check the xdc_runtime_Startup_firstFxns__A array in the XDC
+     *  generated code. Abort if the procId has already been set; we
+     *  must set it!
      */
     if (MultiProc_self() != MultiProc_INVALIDID) {
         System_abort("VirtQueue_init(): MultiProc_self already set!");
         return;
     }
 
-    procId = DNUM + 1;
+    /* clusterId is needed to support single image loading */
+    clusterId = MultiProc_getBaseIdOfCluster();
 
-    /* Set the local ID */
+    /* compute local procId, add one to account for HOST processor */
+    procId = clusterId + DNUM + 1;
+
+    /* set the local procId */
     MultiProc_setLocalId(procId);
 }
 
 /*
  * ======== VirtQueue_Instance_init ========
  */
-Void VirtQueue_Instance_init(VirtQueue_Object *vq, UInt16 remoteProcId,
-                             const VirtQueue_Params *params)
+Int VirtQueue_Instance_init(VirtQueue_Object *vq, UInt16 remoteProcId,
+                             const VirtQueue_Params *params, Error_Block *eb)
 {
     void *vringAddr = NULL;
-    Error_Block eb;
+#if !defined(xdc_runtime_Assert_DISABLE_ALL) \
+        || !defined(xdc_runtime_Log_DISABLE_ALL)
+    UInt32 marValue;
+#endif
 
     VirtQueue_module->traceBufPtr = Resource_getTraceBufPtr();
 
-    Error_init(&eb);
+    /* create the thread protection gate */
+    vq->gateH = GateAll_create(NULL, eb);
+    if (Error_check(eb)) {
+        Log_error0("VirtQueue_create: could not create gate object");
+        Error_raise(NULL, Error_E_generic, 0, 0);
+        return(0);
+    }
 
-    vq->vringPtr = Memory_calloc(NULL, sizeof(struct vring), 0, &eb);
+    vq->vringPtr = Memory_calloc(NULL, sizeof(struct vring), 0, eb);
     Assert_isTrue((vq->vringPtr != NULL), NULL);
 
     vq->callback = params->callback;
@@ -158,23 +167,41 @@ Void VirtQueue_Instance_init(VirtQueue_Object *vq, UInt16 remoteProcId,
     vq->swiHandle = params->swiHandle;
 
     switch (vq->id) {
-        case ID_DSP_TO_A9:
-            vringAddr = (struct vring *) (VirtQueue_CORE0_MEM_VRING0 +
-                (DNUM * VirtQueue_VRING_OFFSET));
-            break;
-        case ID_A9_TO_DSP:
-            vringAddr = (struct vring *) (VirtQueue_CORE0_MEM_VRING1 +
-                (DNUM * VirtQueue_VRING_OFFSET));
-            break;
+        case ID_SELF_TO_HOST:
+        case ID_HOST_TO_SELF:
+            vringAddr = (struct vring *)Resource_getVringDA(vq->id);
+            Assert_isTrue(vringAddr != NULL, NULL);
+#ifdef PER_CORE_VRING_PATCH
+            /* Add per core offset: must match on host side: */
+            vringAddr = (struct vring *)((UInt32)vringAddr +
+                                         (DNUM * VirtQueue_VRING_OFFSET));
+#endif
+            /* Also, assert that the vring address is non-cached: */
+#if !defined(xdc_runtime_Assert_DISABLE_ALL) \
+        || !defined(xdc_runtime_Log_DISABLE_ALL)
+            marValue = Cache_getMar((Ptr)vringAddr);
+#endif
+            Log_print1(Diags_USER1, "Vring cache is %s",
+                 (IArg)(marValue & 0x1 ? "enabled" : "disabled"));
+            Assert_isTrue(!(marValue & 0x1), NULL);
+            break ;
+
+         default:
+            Log_error1("VirtQueue_create: invalid vq->id: %d", vq->id);
+            GateAll_delete(&vq->gateH);
+            Memory_free(NULL, vq->vringPtr, sizeof(struct vring));
+            Error_raise(NULL, Error_E_generic, 0, 0);
+            return(0);
     }
 
-    Log_print3(Diags_USER1,
-            "vring: %d 0x%x (0x%x)\n", vq->id, (IArg)vringAddr,
+    Log_print3(Diags_USER1, "vring: %d 0x%x (0x%x)", vq->id, (IArg)vringAddr,
             RP_MSG_RING_SIZE);
 
-    vring_init(vq->vringPtr, VirtQueue_RP_MSG_NUM_BUFS, vringAddr, VirtQueue_RP_MSG_VRING_ALIGN);
+    vring_init(vq->vringPtr, VirtQueue_RP_MSG_NUM_BUFS, vringAddr,
+            VirtQueue_RP_MSG_VRING_ALIGN);
 
     queueRegistry[vq->id] = vq;
+    return(0);
 }
 
 /*
@@ -183,21 +210,18 @@ Void VirtQueue_Instance_init(VirtQueue_Object *vq, UInt16 remoteProcId,
 Void VirtQueue_kick(VirtQueue_Handle vq)
 {
     struct vring *vring = vq->vringPtr;
-    IInterrupt_IntInfo intInfo;
 
     /* For now, simply interrupt remote processor */
     if (vring->avail->flags & VRING_AVAIL_F_NO_INTERRUPT) {
-        Log_print0(Diags_USER1,
-                "VirtQueue_kick: no kick because of VRING_AVAIL_F_NO_INTERRUPT\n");
+        Log_print0(Diags_USER1, "VirtQueue_kick: no kick because of "
+                "VRING_AVAIL_F_NO_INTERRUPT");
         return;
     }
 
-    Log_print2(Diags_USER1,
-            "VirtQueue_kick: Sending interrupt to proc %d with payload 0x%x\n",
-            (IArg)vq->procId, (IArg)vq->id);
+    Log_print2(Diags_USER1, "VirtQueue_kick: Sending interrupt to proc %d "
+            "with payload 0x%x", (IArg)vq->procId, (IArg)vq->id);
 
-    intInfo.localIntId  = Interrupt_SRCS_BITPOS_CORE0;
-    Interrupt_intSend(vq->procId, &intInfo, vq->id);
+    VirtQueue_InterruptProxy_intSend(vq->procId, NULL, 0);
 }
 
 /*
@@ -207,20 +231,24 @@ Int VirtQueue_addUsedBuf(VirtQueue_Handle vq, Int16 head, Int len)
 {
     struct vring_used_elem *used;
     struct vring *vring = vq->vringPtr;
+    IArg key;
 
-    if ((head > vring->num) || (head < 0)) {
+    key = GateAll_enter(vq->gateH);
+    if (((unsigned int)head > vring->num) || (head < 0)) {
         Error_raise(NULL, Error_E_generic, 0, 0);
     }
-
-    /*
-    * The virtqueue contains a ring of used buffers.  Get a pointer to the
-    * next entry in that used ring.
-    */
-    used = &vring->used->ring[vring->used->idx % vring->num];
-    used->id = head;
-    used->len = len;
-
-    vring->used->idx++;
+    else {
+        /*
+         * The virtqueue contains a ring of used buffers.  Get a pointer to the
+         * next entry in that used ring.
+         */
+        used = &vring->used->ring[vring->used->idx % vring->num];
+        used->id = head;
+        used->len = len;
+
+        vring->used->idx++;
+    }
+    GateAll_leave(vq->gateH, key);
 
     return (0);
 }
@@ -232,18 +260,22 @@ Int VirtQueue_addAvailBuf(VirtQueue_Object *vq, Void *buf)
 {
     UInt16 avail;
     struct vring *vring = vq->vringPtr;
+    IArg key;
 
+    key = GateAll_enter(vq->gateH);
     if (vq->num_free == 0) {
         /* There's no more space */
         Error_raise(NULL, Error_E_generic, 0, 0);
     }
+    else {
+        vq->num_free--;
 
-    vq->num_free--;
+        avail =  vring->avail->idx++ % vring->num;
 
-    avail =  vring->avail->idx++ % vring->num;
-
-    vring->desc[avail].addr = mapVAtoPA(buf);
-    vring->desc[avail].len = RPMSG_BUF_SIZE;
+        vring->desc[avail].addr = mapVAtoPA(buf);
+        vring->desc[avail].len = RPMSG_BUF_SIZE;
+    }
+    GateAll_leave(vq->gateH, key);
 
     return (vq->num_free);
 }
@@ -256,17 +288,21 @@ Void *VirtQueue_getUsedBuf(VirtQueue_Object *vq)
     UInt16 head;
     Void *buf;
     struct vring *vring = vq->vringPtr;
+    IArg key;
 
+    key = GateAll_enter(vq->gateH);
     /* There's nothing available? */
     if (vq->last_used_idx == vring->used->idx) {
-        return (NULL);
+        buf = NULL;
     }
+    else {
+        head = vring->used->ring[vq->last_used_idx % vring->num].id;
+        vq->last_used_idx++;
+        vq->num_free++;
 
-    head = vring->used->ring[vq->last_used_idx % vring->num].id;
-    vq->last_used_idx++;
-    vq->num_free++;
-
-    buf = mapPAtoVA(vring->desc[head].addr);
+        buf = mapPAtoVA(vring->desc[head].addr);
+    }
+    GateAll_leave(vq->gateH, key);
 
     return (buf);
 }
@@ -276,32 +312,39 @@ Void *VirtQueue_getUsedBuf(VirtQueue_Object *vq)
  */
 Int16 VirtQueue_getAvailBuf(VirtQueue_Handle vq, Void **buf, Int *len)
 {
-    UInt16 head;
+    Int16 head;
     struct vring *vring = vq->vringPtr;
+    IArg key;
+
+    key = GateAll_enter(vq->gateH);
+    Log_print6(Diags_USER1, "getAvailBuf vq: 0x%x %d %d %d 0x%x 0x%x",
+        (IArg)vq, (IArg)vq->last_avail_idx, (IArg)vring->avail->idx,
+        (IArg)vring->num, (IArg)&vring->avail, (IArg)vring->avail);
 
-    Log_print6(Diags_USER1, "getAvailBuf vq: 0x%x %d %d %d 0x%x 0x%x\n",
-        (IArg)vq,
-        vq->last_avail_idx, vring->avail->idx, vring->num,
-        (IArg)&vring->avail, (IArg)vring->avail);
+    /*  Clear flag here to avoid race condition with remote processor.
+     *  This is a negative flag, clearing it means that we want to
+     *  receive an interrupt when a buffer has been added to the pool.
+     */
+    vring->used->flags &= ~VRING_USED_F_NO_NOTIFY;
 
     /* There's nothing available? */
     if (vq->last_avail_idx == vring->avail->idx) {
-        /* We need to know about added buffers */
-        vring->used->flags &= ~VRING_USED_F_NO_NOTIFY;
-        return (-1);
+        head = (-1);
     }
-
-    /* No need to be kicked about added buffers anymore */
-    vring->used->flags |= VRING_USED_F_NO_NOTIFY;
-
-    /*
-     * Grab the next descriptor number they're advertising, and increment
-     * the index we've seen.
-     */
-    head = vring->avail->ring[vq->last_avail_idx++ % vring->num];
-
-    *buf = mapPAtoVA(vring->desc[head].addr);
-    *len = vring->desc[head].len;
+    else {
+        /* No need to be kicked about added buffers anymore */
+        vring->used->flags |= VRING_USED_F_NO_NOTIFY;
+
+        /*
+         * Grab the next descriptor number they're advertising, and increment
+         * the index we've seen.
+         */
+        head = vring->avail->ring[vq->last_avail_idx++ % vring->num];
+
+        *buf = mapPAtoVA(vring->desc[head].addr);
+        *len = vring->desc[head].len;
+    }
+    GateAll_leave(vq->gateH, key);
 
     return (head);
 }
@@ -310,11 +353,11 @@ Int16 VirtQueue_getAvailBuf(VirtQueue_Handle vq, Void **buf, Int *len)
  * ======== VirtQueue_isr ========
  * Note 'msg' is ignored: it is only used where there is a mailbox payload.
  */
-Void VirtQueue_isr(UArg msg)
+static Void VirtQueue_isr(UArg msg)
 {
     VirtQueue_Object *vq;
 
-    Log_print1(Diags_USER1, "VirtQueue_isr received msg = 0x%x\n", msg);
+    Log_print1(Diags_USER1, "VirtQueue_isr received msg = 0x%x", msg);
 
     vq = queueRegistry[0];
     if (vq) {
@@ -329,26 +372,19 @@ Void VirtQueue_isr(UArg msg)
 /*
  * ======== VirtQueue_startup ========
  */
-Void VirtQueue_startup(UInt16 remoteProcId, Bool isHost)
+Void VirtQueue_startup(UInt16 procId, Bool isHost)
 {
-    IInterrupt_IntInfo intInfo;
 
-    intInfo.intVectorId = Interrupt_DSPINT;
-    intInfo.localIntId  = Interrupt_SRCS_BITPOS_HOST;
-
-
-    /*
-     * Wait for first kick from host, which happens to coincide with the
+    /* Wait for first kick from host, which happens to coincide with the
      * priming of host's receive buffers, indicating host is ready to send.
      * Since interrupt is cleared, we throw away this first kick, which is
      * OK since we don't process this in the ISR anyway.
      */
-    Log_print0(Diags_USER1, "VirtQueue_startup: Polling for host int...\n");
-    while (!Interrupt_checkAndClear(remoteProcId, &intInfo));
-
-    Interrupt_intRegister(remoteProcId, &intInfo, (Fxn)VirtQueue_isr, NULL);
+    Log_print0(Diags_USER1, "VirtQueue_startup: Polling for host int...");
+    while (!VirtQueue_InterruptProxy_intClear(procId, NULL));
 
-    Log_print0(Diags_USER1, "Passed VirtQueue_startup\n");
+    VirtQueue_InterruptProxy_intRegister(procId, NULL, (Fxn)VirtQueue_isr, 0);
+    Log_print0(Diags_USER1, "Passed VirtQueue_startup");
 }
 
 /* By convention, Host VirtQueues host are the even number in the pair */
@@ -394,6 +430,6 @@ Void VirtQueue_cacheWb()
 
     /* Flush the cache of the SysMin buffer only: */
     Assert_isTrue((VirtQueue_module->traceBufPtr != NULL), NULL);
-    Cache_wb(VirtQueue_module->traceBufPtr, SysMin_bufSize, Cache_Type_ALL,
+    Cache_wb(VirtQueue_module->traceBufPtr, Resource_getTraceBufSize(), Cache_Type_ALL,
              FALSE);
 }