[PATCH v2 0/4] dma-mapping: Add cache flush/invalidation to dma_{un}map_single

Drivers (especially frameworks ported from Linux such as USB) expect dma_{un}map_single() APIs to take care of cache maintenance. But this is not the case in U-Boot and few drivers take care of flushing caches locally. Instead add flush/invalidate calls to DMA APIs in arch specific dma-mapping.h file so that per driver implementation of these APIs can be avoided.
travis-ci is green: https://travis-ci.org/r-vignesh/u-boot/builds/637784160
v2: Fix compilation failure on AM335x etc due to recent U-Boot changes Collect R-bys
Vignesh Raghavendra (4): asm: dma-mapping.h: Fix dma mapping functions mmc: tmio-common: Drop custom dma mapping functions mtd: denali: Drop custom dma mapping functions net: macb: Drop local cache flush
arch/arm/include/asm/dma-mapping.h | 23 ++++++++++++++++-- arch/nds32/include/asm/dma-mapping.h | 23 ++++++++++++++++-- arch/riscv/include/asm/dma-mapping.h | 23 ++++++++++++++++-- arch/x86/include/asm/dma-mapping.h | 23 ++++++++++++++++-- drivers/mmc/tmio-common.c | 25 +++----------------- drivers/mtd/nand/raw/denali.c | 35 +++------------------------- drivers/net/macb.c | 4 +--- 7 files changed, 91 insertions(+), 65 deletions(-)

