diff options
Diffstat (limited to 'drivers/watchdog/it87_wdt.c')
-rw-r--r-- | drivers/watchdog/it87_wdt.c | 96 |
1 files changed, 68 insertions, 28 deletions
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index b709b3b..dad2924 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -12,7 +12,7 @@ * http://www.ite.com.tw/ * * Support of the watchdog timers, which are available on - * IT8716, IT8718, IT8726 and IT8712 (J,K version). + * IT8702, IT8712, IT8716, IT8718, IT8720 and IT8726. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -45,7 +45,7 @@ #include <asm/system.h> -#define WATCHDOG_VERSION "1.12" +#define WATCHDOG_VERSION "1.13" #define WATCHDOG_NAME "IT87 WDT" #define PFX WATCHDOG_NAME ": " #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" @@ -76,10 +76,12 @@ /* Chip Id numbers */ #define NO_DEV_ID 0xffff +#define IT8702_ID 0x8702 #define IT8705_ID 0x8705 #define IT8712_ID 0x8712 #define IT8716_ID 0x8716 #define IT8718_ID 0x8718 +#define IT8720_ID 0x8720 #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ /* GPIO Configuration Registers LDN=0x07 */ @@ -92,7 +94,7 @@ #define WDT_CIRINT 0x80 #define WDT_MOUSEINT 0x40 #define WDT_KYBINT 0x20 -#define WDT_GAMEPORT 0x10 /* not it8718 */ +#define WDT_GAMEPORT 0x10 /* not in it8718, it8720 */ #define WDT_FORCE 0x02 #define WDT_ZERO 0x01 @@ -132,7 +134,7 @@ #define WDTS_USE_GP 4 #define WDTS_EXPECTED 5 -static unsigned int base, gpact, ciract; +static unsigned int base, gpact, ciract, max_units; static unsigned long wdt_status; static DEFINE_SPINLOCK(spinlock); @@ -210,6 +212,33 @@ static inline void superio_outw(int val, int reg) outb(val, VAL); } +/* Internal function, should be called after superio_select(GPIO) */ +static void wdt_update_timeout(void) +{ + unsigned char cfg = WDT_KRST | WDT_PWROK; + int tm = timeout; + + if (testmode) + cfg = 0; + + if (tm <= max_units) + cfg |= WDT_TOV1; + else + tm /= 60; + + superio_outb(cfg, WDTCFG); + superio_outb(tm, WDTVALLSB); + if (max_units > 255) + superio_outb(tm>>8, WDTVALMSB); +} + +static int wdt_round_time(int t) +{ + t += 59; + t -= t % 60; + return t; +} + /* watchdog timer handling */ static void wdt_keepalive(void) @@ -234,12 +263,7 @@ static void wdt_start(void) superio_outb(WDT_GAMEPORT, WDTCTRL); else superio_outb(WDT_CIRINT, WDTCTRL); - if (!testmode) - superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG); - else - superio_outb(WDT_TOV1, WDTCFG); - superio_outb(timeout>>8, WDTVALMSB); - superio_outb(timeout, WDTVALLSB); + wdt_update_timeout(); superio_exit(); spin_unlock_irqrestore(&spinlock, flags); @@ -255,8 +279,9 @@ static void wdt_stop(void) superio_select(GPIO); superio_outb(0x00, WDTCTRL); superio_outb(WDT_TOV1, WDTCFG); - superio_outb(0x00, WDTVALMSB); superio_outb(0x00, WDTVALLSB); + if (max_units > 255) + superio_outb(0x00, WDTVALMSB); superio_exit(); spin_unlock_irqrestore(&spinlock, flags); @@ -266,8 +291,8 @@ static void wdt_stop(void) * wdt_set_timeout - set a new timeout value with watchdog ioctl * @t: timeout value in seconds * - * The hardware device has a 16 bit watchdog timer, thus the - * timeout time ranges between 1 and 65535 seconds. + * The hardware device has a 8 or 16 bit watchdog timer (depends on + * chip version) that can be configured to count seconds or minutes. * * Used within WDIOC_SETTIMEOUT watchdog device ioctl. */ @@ -276,19 +301,19 @@ static int wdt_set_timeout(int t) { unsigned long flags; - if (t < 1 || t > 65535) + if (t < 1 || t > max_units * 60) return -EINVAL; - timeout = t; + if (t > max_units) + timeout = wdt_round_time(t); + else + timeout = t; spin_lock_irqsave(&spinlock, flags); if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { superio_enter(); - superio_select(GPIO); - superio_outb(t>>8, WDTVALMSB); - superio_outb(t, WDTVALLSB); - + wdt_update_timeout(); superio_exit(); } spin_unlock_irqrestore(&spinlock, flags); @@ -529,10 +554,13 @@ static struct notifier_block wdt_notifier = { static int __init it87_wdt_init(void) { int rc = 0; + int try_gameport = !nogameport; u16 chip_type; u8 chip_rev; unsigned long flags; + wdt_status = 0; + spin_lock_irqsave(&spinlock, flags); superio_enter(); chip_type = superio_inw(CHIPID); @@ -541,13 +569,21 @@ static int __init it87_wdt_init(void) spin_unlock_irqrestore(&spinlock, flags); switch (chip_type) { + case IT8702_ID: + max_units = 255; + break; + case IT8712_ID: + max_units = (chip_rev < 8) ? 255 : 65535; + break; case IT8716_ID: - case IT8718_ID: case IT8726_ID: + max_units = 65535; + break; + case IT8718_ID: + case IT8720_ID: + max_units = 65535; + try_gameport = 0; break; - case IT8712_ID: - if (chip_rev > 7) - break; case IT8705_ID: printk(KERN_ERR PFX "Unsupported Chip found, Chip %04x Revision %02x\n", @@ -571,7 +607,7 @@ static int __init it87_wdt_init(void) superio_outb(0x00, WDTCTRL); /* First try to get Gameport support */ - if (chip_type != IT8718_ID && !nogameport) { + if (try_gameport) { superio_select(GAMEPORT); base = superio_inw(BASEREG); if (!base) { @@ -623,13 +659,16 @@ static int __init it87_wdt_init(void) spin_unlock_irqrestore(&spinlock, flags); } - if (timeout < 1 || timeout > 65535) { + if (timeout < 1 || timeout > max_units * 60) { timeout = DEFAULT_TIMEOUT; printk(KERN_WARNING PFX "Timeout value out of range, use default %d sec\n", DEFAULT_TIMEOUT); } + if (timeout > max_units) + timeout = wdt_round_time(timeout); + rc = register_reboot_notifier(&wdt_notifier); if (rc) { printk(KERN_ERR PFX @@ -656,7 +695,7 @@ static int __init it87_wdt_init(void) outb(0x09, CIR_IER(base)); } - printk(KERN_INFO PFX "Chip it%04x revision %d initialized. " + printk(KERN_INFO PFX "Chip IT%04x revision %d initialized. " "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d " "nogameport=%d)\n", chip_type, chip_rev, timeout, nowayout, testmode, exclusive, nogameport); @@ -676,7 +715,7 @@ err_out_region: spin_unlock_irqrestore(&spinlock, flags); } err_out: - if (chip_type != IT8718_ID && !nogameport) { + if (try_gameport) { spin_lock_irqsave(&spinlock, flags); superio_enter(); superio_select(GAMEPORT); @@ -698,8 +737,9 @@ static void __exit it87_wdt_exit(void) superio_select(GPIO); superio_outb(0x00, WDTCTRL); superio_outb(0x00, WDTCFG); - superio_outb(0x00, WDTVALMSB); superio_outb(0x00, WDTVALLSB); + if (max_units > 255) + superio_outb(0x00, WDTVALMSB); if (test_bit(WDTS_USE_GP, &wdt_status)) { superio_select(GAMEPORT); superio_outb(gpact, ACTREG); |