History

x86/ioapic: Generate RTE directly from parent irqchip's MSI message

The I/O-APIC generates an MSI cycle with address/data bits taken from its Redirection Table Entry in some combination which used to make sense, but now is just a bunch of bits which get passed through in some seemingly arbitrary order. Instead of making IRQ remapping drivers directly frob the I/OA-PIC RTE, let them just do their job and generate an MSI message. The bit swizzling to turn that MSI message into the I/O-APIC's RTE is the same in all cases, since it's a function of the I/O-APIC hardware. The IRQ remappers have no real need to get involved with that. The only slight caveat is that the I/OAPIC is interpreting some of those fields too, and it does want the 'vector' field to be unique to make EOI work. The AMD IOMMU happens to put its IRTE index in the bits that the I/O-APIC thinks are the vector field, and accommodates this requirement by reserving the first 32 indices for the I/O-APIC. The Intel IOMMU doesn't actually use the bits that the I/O-APIC thinks are the vector field, so it fills in the 'pin' value there instead. [ tglx: Replaced the unreadably macro maze with the cleaned up RTE/msi_msg bitfields and added commentry to explain the mapping magic ]

David Woodhouse committed 6 years ago

Commit 5d5a9711 parent 341b4a75 files · +83 −105Browse files

Unified · Split

5 files
  1. arch/x86/include/asm/hw_irq.h +5 −6
  2. arch/x86/kernel/apic/io_apic.c +72 −31
  3. drivers/iommu/amd/iommu.c +0 −12
  4. drivers/iommu/hyperv-iommu.c +0 −31
  5. drivers/iommu/intel/irq_remapping.c +6 −25
arch/x86/include/asm/hw_irq.h+5−6
@@ -45,12 +45,11 @@ enum irq_alloc_type { · 44 unmodified lines
4545 };
4646
4747 struct ioapic_alloc_info {
48− int pin;
49− int node;
50− u32 is_level : 1;
51− u32 active_low : 1;
52− u32 valid : 1;
53− struct IO_APIC_route_entry *entry;
48+ int pin;
49+ int node;
50+ u32 is_level : 1;
51+ u32 active_low : 1;
52+ u32 valid : 1;
5453 };
5554
5655 struct uv_alloc_info {
arch/x86/kernel/apic/io_apic.c+72−31
@@ -48,6 +48,7 @@ · 47 unmodified lines
4848 #include <linux/jiffies.h> /* time_after() */
4949 #include <linux/slab.h>
5050 #include <linux/memblock.h>
51+#include <linux/msi.h>
5152
5253 #include <asm/irqdomain.h>
5354 #include <asm/io.h>
@@ -63,7 +64,6 @@ · 9 unmodified lines
6364 #include <asm/setup.h>
6465 #include <asm/irq_remapping.h>
6566 #include <asm/hw_irq.h>
66−
6767 #include <asm/apic.h>
6868
6969 #define for_each_ioapic(idx) \
@@ -1848,21 +1848,58 @@ static void ioapic_ir_ack_level(struct irq_data *irq_data) · 1778 unmodified lines
18481848 eoi_ioapic_pin(data->entry.vector, data);
18491849 }
18501850
1851+/*
1852+ * The I/OAPIC is just a device for generating MSI messages from legacy
1853+ * interrupt pins. Various fields of the RTE translate into bits of the
1854+ * resulting MSI which had a historical meaning.
1855+ *
1856+ * With interrupt remapping, many of those bits have different meanings
1857+ * in the underlying MSI, but the way that the I/OAPIC transforms them
1858+ * from its RTE to the MSI message is the same. This function allows
1859+ * the parent IRQ domain to compose the MSI message, then takes the
1860+ * relevant bits to put them in the appropriate places in the RTE in
1861+ * order to generate that message when the IRQ happens.
1862+ *
1863+ * The setup here relies on a preconfigured route entry (is_level,
1864+ * active_low, masked) because the parent domain is merely composing the
1865+ * generic message routing information which is used for the MSI.
1866+ */
1867+static void ioapic_setup_msg_from_msi(struct irq_data *irq_data,
1868+ struct IO_APIC_route_entry *entry)
1869+{
1870+ struct msi_msg msg;
1871+
1872+ /* Let the parent domain compose the MSI message */
1873+ irq_chip_compose_msi_msg(irq_data, &msg);
1874+
1875+ /*
1876+ * - Real vector
1877+ * - DMAR/IR: 8bit subhandle (ioapic.pin)
1878+ * - AMD/IR: 8bit IRTE index
1879+ */
1880+ entry->vector = msg.arch_data.vector;
1881+ /* Delivery mode (for DMAR/IR all 0) */
1882+ entry->delivery_mode = msg.arch_data.delivery_mode;
1883+ /* Destination mode or DMAR/IR index bit 15 */
1884+ entry->dest_mode_logical = msg.arch_addr_lo.dest_mode_logical;
1885+ /* DMAR/IR: 1, 0 for all other modes */
1886+ entry->ir_format = msg.arch_addr_lo.dmar_format;
1887+ /*
1888+ * DMAR/IR: index bit 0-14.
1889+ *
1890+ * All other modes have bit 0-6 of dmar_index_0_14 cleared and the
1891+ * topmost 8 bits are destination id bit 0-7 (entry::destid_0_7).
1892+ */
1893+ entry->ir_index_0_14 = msg.arch_addr_lo.dmar_index_0_14;
1894+}
1895+
18511896 static void ioapic_configure_entry(struct irq_data *irqd)
18521897 {
18531898 struct mp_chip_data *mpd = irqd->chip_data;
1854− struct irq_cfg *cfg = irqd_cfg(irqd);
18551899 struct irq_pin_list *entry;
18561900
1857− /*
1858− * Only update when the parent is the vector domain, don't touch it
1859− * if the parent is the remapping domain. Check the installed
1860− * ioapic chip to verify that.
1861− */
1862− if (irqd->chip == &ioapic_chip) {
1863− mpd->entry.destid_0_7 = cfg->dest_apicid;
1864− mpd->entry.vector = cfg->vector;
1865− }
1901+ ioapic_setup_msg_from_msi(irqd, &mpd->entry);
1902+
18661903 for_each_irq_pin(entry, mpd->irq_2_pin)
18671904 __ioapic_write_entry(entry->apic, entry->pin, mpd->entry);
18681905 }
@@ -2919,14 +2956,23 @@ static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data, · 1050 unmodified lines
29192956 }
29202957 }
29212958
2922−static void mp_setup_entry(struct irq_cfg *cfg, struct mp_chip_data *data,
2923− struct IO_APIC_route_entry *entry)
2959+/*
2960+ * Configure the I/O-APIC specific fields in the routing entry.
2961+ *
2962+ * This is important to setup the I/O-APIC specific bits (is_level,
2963+ * active_low, masked) because the underlying parent domain will only
2964+ * provide the routing information and is oblivious of the I/O-APIC
2965+ * specific bits.
2966+ *
2967+ * The entry is just preconfigured at this point and not written into the
2968+ * RTE. This happens later during activation which will fill in the actual
2969+ * routing information.
2970+ */
2971+static void mp_preconfigure_entry(struct mp_chip_data *data)
29242972 {
2973+ struct IO_APIC_route_entry *entry = &data->entry;
2974+
29252975 memset(entry, 0, sizeof(*entry));
2926− entry->delivery_mode = apic->delivery_mode;
2927− entry->dest_mode_logical = apic->dest_mode_logical;
2928− entry->destid_0_7 = cfg->dest_apicid;
2929− entry->vector = cfg->vector;
29302976 entry->is_level = data->is_level;
29312977 entry->active_low = data->active_low;
29322978 /*
@@ -2939,11 +2985,10 @@ static void mp_setup_entry(struct irq_cfg *cfg, struct mp_chip_data *data, · 6 unmodified lines
29392985 int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
29402986 unsigned int nr_irqs, void *arg)
29412987 {
2942− int ret, ioapic, pin;
2943− struct irq_cfg *cfg;
2944− struct irq_data *irq_data;
2945− struct mp_chip_data *data;
29462988 struct irq_alloc_info *info = arg;
2989+ struct mp_chip_data *data;
2990+ struct irq_data *irq_data;
2991+ int ret, ioapic, pin;
29472992 unsigned long flags;
29482993
29492994 if (!info || nr_irqs > 1)
@@ -2961,7 +3006,6 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, · 11 unmodified lines
29613006 if (!data)
29623007 return -ENOMEM;
29633008
2964− info->ioapic.entry = &data->entry;
29653009 ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
29663010 if (ret < 0) {
29673011 kfree(data);
@@ -2975,23 +3019,20 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, · 7 unmodified lines
29753019 irq_data->chip_data = data;
29763020 mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
29773021
2978− cfg = irqd_cfg(irq_data);
29793022 add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
29803023
2981− local_irq_save(flags);
2982− if (info->ioapic.entry)
2983− mp_setup_entry(cfg, data, info->ioapic.entry);
3024+ mp_preconfigure_entry(data);
29843025 mp_register_handler(virq, data->is_level);
3026+
3027+ local_irq_save(flags);
29853028 if (virq < nr_legacy_irqs())
29863029 legacy_pic->mask(virq);
29873030 local_irq_restore(flags);
29883031
29893032 apic_printk(APIC_VERBOSE, KERN_DEBUG
2990− "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n",
2991− ioapic, mpc_ioapic_id(ioapic), pin, cfg->vector,
2992− virq, data->is_level, data->active_low,
2993− cfg->dest_apicid);
2994−
3033+ "IOAPIC[%d]: Preconfigured routing entry (%d-%d -> IRQ %d Level:%i ActiveLow:%i)\n",
3034+ ioapic, mpc_ioapic_id(ioapic), pin, virq,
3035+ data->is_level, data->active_low);
29953036 return 0;
29963037 }
29973038
drivers/iommu/amd/iommu.c+0−12
@@ -3669,7 +3669,6 @@ static void irq_remapping_prepare_irte(struct amd_ir_data *data, · 3668 unmodified lines
36693669 int devid, int index, int sub_handle)
36703670 {
36713671 struct irq_2_irte *irte_info = &data->irq_2_irte;
3672− struct IO_APIC_route_entry *entry;
36733672 struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
36743673
36753674 if (!iommu)
@@ -3683,17 +3682,6 @@ static void irq_remapping_prepare_irte(struct amd_ir_data *data, · 7 unmodified lines
36833682
36843683 switch (info->type) {
36853684 case X86_IRQ_ALLOC_TYPE_IOAPIC:
3686− /* Setup IOAPIC entry */
3687− entry = info->ioapic.entry;
3688− info->ioapic.entry = NULL;
3689− memset(entry, 0, sizeof(*entry));
3690− entry->vector = index;
3691− entry->is_level = info->ioapic.is_level;
3692− entry->active_low = info->ioapic.active_low;
3693− /* Mask level triggered irqs. */
3694− entry->masked = info->ioapic.is_level;
3695− break;
3696−
36973685 case X86_IRQ_ALLOC_TYPE_HPET:
36983686 case X86_IRQ_ALLOC_TYPE_PCI_MSI:
36993687 case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
drivers/iommu/hyperv-iommu.c+0−31
@@ -40,7 +40,6 @@ static int hyperv_ir_set_affinity(struct irq_data *data, · 39 unmodified lines
4040 {
4141 struct irq_data *parent = data->parent_data;
4242 struct irq_cfg *cfg = irqd_cfg(data);
43− struct IO_APIC_route_entry *entry;
4443 int ret;
4544
4645 /* Return error If new irq affinity is out of ioapic_max_cpumask. */
@@ -51,9 +50,6 @@ static int hyperv_ir_set_affinity(struct irq_data *data, · 4 unmodified lines
5150 if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
5251 return ret;
5352
54− entry = data->chip_data;
55− entry->destid_0_7 = cfg->dest_apicid;
56− entry->vector = cfg->vector;
5753 send_cleanup_vector(cfg);
5854
5955 return 0;
@@ -89,20 +85,6 @@ static int hyperv_irq_remapping_alloc(struct irq_domain *domain, · 29 unmodified lines
8985
9086 irq_data->chip = &hyperv_ir_chip;
9187
92− /*
93− * If there is interrupt remapping function of IOMMU, setting irq
94− * affinity only needs to change IRTE of IOMMU. But Hyper-V doesn't
95− * support interrupt remapping function, setting irq affinity of IO-APIC
96− * interrupts still needs to change IO-APIC registers. But ioapic_
97− * configure_entry() will ignore value of cfg->vector and cfg->
98− * dest_apicid when IO-APIC's parent irq domain is not the vector
99− * domain.(See ioapic_configure_entry()) In order to setting vector
100− * and dest_apicid to IO-APIC register, IO-APIC entry pointer is saved
101− * in the chip_data and hyperv_irq_remapping_activate()/hyperv_ir_set_
102− * affinity() set vector and dest_apicid directly into IO-APIC entry.
103− */
104− irq_data->chip_data = info->ioapic.entry;
105−
10688 /*
10789 * Hypver-V IO APIC irq affinity should be in the scope of
10890 * ioapic_max_cpumask because no irq remapping support.
@@ -119,22 +101,9 @@ static void hyperv_irq_remapping_free(struct irq_domain *domain, · 10 unmodified lines
119101 irq_domain_free_irqs_common(domain, virq, nr_irqs);
120102 }
121103
122−static int hyperv_irq_remapping_activate(struct irq_domain *domain,
123− struct irq_data *irq_data, bool reserve)
124−{
125− struct irq_cfg *cfg = irqd_cfg(irq_data);
126− struct IO_APIC_route_entry *entry = irq_data->chip_data;
127−
128− entry->destid_0_7 = cfg->dest_apicid;
129− entry->vector = cfg->vector;
130−
131− return 0;
132−}
133−
134104 static const struct irq_domain_ops hyperv_ir_domain_ops = {
135105 .alloc = hyperv_irq_remapping_alloc,
136106 .free = hyperv_irq_remapping_free,
137− .activate = hyperv_irq_remapping_activate,
138107 };
139108
140109 static int __init hyperv_prepare_irq_remapping(void)
drivers/iommu/intel/irq_remapping.c+6−25
@@ -1280,9 +1280,9 @@ static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data, · 1279 unmodified lines
12801280 int index, int sub_handle)
12811281 {
12821282 struct irte *irte = &data->irte_entry;
1283− struct IO_APIC_route_entry *entry;
12841283
12851284 prepare_irte(irte, irq_cfg->vector, irq_cfg->dest_apicid);
1285+
12861286 switch (info->type) {
12871287 case X86_IRQ_ALLOC_TYPE_IOAPIC:
12881288 /* Set source-id of interrupt request */
@@ -1293,39 +1293,20 @@ static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data, · 4 unmodified lines
12931293 irte->trigger_mode, irte->dlvry_mode,
12941294 irte->avail, irte->vector, irte->dest_id,
12951295 irte->sid, irte->sq, irte->svt);
1296−
1297− entry = info->ioapic.entry;
1298− info->ioapic.entry = NULL;
1299− memset(entry, 0, sizeof(*entry));
1300− entry->ir_index_15 = !!(index & 0x8000);
1301− entry->ir_format = true;
1302− entry->ir_index_0_14 = index & 0x7fff;
1303− /*
1304− * IO-APIC RTE will be configured with virtual vector.
1305− * irq handler will do the explicit EOI to the io-apic.
1306− */
1307− entry->vector = info->ioapic.pin;
1308− entry->is_level = info->ioapic.is_level;
1309− entry->active_low = info->ioapic.active_low;
1310− /* Mask level triggered irqs. */
1311− entry->masked = info->ioapic.is_level;
1296+ sub_handle = info->ioapic.pin;
13121297 break;
1313−
13141298 case X86_IRQ_ALLOC_TYPE_HPET:
1299+ set_hpet_sid(irte, info->devid);
1300+ break;
13151301 case X86_IRQ_ALLOC_TYPE_PCI_MSI:
13161302 case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
1317− if (info->type == X86_IRQ_ALLOC_TYPE_HPET)
1318− set_hpet_sid(irte, info->devid);
1319− else
1320− set_msi_sid(irte, msi_desc_to_pci_dev(info->desc));
1321−
1322− fill_msi_msg(&data->msi_entry, index, sub_handle);
1303+ set_msi_sid(irte, msi_desc_to_pci_dev(info->desc));
13231304 break;
1324−
13251305 default:
13261306 BUG_ON(1);
13271307 break;
13281308 }
1309+ fill_msi_msg(&data->msi_entry, index, sub_handle);
13291310 }
13301311
13311312 static void intel_free_irq_resources(struct irq_domain *domain,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t