Joerg Roedel b97c99
From: David Woodhouse <dwmw@amazon.co.uk>
Joerg Roedel b97c99
Date: Wed, 7 Oct 2020 13:20:45 +0100
Joerg Roedel b97c99
Subject: [PATCH 4/5] x86/apic: Support 15 bits of APIC ID in IOAPIC/MSI where
Joerg Roedel b97c99
 available
Joerg Roedel b97c99
Patch-mainline: Never, upstream uses different implementation
Joerg Roedel b97c99
References: bsc#1181001, jsc#ECO-3191
Joerg Roedel b97c99
Joerg Roedel b97c99
Some hypervisors can allow the guest to use the Extended Destination ID
Joerg Roedel b97c99
field in the IOAPIC RTE and MSI address to address up to 32768 CPUs.
Joerg Roedel b97c99
Joerg Roedel b97c99
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Joerg Roedel b97c99
Acked-by: Joerg Roedel <jroedel@suse.de>
Joerg Roedel b97c99
---
Joerg Roedel b97c99
 arch/x86/include/asm/mpspec.h   |    1 +
Joerg Roedel b97c99
 arch/x86/include/asm/x86_init.h |    2 ++
Joerg Roedel b97c99
 arch/x86/kernel/apic/apic.c     |   15 ++++++++++++++-
Joerg Roedel b97c99
 arch/x86/kernel/apic/msi.c      |    9 ++++++++-
Joerg Roedel b97c99
 arch/x86/kernel/x86_init.c      |    1 +
Joerg Roedel b97c99
 5 files changed, 26 insertions(+), 2 deletions(-)
