summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2004-12-01 03:59:57 -0500
committerLen Brown <lenb@dhcppc3.>2004-12-01 03:59:57 -0500
commit0e3448746fcaaaeb8ea5061efa89d750d7403fbb (patch)
treea66134abc39924c36e25b35c754a1f7e36d421d3
parent7b28bc9322892dba038d3485de0a0ca3227533fa (diff)
[ACPI] disable LAPIC at reboot and poweroff if Linux forced it on
http://bugzilla.kernel.org/show_bug.cgi?id=3643 Signed-off-by: Alexey Y Starikovskiy <alexey.y.starikovskiy@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--arch/i386/kernel/apic.c23
-rw-r--r--arch/i386/kernel/reboot.c13
-rw-r--r--include/asm-i386/apic.h6
3 files changed, 31 insertions, 11 deletions
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 64c175ff4a92..110cc1d46bc2 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -491,12 +491,25 @@ void __init setup_local_APIC (void)
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
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;
/* r/w apic fields */
unsigned int apic_id;
@@ -584,6 +597,10 @@ static int lapic_resume(struct sys_device *dev)
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 = {
set_kset_name("lapic"),
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
index 06974254cd92..fc53f8b1719d 100644
--- a/arch/i386/kernel/reboot.c
+++ b/arch/i386/kernel/reboot.c
@@ -331,13 +331,10 @@ void machine_restart(char * __unused)
* other OSs see a clean IRQ state.
*/
smp_send_stop();
-#elif defined(CONFIG_X86_LOCAL_APIC)
- if (cpu_has_apic) {
- local_irq_disable();
- disable_local_APIC();
- local_irq_enable();
- }
-#endif
+#endif /* CONFIG_SMP */
+
+ lapic_shutdown();
+
#ifdef CONFIG_X86_IO_APIC
disable_IO_APIC();
#endif
@@ -373,6 +370,8 @@ EXPORT_SYMBOL(machine_halt);
void machine_power_off(void)
{
+ lapic_shutdown();
+
if (efi_enabled)
efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
if (pm_power_off)
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
index 8135c7c290f2..55ed2de23a62 100644
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -88,6 +88,7 @@ extern void clear_local_APIC(void);
extern void connect_bsp_APIC (void);
extern void disconnect_bsp_APIC (void);
extern void disable_local_APIC (void);
+extern void lapic_shutdown (void);
extern int verify_local_APIC (void);
extern void cache_APIC_registers (void);
extern void sync_Arb_IDs (void);
@@ -116,6 +117,9 @@ extern unsigned int nmi_watchdog;
#define NMI_LOCAL_APIC 2
#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 */