[PATCH for review] [69/145] x86_64: Disable DAC on VIA PCI bridges

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



r

Because of several reports that it doesn't work

TBD needs a real confirmation this fixes the problem
TBD needs more testing

Signed-off-by: Andi Kleen <[email protected]>

---
 Documentation/x86_64/boot-options.txt |    4 +++
 arch/x86_64/kernel/pci-dma.c          |   42 ++++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+)

Index: linux/Documentation/x86_64/boot-options.txt
===================================================================
--- linux.orig/Documentation/x86_64/boot-options.txt
+++ linux/Documentation/x86_64/boot-options.txt
@@ -199,6 +199,10 @@ IOMMU
    allowed  overwrite iommu off workarounds for specific chipsets.
    soft	 Use software bounce buffering (default for Intel machines)
    noaperture Don't touch the aperture for AGP.
+   allowdac Allow DMA >4GB - default selected based on chipset bugs
+	    When off all DMA over >4GB is forced through an IOMMU or bounce
+	    buffering.
+   nodac    Forbid DMA >4GB
 
   swiotlb=pages[,force]
 
Index: linux/arch/x86_64/kernel/pci-dma.c
===================================================================
--- linux.orig/arch/x86_64/kernel/pci-dma.c
+++ linux/arch/x86_64/kernel/pci-dma.c
@@ -170,11 +170,47 @@ void dma_free_coherent(struct device *de
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
+static int allow_dac;
+
+static int bridge_from_vendor(struct device *dev, u16 vendor)
+{
+#ifdef CONFIG_PCI
+	struct pci_bus *bus;
+	if (dev->bus != &pci_bus_type)
+		return 0;
+	bus = to_pci_dev(dev)->bus;
+	/* RED-PEN
+	   Assumes no locking is needed on these lists because someone
+	   should hold a reference count on the target device.
+	   Correct assumption? */
+	while (bus != NULL) {
+		if (bus->self && bus->self->vendor == vendor)
+			return 1;
+		bus = bus->parent;
+	}
+#endif
+	return 0;
+}
+
 int dma_supported(struct device *dev, u64 mask)
 {
 	if (dma_ops->dma_supported)
 		return dma_ops->dma_supported(dev, mask);
 
+	if (mask > DMA_32BIT_MASK) {
+		/* Some VIA bridges seem to have trouble with Double Address
+		   Cycle.  Disable it behind them all for now. The driver
+		   should fall back to non DAC. */
+		if (bridge_from_vendor(dev, PCI_VENDOR_ID_VIA) && !allow_dac) {
+			printk(KERN_INFO
+			"PCI: %s disallowing DAC because of VIA bridge.\n",
+				dev->bus_id);
+			return 0;
+		}
+		if (allow_dac < 0)
+			return 0;
+	}
+
 	/* Copied from i386. Doesn't make much sense, because it will
 	   only work for pci_alloc_coherent.
 	   The caller just has to use GFP_DMA in this case. */
@@ -231,6 +267,8 @@ EXPORT_SYMBOL(dma_set_mask);
    allowed  overwrite iommu off workarounds for specific chipsets.
    soft	 Use software bounce buffering (default for Intel machines)
    noaperture Don't touch the aperture for AGP.
+   allowdac Allow DMA >4GB - default selected based on chipset bugs
+   nodac    Forbid DMA >4GB
 */
 __init int iommu_setup(char *p)
 {
@@ -264,6 +302,10 @@ __init int iommu_setup(char *p)
 		    iommu_merge = 0;
 	    if (!strncmp(p, "forcesac",8))
 		    iommu_sac_force = 1;
+	    if (!strncmp(p, "allowdac", 8))
+		    allow_dac = 1;
+	    if (!strncmp(p, "nodac", 5))
+		    allow_dac = -1;
 
 #ifdef CONFIG_SWIOTLB
 	    if (!strncmp(p, "soft",4))
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux