Thread (7 messages) flat view 7 messages, 3 authors, 1h ago
HOTtoday

[PATCH 1/2] ARM: dma-mapping: preserve DMA_FROM_DEVICE buffer contents

From: Karl Mehltretter <hidden>
Date: 2026-09-10 06:36:36
Also in: lkml, stable
Subsystem: arm port, the rest · Maintainers: Russell King, Linus Torvalds

The v6, v7 and v7-M cache backends invalidate DMA_FROM_DEVICE buffers
when ownership passes to the device. The common outer-cache path does
the same. On a write-back cache, invalidating a dirty line can discard
CPU-written data. If the device writes only part of the buffer, the
untouched bytes can expose memory contents older than those present at
the handoff.

A mapping-only test on an ARM11 MPCore (ARMv6) system reproduced this
through the v6 path. The existing code lost 402,080 of 409,600
CPU-written bytes over 100 iterations. This change lost none.

Clean the inner and outer cache lines for the buffer at handoff. The
existing completion path still invalidates them before the CPU reads the
buffer. This matches arm64 commit c50f11c6196f ("arm64: mm: Don't
invalidate FROM_DEVICE buffers at start of DMA transfer") and adds no
cache traversal.

Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20220606152150.GA31568@willie-the-truck (local)
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <redacted>
---
 arch/arm/mm/cache-v6.S          | 2 --
 arch/arm/mm/cache-v7.S          | 2 --
 arch/arm/mm/cache-v7m.S         | 2 --
 arch/arm/mm/dma-mapping-nommu.c | 5 +----
 arch/arm/mm/dma-mapping.c       | 8 +-------
 5 files changed, 2 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index 5ceea8965ea1..149042bac423 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -283,8 +283,6 @@ SYM_FUNC_END(v6_dma_flush_range)
  */
 SYM_TYPED_FUNC_START(v6_dma_map_area)
 	add	r1, r1, r0
-	teq	r2, #DMA_FROM_DEVICE
-	beq	v6_dma_inv_range
 	b	v6_dma_clean_range
 SYM_FUNC_END(v6_dma_map_area)
 
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 726681fb7d4d..22897f98cc95 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -441,8 +441,6 @@ SYM_FUNC_END(v7_dma_flush_range)
  */
 SYM_TYPED_FUNC_START(v7_dma_map_area)
 	add	r1, r1, r0
-	teq	r2, #DMA_FROM_DEVICE
-	beq	v7_dma_inv_range
 	b	v7_dma_clean_range
 SYM_FUNC_END(v7_dma_map_area)
 
diff --git a/arch/arm/mm/cache-v7m.S b/arch/arm/mm/cache-v7m.S
index 7f9cfad2ea21..3ea5f047f43e 100644
--- a/arch/arm/mm/cache-v7m.S
+++ b/arch/arm/mm/cache-v7m.S
@@ -432,8 +432,6 @@ SYM_FUNC_END(v7m_dma_flush_range)
  */
 SYM_TYPED_FUNC_START(v7m_dma_map_area)
 	add	r1, r1, r0
-	teq	r2, #DMA_FROM_DEVICE
-	beq	v7m_dma_inv_range
 	b	v7m_dma_clean_range
 SYM_FUNC_END(v7m_dma_map_area)
 
diff --git a/arch/arm/mm/dma-mapping-nommu.c b/arch/arm/mm/dma-mapping-nommu.c
index c6a70686507b..a396bbceee73 100644
--- a/arch/arm/mm/dma-mapping-nommu.c
+++ b/arch/arm/mm/dma-mapping-nommu.c
@@ -18,10 +18,7 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
 {
 	dmac_map_area(__va(paddr), size, dir);
 
-	if (dir == DMA_FROM_DEVICE)
-		outer_inv_range(paddr, paddr + size);
-	else
-		outer_clean_range(paddr, paddr + size);
+	outer_clean_range(paddr, paddr + size);
 }
 
 void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 7761099dde9e..e2df8b680bd6 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -681,18 +681,12 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
 {
 	dma_cache_maint_page(paddr, size, dir, dmac_map_area);
 
-	if (dir == DMA_FROM_DEVICE) {
-		outer_inv_range(paddr, paddr + size);
-	} else {
-		outer_clean_range(paddr, paddr + size);
-	}
-	/* FIXME: non-speculating: flush on bidirectional mappings? */
+	outer_clean_range(paddr, paddr + size);
 }
 
 void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
 			   enum dma_data_direction dir)
 {
-	/* 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);
-- 
2.53.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help