Commit bff23431fe7e2eba939fe4cdaa78d94a4d9497f7

Authored by Wim Van Sebroeck
1 parent 18cb2ae55f

watchdog: iTCO_wdt.c: convert to watchdog core

This patch converts the iTCO_wdt watchdog driver to use the
generic watchdog framework.

Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

Showing 2 changed files with 49 additions and 165 deletions Side-by-side Diff

drivers/watchdog/Kconfig
... ... @@ -578,6 +578,7 @@
578 578 config ITCO_WDT
579 579 tristate "Intel TCO Timer/Watchdog"
580 580 depends on (X86 || IA64) && PCI
  581 + select WATCHDOG_CORE
581 582 select LPC_ICH
582 583 ---help---
583 584 Hardware driver for the intel TCO timer based watchdog devices.
drivers/watchdog/iTCO_wdt.c
... ... @@ -47,7 +47,7 @@
47 47  
48 48 /* Module and version information */
49 49 #define DRV_NAME "iTCO_wdt"
50   -#define DRV_VERSION "1.07"
  50 +#define DRV_VERSION "1.10"
51 51  
52 52 /* Includes */
53 53 #include <linux/module.h> /* For module specific items */
... ... @@ -88,8 +88,6 @@
88 88 #define TCOv2_TMR (TCOBASE + 0x12) /* TCOv2 Timer Initial Value */
89 89  
90 90 /* internal variables */
91   -static unsigned long is_active;
92   -static char expect_release;
93 91 static struct { /* this is private data for the iTCO_wdt device */
94 92 /* TCO version/generation */
95 93 unsigned int iTCO_version;
96 94  
... ... @@ -106,12 +104,12 @@
106 104 } iTCO_wdt_private;
107 105  
108 106 /* module parameters */
109   -#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
110   -static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
  107 +#define WATCHDOG_TIMEOUT 30 /* 30 sec default heartbeat */
  108 +static int heartbeat = WATCHDOG_TIMEOUT; /* in seconds */
111 109 module_param(heartbeat, int, 0);
112 110 MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
113 111 "5..76 (TCO v1) or 3..614 (TCO v2), default="
114   - __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
  112 + __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
115 113  
116 114 static bool nowayout = WATCHDOG_NOWAYOUT;
117 115 module_param(nowayout, bool, 0);
118 116  
... ... @@ -178,13 +176,13 @@
178 176 return ret; /* returns: 0 = OK, -EIO = Error */
179 177 }
180 178  
181   -static int iTCO_wdt_start(void)
  179 +static int iTCO_wdt_start(struct watchdog_device *wd_dev)
182 180 {
183 181 unsigned int val;
184 182  
185 183 spin_lock(&iTCO_wdt_private.io_lock);
186 184  
187   - iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, heartbeat);
  185 + iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, wd_dev->timeout);
188 186  
189 187 /* disable chipset's NO_REBOOT bit */
190 188 if (iTCO_wdt_unset_NO_REBOOT_bit()) {
... ... @@ -212,7 +210,7 @@
212 210 return 0;
213 211 }
214 212  
215   -static int iTCO_wdt_stop(void)
  213 +static int iTCO_wdt_stop(struct watchdog_device *wd_dev)
216 214 {
217 215 unsigned int val;
218 216  
219 217  
... ... @@ -236,11 +234,11 @@
236 234 return 0;
237 235 }
238 236  
239   -static int iTCO_wdt_keepalive(void)
  237 +static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
240 238 {
241 239 spin_lock(&iTCO_wdt_private.io_lock);
242 240  
243   - iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, heartbeat);
  241 + iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, wd_dev->timeout);
244 242  
245 243 /* Reload the timer by writing to the TCO Timer Counter register */
246 244 if (iTCO_wdt_private.iTCO_version == 2)
... ... @@ -257,7 +255,7 @@
257 255 return 0;
258 256 }
259 257  
260   -static int iTCO_wdt_set_heartbeat(int t)
  258 +static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
261 259 {
262 260 unsigned int val16;
263 261 unsigned char val8;
264 262  
265 263  
... ... @@ -304,14 +302,15 @@
304 302 return -EINVAL;
305 303 }
306 304  
307   - heartbeat = t;
  305 + wd_dev->timeout = t;
308 306 return 0;
309 307 }
310 308  
311   -static int iTCO_wdt_get_timeleft(int *time_left)
  309 +static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
312 310 {
313 311 unsigned int val16;
314 312 unsigned char val8;
  313 + unsigned int time_left = 0;
315 314  
316 315 /* read the TCO Timer */
317 316 if (iTCO_wdt_private.iTCO_version == 2) {
... ... @@ -320,7 +319,7 @@
320 319 val16 &= 0x3ff;
321 320 spin_unlock(&iTCO_wdt_private.io_lock);
322 321  
323   - *time_left = (val16 * 6) / 10;
  322 + time_left = (val16 * 6) / 10;
324 323 } else if (iTCO_wdt_private.iTCO_version == 1) {
325 324 spin_lock(&iTCO_wdt_private.io_lock);
326 325 val8 = inb(TCO_RLD);
327 326  
328 327  
329 328  
330 329  
331 330  
... ... @@ -329,156 +328,35 @@
329 328 val8 += (inb(TCOv1_TMR) & 0x3f);
330 329 spin_unlock(&iTCO_wdt_private.io_lock);
331 330  
332   - *time_left = (val8 * 6) / 10;
333   - } else
334   - return -EINVAL;
335   - return 0;
336   -}
337   -
338   -/*
339   - * /dev/watchdog handling
340   - */
341   -
342   -static int iTCO_wdt_open(struct inode *inode, struct file *file)
343   -{
344   - /* /dev/watchdog can only be opened once */
345   - if (test_and_set_bit(0, &is_active))
346   - return -EBUSY;
347   -
348   - /*
349   - * Reload and activate timer
350   - */
351   - iTCO_wdt_start();
352   - return nonseekable_open(inode, file);
353   -}
354   -
355   -static int iTCO_wdt_release(struct inode *inode, struct file *file)
356   -{
357   - /*
358   - * Shut off the timer.
359   - */
360   - if (expect_release == 42) {
361   - iTCO_wdt_stop();
362   - } else {
363   - pr_crit("Unexpected close, not stopping watchdog!\n");
364   - iTCO_wdt_keepalive();
  331 + time_left = (val8 * 6) / 10;
365 332 }
366   - clear_bit(0, &is_active);
367   - expect_release = 0;
368   - return 0;
  333 + return time_left;
369 334 }
370 335  
371   -static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
372   - size_t len, loff_t *ppos)
373   -{
374   - /* See if we got the magic character 'V' and reload the timer */
375   - if (len) {
376   - if (!nowayout) {
377   - size_t i;
378   -
379   - /* note: just in case someone wrote the magic
380   - character five months ago... */
381   - expect_release = 0;
382   -
383   - /* scan to see whether or not we got the
384   - magic character */
385   - for (i = 0; i != len; i++) {
386   - char c;
387   - if (get_user(c, data + i))
388   - return -EFAULT;
389   - if (c == 'V')
390   - expect_release = 42;
391   - }
392   - }
393   -
394   - /* someone wrote to us, we should reload the timer */
395   - iTCO_wdt_keepalive();
396   - }
397   - return len;
398   -}
399   -
400   -static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
401   - unsigned long arg)
402   -{
403   - int new_options, retval = -EINVAL;
404   - int new_heartbeat;
405   - void __user *argp = (void __user *)arg;
406   - int __user *p = argp;
407   - static const struct watchdog_info ident = {
408   - .options = WDIOF_SETTIMEOUT |
409   - WDIOF_KEEPALIVEPING |
410   - WDIOF_MAGICCLOSE,
411   - .firmware_version = 0,
412   - .identity = DRV_NAME,
413   - };
414   -
415   - switch (cmd) {
416   - case WDIOC_GETSUPPORT:
417   - return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
418   - case WDIOC_GETSTATUS:
419   - case WDIOC_GETBOOTSTATUS:
420   - return put_user(0, p);
421   -
422   - case WDIOC_SETOPTIONS:
423   - {
424   - if (get_user(new_options, p))
425   - return -EFAULT;
426   -
427   - if (new_options & WDIOS_DISABLECARD) {
428   - iTCO_wdt_stop();
429   - retval = 0;
430   - }
431   - if (new_options & WDIOS_ENABLECARD) {
432   - iTCO_wdt_keepalive();
433   - iTCO_wdt_start();
434   - retval = 0;
435   - }
436   - return retval;
437   - }
438   - case WDIOC_KEEPALIVE:
439   - iTCO_wdt_keepalive();
440   - return 0;
441   -
442   - case WDIOC_SETTIMEOUT:
443   - {
444   - if (get_user(new_heartbeat, p))
445   - return -EFAULT;
446   - if (iTCO_wdt_set_heartbeat(new_heartbeat))
447   - return -EINVAL;
448   - iTCO_wdt_keepalive();
449   - /* Fall */
450   - }
451   - case WDIOC_GETTIMEOUT:
452   - return put_user(heartbeat, p);
453   - case WDIOC_GETTIMELEFT:
454   - {
455   - int time_left;
456   - if (iTCO_wdt_get_timeleft(&time_left))
457   - return -EINVAL;
458   - return put_user(time_left, p);
459   - }
460   - default:
461   - return -ENOTTY;
462   - }
463   -}
464   -
465 336 /*
466 337 * Kernel Interfaces
467 338 */
468 339  
469   -static const struct file_operations iTCO_wdt_fops = {
  340 +static const struct watchdog_info ident = {
  341 + .options = WDIOF_SETTIMEOUT |
  342 + WDIOF_KEEPALIVEPING |
  343 + WDIOF_MAGICCLOSE,
  344 + .firmware_version = 0,
  345 + .identity = DRV_NAME,
  346 +};
  347 +
  348 +static const struct watchdog_ops iTCO_wdt_ops = {
470 349 .owner = THIS_MODULE,
471   - .llseek = no_llseek,
472   - .write = iTCO_wdt_write,
473   - .unlocked_ioctl = iTCO_wdt_ioctl,
474   - .open = iTCO_wdt_open,
475   - .release = iTCO_wdt_release,
  350 + .start = iTCO_wdt_start,
  351 + .stop = iTCO_wdt_stop,
  352 + .ping = iTCO_wdt_ping,
  353 + .set_timeout = iTCO_wdt_set_timeout,
  354 + .get_timeleft = iTCO_wdt_get_timeleft,
476 355 };
477 356  
478   -static struct miscdevice iTCO_wdt_miscdev = {
479   - .minor = WATCHDOG_MINOR,
480   - .name = "watchdog",
481   - .fops = &iTCO_wdt_fops,
  357 +static struct watchdog_device iTCO_wdt_watchdog_dev = {
  358 + .info = &ident,
  359 + .ops = &iTCO_wdt_ops,
482 360 };
483 361  
484 362 /*
485 363  
... ... @@ -489,10 +367,10 @@
489 367 {
490 368 /* Stop the timer before we leave */
491 369 if (!nowayout)
492   - iTCO_wdt_stop();
  370 + iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
493 371  
494 372 /* Deregister */
495   - misc_deregister(&iTCO_wdt_miscdev);
  373 + watchdog_unregister_device(&iTCO_wdt_watchdog_dev);
496 374  
497 375 /* release resources */
498 376 release_region(iTCO_wdt_private.tco_res->start,
499 377  
500 378  
501 379  
502 380  
... ... @@ -605,20 +483,25 @@
605 483 outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
606 484 outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */
607 485  
  486 + iTCO_wdt_watchdog_dev.bootstatus = 0;
  487 + iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT;
  488 + watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout);
  489 + iTCO_wdt_watchdog_dev.parent = dev->dev.parent;
  490 +
608 491 /* Make sure the watchdog is not running */
609   - iTCO_wdt_stop();
  492 + iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
610 493  
611 494 /* Check that the heartbeat value is within it's range;
612 495 if not reset to the default */
613   - if (iTCO_wdt_set_heartbeat(heartbeat)) {
614   - iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
615   - pr_info("timeout value out of range, using %d\n", heartbeat);
  496 + if (iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, heartbeat)) {
  497 + iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, WATCHDOG_TIMEOUT);
  498 + pr_info("timeout value out of range, using %d\n",
  499 + WATCHDOG_TIMEOUT);
616 500 }
617 501  
618   - ret = misc_register(&iTCO_wdt_miscdev);
  502 + ret = watchdog_register_device(&iTCO_wdt_watchdog_dev);
619 503 if (ret != 0) {
620   - pr_err("cannot register miscdev on minor=%d (err=%d)\n",
621   - WATCHDOG_MINOR, ret);
  504 + pr_err("cannot register watchdog device (err=%d)\n", ret);
622 505 goto unreg_tco;
623 506 }
624 507  
... ... @@ -659,7 +542,7 @@
659 542  
660 543 static void iTCO_wdt_shutdown(struct platform_device *dev)
661 544 {
662   - iTCO_wdt_stop();
  545 + iTCO_wdt_stop(NULL);
663 546 }
664 547  
665 548 static struct platform_driver iTCO_wdt_driver = {