Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2001-2023 Intel Corporation
3 : : */
4 : :
5 : : #include "ice_sched.h"
6 : :
7 : : /**
8 : : * ice_sched_add_root_node - Insert the Tx scheduler root node in SW DB
9 : : * @pi: port information structure
10 : : * @info: Scheduler element information from firmware
11 : : *
12 : : * This function inserts the root node of the scheduling tree topology
13 : : * to the SW DB.
14 : : */
15 : : static int
16 : 0 : ice_sched_add_root_node(struct ice_port_info *pi,
17 : : struct ice_aqc_txsched_elem_data *info)
18 : : {
19 : : struct ice_sched_node *root;
20 : : struct ice_hw *hw;
21 : :
22 [ # # ]: 0 : if (!pi)
23 : : return ICE_ERR_PARAM;
24 : :
25 : 0 : hw = pi->hw;
26 : :
27 : 0 : root = (struct ice_sched_node *)ice_malloc(hw, sizeof(*root));
28 [ # # ]: 0 : if (!root)
29 : : return ICE_ERR_NO_MEMORY;
30 : :
31 : 0 : root->children = (struct ice_sched_node **)
32 : 0 : ice_calloc(hw, hw->max_children[0], sizeof(*root->children));
33 [ # # ]: 0 : if (!root->children) {
34 : 0 : ice_free(hw, root);
35 : 0 : return ICE_ERR_NO_MEMORY;
36 : : }
37 : :
38 [ # # ]: 0 : ice_memcpy(&root->info, info, sizeof(*info), ICE_NONDMA_TO_NONDMA);
39 : 0 : pi->root = root;
40 : 0 : return 0;
41 : : }
42 : :
43 : : /**
44 : : * ice_sched_find_node_by_teid - Find the Tx scheduler node in SW DB
45 : : * @start_node: pointer to the starting ice_sched_node struct in a sub-tree
46 : : * @teid: node TEID to search
47 : : *
48 : : * This function searches for a node matching the TEID in the scheduling tree
49 : : * from the SW DB. The search is recursive and is restricted by the number of
50 : : * layers it has searched through; stopping at the max supported layer.
51 : : *
52 : : * This function needs to be called when holding the port_info->sched_lock
53 : : */
54 : : struct ice_sched_node *
55 : 0 : ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid)
56 : : {
57 : : u16 i;
58 : :
59 [ # # ]: 0 : if (!start_node)
60 : : return NULL;
61 : :
62 : : /* The TEID is same as that of the start_node */
63 [ # # ]: 0 : if (ICE_TXSCHED_GET_NODE_TEID(start_node) == teid)
64 : : return start_node;
65 : :
66 : : /* The node has no children or is at the max layer */
67 [ # # ]: 0 : if (!start_node->num_children ||
68 [ # # ]: 0 : start_node->tx_sched_layer >= ICE_AQC_TOPO_MAX_LEVEL_NUM ||
69 [ # # ]: 0 : start_node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF)
70 : : return NULL;
71 : :
72 : : /* Check if TEID matches to any of the children nodes */
73 [ # # ]: 0 : for (i = 0; i < start_node->num_children; i++)
74 [ # # ]: 0 : if (ICE_TXSCHED_GET_NODE_TEID(start_node->children[i]) == teid)
75 : 0 : return start_node->children[i];
76 : :
77 : : /* Search within each child's sub-tree */
78 [ # # ]: 0 : for (i = 0; i < start_node->num_children; i++) {
79 : : struct ice_sched_node *tmp;
80 : :
81 : 0 : tmp = ice_sched_find_node_by_teid(start_node->children[i],
82 : : teid);
83 [ # # ]: 0 : if (tmp)
84 : 0 : return tmp;
85 : : }
86 : :
87 : : return NULL;
88 : : }
89 : :
90 : : /**
91 : : * ice_aqc_send_sched_elem_cmd - send scheduling elements cmd
92 : : * @hw: pointer to the HW struct
93 : : * @cmd_opc: cmd opcode
94 : : * @elems_req: number of elements to request
95 : : * @buf: pointer to buffer
96 : : * @buf_size: buffer size in bytes
97 : : * @elems_resp: returns total number of elements response
98 : : * @cd: pointer to command details structure or NULL
99 : : *
100 : : * This function sends a scheduling elements cmd (cmd_opc)
101 : : */
102 : : static int
103 : 0 : ice_aqc_send_sched_elem_cmd(struct ice_hw *hw, enum ice_adminq_opc cmd_opc,
104 : : u16 elems_req, void *buf, u16 buf_size,
105 : : u16 *elems_resp, struct ice_sq_cd *cd)
106 : : {
107 : : struct ice_aqc_sched_elem_cmd *cmd;
108 : : struct ice_aq_desc desc;
109 : : int status;
110 : :
111 : : cmd = &desc.params.sched_elem_cmd;
112 : 0 : ice_fill_dflt_direct_cmd_desc(&desc, cmd_opc);
113 : 0 : cmd->num_elem_req = CPU_TO_LE16(elems_req);
114 : 0 : desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
115 : 0 : status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
116 [ # # ]: 0 : if (!status && elems_resp)
117 : 0 : *elems_resp = LE16_TO_CPU(cmd->num_elem_resp);
118 : :
119 : 0 : return status;
120 : : }
121 : :
122 : : /**
123 : : * ice_aq_query_sched_elems - query scheduler elements
124 : : * @hw: pointer to the HW struct
125 : : * @elems_req: number of elements to query
126 : : * @buf: pointer to buffer
127 : : * @buf_size: buffer size in bytes
128 : : * @elems_ret: returns total number of elements returned
129 : : * @cd: pointer to command details structure or NULL
130 : : *
131 : : * Query scheduling elements (0x0404)
132 : : */
133 : : int
134 : 0 : ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req,
135 : : struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
136 : : u16 *elems_ret, struct ice_sq_cd *cd)
137 : : {
138 : 0 : return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_get_sched_elems,
139 : : elems_req, (void *)buf, buf_size,
140 : : elems_ret, cd);
141 : : }
142 : :
143 : : /**
144 : : * ice_sched_add_node - Insert the Tx scheduler node in SW DB
145 : : * @pi: port information structure
146 : : * @layer: Scheduler layer of the node
147 : : * @info: Scheduler element information from firmware
148 : : * @prealloc_node: preallocated ice_sched_node struct for SW DB
149 : : *
150 : : * This function inserts a scheduler node to the SW DB.
151 : : */
152 : : int
153 : 0 : ice_sched_add_node(struct ice_port_info *pi, u8 layer,
154 : : struct ice_aqc_txsched_elem_data *info,
155 : : struct ice_sched_node *prealloc_node)
156 : : {
157 : : struct ice_aqc_txsched_elem_data elem;
158 : : struct ice_sched_node *parent;
159 : : struct ice_sched_node *node;
160 : : struct ice_hw *hw;
161 : : int status;
162 : :
163 [ # # ]: 0 : if (!pi)
164 : : return ICE_ERR_PARAM;
165 : :
166 : 0 : hw = pi->hw;
167 : :
168 : : /* A valid parent node should be there */
169 : 0 : parent = ice_sched_find_node_by_teid(pi->root,
170 : : LE32_TO_CPU(info->parent_teid));
171 [ # # ]: 0 : if (!parent) {
172 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "Parent Node not found for parent_teid=0x%x\n",
173 : : LE32_TO_CPU(info->parent_teid));
174 : 0 : return ICE_ERR_PARAM;
175 : : }
176 : :
177 : : /* query the current node information from FW before adding it
178 : : * to the SW DB
179 : : */
180 : 0 : status = ice_sched_query_elem(hw, LE32_TO_CPU(info->node_teid), &elem);
181 [ # # ]: 0 : if (status)
182 : : return status;
183 : :
184 [ # # ]: 0 : if (prealloc_node)
185 : : node = prealloc_node;
186 : : else
187 : 0 : node = (struct ice_sched_node *)ice_malloc(hw, sizeof(*node));
188 [ # # ]: 0 : if (!node)
189 : : return ICE_ERR_NO_MEMORY;
190 [ # # ]: 0 : if (hw->max_children[layer]) {
191 : 0 : node->children = (struct ice_sched_node **)
192 : 0 : ice_calloc(hw, hw->max_children[layer],
193 : : sizeof(*node->children));
194 [ # # ]: 0 : if (!node->children) {
195 : 0 : ice_free(hw, node);
196 : 0 : return ICE_ERR_NO_MEMORY;
197 : : }
198 : : }
199 : :
200 : 0 : node->in_use = true;
201 : 0 : node->parent = parent;
202 : 0 : node->tx_sched_layer = layer;
203 : 0 : node->vsi_handle = parent->vsi_handle;
204 : 0 : parent->children[parent->num_children++] = node;
205 : 0 : node->info = elem;
206 : 0 : return 0;
207 : : }
208 : :
209 : : /**
210 : : * ice_aq_delete_sched_elems - delete scheduler elements
211 : : * @hw: pointer to the HW struct
212 : : * @grps_req: number of groups to delete
213 : : * @buf: pointer to buffer
214 : : * @buf_size: buffer size in bytes
215 : : * @grps_del: returns total number of elements deleted
216 : : * @cd: pointer to command details structure or NULL
217 : : *
218 : : * Delete scheduling elements (0x040F)
219 : : */
220 : : static int
221 : : ice_aq_delete_sched_elems(struct ice_hw *hw, u16 grps_req,
222 : : struct ice_aqc_delete_elem *buf, u16 buf_size,
223 : : u16 *grps_del, struct ice_sq_cd *cd)
224 : : {
225 : 0 : return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_delete_sched_elems,
226 : : grps_req, (void *)buf, buf_size,
227 : : grps_del, cd);
228 : : }
229 : :
230 : : /**
231 : : * ice_sched_remove_elems - remove nodes from HW
232 : : * @hw: pointer to the HW struct
233 : : * @parent: pointer to the parent node
234 : : * @num_nodes: number of nodes
235 : : * @node_teids: array of node teids to be deleted
236 : : *
237 : : * This function remove nodes from HW
238 : : */
239 : : static int
240 : 0 : ice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent,
241 : : u16 num_nodes, u32 *node_teids)
242 : : {
243 : : struct ice_aqc_delete_elem *buf;
244 : 0 : u16 i, num_groups_removed = 0;
245 : : u16 buf_size;
246 : : int status;
247 : :
248 : 0 : buf_size = ice_struct_size(buf, teid, num_nodes);
249 : 0 : buf = (struct ice_aqc_delete_elem *)ice_malloc(hw, buf_size);
250 [ # # ]: 0 : if (!buf)
251 : : return ICE_ERR_NO_MEMORY;
252 : :
253 : 0 : buf->hdr.parent_teid = parent->info.node_teid;
254 : 0 : buf->hdr.num_elems = CPU_TO_LE16(num_nodes);
255 [ # # ]: 0 : for (i = 0; i < num_nodes; i++)
256 : 0 : buf->teid[i] = CPU_TO_LE32(node_teids[i]);
257 : :
258 : 0 : status = ice_aq_delete_sched_elems(hw, 1, buf, buf_size,
259 : : &num_groups_removed, NULL);
260 [ # # # # ]: 0 : if (status || num_groups_removed != 1)
261 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "remove node failed FW error %d\n",
262 : : hw->adminq.sq_last_status);
263 : :
264 : 0 : ice_free(hw, buf);
265 : 0 : return status;
266 : : }
267 : :
268 : : /**
269 : : * ice_sched_get_first_node - get the first node of the given layer
270 : : * @pi: port information structure
271 : : * @parent: pointer the base node of the subtree
272 : : * @layer: layer number
273 : : *
274 : : * This function retrieves the first node of the given layer from the subtree
275 : : */
276 : : static struct ice_sched_node *
277 : : ice_sched_get_first_node(struct ice_port_info *pi,
278 : : struct ice_sched_node *parent, u8 layer)
279 : : {
280 : 0 : return pi->sib_head[parent->tc_num][layer];
281 : : }
282 : :
283 : : /**
284 : : * ice_sched_get_tc_node - get pointer to TC node
285 : : * @pi: port information structure
286 : : * @tc: TC number
287 : : *
288 : : * This function returns the TC node pointer
289 : : */
290 : 0 : struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc)
291 : : {
292 : : u16 i;
293 : :
294 [ # # # # ]: 0 : if (!pi || !pi->root)
295 : : return NULL;
296 : : /* if no TC nodes, use root as TC node 0 */
297 [ # # ]: 0 : if (!pi->has_tc)
298 [ # # ]: 0 : return tc == 0 ? pi->root : NULL;
299 : :
300 [ # # ]: 0 : for (i = 0; i < pi->root->num_children; i++)
301 [ # # ]: 0 : if (pi->root->children[i]->tc_num == tc)
302 : 0 : return pi->root->children[i];
303 : : return NULL;
304 : : }
305 : :
306 : : /**
307 : : * ice_free_sched_node - Free a Tx scheduler node from SW DB
308 : : * @pi: port information structure
309 : : * @node: pointer to the ice_sched_node struct
310 : : *
311 : : * This function frees up a node from SW DB as well as from HW
312 : : *
313 : : * This function needs to be called with the port_info->sched_lock held
314 : : */
315 : 0 : void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)
316 : : {
317 : : struct ice_sched_node *parent;
318 : 0 : struct ice_hw *hw = pi->hw;
319 : : u16 i, j;
320 : :
321 : : /* Free the children before freeing up the parent node
322 : : * The parent array is updated below and that shifts the nodes
323 : : * in the array. So always pick the first child if num children > 0
324 : : */
325 [ # # ]: 0 : while (node->num_children)
326 : 0 : ice_free_sched_node(pi, node->children[0]);
327 : :
328 : : /* Leaf, TC and root nodes can't be deleted by SW */
329 [ # # ]: 0 : if (node->tx_sched_layer >= hw->sw_entry_point_layer &&
330 [ # # # # ]: 0 : node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
331 [ # # ]: 0 : node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT &&
332 : : node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) {
333 : 0 : u32 teid = LE32_TO_CPU(node->info.node_teid);
334 : :
335 : 0 : ice_sched_remove_elems(hw, node->parent, 1, &teid);
336 : : }
337 : 0 : parent = node->parent;
338 : : /* root has no parent */
339 [ # # ]: 0 : if (parent) {
340 : : struct ice_sched_node *p;
341 : :
342 : : /* update the parent */
343 [ # # ]: 0 : for (i = 0; i < parent->num_children; i++)
344 [ # # ]: 0 : if (parent->children[i] == node) {
345 [ # # ]: 0 : for (j = i + 1; j < parent->num_children; j++)
346 : 0 : parent->children[j - 1] =
347 : 0 : parent->children[j];
348 : 0 : parent->num_children--;
349 : 0 : break;
350 : : }
351 : :
352 : 0 : p = ice_sched_get_first_node(pi, node, node->tx_sched_layer);
353 [ # # ]: 0 : while (p) {
354 [ # # ]: 0 : if (p->sibling == node) {
355 : 0 : p->sibling = node->sibling;
356 : 0 : break;
357 : : }
358 : : p = p->sibling;
359 : : }
360 : :
361 : : /* update the sibling head if head is getting removed */
362 [ # # ]: 0 : if (pi->sib_head[node->tc_num][node->tx_sched_layer] == node)
363 : 0 : pi->sib_head[node->tc_num][node->tx_sched_layer] =
364 : 0 : node->sibling;
365 : : }
366 : :
367 : : /* leaf nodes have no children */
368 [ # # ]: 0 : if (node->children)
369 : 0 : ice_free(hw, node->children);
370 : 0 : ice_free(hw, node);
371 : 0 : }
372 : :
373 : : /**
374 : : * ice_aq_get_dflt_topo - gets default scheduler topology
375 : : * @hw: pointer to the HW struct
376 : : * @lport: logical port number
377 : : * @buf: pointer to buffer
378 : : * @buf_size: buffer size in bytes
379 : : * @num_branches: returns total number of queue to port branches
380 : : * @cd: pointer to command details structure or NULL
381 : : *
382 : : * Get default scheduler topology (0x400)
383 : : */
384 : : static int
385 : 0 : ice_aq_get_dflt_topo(struct ice_hw *hw, u8 lport,
386 : : struct ice_aqc_get_topo_elem *buf, u16 buf_size,
387 : : u8 *num_branches, struct ice_sq_cd *cd)
388 : : {
389 : : struct ice_aqc_get_topo *cmd;
390 : : struct ice_aq_desc desc;
391 : : int status;
392 : :
393 : : cmd = &desc.params.get_topo;
394 : 0 : ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_dflt_topo);
395 : 0 : cmd->port_num = lport;
396 : 0 : status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
397 [ # # ]: 0 : if (!status && num_branches)
398 : 0 : *num_branches = cmd->num_branches;
399 : :
400 : 0 : return status;
401 : : }
402 : :
403 : : /**
404 : : * ice_aq_add_sched_elems - adds scheduling element
405 : : * @hw: pointer to the HW struct
406 : : * @grps_req: the number of groups that are requested to be added
407 : : * @buf: pointer to buffer
408 : : * @buf_size: buffer size in bytes
409 : : * @grps_added: returns total number of groups added
410 : : * @cd: pointer to command details structure or NULL
411 : : *
412 : : * Add scheduling elements (0x0401)
413 : : */
414 : : static int
415 : : ice_aq_add_sched_elems(struct ice_hw *hw, u16 grps_req,
416 : : struct ice_aqc_add_elem *buf, u16 buf_size,
417 : : u16 *grps_added, struct ice_sq_cd *cd)
418 : : {
419 : 0 : return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_add_sched_elems,
420 : : grps_req, (void *)buf, buf_size,
421 : : grps_added, cd);
422 : : }
423 : :
424 : : /**
425 : : * ice_aq_cfg_sched_elems - configures scheduler elements
426 : : * @hw: pointer to the HW struct
427 : : * @elems_req: number of elements to configure
428 : : * @buf: pointer to buffer
429 : : * @buf_size: buffer size in bytes
430 : : * @elems_cfgd: returns total number of elements configured
431 : : * @cd: pointer to command details structure or NULL
432 : : *
433 : : * Configure scheduling elements (0x0403)
434 : : */
435 : : static int
436 : : ice_aq_cfg_sched_elems(struct ice_hw *hw, u16 elems_req,
437 : : struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
438 : : u16 *elems_cfgd, struct ice_sq_cd *cd)
439 : : {
440 : 0 : return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_cfg_sched_elems,
441 : : elems_req, (void *)buf, buf_size,
442 : : elems_cfgd, cd);
443 : : }
444 : :
445 : : /**
446 : : * ice_aq_move_sched_elems - move scheduler elements
447 : : * @hw: pointer to the HW struct
448 : : * @grps_req: number of groups to move
449 : : * @buf: pointer to buffer
450 : : * @buf_size: buffer size in bytes
451 : : * @grps_movd: returns total number of groups moved
452 : : * @cd: pointer to command details structure or NULL
453 : : *
454 : : * Move scheduling elements (0x0408)
455 : : */
456 : : int
457 : 0 : ice_aq_move_sched_elems(struct ice_hw *hw, u16 grps_req,
458 : : struct ice_aqc_move_elem *buf, u16 buf_size,
459 : : u16 *grps_movd, struct ice_sq_cd *cd)
460 : : {
461 : 0 : return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_move_sched_elems,
462 : : grps_req, (void *)buf, buf_size,
463 : : grps_movd, cd);
464 : : }
465 : :
466 : : /**
467 : : * ice_aq_suspend_sched_elems - suspend scheduler elements
468 : : * @hw: pointer to the HW struct
469 : : * @elems_req: number of elements to suspend
470 : : * @buf: pointer to buffer
471 : : * @buf_size: buffer size in bytes
472 : : * @elems_ret: returns total number of elements suspended
473 : : * @cd: pointer to command details structure or NULL
474 : : *
475 : : * Suspend scheduling elements (0x0409)
476 : : */
477 : : static int
478 : : ice_aq_suspend_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf,
479 : : u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)
480 : : {
481 : 0 : return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_suspend_sched_elems,
482 : : elems_req, (void *)buf, buf_size,
483 : : elems_ret, cd);
484 : : }
485 : :
486 : : /**
487 : : * ice_aq_resume_sched_elems - resume scheduler elements
488 : : * @hw: pointer to the HW struct
489 : : * @elems_req: number of elements to resume
490 : : * @buf: pointer to buffer
491 : : * @buf_size: buffer size in bytes
492 : : * @elems_ret: returns total number of elements resumed
493 : : * @cd: pointer to command details structure or NULL
494 : : *
495 : : * resume scheduling elements (0x040A)
496 : : */
497 : : static int
498 : : ice_aq_resume_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf,
499 : : u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd)
500 : : {
501 : 0 : return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_resume_sched_elems,
502 : : elems_req, (void *)buf, buf_size,
503 : : elems_ret, cd);
504 : : }
505 : :
506 : : /**
507 : : * ice_aq_query_sched_res - query scheduler resource
508 : : * @hw: pointer to the HW struct
509 : : * @buf_size: buffer size in bytes
510 : : * @buf: pointer to buffer
511 : : * @cd: pointer to command details structure or NULL
512 : : *
513 : : * Query scheduler resource allocation (0x0412)
514 : : */
515 : : static int
516 : : ice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size,
517 : : struct ice_aqc_query_txsched_res_resp *buf,
518 : : struct ice_sq_cd *cd)
519 : : {
520 : : struct ice_aq_desc desc;
521 : :
522 : 0 : ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_sched_res);
523 : 0 : return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
524 : : }
525 : :
526 : : /**
527 : : * ice_sched_suspend_resume_elems - suspend or resume HW nodes
528 : : * @hw: pointer to the HW struct
529 : : * @num_nodes: number of nodes
530 : : * @node_teids: array of node teids to be suspended or resumed
531 : : * @suspend: true means suspend / false means resume
532 : : *
533 : : * This function suspends or resumes HW nodes
534 : : */
535 : : static int
536 : 0 : ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids,
537 : : bool suspend)
538 : : {
539 : 0 : u16 i, buf_size, num_elem_ret = 0;
540 : : __le32 *buf;
541 : : int status;
542 : :
543 : 0 : buf_size = sizeof(*buf) * num_nodes;
544 : 0 : buf = (__le32 *)ice_malloc(hw, buf_size);
545 [ # # ]: 0 : if (!buf)
546 : : return ICE_ERR_NO_MEMORY;
547 : :
548 [ # # ]: 0 : for (i = 0; i < num_nodes; i++)
549 : 0 : buf[i] = CPU_TO_LE32(node_teids[i]);
550 : :
551 [ # # ]: 0 : if (suspend)
552 : 0 : status = ice_aq_suspend_sched_elems(hw, num_nodes, buf,
553 : : buf_size, &num_elem_ret,
554 : : NULL);
555 : : else
556 : 0 : status = ice_aq_resume_sched_elems(hw, num_nodes, buf,
557 : : buf_size, &num_elem_ret,
558 : : NULL);
559 [ # # # # ]: 0 : if (status || num_elem_ret != num_nodes)
560 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "suspend/resume failed\n");
561 : :
562 : 0 : ice_free(hw, buf);
563 : 0 : return status;
564 : : }
565 : :
566 : : /**
567 : : * ice_alloc_lan_q_ctx - allocate LAN queue contexts for the given VSI and TC
568 : : * @hw: pointer to the HW struct
569 : : * @vsi_handle: VSI handle
570 : : * @tc: TC number
571 : : * @new_numqs: number of queues
572 : : */
573 : : int
574 : 0 : ice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs)
575 : : {
576 : : struct ice_vsi_ctx *vsi_ctx;
577 : : struct ice_q_ctx *q_ctx;
578 : :
579 : 0 : vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
580 [ # # ]: 0 : if (!vsi_ctx)
581 : : return ICE_ERR_PARAM;
582 : : /* allocate LAN queue contexts */
583 [ # # ]: 0 : if (!vsi_ctx->lan_q_ctx[tc]) {
584 : 0 : vsi_ctx->lan_q_ctx[tc] = (struct ice_q_ctx *)
585 : 0 : ice_calloc(hw, new_numqs, sizeof(*q_ctx));
586 [ # # ]: 0 : if (!vsi_ctx->lan_q_ctx[tc])
587 : : return ICE_ERR_NO_MEMORY;
588 : 0 : vsi_ctx->num_lan_q_entries[tc] = new_numqs;
589 : 0 : return 0;
590 : : }
591 : : /* num queues are increased, update the queue contexts */
592 [ # # ]: 0 : if (new_numqs > vsi_ctx->num_lan_q_entries[tc]) {
593 : : u16 prev_num = vsi_ctx->num_lan_q_entries[tc];
594 : :
595 : : q_ctx = (struct ice_q_ctx *)
596 : 0 : ice_calloc(hw, new_numqs, sizeof(*q_ctx));
597 [ # # ]: 0 : if (!q_ctx)
598 : : return ICE_ERR_NO_MEMORY;
599 [ # # ]: 0 : ice_memcpy(q_ctx, vsi_ctx->lan_q_ctx[tc],
600 : : prev_num * sizeof(*q_ctx), ICE_DMA_TO_NONDMA);
601 : 0 : ice_free(hw, vsi_ctx->lan_q_ctx[tc]);
602 : 0 : vsi_ctx->lan_q_ctx[tc] = q_ctx;
603 : 0 : vsi_ctx->num_lan_q_entries[tc] = new_numqs;
604 : : }
605 : : return 0;
606 : : }
607 : :
608 : : /**
609 : : * ice_aq_rl_profile - performs a rate limiting task
610 : : * @hw: pointer to the HW struct
611 : : * @opcode: opcode for add, query, or remove profile(s)
612 : : * @num_profiles: the number of profiles
613 : : * @buf: pointer to buffer
614 : : * @buf_size: buffer size in bytes
615 : : * @num_processed: number of processed add or remove profile(s) to return
616 : : * @cd: pointer to command details structure
617 : : *
618 : : * RL profile function to add, query, or remove profile(s)
619 : : */
620 : : static int
621 : 0 : ice_aq_rl_profile(struct ice_hw *hw, enum ice_adminq_opc opcode,
622 : : u16 num_profiles, struct ice_aqc_rl_profile_elem *buf,
623 : : u16 buf_size, u16 *num_processed, struct ice_sq_cd *cd)
624 : : {
625 : : struct ice_aqc_rl_profile *cmd;
626 : : struct ice_aq_desc desc;
627 : : int status;
628 : :
629 : : cmd = &desc.params.rl_profile;
630 : :
631 : 0 : ice_fill_dflt_direct_cmd_desc(&desc, opcode);
632 : 0 : desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
633 : 0 : cmd->num_profiles = CPU_TO_LE16(num_profiles);
634 : 0 : status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
635 [ # # ]: 0 : if (!status && num_processed)
636 : 0 : *num_processed = LE16_TO_CPU(cmd->num_processed);
637 : 0 : return status;
638 : : }
639 : :
640 : : /**
641 : : * ice_aq_add_rl_profile - adds rate limiting profile(s)
642 : : * @hw: pointer to the HW struct
643 : : * @num_profiles: the number of profile(s) to be add
644 : : * @buf: pointer to buffer
645 : : * @buf_size: buffer size in bytes
646 : : * @num_profiles_added: total number of profiles added to return
647 : : * @cd: pointer to command details structure
648 : : *
649 : : * Add RL profile (0x0410)
650 : : */
651 : : static int
652 : : ice_aq_add_rl_profile(struct ice_hw *hw, u16 num_profiles,
653 : : struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
654 : : u16 *num_profiles_added, struct ice_sq_cd *cd)
655 : : {
656 : 0 : return ice_aq_rl_profile(hw, ice_aqc_opc_add_rl_profiles, num_profiles,
657 : : buf, buf_size, num_profiles_added, cd);
658 : : }
659 : :
660 : : /**
661 : : * ice_aq_query_rl_profile - query rate limiting profile(s)
662 : : * @hw: pointer to the HW struct
663 : : * @num_profiles: the number of profile(s) to query
664 : : * @buf: pointer to buffer
665 : : * @buf_size: buffer size in bytes
666 : : * @cd: pointer to command details structure
667 : : *
668 : : * Query RL profile (0x0411)
669 : : */
670 : : int
671 : 0 : ice_aq_query_rl_profile(struct ice_hw *hw, u16 num_profiles,
672 : : struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
673 : : struct ice_sq_cd *cd)
674 : : {
675 : 0 : return ice_aq_rl_profile(hw, ice_aqc_opc_query_rl_profiles,
676 : : num_profiles, buf, buf_size, NULL, cd);
677 : : }
678 : :
679 : : /**
680 : : * ice_aq_remove_rl_profile - removes RL profile(s)
681 : : * @hw: pointer to the HW struct
682 : : * @num_profiles: the number of profile(s) to remove
683 : : * @buf: pointer to buffer
684 : : * @buf_size: buffer size in bytes
685 : : * @num_profiles_removed: total number of profiles removed to return
686 : : * @cd: pointer to command details structure or NULL
687 : : *
688 : : * Remove RL profile (0x0415)
689 : : */
690 : : static int
691 : : ice_aq_remove_rl_profile(struct ice_hw *hw, u16 num_profiles,
692 : : struct ice_aqc_rl_profile_elem *buf, u16 buf_size,
693 : : u16 *num_profiles_removed, struct ice_sq_cd *cd)
694 : : {
695 : 0 : return ice_aq_rl_profile(hw, ice_aqc_opc_remove_rl_profiles,
696 : : num_profiles, buf, buf_size,
697 : : num_profiles_removed, cd);
698 : : }
699 : :
700 : : /**
701 : : * ice_sched_del_rl_profile - remove RL profile
702 : : * @hw: pointer to the HW struct
703 : : * @rl_info: rate limit profile information
704 : : *
705 : : * If the profile ID is not referenced anymore, it removes profile ID with
706 : : * its associated parameters from HW DB,and locally. The caller needs to
707 : : * hold scheduler lock.
708 : : */
709 : : static int
710 : 0 : ice_sched_del_rl_profile(struct ice_hw *hw,
711 : : struct ice_aqc_rl_profile_info *rl_info)
712 : : {
713 : : struct ice_aqc_rl_profile_elem *buf;
714 : : u16 num_profiles_removed;
715 : : u16 num_profiles = 1;
716 : : int status;
717 : :
718 [ # # ]: 0 : if (rl_info->prof_id_ref != 0)
719 : : return ICE_ERR_IN_USE;
720 : :
721 : : /* Safe to remove profile ID */
722 : 0 : buf = &rl_info->profile;
723 : : status = ice_aq_remove_rl_profile(hw, num_profiles, buf, sizeof(*buf),
724 : : &num_profiles_removed, NULL);
725 [ # # # # ]: 0 : if (status || num_profiles_removed != num_profiles)
726 : : return ICE_ERR_CFG;
727 : :
728 : : /* Delete stale entry now */
729 [ # # ]: 0 : LIST_DEL(&rl_info->list_entry);
730 : 0 : ice_free(hw, rl_info);
731 : 0 : return status;
732 : : }
733 : :
734 : : /**
735 : : * ice_sched_clear_rl_prof - clears RL prof entries
736 : : * @pi: port information structure
737 : : *
738 : : * This function removes all RL profile from HW as well as from SW DB.
739 : : */
740 : 0 : static void ice_sched_clear_rl_prof(struct ice_port_info *pi)
741 : : {
742 : : u16 ln;
743 : 0 : struct ice_hw *hw = pi->hw;
744 : :
745 [ # # ]: 0 : for (ln = 0; ln < hw->num_tx_sched_layers; ln++) {
746 : : struct ice_aqc_rl_profile_info *rl_prof_elem;
747 : : struct ice_aqc_rl_profile_info *rl_prof_tmp;
748 : :
749 [ # # # # : 0 : LIST_FOR_EACH_ENTRY_SAFE(rl_prof_elem, rl_prof_tmp,
# # # # #
# # # ]
750 : : &hw->rl_prof_list[ln],
751 : : ice_aqc_rl_profile_info, list_entry) {
752 : : int status;
753 : :
754 : 0 : rl_prof_elem->prof_id_ref = 0;
755 : 0 : status = ice_sched_del_rl_profile(hw, rl_prof_elem);
756 [ # # ]: 0 : if (status) {
757 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "Remove rl profile failed\n");
758 : : /* On error, free mem required */
759 [ # # ]: 0 : LIST_DEL(&rl_prof_elem->list_entry);
760 : 0 : ice_free(hw, rl_prof_elem);
761 : : }
762 : : }
763 : : }
764 : 0 : }
765 : :
766 : : /**
767 : : * ice_sched_clear_agg - clears the aggregator related information
768 : : * @hw: pointer to the hardware structure
769 : : *
770 : : * This function removes aggregator list and free up aggregator related memory
771 : : * previously allocated.
772 : : */
773 : 0 : void ice_sched_clear_agg(struct ice_hw *hw)
774 : : {
775 : : struct ice_sched_agg_info *agg_info;
776 : : struct ice_sched_agg_info *atmp;
777 : :
778 [ # # # # : 0 : LIST_FOR_EACH_ENTRY_SAFE(agg_info, atmp, &hw->agg_list,
# # # # #
# # # ]
779 : : ice_sched_agg_info,
780 : : list_entry) {
781 : : struct ice_sched_agg_vsi_info *agg_vsi_info;
782 : : struct ice_sched_agg_vsi_info *vtmp;
783 : :
784 [ # # # # : 0 : LIST_FOR_EACH_ENTRY_SAFE(agg_vsi_info, vtmp,
# # # # #
# ]
785 : : &agg_info->agg_vsi_list,
786 : : ice_sched_agg_vsi_info, list_entry) {
787 [ # # ]: 0 : LIST_DEL(&agg_vsi_info->list_entry);
788 : 0 : ice_free(hw, agg_vsi_info);
789 : : }
790 [ # # ]: 0 : LIST_DEL(&agg_info->list_entry);
791 : 0 : ice_free(hw, agg_info);
792 : : }
793 : 0 : }
794 : :
795 : : /**
796 : : * ice_sched_clear_tx_topo - clears the scheduler tree nodes
797 : : * @pi: port information structure
798 : : *
799 : : * This function removes all the nodes from HW as well as from SW DB.
800 : : */
801 : 0 : static void ice_sched_clear_tx_topo(struct ice_port_info *pi)
802 : : {
803 [ # # ]: 0 : if (!pi)
804 : : return;
805 : : /* remove RL profiles related lists */
806 : 0 : ice_sched_clear_rl_prof(pi);
807 [ # # ]: 0 : if (pi->root) {
808 : 0 : ice_free_sched_node(pi, pi->root);
809 : 0 : pi->root = NULL;
810 : : }
811 : : }
812 : :
813 : : /**
814 : : * ice_sched_clear_port - clear the scheduler elements from SW DB for a port
815 : : * @pi: port information structure
816 : : *
817 : : * Cleanup scheduling elements from SW DB
818 : : */
819 : 0 : void ice_sched_clear_port(struct ice_port_info *pi)
820 : : {
821 [ # # # # ]: 0 : if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY)
822 : : return;
823 : :
824 : 0 : pi->port_state = ICE_SCHED_PORT_STATE_INIT;
825 : 0 : ice_acquire_lock(&pi->sched_lock);
826 : 0 : ice_sched_clear_tx_topo(pi);
827 : : ice_release_lock(&pi->sched_lock);
828 : : ice_destroy_lock(&pi->sched_lock);
829 : : }
830 : :
831 : : /**
832 : : * ice_sched_cleanup_all - cleanup scheduler elements from SW DB for all ports
833 : : * @hw: pointer to the HW struct
834 : : *
835 : : * Cleanup scheduling elements from SW DB for all the ports
836 : : */
837 : 0 : void ice_sched_cleanup_all(struct ice_hw *hw)
838 : : {
839 [ # # ]: 0 : if (!hw)
840 : : return;
841 : :
842 [ # # ]: 0 : if (hw->layer_info) {
843 : 0 : ice_free(hw, hw->layer_info);
844 : 0 : hw->layer_info = NULL;
845 : : }
846 : :
847 : 0 : ice_sched_clear_port(hw->port_info);
848 : :
849 : 0 : hw->num_tx_sched_layers = 0;
850 : 0 : hw->num_tx_sched_phys_layers = 0;
851 : 0 : hw->flattened_layers = 0;
852 : 0 : hw->max_cgds = 0;
853 : : }
854 : :
855 : : /**
856 : : * ice_aq_cfg_node_attr - configure nodes' per-cone flattening attributes
857 : : * @hw: pointer to the HW struct
858 : : * @num_nodes: the number of nodes whose attributes to configure
859 : : * @buf: pointer to buffer
860 : : * @buf_size: buffer size in bytes
861 : : * @cd: pointer to command details structure or NULL
862 : : *
863 : : * Configure Node Attributes (0x0417)
864 : : */
865 : : int
866 : 0 : ice_aq_cfg_node_attr(struct ice_hw *hw, u16 num_nodes,
867 : : struct ice_aqc_node_attr_elem *buf, u16 buf_size,
868 : : struct ice_sq_cd *cd)
869 : : {
870 : : struct ice_aqc_node_attr *cmd;
871 : : struct ice_aq_desc desc;
872 : :
873 : : cmd = &desc.params.node_attr;
874 : 0 : ice_fill_dflt_direct_cmd_desc(&desc,
875 : : ice_aqc_opc_cfg_node_attr);
876 : 0 : desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
877 : :
878 : 0 : cmd->num_entries = CPU_TO_LE16(num_nodes);
879 : 0 : return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
880 : : }
881 : :
882 : : /**
883 : : * ice_aq_cfg_l2_node_cgd - configures L2 node to CGD mapping
884 : : * @hw: pointer to the HW struct
885 : : * @num_l2_nodes: the number of L2 nodes whose CGDs to configure
886 : : * @buf: pointer to buffer
887 : : * @buf_size: buffer size in bytes
888 : : * @cd: pointer to command details structure or NULL
889 : : *
890 : : * Configure L2 Node CGD (0x0414)
891 : : */
892 : : int
893 : 0 : ice_aq_cfg_l2_node_cgd(struct ice_hw *hw, u16 num_l2_nodes,
894 : : struct ice_aqc_cfg_l2_node_cgd_elem *buf,
895 : : u16 buf_size, struct ice_sq_cd *cd)
896 : : {
897 : : struct ice_aqc_cfg_l2_node_cgd *cmd;
898 : : struct ice_aq_desc desc;
899 : :
900 : : cmd = &desc.params.cfg_l2_node_cgd;
901 : 0 : ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_cfg_l2_node_cgd);
902 : 0 : desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
903 : :
904 : 0 : cmd->num_l2_nodes = CPU_TO_LE16(num_l2_nodes);
905 : 0 : return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
906 : : }
907 : :
908 : : /**
909 : : * ice_sched_add_elems - add nodes to HW and SW DB
910 : : * @pi: port information structure
911 : : * @tc_node: pointer to the branch node
912 : : * @parent: pointer to the parent node
913 : : * @layer: layer number to add nodes
914 : : * @num_nodes: number of nodes
915 : : * @num_nodes_added: pointer to num nodes added
916 : : * @first_node_teid: if new nodes are added then return the TEID of first node
917 : : * @prealloc_nodes: preallocated nodes struct for software DB
918 : : *
919 : : * This function add nodes to HW as well as to SW DB for a given layer
920 : : */
921 : : int
922 : 0 : ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,
923 : : struct ice_sched_node *parent, u8 layer, u16 num_nodes,
924 : : u16 *num_nodes_added, u32 *first_node_teid,
925 : : struct ice_sched_node **prealloc_nodes)
926 : : {
927 : : struct ice_sched_node *prev, *new_node;
928 : : struct ice_aqc_add_elem *buf;
929 : 0 : u16 i, num_groups_added = 0;
930 : 0 : struct ice_hw *hw = pi->hw;
931 : : int status = 0;
932 : : u16 buf_size;
933 : : u32 teid;
934 : :
935 : 0 : buf_size = ice_struct_size(buf, generic, num_nodes);
936 : 0 : buf = (struct ice_aqc_add_elem *)ice_malloc(hw, buf_size);
937 [ # # ]: 0 : if (!buf)
938 : : return ICE_ERR_NO_MEMORY;
939 : :
940 : 0 : buf->hdr.parent_teid = parent->info.node_teid;
941 : 0 : buf->hdr.num_elems = CPU_TO_LE16(num_nodes);
942 [ # # ]: 0 : for (i = 0; i < num_nodes; i++) {
943 : 0 : buf->generic[i].parent_teid = parent->info.node_teid;
944 : 0 : buf->generic[i].data.elem_type = ICE_AQC_ELEM_TYPE_SE_GENERIC;
945 : 0 : buf->generic[i].data.valid_sections =
946 : : ICE_AQC_ELEM_VALID_GENERIC | ICE_AQC_ELEM_VALID_CIR |
947 : : ICE_AQC_ELEM_VALID_EIR;
948 : 0 : buf->generic[i].data.generic = 0;
949 : 0 : buf->generic[i].data.cir_bw.bw_profile_idx =
950 : : CPU_TO_LE16(ICE_SCHED_DFLT_RL_PROF_ID);
951 : 0 : buf->generic[i].data.cir_bw.bw_alloc =
952 : : CPU_TO_LE16(ICE_SCHED_DFLT_BW_WT);
953 : 0 : buf->generic[i].data.eir_bw.bw_profile_idx =
954 : : CPU_TO_LE16(ICE_SCHED_DFLT_RL_PROF_ID);
955 : 0 : buf->generic[i].data.eir_bw.bw_alloc =
956 : : CPU_TO_LE16(ICE_SCHED_DFLT_BW_WT);
957 : : }
958 : :
959 : 0 : status = ice_aq_add_sched_elems(hw, 1, buf, buf_size,
960 : : &num_groups_added, NULL);
961 [ # # # # ]: 0 : if (status || num_groups_added != 1) {
962 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "add node failed FW Error %d\n",
963 : : hw->adminq.sq_last_status);
964 : 0 : ice_free(hw, buf);
965 : 0 : return ICE_ERR_CFG;
966 : : }
967 : :
968 : 0 : *num_nodes_added = num_nodes;
969 : : /* add nodes to the SW DB */
970 [ # # ]: 0 : for (i = 0; i < num_nodes; i++) {
971 [ # # ]: 0 : if (prealloc_nodes)
972 : 0 : status = ice_sched_add_node(pi, layer, &buf->generic[i], prealloc_nodes[i]);
973 : : else
974 : 0 : status = ice_sched_add_node(pi, layer, &buf->generic[i], NULL);
975 : :
976 [ # # ]: 0 : if (status) {
977 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "add nodes in SW DB failed status =%d\n",
978 : : status);
979 : : break;
980 : : }
981 : :
982 : 0 : teid = LE32_TO_CPU(buf->generic[i].node_teid);
983 : 0 : new_node = ice_sched_find_node_by_teid(parent, teid);
984 [ # # ]: 0 : if (!new_node) {
985 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "Node is missing for teid =%d\n", teid);
986 : : break;
987 : : }
988 : :
989 : 0 : new_node->sibling = NULL;
990 : 0 : new_node->tc_num = tc_node->tc_num;
991 : :
992 : : /* add it to previous node sibling pointer */
993 : : /* Note: siblings are not linked across branches */
994 : 0 : prev = ice_sched_get_first_node(pi, tc_node, layer);
995 [ # # ]: 0 : if (prev && prev != new_node) {
996 [ # # ]: 0 : while (prev->sibling)
997 : : prev = prev->sibling;
998 : 0 : prev->sibling = new_node;
999 : : }
1000 : :
1001 : : /* initialize the sibling head */
1002 [ # # ]: 0 : if (!pi->sib_head[tc_node->tc_num][layer])
1003 : 0 : pi->sib_head[tc_node->tc_num][layer] = new_node;
1004 : :
1005 [ # # ]: 0 : if (i == 0)
1006 : 0 : *first_node_teid = teid;
1007 : : }
1008 : :
1009 : 0 : ice_free(hw, buf);
1010 : 0 : return status;
1011 : : }
1012 : :
1013 : : /**
1014 : : * ice_sched_add_nodes_to_hw_layer - Add nodes to hw layer
1015 : : * @pi: port information structure
1016 : : * @tc_node: pointer to TC node
1017 : : * @parent: pointer to parent node
1018 : : * @layer: layer number to add nodes
1019 : : * @num_nodes: number of nodes to be added
1020 : : * @first_node_teid: pointer to the first node TEID
1021 : : * @num_nodes_added: pointer to number of nodes added
1022 : : *
1023 : : * Add nodes into specific hw layer.
1024 : : */
1025 : : static int
1026 : 0 : ice_sched_add_nodes_to_hw_layer(struct ice_port_info *pi,
1027 : : struct ice_sched_node *tc_node,
1028 : : struct ice_sched_node *parent, u8 layer,
1029 : : u16 num_nodes, u32 *first_node_teid,
1030 : : u16 *num_nodes_added)
1031 : : {
1032 : : u16 max_child_nodes;
1033 : :
1034 : 0 : *num_nodes_added = 0;
1035 : :
1036 [ # # ]: 0 : if (!num_nodes)
1037 : : return 0;
1038 : :
1039 [ # # # # ]: 0 : if (!parent || layer < pi->hw->sw_entry_point_layer)
1040 : : return ICE_ERR_PARAM;
1041 : :
1042 : : /* max children per node per layer */
1043 : 0 : max_child_nodes = pi->hw->max_children[parent->tx_sched_layer];
1044 : :
1045 : : /* current number of children + required nodes exceed max children */
1046 [ # # ]: 0 : if ((parent->num_children + num_nodes) > max_child_nodes) {
1047 : : /* Fail if the parent is a TC node */
1048 [ # # ]: 0 : if (parent == tc_node)
1049 : : return ICE_ERR_CFG;
1050 : 0 : return ICE_ERR_MAX_LIMIT;
1051 : : }
1052 : :
1053 : 0 : return ice_sched_add_elems(pi, tc_node, parent, layer, num_nodes,
1054 : : num_nodes_added, first_node_teid, NULL);
1055 : : }
1056 : :
1057 : : /**
1058 : : * ice_sched_add_nodes_to_layer - Add nodes to a given layer
1059 : : * @pi: port information structure
1060 : : * @tc_node: pointer to TC node
1061 : : * @parent: pointer to parent node
1062 : : * @layer: layer number to add nodes
1063 : : * @num_nodes: number of nodes to be added
1064 : : * @first_node_teid: pointer to the first node TEID
1065 : : * @num_nodes_added: pointer to number of nodes added
1066 : : *
1067 : : * This function add nodes to a given layer.
1068 : : */
1069 : : static int
1070 : 0 : ice_sched_add_nodes_to_layer(struct ice_port_info *pi,
1071 : : struct ice_sched_node *tc_node,
1072 : : struct ice_sched_node *parent, u8 layer,
1073 : : u16 num_nodes, u32 *first_node_teid,
1074 : : u16 *num_nodes_added)
1075 : : {
1076 : : u32 *first_teid_ptr = first_node_teid;
1077 : : u16 new_num_nodes = num_nodes;
1078 : : int status = 0;
1079 : : u32 temp;
1080 : :
1081 : 0 : *num_nodes_added = 0;
1082 [ # # ]: 0 : while (*num_nodes_added < num_nodes) {
1083 : 0 : u16 max_child_nodes, num_added = 0;
1084 : :
1085 : 0 : status = ice_sched_add_nodes_to_hw_layer(pi, tc_node, parent,
1086 : : layer, new_num_nodes,
1087 : : first_teid_ptr,
1088 : : &num_added);
1089 [ # # ]: 0 : if (!status)
1090 : 0 : *num_nodes_added += num_added;
1091 : : /* added more nodes than requested ? */
1092 [ # # ]: 0 : if (*num_nodes_added > num_nodes) {
1093 [ # # ]: 0 : ice_debug(pi->hw, ICE_DBG_SCHED, "added extra nodes %d %d\n", num_nodes,
1094 : : *num_nodes_added);
1095 : : status = ICE_ERR_CFG;
1096 : 0 : break;
1097 : : }
1098 : : /* break if all the nodes are added successfully */
1099 [ # # # # ]: 0 : if (!status && (*num_nodes_added == num_nodes))
1100 : : break;
1101 : : /* break if the error is not max limit */
1102 [ # # ]: 0 : if (status && status != ICE_ERR_MAX_LIMIT)
1103 : : break;
1104 : : /* Exceeded the max children */
1105 : 0 : max_child_nodes = pi->hw->max_children[parent->tx_sched_layer];
1106 : : /* utilize all the spaces if the parent is not full */
1107 [ # # ]: 0 : if (parent->num_children < max_child_nodes) {
1108 : 0 : new_num_nodes = max_child_nodes - parent->num_children;
1109 : : } else {
1110 : : /* This parent is full, try the next sibling */
1111 : 0 : parent = parent->sibling;
1112 : : /* Don't modify the first node TEID memory if the
1113 : : * first node was added already in the above call.
1114 : : * Instead send some temp memory for all other
1115 : : * recursive calls.
1116 : : */
1117 [ # # ]: 0 : if (num_added)
1118 : : first_teid_ptr = &temp;
1119 : :
1120 : 0 : new_num_nodes = num_nodes - *num_nodes_added;
1121 : : }
1122 : : }
1123 : 0 : return status;
1124 : : }
1125 : :
1126 : : /**
1127 : : * ice_sched_get_qgrp_layer - get the current queue group layer number
1128 : : * @hw: pointer to the HW struct
1129 : : *
1130 : : * This function returns the current queue group layer number
1131 : : */
1132 : : static u8 ice_sched_get_qgrp_layer(struct ice_hw *hw)
1133 : : {
1134 : : /* It's always total layers - 1, the array is 0 relative so -2 */
1135 : 0 : return hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET;
1136 : : }
1137 : :
1138 : : /**
1139 : : * ice_sched_get_vsi_layer - get the current VSI layer number
1140 : : * @hw: pointer to the HW struct
1141 : : *
1142 : : * This function returns the current VSI layer number
1143 : : */
1144 : : static u8 ice_sched_get_vsi_layer(struct ice_hw *hw)
1145 : : {
1146 : : /* Num Layers VSI layer
1147 : : * 9 6
1148 : : * 7 4
1149 : : * 5 or less sw_entry_point_layer
1150 : : */
1151 : : /* calculate the VSI layer based on number of layers. */
1152 [ # # # # ]: 0 : if (hw->num_tx_sched_layers == ICE_SCHED_9_LAYERS)
1153 : : return hw->num_tx_sched_layers - ICE_VSI_LAYER_OFFSET;
1154 [ # # # # : 0 : else if (hw->num_tx_sched_layers == ICE_SCHED_5_LAYERS)
# # # # #
# # # # #
# # ]
1155 : : /* qgroup and VSI layers are same */
1156 : : return hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET;
1157 : 0 : return hw->sw_entry_point_layer;
1158 : : }
1159 : :
1160 : : /**
1161 : : * ice_sched_get_agg_layer - get the current aggregator layer number
1162 : : * @hw: pointer to the HW struct
1163 : : *
1164 : : * This function returns the current aggregator layer number
1165 : : */
1166 : : static u8 ice_sched_get_agg_layer(struct ice_hw *hw)
1167 : : {
1168 : : /* Num Layers aggregator layer
1169 : : * 9 4
1170 : : * 7 or less sw_entry_point_layer
1171 : : */
1172 : : /* calculate the aggregator layer based on number of layers. */
1173 [ # # # # : 0 : if (hw->num_tx_sched_layers == ICE_SCHED_9_LAYERS)
# # # # #
# # # # #
# # # # #
# # # ]
1174 : : return hw->num_tx_sched_layers - ICE_AGG_LAYER_OFFSET;
1175 : 0 : return hw->sw_entry_point_layer;
1176 : : }
1177 : :
1178 : : /**
1179 : : * ice_rm_dflt_leaf_node - remove the default leaf node in the tree
1180 : : * @pi: port information structure
1181 : : *
1182 : : * This function removes the leaf node that was created by the FW
1183 : : * during initialization
1184 : : */
1185 : 0 : static void ice_rm_dflt_leaf_node(struct ice_port_info *pi)
1186 : : {
1187 : : struct ice_sched_node *node;
1188 : :
1189 : 0 : node = pi->root;
1190 [ # # ]: 0 : while (node) {
1191 [ # # ]: 0 : if (!node->num_children)
1192 : : break;
1193 : 0 : node = node->children[0];
1194 : : }
1195 [ # # # # ]: 0 : if (node && node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF) {
1196 : 0 : u32 teid = LE32_TO_CPU(node->info.node_teid);
1197 : : int status;
1198 : :
1199 : : /* remove the default leaf node */
1200 : 0 : status = ice_sched_remove_elems(pi->hw, node->parent, 1, &teid);
1201 [ # # ]: 0 : if (!status)
1202 : 0 : ice_free_sched_node(pi, node);
1203 : : }
1204 : 0 : }
1205 : :
1206 : : /**
1207 : : * ice_sched_rm_dflt_nodes - free the default nodes in the tree
1208 : : * @pi: port information structure
1209 : : *
1210 : : * This function frees all the nodes except root and TC that were created by
1211 : : * the FW during initialization
1212 : : */
1213 : 0 : static void ice_sched_rm_dflt_nodes(struct ice_port_info *pi)
1214 : : {
1215 : : struct ice_sched_node *node;
1216 : :
1217 : 0 : ice_rm_dflt_leaf_node(pi);
1218 : :
1219 : : /* remove the default nodes except TC and root nodes */
1220 : 0 : node = pi->root;
1221 [ # # ]: 0 : while (node) {
1222 [ # # ]: 0 : if (node->tx_sched_layer >= pi->hw->sw_entry_point_layer &&
1223 [ # # # # ]: 0 : node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC &&
1224 : : node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT) {
1225 : 0 : ice_free_sched_node(pi, node);
1226 : 0 : break;
1227 : : }
1228 : :
1229 [ # # ]: 0 : if (!node->num_children)
1230 : : break;
1231 : 0 : node = node->children[0];
1232 : : }
1233 : 0 : }
1234 : :
1235 : : /**
1236 : : * ice_sched_init_port - Initialize scheduler by querying information from FW
1237 : : * @pi: port info structure for the tree to cleanup
1238 : : *
1239 : : * This function is the initial call to find the total number of Tx scheduler
1240 : : * resources, default topology created by firmware and storing the information
1241 : : * in SW DB.
1242 : : */
1243 : 0 : int ice_sched_init_port(struct ice_port_info *pi)
1244 : : {
1245 : : struct ice_aqc_get_topo_elem *buf;
1246 : : struct ice_hw *hw;
1247 : : u8 num_branches;
1248 : : u16 num_elems;
1249 : : int status;
1250 : : u8 i, j;
1251 : :
1252 [ # # ]: 0 : if (!pi)
1253 : : return ICE_ERR_PARAM;
1254 : 0 : hw = pi->hw;
1255 : :
1256 : : /* Query the Default Topology from FW */
1257 : 0 : buf = (struct ice_aqc_get_topo_elem *)ice_malloc(hw,
1258 : : ICE_AQ_MAX_BUF_LEN);
1259 [ # # ]: 0 : if (!buf)
1260 : : return ICE_ERR_NO_MEMORY;
1261 : :
1262 : : /* Query default scheduling tree topology */
1263 : 0 : status = ice_aq_get_dflt_topo(hw, pi->lport, buf, ICE_AQ_MAX_BUF_LEN,
1264 : : &num_branches, NULL);
1265 [ # # ]: 0 : if (status)
1266 : 0 : goto err_init_port;
1267 : :
1268 : : /* num_branches should be between 1-8 */
1269 [ # # ]: 0 : if (num_branches < 1 || num_branches > ICE_TXSCHED_MAX_BRANCHES) {
1270 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "num_branches unexpected %d\n",
1271 : : num_branches);
1272 : : status = ICE_ERR_PARAM;
1273 : 0 : goto err_init_port;
1274 : : }
1275 : :
1276 : : /* get the number of elements on the default/first branch */
1277 : 0 : num_elems = LE16_TO_CPU(buf[0].hdr.num_elems);
1278 : :
1279 : : /* num_elems should always be between 1-9 */
1280 [ # # ]: 0 : if (num_elems < 1 || num_elems > ICE_AQC_TOPO_MAX_LEVEL_NUM) {
1281 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "num_elems unexpected %d\n",
1282 : : num_elems);
1283 : : status = ICE_ERR_PARAM;
1284 : 0 : goto err_init_port;
1285 : : }
1286 : :
1287 : : /* If the last node is a leaf node then the index of the queue group
1288 : : * layer is two less than the number of elements.
1289 : : */
1290 [ # # # # ]: 0 : if (num_elems > 2 && buf[0].generic[num_elems - 1].data.elem_type ==
1291 : : ICE_AQC_ELEM_TYPE_LEAF)
1292 : 0 : pi->last_node_teid =
1293 : 0 : LE32_TO_CPU(buf[0].generic[num_elems - 2].node_teid);
1294 : : else
1295 : 0 : pi->last_node_teid =
1296 : 0 : LE32_TO_CPU(buf[0].generic[num_elems - 1].node_teid);
1297 : :
1298 : : /* Insert the Tx Sched root node */
1299 : 0 : status = ice_sched_add_root_node(pi, &buf[0].generic[0]);
1300 [ # # ]: 0 : if (status)
1301 : 0 : goto err_init_port;
1302 : :
1303 : : /* Parse the default tree and cache the information */
1304 [ # # ]: 0 : for (i = 0; i < num_branches; i++) {
1305 : 0 : num_elems = LE16_TO_CPU(buf[i].hdr.num_elems);
1306 : :
1307 : : /* Skip root element as already inserted */
1308 [ # # ]: 0 : for (j = 1; j < num_elems; j++) {
1309 : : /* update the sw entry point */
1310 [ # # ]: 0 : if (buf[0].generic[j].data.elem_type ==
1311 : : ICE_AQC_ELEM_TYPE_ENTRY_POINT)
1312 : 0 : hw->sw_entry_point_layer = j;
1313 [ # # ]: 0 : else if (buf[0].generic[j].data.elem_type ==
1314 : : ICE_AQC_ELEM_TYPE_TC)
1315 : 0 : pi->has_tc = 1;
1316 : 0 : status = ice_sched_add_node(pi, j, &buf[i].generic[j], NULL);
1317 [ # # ]: 0 : if (status)
1318 : 0 : goto err_init_port;
1319 : : }
1320 : : }
1321 : :
1322 : : /* Remove the default nodes. */
1323 [ # # ]: 0 : if (pi->root)
1324 : 0 : ice_sched_rm_dflt_nodes(pi);
1325 : :
1326 : : /* initialize the port for handling the scheduler tree */
1327 : 0 : pi->port_state = ICE_SCHED_PORT_STATE_READY;
1328 : : ice_init_lock(&pi->sched_lock);
1329 [ # # ]: 0 : for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++)
1330 : 0 : INIT_LIST_HEAD(&hw->rl_prof_list[i]);
1331 : :
1332 : 0 : err_init_port:
1333 [ # # # # ]: 0 : if (status && pi->root) {
1334 : 0 : ice_free_sched_node(pi, pi->root);
1335 : 0 : pi->root = NULL;
1336 : : }
1337 : :
1338 : 0 : ice_free(hw, buf);
1339 : 0 : return status;
1340 : : }
1341 : :
1342 : : /**
1343 : : * ice_sched_get_node - Get the struct ice_sched_node for given TEID
1344 : : * @pi: port information structure
1345 : : * @teid: Scheduler node TEID
1346 : : *
1347 : : * This function retrieves the ice_sched_node struct for given TEID from
1348 : : * the SW DB and returns it to the caller.
1349 : : */
1350 : 0 : struct ice_sched_node *ice_sched_get_node(struct ice_port_info *pi, u32 teid)
1351 : : {
1352 : : struct ice_sched_node *node;
1353 : :
1354 [ # # ]: 0 : if (!pi)
1355 : : return NULL;
1356 : :
1357 : : /* Find the node starting from root */
1358 : 0 : ice_acquire_lock(&pi->sched_lock);
1359 : 0 : node = ice_sched_find_node_by_teid(pi->root, teid);
1360 : : ice_release_lock(&pi->sched_lock);
1361 : :
1362 [ # # ]: 0 : if (!node)
1363 [ # # ]: 0 : ice_debug(pi->hw, ICE_DBG_SCHED, "Node not found for teid=0x%x\n", teid);
1364 : :
1365 : : return node;
1366 : : }
1367 : :
1368 : : /**
1369 : : * ice_sched_query_res_alloc - query the FW for num of logical sched layers
1370 : : * @hw: pointer to the HW struct
1371 : : *
1372 : : * query FW for allocated scheduler resources and store in HW struct
1373 : : */
1374 : 0 : int ice_sched_query_res_alloc(struct ice_hw *hw)
1375 : : {
1376 : : struct ice_aqc_query_txsched_res_resp *buf;
1377 : : __le16 max_sibl;
1378 : : int status = 0;
1379 : : u8 i;
1380 : :
1381 [ # # ]: 0 : if (hw->layer_info)
1382 : : return status;
1383 : :
1384 : : buf = (struct ice_aqc_query_txsched_res_resp *)
1385 : 0 : ice_malloc(hw, sizeof(*buf));
1386 [ # # ]: 0 : if (!buf)
1387 : : return ICE_ERR_NO_MEMORY;
1388 : :
1389 : : status = ice_aq_query_sched_res(hw, sizeof(*buf), buf, NULL);
1390 [ # # ]: 0 : if (status)
1391 : 0 : goto sched_query_out;
1392 : :
1393 : 0 : hw->num_tx_sched_layers =
1394 : 0 : (u8)LE16_TO_CPU(buf->sched_props.logical_levels);
1395 : 0 : hw->num_tx_sched_phys_layers =
1396 : 0 : (u8)LE16_TO_CPU(buf->sched_props.phys_levels);
1397 : 0 : hw->flattened_layers = buf->sched_props.flattening_bitmap;
1398 : 0 : hw->max_cgds = buf->sched_props.max_pf_cgds;
1399 : :
1400 : : /* max sibling group size of current layer refers to the max children
1401 : : * of the below layer node.
1402 : : * layer 1 node max children will be layer 2 max sibling group size
1403 : : * layer 2 node max children will be layer 3 max sibling group size
1404 : : * and so on. This array will be populated from root (index 0) to
1405 : : * qgroup layer 7. Leaf node has no children.
1406 : : */
1407 [ # # ]: 0 : for (i = 0; i < hw->num_tx_sched_layers - 1; i++) {
1408 : 0 : max_sibl = buf->layer_props[i + 1].max_sibl_grp_sz;
1409 : 0 : hw->max_children[i] = LE16_TO_CPU(max_sibl);
1410 : : }
1411 : :
1412 : 0 : hw->layer_info = (struct ice_aqc_layer_props *)
1413 : 0 : ice_memdup(hw, buf->layer_props,
1414 : 0 : (hw->num_tx_sched_layers *
1415 : : sizeof(*hw->layer_info)),
1416 : : ICE_NONDMA_TO_NONDMA);
1417 [ # # ]: 0 : if (!hw->layer_info) {
1418 : : status = ICE_ERR_NO_MEMORY;
1419 : 0 : goto sched_query_out;
1420 : : }
1421 : :
1422 : 0 : sched_query_out:
1423 : 0 : ice_free(hw, buf);
1424 : 0 : return status;
1425 : : }
1426 : :
1427 : : /**
1428 : : * ice_sched_get_psm_clk_freq - determine the PSM clock frequency
1429 : : * @hw: pointer to the HW struct
1430 : : *
1431 : : * Determine the PSM clock frequency and store in HW struct
1432 : : */
1433 : 0 : void ice_sched_get_psm_clk_freq(struct ice_hw *hw)
1434 : : {
1435 : : u32 val, clk_src;
1436 : :
1437 : 0 : val = rd32(hw, GLGEN_CLKSTAT_SRC);
1438 : 0 : clk_src = (val & GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M) >>
1439 : : GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_S;
1440 : :
1441 [ # # # # ]: 0 : switch (clk_src) {
1442 : 0 : case PSM_CLK_SRC_367_MHZ:
1443 : 0 : hw->psm_clk_freq = ICE_PSM_CLK_367MHZ_IN_HZ;
1444 : 0 : break;
1445 : 0 : case PSM_CLK_SRC_416_MHZ:
1446 : 0 : hw->psm_clk_freq = ICE_PSM_CLK_416MHZ_IN_HZ;
1447 : 0 : break;
1448 : 0 : case PSM_CLK_SRC_446_MHZ:
1449 : 0 : hw->psm_clk_freq = ICE_PSM_CLK_446MHZ_IN_HZ;
1450 : 0 : break;
1451 : 0 : case PSM_CLK_SRC_390_MHZ:
1452 : 0 : hw->psm_clk_freq = ICE_PSM_CLK_390MHZ_IN_HZ;
1453 : 0 : break;
1454 : :
1455 : : /* default condition is not required as clk_src is restricted
1456 : : * to a 2-bit value from GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M mask.
1457 : : * The above switch statements cover the possible values of
1458 : : * this variable.
1459 : : */
1460 : : }
1461 : 0 : }
1462 : :
1463 : : /**
1464 : : * ice_sched_find_node_in_subtree - Find node in part of base node subtree
1465 : : * @hw: pointer to the HW struct
1466 : : * @base: pointer to the base node
1467 : : * @node: pointer to the node to search
1468 : : *
1469 : : * This function checks whether a given node is part of the base node
1470 : : * subtree or not
1471 : : */
1472 : : bool
1473 : 0 : ice_sched_find_node_in_subtree(struct ice_hw __ALWAYS_UNUSED *hw,
1474 : : struct ice_sched_node *base,
1475 : : struct ice_sched_node *node)
1476 : : {
1477 [ # # ]: 0 : if (base == node)
1478 : : return true;
1479 [ # # # # ]: 0 : while (node->tx_sched_layer != 0 && node->parent != NULL) {
1480 [ # # ]: 0 : if (node->parent == base)
1481 : : return true;
1482 : : node = node->parent;
1483 : : }
1484 : : return false;
1485 : : }
1486 : :
1487 : : /**
1488 : : * ice_sched_get_free_qgrp - Scan all queue group siblings and find a free node
1489 : : * @pi: port information structure
1490 : : * @vsi_node: software VSI handle
1491 : : * @qgrp_node: first queue group node identified for scanning
1492 : : * @owner: LAN or RDMA
1493 : : *
1494 : : * This function retrieves a free LAN or RDMA queue group node by scanning
1495 : : * qgrp_node and its siblings for the queue group with the fewest number
1496 : : * of queues currently assigned.
1497 : : */
1498 : : static struct ice_sched_node *
1499 : 0 : ice_sched_get_free_qgrp(struct ice_port_info *pi,
1500 : : struct ice_sched_node *vsi_node,
1501 : : struct ice_sched_node *qgrp_node, u8 owner)
1502 : : {
1503 : : struct ice_sched_node *min_qgrp;
1504 : : u16 min_children;
1505 : :
1506 [ # # ]: 0 : if (!qgrp_node)
1507 : : return qgrp_node;
1508 : 0 : min_children = qgrp_node->num_children;
1509 [ # # ]: 0 : if (!min_children)
1510 : : return qgrp_node;
1511 : : min_qgrp = qgrp_node;
1512 : : /* scan all queue groups until find a node which has less than the
1513 : : * minimum number of children. This way all queue group nodes get
1514 : : * equal number of shares and active. The bandwidth will be equally
1515 : : * distributed across all queues.
1516 : : */
1517 [ # # ]: 0 : while (qgrp_node) {
1518 : : /* make sure the qgroup node is part of the VSI subtree */
1519 [ # # ]: 0 : if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node))
1520 [ # # ]: 0 : if (qgrp_node->num_children < min_children &&
1521 [ # # ]: 0 : qgrp_node->owner == owner) {
1522 : : /* replace the new min queue group node */
1523 : : min_qgrp = qgrp_node;
1524 : : min_children = min_qgrp->num_children;
1525 : : /* break if it has no children, */
1526 [ # # ]: 0 : if (!min_children)
1527 : : break;
1528 : : }
1529 : 0 : qgrp_node = qgrp_node->sibling;
1530 : : }
1531 : : return min_qgrp;
1532 : : }
1533 : :
1534 : : /**
1535 : : * ice_sched_get_free_qparent - Get a free LAN or RDMA queue group node
1536 : : * @pi: port information structure
1537 : : * @vsi_handle: software VSI handle
1538 : : * @tc: branch number
1539 : : * @owner: LAN or RDMA
1540 : : *
1541 : : * This function retrieves a free LAN or RDMA queue group node
1542 : : */
1543 : : struct ice_sched_node *
1544 : 0 : ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
1545 : : u8 owner)
1546 : : {
1547 : : struct ice_sched_node *vsi_node, *qgrp_node;
1548 : : struct ice_vsi_ctx *vsi_ctx;
1549 : : u8 qgrp_layer, vsi_layer;
1550 : : u16 max_children;
1551 : :
1552 : 0 : qgrp_layer = ice_sched_get_qgrp_layer(pi->hw);
1553 : 0 : max_children = pi->hw->max_children[qgrp_layer];
1554 : :
1555 : 0 : vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
1556 [ # # ]: 0 : if (!vsi_ctx)
1557 : : return NULL;
1558 : 0 : vsi_node = vsi_ctx->sched.vsi_node[tc];
1559 : : /* validate invalid VSI ID */
1560 [ # # ]: 0 : if (!vsi_node)
1561 : : return NULL;
1562 : 0 : vsi_layer = vsi_node->tx_sched_layer;
1563 : :
1564 : : /* If the queue group and vsi layer are same then queues
1565 : : * are all attached directly to VSI
1566 : : */
1567 [ # # ]: 0 : if (qgrp_layer == vsi_layer)
1568 : : return vsi_node;
1569 : :
1570 : : /* get the first queue group node from VSI sub-tree */
1571 : : qgrp_node = ice_sched_get_first_node(pi, vsi_node, qgrp_layer);
1572 [ # # ]: 0 : while (qgrp_node) {
1573 : : /* make sure the qgroup node is part of the VSI subtree */
1574 [ # # ]: 0 : if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node))
1575 [ # # ]: 0 : if (qgrp_node->num_children < max_children &&
1576 [ # # # # ]: 0 : qgrp_node->owner == owner && qgrp_node->vsi_handle == vsi_handle)
1577 : : break;
1578 : 0 : qgrp_node = qgrp_node->sibling;
1579 : : }
1580 : :
1581 : : /* Select the best queue group */
1582 : 0 : return ice_sched_get_free_qgrp(pi, vsi_node, qgrp_node, owner);
1583 : : }
1584 : :
1585 : : /**
1586 : : * ice_sched_get_vsi_node - Get a VSI node based on VSI ID
1587 : : * @pi: pointer to the port information structure
1588 : : * @tc_node: pointer to the TC node
1589 : : * @vsi_handle: software VSI handle
1590 : : *
1591 : : * This function retrieves a VSI node for a given VSI ID from a given
1592 : : * TC branch
1593 : : */
1594 : : struct ice_sched_node *
1595 : 0 : ice_sched_get_vsi_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
1596 : : u16 vsi_handle)
1597 : : {
1598 : : struct ice_sched_node *node;
1599 : : u8 vsi_layer;
1600 : :
1601 [ # # ]: 0 : vsi_layer = ice_sched_get_vsi_layer(pi->hw);
1602 : 0 : node = ice_sched_get_first_node(pi, tc_node, vsi_layer);
1603 : :
1604 : : /* Check whether it already exists */
1605 [ # # ]: 0 : while (node) {
1606 [ # # ]: 0 : if (node->vsi_handle == vsi_handle)
1607 : 0 : return node;
1608 : 0 : node = node->sibling;
1609 : : }
1610 : :
1611 : : return node;
1612 : : }
1613 : :
1614 : : /**
1615 : : * ice_sched_get_agg_node - Get an aggregator node based on aggregator ID
1616 : : * @pi: pointer to the port information structure
1617 : : * @tc_node: pointer to the TC node
1618 : : * @agg_id: aggregator ID
1619 : : *
1620 : : * This function retrieves an aggregator node for a given aggregator ID from
1621 : : * a given TC branch
1622 : : */
1623 : : static struct ice_sched_node *
1624 : : ice_sched_get_agg_node(struct ice_port_info *pi, struct ice_sched_node *tc_node,
1625 : : u32 agg_id)
1626 : : {
1627 : : struct ice_sched_node *node;
1628 : 0 : struct ice_hw *hw = pi->hw;
1629 : : u8 agg_layer;
1630 : :
1631 [ # # # # : 0 : if (!hw)
# # # # #
# # # # #
# # # # ]
1632 : : return NULL;
1633 : : agg_layer = ice_sched_get_agg_layer(hw);
1634 : 0 : node = ice_sched_get_first_node(pi, tc_node, agg_layer);
1635 : :
1636 : : /* Check whether it already exists */
1637 [ # # # # : 0 : while (node) {
# # # # #
# # # # #
# # # # #
# ]
1638 [ # # # # : 0 : if (node->agg_id == agg_id)
# # # # #
# # # # #
# # # # #
# ]
1639 : : return node;
1640 : 0 : node = node->sibling;
1641 : : }
1642 : :
1643 : : return node;
1644 : : }
1645 : :
1646 : : /**
1647 : : * ice_sched_check_node - Compare node parameters between SW DB and HW DB
1648 : : * @hw: pointer to the HW struct
1649 : : * @node: pointer to the ice_sched_node struct
1650 : : *
1651 : : * This function queries and compares the HW element with SW DB node parameters
1652 : : */
1653 : 0 : static bool ice_sched_check_node(struct ice_hw *hw, struct ice_sched_node *node)
1654 : : {
1655 : : struct ice_aqc_txsched_elem_data buf;
1656 : : u32 node_teid;
1657 : : int status;
1658 : :
1659 : 0 : node_teid = LE32_TO_CPU(node->info.node_teid);
1660 : 0 : status = ice_sched_query_elem(hw, node_teid, &buf);
1661 [ # # ]: 0 : if (status)
1662 : : return false;
1663 : :
1664 [ # # ]: 0 : if (memcmp(&buf, &node->info, sizeof(buf))) {
1665 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "Node mismatch for teid=0x%x\n",
1666 : : node_teid);
1667 : 0 : return false;
1668 : : }
1669 : :
1670 : : return true;
1671 : : }
1672 : :
1673 : : /**
1674 : : * ice_sched_calc_vsi_child_nodes - calculate number of VSI child nodes
1675 : : * @hw: pointer to the HW struct
1676 : : * @num_qs: number of queues
1677 : : * @num_nodes: num nodes array
1678 : : *
1679 : : * This function calculates the number of VSI child nodes based on the
1680 : : * number of queues.
1681 : : */
1682 : : static void
1683 : : ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes)
1684 : : {
1685 : : u16 num = num_qs;
1686 : : u8 i, qgl, vsil;
1687 : :
1688 : : qgl = ice_sched_get_qgrp_layer(hw);
1689 : : vsil = ice_sched_get_vsi_layer(hw);
1690 : :
1691 : : /* calculate num nodes from queue group to VSI layer */
1692 [ # # ]: 0 : for (i = qgl; i > vsil; i--) {
1693 : : /* round to the next integer if there is a remainder */
1694 : 0 : num = DIVIDE_AND_ROUND_UP(num, hw->max_children[i]);
1695 : :
1696 : : /* need at least one node */
1697 : 0 : num_nodes[i] = num ? num : 1;
1698 : : }
1699 : : }
1700 : :
1701 : : /**
1702 : : * ice_sched_add_vsi_child_nodes - add VSI child nodes to tree
1703 : : * @pi: port information structure
1704 : : * @vsi_handle: software VSI handle
1705 : : * @tc_node: pointer to the TC node
1706 : : * @num_nodes: pointer to the num nodes that needs to be added per layer
1707 : : * @owner: node owner (LAN or RDMA)
1708 : : *
1709 : : * This function adds the VSI child nodes to tree. It gets called for
1710 : : * LAN and RDMA separately.
1711 : : */
1712 : : static int
1713 : 0 : ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
1714 : : struct ice_sched_node *tc_node, u16 *num_nodes,
1715 : : u8 owner)
1716 : : {
1717 : : struct ice_sched_node *parent, *node;
1718 : 0 : struct ice_hw *hw = pi->hw;
1719 : : u32 first_node_teid;
1720 [ # # ]: 0 : u16 num_added = 0;
1721 : : u8 i, qgl, vsil;
1722 : :
1723 : : qgl = ice_sched_get_qgrp_layer(hw);
1724 : : vsil = ice_sched_get_vsi_layer(hw);
1725 : 0 : parent = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
1726 [ # # ]: 0 : for (i = vsil + 1; i <= qgl; i++) {
1727 : : int status;
1728 : :
1729 [ # # ]: 0 : if (!parent)
1730 : : return ICE_ERR_CFG;
1731 : :
1732 : 0 : status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
1733 : 0 : num_nodes[i],
1734 : : &first_node_teid,
1735 : : &num_added);
1736 [ # # # # ]: 0 : if (status || num_nodes[i] != num_added)
1737 : : return ICE_ERR_CFG;
1738 : :
1739 : : /* The newly added node can be a new parent for the next
1740 : : * layer nodes
1741 : : */
1742 [ # # ]: 0 : if (num_added) {
1743 : 0 : parent = ice_sched_find_node_by_teid(tc_node,
1744 : : first_node_teid);
1745 : : node = parent;
1746 [ # # ]: 0 : while (node) {
1747 : 0 : node->owner = owner;
1748 : 0 : node = node->sibling;
1749 : : }
1750 : : } else {
1751 : 0 : parent = parent->children[0];
1752 : : }
1753 : : }
1754 : :
1755 : : return 0;
1756 : : }
1757 : :
1758 : : /**
1759 : : * ice_sched_calc_vsi_support_nodes - calculate number of VSI support nodes
1760 : : * @pi: pointer to the port info structure
1761 : : * @tc_node: pointer to TC node
1762 : : * @num_nodes: pointer to num nodes array
1763 : : *
1764 : : * This function calculates the number of supported nodes needed to add this
1765 : : * VSI into Tx tree including the VSI, parent and intermediate nodes in below
1766 : : * layers
1767 : : */
1768 : : static void
1769 : 0 : ice_sched_calc_vsi_support_nodes(struct ice_port_info *pi,
1770 : : struct ice_sched_node *tc_node, u16 *num_nodes)
1771 : : {
1772 : : struct ice_sched_node *node;
1773 : : u8 vsil;
1774 : : int i;
1775 : :
1776 [ # # ]: 0 : vsil = ice_sched_get_vsi_layer(pi->hw);
1777 [ # # ]: 0 : for (i = vsil; i >= pi->hw->sw_entry_point_layer; i--)
1778 : : /* Add intermediate nodes if TC has no children and
1779 : : * need at least one node for VSI
1780 : : */
1781 [ # # # # ]: 0 : if (!tc_node->num_children || i == vsil) {
1782 : 0 : num_nodes[i]++;
1783 : : } else {
1784 : : /* If intermediate nodes are reached max children
1785 : : * then add a new one.
1786 : : */
1787 : : node = ice_sched_get_first_node(pi, tc_node, (u8)i);
1788 : : /* scan all the siblings */
1789 [ # # ]: 0 : while (node) {
1790 : 0 : if (node->num_children <
1791 [ # # ]: 0 : pi->hw->max_children[i])
1792 : : break;
1793 : 0 : node = node->sibling;
1794 : : }
1795 : :
1796 : : /* tree has one intermediate node to add this new VSI.
1797 : : * So no need to calculate supported nodes for below
1798 : : * layers.
1799 : : */
1800 [ # # ]: 0 : if (node)
1801 : : break;
1802 : : /* all the nodes are full, allocate a new one */
1803 : 0 : num_nodes[i]++;
1804 : : }
1805 : 0 : }
1806 : :
1807 : : /**
1808 : : * ice_sched_add_vsi_support_nodes - add VSI supported nodes into Tx tree
1809 : : * @pi: port information structure
1810 : : * @vsi_handle: software VSI handle
1811 : : * @tc_node: pointer to TC node
1812 : : * @num_nodes: pointer to num nodes array
1813 : : *
1814 : : * This function adds the VSI supported nodes into Tx tree including the
1815 : : * VSI, its parent and intermediate nodes in below layers
1816 : : */
1817 : : static int
1818 : 0 : ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle,
1819 : : struct ice_sched_node *tc_node, u16 *num_nodes)
1820 : : {
1821 : : struct ice_sched_node *parent = tc_node;
1822 : : u32 first_node_teid;
1823 : 0 : u16 num_added = 0;
1824 : : u8 i, vsil;
1825 : :
1826 [ # # ]: 0 : if (!pi)
1827 : : return ICE_ERR_PARAM;
1828 : :
1829 [ # # ]: 0 : vsil = ice_sched_get_vsi_layer(pi->hw);
1830 [ # # ]: 0 : for (i = pi->hw->sw_entry_point_layer; i <= vsil; i++) {
1831 : : int status;
1832 : :
1833 : 0 : status = ice_sched_add_nodes_to_layer(pi, tc_node, parent,
1834 : 0 : i, num_nodes[i],
1835 : : &first_node_teid,
1836 : : &num_added);
1837 [ # # # # ]: 0 : if (status || num_nodes[i] != num_added)
1838 : : return ICE_ERR_CFG;
1839 : :
1840 : : /* The newly added node can be a new parent for the next
1841 : : * layer nodes
1842 : : */
1843 [ # # ]: 0 : if (num_added)
1844 : 0 : parent = ice_sched_find_node_by_teid(tc_node,
1845 : : first_node_teid);
1846 : : else
1847 : 0 : parent = parent->children[0];
1848 : :
1849 [ # # ]: 0 : if (!parent)
1850 : : return ICE_ERR_CFG;
1851 : :
1852 [ # # ]: 0 : if (i == vsil)
1853 : 0 : parent->vsi_handle = vsi_handle;
1854 : : }
1855 : :
1856 : : return 0;
1857 : : }
1858 : :
1859 : : /**
1860 : : * ice_sched_add_vsi_to_topo - add a new VSI into tree
1861 : : * @pi: port information structure
1862 : : * @vsi_handle: software VSI handle
1863 : : * @tc: TC number
1864 : : *
1865 : : * This function adds a new VSI into scheduler tree
1866 : : */
1867 : : static int
1868 : 0 : ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc)
1869 : : {
1870 : 0 : u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
1871 : : struct ice_sched_node *tc_node;
1872 : :
1873 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
1874 [ # # ]: 0 : if (!tc_node)
1875 : : return ICE_ERR_PARAM;
1876 : :
1877 : : /* calculate number of supported nodes needed for this VSI */
1878 : 0 : ice_sched_calc_vsi_support_nodes(pi, tc_node, num_nodes);
1879 : :
1880 : : /* add VSI supported nodes to TC subtree */
1881 : 0 : return ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node,
1882 : : num_nodes);
1883 : : }
1884 : :
1885 : : /**
1886 : : * ice_sched_update_vsi_child_nodes - update VSI child nodes
1887 : : * @pi: port information structure
1888 : : * @vsi_handle: software VSI handle
1889 : : * @tc: TC number
1890 : : * @new_numqs: new number of max queues
1891 : : * @owner: owner of this subtree
1892 : : *
1893 : : * This function updates the VSI child nodes based on the number of queues
1894 : : */
1895 : : static int
1896 : 0 : ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle,
1897 : : u8 tc, u16 new_numqs, u8 owner)
1898 : : {
1899 : 0 : u16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
1900 : : struct ice_sched_node *vsi_node;
1901 : : struct ice_sched_node *tc_node;
1902 : : struct ice_vsi_ctx *vsi_ctx;
1903 : 0 : struct ice_hw *hw = pi->hw;
1904 : : int status = 0;
1905 : : u16 prev_numqs;
1906 : :
1907 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
1908 [ # # ]: 0 : if (!tc_node)
1909 : : return ICE_ERR_CFG;
1910 : :
1911 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
1912 [ # # ]: 0 : if (!vsi_node)
1913 : : return ICE_ERR_CFG;
1914 : :
1915 : 0 : vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
1916 [ # # ]: 0 : if (!vsi_ctx)
1917 : : return ICE_ERR_PARAM;
1918 : :
1919 : 0 : prev_numqs = vsi_ctx->sched.max_lanq[tc];
1920 : : /* num queues are not changed or less than the previous number */
1921 [ # # ]: 0 : if (new_numqs <= prev_numqs)
1922 : : return status;
1923 : 0 : status = ice_alloc_lan_q_ctx(hw, vsi_handle, tc, new_numqs);
1924 [ # # ]: 0 : if (status)
1925 : : return status;
1926 : :
1927 : : if (new_numqs)
1928 : : ice_sched_calc_vsi_child_nodes(hw, new_numqs, new_num_nodes);
1929 : : /* Keep the max number of queue configuration all the time. Update the
1930 : : * tree only if number of queues > previous number of queues. This may
1931 : : * leave some extra nodes in the tree if number of queues < previous
1932 : : * number but that wouldn't harm anything. Removing those extra nodes
1933 : : * may complicate the code if those nodes are part of SRL or
1934 : : * individually rate limited.
1935 : : */
1936 : 0 : status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node,
1937 : : new_num_nodes, owner);
1938 [ # # ]: 0 : if (status)
1939 : : return status;
1940 : 0 : vsi_ctx->sched.max_lanq[tc] = new_numqs;
1941 : :
1942 : 0 : return 0;
1943 : : }
1944 : :
1945 : : /**
1946 : : * ice_sched_cfg_vsi - configure the new/existing VSI
1947 : : * @pi: port information structure
1948 : : * @vsi_handle: software VSI handle
1949 : : * @tc: TC number
1950 : : * @maxqs: max number of queues
1951 : : * @owner: LAN or RDMA
1952 : : * @enable: TC enabled or disabled
1953 : : *
1954 : : * This function adds/updates VSI nodes based on the number of queues. If TC is
1955 : : * enabled and VSI is in suspended state then resume the VSI back. If TC is
1956 : : * disabled then suspend the VSI if it is not already.
1957 : : */
1958 : : int
1959 : 0 : ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs,
1960 : : u8 owner, bool enable)
1961 : : {
1962 : : struct ice_sched_node *vsi_node, *tc_node;
1963 : : struct ice_vsi_ctx *vsi_ctx;
1964 : 0 : struct ice_hw *hw = pi->hw;
1965 : : int status = 0;
1966 : :
1967 [ # # ]: 0 : ice_debug(pi->hw, ICE_DBG_SCHED, "add/config VSI %d\n", vsi_handle);
1968 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
1969 [ # # ]: 0 : if (!tc_node)
1970 : : return ICE_ERR_PARAM;
1971 : 0 : vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle);
1972 [ # # ]: 0 : if (!vsi_ctx)
1973 : : return ICE_ERR_PARAM;
1974 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
1975 : :
1976 : : /* suspend the VSI if TC is not enabled */
1977 [ # # ]: 0 : if (!enable) {
1978 [ # # # # ]: 0 : if (vsi_node && vsi_node->in_use) {
1979 : 0 : u32 teid = LE32_TO_CPU(vsi_node->info.node_teid);
1980 : :
1981 : 0 : status = ice_sched_suspend_resume_elems(hw, 1, &teid,
1982 : : true);
1983 [ # # ]: 0 : if (!status)
1984 : 0 : vsi_node->in_use = false;
1985 : : }
1986 : 0 : return status;
1987 : : }
1988 : :
1989 : : /* TC is enabled, if it is a new VSI then add it to the tree */
1990 [ # # ]: 0 : if (!vsi_node) {
1991 : 0 : status = ice_sched_add_vsi_to_topo(pi, vsi_handle, tc);
1992 [ # # ]: 0 : if (status)
1993 : : return status;
1994 : :
1995 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
1996 [ # # ]: 0 : if (!vsi_node)
1997 : : return ICE_ERR_CFG;
1998 : :
1999 : 0 : vsi_ctx->sched.vsi_node[tc] = vsi_node;
2000 : 0 : vsi_node->in_use = true;
2001 : : /* invalidate the max queues whenever VSI gets added first time
2002 : : * into the scheduler tree (boot or after reset). We need to
2003 : : * recreate the child nodes all the time in these cases.
2004 : : */
2005 : 0 : vsi_ctx->sched.max_lanq[tc] = 0;
2006 : : }
2007 : :
2008 : : /* update the VSI child nodes */
2009 : 0 : status = ice_sched_update_vsi_child_nodes(pi, vsi_handle, tc, maxqs,
2010 : : owner);
2011 [ # # ]: 0 : if (status)
2012 : : return status;
2013 : :
2014 : : /* TC is enabled, resume the VSI if it is in the suspend state */
2015 [ # # ]: 0 : if (!vsi_node->in_use) {
2016 : 0 : u32 teid = LE32_TO_CPU(vsi_node->info.node_teid);
2017 : :
2018 : 0 : status = ice_sched_suspend_resume_elems(hw, 1, &teid, false);
2019 [ # # ]: 0 : if (!status)
2020 : 0 : vsi_node->in_use = true;
2021 : : }
2022 : :
2023 : : return status;
2024 : : }
2025 : :
2026 : : /**
2027 : : * ice_sched_rm_agg_vsi_info - remove aggregator related VSI info entry
2028 : : * @pi: port information structure
2029 : : * @vsi_handle: software VSI handle
2030 : : *
2031 : : * This function removes single aggregator VSI info entry from
2032 : : * aggregator list.
2033 : : */
2034 : 0 : static void ice_sched_rm_agg_vsi_info(struct ice_port_info *pi, u16 vsi_handle)
2035 : : {
2036 : : struct ice_sched_agg_info *agg_info;
2037 : : struct ice_sched_agg_info *atmp;
2038 : :
2039 [ # # # # : 0 : LIST_FOR_EACH_ENTRY_SAFE(agg_info, atmp, &pi->hw->agg_list,
# # # # #
# # # ]
2040 : : ice_sched_agg_info,
2041 : : list_entry) {
2042 : : struct ice_sched_agg_vsi_info *agg_vsi_info;
2043 : : struct ice_sched_agg_vsi_info *vtmp;
2044 : :
2045 [ # # # # : 0 : LIST_FOR_EACH_ENTRY_SAFE(agg_vsi_info, vtmp,
# # # # #
# ]
2046 : : &agg_info->agg_vsi_list,
2047 : : ice_sched_agg_vsi_info, list_entry)
2048 [ # # ]: 0 : if (agg_vsi_info->vsi_handle == vsi_handle) {
2049 [ # # ]: 0 : LIST_DEL(&agg_vsi_info->list_entry);
2050 : 0 : ice_free(pi->hw, agg_vsi_info);
2051 : 0 : return;
2052 : : }
2053 : : }
2054 : : }
2055 : :
2056 : : /**
2057 : : * ice_sched_is_leaf_node_present - check for a leaf node in the sub-tree
2058 : : * @node: pointer to the sub-tree node
2059 : : *
2060 : : * This function checks for a leaf node presence in a given sub-tree node.
2061 : : */
2062 : 0 : static bool ice_sched_is_leaf_node_present(struct ice_sched_node *node)
2063 : : {
2064 : : u16 i;
2065 : :
2066 [ # # ]: 0 : for (i = 0; i < node->num_children; i++)
2067 [ # # ]: 0 : if (ice_sched_is_leaf_node_present(node->children[i]))
2068 : : return true;
2069 : : /* check for a leaf node */
2070 : 0 : return (node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF);
2071 : : }
2072 : :
2073 : : /**
2074 : : * ice_sched_rm_vsi_cfg - remove the VSI and its children nodes
2075 : : * @pi: port information structure
2076 : : * @vsi_handle: software VSI handle
2077 : : * @owner: LAN or RDMA
2078 : : *
2079 : : * This function removes the VSI and its LAN or RDMA children nodes from the
2080 : : * scheduler tree.
2081 : : */
2082 : : static int
2083 : 0 : ice_sched_rm_vsi_cfg(struct ice_port_info *pi, u16 vsi_handle, u8 owner)
2084 : : {
2085 : : struct ice_vsi_ctx *vsi_ctx;
2086 : : int status = ICE_ERR_PARAM;
2087 : : u8 i;
2088 : :
2089 [ # # ]: 0 : ice_debug(pi->hw, ICE_DBG_SCHED, "removing VSI %d\n", vsi_handle);
2090 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
2091 : : return status;
2092 : 0 : ice_acquire_lock(&pi->sched_lock);
2093 : 0 : vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
2094 [ # # ]: 0 : if (!vsi_ctx)
2095 : 0 : goto exit_sched_rm_vsi_cfg;
2096 : :
2097 [ # # ]: 0 : ice_for_each_traffic_class(i) {
2098 : : struct ice_sched_node *vsi_node, *tc_node;
2099 : : u16 j = 0;
2100 : :
2101 : 0 : tc_node = ice_sched_get_tc_node(pi, i);
2102 [ # # ]: 0 : if (!tc_node)
2103 : 0 : continue;
2104 : :
2105 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
2106 [ # # ]: 0 : if (!vsi_node)
2107 : 0 : continue;
2108 : :
2109 [ # # ]: 0 : if (ice_sched_is_leaf_node_present(vsi_node)) {
2110 [ # # ]: 0 : ice_debug(pi->hw, ICE_DBG_SCHED, "VSI has leaf nodes in TC %d\n", i);
2111 : : status = ICE_ERR_IN_USE;
2112 : 0 : goto exit_sched_rm_vsi_cfg;
2113 : : }
2114 [ # # ]: 0 : while (j < vsi_node->num_children) {
2115 [ # # ]: 0 : if (vsi_node->children[j]->owner == owner) {
2116 : 0 : ice_free_sched_node(pi, vsi_node->children[j]);
2117 : :
2118 : : /* reset the counter again since the num
2119 : : * children will be updated after node removal
2120 : : */
2121 : : j = 0;
2122 : : } else {
2123 : 0 : j++;
2124 : : }
2125 : : }
2126 : : /* remove the VSI if it has no children */
2127 [ # # ]: 0 : if (!vsi_node->num_children) {
2128 : 0 : ice_free_sched_node(pi, vsi_node);
2129 : 0 : vsi_ctx->sched.vsi_node[i] = NULL;
2130 : :
2131 : : /* clean up aggregator related VSI info if any */
2132 : 0 : ice_sched_rm_agg_vsi_info(pi, vsi_handle);
2133 : : }
2134 [ # # ]: 0 : if (owner == ICE_SCHED_NODE_OWNER_LAN)
2135 : 0 : vsi_ctx->sched.max_lanq[i] = 0;
2136 : : }
2137 : : status = 0;
2138 : :
2139 : 0 : exit_sched_rm_vsi_cfg:
2140 : : ice_release_lock(&pi->sched_lock);
2141 : 0 : return status;
2142 : : }
2143 : :
2144 : : /**
2145 : : * ice_rm_vsi_lan_cfg - remove VSI and its LAN children nodes
2146 : : * @pi: port information structure
2147 : : * @vsi_handle: software VSI handle
2148 : : *
2149 : : * This function clears the VSI and its LAN children nodes from scheduler tree
2150 : : * for all TCs.
2151 : : */
2152 : 0 : int ice_rm_vsi_lan_cfg(struct ice_port_info *pi, u16 vsi_handle)
2153 : : {
2154 : 0 : return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_LAN);
2155 : : }
2156 : :
2157 : : /**
2158 : : * ice_sched_is_tree_balanced - Check tree nodes are identical or not
2159 : : * @hw: pointer to the HW struct
2160 : : * @node: pointer to the ice_sched_node struct
2161 : : *
2162 : : * This function compares all the nodes for a given tree against HW DB nodes
2163 : : * This function needs to be called with the port_info->sched_lock held
2164 : : */
2165 : 0 : bool ice_sched_is_tree_balanced(struct ice_hw *hw, struct ice_sched_node *node)
2166 : : {
2167 : : u16 i;
2168 : :
2169 : : /* start from the leaf node */
2170 [ # # ]: 0 : for (i = 0; i < node->num_children; i++)
2171 : : /* Fail if node doesn't match with the SW DB
2172 : : * this recursion is intentional, and wouldn't
2173 : : * go more than 9 calls
2174 : : */
2175 [ # # ]: 0 : if (!ice_sched_is_tree_balanced(hw, node->children[i]))
2176 : : return false;
2177 : :
2178 : 0 : return ice_sched_check_node(hw, node);
2179 : : }
2180 : :
2181 : : /**
2182 : : * ice_aq_query_node_to_root - retrieve the tree topology for a given node TEID
2183 : : * @hw: pointer to the HW struct
2184 : : * @node_teid: node TEID
2185 : : * @buf: pointer to buffer
2186 : : * @buf_size: buffer size in bytes
2187 : : * @cd: pointer to command details structure or NULL
2188 : : *
2189 : : * This function retrieves the tree topology from the firmware for a given
2190 : : * node TEID to the root node.
2191 : : */
2192 : : int
2193 : 0 : ice_aq_query_node_to_root(struct ice_hw *hw, u32 node_teid,
2194 : : struct ice_aqc_txsched_elem_data *buf, u16 buf_size,
2195 : : struct ice_sq_cd *cd)
2196 : : {
2197 : : struct ice_aqc_query_node_to_root *cmd;
2198 : : struct ice_aq_desc desc;
2199 : :
2200 : : cmd = &desc.params.query_node_to_root;
2201 : 0 : ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_node_to_root);
2202 : 0 : cmd->teid = CPU_TO_LE32(node_teid);
2203 : 0 : return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
2204 : : }
2205 : :
2206 : : /**
2207 : : * ice_get_agg_info - get the aggregator ID
2208 : : * @hw: pointer to the hardware structure
2209 : : * @agg_id: aggregator ID
2210 : : *
2211 : : * This function validates aggregator ID. The function returns info if
2212 : : * aggregator ID is present in list otherwise it returns null.
2213 : : */
2214 : : static struct ice_sched_agg_info *
2215 : : ice_get_agg_info(struct ice_hw *hw, u32 agg_id)
2216 : : {
2217 : : struct ice_sched_agg_info *agg_info;
2218 : :
2219 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
2220 : : list_entry)
2221 [ # # # # : 0 : if (agg_info->agg_id == agg_id)
# # # # #
# # # #
# ]
2222 : : return agg_info;
2223 : :
2224 : : return NULL;
2225 : : }
2226 : :
2227 : : /**
2228 : : * ice_sched_get_free_vsi_parent - Find a free parent node in aggregator subtree
2229 : : * @hw: pointer to the HW struct
2230 : : * @node: pointer to a child node
2231 : : * @num_nodes: num nodes count array
2232 : : *
2233 : : * This function walks through the aggregator subtree to find a free parent
2234 : : * node
2235 : : */
2236 : : static struct ice_sched_node *
2237 : 0 : ice_sched_get_free_vsi_parent(struct ice_hw *hw, struct ice_sched_node *node,
2238 : : u16 *num_nodes)
2239 : : {
2240 [ # # ]: 0 : u8 l = node->tx_sched_layer;
2241 : : u8 vsil;
2242 : : u16 i;
2243 : :
2244 : : vsil = ice_sched_get_vsi_layer(hw);
2245 : :
2246 : : /* Is it VSI parent layer ? */
2247 [ # # ]: 0 : if (l == vsil - 1)
2248 [ # # ]: 0 : return (node->num_children < hw->max_children[l]) ? node : NULL;
2249 : :
2250 : : /* We have intermediate nodes. Let's walk through the subtree. If the
2251 : : * intermediate node has space to add a new node then clear the count
2252 : : */
2253 [ # # ]: 0 : if (node->num_children < hw->max_children[l])
2254 : 0 : num_nodes[l] = 0;
2255 : : /* The below recursive call is intentional and wouldn't go more than
2256 : : * 2 or 3 iterations.
2257 : : */
2258 : :
2259 [ # # ]: 0 : for (i = 0; i < node->num_children; i++) {
2260 : : struct ice_sched_node *parent;
2261 : :
2262 : 0 : parent = ice_sched_get_free_vsi_parent(hw, node->children[i],
2263 : : num_nodes);
2264 [ # # ]: 0 : if (parent)
2265 : 0 : return parent;
2266 : : }
2267 : :
2268 : : return NULL;
2269 : : }
2270 : :
2271 : : /**
2272 : : * ice_sched_update_parent - update the new parent in SW DB
2273 : : * @new_parent: pointer to a new parent node
2274 : : * @node: pointer to a child node
2275 : : *
2276 : : * This function removes the child from the old parent and adds it to a new
2277 : : * parent
2278 : : */
2279 : : void
2280 : 0 : ice_sched_update_parent(struct ice_sched_node *new_parent,
2281 : : struct ice_sched_node *node)
2282 : : {
2283 : : struct ice_sched_node *old_parent;
2284 : : u16 i, j;
2285 : :
2286 : 0 : old_parent = node->parent;
2287 : :
2288 : : /* update the old parent children */
2289 [ # # ]: 0 : for (i = 0; i < old_parent->num_children; i++)
2290 [ # # ]: 0 : if (old_parent->children[i] == node) {
2291 [ # # ]: 0 : for (j = i + 1; j < old_parent->num_children; j++)
2292 : 0 : old_parent->children[j - 1] =
2293 : 0 : old_parent->children[j];
2294 : 0 : old_parent->num_children--;
2295 : 0 : break;
2296 : : }
2297 : :
2298 : : /* now move the node to a new parent */
2299 : 0 : new_parent->children[new_parent->num_children++] = node;
2300 : 0 : node->parent = new_parent;
2301 : 0 : node->info.parent_teid = new_parent->info.node_teid;
2302 : 0 : }
2303 : :
2304 : : /**
2305 : : * ice_sched_move_nodes - move child nodes to a given parent
2306 : : * @pi: port information structure
2307 : : * @parent: pointer to parent node
2308 : : * @num_items: number of child nodes to be moved
2309 : : * @list: pointer to child node teids
2310 : : *
2311 : : * This function move the child nodes to a given parent.
2312 : : */
2313 : : int
2314 : 0 : ice_sched_move_nodes(struct ice_port_info *pi, struct ice_sched_node *parent,
2315 : : u16 num_items, u32 *list)
2316 : : {
2317 : : struct ice_aqc_move_elem *buf;
2318 : : struct ice_sched_node *node;
2319 : 0 : u16 i, grps_movd = 0;
2320 : : struct ice_hw *hw;
2321 : : int status = 0;
2322 : : u16 buf_len;
2323 : :
2324 : 0 : hw = pi->hw;
2325 : :
2326 [ # # ]: 0 : if (!parent || !num_items)
2327 : : return ICE_ERR_PARAM;
2328 : :
2329 : : /* Does parent have enough space */
2330 : 0 : if (parent->num_children + num_items >
2331 [ # # ]: 0 : hw->max_children[parent->tx_sched_layer])
2332 : : return ICE_ERR_AQ_FULL;
2333 : :
2334 : : buf_len = ice_struct_size(buf, teid, 1);
2335 : 0 : buf = (struct ice_aqc_move_elem *)ice_malloc(hw, buf_len);
2336 [ # # ]: 0 : if (!buf)
2337 : : return ICE_ERR_NO_MEMORY;
2338 : :
2339 [ # # ]: 0 : for (i = 0; i < num_items; i++) {
2340 : 0 : node = ice_sched_find_node_by_teid(pi->root, list[i]);
2341 [ # # ]: 0 : if (!node) {
2342 : : status = ICE_ERR_PARAM;
2343 : 0 : goto move_err_exit;
2344 : : }
2345 : :
2346 : 0 : buf->hdr.src_parent_teid = node->info.parent_teid;
2347 : 0 : buf->hdr.dest_parent_teid = parent->info.node_teid;
2348 : 0 : buf->teid[0] = node->info.node_teid;
2349 : 0 : buf->hdr.num_elems = CPU_TO_LE16(1);
2350 : 0 : status = ice_aq_move_sched_elems(hw, 1, buf, buf_len,
2351 : : &grps_movd, NULL);
2352 [ # # # # ]: 0 : if (status && grps_movd != 1) {
2353 : : status = ICE_ERR_CFG;
2354 : 0 : goto move_err_exit;
2355 : : }
2356 : :
2357 : : /* update the SW DB */
2358 : 0 : ice_sched_update_parent(parent, node);
2359 : : }
2360 : :
2361 : 0 : move_err_exit:
2362 : 0 : ice_free(hw, buf);
2363 : 0 : return status;
2364 : : }
2365 : :
2366 : : /**
2367 : : * ice_sched_move_vsi_to_agg - move VSI to aggregator node
2368 : : * @pi: port information structure
2369 : : * @vsi_handle: software VSI handle
2370 : : * @agg_id: aggregator ID
2371 : : * @tc: TC number
2372 : : *
2373 : : * This function moves a VSI to an aggregator node or its subtree.
2374 : : * Intermediate nodes may be created if required.
2375 : : */
2376 : : static int
2377 : 0 : ice_sched_move_vsi_to_agg(struct ice_port_info *pi, u16 vsi_handle, u32 agg_id,
2378 : : u8 tc)
2379 : : {
2380 : : struct ice_sched_node *vsi_node, *agg_node, *tc_node, *parent;
2381 : 0 : u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
2382 : : u32 first_node_teid, vsi_teid;
2383 : : u16 num_nodes_added;
2384 : : u8 aggl, vsil;
2385 : : int status;
2386 : : u16 i;
2387 : :
2388 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
2389 [ # # ]: 0 : if (!tc_node)
2390 : : return ICE_ERR_CFG;
2391 : :
2392 : : agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
2393 [ # # ]: 0 : if (!agg_node)
2394 : : return ICE_ERR_DOES_NOT_EXIST;
2395 : :
2396 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
2397 [ # # ]: 0 : if (!vsi_node)
2398 : : return ICE_ERR_DOES_NOT_EXIST;
2399 : :
2400 : : /* Is this VSI already part of given aggregator? */
2401 [ # # ]: 0 : if (ice_sched_find_node_in_subtree(pi->hw, agg_node, vsi_node))
2402 : : return 0;
2403 : :
2404 [ # # ]: 0 : aggl = ice_sched_get_agg_layer(pi->hw);
2405 : : vsil = ice_sched_get_vsi_layer(pi->hw);
2406 : :
2407 : : /* set intermediate node count to 1 between aggregator and VSI layers */
2408 [ # # ]: 0 : for (i = aggl + 1; i < vsil; i++)
2409 : 0 : num_nodes[i] = 1;
2410 : :
2411 : : /* Check if the aggregator subtree has any free node to add the VSI */
2412 [ # # ]: 0 : for (i = 0; i < agg_node->num_children; i++) {
2413 : 0 : parent = ice_sched_get_free_vsi_parent(pi->hw,
2414 : 0 : agg_node->children[i],
2415 : : num_nodes);
2416 [ # # ]: 0 : if (parent)
2417 : 0 : goto move_nodes;
2418 : : }
2419 : :
2420 : : /* add new nodes */
2421 : : parent = agg_node;
2422 [ # # ]: 0 : for (i = aggl + 1; i < vsil; i++) {
2423 : 0 : status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
2424 : 0 : num_nodes[i],
2425 : : &first_node_teid,
2426 : : &num_nodes_added);
2427 [ # # # # ]: 0 : if (status || num_nodes[i] != num_nodes_added)
2428 : : return ICE_ERR_CFG;
2429 : :
2430 : : /* The newly added node can be a new parent for the next
2431 : : * layer nodes
2432 : : */
2433 [ # # ]: 0 : if (num_nodes_added)
2434 : 0 : parent = ice_sched_find_node_by_teid(tc_node,
2435 : : first_node_teid);
2436 : : else
2437 : 0 : parent = parent->children[0];
2438 : :
2439 [ # # ]: 0 : if (!parent)
2440 : : return ICE_ERR_CFG;
2441 : : }
2442 : :
2443 : 0 : move_nodes:
2444 : 0 : vsi_teid = LE32_TO_CPU(vsi_node->info.node_teid);
2445 : 0 : return ice_sched_move_nodes(pi, parent, 1, &vsi_teid);
2446 : : }
2447 : :
2448 : : /**
2449 : : * ice_move_all_vsi_to_dflt_agg - move all VSI(s) to default aggregator
2450 : : * @pi: port information structure
2451 : : * @agg_info: aggregator info
2452 : : * @tc: traffic class number
2453 : : * @rm_vsi_info: true or false
2454 : : *
2455 : : * This function move all the VSI(s) to the default aggregator and delete
2456 : : * aggregator VSI info based on passed in boolean parameter rm_vsi_info. The
2457 : : * caller holds the scheduler lock.
2458 : : */
2459 : : static int
2460 : 0 : ice_move_all_vsi_to_dflt_agg(struct ice_port_info *pi,
2461 : : struct ice_sched_agg_info *agg_info, u8 tc,
2462 : : bool rm_vsi_info)
2463 : : {
2464 : : struct ice_sched_agg_vsi_info *agg_vsi_info;
2465 : : struct ice_sched_agg_vsi_info *tmp;
2466 : : int status = 0;
2467 : :
2468 [ # # # # : 0 : LIST_FOR_EACH_ENTRY_SAFE(agg_vsi_info, tmp, &agg_info->agg_vsi_list,
# # # # #
# ]
2469 : : ice_sched_agg_vsi_info, list_entry) {
2470 : 0 : u16 vsi_handle = agg_vsi_info->vsi_handle;
2471 : :
2472 : : /* Move VSI to default aggregator */
2473 [ # # ]: 0 : if (!ice_is_tc_ena(agg_vsi_info->tc_bitmap[0], tc))
2474 : 0 : continue;
2475 : :
2476 : 0 : status = ice_sched_move_vsi_to_agg(pi, vsi_handle,
2477 : : ICE_DFLT_AGG_ID, tc);
2478 [ # # ]: 0 : if (status)
2479 : : break;
2480 : :
2481 [ # # ]: 0 : ice_clear_bit(tc, agg_vsi_info->tc_bitmap);
2482 [ # # # # ]: 0 : if (rm_vsi_info && !agg_vsi_info->tc_bitmap[0]) {
2483 [ # # ]: 0 : LIST_DEL(&agg_vsi_info->list_entry);
2484 : 0 : ice_free(pi->hw, agg_vsi_info);
2485 : : }
2486 : : }
2487 : :
2488 : 0 : return status;
2489 : : }
2490 : :
2491 : : /**
2492 : : * ice_sched_is_agg_inuse - check whether the aggregator is in use or not
2493 : : * @pi: port information structure
2494 : : * @node: node pointer
2495 : : *
2496 : : * This function checks whether the aggregator is attached with any VSI or not.
2497 : : */
2498 : : static bool
2499 : 0 : ice_sched_is_agg_inuse(struct ice_port_info *pi, struct ice_sched_node *node)
2500 : : {
2501 : : u8 vsil;
2502 : : u16 i;
2503 : :
2504 [ # # ]: 0 : vsil = ice_sched_get_vsi_layer(pi->hw);
2505 [ # # ]: 0 : if (node->tx_sched_layer < vsil - 1) {
2506 [ # # ]: 0 : for (i = 0; i < node->num_children; i++)
2507 [ # # ]: 0 : if (ice_sched_is_agg_inuse(pi, node->children[i]))
2508 : : return true;
2509 : : return false;
2510 : : } else {
2511 : 0 : return node->num_children ? true : false;
2512 : : }
2513 : : }
2514 : :
2515 : : /**
2516 : : * ice_sched_rm_agg_cfg - remove the aggregator node
2517 : : * @pi: port information structure
2518 : : * @agg_id: aggregator ID
2519 : : * @tc: TC number
2520 : : *
2521 : : * This function removes the aggregator node and intermediate nodes if any
2522 : : * from the given TC
2523 : : */
2524 : : static int
2525 : 0 : ice_sched_rm_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc)
2526 : : {
2527 : : struct ice_sched_node *tc_node, *agg_node;
2528 : 0 : struct ice_hw *hw = pi->hw;
2529 : :
2530 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
2531 [ # # ]: 0 : if (!tc_node)
2532 : : return ICE_ERR_CFG;
2533 : :
2534 : : agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
2535 [ # # ]: 0 : if (!agg_node)
2536 : : return ICE_ERR_DOES_NOT_EXIST;
2537 : :
2538 : : /* Can't remove the aggregator node if it has children */
2539 [ # # ]: 0 : if (ice_sched_is_agg_inuse(pi, agg_node))
2540 : : return ICE_ERR_IN_USE;
2541 : :
2542 : : /* need to remove the whole subtree if aggregator node is the
2543 : : * only child.
2544 : : */
2545 [ # # ]: 0 : while (agg_node->tx_sched_layer > hw->sw_entry_point_layer) {
2546 : 0 : struct ice_sched_node *parent = agg_node->parent;
2547 : :
2548 [ # # ]: 0 : if (!parent)
2549 : : return ICE_ERR_CFG;
2550 : :
2551 [ # # ]: 0 : if (parent->num_children > 1)
2552 : : break;
2553 : :
2554 : : agg_node = parent;
2555 : : }
2556 : :
2557 : 0 : ice_free_sched_node(pi, agg_node);
2558 : 0 : return 0;
2559 : : }
2560 : :
2561 : : /**
2562 : : * ice_rm_agg_cfg_tc - remove aggregator configuration for TC
2563 : : * @pi: port information structure
2564 : : * @agg_info: aggregator ID
2565 : : * @tc: TC number
2566 : : * @rm_vsi_info: bool value true or false
2567 : : *
2568 : : * This function removes aggregator reference to VSI of given TC. It removes
2569 : : * the aggregator configuration completely for requested TC. The caller needs
2570 : : * to hold the scheduler lock.
2571 : : */
2572 : : static int
2573 : 0 : ice_rm_agg_cfg_tc(struct ice_port_info *pi, struct ice_sched_agg_info *agg_info,
2574 : : u8 tc, bool rm_vsi_info)
2575 : : {
2576 : : int status = 0;
2577 : :
2578 : : /* If nothing to remove - return success */
2579 [ # # ]: 0 : if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
2580 : 0 : goto exit_rm_agg_cfg_tc;
2581 : :
2582 : 0 : status = ice_move_all_vsi_to_dflt_agg(pi, agg_info, tc, rm_vsi_info);
2583 [ # # ]: 0 : if (status)
2584 : 0 : goto exit_rm_agg_cfg_tc;
2585 : :
2586 : : /* Delete aggregator node(s) */
2587 : 0 : status = ice_sched_rm_agg_cfg(pi, agg_info->agg_id, tc);
2588 [ # # ]: 0 : if (status)
2589 : 0 : goto exit_rm_agg_cfg_tc;
2590 : :
2591 : 0 : ice_clear_bit(tc, agg_info->tc_bitmap);
2592 : 0 : exit_rm_agg_cfg_tc:
2593 : 0 : return status;
2594 : : }
2595 : :
2596 : : /**
2597 : : * ice_save_agg_tc_bitmap - save aggregator TC bitmap
2598 : : * @pi: port information structure
2599 : : * @agg_id: aggregator ID
2600 : : * @tc_bitmap: 8 bits TC bitmap
2601 : : *
2602 : : * Save aggregator TC bitmap. This function needs to be called with scheduler
2603 : : * lock held.
2604 : : */
2605 : : static int
2606 : 0 : ice_save_agg_tc_bitmap(struct ice_port_info *pi, u32 agg_id,
2607 : : ice_bitmap_t *tc_bitmap)
2608 : : {
2609 : : struct ice_sched_agg_info *agg_info;
2610 : :
2611 [ # # ]: 0 : agg_info = ice_get_agg_info(pi->hw, agg_id);
2612 [ # # ]: 0 : if (!agg_info)
2613 : : return ICE_ERR_PARAM;
2614 : 0 : ice_cp_bitmap(agg_info->replay_tc_bitmap, tc_bitmap,
2615 : : ICE_MAX_TRAFFIC_CLASS);
2616 : 0 : return 0;
2617 : : }
2618 : :
2619 : : /**
2620 : : * ice_sched_add_agg_cfg - create an aggregator node
2621 : : * @pi: port information structure
2622 : : * @agg_id: aggregator ID
2623 : : * @tc: TC number
2624 : : *
2625 : : * This function creates an aggregator node and intermediate nodes if required
2626 : : * for the given TC
2627 : : */
2628 : : static int
2629 : 0 : ice_sched_add_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc)
2630 : : {
2631 : : struct ice_sched_node *parent, *agg_node, *tc_node;
2632 : 0 : u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 };
2633 : 0 : struct ice_hw *hw = pi->hw;
2634 : : u32 first_node_teid;
2635 : : u16 num_nodes_added;
2636 : : int status = 0;
2637 : : u8 i, aggl;
2638 : :
2639 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
2640 [ # # ]: 0 : if (!tc_node)
2641 : : return ICE_ERR_CFG;
2642 : :
2643 : : agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
2644 : : /* Does Agg node already exist ? */
2645 [ # # ]: 0 : if (agg_node)
2646 : : return status;
2647 : :
2648 : : aggl = ice_sched_get_agg_layer(hw);
2649 : :
2650 : : /* need one node in Agg layer */
2651 : 0 : num_nodes[aggl] = 1;
2652 : :
2653 : : /* Check whether the intermediate nodes have space to add the
2654 : : * new aggregator. If they are full, then SW needs to allocate a new
2655 : : * intermediate node on those layers
2656 : : */
2657 [ # # ]: 0 : for (i = hw->sw_entry_point_layer; i < aggl; i++) {
2658 : 0 : parent = ice_sched_get_first_node(pi, tc_node, i);
2659 : :
2660 : : /* scan all the siblings */
2661 [ # # ]: 0 : while (parent) {
2662 [ # # ]: 0 : if (parent->num_children < hw->max_children[i])
2663 : : break;
2664 : 0 : parent = parent->sibling;
2665 : : }
2666 : :
2667 : : /* all the nodes are full, reserve one for this layer */
2668 [ # # ]: 0 : if (!parent)
2669 : 0 : num_nodes[i]++;
2670 : : }
2671 : :
2672 : : /* add the aggregator node */
2673 : : parent = tc_node;
2674 [ # # ]: 0 : for (i = hw->sw_entry_point_layer; i <= aggl; i++) {
2675 [ # # ]: 0 : if (!parent)
2676 : : return ICE_ERR_CFG;
2677 : :
2678 : 0 : status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i,
2679 : 0 : num_nodes[i],
2680 : : &first_node_teid,
2681 : : &num_nodes_added);
2682 [ # # # # ]: 0 : if (status || num_nodes[i] != num_nodes_added)
2683 : : return ICE_ERR_CFG;
2684 : :
2685 : : /* The newly added node can be a new parent for the next
2686 : : * layer nodes
2687 : : */
2688 [ # # ]: 0 : if (num_nodes_added) {
2689 : 0 : parent = ice_sched_find_node_by_teid(tc_node,
2690 : : first_node_teid);
2691 : : /* register aggregator ID with the aggregator node */
2692 [ # # ]: 0 : if (parent && i == aggl)
2693 : 0 : parent->agg_id = agg_id;
2694 : : } else {
2695 : 0 : parent = parent->children[0];
2696 : : }
2697 : : }
2698 : :
2699 : : return 0;
2700 : : }
2701 : :
2702 : : /**
2703 : : * ice_sched_cfg_agg - configure aggregator node
2704 : : * @pi: port information structure
2705 : : * @agg_id: aggregator ID
2706 : : * @agg_type: aggregator type queue, VSI, or aggregator group
2707 : : * @tc_bitmap: bits TC bitmap
2708 : : *
2709 : : * It registers a unique aggregator node into scheduler services. It
2710 : : * allows a user to register with a unique ID to track it's resources.
2711 : : * The aggregator type determines if this is a queue group, VSI group
2712 : : * or aggregator group. It then creates the aggregator node(s) for requested
2713 : : * TC(s) or removes an existing aggregator node including its configuration
2714 : : * if indicated via tc_bitmap. Call ice_rm_agg_cfg to release aggregator
2715 : : * resources and remove aggregator ID.
2716 : : * This function needs to be called with scheduler lock held.
2717 : : */
2718 : : static int
2719 : 0 : ice_sched_cfg_agg(struct ice_port_info *pi, u32 agg_id,
2720 : : enum ice_agg_type agg_type, ice_bitmap_t *tc_bitmap)
2721 : : {
2722 : : struct ice_sched_agg_info *agg_info;
2723 [ # # ]: 0 : struct ice_hw *hw = pi->hw;
2724 : : int status = 0;
2725 : : u8 tc;
2726 : :
2727 : : agg_info = ice_get_agg_info(hw, agg_id);
2728 [ # # ]: 0 : if (!agg_info) {
2729 : : /* Create new entry for new aggregator ID */
2730 : : agg_info = (struct ice_sched_agg_info *)
2731 : 0 : ice_malloc(hw, sizeof(*agg_info));
2732 [ # # ]: 0 : if (!agg_info)
2733 : : return ICE_ERR_NO_MEMORY;
2734 : :
2735 : 0 : agg_info->agg_id = agg_id;
2736 : 0 : agg_info->agg_type = agg_type;
2737 : 0 : agg_info->tc_bitmap[0] = 0;
2738 : :
2739 : : /* Initialize the aggregator VSI list head */
2740 : 0 : INIT_LIST_HEAD(&agg_info->agg_vsi_list);
2741 : :
2742 : : /* Add new entry in aggregator list */
2743 [ # # ]: 0 : LIST_ADD(&agg_info->list_entry, &hw->agg_list);
2744 : : }
2745 : : /* Create aggregator node(s) for requested TC(s) */
2746 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
2747 [ # # ]: 0 : if (!ice_is_tc_ena(*tc_bitmap, tc)) {
2748 : : /* Delete aggregator cfg TC if it exists previously */
2749 : 0 : status = ice_rm_agg_cfg_tc(pi, agg_info, tc, false);
2750 [ # # ]: 0 : if (status)
2751 : : break;
2752 : 0 : continue;
2753 : : }
2754 : :
2755 : : /* Check if aggregator node for TC already exists */
2756 [ # # ]: 0 : if (ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
2757 : 0 : continue;
2758 : :
2759 : : /* Create new aggregator node for TC */
2760 : 0 : status = ice_sched_add_agg_cfg(pi, agg_id, tc);
2761 [ # # ]: 0 : if (status)
2762 : : break;
2763 : :
2764 : : /* Save aggregator node's TC information */
2765 : 0 : ice_set_bit(tc, agg_info->tc_bitmap);
2766 : : }
2767 : :
2768 : : return status;
2769 : : }
2770 : :
2771 : : /**
2772 : : * ice_cfg_agg - config aggregator node
2773 : : * @pi: port information structure
2774 : : * @agg_id: aggregator ID
2775 : : * @agg_type: aggregator type queue, VSI, or aggregator group
2776 : : * @tc_bitmap: bits TC bitmap
2777 : : *
2778 : : * This function configures aggregator node(s).
2779 : : */
2780 : : int
2781 : 0 : ice_cfg_agg(struct ice_port_info *pi, u32 agg_id, enum ice_agg_type agg_type,
2782 : : u8 tc_bitmap)
2783 : : {
2784 : 0 : ice_bitmap_t bitmap = tc_bitmap;
2785 : : int status;
2786 : :
2787 : 0 : ice_acquire_lock(&pi->sched_lock);
2788 : 0 : status = ice_sched_cfg_agg(pi, agg_id, agg_type,
2789 : : (ice_bitmap_t *)&bitmap);
2790 [ # # ]: 0 : if (!status)
2791 : 0 : status = ice_save_agg_tc_bitmap(pi, agg_id,
2792 : : (ice_bitmap_t *)&bitmap);
2793 : : ice_release_lock(&pi->sched_lock);
2794 : 0 : return status;
2795 : : }
2796 : :
2797 : : /**
2798 : : * ice_get_agg_vsi_info - get the aggregator ID
2799 : : * @agg_info: aggregator info
2800 : : * @vsi_handle: software VSI handle
2801 : : *
2802 : : * The function returns aggregator VSI info based on VSI handle. This function
2803 : : * needs to be called with scheduler lock held.
2804 : : */
2805 : : static struct ice_sched_agg_vsi_info *
2806 : : ice_get_agg_vsi_info(struct ice_sched_agg_info *agg_info, u16 vsi_handle)
2807 : : {
2808 : : struct ice_sched_agg_vsi_info *agg_vsi_info;
2809 : :
2810 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(agg_vsi_info, &agg_info->agg_vsi_list,
# # # # #
# # # # #
# # # # #
# # # #
# ]
2811 : : ice_sched_agg_vsi_info, list_entry)
2812 [ # # # # : 0 : if (agg_vsi_info->vsi_handle == vsi_handle)
# # # # ]
2813 : : return agg_vsi_info;
2814 : :
2815 : : return NULL;
2816 : : }
2817 : :
2818 : : /**
2819 : : * ice_get_vsi_agg_info - get the aggregator info of VSI
2820 : : * @hw: pointer to the hardware structure
2821 : : * @vsi_handle: Sw VSI handle
2822 : : *
2823 : : * The function returns aggregator info of VSI represented via vsi_handle. The
2824 : : * VSI has in this case a different aggregator than the default one. This
2825 : : * function needs to be called with scheduler lock held.
2826 : : */
2827 : : static struct ice_sched_agg_info *
2828 : 0 : ice_get_vsi_agg_info(struct ice_hw *hw, u16 vsi_handle)
2829 : : {
2830 : : struct ice_sched_agg_info *agg_info;
2831 : :
2832 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
# # ]
2833 : : list_entry) {
2834 : : struct ice_sched_agg_vsi_info *agg_vsi_info;
2835 : :
2836 : : agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
2837 [ # # ]: 0 : if (agg_vsi_info)
2838 : 0 : return agg_info;
2839 : : }
2840 : : return NULL;
2841 : : }
2842 : :
2843 : : /**
2844 : : * ice_save_agg_vsi_tc_bitmap - save aggregator VSI TC bitmap
2845 : : * @pi: port information structure
2846 : : * @agg_id: aggregator ID
2847 : : * @vsi_handle: software VSI handle
2848 : : * @tc_bitmap: TC bitmap of enabled TC(s)
2849 : : *
2850 : : * Save VSI to aggregator TC bitmap. This function needs to call with scheduler
2851 : : * lock held.
2852 : : */
2853 : : static int
2854 : 0 : ice_save_agg_vsi_tc_bitmap(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle,
2855 : : ice_bitmap_t *tc_bitmap)
2856 : : {
2857 : : struct ice_sched_agg_vsi_info *agg_vsi_info;
2858 : : struct ice_sched_agg_info *agg_info;
2859 : :
2860 [ # # ]: 0 : agg_info = ice_get_agg_info(pi->hw, agg_id);
2861 [ # # ]: 0 : if (!agg_info)
2862 : : return ICE_ERR_PARAM;
2863 : : /* check if entry already exist */
2864 : : agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
2865 [ # # ]: 0 : if (!agg_vsi_info)
2866 : : return ICE_ERR_PARAM;
2867 : 0 : ice_cp_bitmap(agg_vsi_info->replay_tc_bitmap, tc_bitmap,
2868 : : ICE_MAX_TRAFFIC_CLASS);
2869 : 0 : return 0;
2870 : : }
2871 : :
2872 : : /**
2873 : : * ice_sched_assoc_vsi_to_agg - associate/move VSI to new/default aggregator
2874 : : * @pi: port information structure
2875 : : * @agg_id: aggregator ID
2876 : : * @vsi_handle: software VSI handle
2877 : : * @tc_bitmap: TC bitmap of enabled TC(s)
2878 : : *
2879 : : * This function moves VSI to a new or default aggregator node. If VSI is
2880 : : * already associated to the aggregator node then no operation is performed on
2881 : : * the tree. This function needs to be called with scheduler lock held.
2882 : : */
2883 : : static int
2884 : 0 : ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
2885 : : u16 vsi_handle, ice_bitmap_t *tc_bitmap)
2886 : : {
2887 : : struct ice_sched_agg_vsi_info *agg_vsi_info, *old_agg_vsi_info = NULL;
2888 : : struct ice_sched_agg_info *agg_info, *old_agg_info;
2889 : 0 : struct ice_hw *hw = pi->hw;
2890 : : int status = 0;
2891 : : u8 tc;
2892 : :
2893 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
2894 : : return ICE_ERR_PARAM;
2895 : : agg_info = ice_get_agg_info(hw, agg_id);
2896 [ # # ]: 0 : if (!agg_info)
2897 : : return ICE_ERR_PARAM;
2898 : : /* If the vsi is already part of another aggregator then update
2899 : : * its vsi info list
2900 : : */
2901 : 0 : old_agg_info = ice_get_vsi_agg_info(hw, vsi_handle);
2902 [ # # ]: 0 : if (old_agg_info && old_agg_info != agg_info) {
2903 : : struct ice_sched_agg_vsi_info *vtmp;
2904 : :
2905 [ # # # # : 0 : LIST_FOR_EACH_ENTRY_SAFE(old_agg_vsi_info, vtmp,
# # # # #
# ]
2906 : : &old_agg_info->agg_vsi_list,
2907 : : ice_sched_agg_vsi_info, list_entry)
2908 [ # # ]: 0 : if (old_agg_vsi_info->vsi_handle == vsi_handle)
2909 : : break;
2910 : : }
2911 : :
2912 : : /* check if entry already exist */
2913 : : agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
2914 [ # # ]: 0 : if (!agg_vsi_info) {
2915 : : /* Create new entry for VSI under aggregator list */
2916 : : agg_vsi_info = (struct ice_sched_agg_vsi_info *)
2917 : 0 : ice_malloc(hw, sizeof(*agg_vsi_info));
2918 [ # # ]: 0 : if (!agg_vsi_info)
2919 : : return ICE_ERR_PARAM;
2920 : :
2921 : : /* add VSI ID into the aggregator list */
2922 : 0 : agg_vsi_info->vsi_handle = vsi_handle;
2923 [ # # ]: 0 : LIST_ADD(&agg_vsi_info->list_entry, &agg_info->agg_vsi_list);
2924 : : }
2925 : : /* Move VSI node to new aggregator node for requested TC(s) */
2926 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
2927 [ # # ]: 0 : if (!ice_is_tc_ena(*tc_bitmap, tc))
2928 : 0 : continue;
2929 : :
2930 : : /* Move VSI to new aggregator */
2931 : 0 : status = ice_sched_move_vsi_to_agg(pi, vsi_handle, agg_id, tc);
2932 [ # # ]: 0 : if (status)
2933 : : break;
2934 : :
2935 [ # # ]: 0 : ice_set_bit(tc, agg_vsi_info->tc_bitmap);
2936 [ # # ]: 0 : if (old_agg_vsi_info)
2937 : 0 : ice_clear_bit(tc, old_agg_vsi_info->tc_bitmap);
2938 : : }
2939 [ # # # # ]: 0 : if (old_agg_vsi_info && !old_agg_vsi_info->tc_bitmap[0]) {
2940 [ # # ]: 0 : LIST_DEL(&old_agg_vsi_info->list_entry);
2941 : 0 : ice_free(pi->hw, old_agg_vsi_info);
2942 : : }
2943 : : return status;
2944 : : }
2945 : :
2946 : : /**
2947 : : * ice_sched_rm_unused_rl_prof - remove unused RL profile
2948 : : * @hw: pointer to the hardware structure
2949 : : *
2950 : : * This function removes unused rate limit profiles from the HW and
2951 : : * SW DB. The caller needs to hold scheduler lock.
2952 : : */
2953 : 0 : static void ice_sched_rm_unused_rl_prof(struct ice_hw *hw)
2954 : : {
2955 : : u16 ln;
2956 : :
2957 [ # # ]: 0 : for (ln = 0; ln < hw->num_tx_sched_layers; ln++) {
2958 : : struct ice_aqc_rl_profile_info *rl_prof_elem;
2959 : : struct ice_aqc_rl_profile_info *rl_prof_tmp;
2960 : :
2961 [ # # # # : 0 : LIST_FOR_EACH_ENTRY_SAFE(rl_prof_elem, rl_prof_tmp,
# # # # #
# # # ]
2962 : : &hw->rl_prof_list[ln],
2963 : : ice_aqc_rl_profile_info, list_entry) {
2964 [ # # ]: 0 : if (!ice_sched_del_rl_profile(hw, rl_prof_elem))
2965 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "Removed rl profile\n");
2966 : : }
2967 : : }
2968 : 0 : }
2969 : :
2970 : : /**
2971 : : * ice_sched_update_elem - update element
2972 : : * @hw: pointer to the HW struct
2973 : : * @node: pointer to node
2974 : : * @info: node info to update
2975 : : *
2976 : : * Update the HW DB, and local SW DB of node. Update the scheduling
2977 : : * parameters of node from argument info data buffer (Info->data buf) and
2978 : : * returns success or error on config sched element failure. The caller
2979 : : * needs to hold scheduler lock.
2980 : : */
2981 : : static int
2982 : 0 : ice_sched_update_elem(struct ice_hw *hw, struct ice_sched_node *node,
2983 : : struct ice_aqc_txsched_elem_data *info)
2984 : : {
2985 : : struct ice_aqc_txsched_elem_data buf;
2986 : 0 : u16 elem_cfgd = 0;
2987 : : u16 num_elems = 1;
2988 : : int status;
2989 : :
2990 : 0 : buf = *info;
2991 : : /* For TC nodes, CIR config is not supported */
2992 [ # # ]: 0 : if (node->info.data.elem_type == ICE_AQC_ELEM_TYPE_TC)
2993 : 0 : buf.data.valid_sections &= ~ICE_AQC_ELEM_VALID_CIR;
2994 : : /* Parent TEID is reserved field in this aq call */
2995 : 0 : buf.parent_teid = 0;
2996 : : /* Element type is reserved field in this aq call */
2997 : 0 : buf.data.elem_type = 0;
2998 : : /* Flags is reserved field in this aq call */
2999 : 0 : buf.data.flags = 0;
3000 : :
3001 : : /* Update HW DB */
3002 : : /* Configure element node */
3003 : : status = ice_aq_cfg_sched_elems(hw, num_elems, &buf, sizeof(buf),
3004 : : &elem_cfgd, NULL);
3005 [ # # # # ]: 0 : if (status || elem_cfgd != num_elems) {
3006 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "Config sched elem error\n");
3007 : 0 : return ICE_ERR_CFG;
3008 : : }
3009 : :
3010 : : /* Config success case */
3011 : : /* Now update local SW DB */
3012 : : /* Only copy the data portion of info buffer */
3013 : 0 : node->info.data = info->data;
3014 : 0 : return status;
3015 : : }
3016 : :
3017 : : /**
3018 : : * ice_sched_cfg_node_bw_alloc - configure node BW weight/alloc params
3019 : : * @hw: pointer to the HW struct
3020 : : * @node: sched node to configure
3021 : : * @rl_type: rate limit type CIR, EIR, or shared
3022 : : * @bw_alloc: BW weight/allocation
3023 : : *
3024 : : * This function configures node element's BW allocation.
3025 : : */
3026 : : int
3027 : 0 : ice_sched_cfg_node_bw_alloc(struct ice_hw *hw, struct ice_sched_node *node,
3028 : : enum ice_rl_type rl_type, u16 bw_alloc)
3029 : : {
3030 : : struct ice_aqc_txsched_elem_data buf;
3031 : : struct ice_aqc_txsched_elem *data;
3032 : : int status;
3033 : :
3034 : 0 : buf = node->info;
3035 : : data = &buf.data;
3036 [ # # ]: 0 : if (rl_type == ICE_MIN_BW) {
3037 : 0 : data->valid_sections |= ICE_AQC_ELEM_VALID_CIR;
3038 : 0 : data->cir_bw.bw_alloc = CPU_TO_LE16(bw_alloc);
3039 [ # # ]: 0 : } else if (rl_type == ICE_MAX_BW) {
3040 : 0 : data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
3041 : 0 : data->eir_bw.bw_alloc = CPU_TO_LE16(bw_alloc);
3042 : : } else {
3043 : : return ICE_ERR_PARAM;
3044 : : }
3045 : :
3046 : : /* Configure element */
3047 : 0 : status = ice_sched_update_elem(hw, node, &buf);
3048 : 0 : return status;
3049 : : }
3050 : :
3051 : : /**
3052 : : * ice_move_vsi_to_agg - moves VSI to new or default aggregator
3053 : : * @pi: port information structure
3054 : : * @agg_id: aggregator ID
3055 : : * @vsi_handle: software VSI handle
3056 : : * @tc_bitmap: TC bitmap of enabled TC(s)
3057 : : *
3058 : : * Move or associate VSI to a new or default aggregator node.
3059 : : */
3060 : : int
3061 : 0 : ice_move_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle,
3062 : : u8 tc_bitmap)
3063 : : {
3064 : 0 : ice_bitmap_t bitmap = tc_bitmap;
3065 : : int status;
3066 : :
3067 : 0 : ice_acquire_lock(&pi->sched_lock);
3068 : 0 : status = ice_sched_assoc_vsi_to_agg(pi, agg_id, vsi_handle,
3069 : : (ice_bitmap_t *)&bitmap);
3070 [ # # ]: 0 : if (!status)
3071 : 0 : status = ice_save_agg_vsi_tc_bitmap(pi, agg_id, vsi_handle,
3072 : : (ice_bitmap_t *)&bitmap);
3073 : : ice_release_lock(&pi->sched_lock);
3074 : 0 : return status;
3075 : : }
3076 : :
3077 : : /**
3078 : : * ice_rm_agg_cfg - remove aggregator configuration
3079 : : * @pi: port information structure
3080 : : * @agg_id: aggregator ID
3081 : : *
3082 : : * This function removes aggregator reference to VSI and delete aggregator ID
3083 : : * info. It removes the aggregator configuration completely.
3084 : : */
3085 : 0 : int ice_rm_agg_cfg(struct ice_port_info *pi, u32 agg_id)
3086 : : {
3087 : : struct ice_sched_agg_info *agg_info;
3088 : : int status = 0;
3089 : : u8 tc;
3090 : :
3091 : 0 : ice_acquire_lock(&pi->sched_lock);
3092 [ # # ]: 0 : agg_info = ice_get_agg_info(pi->hw, agg_id);
3093 [ # # ]: 0 : if (!agg_info) {
3094 : : status = ICE_ERR_DOES_NOT_EXIST;
3095 : 0 : goto exit_ice_rm_agg_cfg;
3096 : : }
3097 : :
3098 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
3099 : 0 : status = ice_rm_agg_cfg_tc(pi, agg_info, tc, true);
3100 [ # # ]: 0 : if (status)
3101 : 0 : goto exit_ice_rm_agg_cfg;
3102 : : }
3103 : :
3104 [ # # ]: 0 : if (ice_is_any_bit_set(agg_info->tc_bitmap, ICE_MAX_TRAFFIC_CLASS)) {
3105 : : status = ICE_ERR_IN_USE;
3106 : 0 : goto exit_ice_rm_agg_cfg;
3107 : : }
3108 : :
3109 : : /* Safe to delete entry now */
3110 [ # # ]: 0 : LIST_DEL(&agg_info->list_entry);
3111 : 0 : ice_free(pi->hw, agg_info);
3112 : :
3113 : : /* Remove unused RL profile IDs from HW and SW DB */
3114 : 0 : ice_sched_rm_unused_rl_prof(pi->hw);
3115 : :
3116 : 0 : exit_ice_rm_agg_cfg:
3117 : : ice_release_lock(&pi->sched_lock);
3118 : 0 : return status;
3119 : : }
3120 : :
3121 : : /**
3122 : : * ice_set_clear_cir_bw_alloc - set or clear CIR BW alloc information
3123 : : * @bw_t_info: bandwidth type information structure
3124 : : * @bw_alloc: Bandwidth allocation information
3125 : : *
3126 : : * Save or clear CIR BW alloc information (bw_alloc) in the passed param
3127 : : * bw_t_info.
3128 : : */
3129 : : static void
3130 : : ice_set_clear_cir_bw_alloc(struct ice_bw_type_info *bw_t_info, u16 bw_alloc)
3131 : : {
3132 : 0 : bw_t_info->cir_bw.bw_alloc = bw_alloc;
3133 : 0 : if (bw_t_info->cir_bw.bw_alloc)
3134 : : ice_set_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap);
3135 : : else
3136 : : ice_clear_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap);
3137 : : }
3138 : :
3139 : : /**
3140 : : * ice_set_clear_eir_bw_alloc - set or clear EIR BW alloc information
3141 : : * @bw_t_info: bandwidth type information structure
3142 : : * @bw_alloc: Bandwidth allocation information
3143 : : *
3144 : : * Save or clear EIR BW alloc information (bw_alloc) in the passed param
3145 : : * bw_t_info.
3146 : : */
3147 : : static void
3148 : : ice_set_clear_eir_bw_alloc(struct ice_bw_type_info *bw_t_info, u16 bw_alloc)
3149 : : {
3150 : 0 : bw_t_info->eir_bw.bw_alloc = bw_alloc;
3151 : 0 : if (bw_t_info->eir_bw.bw_alloc)
3152 : : ice_set_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap);
3153 : : else
3154 : : ice_clear_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap);
3155 : : }
3156 : :
3157 : : /**
3158 : : * ice_sched_save_vsi_bw_alloc - save VSI node's BW alloc information
3159 : : * @pi: port information structure
3160 : : * @vsi_handle: sw VSI handle
3161 : : * @tc: traffic class
3162 : : * @rl_type: rate limit type min or max
3163 : : * @bw_alloc: Bandwidth allocation information
3164 : : *
3165 : : * Save BW alloc information of VSI type node for post replay use.
3166 : : */
3167 : : static int
3168 : 0 : ice_sched_save_vsi_bw_alloc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
3169 : : enum ice_rl_type rl_type, u16 bw_alloc)
3170 : : {
3171 : : struct ice_vsi_ctx *vsi_ctx;
3172 : :
3173 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
3174 : : return ICE_ERR_PARAM;
3175 : 0 : vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
3176 [ # # ]: 0 : if (!vsi_ctx)
3177 : : return ICE_ERR_PARAM;
3178 [ # # # ]: 0 : switch (rl_type) {
3179 : 0 : case ICE_MIN_BW:
3180 [ # # ]: 0 : ice_set_clear_cir_bw_alloc(&vsi_ctx->sched.bw_t_info[tc],
3181 : : bw_alloc);
3182 : : break;
3183 : 0 : case ICE_MAX_BW:
3184 [ # # ]: 0 : ice_set_clear_eir_bw_alloc(&vsi_ctx->sched.bw_t_info[tc],
3185 : : bw_alloc);
3186 : : break;
3187 : : default:
3188 : : return ICE_ERR_PARAM;
3189 : : }
3190 : : return 0;
3191 : : }
3192 : :
3193 : : /**
3194 : : * ice_set_clear_cir_bw - set or clear CIR BW
3195 : : * @bw_t_info: bandwidth type information structure
3196 : : * @bw: bandwidth in Kbps - Kilo bits per sec
3197 : : *
3198 : : * Save or clear CIR bandwidth (BW) in the passed param bw_t_info.
3199 : : */
3200 : : static void ice_set_clear_cir_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
3201 : : {
3202 : 0 : if (bw == ICE_SCHED_DFLT_BW) {
3203 : : ice_clear_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap);
3204 : 0 : bw_t_info->cir_bw.bw = 0;
3205 : : } else {
3206 : : /* Save type of BW information */
3207 : : ice_set_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap);
3208 : 0 : bw_t_info->cir_bw.bw = bw;
3209 : : }
3210 : : }
3211 : :
3212 : : /**
3213 : : * ice_set_clear_eir_bw - set or clear EIR BW
3214 : : * @bw_t_info: bandwidth type information structure
3215 : : * @bw: bandwidth in Kbps - Kilo bits per sec
3216 : : *
3217 : : * Save or clear EIR bandwidth (BW) in the passed param bw_t_info.
3218 : : */
3219 : : static void ice_set_clear_eir_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
3220 : : {
3221 : 0 : if (bw == ICE_SCHED_DFLT_BW) {
3222 : : ice_clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
3223 : 0 : bw_t_info->eir_bw.bw = 0;
3224 : : } else {
3225 : : /* save EIR BW information */
3226 : : ice_set_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap);
3227 : 0 : bw_t_info->eir_bw.bw = bw;
3228 : : }
3229 : : }
3230 : :
3231 : : /**
3232 : : * ice_set_clear_shared_bw - set or clear shared BW
3233 : : * @bw_t_info: bandwidth type information structure
3234 : : * @bw: bandwidth in Kbps - Kilo bits per sec
3235 : : *
3236 : : * Save or clear shared bandwidth (BW) in the passed param bw_t_info.
3237 : : */
3238 : : static void ice_set_clear_shared_bw(struct ice_bw_type_info *bw_t_info, u32 bw)
3239 : : {
3240 : 0 : if (bw == ICE_SCHED_DFLT_BW) {
3241 : : ice_clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
3242 : 0 : bw_t_info->shared_bw = 0;
3243 : : } else {
3244 : : /* save shared BW information */
3245 : : ice_set_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap);
3246 : 0 : bw_t_info->shared_bw = bw;
3247 : : }
3248 : : }
3249 : :
3250 : : /**
3251 : : * ice_sched_save_vsi_bw - save VSI node's BW information
3252 : : * @pi: port information structure
3253 : : * @vsi_handle: sw VSI handle
3254 : : * @tc: traffic class
3255 : : * @rl_type: rate limit type min, max, or shared
3256 : : * @bw: bandwidth in Kbps - Kilo bits per sec
3257 : : *
3258 : : * Save BW information of VSI type node for post replay use.
3259 : : */
3260 : : static int
3261 : 0 : ice_sched_save_vsi_bw(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
3262 : : enum ice_rl_type rl_type, u32 bw)
3263 : : {
3264 : : struct ice_vsi_ctx *vsi_ctx;
3265 : :
3266 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
3267 : : return ICE_ERR_PARAM;
3268 : 0 : vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
3269 [ # # ]: 0 : if (!vsi_ctx)
3270 : : return ICE_ERR_PARAM;
3271 [ # # # # ]: 0 : switch (rl_type) {
3272 : 0 : case ICE_MIN_BW:
3273 [ # # ]: 0 : ice_set_clear_cir_bw(&vsi_ctx->sched.bw_t_info[tc], bw);
3274 : : break;
3275 : 0 : case ICE_MAX_BW:
3276 [ # # ]: 0 : ice_set_clear_eir_bw(&vsi_ctx->sched.bw_t_info[tc], bw);
3277 : : break;
3278 : 0 : case ICE_SHARED_BW:
3279 [ # # ]: 0 : ice_set_clear_shared_bw(&vsi_ctx->sched.bw_t_info[tc], bw);
3280 : : break;
3281 : : default:
3282 : : return ICE_ERR_PARAM;
3283 : : }
3284 : : return 0;
3285 : : }
3286 : :
3287 : : /**
3288 : : * ice_set_clear_prio - set or clear priority information
3289 : : * @bw_t_info: bandwidth type information structure
3290 : : * @prio: priority to save
3291 : : *
3292 : : * Save or clear priority (prio) in the passed param bw_t_info.
3293 : : */
3294 : : static void ice_set_clear_prio(struct ice_bw_type_info *bw_t_info, u8 prio)
3295 : : {
3296 : 0 : bw_t_info->generic = prio;
3297 : 0 : if (bw_t_info->generic)
3298 : : ice_set_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap);
3299 : : else
3300 : : ice_clear_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap);
3301 : : }
3302 : :
3303 : : /**
3304 : : * ice_sched_save_vsi_prio - save VSI node's priority information
3305 : : * @pi: port information structure
3306 : : * @vsi_handle: Software VSI handle
3307 : : * @tc: traffic class
3308 : : * @prio: priority to save
3309 : : *
3310 : : * Save priority information of VSI type node for post replay use.
3311 : : */
3312 : : static int
3313 : 0 : ice_sched_save_vsi_prio(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
3314 : : u8 prio)
3315 : : {
3316 : : struct ice_vsi_ctx *vsi_ctx;
3317 : :
3318 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
3319 : : return ICE_ERR_PARAM;
3320 : 0 : vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
3321 [ # # ]: 0 : if (!vsi_ctx)
3322 : : return ICE_ERR_PARAM;
3323 [ # # ]: 0 : if (tc >= ICE_MAX_TRAFFIC_CLASS)
3324 : : return ICE_ERR_PARAM;
3325 [ # # ]: 0 : ice_set_clear_prio(&vsi_ctx->sched.bw_t_info[tc], prio);
3326 : : return 0;
3327 : : }
3328 : :
3329 : : /**
3330 : : * ice_sched_save_agg_bw_alloc - save aggregator node's BW alloc information
3331 : : * @pi: port information structure
3332 : : * @agg_id: node aggregator ID
3333 : : * @tc: traffic class
3334 : : * @rl_type: rate limit type min or max
3335 : : * @bw_alloc: bandwidth alloc information
3336 : : *
3337 : : * Save BW alloc information of AGG type node for post replay use.
3338 : : */
3339 : : static int
3340 : 0 : ice_sched_save_agg_bw_alloc(struct ice_port_info *pi, u32 agg_id, u8 tc,
3341 : : enum ice_rl_type rl_type, u16 bw_alloc)
3342 : : {
3343 : : struct ice_sched_agg_info *agg_info;
3344 : :
3345 [ # # ]: 0 : agg_info = ice_get_agg_info(pi->hw, agg_id);
3346 [ # # ]: 0 : if (!agg_info)
3347 : : return ICE_ERR_PARAM;
3348 [ # # ]: 0 : if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
3349 : : return ICE_ERR_PARAM;
3350 [ # # # ]: 0 : switch (rl_type) {
3351 : 0 : case ICE_MIN_BW:
3352 [ # # ]: 0 : ice_set_clear_cir_bw_alloc(&agg_info->bw_t_info[tc], bw_alloc);
3353 : : break;
3354 : 0 : case ICE_MAX_BW:
3355 [ # # ]: 0 : ice_set_clear_eir_bw_alloc(&agg_info->bw_t_info[tc], bw_alloc);
3356 : : break;
3357 : : default:
3358 : : return ICE_ERR_PARAM;
3359 : : }
3360 : : return 0;
3361 : : }
3362 : :
3363 : : /**
3364 : : * ice_sched_save_agg_bw - save aggregator node's BW information
3365 : : * @pi: port information structure
3366 : : * @agg_id: node aggregator ID
3367 : : * @tc: traffic class
3368 : : * @rl_type: rate limit type min, max, or shared
3369 : : * @bw: bandwidth in Kbps - Kilo bits per sec
3370 : : *
3371 : : * Save BW information of AGG type node for post replay use.
3372 : : */
3373 : : static int
3374 : 0 : ice_sched_save_agg_bw(struct ice_port_info *pi, u32 agg_id, u8 tc,
3375 : : enum ice_rl_type rl_type, u32 bw)
3376 : : {
3377 : : struct ice_sched_agg_info *agg_info;
3378 : :
3379 [ # # ]: 0 : agg_info = ice_get_agg_info(pi->hw, agg_id);
3380 [ # # ]: 0 : if (!agg_info)
3381 : : return ICE_ERR_PARAM;
3382 [ # # ]: 0 : if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc))
3383 : : return ICE_ERR_PARAM;
3384 [ # # # # ]: 0 : switch (rl_type) {
3385 : 0 : case ICE_MIN_BW:
3386 [ # # ]: 0 : ice_set_clear_cir_bw(&agg_info->bw_t_info[tc], bw);
3387 : : break;
3388 : 0 : case ICE_MAX_BW:
3389 [ # # ]: 0 : ice_set_clear_eir_bw(&agg_info->bw_t_info[tc], bw);
3390 : : break;
3391 : 0 : case ICE_SHARED_BW:
3392 [ # # ]: 0 : ice_set_clear_shared_bw(&agg_info->bw_t_info[tc], bw);
3393 : : break;
3394 : : default:
3395 : : return ICE_ERR_PARAM;
3396 : : }
3397 : : return 0;
3398 : : }
3399 : :
3400 : : /**
3401 : : * ice_cfg_vsi_bw_lmt_per_tc - configure VSI BW limit per TC
3402 : : * @pi: port information structure
3403 : : * @vsi_handle: software VSI handle
3404 : : * @tc: traffic class
3405 : : * @rl_type: min or max
3406 : : * @bw: bandwidth in Kbps
3407 : : *
3408 : : * This function configures BW limit of VSI scheduling node based on TC
3409 : : * information.
3410 : : */
3411 : : int
3412 : 0 : ice_cfg_vsi_bw_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
3413 : : enum ice_rl_type rl_type, u32 bw)
3414 : : {
3415 : : int status;
3416 : :
3417 : 0 : status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle,
3418 : : ICE_AGG_TYPE_VSI,
3419 : : tc, rl_type, bw);
3420 [ # # ]: 0 : if (!status) {
3421 : 0 : ice_acquire_lock(&pi->sched_lock);
3422 : 0 : status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, bw);
3423 : : ice_release_lock(&pi->sched_lock);
3424 : : }
3425 : 0 : return status;
3426 : : }
3427 : :
3428 : : /**
3429 : : * ice_cfg_vsi_bw_dflt_lmt_per_tc - configure default VSI BW limit per TC
3430 : : * @pi: port information structure
3431 : : * @vsi_handle: software VSI handle
3432 : : * @tc: traffic class
3433 : : * @rl_type: min or max
3434 : : *
3435 : : * This function configures default BW limit of VSI scheduling node based on TC
3436 : : * information.
3437 : : */
3438 : : int
3439 : 0 : ice_cfg_vsi_bw_dflt_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
3440 : : enum ice_rl_type rl_type)
3441 : : {
3442 : : int status;
3443 : :
3444 : 0 : status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle,
3445 : : ICE_AGG_TYPE_VSI,
3446 : : tc, rl_type,
3447 : : ICE_SCHED_DFLT_BW);
3448 [ # # ]: 0 : if (!status) {
3449 : 0 : ice_acquire_lock(&pi->sched_lock);
3450 : 0 : status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type,
3451 : : ICE_SCHED_DFLT_BW);
3452 : : ice_release_lock(&pi->sched_lock);
3453 : : }
3454 : 0 : return status;
3455 : : }
3456 : :
3457 : : /**
3458 : : * ice_cfg_agg_bw_lmt_per_tc - configure aggregator BW limit per TC
3459 : : * @pi: port information structure
3460 : : * @agg_id: aggregator ID
3461 : : * @tc: traffic class
3462 : : * @rl_type: min or max
3463 : : * @bw: bandwidth in Kbps
3464 : : *
3465 : : * This function applies BW limit to aggregator scheduling node based on TC
3466 : : * information.
3467 : : */
3468 : : int
3469 : 0 : ice_cfg_agg_bw_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc,
3470 : : enum ice_rl_type rl_type, u32 bw)
3471 : : {
3472 : : int status;
3473 : :
3474 : 0 : status = ice_sched_set_node_bw_lmt_per_tc(pi, agg_id, ICE_AGG_TYPE_AGG,
3475 : : tc, rl_type, bw);
3476 [ # # ]: 0 : if (!status) {
3477 : 0 : ice_acquire_lock(&pi->sched_lock);
3478 : 0 : status = ice_sched_save_agg_bw(pi, agg_id, tc, rl_type, bw);
3479 : : ice_release_lock(&pi->sched_lock);
3480 : : }
3481 : 0 : return status;
3482 : : }
3483 : :
3484 : : /**
3485 : : * ice_cfg_agg_bw_dflt_lmt_per_tc - configure aggregator BW default limit per TC
3486 : : * @pi: port information structure
3487 : : * @agg_id: aggregator ID
3488 : : * @tc: traffic class
3489 : : * @rl_type: min or max
3490 : : *
3491 : : * This function applies default BW limit to aggregator scheduling node based
3492 : : * on TC information.
3493 : : */
3494 : : int
3495 : 0 : ice_cfg_agg_bw_dflt_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc,
3496 : : enum ice_rl_type rl_type)
3497 : : {
3498 : : int status;
3499 : :
3500 : 0 : status = ice_sched_set_node_bw_lmt_per_tc(pi, agg_id, ICE_AGG_TYPE_AGG,
3501 : : tc, rl_type,
3502 : : ICE_SCHED_DFLT_BW);
3503 [ # # ]: 0 : if (!status) {
3504 : 0 : ice_acquire_lock(&pi->sched_lock);
3505 : 0 : status = ice_sched_save_agg_bw(pi, agg_id, tc, rl_type,
3506 : : ICE_SCHED_DFLT_BW);
3507 : : ice_release_lock(&pi->sched_lock);
3508 : : }
3509 : 0 : return status;
3510 : : }
3511 : :
3512 : : /**
3513 : : * ice_cfg_vsi_bw_shared_lmt - configure VSI BW shared limit
3514 : : * @pi: port information structure
3515 : : * @vsi_handle: software VSI handle
3516 : : * @min_bw: minimum bandwidth in Kbps
3517 : : * @max_bw: maximum bandwidth in Kbps
3518 : : * @shared_bw: shared bandwidth in Kbps
3519 : : *
3520 : : * Configure shared rate limiter(SRL) of all VSI type nodes across all traffic
3521 : : * classes for VSI matching handle.
3522 : : */
3523 : : int
3524 : 0 : ice_cfg_vsi_bw_shared_lmt(struct ice_port_info *pi, u16 vsi_handle, u32 min_bw,
3525 : : u32 max_bw, u32 shared_bw)
3526 : : {
3527 : 0 : return ice_sched_set_vsi_bw_shared_lmt(pi, vsi_handle, min_bw, max_bw,
3528 : : shared_bw);
3529 : : }
3530 : :
3531 : : /**
3532 : : * ice_cfg_vsi_bw_no_shared_lmt - configure VSI BW for no shared limiter
3533 : : * @pi: port information structure
3534 : : * @vsi_handle: software VSI handle
3535 : : *
3536 : : * This function removes the shared rate limiter(SRL) of all VSI type nodes
3537 : : * across all traffic classes for VSI matching handle.
3538 : : */
3539 : : int
3540 : 0 : ice_cfg_vsi_bw_no_shared_lmt(struct ice_port_info *pi, u16 vsi_handle)
3541 : : {
3542 : 0 : return ice_sched_set_vsi_bw_shared_lmt(pi, vsi_handle,
3543 : : ICE_SCHED_DFLT_BW,
3544 : : ICE_SCHED_DFLT_BW,
3545 : : ICE_SCHED_DFLT_BW);
3546 : : }
3547 : :
3548 : : /**
3549 : : * ice_cfg_agg_bw_shared_lmt - configure aggregator BW shared limit
3550 : : * @pi: port information structure
3551 : : * @agg_id: aggregator ID
3552 : : * @min_bw: minimum bandwidth in Kbps
3553 : : * @max_bw: maximum bandwidth in Kbps
3554 : : * @shared_bw: shared bandwidth in Kbps
3555 : : *
3556 : : * This function configures the shared rate limiter(SRL) of all aggregator type
3557 : : * nodes across all traffic classes for aggregator matching agg_id.
3558 : : */
3559 : : int
3560 : 0 : ice_cfg_agg_bw_shared_lmt(struct ice_port_info *pi, u32 agg_id, u32 min_bw,
3561 : : u32 max_bw, u32 shared_bw)
3562 : : {
3563 : 0 : return ice_sched_set_agg_bw_shared_lmt(pi, agg_id, min_bw, max_bw,
3564 : : shared_bw);
3565 : : }
3566 : :
3567 : : /**
3568 : : * ice_cfg_agg_bw_no_shared_lmt - configure aggregator BW for no shared limiter
3569 : : * @pi: port information structure
3570 : : * @agg_id: aggregator ID
3571 : : *
3572 : : * This function removes the shared rate limiter(SRL) of all aggregator type
3573 : : * nodes across all traffic classes for aggregator matching agg_id.
3574 : : */
3575 : : int
3576 : 0 : ice_cfg_agg_bw_no_shared_lmt(struct ice_port_info *pi, u32 agg_id)
3577 : : {
3578 : 0 : return ice_sched_set_agg_bw_shared_lmt(pi, agg_id, ICE_SCHED_DFLT_BW,
3579 : : ICE_SCHED_DFLT_BW,
3580 : : ICE_SCHED_DFLT_BW);
3581 : : }
3582 : :
3583 : : /**
3584 : : * ice_cfg_agg_bw_shared_lmt_per_tc - config aggregator BW shared limit per tc
3585 : : * @pi: port information structure
3586 : : * @agg_id: aggregator ID
3587 : : * @tc: traffic class
3588 : : * @min_bw: minimum bandwidth in Kbps
3589 : : * @max_bw: maximum bandwidth in Kbps
3590 : : * @shared_bw: shared bandwidth in Kbps
3591 : : *
3592 : : * This function configures the shared rate limiter(SRL) of all aggregator type
3593 : : * nodes across all traffic classes for aggregator matching agg_id.
3594 : : */
3595 : : int
3596 : 0 : ice_cfg_agg_bw_shared_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc,
3597 : : u32 min_bw, u32 max_bw, u32 shared_bw)
3598 : : {
3599 : 0 : return ice_sched_set_agg_bw_shared_lmt_per_tc(pi, agg_id, tc, min_bw,
3600 : : max_bw, shared_bw);
3601 : : }
3602 : :
3603 : : /**
3604 : : * ice_cfg_agg_bw_no_shared_lmt_per_tc - cfg aggregator BW shared limit per tc
3605 : : * @pi: port information structure
3606 : : * @agg_id: aggregator ID
3607 : : * @tc: traffic class
3608 : : *
3609 : : * This function configures the shared rate limiter(SRL) of all aggregator type
3610 : : * nodes across all traffic classes for aggregator matching agg_id.
3611 : : */
3612 : : int
3613 : 0 : ice_cfg_agg_bw_no_shared_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc)
3614 : : {
3615 : 0 : return ice_sched_set_agg_bw_shared_lmt_per_tc(pi, agg_id, tc,
3616 : : ICE_SCHED_DFLT_BW,
3617 : : ICE_SCHED_DFLT_BW,
3618 : : ICE_SCHED_DFLT_BW);
3619 : : }
3620 : :
3621 : : /**
3622 : : * ice_cfg_vsi_q_priority - config VSI queue priority of node
3623 : : * @pi: port information structure
3624 : : * @num_qs: number of VSI queues
3625 : : * @q_ids: queue IDs array
3626 : : * @q_prio: queue priority array
3627 : : *
3628 : : * This function configures the queue node priority (Sibling Priority) of the
3629 : : * passed in VSI's queue(s) for a given traffic class (TC).
3630 : : */
3631 : : int
3632 : 0 : ice_cfg_vsi_q_priority(struct ice_port_info *pi, u16 num_qs, u32 *q_ids,
3633 : : u8 *q_prio)
3634 : : {
3635 : : int status = ICE_ERR_PARAM;
3636 : : u16 i;
3637 : :
3638 : 0 : ice_acquire_lock(&pi->sched_lock);
3639 : :
3640 [ # # ]: 0 : for (i = 0; i < num_qs; i++) {
3641 : : struct ice_sched_node *node;
3642 : :
3643 : 0 : node = ice_sched_find_node_by_teid(pi->root, q_ids[i]);
3644 [ # # # # ]: 0 : if (!node || node->info.data.elem_type !=
3645 : : ICE_AQC_ELEM_TYPE_LEAF) {
3646 : : status = ICE_ERR_PARAM;
3647 : : break;
3648 : : }
3649 : : /* Configure Priority */
3650 : 0 : status = ice_sched_cfg_sibl_node_prio(pi, node, q_prio[i]);
3651 [ # # ]: 0 : if (status)
3652 : : break;
3653 : : }
3654 : :
3655 : : ice_release_lock(&pi->sched_lock);
3656 : 0 : return status;
3657 : : }
3658 : :
3659 : : /**
3660 : : * ice_sched_cfg_sibl_node_prio_lock - config priority of node
3661 : : * @pi: port information structure
3662 : : * @node: sched node to configure
3663 : : * @priority: sibling priority
3664 : : *
3665 : : * This function configures node element's sibling priority only.
3666 : : */
3667 : : int
3668 : 0 : ice_sched_cfg_sibl_node_prio_lock(struct ice_port_info *pi,
3669 : : struct ice_sched_node *node,
3670 : : u8 priority)
3671 : : {
3672 : : int status;
3673 : :
3674 : 0 : ice_acquire_lock(&pi->sched_lock);
3675 : 0 : status = ice_sched_cfg_sibl_node_prio(pi, node, priority);
3676 : : ice_release_lock(&pi->sched_lock);
3677 : :
3678 : 0 : return status;
3679 : : }
3680 : :
3681 : : /**
3682 : : * ice_sched_save_q_bw_alloc - save queue node's BW allocation information
3683 : : * @q_ctx: queue context structure
3684 : : * @rl_type: rate limit type min, max, or shared
3685 : : * @bw_alloc: BW weight/allocation
3686 : : *
3687 : : * Save BW information of queue type node for post replay use.
3688 : : */
3689 : : static int
3690 : : ice_sched_save_q_bw_alloc(struct ice_q_ctx *q_ctx, enum ice_rl_type rl_type,
3691 : : u32 bw_alloc)
3692 : : {
3693 [ # # # ]: 0 : switch (rl_type) {
3694 [ # # ]: 0 : case ICE_MIN_BW:
3695 : : ice_set_clear_cir_bw_alloc(&q_ctx->bw_t_info, bw_alloc);
3696 : : break;
3697 [ # # ]: 0 : case ICE_MAX_BW:
3698 : : ice_set_clear_eir_bw_alloc(&q_ctx->bw_t_info, bw_alloc);
3699 : : break;
3700 : : default:
3701 : : return ICE_ERR_PARAM;
3702 : : }
3703 : : return 0;
3704 : : }
3705 : :
3706 : : /**
3707 : : * ice_cfg_q_bw_alloc - configure queue BW weight/alloc params
3708 : : * @pi: port information structure
3709 : : * @vsi_handle: sw VSI handle
3710 : : * @tc: traffic class
3711 : : * @q_handle: software queue handle
3712 : : * @rl_type: min, max, or shared
3713 : : * @bw_alloc: BW weight/allocation
3714 : : *
3715 : : * This function configures BW allocation of queue scheduling node.
3716 : : */
3717 : : int
3718 : 0 : ice_cfg_q_bw_alloc(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
3719 : : u16 q_handle, enum ice_rl_type rl_type, u32 bw_alloc)
3720 : : {
3721 : : int status = ICE_ERR_PARAM;
3722 : : struct ice_sched_node *node;
3723 : : struct ice_q_ctx *q_ctx;
3724 : :
3725 : 0 : ice_acquire_lock(&pi->sched_lock);
3726 : 0 : q_ctx = ice_get_lan_q_ctx(pi->hw, vsi_handle, tc, q_handle);
3727 [ # # ]: 0 : if (!q_ctx)
3728 : 0 : goto exit_q_bw_alloc;
3729 : :
3730 : 0 : node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid);
3731 [ # # ]: 0 : if (!node) {
3732 [ # # ]: 0 : ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong q_teid\n");
3733 : 0 : goto exit_q_bw_alloc;
3734 : : }
3735 : :
3736 : 0 : status = ice_sched_cfg_node_bw_alloc(pi->hw, node, rl_type, bw_alloc);
3737 [ # # ]: 0 : if (!status)
3738 : : status = ice_sched_save_q_bw_alloc(q_ctx, rl_type, bw_alloc);
3739 : :
3740 : 0 : exit_q_bw_alloc:
3741 : : ice_release_lock(&pi->sched_lock);
3742 : 0 : return status;
3743 : : }
3744 : :
3745 : : /**
3746 : : * ice_cfg_agg_vsi_priority_per_tc - config aggregator's VSI priority per TC
3747 : : * @pi: port information structure
3748 : : * @agg_id: Aggregator ID
3749 : : * @num_vsis: number of VSI(s)
3750 : : * @vsi_handle_arr: array of software VSI handles
3751 : : * @node_prio: pointer to node priority
3752 : : * @tc: traffic class
3753 : : *
3754 : : * This function configures the node priority (Sibling Priority) of the
3755 : : * passed in VSI's for a given traffic class (TC) of an Aggregator ID.
3756 : : */
3757 : : int
3758 : 0 : ice_cfg_agg_vsi_priority_per_tc(struct ice_port_info *pi, u32 agg_id,
3759 : : u16 num_vsis, u16 *vsi_handle_arr,
3760 : : u8 *node_prio, u8 tc)
3761 : : {
3762 : : struct ice_sched_agg_vsi_info *agg_vsi_info;
3763 : : struct ice_sched_node *tc_node, *agg_node;
3764 : : struct ice_sched_agg_info *agg_info;
3765 : : bool agg_id_present = false;
3766 : 0 : struct ice_hw *hw = pi->hw;
3767 : : int status = ICE_ERR_PARAM;
3768 : : u16 i;
3769 : :
3770 : 0 : ice_acquire_lock(&pi->sched_lock);
3771 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
# # ]
3772 : : list_entry)
3773 [ # # ]: 0 : if (agg_info->agg_id == agg_id) {
3774 : : agg_id_present = true;
3775 : : break;
3776 : : }
3777 [ # # ]: 0 : if (!agg_id_present)
3778 : 0 : goto exit_agg_priority_per_tc;
3779 : :
3780 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
3781 [ # # ]: 0 : if (!tc_node)
3782 : 0 : goto exit_agg_priority_per_tc;
3783 : :
3784 : : agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
3785 [ # # ]: 0 : if (!agg_node)
3786 : 0 : goto exit_agg_priority_per_tc;
3787 : :
3788 [ # # ]: 0 : if (num_vsis > hw->max_children[agg_node->tx_sched_layer])
3789 : 0 : goto exit_agg_priority_per_tc;
3790 : :
3791 [ # # ]: 0 : for (i = 0; i < num_vsis; i++) {
3792 : : struct ice_sched_node *vsi_node;
3793 : : bool vsi_handle_valid = false;
3794 : : u16 vsi_handle;
3795 : :
3796 : : status = ICE_ERR_PARAM;
3797 : 0 : vsi_handle = vsi_handle_arr[i];
3798 [ # # ]: 0 : if (!ice_is_vsi_valid(hw, vsi_handle))
3799 : 0 : goto exit_agg_priority_per_tc;
3800 : : /* Verify child nodes before applying settings */
3801 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(agg_vsi_info, &agg_info->agg_vsi_list,
# # ]
3802 : : ice_sched_agg_vsi_info, list_entry)
3803 [ # # ]: 0 : if (agg_vsi_info->vsi_handle == vsi_handle) {
3804 : : vsi_handle_valid = true;
3805 : : break;
3806 : : }
3807 : :
3808 [ # # ]: 0 : if (!vsi_handle_valid)
3809 : 0 : goto exit_agg_priority_per_tc;
3810 : :
3811 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
3812 [ # # ]: 0 : if (!vsi_node)
3813 : 0 : goto exit_agg_priority_per_tc;
3814 : :
3815 [ # # ]: 0 : if (ice_sched_find_node_in_subtree(hw, agg_node, vsi_node)) {
3816 : : /* Configure Priority */
3817 : 0 : status = ice_sched_cfg_sibl_node_prio(pi, vsi_node,
3818 : 0 : node_prio[i]);
3819 [ # # ]: 0 : if (status)
3820 : : break;
3821 : 0 : status = ice_sched_save_vsi_prio(pi, vsi_handle, tc,
3822 : 0 : node_prio[i]);
3823 [ # # ]: 0 : if (status)
3824 : : break;
3825 : : }
3826 : : }
3827 : :
3828 : 0 : exit_agg_priority_per_tc:
3829 : : ice_release_lock(&pi->sched_lock);
3830 : 0 : return status;
3831 : : }
3832 : :
3833 : : /**
3834 : : * ice_cfg_vsi_bw_alloc - config VSI BW alloc per TC
3835 : : * @pi: port information structure
3836 : : * @vsi_handle: software VSI handle
3837 : : * @ena_tcmap: enabled TC map
3838 : : * @rl_type: Rate limit type CIR/EIR
3839 : : * @bw_alloc: Array of BW alloc
3840 : : *
3841 : : * This function configures the BW allocation of the passed in VSI's
3842 : : * node(s) for enabled traffic class.
3843 : : */
3844 : : int
3845 : 0 : ice_cfg_vsi_bw_alloc(struct ice_port_info *pi, u16 vsi_handle, u8 ena_tcmap,
3846 : : enum ice_rl_type rl_type, u8 *bw_alloc)
3847 : : {
3848 : : int status = 0;
3849 : : u8 tc;
3850 : :
3851 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
3852 : : return ICE_ERR_PARAM;
3853 : :
3854 : 0 : ice_acquire_lock(&pi->sched_lock);
3855 : :
3856 : : /* Return success if no nodes are present across TC */
3857 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
3858 : : struct ice_sched_node *tc_node, *vsi_node;
3859 : :
3860 [ # # ]: 0 : if (!ice_is_tc_ena(ena_tcmap, tc))
3861 : 0 : continue;
3862 : :
3863 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
3864 [ # # ]: 0 : if (!tc_node)
3865 : 0 : continue;
3866 : :
3867 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
3868 [ # # ]: 0 : if (!vsi_node)
3869 : 0 : continue;
3870 : :
3871 : 0 : status = ice_sched_cfg_node_bw_alloc(pi->hw, vsi_node, rl_type,
3872 : 0 : bw_alloc[tc]);
3873 [ # # ]: 0 : if (status)
3874 : : break;
3875 : 0 : status = ice_sched_save_vsi_bw_alloc(pi, vsi_handle, tc,
3876 : 0 : rl_type, bw_alloc[tc]);
3877 [ # # ]: 0 : if (status)
3878 : : break;
3879 : : }
3880 : :
3881 : : ice_release_lock(&pi->sched_lock);
3882 : 0 : return status;
3883 : : }
3884 : :
3885 : : /**
3886 : : * ice_cfg_agg_bw_alloc - config aggregator BW alloc
3887 : : * @pi: port information structure
3888 : : * @agg_id: aggregator ID
3889 : : * @ena_tcmap: enabled TC map
3890 : : * @rl_type: rate limit type CIR/EIR
3891 : : * @bw_alloc: array of BW alloc
3892 : : *
3893 : : * This function configures the BW allocation of passed in aggregator for
3894 : : * enabled traffic class(s).
3895 : : */
3896 : : int
3897 : 0 : ice_cfg_agg_bw_alloc(struct ice_port_info *pi, u32 agg_id, u8 ena_tcmap,
3898 : : enum ice_rl_type rl_type, u8 *bw_alloc)
3899 : : {
3900 : : struct ice_sched_agg_info *agg_info;
3901 : : bool agg_id_present = false;
3902 : 0 : struct ice_hw *hw = pi->hw;
3903 : : int status = 0;
3904 : : u8 tc;
3905 : :
3906 : 0 : ice_acquire_lock(&pi->sched_lock);
3907 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
# # ]
3908 : : list_entry)
3909 [ # # ]: 0 : if (agg_info->agg_id == agg_id) {
3910 : : agg_id_present = true;
3911 : : break;
3912 : : }
3913 [ # # ]: 0 : if (!agg_id_present) {
3914 : : status = ICE_ERR_PARAM;
3915 : 0 : goto exit_cfg_agg_bw_alloc;
3916 : : }
3917 : :
3918 : : /* Return success if no nodes are present across TC */
3919 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
3920 : : struct ice_sched_node *tc_node, *agg_node;
3921 : :
3922 [ # # ]: 0 : if (!ice_is_tc_ena(ena_tcmap, tc))
3923 : 0 : continue;
3924 : :
3925 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
3926 [ # # ]: 0 : if (!tc_node)
3927 : 0 : continue;
3928 : :
3929 : : agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
3930 [ # # ]: 0 : if (!agg_node)
3931 : 0 : continue;
3932 : :
3933 : 0 : status = ice_sched_cfg_node_bw_alloc(hw, agg_node, rl_type,
3934 : 0 : bw_alloc[tc]);
3935 [ # # ]: 0 : if (status)
3936 : : break;
3937 : 0 : status = ice_sched_save_agg_bw_alloc(pi, agg_id, tc, rl_type,
3938 : 0 : bw_alloc[tc]);
3939 [ # # ]: 0 : if (status)
3940 : : break;
3941 : : }
3942 : :
3943 : 0 : exit_cfg_agg_bw_alloc:
3944 : : ice_release_lock(&pi->sched_lock);
3945 : 0 : return status;
3946 : : }
3947 : :
3948 : : /**
3949 : : * ice_sched_calc_wakeup - calculate RL profile wakeup parameter
3950 : : * @hw: pointer to the HW struct
3951 : : * @bw: bandwidth in Kbps
3952 : : *
3953 : : * This function calculates the wakeup parameter of RL profile.
3954 : : */
3955 : 0 : static u16 ice_sched_calc_wakeup(struct ice_hw *hw, s32 bw)
3956 : : {
3957 : : s64 bytes_per_sec, wakeup_int, wakeup_a, wakeup_b, wakeup_f;
3958 : : s32 wakeup_f_int;
3959 : : u16 wakeup = 0;
3960 : :
3961 : : /* Get the wakeup integer value */
3962 [ # # ]: 0 : bytes_per_sec = DIV_S64((s64)bw * 1000, BITS_PER_BYTE);
3963 : 0 : wakeup_int = DIV_S64(hw->psm_clk_freq, bytes_per_sec);
3964 [ # # ]: 0 : if (wakeup_int > 63) {
3965 : 0 : wakeup = (u16)((1 << 15) | wakeup_int);
3966 : : } else {
3967 : : /* Calculate fraction value up to 4 decimals
3968 : : * Convert Integer value to a constant multiplier
3969 : : */
3970 : 0 : wakeup_b = (s64)ICE_RL_PROF_MULTIPLIER * wakeup_int;
3971 [ # # ]: 0 : wakeup_a = DIV_S64((s64)ICE_RL_PROF_MULTIPLIER *
3972 : : hw->psm_clk_freq, bytes_per_sec);
3973 : :
3974 : : /* Get Fraction value */
3975 : 0 : wakeup_f = wakeup_a - wakeup_b;
3976 : :
3977 : : /* Round up the Fractional value via Ceil(Fractional value) */
3978 [ # # ]: 0 : if (wakeup_f > DIV_S64(ICE_RL_PROF_MULTIPLIER, 2))
3979 : 0 : wakeup_f += 1;
3980 : :
3981 : 0 : wakeup_f_int = (s32)DIV_S64(wakeup_f * ICE_RL_PROF_FRACTION,
3982 : : ICE_RL_PROF_MULTIPLIER);
3983 : 0 : wakeup |= (u16)(wakeup_int << 9);
3984 : 0 : wakeup |= (u16)(0x1ff & wakeup_f_int);
3985 : : }
3986 : :
3987 : 0 : return wakeup;
3988 : : }
3989 : :
3990 : : /**
3991 : : * ice_sched_bw_to_rl_profile - convert BW to profile parameters
3992 : : * @hw: pointer to the HW struct
3993 : : * @bw: bandwidth in Kbps
3994 : : * @profile: profile parameters to return
3995 : : *
3996 : : * This function converts the BW to profile structure format.
3997 : : */
3998 : : static int
3999 : 0 : ice_sched_bw_to_rl_profile(struct ice_hw *hw, u32 bw,
4000 : : struct ice_aqc_rl_profile_elem *profile)
4001 : : {
4002 : : s64 bytes_per_sec, ts_rate, mv_tmp;
4003 : : int status = ICE_ERR_PARAM;
4004 : : bool found = false;
4005 : : s32 encode = 0;
4006 : : s64 mv = 0;
4007 : : s32 i;
4008 : :
4009 : : /* Bw settings range is from 0.5Mb/sec to 100Gb/sec */
4010 [ # # ]: 0 : if (bw < ICE_SCHED_MIN_BW || bw > ICE_SCHED_MAX_BW)
4011 : : return status;
4012 : :
4013 : : /* Bytes per second from Kbps */
4014 : 0 : bytes_per_sec = DIV_S64((s64)bw * 1000, BITS_PER_BYTE);
4015 : :
4016 : : /* encode is 6 bits but really useful are 5 bits */
4017 [ # # ]: 0 : for (i = 0; i < 64; i++) {
4018 : : u64 pow_result = BIT_ULL(i);
4019 : :
4020 [ # # ]: 0 : ts_rate = DIV_S64((s64)hw->psm_clk_freq,
4021 : : pow_result * ICE_RL_PROF_TS_MULTIPLIER);
4022 [ # # ]: 0 : if (ts_rate <= 0)
4023 : 0 : continue;
4024 : :
4025 : : /* Multiplier value */
4026 [ # # ]: 0 : mv_tmp = DIV_S64(bytes_per_sec * ICE_RL_PROF_MULTIPLIER,
4027 : : ts_rate);
4028 : :
4029 : : /* Round to the nearest ICE_RL_PROF_MULTIPLIER */
4030 : : mv = round_up_64bit(mv_tmp, ICE_RL_PROF_MULTIPLIER);
4031 : :
4032 : : /* First multiplier value greater than the given
4033 : : * accuracy bytes
4034 : : */
4035 [ # # ]: 0 : if (mv > ICE_RL_PROF_ACCURACY_BYTES) {
4036 : : encode = i;
4037 : : found = true;
4038 : : break;
4039 : : }
4040 : : }
4041 [ # # ]: 0 : if (found) {
4042 : : u16 wm;
4043 : :
4044 : 0 : wm = ice_sched_calc_wakeup(hw, bw);
4045 : 0 : profile->rl_multiply = CPU_TO_LE16(mv);
4046 : 0 : profile->wake_up_calc = CPU_TO_LE16(wm);
4047 : 0 : profile->rl_encode = CPU_TO_LE16(encode);
4048 : : status = 0;
4049 : : } else {
4050 : : status = ICE_ERR_DOES_NOT_EXIST;
4051 : : }
4052 : :
4053 : : return status;
4054 : : }
4055 : :
4056 : : /**
4057 : : * ice_sched_add_rl_profile - add RL profile
4058 : : * @hw: pointer to the hardware structure
4059 : : * @rl_type: type of rate limit BW - min, max, or shared
4060 : : * @bw: bandwidth in Kbps - Kilo bits per sec
4061 : : * @layer_num: specifies in which layer to create profile
4062 : : *
4063 : : * This function first checks the existing list for corresponding BW
4064 : : * parameter. If it exists, it returns the associated profile otherwise
4065 : : * it creates a new rate limit profile for requested BW, and adds it to
4066 : : * the HW DB and local list. It returns the new profile or null on error.
4067 : : * The caller needs to hold the scheduler lock.
4068 : : */
4069 : : static struct ice_aqc_rl_profile_info *
4070 : 0 : ice_sched_add_rl_profile(struct ice_hw *hw, enum ice_rl_type rl_type,
4071 : : u32 bw, u8 layer_num)
4072 : : {
4073 : : struct ice_aqc_rl_profile_info *rl_prof_elem;
4074 : 0 : u16 profiles_added = 0, num_profiles = 1;
4075 : : struct ice_aqc_rl_profile_elem *buf;
4076 : : u8 profile_type;
4077 : : int status;
4078 : :
4079 [ # # # # ]: 0 : if (!hw || layer_num >= hw->num_tx_sched_layers)
4080 : : return NULL;
4081 : : switch (rl_type) {
4082 : : case ICE_MIN_BW:
4083 : : profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR;
4084 : : break;
4085 : : case ICE_MAX_BW:
4086 : : profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR;
4087 : : break;
4088 : : case ICE_SHARED_BW:
4089 : : profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL;
4090 : : break;
4091 : : default:
4092 : : return NULL;
4093 : : }
4094 : :
4095 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(rl_prof_elem, &hw->rl_prof_list[layer_num],
# # ]
4096 : : ice_aqc_rl_profile_info, list_entry)
4097 [ # # ]: 0 : if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) ==
4098 [ # # ]: 0 : profile_type && rl_prof_elem->bw == bw)
4099 : : /* Return existing profile ID info */
4100 : 0 : return rl_prof_elem;
4101 : :
4102 : : /* Create new profile ID */
4103 : : rl_prof_elem = (struct ice_aqc_rl_profile_info *)
4104 : 0 : ice_malloc(hw, sizeof(*rl_prof_elem));
4105 : :
4106 [ # # ]: 0 : if (!rl_prof_elem)
4107 : : return NULL;
4108 : :
4109 : 0 : status = ice_sched_bw_to_rl_profile(hw, bw, &rl_prof_elem->profile);
4110 [ # # ]: 0 : if (status)
4111 : 0 : goto exit_add_rl_prof;
4112 : :
4113 : 0 : rl_prof_elem->bw = bw;
4114 : : /* layer_num is zero relative, and fw expects level from 1 to 9 */
4115 : 0 : rl_prof_elem->profile.level = layer_num + 1;
4116 : 0 : rl_prof_elem->profile.flags = profile_type;
4117 : 0 : rl_prof_elem->profile.max_burst_size = CPU_TO_LE16(hw->max_burst_size);
4118 : :
4119 : : /* Create new entry in HW DB */
4120 : : buf = &rl_prof_elem->profile;
4121 : : status = ice_aq_add_rl_profile(hw, num_profiles, buf, sizeof(*buf),
4122 : : &profiles_added, NULL);
4123 [ # # # # ]: 0 : if (status || profiles_added != num_profiles)
4124 : 0 : goto exit_add_rl_prof;
4125 : :
4126 : : /* Good entry - add in the list */
4127 : 0 : rl_prof_elem->prof_id_ref = 0;
4128 [ # # ]: 0 : LIST_ADD(&rl_prof_elem->list_entry, &hw->rl_prof_list[layer_num]);
4129 : 0 : return rl_prof_elem;
4130 : :
4131 : 0 : exit_add_rl_prof:
4132 : 0 : ice_free(hw, rl_prof_elem);
4133 : 0 : return NULL;
4134 : : }
4135 : :
4136 : : /**
4137 : : * ice_sched_cfg_node_bw_lmt - configure node sched params
4138 : : * @hw: pointer to the HW struct
4139 : : * @node: sched node to configure
4140 : : * @rl_type: rate limit type CIR, EIR, or shared
4141 : : * @rl_prof_id: rate limit profile ID
4142 : : *
4143 : : * This function configures node element's BW limit.
4144 : : */
4145 : : static int
4146 : 0 : ice_sched_cfg_node_bw_lmt(struct ice_hw *hw, struct ice_sched_node *node,
4147 : : enum ice_rl_type rl_type, u16 rl_prof_id)
4148 : : {
4149 : : struct ice_aqc_txsched_elem_data buf;
4150 : : struct ice_aqc_txsched_elem *data;
4151 : :
4152 : 0 : buf = node->info;
4153 : : data = &buf.data;
4154 [ # # # # ]: 0 : switch (rl_type) {
4155 : 0 : case ICE_MIN_BW:
4156 : 0 : data->valid_sections |= ICE_AQC_ELEM_VALID_CIR;
4157 : 0 : data->cir_bw.bw_profile_idx = CPU_TO_LE16(rl_prof_id);
4158 : 0 : break;
4159 : 0 : case ICE_MAX_BW:
4160 : 0 : data->valid_sections |= ICE_AQC_ELEM_VALID_EIR;
4161 : 0 : data->eir_bw.bw_profile_idx = CPU_TO_LE16(rl_prof_id);
4162 : 0 : break;
4163 : 0 : case ICE_SHARED_BW:
4164 : 0 : data->valid_sections |= ICE_AQC_ELEM_VALID_SHARED;
4165 : 0 : data->srl_id = CPU_TO_LE16(rl_prof_id);
4166 : 0 : break;
4167 : : default:
4168 : : /* Unknown rate limit type */
4169 : : return ICE_ERR_PARAM;
4170 : : }
4171 : :
4172 : : /* Configure element */
4173 : 0 : return ice_sched_update_elem(hw, node, &buf);
4174 : : }
4175 : :
4176 : : /**
4177 : : * ice_sched_get_node_rl_prof_id - get node's rate limit profile ID
4178 : : * @node: sched node
4179 : : * @rl_type: rate limit type
4180 : : *
4181 : : * If existing profile matches, it returns the corresponding rate
4182 : : * limit profile ID, otherwise it returns an invalid ID as error.
4183 : : */
4184 : : static u16
4185 : 0 : ice_sched_get_node_rl_prof_id(struct ice_sched_node *node,
4186 : : enum ice_rl_type rl_type)
4187 : : {
4188 : : u16 rl_prof_id = ICE_SCHED_INVAL_PROF_ID;
4189 : : struct ice_aqc_txsched_elem *data;
4190 : :
4191 : : data = &node->info.data;
4192 [ # # # # ]: 0 : switch (rl_type) {
4193 : 0 : case ICE_MIN_BW:
4194 [ # # ]: 0 : if (data->valid_sections & ICE_AQC_ELEM_VALID_CIR)
4195 : 0 : rl_prof_id = LE16_TO_CPU(data->cir_bw.bw_profile_idx);
4196 : : break;
4197 : 0 : case ICE_MAX_BW:
4198 [ # # ]: 0 : if (data->valid_sections & ICE_AQC_ELEM_VALID_EIR)
4199 : 0 : rl_prof_id = LE16_TO_CPU(data->eir_bw.bw_profile_idx);
4200 : : break;
4201 : 0 : case ICE_SHARED_BW:
4202 [ # # ]: 0 : if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED)
4203 : 0 : rl_prof_id = LE16_TO_CPU(data->srl_id);
4204 : : break;
4205 : : default:
4206 : : break;
4207 : : }
4208 : :
4209 : 0 : return rl_prof_id;
4210 : : }
4211 : :
4212 : : /**
4213 : : * ice_sched_get_rl_prof_layer - selects rate limit profile creation layer
4214 : : * @pi: port information structure
4215 : : * @rl_type: type of rate limit BW - min, max, or shared
4216 : : * @layer_index: layer index
4217 : : *
4218 : : * This function returns requested profile creation layer.
4219 : : */
4220 : : static u8
4221 : 0 : ice_sched_get_rl_prof_layer(struct ice_port_info *pi, enum ice_rl_type rl_type,
4222 : : u8 layer_index)
4223 : : {
4224 : 0 : struct ice_hw *hw = pi->hw;
4225 : :
4226 [ # # ]: 0 : if (layer_index >= hw->num_tx_sched_layers)
4227 : : return ICE_SCHED_INVAL_LAYER_NUM;
4228 [ # # # # ]: 0 : switch (rl_type) {
4229 : 0 : case ICE_MIN_BW:
4230 [ # # ]: 0 : if (hw->layer_info[layer_index].max_cir_rl_profiles)
4231 : 0 : return layer_index;
4232 : : break;
4233 : 0 : case ICE_MAX_BW:
4234 [ # # ]: 0 : if (hw->layer_info[layer_index].max_eir_rl_profiles)
4235 : 0 : return layer_index;
4236 : : break;
4237 : 0 : case ICE_SHARED_BW:
4238 : : /* if current layer doesn't support SRL profile creation
4239 : : * then try a layer up or down.
4240 : : */
4241 [ # # ]: 0 : if (hw->layer_info[layer_index].max_srl_profiles)
4242 : : return layer_index;
4243 [ # # ]: 0 : else if (layer_index < hw->num_tx_sched_layers - 1 &&
4244 [ # # ]: 0 : hw->layer_info[layer_index + 1].max_srl_profiles)
4245 : 0 : return layer_index + 1;
4246 [ # # ]: 0 : else if (layer_index > 0 &&
4247 [ # # ]: 0 : hw->layer_info[layer_index - 1].max_srl_profiles)
4248 : 0 : return layer_index - 1;
4249 : : break;
4250 : : default:
4251 : : break;
4252 : : }
4253 : : return ICE_SCHED_INVAL_LAYER_NUM;
4254 : : }
4255 : :
4256 : : /**
4257 : : * ice_sched_get_srl_node - get shared rate limit node
4258 : : * @node: tree node
4259 : : * @srl_layer: shared rate limit layer
4260 : : *
4261 : : * This function returns SRL node to be used for shared rate limit purpose.
4262 : : * The caller needs to hold scheduler lock.
4263 : : */
4264 : : static struct ice_sched_node *
4265 : : ice_sched_get_srl_node(struct ice_sched_node *node, u8 srl_layer)
4266 : : {
4267 [ # # # # ]: 0 : if (srl_layer > node->tx_sched_layer)
4268 : 0 : return node->children[0];
4269 [ # # # # ]: 0 : else if (srl_layer < node->tx_sched_layer)
4270 : : /* Node can't be created without a parent. It will always
4271 : : * have a valid parent except root node.
4272 : : */
4273 : 0 : return node->parent;
4274 : : else
4275 : : return node;
4276 : : }
4277 : :
4278 : : /**
4279 : : * ice_sched_rm_rl_profile - remove RL profile ID
4280 : : * @hw: pointer to the hardware structure
4281 : : * @layer_num: layer number where profiles are saved
4282 : : * @profile_type: profile type like EIR, CIR, or SRL
4283 : : * @profile_id: profile ID to remove
4284 : : *
4285 : : * This function removes rate limit profile from layer 'layer_num' of type
4286 : : * 'profile_type' and profile ID as 'profile_id'. The caller needs to hold
4287 : : * scheduler lock.
4288 : : */
4289 : : static int
4290 : 0 : ice_sched_rm_rl_profile(struct ice_hw *hw, u8 layer_num, u8 profile_type,
4291 : : u16 profile_id)
4292 : : {
4293 : : struct ice_aqc_rl_profile_info *rl_prof_elem;
4294 : : int status = 0;
4295 : :
4296 [ # # # # ]: 0 : if (!hw || layer_num >= hw->num_tx_sched_layers)
4297 : : return ICE_ERR_PARAM;
4298 : : /* Check the existing list for RL profile */
4299 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(rl_prof_elem, &hw->rl_prof_list[layer_num],
# # ]
4300 : : ice_aqc_rl_profile_info, list_entry)
4301 [ # # ]: 0 : if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) ==
4302 : 0 : profile_type &&
4303 [ # # ]: 0 : LE16_TO_CPU(rl_prof_elem->profile.profile_id) ==
4304 : : profile_id) {
4305 [ # # ]: 0 : if (rl_prof_elem->prof_id_ref)
4306 : 0 : rl_prof_elem->prof_id_ref--;
4307 : :
4308 : : /* Remove old profile ID from database */
4309 : 0 : status = ice_sched_del_rl_profile(hw, rl_prof_elem);
4310 [ # # ]: 0 : if (status && status != ICE_ERR_IN_USE)
4311 [ # # ]: 0 : ice_debug(hw, ICE_DBG_SCHED, "Remove rl profile failed\n");
4312 : : break;
4313 : : }
4314 [ # # ]: 0 : if (status == ICE_ERR_IN_USE)
4315 : : status = 0;
4316 : : return status;
4317 : : }
4318 : :
4319 : : /**
4320 : : * ice_sched_set_node_bw_dflt - set node's bandwidth limit to default
4321 : : * @pi: port information structure
4322 : : * @node: pointer to node structure
4323 : : * @rl_type: rate limit type min, max, or shared
4324 : : * @layer_num: layer number where RL profiles are saved
4325 : : *
4326 : : * This function configures node element's BW rate limit profile ID of
4327 : : * type CIR, EIR, or SRL to default. This function needs to be called
4328 : : * with the scheduler lock held.
4329 : : */
4330 : : static int
4331 : 0 : ice_sched_set_node_bw_dflt(struct ice_port_info *pi,
4332 : : struct ice_sched_node *node,
4333 : : enum ice_rl_type rl_type, u8 layer_num)
4334 : : {
4335 : : struct ice_hw *hw;
4336 : : u8 profile_type;
4337 : : u16 rl_prof_id;
4338 : : int status;
4339 : : u16 old_id;
4340 : :
4341 [ # # ]: 0 : hw = pi->hw;
4342 : : switch (rl_type) {
4343 : : case ICE_MIN_BW:
4344 : : profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR;
4345 : : rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID;
4346 : : break;
4347 : : case ICE_MAX_BW:
4348 : : profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR;
4349 : : rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID;
4350 : : break;
4351 : : case ICE_SHARED_BW:
4352 : : profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL;
4353 : : /* No SRL is configured for default case */
4354 : : rl_prof_id = ICE_SCHED_NO_SHARED_RL_PROF_ID;
4355 : : break;
4356 : : default:
4357 : : return ICE_ERR_PARAM;
4358 : : }
4359 : : /* Save existing RL prof ID for later clean up */
4360 : 0 : old_id = ice_sched_get_node_rl_prof_id(node, rl_type);
4361 : : /* Configure BW scheduling parameters */
4362 : 0 : status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id);
4363 [ # # ]: 0 : if (status)
4364 : : return status;
4365 : :
4366 : : /* Remove stale RL profile ID */
4367 [ # # ]: 0 : if (old_id == ICE_SCHED_DFLT_RL_PROF_ID ||
4368 : : old_id == ICE_SCHED_INVAL_PROF_ID)
4369 : : return 0;
4370 : :
4371 : 0 : return ice_sched_rm_rl_profile(hw, layer_num, profile_type, old_id);
4372 : : }
4373 : :
4374 : : /**
4375 : : * ice_sched_set_node_bw - set node's bandwidth
4376 : : * @pi: port information structure
4377 : : * @node: tree node
4378 : : * @rl_type: rate limit type min, max, or shared
4379 : : * @bw: bandwidth in Kbps - Kilo bits per sec
4380 : : * @layer_num: layer number
4381 : : *
4382 : : * This function adds new profile corresponding to requested BW, configures
4383 : : * node's RL profile ID of type CIR, EIR, or SRL, and removes old profile
4384 : : * ID from local database. The caller needs to hold scheduler lock.
4385 : : */
4386 : : int
4387 : 0 : ice_sched_set_node_bw(struct ice_port_info *pi, struct ice_sched_node *node,
4388 : : enum ice_rl_type rl_type, u32 bw, u8 layer_num)
4389 : : {
4390 : : struct ice_aqc_rl_profile_info *rl_prof_info;
4391 : 0 : struct ice_hw *hw = pi->hw;
4392 : : u16 old_id, rl_prof_id;
4393 : : int status = ICE_ERR_PARAM;
4394 : :
4395 : 0 : rl_prof_info = ice_sched_add_rl_profile(hw, rl_type, bw, layer_num);
4396 [ # # ]: 0 : if (!rl_prof_info)
4397 : : return status;
4398 : :
4399 : 0 : rl_prof_id = LE16_TO_CPU(rl_prof_info->profile.profile_id);
4400 : :
4401 : : /* Save existing RL prof ID for later clean up */
4402 : 0 : old_id = ice_sched_get_node_rl_prof_id(node, rl_type);
4403 : : /* Configure BW scheduling parameters */
4404 : 0 : status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id);
4405 [ # # ]: 0 : if (status)
4406 : : return status;
4407 : :
4408 : : /* New changes has been applied */
4409 : : /* Increment the profile ID reference count */
4410 : 0 : rl_prof_info->prof_id_ref++;
4411 : :
4412 : : /* Check for old ID removal */
4413 [ # # ]: 0 : if ((old_id == ICE_SCHED_DFLT_RL_PROF_ID && rl_type != ICE_SHARED_BW) ||
4414 [ # # ]: 0 : old_id == ICE_SCHED_INVAL_PROF_ID || old_id == rl_prof_id)
4415 : : return 0;
4416 : :
4417 : 0 : return ice_sched_rm_rl_profile(hw, layer_num,
4418 : 0 : rl_prof_info->profile.flags &
4419 : : ICE_AQC_RL_PROFILE_TYPE_M, old_id);
4420 : : }
4421 : :
4422 : : /**
4423 : : * ice_sched_set_node_priority - set node's priority
4424 : : * @pi: port information structure
4425 : : * @node: tree node
4426 : : * @priority: number 0-7 representing priority among siblings
4427 : : *
4428 : : * This function sets priority of a node among it's siblings.
4429 : : */
4430 : : int
4431 : 0 : ice_sched_set_node_priority(struct ice_port_info *pi, struct ice_sched_node *node,
4432 : : u16 priority)
4433 : : {
4434 : : struct ice_aqc_txsched_elem_data buf;
4435 : : struct ice_aqc_txsched_elem *data;
4436 : :
4437 : 0 : buf = node->info;
4438 : : data = &buf.data;
4439 : :
4440 : 0 : data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC;
4441 : 0 : data->generic |= ICE_AQC_ELEM_GENERIC_PRIO_M &
4442 : 0 : (priority << ICE_AQC_ELEM_GENERIC_PRIO_S);
4443 : :
4444 : 0 : return ice_sched_update_elem(pi->hw, node, &buf);
4445 : : }
4446 : :
4447 : : /**
4448 : : * ice_sched_set_node_weight - set node's weight
4449 : : * @pi: port information structure
4450 : : * @node: tree node
4451 : : * @weight: number 1-200 representing weight for WFQ
4452 : : *
4453 : : * This function sets weight of the node for WFQ algorithm.
4454 : : */
4455 : : int
4456 : 0 : ice_sched_set_node_weight(struct ice_port_info *pi, struct ice_sched_node *node, u16 weight)
4457 : : {
4458 : : struct ice_aqc_txsched_elem_data buf;
4459 : : struct ice_aqc_txsched_elem *data;
4460 : :
4461 : 0 : buf = node->info;
4462 : : data = &buf.data;
4463 : :
4464 : 0 : data->valid_sections = ICE_AQC_ELEM_VALID_CIR | ICE_AQC_ELEM_VALID_EIR |
4465 : : ICE_AQC_ELEM_VALID_GENERIC;
4466 : 0 : data->cir_bw.bw_alloc = CPU_TO_LE16(weight);
4467 : 0 : data->eir_bw.bw_alloc = CPU_TO_LE16(weight);
4468 : : data->generic |= ICE_AQC_ELEM_GENERIC_SP_M &
4469 : : (0x0 << ICE_AQC_ELEM_GENERIC_SP_S);
4470 : :
4471 : 0 : return ice_sched_update_elem(pi->hw, node, &buf);
4472 : : }
4473 : :
4474 : : /**
4475 : : * ice_sched_set_node_bw_lmt - set node's BW limit
4476 : : * @pi: port information structure
4477 : : * @node: tree node
4478 : : * @rl_type: rate limit type min, max, or shared
4479 : : * @bw: bandwidth in Kbps - Kilo bits per sec
4480 : : *
4481 : : * It updates node's BW limit parameters like BW RL profile ID of type CIR,
4482 : : * EIR, or SRL. The caller needs to hold scheduler lock.
4483 : : *
4484 : : * NOTE: Caller provides the correct SRL node in case of shared profile
4485 : : * settings.
4486 : : */
4487 : : int
4488 : 0 : ice_sched_set_node_bw_lmt(struct ice_port_info *pi, struct ice_sched_node *node,
4489 : : enum ice_rl_type rl_type, u32 bw)
4490 : : {
4491 : : struct ice_hw *hw;
4492 : : u8 layer_num;
4493 : :
4494 [ # # ]: 0 : if (!pi)
4495 : : return ICE_ERR_PARAM;
4496 : 0 : hw = pi->hw;
4497 : : /* Remove unused RL profile IDs from HW and SW DB */
4498 : 0 : ice_sched_rm_unused_rl_prof(hw);
4499 : :
4500 : 0 : layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
4501 : 0 : node->tx_sched_layer);
4502 [ # # ]: 0 : if (layer_num >= hw->num_tx_sched_layers)
4503 : : return ICE_ERR_PARAM;
4504 : :
4505 [ # # ]: 0 : if (bw == ICE_SCHED_DFLT_BW)
4506 : 0 : return ice_sched_set_node_bw_dflt(pi, node, rl_type, layer_num);
4507 : 0 : return ice_sched_set_node_bw(pi, node, rl_type, bw, layer_num);
4508 : : }
4509 : :
4510 : : /**
4511 : : * ice_sched_set_node_bw_dflt_lmt - set node's BW limit to default
4512 : : * @pi: port information structure
4513 : : * @node: pointer to node structure
4514 : : * @rl_type: rate limit type min, max, or shared
4515 : : *
4516 : : * This function configures node element's BW rate limit profile ID of
4517 : : * type CIR, EIR, or SRL to default. This function needs to be called
4518 : : * with the scheduler lock held.
4519 : : */
4520 : : static int
4521 : : ice_sched_set_node_bw_dflt_lmt(struct ice_port_info *pi,
4522 : : struct ice_sched_node *node,
4523 : : enum ice_rl_type rl_type)
4524 : : {
4525 : 0 : return ice_sched_set_node_bw_lmt(pi, node, rl_type,
4526 : : ICE_SCHED_DFLT_BW);
4527 : : }
4528 : :
4529 : : /**
4530 : : * ice_sched_validate_srl_node - Check node for SRL applicability
4531 : : * @node: sched node to configure
4532 : : * @sel_layer: selected SRL layer
4533 : : *
4534 : : * This function checks if the SRL can be applied to a selceted layer node on
4535 : : * behalf of the requested node (first argument). This function needs to be
4536 : : * called with scheduler lock held.
4537 : : */
4538 : : static int
4539 : : ice_sched_validate_srl_node(struct ice_sched_node *node, u8 sel_layer)
4540 : : {
4541 : : /* SRL profiles are not available on all layers. Check if the
4542 : : * SRL profile can be applied to a node above or below the
4543 : : * requested node. SRL configuration is possible only if the
4544 : : * selected layer's node has single child.
4545 : : */
4546 : 0 : if (sel_layer == node->tx_sched_layer ||
4547 [ # # # # : 0 : ((sel_layer == node->tx_sched_layer + 1) &&
# # ]
4548 [ # # # # : 0 : node->num_children == 1) ||
# # ]
4549 [ # # # # : 0 : ((sel_layer == node->tx_sched_layer - 1) &&
# # ]
4550 [ # # # # : 0 : (node->parent && node->parent->num_children == 1)))
# # # # #
# # # ]
4551 : : return 0;
4552 : :
4553 : : return ICE_ERR_CFG;
4554 : : }
4555 : :
4556 : : /**
4557 : : * ice_sched_save_q_bw - save queue node's BW information
4558 : : * @q_ctx: queue context structure
4559 : : * @rl_type: rate limit type min, max, or shared
4560 : : * @bw: bandwidth in Kbps - Kilo bits per sec
4561 : : *
4562 : : * Save BW information of queue type node for post replay use.
4563 : : */
4564 : : static int
4565 : 0 : ice_sched_save_q_bw(struct ice_q_ctx *q_ctx, enum ice_rl_type rl_type, u32 bw)
4566 : : {
4567 [ # # # # ]: 0 : switch (rl_type) {
4568 [ # # ]: 0 : case ICE_MIN_BW:
4569 : : ice_set_clear_cir_bw(&q_ctx->bw_t_info, bw);
4570 : : break;
4571 [ # # ]: 0 : case ICE_MAX_BW:
4572 : : ice_set_clear_eir_bw(&q_ctx->bw_t_info, bw);
4573 : : break;
4574 [ # # ]: 0 : case ICE_SHARED_BW:
4575 : : ice_set_clear_shared_bw(&q_ctx->bw_t_info, bw);
4576 : : break;
4577 : : default:
4578 : : return ICE_ERR_PARAM;
4579 : : }
4580 : : return 0;
4581 : : }
4582 : :
4583 : : /**
4584 : : * ice_sched_set_q_bw_lmt - sets queue BW limit
4585 : : * @pi: port information structure
4586 : : * @vsi_handle: sw VSI handle
4587 : : * @tc: traffic class
4588 : : * @q_handle: software queue handle
4589 : : * @rl_type: min, max, or shared
4590 : : * @bw: bandwidth in Kbps
4591 : : *
4592 : : * This function sets BW limit of queue scheduling node.
4593 : : */
4594 : : static int
4595 : 0 : ice_sched_set_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
4596 : : u16 q_handle, enum ice_rl_type rl_type, u32 bw)
4597 : : {
4598 : : struct ice_sched_node *node;
4599 : : struct ice_q_ctx *q_ctx;
4600 : : int status = ICE_ERR_PARAM;
4601 : :
4602 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
4603 : : return ICE_ERR_PARAM;
4604 : 0 : ice_acquire_lock(&pi->sched_lock);
4605 : 0 : q_ctx = ice_get_lan_q_ctx(pi->hw, vsi_handle, tc, q_handle);
4606 [ # # ]: 0 : if (!q_ctx)
4607 : 0 : goto exit_q_bw_lmt;
4608 : 0 : node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid);
4609 [ # # ]: 0 : if (!node) {
4610 [ # # ]: 0 : ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong q_teid\n");
4611 : 0 : goto exit_q_bw_lmt;
4612 : : }
4613 : :
4614 : : /* Return error if it is not a leaf node */
4615 [ # # ]: 0 : if (node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF)
4616 : 0 : goto exit_q_bw_lmt;
4617 : :
4618 : : /* SRL bandwidth layer selection */
4619 [ # # ]: 0 : if (rl_type == ICE_SHARED_BW) {
4620 : : u8 sel_layer; /* selected layer */
4621 : :
4622 : 0 : sel_layer = ice_sched_get_rl_prof_layer(pi, rl_type,
4623 : 0 : node->tx_sched_layer);
4624 [ # # ]: 0 : if (sel_layer >= pi->hw->num_tx_sched_layers) {
4625 : : status = ICE_ERR_PARAM;
4626 : 0 : goto exit_q_bw_lmt;
4627 : : }
4628 [ # # ]: 0 : status = ice_sched_validate_srl_node(node, sel_layer);
4629 : : if (status)
4630 : 0 : goto exit_q_bw_lmt;
4631 : : }
4632 : :
4633 [ # # ]: 0 : if (bw == ICE_SCHED_DFLT_BW)
4634 : : status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type);
4635 : : else
4636 : 0 : status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw);
4637 : :
4638 [ # # ]: 0 : if (!status)
4639 : 0 : status = ice_sched_save_q_bw(q_ctx, rl_type, bw);
4640 : :
4641 : 0 : exit_q_bw_lmt:
4642 : : ice_release_lock(&pi->sched_lock);
4643 : 0 : return status;
4644 : : }
4645 : :
4646 : : /**
4647 : : * ice_cfg_q_bw_lmt - configure queue BW limit
4648 : : * @pi: port information structure
4649 : : * @vsi_handle: sw VSI handle
4650 : : * @tc: traffic class
4651 : : * @q_handle: software queue handle
4652 : : * @rl_type: min, max, or shared
4653 : : * @bw: bandwidth in Kbps
4654 : : *
4655 : : * This function configures BW limit of queue scheduling node.
4656 : : */
4657 : : int
4658 : 0 : ice_cfg_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
4659 : : u16 q_handle, enum ice_rl_type rl_type, u32 bw)
4660 : : {
4661 : 0 : return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type,
4662 : : bw);
4663 : : }
4664 : :
4665 : : /**
4666 : : * ice_cfg_q_bw_dflt_lmt - configure queue BW default limit
4667 : : * @pi: port information structure
4668 : : * @vsi_handle: sw VSI handle
4669 : : * @tc: traffic class
4670 : : * @q_handle: software queue handle
4671 : : * @rl_type: min, max, or shared
4672 : : *
4673 : : * This function configures BW default limit of queue scheduling node.
4674 : : */
4675 : : int
4676 : 0 : ice_cfg_q_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc,
4677 : : u16 q_handle, enum ice_rl_type rl_type)
4678 : : {
4679 : 0 : return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type,
4680 : : ICE_SCHED_DFLT_BW);
4681 : : }
4682 : :
4683 : : /**
4684 : : * ice_sched_save_tc_node_bw - save TC node BW limit
4685 : : * @pi: port information structure
4686 : : * @tc: TC number
4687 : : * @rl_type: min or max
4688 : : * @bw: bandwidth in Kbps
4689 : : *
4690 : : * This function saves the modified values of bandwidth settings for later
4691 : : * replay purpose (restore) after reset.
4692 : : */
4693 : : static int
4694 : 0 : ice_sched_save_tc_node_bw(struct ice_port_info *pi, u8 tc,
4695 : : enum ice_rl_type rl_type, u32 bw)
4696 : : {
4697 [ # # ]: 0 : if (tc >= ICE_MAX_TRAFFIC_CLASS)
4698 : : return ICE_ERR_PARAM;
4699 [ # # # # ]: 0 : switch (rl_type) {
4700 : 0 : case ICE_MIN_BW:
4701 [ # # ]: 0 : ice_set_clear_cir_bw(&pi->tc_node_bw_t_info[tc], bw);
4702 : : break;
4703 : 0 : case ICE_MAX_BW:
4704 [ # # ]: 0 : ice_set_clear_eir_bw(&pi->tc_node_bw_t_info[tc], bw);
4705 : : break;
4706 : 0 : case ICE_SHARED_BW:
4707 [ # # ]: 0 : ice_set_clear_shared_bw(&pi->tc_node_bw_t_info[tc], bw);
4708 : : break;
4709 : : default:
4710 : : return ICE_ERR_PARAM;
4711 : : }
4712 : : return 0;
4713 : : }
4714 : :
4715 : : #define ICE_SCHED_GENERIC_STRICT_MODE BIT(4)
4716 : : #define ICE_SCHED_GENERIC_PRIO_S 1
4717 : :
4718 : : /**
4719 : : * ice_sched_set_tc_node_bw_lmt - sets TC node BW limit
4720 : : * @pi: port information structure
4721 : : * @tc: TC number
4722 : : * @rl_type: min or max
4723 : : * @bw: bandwidth in Kbps
4724 : : *
4725 : : * This function configures bandwidth limit of TC node.
4726 : : */
4727 : : static int
4728 : 0 : ice_sched_set_tc_node_bw_lmt(struct ice_port_info *pi, u8 tc,
4729 : : enum ice_rl_type rl_type, u32 bw)
4730 : : {
4731 : : struct ice_aqc_txsched_elem_data buf;
4732 : : struct ice_aqc_txsched_elem *data;
4733 : : struct ice_sched_node *tc_node;
4734 : : int status = ICE_ERR_PARAM;
4735 : :
4736 [ # # ]: 0 : if (tc >= ICE_MAX_TRAFFIC_CLASS)
4737 : : return status;
4738 : 0 : ice_acquire_lock(&pi->sched_lock);
4739 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
4740 [ # # ]: 0 : if (!tc_node)
4741 : 0 : goto exit_set_tc_node_bw;
4742 : :
4743 : : /* update node's generic field */
4744 : 0 : buf = tc_node->info;
4745 : : data = &buf.data;
4746 : 0 : data->valid_sections = ICE_AQC_ELEM_VALID_GENERIC;
4747 : 0 : data->generic = (tc << ICE_SCHED_GENERIC_PRIO_S) |
4748 : : ICE_SCHED_GENERIC_STRICT_MODE;
4749 : 0 : status = ice_sched_update_elem(pi->hw, tc_node, &buf);
4750 [ # # ]: 0 : if (status)
4751 : 0 : goto exit_set_tc_node_bw;
4752 : :
4753 [ # # ]: 0 : if (bw == ICE_SCHED_DFLT_BW)
4754 : : status = ice_sched_set_node_bw_dflt_lmt(pi, tc_node, rl_type);
4755 : : else
4756 : 0 : status = ice_sched_set_node_bw_lmt(pi, tc_node, rl_type, bw);
4757 [ # # ]: 0 : if (!status)
4758 : 0 : status = ice_sched_save_tc_node_bw(pi, tc, rl_type, bw);
4759 : :
4760 : 0 : exit_set_tc_node_bw:
4761 : : ice_release_lock(&pi->sched_lock);
4762 : 0 : return status;
4763 : : }
4764 : :
4765 : : /**
4766 : : * ice_cfg_tc_node_bw_lmt - configure TC node BW limit
4767 : : * @pi: port information structure
4768 : : * @tc: TC number
4769 : : * @rl_type: min or max
4770 : : * @bw: bandwidth in Kbps
4771 : : *
4772 : : * This function configures BW limit of TC node.
4773 : : * Note: The minimum guaranteed reservation is done via DCBX.
4774 : : */
4775 : : int
4776 : 0 : ice_cfg_tc_node_bw_lmt(struct ice_port_info *pi, u8 tc,
4777 : : enum ice_rl_type rl_type, u32 bw)
4778 : : {
4779 : 0 : return ice_sched_set_tc_node_bw_lmt(pi, tc, rl_type, bw);
4780 : : }
4781 : :
4782 : : /**
4783 : : * ice_cfg_tc_node_bw_dflt_lmt - configure TC node BW default limit
4784 : : * @pi: port information structure
4785 : : * @tc: TC number
4786 : : * @rl_type: min or max
4787 : : *
4788 : : * This function configures BW default limit of TC node.
4789 : : */
4790 : : int
4791 : 0 : ice_cfg_tc_node_bw_dflt_lmt(struct ice_port_info *pi, u8 tc,
4792 : : enum ice_rl_type rl_type)
4793 : : {
4794 : 0 : return ice_sched_set_tc_node_bw_lmt(pi, tc, rl_type, ICE_SCHED_DFLT_BW);
4795 : : }
4796 : :
4797 : : /**
4798 : : * ice_sched_save_tc_node_bw_alloc - save TC node's BW alloc information
4799 : : * @pi: port information structure
4800 : : * @tc: traffic class
4801 : : * @rl_type: rate limit type min or max
4802 : : * @bw_alloc: Bandwidth allocation information
4803 : : *
4804 : : * Save BW alloc information of VSI type node for post replay use.
4805 : : */
4806 : : static int
4807 : 0 : ice_sched_save_tc_node_bw_alloc(struct ice_port_info *pi, u8 tc,
4808 : : enum ice_rl_type rl_type, u16 bw_alloc)
4809 : : {
4810 [ # # ]: 0 : if (tc >= ICE_MAX_TRAFFIC_CLASS)
4811 : : return ICE_ERR_PARAM;
4812 [ # # # ]: 0 : switch (rl_type) {
4813 : 0 : case ICE_MIN_BW:
4814 [ # # ]: 0 : ice_set_clear_cir_bw_alloc(&pi->tc_node_bw_t_info[tc],
4815 : : bw_alloc);
4816 : : break;
4817 : 0 : case ICE_MAX_BW:
4818 [ # # ]: 0 : ice_set_clear_eir_bw_alloc(&pi->tc_node_bw_t_info[tc],
4819 : : bw_alloc);
4820 : : break;
4821 : : default:
4822 : : return ICE_ERR_PARAM;
4823 : : }
4824 : : return 0;
4825 : : }
4826 : :
4827 : : /**
4828 : : * ice_sched_set_tc_node_bw_alloc - set TC node BW alloc
4829 : : * @pi: port information structure
4830 : : * @tc: TC number
4831 : : * @rl_type: min or max
4832 : : * @bw_alloc: bandwidth alloc
4833 : : *
4834 : : * This function configures bandwidth alloc of TC node, also saves the
4835 : : * changed settings for replay purpose, and return success if it succeeds
4836 : : * in modifying bandwidth alloc setting.
4837 : : */
4838 : : static int
4839 : 0 : ice_sched_set_tc_node_bw_alloc(struct ice_port_info *pi, u8 tc,
4840 : : enum ice_rl_type rl_type, u8 bw_alloc)
4841 : : {
4842 : : struct ice_sched_node *tc_node;
4843 : : int status = ICE_ERR_PARAM;
4844 : :
4845 [ # # ]: 0 : if (tc >= ICE_MAX_TRAFFIC_CLASS)
4846 : : return status;
4847 : 0 : ice_acquire_lock(&pi->sched_lock);
4848 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
4849 [ # # ]: 0 : if (!tc_node)
4850 : 0 : goto exit_set_tc_node_bw_alloc;
4851 : 0 : status = ice_sched_cfg_node_bw_alloc(pi->hw, tc_node, rl_type,
4852 : : bw_alloc);
4853 [ # # ]: 0 : if (status)
4854 : 0 : goto exit_set_tc_node_bw_alloc;
4855 : 0 : status = ice_sched_save_tc_node_bw_alloc(pi, tc, rl_type, bw_alloc);
4856 : :
4857 : 0 : exit_set_tc_node_bw_alloc:
4858 : : ice_release_lock(&pi->sched_lock);
4859 : 0 : return status;
4860 : : }
4861 : :
4862 : : /**
4863 : : * ice_cfg_tc_node_bw_alloc - configure TC node BW alloc
4864 : : * @pi: port information structure
4865 : : * @tc: TC number
4866 : : * @rl_type: min or max
4867 : : * @bw_alloc: bandwidth alloc
4868 : : *
4869 : : * This function configures BW limit of TC node.
4870 : : * Note: The minimum guaranteed reservation is done via DCBX.
4871 : : */
4872 : : int
4873 : 0 : ice_cfg_tc_node_bw_alloc(struct ice_port_info *pi, u8 tc,
4874 : : enum ice_rl_type rl_type, u8 bw_alloc)
4875 : : {
4876 : 0 : return ice_sched_set_tc_node_bw_alloc(pi, tc, rl_type, bw_alloc);
4877 : : }
4878 : :
4879 : : /**
4880 : : * ice_sched_set_agg_bw_dflt_lmt - set aggregator node's BW limit to default
4881 : : * @pi: port information structure
4882 : : * @vsi_handle: software VSI handle
4883 : : *
4884 : : * This function retrieves the aggregator ID based on VSI ID and TC,
4885 : : * and sets node's BW limit to default. This function needs to be
4886 : : * called with the scheduler lock held.
4887 : : */
4888 : : int
4889 : 0 : ice_sched_set_agg_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle)
4890 : : {
4891 : : struct ice_vsi_ctx *vsi_ctx;
4892 : : int status = 0;
4893 : : u8 tc;
4894 : :
4895 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
4896 : : return ICE_ERR_PARAM;
4897 : 0 : vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
4898 [ # # ]: 0 : if (!vsi_ctx)
4899 : : return ICE_ERR_PARAM;
4900 : :
4901 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
4902 : : struct ice_sched_node *node;
4903 : :
4904 : 0 : node = vsi_ctx->sched.ag_node[tc];
4905 [ # # ]: 0 : if (!node)
4906 : 0 : continue;
4907 : :
4908 : : /* Set min profile to default */
4909 : : status = ice_sched_set_node_bw_dflt_lmt(pi, node, ICE_MIN_BW);
4910 [ # # ]: 0 : if (status)
4911 : : break;
4912 : :
4913 : : /* Set max profile to default */
4914 : : status = ice_sched_set_node_bw_dflt_lmt(pi, node, ICE_MAX_BW);
4915 [ # # ]: 0 : if (status)
4916 : : break;
4917 : :
4918 : : /* Remove shared profile, if there is one */
4919 : : status = ice_sched_set_node_bw_dflt_lmt(pi, node,
4920 : : ICE_SHARED_BW);
4921 [ # # ]: 0 : if (status)
4922 : : break;
4923 : : }
4924 : :
4925 : : return status;
4926 : : }
4927 : :
4928 : : /**
4929 : : * ice_sched_get_node_by_id_type - get node from ID type
4930 : : * @pi: port information structure
4931 : : * @id: identifier
4932 : : * @agg_type: type of aggregator
4933 : : * @tc: traffic class
4934 : : *
4935 : : * This function returns node identified by ID of type aggregator, and
4936 : : * based on traffic class (TC). This function needs to be called with
4937 : : * the scheduler lock held.
4938 : : */
4939 : : static struct ice_sched_node *
4940 : 0 : ice_sched_get_node_by_id_type(struct ice_port_info *pi, u32 id,
4941 : : enum ice_agg_type agg_type, u8 tc)
4942 : : {
4943 : : struct ice_sched_node *node = NULL;
4944 : :
4945 [ # # # # : 0 : switch (agg_type) {
# ]
4946 : 0 : case ICE_AGG_TYPE_VSI: {
4947 : : struct ice_vsi_ctx *vsi_ctx;
4948 : : u16 vsi_handle = (u16)id;
4949 : :
4950 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
4951 : : break;
4952 : : /* Get sched_vsi_info */
4953 : 0 : vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
4954 [ # # ]: 0 : if (!vsi_ctx)
4955 : : break;
4956 : 0 : node = vsi_ctx->sched.vsi_node[tc];
4957 : 0 : break;
4958 : : }
4959 : :
4960 : 0 : case ICE_AGG_TYPE_AGG: {
4961 : : struct ice_sched_node *tc_node;
4962 : :
4963 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
4964 [ # # ]: 0 : if (tc_node)
4965 : : node = ice_sched_get_agg_node(pi, tc_node, id);
4966 : : break;
4967 : : }
4968 : :
4969 : 0 : case ICE_AGG_TYPE_Q:
4970 : : /* The current implementation allows single queue to modify */
4971 : 0 : node = ice_sched_find_node_by_teid(pi->root, id);
4972 : 0 : break;
4973 : :
4974 : 0 : case ICE_AGG_TYPE_QG: {
4975 : : struct ice_sched_node *child_node;
4976 : :
4977 : : /* The current implementation allows single qg to modify */
4978 : 0 : child_node = ice_sched_find_node_by_teid(pi->root, id);
4979 [ # # ]: 0 : if (!child_node)
4980 : : break;
4981 : 0 : node = child_node->parent;
4982 : 0 : break;
4983 : : }
4984 : :
4985 : : default:
4986 : : break;
4987 : : }
4988 : :
4989 : 0 : return node;
4990 : : }
4991 : :
4992 : : /**
4993 : : * ice_sched_set_node_bw_lmt_per_tc - set node BW limit per TC
4994 : : * @pi: port information structure
4995 : : * @id: ID (software VSI handle or AGG ID)
4996 : : * @agg_type: aggregator type (VSI or AGG type node)
4997 : : * @tc: traffic class
4998 : : * @rl_type: min or max
4999 : : * @bw: bandwidth in Kbps
5000 : : *
5001 : : * This function sets BW limit of VSI or Aggregator scheduling node
5002 : : * based on TC information from passed in argument BW.
5003 : : */
5004 : : int
5005 : 0 : ice_sched_set_node_bw_lmt_per_tc(struct ice_port_info *pi, u32 id,
5006 : : enum ice_agg_type agg_type, u8 tc,
5007 : : enum ice_rl_type rl_type, u32 bw)
5008 : : {
5009 : : struct ice_sched_node *node;
5010 : : int status = ICE_ERR_PARAM;
5011 : :
5012 [ # # ]: 0 : if (!pi)
5013 : : return status;
5014 : :
5015 [ # # ]: 0 : if (rl_type == ICE_UNKNOWN_BW)
5016 : : return status;
5017 : :
5018 : 0 : ice_acquire_lock(&pi->sched_lock);
5019 : 0 : node = ice_sched_get_node_by_id_type(pi, id, agg_type, tc);
5020 [ # # ]: 0 : if (!node) {
5021 [ # # ]: 0 : ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong id, agg type, or tc\n");
5022 : 0 : goto exit_set_node_bw_lmt_per_tc;
5023 : : }
5024 [ # # ]: 0 : if (bw == ICE_SCHED_DFLT_BW)
5025 : : status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type);
5026 : : else
5027 : 0 : status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw);
5028 : :
5029 : 0 : exit_set_node_bw_lmt_per_tc:
5030 : : ice_release_lock(&pi->sched_lock);
5031 : 0 : return status;
5032 : : }
5033 : :
5034 : : /**
5035 : : * ice_sched_validate_vsi_srl_node - validate VSI SRL node
5036 : : * @pi: port information structure
5037 : : * @vsi_handle: software VSI handle
5038 : : *
5039 : : * This function validates SRL node of the VSI node if available SRL layer is
5040 : : * different than the VSI node layer on all TC(s).This function needs to be
5041 : : * called with scheduler lock held.
5042 : : */
5043 : : static int
5044 : 0 : ice_sched_validate_vsi_srl_node(struct ice_port_info *pi, u16 vsi_handle)
5045 : : {
5046 : : u8 sel_layer = ICE_SCHED_INVAL_LAYER_NUM;
5047 : : u8 tc;
5048 : :
5049 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
5050 : : return ICE_ERR_PARAM;
5051 : :
5052 : : /* Return success if no nodes are present across TC */
5053 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
5054 : : struct ice_sched_node *tc_node, *vsi_node;
5055 : : enum ice_rl_type rl_type = ICE_SHARED_BW;
5056 : : int status;
5057 : :
5058 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
5059 [ # # ]: 0 : if (!tc_node)
5060 : 0 : continue;
5061 : :
5062 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
5063 [ # # ]: 0 : if (!vsi_node)
5064 : 0 : continue;
5065 : :
5066 : : /* SRL bandwidth layer selection */
5067 [ # # ]: 0 : if (sel_layer == ICE_SCHED_INVAL_LAYER_NUM) {
5068 : 0 : u8 node_layer = vsi_node->tx_sched_layer;
5069 : : u8 layer_num;
5070 : :
5071 : 0 : layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
5072 : : node_layer);
5073 [ # # ]: 0 : if (layer_num >= pi->hw->num_tx_sched_layers)
5074 : : return ICE_ERR_PARAM;
5075 : : sel_layer = layer_num;
5076 : : }
5077 : :
5078 [ # # ]: 0 : status = ice_sched_validate_srl_node(vsi_node, sel_layer);
5079 : : if (status)
5080 : : return status;
5081 : : }
5082 : : return 0;
5083 : : }
5084 : :
5085 : : /**
5086 : : * ice_sched_set_save_vsi_srl_node_bw - set VSI shared limit values
5087 : : * @pi: port information structure
5088 : : * @vsi_handle: software VSI handle
5089 : : * @tc: traffic class
5090 : : * @srl_node: sched node to configure
5091 : : * @rl_type: rate limit type minimum, maximum, or shared
5092 : : * @bw: minimum, maximum, or shared bandwidth in Kbps
5093 : : *
5094 : : * Configure shared rate limiter(SRL) of VSI type nodes across given traffic
5095 : : * class, and saves those value for later use for replaying purposes. The
5096 : : * caller holds the scheduler lock.
5097 : : */
5098 : : static int
5099 : 0 : ice_sched_set_save_vsi_srl_node_bw(struct ice_port_info *pi, u16 vsi_handle,
5100 : : u8 tc, struct ice_sched_node *srl_node,
5101 : : enum ice_rl_type rl_type, u32 bw)
5102 : : {
5103 : : int status;
5104 : :
5105 [ # # ]: 0 : if (bw == ICE_SCHED_DFLT_BW) {
5106 : : status = ice_sched_set_node_bw_dflt_lmt(pi, srl_node, rl_type);
5107 : : } else {
5108 : 0 : status = ice_sched_set_node_bw_lmt(pi, srl_node, rl_type, bw);
5109 [ # # ]: 0 : if (status)
5110 : : return status;
5111 : 0 : status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, bw);
5112 : : }
5113 : : return status;
5114 : : }
5115 : :
5116 : : /**
5117 : : * ice_sched_set_vsi_node_srl_per_tc - set VSI node BW shared limit for tc
5118 : : * @pi: port information structure
5119 : : * @vsi_handle: software VSI handle
5120 : : * @tc: traffic class
5121 : : * @min_bw: minimum bandwidth in Kbps
5122 : : * @max_bw: maximum bandwidth in Kbps
5123 : : * @shared_bw: shared bandwidth in Kbps
5124 : : *
5125 : : * Configure shared rate limiter(SRL) of VSI type nodes across requested
5126 : : * traffic class for VSI matching handle. When BW value of ICE_SCHED_DFLT_BW
5127 : : * is passed, it removes the corresponding bw from the node. The caller
5128 : : * holds scheduler lock.
5129 : : */
5130 : : static int
5131 : 0 : ice_sched_set_vsi_node_srl_per_tc(struct ice_port_info *pi, u16 vsi_handle,
5132 : : u8 tc, u32 min_bw, u32 max_bw, u32 shared_bw)
5133 : : {
5134 : : struct ice_sched_node *tc_node, *vsi_node, *cfg_node;
5135 : : u8 layer_num;
5136 : : int status;
5137 : :
5138 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
5139 [ # # ]: 0 : if (!tc_node)
5140 : : return ICE_ERR_CFG;
5141 : :
5142 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
5143 [ # # ]: 0 : if (!vsi_node)
5144 : : return ICE_ERR_CFG;
5145 : :
5146 : 0 : layer_num = ice_sched_get_rl_prof_layer(pi, ICE_SHARED_BW,
5147 : 0 : vsi_node->tx_sched_layer);
5148 [ # # ]: 0 : if (layer_num >= pi->hw->num_tx_sched_layers)
5149 : : return ICE_ERR_PARAM;
5150 : :
5151 : : /* SRL node may be different */
5152 : : cfg_node = ice_sched_get_srl_node(vsi_node, layer_num);
5153 [ # # ]: 0 : if (!cfg_node)
5154 : : return ICE_ERR_CFG;
5155 : :
5156 : 0 : status = ice_sched_set_save_vsi_srl_node_bw(pi, vsi_handle, tc,
5157 : : cfg_node, ICE_MIN_BW,
5158 : : min_bw);
5159 [ # # ]: 0 : if (status)
5160 : : return status;
5161 : :
5162 : 0 : status = ice_sched_set_save_vsi_srl_node_bw(pi, vsi_handle, tc,
5163 : : cfg_node, ICE_MAX_BW,
5164 : : max_bw);
5165 [ # # ]: 0 : if (status)
5166 : : return status;
5167 : :
5168 : 0 : return ice_sched_set_save_vsi_srl_node_bw(pi, vsi_handle, tc, cfg_node,
5169 : : ICE_SHARED_BW, shared_bw);
5170 : : }
5171 : :
5172 : : /**
5173 : : * ice_sched_set_vsi_bw_shared_lmt - set VSI BW shared limit
5174 : : * @pi: port information structure
5175 : : * @vsi_handle: software VSI handle
5176 : : * @min_bw: minimum bandwidth in Kbps
5177 : : * @max_bw: maximum bandwidth in Kbps
5178 : : * @shared_bw: shared bandwidth in Kbps
5179 : : *
5180 : : * Configure shared rate limiter(SRL) of all VSI type nodes across all traffic
5181 : : * classes for VSI matching handle. When BW value of ICE_SCHED_DFLT_BW is
5182 : : * passed, it removes those value(s) from the node.
5183 : : */
5184 : : int
5185 : 0 : ice_sched_set_vsi_bw_shared_lmt(struct ice_port_info *pi, u16 vsi_handle,
5186 : : u32 min_bw, u32 max_bw, u32 shared_bw)
5187 : : {
5188 : : int status = 0;
5189 : : u8 tc;
5190 : :
5191 [ # # ]: 0 : if (!pi)
5192 : : return ICE_ERR_PARAM;
5193 : :
5194 [ # # ]: 0 : if (!ice_is_vsi_valid(pi->hw, vsi_handle))
5195 : : return ICE_ERR_PARAM;
5196 : :
5197 : 0 : ice_acquire_lock(&pi->sched_lock);
5198 : 0 : status = ice_sched_validate_vsi_srl_node(pi, vsi_handle);
5199 [ # # ]: 0 : if (status)
5200 : 0 : goto exit_set_vsi_bw_shared_lmt;
5201 : : /* Return success if no nodes are present across TC */
5202 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
5203 : : struct ice_sched_node *tc_node, *vsi_node;
5204 : :
5205 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
5206 [ # # ]: 0 : if (!tc_node)
5207 : 0 : continue;
5208 : :
5209 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
5210 [ # # ]: 0 : if (!vsi_node)
5211 : 0 : continue;
5212 : :
5213 : 0 : status = ice_sched_set_vsi_node_srl_per_tc(pi, vsi_handle, tc,
5214 : : min_bw, max_bw,
5215 : : shared_bw);
5216 [ # # ]: 0 : if (status)
5217 : : break;
5218 : : }
5219 : :
5220 : 0 : exit_set_vsi_bw_shared_lmt:
5221 : : ice_release_lock(&pi->sched_lock);
5222 : 0 : return status;
5223 : : }
5224 : :
5225 : : /**
5226 : : * ice_sched_validate_agg_srl_node - validate AGG SRL node
5227 : : * @pi: port information structure
5228 : : * @agg_id: aggregator ID
5229 : : *
5230 : : * This function validates SRL node of the AGG node if available SRL layer is
5231 : : * different than the AGG node layer on all TC(s).This function needs to be
5232 : : * called with scheduler lock held.
5233 : : */
5234 : : static int
5235 : 0 : ice_sched_validate_agg_srl_node(struct ice_port_info *pi, u32 agg_id)
5236 : : {
5237 : : u8 sel_layer = ICE_SCHED_INVAL_LAYER_NUM;
5238 : : struct ice_sched_agg_info *agg_info;
5239 : : bool agg_id_present = false;
5240 : : int status = 0;
5241 : : u8 tc;
5242 : :
5243 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(agg_info, &pi->hw->agg_list, ice_sched_agg_info,
# # ]
5244 : : list_entry)
5245 [ # # ]: 0 : if (agg_info->agg_id == agg_id) {
5246 : : agg_id_present = true;
5247 : : break;
5248 : : }
5249 [ # # ]: 0 : if (!agg_id_present)
5250 : : return ICE_ERR_PARAM;
5251 : : /* Return success if no nodes are present across TC */
5252 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
5253 : : struct ice_sched_node *tc_node, *agg_node;
5254 : : enum ice_rl_type rl_type = ICE_SHARED_BW;
5255 : :
5256 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
5257 [ # # ]: 0 : if (!tc_node)
5258 : 0 : continue;
5259 : :
5260 : : agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
5261 [ # # ]: 0 : if (!agg_node)
5262 : 0 : continue;
5263 : : /* SRL bandwidth layer selection */
5264 [ # # ]: 0 : if (sel_layer == ICE_SCHED_INVAL_LAYER_NUM) {
5265 : 0 : u8 node_layer = agg_node->tx_sched_layer;
5266 : : u8 layer_num;
5267 : :
5268 : 0 : layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
5269 : : node_layer);
5270 [ # # ]: 0 : if (layer_num >= pi->hw->num_tx_sched_layers)
5271 : : return ICE_ERR_PARAM;
5272 : : sel_layer = layer_num;
5273 : : }
5274 : :
5275 [ # # ]: 0 : status = ice_sched_validate_srl_node(agg_node, sel_layer);
5276 : : if (status)
5277 : : break;
5278 : : }
5279 : : return status;
5280 : : }
5281 : :
5282 : : /**
5283 : : * ice_sched_validate_agg_id - Validate aggregator id
5284 : : * @pi: port information structure
5285 : : * @agg_id: aggregator ID
5286 : : *
5287 : : * This function validates aggregator id. Caller holds the scheduler lock.
5288 : : */
5289 : : static int
5290 : 0 : ice_sched_validate_agg_id(struct ice_port_info *pi, u32 agg_id)
5291 : : {
5292 : : struct ice_sched_agg_info *agg_info;
5293 : : struct ice_sched_agg_info *tmp;
5294 : : bool agg_id_present = false;
5295 : : int status;
5296 : :
5297 : 0 : status = ice_sched_validate_agg_srl_node(pi, agg_id);
5298 [ # # ]: 0 : if (status)
5299 : : return status;
5300 : :
5301 [ # # # # : 0 : LIST_FOR_EACH_ENTRY_SAFE(agg_info, tmp, &pi->hw->agg_list,
# # # # #
# # # ]
5302 : : ice_sched_agg_info, list_entry)
5303 [ # # ]: 0 : if (agg_info->agg_id == agg_id) {
5304 : : agg_id_present = true;
5305 : : break;
5306 : : }
5307 : :
5308 [ # # ]: 0 : if (!agg_id_present)
5309 : 0 : return ICE_ERR_PARAM;
5310 : :
5311 : : return 0;
5312 : : }
5313 : :
5314 : : /**
5315 : : * ice_sched_set_save_agg_srl_node_bw - set aggregator shared limit values
5316 : : * @pi: port information structure
5317 : : * @agg_id: aggregator ID
5318 : : * @tc: traffic class
5319 : : * @srl_node: sched node to configure
5320 : : * @rl_type: rate limit type minimum, maximum, or shared
5321 : : * @bw: minimum, maximum, or shared bandwidth in Kbps
5322 : : *
5323 : : * Configure shared rate limiter(SRL) of aggregator type nodes across
5324 : : * requested traffic class, and saves those value for later use for
5325 : : * replaying purposes. The caller holds the scheduler lock.
5326 : : */
5327 : : static int
5328 : 0 : ice_sched_set_save_agg_srl_node_bw(struct ice_port_info *pi, u32 agg_id, u8 tc,
5329 : : struct ice_sched_node *srl_node,
5330 : : enum ice_rl_type rl_type, u32 bw)
5331 : : {
5332 : : int status;
5333 : :
5334 [ # # ]: 0 : if (bw == ICE_SCHED_DFLT_BW) {
5335 : : status = ice_sched_set_node_bw_dflt_lmt(pi, srl_node, rl_type);
5336 : : } else {
5337 : 0 : status = ice_sched_set_node_bw_lmt(pi, srl_node, rl_type, bw);
5338 [ # # ]: 0 : if (status)
5339 : : return status;
5340 : 0 : status = ice_sched_save_agg_bw(pi, agg_id, tc, rl_type, bw);
5341 : : }
5342 : : return status;
5343 : : }
5344 : :
5345 : : /**
5346 : : * ice_sched_set_agg_node_srl_per_tc - set aggregator SRL per tc
5347 : : * @pi: port information structure
5348 : : * @agg_id: aggregator ID
5349 : : * @tc: traffic class
5350 : : * @min_bw: minimum bandwidth in Kbps
5351 : : * @max_bw: maximum bandwidth in Kbps
5352 : : * @shared_bw: shared bandwidth in Kbps
5353 : : *
5354 : : * This function configures the shared rate limiter(SRL) of aggregator type
5355 : : * node for a given traffic class for aggregator matching agg_id. When BW
5356 : : * value of ICE_SCHED_DFLT_BW is passed, it removes SRL from the node. Caller
5357 : : * holds the scheduler lock.
5358 : : */
5359 : : static int
5360 : 0 : ice_sched_set_agg_node_srl_per_tc(struct ice_port_info *pi, u32 agg_id,
5361 : : u8 tc, u32 min_bw, u32 max_bw, u32 shared_bw)
5362 : : {
5363 : : struct ice_sched_node *tc_node, *agg_node, *cfg_node;
5364 : : enum ice_rl_type rl_type = ICE_SHARED_BW;
5365 : : int status = ICE_ERR_CFG;
5366 : : u8 layer_num;
5367 : :
5368 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
5369 [ # # ]: 0 : if (!tc_node)
5370 : : return ICE_ERR_CFG;
5371 : :
5372 : : agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
5373 [ # # ]: 0 : if (!agg_node)
5374 : : return ICE_ERR_CFG;
5375 : :
5376 : 0 : layer_num = ice_sched_get_rl_prof_layer(pi, rl_type,
5377 : 0 : agg_node->tx_sched_layer);
5378 [ # # ]: 0 : if (layer_num >= pi->hw->num_tx_sched_layers)
5379 : : return ICE_ERR_PARAM;
5380 : :
5381 : : /* SRL node may be different */
5382 : : cfg_node = ice_sched_get_srl_node(agg_node, layer_num);
5383 [ # # ]: 0 : if (!cfg_node)
5384 : : return ICE_ERR_CFG;
5385 : :
5386 : 0 : status = ice_sched_set_save_agg_srl_node_bw(pi, agg_id, tc, cfg_node,
5387 : : ICE_MIN_BW, min_bw);
5388 [ # # ]: 0 : if (status)
5389 : : return status;
5390 : :
5391 : 0 : status = ice_sched_set_save_agg_srl_node_bw(pi, agg_id, tc, cfg_node,
5392 : : ICE_MAX_BW, max_bw);
5393 [ # # ]: 0 : if (status)
5394 : : return status;
5395 : :
5396 : 0 : status = ice_sched_set_save_agg_srl_node_bw(pi, agg_id, tc, cfg_node,
5397 : : ICE_SHARED_BW, shared_bw);
5398 : 0 : return status;
5399 : : }
5400 : :
5401 : : /**
5402 : : * ice_sched_set_agg_bw_shared_lmt - set aggregator BW shared limit
5403 : : * @pi: port information structure
5404 : : * @agg_id: aggregator ID
5405 : : * @min_bw: minimum bandwidth in Kbps
5406 : : * @max_bw: maximum bandwidth in Kbps
5407 : : * @shared_bw: shared bandwidth in Kbps
5408 : : *
5409 : : * This function configures the shared rate limiter(SRL) of all aggregator type
5410 : : * nodes across all traffic classes for aggregator matching agg_id. When
5411 : : * BW value of ICE_SCHED_DFLT_BW is passed, it removes SRL from the
5412 : : * node(s).
5413 : : */
5414 : : int
5415 : 0 : ice_sched_set_agg_bw_shared_lmt(struct ice_port_info *pi, u32 agg_id,
5416 : : u32 min_bw, u32 max_bw, u32 shared_bw)
5417 : : {
5418 : : int status;
5419 : : u8 tc;
5420 : :
5421 [ # # ]: 0 : if (!pi)
5422 : : return ICE_ERR_PARAM;
5423 : :
5424 : 0 : ice_acquire_lock(&pi->sched_lock);
5425 : 0 : status = ice_sched_validate_agg_id(pi, agg_id);
5426 [ # # ]: 0 : if (status)
5427 : 0 : goto exit_agg_bw_shared_lmt;
5428 : :
5429 : : /* Return success if no nodes are present across TC */
5430 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
5431 : : struct ice_sched_node *tc_node, *agg_node;
5432 : :
5433 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
5434 [ # # ]: 0 : if (!tc_node)
5435 : 0 : continue;
5436 : :
5437 : : agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id);
5438 [ # # ]: 0 : if (!agg_node)
5439 : 0 : continue;
5440 : :
5441 : 0 : status = ice_sched_set_agg_node_srl_per_tc(pi, agg_id, tc,
5442 : : min_bw, max_bw,
5443 : : shared_bw);
5444 [ # # ]: 0 : if (status)
5445 : : break;
5446 : : }
5447 : :
5448 : 0 : exit_agg_bw_shared_lmt:
5449 : : ice_release_lock(&pi->sched_lock);
5450 : 0 : return status;
5451 : : }
5452 : :
5453 : : /**
5454 : : * ice_sched_set_agg_bw_shared_lmt_per_tc - set aggregator BW shared lmt per tc
5455 : : * @pi: port information structure
5456 : : * @agg_id: aggregator ID
5457 : : * @tc: traffic class
5458 : : * @min_bw: minimum bandwidth in Kbps
5459 : : * @max_bw: maximum bandwidth in Kbps
5460 : : * @shared_bw: shared bandwidth in Kbps
5461 : : *
5462 : : * This function configures the shared rate limiter(SRL) of aggregator type
5463 : : * node for a given traffic class for aggregator matching agg_id. When BW
5464 : : * value of ICE_SCHED_DFLT_BW is passed, it removes SRL from the node.
5465 : : */
5466 : : int
5467 : 0 : ice_sched_set_agg_bw_shared_lmt_per_tc(struct ice_port_info *pi, u32 agg_id,
5468 : : u8 tc, u32 min_bw, u32 max_bw,
5469 : : u32 shared_bw)
5470 : : {
5471 : : int status;
5472 : :
5473 [ # # ]: 0 : if (!pi)
5474 : : return ICE_ERR_PARAM;
5475 : 0 : ice_acquire_lock(&pi->sched_lock);
5476 : 0 : status = ice_sched_validate_agg_id(pi, agg_id);
5477 [ # # ]: 0 : if (status)
5478 : 0 : goto exit_agg_bw_shared_lmt_per_tc;
5479 : :
5480 : 0 : status = ice_sched_set_agg_node_srl_per_tc(pi, agg_id, tc, min_bw,
5481 : : max_bw, shared_bw);
5482 : :
5483 : 0 : exit_agg_bw_shared_lmt_per_tc:
5484 : : ice_release_lock(&pi->sched_lock);
5485 : 0 : return status;
5486 : : }
5487 : :
5488 : : /**
5489 : : * ice_sched_cfg_sibl_node_prio - configure node sibling priority
5490 : : * @pi: port information structure
5491 : : * @node: sched node to configure
5492 : : * @priority: sibling priority
5493 : : *
5494 : : * This function configures node element's sibling priority only. This
5495 : : * function needs to be called with scheduler lock held.
5496 : : */
5497 : : int
5498 : 0 : ice_sched_cfg_sibl_node_prio(struct ice_port_info *pi,
5499 : : struct ice_sched_node *node, u8 priority)
5500 : : {
5501 : : struct ice_aqc_txsched_elem_data buf;
5502 : : struct ice_aqc_txsched_elem *data;
5503 : 0 : struct ice_hw *hw = pi->hw;
5504 : : int status;
5505 : :
5506 [ # # ]: 0 : if (!hw)
5507 : : return ICE_ERR_PARAM;
5508 : 0 : buf = node->info;
5509 : : data = &buf.data;
5510 : 0 : data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC;
5511 : 0 : priority = (priority << ICE_AQC_ELEM_GENERIC_PRIO_S) &
5512 : : ICE_AQC_ELEM_GENERIC_PRIO_M;
5513 : 0 : data->generic &= ~ICE_AQC_ELEM_GENERIC_PRIO_M;
5514 : 0 : data->generic |= priority;
5515 : :
5516 : : /* Configure element */
5517 : 0 : status = ice_sched_update_elem(hw, node, &buf);
5518 : 0 : return status;
5519 : : }
5520 : :
5521 : : /**
5522 : : * ice_cfg_rl_burst_size - Set burst size value
5523 : : * @hw: pointer to the HW struct
5524 : : * @bytes: burst size in bytes
5525 : : *
5526 : : * This function configures/set the burst size to requested new value. The new
5527 : : * burst size value is used for future rate limit calls. It doesn't change the
5528 : : * existing or previously created RL profiles.
5529 : : */
5530 : 0 : int ice_cfg_rl_burst_size(struct ice_hw *hw, u32 bytes)
5531 : : {
5532 : : u16 burst_size_to_prog;
5533 : :
5534 [ # # ]: 0 : if (bytes < ICE_MIN_BURST_SIZE_ALLOWED ||
5535 : : bytes > ICE_MAX_BURST_SIZE_ALLOWED)
5536 : : return ICE_ERR_PARAM;
5537 [ # # ]: 0 : if (ice_round_to_num(bytes, 64) <=
5538 : : ICE_MAX_BURST_SIZE_64_BYTE_GRANULARITY) {
5539 : : /* 64 byte granularity case */
5540 : : /* Disable MSB granularity bit */
5541 : : burst_size_to_prog = ICE_64_BYTE_GRANULARITY;
5542 : : /* round number to nearest 64 byte granularity */
5543 : : bytes = ice_round_to_num(bytes, 64);
5544 : : /* The value is in 64 byte chunks */
5545 : 0 : burst_size_to_prog |= (u16)(bytes / 64);
5546 : : } else {
5547 : : /* k bytes granularity case */
5548 : : /* Enable MSB granularity bit */
5549 : : burst_size_to_prog = ICE_KBYTE_GRANULARITY;
5550 : : /* round number to nearest 1024 granularity */
5551 : : bytes = ice_round_to_num(bytes, 1024);
5552 : : /* check rounding doesn't go beyond allowed */
5553 : : if (bytes > ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY)
5554 : : bytes = ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY;
5555 : : /* The value is in k bytes */
5556 : 0 : burst_size_to_prog |= (u16)(bytes / 1024);
5557 : : }
5558 : 0 : hw->max_burst_size = burst_size_to_prog;
5559 : 0 : return 0;
5560 : : }
5561 : :
5562 : : /**
5563 : : * ice_sched_replay_node_prio - re-configure node priority
5564 : : * @hw: pointer to the HW struct
5565 : : * @node: sched node to configure
5566 : : * @priority: priority value
5567 : : *
5568 : : * This function configures node element's priority value. It
5569 : : * needs to be called with scheduler lock held.
5570 : : */
5571 : : static int
5572 : 0 : ice_sched_replay_node_prio(struct ice_hw *hw, struct ice_sched_node *node,
5573 : : u8 priority)
5574 : : {
5575 : : struct ice_aqc_txsched_elem_data buf;
5576 : : struct ice_aqc_txsched_elem *data;
5577 : : int status;
5578 : :
5579 : 0 : buf = node->info;
5580 : : data = &buf.data;
5581 : 0 : data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC;
5582 : 0 : data->generic = priority;
5583 : :
5584 : : /* Configure element */
5585 : 0 : status = ice_sched_update_elem(hw, node, &buf);
5586 : 0 : return status;
5587 : : }
5588 : :
5589 : : /**
5590 : : * ice_sched_replay_node_bw - replay node(s) BW
5591 : : * @hw: pointer to the HW struct
5592 : : * @node: sched node to configure
5593 : : * @bw_t_info: BW type information
5594 : : *
5595 : : * This function restores node's BW from bw_t_info. The caller needs
5596 : : * to hold the scheduler lock.
5597 : : */
5598 : : static int
5599 : 0 : ice_sched_replay_node_bw(struct ice_hw *hw, struct ice_sched_node *node,
5600 : : struct ice_bw_type_info *bw_t_info)
5601 : : {
5602 : 0 : struct ice_port_info *pi = hw->port_info;
5603 : : int status = ICE_ERR_PARAM;
5604 : : u16 bw_alloc;
5605 : :
5606 [ # # ]: 0 : if (!node)
5607 : : return status;
5608 [ # # ]: 0 : if (!ice_is_any_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CNT))
5609 : : return 0;
5610 [ # # ]: 0 : if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_PRIO)) {
5611 : 0 : status = ice_sched_replay_node_prio(hw, node,
5612 : 0 : bw_t_info->generic);
5613 [ # # ]: 0 : if (status)
5614 : : return status;
5615 : : }
5616 [ # # ]: 0 : if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CIR)) {
5617 : 0 : status = ice_sched_set_node_bw_lmt(pi, node, ICE_MIN_BW,
5618 : : bw_t_info->cir_bw.bw);
5619 [ # # ]: 0 : if (status)
5620 : : return status;
5621 : : }
5622 [ # # ]: 0 : if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CIR_WT)) {
5623 : 0 : bw_alloc = bw_t_info->cir_bw.bw_alloc;
5624 : 0 : status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MIN_BW,
5625 : : bw_alloc);
5626 [ # # ]: 0 : if (status)
5627 : : return status;
5628 : : }
5629 [ # # ]: 0 : if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_EIR)) {
5630 : 0 : status = ice_sched_set_node_bw_lmt(pi, node, ICE_MAX_BW,
5631 : : bw_t_info->eir_bw.bw);
5632 [ # # ]: 0 : if (status)
5633 : : return status;
5634 : : }
5635 [ # # ]: 0 : if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_EIR_WT)) {
5636 : 0 : bw_alloc = bw_t_info->eir_bw.bw_alloc;
5637 : 0 : status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MAX_BW,
5638 : : bw_alloc);
5639 [ # # ]: 0 : if (status)
5640 : : return status;
5641 : : }
5642 [ # # ]: 0 : if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_SHARED))
5643 : 0 : status = ice_sched_set_node_bw_lmt(pi, node, ICE_SHARED_BW,
5644 : : bw_t_info->shared_bw);
5645 : : return status;
5646 : : }
5647 : :
5648 : : /**
5649 : : * ice_sched_replay_agg_bw - replay aggregator node(s) BW
5650 : : * @hw: pointer to the HW struct
5651 : : * @agg_info: aggregator data structure
5652 : : *
5653 : : * This function re-creates aggregator type nodes. The caller needs to hold
5654 : : * the scheduler lock.
5655 : : */
5656 : : static int
5657 : 0 : ice_sched_replay_agg_bw(struct ice_hw *hw, struct ice_sched_agg_info *agg_info)
5658 : : {
5659 : : struct ice_sched_node *tc_node, *agg_node;
5660 : : int status = 0;
5661 : : u8 tc;
5662 : :
5663 [ # # ]: 0 : if (!agg_info)
5664 : : return ICE_ERR_PARAM;
5665 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
5666 [ # # ]: 0 : if (!ice_is_any_bit_set(agg_info->bw_t_info[tc].bw_t_bitmap,
5667 : : ICE_BW_TYPE_CNT))
5668 : 0 : continue;
5669 : 0 : tc_node = ice_sched_get_tc_node(hw->port_info, tc);
5670 [ # # ]: 0 : if (!tc_node) {
5671 : : status = ICE_ERR_PARAM;
5672 : : break;
5673 : : }
5674 [ # # ]: 0 : agg_node = ice_sched_get_agg_node(hw->port_info, tc_node,
5675 : : agg_info->agg_id);
5676 [ # # ]: 0 : if (!agg_node) {
5677 : : status = ICE_ERR_PARAM;
5678 : : break;
5679 : : }
5680 : 0 : status = ice_sched_replay_node_bw(hw, agg_node,
5681 : : &agg_info->bw_t_info[tc]);
5682 [ # # ]: 0 : if (status)
5683 : : break;
5684 : : }
5685 : : return status;
5686 : : }
5687 : :
5688 : : /**
5689 : : * ice_sched_get_ena_tc_bitmap - get enabled TC bitmap
5690 : : * @pi: port info struct
5691 : : * @tc_bitmap: 8 bits TC bitmap to check
5692 : : * @ena_tc_bitmap: 8 bits enabled TC bitmap to return
5693 : : *
5694 : : * This function returns enabled TC bitmap in variable ena_tc_bitmap. Some TCs
5695 : : * may be missing, it returns enabled TCs. This function needs to be called with
5696 : : * scheduler lock held.
5697 : : */
5698 : : static void
5699 : 0 : ice_sched_get_ena_tc_bitmap(struct ice_port_info *pi, ice_bitmap_t *tc_bitmap,
5700 : : ice_bitmap_t *ena_tc_bitmap)
5701 : : {
5702 : : u8 tc;
5703 : :
5704 : : /* Some TC(s) may be missing after reset, adjust for replay */
5705 [ # # ]: 0 : ice_for_each_traffic_class(tc)
5706 [ # # # # ]: 0 : if (ice_is_tc_ena(*tc_bitmap, tc) &&
5707 : 0 : (ice_sched_get_tc_node(pi, tc)))
5708 : : ice_set_bit(tc, ena_tc_bitmap);
5709 : 0 : }
5710 : :
5711 : : /**
5712 : : * ice_sched_replay_agg - recreate aggregator node(s)
5713 : : * @hw: pointer to the HW struct
5714 : : *
5715 : : * This function recreate aggregator type nodes which are not replayed earlier.
5716 : : * It also replay aggregator BW information. These aggregator nodes are not
5717 : : * associated with VSI type node yet.
5718 : : */
5719 : 0 : void ice_sched_replay_agg(struct ice_hw *hw)
5720 : : {
5721 : 0 : struct ice_port_info *pi = hw->port_info;
5722 : : struct ice_sched_agg_info *agg_info;
5723 : :
5724 : 0 : ice_acquire_lock(&pi->sched_lock);
5725 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
# # ]
5726 : : list_entry)
5727 : : /* replay aggregator (re-create aggregator node) */
5728 : : if (!ice_cmp_bitmap(agg_info->tc_bitmap,
5729 : : agg_info->replay_tc_bitmap,
5730 : : ICE_MAX_TRAFFIC_CLASS)) {
5731 : : ice_declare_bitmap(replay_bitmap,
5732 : : ICE_MAX_TRAFFIC_CLASS);
5733 : : int status;
5734 : :
5735 : : ice_zero_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
5736 : 0 : ice_sched_get_ena_tc_bitmap(pi,
5737 : 0 : agg_info->replay_tc_bitmap,
5738 : : replay_bitmap);
5739 : 0 : status = ice_sched_cfg_agg(hw->port_info,
5740 : : agg_info->agg_id,
5741 : : ICE_AGG_TYPE_AGG,
5742 : : replay_bitmap);
5743 [ # # ]: 0 : if (status) {
5744 [ # # ]: 0 : ice_info(hw, "Replay agg id[%d] failed\n",
5745 : : agg_info->agg_id);
5746 : : /* Move on to next one */
5747 : 0 : continue;
5748 : : }
5749 : : /* Replay aggregator node BW (restore aggregator BW) */
5750 : 0 : status = ice_sched_replay_agg_bw(hw, agg_info);
5751 [ # # ]: 0 : if (status)
5752 [ # # ]: 0 : ice_info(hw, "Replay agg bw [id=%d] failed\n",
5753 : : agg_info->agg_id);
5754 : : }
5755 : : ice_release_lock(&pi->sched_lock);
5756 : 0 : }
5757 : :
5758 : : /**
5759 : : * ice_sched_replay_agg_vsi_preinit - Agg/VSI replay pre initialization
5760 : : * @hw: pointer to the HW struct
5761 : : *
5762 : : * This function initialize aggregator(s) TC bitmap to zero. A required
5763 : : * preinit step for replaying aggregators.
5764 : : */
5765 : 0 : void ice_sched_replay_agg_vsi_preinit(struct ice_hw *hw)
5766 : : {
5767 : 0 : struct ice_port_info *pi = hw->port_info;
5768 : : struct ice_sched_agg_info *agg_info;
5769 : :
5770 : 0 : ice_acquire_lock(&pi->sched_lock);
5771 [ # # # # : 0 : LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info,
# # ]
5772 : : list_entry) {
5773 : : struct ice_sched_agg_vsi_info *agg_vsi_info;
5774 : :
5775 : 0 : agg_info->tc_bitmap[0] = 0;
5776 [ # # # # ]: 0 : LIST_FOR_EACH_ENTRY(agg_vsi_info, &agg_info->agg_vsi_list,
5777 : : ice_sched_agg_vsi_info, list_entry)
5778 [ # # ]: 0 : agg_vsi_info->tc_bitmap[0] = 0;
5779 : : }
5780 : : ice_release_lock(&pi->sched_lock);
5781 : 0 : }
5782 : :
5783 : : /**
5784 : : * ice_sched_replay_root_node_bw - replay root node BW
5785 : : * @pi: port information structure
5786 : : *
5787 : : * Replay root node BW settings.
5788 : : */
5789 : 0 : int ice_sched_replay_root_node_bw(struct ice_port_info *pi)
5790 : : {
5791 : : int status = 0;
5792 : :
5793 [ # # ]: 0 : if (!pi->hw)
5794 : : return ICE_ERR_PARAM;
5795 : 0 : ice_acquire_lock(&pi->sched_lock);
5796 : :
5797 : 0 : status = ice_sched_replay_node_bw(pi->hw, pi->root,
5798 : : &pi->root_node_bw_t_info);
5799 : : ice_release_lock(&pi->sched_lock);
5800 : 0 : return status;
5801 : : }
5802 : :
5803 : : /**
5804 : : * ice_sched_replay_tc_node_bw - replay TC node(s) BW
5805 : : * @pi: port information structure
5806 : : *
5807 : : * This function replay TC nodes.
5808 : : */
5809 : 0 : int ice_sched_replay_tc_node_bw(struct ice_port_info *pi)
5810 : : {
5811 : : int status = 0;
5812 : : u8 tc;
5813 : :
5814 [ # # ]: 0 : if (!pi->hw)
5815 : : return ICE_ERR_PARAM;
5816 : 0 : ice_acquire_lock(&pi->sched_lock);
5817 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
5818 : : struct ice_sched_node *tc_node;
5819 : :
5820 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
5821 [ # # ]: 0 : if (!tc_node)
5822 : 0 : continue; /* TC not present */
5823 : 0 : status = ice_sched_replay_node_bw(pi->hw, tc_node,
5824 : : &pi->tc_node_bw_t_info[tc]);
5825 [ # # ]: 0 : if (status)
5826 : : break;
5827 : : }
5828 : : ice_release_lock(&pi->sched_lock);
5829 : 0 : return status;
5830 : : }
5831 : :
5832 : : /**
5833 : : * ice_sched_replay_vsi_bw - replay VSI type node(s) BW
5834 : : * @hw: pointer to the HW struct
5835 : : * @vsi_handle: software VSI handle
5836 : : * @tc_bitmap: 8 bits TC bitmap
5837 : : *
5838 : : * This function replays VSI type nodes bandwidth. This function needs to be
5839 : : * called with scheduler lock held.
5840 : : */
5841 : : static int
5842 : 0 : ice_sched_replay_vsi_bw(struct ice_hw *hw, u16 vsi_handle,
5843 : : ice_bitmap_t *tc_bitmap)
5844 : : {
5845 : : struct ice_sched_node *vsi_node, *tc_node;
5846 : 0 : struct ice_port_info *pi = hw->port_info;
5847 : : struct ice_bw_type_info *bw_t_info;
5848 : : struct ice_vsi_ctx *vsi_ctx;
5849 : : int status = 0;
5850 : : u8 tc;
5851 : :
5852 : 0 : vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle);
5853 [ # # ]: 0 : if (!vsi_ctx)
5854 : : return ICE_ERR_PARAM;
5855 [ # # ]: 0 : ice_for_each_traffic_class(tc) {
5856 [ # # ]: 0 : if (!ice_is_tc_ena(*tc_bitmap, tc))
5857 : 0 : continue;
5858 : 0 : tc_node = ice_sched_get_tc_node(pi, tc);
5859 [ # # ]: 0 : if (!tc_node)
5860 : 0 : continue;
5861 : 0 : vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle);
5862 [ # # ]: 0 : if (!vsi_node)
5863 : 0 : continue;
5864 : 0 : bw_t_info = &vsi_ctx->sched.bw_t_info[tc];
5865 : 0 : status = ice_sched_replay_node_bw(hw, vsi_node, bw_t_info);
5866 [ # # ]: 0 : if (status)
5867 : : break;
5868 : : }
5869 : : return status;
5870 : : }
5871 : :
5872 : : /**
5873 : : * ice_sched_replay_vsi_agg - replay aggregator & VSI to aggregator node(s)
5874 : : * @hw: pointer to the HW struct
5875 : : * @vsi_handle: software VSI handle
5876 : : *
5877 : : * This function replays aggregator node, VSI to aggregator type nodes, and
5878 : : * their node bandwidth information. This function needs to be called with
5879 : : * scheduler lock held.
5880 : : */
5881 : : static int
5882 : 0 : ice_sched_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle)
5883 : : {
5884 : : ice_declare_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
5885 : : struct ice_sched_agg_vsi_info *agg_vsi_info;
5886 : 0 : struct ice_port_info *pi = hw->port_info;
5887 : : struct ice_sched_agg_info *agg_info;
5888 : : int status;
5889 : :
5890 : : ice_zero_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
5891 [ # # ]: 0 : if (!ice_is_vsi_valid(hw, vsi_handle))
5892 : : return ICE_ERR_PARAM;
5893 : 0 : agg_info = ice_get_vsi_agg_info(hw, vsi_handle);
5894 [ # # ]: 0 : if (!agg_info)
5895 : : return 0; /* Not present in list - default Agg case */
5896 : : agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle);
5897 [ # # ]: 0 : if (!agg_vsi_info)
5898 : : return 0; /* Not present in list - default Agg case */
5899 : 0 : ice_sched_get_ena_tc_bitmap(pi, agg_info->replay_tc_bitmap,
5900 : : replay_bitmap);
5901 : : /* Replay aggregator node associated to vsi_handle */
5902 : 0 : status = ice_sched_cfg_agg(hw->port_info, agg_info->agg_id,
5903 : : ICE_AGG_TYPE_AGG, replay_bitmap);
5904 [ # # ]: 0 : if (status)
5905 : : return status;
5906 : : /* Replay aggregator node BW (restore aggregator BW) */
5907 : 0 : status = ice_sched_replay_agg_bw(hw, agg_info);
5908 [ # # ]: 0 : if (status)
5909 : : return status;
5910 : :
5911 : : ice_zero_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS);
5912 : 0 : ice_sched_get_ena_tc_bitmap(pi, agg_vsi_info->replay_tc_bitmap,
5913 : : replay_bitmap);
5914 : : /* Move this VSI (vsi_handle) to above aggregator */
5915 : 0 : status = ice_sched_assoc_vsi_to_agg(pi, agg_info->agg_id, vsi_handle,
5916 : : replay_bitmap);
5917 [ # # ]: 0 : if (status)
5918 : : return status;
5919 : : /* Replay VSI BW (restore VSI BW) */
5920 : 0 : return ice_sched_replay_vsi_bw(hw, vsi_handle,
5921 : 0 : agg_vsi_info->tc_bitmap);
5922 : : }
5923 : :
5924 : : /**
5925 : : * ice_replay_vsi_agg - replay VSI to aggregator node
5926 : : * @hw: pointer to the HW struct
5927 : : * @vsi_handle: software VSI handle
5928 : : *
5929 : : * This function replays association of VSI to aggregator type nodes, and
5930 : : * node bandwidth information.
5931 : : */
5932 : 0 : int ice_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle)
5933 : : {
5934 : 0 : struct ice_port_info *pi = hw->port_info;
5935 : : int status;
5936 : :
5937 : 0 : ice_acquire_lock(&pi->sched_lock);
5938 : 0 : status = ice_sched_replay_vsi_agg(hw, vsi_handle);
5939 : : ice_release_lock(&pi->sched_lock);
5940 : 0 : return status;
5941 : : }
5942 : :
5943 : : /**
5944 : : * ice_sched_replay_q_bw - replay queue type node BW
5945 : : * @pi: port information structure
5946 : : * @q_ctx: queue context structure
5947 : : *
5948 : : * This function replays queue type node bandwidth. This function needs to be
5949 : : * called with scheduler lock held.
5950 : : */
5951 : : int
5952 : 0 : ice_sched_replay_q_bw(struct ice_port_info *pi, struct ice_q_ctx *q_ctx)
5953 : : {
5954 : : struct ice_sched_node *q_node;
5955 : :
5956 : : /* Following also checks the presence of node in tree */
5957 : 0 : q_node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid);
5958 [ # # ]: 0 : if (!q_node)
5959 : : return ICE_ERR_PARAM;
5960 : 0 : return ice_sched_replay_node_bw(pi->hw, q_node, &q_ctx->bw_t_info);
5961 : : }
|