aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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