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: 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>
This commit is contained in:
parent
8057b30814
commit
f46493826a
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 (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 (ret) {
|
||||
memset(ret, 0, size);
|
||||
*dma_handle = plat_map_dma_mem(dev, ret, size);
|
||||
if (!page)
|
||||
return NULL;
|
||||
|
||||
if (!plat_device_is_coherent(dev)) {
|
||||
dma_cache_wback_inv((unsigned long) ret, size);
|
||||
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;
|
||||
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue