]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
x86/ioapic: Handle Extended Destination ID field in RTE
authorDavid Woodhouse <dwmw@amazon.co.uk>
Sat, 24 Oct 2020 21:35:31 +0000 (22:35 +0100)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Fri, 6 Aug 2021 17:32:51 +0000 (18:32 +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.

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 <dwmw@amazon.co.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20201024213535.443185-32-dwmw2@infradead.org
(cherry picked from commit 51130d21881d435fad5fa7f25bea77aa0ffc9a4e)

arch/x86/include/asm/io_apic.h
arch/x86/kernel/apic/io_apic.c

index 2f91685fe1cdb51d937eb20d29c46952d54f298f..fb989cb350bdff054dbd6fc48289742654a838f3 100644 (file)
@@ -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));
 
index 484ffab4d3e8567ae7e24454e419255160298421..08df2309c64ae704c90a6a7eebddf123669f31e6 100644 (file)
@@ -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;