aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/nmi.c
diff options
context:
space:
mode:
authorRavikiran G Thirumalai <kiran@scalex86.org>2006-12-09 15:33:35 -0500
committerAndi Kleen <andi@basil.nowhere.org>2006-12-09 15:33:35 -0500
commit92715e282be7c7488f892703c8d39b08976a833b (patch)
tree49acd962775f5a113483b16bbcc9c504728215ca /arch/x86_64/kernel/nmi.c
parent16d279d277aedd640d9dba5ddeb172b5e6bc7d75 (diff)
[PATCH] x86: Fix boot hang due to nmi watchdog init code
2.6.19 stopped booting (or booted based on build/config) on our x86_64 systems due to a bug introduced in 2.6.19. check_nmi_watchdog schedules an IPI on all cpus to busy wait on a flag, but fails to set the busywait flag if NMI functionality is disabled. This causes the secondary cpus to spin in an endless loop, causing the kernel bootup to hang. Depending upon the build, the busywait flag got overwritten (stack variable) and caused the kernel to bootup on certain builds. Following patch fixes the bug by setting the busywait flag before returning from check_nmi_watchdog. I guess using a stack variable is not good here as the calling function could potentially return while the busy wait loop is still spinning on the flag. AK: I redid the patch significantly to be cleaner Signed-off-by: Ravikiran Thirumalai <kiran@scalex86.org> Signed-off-by: Shai Fultheim <shai@scalex86.org> Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/x86_64/kernel/nmi.c')
-rw-r--r--arch/x86_64/kernel/nmi.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 27e95e7922c1..186aebbae32d 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -193,6 +193,8 @@ void nmi_watchdog_default(void)
193 nmi_watchdog = NMI_IO_APIC; 193 nmi_watchdog = NMI_IO_APIC;
194} 194}
195 195
196static int endflag __initdata = 0;
197
196#ifdef CONFIG_SMP 198#ifdef CONFIG_SMP
197/* The performance counters used by NMI_LOCAL_APIC don't trigger when 199/* The performance counters used by NMI_LOCAL_APIC don't trigger when
198 * the CPU is idle. To make sure the NMI watchdog really ticks on all 200 * the CPU is idle. To make sure the NMI watchdog really ticks on all
@@ -200,7 +202,6 @@ void nmi_watchdog_default(void)
200 */ 202 */
201static __init void nmi_cpu_busy(void *data) 203static __init void nmi_cpu_busy(void *data)
202{ 204{
203 volatile int *endflag = data;
204 local_irq_enable_in_hardirq(); 205 local_irq_enable_in_hardirq();
205 /* Intentionally don't use cpu_relax here. This is 206 /* Intentionally don't use cpu_relax here. This is
206 to make sure that the performance counter really ticks, 207 to make sure that the performance counter really ticks,
@@ -208,14 +209,13 @@ static __init void nmi_cpu_busy(void *data)
208 pause instruction. On a real HT machine this is fine because 209 pause instruction. On a real HT machine this is fine because
209 all other CPUs are busy with "useless" delay loops and don't 210 all other CPUs are busy with "useless" delay loops and don't
210 care if they get somewhat less cycles. */ 211 care if they get somewhat less cycles. */
211 while (*endflag == 0) 212 while (endflag == 0)
212 barrier(); 213 mb();
213} 214}
214#endif 215#endif
215 216
216int __init check_nmi_watchdog (void) 217int __init check_nmi_watchdog (void)
217{ 218{
218 volatile int endflag = 0;
219 int *counts; 219 int *counts;
220 int cpu; 220 int cpu;
221 221
@@ -256,6 +256,7 @@ int __init check_nmi_watchdog (void)
256 if (!atomic_read(&nmi_active)) { 256 if (!atomic_read(&nmi_active)) {
257 kfree(counts); 257 kfree(counts);
258 atomic_set(&nmi_active, -1); 258 atomic_set(&nmi_active, -1);
259 endflag = 1;
259 return -1; 260 return -1;
260 } 261 }
261 endflag = 1; 262 endflag = 1;