MIPS: DMA: Add cma support
authorZubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
Wed, 16 Jul 2014 15:51:32 +0000 (16:51 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 22 Sep 2014 11:35:52 +0000 (13:35 +0200)
Adds cma support to the MIPS architecture.

cma uses memblock. However, mips uses bootmem.
bootmem is informed about any regions reserved by memblock

dma api is modified to use cma reserved memory regions when available

Tested using cma_test. cma_test is a simple driver that assigns blocks
of memory from cma reserved sections.

Signed-off-by: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Cc: catalin.marinas@arm.com
Cc: will.deacon@arm.com
Cc: tglx@linutronix.de
Cc: mingo@redhat.com
Cc: hpa@zytor.com
Cc: arnd@arndb.de
Cc: gregkh@linuxfoundation.org
Cc: m.szyprowski@samsung.com
Cc: x86@kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-mips@linux-mips.org
Cc: linux-arch@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/7360/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/Kconfig
arch/mips/include/asm/Kbuild
arch/mips/kernel/setup.c
arch/mips/mm/dma-default.c

index d7c8bd4e2f0ec59670f17f3b258e31798d97ead9..ad6badb6be715735715e25ad3198b19e9f54191b 100644 (file)
@@ -29,6 +29,7 @@ config MIPS
        select GENERIC_ATOMIC64 if !64BIT
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select HAVE_DMA_ATTRS
+       select HAVE_DMA_CONTIGUOUS
        select HAVE_DMA_API_DEBUG
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
index 335e5290ec759f670aea360e53cd85293cdfa7f3..c0b09571a7a5537ed6bd36328c1a5c991957607a 100644 (file)
@@ -1,6 +1,7 @@
 # MIPS headers
 generic-y += cputime.h
 generic-y += current.h
+generic-y += dma-contiguous.h
 generic-y += emergency-restart.h
 generic-y += hash.h
 generic-y += local64.h
index 7c1fe2b42d405fed3c1ca5c61a3bfe743af7a6c3..b3b8f0d9d4a77b9ee4d2f02e0a2761a281ee87b1 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/debugfs.h>
 #include <linux/kexec.h>
 #include <linux/sizes.h>
+#include <linux/device.h>
+#include <linux/dma-contiguous.h>
 
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
@@ -476,6 +478,7 @@ static void __init bootmem_init(void)
  *  o bootmem_init()
  *  o sparse_init()
  *  o paging_init()
+ *  o dma_continguous_reserve()
  *
  * At this stage the bootmem allocator is ready to use.
  *
@@ -609,6 +612,7 @@ static void __init request_crashkernel(struct resource *res)
 
 static void __init arch_mem_init(char **cmdline_p)
 {
+       struct memblock_region *reg;
        extern void plat_mem_setup(void);
 
        /* call board setup routine */
@@ -675,6 +679,11 @@ static void __init arch_mem_init(char **cmdline_p)
        sparse_init();
        plat_swiotlb_setup();
        paging_init();
+
+       dma_contiguous_reserve(PFN_PHYS(max_low_pfn));
+       /* Tell bootmem about cma reserved memblock section */
+       for_each_memblock(reserved, reg)
+               reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
 }
 
 static void __init resource_init(void)
index 44b6dff5aba2a09e92715aab976c2ac37619e729..33ba3c558fe4ff31a0693457ea28a71ae4b5fafa 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/gfp.h>
 #include <linux/highmem.h>
+#include <linux/dma-contiguous.h>
 
 #include <asm/cache.h>
 #include <asm/cpu-type.h>
@@ -128,23 +129,30 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
        dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
 {
        void *ret;
+       struct page *page = NULL;
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
 
        if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
                return ret;
 
        gfp = massage_gfp_flags(dev, gfp);
 
-       ret = (void *) __get_free_pages(gfp, get_order(size));
-
-       if (ret) {
-               memset(ret, 0, size);
-               *dma_handle = plat_map_dma_mem(dev, ret, size);
-
-               if (!plat_device_is_coherent(dev)) {
-                       dma_cache_wback_inv((unsigned long) ret, size);
-                       if (!hw_coherentio)
-                               ret = UNCAC_ADDR(ret);
-               }
+       if (IS_ENABLED(CONFIG_DMA_CMA) && !(gfp & GFP_ATOMIC))
+               page = dma_alloc_from_contiguous(dev,
+                                       count, get_order(size));
+       if (!page)
+               page = alloc_pages(gfp, get_order(size));
+
+       if (!page)
+               return NULL;
+
+       ret = page_address(page);
+       memset(ret, 0, size);
+       *dma_handle = plat_map_dma_mem(dev, ret, size);
+       if (!plat_device_is_coherent(dev)) {
+               dma_cache_wback_inv((unsigned long) ret, size);
+               if (!hw_coherentio)
+                       ret = UNCAC_ADDR(ret);
        }
 
        return ret;
@@ -164,6 +172,8 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
 {
        unsigned long addr = (unsigned long) vaddr;
        int order = get_order(size);
+       unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       struct page *page = NULL;
 
        if (dma_release_from_coherent(dev, order, vaddr))
                return;
@@ -173,7 +183,10 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
        if (!plat_device_is_coherent(dev) && !hw_coherentio)
                addr = CAC_ADDR(addr);
 
-       free_pages(addr, get_order(size));
+       page = virt_to_page((void *) addr);
+
+       if (!dma_release_from_contiguous(dev, page, count))
+               __free_pages(page, get_order(size));
 }
 
 static inline void __dma_sync_virtual(void *addr, size_t size,