Commit fffcb480e4224f25c965b93fa65541bfc7dd732e

Authored by Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog

* master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
  [WATCHDOG] Documentation/watchdog update
  [WATCHDOG] convert AT91RM9200 watchdog to platform driver
  [WATCHDOG] add WDIOC_GETTIMELEFT ioctl
  [WATCHDOG] Pre-Timeout flags

Showing 10 changed files Side-by-side Diff

Documentation/watchdog/pcwd-watchdog.txt
... ... @@ -22,78 +22,9 @@
22 22 to run the program with an "&" to run it in the background!)
23 23  
24 24 If you want to write a program to be compatible with the PC Watchdog
25   - driver, simply do the following:
  25 + driver, simply use of modify the watchdog test program:
  26 + Documentation/watchdog/src/watchdog-test.c
26 27  
27   --- Snippet of code --
28   -/*
29   - * Watchdog Driver Test Program
30   - */
31   -
32   -#include <stdio.h>
33   -#include <stdlib.h>
34   -#include <string.h>
35   -#include <unistd.h>
36   -#include <fcntl.h>
37   -#include <sys/ioctl.h>
38   -#include <linux/types.h>
39   -#include <linux/watchdog.h>
40   -
41   -int fd;
42   -
43   -/*
44   - * This function simply sends an IOCTL to the driver, which in turn ticks
45   - * the PC Watchdog card to reset its internal timer so it doesn't trigger
46   - * a computer reset.
47   - */
48   -void keep_alive(void)
49   -{
50   - int dummy;
51   -
52   - ioctl(fd, WDIOC_KEEPALIVE, &dummy);
53   -}
54   -
55   -/*
56   - * The main program. Run the program with "-d" to disable the card,
57   - * or "-e" to enable the card.
58   - */
59   -int main(int argc, char *argv[])
60   -{
61   - fd = open("/dev/watchdog", O_WRONLY);
62   -
63   - if (fd == -1) {
64   - fprintf(stderr, "Watchdog device not enabled.\n");
65   - fflush(stderr);
66   - exit(-1);
67   - }
68   -
69   - if (argc > 1) {
70   - if (!strncasecmp(argv[1], "-d", 2)) {
71   - ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
72   - fprintf(stderr, "Watchdog card disabled.\n");
73   - fflush(stderr);
74   - exit(0);
75   - } else if (!strncasecmp(argv[1], "-e", 2)) {
76   - ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
77   - fprintf(stderr, "Watchdog card enabled.\n");
78   - fflush(stderr);
79   - exit(0);
80   - } else {
81   - fprintf(stderr, "-d to disable, -e to enable.\n");
82   - fprintf(stderr, "run by itself to tick the card.\n");
83   - fflush(stderr);
84   - exit(0);
85   - }
86   - } else {
87   - fprintf(stderr, "Watchdog Ticking Away!\n");
88   - fflush(stderr);
89   - }
90   -
91   - while(1) {
92   - keep_alive();
93   - sleep(1);
94   - }
95   -}
96   --- End snippet --
97 28  
98 29 Other IOCTL functions include:
99 30  
Documentation/watchdog/src/watchdog-simple.c
  1 +#include <stdlib.h>
  2 +#include <fcntl.h>
  3 +
  4 +int main(int argc, const char *argv[]) {
  5 + int fd = open("/dev/watchdog", O_WRONLY);
  6 + if (fd == -1) {
  7 + perror("watchdog");
  8 + exit(1);
  9 + }
  10 + while (1) {
  11 + write(fd, "\0", 1);
  12 + fsync(fd);
  13 + sleep(10);
  14 + }
  15 +}
Documentation/watchdog/src/watchdog-test.c
  1 +/*
  2 + * Watchdog Driver Test Program
  3 + */
  4 +
  5 +#include <stdio.h>
  6 +#include <stdlib.h>
  7 +#include <string.h>
  8 +#include <unistd.h>
  9 +#include <fcntl.h>
  10 +#include <sys/ioctl.h>
  11 +#include <linux/types.h>
  12 +#include <linux/watchdog.h>
  13 +
  14 +int fd;
  15 +
  16 +/*
  17 + * This function simply sends an IOCTL to the driver, which in turn ticks
  18 + * the PC Watchdog card to reset its internal timer so it doesn't trigger
  19 + * a computer reset.
  20 + */
  21 +void keep_alive(void)
  22 +{
  23 + int dummy;
  24 +
  25 + ioctl(fd, WDIOC_KEEPALIVE, &dummy);
  26 +}
  27 +
  28 +/*
  29 + * The main program. Run the program with "-d" to disable the card,
  30 + * or "-e" to enable the card.
  31 + */
  32 +int main(int argc, char *argv[])
  33 +{
  34 + fd = open("/dev/watchdog", O_WRONLY);
  35 +
  36 + if (fd == -1) {
  37 + fprintf(stderr, "Watchdog device not enabled.\n");
  38 + fflush(stderr);
  39 + exit(-1);
  40 + }
  41 +
  42 + if (argc > 1) {
  43 + if (!strncasecmp(argv[1], "-d", 2)) {
  44 + ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
  45 + fprintf(stderr, "Watchdog card disabled.\n");
  46 + fflush(stderr);
  47 + exit(0);
  48 + } else if (!strncasecmp(argv[1], "-e", 2)) {
  49 + ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
  50 + fprintf(stderr, "Watchdog card enabled.\n");
  51 + fflush(stderr);
  52 + exit(0);
  53 + } else {
  54 + fprintf(stderr, "-d to disable, -e to enable.\n");
  55 + fprintf(stderr, "run by itself to tick the card.\n");
  56 + fflush(stderr);
  57 + exit(0);
  58 + }
  59 + } else {
  60 + fprintf(stderr, "Watchdog Ticking Away!\n");
  61 + fflush(stderr);
  62 + }
  63 +
  64 + while(1) {
  65 + keep_alive();
  66 + sleep(1);
  67 + }
  68 +}
Documentation/watchdog/watchdog-api.txt
... ... @@ -34,23 +34,8 @@
34 34 the watchdog is pinged within a certain time, this time is called the
35 35 timeout or margin. The simplest way to ping the watchdog is to write
36 36 some data to the device. So a very simple watchdog daemon would look
37   -like this:
  37 +like this source file: see Documentation/watchdog/src/watchdog-simple.c
38 38  
39   -#include <stdlib.h>
40   -#include <fcntl.h>
41   -
42   -int main(int argc, const char *argv[]) {
43   - int fd=open("/dev/watchdog",O_WRONLY);
44   - if (fd==-1) {
45   - perror("watchdog");
46   - exit(1);
47   - }
48   - while(1) {
49   - write(fd, "\0", 1);
50   - sleep(10);
51   - }
52   -}
53   -
54 39 A more advanced driver could for example check that a HTTP server is
55 40 still responding before doing the write call to ping the watchdog.
56 41  
57 42  
... ... @@ -110,8 +95,41 @@
110 95 ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
111 96 printf("The timeout was is %d seconds\n", timeout);
112 97  
113   -Envinronmental monitoring:
  98 +Pretimeouts:
114 99  
  100 +Some watchdog timers can be set to have a trigger go off before the
  101 +actual time they will reset the system. This can be done with an NMI,
  102 +interrupt, or other mechanism. This allows Linux to record useful
  103 +information (like panic information and kernel coredumps) before it
  104 +resets.
  105 +
  106 + pretimeout = 10;
  107 + ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout);
  108 +
  109 +Note that the pretimeout is the number of seconds before the time
  110 +when the timeout will go off. It is not the number of seconds until
  111 +the pretimeout. So, for instance, if you set the timeout to 60 seconds
  112 +and the pretimeout to 10 seconds, the pretimout will go of in 50
  113 +seconds. Setting a pretimeout to zero disables it.
  114 +
  115 +There is also a get function for getting the pretimeout:
  116 +
  117 + ioctl(fd, WDIOC_GETPRETIMEOUT, &timeout);
  118 + printf("The pretimeout was is %d seconds\n", timeout);
  119 +
  120 +Not all watchdog drivers will support a pretimeout.
  121 +
  122 +Get the number of seconds before reboot:
  123 +
  124 +Some watchdog drivers have the ability to report the remaining time
  125 +before the system will reboot. The WDIOC_GETTIMELEFT is the ioctl
  126 +that returns the number of seconds before reboot.
  127 +
  128 + ioctl(fd, WDIOC_GETTIMELEFT, &timeleft);
  129 + printf("The timeout was is %d seconds\n", timeleft);
  130 +
  131 +Environmental monitoring:
  132 +
