From 0d20963e0aeb39da919288a3b70ecf555f5ab3a1 Mon Sep 17 00:00:00 2001 From: Pengfei Zhang Date: Fri, 9 Oct 2026 19:11:37 +0800 Subject: [PATCH] net: stmmac: fix RX coalesce frames counter The RX refill path should set the IC bit once every rx_coal_frames descriptors and leave the rest to the RX watchdog (RIWT), as done by commit d429b66e2ebc ("net: stmmac: Implement RX Coalesce Frames setting"). Since commit 6fa9d691b91a ("net: stmmac: Prevent divide-by-zero") the counter is increased by N+1 for each descriptor and then compared against N, so it is always reset to 0. With a non-zero rx-frames, IC is therefore set on every descriptor and every frame raises an interrupt. Fix this by counting one descriptor at a time in a helper used by both stmmac_rx_refill() and stmmac_rx_refill_zc(). Platforms without RIWT (IC on every descriptor) are unaffected. Cc: stable+noautosel@kernel.org # never worked Fixes: 6fa9d691b91a ("net: stmmac: Prevent divide-by-zero") Signed-off-by: Pengfei Zhang Link: https://patch.msgid.link/20261009111138.320089-1-zhangfeionline@gmail.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 56d89a696272..53782ab55e12 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -5110,6 +5110,22 @@ static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb) } } +static bool stmmac_rx_need_ic(struct stmmac_priv *priv, + struct stmmac_rx_queue *rx_q, u32 queue) +{ + u32 frames = priv->rx_coal_frames[queue]; + + /* without the RX watchdog every descriptor needs IC */ + if (!priv->use_riwt) + return true; + + if (!frames || ++rx_q->rx_count_frames < frames) + return false; + + rx_q->rx_count_frames = 0; + return true; +} + /** * stmmac_rx_refill - refill used skb preallocated buffers * @priv: driver private structure @@ -5155,15 +5171,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) stmmac_rx_check_buf2_cap(priv)); stmmac_refill_desc3(priv, rx_q, p); - rx_q->rx_count_frames++; - rx_q->rx_count_frames += priv->rx_coal_frames[queue]; - if (rx_q->rx_count_frames > priv->rx_coal_frames[queue]) - rx_q->rx_count_frames = 0; - - use_rx_wd = !priv->rx_coal_frames[queue]; - use_rx_wd |= rx_q->rx_count_frames > 0; - if (!priv->use_riwt) - use_rx_wd = false; + use_rx_wd = !stmmac_rx_need_ic(priv, rx_q, queue); dma_wmb(); stmmac_set_rx_owner(priv, p, use_rx_wd); @@ -5573,15 +5581,7 @@ static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget) stmmac_set_desc_sec_addr(priv, rx_desc, 0, false); stmmac_refill_desc3(priv, rx_q, rx_desc); - rx_q->rx_count_frames++; - rx_q->rx_count_frames += priv->rx_coal_frames[queue]; - if (rx_q->rx_count_frames > priv->rx_coal_frames[queue]) - rx_q->rx_count_frames = 0; - - use_rx_wd = !priv->rx_coal_frames[queue]; - use_rx_wd |= rx_q->rx_count_frames > 0; - if (!priv->use_riwt) - use_rx_wd = false; + use_rx_wd = !stmmac_rx_need_ic(priv, rx_q, queue); dma_wmb(); stmmac_set_rx_owner(priv, rx_desc, use_rx_wd);