diff options
| author | Stas Sergeev <stsp@aknet.ru> | 2008-05-20 11:47:29 +0200 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2008-05-20 11:56:24 +0200 | 
| commit | 4b7afb0d0d23b298a7e6d30eaba0679449542d2e (patch) | |
| tree | beeff813fbb8d6dcffd13aefde4f43ccf9dc6f8e /sound/drivers/pcsp | |
| parent | 8033c6e9736c29cce5f0d0abbca9a44dffb20c39 (diff) | |
| download | linux-4b7afb0d0d23b298a7e6d30eaba0679449542d2e.tar.bz2 | |
snd-pcsp: use HRTIMER_CB_SOFTIRQ
Change HRTIMER_CB_IRQSAFE to HRTIMER_CB_SOFTIRQ,
as suggested by Thomas Gleixner.
That solves the lock dependancy reported in
Bug #10701.
That also allows to call hrtimer_start()
directly, tasklet "stupid hack" removed.
Signed-off-by: Stas Sergeev <stsp@aknet.ru>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/drivers/pcsp')
| -rw-r--r-- | sound/drivers/pcsp/pcsp.c | 2 | ||||
| -rw-r--r-- | sound/drivers/pcsp/pcsp_lib.c | 37 | 
2 files changed, 5 insertions, 34 deletions
| diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index 54a1f9036c66..1899cf0685bc 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -96,7 +96,7 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)  		return -EINVAL;  	hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -	pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE; +	pcsp_chip.timer.cb_mode = HRTIMER_CB_SOFTIRQ;  	pcsp_chip.timer.function = pcsp_do_timer;  	card = snd_card_new(index, id, THIS_MODULE, 0); diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index 7ad4a1534b2b..e341f3f83b6a 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -9,7 +9,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <sound/pcm.h> -#include <linux/interrupt.h>  #include <asm/io.h>  #include "pcsp.h" @@ -20,34 +19,8 @@ MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround "  #define DMIX_WANTS_S16	1 -static void pcsp_start_timer(unsigned long dummy) -{ -	hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL); -} - -/* - * We need the hrtimer_start as a tasklet to avoid - * the nasty locking problem. :( - * The problem: - * - The timer handler is called with the cpu_base->lock - *   already held by hrtimer code. - * - snd_pcm_period_elapsed() takes the - *   substream->self_group.lock. - * So far so good. - * But the snd_pcsp_trigger() is called with the - * substream->self_group.lock held, and it calls - * hrtimer_start(), which takes the cpu_base->lock. - * You see the problem. We have the code pathes - * which take two locks in a reverse order. This - * can deadlock and the lock validator complains. - * The only solution I could find was to move the - * hrtimer_start() into a tasklet. -stsp - */ -static DECLARE_TASKLET(pcsp_start_timer_tasklet, pcsp_start_timer, 0); -  enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)  { -	unsigned long flags;  	unsigned char timer_cnt, val;  	int fmt_size, periods_elapsed;  	u64 ns; @@ -66,9 +39,7 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)  		return HRTIMER_RESTART;  	} -	/* hrtimer calls us from both hardirq and softirq contexts, -	 * so irqsave :( */ -	spin_lock_irqsave(&chip->substream_lock, flags); +	spin_lock_irq(&chip->substream_lock);  	/* Takashi Iwai says regarding this extra lock:  	If the irq handler handles some data on the DMA buffer, it should @@ -139,7 +110,7 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)  		chip->period_ptr %= buffer_bytes;  	} -	spin_unlock_irqrestore(&chip->substream_lock, flags); +	spin_unlock_irq(&chip->substream_lock);  	if (!atomic_read(&chip->timer_active))  		return HRTIMER_NORESTART; @@ -153,7 +124,7 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)  exit_nr_unlock2:  	snd_pcm_stream_unlock(substream);  exit_nr_unlock1: -	spin_unlock_irqrestore(&chip->substream_lock, flags); +	spin_unlock_irq(&chip->substream_lock);  	return HRTIMER_NORESTART;  } @@ -174,7 +145,7 @@ static void pcsp_start_playing(struct snd_pcsp *chip)  	atomic_set(&chip->timer_active, 1);  	chip->thalf = 0; -	tasklet_schedule(&pcsp_start_timer_tasklet); +	hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL);  }  static void pcsp_stop_playing(struct snd_pcsp *chip) |