115 133 All watchdog drivers are required return more information about the system,
116 134 some do temperature, fan and power level monitoring, some can tell you
117 135 the reason for the last reboot of the system. The GETSUPPORT ioctl is
... ... @@ -168,6 +186,10 @@
168 186 The watchdog saw a keepalive ping since it was last queried.
169 187  
170 188 WDIOF_SETTIMEOUT Can set/get the timeout
  189 +
  190 +The watchdog can do pretimeouts.
  191 +
  192 + WDIOF_PRETIMEOUT Pretimeout (in seconds), get/set
171 193  
172 194  
173 195 For those drivers that return any bits set in the option field, the
Documentation/watchdog/watchdog.txt
... ... @@ -65,28 +65,7 @@
65 65 Minor numbers are however allocated for it.
66 66  
67 67  
68   -Example Watchdog Driver
69   ------------------------
70   -
71   -#include <stdio.h>
72   -#include <unistd.h>
73   -#include <fcntl.h>
74   -
75   -int main(int argc, const char *argv[])
76   -{
77   - int fd=open("/dev/watchdog",O_WRONLY);
78   - if(fd==-1)
79   - {
80   - perror("watchdog");
81   - exit(1);
82   - }
83   - while(1)
84   - {
85   - write(fd,"\0",1);
86   - fsync(fd);
87   - sleep(10);
88   - }
89   -}
  68 +Example Watchdog Driver: see Documentation/watchdog/src/watchdog-simple.c
90 69  
91 70  
92 71 Contact Information
drivers/char/watchdog/at91_wdt.c
... ... @@ -17,14 +17,15 @@
17 17 #include <linux/miscdevice.h>
18 18 #include <linux/module.h>
19 19 #include <linux/moduleparam.h>
  20 +#include <linux/platform_device.h>
20 21 #include <linux/types.h>
21 22 #include <linux/watchdog.h>
22 23 #include <asm/bitops.h>
23 24 #include <asm/uaccess.h>
24 25  
25 26  
26   -#define WDT_DEFAULT_TIME 5 /* 5 seconds */
27   -#define WDT_MAX_TIME 256 /* 256 seconds */
  27 +#define WDT_DEFAULT_TIME 5 /* seconds */
  28 +#define WDT_MAX_TIME 256 /* seconds */
28 29  
29 30 static int wdt_time = WDT_DEFAULT_TIME;
30 31 static int nowayout = WATCHDOG_NOWAYOUT;
31 32  
... ... @@ -32,8 +33,10 @@
32 33 module_param(wdt_time, int, 0);
33 34 MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
34 35  
  36 +#ifdef CONFIG_WATCHDOG_NOWAYOUT
35 37 module_param(nowayout, int, 0);
36 38 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  39 +#endif
37 40  
38 41  
39 42 static unsigned long at91wdt_busy;
... ... @@ -138,7 +141,7 @@
138 141 case WDIOC_SETTIMEOUT:
139 142 if (get_user(new_value, p))
140 143 return -EFAULT;
141   -
  144 +
142 145 if (at91_wdt_settimeout(new_value))
143 146 return -EINVAL;
144 147  
145 148  
146 149  
147 150  
148 151  
... ... @@ -196,27 +199,84 @@
196 199 .fops = &at91wdt_fops,
197 200 };
198 201  
199   -static int __init at91_wdt_init(void)
  202 +static int __init at91wdt_probe(struct platform_device *pdev)
200 203 {
201 204 int res;
202 205  
203   - /* Check that the heartbeat value is within range; if not reset to the default */
204   - if (at91_wdt_settimeout(wdt_time)) {
205   - at91_wdt_settimeout(WDT_DEFAULT_TIME);
206   - printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
207   - }
  206 + if (at91wdt_miscdev.dev)
  207 + return -EBUSY;
  208 + at91wdt_miscdev.dev = &pdev->dev;
208 209  
209 210 res = misc_register(&at91wdt_miscdev);
210 211 if (res)
211 212 return res;
212 213  
213   - printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout);
  214 + printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : "");
214 215 return 0;
215 216 }
216 217  
  218 +static int __exit at91wdt_remove(struct platform_device *pdev)
  219 +{
  220 + int res;
  221 +
  222 + res = misc_deregister(&at91wdt_miscdev);
  223 + if (!res)
  224 + at91wdt_miscdev.dev = NULL;
  225 +
  226 + return res;
  227 +}
  228 +
  229 +static void at91wdt_shutdown(struct platform_device *pdev)
  230 +{
  231 + at91_wdt_stop();
  232 +}
  233 +
  234 +#ifdef CONFIG_PM
  235 +
  236 +static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
  237 +{
  238 + at91_wdt_stop();
  239 + return 0;
  240 +}
  241 +
  242 +static int at91wdt_resume(struct platform_device *pdev)
  243 +{
  244 + if (at91wdt_busy)
  245 + at91_wdt_start();
  246 + return 0;
  247 +}
  248 +
  249 +#else
  250 +#define at91wdt_suspend NULL
  251 +#define at91wdt_resume NULL
  252 +#endif
  253 +
  254 +static struct platform_driver at91wdt_driver = {
  255 + .probe = at91wdt_probe,
  256 + .remove = __exit_p(at91wdt_remove),
  257 + .shutdown = at91wdt_shutdown,
  258 + .suspend = at91wdt_suspend,
  259 + .resume = at91wdt_resume,
  260 + .driver = {
  261 + .name = "at91_wdt",
  262 + .owner = THIS_MODULE,
  263 + },
  264 +};
  265 +
  266 +static int __init at91_wdt_init(void)
  267 +{
  268 + /* Check that the heartbeat value is within range; if not reset to the default */
  269 + if (at91_wdt_settimeout(wdt_time)) {
  270 + at91_wdt_settimeout(WDT_DEFAULT_TIME);
  271 + pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
  272 + }
  273 +
  274 + return platform_driver_register(&at91wdt_driver);
  275 +}
  276 +
217 277 static void __exit at91_wdt_exit(void)
218 278 {
219   - misc_deregister(&at91wdt_miscdev);
  279 + platform_driver_unregister(&at91wdt_driver);
220 280 }
221 281  
222 282 module_init(at91_wdt_init);
drivers/char/watchdog/i8xx_tco.c
... ... @@ -205,6 +205,23 @@
205 205 return 0;
206 206 }
207 207  
  208 +static int tco_timer_get_timeleft (int *time_left)
  209 +{
  210 + unsigned char val;
  211 +
  212 + spin_lock(&tco_lock);
  213 +
  214 + /* read the TCO Timer */
  215 + val = inb (TCO1_RLD);
  216 + val &= 0x3f;
  217 +
  218 + spin_unlock(&tco_lock);
  219 +
  220 + *time_left = (int)((val * 6) / 10);
  221 +
  222 + return 0;
  223 +}
  224 +
208 225 /*
209 226 * /dev/watchdog handling
210 227 */
... ... @@ -272,6 +289,7 @@
272 289 {
273 290 int new_options, retval = -EINVAL;
274 291 int new_heartbeat;
  292 + int time_left;
275 293 void __user *argp = (void __user *)arg;
276 294 int __user *p = argp;
277 295 static struct watchdog_info ident = {
... ... @@ -320,7 +338,7 @@
320 338 return -EFAULT;
321 339  
322 340 if (tco_timer_set_heartbeat(new_heartbeat))
323   - return -EINVAL;
  341 + return -EINVAL;
324 342  
325 343 tco_timer_keepalive ();
326 344 /* Fall */
... ... @@ -328,6 +346,14 @@
328 346  
329 347 case WDIOC_GETTIMEOUT:
330 348 return put_user(heartbeat, p);
  349 +
  350 + case WDIOC_GETTIMELEFT:
  351 + {
  352 + if (tco_timer_get_timeleft(&time_left))
  353 + return -EINVAL;
  354 +
  355 + return put_user(time_left, p);
  356 + }
331 357  
332 358 default:
333 359 return -ENOIOCTLCMD;
drivers/char/watchdog/pcwd_pci.c
... ... @@ -21,7 +21,7 @@
21 21 */
22 22  
23 23 /*
24   - * A bells and whistles driver is available from:
  24 + * A bells and whistles driver is available from:
25 25 * http://www.kernel.org/pub/linux/kernel/people/wim/pcwd/pcwd_pci/
26 26 *
27 27 * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
... ... @@ -390,6 +390,24 @@
390 390 return 0;
391 391 }
392 392  
  393 +static int pcipcwd_get_timeleft(int *time_left)
  394 +{
  395 + int msb;
  396 + int lsb;
  397 +
  398 + /* Read the time that's left before rebooting */
  399 + /* Note: if the board is not yet armed then we will read 0xFFFF */
  400 + send_command(CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
  401 +
  402 + *time_left = (msb << 8) + lsb;
  403 +
  404 + if (debug >= VERBOSE)
  405 + printk(KERN_DEBUG PFX "Time left before next reboot: %d\n",
  406 + *time_left);
  407 +
  408 + return 0;
  409 +}
  410 +
393 411 /*
394 412 * /dev/watchdog handling
395 413 */
... ... @@ -511,6 +529,16 @@
511 529  
512 530 case WDIOC_GETTIMEOUT:
513 531 return put_user(heartbeat, p);
  532 +
  533 + case WDIOC_GETTIMELEFT:
  534 + {
  535 + int time_left;
  536 +
  537 + if (pcipcwd_get_timeleft(&time_left))
  538 + return -EFAULT;
  539 +
  540 + return put_user(time_left, p);
  541 + }
514 542  
515 543 default:
516 544 return -ENOIOCTLCMD;
drivers/char/watchdog/pcwd_usb.c
... ... @@ -317,6 +317,19 @@
317 317 return 0;
318 318 }
319 319  
  320 +static int usb_pcwd_get_timeleft(struct usb_pcwd_private *usb_pcwd, int *time_left)
  321 +{
  322 + unsigned char msb, lsb;
  323 +
  324 + /* Read the time that's left before rebooting */
  325 + /* Note: if the board is not yet armed then we will read 0xFFFF */
  326 + usb_pcwd_send_command(usb_pcwd, CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
  327 +
  328 + *time_left = (msb << 8) + lsb;
  329 +
  330 + return 0;
  331 +}
  332 +
320 333 /*
321 334 * /dev/watchdog handling
322 335 */
... ... @@ -421,6 +434,16 @@
421 434  
422 435 case WDIOC_GETTIMEOUT:
423 436 return put_user(heartbeat, p);
  437 +
  438 + case WDIOC_GETTIMELEFT:
  439 + {
  440 + int time_left;
  441 +
  442 + if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left))
  443 + return -EFAULT;
  444 +
  445 + return put_user(time_left, p);
  446 + }
424 447  
425 448 default:
426 449 return -ENOIOCTLCMD;
include/linux/watchdog.h
... ... @@ -28,6 +28,9 @@
28 28 #define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int)
29 29 #define WDIOC_SETTIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
30 30 #define WDIOC_GETTIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 7, int)
  31 +#define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
  32 +#define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int)
  33 +#define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int)
31 34  
32 35 #define WDIOF_UNKNOWN -1 /* Unknown flag error */
33 36 #define WDIOS_UNKNOWN -1 /* Unknown status error */
... ... @@ -38,9 +41,10 @@
38 41 #define WDIOF_EXTERN2 0x0008 /* External relay 2 */
39 42 #define WDIOF_POWERUNDER 0x0010 /* Power bad/power fault */
40 43 #define WDIOF_CARDRESET 0x0020 /* Card previously reset the CPU */
41   -#define WDIOF_POWEROVER 0x0040 /* Power over voltage */
42   -#define WDIOF_SETTIMEOUT 0x0080 /* Set timeout (in seconds) */
43   -#define WDIOF_MAGICCLOSE 0x0100 /* Supports magic close char */
  44 +#define WDIOF_POWEROVER 0x0040 /* Power over voltage */
  45 +#define WDIOF_SETTIMEOUT 0x0080 /* Set timeout (in seconds) */
  46 +#define WDIOF_MAGICCLOSE 0x0100 /* Supports magic close char */
  47 +#define WDIOF_PRETIMEOUT 0x0200 /* Pretimeout (in seconds), get/set */
44 48 #define WDIOF_KEEPALIVEPING 0x8000 /* Keep alive ping reply */
45 49  
46 50 #define WDIOS_DISABLECARD 0x0001 /* Turn off the watchdog timer */