From e5d1c929784ac82686cbed602b050fb42336eff1 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 9 Apr 2008 13:18:05 -0300 Subject: [PATCH] --- yaml --- r: 91037 b: refs/heads/master c: 5fa78ca75d8e67063948a01b51594a0904af5710 h: refs/heads/master i: 91035: 1d777dfb79dce5b1881d57103ea8e81c5ca0bac3 v: v3 --- [refs] | 2 +- trunk/arch/x86/kernel/pci-dma_32.c | 34 +++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/[refs] b/[refs] index eb1232eba987..2962850876bb 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 8779f2fc3b84ebb6c5181fb13d702e9944c16069 +refs/heads/master: 5fa78ca75d8e67063948a01b51594a0904af5710 diff --git a/trunk/arch/x86/kernel/pci-dma_32.c b/trunk/arch/x86/kernel/pci-dma_32.c index debe9119b724..11f100a5f034 100644 --- a/trunk/arch/x86/kernel/pci-dma_32.c +++ b/trunk/arch/x86/kernel/pci-dma_32.c @@ -76,6 +76,8 @@ void *dma_alloc_coherent(struct device *dev, size_t size, struct page *page; dma_addr_t bus; int order = get_order(size); + unsigned long dma_mask = 0; + /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); @@ -85,15 +87,37 @@ void *dma_alloc_coherent(struct device *dev, size_t size, if (!dev) dev = &fallback_dev; + dma_mask = dev->coherent_dma_mask; + if (dma_mask == 0) + dma_mask = DMA_32BIT_MASK; + + again: page = dma_alloc_pages(dev, gfp, order); if (page == NULL) return NULL; - ret = page_address(page); - bus = page_to_phys(page); - - memset(ret, 0, size); - *dma_handle = bus; + { + int high, mmu; + bus = page_to_phys(page); + ret = page_address(page); + high = (bus + size) >= dma_mask; + mmu = high; + if (force_iommu && !(gfp & GFP_DMA)) + mmu = 1; + else if (high) { + free_pages((unsigned long)ret, + get_order(size)); + + /* Don't use the 16MB ZONE_DMA unless absolutely + needed. It's better to use remapping first. */ + if (dma_mask < DMA_32BIT_MASK && !(gfp & GFP_DMA)) { + gfp = (gfp & ~GFP_DMA32) | GFP_DMA; + goto again; + } + } + memset(ret, 0, size); + *dma_handle = bus; + } return ret; }