aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/octeon-wdt-main.c
diff options
context:
space:
mode:
authorAaro Koskinen <aaro.koskinen@iki.fi>2015-03-28 14:05:38 -0400
committerWim Van Sebroeck <wim@iguana.be>2015-04-22 09:28:31 -0400
commit3d588c93c040c4aacca81b15a7aa9761357ecdc4 (patch)
tree085322695070b4aac78071f85684c08e68f933c8 /drivers/watchdog/octeon-wdt-main.c
parent6290d8c826023a633da3e675784b5f317a9600f0 (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.c185
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
106static unsigned long octeon_wdt_is_open;
107static char expect_close;
108
109static u32 __initdata nmi_stage1_insns[64]; 108static 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. */
111static struct uasm_label __initdata labels[5]; 110static 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
447static void octeon_wdt_ping(void) 446static 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
466static void octeon_wdt_calc_parameters(int t) 466static 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
492static int octeon_wdt_set_heartbeat(int t) 492static 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/** 517static 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
527static 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
562static 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
608static 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/** 524static 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
632static 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
645static const struct file_operations octeon_wdt_fops = { 531static 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
654static struct miscdevice octeon_wdt_miscdev = { 535static 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
660static struct notifier_block octeon_wdt_cpu_notifier = { 540static 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
548static 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
724out: 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);