[PATCH] arm64/dma-mapping: Fix arch_sync_dma_for_device to respect dir parameter

John Cox via B4 Relay devnull+john.cox.raspberrypi.com at kernel.org
Wed Aug 20 03:28:06 PDT 2025


From: John Cox <john.cox at raspberrypi.com>

All other architectures do different cache operations depending on the
dir parameter. Fix arm64 to do the same.

This fixes udmabuf operations when syncing for read e.g. when the CPU
reads back a V4L2 decoded frame buffer.

Signed-off-by: John Cox <john.cox at raspberrypi.com>
---
This patch makes the arch_sync_dma_for_device function on arm64
do different things depending on the value of the dir parameter. In
particular it does a cache invalidate operation if the dir flag is
set to DMA_FROM_DEVICE. The current code does a writeback without
invalidate under all circumstances. Nearly all other architectures do
an invalidate if the direction is FROM_DEVICE which seems like the
correct thing to do to me.

This patch fixes a problem I was having with udmabuf allocated
dmabufs. It also fixes a very similar problem I had with dma_heap
allocated dmabuf but that occured very much less frequently and I
haven't traced exactly what was going on there.

My problem (on a Raspberry Pi5):

[Userland]
Alloc memory with memfd_create + ftruncate
Derive dmabuf from memfd with udmabuf
Close memfd
Queue dmabuf into V4L2 with QBUF
<decode a video frame>
Extract dmabuf from V4L2 with DQBUF
Map dmabuf for read with mmap
Sync for read with DMA_BUF_IOCTL_SYNC with (DMA_BUF_SYNC_START |
DMA_BUF_SYNC_READ)
Read buffer
Sync end
Unmap

I get old (zero) data out of the "Read buffer" stage in some cache
lines sometimes.
It doesn't matter which way round the mmap & sync are.

I am aware that there is a patchset going through for udmabuf that may
well fix the udmabuf case above, but given that this patch fixes
something similar in dma_heap/system too I think it is still worth
having.
---
 arch/arm64/mm/dma-mapping.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index b2b5792b2caaf81ccfc3204c94395bb0faeabddd..51c43c1f563015139e365ed86f0f5f0d9483fa7f 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -16,8 +16,22 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
 			      enum dma_data_direction dir)
 {
 	unsigned long start = (unsigned long)phys_to_virt(paddr);
+	unsigned long end = start + size;
 
-	dcache_clean_poc(start, start + size);
+	switch (dir) {
+	case DMA_BIDIRECTIONAL:
+		dcache_clean_inval_poc(start, end);
+		break;
+	case DMA_TO_DEVICE:
+		dcache_clean_poc(start, end);
+		break;
+	case DMA_FROM_DEVICE:
+		dcache_inval_poc(start, end);
+		break;
+	case DMA_NONE:
+	default:
+		break;
+	}
 }
 
 void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,

---
base-commit: 14131859b2615fd3076ffdad370fc5500a037432
change-id: 20250819-arm64-dma-direction-fix-7a17db452040

Best regards,
-- 
John Cox <john.cox at raspberrypi.com>





More information about the linux-arm-kernel mailing list