Commit 7cd5b08b authored by Wim Van Sebroeck's avatar Wim Van Sebroeck

[WATCHDOG] iTCO_wdt : problem with rebooting on new ICH9 based motherboards

Bugzilla #9868: On Intel motherboards with the ICH9 based I/O controllers
(Like DP35DP and DG33FB) the iTCO timer counts but it doesn't reboot the
system after the counter expires.

This patch fixes this by moving the enabling & disabling of the TCO_EN bit
in the SMI_EN register into the start and stop code.
Signed-off-by: default avatarWim Van Sebroeck <wim@iguana.be>
parent f80e919b
/* /*
* intel TCO vendor specific watchdog driver support * intel TCO vendor specific watchdog driver support
* *
* (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>. * (c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>.
* *
* 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
...@@ -19,8 +19,7 @@ ...@@ -19,8 +19,7 @@
/* Module and version information */ /* Module and version information */
#define DRV_NAME "iTCO_vendor_support" #define DRV_NAME "iTCO_vendor_support"
#define DRV_VERSION "1.01" #define DRV_VERSION "1.02"
#define DRV_RELDATE "11-Nov-2006"
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
/* Includes */ /* Includes */
...@@ -78,24 +77,6 @@ MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (n ...@@ -78,24 +77,6 @@ MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (n
* 20.6 seconds. * 20.6 seconds.
*/ */
static void supermicro_old_pre_start(unsigned long acpibase)
{
unsigned long val32;
val32 = inl(SMI_EN);
val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
outl(val32, SMI_EN); /* Needed to activate watchdog */
}
static void supermicro_old_pre_stop(unsigned long acpibase)
{
unsigned long val32;
val32 = inl(SMI_EN);
val32 &= 0x00002000; /* Turn on SMI clearing watchdog */
outl(val32, SMI_EN); /* Needed to deactivate watchdog */
}
static void supermicro_old_pre_keepalive(unsigned long acpibase) static void supermicro_old_pre_keepalive(unsigned long acpibase)
{ {
/* Reload TCO Timer (done in iTCO_wdt_keepalive) + */ /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
...@@ -247,18 +228,14 @@ static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat) ...@@ -247,18 +228,14 @@ static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
void iTCO_vendor_pre_start(unsigned long acpibase, void iTCO_vendor_pre_start(unsigned long acpibase,
unsigned int heartbeat) unsigned int heartbeat)
{ {
if (vendorsupport == SUPERMICRO_OLD_BOARD) if (vendorsupport == SUPERMICRO_NEW_BOARD)
supermicro_old_pre_start(acpibase);
else if (vendorsupport == SUPERMICRO_NEW_BOARD)
supermicro_new_pre_start(heartbeat); supermicro_new_pre_start(heartbeat);
} }
EXPORT_SYMBOL(iTCO_vendor_pre_start); EXPORT_SYMBOL(iTCO_vendor_pre_start);
void iTCO_vendor_pre_stop(unsigned long acpibase) void iTCO_vendor_pre_stop(unsigned long acpibase)
{ {
if (vendorsupport == SUPERMICRO_OLD_BOARD) if (vendorsupport == SUPERMICRO_NEW_BOARD)
supermicro_old_pre_stop(acpibase);
else if (vendorsupport == SUPERMICRO_NEW_BOARD)
supermicro_new_pre_stop(); supermicro_new_pre_stop();
} }
EXPORT_SYMBOL(iTCO_vendor_pre_stop); EXPORT_SYMBOL(iTCO_vendor_pre_stop);
......
/* /*
* intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets) * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
* *
* (c) Copyright 2006-2007 Wim Van Sebroeck <wim@iguana.be>. * (c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>.
* *
* 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
...@@ -56,8 +56,7 @@ ...@@ -56,8 +56,7 @@
/* Module and version information */ /* Module and version information */
#define DRV_NAME "iTCO_wdt" #define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.03" #define DRV_VERSION "1.04"
#define DRV_RELDATE "30-Apr-2008"
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
/* Includes */ /* Includes */
...@@ -311,6 +310,7 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void) ...@@ -311,6 +310,7 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void)
static int iTCO_wdt_start(void) static int iTCO_wdt_start(void)
{ {
unsigned int val; unsigned int val;
unsigned long val32;
spin_lock(&iTCO_wdt_private.io_lock); spin_lock(&iTCO_wdt_private.io_lock);
...@@ -323,6 +323,18 @@ static int iTCO_wdt_start(void) ...@@ -323,6 +323,18 @@ static int iTCO_wdt_start(void)
return -EIO; return -EIO;
} }
/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
val32 = inl(SMI_EN);
val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
outl(val32, SMI_EN);
/* Force the timer to its reload value by writing to the TCO_RLD
register */
if (iTCO_wdt_private.iTCO_version == 2)
outw(0x01, TCO_RLD);
else if (iTCO_wdt_private.iTCO_version == 1)
outb(0x01, TCO_RLD);
/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
val = inw(TCO1_CNT); val = inw(TCO1_CNT);
val &= 0xf7ff; val &= 0xf7ff;
...@@ -338,6 +350,7 @@ static int iTCO_wdt_start(void) ...@@ -338,6 +350,7 @@ static int iTCO_wdt_start(void)
static int iTCO_wdt_stop(void) static int iTCO_wdt_stop(void)
{ {
unsigned int val; unsigned int val;
unsigned long val32;
spin_lock(&iTCO_wdt_private.io_lock); spin_lock(&iTCO_wdt_private.io_lock);
...@@ -349,6 +362,11 @@ static int iTCO_wdt_stop(void) ...@@ -349,6 +362,11 @@ static int iTCO_wdt_stop(void)
outw(val, TCO1_CNT); outw(val, TCO1_CNT);
val = inw(TCO1_CNT); val = inw(TCO1_CNT);
/* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
val32 = inl(SMI_EN);
val32 &= 0x00002000;
outl(val32, SMI_EN);
/* Set the NO_REBOOT bit to prevent later reboots, just for sure */ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
iTCO_wdt_set_NO_REBOOT_bit(); iTCO_wdt_set_NO_REBOOT_bit();
...@@ -459,7 +477,6 @@ static int iTCO_wdt_open(struct inode *inode, struct file *file) ...@@ -459,7 +477,6 @@ static int iTCO_wdt_open(struct inode *inode, struct file *file)
/* /*
* Reload and activate timer * Reload and activate timer
*/ */
iTCO_wdt_keepalive();
iTCO_wdt_start(); iTCO_wdt_start();
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -604,7 +621,6 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, ...@@ -604,7 +621,6 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
int ret; int ret;
u32 base_address; u32 base_address;
unsigned long RCBA; unsigned long RCBA;
unsigned long val32;
/* /*
* Find the ACPI/PM base I/O address which is the base * Find the ACPI/PM base I/O address which is the base
...@@ -644,17 +660,13 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, ...@@ -644,17 +660,13 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
/* Set the NO_REBOOT bit to prevent later reboots, just for sure */ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
iTCO_wdt_set_NO_REBOOT_bit(); iTCO_wdt_set_NO_REBOOT_bit();
/* Set the TCO_EN bit in SMI_EN register */ /* The TCO logic uses the TCO_EN bit in the SMI_EN register */
if (!request_region(SMI_EN, 4, "iTCO_wdt")) { if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"I/O address 0x%04lx already in use\n", SMI_EN); "I/O address 0x%04lx already in use\n", SMI_EN);
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
val32 = inl(SMI_EN);
val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
outl(val32, SMI_EN);
release_region(SMI_EN, 4);
/* The TCO I/O registers reside in a 32-byte range pointed to /* The TCO I/O registers reside in a 32-byte range pointed to
by the TCOBASE value */ by the TCOBASE value */
...@@ -662,7 +674,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, ...@@ -662,7 +674,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
TCOBASE); TCOBASE);
ret = -EIO; ret = -EIO;
goto out; goto unreg_smi_en;
} }
printk(KERN_INFO PFX printk(KERN_INFO PFX
...@@ -701,6 +713,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, ...@@ -701,6 +713,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
unreg_region: unreg_region:
release_region(TCOBASE, 0x20); release_region(TCOBASE, 0x20);
unreg_smi_en:
release_region(SMI_EN, 4);
out: out:
if (iTCO_wdt_private.iTCO_version == 2) if (iTCO_wdt_private.iTCO_version == 2)
iounmap(iTCO_wdt_private.gcs); iounmap(iTCO_wdt_private.gcs);
...@@ -718,6 +732,7 @@ static void __devexit iTCO_wdt_cleanup(void) ...@@ -718,6 +732,7 @@ static void __devexit iTCO_wdt_cleanup(void)
/* Deregister */ /* Deregister */
misc_deregister(&iTCO_wdt_miscdev); misc_deregister(&iTCO_wdt_miscdev);
release_region(TCOBASE, 0x20); release_region(TCOBASE, 0x20);
release_region(SMI_EN, 4);
if (iTCO_wdt_private.iTCO_version == 2) if (iTCO_wdt_private.iTCO_version == 2)
iounmap(iTCO_wdt_private.gcs); iounmap(iTCO_wdt_private.gcs);
pci_dev_put(iTCO_wdt_private.pdev); pci_dev_put(iTCO_wdt_private.pdev);
...@@ -782,8 +797,8 @@ static int __init iTCO_wdt_init_module(void) ...@@ -782,8 +797,8 @@ static int __init iTCO_wdt_init_module(void)
{ {
int err; int err;
printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s (%s)\n", printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
DRV_VERSION, DRV_RELDATE); DRV_VERSION);
err = platform_driver_register(&iTCO_wdt_driver); err = platform_driver_register(&iTCO_wdt_driver);
if (err) if (err)
......
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