Commit 4b7afb0d0d23b298a7e6d30eaba0679449542d2e

Authored by Stas Sergeev
Committed by Takashi Iwai
1 parent 8033c6e973

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>

Showing 2 changed files with 5 additions and 34 deletions Side-by-side Diff

sound/drivers/pcsp/pcsp.c
... ... @@ -96,7 +96,7 @@
96 96 return -EINVAL;
97 97  
98 98 hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
99   - pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE;
  99 + pcsp_chip.timer.cb_mode = HRTIMER_CB_SOFTIRQ;
100 100 pcsp_chip.timer.function = pcsp_do_timer;
101 101  
102 102 card = snd_card_new(index, id, THIS_MODULE, 0);
sound/drivers/pcsp/pcsp_lib.c
... ... @@ -9,7 +9,6 @@
9 9 #include <linux/module.h>
10 10 #include <linux/moduleparam.h>
11 11 #include <sound/pcm.h>
12   -#include <linux/interrupt.h>
13 12 #include <asm/io.h>
14 13 #include "pcsp.h"
15 14  
16 15  
... ... @@ -20,34 +19,8 @@
20 19  
21 20 #define DMIX_WANTS_S16 1
22 21  
23   -static void pcsp_start_timer(unsigned long dummy)
24   -{
25   - hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL);
26   -}
27   -
28   -/*
29   - * We need the hrtimer_start as a tasklet to avoid
30   - * the nasty locking problem. :(
31   - * The problem:
32   - * - The timer handler is called with the cpu_base->lock
33   - * already held by hrtimer code.
34   - * - snd_pcm_period_elapsed() takes the
35   - * substream->self_group.lock.
36   - * So far so good.
37   - * But the snd_pcsp_trigger() is called with the
38   - * substream->self_group.lock held, and it calls
39   - * hrtimer_start(), which takes the cpu_base->lock.
40   - * You see the problem. We have the code pathes
41   - * which take two locks in a reverse order. This
42   - * can deadlock and the lock validator complains.
43   - * The only solution I could find was to move the
44   - * hrtimer_start() into a tasklet. -stsp
45   - */
46   -static DECLARE_TASKLET(pcsp_start_timer_tasklet, pcsp_start_timer, 0);
47   -
48 22 enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
49 23 {
50   - unsigned long flags;
51 24 unsigned char timer_cnt, val;
52 25 int fmt_size, periods_elapsed;
53 26 u64 ns;
... ... @@ -66,9 +39,7 @@
66 39 return HRTIMER_RESTART;
67 40 }
68 41  
69   - /* hrtimer calls us from both hardirq and softirq contexts,
70   - * so irqsave :( */
71   - spin_lock_irqsave(&chip->substream_lock, flags);
  42 + spin_lock_irq(&chip->substream_lock);
72 43 /* Takashi Iwai says regarding this extra lock:
73 44  
74 45 If the irq handler handles some data on the DMA buffer, it should
... ... @@ -139,7 +110,7 @@
139 110 chip->period_ptr %= buffer_bytes;
140 111 }
141 112  
142   - spin_unlock_irqrestore(&chip->substream_lock, flags);
  113 + spin_unlock_irq(&chip->substream_lock);
143 114  
144 115 if (!atomic_read(&chip->timer_active))
145 116 return HRTIMER_NORESTART;
... ... @@ -153,7 +124,7 @@
153 124 exit_nr_unlock2:
154 125 snd_pcm_stream_unlock(substream);
155 126 exit_nr_unlock1:
156   - spin_unlock_irqrestore(&chip->substream_lock, flags);
  127 + spin_unlock_irq(&chip->substream_lock);
157 128 return HRTIMER_NORESTART;
158 129 }
159 130  
... ... @@ -174,7 +145,7 @@
174 145 atomic_set(&chip->timer_active, 1);
175 146 chip->thalf = 0;
176 147  
177   - tasklet_schedule(&pcsp_start_timer_tasklet);
  148 + hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL);
178 149 }
179 150  
180 151 static void pcsp_stop_playing(struct snd_pcsp *chip)