[PATCH v4 net] octeontx2-pf: reset HTB scheduler topology before freeing queues
From: Ratheesh Kannoth <rkannoth@marvell.com>
Date: 2026-09-03 02:06:08
Also in:
lkml
Subsystem:
marvell octeontx2 physical function driver, networking drivers, the rest · Maintainers:
Sunil Goutham, Geetha sowjanya, Ratheesh Kannoth, Subbaraya Sundeep, Bharat Bhushan, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
HTB offload programs NIX_AF_TLxX_TOPOLOGY on QoS-allocated scheduler
queues via otx2_qos_txschq_set_parent_topology(), but teardown freed
those queues without clearing TOPOLOGY. The AF only restores PARENT and
SCHEDULE on free, so PRIO_ANCHOR/RR_PRIO settings can survive in the
shared scheduler pool and affect later allocations.
Add otx2_qos_reset_schq_topology() and otx2_qos_free_hw_schq() to zero
TL4 through TL2 TOPOLOGY before each schq is returned to the AF during
hierarchy teardown and cfg rollback. Skip the aggregation level (TL1):
it is a per-tx-link queue shared by the PF, default Tx hierarchy and VFs,
and is not freed back to the AF by nix_txschq_free_one().
Fixes: 5e6808b4c68d ("octeontx2-pf: Add support for HTB offload")
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
v3 -> v4: Addressed AI review comments.
https://lore.kernel.org/netdev/20260902172428.534936-1-horms@kernel.org/ (local)
v2 -> v3: Addressed AI review comments.
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260824072147.3524339-1-rkannoth@marvell.com?part=1
v1 -> v2: Addressed sashiko comments
https://sashiko.dev/#/patchset/20260821072812.2890922-1-rkannoth%40marvell.com
---
.../net/ethernet/marvell/octeontx2/nic/qos.c | 60 +++++++++++++++++--
1 file changed, 55 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
index 69c0911e28e9..f160b1618efa 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c@@ -235,13 +235,63 @@ static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf, return rc; } +static int otx2_qos_reset_schq_topology(struct otx2_nic *pfvf, u16 lvl, + u16 schq) +{ + struct mbox *mbox = &pfvf->mbox; + struct nix_txschq_config *cfg; + int rc; + + if (lvl < NIX_TXSCH_LVL_TL4 || lvl >= NIX_TXSCH_LVL_TL1) + return 0; + + mutex_lock(&mbox->lock); + + cfg = otx2_mbox_alloc_msg_nix_txschq_cfg(mbox); + if (!cfg) { + mutex_unlock(&mbox->lock); + return -ENOMEM; + } + + cfg->lvl = lvl; + cfg->num_regs = 1; + + if (lvl == NIX_TXSCH_LVL_TL4) + cfg->reg[0] = NIX_AF_TL4X_TOPOLOGY(schq); + else if (lvl == NIX_TXSCH_LVL_TL3) + cfg->reg[0] = NIX_AF_TL3X_TOPOLOGY(schq); + else if (lvl == NIX_TXSCH_LVL_TL2) + cfg->reg[0] = NIX_AF_TL2X_TOPOLOGY(schq); + + cfg->regval[0] = 0; + + rc = otx2_sync_mbox_msg(mbox); + + mutex_unlock(&mbox->lock); + + return rc; +} + +static void otx2_qos_free_hw_schq(struct otx2_nic *pfvf, u16 lvl, u16 schq) +{ + int err; + + err = otx2_qos_reset_schq_topology(pfvf, lvl, schq); + if (err) + netdev_warn(pfvf->netdev, + "QoS: failed to reset topology for schq %u at level %u: %d\n", + schq, lvl, err); + + otx2_txschq_free_one(pfvf, lvl, schq); +} + static void otx2_qos_free_hw_node_schq(struct otx2_nic *pfvf, struct otx2_qos_node *parent) { struct otx2_qos_node *node; list_for_each_entry_reverse(node, &parent->child_schq_list, list) - otx2_txschq_free_one(pfvf, node->level, node->schq); + otx2_qos_free_hw_schq(pfvf, node->level, node->schq); } static void otx2_qos_free_hw_node(struct otx2_nic *pfvf,
@@ -252,7 +302,7 @@ static void otx2_qos_free_hw_node(struct otx2_nic *pfvf, list_for_each_entry_safe(node, tmp, &parent->child_list, list) { otx2_qos_free_hw_node(pfvf, node); otx2_qos_free_hw_node_schq(pfvf, node); - otx2_txschq_free_one(pfvf, node->level, node->schq); + otx2_qos_free_hw_schq(pfvf, node->level, node->schq); } }
@@ -266,7 +316,7 @@ static void otx2_qos_free_hw_cfg(struct otx2_nic *pfvf, otx2_qos_free_hw_node_schq(pfvf, node); /* free node hw mappings */ - otx2_txschq_free_one(pfvf, node->level, node->schq); + otx2_qos_free_hw_schq(pfvf, node->level, node->schq); mutex_unlock(&pfvf->qos.qos_lock); }
@@ -913,7 +963,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg) for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { for (idx = 0; idx < cfg->schq[lvl]; idx++) { schq = cfg->schq_list[lvl][idx]; - otx2_txschq_free_one(pfvf, lvl, schq); + otx2_qos_free_hw_schq(pfvf, lvl, schq); } }
@@ -921,7 +971,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg) for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) { if (cfg->schq_index_used[lvl][idx]) { schq = cfg->schq_contig_list[lvl][idx]; - otx2_txschq_free_one(pfvf, lvl, schq); + otx2_qos_free_hw_schq(pfvf, lvl, schq); } } }
--
2.43.0