Joerg Roedel b97c99
Joerg Roedel b97c99
--- a/arch/x86/include/asm/mpspec.h
Joerg Roedel b97c99
+++ b/arch/x86/include/asm/mpspec.h
Joerg Roedel b97c99
@@ -41,6 +41,7 @@ extern DECLARE_BITMAP(mp_bus_not_pci, MA
Joerg Roedel b97c99
 extern unsigned int boot_cpu_physical_apicid;
Joerg Roedel b97c99
 extern u8 boot_cpu_apic_version;
Joerg Roedel b97c99
 extern unsigned long mp_lapic_addr;
Joerg Roedel b97c99
+extern int msi_ext_dest_id;
Joerg Roedel b97c99
 
Joerg Roedel b97c99
 #ifdef CONFIG_X86_LOCAL_APIC
Joerg Roedel b97c99
 extern int smp_found_config;
Joerg Roedel b97c99
--- a/arch/x86/include/asm/x86_init.h
Joerg Roedel b97c99
+++ b/arch/x86/include/asm/x86_init.h
Joerg Roedel b97c99
@@ -117,11 +117,13 @@ struct x86_init_pci {
Joerg Roedel b97c99
  * struct x86_hyper_init - x86 hypervisor init functions
Joerg Roedel b97c99
  * @init_platform:		platform setup
Joerg Roedel b97c99
  * @x2apic_available:		X2APIC detection
Joerg Roedel b97c99
+ * @msi_ext_dest_id:		MSI and IOAPIC support 15-bit APIC IDs
Joerg Roedel b97c99
  * @init_mem_mapping:		setup early mappings during init_mem_mapping()
Joerg Roedel b97c99
  */
Joerg Roedel b97c99
 struct x86_hyper_init {
Joerg Roedel b97c99
 	void (*init_platform)(void);
Joerg Roedel b97c99
 	bool (*x2apic_available)(void);
Joerg Roedel b97c99
+	bool (*msi_ext_dest_id)(void);
Joerg Roedel b97c99
 	void (*init_mem_mapping)(void);
Joerg Roedel b97c99
 };
Joerg Roedel b97c99
 
Joerg Roedel b97c99
--- a/arch/x86/kernel/apic/apic.c
Joerg Roedel b97c99
+++ b/arch/x86/kernel/apic/apic.c
Joerg Roedel b97c99
@@ -1576,9 +1576,21 @@ static __init void x2apic_enable(void)
Joerg Roedel b97c99
 
Joerg Roedel b97c99
 static __init void try_to_enable_x2apic(int remap_mode)
Joerg Roedel b97c99
 {
Joerg Roedel b97c99
+	u32 apic_limit = 255;
Joerg Roedel b97c99
+
Joerg Roedel b97c99
 	if (x2apic_state == X2APIC_DISABLED)
Joerg Roedel b97c99
 		return;
Joerg Roedel b97c99
 
Joerg Roedel b97c99
+	/*
Joerg Roedel b97c99
+	 * If the hypervisor supports extended destination ID in IOAPIC
Joerg Roedel b97c99
+	 * and MSI, that increases the maximum APIC ID that can be used
Joerg Roedel b97c99
+	 * for non-remapped IRQ domains.
Joerg Roedel b97c99
+	 */
Joerg Roedel b97c99
+	if (x86_init.hyper.msi_ext_dest_id()) {
Joerg Roedel b97c99
+		msi_ext_dest_id = 1;
Joerg Roedel b97c99
+		apic_limit = 32767;
Joerg Roedel b97c99
+	}
Joerg Roedel b97c99
+
Joerg Roedel b97c99
 	if (remap_mode != IRQ_REMAP_X2APIC_MODE) {
Joerg Roedel b97c99
 		/*
Joerg Roedel b97c99
 		 * Using X2APIC without IR is not architecturally supported
Joerg Roedel b97c99
@@ -1595,9 +1607,10 @@ static __init void try_to_enable_x2apic(
Joerg Roedel b97c99
 		 * in physical mode, and CPUs with an APIC ID that cannnot
Joerg Roedel b97c99
 		 * be addressed must not be brought online.
Joerg Roedel b97c99
 		 */
Joerg Roedel b97c99
-		x2apic_set_max_apicid(255);
Joerg Roedel b97c99
+		x2apic_set_max_apicid(apic_limit);
Joerg Roedel b97c99
 		x2apic_phys = 1;
Joerg Roedel b97c99
 	}
Joerg Roedel b97c99
+
Joerg Roedel b97c99
 	x2apic_enable();
Joerg Roedel b97c99
 }
Joerg Roedel b97c99
 
Joerg Roedel b97c99
--- a/arch/x86/kernel/apic/msi.c
Joerg Roedel b97c99
+++ b/arch/x86/kernel/apic/msi.c
Joerg Roedel b97c99
@@ -25,6 +25,8 @@
Joerg Roedel b97c99
 
Joerg Roedel b97c99
 static struct irq_domain *msi_default_domain;
Joerg Roedel b97c99
 
Joerg Roedel b97c99
+int msi_ext_dest_id;
Joerg Roedel b97c99
+
Joerg Roedel b97c99
 static void __irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg,
Joerg Roedel b97c99
 				  bool dmar)
Joerg Roedel b97c99
 {
Joerg Roedel b97c99
@@ -54,10 +56,15 @@ static void __irq_msi_compose_msg(struct
Joerg Roedel b97c99
 	 * Only the IOMMU itself can use the trick of putting destination
Joerg Roedel b97c99
 	 * APIC ID into the high bits of the address. Anything else would
Joerg Roedel b97c99
 	 * just be writing to memory if it tried that, and needs IR to
Joerg Roedel b97c99
-	 * address higher APIC IDs.
Joerg Roedel b97c99
+	 * address APICs which can't be addressed in the normal 32-bit
Joerg Roedel b97c99
+	 * address range at 0xFFExxxxx. That is typically just 8 bits, but
Joerg Roedel b97c99
+	 * some hypervisors allow the extended destination ID field in bits
Joerg Roedel b97c99
+	 * 11-5 to be used, giving support for 15 bits of APIC IDs in total.
Joerg Roedel b97c99
 	 */
Joerg Roedel b97c99
 	if (dmar)
Joerg Roedel b97c99
 		msg->address_hi |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid);
Joerg Roedel b97c99
+	else if (msi_ext_dest_id && cfg->dest_apicid < 0x8000)
Joerg Roedel b97c99
+		msg->address_lo |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid) >> 3;
Joerg Roedel b97c99
 	else
Joerg Roedel b97c99
 		WARN_ON_ONCE(MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid));
Joerg Roedel b97c99
 }
Joerg Roedel b97c99
--- a/arch/x86/kernel/x86_init.c
Joerg Roedel b97c99
+++ b/arch/x86/kernel/x86_init.c
Joerg Roedel b97c99
@@ -87,6 +87,7 @@ struct x86_init_ops x86_init __initdata
Joerg Roedel b97c99
 	.hyper = {
Joerg Roedel b97c99
 		.init_platform		= x86_init_noop,
Joerg Roedel b97c99
 		.x2apic_available	= bool_x86_init_noop,
Joerg Roedel b97c99
+		.msi_ext_dest_id	= bool_x86_init_noop,
Joerg Roedel b97c99
 		.init_mem_mapping	= x86_init_noop,
Joerg Roedel b97c99
 	},
Joerg Roedel b97c99
 };