aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorWim Van Sebroeck <wim@iguana.be>2006-09-02 14:53:19 -0400
committerWim Van Sebroeck <wim@iguana.be>2006-10-04 16:36:42 -0400
commitaa1fd4d7c3b131026bf156da40fdf94bcbd705aa (patch)
tree10159853c6652287e3f2e80c536867b659b05595 /drivers/char
parent8386c8cfb2131b2a9caae3db6bf94292bbbe1caf (diff)
[WATCHDOG] Winbond SMsC37B787 watchdog fixes
* Added io spinlocking * Deleted WATCHDOG_MINOR (it's in the miscdevice include * Changed timer_enabled to use set_bit functions * WDIOC_GETSUPPORT should return -EFAULT or 0 * timeout should be correct before we initialize the watchdog * we should initialize the watchdog before we give access to userspace * Third parameter of module_param is not the default or initial value Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/watchdog/smsc37b787_wdt.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/char/watchdog/smsc37b787_wdt.c
index 1d01b3074db3..9f56913b484f 100644
--- a/drivers/char/watchdog/smsc37b787_wdt.c
+++ b/drivers/char/watchdog/smsc37b787_wdt.c
@@ -54,6 +54,7 @@
54#include <linux/notifier.h> 54#include <linux/notifier.h>
55#include <linux/reboot.h> 55#include <linux/reboot.h>
56#include <linux/init.h> 56#include <linux/init.h>
57#include <linux/spinlock.h>
57 58
58#include <asm/io.h> 59#include <asm/io.h>
59#include <asm/uaccess.h> 60#include <asm/uaccess.h>
@@ -72,18 +73,18 @@
72#define MODNAME "smsc37b787_wdt: " 73#define MODNAME "smsc37b787_wdt: "
73#define VERSION "1.1" 74#define VERSION "1.1"
74 75
75#define WATCHDOG_MINOR 130
76
77#define IOPORT 0x3F0 76#define IOPORT 0x3F0
78#define IOPORT_SIZE 2 77#define IOPORT_SIZE 2
79#define IODEV_NO 8 78#define IODEV_NO 8
80 79
81static int unit = UNIT_SECOND; /* timer's unit */ 80static int unit = UNIT_SECOND; /* timer's unit */
82static int timeout = 60; /* timeout value: default is 60 "units" */ 81static int timeout = 60; /* timeout value: default is 60 "units" */
83static int timer_enabled = 0; /* is the timer enabled? */ 82static unsigned long timer_enabled = 0; /* is the timer enabled? */
84 83
85static char expect_close; /* is the close expected? */ 84static char expect_close; /* is the close expected? */
86 85
86static spinlock_t io_lock; /* to guard the watchdog from io races */
87
87static int nowayout = WATCHDOG_NOWAYOUT; 88static int nowayout = WATCHDOG_NOWAYOUT;
88 89
89/* -- Low level function ----------------------------------------*/ 90/* -- Low level function ----------------------------------------*/
@@ -210,6 +211,7 @@ static void wb_smsc_wdt_initialize(void)
210{ 211{
211 unsigned char old; 212 unsigned char old;
212 213
214 spin_lock(&io_lock);
213 open_io_config(); 215 open_io_config();
214 select_io_device(IODEV_NO); 216 select_io_device(IODEV_NO);
215 217
@@ -234,12 +236,14 @@ static void wb_smsc_wdt_initialize(void)
234 wdt_timer_units(old); 236 wdt_timer_units(old);
235 237
236 close_io_config(); 238 close_io_config();
239 spin_unlock(&io_lock);
237} 240}
238 241
239/* shutdown the watchdog */ 242/* shutdown the watchdog */
240 243
241static void wb_smsc_wdt_shutdown(void) 244static void wb_smsc_wdt_shutdown(void)
242{ 245{
246 spin_lock(&io_lock);
243 open_io_config(); 247 open_io_config();
244 select_io_device(IODEV_NO); 248 select_io_device(IODEV_NO);
245 249
@@ -257,12 +261,14 @@ static void wb_smsc_wdt_shutdown(void)
257 wdt_timeout_value(0x00); 261 wdt_timeout_value(0x00);
258 262
259 close_io_config(); 263 close_io_config();
264 spin_unlock(&io_lock);
260} 265}
261 266
262/* set timeout => enable watchdog */ 267/* set timeout => enable watchdog */
263 268
264static void wb_smsc_wdt_set_timeout(unsigned char new_timeout) 269static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
265{ 270{
271 spin_lock(&io_lock);
266 open_io_config(); 272 open_io_config();
267 select_io_device(IODEV_NO); 273 select_io_device(IODEV_NO);
268 274
@@ -273,6 +279,7 @@ static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
273 wdt_timeout_value(new_timeout); 279 wdt_timeout_value(new_timeout);
274 280
275 close_io_config(); 281 close_io_config();
282 spin_unlock(&io_lock);
276} 283}
277 284
278/* get timeout */ 285/* get timeout */
@@ -281,10 +288,12 @@ static unsigned char wb_smsc_wdt_get_timeout(void)
281{ 288{
282 unsigned char set_timeout; 289 unsigned char set_timeout;
283 290
291 spin_lock(&io_lock);
284 open_io_config(); 292 open_io_config();
285 select_io_device(IODEV_NO); 293 select_io_device(IODEV_NO);
286 set_timeout = read_io_cr(0xF2); 294 set_timeout = read_io_cr(0xF2);
287 close_io_config(); 295 close_io_config();
296 spin_unlock(&io_lock);
288 297
289 return set_timeout; 298 return set_timeout;
290} 299}
@@ -309,6 +318,7 @@ static void wb_smsc_wdt_enable(void)
309 318
310static void wb_smsc_wdt_reset_timer(void) 319static void wb_smsc_wdt_reset_timer(void)
311{ 320{
321 spin_lock(&io_lock);
312 open_io_config(); 322 open_io_config();
313 select_io_device(IODEV_NO); 323 select_io_device(IODEV_NO);
314 324
@@ -317,6 +327,7 @@ static void wb_smsc_wdt_reset_timer(void)
317 wdt_timer_conf(0x08); 327 wdt_timer_conf(0x08);
318 328
319 close_io_config(); 329 close_io_config();
330 spin_unlock(&io_lock);
320} 331}
321 332
322/* return, if the watchdog is enabled (timeout is set...) */ 333/* return, if the watchdog is enabled (timeout is set...) */
@@ -335,14 +346,13 @@ static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
335{ 346{
336 /* /dev/watchdog can only be opened once */ 347 /* /dev/watchdog can only be opened once */
337 348
338 if (timer_enabled) 349 if (test_and_set_bit(0, &timer_enabled))
339 return -EBUSY; 350 return -EBUSY;
340 351
341 if (nowayout) 352 if (nowayout)
342 __module_get(THIS_MODULE); 353 __module_get(THIS_MODULE);
343 354
344 /* Reload and activate timer */ 355 /* Reload and activate timer */
345 timer_enabled = 1;
346 wb_smsc_wdt_enable(); 356 wb_smsc_wdt_enable();
347 357
348 printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); 358 printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
@@ -364,7 +374,7 @@ static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
364 wb_smsc_wdt_reset_timer(); 374 wb_smsc_wdt_reset_timer();
365 } 375 }
366 376
367 timer_enabled = 0; 377 clear_bit(0, &timer_enabled);
368 expect_close = 0; 378 expect_close = 0;
369 return 0; 379 return 0;
370} 380}
@@ -425,7 +435,8 @@ static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file,
425 return -ENOTTY; 435 return -ENOTTY;
426 436
427 case WDIOC_GETSUPPORT: 437 case WDIOC_GETSUPPORT:
428 return copy_to_user(uarg.ident, &ident, sizeof(ident)); 438 return copy_to_user(uarg.ident, &ident,
439 sizeof(ident)) ? -EFAULT : 0;
429 440
430 case WDIOC_GETSTATUS: 441 case WDIOC_GETSTATUS:
431 return put_user(wb_smsc_wdt_status(), uarg.i); 442 return put_user(wb_smsc_wdt_status(), uarg.i);
@@ -506,12 +517,12 @@ static struct file_operations wb_smsc_wdt_fops =
506 .write = wb_smsc_wdt_write, 517 .write = wb_smsc_wdt_write,
507 .ioctl = wb_smsc_wdt_ioctl, 518 .ioctl = wb_smsc_wdt_ioctl,
508 .open = wb_smsc_wdt_open, 519 .open = wb_smsc_wdt_open,
509 .release = wb_smsc_wdt_release 520 .release = wb_smsc_wdt_release,
510}; 521};
511 522
512static struct notifier_block wb_smsc_wdt_notifier = 523static struct notifier_block wb_smsc_wdt_notifier =
513{ 524{
514 .notifier_call = wb_smsc_wdt_notify_sys 525 .notifier_call = wb_smsc_wdt_notify_sys,
515}; 526};
516 527
517static struct miscdevice wb_smsc_wdt_miscdev = 528static struct miscdevice wb_smsc_wdt_miscdev =
@@ -529,6 +540,8 @@ static int __init wb_smsc_wdt_init(void)
529{ 540{
530 int ret; 541 int ret;
531 542
543 spin_lock_init(&io_lock);
544
532 printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n"); 545 printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n");
533 546
534 if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) { 547 if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
@@ -537,6 +550,13 @@ static int __init wb_smsc_wdt_init(void)
537 goto out_pnp; 550 goto out_pnp;
538 } 551 }
539 552
553 // set new maximum, if it's too big
554 if (timeout > MAX_TIMEOUT)
555 timeout = MAX_TIMEOUT;
556
557 // init the watchdog timer
558 wb_smsc_wdt_initialize();
559
540 ret = register_reboot_notifier(&wb_smsc_wdt_notifier); 560 ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
541 if (ret) { 561 if (ret) {
542 printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret); 562 printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret);
@@ -549,13 +569,6 @@ static int __init wb_smsc_wdt_init(void)
549 goto out_rbt; 569 goto out_rbt;
550 } 570 }
551 571
552 // init the watchdog timer
553 wb_smsc_wdt_initialize();
554
555 // set new maximum, if it's too big
556 if (timeout > MAX_TIMEOUT)
557 timeout = MAX_TIMEOUT;
558
559 // output info 572 // output info
560 printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); 573 printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
561 printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout); 574 printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout);
@@ -607,7 +620,7 @@ module_param(unit, int, 0);
607MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0"); 620MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0");
608#endif 621#endif
609 622
610module_param(timeout, int, 60); 623module_param(timeout, int, 0);
611MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60"); 624MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
612 625
613module_param(nowayout, int, 0); 626module_param(nowayout, int, 0);