Commit a5bfb7f3 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Local APIC enable fixes

From: mikep@csd.uu.se

There has been a number of problem reports about local APIC
interacting badly with ACPI on P4s due to the P4 local APIC
force-enable change in 2.5.74,

This patch reverts the 2.5.74 patch, so if the BIOS disables
the local APIC on a P4, we don't enable it by default any more.

The rescue the situation for those P4 systems where the local
APIC _can_ be enabled safely, I've added two kernel parameters
that can be used to override broken BIOSen:
- "nolapic" prevents the kernel from enabling or using the local
  APIC. This is stronger than listing a machine in the DMI scan
  blacklist, since it also works for machines that boot with the
  local APIC already enabled.
- "lapic" tells the kernel to force-enable the P4 local APIC if
  the BIOS disabled it. I haven't changed the logic for P6/K7
  family processors, so we still force-enable those unless
  "nolapic" was passed to the kernel.

The patch also includes a cleanup: the dont_use_local_apic_timer
flag variable is not set any more since 2.5.74, so it's removed.
parent 14e902a4
...@@ -439,6 +439,8 @@ running once the system is up. ...@@ -439,6 +439,8 @@ running once the system is up.
l2cr= [PPC] l2cr= [PPC]
lapic [IA-32,APIC] Enable the local APIC even if BIOS disabled it.
lasi= [HW,SCSI] PARISC LASI driver for the 53c700 chip lasi= [HW,SCSI] PARISC LASI driver for the 53c700 chip
Format: addr:<io>,irq:<irq> Format: addr:<io>,irq:<irq>
...@@ -626,6 +628,8 @@ running once the system is up. ...@@ -626,6 +628,8 @@ running once the system is up.
nointroute [IA-64] nointroute [IA-64]
nolapic [IA-32,APIC] Do not enable or use the local APIC.
nomce [IA-32] Machine Check Exception nomce [IA-32] Machine Check Exception
noresume [SWSUSP] Disables resume and restore original swap space. noresume [SWSUSP] Disables resume and restore original swap space.
......
...@@ -604,7 +604,26 @@ static void apic_pm_activate(void) { } ...@@ -604,7 +604,26 @@ static void apic_pm_activate(void) { }
* Detect and enable local APICs on non-SMP boards. * Detect and enable local APICs on non-SMP boards.
* Original code written by Keir Fraser. * Original code written by Keir Fraser.
*/ */
int dont_enable_local_apic __initdata = 0;
/*
* Knob to control our willingness to enable the local APIC.
*/
int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
static int __init lapic_disable(char *str)
{
enable_local_apic = -1;
clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
return 0;
}
__setup("nolapic", lapic_disable);
static int __init lapic_enable(char *str)
{
enable_local_apic = 1;
return 0;
}
__setup("lapic", lapic_enable);
static int __init detect_init_APIC (void) static int __init detect_init_APIC (void)
{ {
...@@ -612,7 +631,7 @@ static int __init detect_init_APIC (void) ...@@ -612,7 +631,7 @@ static int __init detect_init_APIC (void)
extern void get_cpu_vendor(struct cpuinfo_x86*); extern void get_cpu_vendor(struct cpuinfo_x86*);
/* Disabled by DMI scan or kernel option? */ /* Disabled by DMI scan or kernel option? */
if (dont_enable_local_apic) if (enable_local_apic < 0)
return -1; return -1;
/* Workaround for us being called before identify_cpu(). */ /* Workaround for us being called before identify_cpu(). */
...@@ -626,7 +645,7 @@ static int __init detect_init_APIC (void) ...@@ -626,7 +645,7 @@ static int __init detect_init_APIC (void)
goto no_apic; goto no_apic;
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
if (boot_cpu_data.x86 == 6 || if (boot_cpu_data.x86 == 6 ||
boot_cpu_data.x86 == 15 || (boot_cpu_data.x86 == 15 && (cpu_has_apic || enable_local_apic > 0)) ||
(boot_cpu_data.x86 == 5 && cpu_has_apic)) (boot_cpu_data.x86 == 5 && cpu_has_apic))
break; break;
goto no_apic; goto no_apic;
...@@ -908,14 +927,8 @@ int __init calibrate_APIC_clock(void) ...@@ -908,14 +927,8 @@ int __init calibrate_APIC_clock(void)
static unsigned int calibration_result; static unsigned int calibration_result;
int dont_use_local_apic_timer __initdata = 0;
void __init setup_boot_APIC_clock(void) void __init setup_boot_APIC_clock(void)
{ {
/* Disabled by DMI scan or kernel option? */
if (dont_use_local_apic_timer)
return;
printk("Using local APIC timer interrupts.\n"); printk("Using local APIC timer interrupts.\n");
using_apic_timer = 1; using_apic_timer = 1;
...@@ -1132,6 +1145,9 @@ asmlinkage void smp_error_interrupt(void) ...@@ -1132,6 +1145,9 @@ asmlinkage void smp_error_interrupt(void)
*/ */
int __init APIC_init_uniprocessor (void) int __init APIC_init_uniprocessor (void)
{ {
if (enable_local_apic < 0)
clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
if (!smp_found_config && !cpu_has_apic) if (!smp_found_config && !cpu_has_apic)
return -1; return -1;
......
...@@ -314,9 +314,9 @@ static __init int apm_is_horked(struct dmi_blacklist *d) ...@@ -314,9 +314,9 @@ static __init int apm_is_horked(struct dmi_blacklist *d)
static int __init local_apic_kills_bios(struct dmi_blacklist *d) static int __init local_apic_kills_bios(struct dmi_blacklist *d)
{ {
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
extern int dont_enable_local_apic; extern int enable_local_apic;
if (!dont_enable_local_apic) { if (enable_local_apic == 0) {
dont_enable_local_apic = 1; enable_local_apic = -1;
printk(KERN_WARNING "%s with broken BIOS detected. " printk(KERN_WARNING "%s with broken BIOS detected. "
"Refusing to enable the local APIC.\n", "Refusing to enable the local APIC.\n",
d->ident); d->ident);
......
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