[PATCH net 2/2] net: stmmac: preserve FPE preemption class across qdisc replacement
From: Lorenzo Bianconi <hidden>
Date: 2026-08-29 08:29:39
Also in:
netdev
Subsystem:
networking drivers, stmmac ethernet driver, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Maxime Chevallier, Linus Torvalds
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 <redacted>
---
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