Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+23 -5
+12 -3
sound/core/pcm_lib.c
··· 1756 1756 wait_queue_t wait; 1757 1757 int err = 0; 1758 1758 snd_pcm_uframes_t avail = 0; 1759 - long tout; 1759 + long wait_time, tout; 1760 1760 1761 + if (runtime->no_period_wakeup) 1762 + wait_time = MAX_SCHEDULE_TIMEOUT; 1763 + else { 1764 + wait_time = 10; 1765 + if (runtime->rate) { 1766 + long t = runtime->period_size * 2 / runtime->rate; 1767 + wait_time = max(t, wait_time); 1768 + } 1769 + wait_time = msecs_to_jiffies(wait_time * 1000); 1770 + } 1761 1771 init_waitqueue_entry(&wait, current); 1762 1772 add_wait_queue(&runtime->tsleep, &wait); 1763 1773 for (;;) { ··· 1775 1765 err = -ERESTARTSYS; 1776 1766 break; 1777 1767 } 1778 - set_current_state(TASK_INTERRUPTIBLE); 1779 1768 snd_pcm_stream_unlock_irq(substream); 1780 - tout = schedule_timeout(msecs_to_jiffies(10000)); 1769 + tout = schedule_timeout_interruptible(wait_time); 1781 1770 snd_pcm_stream_lock_irq(substream); 1782 1771 switch (runtime->status->state) { 1783 1772 case SNDRV_PCM_STATE_SUSPENDED:
+11 -2
sound/core/pcm_native.c
··· 1481 1481 break; /* all drained */ 1482 1482 init_waitqueue_entry(&wait, current); 1483 1483 add_wait_queue(&to_check->sleep, &wait); 1484 - set_current_state(TASK_INTERRUPTIBLE); 1485 1484 snd_pcm_stream_unlock_irq(substream); 1486 1485 up_read(&snd_pcm_link_rwsem); 1487 1486 snd_power_unlock(card); 1488 - tout = schedule_timeout(10 * HZ); 1487 + if (runtime->no_period_wakeup) 1488 + tout = MAX_SCHEDULE_TIMEOUT; 1489 + else { 1490 + tout = 10; 1491 + if (runtime->rate) { 1492 + long t = runtime->period_size * 2 / runtime->rate; 1493 + tout = max(t, tout); 1494 + } 1495 + tout = msecs_to_jiffies(tout * 1000); 1496 + } 1497 + tout = schedule_timeout_interruptible(tout); 1489 1498 snd_power_lock(card); 1490 1499 down_read(&snd_pcm_link_rwsem); 1491 1500 snd_pcm_stream_lock_irq(substream);