Disable DAC on VIA PCI bridges 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 --- 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))