Commit 0e344874 authored by Len Brown's avatar Len Brown Committed by Len Brown

[ACPI] disable LAPIC at reboot and poweroff if Linux forced it on

http://bugzilla.kernel.org/show_bug.cgi?id=3643Signed-off-by: default avatarAlexey Y Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 7b28bc93
...@@ -491,12 +491,25 @@ void __init setup_local_APIC (void) ...@@ -491,12 +491,25 @@ void __init setup_local_APIC (void)
apic_pm_activate(); apic_pm_activate();
} }
/*
* If Linux enabled the LAPIC against the BIOS default
* disable it down before re-entering the BIOS on shutdown.
* Otherwise the BIOS may get confused and not power-off.
*/
void
lapic_shutdown()
{
if (!cpu_has_apic || !enabled_via_apicbase)
return;
local_irq_disable();
disable_local_APIC();
local_irq_enable();
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
static struct { static struct {
/* 'active' is true if the local APIC was enabled by us and
not the BIOS; this signifies that we are also responsible
for disabling it before entering apm/acpi suspend */
int active; int active;
/* r/w apic fields */ /* r/w apic fields */
unsigned int apic_id; unsigned int apic_id;
...@@ -584,6 +597,10 @@ static int lapic_resume(struct sys_device *dev) ...@@ -584,6 +597,10 @@ static int lapic_resume(struct sys_device *dev)
return 0; return 0;
} }
/*
* This device has no shutdown method - fully functioning local APICs
* are needed on every CPU up until machine_halt/restart/poweroff.
*/
static struct sysdev_class lapic_sysclass = { static struct sysdev_class lapic_sysclass = {
set_kset_name("lapic"), set_kset_name("lapic"),
......
...@@ -331,13 +331,10 @@ void machine_restart(char * __unused) ...@@ -331,13 +331,10 @@ 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 defined(CONFIG_X86_LOCAL_APIC) #endif /* CONFIG_SMP */
if (cpu_has_apic) {
local_irq_disable(); lapic_shutdown();
disable_local_APIC();
local_irq_enable();
}
#endif
#ifdef CONFIG_X86_IO_APIC #ifdef CONFIG_X86_IO_APIC
disable_IO_APIC(); disable_IO_APIC();
#endif #endif
...@@ -373,6 +370,8 @@ EXPORT_SYMBOL(machine_halt); ...@@ -373,6 +370,8 @@ EXPORT_SYMBOL(machine_halt);
void machine_power_off(void) void machine_power_off(void)
{ {
lapic_shutdown();
if (efi_enabled) if (efi_enabled)
efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
if (pm_power_off) if (pm_power_off)
......
...@@ -88,6 +88,7 @@ extern void clear_local_APIC(void); ...@@ -88,6 +88,7 @@ extern void clear_local_APIC(void);
extern void connect_bsp_APIC (void); extern void connect_bsp_APIC (void);
extern void disconnect_bsp_APIC (void); extern void disconnect_bsp_APIC (void);
extern void disable_local_APIC (void); extern void disable_local_APIC (void);
extern void lapic_shutdown (void);
extern int verify_local_APIC (void); extern int verify_local_APIC (void);
extern void cache_APIC_registers (void); extern void cache_APIC_registers (void);
extern void sync_Arb_IDs (void); extern void sync_Arb_IDs (void);
...@@ -116,6 +117,9 @@ extern unsigned int nmi_watchdog; ...@@ -116,6 +117,9 @@ extern unsigned int nmi_watchdog;
#define NMI_LOCAL_APIC 2 #define NMI_LOCAL_APIC 2
#define NMI_INVALID 3 #define NMI_INVALID 3
#endif /* CONFIG_X86_LOCAL_APIC */ #else /* !CONFIG_X86_LOCAL_APIC */
static inline void lapic_shutdown(void) { }
#endif /* !CONFIG_X86_LOCAL_APIC */
#endif /* __ASM_APIC_H */ #endif /* __ASM_APIC_H */
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