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 /drivers/watchdog | |
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>
Diffstat (limited to 'drivers/watchdog')
-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 ca344a85eb95..2474ebca88f6 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 bfb93bc2ca9f..75483000a87d 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) |