Skip to content

Commit

Permalink
snd-pcsp: use HRTIMER_CB_SOFTIRQ
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stas Sergeev authored and tiwai committed May 20, 2008
1 parent 8033c6e commit 4b7afb0
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 34 deletions.
2 changes: 1 addition & 1 deletion sound/drivers/pcsp/pcsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
37 changes: 4 additions & 33 deletions sound/drivers/pcsp/pcsp_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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)
Expand Down

0 comments on commit 4b7afb0

Please sign in to comment.