aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorWim Van Sebroeck <wim@iguana.be>2008-11-19 14:39:58 -0500
committerWim Van Sebroeck <wim@iguana.be>2008-11-21 03:34:26 -0500
commit7cd5b08be3c489df11b559fef210b81133764ad4 (patch)
treea52a6549b847945f7743ca5272221317aa37efe2 /drivers/watchdog
parentf80e919bb42c191bbe60ab078a59b30336d11d3b (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.c31
-rw-r--r--drivers/watchdog/iTCO_wdt.c41
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
81static 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
90static 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
99static void supermicro_old_pre_keepalive(unsigned long acpibase) 80static 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)
247void iTCO_vendor_pre_start(unsigned long acpibase, 228void 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}
255EXPORT_SYMBOL(iTCO_vendor_pre_start); 234EXPORT_SYMBOL(iTCO_vendor_pre_start);
256 235
257void iTCO_vendor_pre_stop(unsigned long acpibase) 236void 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}
264EXPORT_SYMBOL(iTCO_vendor_pre_stop); 241EXPORT_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)
311static int iTCO_wdt_start(void) 310static 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)
338static int iTCO_wdt_stop(void) 350static 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
702unreg_region: 714unreg_region:
703 release_region(TCOBASE, 0x20); 715 release_region(TCOBASE, 0x20);
716unreg_smi_en:
717 release_region(SMI_EN, 4);
704out: 718out:
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)