Skip to contentSkip to conversation

DMA Atomic pool for arm64

PATCH In review Laura Abbott 3 participants 10 messages Aug 11, 2014 – Aug 27, 2014

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

v7 cover DMA Atomic pool for arm64

Hi,

This is v7 of the series to add an atomic pool for arm64 and refactor some of the dma atomic code. You know the drill.

Thanks,
Laura

v7: Added correct power aligned algorithm patch. Addressed comments from Andrew.

Laura Abbott (5):
lib/genalloc.c: Add power aligned algorithm lib/genalloc.c: Add genpool range check function
common: dma-mapping: Introduce common remapping functions
arm: use genalloc for the atomic pool
arm64: Add atomic pool for non-coherent and CMA allocations.

 arch/arm/Kconfig                         |   1 +
 arch/arm/mm/dma-mapping.c                | 210 +++++++++----------------------
 arch/arm64/Kconfig                       |   1 +
 arch/arm64/mm/dma-mapping.c              | 164 +++++++++++++++++++++---
 drivers/base/dma-mapping.c               |  68 ++++++++++
 include/asm-generic/dma-mapping-common.h |   9 ++
 include/linux/genalloc.h                 |   7 ++
 lib/genalloc.c                           |  49 ++++++++
 8 files changed, 338 insertions(+), 171 deletions(-)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#1 lore raw

PATCH v7 1/5 lib/genalloc.c: Add power aligned algorithm

One of the more common algorithms used for allocation is to align the start address of the allocation to the order of size requested. Add this as an algorithm option for genalloc.

---
 include/linux/genalloc.h |  4 ++++
 lib/genalloc.c           | 20 ++++++++++++++++++++
 2 files changed, 24 insertions(+)
include/linux/genalloc.h +4 -0
index 1c2fdaa..3cd0934 100644
@@ -110,6 +110,10 @@ extern void gen_pool_set_algo(struct gen_pool *pool, genpool_algo_t algo,
 extern unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
 		unsigned long start, unsigned int nr, void *data);
 
+extern unsigned long gen_pool_first_fit_order_align(unsigned long *map,
+		unsigned long size, unsigned long start, unsigned int nr,
+		void *data);
+
 extern unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
 		unsigned long start, unsigned int nr, void *data);
 
