From: Mikael Pettersson Here is a patch to disable the local APIC before reboot. This fixes BIOS reboot problems reported by a few people. disable_local_APIC() now checks if detect_init_APIC() enabled the local APIC via the APIC_BASE MSR, and if so it now disables APIC_BASE. Previously we would leave APIC_BASE enabled, and that made some BIOSen unhappy. The SMP reboot code calls disable_local_APIC(). On SMP HW there is no change since detect_init_APIC() isn't called and APIC_BASE isn't enabled by us. An SMP kernel on UP HW behaves just like an UP_APIC kernel, so it disables APIC_BASE if we enabled it at boot. The UP_APIC disable-before-suspend code is simplified since the existing code to disable APIC_BASE is moved into disable_local_APIC(). (Felix Kühling originally reported the BIOS reboot problem. This is a fixed-up version of his preliminary patch.) 25-akpm/arch/i386/kernel/apic.c | 14 ++++++++++---- 25-akpm/arch/i386/kernel/reboot.c | 9 +++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff -puN arch/i386/kernel/apic.c~reboot-disable-local-apic arch/i386/kernel/apic.c --- 25/arch/i386/kernel/apic.c~reboot-disable-local-apic Mon Aug 11 16:39:02 2003 +++ 25-akpm/arch/i386/kernel/apic.c Mon Aug 11 16:39:02 2003 @@ -66,6 +66,8 @@ static DEFINE_PER_CPU(int, prof_multipli static DEFINE_PER_CPU(int, prof_old_multiplier) = 1; static DEFINE_PER_CPU(int, prof_counter) = 1; +static int enabled_via_apicbase; + void enable_NMI_through_LVT0 (void * dummy) { unsigned int v, ver; @@ -195,6 +197,13 @@ void disable_local_APIC(void) value = apic_read(APIC_SPIV); value &= ~APIC_SPIV_APIC_ENABLED; apic_write_around(APIC_SPIV, value); + + if (enabled_via_apicbase) { + unsigned int l, h; + rdmsr(MSR_IA32_APICBASE, l, h); + l &= ~MSR_IA32_APICBASE_ENABLE; + wrmsr(MSR_IA32_APICBASE, l, h); + } } /* @@ -490,7 +499,6 @@ static struct { static int lapic_suspend(struct sys_device *dev, u32 state) { - unsigned int l, h; unsigned long flags; if (!apic_pm_state.active) @@ -512,9 +520,6 @@ static int lapic_suspend(struct sys_devi local_irq_save(flags); disable_local_APIC(); - rdmsr(MSR_IA32_APICBASE, l, h); - l &= ~MSR_IA32_APICBASE_ENABLE; - wrmsr(MSR_IA32_APICBASE, l, h); local_irq_restore(flags); return 0; } @@ -660,6 +665,7 @@ static int __init detect_init_APIC (void l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); + enabled_via_apicbase = 1; } } /* diff -puN arch/i386/kernel/reboot.c~reboot-disable-local-apic arch/i386/kernel/reboot.c --- 25/arch/i386/kernel/reboot.c~reboot-disable-local-apic Mon Aug 11 16:39:02 2003 +++ 25-akpm/arch/i386/kernel/reboot.c Mon Aug 11 16:39:02 2003 @@ -8,6 +8,7 @@ #include #include #include +#include #include "mach_reboot.h" /* @@ -248,6 +249,14 @@ void machine_restart(char * __unused) * other OSs see a clean IRQ state. */ smp_send_stop(); +#elif CONFIG_X86_LOCAL_APIC + if (cpu_has_apic) { + local_irq_disable(); + disable_local_APIC(); + local_irq_enable(); + } +#endif +#ifdef CONFIG_X86_IO_APIC disable_IO_APIC(); #endif _