Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: ethernet: ti: am65-cpts: fix timestamp loss due to race conditions

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: c459f606f66df ("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>

authored by

Aksh Garg and committed by
Paolo Abeni
49d34f3d f584239a

+43 -20
+43 -20
drivers/net/ethernet/ti/am65-cpts.c
··· 163 163 struct device_node *clk_mux_np; 164 164 struct clk *refclk; 165 165 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; 167 169 struct list_head pool; 168 170 struct am65_cpts_event pool_data[AM65_CPTS_MAX_EVENTS]; 169 171 spinlock_t lock; /* protects events lists*/ ··· 229 227 am65_cpts_write32(cpts, 0, int_enable); 230 228 } 231 229 230 + static int am65_cpts_purge_event_list(struct am65_cpts *cpts, 231 + struct list_head *events) 232 + { 233 + struct list_head *this, *next; 234 + struct am65_cpts_event *event; 235 + int removed = 0; 236 + 237 + list_for_each_safe(this, next, events) { 238 + event = list_entry(this, struct am65_cpts_event, list); 239 + if (time_after(jiffies, event->tmo)) { 240 + list_del_init(&event->list); 241 + list_add(&event->list, &cpts->pool); 242 + ++removed; 243 + } 244 + } 245 + return removed; 246 + } 247 + 232 248 static int am65_cpts_event_get_port(struct am65_cpts_event *event) 233 249 { 234 250 return (event->event1 & AM65_CPTS_EVENT_1_PORT_NUMBER_MASK) >> ··· 259 239 AM65_CPTS_EVENT_1_EVENT_TYPE_SHIFT; 260 240 } 261 241 262 - static int am65_cpts_cpts_purge_events(struct am65_cpts *cpts) 242 + static int am65_cpts_purge_events(struct am65_cpts *cpts) 263 243 { 264 - struct list_head *this, *next; 265 - struct am65_cpts_event *event; 266 244 int removed = 0; 267 245 268 - list_for_each_safe(this, next, &cpts->events) { 269 - event = list_entry(this, struct am65_cpts_event, list); 270 - if (time_after(jiffies, event->tmo)) { 271 - list_del_init(&event->list); 272 - list_add(&event->list, &cpts->pool); 273 - ++removed; 274 - } 275 - } 246 + removed += am65_cpts_purge_event_list(cpts, &cpts->events_tx); 247 + removed += am65_cpts_purge_event_list(cpts, &cpts->events_rx); 276 248 277 249 if (removed) 278 250 dev_dbg(cpts->dev, "event pool cleaned up %d\n", removed); ··· 299 287 struct am65_cpts_event, list); 300 288 301 289 if (!event) { 302 - if (am65_cpts_cpts_purge_events(cpts)) { 290 + if (am65_cpts_purge_events(cpts)) { 303 291 dev_err(cpts->dev, "cpts: event pool empty\n"); 304 292 ret = -1; 305 293 goto out; ··· 318 306 cpts->timestamp); 319 307 break; 320 308 case AM65_CPTS_EV_RX: 309 + event->tmo = jiffies + 310 + msecs_to_jiffies(AM65_CPTS_EVENT_RX_TX_TIMEOUT); 311 + 312 + list_move_tail(&event->list, &cpts->events_rx); 313 + 314 + dev_dbg(cpts->dev, 315 + "AM65_CPTS_EV_RX e1:%08x e2:%08x t:%lld\n", 316 + event->event1, event->event2, 317 + event->timestamp); 318 + break; 321 319 case AM65_CPTS_EV_TX: 322 320 event->tmo = jiffies + 323 321 msecs_to_jiffies(AM65_CPTS_EVENT_RX_TX_TIMEOUT); 324 322 325 - list_move_tail(&event->list, &cpts->events); 323 + list_move_tail(&event->list, &cpts->events_tx); 326 324 327 325 dev_dbg(cpts->dev, 328 326 "AM65_CPTS_EV_TX e1:%08x e2:%08x t:%lld\n", ··· 850 828 return found; 851 829 } 852 830 853 - static void am65_cpts_find_ts(struct am65_cpts *cpts) 831 + static void am65_cpts_find_tx_ts(struct am65_cpts *cpts) 854 832 { 855 833 struct am65_cpts_event *event; 856 834 struct list_head *this, *next; ··· 859 837 LIST_HEAD(events); 860 838 861 839 spin_lock_irqsave(&cpts->lock, flags); 862 - list_splice_init(&cpts->events, &events); 840 + list_splice_init(&cpts->events_tx, &events); 863 841 spin_unlock_irqrestore(&cpts->lock, flags); 864 842 865 843 list_for_each_safe(this, next, &events) { ··· 872 850 } 873 851 874 852 spin_lock_irqsave(&cpts->lock, flags); 875 - list_splice_tail(&events, &cpts->events); 853 + list_splice_tail(&events, &cpts->events_tx); 876 854 list_splice_tail(&events_free, &cpts->pool); 877 855 spin_unlock_irqrestore(&cpts->lock, flags); 878 856 } ··· 883 861 unsigned long flags; 884 862 long delay = -1; 885 863 886 - am65_cpts_find_ts(cpts); 864 + am65_cpts_find_tx_ts(cpts); 887 865 888 866 spin_lock_irqsave(&cpts->txq.lock, flags); 889 867 if (!skb_queue_empty(&cpts->txq)) ··· 927 905 928 906 spin_lock_irqsave(&cpts->lock, flags); 929 907 __am65_cpts_fifo_read(cpts); 930 - list_for_each_safe(this, next, &cpts->events) { 908 + list_for_each_safe(this, next, &cpts->events_rx) { 931 909 event = list_entry(this, struct am65_cpts_event, list); 932 910 if (time_after(jiffies, event->tmo)) { 933 911 list_move(&event->list, &cpts->pool); ··· 1177 1155 return ERR_PTR(ret); 1178 1156 1179 1157 mutex_init(&cpts->ptp_clk_lock); 1180 - INIT_LIST_HEAD(&cpts->events); 1158 + INIT_LIST_HEAD(&cpts->events_tx); 1159 + INIT_LIST_HEAD(&cpts->events_rx); 1181 1160 INIT_LIST_HEAD(&cpts->pool); 1182 1161 spin_lock_init(&cpts->lock); 1183 1162 skb_queue_head_init(&cpts->txq);