Blob Blame History Raw
From: David Woodhouse <dwmw@amazon.co.uk>
Date: Sat, 24 Oct 2020 22:35:31 +0100
Subject: x86/ioapic: Handle Extended Destination ID field in RTE
Git-commit: 51130d21881d435fad5fa7f25bea77aa0ffc9a4e
Patch-mainline: 5.11-rc1
References: bsc#1181001 jsc#ECO-3191

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 ]

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
Acked-by: Joerg Roedel <jroedel@suse.de>
---
 arch/x86/include/asm/io_apic.h |    3 ++-
 arch/x86/kernel/apic/io_apic.c |   20 ++++++++++++++------
 2 files changed, 16 insertions(+), 7 deletions(-)

--- 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_destid_8_14:  7,
 		dest		:  8;
 } __attribute__ ((packed));
 
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1268,11 +1268,12 @@ static void io_apic_print_entries(unsign
 			       buf, (ir_entry->index << 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",
-			       entry.dest, entry.delivery_mode);
+			       entry.virt_destid_8_14, entry.dest,
+			       entry.delivery_mode);
 	}
 }
 
@@ -1439,6 +1440,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		= IOAPIC_UNMASKED;
@@ -1446,7 +1448,8 @@ void native_disable_io_apic(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_destid_8_14	= apic_id >> 8;
 
 		/*
 		 * Add it to the IO-APIC irq-routing table:
@@ -1861,7 +1864,8 @@ static int ioapic_set_affinity(struct ir
 	raw_spin_lock_irqsave(&ioapic_lock, flags);
 	if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
 		cfg = irqd_cfg(irq_data);
-		data->entry.dest = cfg->dest_apicid;
+		data->entry.dest = cfg->dest_apicid & 0xFF;
+		data->entry.virt_destid_8_14 = cfg->dest_apicid >> 8;
 		data->entry.vector = cfg->vector;
 		for_each_irq_pin(entry, data->irq_2_pin)
 			__ioapic_write_entry(entry->apic, entry->pin,
@@ -1969,6 +1973,7 @@ static inline void __init unlock_ExtINT_
 	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) {
@@ -1984,11 +1989,13 @@ static inline void __init unlock_ExtINT_
 	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_destid_8_14 = apic_id >> 8;
 	entry1.delivery_mode = dest_ExtINT;
 	entry1.polarity = entry0.polarity;
 	entry1.trigger = IOAPIC_EDGE;
@@ -2896,7 +2903,8 @@ static void mp_setup_entry(struct irq_cf
 	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_destid_8_14 = cfg->dest_apicid >> 8;
 	entry->vector	     = cfg->vector;
 	entry->trigger	     = data->trigger;
 	entry->polarity	     = data->polarity;