diff mbox series

[5/5] dma: ti: k3-udma: invalidate prepared buffers before pushing to recv ring

Message ID d3f36df0833702190ce902033a4c14d5d844d9b6.1714117337.git.matthias.schiffer@ew.tq-group.com
State Accepted
Commit 1db973b65f9c1efbfa5370a95d6330f29557b3ab
Delegated to: Tom Rini
Headers show
Series [1/5] net: eth-uclass: guard against reentrant eth_init()/eth_halt() calls | expand

Commit Message

Matthias Schiffer April 26, 2024, 8:02 a.m. UTC
Buffers must not have an unclean cache before being used for DMA - a
pending write-back may corrupt the next dev-to-mem transfer otherwise.

This was consistently noticeable during long TFTP transfers, when an ARP
request is answered by U-Boot in the middle of the transfer:

As U-Boot's arp_receive() reuses the receive buffer to prepare its
reply packet, the beginning of one of the next incoming TFTP packets
is overwritten by the ARP reply. The corrupted packet is ignored, but
the TFTP transfer stalls for a few seconds until a timeout is detected
and a retransmit is triggered.

Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com>
---
 drivers/dma/ti/k3-udma.c | 3 +++
 1 file changed, 3 insertions(+)

Comments

Sverdlin, Alexander May 3, 2024, 6:42 p.m. UTC | #1
Hello Matthias,

On Fri, 2024-04-26 at 10:02 +0200, Matthias Schiffer wrote:
> Buffers must not have an unclean cache before being used for DMA - a
> pending write-back may corrupt the next dev-to-mem transfer otherwise.
> 
> This was consistently noticeable during long TFTP transfers, when an ARP
> request is answered by U-Boot in the middle of the transfer:
> 
> As U-Boot's arp_receive() reuses the receive buffer to prepare its
> reply packet, the beginning of one of the next incoming TFTP packets
> is overwritten by the ARP reply. The corrupted packet is ignored, but
> the TFTP transfer stalls for a few seconds until a timeout is detected
> and a retransmit is triggered.
> 
> Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com>

thanks for the series! I've tested it on a custom AM625-based board
issuing a a couple of pings:

am65_cpsw_nuss ethernet@8000000: K3 CPSW: nuss_ver: 0x6BA01103 cpsw_ver: 0x6BA81103 ale_ver: 0x00290105 Ports:2
Net:   eth0: ethernet@8000000port@1
Autobooting in 3 seconds, press "<Esc><Esc>" to stop
U-Boot# ping 192.168.251.10
ti-udma dma-controller@485c0000: k3_dmaring Ring probed rings:150, sci-dev-id:30
ti-udma dma-controller@485c0000: dma-ring-reset-quirk: disabled
am65_cpsw_nuss_port ethernet@8000000port@1: K3 CPSW: rflow_id_base: 19
link up on port 1, speed 100, full duplex
Using ethernet@8000000port@1 device
host 192.168.251.10 is alive
U-Boot# ping 192.168.251.10
am65_cpsw_nuss_port ethernet@8000000port@1: K3 CPSW: rflow_id_base: 19
link up on port 1, speed 100, full duplex
Using ethernet@8000000port@1 device
host 192.168.251.10 is alive

This sequence looks exactly the same with your patches and without.
Therefore for the whole series:

Tested-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>

> ---
>  drivers/dma/ti/k3-udma.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
> index 4e6f7f570c5..8f6d396653e 100644
> --- a/drivers/dma/ti/k3-udma.c
> +++ b/drivers/dma/ti/k3-udma.c
> @@ -2678,6 +2678,9 @@ int udma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size)
>         cppi5_hdesc_set_pktlen(desc_rx, size);
>         cppi5_hdesc_attach_buf(desc_rx, dma_dst, size, dma_dst, size);
>  
> +       invalidate_dcache_range((unsigned long)dma_dst,
> +                               (unsigned long)(dma_dst + size));
> +
>         flush_dcache_range((unsigned long)desc_rx,
>                            ALIGN((unsigned long)desc_rx + uc->config.hdesc_size,
>                                  ARCH_DMA_MINALIGN));
diff mbox series

Patch

diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 4e6f7f570c5..8f6d396653e 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -2678,6 +2678,9 @@  int udma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size)
 	cppi5_hdesc_set_pktlen(desc_rx, size);
 	cppi5_hdesc_attach_buf(desc_rx, dma_dst, size, dma_dst, size);
 
+	invalidate_dcache_range((unsigned long)dma_dst,
+				(unsigned long)(dma_dst + size));
+
 	flush_dcache_range((unsigned long)desc_rx,
 			   ALIGN((unsigned long)desc_rx + uc->config.hdesc_size,
 				 ARCH_DMA_MINALIGN));