[PATCH net-next] net: stmmac: add tc-mqprio qdisc offload
Lorenzo Bianconi
lorenzo.bianconi at oss.qualcomm.com
Fri Sep 18 04:40:14 PDT 2026
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 a single queue per TC and per-TC offsets below the number of traffic
classes, so every queue referenced by the map stays within the TX queues
enabled by the offload. Configurations with AVB queues are rejected, since
forcing strict priority conflicts with the CBS algorithm.
The per-queue priority bitmasks and the scheduling algorithm are stored in
the new per-qdisc state (priv->xmit_qdisc) so they can be reprogrammed on
device reopen.
Destroying the mqprio qdisc, or failing its setup, restores the netdev TC
map and TX queue count to the previously saved values and resets the
per-qdisc state to the devicetree configuration. The devicetree configured
scheduling algorithm, TX queue priorities and TX queue weights are then
restored on the next device open.
Reviewed-by: Davide Caratti <dcaratti at redhat.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi at oss.qualcomm.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 6 ++
drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c | 2 +-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 25 ++++----
drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 77 ++++++++++++++++++++++-
4 files changed, 96 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 4fc96b317d79..69b400e9b138 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -299,6 +299,12 @@ struct stmmac_priv {
/* Protect est parameters */
struct mutex est_lock;
struct stmmac_est *est;
+
+ struct {
+ u32 prio[MTL_MAX_TX_QUEUES];
+ u8 algo;
+ } xmit_qdisc;
+
struct dma_features dma_cap;
struct stmmac_counters mmc;
int hw_cap_support;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
index c889204a7aa5..b6b5ef7c8fc4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
@@ -230,7 +230,7 @@ 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 (priv->xmit_qdisc.algo == MTL_TX_ALGORITHM_SP) {
NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index bf9e7e4cb1c3..0c9083f8846e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3533,17 +3533,11 @@ static void stmmac_mac_config_rx_queues_prio(struct stmmac_priv *priv)
*/
static 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)
- continue;
+ int i;
- prio = priv->plat->tx_queues_cfg[queue].prio;
- stmmac_tx_queue_prio(priv, priv->hw, prio, queue);
- }
+ for (i = 0; i < priv->plat->tx_queues_to_use; i++)
+ stmmac_tx_queue_prio(priv, priv->hw,
+ priv->xmit_qdisc.prio[i], i);
}
/**
@@ -3604,7 +3598,7 @@ static void stmmac_mtl_configuration(struct stmmac_priv *priv)
/* Configure MTL TX algorithms */
if (tx_queues_count > 1)
stmmac_prog_mtl_tx_algorithms(priv, priv->hw,
- priv->plat->tx_sched_algorithm);
+ priv->xmit_qdisc.algo);
/* Configure CBS in AVB TX queues */
if (tx_queues_count > 1)
@@ -7921,6 +7915,15 @@ static int __stmmac_dvr_probe(struct device *device,
priv->wol_irq = res->wol_irq;
priv->sfty_irq = res->sfty_irq;
+ /* Default xmit qdisc configuration */
+ for (i = 0; i < MTL_MAX_TX_QUEUES; i++) {
+ if (!priv->plat->tx_queues_cfg[i].use_prio)
+ continue;
+
+ priv->xmit_qdisc.prio[i] = priv->plat->tx_queues_cfg[i].prio;
+ }
+ priv->xmit_qdisc.algo = priv->plat->tx_sched_algorithm;
+
if (priv->plat->flags & STMMAC_FLAG_MULTI_MSI_EN) {
ret = stmmac_msi_init(priv, res);
if (ret)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 42a00446e9b4..a2a9680da5c0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -1265,6 +1265,23 @@ static int stmmac_reset_tc_mqprio(struct net_device *ndev,
struct netlink_ext_ack *extack)
{
struct stmmac_priv *priv = netdev_priv(ndev);
+ int i;
+
+ for (i = 0; i < priv->plat->tx_queues_to_use; i++) {
+ u32 prio;
+
+ if (priv->plat->tx_queues_cfg[i].use_prio)
+ prio = priv->plat->tx_queues_cfg[i].prio;
+ else
+ prio = 0;
+
+ stmmac_tx_queue_prio(priv, priv->hw, prio, i);
+ priv->xmit_qdisc.prio[i] = prio;
+ }
+
+ stmmac_prog_mtl_tx_algorithms(priv, priv->hw,
+ priv->plat->tx_sched_algorithm);
+ priv->xmit_qdisc.algo = priv->plat->tx_sched_algorithm;
netdev_reset_tc(ndev);
netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use);
@@ -1278,6 +1295,7 @@ static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
unsigned int ndev_num_tx_queues, num_tx_queues = 0;
struct netdev_tc_txq ndev_tc_to_txq[TC_MAX_QUEUE];
struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE] = {};
+ struct plat_stmmacenet_data *pdata = priv->plat;
struct netlink_ext_ack *extack = mqprio->extack;
struct tc_mqprio_qopt *qopt = &mqprio->qopt;
struct net_device *ndev = priv->dev;
@@ -1290,6 +1308,17 @@ static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
if (qopt->num_tc > ARRAY_SIZE(tc_to_txq))
return -EINVAL;
+ 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 < pdata->tx_queues_to_use; i++) {
+ if (pdata->tx_queues_cfg[i].mode_to_use == MTL_QUEUE_AVB)
+ return -EOPNOTSUPP;
+ }
+
/* save current tc values for reset */
ndev_ntc = netdev_get_num_tc(ndev);
for (i = 0; i < ARRAY_SIZE(ndev->tc_to_txq); i++)
@@ -1299,6 +1328,20 @@ static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
ndev_prio_tc_map[i] = READ_ONCE(ndev->prio_tc_map[i]);
for (i = 0; i < qopt->num_tc; i++) {
+ /* The offload switches the MTL scheduler to strict priority,
+ * which only supports a 1:1 TC to TX queue mapping.
+ */
+ if (qopt->count[i] > 1) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "SP sched requires 1:1 TXQ map");
+ return -EOPNOTSUPP;
+ }
+
+ if (qopt->offset[i] >= qopt->num_tc) {
+ NL_SET_ERR_MSG_MOD(extack, "TX queue range exceeded");
+ return -EINVAL;
+ }
+
tc_to_txq[i] = (struct netdev_tc_txq) {
.count = qopt->count[i],
.offset = qopt->offset[i],
@@ -1315,14 +1358,44 @@ static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv,
if (err)
goto error_reset_tc;
+ priv->xmit_qdisc.algo = MTL_TX_ALGORITHM_SP;
err = stmmac_fpe_map_preemption_class(priv, ndev, extack,
mqprio->preemptible_tcs);
if (err)
- goto error_reset_num_tx_queues;
+ goto error_reset_xmit_algo;
+
+ for (i = 0; i < pdata->tx_queues_to_use; i++) {
+ u32 prio = 0;
+ int j;
+
+ for (j = 0; j < qopt->num_tc; j++) {
+ int p;
+
+ if (qopt->offset[j] != i)
+ continue;
+
+ /* The PSTQX/PSTC priority map is 8 bits wide, so only
+ * priorities 0-7 can be represented in hardware.
+ * Priorities 8-15 are handled in software by the
+ * kernel through the netdev prio_tc_map.
+ */
+ for (p = 0; p < 8; p++) {
+ if (qopt->prio_tc_map[p] == j)
+ prio |= BIT(p);
+ }
+ break;
+ }
+
+ stmmac_tx_queue_prio(priv, priv->hw, prio, i);
+ priv->xmit_qdisc.prio[i] = prio;
+ }
+
+ stmmac_prog_mtl_tx_algorithms(priv, priv->hw, MTL_TX_ALGORITHM_SP);
return 0;
-error_reset_num_tx_queues:
+error_reset_xmit_algo:
+ priv->xmit_qdisc.algo = priv->plat->tx_sched_algorithm;
if (netif_set_real_num_tx_queues(ndev, ndev_num_tx_queues))
netdev_warn(ndev, "Failed to restore %u TX queues\n",
ndev_num_tx_queues);
---
base-commit: 4bb9710c6a68d35207f123aef55dcd50e7195ec5
change-id: 20260918-stmmac-mqprio-prio-offload-3d82d87f7bc8
Best regards,
--
Lorenzo Bianconi <lorenzo.bianconi at oss.qualcomm.com>
More information about the linux-arm-kernel
mailing list