mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 01:53:29 +02:00
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>
This commit is contained in:
commit
8383522821
|
|
@ -551,7 +551,28 @@ static int ocelot_port_stop(struct net_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
static bool ocelot_xmit_timestamp(struct ocelot *ocelot, int port,
|
||||
struct sk_buff *skb, u32 *rew_op)
|
||||
{
|
||||
if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
|
||||
struct sk_buff *clone = NULL;
|
||||
|
||||
if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) {
|
||||
kfree_skb(skb);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (clone)
|
||||
OCELOT_SKB_CB(skb)->clone = clone;
|
||||
|
||||
*rew_op = ocelot_ptp_rew_op(skb);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static netdev_tx_t ocelot_port_xmit_fdma(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct ocelot_port_private *priv = netdev_priv(dev);
|
||||
struct ocelot_port *ocelot_port = &priv->port;
|
||||
|
|
@ -559,36 +580,52 @@ static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
int port = priv->port.index;
|
||||
u32 rew_op = 0;
|
||||
|
||||
if (!static_branch_unlikely(&ocelot_fdma_enabled) &&
|
||||
!ocelot_can_inject(ocelot, 0))
|
||||
return NETDEV_TX_BUSY;
|
||||
if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op))
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
/* Check if timestamping is needed */
|
||||
if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
|
||||
struct sk_buff *clone = NULL;
|
||||
|
||||
if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) {
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
if (clone)
|
||||
OCELOT_SKB_CB(skb)->clone = clone;
|
||||
|
||||
rew_op = ocelot_ptp_rew_op(skb);
|
||||
}
|
||||
|
||||
if (static_branch_unlikely(&ocelot_fdma_enabled)) {
|
||||
ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev);
|
||||
} else {
|
||||
ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
|
||||
|
||||
consume_skb(skb);
|
||||
}
|
||||
ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static netdev_tx_t ocelot_port_xmit_inj(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct ocelot_port_private *priv = netdev_priv(dev);
|
||||
struct ocelot_port *ocelot_port = &priv->port;
|
||||
struct ocelot *ocelot = ocelot_port->ocelot;
|
||||
int port = priv->port.index;
|
||||
u32 rew_op = 0;
|
||||
|
||||
ocelot_lock_inj_grp(ocelot, 0);
|
||||
|
||||
if (!ocelot_can_inject(ocelot, 0)) {
|
||||
ocelot_unlock_inj_grp(ocelot, 0);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op)) {
|
||||
ocelot_unlock_inj_grp(ocelot, 0);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
|
||||
|
||||
ocelot_unlock_inj_grp(ocelot, 0);
|
||||
|
||||
consume_skb(skb);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
if (static_branch_unlikely(&ocelot_fdma_enabled))
|
||||
return ocelot_port_xmit_fdma(skb, dev);
|
||||
|
||||
return ocelot_port_xmit_inj(skb, dev);
|
||||
}
|
||||
|
||||
enum ocelot_action_type {
|
||||
OCELOT_MACT_LEARN,
|
||||
OCELOT_MACT_FORGET,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user