mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 06:17:27 +02:00
net: ethernet: cortina: Count RX drops once per frame
The absence of a partial skb means either that the driver is not
assembling a frame or that the current frame was already dropped.
Consequently, repeated descriptor errors can increment rx_dropped more
than once, while an orphaned descriptor chain can reach EOF without being
counted at all.
Track the dropping state across NAPI polls. Clear it at frame boundaries
and route mapping failures and orphaned continuations through the common
drop path so each discarded frame is counted exactly once.
Fixes: 4d5ae32f5e ("net: ethernet: Add a driver for Gemini gigabit ethernet")
Reported-by: Joe Damato <joe@dama.to>
Closes: https://lore.kernel.org/netdev/apdK5aMmvYssz35F@devvm20253.cco0.facebook.com/
Assisted-by: LLM
Signed-off-by: Linus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260903-gemini-ethernet-fixes-v2-4-2bbbd598ca6e@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
b856c552f5
commit
6520198c43
|
|
@ -124,6 +124,7 @@ struct gemini_ethernet_port {
|
|||
unsigned int rx_coalesce_nsecs;
|
||||
struct sk_buff *rx_skb;
|
||||
unsigned int rx_frag_nr;
|
||||
bool rx_dropping;
|
||||
|
||||
unsigned int freeq_refill;
|
||||
struct gmac_txq txq[TX_QUEUE_NUM];
|
||||
|
|
@ -1451,6 +1452,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
struct gmac_rxdesc *rx = NULL;
|
||||
struct gmac_queue_page *gpage;
|
||||
unsigned int received = 0;
|
||||
bool dropping = port->rx_dropping;
|
||||
union gmac_rxdesc_0 word0;
|
||||
union gmac_rxdesc_1 word1;
|
||||
union gmac_rxdesc_3 word3;
|
||||
|
|
@ -1472,6 +1474,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
w = rw.bits.wptr;
|
||||
|
||||
while (budget && w != r) {
|
||||
page = NULL;
|
||||
rx = port->rxq_ring + r;
|
||||
word0 = rx->word0;
|
||||
word1 = rx->word1;
|
||||
|
|
@ -1485,6 +1488,16 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
frame_len = word1.bits.byte_count;
|
||||
page_offs = mapping & ~PAGE_MASK;
|
||||
|
||||
if (word3.bits32 & SOF_BIT) {
|
||||
if (skb) {
|
||||
napi_free_frags(&port->napi);
|
||||
port->stats.rx_dropped++;
|
||||
skb = NULL;
|
||||
frag_nr = 0;
|
||||
}
|
||||
dropping = false;
|
||||
}
|
||||
|
||||
if (!mapping) {
|
||||
netdev_err(netdev,
|
||||
"rxq[%u]: HW BUG: zero DMA desc\n", r);
|
||||
|
|
@ -1495,24 +1508,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
gpage = gmac_get_queue_page(geth, port, mapping + PAGE_SIZE);
|
||||
if (!gpage) {
|
||||
dev_err(geth->dev, "could not find mapping\n");
|
||||
port->stats.rx_dropped++;
|
||||
if (skb) {
|
||||
napi_free_frags(&port->napi);
|
||||
skb = NULL;
|
||||
frag_nr = 0;
|
||||
}
|
||||
goto next_desc;
|
||||
goto err_drop;
|
||||
}
|
||||
page = gpage->page;
|
||||
|
||||
if (word3.bits32 & SOF_BIT) {
|
||||
if (skb) {
|
||||
napi_free_frags(&port->napi);
|
||||
port->stats.rx_dropped++;
|
||||
skb = NULL;
|
||||
frag_nr = 0;
|
||||
}
|
||||
|
||||
skb = gmac_skb_if_good_frame(port, word0, frame_len);
|
||||
if (!skb)
|
||||
goto err_drop;
|
||||
|
|
@ -1522,8 +1522,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
frag_nr = 0;
|
||||
|
||||
} else if (!skb) {
|
||||
put_page(page);
|
||||
goto next_desc;
|
||||
goto err_drop;
|
||||
}
|
||||
|
||||
if (word3.bits32 & EOF_BIT)
|
||||
|
|
@ -1556,21 +1555,26 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
frag_nr = 0;
|
||||
}
|
||||
|
||||
if (mapping)
|
||||
if (page)
|
||||
put_page(page);
|
||||
|
||||
port->stats.rx_dropped++;
|
||||
if (!dropping) {
|
||||
port->stats.rx_dropped++;
|
||||
dropping = true;
|
||||
}
|
||||
|
||||
next_desc:
|
||||
/* Final or single-descriptor fragment, advance things */
|
||||
if (word3.bits32 & EOF_BIT) {
|
||||
budget--;
|
||||
received++;
|
||||
dropping = false;
|
||||
}
|
||||
}
|
||||
|
||||
port->rx_skb = skb;
|
||||
port->rx_frag_nr = frag_nr;
|
||||
port->rx_dropping = dropping;
|
||||
writew(r, ptr_reg);
|
||||
return received;
|
||||
}
|
||||
|
|
@ -1900,6 +1904,7 @@ static int gmac_stop(struct net_device *netdev)
|
|||
napi_disable(&port->napi);
|
||||
port->rx_skb = NULL;
|
||||
port->rx_frag_nr = 0;
|
||||
port->rx_dropping = false;
|
||||
|
||||
gmac_enable_irq(netdev, 0);
|
||||
gmac_cleanup_rxq(netdev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user