diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index 54a1f90..1899cf0 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 ac6238e..c30820d 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include "pcsp.h" @@ -18,34 +17,8 @@ module_param(nforce_wa, bool, 0444); MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround " "(expect bad sound)"); -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 periods_elapsed; u64 ns; @@ -64,9 +37,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 @@ -132,7 +105,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; @@ -146,7 +119,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; } @@ -167,7 +140,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)