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@xxxxxxx/ Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- 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