summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/include/asm/Kbuild1
-rw-r--r--arch/mips/kernel/setup.c9
-rw-r--r--arch/mips/mm/dma-default.c37
4 files changed, 36 insertions, 12 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index d7c8bd4..ad6badb 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -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
diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild
index 335e529..c0b0957 100644
--- a/arch/mips/include/asm/Kbuild
+++ b/arch/mips/include/asm/Kbuild
@@ -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
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 7c1fe2b..b3b8f0d 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -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)
diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
index 44b6dff..33ba3c5 100644
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -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,
OpenPOWER on IntegriCloud