Commit 0ac17865 authored by Mikael Pettersson's avatar Mikael Pettersson Committed by Linus Torvalds

[PATCH] Disable APIC on reboot

This disables 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.)
parent d6b797dd
...@@ -61,6 +61,8 @@ static DEFINE_PER_CPU(int, prof_multiplier) = 1; ...@@ -61,6 +61,8 @@ static DEFINE_PER_CPU(int, prof_multiplier) = 1;
static DEFINE_PER_CPU(int, prof_old_multiplier) = 1; static DEFINE_PER_CPU(int, prof_old_multiplier) = 1;
static DEFINE_PER_CPU(int, prof_counter) = 1; static DEFINE_PER_CPU(int, prof_counter) = 1;
static int enabled_via_apicbase;
void enable_NMI_through_LVT0 (void * dummy) void enable_NMI_through_LVT0 (void * dummy)
{ {
unsigned int v, ver; unsigned int v, ver;
...@@ -190,6 +192,13 @@ void disable_local_APIC(void) ...@@ -190,6 +192,13 @@ void disable_local_APIC(void)
value = apic_read(APIC_SPIV); value = apic_read(APIC_SPIV);
value &= ~APIC_SPIV_APIC_ENABLED; value &= ~APIC_SPIV_APIC_ENABLED;
apic_write_around(APIC_SPIV, value); 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);
}
} }
/* /*
...@@ -485,7 +494,6 @@ static struct { ...@@ -485,7 +494,6 @@ static struct {
static int lapic_suspend(struct sys_device *dev, u32 state) static int lapic_suspend(struct sys_device *dev, u32 state)
{ {
unsigned int l, h;
unsigned long flags; unsigned long flags;
if (!apic_pm_state.active) if (!apic_pm_state.active)
...@@ -507,9 +515,6 @@ static int lapic_suspend(struct sys_device *dev, u32 state) ...@@ -507,9 +515,6 @@ static int lapic_suspend(struct sys_device *dev, u32 state)
local_irq_save(flags); local_irq_save(flags);
disable_local_APIC(); disable_local_APIC();
rdmsr(MSR_IA32_APICBASE, l, h);
l &= ~MSR_IA32_APICBASE_ENABLE;
wrmsr(MSR_IA32_APICBASE, l, h);
local_irq_restore(flags); local_irq_restore(flags);
return 0; return 0;
} }
...@@ -636,6 +641,7 @@ static int __init detect_init_APIC (void) ...@@ -636,6 +641,7 @@ static int __init detect_init_APIC (void)
l &= ~MSR_IA32_APICBASE_BASE; l &= ~MSR_IA32_APICBASE_BASE;
l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
wrmsr(MSR_IA32_APICBASE, l, h); wrmsr(MSR_IA32_APICBASE, l, h);
enabled_via_apicbase = 1;
} }
} }
/* /*
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mc146818rtc.h> #include <linux/mc146818rtc.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/apic.h>
#include "mach_reboot.h" #include "mach_reboot.h"
/* /*
...@@ -249,6 +250,14 @@ void machine_restart(char * __unused) ...@@ -249,6 +250,14 @@ void machine_restart(char * __unused)
* other OSs see a clean IRQ state. * other OSs see a clean IRQ state.
*/ */
smp_send_stop(); 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(); disable_IO_APIC();
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment