]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
x86/ioapic: Handle Extended Destination ID field in RTE
authorDavid Woodhouse <dwmw@amazon.co.uk>
Fri, 2 Oct 2020 13:49:42 +0000 (14:49 +0100)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Fri, 23 Oct 2020 16:25:50 +0000 (17:25 +0100)
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.

This enlightenment could theoretically be transparent to the I/OAPIC
code if it were always generating its RTE from an MSI message created by
the parent irqchip. That cleanup will happen separately but doesn't cover
all cases — for the ExtINT hackery and restoring boot mode, RTEs are
still generated locally. So we have to teach the I/OAPIC about the
ext_dest bits anyway.

No behavioural change in this patch, since nothing yet permits APIC IDs
above 255 to be used with the non-IR I/OAPIC domain.

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

index a1a26f6d3aa49abd1315d50f4f1c3b4d768db269..5bb3cf4ff2fdd716a7da4d68de77b14530551a24 100644 (file)
@@ -78,7 +78,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));
 
index a33380059db617f921df9d78967b3b65cb035354..54f6a029b1d1046bbbfcb66d4e1db92ca1b791d6 100644 (file)
@@ -1239,10 +1239,10 @@ static void io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
                               buf, (ir_entry->index2 << 15) | ir_entry->index,
                               ir_entry->zero);
                else
-                       printk(KERN_DEBUG "%s, %s, D(%02X), M(%1d)\n",
+                       printk(KERN_DEBUG "%s, %s, D(%02X%02X), M(%1d)\n",
                               buf,
                               entry.dest_mode == IOAPIC_DEST_MODE_LOGICAL ?
-                              "logical " : "physical",
+                              "logical " : "physical", entry.virt_ext_dest,
                               entry.dest, entry.delivery_mode);
        }
 }
@@ -1410,6 +1410,7 @@ void native_restore_boot_irq_mode(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              = IOAPIC_UNMASKED;
@@ -1417,7 +1418,8 @@ void native_restore_boot_irq_mode(void)
                entry.polarity          = IOAPIC_POL_HIGH;
                entry.dest_mode         = IOAPIC_DEST_MODE_PHYSICAL;
                entry.delivery_mode     = dest_ExtINT;
-               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:
@@ -1861,7 +1863,8 @@ static void ioapic_configure_entry(struct irq_data *irqd)
         * ioapic chip to verify that.
         */
        if (irqd->chip == &ioapic_chip) {
-               mpd->entry.dest = cfg->dest_apicid;
+               mpd->entry.dest = cfg->dest_apicid & 0xff;
+               mpd->entry.virt_ext_dest = cfg->dest_apicid >> 8;
                mpd->entry.vector = cfg->vector;
        }
        for_each_irq_pin(entry, mpd->irq_2_pin)
@@ -2027,6 +2030,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) {
@@ -2042,11 +2046,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 = IOAPIC_DEST_MODE_PHYSICAL;
        entry1.mask = IOAPIC_UNMASKED;
-       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 = IOAPIC_EDGE;
@@ -2949,7 +2955,8 @@ static void mp_setup_entry(struct irq_cfg *cfg, struct mp_chip_data *data,
        memset(entry, 0, sizeof(*entry));
        entry->delivery_mode = apic->irq_delivery_mode;
        entry->dest_mode     = apic->irq_dest_mode;
-       entry->dest          = cfg->dest_apicid;
+       entry->dest          = cfg->dest_apicid & 0xff;
+       entry->virt_ext_dest = cfg->dest_apicid >> 8;
        entry->vector        = cfg->vector;
        entry->trigger       = data->trigger;
        entry->polarity      = data->polarity;