aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/it8712f_wdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/it8712f_wdt.c')
-rw-r--r--drivers/watchdog/it8712f_wdt.c63
1 files changed, 45 insertions, 18 deletions
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
index 6143f52ba6b8..8d2d8502d3e8 100644
--- a/drivers/watchdog/it8712f_wdt.c
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -28,10 +28,10 @@
28#include <linux/notifier.h> 28#include <linux/notifier.h>
29#include <linux/reboot.h> 29#include <linux/reboot.h>
30#include <linux/fs.h> 30#include <linux/fs.h>
31#include <linux/pci.h>
32#include <linux/spinlock.h> 31#include <linux/spinlock.h>
33#include <linux/uaccess.h> 32#include <linux/uaccess.h>
34#include <linux/io.h> 33#include <linux/io.h>
34#include <linux/ioport.h>
35 35
36#define NAME "it8712f_wdt" 36#define NAME "it8712f_wdt"
37 37
@@ -51,7 +51,6 @@ MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
51 51
52static unsigned long wdt_open; 52static unsigned long wdt_open;
53static unsigned expect_close; 53static unsigned expect_close;
54static spinlock_t io_lock;
55static unsigned char revision; 54static unsigned char revision;
56 55
57/* Dog Food address - We use the game port address */ 56/* Dog Food address - We use the game port address */
@@ -121,20 +120,26 @@ static inline void superio_select(int ldn)
121 outb(ldn, VAL); 120 outb(ldn, VAL);
122} 121}
123 122
124static inline void superio_enter(void) 123static inline int superio_enter(void)
125{ 124{
126 spin_lock(&io_lock); 125 /*
126 * Try to reserve REG and REG + 1 for exclusive access.
127 */
128 if (!request_muxed_region(REG, 2, NAME))
129 return -EBUSY;
130
127 outb(0x87, REG); 131 outb(0x87, REG);
128 outb(0x01, REG); 132 outb(0x01, REG);
129 outb(0x55, REG); 133 outb(0x55, REG);
130 outb(0x55, REG); 134 outb(0x55, REG);
135 return 0;
131} 136}
132 137
133static inline void superio_exit(void) 138static inline void superio_exit(void)
134{ 139{
135 outb(0x02, REG); 140 outb(0x02, REG);
136 outb(0x02, VAL); 141 outb(0x02, VAL);
137 spin_unlock(&io_lock); 142 release_region(REG, 2);
138} 143}
139 144
140static inline void it8712f_wdt_ping(void) 145static inline void it8712f_wdt_ping(void)
@@ -173,10 +178,13 @@ static int it8712f_wdt_get_status(void)
173 return 0; 178 return 0;
174} 179}
175 180
176static void it8712f_wdt_enable(void) 181static int it8712f_wdt_enable(void)
177{ 182{
183 int ret = superio_enter();
184 if (ret)
185 return ret;
186
178 printk(KERN_DEBUG NAME ": enabling watchdog timer\n"); 187 printk(KERN_DEBUG NAME ": enabling watchdog timer\n");
179 superio_enter();
180 superio_select(LDN_GPIO); 188 superio_select(LDN_GPIO);
181 189
182 superio_outb(wdt_control_reg, WDT_CONTROL); 190 superio_outb(wdt_control_reg, WDT_CONTROL);
@@ -186,13 +194,17 @@ static void it8712f_wdt_enable(void)
186 superio_exit(); 194 superio_exit();
187 195
188 it8712f_wdt_ping(); 196 it8712f_wdt_ping();
197
198 return 0;
189} 199}
190 200
191static void it8712f_wdt_disable(void) 201static int it8712f_wdt_disable(void)
192{ 202{
193 printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); 203 int ret = superio_enter();
204 if (ret)
205 return ret;
194 206
195 superio_enter(); 207 printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
196 superio_select(LDN_GPIO); 208 superio_select(LDN_GPIO);
197 209
198 superio_outb(0, WDT_CONFIG); 210 superio_outb(0, WDT_CONFIG);
@@ -202,6 +214,7 @@ static void it8712f_wdt_disable(void)
202 superio_outb(0, WDT_TIMEOUT); 214 superio_outb(0, WDT_TIMEOUT);
203 215
204 superio_exit(); 216 superio_exit();
217 return 0;
205} 218}
206 219
207static int it8712f_wdt_notify(struct notifier_block *this, 220static int it8712f_wdt_notify(struct notifier_block *this,
@@ -252,6 +265,7 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
252 WDIOF_MAGICCLOSE, 265 WDIOF_MAGICCLOSE,
253 }; 266 };
254 int value; 267 int value;
268 int ret;
255 269
256 switch (cmd) { 270 switch (cmd) {
257 case WDIOC_GETSUPPORT: 271 case WDIOC_GETSUPPORT:
@@ -259,7 +273,9 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
259 return -EFAULT; 273 return -EFAULT;
260 return 0; 274 return 0;
261 case WDIOC_GETSTATUS: 275 case WDIOC_GETSTATUS:
262 superio_enter(); 276 ret = superio_enter();
277 if (ret)
278 return ret;
263 superio_select(LDN_GPIO); 279 superio_select(LDN_GPIO);
264 280
265 value = it8712f_wdt_get_status(); 281 value = it8712f_wdt_get_status();
@@ -280,7 +296,9 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
280 if (value > (max_units * 60)) 296 if (value > (max_units * 60))
281 return -EINVAL; 297 return -EINVAL;
282 margin = value; 298 margin = value;
283 superio_enter(); 299 ret = superio_enter();
300 if (ret)
301 return ret;
284 superio_select(LDN_GPIO); 302 superio_select(LDN_GPIO);
285 303
286 it8712f_wdt_update_margin(); 304 it8712f_wdt_update_margin();
@@ -299,10 +317,14 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
299 317
300static int it8712f_wdt_open(struct inode *inode, struct file *file) 318static int it8712f_wdt_open(struct inode *inode, struct file *file)
301{ 319{
320 int ret;
302 /* only allow one at a time */ 321 /* only allow one at a time */
303 if (test_and_set_bit(0, &wdt_open)) 322 if (test_and_set_bit(0, &wdt_open))
304 return -EBUSY; 323 return -EBUSY;
305 it8712f_wdt_enable(); 324
325 ret = it8712f_wdt_enable();
326 if (ret)
327 return ret;
306 return nonseekable_open(inode, file); 328 return nonseekable_open(inode, file);
307} 329}
308 330
@@ -313,7 +335,8 @@ static int it8712f_wdt_release(struct inode *inode, struct file *file)
313 ": watchdog device closed unexpectedly, will not" 335 ": watchdog device closed unexpectedly, will not"
314 " disable the watchdog timer\n"); 336 " disable the watchdog timer\n");
315 } else if (!nowayout) { 337 } else if (!nowayout) {
316 it8712f_wdt_disable(); 338 if (it8712f_wdt_disable())
339 printk(KERN_WARNING NAME "Watchdog disable failed\n");
317 } 340 }
318 expect_close = 0; 341 expect_close = 0;
319 clear_bit(0, &wdt_open); 342 clear_bit(0, &wdt_open);
@@ -340,8 +363,10 @@ static int __init it8712f_wdt_find(unsigned short *address)
340{ 363{
341 int err = -ENODEV; 364 int err = -ENODEV;
342 int chip_type; 365 int chip_type;
366 int ret = superio_enter();
367 if (ret)
368 return ret;
343 369
344 superio_enter();
345 chip_type = superio_inw(DEVID); 370 chip_type = superio_inw(DEVID);
346 if (chip_type != IT8712F_DEVID) 371 if (chip_type != IT8712F_DEVID)
347 goto exit; 372 goto exit;
@@ -382,8 +407,6 @@ static int __init it8712f_wdt_init(void)
382{ 407{
383 int err = 0; 408 int err = 0;
384 409
385 spin_lock_init(&io_lock);
386
387 if (it8712f_wdt_find(&address)) 410 if (it8712f_wdt_find(&address))
388 return -ENODEV; 411 return -ENODEV;
389 412
@@ -392,7 +415,11 @@ static int __init it8712f_wdt_init(void)
392 return -EBUSY; 415 return -EBUSY;
393 } 416 }
394 417
395 it8712f_wdt_disable(); 418 err = it8712f_wdt_disable();
419 if (err) {
420 printk(KERN_ERR NAME ": unable to disable watchdog timer.\n");
421 goto out;
422 }
396 423
397 err = register_reboot_notifier(&it8712f_wdt_notifier); 424 err = register_reboot_notifier(&it8712f_wdt_notifier);
398 if (err) { 425 if (err) {