diff --git a/arch/x86/kernel/pci-dma_32.c b/arch/x86/kernel/pci-dma_32.c index 5450bd142cb0a568ba0df5e9ff832f834bfb8b9f..f134de3833a2552c1e0a6fa0a31fe477aaa4cb94 100644 --- a/arch/x86/kernel/pci-dma_32.c +++ b/arch/x86/kernel/pci-dma_32.c @@ -116,12 +116,42 @@ void *dma_alloc_coherent(struct device *dev, size_t size, gfp = (gfp & ~GFP_DMA32) | GFP_DMA; goto again; } + + /* Let low level make its own zone decisions */ + gfp &= ~(GFP_DMA32|GFP_DMA); + + if (dma_ops->alloc_coherent) + return dma_ops->alloc_coherent(dev, size, + dma_handle, gfp); + return NULL; + } memset(ret, 0, size); - *dma_handle = bus; + if (!mmu) { + *dma_handle = bus; + return ret; + } + } + + if (dma_ops->alloc_coherent) { + free_pages((unsigned long)ret, get_order(size)); + gfp &= ~(GFP_DMA|GFP_DMA32); + return dma_ops->alloc_coherent(dev, size, dma_handle, gfp); + } + + if (dma_ops->map_simple) { + *dma_handle = dma_ops->map_simple(dev, virt_to_phys(ret), + size, + PCI_DMA_BIDIRECTIONAL); + if (*dma_handle != bad_dma_address) + return ret; } - return ret; + if (panic_on_overflow) + panic("dma_alloc_coherent: IOMMU overflow by %lu bytes\n", + (unsigned long)size); + free_pages((unsigned long)ret, get_order(size)); + return NULL; } EXPORT_SYMBOL(dma_alloc_coherent);