|
@@ -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 <nils@kernelconcepts.de>, All Rights Reserved.
|
|
|
* http://www.kernelconcepts.de
|
|
@@ -63,6 +63,9 @@
|
|
|
* 20050128 Wim Van Sebroeck <wim@iguana.be>
|
|
|
* 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 <wim@iguana.be>
|
|
|
+ * 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);
|