From 25cbff1660d3f4c059a178a1e5b851be6d70c5e8 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Sat, 12 Jun 2010 19:21:42 +0800 Subject: [PATCH 1/3] intel-iommu: Fix reference by physical address in intel_iommu_attach_device() Commit a99c47a2 "intel-iommu: errors with smaller iommu widths" replace the dmar_domain->pgd with the first entry of page table when iommu's supported width is smaller than dmar_domain's. But it use physical address directly for new dmar_domain->pgd... This result in KVM oops with VT-d on some machines. Reported-by: Allen Kay Cc: Tom Lyon Signed-off-by: Sheng Yang Signed-off-by: David Woodhouse --- drivers/pci/intel-iommu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 796828fce34c..3bd30557ce2e 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -3603,7 +3603,8 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, pte = dmar_domain->pgd; if (dma_pte_present(pte)) { free_pgtable_page(dmar_domain->pgd); - dmar_domain->pgd = (struct dma_pte *)dma_pte_addr(pte); + dmar_domain->pgd = (struct dma_pte *) + phys_to_virt(dma_pte_addr(pte)); } dmar_domain->agaw--; } From 00dfff77e7184140dc45724c7232e99302f6bf97 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 14 Jun 2010 17:17:32 +0200 Subject: [PATCH 2/3] intel-iommu: Fix double lock in get_domain_for_dev() stanse found the following double lock. In get_domain_for_dev: spin_lock_irqsave(&device_domain_lock, flags); domain_exit(domain); domain_remove_dev_info(domain); spin_lock_irqsave(&device_domain_lock, flags); spin_unlock_irqrestore(&device_domain_lock, flags); spin_unlock_irqrestore(&device_domain_lock, flags); This happens when the domain is created by another CPU at the same time as this function is creating one, and the other CPU wins the race to attach it to the device in question, so we have to destroy our own newly-created one. Signed-off-by: David Woodhouse --- drivers/pci/intel-iommu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 3bd30557ce2e..bf8fd913d064 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1874,14 +1874,15 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) } } if (found) { + spin_unlock_irqrestore(&device_domain_lock, flags); free_devinfo_mem(info); domain_exit(domain); domain = found; } else { list_add(&info->link, &domain->devices); list_add(&info->global, &device_domain_list); + spin_unlock_irqrestore(&device_domain_lock, flags); } - spin_unlock_irqrestore(&device_domain_lock, flags); } found_domain: From 2d9e667efdfb4e986074d98e7d9a424003c7c43b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 15 Jun 2010 10:57:57 +0100 Subject: [PATCH 3/3] intel-iommu: Force-disable IOMMU for iGFX on broken Cantiga revisions. Certain revisions of this chipset appear to be broken. There is a shadow GTT which mirrors the real GTT but contains pre-translated physical addresses, for performance reasons. When a GTT update happens, the translations are done once and the resulting physical addresses written back to the shadow GTT. Except sometimes, the physical address is actually written back to the _real_ GTT, not the shadow GTT. Thus we start to see faults when that physical address is fed through translation again. Signed-off-by: David Woodhouse --- drivers/pci/intel-iommu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index bf8fd913d064..c9171be74564 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -340,7 +340,7 @@ int dmar_disabled = 0; int dmar_disabled = 1; #endif /*CONFIG_DMAR_DEFAULT_ON*/ -static int __initdata dmar_map_gfx = 1; +static int dmar_map_gfx = 1; static int dmar_forcedac; static int intel_iommu_strict; @@ -3721,6 +3721,12 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) */ printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n"); rwbf_quirk = 1; + + /* https://bugzilla.redhat.com/show_bug.cgi?id=538163 */ + if (dev->revision == 0x07) { + printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n"); + dmar_map_gfx = 0; + } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);