diff options
| author | Wim Van Sebroeck <wim@iguana.be> | 2008-11-19 14:39:58 -0500 |
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2008-11-21 03:34:26 -0500 |
| commit | 7cd5b08be3c489df11b559fef210b81133764ad4 (patch) | |
| tree | a52a6549b847945f7743ca5272221317aa37efe2 | |
| parent | f80e919bb42c191bbe60ab078a59b30336d11d3b (diff) | |
[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: Wim Van Sebroeck <wim@iguana.be>
| -rw-r--r-- | drivers/watchdog/iTCO_vendor_support.c | 31 | ||||
| -rw-r--r-- | drivers/watchdog/iTCO_wdt.c | 41 |
2 files changed, 32 insertions, 40 deletions
diff --git a/drivers/watchdog/iTCO_vendor_support.c b/drivers/watchdog/iTCO_vendor_support.c index ca344a85eb9..2474ebca88f 100644 --- a/drivers/watchdog/iTCO_vendor_support.c +++ b/drivers/watchdog/iTCO_vendor_support.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * intel TCO vendor specific watchdog driver support | 2 | * intel TCO vendor specific watchdog driver support |
| 3 | * | 3 | * |
| 4 | * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>. | 4 | * (c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>. |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
| @@ -19,8 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | /* Module and version information */ | 20 | /* Module and version information */ |
| 21 | #define DRV_NAME "iTCO_vendor_support" | 21 | #define DRV_NAME "iTCO_vendor_support" |
| 22 | #define DRV_VERSION "1.01" | 22 | #define DRV_VERSION "1.02" |
| 23 | #define DRV_RELDATE "11-Nov-2006" | ||
| 24 | #define PFX DRV_NAME ": " | 23 | #define PFX DRV_NAME ": " |
| 25 | 24 | ||
| 26 | /* Includes */ | 25 | /* Includes */ |
| @@ -78,24 +77,6 @@ MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (n | |||
| 78 | * 20.6 seconds. | 77 | * 20.6 seconds. |
| 79 | */ | 78 | */ |
| 80 | 79 | ||
| 81 | static void supermicro_old_pre_start(unsigned long acpibase) | ||
| 82 | { | ||
| 83 | unsigned long val32; | ||
| 84 | |||
| 85 | val32 = inl(SMI_EN); | ||
| 86 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ | ||
| 87 | outl(val32, SMI_EN); /* Needed to activate watchdog */ | ||
| 88 | } | ||
| 89 | |||
| 90 | static void supermicro_old_pre_stop(unsigned long acpibase) | ||
| 91 | { | ||
| 92 | unsigned long val32; | ||
| 93 | |||
| 94 | val32 = inl(SMI_EN); | ||
| 95 | val32 &= 0x00002000; /* Turn on SMI clearing watchdog */ | ||
| 96 | outl(val32, SMI_EN); /* Needed to deactivate watchdog */ | ||
| 97 | } | ||
| 98 | |||
| 99 | static void supermicro_old_pre_keepalive(unsigned long acpibase) | 80 | static void supermicro_old_pre_keepalive(unsigned long acpibase) |
| 100 | { | 81 | { |
| 101 | /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */ | 82 | /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */ |
| @@ -247,18 +228,14 @@ static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat) | |||
| 247 | void iTCO_vendor_pre_start(unsigned long acpibase, | 228 | void iTCO_vendor_pre_start(unsigned long acpibase, |
| 248 | unsigned int heartbeat) | 229 | unsigned int heartbeat) |
| 249 | { | 230 | { |
| 250 | if (vendorsupport == SUPERMICRO_OLD_BOARD) | 231 | if (vendorsupport == SUPERMICRO_NEW_BOARD) |
| 251 | supermicro_old_pre_start(acpibase); | ||
| 252 | else if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
| 253 | supermicro_new_pre_start(heartbeat); | 232 | supermicro_new_pre_start(heartbeat); |
| 254 | } | 233 | } |
| 255 | EXPORT_SYMBOL(iTCO_vendor_pre_start); | 234 | EXPORT_SYMBOL(iTCO_vendor_pre_start); |
| 256 | 235 | ||
| 257 | void iTCO_vendor_pre_stop(unsigned long acpibase) | 236 | void iTCO_vendor_pre_stop(unsigned long acpibase) |
| 258 | { | 237 | { |
| 259 | if (vendorsupport == SUPERMICRO_OLD_BOARD) | 238 | if (vendorsupport == SUPERMICRO_NEW_BOARD) |
| 260 | supermicro_old_pre_stop(acpibase); | ||
| 261 | else if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
| 262 | supermicro_new_pre_stop(); | 239 | supermicro_new_pre_stop(); |
| 263 | } | 240 | } |
| 264 | EXPORT_SYMBOL(iTCO_vendor_pre_stop); | 241 | EXPORT_SYMBOL(iTCO_vendor_pre_stop); |
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index bfb93bc2ca9..75483000a87 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets) | 2 | * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets) |
| 3 | * | 3 | * |
| 4 | * (c) Copyright 2006-2007 Wim Van Sebroeck <wim@iguana.be>. | 4 | * (c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>. |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
| @@ -56,8 +56,7 @@ | |||
| 56 | 56 | ||
| 57 | /* Module and version information */ | 57 | /* Module and version information */ |
| 58 | #define DRV_NAME "iTCO_wdt" | 58 | #define DRV_NAME "iTCO_wdt" |
| 59 | #define DRV_VERSION "1.03" | 59 | #define DRV_VERSION "1.04" |
| 60 | #define DRV_RELDATE "30-Apr-2008" | ||
| 61 | #define PFX DRV_NAME ": " | 60 | #define PFX DRV_NAME ": " |
| 62 | 61 | ||
| 63 | /* Includes */ | 62 | /* Includes */ |
| @@ -311,6 +310,7 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void) | |||
| 311 | static int iTCO_wdt_start(void) | 310 | static int iTCO_wdt_start(void) |
| 312 | { | 311 | { |
| 313 | unsigned int val; | 312 | unsigned int val; |
| 313 | unsigned long val32; | ||
| 314 | 314 | ||
| 315 | spin_lock(&iTCO_wdt_private.io_lock); | 315 | spin_lock(&iTCO_wdt_private.io_lock); |
| 316 | 316 | ||
| @@ -323,6 +323,18 @@ static int iTCO_wdt_start(void) | |||
| 323 | return -EIO; | 323 | return -EIO; |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ | ||
| 327 | val32 = inl(SMI_EN); | ||
| 328 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ | ||
| 329 | outl(val32, SMI_EN); | ||
| 330 | |||
| 331 | /* Force the timer to its reload value by writing to the TCO_RLD | ||
| 332 | register */ | ||
| 333 | if (iTCO_wdt_private.iTCO_version == 2) | ||
| 334 | outw(0x01, TCO_RLD); | ||
| 335 | else if (iTCO_wdt_private.iTCO_version == 1) | ||
| 336 | outb(0x01, TCO_RLD); | ||
| 337 | |||
| 326 | /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ | 338 | /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ |
| 327 | val = inw(TCO1_CNT); | 339 | val = inw(TCO1_CNT); |
| 328 | val &= 0xf7ff; | 340 | val &= 0xf7ff; |
| @@ -338,6 +350,7 @@ static int iTCO_wdt_start(void) | |||
| 338 | static int iTCO_wdt_stop(void) | 350 | static int iTCO_wdt_stop(void) |
| 339 | { | 351 | { |
| 340 | unsigned int val; | 352 | unsigned int val; |
| 353 | unsigned long val32; | ||
| 341 | 354 | ||
| 342 | spin_lock(&iTCO_wdt_private.io_lock); | 355 | spin_lock(&iTCO_wdt_private.io_lock); |
| 343 | 356 | ||
| @@ -349,6 +362,11 @@ static int iTCO_wdt_stop(void) | |||
| 349 | outw(val, TCO1_CNT); | 362 | outw(val, TCO1_CNT); |
| 350 | val = inw(TCO1_CNT); | 363 | val = inw(TCO1_CNT); |
| 351 | 364 | ||
| 365 | /* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */ | ||
| 366 | val32 = inl(SMI_EN); | ||
| 367 | val32 &= 0x00002000; | ||
| 368 | outl(val32, SMI_EN); | ||
| 369 | |||
| 352 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | 370 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ |
| 353 | iTCO_wdt_set_NO_REBOOT_bit(); | 371 | iTCO_wdt_set_NO_REBOOT_bit(); |
| 354 | 372 | ||
| @@ -459,7 +477,6 @@ static int iTCO_wdt_open(struct inode *inode, struct file *file) | |||
| 459 | /* | 477 | /* |
| 460 | * Reload and activate timer | 478 | * Reload and activate timer |
| 461 | */ | 479 | */ |
| 462 | iTCO_wdt_keepalive(); | ||
| 463 | iTCO_wdt_start(); | 480 | iTCO_wdt_start(); |
| 464 | return nonseekable_open(inode, file); | 481 | return nonseekable_open(inode, file); |
| 465 | } | 482 | } |
| @@ -604,7 +621,6 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, | |||
| 604 | int ret; | 621 | int ret; |
| 605 | u32 base_address; | 622 | u32 base_address; |
| 606 | unsigned long RCBA; | 623 | unsigned long RCBA; |
| 607 | unsigned long val32; | ||
| 608 | 624 | ||
| 609 | /* | 625 | /* |
| 610 | * Find the ACPI/PM base I/O address which is the base | 626 | * 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 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | 660 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ |
| 645 | iTCO_wdt_set_NO_REBOOT_bit(); | 661 | iTCO_wdt_set_NO_REBOOT_bit(); |
| 646 | 662 | ||
| 647 | /* Set the TCO_EN bit in SMI_EN register */ | 663 | /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ |
| 648 | if (!request_region(SMI_EN, 4, "iTCO_wdt")) { | 664 | if (!request_region(SMI_EN, 4, "iTCO_wdt")) { |
| 649 | printk(KERN_ERR PFX | 665 | printk(KERN_ERR PFX |
| 650 | "I/O address 0x%04lx already in use\n", SMI_EN); | 666 | "I/O address 0x%04lx already in use\n", SMI_EN); |
| 651 | ret = -EIO; | 667 | ret = -EIO; |
| 652 | goto out; | 668 | goto out; |
| 653 | } | 669 | } |
| 654 | val32 = inl(SMI_EN); | ||
| 655 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ | ||
| 656 | outl(val32, SMI_EN); | ||
| 657 | release_region(SMI_EN, 4); | ||
| 658 | 670 | ||
| 659 | /* The TCO I/O registers reside in a 32-byte range pointed to | 671 | /* The TCO I/O registers reside in a 32-byte range pointed to |
| 660 | by the TCOBASE value */ | 672 | by the TCOBASE value */ |
| @@ -662,7 +674,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, | |||
| 662 | printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", | 674 | printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", |
| 663 | TCOBASE); | 675 | TCOBASE); |
| 664 | ret = -EIO; | 676 | ret = -EIO; |
| 665 | goto out; | 677 | goto unreg_smi_en; |
| 666 | } | 678 | } |
| 667 | 679 | ||
| 668 | printk(KERN_INFO PFX | 680 | printk(KERN_INFO PFX |
| @@ -701,6 +713,8 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, | |||
| 701 | 713 | ||
| 702 | unreg_region: | 714 | unreg_region: |
| 703 | release_region(TCOBASE, 0x20); | 715 | release_region(TCOBASE, 0x20); |
| 716 | unreg_smi_en: | ||
| 717 | release_region(SMI_EN, 4); | ||
| 704 | out: | 718 | out: |
| 705 | if (iTCO_wdt_private.iTCO_version == 2) | 719 | if (iTCO_wdt_private.iTCO_version == 2) |
| 706 | iounmap(iTCO_wdt_private.gcs); | 720 | iounmap(iTCO_wdt_private.gcs); |
| @@ -718,6 +732,7 @@ static void __devexit iTCO_wdt_cleanup(void) | |||
| 718 | /* Deregister */ | 732 | /* Deregister */ |
| 719 | misc_deregister(&iTCO_wdt_miscdev); | 733 | misc_deregister(&iTCO_wdt_miscdev); |
| 720 | release_region(TCOBASE, 0x20); | 734 | release_region(TCOBASE, 0x20); |
| 735 | release_region(SMI_EN, 4); | ||
| 721 | if (iTCO_wdt_private.iTCO_version == 2) | 736 | if (iTCO_wdt_private.iTCO_version == 2) |
| 722 | iounmap(iTCO_wdt_private.gcs); | 737 | iounmap(iTCO_wdt_private.gcs); |
| 723 | pci_dev_put(iTCO_wdt_private.pdev); | 738 | pci_dev_put(iTCO_wdt_private.pdev); |
| @@ -782,8 +797,8 @@ static int __init iTCO_wdt_init_module(void) | |||
| 782 | { | 797 | { |
| 783 | int err; | 798 | int err; |
| 784 | 799 | ||
| 785 | printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s (%s)\n", | 800 | printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n", |
| 786 | DRV_VERSION, DRV_RELDATE); | 801 | DRV_VERSION); |
| 787 | 802 | ||
| 788 | err = platform_driver_register(&iTCO_wdt_driver); | 803 | err = platform_driver_register(&iTCO_wdt_driver); |
| 789 | if (err) | 804 | if (err) |
