From 873363ac591a1774aa3ced84f7ea3d93a3eb9b07 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Thu, 29 Oct 2026 12:48:10 +0100 Subject: [PATCH] net: sparx5/lan969x: release the in-flight slot of a stale TX skb sparx5_ptp_txtstamp_request() counts every two step TX skb waiting for its timestamp in sparx5->ptp_skbs, and refuses new ones once SPARX5_MAX_PTP_ID are in flight. sparx5_ptp_txtstamp_old_release() frees the skbs that have waited longer than SPARX5_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 SPARX5_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 lan9696 board with a modified kernel that drops the TX timestamps of two step frames, after which two step timestamping stopped working on the port. With the fix, timestamping keeps working on that board and on a sparx5 PCB135 board. Fixes: 70dfe25cd866 ("net: sparx5: Update extraction/injection for timestamping") Signed-off-by: Daniel Machon Reviewed-by: Simon Horman Link: https://patch.msgid.link/20261029-sparx5-ptp-stale-tx-slot-v1-1-ec15f391bbb7@microchip.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c index 2826e48af103..9f61692b243b 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c @@ -204,9 +204,10 @@ static void sparx5_ptp_classify(struct sparx5_port *port, struct sk_buff *skb, *rew_op = IFH_REW_OP_TWO_STEP_PTP; } -static void sparx5_ptp_txtstamp_old_release(struct sparx5_port *port) +static unsigned int sparx5_ptp_txtstamp_old_release(struct sparx5_port *port) { struct sk_buff *skb, *skb_tmp; + unsigned int purged = 0; unsigned long flags; spin_lock_irqsave(&port->tx_skbs.lock, flags); @@ -217,8 +218,11 @@ static void sparx5_ptp_txtstamp_old_release(struct sparx5_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 sparx5_ptp_txtstamp_request(struct sparx5_port *port, @@ -226,6 +230,7 @@ int sparx5_ptp_txtstamp_request(struct sparx5_port *port, { struct sparx5 *sparx5 = port->sparx5; u8 rew_op, pdu_type, pdu_w16_offset; + unsigned int purged; unsigned long flags; sparx5_ptp_classify(port, skb, &rew_op, &pdu_type, &pdu_w16_offset); @@ -236,9 +241,10 @@ int sparx5_ptp_txtstamp_request(struct sparx5_port *port, if (rew_op != IFH_REW_OP_TWO_STEP_PTP) return 0; - sparx5_ptp_txtstamp_old_release(port); + purged = sparx5_ptp_txtstamp_old_release(port); spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags); + sparx5->ptp_skbs -= purged; if (sparx5->ptp_skbs == SPARX5_MAX_PTP_ID) { spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags); return -EBUSY;