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
45};45};
46 46
47struct ioapic_alloc_info {47struct ioapic_alloc_info {
48 int pin;48 int pin;
49 int node;49 int node;
50 u32 is_level : 1;50 u32 is_level : 1;
51 u32 active_low : 1;51 u32 active_low : 1;
52 u32 valid : 1;52 u32 valid : 1;
53 struct IO_APIC_route_entry *entry;
54};53};
55 54
56struct uv_alloc_info {55struct uv_alloc_info {
arch/x86/kernel/apic/io_apic.c+72−31
@@ -48,6 +48,7 @@ · 47 unmodified lines
48#include <linux/jiffies.h> /* time_after() */48#include <linux/jiffies.h> /* time_after() */
49#include <linux/slab.h>49#include <linux/slab.h>
50#include <linux/memblock.h>50#include <linux/memblock.h>
51#include <linux/msi.h>
51 52
52#include <asm/irqdomain.h>53#include <asm/irqdomain.h>
53#include <asm/io.h>54#include <asm/io.h>
@@ -63,7 +64,6 @@ · 9 unmodified lines
63#include <asm/setup.h>64#include <asm/setup.h>
64#include <asm/irq_remapping.h>65#include <asm/irq_remapping.h>
65#include <asm/hw_irq.h>66#include <asm/hw_irq.h>
66
67#include <asm/apic.h>67#include <asm/apic.h>
68 68
69#define for_each_ioapic(idx) \69#define for_each_ioapic(idx) \
@@ -1848,21 +1848,58 @@ static void ioapic_ir_ack_level(struct irq_data *irq_data) · 1778 unmodified lines
1848 eoi_ioapic_pin(data->entry.vector, data);1848 eoi_ioapic_pin(data->entry.vector, data);
1849}1849}
1850 1850
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 */
1867static 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
1851static void ioapic_configure_entry(struct irq_data *irqd)1896static void ioapic_configure_entry(struct irq_data *irqd)
1852{1897{
1853 struct mp_chip_data *mpd = irqd->chip_data;1898 struct mp_chip_data *mpd = irqd->chip_data;
1854 struct irq_cfg *cfg = irqd_cfg(irqd);
1855 struct irq_pin_list *entry;1899 struct irq_pin_list *entry;
1856 1900
1857 /*1901 ioapic_setup_msg_from_msi(irqd, &mpd->entry);
1858 * Only update when the parent is the vector domain, don't touch it1902
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 }
1866 for_each_irq_pin(entry, mpd->irq_2_pin)1903 for_each_irq_pin(entry, mpd->irq_2_pin)
1867 __ioapic_write_entry(entry->apic, entry->pin, mpd->entry);1904 __ioapic_write_entry(entry->apic, entry->pin, mpd->entry);
1868}1905}
@@ -2919,14 +2956,23 @@ static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data, · 1050 unmodified lines
2919 }2956 }
2920}2957}
2921 2958
2922static void mp_setup_entry(struct irq_cfg *cfg, struct mp_chip_data *data,2959/*
2923 struct IO_APIC_route_entry *entry)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 */
2971static void mp_preconfigure_entry(struct mp_chip_data *data)
2924{2972{
2973 struct IO_APIC_route_entry *entry = &data->entry;
2974
2925 memset(entry, 0, sizeof(*entry));2975 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;
2930 entry->is_level = data->is_level;2976 entry->is_level = data->is_level;
2931 entry->active_low = data->active_low;2977 entry->active_low = data->active_low;
2932 /*2978 /*
@@ -2939,11 +2985,10 @@ static void mp_setup_entry(struct irq_cfg *cfg, struct mp_chip_data *data, · 6 unmodified lines
2939int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,2985int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
2940 unsigned int nr_irqs, void *arg)2986 unsigned int nr_irqs, void *arg)
2941{2987{
2942 int ret, ioapic, pin;
2943 struct irq_cfg *cfg;
2944 struct irq_data *irq_data;
2945 struct mp_chip_data *data;
2946 struct irq_alloc_info *info = arg;2988 struct irq_alloc_info *info = arg;
2989 struct mp_chip_data *data;
2990 struct irq_data *irq_data;
2991 int ret, ioapic, pin;
2947 unsigned long flags;2992 unsigned long flags;
2948 2993
2949 if (!info || nr_irqs > 1)2994 if (!info || nr_irqs > 1)
@@ -2961,7 +3006,6 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, · 11 unmodified lines
2961 if (!data)3006 if (!data)
2962 return -ENOMEM;3007 return -ENOMEM;
2963 3008
2964 info->ioapic.entry = &data->entry;
2965 ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);3009 ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
2966 if (ret < 0) {3010 if (ret < 0) {
2967 kfree(data);3011 kfree(data);
@@ -2975,23 +3019,20 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, · 7 unmodified lines
2975 irq_data->chip_data = data;3019 irq_data->chip_data = data;
2976 mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);3020 mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
2977 3021
2978 cfg = irqd_cfg(irq_data);
2979 add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);3022 add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
2980 3023
2981 local_irq_save(flags);3024 mp_preconfigure_entry(data);
2982 if (info->ioapic.entry)
2983 mp_setup_entry(cfg, data, info->ioapic.entry);
2984 mp_register_handler(virq, data->is_level);3025 mp_register_handler(virq, data->is_level);
3026
3027 local_irq_save(flags);
2985 if (virq < nr_legacy_irqs())3028 if (virq < nr_legacy_irqs())
2986 legacy_pic->mask(virq);3029 legacy_pic->mask(virq);
2987 local_irq_restore(flags);3030 local_irq_restore(flags);
2988 3031
2989 apic_printk(APIC_VERBOSE, KERN_DEBUG3032 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",3033 "IOAPIC[%d]: Preconfigured routing entry (%d-%d -> IRQ %d Level:%i ActiveLow:%i)\n",
2991 ioapic, mpc_ioapic_id(ioapic), pin, cfg->vector,3034 ioapic, mpc_ioapic_id(ioapic), pin, virq,
2992 virq, data->is_level, data->active_low,3035 data->is_level, data->active_low);
2993 cfg->dest_apicid);
2994
2995 return 0;3036 return 0;
2996}3037}
2997 3038
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
3669 int devid, int index, int sub_handle)3669 int devid, int index, int sub_handle)
3670{3670{
3671 struct irq_2_irte *irte_info = &data->irq_2_irte;3671 struct irq_2_irte *irte_info = &data->irq_2_irte;
3672 struct IO_APIC_route_entry *entry;
3673 struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];3672 struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
3674 3673
3675 if (!iommu)3674 if (!iommu)
@@ -3683,17 +3682,6 @@ static void irq_remapping_prepare_irte(struct amd_ir_data *data, · 7 unmodified lines
3683 3682
3684 switch (info->type) {3683 switch (info->type) {
3685 case X86_IRQ_ALLOC_TYPE_IOAPIC:3684 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
3697 case X86_IRQ_ALLOC_TYPE_HPET:3685 case X86_IRQ_ALLOC_TYPE_HPET:
3698 case X86_IRQ_ALLOC_TYPE_PCI_MSI:3686 case X86_IRQ_ALLOC_TYPE_PCI_MSI:
3699 case X86_IRQ_ALLOC_TYPE_PCI_MSIX:3687 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
40{40{
41 struct irq_data *parent = data->parent_data;41 struct irq_data *parent = data->parent_data;
42 struct irq_cfg *cfg = irqd_cfg(data);42 struct irq_cfg *cfg = irqd_cfg(data);
43 struct IO_APIC_route_entry *entry;
44 int ret;43 int ret;
45 44
46 /* Return error If new irq affinity is out of ioapic_max_cpumask. */45 /* 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
51 if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)50 if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
52 return ret;51 return ret;
53 52
54 entry = data->chip_data;
55 entry->destid_0_7 = cfg->dest_apicid;
56 entry->vector = cfg->vector;
57 send_cleanup_vector(cfg);53 send_cleanup_vector(cfg);
58 54
59 return 0;55 return 0;
@@ -89,20 +85,6 @@ static int hyperv_irq_remapping_alloc(struct irq_domain *domain, · 29 unmodified lines
89 85
90 irq_data->chip = &hyperv_ir_chip;86 irq_data->chip = &hyperv_ir_chip;
91 87
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
106 /*88 /*
107 * Hypver-V IO APIC irq affinity should be in the scope of89 * Hypver-V IO APIC irq affinity should be in the scope of
108 * ioapic_max_cpumask because no irq remapping support.90 * 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
119 irq_domain_free_irqs_common(domain, virq, nr_irqs);101 irq_domain_free_irqs_common(domain, virq, nr_irqs);
120}102}
121 103
122static 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
134static const struct irq_domain_ops hyperv_ir_domain_ops = {104static const struct irq_domain_ops hyperv_ir_domain_ops = {
135 .alloc = hyperv_irq_remapping_alloc,105 .alloc = hyperv_irq_remapping_alloc,
136 .free = hyperv_irq_remapping_free,106 .free = hyperv_irq_remapping_free,
137 .activate = hyperv_irq_remapping_activate,
138};107};
139 108
140static int __init hyperv_prepare_irq_remapping(void)109static 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
1280 int index, int sub_handle)1280 int index, int sub_handle)
1281{1281{
1282 struct irte *irte = &data->irte_entry;1282 struct irte *irte = &data->irte_entry;
1283 struct IO_APIC_route_entry *entry;
1284 1283
1285 prepare_irte(irte, irq_cfg->vector, irq_cfg->dest_apicid);1284 prepare_irte(irte, irq_cfg->vector, irq_cfg->dest_apicid);
1285
1286 switch (info->type) {1286 switch (info->type) {
1287 case X86_IRQ_ALLOC_TYPE_IOAPIC:1287 case X86_IRQ_ALLOC_TYPE_IOAPIC:
1288 /* Set source-id of interrupt request */1288 /* 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
1293 irte->trigger_mode, irte->dlvry_mode,1293 irte->trigger_mode, irte->dlvry_mode,
1294 irte->avail, irte->vector, irte->dest_id,1294 irte->avail, irte->vector, irte->dest_id,
1295 irte->sid, irte->sq, irte->svt);1295 irte->sid, irte->sq, irte->svt);
1296 1296 sub_handle = info->ioapic.pin;
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;
1312 break;1297 break;
1313
1314 case X86_IRQ_ALLOC_TYPE_HPET:1298 case X86_IRQ_ALLOC_TYPE_HPET:
1299 set_hpet_sid(irte, info->devid);
1300 break;
1315 case X86_IRQ_ALLOC_TYPE_PCI_MSI:1301 case X86_IRQ_ALLOC_TYPE_PCI_MSI:
1316 case X86_IRQ_ALLOC_TYPE_PCI_MSIX:1302 case X86_IRQ_ALLOC_TYPE_PCI_MSIX:
1317 if (info->type == X86_IRQ_ALLOC_TYPE_HPET)1303 set_msi_sid(irte, msi_desc_to_pci_dev(info->desc));
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);
1323 break;1304 break;
1324
1325 default:1305 default:
1326 BUG_ON(1);1306 BUG_ON(1);
1327 break;1307 break;
1328 }1308 }
1309 fill_msi_msg(&data->msi_entry, index, sub_handle);
1329}1310}
1330 1311
1331static void intel_free_irq_resources(struct irq_domain *domain,1312static 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