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 d429b66e2e ("net: stmmac: Implement RX Coalesce Frames
setting").

Since commit 6fa9d691b9 ("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: 6fa9d691b9 ("net: stmmac: Prevent divide-by-zero")
Signed-off-by: Pengfei Zhang <zhangfeionline@gmail.com>
Link: https://patch.msgid.link/20261009111138.320089-1-zhangfeionline@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Pengfei Zhang 2026-10-09 19:11:37 +08:00 committed by Jakub Kicinski
parent 7684c2c796
commit 0d20963e0a

View File

@ -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);