[PATCH v2 08/11] dma: fix dma_sync when not all device DMA is equally coherent
Ahmad Fatoum
a.fatoum at pengutronix.de
Wed Jan 10 08:01:10 PST 2024
The LS1046A features a cache-coherent interconnect and the drivers
configure the hardware appropriately, e.g. setting the FMan PRAM_MODE_GLOBAL
bit, so the existing Ethernet Controllers snoop caches.
Yet, we use the standard arm64 cache maintenance routines when the MMU
is enabled and thus risk memory corruption if CPU prefetches receive buffers
in the time window between dma_map_single() cleaning them to
Point-of-Coherency and dma_unmap_single() invalidating them[1].
To properly solve this issue, we need to consult the newly added per-device
dma coherent attribute to decide whether to do manual cache maintenance.
[1]: https://lore.kernel.org/all/a5d6cc26-cd23-7c31-f56e-f6d535ea39b0@arm.com/
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
- switch to boolean comparisons instead of comparison <= or >= to zero
---
drivers/dma/map.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/map.c b/drivers/dma/map.c
index e320f6aad4ac..ab86a8c7b139 100644
--- a/drivers/dma/map.c
+++ b/drivers/dma/map.c
@@ -9,7 +9,8 @@ void dma_sync_single_for_cpu(struct device *dev, dma_addr_t address,
debug_dma_sync_single_for_cpu(dev, address, size, dir);
- arch_sync_dma_for_cpu(ptr, size, dir);
+ if (!dev_is_dma_coherent(dev))
+ arch_sync_dma_for_cpu(ptr, size, dir);
}
void dma_sync_single_for_device(struct device *dev, dma_addr_t address,
@@ -19,7 +20,8 @@ void dma_sync_single_for_device(struct device *dev, dma_addr_t address,
debug_dma_sync_single_for_device(dev, address, size, dir);
- arch_sync_dma_for_device(ptr, size, dir);
+ if (!dev_is_dma_coherent(dev))
+ arch_sync_dma_for_device(ptr, size, dir);
}
dma_addr_t dma_map_single(struct device *dev, void *ptr,
@@ -29,7 +31,8 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr,
debug_dma_map(dev, ptr, size, dir, dma_addr);
- arch_sync_dma_for_device(ptr, size, dir);
+ if (!dev_is_dma_coherent(dev))
+ arch_sync_dma_for_device(ptr, size, dir);
return dma_addr;
}
@@ -37,7 +40,8 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr,
void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
size_t size, enum dma_data_direction dir)
{
- dma_sync_single_for_cpu(dev, dma_addr, size, dir);
+ if (!dev_is_dma_coherent(dev))
+ dma_sync_single_for_cpu(dev, dma_addr, size, dir);
debug_dma_unmap(dev, dma_addr, size, dir);
}
--
2.39.2
More information about the barebox
mailing list