aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc van der Wal <x0r+kernel@x0r.fr>2014-03-06 04:36:59 -0500
committerWim Van Sebroeck <wim@iguana.be>2014-03-31 07:33:55 -0400
commit0bcd0b6a47431d9895dc2dd6a8c4185008849131 (patch)
treef75055beb1a08be642e491595e44bbeaa381e46d
parent5e82ec94ac5d2d941414861654032543a75cf823 (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.txt2
-rw-r--r--drivers/watchdog/it87_wdt.c41
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-------------------------------------------------
151it87_wdt: 151it87_wdt:
152nogameport: Forbid the activation of game port, default=0 152nogameport: Forbid the activation of game port, default=0
153nocir: Forbid the use of CIR (workaround for some buggy setups); set to 1 if
154system resets despite watchdog daemon running, default=0
153exclusive: Watchdog exclusive device open, default=1 155exclusive: Watchdog exclusive device open, default=1
154timeout: Watchdog timeout in seconds, default=60 156timeout: Watchdog timeout in seconds, default=60
155testmode: Watchdog test mode (1 = no reboot), default=0 157testmode: 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
140static unsigned int base, gpact, ciract, max_units, chip_type; 142static unsigned int base, gpact, ciract, max_units, chip_type;
141static unsigned long wdt_status; 143static unsigned long wdt_status;
142 144
143static int nogameport = DEFAULT_NOGAMEPORT; 145static int nogameport = DEFAULT_NOGAMEPORT;
146static int nocir = DEFAULT_NOCIR;
144static int exclusive = DEFAULT_EXCLUSIVE; 147static int exclusive = DEFAULT_EXCLUSIVE;
145static int timeout = DEFAULT_TIMEOUT; 148static int timeout = DEFAULT_TIMEOUT;
146static int testmode = DEFAULT_TESTMODE; 149static int testmode = DEFAULT_TESTMODE;
@@ -149,6 +152,9 @@ static bool nowayout = DEFAULT_NOWAYOUT;
149module_param(nogameport, int, 0); 152module_param(nogameport, int, 0);
150MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default=" 153MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
151 __MODULE_STRING(DEFAULT_NOGAMEPORT)); 154 __MODULE_STRING(DEFAULT_NOGAMEPORT));
155module_param(nocir, int, 0);
156MODULE_PARM_DESC(nocir, "Forbid the use of Consumer IR interrupts to reset timer, default="
157 __MODULE_STRING(DEFAULT_NOCIR));
152module_param(exclusive, int, 0); 158module_param(exclusive, int, 0);
153MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default=" 159MODULE_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)
727err_out_reboot: 742err_out_reboot:
728 unregister_reboot_notifier(&wdt_notifier); 743 unregister_reboot_notifier(&wdt_notifier);
729err_out_region: 744err_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
769module_init(it87_wdt_init); 790module_init(it87_wdt_init);