diff options
Diffstat (limited to 'arch/arm/mm/dma-mapping.c')
-rw-r--r-- | arch/arm/mm/dma-mapping.c | 128 |
1 files changed, 112 insertions, 16 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index c2cdf6500f75..13f555d62491 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,33 @@ 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 | |||
350 | kfree(pages); | ||
351 | no_pages: | ||
322 | kfree(bitmap); | 352 | kfree(bitmap); |
323 | no_bitmap: | 353 | no_bitmap: |
324 | pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", | 354 | pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", |
@@ -358,7 +388,7 @@ void __init dma_contiguous_remap(void) | |||
358 | if (end > arm_lowmem_limit) | 388 | if (end > arm_lowmem_limit) |
359 | end = arm_lowmem_limit; | 389 | end = arm_lowmem_limit; |
360 | if (start >= end) | 390 | if (start >= end) |
361 | return; | 391 | continue; |
362 | 392 | ||
363 | map.pfn = __phys_to_pfn(start); | 393 | map.pfn = __phys_to_pfn(start); |
364 | map.virtual = __phys_to_virt(start); | 394 | map.virtual = __phys_to_virt(start); |
@@ -423,7 +453,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page) | |||
423 | unsigned int pageno; | 453 | unsigned int pageno; |
424 | unsigned long flags; | 454 | unsigned long flags; |
425 | void *ptr = NULL; | 455 | void *ptr = NULL; |
426 | size_t align; | 456 | unsigned long align_mask; |
427 | 457 | ||
428 | if (!pool->vaddr) { | 458 | if (!pool->vaddr) { |
429 | WARN(1, "coherent pool not initialised!\n"); | 459 | WARN(1, "coherent pool not initialised!\n"); |
@@ -435,35 +465,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 | 465 | * small, so align them to their order in pages, minimum is a page |
436 | * size. This helps reduce fragmentation of the DMA space. | 466 | * size. This helps reduce fragmentation of the DMA space. |
437 | */ | 467 | */ |
438 | align = PAGE_SIZE << get_order(size); | 468 | align_mask = (1 << get_order(size)) - 1; |
439 | 469 | ||
440 | spin_lock_irqsave(&pool->lock, flags); | 470 | spin_lock_irqsave(&pool->lock, flags); |
441 | pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages, | 471 | pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages, |
442 | 0, count, (1 << align) - 1); | 472 | 0, count, align_mask); |
443 | if (pageno < pool->nr_pages) { | 473 | if (pageno < pool->nr_pages) { |
444 | bitmap_set(pool->bitmap, pageno, count); | 474 | bitmap_set(pool->bitmap, pageno, count); |
445 | ptr = pool->vaddr + PAGE_SIZE * pageno; | 475 | ptr = pool->vaddr + PAGE_SIZE * pageno; |
446 | *ret_page = pool->page + pageno; | 476 | *ret_page = pool->pages[pageno]; |
477 | } else { | ||
478 | pr_err_once("ERROR: %u KiB atomic DMA coherent pool is too small!\n" | ||
479 | "Please increase it with coherent_pool= kernel parameter!\n", | ||
480 | (unsigned)pool->size / 1024); | ||
447 | } | 481 | } |
448 | spin_unlock_irqrestore(&pool->lock, flags); | 482 | spin_unlock_irqrestore(&pool->lock, flags); |
449 | 483 | ||
450 | return ptr; | 484 | return ptr; |
451 | } | 485 | } |
452 | 486 | ||
487 | static bool __in_atomic_pool(void *start, size_t size) | ||
488 | { | ||
489 | struct dma_pool *pool = &atomic_pool; | ||
490 | void *end = start + size; | ||
491 | void *pool_start = pool->vaddr; | ||
492 | void *pool_end = pool->vaddr + pool->size; | ||
493 | |||
494 | if (start < pool_start || start >= pool_end) | ||
495 | return false; | ||
496 | |||
497 | if (end <= pool_end) | ||
498 | return true; | ||
499 | |||
500 | WARN(1, "Wrong coherent size(%p-%p) from atomic pool(%p-%p)\n", | ||
501 | start, end - 1, pool_start, pool_end - 1); | ||
502 | |||
503 | return false; | ||
504 | } | ||
505 | |||
453 | static int __free_from_pool(void *start, size_t size) | 506 | static int __free_from_pool(void *start, size_t size) |
454 | { | 507 | { |
455 | struct dma_pool *pool = &atomic_pool; | 508 | struct dma_pool *pool = &atomic_pool; |
456 | unsigned long pageno, count; | 509 | unsigned long pageno, count; |
457 | unsigned long flags; | 510 | unsigned long flags; |
458 | 511 | ||
459 | if (start < pool->vaddr || start > pool->vaddr + pool->size) | 512 | if (!__in_atomic_pool(start, size)) |
460 | return 0; | 513 | return 0; |
461 | 514 | ||
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; | 515 | pageno = (start - pool->vaddr) >> PAGE_SHIFT; |
468 | count = size >> PAGE_SHIFT; | 516 | count = size >> PAGE_SHIFT; |
469 | 517 | ||
@@ -648,12 +696,12 @@ void arm_dma_free(struct device *dev, size_t size, void *cpu_addr, | |||
648 | 696 | ||
649 | if (arch_is_coherent() || nommu()) { | 697 | if (arch_is_coherent() || nommu()) { |
650 | __dma_free_buffer(page, size); | 698 | __dma_free_buffer(page, size); |
699 | } else if (__free_from_pool(cpu_addr, size)) { | ||
700 | return; | ||
651 | } else if (!IS_ENABLED(CONFIG_CMA)) { | 701 | } else if (!IS_ENABLED(CONFIG_CMA)) { |
652 | __dma_free_remap(cpu_addr, size); | 702 | __dma_free_remap(cpu_addr, size); |
653 | __dma_free_buffer(page, size); | 703 | __dma_free_buffer(page, size); |
654 | } else { | 704 | } else { |
655 | if (__free_from_pool(cpu_addr, size)) | ||
656 | return; | ||
657 | /* | 705 | /* |
658 | * Non-atomic allocations cannot be freed with IRQs disabled | 706 | * Non-atomic allocations cannot be freed with IRQs disabled |
659 | */ | 707 | */ |
@@ -1090,10 +1138,22 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si | |||
1090 | return 0; | 1138 | return 0; |
1091 | } | 1139 | } |
1092 | 1140 | ||
1141 | static struct page **__atomic_get_pages(void *addr) | ||
1142 | { | ||
1143 | struct dma_pool *pool = &atomic_pool; | ||
1144 | struct page **pages = pool->pages; | ||
1145 | int offs = (addr - pool->vaddr) >> PAGE_SHIFT; | ||
1146 | |||
1147 | return pages + offs; | ||
1148 | } | ||
1149 | |||
1093 | static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) | 1150 | static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) |
1094 | { | 1151 | { |
1095 | struct vm_struct *area; | 1152 | struct vm_struct *area; |
1096 | 1153 | ||
1154 | if (__in_atomic_pool(cpu_addr, PAGE_SIZE)) | ||
1155 | return __atomic_get_pages(cpu_addr); | ||
1156 | |||
1097 | if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) | 1157 | if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) |
1098 | return cpu_addr; | 1158 | return cpu_addr; |
1099 | 1159 | ||
@@ -1103,6 +1163,34 @@ static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) | |||
1103 | return NULL; | 1163 | return NULL; |
1104 | } | 1164 | } |
1105 | 1165 | ||
1166 | static void *__iommu_alloc_atomic(struct device *dev, size_t size, | ||
1167 | dma_addr_t *handle) | ||
1168 | { | ||
1169 | struct page *page; | ||
1170 | void *addr; | ||
1171 | |||
1172 | addr = __alloc_from_pool(size, &page); | ||
1173 | if (!addr) | ||
1174 | return NULL; | ||
1175 | |||
1176 | *handle = __iommu_create_mapping(dev, &page, size); | ||
1177 | if (*handle == DMA_ERROR_CODE) | ||
1178 | goto err_mapping; | ||
1179 | |||
1180 | return addr; | ||
1181 | |||
1182 | err_mapping: | ||
1183 | __free_from_pool(addr, size); | ||
1184 | return NULL; | ||
1185 | } | ||
1186 | |||
1187 | static void __iommu_free_atomic(struct device *dev, struct page **pages, | ||
1188 | dma_addr_t handle, size_t size) | ||
1189 | { | ||
1190 | __iommu_remove_mapping(dev, handle, size); | ||
1191 | __free_from_pool(page_address(pages[0]), size); | ||
1192 | } | ||
1193 | |||
1106 | static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, | 1194 | static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, |
1107 | dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) | 1195 | dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) |
1108 | { | 1196 | { |
@@ -1113,6 +1201,9 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, | |||
1113 | *handle = DMA_ERROR_CODE; | 1201 | *handle = DMA_ERROR_CODE; |
1114 | size = PAGE_ALIGN(size); | 1202 | size = PAGE_ALIGN(size); |
1115 | 1203 | ||
1204 | if (gfp & GFP_ATOMIC) | ||
1205 | return __iommu_alloc_atomic(dev, size, handle); | ||
1206 | |||
1116 | pages = __iommu_alloc_buffer(dev, size, gfp); | 1207 | pages = __iommu_alloc_buffer(dev, size, gfp); |
1117 | if (!pages) | 1208 | if (!pages) |
1118 | return NULL; | 1209 | return NULL; |
@@ -1179,6 +1270,11 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, | |||
1179 | return; | 1270 | return; |
1180 | } | 1271 | } |
1181 | 1272 | ||
1273 | if (__in_atomic_pool(cpu_addr, size)) { | ||
1274 | __iommu_free_atomic(dev, pages, handle, size); | ||
1275 | return; | ||
1276 | } | ||
1277 | |||
1182 | if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) { | 1278 | if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) { |
1183 | unmap_kernel_range((unsigned long)cpu_addr, size); | 1279 | unmap_kernel_range((unsigned long)cpu_addr, size); |
1184 | vunmap(cpu_addr); | 1280 | vunmap(cpu_addr); |