linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* arm: dma-mapping: CPU may not see up-to-date data after DMA transaction
@ 2018-11-22  7:36 JABLONSKY Jan
  2018-11-22  9:29 ` Russell King - ARM Linux
  0 siblings, 1 reply; 9+ messages in thread
From: JABLONSKY Jan @ 2018-11-22  7:36 UTC (permalink / raw)
  To: linux-arm-kernel

Proper cleaning and invalidating has to be performed also for inner cache,
otherwise CPU may work with data from inner cache

Problem appears on The Altera SoC FPGA (Cortex-A9), during
higher CPU and system memory load followed reading by CPU from memory after
DMA transaction.
That means CPU may not see most up-to-date and correct copy of DMA buffer.

Replace with functions __sync_cache_range_r/w, which handle mentioned
situation.
Protect against preemption to make sure, that the code is
running on the current CPU

Signed-off-by: Jan Jablonsky <jan.jablonsky@thalesgroup.com>
---
 arch/arm/mm/dma-mapping.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 661fe48ab78d..f40dc8b250d8 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -997,11 +997,18 @@ static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
 	dma_cache_maint_page(page, off, size, dir, dmac_map_area);
 
 	paddr = page_to_phys(page) + off;
+
+	/*
+	 * Protect against preemption
+	 * Ensure that the code is running on the current CPU
+	 */
+	preempt_disable();
 	if (dir == DMA_FROM_DEVICE) {
-		outer_inv_range(paddr, paddr + size);
+		__sync_cache_range_r(phys_to_virt(paddr), size);
 	} else {
-		outer_clean_range(paddr, paddr + size);
+		__sync_cache_range_w(phys_to_virt(paddr), size);
 	}
+	preempt_enable();
 	/* FIXME: non-speculating: flush on bidirectional mappings? */
 }
 
@@ -1013,7 +1020,13 @@ static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
 	/* FIXME: non-speculating: not required */
 	/* in any case, don't bother invalidating if DMA to device */
 	if (dir != DMA_TO_DEVICE) {
-		outer_inv_range(paddr, paddr + size);
+		/*
+		 * Protect against preemption
+		 * Ensure that the code is running on the current CPU
+		 */
+		preempt_disable();
+		__sync_cache_range_r(phys_to_virt(paddr), size);
+		preempt_enable();
 
 		dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
 	}

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-01-08  9:54 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-11-22  7:36 arm: dma-mapping: CPU may not see up-to-date data after DMA transaction JABLONSKY Jan
2018-11-22  9:29 ` Russell King - ARM Linux
2018-11-22 12:25   ` JABLONSKY Jan
2018-11-22 12:51     ` Russell King - ARM Linux
2018-11-22 15:36       ` JABLONSKY Jan
2018-11-22 16:36         ` Robin Murphy
2018-11-22 16:57         ` Russell King - ARM Linux
2019-01-08  6:10           ` JABLONSKY Jan
2019-01-08  9:51             ` Russell King - ARM Linux

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).