index 438e1af4f4cc007e4d91d8b1ad2a837be37a3daf..5b11e7cc6f33e10ed87cf01ee7f8205275addc99 100644 (file)
/*
- * Copyright (c) 2011-2013, Texas Instruments Incorporated
+ * Copyright (c) 2011-2014, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
*
*/
+/* this define must precede inclusion of any xdc header file */
+#define Registry_CURDESC ti_ipc_family_vayu__Desc
+#define MODULE_NAME "ti.ipc.family.vayu.VirtQueue"
+
#include <xdc/std.h>
#include <xdc/runtime/System.h>
+#include <xdc/runtime/Assert.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/Memory.h>
+#include <xdc/runtime/Registry.h>
#include <xdc/runtime/Log.h>
#include <xdc/runtime/Diags.h>
#include <ti/sysbios/hal/Hwi.h>
#include <ti/sysbios/knl/Clock.h>
-#include <ti/sysbios/gates/GateAll.h>
-#include <ti/sysbios/BIOS.h>
+#include <ti/sysbios/gates/GateHwi.h>
#include <ti/sysbios/hal/Cache.h>
#include <ti/ipc/MultiProc.h>
#endif
#include <string.h>
+#include <ti/ipc/remoteproc/Resource.h>
+#include <ti/ipc/remoteproc/rsc_types.h>
#include <ti/ipc/rpmsg/_VirtQueue.h>
#include <ti/sdo/ipc/notifyDrivers/IInterrupt.h>
#include "VirtQueue.h"
+/*
+ * The following three VIRTIO_* defines must match those in
+ * <Linux_kernel>/include/uapi/linux/virtio_config.h
+ */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
+#define VIRTIO_CONFIG_S_DRIVER 2
+#define VIRTIO_CONFIG_S_DRIVER_OK 4
+
+#define VRING_BUFS_PRIMED (VIRTIO_CONFIG_S_ACKNOWLEDGE | \
+ VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK)
+
/* Used for defining the size of the virtqueue registry */
-#define NUM_QUEUES 4
+#define NUM_QUEUES 2
/* Predefined device addresses */
#ifdef DSP
#define IPC_MEM_VRING0 0xA0000000
#define IPC_MEM_VRING1 0xA0004000
-#define IPC_MEM_VRING2 0xA0008000
-#define IPC_MEM_VRING3 0xA000c000
#else
#define IPC_MEM_VRING0 0x60000000
#define IPC_MEM_VRING1 0x60004000
-#define IPC_MEM_VRING2 0x60008000
-#define IPC_MEM_VRING3 0x6000c000
#endif
/*
- * Sizes of the virtqueues (expressed in number of buffers supported,
+ * Size of the virtqueues (expressed in number of buffers supported,
* and must be power of two)
*/
-#define VQ0_SIZE 256
-#define VQ1_SIZE 256
-#define VQ2_SIZE 256
-#define VQ3_SIZE 256
+#define VQ_SIZE 256
/*
* enum - Predefined Mailbox Messages
};
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
-#define RP_MSG_NUM_BUFS (VQ0_SIZE) /* must be power of two */
+#define RP_MSG_NUM_BUFS (VQ_SIZE) /* must be power of two */
#define RP_MSG_BUF_SIZE (512)
#define RP_MSG_BUFS_SPACE (RP_MSG_NUM_BUFS * RP_MSG_BUF_SIZE * 2)
/* 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_SYSM3_TO_A9 ID_SELF_TO_A9
-#define ID_A9_TO_SYSM3 ID_A9_TO_SELF
-#define ID_DSP_TO_A9 ID_SELF_TO_A9
-#define ID_A9_TO_DSP ID_A9_TO_SELF
-#define ID_APPM3_TO_A9 2
-#define ID_A9_TO_APPM3 3
-
typedef struct VirtQueue_Object {
/* Id for this VirtQueue_Object */
UInt16 id;
UInt16 procId;
/* Gate to protect from multiple threads */
- GateAll_Handle gateH;
+ GateHwi_Handle gateH;
} VirtQueue_Object;
+/* module diags mask */
+Registry_Desc Registry_CURDESC;
+
static struct VirtQueue_Object *queueRegistry[NUM_QUEUES] = {NULL};
static UInt16 hostProcId;
-#ifndef SMP
-static UInt16 dsp1ProcId;
-static UInt16 sysm3ProcId;
-static UInt16 appm3ProcId;
-#endif
#define DSPEVENTID 5
IInterrupt_IntInfo intInfo;
-#if defined(M3_ONLY) && !defined(SMP)
-extern Void OffloadM3_init();
-extern Int OffloadM3_processSysM3Tasks(UArg msg);
-#endif
+/*!
+ * ======== _VirtQueue_init ========
+ *
+ * This function adds the VirtQueue "module" to the Registry so that
+ * DIAGS will work with this non-XDC module.
+ * Since VirtQueue_init is not called by XDC-VirtQueue module clients, this
+ * function is called in the first VirtQueue fxn called: VirtQueue_create.
+ */
+static Void _VirtQueue_init()
+{
+ static int initialized = 0;
+
+ if (!initialized) {
+ Registry_Result result;
+
+ /* register with xdc.runtime to get a diags mask */
+ result = Registry_addModule(&Registry_CURDESC, MODULE_NAME);
+ Assert_isTrue(result == Registry_SUCCESS, (Assert_Id)NULL);
+
+ initialized = 1;
+ }
+}
static inline Void * mapPAtoVA(UInt pa)
{
struct vring_used_elem *used;
IArg key;
- key = GateAll_enter(vq->gateH);
+ key = GateHwi_enter(vq->gateH);
if ((head > vq->vring.num) || (head < 0)) {
- GateAll_leave(vq->gateH, key);
+ GateHwi_leave(vq->gateH, key);
Error_raise(NULL, Error_E_generic, 0, 0);
}
used->len = len;
vq->vring.used->idx++;
- GateAll_leave(vq->gateH, key);
+ GateHwi_leave(vq->gateH, key);
return (0);
}
vq->num_free--;
- key = GateAll_enter(vq->gateH);
+ key = GateHwi_enter(vq->gateH);
avail = vq->vring.avail->idx++ % vq->vring.num;
vq->vring.desc[avail].addr = mapVAtoPA(buf);
vq->vring.desc[avail].len = RP_MSG_BUF_SIZE;
- GateAll_leave(vq->gateH, key);
+ GateHwi_leave(vq->gateH, key);
return (vq->num_free);
}
Void *buf;
IArg key;
- key = GateAll_enter(vq->gateH);
+ key = GateHwi_enter(vq->gateH);
/* There's nothing available? */
if (vq->last_used_idx == vq->vring.used->idx) {
buf = NULL;
buf = mapPAtoVA(vq->vring.desc[head].addr);
}
- GateAll_leave(vq->gateH, key);
+ GateHwi_leave(vq->gateH, key);
return (buf);
}
Int16 head;
IArg key;
- key = GateAll_enter(vq->gateH);
+ key = GateHwi_enter(vq->gateH);
Log_print6(Diags_USER1, "getAvailBuf vq: 0x%x %d %d %d 0x%x 0x%x\n",
(IArg)vq, vq->last_avail_idx, vq->vring.avail->idx, vq->vring.num,
(IArg)&vq->vring.avail, (IArg)vq->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.
+ */
+ vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+
/* There's nothing available? */
if (vq->last_avail_idx == vq->vring.avail->idx) {
- /* We need to know about added buffers */
- vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
head = (-1);
}
else {
+ /* No need to be kicked about added buffers anymore */
+ vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+
/*
* Grab the next descriptor number they're advertising, and increment
* the index we've seen.
*buf = mapPAtoVA(vq->vring.desc[head].addr);
*len = vq->vring.desc[head].len;
}
- GateAll_leave(vq->gateH, key);
+ GateHwi_leave(vq->gateH, key);
return (head);
}
*/
Void VirtQueue_disableCallback(VirtQueue_Object *vq)
{
- //TODO
+ /* TODO */
Log_print0(Diags_USER1, "VirtQueue_disableCallback called.");
}
{
Log_print0(Diags_USER1, "VirtQueue_enableCallback called.");
- //TODO
+ /* TODO */
return (FALSE);
}
Log_print1(Diags_USER1, "VirtQueue_isr received msg = 0x%x\n", msg);
-#ifndef SMP
- if (MultiProc_self() == sysm3ProcId || MultiProc_self() == dsp1ProcId) {
-#endif
- switch(msg) {
- case (UInt)RP_MSG_MBOX_READY:
- return;
+ switch(msg) {
+ case (UInt)RP_MSG_MBOX_READY:
+ return;
- case (UInt)RP_MBOX_ECHO_REQUEST:
- InterruptProxy_intSend(hostProcId, NULL,
- (UInt)(RP_MBOX_ECHO_REPLY));
- return;
+ case (UInt)RP_MBOX_ECHO_REQUEST:
+ InterruptProxy_intSend(hostProcId, NULL, (UInt)(RP_MBOX_ECHO_REPLY));
+ return;
- case (UInt)RP_MBOX_ABORT_REQUEST:
- {
- /* Suppress Coverity Error: FORWARD_NULL: */
- // coverity[assign_zero]
- Fxn f = (Fxn)0x0;
- Log_print0(Diags_USER1, "Crash on demand ...\n");
- // coverity[var_deref_op]
- f();
- }
- return;
+ case (UInt)RP_MBOX_ABORT_REQUEST:
+ {
+ /* Suppress Coverity Error: FORWARD_NULL: */
+ /* coverity[assign_zero] */
+ Fxn f = (Fxn)0x0;
+ Log_print0(Diags_USER1, "Crash on demand ...\n");
+ /* coverity[var_deref_op] */
+ f();
+ }
+ return;
- case (UInt)RP_MSG_FLUSH_CACHE:
- Cache_wbAll();
- return;
+ case (UInt)RP_MSG_FLUSH_CACHE:
+ Cache_wbAll();
+ return;
#ifndef DSP
- case (UInt)RP_MSG_HIBERNATION:
- if (IpcPower_canHibernate() == FALSE) {
- InterruptProxy_intSend(hostProcId, NULL,
- (UInt)RP_MSG_HIBERNATION_CANCEL);
- return;
- }
-
- /* Fall through */
- case (UInt)RP_MSG_HIBERNATION_FORCE:
-#ifndef SMP
- /* Core0 should notify Core1 */
- if (MultiProc_self() == sysm3ProcId) {
- InterruptProxy_intSend(appm3ProcId, NULL,
- (UInt)(RP_MSG_HIBERNATION));
- }
-#endif
- /* Ack request */
+ case (UInt)RP_MSG_HIBERNATION:
+ if (IpcPower_canHibernate() == FALSE) {
InterruptProxy_intSend(hostProcId, NULL,
- (UInt)RP_MSG_HIBERNATION_ACK);
- IpcPower_suspend();
+ (UInt)RP_MSG_HIBERNATION_CANCEL);
return;
-#endif
- default:
-#if defined(M3_ONLY) && !defined(SMP)
- /* Check and process any Inter-M3 Offload messages */
- if (OffloadM3_processSysM3Tasks(msg))
- return;
-#endif
+ }
- /*
- * If the message isn't one of the above, it's either part of the
- * 2-message synchronization sequence or it a virtqueue message
- */
- break;
- }
-#ifndef SMP
- }
- else if (msg & 0xFFFF0000) {
-#ifndef DSP
- if (msg == (UInt)RP_MSG_HIBERNATION) {
+ /* Fall through */
+ case (UInt)RP_MSG_HIBERNATION_FORCE:
+ /* Ack request */
+ InterruptProxy_intSend(hostProcId, NULL,
+ (UInt)RP_MSG_HIBERNATION_ACK);
IpcPower_suspend();
- }
+ return;
#endif
- return;
+ default:
+ /*
+ * If the message isn't one of the above, it's either part of the
+ * 2-message synchronization sequence or it a virtqueue message
+ */
+ break;
}
- if (MultiProc_self() == sysm3ProcId && (msg == ID_A9_TO_APPM3 || msg == ID_APPM3_TO_A9)) {
- InterruptProxy_intSend(appm3ProcId, NULL, (UInt)msg);
+ /* Don't let unknown messages to pass as a virtqueue index */
+ if (msg >= NUM_QUEUES) {
+ /* Adding print here deliberately, we should never see this */
+ System_printf("VirtQueue_isr: Invalid mailbox message 0x%x "
+ "received\n", msg);
+ return;
}
- else {
-#endif
- /* Don't let unknown messages to pass as a virtqueue index */
- if (msg >= NUM_QUEUES) {
- /* Adding print here deliberately, we should never see this */
- System_printf("VirtQueue_isr: Invalid mailbox message 0x%x "
- "received\n", msg);
- return;
- }
- vq = queueRegistry[msg];
- if (vq) {
- vq->callback(vq);
- }
-#ifndef SMP
+ vq = queueRegistry[msg];
+ if (vq) {
+ vq->callback(vq);
}
-#endif
}
@@ -498,13 +490,16 @@ VirtQueue_Handle VirtQueue_create(UInt16 remoteProcId, VirtQueue_Params *params,
VirtQueue_Object *vq;
Void *vringAddr;
+ /* Perform initialization we can't do in Instance_init (being non-XDC): */
+ _VirtQueue_init();
+
vq = Memory_alloc(NULL, sizeof(VirtQueue_Object), 0, eb);
if (NULL == vq) {
return (NULL);
}
/* Create the thread protection gate */
- vq->gateH = GateAll_create(NULL, eb);
+ vq->gateH = GateHwi_create(NULL, eb);
if (Error_check(eb)) {
Log_error0("VirtQueue_create: could not create gate object");
Memory_free(NULL, vq, sizeof(VirtQueue_Object));
@@ -516,14 +511,6 @@ VirtQueue_Handle VirtQueue_create(UInt16 remoteProcId, VirtQueue_Params *params,
vq->procId = remoteProcId;
vq->last_avail_idx = 0;
-#ifndef SMP
- if (MultiProc_self() == appm3ProcId) {
- /* vqindices that belong to AppM3 should be big so they don't
- * collide with SysM3's virtqueues */
- vq->id += 2;
- }
-#endif
-
switch (vq->id) {
/* IPC transport vrings */
case ID_SELF_TO_A9:
@@ -534,18 +521,8 @@ VirtQueue_Handle VirtQueue_create(UInt16 remoteProcId, VirtQueue_Params *params,
/* A9 -> IPU/DSP */
vringAddr = (struct vring *) IPC_MEM_VRING1;
break;
-#ifndef SMP
- case ID_APPM3_TO_A9:
- /* APPM3 -> A9 */
- vringAddr = (struct vring *) IPC_MEM_VRING2;
- break;
- case ID_A9_TO_APPM3:
- /* A9 -> APPM3 */
- vringAddr = (struct vring *) IPC_MEM_VRING3;
- break;
-#endif
default:
- GateAll_delete(&vq->gateH);
+ GateHwi_delete(&vq->gateH);
Memory_free(NULL, vq, sizeof(VirtQueue_Object));
return (NULL);
}
@@ -555,7 +532,7 @@ VirtQueue_Handle VirtQueue_create(UInt16 remoteProcId, VirtQueue_Params *params,
RP_MSG_RING_SIZE);
/* See coverity related comment in vring_init() */
- // coverity[overrun-call]
+ /* coverity[overrun-call] */
vring_init(&(vq->vring), RP_MSG_NUM_BUFS, vringAddr, RP_MSG_VRING_ALIGN);
/*
@@ -563,7 +540,7 @@ VirtQueue_Handle VirtQueue_create(UInt16 remoteProcId, VirtQueue_Params *params,
* available
*/
if (vq->procId == hostProcId) {
- vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+ vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
}
queueRegistry[vq->id] = vq;
@@ -577,11 +554,6 @@ VirtQueue_Handle VirtQueue_create(UInt16 remoteProcId, VirtQueue_Params *params,
Void VirtQueue_startup()
{
hostProcId = MultiProc_getId("HOST");
-#ifndef SMP
- dsp1ProcId = MultiProc_getId("DSP1");
- sysm3ProcId = MultiProc_getId("CORE0");
- appm3ProcId = MultiProc_getId("CORE1");
-#endif
#ifdef DSP
intInfo.intVectorId = DSPEVENTID;
IpcPower_init();
#endif
+ /*
+ * Wait for HLOS (Virtio device) to indicate that priming of host's receive
+ * buffers is complete, indicating that host is ready to send.
+ *
+ * Though this is a Linux Virtio configuration status, it must be
+ * implemented by each non-Linux HLOS as well.
+ */
+ Log_print1(Diags_USER1, "VirtQueue_startup: VDEV status: 0x%x\n",
+ Resource_getVdevStatus(VIRTIO_ID_RPMSG));
+ Log_print0(Diags_USER1, "VirtQueue_startup: Polling VDEV status...\n");
+ while (Resource_getVdevStatus(VIRTIO_ID_RPMSG) != VRING_BUFS_PRIMED);
+ Log_print1(Diags_USER1, "VirtQueue_startup: VDEV status: 0x%x\n",
+ Resource_getVdevStatus(VIRTIO_ID_RPMSG));
+
InterruptProxy_intRegister(hostProcId, &intInfo, (Fxn)VirtQueue_isr, NULL);
+ Log_print0(Diags_USER1, "Passed VirtQueue_startup\n");
}
/*!