dma: Use dma-mapping for cache ops and sync after write
authorAndrew Davis <afd@ti.com>
Fri, 7 Oct 2022 17:11:11 +0000 (12:11 -0500)
committerTom Rini <trini@konsulko.com>
Tue, 18 Oct 2022 17:40:40 +0000 (13:40 -0400)
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

index 012609b..70f06f1 100644 (file)
@@ -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) = {