19c20346bSAnirudh Venkataramanan // SPDX-License-Identifier: GPL-2.0
29c20346bSAnirudh Venkataramanan /* Copyright (c) 2018, Intel Corporation. */
39c20346bSAnirudh Venkataramanan 
416dfa494SMichal Wilczynski #include <net/devlink.h>
59c20346bSAnirudh Venkataramanan #include "ice_sched.h"
69c20346bSAnirudh Venkataramanan 
79c20346bSAnirudh Venkataramanan /**
8dc49c772SAnirudh Venkataramanan  * ice_sched_add_root_node - Insert the Tx scheduler root node in SW DB
9dc49c772SAnirudh Venkataramanan  * @pi: port information structure
10dc49c772SAnirudh Venkataramanan  * @info: Scheduler element information from firmware
11dc49c772SAnirudh Venkataramanan  *
12dc49c772SAnirudh Venkataramanan  * This function inserts the root node of the scheduling tree topology
13dc49c772SAnirudh Venkataramanan  * to the SW DB.
14dc49c772SAnirudh Venkataramanan  */
155e24d598STony Nguyen static int
ice_sched_add_root_node(struct ice_port_info * pi,struct ice_aqc_txsched_elem_data * info)16dc49c772SAnirudh Venkataramanan ice_sched_add_root_node(struct ice_port_info *pi,
17dc49c772SAnirudh Venkataramanan 			struct ice_aqc_txsched_elem_data *info)
18dc49c772SAnirudh Venkataramanan {
19dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *root;
20dc49c772SAnirudh Venkataramanan 	struct ice_hw *hw;
21dc49c772SAnirudh Venkataramanan 
22dc49c772SAnirudh Venkataramanan 	if (!pi)
23d54699e2STony Nguyen 		return -EINVAL;
24dc49c772SAnirudh Venkataramanan 
25dc49c772SAnirudh Venkataramanan 	hw = pi->hw;
26dc49c772SAnirudh Venkataramanan 
27dc49c772SAnirudh Venkataramanan 	root = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*root), GFP_KERNEL);
28dc49c772SAnirudh Venkataramanan 	if (!root)
29d54699e2STony Nguyen 		return -ENOMEM;
30dc49c772SAnirudh Venkataramanan 
31b36c598cSAnirudh Venkataramanan 	/* coverity[suspicious_sizeof] */
32b36c598cSAnirudh Venkataramanan 	root->children = devm_kcalloc(ice_hw_to_dev(hw), hw->max_children[0],
33dc49c772SAnirudh Venkataramanan 				      sizeof(*root), GFP_KERNEL);
34dc49c772SAnirudh Venkataramanan 	if (!root->children) {
35dc49c772SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), root);
36d54699e2STony Nguyen 		return -ENOMEM;
37dc49c772SAnirudh Venkataramanan 	}
38dc49c772SAnirudh Venkataramanan 
39dc49c772SAnirudh Venkataramanan 	memcpy(&root->info, info, sizeof(*info));
40dc49c772SAnirudh Venkataramanan 	pi->root = root;
41dc49c772SAnirudh Venkataramanan 	return 0;
42dc49c772SAnirudh Venkataramanan }
43dc49c772SAnirudh Venkataramanan 
44dc49c772SAnirudh Venkataramanan /**
45dc49c772SAnirudh Venkataramanan  * ice_sched_find_node_by_teid - Find the Tx scheduler node in SW DB
46dc49c772SAnirudh Venkataramanan  * @start_node: pointer to the starting ice_sched_node struct in a sub-tree
47f9867df6SAnirudh Venkataramanan  * @teid: node TEID to search
48dc49c772SAnirudh Venkataramanan  *
49f9867df6SAnirudh Venkataramanan  * This function searches for a node matching the TEID in the scheduling tree
50dc49c772SAnirudh Venkataramanan  * from the SW DB. The search is recursive and is restricted by the number of
51dc49c772SAnirudh Venkataramanan  * layers it has searched through; stopping at the max supported layer.
52dc49c772SAnirudh Venkataramanan  *
53dc49c772SAnirudh Venkataramanan  * This function needs to be called when holding the port_info->sched_lock
54dc49c772SAnirudh Venkataramanan  */
55dc49c772SAnirudh Venkataramanan struct ice_sched_node *
ice_sched_find_node_by_teid(struct ice_sched_node * start_node,u32 teid)56dc49c772SAnirudh Venkataramanan ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid)
57dc49c772SAnirudh Venkataramanan {
58dc49c772SAnirudh Venkataramanan 	u16 i;
59dc49c772SAnirudh Venkataramanan 
60dc49c772SAnirudh Venkataramanan 	/* The TEID is same as that of the start_node */
61dc49c772SAnirudh Venkataramanan 	if (ICE_TXSCHED_GET_NODE_TEID(start_node) == teid)
62dc49c772SAnirudh Venkataramanan 		return start_node;
63dc49c772SAnirudh Venkataramanan 
64dc49c772SAnirudh Venkataramanan 	/* The node has no children or is at the max layer */
65dc49c772SAnirudh Venkataramanan 	if (!start_node->num_children ||
66dc49c772SAnirudh Venkataramanan 	    start_node->tx_sched_layer >= ICE_AQC_TOPO_MAX_LEVEL_NUM ||
67dc49c772SAnirudh Venkataramanan 	    start_node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF)
68dc49c772SAnirudh Venkataramanan 		return NULL;
69dc49c772SAnirudh Venkataramanan 
70f9867df6SAnirudh Venkataramanan 	/* Check if TEID matches to any of the children nodes */
71dc49c772SAnirudh Venkataramanan 	for (i = 0; i < start_node->num_children; i++)
72dc49c772SAnirudh Venkataramanan 		if (ICE_TXSCHED_GET_NODE_TEID(start_node->children[i]) == teid)
73dc49c772SAnirudh Venkataramanan 			return start_node->children[i];
74dc49c772SAnirudh Venkataramanan 
75dc49c772SAnirudh Venkataramanan 	/* Search within each child's sub-tree */
76dc49c772SAnirudh Venkataramanan 	for (i = 0; i < start_node->num_children; i++) {
77dc49c772SAnirudh Venkataramanan 		struct ice_sched_node *tmp;
78dc49c772SAnirudh Venkataramanan 
79dc49c772SAnirudh Venkataramanan 		tmp = ice_sched_find_node_by_teid(start_node->children[i],
80dc49c772SAnirudh Venkataramanan 						  teid);
81dc49c772SAnirudh Venkataramanan 		if (tmp)
82dc49c772SAnirudh Venkataramanan 			return tmp;
83dc49c772SAnirudh Venkataramanan 	}
84dc49c772SAnirudh Venkataramanan 
85dc49c772SAnirudh Venkataramanan 	return NULL;
86dc49c772SAnirudh Venkataramanan }
87dc49c772SAnirudh Venkataramanan 
88dc49c772SAnirudh Venkataramanan /**
891f9c7840SAnirudh Venkataramanan  * ice_aqc_send_sched_elem_cmd - send scheduling elements cmd
90f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
911f9c7840SAnirudh Venkataramanan  * @cmd_opc: cmd opcode
921f9c7840SAnirudh Venkataramanan  * @elems_req: number of elements to request
931f9c7840SAnirudh Venkataramanan  * @buf: pointer to buffer
941f9c7840SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
951f9c7840SAnirudh Venkataramanan  * @elems_resp: returns total number of elements response
961f9c7840SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
971f9c7840SAnirudh Venkataramanan  *
981f9c7840SAnirudh Venkataramanan  * This function sends a scheduling elements cmd (cmd_opc)
991f9c7840SAnirudh Venkataramanan  */
1005e24d598STony Nguyen static int
ice_aqc_send_sched_elem_cmd(struct ice_hw * hw,enum ice_adminq_opc cmd_opc,u16 elems_req,void * buf,u16 buf_size,u16 * elems_resp,struct ice_sq_cd * cd)1011f9c7840SAnirudh Venkataramanan ice_aqc_send_sched_elem_cmd(struct ice_hw *hw, enum ice_adminq_opc cmd_opc,
1021f9c7840SAnirudh Venkataramanan 			    u16 elems_req, void *buf, u16 buf_size,
1031f9c7840SAnirudh Venkataramanan 			    u16 *elems_resp, struct ice_sq_cd *cd)
1041f9c7840SAnirudh Venkataramanan {
1051f9c7840SAnirudh Venkataramanan 	struct ice_aqc_sched_elem_cmd *cmd;
1061f9c7840SAnirudh Venkataramanan 	struct ice_aq_desc desc;
1075e24d598STony Nguyen 	int status;
1081f9c7840SAnirudh Venkataramanan 
1091f9c7840SAnirudh Venkataramanan 	cmd = &desc.params.sched_elem_cmd;
1101f9c7840SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, cmd_opc);
1111f9c7840SAnirudh Venkataramanan 	cmd->num_elem_req = cpu_to_le16(elems_req);
1121f9c7840SAnirudh Venkataramanan 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
1131f9c7840SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
1141f9c7840SAnirudh Venkataramanan 	if (!status && elems_resp)
1151f9c7840SAnirudh Venkataramanan 		*elems_resp = le16_to_cpu(cmd->num_elem_resp);
1161f9c7840SAnirudh Venkataramanan 
1171f9c7840SAnirudh Venkataramanan 	return status;
1181f9c7840SAnirudh Venkataramanan }
1191f9c7840SAnirudh Venkataramanan 
1201f9c7840SAnirudh Venkataramanan /**
12156daee6cSAnirudh Venkataramanan  * ice_aq_query_sched_elems - query scheduler elements
122f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
12356daee6cSAnirudh Venkataramanan  * @elems_req: number of elements to query
12456daee6cSAnirudh Venkataramanan  * @buf: pointer to buffer
12556daee6cSAnirudh Venkataramanan  * @buf_size: buffer size in bytes
12656daee6cSAnirudh Venkataramanan  * @elems_ret: returns total number of elements returned
12756daee6cSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
12856daee6cSAnirudh Venkataramanan  *
12956daee6cSAnirudh Venkataramanan  * Query scheduling elements (0x0404)
13056daee6cSAnirudh Venkataramanan  */
1315e24d598STony Nguyen int
ice_aq_query_sched_elems(struct ice_hw * hw,u16 elems_req,struct ice_aqc_txsched_elem_data * buf,u16 buf_size,u16 * elems_ret,struct ice_sq_cd * cd)13256daee6cSAnirudh Venkataramanan ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req,
133b3c38904SBruce Allan 			 struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
13456daee6cSAnirudh Venkataramanan 			 u16 *elems_ret, struct ice_sq_cd *cd)
13556daee6cSAnirudh Venkataramanan {
1361f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_get_sched_elems,
1371f9c7840SAnirudh Venkataramanan 					   elems_req, (void *)buf, buf_size,
1381f9c7840SAnirudh Venkataramanan 					   elems_ret, cd);
13956daee6cSAnirudh Venkataramanan }
14056daee6cSAnirudh Venkataramanan 
14156daee6cSAnirudh Venkataramanan /**
142dc49c772SAnirudh Venkataramanan  * ice_sched_add_node - Insert the Tx scheduler node in SW DB
143dc49c772SAnirudh Venkataramanan  * @pi: port information structure
144dc49c772SAnirudh Venkataramanan  * @layer: Scheduler layer of the node
145dc49c772SAnirudh Venkataramanan  * @info: Scheduler element information from firmware
146bdf96d96SMichal Wilczynski  * @prealloc_node: preallocated ice_sched_node struct for SW DB
147dc49c772SAnirudh Venkataramanan  *
148dc49c772SAnirudh Venkataramanan  * This function inserts a scheduler node to the SW DB.
149dc49c772SAnirudh Venkataramanan  */
1505e24d598STony Nguyen int
ice_sched_add_node(struct ice_port_info * pi,u8 layer,struct ice_aqc_txsched_elem_data * info,struct ice_sched_node * prealloc_node)151dc49c772SAnirudh Venkataramanan ice_sched_add_node(struct ice_port_info *pi, u8 layer,
152bdf96d96SMichal Wilczynski 		   struct ice_aqc_txsched_elem_data *info,
153bdf96d96SMichal Wilczynski 		   struct ice_sched_node *prealloc_node)
154dc49c772SAnirudh Venkataramanan {
155b3c38904SBruce Allan 	struct ice_aqc_txsched_elem_data elem;
156dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *parent;
157dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *node;
158dc49c772SAnirudh Venkataramanan 	struct ice_hw *hw;
1595518ac2aSTony Nguyen 	int status;
160dc49c772SAnirudh Venkataramanan 
161dc49c772SAnirudh Venkataramanan 	if (!pi)
162d54699e2STony Nguyen 		return -EINVAL;
163dc49c772SAnirudh Venkataramanan 
164dc49c772SAnirudh Venkataramanan 	hw = pi->hw;
165dc49c772SAnirudh Venkataramanan 
166dc49c772SAnirudh Venkataramanan 	/* A valid parent node should be there */
167dc49c772SAnirudh Venkataramanan 	parent = ice_sched_find_node_by_teid(pi->root,
168dc49c772SAnirudh Venkataramanan 					     le32_to_cpu(info->parent_teid));
169dc49c772SAnirudh Venkataramanan 	if (!parent) {
1709228d8b2SJacob Keller 		ice_debug(hw, ICE_DBG_SCHED, "Parent Node not found for parent_teid=0x%x\n",
171dc49c772SAnirudh Venkataramanan 			  le32_to_cpu(info->parent_teid));
172d54699e2STony Nguyen 		return -EINVAL;
173dc49c772SAnirudh Venkataramanan 	}
174dc49c772SAnirudh Venkataramanan 
1757dbc63f0STony Nguyen 	/* query the current node information from FW before adding it
17656daee6cSAnirudh Venkataramanan 	 * to the SW DB
17756daee6cSAnirudh Venkataramanan 	 */
17856daee6cSAnirudh Venkataramanan 	status = ice_sched_query_elem(hw, le32_to_cpu(info->node_teid), &elem);
17956daee6cSAnirudh Venkataramanan 	if (status)
18056daee6cSAnirudh Venkataramanan 		return status;
18156daee6cSAnirudh Venkataramanan 
182bdf96d96SMichal Wilczynski 	if (prealloc_node)
183bdf96d96SMichal Wilczynski 		node = prealloc_node;
184bdf96d96SMichal Wilczynski 	else
185dc49c772SAnirudh Venkataramanan 		node = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*node), GFP_KERNEL);
186dc49c772SAnirudh Venkataramanan 	if (!node)
187d54699e2STony Nguyen 		return -ENOMEM;
188b36c598cSAnirudh Venkataramanan 	if (hw->max_children[layer]) {
189b36c598cSAnirudh Venkataramanan 		/* coverity[suspicious_sizeof] */
190b36c598cSAnirudh Venkataramanan 		node->children = devm_kcalloc(ice_hw_to_dev(hw),
191b36c598cSAnirudh Venkataramanan 					      hw->max_children[layer],
192dc49c772SAnirudh Venkataramanan 					      sizeof(*node), GFP_KERNEL);
193dc49c772SAnirudh Venkataramanan 		if (!node->children) {
194dc49c772SAnirudh Venkataramanan 			devm_kfree(ice_hw_to_dev(hw), node);
195d54699e2STony Nguyen 			return -ENOMEM;
196dc49c772SAnirudh Venkataramanan 		}
197dc49c772SAnirudh Venkataramanan 	}
198dc49c772SAnirudh Venkataramanan 
199dc49c772SAnirudh Venkataramanan 	node->in_use = true;
200dc49c772SAnirudh Venkataramanan 	node->parent = parent;
201dc49c772SAnirudh Venkataramanan 	node->tx_sched_layer = layer;
202dc49c772SAnirudh Venkataramanan 	parent->children[parent->num_children++] = node;
203b3c38904SBruce Allan 	node->info = elem;
204dc49c772SAnirudh Venkataramanan 	return 0;
205dc49c772SAnirudh Venkataramanan }
206dc49c772SAnirudh Venkataramanan 
207dc49c772SAnirudh Venkataramanan /**
2089c20346bSAnirudh Venkataramanan  * ice_aq_delete_sched_elems - delete scheduler elements
209f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
2109c20346bSAnirudh Venkataramanan  * @grps_req: number of groups to delete
2119c20346bSAnirudh Venkataramanan  * @buf: pointer to buffer
2129c20346bSAnirudh Venkataramanan  * @buf_size: buffer size in bytes
2139c20346bSAnirudh Venkataramanan  * @grps_del: returns total number of elements deleted
2149c20346bSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
2159c20346bSAnirudh Venkataramanan  *
2169c20346bSAnirudh Venkataramanan  * Delete scheduling elements (0x040F)
2179c20346bSAnirudh Venkataramanan  */
2185e24d598STony Nguyen static int
ice_aq_delete_sched_elems(struct ice_hw * hw,u16 grps_req,struct ice_aqc_delete_elem * buf,u16 buf_size,u16 * grps_del,struct ice_sq_cd * cd)2199c20346bSAnirudh Venkataramanan ice_aq_delete_sched_elems(struct ice_hw *hw, u16 grps_req,
2209c20346bSAnirudh Venkataramanan 			  struct ice_aqc_delete_elem *buf, u16 buf_size,
2219c20346bSAnirudh Venkataramanan 			  u16 *grps_del, struct ice_sq_cd *cd)
2229c20346bSAnirudh Venkataramanan {
2231f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_delete_sched_elems,
2241f9c7840SAnirudh Venkataramanan 					   grps_req, (void *)buf, buf_size,
2251f9c7840SAnirudh Venkataramanan 					   grps_del, cd);
2269c20346bSAnirudh Venkataramanan }
2279c20346bSAnirudh Venkataramanan 
2289c20346bSAnirudh Venkataramanan /**
229f9867df6SAnirudh Venkataramanan  * ice_sched_remove_elems - remove nodes from HW
230f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
2319c20346bSAnirudh Venkataramanan  * @parent: pointer to the parent node
2329c20346bSAnirudh Venkataramanan  * @num_nodes: number of nodes
2339c20346bSAnirudh Venkataramanan  * @node_teids: array of node teids to be deleted
2349c20346bSAnirudh Venkataramanan  *
235f9867df6SAnirudh Venkataramanan  * This function remove nodes from HW
2369c20346bSAnirudh Venkataramanan  */
2375e24d598STony Nguyen static int
ice_sched_remove_elems(struct ice_hw * hw,struct ice_sched_node * parent,u16 num_nodes,u32 * node_teids)2389c20346bSAnirudh Venkataramanan ice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent,
2399c20346bSAnirudh Venkataramanan 		       u16 num_nodes, u32 *node_teids)
2409c20346bSAnirudh Venkataramanan {
2419c20346bSAnirudh Venkataramanan 	struct ice_aqc_delete_elem *buf;
2429c20346bSAnirudh Venkataramanan 	u16 i, num_groups_removed = 0;
2439c20346bSAnirudh Venkataramanan 	u16 buf_size;
2445518ac2aSTony Nguyen 	int status;
2459c20346bSAnirudh Venkataramanan 
24666486d89SBruce Allan 	buf_size = struct_size(buf, teid, num_nodes);
2479c20346bSAnirudh Venkataramanan 	buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);
2489c20346bSAnirudh Venkataramanan 	if (!buf)
249d54699e2STony Nguyen 		return -ENOMEM;
250b36c598cSAnirudh Venkataramanan 
2519c20346bSAnirudh Venkataramanan 	buf->hdr.parent_teid = parent->info.node_teid;
2529c20346bSAnirudh Venkataramanan 	buf->hdr.num_elems = cpu_to_le16(num_nodes);
2539c20346bSAnirudh Venkataramanan 	for (i = 0; i < num_nodes; i++)
2549c20346bSAnirudh Venkataramanan 		buf->teid[i] = cpu_to_le32(node_teids[i]);
255b36c598cSAnirudh Venkataramanan 
2569c20346bSAnirudh Venkataramanan 	status = ice_aq_delete_sched_elems(hw, 1, buf, buf_size,
2579c20346bSAnirudh Venkataramanan 					   &num_groups_removed, NULL);
2589c20346bSAnirudh Venkataramanan 	if (status || num_groups_removed != 1)
259e1ca65a3SVictor Raj 		ice_debug(hw, ICE_DBG_SCHED, "remove node failed FW error %d\n",
260e1ca65a3SVictor Raj 			  hw->adminq.sq_last_status);
261b36c598cSAnirudh Venkataramanan 
2629c20346bSAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), buf);
2639c20346bSAnirudh Venkataramanan 	return status;
2649c20346bSAnirudh Venkataramanan }
2659c20346bSAnirudh Venkataramanan 
2669c20346bSAnirudh Venkataramanan /**
2679c20346bSAnirudh Venkataramanan  * ice_sched_get_first_node - get the first node of the given layer
26829358248SVictor Raj  * @pi: port information structure
2699c20346bSAnirudh Venkataramanan  * @parent: pointer the base node of the subtree
2709c20346bSAnirudh Venkataramanan  * @layer: layer number
2719c20346bSAnirudh Venkataramanan  *
2729c20346bSAnirudh Venkataramanan  * This function retrieves the first node of the given layer from the subtree
2739c20346bSAnirudh Venkataramanan  */
2749c20346bSAnirudh Venkataramanan static struct ice_sched_node *
ice_sched_get_first_node(struct ice_port_info * pi,struct ice_sched_node * parent,u8 layer)27529358248SVictor Raj ice_sched_get_first_node(struct ice_port_info *pi,
27629358248SVictor Raj 			 struct ice_sched_node *parent, u8 layer)
2779c20346bSAnirudh Venkataramanan {
27829358248SVictor Raj 	return pi->sib_head[parent->tc_num][layer];
2799c20346bSAnirudh Venkataramanan }
2809c20346bSAnirudh Venkataramanan 
2819c20346bSAnirudh Venkataramanan /**
2829c20346bSAnirudh Venkataramanan  * ice_sched_get_tc_node - get pointer to TC node
2839c20346bSAnirudh Venkataramanan  * @pi: port information structure
2849c20346bSAnirudh Venkataramanan  * @tc: TC number
2859c20346bSAnirudh Venkataramanan  *
2869c20346bSAnirudh Venkataramanan  * This function returns the TC node pointer
2879c20346bSAnirudh Venkataramanan  */
ice_sched_get_tc_node(struct ice_port_info * pi,u8 tc)2889c20346bSAnirudh Venkataramanan struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc)
2899c20346bSAnirudh Venkataramanan {
2909c20346bSAnirudh Venkataramanan 	u8 i;
2919c20346bSAnirudh Venkataramanan 
292ade78c2eSAnirudh Venkataramanan 	if (!pi || !pi->root)
2939c20346bSAnirudh Venkataramanan 		return NULL;
2949c20346bSAnirudh Venkataramanan 	for (i = 0; i < pi->root->num_children; i++)
2959c20346bSAnirudh Venkataramanan 		if (pi->root->children[i]->tc_num == tc)
2969c20346bSAnirudh Venkataramanan 			return pi->root->children[i];
2979c20346bSAnirudh Venkataramanan 	return NULL;
2989c20346bSAnirudh Venkataramanan }
2999c20346bSAnirudh Venkataramanan 
3009c20346bSAnirudh Venkataramanan /**
3019c20346bSAnirudh Venkataramanan  * ice_free_sched_node - Free a Tx scheduler node from SW DB
3029c20346bSAnirudh Venkataramanan  * @pi: port information structure
3039c20346bSAnirudh Venkataramanan  * @node: pointer to the ice_sched_node struct
3049c20346bSAnirudh Venkataramanan  *
3059c20346bSAnirudh Venkataramanan  * This function frees up a node from SW DB as well as from HW
3069c20346bSAnirudh Venkataramanan  *
3079c20346bSAnirudh Venkataramanan  * This function needs to be called with the port_info->sched_lock held
3089c20346bSAnirudh Venkataramanan  */
ice_free_sched_node(struct ice_port_info * pi,struct ice_sched_node * node)3099c20346bSAnirudh Venkataramanan void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)
3109c20346bSAnirudh Venkataramanan {
3119c20346bSAnirudh Venkataramanan 	struct ice_sched_node *parent;
3129c20346bSAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
3139c20346bSAnirudh Venkataramanan 	u8 i, j;
3149c20346bSAnirudh Venkataramanan 
3159c20346bSAnirudh Venkataramanan 	/* Free the children before freeing up the parent node
3169c20346bSAnirudh Venkataramanan 	 * The parent array is updated below and that shifts the nodes
3179c20346bSAnirudh Venkataramanan 	 * in the array. So always pick the first child if num children > 0
3189c20346bSAnirudh Venkataramanan 	 */
3199c20346bSAnirudh Venkataramanan 	while (node->num_children)
3209c20346bSAnirudh Venkataramanan 		ice_free_sched_node(pi, node->children[0]);
3219c20346bSAnirudh Venkataramanan 
3229c20346bSAnirudh Venkataramanan 	/* Leaf, TC and root nodes can't be deleted by SW */
3239c20346bSAnirudh Venkataramanan 	if (node->tx_sched_layer >= hw->sw_entry_point_layer &&
3249c20346bSAnirudh Venkataramanan 	    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
3259c20346bSAnirudh Venkataramanan 	    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT &&
3269c20346bSAnirudh Venkataramanan 	    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) {
3279c20346bSAnirudh Venkataramanan 		u32 teid = le32_to_cpu(node->info.node_teid);
3289c20346bSAnirudh Venkataramanan 
329e1ca65a3SVictor Raj 		ice_sched_remove_elems(hw, node->parent, 1, &teid);
3309c20346bSAnirudh Venkataramanan 	}
3319c20346bSAnirudh Venkataramanan 	parent = node->parent;
3329c20346bSAnirudh Venkataramanan 	/* root has no parent */
3339c20346bSAnirudh Venkataramanan 	if (parent) {
33429358248SVictor Raj 		struct ice_sched_node *p;
3359c20346bSAnirudh Venkataramanan 
3369c20346bSAnirudh Venkataramanan 		/* update the parent */
3379c20346bSAnirudh Venkataramanan 		for (i = 0; i < parent->num_children; i++)
3389c20346bSAnirudh Venkataramanan 			if (parent->children[i] == node) {
3399c20346bSAnirudh Venkataramanan 				for (j = i + 1; j < parent->num_children; j++)
3409c20346bSAnirudh Venkataramanan 					parent->children[j - 1] =
3419c20346bSAnirudh Venkataramanan 						parent->children[j];
3429c20346bSAnirudh Venkataramanan 				parent->num_children--;
3439c20346bSAnirudh Venkataramanan 				break;
3449c20346bSAnirudh Venkataramanan 			}
3459c20346bSAnirudh Venkataramanan 
34629358248SVictor Raj 		p = ice_sched_get_first_node(pi, node, node->tx_sched_layer);
3479c20346bSAnirudh Venkataramanan 		while (p) {
3489c20346bSAnirudh Venkataramanan 			if (p->sibling == node) {
3499c20346bSAnirudh Venkataramanan 				p->sibling = node->sibling;
3509c20346bSAnirudh Venkataramanan 				break;
3519c20346bSAnirudh Venkataramanan 			}
3529c20346bSAnirudh Venkataramanan 			p = p->sibling;
3539c20346bSAnirudh Venkataramanan 		}
35429358248SVictor Raj 
35529358248SVictor Raj 		/* update the sibling head if head is getting removed */
35629358248SVictor Raj 		if (pi->sib_head[node->tc_num][node->tx_sched_layer] == node)
35729358248SVictor Raj 			pi->sib_head[node->tc_num][node->tx_sched_layer] =
35829358248SVictor Raj 				node->sibling;
3599c20346bSAnirudh Venkataramanan 	}
36029358248SVictor Raj 
3619c20346bSAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), node->children);
36216dfa494SMichal Wilczynski 	kfree(node->name);
36316dfa494SMichal Wilczynski 	xa_erase(&pi->sched_node_ids, node->id);
3649c20346bSAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), node);
3659c20346bSAnirudh Venkataramanan }
3669c20346bSAnirudh Venkataramanan 
3679c20346bSAnirudh Venkataramanan /**
368dc49c772SAnirudh Venkataramanan  * ice_aq_get_dflt_topo - gets default scheduler topology
369f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
370dc49c772SAnirudh Venkataramanan  * @lport: logical port number
371dc49c772SAnirudh Venkataramanan  * @buf: pointer to buffer
372dc49c772SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
373dc49c772SAnirudh Venkataramanan  * @num_branches: returns total number of queue to port branches
374dc49c772SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
375dc49c772SAnirudh Venkataramanan  *
376dc49c772SAnirudh Venkataramanan  * Get default scheduler topology (0x400)
377dc49c772SAnirudh Venkataramanan  */
3785e24d598STony Nguyen static int
ice_aq_get_dflt_topo(struct ice_hw * hw,u8 lport,struct ice_aqc_get_topo_elem * buf,u16 buf_size,u8 * num_branches,struct ice_sq_cd * cd)379dc49c772SAnirudh Venkataramanan ice_aq_get_dflt_topo(struct ice_hw *hw, u8 lport,
380dc49c772SAnirudh Venkataramanan 		     struct ice_aqc_get_topo_elem *buf, u16 buf_size,
381dc49c772SAnirudh Venkataramanan 		     u8 *num_branches, struct ice_sq_cd *cd)
382dc49c772SAnirudh Venkataramanan {
383dc49c772SAnirudh Venkataramanan 	struct ice_aqc_get_topo *cmd;
384dc49c772SAnirudh Venkataramanan 	struct ice_aq_desc desc;
3855e24d598STony Nguyen 	int status;
386dc49c772SAnirudh Venkataramanan 
387dc49c772SAnirudh Venkataramanan 	cmd = &desc.params.get_topo;
388dc49c772SAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_dflt_topo);
389dc49c772SAnirudh Venkataramanan 	cmd->port_num = lport;
390dc49c772SAnirudh Venkataramanan 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
391dc49c772SAnirudh Venkataramanan 	if (!status && num_branches)
392dc49c772SAnirudh Venkataramanan 		*num_branches = cmd->num_branches;
393dc49c772SAnirudh Venkataramanan 
394dc49c772SAnirudh Venkataramanan 	return status;
395dc49c772SAnirudh Venkataramanan }
396dc49c772SAnirudh Venkataramanan 
397dc49c772SAnirudh Venkataramanan /**
3985513b920SAnirudh Venkataramanan  * ice_aq_add_sched_elems - adds scheduling element
399f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
4005513b920SAnirudh Venkataramanan  * @grps_req: the number of groups that are requested to be added
4015513b920SAnirudh Venkataramanan  * @buf: pointer to buffer
4025513b920SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
4035513b920SAnirudh Venkataramanan  * @grps_added: returns total number of groups added
4045513b920SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
4055513b920SAnirudh Venkataramanan  *
4065513b920SAnirudh Venkataramanan  * Add scheduling elements (0x0401)
4075513b920SAnirudh Venkataramanan  */
4085e24d598STony Nguyen static int
ice_aq_add_sched_elems(struct ice_hw * hw,u16 grps_req,struct ice_aqc_add_elem * buf,u16 buf_size,u16 * grps_added,struct ice_sq_cd * cd)4095513b920SAnirudh Venkataramanan ice_aq_add_sched_elems(struct ice_hw *hw, u16 grps_req,
4105513b920SAnirudh Venkataramanan 		       struct ice_aqc_add_elem *buf, u16 buf_size,
4115513b920SAnirudh Venkataramanan 		       u16 *grps_added, struct ice_sq_cd *cd)
4125513b920SAnirudh Venkataramanan {
4131f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_add_sched_elems,
4141f9c7840SAnirudh Venkataramanan 					   grps_req, (void *)buf, buf_size,
4151f9c7840SAnirudh Venkataramanan 					   grps_added, cd);
4165513b920SAnirudh Venkataramanan }
4175513b920SAnirudh Venkataramanan 
4185513b920SAnirudh Venkataramanan /**
4191ddef455SUsha Ketineni  * ice_aq_cfg_sched_elems - configures scheduler elements
4201ddef455SUsha Ketineni  * @hw: pointer to the HW struct
4211ddef455SUsha Ketineni  * @elems_req: number of elements to configure
4221ddef455SUsha Ketineni  * @buf: pointer to buffer
4231ddef455SUsha Ketineni  * @buf_size: buffer size in bytes
4241ddef455SUsha Ketineni  * @elems_cfgd: returns total number of elements configured
4251ddef455SUsha Ketineni  * @cd: pointer to command details structure or NULL
4261ddef455SUsha Ketineni  *
4271ddef455SUsha Ketineni  * Configure scheduling elements (0x0403)
4281ddef455SUsha Ketineni  */
4295e24d598STony Nguyen static int
ice_aq_cfg_sched_elems(struct ice_hw * hw,u16 elems_req,struct ice_aqc_txsched_elem_data * buf,u16 buf_size,u16 * elems_cfgd,struct ice_sq_cd * cd)4301ddef455SUsha Ketineni ice_aq_cfg_sched_elems(struct ice_hw *hw, u16 elems_req,
431b3c38904SBruce Allan 		       struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
4321ddef455SUsha Ketineni 		       u16 *elems_cfgd, struct ice_sq_cd *cd)
4331ddef455SUsha Ketineni {
4341ddef455SUsha Ketineni 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_cfg_sched_elems,
4351ddef455SUsha Ketineni 					   elems_req, (void *)buf, buf_size,
4361ddef455SUsha Ketineni 					   elems_cfgd, cd);
4371ddef455SUsha Ketineni }
4381ddef455SUsha Ketineni 
4391ddef455SUsha Ketineni /**
440b126bd6bSKiran Patil  * ice_aq_move_sched_elems - move scheduler elements
441b126bd6bSKiran Patil  * @hw: pointer to the HW struct
442b126bd6bSKiran Patil  * @grps_req: number of groups to move
443b126bd6bSKiran Patil  * @buf: pointer to buffer
444b126bd6bSKiran Patil  * @buf_size: buffer size in bytes
445b126bd6bSKiran Patil  * @grps_movd: returns total number of groups moved
446b126bd6bSKiran Patil  * @cd: pointer to command details structure or NULL
447b126bd6bSKiran Patil  *
448b126bd6bSKiran Patil  * Move scheduling elements (0x0408)
449b126bd6bSKiran Patil  */
45023ccae5cSDave Ertman int
ice_aq_move_sched_elems(struct ice_hw * hw,u16 grps_req,struct ice_aqc_move_elem * buf,u16 buf_size,u16 * grps_movd,struct ice_sq_cd * cd)451b126bd6bSKiran Patil ice_aq_move_sched_elems(struct ice_hw *hw, u16 grps_req,
452b126bd6bSKiran Patil 			struct ice_aqc_move_elem *buf, u16 buf_size,
453b126bd6bSKiran Patil 			u16 *grps_movd, struct ice_sq_cd *cd)
454b126bd6bSKiran Patil {
455b126bd6bSKiran Patil 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_move_sched_elems,
456b126bd6bSKiran Patil 					   grps_req, (void *)buf, buf_size,
457b126bd6bSKiran Patil 					   grps_movd, cd);
458b126bd6bSKiran Patil }
459b126bd6bSKiran Patil 
460b126bd6bSKiran Patil /**
4615513b920SAnirudh Venkataramanan  * ice_aq_suspend_sched_elems - suspend scheduler elements
462f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
4635513b920SAnirudh Venkataramanan  * @elems_req: number of elements to suspend
4645513b920SAnirudh Venkataramanan  * @buf: pointer to buffer
4655513b920SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
4665513b920SAnirudh Venkataramanan  * @elems_ret: returns total number of elements suspended
4675513b920SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
4685513b920SAnirudh Venkataramanan  *
4695513b920SAnirudh Venkataramanan  * Suspend scheduling elements (0x0409)
4705513b920SAnirudh Venkataramanan  */
4715e24d598STony Nguyen static int
ice_aq_suspend_sched_elems(struct ice_hw * hw,u16 elems_req,__le32 * buf,u16 buf_size,u16 * elems_ret,struct ice_sq_cd * cd)472b3c38904SBruce Allan ice_aq_suspend_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf,
4735513b920SAnirudh Venkataramanan 			   u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)
4745513b920SAnirudh Venkataramanan {
4751f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_suspend_sched_elems,
4761f9c7840SAnirudh Venkataramanan 					   elems_req, (void *)buf, buf_size,
4771f9c7840SAnirudh Venkataramanan 					   elems_ret, cd);
4785513b920SAnirudh Venkataramanan }
4795513b920SAnirudh Venkataramanan 
4805513b920SAnirudh Venkataramanan /**
4815513b920SAnirudh Venkataramanan  * ice_aq_resume_sched_elems - resume scheduler elements
482f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
4835513b920SAnirudh Venkataramanan  * @elems_req: number of elements to resume
4845513b920SAnirudh Venkataramanan  * @buf: pointer to buffer
4855513b920SAnirudh Venkataramanan  * @buf_size: buffer size in bytes
4865513b920SAnirudh Venkataramanan  * @elems_ret: returns total number of elements resumed
4875513b920SAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
4885513b920SAnirudh Venkataramanan  *
4895513b920SAnirudh Venkataramanan  * resume scheduling elements (0x040A)
4905513b920SAnirudh Venkataramanan  */
4915e24d598STony Nguyen static int
ice_aq_resume_sched_elems(struct ice_hw * hw,u16 elems_req,__le32 * buf,u16 buf_size,u16 * elems_ret,struct ice_sq_cd * cd)492b3c38904SBruce Allan ice_aq_resume_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf,
4935513b920SAnirudh Venkataramanan 			  u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)
4945513b920SAnirudh Venkataramanan {
4951f9c7840SAnirudh Venkataramanan 	return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_resume_sched_elems,
4961f9c7840SAnirudh Venkataramanan 					   elems_req, (void *)buf, buf_size,
4971f9c7840SAnirudh Venkataramanan 					   elems_ret, cd);
4985513b920SAnirudh Venkataramanan }
4995513b920SAnirudh Venkataramanan 
5005513b920SAnirudh Venkataramanan /**
5019c20346bSAnirudh Venkataramanan  * ice_aq_query_sched_res - query scheduler resource
502f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
5039c20346bSAnirudh Venkataramanan  * @buf_size: buffer size in bytes
5049c20346bSAnirudh Venkataramanan  * @buf: pointer to buffer
5059c20346bSAnirudh Venkataramanan  * @cd: pointer to command details structure or NULL
5069c20346bSAnirudh Venkataramanan  *
5079c20346bSAnirudh Venkataramanan  * Query scheduler resource allocation (0x0412)
5089c20346bSAnirudh Venkataramanan  */
5095e24d598STony Nguyen static int
ice_aq_query_sched_res(struct ice_hw * hw,u16 buf_size,struct ice_aqc_query_txsched_res_resp * buf,struct ice_sq_cd * cd)5109c20346bSAnirudh Venkataramanan ice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size,
5119c20346bSAnirudh Venkataramanan 		       struct ice_aqc_query_txsched_res_resp *buf,
5129c20346bSAnirudh Venkataramanan 		       struct ice_sq_cd *cd)
5139c20346bSAnirudh Venkataramanan {
5149c20346bSAnirudh Venkataramanan 	struct ice_aq_desc desc;
5159c20346bSAnirudh Venkataramanan 
5169c20346bSAnirudh Venkataramanan 	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_sched_res);
5179c20346bSAnirudh Venkataramanan 	return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
5189c20346bSAnirudh Venkataramanan }
5199c20346bSAnirudh Venkataramanan 
5209c20346bSAnirudh Venkataramanan /**
521f9867df6SAnirudh Venkataramanan  * ice_sched_suspend_resume_elems - suspend or resume HW nodes
522f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
5235513b920SAnirudh Venkataramanan  * @num_nodes: number of nodes
5245513b920SAnirudh Venkataramanan  * @node_teids: array of node teids to be suspended or resumed
5255513b920SAnirudh Venkataramanan  * @suspend: true means suspend / false means resume
5265513b920SAnirudh Venkataramanan  *
527f9867df6SAnirudh Venkataramanan  * This function suspends or resumes HW nodes
5285513b920SAnirudh Venkataramanan  */
52923ccae5cSDave Ertman int
ice_sched_suspend_resume_elems(struct ice_hw * hw,u8 num_nodes,u32 * node_teids,bool suspend)5305513b920SAnirudh Venkataramanan ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids,
5315513b920SAnirudh Venkataramanan 			       bool suspend)
5325513b920SAnirudh Venkataramanan {
5335513b920SAnirudh Venkataramanan 	u16 i, buf_size, num_elem_ret = 0;
534b3c38904SBruce Allan 	__le32 *buf;
5355518ac2aSTony Nguyen 	int status;
5365513b920SAnirudh Venkataramanan 
5375513b920SAnirudh Venkataramanan 	buf_size = sizeof(*buf) * num_nodes;
5385513b920SAnirudh Venkataramanan 	buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);
5395513b920SAnirudh Venkataramanan 	if (!buf)
540d54699e2STony Nguyen 		return -ENOMEM;
5415513b920SAnirudh Venkataramanan 
5425513b920SAnirudh Venkataramanan 	for (i = 0; i < num_nodes; i++)
543b3c38904SBruce Allan 		buf[i] = cpu_to_le32(node_teids[i]);
5445513b920SAnirudh Venkataramanan 
5455513b920SAnirudh Venkataramanan 	if (suspend)
5465513b920SAnirudh Venkataramanan 		status = ice_aq_suspend_sched_elems(hw, num_nodes, buf,
5475513b920SAnirudh Venkataramanan 						    buf_size, &num_elem_ret,
5485513b920SAnirudh Venkataramanan 						    NULL);
5495513b920SAnirudh Venkataramanan 	else
5505513b920SAnirudh Venkataramanan 		status = ice_aq_resume_sched_elems(hw, num_nodes, buf,
5515513b920SAnirudh Venkataramanan 						   buf_size, &num_elem_ret,
5525513b920SAnirudh Venkataramanan 						   NULL);
5535513b920SAnirudh Venkataramanan 	if (status || num_elem_ret != num_nodes)
5545513b920SAnirudh Venkataramanan 		ice_debug(hw, ICE_DBG_SCHED, "suspend/resume failed\n");
5555513b920SAnirudh Venkataramanan 
5565513b920SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), buf);
5575513b920SAnirudh Venkataramanan 	return status;
5585513b920SAnirudh Venkataramanan }
5595513b920SAnirudh Venkataramanan 
5605513b920SAnirudh Venkataramanan /**
561bb87ee0eSAnirudh Venkataramanan  * ice_alloc_lan_q_ctx - allocate LAN queue contexts for the given VSI and TC
562bb87ee0eSAnirudh Venkataramanan  * @hw: pointer to the HW struct
563bb87ee0eSAnirudh Venkataramanan  * @vsi_handle: VSI handle
564bb87ee0eSAnirudh Venkataramanan  * @tc: TC number
565bb87ee0eSAnirudh Venkataramanan  * @new_numqs: number of queues
566bb87ee0eSAnirudh Venkataramanan  */
5675e24d598STony Nguyen static int
ice_alloc_lan_q_ctx(struct ice_hw * hw,u16 vsi_handle,u8 tc,u16 new_numqs)568bb87ee0eSAnirudh Venkataramanan ice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
569bb87ee0eSAnirudh Venkataramanan {
570bb87ee0eSAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
571bb87ee0eSAnirudh Venkataramanan 	struct ice_q_ctx *q_ctx;
572f3fbda33SJacob Keller 	u16 idx;
573bb87ee0eSAnirudh Venkataramanan 
574bb87ee0eSAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
575bb87ee0eSAnirudh Venkataramanan 	if (!vsi_ctx)
576d54699e2STony Nguyen 		return -EINVAL;
577bb87ee0eSAnirudh Venkataramanan 	/* allocate LAN queue contexts */
578bb87ee0eSAnirudh Venkataramanan 	if (!vsi_ctx->lan_q_ctx[tc]) {
579f3fbda33SJacob Keller 		q_ctx = devm_kcalloc(ice_hw_to_dev(hw), new_numqs,
580f3fbda33SJacob Keller 				     sizeof(*q_ctx), GFP_KERNEL);
581f3fbda33SJacob Keller 		if (!q_ctx)
582d54699e2STony Nguyen 			return -ENOMEM;
583f3fbda33SJacob Keller 
584f3fbda33SJacob Keller 		for (idx = 0; idx < new_numqs; idx++) {
585f3fbda33SJacob Keller 			q_ctx[idx].q_handle = ICE_INVAL_Q_HANDLE;
586f3fbda33SJacob Keller 			q_ctx[idx].q_teid = ICE_INVAL_TEID;
587f3fbda33SJacob Keller 		}
588f3fbda33SJacob Keller 
589f3fbda33SJacob Keller 		vsi_ctx->lan_q_ctx[tc] = q_ctx;
590bb87ee0eSAnirudh Venkataramanan 		vsi_ctx->num_lan_q_entries[tc] = new_numqs;
591bb87ee0eSAnirudh Venkataramanan 		return 0;
592bb87ee0eSAnirudh Venkataramanan 	}
593bb87ee0eSAnirudh Venkataramanan 	/* num queues are increased, update the queue contexts */
594bb87ee0eSAnirudh Venkataramanan 	if (new_numqs > vsi_ctx->num_lan_q_entries[tc]) {
595bb87ee0eSAnirudh Venkataramanan 		u16 prev_num = vsi_ctx->num_lan_q_entries[tc];
596bb87ee0eSAnirudh Venkataramanan 
597bb87ee0eSAnirudh Venkataramanan 		q_ctx = devm_kcalloc(ice_hw_to_dev(hw), new_numqs,
598bb87ee0eSAnirudh Venkataramanan 				     sizeof(*q_ctx), GFP_KERNEL);
599bb87ee0eSAnirudh Venkataramanan 		if (!q_ctx)
600d54699e2STony Nguyen 			return -ENOMEM;
601f3fbda33SJacob Keller 
602bb87ee0eSAnirudh Venkataramanan 		memcpy(q_ctx, vsi_ctx->lan_q_ctx[tc],
603bb87ee0eSAnirudh Venkataramanan 		       prev_num * sizeof(*q_ctx));
604bb87ee0eSAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), vsi_ctx->lan_q_ctx[tc]);
605f3fbda33SJacob Keller 
606f3fbda33SJacob Keller 		for (idx = prev_num; idx < new_numqs; idx++) {
607f3fbda33SJacob Keller 			q_ctx[idx].q_handle = ICE_INVAL_Q_HANDLE;
608f3fbda33SJacob Keller 			q_ctx[idx].q_teid = ICE_INVAL_TEID;
609f3fbda33SJacob Keller 		}
610f3fbda33SJacob Keller 
611bb87ee0eSAnirudh Venkataramanan 		vsi_ctx->lan_q_ctx[tc] = q_ctx;
612bb87ee0eSAnirudh Venkataramanan 		vsi_ctx->num_lan_q_entries[tc] = new_numqs;
613bb87ee0eSAnirudh Venkataramanan 	}
614bb87ee0eSAnirudh Venkataramanan 	return 0;
615bb87ee0eSAnirudh Venkataramanan }
616bb87ee0eSAnirudh Venkataramanan 
617bb87ee0eSAnirudh Venkataramanan /**
618348048e7SDave Ertman  * ice_alloc_rdma_q_ctx - allocate RDMA queue contexts for the given VSI and TC
619348048e7SDave Ertman  * @hw: pointer to the HW struct
620348048e7SDave Ertman  * @vsi_handle: VSI handle
621348048e7SDave Ertman  * @tc: TC number
622348048e7SDave Ertman  * @new_numqs: number of queues
623348048e7SDave Ertman  */
6245e24d598STony Nguyen static int
ice_alloc_rdma_q_ctx(struct ice_hw * hw,u16 vsi_handle,u8 tc,u16 new_numqs)625348048e7SDave Ertman ice_alloc_rdma_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
626348048e7SDave Ertman {
627348048e7SDave Ertman 	struct ice_vsi_ctx *vsi_ctx;
628348048e7SDave Ertman 	struct ice_q_ctx *q_ctx;
629348048e7SDave Ertman 
630348048e7SDave Ertman 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
631348048e7SDave Ertman 	if (!vsi_ctx)
632d54699e2STony Nguyen 		return -EINVAL;
633348048e7SDave Ertman 	/* allocate RDMA queue contexts */
634348048e7SDave Ertman 	if (!vsi_ctx->rdma_q_ctx[tc]) {
635348048e7SDave Ertman 		vsi_ctx->rdma_q_ctx[tc] = devm_kcalloc(ice_hw_to_dev(hw),
636348048e7SDave Ertman 						       new_numqs,
637348048e7SDave Ertman 						       sizeof(*q_ctx),
638348048e7SDave Ertman 						       GFP_KERNEL);
639348048e7SDave Ertman 		if (!vsi_ctx->rdma_q_ctx[tc])
640d54699e2STony Nguyen 			return -ENOMEM;
641348048e7SDave Ertman 		vsi_ctx->num_rdma_q_entries[tc] = new_numqs;
642348048e7SDave Ertman 		return 0;
643348048e7SDave Ertman 	}
644348048e7SDave Ertman 	/* num queues are increased, update the queue contexts */
645348048e7SDave Ertman 	if (new_numqs > vsi_ctx->num_rdma_q_entries[tc]) {
646348048e7SDave Ertman 		u16 prev_num = vsi_ctx->num_rdma_q_entries[tc];
647348048e7SDave Ertman 
648348048e7SDave Ertman 		q_ctx = devm_kcalloc(ice_hw_to_dev(hw), new_numqs,
649348048e7SDave Ertman 				     sizeof(*q_ctx), GFP_KERNEL);
650348048e7SDave Ertman 		if (!q_ctx)
651d54699e2STony Nguyen 			return -ENOMEM;
652348048e7SDave Ertman 		memcpy(q_ctx, vsi_ctx->rdma_q_ctx[tc],
653348048e7SDave Ertman 		       prev_num * sizeof(*q_ctx));
654348048e7SDave Ertman 		devm_kfree(ice_hw_to_dev(hw), vsi_ctx->rdma_q_ctx[tc]);
655348048e7SDave Ertman 		vsi_ctx->rdma_q_ctx[tc] = q_ctx;
656348048e7SDave Ertman 		vsi_ctx->num_rdma_q_entries[tc] = new_numqs;
657348048e7SDave Ertman 	}
658348048e7SDave Ertman 	return 0;
659348048e7SDave Ertman }
660348048e7SDave Ertman 
661348048e7SDave Ertman /**
6621ddef455SUsha Ketineni  * ice_aq_rl_profile - performs a rate limiting task
6631ddef455SUsha Ketineni  * @hw: pointer to the HW struct
6641ddef455SUsha Ketineni  * @opcode: opcode for add, query, or remove profile(s)
6651ddef455SUsha Ketineni  * @num_profiles: the number of profiles
6661ddef455SUsha Ketineni  * @buf: pointer to buffer
6671ddef455SUsha Ketineni  * @buf_size: buffer size in bytes
6681ddef455SUsha Ketineni  * @num_processed: number of processed add or remove profile(s) to return
6691ddef455SUsha Ketineni  * @cd: pointer to command details structure
6701ddef455SUsha Ketineni  *
6711ddef455SUsha Ketineni  * RL profile function to add, query, or remove profile(s)
6721ddef455SUsha Ketineni  */
6735e24d598STony Nguyen static int
ice_aq_rl_profile(struct ice_hw * hw,enum ice_adminq_opc opcode,u16 num_profiles,struct ice_aqc_rl_profile_elem * buf,u16 buf_size,u16 * num_processed,struct ice_sq_cd * cd)6741ddef455SUsha Ketineni ice_aq_rl_profile(struct ice_hw *hw, enum ice_adminq_opc opcode,
675b3c38904SBruce Allan 		  u16 num_profiles, struct ice_aqc_rl_profile_elem *buf,
6761ddef455SUsha Ketineni 		  u16 buf_size, u16 *num_processed, struct ice_sq_cd *cd)
6771ddef455SUsha Ketineni {
6781ddef455SUsha Ketineni 	struct ice_aqc_rl_profile *cmd;
6791ddef455SUsha Ketineni 	struct ice_aq_desc desc;
6805e24d598STony Nguyen 	int status;
6811ddef455SUsha Ketineni 
6821ddef455SUsha Ketineni 	cmd = &desc.params.rl_profile;
6831ddef455SUsha Ketineni 
6841ddef455SUsha Ketineni 	ice_fill_dflt_direct_cmd_desc(&desc, opcode);
6851ddef455SUsha Ketineni 	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
6861ddef455SUsha Ketineni 	cmd->num_profiles = cpu_to_le16(num_profiles);
6871ddef455SUsha Ketineni 	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
6881ddef455SUsha Ketineni 	if (!status && num_processed)
6891ddef455SUsha Ketineni 		*num_processed = le16_to_cpu(cmd->num_processed);
6901ddef455SUsha Ketineni 	return status;
6911ddef455SUsha Ketineni }
6921ddef455SUsha Ketineni 
6931ddef455SUsha Ketineni /**
6941ddef455SUsha Ketineni  * ice_aq_add_rl_profile - adds rate limiting profile(s)
6951ddef455SUsha Ketineni  * @hw: pointer to the HW struct
6961ddef455SUsha Ketineni  * @num_profiles: the number of profile(s) to be add
6971ddef455SUsha Ketineni  * @buf: pointer to buffer
6981ddef455SUsha Ketineni  * @buf_size: buffer size in bytes
6991ddef455SUsha Ketineni  * @num_profiles_added: total number of profiles added to return
7001ddef455SUsha Ketineni  * @cd: pointer to command details structure
7011ddef455SUsha Ketineni  *
7021ddef455SUsha Ketineni  * Add RL profile (0x0410)
7031ddef455SUsha Ketineni  */
7045e24d598STony Nguyen static int
ice_aq_add_rl_profile(struct ice_hw * hw,u16 num_profiles,struct ice_aqc_rl_profile_elem * buf,u16 buf_size,u16 * num_profiles_added,struct ice_sq_cd * cd)7051ddef455SUsha Ketineni ice_aq_add_rl_profile(struct ice_hw *hw, u16 num_profiles,
706b3c38904SBruce Allan 		      struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
707b3c38904SBruce Allan 		      u16 *num_profiles_added, struct ice_sq_cd *cd)
7081ddef455SUsha Ketineni {
709b3c38904SBruce Allan 	return ice_aq_rl_profile(hw, ice_aqc_opc_add_rl_profiles, num_profiles,
710b3c38904SBruce Allan 				 buf, buf_size, num_profiles_added, cd);
7111ddef455SUsha Ketineni }
7121ddef455SUsha Ketineni 
7131ddef455SUsha Ketineni /**
7141ddef455SUsha Ketineni  * ice_aq_remove_rl_profile - removes RL profile(s)
7151ddef455SUsha Ketineni  * @hw: pointer to the HW struct
7161ddef455SUsha Ketineni  * @num_profiles: the number of profile(s) to remove
7171ddef455SUsha Ketineni  * @buf: pointer to buffer
7181ddef455SUsha Ketineni  * @buf_size: buffer size in bytes
7191ddef455SUsha Ketineni  * @num_profiles_removed: total number of profiles removed to return
7201ddef455SUsha Ketineni  * @cd: pointer to command details structure or NULL
7211ddef455SUsha Ketineni  *
7221ddef455SUsha Ketineni  * Remove RL profile (0x0415)
7231ddef455SUsha Ketineni  */
7245e24d598STony Nguyen static int
ice_aq_remove_rl_profile(struct ice_hw * hw,u16 num_profiles,struct ice_aqc_rl_profile_elem * buf,u16 buf_size,u16 * num_profiles_removed,struct ice_sq_cd * cd)7251ddef455SUsha Ketineni ice_aq_remove_rl_profile(struct ice_hw *hw, u16 num_profiles,
726b3c38904SBruce Allan 			 struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
727b3c38904SBruce Allan 			 u16 *num_profiles_removed, struct ice_sq_cd *cd)
7281ddef455SUsha Ketineni {
7291ddef455SUsha Ketineni 	return ice_aq_rl_profile(hw, ice_aqc_opc_remove_rl_profiles,
730b3c38904SBruce Allan 				 num_profiles, buf, buf_size,
731b3c38904SBruce Allan 				 num_profiles_removed, cd);
7321ddef455SUsha Ketineni }
7331ddef455SUsha Ketineni 
7341ddef455SUsha Ketineni /**
7351ddef455SUsha Ketineni  * ice_sched_del_rl_profile - remove RL profile
7361ddef455SUsha Ketineni  * @hw: pointer to the HW struct
7371ddef455SUsha Ketineni  * @rl_info: rate limit profile information
7381ddef455SUsha Ketineni  *
7391ddef455SUsha Ketineni  * If the profile ID is not referenced anymore, it removes profile ID with
7401ddef455SUsha Ketineni  * its associated parameters from HW DB,and locally. The caller needs to
7411ddef455SUsha Ketineni  * hold scheduler lock.
7421ddef455SUsha Ketineni  */
7435e24d598STony Nguyen static int
ice_sched_del_rl_profile(struct ice_hw * hw,struct ice_aqc_rl_profile_info * rl_info)7441ddef455SUsha Ketineni ice_sched_del_rl_profile(struct ice_hw *hw,
7451ddef455SUsha Ketineni 			 struct ice_aqc_rl_profile_info *rl_info)
7461ddef455SUsha Ketineni {
747b3c38904SBruce Allan 	struct ice_aqc_rl_profile_elem *buf;
7481ddef455SUsha Ketineni 	u16 num_profiles_removed;
7491ddef455SUsha Ketineni 	u16 num_profiles = 1;
7505518ac2aSTony Nguyen 	int status;
7511ddef455SUsha Ketineni 
7521ddef455SUsha Ketineni 	if (rl_info->prof_id_ref != 0)
753d54699e2STony Nguyen 		return -EBUSY;
7541ddef455SUsha Ketineni 
7551ddef455SUsha Ketineni 	/* Safe to remove profile ID */
756b3c38904SBruce Allan 	buf = &rl_info->profile;
7571ddef455SUsha Ketineni 	status = ice_aq_remove_rl_profile(hw, num_profiles, buf, sizeof(*buf),
7581ddef455SUsha Ketineni 					  &num_profiles_removed, NULL);
7591ddef455SUsha Ketineni 	if (status || num_profiles_removed != num_profiles)
760d54699e2STony Nguyen 		return -EIO;
7611ddef455SUsha Ketineni 
7621ddef455SUsha Ketineni 	/* Delete stale entry now */
7631ddef455SUsha Ketineni 	list_del(&rl_info->list_entry);
7641ddef455SUsha Ketineni 	devm_kfree(ice_hw_to_dev(hw), rl_info);
7651ddef455SUsha Ketineni 	return status;
7661ddef455SUsha Ketineni }
7671ddef455SUsha Ketineni 
7681ddef455SUsha Ketineni /**
7691ddef455SUsha Ketineni  * ice_sched_clear_rl_prof - clears RL prof entries
7701ddef455SUsha Ketineni  * @pi: port information structure
7711ddef455SUsha Ketineni  *
7721ddef455SUsha Ketineni  * This function removes all RL profile from HW as well as from SW DB.
7731ddef455SUsha Ketineni  */
ice_sched_clear_rl_prof(struct ice_port_info * pi)7741ddef455SUsha Ketineni static void ice_sched_clear_rl_prof(struct ice_port_info *pi)
7751ddef455SUsha Ketineni {
7761ddef455SUsha Ketineni 	u16 ln;
7771ddef455SUsha Ketineni 
7781ddef455SUsha Ketineni 	for (ln = 0; ln < pi->hw->num_tx_sched_layers; ln++) {
7791ddef455SUsha Ketineni 		struct ice_aqc_rl_profile_info *rl_prof_elem;
7801ddef455SUsha Ketineni 		struct ice_aqc_rl_profile_info *rl_prof_tmp;
7811ddef455SUsha Ketineni 
7821ddef455SUsha Ketineni 		list_for_each_entry_safe(rl_prof_elem, rl_prof_tmp,
7831ddef455SUsha Ketineni 					 &pi->rl_prof_list[ln], list_entry) {
7841ddef455SUsha Ketineni 			struct ice_hw *hw = pi->hw;
7855e24d598STony Nguyen 			int status;
7861ddef455SUsha Ketineni 
7871ddef455SUsha Ketineni 			rl_prof_elem->prof_id_ref = 0;
7881ddef455SUsha Ketineni 			status = ice_sched_del_rl_profile(hw, rl_prof_elem);
7891ddef455SUsha Ketineni 			if (status) {
7909228d8b2SJacob Keller 				ice_debug(hw, ICE_DBG_SCHED, "Remove rl profile failed\n");
7911ddef455SUsha Ketineni 				/* On error, free mem required */
7921ddef455SUsha Ketineni 				list_del(&rl_prof_elem->list_entry);
7931ddef455SUsha Ketineni 				devm_kfree(ice_hw_to_dev(hw), rl_prof_elem);
7941ddef455SUsha Ketineni 			}
7951ddef455SUsha Ketineni 		}
7961ddef455SUsha Ketineni 	}
7971ddef455SUsha Ketineni }
7981ddef455SUsha Ketineni 
7991ddef455SUsha Ketineni /**
800f9867df6SAnirudh Venkataramanan  * ice_sched_clear_agg - clears the aggregator related information
8019be1d6f8SAnirudh Venkataramanan  * @hw: pointer to the hardware structure
8029c20346bSAnirudh Venkataramanan  *
803f9867df6SAnirudh Venkataramanan  * This function removes aggregator list and free up aggregator related memory
8049be1d6f8SAnirudh Venkataramanan  * previously allocated.
8059c20346bSAnirudh Venkataramanan  */
ice_sched_clear_agg(struct ice_hw * hw)8069be1d6f8SAnirudh Venkataramanan void ice_sched_clear_agg(struct ice_hw *hw)
8079c20346bSAnirudh Venkataramanan {
8089c20346bSAnirudh Venkataramanan 	struct ice_sched_agg_info *agg_info;
8099c20346bSAnirudh Venkataramanan 	struct ice_sched_agg_info *atmp;
8109c20346bSAnirudh Venkataramanan 
8119be1d6f8SAnirudh Venkataramanan 	list_for_each_entry_safe(agg_info, atmp, &hw->agg_list, list_entry) {
8129c20346bSAnirudh Venkataramanan 		struct ice_sched_agg_vsi_info *agg_vsi_info;
8139c20346bSAnirudh Venkataramanan 		struct ice_sched_agg_vsi_info *vtmp;
8149c20346bSAnirudh Venkataramanan 
8159c20346bSAnirudh Venkataramanan 		list_for_each_entry_safe(agg_vsi_info, vtmp,
8169c20346bSAnirudh Venkataramanan 					 &agg_info->agg_vsi_list, list_entry) {
8179c20346bSAnirudh Venkataramanan 			list_del(&agg_vsi_info->list_entry);
8189c20346bSAnirudh Venkataramanan 			devm_kfree(ice_hw_to_dev(hw), agg_vsi_info);
8199c20346bSAnirudh Venkataramanan 		}
8209be1d6f8SAnirudh Venkataramanan 		list_del(&agg_info->list_entry);
8219be1d6f8SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), agg_info);
8229be1d6f8SAnirudh Venkataramanan 	}
8239c20346bSAnirudh Venkataramanan }
8249c20346bSAnirudh Venkataramanan 
8259be1d6f8SAnirudh Venkataramanan /**
8269be1d6f8SAnirudh Venkataramanan  * ice_sched_clear_tx_topo - clears the scheduler tree nodes
8279be1d6f8SAnirudh Venkataramanan  * @pi: port information structure
8289be1d6f8SAnirudh Venkataramanan  *
8299be1d6f8SAnirudh Venkataramanan  * This function removes all the nodes from HW as well as from SW DB.
8309be1d6f8SAnirudh Venkataramanan  */
ice_sched_clear_tx_topo(struct ice_port_info * pi)8319be1d6f8SAnirudh Venkataramanan static void ice_sched_clear_tx_topo(struct ice_port_info *pi)
8329be1d6f8SAnirudh Venkataramanan {
8339be1d6f8SAnirudh Venkataramanan 	if (!pi)
8349be1d6f8SAnirudh Venkataramanan 		return;
8351ddef455SUsha Ketineni 	/* remove RL profiles related lists */
8361ddef455SUsha Ketineni 	ice_sched_clear_rl_prof(pi);
8379c20346bSAnirudh Venkataramanan 	if (pi->root) {
8389c20346bSAnirudh Venkataramanan 		ice_free_sched_node(pi, pi->root);
8399c20346bSAnirudh Venkataramanan 		pi->root = NULL;
8409c20346bSAnirudh Venkataramanan 	}
8419c20346bSAnirudh Venkataramanan }
8429c20346bSAnirudh Venkataramanan 
8439c20346bSAnirudh Venkataramanan /**
8449c20346bSAnirudh Venkataramanan  * ice_sched_clear_port - clear the scheduler elements from SW DB for a port
8459c20346bSAnirudh Venkataramanan  * @pi: port information structure
8469c20346bSAnirudh Venkataramanan  *
8479c20346bSAnirudh Venkataramanan  * Cleanup scheduling elements from SW DB
8489c20346bSAnirudh Venkataramanan  */
ice_sched_clear_port(struct ice_port_info * pi)849c5a2a4a3SUsha Ketineni void ice_sched_clear_port(struct ice_port_info *pi)
8509c20346bSAnirudh Venkataramanan {
8519c20346bSAnirudh Venkataramanan 	if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
8529c20346bSAnirudh Venkataramanan 		return;
8539c20346bSAnirudh Venkataramanan 
8549c20346bSAnirudh Venkataramanan 	pi->port_state = ICE_SCHED_PORT_STATE_INIT;
8559c20346bSAnirudh Venkataramanan 	mutex_lock(&pi->sched_lock);
8569c20346bSAnirudh Venkataramanan 	ice_sched_clear_tx_topo(pi);
8579c20346bSAnirudh Venkataramanan 	mutex_unlock(&pi->sched_lock);
8589c20346bSAnirudh Venkataramanan 	mutex_destroy(&pi->sched_lock);
8599c20346bSAnirudh Venkataramanan }
8609c20346bSAnirudh Venkataramanan 
8619c20346bSAnirudh Venkataramanan /**
8629c20346bSAnirudh Venkataramanan  * ice_sched_cleanup_all - cleanup scheduler elements from SW DB for all ports
863f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
8649c20346bSAnirudh Venkataramanan  *
8659c20346bSAnirudh Venkataramanan  * Cleanup scheduling elements from SW DB for all the ports
8669c20346bSAnirudh Venkataramanan  */
ice_sched_cleanup_all(struct ice_hw * hw)8679c20346bSAnirudh Venkataramanan void ice_sched_cleanup_all(struct ice_hw *hw)
8689c20346bSAnirudh Venkataramanan {
869b36c598cSAnirudh Venkataramanan 	if (!hw)
8709c20346bSAnirudh Venkataramanan 		return;
8719c20346bSAnirudh Venkataramanan 
8729c20346bSAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), hw->layer_info);
873b36c598cSAnirudh Venkataramanan 	hw->layer_info = NULL;
8749c20346bSAnirudh Venkataramanan 
8759c20346bSAnirudh Venkataramanan 	ice_sched_clear_port(hw->port_info);
8769c20346bSAnirudh Venkataramanan 
8779c20346bSAnirudh Venkataramanan 	hw->num_tx_sched_layers = 0;
8789c20346bSAnirudh Venkataramanan 	hw->num_tx_sched_phys_layers = 0;
8799c20346bSAnirudh Venkataramanan 	hw->flattened_layers = 0;
8809c20346bSAnirudh Venkataramanan 	hw->max_cgds = 0;
8819c20346bSAnirudh Venkataramanan }
8829c20346bSAnirudh Venkataramanan 
8839c20346bSAnirudh Venkataramanan /**
884f9867df6SAnirudh Venkataramanan  * ice_sched_add_elems - add nodes to HW and SW DB
8855513b920SAnirudh Venkataramanan  * @pi: port information structure
8865513b920SAnirudh Venkataramanan  * @tc_node: pointer to the branch node
8875513b920SAnirudh Venkataramanan  * @parent: pointer to the parent node
8885513b920SAnirudh Venkataramanan  * @layer: layer number to add nodes
8895513b920SAnirudh Venkataramanan  * @num_nodes: number of nodes
8905513b920SAnirudh Venkataramanan  * @num_nodes_added: pointer to num nodes added
891f9867df6SAnirudh Venkataramanan  * @first_node_teid: if new nodes are added then return the TEID of first node
892bdf96d96SMichal Wilczynski  * @prealloc_nodes: preallocated nodes struct for software DB
8935513b920SAnirudh Venkataramanan  *
894f9867df6SAnirudh Venkataramanan  * This function add nodes to HW as well as to SW DB for a given layer
8955513b920SAnirudh Venkataramanan  */
89616dfa494SMichal Wilczynski int
ice_sched_add_elems(struct ice_port_info * pi,struct ice_sched_node * tc_node,struct ice_sched_node * parent,u8 layer,u16 num_nodes,u16 * num_nodes_added,u32 * first_node_teid,struct ice_sched_node ** prealloc_nodes)8975513b920SAnirudh Venkataramanan ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
8985513b920SAnirudh Venkataramanan 		    struct ice_sched_node *parent, u8 layer, u16 num_nodes,
899bdf96d96SMichal Wilczynski 		    u16 *num_nodes_added, u32 *first_node_teid,
900bdf96d96SMichal Wilczynski 		    struct ice_sched_node **prealloc_nodes)
9015513b920SAnirudh Venkataramanan {
9025513b920SAnirudh Venkataramanan 	struct ice_sched_node *prev, *new_node;
9035513b920SAnirudh Venkataramanan 	struct ice_aqc_add_elem *buf;
9045513b920SAnirudh Venkataramanan 	u16 i, num_groups_added = 0;
9055513b920SAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
90689f6a305SGustavo A. R. Silva 	size_t buf_size;
9075518ac2aSTony Nguyen 	int status = 0;
9085513b920SAnirudh Venkataramanan 	u32 teid;
9095513b920SAnirudh Venkataramanan 
91066486d89SBruce Allan 	buf_size = struct_size(buf, generic, num_nodes);
9115513b920SAnirudh Venkataramanan 	buf = devm_kzalloc(ice_hw_to_dev(hw), buf_size, GFP_KERNEL);
9125513b920SAnirudh Venkataramanan 	if (!buf)
913d54699e2STony Nguyen 		return -ENOMEM;
9145513b920SAnirudh Venkataramanan 
9155513b920SAnirudh Venkataramanan 	buf->hdr.parent_teid = parent->info.node_teid;
9165513b920SAnirudh Venkataramanan 	buf->hdr.num_elems = cpu_to_le16(num_nodes);
9175513b920SAnirudh Venkataramanan 	for (i = 0; i < num_nodes; i++) {
9185513b920SAnirudh Venkataramanan 		buf->generic[i].parent_teid = parent->info.node_teid;
9195513b920SAnirudh Venkataramanan 		buf->generic[i].data.elem_type = ICE_AQC_ELEM_TYPE_SE_GENERIC;
9205513b920SAnirudh Venkataramanan 		buf->generic[i].data.valid_sections =
9215513b920SAnirudh Venkataramanan 			ICE_AQC_ELEM_VALID_GENERIC | ICE_AQC_ELEM_VALID_CIR |
9225513b920SAnirudh Venkataramanan 			ICE_AQC_ELEM_VALID_EIR;
9235513b920SAnirudh Venkataramanan 		buf->generic[i].data.generic = 0;
9245513b920SAnirudh Venkataramanan 		buf->generic[i].data.cir_bw.bw_profile_idx =
925b36c598cSAnirudh Venkataramanan 			cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
926b36c598cSAnirudh Venkataramanan 		buf->generic[i].data.cir_bw.bw_alloc =
927b36c598cSAnirudh Venkataramanan 			cpu_to_le16(ICE_SCHED_DFLT_BW_WT);
9285513b920SAnirudh Venkataramanan 		buf->generic[i].data.eir_bw.bw_profile_idx =
929b36c598cSAnirudh Venkataramanan 			cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
930b36c598cSAnirudh Venkataramanan 		buf->generic[i].data.eir_bw.bw_alloc =
931b36c598cSAnirudh Venkataramanan 			cpu_to_le16(ICE_SCHED_DFLT_BW_WT);
9325513b920SAnirudh Venkataramanan 	}
9335513b920SAnirudh Venkataramanan 
9345513b920SAnirudh Venkataramanan 	status = ice_aq_add_sched_elems(hw, 1, buf, buf_size,
9355513b920SAnirudh Venkataramanan 					&num_groups_added, NULL);
9365513b920SAnirudh Venkataramanan 	if (status || num_groups_added != 1) {
937e1ca65a3SVictor Raj 		ice_debug(hw, ICE_DBG_SCHED, "add node failed FW Error %d\n",
938e1ca65a3SVictor Raj 			  hw->adminq.sq_last_status);
9395513b920SAnirudh Venkataramanan 		devm_kfree(ice_hw_to_dev(hw), buf);
940d54699e2STony Nguyen 		return -EIO;
9415513b920SAnirudh Venkataramanan 	}
9425513b920SAnirudh Venkataramanan 
9435513b920SAnirudh Venkataramanan 	*num_nodes_added = num_nodes;
9445513b920SAnirudh Venkataramanan 	/* add nodes to the SW DB */
9455513b920SAnirudh Venkataramanan 	for (i = 0; i < num_nodes; i++) {
946bdf96d96SMichal Wilczynski 		if (prealloc_nodes)
947bdf96d96SMichal Wilczynski 			status = ice_sched_add_node(pi, layer, &buf->generic[i], prealloc_nodes[i]);
948bdf96d96SMichal Wilczynski 		else
949bdf96d96SMichal Wilczynski 			status = ice_sched_add_node(pi, layer, &buf->generic[i], NULL);
950bdf96d96SMichal Wilczynski 
9515513b920SAnirudh Venkataramanan 		if (status) {
9529228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_SCHED, "add nodes in SW DB failed status =%d\n",
9535513b920SAnirudh Venkataramanan 				  status);
9545513b920SAnirudh Venkataramanan 			break;
9555513b920SAnirudh Venkataramanan 		}
9565513b920SAnirudh Venkataramanan 
9575513b920SAnirudh Venkataramanan 		teid = le32_to_cpu(buf->generic[i].node_teid);
9585513b920SAnirudh Venkataramanan 		new_node = ice_sched_find_node_by_teid(parent, teid);
9595513b920SAnirudh Venkataramanan 		if (!new_node) {
9609228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_SCHED, "Node is missing for teid =%d\n", teid);
9615513b920SAnirudh Venkataramanan 			break;
9625513b920SAnirudh Venkataramanan 		}
9635513b920SAnirudh Venkataramanan 
9645513b920SAnirudh Venkataramanan 		new_node->sibling = NULL;
9655513b920SAnirudh Venkataramanan 		new_node->tc_num = tc_node->tc_num;
96616dfa494SMichal Wilczynski 		new_node->tx_weight = ICE_SCHED_DFLT_BW_WT;
96716dfa494SMichal Wilczynski 		new_node->tx_share = ICE_SCHED_DFLT_BW;
96816dfa494SMichal Wilczynski 		new_node->tx_max = ICE_SCHED_DFLT_BW;
96916dfa494SMichal Wilczynski 		new_node->name = kzalloc(SCHED_NODE_NAME_MAX_LEN, GFP_KERNEL);
97016dfa494SMichal Wilczynski 		if (!new_node->name)
97116dfa494SMichal Wilczynski 			return -ENOMEM;
97216dfa494SMichal Wilczynski 
97316dfa494SMichal Wilczynski 		status = xa_alloc(&pi->sched_node_ids, &new_node->id, NULL, XA_LIMIT(0, UINT_MAX),
97416dfa494SMichal Wilczynski 				  GFP_KERNEL);
97516dfa494SMichal Wilczynski 		if (status) {
97616dfa494SMichal Wilczynski 			ice_debug(hw, ICE_DBG_SCHED, "xa_alloc failed for sched node status =%d\n",
97716dfa494SMichal Wilczynski 				  status);
97816dfa494SMichal Wilczynski 			break;
97916dfa494SMichal Wilczynski 		}
98016dfa494SMichal Wilczynski 
98116dfa494SMichal Wilczynski 		snprintf(new_node->name, SCHED_NODE_NAME_MAX_LEN, "node_%u", new_node->id);
9825513b920SAnirudh Venkataramanan 
9835513b920SAnirudh Venkataramanan 		/* add it to previous node sibling pointer */
9845513b920SAnirudh Venkataramanan 		/* Note: siblings are not linked across branches */
98529358248SVictor Raj 		prev = ice_sched_get_first_node(pi, tc_node, layer);
9865513b920SAnirudh Venkataramanan 		if (prev && prev != new_node) {
9875513b920SAnirudh Venkataramanan 			while (prev->sibling)
9885513b920SAnirudh Venkataramanan 				prev = prev->sibling;
9895513b920SAnirudh Venkataramanan 			prev->sibling = new_node;
9905513b920SAnirudh Venkataramanan 		}
9915513b920SAnirudh Venkataramanan 
99229358248SVictor Raj 		/* initialize the sibling head */
99329358248SVictor Raj 		if (!pi->sib_head[tc_node->tc_num][layer])
99429358248SVictor Raj 			pi->sib_head[tc_node->tc_num][layer] = new_node;
99529358248SVictor Raj 
9965513b920SAnirudh Venkataramanan 		if (i == 0)
9975513b920SAnirudh Venkataramanan 			*first_node_teid = teid;
9985513b920SAnirudh Venkataramanan 	}
9995513b920SAnirudh Venkataramanan 
10005513b920SAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), buf);
10015513b920SAnirudh Venkataramanan 	return status;
10025513b920SAnirudh Venkataramanan }
10035513b920SAnirudh Venkataramanan 
10045513b920SAnirudh Venkataramanan /**
10057fb09a73SVictor Raj  * ice_sched_add_nodes_to_hw_layer - Add nodes to HW layer
10067fb09a73SVictor Raj  * @pi: port information structure
10077fb09a73SVictor Raj  * @tc_node: pointer to TC node
10087fb09a73SVictor Raj  * @parent: pointer to parent node
10097fb09a73SVictor Raj  * @layer: layer number to add nodes
10107fb09a73SVictor Raj  * @num_nodes: number of nodes to be added
10117fb09a73SVictor Raj  * @first_node_teid: pointer to the first node TEID
10127fb09a73SVictor Raj  * @num_nodes_added: pointer to number of nodes added
10137fb09a73SVictor Raj  *
10147fb09a73SVictor Raj  * Add nodes into specific HW layer.
10157fb09a73SVictor Raj  */
10165e24d598STony Nguyen static int
ice_sched_add_nodes_to_hw_layer(struct ice_port_info * pi,struct ice_sched_node * tc_node,struct ice_sched_node * parent,u8 layer,u16 num_nodes,u32 * first_node_teid,u16 * num_nodes_added)10177fb09a73SVictor Raj ice_sched_add_nodes_to_hw_layer(struct ice_port_info *pi,
10187fb09a73SVictor Raj 				struct ice_sched_node *tc_node,
10197fb09a73SVictor Raj 				struct ice_sched_node *parent, u8 layer,
10207fb09a73SVictor Raj 				u16 num_nodes, u32 *first_node_teid,
10217fb09a73SVictor Raj 				u16 *num_nodes_added)
10227fb09a73SVictor Raj {
10237fb09a73SVictor Raj 	u16 max_child_nodes;
10247fb09a73SVictor Raj 
10257fb09a73SVictor Raj 	*num_nodes_added = 0;
10267fb09a73SVictor Raj 
10277fb09a73SVictor Raj 	if (!num_nodes)
10287fb09a73SVictor Raj 		return 0;
10297fb09a73SVictor Raj 
10307fb09a73SVictor Raj 	if (!parent || layer < pi->hw->sw_entry_point_layer)
1031d54699e2STony Nguyen 		return -EINVAL;
10327fb09a73SVictor Raj 
10337fb09a73SVictor Raj 	/* max children per node per layer */
10347fb09a73SVictor Raj 	max_child_nodes = pi->hw->max_children[parent->tx_sched_layer];
10357fb09a73SVictor Raj 
10367fb09a73SVictor Raj 	/* current number of children + required nodes exceed max children */
10377fb09a73SVictor Raj 	if ((parent->num_children + num_nodes) > max_child_nodes) {
10387fb09a73SVictor Raj 		/* Fail if the parent is a TC node */
10397fb09a73SVictor Raj 		if (parent == tc_node)
1040d54699e2STony Nguyen 			return -EIO;
1041d54699e2STony Nguyen 		return -ENOSPC;
10427fb09a73SVictor Raj 	}
10437fb09a73SVictor Raj 
10447fb09a73SVictor Raj 	return ice_sched_add_elems(pi, tc_node, parent, layer, num_nodes,
1045bdf96d96SMichal Wilczynski 				   num_nodes_added, first_node_teid, NULL);
10467fb09a73SVictor Raj }
10477fb09a73SVictor Raj 
10487fb09a73SVictor Raj /**
10495513b920SAnirudh Venkataramanan  * ice_sched_add_nodes_to_layer - Add nodes to a given layer
10505513b920SAnirudh Venkataramanan  * @pi: port information structure
10515513b920SAnirudh Venkataramanan  * @tc_node: pointer to TC node
10525513b920SAnirudh Venkataramanan  * @parent: pointer to parent node
10535513b920SAnirudh Venkataramanan  * @layer: layer number to add nodes
10545513b920SAnirudh Venkataramanan  * @num_nodes: number of nodes to be added
1055f9867df6SAnirudh Venkataramanan  * @first_node_teid: pointer to the first node TEID
10565513b920SAnirudh Venkataramanan  * @num_nodes_added: pointer to number of nodes added
10575513b920SAnirudh Venkataramanan  *
10585513b920SAnirudh Venkataramanan  * This function add nodes to a given layer.
10595513b920SAnirudh Venkataramanan  */
106023ccae5cSDave Ertman int
ice_sched_add_nodes_to_layer(struct ice_port_info * pi,struct ice_sched_node * tc_node,struct ice_sched_node * parent,u8 layer,u16 num_nodes,u32 * first_node_teid,u16 * num_nodes_added)10615513b920SAnirudh Venkataramanan ice_sched_add_nodes_to_layer(struct ice_port_info *pi,
10625513b920SAnirudh Venkataramanan 			     struct ice_sched_node *tc_node,
10635513b920SAnirudh Venkataramanan 			     struct ice_sched_node *parent, u8 layer,
10645513b920SAnirudh Venkataramanan 			     u16 num_nodes, u32 *first_node_teid,
10655513b920SAnirudh Venkataramanan 			     u16 *num_nodes_added)
10665513b920SAnirudh Venkataramanan {
10675513b920SAnirudh Venkataramanan 	u32 *first_teid_ptr = first_node_teid;
10687fb09a73SVictor Raj 	u16 new_num_nodes = num_nodes;
10695e24d598STony Nguyen 	int status = 0;
10705513b920SAnirudh Venkataramanan 
1071d332a38cSAnirudh Venkataramanan 	*num_nodes_added = 0;
10727fb09a73SVictor Raj 	while (*num_nodes_added < num_nodes) {
10737fb09a73SVictor Raj 		u16 max_child_nodes, num_added = 0;
10747fb09a73SVictor Raj 		u32 temp;
1075d332a38cSAnirudh Venkataramanan 
10767fb09a73SVictor Raj 		status = ice_sched_add_nodes_to_hw_layer(pi, tc_node, parent,
10777fb09a73SVictor Raj 							 layer,	new_num_nodes,
10787fb09a73SVictor Raj 							 first_teid_ptr,
10797fb09a73SVictor Raj 							 &num_added);
10807fb09a73SVictor Raj 		if (!status)
10817fb09a73SVictor Raj 			*num_nodes_added += num_added;
10827fb09a73SVictor Raj 		/* added more nodes than requested ? */
10837fb09a73SVictor Raj 		if (*num_nodes_added > num_nodes) {
10847fb09a73SVictor Raj 			ice_debug(pi->hw, ICE_DBG_SCHED, "added extra nodes %d %d\n", num_nodes,
10857fb09a73SVictor Raj 				  *num_nodes_added);
1086d54699e2STony Nguyen 			status = -EIO;
10877fb09a73SVictor Raj 			break;
10887fb09a73SVictor Raj 		}
10897fb09a73SVictor Raj 		/* break if all the nodes are added successfully */
10907fb09a73SVictor Raj 		if (!status && (*num_nodes_added == num_nodes))
10917fb09a73SVictor Raj 			break;
10927fb09a73SVictor Raj 		/* break if the error is not max limit */
1093d54699e2STony Nguyen 		if (status && status != -ENOSPC)
10947fb09a73SVictor Raj 			break;
10957fb09a73SVictor Raj 		/* Exceeded the max children */
10967fb09a73SVictor Raj 		max_child_nodes = pi->hw->max_children[parent->tx_sched_layer];
10975513b920SAnirudh Venkataramanan 		/* utilize all the spaces if the parent is not full */
10985513b920SAnirudh Venkataramanan 		if (parent->num_children < max_child_nodes) {
10995513b920SAnirudh Venkataramanan 			new_num_nodes = max_child_nodes - parent->num_children;
11007fb09a73SVictor Raj 		} else {
11017fb09a73SVictor Raj 			/* This parent is full, try the next sibling */
11027fb09a73SVictor Raj 			parent = parent->sibling;
11037fb09a73SVictor Raj 			/* Don't modify the first node TEID memory if the
11047fb09a73SVictor Raj 			 * first node was added already in the above call.
11057fb09a73SVictor Raj 			 * Instead send some temp memory for all other
11067fb09a73SVictor Raj 			 * recursive calls.
11075513b920SAnirudh Venkataramanan 			 */
11085513b920SAnirudh Venkataramanan 			if (num_added)
11095513b920SAnirudh Venkataramanan 				first_teid_ptr = &temp;
11105513b920SAnirudh Venkataramanan 
11117fb09a73SVictor Raj 			new_num_nodes = num_nodes - *num_nodes_added;
11125513b920SAnirudh Venkataramanan 		}
11137fb09a73SVictor Raj 	}
11145513b920SAnirudh Venkataramanan 	return status;
11155513b920SAnirudh Venkataramanan }
11165513b920SAnirudh Venkataramanan 
11175513b920SAnirudh Venkataramanan /**
1118cdedef59SAnirudh Venkataramanan  * ice_sched_get_qgrp_layer - get the current queue group layer number
1119f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
1120cdedef59SAnirudh Venkataramanan  *
1121cdedef59SAnirudh Venkataramanan  * This function returns the current queue group layer number
1122cdedef59SAnirudh Venkataramanan  */
ice_sched_get_qgrp_layer(struct ice_hw * hw)1123cdedef59SAnirudh Venkataramanan static u8 ice_sched_get_qgrp_layer(struct ice_hw *hw)
1124cdedef59SAnirudh Venkataramanan {
1125cdedef59SAnirudh Venkataramanan 	/* It's always total layers - 1, the array is 0 relative so -2 */
1126cdedef59SAnirudh Venkataramanan 	return hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET;
1127cdedef59SAnirudh Venkataramanan }
1128cdedef59SAnirudh Venkataramanan 
1129cdedef59SAnirudh Venkataramanan /**
11305513b920SAnirudh Venkataramanan  * ice_sched_get_vsi_layer - get the current VSI layer number
1131f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
11325513b920SAnirudh Venkataramanan  *
11335513b920SAnirudh Venkataramanan  * This function returns the current VSI layer number
11345513b920SAnirudh Venkataramanan  */
ice_sched_get_vsi_layer(struct ice_hw * hw)113523ccae5cSDave Ertman u8 ice_sched_get_vsi_layer(struct ice_hw *hw)
11365513b920SAnirudh Venkataramanan {
11375513b920SAnirudh Venkataramanan 	/* Num Layers       VSI layer
11385513b920SAnirudh Venkataramanan 	 *     9               6
11395513b920SAnirudh Venkataramanan 	 *     7               4
11405513b920SAnirudh Venkataramanan 	 *     5 or less       sw_entry_point_layer
11415513b920SAnirudh Venkataramanan 	 */
1142f9867df6SAnirudh Venkataramanan 	/* calculate the VSI layer based on number of layers. */
11435513b920SAnirudh Venkataramanan 	if (hw->num_tx_sched_layers > ICE_VSI_LAYER_OFFSET + 1) {
11445513b920SAnirudh Venkataramanan 		u8 layer = hw->num_tx_sched_layers - ICE_VSI_LAYER_OFFSET;
11455513b920SAnirudh Venkataramanan 
11465513b920SAnirudh Venkataramanan 		if (layer > hw->sw_entry_point_layer)
11475513b920SAnirudh Venkataramanan 			return layer;
11485513b920SAnirudh Venkataramanan 	}
11495513b920SAnirudh Venkataramanan 	return hw->sw_entry_point_layer;
11505513b920SAnirudh Venkataramanan }
11515513b920SAnirudh Venkataramanan 
11525513b920SAnirudh Venkataramanan /**
1153b126bd6bSKiran Patil  * ice_sched_get_agg_layer - get the current aggregator layer number
1154b126bd6bSKiran Patil  * @hw: pointer to the HW struct
1155b126bd6bSKiran Patil  *
1156b126bd6bSKiran Patil  * This function returns the current aggregator layer number
1157b126bd6bSKiran Patil  */
ice_sched_get_agg_layer(struct ice_hw * hw)115823ccae5cSDave Ertman u8 ice_sched_get_agg_layer(struct ice_hw *hw)
1159b126bd6bSKiran Patil {
1160b126bd6bSKiran Patil 	/* Num Layers       aggregator layer
1161b126bd6bSKiran Patil 	 *     9               4
1162b126bd6bSKiran Patil 	 *     7 or less       sw_entry_point_layer
1163b126bd6bSKiran Patil 	 */
1164b126bd6bSKiran Patil 	/* calculate the aggregator layer based on number of layers. */
1165b126bd6bSKiran Patil 	if (hw->num_tx_sched_layers > ICE_AGG_LAYER_OFFSET + 1) {
1166b126bd6bSKiran Patil 		u8 layer = hw->num_tx_sched_layers - ICE_AGG_LAYER_OFFSET;
1167b126bd6bSKiran Patil 
1168b126bd6bSKiran Patil 		if (layer > hw->sw_entry_point_layer)
1169b126bd6bSKiran Patil 			return layer;
1170b126bd6bSKiran Patil 	}
1171b126bd6bSKiran Patil 	return hw->sw_entry_point_layer;
1172b126bd6bSKiran Patil }
1173b126bd6bSKiran Patil 
1174b126bd6bSKiran Patil /**
1175dc49c772SAnirudh Venkataramanan  * ice_rm_dflt_leaf_node - remove the default leaf node in the tree
1176dc49c772SAnirudh Venkataramanan  * @pi: port information structure
1177dc49c772SAnirudh Venkataramanan  *
1178dc49c772SAnirudh Venkataramanan  * This function removes the leaf node that was created by the FW
1179dc49c772SAnirudh Venkataramanan  * during initialization
1180dc49c772SAnirudh Venkataramanan  */
ice_rm_dflt_leaf_node(struct ice_port_info * pi)11812c5492deSBruce Allan static void ice_rm_dflt_leaf_node(struct ice_port_info *pi)
1182dc49c772SAnirudh Venkataramanan {
1183dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *node;
1184dc49c772SAnirudh Venkataramanan 
1185dc49c772SAnirudh Venkataramanan 	node = pi->root;
1186dc49c772SAnirudh Venkataramanan 	while (node) {
1187dc49c772SAnirudh Venkataramanan 		if (!node->num_children)
1188dc49c772SAnirudh Venkataramanan 			break;
1189dc49c772SAnirudh Venkataramanan 		node = node->children[0];
1190dc49c772SAnirudh Venkataramanan 	}
1191dc49c772SAnirudh Venkataramanan 	if (node && node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF) {
1192dc49c772SAnirudh Venkataramanan 		u32 teid = le32_to_cpu(node->info.node_teid);
11935e24d598STony Nguyen 		int status;
1194dc49c772SAnirudh Venkataramanan 
1195dc49c772SAnirudh Venkataramanan 		/* remove the default leaf node */
1196dc49c772SAnirudh Venkataramanan 		status = ice_sched_remove_elems(pi->hw, node->parent, 1, &teid);
1197dc49c772SAnirudh Venkataramanan 		if (!status)
1198dc49c772SAnirudh Venkataramanan 			ice_free_sched_node(pi, node);
1199dc49c772SAnirudh Venkataramanan 	}
1200dc49c772SAnirudh Venkataramanan }
1201dc49c772SAnirudh Venkataramanan 
1202dc49c772SAnirudh Venkataramanan /**
1203dc49c772SAnirudh Venkataramanan  * ice_sched_rm_dflt_nodes - free the default nodes in the tree
1204dc49c772SAnirudh Venkataramanan  * @pi: port information structure
1205dc49c772SAnirudh Venkataramanan  *
1206dc49c772SAnirudh Venkataramanan  * This function frees all the nodes except root and TC that were created by
1207dc49c772SAnirudh Venkataramanan  * the FW during initialization
1208dc49c772SAnirudh Venkataramanan  */
ice_sched_rm_dflt_nodes(struct ice_port_info * pi)12092c5492deSBruce Allan static void ice_sched_rm_dflt_nodes(struct ice_port_info *pi)
1210dc49c772SAnirudh Venkataramanan {
1211dc49c772SAnirudh Venkataramanan 	struct ice_sched_node *node;
1212dc49c772SAnirudh Venkataramanan 
1213dc49c772SAnirudh Venkataramanan 	ice_rm_dflt_leaf_node(pi);
12145513b920SAnirudh Venkataramanan 
1215dc49c772SAnirudh Venkataramanan 	/* remove the default nodes except TC and root nodes */
1216dc49c772SAnirudh Venkataramanan 	node = pi->root;
1217dc49c772SAnirudh Venkataramanan 	while (node) {
1218dc49c772SAnirudh Venkataramanan 		if (node->tx_sched_layer >= pi->hw->sw_entry_point_layer &&
1219dc49c772SAnirudh Venkataramanan 		    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
1220dc49c772SAnirudh Venkataramanan 		    node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT) {
1221dc49c772SAnirudh Venkataramanan 			ice_free_sched_node(pi, node);
1222dc49c772SAnirudh Venkataramanan 			break;
1223dc49c772SAnirudh Venkataramanan 		}
12245513b920SAnirudh Venkataramanan 
1225dc49c772SAnirudh Venkataramanan 		if (!node->num_children)
1226dc49c772SAnirudh Venkataramanan 			break;
1227dc49c772SAnirudh Venkataramanan 		node = node->children[0];
1228dc49c772SAnirudh Venkataramanan 	}
1229dc49c772SAnirudh Venkataramanan }
1230dc49c772SAnirudh Venkataramanan 
1231dc49c772SAnirudh Venkataramanan /**
1232dc49c772SAnirudh Venkataramanan  * ice_sched_init_port - Initialize scheduler by querying information from FW
1233dc49c772SAnirudh Venkataramanan  * @pi: port info structure for the tree to cleanup
1234dc49c772SAnirudh Venkataramanan  *
1235dc49c772SAnirudh Venkataramanan  * This function is the initial call to find the total number of Tx scheduler
1236dc49c772SAnirudh Venkataramanan  * resources, default topology created by firmware and storing the information
1237dc49c772SAnirudh Venkataramanan  * in SW DB.
1238dc49c772SAnirudh Venkataramanan  */
ice_sched_init_port(struct ice_port_info * pi)12395e24d598STony Nguyen int ice_sched_init_port(struct ice_port_info *pi)
1240dc49c772SAnirudh Venkataramanan {
1241dc49c772SAnirudh Venkataramanan 	struct ice_aqc_get_topo_elem *buf;
1242dc49c772SAnirudh Venkataramanan 	struct ice_hw *hw;
1243dc49c772SAnirudh Venkataramanan 	u8 num_branches;
1244dc49c772SAnirudh Venkataramanan 	u16 num_elems;
12455518ac2aSTony Nguyen 	int status;
1246dc49c772SAnirudh Venkataramanan 	u8 i, j;
1247dc49c772SAnirudh Venkataramanan 
1248dc49c772SAnirudh Venkataramanan 	if (!pi)
1249d54699e2STony Nguyen 		return -EINVAL;
1250dc49c772SAnirudh Venkataramanan 	hw = pi->hw;
1251dc49c772SAnirudh Venkataramanan 
1252dc49c772SAnirudh Venkataramanan 	/* Query the Default Topology from FW */
125304cbaa6cSChristophe JAILLET 	buf = kzalloc(ICE_AQ_MAX_BUF_LEN, GFP_KERNEL);
1254dc49c772SAnirudh Venkataramanan 	if (!buf)
1255d54699e2STony Nguyen 		return -ENOMEM;
1256dc49c772SAnirudh Venkataramanan 
1257dc49c772SAnirudh Venkataramanan 	/* Query default scheduling tree topology */
1258b36c598cSAnirudh Venkataramanan 	status = ice_aq_get_dflt_topo(hw, pi->lport, buf, ICE_AQ_MAX_BUF_LEN,
1259dc49c772SAnirudh Venkataramanan 				      &num_branches, NULL);
1260dc49c772SAnirudh Venkataramanan 	if (status)
1261dc49c772SAnirudh Venkataramanan 		goto err_init_port;
1262dc49c772SAnirudh Venkataramanan 
1263dc49c772SAnirudh Venkataramanan 	/* num_branches should be between 1-8 */
1264dc49c772SAnirudh Venkataramanan 	if (num_branches < 1 || num_branches > ICE_TXSCHED_MAX_BRANCHES) {
1265dc49c772SAnirudh Venkataramanan 		ice_debug(hw, ICE_DBG_SCHED, "num_branches unexpected %d\n",
1266dc49c772SAnirudh Venkataramanan 			  num_branches);
1267d54699e2STony Nguyen 		status = -EINVAL;
1268dc49c772SAnirudh Venkataramanan 		goto err_init_port;
1269dc49c772SAnirudh Venkataramanan 	}
1270dc49c772SAnirudh Venkataramanan 
1271dc49c772SAnirudh Venkataramanan 	/* get the number of elements on the default/first branch */
1272dc49c772SAnirudh Venkataramanan 	num_elems = le16_to_cpu(buf[0].hdr.num_elems);
1273dc49c772SAnirudh Venkataramanan 
1274dc49c772SAnirudh Venkataramanan 	/* num_elems should always be between 1-9 */
1275dc49c772SAnirudh Venkataramanan 	if (num_elems < 1 || num_elems > ICE_AQC_TOPO_MAX_LEVEL_NUM) {
1276dc49c772SAnirudh Venkataramanan 		ice_debug(hw, ICE_DBG_SCHED, "num_elems unexpected %d\n",
1277dc49c772SAnirudh Venkataramanan 			  num_elems);
1278d54699e2STony Nguyen 		status = -EINVAL;
1279dc49c772SAnirudh Venkataramanan 		goto err_init_port;
1280dc49c772SAnirudh Venkataramanan 	}
1281dc49c772SAnirudh Venkataramanan 
1282f9867df6SAnirudh Venkataramanan 	/* If the last node is a leaf node then the index of the queue group
1283dc49c772SAnirudh Venkataramanan 	 * layer is two less than the number of elements.
1284dc49c772SAnirudh Venkataramanan 	 */
1285dc49c772SAnirudh Venkataramanan 	if (num_elems > 2 && buf[0].generic[num_elems - 1].data.elem_type ==
1286dc49c772SAnirudh Venkataramanan 	    ICE_AQC_ELEM_TYPE_LEAF)
1287dc49c772SAnirudh Venkataramanan 		pi->last_node_teid =
1288dc49c772SAnirudh Venkataramanan 			le32_to_cpu(buf[0].generic[num_elems - 2].node_teid);
1289dc49c772SAnirudh Venkataramanan 	else
1290dc49c772SAnirudh Venkataramanan 		pi->last_node_teid =
1291dc49c772SAnirudh Venkataramanan 			le32_to_cpu(buf[0].generic[num_elems - 1].node_teid);
1292dc49c772SAnirudh Venkataramanan 
1293dc49c772SAnirudh Venkataramanan 	/* Insert the Tx Sched root node */
1294dc49c772SAnirudh Venkataramanan 	status = ice_sched_add_root_node(pi, &buf[0].generic[0]);
1295dc49c772SAnirudh Venkataramanan 	if (status)
1296dc49c772SAnirudh Venkataramanan 		goto err_init_port;
1297dc49c772SAnirudh Venkataramanan 
1298dc49c772SAnirudh Venkataramanan 	/* Parse the default tree and cache the information */
1299dc49c772SAnirudh Venkataramanan 	for (i = 0; i < num_branches; i++) {
1300dc49c772SAnirudh Venkataramanan 		num_elems = le16_to_cpu(buf[i].hdr.num_elems);
1301dc49c772SAnirudh Venkataramanan 
1302dc49c772SAnirudh Venkataramanan 		/* Skip root element as already inserted */
1303dc49c772SAnirudh Venkataramanan 		for (j = 1; j < num_elems; j++) {
1304dc49c772SAnirudh Venkataramanan 			/* update the sw entry point */
1305dc49c772SAnirudh Venkataramanan 			if (buf[0].generic[j].data.elem_type ==
1306dc49c772SAnirudh Venkataramanan 			    ICE_AQC_ELEM_TYPE_ENTRY_POINT)
1307dc49c772SAnirudh Venkataramanan 				hw->sw_entry_point_layer = j;
1308dc49c772SAnirudh Venkataramanan 
1309bdf96d96SMichal Wilczynski 			status = ice_sched_add_node(pi, j, &buf[i].generic[j], NULL);
1310dc49c772SAnirudh Venkataramanan 			if (status)
1311dc49c772SAnirudh Venkataramanan 				goto err_init_port;
1312dc49c772SAnirudh Venkataramanan 		}
1313dc49c772SAnirudh Venkataramanan 	}
1314dc49c772SAnirudh Venkataramanan 
1315dc49c772SAnirudh Venkataramanan 	/* Remove the default nodes. */
1316dc49c772SAnirudh Venkataramanan 	if (pi->root)
1317dc49c772SAnirudh Venkataramanan 		ice_sched_rm_dflt_nodes(pi);
1318dc49c772SAnirudh Venkataramanan 
1319dc49c772SAnirudh Venkataramanan 	/* initialize the port for handling the scheduler tree */
1320dc49c772SAnirudh Venkataramanan 	pi->port_state = ICE_SCHED_PORT_STATE_READY;
1321dc49c772SAnirudh Venkataramanan 	mutex_init(&pi->sched_lock);
13221ddef455SUsha Ketineni 	for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++)
13231ddef455SUsha Ketineni 		INIT_LIST_HEAD(&pi->rl_prof_list[i]);
1324dc49c772SAnirudh Venkataramanan 
1325dc49c772SAnirudh Venkataramanan err_init_port:
1326dc49c772SAnirudh Venkataramanan 	if (status && pi->root) {
1327dc49c772SAnirudh Venkataramanan 		ice_free_sched_node(pi, pi->root);
1328dc49c772SAnirudh Venkataramanan 		pi->root = NULL;
1329dc49c772SAnirudh Venkataramanan 	}
1330dc49c772SAnirudh Venkataramanan 
133104cbaa6cSChristophe JAILLET 	kfree(buf);
1332dc49c772SAnirudh Venkataramanan 	return status;
1333dc49c772SAnirudh Venkataramanan }
1334dc49c772SAnirudh Venkataramanan 
1335dc49c772SAnirudh Venkataramanan /**
13369c20346bSAnirudh Venkataramanan  * ice_sched_query_res_alloc - query the FW for num of logical sched layers
13379c20346bSAnirudh Venkataramanan  * @hw: pointer to the HW struct
13389c20346bSAnirudh Venkataramanan  *
13399c20346bSAnirudh Venkataramanan  * query FW for allocated scheduler resources and store in HW struct
13409c20346bSAnirudh Venkataramanan  */
ice_sched_query_res_alloc(struct ice_hw * hw)13415e24d598STony Nguyen int ice_sched_query_res_alloc(struct ice_hw *hw)
13429c20346bSAnirudh Venkataramanan {
13439c20346bSAnirudh Venkataramanan 	struct ice_aqc_query_txsched_res_resp *buf;
1344b36c598cSAnirudh Venkataramanan 	__le16 max_sibl;
13455518ac2aSTony Nguyen 	int status = 0;
1346615457a2SColin Ian King 	u16 i;
13479c20346bSAnirudh Venkataramanan 
13489c20346bSAnirudh Venkataramanan 	if (hw->layer_info)
13499c20346bSAnirudh Venkataramanan 		return status;
13509c20346bSAnirudh Venkataramanan 
13519c20346bSAnirudh Venkataramanan 	buf = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*buf), GFP_KERNEL);
13529c20346bSAnirudh Venkataramanan 	if (!buf)
1353d54699e2STony Nguyen 		return -ENOMEM;
13549c20346bSAnirudh Venkataramanan 
13559c20346bSAnirudh Venkataramanan 	status = ice_aq_query_sched_res(hw, sizeof(*buf), buf, NULL);
13569c20346bSAnirudh Venkataramanan 	if (status)
13579c20346bSAnirudh Venkataramanan 		goto sched_query_out;
13589c20346bSAnirudh Venkataramanan 
13599c20346bSAnirudh Venkataramanan 	hw->num_tx_sched_layers = le16_to_cpu(buf->sched_props.logical_levels);
13609c20346bSAnirudh Venkataramanan 	hw->num_tx_sched_phys_layers =
13619c20346bSAnirudh Venkataramanan 		le16_to_cpu(buf->sched_props.phys_levels);
13629c20346bSAnirudh Venkataramanan 	hw->flattened_layers = buf->sched_props.flattening_bitmap;
13639c20346bSAnirudh Venkataramanan 	hw->max_cgds = buf->sched_props.max_pf_cgds;
13649c20346bSAnirudh Venkataramanan 
1365b36c598cSAnirudh Venkataramanan 	/* max sibling group size of current layer refers to the max children
1366b36c598cSAnirudh Venkataramanan 	 * of the below layer node.
1367b36c598cSAnirudh Venkataramanan 	 * layer 1 node max children will be layer 2 max sibling group size
1368b36c598cSAnirudh Venkataramanan 	 * layer 2 node max children will be layer 3 max sibling group size
1369b36c598cSAnirudh Venkataramanan 	 * and so on. This array will be populated from root (index 0) to
1370b36c598cSAnirudh Venkataramanan 	 * qgroup layer 7. Leaf node has no children.
1371b36c598cSAnirudh Venkataramanan 	 */
13721ddef455SUsha Ketineni 	for (i = 0; i < hw->num_tx_sched_layers - 1; i++) {
13731ddef455SUsha Ketineni 		max_sibl = buf->layer_props[i + 1].max_sibl_grp_sz;
1374b36c598cSAnirudh Venkataramanan 		hw->max_children[i] = le16_to_cpu(max_sibl);
1375b36c598cSAnirudh Venkataramanan 	}
1376b36c598cSAnirudh Venkataramanan 
1377c6dfd690SBruce Allan 	hw->layer_info = devm_kmemdup(ice_hw_to_dev(hw), buf->layer_props,
13789c20346bSAnirudh Venkataramanan 				      (hw->num_tx_sched_layers *
13799c20346bSAnirudh Venkataramanan 				       sizeof(*hw->layer_info)),
13809c20346bSAnirudh Venkataramanan 				      GFP_KERNEL);
13819c20346bSAnirudh Venkataramanan 	if (!hw->layer_info) {
1382d54699e2STony Nguyen 		status = -ENOMEM;
13839c20346bSAnirudh Venkataramanan 		goto sched_query_out;
13849c20346bSAnirudh Venkataramanan 	}
13859c20346bSAnirudh Venkataramanan 
13869c20346bSAnirudh Venkataramanan sched_query_out:
13879c20346bSAnirudh Venkataramanan 	devm_kfree(ice_hw_to_dev(hw), buf);
13889c20346bSAnirudh Venkataramanan 	return status;
13899c20346bSAnirudh Venkataramanan }
1390cdedef59SAnirudh Venkataramanan 
1391cdedef59SAnirudh Venkataramanan /**
13924f8a1497SBen Shelton  * ice_sched_get_psm_clk_freq - determine the PSM clock frequency
13934f8a1497SBen Shelton  * @hw: pointer to the HW struct
13944f8a1497SBen Shelton  *
13954f8a1497SBen Shelton  * Determine the PSM clock frequency and store in HW struct
13964f8a1497SBen Shelton  */
ice_sched_get_psm_clk_freq(struct ice_hw * hw)13974f8a1497SBen Shelton void ice_sched_get_psm_clk_freq(struct ice_hw *hw)
13984f8a1497SBen Shelton {
13994f8a1497SBen Shelton 	u32 val, clk_src;
14004f8a1497SBen Shelton 
14014f8a1497SBen Shelton 	val = rd32(hw, GLGEN_CLKSTAT_SRC);
14024f8a1497SBen Shelton 	clk_src = (val & GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M) >>
14034f8a1497SBen Shelton 		GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_S;
14044f8a1497SBen Shelton 
14054f8a1497SBen Shelton #define PSM_CLK_SRC_367_MHZ 0x0
14064f8a1497SBen Shelton #define PSM_CLK_SRC_416_MHZ 0x1
14074f8a1497SBen Shelton #define PSM_CLK_SRC_446_MHZ 0x2
14084f8a1497SBen Shelton #define PSM_CLK_SRC_390_MHZ 0x3
14094f8a1497SBen Shelton 
14104f8a1497SBen Shelton 	switch (clk_src) {
14114f8a1497SBen Shelton 	case PSM_CLK_SRC_367_MHZ:
14124f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_367MHZ_IN_HZ;
14134f8a1497SBen Shelton 		break;
14144f8a1497SBen Shelton 	case PSM_CLK_SRC_416_MHZ:
14154f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_416MHZ_IN_HZ;
14164f8a1497SBen Shelton 		break;
14174f8a1497SBen Shelton 	case PSM_CLK_SRC_446_MHZ:
14184f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_446MHZ_IN_HZ;
14194f8a1497SBen Shelton 		break;
14204f8a1497SBen Shelton 	case PSM_CLK_SRC_390_MHZ:
14214f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_390MHZ_IN_HZ;
14224f8a1497SBen Shelton 		break;
14234f8a1497SBen Shelton 	default:
14244f8a1497SBen Shelton 		ice_debug(hw, ICE_DBG_SCHED, "PSM clk_src unexpected %u\n",
14254f8a1497SBen Shelton 			  clk_src);
14264f8a1497SBen Shelton 		/* fall back to a safe default */
14274f8a1497SBen Shelton 		hw->psm_clk_freq = ICE_PSM_CLK_446MHZ_IN_HZ;
14284f8a1497SBen Shelton 	}
14294f8a1497SBen Shelton }
14304f8a1497SBen Shelton 
14314f8a1497SBen Shelton /**
1432cdedef59SAnirudh Venkataramanan  * ice_sched_find_node_in_subtree - Find node in part of base node subtree
1433f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
1434cdedef59SAnirudh Venkataramanan  * @base: pointer to the base node
1435cdedef59SAnirudh Venkataramanan  * @node: pointer to the node to search
1436cdedef59SAnirudh Venkataramanan  *
1437cdedef59SAnirudh Venkataramanan  * This function checks whether a given node is part of the base node
1438cdedef59SAnirudh Venkataramanan  * subtree or not
1439cdedef59SAnirudh Venkataramanan  */
1440cdedef59SAnirudh Venkataramanan static bool
ice_sched_find_node_in_subtree(struct ice_hw * hw,struct ice_sched_node * base,struct ice_sched_node * node)1441cdedef59SAnirudh Venkataramanan ice_sched_find_node_in_subtree(struct ice_hw *hw, struct ice_sched_node *base,
1442cdedef59SAnirudh Venkataramanan 			       struct ice_sched_node *node)
1443cdedef59SAnirudh Venkataramanan {
1444cdedef59SAnirudh Venkataramanan 	u8 i;
1445cdedef59SAnirudh Venkataramanan 
1446cdedef59SAnirudh Venkataramanan 	for (i = 0; i < base->num_children; i++) {
1447cdedef59SAnirudh Venkataramanan 		struct ice_sched_node *child = base->children[i];
1448cdedef59SAnirudh Venkataramanan 
1449cdedef59SAnirudh Venkataramanan 		if (node == child)
1450cdedef59SAnirudh Venkataramanan 			return true;
14515513b920SAnirudh Venkataramanan 
1452cdedef59SAnirudh Venkataramanan 		if (child->tx_sched_layer > node->tx_sched_layer)
1453cdedef59SAnirudh Venkataramanan 			return false;
14545513b920SAnirudh Venkataramanan 
1455cdedef59SAnirudh Venkataramanan 		/* this recursion is intentional, and wouldn't
1456cdedef59SAnirudh Venkataramanan 		 * go more than 8 calls
1457cdedef59SAnirudh Venkataramanan 		 */
1458cdedef59SAnirudh Venkataramanan 		if (ice_sched_find_node_in_subtree(hw, child, node))
1459cdedef59SAnirudh Venkataramanan 			return true;
1460cdedef59SAnirudh Venkataramanan 	}
1461cdedef59SAnirudh Venkataramanan 	return false;
1462cdedef59SAnirudh Venkataramanan }
1463cdedef59SAnirudh Venkataramanan 
1464cdedef59SAnirudh Venkataramanan /**
14654043818cSVictor Raj  * ice_sched_get_free_qgrp - Scan all queue group siblings and find a free node
14664043818cSVictor Raj  * @pi: port information structure
14674043818cSVictor Raj  * @vsi_node: software VSI handle
14684043818cSVictor Raj  * @qgrp_node: first queue group node identified for scanning
14694043818cSVictor Raj  * @owner: LAN or RDMA
14704043818cSVictor Raj  *
14714043818cSVictor Raj  * This function retrieves a free LAN or RDMA queue group node by scanning
14724043818cSVictor Raj  * qgrp_node and its siblings for the queue group with the fewest number
14734043818cSVictor Raj  * of queues currently assigned.
14744043818cSVictor Raj  */
14754043818cSVictor Raj static struct ice_sched_node *
ice_sched_get_free_qgrp(struct ice_port_info * pi,struct ice_sched_node * vsi_node,struct ice_sched_node * qgrp_node,u8 owner)14764043818cSVictor Raj ice_sched_get_free_qgrp(struct ice_port_info *pi,
14774043818cSVictor Raj 			struct ice_sched_node *vsi_node,
14784043818cSVictor Raj 			struct ice_sched_node *qgrp_node, u8 owner)
14794043818cSVictor Raj {
14804043818cSVictor Raj 	struct ice_sched_node *min_qgrp;
14814043818cSVictor Raj 	u8 min_children;
14824043818cSVictor Raj 
14834043818cSVictor Raj 	if (!qgrp_node)
14844043818cSVictor Raj 		return qgrp_node;
14854043818cSVictor Raj 	min_children = qgrp_node->num_children;
14864043818cSVictor Raj 	if (!min_children)
14874043818cSVictor Raj 		return qgrp_node;
14884043818cSVictor Raj 	min_qgrp = qgrp_node;
14894043818cSVictor Raj 	/* scan all queue groups until find a node which has less than the
14904043818cSVictor Raj 	 * minimum number of children. This way all queue group nodes get
14914043818cSVictor Raj 	 * equal number of shares and active. The bandwidth will be equally
14924043818cSVictor Raj 	 * distributed across all queues.
14934043818cSVictor Raj 	 */
14944043818cSVictor Raj 	while (qgrp_node) {
14954043818cSVictor Raj 		/* make sure the qgroup node is part of the VSI subtree */
14964043818cSVictor Raj 		if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node))
14974043818cSVictor Raj 			if (qgrp_node->num_children < min_children &&
14984043818cSVictor Raj 			    qgrp_node->owner == owner) {
14994043818cSVictor Raj 				/* replace the new min queue group node */
15004043818cSVictor Raj 				min_qgrp = qgrp_node;
15014043818cSVictor Raj 				min_children = min_qgrp->num_children;
15024043818cSVictor Raj 				/* break if it has no children, */
15034043818cSVictor Raj 				if (!min_children)
15044043818cSVictor Raj 					break;
15054043818cSVictor Raj 			}
15064043818cSVictor Raj 		qgrp_node = qgrp_node->sibling;
15074043818cSVictor Raj 	}
15084043818cSVictor Raj 	return min_qgrp;
15094043818cSVictor Raj }
15104043818cSVictor Raj 
15114043818cSVictor Raj /**
1512f9867df6SAnirudh Venkataramanan  * ice_sched_get_free_qparent - Get a free LAN or RDMA queue group node
1513cdedef59SAnirudh Venkataramanan  * @pi: port information structure
15144fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
1515cdedef59SAnirudh Venkataramanan  * @tc: branch number
1516f9867df6SAnirudh Venkataramanan  * @owner: LAN or RDMA
1517cdedef59SAnirudh Venkataramanan  *
1518f9867df6SAnirudh Venkataramanan  * This function retrieves a free LAN or RDMA queue group node
1519cdedef59SAnirudh Venkataramanan  */
1520cdedef59SAnirudh Venkataramanan struct ice_sched_node *
ice_sched_get_free_qparent(struct ice_port_info * pi,u16 vsi_handle,u8 tc,u8 owner)15214fb33f31SAnirudh Venkataramanan ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
1522cdedef59SAnirudh Venkataramanan 			   u8 owner)
1523cdedef59SAnirudh Venkataramanan {
15244043818cSVictor Raj 	struct ice_sched_node *vsi_node, *qgrp_node;
15254fb33f31SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
1526cdedef59SAnirudh Venkataramanan 	u16 max_children;
1527cdedef59SAnirudh Venkataramanan 	u8 qgrp_layer;
1528cdedef59SAnirudh Venkataramanan 
1529cdedef59SAnirudh Venkataramanan 	qgrp_layer = ice_sched_get_qgrp_layer(pi->hw);
1530b36c598cSAnirudh Venkataramanan 	max_children = pi->hw->max_children[qgrp_layer];
15315513b920SAnirudh Venkataramanan 
15324fb33f31SAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
15334fb33f31SAnirudh Venkataramanan 	if (!vsi_ctx)
15344fb33f31SAnirudh Venkataramanan 		return NULL;
15354fb33f31SAnirudh Venkataramanan 	vsi_node = vsi_ctx->sched.vsi_node[tc];
1536f9867df6SAnirudh Venkataramanan 	/* validate invalid VSI ID */
1537cdedef59SAnirudh Venkataramanan 	if (!vsi_node)
15384043818cSVictor Raj 		return NULL;
15395513b920SAnirudh Venkataramanan 
1540f9867df6SAnirudh Venkataramanan 	/* get the first queue group node from VSI sub-tree */
154129358248SVictor Raj 	qgrp_node = ice_sched_get_first_node(pi, vsi_node, qgrp_layer);
1542cdedef59SAnirudh Venkataramanan 	while (qgrp_node) {
1543cdedef59SAnirudh Venkataramanan 		/* make sure the qgroup node is part of the VSI subtree */
1544cdedef59SAnirudh Venkataramanan 		if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node))
1545cdedef59SAnirudh Venkataramanan 			if (qgrp_node->num_children < max_children &&
1546cdedef59SAnirudh Venkataramanan 			    qgrp_node->owner == owner)
1547cdedef59SAnirudh Venkataramanan 				break;
1548cdedef59SAnirudh Venkataramanan 		qgrp_node = qgrp_node->sibling;
1549cdedef59SAnirudh Venkataramanan 	}
15505513b920SAnirudh Venkataramanan 
15514043818cSVictor Raj 	/* Select the best queue group */
15524043818cSVictor Raj 	return ice_sched_get_free_qgrp(pi, vsi_node, qgrp_node, owner);
1553cdedef59SAnirudh Venkataramanan }
15545513b920SAnirudh Venkataramanan 
15555513b920SAnirudh Venkataramanan /**
1556f9867df6SAnirudh Venkataramanan  * ice_sched_get_vsi_node - Get a VSI node based on VSI ID
1557b126bd6bSKiran Patil  * @pi: pointer to the port information structure
15585513b920SAnirudh Venkataramanan  * @tc_node: pointer to the TC node
15594fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
15605513b920SAnirudh Venkataramanan  *
1561f9867df6SAnirudh Venkataramanan  * This function retrieves a VSI node for a given VSI ID from a given
15625513b920SAnirudh Venkataramanan  * TC branch
15635513b920SAnirudh Venkataramanan  */
15645513b920SAnirudh Venkataramanan static struct ice_sched_node *
ice_sched_get_vsi_node(struct ice_port_info * pi,struct ice_sched_node * tc_node,u16 vsi_handle)1565b126bd6bSKiran Patil ice_sched_get_vsi_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
15664fb33f31SAnirudh Venkataramanan 		       u16 vsi_handle)
15675513b920SAnirudh Venkataramanan {
15685513b920SAnirudh Venkataramanan 	struct ice_sched_node *node;
15695513b920SAnirudh Venkataramanan 	u8 vsi_layer;
15705513b920SAnirudh Venkataramanan 
1571b126bd6bSKiran Patil 	vsi_layer = ice_sched_get_vsi_layer(pi->hw);
1572b126bd6bSKiran Patil 	node = ice_sched_get_first_node(pi, tc_node, vsi_layer);
15735513b920SAnirudh Venkataramanan 
15745513b920SAnirudh Venkataramanan 	/* Check whether it already exists */
15755513b920SAnirudh Venkataramanan 	while (node) {
15764fb33f31SAnirudh Venkataramanan 		if (node->vsi_handle == vsi_handle)
15775513b920SAnirudh Venkataramanan 			return node;
15785513b920SAnirudh Venkataramanan 		node = node->sibling;
15795513b920SAnirudh Venkataramanan 	}
15805513b920SAnirudh Venkataramanan 
15815513b920SAnirudh Venkataramanan 	return node;
15825513b920SAnirudh Venkataramanan }
15835513b920SAnirudh Venkataramanan 
15845513b920SAnirudh Venkataramanan /**
1585b126bd6bSKiran Patil  * ice_sched_get_agg_node - Get an aggregator node based on aggregator ID
1586b126bd6bSKiran Patil  * @pi: pointer to the port information structure
1587b126bd6bSKiran Patil  * @tc_node: pointer to the TC node
1588b126bd6bSKiran Patil  * @agg_id: aggregator ID
1589b126bd6bSKiran Patil  *
1590b126bd6bSKiran Patil  * This function retrieves an aggregator node for a given aggregator ID from
1591b126bd6bSKiran Patil  * a given TC branch
1592b126bd6bSKiran Patil  */
159323ccae5cSDave Ertman struct ice_sched_node *
ice_sched_get_agg_node(struct ice_port_info * pi,struct ice_sched_node * tc_node,u32 agg_id)1594b126bd6bSKiran Patil ice_sched_get_agg_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
1595b126bd6bSKiran Patil 		       u32 agg_id)
1596b126bd6bSKiran Patil {
1597b126bd6bSKiran Patil 	struct ice_sched_node *node;
1598b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
1599b126bd6bSKiran Patil 	u8 agg_layer;
1600b126bd6bSKiran Patil 
1601b126bd6bSKiran Patil 	if (!hw)
1602b126bd6bSKiran Patil 		return NULL;
1603b126bd6bSKiran Patil 	agg_layer = ice_sched_get_agg_layer(hw);
1604b126bd6bSKiran Patil 	node = ice_sched_get_first_node(pi, tc_node, agg_layer);
1605b126bd6bSKiran Patil 
1606b126bd6bSKiran Patil 	/* Check whether it already exists */
1607b126bd6bSKiran Patil 	while (node) {
1608b126bd6bSKiran Patil 		if (node->agg_id == agg_id)
1609b126bd6bSKiran Patil 			return node;
1610b126bd6bSKiran Patil 		node = node->sibling;
1611b126bd6bSKiran Patil 	}
1612b126bd6bSKiran Patil 
1613b126bd6bSKiran Patil 	return node;
1614b126bd6bSKiran Patil }
1615b126bd6bSKiran Patil 
1616b126bd6bSKiran Patil /**
16175513b920SAnirudh Venkataramanan  * ice_sched_calc_vsi_child_nodes - calculate number of VSI child nodes
1618f9867df6SAnirudh Venkataramanan  * @hw: pointer to the HW struct
16195513b920SAnirudh Venkataramanan  * @num_qs: number of queues
16205513b920SAnirudh Venkataramanan  * @num_nodes: num nodes array
16215513b920SAnirudh Venkataramanan  *
16225513b920SAnirudh Venkataramanan  * This function calculates the number of VSI child nodes based on the
16235513b920SAnirudh Venkataramanan  * number of queues.
16245513b920SAnirudh Venkataramanan  */
16255513b920SAnirudh Venkataramanan static void
ice_sched_calc_vsi_child_nodes(struct ice_hw * hw,u16 num_qs,u16 * num_nodes)16265513b920SAnirudh Venkataramanan ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes)
16275513b920SAnirudh Venkataramanan {
16285513b920SAnirudh Venkataramanan 	u16 num = num_qs;
16295513b920SAnirudh Venkataramanan 	u8 i, qgl, vsil;
16305513b920SAnirudh Venkataramanan 
16315513b920SAnirudh Venkataramanan 	qgl = ice_sched_get_qgrp_layer(hw);
16325513b920SAnirudh Venkataramanan 	vsil = ice_sched_get_vsi_layer(hw);
16335513b920SAnirudh Venkataramanan 
1634f9867df6SAnirudh Venkataramanan 	/* calculate num nodes from queue group to VSI layer */
16355513b920SAnirudh Venkataramanan 	for (i = qgl; i > vsil; i--) {
16365513b920SAnirudh Venkataramanan 		/* round to the next integer if there is a remainder */
1637b36c598cSAnirudh Venkataramanan 		num = DIV_ROUND_UP(num, hw->max_children[i]);
16385513b920SAnirudh Venkataramanan 
16395513b920SAnirudh Venkataramanan 		/* need at least one node */
16405513b920SAnirudh Venkataramanan 		num_nodes[i] = num ? num : 1;
16415513b920SAnirudh Venkataramanan 	}
16425513b920SAnirudh Venkataramanan }
16435513b920SAnirudh Venkataramanan 
16445513b920SAnirudh Venkataramanan /**
16455513b920SAnirudh Venkataramanan  * ice_sched_add_vsi_child_nodes - add VSI child nodes to tree
16465513b920SAnirudh Venkataramanan  * @pi: port information structure
16474fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
16485513b920SAnirudh Venkataramanan  * @tc_node: pointer to the TC node
16495513b920SAnirudh Venkataramanan  * @num_nodes: pointer to the num nodes that needs to be added per layer
1650f9867df6SAnirudh Venkataramanan  * @owner: node owner (LAN or RDMA)
16515513b920SAnirudh Venkataramanan  *
16525513b920SAnirudh Venkataramanan  * This function adds the VSI child nodes to tree. It gets called for
1653f9867df6SAnirudh Venkataramanan  * LAN and RDMA separately.
16545513b920SAnirudh Venkataramanan  */
16555e24d598STony Nguyen static int
ice_sched_add_vsi_child_nodes(struct ice_port_info * pi,u16 vsi_handle,struct ice_sched_node * tc_node,u16 * num_nodes,u8 owner)16564fb33f31SAnirudh Venkataramanan ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
16575513b920SAnirudh Venkataramanan 			      struct ice_sched_node *tc_node, u16 *num_nodes,
16585513b920SAnirudh Venkataramanan 			      u8 owner)
16595513b920SAnirudh Venkataramanan {
16605513b920SAnirudh Venkataramanan 	struct ice_sched_node *parent, *node;
16615513b920SAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
16625513b920SAnirudh Venkataramanan 	u32 first_node_teid;
16635513b920SAnirudh Venkataramanan 	u16 num_added = 0;
16645513b920SAnirudh Venkataramanan 	u8 i, qgl, vsil;
16655513b920SAnirudh Venkataramanan 
16665513b920SAnirudh Venkataramanan 	qgl = ice_sched_get_qgrp_layer(hw);
16675513b920SAnirudh Venkataramanan 	vsil = ice_sched_get_vsi_layer(hw);
1668b126bd6bSKiran Patil 	parent = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
16695513b920SAnirudh Venkataramanan 	for (i = vsil + 1; i <= qgl; i++) {
1670bd557d97STony Nguyen 		int status;
1671bd557d97STony Nguyen 
16725513b920SAnirudh Venkataramanan 		if (!parent)
1673d54699e2STony Nguyen 			return -EIO;
1674b36c598cSAnirudh Venkataramanan 
16755513b920SAnirudh Venkataramanan 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
16765513b920SAnirudh Venkataramanan 						      num_nodes[i],
16775513b920SAnirudh Venkataramanan 						      &first_node_teid,
16785513b920SAnirudh Venkataramanan 						      &num_added);
16795513b920SAnirudh Venkataramanan 		if (status || num_nodes[i] != num_added)
1680d54699e2STony Nguyen 			return -EIO;
16815513b920SAnirudh Venkataramanan 
16825513b920SAnirudh Venkataramanan 		/* The newly added node can be a new parent for the next
16835513b920SAnirudh Venkataramanan 		 * layer nodes
16845513b920SAnirudh Venkataramanan 		 */
16855513b920SAnirudh Venkataramanan 		if (num_added) {
16865513b920SAnirudh Venkataramanan 			parent = ice_sched_find_node_by_teid(tc_node,
16875513b920SAnirudh Venkataramanan 							     first_node_teid);
16885513b920SAnirudh Venkataramanan 			node = parent;
16895513b920SAnirudh Venkataramanan 			while (node) {
16905513b920SAnirudh Venkataramanan 				node->owner = owner;
16915513b920SAnirudh Venkataramanan 				node = node->sibling;
16925513b920SAnirudh Venkataramanan 			}
16935513b920SAnirudh Venkataramanan 		} else {
16945513b920SAnirudh Venkataramanan 			parent = parent->children[0];
16955513b920SAnirudh Venkataramanan 		}
16965513b920SAnirudh Venkataramanan 	}
16975513b920SAnirudh Venkataramanan 
16985513b920SAnirudh Venkataramanan 	return 0;
16995513b920SAnirudh Venkataramanan }
17005513b920SAnirudh Venkataramanan 
17015513b920SAnirudh Venkataramanan /**
17025513b920SAnirudh Venkataramanan  * ice_sched_calc_vsi_support_nodes - calculate number of VSI support nodes
1703b126bd6bSKiran Patil  * @pi: pointer to the port info structure
17045513b920SAnirudh Venkataramanan  * @tc_node: pointer to TC node
17055513b920SAnirudh Venkataramanan  * @num_nodes: pointer to num nodes array
17065513b920SAnirudh Venkataramanan  *
17075513b920SAnirudh Venkataramanan  * This function calculates the number of supported nodes needed to add this
1708d337f2afSAnirudh Venkataramanan  * VSI into Tx tree including the VSI, parent and intermediate nodes in below
17095513b920SAnirudh Venkataramanan  * layers
17105513b920SAnirudh Venkataramanan  */
17115513b920SAnirudh Venkataramanan static void
ice_sched_calc_vsi_support_nodes(struct ice_port_info * pi,struct ice_sched_node * tc_node,u16 * num_nodes)1712b126bd6bSKiran Patil ice_sched_calc_vsi_support_nodes(struct ice_port_info *pi,
17135513b920SAnirudh Venkataramanan 				 struct ice_sched_node *tc_node, u16 *num_nodes)
17145513b920SAnirudh Venkataramanan {
17155513b920SAnirudh Venkataramanan 	struct ice_sched_node *node;
1716b36c598cSAnirudh Venkataramanan 	u8 vsil;
1717b36c598cSAnirudh Venkataramanan 	int i;
17185513b920SAnirudh Venkataramanan 
1719b126bd6bSKiran Patil 	vsil = ice_sched_get_vsi_layer(pi->hw);
1720b126bd6bSKiran Patil 	for (i = vsil; i >= pi->hw->sw_entry_point_layer; i--)
17215513b920SAnirudh Venkataramanan 		/* Add intermediate nodes if TC has no children and
17225513b920SAnirudh Venkataramanan 		 * need at least one node for VSI
17235513b920SAnirudh Venkataramanan 		 */
17245513b920SAnirudh Venkataramanan 		if (!tc_node->num_children || i == vsil) {
17255513b920SAnirudh Venkataramanan 			num_nodes[i]++;
17265513b920SAnirudh Venkataramanan 		} else {
17275513b920SAnirudh Venkataramanan 			/* If intermediate nodes are reached max children
17285513b920SAnirudh Venkataramanan 			 * then add a new one.
17295513b920SAnirudh Venkataramanan 			 */
1730b126bd6bSKiran Patil 			node = ice_sched_get_first_node(pi, tc_node, (u8)i);
17315513b920SAnirudh Venkataramanan 			/* scan all the siblings */
17325513b920SAnirudh Venkataramanan 			while (node) {
1733b126bd6bSKiran Patil 				if (node->num_children < pi->hw->max_children[i])
17345513b920SAnirudh Venkataramanan 					break;
17355513b920SAnirudh Venkataramanan 				node = node->sibling;
17365513b920SAnirudh Venkataramanan 			}
17375513b920SAnirudh Venkataramanan 
17380e8fd74dSVictor Raj 			/* tree has one intermediate node to add this new VSI.
17390e8fd74dSVictor Raj 			 * So no need to calculate supported nodes for below
17400e8fd74dSVictor Raj 			 * layers.
17410e8fd74dSVictor Raj 			 */
17420e8fd74dSVictor Raj 			if (node)
17430e8fd74dSVictor Raj 				break;
17445513b920SAnirudh Venkataramanan 			/* all the nodes are full, allocate a new one */
17455513b920SAnirudh Venkataramanan 			num_nodes[i]++;
17465513b920SAnirudh Venkataramanan 		}
17475513b920SAnirudh Venkataramanan }
17485513b920SAnirudh Venkataramanan 
17495513b920SAnirudh Venkataramanan /**
1750d337f2afSAnirudh Venkataramanan  * ice_sched_add_vsi_support_nodes - add VSI supported nodes into Tx tree
17515513b920SAnirudh Venkataramanan  * @pi: port information structure
17524fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
17535513b920SAnirudh Venkataramanan  * @tc_node: pointer to TC node
17545513b920SAnirudh Venkataramanan  * @num_nodes: pointer to num nodes array
17555513b920SAnirudh Venkataramanan  *
1756d337f2afSAnirudh Venkataramanan  * This function adds the VSI supported nodes into Tx tree including the
17575513b920SAnirudh Venkataramanan  * VSI, its parent and intermediate nodes in below layers
17585513b920SAnirudh Venkataramanan  */
17595e24d598STony Nguyen static int
ice_sched_add_vsi_support_nodes(struct ice_port_info * pi,u16 vsi_handle,struct ice_sched_node * tc_node,u16 * num_nodes)17604fb33f31SAnirudh Venkataramanan ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle,
17615513b920SAnirudh Venkataramanan 				struct ice_sched_node *tc_node, u16 *num_nodes)
17625513b920SAnirudh Venkataramanan {
17635513b920SAnirudh Venkataramanan 	struct ice_sched_node *parent = tc_node;
17645513b920SAnirudh Venkataramanan 	u32 first_node_teid;
17655513b920SAnirudh Venkataramanan 	u16 num_added = 0;
17665513b920SAnirudh Venkataramanan 	u8 i, vsil;
17675513b920SAnirudh Venkataramanan 
17685513b920SAnirudh Venkataramanan 	if (!pi)
1769d54699e2STony Nguyen 		return -EINVAL;
17705513b920SAnirudh Venkataramanan 
17715513b920SAnirudh Venkataramanan 	vsil = ice_sched_get_vsi_layer(pi->hw);
17725513b920SAnirudh Venkataramanan 	for (i = pi->hw->sw_entry_point_layer; i <= vsil; i++) {
1773bd557d97STony Nguyen 		int status;
1774bd557d97STony Nguyen 
17755513b920SAnirudh Venkataramanan 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent,
17765513b920SAnirudh Venkataramanan 						      i, num_nodes[i],
17775513b920SAnirudh Venkataramanan 						      &first_node_teid,
17785513b920SAnirudh Venkataramanan 						      &num_added);
17795513b920SAnirudh Venkataramanan 		if (status || num_nodes[i] != num_added)
1780d54699e2STony Nguyen 			return -EIO;
17815513b920SAnirudh Venkataramanan 
17825513b920SAnirudh Venkataramanan 		/* The newly added node can be a new parent for the next
17835513b920SAnirudh Venkataramanan 		 * layer nodes
17845513b920SAnirudh Venkataramanan 		 */
17855513b920SAnirudh Venkataramanan 		if (num_added)
17865513b920SAnirudh Venkataramanan 			parent = ice_sched_find_node_by_teid(tc_node,
17875513b920SAnirudh Venkataramanan 							     first_node_teid);
17885513b920SAnirudh Venkataramanan 		else
17895513b920SAnirudh Venkataramanan 			parent = parent->children[0];
17905513b920SAnirudh Venkataramanan 
17915513b920SAnirudh Venkataramanan 		if (!parent)
1792d54699e2STony Nguyen 			return -EIO;
17935513b920SAnirudh Venkataramanan 
17945513b920SAnirudh Venkataramanan 		if (i == vsil)
17954fb33f31SAnirudh Venkataramanan 			parent->vsi_handle = vsi_handle;
17965513b920SAnirudh Venkataramanan 	}
1797b36c598cSAnirudh Venkataramanan 
17985513b920SAnirudh Venkataramanan 	return 0;
17995513b920SAnirudh Venkataramanan }
18005513b920SAnirudh Venkataramanan 
18015513b920SAnirudh Venkataramanan /**
18025513b920SAnirudh Venkataramanan  * ice_sched_add_vsi_to_topo - add a new VSI into tree
18035513b920SAnirudh Venkataramanan  * @pi: port information structure
18044fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
18055513b920SAnirudh Venkataramanan  * @tc: TC number
18065513b920SAnirudh Venkataramanan  *
18075513b920SAnirudh Venkataramanan  * This function adds a new VSI into scheduler tree
18085513b920SAnirudh Venkataramanan  */
18095e24d598STony Nguyen static int
ice_sched_add_vsi_to_topo(struct ice_port_info * pi,u16 vsi_handle,u8 tc)18104fb33f31SAnirudh Venkataramanan ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc)
18115513b920SAnirudh Venkataramanan {
18125513b920SAnirudh Venkataramanan 	u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
18135513b920SAnirudh Venkataramanan 	struct ice_sched_node *tc_node;
18145513b920SAnirudh Venkataramanan 
18155513b920SAnirudh Venkataramanan 	tc_node = ice_sched_get_tc_node(pi, tc);
18165513b920SAnirudh Venkataramanan 	if (!tc_node)
1817d54699e2STony Nguyen 		return -EINVAL;
18185513b920SAnirudh Venkataramanan 
18195513b920SAnirudh Venkataramanan 	/* calculate number of supported nodes needed for this VSI */
1820b126bd6bSKiran Patil 	ice_sched_calc_vsi_support_nodes(pi, tc_node, num_nodes);
18215513b920SAnirudh Venkataramanan 
1822f9867df6SAnirudh Venkataramanan 	/* add VSI supported nodes to TC subtree */
18234fb33f31SAnirudh Venkataramanan 	return ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node,
18244fb33f31SAnirudh Venkataramanan 					       num_nodes);
18255513b920SAnirudh Venkataramanan }
18265513b920SAnirudh Venkataramanan 
18275513b920SAnirudh Venkataramanan /**
18285513b920SAnirudh Venkataramanan  * ice_sched_update_vsi_child_nodes - update VSI child nodes
18295513b920SAnirudh Venkataramanan  * @pi: port information structure
18304fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
18315513b920SAnirudh Venkataramanan  * @tc: TC number
18325513b920SAnirudh Venkataramanan  * @new_numqs: new number of max queues
18335513b920SAnirudh Venkataramanan  * @owner: owner of this subtree
18345513b920SAnirudh Venkataramanan  *
18355513b920SAnirudh Venkataramanan  * This function updates the VSI child nodes based on the number of queues
18365513b920SAnirudh Venkataramanan  */
18375e24d598STony Nguyen static int
ice_sched_update_vsi_child_nodes(struct ice_port_info * pi,u16 vsi_handle,u8 tc,u16 new_numqs,u8 owner)18384fb33f31SAnirudh Venkataramanan ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
18394fb33f31SAnirudh Venkataramanan 				 u8 tc, u16 new_numqs, u8 owner)
18405513b920SAnirudh Venkataramanan {
18415513b920SAnirudh Venkataramanan 	u16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
18425513b920SAnirudh Venkataramanan 	struct ice_sched_node *vsi_node;
18435513b920SAnirudh Venkataramanan 	struct ice_sched_node *tc_node;
18444fb33f31SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
18455513b920SAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
18465513b920SAnirudh Venkataramanan 	u16 prev_numqs;
18475518ac2aSTony Nguyen 	int status = 0;
18485513b920SAnirudh Venkataramanan 
18495513b920SAnirudh Venkataramanan 	tc_node = ice_sched_get_tc_node(pi, tc);
18505513b920SAnirudh Venkataramanan 	if (!tc_node)
1851d54699e2STony Nguyen 		return -EIO;
18525513b920SAnirudh Venkataramanan 
1853b126bd6bSKiran Patil 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
18545513b920SAnirudh Venkataramanan 	if (!vsi_node)
1855d54699e2STony Nguyen 		return -EIO;
18565513b920SAnirudh Venkataramanan 
18574fb33f31SAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
18584fb33f31SAnirudh Venkataramanan 	if (!vsi_ctx)
1859d54699e2STony Nguyen 		return -EINVAL;
18605513b920SAnirudh Venkataramanan 
1861348048e7SDave Ertman 	if (owner == ICE_SCHED_NODE_OWNER_LAN)
18624fb33f31SAnirudh Venkataramanan 		prev_numqs = vsi_ctx->sched.max_lanq[tc];
1863348048e7SDave Ertman 	else
1864348048e7SDave Ertman 		prev_numqs = vsi_ctx->sched.max_rdmaq[tc];
1865b0153fddSVictor Raj 	/* num queues are not changed or less than the previous number */
1866b0153fddSVictor Raj 	if (new_numqs <= prev_numqs)
18675513b920SAnirudh Venkataramanan 		return status;
1868348048e7SDave Ertman 	if (owner == ICE_SCHED_NODE_OWNER_LAN) {
1869bb87ee0eSAnirudh Venkataramanan 		status = ice_alloc_lan_q_ctx(hw, vsi_handle, tc, new_numqs);
1870bb87ee0eSAnirudh Venkataramanan 		if (status)
1871bb87ee0eSAnirudh Venkataramanan 			return status;
1872348048e7SDave Ertman 	} else {
1873348048e7SDave Ertman 		status = ice_alloc_rdma_q_ctx(hw, vsi_handle, tc, new_numqs);
1874348048e7SDave Ertman 		if (status)
1875348048e7SDave Ertman 			return status;
1876348048e7SDave Ertman 	}
1877bb87ee0eSAnirudh Venkataramanan 
18785513b920SAnirudh Venkataramanan 	if (new_numqs)
18795513b920SAnirudh Venkataramanan 		ice_sched_calc_vsi_child_nodes(hw, new_numqs, new_num_nodes);
1880b0153fddSVictor Raj 	/* Keep the max number of queue configuration all the time. Update the
1881b0153fddSVictor Raj 	 * tree only if number of queues > previous number of queues. This may
1882b0153fddSVictor Raj 	 * leave some extra nodes in the tree if number of queues < previous
1883b0153fddSVictor Raj 	 * number but that wouldn't harm anything. Removing those extra nodes
1884b0153fddSVictor Raj 	 * may complicate the code if those nodes are part of SRL or
1885b0153fddSVictor Raj 	 * individually rate limited.
1886b0153fddSVictor Raj 	 */
18874fb33f31SAnirudh Venkataramanan 	status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node,
18885513b920SAnirudh Venkataramanan 					       new_num_nodes, owner);
18895513b920SAnirudh Venkataramanan 	if (status)
18905513b920SAnirudh Venkataramanan 		return status;
1891348048e7SDave Ertman 	if (owner == ICE_SCHED_NODE_OWNER_LAN)
18924fb33f31SAnirudh Venkataramanan 		vsi_ctx->sched.max_lanq[tc] = new_numqs;
1893348048e7SDave Ertman 	else
1894348048e7SDave Ertman 		vsi_ctx->sched.max_rdmaq[tc] = new_numqs;
18955513b920SAnirudh Venkataramanan 
18961b5c19c7SBruce Allan 	return 0;
18975513b920SAnirudh Venkataramanan }
18985513b920SAnirudh Venkataramanan 
18995513b920SAnirudh Venkataramanan /**
190010e03a22SAnirudh Venkataramanan  * ice_sched_cfg_vsi - configure the new/existing VSI
19015513b920SAnirudh Venkataramanan  * @pi: port information structure
19024fb33f31SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
19035513b920SAnirudh Venkataramanan  * @tc: TC number
19045513b920SAnirudh Venkataramanan  * @maxqs: max number of queues
1905f9867df6SAnirudh Venkataramanan  * @owner: LAN or RDMA
19065513b920SAnirudh Venkataramanan  * @enable: TC enabled or disabled
19075513b920SAnirudh Venkataramanan  *
19085513b920SAnirudh Venkataramanan  * This function adds/updates VSI nodes based on the number of queues. If TC is
19095513b920SAnirudh Venkataramanan  * enabled and VSI is in suspended state then resume the VSI back. If TC is
19105513b920SAnirudh Venkataramanan  * disabled then suspend the VSI if it is not already.
19115513b920SAnirudh Venkataramanan  */
19125e24d598STony Nguyen int
ice_sched_cfg_vsi(struct ice_port_info * pi,u16 vsi_handle,u8 tc,u16 maxqs,u8 owner,bool enable)19134fb33f31SAnirudh Venkataramanan ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs,
19145513b920SAnirudh Venkataramanan 		  u8 owner, bool enable)
19155513b920SAnirudh Venkataramanan {
19165513b920SAnirudh Venkataramanan 	struct ice_sched_node *vsi_node, *tc_node;
19174fb33f31SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
19185513b920SAnirudh Venkataramanan 	struct ice_hw *hw = pi->hw;
19195518ac2aSTony Nguyen 	int status = 0;
19205513b920SAnirudh Venkataramanan 
1921e1ca65a3SVictor Raj 	ice_debug(pi->hw, ICE_DBG_SCHED, "add/config VSI %d\n", vsi_handle);
19225513b920SAnirudh Venkataramanan 	tc_node = ice_sched_get_tc_node(pi, tc);
19235513b920SAnirudh Venkataramanan 	if (!tc_node)
1924d54699e2STony Nguyen 		return -EINVAL;
19254fb33f31SAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
19264fb33f31SAnirudh Venkataramanan 	if (!vsi_ctx)
1927d54699e2STony Nguyen 		return -EINVAL;
1928b126bd6bSKiran Patil 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
19295513b920SAnirudh Venkataramanan 
1930f9867df6SAnirudh Venkataramanan 	/* suspend the VSI if TC is not enabled */
19315513b920SAnirudh Venkataramanan 	if (!enable) {
19325513b920SAnirudh Venkataramanan 		if (vsi_node && vsi_node->in_use) {
19335513b920SAnirudh Venkataramanan 			u32 teid = le32_to_cpu(vsi_node->info.node_teid);
19345513b920SAnirudh Venkataramanan 
19355513b920SAnirudh Venkataramanan 			status = ice_sched_suspend_resume_elems(hw, 1, &teid,
19365513b920SAnirudh Venkataramanan 								true);
19375513b920SAnirudh Venkataramanan 			if (!status)
19385513b920SAnirudh Venkataramanan 				vsi_node->in_use = false;
19395513b920SAnirudh Venkataramanan 		}
19405513b920SAnirudh Venkataramanan 		return status;
19415513b920SAnirudh Venkataramanan 	}
19425513b920SAnirudh Venkataramanan 
19435513b920SAnirudh Venkataramanan 	/* TC is enabled, if it is a new VSI then add it to the tree */
19445513b920SAnirudh Venkataramanan 	if (!vsi_node) {
19454fb33f31SAnirudh Venkataramanan 		status = ice_sched_add_vsi_to_topo(pi, vsi_handle, tc);
19465513b920SAnirudh Venkataramanan 		if (status)
19475513b920SAnirudh Venkataramanan 			return status;
1948b36c598cSAnirudh Venkataramanan 
1949b126bd6bSKiran Patil 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
19505513b920SAnirudh Venkataramanan 		if (!vsi_node)
1951d54699e2STony Nguyen 			return -EIO;
1952b36c598cSAnirudh Venkataramanan 
19534fb33f31SAnirudh Venkataramanan 		vsi_ctx->sched.vsi_node[tc] = vsi_node;
19545513b920SAnirudh Venkataramanan 		vsi_node->in_use = true;
19554fb33f31SAnirudh Venkataramanan 		/* invalidate the max queues whenever VSI gets added first time
19564fb33f31SAnirudh Venkataramanan 		 * into the scheduler tree (boot or after reset). We need to
19574fb33f31SAnirudh Venkataramanan 		 * recreate the child nodes all the time in these cases.
19584fb33f31SAnirudh Venkataramanan 		 */
19594fb33f31SAnirudh Venkataramanan 		vsi_ctx->sched.max_lanq[tc] = 0;
1960348048e7SDave Ertman 		vsi_ctx->sched.max_rdmaq[tc] = 0;
19615513b920SAnirudh Venkataramanan 	}
19625513b920SAnirudh Venkataramanan 
19635513b920SAnirudh Venkataramanan 	/* update the VSI child nodes */
19644fb33f31SAnirudh Venkataramanan 	status = ice_sched_update_vsi_child_nodes(pi, vsi_handle, tc, maxqs,
19654fb33f31SAnirudh Venkataramanan 						  owner);
19665513b920SAnirudh Venkataramanan 	if (status)
19675513b920SAnirudh Venkataramanan 		return status;
19685513b920SAnirudh Venkataramanan 
19695513b920SAnirudh Venkataramanan 	/* TC is enabled, resume the VSI if it is in the suspend state */
19705513b920SAnirudh Venkataramanan 	if (!vsi_node->in_use) {
19715513b920SAnirudh Venkataramanan 		u32 teid = le32_to_cpu(vsi_node->info.node_teid);
19725513b920SAnirudh Venkataramanan 
19735513b920SAnirudh Venkataramanan 		status = ice_sched_suspend_resume_elems(hw, 1, &teid, false);
19745513b920SAnirudh Venkataramanan 		if (!status)
19755513b920SAnirudh Venkataramanan 			vsi_node->in_use = true;
19765513b920SAnirudh Venkataramanan 	}
19775513b920SAnirudh Venkataramanan 
19785513b920SAnirudh Venkataramanan 	return status;
19795513b920SAnirudh Venkataramanan }
198010e03a22SAnirudh Venkataramanan 
198110e03a22SAnirudh Venkataramanan /**
1982ef860480STony Nguyen  * ice_sched_rm_agg_vsi_info - remove aggregator related VSI info entry
198310e03a22SAnirudh Venkataramanan  * @pi: port information structure
198410e03a22SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
198510e03a22SAnirudh Venkataramanan  *
198610e03a22SAnirudh Venkataramanan  * This function removes single aggregator VSI info entry from
198710e03a22SAnirudh Venkataramanan  * aggregator list.
198810e03a22SAnirudh Venkataramanan  */
ice_sched_rm_agg_vsi_info(struct ice_port_info * pi,u16 vsi_handle)1989ebb462dcSBruce Allan static void ice_sched_rm_agg_vsi_info(struct ice_port_info *pi, u16 vsi_handle)
199010e03a22SAnirudh Venkataramanan {
199110e03a22SAnirudh Venkataramanan 	struct ice_sched_agg_info *agg_info;
199210e03a22SAnirudh Venkataramanan 	struct ice_sched_agg_info *atmp;
199310e03a22SAnirudh Venkataramanan 
19949be1d6f8SAnirudh Venkataramanan 	list_for_each_entry_safe(agg_info, atmp, &pi->hw->agg_list,
19959be1d6f8SAnirudh Venkataramanan 				 list_entry) {
199610e03a22SAnirudh Venkataramanan 		struct ice_sched_agg_vsi_info *agg_vsi_info;
199710e03a22SAnirudh Venkataramanan 		struct ice_sched_agg_vsi_info *vtmp;
199810e03a22SAnirudh Venkataramanan 
199910e03a22SAnirudh Venkataramanan 		list_for_each_entry_safe(agg_vsi_info, vtmp,
200010e03a22SAnirudh Venkataramanan 					 &agg_info->agg_vsi_list, list_entry)
200110e03a22SAnirudh Venkataramanan 			if (agg_vsi_info->vsi_handle == vsi_handle) {
200210e03a22SAnirudh Venkataramanan 				list_del(&agg_vsi_info->list_entry);
200310e03a22SAnirudh Venkataramanan 				devm_kfree(ice_hw_to_dev(pi->hw),
200410e03a22SAnirudh Venkataramanan 					   agg_vsi_info);
200510e03a22SAnirudh Venkataramanan 				return;
200610e03a22SAnirudh Venkataramanan 			}
200710e03a22SAnirudh Venkataramanan 	}
200810e03a22SAnirudh Venkataramanan }
200910e03a22SAnirudh Venkataramanan 
201010e03a22SAnirudh Venkataramanan /**
2011f70b9d5fSVictor Raj  * ice_sched_is_leaf_node_present - check for a leaf node in the sub-tree
2012f70b9d5fSVictor Raj  * @node: pointer to the sub-tree node
2013f70b9d5fSVictor Raj  *
2014f70b9d5fSVictor Raj  * This function checks for a leaf node presence in a given sub-tree node.
2015f70b9d5fSVictor Raj  */
ice_sched_is_leaf_node_present(struct ice_sched_node * node)2016f70b9d5fSVictor Raj static bool ice_sched_is_leaf_node_present(struct ice_sched_node *node)
2017f70b9d5fSVictor Raj {
2018f70b9d5fSVictor Raj 	u8 i;
2019f70b9d5fSVictor Raj 
2020f70b9d5fSVictor Raj 	for (i = 0; i < node->num_children; i++)
2021f70b9d5fSVictor Raj 		if (ice_sched_is_leaf_node_present(node->children[i]))
2022f70b9d5fSVictor Raj 			return true;
2023f70b9d5fSVictor Raj 	/* check for a leaf node */
2024f70b9d5fSVictor Raj 	return (node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF);
2025f70b9d5fSVictor Raj }
2026f70b9d5fSVictor Raj 
2027f70b9d5fSVictor Raj /**
202810e03a22SAnirudh Venkataramanan  * ice_sched_rm_vsi_cfg - remove the VSI and its children nodes
202910e03a22SAnirudh Venkataramanan  * @pi: port information structure
203010e03a22SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
203110e03a22SAnirudh Venkataramanan  * @owner: LAN or RDMA
203210e03a22SAnirudh Venkataramanan  *
203310e03a22SAnirudh Venkataramanan  * This function removes the VSI and its LAN or RDMA children nodes from the
203410e03a22SAnirudh Venkataramanan  * scheduler tree.
203510e03a22SAnirudh Venkataramanan  */
20365e24d598STony Nguyen static int
ice_sched_rm_vsi_cfg(struct ice_port_info * pi,u16 vsi_handle,u8 owner)203710e03a22SAnirudh Venkataramanan ice_sched_rm_vsi_cfg(struct ice_port_info *pi, u16 vsi_handle, u8 owner)
203810e03a22SAnirudh Venkataramanan {
203910e03a22SAnirudh Venkataramanan 	struct ice_vsi_ctx *vsi_ctx;
20405518ac2aSTony Nguyen 	int status = -EINVAL;
2041e1ca65a3SVictor Raj 	u8 i;
204210e03a22SAnirudh Venkataramanan 
2043e1ca65a3SVictor Raj 	ice_debug(pi->hw, ICE_DBG_SCHED, "removing VSI %d\n", vsi_handle);
204410e03a22SAnirudh Venkataramanan 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
204510e03a22SAnirudh Venkataramanan 		return status;
204610e03a22SAnirudh Venkataramanan 	mutex_lock(&pi->sched_lock);
204710e03a22SAnirudh Venkataramanan 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
204810e03a22SAnirudh Venkataramanan 	if (!vsi_ctx)
204910e03a22SAnirudh Venkataramanan 		goto exit_sched_rm_vsi_cfg;
205010e03a22SAnirudh Venkataramanan 
20512bdc97beSBruce Allan 	ice_for_each_traffic_class(i) {
205210e03a22SAnirudh Venkataramanan 		struct ice_sched_node *vsi_node, *tc_node;
2053e1ca65a3SVictor Raj 		u8 j = 0;
205410e03a22SAnirudh Venkataramanan 
205510e03a22SAnirudh Venkataramanan 		tc_node = ice_sched_get_tc_node(pi, i);
205610e03a22SAnirudh Venkataramanan 		if (!tc_node)
205710e03a22SAnirudh Venkataramanan 			continue;
205810e03a22SAnirudh Venkataramanan 
2059b126bd6bSKiran Patil 		vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
206010e03a22SAnirudh Venkataramanan 		if (!vsi_node)
206110e03a22SAnirudh Venkataramanan 			continue;
206210e03a22SAnirudh Venkataramanan 
2063f70b9d5fSVictor Raj 		if (ice_sched_is_leaf_node_present(vsi_node)) {
20649228d8b2SJacob Keller 			ice_debug(pi->hw, ICE_DBG_SCHED, "VSI has leaf nodes in TC %d\n", i);
2065d54699e2STony Nguyen 			status = -EBUSY;
2066f70b9d5fSVictor Raj 			goto exit_sched_rm_vsi_cfg;
2067f70b9d5fSVictor Raj 		}
206810e03a22SAnirudh Venkataramanan 		while (j < vsi_node->num_children) {
206910e03a22SAnirudh Venkataramanan 			if (vsi_node->children[j]->owner == owner) {
207010e03a22SAnirudh Venkataramanan 				ice_free_sched_node(pi, vsi_node->children[j]);
207110e03a22SAnirudh Venkataramanan 
207210e03a22SAnirudh Venkataramanan 				/* reset the counter again since the num
207310e03a22SAnirudh Venkataramanan 				 * children will be updated after node removal
207410e03a22SAnirudh Venkataramanan 				 */
207510e03a22SAnirudh Venkataramanan 				j = 0;
207610e03a22SAnirudh Venkataramanan 			} else {
207710e03a22SAnirudh Venkataramanan 				j++;
207810e03a22SAnirudh Venkataramanan 			}
207910e03a22SAnirudh Venkataramanan 		}
208010e03a22SAnirudh Venkataramanan 		/* remove the VSI if it has no children */
208110e03a22SAnirudh Venkataramanan 		if (!vsi_node->num_children) {
208210e03a22SAnirudh Venkataramanan 			ice_free_sched_node(pi, vsi_node);
208310e03a22SAnirudh Venkataramanan 			vsi_ctx->sched.vsi_node[i] = NULL;
208410e03a22SAnirudh Venkataramanan 
2085f9867df6SAnirudh Venkataramanan 			/* clean up aggregator related VSI info if any */
208610e03a22SAnirudh Venkataramanan 			ice_sched_rm_agg_vsi_info(pi, vsi_handle);
208710e03a22SAnirudh Venkataramanan 		}
208810e03a22SAnirudh Venkataramanan 		if (owner == ICE_SCHED_NODE_OWNER_LAN)
208910e03a22SAnirudh Venkataramanan 			vsi_ctx->sched.max_lanq[i] = 0;
2090348048e7SDave Ertman 		else
2091348048e7SDave Ertman 			vsi_ctx->sched.max_rdmaq[i] = 0;
209210e03a22SAnirudh Venkataramanan 	}
209310e03a22SAnirudh Venkataramanan 	status = 0;
209410e03a22SAnirudh Venkataramanan 
209510e03a22SAnirudh Venkataramanan exit_sched_rm_vsi_cfg:
209610e03a22SAnirudh Venkataramanan 	mutex_unlock(&pi->sched_lock);
209710e03a22SAnirudh Venkataramanan 	return status;
209810e03a22SAnirudh Venkataramanan }
209910e03a22SAnirudh Venkataramanan 
210010e03a22SAnirudh Venkataramanan /**
210110e03a22SAnirudh Venkataramanan  * ice_rm_vsi_lan_cfg - remove VSI and its LAN children nodes
210210e03a22SAnirudh Venkataramanan  * @pi: port information structure
210310e03a22SAnirudh Venkataramanan  * @vsi_handle: software VSI handle
210410e03a22SAnirudh Venkataramanan  *
210510e03a22SAnirudh Venkataramanan  * This function clears the VSI and its LAN children nodes from scheduler tree
210610e03a22SAnirudh Venkataramanan  * for all TCs.
210710e03a22SAnirudh Venkataramanan  */
ice_rm_vsi_lan_cfg(struct ice_port_info * pi,u16 vsi_handle)21085e24d598STony Nguyen int ice_rm_vsi_lan_cfg(struct ice_port_info *pi, u16 vsi_handle)
210910e03a22SAnirudh Venkataramanan {
211010e03a22SAnirudh Venkataramanan 	return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_LAN);
211110e03a22SAnirudh Venkataramanan }
21121ddef455SUsha Ketineni 
21131ddef455SUsha Ketineni /**
2114ff7e9321SBrett Creeley  * ice_rm_vsi_rdma_cfg - remove VSI and its RDMA children nodes
2115ff7e9321SBrett Creeley  * @pi: port information structure
2116ff7e9321SBrett Creeley  * @vsi_handle: software VSI handle
2117ff7e9321SBrett Creeley  *
2118ff7e9321SBrett Creeley  * This function clears the VSI and its RDMA children nodes from scheduler tree
2119ff7e9321SBrett Creeley  * for all TCs.
2120ff7e9321SBrett Creeley  */
ice_rm_vsi_rdma_cfg(struct ice_port_info * pi,u16 vsi_handle)21215e24d598STony Nguyen int ice_rm_vsi_rdma_cfg(struct ice_port_info *pi, u16 vsi_handle)
2122ff7e9321SBrett Creeley {
2123ff7e9321SBrett Creeley 	return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_RDMA);
2124ff7e9321SBrett Creeley }
2125ff7e9321SBrett Creeley 
2126ff7e9321SBrett Creeley /**
2127b126bd6bSKiran Patil  * ice_get_agg_info - get the aggregator ID
2128b126bd6bSKiran Patil  * @hw: pointer to the hardware structure
2129b126bd6bSKiran Patil  * @agg_id: aggregator ID
2130b126bd6bSKiran Patil  *
2131b126bd6bSKiran Patil  * This function validates aggregator ID. The function returns info if
2132b126bd6bSKiran Patil  * aggregator ID is present in list otherwise it returns null.
2133b126bd6bSKiran Patil  */
2134b126bd6bSKiran Patil static struct ice_sched_agg_info *
ice_get_agg_info(struct ice_hw * hw,u32 agg_id)2135b126bd6bSKiran Patil ice_get_agg_info(struct ice_hw *hw, u32 agg_id)
2136b126bd6bSKiran Patil {
2137b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2138b126bd6bSKiran Patil 
2139b126bd6bSKiran Patil 	list_for_each_entry(agg_info, &hw->agg_list, list_entry)
2140b126bd6bSKiran Patil 		if (agg_info->agg_id == agg_id)
2141b126bd6bSKiran Patil 			return agg_info;
2142b126bd6bSKiran Patil 
2143b126bd6bSKiran Patil 	return NULL;
2144b126bd6bSKiran Patil }
2145b126bd6bSKiran Patil 
2146b126bd6bSKiran Patil /**
2147b126bd6bSKiran Patil  * ice_sched_get_free_vsi_parent - Find a free parent node in aggregator subtree
2148b126bd6bSKiran Patil  * @hw: pointer to the HW struct
2149b126bd6bSKiran Patil  * @node: pointer to a child node
2150b126bd6bSKiran Patil  * @num_nodes: num nodes count array
2151b126bd6bSKiran Patil  *
2152b126bd6bSKiran Patil  * This function walks through the aggregator subtree to find a free parent
2153b126bd6bSKiran Patil  * node
2154b126bd6bSKiran Patil  */
215523ccae5cSDave Ertman struct ice_sched_node *
ice_sched_get_free_vsi_parent(struct ice_hw * hw,struct ice_sched_node * node,u16 * num_nodes)2156b126bd6bSKiran Patil ice_sched_get_free_vsi_parent(struct ice_hw *hw, struct ice_sched_node *node,
2157b126bd6bSKiran Patil 			      u16 *num_nodes)
2158b126bd6bSKiran Patil {
2159b126bd6bSKiran Patil 	u8 l = node->tx_sched_layer;
2160b126bd6bSKiran Patil 	u8 vsil, i;
2161b126bd6bSKiran Patil 
2162b126bd6bSKiran Patil 	vsil = ice_sched_get_vsi_layer(hw);
2163b126bd6bSKiran Patil 
2164b126bd6bSKiran Patil 	/* Is it VSI parent layer ? */
2165b126bd6bSKiran Patil 	if (l == vsil - 1)
2166b126bd6bSKiran Patil 		return (node->num_children < hw->max_children[l]) ? node : NULL;
2167b126bd6bSKiran Patil 
2168b126bd6bSKiran Patil 	/* We have intermediate nodes. Let's walk through the subtree. If the
2169b126bd6bSKiran Patil 	 * intermediate node has space to add a new node then clear the count
2170b126bd6bSKiran Patil 	 */
2171b126bd6bSKiran Patil 	if (node->num_children < hw->max_children[l])
2172b126bd6bSKiran Patil 		num_nodes[l] = 0;
2173b126bd6bSKiran Patil 	/* The below recursive call is intentional and wouldn't go more than
2174b126bd6bSKiran Patil 	 * 2 or 3 iterations.
2175b126bd6bSKiran Patil 	 */
2176b126bd6bSKiran Patil 
2177b126bd6bSKiran Patil 	for (i = 0; i < node->num_children; i++) {
2178b126bd6bSKiran Patil 		struct ice_sched_node *parent;
2179b126bd6bSKiran Patil 
2180b126bd6bSKiran Patil 		parent = ice_sched_get_free_vsi_parent(hw, node->children[i],
2181b126bd6bSKiran Patil 						       num_nodes);
2182b126bd6bSKiran Patil 		if (parent)
2183b126bd6bSKiran Patil 			return parent;
2184b126bd6bSKiran Patil 	}
2185b126bd6bSKiran Patil 
2186b126bd6bSKiran Patil 	return NULL;
2187b126bd6bSKiran Patil }
2188b126bd6bSKiran Patil 
2189b126bd6bSKiran Patil /**
2190b126bd6bSKiran Patil  * ice_sched_update_parent - update the new parent in SW DB
2191b126bd6bSKiran Patil  * @new_parent: pointer to a new parent node
2192b126bd6bSKiran Patil  * @node: pointer to a child node
2193b126bd6bSKiran Patil  *
2194b126bd6bSKiran Patil  * This function removes the child from the old parent and adds it to a new
2195b126bd6bSKiran Patil  * parent
2196b126bd6bSKiran Patil  */
219716dfa494SMichal Wilczynski void
ice_sched_update_parent(struct ice_sched_node * new_parent,struct ice_sched_node * node)2198b126bd6bSKiran Patil ice_sched_update_parent(struct ice_sched_node *new_parent,
2199b126bd6bSKiran Patil 			struct ice_sched_node *node)
2200b126bd6bSKiran Patil {
2201b126bd6bSKiran Patil 	struct ice_sched_node *old_parent;
2202b126bd6bSKiran Patil 	u8 i, j;
2203b126bd6bSKiran Patil 
2204b126bd6bSKiran Patil 	old_parent = node->parent;
2205b126bd6bSKiran Patil 
2206b126bd6bSKiran Patil 	/* update the old parent children */
2207b126bd6bSKiran Patil 	for (i = 0; i < old_parent->num_children; i++)
2208b126bd6bSKiran Patil 		if (old_parent->children[i] == node) {
2209b126bd6bSKiran Patil 			for (j = i + 1; j < old_parent->num_children; j++)
2210b126bd6bSKiran Patil 				old_parent->children[j - 1] =
2211b126bd6bSKiran Patil 					old_parent->children[j];
2212b126bd6bSKiran Patil 			old_parent->num_children--;
2213b126bd6bSKiran Patil 			break;
2214b126bd6bSKiran Patil 		}
2215b126bd6bSKiran Patil 
2216b126bd6bSKiran Patil 	/* now move the node to a new parent */
2217b126bd6bSKiran Patil 	new_parent->children[new_parent->num_children++] = node;
2218b126bd6bSKiran Patil 	node->parent = new_parent;
2219b126bd6bSKiran Patil 	node->info.parent_teid = new_parent->info.node_teid;
2220b126bd6bSKiran Patil }
2221b126bd6bSKiran Patil 
2222b126bd6bSKiran Patil /**
2223b126bd6bSKiran Patil  * ice_sched_move_nodes - move child nodes to a given parent
2224b126bd6bSKiran Patil  * @pi: port information structure
2225b126bd6bSKiran Patil  * @parent: pointer to parent node
2226b126bd6bSKiran Patil  * @num_items: number of child nodes to be moved
2227b126bd6bSKiran Patil  * @list: pointer to child node teids
2228b126bd6bSKiran Patil  *
2229b126bd6bSKiran Patil  * This function move the child nodes to a given parent.
2230b126bd6bSKiran Patil  */
223116dfa494SMichal Wilczynski int
ice_sched_move_nodes(struct ice_port_info * pi,struct ice_sched_node * parent,u16 num_items,u32 * list)2232b126bd6bSKiran Patil ice_sched_move_nodes(struct ice_port_info *pi, struct ice_sched_node *parent,
2233b126bd6bSKiran Patil 		     u16 num_items, u32 *list)
2234b126bd6bSKiran Patil {
2235b126bd6bSKiran Patil 	struct ice_aqc_move_elem *buf;
2236b126bd6bSKiran Patil 	struct ice_sched_node *node;
2237b126bd6bSKiran Patil 	u16 i, grps_movd = 0;
2238b126bd6bSKiran Patil 	struct ice_hw *hw;
22395518ac2aSTony Nguyen 	int status = 0;
2240b126bd6bSKiran Patil 	u16 buf_len;
2241b126bd6bSKiran Patil 
2242b126bd6bSKiran Patil 	hw = pi->hw;
2243b126bd6bSKiran Patil 
2244b126bd6bSKiran Patil 	if (!parent || !num_items)
2245d54699e2STony Nguyen 		return -EINVAL;
2246b126bd6bSKiran Patil 
2247b126bd6bSKiran Patil 	/* Does parent have enough space */
2248b126bd6bSKiran Patil 	if (parent->num_children + num_items >
2249b126bd6bSKiran Patil 	    hw->max_children[parent->tx_sched_layer])
2250d54699e2STony Nguyen 		return -ENOSPC;
2251b126bd6bSKiran Patil 
2252b126bd6bSKiran Patil 	buf_len = struct_size(buf, teid, 1);
2253b126bd6bSKiran Patil 	buf = kzalloc(buf_len, GFP_KERNEL);
2254b126bd6bSKiran Patil 	if (!buf)
2255d54699e2STony Nguyen 		return -ENOMEM;
2256b126bd6bSKiran Patil 
2257b126bd6bSKiran Patil 	for (i = 0; i < num_items; i++) {
2258b126bd6bSKiran Patil 		node = ice_sched_find_node_by_teid(pi->root, list[i]);
2259b126bd6bSKiran Patil 		if (!node) {
2260d54699e2STony Nguyen 			status = -EINVAL;
2261b126bd6bSKiran Patil 			goto move_err_exit;
2262b126bd6bSKiran Patil 		}
2263b126bd6bSKiran Patil 
2264b126bd6bSKiran Patil 		buf->hdr.src_parent_teid = node->info.parent_teid;
2265b126bd6bSKiran Patil 		buf->hdr.dest_parent_teid = parent->info.node_teid;
2266b126bd6bSKiran Patil 		buf->teid[0] = node->info.node_teid;
2267b126bd6bSKiran Patil 		buf->hdr.num_elems = cpu_to_le16(1);
2268b126bd6bSKiran Patil 		status = ice_aq_move_sched_elems(hw, 1, buf, buf_len,
2269b126bd6bSKiran Patil 						 &grps_movd, NULL);
2270b126bd6bSKiran Patil 		if (status && grps_movd != 1) {
2271d54699e2STony Nguyen 			status = -EIO;
2272b126bd6bSKiran Patil 			goto move_err_exit;
2273b126bd6bSKiran Patil 		}
2274b126bd6bSKiran Patil 
2275b126bd6bSKiran Patil 		/* update the SW DB */
2276b126bd6bSKiran Patil 		ice_sched_update_parent(parent, node);
2277b126bd6bSKiran Patil 	}
2278b126bd6bSKiran Patil 
2279b126bd6bSKiran Patil move_err_exit:
2280b126bd6bSKiran Patil 	kfree(buf);
2281b126bd6bSKiran Patil 	return status;
2282b126bd6bSKiran Patil }
2283b126bd6bSKiran Patil 
2284b126bd6bSKiran Patil /**
2285b126bd6bSKiran Patil  * ice_sched_move_vsi_to_agg - move VSI to aggregator node
2286b126bd6bSKiran Patil  * @pi: port information structure
2287b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2288b126bd6bSKiran Patil  * @agg_id: aggregator ID
2289b126bd6bSKiran Patil  * @tc: TC number
2290b126bd6bSKiran Patil  *
2291b126bd6bSKiran Patil  * This function moves a VSI to an aggregator node or its subtree.
2292b126bd6bSKiran Patil  * Intermediate nodes may be created if required.
2293b126bd6bSKiran Patil  */
22945e24d598STony Nguyen static int
ice_sched_move_vsi_to_agg(struct ice_port_info * pi,u16 vsi_handle,u32 agg_id,u8 tc)2295b126bd6bSKiran Patil ice_sched_move_vsi_to_agg(struct ice_port_info *pi, u16 vsi_handle, u32 agg_id,
2296b126bd6bSKiran Patil 			  u8 tc)
2297b126bd6bSKiran Patil {
2298b126bd6bSKiran Patil 	struct ice_sched_node *vsi_node, *agg_node, *tc_node, *parent;
2299b126bd6bSKiran Patil 	u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
2300b126bd6bSKiran Patil 	u32 first_node_teid, vsi_teid;
2301b126bd6bSKiran Patil 	u16 num_nodes_added;
2302b126bd6bSKiran Patil 	u8 aggl, vsil, i;
23035518ac2aSTony Nguyen 	int status;
2304b126bd6bSKiran Patil 
2305b126bd6bSKiran Patil 	tc_node = ice_sched_get_tc_node(pi, tc);
2306b126bd6bSKiran Patil 	if (!tc_node)
2307d54699e2STony Nguyen 		return -EIO;
2308b126bd6bSKiran Patil 
2309b126bd6bSKiran Patil 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
2310b126bd6bSKiran Patil 	if (!agg_node)
2311d54699e2STony Nguyen 		return -ENOENT;
2312b126bd6bSKiran Patil 
2313b126bd6bSKiran Patil 	vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
2314b126bd6bSKiran Patil 	if (!vsi_node)
2315d54699e2STony Nguyen 		return -ENOENT;
2316b126bd6bSKiran Patil 
2317b126bd6bSKiran Patil 	/* Is this VSI already part of given aggregator? */
2318b126bd6bSKiran Patil 	if (ice_sched_find_node_in_subtree(pi->hw, agg_node, vsi_node))
2319b126bd6bSKiran Patil 		return 0;
2320b126bd6bSKiran Patil 
2321b126bd6bSKiran Patil 	aggl = ice_sched_get_agg_layer(pi->hw);
2322b126bd6bSKiran Patil 	vsil = ice_sched_get_vsi_layer(pi->hw);
2323b126bd6bSKiran Patil 
2324b126bd6bSKiran Patil 	/* set intermediate node count to 1 between aggregator and VSI layers */
2325b126bd6bSKiran Patil 	for (i = aggl + 1; i < vsil; i++)
2326b126bd6bSKiran Patil 		num_nodes[i] = 1;
2327b126bd6bSKiran Patil 
2328b126bd6bSKiran Patil 	/* Check if the aggregator subtree has any free node to add the VSI */
2329b126bd6bSKiran Patil 	for (i = 0; i < agg_node->num_children; i++) {
2330b126bd6bSKiran Patil 		parent = ice_sched_get_free_vsi_parent(pi->hw,
2331b126bd6bSKiran Patil 						       agg_node->children[i],
2332b126bd6bSKiran Patil 						       num_nodes);
2333b126bd6bSKiran Patil 		if (parent)
2334b126bd6bSKiran Patil 			goto move_nodes;
2335b126bd6bSKiran Patil 	}
2336b126bd6bSKiran Patil 
2337b126bd6bSKiran Patil 	/* add new nodes */
2338b126bd6bSKiran Patil 	parent = agg_node;
2339b126bd6bSKiran Patil 	for (i = aggl + 1; i < vsil; i++) {
2340b126bd6bSKiran Patil 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
2341b126bd6bSKiran Patil 						      num_nodes[i],
2342b126bd6bSKiran Patil 						      &first_node_teid,
2343b126bd6bSKiran Patil 						      &num_nodes_added);
2344b126bd6bSKiran Patil 		if (status || num_nodes[i] != num_nodes_added)
2345d54699e2STony Nguyen 			return -EIO;
2346b126bd6bSKiran Patil 
2347b126bd6bSKiran Patil 		/* The newly added node can be a new parent for the next
2348b126bd6bSKiran Patil 		 * layer nodes
2349b126bd6bSKiran Patil 		 */
2350b126bd6bSKiran Patil 		if (num_nodes_added)
2351b126bd6bSKiran Patil 			parent = ice_sched_find_node_by_teid(tc_node,
2352b126bd6bSKiran Patil 							     first_node_teid);
2353b126bd6bSKiran Patil 		else
2354b126bd6bSKiran Patil 			parent = parent->children[0];
2355b126bd6bSKiran Patil 
2356b126bd6bSKiran Patil 		if (!parent)
2357d54699e2STony Nguyen 			return -EIO;
2358b126bd6bSKiran Patil 	}
2359b126bd6bSKiran Patil 
2360b126bd6bSKiran Patil move_nodes:
2361b126bd6bSKiran Patil 	vsi_teid = le32_to_cpu(vsi_node->info.node_teid);
2362b126bd6bSKiran Patil 	return ice_sched_move_nodes(pi, parent, 1, &vsi_teid);
2363b126bd6bSKiran Patil }
2364b126bd6bSKiran Patil 
2365b126bd6bSKiran Patil /**
2366b126bd6bSKiran Patil  * ice_move_all_vsi_to_dflt_agg - move all VSI(s) to default aggregator
2367b126bd6bSKiran Patil  * @pi: port information structure
2368b126bd6bSKiran Patil  * @agg_info: aggregator info
2369b126bd6bSKiran Patil  * @tc: traffic class number
2370b126bd6bSKiran Patil  * @rm_vsi_info: true or false
2371b126bd6bSKiran Patil  *
2372b126bd6bSKiran Patil  * This function move all the VSI(s) to the default aggregator and delete
2373b126bd6bSKiran Patil  * aggregator VSI info based on passed in boolean parameter rm_vsi_info. The
2374b126bd6bSKiran Patil  * caller holds the scheduler lock.
2375b126bd6bSKiran Patil  */
23765e24d598STony Nguyen static int
ice_move_all_vsi_to_dflt_agg(struct ice_port_info * pi,struct ice_sched_agg_info * agg_info,u8 tc,bool rm_vsi_info)2377b126bd6bSKiran Patil ice_move_all_vsi_to_dflt_agg(struct ice_port_info *pi,
2378b126bd6bSKiran Patil 			     struct ice_sched_agg_info *agg_info, u8 tc,
2379b126bd6bSKiran Patil 			     bool rm_vsi_info)
2380b126bd6bSKiran Patil {
2381b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *agg_vsi_info;
2382b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *tmp;
23835e24d598STony Nguyen 	int status = 0;
2384b126bd6bSKiran Patil 
2385b126bd6bSKiran Patil 	list_for_each_entry_safe(agg_vsi_info, tmp, &agg_info->agg_vsi_list,
2386b126bd6bSKiran Patil 				 list_entry) {
2387b126bd6bSKiran Patil 		u16 vsi_handle = agg_vsi_info->vsi_handle;
2388b126bd6bSKiran Patil 
2389b126bd6bSKiran Patil 		/* Move VSI to default aggregator */
2390b126bd6bSKiran Patil 		if (!ice_is_tc_ena(agg_vsi_info->tc_bitmap[0], tc))
2391b126bd6bSKiran Patil 			continue;
2392b126bd6bSKiran Patil 
2393b126bd6bSKiran Patil 		status = ice_sched_move_vsi_to_agg(pi, vsi_handle,
2394b126bd6bSKiran Patil 						   ICE_DFLT_AGG_ID, tc);
2395b126bd6bSKiran Patil 		if (status)
2396b126bd6bSKiran Patil 			break;
2397b126bd6bSKiran Patil 
2398b126bd6bSKiran Patil 		clear_bit(tc, agg_vsi_info->tc_bitmap);
2399b126bd6bSKiran Patil 		if (rm_vsi_info && !agg_vsi_info->tc_bitmap[0]) {
2400b126bd6bSKiran Patil 			list_del(&agg_vsi_info->list_entry);
2401b126bd6bSKiran Patil 			devm_kfree(ice_hw_to_dev(pi->hw), agg_vsi_info);
2402b126bd6bSKiran Patil 		}
2403b126bd6bSKiran Patil 	}
2404b126bd6bSKiran Patil 
2405b126bd6bSKiran Patil 	return status;
2406b126bd6bSKiran Patil }
2407b126bd6bSKiran Patil 
2408b126bd6bSKiran Patil /**
2409b126bd6bSKiran Patil  * ice_sched_is_agg_inuse - check whether the aggregator is in use or not
2410b126bd6bSKiran Patil  * @pi: port information structure
2411b126bd6bSKiran Patil  * @node: node pointer
2412b126bd6bSKiran Patil  *
2413b126bd6bSKiran Patil  * This function checks whether the aggregator is attached with any VSI or not.
2414b126bd6bSKiran Patil  */
2415b126bd6bSKiran Patil static bool
ice_sched_is_agg_inuse(struct ice_port_info * pi,struct ice_sched_node * node)2416b126bd6bSKiran Patil ice_sched_is_agg_inuse(struct ice_port_info *pi, struct ice_sched_node *node)
2417b126bd6bSKiran Patil {
2418b126bd6bSKiran Patil 	u8 vsil, i;
2419b126bd6bSKiran Patil 
2420b126bd6bSKiran Patil 	vsil = ice_sched_get_vsi_layer(pi->hw);
2421b126bd6bSKiran Patil 	if (node->tx_sched_layer < vsil - 1) {
2422b126bd6bSKiran Patil 		for (i = 0; i < node->num_children; i++)
2423b126bd6bSKiran Patil 			if (ice_sched_is_agg_inuse(pi, node->children[i]))
2424b126bd6bSKiran Patil 				return true;
2425b126bd6bSKiran Patil 		return false;
2426b126bd6bSKiran Patil 	} else {
2427b126bd6bSKiran Patil 		return node->num_children ? true : false;
2428b126bd6bSKiran Patil 	}
2429b126bd6bSKiran Patil }
2430b126bd6bSKiran Patil 
2431b126bd6bSKiran Patil /**
2432b126bd6bSKiran Patil  * ice_sched_rm_agg_cfg - remove the aggregator node
2433b126bd6bSKiran Patil  * @pi: port information structure
2434b126bd6bSKiran Patil  * @agg_id: aggregator ID
2435b126bd6bSKiran Patil  * @tc: TC number
2436b126bd6bSKiran Patil  *
2437b126bd6bSKiran Patil  * This function removes the aggregator node and intermediate nodes if any
2438b126bd6bSKiran Patil  * from the given TC
2439b126bd6bSKiran Patil  */
24405e24d598STony Nguyen static int
ice_sched_rm_agg_cfg(struct ice_port_info * pi,u32 agg_id,u8 tc)2441b126bd6bSKiran Patil ice_sched_rm_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc)
2442b126bd6bSKiran Patil {
2443b126bd6bSKiran Patil 	struct ice_sched_node *tc_node, *agg_node;
2444b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
2445b126bd6bSKiran Patil 
2446b126bd6bSKiran Patil 	tc_node = ice_sched_get_tc_node(pi, tc);
2447b126bd6bSKiran Patil 	if (!tc_node)
2448d54699e2STony Nguyen 		return -EIO;
2449b126bd6bSKiran Patil 
2450b126bd6bSKiran Patil 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
2451b126bd6bSKiran Patil 	if (!agg_node)
2452d54699e2STony Nguyen 		return -ENOENT;
2453b126bd6bSKiran Patil 
2454b126bd6bSKiran Patil 	/* Can't remove the aggregator node if it has children */
2455b126bd6bSKiran Patil 	if (ice_sched_is_agg_inuse(pi, agg_node))
2456d54699e2STony Nguyen 		return -EBUSY;
2457b126bd6bSKiran Patil 
2458b126bd6bSKiran Patil 	/* need to remove the whole subtree if aggregator node is the
2459b126bd6bSKiran Patil 	 * only child.
2460b126bd6bSKiran Patil 	 */
2461b126bd6bSKiran Patil 	while (agg_node->tx_sched_layer > hw->sw_entry_point_layer) {
2462b126bd6bSKiran Patil 		struct ice_sched_node *parent = agg_node->parent;
2463b126bd6bSKiran Patil 
2464b126bd6bSKiran Patil 		if (!parent)
2465d54699e2STony Nguyen 			return -EIO;
2466b126bd6bSKiran Patil 
2467b126bd6bSKiran Patil 		if (parent->num_children > 1)
2468b126bd6bSKiran Patil 			break;
2469b126bd6bSKiran Patil 
2470b126bd6bSKiran Patil 		agg_node = parent;
2471b126bd6bSKiran Patil 	}
2472b126bd6bSKiran Patil 
2473b126bd6bSKiran Patil 	ice_free_sched_node(pi, agg_node);
2474b126bd6bSKiran Patil 	return 0;
2475b126bd6bSKiran Patil }
2476b126bd6bSKiran Patil 
2477b126bd6bSKiran Patil /**
2478b126bd6bSKiran Patil  * ice_rm_agg_cfg_tc - remove aggregator configuration for TC
2479b126bd6bSKiran Patil  * @pi: port information structure
2480b126bd6bSKiran Patil  * @agg_info: aggregator ID
2481b126bd6bSKiran Patil  * @tc: TC number
2482b126bd6bSKiran Patil  * @rm_vsi_info: bool value true or false
2483b126bd6bSKiran Patil  *
2484b126bd6bSKiran Patil  * This function removes aggregator reference to VSI of given TC. It removes
2485b126bd6bSKiran Patil  * the aggregator configuration completely for requested TC. The caller needs
2486b126bd6bSKiran Patil  * to hold the scheduler lock.
2487b126bd6bSKiran Patil  */
24885e24d598STony Nguyen static int
ice_rm_agg_cfg_tc(struct ice_port_info * pi,struct ice_sched_agg_info * agg_info,u8 tc,bool rm_vsi_info)2489b126bd6bSKiran Patil ice_rm_agg_cfg_tc(struct ice_port_info *pi, struct ice_sched_agg_info *agg_info,
2490b126bd6bSKiran Patil 		  u8 tc, bool rm_vsi_info)
2491b126bd6bSKiran Patil {
24925e24d598STony Nguyen 	int status = 0;
2493b126bd6bSKiran Patil 
2494b126bd6bSKiran Patil 	/* If nothing to remove - return success */
2495b126bd6bSKiran Patil 	if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
2496b126bd6bSKiran Patil 		goto exit_rm_agg_cfg_tc;
2497b126bd6bSKiran Patil 
2498b126bd6bSKiran Patil 	status = ice_move_all_vsi_to_dflt_agg(pi, agg_info, tc, rm_vsi_info);
2499b126bd6bSKiran Patil 	if (status)
2500b126bd6bSKiran Patil 		goto exit_rm_agg_cfg_tc;
2501b126bd6bSKiran Patil 
2502b126bd6bSKiran Patil 	/* Delete aggregator node(s) */
2503b126bd6bSKiran Patil 	status = ice_sched_rm_agg_cfg(pi, agg_info->agg_id, tc);
2504b126bd6bSKiran Patil 	if (status)
2505b126bd6bSKiran Patil 		goto exit_rm_agg_cfg_tc;
2506b126bd6bSKiran Patil 
2507b126bd6bSKiran Patil 	clear_bit(tc, agg_info->tc_bitmap);
2508b126bd6bSKiran Patil exit_rm_agg_cfg_tc:
2509b126bd6bSKiran Patil 	return status;
2510b126bd6bSKiran Patil }
2511b126bd6bSKiran Patil 
2512b126bd6bSKiran Patil /**
2513b126bd6bSKiran Patil  * ice_save_agg_tc_bitmap - save aggregator TC bitmap
2514b126bd6bSKiran Patil  * @pi: port information structure
2515b126bd6bSKiran Patil  * @agg_id: aggregator ID
2516b126bd6bSKiran Patil  * @tc_bitmap: 8 bits TC bitmap
2517b126bd6bSKiran Patil  *
2518b126bd6bSKiran Patil  * Save aggregator TC bitmap. This function needs to be called with scheduler
2519b126bd6bSKiran Patil  * lock held.
2520b126bd6bSKiran Patil  */
25215e24d598STony Nguyen static int
ice_save_agg_tc_bitmap(struct ice_port_info * pi,u32 agg_id,unsigned long * tc_bitmap)2522b126bd6bSKiran Patil ice_save_agg_tc_bitmap(struct ice_port_info *pi, u32 agg_id,
2523b126bd6bSKiran Patil 		       unsigned long *tc_bitmap)
2524b126bd6bSKiran Patil {
2525b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2526b126bd6bSKiran Patil 
2527b126bd6bSKiran Patil 	agg_info = ice_get_agg_info(pi->hw, agg_id);
2528b126bd6bSKiran Patil 	if (!agg_info)
2529d54699e2STony Nguyen 		return -EINVAL;
2530b126bd6bSKiran Patil 	bitmap_copy(agg_info->replay_tc_bitmap, tc_bitmap,
2531b126bd6bSKiran Patil 		    ICE_MAX_TRAFFIC_CLASS);
2532b126bd6bSKiran Patil 	return 0;
2533b126bd6bSKiran Patil }
2534b126bd6bSKiran Patil 
2535b126bd6bSKiran Patil /**
2536b126bd6bSKiran Patil  * ice_sched_add_agg_cfg - create an aggregator node
2537b126bd6bSKiran Patil  * @pi: port information structure
2538b126bd6bSKiran Patil  * @agg_id: aggregator ID
2539b126bd6bSKiran Patil  * @tc: TC number
2540b126bd6bSKiran Patil  *
2541b126bd6bSKiran Patil  * This function creates an aggregator node and intermediate nodes if required
2542b126bd6bSKiran Patil  * for the given TC
2543b126bd6bSKiran Patil  */
25445e24d598STony Nguyen static int
ice_sched_add_agg_cfg(struct ice_port_info * pi,u32 agg_id,u8 tc)2545b126bd6bSKiran Patil ice_sched_add_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc)
2546b126bd6bSKiran Patil {
2547b126bd6bSKiran Patil 	struct ice_sched_node *parent, *agg_node, *tc_node;
2548b126bd6bSKiran Patil 	u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
2549b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
2550b126bd6bSKiran Patil 	u32 first_node_teid;
2551b126bd6bSKiran Patil 	u16 num_nodes_added;
25525518ac2aSTony Nguyen 	int status = 0;
2553b126bd6bSKiran Patil 	u8 i, aggl;
2554b126bd6bSKiran Patil 
2555b126bd6bSKiran Patil 	tc_node = ice_sched_get_tc_node(pi, tc);
2556b126bd6bSKiran Patil 	if (!tc_node)
2557d54699e2STony Nguyen 		return -EIO;
2558b126bd6bSKiran Patil 
2559b126bd6bSKiran Patil 	agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
2560b126bd6bSKiran Patil 	/* Does Agg node already exist ? */
2561b126bd6bSKiran Patil 	if (agg_node)
2562b126bd6bSKiran Patil 		return status;
2563b126bd6bSKiran Patil 
2564b126bd6bSKiran Patil 	aggl = ice_sched_get_agg_layer(hw);
2565b126bd6bSKiran Patil 
2566b126bd6bSKiran Patil 	/* need one node in Agg layer */
2567b126bd6bSKiran Patil 	num_nodes[aggl] = 1;
2568b126bd6bSKiran Patil 
2569b126bd6bSKiran Patil 	/* Check whether the intermediate nodes have space to add the
2570b126bd6bSKiran Patil 	 * new aggregator. If they are full, then SW needs to allocate a new
2571b126bd6bSKiran Patil 	 * intermediate node on those layers
2572b126bd6bSKiran Patil 	 */
2573b126bd6bSKiran Patil 	for (i = hw->sw_entry_point_layer; i < aggl; i++) {
2574b126bd6bSKiran Patil 		parent = ice_sched_get_first_node(pi, tc_node, i);
2575b126bd6bSKiran Patil 
2576b126bd6bSKiran Patil 		/* scan all the siblings */
2577b126bd6bSKiran Patil 		while (parent) {
2578b126bd6bSKiran Patil 			if (parent->num_children < hw->max_children[i])
2579b126bd6bSKiran Patil 				break;
2580b126bd6bSKiran Patil 			parent = parent->sibling;
2581b126bd6bSKiran Patil 		}
2582b126bd6bSKiran Patil 
2583b126bd6bSKiran Patil 		/* all the nodes are full, reserve one for this layer */
2584b126bd6bSKiran Patil 		if (!parent)
2585b126bd6bSKiran Patil 			num_nodes[i]++;
2586b126bd6bSKiran Patil 	}
2587b126bd6bSKiran Patil 
2588b126bd6bSKiran Patil 	/* add the aggregator node */
2589b126bd6bSKiran Patil 	parent = tc_node;
2590b126bd6bSKiran Patil 	for (i = hw->sw_entry_point_layer; i <= aggl; i++) {
2591b126bd6bSKiran Patil 		if (!parent)
2592d54699e2STony Nguyen 			return -EIO;
2593b126bd6bSKiran Patil 
2594b126bd6bSKiran Patil 		status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
2595b126bd6bSKiran Patil 						      num_nodes[i],
2596b126bd6bSKiran Patil 						      &first_node_teid,
2597b126bd6bSKiran Patil 						      &num_nodes_added);
2598b126bd6bSKiran Patil 		if (status || num_nodes[i] != num_nodes_added)
2599d54699e2STony Nguyen 			return -EIO;
2600b126bd6bSKiran Patil 
2601b126bd6bSKiran Patil 		/* The newly added node can be a new parent for the next
2602b126bd6bSKiran Patil 		 * layer nodes
2603b126bd6bSKiran Patil 		 */
2604b126bd6bSKiran Patil 		if (num_nodes_added) {
2605b126bd6bSKiran Patil 			parent = ice_sched_find_node_by_teid(tc_node,
2606b126bd6bSKiran Patil 							     first_node_teid);
2607b126bd6bSKiran Patil 			/* register aggregator ID with the aggregator node */
2608b126bd6bSKiran Patil 			if (parent && i == aggl)
2609b126bd6bSKiran Patil 				parent->agg_id = agg_id;
2610b126bd6bSKiran Patil 		} else {
2611b126bd6bSKiran Patil 			parent = parent->children[0];
2612b126bd6bSKiran Patil 		}
2613b126bd6bSKiran Patil 	}
2614b126bd6bSKiran Patil 
2615b126bd6bSKiran Patil 	return 0;
2616b126bd6bSKiran Patil }
2617b126bd6bSKiran Patil 
2618b126bd6bSKiran Patil /**
2619b126bd6bSKiran Patil  * ice_sched_cfg_agg - configure aggregator node
2620b126bd6bSKiran Patil  * @pi: port information structure
2621b126bd6bSKiran Patil  * @agg_id: aggregator ID
2622b126bd6bSKiran Patil  * @agg_type: aggregator type queue, VSI, or aggregator group
2623b126bd6bSKiran Patil  * @tc_bitmap: bits TC bitmap
2624b126bd6bSKiran Patil  *
2625b126bd6bSKiran Patil  * It registers a unique aggregator node into scheduler services. It
2626b126bd6bSKiran Patil  * allows a user to register with a unique ID to track it's resources.
2627b126bd6bSKiran Patil  * The aggregator type determines if this is a queue group, VSI group
2628b126bd6bSKiran Patil  * or aggregator group. It then creates the aggregator node(s) for requested
2629b126bd6bSKiran Patil  * TC(s) or removes an existing aggregator node including its configuration
2630b126bd6bSKiran Patil  * if indicated via tc_bitmap. Call ice_rm_agg_cfg to release aggregator
2631b126bd6bSKiran Patil  * resources and remove aggregator ID.
2632b126bd6bSKiran Patil  * This function needs to be called with scheduler lock held.
2633b126bd6bSKiran Patil  */
26345e24d598STony Nguyen static int
ice_sched_cfg_agg(struct ice_port_info * pi,u32 agg_id,enum ice_agg_type agg_type,unsigned long * tc_bitmap)2635b126bd6bSKiran Patil ice_sched_cfg_agg(struct ice_port_info *pi, u32 agg_id,
2636b126bd6bSKiran Patil 		  enum ice_agg_type agg_type, unsigned long *tc_bitmap)
2637b126bd6bSKiran Patil {
2638b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2639b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
26405518ac2aSTony Nguyen 	int status = 0;
2641b126bd6bSKiran Patil 	u8 tc;
2642b126bd6bSKiran Patil 
2643b126bd6bSKiran Patil 	agg_info = ice_get_agg_info(hw, agg_id);
2644b126bd6bSKiran Patil 	if (!agg_info) {
2645b126bd6bSKiran Patil 		/* Create new entry for new aggregator ID */
2646b126bd6bSKiran Patil 		agg_info = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*agg_info),
2647b126bd6bSKiran Patil 					GFP_KERNEL);
2648b126bd6bSKiran Patil 		if (!agg_info)
2649d54699e2STony Nguyen 			return -ENOMEM;
2650b126bd6bSKiran Patil 
2651b126bd6bSKiran Patil 		agg_info->agg_id = agg_id;
2652b126bd6bSKiran Patil 		agg_info->agg_type = agg_type;
2653b126bd6bSKiran Patil 		agg_info->tc_bitmap[0] = 0;
2654b126bd6bSKiran Patil 
2655b126bd6bSKiran Patil 		/* Initialize the aggregator VSI list head */
2656b126bd6bSKiran Patil 		INIT_LIST_HEAD(&agg_info->agg_vsi_list);
2657b126bd6bSKiran Patil 
2658b126bd6bSKiran Patil 		/* Add new entry in aggregator list */
2659b126bd6bSKiran Patil 		list_add(&agg_info->list_entry, &hw->agg_list);
2660b126bd6bSKiran Patil 	}
2661b126bd6bSKiran Patil 	/* Create aggregator node(s) for requested TC(s) */
2662b126bd6bSKiran Patil 	ice_for_each_traffic_class(tc) {
2663b126bd6bSKiran Patil 		if (!ice_is_tc_ena(*tc_bitmap, tc)) {
2664b126bd6bSKiran Patil 			/* Delete aggregator cfg TC if it exists previously */
2665b126bd6bSKiran Patil 			status = ice_rm_agg_cfg_tc(pi, agg_info, tc, false);
2666b126bd6bSKiran Patil 			if (status)
2667b126bd6bSKiran Patil 				break;
2668b126bd6bSKiran Patil 			continue;
2669b126bd6bSKiran Patil 		}
2670b126bd6bSKiran Patil 
2671b126bd6bSKiran Patil 		/* Check if aggregator node for TC already exists */
2672b126bd6bSKiran Patil 		if (ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
2673b126bd6bSKiran Patil 			continue;
2674b126bd6bSKiran Patil 
2675b126bd6bSKiran Patil 		/* Create new aggregator node for TC */
2676b126bd6bSKiran Patil 		status = ice_sched_add_agg_cfg(pi, agg_id, tc);
2677b126bd6bSKiran Patil 		if (status)
2678b126bd6bSKiran Patil 			break;
2679b126bd6bSKiran Patil 
2680b126bd6bSKiran Patil 		/* Save aggregator node's TC information */
2681b126bd6bSKiran Patil 		set_bit(tc, agg_info->tc_bitmap);
2682b126bd6bSKiran Patil 	}
2683b126bd6bSKiran Patil 
2684b126bd6bSKiran Patil 	return status;
2685b126bd6bSKiran Patil }
2686b126bd6bSKiran Patil 
2687b126bd6bSKiran Patil /**
2688b126bd6bSKiran Patil  * ice_cfg_agg - config aggregator node
2689b126bd6bSKiran Patil  * @pi: port information structure
2690b126bd6bSKiran Patil  * @agg_id: aggregator ID
2691b126bd6bSKiran Patil  * @agg_type: aggregator type queue, VSI, or aggregator group
2692b126bd6bSKiran Patil  * @tc_bitmap: bits TC bitmap
2693b126bd6bSKiran Patil  *
2694b126bd6bSKiran Patil  * This function configures aggregator node(s).
2695b126bd6bSKiran Patil  */
26965e24d598STony Nguyen int
ice_cfg_agg(struct ice_port_info * pi,u32 agg_id,enum ice_agg_type agg_type,u8 tc_bitmap)2697b126bd6bSKiran Patil ice_cfg_agg(struct ice_port_info *pi, u32 agg_id, enum ice_agg_type agg_type,
2698b126bd6bSKiran Patil 	    u8 tc_bitmap)
2699b126bd6bSKiran Patil {
2700b126bd6bSKiran Patil 	unsigned long bitmap = tc_bitmap;
27015e24d598STony Nguyen 	int status;
2702b126bd6bSKiran Patil 
2703b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
2704e53a8083SDan Carpenter 	status = ice_sched_cfg_agg(pi, agg_id, agg_type, &bitmap);
2705b126bd6bSKiran Patil 	if (!status)
2706e53a8083SDan Carpenter 		status = ice_save_agg_tc_bitmap(pi, agg_id, &bitmap);
2707b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
2708b126bd6bSKiran Patil 	return status;
2709b126bd6bSKiran Patil }
2710b126bd6bSKiran Patil 
2711b126bd6bSKiran Patil /**
2712b126bd6bSKiran Patil  * ice_get_agg_vsi_info - get the aggregator ID
2713b126bd6bSKiran Patil  * @agg_info: aggregator info
2714b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2715b126bd6bSKiran Patil  *
2716b126bd6bSKiran Patil  * The function returns aggregator VSI info based on VSI handle. This function
2717b126bd6bSKiran Patil  * needs to be called with scheduler lock held.
2718b126bd6bSKiran Patil  */
2719b126bd6bSKiran Patil static struct ice_sched_agg_vsi_info *
ice_get_agg_vsi_info(struct ice_sched_agg_info * agg_info,u16 vsi_handle)2720b126bd6bSKiran Patil ice_get_agg_vsi_info(struct ice_sched_agg_info *agg_info, u16 vsi_handle)
2721b126bd6bSKiran Patil {
2722b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *agg_vsi_info;
2723b126bd6bSKiran Patil 
2724b126bd6bSKiran Patil 	list_for_each_entry(agg_vsi_info, &agg_info->agg_vsi_list, list_entry)
2725b126bd6bSKiran Patil 		if (agg_vsi_info->vsi_handle == vsi_handle)
2726b126bd6bSKiran Patil 			return agg_vsi_info;
2727b126bd6bSKiran Patil 
2728b126bd6bSKiran Patil 	return NULL;
2729b126bd6bSKiran Patil }
2730b126bd6bSKiran Patil 
2731b126bd6bSKiran Patil /**
2732b126bd6bSKiran Patil  * ice_get_vsi_agg_info - get the aggregator info of VSI
2733b126bd6bSKiran Patil  * @hw: pointer to the hardware structure
2734b126bd6bSKiran Patil  * @vsi_handle: Sw VSI handle
2735b126bd6bSKiran Patil  *
2736b126bd6bSKiran Patil  * The function returns aggregator info of VSI represented via vsi_handle. The
2737b126bd6bSKiran Patil  * VSI has in this case a different aggregator than the default one. This
2738b126bd6bSKiran Patil  * function needs to be called with scheduler lock held.
2739b126bd6bSKiran Patil  */
2740b126bd6bSKiran Patil static struct ice_sched_agg_info *
ice_get_vsi_agg_info(struct ice_hw * hw,u16 vsi_handle)2741b126bd6bSKiran Patil ice_get_vsi_agg_info(struct ice_hw *hw, u16 vsi_handle)
2742b126bd6bSKiran Patil {
2743b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2744b126bd6bSKiran Patil 
2745b126bd6bSKiran Patil 	list_for_each_entry(agg_info, &hw->agg_list, list_entry) {
2746b126bd6bSKiran Patil 		struct ice_sched_agg_vsi_info *agg_vsi_info;
2747b126bd6bSKiran Patil 
2748b126bd6bSKiran Patil 		agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
2749b126bd6bSKiran Patil 		if (agg_vsi_info)
2750b126bd6bSKiran Patil 			return agg_info;
2751b126bd6bSKiran Patil 	}
2752b126bd6bSKiran Patil 	return NULL;
2753b126bd6bSKiran Patil }
2754b126bd6bSKiran Patil 
2755b126bd6bSKiran Patil /**
2756b126bd6bSKiran Patil  * ice_save_agg_vsi_tc_bitmap - save aggregator VSI TC bitmap
2757b126bd6bSKiran Patil  * @pi: port information structure
2758b126bd6bSKiran Patil  * @agg_id: aggregator ID
2759b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2760b126bd6bSKiran Patil  * @tc_bitmap: TC bitmap of enabled TC(s)
2761b126bd6bSKiran Patil  *
2762b126bd6bSKiran Patil  * Save VSI to aggregator TC bitmap. This function needs to call with scheduler
2763b126bd6bSKiran Patil  * lock held.
2764b126bd6bSKiran Patil  */
27655e24d598STony Nguyen static int
ice_save_agg_vsi_tc_bitmap(struct ice_port_info * pi,u32 agg_id,u16 vsi_handle,unsigned long * tc_bitmap)2766b126bd6bSKiran Patil ice_save_agg_vsi_tc_bitmap(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle,
2767b126bd6bSKiran Patil 			   unsigned long *tc_bitmap)
2768b126bd6bSKiran Patil {
2769b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *agg_vsi_info;
2770b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
2771b126bd6bSKiran Patil 
2772b126bd6bSKiran Patil 	agg_info = ice_get_agg_info(pi->hw, agg_id);
2773b126bd6bSKiran Patil 	if (!agg_info)
2774d54699e2STony Nguyen 		return -EINVAL;
2775b126bd6bSKiran Patil 	/* check if entry already exist */
2776b126bd6bSKiran Patil 	agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
2777b126bd6bSKiran Patil 	if (!agg_vsi_info)
2778d54699e2STony Nguyen 		return -EINVAL;
2779b126bd6bSKiran Patil 	bitmap_copy(agg_vsi_info->replay_tc_bitmap, tc_bitmap,
2780b126bd6bSKiran Patil 		    ICE_MAX_TRAFFIC_CLASS);
2781b126bd6bSKiran Patil 	return 0;
2782b126bd6bSKiran Patil }
2783b126bd6bSKiran Patil 
2784b126bd6bSKiran Patil /**
2785b126bd6bSKiran Patil  * ice_sched_assoc_vsi_to_agg - associate/move VSI to new/default aggregator
2786b126bd6bSKiran Patil  * @pi: port information structure
2787b126bd6bSKiran Patil  * @agg_id: aggregator ID
2788b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2789b126bd6bSKiran Patil  * @tc_bitmap: TC bitmap of enabled TC(s)
2790b126bd6bSKiran Patil  *
2791b126bd6bSKiran Patil  * This function moves VSI to a new or default aggregator node. If VSI is
2792b126bd6bSKiran Patil  * already associated to the aggregator node then no operation is performed on
2793b126bd6bSKiran Patil  * the tree. This function needs to be called with scheduler lock held.
2794b126bd6bSKiran Patil  */
27955e24d598STony Nguyen static int
ice_sched_assoc_vsi_to_agg(struct ice_port_info * pi,u32 agg_id,u16 vsi_handle,unsigned long * tc_bitmap)2796b126bd6bSKiran Patil ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
2797b126bd6bSKiran Patil 			   u16 vsi_handle, unsigned long *tc_bitmap)
2798b126bd6bSKiran Patil {
2799e9a1cc2eSJakob Koschel 	struct ice_sched_agg_vsi_info *agg_vsi_info, *iter, *old_agg_vsi_info = NULL;
280037c59206SVictor Raj 	struct ice_sched_agg_info *agg_info, *old_agg_info;
2801b126bd6bSKiran Patil 	struct ice_hw *hw = pi->hw;
28025518ac2aSTony Nguyen 	int status = 0;
2803b126bd6bSKiran Patil 	u8 tc;
2804b126bd6bSKiran Patil 
2805b126bd6bSKiran Patil 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
2806d54699e2STony Nguyen 		return -EINVAL;
2807b126bd6bSKiran Patil 	agg_info = ice_get_agg_info(hw, agg_id);
2808b126bd6bSKiran Patil 	if (!agg_info)
2809d54699e2STony Nguyen 		return -EINVAL;
281037c59206SVictor Raj 	/* If the VSI is already part of another aggregator then update
281137c59206SVictor Raj 	 * its VSI info list
281237c59206SVictor Raj 	 */
281337c59206SVictor Raj 	old_agg_info = ice_get_vsi_agg_info(hw, vsi_handle);
281437c59206SVictor Raj 	if (old_agg_info && old_agg_info != agg_info) {
281537c59206SVictor Raj 		struct ice_sched_agg_vsi_info *vtmp;
281637c59206SVictor Raj 
2817e9a1cc2eSJakob Koschel 		list_for_each_entry_safe(iter, vtmp,
281837c59206SVictor Raj 					 &old_agg_info->agg_vsi_list,
281937c59206SVictor Raj 					 list_entry)
2820e9a1cc2eSJakob Koschel 			if (iter->vsi_handle == vsi_handle) {
2821e9a1cc2eSJakob Koschel 				old_agg_vsi_info = iter;
282237c59206SVictor Raj 				break;
282337c59206SVictor Raj 			}
2824e9a1cc2eSJakob Koschel 	}
282537c59206SVictor Raj 
2826b126bd6bSKiran Patil 	/* check if entry already exist */
2827b126bd6bSKiran Patil 	agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
2828b126bd6bSKiran Patil 	if (!agg_vsi_info) {
2829b126bd6bSKiran Patil 		/* Create new entry for VSI under aggregator list */
2830b126bd6bSKiran Patil 		agg_vsi_info = devm_kzalloc(ice_hw_to_dev(hw),
2831b126bd6bSKiran Patil 					    sizeof(*agg_vsi_info), GFP_KERNEL);
2832b126bd6bSKiran Patil 		if (!agg_vsi_info)
2833d54699e2STony Nguyen 			return -EINVAL;
2834b126bd6bSKiran Patil 
2835b126bd6bSKiran Patil 		/* add VSI ID into the aggregator list */
2836b126bd6bSKiran Patil 		agg_vsi_info->vsi_handle = vsi_handle;
2837b126bd6bSKiran Patil 		list_add(&agg_vsi_info->list_entry, &agg_info->agg_vsi_list);
2838b126bd6bSKiran Patil 	}
2839b126bd6bSKiran Patil 	/* Move VSI node to new aggregator node for requested TC(s) */
2840b126bd6bSKiran Patil 	ice_for_each_traffic_class(tc) {
2841b126bd6bSKiran Patil 		if (!ice_is_tc_ena(*tc_bitmap, tc))
2842b126bd6bSKiran Patil 			continue;
2843b126bd6bSKiran Patil 
2844b126bd6bSKiran Patil 		/* Move VSI to new aggregator */
2845b126bd6bSKiran Patil 		status = ice_sched_move_vsi_to_agg(pi, vsi_handle, agg_id, tc);
2846b126bd6bSKiran Patil 		if (status)
2847b126bd6bSKiran Patil 			break;
2848b126bd6bSKiran Patil 
2849b126bd6bSKiran Patil 		set_bit(tc, agg_vsi_info->tc_bitmap);
285037c59206SVictor Raj 		if (old_agg_vsi_info)
285137c59206SVictor Raj 			clear_bit(tc, old_agg_vsi_info->tc_bitmap);
285237c59206SVictor Raj 	}
285337c59206SVictor Raj 	if (old_agg_vsi_info && !old_agg_vsi_info->tc_bitmap[0]) {
285437c59206SVictor Raj 		list_del(&old_agg_vsi_info->list_entry);
285537c59206SVictor Raj 		devm_kfree(ice_hw_to_dev(pi->hw), old_agg_vsi_info);
2856b126bd6bSKiran Patil 	}
2857b126bd6bSKiran Patil 	return status;
2858b126bd6bSKiran Patil }
2859b126bd6bSKiran Patil 
2860b126bd6bSKiran Patil /**
28611ddef455SUsha Ketineni  * ice_sched_rm_unused_rl_prof - remove unused RL profile
28621ddef455SUsha Ketineni  * @pi: port information structure
28631ddef455SUsha Ketineni  *
28641ddef455SUsha Ketineni  * This function removes unused rate limit profiles from the HW and
28651ddef455SUsha Ketineni  * SW DB. The caller needs to hold scheduler lock.
28661ddef455SUsha Ketineni  */
ice_sched_rm_unused_rl_prof(struct ice_port_info * pi)28671ddef455SUsha Ketineni static void ice_sched_rm_unused_rl_prof(struct ice_port_info *pi)
28681ddef455SUsha Ketineni {
28691ddef455SUsha Ketineni 	u16 ln;
28701ddef455SUsha Ketineni 
28711ddef455SUsha Ketineni 	for (ln = 0; ln < pi->hw->num_tx_sched_layers; ln++) {
28721ddef455SUsha Ketineni 		struct ice_aqc_rl_profile_info *rl_prof_elem;
28731ddef455SUsha Ketineni 		struct ice_aqc_rl_profile_info *rl_prof_tmp;
28741ddef455SUsha Ketineni 
28751ddef455SUsha Ketineni 		list_for_each_entry_safe(rl_prof_elem, rl_prof_tmp,
28761ddef455SUsha Ketineni 					 &pi->rl_prof_list[ln], list_entry) {
28771ddef455SUsha Ketineni 			if (!ice_sched_del_rl_profile(pi->hw, rl_prof_elem))
28789228d8b2SJacob Keller 				ice_debug(pi->hw, ICE_DBG_SCHED, "Removed rl profile\n");
28791ddef455SUsha Ketineni 		}
28801ddef455SUsha Ketineni 	}
28811ddef455SUsha Ketineni }
28821ddef455SUsha Ketineni 
28831ddef455SUsha Ketineni /**
28841ddef455SUsha Ketineni  * ice_sched_update_elem - update element
28851ddef455SUsha Ketineni  * @hw: pointer to the HW struct
28861ddef455SUsha Ketineni  * @node: pointer to node
28871ddef455SUsha Ketineni  * @info: node info to update
28881ddef455SUsha Ketineni  *
2889b3c38904SBruce Allan  * Update the HW DB, and local SW DB of node. Update the scheduling
28901ddef455SUsha Ketineni  * parameters of node from argument info data buffer (Info->data buf) and
28911ddef455SUsha Ketineni  * returns success or error on config sched element failure. The caller
28921ddef455SUsha Ketineni  * needs to hold scheduler lock.
28931ddef455SUsha Ketineni  */
28945e24d598STony Nguyen static int
ice_sched_update_elem(struct ice_hw * hw,struct ice_sched_node * node,struct ice_aqc_txsched_elem_data * info)28951ddef455SUsha Ketineni ice_sched_update_elem(struct ice_hw *hw, struct ice_sched_node *node,
28961ddef455SUsha Ketineni 		      struct ice_aqc_txsched_elem_data *info)
28971ddef455SUsha Ketineni {
2898b3c38904SBruce Allan 	struct ice_aqc_txsched_elem_data buf;
28991ddef455SUsha Ketineni 	u16 elem_cfgd = 0;
29001ddef455SUsha Ketineni 	u16 num_elems = 1;
29015518ac2aSTony Nguyen 	int status;
29021ddef455SUsha Ketineni 
2903b3c38904SBruce Allan 	buf = *info;
29041ddef455SUsha Ketineni 	/* Parent TEID is reserved field in this aq call */
2905b3c38904SBruce Allan 	buf.parent_teid = 0;
29061ddef455SUsha Ketineni 	/* Element type is reserved field in this aq call */
2907b3c38904SBruce Allan 	buf.data.elem_type = 0;
29081ddef455SUsha Ketineni 	/* Flags is reserved field in this aq call */
2909b3c38904SBruce Allan 	buf.data.flags = 0;
29101ddef455SUsha Ketineni 
29111ddef455SUsha Ketineni 	/* Update HW DB */
29121ddef455SUsha Ketineni 	/* Configure element node */
29131ddef455SUsha Ketineni 	status = ice_aq_cfg_sched_elems(hw, num_elems, &buf, sizeof(buf),
29141ddef455SUsha Ketineni 					&elem_cfgd, NULL);
29151ddef455SUsha Ketineni 	if (status || elem_cfgd != num_elems) {
29161ddef455SUsha Ketineni 		ice_debug(hw, ICE_DBG_SCHED, "Config sched elem error\n");
2917d54699e2STony Nguyen 		return -EIO;
29181ddef455SUsha Ketineni 	}
29191ddef455SUsha Ketineni 
29201ddef455SUsha Ketineni 	/* Config success case */
29211ddef455SUsha Ketineni 	/* Now update local SW DB */
29221ddef455SUsha Ketineni 	/* Only copy the data portion of info buffer */
29231ddef455SUsha Ketineni 	node->info.data = info->data;
29241ddef455SUsha Ketineni 	return status;
29251ddef455SUsha Ketineni }
29261ddef455SUsha Ketineni 
29271ddef455SUsha Ketineni /**
29281ddef455SUsha Ketineni  * ice_sched_cfg_node_bw_alloc - configure node BW weight/alloc params
29291ddef455SUsha Ketineni  * @hw: pointer to the HW struct
29301ddef455SUsha Ketineni  * @node: sched node to configure
29311ddef455SUsha Ketineni  * @rl_type: rate limit type CIR, EIR, or shared
29321ddef455SUsha Ketineni  * @bw_alloc: BW weight/allocation
29331ddef455SUsha Ketineni  *
29341ddef455SUsha Ketineni  * This function configures node element's BW allocation.
29351ddef455SUsha Ketineni  */
29365e24d598STony Nguyen static int
ice_sched_cfg_node_bw_alloc(struct ice_hw * hw,struct ice_sched_node * node,enum ice_rl_type rl_type,u16 bw_alloc)29371ddef455SUsha Ketineni ice_sched_cfg_node_bw_alloc(struct ice_hw *hw, struct ice_sched_node *node,
293888865fc4SKarol Kolacinski 			    enum ice_rl_type rl_type, u16 bw_alloc)
29391ddef455SUsha Ketineni {
29401ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem_data buf;
29411ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem *data;
29421ddef455SUsha Ketineni 
29431ddef455SUsha Ketineni 	buf = node->info;
29441ddef455SUsha Ketineni 	data = &buf.data;
29451ddef455SUsha Ketineni 	if (rl_type == ICE_MIN_BW) {
29461ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_CIR;
29471ddef455SUsha Ketineni 		data->cir_bw.bw_alloc = cpu_to_le16(bw_alloc);
29481ddef455SUsha Ketineni 	} else if (rl_type == ICE_MAX_BW) {
29491ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
29501ddef455SUsha Ketineni 		data->eir_bw.bw_alloc = cpu_to_le16(bw_alloc);
29511ddef455SUsha Ketineni 	} else {
2952d54699e2STony Nguyen 		return -EINVAL;
29531ddef455SUsha Ketineni 	}
29541ddef455SUsha Ketineni 
29551ddef455SUsha Ketineni 	/* Configure element */
2956b126bd6bSKiran Patil 	return ice_sched_update_elem(hw, node, &buf);
2957b126bd6bSKiran Patil }
2958b126bd6bSKiran Patil 
2959b126bd6bSKiran Patil /**
2960b126bd6bSKiran Patil  * ice_move_vsi_to_agg - moves VSI to new or default aggregator
2961b126bd6bSKiran Patil  * @pi: port information structure
2962b126bd6bSKiran Patil  * @agg_id: aggregator ID
2963b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
2964b126bd6bSKiran Patil  * @tc_bitmap: TC bitmap of enabled TC(s)
2965b126bd6bSKiran Patil  *
2966b126bd6bSKiran Patil  * Move or associate VSI to a new or default aggregator node.
2967b126bd6bSKiran Patil  */
29685e24d598STony Nguyen int
ice_move_vsi_to_agg(struct ice_port_info * pi,u32 agg_id,u16 vsi_handle,u8 tc_bitmap)2969b126bd6bSKiran Patil ice_move_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle,
2970b126bd6bSKiran Patil 		    u8 tc_bitmap)
2971b126bd6bSKiran Patil {
2972b126bd6bSKiran Patil 	unsigned long bitmap = tc_bitmap;
29735e24d598STony Nguyen 	int status;
2974b126bd6bSKiran Patil 
2975b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
2976b126bd6bSKiran Patil 	status = ice_sched_assoc_vsi_to_agg(pi, agg_id, vsi_handle,
2977b126bd6bSKiran Patil 					    (unsigned long *)&bitmap);
2978b126bd6bSKiran Patil 	if (!status)
2979b126bd6bSKiran Patil 		status = ice_save_agg_vsi_tc_bitmap(pi, agg_id, vsi_handle,
2980b126bd6bSKiran Patil 						    (unsigned long *)&bitmap);
2981b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
29821ddef455SUsha Ketineni 	return status;
29831ddef455SUsha Ketineni }
29841ddef455SUsha Ketineni 
29851ddef455SUsha Ketineni /**
29861ddef455SUsha Ketineni  * ice_set_clear_cir_bw - set or clear CIR BW
29871ddef455SUsha Ketineni  * @bw_t_info: bandwidth type information structure
29881ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
29891ddef455SUsha Ketineni  *
29901ddef455SUsha Ketineni  * Save or clear CIR bandwidth (BW) in the passed param bw_t_info.
29911ddef455SUsha Ketineni  */
ice_set_clear_cir_bw(struct ice_bw_type_info * bw_t_info,u32 bw)2992ebb462dcSBruce Allan static void ice_set_clear_cir_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
29931ddef455SUsha Ketineni {
29941ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW) {
29951ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap);
29961ddef455SUsha Ketineni 		bw_t_info->cir_bw.bw = 0;
29971ddef455SUsha Ketineni 	} else {
29981ddef455SUsha Ketineni 		/* Save type of BW information */
29991ddef455SUsha Ketineni 		set_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap);
30001ddef455SUsha Ketineni 		bw_t_info->cir_bw.bw = bw;
30011ddef455SUsha Ketineni 	}
30021ddef455SUsha Ketineni }
30031ddef455SUsha Ketineni 
30041ddef455SUsha Ketineni /**
30051ddef455SUsha Ketineni  * ice_set_clear_eir_bw - set or clear EIR BW
30061ddef455SUsha Ketineni  * @bw_t_info: bandwidth type information structure
30071ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
30081ddef455SUsha Ketineni  *
30091ddef455SUsha Ketineni  * Save or clear EIR bandwidth (BW) in the passed param bw_t_info.
30101ddef455SUsha Ketineni  */
ice_set_clear_eir_bw(struct ice_bw_type_info * bw_t_info,u32 bw)3011ebb462dcSBruce Allan static void ice_set_clear_eir_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
30121ddef455SUsha Ketineni {
30131ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW) {
30141ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
30151ddef455SUsha Ketineni 		bw_t_info->eir_bw.bw = 0;
30161ddef455SUsha Ketineni 	} else {
30171ddef455SUsha Ketineni 		/* EIR BW and Shared BW profiles are mutually exclusive and
30181ddef455SUsha Ketineni 		 * hence only one of them may be set for any given element.
30191ddef455SUsha Ketineni 		 * First clear earlier saved shared BW information.
30201ddef455SUsha Ketineni 		 */
30211ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
30221ddef455SUsha Ketineni 		bw_t_info->shared_bw = 0;
30231ddef455SUsha Ketineni 		/* save EIR BW information */
30241ddef455SUsha Ketineni 		set_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
30251ddef455SUsha Ketineni 		bw_t_info->eir_bw.bw = bw;
30261ddef455SUsha Ketineni 	}
30271ddef455SUsha Ketineni }
30281ddef455SUsha Ketineni 
30291ddef455SUsha Ketineni /**
30301ddef455SUsha Ketineni  * ice_set_clear_shared_bw - set or clear shared BW
30311ddef455SUsha Ketineni  * @bw_t_info: bandwidth type information structure
30321ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
30331ddef455SUsha Ketineni  *
30341ddef455SUsha Ketineni  * Save or clear shared bandwidth (BW) in the passed param bw_t_info.
30351ddef455SUsha Ketineni  */
ice_set_clear_shared_bw(struct ice_bw_type_info * bw_t_info,u32 bw)3036ebb462dcSBruce Allan static void ice_set_clear_shared_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
30371ddef455SUsha Ketineni {
30381ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW) {
30391ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
30401ddef455SUsha Ketineni 		bw_t_info->shared_bw = 0;
30411ddef455SUsha Ketineni 	} else {
30421ddef455SUsha Ketineni 		/* EIR BW and Shared BW profiles are mutually exclusive and
30431ddef455SUsha Ketineni 		 * hence only one of them may be set for any given element.
30441ddef455SUsha Ketineni 		 * First clear earlier saved EIR BW information.
30451ddef455SUsha Ketineni 		 */
30461ddef455SUsha Ketineni 		clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
30471ddef455SUsha Ketineni 		bw_t_info->eir_bw.bw = 0;
30481ddef455SUsha Ketineni 		/* save shared BW information */
30491ddef455SUsha Ketineni 		set_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
30501ddef455SUsha Ketineni 		bw_t_info->shared_bw = bw;
30511ddef455SUsha Ketineni 	}
30521ddef455SUsha Ketineni }
30531ddef455SUsha Ketineni 
30541ddef455SUsha Ketineni /**
30550754d65bSKiran Patil  * ice_sched_save_vsi_bw - save VSI node's BW information
30560754d65bSKiran Patil  * @pi: port information structure
30570754d65bSKiran Patil  * @vsi_handle: sw VSI handle
30580754d65bSKiran Patil  * @tc: traffic class
30590754d65bSKiran Patil  * @rl_type: rate limit type min, max, or shared
30600754d65bSKiran Patil  * @bw: bandwidth in Kbps - Kilo bits per sec
30610754d65bSKiran Patil  *
30620754d65bSKiran Patil  * Save BW information of VSI type node for post replay use.
30630754d65bSKiran Patil  */
30640754d65bSKiran Patil static int
ice_sched_save_vsi_bw(struct ice_port_info * pi,u16 vsi_handle,u8 tc,enum ice_rl_type rl_type,u32 bw)30650754d65bSKiran Patil ice_sched_save_vsi_bw(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
30660754d65bSKiran Patil 		      enum ice_rl_type rl_type, u32 bw)
30670754d65bSKiran Patil {
30680754d65bSKiran Patil 	struct ice_vsi_ctx *vsi_ctx;
30690754d65bSKiran Patil 
30700754d65bSKiran Patil 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
30710754d65bSKiran Patil 		return -EINVAL;
30720754d65bSKiran Patil 	vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
30730754d65bSKiran Patil 	if (!vsi_ctx)
30740754d65bSKiran Patil 		return -EINVAL;
30750754d65bSKiran Patil 	switch (rl_type) {
30760754d65bSKiran Patil 	case ICE_MIN_BW:
30770754d65bSKiran Patil 		ice_set_clear_cir_bw(&vsi_ctx->sched.bw_t_info[tc], bw);
30780754d65bSKiran Patil 		break;
30790754d65bSKiran Patil 	case ICE_MAX_BW:
30800754d65bSKiran Patil 		ice_set_clear_eir_bw(&vsi_ctx->sched.bw_t_info[tc], bw);
30810754d65bSKiran Patil 		break;
30820754d65bSKiran Patil 	case ICE_SHARED_BW:
30830754d65bSKiran Patil 		ice_set_clear_shared_bw(&vsi_ctx->sched.bw_t_info[tc], bw);
30840754d65bSKiran Patil 		break;
30850754d65bSKiran Patil 	default:
30860754d65bSKiran Patil 		return -EINVAL;
30870754d65bSKiran Patil 	}
30880754d65bSKiran Patil 	return 0;
30890754d65bSKiran Patil }
30900754d65bSKiran Patil 
30910754d65bSKiran Patil /**
30921ddef455SUsha Ketineni  * ice_sched_calc_wakeup - calculate RL profile wakeup parameter
30934f8a1497SBen Shelton  * @hw: pointer to the HW struct
30941ddef455SUsha Ketineni  * @bw: bandwidth in Kbps
30951ddef455SUsha Ketineni  *
30961ddef455SUsha Ketineni  * This function calculates the wakeup parameter of RL profile.
30971ddef455SUsha Ketineni  */
ice_sched_calc_wakeup(struct ice_hw * hw,s32 bw)30984f8a1497SBen Shelton static u16 ice_sched_calc_wakeup(struct ice_hw *hw, s32 bw)
30991ddef455SUsha Ketineni {
31001ddef455SUsha Ketineni 	s64 bytes_per_sec, wakeup_int, wakeup_a, wakeup_b, wakeup_f;
31011ddef455SUsha Ketineni 	s32 wakeup_f_int;
31021ddef455SUsha Ketineni 	u16 wakeup = 0;
31031ddef455SUsha Ketineni 
31041ddef455SUsha Ketineni 	/* Get the wakeup integer value */
31051ddef455SUsha Ketineni 	bytes_per_sec = div64_long(((s64)bw * 1000), BITS_PER_BYTE);
31064f8a1497SBen Shelton 	wakeup_int = div64_long(hw->psm_clk_freq, bytes_per_sec);
31071ddef455SUsha Ketineni 	if (wakeup_int > 63) {
31081ddef455SUsha Ketineni 		wakeup = (u16)((1 << 15) | wakeup_int);
31091ddef455SUsha Ketineni 	} else {
31101ddef455SUsha Ketineni 		/* Calculate fraction value up to 4 decimals
31111ddef455SUsha Ketineni 		 * Convert Integer value to a constant multiplier
31121ddef455SUsha Ketineni 		 */
31131ddef455SUsha Ketineni 		wakeup_b = (s64)ICE_RL_PROF_MULTIPLIER * wakeup_int;
31141ddef455SUsha Ketineni 		wakeup_a = div64_long((s64)ICE_RL_PROF_MULTIPLIER *
31154f8a1497SBen Shelton 					   hw->psm_clk_freq, bytes_per_sec);
31161ddef455SUsha Ketineni 
31171ddef455SUsha Ketineni 		/* Get Fraction value */
31181ddef455SUsha Ketineni 		wakeup_f = wakeup_a - wakeup_b;
31191ddef455SUsha Ketineni 
31201ddef455SUsha Ketineni 		/* Round up the Fractional value via Ceil(Fractional value) */
31211ddef455SUsha Ketineni 		if (wakeup_f > div64_long(ICE_RL_PROF_MULTIPLIER, 2))
31221ddef455SUsha Ketineni 			wakeup_f += 1;
31231ddef455SUsha Ketineni 
31241ddef455SUsha Ketineni 		wakeup_f_int = (s32)div64_long(wakeup_f * ICE_RL_PROF_FRACTION,
31251ddef455SUsha Ketineni 					       ICE_RL_PROF_MULTIPLIER);
31261ddef455SUsha Ketineni 		wakeup |= (u16)(wakeup_int << 9);
31271ddef455SUsha Ketineni 		wakeup |= (u16)(0x1ff & wakeup_f_int);
31281ddef455SUsha Ketineni 	}
31291ddef455SUsha Ketineni 
31301ddef455SUsha Ketineni 	return wakeup;
31311ddef455SUsha Ketineni }
31321ddef455SUsha Ketineni 
31331ddef455SUsha Ketineni /**
31341ddef455SUsha Ketineni  * ice_sched_bw_to_rl_profile - convert BW to profile parameters
31354f8a1497SBen Shelton  * @hw: pointer to the HW struct
31361ddef455SUsha Ketineni  * @bw: bandwidth in Kbps
31371ddef455SUsha Ketineni  * @profile: profile parameters to return
31381ddef455SUsha Ketineni  *
31391ddef455SUsha Ketineni  * This function converts the BW to profile structure format.
31401ddef455SUsha Ketineni  */
31415e24d598STony Nguyen static int
ice_sched_bw_to_rl_profile(struct ice_hw * hw,u32 bw,struct ice_aqc_rl_profile_elem * profile)31424f8a1497SBen Shelton ice_sched_bw_to_rl_profile(struct ice_hw *hw, u32 bw,
31434f8a1497SBen Shelton 			   struct ice_aqc_rl_profile_elem *profile)
31441ddef455SUsha Ketineni {
31451ddef455SUsha Ketineni 	s64 bytes_per_sec, ts_rate, mv_tmp;
31465518ac2aSTony Nguyen 	int status = -EINVAL;
31471ddef455SUsha Ketineni 	bool found = false;
31481ddef455SUsha Ketineni 	s32 encode = 0;
31491ddef455SUsha Ketineni 	s64 mv = 0;
31501ddef455SUsha Ketineni 	s32 i;
31511ddef455SUsha Ketineni 
31521ddef455SUsha Ketineni 	/* Bw settings range is from 0.5Mb/sec to 100Gb/sec */
31531ddef455SUsha Ketineni 	if (bw < ICE_SCHED_MIN_BW || bw > ICE_SCHED_MAX_BW)
31541ddef455SUsha Ketineni 		return status;
31551ddef455SUsha Ketineni 
31561ddef455SUsha Ketineni 	/* Bytes per second from Kbps */
31571ddef455SUsha Ketineni 	bytes_per_sec = div64_long(((s64)bw * 1000), BITS_PER_BYTE);
31581ddef455SUsha Ketineni 
31591ddef455SUsha Ketineni 	/* encode is 6 bits but really useful are 5 bits */
31601ddef455SUsha Ketineni 	for (i = 0; i < 64; i++) {
31611ddef455SUsha Ketineni 		u64 pow_result = BIT_ULL(i);
31621ddef455SUsha Ketineni 
31634f8a1497SBen Shelton 		ts_rate = div64_long((s64)hw->psm_clk_freq,
31641ddef455SUsha Ketineni 				     pow_result * ICE_RL_PROF_TS_MULTIPLIER);
31651ddef455SUsha Ketineni 		if (ts_rate <= 0)
31661ddef455SUsha Ketineni 			continue;
31671ddef455SUsha Ketineni 
31681ddef455SUsha Ketineni 		/* Multiplier value */
31691ddef455SUsha Ketineni 		mv_tmp = div64_long(bytes_per_sec * ICE_RL_PROF_MULTIPLIER,
31701ddef455SUsha Ketineni 				    ts_rate);
31711ddef455SUsha Ketineni 
31721ddef455SUsha Ketineni 		/* Round to the nearest ICE_RL_PROF_MULTIPLIER */
31731ddef455SUsha Ketineni 		mv = round_up_64bit(mv_tmp, ICE_RL_PROF_MULTIPLIER);
31741ddef455SUsha Ketineni 
31751ddef455SUsha Ketineni 		/* First multiplier value greater than the given
31761ddef455SUsha Ketineni 		 * accuracy bytes
31771ddef455SUsha Ketineni 		 */
31781ddef455SUsha Ketineni 		if (mv > ICE_RL_PROF_ACCURACY_BYTES) {
31791ddef455SUsha Ketineni 			encode = i;
31801ddef455SUsha Ketineni 			found = true;
31811ddef455SUsha Ketineni 			break;
31821ddef455SUsha Ketineni 		}
31831ddef455SUsha Ketineni 	}
31841ddef455SUsha Ketineni 	if (found) {
31851ddef455SUsha Ketineni 		u16 wm;
31861ddef455SUsha Ketineni 
31874f8a1497SBen Shelton 		wm = ice_sched_calc_wakeup(hw, bw);
31881ddef455SUsha Ketineni 		profile->rl_multiply = cpu_to_le16(mv);
31891ddef455SUsha Ketineni 		profile->wake_up_calc = cpu_to_le16(wm);
31901ddef455SUsha Ketineni 		profile->rl_encode = cpu_to_le16(encode);
31911ddef455SUsha Ketineni 		status = 0;
31921ddef455SUsha Ketineni 	} else {
3193d54699e2STony Nguyen 		status = -ENOENT;
31941ddef455SUsha Ketineni 	}
31951ddef455SUsha Ketineni 
31961ddef455SUsha Ketineni 	return status;
31971ddef455SUsha Ketineni }
31981ddef455SUsha Ketineni 
31991ddef455SUsha Ketineni /**
32001ddef455SUsha Ketineni  * ice_sched_add_rl_profile - add RL profile
32011ddef455SUsha Ketineni  * @pi: port information structure
32021ddef455SUsha Ketineni  * @rl_type: type of rate limit BW - min, max, or shared
32031ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
32041ddef455SUsha Ketineni  * @layer_num: specifies in which layer to create profile
32051ddef455SUsha Ketineni  *
32061ddef455SUsha Ketineni  * This function first checks the existing list for corresponding BW
32071ddef455SUsha Ketineni  * parameter. If it exists, it returns the associated profile otherwise
32081ddef455SUsha Ketineni  * it creates a new rate limit profile for requested BW, and adds it to
32091ddef455SUsha Ketineni  * the HW DB and local list. It returns the new profile or null on error.
32101ddef455SUsha Ketineni  * The caller needs to hold the scheduler lock.
32111ddef455SUsha Ketineni  */
32121ddef455SUsha Ketineni static struct ice_aqc_rl_profile_info *
ice_sched_add_rl_profile(struct ice_port_info * pi,enum ice_rl_type rl_type,u32 bw,u8 layer_num)32131ddef455SUsha Ketineni ice_sched_add_rl_profile(struct ice_port_info *pi,
32141ddef455SUsha Ketineni 			 enum ice_rl_type rl_type, u32 bw, u8 layer_num)
32151ddef455SUsha Ketineni {
32161ddef455SUsha Ketineni 	struct ice_aqc_rl_profile_info *rl_prof_elem;
32171ddef455SUsha Ketineni 	u16 profiles_added = 0, num_profiles = 1;
3218b3c38904SBruce Allan 	struct ice_aqc_rl_profile_elem *buf;
32191ddef455SUsha Ketineni 	struct ice_hw *hw;
32201ddef455SUsha Ketineni 	u8 profile_type;
32215518ac2aSTony Nguyen 	int status;
32221ddef455SUsha Ketineni 
32231ddef455SUsha Ketineni 	if (layer_num >= ICE_AQC_TOPO_MAX_LEVEL_NUM)
32241ddef455SUsha Ketineni 		return NULL;
32251ddef455SUsha Ketineni 	switch (rl_type) {
32261ddef455SUsha Ketineni 	case ICE_MIN_BW:
32271ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR;
32281ddef455SUsha Ketineni 		break;
32291ddef455SUsha Ketineni 	case ICE_MAX_BW:
32301ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR;
32311ddef455SUsha Ketineni 		break;
32321ddef455SUsha Ketineni 	case ICE_SHARED_BW:
32331ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL;
32341ddef455SUsha Ketineni 		break;
32351ddef455SUsha Ketineni 	default:
32361ddef455SUsha Ketineni 		return NULL;
32371ddef455SUsha Ketineni 	}
32381ddef455SUsha Ketineni 
32391ddef455SUsha Ketineni 	if (!pi)
32401ddef455SUsha Ketineni 		return NULL;
32411ddef455SUsha Ketineni 	hw = pi->hw;
32421ddef455SUsha Ketineni 	list_for_each_entry(rl_prof_elem, &pi->rl_prof_list[layer_num],
32431ddef455SUsha Ketineni 			    list_entry)
3244b3b93d6cSTarun Singh 		if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) ==
3245b3b93d6cSTarun Singh 		    profile_type && rl_prof_elem->bw == bw)
32461ddef455SUsha Ketineni 			/* Return existing profile ID info */
32471ddef455SUsha Ketineni 			return rl_prof_elem;
32481ddef455SUsha Ketineni 
32491ddef455SUsha Ketineni 	/* Create new profile ID */
32501ddef455SUsha Ketineni 	rl_prof_elem = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rl_prof_elem),
32511ddef455SUsha Ketineni 				    GFP_KERNEL);
32521ddef455SUsha Ketineni 
32531ddef455SUsha Ketineni 	if (!rl_prof_elem)
32541ddef455SUsha Ketineni 		return NULL;
32551ddef455SUsha Ketineni 
32564f8a1497SBen Shelton 	status = ice_sched_bw_to_rl_profile(hw, bw, &rl_prof_elem->profile);
32571ddef455SUsha Ketineni 	if (status)
32581ddef455SUsha Ketineni 		goto exit_add_rl_prof;
32591ddef455SUsha Ketineni 
32601ddef455SUsha Ketineni 	rl_prof_elem->bw = bw;
32611ddef455SUsha Ketineni 	/* layer_num is zero relative, and fw expects level from 1 to 9 */
32621ddef455SUsha Ketineni 	rl_prof_elem->profile.level = layer_num + 1;
32631ddef455SUsha Ketineni 	rl_prof_elem->profile.flags = profile_type;
32641ddef455SUsha Ketineni 	rl_prof_elem->profile.max_burst_size = cpu_to_le16(hw->max_burst_size);
32651ddef455SUsha Ketineni 
32661ddef455SUsha Ketineni 	/* Create new entry in HW DB */
3267b3c38904SBruce Allan 	buf = &rl_prof_elem->profile;
32681ddef455SUsha Ketineni 	status = ice_aq_add_rl_profile(hw, num_profiles, buf, sizeof(*buf),
32691ddef455SUsha Ketineni 				       &profiles_added, NULL);
32701ddef455SUsha Ketineni 	if (status || profiles_added != num_profiles)
32711ddef455SUsha Ketineni 		goto exit_add_rl_prof;
32721ddef455SUsha Ketineni 
32731ddef455SUsha Ketineni 	/* Good entry - add in the list */
32741ddef455SUsha Ketineni 	rl_prof_elem->prof_id_ref = 0;
32751ddef455SUsha Ketineni 	list_add(&rl_prof_elem->list_entry, &pi->rl_prof_list[layer_num]);
32761ddef455SUsha Ketineni 	return rl_prof_elem;
32771ddef455SUsha Ketineni 
32781ddef455SUsha Ketineni exit_add_rl_prof:
32791ddef455SUsha Ketineni 	devm_kfree(ice_hw_to_dev(hw), rl_prof_elem);
32801ddef455SUsha Ketineni 	return NULL;
32811ddef455SUsha Ketineni }
32821ddef455SUsha Ketineni 
32831ddef455SUsha Ketineni /**
32841ddef455SUsha Ketineni  * ice_sched_cfg_node_bw_lmt - configure node sched params
32851ddef455SUsha Ketineni  * @hw: pointer to the HW struct
32861ddef455SUsha Ketineni  * @node: sched node to configure
32871ddef455SUsha Ketineni  * @rl_type: rate limit type CIR, EIR, or shared
32881ddef455SUsha Ketineni  * @rl_prof_id: rate limit profile ID
32891ddef455SUsha Ketineni  *
32901ddef455SUsha Ketineni  * This function configures node element's BW limit.
32911ddef455SUsha Ketineni  */
32925e24d598STony Nguyen static int
ice_sched_cfg_node_bw_lmt(struct ice_hw * hw,struct ice_sched_node * node,enum ice_rl_type rl_type,u16 rl_prof_id)32931ddef455SUsha Ketineni ice_sched_cfg_node_bw_lmt(struct ice_hw *hw, struct ice_sched_node *node,
32941ddef455SUsha Ketineni 			  enum ice_rl_type rl_type, u16 rl_prof_id)
32951ddef455SUsha Ketineni {
32961ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem_data buf;
32971ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem *data;
32981ddef455SUsha Ketineni 
32991ddef455SUsha Ketineni 	buf = node->info;
33001ddef455SUsha Ketineni 	data = &buf.data;
33011ddef455SUsha Ketineni 	switch (rl_type) {
33021ddef455SUsha Ketineni 	case ICE_MIN_BW:
33031ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_CIR;
33041ddef455SUsha Ketineni 		data->cir_bw.bw_profile_idx = cpu_to_le16(rl_prof_id);
33051ddef455SUsha Ketineni 		break;
33061ddef455SUsha Ketineni 	case ICE_MAX_BW:
33071ddef455SUsha Ketineni 		/* EIR BW and Shared BW profiles are mutually exclusive and
33081ddef455SUsha Ketineni 		 * hence only one of them may be set for any given element
33091ddef455SUsha Ketineni 		 */
33101ddef455SUsha Ketineni 		if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED)
3311d54699e2STony Nguyen 			return -EIO;
33121ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
33131ddef455SUsha Ketineni 		data->eir_bw.bw_profile_idx = cpu_to_le16(rl_prof_id);
33141ddef455SUsha Ketineni 		break;
33151ddef455SUsha Ketineni 	case ICE_SHARED_BW:
33161ddef455SUsha Ketineni 		/* Check for removing shared BW */
33171ddef455SUsha Ketineni 		if (rl_prof_id == ICE_SCHED_NO_SHARED_RL_PROF_ID) {
33181ddef455SUsha Ketineni 			/* remove shared profile */
33191ddef455SUsha Ketineni 			data->valid_sections &= ~ICE_AQC_ELEM_VALID_SHARED;
33201ddef455SUsha Ketineni 			data->srl_id = 0; /* clear SRL field */
33211ddef455SUsha Ketineni 
33221ddef455SUsha Ketineni 			/* enable back EIR to default profile */
33231ddef455SUsha Ketineni 			data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
33241ddef455SUsha Ketineni 			data->eir_bw.bw_profile_idx =
33251ddef455SUsha Ketineni 				cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID);
33261ddef455SUsha Ketineni 			break;
33271ddef455SUsha Ketineni 		}
33281ddef455SUsha Ketineni 		/* EIR BW and Shared BW profiles are mutually exclusive and
33291ddef455SUsha Ketineni 		 * hence only one of them may be set for any given element
33301ddef455SUsha Ketineni 		 */
33311ddef455SUsha Ketineni 		if ((data->valid_sections & ICE_AQC_ELEM_VALID_EIR) &&
33321ddef455SUsha Ketineni 		    (le16_to_cpu(data->eir_bw.bw_profile_idx) !=
33331ddef455SUsha Ketineni 			    ICE_SCHED_DFLT_RL_PROF_ID))
3334d54699e2STony Nguyen 			return -EIO;
33351ddef455SUsha Ketineni 		/* EIR BW is set to default, disable it */
33361ddef455SUsha Ketineni 		data->valid_sections &= ~ICE_AQC_ELEM_VALID_EIR;
33371ddef455SUsha Ketineni 		/* Okay to enable shared BW now */
33381ddef455SUsha Ketineni 		data->valid_sections |= ICE_AQC_ELEM_VALID_SHARED;
33391ddef455SUsha Ketineni 		data->srl_id = cpu_to_le16(rl_prof_id);
33401ddef455SUsha Ketineni 		break;
33411ddef455SUsha Ketineni 	default:
33421ddef455SUsha Ketineni 		/* Unknown rate limit type */
3343d54699e2STony Nguyen 		return -EINVAL;
33441ddef455SUsha Ketineni 	}
33451ddef455SUsha Ketineni 
33461ddef455SUsha Ketineni 	/* Configure element */
33471ddef455SUsha Ketineni 	return ice_sched_update_elem(hw, node, &buf);
33481ddef455SUsha Ketineni }
33491ddef455SUsha Ketineni 
33501ddef455SUsha Ketineni /**
33511ddef455SUsha Ketineni  * ice_sched_get_node_rl_prof_id - get node's rate limit profile ID
33521ddef455SUsha Ketineni  * @node: sched node
33531ddef455SUsha Ketineni  * @rl_type: rate limit type
33541ddef455SUsha Ketineni  *
33551ddef455SUsha Ketineni  * If existing profile matches, it returns the corresponding rate
33561ddef455SUsha Ketineni  * limit profile ID, otherwise it returns an invalid ID as error.
33571ddef455SUsha Ketineni  */
33581ddef455SUsha Ketineni static u16
ice_sched_get_node_rl_prof_id(struct ice_sched_node * node,enum ice_rl_type rl_type)33591ddef455SUsha Ketineni ice_sched_get_node_rl_prof_id(struct ice_sched_node *node,
33601ddef455SUsha Ketineni 			      enum ice_rl_type rl_type)
33611ddef455SUsha Ketineni {
33621ddef455SUsha Ketineni 	u16 rl_prof_id = ICE_SCHED_INVAL_PROF_ID;
33631ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem *data;
33641ddef455SUsha Ketineni 
33651ddef455SUsha Ketineni 	data = &node->info.data;
33661ddef455SUsha Ketineni 	switch (rl_type) {
33671ddef455SUsha Ketineni 	case ICE_MIN_BW:
33681ddef455SUsha Ketineni 		if (data->valid_sections & ICE_AQC_ELEM_VALID_CIR)
33691ddef455SUsha Ketineni 			rl_prof_id = le16_to_cpu(data->cir_bw.bw_profile_idx);
33701ddef455SUsha Ketineni 		break;
33711ddef455SUsha Ketineni 	case ICE_MAX_BW:
33721ddef455SUsha Ketineni 		if (data->valid_sections & ICE_AQC_ELEM_VALID_EIR)
33731ddef455SUsha Ketineni 			rl_prof_id = le16_to_cpu(data->eir_bw.bw_profile_idx);
33741ddef455SUsha Ketineni 		break;
33751ddef455SUsha Ketineni 	case ICE_SHARED_BW:
33761ddef455SUsha Ketineni 		if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED)
33771ddef455SUsha Ketineni 			rl_prof_id = le16_to_cpu(data->srl_id);
33781ddef455SUsha Ketineni 		break;
33791ddef455SUsha Ketineni 	default:
33801ddef455SUsha Ketineni 		break;
33811ddef455SUsha Ketineni 	}
33821ddef455SUsha Ketineni 
33831ddef455SUsha Ketineni 	return rl_prof_id;
33841ddef455SUsha Ketineni }
33851ddef455SUsha Ketineni 
33861ddef455SUsha Ketineni /**
33871ddef455SUsha Ketineni  * ice_sched_get_rl_prof_layer - selects rate limit profile creation layer
33881ddef455SUsha Ketineni  * @pi: port information structure
33891ddef455SUsha Ketineni  * @rl_type: type of rate limit BW - min, max, or shared
33901ddef455SUsha Ketineni  * @layer_index: layer index
33911ddef455SUsha Ketineni  *
33921ddef455SUsha Ketineni  * This function returns requested profile creation layer.
33931ddef455SUsha Ketineni  */
33941ddef455SUsha Ketineni static u8
ice_sched_get_rl_prof_layer(struct ice_port_info * pi,enum ice_rl_type rl_type,u8 layer_index)33951ddef455SUsha Ketineni ice_sched_get_rl_prof_layer(struct ice_port_info *pi, enum ice_rl_type rl_type,
33961ddef455SUsha Ketineni 			    u8 layer_index)
33971ddef455SUsha Ketineni {
33981ddef455SUsha Ketineni 	struct ice_hw *hw = pi->hw;
33991ddef455SUsha Ketineni 
34001ddef455SUsha Ketineni 	if (layer_index >= hw->num_tx_sched_layers)
34011ddef455SUsha Ketineni 		return ICE_SCHED_INVAL_LAYER_NUM;
34021ddef455SUsha Ketineni 	switch (rl_type) {
34031ddef455SUsha Ketineni 	case ICE_MIN_BW:
34041ddef455SUsha Ketineni 		if (hw->layer_info[layer_index].max_cir_rl_profiles)
34051ddef455SUsha Ketineni 			return layer_index;
34061ddef455SUsha Ketineni 		break;
34071ddef455SUsha Ketineni 	case ICE_MAX_BW:
34081ddef455SUsha Ketineni 		if (hw->layer_info[layer_index].max_eir_rl_profiles)
34091ddef455SUsha Ketineni 			return layer_index;
34101ddef455SUsha Ketineni 		break;
34111ddef455SUsha Ketineni 	case ICE_SHARED_BW:
34121ddef455SUsha Ketineni 		/* if current layer doesn't support SRL profile creation
34131ddef455SUsha Ketineni 		 * then try a layer up or down.
34141ddef455SUsha Ketineni 		 */
34151ddef455SUsha Ketineni 		if (hw->layer_info[layer_index].max_srl_profiles)
34161ddef455SUsha Ketineni 			return layer_index;
34171ddef455SUsha Ketineni 		else if (layer_index < hw->num_tx_sched_layers - 1 &&
34181ddef455SUsha Ketineni 			 hw->layer_info[layer_index + 1].max_srl_profiles)
34191ddef455SUsha Ketineni 			return layer_index + 1;
34201ddef455SUsha Ketineni 		else if (layer_index > 0 &&
34211ddef455SUsha Ketineni 			 hw->layer_info[layer_index - 1].max_srl_profiles)
34221ddef455SUsha Ketineni 			return layer_index - 1;
34231ddef455SUsha Ketineni 		break;
34241ddef455SUsha Ketineni 	default:
34251ddef455SUsha Ketineni 		break;
34261ddef455SUsha Ketineni 	}
34271ddef455SUsha Ketineni 	return ICE_SCHED_INVAL_LAYER_NUM;
34281ddef455SUsha Ketineni }
34291ddef455SUsha Ketineni 
34301ddef455SUsha Ketineni /**
34311ddef455SUsha Ketineni  * ice_sched_get_srl_node - get shared rate limit node
34321ddef455SUsha Ketineni  * @node: tree node
34331ddef455SUsha Ketineni  * @srl_layer: shared rate limit layer
34341ddef455SUsha Ketineni  *
34351ddef455SUsha Ketineni  * This function returns SRL node to be used for shared rate limit purpose.
34361ddef455SUsha Ketineni  * The caller needs to hold scheduler lock.
34371ddef455SUsha Ketineni  */
34381ddef455SUsha Ketineni static struct ice_sched_node *
ice_sched_get_srl_node(struct ice_sched_node * node,u8 srl_layer)34391ddef455SUsha Ketineni ice_sched_get_srl_node(struct ice_sched_node *node, u8 srl_layer)
34401ddef455SUsha Ketineni {
34411ddef455SUsha Ketineni 	if (srl_layer > node->tx_sched_layer)
34421ddef455SUsha Ketineni 		return node->children[0];
34431ddef455SUsha Ketineni 	else if (srl_layer < node->tx_sched_layer)
34441ddef455SUsha Ketineni 		/* Node can't be created without a parent. It will always
34451ddef455SUsha Ketineni 		 * have a valid parent except root node.
34461ddef455SUsha Ketineni 		 */
34471ddef455SUsha Ketineni 		return node->parent;
34481ddef455SUsha Ketineni 	else
34491ddef455SUsha Ketineni 		return node;
34501ddef455SUsha Ketineni }
34511ddef455SUsha Ketineni 
34521ddef455SUsha Ketineni /**
34531ddef455SUsha Ketineni  * ice_sched_rm_rl_profile - remove RL profile ID
34541ddef455SUsha Ketineni  * @pi: port information structure
34551ddef455SUsha Ketineni  * @layer_num: layer number where profiles are saved
34561ddef455SUsha Ketineni  * @profile_type: profile type like EIR, CIR, or SRL
34571ddef455SUsha Ketineni  * @profile_id: profile ID to remove
34581ddef455SUsha Ketineni  *
34591ddef455SUsha Ketineni  * This function removes rate limit profile from layer 'layer_num' of type
34601ddef455SUsha Ketineni  * 'profile_type' and profile ID as 'profile_id'. The caller needs to hold
34611ddef455SUsha Ketineni  * scheduler lock.
34621ddef455SUsha Ketineni  */
34635e24d598STony Nguyen static int
ice_sched_rm_rl_profile(struct ice_port_info * pi,u8 layer_num,u8 profile_type,u16 profile_id)34641ddef455SUsha Ketineni ice_sched_rm_rl_profile(struct ice_port_info *pi, u8 layer_num, u8 profile_type,
34651ddef455SUsha Ketineni 			u16 profile_id)
34661ddef455SUsha Ketineni {
34671ddef455SUsha Ketineni 	struct ice_aqc_rl_profile_info *rl_prof_elem;
34685e24d598STony Nguyen 	int status = 0;
34691ddef455SUsha Ketineni 
34701ddef455SUsha Ketineni 	if (layer_num >= ICE_AQC_TOPO_MAX_LEVEL_NUM)
3471d54699e2STony Nguyen 		return -EINVAL;
34721ddef455SUsha Ketineni 	/* Check the existing list for RL profile */
34731ddef455SUsha Ketineni 	list_for_each_entry(rl_prof_elem, &pi->rl_prof_list[layer_num],
34741ddef455SUsha Ketineni 			    list_entry)
3475b3b93d6cSTarun Singh 		if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) ==
3476b3b93d6cSTarun Singh 		    profile_type &&
34771ddef455SUsha Ketineni 		    le16_to_cpu(rl_prof_elem->profile.profile_id) ==
34781ddef455SUsha Ketineni 		    profile_id) {
34791ddef455SUsha Ketineni 			if (rl_prof_elem->prof_id_ref)
34801ddef455SUsha Ketineni 				rl_prof_elem->prof_id_ref--;
34811ddef455SUsha Ketineni 
34821ddef455SUsha Ketineni 			/* Remove old profile ID from database */
34831ddef455SUsha Ketineni 			status = ice_sched_del_rl_profile(pi->hw, rl_prof_elem);
3484d54699e2STony Nguyen 			if (status && status != -EBUSY)
34859228d8b2SJacob Keller 				ice_debug(pi->hw, ICE_DBG_SCHED, "Remove rl profile failed\n");
34861ddef455SUsha Ketineni 			break;
34871ddef455SUsha Ketineni 		}
3488d54699e2STony Nguyen 	if (status == -EBUSY)
34891ddef455SUsha Ketineni 		status = 0;
34901ddef455SUsha Ketineni 	return status;
34911ddef455SUsha Ketineni }
34921ddef455SUsha Ketineni 
34931ddef455SUsha Ketineni /**
34941ddef455SUsha Ketineni  * ice_sched_set_node_bw_dflt - set node's bandwidth limit to default
34951ddef455SUsha Ketineni  * @pi: port information structure
34961ddef455SUsha Ketineni  * @node: pointer to node structure
34971ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
34981ddef455SUsha Ketineni  * @layer_num: layer number where RL profiles are saved
34991ddef455SUsha Ketineni  *
35001ddef455SUsha Ketineni  * This function configures node element's BW rate limit profile ID of
35011ddef455SUsha Ketineni  * type CIR, EIR, or SRL to default. This function needs to be called
35021ddef455SUsha Ketineni  * with the scheduler lock held.
35031ddef455SUsha Ketineni  */
35045e24d598STony Nguyen static int
ice_sched_set_node_bw_dflt(struct ice_port_info * pi,struct ice_sched_node * node,enum ice_rl_type rl_type,u8 layer_num)35051ddef455SUsha Ketineni ice_sched_set_node_bw_dflt(struct ice_port_info *pi,
35061ddef455SUsha Ketineni 			   struct ice_sched_node *node,
35071ddef455SUsha Ketineni 			   enum ice_rl_type rl_type, u8 layer_num)
35081ddef455SUsha Ketineni {
35091ddef455SUsha Ketineni 	struct ice_hw *hw;
35101ddef455SUsha Ketineni 	u8 profile_type;
35111ddef455SUsha Ketineni 	u16 rl_prof_id;
35121ddef455SUsha Ketineni 	u16 old_id;
35135518ac2aSTony Nguyen 	int status;
35141ddef455SUsha Ketineni 
35151ddef455SUsha Ketineni 	hw = pi->hw;
35161ddef455SUsha Ketineni 	switch (rl_type) {
35171ddef455SUsha Ketineni 	case ICE_MIN_BW:
35181ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR;
35191ddef455SUsha Ketineni 		rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID;
35201ddef455SUsha Ketineni 		break;
35211ddef455SUsha Ketineni 	case ICE_MAX_BW:
35221ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR;
35231ddef455SUsha Ketineni 		rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID;
35241ddef455SUsha Ketineni 		break;
35251ddef455SUsha Ketineni 	case ICE_SHARED_BW:
35261ddef455SUsha Ketineni 		profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL;
35271ddef455SUsha Ketineni 		/* No SRL is configured for default case */
35281ddef455SUsha Ketineni 		rl_prof_id = ICE_SCHED_NO_SHARED_RL_PROF_ID;
35291ddef455SUsha Ketineni 		break;
35301ddef455SUsha Ketineni 	default:
3531d54699e2STony Nguyen 		return -EINVAL;
35321ddef455SUsha Ketineni 	}
35331ddef455SUsha Ketineni 	/* Save existing RL prof ID for later clean up */
35341ddef455SUsha Ketineni 	old_id = ice_sched_get_node_rl_prof_id(node, rl_type);
35351ddef455SUsha Ketineni 	/* Configure BW scheduling parameters */
35361ddef455SUsha Ketineni 	status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id);
35371ddef455SUsha Ketineni 	if (status)
35381ddef455SUsha Ketineni 		return status;
35391ddef455SUsha Ketineni 
35401ddef455SUsha Ketineni 	/* Remove stale RL profile ID */
35411ddef455SUsha Ketineni 	if (old_id == ICE_SCHED_DFLT_RL_PROF_ID ||
35421ddef455SUsha Ketineni 	    old_id == ICE_SCHED_INVAL_PROF_ID)
35431ddef455SUsha Ketineni 		return 0;
35441ddef455SUsha Ketineni 
35451ddef455SUsha Ketineni 	return ice_sched_rm_rl_profile(pi, layer_num, profile_type, old_id);
35461ddef455SUsha Ketineni }
35471ddef455SUsha Ketineni 
35481ddef455SUsha Ketineni /**
35491ddef455SUsha Ketineni  * ice_sched_set_eir_srl_excl - set EIR/SRL exclusiveness
35501ddef455SUsha Ketineni  * @pi: port information structure
35511ddef455SUsha Ketineni  * @node: pointer to node structure
35521ddef455SUsha Ketineni  * @layer_num: layer number where rate limit profiles are saved
35531ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
35541ddef455SUsha Ketineni  * @bw: bandwidth value
35551ddef455SUsha Ketineni  *
35561ddef455SUsha Ketineni  * This function prepares node element's bandwidth to SRL or EIR exclusively.
35571ddef455SUsha Ketineni  * EIR BW and Shared BW profiles are mutually exclusive and hence only one of
35581ddef455SUsha Ketineni  * them may be set for any given element. This function needs to be called
35591ddef455SUsha Ketineni  * with the scheduler lock held.
35601ddef455SUsha Ketineni  */
35615e24d598STony Nguyen static int
ice_sched_set_eir_srl_excl(struct ice_port_info * pi,struct ice_sched_node * node,u8 layer_num,enum ice_rl_type rl_type,u32 bw)35621ddef455SUsha Ketineni ice_sched_set_eir_srl_excl(struct ice_port_info *pi,
35631ddef455SUsha Ketineni 			   struct ice_sched_node *node,
35641ddef455SUsha Ketineni 			   u8 layer_num, enum ice_rl_type rl_type, u32 bw)
35651ddef455SUsha Ketineni {
35661ddef455SUsha Ketineni 	if (rl_type == ICE_SHARED_BW) {
35671ddef455SUsha Ketineni 		/* SRL node passed in this case, it may be different node */
35681ddef455SUsha Ketineni 		if (bw == ICE_SCHED_DFLT_BW)
35691ddef455SUsha Ketineni 			/* SRL being removed, ice_sched_cfg_node_bw_lmt()
35701ddef455SUsha Ketineni 			 * enables EIR to default. EIR is not set in this
35711ddef455SUsha Ketineni 			 * case, so no additional action is required.
35721ddef455SUsha Ketineni 			 */
35731ddef455SUsha Ketineni 			return 0;
35741ddef455SUsha Ketineni 
35751ddef455SUsha Ketineni 		/* SRL being configured, set EIR to default here.
35761ddef455SUsha Ketineni 		 * ice_sched_cfg_node_bw_lmt() disables EIR when it
35771ddef455SUsha Ketineni 		 * configures SRL
35781ddef455SUsha Ketineni 		 */
35791ddef455SUsha Ketineni 		return ice_sched_set_node_bw_dflt(pi, node, ICE_MAX_BW,
35801ddef455SUsha Ketineni 						  layer_num);
35811ddef455SUsha Ketineni 	} else if (rl_type == ICE_MAX_BW &&
35821ddef455SUsha Ketineni 		   node->info.data.valid_sections & ICE_AQC_ELEM_VALID_SHARED) {
35831ddef455SUsha Ketineni 		/* Remove Shared profile. Set default shared BW call
35841ddef455SUsha Ketineni 		 * removes shared profile for a node.
35851ddef455SUsha Ketineni 		 */
35861ddef455SUsha Ketineni 		return ice_sched_set_node_bw_dflt(pi, node,
35871ddef455SUsha Ketineni 						  ICE_SHARED_BW,
35881ddef455SUsha Ketineni 						  layer_num);
35891ddef455SUsha Ketineni 	}
35901ddef455SUsha Ketineni 	return 0;
35911ddef455SUsha Ketineni }
35921ddef455SUsha Ketineni 
35931ddef455SUsha Ketineni /**
35941ddef455SUsha Ketineni  * ice_sched_set_node_bw - set node's bandwidth
35951ddef455SUsha Ketineni  * @pi: port information structure
35961ddef455SUsha Ketineni  * @node: tree node
35971ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
35981ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
35991ddef455SUsha Ketineni  * @layer_num: layer number
36001ddef455SUsha Ketineni  *
36011ddef455SUsha Ketineni  * This function adds new profile corresponding to requested BW, configures
36021ddef455SUsha Ketineni  * node's RL profile ID of type CIR, EIR, or SRL, and removes old profile
36031ddef455SUsha Ketineni  * ID from local database. The caller needs to hold scheduler lock.
36041ddef455SUsha Ketineni  */
360516dfa494SMichal Wilczynski int
ice_sched_set_node_bw(struct ice_port_info * pi,struct ice_sched_node * node,enum ice_rl_type rl_type,u32 bw,u8 layer_num)36061ddef455SUsha Ketineni ice_sched_set_node_bw(struct ice_port_info *pi, struct ice_sched_node *node,
36071ddef455SUsha Ketineni 		      enum ice_rl_type rl_type, u32 bw, u8 layer_num)
36081ddef455SUsha Ketineni {
36091ddef455SUsha Ketineni 	struct ice_aqc_rl_profile_info *rl_prof_info;
36101ddef455SUsha Ketineni 	struct ice_hw *hw = pi->hw;
36111ddef455SUsha Ketineni 	u16 old_id, rl_prof_id;
36125518ac2aSTony Nguyen 	int status = -EINVAL;
36131ddef455SUsha Ketineni 
36141ddef455SUsha Ketineni 	rl_prof_info = ice_sched_add_rl_profile(pi, rl_type, bw, layer_num);
36151ddef455SUsha Ketineni 	if (!rl_prof_info)
36161ddef455SUsha Ketineni 		return status;
36171ddef455SUsha Ketineni 
36181ddef455SUsha Ketineni 	rl_prof_id = le16_to_cpu(rl_prof_info->profile.profile_id);
36191ddef455SUsha Ketineni 
36201ddef455SUsha Ketineni 	/* Save existing RL prof ID for later clean up */
36211ddef455SUsha Ketineni 	old_id = ice_sched_get_node_rl_prof_id(node, rl_type);
36221ddef455SUsha Ketineni 	/* Configure BW scheduling parameters */
36231ddef455SUsha Ketineni 	status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id);
36241ddef455SUsha Ketineni 	if (status)
36251ddef455SUsha Ketineni 		return status;
36261ddef455SUsha Ketineni 
36271ddef455SUsha Ketineni 	/* New changes has been applied */
36281ddef455SUsha Ketineni 	/* Increment the profile ID reference count */
36291ddef455SUsha Ketineni 	rl_prof_info->prof_id_ref++;
36301ddef455SUsha Ketineni 
36311ddef455SUsha Ketineni 	/* Check for old ID removal */
36321ddef455SUsha Ketineni 	if ((old_id == ICE_SCHED_DFLT_RL_PROF_ID && rl_type != ICE_SHARED_BW) ||
36331ddef455SUsha Ketineni 	    old_id == ICE_SCHED_INVAL_PROF_ID || old_id == rl_prof_id)
36341ddef455SUsha Ketineni 		return 0;
36351ddef455SUsha Ketineni 
36361ddef455SUsha Ketineni 	return ice_sched_rm_rl_profile(pi, layer_num,
3637b3b93d6cSTarun Singh 				       rl_prof_info->profile.flags &
3638b3b93d6cSTarun Singh 				       ICE_AQC_RL_PROFILE_TYPE_M, old_id);
36391ddef455SUsha Ketineni }
36401ddef455SUsha Ketineni 
36411ddef455SUsha Ketineni /**
364216dfa494SMichal Wilczynski  * ice_sched_set_node_priority - set node's priority
364316dfa494SMichal Wilczynski  * @pi: port information structure
364416dfa494SMichal Wilczynski  * @node: tree node
364516dfa494SMichal Wilczynski  * @priority: number 0-7 representing priority among siblings
364616dfa494SMichal Wilczynski  *
364716dfa494SMichal Wilczynski  * This function sets priority of a node among it's siblings.
364816dfa494SMichal Wilczynski  */
364916dfa494SMichal Wilczynski int
ice_sched_set_node_priority(struct ice_port_info * pi,struct ice_sched_node * node,u16 priority)365016dfa494SMichal Wilczynski ice_sched_set_node_priority(struct ice_port_info *pi, struct ice_sched_node *node,
365116dfa494SMichal Wilczynski 			    u16 priority)
365216dfa494SMichal Wilczynski {
365316dfa494SMichal Wilczynski 	struct ice_aqc_txsched_elem_data buf;
365416dfa494SMichal Wilczynski 	struct ice_aqc_txsched_elem *data;
365516dfa494SMichal Wilczynski 
365616dfa494SMichal Wilczynski 	buf = node->info;
365716dfa494SMichal Wilczynski 	data = &buf.data;
365816dfa494SMichal Wilczynski 
365916dfa494SMichal Wilczynski 	data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC;
366016dfa494SMichal Wilczynski 	data->generic |= FIELD_PREP(ICE_AQC_ELEM_GENERIC_PRIO_M, priority);
366116dfa494SMichal Wilczynski 
366216dfa494SMichal Wilczynski 	return ice_sched_update_elem(pi->hw, node, &buf);
366316dfa494SMichal Wilczynski }
366416dfa494SMichal Wilczynski 
366516dfa494SMichal Wilczynski /**
366616dfa494SMichal Wilczynski  * ice_sched_set_node_weight - set node's weight
366716dfa494SMichal Wilczynski  * @pi: port information structure
366816dfa494SMichal Wilczynski  * @node: tree node
366916dfa494SMichal Wilczynski  * @weight: number 1-200 representing weight for WFQ
367016dfa494SMichal Wilczynski  *
367116dfa494SMichal Wilczynski  * This function sets weight of the node for WFQ algorithm.
367216dfa494SMichal Wilczynski  */
367316dfa494SMichal Wilczynski int
ice_sched_set_node_weight(struct ice_port_info * pi,struct ice_sched_node * node,u16 weight)367416dfa494SMichal Wilczynski ice_sched_set_node_weight(struct ice_port_info *pi, struct ice_sched_node *node, u16 weight)
367516dfa494SMichal Wilczynski {
367616dfa494SMichal Wilczynski 	struct ice_aqc_txsched_elem_data buf;
367716dfa494SMichal Wilczynski 	struct ice_aqc_txsched_elem *data;
367816dfa494SMichal Wilczynski 
367916dfa494SMichal Wilczynski 	buf = node->info;
368016dfa494SMichal Wilczynski 	data = &buf.data;
368116dfa494SMichal Wilczynski 
368216dfa494SMichal Wilczynski 	data->valid_sections = ICE_AQC_ELEM_VALID_CIR | ICE_AQC_ELEM_VALID_EIR |
368316dfa494SMichal Wilczynski 			       ICE_AQC_ELEM_VALID_GENERIC;
368416dfa494SMichal Wilczynski 	data->cir_bw.bw_alloc = cpu_to_le16(weight);
368516dfa494SMichal Wilczynski 	data->eir_bw.bw_alloc = cpu_to_le16(weight);
368616dfa494SMichal Wilczynski 
368716dfa494SMichal Wilczynski 	data->generic |= FIELD_PREP(ICE_AQC_ELEM_GENERIC_SP_M, 0x0);
368816dfa494SMichal Wilczynski 
368916dfa494SMichal Wilczynski 	return ice_sched_update_elem(pi->hw, node, &buf);
369016dfa494SMichal Wilczynski }
369116dfa494SMichal Wilczynski 
369216dfa494SMichal Wilczynski /**
36931ddef455SUsha Ketineni  * ice_sched_set_node_bw_lmt - set node's BW limit
36941ddef455SUsha Ketineni  * @pi: port information structure
36951ddef455SUsha Ketineni  * @node: tree node
36961ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
36971ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
36981ddef455SUsha Ketineni  *
36991ddef455SUsha Ketineni  * It updates node's BW limit parameters like BW RL profile ID of type CIR,
37001ddef455SUsha Ketineni  * EIR, or SRL. The caller needs to hold scheduler lock.
37011ddef455SUsha Ketineni  */
370216dfa494SMichal Wilczynski int
ice_sched_set_node_bw_lmt(struct ice_port_info * pi,struct ice_sched_node * node,enum ice_rl_type rl_type,u32 bw)37031ddef455SUsha Ketineni ice_sched_set_node_bw_lmt(struct ice_port_info *pi, struct ice_sched_node *node,
37041ddef455SUsha Ketineni 			  enum ice_rl_type rl_type, u32 bw)
37051ddef455SUsha Ketineni {
37061ddef455SUsha Ketineni 	struct ice_sched_node *cfg_node = node;
37075e24d598STony Nguyen 	int status;
37081ddef455SUsha Ketineni 
37091ddef455SUsha Ketineni 	struct ice_hw *hw;
37101ddef455SUsha Ketineni 	u8 layer_num;
37111ddef455SUsha Ketineni 
37121ddef455SUsha Ketineni 	if (!pi)
3713d54699e2STony Nguyen 		return -EINVAL;
37141ddef455SUsha Ketineni 	hw = pi->hw;
37151ddef455SUsha Ketineni 	/* Remove unused RL profile IDs from HW and SW DB */
37161ddef455SUsha Ketineni 	ice_sched_rm_unused_rl_prof(pi);
37171ddef455SUsha Ketineni 	layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
37181ddef455SUsha Ketineni 						node->tx_sched_layer);
37191ddef455SUsha Ketineni 	if (layer_num >= hw->num_tx_sched_layers)
3720d54699e2STony Nguyen 		return -EINVAL;
37211ddef455SUsha Ketineni 
37221ddef455SUsha Ketineni 	if (rl_type == ICE_SHARED_BW) {
37231ddef455SUsha Ketineni 		/* SRL node may be different */
37241ddef455SUsha Ketineni 		cfg_node = ice_sched_get_srl_node(node, layer_num);
37251ddef455SUsha Ketineni 		if (!cfg_node)
3726d54699e2STony Nguyen 			return -EIO;
37271ddef455SUsha Ketineni 	}
37281ddef455SUsha Ketineni 	/* EIR BW and Shared BW profiles are mutually exclusive and
37291ddef455SUsha Ketineni 	 * hence only one of them may be set for any given element
37301ddef455SUsha Ketineni 	 */
37311ddef455SUsha Ketineni 	status = ice_sched_set_eir_srl_excl(pi, cfg_node, layer_num, rl_type,
37321ddef455SUsha Ketineni 					    bw);
37331ddef455SUsha Ketineni 	if (status)
37341ddef455SUsha Ketineni 		return status;
37351ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW)
37361ddef455SUsha Ketineni 		return ice_sched_set_node_bw_dflt(pi, cfg_node, rl_type,
37371ddef455SUsha Ketineni 						  layer_num);
37381ddef455SUsha Ketineni 	return ice_sched_set_node_bw(pi, cfg_node, rl_type, bw, layer_num);
37391ddef455SUsha Ketineni }
37401ddef455SUsha Ketineni 
37411ddef455SUsha Ketineni /**
37421ddef455SUsha Ketineni  * ice_sched_set_node_bw_dflt_lmt - set node's BW limit to default
37431ddef455SUsha Ketineni  * @pi: port information structure
37441ddef455SUsha Ketineni  * @node: pointer to node structure
37451ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
37461ddef455SUsha Ketineni  *
37471ddef455SUsha Ketineni  * This function configures node element's BW rate limit profile ID of
37481ddef455SUsha Ketineni  * type CIR, EIR, or SRL to default. This function needs to be called
37491ddef455SUsha Ketineni  * with the scheduler lock held.
37501ddef455SUsha Ketineni  */
37515e24d598STony Nguyen static int
ice_sched_set_node_bw_dflt_lmt(struct ice_port_info * pi,struct ice_sched_node * node,enum ice_rl_type rl_type)37521ddef455SUsha Ketineni ice_sched_set_node_bw_dflt_lmt(struct ice_port_info *pi,
37531ddef455SUsha Ketineni 			       struct ice_sched_node *node,
37541ddef455SUsha Ketineni 			       enum ice_rl_type rl_type)
37551ddef455SUsha Ketineni {
37561ddef455SUsha Ketineni 	return ice_sched_set_node_bw_lmt(pi, node, rl_type,
37571ddef455SUsha Ketineni 					 ICE_SCHED_DFLT_BW);
37581ddef455SUsha Ketineni }
37591ddef455SUsha Ketineni 
37601ddef455SUsha Ketineni /**
37611ddef455SUsha Ketineni  * ice_sched_validate_srl_node - Check node for SRL applicability
37621ddef455SUsha Ketineni  * @node: sched node to configure
37631ddef455SUsha Ketineni  * @sel_layer: selected SRL layer
37641ddef455SUsha Ketineni  *
37651ddef455SUsha Ketineni  * This function checks if the SRL can be applied to a selected layer node on
37661ddef455SUsha Ketineni  * behalf of the requested node (first argument). This function needs to be
37671ddef455SUsha Ketineni  * called with scheduler lock held.
37681ddef455SUsha Ketineni  */
37695e24d598STony Nguyen static int
ice_sched_validate_srl_node(struct ice_sched_node * node,u8 sel_layer)37701ddef455SUsha Ketineni ice_sched_validate_srl_node(struct ice_sched_node *node, u8 sel_layer)
37711ddef455SUsha Ketineni {
37721ddef455SUsha Ketineni 	/* SRL profiles are not available on all layers. Check if the
37731ddef455SUsha Ketineni 	 * SRL profile can be applied to a node above or below the
37741ddef455SUsha Ketineni 	 * requested node. SRL configuration is possible only if the
37751ddef455SUsha Ketineni 	 * selected layer's node has single child.
37761ddef455SUsha Ketineni 	 */
37771ddef455SUsha Ketineni 	if (sel_layer == node->tx_sched_layer ||
37781ddef455SUsha Ketineni 	    ((sel_layer == node->tx_sched_layer + 1) &&
37791ddef455SUsha Ketineni 	    node->num_children == 1) ||
37801ddef455SUsha Ketineni 	    ((sel_layer == node->tx_sched_layer - 1) &&
37811ddef455SUsha Ketineni 	    (node->parent && node->parent->num_children == 1)))
37821ddef455SUsha Ketineni 		return 0;
37831ddef455SUsha Ketineni 
3784d54699e2STony Nguyen 	return -EIO;
37851ddef455SUsha Ketineni }
37861ddef455SUsha Ketineni 
37871ddef455SUsha Ketineni /**
37881ddef455SUsha Ketineni  * ice_sched_save_q_bw - save queue node's BW information
37891ddef455SUsha Ketineni  * @q_ctx: queue context structure
37901ddef455SUsha Ketineni  * @rl_type: rate limit type min, max, or shared
37911ddef455SUsha Ketineni  * @bw: bandwidth in Kbps - Kilo bits per sec
37921ddef455SUsha Ketineni  *
37931ddef455SUsha Ketineni  * Save BW information of queue type node for post replay use.
37941ddef455SUsha Ketineni  */
37955e24d598STony Nguyen static int
ice_sched_save_q_bw(struct ice_q_ctx * q_ctx,enum ice_rl_type rl_type,u32 bw)37961ddef455SUsha Ketineni ice_sched_save_q_bw(struct ice_q_ctx *q_ctx, enum ice_rl_type rl_type, u32 bw)
37971ddef455SUsha Ketineni {
37981ddef455SUsha Ketineni 	switch (rl_type) {
37991ddef455SUsha Ketineni 	case ICE_MIN_BW:
38001ddef455SUsha Ketineni 		ice_set_clear_cir_bw(&q_ctx->bw_t_info, bw);
38011ddef455SUsha Ketineni 		break;
38021ddef455SUsha Ketineni 	case ICE_MAX_BW:
38031ddef455SUsha Ketineni 		ice_set_clear_eir_bw(&q_ctx->bw_t_info, bw);
38041ddef455SUsha Ketineni 		break;
38051ddef455SUsha Ketineni 	case ICE_SHARED_BW:
38061ddef455SUsha Ketineni 		ice_set_clear_shared_bw(&q_ctx->bw_t_info, bw);
38071ddef455SUsha Ketineni 		break;
38081ddef455SUsha Ketineni 	default:
3809d54699e2STony Nguyen 		return -EINVAL;
38101ddef455SUsha Ketineni 	}
38111ddef455SUsha Ketineni 	return 0;
38121ddef455SUsha Ketineni }
38131ddef455SUsha Ketineni 
38141ddef455SUsha Ketineni /**
38151ddef455SUsha Ketineni  * ice_sched_set_q_bw_lmt - sets queue BW limit
38161ddef455SUsha Ketineni  * @pi: port information structure
38171ddef455SUsha Ketineni  * @vsi_handle: sw VSI handle
38181ddef455SUsha Ketineni  * @tc: traffic class
38191ddef455SUsha Ketineni  * @q_handle: software queue handle
38201ddef455SUsha Ketineni  * @rl_type: min, max, or shared
38211ddef455SUsha Ketineni  * @bw: bandwidth in Kbps
38221ddef455SUsha Ketineni  *
38231ddef455SUsha Ketineni  * This function sets BW limit of queue scheduling node.
38241ddef455SUsha Ketineni  */
38255e24d598STony Nguyen static int
ice_sched_set_q_bw_lmt(struct ice_port_info * pi,u16 vsi_handle,u8 tc,u16 q_handle,enum ice_rl_type rl_type,u32 bw)38261ddef455SUsha Ketineni ice_sched_set_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
38271ddef455SUsha Ketineni 		       u16 q_handle, enum ice_rl_type rl_type, u32 bw)
38281ddef455SUsha Ketineni {
38291ddef455SUsha Ketineni 	struct ice_sched_node *node;
38301ddef455SUsha Ketineni 	struct ice_q_ctx *q_ctx;
38315518ac2aSTony Nguyen 	int status = -EINVAL;
38321ddef455SUsha Ketineni 
38331ddef455SUsha Ketineni 	if (!ice_is_vsi_valid(pi->hw, vsi_handle))
3834d54699e2STony Nguyen 		return -EINVAL;
38351ddef455SUsha Ketineni 	mutex_lock(&pi->sched_lock);
38361ddef455SUsha Ketineni 	q_ctx = ice_get_lan_q_ctx(pi->hw, vsi_handle, tc, q_handle);
38371ddef455SUsha Ketineni 	if (!q_ctx)
38381ddef455SUsha Ketineni 		goto exit_q_bw_lmt;
38391ddef455SUsha Ketineni 	node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid);
38401ddef455SUsha Ketineni 	if (!node) {
38411ddef455SUsha Ketineni 		ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong q_teid\n");
38421ddef455SUsha Ketineni 		goto exit_q_bw_lmt;
38431ddef455SUsha Ketineni 	}
38441ddef455SUsha Ketineni 
38451ddef455SUsha Ketineni 	/* Return error if it is not a leaf node */
38461ddef455SUsha Ketineni 	if (node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF)
38471ddef455SUsha Ketineni 		goto exit_q_bw_lmt;
38481ddef455SUsha Ketineni 
38491ddef455SUsha Ketineni 	/* SRL bandwidth layer selection */
38501ddef455SUsha Ketineni 	if (rl_type == ICE_SHARED_BW) {
38511ddef455SUsha Ketineni 		u8 sel_layer; /* selected layer */
38521ddef455SUsha Ketineni 
38531ddef455SUsha Ketineni 		sel_layer = ice_sched_get_rl_prof_layer(pi, rl_type,
38541ddef455SUsha Ketineni 							node->tx_sched_layer);
38551ddef455SUsha Ketineni 		if (sel_layer >= pi->hw->num_tx_sched_layers) {
3856d54699e2STony Nguyen 			status = -EINVAL;
38571ddef455SUsha Ketineni 			goto exit_q_bw_lmt;
38581ddef455SUsha Ketineni 		}
38591ddef455SUsha Ketineni 		status = ice_sched_validate_srl_node(node, sel_layer);
38601ddef455SUsha Ketineni 		if (status)
38611ddef455SUsha Ketineni 			goto exit_q_bw_lmt;
38621ddef455SUsha Ketineni 	}
38631ddef455SUsha Ketineni 
38641ddef455SUsha Ketineni 	if (bw == ICE_SCHED_DFLT_BW)
38651ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type);
38661ddef455SUsha Ketineni 	else
38671ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw);
38681ddef455SUsha Ketineni 
38691ddef455SUsha Ketineni 	if (!status)
38701ddef455SUsha Ketineni 		status = ice_sched_save_q_bw(q_ctx, rl_type, bw);
38711ddef455SUsha Ketineni 
38721ddef455SUsha Ketineni exit_q_bw_lmt:
38731ddef455SUsha Ketineni 	mutex_unlock(&pi->sched_lock);
38741ddef455SUsha Ketineni 	return status;
38751ddef455SUsha Ketineni }
38761ddef455SUsha Ketineni 
38771ddef455SUsha Ketineni /**
38781ddef455SUsha Ketineni  * ice_cfg_q_bw_lmt - configure queue BW limit
38791ddef455SUsha Ketineni  * @pi: port information structure
38801ddef455SUsha Ketineni  * @vsi_handle: sw VSI handle
38811ddef455SUsha Ketineni  * @tc: traffic class
38821ddef455SUsha Ketineni  * @q_handle: software queue handle
38831ddef455SUsha Ketineni  * @rl_type: min, max, or shared
38841ddef455SUsha Ketineni  * @bw: bandwidth in Kbps
38851ddef455SUsha Ketineni  *
38861ddef455SUsha Ketineni  * This function configures BW limit of queue scheduling node.
38871ddef455SUsha Ketineni  */
38885e24d598STony Nguyen int
ice_cfg_q_bw_lmt(struct ice_port_info * pi,u16 vsi_handle,u8 tc,u16 q_handle,enum ice_rl_type rl_type,u32 bw)38891ddef455SUsha Ketineni ice_cfg_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
38901ddef455SUsha Ketineni 		 u16 q_handle, enum ice_rl_type rl_type, u32 bw)
38911ddef455SUsha Ketineni {
38921ddef455SUsha Ketineni 	return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type,
38931ddef455SUsha Ketineni 				      bw);
38941ddef455SUsha Ketineni }
38951ddef455SUsha Ketineni 
38961ddef455SUsha Ketineni /**
38971ddef455SUsha Ketineni  * ice_cfg_q_bw_dflt_lmt - configure queue BW default limit
38981ddef455SUsha Ketineni  * @pi: port information structure
38991ddef455SUsha Ketineni  * @vsi_handle: sw VSI handle
39001ddef455SUsha Ketineni  * @tc: traffic class
39011ddef455SUsha Ketineni  * @q_handle: software queue handle
39021ddef455SUsha Ketineni  * @rl_type: min, max, or shared
39031ddef455SUsha Ketineni  *
39041ddef455SUsha Ketineni  * This function configures BW default limit of queue scheduling node.
39051ddef455SUsha Ketineni  */
39065e24d598STony Nguyen int
ice_cfg_q_bw_dflt_lmt(struct ice_port_info * pi,u16 vsi_handle,u8 tc,u16 q_handle,enum ice_rl_type rl_type)39071ddef455SUsha Ketineni ice_cfg_q_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
39081ddef455SUsha Ketineni 		      u16 q_handle, enum ice_rl_type rl_type)
39091ddef455SUsha Ketineni {
39101ddef455SUsha Ketineni 	return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type,
39111ddef455SUsha Ketineni 				      ICE_SCHED_DFLT_BW);
39121ddef455SUsha Ketineni }
39131ddef455SUsha Ketineni 
39141ddef455SUsha Ketineni /**
39154ecc8633SBrett Creeley  * ice_sched_get_node_by_id_type - get node from ID type
39164ecc8633SBrett Creeley  * @pi: port information structure
39174ecc8633SBrett Creeley  * @id: identifier
39184ecc8633SBrett Creeley  * @agg_type: type of aggregator
39194ecc8633SBrett Creeley  * @tc: traffic class
39204ecc8633SBrett Creeley  *
39214ecc8633SBrett Creeley  * This function returns node identified by ID of type aggregator, and
39224ecc8633SBrett Creeley  * based on traffic class (TC). This function needs to be called with
39234ecc8633SBrett Creeley  * the scheduler lock held.
39244ecc8633SBrett Creeley  */
39254ecc8633SBrett Creeley static struct ice_sched_node *
ice_sched_get_node_by_id_type(struct ice_port_info * pi,u32 id,enum ice_agg_type agg_type,u8 tc)39264ecc8633SBrett Creeley ice_sched_get_node_by_id_type(struct ice_port_info *pi, u32 id,
39274ecc8633SBrett Creeley 			      enum ice_agg_type agg_type, u8 tc)
39284ecc8633SBrett Creeley {
39294ecc8633SBrett Creeley 	struct ice_sched_node *node = NULL;
39304ecc8633SBrett Creeley 
39314ecc8633SBrett Creeley 	switch (agg_type) {
39324ecc8633SBrett Creeley 	case ICE_AGG_TYPE_VSI: {
39334ecc8633SBrett Creeley 		struct ice_vsi_ctx *vsi_ctx;
39344ecc8633SBrett Creeley 		u16 vsi_handle = (u16)id;
39354ecc8633SBrett Creeley 
39364ecc8633SBrett Creeley 		if (!ice_is_vsi_valid(pi->hw, vsi_handle))
39374ecc8633SBrett Creeley 			break;
39384ecc8633SBrett Creeley 		/* Get sched_vsi_info */
39394ecc8633SBrett Creeley 		vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
39404ecc8633SBrett Creeley 		if (!vsi_ctx)
39414ecc8633SBrett Creeley 			break;
39424ecc8633SBrett Creeley 		node = vsi_ctx->sched.vsi_node[tc];
39434ecc8633SBrett Creeley 		break;
39444ecc8633SBrett Creeley 	}
39454ecc8633SBrett Creeley 
39464ecc8633SBrett Creeley 	case ICE_AGG_TYPE_AGG: {
39474ecc8633SBrett Creeley 		struct ice_sched_node *tc_node;
39484ecc8633SBrett Creeley 
39494ecc8633SBrett Creeley 		tc_node = ice_sched_get_tc_node(pi, tc);
39504ecc8633SBrett Creeley 		if (tc_node)
39514ecc8633SBrett Creeley 			node = ice_sched_get_agg_node(pi, tc_node, id);
39524ecc8633SBrett Creeley 		break;
39534ecc8633SBrett Creeley 	}
39544ecc8633SBrett Creeley 
39554ecc8633SBrett Creeley 	default:
39564ecc8633SBrett Creeley 		break;
39574ecc8633SBrett Creeley 	}
39584ecc8633SBrett Creeley 
39594ecc8633SBrett Creeley 	return node;
39604ecc8633SBrett Creeley }
39614ecc8633SBrett Creeley 
39624ecc8633SBrett Creeley /**
39634ecc8633SBrett Creeley  * ice_sched_set_node_bw_lmt_per_tc - set node BW limit per TC
39644ecc8633SBrett Creeley  * @pi: port information structure
39654ecc8633SBrett Creeley  * @id: ID (software VSI handle or AGG ID)
39664ecc8633SBrett Creeley  * @agg_type: aggregator type (VSI or AGG type node)
39674ecc8633SBrett Creeley  * @tc: traffic class
39684ecc8633SBrett Creeley  * @rl_type: min or max
39694ecc8633SBrett Creeley  * @bw: bandwidth in Kbps
39704ecc8633SBrett Creeley  *
39714ecc8633SBrett Creeley  * This function sets BW limit of VSI or Aggregator scheduling node
39724ecc8633SBrett Creeley  * based on TC information from passed in argument BW.
39734ecc8633SBrett Creeley  */
3974*9762f8faSJan Sokolowski static int
ice_sched_set_node_bw_lmt_per_tc(struct ice_port_info * pi,u32 id,enum ice_agg_type agg_type,u8 tc,enum ice_rl_type rl_type,u32 bw)39754ecc8633SBrett Creeley ice_sched_set_node_bw_lmt_per_tc(struct ice_port_info *pi, u32 id,
39764ecc8633SBrett Creeley 				 enum ice_agg_type agg_type, u8 tc,
39774ecc8633SBrett Creeley 				 enum ice_rl_type rl_type, u32 bw)
39784ecc8633SBrett Creeley {
39794ecc8633SBrett Creeley 	struct ice_sched_node *node;
39805518ac2aSTony Nguyen 	int status = -EINVAL;
39814ecc8633SBrett Creeley 
39824ecc8633SBrett Creeley 	if (!pi)
39834ecc8633SBrett Creeley 		return status;
39844ecc8633SBrett Creeley 
39854ecc8633SBrett Creeley 	if (rl_type == ICE_UNKNOWN_BW)
39864ecc8633SBrett Creeley 		return status;
39874ecc8633SBrett Creeley 
39884ecc8633SBrett Creeley 	mutex_lock(&pi->sched_lock);
39894ecc8633SBrett Creeley 	node = ice_sched_get_node_by_id_type(pi, id, agg_type, tc);
39904ecc8633SBrett Creeley 	if (!node) {
39914ecc8633SBrett Creeley 		ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong id, agg type, or tc\n");
39924ecc8633SBrett Creeley 		goto exit_set_node_bw_lmt_per_tc;
39934ecc8633SBrett Creeley 	}
39944ecc8633SBrett Creeley 	if (bw == ICE_SCHED_DFLT_BW)
39954ecc8633SBrett Creeley 		status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type);
39964ecc8633SBrett Creeley 	else
39974ecc8633SBrett Creeley 		status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw);
39984ecc8633SBrett Creeley 
39994ecc8633SBrett Creeley exit_set_node_bw_lmt_per_tc:
40004ecc8633SBrett Creeley 	mutex_unlock(&pi->sched_lock);
40014ecc8633SBrett Creeley 	return status;
40024ecc8633SBrett Creeley }
40034ecc8633SBrett Creeley 
40044ecc8633SBrett Creeley /**
40054ecc8633SBrett Creeley  * ice_cfg_vsi_bw_lmt_per_tc - configure VSI BW limit per TC
40064ecc8633SBrett Creeley  * @pi: port information structure
40074ecc8633SBrett Creeley  * @vsi_handle: software VSI handle
40084ecc8633SBrett Creeley  * @tc: traffic class
40094ecc8633SBrett Creeley  * @rl_type: min or max
40104ecc8633SBrett Creeley  * @bw: bandwidth in Kbps
40114ecc8633SBrett Creeley  *
40124ecc8633SBrett Creeley  * This function configures BW limit of VSI scheduling node based on TC
40134ecc8633SBrett Creeley  * information.
40144ecc8633SBrett Creeley  */
40155e24d598STony Nguyen int
ice_cfg_vsi_bw_lmt_per_tc(struct ice_port_info * pi,u16 vsi_handle,u8 tc,enum ice_rl_type rl_type,u32 bw)40164ecc8633SBrett Creeley ice_cfg_vsi_bw_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
40174ecc8633SBrett Creeley 			  enum ice_rl_type rl_type, u32 bw)
40184ecc8633SBrett Creeley {
40190754d65bSKiran Patil 	int status;
40200754d65bSKiran Patil 
40210754d65bSKiran Patil 	status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle,
40224ecc8633SBrett Creeley 						  ICE_AGG_TYPE_VSI,
40234ecc8633SBrett Creeley 						  tc, rl_type, bw);
40240754d65bSKiran Patil 	if (!status) {
40250754d65bSKiran Patil 		mutex_lock(&pi->sched_lock);
40260754d65bSKiran Patil 		status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, bw);
40270754d65bSKiran Patil 		mutex_unlock(&pi->sched_lock);
40280754d65bSKiran Patil 	}
40290754d65bSKiran Patil 	return status;
40304ecc8633SBrett Creeley }
40314ecc8633SBrett Creeley 
40324ecc8633SBrett Creeley /**
40334ecc8633SBrett Creeley  * ice_cfg_vsi_bw_dflt_lmt_per_tc - configure default VSI BW limit per TC
40344ecc8633SBrett Creeley  * @pi: port information structure
40354ecc8633SBrett Creeley  * @vsi_handle: software VSI handle
40364ecc8633SBrett Creeley  * @tc: traffic class
40374ecc8633SBrett Creeley  * @rl_type: min or max
40384ecc8633SBrett Creeley  *
40394ecc8633SBrett Creeley  * This function configures default BW limit of VSI scheduling node based on TC
40404ecc8633SBrett Creeley  * information.
40414ecc8633SBrett Creeley  */
40425e24d598STony Nguyen int
ice_cfg_vsi_bw_dflt_lmt_per_tc(struct ice_port_info * pi,u16 vsi_handle,u8 tc,enum ice_rl_type rl_type)40434ecc8633SBrett Creeley ice_cfg_vsi_bw_dflt_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
40444ecc8633SBrett Creeley 			       enum ice_rl_type rl_type)
40454ecc8633SBrett Creeley {
40460754d65bSKiran Patil 	int status;
40470754d65bSKiran Patil 
40480754d65bSKiran Patil 	status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle,
40494ecc8633SBrett Creeley 						  ICE_AGG_TYPE_VSI,
40504ecc8633SBrett Creeley 						  tc, rl_type,
40514ecc8633SBrett Creeley 						  ICE_SCHED_DFLT_BW);
40520754d65bSKiran Patil 	if (!status) {
40530754d65bSKiran Patil 		mutex_lock(&pi->sched_lock);
40540754d65bSKiran Patil 		status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type,
40550754d65bSKiran Patil 					       ICE_SCHED_DFLT_BW);
40560754d65bSKiran Patil 		mutex_unlock(&pi->sched_lock);
40570754d65bSKiran Patil 	}
40580754d65bSKiran Patil 	return status;
40594ecc8633SBrett Creeley }
40604ecc8633SBrett Creeley 
40614ecc8633SBrett Creeley /**
40621ddef455SUsha Ketineni  * ice_cfg_rl_burst_size - Set burst size value
40631ddef455SUsha Ketineni  * @hw: pointer to the HW struct
40641ddef455SUsha Ketineni  * @bytes: burst size in bytes
40651ddef455SUsha Ketineni  *
40661ddef455SUsha Ketineni  * This function configures/set the burst size to requested new value. The new
40671ddef455SUsha Ketineni  * burst size value is used for future rate limit calls. It doesn't change the
40681ddef455SUsha Ketineni  * existing or previously created RL profiles.
40691ddef455SUsha Ketineni  */
ice_cfg_rl_burst_size(struct ice_hw * hw,u32 bytes)40705e24d598STony Nguyen int ice_cfg_rl_burst_size(struct ice_hw *hw, u32 bytes)
40711ddef455SUsha Ketineni {
40721ddef455SUsha Ketineni 	u16 burst_size_to_prog;
40731ddef455SUsha Ketineni 
40741ddef455SUsha Ketineni 	if (bytes < ICE_MIN_BURST_SIZE_ALLOWED ||
40751ddef455SUsha Ketineni 	    bytes > ICE_MAX_BURST_SIZE_ALLOWED)
4076d54699e2STony Nguyen 		return -EINVAL;
40771ddef455SUsha Ketineni 	if (ice_round_to_num(bytes, 64) <=
40781ddef455SUsha Ketineni 	    ICE_MAX_BURST_SIZE_64_BYTE_GRANULARITY) {
40791ddef455SUsha Ketineni 		/* 64 byte granularity case */
40801ddef455SUsha Ketineni 		/* Disable MSB granularity bit */
40811ddef455SUsha Ketineni 		burst_size_to_prog = ICE_64_BYTE_GRANULARITY;
40821ddef455SUsha Ketineni 		/* round number to nearest 64 byte granularity */
40831ddef455SUsha Ketineni 		bytes = ice_round_to_num(bytes, 64);
40841ddef455SUsha Ketineni 		/* The value is in 64 byte chunks */
40851ddef455SUsha Ketineni 		burst_size_to_prog |= (u16)(bytes / 64);
40861ddef455SUsha Ketineni 	} else {
40871ddef455SUsha Ketineni 		/* k bytes granularity case */
40881ddef455SUsha Ketineni 		/* Enable MSB granularity bit */
40891ddef455SUsha Ketineni 		burst_size_to_prog = ICE_KBYTE_GRANULARITY;
40901ddef455SUsha Ketineni 		/* round number to nearest 1024 granularity */
40911ddef455SUsha Ketineni 		bytes = ice_round_to_num(bytes, 1024);
40921ddef455SUsha Ketineni 		/* check rounding doesn't go beyond allowed */
40931ddef455SUsha Ketineni 		if (bytes > ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY)
40941ddef455SUsha Ketineni 			bytes = ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY;
40951ddef455SUsha Ketineni 		/* The value is in k bytes */
40961ddef455SUsha Ketineni 		burst_size_to_prog |= (u16)(bytes / 1024);
40971ddef455SUsha Ketineni 	}
40981ddef455SUsha Ketineni 	hw->max_burst_size = burst_size_to_prog;
40991ddef455SUsha Ketineni 	return 0;
41001ddef455SUsha Ketineni }
41011ddef455SUsha Ketineni 
41021ddef455SUsha Ketineni /**
41031ddef455SUsha Ketineni  * ice_sched_replay_node_prio - re-configure node priority
41041ddef455SUsha Ketineni  * @hw: pointer to the HW struct
41051ddef455SUsha Ketineni  * @node: sched node to configure
41061ddef455SUsha Ketineni  * @priority: priority value
41071ddef455SUsha Ketineni  *
41081ddef455SUsha Ketineni  * This function configures node element's priority value. It
41091ddef455SUsha Ketineni  * needs to be called with scheduler lock held.
41101ddef455SUsha Ketineni  */
41115e24d598STony Nguyen static int
ice_sched_replay_node_prio(struct ice_hw * hw,struct ice_sched_node * node,u8 priority)41121ddef455SUsha Ketineni ice_sched_replay_node_prio(struct ice_hw *hw, struct ice_sched_node *node,
41131ddef455SUsha Ketineni 			   u8 priority)
41141ddef455SUsha Ketineni {
41151ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem_data buf;
41161ddef455SUsha Ketineni 	struct ice_aqc_txsched_elem *data;
41175e24d598STony Nguyen 	int status;
41181ddef455SUsha Ketineni 
41191ddef455SUsha Ketineni 	buf = node->info;
41201ddef455SUsha Ketineni 	data = &buf.data;
41211ddef455SUsha Ketineni 	data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC;
41221ddef455SUsha Ketineni 	data->generic = priority;
41231ddef455SUsha Ketineni 
41241ddef455SUsha Ketineni 	/* Configure element */
41251ddef455SUsha Ketineni 	status = ice_sched_update_elem(hw, node, &buf);
41261ddef455SUsha Ketineni 	return status;
41271ddef455SUsha Ketineni }
41281ddef455SUsha Ketineni 
41291ddef455SUsha Ketineni /**
41301ddef455SUsha Ketineni  * ice_sched_replay_node_bw - replay node(s) BW
41311ddef455SUsha Ketineni  * @hw: pointer to the HW struct
41321ddef455SUsha Ketineni  * @node: sched node to configure
41331ddef455SUsha Ketineni  * @bw_t_info: BW type information
41341ddef455SUsha Ketineni  *
41351ddef455SUsha Ketineni  * This function restores node's BW from bw_t_info. The caller needs
41361ddef455SUsha Ketineni  * to hold the scheduler lock.
41371ddef455SUsha Ketineni  */
41385e24d598STony Nguyen static int
ice_sched_replay_node_bw(struct ice_hw * hw,struct ice_sched_node * node,struct ice_bw_type_info * bw_t_info)41391ddef455SUsha Ketineni ice_sched_replay_node_bw(struct ice_hw *hw, struct ice_sched_node *node,
41401ddef455SUsha Ketineni 			 struct ice_bw_type_info *bw_t_info)
41411ddef455SUsha Ketineni {
41421ddef455SUsha Ketineni 	struct ice_port_info *pi = hw->port_info;
4143d54699e2STony Nguyen 	int status = -EINVAL;
41441ddef455SUsha Ketineni 	u16 bw_alloc;
41451ddef455SUsha Ketineni 
41461ddef455SUsha Ketineni 	if (!node)
41471ddef455SUsha Ketineni 		return status;
41481ddef455SUsha Ketineni 	if (bitmap_empty(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CNT))
41491ddef455SUsha Ketineni 		return 0;
41501ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap)) {
41511ddef455SUsha Ketineni 		status = ice_sched_replay_node_prio(hw, node,
41521ddef455SUsha Ketineni 						    bw_t_info->generic);
41531ddef455SUsha Ketineni 		if (status)
41541ddef455SUsha Ketineni 			return status;
41551ddef455SUsha Ketineni 	}
41561ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap)) {
41571ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_lmt(pi, node, ICE_MIN_BW,
41581ddef455SUsha Ketineni 						   bw_t_info->cir_bw.bw);
41591ddef455SUsha Ketineni 		if (status)
41601ddef455SUsha Ketineni 			return status;
41611ddef455SUsha Ketineni 	}
41621ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap)) {
41631ddef455SUsha Ketineni 		bw_alloc = bw_t_info->cir_bw.bw_alloc;
41641ddef455SUsha Ketineni 		status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MIN_BW,
41651ddef455SUsha Ketineni 						     bw_alloc);
41661ddef455SUsha Ketineni 		if (status)
41671ddef455SUsha Ketineni 			return status;
41681ddef455SUsha Ketineni 	}
41691ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap)) {
41701ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_lmt(pi, node, ICE_MAX_BW,
41711ddef455SUsha Ketineni 						   bw_t_info->eir_bw.bw);
41721ddef455SUsha Ketineni 		if (status)
41731ddef455SUsha Ketineni 			return status;
41741ddef455SUsha Ketineni 	}
41751ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap)) {
41761ddef455SUsha Ketineni 		bw_alloc = bw_t_info->eir_bw.bw_alloc;
41771ddef455SUsha Ketineni 		status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MAX_BW,
41781ddef455SUsha Ketineni 						     bw_alloc);
41791ddef455SUsha Ketineni 		if (status)
41801ddef455SUsha Ketineni 			return status;
41811ddef455SUsha Ketineni 	}
41821ddef455SUsha Ketineni 	if (test_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap))
41831ddef455SUsha Ketineni 		status = ice_sched_set_node_bw_lmt(pi, node, ICE_SHARED_BW,
41841ddef455SUsha Ketineni 						   bw_t_info->shared_bw);
41851ddef455SUsha Ketineni 	return status;
41861ddef455SUsha Ketineni }
41871ddef455SUsha Ketineni 
41881ddef455SUsha Ketineni /**
4189b126bd6bSKiran Patil  * ice_sched_get_ena_tc_bitmap - get enabled TC bitmap
4190b126bd6bSKiran Patil  * @pi: port info struct
4191b126bd6bSKiran Patil  * @tc_bitmap: 8 bits TC bitmap to check
4192b126bd6bSKiran Patil  * @ena_tc_bitmap: 8 bits enabled TC bitmap to return
4193b126bd6bSKiran Patil  *
4194b126bd6bSKiran Patil  * This function returns enabled TC bitmap in variable ena_tc_bitmap. Some TCs
4195b126bd6bSKiran Patil  * may be missing, it returns enabled TCs. This function needs to be called with
4196b126bd6bSKiran Patil  * scheduler lock held.
4197b126bd6bSKiran Patil  */
4198b126bd6bSKiran Patil static void
ice_sched_get_ena_tc_bitmap(struct ice_port_info * pi,unsigned long * tc_bitmap,unsigned long * ena_tc_bitmap)4199b126bd6bSKiran Patil ice_sched_get_ena_tc_bitmap(struct ice_port_info *pi,
4200b126bd6bSKiran Patil 			    unsigned long *tc_bitmap,
4201b126bd6bSKiran Patil 			    unsigned long *ena_tc_bitmap)
4202b126bd6bSKiran Patil {
4203b126bd6bSKiran Patil 	u8 tc;
4204b126bd6bSKiran Patil 
4205b126bd6bSKiran Patil 	/* Some TC(s) may be missing after reset, adjust for replay */
4206b126bd6bSKiran Patil 	ice_for_each_traffic_class(tc)
4207b126bd6bSKiran Patil 		if (ice_is_tc_ena(*tc_bitmap, tc) &&
4208b126bd6bSKiran Patil 		    (ice_sched_get_tc_node(pi, tc)))
4209b126bd6bSKiran Patil 			set_bit(tc, ena_tc_bitmap);
4210b126bd6bSKiran Patil }
4211b126bd6bSKiran Patil 
4212b126bd6bSKiran Patil /**
4213b126bd6bSKiran Patil  * ice_sched_replay_agg - recreate aggregator node(s)
4214b126bd6bSKiran Patil  * @hw: pointer to the HW struct
4215b126bd6bSKiran Patil  *
4216b126bd6bSKiran Patil  * This function recreate aggregator type nodes which are not replayed earlier.
4217b126bd6bSKiran Patil  * It also replay aggregator BW information. These aggregator nodes are not
4218b126bd6bSKiran Patil  * associated with VSI type node yet.
4219b126bd6bSKiran Patil  */
ice_sched_replay_agg(struct ice_hw * hw)4220b126bd6bSKiran Patil void ice_sched_replay_agg(struct ice_hw *hw)
4221b126bd6bSKiran Patil {
4222b126bd6bSKiran Patil 	struct ice_port_info *pi = hw->port_info;
4223b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
4224b126bd6bSKiran Patil 
4225b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
4226b126bd6bSKiran Patil 	list_for_each_entry(agg_info, &hw->agg_list, list_entry)
4227b126bd6bSKiran Patil 		/* replay aggregator (re-create aggregator node) */
4228b126bd6bSKiran Patil 		if (!bitmap_equal(agg_info->tc_bitmap, agg_info->replay_tc_bitmap,
4229b126bd6bSKiran Patil 				  ICE_MAX_TRAFFIC_CLASS)) {
4230b126bd6bSKiran Patil 			DECLARE_BITMAP(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
42315e24d598STony Nguyen 			int status;
4232b126bd6bSKiran Patil 
4233b126bd6bSKiran Patil 			bitmap_zero(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
4234b126bd6bSKiran Patil 			ice_sched_get_ena_tc_bitmap(pi,
4235b126bd6bSKiran Patil 						    agg_info->replay_tc_bitmap,
4236b126bd6bSKiran Patil 						    replay_bitmap);
4237b126bd6bSKiran Patil 			status = ice_sched_cfg_agg(hw->port_info,
4238b126bd6bSKiran Patil 						   agg_info->agg_id,
4239b126bd6bSKiran Patil 						   ICE_AGG_TYPE_AGG,
4240b126bd6bSKiran Patil 						   replay_bitmap);
4241b126bd6bSKiran Patil 			if (status) {
4242b126bd6bSKiran Patil 				dev_info(ice_hw_to_dev(hw),
4243b126bd6bSKiran Patil 					 "Replay agg id[%d] failed\n",
4244b126bd6bSKiran Patil 					 agg_info->agg_id);
4245b126bd6bSKiran Patil 				/* Move on to next one */
4246b126bd6bSKiran Patil 				continue;
4247b126bd6bSKiran Patil 			}
4248b126bd6bSKiran Patil 		}
4249b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
4250b126bd6bSKiran Patil }
4251b126bd6bSKiran Patil 
4252b126bd6bSKiran Patil /**
4253b126bd6bSKiran Patil  * ice_sched_replay_agg_vsi_preinit - Agg/VSI replay pre initialization
4254b126bd6bSKiran Patil  * @hw: pointer to the HW struct
4255b126bd6bSKiran Patil  *
4256b126bd6bSKiran Patil  * This function initialize aggregator(s) TC bitmap to zero. A required
4257b126bd6bSKiran Patil  * preinit step for replaying aggregators.
4258b126bd6bSKiran Patil  */
ice_sched_replay_agg_vsi_preinit(struct ice_hw * hw)4259b126bd6bSKiran Patil void ice_sched_replay_agg_vsi_preinit(struct ice_hw *hw)
4260b126bd6bSKiran Patil {
4261b126bd6bSKiran Patil 	struct ice_port_info *pi = hw->port_info;
4262b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
4263b126bd6bSKiran Patil 
4264b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
4265b126bd6bSKiran Patil 	list_for_each_entry(agg_info, &hw->agg_list, list_entry) {
4266b126bd6bSKiran Patil 		struct ice_sched_agg_vsi_info *agg_vsi_info;
4267b126bd6bSKiran Patil 
4268b126bd6bSKiran Patil 		agg_info->tc_bitmap[0] = 0;
4269b126bd6bSKiran Patil 		list_for_each_entry(agg_vsi_info, &agg_info->agg_vsi_list,
4270b126bd6bSKiran Patil 				    list_entry)
4271b126bd6bSKiran Patil 			agg_vsi_info->tc_bitmap[0] = 0;
4272b126bd6bSKiran Patil 	}
4273b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
4274b126bd6bSKiran Patil }
4275b126bd6bSKiran Patil 
4276b126bd6bSKiran Patil /**
4277b126bd6bSKiran Patil  * ice_sched_replay_vsi_agg - replay aggregator & VSI to aggregator node(s)
4278b126bd6bSKiran Patil  * @hw: pointer to the HW struct
4279b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
4280b126bd6bSKiran Patil  *
4281b126bd6bSKiran Patil  * This function replays aggregator node, VSI to aggregator type nodes, and
4282b126bd6bSKiran Patil  * their node bandwidth information. This function needs to be called with
4283b126bd6bSKiran Patil  * scheduler lock held.
4284b126bd6bSKiran Patil  */
ice_sched_replay_vsi_agg(struct ice_hw * hw,u16 vsi_handle)42855518ac2aSTony Nguyen static int ice_sched_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle)
4286b126bd6bSKiran Patil {
4287b126bd6bSKiran Patil 	DECLARE_BITMAP(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
4288b126bd6bSKiran Patil 	struct ice_sched_agg_vsi_info *agg_vsi_info;
4289b126bd6bSKiran Patil 	struct ice_port_info *pi = hw->port_info;
4290b126bd6bSKiran Patil 	struct ice_sched_agg_info *agg_info;
42915e24d598STony Nguyen 	int status;
4292b126bd6bSKiran Patil 
4293b126bd6bSKiran Patil 	bitmap_zero(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
4294b126bd6bSKiran Patil 	if (!ice_is_vsi_valid(hw, vsi_handle))
4295d54699e2STony Nguyen 		return -EINVAL;
4296b126bd6bSKiran Patil 	agg_info = ice_get_vsi_agg_info(hw, vsi_handle);
4297b126bd6bSKiran Patil 	if (!agg_info)
4298b126bd6bSKiran Patil 		return 0; /* Not present in list - default Agg case */
4299b126bd6bSKiran Patil 	agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
4300b126bd6bSKiran Patil 	if (!agg_vsi_info)
4301b126bd6bSKiran Patil 		return 0; /* Not present in list - default Agg case */
4302b126bd6bSKiran Patil 	ice_sched_get_ena_tc_bitmap(pi, agg_info->replay_tc_bitmap,
4303b126bd6bSKiran Patil 				    replay_bitmap);
4304b126bd6bSKiran Patil 	/* Replay aggregator node associated to vsi_handle */
4305b126bd6bSKiran Patil 	status = ice_sched_cfg_agg(hw->port_info, agg_info->agg_id,
4306b126bd6bSKiran Patil 				   ICE_AGG_TYPE_AGG, replay_bitmap);
4307b126bd6bSKiran Patil 	if (status)
4308b126bd6bSKiran Patil 		return status;
4309b126bd6bSKiran Patil 
4310b126bd6bSKiran Patil 	bitmap_zero(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
4311b126bd6bSKiran Patil 	ice_sched_get_ena_tc_bitmap(pi, agg_vsi_info->replay_tc_bitmap,
4312b126bd6bSKiran Patil 				    replay_bitmap);
4313b126bd6bSKiran Patil 	/* Move this VSI (vsi_handle) to above aggregator */
4314b126bd6bSKiran Patil 	return ice_sched_assoc_vsi_to_agg(pi, agg_info->agg_id, vsi_handle,
4315b126bd6bSKiran Patil 					  replay_bitmap);
4316b126bd6bSKiran Patil }
4317b126bd6bSKiran Patil 
4318b126bd6bSKiran Patil /**
4319b126bd6bSKiran Patil  * ice_replay_vsi_agg - replay VSI to aggregator node
4320b126bd6bSKiran Patil  * @hw: pointer to the HW struct
4321b126bd6bSKiran Patil  * @vsi_handle: software VSI handle
4322b126bd6bSKiran Patil  *
4323b126bd6bSKiran Patil  * This function replays association of VSI to aggregator type nodes, and
4324b126bd6bSKiran Patil  * node bandwidth information.
4325b126bd6bSKiran Patil  */
ice_replay_vsi_agg(struct ice_hw * hw,u16 vsi_handle)43265e24d598STony Nguyen int ice_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle)
4327b126bd6bSKiran Patil {
4328b126bd6bSKiran Patil 	struct ice_port_info *pi = hw->port_info;
43295e24d598STony Nguyen 	int status;
4330b126bd6bSKiran Patil 
4331b126bd6bSKiran Patil 	mutex_lock(&pi->sched_lock);
4332b126bd6bSKiran Patil 	status = ice_sched_replay_vsi_agg(hw, vsi_handle);
4333b126bd6bSKiran Patil 	mutex_unlock(&pi->sched_lock);
4334b126bd6bSKiran Patil 	return status;
4335b126bd6bSKiran Patil }
4336b126bd6bSKiran Patil 
4337b126bd6bSKiran Patil /**
43381ddef455SUsha Ketineni  * ice_sched_replay_q_bw - replay queue type node BW
43391ddef455SUsha Ketineni  * @pi: port information structure
43401ddef455SUsha Ketineni  * @q_ctx: queue context structure
43411ddef455SUsha Ketineni  *
43421ddef455SUsha Ketineni  * This function replays queue type node bandwidth. This function needs to be
43431ddef455SUsha Ketineni  * called with scheduler lock held.
43441ddef455SUsha Ketineni  */
ice_sched_replay_q_bw(struct ice_port_info * pi,struct ice_q_ctx * q_ctx)43455518ac2aSTony Nguyen int ice_sched_replay_q_bw(struct ice_port_info *pi, struct ice_q_ctx *q_ctx)
43461ddef455SUsha Ketineni {
43471ddef455SUsha Ketineni 	struct ice_sched_node *q_node;
43481ddef455SUsha Ketineni 
43491ddef455SUsha Ketineni 	/* Following also checks the presence of node in tree */
43501ddef455SUsha Ketineni 	q_node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid);
43511ddef455SUsha Ketineni 	if (!q_node)
4352d54699e2STony Nguyen 		return -EINVAL;
43531ddef455SUsha Ketineni 	return ice_sched_replay_node_bw(pi->hw, q_node, &q_ctx->bw_t_info);
43541ddef455SUsha Ketineni }
4355