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.

Merge branch 'net-mscc-ocelot-fix-missing-lock-in-ocelot_port_xmit'

Ziyi Guo says:

====================
net: mscc: ocelot: fix missing lock in ocelot_port_xmit()

ocelot_port_xmit() calls ocelot_can_inject() and
ocelot_port_inject_frame() without holding the injection group lock.
Both functions contain lockdep_assert_held() for the injection lock,
and the correct caller felix_port_deferred_xmit() properly acquires
the lock using ocelot_lock_inj_grp() before calling these functions.

this v3 splits the fix into a 3-patch series to separate
refactoring from the behavioral change:

1/3: Extract the PTP timestamp handling into an ocelot_xmit_timestamp()
helper so the logic isn't duplicated when the function is split.

2/3: Split ocelot_port_xmit() into ocelot_port_xmit_fdma() and
ocelot_port_xmit_inj(), keeping the FDMA and register injection
code paths fully separate.

3/3: Add ocelot_lock_inj_grp()/ocelot_unlock_inj_grp() in
ocelot_port_xmit_inj() to fix the missing lock protection.

Patches 1-2 are pure refactors with no behavioral change.
Patch 3 is the actual bug fix.
====================

Link: https://patch.msgid.link/20260208225602.1339325-1-n7l8m4@u.northwestern.edu
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+63 -26
+63 -26
drivers/net/ethernet/mscc/ocelot_net.c
··· 551 551 return 0; 552 552 } 553 553 554 - static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) 554 + static bool ocelot_xmit_timestamp(struct ocelot *ocelot, int port, 555 + struct sk_buff *skb, u32 *rew_op) 556 + { 557 + if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { 558 + struct sk_buff *clone = NULL; 559 + 560 + if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) { 561 + kfree_skb(skb); 562 + return false; 563 + } 564 + 565 + if (clone) 566 + OCELOT_SKB_CB(skb)->clone = clone; 567 + 568 + *rew_op = ocelot_ptp_rew_op(skb); 569 + } 570 + 571 + return true; 572 + } 573 + 574 + static netdev_tx_t ocelot_port_xmit_fdma(struct sk_buff *skb, 575 + struct net_device *dev) 555 576 { 556 577 struct ocelot_port_private *priv = netdev_priv(dev); 557 578 struct ocelot_port *ocelot_port = &priv->port; ··· 580 559 int port = priv->port.index; 581 560 u32 rew_op = 0; 582 561 583 - if (!static_branch_unlikely(&ocelot_fdma_enabled) && 584 - !ocelot_can_inject(ocelot, 0)) 585 - return NETDEV_TX_BUSY; 562 + if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op)) 563 + return NETDEV_TX_OK; 586 564 587 - /* Check if timestamping is needed */ 588 - if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { 589 - struct sk_buff *clone = NULL; 590 - 591 - if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) { 592 - kfree_skb(skb); 593 - return NETDEV_TX_OK; 594 - } 595 - 596 - if (clone) 597 - OCELOT_SKB_CB(skb)->clone = clone; 598 - 599 - rew_op = ocelot_ptp_rew_op(skb); 600 - } 601 - 602 - if (static_branch_unlikely(&ocelot_fdma_enabled)) { 603 - ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev); 604 - } else { 605 - ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb); 606 - 607 - consume_skb(skb); 608 - } 565 + ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev); 609 566 610 567 return NETDEV_TX_OK; 568 + } 569 + 570 + static netdev_tx_t ocelot_port_xmit_inj(struct sk_buff *skb, 571 + struct net_device *dev) 572 + { 573 + struct ocelot_port_private *priv = netdev_priv(dev); 574 + struct ocelot_port *ocelot_port = &priv->port; 575 + struct ocelot *ocelot = ocelot_port->ocelot; 576 + int port = priv->port.index; 577 + u32 rew_op = 0; 578 + 579 + ocelot_lock_inj_grp(ocelot, 0); 580 + 581 + if (!ocelot_can_inject(ocelot, 0)) { 582 + ocelot_unlock_inj_grp(ocelot, 0); 583 + return NETDEV_TX_BUSY; 584 + } 585 + 586 + if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op)) { 587 + ocelot_unlock_inj_grp(ocelot, 0); 588 + return NETDEV_TX_OK; 589 + } 590 + 591 + ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb); 592 + 593 + ocelot_unlock_inj_grp(ocelot, 0); 594 + 595 + consume_skb(skb); 596 + 597 + return NETDEV_TX_OK; 598 + } 599 + 600 + static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) 601 + { 602 + if (static_branch_unlikely(&ocelot_fdma_enabled)) 603 + return ocelot_port_xmit_fdma(skb, dev); 604 + 605 + return ocelot_port_xmit_inj(skb, dev); 611 606 } 612 607 613 608 enum ocelot_action_type {