diff options
Diffstat (limited to 'drivers/watchdog/it8712f_wdt.c')
-rw-r--r-- | drivers/watchdog/it8712f_wdt.c | 63 |
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 | ||
52 | static unsigned long wdt_open; | 52 | static unsigned long wdt_open; |
53 | static unsigned expect_close; | 53 | static unsigned expect_close; |
54 | static spinlock_t io_lock; | ||
55 | static unsigned char revision; | 54 | static 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 | ||
124 | static inline void superio_enter(void) | 123 | static 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 | ||
133 | static inline void superio_exit(void) | 138 | static 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 | ||
140 | static inline void it8712f_wdt_ping(void) | 145 | static 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 | ||
176 | static void it8712f_wdt_enable(void) | 181 | static 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 | ||
191 | static void it8712f_wdt_disable(void) | 201 | static 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 | ||
207 | static int it8712f_wdt_notify(struct notifier_block *this, | 220 | static 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 | ||
300 | static int it8712f_wdt_open(struct inode *inode, struct file *file) | 318 | static 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) { |