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