diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-05-26 08:09:38 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-26 08:09:38 +0200 |
commit | f2b3614cefb61ee6046a0aaee503ee37f227d310 (patch) | |
tree | 4e43feacc58c629919d09bc6fd200ac0892d2cca /sound/core/pcm_lib.c | |
parent | MAINTAINERS: add FireWire audio maintainer (diff) | |
download | linux-f2b3614cefb61ee6046a0aaee503ee37f227d310.tar.xz linux-f2b3614cefb61ee6046a0aaee503ee37f227d310.zip |
ALSA: PCM - Don't check DMA time-out too shortly
When the PCM period size is set larger than 10 seconds, currently the
PCM core may abort the operation with DMA-error due to the fixed timeout
for 10 seconds. A similar problem is seen in the drain operation that
has a fixed timeout of 10 seconds, too.
This patch fixes the timeout length depending on the period size and
rate, also including the consideration of no_period_wakeup flag.
Reported-by: Raymond Yau <superquad.vortex2@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/pcm_lib.c')
-rw-r--r-- | sound/core/pcm_lib.c | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index abfeff1611ce..f1341308beda 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1756,8 +1756,18 @@ static int wait_for_avail(struct snd_pcm_substream *substream, wait_queue_t wait; int err = 0; snd_pcm_uframes_t avail = 0; - long tout; - + long wait_time, tout; + + if (runtime->no_period_wakeup) + wait_time = MAX_SCHEDULE_TIMEOUT; + else { + wait_time = 10; + if (runtime->rate) { + long t = runtime->period_size * 2 / runtime->rate; + wait_time = max(t, wait_time); + } + wait_time = msecs_to_jiffies(wait_time * 1000); + } init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->tsleep, &wait); for (;;) { @@ -1765,9 +1775,8 @@ static int wait_for_avail(struct snd_pcm_substream *substream, err = -ERESTARTSYS; break; } - set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); - tout = schedule_timeout(msecs_to_jiffies(10000)); + tout = schedule_timeout_interruptible(wait_time); snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_SUSPENDED: |