Skip to content

Commit e61fb4b

Browse files
AkshGarg-19gregkh
authored andcommitted
net: ethernet: ti: am65-cpts: fix timestamp loss due to race conditions
[ Upstream commit 49d34f3 ] Resolve race conditions in timestamp events list handling between TX and RX paths causing missed timestamps. The current implementation uses a single events list for both TX and RX timestamps. The am65_cpts_find_ts() function acquires the lock, splices all events (TX as well as RX events) to a temporary list, and releases the lock. This function performs matching of timestamps for TX packets only. Before it acquires the lock again to put the non-TX events back to the main events list, a concurrent RX processing thread could acquire the lock (as observed in practice), find an empty events list, and fail to attach timestamp to it, even though a relevant event exists in the spliced list which is yet to be restored to the main list. Fix this by creating separate events lists to handle TX and RX timestamps independently. Fixes: c459f60 ("net: ethernet: ti: am65-cpts: Enable RX HW timestamp for PTP packets using CPTS FIFO") Signed-off-by: Aksh Garg <a-garg7@ti.com> Reviewed-by: Siddharth Vadapalli <s-vadapalli@ti.com> Link: https://patch.msgid.link/20251016115755.1123646-1-a-garg7@ti.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 5b6fc95 commit e61fb4b

File tree

1 file changed

+43
-20
lines changed

1 file changed

+43
-20
lines changed

drivers/net/ethernet/ti/am65-cpts.c

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ struct am65_cpts {
163163
struct device_node *clk_mux_np;
164164
struct clk *refclk;
165165
u32 refclk_freq;
166-
struct list_head events;
166+
/* separate lists to handle TX and RX timestamp independently */
167+
struct list_head events_tx;
168+
struct list_head events_rx;
167169
struct list_head pool;
168170
struct am65_cpts_event pool_data[AM65_CPTS_MAX_EVENTS];
169171
spinlock_t lock; /* protects events lists*/
@@ -227,6 +229,24 @@ static void am65_cpts_disable(struct am65_cpts *cpts)
227229
am65_cpts_write32(cpts, 0, int_enable);
228230
}
229231

232+
static int am65_cpts_purge_event_list(struct am65_cpts *cpts,
233+
struct list_head *events)
234+
{
235+
struct list_head *this, *next;
236+
struct am65_cpts_event *event;
237+
int removed = 0;
238+
239+
list_for_each_safe(this, next, events) {
240+
event = list_entry(this, struct am65_cpts_event, list);
241+
if (time_after(jiffies, event->tmo)) {
242+
list_del_init(&event->list);
243+
list_add(&event->list, &cpts->pool);
244+
++removed;
245+
}
246+
}
247+
return removed;
248+
}
249+
230250
static int am65_cpts_event_get_port(struct am65_cpts_event *event)
231251
{
232252
return (event->event1 & AM65_CPTS_EVENT_1_PORT_NUMBER_MASK) >>
@@ -239,20 +259,12 @@ static int am65_cpts_event_get_type(struct am65_cpts_event *event)
239259
AM65_CPTS_EVENT_1_EVENT_TYPE_SHIFT;
240260
}
241261

242-
static int am65_cpts_cpts_purge_events(struct am65_cpts *cpts)
262+
static int am65_cpts_purge_events(struct am65_cpts *cpts)
243263
{
244-
struct list_head *this, *next;
245-
struct am65_cpts_event *event;
246264
int removed = 0;
247265

248-
list_for_each_safe(this, next, &cpts->events) {
249-
event = list_entry(this, struct am65_cpts_event, list);
250-
if (time_after(jiffies, event->tmo)) {
251-
list_del_init(&event->list);
252-
list_add(&event->list, &cpts->pool);
253-
++removed;
254-
}
255-
}
266+
removed += am65_cpts_purge_event_list(cpts, &cpts->events_tx);
267+
removed += am65_cpts_purge_event_list(cpts, &cpts->events_rx);
256268

257269
if (removed)
258270
dev_dbg(cpts->dev, "event pool cleaned up %d\n", removed);
@@ -287,7 +299,7 @@ static int __am65_cpts_fifo_read(struct am65_cpts *cpts)
287299
struct am65_cpts_event, list);
288300

