mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 20:53:03 +02:00
Merge branch 'net-ethernet-cortina-fix-rx-budget-accounting'
Linus Walleij says: ==================== net: ethernet: cortina: Fix RX budget accounting Finish RX updates before releasing NAPI ownership, report actual NAPI work, charge dropped frames to the poll budget, and drive free-queue refills from consumed RX descriptors. Track RX drop state across descriptor chains so discarded frames are counted exactly once. Tested on the D-Link DIR-685. Hi Sashiko, yes there are more latent issues I will get to them, but my LLM thinks those are on the top of the list. Assisted-by: LLM Signed-off-by: Linus Walleij <linusw@kernel.org> ==================== Link: https://patch.msgid.link/20260903-gemini-ethernet-fixes-v2-0-2bbbd598ca6e@kernel.org Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
e0554c6276
|
|
@ -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];
|
||||
|
|
@ -1439,7 +1440,8 @@ static struct sk_buff *gmac_skb_if_good_frame(struct gemini_ethernet_port *port,
|
|||
return skb;
|
||||
}
|
||||
|
||||
static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
||||
static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget,
|
||||
unsigned int *freeq_consumed)
|
||||
{
|
||||
struct gemini_ethernet_port *port = netdev_priv(netdev);
|
||||
unsigned short m = (1 << port->rxq_order) - 1;
|
||||
|
|
@ -1447,9 +1449,12 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
void __iomem *ptr_reg = port->rxq_rwptr;
|
||||
unsigned int frag_nr = port->rx_frag_nr;
|
||||
struct sk_buff *skb = port->rx_skb;
|
||||
unsigned int consumed = 0;
|
||||
unsigned int frame_len, frag_len;
|
||||
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;
|
||||
|
|
@ -1471,6 +1476,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;
|
||||
|
|
@ -1479,11 +1485,22 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
|
||||
r++;
|
||||
r &= m;
|
||||
consumed++;
|
||||
|
||||
frag_len = word0.bits.buffer_size;
|
||||
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);
|
||||
|
|
@ -1494,24 +1511,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;
|
||||
}
|
||||
continue;
|
||||
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;
|
||||
|
|
@ -1521,8 +1525,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
frag_nr = 0;
|
||||
|
||||
} else if (!skb) {
|
||||
put_page(page);
|
||||
continue;
|
||||
goto err_drop;
|
||||
}
|
||||
|
||||
if (word3.bits32 & EOF_BIT)
|
||||
|
|
@ -1545,9 +1548,8 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)
|
|||
napi_gro_frags(&port->napi);
|
||||
skb = NULL;
|
||||
frag_nr = 0;
|
||||
--budget;
|
||||
}
|
||||
continue;
|
||||
goto next_desc;
|
||||
|
||||
err_drop:
|
||||
if (skb) {
|
||||
|
|
@ -1556,16 +1558,29 @@ 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;
|
||||
*freeq_consumed = consumed;
|
||||
writew(r, ptr_reg);
|
||||
return budget;
|
||||
return received;
|
||||
}
|
||||
|
||||
static int gmac_napi_poll(struct napi_struct *napi, int budget)
|
||||
|
|
@ -1573,26 +1588,27 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)
|
|||
struct gemini_ethernet_port *port = netdev_priv(napi->dev);
|
||||
struct gemini_ethernet *geth = port->geth;
|
||||
unsigned int freeq_threshold;
|
||||
unsigned int freeq_consumed;
|
||||
unsigned int received;
|
||||
|
||||
freeq_threshold = 1 << (geth->freeq_order - 1);
|
||||
u64_stats_update_begin(&port->rx_stats_syncp);
|
||||
|
||||
received = gmac_rx(napi->dev, budget);
|
||||
if (received < budget) {
|
||||
napi_gro_flush(napi, false);
|
||||
napi_complete_done(napi, received);
|
||||
gmac_enable_rx_irq(napi->dev, 1);
|
||||
received = gmac_rx(napi->dev, budget, &freeq_consumed);
|
||||
if (received < budget)
|
||||
++port->rx_napi_exits;
|
||||
}
|
||||
|
||||
port->freeq_refill += (budget - received);
|
||||
u64_stats_update_end(&port->rx_stats_syncp);
|
||||
|
||||
port->freeq_refill += freeq_consumed;
|
||||
if (port->freeq_refill > freeq_threshold) {
|
||||
port->freeq_refill -= freeq_threshold;
|
||||
geth_fill_freeq(geth, true);
|
||||
}
|
||||
|
||||
u64_stats_update_end(&port->rx_stats_syncp);
|
||||
if (received < budget && napi_complete_done(napi, received))
|
||||
gmac_enable_rx_irq(napi->dev, 1);
|
||||
|
||||
return received;
|
||||
}
|
||||
|
||||
|
|
@ -1893,6 +1909,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