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