diff options
author | Wim Van Sebroeck <wim@iguana.be> | 2005-08-09 13:07:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-08-09 15:08:21 -0400 |
commit | 01df0e3a79d3913df178e9a1047ade425a7c118f (patch) | |
tree | 8e2640f616d6611cd32e8b6117d839b94ba5af6b /drivers/char | |
parent | 00dd1e433967872f3997a45d5adf35056fdf2f56 (diff) |
[PATCH] i8xx_tco.c: arm watchdog only when started
i8xx_tco.c v0.08: only "arm" the watchdog when the watchdog has been
started. (Kernel Bug 4251: system reset when battery is read and i8xx_tco
driver loaded)
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/watchdog/i8xx_tco.c | 41 |
1 files changed, 28 insertions, 13 deletions
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index f975dab1ddf9..a13395e2c372 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * i8xx_tco 0.07: TCO timer driver for i8xx chipsets | 2 | * i8xx_tco: TCO timer driver for i8xx chipsets |
3 | * | 3 | * |
4 | * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved. | 4 | * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved. |
5 | * http://www.kernelconcepts.de | 5 | * http://www.kernelconcepts.de |
@@ -63,6 +63,9 @@ | |||
63 | * 20050128 Wim Van Sebroeck <wim@iguana.be> | 63 | * 20050128 Wim Van Sebroeck <wim@iguana.be> |
64 | * 0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW | 64 | * 0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW |
65 | * chipsets. Also added support for the "undocumented" ICH7 chipset. | 65 | * chipsets. Also added support for the "undocumented" ICH7 chipset. |
66 | * 20050807 Wim Van Sebroeck <wim@iguana.be> | ||
67 | * 0.08 Make sure that the watchdog is only "armed" when started. | ||
68 | * (Kernel Bug 4251) | ||
66 | */ | 69 | */ |
67 | 70 | ||
68 | /* | 71 | /* |
@@ -87,7 +90,7 @@ | |||
87 | #include "i8xx_tco.h" | 90 | #include "i8xx_tco.h" |
88 | 91 | ||
89 | /* Module and version information */ | 92 | /* Module and version information */ |
90 | #define TCO_VERSION "0.07" | 93 | #define TCO_VERSION "0.08" |
91 | #define TCO_MODULE_NAME "i8xx TCO timer" | 94 | #define TCO_MODULE_NAME "i8xx TCO timer" |
92 | #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION | 95 | #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION |
93 | #define PFX TCO_MODULE_NAME ": " | 96 | #define PFX TCO_MODULE_NAME ": " |
@@ -125,10 +128,18 @@ static int tco_timer_start (void) | |||
125 | unsigned char val; | 128 | unsigned char val; |
126 | 129 | ||
127 | spin_lock(&tco_lock); | 130 | spin_lock(&tco_lock); |
131 | |||
132 | /* disable chipset's NO_REBOOT bit */ | ||
133 | pci_read_config_byte (i8xx_tco_pci, 0xd4, &val); | ||
134 | val &= 0xfd; | ||
135 | pci_write_config_byte (i8xx_tco_pci, 0xd4, val); | ||
136 | |||
137 | /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ | ||
128 | val = inb (TCO1_CNT + 1); | 138 | val = inb (TCO1_CNT + 1); |
129 | val &= 0xf7; | 139 | val &= 0xf7; |
130 | outb (val, TCO1_CNT + 1); | 140 | outb (val, TCO1_CNT + 1); |
131 | val = inb (TCO1_CNT + 1); | 141 | val = inb (TCO1_CNT + 1); |
142 | |||
132 | spin_unlock(&tco_lock); | 143 | spin_unlock(&tco_lock); |
133 | 144 | ||
134 | if (val & 0x08) | 145 | if (val & 0x08) |
@@ -138,13 +149,20 @@ static int tco_timer_start (void) | |||
138 | 149 | ||
139 | static int tco_timer_stop (void) | 150 | static int tco_timer_stop (void) |
140 | { | 151 | { |
141 | unsigned char val; | 152 | unsigned char val, val1; |
142 | 153 | ||
143 | spin_lock(&tco_lock); | 154 | spin_lock(&tco_lock); |
155 | /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ | ||
144 | val = inb (TCO1_CNT + 1); | 156 | val = inb (TCO1_CNT + 1); |
145 | val |= 0x08; | 157 | val |= 0x08; |
146 | outb (val, TCO1_CNT + 1); | 158 | outb (val, TCO1_CNT + 1); |
147 | val = inb (TCO1_CNT + 1); | 159 | val = inb (TCO1_CNT + 1); |
160 | |||
161 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | ||
162 | pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); | ||
163 | val1 |= 0x02; | ||
164 | pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); | ||
165 | |||
148 | spin_unlock(&tco_lock); | 166 | spin_unlock(&tco_lock); |
149 | 167 | ||
150 | if ((val & 0x08) == 0) | 168 | if ((val & 0x08) == 0) |
@@ -155,6 +173,7 @@ static int tco_timer_stop (void) | |||
155 | static int tco_timer_keepalive (void) | 173 | static int tco_timer_keepalive (void) |
156 | { | 174 | { |
157 | spin_lock(&tco_lock); | 175 | spin_lock(&tco_lock); |
176 | /* Reload the timer by writing to the TCO Timer Reload register */ | ||
158 | outb (0x01, TCO1_RLD); | 177 | outb (0x01, TCO1_RLD); |
159 | spin_unlock(&tco_lock); | 178 | spin_unlock(&tco_lock); |
160 | return 0; | 179 | return 0; |
@@ -417,9 +436,8 @@ static unsigned char __init i8xx_tco_getdevice (void) | |||
417 | printk (KERN_ERR PFX "failed to get TCOBASE address\n"); | 436 | printk (KERN_ERR PFX "failed to get TCOBASE address\n"); |
418 | return 0; | 437 | return 0; |
419 | } | 438 | } |
420 | /* | 439 | |
421 | * Check chipset's NO_REBOOT bit | 440 | /* Check chipset's NO_REBOOT bit */ |
422 | */ | ||
423 | pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); | 441 | pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); |
424 | if (val1 & 0x02) { | 442 | if (val1 & 0x02) { |
425 | val1 &= 0xfd; | 443 | val1 &= 0xfd; |
@@ -430,6 +448,10 @@ static unsigned char __init i8xx_tco_getdevice (void) | |||
430 | return 0; /* Cannot reset NO_REBOOT bit */ | 448 | return 0; /* Cannot reset NO_REBOOT bit */ |
431 | } | 449 | } |
432 | } | 450 | } |
451 | /* Disable reboots untill the watchdog starts */ | ||
452 | val1 |= 0x02; | ||
453 | pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); | ||
454 | |||
433 | /* Set the TCO_EN bit in SMI_EN register */ | 455 | /* Set the TCO_EN bit in SMI_EN register */ |
434 | if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) { | 456 | if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) { |
435 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 457 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", |
@@ -505,17 +527,10 @@ out: | |||
505 | 527 | ||
506 | static void __exit watchdog_cleanup (void) | 528 | static void __exit watchdog_cleanup (void) |
507 | { | 529 | { |
508 | u8 val; | ||
509 | |||
510 | /* Stop the timer before we leave */ | 530 | /* Stop the timer before we leave */ |
511 | if (!nowayout) | 531 | if (!nowayout) |
512 | tco_timer_stop (); | 532 | tco_timer_stop (); |
513 | 533 | ||
514 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | ||
515 | pci_read_config_byte (i8xx_tco_pci, 0xd4, &val); | ||
516 | val |= 0x02; | ||
517 | pci_write_config_byte (i8xx_tco_pci, 0xd4, val); | ||
518 | |||
519 | /* Deregister */ | 534 | /* Deregister */ |
520 | misc_deregister (&i8xx_tco_miscdev); | 535 | misc_deregister (&i8xx_tco_miscdev); |
521 | unregister_reboot_notifier(&i8xx_tco_notifier); | 536 | unregister_reboot_notifier(&i8xx_tco_notifier); |