Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+5 −5
Original line number Original line Diff line number Diff line
@@ -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.
+58 −23
Original line number Original line Diff line number Diff line
@@ -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 @@


/* 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 @@
#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)
	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)
		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)
	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)
 *	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)
{
{
	unsigned long flags;
	unsigned long flags;


	if (t < 1 || t > 65535)
	if (t < 1 || t > max_units * 60)
		return -EINVAL;
		return -EINVAL;


	if (t > max_units)
		timeout = wdt_round_time(t);
	else
		timeout = t;
		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)
	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)
	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)
		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)
		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)
	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);