Commit 9d2ffe5c authored by Max Filippov's avatar Max Filippov
Browse files

xtensa: enable HAVE_DMA_CONTIGUOUS



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: default avatarMax Filippov <jcmvbkbc@gmail.com>
parent 3863c58c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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
+17 −4
Original line number Diff line number Diff line
@@ -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,
+2 −0
Original line number Diff line number Diff line
@@ -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();
}