Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2b3614c authored by Takashi Iwai's avatar Takashi Iwai
Browse files

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: default avatarRaymond Yau <superquad.vortex2@gmail.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent a331b0c3
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -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:
+11 −2
Original line number Diff line number Diff line
@@ -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);