From: Takashi Iwai Date: Thu, 26 May 2011 06:09:38 +0000 (+0200) Subject: ALSA: PCM - Don't check DMA time-out too shortly X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=f2b3614cefb61ee6046a0aaee503ee37f227d310;p=linux-beck.git 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 Signed-off-by: Takashi Iwai --- 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: diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 1a07750f3836..b597408d5faa 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1481,11 +1481,20 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, break; /* all drained */ init_waitqueue_entry(&wait, current); add_wait_queue(&to_check->sleep, &wait); - set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); up_read(&snd_pcm_link_rwsem); snd_power_unlock(card); - tout = schedule_timeout(10 * HZ); + if (runtime->no_period_wakeup) + tout = MAX_SCHEDULE_TIMEOUT; + else { + tout = 10; + if (runtime->rate) { + long t = runtime->period_size * 2 / runtime->rate; + tout = max(t, tout); + } + tout = msecs_to_jiffies(tout * 1000); + } + tout = schedule_timeout_interruptible(tout); snd_power_lock(card); down_read(&snd_pcm_link_rwsem); snd_pcm_stream_lock_irq(substream);