[PATCH net 2/2] net: stmmac: preserve FPE preemption class across qdisc replacement

Lorenzo Bianconi lorenzo.bianconi at oss.qualcomm.com
Sat Aug 29 01:28:50 PDT 2026


The kernel replaces a root qdisc by creating the new qdisc first and
destroying the old one only afterwards (qdisc_create() then
qdisc_graft() -> notify_and_destroy()). For a cross-kind replace this
means the teardown of the old qdisc runs after the offload of the new
one.

This breaks the FPE preemption-class mapping when replacing between
qdiscs that both program it. For example replacing taprio with mqprio:

  1. the mqprio offload (REPLACE) programs FPE_MTL_PREEMPTION_CLASS
     with mqprio->preemptible_tcs
  2. the old taprio is then torn down; tc_taprio_configure() runs the
     TAPRIO_CMD_DESTROY path and resets the preemption class to 0

Track which root qdisc policy is currently offloaded in a new
priv->qdisc_type field and only clear the FPE preemption class during
teardown if the qdisc being destroyed actually owns it.

Fixes: 15d8a407a547 ("net: stmmac: support fp parameter of tc-taprio")
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi at oss.qualcomm.com>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac.h    |  7 +++++++
 drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 22 ++++++++++++++++++----
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 7582fca63741..957317ec1461 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -258,6 +258,12 @@ struct stmmac_msi {
 	char int_name_tx_irq[MTL_MAX_TX_QUEUES][IFNAMSIZ + 18];
 };
 
+enum stmmac_qdisc_type {
+	STMMAC_QDISC_NONE = 0,
+	STMMAC_QDISC_MQPRIO,
+	STMMAC_QDISC_TAPRIO,
+};
+
 struct stmmac_priv {
 	/* Frequently used values are kept adjacent for cache effect */
 	u32 tx_coal_frames[MTL_MAX_TX_QUEUES];
@@ -299,6 +305,7 @@ struct stmmac_priv {
 	/* Protect est parameters */
 	struct mutex est_lock;
 	struct stmmac_est *est;
+	enum stmmac_qdisc_type qdisc_type;
 	struct dma_features dma_cap;
 	struct stmmac_counters mmc;
 	int hw_cap_support;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index be8ddda2aa76..7fe587b47d52 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -1103,6 +1103,8 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
 	if (ret)
 		goto disable;
 
+	priv->qdisc_type = STMMAC_QDISC_TAPRIO;
+
 	return 0;
 
 disable:
@@ -1120,7 +1122,11 @@ static int tc_taprio_configure(struct stmmac_priv *priv,
 		mutex_unlock(&priv->est_lock);
 	}
 
-	stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0);
+	if (priv->qdisc_type == STMMAC_QDISC_TAPRIO &&
+	    qopt->cmd == TAPRIO_CMD_DESTROY) {
+		stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0);
+		priv->qdisc_type = STMMAC_QDISC_NONE;
+	}
 
 	return ret;
 }
@@ -1266,9 +1272,15 @@ static void stmmac_reset_tc_mqprio(struct net_device *ndev,
 {
 	struct stmmac_priv *priv = netdev_priv(ndev);
 
-	netdev_reset_tc(ndev);
-	netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use);
-	stmmac_fpe_map_preemption_class(priv, ndev, extack, 0);
+	if (priv->qdisc_type != STMMAC_QDISC_TAPRIO)
+		stmmac_fpe_map_preemption_class(priv, ndev, extack, 0);
+
+	if (priv->qdisc_type == STMMAC_QDISC_MQPRIO) {
+		netdev_reset_tc(ndev);
+		netif_set_real_num_tx_queues(ndev,
+					     priv->plat->tx_queues_to_use);
+		priv->qdisc_type = STMMAC_QDISC_NONE;
+	}
 }
 
 static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
@@ -1318,6 +1330,8 @@ static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
 	if (err)
 		goto error_reset_num_tx_queues;
 
+	priv->qdisc_type = STMMAC_QDISC_MQPRIO;
+
 	return 0;
 
 error_reset_num_tx_queues:

-- 
2.55.0




More information about the linux-arm-kernel mailing list