dma_generic_alloc_coherent() firstly attempts to allocate by
dma_alloc_from_contiguous() if CONFIG_DMA_CMA is enabled. But the memory
region allocated by it may not fit within the device's DMA mask.
This change makes it fall back to usual alloc_pages_node() allocation
for such cases.

Signed-off-by: Akinobu Mita <[email protected]>
Cc: Marek Szyprowski <[email protected]>
Cc: Konrad Rzeszutek Wilk <[email protected]>
Cc: David Woodhouse <[email protected]>
Cc: Don Dutile <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Andi Kleen <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
 arch/x86/kernel/pci-dma.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index a0ffe44..f15bf8d 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -100,8 +100,13 @@ void *dma_generic_alloc_coherent(struct device *dev, 
size_t size,
 again:
        page = NULL;
        /* CMA can be used only in the context which permits sleeping */
-       if (flag & __GFP_WAIT)
+       if (flag & __GFP_WAIT) {
                page = dma_alloc_from_contiguous(dev, count, get_order(size));
+               if (page && page_to_phys(page) + size > dma_mask) {
+                       dma_release_from_contiguous(dev, page, count);
+                       page = NULL;
+               }
+       }
        /* fallback */
        if (!page)
                page = alloc_pages_node(dev_to_node(dev), flag, 
get_order(size));
-- 
1.8.3.2

--
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/

Reply via email to