From 0815565adfe3f4c369110c57d8ffe83caefeed68 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 4 Aug 2009 09:17:20 +0100 Subject: intel-iommu: Cope with broken HP DC7900 BIOS Yet another reason why trusting this stuff to the BIOS was a bad idea. The HP DC7900 BIOS reports an iommu at an address which just returns all ones, when VT-d is disabled in the BIOS. Fix up the missing iounmap in the error paths while we're at it. Signed-off-by: David Woodhouse --- drivers/pci/dmar.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/pci/dmar.c') diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 7b287cb38b7a..380b60e677e0 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -632,20 +632,31 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); + if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) { + /* Promote an attitude of violence to a BIOS engineer today */ + WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n" + "BIOS vendor: %s; Ver: %s; Product Version: %s\n", + drhd->reg_base_addr, + dmi_get_system_info(DMI_BIOS_VENDOR), + dmi_get_system_info(DMI_BIOS_VERSION), + dmi_get_system_info(DMI_PRODUCT_VERSION)); + goto err_unmap; + } + #ifdef CONFIG_DMAR agaw = iommu_calculate_agaw(iommu); if (agaw < 0) { printk(KERN_ERR "Cannot get a valid agaw for iommu (seq_id = %d)\n", iommu->seq_id); - goto error; + goto err_unmap; } msagaw = iommu_calculate_max_sagaw(iommu); if (msagaw < 0) { printk(KERN_ERR "Cannot get a valid max agaw for iommu (seq_id = %d)\n", iommu->seq_id); - goto error; + goto err_unmap; } #endif iommu->agaw = agaw; @@ -665,7 +676,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) } ver = readl(iommu->reg + DMAR_VER_REG); - pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n", + pr_info("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n", (unsigned long long)drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver), (unsigned long long)iommu->cap, @@ -675,7 +686,10 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) drhd->iommu = iommu; return 0; -error: + + err_unmap: + iounmap(iommu->reg); + error: kfree(iommu); return -1; } -- cgit v1.2.3 From 8211a7b5857914058c52ae977c96463e419b37ab Mon Sep 17 00:00:00 2001 From: Troy Heber Date: Wed, 19 Aug 2009 15:26:11 -0600 Subject: pci/dmar: correct off-by-one error in dmar_fault() DMAR faults are recorded into a ring of "fault recording registers". fault_index is a 0-based index into the ring. The code allows the 0-based fault_index to be equal to the total number of fault registers available from the cap_num_fault_regs() macro, which causes access beyond the last available register. Signed-off-by Troy Heber Signed-off-by: David Woodhouse --- drivers/pci/dmar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/dmar.c') diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 380b60e677e0..3264b626725a 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -1226,7 +1226,7 @@ irqreturn_t dmar_fault(int irq, void *dev_id) source_id, guest_addr); fault_index++; - if (fault_index > cap_num_fault_regs(iommu->cap)) + if (fault_index >= cap_num_fault_regs(iommu->cap)) fault_index = 0; spin_lock_irqsave(&iommu->register_lock, flag); } -- cgit v1.2.3 From e936d0773df172ec8600777fdd72bbc1f75f22ad Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Mon, 7 Sep 2009 10:58:07 -0400 Subject: intel-iommu: Disallow interrupt remapping if not all ioapics covered Current kernel enable interrupt remapping only when all the vt-d unit support interrupt remapping. So it is reasonable we should also disallow enabling intr-remapping if there any io-apics that are not listed under vt-d units. Otherwise we can run into issues. Acked-by: Suresh Siddha Signed-off-by: Youquan Song Signed-off-by: David Woodhouse --- drivers/pci/dmar.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/pci/dmar.c') diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 3264b626725a..fba4f6891680 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -570,9 +570,6 @@ int __init dmar_table_init(void) printk(KERN_INFO PREFIX "No ATSR found\n"); #endif -#ifdef CONFIG_INTR_REMAP - parse_ioapics_under_ir(); -#endif return 0; } -- cgit v1.2.3 From 074835f0143b83845af5044af2739c52c9f53808 Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Wed, 9 Sep 2009 12:05:39 -0400 Subject: intel-iommu: Fix kernel hang if interrupt remapping disabled in BIOS BIOS clear DMAR table INTR_REMAP flag to disable interrupt remapping. Current kernel only check interrupt remapping(IR) flag in DRHD's extended capability register to decide interrupt remapping support or not. But IR flag will not change when BIOS disable/enable interrupt remapping. When user disable interrupt remapping in BIOS or BIOS often defaultly disable interrupt remapping feature when BIOS is not mature.Though BIOS disable interrupt remapping but intr_remapping_supported function will always report to OS support interrupt remapping if VT-d2 chipset populated. On this cases, kernel will continue enable interrupt remapping and result kernel panic. This bug exist on almost all platforms with interrupt remapping support. This patch add DMAR table INTR_REMAP flag check before enable interrupt remapping. Signed-off-by: Youquan Song Signed-off-by: David Woodhouse --- drivers/pci/dmar.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/pci/dmar.c') diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index fba4f6891680..270ed222a075 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -1316,3 +1316,13 @@ int dmar_reenable_qi(struct intel_iommu *iommu) return 0; } + +/* + * Check interrupt remapping support in DMAR table description. + */ +int dmar_ir_support(void) +{ + struct acpi_table_dmar *dmar; + dmar = (struct acpi_table_dmar *)dmar_tbl; + return dmar->flags & 0x1; +} -- cgit v1.2.3