From a93e7251402b8599490250ea3818c27bf4184e1b Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Fri, 5 Sep 2025 02:31:53 -0400 Subject: [PATCH] realtek: RTL93xx: Make use of correct ring size counters The receive path of the RTL93xx SoCs is currently discarding packets in software. Analysis gives the following explanation: - RX ring size registers are setup with the full software ring size - When packets are received the packet counter registers are increased - After RX processing the counter registers are changed the wrong way - From then SOC is allowed to receive more packets than software allows - Overflow interrupts are fired - As a reaction to that the software drops packets Change the processing as follows: - Setup ring size registers with a headroom of 2 buffers - Decrease the counter registers with the real work done With this change no more overflow interrupts occur because the SoC disables the queues before they can overflow or hit a buffer that is still owned by the CPU. Benchmark from single stream iperf3 run, with server process running on ZyXEL XGS1210 (RTL930x). iperf3 run before ----------------------------------------------------------- Server listening on 5201 (test #1) ----------------------------------------------------------- Accepted connection from 192.168.2.86, port 54412 [ 5] local 192.168.2.71 port 5201 connected to 192.168.2.86 port 54418 [ ID] Interval Transfer Bitrate [ 5] 0.00-1.00 sec 384 KBytes 3.14 Mbits/sec [ 5] 1.00-2.00 sec 0.00 Bytes 0.00 bits/sec [ 5] 2.00-3.00 sec 0.00 Bytes 0.00 bits/sec [ 5] 3.00-4.01 sec 5.12 MBytes 42.8 Mbits/sec [ 5] 4.01-5.00 sec 11.4 MBytes 95.8 Mbits/sec [ 5] 5.00-6.00 sec 0.00 Bytes 0.00 bits/sec [ 5] 6.00-7.00 sec 0.00 Bytes 0.00 bits/sec [ 5] 7.00-8.00 sec 0.00 Bytes 0.00 bits/sec [ 5] 8.00-9.00 sec 0.00 Bytes 0.00 bits/sec [ 5] 9.00-10.00 sec 0.00 Bytes 0.00 bits/sec iperf3 run after ----------------------------------------------------------- Server listening on 5201 (test #1) ----------------------------------------------------------- Accepted connection from 192.168.2.86, port 55228 [ 5] local 192.168.2.71 port 5201 connected to 192.168.2.86 port 55232 [ ID] Interval Transfer Bitrate [ 5] 0.00-1.00 sec 22.8 MBytes 191 Mbits/sec [ 5] 1.00-2.01 sec 25.4 MBytes 211 Mbits/sec [ 5] 2.01-3.00 sec 25.4 MBytes 215 Mbits/sec [ 5] 3.00-4.01 sec 26.5 MBytes 220 Mbits/sec [ 5] 4.01-5.00 sec 26.2 MBytes 222 Mbits/sec [ 5] 5.00-6.00 sec 26.9 MBytes 225 Mbits/sec [ 5] 6.00-7.00 sec 27.0 MBytes 226 Mbits/sec [ 5] 7.00-8.01 sec 26.9 MBytes 224 Mbits/sec [ 5] 8.01-9.00 sec 26.5 MBytes 223 Mbits/sec [ 5] 9.00-10.00 sec 26.8 MBytes 225 Mbits/sec [ 5] 10.00-10.02 sec 640 KBytes 224 Mbits/sec Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/19960 Signed-off-by: Robert Marko --- .../drivers/net/ethernet/rtl838x_eth.c | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c index 44f0fe5357..8b30ebcd85 100644 --- a/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c @@ -240,25 +240,18 @@ static void rtl839x_update_cntr(int r, int released) static void rtl930x_update_cntr(int r, int released) { + u32 reg = rtl930x_dma_if_rx_ring_cntr(r); int pos = (r % 3) * 10; - u32 reg = RTL930X_DMA_IF_RX_RING_CNTR + ((r / 3) << 2); - u32 v = sw_r32(reg); - v = (v >> pos) & 0x3ff; - pr_debug("RX: Work done %d, old value: %d, pos %d, reg %04x\n", released, v, pos, reg); - sw_w32_mask(0x3ff << pos, released << pos, reg); - sw_w32(v, reg); + sw_w32(released << pos, reg); } static void rtl931x_update_cntr(int r, int released) { + u32 reg = rtl931x_dma_if_rx_ring_cntr(r); int pos = (r % 3) * 10; - u32 reg = RTL931X_DMA_IF_RX_RING_CNTR + ((r / 3) << 2); - u32 v = sw_r32(reg); - v = (v >> pos) & 0x3ff; - sw_w32_mask(0x3ff << pos, released << pos, reg); - sw_w32(v, reg); + sw_w32(released << pos, reg); } struct dsa_tag { @@ -766,10 +759,11 @@ static void rtl93xx_hw_en_rxtx(struct rtl838x_eth_priv *priv) sw_w32((DEFAULT_MTU << 16) | RX_TRUNCATE_EN_93XX, priv->r->dma_if_ctrl); for (int i = 0; i < priv->rxrings; i++) { + int cnt = min(priv->rxringlen - 2, 0x3ff); int pos = (i % 3) * 10; u32 v; - sw_w32_mask(0x3ff << pos, priv->rxringlen << pos, priv->r->dma_if_rx_ring_size(i)); + sw_w32_mask(0x3ff << pos, cnt << pos, priv->r->dma_if_rx_ring_size(i)); /* Some SoCs have issues with missing underflow protection */ v = (sw_r32(priv->r->dma_if_rx_ring_cntr(i)) >> pos) & 0x3ff; @@ -1329,7 +1323,7 @@ static int rtl838x_hw_receive(struct net_device *dev, int r, int budget) netif_receive_skb_list(&rx_list); /* Update counters */ - priv->r->update_cntr(r, 0); + priv->r->update_cntr(r, work_done); spin_unlock_irqrestore(&priv->lock, flags); -- 2.30.2