
The DMA'd memory area needs cleaned and invalidated after the DMA write so that any stale cache lines do not mask new data.
Signed-off-by: Andrew Davis afd@ti.com --- drivers/dma/dma-uclass.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c index 012609bb53..70f06f1f09 100644 --- a/drivers/dma/dma-uclass.c +++ b/drivers/dma/dma-uclass.c @@ -19,6 +19,7 @@ #include <asm/cache.h> #include <dm/read.h> #include <dma-uclass.h> +#include <linux/dma-mapping.h> #include <dt-structs.h> #include <errno.h>
@@ -235,6 +236,8 @@ int dma_memcpy(void *dst, void *src, size_t len) { struct udevice *dev; const struct dma_ops *ops; + dma_addr_t destination; + dma_addr_t source; int ret;
ret = dma_get_device(DMA_SUPPORTS_MEM_TO_MEM, &dev); @@ -245,11 +248,17 @@ int dma_memcpy(void *dst, void *src, size_t len) if (!ops->transfer) return -ENOSYS;
- /* Invalidate the area, so no writeback into the RAM races with DMA */ - invalidate_dcache_range((unsigned long)dst, (unsigned long)dst + - roundup(len, ARCH_DMA_MINALIGN)); + /* Clean the areas, so no writeback into the RAM races with DMA */ + destination = dma_map_single(dst, len, DMA_FROM_DEVICE); + source = dma_map_single(src, len, DMA_TO_DEVICE);
- return ops->transfer(dev, DMA_MEM_TO_MEM, dst, src, len); + ret = ops->transfer(dev, DMA_MEM_TO_MEM, dst, src, len); + + /* Clean+Invalidate the areas after, so we can see DMA'd data */ + dma_unmap_single(destination, len, DMA_FROM_DEVICE); + dma_unmap_single(source, len, DMA_TO_DEVICE); + + return ret; }
UCLASS_DRIVER(dma) = {