289301
if (!event) {
290-
if (am65_cpts_cpts_purge_events(cpts)) {
302+
if (am65_cpts_purge_events(cpts)) {
291303
dev_err(cpts->dev, "cpts: event pool empty\n");
292304
ret = -1;
293305
goto out;
@@ -306,11 +318,21 @@ static int __am65_cpts_fifo_read(struct am65_cpts *cpts)
306318
cpts->timestamp);
307319
break;
308320
case AM65_CPTS_EV_RX:
321+
event->tmo = jiffies +
322+
msecs_to_jiffies(AM65_CPTS_EVENT_RX_TX_TIMEOUT);
323+
324+
list_move_tail(&event->list, &cpts->events_rx);
325+
326+
dev_dbg(cpts->dev,
327+
"AM65_CPTS_EV_RX e1:%08x e2:%08x t:%lld\n",
328+
event->event1, event->event2,
329+
event->timestamp);
330+
break;
309331
case AM65_CPTS_EV_TX:
310332
event->tmo = jiffies +
311333
msecs_to_jiffies(AM65_CPTS_EVENT_RX_TX_TIMEOUT);
312334

313-
list_move_tail(&event->list, &cpts->events);
335+
list_move_tail(&event->list, &cpts->events_tx);
314336

315337
dev_dbg(cpts->dev,
316338
"AM65_CPTS_EV_TX e1:%08x e2:%08x t:%lld\n",
@@ -828,7 +850,7 @@ static bool am65_cpts_match_tx_ts(struct am65_cpts *cpts,
828850
return found;
829851
}
830852

831-
static void am65_cpts_find_ts(struct am65_cpts *cpts)
853+
static void am65_cpts_find_tx_ts(struct am65_cpts *cpts)
832854
{
833855
struct am65_cpts_event *event;
834856
struct list_head *this, *next;
@@ -837,7 +859,7 @@ static void am65_cpts_find_ts(struct am65_cpts *cpts)
837859
LIST_HEAD(events);
838860

839861
spin_lock_irqsave(&cpts->lock, flags);
840-
list_splice_init(&cpts->events, &events);
862+
list_splice_init(&cpts->events_tx, &events);
841863
spin_unlock_irqrestore(&cpts->lock, flags);
842864

843865
list_for_each_safe(this, next, &events) {
@@ -850,7 +872,7 @@ static void am65_cpts_find_ts(struct am65_cpts *cpts)
850872
}
851873

852874
spin_lock_irqsave(&cpts->lock, flags);
853-
list_splice_tail(&events, &cpts->events);
875+
list_splice_tail(&events, &cpts->events_tx);
854876
list_splice_tail(&events_free, &cpts->pool);
855877
spin_unlock_irqrestore(&cpts->lock, flags);
856878
}
@@ -861,7 +883,7 @@ static long am65_cpts_ts_work(struct ptp_clock_info *ptp)
861883
unsigned long flags;
862884
long delay = -1;
863885

864-
am65_cpts_find_ts(cpts);
886+
am65_cpts_find_tx_ts(cpts);
865887

866888
spin_lock_irqsave(&cpts->txq.lock, flags);
867889
if (!skb_queue_empty(&cpts->txq))
@@ -905,7 +927,7 @@ static u64 am65_cpts_find_rx_ts(struct am65_cpts *cpts, u32 skb_mtype_seqid)
905927

906928
spin_lock_irqsave(&cpts->lock, flags);
907929
__am65_cpts_fifo_read(cpts);
908-
list_for_each_safe(this, next, &cpts->events) {
930+
list_for_each_safe(this, next, &cpts->events_rx) {
909931
event = list_entry(this, struct am65_cpts_event, list);
910932
if (time_after(jiffies, event->tmo)) {
911933
list_move(&event->list, &cpts->pool);
@@ -1155,7 +1177,8 @@ struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs,
11551177
return ERR_PTR(ret);
11561178

11571179
mutex_init(&cpts->ptp_clk_lock);
1158-
INIT_LIST_HEAD(&cpts->events);
1180+
INIT_LIST_HEAD(&cpts->events_tx);
1181+
INIT_LIST_HEAD(&cpts->events_rx);
11591182
INIT_LIST_HEAD(&cpts->pool);
11601183
spin_lock_init(&cpts->lock);
11611184
skb_queue_head_init(&cpts->txq);

0 commit comments

Comments
 (0)