Messages received multiple times in QNX when IPU2 + DSP1/IPU1 are active 3.23 ipc-3.23-next 3.23.02.04
authorvwan@ti.com <vwan@ti.com>
Sat, 6 Dec 2014 00:25:14 +0000 (16:25 -0800)
committerRobert Tivy <rtivy@ti.com>
Tue, 9 Dec 2014 18:20:25 +0000 (10:20 -0800)
This commit fixes a race condition in QNX where IPU2 is exchanging messages
with host while DSP1 or IPU1 is doing the same. It adds protection in
VirtQueue_addAvailBuf and VirtQueue_getUsedBuf to prevent
a VirtQueue from being accessed concurrently by multiple interrupt handlers,
which has the potential of corrupting the buffer indexing and thus
resulting in some messages to be returned multiple times.

This addresses SDOCM00114194.

Signed-off-by: VW <vwan@ti.com>
qnx/src/ipc3x_dev/ti/syslink/ipc/hlos/knl/transports/virtio/VirtQueue.c

index 94f210d0205b7289e275073cdb24289383c88871..1461179f17de28266bbeb12a1c81c388c2377265 100644 (file)
@@ -69,6 +69,7 @@
 #include "virtio_ring.h"
 #include "_rpmsg.h"
 #include <ipu_pm.h>
+#include <pthread.h>
 
 /* Used for defining the size of the virtqueue registry */
 #define NUM_QUEUES                      2
@@ -103,6 +104,9 @@ typedef struct VirtQueue_Object {
 
     /* Private arg from user */
     void *                  arg;
+
+    /* Mutex to protect vrings from multi-thread access */
+    pthread_mutex_t         mutex;
 } VirtQueue_Object;
 
 static UInt numQueues = 0;
@@ -197,6 +201,8 @@ Int VirtQueue_addAvailBuf(VirtQueue_Handle vq, Void *buf, UInt32 len, Int16 head
 {
     UInt16 avail;
 
+    pthread_mutex_lock(&vq->mutex);
+
     if (vq->num_free == 0) {
         /* There's no more space */
         GT_setFailureReason (curTrace,
@@ -225,6 +231,8 @@ Int VirtQueue_addAvailBuf(VirtQueue_Handle vq, Void *buf, UInt32 len, Int16 head
         vq->vring.avail->idx++;
     }
 
+    pthread_mutex_unlock(&vq->mutex);
+
     return (vq->num_free);
 }
 
@@ -235,11 +243,15 @@ Int16 VirtQueue_getUsedBuf(VirtQueue_Object *vq, Void **buf)
 {
     UInt16 head;
 
+    pthread_mutex_lock(&vq->mutex);
+
     /* There's nothing available? */
     if (vq->last_used_idx == vq->vring.used->idx) {
         /* We need to know about added buffers */
         vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
 
+        pthread_mutex_unlock(&vq->mutex);
+
         return (-1);
     }
 
@@ -253,6 +265,8 @@ Int16 VirtQueue_getUsedBuf(VirtQueue_Object *vq, Void **buf)
     vq->last_used_idx++;
     vq->num_free++;
 
+    pthread_mutex_unlock(&vq->mutex);
+
     *buf = mapPAtoVA(vq, vq->vring.desc[head].addr);
 
     return (head);
@@ -393,6 +407,9 @@ VirtQueue_Handle VirtQueue_create (VirtQueue_callback callback, UInt16 procId,
         vq = NULL;
     }
 
+    /* Initialize mutex */
+    pthread_mutex_init(&vq->mutex, NULL);
+
     return (vq);
 }