Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2022 Intel Corporation
3 : : */
4 : : #include <stdlib.h>
5 : :
6 : : #include <rte_ethdev.h>
7 : : #include <rte_tm_driver.h>
8 : :
9 : : #include "ice_ethdev.h"
10 : : #include "ice_rxtx.h"
11 : :
12 : : static int ice_hierarchy_commit(struct rte_eth_dev *dev,
13 : : int clear_on_fail,
14 : : struct rte_tm_error *error);
15 : : static int ice_tm_node_add(struct rte_eth_dev *dev, uint32_t node_id,
16 : : uint32_t parent_node_id, uint32_t priority,
17 : : uint32_t weight, uint32_t level_id,
18 : : const struct rte_tm_node_params *params,
19 : : struct rte_tm_error *error);
20 : : static int ice_node_query(const struct rte_eth_dev *dev, uint32_t node_id,
21 : : uint32_t *parent_node_id, uint32_t *priority,
22 : : uint32_t *weight, uint32_t *level_id,
23 : : struct rte_tm_node_params *params,
24 : : struct rte_tm_error *error);
25 : : static int ice_tm_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
26 : : struct rte_tm_error *error);
27 : : static int ice_node_type_get(struct rte_eth_dev *dev, uint32_t node_id,
28 : : int *is_leaf, struct rte_tm_error *error);
29 : : static int ice_shaper_profile_add(struct rte_eth_dev *dev,
30 : : uint32_t shaper_profile_id,
31 : : const struct rte_tm_shaper_params *profile,
32 : : struct rte_tm_error *error);
33 : : static int ice_shaper_profile_del(struct rte_eth_dev *dev,
34 : : uint32_t shaper_profile_id,
35 : : struct rte_tm_error *error);
36 : :
37 : : const struct rte_tm_ops ice_tm_ops = {
38 : : .shaper_profile_add = ice_shaper_profile_add,
39 : : .shaper_profile_delete = ice_shaper_profile_del,
40 : : .node_add = ice_tm_node_add,
41 : : .node_delete = ice_tm_node_delete,
42 : : .node_type_get = ice_node_type_get,
43 : : .node_query = ice_node_query,
44 : : .hierarchy_commit = ice_hierarchy_commit,
45 : : };
46 : :
47 : : void
48 : 0 : ice_tm_conf_init(struct rte_eth_dev *dev)
49 : : {
50 : 0 : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
51 : :
52 : : /* initialize node configuration */
53 : 0 : TAILQ_INIT(&pf->tm_conf.shaper_profile_list);
54 : 0 : pf->tm_conf.root = NULL;
55 : 0 : pf->tm_conf.committed = false;
56 : 0 : pf->tm_conf.clear_on_fail = false;
57 : 0 : }
58 : :
59 : 0 : static void free_node(struct ice_tm_node *root)
60 : : {
61 : : uint32_t i;
62 : :
63 [ # # ]: 0 : if (root == NULL)
64 : : return;
65 : :
66 [ # # ]: 0 : for (i = 0; i < root->reference_count; i++)
67 : 0 : free_node(root->children[i]);
68 : :
69 : 0 : rte_free(root);
70 : : }
71 : :
72 : : void
73 : 0 : ice_tm_conf_uninit(struct rte_eth_dev *dev)
74 : : {
75 : 0 : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
76 : : struct ice_tm_shaper_profile *shaper_profile;
77 : :
78 : : /* clear profile */
79 [ # # ]: 0 : while ((shaper_profile = TAILQ_FIRST(&pf->tm_conf.shaper_profile_list))) {
80 [ # # ]: 0 : TAILQ_REMOVE(&pf->tm_conf.shaper_profile_list, shaper_profile, node);
81 : 0 : rte_free(shaper_profile);
82 : : }
83 : :
84 : 0 : free_node(pf->tm_conf.root);
85 : 0 : pf->tm_conf.root = NULL;
86 : 0 : }
87 : :
88 : : static int
89 : 0 : ice_node_param_check(uint32_t node_id,
90 : : uint32_t priority, uint32_t weight,
91 : : const struct rte_tm_node_params *params,
92 : : bool is_leaf,
93 : : uint16_t nb_txq,
94 : : struct rte_tm_error *error)
95 : : {
96 [ # # ]: 0 : uint32_t max_leaf_id = (nb_txq != 0) ? nb_txq : RTE_MAX_QUEUES_PER_PORT;
97 : :
98 : : /* checked all the unsupported parameter */
99 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
100 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
101 : 0 : error->message = "invalid node id";
102 : 0 : return -EINVAL;
103 : : }
104 : :
105 [ # # ]: 0 : if (priority >= 8) {
106 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PRIORITY;
107 : 0 : error->message = "priority should be less than 8";
108 : 0 : return -EINVAL;
109 : : }
110 : :
111 [ # # ]: 0 : if (weight > 200 || weight < 1) {
112 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_WEIGHT;
113 : 0 : error->message = "weight must be between 1 and 200";
114 : 0 : return -EINVAL;
115 : : }
116 : :
117 : : /* not support shared shaper */
118 [ # # ]: 0 : if (params->shared_shaper_id) {
119 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;
120 : 0 : error->message = "shared shaper not supported";
121 : 0 : return -EINVAL;
122 : : }
123 [ # # ]: 0 : if (params->n_shared_shapers) {
124 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;
125 : 0 : error->message = "shared shaper not supported";
126 : 0 : return -EINVAL;
127 : : }
128 : :
129 : : /* for non-leaf node */
130 [ # # ]: 0 : if (!is_leaf) {
131 [ # # ]: 0 : if (node_id < max_leaf_id) {
132 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
133 : 0 : error->message = "node ID is reserved for leaf nodes";
134 : 0 : return -EINVAL;
135 : : }
136 [ # # ]: 0 : if (params->nonleaf.wfq_weight_mode) {
137 : 0 : error->type =
138 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;
139 : 0 : error->message = "WFQ not supported";
140 : 0 : return -EINVAL;
141 : : }
142 [ # # ]: 0 : if (params->nonleaf.n_sp_priorities != 1) {
143 : 0 : error->type =
144 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;
145 : 0 : error->message = "SP priority not supported";
146 : 0 : return -EINVAL;
147 : : } else if (params->nonleaf.wfq_weight_mode &&
148 : : !(*params->nonleaf.wfq_weight_mode)) {
149 : : error->type =
150 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;
151 : : error->message = "WFP should be byte mode";
152 : : return -EINVAL;
153 : : }
154 : :
155 : : return 0;
156 : : }
157 : :
158 : : /* for leaf node */
159 [ # # ]: 0 : if (node_id >= max_leaf_id) {
160 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
161 : 0 : error->message = "Node ID out of range for a leaf node.";
162 : 0 : return -EINVAL;
163 : : }
164 [ # # ]: 0 : if (params->leaf.cman) {
165 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;
166 : 0 : error->message = "Congestion management not supported";
167 : 0 : return -EINVAL;
168 : : }
169 [ # # ]: 0 : if (params->leaf.wred.wred_profile_id !=
170 : : RTE_TM_WRED_PROFILE_ID_NONE) {
171 : 0 : error->type =
172 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;
173 : 0 : error->message = "WRED not supported";
174 : 0 : return -EINVAL;
175 : : }
176 [ # # ]: 0 : if (params->leaf.wred.shared_wred_context_id) {
177 : 0 : error->type =
178 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;
179 : 0 : error->message = "WRED not supported";
180 : 0 : return -EINVAL;
181 : : }
182 [ # # ]: 0 : if (params->leaf.wred.n_shared_wred_contexts) {
183 : 0 : error->type =
184 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;
185 : 0 : error->message = "WRED not supported";
186 : 0 : return -EINVAL;
187 : : }
188 : :
189 : : return 0;
190 : : }
191 : :
192 : : static struct ice_tm_node *
193 : 0 : find_node(struct ice_tm_node *root, uint32_t id)
194 : : {
195 : : uint32_t i;
196 : :
197 [ # # # # ]: 0 : if (root == NULL || root->id == id)
198 : : return root;
199 : :
200 [ # # ]: 0 : for (i = 0; i < root->reference_count; i++) {
201 : 0 : struct ice_tm_node *node = find_node(root->children[i], id);
202 : :
203 [ # # ]: 0 : if (node)
204 : 0 : return node;
205 : : }
206 : :
207 : : return NULL;
208 : : }
209 : :
210 : : static inline uint8_t
211 : : ice_get_leaf_level(const struct ice_pf *pf)
212 : : {
213 : 0 : const struct ice_hw *hw = ICE_PF_TO_HW(pf);
214 : 0 : return hw->num_tx_sched_layers - pf->tm_conf.hidden_layers - 1;
215 : : }
216 : :
217 : : static int
218 : 0 : ice_node_type_get(struct rte_eth_dev *dev, uint32_t node_id,
219 : : int *is_leaf, struct rte_tm_error *error)
220 : : {
221 : 0 : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
222 : : struct ice_tm_node *tm_node;
223 : :
224 [ # # ]: 0 : if (!is_leaf || !error)
225 : : return -EINVAL;
226 : :
227 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
228 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
229 : 0 : error->message = "invalid node id";
230 : 0 : return -EINVAL;
231 : : }
232 : :
233 : : /* check if the node id exists */
234 : 0 : tm_node = find_node(pf->tm_conf.root, node_id);
235 [ # # ]: 0 : if (!tm_node) {
236 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
237 : 0 : error->message = "no such node";
238 : 0 : return -EINVAL;
239 : : }
240 : :
241 [ # # ]: 0 : if (tm_node->level == ice_get_leaf_level(pf))
242 : 0 : *is_leaf = true;
243 : : else
244 : 0 : *is_leaf = false;
245 : :
246 : : return 0;
247 : : }
248 : :
249 : : static int
250 : 0 : ice_node_query(const struct rte_eth_dev *dev, uint32_t node_id,
251 : : uint32_t *parent_node_id, uint32_t *priority,
252 : : uint32_t *weight, uint32_t *level_id,
253 : : struct rte_tm_node_params *params,
254 : : struct rte_tm_error *error)
255 : : {
256 : 0 : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
257 : : struct ice_tm_node *tm_node;
258 : :
259 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
260 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
261 : 0 : error->message = "invalid node id";
262 : 0 : return -EINVAL;
263 : : }
264 : :
265 : : /* check if the node id exists */
266 : 0 : tm_node = find_node(pf->tm_conf.root, node_id);
267 [ # # ]: 0 : if (!tm_node) {
268 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
269 : 0 : error->message = "no such node";
270 : 0 : return -EEXIST;
271 : : }
272 : :
273 [ # # ]: 0 : if (parent_node_id != NULL) {
274 [ # # ]: 0 : if (tm_node->parent != NULL)
275 : 0 : *parent_node_id = tm_node->parent->id;
276 : : else
277 : 0 : *parent_node_id = RTE_TM_NODE_ID_NULL;
278 : : }
279 : :
280 [ # # ]: 0 : if (priority != NULL)
281 : 0 : *priority = tm_node->priority;
282 : :
283 [ # # ]: 0 : if (weight != NULL)
284 : 0 : *weight = tm_node->weight;
285 : :
286 [ # # ]: 0 : if (level_id != NULL)
287 : 0 : *level_id = tm_node->level;
288 : :
289 [ # # ]: 0 : if (params != NULL)
290 : 0 : *params = tm_node->params;
291 : :
292 : : return 0;
293 : : }
294 : :
295 : : static inline struct ice_tm_shaper_profile *
296 : : ice_shaper_profile_search(struct rte_eth_dev *dev,
297 : : uint32_t shaper_profile_id)
298 : : {
299 : : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
300 : : struct ice_shaper_profile_list *shaper_profile_list =
301 : : &pf->tm_conf.shaper_profile_list;
302 : : struct ice_tm_shaper_profile *shaper_profile;
303 : :
304 [ # # # # : 0 : TAILQ_FOREACH(shaper_profile, shaper_profile_list, node) {
# # ]
305 [ # # # # : 0 : if (shaper_profile_id == shaper_profile->shaper_profile_id)
# # ]
306 : : return shaper_profile;
307 : : }
308 : :
309 : : return NULL;
310 : : }
311 : :
312 : : static int
313 : : ice_shaper_profile_param_check(const struct rte_tm_shaper_params *profile,
314 : : struct rte_tm_error *error)
315 : : {
316 : : /* min bucket size not supported */
317 [ # # ]: 0 : if (profile->committed.size) {
318 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;
319 : 0 : error->message = "committed bucket size not supported";
320 : : return -EINVAL;
321 : : }
322 : : /* max bucket size not supported */
323 [ # # ]: 0 : if (profile->peak.size) {
324 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;
325 : 0 : error->message = "peak bucket size not supported";
326 : : return -EINVAL;
327 : : }
328 : : /* length adjustment not supported */
329 [ # # ]: 0 : if (profile->pkt_length_adjust) {
330 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;
331 : 0 : error->message = "packet length adjustment not supported";
332 : : return -EINVAL;
333 : : }
334 : :
335 : : return 0;
336 : : }
337 : :
338 : : static int
339 : 0 : ice_shaper_profile_add(struct rte_eth_dev *dev,
340 : : uint32_t shaper_profile_id,
341 : : const struct rte_tm_shaper_params *profile,
342 : : struct rte_tm_error *error)
343 : : {
344 : 0 : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
345 : : struct ice_tm_shaper_profile *shaper_profile;
346 : : int ret;
347 : :
348 [ # # ]: 0 : if (!profile || !error)
349 : : return -EINVAL;
350 : :
351 : : ret = ice_shaper_profile_param_check(profile, error);
352 : : if (ret)
353 : 0 : return ret;
354 : :
355 : : shaper_profile = ice_shaper_profile_search(dev, shaper_profile_id);
356 : :
357 [ # # ]: 0 : if (shaper_profile) {
358 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
359 : 0 : error->message = "profile ID exist";
360 : 0 : return -EINVAL;
361 : : }
362 : :
363 : 0 : shaper_profile = rte_zmalloc("ice_tm_shaper_profile",
364 : : sizeof(struct ice_tm_shaper_profile),
365 : : 0);
366 [ # # ]: 0 : if (!shaper_profile)
367 : : return -ENOMEM;
368 : 0 : shaper_profile->shaper_profile_id = shaper_profile_id;
369 : 0 : memcpy(&shaper_profile->profile, profile,
370 : : sizeof(struct rte_tm_shaper_params));
371 : 0 : TAILQ_INSERT_TAIL(&pf->tm_conf.shaper_profile_list,
372 : : shaper_profile, node);
373 : :
374 : 0 : return 0;
375 : : }
376 : :
377 : : static int
378 : 0 : ice_shaper_profile_del(struct rte_eth_dev *dev,
379 : : uint32_t shaper_profile_id,
380 : : struct rte_tm_error *error)
381 : : {
382 : 0 : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
383 : : struct ice_tm_shaper_profile *shaper_profile;
384 : :
385 [ # # ]: 0 : if (!error)
386 : : return -EINVAL;
387 : :
388 : : shaper_profile = ice_shaper_profile_search(dev, shaper_profile_id);
389 : :
390 [ # # ]: 0 : if (!shaper_profile) {
391 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
392 : 0 : error->message = "profile ID not exist";
393 : 0 : return -EINVAL;
394 : : }
395 : :
396 : : /* don't delete a profile if it's used by one or several nodes */
397 [ # # ]: 0 : if (shaper_profile->reference_count) {
398 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
399 : 0 : error->message = "profile in use";
400 : 0 : return -EINVAL;
401 : : }
402 : :
403 [ # # ]: 0 : TAILQ_REMOVE(&pf->tm_conf.shaper_profile_list, shaper_profile, node);
404 : 0 : rte_free(shaper_profile);
405 : :
406 : 0 : return 0;
407 : : }
408 : :
409 : : static int
410 : 0 : ice_tm_node_add(struct rte_eth_dev *dev, uint32_t node_id,
411 : : uint32_t parent_node_id, uint32_t priority,
412 : : uint32_t weight, uint32_t level_id,
413 : : const struct rte_tm_node_params *params,
414 : : struct rte_tm_error *error)
415 : : {
416 : 0 : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
417 : : struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
418 : : struct ice_tm_shaper_profile *shaper_profile = NULL;
419 : : struct ice_tm_node *tm_node;
420 : : struct ice_tm_node *parent_node = NULL;
421 : 0 : uint8_t layer_offset = pf->tm_conf.hidden_layers;
422 : : int ret;
423 : :
424 [ # # ]: 0 : if (!params || !error)
425 : : return -EINVAL;
426 : :
427 : : /* check the shaper profile id */
428 [ # # ]: 0 : if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE) {
429 : : shaper_profile = ice_shaper_profile_search(dev, params->shaper_profile_id);
430 [ # # ]: 0 : if (!shaper_profile) {
431 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;
432 : 0 : error->message = "shaper profile does not exist";
433 : 0 : return -EINVAL;
434 : : }
435 : : }
436 : :
437 : : /* root node if not have a parent */
438 [ # # ]: 0 : if (parent_node_id == RTE_TM_NODE_ID_NULL) {
439 : : /* check level */
440 [ # # ]: 0 : if (level_id != 0) {
441 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
442 : 0 : error->message = "Wrong level, root node (NULL parent) must be at level 0";
443 : 0 : return -EINVAL;
444 : : }
445 : :
446 : : /* obviously no more than one root */
447 [ # # ]: 0 : if (pf->tm_conf.root) {
448 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
449 : 0 : error->message = "already have a root";
450 : 0 : return -EINVAL;
451 : : }
452 : :
453 : 0 : ret = ice_node_param_check(node_id, priority, weight, params, false,
454 : 0 : dev->data->nb_tx_queues, error);
455 [ # # ]: 0 : if (ret)
456 : : return ret;
457 : :
458 : : /* add the root node */
459 : 0 : tm_node = rte_zmalloc(NULL,
460 : 0 : sizeof(struct ice_tm_node) +
461 : 0 : sizeof(struct ice_tm_node *) * hw->max_children[layer_offset],
462 : : 0);
463 [ # # ]: 0 : if (!tm_node)
464 : : return -ENOMEM;
465 : 0 : tm_node->id = node_id;
466 : 0 : tm_node->level = 0;
467 : 0 : tm_node->parent = NULL;
468 : 0 : tm_node->reference_count = 0;
469 : 0 : tm_node->shaper_profile = shaper_profile;
470 [ # # ]: 0 : if (shaper_profile != NULL)
471 : 0 : shaper_profile->reference_count++;
472 : 0 : tm_node->children = RTE_PTR_ADD(tm_node, sizeof(struct ice_tm_node));
473 : 0 : tm_node->params = *params;
474 : 0 : pf->tm_conf.root = tm_node;
475 : 0 : return 0;
476 : : }
477 : :
478 : 0 : parent_node = find_node(pf->tm_conf.root, parent_node_id);
479 [ # # ]: 0 : if (!parent_node) {
480 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
481 : 0 : error->message = "parent not exist";
482 : 0 : return -EINVAL;
483 : : }
484 : :
485 : : /* check level */
486 [ # # ]: 0 : if (level_id == RTE_TM_NODE_LEVEL_ID_ANY)
487 : 0 : level_id = parent_node->level + 1;
488 [ # # ]: 0 : else if (level_id != parent_node->level + 1) {
489 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
490 : 0 : error->message = "Wrong level";
491 : 0 : return -EINVAL;
492 : : }
493 : :
494 : 0 : ret = ice_node_param_check(node_id, priority, weight,
495 : 0 : params, level_id == ice_get_leaf_level(pf),
496 : 0 : dev->data->nb_tx_queues, error);
497 [ # # ]: 0 : if (ret)
498 : : return ret;
499 : :
500 : : /* check if the node is already existed */
501 [ # # ]: 0 : if (find_node(pf->tm_conf.root, node_id)) {
502 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
503 : 0 : error->message = "node id already used";
504 : 0 : return -EINVAL;
505 : : }
506 : :
507 : : /* check the parent node */
508 : : /* for n-level hierarchy, level n-1 is leaf, so last level with children is n-2 */
509 [ # # ]: 0 : if ((int)parent_node->level > hw->num_tx_sched_layers - 2) {
510 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
511 : 0 : error->message = "parent is not valid";
512 : 0 : return -EINVAL;
513 : : }
514 : :
515 : : /* check the max children allowed at this level */
516 [ # # ]: 0 : if (parent_node->reference_count >= hw->max_children[parent_node->level]) {
517 : 0 : error->type = RTE_TM_ERROR_TYPE_CAPABILITIES;
518 : 0 : error->message = "insufficient number of child nodes supported";
519 : 0 : return -EINVAL;
520 : : }
521 : :
522 : 0 : tm_node = rte_zmalloc(NULL,
523 : 0 : sizeof(struct ice_tm_node) +
524 : 0 : sizeof(struct ice_tm_node *) * hw->max_children[level_id + layer_offset],
525 : : 0);
526 [ # # ]: 0 : if (!tm_node)
527 : : return -ENOMEM;
528 : 0 : tm_node->id = node_id;
529 : 0 : tm_node->priority = priority;
530 : 0 : tm_node->weight = weight;
531 : 0 : tm_node->reference_count = 0;
532 : 0 : tm_node->parent = parent_node;
533 : 0 : tm_node->level = level_id;
534 : 0 : tm_node->shaper_profile = shaper_profile;
535 [ # # ]: 0 : if (shaper_profile != NULL)
536 : 0 : shaper_profile->reference_count++;
537 : 0 : tm_node->children = RTE_PTR_ADD(tm_node, sizeof(struct ice_tm_node));
538 : 0 : tm_node->parent->children[tm_node->parent->reference_count++] = tm_node;
539 : 0 : tm_node->params = *params;
540 : :
541 : : /* Priority cannot be configured for the root level */
542 [ # # # # ]: 0 : if (tm_node->priority != 0 && level_id == 0)
543 : 0 : PMD_DRV_LOG(WARNING, "priority != 0 not supported in level %d", level_id);
544 : :
545 [ # # # # ]: 0 : if (tm_node->weight != 1 && level_id == 0)
546 : 0 : PMD_DRV_LOG(WARNING, "weight != 1 not supported in level %d", level_id);
547 : :
548 : :
549 : : return 0;
550 : : }
551 : :
552 : : static int
553 : 0 : ice_tm_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
554 : : struct rte_tm_error *error)
555 : : {
556 : 0 : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
557 : : struct ice_tm_node *tm_node;
558 : : uint32_t i, j;
559 : :
560 [ # # ]: 0 : if (!error)
561 : : return -EINVAL;
562 : :
563 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
564 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
565 : 0 : error->message = "invalid node id";
566 : 0 : return -EINVAL;
567 : : }
568 : :
569 : : /* check if the node id exists */
570 : 0 : tm_node = find_node(pf->tm_conf.root, node_id);
571 [ # # ]: 0 : if (!tm_node) {
572 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
573 : 0 : error->message = "no such node";
574 : 0 : return -EINVAL;
575 : : }
576 : :
577 : : /* the node should have no child */
578 [ # # ]: 0 : if (tm_node->reference_count) {
579 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
580 : 0 : error->message =
581 : : "cannot delete a node which has children";
582 : 0 : return -EINVAL;
583 : : }
584 : :
585 : : /* root node */
586 [ # # ]: 0 : if (tm_node->level == 0) {
587 [ # # ]: 0 : if (tm_node->shaper_profile != NULL)
588 : 0 : tm_node->shaper_profile->reference_count--;
589 : 0 : rte_free(tm_node);
590 : 0 : pf->tm_conf.root = NULL;
591 : 0 : return 0;
592 : : }
593 : :
594 : : /* queue group or queue node */
595 [ # # ]: 0 : for (i = 0; i < tm_node->parent->reference_count; i++)
596 [ # # ]: 0 : if (tm_node->parent->children[i] == tm_node)
597 : : break;
598 : :
599 [ # # ]: 0 : for (j = i ; j < tm_node->parent->reference_count - 1; j++)
600 : 0 : tm_node->parent->children[j] = tm_node->parent->children[j + 1];
601 : :
602 : 0 : tm_node->parent->reference_count--;
603 [ # # ]: 0 : if (tm_node->shaper_profile != NULL)
604 : 0 : tm_node->shaper_profile->reference_count--;
605 : 0 : rte_free(tm_node);
606 : :
607 : 0 : return 0;
608 : : }
609 : :
610 : 0 : static int ice_set_node_rate(struct ice_hw *hw,
611 : : struct ice_tm_node *tm_node,
612 : : struct ice_sched_node *sched_node)
613 : : {
614 : : bool reset = false;
615 : : uint32_t peak = 0;
616 : : uint32_t committed = 0;
617 : : uint32_t rate;
618 : : int status;
619 : :
620 [ # # # # ]: 0 : if (tm_node == NULL || tm_node->shaper_profile == NULL) {
621 : : reset = true;
622 : : } else {
623 : 0 : peak = (uint32_t)tm_node->shaper_profile->profile.peak.rate;
624 : 0 : committed = (uint32_t)tm_node->shaper_profile->profile.committed.rate;
625 : : }
626 : :
627 [ # # ]: 0 : if (reset || peak == 0)
628 : : rate = ICE_SCHED_DFLT_BW;
629 : : else
630 : 0 : rate = peak / 1000 * BITS_PER_BYTE;
631 : :
632 : :
633 : 0 : status = ice_sched_set_node_bw_lmt(hw->port_info,
634 : : sched_node,
635 : : ICE_MAX_BW,
636 : : rate);
637 [ # # ]: 0 : if (status)
638 : : return -EINVAL;
639 : :
640 [ # # ]: 0 : if (reset || committed == 0)
641 : : rate = ICE_SCHED_DFLT_BW;
642 : : else
643 : 0 : rate = committed / 1000 * BITS_PER_BYTE;
644 : :
645 : 0 : status = ice_sched_set_node_bw_lmt(hw->port_info,
646 : : sched_node,
647 : : ICE_MIN_BW,
648 : : rate);
649 [ # # ]: 0 : if (status)
650 : 0 : return -EINVAL;
651 : :
652 : : return 0;
653 : : }
654 : :
655 : 0 : static int ice_cfg_hw_node(struct ice_hw *hw,
656 : : struct ice_tm_node *tm_node,
657 : : struct ice_sched_node *sched_node)
658 : : {
659 : : uint8_t priority;
660 : : uint16_t weight;
661 : : int status, ret;
662 : :
663 : 0 : ret = ice_set_node_rate(hw, tm_node, sched_node);
664 [ # # ]: 0 : if (ret) {
665 : 0 : PMD_DRV_LOG(ERR,
666 : : "configure queue group %u bandwidth failed",
667 : : sched_node->info.node_teid);
668 : 0 : return ret;
669 : : }
670 : :
671 [ # # ]: 0 : priority = tm_node ? (7 - tm_node->priority) : 0;
672 : 0 : status = ice_sched_cfg_sibl_node_prio(hw->port_info,
673 : : sched_node,
674 : : priority);
675 [ # # ]: 0 : if (status) {
676 : 0 : PMD_DRV_LOG(ERR, "configure node %u priority %u failed",
677 : : sched_node->info.node_teid,
678 : : priority);
679 : 0 : return -EINVAL;
680 : : }
681 : :
682 [ # # ]: 0 : weight = tm_node ? (uint16_t)tm_node->weight : 4;
683 : :
684 : 0 : status = ice_sched_cfg_node_bw_alloc(hw, sched_node,
685 : : ICE_MAX_BW,
686 : : weight);
687 [ # # ]: 0 : if (status) {
688 : 0 : PMD_DRV_LOG(ERR, "configure node %u weight %u failed",
689 : : sched_node->info.node_teid,
690 : : weight);
691 : 0 : return -EINVAL;
692 : : }
693 : :
694 : : return 0;
695 : : }
696 : :
697 : : int
698 : 0 : ice_tm_setup_txq_node(struct ice_pf *pf, struct ice_hw *hw, uint16_t qid, uint32_t teid)
699 : : {
700 : 0 : struct ice_sched_node *hw_node = ice_sched_find_node_by_teid(hw->port_info->root, teid);
701 : 0 : struct ice_tm_node *sw_node = find_node(pf->tm_conf.root, qid);
702 : :
703 : : /* bad node teid passed */
704 [ # # ]: 0 : if (hw_node == NULL)
705 : : return -ENOENT;
706 : :
707 : : /* not configured in hierarchy */
708 [ # # ]: 0 : if (sw_node == NULL)
709 : : return 0;
710 : :
711 : 0 : sw_node->sched_node = hw_node;
712 : :
713 : : /* if the queue node has been put in the wrong place in hierarchy */
714 [ # # ]: 0 : if (hw_node->parent != sw_node->parent->sched_node) {
715 : : struct ice_aqc_move_txqs_data *buf;
716 : 0 : uint8_t txqs_moved = 0;
717 : : uint16_t buf_size = ice_struct_size(buf, txqs, 1);
718 : :
719 : 0 : buf = calloc(1, buf_size);
720 [ # # ]: 0 : if (buf == NULL)
721 : 0 : return -ENOMEM;
722 : :
723 : 0 : struct ice_sched_node *parent = hw_node->parent;
724 : : struct ice_sched_node *new_parent = sw_node->parent->sched_node;
725 : 0 : buf->src_teid = parent->info.node_teid;
726 : 0 : buf->dest_teid = new_parent->info.node_teid;
727 : 0 : buf->txqs[0].q_teid = hw_node->info.node_teid;
728 : 0 : buf->txqs[0].txq_id = qid;
729 : :
730 : 0 : int ret = ice_aq_move_recfg_lan_txq(hw, 1, true, false, false, false, 50,
731 : : NULL, buf, buf_size, &txqs_moved, NULL);
732 : 0 : free(buf);
733 [ # # # # ]: 0 : if (ret || txqs_moved == 0) {
734 : 0 : PMD_DRV_LOG(ERR, "move lan queue %u failed", qid);
735 : 0 : return ICE_ERR_PARAM;
736 : : }
737 : :
738 : : /* now update the ice_sched_nodes to match physical layout */
739 : 0 : new_parent->children[new_parent->num_children++] = hw_node;
740 : 0 : hw_node->parent = new_parent;
741 : 0 : ice_sched_query_elem(hw, hw_node->info.node_teid, &hw_node->info);
742 [ # # ]: 0 : for (uint16_t i = 0; i < parent->num_children; i++)
743 [ # # ]: 0 : if (parent->children[i] == hw_node) {
744 : : /* to remove, just overwrite the old node slot with the last ptr */
745 : 0 : parent->children[i] = parent->children[--parent->num_children];
746 : 0 : break;
747 : : }
748 : : }
749 : :
750 : 0 : return ice_cfg_hw_node(hw, sw_node, hw_node);
751 : : }
752 : :
753 : : /* from a given node, recursively deletes all the nodes that belong to that vsi.
754 : : * Any nodes which can't be deleted because they have children belonging to a different
755 : : * VSI, are now also adjusted to belong to that VSI also
756 : : */
757 : : static int
758 : 0 : free_sched_node_recursive(struct ice_port_info *pi, const struct ice_sched_node *root,
759 : : struct ice_sched_node *node, uint8_t vsi_id)
760 : : {
761 : : uint16_t i = 0;
762 : :
763 [ # # ]: 0 : while (i < node->num_children) {
764 [ # # ]: 0 : if (node->children[i]->vsi_handle != vsi_id) {
765 : 0 : i++;
766 : 0 : continue;
767 : : }
768 : 0 : free_sched_node_recursive(pi, root, node->children[i], vsi_id);
769 : : }
770 : :
771 [ # # ]: 0 : if (node != root) {
772 [ # # ]: 0 : if (node->num_children == 0)
773 : 0 : ice_free_sched_node(pi, node);
774 : : else
775 : 0 : node->vsi_handle = node->children[0]->vsi_handle;
776 : : }
777 : :
778 : 0 : return 0;
779 : : }
780 : :
781 : : static int
782 : 0 : create_sched_node_recursive(struct ice_pf *pf, struct ice_port_info *pi,
783 : : struct ice_tm_node *sw_node, struct ice_sched_node *hw_root, uint16_t *created)
784 : : {
785 : 0 : struct ice_sched_node *parent = sw_node->sched_node;
786 : : uint32_t teid;
787 : : uint16_t added;
788 : :
789 : : /* first create all child nodes */
790 [ # # ]: 0 : for (uint16_t i = 0; i < sw_node->reference_count; i++) {
791 : 0 : struct ice_tm_node *tm_node = sw_node->children[i];
792 : 0 : int res = ice_sched_add_elems(pi, hw_root,
793 : 0 : parent, parent->tx_sched_layer + 1,
794 : : 1 /* num nodes */, &added, &teid,
795 : : NULL /* no pre-alloc */);
796 [ # # ]: 0 : if (res != 0) {
797 : 0 : PMD_DRV_LOG(ERR, "Error with ice_sched_add_elems, adding child node to teid %u",
798 : : parent->info.node_teid);
799 : 0 : return -1;
800 : : }
801 : 0 : struct ice_sched_node *hw_node = ice_sched_find_node_by_teid(parent, teid);
802 [ # # ]: 0 : if (ice_cfg_hw_node(pi->hw, tm_node, hw_node) != 0) {
803 : 0 : PMD_DRV_LOG(ERR, "Error configuring node %u at layer %u",
804 : : teid, parent->tx_sched_layer + 1);
805 : 0 : return -1;
806 : : }
807 : 0 : tm_node->sched_node = hw_node;
808 : 0 : created[hw_node->tx_sched_layer]++;
809 : : }
810 : :
811 : : /* if we have just created the child nodes in the q-group, i.e. last non-leaf layer,
812 : : * then just return, rather than trying to create leaf nodes.
813 : : * That is done later at queue start.
814 : : */
815 [ # # ]: 0 : if (sw_node->level + 2 == ice_get_leaf_level(pf))
816 : : return 0;
817 : :
818 [ # # ]: 0 : for (uint16_t i = 0; i < sw_node->reference_count; i++) {
819 [ # # ]: 0 : if (sw_node->children[i]->reference_count == 0)
820 : 0 : continue;
821 : :
822 [ # # ]: 0 : if (create_sched_node_recursive(pf, pi, sw_node->children[i], hw_root, created) < 0)
823 : : return -1;
824 : : }
825 : : return 0;
826 : : }
827 : :
828 : : static void
829 : 0 : reset_hw_node_recursive(struct ice_hw *hw, struct ice_sched_node *node)
830 : : {
831 : : uint16_t i;
832 : :
833 [ # # ]: 0 : for (i = 0; i < node->num_children; i++) {
834 : 0 : reset_hw_node_recursive(hw, node->children[i]);
835 [ # # ]: 0 : if (ice_cfg_hw_node(hw, NULL, node->children[i]))
836 : 0 : PMD_DRV_LOG(WARNING, "Failed to reset node %u to default configuration",
837 : : node->children[i]->info.node_teid);
838 : : }
839 : 0 : }
840 : :
841 : : static int
842 : 0 : commit_new_hierarchy(struct rte_eth_dev *dev)
843 : : {
844 : 0 : struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
845 : 0 : struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private);
846 : 0 : struct ice_port_info *pi = hw->port_info;
847 : 0 : struct ice_tm_node *sw_root = pf->tm_conf.root;
848 : 0 : const uint16_t new_root_level = pf->tm_conf.hidden_layers;
849 : : /* count nodes per hw level, not per logical */
850 : 0 : uint16_t nodes_created_per_level[ICE_TM_MAX_LAYERS] = {0};
851 : : uint8_t q_lvl = ice_get_leaf_level(pf);
852 : 0 : uint8_t qg_lvl = q_lvl - 1;
853 : 0 : struct ice_sched_node *new_vsi_root = hw->vsi_ctx[pf->main_vsi->idx]->sched.vsi_node[0];
854 : :
855 [ # # ]: 0 : if (sw_root == NULL) {
856 [ # # ]: 0 : if (!pf->tm_conf.committed) {
857 : 0 : PMD_DRV_LOG(ERR, "No root node defined in TM hierarchy");
858 : 0 : return -EINVAL;
859 : : }
860 : : /* TM hierarchy deleted. Restore default scheduler state. */
861 : 0 : reset_hw_node_recursive(hw, hw->vsi_ctx[pf->main_vsi->idx]->sched.vsi_node[0]);
862 : 0 : pf->main_vsi->nb_qps = pf->lan_nb_qps;
863 : 0 : pf->tm_conf.committed = false;
864 : 0 : return ice_alloc_lan_q_ctx(hw, 0, 0, pf->main_vsi->nb_qps);
865 : : }
866 : :
867 : : /* handle case where VSI node needs to move DOWN the hierarchy */
868 [ # # ]: 0 : while (new_vsi_root->tx_sched_layer < new_root_level) {
869 [ # # ]: 0 : if (new_vsi_root->num_children == 0)
870 : : return -1;
871 : : /* remove all child nodes but the first */
872 [ # # ]: 0 : while (new_vsi_root->num_children > 1)
873 : 0 : free_sched_node_recursive(pi, new_vsi_root,
874 : 0 : new_vsi_root->children[1],
875 : 0 : new_vsi_root->vsi_handle);
876 : 0 : new_vsi_root = new_vsi_root->children[0];
877 : : }
878 : : /* handle case where VSI node needs to move UP the hierarchy */
879 [ # # ]: 0 : while (new_vsi_root->tx_sched_layer > new_root_level)
880 : 0 : new_vsi_root = new_vsi_root->parent;
881 : :
882 : 0 : free_sched_node_recursive(pi, new_vsi_root, new_vsi_root, new_vsi_root->vsi_handle);
883 : :
884 : 0 : sw_root->sched_node = new_vsi_root;
885 [ # # ]: 0 : if (create_sched_node_recursive(pf, pi, sw_root, new_vsi_root, nodes_created_per_level) < 0)
886 : : return -1;
887 [ # # ]: 0 : for (uint16_t i = 0; i < RTE_DIM(nodes_created_per_level); i++)
888 : 0 : PMD_DRV_LOG(DEBUG, "Created %u nodes at level %u",
889 : : nodes_created_per_level[i], i);
890 : 0 : hw->vsi_ctx[pf->main_vsi->idx]->sched.vsi_node[0] = new_vsi_root;
891 : :
892 : 0 : pf->main_vsi->nb_qps =
893 : 0 : RTE_MIN(nodes_created_per_level[qg_lvl] * hw->max_children[qg_lvl],
894 : : hw->layer_info[q_lvl].max_device_nodes);
895 : :
896 : 0 : pf->tm_conf.committed = true; /* set flag to be checks on queue start */
897 : :
898 : 0 : return ice_alloc_lan_q_ctx(hw, 0, 0, pf->main_vsi->nb_qps);
899 : : }
900 : :
901 : : static int
902 : 0 : ice_hierarchy_commit(struct rte_eth_dev *dev,
903 : : int clear_on_fail,
904 : : struct rte_tm_error *error)
905 : : {
906 : : bool restart = false;
907 : :
908 : : /* commit should only be done to topology before start
909 : : * If port is already started, stop it and then restart when done.
910 : : */
911 [ # # ]: 0 : if (dev->data->dev_started) {
912 [ # # ]: 0 : if (rte_eth_dev_stop(dev->data->port_id) != 0) {
913 : 0 : error->message = "Device failed to Stop";
914 : 0 : return -1;
915 : : }
916 : : restart = true;
917 : : }
918 : :
919 : 0 : int ret = commit_new_hierarchy(dev);
920 [ # # ]: 0 : if (ret < 0 && clear_on_fail) {
921 : 0 : ice_tm_conf_uninit(dev);
922 : 0 : ice_tm_conf_init(dev);
923 : : }
924 : :
925 [ # # ]: 0 : if (restart) {
926 [ # # ]: 0 : if (rte_eth_dev_start(dev->data->port_id) != 0) {
927 : 0 : error->message = "Device failed to Start";
928 : 0 : return -1;
929 : : }
930 : : }
931 : : return ret;
932 : : }
|