diff mbox series

bcmgenet: fix Rx buffer corruption caused by lack of cache flush

Message ID 20240602082403.17508-1-yasuharu.shibata@gmail.com
State Accepted
Commit b993bd65ec249c842afefd39010946650bec4f8e
Delegated to: Tom Rini
Headers show
Series bcmgenet: fix Rx buffer corruption caused by lack of cache flush | expand

Commit Message

Yasuharu Shibata June 2, 2024, 8:24 a.m. UTC
When bcmgenet complete to write Rx buffer with the DMA,
some U-Boot commands write data to the buffer directly.
Those write data will become dirty in CPU cache.
After this driver calls free_pkt to the buffer,
the buffer is assigned as the future Rx buffer.
At some point, if bcmgenet writes to a buffer with DMA
and CPU cache flushes dirty data to the buffer,
the buffer is corrupted.

This patch calls flush_dcache_range in free_pkt
to immediately flush the data written by U-Boot command
and prevent data corruption.

This issue can be reproduced using wget on Raspberry Pi4.
If wget receives data larger than
RX_BUF_LENGTH * RX_DESCS = 2048 * 256 bytes,
it will timeout due to data corruption.
In addition, if LOG_DEBUG is enabled in net/tcp.c,
the following error log is output.

TCP RX TCP xSum Error

Signed-off-by: Yasuharu Shibata <yasuharu.shibata@gmail.com>
---
 drivers/net/bcmgenet.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Tom Rini June 14, 2024, 2:54 p.m. UTC | #1
On Sun, 02 Jun 2024 17:24:03 +0900, Yasuharu Shibata wrote:

> When bcmgenet complete to write Rx buffer with the DMA,
> some U-Boot commands write data to the buffer directly.
> Those write data will become dirty in CPU cache.
> After this driver calls free_pkt to the buffer,
> the buffer is assigned as the future Rx buffer.
> At some point, if bcmgenet writes to a buffer with DMA
> and CPU cache flushes dirty data to the buffer,
> the buffer is corrupted.
> 
> [...]

Applied to u-boot/master, thanks!
diff mbox series

Patch

diff --git a/drivers/net/bcmgenet.c b/drivers/net/bcmgenet.c
index 4e1f8ed7a4..a0264dc386 100644
--- a/drivers/net/bcmgenet.c
+++ b/drivers/net/bcmgenet.c
@@ -360,6 +360,10 @@  static int bcmgenet_gmac_free_pkt(struct udevice *dev, uchar *packet,
 				  int length)
 {
 	struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+	void *desc_base = priv->rx_desc_base + priv->rx_index * DMA_DESC_SIZE;
+	u32 addr = readl(desc_base + DMA_DESC_ADDRESS_LO);
+
+	flush_dcache_range(addr, addr + RX_BUF_LENGTH);
 
 	/* Tell the MAC we have consumed that last receive buffer. */
 	priv->c_index = (priv->c_index + 1) & 0xFFFF;