diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-09-13 17:54:57 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-09-13 17:54:57 -0400 |
commit | 9a5d5bd8480068c5829e3d997ee21dab9b3ed05f (patch) | |
tree | f8bea83deb720d4fa3a9ada8d4845406c2d7c8f0 /arch/arm/mm/dma-mapping.c | |
parent | 271fd03a3013b106ccc178d54219c1be0c9759b7 (diff) | |
parent | 55d512e245bc7699a8800e23df1a24195dd08217 (diff) |
Merge commit 'v3.6-rc5' into pci/gavin-window-alignment
* commit 'v3.6-rc5': (1098 commits)
Linux 3.6-rc5
HID: tpkbd: work even if the new Lenovo Keyboard driver is not configured
Remove user-triggerable BUG from mpol_to_str
xen/pciback: Fix proper FLR steps.
uml: fix compile error in deliver_alarm()
dj: memory scribble in logi_dj
Fix order of arguments to compat_put_time[spec|val]
xen: Use correct masking in xen_swiotlb_alloc_coherent.
xen: fix logical error in tlb flushing
xen/p2m: Fix one-off error in checking the P2M tree directory.
powerpc: Don't use __put_user() in patch_instruction
powerpc: Make sure IPI handlers see data written by IPI senders
powerpc: Restore correct DSCR in context switch
powerpc: Fix DSCR inheritance in copy_thread()
powerpc: Keep thread.dscr and thread.dscr_inherit in sync
powerpc: Update DSCR on all CPUs when writing sysfs dscr_default
powerpc/powernv: Always go into nap mode when CPU is offline
powerpc: Give hypervisor decrementer interrupts their own handler
powerpc/vphn: Fix arch_update_cpu_topology() return value
ARM: gemini: fix the gemini build
...
Conflicts:
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/rapidio/devices/tsi721.c
Diffstat (limited to 'arch/arm/mm/dma-mapping.c')
-rw-r--r-- | arch/arm/mm/dma-mapping.c | 126 |
1 files changed, 110 insertions, 16 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index c2cdf6500f75..051204fc4617 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c | |||
@@ -267,17 +267,19 @@ static void __dma_free_remap(void *cpu_addr, size_t size) | |||
267 | vunmap(cpu_addr); | 267 | vunmap(cpu_addr); |
268 | } | 268 | } |
269 | 269 | ||
270 | #define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K | ||
271 | |||
270 | struct dma_pool { | 272 | struct dma_pool { |
271 | size_t size; | 273 | size_t size; |
272 | spinlock_t lock; | 274 | spinlock_t lock; |
273 | unsigned long *bitmap; | 275 | unsigned long *bitmap; |
274 | unsigned long nr_pages; | 276 | unsigned long nr_pages; |
275 | void *vaddr; | 277 | void *vaddr; |
276 | struct page *page; | 278 | struct page **pages; |
277 | }; | 279 | }; |
278 | 280 | ||
279 | static struct dma_pool atomic_pool = { | 281 | static struct dma_pool atomic_pool = { |
280 | .size = SZ_256K, | 282 | .size = DEFAULT_DMA_COHERENT_POOL_SIZE, |
281 | }; | 283 | }; |
282 | 284 | ||
283 | static int __init early_coherent_pool(char *p) | 285 | static int __init early_coherent_pool(char *p) |
@@ -287,6 +289,21 @@ static int __init early_coherent_pool(char *p) | |||
287 | } | 289 | } |
288 | early_param("coherent_pool", early_coherent_pool); | 290 | early_param("coherent_pool", early_coherent_pool); |
289 | 291 | ||
292 | void __init init_dma_coherent_pool_size(unsigned long size) | ||
293 | { | ||
294 | /* | ||
295 | * Catch any attempt to set the pool size too late. | ||
296 | */ | ||
297 | BUG_ON(atomic_pool.vaddr); | ||
298 | |||
299 | /* | ||
300 | * Set architecture specific coherent pool size only if | ||
301 | * it has not been changed by kernel command line parameter. | ||
302 | */ | ||
303 | if (atomic_pool.size == DEFAULT_DMA_COHERENT_POOL_SIZE) | ||
304 | atomic_pool.size = size; | ||
305 | } | ||
306 | |||
290 | /* | 307 | /* |
291 | * Initialise the coherent pool for atomic allocations. | 308 | * Initialise the coherent pool for atomic allocations. |
292 | */ | 309 | */ |
@@ -297,6 +314,7 @@ static int __init atomic_pool_init(void) | |||
297 | unsigned long nr_pages = pool->size >> PAGE_SHIFT; | 314 | unsigned long nr_pages = pool->size >> PAGE_SHIFT; |
298 | unsigned long *bitmap; | 315 | unsigned long *bitmap; |
299 | struct page *page; | 316 | struct page *page; |
317 | struct page **pages; | ||
300 | void *ptr; | 318 | void *ptr; |
301 | int bitmap_size = BITS_TO_LONGS(nr_pages) * sizeof(long); | 319 | int bitmap_size = BITS_TO_LONGS(nr_pages) * sizeof(long); |
302 | 320 | ||
@@ -304,21 +322,31 @@ static int __init atomic_pool_init(void) | |||
304 | if (!bitmap) | 322 | if (!bitmap) |
305 | goto no_bitmap; | 323 | goto no_bitmap; |
306 | 324 | ||
325 | pages = kzalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); | ||
326 | if (!pages) | ||
327 | goto no_pages; | ||
328 | |||
307 | if (IS_ENABLED(CONFIG_CMA)) | 329 | if (IS_ENABLED(CONFIG_CMA)) |
308 | ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page); | 330 | ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page); |
309 | else | 331 | else |
310 | ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot, | 332 | ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot, |
311 | &page, NULL); | 333 | &page, NULL); |
312 | if (ptr) { | 334 | if (ptr) { |
335 | int i; | ||
336 | |||
337 | for (i = 0; i < nr_pages; i++) | ||
338 | pages[i] = page + i; | ||
339 | |||
313 | spin_lock_init(&pool->lock); | 340 | spin_lock_init(&pool->lock); |
314 | pool->vaddr = ptr; | 341 | pool->vaddr = ptr; |
315 | pool->page = page; | 342 | pool->pages = pages; |
316 | pool->bitmap = bitmap; | 343 | pool->bitmap = bitmap; |
317 | pool->nr_pages = nr_pages; | 344 | pool->nr_pages = nr_pages; |
318 | pr_info("DMA: preallocated %u KiB pool for atomic coherent allocations\n", | 345 | pr_info("DMA: preallocated %u KiB pool for atomic coherent allocations\n", |
319 | (unsigned)pool->size / 1024); | 346 | (unsigned)pool->size / 1024); |
320 | return 0; | 347 | return 0; |
321 | } | 348 | } |
349 | no_pages: | ||
322 | kfree(bitmap); | 350 | kfree(bitmap); |
323 | no_bitmap: | 351 | no_bitmap: |
324 | pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", | 352 | pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", |
@@ -358,7 +386,7 @@ void __init dma_contiguous_remap(void) | |||
358 | if (end > arm_lowmem_limit) | 386 | if (end > arm_lowmem_limit) |
359 | end = arm_lowmem_limit; | 387 | end = arm_lowmem_limit; |
360 | if (start >= end) | 388 | if (start >= end) |
361 | return; | 389 | continue; |
362 | 390 | ||
363 | map.pfn = __phys_to_pfn(start); | 391 | map.pfn = __phys_to_pfn(start); |
364 | map.virtual = __phys_to_virt(start); | 392 | map.virtual = __phys_to_virt(start); |
@@ -423,7 +451,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page) | |||
423 | unsigned int pageno; | 451 | unsigned int pageno; |
424 | unsigned long flags; | 452 | unsigned long flags; |
425 | void *ptr = NULL; | 453 | void *ptr = NULL; |
426 | size_t align; | 454 | unsigned long align_mask; |
427 | 455 | ||
428 | if (!pool->vaddr) { | 456 | if (!pool->vaddr) { |
429 | WARN(1, "coherent pool not initialised!\n"); | 457 | WARN(1, "coherent pool not initialised!\n"); |
@@ -435,35 +463,53 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page) | |||
435 | * small, so align them to their order in pages, minimum is a page | 463 | * small, so align them to their order in pages, minimum is a page |
436 | * size. This helps reduce fragmentation of the DMA space. | 464 | * size. This helps reduce fragmentation of the DMA space. |
437 | */ | 465 | */ |
438 | align = PAGE_SIZE << get_order(size); | 466 | align_mask = (1 << get_order(size)) - 1; |
439 | 467 | ||
440 | spin_lock_irqsave(&pool->lock, flags); | 468 | spin_lock_irqsave(&pool->lock, flags); |
441 | pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages, | 469 | pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages, |
442 | 0, count, (1 << align) - 1); | 470 | 0, count, align_mask); |
443 | if (pageno < pool->nr_pages) { | 471 | if (pageno < pool->nr_pages) { |
444 | bitmap_set(pool->bitmap, pageno, count); | 472 | bitmap_set(pool->bitmap, pageno, count); |
445 | ptr = pool->vaddr + PAGE_SIZE * pageno; | 473 | ptr = pool->vaddr + PAGE_SIZE * pageno; |
446 | *ret_page = pool->page + pageno; | 474 | *ret_page = pool->pages[pageno]; |
475 | } else { | ||
476 | pr_err_once("ERROR: %u KiB atomic DMA coherent pool is too small!\n" | ||
477 | "Please increase it with coherent_pool= kernel parameter!\n", | ||
478 | (unsigned)pool->size / 1024); | ||
447 | } | 479 | } |
448 | spin_unlock_irqrestore(&pool->lock, flags); | 480 | spin_unlock_irqrestore(&pool->lock, flags); |
449 | 481 | ||
450 | return ptr; | 482 | return ptr; |
451 | } | 483 | } |
452 | 484 | ||
485 | static bool __in_atomic_pool(void *start, size_t size) | ||
486 | { | ||
487 | struct dma_pool *pool = &atomic_pool; | ||
488 | void *end = start + size; | ||
489 | void *pool_start = pool->vaddr; | ||
490 | void *pool_end = pool->vaddr + pool->size; | ||
491 | |||
492 | if (start < pool_start || start > pool_end) | ||
493 | return false; | ||
494 | |||
495 | if (end <= pool_end) | ||
496 | return true; | ||
497 | |||
498 | WARN(1, "Wrong coherent size(%p-%p) from atomic pool(%p-%p)\n", | ||
499 | start, end - 1, pool_start, pool_end - 1); | ||
500 | |||
501 | return false; | ||
502 | } | ||
503 | |||
453 | static int __free_from_pool(void *start, size_t size) | 504 | static int __free_from_pool(void *start, size_t size) |
454 | { | 505 | { |
455 | struct dma_pool *pool = &atomic_pool; | 506 | struct dma_pool *pool = &atomic_pool; |
456 | unsigned long pageno, count; | 507 | unsigned long pageno, count; |
457 | unsigned long flags; | 508 | unsigned long flags; |
458 | 509 | ||
459 | if (start < pool->vaddr || start > pool->vaddr + pool->size) | 510 | if (!__in_atomic_pool(start, size)) |
460 | return 0; | 511 | return 0; |
461 | 512 | ||
462 | if (start + size > pool->vaddr + pool->size) { | ||
463 | WARN(1, "freeing wrong coherent size from pool\n"); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | pageno = (start - pool->vaddr) >> PAGE_SHIFT; | 513 | pageno = (start - pool->vaddr) >> PAGE_SHIFT; |
468 | count = size >> PAGE_SHIFT; | 514 | count = size >> PAGE_SHIFT; |
469 | 515 | ||
@@ -648,12 +694,12 @@ void arm_dma_free(struct device *dev, size_t size, void *cpu_addr, | |||
648 | 694 | ||
649 | if (arch_is_coherent() || nommu()) { | 695 | if (arch_is_coherent() || nommu()) { |
650 | __dma_free_buffer(page, size); | 696 | __dma_free_buffer(page, size); |
697 | } else if (__free_from_pool(cpu_addr, size)) { | ||
698 | return; | ||
651 | } else if (!IS_ENABLED(CONFIG_CMA)) { | 699 | } else if (!IS_ENABLED(CONFIG_CMA)) { |
652 | __dma_free_remap(cpu_addr, size); | 700 | __dma_free_remap(cpu_addr, size); |
653 | __dma_free_buffer(page, size); | 701 | __dma_free_buffer(page, size); |
654 | } else { | 702 | } else { |
655 | if (__free_from_pool(cpu_addr, size)) | ||
656 | return; | ||
657 | /* | 703 | /* |
658 | * Non-atomic allocations cannot be freed with IRQs disabled | 704 | * Non-atomic allocations cannot be freed with IRQs disabled |
659 | */ | 705 | */ |
@@ -1090,10 +1136,22 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si | |||
1090 | return 0; | 1136 | return 0; |
1091 | } | 1137 | } |
1092 | 1138 | ||
1139 | static struct page **__atomic_get_pages(void *addr) | ||
1140 | { | ||
1141 | struct dma_pool *pool = &atomic_pool; | ||
1142 | struct page **pages = pool->pages; | ||
1143 | int offs = (addr - pool->vaddr) >> PAGE_SHIFT; | ||
1144 | |||
1145 | return pages + offs; | ||
1146 | } | ||
1147 | |||
1093 | static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) | 1148 | static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) |
1094 | { | 1149 | { |
1095 | struct vm_struct *area; | 1150 | struct vm_struct *area; |
1096 | 1151 | ||
1152 | if (__in_atomic_pool(cpu_addr, PAGE_SIZE)) | ||
1153 | return __atomic_get_pages(cpu_addr); | ||
1154 | |||
1097 | if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) | 1155 | if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) |
1098 | return cpu_addr; | 1156 | return cpu_addr; |
1099 | 1157 | ||
@@ -1103,6 +1161,34 @@ static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) | |||
1103 | return NULL; | 1161 | return NULL; |
1104 | } | 1162 | } |
1105 | 1163 | ||
1164 | static void *__iommu_alloc_atomic(struct device *dev, size_t size, | ||
1165 | dma_addr_t *handle) | ||
1166 | { | ||
1167 | struct page *page; | ||
1168 | void *addr; | ||
1169 | |||
1170 | addr = __alloc_from_pool(size, &page); | ||
1171 | if (!addr) | ||
1172 | return NULL; | ||
1173 | |||
1174 | *handle = __iommu_create_mapping(dev, &page, size); | ||
1175 | if (*handle == DMA_ERROR_CODE) | ||
1176 | goto err_mapping; | ||
1177 | |||
1178 | return addr; | ||
1179 | |||
1180 | err_mapping: | ||
1181 | __free_from_pool(addr, size); | ||
1182 | return NULL; | ||
1183 | } | ||
1184 | |||
1185 | static void __iommu_free_atomic(struct device *dev, struct page **pages, | ||
1186 | dma_addr_t handle, size_t size) | ||
1187 | { | ||
1188 | __iommu_remove_mapping(dev, handle, size); | ||
1189 | __free_from_pool(page_address(pages[0]), size); | ||
1190 | } | ||
1191 | |||
1106 | static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, | 1192 | static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, |
1107 | dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) | 1193 | dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) |
1108 | { | 1194 | { |
@@ -1113,6 +1199,9 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, | |||
1113 | *handle = DMA_ERROR_CODE; | 1199 | *handle = DMA_ERROR_CODE; |
1114 | size = PAGE_ALIGN(size); | 1200 | size = PAGE_ALIGN(size); |
1115 | 1201 | ||
1202 | if (gfp & GFP_ATOMIC) | ||
1203 | return __iommu_alloc_atomic(dev, size, handle); | ||
1204 | |||
1116 | pages = __iommu_alloc_buffer(dev, size, gfp); | 1205 | pages = __iommu_alloc_buffer(dev, size, gfp); |
1117 | if (!pages) | 1206 | if (!pages) |
1118 | return NULL; | 1207 | return NULL; |
@@ -1179,6 +1268,11 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, | |||
1179 | return; | 1268 | return; |
1180 | } | 1269 | } |
1181 | 1270 | ||
1271 | if (__in_atomic_pool(cpu_addr, size)) { | ||
1272 | __iommu_free_atomic(dev, pages, handle, size); | ||
1273 | return; | ||
1274 | } | ||
1275 | |||
1182 | if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) { | 1276 | if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) { |
1183 | unmap_kernel_range((unsigned long)cpu_addr, size); | 1277 | unmap_kernel_range((unsigned long)cpu_addr, size); |
1184 | vunmap(cpu_addr); | 1278 | vunmap(cpu_addr); |