From 01df0e3a79d3913df178e9a1047ade425a7c118f Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Tue, 9 Aug 2005 10:07:56 -0700 Subject: [PATCH] [PATCH] i8xx_tco.c: arm watchdog only when started i8xx_tco.c v0.08: only "arm" the watchdog when the watchdog has been started. (Kernel Bug 4251: system reset when battery is read and i8xx_tco driver loaded) Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/watchdog/i8xx_tco.c | 41 ++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index f975dab1ddf9..a13395e2c372 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c @@ -1,5 +1,5 @@ /* - * i8xx_tco 0.07: TCO timer driver for i8xx chipsets + * i8xx_tco: TCO timer driver for i8xx chipsets * * (c) Copyright 2000 kernel concepts , All Rights Reserved. * http://www.kernelconcepts.de @@ -63,6 +63,9 @@ * 20050128 Wim Van Sebroeck * 0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW * chipsets. Also added support for the "undocumented" ICH7 chipset. + * 20050807 Wim Van Sebroeck + * 0.08 Make sure that the watchdog is only "armed" when started. + * (Kernel Bug 4251) */ /* @@ -87,7 +90,7 @@ #include "i8xx_tco.h" /* Module and version information */ -#define TCO_VERSION "0.07" +#define TCO_VERSION "0.08" #define TCO_MODULE_NAME "i8xx TCO timer" #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION #define PFX TCO_MODULE_NAME ": " @@ -125,10 +128,18 @@ static int tco_timer_start (void) unsigned char val; spin_lock(&tco_lock); + + /* disable chipset's NO_REBOOT bit */ + pci_read_config_byte (i8xx_tco_pci, 0xd4, &val); + val &= 0xfd; + pci_write_config_byte (i8xx_tco_pci, 0xd4, val); + + /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ val = inb (TCO1_CNT + 1); val &= 0xf7; outb (val, TCO1_CNT + 1); val = inb (TCO1_CNT + 1); + spin_unlock(&tco_lock); if (val & 0x08) @@ -138,13 +149,20 @@ static int tco_timer_start (void) static int tco_timer_stop (void) { - unsigned char val; + unsigned char val, val1; spin_lock(&tco_lock); + /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ val = inb (TCO1_CNT + 1); val |= 0x08; outb (val, TCO1_CNT + 1); val = inb (TCO1_CNT + 1); + + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); + val1 |= 0x02; + pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); + spin_unlock(&tco_lock); if ((val & 0x08) == 0) @@ -155,6 +173,7 @@ static int tco_timer_stop (void) static int tco_timer_keepalive (void) { spin_lock(&tco_lock); + /* Reload the timer by writing to the TCO Timer Reload register */ outb (0x01, TCO1_RLD); spin_unlock(&tco_lock); return 0; @@ -417,9 +436,8 @@ static unsigned char __init i8xx_tco_getdevice (void) printk (KERN_ERR PFX "failed to get TCOBASE address\n"); return 0; } - /* - * Check chipset's NO_REBOOT bit - */ + + /* Check chipset's NO_REBOOT bit */ pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); if (val1 & 0x02) { val1 &= 0xfd; @@ -430,6 +448,10 @@ static unsigned char __init i8xx_tco_getdevice (void) return 0; /* Cannot reset NO_REBOOT bit */ } } + /* Disable reboots untill the watchdog starts */ + val1 |= 0x02; + pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); + /* Set the TCO_EN bit in SMI_EN register */ if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) { printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", @@ -505,17 +527,10 @@ out: static void __exit watchdog_cleanup (void) { - u8 val; - /* Stop the timer before we leave */ if (!nowayout) tco_timer_stop (); - /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - pci_read_config_byte (i8xx_tco_pci, 0xd4, &val); - val |= 0x02; - pci_write_config_byte (i8xx_tco_pci, 0xd4, val); - /* Deregister */ misc_deregister (&i8xx_tco_miscdev); unregister_reboot_notifier(&i8xx_tco_notifier);