Subsystems such as USB expect dma_map_single() and dma_unmap_single() to do dcache flush/invalidate operations as required. For example, see see drivers/usb/gadget/udc/udc-core.c::usb_gadget_map_request(). Currently drivers do this locally, (see drivers/usb/dwc3/ep0.c, drivers/mtd/nand/raw/denali.c etc..) Update arch specific dma_map_single() and dma_unmap_single() APIs to do cache flush/invalidate operations, so that drivers need not implement them locally.
Signed-off-by: Vignesh Raghavendra vigneshr@ti.com Reviewed-by: Masahiro Yamada yamada.masahiro@socionext.com Reviewed-by: Rick Chen rick@andestech.com --- arch/arm/include/asm/dma-mapping.h | 23 +++++++++++++++++++++-- arch/nds32/include/asm/dma-mapping.h | 23 +++++++++++++++++++++-- arch/riscv/include/asm/dma-mapping.h | 23 +++++++++++++++++++++-- arch/x86/include/asm/dma-mapping.h | 23 +++++++++++++++++++++-- 4 files changed, 84 insertions(+), 8 deletions(-)
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index fc5b8f634d54..d20703739fad 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -7,7 +7,11 @@ #ifndef __ASM_ARM_DMA_MAPPING_H #define __ASM_ARM_DMA_MAPPING_H
+#include <common.h> +#include <asm/cache.h> +#include <cpu_func.h> #include <linux/dma-direction.h> +#include <malloc.h>
#define dma_mapping_error(x, y) 0
@@ -25,12 +29,27 @@ static inline void dma_free_coherent(void *addr) static inline unsigned long dma_map_single(volatile void *vaddr, size_t len, enum dma_data_direction dir) { - return (unsigned long)vaddr; + unsigned long addr = (unsigned long)vaddr; + + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir == DMA_FROM_DEVICE) + invalidate_dcache_range(addr, addr + len); + else + flush_dcache_range(addr, addr + len); + + return addr; }
static inline void dma_unmap_single(volatile void *vaddr, size_t len, - unsigned long paddr) + enum dma_data_direction dir) { + unsigned long addr = (unsigned long)vaddr; + + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir != DMA_TO_DEVICE) + invalidate_dcache_range(addr, addr + len); }
#endif /* __ASM_ARM_DMA_MAPPING_H */ diff --git a/arch/nds32/include/asm/dma-mapping.h b/arch/nds32/include/asm/dma-mapping.h index e6808dc84089..c8876ceadda6 100644 --- a/arch/nds32/include/asm/dma-mapping.h +++ b/arch/nds32/include/asm/dma-mapping.h @@ -6,7 +6,11 @@ #ifndef __ASM_NDS_DMA_MAPPING_H #define __ASM_NDS_DMA_MAPPING_H
+#include <common.h> +#include <asm/cache.h> +#include <cpu_func.h> #include <linux/dma-direction.h> +#include <malloc.h>
static void *dma_alloc_coherent(size_t len, unsigned long *handle) { @@ -17,12 +21,27 @@ static void *dma_alloc_coherent(size_t len, unsigned long *handle) static inline unsigned long dma_map_single(volatile void *vaddr, size_t len, enum dma_data_direction dir) { - return (unsigned long)vaddr; + unsigned long addr = (unsigned long)vaddr; + + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir == DMA_FROM_DEVICE) + invalidate_dcache_range(addr, addr + len); + else + flush_dcache_range(addr, addr + len); + + return addr; }
static inline void dma_unmap_single(volatile void *vaddr, size_t len, - unsigned long paddr) + enum dma_data_direction dir) { + unsigned long addr = (unsigned long)vaddr; + + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir != DMA_TO_DEVICE) + invalidate_dcache_range(addr, addr + len); }
#endif /* __ASM_NDS_DMA_MAPPING_H */ diff --git a/arch/riscv/include/asm/dma-mapping.h b/arch/riscv/include/asm/dma-mapping.h index 3d930c90eceb..6cc39469590a 100644 --- a/arch/riscv/include/asm/dma-mapping.h +++ b/arch/riscv/include/asm/dma-mapping.h @@ -9,7 +9,11 @@ #ifndef __ASM_RISCV_DMA_MAPPING_H #define __ASM_RISCV_DMA_MAPPING_H
+#include <common.h> +#include <asm/cache.h> +#include <cpu_func.h> #include <linux/dma-direction.h> +#include <malloc.h>
#define dma_mapping_error(x, y) 0
@@ -27,12 +31,27 @@ static inline void dma_free_coherent(void *addr) static inline unsigned long dma_map_single(volatile void *vaddr, size_t len, enum dma_data_direction dir) { - return (unsigned long)vaddr; + unsigned long addr = (unsigned long)vaddr; + + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir == DMA_FROM_DEVICE) + invalidate_dcache_range(addr, addr + len); + else + flush_dcache_range(addr, addr + len); + + return addr; }
static inline void dma_unmap_single(volatile void *vaddr, size_t len, - unsigned long paddr) + enum dma_data_direction dir) { + unsigned long addr = (unsigned long)vaddr; + + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir != DMA_TO_DEVICE) + invalidate_dcache_range(addr, addr + len); }
#endif /* __ASM_RISCV_DMA_MAPPING_H */ diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index b353ff0bef59..900b99b8a69a 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -7,7 +7,11 @@ #ifndef __ASM_X86_DMA_MAPPING_H #define __ASM_X86_DMA_MAPPING_H
+#include <common.h> +#include <asm/cache.h> +#include <cpu_func.h> #include <linux/dma-direction.h> +#include <malloc.h>
#define dma_mapping_error(x, y) 0
@@ -25,12 +29,27 @@ static inline void dma_free_coherent(void *addr) static inline unsigned long dma_map_single(volatile void *vaddr, size_t len, enum dma_data_direction dir) { - return (unsigned long)vaddr; + unsigned long addr = (unsigned long)vaddr; + + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir == DMA_FROM_DEVICE) + invalidate_dcache_range(addr, addr + len); + else + flush_dcache_range(addr, addr + len); + + return addr; }
static inline void dma_unmap_single(volatile void *vaddr, size_t len, - unsigned long paddr) + enum dma_data_direction dir) { + unsigned long addr = (unsigned long)vaddr; + + len = ALIGN(len, ARCH_DMA_MINALIGN); + + if (dir != DMA_TO_DEVICE) + invalidate_dcache_range(addr, addr + len); }
#endif /* __ASM_X86_DMA_MAPPING_H */

On Thu, Jan 16, 2020 at 02:23:45PM +0530, Vignesh Raghavendra wrote:
Subsystems such as USB expect dma_map_single() and dma_unmap_single() to do dcache flush/invalidate operations as required. For example, see see drivers/usb/gadget/udc/udc-core.c::usb_gadget_map_request(). Currently drivers do this locally, (see drivers/usb/dwc3/ep0.c, drivers/mtd/nand/raw/denali.c etc..) Update arch specific dma_map_single() and dma_unmap_single() APIs to do cache flush/invalidate operations, so that drivers need not implement them locally.
Signed-off-by: Vignesh Raghavendra vigneshr@ti.com Reviewed-by: Masahiro Yamada yamada.masahiro@socionext.com Reviewed-by: Rick Chen rick@andestech.com
Applied to u-boot/master, thanks!

Drop local dma_map_single() and dma_unmap_single() and use arch specific common implementation
Signed-off-by: Vignesh Raghavendra vigneshr@ti.com Acked-by: Masahiro Yamada yamada.masahiro@socionext.com --- drivers/mmc/tmio-common.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-)
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 669410d97f6e..5a8506dcb6bd 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -4,6 +4,7 @@ * Author: Masahiro Yamada yamada.masahiro@socionext.com */
+#include <asm/dma-mapping.h> #include <common.h> #include <clk.h> #include <cpu_func.h> @@ -76,26 +77,6 @@ void tmio_sd_writel(struct tmio_sd_priv *priv, writel(val, priv->regbase + reg); }
-static dma_addr_t __dma_map_single(void *ptr, size_t size, - enum dma_data_direction dir) -{ - unsigned long addr = (unsigned long)ptr; - - if (dir == DMA_FROM_DEVICE) - invalidate_dcache_range(addr, addr + size); - else - flush_dcache_range(addr, addr + size); - - return addr; -} - -static void __dma_unmap_single(dma_addr_t addr, size_t size, - enum dma_data_direction dir) -{ - if (dir != DMA_TO_DEVICE) - invalidate_dcache_range(addr, addr + size); -} - static int tmio_sd_check_error(struct udevice *dev, struct mmc_cmd *cmd) { struct tmio_sd_priv *priv = dev_get_priv(dev); @@ -362,7 +343,7 @@ static int tmio_sd_dma_xfer(struct udevice *dev, struct mmc_data *data)
tmio_sd_writel(priv, tmp, TMIO_SD_DMA_MODE);
- dma_addr = __dma_map_single(buf, len, dir); + dma_addr = dma_map_single(buf, len, dir);
tmio_sd_dma_start(priv, dma_addr);
@@ -371,7 +352,7 @@ static int tmio_sd_dma_xfer(struct udevice *dev, struct mmc_data *data) if (poll_flag == TMIO_SD_DMA_INFO1_END_RD) udelay(1);
- __dma_unmap_single(dma_addr, len, dir); + dma_unmap_single(buf, len, dir);
return ret; }

On Thu, Jan 16, 2020 at 02:23:46PM +0530, Vignesh Raghavendra wrote:
Drop local dma_map_single() and dma_unmap_single() and use arch specific common implementation
Signed-off-by: Vignesh Raghavendra vigneshr@ti.com Acked-by: Masahiro Yamada yamada.masahiro@socionext.com
Applied to u-boot/master, thanks!

Drop local dma_map_single() and dma_unmap_single() and use arch specific common implementation
Signed-off-by: Vignesh Raghavendra vigneshr@ti.com Acked-by: Masahiro Yamada yamada.masahiro@socionext.com --- drivers/mtd/nand/raw/denali.c | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-)
diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 0a7ca8a8dfb4..8537c609fb62 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -5,7 +5,7 @@ * Copyright (C) 2009-2010, Intel Corporation and its suppliers. */
-#include <cpu_func.h> +#include <asm/dma-mapping.h> #include <dm.h> #include <nand.h> #include <linux/bitfield.h> @@ -17,35 +17,6 @@
#include "denali.h"
-static dma_addr_t dma_map_single(void *dev, void *ptr, size_t size, - enum dma_data_direction dir) -{ - unsigned long addr = (unsigned long)ptr; - - size = ALIGN(size, ARCH_DMA_MINALIGN); - - if (dir == DMA_FROM_DEVICE) - invalidate_dcache_range(addr, addr + size); - else - flush_dcache_range(addr, addr + size); - - return addr; -} - -static void dma_unmap_single(void *dev, dma_addr_t addr, size_t size, - enum dma_data_direction dir) -{ - size = ALIGN(size, ARCH_DMA_MINALIGN); - - if (dir != DMA_TO_DEVICE) - invalidate_dcache_range(addr, addr + size); -} - -static int dma_mapping_error(void *dev, dma_addr_t addr) -{ - return 0; -} - #define DENALI_NAND_NAME "denali-nand"
/* for Indexed Addressing */ @@ -565,7 +536,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; int ret = 0;
- dma_addr = dma_map_single(denali->dev, buf, size, dir); + dma_addr = dma_map_single(buf, size, dir); if (dma_mapping_error(denali->dev, dma_addr)) { dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n"); return denali_pio_xfer(denali, buf, size, page, raw, write); @@ -606,7 +577,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
iowrite32(0, denali->reg + DMA_ENABLE);
- dma_unmap_single(denali->dev, dma_addr, size, dir); + dma_unmap_single(buf, size, dir);
if (irq_status & INTR__ERASED_PAGE) memset(buf, 0xff, size);

On Thu, Jan 16, 2020 at 02:23:47PM +0530, Vignesh Raghavendra wrote:
Drop local dma_map_single() and dma_unmap_single() and use arch specific common implementation
Signed-off-by: Vignesh Raghavendra vigneshr@ti.com Acked-by: Masahiro Yamada yamada.masahiro@socionext.com
Applied to u-boot/master, thanks!

Now that arch specific dma mapping APIs take care of cache flush/invalidate, drop local cache flush operation. While at that fix dma_unmap_single() call to match new prototype
Signed-off-by: Vignesh Raghavendra vigneshr@ti.com --- drivers/net/macb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 83594253787c..0d4929bec131 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -327,8 +327,6 @@ static int _macb_send(struct macb_device *macb, const char *name, void *packet, macb->tx_ring[tx_head].addr = paddr; barrier(); macb_flush_ring_desc(macb, TX); - /* Do we need check paddr and length is dcache line aligned? */ - flush_dcache_range(paddr, paddr + ALIGN(length, ARCH_DMA_MINALIGN)); macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
/* @@ -344,7 +342,7 @@ static int _macb_send(struct macb_device *macb, const char *name, void *packet, udelay(1); }
- dma_unmap_single(packet, length, paddr); + dma_unmap_single(packet, length, DMA_TO_DEVICE);
if (i <= MACB_TX_TIMEOUT) { if (ctrl & MACB_BIT(TX_UNDERRUN))

On Thu, Jan 16, 2020 at 02:23:48PM +0530, Vignesh Raghavendra wrote:
Now that arch specific dma mapping APIs take care of cache flush/invalidate, drop local cache flush operation. While at that fix dma_unmap_single() call to match new prototype
Signed-off-by: Vignesh Raghavendra vigneshr@ti.com
Applied to u-boot/master, thanks!

Hi Tom,
On 16/01/20 2:23 pm, Vignesh Raghavendra wrote:
Drivers (especially frameworks ported from Linux such as USB) expect dma_{un}map_single() APIs to take care of cache maintenance. But this is not the case in U-Boot and few drivers take care of flushing caches locally. Instead add flush/invalidate calls to DMA APIs in arch specific dma-mapping.h file so that per driver implementation of these APIs can be avoided.
travis-ci is green: https://travis-ci.org/r-vignesh/u-boot/builds/637784160
Gentle ping...
v2: Fix compilation failure on AM335x etc due to recent U-Boot changes Collect R-bys
Vignesh Raghavendra (4): asm: dma-mapping.h: Fix dma mapping functions mmc: tmio-common: Drop custom dma mapping functions mtd: denali: Drop custom dma mapping functions net: macb: Drop local cache flush
arch/arm/include/asm/dma-mapping.h | 23 ++++++++++++++++-- arch/nds32/include/asm/dma-mapping.h | 23 ++++++++++++++++-- arch/riscv/include/asm/dma-mapping.h | 23 ++++++++++++++++-- arch/x86/include/asm/dma-mapping.h | 23 ++++++++++++++++-- drivers/mmc/tmio-common.c | 25 +++----------------- drivers/mtd/nand/raw/denali.c | 35 +++------------------------- drivers/net/macb.c | 4 +--- 7 files changed, 91 insertions(+), 65 deletions(-)
participants (2)
-
Tom Rini
-
Vignesh Raghavendra