lib/genalloc.c +20 -0
index bdb9a45..c2b3ad7 100644
@@ -481,6 +481,26 @@ unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
 EXPORT_SYMBOL(gen_pool_first_fit);
 
 /**
+ * gen_pool_first_fit_order_align - find the first available region
+ * of memory matching the size requirement. The region will be aligned
+ * to the order of the size specified.
+ * @map: The address to base the search on
+ * @size: The bitmap size in bits
+ * @start: The bitnumber to start searching at
+ * @nr: The number of zeroed bits we're looking for
+ * @data: additional data - unused
+ */
+unsigned long gen_pool_first_fit_order_align(unsigned long *map,
+		unsigned long size, unsigned long start,
+		unsigned int nr, void *data)
+{
+	unsigned long align_mask = roundup_pow_of_two(nr) - 1;
+
+	return bitmap_find_next_zero_area(map, size, start, nr, align_mask);
+}
+EXPORT_SYMBOL(gen_pool_first_fit_order_align);
+
+/**
  * gen_pool_best_fit - find the best fitting region of memory
  * macthing the size requirement (no alignment constraint)
  * @map: The address to base the search on
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#2 lore raw

PATCH v7 2/5 lib/genalloc.c: Add genpool range check function

In reply to Laura Abbott

After allocating an address from a particular genpool, there is no good way to verify if that address actually belongs to a genpool. Introduce addr_in_gen_pool which will return if an address plus size falls completely within the genpool range.

---
 include/linux/genalloc.h |  3 +++
 lib/genalloc.c           | 29 +++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)
include/linux/genalloc.h +3 -0
index 3cd0934..1ccaab4 100644
@@ -121,6 +121,9 @@ extern struct gen_pool *devm_gen_pool_create(struct device *dev,
 		int min_alloc_order, int nid);
 extern struct gen_pool *dev_get_gen_pool(struct device *dev);
 
+bool addr_in_gen_pool(struct gen_pool *pool, unsigned long start,
+			size_t size);
+
 #ifdef CONFIG_OF
 extern struct gen_pool *of_get_named_gen_pool(struct device_node *np,
 	const char *propname, int index);
lib/genalloc.c +29 -0
index c2b3ad7..c7a91cf 100644
@@ -403,6 +403,35 @@ void gen_pool_for_each_chunk(struct gen_pool *pool,
 EXPORT_SYMBOL(gen_pool_for_each_chunk);
 
 /**
+ * addr_in_gen_pool - checks if an address falls within the range of a pool
+ * @pool:	the generic memory pool
+ * @start:	start address
+ * @size:	size of the region
+ *
+ * Check if the range of addresses falls within the specified pool. Returns
+ * true if the entire range is contained in the pool and false otherwise.
+ */
+bool addr_in_gen_pool(struct gen_pool *pool, unsigned long start,
+			size_t size)
+{
+	bool found = false;
+	unsigned long end = start + size;
+	struct gen_pool_chunk *chunk;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(chunk, &(pool)->chunks, next_chunk) {
+		if (start >= chunk->start_addr && start <= chunk->end_addr) {
+			if (end <= chunk->end_addr) {
+				found = true;
+				break;
+			}
+		}
+	}
+	rcu_read_unlock();
+	return found;
+}
+
+/**
  * gen_pool_avail - get available free space of the pool
  * @pool: pool to get available free space
  *
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#3 lore raw

PATCH v7 3/5 common: dma-mapping: Introduce common remapping functions

In reply to Laura Abbott

For architectures without coherent DMA, memory for DMA may need to be remapped with coherent attributes. Factor out the the remapping code from arm and put it in a common location to reduce code duplication.

As part of this, the arm APIs are now migrated away from ioremap_page_range to the common APIs which use map_vm_area for remapping. This should be an equivalent change and using map_vm_area is more correct as ioremap_page_range is intended to bring in io addresses into the cpu space and not regular kernel managed memory.

---
 arch/arm/mm/dma-mapping.c                | 57 +++++---------------------
 drivers/base/dma-mapping.c               | 68 ++++++++++++++++++++++++++++++++
 include/asm-generic/dma-mapping-common.h |  9 +++++
 3 files changed, 86 insertions(+), 48 deletions(-)
arch/arm/mm/dma-mapping.c +9 -48
index 4c88935..f5190ac 100644
@@ -297,37 +297,19 @@ static void *
 __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
 	const void *caller)
 {
-	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_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
-				  caller);
-	if (!area)
-		return NULL;
-	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, prot)) {
-		vunmap((void *)addr);
-		return NULL;
-	}
-	return (void *)addr;
+	return dma_common_contiguous_remap(page, size,
+			VM_ARM_DMA_CONSISTENT | VM_USERMAP,
+			prot, caller);
 }
 
 static void __dma_free_remap(void *cpu_addr, size_t size)
 {
-	unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP;
-	struct vm_struct *area = find_vm_area(cpu_addr);
-	if (!area || (area->flags & flags) != flags) {
-		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_common_free_remap(cpu_addr, size,
+			VM_ARM_DMA_CONSISTENT | VM_USERMAP);
 }
 
 #define DEFAULT_DMA_COHERENT_POOL_SIZE	SZ_256K
@@ -1261,29 +1243,8 @@ static void *
 __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
 		    const void *caller)
 {
-	unsigned int i, nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
-	struct vm_struct *area;
-	unsigned long p;
-
-	area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
-				  caller);
-	if (!area)
-		return NULL;
-
-	area->pages = pages;
-	area->nr_pages = nr_pages;
-	p = (unsigned long)area->addr;
-
-	for (i = 0; i < nr_pages; i++) {
-		phys_addr_t phys = __pfn_to_phys(page_to_pfn(pages[i]));
-		if (ioremap_page_range(p, p + PAGE_SIZE, phys, prot))
-			goto err;
-		p += PAGE_SIZE;
-	}
-	return area->addr;
-err:
-	unmap_kernel_range((unsigned long)area->addr, size);
-	vunmap(area->addr);
+	return dma_common_pages_remap(pages, size,
+			VM_ARM_DMA_CONSISTENT | VM_USERMAP, prot, caller);
 	return NULL;
 }
 
@@ -1491,8 +1452,8 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
 	}
 
 	if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
-		unmap_kernel_range((unsigned long)cpu_addr, size);
-		vunmap(cpu_addr);
+		dma_common_free_remap(cpu_addr, size,
+			VM_ARM_DMA_CONSISTENT | VM_USERMAP);
 	}
 
 	__iommu_remove_mapping(dev, handle, size);
drivers/base/dma-mapping.c +68 -0

77 lines not on this page · raw message

include/asm-generic/dma-mapping-common.h +9 -0
index de8bf89..a9fd248 100644
@@ -179,6 +179,15 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
 			   void *cpu_addr, dma_addr_t dma_addr, size_t size);
 
+void *dma_common_contiguous_remap(struct page *page, size_t size,
+			unsigned long vm_flags,
+			pgprot_t prot, const void *caller);
+
+void *dma_common_pages_remap(struct page **pages, size_t size,
+			unsigned long vm_flags, pgprot_t prot,
+			const void *caller);
+void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags);
+
 /**
  * dma_mmap_attrs - map a coherent DMA allocation into user space
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#4 lore raw

Re: [PATCHv7 3/5] common: dma-mapping: Introduce common remapping functions

Quoted 6 lines · Laura Abbott

For architectures without coherent DMA, memory for DMA may need to be remapped with coherent attributes. Factor out the the remapping code from arm and put it in a common location to reduce code duplication.

Quoted 8 lines

As part of this, the arm APIs are now migrated away from ioremap_page_range to the common APIs which use map_vm_area for remapping. This should be an equivalent change and using map_vm_area is more correct as ioremap_page_range is intended to bring in io addresses into the cpu space and not regular kernel managed memory.

This commit in linux-next () breaks the build for metag:

drivers/base/dma-mapping.c: In function ?dma_common_contiguous_remap?:
drivers/base/dma-mapping.c:294: error: implicit declaration of function ?dma_common_pages_remap? drivers/base/dma-mapping.c:294: warning: assignment makes pointer from integer without a cast
drivers/base/dma-mapping.c: At top level:
drivers/base/dma-mapping.c:308: error: conflicting types for ?dma_common_pages_remap?
drivers/base/dma-mapping.c:294: error: previous implicit declaration of ?dma_common_pages_remap? was here

Looks like metag isn't alone either:

$ git grep -L dma-mapping-common arch/*/include/asm/dma-mapping.h
arch/arc/include/asm/dma-mapping.h
arch/avr32/include/asm/dma-mapping.h
arch/blackfin/include/asm/dma-mapping.h
arch/c6x/include/asm/dma-mapping.h
arch/cris/include/asm/dma-mapping.h
arch/frv/include/asm/dma-mapping.h
arch/m68k/include/asm/dma-mapping.h
arch/metag/include/asm/dma-mapping.h
arch/mn10300/include/asm/dma-mapping.h
arch/parisc/include/asm/dma-mapping.h
arch/xtensa/include/asm/dma-mapping.h

I've checked a couple of these arches (blackfin, xtensa) which don't include dma-mapping-common.h and their builds seem to be broken too.

Cheers
James

Quoted 208 lines
---
 arch/arm/mm/dma-mapping.c                | 57 +++++---------------------
 drivers/base/dma-mapping.c               | 68 ++++++++++++++++++++++++++++++++
 include/asm-generic/dma-mapping-common.h |  9 +++++
 3 files changed, 86 insertions(+), 48 deletions(-)
arch/arm/mm/dma-mapping.c +9 -48
index 4c88935..f5190ac 100644
@@ -297,37 +297,19 @@ static void *
 __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
        const void *caller)
 {
-       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_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
-                                 caller);
-       if (!area)
-               return NULL;
-       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, prot)) {
-               vunmap((void *)addr);
-               return NULL;
-       }
-       return (void *)addr;
+       return dma_common_contiguous_remap(page, size,
+                       VM_ARM_DMA_CONSISTENT | VM_USERMAP,
+                       prot, caller);
 }
 
 static void __dma_free_remap(void *cpu_addr, size_t size)
 {
-       unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP;
-       struct vm_struct *area = find_vm_area(cpu_addr);
-       if (!area || (area->flags & flags) != flags) {
-               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_common_free_remap(cpu_addr, size,
+                       VM_ARM_DMA_CONSISTENT | VM_USERMAP);
 }
 
 #define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
@@ -1261,29 +1243,8 @@ static void *
 __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
                    const void *caller)
 {
-       unsigned int i, nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       struct vm_struct *area;
-       unsigned long p;
-
-       area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
-                                 caller);
-       if (!area)
-               return NULL;
-
-       area->pages = pages;
-       area->nr_pages = nr_pages;
-       p = (unsigned long)area->addr;
-
-       for (i = 0; i < nr_pages; i++) {
-               phys_addr_t phys = __pfn_to_phys(page_to_pfn(pages[i]));
-               if (ioremap_page_range(p, p + PAGE_SIZE, phys, prot))
-                       goto err;
-               p += PAGE_SIZE;
-       }
-       return area->addr;
-err:
-       unmap_kernel_range((unsigned long)area->addr, size);
-       vunmap(area->addr);
+       return dma_common_pages_remap(pages, size,
+                       VM_ARM_DMA_CONSISTENT | VM_USERMAP, prot, caller);
        return NULL;
 }
 
