Fix Intel IOMMU write-buffer flushing
authorDavid Woodhouse <dwmw2@infradead.org>
Fri, 13 Feb 2009 23:18:03 +0000 (23:18 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 20 Feb 2009 22:36:54 +0000 (14:36 -0800)
commit ca77fde8e62cecb2c0769052228d15b901367af8 upstream.

This is the cause of the DMA faults and disk corruption that people have
been seeing. Some chipsets neglect to report the RWBF "capability" --
the flag which says that we need to flush the chipset write-buffer when
changing the DMA page tables, to ensure that the change is visible to
the IOMMU.

Override that bit on the affected chipsets, and everything is happy
again.

Thanks to Chris and Bhavesh and others for helping to debug.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Tested-by: Chris Wright <chrisw@sous-sol.org>
Reviewed-by: Bhavesh Davda <bhavesh@vmware.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/pci/intel-iommu.c

index c3edcdc08e721a823b9faec718be1b58529d1fe7..2d90a3c69c56eee41f99ed72287419c956f33e74 100644 (file)
@@ -72,6 +72,8 @@ static struct deferred_flush_tables *deferred_flush;
 /* bitmap for indexing intel_iommus */
 static int g_num_of_iommus;
 
+static int rwbf_quirk = 0;
+
 static DEFINE_SPINLOCK(async_umap_flush_lock);
 static LIST_HEAD(unmaps_to_do);
 
@@ -527,7 +529,7 @@ static void iommu_flush_write_buffer(struct intel_iommu *iommu)
        u32 val;
        unsigned long flag;
 
-       if (!cap_rwbf(iommu->cap))
+       if (!rwbf_quirk && !cap_rwbf(iommu->cap))
                return;
        val = iommu->gcmd | DMA_GCMD_WBF;
 
@@ -2453,3 +2455,12 @@ int __init intel_iommu_init(void)
        return 0;
 }
 
+static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
+{
+       /* Mobile 4 Series Chipset neglects to set RWBF capability,
+          but needs it */
+       printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
+       rwbf_quirk = 1;
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);