From: David Woodhouse Date: Sat, 24 Oct 2020 21:35:31 +0000 (+0100) Subject: x86/ioapic: Handle Extended Destination ID field in RTE X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=db83d2a658e3c6c58c5bcab691b0603129c69c90;p=users%2Fdwmw2%2Flinux.git x86/ioapic: Handle Extended Destination ID field in RTE Bits 63-48 of the I/OAPIC Redirection Table Entry map directly to bits 19-4 of the address used in the resulting MSI cycle. Historically, the x86 MSI format only used the top 8 of those 16 bits as the destination APIC ID, and the "Extended Destination ID" in the lower 8 bits was unused. With interrupt remapping, the lowest bit of the Extended Destination ID (bit 48 of RTE, bit 4 of MSI address) is now used to indicate a remappable format MSI. A hypervisor can use the other 7 bits of the Extended Destination ID to permit guests to address up to 15 bits of APIC IDs, thus allowing 32768 vCPUs before having to expose a vIOMMU and interrupt remapping to the guest. No behavioural change in this patch, since nothing yet permits APIC IDs above 255 to be used with the non-IR I/OAPIC domain. [ tglx: Converted it to the cleaned up entry/msi_msg format and added commentry ] [ dwmw2: Undid that for backport ] Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20201024213535.443185-32-dwmw2@infradead.org (cherry picked from commit 51130d21881d435fad5fa7f25bea77aa0ffc9a4e) --- diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 2f91685fe1cdb..fb989cb350bdf 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -77,7 +77,8 @@ struct IO_APIC_route_entry { mask : 1, /* 0: enabled, 1: disabled */ __reserved_2 : 15; - __u32 __reserved_3 : 24, + __u32 __reserved_3 : 17, + virt_ext_dest : 7, dest : 8; } __attribute__ ((packed)); diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 484ffab4d3e85..08df2309c64ae 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1221,7 +1221,8 @@ int native_setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, entry->delivery_mode = apic->irq_delivery_mode; entry->dest_mode = apic->irq_dest_mode; - entry->dest = destination; + entry->dest = destination & 0xff; + entry->virt_ext_dest = destination >> 8; entry->vector = vector; entry->mask = 0; /* enable IRQ */ entry->trigger = attr->trigger; @@ -1349,7 +1350,7 @@ void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries) entry = ioapic_read_entry(apic, i); - pr_debug(" %02x %02X ", i, entry.dest); + pr_debug(" %02x %02X%02X ", i, entry.virt_ext_dest, entry.dest); pr_cont("%1d %1d %1d %1d %1d " "%1d %1d %02X\n", entry.mask, @@ -1562,6 +1563,7 @@ void native_disable_io_apic(void) */ if (ioapic_i8259.pin != -1) { struct IO_APIC_route_entry entry; + u32 apic_id = read_apic_id(); memset(&entry, 0, sizeof(entry)); entry.mask = 0; /* Enabled */ @@ -1572,7 +1574,8 @@ void native_disable_io_apic(void) entry.dest_mode = 0; /* Physical */ entry.delivery_mode = dest_ExtINT; /* ExtInt */ entry.vector = 0; - entry.dest = read_apic_id(); + entry.dest = apic_id & 0xff; + entry.virt_ext_dest = apic_id >> 8; /* * Add it to the IO-APIC irq-routing table: @@ -1853,9 +1856,11 @@ int native_ioapic_set_affinity(struct irq_data *data, raw_spin_lock_irqsave(&ioapic_lock, flags); ret = apic_set_affinity(data, mask, &dest); if (!ret) { - /* Only the high 8 bits are valid. */ - dest = SET_APIC_LOGICAL_ID(dest); - __target_IO_APIC_irq(irq, dest, irqd_cfg(data)); + u32 destreg = (dest & 0xff) << 24; + if (x2apic_enabled()) + destreg |= (dest & 0x7f00) << 9; + + __target_IO_APIC_irq(irq, destreg, irqd_cfg(data)); ret = IRQ_SET_MASK_OK_NOCOPY; } raw_spin_unlock_irqrestore(&ioapic_lock, flags); @@ -2096,6 +2101,7 @@ static inline void __init unlock_ExtINT_logic(void) int apic, pin, i; struct IO_APIC_route_entry entry0, entry1; unsigned char save_control, save_freq_select; + u32 apic_id; pin = find_isa_irq_pin(8, mp_INT); if (pin == -1) { @@ -2111,11 +2117,13 @@ static inline void __init unlock_ExtINT_logic(void) entry0 = ioapic_read_entry(apic, pin); clear_IO_APIC_pin(apic, pin); + apic_id = hard_smp_processor_id(); memset(&entry1, 0, sizeof(entry1)); entry1.dest_mode = 0; /* physical delivery */ entry1.mask = 0; /* unmask IRQ now */ - entry1.dest = hard_smp_processor_id(); + entry1.dest = apic_id & 0xff; + entry1.virt_ext_dest = apic_id >> 8; entry1.delivery_mode = dest_ExtINT; entry1.polarity = entry0.polarity; entry1.trigger = 0;