[I810_AUDIO] 1/x: Fix wait queue race in drain_dac

From: Herbert Xu
Date: Sat Nov 22 2003 - 02:13:25 EST


Hi:

This is the first of a number of patches to fix DMA bugs in the
OSS i810_audio driver.

This particular one fixes a textbook race condition in drain_dac
that causes it to timeout when it shouldn't.
--
Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ )
Email: Herbert Xu ~{PmV>HI~} <herbert@xxxxxxxxxxxxxxxxxxx>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Index: kernel-source-2.4/drivers/sound/i810_audio.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.4/drivers/sound/i810_audio.c,v
retrieving revision 1.8
diff -u -r1.8 i810_audio.c
--- kernel-source-2.4/drivers/sound/i810_audio.c 3 Sep 2003 10:27:11 -0000 1.8
+++ kernel-source-2.4/drivers/sound/i810_audio.c 21 Nov 2003 11:20:48 -0000
@@ -1231,6 +1231,17 @@
spin_lock_irqsave(&state->card->lock, flags);
i810_update_ptr(state);
count = dmabuf->count;
+
+ /* It seems that we have to set the current state to
+ * TASK_INTERRUPTIBLE every time to make the process
+ * really go to sleep. This also has to be *after* the
+ * update_ptr() call because update_ptr is likely to
+ * do a wake_up() which will unset this before we ever
+ * try to sleep, resuling in a tight loop in this code
+ * instead of actually sleeping and waiting for an
+ * interrupt to wake us up!
+ */
+ __set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&state->card->lock, flags);

if (count <= 0)
@@ -1250,16 +1261,6 @@
break;
}

- /* It seems that we have to set the current state to
- * TASK_INTERRUPTIBLE every time to make the process
- * really go to sleep. This also has to be *after* the
- * update_ptr() call because update_ptr is likely to
- * do a wake_up() which will unset this before we ever
- * try to sleep, resuling in a tight loop in this code
- * instead of actually sleeping and waiting for an
- * interrupt to wake us up!
- */
- set_current_state(TASK_INTERRUPTIBLE);
/*
* set the timeout to significantly longer than it *should*
* take for the DAC to drain the DMA buffer