linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: lauraa@codeaurora.org (Laura Abbott)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 3/3] swiotlb: Add support for CMA allocations
Date: Mon,  9 Dec 2013 16:12:14 -0800	[thread overview]
Message-ID: <1386634334-31139-4-git-send-email-lauraa@codeaurora.org> (raw)
In-Reply-To: <1386634334-31139-1-git-send-email-lauraa@codeaurora.org>

Some architectures may implement the CMA APIs to allow allocation
of larger contiguous blocks of memory. Add support in the swiotlb
alloc/free functions to allocate from the CMA APIs instead of the
basic page allocator.

Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
---
 lib/swiotlb.c |   92 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 86 insertions(+), 6 deletions(-)

diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index e4399fa..77b4b17 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -29,6 +29,9 @@
 #include <linux/ctype.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
+#include <linux/dma-contiguous.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -610,6 +613,66 @@ void swiotlb_tbl_sync_single(struct device *hwdev, phys_addr_t tlb_addr,
 }
 EXPORT_SYMBOL_GPL(swiotlb_tbl_sync_single);
 
+static void * __alloc_from_contiguous(struct device *hwdev, size_t size,
+					struct page **ret_page)
+{
+	unsigned long order = get_order(size);
+	size_t count = size >> PAGE_SHIFT;
+	struct page *page;
+	void *ptr = NULL;
+
+	page = dma_alloc_from_contiguous(hwdev, count, order);
+	if (!page)
+		return NULL;
+
+	if (PageHighMem(page)) {
+		struct vm_struct *area;
+		unsigned long addr;
+
+		/*
+		 * DMA allocation can be mapped to user space, so lets
+		 * set VM_USERMAP flags too.
+		 */
+		area = get_vm_area(size, VM_USERMAP);
+		if (!area)
+			goto err;
+		addr = (unsigned long)area->addr;
+		area->phys_addr = __pfn_to_phys(page_to_pfn(page));
+
+		if (ioremap_page_range(addr, addr + size, area->phys_addr,
+		    PAGE_KERNEL)) {
+			vunmap((void *)addr);
+			goto err;
+		}
+		ptr = area->addr;
+	} else {
+		ptr = page_address(page);
+	}
+
+	*ret_page = page;
+	return ptr;
+
+err:
+	dma_release_from_contiguous(hwdev, page, count);
+	return NULL;
+}
+
+static void __free_from_contiguous(struct device *hwdev, struct page *page,
+				void *cpu_addr, size_t size)
+{
+	if (PageHighMem(page)) {
+		struct vm_struct *area = find_vm_area(cpu_addr);
+		if (!area) {
+			WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
+			return;
+		}
+		unmap_kernel_range((unsigned long)cpu_addr, size);
+		vunmap(cpu_addr);
+	}
+	dma_release_from_contiguous(hwdev, page, size >> PAGE_SHIFT);
+}
+
+
 void *
 swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 		       dma_addr_t *dma_handle, gfp_t flags)
@@ -618,18 +681,27 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
 	void *ret;
 	int order = get_order(size);
 	u64 dma_mask = DMA_BIT_MASK(32);
+	struct page *page;
 
 	if (hwdev && hwdev->coherent_dma_mask)
 		dma_mask = hwdev->coherent_dma_mask;
 
-	ret = (void *)__get_free_pages(flags, order);
-	if (ret) {
+	if (IS_ENABLED(CONFIG_DMA_CMA)) {
+		ret = __alloc_from_contiguous(hwdev, size, &page);
+		dev_addr = phys_to_dma(hwdev, page_to_phys(page));
+	} else {
+		ret = (void *)__get_free_pages(flags, order);
 		dev_addr = swiotlb_virt_to_bus(hwdev, ret);
+	}
+	if (ret) {
 		if (dev_addr + size - 1 > dma_mask) {
 			/*
 			 * The allocated memory isn't reachable by the device.
 			 */
-			free_pages((unsigned long) ret, order);
+			if(IS_ENABLED(CONFIG_DMA_CMA))
+				__free_from_contiguous(hwdev, page, ret, size);
+			else
+				free_pages((unsigned long) ret, order);
 			ret = NULL;
 		}
 	}
@@ -673,11 +745,19 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
 	phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
 
 	WARN_ON(irqs_disabled());
-	if (!is_swiotlb_buffer(paddr))
-		free_pages((unsigned long)vaddr, get_order(size));
-	else
+	if (!is_swiotlb_buffer(paddr)) {
+		if (IS_ENABLED(CONFIG_DMA_CMA)) {
+			__free_from_contiguous(hwdev,
+				pfn_to_page(paddr >> PAGE_SHIFT),
+				vaddr,
+				size);
+		} else {
+			free_pages((unsigned long)vaddr, get_order(size));
+		}
+	} else {
 		/* DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single */
 		swiotlb_tbl_unmap_single(hwdev, paddr, size, DMA_TO_DEVICE);
+	}
 }
 EXPORT_SYMBOL(swiotlb_free_coherent);
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

  parent reply	other threads:[~2013-12-10  0:12 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-10  0:12 [PATCH 0/3] CMA support for arm64 Laura Abbott
2013-12-10  0:12 ` [PATCH 1/3] arm64: Check for NULL device before getting the coherent_dma_mask Laura Abbott
2013-12-10  0:12 ` [PATCH 2/3] arm64: Enable CMA Laura Abbott
2013-12-10  0:12 ` Laura Abbott [this message]
2013-12-10  0:29   ` [PATCH 3/3] swiotlb: Add support for CMA allocations Konrad Rzeszutek Wilk
2013-12-10  0:36     ` Laura Abbott
2013-12-10  0:40       ` Konrad Rzeszutek Wilk
2013-12-10 10:25         ` Will Deacon
2013-12-10 10:42           ` Catalin Marinas
2013-12-10 13:50             ` Will Deacon
2013-12-10 13:56               ` Konrad Rzeszutek Wilk
2013-12-10 14:50               ` Catalin Marinas
2013-12-10 19:03                 ` Laura Abbott
2013-12-13  0:48             ` Laura Abbott
2013-12-13 13:37               ` Catalin Marinas
2013-12-13 13:45                 ` Will Deacon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1386634334-31139-4-git-send-email-lauraa@codeaurora.org \
    --to=lauraa@codeaurora.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).