Skip to content

Commit

Permalink
ALSA: PCM - Don't check DMA time-out too shortly
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Takashi Iwai committed May 26, 2011
1 parent a331b0c commit f2b3614
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
17 changes: 13 additions & 4 deletions sound/core/pcm_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1756,18 +1756,27 @@ 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 (;;) {
if (signal_pending(current)) {
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:
Expand Down
13 changes: 11 additions & 2 deletions sound/core/pcm_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit f2b3614

Please sign in to comment.