watchdog: it87_wdt: Work around non-working CIR interrupts
[cascardo/linux.git] / drivers / watchdog / it87_wdt.c
index e2bba68..0b93739 100644 (file)
@@ -54,6 +54,7 @@
 
 /* Defaults for Module Parameter */
 #define DEFAULT_NOGAMEPORT     0
+#define DEFAULT_NOCIR          0
 #define DEFAULT_EXCLUSIVE      1
 #define DEFAULT_TIMEOUT                60
 #define DEFAULT_TESTMODE       0
 #define WDTS_LOCKED    3
 #define WDTS_USE_GP    4
 #define WDTS_EXPECTED  5
+#define WDTS_USE_CIR   6
 
 static unsigned int base, gpact, ciract, max_units, chip_type;
 static unsigned long wdt_status;
 
 static int nogameport = DEFAULT_NOGAMEPORT;
+static int nocir      = DEFAULT_NOCIR;
 static int exclusive  = DEFAULT_EXCLUSIVE;
 static int timeout    = DEFAULT_TIMEOUT;
 static int testmode   = DEFAULT_TESTMODE;
@@ -149,6 +152,9 @@ static      bool nowayout   = DEFAULT_NOWAYOUT;
 module_param(nogameport, int, 0);
 MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
                __MODULE_STRING(DEFAULT_NOGAMEPORT));
+module_param(nocir, int, 0);
+MODULE_PARM_DESC(nocir, "Forbid the use of Consumer IR interrupts to reset timer, default="
+               __MODULE_STRING(DEFAULT_NOCIR));
 module_param(exclusive, int, 0);
 MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
                __MODULE_STRING(DEFAULT_EXCLUSIVE));
@@ -258,9 +264,17 @@ static void wdt_keepalive(void)
 {
        if (test_bit(WDTS_USE_GP, &wdt_status))
                inb(base);
-       else
+       else if (test_bit(WDTS_USE_CIR, &wdt_status))
                /* The timer reloads with around 5 msec delay */
                outb(0x55, CIR_DR(base));
+       else {
+               if (superio_enter())
+                       return;
+
+               superio_select(GPIO);
+               wdt_update_timeout();
+               superio_exit();
+       }
        set_bit(WDTS_KEEPALIVE, &wdt_status);
 }
 
@@ -273,7 +287,7 @@ static int wdt_start(void)
        superio_select(GPIO);
        if (test_bit(WDTS_USE_GP, &wdt_status))
                superio_outb(WDT_GAMEPORT, WDTCTRL);
-       else
+       else if (test_bit(WDTS_USE_CIR, &wdt_status))
                superio_outb(WDT_CIRINT, WDTCTRL);
        wdt_update_timeout();
 
@@ -660,7 +674,7 @@ static int __init it87_wdt_init(void)
        }
 
        /* If we haven't Gameport support, try to get CIR support */
-       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+       if (!nocir && !test_bit(WDTS_USE_GP, &wdt_status)) {
                if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
                        if (gp_rreq_fail)
                                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)
                        superio_select(GAMEPORT);
                        superio_outb(gpact, ACTREG);
                }
+               set_bit(WDTS_USE_CIR, &wdt_status);
        }
 
        if (timeout < 1 || timeout > max_units * 60) {
@@ -707,7 +722,7 @@ static int __init it87_wdt_init(void)
        }
 
        /* Initialize CIR to use it as keepalive source */
-       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+       if (test_bit(WDTS_USE_CIR, &wdt_status)) {
                outb(0x00, CIR_RCR(base));
                outb(0xc0, CIR_TCR1(base));
                outb(0x5c, CIR_TCR2(base));
@@ -717,9 +732,9 @@ static int __init it87_wdt_init(void)
                outb(0x09, CIR_IER(base));
        }
 
-       pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d)\n",
+       pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d nocir=%d)\n",
                chip_type, chip_rev, timeout,
-               nowayout, testmode, exclusive, nogameport);
+               nowayout, testmode, exclusive, nogameport, nocir);
 
        superio_exit();
        return 0;
@@ -727,8 +742,10 @@ static int __init it87_wdt_init(void)
 err_out_reboot:
        unregister_reboot_notifier(&wdt_notifier);
 err_out_region:
-       release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
-       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+       if (test_bit(WDTS_USE_GP, &wdt_status))
+               release_region(base, 1);
+       else if (test_bit(WDTS_USE_CIR, &wdt_status)) {
+               release_region(base, 8);
                superio_select(CIR);
                superio_outb(ciract, ACTREG);
        }
@@ -754,7 +771,7 @@ static void __exit it87_wdt_exit(void)
                if (test_bit(WDTS_USE_GP, &wdt_status)) {
                        superio_select(GAMEPORT);
                        superio_outb(gpact, ACTREG);
-               } else {
+               } else if (test_bit(WDTS_USE_CIR, &wdt_status)) {
                        superio_select(CIR);
                        superio_outb(ciract, ACTREG);
                }
@@ -763,7 +780,11 @@ static void __exit it87_wdt_exit(void)
 
        misc_deregister(&wdt_miscdev);
        unregister_reboot_notifier(&wdt_notifier);
-       release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+
+       if (test_bit(WDTS_USE_GP, &wdt_status))
+               release_region(base, 1);
+       else if (test_bit(WDTS_USE_CIR, &wdt_status))
+               release_region(base, 8);
 }
 
 module_init(it87_wdt_init);