VAYU QNX: Prevent race condition when ARM is slow to handle mailbox interrupts
authorvwan@ti.com <vwan@ti.com>
Thu, 6 Feb 2014 22:09:43 +0000 (14:09 -0800)
committerChris Ring <cring@ti.com>
Thu, 6 Feb 2014 22:29:50 +0000 (14:29 -0800)
This patch fixes a race condition where the host side in QNX is slow to clear a
mailbox interrupt. If the slave were to try to send another interrupt before
the ARM has cleared the first one, the code in InterruptDsp_intSend()
will simply drop it. This is bad because on QNX, the code in VirtQueue_ISR
interprets the received arg as the VirtQueue id. Hence if consecutive
messages were sent with different ids, the second message would be missed.

The fix is to poll whenever the mailbox is occupied, and send the message
only when the mailbox is free. (SDOCM00106278)

Signed-off-by: VW <vwan@ti.com>
packages/ti/sdo/ipc/family/vayu/InterruptDsp.c

index ec24a7e9cda3ff1f88d128456e41441fceac790c..406558e14da94b16fb9c64c652f50c9554f32424 100644 (file)
@@ -302,25 +302,17 @@ Void InterruptDsp_intSend(UInt16 remoteProcId, IInterrupt_IntInfo *intInfo,
 
     /*
      *  Before writing to a mailbox, check whether it already contains a
-     *  message.  If so, don't write to the mailbox since we want one and only
-     *  one message per interrupt.  Disable interrupts between reading
+     *  message. If so, wait for the message to be read since we want one
+     *  and only one message per interrupt. Disable interrupts between reading
      *  the MSGSTATUS_X register and writing to the mailbox to protect from
-     *  another thread doing an intSend at the same time
-     *
-     *  Note regarding possible race condition between local 'intSend' and
-     *  remote 'intClear':
-     *  It is possible that we we read the MAILBOX_MSGSTATUS_X register during
-     *  the remote side's intClear.  Therefore, we might choose _not_ to send
-     *  write to the mailbox even though the mailbox is about to be cleared a
-     *  few cycles later. In this case, the interrupt will be lost.
-     *  This is OK, however. intClear should always be called by the Notify
-     *  driver _before_ shared memory is read, so the event will be picked up
-     *  anyway by the previous interrupt that caused intClear to be called.
+     *  another thread doing an intSend at the same time.
      */
     key = Hwi_disable();
-    if (REG32(MAILBOX_STATUS(index)) == 0) {
-        REG32(MAILBOX_MESSAGE(index)) = arg;
+    while (REG32(MAILBOX_STATUS(index)) != 0) {
+        Hwi_restore(key);
+        key = Hwi_disable();
     }
+    REG32(MAILBOX_MESSAGE(index)) = arg;
     Hwi_restore(key);
 }