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 <akinobu.m...@gmail.com>
Cc: Marek Szyprowski <m.szyprow...@samsung.com>
Cc: Konrad Rzeszutek Wilk <konrad.w...@oracle.com>
Cc: David Woodhouse <dw...@infradead.org>
Cc: Don Dutile <ddut...@redhat.com>
Cc: Thomas Gleixner <t...@linutronix.de>
Cc: Ingo Molnar <mi...@redhat.com>
Cc: "H. Peter Anvin" <h...@zytor.com>
Cc: Andi Kleen <a...@firstfloor.org>
Cc: x...@kernel.org
Cc: io...@lists.linux-foundation.org
---
 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 majord...@vger.kernel.org
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