Commit 83835228 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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: default avatarJakub Kicinski <kuba@kernel.org>
parents 6c28aa8d 026f6513
Loading
Loading
Loading
Loading
+56 −19
Original line number Diff line number Diff line
@@ -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;
	ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev);

		if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) {
			kfree_skb(skb);
	return NETDEV_TX_OK;
}

		if (clone)
			OCELOT_SKB_CB(skb)->clone = clone;
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);

		rew_op = ocelot_ptp_rew_op(skb);
	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;
	}

	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);

	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,