diff options
author | Marc van der Wal <x0r+kernel@x0r.fr> | 2014-03-06 04:36:59 -0500 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2014-03-31 07:33:55 -0400 |
commit | 0bcd0b6a47431d9895dc2dd6a8c4185008849131 (patch) | |
tree | f75055beb1a08be642e491595e44bbeaa381e46d | |
parent | 5e82ec94ac5d2d941414861654032543a75cf823 (diff) |
watchdog: it87_wdt: Work around non-working CIR interrupts
On some hardware platforms, the it87_wdt watchdog resets the machine
despite the watchdog daemon running and writing to /dev/watchdog.
This is due to Consumer IR buffer underrun interrupts being used as
triggers to reset the timer. On some buggy hardware implementations
such as the iEi AFL-12A-N270 single-board computer, this method does
not work.
However, resetting the timer by writing its original timeout value in
its configuration register over and over again suppresses the unwanted
reboots.
Add a module option (nocir), 0 by default in order not to break existing
setups. Setting it to 1 enables the workaround.
Fixes bug #42801 <https://bugzilla.kernel.org/show_bug.cgi?id=42801>.
Tested primarily on Linux 3.5.7, applies cleanly on Linux 3.13.5.
Signed-off-by: Marc van der Wal <x0r+kernel@x0r.fr>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r-- | Documentation/watchdog/watchdog-parameters.txt | 2 | ||||
-rw-r--r-- | drivers/watchdog/it87_wdt.c | 41 |
2 files changed, 33 insertions, 10 deletions
diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt index b39f35596ba2..692791cc674c 100644 --- a/Documentation/watchdog/watchdog-parameters.txt +++ b/Documentation/watchdog/watchdog-parameters.txt | |||
@@ -150,6 +150,8 @@ nowayout: Disable watchdog shutdown on close | |||
150 | ------------------------------------------------- | 150 | ------------------------------------------------- |
151 | it87_wdt: | 151 | it87_wdt: |
152 | nogameport: Forbid the activation of game port, default=0 | 152 | nogameport: Forbid the activation of game port, default=0 |
153 | nocir: Forbid the use of CIR (workaround for some buggy setups); set to 1 if | ||
154 | system resets despite watchdog daemon running, default=0 | ||
153 | exclusive: Watchdog exclusive device open, default=1 | 155 | exclusive: Watchdog exclusive device open, default=1 |
154 | timeout: Watchdog timeout in seconds, default=60 | 156 | timeout: Watchdog timeout in seconds, default=60 |
155 | testmode: Watchdog test mode (1 = no reboot), default=0 | 157 | testmode: Watchdog test mode (1 = no reboot), default=0 |
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index e2bba68ae71e..0b93739c0106 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c | |||
@@ -54,6 +54,7 @@ | |||
54 | 54 | ||
55 | /* Defaults for Module Parameter */ | 55 | /* Defaults for Module Parameter */ |
56 | #define DEFAULT_NOGAMEPORT 0 | 56 | #define DEFAULT_NOGAMEPORT 0 |
57 | #define DEFAULT_NOCIR 0 | ||
57 | #define DEFAULT_EXCLUSIVE 1 | 58 | #define DEFAULT_EXCLUSIVE 1 |
58 | #define DEFAULT_TIMEOUT 60 | 59 | #define DEFAULT_TIMEOUT 60 |
59 | #define DEFAULT_TESTMODE 0 | 60 | #define DEFAULT_TESTMODE 0 |
@@ -136,11 +137,13 @@ | |||
136 | #define WDTS_LOCKED 3 | 137 | #define WDTS_LOCKED 3 |
137 | #define WDTS_USE_GP 4 | 138 | #define WDTS_USE_GP 4 |
138 | #define WDTS_EXPECTED 5 | 139 | #define WDTS_EXPECTED 5 |
140 | #define WDTS_USE_CIR 6 | ||
139 | 141 | ||
140 | static unsigned int base, gpact, ciract, max_units, chip_type; | 142 | static unsigned int base, gpact, ciract, max_units, chip_type; |
141 | static unsigned long wdt_status; | 143 | static unsigned long wdt_status; |
142 | 144 | ||
143 | static int nogameport = DEFAULT_NOGAMEPORT; | 145 | static int nogameport = DEFAULT_NOGAMEPORT; |
146 | static int nocir = DEFAULT_NOCIR; | ||
144 | static int exclusive = DEFAULT_EXCLUSIVE; | 147 | static int exclusive = DEFAULT_EXCLUSIVE; |
145 | static int timeout = DEFAULT_TIMEOUT; | 148 | static int timeout = DEFAULT_TIMEOUT; |
146 | static int testmode = DEFAULT_TESTMODE; | 149 | static int testmode = DEFAULT_TESTMODE; |
@@ -149,6 +152,9 @@ static bool nowayout = DEFAULT_NOWAYOUT; | |||
149 | module_param(nogameport, int, 0); | 152 | module_param(nogameport, int, 0); |
150 | MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default=" | 153 | MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default=" |
151 | __MODULE_STRING(DEFAULT_NOGAMEPORT)); | 154 | __MODULE_STRING(DEFAULT_NOGAMEPORT)); |
155 | module_param(nocir, int, 0); | ||
156 | MODULE_PARM_DESC(nocir, "Forbid the use of Consumer IR interrupts to reset timer, default=" | ||
157 | __MODULE_STRING(DEFAULT_NOCIR)); | ||
152 | module_param(exclusive, int, 0); | 158 | module_param(exclusive, int, 0); |
153 | MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default=" | 159 | MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default=" |
154 | __MODULE_STRING(DEFAULT_EXCLUSIVE)); | 160 | __MODULE_STRING(DEFAULT_EXCLUSIVE)); |
@@ -258,9 +264,17 @@ static void wdt_keepalive(void) | |||
258 | { | 264 | { |
259 | if (test_bit(WDTS_USE_GP, &wdt_status)) | 265 | if (test_bit(WDTS_USE_GP, &wdt_status)) |
260 | inb(base); | 266 | inb(base); |
261 | else | 267 | else if (test_bit(WDTS_USE_CIR, &wdt_status)) |
262 | /* The timer reloads with around 5 msec delay */ | 268 | /* The timer reloads with around 5 msec delay */ |
263 | outb(0x55, CIR_DR(base)); | 269 | outb(0x55, CIR_DR(base)); |
270 | else { | ||
271 | if (superio_enter()) | ||
272 | return; | ||
273 | |||
274 | superio_select(GPIO); | ||
275 | wdt_update_timeout(); | ||
276 | superio_exit(); | ||
277 | } | ||
264 | set_bit(WDTS_KEEPALIVE, &wdt_status); | 278 | set_bit(WDTS_KEEPALIVE, &wdt_status); |
265 | } | 279 | } |
266 | 280 | ||
@@ -273,7 +287,7 @@ static int wdt_start(void) | |||
273 | superio_select(GPIO); | 287 | superio_select(GPIO); |
274 | if (test_bit(WDTS_USE_GP, &wdt_status)) | 288 | if (test_bit(WDTS_USE_GP, &wdt_status)) |
275 | superio_outb(WDT_GAMEPORT, WDTCTRL); | 289 | superio_outb(WDT_GAMEPORT, WDTCTRL); |
276 | else | 290 | else if (test_bit(WDTS_USE_CIR, &wdt_status)) |
277 | superio_outb(WDT_CIRINT, WDTCTRL); | 291 | superio_outb(WDT_CIRINT, WDTCTRL); |
278 | wdt_update_timeout(); | 292 | wdt_update_timeout(); |
279 | 293 | ||
@@ -660,7 +674,7 @@ static int __init it87_wdt_init(void) | |||
660 | } | 674 | } |
661 | 675 | ||
662 | /* If we haven't Gameport support, try to get CIR support */ | 676 | /* If we haven't Gameport support, try to get CIR support */ |
663 | if (!test_bit(WDTS_USE_GP, &wdt_status)) { | 677 | if (!nocir && !test_bit(WDTS_USE_GP, &wdt_status)) { |
664 | if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) { | 678 | if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) { |
665 | if (gp_rreq_fail) | 679 | if (gp_rreq_fail) |
666 | pr_err("I/O Address 0x%04x and 0x%04x already in use\n", | 680 | pr_err("I/O Address 0x%04x and 0x%04x already in use\n", |
@@ -682,6 +696,7 @@ static int __init it87_wdt_init(void) | |||
682 | superio_select(GAMEPORT); | 696 | superio_select(GAMEPORT); |
683 | superio_outb(gpact, ACTREG); | 697 | superio_outb(gpact, ACTREG); |
684 | } | 698 | } |
699 | set_bit(WDTS_USE_CIR, &wdt_status); | ||
685 | } | 700 | } |
686 | 701 | ||
687 | if (timeout < 1 || timeout > max_units * 60) { | 702 | if (timeout < 1 || timeout > max_units * 60) { |
@@ -707,7 +722,7 @@ static int __init it87_wdt_init(void) | |||
707 | } | 722 | } |
708 | 723 | ||
709 | /* Initialize CIR to use it as keepalive source */ | 724 | /* Initialize CIR to use it as keepalive source */ |
710 | if (!test_bit(WDTS_USE_GP, &wdt_status)) { | 725 | if (test_bit(WDTS_USE_CIR, &wdt_status)) { |
711 | outb(0x00, CIR_RCR(base)); | 726 | outb(0x00, CIR_RCR(base)); |
712 | outb(0xc0, CIR_TCR1(base)); | 727 | outb(0xc0, CIR_TCR1(base)); |
713 | outb(0x5c, CIR_TCR2(base)); | 728 | outb(0x5c, CIR_TCR2(base)); |
@@ -717,9 +732,9 @@ static int __init it87_wdt_init(void) | |||
717 | outb(0x09, CIR_IER(base)); | 732 | outb(0x09, CIR_IER(base)); |
718 | } | 733 | } |
719 | 734 | ||
720 | pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d)\n", | 735 | pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d nocir=%d)\n", |
721 | chip_type, chip_rev, timeout, | 736 | chip_type, chip_rev, timeout, |
722 | nowayout, testmode, exclusive, nogameport); | 737 | nowayout, testmode, exclusive, nogameport, nocir); |
723 | 738 | ||
724 | superio_exit(); | 739 | superio_exit(); |
725 | return 0; | 740 | return 0; |
@@ -727,8 +742,10 @@ static int __init it87_wdt_init(void) | |||
727 | err_out_reboot: | 742 | err_out_reboot: |
728 | unregister_reboot_notifier(&wdt_notifier); | 743 | unregister_reboot_notifier(&wdt_notifier); |
729 | err_out_region: | 744 | err_out_region: |
730 | release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); | 745 | if (test_bit(WDTS_USE_GP, &wdt_status)) |
731 | if (!test_bit(WDTS_USE_GP, &wdt_status)) { | 746 | release_region(base, 1); |
747 | else if (test_bit(WDTS_USE_CIR, &wdt_status)) { | ||
748 | release_region(base, 8); | ||
732 | superio_select(CIR); | 749 | superio_select(CIR); |
733 | superio_outb(ciract, ACTREG); | 750 | superio_outb(ciract, ACTREG); |
734 | } | 751 | } |
@@ -754,7 +771,7 @@ static void __exit it87_wdt_exit(void) | |||
754 | if (test_bit(WDTS_USE_GP, &wdt_status)) { | 771 | if (test_bit(WDTS_USE_GP, &wdt_status)) { |
755 | superio_select(GAMEPORT); | 772 | superio_select(GAMEPORT); |
756 | superio_outb(gpact, ACTREG); | 773 | superio_outb(gpact, ACTREG); |
757 | } else { | 774 | } else if (test_bit(WDTS_USE_CIR, &wdt_status)) { |
758 | superio_select(CIR); | 775 | superio_select(CIR); |
759 | superio_outb(ciract, ACTREG); | 776 | superio_outb(ciract, ACTREG); |
760 | } | 777 | } |
@@ -763,7 +780,11 @@ static void __exit it87_wdt_exit(void) | |||
763 | 780 | ||
764 | misc_deregister(&wdt_miscdev); | 781 | misc_deregister(&wdt_miscdev); |
765 | unregister_reboot_notifier(&wdt_notifier); | 782 | unregister_reboot_notifier(&wdt_notifier); |
766 | release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); | 783 | |
784 | if (test_bit(WDTS_USE_GP, &wdt_status)) | ||
785 | release_region(base, 1); | ||
786 | else if (test_bit(WDTS_USE_CIR, &wdt_status)) | ||
787 | release_region(base, 8); | ||
767 | } | 788 | } |
768 | 789 | ||
769 | module_init(it87_wdt_init); | 790 | module_init(it87_wdt_init); |