* [PATCH net-next v3 0/3] Implement mqprio and ets qdisc offload in stmmac driver
@ 2026-08-08 14:49 Lorenzo Bianconi
2026-08-08 14:49 ` [PATCH net-next v3 1/3] net: stmmac: add tc-ets qdisc offload Lorenzo Bianconi
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Lorenzo Bianconi @ 2026-08-08 14:49 UTC (permalink / raw)
To: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue
Cc: Daniel Thompson, Alex Elder, Davide Caratti, netdev, linux-stm32,
linux-arm-kernel, Lorenzo Bianconi
---
Changes in v3:
- Limit number of tx queues to ETS bands enabling ETS qdisc offload.
- Do not overwrite previosuly configured qdisc if ETS offloading fails.
- Check dcb DMA capability before programming the sched registers.
- Always power-on the device before applying qdisc offload configuration
- Fix priority applied for SP tx queues.
- Link to v2: https://lore.kernel.org/r/20260807-stmmac-ets-offload-v2-0-9ac67af92cb8@oss.qualcomm.com
Changes in v2:
- Implement strict priority policy in mqprio qdisc offload
- Restore to dt configured values destroying the qdisc
- Do not ets offload if there are any queues in avb mode.
- Re-apply ETS configuration closing/opening the net_device.
- Link to v1: https://lore.kernel.org/r/20260804-stmmac-ets-offload-v1-1-f3a09169d22b@oss.qualcomm.com
---
Lorenzo Bianconi (3):
net: stmmac: add tc-ets qdisc offload
net: stmmac: add tc-mqprio qdisc offload
net: stmmac: hold runtime PM reference in setup_tc
drivers/net/ethernet/stmicro/stmmac/hwif.h | 4 +
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 10 ++
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c | 20 ++-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 86 +++++++++---
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 159 +++++++++++++++++++++-
5 files changed, 251 insertions(+), 28 deletions(-)
---
base-commit: 8ac4255c1e0c83d2e1559a18b8918673116fc8d6
change-id: 20260804-stmmac-ets-offload-cc936c99fdb1
Best regards,
--
Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net-next v3 1/3] net: stmmac: add tc-ets qdisc offload
2026-08-08 14:49 [PATCH net-next v3 0/3] Implement mqprio and ets qdisc offload in stmmac driver Lorenzo Bianconi
@ 2026-08-08 14:49 ` Lorenzo Bianconi
2026-08-08 14:49 ` [PATCH net-next v3 2/3] net: stmmac: add tc-mqprio " Lorenzo Bianconi
2026-08-08 14:49 ` [PATCH net-next v3 3/3] net: stmmac: hold runtime PM reference in setup_tc Lorenzo Bianconi
2 siblings, 0 replies; 5+ messages in thread
From: Lorenzo Bianconi @ 2026-08-08 14:49 UTC (permalink / raw)
To: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue
Cc: Daniel Thompson, Alex Elder, Davide Caratti, netdev, linux-stm32,
linux-arm-kernel, Lorenzo Bianconi
Implement offload of the tc-ets qdisc in the stmmac driver. The number of
ETS bands cannot exceed the number of TX queues, and strict priority bands
(zero quanta) are rejected since sched prio is not implemented in the ETS
offload but will be implemented in the mqprio qdisc offload. Weighted
bands whose quantum is zero are rejected as well, since MTL DWRR would
never schedule traffic on them. Configurations with AVB queues, or on
cores without the DCB feature, are not offloaded either.
The requested quanta are applied to the TX queues and the MTL scheduler
is switched to DWRR. The number of active TX queues is restricted to the
band count so the stack never routes traffic onto queues left with a zero
quantum, which the MTL scheduler would never drain. The offload state is
cached in priv->qdisc and re-applied on device open (scheduler, queue
weights and queue count), so it survives a reopen or a reset.
TC_ETS_GRAFT is not offloaded and silently falls back to the software
implementation, while TC_ETS_STATS is accepted when the ETS qdisc is
offloaded, although no hardware statistics are provided. The DESTROY and
STATS paths act only on the ETS instance actually offloaded, so a
software-only child ETS or the old root qdisc of a replace cannot reset
the hardware configuration of a live offload.
The FPE preemption mapping is now validated against the effective
scheduling algorithm and weights (the DWRR quanta when ETS is offloaded)
rather than the DT configuration. Export stmmac_set_tx_queue_weight() so
the ETS path can reprogram queue weights, and have it skip AVB queues,
whose weight register is repurposed as the CBS idle slope. Wire
TC_SETUP_QDISC_ETS into stmmac_setup_tc(). Destroying the ETS qdisc
restores the devicetree configured scheduling algorithm and TX queue
weights.
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
drivers/net/ethernet/stmicro/stmmac/hwif.h | 4 +
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 8 ++
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c | 20 ++++-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 34 +++++--
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 104 ++++++++++++++++++++++
5 files changed, 159 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 04dafec021b4..b70883a53b09 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -580,6 +580,8 @@ struct stmmac_tc_ops {
struct tc_taprio_qopt_offload *qopt);
int (*setup_etf)(struct stmmac_priv *priv,
struct tc_etf_qopt_offload *qopt);
+ int (*setup_ets)(struct stmmac_priv *priv,
+ struct tc_ets_qopt_offload *qopt);
int (*query_caps)(struct stmmac_priv *priv,
struct tc_query_caps_base *base);
int (*setup_mqprio)(struct stmmac_priv *priv,
@@ -598,6 +600,8 @@ struct stmmac_tc_ops {
stmmac_do_callback(__priv, tc, setup_taprio, __args)
#define stmmac_tc_setup_etf(__priv, __args...) \
stmmac_do_callback(__priv, tc, setup_etf, __args)
+#define stmmac_tc_setup_ets(__priv, __args...) \
+ stmmac_do_callback(__priv, tc, setup_ets, __args)
#define stmmac_tc_query_caps(__priv, __args...) \
stmmac_do_callback(__priv, tc, query_caps, __args)
#define stmmac_tc_setup_mqprio(__priv, __args...) \
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 8ba8f03e1ce0..33c37f843336 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -301,6 +301,13 @@ struct stmmac_priv {
/* Protect est parameters */
struct mutex est_lock;
struct stmmac_est *est;
+ struct {
+ bool enable;
+ u8 algo;
+ u8 bands;
+ u32 handle;
+ u32 quanta[MTL_MAX_TX_QUEUES];
+ } qdisc;
struct dma_features dma_cap;
struct stmmac_counters mmc;
int hw_cap_support;
@@ -394,6 +401,7 @@ enum stmmac_state {
extern const struct dev_pm_ops stmmac_simple_pm_ops;
+void stmmac_set_tx_queue_weight(struct stmmac_priv *priv);
int stmmac_mdio_unregister(struct net_device *ndev);
int stmmac_mdio_register(struct net_device *ndev);
int stmmac_mdio_reset(struct mii_bus *mii);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
index c54c70224351..d84b6fdc01b3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
@@ -205,7 +205,10 @@ int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
{
u32 val, offset, count, queue_weight, preemptible_txqs = 0;
struct stmmac_priv *priv = netdev_priv(ndev);
+ struct plat_stmmacenet_data *pdata = priv->plat;
int num_tc = netdev_get_num_tc(ndev);
+ u32 sched_algo;
+ bool ets;
if (!pclass)
goto update_mapping;
@@ -216,6 +219,11 @@ int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
* "The number of Tx DMA channels is equal to the number of Tx queues,
* and is direct one-to-one mapping."
*/
+
+ sched_algo = priv->qdisc.enable ? priv->qdisc.algo
+ : pdata->tx_sched_algorithm;
+ ets = priv->qdisc.enable && sched_algo == MTL_TX_ALGORITHM_DWRR;
+
for (u32 tc = 0; tc < num_tc; tc++) {
count = ndev->tc_to_txq[tc].count;
offset = ndev->tc_to_txq[tc].offset;
@@ -227,16 +235,20 @@ int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
if (count == 1)
continue;
- if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) {
+ if (sched_algo == MTL_TX_ALGORITHM_SP) {
NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
return -EINVAL;
}
- queue_weight = priv->plat->tx_queues_cfg[offset].weight;
+ queue_weight = ets ? priv->qdisc.quanta[offset]
+ : pdata->tx_queues_cfg[offset].weight;
for (u32 i = 1; i < count; i++) {
- if (priv->plat->tx_queues_cfg[offset + i].weight !=
- queue_weight) {
+ u32 weight;
+
+ weight = ets ? priv->qdisc.quanta[offset + i]
+ : pdata->tx_queues_cfg[offset + i].weight;
+ if (weight != queue_weight) {
NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG,
queue_weight, tc);
return -EINVAL;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index b2b7d0242dd3..5acddc9cbd3f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3419,14 +3419,22 @@ static void stmmac_set_rings_length(struct stmmac_priv *priv)
* @priv: driver private structure
* Description: It is used for setting TX queues weight
*/
-static void stmmac_set_tx_queue_weight(struct stmmac_priv *priv)
+void stmmac_set_tx_queue_weight(struct stmmac_priv *priv)
{
- u8 tx_queues_count = priv->plat->tx_queues_to_use;
+ struct plat_stmmacenet_data *pdata = priv->plat;
+ u8 tx_queues_count = pdata->tx_queues_to_use;
u32 weight;
u8 queue;
for (queue = 0; queue < tx_queues_count; queue++) {
- weight = priv->plat->tx_queues_cfg[queue].weight;
+ if (pdata->tx_queues_cfg[queue].mode_to_use == MTL_QUEUE_AVB)
+ continue;
+
+ if (priv->qdisc.enable &&
+ priv->qdisc.algo == MTL_TX_ALGORITHM_DWRR)
+ weight = priv->qdisc.quanta[queue];
+ else
+ weight = pdata->tx_queues_cfg[queue].weight;
stmmac_set_mtl_tx_queue_weight(priv, priv->hw, weight, queue);
}
}
@@ -3570,9 +3578,15 @@ static void stmmac_mtl_configuration(struct stmmac_priv *priv)
priv->plat->rx_sched_algorithm);
/* Configure MTL TX algorithms */
- if (tx_queues_count > 1)
- stmmac_prog_mtl_tx_algorithms(priv, priv->hw,
- priv->plat->tx_sched_algorithm);
+ if (tx_queues_count > 1) {
+ u8 tx_sched_algo;
+
+ if (priv->qdisc.enable)
+ tx_sched_algo = priv->qdisc.algo;
+ else
+ tx_sched_algo = priv->plat->tx_sched_algorithm;
+ stmmac_prog_mtl_tx_algorithms(priv, priv->hw, tx_sched_algo);
+ }
/* Configure CBS in AVB TX queues */
if (tx_queues_count > 1)
@@ -3738,7 +3752,11 @@ static int stmmac_hw_setup(struct net_device *dev)
/* Configure real RX and TX queues */
netif_set_real_num_rx_queues(dev, priv->plat->rx_queues_to_use);
- netif_set_real_num_tx_queues(dev, priv->plat->tx_queues_to_use);
+ if (priv->qdisc.enable && priv->qdisc.algo == MTL_TX_ALGORITHM_DWRR)
+ netif_set_real_num_tx_queues(dev, priv->qdisc.bands);
+ else
+ netif_set_real_num_tx_queues(dev,
+ priv->plat->tx_queues_to_use);
/* Start the ball rolling... */
stmmac_start_all_dma(priv);
@@ -6437,6 +6455,8 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
return stmmac_tc_setup_taprio(priv, priv, type_data);
case TC_SETUP_QDISC_ETF:
return stmmac_tc_setup_etf(priv, priv, type_data);
+ case TC_SETUP_QDISC_ETS:
+ return stmmac_tc_setup_ets(priv, priv, type_data);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 14cabe76e53e..15949b5d9f32 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -1210,6 +1210,108 @@ static int tc_setup_etf(struct stmmac_priv *priv,
return 0;
}
+/* Max quantum value supported by the MTL DWRR scheduler */
+#define MTL_TXQ_WEIGHT_QUANTUM_MAX 0x1312d0
+
+static void stmmac_qdisc_restore_dt_config(struct stmmac_priv *priv)
+{
+ /* reset to the dt configured algorithm. */
+ priv->qdisc.enable = false;
+ netif_set_real_num_tx_queues(priv->dev, priv->plat->tx_queues_to_use);
+ stmmac_set_tx_queue_weight(priv);
+ stmmac_prog_mtl_tx_algorithms(priv, priv->hw,
+ priv->plat->tx_sched_algorithm);
+}
+
+static int tc_setup_ets_sched(struct stmmac_priv *priv,
+ struct tc_ets_qopt_offload *qopt)
+{
+ struct tc_ets_qopt_offload_replace_params *p = &qopt->replace_params;
+ struct plat_stmmacenet_data *pdata = priv->plat;
+ int err, i;
+
+ if (!priv->dma_cap.dcben)
+ return -EOPNOTSUPP;
+
+ if (qopt->parent != TC_H_ROOT)
+ return -EOPNOTSUPP;
+
+ if (p->bands > pdata->tx_queues_to_use)
+ return -EOPNOTSUPP;
+
+ for (i = 0; i < pdata->tx_queues_to_use; i++) {
+ if (pdata->tx_queues_cfg[i].mode_to_use == MTL_QUEUE_AVB)
+ return -EOPNOTSUPP;
+ }
+
+ for (i = 0; i < p->bands; i++) {
+ if (!p->quanta[i])
+ return -EOPNOTSUPP;
+
+ if (p->quanta[i] > MTL_TXQ_WEIGHT_QUANTUM_MAX)
+ return -EOPNOTSUPP;
+ }
+
+ err = netif_set_real_num_tx_queues(priv->dev, p->bands);
+ if (err)
+ return err;
+
+ for (i = 0; i < pdata->tx_queues_to_use; i++) {
+ u32 quantum = i < p->bands ? p->quanta[i] : 0;
+
+ priv->qdisc.quanta[i] = quantum;
+ stmmac_set_mtl_tx_queue_weight(priv, priv->hw, quantum, i);
+ }
+
+ stmmac_prog_mtl_tx_algorithms(priv, priv->hw, MTL_TX_ALGORITHM_DWRR);
+ priv->qdisc.algo = MTL_TX_ALGORITHM_DWRR;
+ priv->qdisc.handle = qopt->handle;
+ priv->qdisc.bands = p->bands;
+ priv->qdisc.enable = true;
+
+ return 0;
+}
+
+static int tc_setup_ets_destroy(struct stmmac_priv *priv,
+ struct tc_ets_qopt_offload *qopt)
+{
+ if (qopt->parent != TC_H_ROOT ||
+ qopt->handle != priv->qdisc.handle)
+ return -EOPNOTSUPP;
+
+ if (!priv->qdisc.enable ||
+ priv->qdisc.algo != MTL_TX_ALGORITHM_DWRR)
+ return -EOPNOTSUPP;
+
+ stmmac_qdisc_restore_dt_config(priv);
+
+ return 0;
+}
+
+static int tc_setup_ets(struct stmmac_priv *priv,
+ struct tc_ets_qopt_offload *qopt)
+{
+ switch (qopt->command) {
+ case TC_ETS_REPLACE:
+ return tc_setup_ets_sched(priv, qopt);
+ case TC_ETS_DESTROY:
+ return tc_setup_ets_destroy(priv, qopt);
+ case TC_ETS_GRAFT:
+ break;
+ case TC_ETS_STATS:
+ if (qopt->parent == TC_H_ROOT &&
+ qopt->handle == priv->qdisc.handle &&
+ priv->qdisc.enable &&
+ priv->qdisc.algo == MTL_TX_ALGORITHM_DWRR)
+ break;
+ fallthrough;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static int tc_query_caps(struct stmmac_priv *priv,
struct tc_query_caps_base *base)
{
@@ -1308,6 +1410,7 @@ const struct stmmac_tc_ops dwmac4_tc_ops = {
.setup_cls = tc_setup_cls,
.setup_taprio = tc_setup_taprio_without_fpe,
.setup_etf = tc_setup_etf,
+ .setup_ets = tc_setup_ets,
.query_caps = tc_query_caps,
.setup_mqprio = tc_setup_mqprio_unimplemented,
};
@@ -1319,6 +1422,7 @@ const struct stmmac_tc_ops dwmac510_tc_ops = {
.setup_cls = tc_setup_cls,
.setup_taprio = tc_setup_taprio,
.setup_etf = tc_setup_etf,
+ .setup_ets = tc_setup_ets,
.query_caps = tc_query_caps,
.setup_mqprio = tc_setup_dwmac510_mqprio,
};
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next v3 2/3] net: stmmac: add tc-mqprio qdisc offload
2026-08-08 14:49 [PATCH net-next v3 0/3] Implement mqprio and ets qdisc offload in stmmac driver Lorenzo Bianconi
2026-08-08 14:49 ` [PATCH net-next v3 1/3] net: stmmac: add tc-ets qdisc offload Lorenzo Bianconi
@ 2026-08-08 14:49 ` Lorenzo Bianconi
2026-08-14 20:56 ` Jakub Kicinski
2026-08-08 14:49 ` [PATCH net-next v3 3/3] net: stmmac: hold runtime PM reference in setup_tc Lorenzo Bianconi
2 siblings, 1 reply; 5+ messages in thread
From: Lorenzo Bianconi @ 2026-08-08 14:49 UTC (permalink / raw)
To: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue
Cc: Daniel Thompson, Alex Elder, Davide Caratti, netdev, linux-stm32,
linux-arm-kernel, Lorenzo Bianconi
Implement offload of the tc-mqprio qdisc in the stmmac driver. The MTL TX
scheduler is switched to strict priority, and the PSTQX/PSTC priority
bitmask of each TX queue is programmed from the set of frame priorities
mapped to the owning traffic class (qopt->prio_tc_map).
The offload requires the DCB feature and a 1:1 TC to TX queue mapping,
with the queue ranges bounded by the number of queues the MAC implements.
Configurations with AVB queues are rejected, since forcing strict
priority conflicts with the CBS algorithm.
The per-queue priority bitmasks are stored in the unified qdisc state
(priv->qdisc.prio) so they can be reprogrammed on device reopen, and are
applied through the MTL TX queue priority map registers. Export
stmmac_mac_config_tx_queues_prio() so the mqprio path can reprogram the
queue priorities, leaving queues without snps,priority untouched.
Destroying the mqprio qdisc, or failing its setup, restores the
devicetree configured scheduling algorithm, TX queue priorities and TX
queue weights, unless a different offload is active.
Reviewed-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 15 ++++---
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 55 ++++++++++++++++++++++-
3 files changed, 65 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 33c37f843336..1967279a4ccc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -307,6 +307,7 @@ struct stmmac_priv {
u8 bands;
u32 handle;
u32 quanta[MTL_MAX_TX_QUEUES];
+ u32 prio[MTL_MAX_TX_QUEUES];
} qdisc;
struct dma_features dma_cap;
struct stmmac_counters mmc;
@@ -402,6 +403,7 @@ enum stmmac_state {
extern const struct dev_pm_ops stmmac_simple_pm_ops;
void stmmac_set_tx_queue_weight(struct stmmac_priv *priv);
+void stmmac_mac_config_tx_queues_prio(struct stmmac_priv *priv);
int stmmac_mdio_unregister(struct net_device *ndev);
int stmmac_mdio_register(struct net_device *ndev);
int stmmac_mdio_reset(struct mii_bus *mii);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 5acddc9cbd3f..e19f75d8c393 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3507,18 +3507,23 @@ static void stmmac_mac_config_rx_queues_prio(struct stmmac_priv *priv)
* @priv: driver private structure
* Description: It is used for configuring the TX Queue Priority
*/
-static void stmmac_mac_config_tx_queues_prio(struct stmmac_priv *priv)
+void stmmac_mac_config_tx_queues_prio(struct stmmac_priv *priv)
{
u8 tx_queues_count = priv->plat->tx_queues_to_use;
u8 queue;
- u32 prio;
for (queue = 0; queue < tx_queues_count; queue++) {
- if (!priv->plat->tx_queues_cfg[queue].use_prio)
+ if (priv->qdisc.enable &&
+ priv->qdisc.algo == MTL_TX_ALGORITHM_SP) {
+ stmmac_tx_queue_prio(priv, priv->hw,
+ priv->qdisc.prio[queue], queue);
continue;
+ }
- prio = priv->plat->tx_queues_cfg[queue].prio;
- stmmac_tx_queue_prio(priv, priv->hw, prio, queue);
+ if (priv->plat->tx_queues_cfg[queue].use_prio)
+ stmmac_tx_queue_prio(priv, priv->hw,
+ priv->plat->tx_queues_cfg[queue].prio,
+ queue);
}
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 15949b5d9f32..336350d6786b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -1219,6 +1219,7 @@ static void stmmac_qdisc_restore_dt_config(struct stmmac_priv *priv)
priv->qdisc.enable = false;
netif_set_real_num_tx_queues(priv->dev, priv->plat->tx_queues_to_use);
stmmac_set_tx_queue_weight(priv);
+ stmmac_mac_config_tx_queues_prio(priv);
stmmac_prog_mtl_tx_algorithms(priv, priv->hw,
priv->plat->tx_sched_algorithm);
}
@@ -1345,8 +1346,16 @@ 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.enable && priv->qdisc.algo == MTL_TX_ALGORITHM_SP) {
+ stmmac_qdisc_restore_dt_config(priv);
+ } else {
+ u8 bands = priv->qdisc.enable ? priv->qdisc.bands
+ : priv->plat->tx_queues_to_use;
+
+ netif_set_real_num_tx_queues(ndev, bands);
+ }
}
static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
@@ -1357,13 +1366,24 @@ static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
u32 offset, count, num_stack_tx_queues = 0;
struct net_device *ndev = priv->dev;
u32 num_tc = qopt->num_tc;
- int err;
+ int i, tc, err;
if (!num_tc) {
stmmac_reset_tc_mqprio(ndev, extack);
return 0;
}
+ if (!priv->dma_cap.dcben)
+ return -EOPNOTSUPP;
+
+ /* Forcing strict priority conflicts with the CBS algorithm of AVB
+ * queues, so reject the offload when any queue is configured as AVB.
+ */
+ for (i = 0; i < priv->plat->tx_queues_to_use; i++) {
+ if (priv->plat->tx_queues_cfg[i].mode_to_use == MTL_QUEUE_AVB)
+ return -EOPNOTSUPP;
+ }
+
err = netdev_set_num_tc(ndev, num_tc);
if (err)
return err;
@@ -1373,6 +1393,15 @@ static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
count = qopt->count[tc];
num_stack_tx_queues += count;
+ if (offset + count > priv->plat->tx_queues_to_use)
+ goto err_reset_tc;
+
+ /* The offload switches the MTL scheduler to strict priority,
+ * which only supports a 1:1 TC to TX queue mapping.
+ */
+ if (count > 1)
+ goto err_reset_tc;
+
err = netdev_set_tc_queue(ndev, tc, count, offset);
if (err)
goto err_reset_tc;
@@ -1387,6 +1416,28 @@ static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
if (err)
goto err_reset_tc;
+ for (i = 0; i < priv->plat->tx_queues_to_use; i++) {
+ u32 prio = 0;
+
+ for (tc = 0; tc < num_tc; tc++) {
+ int p;
+
+ if (qopt->offset[tc] != i)
+ continue;
+
+ for (p = 0; p < ARRAY_SIZE(qopt->prio_tc_map); p++)
+ if (qopt->prio_tc_map[p] == tc)
+ prio |= BIT(p);
+ break;
+ }
+
+ priv->qdisc.prio[i] = prio;
+ stmmac_tx_queue_prio(priv, priv->hw, prio, i);
+ }
+ stmmac_prog_mtl_tx_algorithms(priv, priv->hw, MTL_TX_ALGORITHM_SP);
+ priv->qdisc.algo = MTL_TX_ALGORITHM_SP;
+ priv->qdisc.enable = true;
+
return 0;
err_reset_tc:
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net-next v3 3/3] net: stmmac: hold runtime PM reference in setup_tc
2026-08-08 14:49 [PATCH net-next v3 0/3] Implement mqprio and ets qdisc offload in stmmac driver Lorenzo Bianconi
2026-08-08 14:49 ` [PATCH net-next v3 1/3] net: stmmac: add tc-ets qdisc offload Lorenzo Bianconi
2026-08-08 14:49 ` [PATCH net-next v3 2/3] net: stmmac: add tc-mqprio " Lorenzo Bianconi
@ 2026-08-08 14:49 ` Lorenzo Bianconi
2 siblings, 0 replies; 5+ messages in thread
From: Lorenzo Bianconi @ 2026-08-08 14:49 UTC (permalink / raw)
To: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue
Cc: Daniel Thompson, Alex Elder, Davide Caratti, netdev, linux-stm32,
linux-arm-kernel, Lorenzo Bianconi
The qdisc offload callbacks invoked by stmmac_setup_tc() program
MTL/MAC registers, but they can be reached while the interface is down,
when stmmac_release() has dropped the runtime PM usage counter and the
device may be suspended with its clocks gated. Accessing the registers
in that state can trigger a bus error.
Hold a runtime PM reference for the whole setup_tc() call so the device
is active, and its clocks enabled, whenever a qdisc offload is
configured or torn down. This covers all qdisc offloads, including the
pre-existing CBS/TAPRIO paths that had the same issue.
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 39 ++++++++++++++++-------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index e19f75d8c393..5aee03ebe131 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -6443,28 +6443,45 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data)
{
struct stmmac_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(priv->device);
+ if (ret < 0)
+ return ret;
switch (type) {
case TC_QUERY_CAPS:
- return stmmac_tc_query_caps(priv, priv, type_data);
+ ret = stmmac_tc_query_caps(priv, priv, type_data);
+ break;
case TC_SETUP_QDISC_MQPRIO:
- return stmmac_tc_setup_mqprio(priv, priv, type_data);
+ ret = stmmac_tc_setup_mqprio(priv, priv, type_data);
+ break;
case TC_SETUP_BLOCK:
- return flow_block_cb_setup_simple(type_data,
- &stmmac_block_cb_list,
- stmmac_setup_tc_block_cb,
- priv, priv, true);
+ ret = flow_block_cb_setup_simple(type_data,
+ &stmmac_block_cb_list,
+ stmmac_setup_tc_block_cb,
+ priv, priv, true);
+ break;
case TC_SETUP_QDISC_CBS:
- return stmmac_tc_setup_cbs(priv, priv, type_data);
+ ret = stmmac_tc_setup_cbs(priv, priv, type_data);
+ break;
case TC_SETUP_QDISC_TAPRIO:
- return stmmac_tc_setup_taprio(priv, priv, type_data);
+ ret = stmmac_tc_setup_taprio(priv, priv, type_data);
+ break;
case TC_SETUP_QDISC_ETF:
- return stmmac_tc_setup_etf(priv, priv, type_data);
+ ret = stmmac_tc_setup_etf(priv, priv, type_data);
+ break;
case TC_SETUP_QDISC_ETS:
- return stmmac_tc_setup_ets(priv, priv, type_data);
+ ret = stmmac_tc_setup_ets(priv, priv, type_data);
+ break;
default:
- return -EOPNOTSUPP;
+ ret = -EOPNOTSUPP;
+ break;
}
+
+ pm_runtime_put(priv->device);
+
+ return ret;
}
static u16 stmmac_select_queue(struct net_device *dev, struct sk_buff *skb,
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net-next v3 2/3] net: stmmac: add tc-mqprio qdisc offload
2026-08-08 14:49 ` [PATCH net-next v3 2/3] net: stmmac: add tc-mqprio " Lorenzo Bianconi
@ 2026-08-14 20:56 ` Jakub Kicinski
0 siblings, 0 replies; 5+ messages in thread
From: Jakub Kicinski @ 2026-08-14 20:56 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, Maxime Coquelin, Alexandre Torgue, Daniel Thompson,
Alex Elder, Davide Caratti, netdev, linux-stm32, linux-arm-kernel
On Sat, 08 Aug 2026 16:49:58 +0200 Lorenzo Bianconi wrote:
> Subject: [PATCH net-next v3 2/3] net: stmmac: add tc-mqprio qdisc offload
>
> Implement offload of the tc-mqprio qdisc in the stmmac driver. The MTL TX
> scheduler is switched to strict priority, and the PSTQX/PSTC priority
> bitmask of each TX queue is programmed from the set of frame priorities
> mapped to the owning traffic class (qopt->prio_tc_map).
>
> The offload requires the DCB feature and a 1:1 TC to TX queue mapping,
> with the queue ranges bounded by the number of queues the MAC implements.
> Configurations with AVB queues are rejected, since forcing strict
> priority conflicts with the CBS algorithm.
Clashiko has a bunch of comments, I assume at least one of them is
actionable. High level - you say "add tc-mqprio qdisc offload"
but the driver already has a bunch of mqprio code. Background
would be useful. You also say "1:1 TC to TX queue mapping", if there's
only one queue per priority why offload mqprio and not prio?
At least a note in the commit message would be useful.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-14 20:56 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-08 14:49 [PATCH net-next v3 0/3] Implement mqprio and ets qdisc offload in stmmac driver Lorenzo Bianconi
2026-08-08 14:49 ` [PATCH net-next v3 1/3] net: stmmac: add tc-ets qdisc offload Lorenzo Bianconi
2026-08-08 14:49 ` [PATCH net-next v3 2/3] net: stmmac: add tc-mqprio " Lorenzo Bianconi
2026-08-14 20:56 ` Jakub Kicinski
2026-08-08 14:49 ` [PATCH net-next v3 3/3] net: stmmac: hold runtime PM reference in setup_tc Lorenzo Bianconi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox