Commit f4649382 authored by Zubair Lutfullah Kakakhel's avatar Zubair Lutfullah Kakakhel Committed by Ralf Baechle

MIPS: DMA: Add cma support

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: default avatarZubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
Acked-by: default avatarMichal 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: default avatarRalf Baechle <ralf@linux-mips.org>
parent 8057b308
...@@ -29,6 +29,7 @@ config MIPS ...@@ -29,6 +29,7 @@ config MIPS
select GENERIC_ATOMIC64 if !64BIT select GENERIC_ATOMIC64 if !64BIT
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select HAVE_DMA_ATTRS select HAVE_DMA_ATTRS
select HAVE_DMA_CONTIGUOUS
select HAVE_DMA_API_DEBUG select HAVE_DMA_API_DEBUG
select GENERIC_IRQ_PROBE select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
......
# MIPS headers # MIPS headers
generic-y += cputime.h generic-y += cputime.h
generic-y += current.h generic-y += current.h
generic-y += dma-contiguous.h
generic-y += emergency-restart.h generic-y += emergency-restart.h
generic-y += hash.h generic-y += hash.h
generic-y += local64.h generic-y += local64.h
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/kexec.h> #include <linux/kexec.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/device.h>
#include <linux/dma-contiguous.h>
#include <asm/addrspace.h> #include <asm/addrspace.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
...@@ -476,6 +478,7 @@ static void __init bootmem_init(void) ...@@ -476,6 +478,7 @@ static void __init bootmem_init(void)
* o bootmem_init() * o bootmem_init()
* o sparse_init() * o sparse_init()
* o paging_init() * o paging_init()
* o dma_continguous_reserve()
* *
* At this stage the bootmem allocator is ready to use. * At this stage the bootmem allocator is ready to use.
* *
...@@ -609,6 +612,7 @@ static void __init request_crashkernel(struct resource *res) ...@@ -609,6 +612,7 @@ static void __init request_crashkernel(struct resource *res)
static void __init arch_mem_init(char **cmdline_p) static void __init arch_mem_init(char **cmdline_p)
{ {
struct memblock_region *reg;
extern void plat_mem_setup(void); extern void plat_mem_setup(void);
/* call board setup routine */ /* call board setup routine */
...@@ -675,6 +679,11 @@ static void __init arch_mem_init(char **cmdline_p) ...@@ -675,6 +679,11 @@ static void __init arch_mem_init(char **cmdline_p)
sparse_init(); sparse_init();
plat_swiotlb_setup(); plat_swiotlb_setup();
paging_init(); 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) static void __init resource_init(void)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/dma-contiguous.h>
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/cpu-type.h> #include <asm/cpu-type.h>
...@@ -128,23 +129,30 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size, ...@@ -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) dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs)
{ {
void *ret; void *ret;
struct page *page = NULL;
unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
return ret; return ret;
gfp = massage_gfp_flags(dev, gfp); gfp = massage_gfp_flags(dev, gfp);
ret = (void *) __get_free_pages(gfp, get_order(size)); if (IS_ENABLED(CONFIG_DMA_CMA) && !(gfp & GFP_ATOMIC))
page = dma_alloc_from_contiguous(dev,
if (ret) { count, get_order(size));
memset(ret, 0, size); if (!page)
*dma_handle = plat_map_dma_mem(dev, ret, size); page = alloc_pages(gfp, get_order(size));
if (!plat_device_is_coherent(dev)) { if (!page)
dma_cache_wback_inv((unsigned long) ret, size); return NULL;
if (!hw_coherentio)
ret = UNCAC_ADDR(ret); 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; return ret;
...@@ -164,6 +172,8 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, ...@@ -164,6 +172,8 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
{ {
unsigned long addr = (unsigned long) vaddr; unsigned long addr = (unsigned long) vaddr;
int order = get_order(size); 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)) if (dma_release_from_coherent(dev, order, vaddr))
return; return;
...@@ -173,7 +183,10 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, ...@@ -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) if (!plat_device_is_coherent(dev) && !hw_coherentio)
addr = CAC_ADDR(addr); 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, static inline void __dma_sync_virtual(void *addr, size_t size,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment