15e6808b4SNaveen Mamindlapalli // SPDX-License-Identifier: GPL-2.0 25e6808b4SNaveen Mamindlapalli /* Marvell RVU Ethernet driver 35e6808b4SNaveen Mamindlapalli * 45e6808b4SNaveen Mamindlapalli * Copyright (C) 2023 Marvell. 55e6808b4SNaveen Mamindlapalli * 65e6808b4SNaveen Mamindlapalli */ 75e6808b4SNaveen Mamindlapalli #include <linux/netdevice.h> 85e6808b4SNaveen Mamindlapalli #include <linux/etherdevice.h> 95e6808b4SNaveen Mamindlapalli #include <linux/inetdevice.h> 105e6808b4SNaveen Mamindlapalli #include <linux/bitfield.h> 115e6808b4SNaveen Mamindlapalli 125e6808b4SNaveen Mamindlapalli #include "otx2_common.h" 135e6808b4SNaveen Mamindlapalli #include "cn10k.h" 145e6808b4SNaveen Mamindlapalli #include "qos.h" 155e6808b4SNaveen Mamindlapalli 165e6808b4SNaveen Mamindlapalli #define OTX2_QOS_QID_INNER 0xFFFFU 175e6808b4SNaveen Mamindlapalli #define OTX2_QOS_QID_NONE 0xFFFEU 185e6808b4SNaveen Mamindlapalli #define OTX2_QOS_ROOT_CLASSID 0xFFFFFFFF 195e6808b4SNaveen Mamindlapalli #define OTX2_QOS_CLASS_NONE 0 205e6808b4SNaveen Mamindlapalli #define OTX2_QOS_DEFAULT_PRIO 0xF 215e6808b4SNaveen Mamindlapalli #define OTX2_QOS_INVALID_SQ 0xFFFF 22f78dca69SNaveen Mamindlapalli #define OTX2_QOS_INVALID_TXSCHQ_IDX 0xFFFF 2347a9656fSNaveen Mamindlapalli #define CN10K_MAX_RR_WEIGHT GENMASK_ULL(13, 0) 2447a9656fSNaveen Mamindlapalli #define OTX2_MAX_RR_QUANTUM GENMASK_ULL(23, 0) 255e6808b4SNaveen Mamindlapalli 265e6808b4SNaveen Mamindlapalli static void otx2_qos_update_tx_netdev_queues(struct otx2_nic *pfvf) 275e6808b4SNaveen Mamindlapalli { 285e6808b4SNaveen Mamindlapalli struct otx2_hw *hw = &pfvf->hw; 295e6808b4SNaveen Mamindlapalli int tx_queues, qos_txqs, err; 305e6808b4SNaveen Mamindlapalli 315e6808b4SNaveen Mamindlapalli qos_txqs = bitmap_weight(pfvf->qos.qos_sq_bmap, 325e6808b4SNaveen Mamindlapalli OTX2_QOS_MAX_LEAF_NODES); 335e6808b4SNaveen Mamindlapalli 345e6808b4SNaveen Mamindlapalli tx_queues = hw->tx_queues + qos_txqs; 355e6808b4SNaveen Mamindlapalli 365e6808b4SNaveen Mamindlapalli err = netif_set_real_num_tx_queues(pfvf->netdev, tx_queues); 375e6808b4SNaveen Mamindlapalli if (err) { 385e6808b4SNaveen Mamindlapalli netdev_err(pfvf->netdev, 395e6808b4SNaveen Mamindlapalli "Failed to set no of Tx queues: %d\n", tx_queues); 405e6808b4SNaveen Mamindlapalli return; 415e6808b4SNaveen Mamindlapalli } 425e6808b4SNaveen Mamindlapalli } 435e6808b4SNaveen Mamindlapalli 445e6808b4SNaveen Mamindlapalli static void otx2_qos_get_regaddr(struct otx2_qos_node *node, 455e6808b4SNaveen Mamindlapalli struct nix_txschq_config *cfg, 465e6808b4SNaveen Mamindlapalli int index) 475e6808b4SNaveen Mamindlapalli { 485e6808b4SNaveen Mamindlapalli if (node->level == NIX_TXSCH_LVL_SMQ) { 495e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_MDQX_PARENT(node->schq); 505e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_MDQX_SCHEDULE(node->schq); 515e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_MDQX_PIR(node->schq); 525e6808b4SNaveen Mamindlapalli cfg->reg[index] = NIX_AF_MDQX_CIR(node->schq); 535e6808b4SNaveen Mamindlapalli } else if (node->level == NIX_TXSCH_LVL_TL4) { 545e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_TL4X_PARENT(node->schq); 555e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_TL4X_SCHEDULE(node->schq); 565e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_TL4X_PIR(node->schq); 575e6808b4SNaveen Mamindlapalli cfg->reg[index] = NIX_AF_TL4X_CIR(node->schq); 585e6808b4SNaveen Mamindlapalli } else if (node->level == NIX_TXSCH_LVL_TL3) { 595e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_TL3X_PARENT(node->schq); 605e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_TL3X_SCHEDULE(node->schq); 615e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_TL3X_PIR(node->schq); 625e6808b4SNaveen Mamindlapalli cfg->reg[index] = NIX_AF_TL3X_CIR(node->schq); 635e6808b4SNaveen Mamindlapalli } else if (node->level == NIX_TXSCH_LVL_TL2) { 645e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_TL2X_PARENT(node->schq); 655e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_TL2X_SCHEDULE(node->schq); 665e6808b4SNaveen Mamindlapalli cfg->reg[index++] = NIX_AF_TL2X_PIR(node->schq); 675e6808b4SNaveen Mamindlapalli cfg->reg[index] = NIX_AF_TL2X_CIR(node->schq); 685e6808b4SNaveen Mamindlapalli } 695e6808b4SNaveen Mamindlapalli } 705e6808b4SNaveen Mamindlapalli 7147a9656fSNaveen Mamindlapalli static int otx2_qos_quantum_to_dwrr_weight(struct otx2_nic *pfvf, u32 quantum) 7247a9656fSNaveen Mamindlapalli { 7347a9656fSNaveen Mamindlapalli u32 weight; 7447a9656fSNaveen Mamindlapalli 7547a9656fSNaveen Mamindlapalli weight = quantum / pfvf->hw.dwrr_mtu; 7647a9656fSNaveen Mamindlapalli if (quantum % pfvf->hw.dwrr_mtu) 7747a9656fSNaveen Mamindlapalli weight += 1; 7847a9656fSNaveen Mamindlapalli 7947a9656fSNaveen Mamindlapalli return weight; 8047a9656fSNaveen Mamindlapalli } 8147a9656fSNaveen Mamindlapalli 825e6808b4SNaveen Mamindlapalli static void otx2_config_sched_shaping(struct otx2_nic *pfvf, 835e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 845e6808b4SNaveen Mamindlapalli struct nix_txschq_config *cfg, 855e6808b4SNaveen Mamindlapalli int *num_regs) 865e6808b4SNaveen Mamindlapalli { 8747a9656fSNaveen Mamindlapalli u32 rr_weight; 8847a9656fSNaveen Mamindlapalli u32 quantum; 895e6808b4SNaveen Mamindlapalli u64 maxrate; 905e6808b4SNaveen Mamindlapalli 915e6808b4SNaveen Mamindlapalli otx2_qos_get_regaddr(node, cfg, *num_regs); 925e6808b4SNaveen Mamindlapalli 935e6808b4SNaveen Mamindlapalli /* configure parent txschq */ 945e6808b4SNaveen Mamindlapalli cfg->regval[*num_regs] = node->parent->schq << 16; 955e6808b4SNaveen Mamindlapalli (*num_regs)++; 965e6808b4SNaveen Mamindlapalli 975e6808b4SNaveen Mamindlapalli /* configure prio/quantum */ 985e6808b4SNaveen Mamindlapalli if (node->qid == OTX2_QOS_QID_NONE) { 995e6808b4SNaveen Mamindlapalli cfg->regval[*num_regs] = node->prio << 24 | 1005e6808b4SNaveen Mamindlapalli mtu_to_dwrr_weight(pfvf, pfvf->tx_max_pktlen); 1015e6808b4SNaveen Mamindlapalli (*num_regs)++; 1025e6808b4SNaveen Mamindlapalli return; 1035e6808b4SNaveen Mamindlapalli } 1045e6808b4SNaveen Mamindlapalli 10547a9656fSNaveen Mamindlapalli /* configure priority/quantum */ 10647a9656fSNaveen Mamindlapalli if (node->is_static) { 10747a9656fSNaveen Mamindlapalli cfg->regval[*num_regs] = 10847a9656fSNaveen Mamindlapalli (node->schq - node->parent->prio_anchor) << 24; 10947a9656fSNaveen Mamindlapalli } else { 11047a9656fSNaveen Mamindlapalli quantum = node->quantum ? 11147a9656fSNaveen Mamindlapalli node->quantum : pfvf->tx_max_pktlen; 11247a9656fSNaveen Mamindlapalli rr_weight = otx2_qos_quantum_to_dwrr_weight(pfvf, quantum); 11347a9656fSNaveen Mamindlapalli cfg->regval[*num_regs] = node->parent->child_dwrr_prio << 24 | 11447a9656fSNaveen Mamindlapalli rr_weight; 11547a9656fSNaveen Mamindlapalli } 1165e6808b4SNaveen Mamindlapalli (*num_regs)++; 1175e6808b4SNaveen Mamindlapalli 1185e6808b4SNaveen Mamindlapalli /* configure PIR */ 1195e6808b4SNaveen Mamindlapalli maxrate = (node->rate > node->ceil) ? node->rate : node->ceil; 1205e6808b4SNaveen Mamindlapalli 1215e6808b4SNaveen Mamindlapalli cfg->regval[*num_regs] = 1225e6808b4SNaveen Mamindlapalli otx2_get_txschq_rate_regval(pfvf, maxrate, 65536); 1235e6808b4SNaveen Mamindlapalli (*num_regs)++; 1245e6808b4SNaveen Mamindlapalli 1255e6808b4SNaveen Mamindlapalli /* Don't configure CIR when both CIR+PIR not supported 1265e6808b4SNaveen Mamindlapalli * On 96xx, CIR + PIR + RED_ALGO=STALL causes deadlock 1275e6808b4SNaveen Mamindlapalli */ 1285e6808b4SNaveen Mamindlapalli if (!test_bit(QOS_CIR_PIR_SUPPORT, &pfvf->hw.cap_flag)) 1295e6808b4SNaveen Mamindlapalli return; 1305e6808b4SNaveen Mamindlapalli 1315e6808b4SNaveen Mamindlapalli cfg->regval[*num_regs] = 1325e6808b4SNaveen Mamindlapalli otx2_get_txschq_rate_regval(pfvf, node->rate, 65536); 1335e6808b4SNaveen Mamindlapalli (*num_regs)++; 1345e6808b4SNaveen Mamindlapalli } 1355e6808b4SNaveen Mamindlapalli 1365e6808b4SNaveen Mamindlapalli static void __otx2_qos_txschq_cfg(struct otx2_nic *pfvf, 1375e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 1385e6808b4SNaveen Mamindlapalli struct nix_txschq_config *cfg) 1395e6808b4SNaveen Mamindlapalli { 1405e6808b4SNaveen Mamindlapalli struct otx2_hw *hw = &pfvf->hw; 1415e6808b4SNaveen Mamindlapalli int num_regs = 0; 1425e6808b4SNaveen Mamindlapalli u8 level; 1435e6808b4SNaveen Mamindlapalli 1445e6808b4SNaveen Mamindlapalli level = node->level; 1455e6808b4SNaveen Mamindlapalli 1465e6808b4SNaveen Mamindlapalli /* program txschq registers */ 1475e6808b4SNaveen Mamindlapalli if (level == NIX_TXSCH_LVL_SMQ) { 1485e6808b4SNaveen Mamindlapalli cfg->reg[num_regs] = NIX_AF_SMQX_CFG(node->schq); 1495e6808b4SNaveen Mamindlapalli cfg->regval[num_regs] = ((u64)pfvf->tx_max_pktlen << 8) | 1505e6808b4SNaveen Mamindlapalli OTX2_MIN_MTU; 1515e6808b4SNaveen Mamindlapalli cfg->regval[num_regs] |= (0x20ULL << 51) | (0x80ULL << 39) | 1525e6808b4SNaveen Mamindlapalli (0x2ULL << 36); 1535e6808b4SNaveen Mamindlapalli num_regs++; 1545e6808b4SNaveen Mamindlapalli 1555e6808b4SNaveen Mamindlapalli otx2_config_sched_shaping(pfvf, node, cfg, &num_regs); 1565e6808b4SNaveen Mamindlapalli } else if (level == NIX_TXSCH_LVL_TL4) { 1575e6808b4SNaveen Mamindlapalli otx2_config_sched_shaping(pfvf, node, cfg, &num_regs); 1585e6808b4SNaveen Mamindlapalli } else if (level == NIX_TXSCH_LVL_TL3) { 1595e6808b4SNaveen Mamindlapalli /* configure link cfg */ 1605e6808b4SNaveen Mamindlapalli if (level == pfvf->qos.link_cfg_lvl) { 1615e6808b4SNaveen Mamindlapalli cfg->reg[num_regs] = NIX_AF_TL3_TL2X_LINKX_CFG(node->schq, hw->tx_link); 1625e6808b4SNaveen Mamindlapalli cfg->regval[num_regs] = BIT_ULL(13) | BIT_ULL(12); 1635e6808b4SNaveen Mamindlapalli num_regs++; 1645e6808b4SNaveen Mamindlapalli } 1655e6808b4SNaveen Mamindlapalli 1665e6808b4SNaveen Mamindlapalli otx2_config_sched_shaping(pfvf, node, cfg, &num_regs); 1675e6808b4SNaveen Mamindlapalli } else if (level == NIX_TXSCH_LVL_TL2) { 1685e6808b4SNaveen Mamindlapalli /* configure link cfg */ 1695e6808b4SNaveen Mamindlapalli if (level == pfvf->qos.link_cfg_lvl) { 1705e6808b4SNaveen Mamindlapalli cfg->reg[num_regs] = NIX_AF_TL3_TL2X_LINKX_CFG(node->schq, hw->tx_link); 1715e6808b4SNaveen Mamindlapalli cfg->regval[num_regs] = BIT_ULL(13) | BIT_ULL(12); 1725e6808b4SNaveen Mamindlapalli num_regs++; 1735e6808b4SNaveen Mamindlapalli } 1745e6808b4SNaveen Mamindlapalli 1755e6808b4SNaveen Mamindlapalli /* check if node is root */ 1765e6808b4SNaveen Mamindlapalli if (node->qid == OTX2_QOS_QID_INNER && !node->parent) { 1775e6808b4SNaveen Mamindlapalli cfg->reg[num_regs] = NIX_AF_TL2X_SCHEDULE(node->schq); 178*02ea3120SRatheesh Kannoth cfg->regval[num_regs] = (u64)hw->txschq_aggr_lvl_rr_prio << 24 | 1795e6808b4SNaveen Mamindlapalli mtu_to_dwrr_weight(pfvf, 1805e6808b4SNaveen Mamindlapalli pfvf->tx_max_pktlen); 1815e6808b4SNaveen Mamindlapalli num_regs++; 1825e6808b4SNaveen Mamindlapalli goto txschq_cfg_out; 1835e6808b4SNaveen Mamindlapalli } 1845e6808b4SNaveen Mamindlapalli 1855e6808b4SNaveen Mamindlapalli otx2_config_sched_shaping(pfvf, node, cfg, &num_regs); 1865e6808b4SNaveen Mamindlapalli } 1875e6808b4SNaveen Mamindlapalli 1885e6808b4SNaveen Mamindlapalli txschq_cfg_out: 1895e6808b4SNaveen Mamindlapalli cfg->num_regs = num_regs; 1905e6808b4SNaveen Mamindlapalli } 1915e6808b4SNaveen Mamindlapalli 1925e6808b4SNaveen Mamindlapalli static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf, 1935e6808b4SNaveen Mamindlapalli struct otx2_qos_node *parent) 1945e6808b4SNaveen Mamindlapalli { 1955e6808b4SNaveen Mamindlapalli struct mbox *mbox = &pfvf->mbox; 1965e6808b4SNaveen Mamindlapalli struct nix_txschq_config *cfg; 1975e6808b4SNaveen Mamindlapalli int rc; 1985e6808b4SNaveen Mamindlapalli 1995e6808b4SNaveen Mamindlapalli if (parent->level == NIX_TXSCH_LVL_MDQ) 2005e6808b4SNaveen Mamindlapalli return 0; 2015e6808b4SNaveen Mamindlapalli 2025e6808b4SNaveen Mamindlapalli mutex_lock(&mbox->lock); 2035e6808b4SNaveen Mamindlapalli 2045e6808b4SNaveen Mamindlapalli cfg = otx2_mbox_alloc_msg_nix_txschq_cfg(&pfvf->mbox); 2055e6808b4SNaveen Mamindlapalli if (!cfg) { 2065e6808b4SNaveen Mamindlapalli mutex_unlock(&mbox->lock); 2075e6808b4SNaveen Mamindlapalli return -ENOMEM; 2085e6808b4SNaveen Mamindlapalli } 2095e6808b4SNaveen Mamindlapalli 2105e6808b4SNaveen Mamindlapalli cfg->lvl = parent->level; 2115e6808b4SNaveen Mamindlapalli 2125e6808b4SNaveen Mamindlapalli if (parent->level == NIX_TXSCH_LVL_TL4) 2135e6808b4SNaveen Mamindlapalli cfg->reg[0] = NIX_AF_TL4X_TOPOLOGY(parent->schq); 2145e6808b4SNaveen Mamindlapalli else if (parent->level == NIX_TXSCH_LVL_TL3) 2155e6808b4SNaveen Mamindlapalli cfg->reg[0] = NIX_AF_TL3X_TOPOLOGY(parent->schq); 2165e6808b4SNaveen Mamindlapalli else if (parent->level == NIX_TXSCH_LVL_TL2) 2175e6808b4SNaveen Mamindlapalli cfg->reg[0] = NIX_AF_TL2X_TOPOLOGY(parent->schq); 2185e6808b4SNaveen Mamindlapalli else if (parent->level == NIX_TXSCH_LVL_TL1) 2195e6808b4SNaveen Mamindlapalli cfg->reg[0] = NIX_AF_TL1X_TOPOLOGY(parent->schq); 2205e6808b4SNaveen Mamindlapalli 2215e6808b4SNaveen Mamindlapalli cfg->regval[0] = (u64)parent->prio_anchor << 32; 22247a9656fSNaveen Mamindlapalli cfg->regval[0] |= ((parent->child_dwrr_prio != OTX2_QOS_DEFAULT_PRIO) ? 22347a9656fSNaveen Mamindlapalli parent->child_dwrr_prio : 0) << 1; 2245e6808b4SNaveen Mamindlapalli cfg->num_regs++; 2255e6808b4SNaveen Mamindlapalli 2265e6808b4SNaveen Mamindlapalli rc = otx2_sync_mbox_msg(&pfvf->mbox); 2275e6808b4SNaveen Mamindlapalli 2285e6808b4SNaveen Mamindlapalli mutex_unlock(&mbox->lock); 2295e6808b4SNaveen Mamindlapalli 2305e6808b4SNaveen Mamindlapalli return rc; 2315e6808b4SNaveen Mamindlapalli } 2325e6808b4SNaveen Mamindlapalli 2335e6808b4SNaveen Mamindlapalli static void otx2_qos_free_hw_node_schq(struct otx2_nic *pfvf, 2345e6808b4SNaveen Mamindlapalli struct otx2_qos_node *parent) 2355e6808b4SNaveen Mamindlapalli { 2365e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node; 2375e6808b4SNaveen Mamindlapalli 2385e6808b4SNaveen Mamindlapalli list_for_each_entry_reverse(node, &parent->child_schq_list, list) 2395e6808b4SNaveen Mamindlapalli otx2_txschq_free_one(pfvf, node->level, node->schq); 2405e6808b4SNaveen Mamindlapalli } 2415e6808b4SNaveen Mamindlapalli 2425e6808b4SNaveen Mamindlapalli static void otx2_qos_free_hw_node(struct otx2_nic *pfvf, 2435e6808b4SNaveen Mamindlapalli struct otx2_qos_node *parent) 2445e6808b4SNaveen Mamindlapalli { 2455e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, *tmp; 2465e6808b4SNaveen Mamindlapalli 2475e6808b4SNaveen Mamindlapalli list_for_each_entry_safe(node, tmp, &parent->child_list, list) { 2485e6808b4SNaveen Mamindlapalli otx2_qos_free_hw_node(pfvf, node); 2495e6808b4SNaveen Mamindlapalli otx2_qos_free_hw_node_schq(pfvf, node); 2505e6808b4SNaveen Mamindlapalli otx2_txschq_free_one(pfvf, node->level, node->schq); 2515e6808b4SNaveen Mamindlapalli } 2525e6808b4SNaveen Mamindlapalli } 2535e6808b4SNaveen Mamindlapalli 2545e6808b4SNaveen Mamindlapalli static void otx2_qos_free_hw_cfg(struct otx2_nic *pfvf, 2555e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node) 2565e6808b4SNaveen Mamindlapalli { 2575e6808b4SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 2585e6808b4SNaveen Mamindlapalli 2595e6808b4SNaveen Mamindlapalli /* free child node hw mappings */ 2605e6808b4SNaveen Mamindlapalli otx2_qos_free_hw_node(pfvf, node); 2615e6808b4SNaveen Mamindlapalli otx2_qos_free_hw_node_schq(pfvf, node); 2625e6808b4SNaveen Mamindlapalli 2635e6808b4SNaveen Mamindlapalli /* free node hw mappings */ 2645e6808b4SNaveen Mamindlapalli otx2_txschq_free_one(pfvf, node->level, node->schq); 2655e6808b4SNaveen Mamindlapalli 2665e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 2675e6808b4SNaveen Mamindlapalli } 2685e6808b4SNaveen Mamindlapalli 2695e6808b4SNaveen Mamindlapalli static void otx2_qos_sw_node_delete(struct otx2_nic *pfvf, 2705e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node) 2715e6808b4SNaveen Mamindlapalli { 2725e6808b4SNaveen Mamindlapalli hash_del_rcu(&node->hlist); 2735e6808b4SNaveen Mamindlapalli 2745e6808b4SNaveen Mamindlapalli if (node->qid != OTX2_QOS_QID_INNER && node->qid != OTX2_QOS_QID_NONE) { 2755e6808b4SNaveen Mamindlapalli __clear_bit(node->qid, pfvf->qos.qos_sq_bmap); 2765e6808b4SNaveen Mamindlapalli otx2_qos_update_tx_netdev_queues(pfvf); 2775e6808b4SNaveen Mamindlapalli } 2785e6808b4SNaveen Mamindlapalli 2795e6808b4SNaveen Mamindlapalli list_del(&node->list); 2805e6808b4SNaveen Mamindlapalli kfree(node); 2815e6808b4SNaveen Mamindlapalli } 2825e6808b4SNaveen Mamindlapalli 2835e6808b4SNaveen Mamindlapalli static void otx2_qos_free_sw_node_schq(struct otx2_nic *pfvf, 2845e6808b4SNaveen Mamindlapalli struct otx2_qos_node *parent) 2855e6808b4SNaveen Mamindlapalli { 2865e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, *tmp; 2875e6808b4SNaveen Mamindlapalli 2885e6808b4SNaveen Mamindlapalli list_for_each_entry_safe(node, tmp, &parent->child_schq_list, list) { 2895e6808b4SNaveen Mamindlapalli list_del(&node->list); 2905e6808b4SNaveen Mamindlapalli kfree(node); 2915e6808b4SNaveen Mamindlapalli } 2925e6808b4SNaveen Mamindlapalli } 2935e6808b4SNaveen Mamindlapalli 2945e6808b4SNaveen Mamindlapalli static void __otx2_qos_free_sw_node(struct otx2_nic *pfvf, 2955e6808b4SNaveen Mamindlapalli struct otx2_qos_node *parent) 2965e6808b4SNaveen Mamindlapalli { 2975e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, *tmp; 2985e6808b4SNaveen Mamindlapalli 2995e6808b4SNaveen Mamindlapalli list_for_each_entry_safe(node, tmp, &parent->child_list, list) { 3005e6808b4SNaveen Mamindlapalli __otx2_qos_free_sw_node(pfvf, node); 3015e6808b4SNaveen Mamindlapalli otx2_qos_free_sw_node_schq(pfvf, node); 3025e6808b4SNaveen Mamindlapalli otx2_qos_sw_node_delete(pfvf, node); 3035e6808b4SNaveen Mamindlapalli } 3045e6808b4SNaveen Mamindlapalli } 3055e6808b4SNaveen Mamindlapalli 3065e6808b4SNaveen Mamindlapalli static void otx2_qos_free_sw_node(struct otx2_nic *pfvf, 3075e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node) 3085e6808b4SNaveen Mamindlapalli { 3095e6808b4SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 3105e6808b4SNaveen Mamindlapalli 3115e6808b4SNaveen Mamindlapalli __otx2_qos_free_sw_node(pfvf, node); 3125e6808b4SNaveen Mamindlapalli otx2_qos_free_sw_node_schq(pfvf, node); 3135e6808b4SNaveen Mamindlapalli otx2_qos_sw_node_delete(pfvf, node); 3145e6808b4SNaveen Mamindlapalli 3155e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 3165e6808b4SNaveen Mamindlapalli } 3175e6808b4SNaveen Mamindlapalli 3185e6808b4SNaveen Mamindlapalli static void otx2_qos_destroy_node(struct otx2_nic *pfvf, 3195e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node) 3205e6808b4SNaveen Mamindlapalli { 3215e6808b4SNaveen Mamindlapalli otx2_qos_free_hw_cfg(pfvf, node); 3225e6808b4SNaveen Mamindlapalli otx2_qos_free_sw_node(pfvf, node); 3235e6808b4SNaveen Mamindlapalli } 3245e6808b4SNaveen Mamindlapalli 3255e6808b4SNaveen Mamindlapalli static void otx2_qos_fill_cfg_schq(struct otx2_qos_node *parent, 3265e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 3275e6808b4SNaveen Mamindlapalli { 3285e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node; 3295e6808b4SNaveen Mamindlapalli 3305e6808b4SNaveen Mamindlapalli list_for_each_entry(node, &parent->child_schq_list, list) 3315e6808b4SNaveen Mamindlapalli cfg->schq[node->level]++; 3325e6808b4SNaveen Mamindlapalli } 3335e6808b4SNaveen Mamindlapalli 3345e6808b4SNaveen Mamindlapalli static void otx2_qos_fill_cfg_tl(struct otx2_qos_node *parent, 3355e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 3365e6808b4SNaveen Mamindlapalli { 3375e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node; 3385e6808b4SNaveen Mamindlapalli 3395e6808b4SNaveen Mamindlapalli list_for_each_entry(node, &parent->child_list, list) { 3405e6808b4SNaveen Mamindlapalli otx2_qos_fill_cfg_tl(node, cfg); 3415e6808b4SNaveen Mamindlapalli otx2_qos_fill_cfg_schq(node, cfg); 3425e6808b4SNaveen Mamindlapalli } 343f78dca69SNaveen Mamindlapalli 344f78dca69SNaveen Mamindlapalli /* Assign the required number of transmit schedular queues under the 345f78dca69SNaveen Mamindlapalli * given class 346f78dca69SNaveen Mamindlapalli */ 347f78dca69SNaveen Mamindlapalli cfg->schq_contig[parent->level - 1] += parent->child_dwrr_cnt + 348f78dca69SNaveen Mamindlapalli parent->max_static_prio + 1; 3495e6808b4SNaveen Mamindlapalli } 3505e6808b4SNaveen Mamindlapalli 3515e6808b4SNaveen Mamindlapalli static void otx2_qos_prepare_txschq_cfg(struct otx2_nic *pfvf, 3525e6808b4SNaveen Mamindlapalli struct otx2_qos_node *parent, 3535e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 3545e6808b4SNaveen Mamindlapalli { 3555e6808b4SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 3565e6808b4SNaveen Mamindlapalli otx2_qos_fill_cfg_tl(parent, cfg); 3575e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 3585e6808b4SNaveen Mamindlapalli } 3595e6808b4SNaveen Mamindlapalli 3605e6808b4SNaveen Mamindlapalli static void otx2_qos_read_txschq_cfg_schq(struct otx2_qos_node *parent, 3615e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 3625e6808b4SNaveen Mamindlapalli { 3635e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node; 3645e6808b4SNaveen Mamindlapalli int cnt; 3655e6808b4SNaveen Mamindlapalli 3665e6808b4SNaveen Mamindlapalli list_for_each_entry(node, &parent->child_schq_list, list) { 3675e6808b4SNaveen Mamindlapalli cnt = cfg->dwrr_node_pos[node->level]; 3685e6808b4SNaveen Mamindlapalli cfg->schq_list[node->level][cnt] = node->schq; 3695e6808b4SNaveen Mamindlapalli cfg->schq[node->level]++; 3705e6808b4SNaveen Mamindlapalli cfg->dwrr_node_pos[node->level]++; 3715e6808b4SNaveen Mamindlapalli } 3725e6808b4SNaveen Mamindlapalli } 3735e6808b4SNaveen Mamindlapalli 3745e6808b4SNaveen Mamindlapalli static void otx2_qos_read_txschq_cfg_tl(struct otx2_qos_node *parent, 3755e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 3765e6808b4SNaveen Mamindlapalli { 3775e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node; 3785e6808b4SNaveen Mamindlapalli int cnt; 3795e6808b4SNaveen Mamindlapalli 3805e6808b4SNaveen Mamindlapalli list_for_each_entry(node, &parent->child_list, list) { 3815e6808b4SNaveen Mamindlapalli otx2_qos_read_txschq_cfg_tl(node, cfg); 3825e6808b4SNaveen Mamindlapalli cnt = cfg->static_node_pos[node->level]; 3835e6808b4SNaveen Mamindlapalli cfg->schq_contig_list[node->level][cnt] = node->schq; 384bccb798eSHariprasad Kelam cfg->schq_index_used[node->level][cnt] = true; 3855e6808b4SNaveen Mamindlapalli cfg->schq_contig[node->level]++; 3865e6808b4SNaveen Mamindlapalli cfg->static_node_pos[node->level]++; 3875e6808b4SNaveen Mamindlapalli otx2_qos_read_txschq_cfg_schq(node, cfg); 3885e6808b4SNaveen Mamindlapalli } 3895e6808b4SNaveen Mamindlapalli } 3905e6808b4SNaveen Mamindlapalli 3915e6808b4SNaveen Mamindlapalli static void otx2_qos_read_txschq_cfg(struct otx2_nic *pfvf, 3925e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 3935e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 3945e6808b4SNaveen Mamindlapalli { 3955e6808b4SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 3965e6808b4SNaveen Mamindlapalli otx2_qos_read_txschq_cfg_tl(node, cfg); 3975e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 3985e6808b4SNaveen Mamindlapalli } 3995e6808b4SNaveen Mamindlapalli 4005e6808b4SNaveen Mamindlapalli static struct otx2_qos_node * 4015e6808b4SNaveen Mamindlapalli otx2_qos_alloc_root(struct otx2_nic *pfvf) 4025e6808b4SNaveen Mamindlapalli { 4035e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node; 4045e6808b4SNaveen Mamindlapalli 4055e6808b4SNaveen Mamindlapalli node = kzalloc(sizeof(*node), GFP_KERNEL); 4065e6808b4SNaveen Mamindlapalli if (!node) 4075e6808b4SNaveen Mamindlapalli return ERR_PTR(-ENOMEM); 4085e6808b4SNaveen Mamindlapalli 4095e6808b4SNaveen Mamindlapalli node->parent = NULL; 41047a9656fSNaveen Mamindlapalli if (!is_otx2_vf(pfvf->pcifunc)) { 4115e6808b4SNaveen Mamindlapalli node->level = NIX_TXSCH_LVL_TL1; 41247a9656fSNaveen Mamindlapalli } else { 4135e6808b4SNaveen Mamindlapalli node->level = NIX_TXSCH_LVL_TL2; 41447a9656fSNaveen Mamindlapalli node->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO; 41547a9656fSNaveen Mamindlapalli } 4165e6808b4SNaveen Mamindlapalli 4175e6808b4SNaveen Mamindlapalli WRITE_ONCE(node->qid, OTX2_QOS_QID_INNER); 4185e6808b4SNaveen Mamindlapalli node->classid = OTX2_QOS_ROOT_CLASSID; 4195e6808b4SNaveen Mamindlapalli 4205e6808b4SNaveen Mamindlapalli hash_add_rcu(pfvf->qos.qos_hlist, &node->hlist, node->classid); 4215e6808b4SNaveen Mamindlapalli list_add_tail(&node->list, &pfvf->qos.qos_tree); 4225e6808b4SNaveen Mamindlapalli INIT_LIST_HEAD(&node->child_list); 4235e6808b4SNaveen Mamindlapalli INIT_LIST_HEAD(&node->child_schq_list); 4245e6808b4SNaveen Mamindlapalli 4255e6808b4SNaveen Mamindlapalli return node; 4265e6808b4SNaveen Mamindlapalli } 4275e6808b4SNaveen Mamindlapalli 4285e6808b4SNaveen Mamindlapalli static int otx2_qos_add_child_node(struct otx2_qos_node *parent, 4295e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node) 4305e6808b4SNaveen Mamindlapalli { 4315e6808b4SNaveen Mamindlapalli struct list_head *head = &parent->child_list; 4325e6808b4SNaveen Mamindlapalli struct otx2_qos_node *tmp_node; 4335e6808b4SNaveen Mamindlapalli struct list_head *tmp; 4345e6808b4SNaveen Mamindlapalli 435f78dca69SNaveen Mamindlapalli if (node->prio > parent->max_static_prio) 436f78dca69SNaveen Mamindlapalli parent->max_static_prio = node->prio; 437f78dca69SNaveen Mamindlapalli 4385e6808b4SNaveen Mamindlapalli for (tmp = head->next; tmp != head; tmp = tmp->next) { 4395e6808b4SNaveen Mamindlapalli tmp_node = list_entry(tmp, struct otx2_qos_node, list); 440f78dca69SNaveen Mamindlapalli if (tmp_node->prio == node->prio && 441f78dca69SNaveen Mamindlapalli tmp_node->is_static) 4425e6808b4SNaveen Mamindlapalli return -EEXIST; 4435e6808b4SNaveen Mamindlapalli if (tmp_node->prio > node->prio) { 4445e6808b4SNaveen Mamindlapalli list_add_tail(&node->list, tmp); 4455e6808b4SNaveen Mamindlapalli return 0; 4465e6808b4SNaveen Mamindlapalli } 4475e6808b4SNaveen Mamindlapalli } 4485e6808b4SNaveen Mamindlapalli 4495e6808b4SNaveen Mamindlapalli list_add_tail(&node->list, head); 4505e6808b4SNaveen Mamindlapalli return 0; 4515e6808b4SNaveen Mamindlapalli } 4525e6808b4SNaveen Mamindlapalli 4535e6808b4SNaveen Mamindlapalli static int otx2_qos_alloc_txschq_node(struct otx2_nic *pfvf, 4545e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node) 4555e6808b4SNaveen Mamindlapalli { 4565e6808b4SNaveen Mamindlapalli struct otx2_qos_node *txschq_node, *parent, *tmp; 4575e6808b4SNaveen Mamindlapalli int lvl; 4585e6808b4SNaveen Mamindlapalli 4595e6808b4SNaveen Mamindlapalli parent = node; 4605e6808b4SNaveen Mamindlapalli for (lvl = node->level - 1; lvl >= NIX_TXSCH_LVL_MDQ; lvl--) { 4615e6808b4SNaveen Mamindlapalli txschq_node = kzalloc(sizeof(*txschq_node), GFP_KERNEL); 4625e6808b4SNaveen Mamindlapalli if (!txschq_node) 4635e6808b4SNaveen Mamindlapalli goto err_out; 4645e6808b4SNaveen Mamindlapalli 4655e6808b4SNaveen Mamindlapalli txschq_node->parent = parent; 4665e6808b4SNaveen Mamindlapalli txschq_node->level = lvl; 4675e6808b4SNaveen Mamindlapalli txschq_node->classid = OTX2_QOS_CLASS_NONE; 4685e6808b4SNaveen Mamindlapalli WRITE_ONCE(txschq_node->qid, OTX2_QOS_QID_NONE); 4695e6808b4SNaveen Mamindlapalli txschq_node->rate = 0; 4705e6808b4SNaveen Mamindlapalli txschq_node->ceil = 0; 4715e6808b4SNaveen Mamindlapalli txschq_node->prio = 0; 47247a9656fSNaveen Mamindlapalli txschq_node->quantum = 0; 47347a9656fSNaveen Mamindlapalli txschq_node->is_static = true; 47447a9656fSNaveen Mamindlapalli txschq_node->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO; 47547a9656fSNaveen Mamindlapalli txschq_node->txschq_idx = OTX2_QOS_INVALID_TXSCHQ_IDX; 4765e6808b4SNaveen Mamindlapalli 4775e6808b4SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 4785e6808b4SNaveen Mamindlapalli list_add_tail(&txschq_node->list, &node->child_schq_list); 4795e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 4805e6808b4SNaveen Mamindlapalli 4815e6808b4SNaveen Mamindlapalli INIT_LIST_HEAD(&txschq_node->child_list); 4825e6808b4SNaveen Mamindlapalli INIT_LIST_HEAD(&txschq_node->child_schq_list); 4835e6808b4SNaveen Mamindlapalli parent = txschq_node; 4845e6808b4SNaveen Mamindlapalli } 4855e6808b4SNaveen Mamindlapalli 4865e6808b4SNaveen Mamindlapalli return 0; 4875e6808b4SNaveen Mamindlapalli 4885e6808b4SNaveen Mamindlapalli err_out: 4895e6808b4SNaveen Mamindlapalli list_for_each_entry_safe(txschq_node, tmp, &node->child_schq_list, 4905e6808b4SNaveen Mamindlapalli list) { 4915e6808b4SNaveen Mamindlapalli list_del(&txschq_node->list); 4925e6808b4SNaveen Mamindlapalli kfree(txschq_node); 4935e6808b4SNaveen Mamindlapalli } 4945e6808b4SNaveen Mamindlapalli return -ENOMEM; 4955e6808b4SNaveen Mamindlapalli } 4965e6808b4SNaveen Mamindlapalli 4975e6808b4SNaveen Mamindlapalli static struct otx2_qos_node * 4985e6808b4SNaveen Mamindlapalli otx2_qos_sw_create_leaf_node(struct otx2_nic *pfvf, 4995e6808b4SNaveen Mamindlapalli struct otx2_qos_node *parent, 5005e6808b4SNaveen Mamindlapalli u16 classid, u32 prio, u64 rate, u64 ceil, 50147a9656fSNaveen Mamindlapalli u32 quantum, u16 qid, bool static_cfg) 5025e6808b4SNaveen Mamindlapalli { 5035e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node; 5045e6808b4SNaveen Mamindlapalli int err; 5055e6808b4SNaveen Mamindlapalli 5065e6808b4SNaveen Mamindlapalli node = kzalloc(sizeof(*node), GFP_KERNEL); 5075e6808b4SNaveen Mamindlapalli if (!node) 5085e6808b4SNaveen Mamindlapalli return ERR_PTR(-ENOMEM); 5095e6808b4SNaveen Mamindlapalli 5105e6808b4SNaveen Mamindlapalli node->parent = parent; 5115e6808b4SNaveen Mamindlapalli node->level = parent->level - 1; 5125e6808b4SNaveen Mamindlapalli node->classid = classid; 5135e6808b4SNaveen Mamindlapalli WRITE_ONCE(node->qid, qid); 5145e6808b4SNaveen Mamindlapalli 5155e6808b4SNaveen Mamindlapalli node->rate = otx2_convert_rate(rate); 5165e6808b4SNaveen Mamindlapalli node->ceil = otx2_convert_rate(ceil); 5175e6808b4SNaveen Mamindlapalli node->prio = prio; 51847a9656fSNaveen Mamindlapalli node->quantum = quantum; 51947a9656fSNaveen Mamindlapalli node->is_static = static_cfg; 52047a9656fSNaveen Mamindlapalli node->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO; 52147a9656fSNaveen Mamindlapalli node->txschq_idx = OTX2_QOS_INVALID_TXSCHQ_IDX; 5225e6808b4SNaveen Mamindlapalli 5235e6808b4SNaveen Mamindlapalli __set_bit(qid, pfvf->qos.qos_sq_bmap); 5245e6808b4SNaveen Mamindlapalli 5255e6808b4SNaveen Mamindlapalli hash_add_rcu(pfvf->qos.qos_hlist, &node->hlist, classid); 5265e6808b4SNaveen Mamindlapalli 5275e6808b4SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 5285e6808b4SNaveen Mamindlapalli err = otx2_qos_add_child_node(parent, node); 5295e6808b4SNaveen Mamindlapalli if (err) { 5305e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 5315e6808b4SNaveen Mamindlapalli return ERR_PTR(err); 5325e6808b4SNaveen Mamindlapalli } 5335e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 5345e6808b4SNaveen Mamindlapalli 5355e6808b4SNaveen Mamindlapalli INIT_LIST_HEAD(&node->child_list); 5365e6808b4SNaveen Mamindlapalli INIT_LIST_HEAD(&node->child_schq_list); 5375e6808b4SNaveen Mamindlapalli 5385e6808b4SNaveen Mamindlapalli err = otx2_qos_alloc_txschq_node(pfvf, node); 5395e6808b4SNaveen Mamindlapalli if (err) { 5405e6808b4SNaveen Mamindlapalli otx2_qos_sw_node_delete(pfvf, node); 5415e6808b4SNaveen Mamindlapalli return ERR_PTR(-ENOMEM); 5425e6808b4SNaveen Mamindlapalli } 5435e6808b4SNaveen Mamindlapalli 5445e6808b4SNaveen Mamindlapalli return node; 5455e6808b4SNaveen Mamindlapalli } 5465e6808b4SNaveen Mamindlapalli 54704fb71ccSHariprasad Kelam static struct otx2_qos_node 54804fb71ccSHariprasad Kelam *otx2_sw_node_find_by_qid(struct otx2_nic *pfvf, u16 qid) 54904fb71ccSHariprasad Kelam { 55004fb71ccSHariprasad Kelam struct otx2_qos_node *node = NULL; 55104fb71ccSHariprasad Kelam int bkt; 55204fb71ccSHariprasad Kelam 55304fb71ccSHariprasad Kelam hash_for_each(pfvf->qos.qos_hlist, bkt, node, hlist) { 55404fb71ccSHariprasad Kelam if (node->qid == qid) 55504fb71ccSHariprasad Kelam break; 55604fb71ccSHariprasad Kelam } 55704fb71ccSHariprasad Kelam 55804fb71ccSHariprasad Kelam return node; 55904fb71ccSHariprasad Kelam } 56004fb71ccSHariprasad Kelam 5615e6808b4SNaveen Mamindlapalli static struct otx2_qos_node * 5625e6808b4SNaveen Mamindlapalli otx2_sw_node_find(struct otx2_nic *pfvf, u32 classid) 5635e6808b4SNaveen Mamindlapalli { 5645e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node = NULL; 5655e6808b4SNaveen Mamindlapalli 5665e6808b4SNaveen Mamindlapalli hash_for_each_possible(pfvf->qos.qos_hlist, node, hlist, classid) { 5675e6808b4SNaveen Mamindlapalli if (node->classid == classid) 5685e6808b4SNaveen Mamindlapalli break; 5695e6808b4SNaveen Mamindlapalli } 5705e6808b4SNaveen Mamindlapalli 5715e6808b4SNaveen Mamindlapalli return node; 5725e6808b4SNaveen Mamindlapalli } 5735e6808b4SNaveen Mamindlapalli 5745e6808b4SNaveen Mamindlapalli static struct otx2_qos_node * 5755e6808b4SNaveen Mamindlapalli otx2_sw_node_find_rcu(struct otx2_nic *pfvf, u32 classid) 5765e6808b4SNaveen Mamindlapalli { 5775e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node = NULL; 5785e6808b4SNaveen Mamindlapalli 5795e6808b4SNaveen Mamindlapalli hash_for_each_possible_rcu(pfvf->qos.qos_hlist, node, hlist, classid) { 5805e6808b4SNaveen Mamindlapalli if (node->classid == classid) 5815e6808b4SNaveen Mamindlapalli break; 5825e6808b4SNaveen Mamindlapalli } 5835e6808b4SNaveen Mamindlapalli 5845e6808b4SNaveen Mamindlapalli return node; 5855e6808b4SNaveen Mamindlapalli } 5865e6808b4SNaveen Mamindlapalli 5875e6808b4SNaveen Mamindlapalli int otx2_get_txq_by_classid(struct otx2_nic *pfvf, u16 classid) 5885e6808b4SNaveen Mamindlapalli { 5895e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node; 5905e6808b4SNaveen Mamindlapalli u16 qid; 5915e6808b4SNaveen Mamindlapalli int res; 5925e6808b4SNaveen Mamindlapalli 5935e6808b4SNaveen Mamindlapalli node = otx2_sw_node_find_rcu(pfvf, classid); 5945e6808b4SNaveen Mamindlapalli if (!node) { 5955e6808b4SNaveen Mamindlapalli res = -ENOENT; 5965e6808b4SNaveen Mamindlapalli goto out; 5975e6808b4SNaveen Mamindlapalli } 5985e6808b4SNaveen Mamindlapalli qid = READ_ONCE(node->qid); 5995e6808b4SNaveen Mamindlapalli if (qid == OTX2_QOS_QID_INNER) { 6005e6808b4SNaveen Mamindlapalli res = -EINVAL; 6015e6808b4SNaveen Mamindlapalli goto out; 6025e6808b4SNaveen Mamindlapalli } 6035e6808b4SNaveen Mamindlapalli res = pfvf->hw.tx_queues + qid; 6045e6808b4SNaveen Mamindlapalli out: 6055e6808b4SNaveen Mamindlapalli return res; 6065e6808b4SNaveen Mamindlapalli } 6075e6808b4SNaveen Mamindlapalli 6085e6808b4SNaveen Mamindlapalli static int 6095e6808b4SNaveen Mamindlapalli otx2_qos_txschq_config(struct otx2_nic *pfvf, struct otx2_qos_node *node) 6105e6808b4SNaveen Mamindlapalli { 6115e6808b4SNaveen Mamindlapalli struct mbox *mbox = &pfvf->mbox; 6125e6808b4SNaveen Mamindlapalli struct nix_txschq_config *req; 6135e6808b4SNaveen Mamindlapalli int rc; 6145e6808b4SNaveen Mamindlapalli 6155e6808b4SNaveen Mamindlapalli mutex_lock(&mbox->lock); 6165e6808b4SNaveen Mamindlapalli 6175e6808b4SNaveen Mamindlapalli req = otx2_mbox_alloc_msg_nix_txschq_cfg(&pfvf->mbox); 6185e6808b4SNaveen Mamindlapalli if (!req) { 6195e6808b4SNaveen Mamindlapalli mutex_unlock(&mbox->lock); 6205e6808b4SNaveen Mamindlapalli return -ENOMEM; 6215e6808b4SNaveen Mamindlapalli } 6225e6808b4SNaveen Mamindlapalli 6235e6808b4SNaveen Mamindlapalli req->lvl = node->level; 6245e6808b4SNaveen Mamindlapalli __otx2_qos_txschq_cfg(pfvf, node, req); 6255e6808b4SNaveen Mamindlapalli 6265e6808b4SNaveen Mamindlapalli rc = otx2_sync_mbox_msg(&pfvf->mbox); 6275e6808b4SNaveen Mamindlapalli 6285e6808b4SNaveen Mamindlapalli mutex_unlock(&mbox->lock); 6295e6808b4SNaveen Mamindlapalli 6305e6808b4SNaveen Mamindlapalli return rc; 6315e6808b4SNaveen Mamindlapalli } 6325e6808b4SNaveen Mamindlapalli 6335e6808b4SNaveen Mamindlapalli static int otx2_qos_txschq_alloc(struct otx2_nic *pfvf, 6345e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 6355e6808b4SNaveen Mamindlapalli { 6365e6808b4SNaveen Mamindlapalli struct nix_txsch_alloc_req *req; 6375e6808b4SNaveen Mamindlapalli struct nix_txsch_alloc_rsp *rsp; 6385e6808b4SNaveen Mamindlapalli struct mbox *mbox = &pfvf->mbox; 6395e6808b4SNaveen Mamindlapalli int lvl, rc, schq; 6405e6808b4SNaveen Mamindlapalli 6415e6808b4SNaveen Mamindlapalli mutex_lock(&mbox->lock); 6425e6808b4SNaveen Mamindlapalli req = otx2_mbox_alloc_msg_nix_txsch_alloc(&pfvf->mbox); 6435e6808b4SNaveen Mamindlapalli if (!req) { 6445e6808b4SNaveen Mamindlapalli mutex_unlock(&mbox->lock); 6455e6808b4SNaveen Mamindlapalli return -ENOMEM; 6465e6808b4SNaveen Mamindlapalli } 6475e6808b4SNaveen Mamindlapalli 6485e6808b4SNaveen Mamindlapalli for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { 6495e6808b4SNaveen Mamindlapalli req->schq[lvl] = cfg->schq[lvl]; 6505e6808b4SNaveen Mamindlapalli req->schq_contig[lvl] = cfg->schq_contig[lvl]; 6515e6808b4SNaveen Mamindlapalli } 6525e6808b4SNaveen Mamindlapalli 6535e6808b4SNaveen Mamindlapalli rc = otx2_sync_mbox_msg(&pfvf->mbox); 6545e6808b4SNaveen Mamindlapalli if (rc) { 6555e6808b4SNaveen Mamindlapalli mutex_unlock(&mbox->lock); 6565e6808b4SNaveen Mamindlapalli return rc; 6575e6808b4SNaveen Mamindlapalli } 6585e6808b4SNaveen Mamindlapalli 6595e6808b4SNaveen Mamindlapalli rsp = (struct nix_txsch_alloc_rsp *) 6605e6808b4SNaveen Mamindlapalli otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); 6615e6808b4SNaveen Mamindlapalli 6625e6808b4SNaveen Mamindlapalli if (IS_ERR(rsp)) { 6635e6808b4SNaveen Mamindlapalli rc = PTR_ERR(rsp); 6645e6808b4SNaveen Mamindlapalli goto out; 6655e6808b4SNaveen Mamindlapalli } 6665e6808b4SNaveen Mamindlapalli 6675e6808b4SNaveen Mamindlapalli for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { 6685e6808b4SNaveen Mamindlapalli for (schq = 0; schq < rsp->schq_contig[lvl]; schq++) { 6695e6808b4SNaveen Mamindlapalli cfg->schq_contig_list[lvl][schq] = 6705e6808b4SNaveen Mamindlapalli rsp->schq_contig_list[lvl][schq]; 6715e6808b4SNaveen Mamindlapalli } 6725e6808b4SNaveen Mamindlapalli } 6735e6808b4SNaveen Mamindlapalli 6745e6808b4SNaveen Mamindlapalli for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { 6755e6808b4SNaveen Mamindlapalli for (schq = 0; schq < rsp->schq[lvl]; schq++) { 6765e6808b4SNaveen Mamindlapalli cfg->schq_list[lvl][schq] = 6775e6808b4SNaveen Mamindlapalli rsp->schq_list[lvl][schq]; 6785e6808b4SNaveen Mamindlapalli } 6795e6808b4SNaveen Mamindlapalli } 6805e6808b4SNaveen Mamindlapalli 6815e6808b4SNaveen Mamindlapalli pfvf->qos.link_cfg_lvl = rsp->link_cfg_lvl; 68247a9656fSNaveen Mamindlapalli pfvf->hw.txschq_aggr_lvl_rr_prio = rsp->aggr_lvl_rr_prio; 6835e6808b4SNaveen Mamindlapalli 6845e6808b4SNaveen Mamindlapalli out: 6855e6808b4SNaveen Mamindlapalli mutex_unlock(&mbox->lock); 6865e6808b4SNaveen Mamindlapalli return rc; 6875e6808b4SNaveen Mamindlapalli } 6885e6808b4SNaveen Mamindlapalli 689f78dca69SNaveen Mamindlapalli static void otx2_qos_free_unused_txschq(struct otx2_nic *pfvf, 690f78dca69SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 691f78dca69SNaveen Mamindlapalli { 692f78dca69SNaveen Mamindlapalli int lvl, idx, schq; 693f78dca69SNaveen Mamindlapalli 694f78dca69SNaveen Mamindlapalli for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { 695f78dca69SNaveen Mamindlapalli for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) { 696f78dca69SNaveen Mamindlapalli if (!cfg->schq_index_used[lvl][idx]) { 697f78dca69SNaveen Mamindlapalli schq = cfg->schq_contig_list[lvl][idx]; 698f78dca69SNaveen Mamindlapalli otx2_txschq_free_one(pfvf, lvl, schq); 699f78dca69SNaveen Mamindlapalli } 700f78dca69SNaveen Mamindlapalli } 701f78dca69SNaveen Mamindlapalli } 702f78dca69SNaveen Mamindlapalli } 703f78dca69SNaveen Mamindlapalli 7045e6808b4SNaveen Mamindlapalli static void otx2_qos_txschq_fill_cfg_schq(struct otx2_nic *pfvf, 7055e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 7065e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 7075e6808b4SNaveen Mamindlapalli { 7085e6808b4SNaveen Mamindlapalli struct otx2_qos_node *tmp; 7095e6808b4SNaveen Mamindlapalli int cnt; 7105e6808b4SNaveen Mamindlapalli 7115e6808b4SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_schq_list, list) { 7125e6808b4SNaveen Mamindlapalli cnt = cfg->dwrr_node_pos[tmp->level]; 7135e6808b4SNaveen Mamindlapalli tmp->schq = cfg->schq_list[tmp->level][cnt]; 7145e6808b4SNaveen Mamindlapalli cfg->dwrr_node_pos[tmp->level]++; 7155e6808b4SNaveen Mamindlapalli } 7165e6808b4SNaveen Mamindlapalli } 7175e6808b4SNaveen Mamindlapalli 7185e6808b4SNaveen Mamindlapalli static void otx2_qos_txschq_fill_cfg_tl(struct otx2_nic *pfvf, 7195e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 7205e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 7215e6808b4SNaveen Mamindlapalli { 7225e6808b4SNaveen Mamindlapalli struct otx2_qos_node *tmp; 7235e6808b4SNaveen Mamindlapalli int cnt; 7245e6808b4SNaveen Mamindlapalli 7255e6808b4SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_list, list) { 7265e6808b4SNaveen Mamindlapalli otx2_qos_txschq_fill_cfg_tl(pfvf, tmp, cfg); 7275e6808b4SNaveen Mamindlapalli cnt = cfg->static_node_pos[tmp->level]; 728f78dca69SNaveen Mamindlapalli tmp->schq = cfg->schq_contig_list[tmp->level][tmp->txschq_idx]; 729f78dca69SNaveen Mamindlapalli cfg->schq_index_used[tmp->level][tmp->txschq_idx] = true; 7305e6808b4SNaveen Mamindlapalli if (cnt == 0) 731f78dca69SNaveen Mamindlapalli node->prio_anchor = 732f78dca69SNaveen Mamindlapalli cfg->schq_contig_list[tmp->level][0]; 7335e6808b4SNaveen Mamindlapalli cfg->static_node_pos[tmp->level]++; 7345e6808b4SNaveen Mamindlapalli otx2_qos_txschq_fill_cfg_schq(pfvf, tmp, cfg); 7355e6808b4SNaveen Mamindlapalli } 7365e6808b4SNaveen Mamindlapalli } 7375e6808b4SNaveen Mamindlapalli 7385e6808b4SNaveen Mamindlapalli static void otx2_qos_txschq_fill_cfg(struct otx2_nic *pfvf, 7395e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 7405e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 7415e6808b4SNaveen Mamindlapalli { 7425e6808b4SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 7435e6808b4SNaveen Mamindlapalli otx2_qos_txschq_fill_cfg_tl(pfvf, node, cfg); 7445e6808b4SNaveen Mamindlapalli otx2_qos_txschq_fill_cfg_schq(pfvf, node, cfg); 745f78dca69SNaveen Mamindlapalli otx2_qos_free_unused_txschq(pfvf, cfg); 7465e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 7475e6808b4SNaveen Mamindlapalli } 7485e6808b4SNaveen Mamindlapalli 749f78dca69SNaveen Mamindlapalli static void __otx2_qos_assign_base_idx_tl(struct otx2_nic *pfvf, 750f78dca69SNaveen Mamindlapalli struct otx2_qos_node *tmp, 751f78dca69SNaveen Mamindlapalli unsigned long *child_idx_bmap, 752f78dca69SNaveen Mamindlapalli int child_cnt) 753f78dca69SNaveen Mamindlapalli { 754f78dca69SNaveen Mamindlapalli int idx; 755f78dca69SNaveen Mamindlapalli 756f78dca69SNaveen Mamindlapalli if (tmp->txschq_idx != OTX2_QOS_INVALID_TXSCHQ_IDX) 757f78dca69SNaveen Mamindlapalli return; 758f78dca69SNaveen Mamindlapalli 759f78dca69SNaveen Mamindlapalli /* assign static nodes 1:1 prio mapping first, then remaining nodes */ 760f78dca69SNaveen Mamindlapalli for (idx = 0; idx < child_cnt; idx++) { 761f78dca69SNaveen Mamindlapalli if (tmp->is_static && tmp->prio == idx && 762f78dca69SNaveen Mamindlapalli !test_bit(idx, child_idx_bmap)) { 763f78dca69SNaveen Mamindlapalli tmp->txschq_idx = idx; 764f78dca69SNaveen Mamindlapalli set_bit(idx, child_idx_bmap); 765f78dca69SNaveen Mamindlapalli return; 766f78dca69SNaveen Mamindlapalli } else if (!tmp->is_static && idx >= tmp->prio && 767f78dca69SNaveen Mamindlapalli !test_bit(idx, child_idx_bmap)) { 768f78dca69SNaveen Mamindlapalli tmp->txschq_idx = idx; 769f78dca69SNaveen Mamindlapalli set_bit(idx, child_idx_bmap); 770f78dca69SNaveen Mamindlapalli return; 771f78dca69SNaveen Mamindlapalli } 772f78dca69SNaveen Mamindlapalli } 773f78dca69SNaveen Mamindlapalli } 774f78dca69SNaveen Mamindlapalli 775f78dca69SNaveen Mamindlapalli static int otx2_qos_assign_base_idx_tl(struct otx2_nic *pfvf, 776f78dca69SNaveen Mamindlapalli struct otx2_qos_node *node) 777f78dca69SNaveen Mamindlapalli { 778f78dca69SNaveen Mamindlapalli unsigned long *child_idx_bmap; 779f78dca69SNaveen Mamindlapalli struct otx2_qos_node *tmp; 780f78dca69SNaveen Mamindlapalli int child_cnt; 781f78dca69SNaveen Mamindlapalli 782f78dca69SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_list, list) 783f78dca69SNaveen Mamindlapalli tmp->txschq_idx = OTX2_QOS_INVALID_TXSCHQ_IDX; 784f78dca69SNaveen Mamindlapalli 785f78dca69SNaveen Mamindlapalli /* allocate child index array */ 786f78dca69SNaveen Mamindlapalli child_cnt = node->child_dwrr_cnt + node->max_static_prio + 1; 787f78dca69SNaveen Mamindlapalli child_idx_bmap = kcalloc(BITS_TO_LONGS(child_cnt), 788f78dca69SNaveen Mamindlapalli sizeof(unsigned long), 789f78dca69SNaveen Mamindlapalli GFP_KERNEL); 790f78dca69SNaveen Mamindlapalli if (!child_idx_bmap) 791f78dca69SNaveen Mamindlapalli return -ENOMEM; 792f78dca69SNaveen Mamindlapalli 793f78dca69SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_list, list) 794f78dca69SNaveen Mamindlapalli otx2_qos_assign_base_idx_tl(pfvf, tmp); 795f78dca69SNaveen Mamindlapalli 796f78dca69SNaveen Mamindlapalli /* assign base index of static priority children first */ 797f78dca69SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_list, list) { 798f78dca69SNaveen Mamindlapalli if (!tmp->is_static) 799f78dca69SNaveen Mamindlapalli continue; 800f78dca69SNaveen Mamindlapalli __otx2_qos_assign_base_idx_tl(pfvf, tmp, child_idx_bmap, 801f78dca69SNaveen Mamindlapalli child_cnt); 802f78dca69SNaveen Mamindlapalli } 803f78dca69SNaveen Mamindlapalli 804f78dca69SNaveen Mamindlapalli /* assign base index of dwrr priority children */ 805f78dca69SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_list, list) 806f78dca69SNaveen Mamindlapalli __otx2_qos_assign_base_idx_tl(pfvf, tmp, child_idx_bmap, 807f78dca69SNaveen Mamindlapalli child_cnt); 808f78dca69SNaveen Mamindlapalli 809f78dca69SNaveen Mamindlapalli kfree(child_idx_bmap); 810f78dca69SNaveen Mamindlapalli 811f78dca69SNaveen Mamindlapalli return 0; 812f78dca69SNaveen Mamindlapalli } 813f78dca69SNaveen Mamindlapalli 814f78dca69SNaveen Mamindlapalli static int otx2_qos_assign_base_idx(struct otx2_nic *pfvf, 815f78dca69SNaveen Mamindlapalli struct otx2_qos_node *node) 816f78dca69SNaveen Mamindlapalli { 817f78dca69SNaveen Mamindlapalli int ret = 0; 818f78dca69SNaveen Mamindlapalli 819f78dca69SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 820f78dca69SNaveen Mamindlapalli ret = otx2_qos_assign_base_idx_tl(pfvf, node); 821f78dca69SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 822f78dca69SNaveen Mamindlapalli 823f78dca69SNaveen Mamindlapalli return ret; 824f78dca69SNaveen Mamindlapalli } 825f78dca69SNaveen Mamindlapalli 8265e6808b4SNaveen Mamindlapalli static int otx2_qos_txschq_push_cfg_schq(struct otx2_nic *pfvf, 8275e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 8285e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 8295e6808b4SNaveen Mamindlapalli { 8305e6808b4SNaveen Mamindlapalli struct otx2_qos_node *tmp; 8315e6808b4SNaveen Mamindlapalli int ret; 8325e6808b4SNaveen Mamindlapalli 8335e6808b4SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_schq_list, list) { 8345e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_config(pfvf, tmp); 8355e6808b4SNaveen Mamindlapalli if (ret) 8365e6808b4SNaveen Mamindlapalli return -EIO; 8375e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_set_parent_topology(pfvf, tmp->parent); 8385e6808b4SNaveen Mamindlapalli if (ret) 8395e6808b4SNaveen Mamindlapalli return -EIO; 8405e6808b4SNaveen Mamindlapalli } 8415e6808b4SNaveen Mamindlapalli 8425e6808b4SNaveen Mamindlapalli return 0; 8435e6808b4SNaveen Mamindlapalli } 8445e6808b4SNaveen Mamindlapalli 8455e6808b4SNaveen Mamindlapalli static int otx2_qos_txschq_push_cfg_tl(struct otx2_nic *pfvf, 8465e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 8475e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 8485e6808b4SNaveen Mamindlapalli { 8495e6808b4SNaveen Mamindlapalli struct otx2_qos_node *tmp; 8505e6808b4SNaveen Mamindlapalli int ret; 8515e6808b4SNaveen Mamindlapalli 8525e6808b4SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_list, list) { 8535e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_push_cfg_tl(pfvf, tmp, cfg); 8545e6808b4SNaveen Mamindlapalli if (ret) 8555e6808b4SNaveen Mamindlapalli return -EIO; 8565e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_config(pfvf, tmp); 8575e6808b4SNaveen Mamindlapalli if (ret) 8585e6808b4SNaveen Mamindlapalli return -EIO; 8595e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_push_cfg_schq(pfvf, tmp, cfg); 8605e6808b4SNaveen Mamindlapalli if (ret) 8615e6808b4SNaveen Mamindlapalli return -EIO; 8625e6808b4SNaveen Mamindlapalli } 8635e6808b4SNaveen Mamindlapalli 8645e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_set_parent_topology(pfvf, node); 8655e6808b4SNaveen Mamindlapalli if (ret) 8665e6808b4SNaveen Mamindlapalli return -EIO; 8675e6808b4SNaveen Mamindlapalli 8685e6808b4SNaveen Mamindlapalli return 0; 8695e6808b4SNaveen Mamindlapalli } 8705e6808b4SNaveen Mamindlapalli 8715e6808b4SNaveen Mamindlapalli static int otx2_qos_txschq_push_cfg(struct otx2_nic *pfvf, 8725e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 8735e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 8745e6808b4SNaveen Mamindlapalli { 8755e6808b4SNaveen Mamindlapalli int ret; 8765e6808b4SNaveen Mamindlapalli 8775e6808b4SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 8785e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_push_cfg_tl(pfvf, node, cfg); 8795e6808b4SNaveen Mamindlapalli if (ret) 8805e6808b4SNaveen Mamindlapalli goto out; 8815e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_push_cfg_schq(pfvf, node, cfg); 8825e6808b4SNaveen Mamindlapalli out: 8835e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 8845e6808b4SNaveen Mamindlapalli return ret; 8855e6808b4SNaveen Mamindlapalli } 8865e6808b4SNaveen Mamindlapalli 8875e6808b4SNaveen Mamindlapalli static int otx2_qos_txschq_update_config(struct otx2_nic *pfvf, 8885e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 8895e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 8905e6808b4SNaveen Mamindlapalli { 8915e6808b4SNaveen Mamindlapalli otx2_qos_txschq_fill_cfg(pfvf, node, cfg); 8925e6808b4SNaveen Mamindlapalli 8935e6808b4SNaveen Mamindlapalli return otx2_qos_txschq_push_cfg(pfvf, node, cfg); 8945e6808b4SNaveen Mamindlapalli } 8955e6808b4SNaveen Mamindlapalli 8965e6808b4SNaveen Mamindlapalli static int otx2_qos_txschq_update_root_cfg(struct otx2_nic *pfvf, 8975e6808b4SNaveen Mamindlapalli struct otx2_qos_node *root, 8985e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 8995e6808b4SNaveen Mamindlapalli { 9005e6808b4SNaveen Mamindlapalli root->schq = cfg->schq_list[root->level][0]; 9015e6808b4SNaveen Mamindlapalli return otx2_qos_txschq_config(pfvf, root); 9025e6808b4SNaveen Mamindlapalli } 9035e6808b4SNaveen Mamindlapalli 9045e6808b4SNaveen Mamindlapalli static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg) 9055e6808b4SNaveen Mamindlapalli { 9065e6808b4SNaveen Mamindlapalli int lvl, idx, schq; 9075e6808b4SNaveen Mamindlapalli 9085e6808b4SNaveen Mamindlapalli for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { 9095e6808b4SNaveen Mamindlapalli for (idx = 0; idx < cfg->schq[lvl]; idx++) { 9105e6808b4SNaveen Mamindlapalli schq = cfg->schq_list[lvl][idx]; 9115e6808b4SNaveen Mamindlapalli otx2_txschq_free_one(pfvf, lvl, schq); 9125e6808b4SNaveen Mamindlapalli } 9135e6808b4SNaveen Mamindlapalli } 9145e6808b4SNaveen Mamindlapalli 9155e6808b4SNaveen Mamindlapalli for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { 9165e6808b4SNaveen Mamindlapalli for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) { 917f78dca69SNaveen Mamindlapalli if (cfg->schq_index_used[lvl][idx]) { 9185e6808b4SNaveen Mamindlapalli schq = cfg->schq_contig_list[lvl][idx]; 9195e6808b4SNaveen Mamindlapalli otx2_txschq_free_one(pfvf, lvl, schq); 9205e6808b4SNaveen Mamindlapalli } 9215e6808b4SNaveen Mamindlapalli } 9225e6808b4SNaveen Mamindlapalli } 923f78dca69SNaveen Mamindlapalli } 9245e6808b4SNaveen Mamindlapalli 9255e6808b4SNaveen Mamindlapalli static void otx2_qos_enadis_sq(struct otx2_nic *pfvf, 9265e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 9275e6808b4SNaveen Mamindlapalli u16 qid) 9285e6808b4SNaveen Mamindlapalli { 9295e6808b4SNaveen Mamindlapalli if (pfvf->qos.qid_to_sqmap[qid] != OTX2_QOS_INVALID_SQ) 9305e6808b4SNaveen Mamindlapalli otx2_qos_disable_sq(pfvf, qid); 9315e6808b4SNaveen Mamindlapalli 9325e6808b4SNaveen Mamindlapalli pfvf->qos.qid_to_sqmap[qid] = node->schq; 93304fb71ccSHariprasad Kelam otx2_qos_txschq_config(pfvf, node); 9345e6808b4SNaveen Mamindlapalli otx2_qos_enable_sq(pfvf, qid); 9355e6808b4SNaveen Mamindlapalli } 9365e6808b4SNaveen Mamindlapalli 9375e6808b4SNaveen Mamindlapalli static void otx2_qos_update_smq_schq(struct otx2_nic *pfvf, 9385e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 9395e6808b4SNaveen Mamindlapalli bool action) 9405e6808b4SNaveen Mamindlapalli { 9415e6808b4SNaveen Mamindlapalli struct otx2_qos_node *tmp; 9425e6808b4SNaveen Mamindlapalli 9435e6808b4SNaveen Mamindlapalli if (node->qid == OTX2_QOS_QID_INNER) 9445e6808b4SNaveen Mamindlapalli return; 9455e6808b4SNaveen Mamindlapalli 9465e6808b4SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_schq_list, list) { 9475e6808b4SNaveen Mamindlapalli if (tmp->level == NIX_TXSCH_LVL_MDQ) { 9485e6808b4SNaveen Mamindlapalli if (action == QOS_SMQ_FLUSH) 9495e6808b4SNaveen Mamindlapalli otx2_smq_flush(pfvf, tmp->schq); 9505e6808b4SNaveen Mamindlapalli else 9515e6808b4SNaveen Mamindlapalli otx2_qos_enadis_sq(pfvf, tmp, node->qid); 9525e6808b4SNaveen Mamindlapalli } 9535e6808b4SNaveen Mamindlapalli } 9545e6808b4SNaveen Mamindlapalli } 9555e6808b4SNaveen Mamindlapalli 9565e6808b4SNaveen Mamindlapalli static void __otx2_qos_update_smq(struct otx2_nic *pfvf, 9575e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 9585e6808b4SNaveen Mamindlapalli bool action) 9595e6808b4SNaveen Mamindlapalli { 9605e6808b4SNaveen Mamindlapalli struct otx2_qos_node *tmp; 9615e6808b4SNaveen Mamindlapalli 9625e6808b4SNaveen Mamindlapalli list_for_each_entry(tmp, &node->child_list, list) { 9635e6808b4SNaveen Mamindlapalli __otx2_qos_update_smq(pfvf, tmp, action); 9645e6808b4SNaveen Mamindlapalli if (tmp->qid == OTX2_QOS_QID_INNER) 9655e6808b4SNaveen Mamindlapalli continue; 9665e6808b4SNaveen Mamindlapalli if (tmp->level == NIX_TXSCH_LVL_MDQ) { 9675e6808b4SNaveen Mamindlapalli if (action == QOS_SMQ_FLUSH) 9685e6808b4SNaveen Mamindlapalli otx2_smq_flush(pfvf, tmp->schq); 9695e6808b4SNaveen Mamindlapalli else 9705e6808b4SNaveen Mamindlapalli otx2_qos_enadis_sq(pfvf, tmp, tmp->qid); 9715e6808b4SNaveen Mamindlapalli } else { 9725e6808b4SNaveen Mamindlapalli otx2_qos_update_smq_schq(pfvf, tmp, action); 9735e6808b4SNaveen Mamindlapalli } 9745e6808b4SNaveen Mamindlapalli } 9755e6808b4SNaveen Mamindlapalli } 9765e6808b4SNaveen Mamindlapalli 9775e6808b4SNaveen Mamindlapalli static void otx2_qos_update_smq(struct otx2_nic *pfvf, 9785e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 9795e6808b4SNaveen Mamindlapalli bool action) 9805e6808b4SNaveen Mamindlapalli { 9815e6808b4SNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 9825e6808b4SNaveen Mamindlapalli __otx2_qos_update_smq(pfvf, node, action); 9835e6808b4SNaveen Mamindlapalli otx2_qos_update_smq_schq(pfvf, node, action); 9845e6808b4SNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 9855e6808b4SNaveen Mamindlapalli } 9865e6808b4SNaveen Mamindlapalli 9875e6808b4SNaveen Mamindlapalli static int otx2_qos_push_txschq_cfg(struct otx2_nic *pfvf, 9885e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 9895e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 9905e6808b4SNaveen Mamindlapalli { 9915e6808b4SNaveen Mamindlapalli int ret; 9925e6808b4SNaveen Mamindlapalli 9935e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_alloc(pfvf, cfg); 9945e6808b4SNaveen Mamindlapalli if (ret) 9955e6808b4SNaveen Mamindlapalli return -ENOSPC; 9965e6808b4SNaveen Mamindlapalli 997f78dca69SNaveen Mamindlapalli ret = otx2_qos_assign_base_idx(pfvf, node); 998f78dca69SNaveen Mamindlapalli if (ret) 999f78dca69SNaveen Mamindlapalli return -ENOMEM; 1000f78dca69SNaveen Mamindlapalli 10015e6808b4SNaveen Mamindlapalli if (!(pfvf->netdev->flags & IFF_UP)) { 10025e6808b4SNaveen Mamindlapalli otx2_qos_txschq_fill_cfg(pfvf, node, cfg); 10035e6808b4SNaveen Mamindlapalli return 0; 10045e6808b4SNaveen Mamindlapalli } 10055e6808b4SNaveen Mamindlapalli 10065e6808b4SNaveen Mamindlapalli ret = otx2_qos_txschq_update_config(pfvf, node, cfg); 10075e6808b4SNaveen Mamindlapalli if (ret) { 10085e6808b4SNaveen Mamindlapalli otx2_qos_free_cfg(pfvf, cfg); 10095e6808b4SNaveen Mamindlapalli return -EIO; 10105e6808b4SNaveen Mamindlapalli } 10115e6808b4SNaveen Mamindlapalli 10125e6808b4SNaveen Mamindlapalli otx2_qos_update_smq(pfvf, node, QOS_CFG_SQ); 10135e6808b4SNaveen Mamindlapalli 10145e6808b4SNaveen Mamindlapalli return 0; 10155e6808b4SNaveen Mamindlapalli } 10165e6808b4SNaveen Mamindlapalli 10175e6808b4SNaveen Mamindlapalli static int otx2_qos_update_tree(struct otx2_nic *pfvf, 10185e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, 10195e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *cfg) 10205e6808b4SNaveen Mamindlapalli { 10215e6808b4SNaveen Mamindlapalli otx2_qos_prepare_txschq_cfg(pfvf, node->parent, cfg); 10225e6808b4SNaveen Mamindlapalli return otx2_qos_push_txschq_cfg(pfvf, node->parent, cfg); 10235e6808b4SNaveen Mamindlapalli } 10245e6808b4SNaveen Mamindlapalli 10255e6808b4SNaveen Mamindlapalli static int otx2_qos_root_add(struct otx2_nic *pfvf, u16 htb_maj_id, u16 htb_defcls, 10265e6808b4SNaveen Mamindlapalli struct netlink_ext_ack *extack) 10275e6808b4SNaveen Mamindlapalli { 10285e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *new_cfg; 10295e6808b4SNaveen Mamindlapalli struct otx2_qos_node *root; 10305e6808b4SNaveen Mamindlapalli int err; 10315e6808b4SNaveen Mamindlapalli 10325e6808b4SNaveen Mamindlapalli netdev_dbg(pfvf->netdev, 10335e6808b4SNaveen Mamindlapalli "TC_HTB_CREATE: handle=0x%x defcls=0x%x\n", 10345e6808b4SNaveen Mamindlapalli htb_maj_id, htb_defcls); 10355e6808b4SNaveen Mamindlapalli 10365e6808b4SNaveen Mamindlapalli root = otx2_qos_alloc_root(pfvf); 10375e6808b4SNaveen Mamindlapalli if (IS_ERR(root)) { 10385e6808b4SNaveen Mamindlapalli err = PTR_ERR(root); 10395e6808b4SNaveen Mamindlapalli return err; 10405e6808b4SNaveen Mamindlapalli } 10415e6808b4SNaveen Mamindlapalli 10425e6808b4SNaveen Mamindlapalli /* allocate txschq queue */ 10435e6808b4SNaveen Mamindlapalli new_cfg = kzalloc(sizeof(*new_cfg), GFP_KERNEL); 10445e6808b4SNaveen Mamindlapalli if (!new_cfg) { 10455e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); 10465e6808b4SNaveen Mamindlapalli err = -ENOMEM; 10475e6808b4SNaveen Mamindlapalli goto free_root_node; 10485e6808b4SNaveen Mamindlapalli } 10495e6808b4SNaveen Mamindlapalli /* allocate htb root node */ 10505e6808b4SNaveen Mamindlapalli new_cfg->schq[root->level] = 1; 10515e6808b4SNaveen Mamindlapalli err = otx2_qos_txschq_alloc(pfvf, new_cfg); 10525e6808b4SNaveen Mamindlapalli if (err) { 10535e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Error allocating txschq"); 10545e6808b4SNaveen Mamindlapalli goto free_root_node; 10555e6808b4SNaveen Mamindlapalli } 10565e6808b4SNaveen Mamindlapalli 105747a9656fSNaveen Mamindlapalli /* Update TL1 RR PRIO */ 105847a9656fSNaveen Mamindlapalli if (root->level == NIX_TXSCH_LVL_TL1) { 105947a9656fSNaveen Mamindlapalli root->child_dwrr_prio = pfvf->hw.txschq_aggr_lvl_rr_prio; 106047a9656fSNaveen Mamindlapalli netdev_dbg(pfvf->netdev, 106147a9656fSNaveen Mamindlapalli "TL1 DWRR Priority %d\n", root->child_dwrr_prio); 106247a9656fSNaveen Mamindlapalli } 106347a9656fSNaveen Mamindlapalli 10645e6808b4SNaveen Mamindlapalli if (!(pfvf->netdev->flags & IFF_UP) || 10655e6808b4SNaveen Mamindlapalli root->level == NIX_TXSCH_LVL_TL1) { 10665e6808b4SNaveen Mamindlapalli root->schq = new_cfg->schq_list[root->level][0]; 10675e6808b4SNaveen Mamindlapalli goto out; 10685e6808b4SNaveen Mamindlapalli } 10695e6808b4SNaveen Mamindlapalli 10705e6808b4SNaveen Mamindlapalli /* update the txschq configuration in hw */ 10715e6808b4SNaveen Mamindlapalli err = otx2_qos_txschq_update_root_cfg(pfvf, root, new_cfg); 10725e6808b4SNaveen Mamindlapalli if (err) { 10735e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, 10745e6808b4SNaveen Mamindlapalli "Error updating txschq configuration"); 10755e6808b4SNaveen Mamindlapalli goto txschq_free; 10765e6808b4SNaveen Mamindlapalli } 10775e6808b4SNaveen Mamindlapalli 10785e6808b4SNaveen Mamindlapalli out: 10795e6808b4SNaveen Mamindlapalli WRITE_ONCE(pfvf->qos.defcls, htb_defcls); 10805e6808b4SNaveen Mamindlapalli /* Pairs with smp_load_acquire() in ndo_select_queue */ 10815e6808b4SNaveen Mamindlapalli smp_store_release(&pfvf->qos.maj_id, htb_maj_id); 10825e6808b4SNaveen Mamindlapalli kfree(new_cfg); 10835e6808b4SNaveen Mamindlapalli return 0; 10845e6808b4SNaveen Mamindlapalli 10855e6808b4SNaveen Mamindlapalli txschq_free: 10865e6808b4SNaveen Mamindlapalli otx2_qos_free_cfg(pfvf, new_cfg); 10875e6808b4SNaveen Mamindlapalli free_root_node: 10885e6808b4SNaveen Mamindlapalli kfree(new_cfg); 10895e6808b4SNaveen Mamindlapalli otx2_qos_sw_node_delete(pfvf, root); 10905e6808b4SNaveen Mamindlapalli return err; 10915e6808b4SNaveen Mamindlapalli } 10925e6808b4SNaveen Mamindlapalli 10935e6808b4SNaveen Mamindlapalli static int otx2_qos_root_destroy(struct otx2_nic *pfvf) 10945e6808b4SNaveen Mamindlapalli { 10955e6808b4SNaveen Mamindlapalli struct otx2_qos_node *root; 10965e6808b4SNaveen Mamindlapalli 10975e6808b4SNaveen Mamindlapalli netdev_dbg(pfvf->netdev, "TC_HTB_DESTROY\n"); 10985e6808b4SNaveen Mamindlapalli 10995e6808b4SNaveen Mamindlapalli /* find root node */ 11005e6808b4SNaveen Mamindlapalli root = otx2_sw_node_find(pfvf, OTX2_QOS_ROOT_CLASSID); 11015e6808b4SNaveen Mamindlapalli if (!root) 11025e6808b4SNaveen Mamindlapalli return -ENOENT; 11035e6808b4SNaveen Mamindlapalli 11045e6808b4SNaveen Mamindlapalli /* free the hw mappings */ 11055e6808b4SNaveen Mamindlapalli otx2_qos_destroy_node(pfvf, root); 11065e6808b4SNaveen Mamindlapalli 11075e6808b4SNaveen Mamindlapalli return 0; 11085e6808b4SNaveen Mamindlapalli } 11095e6808b4SNaveen Mamindlapalli 111047a9656fSNaveen Mamindlapalli static int otx2_qos_validate_quantum(struct otx2_nic *pfvf, u32 quantum) 11115e6808b4SNaveen Mamindlapalli { 111247a9656fSNaveen Mamindlapalli u32 rr_weight = otx2_qos_quantum_to_dwrr_weight(pfvf, quantum); 111347a9656fSNaveen Mamindlapalli int err = 0; 111447a9656fSNaveen Mamindlapalli 111547a9656fSNaveen Mamindlapalli /* Max Round robin weight supported by octeontx2 and CN10K 111647a9656fSNaveen Mamindlapalli * is different. Validate accordingly 111747a9656fSNaveen Mamindlapalli */ 111847a9656fSNaveen Mamindlapalli if (is_dev_otx2(pfvf->pdev)) 111947a9656fSNaveen Mamindlapalli err = (rr_weight > OTX2_MAX_RR_QUANTUM) ? -EINVAL : 0; 112047a9656fSNaveen Mamindlapalli else if (rr_weight > CN10K_MAX_RR_WEIGHT) 112147a9656fSNaveen Mamindlapalli err = -EINVAL; 112247a9656fSNaveen Mamindlapalli 112347a9656fSNaveen Mamindlapalli return err; 11245e6808b4SNaveen Mamindlapalli } 11255e6808b4SNaveen Mamindlapalli 112647a9656fSNaveen Mamindlapalli static int otx2_qos_validate_dwrr_cfg(struct otx2_qos_node *parent, 112747a9656fSNaveen Mamindlapalli struct netlink_ext_ack *extack, 112847a9656fSNaveen Mamindlapalli struct otx2_nic *pfvf, 112947a9656fSNaveen Mamindlapalli u64 prio, u64 quantum) 113047a9656fSNaveen Mamindlapalli { 113147a9656fSNaveen Mamindlapalli int err; 113247a9656fSNaveen Mamindlapalli 113347a9656fSNaveen Mamindlapalli err = otx2_qos_validate_quantum(pfvf, quantum); 113447a9656fSNaveen Mamindlapalli if (err) { 113547a9656fSNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Unsupported quantum value"); 113647a9656fSNaveen Mamindlapalli return err; 113747a9656fSNaveen Mamindlapalli } 113847a9656fSNaveen Mamindlapalli 113947a9656fSNaveen Mamindlapalli if (parent->child_dwrr_prio == OTX2_QOS_DEFAULT_PRIO) { 114047a9656fSNaveen Mamindlapalli parent->child_dwrr_prio = prio; 114147a9656fSNaveen Mamindlapalli } else if (prio != parent->child_dwrr_prio) { 114247a9656fSNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Only one DWRR group is allowed"); 114347a9656fSNaveen Mamindlapalli return -EOPNOTSUPP; 11445e6808b4SNaveen Mamindlapalli } 11455e6808b4SNaveen Mamindlapalli 11465e6808b4SNaveen Mamindlapalli return 0; 11475e6808b4SNaveen Mamindlapalli } 11485e6808b4SNaveen Mamindlapalli 114947a9656fSNaveen Mamindlapalli static int otx2_qos_validate_configuration(struct otx2_qos_node *parent, 115047a9656fSNaveen Mamindlapalli struct netlink_ext_ack *extack, 115147a9656fSNaveen Mamindlapalli struct otx2_nic *pfvf, 115247a9656fSNaveen Mamindlapalli u64 prio, bool static_cfg) 115347a9656fSNaveen Mamindlapalli { 115447a9656fSNaveen Mamindlapalli if (prio == parent->child_dwrr_prio && static_cfg) { 115547a9656fSNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "DWRR child group with same priority exists"); 115647a9656fSNaveen Mamindlapalli return -EEXIST; 115747a9656fSNaveen Mamindlapalli } 115847a9656fSNaveen Mamindlapalli 115947a9656fSNaveen Mamindlapalli if (static_cfg && test_bit(prio, parent->prio_bmap)) { 116047a9656fSNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, 116147a9656fSNaveen Mamindlapalli "Static priority child with same priority exists"); 116247a9656fSNaveen Mamindlapalli return -EEXIST; 116347a9656fSNaveen Mamindlapalli } 116447a9656fSNaveen Mamindlapalli 116547a9656fSNaveen Mamindlapalli return 0; 116647a9656fSNaveen Mamindlapalli } 116747a9656fSNaveen Mamindlapalli 116847a9656fSNaveen Mamindlapalli static void otx2_reset_dwrr_prio(struct otx2_qos_node *parent, u64 prio) 116947a9656fSNaveen Mamindlapalli { 117047a9656fSNaveen Mamindlapalli /* For PF, root node dwrr priority is static */ 117147a9656fSNaveen Mamindlapalli if (parent->level == NIX_TXSCH_LVL_TL1) 117247a9656fSNaveen Mamindlapalli return; 117347a9656fSNaveen Mamindlapalli 117447a9656fSNaveen Mamindlapalli if (parent->child_dwrr_prio != OTX2_QOS_DEFAULT_PRIO) { 117547a9656fSNaveen Mamindlapalli parent->child_dwrr_prio = OTX2_QOS_DEFAULT_PRIO; 117647a9656fSNaveen Mamindlapalli clear_bit(prio, parent->prio_bmap); 117747a9656fSNaveen Mamindlapalli } 117847a9656fSNaveen Mamindlapalli } 117947a9656fSNaveen Mamindlapalli 118047a9656fSNaveen Mamindlapalli static bool is_qos_node_dwrr(struct otx2_qos_node *parent, 118147a9656fSNaveen Mamindlapalli struct otx2_nic *pfvf, 118247a9656fSNaveen Mamindlapalli u64 prio) 118347a9656fSNaveen Mamindlapalli { 118447a9656fSNaveen Mamindlapalli struct otx2_qos_node *node; 118547a9656fSNaveen Mamindlapalli bool ret = false; 118647a9656fSNaveen Mamindlapalli 118747a9656fSNaveen Mamindlapalli if (parent->child_dwrr_prio == prio) 118847a9656fSNaveen Mamindlapalli return true; 118947a9656fSNaveen Mamindlapalli 119047a9656fSNaveen Mamindlapalli mutex_lock(&pfvf->qos.qos_lock); 119147a9656fSNaveen Mamindlapalli list_for_each_entry(node, &parent->child_list, list) { 119247a9656fSNaveen Mamindlapalli if (prio == node->prio) { 119347a9656fSNaveen Mamindlapalli if (parent->child_dwrr_prio != OTX2_QOS_DEFAULT_PRIO && 119447a9656fSNaveen Mamindlapalli parent->child_dwrr_prio != prio) 119547a9656fSNaveen Mamindlapalli continue; 119647a9656fSNaveen Mamindlapalli 119747a9656fSNaveen Mamindlapalli if (otx2_qos_validate_quantum(pfvf, node->quantum)) { 119847a9656fSNaveen Mamindlapalli netdev_err(pfvf->netdev, 119947a9656fSNaveen Mamindlapalli "Unsupported quantum value for existing classid=0x%x quantum=%d prio=%d", 120047a9656fSNaveen Mamindlapalli node->classid, node->quantum, 120147a9656fSNaveen Mamindlapalli node->prio); 120247a9656fSNaveen Mamindlapalli break; 120347a9656fSNaveen Mamindlapalli } 120447a9656fSNaveen Mamindlapalli /* mark old node as dwrr */ 120547a9656fSNaveen Mamindlapalli node->is_static = false; 120647a9656fSNaveen Mamindlapalli parent->child_dwrr_cnt++; 120747a9656fSNaveen Mamindlapalli parent->child_static_cnt--; 120847a9656fSNaveen Mamindlapalli ret = true; 120947a9656fSNaveen Mamindlapalli break; 121047a9656fSNaveen Mamindlapalli } 121147a9656fSNaveen Mamindlapalli } 121247a9656fSNaveen Mamindlapalli mutex_unlock(&pfvf->qos.qos_lock); 121347a9656fSNaveen Mamindlapalli 121447a9656fSNaveen Mamindlapalli return ret; 121547a9656fSNaveen Mamindlapalli } 121647a9656fSNaveen Mamindlapalli 12175e6808b4SNaveen Mamindlapalli static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid, 12185e6808b4SNaveen Mamindlapalli u32 parent_classid, u64 rate, u64 ceil, 121947a9656fSNaveen Mamindlapalli u64 prio, u32 quantum, 122047a9656fSNaveen Mamindlapalli struct netlink_ext_ack *extack) 12215e6808b4SNaveen Mamindlapalli { 12225e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *old_cfg, *new_cfg; 12235e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, *parent; 12245e6808b4SNaveen Mamindlapalli int qid, ret, err; 122547a9656fSNaveen Mamindlapalli bool static_cfg; 12265e6808b4SNaveen Mamindlapalli 12275e6808b4SNaveen Mamindlapalli netdev_dbg(pfvf->netdev, 122847a9656fSNaveen Mamindlapalli "TC_HTB_LEAF_ALLOC_QUEUE: classid=0x%x parent_classid=0x%x rate=%lld ceil=%lld prio=%lld quantum=%d\n", 122947a9656fSNaveen Mamindlapalli classid, parent_classid, rate, ceil, prio, quantum); 12305e6808b4SNaveen Mamindlapalli 12315e6808b4SNaveen Mamindlapalli if (prio > OTX2_QOS_MAX_PRIO) { 12325e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Valid priority range 0 to 7"); 12335e6808b4SNaveen Mamindlapalli ret = -EOPNOTSUPP; 12345e6808b4SNaveen Mamindlapalli goto out; 12355e6808b4SNaveen Mamindlapalli } 12365e6808b4SNaveen Mamindlapalli 123747a9656fSNaveen Mamindlapalli if (!quantum || quantum > INT_MAX) { 123847a9656fSNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Invalid quantum, range 1 - 2147483647 bytes"); 123947a9656fSNaveen Mamindlapalli ret = -EOPNOTSUPP; 124047a9656fSNaveen Mamindlapalli goto out; 124147a9656fSNaveen Mamindlapalli } 124247a9656fSNaveen Mamindlapalli 12435e6808b4SNaveen Mamindlapalli /* get parent node */ 12445e6808b4SNaveen Mamindlapalli parent = otx2_sw_node_find(pfvf, parent_classid); 12455e6808b4SNaveen Mamindlapalli if (!parent) { 12465e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "parent node not found"); 12475e6808b4SNaveen Mamindlapalli ret = -ENOENT; 12485e6808b4SNaveen Mamindlapalli goto out; 12495e6808b4SNaveen Mamindlapalli } 12505e6808b4SNaveen Mamindlapalli if (parent->level == NIX_TXSCH_LVL_MDQ) { 12515e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "HTB qos max levels reached"); 12525e6808b4SNaveen Mamindlapalli ret = -EOPNOTSUPP; 12535e6808b4SNaveen Mamindlapalli goto out; 12545e6808b4SNaveen Mamindlapalli } 12555e6808b4SNaveen Mamindlapalli 125647a9656fSNaveen Mamindlapalli static_cfg = !is_qos_node_dwrr(parent, pfvf, prio); 125747a9656fSNaveen Mamindlapalli ret = otx2_qos_validate_configuration(parent, extack, pfvf, prio, 125847a9656fSNaveen Mamindlapalli static_cfg); 12595e6808b4SNaveen Mamindlapalli if (ret) 12605e6808b4SNaveen Mamindlapalli goto out; 12615e6808b4SNaveen Mamindlapalli 126247a9656fSNaveen Mamindlapalli if (!static_cfg) { 126347a9656fSNaveen Mamindlapalli ret = otx2_qos_validate_dwrr_cfg(parent, extack, pfvf, prio, 126447a9656fSNaveen Mamindlapalli quantum); 126547a9656fSNaveen Mamindlapalli if (ret) 126647a9656fSNaveen Mamindlapalli goto out; 126747a9656fSNaveen Mamindlapalli } 126847a9656fSNaveen Mamindlapalli 126947a9656fSNaveen Mamindlapalli if (static_cfg) 1270f78dca69SNaveen Mamindlapalli parent->child_static_cnt++; 127147a9656fSNaveen Mamindlapalli else 127247a9656fSNaveen Mamindlapalli parent->child_dwrr_cnt++; 127347a9656fSNaveen Mamindlapalli 12745e6808b4SNaveen Mamindlapalli set_bit(prio, parent->prio_bmap); 12755e6808b4SNaveen Mamindlapalli 12765e6808b4SNaveen Mamindlapalli /* read current txschq configuration */ 12775e6808b4SNaveen Mamindlapalli old_cfg = kzalloc(sizeof(*old_cfg), GFP_KERNEL); 12785e6808b4SNaveen Mamindlapalli if (!old_cfg) { 12795e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); 12805e6808b4SNaveen Mamindlapalli ret = -ENOMEM; 12815e6808b4SNaveen Mamindlapalli goto reset_prio; 12825e6808b4SNaveen Mamindlapalli } 12835e6808b4SNaveen Mamindlapalli otx2_qos_read_txschq_cfg(pfvf, parent, old_cfg); 12845e6808b4SNaveen Mamindlapalli 12855e6808b4SNaveen Mamindlapalli /* allocate a new sq */ 12865e6808b4SNaveen Mamindlapalli qid = otx2_qos_get_qid(pfvf); 12875e6808b4SNaveen Mamindlapalli if (qid < 0) { 12885e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Reached max supported QOS SQ's"); 12895e6808b4SNaveen Mamindlapalli ret = -ENOMEM; 12905e6808b4SNaveen Mamindlapalli goto free_old_cfg; 12915e6808b4SNaveen Mamindlapalli } 12925e6808b4SNaveen Mamindlapalli 12935e6808b4SNaveen Mamindlapalli /* Actual SQ mapping will be updated after SMQ alloc */ 12945e6808b4SNaveen Mamindlapalli pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ; 12955e6808b4SNaveen Mamindlapalli 12965e6808b4SNaveen Mamindlapalli /* allocate and initialize a new child node */ 12975e6808b4SNaveen Mamindlapalli node = otx2_qos_sw_create_leaf_node(pfvf, parent, classid, prio, rate, 129847a9656fSNaveen Mamindlapalli ceil, quantum, qid, static_cfg); 12995e6808b4SNaveen Mamindlapalli if (IS_ERR(node)) { 13005e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Unable to allocate leaf node"); 13015e6808b4SNaveen Mamindlapalli ret = PTR_ERR(node); 13025e6808b4SNaveen Mamindlapalli goto free_old_cfg; 13035e6808b4SNaveen Mamindlapalli } 13045e6808b4SNaveen Mamindlapalli 13055e6808b4SNaveen Mamindlapalli /* push new txschq config to hw */ 13065e6808b4SNaveen Mamindlapalli new_cfg = kzalloc(sizeof(*new_cfg), GFP_KERNEL); 13075e6808b4SNaveen Mamindlapalli if (!new_cfg) { 13085e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); 13095e6808b4SNaveen Mamindlapalli ret = -ENOMEM; 13105e6808b4SNaveen Mamindlapalli goto free_node; 13115e6808b4SNaveen Mamindlapalli } 13125e6808b4SNaveen Mamindlapalli ret = otx2_qos_update_tree(pfvf, node, new_cfg); 13135e6808b4SNaveen Mamindlapalli if (ret) { 13145e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "HTB HW configuration error"); 13155e6808b4SNaveen Mamindlapalli kfree(new_cfg); 13165e6808b4SNaveen Mamindlapalli otx2_qos_sw_node_delete(pfvf, node); 13175e6808b4SNaveen Mamindlapalli /* restore the old qos tree */ 13185e6808b4SNaveen Mamindlapalli err = otx2_qos_txschq_update_config(pfvf, parent, old_cfg); 13195e6808b4SNaveen Mamindlapalli if (err) { 13205e6808b4SNaveen Mamindlapalli netdev_err(pfvf->netdev, 13215e6808b4SNaveen Mamindlapalli "Failed to restore txcshq configuration"); 13225e6808b4SNaveen Mamindlapalli goto free_old_cfg; 13235e6808b4SNaveen Mamindlapalli } 13245e6808b4SNaveen Mamindlapalli 13255e6808b4SNaveen Mamindlapalli otx2_qos_update_smq(pfvf, parent, QOS_CFG_SQ); 13265e6808b4SNaveen Mamindlapalli goto free_old_cfg; 13275e6808b4SNaveen Mamindlapalli } 13285e6808b4SNaveen Mamindlapalli 13295e6808b4SNaveen Mamindlapalli /* update tx_real_queues */ 13305e6808b4SNaveen Mamindlapalli otx2_qos_update_tx_netdev_queues(pfvf); 13315e6808b4SNaveen Mamindlapalli 13325e6808b4SNaveen Mamindlapalli /* free new txschq config */ 13335e6808b4SNaveen Mamindlapalli kfree(new_cfg); 13345e6808b4SNaveen Mamindlapalli 13355e6808b4SNaveen Mamindlapalli /* free old txschq config */ 13365e6808b4SNaveen Mamindlapalli otx2_qos_free_cfg(pfvf, old_cfg); 13375e6808b4SNaveen Mamindlapalli kfree(old_cfg); 13385e6808b4SNaveen Mamindlapalli 13395e6808b4SNaveen Mamindlapalli return pfvf->hw.tx_queues + qid; 13405e6808b4SNaveen Mamindlapalli 13415e6808b4SNaveen Mamindlapalli free_node: 13425e6808b4SNaveen Mamindlapalli otx2_qos_sw_node_delete(pfvf, node); 13435e6808b4SNaveen Mamindlapalli free_old_cfg: 13445e6808b4SNaveen Mamindlapalli kfree(old_cfg); 13455e6808b4SNaveen Mamindlapalli reset_prio: 134647a9656fSNaveen Mamindlapalli if (static_cfg) 1347f78dca69SNaveen Mamindlapalli parent->child_static_cnt--; 134847a9656fSNaveen Mamindlapalli else 134947a9656fSNaveen Mamindlapalli parent->child_dwrr_cnt--; 135047a9656fSNaveen Mamindlapalli 13515e6808b4SNaveen Mamindlapalli clear_bit(prio, parent->prio_bmap); 13525e6808b4SNaveen Mamindlapalli out: 13535e6808b4SNaveen Mamindlapalli return ret; 13545e6808b4SNaveen Mamindlapalli } 13555e6808b4SNaveen Mamindlapalli 13565e6808b4SNaveen Mamindlapalli static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid, 13575e6808b4SNaveen Mamindlapalli u16 child_classid, u64 rate, u64 ceil, u64 prio, 135847a9656fSNaveen Mamindlapalli u32 quantum, struct netlink_ext_ack *extack) 13595e6808b4SNaveen Mamindlapalli { 13605e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *old_cfg, *new_cfg; 13615e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, *child; 136247a9656fSNaveen Mamindlapalli bool static_cfg; 13635e6808b4SNaveen Mamindlapalli int ret, err; 13645e6808b4SNaveen Mamindlapalli u16 qid; 13655e6808b4SNaveen Mamindlapalli 13665e6808b4SNaveen Mamindlapalli netdev_dbg(pfvf->netdev, 13675e6808b4SNaveen Mamindlapalli "TC_HTB_LEAF_TO_INNER classid %04x, child %04x, rate %llu, ceil %llu\n", 13685e6808b4SNaveen Mamindlapalli classid, child_classid, rate, ceil); 13695e6808b4SNaveen Mamindlapalli 13705e6808b4SNaveen Mamindlapalli if (prio > OTX2_QOS_MAX_PRIO) { 13715e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Valid priority range 0 to 7"); 13725e6808b4SNaveen Mamindlapalli ret = -EOPNOTSUPP; 13735e6808b4SNaveen Mamindlapalli goto out; 13745e6808b4SNaveen Mamindlapalli } 13755e6808b4SNaveen Mamindlapalli 137647a9656fSNaveen Mamindlapalli if (!quantum || quantum > INT_MAX) { 137747a9656fSNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Invalid quantum, range 1 - 2147483647 bytes"); 137847a9656fSNaveen Mamindlapalli ret = -EOPNOTSUPP; 137947a9656fSNaveen Mamindlapalli goto out; 138047a9656fSNaveen Mamindlapalli } 138147a9656fSNaveen Mamindlapalli 13825e6808b4SNaveen Mamindlapalli /* find node related to classid */ 13835e6808b4SNaveen Mamindlapalli node = otx2_sw_node_find(pfvf, classid); 13845e6808b4SNaveen Mamindlapalli if (!node) { 13855e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "HTB node not found"); 13865e6808b4SNaveen Mamindlapalli ret = -ENOENT; 13875e6808b4SNaveen Mamindlapalli goto out; 13885e6808b4SNaveen Mamindlapalli } 13895e6808b4SNaveen Mamindlapalli /* check max qos txschq level */ 13905e6808b4SNaveen Mamindlapalli if (node->level == NIX_TXSCH_LVL_MDQ) { 13915e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "HTB qos level not supported"); 13925e6808b4SNaveen Mamindlapalli ret = -EOPNOTSUPP; 13935e6808b4SNaveen Mamindlapalli goto out; 13945e6808b4SNaveen Mamindlapalli } 13955e6808b4SNaveen Mamindlapalli 139647a9656fSNaveen Mamindlapalli static_cfg = !is_qos_node_dwrr(node, pfvf, prio); 139747a9656fSNaveen Mamindlapalli if (!static_cfg) { 139847a9656fSNaveen Mamindlapalli ret = otx2_qos_validate_dwrr_cfg(node, extack, pfvf, prio, 139947a9656fSNaveen Mamindlapalli quantum); 140047a9656fSNaveen Mamindlapalli if (ret) 140147a9656fSNaveen Mamindlapalli goto out; 140247a9656fSNaveen Mamindlapalli } 140347a9656fSNaveen Mamindlapalli 140447a9656fSNaveen Mamindlapalli if (static_cfg) 1405f78dca69SNaveen Mamindlapalli node->child_static_cnt++; 140647a9656fSNaveen Mamindlapalli else 140747a9656fSNaveen Mamindlapalli node->child_dwrr_cnt++; 140847a9656fSNaveen Mamindlapalli 14095e6808b4SNaveen Mamindlapalli set_bit(prio, node->prio_bmap); 14105e6808b4SNaveen Mamindlapalli 14115e6808b4SNaveen Mamindlapalli /* store the qid to assign to leaf node */ 14125e6808b4SNaveen Mamindlapalli qid = node->qid; 14135e6808b4SNaveen Mamindlapalli 14145e6808b4SNaveen Mamindlapalli /* read current txschq configuration */ 14155e6808b4SNaveen Mamindlapalli old_cfg = kzalloc(sizeof(*old_cfg), GFP_KERNEL); 14165e6808b4SNaveen Mamindlapalli if (!old_cfg) { 14175e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); 14185e6808b4SNaveen Mamindlapalli ret = -ENOMEM; 14195e6808b4SNaveen Mamindlapalli goto reset_prio; 14205e6808b4SNaveen Mamindlapalli } 14215e6808b4SNaveen Mamindlapalli otx2_qos_read_txschq_cfg(pfvf, node, old_cfg); 14225e6808b4SNaveen Mamindlapalli 14235e6808b4SNaveen Mamindlapalli /* delete the txschq nodes allocated for this node */ 142416848421SHariprasad Kelam otx2_qos_disable_sq(pfvf, qid); 142516848421SHariprasad Kelam otx2_qos_free_hw_node_schq(pfvf, node); 14265e6808b4SNaveen Mamindlapalli otx2_qos_free_sw_node_schq(pfvf, node); 142716848421SHariprasad Kelam pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ; 14285e6808b4SNaveen Mamindlapalli 14295e6808b4SNaveen Mamindlapalli /* mark this node as htb inner node */ 14305e6808b4SNaveen Mamindlapalli WRITE_ONCE(node->qid, OTX2_QOS_QID_INNER); 14315e6808b4SNaveen Mamindlapalli 14325e6808b4SNaveen Mamindlapalli /* allocate and initialize a new child node */ 14335e6808b4SNaveen Mamindlapalli child = otx2_qos_sw_create_leaf_node(pfvf, node, child_classid, 143447a9656fSNaveen Mamindlapalli prio, rate, ceil, quantum, 143547a9656fSNaveen Mamindlapalli qid, static_cfg); 14365e6808b4SNaveen Mamindlapalli if (IS_ERR(child)) { 14375e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Unable to allocate leaf node"); 14385e6808b4SNaveen Mamindlapalli ret = PTR_ERR(child); 14395e6808b4SNaveen Mamindlapalli goto free_old_cfg; 14405e6808b4SNaveen Mamindlapalli } 14415e6808b4SNaveen Mamindlapalli 14425e6808b4SNaveen Mamindlapalli /* push new txschq config to hw */ 14435e6808b4SNaveen Mamindlapalli new_cfg = kzalloc(sizeof(*new_cfg), GFP_KERNEL); 14445e6808b4SNaveen Mamindlapalli if (!new_cfg) { 14455e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); 14465e6808b4SNaveen Mamindlapalli ret = -ENOMEM; 14475e6808b4SNaveen Mamindlapalli goto free_node; 14485e6808b4SNaveen Mamindlapalli } 14495e6808b4SNaveen Mamindlapalli ret = otx2_qos_update_tree(pfvf, child, new_cfg); 14505e6808b4SNaveen Mamindlapalli if (ret) { 14515e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "HTB HW configuration error"); 14525e6808b4SNaveen Mamindlapalli kfree(new_cfg); 14535e6808b4SNaveen Mamindlapalli otx2_qos_sw_node_delete(pfvf, child); 14545e6808b4SNaveen Mamindlapalli /* restore the old qos tree */ 14555e6808b4SNaveen Mamindlapalli WRITE_ONCE(node->qid, qid); 14565e6808b4SNaveen Mamindlapalli err = otx2_qos_alloc_txschq_node(pfvf, node); 14575e6808b4SNaveen Mamindlapalli if (err) { 14585e6808b4SNaveen Mamindlapalli netdev_err(pfvf->netdev, 14595e6808b4SNaveen Mamindlapalli "Failed to restore old leaf node"); 14605e6808b4SNaveen Mamindlapalli goto free_old_cfg; 14615e6808b4SNaveen Mamindlapalli } 14625e6808b4SNaveen Mamindlapalli err = otx2_qos_txschq_update_config(pfvf, node, old_cfg); 14635e6808b4SNaveen Mamindlapalli if (err) { 14645e6808b4SNaveen Mamindlapalli netdev_err(pfvf->netdev, 14655e6808b4SNaveen Mamindlapalli "Failed to restore txcshq configuration"); 14665e6808b4SNaveen Mamindlapalli goto free_old_cfg; 14675e6808b4SNaveen Mamindlapalli } 14685e6808b4SNaveen Mamindlapalli otx2_qos_update_smq(pfvf, node, QOS_CFG_SQ); 14695e6808b4SNaveen Mamindlapalli goto free_old_cfg; 14705e6808b4SNaveen Mamindlapalli } 14715e6808b4SNaveen Mamindlapalli 14725e6808b4SNaveen Mamindlapalli /* free new txschq config */ 14735e6808b4SNaveen Mamindlapalli kfree(new_cfg); 14745e6808b4SNaveen Mamindlapalli 14755e6808b4SNaveen Mamindlapalli /* free old txschq config */ 14765e6808b4SNaveen Mamindlapalli otx2_qos_free_cfg(pfvf, old_cfg); 14775e6808b4SNaveen Mamindlapalli kfree(old_cfg); 14785e6808b4SNaveen Mamindlapalli 14795e6808b4SNaveen Mamindlapalli return 0; 14805e6808b4SNaveen Mamindlapalli 14815e6808b4SNaveen Mamindlapalli free_node: 14825e6808b4SNaveen Mamindlapalli otx2_qos_sw_node_delete(pfvf, child); 14835e6808b4SNaveen Mamindlapalli free_old_cfg: 14845e6808b4SNaveen Mamindlapalli kfree(old_cfg); 14855e6808b4SNaveen Mamindlapalli reset_prio: 148647a9656fSNaveen Mamindlapalli if (static_cfg) 1487f78dca69SNaveen Mamindlapalli node->child_static_cnt--; 148847a9656fSNaveen Mamindlapalli else 148947a9656fSNaveen Mamindlapalli node->child_dwrr_cnt--; 14905e6808b4SNaveen Mamindlapalli clear_bit(prio, node->prio_bmap); 14915e6808b4SNaveen Mamindlapalli out: 14925e6808b4SNaveen Mamindlapalli return ret; 14935e6808b4SNaveen Mamindlapalli } 14945e6808b4SNaveen Mamindlapalli 149504fb71ccSHariprasad Kelam static int otx2_qos_cur_leaf_nodes(struct otx2_nic *pfvf) 149604fb71ccSHariprasad Kelam { 149704fb71ccSHariprasad Kelam int last = find_last_bit(pfvf->qos.qos_sq_bmap, pfvf->hw.tc_tx_queues); 149804fb71ccSHariprasad Kelam 149904fb71ccSHariprasad Kelam return last == pfvf->hw.tc_tx_queues ? 0 : last + 1; 150004fb71ccSHariprasad Kelam } 150104fb71ccSHariprasad Kelam 150204fb71ccSHariprasad Kelam static void otx2_reset_qdisc(struct net_device *dev, u16 qid) 150304fb71ccSHariprasad Kelam { 150404fb71ccSHariprasad Kelam struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, qid); 150504fb71ccSHariprasad Kelam struct Qdisc *qdisc = rtnl_dereference(dev_queue->qdisc_sleeping); 150604fb71ccSHariprasad Kelam 150704fb71ccSHariprasad Kelam if (!qdisc) 150804fb71ccSHariprasad Kelam return; 150904fb71ccSHariprasad Kelam 151004fb71ccSHariprasad Kelam spin_lock_bh(qdisc_lock(qdisc)); 151104fb71ccSHariprasad Kelam qdisc_reset(qdisc); 151204fb71ccSHariprasad Kelam spin_unlock_bh(qdisc_lock(qdisc)); 151304fb71ccSHariprasad Kelam } 151404fb71ccSHariprasad Kelam 151504fb71ccSHariprasad Kelam static void otx2_cfg_smq(struct otx2_nic *pfvf, struct otx2_qos_node *node, 151604fb71ccSHariprasad Kelam int qid) 151704fb71ccSHariprasad Kelam { 151804fb71ccSHariprasad Kelam struct otx2_qos_node *tmp; 151904fb71ccSHariprasad Kelam 152004fb71ccSHariprasad Kelam list_for_each_entry(tmp, &node->child_schq_list, list) 152104fb71ccSHariprasad Kelam if (tmp->level == NIX_TXSCH_LVL_MDQ) { 152204fb71ccSHariprasad Kelam otx2_qos_txschq_config(pfvf, tmp); 152304fb71ccSHariprasad Kelam pfvf->qos.qid_to_sqmap[qid] = tmp->schq; 152404fb71ccSHariprasad Kelam } 152504fb71ccSHariprasad Kelam } 152604fb71ccSHariprasad Kelam 15275e6808b4SNaveen Mamindlapalli static int otx2_qos_leaf_del(struct otx2_nic *pfvf, u16 *classid, 15285e6808b4SNaveen Mamindlapalli struct netlink_ext_ack *extack) 15295e6808b4SNaveen Mamindlapalli { 15305e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, *parent; 153147a9656fSNaveen Mamindlapalli int dwrr_del_node = false; 153204fb71ccSHariprasad Kelam u16 qid, moved_qid; 15335e6808b4SNaveen Mamindlapalli u64 prio; 15345e6808b4SNaveen Mamindlapalli 15355e6808b4SNaveen Mamindlapalli netdev_dbg(pfvf->netdev, "TC_HTB_LEAF_DEL classid %04x\n", *classid); 15365e6808b4SNaveen Mamindlapalli 15375e6808b4SNaveen Mamindlapalli /* find node related to classid */ 15385e6808b4SNaveen Mamindlapalli node = otx2_sw_node_find(pfvf, *classid); 15395e6808b4SNaveen Mamindlapalli if (!node) { 15405e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "HTB node not found"); 15415e6808b4SNaveen Mamindlapalli return -ENOENT; 15425e6808b4SNaveen Mamindlapalli } 15435e6808b4SNaveen Mamindlapalli parent = node->parent; 15445e6808b4SNaveen Mamindlapalli prio = node->prio; 15455e6808b4SNaveen Mamindlapalli qid = node->qid; 15465e6808b4SNaveen Mamindlapalli 154747a9656fSNaveen Mamindlapalli if (!node->is_static) 154847a9656fSNaveen Mamindlapalli dwrr_del_node = true; 154947a9656fSNaveen Mamindlapalli 15505e6808b4SNaveen Mamindlapalli otx2_qos_disable_sq(pfvf, node->qid); 15515e6808b4SNaveen Mamindlapalli 15525e6808b4SNaveen Mamindlapalli otx2_qos_destroy_node(pfvf, node); 15535e6808b4SNaveen Mamindlapalli pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ; 15545e6808b4SNaveen Mamindlapalli 155547a9656fSNaveen Mamindlapalli if (dwrr_del_node) { 155647a9656fSNaveen Mamindlapalli parent->child_dwrr_cnt--; 155747a9656fSNaveen Mamindlapalli } else { 1558f78dca69SNaveen Mamindlapalli parent->child_static_cnt--; 155947a9656fSNaveen Mamindlapalli clear_bit(prio, parent->prio_bmap); 156047a9656fSNaveen Mamindlapalli } 156147a9656fSNaveen Mamindlapalli 156247a9656fSNaveen Mamindlapalli /* Reset DWRR priority if all dwrr nodes are deleted */ 156347a9656fSNaveen Mamindlapalli if (!parent->child_dwrr_cnt) 156447a9656fSNaveen Mamindlapalli otx2_reset_dwrr_prio(parent, prio); 156547a9656fSNaveen Mamindlapalli 1566f78dca69SNaveen Mamindlapalli if (!parent->child_static_cnt) 1567f78dca69SNaveen Mamindlapalli parent->max_static_prio = 0; 1568f78dca69SNaveen Mamindlapalli 156904fb71ccSHariprasad Kelam moved_qid = otx2_qos_cur_leaf_nodes(pfvf); 157004fb71ccSHariprasad Kelam 157104fb71ccSHariprasad Kelam /* last node just deleted */ 157204fb71ccSHariprasad Kelam if (moved_qid == 0 || moved_qid == qid) 157304fb71ccSHariprasad Kelam return 0; 157404fb71ccSHariprasad Kelam 157504fb71ccSHariprasad Kelam moved_qid--; 157604fb71ccSHariprasad Kelam 157704fb71ccSHariprasad Kelam node = otx2_sw_node_find_by_qid(pfvf, moved_qid); 157804fb71ccSHariprasad Kelam if (!node) 157904fb71ccSHariprasad Kelam return 0; 158004fb71ccSHariprasad Kelam 158104fb71ccSHariprasad Kelam /* stop traffic to the old queue and disable 158204fb71ccSHariprasad Kelam * SQ associated with it 158304fb71ccSHariprasad Kelam */ 158404fb71ccSHariprasad Kelam node->qid = OTX2_QOS_QID_INNER; 158504fb71ccSHariprasad Kelam __clear_bit(moved_qid, pfvf->qos.qos_sq_bmap); 158604fb71ccSHariprasad Kelam otx2_qos_disable_sq(pfvf, moved_qid); 158704fb71ccSHariprasad Kelam 158804fb71ccSHariprasad Kelam otx2_reset_qdisc(pfvf->netdev, pfvf->hw.tx_queues + moved_qid); 158904fb71ccSHariprasad Kelam 159004fb71ccSHariprasad Kelam /* enable SQ associated with qid and 159104fb71ccSHariprasad Kelam * update the node 159204fb71ccSHariprasad Kelam */ 159304fb71ccSHariprasad Kelam otx2_cfg_smq(pfvf, node, qid); 159404fb71ccSHariprasad Kelam 159504fb71ccSHariprasad Kelam otx2_qos_enable_sq(pfvf, qid); 159604fb71ccSHariprasad Kelam __set_bit(qid, pfvf->qos.qos_sq_bmap); 159704fb71ccSHariprasad Kelam node->qid = qid; 159804fb71ccSHariprasad Kelam 159904fb71ccSHariprasad Kelam *classid = node->classid; 16005e6808b4SNaveen Mamindlapalli return 0; 16015e6808b4SNaveen Mamindlapalli } 16025e6808b4SNaveen Mamindlapalli 16035e6808b4SNaveen Mamindlapalli static int otx2_qos_leaf_del_last(struct otx2_nic *pfvf, u16 classid, bool force, 16045e6808b4SNaveen Mamindlapalli struct netlink_ext_ack *extack) 16055e6808b4SNaveen Mamindlapalli { 16065e6808b4SNaveen Mamindlapalli struct otx2_qos_node *node, *parent; 16075e6808b4SNaveen Mamindlapalli struct otx2_qos_cfg *new_cfg; 160847a9656fSNaveen Mamindlapalli int dwrr_del_node = false; 16095e6808b4SNaveen Mamindlapalli u64 prio; 16105e6808b4SNaveen Mamindlapalli int err; 16115e6808b4SNaveen Mamindlapalli u16 qid; 16125e6808b4SNaveen Mamindlapalli 16135e6808b4SNaveen Mamindlapalli netdev_dbg(pfvf->netdev, 16145e6808b4SNaveen Mamindlapalli "TC_HTB_LEAF_DEL_LAST classid %04x\n", classid); 16155e6808b4SNaveen Mamindlapalli 16165e6808b4SNaveen Mamindlapalli /* find node related to classid */ 16175e6808b4SNaveen Mamindlapalli node = otx2_sw_node_find(pfvf, classid); 16185e6808b4SNaveen Mamindlapalli if (!node) { 16195e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "HTB node not found"); 16205e6808b4SNaveen Mamindlapalli return -ENOENT; 16215e6808b4SNaveen Mamindlapalli } 16225e6808b4SNaveen Mamindlapalli 16235e6808b4SNaveen Mamindlapalli /* save qid for use by parent */ 16245e6808b4SNaveen Mamindlapalli qid = node->qid; 16255e6808b4SNaveen Mamindlapalli prio = node->prio; 16265e6808b4SNaveen Mamindlapalli 16275e6808b4SNaveen Mamindlapalli parent = otx2_sw_node_find(pfvf, node->parent->classid); 16285e6808b4SNaveen Mamindlapalli if (!parent) { 16295e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "parent node not found"); 16305e6808b4SNaveen Mamindlapalli return -ENOENT; 16315e6808b4SNaveen Mamindlapalli } 16325e6808b4SNaveen Mamindlapalli 163347a9656fSNaveen Mamindlapalli if (!node->is_static) 163447a9656fSNaveen Mamindlapalli dwrr_del_node = true; 163547a9656fSNaveen Mamindlapalli 16365e6808b4SNaveen Mamindlapalli /* destroy the leaf node */ 163716848421SHariprasad Kelam otx2_qos_disable_sq(pfvf, qid); 16385e6808b4SNaveen Mamindlapalli otx2_qos_destroy_node(pfvf, node); 16395e6808b4SNaveen Mamindlapalli pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ; 16405e6808b4SNaveen Mamindlapalli 164147a9656fSNaveen Mamindlapalli if (dwrr_del_node) { 164247a9656fSNaveen Mamindlapalli parent->child_dwrr_cnt--; 164347a9656fSNaveen Mamindlapalli } else { 1644f78dca69SNaveen Mamindlapalli parent->child_static_cnt--; 164547a9656fSNaveen Mamindlapalli clear_bit(prio, parent->prio_bmap); 164647a9656fSNaveen Mamindlapalli } 164747a9656fSNaveen Mamindlapalli 164847a9656fSNaveen Mamindlapalli /* Reset DWRR priority if all dwrr nodes are deleted */ 164947a9656fSNaveen Mamindlapalli if (!parent->child_dwrr_cnt) 165047a9656fSNaveen Mamindlapalli otx2_reset_dwrr_prio(parent, prio); 165147a9656fSNaveen Mamindlapalli 1652f78dca69SNaveen Mamindlapalli if (!parent->child_static_cnt) 1653f78dca69SNaveen Mamindlapalli parent->max_static_prio = 0; 1654f78dca69SNaveen Mamindlapalli 16555e6808b4SNaveen Mamindlapalli /* create downstream txschq entries to parent */ 16565e6808b4SNaveen Mamindlapalli err = otx2_qos_alloc_txschq_node(pfvf, parent); 16575e6808b4SNaveen Mamindlapalli if (err) { 16585e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "HTB failed to create txsch configuration"); 16595e6808b4SNaveen Mamindlapalli return err; 16605e6808b4SNaveen Mamindlapalli } 16615e6808b4SNaveen Mamindlapalli WRITE_ONCE(parent->qid, qid); 16625e6808b4SNaveen Mamindlapalli __set_bit(qid, pfvf->qos.qos_sq_bmap); 16635e6808b4SNaveen Mamindlapalli 16645e6808b4SNaveen Mamindlapalli /* push new txschq config to hw */ 16655e6808b4SNaveen Mamindlapalli new_cfg = kzalloc(sizeof(*new_cfg), GFP_KERNEL); 16665e6808b4SNaveen Mamindlapalli if (!new_cfg) { 16675e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); 16685e6808b4SNaveen Mamindlapalli return -ENOMEM; 16695e6808b4SNaveen Mamindlapalli } 16705e6808b4SNaveen Mamindlapalli /* fill txschq cfg and push txschq cfg to hw */ 16715e6808b4SNaveen Mamindlapalli otx2_qos_fill_cfg_schq(parent, new_cfg); 16725e6808b4SNaveen Mamindlapalli err = otx2_qos_push_txschq_cfg(pfvf, parent, new_cfg); 16735e6808b4SNaveen Mamindlapalli if (err) { 16745e6808b4SNaveen Mamindlapalli NL_SET_ERR_MSG_MOD(extack, "HTB HW configuration error"); 16755e6808b4SNaveen Mamindlapalli kfree(new_cfg); 16765e6808b4SNaveen Mamindlapalli return err; 16775e6808b4SNaveen Mamindlapalli } 16785e6808b4SNaveen Mamindlapalli kfree(new_cfg); 16795e6808b4SNaveen Mamindlapalli 16805e6808b4SNaveen Mamindlapalli /* update tx_real_queues */ 16815e6808b4SNaveen Mamindlapalli otx2_qos_update_tx_netdev_queues(pfvf); 16825e6808b4SNaveen Mamindlapalli 16835e6808b4SNaveen Mamindlapalli return 0; 16845e6808b4SNaveen Mamindlapalli } 16855e6808b4SNaveen Mamindlapalli 16865e6808b4SNaveen Mamindlapalli void otx2_clean_qos_queues(struct otx2_nic *pfvf) 16875e6808b4SNaveen Mamindlapalli { 16885e6808b4SNaveen Mamindlapalli struct otx2_qos_node *root; 16895e6808b4SNaveen Mamindlapalli 16905e6808b4SNaveen Mamindlapalli root = otx2_sw_node_find(pfvf, OTX2_QOS_ROOT_CLASSID); 16915e6808b4SNaveen Mamindlapalli if (!root) 16925e6808b4SNaveen Mamindlapalli return; 16935e6808b4SNaveen Mamindlapalli 16945e6808b4SNaveen Mamindlapalli otx2_qos_update_smq(pfvf, root, QOS_SMQ_FLUSH); 16955e6808b4SNaveen Mamindlapalli } 16965e6808b4SNaveen Mamindlapalli 16975e6808b4SNaveen Mamindlapalli void otx2_qos_config_txschq(struct otx2_nic *pfvf) 16985e6808b4SNaveen Mamindlapalli { 16995e6808b4SNaveen Mamindlapalli struct otx2_qos_node *root; 17005e6808b4SNaveen Mamindlapalli int err; 17015e6808b4SNaveen Mamindlapalli 17025e6808b4SNaveen Mamindlapalli root = otx2_sw_node_find(pfvf, OTX2_QOS_ROOT_CLASSID); 17035e6808b4SNaveen Mamindlapalli if (!root) 17045e6808b4SNaveen Mamindlapalli return; 17055e6808b4SNaveen Mamindlapalli 170647a9656fSNaveen Mamindlapalli if (root->level != NIX_TXSCH_LVL_TL1) { 17075e6808b4SNaveen Mamindlapalli err = otx2_qos_txschq_config(pfvf, root); 17085e6808b4SNaveen Mamindlapalli if (err) { 17095e6808b4SNaveen Mamindlapalli netdev_err(pfvf->netdev, "Error update txschq configuration\n"); 17105e6808b4SNaveen Mamindlapalli goto root_destroy; 17115e6808b4SNaveen Mamindlapalli } 171247a9656fSNaveen Mamindlapalli } 17135e6808b4SNaveen Mamindlapalli 17145e6808b4SNaveen Mamindlapalli err = otx2_qos_txschq_push_cfg_tl(pfvf, root, NULL); 17155e6808b4SNaveen Mamindlapalli if (err) { 17165e6808b4SNaveen Mamindlapalli netdev_err(pfvf->netdev, "Error update txschq configuration\n"); 17175e6808b4SNaveen Mamindlapalli goto root_destroy; 17185e6808b4SNaveen Mamindlapalli } 17195e6808b4SNaveen Mamindlapalli 17205e6808b4SNaveen Mamindlapalli otx2_qos_update_smq(pfvf, root, QOS_CFG_SQ); 17215e6808b4SNaveen Mamindlapalli return; 17225e6808b4SNaveen Mamindlapalli 17235e6808b4SNaveen Mamindlapalli root_destroy: 17245e6808b4SNaveen Mamindlapalli netdev_err(pfvf->netdev, "Failed to update Scheduler/Shaping config in Hardware\n"); 17255e6808b4SNaveen Mamindlapalli /* Free resources allocated */ 17265e6808b4SNaveen Mamindlapalli otx2_qos_root_destroy(pfvf); 17275e6808b4SNaveen Mamindlapalli } 17285e6808b4SNaveen Mamindlapalli 17295e6808b4SNaveen Mamindlapalli int otx2_setup_tc_htb(struct net_device *ndev, struct tc_htb_qopt_offload *htb) 17305e6808b4SNaveen Mamindlapalli { 17315e6808b4SNaveen Mamindlapalli struct otx2_nic *pfvf = netdev_priv(ndev); 17325e6808b4SNaveen Mamindlapalli int res; 17335e6808b4SNaveen Mamindlapalli 17345e6808b4SNaveen Mamindlapalli switch (htb->command) { 17355e6808b4SNaveen Mamindlapalli case TC_HTB_CREATE: 17365e6808b4SNaveen Mamindlapalli return otx2_qos_root_add(pfvf, htb->parent_classid, 17375e6808b4SNaveen Mamindlapalli htb->classid, htb->extack); 17385e6808b4SNaveen Mamindlapalli case TC_HTB_DESTROY: 17395e6808b4SNaveen Mamindlapalli return otx2_qos_root_destroy(pfvf); 17405e6808b4SNaveen Mamindlapalli case TC_HTB_LEAF_ALLOC_QUEUE: 17415e6808b4SNaveen Mamindlapalli res = otx2_qos_leaf_alloc_queue(pfvf, htb->classid, 17425e6808b4SNaveen Mamindlapalli htb->parent_classid, 17435e6808b4SNaveen Mamindlapalli htb->rate, htb->ceil, 174447a9656fSNaveen Mamindlapalli htb->prio, htb->quantum, 174547a9656fSNaveen Mamindlapalli htb->extack); 17465e6808b4SNaveen Mamindlapalli if (res < 0) 17475e6808b4SNaveen Mamindlapalli return res; 17485e6808b4SNaveen Mamindlapalli htb->qid = res; 17495e6808b4SNaveen Mamindlapalli return 0; 17505e6808b4SNaveen Mamindlapalli case TC_HTB_LEAF_TO_INNER: 17515e6808b4SNaveen Mamindlapalli return otx2_qos_leaf_to_inner(pfvf, htb->parent_classid, 17525e6808b4SNaveen Mamindlapalli htb->classid, htb->rate, 17535e6808b4SNaveen Mamindlapalli htb->ceil, htb->prio, 175447a9656fSNaveen Mamindlapalli htb->quantum, htb->extack); 17555e6808b4SNaveen Mamindlapalli case TC_HTB_LEAF_DEL: 17565e6808b4SNaveen Mamindlapalli return otx2_qos_leaf_del(pfvf, &htb->classid, htb->extack); 17575e6808b4SNaveen Mamindlapalli case TC_HTB_LEAF_DEL_LAST: 17585e6808b4SNaveen Mamindlapalli case TC_HTB_LEAF_DEL_LAST_FORCE: 17595e6808b4SNaveen Mamindlapalli return otx2_qos_leaf_del_last(pfvf, htb->classid, 17605e6808b4SNaveen Mamindlapalli htb->command == TC_HTB_LEAF_DEL_LAST_FORCE, 17615e6808b4SNaveen Mamindlapalli htb->extack); 17625e6808b4SNaveen Mamindlapalli case TC_HTB_LEAF_QUERY_QUEUE: 17635e6808b4SNaveen Mamindlapalli res = otx2_get_txq_by_classid(pfvf, htb->classid); 17645e6808b4SNaveen Mamindlapalli htb->qid = res; 17655e6808b4SNaveen Mamindlapalli return 0; 17665e6808b4SNaveen Mamindlapalli case TC_HTB_NODE_MODIFY: 17675e6808b4SNaveen Mamindlapalli fallthrough; 17685e6808b4SNaveen Mamindlapalli default: 17695e6808b4SNaveen Mamindlapalli return -EOPNOTSUPP; 17705e6808b4SNaveen Mamindlapalli } 17715e6808b4SNaveen Mamindlapalli } 1772