diff options
author | Marek Szyprowski <m.szyprowski@samsung.com> | 2012-07-30 03:11:33 -0400 |
---|---|---|
committer | Marek Szyprowski <m.szyprowski@samsung.com> | 2012-07-30 06:25:45 -0400 |
commit | e9da6e9905e639b0f842a244bc770b48ad0523e9 (patch) | |
tree | c99beeb259716121dcb388f35f54f99a2a414a92 /arch/arm/mm | |
parent | 5e6cafc83e30f0f70c79a2b7aef237dc57e29f02 (diff) |
ARM: dma-mapping: remove custom consistent dma region
This patch changes dma-mapping subsystem to use generic vmalloc areas
for all consistent dma allocations. This increases the total size limit
of the consistent allocations and removes platform hacks and a lot of
duplicated code.
Atomic allocations are served from special pool preallocated on boot,
because vmalloc areas cannot be reliably created in atomic context.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Diffstat (limited to 'arch/arm/mm')
-rw-r--r-- | arch/arm/mm/dma-mapping.c | 486 | ||||
-rw-r--r-- | arch/arm/mm/mm.h | 3 |
2 files changed, 169 insertions, 320 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 655878bcc96d..f906d5f4cbd8 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/memblock.h> | 22 | #include <linux/memblock.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/iommu.h> | 24 | #include <linux/iommu.h> |
25 | #include <linux/io.h> | ||
25 | #include <linux/vmalloc.h> | 26 | #include <linux/vmalloc.h> |
26 | 27 | ||
27 | #include <asm/memory.h> | 28 | #include <asm/memory.h> |
@@ -217,115 +218,70 @@ static void __dma_free_buffer(struct page *page, size_t size) | |||
217 | } | 218 | } |
218 | 219 | ||
219 | #ifdef CONFIG_MMU | 220 | #ifdef CONFIG_MMU |
221 | #ifdef CONFIG_HUGETLB_PAGE | ||
222 | #error ARM Coherent DMA allocator does not (yet) support huge TLB | ||
223 | #endif | ||
220 | 224 | ||
221 | #define CONSISTENT_OFFSET(x) (((unsigned long)(x) - consistent_base) >> PAGE_SHIFT) | 225 | static void *__alloc_from_contiguous(struct device *dev, size_t size, |
222 | #define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - consistent_base) >> PMD_SHIFT) | 226 | pgprot_t prot, struct page **ret_page); |
223 | |||
224 | /* | ||
225 | * These are the page tables (2MB each) covering uncached, DMA consistent allocations | ||
226 | */ | ||
227 | static pte_t **consistent_pte; | ||
228 | |||
229 | #define DEFAULT_CONSISTENT_DMA_SIZE SZ_2M | ||
230 | 227 | ||
231 | static unsigned long consistent_base = CONSISTENT_END - DEFAULT_CONSISTENT_DMA_SIZE; | 228 | static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, |
229 | pgprot_t prot, struct page **ret_page, | ||
230 | const void *caller); | ||
232 | 231 | ||
233 | void __init init_consistent_dma_size(unsigned long size) | 232 | static void * |
233 | __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, | ||
234 | const void *caller) | ||
234 | { | 235 | { |
235 | unsigned long base = CONSISTENT_END - ALIGN(size, SZ_2M); | 236 | struct vm_struct *area; |
237 | unsigned long addr; | ||
236 | 238 | ||
237 | BUG_ON(consistent_pte); /* Check we're called before DMA region init */ | 239 | /* |
238 | BUG_ON(base < VMALLOC_END); | 240 | * DMA allocation can be mapped to user space, so lets |
241 | * set VM_USERMAP flags too. | ||
242 | */ | ||
243 | area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP, | ||
244 | caller); | ||
245 | if (!area) | ||
246 | return NULL; | ||
247 | addr = (unsigned long)area->addr; | ||
248 | area->phys_addr = __pfn_to_phys(page_to_pfn(page)); | ||
239 | 249 | ||
240 | /* Grow region to accommodate specified size */ | 250 | if (ioremap_page_range(addr, addr + size, area->phys_addr, prot)) { |
241 | if (base < consistent_base) | 251 | vunmap((void *)addr); |
242 | consistent_base = base; | 252 | return NULL; |
253 | } | ||
254 | return (void *)addr; | ||
243 | } | 255 | } |
244 | 256 | ||
245 | #include "vmregion.h" | 257 | static void __dma_free_remap(void *cpu_addr, size_t size) |
246 | |||
247 | static struct arm_vmregion_head consistent_head = { | ||
248 | .vm_lock = __SPIN_LOCK_UNLOCKED(&consistent_head.vm_lock), | ||
249 | .vm_list = LIST_HEAD_INIT(consistent_head.vm_list), | ||
250 | .vm_end = CONSISTENT_END, | ||
251 | }; | ||
252 | |||
253 | #ifdef CONFIG_HUGETLB_PAGE | ||
254 | #error ARM Coherent DMA allocator does not (yet) support huge TLB | ||
255 | #endif | ||
256 | |||
257 | /* | ||
258 | * Initialise the consistent memory allocation. | ||
259 | */ | ||
260 | static int __init consistent_init(void) | ||
261 | { | 258 | { |
262 | int ret = 0; | 259 | unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP; |
263 | pgd_t *pgd; | 260 | struct vm_struct *area = find_vm_area(cpu_addr); |
264 | pud_t *pud; | 261 | if (!area || (area->flags & flags) != flags) { |
265 | pmd_t *pmd; | 262 | WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); |
266 | pte_t *pte; | 263 | return; |
267 | int i = 0; | ||
268 | unsigned long base = consistent_base; | ||
269 | unsigned long num_ptes = (CONSISTENT_END - base) >> PMD_SHIFT; | ||
270 | |||
271 | if (IS_ENABLED(CONFIG_CMA) && !IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) | ||
272 | return 0; | ||
273 | |||
274 | consistent_pte = kmalloc(num_ptes * sizeof(pte_t), GFP_KERNEL); | ||
275 | if (!consistent_pte) { | ||
276 | pr_err("%s: no memory\n", __func__); | ||
277 | return -ENOMEM; | ||
278 | } | 264 | } |
279 | 265 | unmap_kernel_range((unsigned long)cpu_addr, size); | |
280 | pr_debug("DMA memory: 0x%08lx - 0x%08lx:\n", base, CONSISTENT_END); | 266 | vunmap(cpu_addr); |
281 | consistent_head.vm_start = base; | ||
282 | |||
283 | do { | ||
284 | pgd = pgd_offset(&init_mm, base); | ||
285 | |||
286 | pud = pud_alloc(&init_mm, pgd, base); | ||
287 | if (!pud) { | ||
288 | pr_err("%s: no pud tables\n", __func__); | ||
289 | ret = -ENOMEM; | ||
290 | break; | ||
291 | } | ||
292 | |||
293 | pmd = pmd_alloc(&init_mm, pud, base); | ||
294 | if (!pmd) { | ||
295 | pr_err("%s: no pmd tables\n", __func__); | ||
296 | ret = -ENOMEM; | ||
297 | break; | ||
298 | } | ||
299 | WARN_ON(!pmd_none(*pmd)); | ||
300 | |||
301 | pte = pte_alloc_kernel(pmd, base); | ||
302 | if (!pte) { | ||
303 | pr_err("%s: no pte tables\n", __func__); | ||
304 | ret = -ENOMEM; | ||
305 | break; | ||
306 | } | ||
307 | |||
308 | consistent_pte[i++] = pte; | ||
309 | base += PMD_SIZE; | ||
310 | } while (base < CONSISTENT_END); | ||
311 | |||
312 | return ret; | ||
313 | } | 267 | } |
314 | core_initcall(consistent_init); | ||
315 | |||
316 | static void *__alloc_from_contiguous(struct device *dev, size_t size, | ||
317 | pgprot_t prot, struct page **ret_page); | ||
318 | 268 | ||
319 | static struct arm_vmregion_head coherent_head = { | 269 | struct dma_pool { |
320 | .vm_lock = __SPIN_LOCK_UNLOCKED(&coherent_head.vm_lock), | 270 | size_t size; |
321 | .vm_list = LIST_HEAD_INIT(coherent_head.vm_list), | 271 | spinlock_t lock; |
272 | unsigned long *bitmap; | ||
273 | unsigned long nr_pages; | ||
274 | void *vaddr; | ||
275 | struct page *page; | ||
322 | }; | 276 | }; |
323 | 277 | ||
324 | static size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8; | 278 | static struct dma_pool atomic_pool = { |
279 | .size = SZ_256K, | ||
280 | }; | ||
325 | 281 | ||
326 | static int __init early_coherent_pool(char *p) | 282 | static int __init early_coherent_pool(char *p) |
327 | { | 283 | { |
328 | coherent_pool_size = memparse(p, &p); | 284 | atomic_pool.size = memparse(p, &p); |
329 | return 0; | 285 | return 0; |
330 | } | 286 | } |
331 | early_param("coherent_pool", early_coherent_pool); | 287 | early_param("coherent_pool", early_coherent_pool); |
@@ -333,32 +289,45 @@ early_param("coherent_pool", early_coherent_pool); | |||
333 | /* | 289 | /* |
334 | * Initialise the coherent pool for atomic allocations. | 290 | * Initialise the coherent pool for atomic allocations. |
335 | */ | 291 | */ |
336 | static int __init coherent_init(void) | 292 | static int __init atomic_pool_init(void) |
337 | { | 293 | { |
294 | struct dma_pool *pool = &atomic_pool; | ||
338 | pgprot_t prot = pgprot_dmacoherent(pgprot_kernel); | 295 | pgprot_t prot = pgprot_dmacoherent(pgprot_kernel); |
339 | size_t size = coherent_pool_size; | 296 | unsigned long nr_pages = pool->size >> PAGE_SHIFT; |
297 | unsigned long *bitmap; | ||
340 | struct page *page; | 298 | struct page *page; |
341 | void *ptr; | 299 | void *ptr; |
300 | int bitmap_size = BITS_TO_LONGS(nr_pages) * sizeof(long); | ||
342 | 301 | ||
343 | if (!IS_ENABLED(CONFIG_CMA)) | 302 | bitmap = kzalloc(bitmap_size, GFP_KERNEL); |
344 | return 0; | 303 | if (!bitmap) |
304 | goto no_bitmap; | ||
345 | 305 | ||
346 | ptr = __alloc_from_contiguous(NULL, size, prot, &page); | 306 | if (IS_ENABLED(CONFIG_CMA)) |
307 | ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page); | ||
308 | else | ||
309 | ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot, | ||
310 | &page, NULL); | ||
347 | if (ptr) { | 311 | if (ptr) { |
348 | coherent_head.vm_start = (unsigned long) ptr; | 312 | spin_lock_init(&pool->lock); |
349 | coherent_head.vm_end = (unsigned long) ptr + size; | 313 | pool->vaddr = ptr; |
350 | printk(KERN_INFO "DMA: preallocated %u KiB pool for atomic coherent allocations\n", | 314 | pool->page = page; |
351 | (unsigned)size / 1024); | 315 | pool->bitmap = bitmap; |
316 | pool->nr_pages = nr_pages; | ||
317 | pr_info("DMA: preallocated %u KiB pool for atomic coherent allocations\n", | ||
318 | (unsigned)pool->size / 1024); | ||
352 | return 0; | 319 | return 0; |
353 | } | 320 | } |
354 | printk(KERN_ERR "DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", | 321 | kfree(bitmap); |
355 | (unsigned)size / 1024); | 322 | no_bitmap: |
323 | pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", | ||
324 | (unsigned)pool->size / 1024); | ||
356 | return -ENOMEM; | 325 | return -ENOMEM; |
357 | } | 326 | } |
358 | /* | 327 | /* |
359 | * CMA is activated by core_initcall, so we must be called after it. | 328 | * CMA is activated by core_initcall, so we must be called after it. |
360 | */ | 329 | */ |
361 | postcore_initcall(coherent_init); | 330 | postcore_initcall(atomic_pool_init); |
362 | 331 | ||
363 | struct dma_contig_early_reserve { | 332 | struct dma_contig_early_reserve { |
364 | phys_addr_t base; | 333 | phys_addr_t base; |
@@ -406,112 +375,6 @@ void __init dma_contiguous_remap(void) | |||
406 | } | 375 | } |
407 | } | 376 | } |
408 | 377 | ||
409 | static void * | ||
410 | __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, | ||
411 | const void *caller) | ||
412 | { | ||
413 | struct arm_vmregion *c; | ||
414 | size_t align; | ||
415 | int bit; | ||
416 | |||
417 | if (!consistent_pte) { | ||
418 | pr_err("%s: not initialised\n", __func__); | ||
419 | dump_stack(); | ||
420 | return NULL; | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * Align the virtual region allocation - maximum alignment is | ||
425 | * a section size, minimum is a page size. This helps reduce | ||
426 | * fragmentation of the DMA space, and also prevents allocations | ||
427 | * smaller than a section from crossing a section boundary. | ||
428 | */ | ||
429 | bit = fls(size - 1); | ||
430 | if (bit > SECTION_SHIFT) | ||
431 | bit = SECTION_SHIFT; | ||
432 | align = 1 << bit; | ||
433 | |||
434 | /* | ||
435 | * Allocate a virtual address in the consistent mapping region. | ||
436 | */ | ||
437 | c = arm_vmregion_alloc(&consistent_head, align, size, | ||
438 | gfp & ~(__GFP_DMA | __GFP_HIGHMEM), caller); | ||
439 | if (c) { | ||
440 | pte_t *pte; | ||
441 | int idx = CONSISTENT_PTE_INDEX(c->vm_start); | ||
442 | u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); | ||
443 | |||
444 | pte = consistent_pte[idx] + off; | ||
445 | c->priv = page; | ||
446 | |||
447 | do { | ||
448 | BUG_ON(!pte_none(*pte)); | ||
449 | |||
450 | set_pte_ext(pte, mk_pte(page, prot), 0); | ||
451 | page++; | ||
452 | pte++; | ||
453 | off++; | ||
454 | if (off >= PTRS_PER_PTE) { | ||
455 | off = 0; | ||
456 | pte = consistent_pte[++idx]; | ||
457 | } | ||
458 | } while (size -= PAGE_SIZE); | ||
459 | |||
460 | dsb(); | ||
461 | |||
462 | return (void *)c->vm_start; | ||
463 | } | ||
464 | return NULL; | ||
465 | } | ||
466 | |||
467 | static void __dma_free_remap(void *cpu_addr, size_t size) | ||
468 | { | ||
469 | struct arm_vmregion *c; | ||
470 | unsigned long addr; | ||
471 | pte_t *ptep; | ||
472 | int idx; | ||
473 | u32 off; | ||
474 | |||
475 | c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr); | ||
476 | if (!c) { | ||
477 | pr_err("%s: trying to free invalid coherent area: %p\n", | ||
478 | __func__, cpu_addr); | ||
479 | dump_stack(); | ||
480 | return; | ||
481 | } | ||
482 | |||
483 | if ((c->vm_end - c->vm_start) != size) { | ||
484 | pr_err("%s: freeing wrong coherent size (%ld != %d)\n", | ||
485 | __func__, c->vm_end - c->vm_start, size); | ||
486 | dump_stack(); | ||
487 | size = c->vm_end - c->vm_start; | ||
488 | } | ||
489 | |||
490 | idx = CONSISTENT_PTE_INDEX(c->vm_start); | ||
491 | off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); | ||
492 | ptep = consistent_pte[idx] + off; | ||
493 | addr = c->vm_start; | ||
494 | do { | ||
495 | pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep); | ||
496 | |||
497 | ptep++; | ||
498 | addr += PAGE_SIZE; | ||
499 | off++; | ||
500 | if (off >= PTRS_PER_PTE) { | ||
501 | off = 0; | ||
502 | ptep = consistent_pte[++idx]; | ||
503 | } | ||
504 | |||
505 | if (pte_none(pte) || !pte_present(pte)) | ||
506 | pr_crit("%s: bad page in kernel page table\n", | ||
507 | __func__); | ||
508 | } while (size -= PAGE_SIZE); | ||
509 | |||
510 | flush_tlb_kernel_range(c->vm_start, c->vm_end); | ||
511 | |||
512 | arm_vmregion_free(&consistent_head, c); | ||
513 | } | ||
514 | |||
515 | static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr, | 378 | static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr, |
516 | void *data) | 379 | void *data) |
517 | { | 380 | { |
@@ -552,16 +415,17 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, | |||
552 | return ptr; | 415 | return ptr; |
553 | } | 416 | } |
554 | 417 | ||
555 | static void *__alloc_from_pool(struct device *dev, size_t size, | 418 | static void *__alloc_from_pool(size_t size, struct page **ret_page) |
556 | struct page **ret_page, const void *caller) | ||
557 | { | 419 | { |
558 | struct arm_vmregion *c; | 420 | struct dma_pool *pool = &atomic_pool; |
421 | unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; | ||
422 | unsigned int pageno; | ||
423 | unsigned long flags; | ||
424 | void *ptr = NULL; | ||
559 | size_t align; | 425 | size_t align; |
560 | 426 | ||
561 | if (!coherent_head.vm_start) { | 427 | if (!pool->vaddr) { |
562 | printk(KERN_ERR "%s: coherent pool not initialised!\n", | 428 | WARN(1, "coherent pool not initialised!\n"); |
563 | __func__); | ||
564 | dump_stack(); | ||
565 | return NULL; | 429 | return NULL; |
566 | } | 430 | } |
567 | 431 | ||
@@ -571,35 +435,41 @@ static void *__alloc_from_pool(struct device *dev, size_t size, | |||
571 | * size. This helps reduce fragmentation of the DMA space. | 435 | * size. This helps reduce fragmentation of the DMA space. |
572 | */ | 436 | */ |
573 | align = PAGE_SIZE << get_order(size); | 437 | align = PAGE_SIZE << get_order(size); |
574 | c = arm_vmregion_alloc(&coherent_head, align, size, 0, caller); | 438 | |
575 | if (c) { | 439 | spin_lock_irqsave(&pool->lock, flags); |
576 | void *ptr = (void *)c->vm_start; | 440 | pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages, |
577 | struct page *page = virt_to_page(ptr); | 441 | 0, count, (1 << align) - 1); |
578 | *ret_page = page; | 442 | if (pageno < pool->nr_pages) { |
579 | return ptr; | 443 | bitmap_set(pool->bitmap, pageno, count); |
444 | ptr = pool->vaddr + PAGE_SIZE * pageno; | ||
445 | *ret_page = pool->page + pageno; | ||
580 | } | 446 | } |
581 | return NULL; | 447 | spin_unlock_irqrestore(&pool->lock, flags); |
448 | |||
449 | return ptr; | ||
582 | } | 450 | } |
583 | 451 | ||
584 | static int __free_from_pool(void *cpu_addr, size_t size) | 452 | static int __free_from_pool(void *start, size_t size) |
585 | { | 453 | { |
586 | unsigned long start = (unsigned long)cpu_addr; | 454 | struct dma_pool *pool = &atomic_pool; |
587 | unsigned long end = start + size; | 455 | unsigned long pageno, count; |
588 | struct arm_vmregion *c; | 456 | unsigned long flags; |
589 | 457 | ||
590 | if (start < coherent_head.vm_start || end > coherent_head.vm_end) | 458 | if (start < pool->vaddr || start > pool->vaddr + pool->size) |
591 | return 0; | 459 | return 0; |
592 | 460 | ||
593 | c = arm_vmregion_find_remove(&coherent_head, (unsigned long)start); | 461 | if (start + size > pool->vaddr + pool->size) { |
594 | 462 | WARN(1, "freeing wrong coherent size from pool\n"); | |
595 | if ((c->vm_end - c->vm_start) != size) { | 463 | return 0; |
596 | printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", | ||
597 | __func__, c->vm_end - c->vm_start, size); | ||
598 | dump_stack(); | ||
599 | size = c->vm_end - c->vm_start; | ||
600 | } | 464 | } |
601 | 465 | ||
602 | arm_vmregion_free(&coherent_head, c); | 466 | pageno = (start - pool->vaddr) >> PAGE_SHIFT; |
467 | count = size >> PAGE_SHIFT; | ||
468 | |||
469 | spin_lock_irqsave(&pool->lock, flags); | ||
470 | bitmap_clear(pool->bitmap, pageno, count); | ||
471 | spin_unlock_irqrestore(&pool->lock, flags); | ||
472 | |||
603 | return 1; | 473 | return 1; |
604 | } | 474 | } |
605 | 475 | ||
@@ -644,7 +514,7 @@ static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot) | |||
644 | 514 | ||
645 | #define __get_dma_pgprot(attrs, prot) __pgprot(0) | 515 | #define __get_dma_pgprot(attrs, prot) __pgprot(0) |
646 | #define __alloc_remap_buffer(dev, size, gfp, prot, ret, c) NULL | 516 | #define __alloc_remap_buffer(dev, size, gfp, prot, ret, c) NULL |
647 | #define __alloc_from_pool(dev, size, ret_page, c) NULL | 517 | #define __alloc_from_pool(size, ret_page) NULL |
648 | #define __alloc_from_contiguous(dev, size, prot, ret) NULL | 518 | #define __alloc_from_contiguous(dev, size, prot, ret) NULL |
649 | #define __free_from_pool(cpu_addr, size) 0 | 519 | #define __free_from_pool(cpu_addr, size) 0 |
650 | #define __free_from_contiguous(dev, page, size) do { } while (0) | 520 | #define __free_from_contiguous(dev, page, size) do { } while (0) |
@@ -702,10 +572,10 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, | |||
702 | 572 | ||
703 | if (arch_is_coherent() || nommu()) | 573 | if (arch_is_coherent() || nommu()) |
704 | addr = __alloc_simple_buffer(dev, size, gfp, &page); | 574 | addr = __alloc_simple_buffer(dev, size, gfp, &page); |
575 | else if (gfp & GFP_ATOMIC) | ||
576 | addr = __alloc_from_pool(size, &page); | ||
705 | else if (!IS_ENABLED(CONFIG_CMA)) | 577 | else if (!IS_ENABLED(CONFIG_CMA)) |
706 | addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); | 578 | addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); |
707 | else if (gfp & GFP_ATOMIC) | ||
708 | addr = __alloc_from_pool(dev, size, &page, caller); | ||
709 | else | 579 | else |
710 | addr = __alloc_from_contiguous(dev, size, prot, &page); | 580 | addr = __alloc_from_contiguous(dev, size, prot, &page); |
711 | 581 | ||
@@ -998,9 +868,6 @@ static int arm_dma_set_mask(struct device *dev, u64 dma_mask) | |||
998 | 868 | ||
999 | static int __init dma_debug_do_init(void) | 869 | static int __init dma_debug_do_init(void) |
1000 | { | 870 | { |
1001 | #ifdef CONFIG_MMU | ||
1002 | arm_vmregion_create_proc("dma-mappings", &consistent_head); | ||
1003 | #endif | ||
1004 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); | 871 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); |
1005 | return 0; | 872 | return 0; |
1006 | } | 873 | } |
@@ -1117,61 +984,32 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t s | |||
1117 | * Create a CPU mapping for a specified pages | 984 | * Create a CPU mapping for a specified pages |
1118 | */ | 985 | */ |
1119 | static void * | 986 | static void * |
1120 | __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot) | 987 | __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot, |
988 | const void *caller) | ||
1121 | { | 989 | { |
1122 | struct arm_vmregion *c; | 990 | unsigned int i, nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; |
1123 | size_t align; | 991 | struct vm_struct *area; |
1124 | size_t count = size >> PAGE_SHIFT; | 992 | unsigned long p; |
1125 | int bit; | ||
1126 | 993 | ||
1127 | if (!consistent_pte[0]) { | 994 | area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP, |
1128 | pr_err("%s: not initialised\n", __func__); | 995 | caller); |
1129 | dump_stack(); | 996 | if (!area) |
1130 | return NULL; | 997 | return NULL; |
1131 | } | ||
1132 | 998 | ||
1133 | /* | 999 | area->pages = pages; |
1134 | * Align the virtual region allocation - maximum alignment is | 1000 | area->nr_pages = nr_pages; |
1135 | * a section size, minimum is a page size. This helps reduce | 1001 | p = (unsigned long)area->addr; |
1136 | * fragmentation of the DMA space, and also prevents allocations | ||
1137 | * smaller than a section from crossing a section boundary. | ||
1138 | */ | ||
1139 | bit = fls(size - 1); | ||
1140 | if (bit > SECTION_SHIFT) | ||
1141 | bit = SECTION_SHIFT; | ||
1142 | align = 1 << bit; | ||
1143 | |||
1144 | /* | ||
1145 | * Allocate a virtual address in the consistent mapping region. | ||
1146 | */ | ||
1147 | c = arm_vmregion_alloc(&consistent_head, align, size, | ||
1148 | gfp & ~(__GFP_DMA | __GFP_HIGHMEM), NULL); | ||
1149 | if (c) { | ||
1150 | pte_t *pte; | ||
1151 | int idx = CONSISTENT_PTE_INDEX(c->vm_start); | ||
1152 | int i = 0; | ||
1153 | u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); | ||
1154 | |||
1155 | pte = consistent_pte[idx] + off; | ||
1156 | c->priv = pages; | ||
1157 | |||
1158 | do { | ||
1159 | BUG_ON(!pte_none(*pte)); | ||
1160 | |||
1161 | set_pte_ext(pte, mk_pte(pages[i], prot), 0); | ||
1162 | pte++; | ||
1163 | off++; | ||
1164 | i++; | ||
1165 | if (off >= PTRS_PER_PTE) { | ||
1166 | off = 0; | ||
1167 | pte = consistent_pte[++idx]; | ||
1168 | } | ||
1169 | } while (i < count); | ||
1170 | |||
1171 | dsb(); | ||
1172 | 1002 | ||
1173 | return (void *)c->vm_start; | 1003 | for (i = 0; i < nr_pages; i++) { |
1004 | phys_addr_t phys = __pfn_to_phys(page_to_pfn(pages[i])); | ||
1005 | if (ioremap_page_range(p, p + PAGE_SIZE, phys, prot)) | ||
1006 | goto err; | ||
1007 | p += PAGE_SIZE; | ||
1174 | } | 1008 | } |
1009 | return area->addr; | ||
1010 | err: | ||
1011 | unmap_kernel_range((unsigned long)area->addr, size); | ||
1012 | vunmap(area->addr); | ||
1175 | return NULL; | 1013 | return NULL; |
1176 | } | 1014 | } |
1177 | 1015 | ||
@@ -1230,6 +1068,16 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si | |||
1230 | return 0; | 1068 | return 0; |
1231 | } | 1069 | } |
1232 | 1070 | ||
1071 | static struct page **__iommu_get_pages(void *cpu_addr) | ||
1072 | { | ||
1073 | struct vm_struct *area; | ||
1074 | |||
1075 | area = find_vm_area(cpu_addr); | ||
1076 | if (area && (area->flags & VM_ARM_DMA_CONSISTENT)) | ||
1077 | return area->pages; | ||
1078 | return NULL; | ||
1079 | } | ||
1080 | |||
1233 | static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, | 1081 | static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, |
1234 | dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) | 1082 | dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) |
1235 | { | 1083 | { |
@@ -1248,7 +1096,8 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, | |||
1248 | if (*handle == DMA_ERROR_CODE) | 1096 | if (*handle == DMA_ERROR_CODE) |
1249 | goto err_buffer; | 1097 | goto err_buffer; |
1250 | 1098 | ||
1251 | addr = __iommu_alloc_remap(pages, size, gfp, prot); | 1099 | addr = __iommu_alloc_remap(pages, size, gfp, prot, |
1100 | __builtin_return_address(0)); | ||
1252 | if (!addr) | 1101 | if (!addr) |
1253 | goto err_mapping; | 1102 | goto err_mapping; |
1254 | 1103 | ||
@@ -1265,31 +1114,25 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, | |||
1265 | void *cpu_addr, dma_addr_t dma_addr, size_t size, | 1114 | void *cpu_addr, dma_addr_t dma_addr, size_t size, |
1266 | struct dma_attrs *attrs) | 1115 | struct dma_attrs *attrs) |
1267 | { | 1116 | { |
1268 | struct arm_vmregion *c; | 1117 | unsigned long uaddr = vma->vm_start; |
1118 | unsigned long usize = vma->vm_end - vma->vm_start; | ||
1119 | struct page **pages = __iommu_get_pages(cpu_addr); | ||
1269 | 1120 | ||
1270 | vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); | 1121 | vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); |
1271 | c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr); | ||
1272 | 1122 | ||
1273 | if (c) { | 1123 | if (!pages) |
1274 | struct page **pages = c->priv; | 1124 | return -ENXIO; |
1275 | |||
1276 | unsigned long uaddr = vma->vm_start; | ||
1277 | unsigned long usize = vma->vm_end - vma->vm_start; | ||
1278 | int i = 0; | ||
1279 | |||
1280 | do { | ||
1281 | int ret; | ||
1282 | 1125 | ||
1283 | ret = vm_insert_page(vma, uaddr, pages[i++]); | 1126 | do { |
1284 | if (ret) { | 1127 | int ret = vm_insert_page(vma, uaddr, *pages++); |
1285 | pr_err("Remapping memory, error: %d\n", ret); | 1128 | if (ret) { |
1286 | return ret; | 1129 | pr_err("Remapping memory failed: %d\n", ret); |
1287 | } | 1130 | return ret; |
1131 | } | ||
1132 | uaddr += PAGE_SIZE; | ||
1133 | usize -= PAGE_SIZE; | ||
1134 | } while (usize > 0); | ||
1288 | 1135 | ||
1289 | uaddr += PAGE_SIZE; | ||
1290 | usize -= PAGE_SIZE; | ||
1291 | } while (usize > 0); | ||
1292 | } | ||
1293 | return 0; | 1136 | return 0; |
1294 | } | 1137 | } |
1295 | 1138 | ||
@@ -1300,16 +1143,19 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, | |||
1300 | void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, | 1143 | void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, |
1301 | dma_addr_t handle, struct dma_attrs *attrs) | 1144 | dma_addr_t handle, struct dma_attrs *attrs) |
1302 | { | 1145 | { |
1303 | struct arm_vmregion *c; | 1146 | struct page **pages = __iommu_get_pages(cpu_addr); |
1304 | size = PAGE_ALIGN(size); | 1147 | size = PAGE_ALIGN(size); |
1305 | 1148 | ||
1306 | c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr); | 1149 | if (!pages) { |
1307 | if (c) { | 1150 | WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); |
1308 | struct page **pages = c->priv; | 1151 | return; |
1309 | __dma_free_remap(cpu_addr, size); | ||
1310 | __iommu_remove_mapping(dev, handle, size); | ||
1311 | __iommu_free_buffer(dev, pages, size); | ||
1312 | } | 1152 | } |
1153 | |||
1154 | unmap_kernel_range((unsigned long)cpu_addr, size); | ||
1155 | vunmap(cpu_addr); | ||
1156 | |||
1157 | __iommu_remove_mapping(dev, handle, size); | ||
1158 | __iommu_free_buffer(dev, pages, size); | ||
1313 | } | 1159 | } |
1314 | 1160 | ||
1315 | /* | 1161 | /* |
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 2e8a1efdf7b8..6776160618ef 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h | |||
@@ -59,6 +59,9 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page | |||
59 | #define VM_ARM_MTYPE(mt) ((mt) << 20) | 59 | #define VM_ARM_MTYPE(mt) ((mt) << 20) |
60 | #define VM_ARM_MTYPE_MASK (0x1f << 20) | 60 | #define VM_ARM_MTYPE_MASK (0x1f << 20) |
61 | 61 | ||
62 | /* consistent regions used by dma_alloc_attrs() */ | ||
63 | #define VM_ARM_DMA_CONSISTENT 0x20000000 | ||
64 | |||
62 | #endif | 65 | #endif |
63 | 66 | ||
64 | #ifdef CONFIG_ZONE_DMA | 67 | #ifdef CONFIG_ZONE_DMA |