Atomic pool for arm64
Subsystems (6)
v4 cover Atomic pool for arm64
Hi,
This is another revision of the series to properly add atomic allocations for arm64. This version mostly addressed review comments. As always, reviews and testing welcome
Thanks,
Laura
v4: Addressed comments from Thierry and Catalin. Updated map_vm_area call in dma_common_pages_remap since the API changed.
v3: Now a patch series due to refactoring of arm code. arm and arm64 now both use genalloc for atomic pool management. genalloc extensions added. DMA remapping code factored out as well.
v2: Various bug fixes pointed out by David and Ritesh (CMA dependency, swapping coherent, noncoherent). I'm still not sure how to address the devicetree suggestion by Will [1][2]. I added the devicetree mailing list this time around to get more input on this.
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/249180.html
[2] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/249528.html
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 | 67 ++++++++++ include/asm-generic/dma-mapping-common.h | 9 ++ include/linux/genalloc.h | 7 ++ lib/genalloc.c | 50 ++++++++ 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
PATCH v4 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 | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+)
include/linux/genalloc.h +4 -0
@@ -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 +21 -0
@@ -481,6 +481,27 @@ 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 order = (unsigned long ) data; +unsigned long align_mask = (1 <<get_order (nr << order)) -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
PATCH v4 2/5 lib/genalloc.c: Add genpool range check function
In reply to Laura AbbottAfter 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
@@ -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
@@ -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. Takes +* the rcu_read_lock for the duration of the check. +*/ +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
PATCH v4 3/5 common: dma-mapping: Introduce common remapping functions
In reply to Laura AbbottFor 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 reduced code duplication.
--- arch/arm/mm/dma-mapping.c | 57 +++++---------------------- drivers/base/dma-mapping.c | 67 ++++++++++++++++++++++++++++++++ include/asm-generic/dma-mapping-common.h | 9 +++++ 3 files changed, 85 insertions(+), 48 deletions(-)
arch/arm/mm/dma-mapping.c +9 -48
@@ -298,37 +298,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
@@ -1262,29 +1244,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 ; }
@@ -1492,8 +1453,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 +67 -0
76 lines not on this page · raw message
include/asm-generic/dma-mapping-common.h +9 -0
@@ -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
Catalin Marinas
maintainerRe: [PATCHv4 3/5] common: dma-mapping: Introduce common remapping functions
Quoted 18 lines · Laura Abbott
arch/arm/mm/dma-mapping.c +0
-8@@ -298,37 +298,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;
arch/arm/mm/dma-mapping.c static void * · line 307
Quoted 10 lines
arch/arm/mm/dma-mapping.c +3
-7- 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);
I think we still need at least a comment in the commit log since the arm code is moving from ioremap_page_range() to map_vm_area(). There is a slight performance penalty with the addition of a kmalloc() on this path.
Or even better (IMO), see below.
Quoted 2 lines
drivers/base/dma-mapping.c +0
-0
[...]
Quoted 11 lines
drivers/base/dma-mapping.c +11
-0+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; + + pages =kmalloc (sizeof (struct page *) <<get_order (size),GFP_KERNEL ); +if (!pages) +return NULL ;
drivers/base/dma-mapping.c int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, · line 298
Quoted 10 lines
drivers/base/dma-mapping.c +10
-0+ +for (i =0 ; i < (size >>PAGE_SHIFT ); i++) + pages[i] = page + i; + + ptr =dma_common_pages_remap (pages, size, vm_flags, prot, caller); + +kfree (pages); + +return ptr; +}
You could avoid the dma_common_page_remap() here (and kmalloc) and simply use ioremap_page_range(). We know that dma_common_contiguous_remap() is only called with contiguous physical range, so ioremap_page_range() is suitable. It also makes it a non-functional change for arch/arm.
Signature · 1 line
Catalin
Re: [PATCHv4 3/5] common: dma-mapping: Introduce common remapping functions
Quoted 59 lines · Catalin Marinas
Quoted 18 lines · Laura Abbott
arch/arm/mm/dma-mapping.c +0
-8@@ -298,37 +298,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;arch/arm/mm/dma-mapping.c static void * · line 307
Quoted 10 lines
arch/arm/mm/dma-mapping.c +3
-7- 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);I think we still need at least a comment in the commit log since the arm code is moving from
ioremap_page_range()tomap_vm_area(). There is a slight performance penalty with the addition of akmalloc()on this path.Or even better (IMO), see below.
Quoted 2 lines
drivers/base/dma-mapping.c +0
-0[...]
Quoted 19 lines
drivers/base/dma-mapping.c +19
-0+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; + + pages =kmalloc (sizeof (struct page *) <<get_order (size),GFP_KERNEL ); +if (!pages) +return NULL ; + +for (i =0 ; i < (size >>PAGE_SHIFT ); i++) + pages[i] = page + i; + + ptr =dma_common_pages_remap (pages, size, vm_flags, prot, caller); + +kfree (pages); +
Quoted 9 lines
drivers/base/dma-mapping.c
Quoted 2 lines
drivers/base/dma-mapping.c +2
-0+return ptr; +}You could avoid the
dma_common_page_remap()here (and kmalloc) and simply useioremap_page_range(). We know thatdma_common_contiguous_remap()is only called with contiguous physical range, soioremap_page_range()is suitable. It also makes it a non-functional change forarch/arm.
My original thought with using map_vm_area vs. ioremap_page_range was that ioremap_page_range is really intended for mapping io devices and the like into the kernel virtual address space. map_vm_area is designed to handle pages of kernel managed memory. Perhaps it's too nit-picky a distinction though.
Thanks,
Laura
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Catalin Marinas
maintainerRe: [PATCHv4 3/5] common: dma-mapping: Introduce common remapping functions
Quoted 33 lines · Laura Abbott
Quoted 23 lines · Catalin Marinas
Quoted 2 lines · Laura Abbott
drivers/base/dma-mapping.c +0
-0[...]
Quoted 19 lines
drivers/base/dma-mapping.c +19
-0+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; + + pages =kmalloc (sizeof (struct page *) <<get_order (size),GFP_KERNEL ); +if (!pages) +return NULL ; + +for (i =0 ; i < (size >>PAGE_SHIFT ); i++) + pages[i] = page + i; + + ptr =dma_common_pages_remap (pages, size, vm_flags, prot, caller); + +kfree (pages); +Quoted 8 lines
drivers/base/dma-mapping.c
Quoted 2 lines
drivers/base/dma-mapping.c +2
-0+return ptr; +}You could avoid the
dma_common_page_remap()here (and kmalloc) and simply useioremap_page_range(). We know thatdma_common_contiguous_remap()is only called with contiguous physical range, soioremap_page_range()is suitable. It also makes it a non-functional change forarch/arm.
Quoted 5 lines
My original thought with using
map_vm_areavs.ioremap_page_rangewas thatioremap_page_rangeis really intended for mapping io devices and the like into the kernel virtual address space.map_vm_areais designed to handle pages of kernel managed memory. Perhaps it's too nit-picky a distinction though.
I think you are right. We had a discussion in the past about using ioremap on valid RAM addresses and decided not to allow this. This would be similar with the ioremap_page_range() here.
Quoted 1 line
From my perspective, you can leave the code as is (wouldn't be any
functional change for arm64 since it was using vmap() already). But please add a comment in the commit log about this change.
Signature · 1 line
Catalin
Catalin Marinas
maintainerRe: [PATCHv4 3/5] common: dma-mapping: Introduce common remapping functions
In reply to Laura Abbottdrivers/base/dma-mapping.c int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, · line 336
Quoted 12 lines · Laura Abbott
drivers/base/dma-mapping.c +12
-0+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); +}
One more thing - is unmap_kernel_range() needed here? vunmap() ends up calling vunmap_page_range(), same as unmap_kernel_range(). I think one difference is that in the vunmap case, TLB flushing is done lazily.
Signature · 1 line
Catalin
PATCH v4 4/5 arm: use genalloc for the atomic pool
In reply to Laura AbbottARM 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
@@ -13,6 +13,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
PATCH v4 5/5 arm64: Add atomic pool for non-coherent and CMA allocations.
In reply to Laura AbbottNeither 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
@@ -18,6 +18,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
Quoted 6 lines · Laura Abbott
Laura Abbott (5):
lib/genalloc.c: Add power aligned algorithmlib/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.
The only thing left is the removal of unmap_kernel_range() call in dma_common_free_remap() (vunmap is enough). Feel free to add my review to the whole series:
Thanks.
Signature · 1 line
Catalin