@@ -1491,8 +1452,8 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
        }
 
        if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
-               unmap_kernel_range((unsigned long)cpu_addr, size);
-               vunmap(cpu_addr);
+               dma_common_free_remap(cpu_addr, size,
+                       VM_ARM_DMA_CONSISTENT | VM_USERMAP);
        }
 
        __iommu_remove_mapping(dev, handle, size);
drivers/base/dma-mapping.c +68 -0
index 6cd08e1..1bc46df 100644
@@ -10,6 +10,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <asm-generic/dma-coherent.h>
 
 /*
@@ -267,3 +269,69 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
        return ret;
 }
 EXPORT_SYMBOL(dma_common_mmap);
+
+/*
+ * remaps an allocated contiguous region into another vm_area.
+ * Cannot be used in non-sleeping contexts
+ */
+
+void *dma_common_contiguous_remap(struct page *page, size_t size,
+                       unsigned long vm_flags,
+                       pgprot_t prot, const void *caller)
+{
+       int i;
+       struct page **pages;
+       void *ptr;
+       unsigned long pfn;
+
+       pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL);
+       if (!pages)
+               return NULL;
+
+       for (i = 0, pfn = page_to_pfn(page); i < (size >> PAGE_SHIFT); i++)
+               pages[i] = pfn_to_page(pfn + i);
+
+       ptr = dma_common_pages_remap(pages, size, vm_flags, prot, caller);
+
+       kfree(pages);
+
+       return ptr;
+}
+
+/*
+ * remaps an array of PAGE_SIZE pages into another vm_area
+ * Cannot be used in non-sleeping contexts
+ */
+void *dma_common_pages_remap(struct page **pages, size_t size,
+                       unsigned long vm_flags, pgprot_t prot,
+                       const void *caller)
+{
+       struct vm_struct *area;
+
+       area = get_vm_area_caller(size, vm_flags, caller);
+       if (!area)
+               return NULL;
+
+       if (map_vm_area(area, prot, pages)) {
+               vunmap(area->addr);
+               return NULL;
+       }
+
+       return area->addr;
+}
+
+/*
+ * unmaps a range previously mapped by dma_common_*_remap
+ */
+void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
+{
+       struct vm_struct *area = find_vm_area(cpu_addr);
+
+       if (!area || (area->flags & vm_flags) != vm_flags) {
+               WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
+               return;
+       }
+
+       unmap_kernel_range((unsigned long)cpu_addr, size);
+       vunmap(cpu_addr);
+}
include/asm-generic/dma-mapping-common.h +9 -1
index de8bf89..a9fd248 100644
@@ -179,6 +179,15 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
                           void *cpu_addr, dma_addr_t dma_addr, size_t size);
 
+void *dma_common_contiguous_remap(struct page *page, size_t size,
+                       unsigned long vm_flags,
+                       pgprot_t prot, const void *caller);
+
+void *dma_common_pages_remap(struct page **pages, size_t size,
+                       unsigned long vm_flags, pgprot_t prot,
+                       const void *caller);
+void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags);
+
 /**
  * dma_mmap_attrs - map a coherent DMA allocation into user space
  * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
--

The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#5 lore raw

Re: [PATCHv7 3/5] common: dma-mapping: Introduce common remapping functions

Quoted 44 lines · James Hogan
Quoted 6 lines · Laura Abbott

For architectures without coherent DMA, memory for DMA may need to be remapped with coherent attributes. Factor out the the remapping code from arm and put it in a common location to reduce code duplication.

Quoted 8 lines

As part of this, the arm APIs are now migrated away from ioremap_page_range to the common APIs which use map_vm_area for remapping. This should be an equivalent change and using map_vm_area is more correct as ioremap_page_range is intended to bring in io addresses into the cpu space and not regular kernel managed memory.

This commit in linux-next () breaks the build for metag:

drivers/base/dma-mapping.c: In function ?dma_common_contiguous_remap?:
drivers/base/dma-mapping.c:294: error: implicit declaration of function ?dma_common_pages_remap? drivers/base/dma-mapping.c:294: warning: assignment makes pointer from integer without a cast
drivers/base/dma-mapping.c: At top level:
drivers/base/dma-mapping.c:308: error: conflicting types for ?dma_common_pages_remap?
drivers/base/dma-mapping.c:294: error: previous implicit declaration of ?dma_common_pages_remap? was here

Looks like metag isn't alone either:

$ git grep -L dma-mapping-common arch/*/include/asm/dma-mapping.h
arch/arc/include/asm/dma-mapping.h
arch/avr32/include/asm/dma-mapping.h
arch/blackfin/include/asm/dma-mapping.h
arch/c6x/include/asm/dma-mapping.h
arch/cris/include/asm/dma-mapping.h
arch/frv/include/asm/dma-mapping.h
arch/m68k/include/asm/dma-mapping.h
arch/metag/include/asm/dma-mapping.h
arch/mn10300/include/asm/dma-mapping.h
arch/parisc/include/asm/dma-mapping.h
arch/xtensa/include/asm/dma-mapping.h
Quoted 6 lines

I've checked a couple of these arches (blackfin, xtensa) which don't include dma-mapping-common.h and their builds seem to be broken too.

Cheers
James

Thanks for the report. Would you mind giving the following patch a test (this is theoretical only but I think it should work)

-----8<------

Quoted 1 line

From 81c9a5504cbc1d72ff1df084d48502b248cd79d0 Mon Sep 17 00:00:00 2001

From: Laura Abbott <[email protected]>
Date: Tue, 26 Aug 2014 09:50:49 -0700
Subject: [PATCH] common: dma-mapping: Swap function order

Fix the order of dma_common_contiguous_remap and dma_common_pages_remap to avoid function declaration errors:

