summaryrefslogtreecommitdiffstats
path: root/drivers/base/dma-mapping.c
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 /drivers/base/dma-mapping.c
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>
Diffstat (limited to 'drivers/base/dma-mapping.c')
-rw-r--r--drivers/base/dma-mapping.c72
1 files changed, 72 insertions, 0 deletions
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