diff options
author | Aaro Koskinen <aaro.koskinen@iki.fi> | 2015-03-28 14:05:38 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2015-04-22 09:28:31 -0400 |
commit | 3d588c93c040c4aacca81b15a7aa9761357ecdc4 (patch) | |
tree | 085322695070b4aac78071f85684c08e68f933c8 /drivers/watchdog/octeon-wdt-main.c | |
parent | 6290d8c826023a633da3e675784b5f317a9600f0 (diff) |
watchdog: octeon: convert to WATCHDOG_CORE API
Convert OCTEON watchdog to WATCHDOG_CORE API. This enables support
for multiple watchdogs on OCTEON boards.
Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog/octeon-wdt-main.c')
-rw-r--r-- | drivers/watchdog/octeon-wdt-main.c | 185 |
1 files changed, 38 insertions, 147 deletions
diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index 8453531545df..9aa5121d7d50 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c | |||
@@ -3,6 +3,8 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2008, 2009, 2010 Cavium Networks | 4 | * Copyright (C) 2007, 2008, 2009, 2010 Cavium Networks |
5 | * | 5 | * |
6 | * Converted to use WATCHDOG_CORE by Aaro Koskinen <aaro.koskinen@iki.fi>. | ||
7 | * | ||
6 | * Some parts derived from wdt.c | 8 | * Some parts derived from wdt.c |
7 | * | 9 | * |
8 | * (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>, | 10 | * (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>, |
@@ -103,9 +105,6 @@ MODULE_PARM_DESC(nowayout, | |||
103 | "Watchdog cannot be stopped once started (default=" | 105 | "Watchdog cannot be stopped once started (default=" |
104 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 106 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
105 | 107 | ||
106 | static unsigned long octeon_wdt_is_open; | ||
107 | static char expect_close; | ||
108 | |||
109 | static u32 __initdata nmi_stage1_insns[64]; | 108 | static u32 __initdata nmi_stage1_insns[64]; |
110 | /* We need one branch and therefore one relocation per target label. */ | 109 | /* We need one branch and therefore one relocation per target label. */ |
111 | static struct uasm_label __initdata labels[5]; | 110 | static struct uasm_label __initdata labels[5]; |
@@ -444,7 +443,7 @@ static int octeon_wdt_cpu_callback(struct notifier_block *nfb, | |||
444 | return NOTIFY_OK; | 443 | return NOTIFY_OK; |
445 | } | 444 | } |
446 | 445 | ||
447 | static void octeon_wdt_ping(void) | 446 | static int octeon_wdt_ping(struct watchdog_device __always_unused *wdog) |
448 | { | 447 | { |
449 | int cpu; | 448 | int cpu; |
450 | int coreid; | 449 | int coreid; |
@@ -461,6 +460,7 @@ static void octeon_wdt_ping(void) | |||
461 | cpumask_set_cpu(cpu, &irq_enabled_cpus); | 460 | cpumask_set_cpu(cpu, &irq_enabled_cpus); |
462 | } | 461 | } |
463 | } | 462 | } |
463 | return 0; | ||
464 | } | 464 | } |
465 | 465 | ||
466 | static void octeon_wdt_calc_parameters(int t) | 466 | static void octeon_wdt_calc_parameters(int t) |
@@ -489,7 +489,8 @@ static void octeon_wdt_calc_parameters(int t) | |||
489 | timeout_cnt = ((octeon_get_io_clock_rate() >> 8) * timeout_sec) >> 8; | 489 | timeout_cnt = ((octeon_get_io_clock_rate() >> 8) * timeout_sec) >> 8; |
490 | } | 490 | } |
491 | 491 | ||
492 | static int octeon_wdt_set_heartbeat(int t) | 492 | static int octeon_wdt_set_timeout(struct watchdog_device *wdog, |
493 | unsigned int t) | ||
493 | { | 494 | { |
494 | int cpu; | 495 | int cpu; |
495 | int coreid; | 496 | int coreid; |
@@ -509,158 +510,45 @@ static int octeon_wdt_set_heartbeat(int t) | |||
509 | cvmx_write_csr(CVMX_CIU_WDOGX(coreid), ciu_wdog.u64); | 510 | cvmx_write_csr(CVMX_CIU_WDOGX(coreid), ciu_wdog.u64); |
510 | cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1); | 511 | cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1); |
511 | } | 512 | } |
512 | octeon_wdt_ping(); /* Get the irqs back on. */ | 513 | octeon_wdt_ping(wdog); /* Get the irqs back on. */ |
513 | return 0; | 514 | return 0; |
514 | } | 515 | } |
515 | 516 | ||
516 | /** | 517 | static int octeon_wdt_start(struct watchdog_device *wdog) |
517 | * octeon_wdt_write: | ||
518 | * @file: file handle to the watchdog | ||
519 | * @buf: buffer to write (unused as data does not matter here | ||
520 | * @count: count of bytes | ||
521 | * @ppos: pointer to the position to write. No seeks allowed | ||
522 | * | ||
523 | * A write to a watchdog device is defined as a keepalive signal. Any | ||
524 | * write of data will do, as we we don't define content meaning. | ||
525 | */ | ||
526 | |||
527 | static ssize_t octeon_wdt_write(struct file *file, const char __user *buf, | ||
528 | size_t count, loff_t *ppos) | ||
529 | { | ||
530 | if (count) { | ||
531 | if (!nowayout) { | ||
532 | size_t i; | ||
533 | |||
534 | /* In case it was set long ago */ | ||
535 | expect_close = 0; | ||
536 | |||
537 | for (i = 0; i != count; i++) { | ||
538 | char c; | ||
539 | if (get_user(c, buf + i)) | ||
540 | return -EFAULT; | ||
541 | if (c == 'V') | ||
542 | expect_close = 1; | ||
543 | } | ||
544 | } | ||
545 | octeon_wdt_ping(); | ||
546 | } | ||
547 | return count; | ||
548 | } | ||
549 | |||
550 | /** | ||
551 | * octeon_wdt_ioctl: | ||
552 | * @file: file handle to the device | ||
553 | * @cmd: watchdog command | ||
554 | * @arg: argument pointer | ||
555 | * | ||
556 | * The watchdog API defines a common set of functions for all | ||
557 | * watchdogs according to their available features. We only | ||
558 | * actually usefully support querying capabilities and setting | ||
559 | * the timeout. | ||
560 | */ | ||
561 | |||
562 | static long octeon_wdt_ioctl(struct file *file, unsigned int cmd, | ||
563 | unsigned long arg) | ||
564 | { | ||
565 | void __user *argp = (void __user *)arg; | ||
566 | int __user *p = argp; | ||
567 | int new_heartbeat; | ||
568 | |||
569 | static struct watchdog_info ident = { | ||
570 | .options = WDIOF_SETTIMEOUT| | ||
571 | WDIOF_MAGICCLOSE| | ||
572 | WDIOF_KEEPALIVEPING, | ||
573 | .firmware_version = 1, | ||
574 | .identity = "OCTEON", | ||
575 | }; | ||
576 | |||
577 | switch (cmd) { | ||
578 | case WDIOC_GETSUPPORT: | ||
579 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
580 | case WDIOC_GETSTATUS: | ||
581 | case WDIOC_GETBOOTSTATUS: | ||
582 | return put_user(0, p); | ||
583 | case WDIOC_KEEPALIVE: | ||
584 | octeon_wdt_ping(); | ||
585 | return 0; | ||
586 | case WDIOC_SETTIMEOUT: | ||
587 | if (get_user(new_heartbeat, p)) | ||
588 | return -EFAULT; | ||
589 | if (octeon_wdt_set_heartbeat(new_heartbeat)) | ||
590 | return -EINVAL; | ||
591 | /* Fall through. */ | ||
592 | case WDIOC_GETTIMEOUT: | ||
593 | return put_user(heartbeat, p); | ||
594 | default: | ||
595 | return -ENOTTY; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /** | ||
600 | * octeon_wdt_open: | ||
601 | * @inode: inode of device | ||
602 | * @file: file handle to device | ||
603 | * | ||
604 | * The watchdog device has been opened. The watchdog device is single | ||
605 | * open and on opening we do a ping to reset the counters. | ||
606 | */ | ||
607 | |||
608 | static int octeon_wdt_open(struct inode *inode, struct file *file) | ||
609 | { | 518 | { |
610 | if (test_and_set_bit(0, &octeon_wdt_is_open)) | 519 | octeon_wdt_ping(wdog); |
611 | return -EBUSY; | ||
612 | /* | ||
613 | * Activate | ||
614 | */ | ||
615 | octeon_wdt_ping(); | ||
616 | do_coundown = 1; | 520 | do_coundown = 1; |
617 | return nonseekable_open(inode, file); | 521 | return 0; |
618 | } | 522 | } |
619 | 523 | ||
620 | /** | 524 | static int octeon_wdt_stop(struct watchdog_device *wdog) |
621 | * octeon_wdt_release: | ||
622 | * @inode: inode to board | ||
623 | * @file: file handle to board | ||
624 | * | ||
625 | * The watchdog has a configurable API. There is a religious dispute | ||
626 | * between people who want their watchdog to be able to shut down and | ||
627 | * those who want to be sure if the watchdog manager dies the machine | ||
628 | * reboots. In the former case we disable the counters, in the latter | ||
629 | * case you have to open it again very soon. | ||
630 | */ | ||
631 | |||
632 | static int octeon_wdt_release(struct inode *inode, struct file *file) | ||
633 | { | 525 | { |
634 | if (expect_close) { | 526 | do_coundown = 0; |
635 | do_coundown = 0; | 527 | octeon_wdt_ping(wdog); |
636 | octeon_wdt_ping(); | ||
637 | } else { | ||
638 | pr_crit("WDT device closed unexpectedly. WDT will not stop!\n"); | ||
639 | } | ||
640 | clear_bit(0, &octeon_wdt_is_open); | ||
641 | expect_close = 0; | ||
642 | return 0; | 528 | return 0; |
643 | } | 529 | } |
644 | 530 | ||
645 | static const struct file_operations octeon_wdt_fops = { | 531 | static struct notifier_block octeon_wdt_cpu_notifier = { |
646 | .owner = THIS_MODULE, | 532 | .notifier_call = octeon_wdt_cpu_callback, |
647 | .llseek = no_llseek, | ||
648 | .write = octeon_wdt_write, | ||
649 | .unlocked_ioctl = octeon_wdt_ioctl, | ||
650 | .open = octeon_wdt_open, | ||
651 | .release = octeon_wdt_release, | ||
652 | }; | 533 | }; |
653 | 534 | ||
654 | static struct miscdevice octeon_wdt_miscdev = { | 535 | static const struct watchdog_info octeon_wdt_info = { |
655 | .minor = WATCHDOG_MINOR, | 536 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, |
656 | .name = "watchdog", | 537 | .identity = "OCTEON", |
657 | .fops = &octeon_wdt_fops, | ||
658 | }; | 538 | }; |
659 | 539 | ||
660 | static struct notifier_block octeon_wdt_cpu_notifier = { | 540 | static const struct watchdog_ops octeon_wdt_ops = { |
661 | .notifier_call = octeon_wdt_cpu_callback, | 541 | .owner = THIS_MODULE, |
542 | .start = octeon_wdt_start, | ||
543 | .stop = octeon_wdt_stop, | ||
544 | .ping = octeon_wdt_ping, | ||
545 | .set_timeout = octeon_wdt_set_timeout, | ||
662 | }; | 546 | }; |
663 | 547 | ||
548 | static struct watchdog_device octeon_wdt = { | ||
549 | .info = &octeon_wdt_info, | ||
550 | .ops = &octeon_wdt_ops, | ||
551 | }; | ||
664 | 552 | ||
665 | /** | 553 | /** |
666 | * Module/ driver initialization. | 554 | * Module/ driver initialization. |
@@ -694,11 +582,15 @@ static int __init octeon_wdt_init(void) | |||
694 | 582 | ||
695 | pr_info("Initial granularity %d Sec\n", timeout_sec); | 583 | pr_info("Initial granularity %d Sec\n", timeout_sec); |
696 | 584 | ||
697 | ret = misc_register(&octeon_wdt_miscdev); | 585 | octeon_wdt.timeout = timeout_sec; |
586 | octeon_wdt.max_timeout = UINT_MAX; | ||
587 | |||
588 | watchdog_set_nowayout(&octeon_wdt, nowayout); | ||
589 | |||
590 | ret = watchdog_register_device(&octeon_wdt); | ||
698 | if (ret) { | 591 | if (ret) { |
699 | pr_err("cannot register miscdev on minor=%d (err=%d)\n", | 592 | pr_err("watchdog_register_device() failed: %d\n", ret); |
700 | WATCHDOG_MINOR, ret); | 593 | return ret; |
701 | goto out; | ||
702 | } | 594 | } |
703 | 595 | ||
704 | /* Build the NMI handler ... */ | 596 | /* Build the NMI handler ... */ |
@@ -721,8 +613,7 @@ static int __init octeon_wdt_init(void) | |||
721 | __register_hotcpu_notifier(&octeon_wdt_cpu_notifier); | 613 | __register_hotcpu_notifier(&octeon_wdt_cpu_notifier); |
722 | cpu_notifier_register_done(); | 614 | cpu_notifier_register_done(); |
723 | 615 | ||
724 | out: | 616 | return 0; |
725 | return ret; | ||
726 | } | 617 | } |
727 | 618 | ||
728 | /** | 619 | /** |
@@ -732,7 +623,7 @@ static void __exit octeon_wdt_cleanup(void) | |||
732 | { | 623 | { |
733 | int cpu; | 624 | int cpu; |
734 | 625 | ||
735 | misc_deregister(&octeon_wdt_miscdev); | 626 | watchdog_unregister_device(&octeon_wdt); |
736 | 627 | ||
737 | cpu_notifier_register_begin(); | 628 | cpu_notifier_register_begin(); |
738 | __unregister_hotcpu_notifier(&octeon_wdt_cpu_notifier); | 629 | __unregister_hotcpu_notifier(&octeon_wdt_cpu_notifier); |