drivers/base/dma-mapping.c: In function 'dma_common_contiguous_remap':
drivers/base/dma-mapping.c:294: error: implicit declaration of function 'dma_common_pages_remap' drivers/base/dma-mapping.c:294: warning: assignment makes pointer from integer without a cast
drivers/base/dma-mapping.c: At top level:
drivers/base/dma-mapping.c:308: error: conflicting types for 'dma_common_pages_remap'
drivers/base/dma-mapping.c:294: error: previous implicit declaration of 'dma_common_pages_remap' was here

Change-Id I65db739114e8f5816a24a279a2ff1a6dc92e2b83
---
 drivers/base/dma-mapping.c | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)
drivers/base/dma-mapping.c +22 -22
index 1bc46df..056fd46 100644
@@ -271,6 +271,28 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
 EXPORT_SYMBOL(dma_common_mmap);
 
 /*
+ * remaps an array of PAGE_SIZE pages into another vm_area
+ * Cannot be used in non-sleeping contexts
+ */
+void *dma_common_pages_remap(struct page **pages, size_t size,
+			unsigned long vm_flags, pgprot_t prot,
+			const void *caller)
+{
+	struct vm_struct *area;
+
+	area = get_vm_area_caller(size, vm_flags, caller);
+	if (!area)
+		return NULL;
+
+	if (map_vm_area(area, prot, pages)) {
+		vunmap(area->addr);
+		return NULL;
+	}
+
+	return area->addr;
+}
+
+/*
  * remaps an allocated contiguous region into another vm_area.
  * Cannot be used in non-sleeping contexts
  */
@@ -299,28 +321,6 @@ void *dma_common_contiguous_remap(struct page *page, size_t size,
 }
 
 /*
- * remaps an array of PAGE_SIZE pages into another vm_area
- * Cannot be used in non-sleeping contexts
- */
-void *dma_common_pages_remap(struct page **pages, size_t size,
-			unsigned long vm_flags, pgprot_t prot,
-			const void *caller)
-{
-	struct vm_struct *area;
-
-	area = get_vm_area_caller(size, vm_flags, caller);
-	if (!area)
-		return NULL;
-
-	if (map_vm_area(area, prot, pages)) {
-		vunmap(area->addr);
-		return NULL;
-	}
-
-	return area->addr;
-}
-
-/*
  * unmaps a range previously mapped by dma_common_*_remap
  */
 void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
Signature · 6 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#6 lore raw

Re: [PATCHv7 3/5] common: dma-mapping: Introduce common remapping functions

Quoted 48 lines · Laura Abbott
Quoted 47 lines · James Hogan
Quoted 6 lines · Laura Abbott

For architectures without coherent DMA, memory for DMA may need to be remapped with coherent attributes. Factor out the the remapping code from arm and put it in a common location to reduce code duplication.

Quoted 8 lines

As part of this, the arm APIs are now migrated away from ioremap_page_range to the common APIs which use map_vm_area for remapping. This should be an equivalent change and using map_vm_area is more correct as ioremap_page_range is intended to bring in io addresses into the cpu space and not regular kernel managed memory.

This commit in linux-next () breaks the build for metag:

drivers/base/dma-mapping.c: In function ?dma_common_contiguous_remap?:
drivers/base/dma-mapping.c:294: error: implicit declaration of function ?dma_common_pages_remap? drivers/base/dma-mapping.c:294: warning: assignment makes pointer from integer without a cast
drivers/base/dma-mapping.c: At top level:
drivers/base/dma-mapping.c:308: error: conflicting types for ?dma_common_pages_remap?
drivers/base/dma-mapping.c:294: error: previous implicit declaration of ?dma_common_pages_remap? was here

Looks like metag isn't alone either:

