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().
Unified · Split
| @@ -235,13 +235,63 @@ static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf, · 234 unmodified lines | ||
| 235 | 235 | return rc; |
| 236 | 236 | } |
| 237 | 237 | |
| 238 | +static int otx2_qos_reset_schq_topology(struct otx2_nic *pfvf, u16 lvl, | |
| 239 | + u16 schq) | |
| 240 | +{ | |
| 241 | + struct mbox *mbox = &pfvf->mbox; | |
| 242 | + struct nix_txschq_config *cfg; | |
| 243 | + int rc; | |
| 244 | + | |
| 245 | + if (lvl < NIX_TXSCH_LVL_TL4 || lvl >= NIX_TXSCH_LVL_TL1) | |
| 246 | + return 0; | |
| 247 | + | |
| 248 | + mutex_lock(&mbox->lock); | |
| 249 | + | |
| 250 | + cfg = otx2_mbox_alloc_msg_nix_txschq_cfg(mbox); | |
| 251 | + if (!cfg) { | |
| 252 | + mutex_unlock(&mbox->lock); | |
| 253 | + return -ENOMEM; | |
| 254 | + } | |
| 255 | + | |
| 256 | + cfg->lvl = lvl; | |
| 257 | + cfg->num_regs = 1; | |
| 258 | + | |
| 259 | + if (lvl == NIX_TXSCH_LVL_TL4) | |
| 260 | + cfg->reg[0] = NIX_AF_TL4X_TOPOLOGY(schq); | |
| 261 | + else if (lvl == NIX_TXSCH_LVL_TL3) | |
| 262 | + cfg->reg[0] = NIX_AF_TL3X_TOPOLOGY(schq); | |
| 263 | + else if (lvl == NIX_TXSCH_LVL_TL2) | |
| 264 | + cfg->reg[0] = NIX_AF_TL2X_TOPOLOGY(schq); | |
| 265 | + | |
| 266 | + cfg->regval[0] = 0; | |
| 267 | + | |
| 268 | + rc = otx2_sync_mbox_msg(mbox); | |
| 269 | + | |
| 270 | + mutex_unlock(&mbox->lock); | |
| 271 | + | |
| 272 | + return rc; | |
| 273 | +} | |
| 274 | + | |
| 275 | +static void otx2_qos_free_hw_schq(struct otx2_nic *pfvf, u16 lvl, u16 schq) | |
| 276 | +{ | |
| 277 | + int err; | |
| 278 | + | |
| 279 | + err = otx2_qos_reset_schq_topology(pfvf, lvl, schq); | |
| 280 | + if (err) | |
| 281 | + netdev_warn(pfvf->netdev, | |
| 282 | + "QoS: failed to reset topology for schq %u at level %u: %d\n", | |
| 283 | + schq, lvl, err); | |
| 284 | + | |
| 285 | + otx2_txschq_free_one(pfvf, lvl, schq); | |
| 286 | +} | |
| 287 | + | |
| 238 | 288 | static void otx2_qos_free_hw_node_schq(struct otx2_nic *pfvf, |
| 239 | 289 | struct otx2_qos_node *parent) |
| 240 | 290 | { |
| 241 | 291 | struct otx2_qos_node *node; |
| 242 | 292 | |
| 243 | 293 | list_for_each_entry_reverse(node, &parent->child_schq_list, list) |
| 244 | − otx2_txschq_free_one(pfvf, node->level, node->schq); | |
| 294 | + otx2_qos_free_hw_schq(pfvf, node->level, node->schq); | |
| 245 | 295 | } |
| 246 | 296 | |
| 247 | 297 | 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, · 4 unmodified lines | ||
| 252 | 302 | list_for_each_entry_safe(node, tmp, &parent->child_list, list) { |
| 253 | 303 | otx2_qos_free_hw_node(pfvf, node); |
| 254 | 304 | otx2_qos_free_hw_node_schq(pfvf, node); |
| 255 | − otx2_txschq_free_one(pfvf, node->level, node->schq); | |
| 305 | + otx2_qos_free_hw_schq(pfvf, node->level, node->schq); | |
| 256 | 306 | } |
| 257 | 307 | } |
| 258 | 308 | |
| @@ -266,7 +316,7 @@ static void otx2_qos_free_hw_cfg(struct otx2_nic *pfvf, · 7 unmodified lines | ||
| 266 | 316 | otx2_qos_free_hw_node_schq(pfvf, node); |
| 267 | 317 | |
| 268 | 318 | /* free node hw mappings */ |
| 269 | − otx2_txschq_free_one(pfvf, node->level, node->schq); | |
| 319 | + otx2_qos_free_hw_schq(pfvf, node->level, node->schq); | |
| 270 | 320 | |
| 271 | 321 | mutex_unlock(&pfvf->qos.qos_lock); |
| 272 | 322 | } |
| @@ -913,7 +963,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg) · 640 unmodified lines | ||
| 913 | 963 | for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { |
| 914 | 964 | for (idx = 0; idx < cfg->schq[lvl]; idx++) { |
| 915 | 965 | schq = cfg->schq_list[lvl][idx]; |
| 916 | − otx2_txschq_free_one(pfvf, lvl, schq); | |
| 966 | + otx2_qos_free_hw_schq(pfvf, lvl, schq); | |
| 917 | 967 | } |
| 918 | 968 | } |
| 919 | 969 | |
| @@ -921,7 +971,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg) · 1 unmodified line | ||
| 921 | 971 | for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) { |
| 922 | 972 | if (cfg->schq_index_used[lvl][idx]) { |
| 923 | 973 | schq = cfg->schq_contig_list[lvl][idx]; |
| 924 | − otx2_txschq_free_one(pfvf, lvl, schq); | |
| 974 | + otx2_qos_free_hw_schq(pfvf, lvl, schq); | |
| 925 | 975 | } |
| 926 | 976 | } |
| 927 | 977 | } |