xref: /freebsd-src/sys/dev/ice/ice_sched.c (revision f2635e844dd138ac9dfba676f27d41750049af26)
171d10453SEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */
2015f8cc5SEric Joyner /*  Copyright (c) 2024, Intel Corporation
371d10453SEric Joyner  *  All rights reserved.
471d10453SEric Joyner  *
571d10453SEric Joyner  *  Redistribution and use in source and binary forms, with or without
671d10453SEric Joyner  *  modification, are permitted provided that the following conditions are met:
771d10453SEric Joyner  *
871d10453SEric Joyner  *   1. Redistributions of source code must retain the above copyright notice,
971d10453SEric Joyner  *      this list of conditions and the following disclaimer.
1071d10453SEric Joyner  *
1171d10453SEric Joyner  *   2. Redistributions in binary form must reproduce the above copyright
1271d10453SEric Joyner  *      notice, this list of conditions and the following disclaimer in the
1371d10453SEric Joyner  *      documentation and/or other materials provided with the distribution.
1471d10453SEric Joyner  *
1571d10453SEric Joyner  *   3. Neither the name of the Intel Corporation nor the names of its
1671d10453SEric Joyner  *      contributors may be used to endorse or promote products derived from
1771d10453SEric Joyner  *      this software without specific prior written permission.
1871d10453SEric Joyner  *
1971d10453SEric Joyner  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2071d10453SEric Joyner  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2171d10453SEric Joyner  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2271d10453SEric Joyner  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2371d10453SEric Joyner  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2471d10453SEric Joyner  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2571d10453SEric Joyner  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2671d10453SEric Joyner  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2771d10453SEric Joyner  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2871d10453SEric Joyner  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2971d10453SEric Joyner  *  POSSIBILITY OF SUCH DAMAGE.
3071d10453SEric Joyner  */
3171d10453SEric Joyner 
3271d10453SEric Joyner #include "ice_sched.h"
3371d10453SEric Joyner 
3471d10453SEric Joyner /**
3571d10453SEric Joyner  * ice_sched_add_root_node - Insert the Tx scheduler root node in SW DB
3671d10453SEric Joyner  * @pi: port information structure
3771d10453SEric Joyner  * @info: Scheduler element information from firmware
3871d10453SEric Joyner  *
3971d10453SEric Joyner  * This function inserts the root node of the scheduling tree topology
4071d10453SEric Joyner  * to the SW DB.
4171d10453SEric Joyner  */
42*f2635e84SEric Joyner static int
4371d10453SEric Joyner ice_sched_add_root_node(struct ice_port_info *pi,
4471d10453SEric Joyner 			struct ice_aqc_txsched_elem_data *info)
4571d10453SEric Joyner {
4671d10453SEric Joyner 	struct ice_sched_node *root;
4771d10453SEric Joyner 	struct ice_hw *hw;
4871d10453SEric Joyner 
4971d10453SEric Joyner 	if (!pi)
5071d10453SEric Joyner 		return ICE_ERR_PARAM;
5171d10453SEric Joyner 
5271d10453SEric Joyner 	hw = pi->hw;
5371d10453SEric Joyner 
5471d10453SEric Joyner 	root = (struct ice_sched_node *)ice_malloc(hw, sizeof(*root));
5571d10453SEric Joyner 	if (!root)
5671d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
5771d10453SEric Joyner 
5871d10453SEric Joyner 	root->children = (struct ice_sched_node **)
599e54973fSEric Joyner 		ice_calloc(hw, hw->max_children[0], sizeof(*root->children));
6071d10453SEric Joyner 	if (!root->children) {
6171d10453SEric Joyner 		ice_free(hw, root);
6271d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
6371d10453SEric Joyner 	}
6471d10453SEric Joyner 
65*f2635e84SEric Joyner 	ice_memcpy(&root->info, info, sizeof(*info), ICE_NONDMA_TO_NONDMA);
6671d10453SEric Joyner 	pi->root = root;
67*f2635e84SEric Joyner 	return 0;
6871d10453SEric Joyner }
6971d10453SEric Joyner 
7071d10453SEric Joyner /**
7171d10453SEric Joyner  * ice_sched_find_node_by_teid - Find the Tx scheduler node in SW DB
7271d10453SEric Joyner  * @start_node: pointer to the starting ice_sched_node struct in a sub-tree
7371d10453SEric Joyner  * @teid: node TEID to search
7471d10453SEric Joyner  *
7571d10453SEric Joyner  * This function searches for a node matching the TEID in the scheduling tree
7671d10453SEric Joyner  * from the SW DB. The search is recursive and is restricted by the number of
7771d10453SEric Joyner  * layers it has searched through; stopping at the max supported layer.
7871d10453SEric Joyner  *
7971d10453SEric Joyner  * This function needs to be called when holding the port_info->sched_lock
8071d10453SEric Joyner  */
8171d10453SEric Joyner struct ice_sched_node *
8271d10453SEric Joyner ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid)
8371d10453SEric Joyner {
8471d10453SEric Joyner 	u16 i;
8571d10453SEric Joyner 
86*f2635e84SEric Joyner 	if (!start_node)
87*f2635e84SEric Joyner 		return NULL;
88*f2635e84SEric Joyner 
8971d10453SEric Joyner 	/* The TEID is same as that of the start_node */
9071d10453SEric Joyner 	if (ICE_TXSCHED_GET_NODE_TEID(start_node) == teid)
9171d10453SEric Joyner 		return start_node;
9271d10453SEric Joyner 
9371d10453SEric Joyner 	/* The node has no children or is at the max layer */
9471d10453SEric Joyner 	if (!start_node->num_children ||
9571d10453SEric Joyner 	    start_node->tx_sched_layer >= ICE_AQC_TOPO_MAX_LEVEL_NUM ||
9671d10453SEric Joyner 	    start_node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF)
9771d10453SEric Joyner 		return NULL;
9871d10453SEric Joyner 
9971d10453SEric Joyner 	/* Check if TEID matches to any of the children nodes */
10071d10453SEric Joyner 	for (i = 0; i < start_node->num_children; i++)
10171d10453SEric Joyner 		if (ICE_TXSCHED_GET_NODE_TEID(start_node->children[i]) == teid)
10271d10453SEric Joyner 			return start_node->children[i];
10371d10453SEric Joyner 
10471d10453SEric Joyner 	/* Search within each child's sub-tree */
10571d10453SEric Joyner 	for (i = 0; i < start_node->num_children; i++) {
10671d10453SEric Joyner 		struct ice_sched_node *tmp;
10771d10453SEric Joyner 
10871d10453SEric Joyner 		tmp = ice_sched_find_node_by_teid(start_node->children[i],
10971d10453SEric Joyner 						  teid);
11071d10453SEric Joyner 		if (tmp)
11171d10453SEric Joyner 			return tmp;
11271d10453SEric Joyner 	}
11371d10453SEric Joyner 
11471d10453SEric Joyner 	return NULL;
11571d10453SEric Joyner }
11671d10453SEric Joyner 
11771d10453SEric Joyner /**
11871d10453SEric Joyner  * ice_aqc_send_sched_elem_cmd - send scheduling elements cmd
11971d10453SEric Joyner  * @hw: pointer to the HW struct
12071d10453SEric Joyner  * @cmd_opc: cmd opcode
12171d10453SEric Joyner  * @elems_req: number of elements to request
12271d10453SEric Joyner  * @buf: pointer to buffer
12371d10453SEric Joyner  * @buf_size: buffer size in bytes
12471d10453SEric Joyner  * @elems_resp: returns total number of elements response
12571d10453SEric Joyner  * @cd: pointer to command details structure or NULL
12671d10453SEric Joyner  *
12771d10453SEric Joyner  * This function sends a scheduling elements cmd (cmd_opc)
12871d10453SEric Joyner  */
129*f2635e84SEric Joyner static int
13071d10453SEric Joyner ice_aqc_send_sched_elem_cmd(struct ice_hw *hw, enum ice_adminq_opc cmd_opc,
13171d10453SEric Joyner 			    u16 elems_req, void *buf, u16 buf_size,
13271d10453SEric Joyner 			    u16 *elems_resp, struct ice_sq_cd *cd)
13371d10453SEric Joyner {
13471d10453SEric Joyner 	struct ice_aqc_sched_elem_cmd *cmd;
13571d10453SEric Joyner 	struct ice_aq_desc desc;
136*f2635e84SEric Joyner 	int status;
13771d10453SEric Joyner 
13871d10453SEric Joyner 	cmd = &desc.params.sched_elem_cmd;
13971d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, cmd_opc);
14071d10453SEric Joyner 	cmd->num_elem_req = CPU_TO_LE16(elems_req);
14171d10453SEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
14271d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
14371d10453SEric Joyner 	if (!status && elems_resp)
14471d10453SEric Joyner 		*elems_resp = LE16_TO_CPU(cmd->num_elem_resp);
14571d10453SEric Joyner 
14671d10453SEric Joyner 	return status;
14771d10453SEric Joyner }
14871d10453SEric Joyner 
14971d10453SEric Joyner /**
15071d10453SEric Joyner  * ice_aq_query_sched_elems - query scheduler elements
15171d10453SEric Joyner  * @hw: pointer to the HW struct
15271d10453SEric Joyner  * @elems_req: number of elements to query
15371d10453SEric Joyner  * @buf: pointer to buffer
15471d10453SEric Joyner  * @buf_size: buffer size in bytes
15571d10453SEric Joyner  * @elems_ret: returns total number of elements returned
15671d10453SEric Joyner  * @cd: pointer to command details structure or NULL
15771d10453SEric Joyner  *
15871d10453SEric Joyner  * Query scheduling elements (0x0404)
15971d10453SEric Joyner  */
160*f2635e84SEric Joyner int
16171d10453SEric Joyner ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req,
1627d7af7f8SEric Joyner 			 struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
16371d10453SEric Joyner 			 u16 *elems_ret, struct ice_sq_cd *cd)
16471d10453SEric Joyner {
16571d10453SEric Joyner 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_get_sched_elems,
16671d10453SEric Joyner 					   elems_req, (void *)buf, buf_size,
16771d10453SEric Joyner 					   elems_ret, cd);
16871d10453SEric Joyner }
16971d10453SEric Joyner 
17071d10453SEric Joyner /**
17171d10453SEric Joyner  * ice_sched_add_node - Insert the Tx scheduler node in SW DB
17271d10453SEric Joyner  * @pi: port information structure
17371d10453SEric Joyner  * @layer: Scheduler layer of the node
17471d10453SEric Joyner  * @info: Scheduler element information from firmware
1759c30461dSEric Joyner  * @prealloc_node: preallocated ice_sched_node struct for SW DB
17671d10453SEric Joyner  *
17771d10453SEric Joyner  * This function inserts a scheduler node to the SW DB.
17871d10453SEric Joyner  */
179*f2635e84SEric Joyner int
18071d10453SEric Joyner ice_sched_add_node(struct ice_port_info *pi, u8 layer,
1819c30461dSEric Joyner 		   struct ice_aqc_txsched_elem_data *info,
1829c30461dSEric Joyner 		   struct ice_sched_node *prealloc_node)
18371d10453SEric Joyner {
1847d7af7f8SEric Joyner 	struct ice_aqc_txsched_elem_data elem;
18571d10453SEric Joyner 	struct ice_sched_node *parent;
18671d10453SEric Joyner 	struct ice_sched_node *node;
18771d10453SEric Joyner 	struct ice_hw *hw;
188*f2635e84SEric Joyner 	int status;
18971d10453SEric Joyner 
19071d10453SEric Joyner 	if (!pi)
19171d10453SEric Joyner 		return ICE_ERR_PARAM;
19271d10453SEric Joyner 
19371d10453SEric Joyner 	hw = pi->hw;
19471d10453SEric Joyner 
19571d10453SEric Joyner 	/* A valid parent node should be there */
19671d10453SEric Joyner 	parent = ice_sched_find_node_by_teid(pi->root,
19771d10453SEric Joyner 					     LE32_TO_CPU(info->parent_teid));
19871d10453SEric Joyner 	if (!parent) {
1997d7af7f8SEric Joyner 		ice_debug(hw, ICE_DBG_SCHED, "Parent Node not found for parent_teid=0x%x\n",
20071d10453SEric Joyner 			  LE32_TO_CPU(info->parent_teid));
20171d10453SEric Joyner 		return ICE_ERR_PARAM;
20271d10453SEric Joyner 	}
20371d10453SEric Joyner 
2047d7af7f8SEric Joyner 	/* query the current node information from FW before adding it
20571d10453SEric Joyner 	 * to the SW DB
20671d10453SEric Joyner 	 */
20771d10453SEric Joyner 	status = ice_sched_query_elem(hw, LE32_TO_CPU(info->node_teid), &elem);
20871d10453SEric Joyner 	if (status)
20971d10453SEric Joyner 		return status;
2109c30461dSEric Joyner 
2119c30461dSEric Joyner 	if (prealloc_node)
2129c30461dSEric Joyner 		node = prealloc_node;
2139c30461dSEric Joyner 	else
21471d10453SEric Joyner 		node = (struct ice_sched_node *)ice_malloc(hw, sizeof(*node));
21571d10453SEric Joyner 	if (!node)
21671d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
21771d10453SEric Joyner 	if (hw->max_children[layer]) {
21871d10453SEric Joyner 		node->children = (struct ice_sched_node **)
2199e54973fSEric Joyner 			ice_calloc(hw, hw->max_children[layer],
2209e54973fSEric Joyner 				   sizeof(*node->children));
22171d10453SEric Joyner 		if (!node->children) {
22271d10453SEric Joyner 			ice_free(hw, node);
22371d10453SEric Joyner 			return ICE_ERR_NO_MEMORY;
22471d10453SEric Joyner 		}
22571d10453SEric Joyner 	}
22671d10453SEric Joyner 
22771d10453SEric Joyner 	node->in_use = true;
22871d10453SEric Joyner 	node->parent = parent;
22971d10453SEric Joyner 	node->tx_sched_layer = layer;
23071d10453SEric Joyner 	parent->children[parent->num_children++] = node;
2317d7af7f8SEric Joyner 	node->info = elem;
232*f2635e84SEric Joyner 	return 0;
23371d10453SEric Joyner }
23471d10453SEric Joyner 
23571d10453SEric Joyner /**
23671d10453SEric Joyner  * ice_aq_delete_sched_elems - delete scheduler elements
23771d10453SEric Joyner  * @hw: pointer to the HW struct
23871d10453SEric Joyner  * @grps_req: number of groups to delete
23971d10453SEric Joyner  * @buf: pointer to buffer
24071d10453SEric Joyner  * @buf_size: buffer size in bytes
24171d10453SEric Joyner  * @grps_del: returns total number of elements deleted
24271d10453SEric Joyner  * @cd: pointer to command details structure or NULL
24371d10453SEric Joyner  *
24471d10453SEric Joyner  * Delete scheduling elements (0x040F)
24571d10453SEric Joyner  */
246*f2635e84SEric Joyner static int
24771d10453SEric Joyner ice_aq_delete_sched_elems(struct ice_hw *hw, u16 grps_req,
24871d10453SEric Joyner 			  struct ice_aqc_delete_elem *buf, u16 buf_size,
24971d10453SEric Joyner 			  u16 *grps_del, struct ice_sq_cd *cd)
25071d10453SEric Joyner {
25171d10453SEric Joyner 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_delete_sched_elems,
25271d10453SEric Joyner 					   grps_req, (void *)buf, buf_size,
25371d10453SEric Joyner 					   grps_del, cd);
25471d10453SEric Joyner }
25571d10453SEric Joyner 
25671d10453SEric Joyner /**
25771d10453SEric Joyner  * ice_sched_remove_elems - remove nodes from HW
25871d10453SEric Joyner  * @hw: pointer to the HW struct
25971d10453SEric Joyner  * @parent: pointer to the parent node
26071d10453SEric Joyner  * @num_nodes: number of nodes
26171d10453SEric Joyner  * @node_teids: array of node teids to be deleted
26271d10453SEric Joyner  *
26371d10453SEric Joyner  * This function remove nodes from HW
26471d10453SEric Joyner  */
265*f2635e84SEric Joyner static int
26671d10453SEric Joyner ice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent,
26771d10453SEric Joyner 		       u16 num_nodes, u32 *node_teids)
26871d10453SEric Joyner {
26971d10453SEric Joyner 	struct ice_aqc_delete_elem *buf;
27071d10453SEric Joyner 	u16 i, num_groups_removed = 0;
27171d10453SEric Joyner 	u16 buf_size;
272*f2635e84SEric Joyner 	int status;
27371d10453SEric Joyner 
2747d7af7f8SEric Joyner 	buf_size = ice_struct_size(buf, teid, num_nodes);
27571d10453SEric Joyner 	buf = (struct ice_aqc_delete_elem *)ice_malloc(hw, buf_size);
27671d10453SEric Joyner 	if (!buf)
27771d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
27871d10453SEric Joyner 
27971d10453SEric Joyner 	buf->hdr.parent_teid = parent->info.node_teid;
28071d10453SEric Joyner 	buf->hdr.num_elems = CPU_TO_LE16(num_nodes);
28171d10453SEric Joyner 	for (i = 0; i < num_nodes; i++)
28271d10453SEric Joyner 		buf->teid[i] = CPU_TO_LE32(node_teids[i]);
28371d10453SEric Joyner 
28471d10453SEric Joyner 	status = ice_aq_delete_sched_elems(hw, 1, buf, buf_size,
28571d10453SEric Joyner 					   &num_groups_removed, NULL);
286*f2635e84SEric Joyner 	if (status || num_groups_removed != 1)
28771d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SCHED, "remove node failed FW error %d\n",
28871d10453SEric Joyner 			  hw->adminq.sq_last_status);
28971d10453SEric Joyner 
29071d10453SEric Joyner 	ice_free(hw, buf);
29171d10453SEric Joyner 	return status;
29271d10453SEric Joyner }
29371d10453SEric Joyner 
29471d10453SEric Joyner /**
29571d10453SEric Joyner  * ice_sched_get_first_node - get the first node of the given layer
29671d10453SEric Joyner  * @pi: port information structure
29771d10453SEric Joyner  * @parent: pointer the base node of the subtree
29871d10453SEric Joyner  * @layer: layer number
29971d10453SEric Joyner  *
30071d10453SEric Joyner  * This function retrieves the first node of the given layer from the subtree
30171d10453SEric Joyner  */
30271d10453SEric Joyner static struct ice_sched_node *
30371d10453SEric Joyner ice_sched_get_first_node(struct ice_port_info *pi,
30471d10453SEric Joyner 			 struct ice_sched_node *parent, u8 layer)
30571d10453SEric Joyner {
30671d10453SEric Joyner 	return pi->sib_head[parent->tc_num][layer];
30771d10453SEric Joyner }
30871d10453SEric Joyner 
30971d10453SEric Joyner /**
31071d10453SEric Joyner  * ice_sched_get_tc_node - get pointer to TC node
31171d10453SEric Joyner  * @pi: port information structure
31271d10453SEric Joyner  * @tc: TC number
31371d10453SEric Joyner  *
31471d10453SEric Joyner  * This function returns the TC node pointer
31571d10453SEric Joyner  */
31671d10453SEric Joyner struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc)
31771d10453SEric Joyner {
31871d10453SEric Joyner 	u8 i;
31971d10453SEric Joyner 
32071d10453SEric Joyner 	if (!pi || !pi->root)
32171d10453SEric Joyner 		return NULL;
32271d10453SEric Joyner 	for (i = 0; i < pi->root->num_children; i++)
32371d10453SEric Joyner 		if (pi->root->children[i]->tc_num == tc)
32471d10453SEric Joyner 			return pi->root->children[i];
32571d10453SEric Joyner 	return NULL;
32671d10453SEric Joyner }
32771d10453SEric Joyner 
32871d10453SEric Joyner /**
32971d10453SEric Joyner  * ice_free_sched_node - Free a Tx scheduler node from SW DB
33071d10453SEric Joyner  * @pi: port information structure
33171d10453SEric Joyner  * @node: pointer to the ice_sched_node struct
33271d10453SEric Joyner  *
33371d10453SEric Joyner  * This function frees up a node from SW DB as well as from HW
33471d10453SEric Joyner  *
33571d10453SEric Joyner  * This function needs to be called with the port_info->sched_lock held
33671d10453SEric Joyner  */
33771d10453SEric Joyner void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)
33871d10453SEric Joyner {
33971d10453SEric Joyner 	struct ice_sched_node *parent;
34071d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
34171d10453SEric Joyner 	u8 i, j;
34271d10453SEric Joyner 
34371d10453SEric Joyner 	/* Free the children before freeing up the parent node
34471d10453SEric Joyner 	 * The parent array is updated below and that shifts the nodes
34571d10453SEric Joyner 	 * in the array. So always pick the first child if num children > 0
34671d10453SEric Joyner 	 */
34771d10453SEric Joyner 	while (node->num_children)
34871d10453SEric Joyner 		ice_free_sched_node(pi, node->children[0]);
34971d10453SEric Joyner 
35071d10453SEric Joyner 	/* Leaf, TC and root nodes can't be deleted by SW */
35171d10453SEric Joyner 	if (node->tx_sched_layer >= hw->sw_entry_point_layer &&
35271d10453SEric Joyner 	    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
35371d10453SEric Joyner 	    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT &&
35471d10453SEric Joyner 	    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) {
35571d10453SEric Joyner 		u32 teid = LE32_TO_CPU(node->info.node_teid);
35671d10453SEric Joyner 
35771d10453SEric Joyner 		ice_sched_remove_elems(hw, node->parent, 1, &teid);
35871d10453SEric Joyner 	}
35971d10453SEric Joyner 	parent = node->parent;
36071d10453SEric Joyner 	/* root has no parent */
36171d10453SEric Joyner 	if (parent) {
36271d10453SEric Joyner 		struct ice_sched_node *p;
36371d10453SEric Joyner 
36471d10453SEric Joyner 		/* update the parent */
36571d10453SEric Joyner 		for (i = 0; i < parent->num_children; i++)
36671d10453SEric Joyner 			if (parent->children[i] == node) {
36771d10453SEric Joyner 				for (j = i + 1; j < parent->num_children; j++)
36871d10453SEric Joyner 					parent->children[j - 1] =
36971d10453SEric Joyner 						parent->children[j];
37071d10453SEric Joyner 				parent->num_children--;
37171d10453SEric Joyner 				break;
37271d10453SEric Joyner 			}
37371d10453SEric Joyner 
37471d10453SEric Joyner 		p = ice_sched_get_first_node(pi, node, node->tx_sched_layer);
37571d10453SEric Joyner 		while (p) {
37671d10453SEric Joyner 			if (p->sibling == node) {
37771d10453SEric Joyner 				p->sibling = node->sibling;
37871d10453SEric Joyner 				break;
37971d10453SEric Joyner 			}
38071d10453SEric Joyner 			p = p->sibling;
38171d10453SEric Joyner 		}
38271d10453SEric Joyner 
38371d10453SEric Joyner 		/* update the sibling head if head is getting removed */
38471d10453SEric Joyner 		if (pi->sib_head[node->tc_num][node->tx_sched_layer] == node)
38571d10453SEric Joyner 			pi->sib_head[node->tc_num][node->tx_sched_layer] =
38671d10453SEric Joyner 				node->sibling;
38771d10453SEric Joyner 	}
38871d10453SEric Joyner 
38971d10453SEric Joyner 	/* leaf nodes have no children */
39071d10453SEric Joyner 	if (node->children)
39171d10453SEric Joyner 		ice_free(hw, node->children);
39271d10453SEric Joyner 	ice_free(hw, node);
39371d10453SEric Joyner }
39471d10453SEric Joyner 
39571d10453SEric Joyner /**
39671d10453SEric Joyner  * ice_aq_get_dflt_topo - gets default scheduler topology
39771d10453SEric Joyner  * @hw: pointer to the HW struct
39871d10453SEric Joyner  * @lport: logical port number
39971d10453SEric Joyner  * @buf: pointer to buffer
40071d10453SEric Joyner  * @buf_size: buffer size in bytes
40171d10453SEric Joyner  * @num_branches: returns total number of queue to port branches
40271d10453SEric Joyner  * @cd: pointer to command details structure or NULL
40371d10453SEric Joyner  *
40471d10453SEric Joyner  * Get default scheduler topology (0x400)
40571d10453SEric Joyner  */
406*f2635e84SEric Joyner static int
40771d10453SEric Joyner ice_aq_get_dflt_topo(struct ice_hw *hw, u8 lport,
40871d10453SEric Joyner 		     struct ice_aqc_get_topo_elem *buf, u16 buf_size,
40971d10453SEric Joyner 		     u8 *num_branches, struct ice_sq_cd *cd)
41071d10453SEric Joyner {
41171d10453SEric Joyner 	struct ice_aqc_get_topo *cmd;
41271d10453SEric Joyner 	struct ice_aq_desc desc;
413*f2635e84SEric Joyner 	int status;
41471d10453SEric Joyner 
41571d10453SEric Joyner 	cmd = &desc.params.get_topo;
41671d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_dflt_topo);
41771d10453SEric Joyner 	cmd->port_num = lport;
41871d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
41971d10453SEric Joyner 	if (!status && num_branches)
42071d10453SEric Joyner 		*num_branches = cmd->num_branches;
42171d10453SEric Joyner 
42271d10453SEric Joyner 	return status;
42371d10453SEric Joyner }
42471d10453SEric Joyner 
42571d10453SEric Joyner /**
42671d10453SEric Joyner  * ice_aq_add_sched_elems - adds scheduling element
42771d10453SEric Joyner  * @hw: pointer to the HW struct
42871d10453SEric Joyner  * @grps_req: the number of groups that are requested to be added
42971d10453SEric Joyner  * @buf: pointer to buffer
43071d10453SEric Joyner  * @buf_size: buffer size in bytes
43171d10453SEric Joyner  * @grps_added: returns total number of groups added
43271d10453SEric Joyner  * @cd: pointer to command details structure or NULL
43371d10453SEric Joyner  *
43471d10453SEric Joyner  * Add scheduling elements (0x0401)
43571d10453SEric Joyner  */
436*f2635e84SEric Joyner static int
43771d10453SEric Joyner ice_aq_add_sched_elems(struct ice_hw *hw, u16 grps_req,
43871d10453SEric Joyner 		       struct ice_aqc_add_elem *buf, u16 buf_size,
43971d10453SEric Joyner 		       u16 *grps_added, struct ice_sq_cd *cd)
44071d10453SEric Joyner {
44171d10453SEric Joyner 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_add_sched_elems,
44271d10453SEric Joyner 					   grps_req, (void *)buf, buf_size,
44371d10453SEric Joyner 					   grps_added, cd);
44471d10453SEric Joyner }
44571d10453SEric Joyner 
44671d10453SEric Joyner /**
44771d10453SEric Joyner  * ice_aq_cfg_sched_elems - configures scheduler elements
44871d10453SEric Joyner  * @hw: pointer to the HW struct
44971d10453SEric Joyner  * @elems_req: number of elements to configure
45071d10453SEric Joyner  * @buf: pointer to buffer
45171d10453SEric Joyner  * @buf_size: buffer size in bytes
45271d10453SEric Joyner  * @elems_cfgd: returns total number of elements configured
45371d10453SEric Joyner  * @cd: pointer to command details structure or NULL
45471d10453SEric Joyner  *
45571d10453SEric Joyner  * Configure scheduling elements (0x0403)
45671d10453SEric Joyner  */
457*f2635e84SEric Joyner static int
45871d10453SEric Joyner ice_aq_cfg_sched_elems(struct ice_hw *hw, u16 elems_req,
4597d7af7f8SEric Joyner 		       struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
46071d10453SEric Joyner 		       u16 *elems_cfgd, struct ice_sq_cd *cd)
46171d10453SEric Joyner {
46271d10453SEric Joyner 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_cfg_sched_elems,
46371d10453SEric Joyner 					   elems_req, (void *)buf, buf_size,
46471d10453SEric Joyner 					   elems_cfgd, cd);
46571d10453SEric Joyner }
46671d10453SEric Joyner 
46771d10453SEric Joyner /**
46871d10453SEric Joyner  * ice_aq_move_sched_elems - move scheduler elements
46971d10453SEric Joyner  * @hw: pointer to the HW struct
47071d10453SEric Joyner  * @grps_req: number of groups to move
47171d10453SEric Joyner  * @buf: pointer to buffer
47271d10453SEric Joyner  * @buf_size: buffer size in bytes
47371d10453SEric Joyner  * @grps_movd: returns total number of groups moved
47471d10453SEric Joyner  * @cd: pointer to command details structure or NULL
47571d10453SEric Joyner  *
47671d10453SEric Joyner  * Move scheduling elements (0x0408)
47771d10453SEric Joyner  */
478*f2635e84SEric Joyner int
47971d10453SEric Joyner ice_aq_move_sched_elems(struct ice_hw *hw, u16 grps_req,
48071d10453SEric Joyner 			struct ice_aqc_move_elem *buf, u16 buf_size,
48171d10453SEric Joyner 			u16 *grps_movd, struct ice_sq_cd *cd)
48271d10453SEric Joyner {
48371d10453SEric Joyner 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_move_sched_elems,
48471d10453SEric Joyner 					   grps_req, (void *)buf, buf_size,
48571d10453SEric Joyner 					   grps_movd, cd);
48671d10453SEric Joyner }
48771d10453SEric Joyner 
48871d10453SEric Joyner /**
48971d10453SEric Joyner  * ice_aq_suspend_sched_elems - suspend scheduler elements
49071d10453SEric Joyner  * @hw: pointer to the HW struct
49171d10453SEric Joyner  * @elems_req: number of elements to suspend
49271d10453SEric Joyner  * @buf: pointer to buffer
49371d10453SEric Joyner  * @buf_size: buffer size in bytes
49471d10453SEric Joyner  * @elems_ret: returns total number of elements suspended
49571d10453SEric Joyner  * @cd: pointer to command details structure or NULL
49671d10453SEric Joyner  *
49771d10453SEric Joyner  * Suspend scheduling elements (0x0409)
49871d10453SEric Joyner  */
499*f2635e84SEric Joyner static int
5007d7af7f8SEric Joyner ice_aq_suspend_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf,
50171d10453SEric Joyner 			   u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)
50271d10453SEric Joyner {
50371d10453SEric Joyner 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_suspend_sched_elems,
50471d10453SEric Joyner 					   elems_req, (void *)buf, buf_size,
50571d10453SEric Joyner 					   elems_ret, cd);
50671d10453SEric Joyner }
50771d10453SEric Joyner 
50871d10453SEric Joyner /**
50971d10453SEric Joyner  * ice_aq_resume_sched_elems - resume scheduler elements
51071d10453SEric Joyner  * @hw: pointer to the HW struct
51171d10453SEric Joyner  * @elems_req: number of elements to resume
51271d10453SEric Joyner  * @buf: pointer to buffer
51371d10453SEric Joyner  * @buf_size: buffer size in bytes
51471d10453SEric Joyner  * @elems_ret: returns total number of elements resumed
51571d10453SEric Joyner  * @cd: pointer to command details structure or NULL
51671d10453SEric Joyner  *
51771d10453SEric Joyner  * resume scheduling elements (0x040A)
51871d10453SEric Joyner  */
519*f2635e84SEric Joyner static int
5207d7af7f8SEric Joyner ice_aq_resume_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf,
52171d10453SEric Joyner 			  u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)
52271d10453SEric Joyner {
52371d10453SEric Joyner 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_resume_sched_elems,
52471d10453SEric Joyner 					   elems_req, (void *)buf, buf_size,
52571d10453SEric Joyner 					   elems_ret, cd);
52671d10453SEric Joyner }
52771d10453SEric Joyner 
52871d10453SEric Joyner /**
52971d10453SEric Joyner  * ice_aq_query_sched_res - query scheduler resource
53071d10453SEric Joyner  * @hw: pointer to the HW struct
53171d10453SEric Joyner  * @buf_size: buffer size in bytes
53271d10453SEric Joyner  * @buf: pointer to buffer
53371d10453SEric Joyner  * @cd: pointer to command details structure or NULL
53471d10453SEric Joyner  *
53571d10453SEric Joyner  * Query scheduler resource allocation (0x0412)
53671d10453SEric Joyner  */
537*f2635e84SEric Joyner static int
53871d10453SEric Joyner ice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size,
53971d10453SEric Joyner 		       struct ice_aqc_query_txsched_res_resp *buf,
54071d10453SEric Joyner 		       struct ice_sq_cd *cd)
54171d10453SEric Joyner {
54271d10453SEric Joyner 	struct ice_aq_desc desc;
54371d10453SEric Joyner 
54471d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_sched_res);
54571d10453SEric Joyner 	return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
54671d10453SEric Joyner }
54771d10453SEric Joyner 
54871d10453SEric Joyner /**
54971d10453SEric Joyner  * ice_sched_suspend_resume_elems - suspend or resume HW nodes
55071d10453SEric Joyner  * @hw: pointer to the HW struct
55171d10453SEric Joyner  * @num_nodes: number of nodes
55271d10453SEric Joyner  * @node_teids: array of node teids to be suspended or resumed
55371d10453SEric Joyner  * @suspend: true means suspend / false means resume
55471d10453SEric Joyner  *
55571d10453SEric Joyner  * This function suspends or resumes HW nodes
55671d10453SEric Joyner  */
557*f2635e84SEric Joyner static int
55871d10453SEric Joyner ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids,
55971d10453SEric Joyner 			       bool suspend)
56071d10453SEric Joyner {
56171d10453SEric Joyner 	u16 i, buf_size, num_elem_ret = 0;
5627d7af7f8SEric Joyner 	__le32 *buf;
563*f2635e84SEric Joyner 	int status;
56471d10453SEric Joyner 
56571d10453SEric Joyner 	buf_size = sizeof(*buf) * num_nodes;
5667d7af7f8SEric Joyner 	buf = (__le32 *)ice_malloc(hw, buf_size);
56771d10453SEric Joyner 	if (!buf)
56871d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
56971d10453SEric Joyner 
57071d10453SEric Joyner 	for (i = 0; i < num_nodes; i++)
5717d7af7f8SEric Joyner 		buf[i] = CPU_TO_LE32(node_teids[i]);
57271d10453SEric Joyner 
57371d10453SEric Joyner 	if (suspend)
57471d10453SEric Joyner 		status = ice_aq_suspend_sched_elems(hw, num_nodes, buf,
57571d10453SEric Joyner 						    buf_size, &num_elem_ret,
57671d10453SEric Joyner 						    NULL);
57771d10453SEric Joyner 	else
57871d10453SEric Joyner 		status = ice_aq_resume_sched_elems(hw, num_nodes, buf,
57971d10453SEric Joyner 						   buf_size, &num_elem_ret,
58071d10453SEric Joyner 						   NULL);
581*f2635e84SEric Joyner 	if (status || num_elem_ret != num_nodes)
58271d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SCHED, "suspend/resume failed\n");
58371d10453SEric Joyner 
58471d10453SEric Joyner 	ice_free(hw, buf);
58571d10453SEric Joyner 	return status;
58671d10453SEric Joyner }
58771d10453SEric Joyner 
58871d10453SEric Joyner /**
58971d10453SEric Joyner  * ice_alloc_lan_q_ctx - allocate LAN queue contexts for the given VSI and TC
59071d10453SEric Joyner  * @hw: pointer to the HW struct
59171d10453SEric Joyner  * @vsi_handle: VSI handle
59271d10453SEric Joyner  * @tc: TC number
59371d10453SEric Joyner  * @new_numqs: number of queues
59471d10453SEric Joyner  */
595*f2635e84SEric Joyner static int
59671d10453SEric Joyner ice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
59771d10453SEric Joyner {
59871d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
59971d10453SEric Joyner 	struct ice_q_ctx *q_ctx;
60071d10453SEric Joyner 
60171d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
60271d10453SEric Joyner 	if (!vsi_ctx)
60371d10453SEric Joyner 		return ICE_ERR_PARAM;
60471d10453SEric Joyner 	/* allocate LAN queue contexts */
60571d10453SEric Joyner 	if (!vsi_ctx->lan_q_ctx[tc]) {
60671d10453SEric Joyner 		vsi_ctx->lan_q_ctx[tc] = (struct ice_q_ctx *)
60771d10453SEric Joyner 			ice_calloc(hw, new_numqs, sizeof(*q_ctx));
60871d10453SEric Joyner 		if (!vsi_ctx->lan_q_ctx[tc])
60971d10453SEric Joyner 			return ICE_ERR_NO_MEMORY;
61071d10453SEric Joyner 		vsi_ctx->num_lan_q_entries[tc] = new_numqs;
611*f2635e84SEric Joyner 		return 0;
61271d10453SEric Joyner 	}
61371d10453SEric Joyner 	/* num queues are increased, update the queue contexts */
61471d10453SEric Joyner 	if (new_numqs > vsi_ctx->num_lan_q_entries[tc]) {
61571d10453SEric Joyner 		u16 prev_num = vsi_ctx->num_lan_q_entries[tc];
61671d10453SEric Joyner 
61771d10453SEric Joyner 		q_ctx = (struct ice_q_ctx *)
61871d10453SEric Joyner 			ice_calloc(hw, new_numqs, sizeof(*q_ctx));
61971d10453SEric Joyner 		if (!q_ctx)
62071d10453SEric Joyner 			return ICE_ERR_NO_MEMORY;
62171d10453SEric Joyner 		ice_memcpy(q_ctx, vsi_ctx->lan_q_ctx[tc],
62271d10453SEric Joyner 			   prev_num * sizeof(*q_ctx), ICE_DMA_TO_NONDMA);
62371d10453SEric Joyner 		ice_free(hw, vsi_ctx->lan_q_ctx[tc]);
62471d10453SEric Joyner 		vsi_ctx->lan_q_ctx[tc] = q_ctx;
62571d10453SEric Joyner 		vsi_ctx->num_lan_q_entries[tc] = new_numqs;
62671d10453SEric Joyner 	}
627*f2635e84SEric Joyner 	return 0;
62871d10453SEric Joyner }
62971d10453SEric Joyner 
63071d10453SEric Joyner /**
6318a13362dSEric Joyner  * ice_alloc_rdma_q_ctx - allocate RDMA queue contexts for the given VSI and TC
6328a13362dSEric Joyner  * @hw: pointer to the HW struct
6338a13362dSEric Joyner  * @vsi_handle: VSI handle
6348a13362dSEric Joyner  * @tc: TC number
6358a13362dSEric Joyner  * @new_numqs: number of queues
6368a13362dSEric Joyner  */
637*f2635e84SEric Joyner static int
6388a13362dSEric Joyner ice_alloc_rdma_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
6398a13362dSEric Joyner {
6408a13362dSEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
6418a13362dSEric Joyner 	struct ice_q_ctx *q_ctx;
6428a13362dSEric Joyner 
6438a13362dSEric Joyner 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
6448a13362dSEric Joyner 	if (!vsi_ctx)
6458a13362dSEric Joyner 		return ICE_ERR_PARAM;
6468a13362dSEric Joyner 	/* allocate RDMA queue contexts */
6478a13362dSEric Joyner 	if (!vsi_ctx->rdma_q_ctx[tc]) {
6488a13362dSEric Joyner 		vsi_ctx->rdma_q_ctx[tc] = (struct ice_q_ctx *)
6498a13362dSEric Joyner 			ice_calloc(hw, new_numqs, sizeof(*q_ctx));
6508a13362dSEric Joyner 		if (!vsi_ctx->rdma_q_ctx[tc])
6518a13362dSEric Joyner 			return ICE_ERR_NO_MEMORY;
6528a13362dSEric Joyner 		vsi_ctx->num_rdma_q_entries[tc] = new_numqs;
653*f2635e84SEric Joyner 		return 0;
6548a13362dSEric Joyner 	}
6558a13362dSEric Joyner 	/* num queues are increased, update the queue contexts */
6568a13362dSEric Joyner 	if (new_numqs > vsi_ctx->num_rdma_q_entries[tc]) {
6578a13362dSEric Joyner 		u16 prev_num = vsi_ctx->num_rdma_q_entries[tc];
6588a13362dSEric Joyner 
6598a13362dSEric Joyner 		q_ctx = (struct ice_q_ctx *)
6608a13362dSEric Joyner 			ice_calloc(hw, new_numqs, sizeof(*q_ctx));
6618a13362dSEric Joyner 		if (!q_ctx)
6628a13362dSEric Joyner 			return ICE_ERR_NO_MEMORY;
6638a13362dSEric Joyner 		ice_memcpy(q_ctx, vsi_ctx->rdma_q_ctx[tc],
6648a13362dSEric Joyner 			   prev_num * sizeof(*q_ctx), ICE_DMA_TO_NONDMA);
6658a13362dSEric Joyner 		ice_free(hw, vsi_ctx->rdma_q_ctx[tc]);
6668a13362dSEric Joyner 		vsi_ctx->rdma_q_ctx[tc] = q_ctx;
6678a13362dSEric Joyner 		vsi_ctx->num_rdma_q_entries[tc] = new_numqs;
6688a13362dSEric Joyner 	}
669*f2635e84SEric Joyner 	return 0;
6708a13362dSEric Joyner }
6718a13362dSEric Joyner 
6728a13362dSEric Joyner /**
67371d10453SEric Joyner  * ice_aq_rl_profile - performs a rate limiting task
67471d10453SEric Joyner  * @hw: pointer to the HW struct
67571d10453SEric Joyner  * @opcode: opcode for add, query, or remove profile(s)
67671d10453SEric Joyner  * @num_profiles: the number of profiles
67771d10453SEric Joyner  * @buf: pointer to buffer
67871d10453SEric Joyner  * @buf_size: buffer size in bytes
67971d10453SEric Joyner  * @num_processed: number of processed add or remove profile(s) to return
68071d10453SEric Joyner  * @cd: pointer to command details structure
68171d10453SEric Joyner  *
6827d7af7f8SEric Joyner  * RL profile function to add, query, or remove profile(s)
68371d10453SEric Joyner  */
684*f2635e84SEric Joyner static int
68571d10453SEric Joyner ice_aq_rl_profile(struct ice_hw *hw, enum ice_adminq_opc opcode,
6867d7af7f8SEric Joyner 		  u16 num_profiles, struct ice_aqc_rl_profile_elem *buf,
68771d10453SEric Joyner 		  u16 buf_size, u16 *num_processed, struct ice_sq_cd *cd)
68871d10453SEric Joyner {
68971d10453SEric Joyner 	struct ice_aqc_rl_profile *cmd;
69071d10453SEric Joyner 	struct ice_aq_desc desc;
691*f2635e84SEric Joyner 	int status;
69271d10453SEric Joyner 
69371d10453SEric Joyner 	cmd = &desc.params.rl_profile;
69471d10453SEric Joyner 
69571d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, opcode);
69671d10453SEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
69771d10453SEric Joyner 	cmd->num_profiles = CPU_TO_LE16(num_profiles);
69871d10453SEric Joyner 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
69971d10453SEric Joyner 	if (!status && num_processed)
70071d10453SEric Joyner 		*num_processed = LE16_TO_CPU(cmd->num_processed);
70171d10453SEric Joyner 	return status;
70271d10453SEric Joyner }
70371d10453SEric Joyner 
70471d10453SEric Joyner /**
70571d10453SEric Joyner  * ice_aq_add_rl_profile - adds rate limiting profile(s)
70671d10453SEric Joyner  * @hw: pointer to the HW struct
70771d10453SEric Joyner  * @num_profiles: the number of profile(s) to be add
70871d10453SEric Joyner  * @buf: pointer to buffer
70971d10453SEric Joyner  * @buf_size: buffer size in bytes
71071d10453SEric Joyner  * @num_profiles_added: total number of profiles added to return
71171d10453SEric Joyner  * @cd: pointer to command details structure
71271d10453SEric Joyner  *
71371d10453SEric Joyner  * Add RL profile (0x0410)
71471d10453SEric Joyner  */
715*f2635e84SEric Joyner static int
71671d10453SEric Joyner ice_aq_add_rl_profile(struct ice_hw *hw, u16 num_profiles,
7177d7af7f8SEric Joyner 		      struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
7187d7af7f8SEric Joyner 		      u16 *num_profiles_added, struct ice_sq_cd *cd)
71971d10453SEric Joyner {
7207d7af7f8SEric Joyner 	return ice_aq_rl_profile(hw, ice_aqc_opc_add_rl_profiles, num_profiles,
7217d7af7f8SEric Joyner 				 buf, buf_size, num_profiles_added, cd);
72271d10453SEric Joyner }
72371d10453SEric Joyner 
72471d10453SEric Joyner /**
72571d10453SEric Joyner  * ice_aq_query_rl_profile - query rate limiting profile(s)
72671d10453SEric Joyner  * @hw: pointer to the HW struct
72771d10453SEric Joyner  * @num_profiles: the number of profile(s) to query
72871d10453SEric Joyner  * @buf: pointer to buffer
72971d10453SEric Joyner  * @buf_size: buffer size in bytes
73071d10453SEric Joyner  * @cd: pointer to command details structure
73171d10453SEric Joyner  *
73271d10453SEric Joyner  * Query RL profile (0x0411)
73371d10453SEric Joyner  */
734*f2635e84SEric Joyner int
73571d10453SEric Joyner ice_aq_query_rl_profile(struct ice_hw *hw, u16 num_profiles,
7367d7af7f8SEric Joyner 			struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
7377d7af7f8SEric Joyner 			struct ice_sq_cd *cd)
73871d10453SEric Joyner {
73971d10453SEric Joyner 	return ice_aq_rl_profile(hw, ice_aqc_opc_query_rl_profiles,
74071d10453SEric Joyner 				 num_profiles, buf, buf_size, NULL, cd);
74171d10453SEric Joyner }
74271d10453SEric Joyner 
74371d10453SEric Joyner /**
74471d10453SEric Joyner  * ice_aq_remove_rl_profile - removes RL profile(s)
74571d10453SEric Joyner  * @hw: pointer to the HW struct
74671d10453SEric Joyner  * @num_profiles: the number of profile(s) to remove
74771d10453SEric Joyner  * @buf: pointer to buffer
74871d10453SEric Joyner  * @buf_size: buffer size in bytes
74971d10453SEric Joyner  * @num_profiles_removed: total number of profiles removed to return
75071d10453SEric Joyner  * @cd: pointer to command details structure or NULL
75171d10453SEric Joyner  *
75271d10453SEric Joyner  * Remove RL profile (0x0415)
75371d10453SEric Joyner  */
754*f2635e84SEric Joyner static int
75571d10453SEric Joyner ice_aq_remove_rl_profile(struct ice_hw *hw, u16 num_profiles,
7567d7af7f8SEric Joyner 			 struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
7577d7af7f8SEric Joyner 			 u16 *num_profiles_removed, struct ice_sq_cd *cd)
75871d10453SEric Joyner {
75971d10453SEric Joyner 	return ice_aq_rl_profile(hw, ice_aqc_opc_remove_rl_profiles,
7607d7af7f8SEric Joyner 				 num_profiles, buf, buf_size,
7617d7af7f8SEric Joyner 				 num_profiles_removed, cd);
76271d10453SEric Joyner }
76371d10453SEric Joyner 
76471d10453SEric Joyner /**
76571d10453SEric Joyner  * ice_sched_del_rl_profile - remove RL profile
76671d10453SEric Joyner  * @hw: pointer to the HW struct
76771d10453SEric Joyner  * @rl_info: rate limit profile information
76871d10453SEric Joyner  *
76971d10453SEric Joyner  * If the profile ID is not referenced anymore, it removes profile ID with
77071d10453SEric Joyner  * its associated parameters from HW DB,and locally. The caller needs to
77171d10453SEric Joyner  * hold scheduler lock.
77271d10453SEric Joyner  */
773*f2635e84SEric Joyner static int
77471d10453SEric Joyner ice_sched_del_rl_profile(struct ice_hw *hw,
77571d10453SEric Joyner 			 struct ice_aqc_rl_profile_info *rl_info)
77671d10453SEric Joyner {
7777d7af7f8SEric Joyner 	struct ice_aqc_rl_profile_elem *buf;
77871d10453SEric Joyner 	u16 num_profiles_removed;
77971d10453SEric Joyner 	u16 num_profiles = 1;
780*f2635e84SEric Joyner 	int status;
78171d10453SEric Joyner 
78271d10453SEric Joyner 	if (rl_info->prof_id_ref != 0)
78371d10453SEric Joyner 		return ICE_ERR_IN_USE;
78471d10453SEric Joyner 
78571d10453SEric Joyner 	/* Safe to remove profile ID */
7867d7af7f8SEric Joyner 	buf = &rl_info->profile;
78771d10453SEric Joyner 	status = ice_aq_remove_rl_profile(hw, num_profiles, buf, sizeof(*buf),
78871d10453SEric Joyner 					  &num_profiles_removed, NULL);
78971d10453SEric Joyner 	if (status || num_profiles_removed != num_profiles)
79071d10453SEric Joyner 		return ICE_ERR_CFG;
79171d10453SEric Joyner 
79271d10453SEric Joyner 	/* Delete stale entry now */
79371d10453SEric Joyner 	LIST_DEL(&rl_info->list_entry);
79471d10453SEric Joyner 	ice_free(hw, rl_info);
79571d10453SEric Joyner 	return status;
79671d10453SEric Joyner }
79771d10453SEric Joyner 
79871d10453SEric Joyner /**
79971d10453SEric Joyner  * ice_sched_clear_rl_prof - clears RL prof entries
80071d10453SEric Joyner  * @pi: port information structure
80171d10453SEric Joyner  *
80271d10453SEric Joyner  * This function removes all RL profile from HW as well as from SW DB.
80371d10453SEric Joyner  */
80471d10453SEric Joyner static void ice_sched_clear_rl_prof(struct ice_port_info *pi)
80571d10453SEric Joyner {
80671d10453SEric Joyner 	u16 ln;
807d08b8680SEric Joyner 	struct ice_hw *hw = pi->hw;
80871d10453SEric Joyner 
809d08b8680SEric Joyner 	for (ln = 0; ln < hw->num_tx_sched_layers; ln++) {
81071d10453SEric Joyner 		struct ice_aqc_rl_profile_info *rl_prof_elem;
81171d10453SEric Joyner 		struct ice_aqc_rl_profile_info *rl_prof_tmp;
81271d10453SEric Joyner 
81371d10453SEric Joyner 		LIST_FOR_EACH_ENTRY_SAFE(rl_prof_elem, rl_prof_tmp,
814d08b8680SEric Joyner 					 &hw->rl_prof_list[ln],
81571d10453SEric Joyner 					 ice_aqc_rl_profile_info, list_entry) {
816*f2635e84SEric Joyner 			int status;
81771d10453SEric Joyner 
81871d10453SEric Joyner 			rl_prof_elem->prof_id_ref = 0;
81971d10453SEric Joyner 			status = ice_sched_del_rl_profile(hw, rl_prof_elem);
82071d10453SEric Joyner 			if (status) {
8217d7af7f8SEric Joyner 				ice_debug(hw, ICE_DBG_SCHED, "Remove rl profile failed\n");
82271d10453SEric Joyner 				/* On error, free mem required */
82371d10453SEric Joyner 				LIST_DEL(&rl_prof_elem->list_entry);
82471d10453SEric Joyner 				ice_free(hw, rl_prof_elem);
82571d10453SEric Joyner 			}
82671d10453SEric Joyner 		}
82771d10453SEric Joyner 	}
82871d10453SEric Joyner }
82971d10453SEric Joyner 
83071d10453SEric Joyner /**
83171d10453SEric Joyner  * ice_sched_clear_agg - clears the aggregator related information
83271d10453SEric Joyner  * @hw: pointer to the hardware structure
83371d10453SEric Joyner  *
83471d10453SEric Joyner  * This function removes aggregator list and free up aggregator related memory
83571d10453SEric Joyner  * previously allocated.
83671d10453SEric Joyner  */
83771d10453SEric Joyner void ice_sched_clear_agg(struct ice_hw *hw)
83871d10453SEric Joyner {
83971d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
84071d10453SEric Joyner 	struct ice_sched_agg_info *atmp;
84171d10453SEric Joyner 
84271d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(agg_info, atmp, &hw->agg_list,
84371d10453SEric Joyner 				 ice_sched_agg_info,
84471d10453SEric Joyner 				 list_entry) {
84571d10453SEric Joyner 		struct ice_sched_agg_vsi_info *agg_vsi_info;
84671d10453SEric Joyner 		struct ice_sched_agg_vsi_info *vtmp;
84771d10453SEric Joyner 
84871d10453SEric Joyner 		LIST_FOR_EACH_ENTRY_SAFE(agg_vsi_info, vtmp,
84971d10453SEric Joyner 					 &agg_info->agg_vsi_list,
85071d10453SEric Joyner 					 ice_sched_agg_vsi_info, list_entry) {
85171d10453SEric Joyner 			LIST_DEL(&agg_vsi_info->list_entry);
85271d10453SEric Joyner 			ice_free(hw, agg_vsi_info);
85371d10453SEric Joyner 		}
85471d10453SEric Joyner 		LIST_DEL(&agg_info->list_entry);
85571d10453SEric Joyner 		ice_free(hw, agg_info);
85671d10453SEric Joyner 	}
85771d10453SEric Joyner }
85871d10453SEric Joyner 
85971d10453SEric Joyner /**
8607d7af7f8SEric Joyner  * ice_sched_clear_tx_topo - clears the scheduler tree nodes
86171d10453SEric Joyner  * @pi: port information structure
86271d10453SEric Joyner  *
86371d10453SEric Joyner  * This function removes all the nodes from HW as well as from SW DB.
86471d10453SEric Joyner  */
86571d10453SEric Joyner static void ice_sched_clear_tx_topo(struct ice_port_info *pi)
86671d10453SEric Joyner {
86771d10453SEric Joyner 	if (!pi)
86871d10453SEric Joyner 		return;
86971d10453SEric Joyner 	/* remove RL profiles related lists */
87071d10453SEric Joyner 	ice_sched_clear_rl_prof(pi);
87171d10453SEric Joyner 	if (pi->root) {
87271d10453SEric Joyner 		ice_free_sched_node(pi, pi->root);
87371d10453SEric Joyner 		pi->root = NULL;
87471d10453SEric Joyner 	}
87571d10453SEric Joyner }
87671d10453SEric Joyner 
87771d10453SEric Joyner /**
87871d10453SEric Joyner  * ice_sched_clear_port - clear the scheduler elements from SW DB for a port
87971d10453SEric Joyner  * @pi: port information structure
88071d10453SEric Joyner  *
88171d10453SEric Joyner  * Cleanup scheduling elements from SW DB
88271d10453SEric Joyner  */
88371d10453SEric Joyner void ice_sched_clear_port(struct ice_port_info *pi)
88471d10453SEric Joyner {
88571d10453SEric Joyner 	if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
88671d10453SEric Joyner 		return;
88771d10453SEric Joyner 
88871d10453SEric Joyner 	pi->port_state = ICE_SCHED_PORT_STATE_INIT;
88971d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
89071d10453SEric Joyner 	ice_sched_clear_tx_topo(pi);
89171d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
89271d10453SEric Joyner 	ice_destroy_lock(&pi->sched_lock);
89371d10453SEric Joyner }
89471d10453SEric Joyner 
89571d10453SEric Joyner /**
89671d10453SEric Joyner  * ice_sched_cleanup_all - cleanup scheduler elements from SW DB for all ports
89771d10453SEric Joyner  * @hw: pointer to the HW struct
89871d10453SEric Joyner  *
89971d10453SEric Joyner  * Cleanup scheduling elements from SW DB for all the ports
90071d10453SEric Joyner  */
90171d10453SEric Joyner void ice_sched_cleanup_all(struct ice_hw *hw)
90271d10453SEric Joyner {
90371d10453SEric Joyner 	if (!hw)
90471d10453SEric Joyner 		return;
90571d10453SEric Joyner 
90671d10453SEric Joyner 	if (hw->layer_info) {
90771d10453SEric Joyner 		ice_free(hw, hw->layer_info);
90871d10453SEric Joyner 		hw->layer_info = NULL;
90971d10453SEric Joyner 	}
91071d10453SEric Joyner 
91171d10453SEric Joyner 	ice_sched_clear_port(hw->port_info);
91271d10453SEric Joyner 
91371d10453SEric Joyner 	hw->num_tx_sched_layers = 0;
91471d10453SEric Joyner 	hw->num_tx_sched_phys_layers = 0;
91571d10453SEric Joyner 	hw->flattened_layers = 0;
91671d10453SEric Joyner 	hw->max_cgds = 0;
91771d10453SEric Joyner }
91871d10453SEric Joyner 
91971d10453SEric Joyner /**
9208923de59SPiotr Kubaj  * ice_aq_cfg_node_attr - configure nodes' per-cone flattening attributes
9218923de59SPiotr Kubaj  * @hw: pointer to the HW struct
9228923de59SPiotr Kubaj  * @num_nodes: the number of nodes whose attributes to configure
9238923de59SPiotr Kubaj  * @buf: pointer to buffer
9248923de59SPiotr Kubaj  * @buf_size: buffer size in bytes
9258923de59SPiotr Kubaj  * @cd: pointer to command details structure or NULL
9268923de59SPiotr Kubaj  *
9278923de59SPiotr Kubaj  * Configure Node Attributes (0x0417)
9288923de59SPiotr Kubaj  */
929*f2635e84SEric Joyner int
9308923de59SPiotr Kubaj ice_aq_cfg_node_attr(struct ice_hw *hw, u16 num_nodes,
9318923de59SPiotr Kubaj 		     struct ice_aqc_node_attr_elem *buf, u16 buf_size,
9328923de59SPiotr Kubaj 		     struct ice_sq_cd *cd)
9338923de59SPiotr Kubaj {
9348923de59SPiotr Kubaj 	struct ice_aqc_node_attr *cmd;
9358923de59SPiotr Kubaj 	struct ice_aq_desc desc;
9368923de59SPiotr Kubaj 
9378923de59SPiotr Kubaj 	cmd = &desc.params.node_attr;
9388923de59SPiotr Kubaj 	ice_fill_dflt_direct_cmd_desc(&desc,
9398923de59SPiotr Kubaj 				      ice_aqc_opc_cfg_node_attr);
9408923de59SPiotr Kubaj 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
9418923de59SPiotr Kubaj 
9428923de59SPiotr Kubaj 	cmd->num_entries = CPU_TO_LE16(num_nodes);
9438923de59SPiotr Kubaj 	return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
9448923de59SPiotr Kubaj }
9458923de59SPiotr Kubaj 
9468923de59SPiotr Kubaj /**
94771d10453SEric Joyner  * ice_aq_cfg_l2_node_cgd - configures L2 node to CGD mapping
94871d10453SEric Joyner  * @hw: pointer to the HW struct
94971d10453SEric Joyner  * @num_l2_nodes: the number of L2 nodes whose CGDs to configure
95071d10453SEric Joyner  * @buf: pointer to buffer
95171d10453SEric Joyner  * @buf_size: buffer size in bytes
95271d10453SEric Joyner  * @cd: pointer to command details structure or NULL
95371d10453SEric Joyner  *
95471d10453SEric Joyner  * Configure L2 Node CGD (0x0414)
95571d10453SEric Joyner  */
956*f2635e84SEric Joyner int
95771d10453SEric Joyner ice_aq_cfg_l2_node_cgd(struct ice_hw *hw, u16 num_l2_nodes,
9587d7af7f8SEric Joyner 		       struct ice_aqc_cfg_l2_node_cgd_elem *buf,
95971d10453SEric Joyner 		       u16 buf_size, struct ice_sq_cd *cd)
96071d10453SEric Joyner {
96171d10453SEric Joyner 	struct ice_aqc_cfg_l2_node_cgd *cmd;
96271d10453SEric Joyner 	struct ice_aq_desc desc;
96371d10453SEric Joyner 
96471d10453SEric Joyner 	cmd = &desc.params.cfg_l2_node_cgd;
96571d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_cfg_l2_node_cgd);
96671d10453SEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
96771d10453SEric Joyner 
96871d10453SEric Joyner 	cmd->num_l2_nodes = CPU_TO_LE16(num_l2_nodes);
96971d10453SEric Joyner 	return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
97071d10453SEric Joyner }
97171d10453SEric Joyner 
97271d10453SEric Joyner /**
97371d10453SEric Joyner  * ice_sched_add_elems - add nodes to HW and SW DB
97471d10453SEric Joyner  * @pi: port information structure
97571d10453SEric Joyner  * @tc_node: pointer to the branch node
97671d10453SEric Joyner  * @parent: pointer to the parent node
97771d10453SEric Joyner  * @layer: layer number to add nodes
97871d10453SEric Joyner  * @num_nodes: number of nodes
97971d10453SEric Joyner  * @num_nodes_added: pointer to num nodes added
98071d10453SEric Joyner  * @first_node_teid: if new nodes are added then return the TEID of first node
9819c30461dSEric Joyner  * @prealloc_nodes: preallocated nodes struct for software DB
98271d10453SEric Joyner  *
98371d10453SEric Joyner  * This function add nodes to HW as well as to SW DB for a given layer
98471d10453SEric Joyner  */
985*f2635e84SEric Joyner int
98671d10453SEric Joyner ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
98771d10453SEric Joyner 		    struct ice_sched_node *parent, u8 layer, u16 num_nodes,
9889c30461dSEric Joyner 		    u16 *num_nodes_added, u32 *first_node_teid,
9899c30461dSEric Joyner 		    struct ice_sched_node **prealloc_nodes)
99071d10453SEric Joyner {
99171d10453SEric Joyner 	struct ice_sched_node *prev, *new_node;
99271d10453SEric Joyner 	struct ice_aqc_add_elem *buf;
99371d10453SEric Joyner 	u16 i, num_groups_added = 0;
99471d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
995*f2635e84SEric Joyner 	int status = 0;
99671d10453SEric Joyner 	u16 buf_size;
99771d10453SEric Joyner 	u32 teid;
99871d10453SEric Joyner 
9997d7af7f8SEric Joyner 	buf_size = ice_struct_size(buf, generic, num_nodes);
100071d10453SEric Joyner 	buf = (struct ice_aqc_add_elem *)ice_malloc(hw, buf_size);
100171d10453SEric Joyner 	if (!buf)
100271d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
100371d10453SEric Joyner 
100471d10453SEric Joyner 	buf->hdr.parent_teid = parent->info.node_teid;
100571d10453SEric Joyner 	buf->hdr.num_elems = CPU_TO_LE16(num_nodes);
100671d10453SEric Joyner 	for (i = 0; i < num_nodes; i++) {
100771d10453SEric Joyner 		buf->generic[i].parent_teid = parent->info.node_teid;
100871d10453SEric Joyner 		buf->generic[i].data.elem_type = ICE_AQC_ELEM_TYPE_SE_GENERIC;
100971d10453SEric Joyner 		buf->generic[i].data.valid_sections =
101071d10453SEric Joyner 			ICE_AQC_ELEM_VALID_GENERIC | ICE_AQC_ELEM_VALID_CIR |
101171d10453SEric Joyner 			ICE_AQC_ELEM_VALID_EIR;
101271d10453SEric Joyner 		buf->generic[i].data.generic = 0;
101371d10453SEric Joyner 		buf->generic[i].data.cir_bw.bw_profile_idx =
101471d10453SEric Joyner 			CPU_TO_LE16(ICE_SCHED_DFLT_RL_PROF_ID);
101571d10453SEric Joyner 		buf->generic[i].data.cir_bw.bw_alloc =
101671d10453SEric Joyner 			CPU_TO_LE16(ICE_SCHED_DFLT_BW_WT);
101771d10453SEric Joyner 		buf->generic[i].data.eir_bw.bw_profile_idx =
101871d10453SEric Joyner 			CPU_TO_LE16(ICE_SCHED_DFLT_RL_PROF_ID);
101971d10453SEric Joyner 		buf->generic[i].data.eir_bw.bw_alloc =
102071d10453SEric Joyner 			CPU_TO_LE16(ICE_SCHED_DFLT_BW_WT);
102171d10453SEric Joyner 	}
102271d10453SEric Joyner 
102371d10453SEric Joyner 	status = ice_aq_add_sched_elems(hw, 1, buf, buf_size,
102471d10453SEric Joyner 					&num_groups_added, NULL);
1025*f2635e84SEric Joyner 	if (status || num_groups_added != 1) {
102671d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SCHED, "add node failed FW Error %d\n",
102771d10453SEric Joyner 			  hw->adminq.sq_last_status);
102871d10453SEric Joyner 		ice_free(hw, buf);
102971d10453SEric Joyner 		return ICE_ERR_CFG;
103071d10453SEric Joyner 	}
103171d10453SEric Joyner 
103271d10453SEric Joyner 	*num_nodes_added = num_nodes;
103371d10453SEric Joyner 	/* add nodes to the SW DB */
103471d10453SEric Joyner 	for (i = 0; i < num_nodes; i++) {
10359c30461dSEric Joyner 		if (prealloc_nodes)
10369c30461dSEric Joyner 			status = ice_sched_add_node(pi, layer, &buf->generic[i], prealloc_nodes[i]);
10379c30461dSEric Joyner 		else
10389c30461dSEric Joyner 			status = ice_sched_add_node(pi, layer, &buf->generic[i], NULL);
10399c30461dSEric Joyner 
1040*f2635e84SEric Joyner 		if (status) {
10417d7af7f8SEric Joyner 			ice_debug(hw, ICE_DBG_SCHED, "add nodes in SW DB failed status =%d\n",
104271d10453SEric Joyner 				  status);
104371d10453SEric Joyner 			break;
104471d10453SEric Joyner 		}
104571d10453SEric Joyner 
104671d10453SEric Joyner 		teid = LE32_TO_CPU(buf->generic[i].node_teid);
104771d10453SEric Joyner 		new_node = ice_sched_find_node_by_teid(parent, teid);
104871d10453SEric Joyner 		if (!new_node) {
10497d7af7f8SEric Joyner 			ice_debug(hw, ICE_DBG_SCHED, "Node is missing for teid =%d\n", teid);
105071d10453SEric Joyner 			break;
105171d10453SEric Joyner 		}
105271d10453SEric Joyner 
105371d10453SEric Joyner 		new_node->sibling = NULL;
105471d10453SEric Joyner 		new_node->tc_num = tc_node->tc_num;
105571d10453SEric Joyner 
105671d10453SEric Joyner 		/* add it to previous node sibling pointer */
105771d10453SEric Joyner 		/* Note: siblings are not linked across branches */
105871d10453SEric Joyner 		prev = ice_sched_get_first_node(pi, tc_node, layer);
105971d10453SEric Joyner 		if (prev && prev != new_node) {
106071d10453SEric Joyner 			while (prev->sibling)
106171d10453SEric Joyner 				prev = prev->sibling;
106271d10453SEric Joyner 			prev->sibling = new_node;
106371d10453SEric Joyner 		}
106471d10453SEric Joyner 
106571d10453SEric Joyner 		/* initialize the sibling head */
106671d10453SEric Joyner 		if (!pi->sib_head[tc_node->tc_num][layer])
106771d10453SEric Joyner 			pi->sib_head[tc_node->tc_num][layer] = new_node;
106871d10453SEric Joyner 
106971d10453SEric Joyner 		if (i == 0)
107071d10453SEric Joyner 			*first_node_teid = teid;
107171d10453SEric Joyner 	}
107271d10453SEric Joyner 
107371d10453SEric Joyner 	ice_free(hw, buf);
107471d10453SEric Joyner 	return status;
107571d10453SEric Joyner }
107671d10453SEric Joyner 
107771d10453SEric Joyner /**
10789cf1841cSEric Joyner  * ice_sched_add_nodes_to_hw_layer - Add nodes to hw layer
10799cf1841cSEric Joyner  * @pi: port information structure
10809cf1841cSEric Joyner  * @tc_node: pointer to TC node
10819cf1841cSEric Joyner  * @parent: pointer to parent node
10829cf1841cSEric Joyner  * @layer: layer number to add nodes
10839cf1841cSEric Joyner  * @num_nodes: number of nodes to be added
10849cf1841cSEric Joyner  * @first_node_teid: pointer to the first node TEID
10859cf1841cSEric Joyner  * @num_nodes_added: pointer to number of nodes added
10869cf1841cSEric Joyner  *
10879cf1841cSEric Joyner  * Add nodes into specific hw layer.
10889cf1841cSEric Joyner  */
1089*f2635e84SEric Joyner static int
10909cf1841cSEric Joyner ice_sched_add_nodes_to_hw_layer(struct ice_port_info *pi,
10919cf1841cSEric Joyner 				struct ice_sched_node *tc_node,
10929cf1841cSEric Joyner 				struct ice_sched_node *parent, u8 layer,
10939cf1841cSEric Joyner 				u16 num_nodes, u32 *first_node_teid,
10949cf1841cSEric Joyner 				u16 *num_nodes_added)
10959cf1841cSEric Joyner {
10969cf1841cSEric Joyner 	u16 max_child_nodes;
10979cf1841cSEric Joyner 
10989cf1841cSEric Joyner 	*num_nodes_added = 0;
10999cf1841cSEric Joyner 
11009cf1841cSEric Joyner 	if (!num_nodes)
1101*f2635e84SEric Joyner 		return 0;
11029cf1841cSEric Joyner 
11039cf1841cSEric Joyner 	if (!parent || layer < pi->hw->sw_entry_point_layer)
11049cf1841cSEric Joyner 		return ICE_ERR_PARAM;
11059cf1841cSEric Joyner 
11069cf1841cSEric Joyner 	/* max children per node per layer */
11079cf1841cSEric Joyner 	max_child_nodes = pi->hw->max_children[parent->tx_sched_layer];
11089cf1841cSEric Joyner 
11099cf1841cSEric Joyner 	/* current number of children + required nodes exceed max children */
11109cf1841cSEric Joyner 	if ((parent->num_children + num_nodes) > max_child_nodes) {
11119cf1841cSEric Joyner 		/* Fail if the parent is a TC node */
11129cf1841cSEric Joyner 		if (parent == tc_node)
11139cf1841cSEric Joyner 			return ICE_ERR_CFG;
11149cf1841cSEric Joyner 		return ICE_ERR_MAX_LIMIT;
11159cf1841cSEric Joyner 	}
11169cf1841cSEric Joyner 
11179cf1841cSEric Joyner 	return ice_sched_add_elems(pi, tc_node, parent, layer, num_nodes,
11189c30461dSEric Joyner 				   num_nodes_added, first_node_teid, NULL);
11199cf1841cSEric Joyner }
11209cf1841cSEric Joyner 
11219cf1841cSEric Joyner /**
112271d10453SEric Joyner  * ice_sched_add_nodes_to_layer - Add nodes to a given layer
112371d10453SEric Joyner  * @pi: port information structure
112471d10453SEric Joyner  * @tc_node: pointer to TC node
112571d10453SEric Joyner  * @parent: pointer to parent node
112671d10453SEric Joyner  * @layer: layer number to add nodes
112771d10453SEric Joyner  * @num_nodes: number of nodes to be added
112871d10453SEric Joyner  * @first_node_teid: pointer to the first node TEID
112971d10453SEric Joyner  * @num_nodes_added: pointer to number of nodes added
113071d10453SEric Joyner  *
113171d10453SEric Joyner  * This function add nodes to a given layer.
113271d10453SEric Joyner  */
1133*f2635e84SEric Joyner static int
113471d10453SEric Joyner ice_sched_add_nodes_to_layer(struct ice_port_info *pi,
113571d10453SEric Joyner 			     struct ice_sched_node *tc_node,
113671d10453SEric Joyner 			     struct ice_sched_node *parent, u8 layer,
113771d10453SEric Joyner 			     u16 num_nodes, u32 *first_node_teid,
113871d10453SEric Joyner 			     u16 *num_nodes_added)
113971d10453SEric Joyner {
114071d10453SEric Joyner 	u32 *first_teid_ptr = first_node_teid;
11419cf1841cSEric Joyner 	u16 new_num_nodes = num_nodes;
1142*f2635e84SEric Joyner 	int status = 0;
11439c30461dSEric Joyner 	u32 temp;
114471d10453SEric Joyner 
114571d10453SEric Joyner 	*num_nodes_added = 0;
11469cf1841cSEric Joyner 	while (*num_nodes_added < num_nodes) {
11479cf1841cSEric Joyner 		u16 max_child_nodes, num_added = 0;
114871d10453SEric Joyner 
11499cf1841cSEric Joyner 		status = ice_sched_add_nodes_to_hw_layer(pi, tc_node, parent,
11509cf1841cSEric Joyner 							 layer,	new_num_nodes,
11519cf1841cSEric Joyner 							 first_teid_ptr,
11529cf1841cSEric Joyner 							 &num_added);
1153*f2635e84SEric Joyner 		if (!status)
11549cf1841cSEric Joyner 			*num_nodes_added += num_added;
11559cf1841cSEric Joyner 		/* added more nodes than requested ? */
11569cf1841cSEric Joyner 		if (*num_nodes_added > num_nodes) {
11579cf1841cSEric Joyner 			ice_debug(pi->hw, ICE_DBG_SCHED, "added extra nodes %d %d\n", num_nodes,
11589cf1841cSEric Joyner 				  *num_nodes_added);
11599cf1841cSEric Joyner 			status = ICE_ERR_CFG;
11609cf1841cSEric Joyner 			break;
11619cf1841cSEric Joyner 		}
11629cf1841cSEric Joyner 		/* break if all the nodes are added successfully */
1163*f2635e84SEric Joyner 		if (!status && (*num_nodes_added == num_nodes))
11649cf1841cSEric Joyner 			break;
11659cf1841cSEric Joyner 		/* break if the error is not max limit */
1166*f2635e84SEric Joyner 		if (status && status != ICE_ERR_MAX_LIMIT)
11679cf1841cSEric Joyner 			break;
11689cf1841cSEric Joyner 		/* Exceeded the max children */
11699cf1841cSEric Joyner 		max_child_nodes = pi->hw->max_children[parent->tx_sched_layer];
117071d10453SEric Joyner 		/* utilize all the spaces if the parent is not full */
117171d10453SEric Joyner 		if (parent->num_children < max_child_nodes) {
117271d10453SEric Joyner 			new_num_nodes = max_child_nodes - parent->num_children;
11739cf1841cSEric Joyner 		} else {
11749cf1841cSEric Joyner 			/* This parent is full, try the next sibling */
11759cf1841cSEric Joyner 			parent = parent->sibling;
11769cf1841cSEric Joyner 			/* Don't modify the first node TEID memory if the
11779cf1841cSEric Joyner 			 * first node was added already in the above call.
11789cf1841cSEric Joyner 			 * Instead send some temp memory for all other
11799cf1841cSEric Joyner 			 * recursive calls.
118071d10453SEric Joyner 			 */
118171d10453SEric Joyner 			if (num_added)
118271d10453SEric Joyner 				first_teid_ptr = &temp;
118371d10453SEric Joyner 
11849cf1841cSEric Joyner 			new_num_nodes = num_nodes - *num_nodes_added;
118571d10453SEric Joyner 		}
11869cf1841cSEric Joyner 	}
118771d10453SEric Joyner 	return status;
118871d10453SEric Joyner }
118971d10453SEric Joyner 
119071d10453SEric Joyner /**
119171d10453SEric Joyner  * ice_sched_get_qgrp_layer - get the current queue group layer number
119271d10453SEric Joyner  * @hw: pointer to the HW struct
119371d10453SEric Joyner  *
119471d10453SEric Joyner  * This function returns the current queue group layer number
119571d10453SEric Joyner  */
119671d10453SEric Joyner static u8 ice_sched_get_qgrp_layer(struct ice_hw *hw)
119771d10453SEric Joyner {
119871d10453SEric Joyner 	/* It's always total layers - 1, the array is 0 relative so -2 */
119971d10453SEric Joyner 	return hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET;
120071d10453SEric Joyner }
120171d10453SEric Joyner 
120271d10453SEric Joyner /**
120371d10453SEric Joyner  * ice_sched_get_vsi_layer - get the current VSI layer number
120471d10453SEric Joyner  * @hw: pointer to the HW struct
120571d10453SEric Joyner  *
120671d10453SEric Joyner  * This function returns the current VSI layer number
120771d10453SEric Joyner  */
120871d10453SEric Joyner static u8 ice_sched_get_vsi_layer(struct ice_hw *hw)
120971d10453SEric Joyner {
121071d10453SEric Joyner 	/* Num Layers       VSI layer
121171d10453SEric Joyner 	 *     9               6
121271d10453SEric Joyner 	 *     7               4
121371d10453SEric Joyner 	 *     5 or less       sw_entry_point_layer
121471d10453SEric Joyner 	 */
121571d10453SEric Joyner 	/* calculate the VSI layer based on number of layers. */
12168923de59SPiotr Kubaj 	if (hw->num_tx_sched_layers == ICE_SCHED_9_LAYERS)
12178923de59SPiotr Kubaj 		return hw->num_tx_sched_layers - ICE_VSI_LAYER_OFFSET;
12188923de59SPiotr Kubaj 	else if (hw->num_tx_sched_layers == ICE_SCHED_5_LAYERS)
12198923de59SPiotr Kubaj 		/* qgroup and VSI layers are same */
12208923de59SPiotr Kubaj 		return hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET;
122171d10453SEric Joyner 	return hw->sw_entry_point_layer;
122271d10453SEric Joyner }
122371d10453SEric Joyner 
122471d10453SEric Joyner /**
122571d10453SEric Joyner  * ice_sched_get_agg_layer - get the current aggregator layer number
122671d10453SEric Joyner  * @hw: pointer to the HW struct
122771d10453SEric Joyner  *
122871d10453SEric Joyner  * This function returns the current aggregator layer number
122971d10453SEric Joyner  */
123071d10453SEric Joyner static u8 ice_sched_get_agg_layer(struct ice_hw *hw)
123171d10453SEric Joyner {
123271d10453SEric Joyner 	/* Num Layers       aggregator layer
123371d10453SEric Joyner 	 *     9               4
123471d10453SEric Joyner 	 *     7 or less       sw_entry_point_layer
123571d10453SEric Joyner 	 */
123671d10453SEric Joyner 	/* calculate the aggregator layer based on number of layers. */
12378923de59SPiotr Kubaj 	if (hw->num_tx_sched_layers == ICE_SCHED_9_LAYERS)
12388923de59SPiotr Kubaj 		return hw->num_tx_sched_layers - ICE_AGG_LAYER_OFFSET;
123971d10453SEric Joyner 	return hw->sw_entry_point_layer;
124071d10453SEric Joyner }
124171d10453SEric Joyner 
124271d10453SEric Joyner /**
124371d10453SEric Joyner  * ice_rm_dflt_leaf_node - remove the default leaf node in the tree
124471d10453SEric Joyner  * @pi: port information structure
124571d10453SEric Joyner  *
124671d10453SEric Joyner  * This function removes the leaf node that was created by the FW
124771d10453SEric Joyner  * during initialization
124871d10453SEric Joyner  */
124971d10453SEric Joyner static void ice_rm_dflt_leaf_node(struct ice_port_info *pi)
125071d10453SEric Joyner {
125171d10453SEric Joyner 	struct ice_sched_node *node;
125271d10453SEric Joyner 
125371d10453SEric Joyner 	node = pi->root;
125471d10453SEric Joyner 	while (node) {
125571d10453SEric Joyner 		if (!node->num_children)
125671d10453SEric Joyner 			break;
125771d10453SEric Joyner 		node = node->children[0];
125871d10453SEric Joyner 	}
125971d10453SEric Joyner 	if (node && node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF) {
126071d10453SEric Joyner 		u32 teid = LE32_TO_CPU(node->info.node_teid);
1261*f2635e84SEric Joyner 		int status;
126271d10453SEric Joyner 
126371d10453SEric Joyner 		/* remove the default leaf node */
126471d10453SEric Joyner 		status = ice_sched_remove_elems(pi->hw, node->parent, 1, &teid);
126571d10453SEric Joyner 		if (!status)
126671d10453SEric Joyner 			ice_free_sched_node(pi, node);
126771d10453SEric Joyner 	}
126871d10453SEric Joyner }
126971d10453SEric Joyner 
127071d10453SEric Joyner /**
127171d10453SEric Joyner  * ice_sched_rm_dflt_nodes - free the default nodes in the tree
127271d10453SEric Joyner  * @pi: port information structure
127371d10453SEric Joyner  *
127471d10453SEric Joyner  * This function frees all the nodes except root and TC that were created by
127571d10453SEric Joyner  * the FW during initialization
127671d10453SEric Joyner  */
127771d10453SEric Joyner static void ice_sched_rm_dflt_nodes(struct ice_port_info *pi)
127871d10453SEric Joyner {
127971d10453SEric Joyner 	struct ice_sched_node *node;
128071d10453SEric Joyner 
128171d10453SEric Joyner 	ice_rm_dflt_leaf_node(pi);
128271d10453SEric Joyner 
128371d10453SEric Joyner 	/* remove the default nodes except TC and root nodes */
128471d10453SEric Joyner 	node = pi->root;
128571d10453SEric Joyner 	while (node) {
128671d10453SEric Joyner 		if (node->tx_sched_layer >= pi->hw->sw_entry_point_layer &&
128771d10453SEric Joyner 		    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
128871d10453SEric Joyner 		    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT) {
128971d10453SEric Joyner 			ice_free_sched_node(pi, node);
129071d10453SEric Joyner 			break;
129171d10453SEric Joyner 		}
129271d10453SEric Joyner 
129371d10453SEric Joyner 		if (!node->num_children)
129471d10453SEric Joyner 			break;
129571d10453SEric Joyner 		node = node->children[0];
129671d10453SEric Joyner 	}
129771d10453SEric Joyner }
129871d10453SEric Joyner 
129971d10453SEric Joyner /**
130071d10453SEric Joyner  * ice_sched_init_port - Initialize scheduler by querying information from FW
130171d10453SEric Joyner  * @pi: port info structure for the tree to cleanup
130271d10453SEric Joyner  *
130371d10453SEric Joyner  * This function is the initial call to find the total number of Tx scheduler
130471d10453SEric Joyner  * resources, default topology created by firmware and storing the information
130571d10453SEric Joyner  * in SW DB.
130671d10453SEric Joyner  */
1307*f2635e84SEric Joyner int ice_sched_init_port(struct ice_port_info *pi)
130871d10453SEric Joyner {
130971d10453SEric Joyner 	struct ice_aqc_get_topo_elem *buf;
131071d10453SEric Joyner 	struct ice_hw *hw;
131171d10453SEric Joyner 	u8 num_branches;
131271d10453SEric Joyner 	u16 num_elems;
1313*f2635e84SEric Joyner 	int status;
131471d10453SEric Joyner 	u8 i, j;
131571d10453SEric Joyner 
131671d10453SEric Joyner 	if (!pi)
131771d10453SEric Joyner 		return ICE_ERR_PARAM;
131871d10453SEric Joyner 	hw = pi->hw;
131971d10453SEric Joyner 
132071d10453SEric Joyner 	/* Query the Default Topology from FW */
132171d10453SEric Joyner 	buf = (struct ice_aqc_get_topo_elem *)ice_malloc(hw,
132271d10453SEric Joyner 							 ICE_AQ_MAX_BUF_LEN);
132371d10453SEric Joyner 	if (!buf)
132471d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
132571d10453SEric Joyner 
132671d10453SEric Joyner 	/* Query default scheduling tree topology */
132771d10453SEric Joyner 	status = ice_aq_get_dflt_topo(hw, pi->lport, buf, ICE_AQ_MAX_BUF_LEN,
132871d10453SEric Joyner 				      &num_branches, NULL);
132971d10453SEric Joyner 	if (status)
133071d10453SEric Joyner 		goto err_init_port;
133171d10453SEric Joyner 
133271d10453SEric Joyner 	/* num_branches should be between 1-8 */
133371d10453SEric Joyner 	if (num_branches < 1 || num_branches > ICE_TXSCHED_MAX_BRANCHES) {
133471d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SCHED, "num_branches unexpected %d\n",
133571d10453SEric Joyner 			  num_branches);
133671d10453SEric Joyner 		status = ICE_ERR_PARAM;
133771d10453SEric Joyner 		goto err_init_port;
133871d10453SEric Joyner 	}
133971d10453SEric Joyner 
134071d10453SEric Joyner 	/* get the number of elements on the default/first branch */
134171d10453SEric Joyner 	num_elems = LE16_TO_CPU(buf[0].hdr.num_elems);
134271d10453SEric Joyner 
134371d10453SEric Joyner 	/* num_elems should always be between 1-9 */
134471d10453SEric Joyner 	if (num_elems < 1 || num_elems > ICE_AQC_TOPO_MAX_LEVEL_NUM) {
134571d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SCHED, "num_elems unexpected %d\n",
134671d10453SEric Joyner 			  num_elems);
134771d10453SEric Joyner 		status = ICE_ERR_PARAM;
134871d10453SEric Joyner 		goto err_init_port;
134971d10453SEric Joyner 	}
135071d10453SEric Joyner 
135171d10453SEric Joyner 	/* If the last node is a leaf node then the index of the queue group
135271d10453SEric Joyner 	 * layer is two less than the number of elements.
135371d10453SEric Joyner 	 */
135471d10453SEric Joyner 	if (num_elems > 2 && buf[0].generic[num_elems - 1].data.elem_type ==
135571d10453SEric Joyner 	    ICE_AQC_ELEM_TYPE_LEAF)
135671d10453SEric Joyner 		pi->last_node_teid =
135771d10453SEric Joyner 			LE32_TO_CPU(buf[0].generic[num_elems - 2].node_teid);
135871d10453SEric Joyner 	else
135971d10453SEric Joyner 		pi->last_node_teid =
136071d10453SEric Joyner 			LE32_TO_CPU(buf[0].generic[num_elems - 1].node_teid);
136171d10453SEric Joyner 
136271d10453SEric Joyner 	/* Insert the Tx Sched root node */
136371d10453SEric Joyner 	status = ice_sched_add_root_node(pi, &buf[0].generic[0]);
136471d10453SEric Joyner 	if (status)
136571d10453SEric Joyner 		goto err_init_port;
136671d10453SEric Joyner 
136771d10453SEric Joyner 	/* Parse the default tree and cache the information */
136871d10453SEric Joyner 	for (i = 0; i < num_branches; i++) {
136971d10453SEric Joyner 		num_elems = LE16_TO_CPU(buf[i].hdr.num_elems);
137071d10453SEric Joyner 
137171d10453SEric Joyner 		/* Skip root element as already inserted */
137271d10453SEric Joyner 		for (j = 1; j < num_elems; j++) {
137371d10453SEric Joyner 			/* update the sw entry point */
137471d10453SEric Joyner 			if (buf[0].generic[j].data.elem_type ==
137571d10453SEric Joyner 			    ICE_AQC_ELEM_TYPE_ENTRY_POINT)
137671d10453SEric Joyner 				hw->sw_entry_point_layer = j;
137771d10453SEric Joyner 
13789c30461dSEric Joyner 			status = ice_sched_add_node(pi, j, &buf[i].generic[j], NULL);
137971d10453SEric Joyner 			if (status)
138071d10453SEric Joyner 				goto err_init_port;
138171d10453SEric Joyner 		}
138271d10453SEric Joyner 	}
138371d10453SEric Joyner 
138471d10453SEric Joyner 	/* Remove the default nodes. */
138571d10453SEric Joyner 	if (pi->root)
138671d10453SEric Joyner 		ice_sched_rm_dflt_nodes(pi);
138771d10453SEric Joyner 
138871d10453SEric Joyner 	/* initialize the port for handling the scheduler tree */
138971d10453SEric Joyner 	pi->port_state = ICE_SCHED_PORT_STATE_READY;
139071d10453SEric Joyner 	ice_init_lock(&pi->sched_lock);
139171d10453SEric Joyner 	for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++)
1392d08b8680SEric Joyner 		INIT_LIST_HEAD(&hw->rl_prof_list[i]);
139371d10453SEric Joyner 
139471d10453SEric Joyner err_init_port:
139571d10453SEric Joyner 	if (status && pi->root) {
139671d10453SEric Joyner 		ice_free_sched_node(pi, pi->root);
139771d10453SEric Joyner 		pi->root = NULL;
139871d10453SEric Joyner 	}
139971d10453SEric Joyner 
140071d10453SEric Joyner 	ice_free(hw, buf);
140171d10453SEric Joyner 	return status;
140271d10453SEric Joyner }
140371d10453SEric Joyner 
140471d10453SEric Joyner /**
140571d10453SEric Joyner  * ice_sched_get_node - Get the struct ice_sched_node for given TEID
140671d10453SEric Joyner  * @pi: port information structure
140771d10453SEric Joyner  * @teid: Scheduler node TEID
140871d10453SEric Joyner  *
140971d10453SEric Joyner  * This function retrieves the ice_sched_node struct for given TEID from
141071d10453SEric Joyner  * the SW DB and returns it to the caller.
141171d10453SEric Joyner  */
141271d10453SEric Joyner struct ice_sched_node *ice_sched_get_node(struct ice_port_info *pi, u32 teid)
141371d10453SEric Joyner {
141471d10453SEric Joyner 	struct ice_sched_node *node;
141571d10453SEric Joyner 
141671d10453SEric Joyner 	if (!pi)
141771d10453SEric Joyner 		return NULL;
141871d10453SEric Joyner 
141971d10453SEric Joyner 	/* Find the node starting from root */
142071d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
142171d10453SEric Joyner 	node = ice_sched_find_node_by_teid(pi->root, teid);
142271d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
142371d10453SEric Joyner 
142471d10453SEric Joyner 	if (!node)
14257d7af7f8SEric Joyner 		ice_debug(pi->hw, ICE_DBG_SCHED, "Node not found for teid=0x%x\n", teid);
142671d10453SEric Joyner 
142771d10453SEric Joyner 	return node;
142871d10453SEric Joyner }
142971d10453SEric Joyner 
143071d10453SEric Joyner /**
143171d10453SEric Joyner  * ice_sched_query_res_alloc - query the FW for num of logical sched layers
143271d10453SEric Joyner  * @hw: pointer to the HW struct
143371d10453SEric Joyner  *
143471d10453SEric Joyner  * query FW for allocated scheduler resources and store in HW struct
143571d10453SEric Joyner  */
1436*f2635e84SEric Joyner int ice_sched_query_res_alloc(struct ice_hw *hw)
143771d10453SEric Joyner {
143871d10453SEric Joyner 	struct ice_aqc_query_txsched_res_resp *buf;
143971d10453SEric Joyner 	__le16 max_sibl;
1440*f2635e84SEric Joyner 	int status = 0;
1441*f2635e84SEric Joyner 	u16 i;
144271d10453SEric Joyner 
144371d10453SEric Joyner 	if (hw->layer_info)
144471d10453SEric Joyner 		return status;
144571d10453SEric Joyner 
144671d10453SEric Joyner 	buf = (struct ice_aqc_query_txsched_res_resp *)
144771d10453SEric Joyner 		ice_malloc(hw, sizeof(*buf));
144871d10453SEric Joyner 	if (!buf)
144971d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
145071d10453SEric Joyner 
145171d10453SEric Joyner 	status = ice_aq_query_sched_res(hw, sizeof(*buf), buf, NULL);
145271d10453SEric Joyner 	if (status)
145371d10453SEric Joyner 		goto sched_query_out;
145471d10453SEric Joyner 
14558923de59SPiotr Kubaj 	hw->num_tx_sched_layers =
14568923de59SPiotr Kubaj 		(u8)LE16_TO_CPU(buf->sched_props.logical_levels);
145771d10453SEric Joyner 	hw->num_tx_sched_phys_layers =
14588923de59SPiotr Kubaj 		(u8)LE16_TO_CPU(buf->sched_props.phys_levels);
145971d10453SEric Joyner 	hw->flattened_layers = buf->sched_props.flattening_bitmap;
146071d10453SEric Joyner 	hw->max_cgds = buf->sched_props.max_pf_cgds;
146171d10453SEric Joyner 
146271d10453SEric Joyner 	/* max sibling group size of current layer refers to the max children
146371d10453SEric Joyner 	 * of the below layer node.
146471d10453SEric Joyner 	 * layer 1 node max children will be layer 2 max sibling group size
146571d10453SEric Joyner 	 * layer 2 node max children will be layer 3 max sibling group size
146671d10453SEric Joyner 	 * and so on. This array will be populated from root (index 0) to
146771d10453SEric Joyner 	 * qgroup layer 7. Leaf node has no children.
146871d10453SEric Joyner 	 */
146971d10453SEric Joyner 	for (i = 0; i < hw->num_tx_sched_layers - 1; i++) {
147071d10453SEric Joyner 		max_sibl = buf->layer_props[i + 1].max_sibl_grp_sz;
147171d10453SEric Joyner 		hw->max_children[i] = LE16_TO_CPU(max_sibl);
147271d10453SEric Joyner 	}
147371d10453SEric Joyner 
147471d10453SEric Joyner 	hw->layer_info = (struct ice_aqc_layer_props *)
147571d10453SEric Joyner 			 ice_memdup(hw, buf->layer_props,
147671d10453SEric Joyner 				    (hw->num_tx_sched_layers *
147771d10453SEric Joyner 				     sizeof(*hw->layer_info)),
14789cf1841cSEric Joyner 				    ICE_NONDMA_TO_NONDMA);
147971d10453SEric Joyner 	if (!hw->layer_info) {
148071d10453SEric Joyner 		status = ICE_ERR_NO_MEMORY;
148171d10453SEric Joyner 		goto sched_query_out;
148271d10453SEric Joyner 	}
148371d10453SEric Joyner 
148471d10453SEric Joyner sched_query_out:
148571d10453SEric Joyner 	ice_free(hw, buf);
148671d10453SEric Joyner 	return status;
148771d10453SEric Joyner }
148871d10453SEric Joyner 
148971d10453SEric Joyner /**
149071d10453SEric Joyner  * ice_sched_get_psm_clk_freq - determine the PSM clock frequency
149171d10453SEric Joyner  * @hw: pointer to the HW struct
149271d10453SEric Joyner  *
149371d10453SEric Joyner  * Determine the PSM clock frequency and store in HW struct
149471d10453SEric Joyner  */
149571d10453SEric Joyner void ice_sched_get_psm_clk_freq(struct ice_hw *hw)
149671d10453SEric Joyner {
149771d10453SEric Joyner 	u32 val, clk_src;
149871d10453SEric Joyner 
149971d10453SEric Joyner 	val = rd32(hw, GLGEN_CLKSTAT_SRC);
150071d10453SEric Joyner 	clk_src = (val & GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M) >>
150171d10453SEric Joyner 		GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_S;
150271d10453SEric Joyner 
150371d10453SEric Joyner 	switch (clk_src) {
150471d10453SEric Joyner 	case PSM_CLK_SRC_367_MHZ:
150571d10453SEric Joyner 		hw->psm_clk_freq = ICE_PSM_CLK_367MHZ_IN_HZ;
150671d10453SEric Joyner 		break;
150771d10453SEric Joyner 	case PSM_CLK_SRC_416_MHZ:
150871d10453SEric Joyner 		hw->psm_clk_freq = ICE_PSM_CLK_416MHZ_IN_HZ;
150971d10453SEric Joyner 		break;
151071d10453SEric Joyner 	case PSM_CLK_SRC_446_MHZ:
151171d10453SEric Joyner 		hw->psm_clk_freq = ICE_PSM_CLK_446MHZ_IN_HZ;
151271d10453SEric Joyner 		break;
151371d10453SEric Joyner 	case PSM_CLK_SRC_390_MHZ:
151471d10453SEric Joyner 		hw->psm_clk_freq = ICE_PSM_CLK_390MHZ_IN_HZ;
151571d10453SEric Joyner 		break;
15169c30461dSEric Joyner 
15179c30461dSEric Joyner 	/* default condition is not required as clk_src is restricted
15189c30461dSEric Joyner 	 * to a 2-bit value from GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M mask.
15199c30461dSEric Joyner 	 * The above switch statements cover the possible values of
15209c30461dSEric Joyner 	 * this variable.
15219c30461dSEric Joyner 	 */
152271d10453SEric Joyner 	}
152371d10453SEric Joyner }
152471d10453SEric Joyner 
152571d10453SEric Joyner /**
152671d10453SEric Joyner  * ice_sched_find_node_in_subtree - Find node in part of base node subtree
152771d10453SEric Joyner  * @hw: pointer to the HW struct
152871d10453SEric Joyner  * @base: pointer to the base node
152971d10453SEric Joyner  * @node: pointer to the node to search
153071d10453SEric Joyner  *
153171d10453SEric Joyner  * This function checks whether a given node is part of the base node
153271d10453SEric Joyner  * subtree or not
153371d10453SEric Joyner  */
153471d10453SEric Joyner bool
153571d10453SEric Joyner ice_sched_find_node_in_subtree(struct ice_hw *hw, struct ice_sched_node *base,
153671d10453SEric Joyner 			       struct ice_sched_node *node)
153771d10453SEric Joyner {
153871d10453SEric Joyner 	u8 i;
153971d10453SEric Joyner 
154071d10453SEric Joyner 	for (i = 0; i < base->num_children; i++) {
154171d10453SEric Joyner 		struct ice_sched_node *child = base->children[i];
154271d10453SEric Joyner 
154371d10453SEric Joyner 		if (node == child)
154471d10453SEric Joyner 			return true;
154571d10453SEric Joyner 
154671d10453SEric Joyner 		if (child->tx_sched_layer > node->tx_sched_layer)
154771d10453SEric Joyner 			return false;
154871d10453SEric Joyner 
154971d10453SEric Joyner 		/* this recursion is intentional, and wouldn't
155071d10453SEric Joyner 		 * go more than 8 calls
155171d10453SEric Joyner 		 */
155271d10453SEric Joyner 		if (ice_sched_find_node_in_subtree(hw, child, node))
155371d10453SEric Joyner 			return true;
155471d10453SEric Joyner 	}
155571d10453SEric Joyner 	return false;
155671d10453SEric Joyner }
155771d10453SEric Joyner 
155871d10453SEric Joyner /**
15597d7af7f8SEric Joyner  * ice_sched_get_free_qgrp - Scan all queue group siblings and find a free node
15607d7af7f8SEric Joyner  * @pi: port information structure
15617d7af7f8SEric Joyner  * @vsi_node: software VSI handle
15627d7af7f8SEric Joyner  * @qgrp_node: first queue group node identified for scanning
15637d7af7f8SEric Joyner  * @owner: LAN or RDMA
15647d7af7f8SEric Joyner  *
15657d7af7f8SEric Joyner  * This function retrieves a free LAN or RDMA queue group node by scanning
15667d7af7f8SEric Joyner  * qgrp_node and its siblings for the queue group with the fewest number
15677d7af7f8SEric Joyner  * of queues currently assigned.
15687d7af7f8SEric Joyner  */
15697d7af7f8SEric Joyner static struct ice_sched_node *
15707d7af7f8SEric Joyner ice_sched_get_free_qgrp(struct ice_port_info *pi,
15717d7af7f8SEric Joyner 			struct ice_sched_node *vsi_node,
15727d7af7f8SEric Joyner 			struct ice_sched_node *qgrp_node, u8 owner)
15737d7af7f8SEric Joyner {
15747d7af7f8SEric Joyner 	struct ice_sched_node *min_qgrp;
15757d7af7f8SEric Joyner 	u8 min_children;
15767d7af7f8SEric Joyner 
15777d7af7f8SEric Joyner 	if (!qgrp_node)
15787d7af7f8SEric Joyner 		return qgrp_node;
15797d7af7f8SEric Joyner 	min_children = qgrp_node->num_children;
15807d7af7f8SEric Joyner 	if (!min_children)
15817d7af7f8SEric Joyner 		return qgrp_node;
15827d7af7f8SEric Joyner 	min_qgrp = qgrp_node;
15837d7af7f8SEric Joyner 	/* scan all queue groups until find a node which has less than the
15847d7af7f8SEric Joyner 	 * minimum number of children. This way all queue group nodes get
15857d7af7f8SEric Joyner 	 * equal number of shares and active. The bandwidth will be equally
15867d7af7f8SEric Joyner 	 * distributed across all queues.
15877d7af7f8SEric Joyner 	 */
15887d7af7f8SEric Joyner 	while (qgrp_node) {
15897d7af7f8SEric Joyner 		/* make sure the qgroup node is part of the VSI subtree */
15907d7af7f8SEric Joyner 		if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node))
15917d7af7f8SEric Joyner 			if (qgrp_node->num_children < min_children &&
15927d7af7f8SEric Joyner 			    qgrp_node->owner == owner) {
15937d7af7f8SEric Joyner 				/* replace the new min queue group node */
15947d7af7f8SEric Joyner 				min_qgrp = qgrp_node;
15957d7af7f8SEric Joyner 				min_children = min_qgrp->num_children;
15967d7af7f8SEric Joyner 				/* break if it has no children, */
15977d7af7f8SEric Joyner 				if (!min_children)
15987d7af7f8SEric Joyner 					break;
15997d7af7f8SEric Joyner 			}
16007d7af7f8SEric Joyner 		qgrp_node = qgrp_node->sibling;
16017d7af7f8SEric Joyner 	}
16027d7af7f8SEric Joyner 	return min_qgrp;
16037d7af7f8SEric Joyner }
16047d7af7f8SEric Joyner 
16057d7af7f8SEric Joyner /**
160671d10453SEric Joyner  * ice_sched_get_free_qparent - Get a free LAN or RDMA queue group node
160771d10453SEric Joyner  * @pi: port information structure
160871d10453SEric Joyner  * @vsi_handle: software VSI handle
160971d10453SEric Joyner  * @tc: branch number
161071d10453SEric Joyner  * @owner: LAN or RDMA
161171d10453SEric Joyner  *
161271d10453SEric Joyner  * This function retrieves a free LAN or RDMA queue group node
161371d10453SEric Joyner  */
161471d10453SEric Joyner struct ice_sched_node *
161571d10453SEric Joyner ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
161671d10453SEric Joyner 			   u8 owner)
161771d10453SEric Joyner {
16187d7af7f8SEric Joyner 	struct ice_sched_node *vsi_node, *qgrp_node;
161971d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
16208923de59SPiotr Kubaj 	u8 qgrp_layer, vsi_layer;
162171d10453SEric Joyner 	u16 max_children;
162271d10453SEric Joyner 
162371d10453SEric Joyner 	qgrp_layer = ice_sched_get_qgrp_layer(pi->hw);
16248923de59SPiotr Kubaj 	vsi_layer = ice_sched_get_vsi_layer(pi->hw);
162571d10453SEric Joyner 	max_children = pi->hw->max_children[qgrp_layer];
162671d10453SEric Joyner 
162771d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
162871d10453SEric Joyner 	if (!vsi_ctx)
162971d10453SEric Joyner 		return NULL;
163071d10453SEric Joyner 	vsi_node = vsi_ctx->sched.vsi_node[tc];
163171d10453SEric Joyner 	/* validate invalid VSI ID */
163271d10453SEric Joyner 	if (!vsi_node)
16337d7af7f8SEric Joyner 		return NULL;
163471d10453SEric Joyner 
16358923de59SPiotr Kubaj 	/* If the queue group and vsi layer are same then queues
16368923de59SPiotr Kubaj 	 * are all attached directly to VSI
16378923de59SPiotr Kubaj 	 */
16388923de59SPiotr Kubaj 	if (qgrp_layer == vsi_layer)
16398923de59SPiotr Kubaj 		return vsi_node;
16408923de59SPiotr Kubaj 
164171d10453SEric Joyner 	/* get the first queue group node from VSI sub-tree */
164271d10453SEric Joyner 	qgrp_node = ice_sched_get_first_node(pi, vsi_node, qgrp_layer);
164371d10453SEric Joyner 	while (qgrp_node) {
164471d10453SEric Joyner 		/* make sure the qgroup node is part of the VSI subtree */
164571d10453SEric Joyner 		if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node))
164671d10453SEric Joyner 			if (qgrp_node->num_children < max_children &&
164771d10453SEric Joyner 			    qgrp_node->owner == owner)
164871d10453SEric Joyner 				break;
164971d10453SEric Joyner 		qgrp_node = qgrp_node->sibling;
165071d10453SEric Joyner 	}
165171d10453SEric Joyner 
16527d7af7f8SEric Joyner 	/* Select the best queue group */
16537d7af7f8SEric Joyner 	return ice_sched_get_free_qgrp(pi, vsi_node, qgrp_node, owner);
165471d10453SEric Joyner }
165571d10453SEric Joyner 
165671d10453SEric Joyner /**
165771d10453SEric Joyner  * ice_sched_get_vsi_node - Get a VSI node based on VSI ID
165871d10453SEric Joyner  * @pi: pointer to the port information structure
165971d10453SEric Joyner  * @tc_node: pointer to the TC node
166071d10453SEric Joyner  * @vsi_handle: software VSI handle
166171d10453SEric Joyner  *
166271d10453SEric Joyner  * This function retrieves a VSI node for a given VSI ID from a given
166371d10453SEric Joyner  * TC branch
166471d10453SEric Joyner  */
166571d10453SEric Joyner struct ice_sched_node *
166671d10453SEric Joyner ice_sched_get_vsi_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
166771d10453SEric Joyner 		       u16 vsi_handle)
166871d10453SEric Joyner {
166971d10453SEric Joyner 	struct ice_sched_node *node;
167071d10453SEric Joyner 	u8 vsi_layer;
167171d10453SEric Joyner 
167271d10453SEric Joyner 	vsi_layer = ice_sched_get_vsi_layer(pi->hw);
167371d10453SEric Joyner 	node = ice_sched_get_first_node(pi, tc_node, vsi_layer);
167471d10453SEric Joyner 
167571d10453SEric Joyner 	/* Check whether it already exists */
167671d10453SEric Joyner 	while (node) {
167771d10453SEric Joyner 		if (node->vsi_handle == vsi_handle)
167871d10453SEric Joyner 			return node;
167971d10453SEric Joyner 		node = node->sibling;
168071d10453SEric Joyner 	}
168171d10453SEric Joyner 
168271d10453SEric Joyner 	return node;
168371d10453SEric Joyner }
168471d10453SEric Joyner 
168571d10453SEric Joyner /**
168671d10453SEric Joyner  * ice_sched_get_agg_node - Get an aggregator node based on aggregator ID
168771d10453SEric Joyner  * @pi: pointer to the port information structure
168871d10453SEric Joyner  * @tc_node: pointer to the TC node
168971d10453SEric Joyner  * @agg_id: aggregator ID
169071d10453SEric Joyner  *
169171d10453SEric Joyner  * This function retrieves an aggregator node for a given aggregator ID from
169271d10453SEric Joyner  * a given TC branch
169371d10453SEric Joyner  */
169471d10453SEric Joyner static struct ice_sched_node *
169571d10453SEric Joyner ice_sched_get_agg_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
169671d10453SEric Joyner 		       u32 agg_id)
169771d10453SEric Joyner {
169871d10453SEric Joyner 	struct ice_sched_node *node;
169971d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
170071d10453SEric Joyner 	u8 agg_layer;
170171d10453SEric Joyner 
170271d10453SEric Joyner 	if (!hw)
170371d10453SEric Joyner 		return NULL;
170471d10453SEric Joyner 	agg_layer = ice_sched_get_agg_layer(hw);
170571d10453SEric Joyner 	node = ice_sched_get_first_node(pi, tc_node, agg_layer);
170671d10453SEric Joyner 
170771d10453SEric Joyner 	/* Check whether it already exists */
170871d10453SEric Joyner 	while (node) {
170971d10453SEric Joyner 		if (node->agg_id == agg_id)
171071d10453SEric Joyner 			return node;
171171d10453SEric Joyner 		node = node->sibling;
171271d10453SEric Joyner 	}
171371d10453SEric Joyner 
171471d10453SEric Joyner 	return node;
171571d10453SEric Joyner }
171671d10453SEric Joyner 
171771d10453SEric Joyner /**
171871d10453SEric Joyner  * ice_sched_check_node - Compare node parameters between SW DB and HW DB
171971d10453SEric Joyner  * @hw: pointer to the HW struct
172071d10453SEric Joyner  * @node: pointer to the ice_sched_node struct
172171d10453SEric Joyner  *
172271d10453SEric Joyner  * This function queries and compares the HW element with SW DB node parameters
172371d10453SEric Joyner  */
172471d10453SEric Joyner static bool ice_sched_check_node(struct ice_hw *hw, struct ice_sched_node *node)
172571d10453SEric Joyner {
17267d7af7f8SEric Joyner 	struct ice_aqc_txsched_elem_data buf;
172771d10453SEric Joyner 	u32 node_teid;
1728*f2635e84SEric Joyner 	int status;
172971d10453SEric Joyner 
173071d10453SEric Joyner 	node_teid = LE32_TO_CPU(node->info.node_teid);
173171d10453SEric Joyner 	status = ice_sched_query_elem(hw, node_teid, &buf);
1732*f2635e84SEric Joyner 	if (status)
173371d10453SEric Joyner 		return false;
173471d10453SEric Joyner 
17357d7af7f8SEric Joyner 	if (memcmp(&buf, &node->info, sizeof(buf))) {
173671d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SCHED, "Node mismatch for teid=0x%x\n",
173771d10453SEric Joyner 			  node_teid);
173871d10453SEric Joyner 		return false;
173971d10453SEric Joyner 	}
174071d10453SEric Joyner 
174171d10453SEric Joyner 	return true;
174271d10453SEric Joyner }
174371d10453SEric Joyner 
174471d10453SEric Joyner /**
174571d10453SEric Joyner  * ice_sched_calc_vsi_child_nodes - calculate number of VSI child nodes
174671d10453SEric Joyner  * @hw: pointer to the HW struct
174771d10453SEric Joyner  * @num_qs: number of queues
174871d10453SEric Joyner  * @num_nodes: num nodes array
174971d10453SEric Joyner  *
175071d10453SEric Joyner  * This function calculates the number of VSI child nodes based on the
175171d10453SEric Joyner  * number of queues.
175271d10453SEric Joyner  */
175371d10453SEric Joyner static void
175471d10453SEric Joyner ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes)
175571d10453SEric Joyner {
175671d10453SEric Joyner 	u16 num = num_qs;
175771d10453SEric Joyner 	u8 i, qgl, vsil;
175871d10453SEric Joyner 
175971d10453SEric Joyner 	qgl = ice_sched_get_qgrp_layer(hw);
176071d10453SEric Joyner 	vsil = ice_sched_get_vsi_layer(hw);
176171d10453SEric Joyner 
176271d10453SEric Joyner 	/* calculate num nodes from queue group to VSI layer */
176371d10453SEric Joyner 	for (i = qgl; i > vsil; i--) {
176471d10453SEric Joyner 		/* round to the next integer if there is a remainder */
176571d10453SEric Joyner 		num = DIVIDE_AND_ROUND_UP(num, hw->max_children[i]);
176671d10453SEric Joyner 
176771d10453SEric Joyner 		/* need at least one node */
176871d10453SEric Joyner 		num_nodes[i] = num ? num : 1;
176971d10453SEric Joyner 	}
177071d10453SEric Joyner }
177171d10453SEric Joyner 
177271d10453SEric Joyner /**
177371d10453SEric Joyner  * ice_sched_add_vsi_child_nodes - add VSI child nodes to tree
177471d10453SEric Joyner  * @pi: port information structure
177571d10453SEric Joyner  * @vsi_handle: software VSI handle
177671d10453SEric Joyner  * @tc_node: pointer to the TC node
177771d10453SEric Joyner  * @num_nodes: pointer to the num nodes that needs to be added per layer
177871d10453SEric Joyner  * @owner: node owner (LAN or RDMA)
177971d10453SEric Joyner  *
178071d10453SEric Joyner  * This function adds the VSI child nodes to tree. It gets called for
178171d10453SEric Joyner  * LAN and RDMA separately.
178271d10453SEric Joyner  */
1783*f2635e84SEric Joyner static int
178471d10453SEric Joyner ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
178571d10453SEric Joyner 			      struct ice_sched_node *tc_node, u16 *num_nodes,
178671d10453SEric Joyner 			      u8 owner)
178771d10453SEric Joyner {
178871d10453SEric Joyner 	struct ice_sched_node *parent, *node;
178971d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
179071d10453SEric Joyner 	u32 first_node_teid;
179171d10453SEric Joyner 	u16 num_added = 0;
179271d10453SEric Joyner 	u8 i, qgl, vsil;
179371d10453SEric Joyner 
179471d10453SEric Joyner 	qgl = ice_sched_get_qgrp_layer(hw);
179571d10453SEric Joyner 	vsil = ice_sched_get_vsi_layer(hw);
179671d10453SEric Joyner 	parent = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
179771d10453SEric Joyner 	for (i = vsil + 1; i <= qgl; i++) {
1798*f2635e84SEric Joyner 		int status;
17998923de59SPiotr Kubaj 
180071d10453SEric Joyner 		if (!parent)
180171d10453SEric Joyner 			return ICE_ERR_CFG;
180271d10453SEric Joyner 
180371d10453SEric Joyner 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
180471d10453SEric Joyner 						      num_nodes[i],
180571d10453SEric Joyner 						      &first_node_teid,
180671d10453SEric Joyner 						      &num_added);
1807*f2635e84SEric Joyner 		if (status || num_nodes[i] != num_added)
180871d10453SEric Joyner 			return ICE_ERR_CFG;
180971d10453SEric Joyner 
181071d10453SEric Joyner 		/* The newly added node can be a new parent for the next
181171d10453SEric Joyner 		 * layer nodes
181271d10453SEric Joyner 		 */
181371d10453SEric Joyner 		if (num_added) {
181471d10453SEric Joyner 			parent = ice_sched_find_node_by_teid(tc_node,
181571d10453SEric Joyner 							     first_node_teid);
181671d10453SEric Joyner 			node = parent;
181771d10453SEric Joyner 			while (node) {
181871d10453SEric Joyner 				node->owner = owner;
181971d10453SEric Joyner 				node = node->sibling;
182071d10453SEric Joyner 			}
182171d10453SEric Joyner 		} else {
182271d10453SEric Joyner 			parent = parent->children[0];
182371d10453SEric Joyner 		}
182471d10453SEric Joyner 	}
182571d10453SEric Joyner 
1826*f2635e84SEric Joyner 	return 0;
182771d10453SEric Joyner }
182871d10453SEric Joyner 
182971d10453SEric Joyner /**
183071d10453SEric Joyner  * ice_sched_calc_vsi_support_nodes - calculate number of VSI support nodes
183171d10453SEric Joyner  * @pi: pointer to the port info structure
183271d10453SEric Joyner  * @tc_node: pointer to TC node
183371d10453SEric Joyner  * @num_nodes: pointer to num nodes array
183471d10453SEric Joyner  *
183571d10453SEric Joyner  * This function calculates the number of supported nodes needed to add this
183671d10453SEric Joyner  * VSI into Tx tree including the VSI, parent and intermediate nodes in below
183771d10453SEric Joyner  * layers
183871d10453SEric Joyner  */
183971d10453SEric Joyner static void
184071d10453SEric Joyner ice_sched_calc_vsi_support_nodes(struct ice_port_info *pi,
184171d10453SEric Joyner 				 struct ice_sched_node *tc_node, u16 *num_nodes)
184271d10453SEric Joyner {
184371d10453SEric Joyner 	struct ice_sched_node *node;
184471d10453SEric Joyner 	u8 vsil;
184571d10453SEric Joyner 	int i;
184671d10453SEric Joyner 
184771d10453SEric Joyner 	vsil = ice_sched_get_vsi_layer(pi->hw);
184871d10453SEric Joyner 	for (i = vsil; i >= pi->hw->sw_entry_point_layer; i--)
184971d10453SEric Joyner 		/* Add intermediate nodes if TC has no children and
185071d10453SEric Joyner 		 * need at least one node for VSI
185171d10453SEric Joyner 		 */
185271d10453SEric Joyner 		if (!tc_node->num_children || i == vsil) {
185371d10453SEric Joyner 			num_nodes[i]++;
185471d10453SEric Joyner 		} else {
185571d10453SEric Joyner 			/* If intermediate nodes are reached max children
185671d10453SEric Joyner 			 * then add a new one.
185771d10453SEric Joyner 			 */
185871d10453SEric Joyner 			node = ice_sched_get_first_node(pi, tc_node, (u8)i);
185971d10453SEric Joyner 			/* scan all the siblings */
186071d10453SEric Joyner 			while (node) {
186171d10453SEric Joyner 				if (node->num_children <
186271d10453SEric Joyner 				    pi->hw->max_children[i])
186371d10453SEric Joyner 					break;
186471d10453SEric Joyner 				node = node->sibling;
186571d10453SEric Joyner 			}
186671d10453SEric Joyner 
186771d10453SEric Joyner 			/* tree has one intermediate node to add this new VSI.
186871d10453SEric Joyner 			 * So no need to calculate supported nodes for below
186971d10453SEric Joyner 			 * layers.
187071d10453SEric Joyner 			 */
187171d10453SEric Joyner 			if (node)
187271d10453SEric Joyner 				break;
187371d10453SEric Joyner 			/* all the nodes are full, allocate a new one */
187471d10453SEric Joyner 			num_nodes[i]++;
187571d10453SEric Joyner 		}
187671d10453SEric Joyner }
187771d10453SEric Joyner 
187871d10453SEric Joyner /**
187971d10453SEric Joyner  * ice_sched_add_vsi_support_nodes - add VSI supported nodes into Tx tree
188071d10453SEric Joyner  * @pi: port information structure
188171d10453SEric Joyner  * @vsi_handle: software VSI handle
188271d10453SEric Joyner  * @tc_node: pointer to TC node
188371d10453SEric Joyner  * @num_nodes: pointer to num nodes array
188471d10453SEric Joyner  *
188571d10453SEric Joyner  * This function adds the VSI supported nodes into Tx tree including the
188671d10453SEric Joyner  * VSI, its parent and intermediate nodes in below layers
188771d10453SEric Joyner  */
1888*f2635e84SEric Joyner static int
188971d10453SEric Joyner ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle,
189071d10453SEric Joyner 				struct ice_sched_node *tc_node, u16 *num_nodes)
189171d10453SEric Joyner {
189271d10453SEric Joyner 	struct ice_sched_node *parent = tc_node;
189371d10453SEric Joyner 	u32 first_node_teid;
189471d10453SEric Joyner 	u16 num_added = 0;
189571d10453SEric Joyner 	u8 i, vsil;
189671d10453SEric Joyner 
189771d10453SEric Joyner 	if (!pi)
189871d10453SEric Joyner 		return ICE_ERR_PARAM;
189971d10453SEric Joyner 
190071d10453SEric Joyner 	vsil = ice_sched_get_vsi_layer(pi->hw);
190171d10453SEric Joyner 	for (i = pi->hw->sw_entry_point_layer; i <= vsil; i++) {
1902*f2635e84SEric Joyner 		int status;
19038923de59SPiotr Kubaj 
190471d10453SEric Joyner 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent,
190571d10453SEric Joyner 						      i, num_nodes[i],
190671d10453SEric Joyner 						      &first_node_teid,
190771d10453SEric Joyner 						      &num_added);
1908*f2635e84SEric Joyner 		if (status || num_nodes[i] != num_added)
190971d10453SEric Joyner 			return ICE_ERR_CFG;
191071d10453SEric Joyner 
191171d10453SEric Joyner 		/* The newly added node can be a new parent for the next
191271d10453SEric Joyner 		 * layer nodes
191371d10453SEric Joyner 		 */
191471d10453SEric Joyner 		if (num_added)
191571d10453SEric Joyner 			parent = ice_sched_find_node_by_teid(tc_node,
191671d10453SEric Joyner 							     first_node_teid);
191771d10453SEric Joyner 		else
191871d10453SEric Joyner 			parent = parent->children[0];
191971d10453SEric Joyner 
192071d10453SEric Joyner 		if (!parent)
192171d10453SEric Joyner 			return ICE_ERR_CFG;
192271d10453SEric Joyner 
192371d10453SEric Joyner 		if (i == vsil)
192471d10453SEric Joyner 			parent->vsi_handle = vsi_handle;
192571d10453SEric Joyner 	}
192671d10453SEric Joyner 
1927*f2635e84SEric Joyner 	return 0;
192871d10453SEric Joyner }
192971d10453SEric Joyner 
193071d10453SEric Joyner /**
193171d10453SEric Joyner  * ice_sched_add_vsi_to_topo - add a new VSI into tree
193271d10453SEric Joyner  * @pi: port information structure
193371d10453SEric Joyner  * @vsi_handle: software VSI handle
193471d10453SEric Joyner  * @tc: TC number
193571d10453SEric Joyner  *
193671d10453SEric Joyner  * This function adds a new VSI into scheduler tree
193771d10453SEric Joyner  */
1938*f2635e84SEric Joyner static int
193971d10453SEric Joyner ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc)
194071d10453SEric Joyner {
194171d10453SEric Joyner 	u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
194271d10453SEric Joyner 	struct ice_sched_node *tc_node;
194371d10453SEric Joyner 
194471d10453SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
194571d10453SEric Joyner 	if (!tc_node)
194671d10453SEric Joyner 		return ICE_ERR_PARAM;
194771d10453SEric Joyner 
194871d10453SEric Joyner 	/* calculate number of supported nodes needed for this VSI */
194971d10453SEric Joyner 	ice_sched_calc_vsi_support_nodes(pi, tc_node, num_nodes);
195071d10453SEric Joyner 
195171d10453SEric Joyner 	/* add VSI supported nodes to TC subtree */
195271d10453SEric Joyner 	return ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node,
195371d10453SEric Joyner 					       num_nodes);
195471d10453SEric Joyner }
195571d10453SEric Joyner 
195671d10453SEric Joyner /**
195771d10453SEric Joyner  * ice_sched_update_vsi_child_nodes - update VSI child nodes
195871d10453SEric Joyner  * @pi: port information structure
195971d10453SEric Joyner  * @vsi_handle: software VSI handle
196071d10453SEric Joyner  * @tc: TC number
196171d10453SEric Joyner  * @new_numqs: new number of max queues
196271d10453SEric Joyner  * @owner: owner of this subtree
196371d10453SEric Joyner  *
196471d10453SEric Joyner  * This function updates the VSI child nodes based on the number of queues
196571d10453SEric Joyner  */
1966*f2635e84SEric Joyner static int
196771d10453SEric Joyner ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
196871d10453SEric Joyner 				 u8 tc, u16 new_numqs, u8 owner)
196971d10453SEric Joyner {
197071d10453SEric Joyner 	u16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
197171d10453SEric Joyner 	struct ice_sched_node *vsi_node;
197271d10453SEric Joyner 	struct ice_sched_node *tc_node;
197371d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
197471d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
1975*f2635e84SEric Joyner 	int status = 0;
197671d10453SEric Joyner 	u16 prev_numqs;
197771d10453SEric Joyner 
197871d10453SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
197971d10453SEric Joyner 	if (!tc_node)
198071d10453SEric Joyner 		return ICE_ERR_CFG;
198171d10453SEric Joyner 
198271d10453SEric Joyner 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
198371d10453SEric Joyner 	if (!vsi_node)
198471d10453SEric Joyner 		return ICE_ERR_CFG;
198571d10453SEric Joyner 
198671d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
198771d10453SEric Joyner 	if (!vsi_ctx)
198871d10453SEric Joyner 		return ICE_ERR_PARAM;
198971d10453SEric Joyner 
19908a13362dSEric Joyner 	if (owner == ICE_SCHED_NODE_OWNER_LAN)
199171d10453SEric Joyner 		prev_numqs = vsi_ctx->sched.max_lanq[tc];
19928a13362dSEric Joyner 	else
19938a13362dSEric Joyner 		prev_numqs = vsi_ctx->sched.max_rdmaq[tc];
199471d10453SEric Joyner 	/* num queues are not changed or less than the previous number */
199571d10453SEric Joyner 	if (new_numqs <= prev_numqs)
199671d10453SEric Joyner 		return status;
19978a13362dSEric Joyner 	if (owner == ICE_SCHED_NODE_OWNER_LAN) {
199871d10453SEric Joyner 		status = ice_alloc_lan_q_ctx(hw, vsi_handle, tc, new_numqs);
199971d10453SEric Joyner 		if (status)
200071d10453SEric Joyner 			return status;
20018a13362dSEric Joyner 	} else {
20028a13362dSEric Joyner 		status = ice_alloc_rdma_q_ctx(hw, vsi_handle, tc, new_numqs);
20038a13362dSEric Joyner 		if (status)
20048a13362dSEric Joyner 			return status;
20058a13362dSEric Joyner 	}
200671d10453SEric Joyner 
200771d10453SEric Joyner 	if (new_numqs)
200871d10453SEric Joyner 		ice_sched_calc_vsi_child_nodes(hw, new_numqs, new_num_nodes);
200971d10453SEric Joyner 	/* Keep the max number of queue configuration all the time. Update the
201071d10453SEric Joyner 	 * tree only if number of queues > previous number of queues. This may
201171d10453SEric Joyner 	 * leave some extra nodes in the tree if number of queues < previous
201271d10453SEric Joyner 	 * number but that wouldn't harm anything. Removing those extra nodes
201371d10453SEric Joyner 	 * may complicate the code if those nodes are part of SRL or
201471d10453SEric Joyner 	 * individually rate limited.
201571d10453SEric Joyner 	 */
201671d10453SEric Joyner 	status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node,
201771d10453SEric Joyner 					       new_num_nodes, owner);
201871d10453SEric Joyner 	if (status)
201971d10453SEric Joyner 		return status;
20208a13362dSEric Joyner 	if (owner == ICE_SCHED_NODE_OWNER_LAN)
202171d10453SEric Joyner 		vsi_ctx->sched.max_lanq[tc] = new_numqs;
20228a13362dSEric Joyner 	else
20238a13362dSEric Joyner 		vsi_ctx->sched.max_rdmaq[tc] = new_numqs;
202471d10453SEric Joyner 
2025*f2635e84SEric Joyner 	return 0;
202671d10453SEric Joyner }
202771d10453SEric Joyner 
202871d10453SEric Joyner /**
202971d10453SEric Joyner  * ice_sched_cfg_vsi - configure the new/existing VSI
203071d10453SEric Joyner  * @pi: port information structure
203171d10453SEric Joyner  * @vsi_handle: software VSI handle
203271d10453SEric Joyner  * @tc: TC number
203371d10453SEric Joyner  * @maxqs: max number of queues
203471d10453SEric Joyner  * @owner: LAN or RDMA
203571d10453SEric Joyner  * @enable: TC enabled or disabled
203671d10453SEric Joyner  *
203771d10453SEric Joyner  * This function adds/updates VSI nodes based on the number of queues. If TC is
203871d10453SEric Joyner  * enabled and VSI is in suspended state then resume the VSI back. If TC is
203971d10453SEric Joyner  * disabled then suspend the VSI if it is not already.
204071d10453SEric Joyner  */
2041*f2635e84SEric Joyner int
204271d10453SEric Joyner ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs,
204371d10453SEric Joyner 		  u8 owner, bool enable)
204471d10453SEric Joyner {
204571d10453SEric Joyner 	struct ice_sched_node *vsi_node, *tc_node;
204671d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
204771d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
2048*f2635e84SEric Joyner 	int status = 0;
204971d10453SEric Joyner 
205071d10453SEric Joyner 	ice_debug(pi->hw, ICE_DBG_SCHED, "add/config VSI %d\n", vsi_handle);
205171d10453SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
205271d10453SEric Joyner 	if (!tc_node)
205371d10453SEric Joyner 		return ICE_ERR_PARAM;
205471d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
205571d10453SEric Joyner 	if (!vsi_ctx)
205671d10453SEric Joyner 		return ICE_ERR_PARAM;
205771d10453SEric Joyner 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
205871d10453SEric Joyner 
205971d10453SEric Joyner 	/* suspend the VSI if TC is not enabled */
206071d10453SEric Joyner 	if (!enable) {
206171d10453SEric Joyner 		if (vsi_node && vsi_node->in_use) {
206271d10453SEric Joyner 			u32 teid = LE32_TO_CPU(vsi_node->info.node_teid);
206371d10453SEric Joyner 
206471d10453SEric Joyner 			status = ice_sched_suspend_resume_elems(hw, 1, &teid,
206571d10453SEric Joyner 								true);
206671d10453SEric Joyner 			if (!status)
206771d10453SEric Joyner 				vsi_node->in_use = false;
206871d10453SEric Joyner 		}
206971d10453SEric Joyner 		return status;
207071d10453SEric Joyner 	}
207171d10453SEric Joyner 
207271d10453SEric Joyner 	/* TC is enabled, if it is a new VSI then add it to the tree */
207371d10453SEric Joyner 	if (!vsi_node) {
207471d10453SEric Joyner 		status = ice_sched_add_vsi_to_topo(pi, vsi_handle, tc);
207571d10453SEric Joyner 		if (status)
207671d10453SEric Joyner 			return status;
207771d10453SEric Joyner 
207871d10453SEric Joyner 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
207971d10453SEric Joyner 		if (!vsi_node)
208071d10453SEric Joyner 			return ICE_ERR_CFG;
208171d10453SEric Joyner 
208271d10453SEric Joyner 		vsi_ctx->sched.vsi_node[tc] = vsi_node;
208371d10453SEric Joyner 		vsi_node->in_use = true;
208471d10453SEric Joyner 		/* invalidate the max queues whenever VSI gets added first time
208571d10453SEric Joyner 		 * into the scheduler tree (boot or after reset). We need to
208671d10453SEric Joyner 		 * recreate the child nodes all the time in these cases.
208771d10453SEric Joyner 		 */
208871d10453SEric Joyner 		vsi_ctx->sched.max_lanq[tc] = 0;
20898a13362dSEric Joyner 		vsi_ctx->sched.max_rdmaq[tc] = 0;
209071d10453SEric Joyner 	}
209171d10453SEric Joyner 
209271d10453SEric Joyner 	/* update the VSI child nodes */
209371d10453SEric Joyner 	status = ice_sched_update_vsi_child_nodes(pi, vsi_handle, tc, maxqs,
209471d10453SEric Joyner 						  owner);
209571d10453SEric Joyner 	if (status)
209671d10453SEric Joyner 		return status;
209771d10453SEric Joyner 
209871d10453SEric Joyner 	/* TC is enabled, resume the VSI if it is in the suspend state */
209971d10453SEric Joyner 	if (!vsi_node->in_use) {
210071d10453SEric Joyner 		u32 teid = LE32_TO_CPU(vsi_node->info.node_teid);
210171d10453SEric Joyner 
210271d10453SEric Joyner 		status = ice_sched_suspend_resume_elems(hw, 1, &teid, false);
210371d10453SEric Joyner 		if (!status)
210471d10453SEric Joyner 			vsi_node->in_use = true;
210571d10453SEric Joyner 	}
210671d10453SEric Joyner 
210771d10453SEric Joyner 	return status;
210871d10453SEric Joyner }
210971d10453SEric Joyner 
211071d10453SEric Joyner /**
211156429daeSEric Joyner  * ice_sched_rm_agg_vsi_info - remove aggregator related VSI info entry
211271d10453SEric Joyner  * @pi: port information structure
211371d10453SEric Joyner  * @vsi_handle: software VSI handle
211471d10453SEric Joyner  *
211571d10453SEric Joyner  * This function removes single aggregator VSI info entry from
211671d10453SEric Joyner  * aggregator list.
211771d10453SEric Joyner  */
21187d7af7f8SEric Joyner static void ice_sched_rm_agg_vsi_info(struct ice_port_info *pi, u16 vsi_handle)
211971d10453SEric Joyner {
212071d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
212171d10453SEric Joyner 	struct ice_sched_agg_info *atmp;
212271d10453SEric Joyner 
212371d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(agg_info, atmp, &pi->hw->agg_list,
212471d10453SEric Joyner 				 ice_sched_agg_info,
212571d10453SEric Joyner 				 list_entry) {
212671d10453SEric Joyner 		struct ice_sched_agg_vsi_info *agg_vsi_info;
212771d10453SEric Joyner 		struct ice_sched_agg_vsi_info *vtmp;
212871d10453SEric Joyner 
212971d10453SEric Joyner 		LIST_FOR_EACH_ENTRY_SAFE(agg_vsi_info, vtmp,
213071d10453SEric Joyner 					 &agg_info->agg_vsi_list,
213171d10453SEric Joyner 					 ice_sched_agg_vsi_info, list_entry)
213271d10453SEric Joyner 			if (agg_vsi_info->vsi_handle == vsi_handle) {
213371d10453SEric Joyner 				LIST_DEL(&agg_vsi_info->list_entry);
213471d10453SEric Joyner 				ice_free(pi->hw, agg_vsi_info);
213571d10453SEric Joyner 				return;
213671d10453SEric Joyner 			}
213771d10453SEric Joyner 	}
213871d10453SEric Joyner }
213971d10453SEric Joyner 
214071d10453SEric Joyner /**
214171d10453SEric Joyner  * ice_sched_is_leaf_node_present - check for a leaf node in the sub-tree
214271d10453SEric Joyner  * @node: pointer to the sub-tree node
214371d10453SEric Joyner  *
214471d10453SEric Joyner  * This function checks for a leaf node presence in a given sub-tree node.
214571d10453SEric Joyner  */
214671d10453SEric Joyner static bool ice_sched_is_leaf_node_present(struct ice_sched_node *node)
214771d10453SEric Joyner {
214871d10453SEric Joyner 	u8 i;
214971d10453SEric Joyner 
215071d10453SEric Joyner 	for (i = 0; i < node->num_children; i++)
215171d10453SEric Joyner 		if (ice_sched_is_leaf_node_present(node->children[i]))
215271d10453SEric Joyner 			return true;
215371d10453SEric Joyner 	/* check for a leaf node */
215471d10453SEric Joyner 	return (node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF);
215571d10453SEric Joyner }
215671d10453SEric Joyner 
215771d10453SEric Joyner /**
215871d10453SEric Joyner  * ice_sched_rm_vsi_cfg - remove the VSI and its children nodes
215971d10453SEric Joyner  * @pi: port information structure
216071d10453SEric Joyner  * @vsi_handle: software VSI handle
216171d10453SEric Joyner  * @owner: LAN or RDMA
216271d10453SEric Joyner  *
216371d10453SEric Joyner  * This function removes the VSI and its LAN or RDMA children nodes from the
216471d10453SEric Joyner  * scheduler tree.
216571d10453SEric Joyner  */
2166*f2635e84SEric Joyner static int
216771d10453SEric Joyner ice_sched_rm_vsi_cfg(struct ice_port_info *pi, u16 vsi_handle, u8 owner)
216871d10453SEric Joyner {
216971d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
2170*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
217171d10453SEric Joyner 	u8 i;
217271d10453SEric Joyner 
217371d10453SEric Joyner 	ice_debug(pi->hw, ICE_DBG_SCHED, "removing VSI %d\n", vsi_handle);
217471d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
217571d10453SEric Joyner 		return status;
217671d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
217771d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
217871d10453SEric Joyner 	if (!vsi_ctx)
217971d10453SEric Joyner 		goto exit_sched_rm_vsi_cfg;
218071d10453SEric Joyner 
218171d10453SEric Joyner 	ice_for_each_traffic_class(i) {
218271d10453SEric Joyner 		struct ice_sched_node *vsi_node, *tc_node;
218371d10453SEric Joyner 		u8 j = 0;
218471d10453SEric Joyner 
218571d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, i);
218671d10453SEric Joyner 		if (!tc_node)
218771d10453SEric Joyner 			continue;
218871d10453SEric Joyner 
218971d10453SEric Joyner 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
219071d10453SEric Joyner 		if (!vsi_node)
219171d10453SEric Joyner 			continue;
219271d10453SEric Joyner 
219371d10453SEric Joyner 		if (ice_sched_is_leaf_node_present(vsi_node)) {
21947d7af7f8SEric Joyner 			ice_debug(pi->hw, ICE_DBG_SCHED, "VSI has leaf nodes in TC %d\n", i);
219571d10453SEric Joyner 			status = ICE_ERR_IN_USE;
219671d10453SEric Joyner 			goto exit_sched_rm_vsi_cfg;
219771d10453SEric Joyner 		}
219871d10453SEric Joyner 		while (j < vsi_node->num_children) {
219971d10453SEric Joyner 			if (vsi_node->children[j]->owner == owner) {
220071d10453SEric Joyner 				ice_free_sched_node(pi, vsi_node->children[j]);
220171d10453SEric Joyner 
220271d10453SEric Joyner 				/* reset the counter again since the num
220371d10453SEric Joyner 				 * children will be updated after node removal
220471d10453SEric Joyner 				 */
220571d10453SEric Joyner 				j = 0;
220671d10453SEric Joyner 			} else {
220771d10453SEric Joyner 				j++;
220871d10453SEric Joyner 			}
220971d10453SEric Joyner 		}
221071d10453SEric Joyner 		/* remove the VSI if it has no children */
221171d10453SEric Joyner 		if (!vsi_node->num_children) {
221271d10453SEric Joyner 			ice_free_sched_node(pi, vsi_node);
221371d10453SEric Joyner 			vsi_ctx->sched.vsi_node[i] = NULL;
221471d10453SEric Joyner 
221571d10453SEric Joyner 			/* clean up aggregator related VSI info if any */
221671d10453SEric Joyner 			ice_sched_rm_agg_vsi_info(pi, vsi_handle);
221771d10453SEric Joyner 		}
221871d10453SEric Joyner 		if (owner == ICE_SCHED_NODE_OWNER_LAN)
221971d10453SEric Joyner 			vsi_ctx->sched.max_lanq[i] = 0;
22208a13362dSEric Joyner 		else
22218a13362dSEric Joyner 			vsi_ctx->sched.max_rdmaq[i] = 0;
222271d10453SEric Joyner 	}
2223*f2635e84SEric Joyner 	status = 0;
222471d10453SEric Joyner 
222571d10453SEric Joyner exit_sched_rm_vsi_cfg:
222671d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
222771d10453SEric Joyner 	return status;
222871d10453SEric Joyner }
222971d10453SEric Joyner 
223071d10453SEric Joyner /**
223171d10453SEric Joyner  * ice_rm_vsi_lan_cfg - remove VSI and its LAN children nodes
223271d10453SEric Joyner  * @pi: port information structure
223371d10453SEric Joyner  * @vsi_handle: software VSI handle
223471d10453SEric Joyner  *
223571d10453SEric Joyner  * This function clears the VSI and its LAN children nodes from scheduler tree
223671d10453SEric Joyner  * for all TCs.
223771d10453SEric Joyner  */
2238*f2635e84SEric Joyner int ice_rm_vsi_lan_cfg(struct ice_port_info *pi, u16 vsi_handle)
223971d10453SEric Joyner {
224071d10453SEric Joyner 	return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_LAN);
224171d10453SEric Joyner }
224271d10453SEric Joyner 
224371d10453SEric Joyner /**
22448a13362dSEric Joyner  * ice_rm_vsi_rdma_cfg - remove VSI and its RDMA children nodes
22458a13362dSEric Joyner  * @pi: port information structure
22468a13362dSEric Joyner  * @vsi_handle: software VSI handle
22478a13362dSEric Joyner  *
22488a13362dSEric Joyner  * This function clears the VSI and its RDMA children nodes from scheduler tree
22498a13362dSEric Joyner  * for all TCs.
22508a13362dSEric Joyner  */
2251*f2635e84SEric Joyner int ice_rm_vsi_rdma_cfg(struct ice_port_info *pi, u16 vsi_handle)
22528a13362dSEric Joyner {
22538a13362dSEric Joyner 	return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_RDMA);
22548a13362dSEric Joyner }
22558a13362dSEric Joyner 
22568a13362dSEric Joyner /**
225771d10453SEric Joyner  * ice_sched_is_tree_balanced - Check tree nodes are identical or not
225871d10453SEric Joyner  * @hw: pointer to the HW struct
225971d10453SEric Joyner  * @node: pointer to the ice_sched_node struct
226071d10453SEric Joyner  *
226171d10453SEric Joyner  * This function compares all the nodes for a given tree against HW DB nodes
226271d10453SEric Joyner  * This function needs to be called with the port_info->sched_lock held
226371d10453SEric Joyner  */
226471d10453SEric Joyner bool ice_sched_is_tree_balanced(struct ice_hw *hw, struct ice_sched_node *node)
226571d10453SEric Joyner {
226671d10453SEric Joyner 	u8 i;
226771d10453SEric Joyner 
226871d10453SEric Joyner 	/* start from the leaf node */
226971d10453SEric Joyner 	for (i = 0; i < node->num_children; i++)
227071d10453SEric Joyner 		/* Fail if node doesn't match with the SW DB
227171d10453SEric Joyner 		 * this recursion is intentional, and wouldn't
227271d10453SEric Joyner 		 * go more than 9 calls
227371d10453SEric Joyner 		 */
227471d10453SEric Joyner 		if (!ice_sched_is_tree_balanced(hw, node->children[i]))
227571d10453SEric Joyner 			return false;
227671d10453SEric Joyner 
227771d10453SEric Joyner 	return ice_sched_check_node(hw, node);
227871d10453SEric Joyner }
227971d10453SEric Joyner 
228071d10453SEric Joyner /**
228171d10453SEric Joyner  * ice_aq_query_node_to_root - retrieve the tree topology for a given node TEID
228271d10453SEric Joyner  * @hw: pointer to the HW struct
228371d10453SEric Joyner  * @node_teid: node TEID
228471d10453SEric Joyner  * @buf: pointer to buffer
228571d10453SEric Joyner  * @buf_size: buffer size in bytes
228671d10453SEric Joyner  * @cd: pointer to command details structure or NULL
228771d10453SEric Joyner  *
228871d10453SEric Joyner  * This function retrieves the tree topology from the firmware for a given
228971d10453SEric Joyner  * node TEID to the root node.
229071d10453SEric Joyner  */
2291*f2635e84SEric Joyner int
229271d10453SEric Joyner ice_aq_query_node_to_root(struct ice_hw *hw, u32 node_teid,
22937d7af7f8SEric Joyner 			  struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
229471d10453SEric Joyner 			  struct ice_sq_cd *cd)
229571d10453SEric Joyner {
229671d10453SEric Joyner 	struct ice_aqc_query_node_to_root *cmd;
229771d10453SEric Joyner 	struct ice_aq_desc desc;
229871d10453SEric Joyner 
229971d10453SEric Joyner 	cmd = &desc.params.query_node_to_root;
230071d10453SEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_node_to_root);
230171d10453SEric Joyner 	cmd->teid = CPU_TO_LE32(node_teid);
230271d10453SEric Joyner 	return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
230371d10453SEric Joyner }
230471d10453SEric Joyner 
230571d10453SEric Joyner /**
230671d10453SEric Joyner  * ice_get_agg_info - get the aggregator ID
230771d10453SEric Joyner  * @hw: pointer to the hardware structure
230871d10453SEric Joyner  * @agg_id: aggregator ID
230971d10453SEric Joyner  *
231071d10453SEric Joyner  * This function validates aggregator ID. The function returns info if
231171d10453SEric Joyner  * aggregator ID is present in list otherwise it returns null.
231271d10453SEric Joyner  */
231371d10453SEric Joyner static struct ice_sched_agg_info *
231471d10453SEric Joyner ice_get_agg_info(struct ice_hw *hw, u32 agg_id)
231571d10453SEric Joyner {
231671d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
231771d10453SEric Joyner 
231871d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
231971d10453SEric Joyner 			    list_entry)
232071d10453SEric Joyner 		if (agg_info->agg_id == agg_id)
232171d10453SEric Joyner 			return agg_info;
232271d10453SEric Joyner 
232371d10453SEric Joyner 	return NULL;
232471d10453SEric Joyner }
232571d10453SEric Joyner 
232671d10453SEric Joyner /**
232771d10453SEric Joyner  * ice_sched_get_free_vsi_parent - Find a free parent node in aggregator subtree
232871d10453SEric Joyner  * @hw: pointer to the HW struct
232971d10453SEric Joyner  * @node: pointer to a child node
233071d10453SEric Joyner  * @num_nodes: num nodes count array
233171d10453SEric Joyner  *
233271d10453SEric Joyner  * This function walks through the aggregator subtree to find a free parent
233371d10453SEric Joyner  * node
233471d10453SEric Joyner  */
233571d10453SEric Joyner static struct ice_sched_node *
233671d10453SEric Joyner ice_sched_get_free_vsi_parent(struct ice_hw *hw, struct ice_sched_node *node,
233771d10453SEric Joyner 			      u16 *num_nodes)
233871d10453SEric Joyner {
233971d10453SEric Joyner 	u8 l = node->tx_sched_layer;
234071d10453SEric Joyner 	u8 vsil, i;
234171d10453SEric Joyner 
234271d10453SEric Joyner 	vsil = ice_sched_get_vsi_layer(hw);
234371d10453SEric Joyner 
234471d10453SEric Joyner 	/* Is it VSI parent layer ? */
234571d10453SEric Joyner 	if (l == vsil - 1)
234671d10453SEric Joyner 		return (node->num_children < hw->max_children[l]) ? node : NULL;
234771d10453SEric Joyner 
234871d10453SEric Joyner 	/* We have intermediate nodes. Let's walk through the subtree. If the
234971d10453SEric Joyner 	 * intermediate node has space to add a new node then clear the count
235071d10453SEric Joyner 	 */
235171d10453SEric Joyner 	if (node->num_children < hw->max_children[l])
235271d10453SEric Joyner 		num_nodes[l] = 0;
235371d10453SEric Joyner 	/* The below recursive call is intentional and wouldn't go more than
235471d10453SEric Joyner 	 * 2 or 3 iterations.
235571d10453SEric Joyner 	 */
235671d10453SEric Joyner 
235771d10453SEric Joyner 	for (i = 0; i < node->num_children; i++) {
235871d10453SEric Joyner 		struct ice_sched_node *parent;
235971d10453SEric Joyner 
236071d10453SEric Joyner 		parent = ice_sched_get_free_vsi_parent(hw, node->children[i],
236171d10453SEric Joyner 						       num_nodes);
236271d10453SEric Joyner 		if (parent)
236371d10453SEric Joyner 			return parent;
236471d10453SEric Joyner 	}
236571d10453SEric Joyner 
236671d10453SEric Joyner 	return NULL;
236771d10453SEric Joyner }
236871d10453SEric Joyner 
236971d10453SEric Joyner /**
237071d10453SEric Joyner  * ice_sched_update_parent - update the new parent in SW DB
237171d10453SEric Joyner  * @new_parent: pointer to a new parent node
237271d10453SEric Joyner  * @node: pointer to a child node
237371d10453SEric Joyner  *
237471d10453SEric Joyner  * This function removes the child from the old parent and adds it to a new
237571d10453SEric Joyner  * parent
237671d10453SEric Joyner  */
23779c30461dSEric Joyner void
237871d10453SEric Joyner ice_sched_update_parent(struct ice_sched_node *new_parent,
237971d10453SEric Joyner 			struct ice_sched_node *node)
238071d10453SEric Joyner {
238171d10453SEric Joyner 	struct ice_sched_node *old_parent;
238271d10453SEric Joyner 	u8 i, j;
238371d10453SEric Joyner 
238471d10453SEric Joyner 	old_parent = node->parent;
238571d10453SEric Joyner 
238671d10453SEric Joyner 	/* update the old parent children */
238771d10453SEric Joyner 	for (i = 0; i < old_parent->num_children; i++)
238871d10453SEric Joyner 		if (old_parent->children[i] == node) {
238971d10453SEric Joyner 			for (j = i + 1; j < old_parent->num_children; j++)
239071d10453SEric Joyner 				old_parent->children[j - 1] =
239171d10453SEric Joyner 					old_parent->children[j];
239271d10453SEric Joyner 			old_parent->num_children--;
239371d10453SEric Joyner 			break;
239471d10453SEric Joyner 		}
239571d10453SEric Joyner 
239671d10453SEric Joyner 	/* now move the node to a new parent */
239771d10453SEric Joyner 	new_parent->children[new_parent->num_children++] = node;
239871d10453SEric Joyner 	node->parent = new_parent;
239971d10453SEric Joyner 	node->info.parent_teid = new_parent->info.node_teid;
240071d10453SEric Joyner }
240171d10453SEric Joyner 
240271d10453SEric Joyner /**
240371d10453SEric Joyner  * ice_sched_move_nodes - move child nodes to a given parent
240471d10453SEric Joyner  * @pi: port information structure
240571d10453SEric Joyner  * @parent: pointer to parent node
240671d10453SEric Joyner  * @num_items: number of child nodes to be moved
240771d10453SEric Joyner  * @list: pointer to child node teids
240871d10453SEric Joyner  *
240971d10453SEric Joyner  * This function move the child nodes to a given parent.
241071d10453SEric Joyner  */
2411*f2635e84SEric Joyner int
241271d10453SEric Joyner ice_sched_move_nodes(struct ice_port_info *pi, struct ice_sched_node *parent,
241371d10453SEric Joyner 		     u16 num_items, u32 *list)
241471d10453SEric Joyner {
241571d10453SEric Joyner 	struct ice_aqc_move_elem *buf;
241671d10453SEric Joyner 	struct ice_sched_node *node;
241771d10453SEric Joyner 	u16 i, grps_movd = 0;
241871d10453SEric Joyner 	struct ice_hw *hw;
2419*f2635e84SEric Joyner 	int status = 0;
24207d7af7f8SEric Joyner 	u16 buf_len;
242171d10453SEric Joyner 
242271d10453SEric Joyner 	hw = pi->hw;
242371d10453SEric Joyner 
242471d10453SEric Joyner 	if (!parent || !num_items)
242571d10453SEric Joyner 		return ICE_ERR_PARAM;
242671d10453SEric Joyner 
242771d10453SEric Joyner 	/* Does parent have enough space */
24287d7af7f8SEric Joyner 	if (parent->num_children + num_items >
242971d10453SEric Joyner 	    hw->max_children[parent->tx_sched_layer])
243071d10453SEric Joyner 		return ICE_ERR_AQ_FULL;
243171d10453SEric Joyner 
24327d7af7f8SEric Joyner 	buf_len = ice_struct_size(buf, teid, 1);
24337d7af7f8SEric Joyner 	buf = (struct ice_aqc_move_elem *)ice_malloc(hw, buf_len);
243471d10453SEric Joyner 	if (!buf)
243571d10453SEric Joyner 		return ICE_ERR_NO_MEMORY;
243671d10453SEric Joyner 
243771d10453SEric Joyner 	for (i = 0; i < num_items; i++) {
243871d10453SEric Joyner 		node = ice_sched_find_node_by_teid(pi->root, list[i]);
243971d10453SEric Joyner 		if (!node) {
244071d10453SEric Joyner 			status = ICE_ERR_PARAM;
244171d10453SEric Joyner 			goto move_err_exit;
244271d10453SEric Joyner 		}
244371d10453SEric Joyner 
244471d10453SEric Joyner 		buf->hdr.src_parent_teid = node->info.parent_teid;
244571d10453SEric Joyner 		buf->hdr.dest_parent_teid = parent->info.node_teid;
244671d10453SEric Joyner 		buf->teid[0] = node->info.node_teid;
244771d10453SEric Joyner 		buf->hdr.num_elems = CPU_TO_LE16(1);
24487d7af7f8SEric Joyner 		status = ice_aq_move_sched_elems(hw, 1, buf, buf_len,
244971d10453SEric Joyner 						 &grps_movd, NULL);
245071d10453SEric Joyner 		if (status && grps_movd != 1) {
245171d10453SEric Joyner 			status = ICE_ERR_CFG;
245271d10453SEric Joyner 			goto move_err_exit;
245371d10453SEric Joyner 		}
245471d10453SEric Joyner 
245571d10453SEric Joyner 		/* update the SW DB */
245671d10453SEric Joyner 		ice_sched_update_parent(parent, node);
245771d10453SEric Joyner 	}
245871d10453SEric Joyner 
245971d10453SEric Joyner move_err_exit:
246071d10453SEric Joyner 	ice_free(hw, buf);
246171d10453SEric Joyner 	return status;
246271d10453SEric Joyner }
246371d10453SEric Joyner 
246471d10453SEric Joyner /**
246571d10453SEric Joyner  * ice_sched_move_vsi_to_agg - move VSI to aggregator node
246671d10453SEric Joyner  * @pi: port information structure
246771d10453SEric Joyner  * @vsi_handle: software VSI handle
246871d10453SEric Joyner  * @agg_id: aggregator ID
246971d10453SEric Joyner  * @tc: TC number
247071d10453SEric Joyner  *
247171d10453SEric Joyner  * This function moves a VSI to an aggregator node or its subtree.
247271d10453SEric Joyner  * Intermediate nodes may be created if required.
247371d10453SEric Joyner  */
2474*f2635e84SEric Joyner static int
247571d10453SEric Joyner ice_sched_move_vsi_to_agg(struct ice_port_info *pi, u16 vsi_handle, u32 agg_id,
247671d10453SEric Joyner 			  u8 tc)
247771d10453SEric Joyner {
247871d10453SEric Joyner 	struct ice_sched_node *vsi_node, *agg_node, *tc_node, *parent;
247971d10453SEric Joyner 	u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
248071d10453SEric Joyner 	u32 first_node_teid, vsi_teid;
248171d10453SEric Joyner 	u16 num_nodes_added;
248271d10453SEric Joyner 	u8 aggl, vsil, i;
2483*f2635e84SEric Joyner 	int status;
248471d10453SEric Joyner 
248571d10453SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
248671d10453SEric Joyner 	if (!tc_node)
248771d10453SEric Joyner 		return ICE_ERR_CFG;
248871d10453SEric Joyner 
248971d10453SEric Joyner 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
249071d10453SEric Joyner 	if (!agg_node)
249171d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
249271d10453SEric Joyner 
249371d10453SEric Joyner 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
249471d10453SEric Joyner 	if (!vsi_node)
249571d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
249671d10453SEric Joyner 
24977d7af7f8SEric Joyner 	/* Is this VSI already part of given aggregator? */
24987d7af7f8SEric Joyner 	if (ice_sched_find_node_in_subtree(pi->hw, agg_node, vsi_node))
2499*f2635e84SEric Joyner 		return 0;
25007d7af7f8SEric Joyner 
250171d10453SEric Joyner 	aggl = ice_sched_get_agg_layer(pi->hw);
250271d10453SEric Joyner 	vsil = ice_sched_get_vsi_layer(pi->hw);
250371d10453SEric Joyner 
250471d10453SEric Joyner 	/* set intermediate node count to 1 between aggregator and VSI layers */
250571d10453SEric Joyner 	for (i = aggl + 1; i < vsil; i++)
250671d10453SEric Joyner 		num_nodes[i] = 1;
250771d10453SEric Joyner 
250871d10453SEric Joyner 	/* Check if the aggregator subtree has any free node to add the VSI */
250971d10453SEric Joyner 	for (i = 0; i < agg_node->num_children; i++) {
251071d10453SEric Joyner 		parent = ice_sched_get_free_vsi_parent(pi->hw,
251171d10453SEric Joyner 						       agg_node->children[i],
251271d10453SEric Joyner 						       num_nodes);
251371d10453SEric Joyner 		if (parent)
251471d10453SEric Joyner 			goto move_nodes;
251571d10453SEric Joyner 	}
251671d10453SEric Joyner 
251771d10453SEric Joyner 	/* add new nodes */
251871d10453SEric Joyner 	parent = agg_node;
251971d10453SEric Joyner 	for (i = aggl + 1; i < vsil; i++) {
252071d10453SEric Joyner 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
252171d10453SEric Joyner 						      num_nodes[i],
252271d10453SEric Joyner 						      &first_node_teid,
252371d10453SEric Joyner 						      &num_nodes_added);
2524*f2635e84SEric Joyner 		if (status || num_nodes[i] != num_nodes_added)
252571d10453SEric Joyner 			return ICE_ERR_CFG;
252671d10453SEric Joyner 
252771d10453SEric Joyner 		/* The newly added node can be a new parent for the next
252871d10453SEric Joyner 		 * layer nodes
252971d10453SEric Joyner 		 */
253071d10453SEric Joyner 		if (num_nodes_added)
253171d10453SEric Joyner 			parent = ice_sched_find_node_by_teid(tc_node,
253271d10453SEric Joyner 							     first_node_teid);
253371d10453SEric Joyner 		else
253471d10453SEric Joyner 			parent = parent->children[0];
253571d10453SEric Joyner 
253671d10453SEric Joyner 		if (!parent)
253771d10453SEric Joyner 			return ICE_ERR_CFG;
253871d10453SEric Joyner 	}
253971d10453SEric Joyner 
254071d10453SEric Joyner move_nodes:
254171d10453SEric Joyner 	vsi_teid = LE32_TO_CPU(vsi_node->info.node_teid);
254271d10453SEric Joyner 	return ice_sched_move_nodes(pi, parent, 1, &vsi_teid);
254371d10453SEric Joyner }
254471d10453SEric Joyner 
254571d10453SEric Joyner /**
254671d10453SEric Joyner  * ice_move_all_vsi_to_dflt_agg - move all VSI(s) to default aggregator
254771d10453SEric Joyner  * @pi: port information structure
254871d10453SEric Joyner  * @agg_info: aggregator info
254971d10453SEric Joyner  * @tc: traffic class number
255071d10453SEric Joyner  * @rm_vsi_info: true or false
255171d10453SEric Joyner  *
255271d10453SEric Joyner  * This function move all the VSI(s) to the default aggregator and delete
255371d10453SEric Joyner  * aggregator VSI info based on passed in boolean parameter rm_vsi_info. The
255471d10453SEric Joyner  * caller holds the scheduler lock.
255571d10453SEric Joyner  */
2556*f2635e84SEric Joyner static int
255771d10453SEric Joyner ice_move_all_vsi_to_dflt_agg(struct ice_port_info *pi,
255871d10453SEric Joyner 			     struct ice_sched_agg_info *agg_info, u8 tc,
255971d10453SEric Joyner 			     bool rm_vsi_info)
256071d10453SEric Joyner {
256171d10453SEric Joyner 	struct ice_sched_agg_vsi_info *agg_vsi_info;
256271d10453SEric Joyner 	struct ice_sched_agg_vsi_info *tmp;
2563*f2635e84SEric Joyner 	int status = 0;
256471d10453SEric Joyner 
256571d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(agg_vsi_info, tmp, &agg_info->agg_vsi_list,
256671d10453SEric Joyner 				 ice_sched_agg_vsi_info, list_entry) {
256771d10453SEric Joyner 		u16 vsi_handle = agg_vsi_info->vsi_handle;
256871d10453SEric Joyner 
256971d10453SEric Joyner 		/* Move VSI to default aggregator */
257071d10453SEric Joyner 		if (!ice_is_tc_ena(agg_vsi_info->tc_bitmap[0], tc))
257171d10453SEric Joyner 			continue;
257271d10453SEric Joyner 
257371d10453SEric Joyner 		status = ice_sched_move_vsi_to_agg(pi, vsi_handle,
257471d10453SEric Joyner 						   ICE_DFLT_AGG_ID, tc);
257571d10453SEric Joyner 		if (status)
257671d10453SEric Joyner 			break;
257771d10453SEric Joyner 
257871d10453SEric Joyner 		ice_clear_bit(tc, agg_vsi_info->tc_bitmap);
257971d10453SEric Joyner 		if (rm_vsi_info && !agg_vsi_info->tc_bitmap[0]) {
258071d10453SEric Joyner 			LIST_DEL(&agg_vsi_info->list_entry);
258171d10453SEric Joyner 			ice_free(pi->hw, agg_vsi_info);
258271d10453SEric Joyner 		}
258371d10453SEric Joyner 	}
258471d10453SEric Joyner 
258571d10453SEric Joyner 	return status;
258671d10453SEric Joyner }
258771d10453SEric Joyner 
258871d10453SEric Joyner /**
258971d10453SEric Joyner  * ice_sched_is_agg_inuse - check whether the aggregator is in use or not
259071d10453SEric Joyner  * @pi: port information structure
259171d10453SEric Joyner  * @node: node pointer
259271d10453SEric Joyner  *
259371d10453SEric Joyner  * This function checks whether the aggregator is attached with any VSI or not.
259471d10453SEric Joyner  */
259571d10453SEric Joyner static bool
259671d10453SEric Joyner ice_sched_is_agg_inuse(struct ice_port_info *pi, struct ice_sched_node *node)
259771d10453SEric Joyner {
259871d10453SEric Joyner 	u8 vsil, i;
259971d10453SEric Joyner 
260071d10453SEric Joyner 	vsil = ice_sched_get_vsi_layer(pi->hw);
260171d10453SEric Joyner 	if (node->tx_sched_layer < vsil - 1) {
260271d10453SEric Joyner 		for (i = 0; i < node->num_children; i++)
260371d10453SEric Joyner 			if (ice_sched_is_agg_inuse(pi, node->children[i]))
260471d10453SEric Joyner 				return true;
260571d10453SEric Joyner 		return false;
260671d10453SEric Joyner 	} else {
260771d10453SEric Joyner 		return node->num_children ? true : false;
260871d10453SEric Joyner 	}
260971d10453SEric Joyner }
261071d10453SEric Joyner 
261171d10453SEric Joyner /**
261271d10453SEric Joyner  * ice_sched_rm_agg_cfg - remove the aggregator node
261371d10453SEric Joyner  * @pi: port information structure
261471d10453SEric Joyner  * @agg_id: aggregator ID
261571d10453SEric Joyner  * @tc: TC number
261671d10453SEric Joyner  *
261771d10453SEric Joyner  * This function removes the aggregator node and intermediate nodes if any
261871d10453SEric Joyner  * from the given TC
261971d10453SEric Joyner  */
2620*f2635e84SEric Joyner static int
262171d10453SEric Joyner ice_sched_rm_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc)
262271d10453SEric Joyner {
262371d10453SEric Joyner 	struct ice_sched_node *tc_node, *agg_node;
262471d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
262571d10453SEric Joyner 
262671d10453SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
262771d10453SEric Joyner 	if (!tc_node)
262871d10453SEric Joyner 		return ICE_ERR_CFG;
262971d10453SEric Joyner 
263071d10453SEric Joyner 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
263171d10453SEric Joyner 	if (!agg_node)
263271d10453SEric Joyner 		return ICE_ERR_DOES_NOT_EXIST;
263371d10453SEric Joyner 
263471d10453SEric Joyner 	/* Can't remove the aggregator node if it has children */
263571d10453SEric Joyner 	if (ice_sched_is_agg_inuse(pi, agg_node))
263671d10453SEric Joyner 		return ICE_ERR_IN_USE;
263771d10453SEric Joyner 
263871d10453SEric Joyner 	/* need to remove the whole subtree if aggregator node is the
263971d10453SEric Joyner 	 * only child.
264071d10453SEric Joyner 	 */
264171d10453SEric Joyner 	while (agg_node->tx_sched_layer > hw->sw_entry_point_layer) {
264271d10453SEric Joyner 		struct ice_sched_node *parent = agg_node->parent;
264371d10453SEric Joyner 
264471d10453SEric Joyner 		if (!parent)
264571d10453SEric Joyner 			return ICE_ERR_CFG;
264671d10453SEric Joyner 
264771d10453SEric Joyner 		if (parent->num_children > 1)
264871d10453SEric Joyner 			break;
264971d10453SEric Joyner 
265071d10453SEric Joyner 		agg_node = parent;
265171d10453SEric Joyner 	}
265271d10453SEric Joyner 
265371d10453SEric Joyner 	ice_free_sched_node(pi, agg_node);
2654*f2635e84SEric Joyner 	return 0;
265571d10453SEric Joyner }
265671d10453SEric Joyner 
265771d10453SEric Joyner /**
265871d10453SEric Joyner  * ice_rm_agg_cfg_tc - remove aggregator configuration for TC
265971d10453SEric Joyner  * @pi: port information structure
266071d10453SEric Joyner  * @agg_info: aggregator ID
266171d10453SEric Joyner  * @tc: TC number
266271d10453SEric Joyner  * @rm_vsi_info: bool value true or false
266371d10453SEric Joyner  *
266471d10453SEric Joyner  * This function removes aggregator reference to VSI of given TC. It removes
266571d10453SEric Joyner  * the aggregator configuration completely for requested TC. The caller needs
266671d10453SEric Joyner  * to hold the scheduler lock.
266771d10453SEric Joyner  */
2668*f2635e84SEric Joyner static int
266971d10453SEric Joyner ice_rm_agg_cfg_tc(struct ice_port_info *pi, struct ice_sched_agg_info *agg_info,
267071d10453SEric Joyner 		  u8 tc, bool rm_vsi_info)
267171d10453SEric Joyner {
2672*f2635e84SEric Joyner 	int status = 0;
267371d10453SEric Joyner 
267471d10453SEric Joyner 	/* If nothing to remove - return success */
267571d10453SEric Joyner 	if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
267671d10453SEric Joyner 		goto exit_rm_agg_cfg_tc;
267771d10453SEric Joyner 
267871d10453SEric Joyner 	status = ice_move_all_vsi_to_dflt_agg(pi, agg_info, tc, rm_vsi_info);
267971d10453SEric Joyner 	if (status)
268071d10453SEric Joyner 		goto exit_rm_agg_cfg_tc;
268171d10453SEric Joyner 
268271d10453SEric Joyner 	/* Delete aggregator node(s) */
268371d10453SEric Joyner 	status = ice_sched_rm_agg_cfg(pi, agg_info->agg_id, tc);
268471d10453SEric Joyner 	if (status)
268571d10453SEric Joyner 		goto exit_rm_agg_cfg_tc;
268671d10453SEric Joyner 
268771d10453SEric Joyner 	ice_clear_bit(tc, agg_info->tc_bitmap);
268871d10453SEric Joyner exit_rm_agg_cfg_tc:
268971d10453SEric Joyner 	return status;
269071d10453SEric Joyner }
269171d10453SEric Joyner 
269271d10453SEric Joyner /**
269371d10453SEric Joyner  * ice_save_agg_tc_bitmap - save aggregator TC bitmap
269471d10453SEric Joyner  * @pi: port information structure
269571d10453SEric Joyner  * @agg_id: aggregator ID
269671d10453SEric Joyner  * @tc_bitmap: 8 bits TC bitmap
269771d10453SEric Joyner  *
269871d10453SEric Joyner  * Save aggregator TC bitmap. This function needs to be called with scheduler
269971d10453SEric Joyner  * lock held.
270071d10453SEric Joyner  */
2701*f2635e84SEric Joyner static int
270271d10453SEric Joyner ice_save_agg_tc_bitmap(struct ice_port_info *pi, u32 agg_id,
270371d10453SEric Joyner 		       ice_bitmap_t *tc_bitmap)
270471d10453SEric Joyner {
270571d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
270671d10453SEric Joyner 
270771d10453SEric Joyner 	agg_info = ice_get_agg_info(pi->hw, agg_id);
270871d10453SEric Joyner 	if (!agg_info)
270971d10453SEric Joyner 		return ICE_ERR_PARAM;
271071d10453SEric Joyner 	ice_cp_bitmap(agg_info->replay_tc_bitmap, tc_bitmap,
271171d10453SEric Joyner 		      ICE_MAX_TRAFFIC_CLASS);
2712*f2635e84SEric Joyner 	return 0;
271371d10453SEric Joyner }
271471d10453SEric Joyner 
271571d10453SEric Joyner /**
271671d10453SEric Joyner  * ice_sched_add_agg_cfg - create an aggregator node
271771d10453SEric Joyner  * @pi: port information structure
271871d10453SEric Joyner  * @agg_id: aggregator ID
271971d10453SEric Joyner  * @tc: TC number
272071d10453SEric Joyner  *
272171d10453SEric Joyner  * This function creates an aggregator node and intermediate nodes if required
272271d10453SEric Joyner  * for the given TC
272371d10453SEric Joyner  */
2724*f2635e84SEric Joyner static int
272571d10453SEric Joyner ice_sched_add_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc)
272671d10453SEric Joyner {
272771d10453SEric Joyner 	struct ice_sched_node *parent, *agg_node, *tc_node;
272871d10453SEric Joyner 	u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
272971d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
273071d10453SEric Joyner 	u32 first_node_teid;
273171d10453SEric Joyner 	u16 num_nodes_added;
2732*f2635e84SEric Joyner 	int status = 0;
273371d10453SEric Joyner 	u8 i, aggl;
273471d10453SEric Joyner 
273571d10453SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
273671d10453SEric Joyner 	if (!tc_node)
273771d10453SEric Joyner 		return ICE_ERR_CFG;
273871d10453SEric Joyner 
273971d10453SEric Joyner 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
274071d10453SEric Joyner 	/* Does Agg node already exist ? */
274171d10453SEric Joyner 	if (agg_node)
274271d10453SEric Joyner 		return status;
274371d10453SEric Joyner 
274471d10453SEric Joyner 	aggl = ice_sched_get_agg_layer(hw);
274571d10453SEric Joyner 
274671d10453SEric Joyner 	/* need one node in Agg layer */
274771d10453SEric Joyner 	num_nodes[aggl] = 1;
274871d10453SEric Joyner 
274971d10453SEric Joyner 	/* Check whether the intermediate nodes have space to add the
275071d10453SEric Joyner 	 * new aggregator. If they are full, then SW needs to allocate a new
275171d10453SEric Joyner 	 * intermediate node on those layers
275271d10453SEric Joyner 	 */
275371d10453SEric Joyner 	for (i = hw->sw_entry_point_layer; i < aggl; i++) {
275471d10453SEric Joyner 		parent = ice_sched_get_first_node(pi, tc_node, i);
275571d10453SEric Joyner 
275671d10453SEric Joyner 		/* scan all the siblings */
275771d10453SEric Joyner 		while (parent) {
275871d10453SEric Joyner 			if (parent->num_children < hw->max_children[i])
275971d10453SEric Joyner 				break;
276071d10453SEric Joyner 			parent = parent->sibling;
276171d10453SEric Joyner 		}
276271d10453SEric Joyner 
276371d10453SEric Joyner 		/* all the nodes are full, reserve one for this layer */
276471d10453SEric Joyner 		if (!parent)
276571d10453SEric Joyner 			num_nodes[i]++;
276671d10453SEric Joyner 	}
276771d10453SEric Joyner 
276871d10453SEric Joyner 	/* add the aggregator node */
276971d10453SEric Joyner 	parent = tc_node;
277071d10453SEric Joyner 	for (i = hw->sw_entry_point_layer; i <= aggl; i++) {
277171d10453SEric Joyner 		if (!parent)
277271d10453SEric Joyner 			return ICE_ERR_CFG;
277371d10453SEric Joyner 
277471d10453SEric Joyner 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
277571d10453SEric Joyner 						      num_nodes[i],
277671d10453SEric Joyner 						      &first_node_teid,
277771d10453SEric Joyner 						      &num_nodes_added);
2778*f2635e84SEric Joyner 		if (status || num_nodes[i] != num_nodes_added)
277971d10453SEric Joyner 			return ICE_ERR_CFG;
278071d10453SEric Joyner 
278171d10453SEric Joyner 		/* The newly added node can be a new parent for the next
278271d10453SEric Joyner 		 * layer nodes
278371d10453SEric Joyner 		 */
278471d10453SEric Joyner 		if (num_nodes_added) {
278571d10453SEric Joyner 			parent = ice_sched_find_node_by_teid(tc_node,
278671d10453SEric Joyner 							     first_node_teid);
278771d10453SEric Joyner 			/* register aggregator ID with the aggregator node */
278871d10453SEric Joyner 			if (parent && i == aggl)
278971d10453SEric Joyner 				parent->agg_id = agg_id;
279071d10453SEric Joyner 		} else {
279171d10453SEric Joyner 			parent = parent->children[0];
279271d10453SEric Joyner 		}
279371d10453SEric Joyner 	}
279471d10453SEric Joyner 
2795*f2635e84SEric Joyner 	return 0;
279671d10453SEric Joyner }
279771d10453SEric Joyner 
279871d10453SEric Joyner /**
279971d10453SEric Joyner  * ice_sched_cfg_agg - configure aggregator node
280071d10453SEric Joyner  * @pi: port information structure
280171d10453SEric Joyner  * @agg_id: aggregator ID
280271d10453SEric Joyner  * @agg_type: aggregator type queue, VSI, or aggregator group
280371d10453SEric Joyner  * @tc_bitmap: bits TC bitmap
280471d10453SEric Joyner  *
280571d10453SEric Joyner  * It registers a unique aggregator node into scheduler services. It
280671d10453SEric Joyner  * allows a user to register with a unique ID to track it's resources.
280771d10453SEric Joyner  * The aggregator type determines if this is a queue group, VSI group
280871d10453SEric Joyner  * or aggregator group. It then creates the aggregator node(s) for requested
280971d10453SEric Joyner  * TC(s) or removes an existing aggregator node including its configuration
281071d10453SEric Joyner  * if indicated via tc_bitmap. Call ice_rm_agg_cfg to release aggregator
281171d10453SEric Joyner  * resources and remove aggregator ID.
281271d10453SEric Joyner  * This function needs to be called with scheduler lock held.
281371d10453SEric Joyner  */
2814*f2635e84SEric Joyner static int
281571d10453SEric Joyner ice_sched_cfg_agg(struct ice_port_info *pi, u32 agg_id,
281671d10453SEric Joyner 		  enum ice_agg_type agg_type, ice_bitmap_t *tc_bitmap)
281771d10453SEric Joyner {
281871d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
281971d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
2820*f2635e84SEric Joyner 	int status = 0;
282171d10453SEric Joyner 	u8 tc;
282271d10453SEric Joyner 
282371d10453SEric Joyner 	agg_info = ice_get_agg_info(hw, agg_id);
282471d10453SEric Joyner 	if (!agg_info) {
282571d10453SEric Joyner 		/* Create new entry for new aggregator ID */
282671d10453SEric Joyner 		agg_info = (struct ice_sched_agg_info *)
282771d10453SEric Joyner 			ice_malloc(hw, sizeof(*agg_info));
2828d08b8680SEric Joyner 		if (!agg_info)
2829d08b8680SEric Joyner 			return ICE_ERR_NO_MEMORY;
2830d08b8680SEric Joyner 
283171d10453SEric Joyner 		agg_info->agg_id = agg_id;
283271d10453SEric Joyner 		agg_info->agg_type = agg_type;
283371d10453SEric Joyner 		agg_info->tc_bitmap[0] = 0;
283471d10453SEric Joyner 
283571d10453SEric Joyner 		/* Initialize the aggregator VSI list head */
283671d10453SEric Joyner 		INIT_LIST_HEAD(&agg_info->agg_vsi_list);
283771d10453SEric Joyner 
283871d10453SEric Joyner 		/* Add new entry in aggregator list */
283971d10453SEric Joyner 		LIST_ADD(&agg_info->list_entry, &hw->agg_list);
284071d10453SEric Joyner 	}
284171d10453SEric Joyner 	/* Create aggregator node(s) for requested TC(s) */
284271d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
284371d10453SEric Joyner 		if (!ice_is_tc_ena(*tc_bitmap, tc)) {
284471d10453SEric Joyner 			/* Delete aggregator cfg TC if it exists previously */
284571d10453SEric Joyner 			status = ice_rm_agg_cfg_tc(pi, agg_info, tc, false);
284671d10453SEric Joyner 			if (status)
284771d10453SEric Joyner 				break;
284871d10453SEric Joyner 			continue;
284971d10453SEric Joyner 		}
285071d10453SEric Joyner 
285171d10453SEric Joyner 		/* Check if aggregator node for TC already exists */
285271d10453SEric Joyner 		if (ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
285371d10453SEric Joyner 			continue;
285471d10453SEric Joyner 
285571d10453SEric Joyner 		/* Create new aggregator node for TC */
285671d10453SEric Joyner 		status = ice_sched_add_agg_cfg(pi, agg_id, tc);
285771d10453SEric Joyner 		if (status)
285871d10453SEric Joyner 			break;
285971d10453SEric Joyner 
286071d10453SEric Joyner 		/* Save aggregator node's TC information */
286171d10453SEric Joyner 		ice_set_bit(tc, agg_info->tc_bitmap);
286271d10453SEric Joyner 	}
2863d08b8680SEric Joyner 
286471d10453SEric Joyner 	return status;
286571d10453SEric Joyner }
286671d10453SEric Joyner 
286771d10453SEric Joyner /**
286871d10453SEric Joyner  * ice_cfg_agg - config aggregator node
286971d10453SEric Joyner  * @pi: port information structure
287071d10453SEric Joyner  * @agg_id: aggregator ID
287171d10453SEric Joyner  * @agg_type: aggregator type queue, VSI, or aggregator group
287271d10453SEric Joyner  * @tc_bitmap: bits TC bitmap
287371d10453SEric Joyner  *
287471d10453SEric Joyner  * This function configures aggregator node(s).
287571d10453SEric Joyner  */
2876*f2635e84SEric Joyner int
287771d10453SEric Joyner ice_cfg_agg(struct ice_port_info *pi, u32 agg_id, enum ice_agg_type agg_type,
287871d10453SEric Joyner 	    u8 tc_bitmap)
287971d10453SEric Joyner {
288071d10453SEric Joyner 	ice_bitmap_t bitmap = tc_bitmap;
2881*f2635e84SEric Joyner 	int status;
288271d10453SEric Joyner 
288371d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
288471d10453SEric Joyner 	status = ice_sched_cfg_agg(pi, agg_id, agg_type,
288571d10453SEric Joyner 				   (ice_bitmap_t *)&bitmap);
288671d10453SEric Joyner 	if (!status)
288771d10453SEric Joyner 		status = ice_save_agg_tc_bitmap(pi, agg_id,
288871d10453SEric Joyner 						(ice_bitmap_t *)&bitmap);
288971d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
289071d10453SEric Joyner 	return status;
289171d10453SEric Joyner }
289271d10453SEric Joyner 
289371d10453SEric Joyner /**
289471d10453SEric Joyner  * ice_get_agg_vsi_info - get the aggregator ID
289571d10453SEric Joyner  * @agg_info: aggregator info
289671d10453SEric Joyner  * @vsi_handle: software VSI handle
289771d10453SEric Joyner  *
289871d10453SEric Joyner  * The function returns aggregator VSI info based on VSI handle. This function
289971d10453SEric Joyner  * needs to be called with scheduler lock held.
290071d10453SEric Joyner  */
290171d10453SEric Joyner static struct ice_sched_agg_vsi_info *
290271d10453SEric Joyner ice_get_agg_vsi_info(struct ice_sched_agg_info *agg_info, u16 vsi_handle)
290371d10453SEric Joyner {
290471d10453SEric Joyner 	struct ice_sched_agg_vsi_info *agg_vsi_info;
290571d10453SEric Joyner 
290671d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(agg_vsi_info, &agg_info->agg_vsi_list,
290771d10453SEric Joyner 			    ice_sched_agg_vsi_info, list_entry)
290871d10453SEric Joyner 		if (agg_vsi_info->vsi_handle == vsi_handle)
290971d10453SEric Joyner 			return agg_vsi_info;
291071d10453SEric Joyner 
291171d10453SEric Joyner 	return NULL;
291271d10453SEric Joyner }
291371d10453SEric Joyner 
291471d10453SEric Joyner /**
291571d10453SEric Joyner  * ice_get_vsi_agg_info - get the aggregator info of VSI
291671d10453SEric Joyner  * @hw: pointer to the hardware structure
291771d10453SEric Joyner  * @vsi_handle: Sw VSI handle
291871d10453SEric Joyner  *
291971d10453SEric Joyner  * The function returns aggregator info of VSI represented via vsi_handle. The
292071d10453SEric Joyner  * VSI has in this case a different aggregator than the default one. This
292171d10453SEric Joyner  * function needs to be called with scheduler lock held.
292271d10453SEric Joyner  */
292371d10453SEric Joyner static struct ice_sched_agg_info *
292471d10453SEric Joyner ice_get_vsi_agg_info(struct ice_hw *hw, u16 vsi_handle)
292571d10453SEric Joyner {
292671d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
292771d10453SEric Joyner 
292871d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
292971d10453SEric Joyner 			    list_entry) {
293071d10453SEric Joyner 		struct ice_sched_agg_vsi_info *agg_vsi_info;
293171d10453SEric Joyner 
293271d10453SEric Joyner 		agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
293371d10453SEric Joyner 		if (agg_vsi_info)
293471d10453SEric Joyner 			return agg_info;
293571d10453SEric Joyner 	}
293671d10453SEric Joyner 	return NULL;
293771d10453SEric Joyner }
293871d10453SEric Joyner 
293971d10453SEric Joyner /**
294071d10453SEric Joyner  * ice_save_agg_vsi_tc_bitmap - save aggregator VSI TC bitmap
294171d10453SEric Joyner  * @pi: port information structure
294271d10453SEric Joyner  * @agg_id: aggregator ID
294371d10453SEric Joyner  * @vsi_handle: software VSI handle
294471d10453SEric Joyner  * @tc_bitmap: TC bitmap of enabled TC(s)
294571d10453SEric Joyner  *
294671d10453SEric Joyner  * Save VSI to aggregator TC bitmap. This function needs to call with scheduler
294771d10453SEric Joyner  * lock held.
294871d10453SEric Joyner  */
2949*f2635e84SEric Joyner static int
295071d10453SEric Joyner ice_save_agg_vsi_tc_bitmap(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle,
295171d10453SEric Joyner 			   ice_bitmap_t *tc_bitmap)
295271d10453SEric Joyner {
295371d10453SEric Joyner 	struct ice_sched_agg_vsi_info *agg_vsi_info;
295471d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
295571d10453SEric Joyner 
295671d10453SEric Joyner 	agg_info = ice_get_agg_info(pi->hw, agg_id);
295771d10453SEric Joyner 	if (!agg_info)
295871d10453SEric Joyner 		return ICE_ERR_PARAM;
295971d10453SEric Joyner 	/* check if entry already exist */
296071d10453SEric Joyner 	agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
296171d10453SEric Joyner 	if (!agg_vsi_info)
296271d10453SEric Joyner 		return ICE_ERR_PARAM;
296371d10453SEric Joyner 	ice_cp_bitmap(agg_vsi_info->replay_tc_bitmap, tc_bitmap,
296471d10453SEric Joyner 		      ICE_MAX_TRAFFIC_CLASS);
2965*f2635e84SEric Joyner 	return 0;
296671d10453SEric Joyner }
296771d10453SEric Joyner 
296871d10453SEric Joyner /**
296971d10453SEric Joyner  * ice_sched_assoc_vsi_to_agg - associate/move VSI to new/default aggregator
297071d10453SEric Joyner  * @pi: port information structure
297171d10453SEric Joyner  * @agg_id: aggregator ID
297271d10453SEric Joyner  * @vsi_handle: software VSI handle
297371d10453SEric Joyner  * @tc_bitmap: TC bitmap of enabled TC(s)
297471d10453SEric Joyner  *
297571d10453SEric Joyner  * This function moves VSI to a new or default aggregator node. If VSI is
297671d10453SEric Joyner  * already associated to the aggregator node then no operation is performed on
297771d10453SEric Joyner  * the tree. This function needs to be called with scheduler lock held.
297871d10453SEric Joyner  */
2979*f2635e84SEric Joyner static int
298071d10453SEric Joyner ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
298171d10453SEric Joyner 			   u16 vsi_handle, ice_bitmap_t *tc_bitmap)
298271d10453SEric Joyner {
298356429daeSEric Joyner 	struct ice_sched_agg_vsi_info *agg_vsi_info, *old_agg_vsi_info = NULL;
298456429daeSEric Joyner 	struct ice_sched_agg_info *agg_info, *old_agg_info;
298571d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
2986*f2635e84SEric Joyner 	int status = 0;
298771d10453SEric Joyner 	u8 tc;
298871d10453SEric Joyner 
298971d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
299071d10453SEric Joyner 		return ICE_ERR_PARAM;
299171d10453SEric Joyner 	agg_info = ice_get_agg_info(hw, agg_id);
299271d10453SEric Joyner 	if (!agg_info)
299371d10453SEric Joyner 		return ICE_ERR_PARAM;
299456429daeSEric Joyner 	/* If the vsi is already part of another aggregator then update
299556429daeSEric Joyner 	 * its vsi info list
299656429daeSEric Joyner 	 */
299756429daeSEric Joyner 	old_agg_info = ice_get_vsi_agg_info(hw, vsi_handle);
299856429daeSEric Joyner 	if (old_agg_info && old_agg_info != agg_info) {
299956429daeSEric Joyner 		struct ice_sched_agg_vsi_info *vtmp;
300056429daeSEric Joyner 
300156429daeSEric Joyner 		LIST_FOR_EACH_ENTRY_SAFE(old_agg_vsi_info, vtmp,
300256429daeSEric Joyner 					 &old_agg_info->agg_vsi_list,
300356429daeSEric Joyner 					 ice_sched_agg_vsi_info, list_entry)
300456429daeSEric Joyner 			if (old_agg_vsi_info->vsi_handle == vsi_handle)
300556429daeSEric Joyner 				break;
300656429daeSEric Joyner 	}
300756429daeSEric Joyner 
300871d10453SEric Joyner 	/* check if entry already exist */
300971d10453SEric Joyner 	agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
301071d10453SEric Joyner 	if (!agg_vsi_info) {
301171d10453SEric Joyner 		/* Create new entry for VSI under aggregator list */
301271d10453SEric Joyner 		agg_vsi_info = (struct ice_sched_agg_vsi_info *)
301371d10453SEric Joyner 			ice_malloc(hw, sizeof(*agg_vsi_info));
301471d10453SEric Joyner 		if (!agg_vsi_info)
301571d10453SEric Joyner 			return ICE_ERR_PARAM;
301671d10453SEric Joyner 
301771d10453SEric Joyner 		/* add VSI ID into the aggregator list */
301871d10453SEric Joyner 		agg_vsi_info->vsi_handle = vsi_handle;
301971d10453SEric Joyner 		LIST_ADD(&agg_vsi_info->list_entry, &agg_info->agg_vsi_list);
302071d10453SEric Joyner 	}
302171d10453SEric Joyner 	/* Move VSI node to new aggregator node for requested TC(s) */
302271d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
302371d10453SEric Joyner 		if (!ice_is_tc_ena(*tc_bitmap, tc))
302471d10453SEric Joyner 			continue;
302571d10453SEric Joyner 
302671d10453SEric Joyner 		/* Move VSI to new aggregator */
302771d10453SEric Joyner 		status = ice_sched_move_vsi_to_agg(pi, vsi_handle, agg_id, tc);
302871d10453SEric Joyner 		if (status)
302971d10453SEric Joyner 			break;
303071d10453SEric Joyner 
303171d10453SEric Joyner 		ice_set_bit(tc, agg_vsi_info->tc_bitmap);
303256429daeSEric Joyner 		if (old_agg_vsi_info)
303356429daeSEric Joyner 			ice_clear_bit(tc, old_agg_vsi_info->tc_bitmap);
303456429daeSEric Joyner 	}
303556429daeSEric Joyner 	if (old_agg_vsi_info && !old_agg_vsi_info->tc_bitmap[0]) {
303656429daeSEric Joyner 		LIST_DEL(&old_agg_vsi_info->list_entry);
303756429daeSEric Joyner 		ice_free(pi->hw, old_agg_vsi_info);
303871d10453SEric Joyner 	}
303971d10453SEric Joyner 	return status;
304071d10453SEric Joyner }
304171d10453SEric Joyner 
304271d10453SEric Joyner /**
304371d10453SEric Joyner  * ice_sched_rm_unused_rl_prof - remove unused RL profile
3044d08b8680SEric Joyner  * @hw: pointer to the hardware structure
304571d10453SEric Joyner  *
304671d10453SEric Joyner  * This function removes unused rate limit profiles from the HW and
304771d10453SEric Joyner  * SW DB. The caller needs to hold scheduler lock.
304871d10453SEric Joyner  */
3049d08b8680SEric Joyner static void ice_sched_rm_unused_rl_prof(struct ice_hw *hw)
305071d10453SEric Joyner {
305171d10453SEric Joyner 	u16 ln;
305271d10453SEric Joyner 
3053d08b8680SEric Joyner 	for (ln = 0; ln < hw->num_tx_sched_layers; ln++) {
305471d10453SEric Joyner 		struct ice_aqc_rl_profile_info *rl_prof_elem;
305571d10453SEric Joyner 		struct ice_aqc_rl_profile_info *rl_prof_tmp;
305671d10453SEric Joyner 
305771d10453SEric Joyner 		LIST_FOR_EACH_ENTRY_SAFE(rl_prof_elem, rl_prof_tmp,
3058d08b8680SEric Joyner 					 &hw->rl_prof_list[ln],
305971d10453SEric Joyner 					 ice_aqc_rl_profile_info, list_entry) {
3060d08b8680SEric Joyner 			if (!ice_sched_del_rl_profile(hw, rl_prof_elem))
3061d08b8680SEric Joyner 				ice_debug(hw, ICE_DBG_SCHED, "Removed rl profile\n");
306271d10453SEric Joyner 		}
306371d10453SEric Joyner 	}
306471d10453SEric Joyner }
306571d10453SEric Joyner 
306671d10453SEric Joyner /**
306771d10453SEric Joyner  * ice_sched_update_elem - update element
306871d10453SEric Joyner  * @hw: pointer to the HW struct
306971d10453SEric Joyner  * @node: pointer to node
307071d10453SEric Joyner  * @info: node info to update
307171d10453SEric Joyner  *
30727d7af7f8SEric Joyner  * Update the HW DB, and local SW DB of node. Update the scheduling
307371d10453SEric Joyner  * parameters of node from argument info data buffer (Info->data buf) and
307471d10453SEric Joyner  * returns success or error on config sched element failure. The caller
307571d10453SEric Joyner  * needs to hold scheduler lock.
307671d10453SEric Joyner  */
3077*f2635e84SEric Joyner static int
307871d10453SEric Joyner ice_sched_update_elem(struct ice_hw *hw, struct ice_sched_node *node,
307971d10453SEric Joyner 		      struct ice_aqc_txsched_elem_data *info)
308071d10453SEric Joyner {
30817d7af7f8SEric Joyner 	struct ice_aqc_txsched_elem_data buf;
308271d10453SEric Joyner 	u16 elem_cfgd = 0;
308371d10453SEric Joyner 	u16 num_elems = 1;
3084*f2635e84SEric Joyner 	int status;
308571d10453SEric Joyner 
30867d7af7f8SEric Joyner 	buf = *info;
308756429daeSEric Joyner 	/* For TC nodes, CIR config is not supported */
308856429daeSEric Joyner 	if (node->info.data.elem_type == ICE_AQC_ELEM_TYPE_TC)
308956429daeSEric Joyner 		buf.data.valid_sections &= ~ICE_AQC_ELEM_VALID_CIR;
309071d10453SEric Joyner 	/* Parent TEID is reserved field in this aq call */
30917d7af7f8SEric Joyner 	buf.parent_teid = 0;
309271d10453SEric Joyner 	/* Element type is reserved field in this aq call */
30937d7af7f8SEric Joyner 	buf.data.elem_type = 0;
309471d10453SEric Joyner 	/* Flags is reserved field in this aq call */
30957d7af7f8SEric Joyner 	buf.data.flags = 0;
309671d10453SEric Joyner 
309771d10453SEric Joyner 	/* Update HW DB */
309871d10453SEric Joyner 	/* Configure element node */
309971d10453SEric Joyner 	status = ice_aq_cfg_sched_elems(hw, num_elems, &buf, sizeof(buf),
310071d10453SEric Joyner 					&elem_cfgd, NULL);
310171d10453SEric Joyner 	if (status || elem_cfgd != num_elems) {
310271d10453SEric Joyner 		ice_debug(hw, ICE_DBG_SCHED, "Config sched elem error\n");
310371d10453SEric Joyner 		return ICE_ERR_CFG;
310471d10453SEric Joyner 	}
310571d10453SEric Joyner 
310671d10453SEric Joyner 	/* Config success case */
310771d10453SEric Joyner 	/* Now update local SW DB */
310871d10453SEric Joyner 	/* Only copy the data portion of info buffer */
310971d10453SEric Joyner 	node->info.data = info->data;
311071d10453SEric Joyner 	return status;
311171d10453SEric Joyner }
311271d10453SEric Joyner 
311371d10453SEric Joyner /**
311471d10453SEric Joyner  * ice_sched_cfg_node_bw_alloc - configure node BW weight/alloc params
311571d10453SEric Joyner  * @hw: pointer to the HW struct
311671d10453SEric Joyner  * @node: sched node to configure
311771d10453SEric Joyner  * @rl_type: rate limit type CIR, EIR, or shared
311871d10453SEric Joyner  * @bw_alloc: BW weight/allocation
311971d10453SEric Joyner  *
312071d10453SEric Joyner  * This function configures node element's BW allocation.
312171d10453SEric Joyner  */
3122*f2635e84SEric Joyner static int
312371d10453SEric Joyner ice_sched_cfg_node_bw_alloc(struct ice_hw *hw, struct ice_sched_node *node,
312471d10453SEric Joyner 			    enum ice_rl_type rl_type, u16 bw_alloc)
312571d10453SEric Joyner {
312671d10453SEric Joyner 	struct ice_aqc_txsched_elem_data buf;
312771d10453SEric Joyner 	struct ice_aqc_txsched_elem *data;
3128*f2635e84SEric Joyner 	int status;
312971d10453SEric Joyner 
313071d10453SEric Joyner 	buf = node->info;
313171d10453SEric Joyner 	data = &buf.data;
313271d10453SEric Joyner 	if (rl_type == ICE_MIN_BW) {
313371d10453SEric Joyner 		data->valid_sections |= ICE_AQC_ELEM_VALID_CIR;
313471d10453SEric Joyner 		data->cir_bw.bw_alloc = CPU_TO_LE16(bw_alloc);
313571d10453SEric Joyner 	} else if (rl_type == ICE_MAX_BW) {
313671d10453SEric Joyner 		data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
313771d10453SEric Joyner 		data->eir_bw.bw_alloc = CPU_TO_LE16(bw_alloc);
313871d10453SEric Joyner 	} else {
313971d10453SEric Joyner 		return ICE_ERR_PARAM;
314071d10453SEric Joyner 	}
314171d10453SEric Joyner 
314271d10453SEric Joyner 	/* Configure element */
314371d10453SEric Joyner 	status = ice_sched_update_elem(hw, node, &buf);
314471d10453SEric Joyner 	return status;
314571d10453SEric Joyner }
314671d10453SEric Joyner 
314771d10453SEric Joyner /**
314871d10453SEric Joyner  * ice_move_vsi_to_agg - moves VSI to new or default aggregator
314971d10453SEric Joyner  * @pi: port information structure
315071d10453SEric Joyner  * @agg_id: aggregator ID
315171d10453SEric Joyner  * @vsi_handle: software VSI handle
315271d10453SEric Joyner  * @tc_bitmap: TC bitmap of enabled TC(s)
315371d10453SEric Joyner  *
315471d10453SEric Joyner  * Move or associate VSI to a new or default aggregator node.
315571d10453SEric Joyner  */
3156*f2635e84SEric Joyner int
315771d10453SEric Joyner ice_move_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle,
315871d10453SEric Joyner 		    u8 tc_bitmap)
315971d10453SEric Joyner {
316071d10453SEric Joyner 	ice_bitmap_t bitmap = tc_bitmap;
3161*f2635e84SEric Joyner 	int status;
316271d10453SEric Joyner 
316371d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
316471d10453SEric Joyner 	status = ice_sched_assoc_vsi_to_agg(pi, agg_id, vsi_handle,
316571d10453SEric Joyner 					    (ice_bitmap_t *)&bitmap);
316671d10453SEric Joyner 	if (!status)
316771d10453SEric Joyner 		status = ice_save_agg_vsi_tc_bitmap(pi, agg_id, vsi_handle,
316871d10453SEric Joyner 						    (ice_bitmap_t *)&bitmap);
316971d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
317071d10453SEric Joyner 	return status;
317171d10453SEric Joyner }
317271d10453SEric Joyner 
317371d10453SEric Joyner /**
317471d10453SEric Joyner  * ice_rm_agg_cfg - remove aggregator configuration
317571d10453SEric Joyner  * @pi: port information structure
317671d10453SEric Joyner  * @agg_id: aggregator ID
317771d10453SEric Joyner  *
317871d10453SEric Joyner  * This function removes aggregator reference to VSI and delete aggregator ID
317971d10453SEric Joyner  * info. It removes the aggregator configuration completely.
318071d10453SEric Joyner  */
3181*f2635e84SEric Joyner int ice_rm_agg_cfg(struct ice_port_info *pi, u32 agg_id)
318271d10453SEric Joyner {
318371d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
3184*f2635e84SEric Joyner 	int status = 0;
318571d10453SEric Joyner 	u8 tc;
318671d10453SEric Joyner 
318771d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
318871d10453SEric Joyner 	agg_info = ice_get_agg_info(pi->hw, agg_id);
318971d10453SEric Joyner 	if (!agg_info) {
319071d10453SEric Joyner 		status = ICE_ERR_DOES_NOT_EXIST;
319171d10453SEric Joyner 		goto exit_ice_rm_agg_cfg;
319271d10453SEric Joyner 	}
319371d10453SEric Joyner 
319471d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
319571d10453SEric Joyner 		status = ice_rm_agg_cfg_tc(pi, agg_info, tc, true);
319671d10453SEric Joyner 		if (status)
319771d10453SEric Joyner 			goto exit_ice_rm_agg_cfg;
319871d10453SEric Joyner 	}
319971d10453SEric Joyner 
320071d10453SEric Joyner 	if (ice_is_any_bit_set(agg_info->tc_bitmap, ICE_MAX_TRAFFIC_CLASS)) {
320171d10453SEric Joyner 		status = ICE_ERR_IN_USE;
320271d10453SEric Joyner 		goto exit_ice_rm_agg_cfg;
320371d10453SEric Joyner 	}
320471d10453SEric Joyner 
320571d10453SEric Joyner 	/* Safe to delete entry now */
320671d10453SEric Joyner 	LIST_DEL(&agg_info->list_entry);
320771d10453SEric Joyner 	ice_free(pi->hw, agg_info);
320871d10453SEric Joyner 
320971d10453SEric Joyner 	/* Remove unused RL profile IDs from HW and SW DB */
3210d08b8680SEric Joyner 	ice_sched_rm_unused_rl_prof(pi->hw);
321171d10453SEric Joyner 
321271d10453SEric Joyner exit_ice_rm_agg_cfg:
321371d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
321471d10453SEric Joyner 	return status;
321571d10453SEric Joyner }
321671d10453SEric Joyner 
321771d10453SEric Joyner /**
321871d10453SEric Joyner  * ice_set_clear_cir_bw_alloc - set or clear CIR BW alloc information
321971d10453SEric Joyner  * @bw_t_info: bandwidth type information structure
322071d10453SEric Joyner  * @bw_alloc: Bandwidth allocation information
322171d10453SEric Joyner  *
322271d10453SEric Joyner  * Save or clear CIR BW alloc information (bw_alloc) in the passed param
322371d10453SEric Joyner  * bw_t_info.
322471d10453SEric Joyner  */
322571d10453SEric Joyner static void
322671d10453SEric Joyner ice_set_clear_cir_bw_alloc(struct ice_bw_type_info *bw_t_info, u16 bw_alloc)
322771d10453SEric Joyner {
322871d10453SEric Joyner 	bw_t_info->cir_bw.bw_alloc = bw_alloc;
322971d10453SEric Joyner 	if (bw_t_info->cir_bw.bw_alloc)
323071d10453SEric Joyner 		ice_set_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap);
323171d10453SEric Joyner 	else
323271d10453SEric Joyner 		ice_clear_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap);
323371d10453SEric Joyner }
323471d10453SEric Joyner 
323571d10453SEric Joyner /**
323671d10453SEric Joyner  * ice_set_clear_eir_bw_alloc - set or clear EIR BW alloc information
323771d10453SEric Joyner  * @bw_t_info: bandwidth type information structure
323871d10453SEric Joyner  * @bw_alloc: Bandwidth allocation information
323971d10453SEric Joyner  *
324071d10453SEric Joyner  * Save or clear EIR BW alloc information (bw_alloc) in the passed param
324171d10453SEric Joyner  * bw_t_info.
324271d10453SEric Joyner  */
324371d10453SEric Joyner static void
324471d10453SEric Joyner ice_set_clear_eir_bw_alloc(struct ice_bw_type_info *bw_t_info, u16 bw_alloc)
324571d10453SEric Joyner {
324671d10453SEric Joyner 	bw_t_info->eir_bw.bw_alloc = bw_alloc;
324771d10453SEric Joyner 	if (bw_t_info->eir_bw.bw_alloc)
324871d10453SEric Joyner 		ice_set_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap);
324971d10453SEric Joyner 	else
325071d10453SEric Joyner 		ice_clear_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap);
325171d10453SEric Joyner }
325271d10453SEric Joyner 
325371d10453SEric Joyner /**
325471d10453SEric Joyner  * ice_sched_save_vsi_bw_alloc - save VSI node's BW alloc information
325571d10453SEric Joyner  * @pi: port information structure
325671d10453SEric Joyner  * @vsi_handle: sw VSI handle
325771d10453SEric Joyner  * @tc: traffic class
325871d10453SEric Joyner  * @rl_type: rate limit type min or max
325971d10453SEric Joyner  * @bw_alloc: Bandwidth allocation information
326071d10453SEric Joyner  *
326171d10453SEric Joyner  * Save BW alloc information of VSI type node for post replay use.
326271d10453SEric Joyner  */
3263*f2635e84SEric Joyner static int
326471d10453SEric Joyner ice_sched_save_vsi_bw_alloc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
326571d10453SEric Joyner 			    enum ice_rl_type rl_type, u16 bw_alloc)
326671d10453SEric Joyner {
326771d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
326871d10453SEric Joyner 
326971d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
327071d10453SEric Joyner 		return ICE_ERR_PARAM;
327171d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
327271d10453SEric Joyner 	if (!vsi_ctx)
327371d10453SEric Joyner 		return ICE_ERR_PARAM;
327471d10453SEric Joyner 	switch (rl_type) {
327571d10453SEric Joyner 	case ICE_MIN_BW:
327671d10453SEric Joyner 		ice_set_clear_cir_bw_alloc(&vsi_ctx->sched.bw_t_info[tc],
327771d10453SEric Joyner 					   bw_alloc);
327871d10453SEric Joyner 		break;
327971d10453SEric Joyner 	case ICE_MAX_BW:
328071d10453SEric Joyner 		ice_set_clear_eir_bw_alloc(&vsi_ctx->sched.bw_t_info[tc],
328171d10453SEric Joyner 					   bw_alloc);
328271d10453SEric Joyner 		break;
328371d10453SEric Joyner 	default:
328471d10453SEric Joyner 		return ICE_ERR_PARAM;
328571d10453SEric Joyner 	}
3286*f2635e84SEric Joyner 	return 0;
328771d10453SEric Joyner }
328871d10453SEric Joyner 
328971d10453SEric Joyner /**
329071d10453SEric Joyner  * ice_set_clear_cir_bw - set or clear CIR BW
329171d10453SEric Joyner  * @bw_t_info: bandwidth type information structure
329271d10453SEric Joyner  * @bw: bandwidth in Kbps - Kilo bits per sec
329371d10453SEric Joyner  *
329471d10453SEric Joyner  * Save or clear CIR bandwidth (BW) in the passed param bw_t_info.
329571d10453SEric Joyner  */
32967d7af7f8SEric Joyner static void ice_set_clear_cir_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
329771d10453SEric Joyner {
329871d10453SEric Joyner 	if (bw == ICE_SCHED_DFLT_BW) {
329971d10453SEric Joyner 		ice_clear_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap);
330071d10453SEric Joyner 		bw_t_info->cir_bw.bw = 0;
330171d10453SEric Joyner 	} else {
330271d10453SEric Joyner 		/* Save type of BW information */
330371d10453SEric Joyner 		ice_set_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap);
330471d10453SEric Joyner 		bw_t_info->cir_bw.bw = bw;
330571d10453SEric Joyner 	}
330671d10453SEric Joyner }
330771d10453SEric Joyner 
330871d10453SEric Joyner /**
330971d10453SEric Joyner  * ice_set_clear_eir_bw - set or clear EIR BW
331071d10453SEric Joyner  * @bw_t_info: bandwidth type information structure
331171d10453SEric Joyner  * @bw: bandwidth in Kbps - Kilo bits per sec
331271d10453SEric Joyner  *
331371d10453SEric Joyner  * Save or clear EIR bandwidth (BW) in the passed param bw_t_info.
331471d10453SEric Joyner  */
33157d7af7f8SEric Joyner static void ice_set_clear_eir_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
331671d10453SEric Joyner {
331771d10453SEric Joyner 	if (bw == ICE_SCHED_DFLT_BW) {
331871d10453SEric Joyner 		ice_clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
331971d10453SEric Joyner 		bw_t_info->eir_bw.bw = 0;
332071d10453SEric Joyner 	} else {
332171d10453SEric Joyner 		/* save EIR BW information */
332271d10453SEric Joyner 		ice_set_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
332371d10453SEric Joyner 		bw_t_info->eir_bw.bw = bw;
332471d10453SEric Joyner 	}
332571d10453SEric Joyner }
332671d10453SEric Joyner 
332771d10453SEric Joyner /**
332871d10453SEric Joyner  * ice_set_clear_shared_bw - set or clear shared BW
332971d10453SEric Joyner  * @bw_t_info: bandwidth type information structure
333071d10453SEric Joyner  * @bw: bandwidth in Kbps - Kilo bits per sec
333171d10453SEric Joyner  *
333271d10453SEric Joyner  * Save or clear shared bandwidth (BW) in the passed param bw_t_info.
333371d10453SEric Joyner  */
33347d7af7f8SEric Joyner static void ice_set_clear_shared_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
333571d10453SEric Joyner {
333671d10453SEric Joyner 	if (bw == ICE_SCHED_DFLT_BW) {
333771d10453SEric Joyner 		ice_clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
333871d10453SEric Joyner 		bw_t_info->shared_bw = 0;
333971d10453SEric Joyner 	} else {
334071d10453SEric Joyner 		/* save shared BW information */
334171d10453SEric Joyner 		ice_set_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
334271d10453SEric Joyner 		bw_t_info->shared_bw = bw;
334371d10453SEric Joyner 	}
334471d10453SEric Joyner }
334571d10453SEric Joyner 
334671d10453SEric Joyner /**
334771d10453SEric Joyner  * ice_sched_save_vsi_bw - save VSI node's BW information
334871d10453SEric Joyner  * @pi: port information structure
334971d10453SEric Joyner  * @vsi_handle: sw VSI handle
335071d10453SEric Joyner  * @tc: traffic class
335171d10453SEric Joyner  * @rl_type: rate limit type min, max, or shared
335271d10453SEric Joyner  * @bw: bandwidth in Kbps - Kilo bits per sec
335371d10453SEric Joyner  *
335471d10453SEric Joyner  * Save BW information of VSI type node for post replay use.
335571d10453SEric Joyner  */
3356*f2635e84SEric Joyner static int
335771d10453SEric Joyner ice_sched_save_vsi_bw(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
335871d10453SEric Joyner 		      enum ice_rl_type rl_type, u32 bw)
335971d10453SEric Joyner {
336071d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
336171d10453SEric Joyner 
336271d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
336371d10453SEric Joyner 		return ICE_ERR_PARAM;
336471d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
336571d10453SEric Joyner 	if (!vsi_ctx)
336671d10453SEric Joyner 		return ICE_ERR_PARAM;
336771d10453SEric Joyner 	switch (rl_type) {
336871d10453SEric Joyner 	case ICE_MIN_BW:
336971d10453SEric Joyner 		ice_set_clear_cir_bw(&vsi_ctx->sched.bw_t_info[tc], bw);
337071d10453SEric Joyner 		break;
337171d10453SEric Joyner 	case ICE_MAX_BW:
337271d10453SEric Joyner 		ice_set_clear_eir_bw(&vsi_ctx->sched.bw_t_info[tc], bw);
337371d10453SEric Joyner 		break;
337471d10453SEric Joyner 	case ICE_SHARED_BW:
337571d10453SEric Joyner 		ice_set_clear_shared_bw(&vsi_ctx->sched.bw_t_info[tc], bw);
337671d10453SEric Joyner 		break;
337771d10453SEric Joyner 	default:
337871d10453SEric Joyner 		return ICE_ERR_PARAM;
337971d10453SEric Joyner 	}
3380*f2635e84SEric Joyner 	return 0;
338171d10453SEric Joyner }
338271d10453SEric Joyner 
338371d10453SEric Joyner /**
338471d10453SEric Joyner  * ice_set_clear_prio - set or clear priority information
338571d10453SEric Joyner  * @bw_t_info: bandwidth type information structure
338671d10453SEric Joyner  * @prio: priority to save
338771d10453SEric Joyner  *
338871d10453SEric Joyner  * Save or clear priority (prio) in the passed param bw_t_info.
338971d10453SEric Joyner  */
33907d7af7f8SEric Joyner static void ice_set_clear_prio(struct ice_bw_type_info *bw_t_info, u8 prio)
339171d10453SEric Joyner {
339271d10453SEric Joyner 	bw_t_info->generic = prio;
339371d10453SEric Joyner 	if (bw_t_info->generic)
339471d10453SEric Joyner 		ice_set_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap);
339571d10453SEric Joyner 	else
339671d10453SEric Joyner 		ice_clear_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap);
339771d10453SEric Joyner }
339871d10453SEric Joyner 
339971d10453SEric Joyner /**
340071d10453SEric Joyner  * ice_sched_save_vsi_prio - save VSI node's priority information
340171d10453SEric Joyner  * @pi: port information structure
340271d10453SEric Joyner  * @vsi_handle: Software VSI handle
340371d10453SEric Joyner  * @tc: traffic class
340471d10453SEric Joyner  * @prio: priority to save
340571d10453SEric Joyner  *
340671d10453SEric Joyner  * Save priority information of VSI type node for post replay use.
340771d10453SEric Joyner  */
3408*f2635e84SEric Joyner static int
340971d10453SEric Joyner ice_sched_save_vsi_prio(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
341071d10453SEric Joyner 			u8 prio)
341171d10453SEric Joyner {
341271d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
341371d10453SEric Joyner 
341471d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
341571d10453SEric Joyner 		return ICE_ERR_PARAM;
341671d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
341771d10453SEric Joyner 	if (!vsi_ctx)
341871d10453SEric Joyner 		return ICE_ERR_PARAM;
341971d10453SEric Joyner 	if (tc >= ICE_MAX_TRAFFIC_CLASS)
342071d10453SEric Joyner 		return ICE_ERR_PARAM;
342171d10453SEric Joyner 	ice_set_clear_prio(&vsi_ctx->sched.bw_t_info[tc], prio);
3422*f2635e84SEric Joyner 	return 0;
342371d10453SEric Joyner }
342471d10453SEric Joyner 
342571d10453SEric Joyner /**
342671d10453SEric Joyner  * ice_sched_save_agg_bw_alloc - save aggregator node's BW alloc information
342771d10453SEric Joyner  * @pi: port information structure
342871d10453SEric Joyner  * @agg_id: node aggregator ID
342971d10453SEric Joyner  * @tc: traffic class
343071d10453SEric Joyner  * @rl_type: rate limit type min or max
343171d10453SEric Joyner  * @bw_alloc: bandwidth alloc information
343271d10453SEric Joyner  *
343371d10453SEric Joyner  * Save BW alloc information of AGG type node for post replay use.
343471d10453SEric Joyner  */
3435*f2635e84SEric Joyner static int
343671d10453SEric Joyner ice_sched_save_agg_bw_alloc(struct ice_port_info *pi, u32 agg_id, u8 tc,
343771d10453SEric Joyner 			    enum ice_rl_type rl_type, u16 bw_alloc)
343871d10453SEric Joyner {
343971d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
344071d10453SEric Joyner 
344171d10453SEric Joyner 	agg_info = ice_get_agg_info(pi->hw, agg_id);
344271d10453SEric Joyner 	if (!agg_info)
344371d10453SEric Joyner 		return ICE_ERR_PARAM;
344471d10453SEric Joyner 	if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
344571d10453SEric Joyner 		return ICE_ERR_PARAM;
344671d10453SEric Joyner 	switch (rl_type) {
344771d10453SEric Joyner 	case ICE_MIN_BW:
344871d10453SEric Joyner 		ice_set_clear_cir_bw_alloc(&agg_info->bw_t_info[tc], bw_alloc);
344971d10453SEric Joyner 		break;
345071d10453SEric Joyner 	case ICE_MAX_BW:
345171d10453SEric Joyner 		ice_set_clear_eir_bw_alloc(&agg_info->bw_t_info[tc], bw_alloc);
345271d10453SEric Joyner 		break;
345371d10453SEric Joyner 	default:
345471d10453SEric Joyner 		return ICE_ERR_PARAM;
345571d10453SEric Joyner 	}
3456*f2635e84SEric Joyner 	return 0;
345771d10453SEric Joyner }
345871d10453SEric Joyner 
345971d10453SEric Joyner /**
346071d10453SEric Joyner  * ice_sched_save_agg_bw - save aggregator node's BW information
346171d10453SEric Joyner  * @pi: port information structure
346271d10453SEric Joyner  * @agg_id: node aggregator ID
346371d10453SEric Joyner  * @tc: traffic class
346471d10453SEric Joyner  * @rl_type: rate limit type min, max, or shared
346571d10453SEric Joyner  * @bw: bandwidth in Kbps - Kilo bits per sec
346671d10453SEric Joyner  *
346771d10453SEric Joyner  * Save BW information of AGG type node for post replay use.
346871d10453SEric Joyner  */
3469*f2635e84SEric Joyner static int
347071d10453SEric Joyner ice_sched_save_agg_bw(struct ice_port_info *pi, u32 agg_id, u8 tc,
347171d10453SEric Joyner 		      enum ice_rl_type rl_type, u32 bw)
347271d10453SEric Joyner {
347371d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
347471d10453SEric Joyner 
347571d10453SEric Joyner 	agg_info = ice_get_agg_info(pi->hw, agg_id);
347671d10453SEric Joyner 	if (!agg_info)
347771d10453SEric Joyner 		return ICE_ERR_PARAM;
347871d10453SEric Joyner 	if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
347971d10453SEric Joyner 		return ICE_ERR_PARAM;
348071d10453SEric Joyner 	switch (rl_type) {
348171d10453SEric Joyner 	case ICE_MIN_BW:
348271d10453SEric Joyner 		ice_set_clear_cir_bw(&agg_info->bw_t_info[tc], bw);
348371d10453SEric Joyner 		break;
348471d10453SEric Joyner 	case ICE_MAX_BW:
348571d10453SEric Joyner 		ice_set_clear_eir_bw(&agg_info->bw_t_info[tc], bw);
348671d10453SEric Joyner 		break;
348771d10453SEric Joyner 	case ICE_SHARED_BW:
348871d10453SEric Joyner 		ice_set_clear_shared_bw(&agg_info->bw_t_info[tc], bw);
348971d10453SEric Joyner 		break;
349071d10453SEric Joyner 	default:
349171d10453SEric Joyner 		return ICE_ERR_PARAM;
349271d10453SEric Joyner 	}
3493*f2635e84SEric Joyner 	return 0;
349471d10453SEric Joyner }
349571d10453SEric Joyner 
349671d10453SEric Joyner /**
349771d10453SEric Joyner  * ice_cfg_vsi_bw_lmt_per_tc - configure VSI BW limit per TC
349871d10453SEric Joyner  * @pi: port information structure
349971d10453SEric Joyner  * @vsi_handle: software VSI handle
350071d10453SEric Joyner  * @tc: traffic class
350171d10453SEric Joyner  * @rl_type: min or max
350271d10453SEric Joyner  * @bw: bandwidth in Kbps
350371d10453SEric Joyner  *
350471d10453SEric Joyner  * This function configures BW limit of VSI scheduling node based on TC
350571d10453SEric Joyner  * information.
350671d10453SEric Joyner  */
3507*f2635e84SEric Joyner int
350871d10453SEric Joyner ice_cfg_vsi_bw_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
350971d10453SEric Joyner 			  enum ice_rl_type rl_type, u32 bw)
351071d10453SEric Joyner {
3511*f2635e84SEric Joyner 	int status;
351271d10453SEric Joyner 
351371d10453SEric Joyner 	status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle,
351471d10453SEric Joyner 						  ICE_AGG_TYPE_VSI,
351571d10453SEric Joyner 						  tc, rl_type, bw);
351671d10453SEric Joyner 	if (!status) {
351771d10453SEric Joyner 		ice_acquire_lock(&pi->sched_lock);
351871d10453SEric Joyner 		status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, bw);
351971d10453SEric Joyner 		ice_release_lock(&pi->sched_lock);
352071d10453SEric Joyner 	}
352171d10453SEric Joyner 	return status;
352271d10453SEric Joyner }
352371d10453SEric Joyner 
352471d10453SEric Joyner /**
352556429daeSEric Joyner  * ice_cfg_vsi_bw_dflt_lmt_per_tc - configure default VSI BW limit per TC
352671d10453SEric Joyner  * @pi: port information structure
352771d10453SEric Joyner  * @vsi_handle: software VSI handle
352871d10453SEric Joyner  * @tc: traffic class
352971d10453SEric Joyner  * @rl_type: min or max
353071d10453SEric Joyner  *
353171d10453SEric Joyner  * This function configures default BW limit of VSI scheduling node based on TC
353271d10453SEric Joyner  * information.
353371d10453SEric Joyner  */
3534*f2635e84SEric Joyner int
353571d10453SEric Joyner ice_cfg_vsi_bw_dflt_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
353671d10453SEric Joyner 			       enum ice_rl_type rl_type)
353771d10453SEric Joyner {
3538*f2635e84SEric Joyner 	int status;
353971d10453SEric Joyner 
354071d10453SEric Joyner 	status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle,
354171d10453SEric Joyner 						  ICE_AGG_TYPE_VSI,
354271d10453SEric Joyner 						  tc, rl_type,
354371d10453SEric Joyner 						  ICE_SCHED_DFLT_BW);
354471d10453SEric Joyner 	if (!status) {
354571d10453SEric Joyner 		ice_acquire_lock(&pi->sched_lock);
354671d10453SEric Joyner 		status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type,
354771d10453SEric Joyner 					       ICE_SCHED_DFLT_BW);
354871d10453SEric Joyner 		ice_release_lock(&pi->sched_lock);
354971d10453SEric Joyner 	}
355071d10453SEric Joyner 	return status;
355171d10453SEric Joyner }
355271d10453SEric Joyner 
355371d10453SEric Joyner /**
355471d10453SEric Joyner  * ice_cfg_agg_bw_lmt_per_tc - configure aggregator BW limit per TC
355571d10453SEric Joyner  * @pi: port information structure
355671d10453SEric Joyner  * @agg_id: aggregator ID
355771d10453SEric Joyner  * @tc: traffic class
355871d10453SEric Joyner  * @rl_type: min or max
355971d10453SEric Joyner  * @bw: bandwidth in Kbps
356071d10453SEric Joyner  *
356171d10453SEric Joyner  * This function applies BW limit to aggregator scheduling node based on TC
356271d10453SEric Joyner  * information.
356371d10453SEric Joyner  */
3564*f2635e84SEric Joyner int
356571d10453SEric Joyner ice_cfg_agg_bw_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc,
356671d10453SEric Joyner 			  enum ice_rl_type rl_type, u32 bw)
356771d10453SEric Joyner {
3568*f2635e84SEric Joyner 	int status;
356971d10453SEric Joyner 
357071d10453SEric Joyner 	status = ice_sched_set_node_bw_lmt_per_tc(pi, agg_id, ICE_AGG_TYPE_AGG,
357171d10453SEric Joyner 						  tc, rl_type, bw);
357271d10453SEric Joyner 	if (!status) {
357371d10453SEric Joyner 		ice_acquire_lock(&pi->sched_lock);
357471d10453SEric Joyner 		status = ice_sched_save_agg_bw(pi, agg_id, tc, rl_type, bw);
357571d10453SEric Joyner 		ice_release_lock(&pi->sched_lock);
357671d10453SEric Joyner 	}
357771d10453SEric Joyner 	return status;
357871d10453SEric Joyner }
357971d10453SEric Joyner 
358071d10453SEric Joyner /**
358171d10453SEric Joyner  * ice_cfg_agg_bw_dflt_lmt_per_tc - configure aggregator BW default limit per TC
358271d10453SEric Joyner  * @pi: port information structure
358371d10453SEric Joyner  * @agg_id: aggregator ID
358471d10453SEric Joyner  * @tc: traffic class
358571d10453SEric Joyner  * @rl_type: min or max
358671d10453SEric Joyner  *
358771d10453SEric Joyner  * This function applies default BW limit to aggregator scheduling node based
358871d10453SEric Joyner  * on TC information.
358971d10453SEric Joyner  */
3590*f2635e84SEric Joyner int
359171d10453SEric Joyner ice_cfg_agg_bw_dflt_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc,
359271d10453SEric Joyner 			       enum ice_rl_type rl_type)
359371d10453SEric Joyner {
3594*f2635e84SEric Joyner 	int status;
359571d10453SEric Joyner 
359671d10453SEric Joyner 	status = ice_sched_set_node_bw_lmt_per_tc(pi, agg_id, ICE_AGG_TYPE_AGG,
359771d10453SEric Joyner 						  tc, rl_type,
359871d10453SEric Joyner 						  ICE_SCHED_DFLT_BW);
359971d10453SEric Joyner 	if (!status) {
360071d10453SEric Joyner 		ice_acquire_lock(&pi->sched_lock);
360171d10453SEric Joyner 		status = ice_sched_save_agg_bw(pi, agg_id, tc, rl_type,
360271d10453SEric Joyner 					       ICE_SCHED_DFLT_BW);
360371d10453SEric Joyner 		ice_release_lock(&pi->sched_lock);
360471d10453SEric Joyner 	}
360571d10453SEric Joyner 	return status;
360671d10453SEric Joyner }
360771d10453SEric Joyner 
360871d10453SEric Joyner /**
360971d10453SEric Joyner  * ice_cfg_vsi_bw_shared_lmt - configure VSI BW shared limit
361071d10453SEric Joyner  * @pi: port information structure
361171d10453SEric Joyner  * @vsi_handle: software VSI handle
3612d08b8680SEric Joyner  * @min_bw: minimum bandwidth in Kbps
3613d08b8680SEric Joyner  * @max_bw: maximum bandwidth in Kbps
3614d08b8680SEric Joyner  * @shared_bw: shared bandwidth in Kbps
361571d10453SEric Joyner  *
3616d08b8680SEric Joyner  * Configure shared rate limiter(SRL) of all VSI type nodes across all traffic
3617d08b8680SEric Joyner  * classes for VSI matching handle.
361871d10453SEric Joyner  */
3619*f2635e84SEric Joyner int
3620d08b8680SEric Joyner ice_cfg_vsi_bw_shared_lmt(struct ice_port_info *pi, u16 vsi_handle, u32 min_bw,
3621d08b8680SEric Joyner 			  u32 max_bw, u32 shared_bw)
362271d10453SEric Joyner {
3623d08b8680SEric Joyner 	return ice_sched_set_vsi_bw_shared_lmt(pi, vsi_handle, min_bw, max_bw,
3624d08b8680SEric Joyner 					       shared_bw);
362571d10453SEric Joyner }
362671d10453SEric Joyner 
362771d10453SEric Joyner /**
362871d10453SEric Joyner  * ice_cfg_vsi_bw_no_shared_lmt - configure VSI BW for no shared limiter
362971d10453SEric Joyner  * @pi: port information structure
363071d10453SEric Joyner  * @vsi_handle: software VSI handle
363171d10453SEric Joyner  *
363271d10453SEric Joyner  * This function removes the shared rate limiter(SRL) of all VSI type nodes
363371d10453SEric Joyner  * across all traffic classes for VSI matching handle.
363471d10453SEric Joyner  */
3635*f2635e84SEric Joyner int
363671d10453SEric Joyner ice_cfg_vsi_bw_no_shared_lmt(struct ice_port_info *pi, u16 vsi_handle)
363771d10453SEric Joyner {
363871d10453SEric Joyner 	return ice_sched_set_vsi_bw_shared_lmt(pi, vsi_handle,
3639d08b8680SEric Joyner 					       ICE_SCHED_DFLT_BW,
3640d08b8680SEric Joyner 					       ICE_SCHED_DFLT_BW,
364171d10453SEric Joyner 					       ICE_SCHED_DFLT_BW);
364271d10453SEric Joyner }
364371d10453SEric Joyner 
364471d10453SEric Joyner /**
364571d10453SEric Joyner  * ice_cfg_agg_bw_shared_lmt - configure aggregator BW shared limit
364671d10453SEric Joyner  * @pi: port information structure
364771d10453SEric Joyner  * @agg_id: aggregator ID
3648d08b8680SEric Joyner  * @min_bw: minimum bandwidth in Kbps
3649d08b8680SEric Joyner  * @max_bw: maximum bandwidth in Kbps
3650d08b8680SEric Joyner  * @shared_bw: shared bandwidth in Kbps
365171d10453SEric Joyner  *
365271d10453SEric Joyner  * This function configures the shared rate limiter(SRL) of all aggregator type
365371d10453SEric Joyner  * nodes across all traffic classes for aggregator matching agg_id.
365471d10453SEric Joyner  */
3655*f2635e84SEric Joyner int
3656d08b8680SEric Joyner ice_cfg_agg_bw_shared_lmt(struct ice_port_info *pi, u32 agg_id, u32 min_bw,
3657d08b8680SEric Joyner 			  u32 max_bw, u32 shared_bw)
365871d10453SEric Joyner {
3659d08b8680SEric Joyner 	return ice_sched_set_agg_bw_shared_lmt(pi, agg_id, min_bw, max_bw,
3660d08b8680SEric Joyner 					       shared_bw);
366171d10453SEric Joyner }
366271d10453SEric Joyner 
366371d10453SEric Joyner /**
366471d10453SEric Joyner  * ice_cfg_agg_bw_no_shared_lmt - configure aggregator BW for no shared limiter
366571d10453SEric Joyner  * @pi: port information structure
366671d10453SEric Joyner  * @agg_id: aggregator ID
366771d10453SEric Joyner  *
366871d10453SEric Joyner  * This function removes the shared rate limiter(SRL) of all aggregator type
366971d10453SEric Joyner  * nodes across all traffic classes for aggregator matching agg_id.
367071d10453SEric Joyner  */
3671*f2635e84SEric Joyner int
367271d10453SEric Joyner ice_cfg_agg_bw_no_shared_lmt(struct ice_port_info *pi, u32 agg_id)
367371d10453SEric Joyner {
3674d08b8680SEric Joyner 	return ice_sched_set_agg_bw_shared_lmt(pi, agg_id, ICE_SCHED_DFLT_BW,
3675d08b8680SEric Joyner 					       ICE_SCHED_DFLT_BW,
3676d08b8680SEric Joyner 					       ICE_SCHED_DFLT_BW);
3677d08b8680SEric Joyner }
3678d08b8680SEric Joyner 
3679d08b8680SEric Joyner /**
368056429daeSEric Joyner  * ice_cfg_agg_bw_shared_lmt_per_tc - config aggregator BW shared limit per tc
3681d08b8680SEric Joyner  * @pi: port information structure
3682d08b8680SEric Joyner  * @agg_id: aggregator ID
3683d08b8680SEric Joyner  * @tc: traffic class
3684d08b8680SEric Joyner  * @min_bw: minimum bandwidth in Kbps
3685d08b8680SEric Joyner  * @max_bw: maximum bandwidth in Kbps
3686d08b8680SEric Joyner  * @shared_bw: shared bandwidth in Kbps
3687d08b8680SEric Joyner  *
3688d08b8680SEric Joyner  * This function configures the shared rate limiter(SRL) of all aggregator type
3689d08b8680SEric Joyner  * nodes across all traffic classes for aggregator matching agg_id.
3690d08b8680SEric Joyner  */
3691*f2635e84SEric Joyner int
3692d08b8680SEric Joyner ice_cfg_agg_bw_shared_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc,
3693d08b8680SEric Joyner 				 u32 min_bw, u32 max_bw, u32 shared_bw)
3694d08b8680SEric Joyner {
3695d08b8680SEric Joyner 	return ice_sched_set_agg_bw_shared_lmt_per_tc(pi, agg_id, tc, min_bw,
3696d08b8680SEric Joyner 						      max_bw, shared_bw);
3697d08b8680SEric Joyner }
3698d08b8680SEric Joyner 
3699d08b8680SEric Joyner /**
370056429daeSEric Joyner  * ice_cfg_agg_bw_no_shared_lmt_per_tc - cfg aggregator BW shared limit per tc
3701d08b8680SEric Joyner  * @pi: port information structure
3702d08b8680SEric Joyner  * @agg_id: aggregator ID
3703d08b8680SEric Joyner  * @tc: traffic class
3704d08b8680SEric Joyner  *
3705d08b8680SEric Joyner  * This function configures the shared rate limiter(SRL) of all aggregator type
3706d08b8680SEric Joyner  * nodes across all traffic classes for aggregator matching agg_id.
3707d08b8680SEric Joyner  */
3708*f2635e84SEric Joyner int
3709d08b8680SEric Joyner ice_cfg_agg_bw_no_shared_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc)
3710d08b8680SEric Joyner {
3711d08b8680SEric Joyner 	return ice_sched_set_agg_bw_shared_lmt_per_tc(pi, agg_id, tc,
3712d08b8680SEric Joyner 						      ICE_SCHED_DFLT_BW,
3713d08b8680SEric Joyner 						      ICE_SCHED_DFLT_BW,
3714d08b8680SEric Joyner 						      ICE_SCHED_DFLT_BW);
371571d10453SEric Joyner }
371671d10453SEric Joyner 
371771d10453SEric Joyner /**
371856429daeSEric Joyner  * ice_cfg_vsi_q_priority - config VSI queue priority of node
371971d10453SEric Joyner  * @pi: port information structure
372071d10453SEric Joyner  * @num_qs: number of VSI queues
372171d10453SEric Joyner  * @q_ids: queue IDs array
372271d10453SEric Joyner  * @q_prio: queue priority array
372371d10453SEric Joyner  *
372471d10453SEric Joyner  * This function configures the queue node priority (Sibling Priority) of the
372571d10453SEric Joyner  * passed in VSI's queue(s) for a given traffic class (TC).
372671d10453SEric Joyner  */
3727*f2635e84SEric Joyner int
372871d10453SEric Joyner ice_cfg_vsi_q_priority(struct ice_port_info *pi, u16 num_qs, u32 *q_ids,
372971d10453SEric Joyner 		       u8 *q_prio)
373071d10453SEric Joyner {
3731*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
373271d10453SEric Joyner 	u16 i;
373371d10453SEric Joyner 
373471d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
373571d10453SEric Joyner 
373671d10453SEric Joyner 	for (i = 0; i < num_qs; i++) {
373771d10453SEric Joyner 		struct ice_sched_node *node;
373871d10453SEric Joyner 
373971d10453SEric Joyner 		node = ice_sched_find_node_by_teid(pi->root, q_ids[i]);
374071d10453SEric Joyner 		if (!node || node->info.data.elem_type !=
374171d10453SEric Joyner 		    ICE_AQC_ELEM_TYPE_LEAF) {
374271d10453SEric Joyner 			status = ICE_ERR_PARAM;
374371d10453SEric Joyner 			break;
374471d10453SEric Joyner 		}
374571d10453SEric Joyner 		/* Configure Priority */
374671d10453SEric Joyner 		status = ice_sched_cfg_sibl_node_prio(pi, node, q_prio[i]);
374771d10453SEric Joyner 		if (status)
374871d10453SEric Joyner 			break;
374971d10453SEric Joyner 	}
375071d10453SEric Joyner 
375171d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
375271d10453SEric Joyner 	return status;
375371d10453SEric Joyner }
375471d10453SEric Joyner 
375571d10453SEric Joyner /**
375671d10453SEric Joyner  * ice_cfg_agg_vsi_priority_per_tc - config aggregator's VSI priority per TC
375771d10453SEric Joyner  * @pi: port information structure
375871d10453SEric Joyner  * @agg_id: Aggregator ID
375971d10453SEric Joyner  * @num_vsis: number of VSI(s)
376071d10453SEric Joyner  * @vsi_handle_arr: array of software VSI handles
376171d10453SEric Joyner  * @node_prio: pointer to node priority
376271d10453SEric Joyner  * @tc: traffic class
376371d10453SEric Joyner  *
376471d10453SEric Joyner  * This function configures the node priority (Sibling Priority) of the
376571d10453SEric Joyner  * passed in VSI's for a given traffic class (TC) of an Aggregator ID.
376671d10453SEric Joyner  */
3767*f2635e84SEric Joyner int
376871d10453SEric Joyner ice_cfg_agg_vsi_priority_per_tc(struct ice_port_info *pi, u32 agg_id,
376971d10453SEric Joyner 				u16 num_vsis, u16 *vsi_handle_arr,
377071d10453SEric Joyner 				u8 *node_prio, u8 tc)
377171d10453SEric Joyner {
377271d10453SEric Joyner 	struct ice_sched_agg_vsi_info *agg_vsi_info;
377371d10453SEric Joyner 	struct ice_sched_node *tc_node, *agg_node;
377471d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
377571d10453SEric Joyner 	bool agg_id_present = false;
377671d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
3777*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
377871d10453SEric Joyner 	u16 i;
377971d10453SEric Joyner 
378071d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
378171d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
378271d10453SEric Joyner 			    list_entry)
378371d10453SEric Joyner 		if (agg_info->agg_id == agg_id) {
378471d10453SEric Joyner 			agg_id_present = true;
378571d10453SEric Joyner 			break;
378671d10453SEric Joyner 		}
378771d10453SEric Joyner 	if (!agg_id_present)
378871d10453SEric Joyner 		goto exit_agg_priority_per_tc;
378971d10453SEric Joyner 
379071d10453SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
379171d10453SEric Joyner 	if (!tc_node)
379271d10453SEric Joyner 		goto exit_agg_priority_per_tc;
379371d10453SEric Joyner 
379471d10453SEric Joyner 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
379571d10453SEric Joyner 	if (!agg_node)
379671d10453SEric Joyner 		goto exit_agg_priority_per_tc;
379771d10453SEric Joyner 
379871d10453SEric Joyner 	if (num_vsis > hw->max_children[agg_node->tx_sched_layer])
379971d10453SEric Joyner 		goto exit_agg_priority_per_tc;
380071d10453SEric Joyner 
380171d10453SEric Joyner 	for (i = 0; i < num_vsis; i++) {
380271d10453SEric Joyner 		struct ice_sched_node *vsi_node;
380371d10453SEric Joyner 		bool vsi_handle_valid = false;
380471d10453SEric Joyner 		u16 vsi_handle;
380571d10453SEric Joyner 
380671d10453SEric Joyner 		status = ICE_ERR_PARAM;
380771d10453SEric Joyner 		vsi_handle = vsi_handle_arr[i];
380871d10453SEric Joyner 		if (!ice_is_vsi_valid(hw, vsi_handle))
380971d10453SEric Joyner 			goto exit_agg_priority_per_tc;
381071d10453SEric Joyner 		/* Verify child nodes before applying settings */
381171d10453SEric Joyner 		LIST_FOR_EACH_ENTRY(agg_vsi_info, &agg_info->agg_vsi_list,
381271d10453SEric Joyner 				    ice_sched_agg_vsi_info, list_entry)
381371d10453SEric Joyner 			if (agg_vsi_info->vsi_handle == vsi_handle) {
381471d10453SEric Joyner 				vsi_handle_valid = true;
381571d10453SEric Joyner 				break;
381671d10453SEric Joyner 			}
381771d10453SEric Joyner 
381871d10453SEric Joyner 		if (!vsi_handle_valid)
381971d10453SEric Joyner 			goto exit_agg_priority_per_tc;
382071d10453SEric Joyner 
382171d10453SEric Joyner 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
382271d10453SEric Joyner 		if (!vsi_node)
382371d10453SEric Joyner 			goto exit_agg_priority_per_tc;
382471d10453SEric Joyner 
382571d10453SEric Joyner 		if (ice_sched_find_node_in_subtree(hw, agg_node, vsi_node)) {
382671d10453SEric Joyner 			/* Configure Priority */
382771d10453SEric Joyner 			status = ice_sched_cfg_sibl_node_prio(pi, vsi_node,
382871d10453SEric Joyner 							      node_prio[i]);
382971d10453SEric Joyner 			if (status)
383071d10453SEric Joyner 				break;
383171d10453SEric Joyner 			status = ice_sched_save_vsi_prio(pi, vsi_handle, tc,
383271d10453SEric Joyner 							 node_prio[i]);
383371d10453SEric Joyner 			if (status)
383471d10453SEric Joyner 				break;
383571d10453SEric Joyner 		}
383671d10453SEric Joyner 	}
383771d10453SEric Joyner 
383871d10453SEric Joyner exit_agg_priority_per_tc:
383971d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
384071d10453SEric Joyner 	return status;
384171d10453SEric Joyner }
384271d10453SEric Joyner 
384371d10453SEric Joyner /**
384471d10453SEric Joyner  * ice_cfg_vsi_bw_alloc - config VSI BW alloc per TC
384571d10453SEric Joyner  * @pi: port information structure
384671d10453SEric Joyner  * @vsi_handle: software VSI handle
384771d10453SEric Joyner  * @ena_tcmap: enabled TC map
384871d10453SEric Joyner  * @rl_type: Rate limit type CIR/EIR
384971d10453SEric Joyner  * @bw_alloc: Array of BW alloc
385071d10453SEric Joyner  *
385171d10453SEric Joyner  * This function configures the BW allocation of the passed in VSI's
385271d10453SEric Joyner  * node(s) for enabled traffic class.
385371d10453SEric Joyner  */
3854*f2635e84SEric Joyner int
385571d10453SEric Joyner ice_cfg_vsi_bw_alloc(struct ice_port_info *pi, u16 vsi_handle, u8 ena_tcmap,
385671d10453SEric Joyner 		     enum ice_rl_type rl_type, u8 *bw_alloc)
385771d10453SEric Joyner {
3858*f2635e84SEric Joyner 	int status = 0;
385971d10453SEric Joyner 	u8 tc;
386071d10453SEric Joyner 
386171d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
386271d10453SEric Joyner 		return ICE_ERR_PARAM;
386371d10453SEric Joyner 
386471d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
386571d10453SEric Joyner 
386671d10453SEric Joyner 	/* Return success if no nodes are present across TC */
386771d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
386871d10453SEric Joyner 		struct ice_sched_node *tc_node, *vsi_node;
386971d10453SEric Joyner 
387071d10453SEric Joyner 		if (!ice_is_tc_ena(ena_tcmap, tc))
387171d10453SEric Joyner 			continue;
387271d10453SEric Joyner 
387371d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, tc);
387471d10453SEric Joyner 		if (!tc_node)
387571d10453SEric Joyner 			continue;
387671d10453SEric Joyner 
387771d10453SEric Joyner 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
387871d10453SEric Joyner 		if (!vsi_node)
387971d10453SEric Joyner 			continue;
388071d10453SEric Joyner 
388171d10453SEric Joyner 		status = ice_sched_cfg_node_bw_alloc(pi->hw, vsi_node, rl_type,
388271d10453SEric Joyner 						     bw_alloc[tc]);
388371d10453SEric Joyner 		if (status)
388471d10453SEric Joyner 			break;
388571d10453SEric Joyner 		status = ice_sched_save_vsi_bw_alloc(pi, vsi_handle, tc,
388671d10453SEric Joyner 						     rl_type, bw_alloc[tc]);
388771d10453SEric Joyner 		if (status)
388871d10453SEric Joyner 			break;
388971d10453SEric Joyner 	}
389071d10453SEric Joyner 
389171d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
389271d10453SEric Joyner 	return status;
389371d10453SEric Joyner }
389471d10453SEric Joyner 
389571d10453SEric Joyner /**
389671d10453SEric Joyner  * ice_cfg_agg_bw_alloc - config aggregator BW alloc
389771d10453SEric Joyner  * @pi: port information structure
389871d10453SEric Joyner  * @agg_id: aggregator ID
389971d10453SEric Joyner  * @ena_tcmap: enabled TC map
390071d10453SEric Joyner  * @rl_type: rate limit type CIR/EIR
390171d10453SEric Joyner  * @bw_alloc: array of BW alloc
390271d10453SEric Joyner  *
390371d10453SEric Joyner  * This function configures the BW allocation of passed in aggregator for
390471d10453SEric Joyner  * enabled traffic class(s).
390571d10453SEric Joyner  */
3906*f2635e84SEric Joyner int
390771d10453SEric Joyner ice_cfg_agg_bw_alloc(struct ice_port_info *pi, u32 agg_id, u8 ena_tcmap,
390871d10453SEric Joyner 		     enum ice_rl_type rl_type, u8 *bw_alloc)
390971d10453SEric Joyner {
391071d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
391171d10453SEric Joyner 	bool agg_id_present = false;
391271d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
3913*f2635e84SEric Joyner 	int status = 0;
391471d10453SEric Joyner 	u8 tc;
391571d10453SEric Joyner 
391671d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
391771d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
391871d10453SEric Joyner 			    list_entry)
391971d10453SEric Joyner 		if (agg_info->agg_id == agg_id) {
392071d10453SEric Joyner 			agg_id_present = true;
392171d10453SEric Joyner 			break;
392271d10453SEric Joyner 		}
392371d10453SEric Joyner 	if (!agg_id_present) {
392471d10453SEric Joyner 		status = ICE_ERR_PARAM;
392571d10453SEric Joyner 		goto exit_cfg_agg_bw_alloc;
392671d10453SEric Joyner 	}
392771d10453SEric Joyner 
392871d10453SEric Joyner 	/* Return success if no nodes are present across TC */
392971d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
393071d10453SEric Joyner 		struct ice_sched_node *tc_node, *agg_node;
393171d10453SEric Joyner 
393271d10453SEric Joyner 		if (!ice_is_tc_ena(ena_tcmap, tc))
393371d10453SEric Joyner 			continue;
393471d10453SEric Joyner 
393571d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, tc);
393671d10453SEric Joyner 		if (!tc_node)
393771d10453SEric Joyner 			continue;
393871d10453SEric Joyner 
393971d10453SEric Joyner 		agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
394071d10453SEric Joyner 		if (!agg_node)
394171d10453SEric Joyner 			continue;
394271d10453SEric Joyner 
394371d10453SEric Joyner 		status = ice_sched_cfg_node_bw_alloc(hw, agg_node, rl_type,
394471d10453SEric Joyner 						     bw_alloc[tc]);
394571d10453SEric Joyner 		if (status)
394671d10453SEric Joyner 			break;
394771d10453SEric Joyner 		status = ice_sched_save_agg_bw_alloc(pi, agg_id, tc, rl_type,
394871d10453SEric Joyner 						     bw_alloc[tc]);
394971d10453SEric Joyner 		if (status)
395071d10453SEric Joyner 			break;
395171d10453SEric Joyner 	}
395271d10453SEric Joyner 
395371d10453SEric Joyner exit_cfg_agg_bw_alloc:
395471d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
395571d10453SEric Joyner 	return status;
395671d10453SEric Joyner }
395771d10453SEric Joyner 
395871d10453SEric Joyner /**
395971d10453SEric Joyner  * ice_sched_calc_wakeup - calculate RL profile wakeup parameter
396071d10453SEric Joyner  * @hw: pointer to the HW struct
396171d10453SEric Joyner  * @bw: bandwidth in Kbps
396271d10453SEric Joyner  *
396371d10453SEric Joyner  * This function calculates the wakeup parameter of RL profile.
396471d10453SEric Joyner  */
396571d10453SEric Joyner static u16 ice_sched_calc_wakeup(struct ice_hw *hw, s32 bw)
396671d10453SEric Joyner {
396771d10453SEric Joyner 	s64 bytes_per_sec, wakeup_int, wakeup_a, wakeup_b, wakeup_f;
396871d10453SEric Joyner 	s32 wakeup_f_int;
396971d10453SEric Joyner 	u16 wakeup = 0;
397071d10453SEric Joyner 
397171d10453SEric Joyner 	/* Get the wakeup integer value */
39728923de59SPiotr Kubaj 	bytes_per_sec = DIV_S64((s64)bw * 1000, BITS_PER_BYTE);
397356429daeSEric Joyner 	wakeup_int = DIV_S64(hw->psm_clk_freq, bytes_per_sec);
397471d10453SEric Joyner 	if (wakeup_int > 63) {
397571d10453SEric Joyner 		wakeup = (u16)((1 << 15) | wakeup_int);
397671d10453SEric Joyner 	} else {
397771d10453SEric Joyner 		/* Calculate fraction value up to 4 decimals
397871d10453SEric Joyner 		 * Convert Integer value to a constant multiplier
397971d10453SEric Joyner 		 */
398071d10453SEric Joyner 		wakeup_b = (s64)ICE_RL_PROF_MULTIPLIER * wakeup_int;
39818923de59SPiotr Kubaj 		wakeup_a = DIV_S64((s64)ICE_RL_PROF_MULTIPLIER *
398271d10453SEric Joyner 				   hw->psm_clk_freq, bytes_per_sec);
398371d10453SEric Joyner 
398471d10453SEric Joyner 		/* Get Fraction value */
398571d10453SEric Joyner 		wakeup_f = wakeup_a - wakeup_b;
398671d10453SEric Joyner 
398771d10453SEric Joyner 		/* Round up the Fractional value via Ceil(Fractional value) */
398856429daeSEric Joyner 		if (wakeup_f > DIV_S64(ICE_RL_PROF_MULTIPLIER, 2))
398971d10453SEric Joyner 			wakeup_f += 1;
399071d10453SEric Joyner 
399156429daeSEric Joyner 		wakeup_f_int = (s32)DIV_S64(wakeup_f * ICE_RL_PROF_FRACTION,
399271d10453SEric Joyner 					    ICE_RL_PROF_MULTIPLIER);
399371d10453SEric Joyner 		wakeup |= (u16)(wakeup_int << 9);
399471d10453SEric Joyner 		wakeup |= (u16)(0x1ff & wakeup_f_int);
399571d10453SEric Joyner 	}
399671d10453SEric Joyner 
399771d10453SEric Joyner 	return wakeup;
399871d10453SEric Joyner }
399971d10453SEric Joyner 
400071d10453SEric Joyner /**
400171d10453SEric Joyner  * ice_sched_bw_to_rl_profile - convert BW to profile parameters
400271d10453SEric Joyner  * @hw: pointer to the HW struct
400371d10453SEric Joyner  * @bw: bandwidth in Kbps
400471d10453SEric Joyner  * @profile: profile parameters to return
400571d10453SEric Joyner  *
400671d10453SEric Joyner  * This function converts the BW to profile structure format.
400771d10453SEric Joyner  */
4008*f2635e84SEric Joyner static int
400971d10453SEric Joyner ice_sched_bw_to_rl_profile(struct ice_hw *hw, u32 bw,
401071d10453SEric Joyner 			   struct ice_aqc_rl_profile_elem *profile)
401171d10453SEric Joyner {
401271d10453SEric Joyner 	s64 bytes_per_sec, ts_rate, mv_tmp;
4013*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
401471d10453SEric Joyner 	bool found = false;
401571d10453SEric Joyner 	s32 encode = 0;
401671d10453SEric Joyner 	s64 mv = 0;
401771d10453SEric Joyner 	s32 i;
401871d10453SEric Joyner 
401971d10453SEric Joyner 	/* Bw settings range is from 0.5Mb/sec to 100Gb/sec */
402071d10453SEric Joyner 	if (bw < ICE_SCHED_MIN_BW || bw > ICE_SCHED_MAX_BW)
402171d10453SEric Joyner 		return status;
402271d10453SEric Joyner 
402371d10453SEric Joyner 	/* Bytes per second from Kbps */
40248923de59SPiotr Kubaj 	bytes_per_sec = DIV_S64((s64)bw * 1000, BITS_PER_BYTE);
402571d10453SEric Joyner 
402671d10453SEric Joyner 	/* encode is 6 bits but really useful are 5 bits */
402771d10453SEric Joyner 	for (i = 0; i < 64; i++) {
402871d10453SEric Joyner 		u64 pow_result = BIT_ULL(i);
402971d10453SEric Joyner 
40308923de59SPiotr Kubaj 		ts_rate = DIV_S64((s64)hw->psm_clk_freq,
403171d10453SEric Joyner 				  pow_result * ICE_RL_PROF_TS_MULTIPLIER);
403271d10453SEric Joyner 		if (ts_rate <= 0)
403371d10453SEric Joyner 			continue;
403471d10453SEric Joyner 
403571d10453SEric Joyner 		/* Multiplier value */
403656429daeSEric Joyner 		mv_tmp = DIV_S64(bytes_per_sec * ICE_RL_PROF_MULTIPLIER,
403771d10453SEric Joyner 				 ts_rate);
403871d10453SEric Joyner 
403971d10453SEric Joyner 		/* Round to the nearest ICE_RL_PROF_MULTIPLIER */
404071d10453SEric Joyner 		mv = round_up_64bit(mv_tmp, ICE_RL_PROF_MULTIPLIER);
404171d10453SEric Joyner 
404271d10453SEric Joyner 		/* First multiplier value greater than the given
404371d10453SEric Joyner 		 * accuracy bytes
404471d10453SEric Joyner 		 */
404571d10453SEric Joyner 		if (mv > ICE_RL_PROF_ACCURACY_BYTES) {
404671d10453SEric Joyner 			encode = i;
404771d10453SEric Joyner 			found = true;
404871d10453SEric Joyner 			break;
404971d10453SEric Joyner 		}
405071d10453SEric Joyner 	}
405171d10453SEric Joyner 	if (found) {
405271d10453SEric Joyner 		u16 wm;
405371d10453SEric Joyner 
405471d10453SEric Joyner 		wm = ice_sched_calc_wakeup(hw, bw);
405571d10453SEric Joyner 		profile->rl_multiply = CPU_TO_LE16(mv);
405671d10453SEric Joyner 		profile->wake_up_calc = CPU_TO_LE16(wm);
405771d10453SEric Joyner 		profile->rl_encode = CPU_TO_LE16(encode);
4058*f2635e84SEric Joyner 		status = 0;
405971d10453SEric Joyner 	} else {
406071d10453SEric Joyner 		status = ICE_ERR_DOES_NOT_EXIST;
406171d10453SEric Joyner 	}
406271d10453SEric Joyner 
406371d10453SEric Joyner 	return status;
406471d10453SEric Joyner }
406571d10453SEric Joyner 
406671d10453SEric Joyner /**
406771d10453SEric Joyner  * ice_sched_add_rl_profile - add RL profile
4068d08b8680SEric Joyner  * @hw: pointer to the hardware structure
406971d10453SEric Joyner  * @rl_type: type of rate limit BW - min, max, or shared
407071d10453SEric Joyner  * @bw: bandwidth in Kbps - Kilo bits per sec
407171d10453SEric Joyner  * @layer_num: specifies in which layer to create profile
407271d10453SEric Joyner  *
407371d10453SEric Joyner  * This function first checks the existing list for corresponding BW
407471d10453SEric Joyner  * parameter. If it exists, it returns the associated profile otherwise
407571d10453SEric Joyner  * it creates a new rate limit profile for requested BW, and adds it to
407671d10453SEric Joyner  * the HW DB and local list. It returns the new profile or null on error.
407771d10453SEric Joyner  * The caller needs to hold the scheduler lock.
407871d10453SEric Joyner  */
407971d10453SEric Joyner static struct ice_aqc_rl_profile_info *
4080d08b8680SEric Joyner ice_sched_add_rl_profile(struct ice_hw *hw, enum ice_rl_type rl_type,
4081d08b8680SEric Joyner 			 u32 bw, u8 layer_num)
408271d10453SEric Joyner {
408371d10453SEric Joyner 	struct ice_aqc_rl_profile_info *rl_prof_elem;
408471d10453SEric Joyner 	u16 profiles_added = 0, num_profiles = 1;
40857d7af7f8SEric Joyner 	struct ice_aqc_rl_profile_elem *buf;
408671d10453SEric Joyner 	u8 profile_type;
4087*f2635e84SEric Joyner 	int status;
408871d10453SEric Joyner 
40898923de59SPiotr Kubaj 	if (!hw || layer_num >= hw->num_tx_sched_layers)
409071d10453SEric Joyner 		return NULL;
409171d10453SEric Joyner 	switch (rl_type) {
409271d10453SEric Joyner 	case ICE_MIN_BW:
409371d10453SEric Joyner 		profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR;
409471d10453SEric Joyner 		break;
409571d10453SEric Joyner 	case ICE_MAX_BW:
409671d10453SEric Joyner 		profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR;
409771d10453SEric Joyner 		break;
409871d10453SEric Joyner 	case ICE_SHARED_BW:
409971d10453SEric Joyner 		profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL;
410071d10453SEric Joyner 		break;
410171d10453SEric Joyner 	default:
410271d10453SEric Joyner 		return NULL;
410371d10453SEric Joyner 	}
410471d10453SEric Joyner 
4105d08b8680SEric Joyner 	LIST_FOR_EACH_ENTRY(rl_prof_elem, &hw->rl_prof_list[layer_num],
410671d10453SEric Joyner 			    ice_aqc_rl_profile_info, list_entry)
41077d7af7f8SEric Joyner 		if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) ==
41087d7af7f8SEric Joyner 		    profile_type && rl_prof_elem->bw == bw)
410971d10453SEric Joyner 			/* Return existing profile ID info */
411071d10453SEric Joyner 			return rl_prof_elem;
411171d10453SEric Joyner 
411271d10453SEric Joyner 	/* Create new profile ID */
411371d10453SEric Joyner 	rl_prof_elem = (struct ice_aqc_rl_profile_info *)
411471d10453SEric Joyner 		ice_malloc(hw, sizeof(*rl_prof_elem));
411571d10453SEric Joyner 
411671d10453SEric Joyner 	if (!rl_prof_elem)
411771d10453SEric Joyner 		return NULL;
411871d10453SEric Joyner 
411971d10453SEric Joyner 	status = ice_sched_bw_to_rl_profile(hw, bw, &rl_prof_elem->profile);
4120*f2635e84SEric Joyner 	if (status)
412171d10453SEric Joyner 		goto exit_add_rl_prof;
412271d10453SEric Joyner 
412371d10453SEric Joyner 	rl_prof_elem->bw = bw;
412471d10453SEric Joyner 	/* layer_num is zero relative, and fw expects level from 1 to 9 */
412571d10453SEric Joyner 	rl_prof_elem->profile.level = layer_num + 1;
412671d10453SEric Joyner 	rl_prof_elem->profile.flags = profile_type;
412771d10453SEric Joyner 	rl_prof_elem->profile.max_burst_size = CPU_TO_LE16(hw->max_burst_size);
412871d10453SEric Joyner 
412971d10453SEric Joyner 	/* Create new entry in HW DB */
41307d7af7f8SEric Joyner 	buf = &rl_prof_elem->profile;
413171d10453SEric Joyner 	status = ice_aq_add_rl_profile(hw, num_profiles, buf, sizeof(*buf),
413271d10453SEric Joyner 				       &profiles_added, NULL);
413371d10453SEric Joyner 	if (status || profiles_added != num_profiles)
413471d10453SEric Joyner 		goto exit_add_rl_prof;
413571d10453SEric Joyner 
413671d10453SEric Joyner 	/* Good entry - add in the list */
413771d10453SEric Joyner 	rl_prof_elem->prof_id_ref = 0;
4138d08b8680SEric Joyner 	LIST_ADD(&rl_prof_elem->list_entry, &hw->rl_prof_list[layer_num]);
413971d10453SEric Joyner 	return rl_prof_elem;
414071d10453SEric Joyner 
414171d10453SEric Joyner exit_add_rl_prof:
414271d10453SEric Joyner 	ice_free(hw, rl_prof_elem);
414371d10453SEric Joyner 	return NULL;
414471d10453SEric Joyner }
414571d10453SEric Joyner 
414671d10453SEric Joyner /**
414771d10453SEric Joyner  * ice_sched_cfg_node_bw_lmt - configure node sched params
414871d10453SEric Joyner  * @hw: pointer to the HW struct
414971d10453SEric Joyner  * @node: sched node to configure
415071d10453SEric Joyner  * @rl_type: rate limit type CIR, EIR, or shared
415171d10453SEric Joyner  * @rl_prof_id: rate limit profile ID
415271d10453SEric Joyner  *
415371d10453SEric Joyner  * This function configures node element's BW limit.
415471d10453SEric Joyner  */
4155*f2635e84SEric Joyner static int
415671d10453SEric Joyner ice_sched_cfg_node_bw_lmt(struct ice_hw *hw, struct ice_sched_node *node,
415771d10453SEric Joyner 			  enum ice_rl_type rl_type, u16 rl_prof_id)
415871d10453SEric Joyner {
415971d10453SEric Joyner 	struct ice_aqc_txsched_elem_data buf;
416071d10453SEric Joyner 	struct ice_aqc_txsched_elem *data;
416171d10453SEric Joyner 
416271d10453SEric Joyner 	buf = node->info;
416371d10453SEric Joyner 	data = &buf.data;
416471d10453SEric Joyner 	switch (rl_type) {
416571d10453SEric Joyner 	case ICE_MIN_BW:
416671d10453SEric Joyner 		data->valid_sections |= ICE_AQC_ELEM_VALID_CIR;
416771d10453SEric Joyner 		data->cir_bw.bw_profile_idx = CPU_TO_LE16(rl_prof_id);
416871d10453SEric Joyner 		break;
416971d10453SEric Joyner 	case ICE_MAX_BW:
417071d10453SEric Joyner 		data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
417171d10453SEric Joyner 		data->eir_bw.bw_profile_idx = CPU_TO_LE16(rl_prof_id);
417271d10453SEric Joyner 		break;
417371d10453SEric Joyner 	case ICE_SHARED_BW:
417471d10453SEric Joyner 		data->valid_sections |= ICE_AQC_ELEM_VALID_SHARED;
417571d10453SEric Joyner 		data->srl_id = CPU_TO_LE16(rl_prof_id);
417671d10453SEric Joyner 		break;
417771d10453SEric Joyner 	default:
417871d10453SEric Joyner 		/* Unknown rate limit type */
417971d10453SEric Joyner 		return ICE_ERR_PARAM;
418071d10453SEric Joyner 	}
418171d10453SEric Joyner 
418271d10453SEric Joyner 	/* Configure element */
418371d10453SEric Joyner 	return ice_sched_update_elem(hw, node, &buf);
418471d10453SEric Joyner }
418571d10453SEric Joyner 
418671d10453SEric Joyner /**
418771d10453SEric Joyner  * ice_sched_get_node_rl_prof_id - get node's rate limit profile ID
418871d10453SEric Joyner  * @node: sched node
418971d10453SEric Joyner  * @rl_type: rate limit type
419071d10453SEric Joyner  *
419171d10453SEric Joyner  * If existing profile matches, it returns the corresponding rate
419271d10453SEric Joyner  * limit profile ID, otherwise it returns an invalid ID as error.
419371d10453SEric Joyner  */
419471d10453SEric Joyner static u16
419571d10453SEric Joyner ice_sched_get_node_rl_prof_id(struct ice_sched_node *node,
419671d10453SEric Joyner 			      enum ice_rl_type rl_type)
419771d10453SEric Joyner {
419871d10453SEric Joyner 	u16 rl_prof_id = ICE_SCHED_INVAL_PROF_ID;
419971d10453SEric Joyner 	struct ice_aqc_txsched_elem *data;
420071d10453SEric Joyner 
420171d10453SEric Joyner 	data = &node->info.data;
420271d10453SEric Joyner 	switch (rl_type) {
420371d10453SEric Joyner 	case ICE_MIN_BW:
420471d10453SEric Joyner 		if (data->valid_sections & ICE_AQC_ELEM_VALID_CIR)
420571d10453SEric Joyner 			rl_prof_id = LE16_TO_CPU(data->cir_bw.bw_profile_idx);
420671d10453SEric Joyner 		break;
420771d10453SEric Joyner 	case ICE_MAX_BW:
420871d10453SEric Joyner 		if (data->valid_sections & ICE_AQC_ELEM_VALID_EIR)
420971d10453SEric Joyner 			rl_prof_id = LE16_TO_CPU(data->eir_bw.bw_profile_idx);
421071d10453SEric Joyner 		break;
421171d10453SEric Joyner 	case ICE_SHARED_BW:
421271d10453SEric Joyner 		if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED)
421371d10453SEric Joyner 			rl_prof_id = LE16_TO_CPU(data->srl_id);
421471d10453SEric Joyner 		break;
421571d10453SEric Joyner 	default:
421671d10453SEric Joyner 		break;
421771d10453SEric Joyner 	}
421871d10453SEric Joyner 
421971d10453SEric Joyner 	return rl_prof_id;
422071d10453SEric Joyner }
422171d10453SEric Joyner 
422271d10453SEric Joyner /**
422371d10453SEric Joyner  * ice_sched_get_rl_prof_layer - selects rate limit profile creation layer
422471d10453SEric Joyner  * @pi: port information structure
422571d10453SEric Joyner  * @rl_type: type of rate limit BW - min, max, or shared
422671d10453SEric Joyner  * @layer_index: layer index
422771d10453SEric Joyner  *
422871d10453SEric Joyner  * This function returns requested profile creation layer.
422971d10453SEric Joyner  */
423071d10453SEric Joyner static u8
423171d10453SEric Joyner ice_sched_get_rl_prof_layer(struct ice_port_info *pi, enum ice_rl_type rl_type,
423271d10453SEric Joyner 			    u8 layer_index)
423371d10453SEric Joyner {
423471d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
423571d10453SEric Joyner 
423671d10453SEric Joyner 	if (layer_index >= hw->num_tx_sched_layers)
423771d10453SEric Joyner 		return ICE_SCHED_INVAL_LAYER_NUM;
423871d10453SEric Joyner 	switch (rl_type) {
423971d10453SEric Joyner 	case ICE_MIN_BW:
424071d10453SEric Joyner 		if (hw->layer_info[layer_index].max_cir_rl_profiles)
424171d10453SEric Joyner 			return layer_index;
424271d10453SEric Joyner 		break;
424371d10453SEric Joyner 	case ICE_MAX_BW:
424471d10453SEric Joyner 		if (hw->layer_info[layer_index].max_eir_rl_profiles)
424571d10453SEric Joyner 			return layer_index;
424671d10453SEric Joyner 		break;
424771d10453SEric Joyner 	case ICE_SHARED_BW:
424871d10453SEric Joyner 		/* if current layer doesn't support SRL profile creation
424971d10453SEric Joyner 		 * then try a layer up or down.
425071d10453SEric Joyner 		 */
425171d10453SEric Joyner 		if (hw->layer_info[layer_index].max_srl_profiles)
425271d10453SEric Joyner 			return layer_index;
425371d10453SEric Joyner 		else if (layer_index < hw->num_tx_sched_layers - 1 &&
425471d10453SEric Joyner 			 hw->layer_info[layer_index + 1].max_srl_profiles)
425571d10453SEric Joyner 			return layer_index + 1;
425671d10453SEric Joyner 		else if (layer_index > 0 &&
425771d10453SEric Joyner 			 hw->layer_info[layer_index - 1].max_srl_profiles)
425871d10453SEric Joyner 			return layer_index - 1;
425971d10453SEric Joyner 		break;
426071d10453SEric Joyner 	default:
426171d10453SEric Joyner 		break;
426271d10453SEric Joyner 	}
426371d10453SEric Joyner 	return ICE_SCHED_INVAL_LAYER_NUM;
426471d10453SEric Joyner }
426571d10453SEric Joyner 
426671d10453SEric Joyner /**
426771d10453SEric Joyner  * ice_sched_get_srl_node - get shared rate limit node
426871d10453SEric Joyner  * @node: tree node
426971d10453SEric Joyner  * @srl_layer: shared rate limit layer
427071d10453SEric Joyner  *
427171d10453SEric Joyner  * This function returns SRL node to be used for shared rate limit purpose.
427271d10453SEric Joyner  * The caller needs to hold scheduler lock.
427371d10453SEric Joyner  */
427471d10453SEric Joyner static struct ice_sched_node *
427571d10453SEric Joyner ice_sched_get_srl_node(struct ice_sched_node *node, u8 srl_layer)
427671d10453SEric Joyner {
427771d10453SEric Joyner 	if (srl_layer > node->tx_sched_layer)
427871d10453SEric Joyner 		return node->children[0];
427971d10453SEric Joyner 	else if (srl_layer < node->tx_sched_layer)
428071d10453SEric Joyner 		/* Node can't be created without a parent. It will always
428171d10453SEric Joyner 		 * have a valid parent except root node.
428271d10453SEric Joyner 		 */
428371d10453SEric Joyner 		return node->parent;
428471d10453SEric Joyner 	else
428571d10453SEric Joyner 		return node;
428671d10453SEric Joyner }
428771d10453SEric Joyner 
428871d10453SEric Joyner /**
428971d10453SEric Joyner  * ice_sched_rm_rl_profile - remove RL profile ID
4290d08b8680SEric Joyner  * @hw: pointer to the hardware structure
429171d10453SEric Joyner  * @layer_num: layer number where profiles are saved
429271d10453SEric Joyner  * @profile_type: profile type like EIR, CIR, or SRL
429371d10453SEric Joyner  * @profile_id: profile ID to remove
429471d10453SEric Joyner  *
429571d10453SEric Joyner  * This function removes rate limit profile from layer 'layer_num' of type
429671d10453SEric Joyner  * 'profile_type' and profile ID as 'profile_id'. The caller needs to hold
429771d10453SEric Joyner  * scheduler lock.
429871d10453SEric Joyner  */
4299*f2635e84SEric Joyner static int
4300d08b8680SEric Joyner ice_sched_rm_rl_profile(struct ice_hw *hw, u8 layer_num, u8 profile_type,
430171d10453SEric Joyner 			u16 profile_id)
430271d10453SEric Joyner {
430371d10453SEric Joyner 	struct ice_aqc_rl_profile_info *rl_prof_elem;
4304*f2635e84SEric Joyner 	int status = 0;
430571d10453SEric Joyner 
43068923de59SPiotr Kubaj 	if (!hw || layer_num >= hw->num_tx_sched_layers)
430771d10453SEric Joyner 		return ICE_ERR_PARAM;
430871d10453SEric Joyner 	/* Check the existing list for RL profile */
4309d08b8680SEric Joyner 	LIST_FOR_EACH_ENTRY(rl_prof_elem, &hw->rl_prof_list[layer_num],
431071d10453SEric Joyner 			    ice_aqc_rl_profile_info, list_entry)
43117d7af7f8SEric Joyner 		if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) ==
43127d7af7f8SEric Joyner 		    profile_type &&
431371d10453SEric Joyner 		    LE16_TO_CPU(rl_prof_elem->profile.profile_id) ==
431471d10453SEric Joyner 		    profile_id) {
431571d10453SEric Joyner 			if (rl_prof_elem->prof_id_ref)
431671d10453SEric Joyner 				rl_prof_elem->prof_id_ref--;
431771d10453SEric Joyner 
431871d10453SEric Joyner 			/* Remove old profile ID from database */
4319d08b8680SEric Joyner 			status = ice_sched_del_rl_profile(hw, rl_prof_elem);
432071d10453SEric Joyner 			if (status && status != ICE_ERR_IN_USE)
4321d08b8680SEric Joyner 				ice_debug(hw, ICE_DBG_SCHED, "Remove rl profile failed\n");
432271d10453SEric Joyner 			break;
432371d10453SEric Joyner 		}
432471d10453SEric Joyner 	if (status == ICE_ERR_IN_USE)
4325*f2635e84SEric Joyner 		status = 0;
432671d10453SEric Joyner 	return status;
432771d10453SEric Joyner }
432871d10453SEric Joyner 
432971d10453SEric Joyner /**
433071d10453SEric Joyner  * ice_sched_set_node_bw_dflt - set node's bandwidth limit to default
433171d10453SEric Joyner  * @pi: port information structure
433271d10453SEric Joyner  * @node: pointer to node structure
433371d10453SEric Joyner  * @rl_type: rate limit type min, max, or shared
433471d10453SEric Joyner  * @layer_num: layer number where RL profiles are saved
433571d10453SEric Joyner  *
433671d10453SEric Joyner  * This function configures node element's BW rate limit profile ID of
433771d10453SEric Joyner  * type CIR, EIR, or SRL to default. This function needs to be called
433871d10453SEric Joyner  * with the scheduler lock held.
433971d10453SEric Joyner  */
4340*f2635e84SEric Joyner static int
434171d10453SEric Joyner ice_sched_set_node_bw_dflt(struct ice_port_info *pi,
434271d10453SEric Joyner 			   struct ice_sched_node *node,
434371d10453SEric Joyner 			   enum ice_rl_type rl_type, u8 layer_num)
434471d10453SEric Joyner {
434571d10453SEric Joyner 	struct ice_hw *hw;
434671d10453SEric Joyner 	u8 profile_type;
434771d10453SEric Joyner 	u16 rl_prof_id;
4348*f2635e84SEric Joyner 	int status;
434971d10453SEric Joyner 	u16 old_id;
435071d10453SEric Joyner 
435171d10453SEric Joyner 	hw = pi->hw;
435271d10453SEric Joyner 	switch (rl_type) {
435371d10453SEric Joyner 	case ICE_MIN_BW:
435471d10453SEric Joyner 		profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR;
435571d10453SEric Joyner 		rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID;
435671d10453SEric Joyner 		break;
435771d10453SEric Joyner 	case ICE_MAX_BW:
435871d10453SEric Joyner 		profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR;
435971d10453SEric Joyner 		rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID;
436071d10453SEric Joyner 		break;
436171d10453SEric Joyner 	case ICE_SHARED_BW:
436271d10453SEric Joyner 		profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL;
436371d10453SEric Joyner 		/* No SRL is configured for default case */
436471d10453SEric Joyner 		rl_prof_id = ICE_SCHED_NO_SHARED_RL_PROF_ID;
436571d10453SEric Joyner 		break;
436671d10453SEric Joyner 	default:
436771d10453SEric Joyner 		return ICE_ERR_PARAM;
436871d10453SEric Joyner 	}
436971d10453SEric Joyner 	/* Save existing RL prof ID for later clean up */
437071d10453SEric Joyner 	old_id = ice_sched_get_node_rl_prof_id(node, rl_type);
437171d10453SEric Joyner 	/* Configure BW scheduling parameters */
437271d10453SEric Joyner 	status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id);
437371d10453SEric Joyner 	if (status)
437471d10453SEric Joyner 		return status;
437571d10453SEric Joyner 
437671d10453SEric Joyner 	/* Remove stale RL profile ID */
437771d10453SEric Joyner 	if (old_id == ICE_SCHED_DFLT_RL_PROF_ID ||
437871d10453SEric Joyner 	    old_id == ICE_SCHED_INVAL_PROF_ID)
4379*f2635e84SEric Joyner 		return 0;
438071d10453SEric Joyner 
4381d08b8680SEric Joyner 	return ice_sched_rm_rl_profile(hw, layer_num, profile_type, old_id);
438271d10453SEric Joyner }
438371d10453SEric Joyner 
438471d10453SEric Joyner /**
438571d10453SEric Joyner  * ice_sched_set_node_bw - set node's bandwidth
438671d10453SEric Joyner  * @pi: port information structure
438771d10453SEric Joyner  * @node: tree node
438871d10453SEric Joyner  * @rl_type: rate limit type min, max, or shared
438971d10453SEric Joyner  * @bw: bandwidth in Kbps - Kilo bits per sec
439071d10453SEric Joyner  * @layer_num: layer number
439171d10453SEric Joyner  *
439271d10453SEric Joyner  * This function adds new profile corresponding to requested BW, configures
439371d10453SEric Joyner  * node's RL profile ID of type CIR, EIR, or SRL, and removes old profile
439471d10453SEric Joyner  * ID from local database. The caller needs to hold scheduler lock.
439571d10453SEric Joyner  */
4396*f2635e84SEric Joyner int
439771d10453SEric Joyner ice_sched_set_node_bw(struct ice_port_info *pi, struct ice_sched_node *node,
439871d10453SEric Joyner 		      enum ice_rl_type rl_type, u32 bw, u8 layer_num)
439971d10453SEric Joyner {
440071d10453SEric Joyner 	struct ice_aqc_rl_profile_info *rl_prof_info;
440171d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
440271d10453SEric Joyner 	u16 old_id, rl_prof_id;
4403*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
440471d10453SEric Joyner 
4405d08b8680SEric Joyner 	rl_prof_info = ice_sched_add_rl_profile(hw, rl_type, bw, layer_num);
440671d10453SEric Joyner 	if (!rl_prof_info)
440771d10453SEric Joyner 		return status;
440871d10453SEric Joyner 
440971d10453SEric Joyner 	rl_prof_id = LE16_TO_CPU(rl_prof_info->profile.profile_id);
441071d10453SEric Joyner 
441171d10453SEric Joyner 	/* Save existing RL prof ID for later clean up */
441271d10453SEric Joyner 	old_id = ice_sched_get_node_rl_prof_id(node, rl_type);
441371d10453SEric Joyner 	/* Configure BW scheduling parameters */
441471d10453SEric Joyner 	status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id);
441571d10453SEric Joyner 	if (status)
441671d10453SEric Joyner 		return status;
441771d10453SEric Joyner 
441871d10453SEric Joyner 	/* New changes has been applied */
441971d10453SEric Joyner 	/* Increment the profile ID reference count */
442071d10453SEric Joyner 	rl_prof_info->prof_id_ref++;
442171d10453SEric Joyner 
442271d10453SEric Joyner 	/* Check for old ID removal */
442371d10453SEric Joyner 	if ((old_id == ICE_SCHED_DFLT_RL_PROF_ID && rl_type != ICE_SHARED_BW) ||
442471d10453SEric Joyner 	    old_id == ICE_SCHED_INVAL_PROF_ID || old_id == rl_prof_id)
4425*f2635e84SEric Joyner 		return 0;
442671d10453SEric Joyner 
4427d08b8680SEric Joyner 	return ice_sched_rm_rl_profile(hw, layer_num,
44287d7af7f8SEric Joyner 				       rl_prof_info->profile.flags &
44297d7af7f8SEric Joyner 				       ICE_AQC_RL_PROFILE_TYPE_M, old_id);
443071d10453SEric Joyner }
443171d10453SEric Joyner 
443271d10453SEric Joyner /**
44339c30461dSEric Joyner  * ice_sched_set_node_priority - set node's priority
44349c30461dSEric Joyner  * @pi: port information structure
44359c30461dSEric Joyner  * @node: tree node
44369c30461dSEric Joyner  * @priority: number 0-7 representing priority among siblings
44379c30461dSEric Joyner  *
44389c30461dSEric Joyner  * This function sets priority of a node among it's siblings.
44399c30461dSEric Joyner  */
4440*f2635e84SEric Joyner int
44419c30461dSEric Joyner ice_sched_set_node_priority(struct ice_port_info *pi, struct ice_sched_node *node,
44429c30461dSEric Joyner 			    u16 priority)
44439c30461dSEric Joyner {
44449c30461dSEric Joyner 	struct ice_aqc_txsched_elem_data buf;
44459c30461dSEric Joyner 	struct ice_aqc_txsched_elem *data;
44469c30461dSEric Joyner 
44479c30461dSEric Joyner 	buf = node->info;
44489c30461dSEric Joyner 	data = &buf.data;
44499c30461dSEric Joyner 
44509c30461dSEric Joyner 	data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC;
44519c30461dSEric Joyner 	data->generic |= ICE_AQC_ELEM_GENERIC_PRIO_M &
44529c30461dSEric Joyner 			 (priority << ICE_AQC_ELEM_GENERIC_PRIO_S);
44539c30461dSEric Joyner 
44549c30461dSEric Joyner 	return ice_sched_update_elem(pi->hw, node, &buf);
44559c30461dSEric Joyner }
44569c30461dSEric Joyner 
44579c30461dSEric Joyner /**
44589c30461dSEric Joyner  * ice_sched_set_node_weight - set node's weight
44599c30461dSEric Joyner  * @pi: port information structure
44609c30461dSEric Joyner  * @node: tree node
44619c30461dSEric Joyner  * @weight: number 1-200 representing weight for WFQ
44629c30461dSEric Joyner  *
44639c30461dSEric Joyner  * This function sets weight of the node for WFQ algorithm.
44649c30461dSEric Joyner  */
4465*f2635e84SEric Joyner int
44669c30461dSEric Joyner ice_sched_set_node_weight(struct ice_port_info *pi, struct ice_sched_node *node, u16 weight)
44679c30461dSEric Joyner {
44689c30461dSEric Joyner 	struct ice_aqc_txsched_elem_data buf;
44699c30461dSEric Joyner 	struct ice_aqc_txsched_elem *data;
44709c30461dSEric Joyner 
44719c30461dSEric Joyner 	buf = node->info;
44729c30461dSEric Joyner 	data = &buf.data;
44739c30461dSEric Joyner 
44749c30461dSEric Joyner 	data->valid_sections = ICE_AQC_ELEM_VALID_CIR | ICE_AQC_ELEM_VALID_EIR |
44759c30461dSEric Joyner 			       ICE_AQC_ELEM_VALID_GENERIC;
44769c30461dSEric Joyner 	data->cir_bw.bw_alloc = CPU_TO_LE16(weight);
44779c30461dSEric Joyner 	data->eir_bw.bw_alloc = CPU_TO_LE16(weight);
44789c30461dSEric Joyner 	data->generic |= ICE_AQC_ELEM_GENERIC_SP_M &
44799c30461dSEric Joyner 			 (0x0 << ICE_AQC_ELEM_GENERIC_SP_S);
44809c30461dSEric Joyner 
44819c30461dSEric Joyner 	return ice_sched_update_elem(pi->hw, node, &buf);
44829c30461dSEric Joyner }
44839c30461dSEric Joyner 
44849c30461dSEric Joyner /**
448571d10453SEric Joyner  * ice_sched_set_node_bw_lmt - set node's BW limit
448671d10453SEric Joyner  * @pi: port information structure
448771d10453SEric Joyner  * @node: tree node
448871d10453SEric Joyner  * @rl_type: rate limit type min, max, or shared
448971d10453SEric Joyner  * @bw: bandwidth in Kbps - Kilo bits per sec
449071d10453SEric Joyner  *
449171d10453SEric Joyner  * It updates node's BW limit parameters like BW RL profile ID of type CIR,
449271d10453SEric Joyner  * EIR, or SRL. The caller needs to hold scheduler lock.
4493d08b8680SEric Joyner  *
4494d08b8680SEric Joyner  * NOTE: Caller provides the correct SRL node in case of shared profile
4495d08b8680SEric Joyner  * settings.
449671d10453SEric Joyner  */
4497*f2635e84SEric Joyner int
449871d10453SEric Joyner ice_sched_set_node_bw_lmt(struct ice_port_info *pi, struct ice_sched_node *node,
449971d10453SEric Joyner 			  enum ice_rl_type rl_type, u32 bw)
450071d10453SEric Joyner {
450171d10453SEric Joyner 	struct ice_hw *hw;
450271d10453SEric Joyner 	u8 layer_num;
450371d10453SEric Joyner 
450471d10453SEric Joyner 	if (!pi)
450571d10453SEric Joyner 		return ICE_ERR_PARAM;
450671d10453SEric Joyner 	hw = pi->hw;
450771d10453SEric Joyner 	/* Remove unused RL profile IDs from HW and SW DB */
4508d08b8680SEric Joyner 	ice_sched_rm_unused_rl_prof(hw);
4509d08b8680SEric Joyner 
451071d10453SEric Joyner 	layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
451171d10453SEric Joyner 						node->tx_sched_layer);
451271d10453SEric Joyner 	if (layer_num >= hw->num_tx_sched_layers)
451371d10453SEric Joyner 		return ICE_ERR_PARAM;
451471d10453SEric Joyner 
451571d10453SEric Joyner 	if (bw == ICE_SCHED_DFLT_BW)
4516d08b8680SEric Joyner 		return ice_sched_set_node_bw_dflt(pi, node, rl_type, layer_num);
4517d08b8680SEric Joyner 	return ice_sched_set_node_bw(pi, node, rl_type, bw, layer_num);
451871d10453SEric Joyner }
451971d10453SEric Joyner 
452071d10453SEric Joyner /**
452171d10453SEric Joyner  * ice_sched_set_node_bw_dflt_lmt - set node's BW limit to default
452271d10453SEric Joyner  * @pi: port information structure
452371d10453SEric Joyner  * @node: pointer to node structure
452471d10453SEric Joyner  * @rl_type: rate limit type min, max, or shared
452571d10453SEric Joyner  *
452671d10453SEric Joyner  * This function configures node element's BW rate limit profile ID of
452771d10453SEric Joyner  * type CIR, EIR, or SRL to default. This function needs to be called
452871d10453SEric Joyner  * with the scheduler lock held.
452971d10453SEric Joyner  */
4530*f2635e84SEric Joyner static int
453171d10453SEric Joyner ice_sched_set_node_bw_dflt_lmt(struct ice_port_info *pi,
453271d10453SEric Joyner 			       struct ice_sched_node *node,
453371d10453SEric Joyner 			       enum ice_rl_type rl_type)
453471d10453SEric Joyner {
453571d10453SEric Joyner 	return ice_sched_set_node_bw_lmt(pi, node, rl_type,
453671d10453SEric Joyner 					 ICE_SCHED_DFLT_BW);
453771d10453SEric Joyner }
453871d10453SEric Joyner 
453971d10453SEric Joyner /**
454071d10453SEric Joyner  * ice_sched_validate_srl_node - Check node for SRL applicability
454171d10453SEric Joyner  * @node: sched node to configure
454271d10453SEric Joyner  * @sel_layer: selected SRL layer
454371d10453SEric Joyner  *
454471d10453SEric Joyner  * This function checks if the SRL can be applied to a selceted layer node on
454571d10453SEric Joyner  * behalf of the requested node (first argument). This function needs to be
454671d10453SEric Joyner  * called with scheduler lock held.
454771d10453SEric Joyner  */
4548*f2635e84SEric Joyner static int
454971d10453SEric Joyner ice_sched_validate_srl_node(struct ice_sched_node *node, u8 sel_layer)
455071d10453SEric Joyner {
455171d10453SEric Joyner 	/* SRL profiles are not available on all layers. Check if the
455271d10453SEric Joyner 	 * SRL profile can be applied to a node above or below the
455371d10453SEric Joyner 	 * requested node. SRL configuration is possible only if the
455471d10453SEric Joyner 	 * selected layer's node has single child.
455571d10453SEric Joyner 	 */
455671d10453SEric Joyner 	if (sel_layer == node->tx_sched_layer ||
455771d10453SEric Joyner 	    ((sel_layer == node->tx_sched_layer + 1) &&
455871d10453SEric Joyner 	    node->num_children == 1) ||
455971d10453SEric Joyner 	    ((sel_layer == node->tx_sched_layer - 1) &&
456071d10453SEric Joyner 	    (node->parent && node->parent->num_children == 1)))
4561*f2635e84SEric Joyner 		return 0;
456271d10453SEric Joyner 
456371d10453SEric Joyner 	return ICE_ERR_CFG;
456471d10453SEric Joyner }
456571d10453SEric Joyner 
456671d10453SEric Joyner /**
456771d10453SEric Joyner  * ice_sched_save_q_bw - save queue node's BW information
456871d10453SEric Joyner  * @q_ctx: queue context structure
456971d10453SEric Joyner  * @rl_type: rate limit type min, max, or shared
457071d10453SEric Joyner  * @bw: bandwidth in Kbps - Kilo bits per sec
457171d10453SEric Joyner  *
457271d10453SEric Joyner  * Save BW information of queue type node for post replay use.
457371d10453SEric Joyner  */
4574*f2635e84SEric Joyner static int
457571d10453SEric Joyner ice_sched_save_q_bw(struct ice_q_ctx *q_ctx, enum ice_rl_type rl_type, u32 bw)
457671d10453SEric Joyner {
457771d10453SEric Joyner 	switch (rl_type) {
457871d10453SEric Joyner 	case ICE_MIN_BW:
457971d10453SEric Joyner 		ice_set_clear_cir_bw(&q_ctx->bw_t_info, bw);
458071d10453SEric Joyner 		break;
458171d10453SEric Joyner 	case ICE_MAX_BW:
458271d10453SEric Joyner 		ice_set_clear_eir_bw(&q_ctx->bw_t_info, bw);
458371d10453SEric Joyner 		break;
458471d10453SEric Joyner 	case ICE_SHARED_BW:
458571d10453SEric Joyner 		ice_set_clear_shared_bw(&q_ctx->bw_t_info, bw);
458671d10453SEric Joyner 		break;
458771d10453SEric Joyner 	default:
458871d10453SEric Joyner 		return ICE_ERR_PARAM;
458971d10453SEric Joyner 	}
4590*f2635e84SEric Joyner 	return 0;
459171d10453SEric Joyner }
459271d10453SEric Joyner 
459371d10453SEric Joyner /**
459471d10453SEric Joyner  * ice_sched_set_q_bw_lmt - sets queue BW limit
459571d10453SEric Joyner  * @pi: port information structure
459671d10453SEric Joyner  * @vsi_handle: sw VSI handle
459771d10453SEric Joyner  * @tc: traffic class
459871d10453SEric Joyner  * @q_handle: software queue handle
459971d10453SEric Joyner  * @rl_type: min, max, or shared
460071d10453SEric Joyner  * @bw: bandwidth in Kbps
460171d10453SEric Joyner  *
460271d10453SEric Joyner  * This function sets BW limit of queue scheduling node.
460371d10453SEric Joyner  */
4604*f2635e84SEric Joyner static int
460571d10453SEric Joyner ice_sched_set_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
460671d10453SEric Joyner 		       u16 q_handle, enum ice_rl_type rl_type, u32 bw)
460771d10453SEric Joyner {
460871d10453SEric Joyner 	struct ice_sched_node *node;
460971d10453SEric Joyner 	struct ice_q_ctx *q_ctx;
4610*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
461171d10453SEric Joyner 
461271d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
461371d10453SEric Joyner 		return ICE_ERR_PARAM;
461471d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
461571d10453SEric Joyner 	q_ctx = ice_get_lan_q_ctx(pi->hw, vsi_handle, tc, q_handle);
461671d10453SEric Joyner 	if (!q_ctx)
461771d10453SEric Joyner 		goto exit_q_bw_lmt;
461871d10453SEric Joyner 	node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid);
461971d10453SEric Joyner 	if (!node) {
462071d10453SEric Joyner 		ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong q_teid\n");
462171d10453SEric Joyner 		goto exit_q_bw_lmt;
462271d10453SEric Joyner 	}
462371d10453SEric Joyner 
462471d10453SEric Joyner 	/* Return error if it is not a leaf node */
462571d10453SEric Joyner 	if (node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF)
462671d10453SEric Joyner 		goto exit_q_bw_lmt;
462771d10453SEric Joyner 
462871d10453SEric Joyner 	/* SRL bandwidth layer selection */
462971d10453SEric Joyner 	if (rl_type == ICE_SHARED_BW) {
463071d10453SEric Joyner 		u8 sel_layer; /* selected layer */
463171d10453SEric Joyner 
463271d10453SEric Joyner 		sel_layer = ice_sched_get_rl_prof_layer(pi, rl_type,
463371d10453SEric Joyner 							node->tx_sched_layer);
463471d10453SEric Joyner 		if (sel_layer >= pi->hw->num_tx_sched_layers) {
463571d10453SEric Joyner 			status = ICE_ERR_PARAM;
463671d10453SEric Joyner 			goto exit_q_bw_lmt;
463771d10453SEric Joyner 		}
463871d10453SEric Joyner 		status = ice_sched_validate_srl_node(node, sel_layer);
463971d10453SEric Joyner 		if (status)
464071d10453SEric Joyner 			goto exit_q_bw_lmt;
464171d10453SEric Joyner 	}
464271d10453SEric Joyner 
464371d10453SEric Joyner 	if (bw == ICE_SCHED_DFLT_BW)
464471d10453SEric Joyner 		status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type);
464571d10453SEric Joyner 	else
464671d10453SEric Joyner 		status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw);
464771d10453SEric Joyner 
464871d10453SEric Joyner 	if (!status)
464971d10453SEric Joyner 		status = ice_sched_save_q_bw(q_ctx, rl_type, bw);
465071d10453SEric Joyner 
465171d10453SEric Joyner exit_q_bw_lmt:
465271d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
465371d10453SEric Joyner 	return status;
465471d10453SEric Joyner }
465571d10453SEric Joyner 
465671d10453SEric Joyner /**
465771d10453SEric Joyner  * ice_cfg_q_bw_lmt - configure queue BW limit
465871d10453SEric Joyner  * @pi: port information structure
465971d10453SEric Joyner  * @vsi_handle: sw VSI handle
466071d10453SEric Joyner  * @tc: traffic class
466171d10453SEric Joyner  * @q_handle: software queue handle
466271d10453SEric Joyner  * @rl_type: min, max, or shared
466371d10453SEric Joyner  * @bw: bandwidth in Kbps
466471d10453SEric Joyner  *
466571d10453SEric Joyner  * This function configures BW limit of queue scheduling node.
466671d10453SEric Joyner  */
4667*f2635e84SEric Joyner int
466871d10453SEric Joyner ice_cfg_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
466971d10453SEric Joyner 		 u16 q_handle, enum ice_rl_type rl_type, u32 bw)
467071d10453SEric Joyner {
467171d10453SEric Joyner 	return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type,
467271d10453SEric Joyner 				      bw);
467371d10453SEric Joyner }
467471d10453SEric Joyner 
467571d10453SEric Joyner /**
467671d10453SEric Joyner  * ice_cfg_q_bw_dflt_lmt - configure queue BW default limit
467771d10453SEric Joyner  * @pi: port information structure
467871d10453SEric Joyner  * @vsi_handle: sw VSI handle
467971d10453SEric Joyner  * @tc: traffic class
468071d10453SEric Joyner  * @q_handle: software queue handle
468171d10453SEric Joyner  * @rl_type: min, max, or shared
468271d10453SEric Joyner  *
468371d10453SEric Joyner  * This function configures BW default limit of queue scheduling node.
468471d10453SEric Joyner  */
4685*f2635e84SEric Joyner int
468671d10453SEric Joyner ice_cfg_q_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
468771d10453SEric Joyner 		      u16 q_handle, enum ice_rl_type rl_type)
468871d10453SEric Joyner {
468971d10453SEric Joyner 	return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type,
469071d10453SEric Joyner 				      ICE_SCHED_DFLT_BW);
469171d10453SEric Joyner }
469271d10453SEric Joyner 
469371d10453SEric Joyner /**
469471d10453SEric Joyner  * ice_sched_save_tc_node_bw - save TC node BW limit
469571d10453SEric Joyner  * @pi: port information structure
469671d10453SEric Joyner  * @tc: TC number
469771d10453SEric Joyner  * @rl_type: min or max
469871d10453SEric Joyner  * @bw: bandwidth in Kbps
469971d10453SEric Joyner  *
470071d10453SEric Joyner  * This function saves the modified values of bandwidth settings for later
470171d10453SEric Joyner  * replay purpose (restore) after reset.
470271d10453SEric Joyner  */
4703*f2635e84SEric Joyner static int
470471d10453SEric Joyner ice_sched_save_tc_node_bw(struct ice_port_info *pi, u8 tc,
470571d10453SEric Joyner 			  enum ice_rl_type rl_type, u32 bw)
470671d10453SEric Joyner {
470771d10453SEric Joyner 	if (tc >= ICE_MAX_TRAFFIC_CLASS)
470871d10453SEric Joyner 		return ICE_ERR_PARAM;
470971d10453SEric Joyner 	switch (rl_type) {
471071d10453SEric Joyner 	case ICE_MIN_BW:
471171d10453SEric Joyner 		ice_set_clear_cir_bw(&pi->tc_node_bw_t_info[tc], bw);
471271d10453SEric Joyner 		break;
471371d10453SEric Joyner 	case ICE_MAX_BW:
471471d10453SEric Joyner 		ice_set_clear_eir_bw(&pi->tc_node_bw_t_info[tc], bw);
471571d10453SEric Joyner 		break;
471671d10453SEric Joyner 	case ICE_SHARED_BW:
471771d10453SEric Joyner 		ice_set_clear_shared_bw(&pi->tc_node_bw_t_info[tc], bw);
471871d10453SEric Joyner 		break;
471971d10453SEric Joyner 	default:
472071d10453SEric Joyner 		return ICE_ERR_PARAM;
472171d10453SEric Joyner 	}
4722*f2635e84SEric Joyner 	return 0;
472371d10453SEric Joyner }
472471d10453SEric Joyner 
4725*f2635e84SEric Joyner #define ICE_SCHED_GENERIC_STRICT_MODE		BIT(4)
4726*f2635e84SEric Joyner #define ICE_SCHED_GENERIC_PRIO_S		1
4727*f2635e84SEric Joyner 
472871d10453SEric Joyner /**
472971d10453SEric Joyner  * ice_sched_set_tc_node_bw_lmt - sets TC node BW limit
473071d10453SEric Joyner  * @pi: port information structure
473171d10453SEric Joyner  * @tc: TC number
473271d10453SEric Joyner  * @rl_type: min or max
473371d10453SEric Joyner  * @bw: bandwidth in Kbps
473471d10453SEric Joyner  *
473571d10453SEric Joyner  * This function configures bandwidth limit of TC node.
473671d10453SEric Joyner  */
4737*f2635e84SEric Joyner static int
473871d10453SEric Joyner ice_sched_set_tc_node_bw_lmt(struct ice_port_info *pi, u8 tc,
473971d10453SEric Joyner 			     enum ice_rl_type rl_type, u32 bw)
474071d10453SEric Joyner {
4741*f2635e84SEric Joyner 	struct ice_aqc_txsched_elem_data buf;
4742*f2635e84SEric Joyner 	struct ice_aqc_txsched_elem *data;
474371d10453SEric Joyner 	struct ice_sched_node *tc_node;
4744*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
474571d10453SEric Joyner 
474671d10453SEric Joyner 	if (tc >= ICE_MAX_TRAFFIC_CLASS)
474771d10453SEric Joyner 		return status;
474871d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
474971d10453SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
475071d10453SEric Joyner 	if (!tc_node)
475171d10453SEric Joyner 		goto exit_set_tc_node_bw;
4752*f2635e84SEric Joyner 
4753*f2635e84SEric Joyner 	/* update node's generic field */
4754*f2635e84SEric Joyner 	buf = tc_node->info;
4755*f2635e84SEric Joyner 	data = &buf.data;
4756*f2635e84SEric Joyner 	data->valid_sections = ICE_AQC_ELEM_VALID_GENERIC;
4757*f2635e84SEric Joyner 	data->generic = (tc << ICE_SCHED_GENERIC_PRIO_S) |
4758*f2635e84SEric Joyner 		ICE_SCHED_GENERIC_STRICT_MODE;
4759*f2635e84SEric Joyner 	status = ice_sched_update_elem(pi->hw, tc_node, &buf);
4760*f2635e84SEric Joyner 	if (status)
4761*f2635e84SEric Joyner 		goto exit_set_tc_node_bw;
4762*f2635e84SEric Joyner 
476371d10453SEric Joyner 	if (bw == ICE_SCHED_DFLT_BW)
476471d10453SEric Joyner 		status = ice_sched_set_node_bw_dflt_lmt(pi, tc_node, rl_type);
476571d10453SEric Joyner 	else
476671d10453SEric Joyner 		status = ice_sched_set_node_bw_lmt(pi, tc_node, rl_type, bw);
476771d10453SEric Joyner 	if (!status)
476871d10453SEric Joyner 		status = ice_sched_save_tc_node_bw(pi, tc, rl_type, bw);
476971d10453SEric Joyner 
477071d10453SEric Joyner exit_set_tc_node_bw:
477171d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
477271d10453SEric Joyner 	return status;
477371d10453SEric Joyner }
477471d10453SEric Joyner 
477571d10453SEric Joyner /**
477671d10453SEric Joyner  * ice_cfg_tc_node_bw_lmt - configure TC node BW limit
477771d10453SEric Joyner  * @pi: port information structure
477871d10453SEric Joyner  * @tc: TC number
477971d10453SEric Joyner  * @rl_type: min or max
478071d10453SEric Joyner  * @bw: bandwidth in Kbps
478171d10453SEric Joyner  *
478271d10453SEric Joyner  * This function configures BW limit of TC node.
478371d10453SEric Joyner  * Note: The minimum guaranteed reservation is done via DCBX.
478471d10453SEric Joyner  */
4785*f2635e84SEric Joyner int
478671d10453SEric Joyner ice_cfg_tc_node_bw_lmt(struct ice_port_info *pi, u8 tc,
478771d10453SEric Joyner 		       enum ice_rl_type rl_type, u32 bw)
478871d10453SEric Joyner {
478971d10453SEric Joyner 	return ice_sched_set_tc_node_bw_lmt(pi, tc, rl_type, bw);
479071d10453SEric Joyner }
479171d10453SEric Joyner 
479271d10453SEric Joyner /**
479371d10453SEric Joyner  * ice_cfg_tc_node_bw_dflt_lmt - configure TC node BW default limit
479471d10453SEric Joyner  * @pi: port information structure
479571d10453SEric Joyner  * @tc: TC number
479671d10453SEric Joyner  * @rl_type: min or max
479771d10453SEric Joyner  *
479871d10453SEric Joyner  * This function configures BW default limit of TC node.
479971d10453SEric Joyner  */
4800*f2635e84SEric Joyner int
480171d10453SEric Joyner ice_cfg_tc_node_bw_dflt_lmt(struct ice_port_info *pi, u8 tc,
480271d10453SEric Joyner 			    enum ice_rl_type rl_type)
480371d10453SEric Joyner {
480471d10453SEric Joyner 	return ice_sched_set_tc_node_bw_lmt(pi, tc, rl_type, ICE_SCHED_DFLT_BW);
480571d10453SEric Joyner }
480671d10453SEric Joyner 
480771d10453SEric Joyner /**
480871d10453SEric Joyner  * ice_sched_save_tc_node_bw_alloc - save TC node's BW alloc information
480971d10453SEric Joyner  * @pi: port information structure
481071d10453SEric Joyner  * @tc: traffic class
481171d10453SEric Joyner  * @rl_type: rate limit type min or max
481271d10453SEric Joyner  * @bw_alloc: Bandwidth allocation information
481371d10453SEric Joyner  *
481471d10453SEric Joyner  * Save BW alloc information of VSI type node for post replay use.
481571d10453SEric Joyner  */
4816*f2635e84SEric Joyner static int
481771d10453SEric Joyner ice_sched_save_tc_node_bw_alloc(struct ice_port_info *pi, u8 tc,
481871d10453SEric Joyner 				enum ice_rl_type rl_type, u16 bw_alloc)
481971d10453SEric Joyner {
482071d10453SEric Joyner 	if (tc >= ICE_MAX_TRAFFIC_CLASS)
482171d10453SEric Joyner 		return ICE_ERR_PARAM;
482271d10453SEric Joyner 	switch (rl_type) {
482371d10453SEric Joyner 	case ICE_MIN_BW:
482471d10453SEric Joyner 		ice_set_clear_cir_bw_alloc(&pi->tc_node_bw_t_info[tc],
482571d10453SEric Joyner 					   bw_alloc);
482671d10453SEric Joyner 		break;
482771d10453SEric Joyner 	case ICE_MAX_BW:
482871d10453SEric Joyner 		ice_set_clear_eir_bw_alloc(&pi->tc_node_bw_t_info[tc],
482971d10453SEric Joyner 					   bw_alloc);
483071d10453SEric Joyner 		break;
483171d10453SEric Joyner 	default:
483271d10453SEric Joyner 		return ICE_ERR_PARAM;
483371d10453SEric Joyner 	}
4834*f2635e84SEric Joyner 	return 0;
483571d10453SEric Joyner }
483671d10453SEric Joyner 
483771d10453SEric Joyner /**
483871d10453SEric Joyner  * ice_sched_set_tc_node_bw_alloc - set TC node BW alloc
483971d10453SEric Joyner  * @pi: port information structure
484071d10453SEric Joyner  * @tc: TC number
484171d10453SEric Joyner  * @rl_type: min or max
484271d10453SEric Joyner  * @bw_alloc: bandwidth alloc
484371d10453SEric Joyner  *
484471d10453SEric Joyner  * This function configures bandwidth alloc of TC node, also saves the
484571d10453SEric Joyner  * changed settings for replay purpose, and return success if it succeeds
484671d10453SEric Joyner  * in modifying bandwidth alloc setting.
484771d10453SEric Joyner  */
4848*f2635e84SEric Joyner static int
484971d10453SEric Joyner ice_sched_set_tc_node_bw_alloc(struct ice_port_info *pi, u8 tc,
485071d10453SEric Joyner 			       enum ice_rl_type rl_type, u8 bw_alloc)
485171d10453SEric Joyner {
485271d10453SEric Joyner 	struct ice_sched_node *tc_node;
4853*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
485471d10453SEric Joyner 
485571d10453SEric Joyner 	if (tc >= ICE_MAX_TRAFFIC_CLASS)
485671d10453SEric Joyner 		return status;
485771d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
485871d10453SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
485971d10453SEric Joyner 	if (!tc_node)
486071d10453SEric Joyner 		goto exit_set_tc_node_bw_alloc;
486171d10453SEric Joyner 	status = ice_sched_cfg_node_bw_alloc(pi->hw, tc_node, rl_type,
486271d10453SEric Joyner 					     bw_alloc);
486371d10453SEric Joyner 	if (status)
486471d10453SEric Joyner 		goto exit_set_tc_node_bw_alloc;
486571d10453SEric Joyner 	status = ice_sched_save_tc_node_bw_alloc(pi, tc, rl_type, bw_alloc);
486671d10453SEric Joyner 
486771d10453SEric Joyner exit_set_tc_node_bw_alloc:
486871d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
486971d10453SEric Joyner 	return status;
487071d10453SEric Joyner }
487171d10453SEric Joyner 
487271d10453SEric Joyner /**
487371d10453SEric Joyner  * ice_cfg_tc_node_bw_alloc - configure TC node BW alloc
487471d10453SEric Joyner  * @pi: port information structure
487571d10453SEric Joyner  * @tc: TC number
487671d10453SEric Joyner  * @rl_type: min or max
487771d10453SEric Joyner  * @bw_alloc: bandwidth alloc
487871d10453SEric Joyner  *
487971d10453SEric Joyner  * This function configures BW limit of TC node.
488071d10453SEric Joyner  * Note: The minimum guaranteed reservation is done via DCBX.
488171d10453SEric Joyner  */
4882*f2635e84SEric Joyner int
488371d10453SEric Joyner ice_cfg_tc_node_bw_alloc(struct ice_port_info *pi, u8 tc,
488471d10453SEric Joyner 			 enum ice_rl_type rl_type, u8 bw_alloc)
488571d10453SEric Joyner {
488671d10453SEric Joyner 	return ice_sched_set_tc_node_bw_alloc(pi, tc, rl_type, bw_alloc);
488771d10453SEric Joyner }
488871d10453SEric Joyner 
488971d10453SEric Joyner /**
489071d10453SEric Joyner  * ice_sched_set_agg_bw_dflt_lmt - set aggregator node's BW limit to default
489171d10453SEric Joyner  * @pi: port information structure
489271d10453SEric Joyner  * @vsi_handle: software VSI handle
489371d10453SEric Joyner  *
489471d10453SEric Joyner  * This function retrieves the aggregator ID based on VSI ID and TC,
489571d10453SEric Joyner  * and sets node's BW limit to default. This function needs to be
489671d10453SEric Joyner  * called with the scheduler lock held.
489771d10453SEric Joyner  */
4898*f2635e84SEric Joyner int
489971d10453SEric Joyner ice_sched_set_agg_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle)
490071d10453SEric Joyner {
490171d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
4902*f2635e84SEric Joyner 	int status = 0;
490371d10453SEric Joyner 	u8 tc;
490471d10453SEric Joyner 
490571d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
490671d10453SEric Joyner 		return ICE_ERR_PARAM;
490771d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
490871d10453SEric Joyner 	if (!vsi_ctx)
490971d10453SEric Joyner 		return ICE_ERR_PARAM;
491071d10453SEric Joyner 
491171d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
491271d10453SEric Joyner 		struct ice_sched_node *node;
491371d10453SEric Joyner 
491471d10453SEric Joyner 		node = vsi_ctx->sched.ag_node[tc];
491571d10453SEric Joyner 		if (!node)
491671d10453SEric Joyner 			continue;
491771d10453SEric Joyner 
491871d10453SEric Joyner 		/* Set min profile to default */
491971d10453SEric Joyner 		status = ice_sched_set_node_bw_dflt_lmt(pi, node, ICE_MIN_BW);
492071d10453SEric Joyner 		if (status)
492171d10453SEric Joyner 			break;
492271d10453SEric Joyner 
492371d10453SEric Joyner 		/* Set max profile to default */
492471d10453SEric Joyner 		status = ice_sched_set_node_bw_dflt_lmt(pi, node, ICE_MAX_BW);
492571d10453SEric Joyner 		if (status)
492671d10453SEric Joyner 			break;
492771d10453SEric Joyner 
492871d10453SEric Joyner 		/* Remove shared profile, if there is one */
492971d10453SEric Joyner 		status = ice_sched_set_node_bw_dflt_lmt(pi, node,
493071d10453SEric Joyner 							ICE_SHARED_BW);
493171d10453SEric Joyner 		if (status)
493271d10453SEric Joyner 			break;
493371d10453SEric Joyner 	}
493471d10453SEric Joyner 
493571d10453SEric Joyner 	return status;
493671d10453SEric Joyner }
493771d10453SEric Joyner 
493871d10453SEric Joyner /**
493971d10453SEric Joyner  * ice_sched_get_node_by_id_type - get node from ID type
494071d10453SEric Joyner  * @pi: port information structure
494171d10453SEric Joyner  * @id: identifier
494271d10453SEric Joyner  * @agg_type: type of aggregator
494371d10453SEric Joyner  * @tc: traffic class
494471d10453SEric Joyner  *
494571d10453SEric Joyner  * This function returns node identified by ID of type aggregator, and
494671d10453SEric Joyner  * based on traffic class (TC). This function needs to be called with
494771d10453SEric Joyner  * the scheduler lock held.
494871d10453SEric Joyner  */
494971d10453SEric Joyner static struct ice_sched_node *
495071d10453SEric Joyner ice_sched_get_node_by_id_type(struct ice_port_info *pi, u32 id,
495171d10453SEric Joyner 			      enum ice_agg_type agg_type, u8 tc)
495271d10453SEric Joyner {
495371d10453SEric Joyner 	struct ice_sched_node *node = NULL;
495471d10453SEric Joyner 
495571d10453SEric Joyner 	switch (agg_type) {
495671d10453SEric Joyner 	case ICE_AGG_TYPE_VSI: {
495771d10453SEric Joyner 		struct ice_vsi_ctx *vsi_ctx;
495871d10453SEric Joyner 		u16 vsi_handle = (u16)id;
495971d10453SEric Joyner 
496071d10453SEric Joyner 		if (!ice_is_vsi_valid(pi->hw, vsi_handle))
496171d10453SEric Joyner 			break;
496271d10453SEric Joyner 		/* Get sched_vsi_info */
496371d10453SEric Joyner 		vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
496471d10453SEric Joyner 		if (!vsi_ctx)
496571d10453SEric Joyner 			break;
496671d10453SEric Joyner 		node = vsi_ctx->sched.vsi_node[tc];
496771d10453SEric Joyner 		break;
496871d10453SEric Joyner 	}
496971d10453SEric Joyner 
497071d10453SEric Joyner 	case ICE_AGG_TYPE_AGG: {
497171d10453SEric Joyner 		struct ice_sched_node *tc_node;
497271d10453SEric Joyner 
497371d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, tc);
497471d10453SEric Joyner 		if (tc_node)
497571d10453SEric Joyner 			node = ice_sched_get_agg_node(pi, tc_node, id);
497671d10453SEric Joyner 		break;
497771d10453SEric Joyner 	}
497871d10453SEric Joyner 
497971d10453SEric Joyner 	case ICE_AGG_TYPE_Q:
498071d10453SEric Joyner 		/* The current implementation allows single queue to modify */
49818923de59SPiotr Kubaj 		node = ice_sched_find_node_by_teid(pi->root, id);
498271d10453SEric Joyner 		break;
498371d10453SEric Joyner 
49848923de59SPiotr Kubaj 	case ICE_AGG_TYPE_QG: {
49858923de59SPiotr Kubaj 		struct ice_sched_node *child_node;
49868923de59SPiotr Kubaj 
498771d10453SEric Joyner 		/* The current implementation allows single qg to modify */
49888923de59SPiotr Kubaj 		child_node = ice_sched_find_node_by_teid(pi->root, id);
498971d10453SEric Joyner 		if (!child_node)
499071d10453SEric Joyner 			break;
499171d10453SEric Joyner 		node = child_node->parent;
499271d10453SEric Joyner 		break;
49938923de59SPiotr Kubaj 	}
499471d10453SEric Joyner 
499571d10453SEric Joyner 	default:
499671d10453SEric Joyner 		break;
499771d10453SEric Joyner 	}
499871d10453SEric Joyner 
499971d10453SEric Joyner 	return node;
500071d10453SEric Joyner }
500171d10453SEric Joyner 
500271d10453SEric Joyner /**
500371d10453SEric Joyner  * ice_sched_set_node_bw_lmt_per_tc - set node BW limit per TC
500471d10453SEric Joyner  * @pi: port information structure
500571d10453SEric Joyner  * @id: ID (software VSI handle or AGG ID)
500671d10453SEric Joyner  * @agg_type: aggregator type (VSI or AGG type node)
500771d10453SEric Joyner  * @tc: traffic class
500871d10453SEric Joyner  * @rl_type: min or max
500971d10453SEric Joyner  * @bw: bandwidth in Kbps
501071d10453SEric Joyner  *
501171d10453SEric Joyner  * This function sets BW limit of VSI or Aggregator scheduling node
501271d10453SEric Joyner  * based on TC information from passed in argument BW.
501371d10453SEric Joyner  */
5014*f2635e84SEric Joyner int
501571d10453SEric Joyner ice_sched_set_node_bw_lmt_per_tc(struct ice_port_info *pi, u32 id,
501671d10453SEric Joyner 				 enum ice_agg_type agg_type, u8 tc,
501771d10453SEric Joyner 				 enum ice_rl_type rl_type, u32 bw)
501871d10453SEric Joyner {
501971d10453SEric Joyner 	struct ice_sched_node *node;
5020*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
502171d10453SEric Joyner 
502271d10453SEric Joyner 	if (!pi)
502371d10453SEric Joyner 		return status;
502471d10453SEric Joyner 
502571d10453SEric Joyner 	if (rl_type == ICE_UNKNOWN_BW)
502671d10453SEric Joyner 		return status;
502771d10453SEric Joyner 
502871d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
502971d10453SEric Joyner 	node = ice_sched_get_node_by_id_type(pi, id, agg_type, tc);
503071d10453SEric Joyner 	if (!node) {
503171d10453SEric Joyner 		ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong id, agg type, or tc\n");
503271d10453SEric Joyner 		goto exit_set_node_bw_lmt_per_tc;
503371d10453SEric Joyner 	}
503471d10453SEric Joyner 	if (bw == ICE_SCHED_DFLT_BW)
503571d10453SEric Joyner 		status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type);
503671d10453SEric Joyner 	else
503771d10453SEric Joyner 		status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw);
503871d10453SEric Joyner 
503971d10453SEric Joyner exit_set_node_bw_lmt_per_tc:
504071d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
504171d10453SEric Joyner 	return status;
504271d10453SEric Joyner }
504371d10453SEric Joyner 
504471d10453SEric Joyner /**
504571d10453SEric Joyner  * ice_sched_validate_vsi_srl_node - validate VSI SRL node
504671d10453SEric Joyner  * @pi: port information structure
504771d10453SEric Joyner  * @vsi_handle: software VSI handle
504871d10453SEric Joyner  *
504971d10453SEric Joyner  * This function validates SRL node of the VSI node if available SRL layer is
505071d10453SEric Joyner  * different than the VSI node layer on all TC(s).This function needs to be
505171d10453SEric Joyner  * called with scheduler lock held.
505271d10453SEric Joyner  */
5053*f2635e84SEric Joyner static int
505471d10453SEric Joyner ice_sched_validate_vsi_srl_node(struct ice_port_info *pi, u16 vsi_handle)
505571d10453SEric Joyner {
505671d10453SEric Joyner 	u8 sel_layer = ICE_SCHED_INVAL_LAYER_NUM;
505771d10453SEric Joyner 	u8 tc;
505871d10453SEric Joyner 
505971d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
506071d10453SEric Joyner 		return ICE_ERR_PARAM;
506171d10453SEric Joyner 
506271d10453SEric Joyner 	/* Return success if no nodes are present across TC */
506371d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
506471d10453SEric Joyner 		struct ice_sched_node *tc_node, *vsi_node;
506571d10453SEric Joyner 		enum ice_rl_type rl_type = ICE_SHARED_BW;
5066*f2635e84SEric Joyner 		int status;
506771d10453SEric Joyner 
506871d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, tc);
506971d10453SEric Joyner 		if (!tc_node)
507071d10453SEric Joyner 			continue;
507171d10453SEric Joyner 
507271d10453SEric Joyner 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
507371d10453SEric Joyner 		if (!vsi_node)
507471d10453SEric Joyner 			continue;
507571d10453SEric Joyner 
507671d10453SEric Joyner 		/* SRL bandwidth layer selection */
507771d10453SEric Joyner 		if (sel_layer == ICE_SCHED_INVAL_LAYER_NUM) {
507871d10453SEric Joyner 			u8 node_layer = vsi_node->tx_sched_layer;
507971d10453SEric Joyner 			u8 layer_num;
508071d10453SEric Joyner 
508171d10453SEric Joyner 			layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
508271d10453SEric Joyner 								node_layer);
508371d10453SEric Joyner 			if (layer_num >= pi->hw->num_tx_sched_layers)
508471d10453SEric Joyner 				return ICE_ERR_PARAM;
508571d10453SEric Joyner 			sel_layer = layer_num;
508671d10453SEric Joyner 		}
508771d10453SEric Joyner 
508871d10453SEric Joyner 		status = ice_sched_validate_srl_node(vsi_node, sel_layer);
508971d10453SEric Joyner 		if (status)
509071d10453SEric Joyner 			return status;
509171d10453SEric Joyner 	}
5092*f2635e84SEric Joyner 	return 0;
509371d10453SEric Joyner }
509471d10453SEric Joyner 
509571d10453SEric Joyner /**
5096d08b8680SEric Joyner  * ice_sched_set_save_vsi_srl_node_bw - set VSI shared limit values
5097d08b8680SEric Joyner  * @pi: port information structure
5098d08b8680SEric Joyner  * @vsi_handle: software VSI handle
5099d08b8680SEric Joyner  * @tc: traffic class
5100d08b8680SEric Joyner  * @srl_node: sched node to configure
5101d08b8680SEric Joyner  * @rl_type: rate limit type minimum, maximum, or shared
5102d08b8680SEric Joyner  * @bw: minimum, maximum, or shared bandwidth in Kbps
5103d08b8680SEric Joyner  *
5104d08b8680SEric Joyner  * Configure shared rate limiter(SRL) of VSI type nodes across given traffic
5105d08b8680SEric Joyner  * class, and saves those value for later use for replaying purposes. The
5106d08b8680SEric Joyner  * caller holds the scheduler lock.
5107d08b8680SEric Joyner  */
5108*f2635e84SEric Joyner static int
5109d08b8680SEric Joyner ice_sched_set_save_vsi_srl_node_bw(struct ice_port_info *pi, u16 vsi_handle,
5110d08b8680SEric Joyner 				   u8 tc, struct ice_sched_node *srl_node,
5111d08b8680SEric Joyner 				   enum ice_rl_type rl_type, u32 bw)
5112d08b8680SEric Joyner {
5113*f2635e84SEric Joyner 	int status;
5114d08b8680SEric Joyner 
5115d08b8680SEric Joyner 	if (bw == ICE_SCHED_DFLT_BW) {
5116d08b8680SEric Joyner 		status = ice_sched_set_node_bw_dflt_lmt(pi, srl_node, rl_type);
5117d08b8680SEric Joyner 	} else {
5118d08b8680SEric Joyner 		status = ice_sched_set_node_bw_lmt(pi, srl_node, rl_type, bw);
5119d08b8680SEric Joyner 		if (status)
5120d08b8680SEric Joyner 			return status;
5121d08b8680SEric Joyner 		status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, bw);
5122d08b8680SEric Joyner 	}
5123d08b8680SEric Joyner 	return status;
5124d08b8680SEric Joyner }
5125d08b8680SEric Joyner 
5126d08b8680SEric Joyner /**
5127d08b8680SEric Joyner  * ice_sched_set_vsi_node_srl_per_tc - set VSI node BW shared limit for tc
5128d08b8680SEric Joyner  * @pi: port information structure
5129d08b8680SEric Joyner  * @vsi_handle: software VSI handle
5130d08b8680SEric Joyner  * @tc: traffic class
5131d08b8680SEric Joyner  * @min_bw: minimum bandwidth in Kbps
5132d08b8680SEric Joyner  * @max_bw: maximum bandwidth in Kbps
5133d08b8680SEric Joyner  * @shared_bw: shared bandwidth in Kbps
5134d08b8680SEric Joyner  *
5135d08b8680SEric Joyner  * Configure shared rate limiter(SRL) of  VSI type nodes across requested
5136d08b8680SEric Joyner  * traffic class for VSI matching handle. When BW value of ICE_SCHED_DFLT_BW
5137d08b8680SEric Joyner  * is passed, it removes the corresponding bw from the node. The caller
5138d08b8680SEric Joyner  * holds scheduler lock.
5139d08b8680SEric Joyner  */
5140*f2635e84SEric Joyner static int
5141d08b8680SEric Joyner ice_sched_set_vsi_node_srl_per_tc(struct ice_port_info *pi, u16 vsi_handle,
5142d08b8680SEric Joyner 				  u8 tc, u32 min_bw, u32 max_bw, u32 shared_bw)
5143d08b8680SEric Joyner {
5144d08b8680SEric Joyner 	struct ice_sched_node *tc_node, *vsi_node, *cfg_node;
5145d08b8680SEric Joyner 	u8 layer_num;
5146*f2635e84SEric Joyner 	int status;
5147d08b8680SEric Joyner 
5148d08b8680SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
5149d08b8680SEric Joyner 	if (!tc_node)
5150d08b8680SEric Joyner 		return ICE_ERR_CFG;
5151d08b8680SEric Joyner 
5152d08b8680SEric Joyner 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
5153d08b8680SEric Joyner 	if (!vsi_node)
5154d08b8680SEric Joyner 		return ICE_ERR_CFG;
5155d08b8680SEric Joyner 
5156d08b8680SEric Joyner 	layer_num = ice_sched_get_rl_prof_layer(pi, ICE_SHARED_BW,
5157d08b8680SEric Joyner 						vsi_node->tx_sched_layer);
5158d08b8680SEric Joyner 	if (layer_num >= pi->hw->num_tx_sched_layers)
5159d08b8680SEric Joyner 		return ICE_ERR_PARAM;
5160d08b8680SEric Joyner 
5161d08b8680SEric Joyner 	/* SRL node may be different */
5162d08b8680SEric Joyner 	cfg_node = ice_sched_get_srl_node(vsi_node, layer_num);
5163d08b8680SEric Joyner 	if (!cfg_node)
5164d08b8680SEric Joyner 		return ICE_ERR_CFG;
5165d08b8680SEric Joyner 
5166d08b8680SEric Joyner 	status = ice_sched_set_save_vsi_srl_node_bw(pi, vsi_handle, tc,
5167d08b8680SEric Joyner 						    cfg_node, ICE_MIN_BW,
5168d08b8680SEric Joyner 						    min_bw);
5169d08b8680SEric Joyner 	if (status)
5170d08b8680SEric Joyner 		return status;
5171d08b8680SEric Joyner 
5172d08b8680SEric Joyner 	status = ice_sched_set_save_vsi_srl_node_bw(pi, vsi_handle, tc,
5173d08b8680SEric Joyner 						    cfg_node, ICE_MAX_BW,
5174d08b8680SEric Joyner 						    max_bw);
5175d08b8680SEric Joyner 	if (status)
5176d08b8680SEric Joyner 		return status;
5177d08b8680SEric Joyner 
5178d08b8680SEric Joyner 	return ice_sched_set_save_vsi_srl_node_bw(pi, vsi_handle, tc, cfg_node,
5179d08b8680SEric Joyner 						  ICE_SHARED_BW, shared_bw);
5180d08b8680SEric Joyner }
5181d08b8680SEric Joyner 
5182d08b8680SEric Joyner /**
518371d10453SEric Joyner  * ice_sched_set_vsi_bw_shared_lmt - set VSI BW shared limit
518471d10453SEric Joyner  * @pi: port information structure
518571d10453SEric Joyner  * @vsi_handle: software VSI handle
5186d08b8680SEric Joyner  * @min_bw: minimum bandwidth in Kbps
5187d08b8680SEric Joyner  * @max_bw: maximum bandwidth in Kbps
5188d08b8680SEric Joyner  * @shared_bw: shared bandwidth in Kbps
518971d10453SEric Joyner  *
5190d08b8680SEric Joyner  * Configure shared rate limiter(SRL) of all VSI type nodes across all traffic
5191d08b8680SEric Joyner  * classes for VSI matching handle. When BW value of ICE_SCHED_DFLT_BW is
5192d08b8680SEric Joyner  * passed, it removes those value(s) from the node.
519371d10453SEric Joyner  */
5194*f2635e84SEric Joyner int
519571d10453SEric Joyner ice_sched_set_vsi_bw_shared_lmt(struct ice_port_info *pi, u16 vsi_handle,
5196d08b8680SEric Joyner 				u32 min_bw, u32 max_bw, u32 shared_bw)
519771d10453SEric Joyner {
5198*f2635e84SEric Joyner 	int status = 0;
519971d10453SEric Joyner 	u8 tc;
520071d10453SEric Joyner 
520171d10453SEric Joyner 	if (!pi)
520271d10453SEric Joyner 		return ICE_ERR_PARAM;
520371d10453SEric Joyner 
520471d10453SEric Joyner 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
520571d10453SEric Joyner 		return ICE_ERR_PARAM;
520671d10453SEric Joyner 
520771d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
520871d10453SEric Joyner 	status = ice_sched_validate_vsi_srl_node(pi, vsi_handle);
520971d10453SEric Joyner 	if (status)
521071d10453SEric Joyner 		goto exit_set_vsi_bw_shared_lmt;
521171d10453SEric Joyner 	/* Return success if no nodes are present across TC */
521271d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
521371d10453SEric Joyner 		struct ice_sched_node *tc_node, *vsi_node;
521471d10453SEric Joyner 
521571d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, tc);
521671d10453SEric Joyner 		if (!tc_node)
521771d10453SEric Joyner 			continue;
521871d10453SEric Joyner 
521971d10453SEric Joyner 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
522071d10453SEric Joyner 		if (!vsi_node)
522171d10453SEric Joyner 			continue;
522271d10453SEric Joyner 
5223d08b8680SEric Joyner 		status = ice_sched_set_vsi_node_srl_per_tc(pi, vsi_handle, tc,
5224d08b8680SEric Joyner 							   min_bw, max_bw,
5225d08b8680SEric Joyner 							   shared_bw);
522671d10453SEric Joyner 		if (status)
522771d10453SEric Joyner 			break;
522871d10453SEric Joyner 	}
522971d10453SEric Joyner 
523071d10453SEric Joyner exit_set_vsi_bw_shared_lmt:
523171d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
523271d10453SEric Joyner 	return status;
523371d10453SEric Joyner }
523471d10453SEric Joyner 
523571d10453SEric Joyner /**
523671d10453SEric Joyner  * ice_sched_validate_agg_srl_node - validate AGG SRL node
523771d10453SEric Joyner  * @pi: port information structure
523871d10453SEric Joyner  * @agg_id: aggregator ID
523971d10453SEric Joyner  *
524071d10453SEric Joyner  * This function validates SRL node of the AGG node if available SRL layer is
524171d10453SEric Joyner  * different than the AGG node layer on all TC(s).This function needs to be
524271d10453SEric Joyner  * called with scheduler lock held.
524371d10453SEric Joyner  */
5244*f2635e84SEric Joyner static int
524571d10453SEric Joyner ice_sched_validate_agg_srl_node(struct ice_port_info *pi, u32 agg_id)
524671d10453SEric Joyner {
524771d10453SEric Joyner 	u8 sel_layer = ICE_SCHED_INVAL_LAYER_NUM;
524871d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
524971d10453SEric Joyner 	bool agg_id_present = false;
5250*f2635e84SEric Joyner 	int status = 0;
525171d10453SEric Joyner 	u8 tc;
525271d10453SEric Joyner 
525371d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(agg_info, &pi->hw->agg_list, ice_sched_agg_info,
525471d10453SEric Joyner 			    list_entry)
525571d10453SEric Joyner 		if (agg_info->agg_id == agg_id) {
525671d10453SEric Joyner 			agg_id_present = true;
525771d10453SEric Joyner 			break;
525871d10453SEric Joyner 		}
525971d10453SEric Joyner 	if (!agg_id_present)
526071d10453SEric Joyner 		return ICE_ERR_PARAM;
526171d10453SEric Joyner 	/* Return success if no nodes are present across TC */
526271d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
526371d10453SEric Joyner 		struct ice_sched_node *tc_node, *agg_node;
526471d10453SEric Joyner 		enum ice_rl_type rl_type = ICE_SHARED_BW;
526571d10453SEric Joyner 
526671d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, tc);
526771d10453SEric Joyner 		if (!tc_node)
526871d10453SEric Joyner 			continue;
526971d10453SEric Joyner 
527071d10453SEric Joyner 		agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
527171d10453SEric Joyner 		if (!agg_node)
527271d10453SEric Joyner 			continue;
527371d10453SEric Joyner 		/* SRL bandwidth layer selection */
527471d10453SEric Joyner 		if (sel_layer == ICE_SCHED_INVAL_LAYER_NUM) {
527571d10453SEric Joyner 			u8 node_layer = agg_node->tx_sched_layer;
527671d10453SEric Joyner 			u8 layer_num;
527771d10453SEric Joyner 
527871d10453SEric Joyner 			layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
527971d10453SEric Joyner 								node_layer);
528071d10453SEric Joyner 			if (layer_num >= pi->hw->num_tx_sched_layers)
528171d10453SEric Joyner 				return ICE_ERR_PARAM;
528271d10453SEric Joyner 			sel_layer = layer_num;
528371d10453SEric Joyner 		}
528471d10453SEric Joyner 
528571d10453SEric Joyner 		status = ice_sched_validate_srl_node(agg_node, sel_layer);
528671d10453SEric Joyner 		if (status)
528771d10453SEric Joyner 			break;
528871d10453SEric Joyner 	}
528971d10453SEric Joyner 	return status;
529071d10453SEric Joyner }
529171d10453SEric Joyner 
529271d10453SEric Joyner /**
5293d08b8680SEric Joyner  * ice_sched_validate_agg_id - Validate aggregator id
529471d10453SEric Joyner  * @pi: port information structure
529571d10453SEric Joyner  * @agg_id: aggregator ID
529671d10453SEric Joyner  *
5297d08b8680SEric Joyner  * This function validates aggregator id. Caller holds the scheduler lock.
529871d10453SEric Joyner  */
5299*f2635e84SEric Joyner static int
5300d08b8680SEric Joyner ice_sched_validate_agg_id(struct ice_port_info *pi, u32 agg_id)
530171d10453SEric Joyner {
530271d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
530371d10453SEric Joyner 	struct ice_sched_agg_info *tmp;
530471d10453SEric Joyner 	bool agg_id_present = false;
5305*f2635e84SEric Joyner 	int status;
530671d10453SEric Joyner 
530771d10453SEric Joyner 	status = ice_sched_validate_agg_srl_node(pi, agg_id);
530871d10453SEric Joyner 	if (status)
5309d08b8680SEric Joyner 		return status;
531071d10453SEric Joyner 
531171d10453SEric Joyner 	LIST_FOR_EACH_ENTRY_SAFE(agg_info, tmp, &pi->hw->agg_list,
531271d10453SEric Joyner 				 ice_sched_agg_info, list_entry)
531371d10453SEric Joyner 		if (agg_info->agg_id == agg_id) {
531471d10453SEric Joyner 			agg_id_present = true;
531571d10453SEric Joyner 			break;
531671d10453SEric Joyner 		}
531771d10453SEric Joyner 
5318d08b8680SEric Joyner 	if (!agg_id_present)
5319d08b8680SEric Joyner 		return ICE_ERR_PARAM;
5320d08b8680SEric Joyner 
5321*f2635e84SEric Joyner 	return 0;
532271d10453SEric Joyner }
532371d10453SEric Joyner 
5324d08b8680SEric Joyner /**
5325d08b8680SEric Joyner  * ice_sched_set_save_agg_srl_node_bw - set aggregator shared limit values
5326d08b8680SEric Joyner  * @pi: port information structure
5327d08b8680SEric Joyner  * @agg_id: aggregator ID
5328d08b8680SEric Joyner  * @tc: traffic class
5329d08b8680SEric Joyner  * @srl_node: sched node to configure
5330d08b8680SEric Joyner  * @rl_type: rate limit type minimum, maximum, or shared
5331d08b8680SEric Joyner  * @bw: minimum, maximum, or shared bandwidth in Kbps
5332d08b8680SEric Joyner  *
5333d08b8680SEric Joyner  * Configure shared rate limiter(SRL) of aggregator type nodes across
5334d08b8680SEric Joyner  * requested traffic class, and saves those value for later use for
5335d08b8680SEric Joyner  * replaying purposes. The caller holds the scheduler lock.
5336d08b8680SEric Joyner  */
5337*f2635e84SEric Joyner static int
5338d08b8680SEric Joyner ice_sched_set_save_agg_srl_node_bw(struct ice_port_info *pi, u32 agg_id, u8 tc,
5339d08b8680SEric Joyner 				   struct ice_sched_node *srl_node,
5340d08b8680SEric Joyner 				   enum ice_rl_type rl_type, u32 bw)
5341d08b8680SEric Joyner {
5342*f2635e84SEric Joyner 	int status;
5343d08b8680SEric Joyner 
5344d08b8680SEric Joyner 	if (bw == ICE_SCHED_DFLT_BW) {
5345d08b8680SEric Joyner 		status = ice_sched_set_node_bw_dflt_lmt(pi, srl_node, rl_type);
5346d08b8680SEric Joyner 	} else {
5347d08b8680SEric Joyner 		status = ice_sched_set_node_bw_lmt(pi, srl_node, rl_type, bw);
5348d08b8680SEric Joyner 		if (status)
5349d08b8680SEric Joyner 			return status;
5350d08b8680SEric Joyner 		status = ice_sched_save_agg_bw(pi, agg_id, tc, rl_type, bw);
5351d08b8680SEric Joyner 	}
5352d08b8680SEric Joyner 	return status;
5353d08b8680SEric Joyner }
5354d08b8680SEric Joyner 
5355d08b8680SEric Joyner /**
5356d08b8680SEric Joyner  * ice_sched_set_agg_node_srl_per_tc - set aggregator SRL per tc
5357d08b8680SEric Joyner  * @pi: port information structure
5358d08b8680SEric Joyner  * @agg_id: aggregator ID
5359d08b8680SEric Joyner  * @tc: traffic class
5360d08b8680SEric Joyner  * @min_bw: minimum bandwidth in Kbps
5361d08b8680SEric Joyner  * @max_bw: maximum bandwidth in Kbps
5362d08b8680SEric Joyner  * @shared_bw: shared bandwidth in Kbps
5363d08b8680SEric Joyner  *
5364d08b8680SEric Joyner  * This function configures the shared rate limiter(SRL) of aggregator type
5365d08b8680SEric Joyner  * node for a given traffic class for aggregator matching agg_id. When BW
5366d08b8680SEric Joyner  * value of ICE_SCHED_DFLT_BW is passed, it removes SRL from the node. Caller
5367d08b8680SEric Joyner  * holds the scheduler lock.
5368d08b8680SEric Joyner  */
5369*f2635e84SEric Joyner static int
5370d08b8680SEric Joyner ice_sched_set_agg_node_srl_per_tc(struct ice_port_info *pi, u32 agg_id,
5371d08b8680SEric Joyner 				  u8 tc, u32 min_bw, u32 max_bw, u32 shared_bw)
5372d08b8680SEric Joyner {
5373d08b8680SEric Joyner 	struct ice_sched_node *tc_node, *agg_node, *cfg_node;
5374d08b8680SEric Joyner 	enum ice_rl_type rl_type = ICE_SHARED_BW;
5375*f2635e84SEric Joyner 	int status = ICE_ERR_CFG;
5376d08b8680SEric Joyner 	u8 layer_num;
5377d08b8680SEric Joyner 
5378d08b8680SEric Joyner 	tc_node = ice_sched_get_tc_node(pi, tc);
5379d08b8680SEric Joyner 	if (!tc_node)
5380d08b8680SEric Joyner 		return ICE_ERR_CFG;
5381d08b8680SEric Joyner 
5382d08b8680SEric Joyner 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
5383d08b8680SEric Joyner 	if (!agg_node)
5384d08b8680SEric Joyner 		return ICE_ERR_CFG;
5385d08b8680SEric Joyner 
5386d08b8680SEric Joyner 	layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
5387d08b8680SEric Joyner 						agg_node->tx_sched_layer);
5388d08b8680SEric Joyner 	if (layer_num >= pi->hw->num_tx_sched_layers)
5389d08b8680SEric Joyner 		return ICE_ERR_PARAM;
5390d08b8680SEric Joyner 
5391d08b8680SEric Joyner 	/* SRL node may be different */
5392d08b8680SEric Joyner 	cfg_node = ice_sched_get_srl_node(agg_node, layer_num);
5393d08b8680SEric Joyner 	if (!cfg_node)
5394d08b8680SEric Joyner 		return ICE_ERR_CFG;
5395d08b8680SEric Joyner 
5396d08b8680SEric Joyner 	status = ice_sched_set_save_agg_srl_node_bw(pi, agg_id, tc, cfg_node,
5397d08b8680SEric Joyner 						    ICE_MIN_BW, min_bw);
5398d08b8680SEric Joyner 	if (status)
5399d08b8680SEric Joyner 		return status;
5400d08b8680SEric Joyner 
5401d08b8680SEric Joyner 	status = ice_sched_set_save_agg_srl_node_bw(pi, agg_id, tc, cfg_node,
5402d08b8680SEric Joyner 						    ICE_MAX_BW, max_bw);
5403d08b8680SEric Joyner 	if (status)
5404d08b8680SEric Joyner 		return status;
5405d08b8680SEric Joyner 
5406d08b8680SEric Joyner 	status = ice_sched_set_save_agg_srl_node_bw(pi, agg_id, tc, cfg_node,
5407d08b8680SEric Joyner 						    ICE_SHARED_BW, shared_bw);
5408d08b8680SEric Joyner 	return status;
5409d08b8680SEric Joyner }
5410d08b8680SEric Joyner 
5411d08b8680SEric Joyner /**
5412d08b8680SEric Joyner  * ice_sched_set_agg_bw_shared_lmt - set aggregator BW shared limit
5413d08b8680SEric Joyner  * @pi: port information structure
5414d08b8680SEric Joyner  * @agg_id: aggregator ID
5415d08b8680SEric Joyner  * @min_bw: minimum bandwidth in Kbps
5416d08b8680SEric Joyner  * @max_bw: maximum bandwidth in Kbps
5417d08b8680SEric Joyner  * @shared_bw: shared bandwidth in Kbps
5418d08b8680SEric Joyner  *
5419d08b8680SEric Joyner  * This function configures the shared rate limiter(SRL) of all aggregator type
5420d08b8680SEric Joyner  * nodes across all traffic classes for aggregator matching agg_id. When
5421d08b8680SEric Joyner  * BW value of ICE_SCHED_DFLT_BW is passed, it removes SRL from the
5422d08b8680SEric Joyner  * node(s).
5423d08b8680SEric Joyner  */
5424*f2635e84SEric Joyner int
5425d08b8680SEric Joyner ice_sched_set_agg_bw_shared_lmt(struct ice_port_info *pi, u32 agg_id,
5426d08b8680SEric Joyner 				u32 min_bw, u32 max_bw, u32 shared_bw)
5427d08b8680SEric Joyner {
5428*f2635e84SEric Joyner 	int status;
5429d08b8680SEric Joyner 	u8 tc;
5430d08b8680SEric Joyner 
5431d08b8680SEric Joyner 	if (!pi)
5432d08b8680SEric Joyner 		return ICE_ERR_PARAM;
5433d08b8680SEric Joyner 
5434d08b8680SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
5435d08b8680SEric Joyner 	status = ice_sched_validate_agg_id(pi, agg_id);
5436d08b8680SEric Joyner 	if (status)
5437d08b8680SEric Joyner 		goto exit_agg_bw_shared_lmt;
5438d08b8680SEric Joyner 
543971d10453SEric Joyner 	/* Return success if no nodes are present across TC */
544071d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
544171d10453SEric Joyner 		struct ice_sched_node *tc_node, *agg_node;
544271d10453SEric Joyner 
544371d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, tc);
544471d10453SEric Joyner 		if (!tc_node)
544571d10453SEric Joyner 			continue;
544671d10453SEric Joyner 
544771d10453SEric Joyner 		agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
544871d10453SEric Joyner 		if (!agg_node)
544971d10453SEric Joyner 			continue;
545071d10453SEric Joyner 
5451d08b8680SEric Joyner 		status = ice_sched_set_agg_node_srl_per_tc(pi, agg_id, tc,
5452d08b8680SEric Joyner 							   min_bw, max_bw,
5453d08b8680SEric Joyner 							   shared_bw);
545471d10453SEric Joyner 		if (status)
545571d10453SEric Joyner 			break;
545671d10453SEric Joyner 	}
545771d10453SEric Joyner 
545871d10453SEric Joyner exit_agg_bw_shared_lmt:
545971d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
546071d10453SEric Joyner 	return status;
546171d10453SEric Joyner }
546271d10453SEric Joyner 
546371d10453SEric Joyner /**
5464d08b8680SEric Joyner  * ice_sched_set_agg_bw_shared_lmt_per_tc - set aggregator BW shared lmt per tc
5465d08b8680SEric Joyner  * @pi: port information structure
5466d08b8680SEric Joyner  * @agg_id: aggregator ID
5467d08b8680SEric Joyner  * @tc: traffic class
5468d08b8680SEric Joyner  * @min_bw: minimum bandwidth in Kbps
5469d08b8680SEric Joyner  * @max_bw: maximum bandwidth in Kbps
5470d08b8680SEric Joyner  * @shared_bw: shared bandwidth in Kbps
5471d08b8680SEric Joyner  *
5472d08b8680SEric Joyner  * This function configures the shared rate limiter(SRL) of aggregator type
5473d08b8680SEric Joyner  * node for a given traffic class for aggregator matching agg_id. When BW
5474d08b8680SEric Joyner  * value of ICE_SCHED_DFLT_BW is passed, it removes SRL from the node.
5475d08b8680SEric Joyner  */
5476*f2635e84SEric Joyner int
5477d08b8680SEric Joyner ice_sched_set_agg_bw_shared_lmt_per_tc(struct ice_port_info *pi, u32 agg_id,
5478d08b8680SEric Joyner 				       u8 tc, u32 min_bw, u32 max_bw,
5479d08b8680SEric Joyner 				       u32 shared_bw)
5480d08b8680SEric Joyner {
5481*f2635e84SEric Joyner 	int status;
5482d08b8680SEric Joyner 
5483d08b8680SEric Joyner 	if (!pi)
5484d08b8680SEric Joyner 		return ICE_ERR_PARAM;
5485d08b8680SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
5486d08b8680SEric Joyner 	status = ice_sched_validate_agg_id(pi, agg_id);
5487d08b8680SEric Joyner 	if (status)
5488d08b8680SEric Joyner 		goto exit_agg_bw_shared_lmt_per_tc;
5489d08b8680SEric Joyner 
5490d08b8680SEric Joyner 	status = ice_sched_set_agg_node_srl_per_tc(pi, agg_id, tc, min_bw,
5491d08b8680SEric Joyner 						   max_bw, shared_bw);
5492d08b8680SEric Joyner 
5493d08b8680SEric Joyner exit_agg_bw_shared_lmt_per_tc:
5494d08b8680SEric Joyner 	ice_release_lock(&pi->sched_lock);
5495d08b8680SEric Joyner 	return status;
5496d08b8680SEric Joyner }
5497d08b8680SEric Joyner 
5498d08b8680SEric Joyner /**
549971d10453SEric Joyner  * ice_sched_cfg_sibl_node_prio - configure node sibling priority
550071d10453SEric Joyner  * @pi: port information structure
550171d10453SEric Joyner  * @node: sched node to configure
550271d10453SEric Joyner  * @priority: sibling priority
550371d10453SEric Joyner  *
550471d10453SEric Joyner  * This function configures node element's sibling priority only. This
550571d10453SEric Joyner  * function needs to be called with scheduler lock held.
550671d10453SEric Joyner  */
5507*f2635e84SEric Joyner int
550871d10453SEric Joyner ice_sched_cfg_sibl_node_prio(struct ice_port_info *pi,
550971d10453SEric Joyner 			     struct ice_sched_node *node, u8 priority)
551071d10453SEric Joyner {
551171d10453SEric Joyner 	struct ice_aqc_txsched_elem_data buf;
551271d10453SEric Joyner 	struct ice_aqc_txsched_elem *data;
551371d10453SEric Joyner 	struct ice_hw *hw = pi->hw;
5514*f2635e84SEric Joyner 	int status;
551571d10453SEric Joyner 
551671d10453SEric Joyner 	if (!hw)
551771d10453SEric Joyner 		return ICE_ERR_PARAM;
551871d10453SEric Joyner 	buf = node->info;
551971d10453SEric Joyner 	data = &buf.data;
552071d10453SEric Joyner 	data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC;
552171d10453SEric Joyner 	priority = (priority << ICE_AQC_ELEM_GENERIC_PRIO_S) &
552271d10453SEric Joyner 		   ICE_AQC_ELEM_GENERIC_PRIO_M;
552371d10453SEric Joyner 	data->generic &= ~ICE_AQC_ELEM_GENERIC_PRIO_M;
552471d10453SEric Joyner 	data->generic |= priority;
552571d10453SEric Joyner 
552671d10453SEric Joyner 	/* Configure element */
552771d10453SEric Joyner 	status = ice_sched_update_elem(hw, node, &buf);
552871d10453SEric Joyner 	return status;
552971d10453SEric Joyner }
553071d10453SEric Joyner 
553171d10453SEric Joyner /**
553271d10453SEric Joyner  * ice_cfg_rl_burst_size - Set burst size value
553371d10453SEric Joyner  * @hw: pointer to the HW struct
553471d10453SEric Joyner  * @bytes: burst size in bytes
553571d10453SEric Joyner  *
553671d10453SEric Joyner  * This function configures/set the burst size to requested new value. The new
553771d10453SEric Joyner  * burst size value is used for future rate limit calls. It doesn't change the
553871d10453SEric Joyner  * existing or previously created RL profiles.
553971d10453SEric Joyner  */
5540*f2635e84SEric Joyner int ice_cfg_rl_burst_size(struct ice_hw *hw, u32 bytes)
554171d10453SEric Joyner {
554271d10453SEric Joyner 	u16 burst_size_to_prog;
554371d10453SEric Joyner 
554471d10453SEric Joyner 	if (bytes < ICE_MIN_BURST_SIZE_ALLOWED ||
554571d10453SEric Joyner 	    bytes > ICE_MAX_BURST_SIZE_ALLOWED)
554671d10453SEric Joyner 		return ICE_ERR_PARAM;
554771d10453SEric Joyner 	if (ice_round_to_num(bytes, 64) <=
554871d10453SEric Joyner 	    ICE_MAX_BURST_SIZE_64_BYTE_GRANULARITY) {
554971d10453SEric Joyner 		/* 64 byte granularity case */
555071d10453SEric Joyner 		/* Disable MSB granularity bit */
555171d10453SEric Joyner 		burst_size_to_prog = ICE_64_BYTE_GRANULARITY;
555271d10453SEric Joyner 		/* round number to nearest 64 byte granularity */
555371d10453SEric Joyner 		bytes = ice_round_to_num(bytes, 64);
555471d10453SEric Joyner 		/* The value is in 64 byte chunks */
555571d10453SEric Joyner 		burst_size_to_prog |= (u16)(bytes / 64);
555671d10453SEric Joyner 	} else {
555771d10453SEric Joyner 		/* k bytes granularity case */
555871d10453SEric Joyner 		/* Enable MSB granularity bit */
555971d10453SEric Joyner 		burst_size_to_prog = ICE_KBYTE_GRANULARITY;
556071d10453SEric Joyner 		/* round number to nearest 1024 granularity */
556171d10453SEric Joyner 		bytes = ice_round_to_num(bytes, 1024);
556271d10453SEric Joyner 		/* check rounding doesn't go beyond allowed */
556371d10453SEric Joyner 		if (bytes > ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY)
556471d10453SEric Joyner 			bytes = ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY;
556571d10453SEric Joyner 		/* The value is in k bytes */
556671d10453SEric Joyner 		burst_size_to_prog |= (u16)(bytes / 1024);
556771d10453SEric Joyner 	}
556871d10453SEric Joyner 	hw->max_burst_size = burst_size_to_prog;
5569*f2635e84SEric Joyner 	return 0;
557071d10453SEric Joyner }
557171d10453SEric Joyner 
55727d7af7f8SEric Joyner /**
557371d10453SEric Joyner  * ice_sched_replay_node_prio - re-configure node priority
557471d10453SEric Joyner  * @hw: pointer to the HW struct
557571d10453SEric Joyner  * @node: sched node to configure
557671d10453SEric Joyner  * @priority: priority value
557771d10453SEric Joyner  *
557871d10453SEric Joyner  * This function configures node element's priority value. It
557971d10453SEric Joyner  * needs to be called with scheduler lock held.
558071d10453SEric Joyner  */
5581*f2635e84SEric Joyner static int
558271d10453SEric Joyner ice_sched_replay_node_prio(struct ice_hw *hw, struct ice_sched_node *node,
558371d10453SEric Joyner 			   u8 priority)
558471d10453SEric Joyner {
558571d10453SEric Joyner 	struct ice_aqc_txsched_elem_data buf;
558671d10453SEric Joyner 	struct ice_aqc_txsched_elem *data;
5587*f2635e84SEric Joyner 	int status;
558871d10453SEric Joyner 
558971d10453SEric Joyner 	buf = node->info;
559071d10453SEric Joyner 	data = &buf.data;
559171d10453SEric Joyner 	data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC;
559271d10453SEric Joyner 	data->generic = priority;
559371d10453SEric Joyner 
559471d10453SEric Joyner 	/* Configure element */
559571d10453SEric Joyner 	status = ice_sched_update_elem(hw, node, &buf);
559671d10453SEric Joyner 	return status;
559771d10453SEric Joyner }
559871d10453SEric Joyner 
559971d10453SEric Joyner /**
560071d10453SEric Joyner  * ice_sched_replay_node_bw - replay node(s) BW
560171d10453SEric Joyner  * @hw: pointer to the HW struct
560271d10453SEric Joyner  * @node: sched node to configure
560371d10453SEric Joyner  * @bw_t_info: BW type information
560471d10453SEric Joyner  *
560571d10453SEric Joyner  * This function restores node's BW from bw_t_info. The caller needs
560671d10453SEric Joyner  * to hold the scheduler lock.
560771d10453SEric Joyner  */
5608*f2635e84SEric Joyner static int
560971d10453SEric Joyner ice_sched_replay_node_bw(struct ice_hw *hw, struct ice_sched_node *node,
561071d10453SEric Joyner 			 struct ice_bw_type_info *bw_t_info)
561171d10453SEric Joyner {
561271d10453SEric Joyner 	struct ice_port_info *pi = hw->port_info;
5613*f2635e84SEric Joyner 	int status = ICE_ERR_PARAM;
561471d10453SEric Joyner 	u16 bw_alloc;
561571d10453SEric Joyner 
561671d10453SEric Joyner 	if (!node)
561771d10453SEric Joyner 		return status;
561871d10453SEric Joyner 	if (!ice_is_any_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CNT))
5619*f2635e84SEric Joyner 		return 0;
562071d10453SEric Joyner 	if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_PRIO)) {
562171d10453SEric Joyner 		status = ice_sched_replay_node_prio(hw, node,
562271d10453SEric Joyner 						    bw_t_info->generic);
562371d10453SEric Joyner 		if (status)
562471d10453SEric Joyner 			return status;
562571d10453SEric Joyner 	}
562671d10453SEric Joyner 	if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CIR)) {
562771d10453SEric Joyner 		status = ice_sched_set_node_bw_lmt(pi, node, ICE_MIN_BW,
562871d10453SEric Joyner 						   bw_t_info->cir_bw.bw);
562971d10453SEric Joyner 		if (status)
563071d10453SEric Joyner 			return status;
563171d10453SEric Joyner 	}
563271d10453SEric Joyner 	if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CIR_WT)) {
563371d10453SEric Joyner 		bw_alloc = bw_t_info->cir_bw.bw_alloc;
563471d10453SEric Joyner 		status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MIN_BW,
563571d10453SEric Joyner 						     bw_alloc);
563671d10453SEric Joyner 		if (status)
563771d10453SEric Joyner 			return status;
563871d10453SEric Joyner 	}
563971d10453SEric Joyner 	if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_EIR)) {
564071d10453SEric Joyner 		status = ice_sched_set_node_bw_lmt(pi, node, ICE_MAX_BW,
564171d10453SEric Joyner 						   bw_t_info->eir_bw.bw);
564271d10453SEric Joyner 		if (status)
564371d10453SEric Joyner 			return status;
564471d10453SEric Joyner 	}
564571d10453SEric Joyner 	if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_EIR_WT)) {
564671d10453SEric Joyner 		bw_alloc = bw_t_info->eir_bw.bw_alloc;
564771d10453SEric Joyner 		status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MAX_BW,
564871d10453SEric Joyner 						     bw_alloc);
564971d10453SEric Joyner 		if (status)
565071d10453SEric Joyner 			return status;
565171d10453SEric Joyner 	}
565271d10453SEric Joyner 	if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_SHARED))
565371d10453SEric Joyner 		status = ice_sched_set_node_bw_lmt(pi, node, ICE_SHARED_BW,
565471d10453SEric Joyner 						   bw_t_info->shared_bw);
565571d10453SEric Joyner 	return status;
565671d10453SEric Joyner }
565771d10453SEric Joyner 
565871d10453SEric Joyner /**
565971d10453SEric Joyner  * ice_sched_replay_agg_bw - replay aggregator node(s) BW
566071d10453SEric Joyner  * @hw: pointer to the HW struct
566171d10453SEric Joyner  * @agg_info: aggregator data structure
566271d10453SEric Joyner  *
566371d10453SEric Joyner  * This function re-creates aggregator type nodes. The caller needs to hold
566471d10453SEric Joyner  * the scheduler lock.
566571d10453SEric Joyner  */
5666*f2635e84SEric Joyner static int
566771d10453SEric Joyner ice_sched_replay_agg_bw(struct ice_hw *hw, struct ice_sched_agg_info *agg_info)
566871d10453SEric Joyner {
566971d10453SEric Joyner 	struct ice_sched_node *tc_node, *agg_node;
5670*f2635e84SEric Joyner 	int status = 0;
567171d10453SEric Joyner 	u8 tc;
567271d10453SEric Joyner 
567371d10453SEric Joyner 	if (!agg_info)
567471d10453SEric Joyner 		return ICE_ERR_PARAM;
567571d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
567671d10453SEric Joyner 		if (!ice_is_any_bit_set(agg_info->bw_t_info[tc].bw_t_bitmap,
567771d10453SEric Joyner 					ICE_BW_TYPE_CNT))
567871d10453SEric Joyner 			continue;
567971d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(hw->port_info, tc);
568071d10453SEric Joyner 		if (!tc_node) {
568171d10453SEric Joyner 			status = ICE_ERR_PARAM;
568271d10453SEric Joyner 			break;
568371d10453SEric Joyner 		}
568471d10453SEric Joyner 		agg_node = ice_sched_get_agg_node(hw->port_info, tc_node,
568571d10453SEric Joyner 						  agg_info->agg_id);
568671d10453SEric Joyner 		if (!agg_node) {
568771d10453SEric Joyner 			status = ICE_ERR_PARAM;
568871d10453SEric Joyner 			break;
568971d10453SEric Joyner 		}
569071d10453SEric Joyner 		status = ice_sched_replay_node_bw(hw, agg_node,
569171d10453SEric Joyner 						  &agg_info->bw_t_info[tc]);
569271d10453SEric Joyner 		if (status)
569371d10453SEric Joyner 			break;
569471d10453SEric Joyner 	}
569571d10453SEric Joyner 	return status;
569671d10453SEric Joyner }
569771d10453SEric Joyner 
569871d10453SEric Joyner /**
569971d10453SEric Joyner  * ice_sched_get_ena_tc_bitmap - get enabled TC bitmap
570071d10453SEric Joyner  * @pi: port info struct
570171d10453SEric Joyner  * @tc_bitmap: 8 bits TC bitmap to check
570271d10453SEric Joyner  * @ena_tc_bitmap: 8 bits enabled TC bitmap to return
570371d10453SEric Joyner  *
570471d10453SEric Joyner  * This function returns enabled TC bitmap in variable ena_tc_bitmap. Some TCs
570571d10453SEric Joyner  * may be missing, it returns enabled TCs. This function needs to be called with
570671d10453SEric Joyner  * scheduler lock held.
570771d10453SEric Joyner  */
570871d10453SEric Joyner static void
570971d10453SEric Joyner ice_sched_get_ena_tc_bitmap(struct ice_port_info *pi, ice_bitmap_t *tc_bitmap,
571071d10453SEric Joyner 			    ice_bitmap_t *ena_tc_bitmap)
571171d10453SEric Joyner {
571271d10453SEric Joyner 	u8 tc;
571371d10453SEric Joyner 
571471d10453SEric Joyner 	/* Some TC(s) may be missing after reset, adjust for replay */
571571d10453SEric Joyner 	ice_for_each_traffic_class(tc)
571671d10453SEric Joyner 		if (ice_is_tc_ena(*tc_bitmap, tc) &&
571771d10453SEric Joyner 		    (ice_sched_get_tc_node(pi, tc)))
571871d10453SEric Joyner 			ice_set_bit(tc, ena_tc_bitmap);
571971d10453SEric Joyner }
572071d10453SEric Joyner 
572171d10453SEric Joyner /**
572271d10453SEric Joyner  * ice_sched_replay_agg - recreate aggregator node(s)
572371d10453SEric Joyner  * @hw: pointer to the HW struct
572471d10453SEric Joyner  *
572571d10453SEric Joyner  * This function recreate aggregator type nodes which are not replayed earlier.
572671d10453SEric Joyner  * It also replay aggregator BW information. These aggregator nodes are not
572771d10453SEric Joyner  * associated with VSI type node yet.
572871d10453SEric Joyner  */
572971d10453SEric Joyner void ice_sched_replay_agg(struct ice_hw *hw)
573071d10453SEric Joyner {
573171d10453SEric Joyner 	struct ice_port_info *pi = hw->port_info;
573271d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
573371d10453SEric Joyner 
573471d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
573571d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
57367d7af7f8SEric Joyner 			    list_entry)
573771d10453SEric Joyner 		/* replay aggregator (re-create aggregator node) */
573871d10453SEric Joyner 		if (!ice_cmp_bitmap(agg_info->tc_bitmap,
573971d10453SEric Joyner 				    agg_info->replay_tc_bitmap,
574071d10453SEric Joyner 				    ICE_MAX_TRAFFIC_CLASS)) {
574171d10453SEric Joyner 			ice_declare_bitmap(replay_bitmap,
574271d10453SEric Joyner 					   ICE_MAX_TRAFFIC_CLASS);
5743*f2635e84SEric Joyner 			int status;
574471d10453SEric Joyner 
574571d10453SEric Joyner 			ice_zero_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
574671d10453SEric Joyner 			ice_sched_get_ena_tc_bitmap(pi,
574771d10453SEric Joyner 						    agg_info->replay_tc_bitmap,
574871d10453SEric Joyner 						    replay_bitmap);
574971d10453SEric Joyner 			status = ice_sched_cfg_agg(hw->port_info,
575071d10453SEric Joyner 						   agg_info->agg_id,
575171d10453SEric Joyner 						   ICE_AGG_TYPE_AGG,
575271d10453SEric Joyner 						   replay_bitmap);
575371d10453SEric Joyner 			if (status) {
575471d10453SEric Joyner 				ice_info(hw, "Replay agg id[%d] failed\n",
575571d10453SEric Joyner 					 agg_info->agg_id);
575671d10453SEric Joyner 				/* Move on to next one */
575771d10453SEric Joyner 				continue;
575871d10453SEric Joyner 			}
575971d10453SEric Joyner 			/* Replay aggregator node BW (restore aggregator BW) */
576071d10453SEric Joyner 			status = ice_sched_replay_agg_bw(hw, agg_info);
576171d10453SEric Joyner 			if (status)
576271d10453SEric Joyner 				ice_info(hw, "Replay agg bw [id=%d] failed\n",
576371d10453SEric Joyner 					 agg_info->agg_id);
576471d10453SEric Joyner 		}
576571d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
576671d10453SEric Joyner }
576771d10453SEric Joyner 
576871d10453SEric Joyner /**
576971d10453SEric Joyner  * ice_sched_replay_agg_vsi_preinit - Agg/VSI replay pre initialization
577071d10453SEric Joyner  * @hw: pointer to the HW struct
577171d10453SEric Joyner  *
577271d10453SEric Joyner  * This function initialize aggregator(s) TC bitmap to zero. A required
577371d10453SEric Joyner  * preinit step for replaying aggregators.
577471d10453SEric Joyner  */
577571d10453SEric Joyner void ice_sched_replay_agg_vsi_preinit(struct ice_hw *hw)
577671d10453SEric Joyner {
577771d10453SEric Joyner 	struct ice_port_info *pi = hw->port_info;
577871d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
577971d10453SEric Joyner 
578071d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
578171d10453SEric Joyner 	LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
578271d10453SEric Joyner 			    list_entry) {
578371d10453SEric Joyner 		struct ice_sched_agg_vsi_info *agg_vsi_info;
578471d10453SEric Joyner 
578571d10453SEric Joyner 		agg_info->tc_bitmap[0] = 0;
578671d10453SEric Joyner 		LIST_FOR_EACH_ENTRY(agg_vsi_info, &agg_info->agg_vsi_list,
578771d10453SEric Joyner 				    ice_sched_agg_vsi_info, list_entry)
578871d10453SEric Joyner 			agg_vsi_info->tc_bitmap[0] = 0;
578971d10453SEric Joyner 	}
579071d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
579171d10453SEric Joyner }
579271d10453SEric Joyner 
579371d10453SEric Joyner /**
57947d7af7f8SEric Joyner  * ice_sched_replay_root_node_bw - replay root node BW
57957d7af7f8SEric Joyner  * @pi: port information structure
57967d7af7f8SEric Joyner  *
57977d7af7f8SEric Joyner  * Replay root node BW settings.
57987d7af7f8SEric Joyner  */
5799*f2635e84SEric Joyner int ice_sched_replay_root_node_bw(struct ice_port_info *pi)
58007d7af7f8SEric Joyner {
5801*f2635e84SEric Joyner 	int status = 0;
58027d7af7f8SEric Joyner 
58037d7af7f8SEric Joyner 	if (!pi->hw)
58047d7af7f8SEric Joyner 		return ICE_ERR_PARAM;
58057d7af7f8SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
58067d7af7f8SEric Joyner 
58077d7af7f8SEric Joyner 	status = ice_sched_replay_node_bw(pi->hw, pi->root,
58087d7af7f8SEric Joyner 					  &pi->root_node_bw_t_info);
58097d7af7f8SEric Joyner 	ice_release_lock(&pi->sched_lock);
58107d7af7f8SEric Joyner 	return status;
58117d7af7f8SEric Joyner }
58127d7af7f8SEric Joyner 
58137d7af7f8SEric Joyner /**
581471d10453SEric Joyner  * ice_sched_replay_tc_node_bw - replay TC node(s) BW
581571d10453SEric Joyner  * @pi: port information structure
581671d10453SEric Joyner  *
581771d10453SEric Joyner  * This function replay TC nodes.
581871d10453SEric Joyner  */
5819*f2635e84SEric Joyner int ice_sched_replay_tc_node_bw(struct ice_port_info *pi)
582071d10453SEric Joyner {
5821*f2635e84SEric Joyner 	int status = 0;
582271d10453SEric Joyner 	u8 tc;
582371d10453SEric Joyner 
582471d10453SEric Joyner 	if (!pi->hw)
582571d10453SEric Joyner 		return ICE_ERR_PARAM;
582671d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
582771d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
582871d10453SEric Joyner 		struct ice_sched_node *tc_node;
582971d10453SEric Joyner 
583071d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, tc);
583171d10453SEric Joyner 		if (!tc_node)
583271d10453SEric Joyner 			continue; /* TC not present */
583371d10453SEric Joyner 		status = ice_sched_replay_node_bw(pi->hw, tc_node,
583471d10453SEric Joyner 						  &pi->tc_node_bw_t_info[tc]);
583571d10453SEric Joyner 		if (status)
583671d10453SEric Joyner 			break;
583771d10453SEric Joyner 	}
583871d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
583971d10453SEric Joyner 	return status;
584071d10453SEric Joyner }
584171d10453SEric Joyner 
584271d10453SEric Joyner /**
584371d10453SEric Joyner  * ice_sched_replay_vsi_bw - replay VSI type node(s) BW
584471d10453SEric Joyner  * @hw: pointer to the HW struct
584571d10453SEric Joyner  * @vsi_handle: software VSI handle
584671d10453SEric Joyner  * @tc_bitmap: 8 bits TC bitmap
584771d10453SEric Joyner  *
584871d10453SEric Joyner  * This function replays VSI type nodes bandwidth. This function needs to be
584971d10453SEric Joyner  * called with scheduler lock held.
585071d10453SEric Joyner  */
5851*f2635e84SEric Joyner static int
585271d10453SEric Joyner ice_sched_replay_vsi_bw(struct ice_hw *hw, u16 vsi_handle,
585371d10453SEric Joyner 			ice_bitmap_t *tc_bitmap)
585471d10453SEric Joyner {
585571d10453SEric Joyner 	struct ice_sched_node *vsi_node, *tc_node;
585671d10453SEric Joyner 	struct ice_port_info *pi = hw->port_info;
585771d10453SEric Joyner 	struct ice_bw_type_info *bw_t_info;
585871d10453SEric Joyner 	struct ice_vsi_ctx *vsi_ctx;
5859*f2635e84SEric Joyner 	int status = 0;
586071d10453SEric Joyner 	u8 tc;
586171d10453SEric Joyner 
586271d10453SEric Joyner 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
586371d10453SEric Joyner 	if (!vsi_ctx)
586471d10453SEric Joyner 		return ICE_ERR_PARAM;
586571d10453SEric Joyner 	ice_for_each_traffic_class(tc) {
586671d10453SEric Joyner 		if (!ice_is_tc_ena(*tc_bitmap, tc))
586771d10453SEric Joyner 			continue;
586871d10453SEric Joyner 		tc_node = ice_sched_get_tc_node(pi, tc);
586971d10453SEric Joyner 		if (!tc_node)
587071d10453SEric Joyner 			continue;
587171d10453SEric Joyner 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
587271d10453SEric Joyner 		if (!vsi_node)
587371d10453SEric Joyner 			continue;
587471d10453SEric Joyner 		bw_t_info = &vsi_ctx->sched.bw_t_info[tc];
587571d10453SEric Joyner 		status = ice_sched_replay_node_bw(hw, vsi_node, bw_t_info);
587671d10453SEric Joyner 		if (status)
587771d10453SEric Joyner 			break;
587871d10453SEric Joyner 	}
587971d10453SEric Joyner 	return status;
588071d10453SEric Joyner }
588171d10453SEric Joyner 
588271d10453SEric Joyner /**
588371d10453SEric Joyner  * ice_sched_replay_vsi_agg - replay aggregator & VSI to aggregator node(s)
588471d10453SEric Joyner  * @hw: pointer to the HW struct
588571d10453SEric Joyner  * @vsi_handle: software VSI handle
588671d10453SEric Joyner  *
588771d10453SEric Joyner  * This function replays aggregator node, VSI to aggregator type nodes, and
588871d10453SEric Joyner  * their node bandwidth information. This function needs to be called with
588971d10453SEric Joyner  * scheduler lock held.
589071d10453SEric Joyner  */
5891*f2635e84SEric Joyner static int
589271d10453SEric Joyner ice_sched_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle)
589371d10453SEric Joyner {
589471d10453SEric Joyner 	ice_declare_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
589571d10453SEric Joyner 	struct ice_sched_agg_vsi_info *agg_vsi_info;
589671d10453SEric Joyner 	struct ice_port_info *pi = hw->port_info;
589771d10453SEric Joyner 	struct ice_sched_agg_info *agg_info;
5898*f2635e84SEric Joyner 	int status;
589971d10453SEric Joyner 
590071d10453SEric Joyner 	ice_zero_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
590171d10453SEric Joyner 	if (!ice_is_vsi_valid(hw, vsi_handle))
590271d10453SEric Joyner 		return ICE_ERR_PARAM;
590371d10453SEric Joyner 	agg_info = ice_get_vsi_agg_info(hw, vsi_handle);
590471d10453SEric Joyner 	if (!agg_info)
5905*f2635e84SEric Joyner 		return 0; /* Not present in list - default Agg case */
590671d10453SEric Joyner 	agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
590771d10453SEric Joyner 	if (!agg_vsi_info)
5908*f2635e84SEric Joyner 		return 0; /* Not present in list - default Agg case */
590971d10453SEric Joyner 	ice_sched_get_ena_tc_bitmap(pi, agg_info->replay_tc_bitmap,
591071d10453SEric Joyner 				    replay_bitmap);
591171d10453SEric Joyner 	/* Replay aggregator node associated to vsi_handle */
591271d10453SEric Joyner 	status = ice_sched_cfg_agg(hw->port_info, agg_info->agg_id,
591371d10453SEric Joyner 				   ICE_AGG_TYPE_AGG, replay_bitmap);
591471d10453SEric Joyner 	if (status)
591571d10453SEric Joyner 		return status;
591671d10453SEric Joyner 	/* Replay aggregator node BW (restore aggregator BW) */
591771d10453SEric Joyner 	status = ice_sched_replay_agg_bw(hw, agg_info);
591871d10453SEric Joyner 	if (status)
591971d10453SEric Joyner 		return status;
592071d10453SEric Joyner 
592171d10453SEric Joyner 	ice_zero_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
592271d10453SEric Joyner 	ice_sched_get_ena_tc_bitmap(pi, agg_vsi_info->replay_tc_bitmap,
592371d10453SEric Joyner 				    replay_bitmap);
592471d10453SEric Joyner 	/* Move this VSI (vsi_handle) to above aggregator */
592571d10453SEric Joyner 	status = ice_sched_assoc_vsi_to_agg(pi, agg_info->agg_id, vsi_handle,
592671d10453SEric Joyner 					    replay_bitmap);
592771d10453SEric Joyner 	if (status)
592871d10453SEric Joyner 		return status;
592971d10453SEric Joyner 	/* Replay VSI BW (restore VSI BW) */
593071d10453SEric Joyner 	return ice_sched_replay_vsi_bw(hw, vsi_handle,
593171d10453SEric Joyner 				       agg_vsi_info->tc_bitmap);
593271d10453SEric Joyner }
593371d10453SEric Joyner 
593471d10453SEric Joyner /**
593571d10453SEric Joyner  * ice_replay_vsi_agg - replay VSI to aggregator node
593671d10453SEric Joyner  * @hw: pointer to the HW struct
593771d10453SEric Joyner  * @vsi_handle: software VSI handle
593871d10453SEric Joyner  *
593971d10453SEric Joyner  * This function replays association of VSI to aggregator type nodes, and
594071d10453SEric Joyner  * node bandwidth information.
594171d10453SEric Joyner  */
5942*f2635e84SEric Joyner int ice_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle)
594371d10453SEric Joyner {
594471d10453SEric Joyner 	struct ice_port_info *pi = hw->port_info;
5945*f2635e84SEric Joyner 	int status;
594671d10453SEric Joyner 
594771d10453SEric Joyner 	ice_acquire_lock(&pi->sched_lock);
594871d10453SEric Joyner 	status = ice_sched_replay_vsi_agg(hw, vsi_handle);
594971d10453SEric Joyner 	ice_release_lock(&pi->sched_lock);
595071d10453SEric Joyner 	return status;
595171d10453SEric Joyner }
595271d10453SEric Joyner 
595371d10453SEric Joyner /**
595471d10453SEric Joyner  * ice_sched_replay_q_bw - replay queue type node BW
595571d10453SEric Joyner  * @pi: port information structure
595671d10453SEric Joyner  * @q_ctx: queue context structure
595771d10453SEric Joyner  *
595871d10453SEric Joyner  * This function replays queue type node bandwidth. This function needs to be
595971d10453SEric Joyner  * called with scheduler lock held.
596071d10453SEric Joyner  */
5961*f2635e84SEric Joyner int
596271d10453SEric Joyner ice_sched_replay_q_bw(struct ice_port_info *pi, struct ice_q_ctx *q_ctx)
596371d10453SEric Joyner {
596471d10453SEric Joyner 	struct ice_sched_node *q_node;
596571d10453SEric Joyner 
596671d10453SEric Joyner 	/* Following also checks the presence of node in tree */
596771d10453SEric Joyner 	q_node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid);
596871d10453SEric Joyner 	if (!q_node)
596971d10453SEric Joyner 		return ICE_ERR_PARAM;
597071d10453SEric Joyner 	return ice_sched_replay_node_bw(pi->hw, q_node, &q_ctx->bw_t_info);
597171d10453SEric Joyner }
5972