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/iTCO_wdt.c | |
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/iTCO_wdt.c')
-rw-r--r-- | drivers/watchdog/iTCO_wdt.c | 41 |
1 files changed, 28 insertions, 13 deletions
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) |