Commit bff23431fe7e2eba939fe4cdaa78d94a4d9497f7
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
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 = { |