aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2007-02-13 07:26:24 -0500
committerAndi Kleen <andi@basil.nowhere.org>2007-02-13 07:26:24 -0500
commit5d0e600d903caa09e790824cc5812f0d97113b23 (patch)
treea9650a9a77d6aa394e98d766aef67ac14666ccc6 /arch
parent310adfdd9153f6ae818981a38a48dd2330990d8d (diff)
[PATCH] x86: fix laptop bootup hang in init_acpi()
During kernel bootup, a new T60 laptop (CoreDuo, 32-bit) hangs about 10%-20% of the time in acpi_init(): Calling initcall 0xc055ce1a: topology_init+0x0/0x2f() Calling initcall 0xc055d75e: mtrr_init_finialize+0x0/0x2c() Calling initcall 0xc05664f3: param_sysfs_init+0x0/0x175() Calling initcall 0xc014cb65: pm_sysrq_init+0x0/0x17() Calling initcall 0xc0569f99: init_bio+0x0/0xf4() Calling initcall 0xc056b865: genhd_device_init+0x0/0x50() Calling initcall 0xc056c4bd: fbmem_init+0x0/0x87() Calling initcall 0xc056dd74: acpi_init+0x0/0x1ee() It's a hard hang that not even an NMI could punch through! Frustratingly, adding printks or function tracing to the ACPI code made the hangs go away ... After some time an additional detail emerged: disabling the NMI watchdog made these occasional hangs go away. So i spent the better part of today trying to debug this and trying out various theories when i finally found the likely reason for the hang: if acpi_ns_initialize_devices() executes an _INI AML method and an NMI happens to hit that AML execution in the wrong moment, the machine would hang. (my theory is that this must be some sort of chipset setup method doing stores to chipset mmio registers?) Unfortunately given the characteristics of the hang it was sheer impossible to figure out which of the numerous AML methods is impacted by this problem. As a workaround i wrote an interface to disable chipset-based NMIs while executing _INI sections - and indeed this fixed the hang. I did a boot-loop of 100 separate reboots and none hung - while without the patch it would hang every 5-10 attempts. Out of caution i did not touch the nmi_watchdog=2 case (it's not related to the chipset anyway and didnt hang). I implemented this for both x86_64 and i686, tested the i686 laptop both with nmi_watchdog=1 [which triggered the hangs] and nmi_watchdog=2, and tested an Athlon64 box with the 64-bit kernel as well. Everything builds and works with the patch applied. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Andi Kleen <ak@suse.de> Cc: Len Brown <lenb@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/kernel/nmi.c28
-rw-r--r--arch/x86_64/kernel/nmi.c27
2 files changed, 55 insertions, 0 deletions
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index 7d3f4e22d6fb..b11abacc5cfd 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -383,6 +383,34 @@ void enable_timer_nmi_watchdog(void)
383 } 383 }
384} 384}
385 385
386static void __acpi_nmi_disable(void *__unused)
387{
388 apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
389}
390
391/*
392 * Disable timer based NMIs on all CPUs:
393 */
394void acpi_nmi_disable(void)
395{
396 if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
397 on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
398}
399
400static void __acpi_nmi_enable(void *__unused)
401{
402 apic_write_around(APIC_LVT0, APIC_DM_NMI);
403}
404
405/*
406 * Enable timer based NMIs on all CPUs:
407 */
408void acpi_nmi_enable(void)
409{
410 if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
411 on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
412}
413
386#ifdef CONFIG_PM 414#ifdef CONFIG_PM
387 415
388static int nmi_pm_active; /* nmi_active before suspend */ 416static int nmi_pm_active; /* nmi_active before suspend */
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index e59cda134166..269fe585e71e 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -368,6 +368,33 @@ void enable_timer_nmi_watchdog(void)
368 } 368 }
369} 369}
370 370
371static void __acpi_nmi_disable(void *__unused)
372{
373 apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
374}
375
376/*
377 * Disable timer based NMIs on all CPUs:
378 */
379void acpi_nmi_disable(void)
380{
381 if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
382 on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
383}
384
385static void __acpi_nmi_enable(void *__unused)
386{
387 apic_write(APIC_LVT0, APIC_DM_NMI);
388}
389
390/*
391 * Enable timer based NMIs on all CPUs:
392 */
393void acpi_nmi_enable(void)
394{
395 if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
396 on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
397}
371#ifdef CONFIG_PM 398#ifdef CONFIG_PM
372 399
373static int nmi_pm_active; /* nmi_active before suspend */ 400static int nmi_pm_active; /* nmi_active before suspend */