aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/wdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/wdt.c')
-rw-r--r--drivers/watchdog/wdt.c176
1 files changed, 94 insertions, 82 deletions
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 756fb15fdce7..53a6b18bcb9a 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -24,9 +24,10 @@
24 * Matt Crocker). 24 * Matt Crocker).
25 * Alan Cox : Added wdt= boot option 25 * Alan Cox : Added wdt= boot option
26 * Alan Cox : Cleaned up copy/user stuff 26 * Alan Cox : Cleaned up copy/user stuff
27 * Tim Hockin : Added insmod parameters, comment cleanup 27 * Tim Hockin : Added insmod parameters, comment
28 * Parameterized timeout 28 * cleanup, parameterized timeout
29 * Tigran Aivazian : Restructured wdt_init() to handle failures 29 * Tigran Aivazian : Restructured wdt_init() to handle
30 * failures
30 * Joel Becker : Added WDIOC_GET/SETTIMEOUT 31 * Joel Becker : Added WDIOC_GET/SETTIMEOUT
31 * Matt Domsch : Added nowayout module option 32 * Matt Domsch : Added nowayout module option
32 */ 33 */
@@ -42,9 +43,9 @@
42#include <linux/notifier.h> 43#include <linux/notifier.h>
43#include <linux/reboot.h> 44#include <linux/reboot.h>
44#include <linux/init.h> 45#include <linux/init.h>
46#include <linux/io.h>
47#include <linux/uaccess.h>
45 48
46#include <asm/io.h>
47#include <asm/uaccess.h>
48#include <asm/system.h> 49#include <asm/system.h>
49#include "wd501p.h" 50#include "wd501p.h"
50 51
@@ -60,15 +61,19 @@ static char expect_close;
60static int heartbeat = WD_TIMO; 61static int heartbeat = WD_TIMO;
61static int wd_heartbeat; 62static int wd_heartbeat;
62module_param(heartbeat, int, 0); 63module_param(heartbeat, int, 0);
63MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")"); 64MODULE_PARM_DESC(heartbeat,
65 "Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default="
66 __MODULE_STRING(WD_TIMO) ")");
64 67
65static int nowayout = WATCHDOG_NOWAYOUT; 68static int nowayout = WATCHDOG_NOWAYOUT;
66module_param(nowayout, int, 0); 69module_param(nowayout, int, 0);
67MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 70MODULE_PARM_DESC(nowayout,
71 "Watchdog cannot be stopped once started (default="
72 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
68 73
69/* You must set these - there is no sane way to probe for this board. */ 74/* You must set these - there is no sane way to probe for this board. */
70static int io=0x240; 75static int io = 0x240;
71static int irq=11; 76static int irq = 11;
72 77
73static DEFINE_SPINLOCK(wdt_lock); 78static DEFINE_SPINLOCK(wdt_lock);
74 79
@@ -82,7 +87,8 @@ MODULE_PARM_DESC(irq, "WDT irq (default=11)");
82static int tachometer; 87static int tachometer;
83 88
84module_param(tachometer, int, 0); 89module_param(tachometer, int, 0);
85MODULE_PARM_DESC(tachometer, "WDT501-P Fan Tachometer support (0=disable, default=0)"); 90MODULE_PARM_DESC(tachometer,
91 "WDT501-P Fan Tachometer support (0=disable, default=0)");
86#endif /* CONFIG_WDT_501 */ 92#endif /* CONFIG_WDT_501 */
87 93
88/* 94/*
@@ -91,9 +97,9 @@ MODULE_PARM_DESC(tachometer, "WDT501-P Fan Tachometer support (0=disable, defaul
91 97
92static void wdt_ctr_mode(int ctr, int mode) 98static void wdt_ctr_mode(int ctr, int mode)
93{ 99{
94 ctr<<=6; 100 ctr <<= 6;
95 ctr|=0x30; 101 ctr |= 0x30;
96 ctr|=(mode<<1); 102 ctr |= (mode << 1);
97 outb_p(ctr, WDT_CR); 103 outb_p(ctr, WDT_CR);
98} 104}
99 105
@@ -114,12 +120,15 @@ static int wdt_start(void)
114 unsigned long flags; 120 unsigned long flags;
115 spin_lock_irqsave(&wdt_lock, flags); 121 spin_lock_irqsave(&wdt_lock, flags);
116 inb_p(WDT_DC); /* Disable watchdog */ 122 inb_p(WDT_DC); /* Disable watchdog */
117 wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ 123 wdt_ctr_mode(0, 3); /* Program CTR0 for Mode 3:
118 wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ 124 Square Wave Generator */
119 wdt_ctr_mode(2,0); /* Program CTR2 for Mode 0: Pulse on Terminal Count */ 125 wdt_ctr_mode(1, 2); /* Program CTR1 for Mode 2:
126 Rate Generator */
127 wdt_ctr_mode(2, 0); /* Program CTR2 for Mode 0:
128 Pulse on Terminal Count */
120 wdt_ctr_load(0, 8948); /* Count at 100Hz */ 129 wdt_ctr_load(0, 8948); /* Count at 100Hz */
121 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ 130 wdt_ctr_load(1, wd_heartbeat); /* Heartbeat */
122 wdt_ctr_load(2,65535); /* Length of reset pulse */ 131 wdt_ctr_load(2, 65535); /* Length of reset pulse */
123 outb_p(0, WDT_DC); /* Enable watchdog */ 132 outb_p(0, WDT_DC); /* Enable watchdog */
124 spin_unlock_irqrestore(&wdt_lock, flags); 133 spin_unlock_irqrestore(&wdt_lock, flags);
125 return 0; 134 return 0;
@@ -131,13 +140,13 @@ static int wdt_start(void)
131 * Stop the watchdog driver. 140 * Stop the watchdog driver.
132 */ 141 */
133 142
134static int wdt_stop (void) 143static int wdt_stop(void)
135{ 144{
136 unsigned long flags; 145 unsigned long flags;
137 spin_lock_irqsave(&wdt_lock, flags); 146 spin_lock_irqsave(&wdt_lock, flags);
138 /* Turn the card off */ 147 /* Turn the card off */
139 inb_p(WDT_DC); /* Disable watchdog */ 148 inb_p(WDT_DC); /* Disable watchdog */
140 wdt_ctr_load(2,0); /* 0 length reset pulses now */ 149 wdt_ctr_load(2, 0); /* 0 length reset pulses now */
141 spin_unlock_irqrestore(&wdt_lock, flags); 150 spin_unlock_irqrestore(&wdt_lock, flags);
142 return 0; 151 return 0;
143} 152}
@@ -145,8 +154,8 @@ static int wdt_stop (void)
145/** 154/**
146 * wdt_ping: 155 * wdt_ping:
147 * 156 *
148 * Reload counter one with the watchdog heartbeat. We don't bother reloading 157 * Reload counter one with the watchdog heartbeat. We don't bother
149 * the cascade counter. 158 * reloading the cascade counter.
150 */ 159 */
151 160
152static int wdt_ping(void) 161static int wdt_ping(void)
@@ -155,8 +164,9 @@ static int wdt_ping(void)
155 spin_lock_irqsave(&wdt_lock, flags); 164 spin_lock_irqsave(&wdt_lock, flags);
156 /* Write a watchdog value */ 165 /* Write a watchdog value */
157 inb_p(WDT_DC); /* Disable watchdog */ 166 inb_p(WDT_DC); /* Disable watchdog */
158 wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ 167 wdt_ctr_mode(1, 2); /* Re-Program CTR1 for Mode 2:
159 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ 168 Rate Generator */
169 wdt_ctr_load(1, wd_heartbeat); /* Heartbeat */
160 outb_p(0, WDT_DC); /* Enable watchdog */ 170 outb_p(0, WDT_DC); /* Enable watchdog */
161 spin_unlock_irqrestore(&wdt_lock, flags); 171 spin_unlock_irqrestore(&wdt_lock, flags);
162 return 0; 172 return 0;
@@ -166,13 +176,14 @@ static int wdt_ping(void)
166 * wdt_set_heartbeat: 176 * wdt_set_heartbeat:
167 * @t: the new heartbeat value that needs to be set. 177 * @t: the new heartbeat value that needs to be set.
168 * 178 *
169 * Set a new heartbeat value for the watchdog device. If the heartbeat value is 179 * Set a new heartbeat value for the watchdog device. If the heartbeat
170 * incorrect we keep the old value and return -EINVAL. If successfull we 180 * value is incorrect we keep the old value and return -EINVAL. If
171 * return 0. 181 * successful we return 0.
172 */ 182 */
183
173static int wdt_set_heartbeat(int t) 184static int wdt_set_heartbeat(int t)
174{ 185{
175 if ((t < 1) || (t > 65535)) 186 if (t < 1 || t > 65535)
176 return -EINVAL; 187 return -EINVAL;
177 188
178 heartbeat = t; 189 heartbeat = t;
@@ -200,7 +211,7 @@ static int wdt_get_status(int *status)
200 new_status = inb_p(WDT_SR); 211 new_status = inb_p(WDT_SR);
201 spin_unlock_irqrestore(&wdt_lock, flags); 212 spin_unlock_irqrestore(&wdt_lock, flags);
202 213
203 *status=0; 214 *status = 0;
204 if (new_status & WDC_SR_ISOI0) 215 if (new_status & WDC_SR_ISOI0)
205 *status |= WDIOF_EXTERN1; 216 *status |= WDIOF_EXTERN1;
206 if (new_status & WDC_SR_ISII1) 217 if (new_status & WDC_SR_ISII1)
@@ -266,7 +277,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
266 277
267#ifdef CONFIG_WDT_501 278#ifdef CONFIG_WDT_501
268 if (!(status & WDC_SR_TGOOD)) 279 if (!(status & WDC_SR_TGOOD))
269 printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); 280 printk(KERN_CRIT "Overheat alarm.(%d)\n", inb_p(WDT_RT));
270 if (!(status & WDC_SR_PSUOVER)) 281 if (!(status & WDC_SR_PSUOVER))
271 printk(KERN_CRIT "PSU over voltage.\n"); 282 printk(KERN_CRIT "PSU over voltage.\n");
272 if (!(status & WDC_SR_PSUUNDR)) 283 if (!(status & WDC_SR_PSUUNDR))
@@ -304,9 +315,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
304 * write of data will do, as we we don't define content meaning. 315 * write of data will do, as we we don't define content meaning.
305 */ 316 */
306 317
307static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 318static ssize_t wdt_write(struct file *file, const char __user *buf,
319 size_t count, loff_t *ppos)
308{ 320{
309 if(count) { 321 if (count) {
310 if (!nowayout) { 322 if (!nowayout) {
311 size_t i; 323 size_t i;
312 324
@@ -328,7 +340,6 @@ static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count
328 340
329/** 341/**
330 * wdt_ioctl: 342 * wdt_ioctl:
331 * @inode: inode of the device
332 * @file: file handle to the device 343 * @file: file handle to the device
333 * @cmd: watchdog command 344 * @cmd: watchdog command
334 * @arg: argument pointer 345 * @arg: argument pointer
@@ -338,8 +349,7 @@ static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count
338 * querying capabilities and current status. 349 * querying capabilities and current status.
339 */ 350 */
340 351
341static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 352static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
342 unsigned long arg)
343{ 353{
344 void __user *argp = (void __user *)arg; 354 void __user *argp = (void __user *)arg;
345 int __user *p = argp; 355 int __user *p = argp;
@@ -362,32 +372,28 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
362 ident.options |= WDIOF_FANFAULT; 372 ident.options |= WDIOF_FANFAULT;
363#endif /* CONFIG_WDT_501 */ 373#endif /* CONFIG_WDT_501 */
364 374
365 switch(cmd) 375 switch (cmd) {
366 { 376 default:
367 default: 377 return -ENOTTY;
368 return -ENOTTY; 378 case WDIOC_GETSUPPORT:
369 case WDIOC_GETSUPPORT: 379 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
370 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; 380 case WDIOC_GETSTATUS:
371 381 wdt_get_status(&status);
372 case WDIOC_GETSTATUS: 382 return put_user(status, p);
373 wdt_get_status(&status); 383 case WDIOC_GETBOOTSTATUS:
374 return put_user(status, p); 384 return put_user(0, p);
375 case WDIOC_GETBOOTSTATUS: 385 case WDIOC_KEEPALIVE:
376 return put_user(0, p); 386 wdt_ping();
377 case WDIOC_KEEPALIVE: 387 return 0;
378 wdt_ping(); 388 case WDIOC_SETTIMEOUT:
379 return 0; 389 if (get_user(new_heartbeat, p))
380 case WDIOC_SETTIMEOUT: 390 return -EFAULT;
381 if (get_user(new_heartbeat, p)) 391 if (wdt_set_heartbeat(new_heartbeat))
382 return -EFAULT; 392 return -EINVAL;
383 393 wdt_ping();
384 if (wdt_set_heartbeat(new_heartbeat)) 394 /* Fall */
385 return -EINVAL; 395 case WDIOC_GETTIMEOUT:
386 396 return put_user(heartbeat, p);
387 wdt_ping();
388 /* Fall */
389 case WDIOC_GETTIMEOUT:
390 return put_user(heartbeat, p);
391 } 397 }
392} 398}
393 399
@@ -405,7 +411,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
405 411
406static int wdt_open(struct inode *inode, struct file *file) 412static int wdt_open(struct inode *inode, struct file *file)
407{ 413{
408 if(test_and_set_bit(0, &wdt_is_open)) 414 if (test_and_set_bit(0, &wdt_is_open))
409 return -EBUSY; 415 return -EBUSY;
410 /* 416 /*
411 * Activate 417 * Activate
@@ -432,7 +438,8 @@ static int wdt_release(struct inode *inode, struct file *file)
432 wdt_stop(); 438 wdt_stop();
433 clear_bit(0, &wdt_is_open); 439 clear_bit(0, &wdt_is_open);
434 } else { 440 } else {
435 printk(KERN_CRIT "wdt: WDT device closed unexpectedly. WDT will not stop!\n"); 441 printk(KERN_CRIT
442 "wdt: WDT device closed unexpectedly. WDT will not stop!\n");
436 wdt_ping(); 443 wdt_ping();
437 } 444 }
438 expect_close = 0; 445 expect_close = 0;
@@ -451,14 +458,15 @@ static int wdt_release(struct inode *inode, struct file *file)
451 * farenheit. It was designed by an imperial measurement luddite. 458 * farenheit. It was designed by an imperial measurement luddite.
452 */ 459 */
453 460
454static ssize_t wdt_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) 461static ssize_t wdt_temp_read(struct file *file, char __user *buf,
462 size_t count, loff_t *ptr)
455{ 463{
456 int temperature; 464 int temperature;
457 465
458 if (wdt_get_temperature(&temperature)) 466 if (wdt_get_temperature(&temperature))
459 return -EFAULT; 467 return -EFAULT;
460 468
461 if (copy_to_user (buf, &temperature, 1)) 469 if (copy_to_user(buf, &temperature, 1))
462 return -EFAULT; 470 return -EFAULT;
463 471
464 return 1; 472 return 1;
@@ -506,10 +514,8 @@ static int wdt_temp_release(struct inode *inode, struct file *file)
506static int wdt_notify_sys(struct notifier_block *this, unsigned long code, 514static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
507 void *unused) 515 void *unused)
508{ 516{
509 if(code==SYS_DOWN || code==SYS_HALT) { 517 if (code == SYS_DOWN || code == SYS_HALT)
510 /* Turn the card off */
511 wdt_stop(); 518 wdt_stop();
512 }
513 return NOTIFY_DONE; 519 return NOTIFY_DONE;
514} 520}
515 521
@@ -522,7 +528,7 @@ static const struct file_operations wdt_fops = {
522 .owner = THIS_MODULE, 528 .owner = THIS_MODULE,
523 .llseek = no_llseek, 529 .llseek = no_llseek,
524 .write = wdt_write, 530 .write = wdt_write,
525 .ioctl = wdt_ioctl, 531 .unlocked_ioctl = wdt_ioctl,
526 .open = wdt_open, 532 .open = wdt_open,
527 .release = wdt_release, 533 .release = wdt_release,
528}; 534};
@@ -576,7 +582,7 @@ static void __exit wdt_exit(void)
576#endif /* CONFIG_WDT_501 */ 582#endif /* CONFIG_WDT_501 */
577 unregister_reboot_notifier(&wdt_notifier); 583 unregister_reboot_notifier(&wdt_notifier);
578 free_irq(irq, NULL); 584 free_irq(irq, NULL);
579 release_region(io,8); 585 release_region(io, 8);
580} 586}
581 587
582/** 588/**
@@ -591,44 +597,49 @@ static int __init wdt_init(void)
591{ 597{
592 int ret; 598 int ret;
593 599
594 /* Check that the heartbeat value is within it's range ; if not reset to the default */ 600 /* Check that the heartbeat value is within it's range;
601 if not reset to the default */
595 if (wdt_set_heartbeat(heartbeat)) { 602 if (wdt_set_heartbeat(heartbeat)) {
596 wdt_set_heartbeat(WD_TIMO); 603 wdt_set_heartbeat(WD_TIMO);
597 printk(KERN_INFO "wdt: heartbeat value must be 0<heartbeat<65536, using %d\n", 604 printk(KERN_INFO "wdt: heartbeat value must be 0 < heartbeat < 65536, using %d\n",
598 WD_TIMO); 605 WD_TIMO);
599 } 606 }
600 607
601 if (!request_region(io, 8, "wdt501p")) { 608 if (!request_region(io, 8, "wdt501p")) {
602 printk(KERN_ERR "wdt: I/O address 0x%04x already in use\n", io); 609 printk(KERN_ERR
610 "wdt: I/O address 0x%04x already in use\n", io);
603 ret = -EBUSY; 611 ret = -EBUSY;
604 goto out; 612 goto out;
605 } 613 }
606 614
607 ret = request_irq(irq, wdt_interrupt, IRQF_DISABLED, "wdt501p", NULL); 615 ret = request_irq(irq, wdt_interrupt, IRQF_DISABLED, "wdt501p", NULL);
608 if(ret) { 616 if (ret) {
609 printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); 617 printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq);
610 goto outreg; 618 goto outreg;
611 } 619 }
612 620
613 ret = register_reboot_notifier(&wdt_notifier); 621 ret = register_reboot_notifier(&wdt_notifier);
614 if(ret) { 622 if (ret) {
615 printk(KERN_ERR "wdt: cannot register reboot notifier (err=%d)\n", ret); 623 printk(KERN_ERR
624 "wdt: cannot register reboot notifier (err=%d)\n", ret);
616 goto outirq; 625 goto outirq;
617 } 626 }
618 627
619#ifdef CONFIG_WDT_501 628#ifdef CONFIG_WDT_501
620 ret = misc_register(&temp_miscdev); 629 ret = misc_register(&temp_miscdev);
621 if (ret) { 630 if (ret) {
622 printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n", 631 printk(KERN_ERR
623 TEMP_MINOR, ret); 632 "wdt: cannot register miscdev on minor=%d (err=%d)\n",
633 TEMP_MINOR, ret);
624 goto outrbt; 634 goto outrbt;
625 } 635 }
626#endif /* CONFIG_WDT_501 */ 636#endif /* CONFIG_WDT_501 */
627 637
628 ret = misc_register(&wdt_miscdev); 638 ret = misc_register(&wdt_miscdev);
629 if (ret) { 639 if (ret) {
630 printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n", 640 printk(KERN_ERR
631 WATCHDOG_MINOR, ret); 641 "wdt: cannot register miscdev on minor=%d (err=%d)\n",
642 WATCHDOG_MINOR, ret);
632 goto outmisc; 643 goto outmisc;
633 } 644 }
634 645
@@ -636,7 +647,8 @@ static int __init wdt_init(void)
636 printk(KERN_INFO "WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n", 647 printk(KERN_INFO "WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
637 io, irq, heartbeat, nowayout); 648 io, irq, heartbeat, nowayout);
638#ifdef CONFIG_WDT_501 649#ifdef CONFIG_WDT_501
639 printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled")); 650 printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
651 (tachometer ? "Enabled" : "Disabled"));
640#endif /* CONFIG_WDT_501 */ 652#endif /* CONFIG_WDT_501 */
641 653
642out: 654out:
@@ -651,7 +663,7 @@ outrbt:
651outirq: 663outirq:
652 free_irq(irq, NULL); 664 free_irq(irq, NULL);
653outreg: 665outreg:
654 release_region(io,8); 666 release_region(io, 8);
655 goto out; 667 goto out;
656} 668}
657 669