From: David Woodhouse <dwmw@amazon.co.uk>
Date: Wed, 7 Oct 2020 13:20:42 +0100
Subject: [PATCH 1/5] x86/apic: Fix x2apic enablement without interrupt
remapping
Patch-mainline: Never, upstream uses different implementation
References: bsc#1181001, jsc#ECO-3191
Currently, Linux as a hypervisor guest will enable x2apic only if there
are no CPUs present at boot time with an APIC ID above 255.
Hotplugging a CPU later with a higher APIC ID would result in a CPU
which cannot be targeted by external interrupts.
Add a filter in x2apic_apic_id_valid() which can be used to prevent
such CPUs from coming online, and allow x2apic to be enabled even if
they are present at boot time.
Fixes: ce69a784504 ("x86/apic: Enable x2APIC without interrupt remapping under KVM")
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Acked-by: Joerg Roedel <jroedel@suse.de>
---
arch/x86/include/asm/apic.h | 1 +
arch/x86/include/asm/x2apic.h | 5 +++++
arch/x86/kernel/apic/apic.c | 14 ++++++++------
arch/x86/kernel/apic/x2apic_phys.c | 6 ++++++
4 files changed, 20 insertions(+), 6 deletions(-)
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -235,6 +235,7 @@ static inline u64 native_x2apic_icr_read
extern int x2apic_mode;
extern int x2apic_phys;
+extern void __init x2apic_set_max_apicid(u32 apicid);
extern void __init check_x2apic(void);
extern void x2apic_setup(void);
static inline int x2apic_enabled(void)
--- a/arch/x86/include/asm/x2apic.h
+++ b/arch/x86/include/asm/x2apic.h
@@ -9,8 +9,13 @@
#include <asm/ipi.h>
#include <linux/cpumask.h>
+extern u32 x2apic_max_apicid;
+
static int x2apic_apic_id_valid(int apicid)
{
+ if (x2apic_max_apicid && apicid > x2apic_max_apicid)
+ return 0;
+
return 1;
}
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1580,20 +1580,22 @@ static __init void try_to_enable_x2apic(
return;
if (remap_mode != IRQ_REMAP_X2APIC_MODE) {
- /* IR is required if there is APIC ID > 255 even when running
- * under KVM
+ /*
+ * Using X2APIC without IR is not architecturally supported
+ * on bare metal but may be supported in guests.
*/
- if (max_physical_apicid > 255 ||
- !x86_init.hyper.x2apic_available()) {
+ if (!x86_init.hyper.x2apic_available()) {
pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n");
x2apic_disable();
return;
}
/*
- * without IR all CPUs can be addressed by IOAPIC/MSI
- * only in physical mode
+ * Without IR, all CPUs can be addressed by IOAPIC/MSI only
+ * in physical mode, and CPUs with an APIC ID that cannnot
+ * be addressed must not be brought online.
*/
+ x2apic_set_max_apicid(255);
x2apic_phys = 1;
}
x2apic_enable();
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -11,6 +11,12 @@
int x2apic_phys;
static struct apic apic_x2apic_phys;
+u32 x2apic_max_apicid;
+
+void __init x2apic_set_max_apicid(u32 apicid)
+{
+ x2apic_max_apicid = apicid;
+}
static int set_x2apic_phys_mode(char *arg)
{