]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
x86/apic: Support 15 bits of APIC ID in IOAPIC/MSI where available
authorDavid Woodhouse <dwmw@amazon.co.uk>
Fri, 2 Oct 2020 15:00:55 +0000 (16:00 +0100)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Wed, 7 Oct 2020 09:52:48 +0000 (10:52 +0100)
Some hypervisors can allow the guest to use the Extended Destination ID
field in the IOAPIC RTE and MSI address to address up to 32768 CPUs.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
arch/x86/include/asm/mpspec.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/msi.c
arch/x86/kernel/x86_init.c

index e90ac7e9ae2c6dee1abdac0fc1b3ecc638bf66e7..25ee8ca0a1f28391341e7efde5d4cce13537650e 100644 (file)
@@ -42,6 +42,7 @@ extern DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
 extern unsigned int boot_cpu_physical_apicid;
 extern u8 boot_cpu_apic_version;
 extern unsigned long mp_lapic_addr;
+extern int msi_ext_dest_id;
 
 #ifdef CONFIG_X86_LOCAL_APIC
 extern int smp_found_config;
index 397196fae24d36333bd2c6d4be43fe5041157cce..5af3fe9e38f3cc88074c7a676ca261d2cfc269cb 100644 (file)
@@ -114,6 +114,7 @@ struct x86_init_pci {
  * @init_platform:             platform setup
  * @guest_late_init:           guest late init
  * @x2apic_available:          X2APIC detection
+ * @msi_ext_dest_id:           MSI and IOAPIC support 15-bit APIC IDs
  * @init_mem_mapping:          setup early mappings during init_mem_mapping()
  * @init_after_bootmem:                guest init after boot allocator is finished
  */
@@ -121,6 +122,7 @@ struct x86_hyper_init {
        void (*init_platform)(void);
        void (*guest_late_init)(void);
        bool (*x2apic_available)(void);
+       bool (*msi_ext_dest_id)(void);
        void (*init_mem_mapping)(void);
        void (*init_after_bootmem)(void);
 };
index 113f6ca7b82849fd18271f3661b78b479accc2e6..ba24a343c1f246e0d10fa133046372b3980225fe 100644 (file)
@@ -1837,9 +1837,21 @@ static __init void x2apic_enable(void)
 
 static __init void try_to_enable_x2apic(int remap_mode)
 {
+       u32 apic_limit = 255;
+
        if (x2apic_state == X2APIC_DISABLED)
                return;
 
+       /*
+        * If the hypervisor supports extended destination ID in IOAPIC
+        * and MSI, that increases the maximum APIC ID that can be used
+        * for non-remapped IRQ domains.
+        */
+       if (x86_init.hyper.msi_ext_dest_id()) {
+               msi_ext_dest_id = 1;
+               apic_limit = 32767;
+       }
+
        if (remap_mode != IRQ_REMAP_X2APIC_MODE) {
                /*
                 * Using X2APIC without IR is not architecturally supported
@@ -1856,9 +1868,10 @@ static __init void try_to_enable_x2apic(int remap_mode)
                 * in physical mode, and CPUs with an APIC ID that cannnot
                 * be addressed must not be brought online.
                 */
-               x2apic_set_max_apicid(255);
+               x2apic_set_max_apicid(apic_limit);
                x2apic_phys = 1;
        }
+
        x2apic_enable();
 }
 
index 2825e003259c0457d19a1698f275b33256eee15d..85206f971284a64928c051fee2219ec1d1975e0e 100644 (file)
 
 struct irq_domain *x86_pci_msi_default_domain __ro_after_init;
 
+int msi_ext_dest_id __ro_after_init;
+
 static void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg,
                                  bool dmar)
+
 {
        msg->address_hi = MSI_ADDR_BASE_HI;
 
@@ -46,10 +49,15 @@ static void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg,
         * Only the IOMMU itself can use the trick of putting destination
         * APIC ID into the high bits of the address. Anything else would
         * just be writing to memory if it tried that, and needs IR to
-        * address higher APIC IDs.
+        * address APICs which can't be addressed in the normal 32-bit
+        * address range at 0xFFExxxxx. That is typically just 8 bits, but
+        * some hypervisors allow the extended destination ID field in bits
+        * 11-5 to be used, giving support for 15 bits of APIC IDs in total.
         */
        if (dmar)
                msg->address_hi |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid);
+       else if (msi_ext_dest_id && cfg->dest_apicid < 0x8000)
+               msg->address_lo |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid) >> 3;
        else
                WARN_ON_ONCE(MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid));
 }
index a3038d8deb6a4c98a00b05284a119e061b7985e0..8b395821cb8d022ba7a532f43dfcf01361fe12bf 100644 (file)
@@ -110,6 +110,7 @@ struct x86_init_ops x86_init __initdata = {
                .init_platform          = x86_init_noop,
                .guest_late_init        = x86_init_noop,
                .x2apic_available       = bool_x86_init_noop,
+               .msi_ext_dest_id        = bool_x86_init_noop,
                .init_mem_mapping       = x86_init_noop,
                .init_after_bootmem     = x86_init_noop,
        },