aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2008-01-10 00:36:01 -0500
committerWim Van Sebroeck <wim@iguana.be>2008-01-25 15:23:28 -0500
commit01c785dcb4e9fd6c4c370fd9915fc10585ed64bd (patch)
tree18afb2d73c5f2fe21cae6908c110440320b3fcff
parentb47711bfbcd4eb77ca61ef0162487b20e023ae55 (diff)
[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>
-rw-r--r--drivers/watchdog/wdt.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 53d0bb410df8..756fb15fdce7 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -70,6 +70,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _
70static int io=0x240; 70static int io=0x240;
71static int irq=11; 71static int irq=11;
72 72
73static DEFINE_SPINLOCK(wdt_lock);
74
73module_param(io, int, 0); 75module_param(io, int, 0);
74MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); 76MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
75module_param(irq, int, 0); 77module_param(irq, int, 0);
@@ -109,6 +111,8 @@ static void wdt_ctr_load(int ctr, int val)
109 111
110static int wdt_start(void) 112static int wdt_start(void)
111{ 113{
114 unsigned long flags;
115 spin_lock_irqsave(&wdt_lock, flags);
112 inb_p(WDT_DC); /* Disable watchdog */ 116 inb_p(WDT_DC); /* Disable watchdog */
113 wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ 117 wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */
114 wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ 118 wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */
@@ -117,6 +121,7 @@ static int wdt_start(void)
117 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ 121 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
118 wdt_ctr_load(2,65535); /* Length of reset pulse */ 122 wdt_ctr_load(2,65535); /* Length of reset pulse */
119 outb_p(0, WDT_DC); /* Enable watchdog */ 123 outb_p(0, WDT_DC); /* Enable watchdog */
124 spin_unlock_irqrestore(&wdt_lock, flags);
120 return 0; 125 return 0;
121} 126}
122 127
@@ -128,9 +133,12 @@ static int wdt_start(void)
128 133
129static int wdt_stop (void) 134static int wdt_stop (void)
130{ 135{
136 unsigned long flags;
137 spin_lock_irqsave(&wdt_lock, flags);
131 /* Turn the card off */ 138 /* Turn the card off */
132 inb_p(WDT_DC); /* Disable watchdog */ 139 inb_p(WDT_DC); /* Disable watchdog */
133 wdt_ctr_load(2,0); /* 0 length reset pulses now */ 140 wdt_ctr_load(2,0); /* 0 length reset pulses now */
141 spin_unlock_irqrestore(&wdt_lock, flags);
134 return 0; 142 return 0;
135} 143}
136 144
@@ -143,11 +151,14 @@ static int wdt_stop (void)
143 151
144static int wdt_ping(void) 152static int wdt_ping(void)
145{ 153{
154 unsigned long flags;
155 spin_lock_irqsave(&wdt_lock, flags);
146 /* Write a watchdog value */ 156 /* Write a watchdog value */
147 inb_p(WDT_DC); /* Disable watchdog */ 157 inb_p(WDT_DC); /* Disable watchdog */
148 wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ 158 wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */
149 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ 159 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
150 outb_p(0, WDT_DC); /* Enable watchdog */ 160 outb_p(0, WDT_DC); /* Enable watchdog */
161 spin_unlock_irqrestore(&wdt_lock, flags);
151 return 0; 162 return 0;
152} 163}
153 164
@@ -182,7 +193,12 @@ static int wdt_set_heartbeat(int t)
182 193
183static int wdt_get_status(int *status) 194static 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;
198
199 spin_lock_irqsave(&wdt_lock, flags);
200 new_status = inb_p(WDT_SR);
201 spin_unlock_irqrestore(&wdt_lock, flags);
186 202
187 *status=0; 203 *status=0;
188 if (new_status & WDC_SR_ISOI0) 204 if (new_status & WDC_SR_ISOI0)
@@ -214,8 +230,12 @@ static int wdt_get_status(int *status)
214 230
215static int wdt_get_temperature(int *temperature) 231static 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 *temperature = (c * 11 / 15) + 7; 239 *temperature = (c * 11 / 15) + 7;
220 return 0; 240 return 0;
221} 241}
@@ -237,7 +257,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
237 * Read the status register see what is up and 257 * Read the status register see what is up and
238 * then printk it. 258 * then printk it.
239 */ 259 */
240 unsigned char status=inb_p(WDT_SR); 260 unsigned char status;
261
262 spin_lock(&wdt_lock);
263 status = inb_p(WDT_SR);
241 264
242 printk(KERN_CRIT "WDT status %d\n", status); 265 printk(KERN_CRIT "WDT status %d\n", status);
243 266
@@ -265,6 +288,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
265 printk(KERN_CRIT "Reset in 5ms.\n"); 288 printk(KERN_CRIT "Reset in 5ms.\n");
266#endif 289#endif
267 } 290 }
291 spin_unlock(&wdt_lock);
268 return IRQ_HANDLED; 292 return IRQ_HANDLED;
269} 293}
270 294