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

Commit 8dca4197 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: ctxfi - Fix deadlock with xfi-timer



The PCM x-fi native update routine can cause deadlocks when the
trigger(START) is called while the stream is running.

This patch fixes the deadlock by just postponing the pcm period update
to the next possible wake-up.  Also it adds the flip of ti->running
flag (just to be sure as now).

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 635c265f
Loading
Loading
Loading
Loading
+10 −8
Original line number Diff line number Diff line
@@ -180,7 +180,7 @@ static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
 *
 * call this inside the lock and irq disabled
 */
static int ct_xfitimer_reprogram(struct ct_timer *atimer)
static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
{
	struct ct_timer_instance *ti;
	unsigned int min_intr = (unsigned int)-1;
@@ -216,6 +216,8 @@ static int ct_xfitimer_reprogram(struct ct_timer *atimer)
			ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
						 rate - 1, rate);
		}
		if (ti->need_update && !can_update)
			min_intr = 0; /* pending to the next irq */
		if (ti->frag_count < min_intr)
			min_intr = ti->frag_count;
	}
@@ -235,7 +237,7 @@ static void ct_xfitimer_check_period(struct ct_timer *atimer)

	spin_lock_irqsave(&atimer->list_lock, flags);
	list_for_each_entry(ti, &atimer->instance_head, instance_list) {
		if (ti->need_update) {
		if (ti->running && ti->need_update) {
			ti->need_update = 0;
			ti->apcm->interrupt(ti->apcm);
		}
@@ -252,7 +254,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer)
	spin_lock_irqsave(&atimer->lock, flags);
	atimer->irq_handling = 1;
	do {
		update = ct_xfitimer_reprogram(atimer);
		update = ct_xfitimer_reprogram(atimer, 1);
		spin_unlock(&atimer->lock);
		if (update)
			ct_xfitimer_check_period(atimer);
@@ -265,6 +267,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer)
static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
{
	ti->frag_count = ti->substream->runtime->period_size;
	ti->running = 0;
	ti->need_update = 0;
}

@@ -273,7 +276,6 @@ static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
static void ct_xfitimer_update(struct ct_timer *atimer)
{
	unsigned long flags;
	int update;

	spin_lock_irqsave(&atimer->lock, flags);
	if (atimer->irq_handling) {
@@ -284,10 +286,8 @@ static void ct_xfitimer_update(struct ct_timer *atimer)
	}

	ct_xfitimer_irq_stop(atimer);
	update = ct_xfitimer_reprogram(atimer);
	ct_xfitimer_reprogram(atimer, 0);
	spin_unlock_irqrestore(&atimer->lock, flags);
	if (update)
		ct_xfitimer_check_period(atimer);
}

static void ct_xfitimer_start(struct ct_timer_instance *ti)
@@ -298,6 +298,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti)
	spin_lock_irqsave(&atimer->lock, flags);
	if (list_empty(&ti->running_list))
		atimer->wc = ct_xfitimer_get_wc(atimer);
	ti->running = 1;
	ti->need_update = 0;
	list_add(&ti->running_list, &atimer->running_head);
	spin_unlock_irqrestore(&atimer->lock, flags);
	ct_xfitimer_update(atimer);
@@ -310,7 +312,7 @@ static void ct_xfitimer_stop(struct ct_timer_instance *ti)

	spin_lock_irqsave(&atimer->lock, flags);
	list_del_init(&ti->running_list);
	ti->need_update = 0;
	ti->running = 0;
	spin_unlock_irqrestore(&atimer->lock, flags);
	ct_xfitimer_update(atimer);
}