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.



 Documentation/kernel-parameters.txt |    4 ++++
 arch/i386/kernel/apic.c             |   34 +++++++++++++++++++++++++---------
 arch/i386/kernel/dmi_scan.c         |    6 +++---
 3 files changed, 32 insertions(+), 12 deletions(-)

diff -puN arch/i386/kernel/apic.c~local-apic-enable-fixes arch/i386/kernel/apic.c
--- 25/arch/i386/kernel/apic.c~local-apic-enable-fixes	2003-08-18 22:27:07.000000000 -0700
+++ 25-akpm/arch/i386/kernel/apic.c	2003-08-18 22:27:07.000000000 -0700
@@ -604,7 +604,26 @@ static void apic_pm_activate(void) { }
  * Detect and enable local APICs on non-SMP boards.
  * 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)
 {
@@ -612,7 +631,7 @@ static int __init detect_init_APIC (void
 	extern void get_cpu_vendor(struct cpuinfo_x86*);
 
 	/* Disabled by DMI scan or kernel option? */
-	if (dont_enable_local_apic)
+	if (enable_local_apic < 0)
 		return -1;
 
 	/* Workaround for us being called before identify_cpu(). */
@@ -626,7 +645,7 @@ static int __init detect_init_APIC (void
 		goto no_apic;
 	case X86_VENDOR_INTEL:
 		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))
 			break;
 		goto no_apic;
@@ -908,14 +927,8 @@ int __init calibrate_APIC_clock(void)
 
 static unsigned int calibration_result;
 
-int dont_use_local_apic_timer __initdata = 0;
-
 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");
 	using_apic_timer = 1;
 
@@ -1132,6 +1145,9 @@ asmlinkage void smp_error_interrupt(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)
 		return -1;
 
diff -puN arch/i386/kernel/dmi_scan.c~local-apic-enable-fixes arch/i386/kernel/dmi_scan.c
--- 25/arch/i386/kernel/dmi_scan.c~local-apic-enable-fixes	2003-08-18 22:27:07.000000000 -0700
+++ 25-akpm/arch/i386/kernel/dmi_scan.c	2003-08-18 22:27:07.000000000 -0700
@@ -314,9 +314,9 @@ static __init int apm_is_horked(struct d
 static int __init local_apic_kills_bios(struct dmi_blacklist *d)
 {
 #ifdef CONFIG_X86_LOCAL_APIC
-	extern int dont_enable_local_apic;
-	if (!dont_enable_local_apic) {
-		dont_enable_local_apic = 1;
+	extern int enable_local_apic;
+	if (enable_local_apic == 0) {
+		enable_local_apic = -1;
 		printk(KERN_WARNING "%s with broken BIOS detected. "
 		       "Refusing to enable the local APIC.\n",
 		       d->ident);
diff -puN Documentation/kernel-parameters.txt~local-apic-enable-fixes Documentation/kernel-parameters.txt
--- 25/Documentation/kernel-parameters.txt~local-apic-enable-fixes	2003-08-18 22:27:07.000000000 -0700
+++ 25-akpm/Documentation/kernel-parameters.txt	2003-08-18 22:27:07.000000000 -0700
@@ -439,6 +439,8 @@ running once the system is up.
 
 	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
 			Format: addr:<io>,irq:<irq>
 
@@ -626,6 +628,8 @@ running once the system is up.
 
 	nointroute	[IA-64]
 
+	nolapic		[IA-32,APIC] Do not enable or use the local APIC.
+
 	nomce		[IA-32] Machine Check Exception
 
 	noresume	[SWSUSP] Disables resume and restore original swap space.

_