$ git grep -L dma-mapping-common arch/*/include/asm/dma-mapping.h
arch/arc/include/asm/dma-mapping.h
arch/avr32/include/asm/dma-mapping.h
arch/blackfin/include/asm/dma-mapping.h
arch/c6x/include/asm/dma-mapping.h
arch/cris/include/asm/dma-mapping.h
arch/frv/include/asm/dma-mapping.h
arch/m68k/include/asm/dma-mapping.h
arch/metag/include/asm/dma-mapping.h
arch/mn10300/include/asm/dma-mapping.h
arch/parisc/include/asm/dma-mapping.h
arch/xtensa/include/asm/dma-mapping.h

I've checked a couple of these arches (blackfin, xtensa) which don't include dma-mapping-common.h and their builds seem to be broken too.

Quoted 6 lines
Quoted 3 lines

Cheers
James

Thanks for the report. Would you mind giving the following patch a test (this is theoretical only but I think it should work)

It certainly fixes the build for metag.

Thanks
James

Quoted 93 lines

-----8<------

From 81c9a5504cbc1d72ff1df084d48502b248cd79d0 Mon Sep 17 00:00:00 2001
From: Laura Abbott <[email protected]>
Date: Tue, 26 Aug 2014 09:50:49 -0700
Subject: [PATCH] common: dma-mapping: Swap function order

Fix the order of dma_common_contiguous_remap and dma_common_pages_remap to avoid function declaration errors:

drivers/base/dma-mapping.c: In function 'dma_common_contiguous_remap':
drivers/base/dma-mapping.c:294: error: implicit declaration of function 'dma_common_pages_remap' drivers/base/dma-mapping.c:294: warning: assignment makes pointer from integer without a cast
drivers/base/dma-mapping.c: At top level:
drivers/base/dma-mapping.c:308: error: conflicting types for 'dma_common_pages_remap'
drivers/base/dma-mapping.c:294: error: previous implicit declaration of 'dma_common_pages_remap' was here

Change-Id I65db739114e8f5816a24a279a2ff1a6dc92e2b83
---
 drivers/base/dma-mapping.c | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)
drivers/base/dma-mapping.c +22 -22
index 1bc46df..056fd46 100644
@@ -271,6 +271,28 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
 EXPORT_SYMBOL(dma_common_mmap);
 
 /*
+ * remaps an array of PAGE_SIZE pages into another vm_area
+ * Cannot be used in non-sleeping contexts
+ */
+void *dma_common_pages_remap(struct page **pages, size_t size,
+			unsigned long vm_flags, pgprot_t prot,
+			const void *caller)
+{
+	struct vm_struct *area;
+
+	area = get_vm_area_caller(size, vm_flags, caller);
+	if (!area)
+		return NULL;
+
+	if (map_vm_area(area, prot, pages)) {
+		vunmap(area->addr);
+		return NULL;
+	}
+
+	return area->addr;
+}
+
+/*
  * remaps an allocated contiguous region into another vm_area.
  * Cannot be used in non-sleeping contexts
  */
@@ -299,28 +321,6 @@ void *dma_common_contiguous_remap(struct page *page, size_t size,
 }
 
 /*
- * remaps an array of PAGE_SIZE pages into another vm_area
- * Cannot be used in non-sleeping contexts
- */
-void *dma_common_pages_remap(struct page **pages, size_t size,
-			unsigned long vm_flags, pgprot_t prot,
-			const void *caller)
-{
-	struct vm_struct *area;
-
-	area = get_vm_area_caller(size, vm_flags, caller);
-	if (!area)
-		return NULL;
-
-	if (map_vm_area(area, prot, pages)) {
-		vunmap(area->addr);
-		return NULL;
-	}
-
-	return area->addr;
-}
-
-/*
  * unmaps a range previously mapped by dma_common_*_remap
  */
 void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
#7 lore raw

Re: [PATCHv7 3/5] common: dma-mapping: Introduce common remapping functions

In reply to Laura Abbott
Quoted 48 lines · Laura Abbott
Quoted 47 lines · James Hogan
Quoted 6 lines · Laura Abbott

For architectures without coherent DMA, memory for DMA may need to be remapped with coherent attributes. Factor out the the remapping code from arm and put it in a common location to reduce code duplication.

Quoted 8 lines

