Commit 32d687cad3f188457696691677d0d276f115def0
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Merge branch 'fixes-for-3.6' of git://git.linaro.org/people/mszyprowski/linux-dma-mapping
Pull DMA-mapping fixes from Marek Szyprowski: "Another set of fixes for ARM dma-mapping subsystem. Commit e9da6e9905e6 replaced custom consistent buffer remapping code with generic vmalloc areas. It however introduced some regressions caused by limited support for allocations in atomic context. This series contains fixes for those regressions. For some subplatforms the default, pre-allocated pool for atomic allocations turned out to be too small, so a function for setting its size has been added. Another set of patches adds support for atomic allocations to IOMMU-aware DMA-mapping implementation. The last part of this pull request contains two fixes for Contiguous Memory Allocator, which relax too strict requirements." * 'fixes-for-3.6' of git://git.linaro.org/people/mszyprowski/linux-dma-mapping: ARM: dma-mapping: IOMMU allocates pages from atomic_pool with GFP_ATOMIC ARM: dma-mapping: Introduce __atomic_get_pages() for __iommu_get_pages() ARM: dma-mapping: Refactor out to introduce __in_atomic_pool ARM: dma-mapping: atomic_pool with struct page **pages ARM: Kirkwood: increase atomic coherent pool size ARM: DMA-Mapping: print warning when atomic coherent allocation fails ARM: DMA-Mapping: add function for setting coherent pool size from platform code ARM: relax conditions required for enabling Contiguous Memory Allocator mm: cma: fix alignment requirements for contiguous regions
Showing 5 changed files Side-by-side Diff
arch/arm/Kconfig
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | select HAVE_DMA_API_DEBUG |
7 | 7 | select HAVE_IDE if PCI || ISA || PCMCIA |
8 | 8 | select HAVE_DMA_ATTRS |
9 | - select HAVE_DMA_CONTIGUOUS if (CPU_V6 || CPU_V6K || CPU_V7) | |
9 | + select HAVE_DMA_CONTIGUOUS if MMU | |
10 | 10 | select HAVE_MEMBLOCK |
11 | 11 | select RTC_LIB |
12 | 12 | select SYS_SUPPORTS_APM_EMULATION |
arch/arm/include/asm/dma-mapping.h
... | ... | @@ -203,6 +203,13 @@ |
203 | 203 | } |
204 | 204 | |
205 | 205 | /* |
206 | + * This can be called during early boot to increase the size of the atomic | |
207 | + * coherent DMA pool above the default value of 256KiB. It must be called | |
208 | + * before postcore_initcall. | |
209 | + */ | |
210 | +extern void __init init_dma_coherent_pool_size(unsigned long size); | |
211 | + | |
212 | +/* | |
206 | 213 | * This can be called during boot to increase the size of the consistent |
207 | 214 | * DMA region above it's default value of 2MB. It must be called before the |
208 | 215 | * memory allocator is initialised, i.e. before any core_initcall. |
arch/arm/mach-kirkwood/common.c
... | ... | @@ -517,6 +517,13 @@ |
517 | 517 | void __init kirkwood_init_early(void) |
518 | 518 | { |
519 | 519 | orion_time_set_base(TIMER_VIRT_BASE); |
520 | + | |
521 | + /* | |
522 | + * Some Kirkwood devices allocate their coherent buffers from atomic | |
523 | + * context. Increase size of atomic coherent pool to make sure such | |
524 | + * the allocations won't fail. | |
525 | + */ | |
526 | + init_dma_coherent_pool_size(SZ_1M); | |
520 | 527 | } |
521 | 528 | |
522 | 529 | int kirkwood_tclk; |
arch/arm/mm/dma-mapping.c
... | ... | @@ -267,17 +267,19 @@ |
267 | 267 | vunmap(cpu_addr); |
268 | 268 | } |
269 | 269 | |
270 | +#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K | |
271 | + | |
270 | 272 | struct dma_pool { |
271 | 273 | size_t size; |
272 | 274 | spinlock_t lock; |
273 | 275 | unsigned long *bitmap; |
274 | 276 | unsigned long nr_pages; |
275 | 277 | void *vaddr; |
276 | - struct page *page; | |
278 | + struct page **pages; | |
277 | 279 | }; |
278 | 280 | |
279 | 281 | static struct dma_pool atomic_pool = { |
280 | - .size = SZ_256K, | |
282 | + .size = DEFAULT_DMA_COHERENT_POOL_SIZE, | |
281 | 283 | }; |
282 | 284 | |
283 | 285 | static int __init early_coherent_pool(char *p) |
... | ... | @@ -287,6 +289,21 @@ |
287 | 289 | } |
288 | 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 | 308 | * Initialise the coherent pool for atomic allocations. |
292 | 309 | */ |
... | ... | @@ -297,6 +314,7 @@ |
297 | 314 | unsigned long nr_pages = pool->size >> PAGE_SHIFT; |
298 | 315 | unsigned long *bitmap; |
299 | 316 | struct page *page; |
317 | + struct page **pages; | |
300 | 318 | void *ptr; |
301 | 319 | int bitmap_size = BITS_TO_LONGS(nr_pages) * sizeof(long); |
302 | 320 | |
303 | 321 | |
304 | 322 | |
305 | 323 | |
... | ... | @@ -304,21 +322,31 @@ |
304 | 322 | if (!bitmap) |
305 | 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 | 329 | if (IS_ENABLED(CONFIG_CMA)) |
308 | 330 | ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page); |
309 | 331 | else |
310 | 332 | ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot, |
311 | 333 | &page, NULL); |
312 | 334 | if (ptr) { |
335 | + int i; | |
336 | + | |
337 | + for (i = 0; i < nr_pages; i++) | |
338 | + pages[i] = page + i; | |
339 | + | |
313 | 340 | spin_lock_init(&pool->lock); |
314 | 341 | pool->vaddr = ptr; |
315 | - pool->page = page; | |
342 | + pool->pages = pages; | |
316 | 343 | pool->bitmap = bitmap; |
317 | 344 | pool->nr_pages = nr_pages; |
318 | 345 | pr_info("DMA: preallocated %u KiB pool for atomic coherent allocations\n", |
319 | 346 | (unsigned)pool->size / 1024); |
320 | 347 | return 0; |
321 | 348 | } |
349 | +no_pages: | |
322 | 350 | kfree(bitmap); |
323 | 351 | no_bitmap: |
324 | 352 | pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", |
325 | 353 | |
326 | 354 | |
327 | 355 | |
... | ... | @@ -443,27 +471,45 @@ |
443 | 471 | if (pageno < pool->nr_pages) { |
444 | 472 | bitmap_set(pool->bitmap, pageno, count); |
445 | 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 | 480 | spin_unlock_irqrestore(&pool->lock, flags); |
449 | 481 | |
450 | 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 | 504 | static int __free_from_pool(void *start, size_t size) |
454 | 505 | { |
455 | 506 | struct dma_pool *pool = &atomic_pool; |
456 | 507 | unsigned long pageno, count; |
457 | 508 | unsigned long flags; |
458 | 509 | |
459 | - if (start < pool->vaddr || start > pool->vaddr + pool->size) | |
510 | + if (!__in_atomic_pool(start, size)) | |
460 | 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 | 513 | pageno = (start - pool->vaddr) >> PAGE_SHIFT; |
468 | 514 | count = size >> PAGE_SHIFT; |
469 | 515 | |
470 | 516 | |
... | ... | @@ -1090,10 +1136,22 @@ |
1090 | 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 | 1148 | static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) |
1094 | 1149 | { |
1095 | 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 | 1155 | if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) |
1098 | 1156 | return cpu_addr; |
1099 | 1157 | |
... | ... | @@ -1103,6 +1161,34 @@ |
1103 | 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 | 1192 | static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, |
1107 | 1193 | dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) |
1108 | 1194 | { |
... | ... | @@ -1113,6 +1199,9 @@ |
1113 | 1199 | *handle = DMA_ERROR_CODE; |
1114 | 1200 | size = PAGE_ALIGN(size); |
1115 | 1201 | |
1202 | + if (gfp & GFP_ATOMIC) | |
1203 | + return __iommu_alloc_atomic(dev, size, handle); | |
1204 | + | |
1116 | 1205 | pages = __iommu_alloc_buffer(dev, size, gfp); |
1117 | 1206 | if (!pages) |
1118 | 1207 | return NULL; |
... | ... | @@ -1176,6 +1265,11 @@ |
1176 | 1265 | |
1177 | 1266 | if (!pages) { |
1178 | 1267 | WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); |
1268 | + return; | |
1269 | + } | |
1270 | + | |
1271 | + if (__in_atomic_pool(cpu_addr, size)) { | |
1272 | + __iommu_free_atomic(dev, pages, handle, size); | |
1179 | 1273 | return; |
1180 | 1274 | } |
1181 | 1275 |
drivers/base/dma-contiguous.c
... | ... | @@ -250,7 +250,7 @@ |
250 | 250 | return -EINVAL; |
251 | 251 | |
252 | 252 | /* Sanitise input arguments */ |
253 | - alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order); | |
253 | + alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); | |
254 | 254 | base = ALIGN(base, alignment); |
255 | 255 | size = ALIGN(size, alignment); |
256 | 256 | limit &= ~(alignment - 1); |