19c20346bSAnirudh Venkataramanan // SPDX-License-Identifier: GPL-2.0
29c20346bSAnirudh Venkataramanan /* Copyright (c) 2018, Intel Corporation. */
39c20346bSAnirudh Venkataramanan 
49c20346bSAnirudh Venkataramanan #include "ice_sched.h"
59c20346bSAnirudh Venkataramanan 
69c20346bSAnirudh Venkataramanan /**
7dc49c772SAnirudh Venkataramanan  * ice_sched_add_root_node - Insert the Tx scheduler root node in SW DB
8dc49c772SAnirudh Venkataramanan  * @pi: port information structure
9dc49c772SAnirudh Venkataramanan  * @info: Scheduler element information from firmware
10dc49c772SAnirudh Venkataramanan  *
11dc49c772SAnirudh Venkataramanan  * This function inserts the root node of the scheduling tree topology
12dc49c772SAnirudh Venkataramanan  * to the SW DB.
13dc49c772SAnirudh Venkataramanan  */
14dc49c772SAnirudh Venkataramanan static enum ice_status
15dc49c772SAnirudh Venkataramanan ice_sched_add_root_node(struct ice_port_info *pi,
16dc49c772SAnirudh Venkataramanan 			struct ice_aqc_txsched_elem_data *info)
17dc49c772SAnirudh Venkataramanan {
18dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *root;
19dc49c772SAnirudh Venkataramanan 	struct ice_hw *hw;
20dc49c772SAnirudh Venkataramanan 
21dc49c772SAnirudh Venkataramanan 	if (!pi)
22dc49c772SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
23dc49c772SAnirudh Venkataramanan 
24dc49c772SAnirudh Venkataramanan 	hw = pi->hw;
25dc49c772SAnirudh Venkataramanan 
26dc49c772SAnirudh Venkataramanan 	root = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*root), GFP_KERNEL);
27dc49c772SAnirudh Venkataramanan 	if (!root)
28dc49c772SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
29dc49c772SAnirudh Venkataramanan 
30b36c598cSAnirudh Venkataramanan 	/* coverity[suspicious_sizeof] */
31b36c598cSAnirudh Venkataramanan 	root->children = devm_kcalloc(ice_hw_to_dev(hw), hw->max_children[0],
32dc49c772SAnirudh Venkataramanan 				      sizeof(*root), GFP_KERNEL);
33dc49c772SAnirudh Venkataramanan 	if (!root->children) {
34dc49c772SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), root);
35dc49c772SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
36dc49c772SAnirudh Venkataramanan 	}
37dc49c772SAnirudh Venkataramanan 
38dc49c772SAnirudh Venkataramanan 	memcpy(&root->info, info, sizeof(*info));
39dc49c772SAnirudh Venkataramanan 	pi->root = root;
40dc49c772SAnirudh Venkataramanan 	return 0;
41dc49c772SAnirudh Venkataramanan }
42dc49c772SAnirudh Venkataramanan 
43dc49c772SAnirudh Venkataramanan /**
44dc49c772SAnirudh Venkataramanan  * ice_sched_find_node_by_teid - Find the Tx scheduler node in SW DB
45dc49c772SAnirudh Venkataramanan  * @start_node: pointer to the starting ice_sched_node struct in a sub-tree
46f9867df6SAnirudh Venkataramanan  * @teid: node TEID to search
47dc49c772SAnirudh Venkataramanan  *
48f9867df6SAnirudh Venkataramanan  * This function searches for a node matching the TEID in the scheduling tree
49dc49c772SAnirudh Venkataramanan  * from the SW DB. The search is recursive and is restricted by the number of
50dc49c772SAnirudh Venkataramanan  * layers it has searched through; stopping at the max supported layer.
51dc49c772SAnirudh Venkataramanan  *
52dc49c772SAnirudh Venkataramanan  * This function needs to be called when holding the port_info->sched_lock
53dc49c772SAnirudh Venkataramanan  */
54dc49c772SAnirudh Venkataramanan struct ice_sched_node *
55dc49c772SAnirudh Venkataramanan ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid)
56dc49c772SAnirudh Venkataramanan {
57dc49c772SAnirudh Venkataramanan 	u16 i;
58dc49c772SAnirudh Venkataramanan 
59dc49c772SAnirudh Venkataramanan 	/* The TEID is same as that of the start_node */
60dc49c772SAnirudh Venkataramanan 	if (ICE_TXSCHED_GET_NODE_TEID(start_node) == teid)
61dc49c772SAnirudh Venkataramanan 		return start_node;
62dc49c772SAnirudh Venkataramanan 
63dc49c772SAnirudh Venkataramanan 	/* The node has no children or is at the max layer */
64dc49c772SAnirudh Venkataramanan 	if (!start_node->num_children ||
65dc49c772SAnirudh Venkataramanan 	    start_node->tx_sched_layer >= ICE_AQC_TOPO_MAX_LEVEL_NUM ||
66dc49c772SAnirudh Venkataramanan 	    start_node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF)
67dc49c772SAnirudh Venkataramanan 		return NULL;
68dc49c772SAnirudh Venkataramanan 
69f9867df6SAnirudh Venkataramanan 	/* Check if TEID matches to any of the children nodes */
70dc49c772SAnirudh Venkataramanan 	for (i = 0; i < start_node->num_children; i++)
71dc49c772SAnirudh Venkataramanan 		if (ICE_TXSCHED_GET_NODE_TEID(start_node->children[i]) == teid)
72dc49c772SAnirudh Venkataramanan 			return start_node->children[i];
73dc49c772SAnirudh Venkataramanan 
74dc49c772SAnirudh Venkataramanan 	/* Search within each child's sub-tree */
75dc49c772SAnirudh Venkataramanan 	for (i = 0; i < start_node->num_children; i++) {
76dc49c772SAnirudh Venkataramanan 		struct ice_sched_node *tmp;
77dc49c772SAnirudh Venkataramanan 
78dc49c772SAnirudh Venkataramanan 		tmp = ice_sched_find_node_by_teid(start_node->children[i],
79dc49c772SAnirudh Venkataramanan 						  teid);
80dc49c772SAnirudh Venkataramanan 		if (tmp)
81dc49c772SAnirudh Venkataramanan 			return tmp;
82dc49c772SAnirudh Venkataramanan 	}
83dc49c772SAnirudh Venkataramanan 
84dc49c772SAnirudh Venkataramanan 	return NULL;
85dc49c772SAnirudh Venkataramanan }
86dc49c772SAnirudh Venkataramanan 
87dc49c772SAnirudh Venkataramanan /**
881f9c7840SAnirudh Venkataramanan  * ice_aqc_send_sched_elem_cmd - send scheduling elements cmd
89f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
901f9c7840SAnirudh Venkataramanan  * @cmd_opc: cmd opcode
911f9c7840SAnirudh Venkataramanan  * @elems_req: number of elements to request
921f9c7840SAnirudh Venkataramanan  * @buf: pointer to buffer
931f9c7840SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
941f9c7840SAnirudh Venkataramanan  * @elems_resp: returns total number of elements response
951f9c7840SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
961f9c7840SAnirudh Venkataramanan  *
971f9c7840SAnirudh Venkataramanan  * This function sends a scheduling elements cmd (cmd_opc)
981f9c7840SAnirudh Venkataramanan  */
991f9c7840SAnirudh Venkataramanan static enum ice_status
1001f9c7840SAnirudh Venkataramanan ice_aqc_send_sched_elem_cmd(struct ice_hw *hw, enum ice_adminq_opc cmd_opc,
1011f9c7840SAnirudh Venkataramanan 			    u16 elems_req, void *buf, u16 buf_size,
1021f9c7840SAnirudh Venkataramanan 			    u16 *elems_resp, struct ice_sq_cd *cd)
1031f9c7840SAnirudh Venkataramanan {
1041f9c7840SAnirudh Venkataramanan 	struct ice_aqc_sched_elem_cmd *cmd;
1051f9c7840SAnirudh Venkataramanan 	struct ice_aq_desc desc;
1061f9c7840SAnirudh Venkataramanan 	enum ice_status status;
1071f9c7840SAnirudh Venkataramanan 
1081f9c7840SAnirudh Venkataramanan 	cmd = &desc.params.sched_elem_cmd;
1091f9c7840SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, cmd_opc);
1101f9c7840SAnirudh Venkataramanan 	cmd->num_elem_req = cpu_to_le16(elems_req);
1111f9c7840SAnirudh Venkataramanan 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1121f9c7840SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
1131f9c7840SAnirudh Venkataramanan 	if (!status && elems_resp)
1141f9c7840SAnirudh Venkataramanan 		*elems_resp = le16_to_cpu(cmd->num_elem_resp);
1151f9c7840SAnirudh Venkataramanan 
1161f9c7840SAnirudh Venkataramanan 	return status;
1171f9c7840SAnirudh Venkataramanan }
1181f9c7840SAnirudh Venkataramanan 
1191f9c7840SAnirudh Venkataramanan /**
12056daee6cSAnirudh Venkataramanan  * ice_aq_query_sched_elems - query scheduler elements
121f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
12256daee6cSAnirudh Venkataramanan  * @elems_req: number of elements to query
12356daee6cSAnirudh Venkataramanan  * @buf: pointer to buffer
12456daee6cSAnirudh Venkataramanan  * @buf_size: buffer size in bytes
12556daee6cSAnirudh Venkataramanan  * @elems_ret: returns total number of elements returned
12656daee6cSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
12756daee6cSAnirudh Venkataramanan  *
12856daee6cSAnirudh Venkataramanan  * Query scheduling elements (0x0404)
12956daee6cSAnirudh Venkataramanan  */
1307b9ffc76SAnirudh Venkataramanan enum ice_status
13156daee6cSAnirudh Venkataramanan ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req,
132b3c38904SBruce Allan 			 struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
13356daee6cSAnirudh Venkataramanan 			 u16 *elems_ret, struct ice_sq_cd *cd)
13456daee6cSAnirudh Venkataramanan {
1351f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_get_sched_elems,
1361f9c7840SAnirudh Venkataramanan 					   elems_req, (void *)buf, buf_size,
1371f9c7840SAnirudh Venkataramanan 					   elems_ret, cd);
13856daee6cSAnirudh Venkataramanan }
13956daee6cSAnirudh Venkataramanan 
14056daee6cSAnirudh Venkataramanan /**
141dc49c772SAnirudh Venkataramanan  * ice_sched_add_node - Insert the Tx scheduler node in SW DB
142dc49c772SAnirudh Venkataramanan  * @pi: port information structure
143dc49c772SAnirudh Venkataramanan  * @layer: Scheduler layer of the node
144dc49c772SAnirudh Venkataramanan  * @info: Scheduler element information from firmware
145dc49c772SAnirudh Venkataramanan  *
146dc49c772SAnirudh Venkataramanan  * This function inserts a scheduler node to the SW DB.
147dc49c772SAnirudh Venkataramanan  */
148dc49c772SAnirudh Venkataramanan enum ice_status
149dc49c772SAnirudh Venkataramanan ice_sched_add_node(struct ice_port_info *pi, u8 layer,
150dc49c772SAnirudh Venkataramanan 		   struct ice_aqc_txsched_elem_data *info)
151dc49c772SAnirudh Venkataramanan {
152b3c38904SBruce Allan 	struct ice_aqc_txsched_elem_data elem;
153dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *parent;
154dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *node;
15556daee6cSAnirudh Venkataramanan 	enum ice_status status;
156dc49c772SAnirudh Venkataramanan 	struct ice_hw *hw;
157dc49c772SAnirudh Venkataramanan 
158dc49c772SAnirudh Venkataramanan 	if (!pi)
159dc49c772SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
160dc49c772SAnirudh Venkataramanan 
161dc49c772SAnirudh Venkataramanan 	hw = pi->hw;
162dc49c772SAnirudh Venkataramanan 
163dc49c772SAnirudh Venkataramanan 	/* A valid parent node should be there */
164dc49c772SAnirudh Venkataramanan 	parent = ice_sched_find_node_by_teid(pi->root,
165dc49c772SAnirudh Venkataramanan 					     le32_to_cpu(info->parent_teid));
166dc49c772SAnirudh Venkataramanan 	if (!parent) {
1679228d8b2SJacob Keller 		ice_debug(hw, ICE_DBG_SCHED, "Parent Node not found for parent_teid=0x%x\n",
168dc49c772SAnirudh Venkataramanan 			  le32_to_cpu(info->parent_teid));
169dc49c772SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
170dc49c772SAnirudh Venkataramanan 	}
171dc49c772SAnirudh Venkataramanan 
1727dbc63f0STony Nguyen 	/* query the current node information from FW before adding it
17356daee6cSAnirudh Venkataramanan 	 * to the SW DB
17456daee6cSAnirudh Venkataramanan 	 */
17556daee6cSAnirudh Venkataramanan 	status = ice_sched_query_elem(hw, le32_to_cpu(info->node_teid), &elem);
17656daee6cSAnirudh Venkataramanan 	if (status)
17756daee6cSAnirudh Venkataramanan 		return status;
17856daee6cSAnirudh Venkataramanan 
179dc49c772SAnirudh Venkataramanan 	node = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*node), GFP_KERNEL);
180dc49c772SAnirudh Venkataramanan 	if (!node)
181dc49c772SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
182b36c598cSAnirudh Venkataramanan 	if (hw->max_children[layer]) {
183b36c598cSAnirudh Venkataramanan 		/* coverity[suspicious_sizeof] */
184b36c598cSAnirudh Venkataramanan 		node->children = devm_kcalloc(ice_hw_to_dev(hw),
185b36c598cSAnirudh Venkataramanan 					      hw->max_children[layer],
186dc49c772SAnirudh Venkataramanan 					      sizeof(*node), GFP_KERNEL);
187dc49c772SAnirudh Venkataramanan 		if (!node->children) {
188dc49c772SAnirudh Venkataramanan 			devm_kfree(ice_hw_to_dev(hw), node);
189dc49c772SAnirudh Venkataramanan 			return ICE_ERR_NO_MEMORY;
190dc49c772SAnirudh Venkataramanan 		}
191dc49c772SAnirudh Venkataramanan 	}
192dc49c772SAnirudh Venkataramanan 
193dc49c772SAnirudh Venkataramanan 	node->in_use = true;
194dc49c772SAnirudh Venkataramanan 	node->parent = parent;
195dc49c772SAnirudh Venkataramanan 	node->tx_sched_layer = layer;
196dc49c772SAnirudh Venkataramanan 	parent->children[parent->num_children++] = node;
197b3c38904SBruce Allan 	node->info = elem;
198dc49c772SAnirudh Venkataramanan 	return 0;
199dc49c772SAnirudh Venkataramanan }
200dc49c772SAnirudh Venkataramanan 
201dc49c772SAnirudh Venkataramanan /**
2029c20346bSAnirudh Venkataramanan  * ice_aq_delete_sched_elems - delete scheduler elements
203f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
2049c20346bSAnirudh Venkataramanan  * @grps_req: number of groups to delete
2059c20346bSAnirudh Venkataramanan  * @buf: pointer to buffer
2069c20346bSAnirudh Venkataramanan  * @buf_size: buffer size in bytes
2079c20346bSAnirudh Venkataramanan  * @grps_del: returns total number of elements deleted
2089c20346bSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
2099c20346bSAnirudh Venkataramanan  *
2109c20346bSAnirudh Venkataramanan  * Delete scheduling elements (0x040F)
2119c20346bSAnirudh Venkataramanan  */
2129c20346bSAnirudh Venkataramanan static enum ice_status
2139c20346bSAnirudh Venkataramanan ice_aq_delete_sched_elems(struct ice_hw *hw, u16 grps_req,
2149c20346bSAnirudh Venkataramanan 			  struct ice_aqc_delete_elem *buf, u16 buf_size,
2159c20346bSAnirudh Venkataramanan 			  u16 *grps_del, struct ice_sq_cd *cd)
2169c20346bSAnirudh Venkataramanan {
2171f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_delete_sched_elems,
2181f9c7840SAnirudh Venkataramanan 					   grps_req, (void *)buf, buf_size,
2191f9c7840SAnirudh Venkataramanan 					   grps_del, cd);
2209c20346bSAnirudh Venkataramanan }
2219c20346bSAnirudh Venkataramanan 
2229c20346bSAnirudh Venkataramanan /**
223f9867df6SAnirudh Venkataramanan  * ice_sched_remove_elems - remove nodes from HW
224f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
2259c20346bSAnirudh Venkataramanan  * @parent: pointer to the parent node
2269c20346bSAnirudh Venkataramanan  * @num_nodes: number of nodes
2279c20346bSAnirudh Venkataramanan  * @node_teids: array of node teids to be deleted
2289c20346bSAnirudh Venkataramanan  *
229f9867df6SAnirudh Venkataramanan  * This function remove nodes from HW
2309c20346bSAnirudh Venkataramanan  */
2319c20346bSAnirudh Venkataramanan static enum ice_status
2329c20346bSAnirudh Venkataramanan ice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent,
2339c20346bSAnirudh Venkataramanan 		       u16 num_nodes, u32 *node_teids)
2349c20346bSAnirudh Venkataramanan {
2359c20346bSAnirudh Venkataramanan 	struct ice_aqc_delete_elem *buf;
2369c20346bSAnirudh Venkataramanan 	u16 i, num_groups_removed = 0;
2379c20346bSAnirudh Venkataramanan 	enum ice_status status;
2389c20346bSAnirudh Venkataramanan 	u16 buf_size;
2399c20346bSAnirudh Venkataramanan 
24066486d89SBruce Allan 	buf_size = struct_size(buf, teid, num_nodes);
2419c20346bSAnirudh Venkataramanan 	buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);
2429c20346bSAnirudh Venkataramanan 	if (!buf)
2439c20346bSAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
244b36c598cSAnirudh Venkataramanan 
2459c20346bSAnirudh Venkataramanan 	buf->hdr.parent_teid = parent->info.node_teid;
2469c20346bSAnirudh Venkataramanan 	buf->hdr.num_elems = cpu_to_le16(num_nodes);
2479c20346bSAnirudh Venkataramanan 	for (i = 0; i < num_nodes; i++)
2489c20346bSAnirudh Venkataramanan 		buf->teid[i] = cpu_to_le32(node_teids[i]);
249b36c598cSAnirudh Venkataramanan 
2509c20346bSAnirudh Venkataramanan 	status = ice_aq_delete_sched_elems(hw, 1, buf, buf_size,
2519c20346bSAnirudh Venkataramanan 					   &num_groups_removed, NULL);
2529c20346bSAnirudh Venkataramanan 	if (status || num_groups_removed != 1)
253e1ca65a3SVictor Raj 		ice_debug(hw, ICE_DBG_SCHED, "remove node failed FW error %d\n",
254e1ca65a3SVictor Raj 			  hw->adminq.sq_last_status);
255b36c598cSAnirudh Venkataramanan 
2569c20346bSAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), buf);
2579c20346bSAnirudh Venkataramanan 	return status;
2589c20346bSAnirudh Venkataramanan }
2599c20346bSAnirudh Venkataramanan 
2609c20346bSAnirudh Venkataramanan /**
2619c20346bSAnirudh Venkataramanan  * ice_sched_get_first_node - get the first node of the given layer
26229358248SVictor Raj  * @pi: port information structure
2639c20346bSAnirudh Venkataramanan  * @parent: pointer the base node of the subtree
2649c20346bSAnirudh Venkataramanan  * @layer: layer number
2659c20346bSAnirudh Venkataramanan  *
2669c20346bSAnirudh Venkataramanan  * This function retrieves the first node of the given layer from the subtree
2679c20346bSAnirudh Venkataramanan  */
2689c20346bSAnirudh Venkataramanan static struct ice_sched_node *
26929358248SVictor Raj ice_sched_get_first_node(struct ice_port_info *pi,
27029358248SVictor Raj 			 struct ice_sched_node *parent, u8 layer)
2719c20346bSAnirudh Venkataramanan {
27229358248SVictor Raj 	return pi->sib_head[parent->tc_num][layer];
2739c20346bSAnirudh Venkataramanan }
2749c20346bSAnirudh Venkataramanan 
2759c20346bSAnirudh Venkataramanan /**
2769c20346bSAnirudh Venkataramanan  * ice_sched_get_tc_node - get pointer to TC node
2779c20346bSAnirudh Venkataramanan  * @pi: port information structure
2789c20346bSAnirudh Venkataramanan  * @tc: TC number
2799c20346bSAnirudh Venkataramanan  *
2809c20346bSAnirudh Venkataramanan  * This function returns the TC node pointer
2819c20346bSAnirudh Venkataramanan  */
2829c20346bSAnirudh Venkataramanan struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc)
2839c20346bSAnirudh Venkataramanan {
2849c20346bSAnirudh Venkataramanan 	u8 i;
2859c20346bSAnirudh Venkataramanan 
286ade78c2eSAnirudh Venkataramanan 	if (!pi || !pi->root)
2879c20346bSAnirudh Venkataramanan 		return NULL;
2889c20346bSAnirudh Venkataramanan 	for (i = 0; i < pi->root->num_children; i++)
2899c20346bSAnirudh Venkataramanan 		if (pi->root->children[i]->tc_num == tc)
2909c20346bSAnirudh Venkataramanan 			return pi->root->children[i];
2919c20346bSAnirudh Venkataramanan 	return NULL;
2929c20346bSAnirudh Venkataramanan }
2939c20346bSAnirudh Venkataramanan 
2949c20346bSAnirudh Venkataramanan /**
2959c20346bSAnirudh Venkataramanan  * ice_free_sched_node - Free a Tx scheduler node from SW DB
2969c20346bSAnirudh Venkataramanan  * @pi: port information structure
2979c20346bSAnirudh Venkataramanan  * @node: pointer to the ice_sched_node struct
2989c20346bSAnirudh Venkataramanan  *
2999c20346bSAnirudh Venkataramanan  * This function frees up a node from SW DB as well as from HW
3009c20346bSAnirudh Venkataramanan  *
3019c20346bSAnirudh Venkataramanan  * This function needs to be called with the port_info->sched_lock held
3029c20346bSAnirudh Venkataramanan  */
3039c20346bSAnirudh Venkataramanan void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)
3049c20346bSAnirudh Venkataramanan {
3059c20346bSAnirudh Venkataramanan 	struct ice_sched_node *parent;
3069c20346bSAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
3079c20346bSAnirudh Venkataramanan 	u8 i, j;
3089c20346bSAnirudh Venkataramanan 
3099c20346bSAnirudh Venkataramanan 	/* Free the children before freeing up the parent node
3109c20346bSAnirudh Venkataramanan 	 * The parent array is updated below and that shifts the nodes
3119c20346bSAnirudh Venkataramanan 	 * in the array. So always pick the first child if num children > 0
3129c20346bSAnirudh Venkataramanan 	 */
3139c20346bSAnirudh Venkataramanan 	while (node->num_children)
3149c20346bSAnirudh Venkataramanan 		ice_free_sched_node(pi, node->children[0]);
3159c20346bSAnirudh Venkataramanan 
3169c20346bSAnirudh Venkataramanan 	/* Leaf, TC and root nodes can't be deleted by SW */
3179c20346bSAnirudh Venkataramanan 	if (node->tx_sched_layer >= hw->sw_entry_point_layer &&
3189c20346bSAnirudh Venkataramanan 	    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
3199c20346bSAnirudh Venkataramanan 	    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT &&
3209c20346bSAnirudh Venkataramanan 	    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) {
3219c20346bSAnirudh Venkataramanan 		u32 teid = le32_to_cpu(node->info.node_teid);
3229c20346bSAnirudh Venkataramanan 
323e1ca65a3SVictor Raj 		ice_sched_remove_elems(hw, node->parent, 1, &teid);
3249c20346bSAnirudh Venkataramanan 	}
3259c20346bSAnirudh Venkataramanan 	parent = node->parent;
3269c20346bSAnirudh Venkataramanan 	/* root has no parent */
3279c20346bSAnirudh Venkataramanan 	if (parent) {
32829358248SVictor Raj 		struct ice_sched_node *p;
3299c20346bSAnirudh Venkataramanan 
3309c20346bSAnirudh Venkataramanan 		/* update the parent */
3319c20346bSAnirudh Venkataramanan 		for (i = 0; i < parent->num_children; i++)
3329c20346bSAnirudh Venkataramanan 			if (parent->children[i] == node) {
3339c20346bSAnirudh Venkataramanan 				for (j = i + 1; j < parent->num_children; j++)
3349c20346bSAnirudh Venkataramanan 					parent->children[j - 1] =
3359c20346bSAnirudh Venkataramanan 						parent->children[j];
3369c20346bSAnirudh Venkataramanan 				parent->num_children--;
3379c20346bSAnirudh Venkataramanan 				break;
3389c20346bSAnirudh Venkataramanan 			}
3399c20346bSAnirudh Venkataramanan 
34029358248SVictor Raj 		p = ice_sched_get_first_node(pi, node, node->tx_sched_layer);
3419c20346bSAnirudh Venkataramanan 		while (p) {
3429c20346bSAnirudh Venkataramanan 			if (p->sibling == node) {
3439c20346bSAnirudh Venkataramanan 				p->sibling = node->sibling;
3449c20346bSAnirudh Venkataramanan 				break;
3459c20346bSAnirudh Venkataramanan 			}
3469c20346bSAnirudh Venkataramanan 			p = p->sibling;
3479c20346bSAnirudh Venkataramanan 		}
34829358248SVictor Raj 
34929358248SVictor Raj 		/* update the sibling head if head is getting removed */
35029358248SVictor Raj 		if (pi->sib_head[node->tc_num][node->tx_sched_layer] == node)
35129358248SVictor Raj 			pi->sib_head[node->tc_num][node->tx_sched_layer] =
35229358248SVictor Raj 				node->sibling;
3539c20346bSAnirudh Venkataramanan 	}
35429358248SVictor Raj 
3559c20346bSAnirudh Venkataramanan 	/* leaf nodes have no children */
3569c20346bSAnirudh Venkataramanan 	if (node->children)
3579c20346bSAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), node->children);
3589c20346bSAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), node);
3599c20346bSAnirudh Venkataramanan }
3609c20346bSAnirudh Venkataramanan 
3619c20346bSAnirudh Venkataramanan /**
362dc49c772SAnirudh Venkataramanan  * ice_aq_get_dflt_topo - gets default scheduler topology
363f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
364dc49c772SAnirudh Venkataramanan  * @lport: logical port number
365dc49c772SAnirudh Venkataramanan  * @buf: pointer to buffer
366dc49c772SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
367dc49c772SAnirudh Venkataramanan  * @num_branches: returns total number of queue to port branches
368dc49c772SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
369dc49c772SAnirudh Venkataramanan  *
370dc49c772SAnirudh Venkataramanan  * Get default scheduler topology (0x400)
371dc49c772SAnirudh Venkataramanan  */
372dc49c772SAnirudh Venkataramanan static enum ice_status
373dc49c772SAnirudh Venkataramanan ice_aq_get_dflt_topo(struct ice_hw *hw, u8 lport,
374dc49c772SAnirudh Venkataramanan 		     struct ice_aqc_get_topo_elem *buf, u16 buf_size,
375dc49c772SAnirudh Venkataramanan 		     u8 *num_branches, struct ice_sq_cd *cd)
376dc49c772SAnirudh Venkataramanan {
377dc49c772SAnirudh Venkataramanan 	struct ice_aqc_get_topo *cmd;
378dc49c772SAnirudh Venkataramanan 	struct ice_aq_desc desc;
379dc49c772SAnirudh Venkataramanan 	enum ice_status status;
380dc49c772SAnirudh Venkataramanan 
381dc49c772SAnirudh Venkataramanan 	cmd = &desc.params.get_topo;
382dc49c772SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_dflt_topo);
383dc49c772SAnirudh Venkataramanan 	cmd->port_num = lport;
384dc49c772SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
385dc49c772SAnirudh Venkataramanan 	if (!status && num_branches)
386dc49c772SAnirudh Venkataramanan 		*num_branches = cmd->num_branches;
387dc49c772SAnirudh Venkataramanan 
388dc49c772SAnirudh Venkataramanan 	return status;
389dc49c772SAnirudh Venkataramanan }
390dc49c772SAnirudh Venkataramanan 
391dc49c772SAnirudh Venkataramanan /**
3925513b920SAnirudh Venkataramanan  * ice_aq_add_sched_elems - adds scheduling element
393f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
3945513b920SAnirudh Venkataramanan  * @grps_req: the number of groups that are requested to be added
3955513b920SAnirudh Venkataramanan  * @buf: pointer to buffer
3965513b920SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
3975513b920SAnirudh Venkataramanan  * @grps_added: returns total number of groups added
3985513b920SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
3995513b920SAnirudh Venkataramanan  *
4005513b920SAnirudh Venkataramanan  * Add scheduling elements (0x0401)
4015513b920SAnirudh Venkataramanan  */
4025513b920SAnirudh Venkataramanan static enum ice_status
4035513b920SAnirudh Venkataramanan ice_aq_add_sched_elems(struct ice_hw *hw, u16 grps_req,
4045513b920SAnirudh Venkataramanan 		       struct ice_aqc_add_elem *buf, u16 buf_size,
4055513b920SAnirudh Venkataramanan 		       u16 *grps_added, struct ice_sq_cd *cd)
4065513b920SAnirudh Venkataramanan {
4071f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_add_sched_elems,
4081f9c7840SAnirudh Venkataramanan 					   grps_req, (void *)buf, buf_size,
4091f9c7840SAnirudh Venkataramanan 					   grps_added, cd);
4105513b920SAnirudh Venkataramanan }
4115513b920SAnirudh Venkataramanan 
4125513b920SAnirudh Venkataramanan /**
4131ddef455SUsha Ketineni  * ice_aq_cfg_sched_elems - configures scheduler elements
4141ddef455SUsha Ketineni  * @hw: pointer to the HW struct
4151ddef455SUsha Ketineni  * @elems_req: number of elements to configure
4161ddef455SUsha Ketineni  * @buf: pointer to buffer
4171ddef455SUsha Ketineni  * @buf_size: buffer size in bytes
4181ddef455SUsha Ketineni  * @elems_cfgd: returns total number of elements configured
4191ddef455SUsha Ketineni  * @cd: pointer to command details structure or NULL
4201ddef455SUsha Ketineni  *
4211ddef455SUsha Ketineni  * Configure scheduling elements (0x0403)
4221ddef455SUsha Ketineni  */
4231ddef455SUsha Ketineni static enum ice_status
4241ddef455SUsha Ketineni ice_aq_cfg_sched_elems(struct ice_hw *hw, u16 elems_req,
425b3c38904SBruce Allan 		       struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
4261ddef455SUsha Ketineni 		       u16 *elems_cfgd, struct ice_sq_cd *cd)
4271ddef455SUsha Ketineni {
4281ddef455SUsha Ketineni 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_cfg_sched_elems,
4291ddef455SUsha Ketineni 					   elems_req, (void *)buf, buf_size,
4301ddef455SUsha Ketineni 					   elems_cfgd, cd);
4311ddef455SUsha Ketineni }
4321ddef455SUsha Ketineni 
4331ddef455SUsha Ketineni /**
434b126bd6bSKiran Patil  * ice_aq_move_sched_elems - move scheduler elements
435b126bd6bSKiran Patil  * @hw: pointer to the HW struct
436b126bd6bSKiran Patil  * @grps_req: number of groups to move
437b126bd6bSKiran Patil  * @buf: pointer to buffer
438b126bd6bSKiran Patil  * @buf_size: buffer size in bytes
439b126bd6bSKiran Patil  * @grps_movd: returns total number of groups moved
440b126bd6bSKiran Patil  * @cd: pointer to command details structure or NULL
441b126bd6bSKiran Patil  *
442b126bd6bSKiran Patil  * Move scheduling elements (0x0408)
443b126bd6bSKiran Patil  */
444b126bd6bSKiran Patil static enum ice_status
445b126bd6bSKiran Patil ice_aq_move_sched_elems(struct ice_hw *hw, u16 grps_req,
446b126bd6bSKiran Patil 			struct ice_aqc_move_elem *buf, u16 buf_size,
447b126bd6bSKiran Patil 			u16 *grps_movd, struct ice_sq_cd *cd)
448b126bd6bSKiran Patil {
449b126bd6bSKiran Patil 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_move_sched_elems,
450b126bd6bSKiran Patil 					   grps_req, (void *)buf, buf_size,
451b126bd6bSKiran Patil 					   grps_movd, cd);
452b126bd6bSKiran Patil }
453b126bd6bSKiran Patil 
454b126bd6bSKiran Patil /**
4555513b920SAnirudh Venkataramanan  * ice_aq_suspend_sched_elems - suspend scheduler elements
456f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
4575513b920SAnirudh Venkataramanan  * @elems_req: number of elements to suspend
4585513b920SAnirudh Venkataramanan  * @buf: pointer to buffer
4595513b920SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
4605513b920SAnirudh Venkataramanan  * @elems_ret: returns total number of elements suspended
4615513b920SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
4625513b920SAnirudh Venkataramanan  *
4635513b920SAnirudh Venkataramanan  * Suspend scheduling elements (0x0409)
4645513b920SAnirudh Venkataramanan  */
4655513b920SAnirudh Venkataramanan static enum ice_status
466b3c38904SBruce Allan ice_aq_suspend_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf,
4675513b920SAnirudh Venkataramanan 			   u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)
4685513b920SAnirudh Venkataramanan {
4691f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_suspend_sched_elems,
4701f9c7840SAnirudh Venkataramanan 					   elems_req, (void *)buf, buf_size,
4711f9c7840SAnirudh Venkataramanan 					   elems_ret, cd);
4725513b920SAnirudh Venkataramanan }
4735513b920SAnirudh Venkataramanan 
4745513b920SAnirudh Venkataramanan /**
4755513b920SAnirudh Venkataramanan  * ice_aq_resume_sched_elems - resume scheduler elements
476f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
4775513b920SAnirudh Venkataramanan  * @elems_req: number of elements to resume
4785513b920SAnirudh Venkataramanan  * @buf: pointer to buffer
4795513b920SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
4805513b920SAnirudh Venkataramanan  * @elems_ret: returns total number of elements resumed
4815513b920SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
4825513b920SAnirudh Venkataramanan  *
4835513b920SAnirudh Venkataramanan  * resume scheduling elements (0x040A)
4845513b920SAnirudh Venkataramanan  */
4855513b920SAnirudh Venkataramanan static enum ice_status
486b3c38904SBruce Allan ice_aq_resume_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf,
4875513b920SAnirudh Venkataramanan 			  u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)
4885513b920SAnirudh Venkataramanan {
4891f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_resume_sched_elems,
4901f9c7840SAnirudh Venkataramanan 					   elems_req, (void *)buf, buf_size,
4911f9c7840SAnirudh Venkataramanan 					   elems_ret, cd);
4925513b920SAnirudh Venkataramanan }
4935513b920SAnirudh Venkataramanan 
4945513b920SAnirudh Venkataramanan /**
4959c20346bSAnirudh Venkataramanan  * ice_aq_query_sched_res - query scheduler resource
496f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
4979c20346bSAnirudh Venkataramanan  * @buf_size: buffer size in bytes
4989c20346bSAnirudh Venkataramanan  * @buf: pointer to buffer
4999c20346bSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
5009c20346bSAnirudh Venkataramanan  *
5019c20346bSAnirudh Venkataramanan  * Query scheduler resource allocation (0x0412)
5029c20346bSAnirudh Venkataramanan  */
5039c20346bSAnirudh Venkataramanan static enum ice_status
5049c20346bSAnirudh Venkataramanan ice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size,
5059c20346bSAnirudh Venkataramanan 		       struct ice_aqc_query_txsched_res_resp *buf,
5069c20346bSAnirudh Venkataramanan 		       struct ice_sq_cd *cd)
5079c20346bSAnirudh Venkataramanan {
5089c20346bSAnirudh Venkataramanan 	struct ice_aq_desc desc;
5099c20346bSAnirudh Venkataramanan 
5109c20346bSAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_sched_res);
5119c20346bSAnirudh Venkataramanan 	return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
5129c20346bSAnirudh Venkataramanan }
5139c20346bSAnirudh Venkataramanan 
5149c20346bSAnirudh Venkataramanan /**
515f9867df6SAnirudh Venkataramanan  * ice_sched_suspend_resume_elems - suspend or resume HW nodes
516f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
5175513b920SAnirudh Venkataramanan  * @num_nodes: number of nodes
5185513b920SAnirudh Venkataramanan  * @node_teids: array of node teids to be suspended or resumed
5195513b920SAnirudh Venkataramanan  * @suspend: true means suspend / false means resume
5205513b920SAnirudh Venkataramanan  *
521f9867df6SAnirudh Venkataramanan  * This function suspends or resumes HW nodes
5225513b920SAnirudh Venkataramanan  */
5235513b920SAnirudh Venkataramanan static enum ice_status
5245513b920SAnirudh Venkataramanan ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids,
5255513b920SAnirudh Venkataramanan 			       bool suspend)
5265513b920SAnirudh Venkataramanan {
5275513b920SAnirudh Venkataramanan 	u16 i, buf_size, num_elem_ret = 0;
5285513b920SAnirudh Venkataramanan 	enum ice_status status;
529b3c38904SBruce Allan 	__le32 *buf;
5305513b920SAnirudh Venkataramanan 
5315513b920SAnirudh Venkataramanan 	buf_size = sizeof(*buf) * num_nodes;
5325513b920SAnirudh Venkataramanan 	buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);
5335513b920SAnirudh Venkataramanan 	if (!buf)
5345513b920SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
5355513b920SAnirudh Venkataramanan 
5365513b920SAnirudh Venkataramanan 	for (i = 0; i < num_nodes; i++)
537b3c38904SBruce Allan 		buf[i] = cpu_to_le32(node_teids[i]);
5385513b920SAnirudh Venkataramanan 
5395513b920SAnirudh Venkataramanan 	if (suspend)
5405513b920SAnirudh Venkataramanan 		status = ice_aq_suspend_sched_elems(hw, num_nodes, buf,
5415513b920SAnirudh Venkataramanan 						    buf_size, &num_elem_ret,
5425513b920SAnirudh Venkataramanan 						    NULL);
5435513b920SAnirudh Venkataramanan 	else
5445513b920SAnirudh Venkataramanan 		status = ice_aq_resume_sched_elems(hw, num_nodes, buf,
5455513b920SAnirudh Venkataramanan 						   buf_size, &num_elem_ret,
5465513b920SAnirudh Venkataramanan 						   NULL);
5475513b920SAnirudh Venkataramanan 	if (status || num_elem_ret != num_nodes)
5485513b920SAnirudh Venkataramanan 		ice_debug(hw, ICE_DBG_SCHED, "suspend/resume failed\n");
5495513b920SAnirudh Venkataramanan 
5505513b920SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), buf);
5515513b920SAnirudh Venkataramanan 	return status;
5525513b920SAnirudh Venkataramanan }
5535513b920SAnirudh Venkataramanan 
5545513b920SAnirudh Venkataramanan /**
555bb87ee0eSAnirudh Venkataramanan  * ice_alloc_lan_q_ctx - allocate LAN queue contexts for the given VSI and TC
556bb87ee0eSAnirudh Venkataramanan  * @hw: pointer to the HW struct
557bb87ee0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle
558bb87ee0eSAnirudh Venkataramanan  * @tc: TC number
559bb87ee0eSAnirudh Venkataramanan  * @new_numqs: number of queues
560bb87ee0eSAnirudh Venkataramanan  */
561bb87ee0eSAnirudh Venkataramanan static enum ice_status
562bb87ee0eSAnirudh Venkataramanan ice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
563bb87ee0eSAnirudh Venkataramanan {
564bb87ee0eSAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
565bb87ee0eSAnirudh Venkataramanan 	struct ice_q_ctx *q_ctx;
566bb87ee0eSAnirudh Venkataramanan 
567bb87ee0eSAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
568bb87ee0eSAnirudh Venkataramanan 	if (!vsi_ctx)
569bb87ee0eSAnirudh Venkataramanan 		return ICE_ERR_PARAM;
570bb87ee0eSAnirudh Venkataramanan 	/* allocate LAN queue contexts */
571bb87ee0eSAnirudh Venkataramanan 	if (!vsi_ctx->lan_q_ctx[tc]) {
572bb87ee0eSAnirudh Venkataramanan 		vsi_ctx->lan_q_ctx[tc] = devm_kcalloc(ice_hw_to_dev(hw),
573bb87ee0eSAnirudh Venkataramanan 						      new_numqs,
574bb87ee0eSAnirudh Venkataramanan 						      sizeof(*q_ctx),
575bb87ee0eSAnirudh Venkataramanan 						      GFP_KERNEL);
576bb87ee0eSAnirudh Venkataramanan 		if (!vsi_ctx->lan_q_ctx[tc])
577bb87ee0eSAnirudh Venkataramanan 			return ICE_ERR_NO_MEMORY;
578bb87ee0eSAnirudh Venkataramanan 		vsi_ctx->num_lan_q_entries[tc] = new_numqs;
579bb87ee0eSAnirudh Venkataramanan 		return 0;
580bb87ee0eSAnirudh Venkataramanan 	}
581bb87ee0eSAnirudh Venkataramanan 	/* num queues are increased, update the queue contexts */
582bb87ee0eSAnirudh Venkataramanan 	if (new_numqs > vsi_ctx->num_lan_q_entries[tc]) {
583bb87ee0eSAnirudh Venkataramanan 		u16 prev_num = vsi_ctx->num_lan_q_entries[tc];
584bb87ee0eSAnirudh Venkataramanan 
585bb87ee0eSAnirudh Venkataramanan 		q_ctx = devm_kcalloc(ice_hw_to_dev(hw), new_numqs,
586bb87ee0eSAnirudh Venkataramanan 				     sizeof(*q_ctx), GFP_KERNEL);
587bb87ee0eSAnirudh Venkataramanan 		if (!q_ctx)
588bb87ee0eSAnirudh Venkataramanan 			return ICE_ERR_NO_MEMORY;
589bb87ee0eSAnirudh Venkataramanan 		memcpy(q_ctx, vsi_ctx->lan_q_ctx[tc],
590bb87ee0eSAnirudh Venkataramanan 		       prev_num * sizeof(*q_ctx));
591bb87ee0eSAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), vsi_ctx->lan_q_ctx[tc]);
592bb87ee0eSAnirudh Venkataramanan 		vsi_ctx->lan_q_ctx[tc] = q_ctx;
593bb87ee0eSAnirudh Venkataramanan 		vsi_ctx->num_lan_q_entries[tc] = new_numqs;
594bb87ee0eSAnirudh Venkataramanan 	}
595bb87ee0eSAnirudh Venkataramanan 	return 0;
596bb87ee0eSAnirudh Venkataramanan }
597bb87ee0eSAnirudh Venkataramanan 
598bb87ee0eSAnirudh Venkataramanan /**
5991ddef455SUsha Ketineni  * ice_aq_rl_profile - performs a rate limiting task
6001ddef455SUsha Ketineni  * @hw: pointer to the HW struct
6011ddef455SUsha Ketineni  * @opcode: opcode for add, query, or remove profile(s)
6021ddef455SUsha Ketineni  * @num_profiles: the number of profiles
6031ddef455SUsha Ketineni  * @buf: pointer to buffer
6041ddef455SUsha Ketineni  * @buf_size: buffer size in bytes
6051ddef455SUsha Ketineni  * @num_processed: number of processed add or remove profile(s) to return
6061ddef455SUsha Ketineni  * @cd: pointer to command details structure
6071ddef455SUsha Ketineni  *
6081ddef455SUsha Ketineni  * RL profile function to add, query, or remove profile(s)
6091ddef455SUsha Ketineni  */
6101ddef455SUsha Ketineni static enum ice_status
6111ddef455SUsha Ketineni ice_aq_rl_profile(struct ice_hw *hw, enum ice_adminq_opc opcode,
612b3c38904SBruce Allan 		  u16 num_profiles, struct ice_aqc_rl_profile_elem *buf,
6131ddef455SUsha Ketineni 		  u16 buf_size, u16 *num_processed, struct ice_sq_cd *cd)
6141ddef455SUsha Ketineni {
6151ddef455SUsha Ketineni 	struct ice_aqc_rl_profile *cmd;
6161ddef455SUsha Ketineni 	struct ice_aq_desc desc;
6171ddef455SUsha Ketineni 	enum ice_status status;
6181ddef455SUsha Ketineni 
6191ddef455SUsha Ketineni 	cmd = &desc.params.rl_profile;
6201ddef455SUsha Ketineni 
6211ddef455SUsha Ketineni 	ice_fill_dflt_direct_cmd_desc(&desc, opcode);
6221ddef455SUsha Ketineni 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
6231ddef455SUsha Ketineni 	cmd->num_profiles = cpu_to_le16(num_profiles);
6241ddef455SUsha Ketineni 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
6251ddef455SUsha Ketineni 	if (!status && num_processed)
6261ddef455SUsha Ketineni 		*num_processed = le16_to_cpu(cmd->num_processed);
6271ddef455SUsha Ketineni 	return status;
6281ddef455SUsha Ketineni }
6291ddef455SUsha Ketineni 
6301ddef455SUsha Ketineni /**
6311ddef455SUsha Ketineni  * ice_aq_add_rl_profile - adds rate limiting profile(s)
6321ddef455SUsha Ketineni  * @hw: pointer to the HW struct
6331ddef455SUsha Ketineni  * @num_profiles: the number of profile(s) to be add
6341ddef455SUsha Ketineni  * @buf: pointer to buffer
6351ddef455SUsha Ketineni  * @buf_size: buffer size in bytes
6361ddef455SUsha Ketineni  * @num_profiles_added: total number of profiles added to return
6371ddef455SUsha Ketineni  * @cd: pointer to command details structure
6381ddef455SUsha Ketineni  *
6391ddef455SUsha Ketineni  * Add RL profile (0x0410)
6401ddef455SUsha Ketineni  */
6411ddef455SUsha Ketineni static enum ice_status
6421ddef455SUsha Ketineni ice_aq_add_rl_profile(struct ice_hw *hw, u16 num_profiles,
643b3c38904SBruce Allan 		      struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
644b3c38904SBruce Allan 		      u16 *num_profiles_added, struct ice_sq_cd *cd)
6451ddef455SUsha Ketineni {
646b3c38904SBruce Allan 	return ice_aq_rl_profile(hw, ice_aqc_opc_add_rl_profiles, num_profiles,
647b3c38904SBruce Allan 				 buf, buf_size, num_profiles_added, cd);
6481ddef455SUsha Ketineni }
6491ddef455SUsha Ketineni 
6501ddef455SUsha Ketineni /**
6511ddef455SUsha Ketineni  * ice_aq_remove_rl_profile - removes RL profile(s)
6521ddef455SUsha Ketineni  * @hw: pointer to the HW struct
6531ddef455SUsha Ketineni  * @num_profiles: the number of profile(s) to remove
6541ddef455SUsha Ketineni  * @buf: pointer to buffer
6551ddef455SUsha Ketineni  * @buf_size: buffer size in bytes
6561ddef455SUsha Ketineni  * @num_profiles_removed: total number of profiles removed to return
6571ddef455SUsha Ketineni  * @cd: pointer to command details structure or NULL
6581ddef455SUsha Ketineni  *
6591ddef455SUsha Ketineni  * Remove RL profile (0x0415)
6601ddef455SUsha Ketineni  */
6611ddef455SUsha Ketineni static enum ice_status
6621ddef455SUsha Ketineni ice_aq_remove_rl_profile(struct ice_hw *hw, u16 num_profiles,
663b3c38904SBruce Allan 			 struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
664b3c38904SBruce Allan 			 u16 *num_profiles_removed, struct ice_sq_cd *cd)
6651ddef455SUsha Ketineni {
6661ddef455SUsha Ketineni 	return ice_aq_rl_profile(hw, ice_aqc_opc_remove_rl_profiles,
667b3c38904SBruce Allan 				 num_profiles, buf, buf_size,
668b3c38904SBruce Allan 				 num_profiles_removed, cd);
6691ddef455SUsha Ketineni }
6701ddef455SUsha Ketineni 
6711ddef455SUsha Ketineni /**
6721ddef455SUsha Ketineni  * ice_sched_del_rl_profile - remove RL profile
6731ddef455SUsha Ketineni  * @hw: pointer to the HW struct
6741ddef455SUsha Ketineni  * @rl_info: rate limit profile information
6751ddef455SUsha Ketineni  *
6761ddef455SUsha Ketineni  * If the profile ID is not referenced anymore, it removes profile ID with
6771ddef455SUsha Ketineni  * its associated parameters from HW DB,and locally. The caller needs to
6781ddef455SUsha Ketineni  * hold scheduler lock.
6791ddef455SUsha Ketineni  */
6801ddef455SUsha Ketineni static enum ice_status
6811ddef455SUsha Ketineni ice_sched_del_rl_profile(struct ice_hw *hw,
6821ddef455SUsha Ketineni 			 struct ice_aqc_rl_profile_info *rl_info)
6831ddef455SUsha Ketineni {
684b3c38904SBruce Allan 	struct ice_aqc_rl_profile_elem *buf;
6851ddef455SUsha Ketineni 	u16 num_profiles_removed;
6861ddef455SUsha Ketineni 	enum ice_status status;
6871ddef455SUsha Ketineni 	u16 num_profiles = 1;
6881ddef455SUsha Ketineni 
6891ddef455SUsha Ketineni 	if (rl_info->prof_id_ref != 0)
6901ddef455SUsha Ketineni 		return ICE_ERR_IN_USE;
6911ddef455SUsha Ketineni 
6921ddef455SUsha Ketineni 	/* Safe to remove profile ID */
693b3c38904SBruce Allan 	buf = &rl_info->profile;
6941ddef455SUsha Ketineni 	status = ice_aq_remove_rl_profile(hw, num_profiles, buf, sizeof(*buf),
6951ddef455SUsha Ketineni 					  &num_profiles_removed, NULL);
6961ddef455SUsha Ketineni 	if (status || num_profiles_removed != num_profiles)
6971ddef455SUsha Ketineni 		return ICE_ERR_CFG;
6981ddef455SUsha Ketineni 
6991ddef455SUsha Ketineni 	/* Delete stale entry now */
7001ddef455SUsha Ketineni 	list_del(&rl_info->list_entry);
7011ddef455SUsha Ketineni 	devm_kfree(ice_hw_to_dev(hw), rl_info);
7021ddef455SUsha Ketineni 	return status;
7031ddef455SUsha Ketineni }
7041ddef455SUsha Ketineni 
7051ddef455SUsha Ketineni /**
7061ddef455SUsha Ketineni  * ice_sched_clear_rl_prof - clears RL prof entries
7071ddef455SUsha Ketineni  * @pi: port information structure
7081ddef455SUsha Ketineni  *
7091ddef455SUsha Ketineni  * This function removes all RL profile from HW as well as from SW DB.
7101ddef455SUsha Ketineni  */
7111ddef455SUsha Ketineni static void ice_sched_clear_rl_prof(struct ice_port_info *pi)
7121ddef455SUsha Ketineni {
7131ddef455SUsha Ketineni 	u16 ln;
7141ddef455SUsha Ketineni 
7151ddef455SUsha Ketineni 	for (ln = 0; ln < pi->hw->num_tx_sched_layers; ln++) {
7161ddef455SUsha Ketineni 		struct ice_aqc_rl_profile_info *rl_prof_elem;
7171ddef455SUsha Ketineni 		struct ice_aqc_rl_profile_info *rl_prof_tmp;
7181ddef455SUsha Ketineni 
7191ddef455SUsha Ketineni 		list_for_each_entry_safe(rl_prof_elem, rl_prof_tmp,
7201ddef455SUsha Ketineni 					 &pi->rl_prof_list[ln], list_entry) {
7211ddef455SUsha Ketineni 			struct ice_hw *hw = pi->hw;
7221ddef455SUsha Ketineni 			enum ice_status status;
7231ddef455SUsha Ketineni 
7241ddef455SUsha Ketineni 			rl_prof_elem->prof_id_ref = 0;
7251ddef455SUsha Ketineni 			status = ice_sched_del_rl_profile(hw, rl_prof_elem);
7261ddef455SUsha Ketineni 			if (status) {
7279228d8b2SJacob Keller 				ice_debug(hw, ICE_DBG_SCHED, "Remove rl profile failed\n");
7281ddef455SUsha Ketineni 				/* On error, free mem required */
7291ddef455SUsha Ketineni 				list_del(&rl_prof_elem->list_entry);
7301ddef455SUsha Ketineni 				devm_kfree(ice_hw_to_dev(hw), rl_prof_elem);
7311ddef455SUsha Ketineni 			}
7321ddef455SUsha Ketineni 		}
7331ddef455SUsha Ketineni 	}
7341ddef455SUsha Ketineni }
7351ddef455SUsha Ketineni 
7361ddef455SUsha Ketineni /**
737f9867df6SAnirudh Venkataramanan  * ice_sched_clear_agg - clears the aggregator related information
7389be1d6f8SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
7399c20346bSAnirudh Venkataramanan  *
740f9867df6SAnirudh Venkataramanan  * This function removes aggregator list and free up aggregator related memory
7419be1d6f8SAnirudh Venkataramanan  * previously allocated.
7429c20346bSAnirudh Venkataramanan  */
7439be1d6f8SAnirudh Venkataramanan void ice_sched_clear_agg(struct ice_hw *hw)
7449c20346bSAnirudh Venkataramanan {
7459c20346bSAnirudh Venkataramanan 	struct ice_sched_agg_info *agg_info;
7469c20346bSAnirudh Venkataramanan 	struct ice_sched_agg_info *atmp;
7479c20346bSAnirudh Venkataramanan 
7489be1d6f8SAnirudh Venkataramanan 	list_for_each_entry_safe(agg_info, atmp, &hw->agg_list, list_entry) {
7499c20346bSAnirudh Venkataramanan 		struct ice_sched_agg_vsi_info *agg_vsi_info;
7509c20346bSAnirudh Venkataramanan 		struct ice_sched_agg_vsi_info *vtmp;
7519c20346bSAnirudh Venkataramanan 
7529c20346bSAnirudh Venkataramanan 		list_for_each_entry_safe(agg_vsi_info, vtmp,
7539c20346bSAnirudh Venkataramanan 					 &agg_info->agg_vsi_list, list_entry) {
7549c20346bSAnirudh Venkataramanan 			list_del(&agg_vsi_info->list_entry);
7559c20346bSAnirudh Venkataramanan 			devm_kfree(ice_hw_to_dev(hw), agg_vsi_info);
7569c20346bSAnirudh Venkataramanan 		}
7579be1d6f8SAnirudh Venkataramanan 		list_del(&agg_info->list_entry);
7589be1d6f8SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), agg_info);
7599be1d6f8SAnirudh Venkataramanan 	}
7609c20346bSAnirudh Venkataramanan }
7619c20346bSAnirudh Venkataramanan 
7629be1d6f8SAnirudh Venkataramanan /**
7639be1d6f8SAnirudh Venkataramanan  * ice_sched_clear_tx_topo - clears the scheduler tree nodes
7649be1d6f8SAnirudh Venkataramanan  * @pi: port information structure
7659be1d6f8SAnirudh Venkataramanan  *
7669be1d6f8SAnirudh Venkataramanan  * This function removes all the nodes from HW as well as from SW DB.
7679be1d6f8SAnirudh Venkataramanan  */
7689be1d6f8SAnirudh Venkataramanan static void ice_sched_clear_tx_topo(struct ice_port_info *pi)
7699be1d6f8SAnirudh Venkataramanan {
7709be1d6f8SAnirudh Venkataramanan 	if (!pi)
7719be1d6f8SAnirudh Venkataramanan 		return;
7721ddef455SUsha Ketineni 	/* remove RL profiles related lists */
7731ddef455SUsha Ketineni 	ice_sched_clear_rl_prof(pi);
7749c20346bSAnirudh Venkataramanan 	if (pi->root) {
7759c20346bSAnirudh Venkataramanan 		ice_free_sched_node(pi, pi->root);
7769c20346bSAnirudh Venkataramanan 		pi->root = NULL;
7779c20346bSAnirudh Venkataramanan 	}
7789c20346bSAnirudh Venkataramanan }
7799c20346bSAnirudh Venkataramanan 
7809c20346bSAnirudh Venkataramanan /**
7819c20346bSAnirudh Venkataramanan  * ice_sched_clear_port - clear the scheduler elements from SW DB for a port
7829c20346bSAnirudh Venkataramanan  * @pi: port information structure
7839c20346bSAnirudh Venkataramanan  *
7849c20346bSAnirudh Venkataramanan  * Cleanup scheduling elements from SW DB
7859c20346bSAnirudh Venkataramanan  */
786c5a2a4a3SUsha Ketineni void ice_sched_clear_port(struct ice_port_info *pi)
7879c20346bSAnirudh Venkataramanan {
7889c20346bSAnirudh Venkataramanan 	if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
7899c20346bSAnirudh Venkataramanan 		return;
7909c20346bSAnirudh Venkataramanan 
7919c20346bSAnirudh Venkataramanan 	pi->port_state = ICE_SCHED_PORT_STATE_INIT;
7929c20346bSAnirudh Venkataramanan 	mutex_lock(&pi->sched_lock);
7939c20346bSAnirudh Venkataramanan 	ice_sched_clear_tx_topo(pi);
7949c20346bSAnirudh Venkataramanan 	mutex_unlock(&pi->sched_lock);
7959c20346bSAnirudh Venkataramanan 	mutex_destroy(&pi->sched_lock);
7969c20346bSAnirudh Venkataramanan }
7979c20346bSAnirudh Venkataramanan 
7989c20346bSAnirudh Venkataramanan /**
7999c20346bSAnirudh Venkataramanan  * ice_sched_cleanup_all - cleanup scheduler elements from SW DB for all ports
800f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
8019c20346bSAnirudh Venkataramanan  *
8029c20346bSAnirudh Venkataramanan  * Cleanup scheduling elements from SW DB for all the ports
8039c20346bSAnirudh Venkataramanan  */
8049c20346bSAnirudh Venkataramanan void ice_sched_cleanup_all(struct ice_hw *hw)
8059c20346bSAnirudh Venkataramanan {
806b36c598cSAnirudh Venkataramanan 	if (!hw)
8079c20346bSAnirudh Venkataramanan 		return;
8089c20346bSAnirudh Venkataramanan 
809b36c598cSAnirudh Venkataramanan 	if (hw->layer_info) {
8109c20346bSAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), hw->layer_info);
811b36c598cSAnirudh Venkataramanan 		hw->layer_info = NULL;
812b36c598cSAnirudh Venkataramanan 	}
8139c20346bSAnirudh Venkataramanan 
8149c20346bSAnirudh Venkataramanan 	ice_sched_clear_port(hw->port_info);
8159c20346bSAnirudh Venkataramanan 
8169c20346bSAnirudh Venkataramanan 	hw->num_tx_sched_layers = 0;
8179c20346bSAnirudh Venkataramanan 	hw->num_tx_sched_phys_layers = 0;
8189c20346bSAnirudh Venkataramanan 	hw->flattened_layers = 0;
8199c20346bSAnirudh Venkataramanan 	hw->max_cgds = 0;
8209c20346bSAnirudh Venkataramanan }
8219c20346bSAnirudh Venkataramanan 
8229c20346bSAnirudh Venkataramanan /**
823f9867df6SAnirudh Venkataramanan  * ice_sched_add_elems - add nodes to HW and SW DB
8245513b920SAnirudh Venkataramanan  * @pi: port information structure
8255513b920SAnirudh Venkataramanan  * @tc_node: pointer to the branch node
8265513b920SAnirudh Venkataramanan  * @parent: pointer to the parent node
8275513b920SAnirudh Venkataramanan  * @layer: layer number to add nodes
8285513b920SAnirudh Venkataramanan  * @num_nodes: number of nodes
8295513b920SAnirudh Venkataramanan  * @num_nodes_added: pointer to num nodes added
830f9867df6SAnirudh Venkataramanan  * @first_node_teid: if new nodes are added then return the TEID of first node
8315513b920SAnirudh Venkataramanan  *
832f9867df6SAnirudh Venkataramanan  * This function add nodes to HW as well as to SW DB for a given layer
8335513b920SAnirudh Venkataramanan  */
8345513b920SAnirudh Venkataramanan static enum ice_status
8355513b920SAnirudh Venkataramanan ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
8365513b920SAnirudh Venkataramanan 		    struct ice_sched_node *parent, u8 layer, u16 num_nodes,
8375513b920SAnirudh Venkataramanan 		    u16 *num_nodes_added, u32 *first_node_teid)
8385513b920SAnirudh Venkataramanan {
8395513b920SAnirudh Venkataramanan 	struct ice_sched_node *prev, *new_node;
8405513b920SAnirudh Venkataramanan 	struct ice_aqc_add_elem *buf;
8415513b920SAnirudh Venkataramanan 	u16 i, num_groups_added = 0;
8425513b920SAnirudh Venkataramanan 	enum ice_status status = 0;
8435513b920SAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
84489f6a305SGustavo A. R. Silva 	size_t buf_size;
8455513b920SAnirudh Venkataramanan 	u32 teid;
8465513b920SAnirudh Venkataramanan 
84766486d89SBruce Allan 	buf_size = struct_size(buf, generic, num_nodes);
8485513b920SAnirudh Venkataramanan 	buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);
8495513b920SAnirudh Venkataramanan 	if (!buf)
8505513b920SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
8515513b920SAnirudh Venkataramanan 
8525513b920SAnirudh Venkataramanan 	buf->hdr.parent_teid = parent->info.node_teid;
8535513b920SAnirudh Venkataramanan 	buf->hdr.num_elems = cpu_to_le16(num_nodes);
8545513b920SAnirudh Venkataramanan 	for (i = 0; i < num_nodes; i++) {
8555513b920SAnirudh Venkataramanan 		buf->generic[i].parent_teid = parent->info.node_teid;
8565513b920SAnirudh Venkataramanan 		buf->generic[i].data.elem_type = ICE_AQC_ELEM_TYPE_SE_GENERIC;
8575513b920SAnirudh Venkataramanan 		buf->generic[i].data.valid_sections =
8585513b920SAnirudh Venkataramanan 			ICE_AQC_ELEM_VALID_GENERIC | ICE_AQC_ELEM_VALID_CIR |
8595513b920SAnirudh Venkataramanan 			ICE_AQC_ELEM_VALID_EIR;
8605513b920SAnirudh Venkataramanan 		buf->generic[i].data.generic = 0;
8615513b920SAnirudh Venkataramanan 		buf->generic[i].data.cir_bw.bw_profile_idx =
862b36c598cSAnirudh Venkataramanan 			cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
863b36c598cSAnirudh Venkataramanan 		buf->generic[i].data.cir_bw.bw_alloc =
864b36c598cSAnirudh Venkataramanan 			cpu_to_le16(ICE_SCHED_DFLT_BW_WT);
8655513b920SAnirudh Venkataramanan 		buf->generic[i].data.eir_bw.bw_profile_idx =
866b36c598cSAnirudh Venkataramanan 			cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
867b36c598cSAnirudh Venkataramanan 		buf->generic[i].data.eir_bw.bw_alloc =
868b36c598cSAnirudh Venkataramanan 			cpu_to_le16(ICE_SCHED_DFLT_BW_WT);
8695513b920SAnirudh Venkataramanan 	}
8705513b920SAnirudh Venkataramanan 
8715513b920SAnirudh Venkataramanan 	status = ice_aq_add_sched_elems(hw, 1, buf, buf_size,
8725513b920SAnirudh Venkataramanan 					&num_groups_added, NULL);
8735513b920SAnirudh Venkataramanan 	if (status || num_groups_added != 1) {
874e1ca65a3SVictor Raj 		ice_debug(hw, ICE_DBG_SCHED, "add node failed FW Error %d\n",
875e1ca65a3SVictor Raj 			  hw->adminq.sq_last_status);
8765513b920SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), buf);
8775513b920SAnirudh Venkataramanan 		return ICE_ERR_CFG;
8785513b920SAnirudh Venkataramanan 	}
8795513b920SAnirudh Venkataramanan 
8805513b920SAnirudh Venkataramanan 	*num_nodes_added = num_nodes;
8815513b920SAnirudh Venkataramanan 	/* add nodes to the SW DB */
8825513b920SAnirudh Venkataramanan 	for (i = 0; i < num_nodes; i++) {
8835513b920SAnirudh Venkataramanan 		status = ice_sched_add_node(pi, layer, &buf->generic[i]);
8845513b920SAnirudh Venkataramanan 		if (status) {
8859228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_SCHED, "add nodes in SW DB failed status =%d\n",
8865513b920SAnirudh Venkataramanan 				  status);
8875513b920SAnirudh Venkataramanan 			break;
8885513b920SAnirudh Venkataramanan 		}
8895513b920SAnirudh Venkataramanan 
8905513b920SAnirudh Venkataramanan 		teid = le32_to_cpu(buf->generic[i].node_teid);
8915513b920SAnirudh Venkataramanan 		new_node = ice_sched_find_node_by_teid(parent, teid);
8925513b920SAnirudh Venkataramanan 		if (!new_node) {
8939228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_SCHED, "Node is missing for teid =%d\n", teid);
8945513b920SAnirudh Venkataramanan 			break;
8955513b920SAnirudh Venkataramanan 		}
8965513b920SAnirudh Venkataramanan 
8975513b920SAnirudh Venkataramanan 		new_node->sibling = NULL;
8985513b920SAnirudh Venkataramanan 		new_node->tc_num = tc_node->tc_num;
8995513b920SAnirudh Venkataramanan 
9005513b920SAnirudh Venkataramanan 		/* add it to previous node sibling pointer */
9015513b920SAnirudh Venkataramanan 		/* Note: siblings are not linked across branches */
90229358248SVictor Raj 		prev = ice_sched_get_first_node(pi, tc_node, layer);
9035513b920SAnirudh Venkataramanan 		if (prev && prev != new_node) {
9045513b920SAnirudh Venkataramanan 			while (prev->sibling)
9055513b920SAnirudh Venkataramanan 				prev = prev->sibling;
9065513b920SAnirudh Venkataramanan 			prev->sibling = new_node;
9075513b920SAnirudh Venkataramanan 		}
9085513b920SAnirudh Venkataramanan 
90929358248SVictor Raj 		/* initialize the sibling head */
91029358248SVictor Raj 		if (!pi->sib_head[tc_node->tc_num][layer])
91129358248SVictor Raj 			pi->sib_head[tc_node->tc_num][layer] = new_node;
91229358248SVictor Raj 
9135513b920SAnirudh Venkataramanan 		if (i == 0)
9145513b920SAnirudh Venkataramanan 			*first_node_teid = teid;
9155513b920SAnirudh Venkataramanan 	}
9165513b920SAnirudh Venkataramanan 
9175513b920SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), buf);
9185513b920SAnirudh Venkataramanan 	return status;
9195513b920SAnirudh Venkataramanan }
9205513b920SAnirudh Venkataramanan 
9215513b920SAnirudh Venkataramanan /**
9225513b920SAnirudh Venkataramanan  * ice_sched_add_nodes_to_layer - Add nodes to a given layer
9235513b920SAnirudh Venkataramanan  * @pi: port information structure
9245513b920SAnirudh Venkataramanan  * @tc_node: pointer to TC node
9255513b920SAnirudh Venkataramanan  * @parent: pointer to parent node
9265513b920SAnirudh Venkataramanan  * @layer: layer number to add nodes
9275513b920SAnirudh Venkataramanan  * @num_nodes: number of nodes to be added
928f9867df6SAnirudh Venkataramanan  * @first_node_teid: pointer to the first node TEID
9295513b920SAnirudh Venkataramanan  * @num_nodes_added: pointer to number of nodes added
9305513b920SAnirudh Venkataramanan  *
9315513b920SAnirudh Venkataramanan  * This function add nodes to a given layer.
9325513b920SAnirudh Venkataramanan  */
9335513b920SAnirudh Venkataramanan static enum ice_status
9345513b920SAnirudh Venkataramanan ice_sched_add_nodes_to_layer(struct ice_port_info *pi,
9355513b920SAnirudh Venkataramanan 			     struct ice_sched_node *tc_node,
9365513b920SAnirudh Venkataramanan 			     struct ice_sched_node *parent, u8 layer,
9375513b920SAnirudh Venkataramanan 			     u16 num_nodes, u32 *first_node_teid,
9385513b920SAnirudh Venkataramanan 			     u16 *num_nodes_added)
9395513b920SAnirudh Venkataramanan {
9405513b920SAnirudh Venkataramanan 	u32 *first_teid_ptr = first_node_teid;
9415513b920SAnirudh Venkataramanan 	u16 new_num_nodes, max_child_nodes;
9425513b920SAnirudh Venkataramanan 	enum ice_status status = 0;
9435513b920SAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
9445513b920SAnirudh Venkataramanan 	u16 num_added = 0;
9455513b920SAnirudh Venkataramanan 	u32 temp;
9465513b920SAnirudh Venkataramanan 
947d332a38cSAnirudh Venkataramanan 	*num_nodes_added = 0;
948d332a38cSAnirudh Venkataramanan 
9495513b920SAnirudh Venkataramanan 	if (!num_nodes)
9505513b920SAnirudh Venkataramanan 		return status;
9515513b920SAnirudh Venkataramanan 
9525513b920SAnirudh Venkataramanan 	if (!parent || layer < hw->sw_entry_point_layer)
9535513b920SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
9545513b920SAnirudh Venkataramanan 
9555513b920SAnirudh Venkataramanan 	/* max children per node per layer */
956b36c598cSAnirudh Venkataramanan 	max_child_nodes = hw->max_children[parent->tx_sched_layer];
9575513b920SAnirudh Venkataramanan 
9585513b920SAnirudh Venkataramanan 	/* current number of children + required nodes exceed max children ? */
9595513b920SAnirudh Venkataramanan 	if ((parent->num_children + num_nodes) > max_child_nodes) {
9605513b920SAnirudh Venkataramanan 		/* Fail if the parent is a TC node */
9615513b920SAnirudh Venkataramanan 		if (parent == tc_node)
9625513b920SAnirudh Venkataramanan 			return ICE_ERR_CFG;
9635513b920SAnirudh Venkataramanan 
9645513b920SAnirudh Venkataramanan 		/* utilize all the spaces if the parent is not full */
9655513b920SAnirudh Venkataramanan 		if (parent->num_children < max_child_nodes) {
9665513b920SAnirudh Venkataramanan 			new_num_nodes = max_child_nodes - parent->num_children;
9675513b920SAnirudh Venkataramanan 			/* this recursion is intentional, and wouldn't
9685513b920SAnirudh Venkataramanan 			 * go more than 2 calls
9695513b920SAnirudh Venkataramanan 			 */
9705513b920SAnirudh Venkataramanan 			status = ice_sched_add_nodes_to_layer(pi, tc_node,
9715513b920SAnirudh Venkataramanan 							      parent, layer,
9725513b920SAnirudh Venkataramanan 							      new_num_nodes,
9735513b920SAnirudh Venkataramanan 							      first_node_teid,
9745513b920SAnirudh Venkataramanan 							      &num_added);
9755513b920SAnirudh Venkataramanan 			if (status)
9765513b920SAnirudh Venkataramanan 				return status;
9775513b920SAnirudh Venkataramanan 
9785513b920SAnirudh Venkataramanan 			*num_nodes_added += num_added;
9795513b920SAnirudh Venkataramanan 		}
980f9867df6SAnirudh Venkataramanan 		/* Don't modify the first node TEID memory if the first node was
9815513b920SAnirudh Venkataramanan 		 * added already in the above call. Instead send some temp
9825513b920SAnirudh Venkataramanan 		 * memory for all other recursive calls.
9835513b920SAnirudh Venkataramanan 		 */
9845513b920SAnirudh Venkataramanan 		if (num_added)
9855513b920SAnirudh Venkataramanan 			first_teid_ptr = &temp;
9865513b920SAnirudh Venkataramanan 
9875513b920SAnirudh Venkataramanan 		new_num_nodes = num_nodes - num_added;
9885513b920SAnirudh Venkataramanan 
9895513b920SAnirudh Venkataramanan 		/* This parent is full, try the next sibling */
9905513b920SAnirudh Venkataramanan 		parent = parent->sibling;
9915513b920SAnirudh Venkataramanan 
9925513b920SAnirudh Venkataramanan 		/* this recursion is intentional, for 1024 queues
9935513b920SAnirudh Venkataramanan 		 * per VSI, it goes max of 16 iterations.
9945513b920SAnirudh Venkataramanan 		 * 1024 / 8 = 128 layer 8 nodes
9955513b920SAnirudh Venkataramanan 		 * 128 /8 = 16 (add 8 nodes per iteration)
9965513b920SAnirudh Venkataramanan 		 */
9975513b920SAnirudh Venkataramanan 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent,
9985513b920SAnirudh Venkataramanan 						      layer, new_num_nodes,
9995513b920SAnirudh Venkataramanan 						      first_teid_ptr,
10005513b920SAnirudh Venkataramanan 						      &num_added);
10015513b920SAnirudh Venkataramanan 		*num_nodes_added += num_added;
10025513b920SAnirudh Venkataramanan 		return status;
10035513b920SAnirudh Venkataramanan 	}
10045513b920SAnirudh Venkataramanan 
10055513b920SAnirudh Venkataramanan 	status = ice_sched_add_elems(pi, tc_node, parent, layer, num_nodes,
10065513b920SAnirudh Venkataramanan 				     num_nodes_added, first_node_teid);
10075513b920SAnirudh Venkataramanan 	return status;
10085513b920SAnirudh Venkataramanan }
10095513b920SAnirudh Venkataramanan 
10105513b920SAnirudh Venkataramanan /**
1011cdedef59SAnirudh Venkataramanan  * ice_sched_get_qgrp_layer - get the current queue group layer number
1012f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
1013cdedef59SAnirudh Venkataramanan  *
1014cdedef59SAnirudh Venkataramanan  * This function returns the current queue group layer number
1015cdedef59SAnirudh Venkataramanan  */
1016cdedef59SAnirudh Venkataramanan static u8 ice_sched_get_qgrp_layer(struct ice_hw *hw)
1017cdedef59SAnirudh Venkataramanan {
1018cdedef59SAnirudh Venkataramanan 	/* It's always total layers - 1, the array is 0 relative so -2 */
1019cdedef59SAnirudh Venkataramanan 	return hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET;
1020cdedef59SAnirudh Venkataramanan }
1021cdedef59SAnirudh Venkataramanan 
1022cdedef59SAnirudh Venkataramanan /**
10235513b920SAnirudh Venkataramanan  * ice_sched_get_vsi_layer - get the current VSI layer number
1024f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
10255513b920SAnirudh Venkataramanan  *
10265513b920SAnirudh Venkataramanan  * This function returns the current VSI layer number
10275513b920SAnirudh Venkataramanan  */
10285513b920SAnirudh Venkataramanan static u8 ice_sched_get_vsi_layer(struct ice_hw *hw)
10295513b920SAnirudh Venkataramanan {
10305513b920SAnirudh Venkataramanan 	/* Num Layers       VSI layer
10315513b920SAnirudh Venkataramanan 	 *     9               6
10325513b920SAnirudh Venkataramanan 	 *     7               4
10335513b920SAnirudh Venkataramanan 	 *     5 or less       sw_entry_point_layer
10345513b920SAnirudh Venkataramanan 	 */
1035f9867df6SAnirudh Venkataramanan 	/* calculate the VSI layer based on number of layers. */
10365513b920SAnirudh Venkataramanan 	if (hw->num_tx_sched_layers > ICE_VSI_LAYER_OFFSET + 1) {
10375513b920SAnirudh Venkataramanan 		u8 layer = hw->num_tx_sched_layers - ICE_VSI_LAYER_OFFSET;
10385513b920SAnirudh Venkataramanan 
10395513b920SAnirudh Venkataramanan 		if (layer > hw->sw_entry_point_layer)
10405513b920SAnirudh Venkataramanan 			return layer;
10415513b920SAnirudh Venkataramanan 	}
10425513b920SAnirudh Venkataramanan 	return hw->sw_entry_point_layer;
10435513b920SAnirudh Venkataramanan }
10445513b920SAnirudh Venkataramanan 
10455513b920SAnirudh Venkataramanan /**
1046b126bd6bSKiran Patil  * ice_sched_get_agg_layer - get the current aggregator layer number
1047b126bd6bSKiran Patil  * @hw: pointer to the HW struct
1048b126bd6bSKiran Patil  *
1049b126bd6bSKiran Patil  * This function returns the current aggregator layer number
1050b126bd6bSKiran Patil  */
1051b126bd6bSKiran Patil static u8 ice_sched_get_agg_layer(struct ice_hw *hw)
1052b126bd6bSKiran Patil {
1053b126bd6bSKiran Patil 	/* Num Layers       aggregator layer
1054b126bd6bSKiran Patil 	 *     9               4
1055b126bd6bSKiran Patil 	 *     7 or less       sw_entry_point_layer
1056b126bd6bSKiran Patil 	 */
1057b126bd6bSKiran Patil 	/* calculate the aggregator layer based on number of layers. */
1058b126bd6bSKiran Patil 	if (hw->num_tx_sched_layers > ICE_AGG_LAYER_OFFSET + 1) {
1059b126bd6bSKiran Patil 		u8 layer = hw->num_tx_sched_layers - ICE_AGG_LAYER_OFFSET;
1060b126bd6bSKiran Patil 
1061b126bd6bSKiran Patil 		if (layer > hw->sw_entry_point_layer)
1062b126bd6bSKiran Patil 			return layer;
1063b126bd6bSKiran Patil 	}
1064b126bd6bSKiran Patil 	return hw->sw_entry_point_layer;
1065b126bd6bSKiran Patil }
1066b126bd6bSKiran Patil 
1067b126bd6bSKiran Patil /**
1068dc49c772SAnirudh Venkataramanan  * ice_rm_dflt_leaf_node - remove the default leaf node in the tree
1069dc49c772SAnirudh Venkataramanan  * @pi: port information structure
1070dc49c772SAnirudh Venkataramanan  *
1071dc49c772SAnirudh Venkataramanan  * This function removes the leaf node that was created by the FW
1072dc49c772SAnirudh Venkataramanan  * during initialization
1073dc49c772SAnirudh Venkataramanan  */
10742c5492deSBruce Allan static void ice_rm_dflt_leaf_node(struct ice_port_info *pi)
1075dc49c772SAnirudh Venkataramanan {
1076dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *node;
1077dc49c772SAnirudh Venkataramanan 
1078dc49c772SAnirudh Venkataramanan 	node = pi->root;
1079dc49c772SAnirudh Venkataramanan 	while (node) {
1080dc49c772SAnirudh Venkataramanan 		if (!node->num_children)
1081dc49c772SAnirudh Venkataramanan 			break;
1082dc49c772SAnirudh Venkataramanan 		node = node->children[0];
1083dc49c772SAnirudh Venkataramanan 	}
1084dc49c772SAnirudh Venkataramanan 	if (node && node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF) {
1085dc49c772SAnirudh Venkataramanan 		u32 teid = le32_to_cpu(node->info.node_teid);
1086dc49c772SAnirudh Venkataramanan 		enum ice_status status;
1087dc49c772SAnirudh Venkataramanan 
1088dc49c772SAnirudh Venkataramanan 		/* remove the default leaf node */
1089dc49c772SAnirudh Venkataramanan 		status = ice_sched_remove_elems(pi->hw, node->parent, 1, &teid);
1090dc49c772SAnirudh Venkataramanan 		if (!status)
1091dc49c772SAnirudh Venkataramanan 			ice_free_sched_node(pi, node);
1092dc49c772SAnirudh Venkataramanan 	}
1093dc49c772SAnirudh Venkataramanan }
1094dc49c772SAnirudh Venkataramanan 
1095dc49c772SAnirudh Venkataramanan /**
1096dc49c772SAnirudh Venkataramanan  * ice_sched_rm_dflt_nodes - free the default nodes in the tree
1097dc49c772SAnirudh Venkataramanan  * @pi: port information structure
1098dc49c772SAnirudh Venkataramanan  *
1099dc49c772SAnirudh Venkataramanan  * This function frees all the nodes except root and TC that were created by
1100dc49c772SAnirudh Venkataramanan  * the FW during initialization
1101dc49c772SAnirudh Venkataramanan  */
11022c5492deSBruce Allan static void ice_sched_rm_dflt_nodes(struct ice_port_info *pi)
1103dc49c772SAnirudh Venkataramanan {
1104dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *node;
1105dc49c772SAnirudh Venkataramanan 
1106dc49c772SAnirudh Venkataramanan 	ice_rm_dflt_leaf_node(pi);
11075513b920SAnirudh Venkataramanan 
1108dc49c772SAnirudh Venkataramanan 	/* remove the default nodes except TC and root nodes */
1109dc49c772SAnirudh Venkataramanan 	node = pi->root;
1110dc49c772SAnirudh Venkataramanan 	while (node) {
1111dc49c772SAnirudh Venkataramanan 		if (node->tx_sched_layer >= pi->hw->sw_entry_point_layer &&
1112dc49c772SAnirudh Venkataramanan 		    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
1113dc49c772SAnirudh Venkataramanan 		    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT) {
1114dc49c772SAnirudh Venkataramanan 			ice_free_sched_node(pi, node);
1115dc49c772SAnirudh Venkataramanan 			break;
1116dc49c772SAnirudh Venkataramanan 		}
11175513b920SAnirudh Venkataramanan 
1118dc49c772SAnirudh Venkataramanan 		if (!node->num_children)
1119dc49c772SAnirudh Venkataramanan 			break;
1120dc49c772SAnirudh Venkataramanan 		node = node->children[0];
1121dc49c772SAnirudh Venkataramanan 	}
1122dc49c772SAnirudh Venkataramanan }
1123dc49c772SAnirudh Venkataramanan 
1124dc49c772SAnirudh Venkataramanan /**
1125dc49c772SAnirudh Venkataramanan  * ice_sched_init_port - Initialize scheduler by querying information from FW
1126dc49c772SAnirudh Venkataramanan  * @pi: port info structure for the tree to cleanup
1127dc49c772SAnirudh Venkataramanan  *
1128dc49c772SAnirudh Venkataramanan  * This function is the initial call to find the total number of Tx scheduler
1129dc49c772SAnirudh Venkataramanan  * resources, default topology created by firmware and storing the information
1130dc49c772SAnirudh Venkataramanan  * in SW DB.
1131dc49c772SAnirudh Venkataramanan  */
1132dc49c772SAnirudh Venkataramanan enum ice_status ice_sched_init_port(struct ice_port_info *pi)
1133dc49c772SAnirudh Venkataramanan {
1134dc49c772SAnirudh Venkataramanan 	struct ice_aqc_get_topo_elem *buf;
1135dc49c772SAnirudh Venkataramanan 	enum ice_status status;
1136dc49c772SAnirudh Venkataramanan 	struct ice_hw *hw;
1137dc49c772SAnirudh Venkataramanan 	u8 num_branches;
1138dc49c772SAnirudh Venkataramanan 	u16 num_elems;
1139dc49c772SAnirudh Venkataramanan 	u8 i, j;
1140dc49c772SAnirudh Venkataramanan 
1141dc49c772SAnirudh Venkataramanan 	if (!pi)
1142dc49c772SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
1143dc49c772SAnirudh Venkataramanan 	hw = pi->hw;
1144dc49c772SAnirudh Venkataramanan 
1145dc49c772SAnirudh Venkataramanan 	/* Query the Default Topology from FW */
1146b36c598cSAnirudh Venkataramanan 	buf = devm_kzalloc(ice_hw_to_dev(hw), ICE_AQ_MAX_BUF_LEN, GFP_KERNEL);
1147dc49c772SAnirudh Venkataramanan 	if (!buf)
1148dc49c772SAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
1149dc49c772SAnirudh Venkataramanan 
1150dc49c772SAnirudh Venkataramanan 	/* Query default scheduling tree topology */
1151b36c598cSAnirudh Venkataramanan 	status = ice_aq_get_dflt_topo(hw, pi->lport, buf, ICE_AQ_MAX_BUF_LEN,
1152dc49c772SAnirudh Venkataramanan 				      &num_branches, NULL);
1153dc49c772SAnirudh Venkataramanan 	if (status)
1154dc49c772SAnirudh Venkataramanan 		goto err_init_port;
1155dc49c772SAnirudh Venkataramanan 
1156dc49c772SAnirudh Venkataramanan 	/* num_branches should be between 1-8 */
1157dc49c772SAnirudh Venkataramanan 	if (num_branches < 1 || num_branches > ICE_TXSCHED_MAX_BRANCHES) {
1158dc49c772SAnirudh Venkataramanan 		ice_debug(hw, ICE_DBG_SCHED, "num_branches unexpected %d\n",
1159dc49c772SAnirudh Venkataramanan 			  num_branches);
1160dc49c772SAnirudh Venkataramanan 		status = ICE_ERR_PARAM;
1161dc49c772SAnirudh Venkataramanan 		goto err_init_port;
1162dc49c772SAnirudh Venkataramanan 	}
1163dc49c772SAnirudh Venkataramanan 
1164dc49c772SAnirudh Venkataramanan 	/* get the number of elements on the default/first branch */
1165dc49c772SAnirudh Venkataramanan 	num_elems = le16_to_cpu(buf[0].hdr.num_elems);
1166dc49c772SAnirudh Venkataramanan 
1167dc49c772SAnirudh Venkataramanan 	/* num_elems should always be between 1-9 */
1168dc49c772SAnirudh Venkataramanan 	if (num_elems < 1 || num_elems > ICE_AQC_TOPO_MAX_LEVEL_NUM) {
1169dc49c772SAnirudh Venkataramanan 		ice_debug(hw, ICE_DBG_SCHED, "num_elems unexpected %d\n",
1170dc49c772SAnirudh Venkataramanan 			  num_elems);
1171dc49c772SAnirudh Venkataramanan 		status = ICE_ERR_PARAM;
1172dc49c772SAnirudh Venkataramanan 		goto err_init_port;
1173dc49c772SAnirudh Venkataramanan 	}
1174dc49c772SAnirudh Venkataramanan 
1175f9867df6SAnirudh Venkataramanan 	/* If the last node is a leaf node then the index of the queue group
1176dc49c772SAnirudh Venkataramanan 	 * layer is two less than the number of elements.
1177dc49c772SAnirudh Venkataramanan 	 */
1178dc49c772SAnirudh Venkataramanan 	if (num_elems > 2 && buf[0].generic[num_elems - 1].data.elem_type ==
1179dc49c772SAnirudh Venkataramanan 	    ICE_AQC_ELEM_TYPE_LEAF)
1180dc49c772SAnirudh Venkataramanan 		pi->last_node_teid =
1181dc49c772SAnirudh Venkataramanan 			le32_to_cpu(buf[0].generic[num_elems - 2].node_teid);
1182dc49c772SAnirudh Venkataramanan 	else
1183dc49c772SAnirudh Venkataramanan 		pi->last_node_teid =
1184dc49c772SAnirudh Venkataramanan 			le32_to_cpu(buf[0].generic[num_elems - 1].node_teid);
1185dc49c772SAnirudh Venkataramanan 
1186dc49c772SAnirudh Venkataramanan 	/* Insert the Tx Sched root node */
1187dc49c772SAnirudh Venkataramanan 	status = ice_sched_add_root_node(pi, &buf[0].generic[0]);
1188dc49c772SAnirudh Venkataramanan 	if (status)
1189dc49c772SAnirudh Venkataramanan 		goto err_init_port;
1190dc49c772SAnirudh Venkataramanan 
1191dc49c772SAnirudh Venkataramanan 	/* Parse the default tree and cache the information */
1192dc49c772SAnirudh Venkataramanan 	for (i = 0; i < num_branches; i++) {
1193dc49c772SAnirudh Venkataramanan 		num_elems = le16_to_cpu(buf[i].hdr.num_elems);
1194dc49c772SAnirudh Venkataramanan 
1195dc49c772SAnirudh Venkataramanan 		/* Skip root element as already inserted */
1196dc49c772SAnirudh Venkataramanan 		for (j = 1; j < num_elems; j++) {
1197dc49c772SAnirudh Venkataramanan 			/* update the sw entry point */
1198dc49c772SAnirudh Venkataramanan 			if (buf[0].generic[j].data.elem_type ==
1199dc49c772SAnirudh Venkataramanan 			    ICE_AQC_ELEM_TYPE_ENTRY_POINT)
1200dc49c772SAnirudh Venkataramanan 				hw->sw_entry_point_layer = j;
1201dc49c772SAnirudh Venkataramanan 
1202dc49c772SAnirudh Venkataramanan 			status = ice_sched_add_node(pi, j, &buf[i].generic[j]);
1203dc49c772SAnirudh Venkataramanan 			if (status)
1204dc49c772SAnirudh Venkataramanan 				goto err_init_port;
1205dc49c772SAnirudh Venkataramanan 		}
1206dc49c772SAnirudh Venkataramanan 	}
1207dc49c772SAnirudh Venkataramanan 
1208dc49c772SAnirudh Venkataramanan 	/* Remove the default nodes. */
1209dc49c772SAnirudh Venkataramanan 	if (pi->root)
1210dc49c772SAnirudh Venkataramanan 		ice_sched_rm_dflt_nodes(pi);
1211dc49c772SAnirudh Venkataramanan 
1212dc49c772SAnirudh Venkataramanan 	/* initialize the port for handling the scheduler tree */
1213dc49c772SAnirudh Venkataramanan 	pi->port_state = ICE_SCHED_PORT_STATE_READY;
1214dc49c772SAnirudh Venkataramanan 	mutex_init(&pi->sched_lock);
12151ddef455SUsha Ketineni 	for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++)
12161ddef455SUsha Ketineni 		INIT_LIST_HEAD(&pi->rl_prof_list[i]);
1217dc49c772SAnirudh Venkataramanan 
1218dc49c772SAnirudh Venkataramanan err_init_port:
1219dc49c772SAnirudh Venkataramanan 	if (status && pi->root) {
1220dc49c772SAnirudh Venkataramanan 		ice_free_sched_node(pi, pi->root);
1221dc49c772SAnirudh Venkataramanan 		pi->root = NULL;
1222dc49c772SAnirudh Venkataramanan 	}
1223dc49c772SAnirudh Venkataramanan 
1224dc49c772SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), buf);
1225dc49c772SAnirudh Venkataramanan 	return status;
1226dc49c772SAnirudh Venkataramanan }
1227dc49c772SAnirudh Venkataramanan 
1228dc49c772SAnirudh Venkataramanan /**
12299c20346bSAnirudh Venkataramanan  * ice_sched_query_res_alloc - query the FW for num of logical sched layers
12309c20346bSAnirudh Venkataramanan  * @hw: pointer to the HW struct
12319c20346bSAnirudh Venkataramanan  *
12329c20346bSAnirudh Venkataramanan  * query FW for allocated scheduler resources and store in HW struct
12339c20346bSAnirudh Venkataramanan  */
12349c20346bSAnirudh Venkataramanan enum ice_status ice_sched_query_res_alloc(struct ice_hw *hw)
12359c20346bSAnirudh Venkataramanan {
12369c20346bSAnirudh Venkataramanan 	struct ice_aqc_query_txsched_res_resp *buf;
12379c20346bSAnirudh Venkataramanan 	enum ice_status status = 0;
1238b36c598cSAnirudh Venkataramanan 	__le16 max_sibl;
1239615457a2SColin Ian King 	u16 i;
12409c20346bSAnirudh Venkataramanan 
12419c20346bSAnirudh Venkataramanan 	if (hw->layer_info)
12429c20346bSAnirudh Venkataramanan 		return status;
12439c20346bSAnirudh Venkataramanan 
12449c20346bSAnirudh Venkataramanan 	buf = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*buf), GFP_KERNEL);
12459c20346bSAnirudh Venkataramanan 	if (!buf)
12469c20346bSAnirudh Venkataramanan 		return ICE_ERR_NO_MEMORY;
12479c20346bSAnirudh Venkataramanan 
12489c20346bSAnirudh Venkataramanan 	status = ice_aq_query_sched_res(hw, sizeof(*buf), buf, NULL);
12499c20346bSAnirudh Venkataramanan 	if (status)
12509c20346bSAnirudh Venkataramanan 		goto sched_query_out;
12519c20346bSAnirudh Venkataramanan 
12529c20346bSAnirudh Venkataramanan 	hw->num_tx_sched_layers = le16_to_cpu(buf->sched_props.logical_levels);
12539c20346bSAnirudh Venkataramanan 	hw->num_tx_sched_phys_layers =
12549c20346bSAnirudh Venkataramanan 		le16_to_cpu(buf->sched_props.phys_levels);
12559c20346bSAnirudh Venkataramanan 	hw->flattened_layers = buf->sched_props.flattening_bitmap;
12569c20346bSAnirudh Venkataramanan 	hw->max_cgds = buf->sched_props.max_pf_cgds;
12579c20346bSAnirudh Venkataramanan 
1258b36c598cSAnirudh Venkataramanan 	/* max sibling group size of current layer refers to the max children
1259b36c598cSAnirudh Venkataramanan 	 * of the below layer node.
1260b36c598cSAnirudh Venkataramanan 	 * layer 1 node max children will be layer 2 max sibling group size
1261b36c598cSAnirudh Venkataramanan 	 * layer 2 node max children will be layer 3 max sibling group size
1262b36c598cSAnirudh Venkataramanan 	 * and so on. This array will be populated from root (index 0) to
1263b36c598cSAnirudh Venkataramanan 	 * qgroup layer 7. Leaf node has no children.
1264b36c598cSAnirudh Venkataramanan 	 */
12651ddef455SUsha Ketineni 	for (i = 0; i < hw->num_tx_sched_layers - 1; i++) {
12661ddef455SUsha Ketineni 		max_sibl = buf->layer_props[i + 1].max_sibl_grp_sz;
1267b36c598cSAnirudh Venkataramanan 		hw->max_children[i] = le16_to_cpu(max_sibl);
1268b36c598cSAnirudh Venkataramanan 	}
1269b36c598cSAnirudh Venkataramanan 
1270c6dfd690SBruce Allan 	hw->layer_info = devm_kmemdup(ice_hw_to_dev(hw), buf->layer_props,
12719c20346bSAnirudh Venkataramanan 				      (hw->num_tx_sched_layers *
12729c20346bSAnirudh Venkataramanan 				       sizeof(*hw->layer_info)),
12739c20346bSAnirudh Venkataramanan 				      GFP_KERNEL);
12749c20346bSAnirudh Venkataramanan 	if (!hw->layer_info) {
12759c20346bSAnirudh Venkataramanan 		status = ICE_ERR_NO_MEMORY;
12769c20346bSAnirudh Venkataramanan 		goto sched_query_out;
12779c20346bSAnirudh Venkataramanan 	}
12789c20346bSAnirudh Venkataramanan 
12799c20346bSAnirudh Venkataramanan sched_query_out:
12809c20346bSAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), buf);
12819c20346bSAnirudh Venkataramanan 	return status;
12829c20346bSAnirudh Venkataramanan }
1283cdedef59SAnirudh Venkataramanan 
1284cdedef59SAnirudh Venkataramanan /**
12854f8a1497SBen Shelton  * ice_sched_get_psm_clk_freq - determine the PSM clock frequency
12864f8a1497SBen Shelton  * @hw: pointer to the HW struct
12874f8a1497SBen Shelton  *
12884f8a1497SBen Shelton  * Determine the PSM clock frequency and store in HW struct
12894f8a1497SBen Shelton  */
12904f8a1497SBen Shelton void ice_sched_get_psm_clk_freq(struct ice_hw *hw)
12914f8a1497SBen Shelton {
12924f8a1497SBen Shelton 	u32 val, clk_src;
12934f8a1497SBen Shelton 
12944f8a1497SBen Shelton 	val = rd32(hw, GLGEN_CLKSTAT_SRC);
12954f8a1497SBen Shelton 	clk_src = (val & GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M) >>
12964f8a1497SBen Shelton 		GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_S;
12974f8a1497SBen Shelton 
12984f8a1497SBen Shelton #define PSM_CLK_SRC_367_MHZ 0x0
12994f8a1497SBen Shelton #define PSM_CLK_SRC_416_MHZ 0x1
13004f8a1497SBen Shelton #define PSM_CLK_SRC_446_MHZ 0x2
13014f8a1497SBen Shelton #define PSM_CLK_SRC_390_MHZ 0x3
13024f8a1497SBen Shelton 
13034f8a1497SBen Shelton 	switch (clk_src) {
13044f8a1497SBen Shelton 	case PSM_CLK_SRC_367_MHZ:
13054f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_367MHZ_IN_HZ;
13064f8a1497SBen Shelton 		break;
13074f8a1497SBen Shelton 	case PSM_CLK_SRC_416_MHZ:
13084f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_416MHZ_IN_HZ;
13094f8a1497SBen Shelton 		break;
13104f8a1497SBen Shelton 	case PSM_CLK_SRC_446_MHZ:
13114f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_446MHZ_IN_HZ;
13124f8a1497SBen Shelton 		break;
13134f8a1497SBen Shelton 	case PSM_CLK_SRC_390_MHZ:
13144f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_390MHZ_IN_HZ;
13154f8a1497SBen Shelton 		break;
13164f8a1497SBen Shelton 	default:
13174f8a1497SBen Shelton 		ice_debug(hw, ICE_DBG_SCHED, "PSM clk_src unexpected %u\n",
13184f8a1497SBen Shelton 			  clk_src);
13194f8a1497SBen Shelton 		/* fall back to a safe default */
13204f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_446MHZ_IN_HZ;
13214f8a1497SBen Shelton 	}
13224f8a1497SBen Shelton }
13234f8a1497SBen Shelton 
13244f8a1497SBen Shelton /**
1325cdedef59SAnirudh Venkataramanan  * ice_sched_find_node_in_subtree - Find node in part of base node subtree
1326f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
1327cdedef59SAnirudh Venkataramanan  * @base: pointer to the base node
1328cdedef59SAnirudh Venkataramanan  * @node: pointer to the node to search
1329cdedef59SAnirudh Venkataramanan  *
1330cdedef59SAnirudh Venkataramanan  * This function checks whether a given node is part of the base node
1331cdedef59SAnirudh Venkataramanan  * subtree or not
1332cdedef59SAnirudh Venkataramanan  */
1333cdedef59SAnirudh Venkataramanan static bool
1334cdedef59SAnirudh Venkataramanan ice_sched_find_node_in_subtree(struct ice_hw *hw, struct ice_sched_node *base,
1335cdedef59SAnirudh Venkataramanan 			       struct ice_sched_node *node)
1336cdedef59SAnirudh Venkataramanan {
1337cdedef59SAnirudh Venkataramanan 	u8 i;
1338cdedef59SAnirudh Venkataramanan 
1339cdedef59SAnirudh Venkataramanan 	for (i = 0; i < base->num_children; i++) {
1340cdedef59SAnirudh Venkataramanan 		struct ice_sched_node *child = base->children[i];
1341cdedef59SAnirudh Venkataramanan 
1342cdedef59SAnirudh Venkataramanan 		if (node == child)
1343cdedef59SAnirudh Venkataramanan 			return true;
13445513b920SAnirudh Venkataramanan 
1345cdedef59SAnirudh Venkataramanan 		if (child->tx_sched_layer > node->tx_sched_layer)
1346cdedef59SAnirudh Venkataramanan 			return false;
13475513b920SAnirudh Venkataramanan 
1348cdedef59SAnirudh Venkataramanan 		/* this recursion is intentional, and wouldn't
1349cdedef59SAnirudh Venkataramanan 		 * go more than 8 calls
1350cdedef59SAnirudh Venkataramanan 		 */
1351cdedef59SAnirudh Venkataramanan 		if (ice_sched_find_node_in_subtree(hw, child, node))
1352cdedef59SAnirudh Venkataramanan 			return true;
1353cdedef59SAnirudh Venkataramanan 	}
1354cdedef59SAnirudh Venkataramanan 	return false;
1355cdedef59SAnirudh Venkataramanan }
1356cdedef59SAnirudh Venkataramanan 
1357cdedef59SAnirudh Venkataramanan /**
13584043818cSVictor Raj  * ice_sched_get_free_qgrp - Scan all queue group siblings and find a free node
13594043818cSVictor Raj  * @pi: port information structure
13604043818cSVictor Raj  * @vsi_node: software VSI handle
13614043818cSVictor Raj  * @qgrp_node: first queue group node identified for scanning
13624043818cSVictor Raj  * @owner: LAN or RDMA
13634043818cSVictor Raj  *
13644043818cSVictor Raj  * This function retrieves a free LAN or RDMA queue group node by scanning
13654043818cSVictor Raj  * qgrp_node and its siblings for the queue group with the fewest number
13664043818cSVictor Raj  * of queues currently assigned.
13674043818cSVictor Raj  */
13684043818cSVictor Raj static struct ice_sched_node *
13694043818cSVictor Raj ice_sched_get_free_qgrp(struct ice_port_info *pi,
13704043818cSVictor Raj 			struct ice_sched_node *vsi_node,
13714043818cSVictor Raj 			struct ice_sched_node *qgrp_node, u8 owner)
13724043818cSVictor Raj {
13734043818cSVictor Raj 	struct ice_sched_node *min_qgrp;
13744043818cSVictor Raj 	u8 min_children;
13754043818cSVictor Raj 
13764043818cSVictor Raj 	if (!qgrp_node)
13774043818cSVictor Raj 		return qgrp_node;
13784043818cSVictor Raj 	min_children = qgrp_node->num_children;
13794043818cSVictor Raj 	if (!min_children)
13804043818cSVictor Raj 		return qgrp_node;
13814043818cSVictor Raj 	min_qgrp = qgrp_node;
13824043818cSVictor Raj 	/* scan all queue groups until find a node which has less than the
13834043818cSVictor Raj 	 * minimum number of children. This way all queue group nodes get
13844043818cSVictor Raj 	 * equal number of shares and active. The bandwidth will be equally
13854043818cSVictor Raj 	 * distributed across all queues.
13864043818cSVictor Raj 	 */
13874043818cSVictor Raj 	while (qgrp_node) {
13884043818cSVictor Raj 		/* make sure the qgroup node is part of the VSI subtree */
13894043818cSVictor Raj 		if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node))
13904043818cSVictor Raj 			if (qgrp_node->num_children < min_children &&
13914043818cSVictor Raj 			    qgrp_node->owner == owner) {
13924043818cSVictor Raj 				/* replace the new min queue group node */
13934043818cSVictor Raj 				min_qgrp = qgrp_node;
13944043818cSVictor Raj 				min_children = min_qgrp->num_children;
13954043818cSVictor Raj 				/* break if it has no children, */
13964043818cSVictor Raj 				if (!min_children)
13974043818cSVictor Raj 					break;
13984043818cSVictor Raj 			}
13994043818cSVictor Raj 		qgrp_node = qgrp_node->sibling;
14004043818cSVictor Raj 	}
14014043818cSVictor Raj 	return min_qgrp;
14024043818cSVictor Raj }
14034043818cSVictor Raj 
14044043818cSVictor Raj /**
1405f9867df6SAnirudh Venkataramanan  * ice_sched_get_free_qparent - Get a free LAN or RDMA queue group node
1406cdedef59SAnirudh Venkataramanan  * @pi: port information structure
14074fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
1408cdedef59SAnirudh Venkataramanan  * @tc: branch number
1409f9867df6SAnirudh Venkataramanan  * @owner: LAN or RDMA
1410cdedef59SAnirudh Venkataramanan  *
1411f9867df6SAnirudh Venkataramanan  * This function retrieves a free LAN or RDMA queue group node
1412cdedef59SAnirudh Venkataramanan  */
1413cdedef59SAnirudh Venkataramanan struct ice_sched_node *
14144fb33f31SAnirudh Venkataramanan ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
1415cdedef59SAnirudh Venkataramanan 			   u8 owner)
1416cdedef59SAnirudh Venkataramanan {
14174043818cSVictor Raj 	struct ice_sched_node *vsi_node, *qgrp_node;
14184fb33f31SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
1419cdedef59SAnirudh Venkataramanan 	u16 max_children;
1420cdedef59SAnirudh Venkataramanan 	u8 qgrp_layer;
1421cdedef59SAnirudh Venkataramanan 
1422cdedef59SAnirudh Venkataramanan 	qgrp_layer = ice_sched_get_qgrp_layer(pi->hw);
1423b36c598cSAnirudh Venkataramanan 	max_children = pi->hw->max_children[qgrp_layer];
14245513b920SAnirudh Venkataramanan 
14254fb33f31SAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
14264fb33f31SAnirudh Venkataramanan 	if (!vsi_ctx)
14274fb33f31SAnirudh Venkataramanan 		return NULL;
14284fb33f31SAnirudh Venkataramanan 	vsi_node = vsi_ctx->sched.vsi_node[tc];
1429f9867df6SAnirudh Venkataramanan 	/* validate invalid VSI ID */
1430cdedef59SAnirudh Venkataramanan 	if (!vsi_node)
14314043818cSVictor Raj 		return NULL;
14325513b920SAnirudh Venkataramanan 
1433f9867df6SAnirudh Venkataramanan 	/* get the first queue group node from VSI sub-tree */
143429358248SVictor Raj 	qgrp_node = ice_sched_get_first_node(pi, vsi_node, qgrp_layer);
1435cdedef59SAnirudh Venkataramanan 	while (qgrp_node) {
1436cdedef59SAnirudh Venkataramanan 		/* make sure the qgroup node is part of the VSI subtree */
1437cdedef59SAnirudh Venkataramanan 		if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node))
1438cdedef59SAnirudh Venkataramanan 			if (qgrp_node->num_children < max_children &&
1439cdedef59SAnirudh Venkataramanan 			    qgrp_node->owner == owner)
1440cdedef59SAnirudh Venkataramanan 				break;
1441cdedef59SAnirudh Venkataramanan 		qgrp_node = qgrp_node->sibling;
1442cdedef59SAnirudh Venkataramanan 	}
14435513b920SAnirudh Venkataramanan 
14444043818cSVictor Raj 	/* Select the best queue group */
14454043818cSVictor Raj 	return ice_sched_get_free_qgrp(pi, vsi_node, qgrp_node, owner);
1446cdedef59SAnirudh Venkataramanan }
14475513b920SAnirudh Venkataramanan 
14485513b920SAnirudh Venkataramanan /**
1449f9867df6SAnirudh Venkataramanan  * ice_sched_get_vsi_node - Get a VSI node based on VSI ID
1450b126bd6bSKiran Patil  * @pi: pointer to the port information structure
14515513b920SAnirudh Venkataramanan  * @tc_node: pointer to the TC node
14524fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
14535513b920SAnirudh Venkataramanan  *
1454f9867df6SAnirudh Venkataramanan  * This function retrieves a VSI node for a given VSI ID from a given
14555513b920SAnirudh Venkataramanan  * TC branch
14565513b920SAnirudh Venkataramanan  */
14575513b920SAnirudh Venkataramanan static struct ice_sched_node *
1458b126bd6bSKiran Patil ice_sched_get_vsi_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
14594fb33f31SAnirudh Venkataramanan 		       u16 vsi_handle)
14605513b920SAnirudh Venkataramanan {
14615513b920SAnirudh Venkataramanan 	struct ice_sched_node *node;
14625513b920SAnirudh Venkataramanan 	u8 vsi_layer;
14635513b920SAnirudh Venkataramanan 
1464b126bd6bSKiran Patil 	vsi_layer = ice_sched_get_vsi_layer(pi->hw);
1465b126bd6bSKiran Patil 	node = ice_sched_get_first_node(pi, tc_node, vsi_layer);
14665513b920SAnirudh Venkataramanan 
14675513b920SAnirudh Venkataramanan 	/* Check whether it already exists */
14685513b920SAnirudh Venkataramanan 	while (node) {
14694fb33f31SAnirudh Venkataramanan 		if (node->vsi_handle == vsi_handle)
14705513b920SAnirudh Venkataramanan 			return node;
14715513b920SAnirudh Venkataramanan 		node = node->sibling;
14725513b920SAnirudh Venkataramanan 	}
14735513b920SAnirudh Venkataramanan 
14745513b920SAnirudh Venkataramanan 	return node;
14755513b920SAnirudh Venkataramanan }
14765513b920SAnirudh Venkataramanan 
14775513b920SAnirudh Venkataramanan /**
1478b126bd6bSKiran Patil  * ice_sched_get_agg_node - Get an aggregator node based on aggregator ID
1479b126bd6bSKiran Patil  * @pi: pointer to the port information structure
1480b126bd6bSKiran Patil  * @tc_node: pointer to the TC node
1481b126bd6bSKiran Patil  * @agg_id: aggregator ID
1482b126bd6bSKiran Patil  *
1483b126bd6bSKiran Patil  * This function retrieves an aggregator node for a given aggregator ID from
1484b126bd6bSKiran Patil  * a given TC branch
1485b126bd6bSKiran Patil  */
1486b126bd6bSKiran Patil static struct ice_sched_node *
1487b126bd6bSKiran Patil ice_sched_get_agg_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
1488b126bd6bSKiran Patil 		       u32 agg_id)
1489b126bd6bSKiran Patil {
1490b126bd6bSKiran Patil 	struct ice_sched_node *node;
1491b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
1492b126bd6bSKiran Patil 	u8 agg_layer;
1493b126bd6bSKiran Patil 
1494b126bd6bSKiran Patil 	if (!hw)
1495b126bd6bSKiran Patil 		return NULL;
1496b126bd6bSKiran Patil 	agg_layer = ice_sched_get_agg_layer(hw);
1497b126bd6bSKiran Patil 	node = ice_sched_get_first_node(pi, tc_node, agg_layer);
1498b126bd6bSKiran Patil 
1499b126bd6bSKiran Patil 	/* Check whether it already exists */
1500b126bd6bSKiran Patil 	while (node) {
1501b126bd6bSKiran Patil 		if (node->agg_id == agg_id)
1502b126bd6bSKiran Patil 			return node;
1503b126bd6bSKiran Patil 		node = node->sibling;
1504b126bd6bSKiran Patil 	}
1505b126bd6bSKiran Patil 
1506b126bd6bSKiran Patil 	return node;
1507b126bd6bSKiran Patil }
1508b126bd6bSKiran Patil 
1509b126bd6bSKiran Patil /**
15105513b920SAnirudh Venkataramanan  * ice_sched_calc_vsi_child_nodes - calculate number of VSI child nodes
1511f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
15125513b920SAnirudh Venkataramanan  * @num_qs: number of queues
15135513b920SAnirudh Venkataramanan  * @num_nodes: num nodes array
15145513b920SAnirudh Venkataramanan  *
15155513b920SAnirudh Venkataramanan  * This function calculates the number of VSI child nodes based on the
15165513b920SAnirudh Venkataramanan  * number of queues.
15175513b920SAnirudh Venkataramanan  */
15185513b920SAnirudh Venkataramanan static void
15195513b920SAnirudh Venkataramanan ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes)
15205513b920SAnirudh Venkataramanan {
15215513b920SAnirudh Venkataramanan 	u16 num = num_qs;
15225513b920SAnirudh Venkataramanan 	u8 i, qgl, vsil;
15235513b920SAnirudh Venkataramanan 
15245513b920SAnirudh Venkataramanan 	qgl = ice_sched_get_qgrp_layer(hw);
15255513b920SAnirudh Venkataramanan 	vsil = ice_sched_get_vsi_layer(hw);
15265513b920SAnirudh Venkataramanan 
1527f9867df6SAnirudh Venkataramanan 	/* calculate num nodes from queue group to VSI layer */
15285513b920SAnirudh Venkataramanan 	for (i = qgl; i > vsil; i--) {
15295513b920SAnirudh Venkataramanan 		/* round to the next integer if there is a remainder */
1530b36c598cSAnirudh Venkataramanan 		num = DIV_ROUND_UP(num, hw->max_children[i]);
15315513b920SAnirudh Venkataramanan 
15325513b920SAnirudh Venkataramanan 		/* need at least one node */
15335513b920SAnirudh Venkataramanan 		num_nodes[i] = num ? num : 1;
15345513b920SAnirudh Venkataramanan 	}
15355513b920SAnirudh Venkataramanan }
15365513b920SAnirudh Venkataramanan 
15375513b920SAnirudh Venkataramanan /**
15385513b920SAnirudh Venkataramanan  * ice_sched_add_vsi_child_nodes - add VSI child nodes to tree
15395513b920SAnirudh Venkataramanan  * @pi: port information structure
15404fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
15415513b920SAnirudh Venkataramanan  * @tc_node: pointer to the TC node
15425513b920SAnirudh Venkataramanan  * @num_nodes: pointer to the num nodes that needs to be added per layer
1543f9867df6SAnirudh Venkataramanan  * @owner: node owner (LAN or RDMA)
15445513b920SAnirudh Venkataramanan  *
15455513b920SAnirudh Venkataramanan  * This function adds the VSI child nodes to tree. It gets called for
1546f9867df6SAnirudh Venkataramanan  * LAN and RDMA separately.
15475513b920SAnirudh Venkataramanan  */
15485513b920SAnirudh Venkataramanan static enum ice_status
15494fb33f31SAnirudh Venkataramanan ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
15505513b920SAnirudh Venkataramanan 			      struct ice_sched_node *tc_node, u16 *num_nodes,
15515513b920SAnirudh Venkataramanan 			      u8 owner)
15525513b920SAnirudh Venkataramanan {
15535513b920SAnirudh Venkataramanan 	struct ice_sched_node *parent, *node;
15545513b920SAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
15555513b920SAnirudh Venkataramanan 	enum ice_status status;
15565513b920SAnirudh Venkataramanan 	u32 first_node_teid;
15575513b920SAnirudh Venkataramanan 	u16 num_added = 0;
15585513b920SAnirudh Venkataramanan 	u8 i, qgl, vsil;
15595513b920SAnirudh Venkataramanan 
15605513b920SAnirudh Venkataramanan 	qgl = ice_sched_get_qgrp_layer(hw);
15615513b920SAnirudh Venkataramanan 	vsil = ice_sched_get_vsi_layer(hw);
1562b126bd6bSKiran Patil 	parent = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
15635513b920SAnirudh Venkataramanan 	for (i = vsil + 1; i <= qgl; i++) {
15645513b920SAnirudh Venkataramanan 		if (!parent)
15655513b920SAnirudh Venkataramanan 			return ICE_ERR_CFG;
1566b36c598cSAnirudh Venkataramanan 
15675513b920SAnirudh Venkataramanan 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
15685513b920SAnirudh Venkataramanan 						      num_nodes[i],
15695513b920SAnirudh Venkataramanan 						      &first_node_teid,
15705513b920SAnirudh Venkataramanan 						      &num_added);
15715513b920SAnirudh Venkataramanan 		if (status || num_nodes[i] != num_added)
15725513b920SAnirudh Venkataramanan 			return ICE_ERR_CFG;
15735513b920SAnirudh Venkataramanan 
15745513b920SAnirudh Venkataramanan 		/* The newly added node can be a new parent for the next
15755513b920SAnirudh Venkataramanan 		 * layer nodes
15765513b920SAnirudh Venkataramanan 		 */
15775513b920SAnirudh Venkataramanan 		if (num_added) {
15785513b920SAnirudh Venkataramanan 			parent = ice_sched_find_node_by_teid(tc_node,
15795513b920SAnirudh Venkataramanan 							     first_node_teid);
15805513b920SAnirudh Venkataramanan 			node = parent;
15815513b920SAnirudh Venkataramanan 			while (node) {
15825513b920SAnirudh Venkataramanan 				node->owner = owner;
15835513b920SAnirudh Venkataramanan 				node = node->sibling;
15845513b920SAnirudh Venkataramanan 			}
15855513b920SAnirudh Venkataramanan 		} else {
15865513b920SAnirudh Venkataramanan 			parent = parent->children[0];
15875513b920SAnirudh Venkataramanan 		}
15885513b920SAnirudh Venkataramanan 	}
15895513b920SAnirudh Venkataramanan 
15905513b920SAnirudh Venkataramanan 	return 0;
15915513b920SAnirudh Venkataramanan }
15925513b920SAnirudh Venkataramanan 
15935513b920SAnirudh Venkataramanan /**
15945513b920SAnirudh Venkataramanan  * ice_sched_calc_vsi_support_nodes - calculate number of VSI support nodes
1595b126bd6bSKiran Patil  * @pi: pointer to the port info structure
15965513b920SAnirudh Venkataramanan  * @tc_node: pointer to TC node
15975513b920SAnirudh Venkataramanan  * @num_nodes: pointer to num nodes array
15985513b920SAnirudh Venkataramanan  *
15995513b920SAnirudh Venkataramanan  * This function calculates the number of supported nodes needed to add this
1600d337f2afSAnirudh Venkataramanan  * VSI into Tx tree including the VSI, parent and intermediate nodes in below
16015513b920SAnirudh Venkataramanan  * layers
16025513b920SAnirudh Venkataramanan  */
16035513b920SAnirudh Venkataramanan static void
1604b126bd6bSKiran Patil ice_sched_calc_vsi_support_nodes(struct ice_port_info *pi,
16055513b920SAnirudh Venkataramanan 				 struct ice_sched_node *tc_node, u16 *num_nodes)
16065513b920SAnirudh Venkataramanan {
16075513b920SAnirudh Venkataramanan 	struct ice_sched_node *node;
1608b36c598cSAnirudh Venkataramanan 	u8 vsil;
1609b36c598cSAnirudh Venkataramanan 	int i;
16105513b920SAnirudh Venkataramanan 
1611b126bd6bSKiran Patil 	vsil = ice_sched_get_vsi_layer(pi->hw);
1612b126bd6bSKiran Patil 	for (i = vsil; i >= pi->hw->sw_entry_point_layer; i--)
16135513b920SAnirudh Venkataramanan 		/* Add intermediate nodes if TC has no children and
16145513b920SAnirudh Venkataramanan 		 * need at least one node for VSI
16155513b920SAnirudh Venkataramanan 		 */
16165513b920SAnirudh Venkataramanan 		if (!tc_node->num_children || i == vsil) {
16175513b920SAnirudh Venkataramanan 			num_nodes[i]++;
16185513b920SAnirudh Venkataramanan 		} else {
16195513b920SAnirudh Venkataramanan 			/* If intermediate nodes are reached max children
16205513b920SAnirudh Venkataramanan 			 * then add a new one.
16215513b920SAnirudh Venkataramanan 			 */
1622b126bd6bSKiran Patil 			node = ice_sched_get_first_node(pi, tc_node, (u8)i);
16235513b920SAnirudh Venkataramanan 			/* scan all the siblings */
16245513b920SAnirudh Venkataramanan 			while (node) {
1625b126bd6bSKiran Patil 				if (node->num_children < pi->hw->max_children[i])
16265513b920SAnirudh Venkataramanan 					break;
16275513b920SAnirudh Venkataramanan 				node = node->sibling;
16285513b920SAnirudh Venkataramanan 			}
16295513b920SAnirudh Venkataramanan 
16300e8fd74dSVictor Raj 			/* tree has one intermediate node to add this new VSI.
16310e8fd74dSVictor Raj 			 * So no need to calculate supported nodes for below
16320e8fd74dSVictor Raj 			 * layers.
16330e8fd74dSVictor Raj 			 */
16340e8fd74dSVictor Raj 			if (node)
16350e8fd74dSVictor Raj 				break;
16365513b920SAnirudh Venkataramanan 			/* all the nodes are full, allocate a new one */
16375513b920SAnirudh Venkataramanan 			num_nodes[i]++;
16385513b920SAnirudh Venkataramanan 		}
16395513b920SAnirudh Venkataramanan }
16405513b920SAnirudh Venkataramanan 
16415513b920SAnirudh Venkataramanan /**
1642d337f2afSAnirudh Venkataramanan  * ice_sched_add_vsi_support_nodes - add VSI supported nodes into Tx tree
16435513b920SAnirudh Venkataramanan  * @pi: port information structure
16444fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
16455513b920SAnirudh Venkataramanan  * @tc_node: pointer to TC node
16465513b920SAnirudh Venkataramanan  * @num_nodes: pointer to num nodes array
16475513b920SAnirudh Venkataramanan  *
1648d337f2afSAnirudh Venkataramanan  * This function adds the VSI supported nodes into Tx tree including the
16495513b920SAnirudh Venkataramanan  * VSI, its parent and intermediate nodes in below layers
16505513b920SAnirudh Venkataramanan  */
16515513b920SAnirudh Venkataramanan static enum ice_status
16524fb33f31SAnirudh Venkataramanan ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle,
16535513b920SAnirudh Venkataramanan 				struct ice_sched_node *tc_node, u16 *num_nodes)
16545513b920SAnirudh Venkataramanan {
16555513b920SAnirudh Venkataramanan 	struct ice_sched_node *parent = tc_node;
16565513b920SAnirudh Venkataramanan 	enum ice_status status;
16575513b920SAnirudh Venkataramanan 	u32 first_node_teid;
16585513b920SAnirudh Venkataramanan 	u16 num_added = 0;
16595513b920SAnirudh Venkataramanan 	u8 i, vsil;
16605513b920SAnirudh Venkataramanan 
16615513b920SAnirudh Venkataramanan 	if (!pi)
16625513b920SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
16635513b920SAnirudh Venkataramanan 
16645513b920SAnirudh Venkataramanan 	vsil = ice_sched_get_vsi_layer(pi->hw);
16655513b920SAnirudh Venkataramanan 	for (i = pi->hw->sw_entry_point_layer; i <= vsil; i++) {
16665513b920SAnirudh Venkataramanan 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent,
16675513b920SAnirudh Venkataramanan 						      i, num_nodes[i],
16685513b920SAnirudh Venkataramanan 						      &first_node_teid,
16695513b920SAnirudh Venkataramanan 						      &num_added);
16705513b920SAnirudh Venkataramanan 		if (status || num_nodes[i] != num_added)
16715513b920SAnirudh Venkataramanan 			return ICE_ERR_CFG;
16725513b920SAnirudh Venkataramanan 
16735513b920SAnirudh Venkataramanan 		/* The newly added node can be a new parent for the next
16745513b920SAnirudh Venkataramanan 		 * layer nodes
16755513b920SAnirudh Venkataramanan 		 */
16765513b920SAnirudh Venkataramanan 		if (num_added)
16775513b920SAnirudh Venkataramanan 			parent = ice_sched_find_node_by_teid(tc_node,
16785513b920SAnirudh Venkataramanan 							     first_node_teid);
16795513b920SAnirudh Venkataramanan 		else
16805513b920SAnirudh Venkataramanan 			parent = parent->children[0];
16815513b920SAnirudh Venkataramanan 
16825513b920SAnirudh Venkataramanan 		if (!parent)
16835513b920SAnirudh Venkataramanan 			return ICE_ERR_CFG;
16845513b920SAnirudh Venkataramanan 
16855513b920SAnirudh Venkataramanan 		if (i == vsil)
16864fb33f31SAnirudh Venkataramanan 			parent->vsi_handle = vsi_handle;
16875513b920SAnirudh Venkataramanan 	}
1688b36c598cSAnirudh Venkataramanan 
16895513b920SAnirudh Venkataramanan 	return 0;
16905513b920SAnirudh Venkataramanan }
16915513b920SAnirudh Venkataramanan 
16925513b920SAnirudh Venkataramanan /**
16935513b920SAnirudh Venkataramanan  * ice_sched_add_vsi_to_topo - add a new VSI into tree
16945513b920SAnirudh Venkataramanan  * @pi: port information structure
16954fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
16965513b920SAnirudh Venkataramanan  * @tc: TC number
16975513b920SAnirudh Venkataramanan  *
16985513b920SAnirudh Venkataramanan  * This function adds a new VSI into scheduler tree
16995513b920SAnirudh Venkataramanan  */
17005513b920SAnirudh Venkataramanan static enum ice_status
17014fb33f31SAnirudh Venkataramanan ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc)
17025513b920SAnirudh Venkataramanan {
17035513b920SAnirudh Venkataramanan 	u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
17045513b920SAnirudh Venkataramanan 	struct ice_sched_node *tc_node;
17055513b920SAnirudh Venkataramanan 
17065513b920SAnirudh Venkataramanan 	tc_node = ice_sched_get_tc_node(pi, tc);
17075513b920SAnirudh Venkataramanan 	if (!tc_node)
17085513b920SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
17095513b920SAnirudh Venkataramanan 
17105513b920SAnirudh Venkataramanan 	/* calculate number of supported nodes needed for this VSI */
1711b126bd6bSKiran Patil 	ice_sched_calc_vsi_support_nodes(pi, tc_node, num_nodes);
17125513b920SAnirudh Venkataramanan 
1713f9867df6SAnirudh Venkataramanan 	/* add VSI supported nodes to TC subtree */
17144fb33f31SAnirudh Venkataramanan 	return ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node,
17154fb33f31SAnirudh Venkataramanan 					       num_nodes);
17165513b920SAnirudh Venkataramanan }
17175513b920SAnirudh Venkataramanan 
17185513b920SAnirudh Venkataramanan /**
17195513b920SAnirudh Venkataramanan  * ice_sched_update_vsi_child_nodes - update VSI child nodes
17205513b920SAnirudh Venkataramanan  * @pi: port information structure
17214fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
17225513b920SAnirudh Venkataramanan  * @tc: TC number
17235513b920SAnirudh Venkataramanan  * @new_numqs: new number of max queues
17245513b920SAnirudh Venkataramanan  * @owner: owner of this subtree
17255513b920SAnirudh Venkataramanan  *
17265513b920SAnirudh Venkataramanan  * This function updates the VSI child nodes based on the number of queues
17275513b920SAnirudh Venkataramanan  */
17285513b920SAnirudh Venkataramanan static enum ice_status
17294fb33f31SAnirudh Venkataramanan ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
17304fb33f31SAnirudh Venkataramanan 				 u8 tc, u16 new_numqs, u8 owner)
17315513b920SAnirudh Venkataramanan {
17325513b920SAnirudh Venkataramanan 	u16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
17335513b920SAnirudh Venkataramanan 	struct ice_sched_node *vsi_node;
17345513b920SAnirudh Venkataramanan 	struct ice_sched_node *tc_node;
17354fb33f31SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
17365513b920SAnirudh Venkataramanan 	enum ice_status status = 0;
17375513b920SAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
17385513b920SAnirudh Venkataramanan 	u16 prev_numqs;
17395513b920SAnirudh Venkataramanan 
17405513b920SAnirudh Venkataramanan 	tc_node = ice_sched_get_tc_node(pi, tc);
17415513b920SAnirudh Venkataramanan 	if (!tc_node)
17425513b920SAnirudh Venkataramanan 		return ICE_ERR_CFG;
17435513b920SAnirudh Venkataramanan 
1744b126bd6bSKiran Patil 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
17455513b920SAnirudh Venkataramanan 	if (!vsi_node)
17465513b920SAnirudh Venkataramanan 		return ICE_ERR_CFG;
17475513b920SAnirudh Venkataramanan 
17484fb33f31SAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
17494fb33f31SAnirudh Venkataramanan 	if (!vsi_ctx)
17504fb33f31SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
17515513b920SAnirudh Venkataramanan 
17524fb33f31SAnirudh Venkataramanan 	prev_numqs = vsi_ctx->sched.max_lanq[tc];
1753b0153fddSVictor Raj 	/* num queues are not changed or less than the previous number */
1754b0153fddSVictor Raj 	if (new_numqs <= prev_numqs)
17555513b920SAnirudh Venkataramanan 		return status;
1756bb87ee0eSAnirudh Venkataramanan 	status = ice_alloc_lan_q_ctx(hw, vsi_handle, tc, new_numqs);
1757bb87ee0eSAnirudh Venkataramanan 	if (status)
1758bb87ee0eSAnirudh Venkataramanan 		return status;
1759bb87ee0eSAnirudh Venkataramanan 
17605513b920SAnirudh Venkataramanan 	if (new_numqs)
17615513b920SAnirudh Venkataramanan 		ice_sched_calc_vsi_child_nodes(hw, new_numqs, new_num_nodes);
1762b0153fddSVictor Raj 	/* Keep the max number of queue configuration all the time. Update the
1763b0153fddSVictor Raj 	 * tree only if number of queues > previous number of queues. This may
1764b0153fddSVictor Raj 	 * leave some extra nodes in the tree if number of queues < previous
1765b0153fddSVictor Raj 	 * number but that wouldn't harm anything. Removing those extra nodes
1766b0153fddSVictor Raj 	 * may complicate the code if those nodes are part of SRL or
1767b0153fddSVictor Raj 	 * individually rate limited.
1768b0153fddSVictor Raj 	 */
17694fb33f31SAnirudh Venkataramanan 	status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node,
17705513b920SAnirudh Venkataramanan 					       new_num_nodes, owner);
17715513b920SAnirudh Venkataramanan 	if (status)
17725513b920SAnirudh Venkataramanan 		return status;
17734fb33f31SAnirudh Venkataramanan 	vsi_ctx->sched.max_lanq[tc] = new_numqs;
17745513b920SAnirudh Venkataramanan 
17751b5c19c7SBruce Allan 	return 0;
17765513b920SAnirudh Venkataramanan }
17775513b920SAnirudh Venkataramanan 
17785513b920SAnirudh Venkataramanan /**
177910e03a22SAnirudh Venkataramanan  * ice_sched_cfg_vsi - configure the new/existing VSI
17805513b920SAnirudh Venkataramanan  * @pi: port information structure
17814fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
17825513b920SAnirudh Venkataramanan  * @tc: TC number
17835513b920SAnirudh Venkataramanan  * @maxqs: max number of queues
1784f9867df6SAnirudh Venkataramanan  * @owner: LAN or RDMA
17855513b920SAnirudh Venkataramanan  * @enable: TC enabled or disabled
17865513b920SAnirudh Venkataramanan  *
17875513b920SAnirudh Venkataramanan  * This function adds/updates VSI nodes based on the number of queues. If TC is
17885513b920SAnirudh Venkataramanan  * enabled and VSI is in suspended state then resume the VSI back. If TC is
17895513b920SAnirudh Venkataramanan  * disabled then suspend the VSI if it is not already.
17905513b920SAnirudh Venkataramanan  */
17915513b920SAnirudh Venkataramanan enum ice_status
17924fb33f31SAnirudh Venkataramanan ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs,
17935513b920SAnirudh Venkataramanan 		  u8 owner, bool enable)
17945513b920SAnirudh Venkataramanan {
17955513b920SAnirudh Venkataramanan 	struct ice_sched_node *vsi_node, *tc_node;
17964fb33f31SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
17975513b920SAnirudh Venkataramanan 	enum ice_status status = 0;
17985513b920SAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
17995513b920SAnirudh Venkataramanan 
1800e1ca65a3SVictor Raj 	ice_debug(pi->hw, ICE_DBG_SCHED, "add/config VSI %d\n", vsi_handle);
18015513b920SAnirudh Venkataramanan 	tc_node = ice_sched_get_tc_node(pi, tc);
18025513b920SAnirudh Venkataramanan 	if (!tc_node)
18035513b920SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
18044fb33f31SAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
18054fb33f31SAnirudh Venkataramanan 	if (!vsi_ctx)
18064fb33f31SAnirudh Venkataramanan 		return ICE_ERR_PARAM;
1807b126bd6bSKiran Patil 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
18085513b920SAnirudh Venkataramanan 
1809f9867df6SAnirudh Venkataramanan 	/* suspend the VSI if TC is not enabled */
18105513b920SAnirudh Venkataramanan 	if (!enable) {
18115513b920SAnirudh Venkataramanan 		if (vsi_node && vsi_node->in_use) {
18125513b920SAnirudh Venkataramanan 			u32 teid = le32_to_cpu(vsi_node->info.node_teid);
18135513b920SAnirudh Venkataramanan 
18145513b920SAnirudh Venkataramanan 			status = ice_sched_suspend_resume_elems(hw, 1, &teid,
18155513b920SAnirudh Venkataramanan 								true);
18165513b920SAnirudh Venkataramanan 			if (!status)
18175513b920SAnirudh Venkataramanan 				vsi_node->in_use = false;
18185513b920SAnirudh Venkataramanan 		}
18195513b920SAnirudh Venkataramanan 		return status;
18205513b920SAnirudh Venkataramanan 	}
18215513b920SAnirudh Venkataramanan 
18225513b920SAnirudh Venkataramanan 	/* TC is enabled, if it is a new VSI then add it to the tree */
18235513b920SAnirudh Venkataramanan 	if (!vsi_node) {
18244fb33f31SAnirudh Venkataramanan 		status = ice_sched_add_vsi_to_topo(pi, vsi_handle, tc);
18255513b920SAnirudh Venkataramanan 		if (status)
18265513b920SAnirudh Venkataramanan 			return status;
1827b36c598cSAnirudh Venkataramanan 
1828b126bd6bSKiran Patil 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
18295513b920SAnirudh Venkataramanan 		if (!vsi_node)
18305513b920SAnirudh Venkataramanan 			return ICE_ERR_CFG;
1831b36c598cSAnirudh Venkataramanan 
18324fb33f31SAnirudh Venkataramanan 		vsi_ctx->sched.vsi_node[tc] = vsi_node;
18335513b920SAnirudh Venkataramanan 		vsi_node->in_use = true;
18344fb33f31SAnirudh Venkataramanan 		/* invalidate the max queues whenever VSI gets added first time
18354fb33f31SAnirudh Venkataramanan 		 * into the scheduler tree (boot or after reset). We need to
18364fb33f31SAnirudh Venkataramanan 		 * recreate the child nodes all the time in these cases.
18374fb33f31SAnirudh Venkataramanan 		 */
18384fb33f31SAnirudh Venkataramanan 		vsi_ctx->sched.max_lanq[tc] = 0;
18395513b920SAnirudh Venkataramanan 	}
18405513b920SAnirudh Venkataramanan 
18415513b920SAnirudh Venkataramanan 	/* update the VSI child nodes */
18424fb33f31SAnirudh Venkataramanan 	status = ice_sched_update_vsi_child_nodes(pi, vsi_handle, tc, maxqs,
18434fb33f31SAnirudh Venkataramanan 						  owner);
18445513b920SAnirudh Venkataramanan 	if (status)
18455513b920SAnirudh Venkataramanan 		return status;
18465513b920SAnirudh Venkataramanan 
18475513b920SAnirudh Venkataramanan 	/* TC is enabled, resume the VSI if it is in the suspend state */
18485513b920SAnirudh Venkataramanan 	if (!vsi_node->in_use) {
18495513b920SAnirudh Venkataramanan 		u32 teid = le32_to_cpu(vsi_node->info.node_teid);
18505513b920SAnirudh Venkataramanan 
18515513b920SAnirudh Venkataramanan 		status = ice_sched_suspend_resume_elems(hw, 1, &teid, false);
18525513b920SAnirudh Venkataramanan 		if (!status)
18535513b920SAnirudh Venkataramanan 			vsi_node->in_use = true;
18545513b920SAnirudh Venkataramanan 	}
18555513b920SAnirudh Venkataramanan 
18565513b920SAnirudh Venkataramanan 	return status;
18575513b920SAnirudh Venkataramanan }
185810e03a22SAnirudh Venkataramanan 
185910e03a22SAnirudh Venkataramanan /**
1860*ef860480STony Nguyen  * ice_sched_rm_agg_vsi_info - remove aggregator related VSI info entry
186110e03a22SAnirudh Venkataramanan  * @pi: port information structure
186210e03a22SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
186310e03a22SAnirudh Venkataramanan  *
186410e03a22SAnirudh Venkataramanan  * This function removes single aggregator VSI info entry from
186510e03a22SAnirudh Venkataramanan  * aggregator list.
186610e03a22SAnirudh Venkataramanan  */
1867ebb462dcSBruce Allan static void ice_sched_rm_agg_vsi_info(struct ice_port_info *pi, u16 vsi_handle)
186810e03a22SAnirudh Venkataramanan {
186910e03a22SAnirudh Venkataramanan 	struct ice_sched_agg_info *agg_info;
187010e03a22SAnirudh Venkataramanan 	struct ice_sched_agg_info *atmp;
187110e03a22SAnirudh Venkataramanan 
18729be1d6f8SAnirudh Venkataramanan 	list_for_each_entry_safe(agg_info, atmp, &pi->hw->agg_list,
18739be1d6f8SAnirudh Venkataramanan 				 list_entry) {
187410e03a22SAnirudh Venkataramanan 		struct ice_sched_agg_vsi_info *agg_vsi_info;
187510e03a22SAnirudh Venkataramanan 		struct ice_sched_agg_vsi_info *vtmp;
187610e03a22SAnirudh Venkataramanan 
187710e03a22SAnirudh Venkataramanan 		list_for_each_entry_safe(agg_vsi_info, vtmp,
187810e03a22SAnirudh Venkataramanan 					 &agg_info->agg_vsi_list, list_entry)
187910e03a22SAnirudh Venkataramanan 			if (agg_vsi_info->vsi_handle == vsi_handle) {
188010e03a22SAnirudh Venkataramanan 				list_del(&agg_vsi_info->list_entry);
188110e03a22SAnirudh Venkataramanan 				devm_kfree(ice_hw_to_dev(pi->hw),
188210e03a22SAnirudh Venkataramanan 					   agg_vsi_info);
188310e03a22SAnirudh Venkataramanan 				return;
188410e03a22SAnirudh Venkataramanan 			}
188510e03a22SAnirudh Venkataramanan 	}
188610e03a22SAnirudh Venkataramanan }
188710e03a22SAnirudh Venkataramanan 
188810e03a22SAnirudh Venkataramanan /**
1889f70b9d5fSVictor Raj  * ice_sched_is_leaf_node_present - check for a leaf node in the sub-tree
1890f70b9d5fSVictor Raj  * @node: pointer to the sub-tree node
1891f70b9d5fSVictor Raj  *
1892f70b9d5fSVictor Raj  * This function checks for a leaf node presence in a given sub-tree node.
1893f70b9d5fSVictor Raj  */
1894f70b9d5fSVictor Raj static bool ice_sched_is_leaf_node_present(struct ice_sched_node *node)
1895f70b9d5fSVictor Raj {
1896f70b9d5fSVictor Raj 	u8 i;
1897f70b9d5fSVictor Raj 
1898f70b9d5fSVictor Raj 	for (i = 0; i < node->num_children; i++)
1899f70b9d5fSVictor Raj 		if (ice_sched_is_leaf_node_present(node->children[i]))
1900f70b9d5fSVictor Raj 			return true;
1901f70b9d5fSVictor Raj 	/* check for a leaf node */
1902f70b9d5fSVictor Raj 	return (node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF);
1903f70b9d5fSVictor Raj }
1904f70b9d5fSVictor Raj 
1905f70b9d5fSVictor Raj /**
190610e03a22SAnirudh Venkataramanan  * ice_sched_rm_vsi_cfg - remove the VSI and its children nodes
190710e03a22SAnirudh Venkataramanan  * @pi: port information structure
190810e03a22SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
190910e03a22SAnirudh Venkataramanan  * @owner: LAN or RDMA
191010e03a22SAnirudh Venkataramanan  *
191110e03a22SAnirudh Venkataramanan  * This function removes the VSI and its LAN or RDMA children nodes from the
191210e03a22SAnirudh Venkataramanan  * scheduler tree.
191310e03a22SAnirudh Venkataramanan  */
191410e03a22SAnirudh Venkataramanan static enum ice_status
191510e03a22SAnirudh Venkataramanan ice_sched_rm_vsi_cfg(struct ice_port_info *pi, u16 vsi_handle, u8 owner)
191610e03a22SAnirudh Venkataramanan {
191710e03a22SAnirudh Venkataramanan 	enum ice_status status = ICE_ERR_PARAM;
191810e03a22SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
1919e1ca65a3SVictor Raj 	u8 i;
192010e03a22SAnirudh Venkataramanan 
1921e1ca65a3SVictor Raj 	ice_debug(pi->hw, ICE_DBG_SCHED, "removing VSI %d\n", vsi_handle);
192210e03a22SAnirudh Venkataramanan 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
192310e03a22SAnirudh Venkataramanan 		return status;
192410e03a22SAnirudh Venkataramanan 	mutex_lock(&pi->sched_lock);
192510e03a22SAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
192610e03a22SAnirudh Venkataramanan 	if (!vsi_ctx)
192710e03a22SAnirudh Venkataramanan 		goto exit_sched_rm_vsi_cfg;
192810e03a22SAnirudh Venkataramanan 
19292bdc97beSBruce Allan 	ice_for_each_traffic_class(i) {
193010e03a22SAnirudh Venkataramanan 		struct ice_sched_node *vsi_node, *tc_node;
1931e1ca65a3SVictor Raj 		u8 j = 0;
193210e03a22SAnirudh Venkataramanan 
193310e03a22SAnirudh Venkataramanan 		tc_node = ice_sched_get_tc_node(pi, i);
193410e03a22SAnirudh Venkataramanan 		if (!tc_node)
193510e03a22SAnirudh Venkataramanan 			continue;
193610e03a22SAnirudh Venkataramanan 
1937b126bd6bSKiran Patil 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
193810e03a22SAnirudh Venkataramanan 		if (!vsi_node)
193910e03a22SAnirudh Venkataramanan 			continue;
194010e03a22SAnirudh Venkataramanan 
1941f70b9d5fSVictor Raj 		if (ice_sched_is_leaf_node_present(vsi_node)) {
19429228d8b2SJacob Keller 			ice_debug(pi->hw, ICE_DBG_SCHED, "VSI has leaf nodes in TC %d\n", i);
1943f70b9d5fSVictor Raj 			status = ICE_ERR_IN_USE;
1944f70b9d5fSVictor Raj 			goto exit_sched_rm_vsi_cfg;
1945f70b9d5fSVictor Raj 		}
194610e03a22SAnirudh Venkataramanan 		while (j < vsi_node->num_children) {
194710e03a22SAnirudh Venkataramanan 			if (vsi_node->children[j]->owner == owner) {
194810e03a22SAnirudh Venkataramanan 				ice_free_sched_node(pi, vsi_node->children[j]);
194910e03a22SAnirudh Venkataramanan 
195010e03a22SAnirudh Venkataramanan 				/* reset the counter again since the num
195110e03a22SAnirudh Venkataramanan 				 * children will be updated after node removal
195210e03a22SAnirudh Venkataramanan 				 */
195310e03a22SAnirudh Venkataramanan 				j = 0;
195410e03a22SAnirudh Venkataramanan 			} else {
195510e03a22SAnirudh Venkataramanan 				j++;
195610e03a22SAnirudh Venkataramanan 			}
195710e03a22SAnirudh Venkataramanan 		}
195810e03a22SAnirudh Venkataramanan 		/* remove the VSI if it has no children */
195910e03a22SAnirudh Venkataramanan 		if (!vsi_node->num_children) {
196010e03a22SAnirudh Venkataramanan 			ice_free_sched_node(pi, vsi_node);
196110e03a22SAnirudh Venkataramanan 			vsi_ctx->sched.vsi_node[i] = NULL;
196210e03a22SAnirudh Venkataramanan 
1963f9867df6SAnirudh Venkataramanan 			/* clean up aggregator related VSI info if any */
196410e03a22SAnirudh Venkataramanan 			ice_sched_rm_agg_vsi_info(pi, vsi_handle);
196510e03a22SAnirudh Venkataramanan 		}
196610e03a22SAnirudh Venkataramanan 		if (owner == ICE_SCHED_NODE_OWNER_LAN)
196710e03a22SAnirudh Venkataramanan 			vsi_ctx->sched.max_lanq[i] = 0;
196810e03a22SAnirudh Venkataramanan 	}
196910e03a22SAnirudh Venkataramanan 	status = 0;
197010e03a22SAnirudh Venkataramanan 
197110e03a22SAnirudh Venkataramanan exit_sched_rm_vsi_cfg:
197210e03a22SAnirudh Venkataramanan 	mutex_unlock(&pi->sched_lock);
197310e03a22SAnirudh Venkataramanan 	return status;
197410e03a22SAnirudh Venkataramanan }
197510e03a22SAnirudh Venkataramanan 
197610e03a22SAnirudh Venkataramanan /**
197710e03a22SAnirudh Venkataramanan  * ice_rm_vsi_lan_cfg - remove VSI and its LAN children nodes
197810e03a22SAnirudh Venkataramanan  * @pi: port information structure
197910e03a22SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
198010e03a22SAnirudh Venkataramanan  *
198110e03a22SAnirudh Venkataramanan  * This function clears the VSI and its LAN children nodes from scheduler tree
198210e03a22SAnirudh Venkataramanan  * for all TCs.
198310e03a22SAnirudh Venkataramanan  */
198410e03a22SAnirudh Venkataramanan enum ice_status ice_rm_vsi_lan_cfg(struct ice_port_info *pi, u16 vsi_handle)
198510e03a22SAnirudh Venkataramanan {
198610e03a22SAnirudh Venkataramanan 	return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_LAN);
198710e03a22SAnirudh Venkataramanan }
19881ddef455SUsha Ketineni 
19891ddef455SUsha Ketineni /**
1990b126bd6bSKiran Patil  * ice_get_agg_info - get the aggregator ID
1991b126bd6bSKiran Patil  * @hw: pointer to the hardware structure
1992b126bd6bSKiran Patil  * @agg_id: aggregator ID
1993b126bd6bSKiran Patil  *
1994b126bd6bSKiran Patil  * This function validates aggregator ID. The function returns info if
1995b126bd6bSKiran Patil  * aggregator ID is present in list otherwise it returns null.
1996b126bd6bSKiran Patil  */
1997b126bd6bSKiran Patil static struct ice_sched_agg_info *
1998b126bd6bSKiran Patil ice_get_agg_info(struct ice_hw *hw, u32 agg_id)
1999b126bd6bSKiran Patil {
2000b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2001b126bd6bSKiran Patil 
2002b126bd6bSKiran Patil 	list_for_each_entry(agg_info, &hw->agg_list, list_entry)
2003b126bd6bSKiran Patil 		if (agg_info->agg_id == agg_id)
2004b126bd6bSKiran Patil 			return agg_info;
2005b126bd6bSKiran Patil 
2006b126bd6bSKiran Patil 	return NULL;
2007b126bd6bSKiran Patil }
2008b126bd6bSKiran Patil 
2009b126bd6bSKiran Patil /**
2010b126bd6bSKiran Patil  * ice_sched_get_free_vsi_parent - Find a free parent node in aggregator subtree
2011b126bd6bSKiran Patil  * @hw: pointer to the HW struct
2012b126bd6bSKiran Patil  * @node: pointer to a child node
2013b126bd6bSKiran Patil  * @num_nodes: num nodes count array
2014b126bd6bSKiran Patil  *
2015b126bd6bSKiran Patil  * This function walks through the aggregator subtree to find a free parent
2016b126bd6bSKiran Patil  * node
2017b126bd6bSKiran Patil  */
2018b126bd6bSKiran Patil static struct ice_sched_node *
2019b126bd6bSKiran Patil ice_sched_get_free_vsi_parent(struct ice_hw *hw, struct ice_sched_node *node,
2020b126bd6bSKiran Patil 			      u16 *num_nodes)
2021b126bd6bSKiran Patil {
2022b126bd6bSKiran Patil 	u8 l = node->tx_sched_layer;
2023b126bd6bSKiran Patil 	u8 vsil, i;
2024b126bd6bSKiran Patil 
2025b126bd6bSKiran Patil 	vsil = ice_sched_get_vsi_layer(hw);
2026b126bd6bSKiran Patil 
2027b126bd6bSKiran Patil 	/* Is it VSI parent layer ? */
2028b126bd6bSKiran Patil 	if (l == vsil - 1)
2029b126bd6bSKiran Patil 		return (node->num_children < hw->max_children[l]) ? node : NULL;
2030b126bd6bSKiran Patil 
2031b126bd6bSKiran Patil 	/* We have intermediate nodes. Let's walk through the subtree. If the
2032b126bd6bSKiran Patil 	 * intermediate node has space to add a new node then clear the count
2033b126bd6bSKiran Patil 	 */
2034b126bd6bSKiran Patil 	if (node->num_children < hw->max_children[l])
2035b126bd6bSKiran Patil 		num_nodes[l] = 0;
2036b126bd6bSKiran Patil 	/* The below recursive call is intentional and wouldn't go more than
2037b126bd6bSKiran Patil 	 * 2 or 3 iterations.
2038b126bd6bSKiran Patil 	 */
2039b126bd6bSKiran Patil 
2040b126bd6bSKiran Patil 	for (i = 0; i < node->num_children; i++) {
2041b126bd6bSKiran Patil 		struct ice_sched_node *parent;
2042b126bd6bSKiran Patil 
2043b126bd6bSKiran Patil 		parent = ice_sched_get_free_vsi_parent(hw, node->children[i],
2044b126bd6bSKiran Patil 						       num_nodes);
2045b126bd6bSKiran Patil 		if (parent)
2046b126bd6bSKiran Patil 			return parent;
2047b126bd6bSKiran Patil 	}
2048b126bd6bSKiran Patil 
2049b126bd6bSKiran Patil 	return NULL;
2050b126bd6bSKiran Patil }
2051b126bd6bSKiran Patil 
2052b126bd6bSKiran Patil /**
2053b126bd6bSKiran Patil  * ice_sched_update_parent - update the new parent in SW DB
2054b126bd6bSKiran Patil  * @new_parent: pointer to a new parent node
2055b126bd6bSKiran Patil  * @node: pointer to a child node
2056b126bd6bSKiran Patil  *
2057b126bd6bSKiran Patil  * This function removes the child from the old parent and adds it to a new
2058b126bd6bSKiran Patil  * parent
2059b126bd6bSKiran Patil  */
2060b126bd6bSKiran Patil static void
2061b126bd6bSKiran Patil ice_sched_update_parent(struct ice_sched_node *new_parent,
2062b126bd6bSKiran Patil 			struct ice_sched_node *node)
2063b126bd6bSKiran Patil {
2064b126bd6bSKiran Patil 	struct ice_sched_node *old_parent;
2065b126bd6bSKiran Patil 	u8 i, j;
2066b126bd6bSKiran Patil 
2067b126bd6bSKiran Patil 	old_parent = node->parent;
2068b126bd6bSKiran Patil 
2069b126bd6bSKiran Patil 	/* update the old parent children */
2070b126bd6bSKiran Patil 	for (i = 0; i < old_parent->num_children; i++)
2071b126bd6bSKiran Patil 		if (old_parent->children[i] == node) {
2072b126bd6bSKiran Patil 			for (j = i + 1; j < old_parent->num_children; j++)
2073b126bd6bSKiran Patil 				old_parent->children[j - 1] =
2074b126bd6bSKiran Patil 					old_parent->children[j];
2075b126bd6bSKiran Patil 			old_parent->num_children--;
2076b126bd6bSKiran Patil 			break;
2077b126bd6bSKiran Patil 		}
2078b126bd6bSKiran Patil 
2079b126bd6bSKiran Patil 	/* now move the node to a new parent */
2080b126bd6bSKiran Patil 	new_parent->children[new_parent->num_children++] = node;
2081b126bd6bSKiran Patil 	node->parent = new_parent;
2082b126bd6bSKiran Patil 	node->info.parent_teid = new_parent->info.node_teid;
2083b126bd6bSKiran Patil }
2084b126bd6bSKiran Patil 
2085b126bd6bSKiran Patil /**
2086b126bd6bSKiran Patil  * ice_sched_move_nodes - move child nodes to a given parent
2087b126bd6bSKiran Patil  * @pi: port information structure
2088b126bd6bSKiran Patil  * @parent: pointer to parent node
2089b126bd6bSKiran Patil  * @num_items: number of child nodes to be moved
2090b126bd6bSKiran Patil  * @list: pointer to child node teids
2091b126bd6bSKiran Patil  *
2092b126bd6bSKiran Patil  * This function move the child nodes to a given parent.
2093b126bd6bSKiran Patil  */
2094b126bd6bSKiran Patil static enum ice_status
2095b126bd6bSKiran Patil ice_sched_move_nodes(struct ice_port_info *pi, struct ice_sched_node *parent,
2096b126bd6bSKiran Patil 		     u16 num_items, u32 *list)
2097b126bd6bSKiran Patil {
2098b126bd6bSKiran Patil 	struct ice_aqc_move_elem *buf;
2099b126bd6bSKiran Patil 	struct ice_sched_node *node;
2100b126bd6bSKiran Patil 	enum ice_status status = 0;
2101b126bd6bSKiran Patil 	u16 i, grps_movd = 0;
2102b126bd6bSKiran Patil 	struct ice_hw *hw;
2103b126bd6bSKiran Patil 	u16 buf_len;
2104b126bd6bSKiran Patil 
2105b126bd6bSKiran Patil 	hw = pi->hw;
2106b126bd6bSKiran Patil 
2107b126bd6bSKiran Patil 	if (!parent || !num_items)
2108b126bd6bSKiran Patil 		return ICE_ERR_PARAM;
2109b126bd6bSKiran Patil 
2110b126bd6bSKiran Patil 	/* Does parent have enough space */
2111b126bd6bSKiran Patil 	if (parent->num_children + num_items >
2112b126bd6bSKiran Patil 	    hw->max_children[parent->tx_sched_layer])
2113b126bd6bSKiran Patil 		return ICE_ERR_AQ_FULL;
2114b126bd6bSKiran Patil 
2115b126bd6bSKiran Patil 	buf_len = struct_size(buf, teid, 1);
2116b126bd6bSKiran Patil 	buf = kzalloc(buf_len, GFP_KERNEL);
2117b126bd6bSKiran Patil 	if (!buf)
2118b126bd6bSKiran Patil 		return ICE_ERR_NO_MEMORY;
2119b126bd6bSKiran Patil 
2120b126bd6bSKiran Patil 	for (i = 0; i < num_items; i++) {
2121b126bd6bSKiran Patil 		node = ice_sched_find_node_by_teid(pi->root, list[i]);
2122b126bd6bSKiran Patil 		if (!node) {
2123b126bd6bSKiran Patil 			status = ICE_ERR_PARAM;
2124b126bd6bSKiran Patil 			goto move_err_exit;
2125b126bd6bSKiran Patil 		}
2126b126bd6bSKiran Patil 
2127b126bd6bSKiran Patil 		buf->hdr.src_parent_teid = node->info.parent_teid;
2128b126bd6bSKiran Patil 		buf->hdr.dest_parent_teid = parent->info.node_teid;
2129b126bd6bSKiran Patil 		buf->teid[0] = node->info.node_teid;
2130b126bd6bSKiran Patil 		buf->hdr.num_elems = cpu_to_le16(1);
2131b126bd6bSKiran Patil 		status = ice_aq_move_sched_elems(hw, 1, buf, buf_len,
2132b126bd6bSKiran Patil 						 &grps_movd, NULL);
2133b126bd6bSKiran Patil 		if (status && grps_movd != 1) {
2134b126bd6bSKiran Patil 			status = ICE_ERR_CFG;
2135b126bd6bSKiran Patil 			goto move_err_exit;
2136b126bd6bSKiran Patil 		}
2137b126bd6bSKiran Patil 
2138b126bd6bSKiran Patil 		/* update the SW DB */
2139b126bd6bSKiran Patil 		ice_sched_update_parent(parent, node);
2140b126bd6bSKiran Patil 	}
2141b126bd6bSKiran Patil 
2142b126bd6bSKiran Patil move_err_exit:
2143b126bd6bSKiran Patil 	kfree(buf);
2144b126bd6bSKiran Patil 	return status;
2145b126bd6bSKiran Patil }
2146b126bd6bSKiran Patil 
2147b126bd6bSKiran Patil /**
2148b126bd6bSKiran Patil  * ice_sched_move_vsi_to_agg - move VSI to aggregator node
2149b126bd6bSKiran Patil  * @pi: port information structure
2150b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2151b126bd6bSKiran Patil  * @agg_id: aggregator ID
2152b126bd6bSKiran Patil  * @tc: TC number
2153b126bd6bSKiran Patil  *
2154b126bd6bSKiran Patil  * This function moves a VSI to an aggregator node or its subtree.
2155b126bd6bSKiran Patil  * Intermediate nodes may be created if required.
2156b126bd6bSKiran Patil  */
2157b126bd6bSKiran Patil static enum ice_status
2158b126bd6bSKiran Patil ice_sched_move_vsi_to_agg(struct ice_port_info *pi, u16 vsi_handle, u32 agg_id,
2159b126bd6bSKiran Patil 			  u8 tc)
2160b126bd6bSKiran Patil {
2161b126bd6bSKiran Patil 	struct ice_sched_node *vsi_node, *agg_node, *tc_node, *parent;
2162b126bd6bSKiran Patil 	u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
2163b126bd6bSKiran Patil 	u32 first_node_teid, vsi_teid;
2164b126bd6bSKiran Patil 	enum ice_status status;
2165b126bd6bSKiran Patil 	u16 num_nodes_added;
2166b126bd6bSKiran Patil 	u8 aggl, vsil, i;
2167b126bd6bSKiran Patil 
2168b126bd6bSKiran Patil 	tc_node = ice_sched_get_tc_node(pi, tc);
2169b126bd6bSKiran Patil 	if (!tc_node)
2170b126bd6bSKiran Patil 		return ICE_ERR_CFG;
2171b126bd6bSKiran Patil 
2172b126bd6bSKiran Patil 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
2173b126bd6bSKiran Patil 	if (!agg_node)
2174b126bd6bSKiran Patil 		return ICE_ERR_DOES_NOT_EXIST;
2175b126bd6bSKiran Patil 
2176b126bd6bSKiran Patil 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
2177b126bd6bSKiran Patil 	if (!vsi_node)
2178b126bd6bSKiran Patil 		return ICE_ERR_DOES_NOT_EXIST;
2179b126bd6bSKiran Patil 
2180b126bd6bSKiran Patil 	/* Is this VSI already part of given aggregator? */
2181b126bd6bSKiran Patil 	if (ice_sched_find_node_in_subtree(pi->hw, agg_node, vsi_node))
2182b126bd6bSKiran Patil 		return 0;
2183b126bd6bSKiran Patil 
2184b126bd6bSKiran Patil 	aggl = ice_sched_get_agg_layer(pi->hw);
2185b126bd6bSKiran Patil 	vsil = ice_sched_get_vsi_layer(pi->hw);
2186b126bd6bSKiran Patil 
2187b126bd6bSKiran Patil 	/* set intermediate node count to 1 between aggregator and VSI layers */
2188b126bd6bSKiran Patil 	for (i = aggl + 1; i < vsil; i++)
2189b126bd6bSKiran Patil 		num_nodes[i] = 1;
2190b126bd6bSKiran Patil 
2191b126bd6bSKiran Patil 	/* Check if the aggregator subtree has any free node to add the VSI */
2192b126bd6bSKiran Patil 	for (i = 0; i < agg_node->num_children; i++) {
2193b126bd6bSKiran Patil 		parent = ice_sched_get_free_vsi_parent(pi->hw,
2194b126bd6bSKiran Patil 						       agg_node->children[i],
2195b126bd6bSKiran Patil 						       num_nodes);
2196b126bd6bSKiran Patil 		if (parent)
2197b126bd6bSKiran Patil 			goto move_nodes;
2198b126bd6bSKiran Patil 	}
2199b126bd6bSKiran Patil 
2200b126bd6bSKiran Patil 	/* add new nodes */
2201b126bd6bSKiran Patil 	parent = agg_node;
2202b126bd6bSKiran Patil 	for (i = aggl + 1; i < vsil; i++) {
2203b126bd6bSKiran Patil 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
2204b126bd6bSKiran Patil 						      num_nodes[i],
2205b126bd6bSKiran Patil 						      &first_node_teid,
2206b126bd6bSKiran Patil 						      &num_nodes_added);
2207b126bd6bSKiran Patil 		if (status || num_nodes[i] != num_nodes_added)
2208b126bd6bSKiran Patil 			return ICE_ERR_CFG;
2209b126bd6bSKiran Patil 
2210b126bd6bSKiran Patil 		/* The newly added node can be a new parent for the next
2211b126bd6bSKiran Patil 		 * layer nodes
2212b126bd6bSKiran Patil 		 */
2213b126bd6bSKiran Patil 		if (num_nodes_added)
2214b126bd6bSKiran Patil 			parent = ice_sched_find_node_by_teid(tc_node,
2215b126bd6bSKiran Patil 							     first_node_teid);
2216b126bd6bSKiran Patil 		else
2217b126bd6bSKiran Patil 			parent = parent->children[0];
2218b126bd6bSKiran Patil 
2219b126bd6bSKiran Patil 		if (!parent)
2220b126bd6bSKiran Patil 			return ICE_ERR_CFG;
2221b126bd6bSKiran Patil 	}
2222b126bd6bSKiran Patil 
2223b126bd6bSKiran Patil move_nodes:
2224b126bd6bSKiran Patil 	vsi_teid = le32_to_cpu(vsi_node->info.node_teid);
2225b126bd6bSKiran Patil 	return ice_sched_move_nodes(pi, parent, 1, &vsi_teid);
2226b126bd6bSKiran Patil }
2227b126bd6bSKiran Patil 
2228b126bd6bSKiran Patil /**
2229b126bd6bSKiran Patil  * ice_move_all_vsi_to_dflt_agg - move all VSI(s) to default aggregator
2230b126bd6bSKiran Patil  * @pi: port information structure
2231b126bd6bSKiran Patil  * @agg_info: aggregator info
2232b126bd6bSKiran Patil  * @tc: traffic class number
2233b126bd6bSKiran Patil  * @rm_vsi_info: true or false
2234b126bd6bSKiran Patil  *
2235b126bd6bSKiran Patil  * This function move all the VSI(s) to the default aggregator and delete
2236b126bd6bSKiran Patil  * aggregator VSI info based on passed in boolean parameter rm_vsi_info. The
2237b126bd6bSKiran Patil  * caller holds the scheduler lock.
2238b126bd6bSKiran Patil  */
2239b126bd6bSKiran Patil static enum ice_status
2240b126bd6bSKiran Patil ice_move_all_vsi_to_dflt_agg(struct ice_port_info *pi,
2241b126bd6bSKiran Patil 			     struct ice_sched_agg_info *agg_info, u8 tc,
2242b126bd6bSKiran Patil 			     bool rm_vsi_info)
2243b126bd6bSKiran Patil {
2244b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *agg_vsi_info;
2245b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *tmp;
2246b126bd6bSKiran Patil 	enum ice_status status = 0;
2247b126bd6bSKiran Patil 
2248b126bd6bSKiran Patil 	list_for_each_entry_safe(agg_vsi_info, tmp, &agg_info->agg_vsi_list,
2249b126bd6bSKiran Patil 				 list_entry) {
2250b126bd6bSKiran Patil 		u16 vsi_handle = agg_vsi_info->vsi_handle;
2251b126bd6bSKiran Patil 
2252b126bd6bSKiran Patil 		/* Move VSI to default aggregator */
2253b126bd6bSKiran Patil 		if (!ice_is_tc_ena(agg_vsi_info->tc_bitmap[0], tc))
2254b126bd6bSKiran Patil 			continue;
2255b126bd6bSKiran Patil 
2256b126bd6bSKiran Patil 		status = ice_sched_move_vsi_to_agg(pi, vsi_handle,
2257b126bd6bSKiran Patil 						   ICE_DFLT_AGG_ID, tc);
2258b126bd6bSKiran Patil 		if (status)
2259b126bd6bSKiran Patil 			break;
2260b126bd6bSKiran Patil 
2261b126bd6bSKiran Patil 		clear_bit(tc, agg_vsi_info->tc_bitmap);
2262b126bd6bSKiran Patil 		if (rm_vsi_info && !agg_vsi_info->tc_bitmap[0]) {
2263b126bd6bSKiran Patil 			list_del(&agg_vsi_info->list_entry);
2264b126bd6bSKiran Patil 			devm_kfree(ice_hw_to_dev(pi->hw), agg_vsi_info);
2265b126bd6bSKiran Patil 		}
2266b126bd6bSKiran Patil 	}
2267b126bd6bSKiran Patil 
2268b126bd6bSKiran Patil 	return status;
2269b126bd6bSKiran Patil }
2270b126bd6bSKiran Patil 
2271b126bd6bSKiran Patil /**
2272b126bd6bSKiran Patil  * ice_sched_is_agg_inuse - check whether the aggregator is in use or not
2273b126bd6bSKiran Patil  * @pi: port information structure
2274b126bd6bSKiran Patil  * @node: node pointer
2275b126bd6bSKiran Patil  *
2276b126bd6bSKiran Patil  * This function checks whether the aggregator is attached with any VSI or not.
2277b126bd6bSKiran Patil  */
2278b126bd6bSKiran Patil static bool
2279b126bd6bSKiran Patil ice_sched_is_agg_inuse(struct ice_port_info *pi, struct ice_sched_node *node)
2280b126bd6bSKiran Patil {
2281b126bd6bSKiran Patil 	u8 vsil, i;
2282b126bd6bSKiran Patil 
2283b126bd6bSKiran Patil 	vsil = ice_sched_get_vsi_layer(pi->hw);
2284b126bd6bSKiran Patil 	if (node->tx_sched_layer < vsil - 1) {
2285b126bd6bSKiran Patil 		for (i = 0; i < node->num_children; i++)
2286b126bd6bSKiran Patil 			if (ice_sched_is_agg_inuse(pi, node->children[i]))
2287b126bd6bSKiran Patil 				return true;
2288b126bd6bSKiran Patil 		return false;
2289b126bd6bSKiran Patil 	} else {
2290b126bd6bSKiran Patil 		return node->num_children ? true : false;
2291b126bd6bSKiran Patil 	}
2292b126bd6bSKiran Patil }
2293b126bd6bSKiran Patil 
2294b126bd6bSKiran Patil /**
2295b126bd6bSKiran Patil  * ice_sched_rm_agg_cfg - remove the aggregator node
2296b126bd6bSKiran Patil  * @pi: port information structure
2297b126bd6bSKiran Patil  * @agg_id: aggregator ID
2298b126bd6bSKiran Patil  * @tc: TC number
2299b126bd6bSKiran Patil  *
2300b126bd6bSKiran Patil  * This function removes the aggregator node and intermediate nodes if any
2301b126bd6bSKiran Patil  * from the given TC
2302b126bd6bSKiran Patil  */
2303b126bd6bSKiran Patil static enum ice_status
2304b126bd6bSKiran Patil ice_sched_rm_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc)
2305b126bd6bSKiran Patil {
2306b126bd6bSKiran Patil 	struct ice_sched_node *tc_node, *agg_node;
2307b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
2308b126bd6bSKiran Patil 
2309b126bd6bSKiran Patil 	tc_node = ice_sched_get_tc_node(pi, tc);
2310b126bd6bSKiran Patil 	if (!tc_node)
2311b126bd6bSKiran Patil 		return ICE_ERR_CFG;
2312b126bd6bSKiran Patil 
2313b126bd6bSKiran Patil 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
2314b126bd6bSKiran Patil 	if (!agg_node)
2315b126bd6bSKiran Patil 		return ICE_ERR_DOES_NOT_EXIST;
2316b126bd6bSKiran Patil 
2317b126bd6bSKiran Patil 	/* Can't remove the aggregator node if it has children */
2318b126bd6bSKiran Patil 	if (ice_sched_is_agg_inuse(pi, agg_node))
2319b126bd6bSKiran Patil 		return ICE_ERR_IN_USE;
2320b126bd6bSKiran Patil 
2321b126bd6bSKiran Patil 	/* need to remove the whole subtree if aggregator node is the
2322b126bd6bSKiran Patil 	 * only child.
2323b126bd6bSKiran Patil 	 */
2324b126bd6bSKiran Patil 	while (agg_node->tx_sched_layer > hw->sw_entry_point_layer) {
2325b126bd6bSKiran Patil 		struct ice_sched_node *parent = agg_node->parent;
2326b126bd6bSKiran Patil 
2327b126bd6bSKiran Patil 		if (!parent)
2328b126bd6bSKiran Patil 			return ICE_ERR_CFG;
2329b126bd6bSKiran Patil 
2330b126bd6bSKiran Patil 		if (parent->num_children > 1)
2331b126bd6bSKiran Patil 			break;
2332b126bd6bSKiran Patil 
2333b126bd6bSKiran Patil 		agg_node = parent;
2334b126bd6bSKiran Patil 	}
2335b126bd6bSKiran Patil 
2336b126bd6bSKiran Patil 	ice_free_sched_node(pi, agg_node);
2337b126bd6bSKiran Patil 	return 0;
2338b126bd6bSKiran Patil }
2339b126bd6bSKiran Patil 
2340b126bd6bSKiran Patil /**
2341b126bd6bSKiran Patil  * ice_rm_agg_cfg_tc - remove aggregator configuration for TC
2342b126bd6bSKiran Patil  * @pi: port information structure
2343b126bd6bSKiran Patil  * @agg_info: aggregator ID
2344b126bd6bSKiran Patil  * @tc: TC number
2345b126bd6bSKiran Patil  * @rm_vsi_info: bool value true or false
2346b126bd6bSKiran Patil  *
2347b126bd6bSKiran Patil  * This function removes aggregator reference to VSI of given TC. It removes
2348b126bd6bSKiran Patil  * the aggregator configuration completely for requested TC. The caller needs
2349b126bd6bSKiran Patil  * to hold the scheduler lock.
2350b126bd6bSKiran Patil  */
2351b126bd6bSKiran Patil static enum ice_status
2352b126bd6bSKiran Patil ice_rm_agg_cfg_tc(struct ice_port_info *pi, struct ice_sched_agg_info *agg_info,
2353b126bd6bSKiran Patil 		  u8 tc, bool rm_vsi_info)
2354b126bd6bSKiran Patil {
2355b126bd6bSKiran Patil 	enum ice_status status = 0;
2356b126bd6bSKiran Patil 
2357b126bd6bSKiran Patil 	/* If nothing to remove - return success */
2358b126bd6bSKiran Patil 	if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
2359b126bd6bSKiran Patil 		goto exit_rm_agg_cfg_tc;
2360b126bd6bSKiran Patil 
2361b126bd6bSKiran Patil 	status = ice_move_all_vsi_to_dflt_agg(pi, agg_info, tc, rm_vsi_info);
2362b126bd6bSKiran Patil 	if (status)
2363b126bd6bSKiran Patil 		goto exit_rm_agg_cfg_tc;
2364b126bd6bSKiran Patil 
2365b126bd6bSKiran Patil 	/* Delete aggregator node(s) */
2366b126bd6bSKiran Patil 	status = ice_sched_rm_agg_cfg(pi, agg_info->agg_id, tc);
2367b126bd6bSKiran Patil 	if (status)
2368b126bd6bSKiran Patil 		goto exit_rm_agg_cfg_tc;
2369b126bd6bSKiran Patil 
2370b126bd6bSKiran Patil 	clear_bit(tc, agg_info->tc_bitmap);
2371b126bd6bSKiran Patil exit_rm_agg_cfg_tc:
2372b126bd6bSKiran Patil 	return status;
2373b126bd6bSKiran Patil }
2374b126bd6bSKiran Patil 
2375b126bd6bSKiran Patil /**
2376b126bd6bSKiran Patil  * ice_save_agg_tc_bitmap - save aggregator TC bitmap
2377b126bd6bSKiran Patil  * @pi: port information structure
2378b126bd6bSKiran Patil  * @agg_id: aggregator ID
2379b126bd6bSKiran Patil  * @tc_bitmap: 8 bits TC bitmap
2380b126bd6bSKiran Patil  *
2381b126bd6bSKiran Patil  * Save aggregator TC bitmap. This function needs to be called with scheduler
2382b126bd6bSKiran Patil  * lock held.
2383b126bd6bSKiran Patil  */
2384b126bd6bSKiran Patil static enum ice_status
2385b126bd6bSKiran Patil ice_save_agg_tc_bitmap(struct ice_port_info *pi, u32 agg_id,
2386b126bd6bSKiran Patil 		       unsigned long *tc_bitmap)
2387b126bd6bSKiran Patil {
2388b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2389b126bd6bSKiran Patil 
2390b126bd6bSKiran Patil 	agg_info = ice_get_agg_info(pi->hw, agg_id);
2391b126bd6bSKiran Patil 	if (!agg_info)
2392b126bd6bSKiran Patil 		return ICE_ERR_PARAM;
2393b126bd6bSKiran Patil 	bitmap_copy(agg_info->replay_tc_bitmap, tc_bitmap,
2394b126bd6bSKiran Patil 		    ICE_MAX_TRAFFIC_CLASS);
2395b126bd6bSKiran Patil 	return 0;
2396b126bd6bSKiran Patil }
2397b126bd6bSKiran Patil 
2398b126bd6bSKiran Patil /**
2399b126bd6bSKiran Patil  * ice_sched_add_agg_cfg - create an aggregator node
2400b126bd6bSKiran Patil  * @pi: port information structure
2401b126bd6bSKiran Patil  * @agg_id: aggregator ID
2402b126bd6bSKiran Patil  * @tc: TC number
2403b126bd6bSKiran Patil  *
2404b126bd6bSKiran Patil  * This function creates an aggregator node and intermediate nodes if required
2405b126bd6bSKiran Patil  * for the given TC
2406b126bd6bSKiran Patil  */
2407b126bd6bSKiran Patil static enum ice_status
2408b126bd6bSKiran Patil ice_sched_add_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc)
2409b126bd6bSKiran Patil {
2410b126bd6bSKiran Patil 	struct ice_sched_node *parent, *agg_node, *tc_node;
2411b126bd6bSKiran Patil 	u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
2412b126bd6bSKiran Patil 	enum ice_status status = 0;
2413b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
2414b126bd6bSKiran Patil 	u32 first_node_teid;
2415b126bd6bSKiran Patil 	u16 num_nodes_added;
2416b126bd6bSKiran Patil 	u8 i, aggl;
2417b126bd6bSKiran Patil 
2418b126bd6bSKiran Patil 	tc_node = ice_sched_get_tc_node(pi, tc);
2419b126bd6bSKiran Patil 	if (!tc_node)
2420b126bd6bSKiran Patil 		return ICE_ERR_CFG;
2421b126bd6bSKiran Patil 
2422b126bd6bSKiran Patil 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
2423b126bd6bSKiran Patil 	/* Does Agg node already exist ? */
2424b126bd6bSKiran Patil 	if (agg_node)
2425b126bd6bSKiran Patil 		return status;
2426b126bd6bSKiran Patil 
2427b126bd6bSKiran Patil 	aggl = ice_sched_get_agg_layer(hw);
2428b126bd6bSKiran Patil 
2429b126bd6bSKiran Patil 	/* need one node in Agg layer */
2430b126bd6bSKiran Patil 	num_nodes[aggl] = 1;
2431b126bd6bSKiran Patil 
2432b126bd6bSKiran Patil 	/* Check whether the intermediate nodes have space to add the
2433b126bd6bSKiran Patil 	 * new aggregator. If they are full, then SW needs to allocate a new
2434b126bd6bSKiran Patil 	 * intermediate node on those layers
2435b126bd6bSKiran Patil 	 */
2436b126bd6bSKiran Patil 	for (i = hw->sw_entry_point_layer; i < aggl; i++) {
2437b126bd6bSKiran Patil 		parent = ice_sched_get_first_node(pi, tc_node, i);
2438b126bd6bSKiran Patil 
2439b126bd6bSKiran Patil 		/* scan all the siblings */
2440b126bd6bSKiran Patil 		while (parent) {
2441b126bd6bSKiran Patil 			if (parent->num_children < hw->max_children[i])
2442b126bd6bSKiran Patil 				break;
2443b126bd6bSKiran Patil 			parent = parent->sibling;
2444b126bd6bSKiran Patil 		}
2445b126bd6bSKiran Patil 
2446b126bd6bSKiran Patil 		/* all the nodes are full, reserve one for this layer */
2447b126bd6bSKiran Patil 		if (!parent)
2448b126bd6bSKiran Patil 			num_nodes[i]++;
2449b126bd6bSKiran Patil 	}
2450b126bd6bSKiran Patil 
2451b126bd6bSKiran Patil 	/* add the aggregator node */
2452b126bd6bSKiran Patil 	parent = tc_node;
2453b126bd6bSKiran Patil 	for (i = hw->sw_entry_point_layer; i <= aggl; i++) {
2454b126bd6bSKiran Patil 		if (!parent)
2455b126bd6bSKiran Patil 			return ICE_ERR_CFG;
2456b126bd6bSKiran Patil 
2457b126bd6bSKiran Patil 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
2458b126bd6bSKiran Patil 						      num_nodes[i],
2459b126bd6bSKiran Patil 						      &first_node_teid,
2460b126bd6bSKiran Patil 						      &num_nodes_added);
2461b126bd6bSKiran Patil 		if (status || num_nodes[i] != num_nodes_added)
2462b126bd6bSKiran Patil 			return ICE_ERR_CFG;
2463b126bd6bSKiran Patil 
2464b126bd6bSKiran Patil 		/* The newly added node can be a new parent for the next
2465b126bd6bSKiran Patil 		 * layer nodes
2466b126bd6bSKiran Patil 		 */
2467b126bd6bSKiran Patil 		if (num_nodes_added) {
2468b126bd6bSKiran Patil 			parent = ice_sched_find_node_by_teid(tc_node,
2469b126bd6bSKiran Patil 							     first_node_teid);
2470b126bd6bSKiran Patil 			/* register aggregator ID with the aggregator node */
2471b126bd6bSKiran Patil 			if (parent && i == aggl)
2472b126bd6bSKiran Patil 				parent->agg_id = agg_id;
2473b126bd6bSKiran Patil 		} else {
2474b126bd6bSKiran Patil 			parent = parent->children[0];
2475b126bd6bSKiran Patil 		}
2476b126bd6bSKiran Patil 	}
2477b126bd6bSKiran Patil 
2478b126bd6bSKiran Patil 	return 0;
2479b126bd6bSKiran Patil }
2480b126bd6bSKiran Patil 
2481b126bd6bSKiran Patil /**
2482b126bd6bSKiran Patil  * ice_sched_cfg_agg - configure aggregator node
2483b126bd6bSKiran Patil  * @pi: port information structure
2484b126bd6bSKiran Patil  * @agg_id: aggregator ID
2485b126bd6bSKiran Patil  * @agg_type: aggregator type queue, VSI, or aggregator group
2486b126bd6bSKiran Patil  * @tc_bitmap: bits TC bitmap
2487b126bd6bSKiran Patil  *
2488b126bd6bSKiran Patil  * It registers a unique aggregator node into scheduler services. It
2489b126bd6bSKiran Patil  * allows a user to register with a unique ID to track it's resources.
2490b126bd6bSKiran Patil  * The aggregator type determines if this is a queue group, VSI group
2491b126bd6bSKiran Patil  * or aggregator group. It then creates the aggregator node(s) for requested
2492b126bd6bSKiran Patil  * TC(s) or removes an existing aggregator node including its configuration
2493b126bd6bSKiran Patil  * if indicated via tc_bitmap. Call ice_rm_agg_cfg to release aggregator
2494b126bd6bSKiran Patil  * resources and remove aggregator ID.
2495b126bd6bSKiran Patil  * This function needs to be called with scheduler lock held.
2496b126bd6bSKiran Patil  */
2497b126bd6bSKiran Patil static enum ice_status
2498b126bd6bSKiran Patil ice_sched_cfg_agg(struct ice_port_info *pi, u32 agg_id,
2499b126bd6bSKiran Patil 		  enum ice_agg_type agg_type, unsigned long *tc_bitmap)
2500b126bd6bSKiran Patil {
2501b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2502b126bd6bSKiran Patil 	enum ice_status status = 0;
2503b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
2504b126bd6bSKiran Patil 	u8 tc;
2505b126bd6bSKiran Patil 
2506b126bd6bSKiran Patil 	agg_info = ice_get_agg_info(hw, agg_id);
2507b126bd6bSKiran Patil 	if (!agg_info) {
2508b126bd6bSKiran Patil 		/* Create new entry for new aggregator ID */
2509b126bd6bSKiran Patil 		agg_info = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*agg_info),
2510b126bd6bSKiran Patil 					GFP_KERNEL);
2511b126bd6bSKiran Patil 		if (!agg_info)
2512b126bd6bSKiran Patil 			return ICE_ERR_NO_MEMORY;
2513b126bd6bSKiran Patil 
2514b126bd6bSKiran Patil 		agg_info->agg_id = agg_id;
2515b126bd6bSKiran Patil 		agg_info->agg_type = agg_type;
2516b126bd6bSKiran Patil 		agg_info->tc_bitmap[0] = 0;
2517b126bd6bSKiran Patil 
2518b126bd6bSKiran Patil 		/* Initialize the aggregator VSI list head */
2519b126bd6bSKiran Patil 		INIT_LIST_HEAD(&agg_info->agg_vsi_list);
2520b126bd6bSKiran Patil 
2521b126bd6bSKiran Patil 		/* Add new entry in aggregator list */
2522b126bd6bSKiran Patil 		list_add(&agg_info->list_entry, &hw->agg_list);
2523b126bd6bSKiran Patil 	}
2524b126bd6bSKiran Patil 	/* Create aggregator node(s) for requested TC(s) */
2525b126bd6bSKiran Patil 	ice_for_each_traffic_class(tc) {
2526b126bd6bSKiran Patil 		if (!ice_is_tc_ena(*tc_bitmap, tc)) {
2527b126bd6bSKiran Patil 			/* Delete aggregator cfg TC if it exists previously */
2528b126bd6bSKiran Patil 			status = ice_rm_agg_cfg_tc(pi, agg_info, tc, false);
2529b126bd6bSKiran Patil 			if (status)
2530b126bd6bSKiran Patil 				break;
2531b126bd6bSKiran Patil 			continue;
2532b126bd6bSKiran Patil 		}
2533b126bd6bSKiran Patil 
2534b126bd6bSKiran Patil 		/* Check if aggregator node for TC already exists */
2535b126bd6bSKiran Patil 		if (ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
2536b126bd6bSKiran Patil 			continue;
2537b126bd6bSKiran Patil 
2538b126bd6bSKiran Patil 		/* Create new aggregator node for TC */
2539b126bd6bSKiran Patil 		status = ice_sched_add_agg_cfg(pi, agg_id, tc);
2540b126bd6bSKiran Patil 		if (status)
2541b126bd6bSKiran Patil 			break;
2542b126bd6bSKiran Patil 
2543b126bd6bSKiran Patil 		/* Save aggregator node's TC information */
2544b126bd6bSKiran Patil 		set_bit(tc, agg_info->tc_bitmap);
2545b126bd6bSKiran Patil 	}
2546b126bd6bSKiran Patil 
2547b126bd6bSKiran Patil 	return status;
2548b126bd6bSKiran Patil }
2549b126bd6bSKiran Patil 
2550b126bd6bSKiran Patil /**
2551b126bd6bSKiran Patil  * ice_cfg_agg - config aggregator node
2552b126bd6bSKiran Patil  * @pi: port information structure
2553b126bd6bSKiran Patil  * @agg_id: aggregator ID
2554b126bd6bSKiran Patil  * @agg_type: aggregator type queue, VSI, or aggregator group
2555b126bd6bSKiran Patil  * @tc_bitmap: bits TC bitmap
2556b126bd6bSKiran Patil  *
2557b126bd6bSKiran Patil  * This function configures aggregator node(s).
2558b126bd6bSKiran Patil  */
2559b126bd6bSKiran Patil enum ice_status
2560b126bd6bSKiran Patil ice_cfg_agg(struct ice_port_info *pi, u32 agg_id, enum ice_agg_type agg_type,
2561b126bd6bSKiran Patil 	    u8 tc_bitmap)
2562b126bd6bSKiran Patil {
2563b126bd6bSKiran Patil 	unsigned long bitmap = tc_bitmap;
2564b126bd6bSKiran Patil 	enum ice_status status;
2565b126bd6bSKiran Patil 
2566b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
2567b126bd6bSKiran Patil 	status = ice_sched_cfg_agg(pi, agg_id, agg_type,
2568b126bd6bSKiran Patil 				   (unsigned long *)&bitmap);
2569b126bd6bSKiran Patil 	if (!status)
2570b126bd6bSKiran Patil 		status = ice_save_agg_tc_bitmap(pi, agg_id,
2571b126bd6bSKiran Patil 						(unsigned long *)&bitmap);
2572b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
2573b126bd6bSKiran Patil 	return status;
2574b126bd6bSKiran Patil }
2575b126bd6bSKiran Patil 
2576b126bd6bSKiran Patil /**
2577b126bd6bSKiran Patil  * ice_get_agg_vsi_info - get the aggregator ID
2578b126bd6bSKiran Patil  * @agg_info: aggregator info
2579b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2580b126bd6bSKiran Patil  *
2581b126bd6bSKiran Patil  * The function returns aggregator VSI info based on VSI handle. This function
2582b126bd6bSKiran Patil  * needs to be called with scheduler lock held.
2583b126bd6bSKiran Patil  */
2584b126bd6bSKiran Patil static struct ice_sched_agg_vsi_info *
2585b126bd6bSKiran Patil ice_get_agg_vsi_info(struct ice_sched_agg_info *agg_info, u16 vsi_handle)
2586b126bd6bSKiran Patil {
2587b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *agg_vsi_info;
2588b126bd6bSKiran Patil 
2589b126bd6bSKiran Patil 	list_for_each_entry(agg_vsi_info, &agg_info->agg_vsi_list, list_entry)
2590b126bd6bSKiran Patil 		if (agg_vsi_info->vsi_handle == vsi_handle)
2591b126bd6bSKiran Patil 			return agg_vsi_info;
2592b126bd6bSKiran Patil 
2593b126bd6bSKiran Patil 	return NULL;
2594b126bd6bSKiran Patil }
2595b126bd6bSKiran Patil 
2596b126bd6bSKiran Patil /**
2597b126bd6bSKiran Patil  * ice_get_vsi_agg_info - get the aggregator info of VSI
2598b126bd6bSKiran Patil  * @hw: pointer to the hardware structure
2599b126bd6bSKiran Patil  * @vsi_handle: Sw VSI handle
2600b126bd6bSKiran Patil  *
2601b126bd6bSKiran Patil  * The function returns aggregator info of VSI represented via vsi_handle. The
2602b126bd6bSKiran Patil  * VSI has in this case a different aggregator than the default one. This
2603b126bd6bSKiran Patil  * function needs to be called with scheduler lock held.
2604b126bd6bSKiran Patil  */
2605b126bd6bSKiran Patil static struct ice_sched_agg_info *
2606b126bd6bSKiran Patil ice_get_vsi_agg_info(struct ice_hw *hw, u16 vsi_handle)
2607b126bd6bSKiran Patil {
2608b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2609b126bd6bSKiran Patil 
2610b126bd6bSKiran Patil 	list_for_each_entry(agg_info, &hw->agg_list, list_entry) {
2611b126bd6bSKiran Patil 		struct ice_sched_agg_vsi_info *agg_vsi_info;
2612b126bd6bSKiran Patil 
2613b126bd6bSKiran Patil 		agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
2614b126bd6bSKiran Patil 		if (agg_vsi_info)
2615b126bd6bSKiran Patil 			return agg_info;
2616b126bd6bSKiran Patil 	}
2617b126bd6bSKiran Patil 	return NULL;
2618b126bd6bSKiran Patil }
2619b126bd6bSKiran Patil 
2620b126bd6bSKiran Patil /**
2621b126bd6bSKiran Patil  * ice_save_agg_vsi_tc_bitmap - save aggregator VSI TC bitmap
2622b126bd6bSKiran Patil  * @pi: port information structure
2623b126bd6bSKiran Patil  * @agg_id: aggregator ID
2624b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2625b126bd6bSKiran Patil  * @tc_bitmap: TC bitmap of enabled TC(s)
2626b126bd6bSKiran Patil  *
2627b126bd6bSKiran Patil  * Save VSI to aggregator TC bitmap. This function needs to call with scheduler
2628b126bd6bSKiran Patil  * lock held.
2629b126bd6bSKiran Patil  */
2630b126bd6bSKiran Patil static enum ice_status
2631b126bd6bSKiran Patil ice_save_agg_vsi_tc_bitmap(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle,
2632b126bd6bSKiran Patil 			   unsigned long *tc_bitmap)
2633b126bd6bSKiran Patil {
2634b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *agg_vsi_info;
2635b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2636b126bd6bSKiran Patil 
2637b126bd6bSKiran Patil 	agg_info = ice_get_agg_info(pi->hw, agg_id);
2638b126bd6bSKiran Patil 	if (!agg_info)
2639b126bd6bSKiran Patil 		return ICE_ERR_PARAM;
2640b126bd6bSKiran Patil 	/* check if entry already exist */
2641b126bd6bSKiran Patil 	agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
2642b126bd6bSKiran Patil 	if (!agg_vsi_info)
2643b126bd6bSKiran Patil 		return ICE_ERR_PARAM;
2644b126bd6bSKiran Patil 	bitmap_copy(agg_vsi_info->replay_tc_bitmap, tc_bitmap,
2645b126bd6bSKiran Patil 		    ICE_MAX_TRAFFIC_CLASS);
2646b126bd6bSKiran Patil 	return 0;
2647b126bd6bSKiran Patil }
2648b126bd6bSKiran Patil 
2649b126bd6bSKiran Patil /**
2650b126bd6bSKiran Patil  * ice_sched_assoc_vsi_to_agg - associate/move VSI to new/default aggregator
2651b126bd6bSKiran Patil  * @pi: port information structure
2652b126bd6bSKiran Patil  * @agg_id: aggregator ID
2653b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2654b126bd6bSKiran Patil  * @tc_bitmap: TC bitmap of enabled TC(s)
2655b126bd6bSKiran Patil  *
2656b126bd6bSKiran Patil  * This function moves VSI to a new or default aggregator node. If VSI is
2657b126bd6bSKiran Patil  * already associated to the aggregator node then no operation is performed on
2658b126bd6bSKiran Patil  * the tree. This function needs to be called with scheduler lock held.
2659b126bd6bSKiran Patil  */
2660b126bd6bSKiran Patil static enum ice_status
2661b126bd6bSKiran Patil ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
2662b126bd6bSKiran Patil 			   u16 vsi_handle, unsigned long *tc_bitmap)
2663b126bd6bSKiran Patil {
2664b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *agg_vsi_info;
2665b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2666b126bd6bSKiran Patil 	enum ice_status status = 0;
2667b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
2668b126bd6bSKiran Patil 	u8 tc;
2669b126bd6bSKiran Patil 
2670b126bd6bSKiran Patil 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
2671b126bd6bSKiran Patil 		return ICE_ERR_PARAM;
2672b126bd6bSKiran Patil 	agg_info = ice_get_agg_info(hw, agg_id);
2673b126bd6bSKiran Patil 	if (!agg_info)
2674b126bd6bSKiran Patil 		return ICE_ERR_PARAM;
2675b126bd6bSKiran Patil 	/* check if entry already exist */
2676b126bd6bSKiran Patil 	agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
2677b126bd6bSKiran Patil 	if (!agg_vsi_info) {
2678b126bd6bSKiran Patil 		/* Create new entry for VSI under aggregator list */
2679b126bd6bSKiran Patil 		agg_vsi_info = devm_kzalloc(ice_hw_to_dev(hw),
2680b126bd6bSKiran Patil 					    sizeof(*agg_vsi_info), GFP_KERNEL);
2681b126bd6bSKiran Patil 		if (!agg_vsi_info)
2682b126bd6bSKiran Patil 			return ICE_ERR_PARAM;
2683b126bd6bSKiran Patil 
2684b126bd6bSKiran Patil 		/* add VSI ID into the aggregator list */
2685b126bd6bSKiran Patil 		agg_vsi_info->vsi_handle = vsi_handle;
2686b126bd6bSKiran Patil 		list_add(&agg_vsi_info->list_entry, &agg_info->agg_vsi_list);
2687b126bd6bSKiran Patil 	}
2688b126bd6bSKiran Patil 	/* Move VSI node to new aggregator node for requested TC(s) */
2689b126bd6bSKiran Patil 	ice_for_each_traffic_class(tc) {
2690b126bd6bSKiran Patil 		if (!ice_is_tc_ena(*tc_bitmap, tc))
2691b126bd6bSKiran Patil 			continue;
2692b126bd6bSKiran Patil 
2693b126bd6bSKiran Patil 		/* Move VSI to new aggregator */
2694b126bd6bSKiran Patil 		status = ice_sched_move_vsi_to_agg(pi, vsi_handle, agg_id, tc);
2695b126bd6bSKiran Patil 		if (status)
2696b126bd6bSKiran Patil 			break;
2697b126bd6bSKiran Patil 
2698b126bd6bSKiran Patil 		set_bit(tc, agg_vsi_info->tc_bitmap);
2699b126bd6bSKiran Patil 	}
2700b126bd6bSKiran Patil 	return status;
2701b126bd6bSKiran Patil }
2702b126bd6bSKiran Patil 
2703b126bd6bSKiran Patil /**
27041ddef455SUsha Ketineni  * ice_sched_rm_unused_rl_prof - remove unused RL profile
27051ddef455SUsha Ketineni  * @pi: port information structure
27061ddef455SUsha Ketineni  *
27071ddef455SUsha Ketineni  * This function removes unused rate limit profiles from the HW and
27081ddef455SUsha Ketineni  * SW DB. The caller needs to hold scheduler lock.
27091ddef455SUsha Ketineni  */
27101ddef455SUsha Ketineni static void ice_sched_rm_unused_rl_prof(struct ice_port_info *pi)
27111ddef455SUsha Ketineni {
27121ddef455SUsha Ketineni 	u16 ln;
27131ddef455SUsha Ketineni 
27141ddef455SUsha Ketineni 	for (ln = 0; ln < pi->hw->num_tx_sched_layers; ln++) {
27151ddef455SUsha Ketineni 		struct ice_aqc_rl_profile_info *rl_prof_elem;
27161ddef455SUsha Ketineni 		struct ice_aqc_rl_profile_info *rl_prof_tmp;
27171ddef455SUsha Ketineni 
27181ddef455SUsha Ketineni 		list_for_each_entry_safe(rl_prof_elem, rl_prof_tmp,
27191ddef455SUsha Ketineni 					 &pi->rl_prof_list[ln], list_entry) {
27201ddef455SUsha Ketineni 			if (!ice_sched_del_rl_profile(pi->hw, rl_prof_elem))
27219228d8b2SJacob Keller 				ice_debug(pi->hw, ICE_DBG_SCHED, "Removed rl profile\n");
27221ddef455SUsha Ketineni 		}
27231ddef455SUsha Ketineni 	}
27241ddef455SUsha Ketineni }
27251ddef455SUsha Ketineni 
27261ddef455SUsha Ketineni /**
27271ddef455SUsha Ketineni  * ice_sched_update_elem - update element
27281ddef455SUsha Ketineni  * @hw: pointer to the HW struct
27291ddef455SUsha Ketineni  * @node: pointer to node
27301ddef455SUsha Ketineni  * @info: node info to update
27311ddef455SUsha Ketineni  *
2732b3c38904SBruce Allan  * Update the HW DB, and local SW DB of node. Update the scheduling
27331ddef455SUsha Ketineni  * parameters of node from argument info data buffer (Info->data buf) and
27341ddef455SUsha Ketineni  * returns success or error on config sched element failure. The caller
27351ddef455SUsha Ketineni  * needs to hold scheduler lock.
27361ddef455SUsha Ketineni  */
27371ddef455SUsha Ketineni static enum ice_status
27381ddef455SUsha Ketineni ice_sched_update_elem(struct ice_hw *hw, struct ice_sched_node *node,
27391ddef455SUsha Ketineni 		      struct ice_aqc_txsched_elem_data *info)
27401ddef455SUsha Ketineni {
2741b3c38904SBruce Allan 	struct ice_aqc_txsched_elem_data buf;
27421ddef455SUsha Ketineni 	enum ice_status status;
27431ddef455SUsha Ketineni 	u16 elem_cfgd = 0;
27441ddef455SUsha Ketineni 	u16 num_elems = 1;
27451ddef455SUsha Ketineni 
2746b3c38904SBruce Allan 	buf = *info;
27471ddef455SUsha Ketineni 	/* Parent TEID is reserved field in this aq call */
2748b3c38904SBruce Allan 	buf.parent_teid = 0;
27491ddef455SUsha Ketineni 	/* Element type is reserved field in this aq call */
2750b3c38904SBruce Allan 	buf.data.elem_type = 0;
27511ddef455SUsha Ketineni 	/* Flags is reserved field in this aq call */
2752b3c38904SBruce Allan 	buf.data.flags = 0;
27531ddef455SUsha Ketineni 
27541ddef455SUsha Ketineni 	/* Update HW DB */
27551ddef455SUsha Ketineni 	/* Configure element node */
27561ddef455SUsha Ketineni 	status = ice_aq_cfg_sched_elems(hw, num_elems, &buf, sizeof(buf),
27571ddef455SUsha Ketineni 					&elem_cfgd, NULL);
27581ddef455SUsha Ketineni 	if (status || elem_cfgd != num_elems) {
27591ddef455SUsha Ketineni 		ice_debug(hw, ICE_DBG_SCHED, "Config sched elem error\n");
27601ddef455SUsha Ketineni 		return ICE_ERR_CFG;
27611ddef455SUsha Ketineni 	}
27621ddef455SUsha Ketineni 
27631ddef455SUsha Ketineni 	/* Config success case */
27641ddef455SUsha Ketineni 	/* Now update local SW DB */
27651ddef455SUsha Ketineni 	/* Only copy the data portion of info buffer */
27661ddef455SUsha Ketineni 	node->info.data = info->data;
27671ddef455SUsha Ketineni 	return status;
27681ddef455SUsha Ketineni }
27691ddef455SUsha Ketineni 
27701ddef455SUsha Ketineni /**
27711ddef455SUsha Ketineni  * ice_sched_cfg_node_bw_alloc - configure node BW weight/alloc params
27721ddef455SUsha Ketineni  * @hw: pointer to the HW struct
27731ddef455SUsha Ketineni  * @node: sched node to configure
27741ddef455SUsha Ketineni  * @rl_type: rate limit type CIR, EIR, or shared
27751ddef455SUsha Ketineni  * @bw_alloc: BW weight/allocation
27761ddef455SUsha Ketineni  *
27771ddef455SUsha Ketineni  * This function configures node element's BW allocation.
27781ddef455SUsha Ketineni  */
27791ddef455SUsha Ketineni static enum ice_status
27801ddef455SUsha Ketineni ice_sched_cfg_node_bw_alloc(struct ice_hw *hw, struct ice_sched_node *node,
278188865fc4SKarol Kolacinski 			    enum ice_rl_type rl_type, u16 bw_alloc)
27821ddef455SUsha Ketineni {
27831ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem_data buf;
27841ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem *data;
27851ddef455SUsha Ketineni 
27861ddef455SUsha Ketineni 	buf = node->info;
27871ddef455SUsha Ketineni 	data = &buf.data;
27881ddef455SUsha Ketineni 	if (rl_type == ICE_MIN_BW) {
27891ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_CIR;
27901ddef455SUsha Ketineni 		data->cir_bw.bw_alloc = cpu_to_le16(bw_alloc);
27911ddef455SUsha Ketineni 	} else if (rl_type == ICE_MAX_BW) {
27921ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
27931ddef455SUsha Ketineni 		data->eir_bw.bw_alloc = cpu_to_le16(bw_alloc);
27941ddef455SUsha Ketineni 	} else {
27951ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
27961ddef455SUsha Ketineni 	}
27971ddef455SUsha Ketineni 
27981ddef455SUsha Ketineni 	/* Configure element */
2799b126bd6bSKiran Patil 	return ice_sched_update_elem(hw, node, &buf);
2800b126bd6bSKiran Patil }
2801b126bd6bSKiran Patil 
2802b126bd6bSKiran Patil /**
2803b126bd6bSKiran Patil  * ice_move_vsi_to_agg - moves VSI to new or default aggregator
2804b126bd6bSKiran Patil  * @pi: port information structure
2805b126bd6bSKiran Patil  * @agg_id: aggregator ID
2806b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2807b126bd6bSKiran Patil  * @tc_bitmap: TC bitmap of enabled TC(s)
2808b126bd6bSKiran Patil  *
2809b126bd6bSKiran Patil  * Move or associate VSI to a new or default aggregator node.
2810b126bd6bSKiran Patil  */
2811b126bd6bSKiran Patil enum ice_status
2812b126bd6bSKiran Patil ice_move_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle,
2813b126bd6bSKiran Patil 		    u8 tc_bitmap)
2814b126bd6bSKiran Patil {
2815b126bd6bSKiran Patil 	unsigned long bitmap = tc_bitmap;
2816b126bd6bSKiran Patil 	enum ice_status status;
2817b126bd6bSKiran Patil 
2818b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
2819b126bd6bSKiran Patil 	status = ice_sched_assoc_vsi_to_agg(pi, agg_id, vsi_handle,
2820b126bd6bSKiran Patil 					    (unsigned long *)&bitmap);
2821b126bd6bSKiran Patil 	if (!status)
2822b126bd6bSKiran Patil 		status = ice_save_agg_vsi_tc_bitmap(pi, agg_id, vsi_handle,
2823b126bd6bSKiran Patil 						    (unsigned long *)&bitmap);
2824b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
28251ddef455SUsha Ketineni 	return status;
28261ddef455SUsha Ketineni }
28271ddef455SUsha Ketineni 
28281ddef455SUsha Ketineni /**
28291ddef455SUsha Ketineni  * ice_set_clear_cir_bw - set or clear CIR BW
28301ddef455SUsha Ketineni  * @bw_t_info: bandwidth type information structure
28311ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
28321ddef455SUsha Ketineni  *
28331ddef455SUsha Ketineni  * Save or clear CIR bandwidth (BW) in the passed param bw_t_info.
28341ddef455SUsha Ketineni  */
2835ebb462dcSBruce Allan static void ice_set_clear_cir_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
28361ddef455SUsha Ketineni {
28371ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW) {
28381ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap);
28391ddef455SUsha Ketineni 		bw_t_info->cir_bw.bw = 0;
28401ddef455SUsha Ketineni 	} else {
28411ddef455SUsha Ketineni 		/* Save type of BW information */
28421ddef455SUsha Ketineni 		set_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap);
28431ddef455SUsha Ketineni 		bw_t_info->cir_bw.bw = bw;
28441ddef455SUsha Ketineni 	}
28451ddef455SUsha Ketineni }
28461ddef455SUsha Ketineni 
28471ddef455SUsha Ketineni /**
28481ddef455SUsha Ketineni  * ice_set_clear_eir_bw - set or clear EIR BW
28491ddef455SUsha Ketineni  * @bw_t_info: bandwidth type information structure
28501ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
28511ddef455SUsha Ketineni  *
28521ddef455SUsha Ketineni  * Save or clear EIR bandwidth (BW) in the passed param bw_t_info.
28531ddef455SUsha Ketineni  */
2854ebb462dcSBruce Allan static void ice_set_clear_eir_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
28551ddef455SUsha Ketineni {
28561ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW) {
28571ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
28581ddef455SUsha Ketineni 		bw_t_info->eir_bw.bw = 0;
28591ddef455SUsha Ketineni 	} else {
28601ddef455SUsha Ketineni 		/* EIR BW and Shared BW profiles are mutually exclusive and
28611ddef455SUsha Ketineni 		 * hence only one of them may be set for any given element.
28621ddef455SUsha Ketineni 		 * First clear earlier saved shared BW information.
28631ddef455SUsha Ketineni 		 */
28641ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
28651ddef455SUsha Ketineni 		bw_t_info->shared_bw = 0;
28661ddef455SUsha Ketineni 		/* save EIR BW information */
28671ddef455SUsha Ketineni 		set_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
28681ddef455SUsha Ketineni 		bw_t_info->eir_bw.bw = bw;
28691ddef455SUsha Ketineni 	}
28701ddef455SUsha Ketineni }
28711ddef455SUsha Ketineni 
28721ddef455SUsha Ketineni /**
28731ddef455SUsha Ketineni  * ice_set_clear_shared_bw - set or clear shared BW
28741ddef455SUsha Ketineni  * @bw_t_info: bandwidth type information structure
28751ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
28761ddef455SUsha Ketineni  *
28771ddef455SUsha Ketineni  * Save or clear shared bandwidth (BW) in the passed param bw_t_info.
28781ddef455SUsha Ketineni  */
2879ebb462dcSBruce Allan static void ice_set_clear_shared_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
28801ddef455SUsha Ketineni {
28811ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW) {
28821ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
28831ddef455SUsha Ketineni 		bw_t_info->shared_bw = 0;
28841ddef455SUsha Ketineni 	} else {
28851ddef455SUsha Ketineni 		/* EIR BW and Shared BW profiles are mutually exclusive and
28861ddef455SUsha Ketineni 		 * hence only one of them may be set for any given element.
28871ddef455SUsha Ketineni 		 * First clear earlier saved EIR BW information.
28881ddef455SUsha Ketineni 		 */
28891ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
28901ddef455SUsha Ketineni 		bw_t_info->eir_bw.bw = 0;
28911ddef455SUsha Ketineni 		/* save shared BW information */
28921ddef455SUsha Ketineni 		set_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
28931ddef455SUsha Ketineni 		bw_t_info->shared_bw = bw;
28941ddef455SUsha Ketineni 	}
28951ddef455SUsha Ketineni }
28961ddef455SUsha Ketineni 
28971ddef455SUsha Ketineni /**
28981ddef455SUsha Ketineni  * ice_sched_calc_wakeup - calculate RL profile wakeup parameter
28994f8a1497SBen Shelton  * @hw: pointer to the HW struct
29001ddef455SUsha Ketineni  * @bw: bandwidth in Kbps
29011ddef455SUsha Ketineni  *
29021ddef455SUsha Ketineni  * This function calculates the wakeup parameter of RL profile.
29031ddef455SUsha Ketineni  */
29044f8a1497SBen Shelton static u16 ice_sched_calc_wakeup(struct ice_hw *hw, s32 bw)
29051ddef455SUsha Ketineni {
29061ddef455SUsha Ketineni 	s64 bytes_per_sec, wakeup_int, wakeup_a, wakeup_b, wakeup_f;
29071ddef455SUsha Ketineni 	s32 wakeup_f_int;
29081ddef455SUsha Ketineni 	u16 wakeup = 0;
29091ddef455SUsha Ketineni 
29101ddef455SUsha Ketineni 	/* Get the wakeup integer value */
29111ddef455SUsha Ketineni 	bytes_per_sec = div64_long(((s64)bw * 1000), BITS_PER_BYTE);
29124f8a1497SBen Shelton 	wakeup_int = div64_long(hw->psm_clk_freq, bytes_per_sec);
29131ddef455SUsha Ketineni 	if (wakeup_int > 63) {
29141ddef455SUsha Ketineni 		wakeup = (u16)((1 << 15) | wakeup_int);
29151ddef455SUsha Ketineni 	} else {
29161ddef455SUsha Ketineni 		/* Calculate fraction value up to 4 decimals
29171ddef455SUsha Ketineni 		 * Convert Integer value to a constant multiplier
29181ddef455SUsha Ketineni 		 */
29191ddef455SUsha Ketineni 		wakeup_b = (s64)ICE_RL_PROF_MULTIPLIER * wakeup_int;
29201ddef455SUsha Ketineni 		wakeup_a = div64_long((s64)ICE_RL_PROF_MULTIPLIER *
29214f8a1497SBen Shelton 					   hw->psm_clk_freq, bytes_per_sec);
29221ddef455SUsha Ketineni 
29231ddef455SUsha Ketineni 		/* Get Fraction value */
29241ddef455SUsha Ketineni 		wakeup_f = wakeup_a - wakeup_b;
29251ddef455SUsha Ketineni 
29261ddef455SUsha Ketineni 		/* Round up the Fractional value via Ceil(Fractional value) */
29271ddef455SUsha Ketineni 		if (wakeup_f > div64_long(ICE_RL_PROF_MULTIPLIER, 2))
29281ddef455SUsha Ketineni 			wakeup_f += 1;
29291ddef455SUsha Ketineni 
29301ddef455SUsha Ketineni 		wakeup_f_int = (s32)div64_long(wakeup_f * ICE_RL_PROF_FRACTION,
29311ddef455SUsha Ketineni 					       ICE_RL_PROF_MULTIPLIER);
29321ddef455SUsha Ketineni 		wakeup |= (u16)(wakeup_int << 9);
29331ddef455SUsha Ketineni 		wakeup |= (u16)(0x1ff & wakeup_f_int);
29341ddef455SUsha Ketineni 	}
29351ddef455SUsha Ketineni 
29361ddef455SUsha Ketineni 	return wakeup;
29371ddef455SUsha Ketineni }
29381ddef455SUsha Ketineni 
29391ddef455SUsha Ketineni /**
29401ddef455SUsha Ketineni  * ice_sched_bw_to_rl_profile - convert BW to profile parameters
29414f8a1497SBen Shelton  * @hw: pointer to the HW struct
29421ddef455SUsha Ketineni  * @bw: bandwidth in Kbps
29431ddef455SUsha Ketineni  * @profile: profile parameters to return
29441ddef455SUsha Ketineni  *
29451ddef455SUsha Ketineni  * This function converts the BW to profile structure format.
29461ddef455SUsha Ketineni  */
29471ddef455SUsha Ketineni static enum ice_status
29484f8a1497SBen Shelton ice_sched_bw_to_rl_profile(struct ice_hw *hw, u32 bw,
29494f8a1497SBen Shelton 			   struct ice_aqc_rl_profile_elem *profile)
29501ddef455SUsha Ketineni {
29511ddef455SUsha Ketineni 	enum ice_status status = ICE_ERR_PARAM;
29521ddef455SUsha Ketineni 	s64 bytes_per_sec, ts_rate, mv_tmp;
29531ddef455SUsha Ketineni 	bool found = false;
29541ddef455SUsha Ketineni 	s32 encode = 0;
29551ddef455SUsha Ketineni 	s64 mv = 0;
29561ddef455SUsha Ketineni 	s32 i;
29571ddef455SUsha Ketineni 
29581ddef455SUsha Ketineni 	/* Bw settings range is from 0.5Mb/sec to 100Gb/sec */
29591ddef455SUsha Ketineni 	if (bw < ICE_SCHED_MIN_BW || bw > ICE_SCHED_MAX_BW)
29601ddef455SUsha Ketineni 		return status;
29611ddef455SUsha Ketineni 
29621ddef455SUsha Ketineni 	/* Bytes per second from Kbps */
29631ddef455SUsha Ketineni 	bytes_per_sec = div64_long(((s64)bw * 1000), BITS_PER_BYTE);
29641ddef455SUsha Ketineni 
29651ddef455SUsha Ketineni 	/* encode is 6 bits but really useful are 5 bits */
29661ddef455SUsha Ketineni 	for (i = 0; i < 64; i++) {
29671ddef455SUsha Ketineni 		u64 pow_result = BIT_ULL(i);
29681ddef455SUsha Ketineni 
29694f8a1497SBen Shelton 		ts_rate = div64_long((s64)hw->psm_clk_freq,
29701ddef455SUsha Ketineni 				     pow_result * ICE_RL_PROF_TS_MULTIPLIER);
29711ddef455SUsha Ketineni 		if (ts_rate <= 0)
29721ddef455SUsha Ketineni 			continue;
29731ddef455SUsha Ketineni 
29741ddef455SUsha Ketineni 		/* Multiplier value */
29751ddef455SUsha Ketineni 		mv_tmp = div64_long(bytes_per_sec * ICE_RL_PROF_MULTIPLIER,
29761ddef455SUsha Ketineni 				    ts_rate);
29771ddef455SUsha Ketineni 
29781ddef455SUsha Ketineni 		/* Round to the nearest ICE_RL_PROF_MULTIPLIER */
29791ddef455SUsha Ketineni 		mv = round_up_64bit(mv_tmp, ICE_RL_PROF_MULTIPLIER);
29801ddef455SUsha Ketineni 
29811ddef455SUsha Ketineni 		/* First multiplier value greater than the given
29821ddef455SUsha Ketineni 		 * accuracy bytes
29831ddef455SUsha Ketineni 		 */
29841ddef455SUsha Ketineni 		if (mv > ICE_RL_PROF_ACCURACY_BYTES) {
29851ddef455SUsha Ketineni 			encode = i;
29861ddef455SUsha Ketineni 			found = true;
29871ddef455SUsha Ketineni 			break;
29881ddef455SUsha Ketineni 		}
29891ddef455SUsha Ketineni 	}
29901ddef455SUsha Ketineni 	if (found) {
29911ddef455SUsha Ketineni 		u16 wm;
29921ddef455SUsha Ketineni 
29934f8a1497SBen Shelton 		wm = ice_sched_calc_wakeup(hw, bw);
29941ddef455SUsha Ketineni 		profile->rl_multiply = cpu_to_le16(mv);
29951ddef455SUsha Ketineni 		profile->wake_up_calc = cpu_to_le16(wm);
29961ddef455SUsha Ketineni 		profile->rl_encode = cpu_to_le16(encode);
29971ddef455SUsha Ketineni 		status = 0;
29981ddef455SUsha Ketineni 	} else {
29991ddef455SUsha Ketineni 		status = ICE_ERR_DOES_NOT_EXIST;
30001ddef455SUsha Ketineni 	}
30011ddef455SUsha Ketineni 
30021ddef455SUsha Ketineni 	return status;
30031ddef455SUsha Ketineni }
30041ddef455SUsha Ketineni 
30051ddef455SUsha Ketineni /**
30061ddef455SUsha Ketineni  * ice_sched_add_rl_profile - add RL profile
30071ddef455SUsha Ketineni  * @pi: port information structure
30081ddef455SUsha Ketineni  * @rl_type: type of rate limit BW - min, max, or shared
30091ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
30101ddef455SUsha Ketineni  * @layer_num: specifies in which layer to create profile
30111ddef455SUsha Ketineni  *
30121ddef455SUsha Ketineni  * This function first checks the existing list for corresponding BW
30131ddef455SUsha Ketineni  * parameter. If it exists, it returns the associated profile otherwise
30141ddef455SUsha Ketineni  * it creates a new rate limit profile for requested BW, and adds it to
30151ddef455SUsha Ketineni  * the HW DB and local list. It returns the new profile or null on error.
30161ddef455SUsha Ketineni  * The caller needs to hold the scheduler lock.
30171ddef455SUsha Ketineni  */
30181ddef455SUsha Ketineni static struct ice_aqc_rl_profile_info *
30191ddef455SUsha Ketineni ice_sched_add_rl_profile(struct ice_port_info *pi,
30201ddef455SUsha Ketineni 			 enum ice_rl_type rl_type, u32 bw, u8 layer_num)
30211ddef455SUsha Ketineni {
30221ddef455SUsha Ketineni 	struct ice_aqc_rl_profile_info *rl_prof_elem;
30231ddef455SUsha Ketineni 	u16 profiles_added = 0, num_profiles = 1;
3024b3c38904SBruce Allan 	struct ice_aqc_rl_profile_elem *buf;
30251ddef455SUsha Ketineni 	enum ice_status status;
30261ddef455SUsha Ketineni 	struct ice_hw *hw;
30271ddef455SUsha Ketineni 	u8 profile_type;
30281ddef455SUsha Ketineni 
30291ddef455SUsha Ketineni 	if (layer_num >= ICE_AQC_TOPO_MAX_LEVEL_NUM)
30301ddef455SUsha Ketineni 		return NULL;
30311ddef455SUsha Ketineni 	switch (rl_type) {
30321ddef455SUsha Ketineni 	case ICE_MIN_BW:
30331ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR;
30341ddef455SUsha Ketineni 		break;
30351ddef455SUsha Ketineni 	case ICE_MAX_BW:
30361ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR;
30371ddef455SUsha Ketineni 		break;
30381ddef455SUsha Ketineni 	case ICE_SHARED_BW:
30391ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL;
30401ddef455SUsha Ketineni 		break;
30411ddef455SUsha Ketineni 	default:
30421ddef455SUsha Ketineni 		return NULL;
30431ddef455SUsha Ketineni 	}
30441ddef455SUsha Ketineni 
30451ddef455SUsha Ketineni 	if (!pi)
30461ddef455SUsha Ketineni 		return NULL;
30471ddef455SUsha Ketineni 	hw = pi->hw;
30481ddef455SUsha Ketineni 	list_for_each_entry(rl_prof_elem, &pi->rl_prof_list[layer_num],
30491ddef455SUsha Ketineni 			    list_entry)
3050b3b93d6cSTarun Singh 		if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) ==
3051b3b93d6cSTarun Singh 		    profile_type && rl_prof_elem->bw == bw)
30521ddef455SUsha Ketineni 			/* Return existing profile ID info */
30531ddef455SUsha Ketineni 			return rl_prof_elem;
30541ddef455SUsha Ketineni 
30551ddef455SUsha Ketineni 	/* Create new profile ID */
30561ddef455SUsha Ketineni 	rl_prof_elem = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rl_prof_elem),
30571ddef455SUsha Ketineni 				    GFP_KERNEL);
30581ddef455SUsha Ketineni 
30591ddef455SUsha Ketineni 	if (!rl_prof_elem)
30601ddef455SUsha Ketineni 		return NULL;
30611ddef455SUsha Ketineni 
30624f8a1497SBen Shelton 	status = ice_sched_bw_to_rl_profile(hw, bw, &rl_prof_elem->profile);
30631ddef455SUsha Ketineni 	if (status)
30641ddef455SUsha Ketineni 		goto exit_add_rl_prof;
30651ddef455SUsha Ketineni 
30661ddef455SUsha Ketineni 	rl_prof_elem->bw = bw;
30671ddef455SUsha Ketineni 	/* layer_num is zero relative, and fw expects level from 1 to 9 */
30681ddef455SUsha Ketineni 	rl_prof_elem->profile.level = layer_num + 1;
30691ddef455SUsha Ketineni 	rl_prof_elem->profile.flags = profile_type;
30701ddef455SUsha Ketineni 	rl_prof_elem->profile.max_burst_size = cpu_to_le16(hw->max_burst_size);
30711ddef455SUsha Ketineni 
30721ddef455SUsha Ketineni 	/* Create new entry in HW DB */
3073b3c38904SBruce Allan 	buf = &rl_prof_elem->profile;
30741ddef455SUsha Ketineni 	status = ice_aq_add_rl_profile(hw, num_profiles, buf, sizeof(*buf),
30751ddef455SUsha Ketineni 				       &profiles_added, NULL);
30761ddef455SUsha Ketineni 	if (status || profiles_added != num_profiles)
30771ddef455SUsha Ketineni 		goto exit_add_rl_prof;
30781ddef455SUsha Ketineni 
30791ddef455SUsha Ketineni 	/* Good entry - add in the list */
30801ddef455SUsha Ketineni 	rl_prof_elem->prof_id_ref = 0;
30811ddef455SUsha Ketineni 	list_add(&rl_prof_elem->list_entry, &pi->rl_prof_list[layer_num]);
30821ddef455SUsha Ketineni 	return rl_prof_elem;
30831ddef455SUsha Ketineni 
30841ddef455SUsha Ketineni exit_add_rl_prof:
30851ddef455SUsha Ketineni 	devm_kfree(ice_hw_to_dev(hw), rl_prof_elem);
30861ddef455SUsha Ketineni 	return NULL;
30871ddef455SUsha Ketineni }
30881ddef455SUsha Ketineni 
30891ddef455SUsha Ketineni /**
30901ddef455SUsha Ketineni  * ice_sched_cfg_node_bw_lmt - configure node sched params
30911ddef455SUsha Ketineni  * @hw: pointer to the HW struct
30921ddef455SUsha Ketineni  * @node: sched node to configure
30931ddef455SUsha Ketineni  * @rl_type: rate limit type CIR, EIR, or shared
30941ddef455SUsha Ketineni  * @rl_prof_id: rate limit profile ID
30951ddef455SUsha Ketineni  *
30961ddef455SUsha Ketineni  * This function configures node element's BW limit.
30971ddef455SUsha Ketineni  */
30981ddef455SUsha Ketineni static enum ice_status
30991ddef455SUsha Ketineni ice_sched_cfg_node_bw_lmt(struct ice_hw *hw, struct ice_sched_node *node,
31001ddef455SUsha Ketineni 			  enum ice_rl_type rl_type, u16 rl_prof_id)
31011ddef455SUsha Ketineni {
31021ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem_data buf;
31031ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem *data;
31041ddef455SUsha Ketineni 
31051ddef455SUsha Ketineni 	buf = node->info;
31061ddef455SUsha Ketineni 	data = &buf.data;
31071ddef455SUsha Ketineni 	switch (rl_type) {
31081ddef455SUsha Ketineni 	case ICE_MIN_BW:
31091ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_CIR;
31101ddef455SUsha Ketineni 		data->cir_bw.bw_profile_idx = cpu_to_le16(rl_prof_id);
31111ddef455SUsha Ketineni 		break;
31121ddef455SUsha Ketineni 	case ICE_MAX_BW:
31131ddef455SUsha Ketineni 		/* EIR BW and Shared BW profiles are mutually exclusive and
31141ddef455SUsha Ketineni 		 * hence only one of them may be set for any given element
31151ddef455SUsha Ketineni 		 */
31161ddef455SUsha Ketineni 		if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED)
31171ddef455SUsha Ketineni 			return ICE_ERR_CFG;
31181ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
31191ddef455SUsha Ketineni 		data->eir_bw.bw_profile_idx = cpu_to_le16(rl_prof_id);
31201ddef455SUsha Ketineni 		break;
31211ddef455SUsha Ketineni 	case ICE_SHARED_BW:
31221ddef455SUsha Ketineni 		/* Check for removing shared BW */
31231ddef455SUsha Ketineni 		if (rl_prof_id == ICE_SCHED_NO_SHARED_RL_PROF_ID) {
31241ddef455SUsha Ketineni 			/* remove shared profile */
31251ddef455SUsha Ketineni 			data->valid_sections &= ~ICE_AQC_ELEM_VALID_SHARED;
31261ddef455SUsha Ketineni 			data->srl_id = 0; /* clear SRL field */
31271ddef455SUsha Ketineni 
31281ddef455SUsha Ketineni 			/* enable back EIR to default profile */
31291ddef455SUsha Ketineni 			data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
31301ddef455SUsha Ketineni 			data->eir_bw.bw_profile_idx =
31311ddef455SUsha Ketineni 				cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
31321ddef455SUsha Ketineni 			break;
31331ddef455SUsha Ketineni 		}
31341ddef455SUsha Ketineni 		/* EIR BW and Shared BW profiles are mutually exclusive and
31351ddef455SUsha Ketineni 		 * hence only one of them may be set for any given element
31361ddef455SUsha Ketineni 		 */
31371ddef455SUsha Ketineni 		if ((data->valid_sections & ICE_AQC_ELEM_VALID_EIR) &&
31381ddef455SUsha Ketineni 		    (le16_to_cpu(data->eir_bw.bw_profile_idx) !=
31391ddef455SUsha Ketineni 			    ICE_SCHED_DFLT_RL_PROF_ID))
31401ddef455SUsha Ketineni 			return ICE_ERR_CFG;
31411ddef455SUsha Ketineni 		/* EIR BW is set to default, disable it */
31421ddef455SUsha Ketineni 		data->valid_sections &= ~ICE_AQC_ELEM_VALID_EIR;
31431ddef455SUsha Ketineni 		/* Okay to enable shared BW now */
31441ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_SHARED;
31451ddef455SUsha Ketineni 		data->srl_id = cpu_to_le16(rl_prof_id);
31461ddef455SUsha Ketineni 		break;
31471ddef455SUsha Ketineni 	default:
31481ddef455SUsha Ketineni 		/* Unknown rate limit type */
31491ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
31501ddef455SUsha Ketineni 	}
31511ddef455SUsha Ketineni 
31521ddef455SUsha Ketineni 	/* Configure element */
31531ddef455SUsha Ketineni 	return ice_sched_update_elem(hw, node, &buf);
31541ddef455SUsha Ketineni }
31551ddef455SUsha Ketineni 
31561ddef455SUsha Ketineni /**
31571ddef455SUsha Ketineni  * ice_sched_get_node_rl_prof_id - get node's rate limit profile ID
31581ddef455SUsha Ketineni  * @node: sched node
31591ddef455SUsha Ketineni  * @rl_type: rate limit type
31601ddef455SUsha Ketineni  *
31611ddef455SUsha Ketineni  * If existing profile matches, it returns the corresponding rate
31621ddef455SUsha Ketineni  * limit profile ID, otherwise it returns an invalid ID as error.
31631ddef455SUsha Ketineni  */
31641ddef455SUsha Ketineni static u16
31651ddef455SUsha Ketineni ice_sched_get_node_rl_prof_id(struct ice_sched_node *node,
31661ddef455SUsha Ketineni 			      enum ice_rl_type rl_type)
31671ddef455SUsha Ketineni {
31681ddef455SUsha Ketineni 	u16 rl_prof_id = ICE_SCHED_INVAL_PROF_ID;
31691ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem *data;
31701ddef455SUsha Ketineni 
31711ddef455SUsha Ketineni 	data = &node->info.data;
31721ddef455SUsha Ketineni 	switch (rl_type) {
31731ddef455SUsha Ketineni 	case ICE_MIN_BW:
31741ddef455SUsha Ketineni 		if (data->valid_sections & ICE_AQC_ELEM_VALID_CIR)
31751ddef455SUsha Ketineni 			rl_prof_id = le16_to_cpu(data->cir_bw.bw_profile_idx);
31761ddef455SUsha Ketineni 		break;
31771ddef455SUsha Ketineni 	case ICE_MAX_BW:
31781ddef455SUsha Ketineni 		if (data->valid_sections & ICE_AQC_ELEM_VALID_EIR)
31791ddef455SUsha Ketineni 			rl_prof_id = le16_to_cpu(data->eir_bw.bw_profile_idx);
31801ddef455SUsha Ketineni 		break;
31811ddef455SUsha Ketineni 	case ICE_SHARED_BW:
31821ddef455SUsha Ketineni 		if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED)
31831ddef455SUsha Ketineni 			rl_prof_id = le16_to_cpu(data->srl_id);
31841ddef455SUsha Ketineni 		break;
31851ddef455SUsha Ketineni 	default:
31861ddef455SUsha Ketineni 		break;
31871ddef455SUsha Ketineni 	}
31881ddef455SUsha Ketineni 
31891ddef455SUsha Ketineni 	return rl_prof_id;
31901ddef455SUsha Ketineni }
31911ddef455SUsha Ketineni 
31921ddef455SUsha Ketineni /**
31931ddef455SUsha Ketineni  * ice_sched_get_rl_prof_layer - selects rate limit profile creation layer
31941ddef455SUsha Ketineni  * @pi: port information structure
31951ddef455SUsha Ketineni  * @rl_type: type of rate limit BW - min, max, or shared
31961ddef455SUsha Ketineni  * @layer_index: layer index
31971ddef455SUsha Ketineni  *
31981ddef455SUsha Ketineni  * This function returns requested profile creation layer.
31991ddef455SUsha Ketineni  */
32001ddef455SUsha Ketineni static u8
32011ddef455SUsha Ketineni ice_sched_get_rl_prof_layer(struct ice_port_info *pi, enum ice_rl_type rl_type,
32021ddef455SUsha Ketineni 			    u8 layer_index)
32031ddef455SUsha Ketineni {
32041ddef455SUsha Ketineni 	struct ice_hw *hw = pi->hw;
32051ddef455SUsha Ketineni 
32061ddef455SUsha Ketineni 	if (layer_index >= hw->num_tx_sched_layers)
32071ddef455SUsha Ketineni 		return ICE_SCHED_INVAL_LAYER_NUM;
32081ddef455SUsha Ketineni 	switch (rl_type) {
32091ddef455SUsha Ketineni 	case ICE_MIN_BW:
32101ddef455SUsha Ketineni 		if (hw->layer_info[layer_index].max_cir_rl_profiles)
32111ddef455SUsha Ketineni 			return layer_index;
32121ddef455SUsha Ketineni 		break;
32131ddef455SUsha Ketineni 	case ICE_MAX_BW:
32141ddef455SUsha Ketineni 		if (hw->layer_info[layer_index].max_eir_rl_profiles)
32151ddef455SUsha Ketineni 			return layer_index;
32161ddef455SUsha Ketineni 		break;
32171ddef455SUsha Ketineni 	case ICE_SHARED_BW:
32181ddef455SUsha Ketineni 		/* if current layer doesn't support SRL profile creation
32191ddef455SUsha Ketineni 		 * then try a layer up or down.
32201ddef455SUsha Ketineni 		 */
32211ddef455SUsha Ketineni 		if (hw->layer_info[layer_index].max_srl_profiles)
32221ddef455SUsha Ketineni 			return layer_index;
32231ddef455SUsha Ketineni 		else if (layer_index < hw->num_tx_sched_layers - 1 &&
32241ddef455SUsha Ketineni 			 hw->layer_info[layer_index + 1].max_srl_profiles)
32251ddef455SUsha Ketineni 			return layer_index + 1;
32261ddef455SUsha Ketineni 		else if (layer_index > 0 &&
32271ddef455SUsha Ketineni 			 hw->layer_info[layer_index - 1].max_srl_profiles)
32281ddef455SUsha Ketineni 			return layer_index - 1;
32291ddef455SUsha Ketineni 		break;
32301ddef455SUsha Ketineni 	default:
32311ddef455SUsha Ketineni 		break;
32321ddef455SUsha Ketineni 	}
32331ddef455SUsha Ketineni 	return ICE_SCHED_INVAL_LAYER_NUM;
32341ddef455SUsha Ketineni }
32351ddef455SUsha Ketineni 
32361ddef455SUsha Ketineni /**
32371ddef455SUsha Ketineni  * ice_sched_get_srl_node - get shared rate limit node
32381ddef455SUsha Ketineni  * @node: tree node
32391ddef455SUsha Ketineni  * @srl_layer: shared rate limit layer
32401ddef455SUsha Ketineni  *
32411ddef455SUsha Ketineni  * This function returns SRL node to be used for shared rate limit purpose.
32421ddef455SUsha Ketineni  * The caller needs to hold scheduler lock.
32431ddef455SUsha Ketineni  */
32441ddef455SUsha Ketineni static struct ice_sched_node *
32451ddef455SUsha Ketineni ice_sched_get_srl_node(struct ice_sched_node *node, u8 srl_layer)
32461ddef455SUsha Ketineni {
32471ddef455SUsha Ketineni 	if (srl_layer > node->tx_sched_layer)
32481ddef455SUsha Ketineni 		return node->children[0];
32491ddef455SUsha Ketineni 	else if (srl_layer < node->tx_sched_layer)
32501ddef455SUsha Ketineni 		/* Node can't be created without a parent. It will always
32511ddef455SUsha Ketineni 		 * have a valid parent except root node.
32521ddef455SUsha Ketineni 		 */
32531ddef455SUsha Ketineni 		return node->parent;
32541ddef455SUsha Ketineni 	else
32551ddef455SUsha Ketineni 		return node;
32561ddef455SUsha Ketineni }
32571ddef455SUsha Ketineni 
32581ddef455SUsha Ketineni /**
32591ddef455SUsha Ketineni  * ice_sched_rm_rl_profile - remove RL profile ID
32601ddef455SUsha Ketineni  * @pi: port information structure
32611ddef455SUsha Ketineni  * @layer_num: layer number where profiles are saved
32621ddef455SUsha Ketineni  * @profile_type: profile type like EIR, CIR, or SRL
32631ddef455SUsha Ketineni  * @profile_id: profile ID to remove
32641ddef455SUsha Ketineni  *
32651ddef455SUsha Ketineni  * This function removes rate limit profile from layer 'layer_num' of type
32661ddef455SUsha Ketineni  * 'profile_type' and profile ID as 'profile_id'. The caller needs to hold
32671ddef455SUsha Ketineni  * scheduler lock.
32681ddef455SUsha Ketineni  */
32691ddef455SUsha Ketineni static enum ice_status
32701ddef455SUsha Ketineni ice_sched_rm_rl_profile(struct ice_port_info *pi, u8 layer_num, u8 profile_type,
32711ddef455SUsha Ketineni 			u16 profile_id)
32721ddef455SUsha Ketineni {
32731ddef455SUsha Ketineni 	struct ice_aqc_rl_profile_info *rl_prof_elem;
32741ddef455SUsha Ketineni 	enum ice_status status = 0;
32751ddef455SUsha Ketineni 
32761ddef455SUsha Ketineni 	if (layer_num >= ICE_AQC_TOPO_MAX_LEVEL_NUM)
32771ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
32781ddef455SUsha Ketineni 	/* Check the existing list for RL profile */
32791ddef455SUsha Ketineni 	list_for_each_entry(rl_prof_elem, &pi->rl_prof_list[layer_num],
32801ddef455SUsha Ketineni 			    list_entry)
3281b3b93d6cSTarun Singh 		if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) ==
3282b3b93d6cSTarun Singh 		    profile_type &&
32831ddef455SUsha Ketineni 		    le16_to_cpu(rl_prof_elem->profile.profile_id) ==
32841ddef455SUsha Ketineni 		    profile_id) {
32851ddef455SUsha Ketineni 			if (rl_prof_elem->prof_id_ref)
32861ddef455SUsha Ketineni 				rl_prof_elem->prof_id_ref--;
32871ddef455SUsha Ketineni 
32881ddef455SUsha Ketineni 			/* Remove old profile ID from database */
32891ddef455SUsha Ketineni 			status = ice_sched_del_rl_profile(pi->hw, rl_prof_elem);
32901ddef455SUsha Ketineni 			if (status && status != ICE_ERR_IN_USE)
32919228d8b2SJacob Keller 				ice_debug(pi->hw, ICE_DBG_SCHED, "Remove rl profile failed\n");
32921ddef455SUsha Ketineni 			break;
32931ddef455SUsha Ketineni 		}
32941ddef455SUsha Ketineni 	if (status == ICE_ERR_IN_USE)
32951ddef455SUsha Ketineni 		status = 0;
32961ddef455SUsha Ketineni 	return status;
32971ddef455SUsha Ketineni }
32981ddef455SUsha Ketineni 
32991ddef455SUsha Ketineni /**
33001ddef455SUsha Ketineni  * ice_sched_set_node_bw_dflt - set node's bandwidth limit to default
33011ddef455SUsha Ketineni  * @pi: port information structure
33021ddef455SUsha Ketineni  * @node: pointer to node structure
33031ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
33041ddef455SUsha Ketineni  * @layer_num: layer number where RL profiles are saved
33051ddef455SUsha Ketineni  *
33061ddef455SUsha Ketineni  * This function configures node element's BW rate limit profile ID of
33071ddef455SUsha Ketineni  * type CIR, EIR, or SRL to default. This function needs to be called
33081ddef455SUsha Ketineni  * with the scheduler lock held.
33091ddef455SUsha Ketineni  */
33101ddef455SUsha Ketineni static enum ice_status
33111ddef455SUsha Ketineni ice_sched_set_node_bw_dflt(struct ice_port_info *pi,
33121ddef455SUsha Ketineni 			   struct ice_sched_node *node,
33131ddef455SUsha Ketineni 			   enum ice_rl_type rl_type, u8 layer_num)
33141ddef455SUsha Ketineni {
33151ddef455SUsha Ketineni 	enum ice_status status;
33161ddef455SUsha Ketineni 	struct ice_hw *hw;
33171ddef455SUsha Ketineni 	u8 profile_type;
33181ddef455SUsha Ketineni 	u16 rl_prof_id;
33191ddef455SUsha Ketineni 	u16 old_id;
33201ddef455SUsha Ketineni 
33211ddef455SUsha Ketineni 	hw = pi->hw;
33221ddef455SUsha Ketineni 	switch (rl_type) {
33231ddef455SUsha Ketineni 	case ICE_MIN_BW:
33241ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR;
33251ddef455SUsha Ketineni 		rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID;
33261ddef455SUsha Ketineni 		break;
33271ddef455SUsha Ketineni 	case ICE_MAX_BW:
33281ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR;
33291ddef455SUsha Ketineni 		rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID;
33301ddef455SUsha Ketineni 		break;
33311ddef455SUsha Ketineni 	case ICE_SHARED_BW:
33321ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL;
33331ddef455SUsha Ketineni 		/* No SRL is configured for default case */
33341ddef455SUsha Ketineni 		rl_prof_id = ICE_SCHED_NO_SHARED_RL_PROF_ID;
33351ddef455SUsha Ketineni 		break;
33361ddef455SUsha Ketineni 	default:
33371ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
33381ddef455SUsha Ketineni 	}
33391ddef455SUsha Ketineni 	/* Save existing RL prof ID for later clean up */
33401ddef455SUsha Ketineni 	old_id = ice_sched_get_node_rl_prof_id(node, rl_type);
33411ddef455SUsha Ketineni 	/* Configure BW scheduling parameters */
33421ddef455SUsha Ketineni 	status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id);
33431ddef455SUsha Ketineni 	if (status)
33441ddef455SUsha Ketineni 		return status;
33451ddef455SUsha Ketineni 
33461ddef455SUsha Ketineni 	/* Remove stale RL profile ID */
33471ddef455SUsha Ketineni 	if (old_id == ICE_SCHED_DFLT_RL_PROF_ID ||
33481ddef455SUsha Ketineni 	    old_id == ICE_SCHED_INVAL_PROF_ID)
33491ddef455SUsha Ketineni 		return 0;
33501ddef455SUsha Ketineni 
33511ddef455SUsha Ketineni 	return ice_sched_rm_rl_profile(pi, layer_num, profile_type, old_id);
33521ddef455SUsha Ketineni }
33531ddef455SUsha Ketineni 
33541ddef455SUsha Ketineni /**
33551ddef455SUsha Ketineni  * ice_sched_set_eir_srl_excl - set EIR/SRL exclusiveness
33561ddef455SUsha Ketineni  * @pi: port information structure
33571ddef455SUsha Ketineni  * @node: pointer to node structure
33581ddef455SUsha Ketineni  * @layer_num: layer number where rate limit profiles are saved
33591ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
33601ddef455SUsha Ketineni  * @bw: bandwidth value
33611ddef455SUsha Ketineni  *
33621ddef455SUsha Ketineni  * This function prepares node element's bandwidth to SRL or EIR exclusively.
33631ddef455SUsha Ketineni  * EIR BW and Shared BW profiles are mutually exclusive and hence only one of
33641ddef455SUsha Ketineni  * them may be set for any given element. This function needs to be called
33651ddef455SUsha Ketineni  * with the scheduler lock held.
33661ddef455SUsha Ketineni  */
33671ddef455SUsha Ketineni static enum ice_status
33681ddef455SUsha Ketineni ice_sched_set_eir_srl_excl(struct ice_port_info *pi,
33691ddef455SUsha Ketineni 			   struct ice_sched_node *node,
33701ddef455SUsha Ketineni 			   u8 layer_num, enum ice_rl_type rl_type, u32 bw)
33711ddef455SUsha Ketineni {
33721ddef455SUsha Ketineni 	if (rl_type == ICE_SHARED_BW) {
33731ddef455SUsha Ketineni 		/* SRL node passed in this case, it may be different node */
33741ddef455SUsha Ketineni 		if (bw == ICE_SCHED_DFLT_BW)
33751ddef455SUsha Ketineni 			/* SRL being removed, ice_sched_cfg_node_bw_lmt()
33761ddef455SUsha Ketineni 			 * enables EIR to default. EIR is not set in this
33771ddef455SUsha Ketineni 			 * case, so no additional action is required.
33781ddef455SUsha Ketineni 			 */
33791ddef455SUsha Ketineni 			return 0;
33801ddef455SUsha Ketineni 
33811ddef455SUsha Ketineni 		/* SRL being configured, set EIR to default here.
33821ddef455SUsha Ketineni 		 * ice_sched_cfg_node_bw_lmt() disables EIR when it
33831ddef455SUsha Ketineni 		 * configures SRL
33841ddef455SUsha Ketineni 		 */
33851ddef455SUsha Ketineni 		return ice_sched_set_node_bw_dflt(pi, node, ICE_MAX_BW,
33861ddef455SUsha Ketineni 						  layer_num);
33871ddef455SUsha Ketineni 	} else if (rl_type == ICE_MAX_BW &&
33881ddef455SUsha Ketineni 		   node->info.data.valid_sections & ICE_AQC_ELEM_VALID_SHARED) {
33891ddef455SUsha Ketineni 		/* Remove Shared profile. Set default shared BW call
33901ddef455SUsha Ketineni 		 * removes shared profile for a node.
33911ddef455SUsha Ketineni 		 */
33921ddef455SUsha Ketineni 		return ice_sched_set_node_bw_dflt(pi, node,
33931ddef455SUsha Ketineni 						  ICE_SHARED_BW,
33941ddef455SUsha Ketineni 						  layer_num);
33951ddef455SUsha Ketineni 	}
33961ddef455SUsha Ketineni 	return 0;
33971ddef455SUsha Ketineni }
33981ddef455SUsha Ketineni 
33991ddef455SUsha Ketineni /**
34001ddef455SUsha Ketineni  * ice_sched_set_node_bw - set node's bandwidth
34011ddef455SUsha Ketineni  * @pi: port information structure
34021ddef455SUsha Ketineni  * @node: tree node
34031ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
34041ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
34051ddef455SUsha Ketineni  * @layer_num: layer number
34061ddef455SUsha Ketineni  *
34071ddef455SUsha Ketineni  * This function adds new profile corresponding to requested BW, configures
34081ddef455SUsha Ketineni  * node's RL profile ID of type CIR, EIR, or SRL, and removes old profile
34091ddef455SUsha Ketineni  * ID from local database. The caller needs to hold scheduler lock.
34101ddef455SUsha Ketineni  */
34111ddef455SUsha Ketineni static enum ice_status
34121ddef455SUsha Ketineni ice_sched_set_node_bw(struct ice_port_info *pi, struct ice_sched_node *node,
34131ddef455SUsha Ketineni 		      enum ice_rl_type rl_type, u32 bw, u8 layer_num)
34141ddef455SUsha Ketineni {
34151ddef455SUsha Ketineni 	struct ice_aqc_rl_profile_info *rl_prof_info;
34161ddef455SUsha Ketineni 	enum ice_status status = ICE_ERR_PARAM;
34171ddef455SUsha Ketineni 	struct ice_hw *hw = pi->hw;
34181ddef455SUsha Ketineni 	u16 old_id, rl_prof_id;
34191ddef455SUsha Ketineni 
34201ddef455SUsha Ketineni 	rl_prof_info = ice_sched_add_rl_profile(pi, rl_type, bw, layer_num);
34211ddef455SUsha Ketineni 	if (!rl_prof_info)
34221ddef455SUsha Ketineni 		return status;
34231ddef455SUsha Ketineni 
34241ddef455SUsha Ketineni 	rl_prof_id = le16_to_cpu(rl_prof_info->profile.profile_id);
34251ddef455SUsha Ketineni 
34261ddef455SUsha Ketineni 	/* Save existing RL prof ID for later clean up */
34271ddef455SUsha Ketineni 	old_id = ice_sched_get_node_rl_prof_id(node, rl_type);
34281ddef455SUsha Ketineni 	/* Configure BW scheduling parameters */
34291ddef455SUsha Ketineni 	status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id);
34301ddef455SUsha Ketineni 	if (status)
34311ddef455SUsha Ketineni 		return status;
34321ddef455SUsha Ketineni 
34331ddef455SUsha Ketineni 	/* New changes has been applied */
34341ddef455SUsha Ketineni 	/* Increment the profile ID reference count */
34351ddef455SUsha Ketineni 	rl_prof_info->prof_id_ref++;
34361ddef455SUsha Ketineni 
34371ddef455SUsha Ketineni 	/* Check for old ID removal */
34381ddef455SUsha Ketineni 	if ((old_id == ICE_SCHED_DFLT_RL_PROF_ID && rl_type != ICE_SHARED_BW) ||
34391ddef455SUsha Ketineni 	    old_id == ICE_SCHED_INVAL_PROF_ID || old_id == rl_prof_id)
34401ddef455SUsha Ketineni 		return 0;
34411ddef455SUsha Ketineni 
34421ddef455SUsha Ketineni 	return ice_sched_rm_rl_profile(pi, layer_num,
3443b3b93d6cSTarun Singh 				       rl_prof_info->profile.flags &
3444b3b93d6cSTarun Singh 				       ICE_AQC_RL_PROFILE_TYPE_M, old_id);
34451ddef455SUsha Ketineni }
34461ddef455SUsha Ketineni 
34471ddef455SUsha Ketineni /**
34481ddef455SUsha Ketineni  * ice_sched_set_node_bw_lmt - set node's BW limit
34491ddef455SUsha Ketineni  * @pi: port information structure
34501ddef455SUsha Ketineni  * @node: tree node
34511ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
34521ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
34531ddef455SUsha Ketineni  *
34541ddef455SUsha Ketineni  * It updates node's BW limit parameters like BW RL profile ID of type CIR,
34551ddef455SUsha Ketineni  * EIR, or SRL. The caller needs to hold scheduler lock.
34561ddef455SUsha Ketineni  */
34571ddef455SUsha Ketineni static enum ice_status
34581ddef455SUsha Ketineni ice_sched_set_node_bw_lmt(struct ice_port_info *pi, struct ice_sched_node *node,
34591ddef455SUsha Ketineni 			  enum ice_rl_type rl_type, u32 bw)
34601ddef455SUsha Ketineni {
34611ddef455SUsha Ketineni 	struct ice_sched_node *cfg_node = node;
34621ddef455SUsha Ketineni 	enum ice_status status;
34631ddef455SUsha Ketineni 
34641ddef455SUsha Ketineni 	struct ice_hw *hw;
34651ddef455SUsha Ketineni 	u8 layer_num;
34661ddef455SUsha Ketineni 
34671ddef455SUsha Ketineni 	if (!pi)
34681ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
34691ddef455SUsha Ketineni 	hw = pi->hw;
34701ddef455SUsha Ketineni 	/* Remove unused RL profile IDs from HW and SW DB */
34711ddef455SUsha Ketineni 	ice_sched_rm_unused_rl_prof(pi);
34721ddef455SUsha Ketineni 	layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
34731ddef455SUsha Ketineni 						node->tx_sched_layer);
34741ddef455SUsha Ketineni 	if (layer_num >= hw->num_tx_sched_layers)
34751ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
34761ddef455SUsha Ketineni 
34771ddef455SUsha Ketineni 	if (rl_type == ICE_SHARED_BW) {
34781ddef455SUsha Ketineni 		/* SRL node may be different */
34791ddef455SUsha Ketineni 		cfg_node = ice_sched_get_srl_node(node, layer_num);
34801ddef455SUsha Ketineni 		if (!cfg_node)
34811ddef455SUsha Ketineni 			return ICE_ERR_CFG;
34821ddef455SUsha Ketineni 	}
34831ddef455SUsha Ketineni 	/* EIR BW and Shared BW profiles are mutually exclusive and
34841ddef455SUsha Ketineni 	 * hence only one of them may be set for any given element
34851ddef455SUsha Ketineni 	 */
34861ddef455SUsha Ketineni 	status = ice_sched_set_eir_srl_excl(pi, cfg_node, layer_num, rl_type,
34871ddef455SUsha Ketineni 					    bw);
34881ddef455SUsha Ketineni 	if (status)
34891ddef455SUsha Ketineni 		return status;
34901ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW)
34911ddef455SUsha Ketineni 		return ice_sched_set_node_bw_dflt(pi, cfg_node, rl_type,
34921ddef455SUsha Ketineni 						  layer_num);
34931ddef455SUsha Ketineni 	return ice_sched_set_node_bw(pi, cfg_node, rl_type, bw, layer_num);
34941ddef455SUsha Ketineni }
34951ddef455SUsha Ketineni 
34961ddef455SUsha Ketineni /**
34971ddef455SUsha Ketineni  * ice_sched_set_node_bw_dflt_lmt - set node's BW limit to default
34981ddef455SUsha Ketineni  * @pi: port information structure
34991ddef455SUsha Ketineni  * @node: pointer to node structure
35001ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
35011ddef455SUsha Ketineni  *
35021ddef455SUsha Ketineni  * This function configures node element's BW rate limit profile ID of
35031ddef455SUsha Ketineni  * type CIR, EIR, or SRL to default. This function needs to be called
35041ddef455SUsha Ketineni  * with the scheduler lock held.
35051ddef455SUsha Ketineni  */
35061ddef455SUsha Ketineni static enum ice_status
35071ddef455SUsha Ketineni ice_sched_set_node_bw_dflt_lmt(struct ice_port_info *pi,
35081ddef455SUsha Ketineni 			       struct ice_sched_node *node,
35091ddef455SUsha Ketineni 			       enum ice_rl_type rl_type)
35101ddef455SUsha Ketineni {
35111ddef455SUsha Ketineni 	return ice_sched_set_node_bw_lmt(pi, node, rl_type,
35121ddef455SUsha Ketineni 					 ICE_SCHED_DFLT_BW);
35131ddef455SUsha Ketineni }
35141ddef455SUsha Ketineni 
35151ddef455SUsha Ketineni /**
35161ddef455SUsha Ketineni  * ice_sched_validate_srl_node - Check node for SRL applicability
35171ddef455SUsha Ketineni  * @node: sched node to configure
35181ddef455SUsha Ketineni  * @sel_layer: selected SRL layer
35191ddef455SUsha Ketineni  *
35201ddef455SUsha Ketineni  * This function checks if the SRL can be applied to a selected layer node on
35211ddef455SUsha Ketineni  * behalf of the requested node (first argument). This function needs to be
35221ddef455SUsha Ketineni  * called with scheduler lock held.
35231ddef455SUsha Ketineni  */
35241ddef455SUsha Ketineni static enum ice_status
35251ddef455SUsha Ketineni ice_sched_validate_srl_node(struct ice_sched_node *node, u8 sel_layer)
35261ddef455SUsha Ketineni {
35271ddef455SUsha Ketineni 	/* SRL profiles are not available on all layers. Check if the
35281ddef455SUsha Ketineni 	 * SRL profile can be applied to a node above or below the
35291ddef455SUsha Ketineni 	 * requested node. SRL configuration is possible only if the
35301ddef455SUsha Ketineni 	 * selected layer's node has single child.
35311ddef455SUsha Ketineni 	 */
35321ddef455SUsha Ketineni 	if (sel_layer == node->tx_sched_layer ||
35331ddef455SUsha Ketineni 	    ((sel_layer == node->tx_sched_layer + 1) &&
35341ddef455SUsha Ketineni 	    node->num_children == 1) ||
35351ddef455SUsha Ketineni 	    ((sel_layer == node->tx_sched_layer - 1) &&
35361ddef455SUsha Ketineni 	    (node->parent && node->parent->num_children == 1)))
35371ddef455SUsha Ketineni 		return 0;
35381ddef455SUsha Ketineni 
35391ddef455SUsha Ketineni 	return ICE_ERR_CFG;
35401ddef455SUsha Ketineni }
35411ddef455SUsha Ketineni 
35421ddef455SUsha Ketineni /**
35431ddef455SUsha Ketineni  * ice_sched_save_q_bw - save queue node's BW information
35441ddef455SUsha Ketineni  * @q_ctx: queue context structure
35451ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
35461ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
35471ddef455SUsha Ketineni  *
35481ddef455SUsha Ketineni  * Save BW information of queue type node for post replay use.
35491ddef455SUsha Ketineni  */
35501ddef455SUsha Ketineni static enum ice_status
35511ddef455SUsha Ketineni ice_sched_save_q_bw(struct ice_q_ctx *q_ctx, enum ice_rl_type rl_type, u32 bw)
35521ddef455SUsha Ketineni {
35531ddef455SUsha Ketineni 	switch (rl_type) {
35541ddef455SUsha Ketineni 	case ICE_MIN_BW:
35551ddef455SUsha Ketineni 		ice_set_clear_cir_bw(&q_ctx->bw_t_info, bw);
35561ddef455SUsha Ketineni 		break;
35571ddef455SUsha Ketineni 	case ICE_MAX_BW:
35581ddef455SUsha Ketineni 		ice_set_clear_eir_bw(&q_ctx->bw_t_info, bw);
35591ddef455SUsha Ketineni 		break;
35601ddef455SUsha Ketineni 	case ICE_SHARED_BW:
35611ddef455SUsha Ketineni 		ice_set_clear_shared_bw(&q_ctx->bw_t_info, bw);
35621ddef455SUsha Ketineni 		break;
35631ddef455SUsha Ketineni 	default:
35641ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
35651ddef455SUsha Ketineni 	}
35661ddef455SUsha Ketineni 	return 0;
35671ddef455SUsha Ketineni }
35681ddef455SUsha Ketineni 
35691ddef455SUsha Ketineni /**
35701ddef455SUsha Ketineni  * ice_sched_set_q_bw_lmt - sets queue BW limit
35711ddef455SUsha Ketineni  * @pi: port information structure
35721ddef455SUsha Ketineni  * @vsi_handle: sw VSI handle
35731ddef455SUsha Ketineni  * @tc: traffic class
35741ddef455SUsha Ketineni  * @q_handle: software queue handle
35751ddef455SUsha Ketineni  * @rl_type: min, max, or shared
35761ddef455SUsha Ketineni  * @bw: bandwidth in Kbps
35771ddef455SUsha Ketineni  *
35781ddef455SUsha Ketineni  * This function sets BW limit of queue scheduling node.
35791ddef455SUsha Ketineni  */
35801ddef455SUsha Ketineni static enum ice_status
35811ddef455SUsha Ketineni ice_sched_set_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
35821ddef455SUsha Ketineni 		       u16 q_handle, enum ice_rl_type rl_type, u32 bw)
35831ddef455SUsha Ketineni {
35841ddef455SUsha Ketineni 	enum ice_status status = ICE_ERR_PARAM;
35851ddef455SUsha Ketineni 	struct ice_sched_node *node;
35861ddef455SUsha Ketineni 	struct ice_q_ctx *q_ctx;
35871ddef455SUsha Ketineni 
35881ddef455SUsha Ketineni 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
35891ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
35901ddef455SUsha Ketineni 	mutex_lock(&pi->sched_lock);
35911ddef455SUsha Ketineni 	q_ctx = ice_get_lan_q_ctx(pi->hw, vsi_handle, tc, q_handle);
35921ddef455SUsha Ketineni 	if (!q_ctx)
35931ddef455SUsha Ketineni 		goto exit_q_bw_lmt;
35941ddef455SUsha Ketineni 	node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid);
35951ddef455SUsha Ketineni 	if (!node) {
35961ddef455SUsha Ketineni 		ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong q_teid\n");
35971ddef455SUsha Ketineni 		goto exit_q_bw_lmt;
35981ddef455SUsha Ketineni 	}
35991ddef455SUsha Ketineni 
36001ddef455SUsha Ketineni 	/* Return error if it is not a leaf node */
36011ddef455SUsha Ketineni 	if (node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF)
36021ddef455SUsha Ketineni 		goto exit_q_bw_lmt;
36031ddef455SUsha Ketineni 
36041ddef455SUsha Ketineni 	/* SRL bandwidth layer selection */
36051ddef455SUsha Ketineni 	if (rl_type == ICE_SHARED_BW) {
36061ddef455SUsha Ketineni 		u8 sel_layer; /* selected layer */
36071ddef455SUsha Ketineni 
36081ddef455SUsha Ketineni 		sel_layer = ice_sched_get_rl_prof_layer(pi, rl_type,
36091ddef455SUsha Ketineni 							node->tx_sched_layer);
36101ddef455SUsha Ketineni 		if (sel_layer >= pi->hw->num_tx_sched_layers) {
36111ddef455SUsha Ketineni 			status = ICE_ERR_PARAM;
36121ddef455SUsha Ketineni 			goto exit_q_bw_lmt;
36131ddef455SUsha Ketineni 		}
36141ddef455SUsha Ketineni 		status = ice_sched_validate_srl_node(node, sel_layer);
36151ddef455SUsha Ketineni 		if (status)
36161ddef455SUsha Ketineni 			goto exit_q_bw_lmt;
36171ddef455SUsha Ketineni 	}
36181ddef455SUsha Ketineni 
36191ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW)
36201ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type);
36211ddef455SUsha Ketineni 	else
36221ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw);
36231ddef455SUsha Ketineni 
36241ddef455SUsha Ketineni 	if (!status)
36251ddef455SUsha Ketineni 		status = ice_sched_save_q_bw(q_ctx, rl_type, bw);
36261ddef455SUsha Ketineni 
36271ddef455SUsha Ketineni exit_q_bw_lmt:
36281ddef455SUsha Ketineni 	mutex_unlock(&pi->sched_lock);
36291ddef455SUsha Ketineni 	return status;
36301ddef455SUsha Ketineni }
36311ddef455SUsha Ketineni 
36321ddef455SUsha Ketineni /**
36331ddef455SUsha Ketineni  * ice_cfg_q_bw_lmt - configure queue BW limit
36341ddef455SUsha Ketineni  * @pi: port information structure
36351ddef455SUsha Ketineni  * @vsi_handle: sw VSI handle
36361ddef455SUsha Ketineni  * @tc: traffic class
36371ddef455SUsha Ketineni  * @q_handle: software queue handle
36381ddef455SUsha Ketineni  * @rl_type: min, max, or shared
36391ddef455SUsha Ketineni  * @bw: bandwidth in Kbps
36401ddef455SUsha Ketineni  *
36411ddef455SUsha Ketineni  * This function configures BW limit of queue scheduling node.
36421ddef455SUsha Ketineni  */
36431ddef455SUsha Ketineni enum ice_status
36441ddef455SUsha Ketineni ice_cfg_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
36451ddef455SUsha Ketineni 		 u16 q_handle, enum ice_rl_type rl_type, u32 bw)
36461ddef455SUsha Ketineni {
36471ddef455SUsha Ketineni 	return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type,
36481ddef455SUsha Ketineni 				      bw);
36491ddef455SUsha Ketineni }
36501ddef455SUsha Ketineni 
36511ddef455SUsha Ketineni /**
36521ddef455SUsha Ketineni  * ice_cfg_q_bw_dflt_lmt - configure queue BW default limit
36531ddef455SUsha Ketineni  * @pi: port information structure
36541ddef455SUsha Ketineni  * @vsi_handle: sw VSI handle
36551ddef455SUsha Ketineni  * @tc: traffic class
36561ddef455SUsha Ketineni  * @q_handle: software queue handle
36571ddef455SUsha Ketineni  * @rl_type: min, max, or shared
36581ddef455SUsha Ketineni  *
36591ddef455SUsha Ketineni  * This function configures BW default limit of queue scheduling node.
36601ddef455SUsha Ketineni  */
36611ddef455SUsha Ketineni enum ice_status
36621ddef455SUsha Ketineni ice_cfg_q_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
36631ddef455SUsha Ketineni 		      u16 q_handle, enum ice_rl_type rl_type)
36641ddef455SUsha Ketineni {
36651ddef455SUsha Ketineni 	return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type,
36661ddef455SUsha Ketineni 				      ICE_SCHED_DFLT_BW);
36671ddef455SUsha Ketineni }
36681ddef455SUsha Ketineni 
36691ddef455SUsha Ketineni /**
36701ddef455SUsha Ketineni  * ice_cfg_rl_burst_size - Set burst size value
36711ddef455SUsha Ketineni  * @hw: pointer to the HW struct
36721ddef455SUsha Ketineni  * @bytes: burst size in bytes
36731ddef455SUsha Ketineni  *
36741ddef455SUsha Ketineni  * This function configures/set the burst size to requested new value. The new
36751ddef455SUsha Ketineni  * burst size value is used for future rate limit calls. It doesn't change the
36761ddef455SUsha Ketineni  * existing or previously created RL profiles.
36771ddef455SUsha Ketineni  */
36781ddef455SUsha Ketineni enum ice_status ice_cfg_rl_burst_size(struct ice_hw *hw, u32 bytes)
36791ddef455SUsha Ketineni {
36801ddef455SUsha Ketineni 	u16 burst_size_to_prog;
36811ddef455SUsha Ketineni 
36821ddef455SUsha Ketineni 	if (bytes < ICE_MIN_BURST_SIZE_ALLOWED ||
36831ddef455SUsha Ketineni 	    bytes > ICE_MAX_BURST_SIZE_ALLOWED)
36841ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
36851ddef455SUsha Ketineni 	if (ice_round_to_num(bytes, 64) <=
36861ddef455SUsha Ketineni 	    ICE_MAX_BURST_SIZE_64_BYTE_GRANULARITY) {
36871ddef455SUsha Ketineni 		/* 64 byte granularity case */
36881ddef455SUsha Ketineni 		/* Disable MSB granularity bit */
36891ddef455SUsha Ketineni 		burst_size_to_prog = ICE_64_BYTE_GRANULARITY;
36901ddef455SUsha Ketineni 		/* round number to nearest 64 byte granularity */
36911ddef455SUsha Ketineni 		bytes = ice_round_to_num(bytes, 64);
36921ddef455SUsha Ketineni 		/* The value is in 64 byte chunks */
36931ddef455SUsha Ketineni 		burst_size_to_prog |= (u16)(bytes / 64);
36941ddef455SUsha Ketineni 	} else {
36951ddef455SUsha Ketineni 		/* k bytes granularity case */
36961ddef455SUsha Ketineni 		/* Enable MSB granularity bit */
36971ddef455SUsha Ketineni 		burst_size_to_prog = ICE_KBYTE_GRANULARITY;
36981ddef455SUsha Ketineni 		/* round number to nearest 1024 granularity */
36991ddef455SUsha Ketineni 		bytes = ice_round_to_num(bytes, 1024);
37001ddef455SUsha Ketineni 		/* check rounding doesn't go beyond allowed */
37011ddef455SUsha Ketineni 		if (bytes > ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY)
37021ddef455SUsha Ketineni 			bytes = ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY;
37031ddef455SUsha Ketineni 		/* The value is in k bytes */
37041ddef455SUsha Ketineni 		burst_size_to_prog |= (u16)(bytes / 1024);
37051ddef455SUsha Ketineni 	}
37061ddef455SUsha Ketineni 	hw->max_burst_size = burst_size_to_prog;
37071ddef455SUsha Ketineni 	return 0;
37081ddef455SUsha Ketineni }
37091ddef455SUsha Ketineni 
37101ddef455SUsha Ketineni /**
37111ddef455SUsha Ketineni  * ice_sched_replay_node_prio - re-configure node priority
37121ddef455SUsha Ketineni  * @hw: pointer to the HW struct
37131ddef455SUsha Ketineni  * @node: sched node to configure
37141ddef455SUsha Ketineni  * @priority: priority value
37151ddef455SUsha Ketineni  *
37161ddef455SUsha Ketineni  * This function configures node element's priority value. It
37171ddef455SUsha Ketineni  * needs to be called with scheduler lock held.
37181ddef455SUsha Ketineni  */
37191ddef455SUsha Ketineni static enum ice_status
37201ddef455SUsha Ketineni ice_sched_replay_node_prio(struct ice_hw *hw, struct ice_sched_node *node,
37211ddef455SUsha Ketineni 			   u8 priority)
37221ddef455SUsha Ketineni {
37231ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem_data buf;
37241ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem *data;
37251ddef455SUsha Ketineni 	enum ice_status status;
37261ddef455SUsha Ketineni 
37271ddef455SUsha Ketineni 	buf = node->info;
37281ddef455SUsha Ketineni 	data = &buf.data;
37291ddef455SUsha Ketineni 	data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC;
37301ddef455SUsha Ketineni 	data->generic = priority;
37311ddef455SUsha Ketineni 
37321ddef455SUsha Ketineni 	/* Configure element */
37331ddef455SUsha Ketineni 	status = ice_sched_update_elem(hw, node, &buf);
37341ddef455SUsha Ketineni 	return status;
37351ddef455SUsha Ketineni }
37361ddef455SUsha Ketineni 
37371ddef455SUsha Ketineni /**
37381ddef455SUsha Ketineni  * ice_sched_replay_node_bw - replay node(s) BW
37391ddef455SUsha Ketineni  * @hw: pointer to the HW struct
37401ddef455SUsha Ketineni  * @node: sched node to configure
37411ddef455SUsha Ketineni  * @bw_t_info: BW type information
37421ddef455SUsha Ketineni  *
37431ddef455SUsha Ketineni  * This function restores node's BW from bw_t_info. The caller needs
37441ddef455SUsha Ketineni  * to hold the scheduler lock.
37451ddef455SUsha Ketineni  */
37461ddef455SUsha Ketineni static enum ice_status
37471ddef455SUsha Ketineni ice_sched_replay_node_bw(struct ice_hw *hw, struct ice_sched_node *node,
37481ddef455SUsha Ketineni 			 struct ice_bw_type_info *bw_t_info)
37491ddef455SUsha Ketineni {
37501ddef455SUsha Ketineni 	struct ice_port_info *pi = hw->port_info;
37511ddef455SUsha Ketineni 	enum ice_status status = ICE_ERR_PARAM;
37521ddef455SUsha Ketineni 	u16 bw_alloc;
37531ddef455SUsha Ketineni 
37541ddef455SUsha Ketineni 	if (!node)
37551ddef455SUsha Ketineni 		return status;
37561ddef455SUsha Ketineni 	if (bitmap_empty(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CNT))
37571ddef455SUsha Ketineni 		return 0;
37581ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap)) {
37591ddef455SUsha Ketineni 		status = ice_sched_replay_node_prio(hw, node,
37601ddef455SUsha Ketineni 						    bw_t_info->generic);
37611ddef455SUsha Ketineni 		if (status)
37621ddef455SUsha Ketineni 			return status;
37631ddef455SUsha Ketineni 	}
37641ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap)) {
37651ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_lmt(pi, node, ICE_MIN_BW,
37661ddef455SUsha Ketineni 						   bw_t_info->cir_bw.bw);
37671ddef455SUsha Ketineni 		if (status)
37681ddef455SUsha Ketineni 			return status;
37691ddef455SUsha Ketineni 	}
37701ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap)) {
37711ddef455SUsha Ketineni 		bw_alloc = bw_t_info->cir_bw.bw_alloc;
37721ddef455SUsha Ketineni 		status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MIN_BW,
37731ddef455SUsha Ketineni 						     bw_alloc);
37741ddef455SUsha Ketineni 		if (status)
37751ddef455SUsha Ketineni 			return status;
37761ddef455SUsha Ketineni 	}
37771ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap)) {
37781ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_lmt(pi, node, ICE_MAX_BW,
37791ddef455SUsha Ketineni 						   bw_t_info->eir_bw.bw);
37801ddef455SUsha Ketineni 		if (status)
37811ddef455SUsha Ketineni 			return status;
37821ddef455SUsha Ketineni 	}
37831ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap)) {
37841ddef455SUsha Ketineni 		bw_alloc = bw_t_info->eir_bw.bw_alloc;
37851ddef455SUsha Ketineni 		status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MAX_BW,
37861ddef455SUsha Ketineni 						     bw_alloc);
37871ddef455SUsha Ketineni 		if (status)
37881ddef455SUsha Ketineni 			return status;
37891ddef455SUsha Ketineni 	}
37901ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap))
37911ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_lmt(pi, node, ICE_SHARED_BW,
37921ddef455SUsha Ketineni 						   bw_t_info->shared_bw);
37931ddef455SUsha Ketineni 	return status;
37941ddef455SUsha Ketineni }
37951ddef455SUsha Ketineni 
37961ddef455SUsha Ketineni /**
3797b126bd6bSKiran Patil  * ice_sched_get_ena_tc_bitmap - get enabled TC bitmap
3798b126bd6bSKiran Patil  * @pi: port info struct
3799b126bd6bSKiran Patil  * @tc_bitmap: 8 bits TC bitmap to check
3800b126bd6bSKiran Patil  * @ena_tc_bitmap: 8 bits enabled TC bitmap to return
3801b126bd6bSKiran Patil  *
3802b126bd6bSKiran Patil  * This function returns enabled TC bitmap in variable ena_tc_bitmap. Some TCs
3803b126bd6bSKiran Patil  * may be missing, it returns enabled TCs. This function needs to be called with
3804b126bd6bSKiran Patil  * scheduler lock held.
3805b126bd6bSKiran Patil  */
3806b126bd6bSKiran Patil static void
3807b126bd6bSKiran Patil ice_sched_get_ena_tc_bitmap(struct ice_port_info *pi,
3808b126bd6bSKiran Patil 			    unsigned long *tc_bitmap,
3809b126bd6bSKiran Patil 			    unsigned long *ena_tc_bitmap)
3810b126bd6bSKiran Patil {
3811b126bd6bSKiran Patil 	u8 tc;
3812b126bd6bSKiran Patil 
3813b126bd6bSKiran Patil 	/* Some TC(s) may be missing after reset, adjust for replay */
3814b126bd6bSKiran Patil 	ice_for_each_traffic_class(tc)
3815b126bd6bSKiran Patil 		if (ice_is_tc_ena(*tc_bitmap, tc) &&
3816b126bd6bSKiran Patil 		    (ice_sched_get_tc_node(pi, tc)))
3817b126bd6bSKiran Patil 			set_bit(tc, ena_tc_bitmap);
3818b126bd6bSKiran Patil }
3819b126bd6bSKiran Patil 
3820b126bd6bSKiran Patil /**
3821b126bd6bSKiran Patil  * ice_sched_replay_agg - recreate aggregator node(s)
3822b126bd6bSKiran Patil  * @hw: pointer to the HW struct
3823b126bd6bSKiran Patil  *
3824b126bd6bSKiran Patil  * This function recreate aggregator type nodes which are not replayed earlier.
3825b126bd6bSKiran Patil  * It also replay aggregator BW information. These aggregator nodes are not
3826b126bd6bSKiran Patil  * associated with VSI type node yet.
3827b126bd6bSKiran Patil  */
3828b126bd6bSKiran Patil void ice_sched_replay_agg(struct ice_hw *hw)
3829b126bd6bSKiran Patil {
3830b126bd6bSKiran Patil 	struct ice_port_info *pi = hw->port_info;
3831b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
3832b126bd6bSKiran Patil 
3833b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
3834b126bd6bSKiran Patil 	list_for_each_entry(agg_info, &hw->agg_list, list_entry)
3835b126bd6bSKiran Patil 		/* replay aggregator (re-create aggregator node) */
3836b126bd6bSKiran Patil 		if (!bitmap_equal(agg_info->tc_bitmap, agg_info->replay_tc_bitmap,
3837b126bd6bSKiran Patil 				  ICE_MAX_TRAFFIC_CLASS)) {
3838b126bd6bSKiran Patil 			DECLARE_BITMAP(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
3839b126bd6bSKiran Patil 			enum ice_status status;
3840b126bd6bSKiran Patil 
3841b126bd6bSKiran Patil 			bitmap_zero(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
3842b126bd6bSKiran Patil 			ice_sched_get_ena_tc_bitmap(pi,
3843b126bd6bSKiran Patil 						    agg_info->replay_tc_bitmap,
3844b126bd6bSKiran Patil 						    replay_bitmap);
3845b126bd6bSKiran Patil 			status = ice_sched_cfg_agg(hw->port_info,
3846b126bd6bSKiran Patil 						   agg_info->agg_id,
3847b126bd6bSKiran Patil 						   ICE_AGG_TYPE_AGG,
3848b126bd6bSKiran Patil 						   replay_bitmap);
3849b126bd6bSKiran Patil 			if (status) {
3850b126bd6bSKiran Patil 				dev_info(ice_hw_to_dev(hw),
3851b126bd6bSKiran Patil 					 "Replay agg id[%d] failed\n",
3852b126bd6bSKiran Patil 					 agg_info->agg_id);
3853b126bd6bSKiran Patil 				/* Move on to next one */
3854b126bd6bSKiran Patil 				continue;
3855b126bd6bSKiran Patil 			}
3856b126bd6bSKiran Patil 		}
3857b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
3858b126bd6bSKiran Patil }
3859b126bd6bSKiran Patil 
3860b126bd6bSKiran Patil /**
3861b126bd6bSKiran Patil  * ice_sched_replay_agg_vsi_preinit - Agg/VSI replay pre initialization
3862b126bd6bSKiran Patil  * @hw: pointer to the HW struct
3863b126bd6bSKiran Patil  *
3864b126bd6bSKiran Patil  * This function initialize aggregator(s) TC bitmap to zero. A required
3865b126bd6bSKiran Patil  * preinit step for replaying aggregators.
3866b126bd6bSKiran Patil  */
3867b126bd6bSKiran Patil void ice_sched_replay_agg_vsi_preinit(struct ice_hw *hw)
3868b126bd6bSKiran Patil {
3869b126bd6bSKiran Patil 	struct ice_port_info *pi = hw->port_info;
3870b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
3871b126bd6bSKiran Patil 
3872b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
3873b126bd6bSKiran Patil 	list_for_each_entry(agg_info, &hw->agg_list, list_entry) {
3874b126bd6bSKiran Patil 		struct ice_sched_agg_vsi_info *agg_vsi_info;
3875b126bd6bSKiran Patil 
3876b126bd6bSKiran Patil 		agg_info->tc_bitmap[0] = 0;
3877b126bd6bSKiran Patil 		list_for_each_entry(agg_vsi_info, &agg_info->agg_vsi_list,
3878b126bd6bSKiran Patil 				    list_entry)
3879b126bd6bSKiran Patil 			agg_vsi_info->tc_bitmap[0] = 0;
3880b126bd6bSKiran Patil 	}
3881b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
3882b126bd6bSKiran Patil }
3883b126bd6bSKiran Patil 
3884b126bd6bSKiran Patil /**
3885b126bd6bSKiran Patil  * ice_sched_replay_vsi_agg - replay aggregator & VSI to aggregator node(s)
3886b126bd6bSKiran Patil  * @hw: pointer to the HW struct
3887b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
3888b126bd6bSKiran Patil  *
3889b126bd6bSKiran Patil  * This function replays aggregator node, VSI to aggregator type nodes, and
3890b126bd6bSKiran Patil  * their node bandwidth information. This function needs to be called with
3891b126bd6bSKiran Patil  * scheduler lock held.
3892b126bd6bSKiran Patil  */
3893b126bd6bSKiran Patil static enum ice_status
3894b126bd6bSKiran Patil ice_sched_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle)
3895b126bd6bSKiran Patil {
3896b126bd6bSKiran Patil 	DECLARE_BITMAP(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
3897b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *agg_vsi_info;
3898b126bd6bSKiran Patil 	struct ice_port_info *pi = hw->port_info;
3899b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
3900b126bd6bSKiran Patil 	enum ice_status status;
3901b126bd6bSKiran Patil 
3902b126bd6bSKiran Patil 	bitmap_zero(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
3903b126bd6bSKiran Patil 	if (!ice_is_vsi_valid(hw, vsi_handle))
3904b126bd6bSKiran Patil 		return ICE_ERR_PARAM;
3905b126bd6bSKiran Patil 	agg_info = ice_get_vsi_agg_info(hw, vsi_handle);
3906b126bd6bSKiran Patil 	if (!agg_info)
3907b126bd6bSKiran Patil 		return 0; /* Not present in list - default Agg case */
3908b126bd6bSKiran Patil 	agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
3909b126bd6bSKiran Patil 	if (!agg_vsi_info)
3910b126bd6bSKiran Patil 		return 0; /* Not present in list - default Agg case */
3911b126bd6bSKiran Patil 	ice_sched_get_ena_tc_bitmap(pi, agg_info->replay_tc_bitmap,
3912b126bd6bSKiran Patil 				    replay_bitmap);
3913b126bd6bSKiran Patil 	/* Replay aggregator node associated to vsi_handle */
3914b126bd6bSKiran Patil 	status = ice_sched_cfg_agg(hw->port_info, agg_info->agg_id,
3915b126bd6bSKiran Patil 				   ICE_AGG_TYPE_AGG, replay_bitmap);
3916b126bd6bSKiran Patil 	if (status)
3917b126bd6bSKiran Patil 		return status;
3918b126bd6bSKiran Patil 
3919b126bd6bSKiran Patil 	bitmap_zero(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
3920b126bd6bSKiran Patil 	ice_sched_get_ena_tc_bitmap(pi, agg_vsi_info->replay_tc_bitmap,
3921b126bd6bSKiran Patil 				    replay_bitmap);
3922b126bd6bSKiran Patil 	/* Move this VSI (vsi_handle) to above aggregator */
3923b126bd6bSKiran Patil 	return ice_sched_assoc_vsi_to_agg(pi, agg_info->agg_id, vsi_handle,
3924b126bd6bSKiran Patil 					  replay_bitmap);
3925b126bd6bSKiran Patil }
3926b126bd6bSKiran Patil 
3927b126bd6bSKiran Patil /**
3928b126bd6bSKiran Patil  * ice_replay_vsi_agg - replay VSI to aggregator node
3929b126bd6bSKiran Patil  * @hw: pointer to the HW struct
3930b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
3931b126bd6bSKiran Patil  *
3932b126bd6bSKiran Patil  * This function replays association of VSI to aggregator type nodes, and
3933b126bd6bSKiran Patil  * node bandwidth information.
3934b126bd6bSKiran Patil  */
3935b126bd6bSKiran Patil enum ice_status ice_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle)
3936b126bd6bSKiran Patil {
3937b126bd6bSKiran Patil 	struct ice_port_info *pi = hw->port_info;
3938b126bd6bSKiran Patil 	enum ice_status status;
3939b126bd6bSKiran Patil 
3940b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
3941b126bd6bSKiran Patil 	status = ice_sched_replay_vsi_agg(hw, vsi_handle);
3942b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
3943b126bd6bSKiran Patil 	return status;
3944b126bd6bSKiran Patil }
3945b126bd6bSKiran Patil 
3946b126bd6bSKiran Patil /**
39471ddef455SUsha Ketineni  * ice_sched_replay_q_bw - replay queue type node BW
39481ddef455SUsha Ketineni  * @pi: port information structure
39491ddef455SUsha Ketineni  * @q_ctx: queue context structure
39501ddef455SUsha Ketineni  *
39511ddef455SUsha Ketineni  * This function replays queue type node bandwidth. This function needs to be
39521ddef455SUsha Ketineni  * called with scheduler lock held.
39531ddef455SUsha Ketineni  */
39541ddef455SUsha Ketineni enum ice_status
39551ddef455SUsha Ketineni ice_sched_replay_q_bw(struct ice_port_info *pi, struct ice_q_ctx *q_ctx)
39561ddef455SUsha Ketineni {
39571ddef455SUsha Ketineni 	struct ice_sched_node *q_node;
39581ddef455SUsha Ketineni 
39591ddef455SUsha Ketineni 	/* Following also checks the presence of node in tree */
39601ddef455SUsha Ketineni 	q_node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid);
39611ddef455SUsha Ketineni 	if (!q_node)
39621ddef455SUsha Ketineni 		return ICE_ERR_PARAM;
39631ddef455SUsha Ketineni 	return ice_sched_replay_node_bw(pi->hw, q_node, &q_ctx->bw_t_info);
39641ddef455SUsha Ketineni }
3965