From 39f78e70567a07a6fc0d7a4ca9e3331e44dd400d Mon Sep 17 00:00:00 2001 From: Chris Brand Date: Tue, 7 Aug 2012 14:01:14 +0200 Subject: [PATCH 1/3] ARM: mm: fix MMU mapping of CMA regions Fix dma_contiguous_remap() so that it continues through all the regions, even after encountering one that is outside lowmem. Without this change, if you have two CMA regions, the first outside lowmem and the seocnd inside lowmem, only the second one will get set up in the MMU. Data written to that region then doesn't get automatically flushed from the cache into memory. Signed-off-by: Chris Brand [extended patch subject with 'fix' word] Signed-off-by: Marek Szyprowski --- arch/arm/mm/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index c2cdf6500f75..334dd79ad5e6 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -358,7 +358,7 @@ void __init dma_contiguous_remap(void) if (end > arm_lowmem_limit) end = arm_lowmem_limit; if (start >= end) - return; + continue; map.pfn = __phys_to_pfn(start); map.virtual = __phys_to_virt(start); From e4ea6918c93b9f59d34e8ca2124b2b64b1afe73b Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Tue, 7 Aug 2012 14:39:25 +0200 Subject: [PATCH 2/3] ARM: dma-mapping: fix atomic allocation alignment The alignment mask is calculated incorrectly. Fixing the calculation makes strange hangs/lockups disappear during the boot with Amstrad E3 and 3.6-rc1 kernel. Signed-off-by: Aaro Koskinen Signed-off-by: Marek Szyprowski --- arch/arm/mm/dma-mapping.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 334dd79ad5e6..4bdeccd24d93 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -423,7 +423,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page) unsigned int pageno; unsigned long flags; void *ptr = NULL; - size_t align; + unsigned long align_mask; if (!pool->vaddr) { WARN(1, "coherent pool not initialised!\n"); @@ -435,11 +435,11 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page) * small, so align them to their order in pages, minimum is a page * size. This helps reduce fragmentation of the DMA space. */ - align = PAGE_SIZE << get_order(size); + align_mask = (1 << get_order(size)) - 1; spin_lock_irqsave(&pool->lock, flags); pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages, - 0, count, (1 << align) - 1); + 0, count, align_mask); if (pageno < pool->nr_pages) { bitmap_set(pool->bitmap, pageno, count); ptr = pool->vaddr + PAGE_SIZE * pageno; From d9e0d149b5dcc2ef4688afc572b9906bcda941ef Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Tue, 7 Aug 2012 14:44:05 +0200 Subject: [PATCH 3/3] ARM: dma-mapping: fix incorrect freeing of atomic allocations Commit e9da6e9905e639b0f842a244bc770b48ad0523e9 (ARM: dma-mapping: remove custom consistent dma region) changed the way atomic allocations are handled. However, arm_dma_free() was not modified accordingly, and as a result freeing of atomic allocations does not work correctly when CMA is disabled. Memory is leaked and following WARNINGs are seen: [ 57.698911] ------------[ cut here ]------------ [ 57.753518] WARNING: at arch/arm/mm/dma-mapping.c:263 arm_dma_free+0x88/0xe4() [ 57.811473] trying to free invalid coherent area: e0848000 [ 57.867398] Modules linked in: sata_mv(-) [ 57.921373] [] (unwind_backtrace+0x0/0xf0) from [] (warn_slowpath_common+0x50/0x68) [ 58.033924] [] (warn_slowpath_common+0x50/0x68) from [] (warn_slowpath_fmt+0x30/0x40) [ 58.152024] [] (warn_slowpath_fmt+0x30/0x40) from [] (arm_dma_free+0x88/0xe4) [ 58.219592] [] (arm_dma_free+0x88/0xe4) from [] (dma_pool_destroy+0x100/0x148) [ 58.345526] [] (dma_pool_destroy+0x100/0x148) from [] (release_nodes+0x144/0x218) [ 58.475782] [] (release_nodes+0x144/0x218) from [] (__device_release_driver+0x60/0xb8) [ 58.614260] [] (__device_release_driver+0x60/0xb8) from [] (driver_detach+0xd8/0xec) [ 58.756527] [] (driver_detach+0xd8/0xec) from [] (bus_remove_driver+0x7c/0xc4) [ 58.901648] [] (bus_remove_driver+0x7c/0xc4) from [] (sys_delete_module+0x19c/0x220) [ 59.051447] [] (sys_delete_module+0x19c/0x220) from [] (ret_fast_syscall+0x0/0x2c) [ 59.207996] ---[ end trace 0745420412c0325a ]--- [ 59.287110] ------------[ cut here ]------------ [ 59.366324] WARNING: at arch/arm/mm/dma-mapping.c:263 arm_dma_free+0x88/0xe4() [ 59.450511] trying to free invalid coherent area: e0847000 [ 59.534357] Modules linked in: sata_mv(-) [ 59.616785] [] (unwind_backtrace+0x0/0xf0) from [] (warn_slowpath_common+0x50/0x68) [ 59.790030] [] (warn_slowpath_common+0x50/0x68) from [] (warn_slowpath_fmt+0x30/0x40) [ 59.972322] [] (warn_slowpath_fmt+0x30/0x40) from [] (arm_dma_free+0x88/0xe4) [ 60.070701] [] (arm_dma_free+0x88/0xe4) from [] (dma_pool_destroy+0x100/0x148) [ 60.256817] [] (dma_pool_destroy+0x100/0x148) from [] (release_nodes+0x144/0x218) [ 60.445201] [] (release_nodes+0x144/0x218) from [] (__device_release_driver+0x60/0xb8) [ 60.634148] [] (__device_release_driver+0x60/0xb8) from [] (driver_detach+0xd8/0xec) [ 60.823623] [] (driver_detach+0xd8/0xec) from [] (bus_remove_driver+0x7c/0xc4) [ 61.013268] [] (bus_remove_driver+0x7c/0xc4) from [] (sys_delete_module+0x19c/0x220) [ 61.203472] [] (sys_delete_module+0x19c/0x220) from [] (ret_fast_syscall+0x0/0x2c) [ 61.393390] ---[ end trace 0745420412c0325b ]--- The patch fixes this. Signed-off-by: Aaro Koskinen Signed-off-by: Marek Szyprowski --- arch/arm/mm/dma-mapping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 4bdeccd24d93..4e7d1182e8a3 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -648,12 +648,12 @@ void arm_dma_free(struct device *dev, size_t size, void *cpu_addr, if (arch_is_coherent() || nommu()) { __dma_free_buffer(page, size); + } else if (__free_from_pool(cpu_addr, size)) { + return; } else if (!IS_ENABLED(CONFIG_CMA)) { __dma_free_remap(cpu_addr, size); __dma_free_buffer(page, size); } else { - if (__free_from_pool(cpu_addr, size)) - return; /* * Non-atomic allocations cannot be freed with IRQs disabled */