Subject: [PATCH] x86, apic: Check fadt x2apic phys in x2apic_phys_probe()
From: Stoney Wang <[email-masked]>

HP has systems that work with x2apic phys mode and BIOS set
ACPI_FADT_APIC_PHYSICAL in FADT table, and all cpuid < 255, the spec
requires BIOS only put system on xapic mode.
Kernel will set to x2apic logical mode instead of x2apic phys mode.

Current code handle x2apic as:
1. BIOS set x2apic mode:
When user specify x2apic_phys, or FADT indicates PHYSICAL.
During madt oem check, apic driver will set correctly to x2apic phys driver.

2. BIOS does NOT set x2apic mode:
When user specify x2apic_phys, or FADT indicates PHYSICAL.
During madt oem check, apic driver will get set with xapic logical or
xapic phys driver at first.
Later enable_IR_x2apic() will enable x2apic_mode.
After that, x2apic_phys_probe() get called.
That will install right x2apic physical driver when user specify x2apic_phys,
but will install wrong apic driver (x2apic logical) when FADT indicates
PHYSICAL, because that probe does not check FADT PHYSICAL.

Fix that by adding check x2apic_fadt_phys in x2apic_phys_probe().

[ changelog, and simplify code - Yinghai Lu ]
Signed-off-by: Stoney Wang <[email-masked]>
Signed-off-by: Yinghai Lu <[email-masked]>

---
 arch/x86/kernel/apic/x2apic_phys.c |   19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

Index: linux-2.6/arch/x86/kernel/apic/x2apic_phys.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/apic/x2apic_phys.c
+++ linux-2.6/arch/x86/kernel/apic/x2apic_phys.c
@@ -20,18 +20,19 @@ static int set_x2apic_phys_mode(char *ar
 }
 early_param("x2apic_phys", set_x2apic_phys_mode);
 
-static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+static int x2apic_fadt_phys(void)
 {
-	if (x2apic_phys)
-		return x2apic_enabled();
-	else if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
-		(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) &&
-		x2apic_enabled()) {
+	if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
+		(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
 		printk(KERN_DEBUG "System requires x2apic physical mode\n");
 		return 1;
 	}
-	else
-		return 0;
+	return 0;
+}
+
+static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys());
 }
 
 static void
@@ -82,7 +83,7 @@ static void init_x2apic_ldr(void)
 
 static int x2apic_phys_probe(void)
 {
-	if (x2apic_mode && x2apic_phys)
+	if (x2apic_mode && (x2apic_phys || x2apic_fadt_phys()))
 		return 1;
 
 	return apic == &apic_x2apic_phys;