Commit 01c785dcb4e9fd6c4c370fd9915fc10585ed64bd
Committed by
Wim Van Sebroeck
1 parent
b47711bfbc
Exists in
master
and in
7 other branches
[WATCHDOG] wdt: fix locking
The audit of _p usage shows various drivers assume inb_p is somehow atomic. Of course it isn't and the delay can be split from the I/O cycle causing a timing violation on chips that matter (eg this one) With the proposed use of udelay() for some _p delays this will cease to be a mostly theoretical bug (as the delay stall is unsplittable) and wants fixing. Lots of other drivers need fixing this way too. Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Showing 1 changed file with 27 additions and 3 deletions Side-by-side Diff
drivers/watchdog/wdt.c
... | ... | @@ -70,6 +70,8 @@ |
70 | 70 | static int io=0x240; |
71 | 71 | static int irq=11; |
72 | 72 | |
73 | +static DEFINE_SPINLOCK(wdt_lock); | |
74 | + | |
73 | 75 | module_param(io, int, 0); |
74 | 76 | MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); |
75 | 77 | module_param(irq, int, 0); |
... | ... | @@ -109,6 +111,8 @@ |
109 | 111 | |
110 | 112 | static int wdt_start(void) |
111 | 113 | { |
114 | + unsigned long flags; | |
115 | + spin_lock_irqsave(&wdt_lock, flags); | |
112 | 116 | inb_p(WDT_DC); /* Disable watchdog */ |
113 | 117 | wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ |
114 | 118 | wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ |
... | ... | @@ -117,6 +121,7 @@ |
117 | 121 | wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ |
118 | 122 | wdt_ctr_load(2,65535); /* Length of reset pulse */ |
119 | 123 | outb_p(0, WDT_DC); /* Enable watchdog */ |
124 | + spin_unlock_irqrestore(&wdt_lock, flags); | |
120 | 125 | return 0; |
121 | 126 | } |
122 | 127 | |
123 | 128 | |
... | ... | @@ -128,9 +133,12 @@ |
128 | 133 | |
129 | 134 | static int wdt_stop (void) |
130 | 135 | { |
136 | + unsigned long flags; | |
137 | + spin_lock_irqsave(&wdt_lock, flags); | |
131 | 138 | /* Turn the card off */ |
132 | 139 | inb_p(WDT_DC); /* Disable watchdog */ |
133 | 140 | wdt_ctr_load(2,0); /* 0 length reset pulses now */ |
141 | + spin_unlock_irqrestore(&wdt_lock, flags); | |
134 | 142 | return 0; |
135 | 143 | } |
136 | 144 | |
137 | 145 | |
... | ... | @@ -143,11 +151,14 @@ |
143 | 151 | |
144 | 152 | static int wdt_ping(void) |
145 | 153 | { |
154 | + unsigned long flags; | |
155 | + spin_lock_irqsave(&wdt_lock, flags); | |
146 | 156 | /* Write a watchdog value */ |
147 | 157 | inb_p(WDT_DC); /* Disable watchdog */ |
148 | 158 | wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ |
149 | 159 | wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ |
150 | 160 | outb_p(0, WDT_DC); /* Enable watchdog */ |
161 | + spin_unlock_irqrestore(&wdt_lock, flags); | |
151 | 162 | return 0; |
152 | 163 | } |
153 | 164 | |
154 | 165 | |
... | ... | @@ -182,8 +193,13 @@ |
182 | 193 | |
183 | 194 | static int wdt_get_status(int *status) |
184 | 195 | { |
185 | - unsigned char new_status=inb_p(WDT_SR); | |
196 | + unsigned char new_status; | |
197 | + unsigned long flags; | |
186 | 198 | |
199 | + spin_lock_irqsave(&wdt_lock, flags); | |
200 | + new_status = inb_p(WDT_SR); | |
201 | + spin_unlock_irqrestore(&wdt_lock, flags); | |
202 | + | |
187 | 203 | *status=0; |
188 | 204 | if (new_status & WDC_SR_ISOI0) |
189 | 205 | *status |= WDIOF_EXTERN1; |
190 | 206 | |
... | ... | @@ -214,8 +230,12 @@ |
214 | 230 | |
215 | 231 | static int wdt_get_temperature(int *temperature) |
216 | 232 | { |
217 | - unsigned short c=inb_p(WDT_RT); | |
233 | + unsigned short c; | |
234 | + unsigned long flags; | |
218 | 235 | |
236 | + spin_lock_irqsave(&wdt_lock, flags); | |
237 | + c = inb_p(WDT_RT); | |
238 | + spin_unlock_irqrestore(&wdt_lock, flags); | |
219 | 239 | *temperature = (c * 11 / 15) + 7; |
220 | 240 | return 0; |
221 | 241 | } |
222 | 242 | |
... | ... | @@ -237,8 +257,11 @@ |
237 | 257 | * Read the status register see what is up and |
238 | 258 | * then printk it. |
239 | 259 | */ |
240 | - unsigned char status=inb_p(WDT_SR); | |
260 | + unsigned char status; | |
241 | 261 | |
262 | + spin_lock(&wdt_lock); | |
263 | + status = inb_p(WDT_SR); | |
264 | + | |
242 | 265 | printk(KERN_CRIT "WDT status %d\n", status); |
243 | 266 | |
244 | 267 | #ifdef CONFIG_WDT_501 |
... | ... | @@ -265,6 +288,7 @@ |
265 | 288 | printk(KERN_CRIT "Reset in 5ms.\n"); |
266 | 289 | #endif |
267 | 290 | } |
291 | + spin_unlock(&wdt_lock); | |
268 | 292 | return IRQ_HANDLED; |
269 | 293 | } |
270 | 294 |