From 074caa30a62726c0ee959e8b8ccb64cda0b26ae5 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Mon, 26 Oct 2026 14:46:54 +0100 Subject: [PATCH] net: lan966x: release the in-flight slot of a stale TX skb lan966x_ptp_txtstamp_request() counts every two step TX skb waiting for its timestamp in lan966x->ptp_skbs, and refuses new ones once LAN966X_MAX_PTP_ID are in flight. lan966x_ptp_txtstamp_old_release() frees the skbs that have waited longer than LAN966X_PTP_TIMEOUT. Before this patch, old_release() does not decrement ptp_skbs, so every skb whose timestamp never arrives, for example because the switch discarded the frame, keeps its slot forever. Once LAN966X_MAX_PTP_ID slots are lost, two step frames fail to transmit on every port of the switch. Return the number of released skbs from old_release() and subtract it from ptp_skbs in txtstamp_request(), under the ptp_ts_id_lock it already takes. This fixes the accounting only. A port's stale skbs are still aged out only when that port sends a two step frame, so a port that stops sending them keeps its stale skbs, and their slots, until it sends one again. That behaviour is unchanged by this patch. Found by an AI code review agent. Reproduced on a lan9668 board. Fixes: 77eecf25bd9d ("net: lan966x: Update extraction/injection for timestamping") Signed-off-by: Daniel Machon Link: https://patch.msgid.link/20261026-lan966x-ptp-stale-tx-slot-v1-1-9f7c895eb1ff@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c index 8c40db90ee8f..9be2cfe6feeb 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_ptp.c @@ -376,9 +376,10 @@ static void lan966x_ptp_classify(struct lan966x_port *port, struct sk_buff *skb, *rew_op = IFH_REW_OP_TWO_STEP_PTP; } -static void lan966x_ptp_txtstamp_old_release(struct lan966x_port *port) +static unsigned int lan966x_ptp_txtstamp_old_release(struct lan966x_port *port) { struct sk_buff *skb, *skb_tmp; + unsigned int purged = 0; unsigned long flags; spin_lock_irqsave(&port->tx_skbs.lock, flags); @@ -389,14 +390,18 @@ static void lan966x_ptp_txtstamp_old_release(struct lan966x_port *port) __skb_unlink(skb, &port->tx_skbs); dev_kfree_skb_any(skb); + purged++; } spin_unlock_irqrestore(&port->tx_skbs.lock, flags); + + return purged; } int lan966x_ptp_txtstamp_request(struct lan966x_port *port, struct sk_buff *skb) { struct lan966x *lan966x = port->lan966x; + unsigned int purged; unsigned long flags; u8 pdu_type; u8 rew_op; @@ -408,9 +413,10 @@ int lan966x_ptp_txtstamp_request(struct lan966x_port *port, if (rew_op != IFH_REW_OP_TWO_STEP_PTP) return 0; - lan966x_ptp_txtstamp_old_release(port); + purged = lan966x_ptp_txtstamp_old_release(port); spin_lock_irqsave(&lan966x->ptp_ts_id_lock, flags); + lan966x->ptp_skbs -= purged; if (lan966x->ptp_skbs == LAN966X_MAX_PTP_ID) { spin_unlock_irqrestore(&lan966x->ptp_ts_id_lock, flags); return -EBUSY;