From 70733e0c7ed22177e2cfe660fa2a0e90f1f39126 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:33 +0200 Subject: x86, apic: Move irq_remapping_enabled checks into IRQ-remapping code Move the three easy to move checks in the x86' apic.c file into the IRQ-remapping code. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index faf85d6e33fe..19381b90e619 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -87,7 +87,9 @@ int __init irq_remapping_enable(void) void irq_remapping_disable(void) { - if (!remap_ops || !remap_ops->disable) + if (!irq_remapping_enabled || + !remap_ops || + !remap_ops->disable) return; remap_ops->disable(); @@ -95,7 +97,9 @@ void irq_remapping_disable(void) int irq_remapping_reenable(int mode) { - if (!remap_ops || !remap_ops->reenable) + if (!irq_remapping_enabled || + !remap_ops || + !remap_ops->reenable) return 0; return remap_ops->reenable(mode); @@ -103,6 +107,9 @@ int irq_remapping_reenable(int mode) int __init irq_remap_enable_fault_handling(void) { + if (!irq_remapping_enabled) + return 0; + if (!remap_ops || !remap_ops->enable_faulting) return -ENODEV; -- cgit v1.2.1 From 1c4248ca4e783e47cc34e313d9f82b4ea52774cc Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:35 +0200 Subject: x86, io_apic: Introduce x86_io_apic_ops.disable() This function pointer is used to call a system-specific function for disabling the IO-APIC. Currently this is used for IRQ remapping which has its own disable routine. Also introduce the necessary infrastructure in the interrupt remapping code to overwrite this and other function pointers as necessary by interrupt remapping. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 19381b90e619..db3dcaf4ddf0 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,6 +7,9 @@ #include #include +#include +#include +#include #include "irq_remapping.h" @@ -17,6 +21,24 @@ int no_x2apic_optout; static struct irq_remap_ops *remap_ops; +static void irq_remapping_disable_io_apic(void) +{ + /* + * With interrupt-remapping, for now we will use virtual wire A + * mode, as virtual wire B is little complex (need to configure + * both IOAPIC RTE as well as interrupt-remapping table entry). + * As this gets called during crash dump, keep this simple for + * now. + */ + if (cpu_has_apic || apic_from_smp_config()) + disconnect_bsp_APIC(0); +} + +static void __init irq_remapping_modify_x86_ops(void) +{ + x86_io_apic_ops.disable = irq_remapping_disable_io_apic; +} + static __init int setup_nointremap(char *str) { disable_irq_remap = 1; @@ -79,10 +101,17 @@ int __init irq_remapping_prepare(void) int __init irq_remapping_enable(void) { + int ret; + if (!remap_ops || !remap_ops->enable) return -ENODEV; - return remap_ops->enable(); + ret = remap_ops->enable(); + + if (irq_remapping_enabled) + irq_remapping_modify_x86_ops(); + + return ret; } void irq_remapping_disable(void) -- cgit v1.2.1 From afcc8a40a090f7a65d3b72bac1a26fc6dbb63b10 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:36 +0200 Subject: x86, io_apic: Introduce x86_io_apic_ops.print_entries for debugging This call-back is used to dump IO-APIC entries for debugging purposes into the kernel log. VT-d needs a special routine for this and will overwrite the default. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/intel_irq_remapping.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index af8904de1d44..cb9a72d4cc09 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -617,6 +617,14 @@ static int __init intel_enable_irq_remapping(void) goto error; irq_remapping_enabled = 1; + + /* + * VT-d has a different layout for IO-APIC entries when + * interrupt remapping is enabled. So it needs a special routine + * to print IO-APIC entries for debugging purposes too. + */ + x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries; + pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic"); return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; -- cgit v1.2.1 From 71054d8841b442bb3d8be60bde2bfac0483c19da Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:37 +0200 Subject: x86, hpet: Introduce x86_msi_ops.setup_hpet_msi This function pointer can be overwritten by the IRQ remapping code. The irq_remapping_enabled check can be removed from default_setup_hpet_msi. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index db3dcaf4ddf0..0baad3b9ecba 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -36,7 +36,8 @@ static void irq_remapping_disable_io_apic(void) static void __init irq_remapping_modify_x86_ops(void) { - x86_io_apic_ops.disable = irq_remapping_disable_io_apic; + x86_io_apic_ops.disable = irq_remapping_disable_io_apic; + x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; } static __init int setup_nointremap(char *str) -- cgit v1.2.1 From 5afba62cc8a16716508605e02c1b02ee5f969184 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:38 +0200 Subject: x86, msi: Use IRQ remapping specific setup_msi_irqs routine Use seperate routines to setup MSI IRQs for both irq_remapping_enabled cases. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 112 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 3 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 0baad3b9ecba..20f04b67efd2 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -21,6 +23,10 @@ int no_x2apic_optout; static struct irq_remap_ops *remap_ops; +static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); +static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, + int index, int sub_handle); + static void irq_remapping_disable_io_apic(void) { /* @@ -34,9 +40,109 @@ static void irq_remapping_disable_io_apic(void) disconnect_bsp_APIC(0); } +static int do_setup_msi_irqs(struct pci_dev *dev, int nvec) +{ + int node, ret, sub_handle, index = 0; + unsigned int irq; + struct msi_desc *msidesc; + + nvec = __roundup_pow_of_two(nvec); + + WARN_ON(!list_is_singular(&dev->msi_list)); + msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); + WARN_ON(msidesc->irq); + WARN_ON(msidesc->msi_attrib.multiple); + + node = dev_to_node(&dev->dev); + irq = __create_irqs(get_nr_irqs_gsi(), nvec, node); + if (irq == 0) + return -ENOSPC; + + msidesc->msi_attrib.multiple = ilog2(nvec); + for (sub_handle = 0; sub_handle < nvec; sub_handle++) { + if (!sub_handle) { + index = msi_alloc_remapped_irq(dev, irq, nvec); + if (index < 0) { + ret = index; + goto error; + } + } else { + ret = msi_setup_remapped_irq(dev, irq + sub_handle, + index, sub_handle); + if (ret < 0) + goto error; + } + ret = setup_msi_irq(dev, msidesc, irq, sub_handle); + if (ret < 0) + goto error; + } + return 0; + +error: + destroy_irqs(irq, nvec); + + /* + * Restore altered MSI descriptor fields and prevent just destroyed + * IRQs from tearing down again in default_teardown_msi_irqs() + */ + msidesc->irq = 0; + msidesc->msi_attrib.multiple = 0; + + return ret; +} + +static int do_setup_msix_irqs(struct pci_dev *dev, int nvec) +{ + int node, ret, sub_handle, index = 0; + struct msi_desc *msidesc; + unsigned int irq; + + node = dev_to_node(&dev->dev); + irq = get_nr_irqs_gsi(); + sub_handle = 0; + + list_for_each_entry(msidesc, &dev->msi_list, list) { + + irq = create_irq_nr(irq, node); + if (irq == 0) + return -1; + + if (sub_handle == 0) + ret = index = msi_alloc_remapped_irq(dev, irq, nvec); + else + ret = msi_setup_remapped_irq(dev, irq, index, sub_handle); + + if (ret < 0) + goto error; + + ret = setup_msi_irq(dev, msidesc, irq, 0); + if (ret < 0) + goto error; + + sub_handle += 1; + irq += 1; + } + + return 0; + +error: + destroy_irq(irq); + return ret; +} + +static int irq_remapping_setup_msi_irqs(struct pci_dev *dev, + int nvec, int type) +{ + if (type == PCI_CAP_ID_MSI) + return do_setup_msi_irqs(dev, nvec); + else + return do_setup_msix_irqs(dev, nvec); +} + static void __init irq_remapping_modify_x86_ops(void) { x86_io_apic_ops.disable = irq_remapping_disable_io_apic; + x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; } @@ -186,7 +292,7 @@ void compose_remapped_msi_msg(struct pci_dev *pdev, remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); } -int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) +static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) { if (!remap_ops || !remap_ops->msi_alloc_irq) return -ENODEV; @@ -194,8 +300,8 @@ int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) return remap_ops->msi_alloc_irq(pdev, irq, nvec); } -int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, - int index, int sub_handle) +static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, + int index, int sub_handle) { if (!remap_ops || !remap_ops->msi_setup_irq) return -ENODEV; -- cgit v1.2.1 From 373dd7a27f2469020e7b56744cf47b82986b9749 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:39 +0200 Subject: x86, io_apic: Introduce set_affinity function pointer With interrupt remapping a special function is used to change the affinity of an IO-APIC interrupt. Abstract this with a function pointer. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 20f04b67efd2..67b243c6c4e9 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -26,6 +26,9 @@ static struct irq_remap_ops *remap_ops; static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, int index, int sub_handle); +static int set_remapped_irq_affinity(struct irq_data *data, + const struct cpumask *mask, + bool force); static void irq_remapping_disable_io_apic(void) { @@ -142,6 +145,7 @@ static int irq_remapping_setup_msi_irqs(struct pci_dev *dev, static void __init irq_remapping_modify_x86_ops(void) { x86_io_apic_ops.disable = irq_remapping_disable_io_apic; + x86_io_apic_ops.set_affinity = set_remapped_irq_affinity; x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; } -- cgit v1.2.1 From a6a25dd3270944f3c4182ffcbe0f60482471e849 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:40 +0200 Subject: x86, io_apic: Convert setup_ioapic_entry to function pointer This pointer is changed to a different function when IRQ remapping is enabled. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 67b243c6c4e9..886ad67987fd 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -146,6 +146,7 @@ static void __init irq_remapping_modify_x86_ops(void) { x86_io_apic_ops.disable = irq_remapping_disable_io_apic; x86_io_apic_ops.set_affinity = set_remapped_irq_affinity; + x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry; x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; } -- cgit v1.2.1 From 6a9f5de27216801b4e38ccd8aa0168a5dd8eca9b Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:41 +0200 Subject: x86, io_apic: Move irq_remapping_enabled checks out of check_timer() Move these checks to IRQ remapping code by introducing the panic_on_irq_remap() function. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 886ad67987fd..ebd02bf98062 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -321,3 +321,9 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) return remap_ops->setup_hpet_msi(irq, id); } + +void panic_if_irq_remap(const char *msg) +{ + if (irq_remapping_enabled) + panic(msg); +} -- cgit v1.2.1 From 078e1ee26a061663bd7a4773c06b33cdb997380d Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:43 +0200 Subject: x86, irq: Move irq_remapping_enabled declaration to iommu code Remove the last left-over from this flag from x86 code. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/dmar.c | 2 ++ drivers/iommu/intel-iommu.c | 2 ++ drivers/iommu/irq_remapping.h | 1 + 3 files changed, 5 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 86e2f4a62b9a..174bb654453d 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -41,6 +41,8 @@ #include #include +#include "irq_remapping.h" + /* No locks are needed as DMA remapping hardware unit * list is constructed at boot time and hotplug of * these units are not supported by the architecture. diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index b9d091157884..64ae948a3802 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -46,6 +46,8 @@ #include #include +#include "irq_remapping.h" + #define ROOT_SIZE VTD_PAGE_SIZE #define CONTEXT_SIZE VTD_PAGE_SIZE diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h index 95363acb583f..ecb637670405 100644 --- a/drivers/iommu/irq_remapping.h +++ b/drivers/iommu/irq_remapping.h @@ -34,6 +34,7 @@ struct msi_msg; extern int disable_irq_remap; extern int disable_sourceid_checking; extern int no_x2apic_optout; +extern int irq_remapping_enabled; struct irq_remap_ops { /* Check whether Interrupt Remapping is supported */ -- cgit v1.2.1 From 9b1b0e42f54bc452817f4bb6a8d939afe4f04303 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:45 +0200 Subject: x86, io-apic: Move CONFIG_IRQ_REMAP code out of x86 core Move all the code to either to the header file asm/irq_remapping.h or to drivers/iommu/. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/amd_iommu.c | 8 ++++---- drivers/iommu/intel_irq_remapping.c | 4 ++++ drivers/iommu/irq_remapping.c | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index c1c74e030a58..d33eaaf783ad 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -4017,10 +4017,10 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count) index -= count - 1; + cfg->remapped = 1; irte_info = &cfg->irq_2_iommu; irte_info->sub_handle = devid; irte_info->irte_index = index; - irte_info->iommu = (void *)cfg; goto out; } @@ -4127,9 +4127,9 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, index = attr->ioapic_pin; /* Setup IRQ remapping info */ + cfg->remapped = 1; irte_info->sub_handle = devid; irte_info->irte_index = index; - irte_info->iommu = (void *)cfg; /* Setup IRTE for IOMMU */ irte.val = 0; @@ -4288,9 +4288,9 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq, devid = get_device_id(&pdev->dev); irte_info = &cfg->irq_2_iommu; + cfg->remapped = 1; irte_info->sub_handle = devid; irte_info->irte_index = index + offset; - irte_info->iommu = (void *)cfg; return 0; } @@ -4314,9 +4314,9 @@ static int setup_hpet_msi(unsigned int irq, unsigned int id) if (index < 0) return index; + cfg->remapped = 1; irte_info->sub_handle = devid; irte_info->irte_index = index; - irte_info->iommu = (void *)cfg; return 0; } diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index cb9a72d4cc09..7ca4947c3c10 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -68,6 +68,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) { struct ir_table *table = iommu->ir_table; struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); + struct irq_cfg *cfg = irq_get_chip_data(irq); u16 index, start_index; unsigned int mask = 0; unsigned long flags; @@ -115,6 +116,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) for (i = index; i < index + count; i++) table->base[i].present = 1; + cfg->remapped = 1; irq_iommu->iommu = iommu; irq_iommu->irte_index = index; irq_iommu->sub_handle = 0; @@ -155,6 +157,7 @@ static int map_irq_to_irte_handle(int irq, u16 *sub_handle) static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) { struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); + struct irq_cfg *cfg = irq_get_chip_data(irq); unsigned long flags; if (!irq_iommu) @@ -162,6 +165,7 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subha raw_spin_lock_irqsave(&irq_2_ir_lock, flags); + cfg->remapped = 1; irq_iommu->iommu = iommu; irq_iommu->irte_index = index; irq_iommu->sub_handle = subhandle; diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index ebd02bf98062..75afdf43317c 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -327,3 +328,27 @@ void panic_if_irq_remap(const char *msg) if (irq_remapping_enabled) panic(msg); } + +static void ir_ack_apic_edge(struct irq_data *data) +{ + ack_APIC_irq(); +} + +static void ir_ack_apic_level(struct irq_data *data) +{ + ack_APIC_irq(); + eoi_ioapic_irq(data->irq, data->chip_data); +} + +static void ir_print_prefix(struct irq_data *data, struct seq_file *p) +{ + seq_printf(p, " IR-%s", data->chip->name); +} + +void irq_remap_modify_chip_defaults(struct irq_chip *chip) +{ + chip->irq_print_chip = ir_print_prefix; + chip->irq_ack = ir_ack_apic_edge; + chip->irq_eoi = ir_ack_apic_level; + chip->irq_set_affinity = x86_io_apic_ops.set_affinity; +} -- cgit v1.2.1 From 11b4a1cc3836ac71a214446d350e923c76012368 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:47 +0200 Subject: x86, irq: Move irq_remapped() check into free_remapped_irq The function is called unconditionally now in IO-APIC code removing another irq_remapped() check from x86 core code. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 75afdf43317c..cff04789e1a3 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -282,10 +282,13 @@ int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask, void free_remapped_irq(int irq) { + struct irq_cfg *cfg = irq_get_chip_data(irq); + if (!remap_ops || !remap_ops->free_irq) return; - remap_ops->free_irq(irq); + if (irq_remapped(cfg)) + remap_ops->free_irq(irq); } void compose_remapped_msi_msg(struct pci_dev *pdev, -- cgit v1.2.1 From 2976fd8417f5744de3bb9109e4f30f353a36b1c0 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:48 +0200 Subject: x86, irq: Introduce setup_remapped_irq() This function does irq-remapping specific interrupt setup like modifying the chip defaults. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index cff04789e1a3..339260c98cf9 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -355,3 +355,12 @@ void irq_remap_modify_chip_defaults(struct irq_chip *chip) chip->irq_eoi = ir_ack_apic_level; chip->irq_set_affinity = x86_io_apic_ops.set_affinity; } + +bool setup_remapped_irq(int irq, struct irq_cfg *cfg, struct irq_chip *chip) +{ + if (!irq_remapped(cfg)) + return false; + irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); + irq_remap_modify_chip_defaults(chip); + return true; +} -- cgit v1.2.1 From 7601384f91be1a5ea60cb4ef6e28cad628e6cd1e Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:49 +0200 Subject: x86, msi: Introduce x86_msi.compose_msi_msg call-back This call-back points to the right function for initializing the msi_msg structure. The old code for msi_msg generation was split up into the irq-remapped and the default case. The irq-remapped case just calls into the specific Intel or AMD implementation when the device is behind an IOMMU. Otherwise the default function is called. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 339260c98cf9..158091b345cb 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -150,6 +150,7 @@ static void __init irq_remapping_modify_x86_ops(void) x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry; x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; + x86_msi.compose_msi_msg = compose_remapped_msi_msg; } static __init int setup_nointremap(char *str) @@ -295,10 +296,12 @@ void compose_remapped_msi_msg(struct pci_dev *pdev, unsigned int irq, unsigned int dest, struct msi_msg *msg, u8 hpet_id) { - if (!remap_ops || !remap_ops->compose_msi_msg) - return; + struct irq_cfg *cfg = irq_get_chip_data(irq); - remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); + if (!irq_remapped(cfg)) + native_compose_msi_msg(pdev, irq, dest, msg, hpet_id); + else if (remap_ops && remap_ops->compose_msi_msg) + remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); } static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) -- cgit v1.2.1 From da165322dfb6cbc50042b1051f07b837a26f3bb8 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:50 +0200 Subject: x86, io_apic: Introduce eoi_ioapic_pin call-back This callback replaces the old __eoi_ioapic_pin function which needs a special path for interrupt remapping. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 158091b345cb..849ce4ce500b 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -143,11 +143,23 @@ static int irq_remapping_setup_msi_irqs(struct pci_dev *dev, return do_setup_msix_irqs(dev, nvec); } +void eoi_ioapic_pin_remapped(int apic, int pin, int vector) +{ + /* + * Intr-remapping uses pin number as the virtual vector + * in the RTE. Actual vector is programmed in + * intr-remapping table entry. Hence for the io-apic + * EOI we use the pin number. + */ + io_apic_eoi(apic, pin); +} + static void __init irq_remapping_modify_x86_ops(void) { x86_io_apic_ops.disable = irq_remapping_disable_io_apic; x86_io_apic_ops.set_affinity = set_remapped_irq_affinity; x86_io_apic_ops.setup_entry = setup_ioapic_remapped_entry; + x86_io_apic_ops.eoi_ioapic_pin = eoi_ioapic_pin_remapped; x86_msi.setup_msi_irqs = irq_remapping_setup_msi_irqs; x86_msi.setup_hpet_msi = setup_hpet_msi_remapped; x86_msi.compose_msi_msg = compose_remapped_msi_msg; -- cgit v1.2.1 From a1bb20c232d066de0762f8e7cf332e5ce8385210 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 26 Sep 2012 12:44:51 +0200 Subject: x86, irq: Move irq_remapped out of x86 core code The irq_remapped function is only used in IOMMU code after the last patch. So move its definition there too. Signed-off-by: Joerg Roedel Acked-by: Sebastian Andrzej Siewior Reviewed-by: Konrad Rzeszutek Wilk --- drivers/iommu/irq_remapping.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/iommu') diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 849ce4ce500b..d56f8c17c5fe 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -31,6 +31,11 @@ static int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask, bool force); +static bool irq_remapped(struct irq_cfg *cfg) +{ + return (cfg->remapped == 1); +} + static void irq_remapping_disable_io_apic(void) { /* -- cgit v1.2.1 From af8d102f999a41c0189bd2cce488bac2ee88c29b Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 1 Feb 2013 14:57:43 -0800 Subject: x86/intel/irq_remapping: Clean up x2apic opt-out security warning mess Current kernels print this on my Dell server: ------------[ cut here ]------------ WARNING: at drivers/iommu/intel_irq_remapping.c:542 intel_enable_irq_remapping+0x7b/0x27e() Hardware name: PowerEdge R620 Your BIOS is broken and requested that x2apic be disabled This will leave your machine vulnerable to irq-injection attacks Use 'intremap=no_x2apic_optout' to override BIOS request [...] Enabled IRQ remapping in xapic mode x2apic not enabled, IRQ remapping is in xapic mode This is inconsistent with itself -- interrupt remapping is *on*. Fix the mess by making the warnings say what they mean and my making sure that compatibility format interrupts (the dangerous ones) are disabled if x2apic is present regardless of BIOS settings. With this patch applied, the output is: Your BIOS is broken and requested that x2apic be disabled. This will slightly decrease performance. Use 'intremap=no_x2apic_optout' to override BIOS request. Enabled IRQ remapping in xapic mode x2apic not enabled, IRQ remapping is in xapic mode This should make us as or more secure than we are now and replace a rather scary warning with a much less scary warning on silly but functional systems. Signed-off-by: Andy Lutomirski Cc: Suresh Siddha Cc: Prarit Bhargava Cc: Gleb Natapov Cc: Don Zickus Cc: Alex Williamson Link: http://lkml.kernel.org/r/2011b943a886fd7c46079eb10bc24fc130587503.1359759303.git.luto@amacapital.net Signed-off-by: Ingo Molnar --- drivers/iommu/intel_irq_remapping.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'drivers/iommu') diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 7ca4947c3c10..f3b8f23b5d8f 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -429,11 +429,22 @@ static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode) /* Enable interrupt-remapping */ iommu->gcmd |= DMA_GCMD_IRE; + iommu->gcmd &= ~DMA_GCMD_CFI; /* Block compatibility-format MSIs */ writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG); IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, readl, (sts & DMA_GSTS_IRES), sts); + /* + * With CFI clear in the Global Command register, we should be + * protected from dangerous (i.e. compatibility) interrupts + * regardless of x2apic status. Check just to be sure. + */ + if (sts & DMA_GSTS_CFIS) + WARN(1, KERN_WARNING + "Compatibility-format IRQs enabled despite intr remapping;\n" + "you are vulnerable to IRQ injection.\n"); + raw_spin_unlock_irqrestore(&iommu->register_lock, flags); } @@ -530,20 +541,24 @@ static int __init intel_irq_remapping_supported(void) static int __init intel_enable_irq_remapping(void) { struct dmar_drhd_unit *drhd; + bool x2apic_present; int setup = 0; int eim = 0; + x2apic_present = x2apic_supported(); + if (parse_ioapics_under_ir() != 1) { printk(KERN_INFO "Not enable interrupt remapping\n"); - return -1; + goto error; } - if (x2apic_supported()) { + if (x2apic_present) { eim = !dmar_x2apic_optout(); - WARN(!eim, KERN_WARNING - "Your BIOS is broken and requested that x2apic be disabled\n" - "This will leave your machine vulnerable to irq-injection attacks\n" - "Use 'intremap=no_x2apic_optout' to override BIOS request\n"); + if (!eim) + printk(KERN_WARNING + "Your BIOS is broken and requested that x2apic be disabled.\n" + "This will slightly decrease performance.\n" + "Use 'intremap=no_x2apic_optout' to override BIOS request.\n"); } for_each_drhd_unit(drhd) { @@ -582,7 +597,7 @@ static int __init intel_enable_irq_remapping(void) if (eim && !ecap_eim_support(iommu->ecap)) { printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); - return -1; + goto error; } } @@ -598,7 +613,7 @@ static int __init intel_enable_irq_remapping(void) printk(KERN_ERR "DRHD %Lx: failed to enable queued, " " invalidation, ecap %Lx, ret %d\n", drhd->reg_base_addr, iommu->ecap, ret); - return -1; + goto error; } } @@ -637,6 +652,11 @@ error: /* * handle error condition gracefully here! */ + + if (x2apic_present) + WARN(1, KERN_WARNING + "Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n"); + return -1; } -- cgit v1.2.1