As part of this, the arm APIs are now migrated away from ioremap_page_range to the common APIs which use map_vm_area for remapping. This should be an equivalent change and using map_vm_area is more correct as ioremap_page_range is intended to bring in io addresses into the cpu space and not regular kernel managed memory.

This commit in linux-next () breaks the build for metag:

drivers/base/dma-mapping.c: In function ?dma_common_contiguous_remap?:
drivers/base/dma-mapping.c:294: error: implicit declaration of function ?dma_common_pages_remap? drivers/base/dma-mapping.c:294: warning: assignment makes pointer from integer without a cast
drivers/base/dma-mapping.c: At top level:
drivers/base/dma-mapping.c:308: error: conflicting types for ?dma_common_pages_remap?
drivers/base/dma-mapping.c:294: error: previous implicit declaration of ?dma_common_pages_remap? was here

Looks like metag isn't alone either:

$ git grep -L dma-mapping-common arch/*/include/asm/dma-mapping.h
arch/arc/include/asm/dma-mapping.h
arch/avr32/include/asm/dma-mapping.h
arch/blackfin/include/asm/dma-mapping.h
arch/c6x/include/asm/dma-mapping.h
arch/cris/include/asm/dma-mapping.h
arch/frv/include/asm/dma-mapping.h
arch/m68k/include/asm/dma-mapping.h
arch/metag/include/asm/dma-mapping.h
arch/mn10300/include/asm/dma-mapping.h
arch/parisc/include/asm/dma-mapping.h
arch/xtensa/include/asm/dma-mapping.h

I've checked a couple of these arches (blackfin, xtensa) which don't include dma-mapping-common.h and their builds seem to be broken too.

Quoted 6 lines
Quoted 3 lines

Cheers
James

Thanks for the report. Would you mind giving the following patch a test (this is theoretical only but I think it should work)

There's a further problem with c6x (no MMU):

drivers/built-in.o: In function `dma_common_pages_remap':
(.text+0x220c4): undefined reference to get_vm_area_caller' drivers/built-in.o: In function dma_common_pages_remap':
(.text+0x22108): undefined reference to map_vm_area' drivers/built-in.o: In function dma_common_free_remap':
(.text+0x22278): undefined reference to `find_vm_area'

#8 lore raw

PATCH v7 4/5 arm: use genalloc for the atomic pool

In reply to Laura Abbott

ARM currently uses a bitmap for tracking atomic allocations. genalloc already handles this type of memory pool allocation so switch to using that instead.

---
 arch/arm/Kconfig          |   1 +
 arch/arm/mm/dma-mapping.c | 153 +++++++++++++++-------------------------------
 2 files changed, 50 insertions(+), 104 deletions(-)
arch/arm/Kconfig +1 -0
index 88acf8b..98776f5 100644
@@ -14,6 +14,7 @@ config ARM
 	select CLONE_BACKWARDS
 	select CPU_PM if (SUSPEND || CPU_IDLE)
 	select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS
+	select GENERIC_ALLOCATOR
 	select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
 	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
 	select GENERIC_IDLE_POLL_SETUP
arch/arm/mm/dma-mapping.c +49 -104

231 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#9 lore raw

PATCH v7 5/5 arm64: Add atomic pool for non-coherent and CMA allocations.

In reply to Laura Abbott

Neither CMA nor noncoherent allocations support atomic allocations. Add a dedicated atomic pool to support this.

---
 arch/arm64/Kconfig          |   1 +
 arch/arm64/mm/dma-mapping.c | 164 +++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 146 insertions(+), 19 deletions(-)
arch/arm64/Kconfig +1 -0
index 839f48c..335374b 100644
@@ -16,6 +16,7 @@ config ARM64
 	select COMMON_CLK
 	select CPU_PM if (SUSPEND || CPU_IDLE)
 	select DCACHE_WORD_ACCESS
+	select GENERIC_ALLOCATOR
 	select GENERIC_CLOCKEVENTS
 	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
 	select GENERIC_CPU_AUTOPROBE
arch/arm64/mm/dma-mapping.c +145 -19

233 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation