ff41e30
From a57e456a7b28431b55e407e5ab78ebd5b378d19e Mon Sep 17 00:00:00 2001
ff41e30
From: Thomas Gleixner <tglx@linutronix.de>
ff41e30
Date: Sat, 22 Aug 2015 16:41:17 +0200
ff41e30
Subject: [PATCH] x86/apic: Fix fallout from x2apic cleanup
ff41e30
ff41e30
In the recent x2apic cleanup I got two things really wrong:
ff41e30
1) The safety check in __disable_x2apic which allows the function to
ff41e30
   be called unconditionally is backwards. The check is there to
ff41e30
   prevent access to the apic MSR in case that the machine has no
ff41e30
   apic. Though right now it returns if the machine has an apic and
ff41e30
   therefor the disabling of x2apic is never invoked.
ff41e30
ff41e30
2) x2apic_disable() sets x2apic_mode to 0 after registering the local
ff41e30
   apic. That's wrong, because register_lapic_address() checks x2apic
ff41e30
   mode and therefor takes the wrong code path.
ff41e30
ff41e30
This results in boot failures on machines with x2apic preenabled by
ff41e30
BIOS and can also lead to an fatal MSR access on machines without
ff41e30
apic.
ff41e30
ff41e30
The solutions are simple:
ff41e30
1) Correct the sanity check for apic availability
ff41e30
2) Clear x2apic_mode _before_ calling register_lapic_address()
ff41e30
ff41e30
Fixes: 659006bf3ae3 'x86/x2apic: Split enable and setup function'
ff41e30
Reported-and-tested-by: Javier Monteagudo <javiermon@gmail.com>
ff41e30
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
ff41e30
Link: https://bugzilla.redhat.com/show_bug.cgi?id=1224764
ff41e30
Cc: stable@vger.kernel.org # 4.0+
ff41e30
Cc: Laura Abbott <labbott@redhat.com>
ff41e30
Cc: Jiang Liu <jiang.liu@linux.intel.com>
ff41e30
Cc: Joerg Roedel <joro@8bytes.org>
ff41e30
Cc: Tony Luck <tony.luck@intel.com>
ff41e30
Cc: Borislav Petkov <bp@alien8.de>
ff41e30
---
ff41e30
 arch/x86/kernel/apic/apic.c | 14 +++++++-------
ff41e30
 1 file changed, 7 insertions(+), 7 deletions(-)
ff41e30
ff41e30
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
ff41e30
index dcb5285..cde732c 100644
ff41e30
--- a/arch/x86/kernel/apic/apic.c
ff41e30
+++ b/arch/x86/kernel/apic/apic.c
ff41e30
@@ -1424,7 +1424,7 @@ static inline void __x2apic_disable(void)
ff41e30
 {
ff41e30
 	u64 msr;
ff41e30
 
ff41e30
-	if (cpu_has_apic)
ff41e30
+	if (!cpu_has_apic)
ff41e30
 		return;
ff41e30
 
ff41e30
 	rdmsrl(MSR_IA32_APICBASE, msr);
ff41e30
@@ -1483,10 +1483,13 @@ void x2apic_setup(void)
ff41e30
 
ff41e30
 static __init void x2apic_disable(void)
ff41e30
 {
ff41e30
-	u32 x2apic_id;
ff41e30
+	u32 x2apic_id, state = x2apic_state;
ff41e30
 
ff41e30
-	if (x2apic_state != X2APIC_ON)
ff41e30
-		goto out;
ff41e30
+	x2apic_mode = 0;
ff41e30
+	x2apic_state = X2APIC_DISABLED;
ff41e30
+
ff41e30
+	if (state != X2APIC_ON)
ff41e30
+		return;
ff41e30
 
ff41e30
 	x2apic_id = read_apic_id();
ff41e30
 	if (x2apic_id >= 255)
ff41e30
@@ -1494,9 +1497,6 @@ static __init void x2apic_disable(void)
ff41e30
 
ff41e30
 	__x2apic_disable();
ff41e30
 	register_lapic_address(mp_lapic_addr);
ff41e30
-out:
ff41e30
-	x2apic_state = X2APIC_DISABLED;
ff41e30
-	x2apic_mode = 0;
ff41e30
 }
ff41e30
 
ff41e30
 static __init void x2apic_enable(void)
ff41e30
-- 
ff41e30
2.4.3
ff41e30