aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaura Abbott <lauraa@codeaurora.org>2014-10-09 18:26:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-09 22:25:52 -0400
commit513510ddba9650fc7da456eefeb0ead7632324f6 (patch)
tree8e21369797216203ba554d99d031403c5b8d95cb
parent9efb3a421d55d30b65fb0dbee05108d15c6c55f7 (diff)
common: dma-mapping: introduce common remapping functions
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. Signed-off-by: Laura Abbott <lauraa@codeaurora.org> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: David Riley <davidriley@chromium.org> Cc: Olof Johansson <olof@lixom.net> Cc: Ritesh Harjain <ritesh.harjani@gmail.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Will Deacon <will.deacon@arm.com> Cc: James Hogan <james.hogan@imgtec.com> Cc: Laura Abbott <lauraa@codeaurora.org> Cc: Mitchel Humpherys <mitchelh@codeaurora.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/arm/mm/dma-mapping.c57
-rw-r--r--drivers/base/dma-mapping.c72
-rw-r--r--include/asm-generic/dma-mapping-common.h9
3 files changed, 90 insertions, 48 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 7a996aaa061e..eecc8e60deea 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -298,37 +298,19 @@ static void *
298__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, 298__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
299 const void *caller) 299 const void *caller)
300{ 300{
301 struct vm_struct *area;
302 unsigned long addr;
303
304 /* 301 /*
305 * DMA allocation can be mapped to user space, so lets 302 * DMA allocation can be mapped to user space, so lets
306 * set VM_USERMAP flags too. 303 * set VM_USERMAP flags too.
307 */ 304 */
308 area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP, 305 return dma_common_contiguous_remap(page, size,
309 caller); 306 VM_ARM_DMA_CONSISTENT | VM_USERMAP,
310 if (!area) 307 prot, caller);
311 return NULL;
312 addr = (unsigned long)area->addr;
313 area->phys_addr = __pfn_to_phys(page_to_pfn(page));
314
315 if (ioremap_page_range(addr, addr + size, area->phys_addr, prot)) {
316 vunmap((void *)addr);
317 return NULL;
318 }
319 return (void *)addr;
320} 308}
321 309
322static void __dma_free_remap(void *cpu_addr, size_t size) 310static void __dma_free_remap(void *cpu_addr, size_t size)
323{ 311{
324 unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP; 312 dma_common_free_remap(cpu_addr, size,
325 struct vm_struct *area = find_vm_area(cpu_addr); 313 VM_ARM_DMA_CONSISTENT | VM_USERMAP);
326 if (!area || (area->flags & flags) != flags) {
327 WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
328 return;
329 }
330 unmap_kernel_range((unsigned long)cpu_addr, size);
331 vunmap(cpu_addr);
332} 314}
333 315
334#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K 316#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
@@ -1271,29 +1253,8 @@ static void *
1271__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot, 1253__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
1272 const void *caller) 1254 const void *caller)
1273{ 1255{
1274 unsigned int i, nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; 1256 return dma_common_pages_remap(pages, size,
1275 struct vm_struct *area; 1257 VM_ARM_DMA_CONSISTENT | VM_USERMAP, prot, caller);
1276 unsigned long p;
1277
1278 area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
1279 caller);
1280 if (!area)
1281 return NULL;
1282
1283 area->pages = pages;
1284 area->nr_pages = nr_pages;
1285 p = (unsigned long)area->addr;
1286
1287 for (i = 0; i < nr_pages; i++) {
1288 phys_addr_t phys = __pfn_to_phys(page_to_pfn(pages[i]));
1289 if (ioremap_page_range(p, p + PAGE_SIZE, phys, prot))
1290 goto err;
1291 p += PAGE_SIZE;
1292 }
1293 return area->addr;
1294err:
1295 unmap_kernel_range((unsigned long)area->addr, size);
1296 vunmap(area->addr);
1297 return NULL; 1258 return NULL;
1298} 1259}
1299 1260
@@ -1501,8 +1462,8 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
1501 } 1462 }
1502 1463
1503 if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) { 1464 if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
1504 unmap_kernel_range((unsigned long)cpu_addr, size); 1465 dma_common_free_remap(cpu_addr, size,
1505 vunmap(cpu_addr); 1466 VM_ARM_DMA_CONSISTENT | VM_USERMAP);
1506 } 1467 }
1507 1468
1508 __iommu_remove_mapping(dev, handle, size); 1469 __iommu_remove_mapping(dev, handle, size);
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
index 6cd08e145bfa..9e8bbdd470ca 100644
--- a/drivers/base/dma-mapping.c
+++ b/drivers/base/dma-mapping.c
@@ -10,6 +10,8 @@
10#include <linux/dma-mapping.h> 10#include <linux/dma-mapping.h>
11#include <linux/export.h> 11#include <linux/export.h>
12#include <linux/gfp.h> 12#include <linux/gfp.h>
13#include <linux/slab.h>
14#include <linux/vmalloc.h>
13#include <asm-generic/dma-coherent.h> 15#include <asm-generic/dma-coherent.h>
14 16
15/* 17/*
@@ -267,3 +269,73 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
267 return ret; 269 return ret;
268} 270}
269EXPORT_SYMBOL(dma_common_mmap); 271EXPORT_SYMBOL(dma_common_mmap);
272
273#ifdef CONFIG_MMU
274/*
275 * remaps an array of PAGE_SIZE pages into another vm_area
276 * Cannot be used in non-sleeping contexts
277 */
278void *dma_common_pages_remap(struct page **pages, size_t size,
279 unsigned long vm_flags, pgprot_t prot,
280 const void *caller)
281{
282 struct vm_struct *area;
283
284 area = get_vm_area_caller(size, vm_flags, caller);
285 if (!area)
286 return NULL;
287
288 area->pages = pages;
289
290 if (map_vm_area(area, prot, pages)) {
291 vunmap(area->addr);
292 return NULL;
293 }
294
295 return area->addr;
296}
297
298/*
299 * remaps an allocated contiguous region into another vm_area.
300 * Cannot be used in non-sleeping contexts
301 */
302
303void *dma_common_contiguous_remap(struct page *page, size_t size,
304 unsigned long vm_flags,
305 pgprot_t prot, const void *caller)
306{
307 int i;
308 struct page **pages;
309 void *ptr;
310 unsigned long pfn;
311
312 pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL);
313 if (!pages)
314 return NULL;
315
316 for (i = 0, pfn = page_to_pfn(page); i < (size >> PAGE_SHIFT); i++)
317 pages[i] = pfn_to_page(pfn + i);
318
319 ptr = dma_common_pages_remap(pages, size, vm_flags, prot, caller);
320
321 kfree(pages);
322
323 return ptr;
324}
325
326/*
327 * unmaps a range previously mapped by dma_common_*_remap
328 */
329void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
330{
331 struct vm_struct *area = find_vm_area(cpu_addr);
332
333 if (!area || (area->flags & vm_flags) != vm_flags) {
334 WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
335 return;
336 }
337
338 unmap_kernel_range((unsigned long)cpu_addr, size);
339 vunmap(cpu_addr);
340}
341#endif
diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h
index de8bf89940f8..a9fd248f5d48 100644
--- a/include/asm-generic/dma-mapping-common.h
+++ b/include/asm-generic/dma-mapping-common.h
@@ -179,6 +179,15 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
179extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, 179extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
180 void *cpu_addr, dma_addr_t dma_addr, size_t size); 180 void *cpu_addr, dma_addr_t dma_addr, size_t size);
181 181
182void *dma_common_contiguous_remap(struct page *page, size_t size,
183 unsigned long vm_flags,
184 pgprot_t prot, const void *caller);
185
186void *dma_common_pages_remap(struct page **pages, size_t size,
187 unsigned long vm_flags, pgprot_t prot,
188 const void *caller);
189void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags);
190
182/** 191/**
183 * dma_mmap_attrs - map a coherent DMA allocation into user space 192 * dma_mmap_attrs - map a coherent DMA allocation into user space
184 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices 193 * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices