xtensa: enable HAVE_DMA_CONTIGUOUS
authorMax Filippov <jcmvbkbc@gmail.com>
Mon, 25 Apr 2016 19:08:52 +0000 (22:08 +0300)
committerMax Filippov <jcmvbkbc@gmail.com>
Thu, 15 Dec 2016 18:41:50 +0000 (10:41 -0800)
Enable HAVE_DMA_CONTIGUOUS, reserve contiguous memory at bootmem_init,
use dma_alloc_from_contiguous and dma_release_from_contiguous in
xtensa_dma_alloc/free.
This allows for big contiguous DMA buffer allocation from designated
area configured in the device tree.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
arch/xtensa/Kconfig
arch/xtensa/include/asm/Kbuild
arch/xtensa/kernel/pci-dma.c
arch/xtensa/mm/init.c

index f61058617ada462c6e571c7936c3ebf92621aa26..f4126cf997a469da01161244e93a320d1dd2104e 100644 (file)
@@ -15,6 +15,7 @@ config XTENSA
        select GENERIC_SCHED_CLOCK
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_API_DEBUG
+       select HAVE_DMA_CONTIGUOUS
        select HAVE_EXIT_THREAD
        select HAVE_FUNCTION_TRACER
        select HAVE_FUTEX_CMPXCHG if !MMU
index 28cf4c5d65efade019dbefaf809e71d13624e37c..b7fbaa56b51a573f393ce6d6abb6ec5c1895c27e 100644 (file)
@@ -3,6 +3,7 @@ generic-y += bug.h
 generic-y += clkdev.h
 generic-y += cputime.h
 generic-y += div64.h
+generic-y += dma-contiguous.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
index 1e68806d6695afc4a3fa21a8c7553fa38d5f885c..10e5b8acf944341b57110aeb817d80ead87d424d 100644 (file)
@@ -15,6 +15,7 @@
  * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
  */
 
+#include <linux/dma-contiguous.h>
 #include <linux/gfp.h>
 #include <linux/highmem.h>
 #include <linux/mm.h>
@@ -146,6 +147,8 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 {
        unsigned long ret;
        unsigned long uncached = 0;
+       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       struct page *page = NULL;
 
        /* ignore region speicifiers */
 
@@ -153,11 +156,18 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 
        if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
                flag |= GFP_DMA;
-       ret = (unsigned long)__get_free_pages(flag, get_order(size));
 
-       if (ret == 0)
+       if (gfpflags_allow_blocking(flag))
+               page = dma_alloc_from_contiguous(dev, count, get_order(size));
+
+       if (!page)
+               page = alloc_pages(flag, get_order(size));
+
+       if (!page)
                return NULL;
 
+       ret = (unsigned long)page_address(page);
+
        /* We currently don't support coherent memory outside KSEG */
 
        BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR ||
@@ -170,16 +180,19 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
        return (void *)uncached;
 }
 
-static void xtensa_dma_free(struct device *hwdev, size_t size, void *vaddr,
+static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr,
                            dma_addr_t dma_handle, unsigned long attrs)
 {
        unsigned long addr = (unsigned long)vaddr +
                XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
+       struct page *page = virt_to_page(addr);
+       unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 
        BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR ||
               addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
 
-       free_pages(addr, get_order(size));
+       if (!dma_release_from_contiguous(dev, page, count))
+               __free_pages(page, get_order(size));
 }
 
 static dma_addr_t xtensa_map_page(struct device *dev, struct page *page,
index 80e4cfb2471ad5af6a99433d6e8af76e16865558..720fe4e8b49712db84e4e00d5fb938c9ecb4220e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/nodemask.h>
 #include <linux/mm.h>
 #include <linux/of_fdt.h>
+#include <linux/dma-contiguous.h>
 
 #include <asm/bootparam.h>
 #include <asm/page.h>
@@ -60,6 +61,7 @@ void __init bootmem_init(void)
        max_low_pfn = min(max_pfn, MAX_LOW_PFN);
 
        memblock_set_current_limit(PFN_PHYS(max_low_pfn));
+       dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
 
        memblock_dump_all();
 }