Commit dfb0b8ea authored by Ondrej Zajicek's avatar Ondrej Zajicek Committed by Wim Van Sebroeck

watchdog: it87_wdt: Add support for watchdogs with 8b timers

This patch adds support for watchdogs with 8b timers, like ones in
IT8702F and older revisions of IT8712F Super IO chip, to it87_wdt
driver. This patch should be used after the patch
'it87_wdt: Add support for IT8720F watchdog'.
Signed-off-by: default avatarOndrej Zajicek <santiago@crfreenet.org>
Signed-off-by: default avatarWim Van Sebroeck <wim@iguana.be>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent ee3e9658
...@@ -565,11 +565,11 @@ config IT87_WDT ...@@ -565,11 +565,11 @@ config IT87_WDT
tristate "IT87 Watchdog Timer" tristate "IT87 Watchdog Timer"
depends on X86 && EXPERIMENTAL depends on X86 && EXPERIMENTAL
---help--- ---help---
This is the driver for the hardware watchdog on the ITE This is the driver for the hardware watchdog on the ITE IT8702,
IT8716, IT8718, IT8720, IT8726, IT8712(Version J,K) Super I/O IT8712, IT8716, IT8718, IT8720, IT8726, IT8712 Super I/O chips.
chips. This watchdog simply watches your kernel to make sure This watchdog simply watches your kernel to make sure it doesn't
it doesn't freeze, and if it does, it reboots your computer freeze, and if it does, it reboots your computer after a certain
after a certain amount of time. amount of time.
To compile this driver as a module, choose M here: the module will To compile this driver as a module, choose M here: the module will
be called it87_wdt. be called it87_wdt.
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* http://www.ite.com.tw/ * http://www.ite.com.tw/
* *
* Support of the watchdog timers, which are available on * Support of the watchdog timers, which are available on
* IT8716, IT8718, IT8720, IT8726 and IT8712 (J,K version). * IT8702, IT8712, IT8716, IT8718, IT8720 and IT8726.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
/* Chip Id numbers */ /* Chip Id numbers */
#define NO_DEV_ID 0xffff #define NO_DEV_ID 0xffff
#define IT8702_ID 0x8702
#define IT8705_ID 0x8705 #define IT8705_ID 0x8705
#define IT8712_ID 0x8712 #define IT8712_ID 0x8712
#define IT8716_ID 0x8716 #define IT8716_ID 0x8716
...@@ -133,7 +134,7 @@ ...@@ -133,7 +134,7 @@
#define WDTS_USE_GP 4 #define WDTS_USE_GP 4
#define WDTS_EXPECTED 5 #define WDTS_EXPECTED 5
static unsigned int base, gpact, ciract; static unsigned int base, gpact, ciract, max_units;
static unsigned long wdt_status; static unsigned long wdt_status;
static DEFINE_SPINLOCK(spinlock); static DEFINE_SPINLOCK(spinlock);
...@@ -211,6 +212,33 @@ static inline void superio_outw(int val, int reg) ...@@ -211,6 +212,33 @@ static inline void superio_outw(int val, int reg)
outb(val, VAL); 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 */ /* watchdog timer handling */
static void wdt_keepalive(void) static void wdt_keepalive(void)
...@@ -235,12 +263,7 @@ static void wdt_start(void) ...@@ -235,12 +263,7 @@ static void wdt_start(void)
superio_outb(WDT_GAMEPORT, WDTCTRL); superio_outb(WDT_GAMEPORT, WDTCTRL);
else else
superio_outb(WDT_CIRINT, WDTCTRL); superio_outb(WDT_CIRINT, WDTCTRL);
if (!testmode) wdt_update_timeout();
superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG);
else
superio_outb(WDT_TOV1, WDTCFG);
superio_outb(timeout>>8, WDTVALMSB);
superio_outb(timeout, WDTVALLSB);
superio_exit(); superio_exit();
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
...@@ -256,8 +279,9 @@ static void wdt_stop(void) ...@@ -256,8 +279,9 @@ static void wdt_stop(void)
superio_select(GPIO); superio_select(GPIO);
superio_outb(0x00, WDTCTRL); superio_outb(0x00, WDTCTRL);
superio_outb(WDT_TOV1, WDTCFG); superio_outb(WDT_TOV1, WDTCFG);
superio_outb(0x00, WDTVALMSB);
superio_outb(0x00, WDTVALLSB); superio_outb(0x00, WDTVALLSB);
if (max_units > 255)
superio_outb(0x00, WDTVALMSB);
superio_exit(); superio_exit();
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
...@@ -267,8 +291,8 @@ static void wdt_stop(void) ...@@ -267,8 +291,8 @@ static void wdt_stop(void)
* wdt_set_timeout - set a new timeout value with watchdog ioctl * wdt_set_timeout - set a new timeout value with watchdog ioctl
* @t: timeout value in seconds * @t: timeout value in seconds
* *
* The hardware device has a 16 bit watchdog timer, thus the * The hardware device has a 8 or 16 bit watchdog timer (depends on
* timeout time ranges between 1 and 65535 seconds. * chip version) that can be configured to count seconds or minutes.
* *
* Used within WDIOC_SETTIMEOUT watchdog device ioctl. * Used within WDIOC_SETTIMEOUT watchdog device ioctl.
*/ */
...@@ -277,19 +301,19 @@ static int wdt_set_timeout(int t) ...@@ -277,19 +301,19 @@ static int wdt_set_timeout(int t)
{ {
unsigned long flags; unsigned long flags;
if (t < 1 || t > 65535) if (t < 1 || t > max_units * 60)
return -EINVAL; return -EINVAL;
timeout = t; if (t > max_units)
timeout = wdt_round_time(t);
else
timeout = t;
spin_lock_irqsave(&spinlock, flags); spin_lock_irqsave(&spinlock, flags);
if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
superio_enter(); superio_enter();
superio_select(GPIO); superio_select(GPIO);
superio_outb(t>>8, WDTVALMSB); wdt_update_timeout();
superio_outb(t, WDTVALLSB);
superio_exit(); superio_exit();
} }
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
...@@ -535,6 +559,8 @@ static int __init it87_wdt_init(void) ...@@ -535,6 +559,8 @@ static int __init it87_wdt_init(void)
u8 chip_rev; u8 chip_rev;
unsigned long flags; unsigned long flags;
wdt_status = 0;
spin_lock_irqsave(&spinlock, flags); spin_lock_irqsave(&spinlock, flags);
superio_enter(); superio_enter();
chip_type = superio_inw(CHIPID); chip_type = superio_inw(CHIPID);
...@@ -543,16 +569,21 @@ static int __init it87_wdt_init(void) ...@@ -543,16 +569,21 @@ static int __init it87_wdt_init(void)
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
switch (chip_type) { 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 IT8716_ID:
case IT8726_ID: case IT8726_ID:
max_units = 65535;
break; break;
case IT8718_ID: case IT8718_ID:
case IT8720_ID: case IT8720_ID:
max_units = 65535;
try_gameport = 0; try_gameport = 0;
break; break;
case IT8712_ID:
if (chip_rev > 7)
break;
case IT8705_ID: case IT8705_ID:
printk(KERN_ERR PFX printk(KERN_ERR PFX
"Unsupported Chip found, Chip %04x Revision %02x\n", "Unsupported Chip found, Chip %04x Revision %02x\n",
...@@ -628,13 +659,16 @@ static int __init it87_wdt_init(void) ...@@ -628,13 +659,16 @@ static int __init it87_wdt_init(void)
spin_unlock_irqrestore(&spinlock, flags); spin_unlock_irqrestore(&spinlock, flags);
} }
if (timeout < 1 || timeout > 65535) { if (timeout < 1 || timeout > max_units * 60) {
timeout = DEFAULT_TIMEOUT; timeout = DEFAULT_TIMEOUT;
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"Timeout value out of range, use default %d sec\n", "Timeout value out of range, use default %d sec\n",
DEFAULT_TIMEOUT); DEFAULT_TIMEOUT);
} }
if (timeout > max_units)
timeout = wdt_round_time(timeout);
rc = register_reboot_notifier(&wdt_notifier); rc = register_reboot_notifier(&wdt_notifier);
if (rc) { if (rc) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
...@@ -661,7 +695,7 @@ static int __init it87_wdt_init(void) ...@@ -661,7 +695,7 @@ static int __init it87_wdt_init(void)
outb(0x09, CIR_IER(base)); 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 " "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
"nogameport=%d)\n", chip_type, chip_rev, timeout, "nogameport=%d)\n", chip_type, chip_rev, timeout,
nowayout, testmode, exclusive, nogameport); nowayout, testmode, exclusive, nogameport);
...@@ -703,8 +737,9 @@ static void __exit it87_wdt_exit(void) ...@@ -703,8 +737,9 @@ static void __exit it87_wdt_exit(void)
superio_select(GPIO); superio_select(GPIO);
superio_outb(0x00, WDTCTRL); superio_outb(0x00, WDTCTRL);
superio_outb(0x00, WDTCFG); superio_outb(0x00, WDTCFG);
superio_outb(0x00, WDTVALMSB);
superio_outb(0x00, WDTVALLSB); superio_outb(0x00, WDTVALLSB);
if (max_units > 255)
superio_outb(0x00, WDTVALMSB);
if (test_bit(WDTS_USE_GP, &wdt_status)) { if (test_bit(WDTS_USE_GP, &wdt_status)) {
superio_select(GAMEPORT); superio_select(GAMEPORT);
superio_outb(gpact, ACTREG); superio_outb(gpact, ACTREG);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment