Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2015-2020 Beijing WangXun Technology Co., Ltd.
3 : : * Copyright(c) 2010-2017 Intel Corporation
4 : : */
5 : :
6 : : #include <rte_malloc.h>
7 : :
8 : : #include "txgbe_ethdev.h"
9 : :
10 : : static int txgbe_tm_capabilities_get(struct rte_eth_dev *dev,
11 : : struct rte_tm_capabilities *cap,
12 : : struct rte_tm_error *error);
13 : : static int txgbe_shaper_profile_add(struct rte_eth_dev *dev,
14 : : uint32_t shaper_profile_id,
15 : : const struct rte_tm_shaper_params *profile,
16 : : struct rte_tm_error *error);
17 : : static int txgbe_shaper_profile_del(struct rte_eth_dev *dev,
18 : : uint32_t shaper_profile_id,
19 : : struct rte_tm_error *error);
20 : : static int txgbe_node_add(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 : : const struct rte_tm_node_params *params,
24 : : struct rte_tm_error *error);
25 : : static int txgbe_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
26 : : struct rte_tm_error *error);
27 : : static int txgbe_node_type_get(struct rte_eth_dev *dev, uint32_t node_id,
28 : : int *is_leaf, struct rte_tm_error *error);
29 : : static int txgbe_level_capabilities_get(struct rte_eth_dev *dev,
30 : : uint32_t level_id,
31 : : struct rte_tm_level_capabilities *cap,
32 : : struct rte_tm_error *error);
33 : : static int txgbe_node_capabilities_get(struct rte_eth_dev *dev,
34 : : uint32_t node_id,
35 : : struct rte_tm_node_capabilities *cap,
36 : : struct rte_tm_error *error);
37 : : static int txgbe_hierarchy_commit(struct rte_eth_dev *dev,
38 : : int clear_on_fail,
39 : : struct rte_tm_error *error);
40 : :
41 : : const struct rte_tm_ops txgbe_tm_ops = {
42 : : .capabilities_get = txgbe_tm_capabilities_get,
43 : : .shaper_profile_add = txgbe_shaper_profile_add,
44 : : .shaper_profile_delete = txgbe_shaper_profile_del,
45 : : .node_add = txgbe_node_add,
46 : : .node_delete = txgbe_node_delete,
47 : : .node_type_get = txgbe_node_type_get,
48 : : .level_capabilities_get = txgbe_level_capabilities_get,
49 : : .node_capabilities_get = txgbe_node_capabilities_get,
50 : : .hierarchy_commit = txgbe_hierarchy_commit,
51 : : };
52 : :
53 : : int
54 : 0 : txgbe_tm_ops_get(struct rte_eth_dev *dev __rte_unused,
55 : : void *arg)
56 : : {
57 [ # # ]: 0 : if (!arg)
58 : : return -EINVAL;
59 : :
60 : 0 : *(const void **)arg = &txgbe_tm_ops;
61 : :
62 : 0 : return 0;
63 : : }
64 : :
65 : : void
66 : 0 : txgbe_tm_conf_init(struct rte_eth_dev *dev)
67 : : {
68 : 0 : struct txgbe_tm_conf *tm_conf = TXGBE_DEV_TM_CONF(dev);
69 : :
70 : : /* initialize shaper profile list */
71 : 0 : TAILQ_INIT(&tm_conf->shaper_profile_list);
72 : :
73 : : /* initialize node configuration */
74 : 0 : tm_conf->root = NULL;
75 : 0 : TAILQ_INIT(&tm_conf->queue_list);
76 : 0 : TAILQ_INIT(&tm_conf->tc_list);
77 : 0 : tm_conf->nb_tc_node = 0;
78 : 0 : tm_conf->nb_queue_node = 0;
79 : 0 : tm_conf->committed = false;
80 : 0 : }
81 : :
82 : : void
83 : 0 : txgbe_tm_conf_uninit(struct rte_eth_dev *dev)
84 : : {
85 : 0 : struct txgbe_tm_conf *tm_conf = TXGBE_DEV_TM_CONF(dev);
86 : : struct txgbe_tm_shaper_profile *shaper_profile;
87 : : struct txgbe_tm_node *tm_node;
88 : :
89 : : /* clear node configuration */
90 [ # # ]: 0 : while ((tm_node = TAILQ_FIRST(&tm_conf->queue_list))) {
91 [ # # ]: 0 : TAILQ_REMOVE(&tm_conf->queue_list, tm_node, node);
92 : 0 : rte_free(tm_node);
93 : : }
94 : 0 : tm_conf->nb_queue_node = 0;
95 [ # # ]: 0 : while ((tm_node = TAILQ_FIRST(&tm_conf->tc_list))) {
96 [ # # ]: 0 : TAILQ_REMOVE(&tm_conf->tc_list, tm_node, node);
97 : 0 : rte_free(tm_node);
98 : : }
99 : 0 : tm_conf->nb_tc_node = 0;
100 [ # # ]: 0 : if (tm_conf->root) {
101 : 0 : rte_free(tm_conf->root);
102 : 0 : tm_conf->root = NULL;
103 : : }
104 : :
105 : : /* Remove all shaper profiles */
106 [ # # ]: 0 : while ((shaper_profile =
107 : : TAILQ_FIRST(&tm_conf->shaper_profile_list))) {
108 [ # # ]: 0 : TAILQ_REMOVE(&tm_conf->shaper_profile_list,
109 : : shaper_profile, node);
110 : 0 : rte_free(shaper_profile);
111 : : }
112 : 0 : }
113 : :
114 : : static inline uint8_t
115 : : txgbe_tc_nb_get(struct rte_eth_dev *dev)
116 : : {
117 : : struct rte_eth_conf *eth_conf;
118 : : uint8_t nb_tcs = 0;
119 : :
120 : 0 : eth_conf = &dev->data->dev_conf;
121 [ # # ]: 0 : if (eth_conf->txmode.mq_mode == RTE_ETH_MQ_TX_DCB) {
122 : 0 : nb_tcs = eth_conf->tx_adv_conf.dcb_tx_conf.nb_tcs;
123 [ # # # # : 0 : } else if (eth_conf->txmode.mq_mode == RTE_ETH_MQ_TX_VMDQ_DCB) {
# # ]
124 [ # # # # : 0 : if (eth_conf->tx_adv_conf.vmdq_dcb_tx_conf.nb_queue_pools ==
# # ]
125 : : RTE_ETH_32_POOLS)
126 : : nb_tcs = RTE_ETH_4_TCS;
127 : : else
128 : : nb_tcs = RTE_ETH_8_TCS;
129 : : } else {
130 : : nb_tcs = 1;
131 : : }
132 : :
133 : : return nb_tcs;
134 : : }
135 : :
136 : : static int
137 : 0 : txgbe_tm_capabilities_get(struct rte_eth_dev *dev,
138 : : struct rte_tm_capabilities *cap,
139 : : struct rte_tm_error *error)
140 : : {
141 [ # # ]: 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
142 : : uint8_t tc_nb = txgbe_tc_nb_get(dev);
143 : :
144 [ # # ]: 0 : if (!cap || !error)
145 : : return -EINVAL;
146 : :
147 [ # # ]: 0 : if (tc_nb > hw->mac.max_tx_queues)
148 : : return -EINVAL;
149 : :
150 : 0 : error->type = RTE_TM_ERROR_TYPE_NONE;
151 : :
152 : : /* set all the parameters to 0 first. */
153 : : memset(cap, 0, sizeof(struct rte_tm_capabilities));
154 : :
155 : : /**
156 : : * here is the max capability not the current configuration.
157 : : */
158 : : /* port + TCs + queues */
159 : 0 : cap->n_nodes_max = 1 + TXGBE_DCB_TC_MAX +
160 : 0 : hw->mac.max_tx_queues;
161 : 0 : cap->n_levels_max = 3;
162 : 0 : cap->non_leaf_nodes_identical = 1;
163 : 0 : cap->leaf_nodes_identical = 1;
164 : 0 : cap->shaper_n_max = cap->n_nodes_max;
165 : 0 : cap->shaper_private_n_max = cap->n_nodes_max;
166 : : cap->shaper_private_dual_rate_n_max = 0;
167 : : cap->shaper_private_rate_min = 0;
168 : : /* 10Gbps -> 1.25GBps */
169 : 0 : cap->shaper_private_rate_max = 1250000000ull;
170 : : cap->shaper_shared_n_max = 0;
171 : : cap->shaper_shared_n_nodes_per_shaper_max = 0;
172 : : cap->shaper_shared_n_shapers_per_node_max = 0;
173 : : cap->shaper_shared_dual_rate_n_max = 0;
174 : : cap->shaper_shared_rate_min = 0;
175 : : cap->shaper_shared_rate_max = 0;
176 : 0 : cap->sched_n_children_max = hw->mac.max_tx_queues;
177 : : /**
178 : : * HW supports SP. But no plan to support it now.
179 : : * So, all the nodes should have the same priority.
180 : : */
181 : 0 : cap->sched_sp_n_priorities_max = 1;
182 : : cap->sched_wfq_n_children_per_group_max = 0;
183 : : cap->sched_wfq_n_groups_max = 0;
184 : : /**
185 : : * SW only supports fair round robin now.
186 : : * So, all the nodes should have the same weight.
187 : : */
188 : 0 : cap->sched_wfq_weight_max = 1;
189 : : cap->cman_head_drop_supported = 0;
190 : : cap->dynamic_update_mask = 0;
191 : 0 : cap->shaper_pkt_length_adjust_min = RTE_TM_ETH_FRAMING_OVERHEAD;
192 : 0 : cap->shaper_pkt_length_adjust_max = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
193 : : cap->cman_wred_context_n_max = 0;
194 : : cap->cman_wred_context_private_n_max = 0;
195 : : cap->cman_wred_context_shared_n_max = 0;
196 : : cap->cman_wred_context_shared_n_nodes_per_context_max = 0;
197 : : cap->cman_wred_context_shared_n_contexts_per_node_max = 0;
198 : : cap->stats_mask = 0;
199 : :
200 : 0 : return 0;
201 : : }
202 : :
203 : : static inline struct txgbe_tm_shaper_profile *
204 : : txgbe_shaper_profile_search(struct rte_eth_dev *dev,
205 : : uint32_t shaper_profile_id)
206 : : {
207 : : struct txgbe_tm_conf *tm_conf = TXGBE_DEV_TM_CONF(dev);
208 : : struct txgbe_shaper_profile_list *shaper_profile_list =
209 : : &tm_conf->shaper_profile_list;
210 : : struct txgbe_tm_shaper_profile *shaper_profile;
211 : :
212 [ # # # # : 0 : TAILQ_FOREACH(shaper_profile, shaper_profile_list, node) {
# # ]
213 [ # # # # : 0 : if (shaper_profile_id == shaper_profile->shaper_profile_id)
# # ]
214 : : return shaper_profile;
215 : : }
216 : :
217 : : return NULL;
218 : : }
219 : :
220 : : static int
221 : : txgbe_shaper_profile_param_check(const struct rte_tm_shaper_params *profile,
222 : : struct rte_tm_error *error)
223 : : {
224 : : /* min rate not supported */
225 [ # # ]: 0 : if (profile->committed.rate) {
226 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE;
227 : 0 : error->message = "committed rate not supported";
228 : : return -EINVAL;
229 : : }
230 : : /* min bucket size not supported */
231 [ # # ]: 0 : if (profile->committed.size) {
232 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;
233 : 0 : error->message = "committed bucket size not supported";
234 : : return -EINVAL;
235 : : }
236 : : /* max bucket size not supported */
237 [ # # ]: 0 : if (profile->peak.size) {
238 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;
239 : 0 : error->message = "peak bucket size not supported";
240 : : return -EINVAL;
241 : : }
242 : : /* length adjustment not supported */
243 [ # # ]: 0 : if (profile->pkt_length_adjust) {
244 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;
245 : 0 : error->message = "packet length adjustment not supported";
246 : : return -EINVAL;
247 : : }
248 : :
249 : : return 0;
250 : : }
251 : :
252 : : static int
253 : 0 : txgbe_shaper_profile_add(struct rte_eth_dev *dev,
254 : : uint32_t shaper_profile_id,
255 : : const struct rte_tm_shaper_params *profile,
256 : : struct rte_tm_error *error)
257 : : {
258 : 0 : struct txgbe_tm_conf *tm_conf = TXGBE_DEV_TM_CONF(dev);
259 : : struct txgbe_tm_shaper_profile *shaper_profile;
260 : : int ret;
261 : :
262 [ # # ]: 0 : if (!profile || !error)
263 : : return -EINVAL;
264 : :
265 : : ret = txgbe_shaper_profile_param_check(profile, error);
266 : : if (ret)
267 : 0 : return ret;
268 : :
269 : : shaper_profile = txgbe_shaper_profile_search(dev, shaper_profile_id);
270 : :
271 [ # # ]: 0 : if (shaper_profile) {
272 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
273 : 0 : error->message = "profile ID exist";
274 : 0 : return -EINVAL;
275 : : }
276 : :
277 : 0 : shaper_profile = rte_zmalloc("txgbe_tm_shaper_profile",
278 : : sizeof(struct txgbe_tm_shaper_profile),
279 : : 0);
280 [ # # ]: 0 : if (!shaper_profile)
281 : : return -ENOMEM;
282 : 0 : shaper_profile->shaper_profile_id = shaper_profile_id;
283 [ # # ]: 0 : rte_memcpy(&shaper_profile->profile, profile,
284 : : sizeof(struct rte_tm_shaper_params));
285 : 0 : TAILQ_INSERT_TAIL(&tm_conf->shaper_profile_list,
286 : : shaper_profile, node);
287 : :
288 : 0 : return 0;
289 : : }
290 : :
291 : : static int
292 : 0 : txgbe_shaper_profile_del(struct rte_eth_dev *dev,
293 : : uint32_t shaper_profile_id,
294 : : struct rte_tm_error *error)
295 : : {
296 : 0 : struct txgbe_tm_conf *tm_conf = TXGBE_DEV_TM_CONF(dev);
297 : : struct txgbe_tm_shaper_profile *shaper_profile;
298 : :
299 [ # # ]: 0 : if (!error)
300 : : return -EINVAL;
301 : :
302 : : shaper_profile = txgbe_shaper_profile_search(dev, shaper_profile_id);
303 : :
304 [ # # ]: 0 : if (!shaper_profile) {
305 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;
306 : 0 : error->message = "profile ID not exist";
307 : 0 : return -EINVAL;
308 : : }
309 : :
310 : : /* don't delete a profile if it's used by one or several nodes */
311 [ # # ]: 0 : if (shaper_profile->reference_count) {
312 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
313 : 0 : error->message = "profile in use";
314 : 0 : return -EINVAL;
315 : : }
316 : :
317 [ # # ]: 0 : TAILQ_REMOVE(&tm_conf->shaper_profile_list, shaper_profile, node);
318 : 0 : rte_free(shaper_profile);
319 : :
320 : 0 : return 0;
321 : : }
322 : :
323 : : static inline struct txgbe_tm_node *
324 : 0 : txgbe_tm_node_search(struct rte_eth_dev *dev, uint32_t node_id,
325 : : enum txgbe_tm_node_type *node_type)
326 : : {
327 : 0 : struct txgbe_tm_conf *tm_conf = TXGBE_DEV_TM_CONF(dev);
328 : : struct txgbe_tm_node *tm_node;
329 : :
330 [ # # # # ]: 0 : if (tm_conf->root && tm_conf->root->id == node_id) {
331 : 0 : *node_type = TXGBE_TM_NODE_TYPE_PORT;
332 : 0 : return tm_conf->root;
333 : : }
334 : :
335 [ # # ]: 0 : TAILQ_FOREACH(tm_node, &tm_conf->tc_list, node) {
336 [ # # ]: 0 : if (tm_node->id == node_id) {
337 : 0 : *node_type = TXGBE_TM_NODE_TYPE_TC;
338 : 0 : return tm_node;
339 : : }
340 : : }
341 : :
342 [ # # ]: 0 : TAILQ_FOREACH(tm_node, &tm_conf->queue_list, node) {
343 [ # # ]: 0 : if (tm_node->id == node_id) {
344 : 0 : *node_type = TXGBE_TM_NODE_TYPE_QUEUE;
345 : 0 : return tm_node;
346 : : }
347 : : }
348 : :
349 : : return NULL;
350 : : }
351 : :
352 : : static void
353 [ # # ]: 0 : txgbe_queue_base_nb_get(struct rte_eth_dev *dev, uint16_t tc_node_no,
354 : : uint16_t *base, uint16_t *nb)
355 : : {
356 : : uint8_t nb_tcs = txgbe_tc_nb_get(dev);
357 : 0 : struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
358 : 0 : uint16_t vf_num = pci_dev->max_vfs;
359 : :
360 : 0 : *base = 0;
361 : 0 : *nb = 0;
362 : :
363 : : /* VT on */
364 [ # # ]: 0 : if (vf_num) {
365 : : /* no DCB */
366 [ # # ]: 0 : if (nb_tcs == 1) {
367 [ # # ]: 0 : if (vf_num >= RTE_ETH_32_POOLS) {
368 : 0 : *nb = 2;
369 : 0 : *base = vf_num * 2;
370 [ # # ]: 0 : } else if (vf_num >= RTE_ETH_16_POOLS) {
371 : 0 : *nb = 4;
372 : 0 : *base = vf_num * 4;
373 : : } else {
374 : 0 : *nb = 8;
375 : 0 : *base = vf_num * 8;
376 : : }
377 : : } else {
378 : : /* DCB */
379 : 0 : *nb = 1;
380 : 0 : *base = vf_num * nb_tcs + tc_node_no;
381 : : }
382 : : } else {
383 : : /* VT off */
384 [ # # ]: 0 : if (nb_tcs == RTE_ETH_8_TCS) {
385 [ # # # # : 0 : switch (tc_node_no) {
# # # #
# ]
386 : 0 : case 0:
387 : : *base = 0;
388 : 0 : *nb = 32;
389 : 0 : break;
390 : 0 : case 1:
391 : 0 : *base = 32;
392 : 0 : *nb = 32;
393 : 0 : break;
394 : 0 : case 2:
395 : 0 : *base = 64;
396 : 0 : *nb = 16;
397 : 0 : break;
398 : 0 : case 3:
399 : 0 : *base = 80;
400 : 0 : *nb = 16;
401 : 0 : break;
402 : 0 : case 4:
403 : 0 : *base = 96;
404 : 0 : *nb = 8;
405 : 0 : break;
406 : 0 : case 5:
407 : 0 : *base = 104;
408 : 0 : *nb = 8;
409 : 0 : break;
410 : 0 : case 6:
411 : 0 : *base = 112;
412 : 0 : *nb = 8;
413 : 0 : break;
414 : 0 : case 7:
415 : 0 : *base = 120;
416 : 0 : *nb = 8;
417 : 0 : break;
418 : : default:
419 : : return;
420 : : }
421 : : } else {
422 [ # # # # : 0 : switch (tc_node_no) {
# ]
423 : : /**
424 : : * If no VF and no DCB, only 64 queues can be used.
425 : : * This case also be covered by this "case 0".
426 : : */
427 : 0 : case 0:
428 : : *base = 0;
429 : 0 : *nb = 64;
430 : 0 : break;
431 : 0 : case 1:
432 : 0 : *base = 64;
433 : 0 : *nb = 32;
434 : 0 : break;
435 : 0 : case 2:
436 : 0 : *base = 96;
437 : 0 : *nb = 16;
438 : 0 : break;
439 : 0 : case 3:
440 : 0 : *base = 112;
441 : 0 : *nb = 16;
442 : 0 : break;
443 : : default:
444 : : return;
445 : : }
446 : : }
447 : : }
448 : : }
449 : :
450 : : static int
451 : 0 : txgbe_node_param_check(struct rte_eth_dev *dev, uint32_t node_id,
452 : : uint32_t priority, uint32_t weight,
453 : : const struct rte_tm_node_params *params,
454 : : struct rte_tm_error *error)
455 : : {
456 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
457 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
458 : 0 : error->message = "invalid node id";
459 : 0 : return -EINVAL;
460 : : }
461 : :
462 [ # # ]: 0 : if (priority) {
463 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PRIORITY;
464 : 0 : error->message = "priority should be 0";
465 : 0 : return -EINVAL;
466 : : }
467 : :
468 [ # # ]: 0 : if (weight != 1) {
469 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_WEIGHT;
470 : 0 : error->message = "weight must be 1";
471 : 0 : return -EINVAL;
472 : : }
473 : :
474 : : /* not support shared shaper */
475 [ # # ]: 0 : if (params->shared_shaper_id) {
476 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;
477 : 0 : error->message = "shared shaper not supported";
478 : 0 : return -EINVAL;
479 : : }
480 [ # # ]: 0 : if (params->n_shared_shapers) {
481 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;
482 : 0 : error->message = "shared shaper not supported";
483 : 0 : return -EINVAL;
484 : : }
485 : :
486 : : /* for non-leaf node */
487 [ # # ]: 0 : if (node_id >= dev->data->nb_tx_queues) {
488 : : /* check the unsupported parameters */
489 [ # # ]: 0 : if (params->nonleaf.wfq_weight_mode) {
490 : 0 : error->type =
491 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;
492 : 0 : error->message = "WFQ not supported";
493 : 0 : return -EINVAL;
494 : : }
495 [ # # ]: 0 : if (params->nonleaf.n_sp_priorities != 1) {
496 : 0 : error->type =
497 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;
498 : 0 : error->message = "SP priority not supported";
499 : 0 : return -EINVAL;
500 : : } else if (params->nonleaf.wfq_weight_mode &&
501 : : !(*params->nonleaf.wfq_weight_mode)) {
502 : : error->type =
503 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;
504 : : error->message = "WFP should be byte mode";
505 : : return -EINVAL;
506 : : }
507 : :
508 : : return 0;
509 : : }
510 : :
511 : : /* for leaf node */
512 : : /* check the unsupported parameters */
513 [ # # ]: 0 : if (params->leaf.cman) {
514 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;
515 : 0 : error->message = "Congestion management not supported";
516 : 0 : return -EINVAL;
517 : : }
518 [ # # ]: 0 : if (params->leaf.wred.wred_profile_id !=
519 : : RTE_TM_WRED_PROFILE_ID_NONE) {
520 : 0 : error->type =
521 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;
522 : 0 : error->message = "WRED not supported";
523 : 0 : return -EINVAL;
524 : : }
525 [ # # ]: 0 : if (params->leaf.wred.shared_wred_context_id) {
526 : 0 : error->type =
527 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;
528 : 0 : error->message = "WRED not supported";
529 : 0 : return -EINVAL;
530 : : }
531 [ # # ]: 0 : if (params->leaf.wred.n_shared_wred_contexts) {
532 : 0 : error->type =
533 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;
534 : 0 : error->message = "WRED not supported";
535 : 0 : return -EINVAL;
536 : : }
537 : :
538 : : return 0;
539 : : }
540 : :
541 : : /**
542 : : * Now the TC and queue configuration is controlled by DCB.
543 : : * We need check if the node configuration follows the DCB configuration.
544 : : * In the future, we may use TM to cover DCB.
545 : : */
546 : : static int
547 : 0 : txgbe_node_add(struct rte_eth_dev *dev, uint32_t node_id,
548 : : uint32_t parent_node_id, uint32_t priority,
549 : : uint32_t weight, uint32_t level_id,
550 : : const struct rte_tm_node_params *params,
551 : : struct rte_tm_error *error)
552 : : {
553 : 0 : struct txgbe_tm_conf *tm_conf = TXGBE_DEV_TM_CONF(dev);
554 : 0 : enum txgbe_tm_node_type node_type = TXGBE_TM_NODE_TYPE_MAX;
555 : 0 : enum txgbe_tm_node_type parent_node_type = TXGBE_TM_NODE_TYPE_MAX;
556 : : struct txgbe_tm_shaper_profile *shaper_profile = NULL;
557 : : struct txgbe_tm_node *tm_node;
558 : : struct txgbe_tm_node *parent_node;
559 : : uint8_t nb_tcs;
560 : 0 : uint16_t q_base = 0;
561 : 0 : uint16_t q_nb = 0;
562 : : int ret;
563 : :
564 [ # # ]: 0 : if (!params || !error)
565 : : return -EINVAL;
566 : :
567 : : /* if already committed */
568 [ # # ]: 0 : if (tm_conf->committed) {
569 : 0 : error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
570 : 0 : error->message = "already committed";
571 : 0 : return -EINVAL;
572 : : }
573 : :
574 : 0 : ret = txgbe_node_param_check(dev, node_id, priority, weight,
575 : : params, error);
576 [ # # ]: 0 : if (ret)
577 : : return ret;
578 : :
579 : : /* check if the node ID is already used */
580 [ # # ]: 0 : if (txgbe_tm_node_search(dev, node_id, &node_type)) {
581 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
582 : 0 : error->message = "node id already used";
583 : 0 : return -EINVAL;
584 : : }
585 : :
586 : : /* check the shaper profile id */
587 [ # # ]: 0 : if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE) {
588 : : shaper_profile = txgbe_shaper_profile_search(dev,
589 : : params->shaper_profile_id);
590 [ # # ]: 0 : if (!shaper_profile) {
591 : 0 : error->type =
592 : : RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;
593 : 0 : error->message = "shaper profile not exist";
594 : 0 : return -EINVAL;
595 : : }
596 : : }
597 : :
598 : : /* root node if not have a parent */
599 [ # # ]: 0 : if (parent_node_id == RTE_TM_NODE_ID_NULL) {
600 : : /* check level */
601 [ # # ]: 0 : if (level_id != RTE_TM_NODE_LEVEL_ID_ANY &&
602 : : level_id > TXGBE_TM_NODE_TYPE_PORT) {
603 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
604 : 0 : error->message = "Wrong level";
605 : 0 : return -EINVAL;
606 : : }
607 : :
608 : : /* obviously no more than one root */
609 [ # # ]: 0 : if (tm_conf->root) {
610 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
611 : 0 : error->message = "already have a root";
612 : 0 : return -EINVAL;
613 : : }
614 : :
615 : : /* add the root node */
616 : 0 : tm_node = rte_zmalloc("txgbe_tm_node",
617 : : sizeof(struct txgbe_tm_node),
618 : : 0);
619 [ # # ]: 0 : if (!tm_node)
620 : : return -ENOMEM;
621 : 0 : tm_node->id = node_id;
622 : 0 : tm_node->priority = priority;
623 : 0 : tm_node->weight = weight;
624 : 0 : tm_node->reference_count = 0;
625 : 0 : tm_node->no = 0;
626 : 0 : tm_node->parent = NULL;
627 : 0 : tm_node->shaper_profile = shaper_profile;
628 [ # # ]: 0 : rte_memcpy(&tm_node->params, params,
629 : : sizeof(struct rte_tm_node_params));
630 : 0 : tm_conf->root = tm_node;
631 : :
632 : : /* increase the reference counter of the shaper profile */
633 [ # # ]: 0 : if (shaper_profile)
634 : 0 : shaper_profile->reference_count++;
635 : :
636 : 0 : return 0;
637 : : }
638 : :
639 : : /* TC or queue node */
640 : : /* check the parent node */
641 : 0 : parent_node = txgbe_tm_node_search(dev, parent_node_id,
642 : : &parent_node_type);
643 [ # # ]: 0 : if (!parent_node) {
644 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
645 : 0 : error->message = "parent not exist";
646 : 0 : return -EINVAL;
647 : : }
648 [ # # ]: 0 : if (parent_node_type != TXGBE_TM_NODE_TYPE_PORT &&
649 : : parent_node_type != TXGBE_TM_NODE_TYPE_TC) {
650 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;
651 : 0 : error->message = "parent is not port or TC";
652 : 0 : return -EINVAL;
653 : : }
654 : : /* check level */
655 [ # # ]: 0 : if (level_id != RTE_TM_NODE_LEVEL_ID_ANY &&
656 [ # # ]: 0 : level_id != parent_node_type + 1) {
657 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS;
658 : 0 : error->message = "Wrong level";
659 : 0 : return -EINVAL;
660 : : }
661 : :
662 : : /* check the node number */
663 [ # # ]: 0 : if (parent_node_type == TXGBE_TM_NODE_TYPE_PORT) {
664 : : /* check TC number */
665 : : nb_tcs = txgbe_tc_nb_get(dev);
666 [ # # ]: 0 : if (tm_conf->nb_tc_node >= nb_tcs) {
667 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
668 : 0 : error->message = "too many TCs";
669 : 0 : return -EINVAL;
670 : : }
671 : : } else {
672 : : /* check queue number */
673 [ # # ]: 0 : if (tm_conf->nb_queue_node >= dev->data->nb_tx_queues) {
674 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
675 : 0 : error->message = "too many queues";
676 : 0 : return -EINVAL;
677 : : }
678 : :
679 : 0 : txgbe_queue_base_nb_get(dev, parent_node->no, &q_base, &q_nb);
680 [ # # ]: 0 : if (parent_node->reference_count >= q_nb) {
681 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
682 : 0 : error->message = "too many queues than TC supported";
683 : 0 : return -EINVAL;
684 : : }
685 : :
686 : : /**
687 : : * check the node id.
688 : : * For queue, the node id means queue id.
689 : : */
690 [ # # ]: 0 : if (node_id >= dev->data->nb_tx_queues) {
691 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
692 : 0 : error->message = "too large queue id";
693 : 0 : return -EINVAL;
694 : : }
695 : : }
696 : :
697 : : /* add the TC or queue node */
698 : 0 : tm_node = rte_zmalloc("txgbe_tm_node",
699 : : sizeof(struct txgbe_tm_node),
700 : : 0);
701 [ # # ]: 0 : if (!tm_node)
702 : : return -ENOMEM;
703 : 0 : tm_node->id = node_id;
704 : 0 : tm_node->priority = priority;
705 : 0 : tm_node->weight = weight;
706 : 0 : tm_node->reference_count = 0;
707 : 0 : tm_node->parent = parent_node;
708 : 0 : tm_node->shaper_profile = shaper_profile;
709 [ # # ]: 0 : rte_memcpy(&tm_node->params, params,
710 : : sizeof(struct rte_tm_node_params));
711 [ # # ]: 0 : if (parent_node_type == TXGBE_TM_NODE_TYPE_PORT) {
712 : 0 : tm_node->no = parent_node->reference_count;
713 : 0 : TAILQ_INSERT_TAIL(&tm_conf->tc_list,
714 : : tm_node, node);
715 : 0 : tm_conf->nb_tc_node++;
716 : : } else {
717 : 0 : tm_node->no = q_base + parent_node->reference_count;
718 : 0 : TAILQ_INSERT_TAIL(&tm_conf->queue_list,
719 : : tm_node, node);
720 : 0 : tm_conf->nb_queue_node++;
721 : : }
722 : 0 : tm_node->parent->reference_count++;
723 : :
724 : : /* increase the reference counter of the shaper profile */
725 [ # # ]: 0 : if (shaper_profile)
726 : 0 : shaper_profile->reference_count++;
727 : :
728 : : return 0;
729 : : }
730 : :
731 : : static int
732 : 0 : txgbe_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
733 : : struct rte_tm_error *error)
734 : : {
735 : 0 : struct txgbe_tm_conf *tm_conf = TXGBE_DEV_TM_CONF(dev);
736 : 0 : enum txgbe_tm_node_type node_type = TXGBE_TM_NODE_TYPE_MAX;
737 : : struct txgbe_tm_node *tm_node;
738 : :
739 [ # # ]: 0 : if (!error)
740 : : return -EINVAL;
741 : :
742 : : /* if already committed */
743 [ # # ]: 0 : if (tm_conf->committed) {
744 : 0 : error->type = RTE_TM_ERROR_TYPE_UNSPECIFIED;
745 : 0 : error->message = "already committed";
746 : 0 : return -EINVAL;
747 : : }
748 : :
749 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
750 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
751 : 0 : error->message = "invalid node id";
752 : 0 : return -EINVAL;
753 : : }
754 : :
755 : : /* check the if the node id exists */
756 : 0 : tm_node = txgbe_tm_node_search(dev, node_id, &node_type);
757 [ # # ]: 0 : if (!tm_node) {
758 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
759 : 0 : error->message = "no such node";
760 : 0 : return -EINVAL;
761 : : }
762 : :
763 : : /* the node should have no child */
764 [ # # ]: 0 : if (tm_node->reference_count) {
765 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
766 : 0 : error->message =
767 : : "cannot delete a node which has children";
768 : 0 : return -EINVAL;
769 : : }
770 : :
771 : : /* root node */
772 [ # # ]: 0 : if (node_type == TXGBE_TM_NODE_TYPE_PORT) {
773 [ # # ]: 0 : if (tm_node->shaper_profile)
774 : 0 : tm_node->shaper_profile->reference_count--;
775 : 0 : rte_free(tm_node);
776 : 0 : tm_conf->root = NULL;
777 : 0 : return 0;
778 : : }
779 : :
780 : : /* TC or queue node */
781 [ # # ]: 0 : if (tm_node->shaper_profile)
782 : 0 : tm_node->shaper_profile->reference_count--;
783 : 0 : tm_node->parent->reference_count--;
784 [ # # ]: 0 : if (node_type == TXGBE_TM_NODE_TYPE_TC) {
785 [ # # ]: 0 : TAILQ_REMOVE(&tm_conf->tc_list, tm_node, node);
786 : 0 : tm_conf->nb_tc_node--;
787 : : } else {
788 [ # # ]: 0 : TAILQ_REMOVE(&tm_conf->queue_list, tm_node, node);
789 : 0 : tm_conf->nb_queue_node--;
790 : : }
791 : 0 : rte_free(tm_node);
792 : :
793 : 0 : return 0;
794 : : }
795 : :
796 : : static int
797 : 0 : txgbe_node_type_get(struct rte_eth_dev *dev, uint32_t node_id,
798 : : int *is_leaf, struct rte_tm_error *error)
799 : : {
800 : 0 : enum txgbe_tm_node_type node_type = TXGBE_TM_NODE_TYPE_MAX;
801 : : struct txgbe_tm_node *tm_node;
802 : :
803 [ # # ]: 0 : if (!is_leaf || !error)
804 : : return -EINVAL;
805 : :
806 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
807 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
808 : 0 : error->message = "invalid node id";
809 : 0 : return -EINVAL;
810 : : }
811 : :
812 : : /* check if the node id exists */
813 : 0 : tm_node = txgbe_tm_node_search(dev, node_id, &node_type);
814 [ # # ]: 0 : if (!tm_node) {
815 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
816 : 0 : error->message = "no such node";
817 : 0 : return -EINVAL;
818 : : }
819 : :
820 [ # # ]: 0 : if (node_type == TXGBE_TM_NODE_TYPE_QUEUE)
821 : 0 : *is_leaf = true;
822 : : else
823 : 0 : *is_leaf = false;
824 : :
825 : : return 0;
826 : : }
827 : :
828 : : static int
829 : 0 : txgbe_level_capabilities_get(struct rte_eth_dev *dev,
830 : : uint32_t level_id,
831 : : struct rte_tm_level_capabilities *cap,
832 : : struct rte_tm_error *error)
833 : : {
834 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
835 : :
836 [ # # ]: 0 : if (!cap || !error)
837 : : return -EINVAL;
838 : :
839 [ # # ]: 0 : if (level_id >= TXGBE_TM_NODE_TYPE_MAX) {
840 : 0 : error->type = RTE_TM_ERROR_TYPE_LEVEL_ID;
841 : 0 : error->message = "too deep level";
842 : 0 : return -EINVAL;
843 : : }
844 : :
845 : : /* root node */
846 [ # # ]: 0 : if (level_id == TXGBE_TM_NODE_TYPE_PORT) {
847 : 0 : cap->n_nodes_max = 1;
848 : 0 : cap->n_nodes_nonleaf_max = 1;
849 : 0 : cap->n_nodes_leaf_max = 0;
850 [ # # ]: 0 : } else if (level_id == TXGBE_TM_NODE_TYPE_TC) {
851 : : /* TC */
852 : 0 : cap->n_nodes_max = TXGBE_DCB_TC_MAX;
853 : 0 : cap->n_nodes_nonleaf_max = TXGBE_DCB_TC_MAX;
854 : 0 : cap->n_nodes_leaf_max = 0;
855 : : } else {
856 : : /* queue */
857 : 0 : cap->n_nodes_max = hw->mac.max_tx_queues;
858 : 0 : cap->n_nodes_nonleaf_max = 0;
859 : 0 : cap->n_nodes_leaf_max = hw->mac.max_tx_queues;
860 : : }
861 : :
862 : 0 : cap->non_leaf_nodes_identical = true;
863 : 0 : cap->leaf_nodes_identical = true;
864 : :
865 [ # # ]: 0 : if (level_id != TXGBE_TM_NODE_TYPE_QUEUE) {
866 : 0 : cap->nonleaf.shaper_private_supported = true;
867 : 0 : cap->nonleaf.shaper_private_dual_rate_supported = false;
868 : 0 : cap->nonleaf.shaper_private_rate_min = 0;
869 : : /* 10Gbps -> 1.25GBps */
870 : 0 : cap->nonleaf.shaper_private_rate_max = 1250000000ull;
871 : 0 : cap->nonleaf.shaper_shared_n_max = 0;
872 [ # # ]: 0 : if (level_id == TXGBE_TM_NODE_TYPE_PORT)
873 : 0 : cap->nonleaf.sched_n_children_max =
874 : : TXGBE_DCB_TC_MAX;
875 : : else
876 : 0 : cap->nonleaf.sched_n_children_max =
877 : 0 : hw->mac.max_tx_queues;
878 : 0 : cap->nonleaf.sched_sp_n_priorities_max = 1;
879 : 0 : cap->nonleaf.sched_wfq_n_children_per_group_max = 0;
880 : 0 : cap->nonleaf.sched_wfq_n_groups_max = 0;
881 : 0 : cap->nonleaf.sched_wfq_weight_max = 1;
882 : 0 : cap->nonleaf.stats_mask = 0;
883 : :
884 : 0 : return 0;
885 : : }
886 : :
887 : : /* queue node */
888 : 0 : cap->leaf.shaper_private_supported = true;
889 : 0 : cap->leaf.shaper_private_dual_rate_supported = false;
890 : 0 : cap->leaf.shaper_private_rate_min = 0;
891 : : /* 10Gbps -> 1.25GBps */
892 : 0 : cap->leaf.shaper_private_rate_max = 1250000000ull;
893 : 0 : cap->leaf.shaper_shared_n_max = 0;
894 : 0 : cap->leaf.cman_head_drop_supported = false;
895 : 0 : cap->leaf.cman_wred_context_private_supported = true;
896 : 0 : cap->leaf.cman_wred_context_shared_n_max = 0;
897 : 0 : cap->leaf.stats_mask = 0;
898 : :
899 : 0 : return 0;
900 : : }
901 : :
902 : : static int
903 : 0 : txgbe_node_capabilities_get(struct rte_eth_dev *dev,
904 : : uint32_t node_id,
905 : : struct rte_tm_node_capabilities *cap,
906 : : struct rte_tm_error *error)
907 : : {
908 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
909 : 0 : enum txgbe_tm_node_type node_type = TXGBE_TM_NODE_TYPE_MAX;
910 : : struct txgbe_tm_node *tm_node;
911 : :
912 [ # # ]: 0 : if (!cap || !error)
913 : : return -EINVAL;
914 : :
915 [ # # ]: 0 : if (node_id == RTE_TM_NODE_ID_NULL) {
916 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
917 : 0 : error->message = "invalid node id";
918 : 0 : return -EINVAL;
919 : : }
920 : :
921 : : /* check if the node id exists */
922 : 0 : tm_node = txgbe_tm_node_search(dev, node_id, &node_type);
923 [ # # ]: 0 : if (!tm_node) {
924 : 0 : error->type = RTE_TM_ERROR_TYPE_NODE_ID;
925 : 0 : error->message = "no such node";
926 : 0 : return -EINVAL;
927 : : }
928 : :
929 : 0 : cap->shaper_private_supported = true;
930 : 0 : cap->shaper_private_dual_rate_supported = false;
931 : 0 : cap->shaper_private_rate_min = 0;
932 : : /* 10Gbps -> 1.25GBps */
933 : 0 : cap->shaper_private_rate_max = 1250000000ull;
934 : 0 : cap->shaper_shared_n_max = 0;
935 : :
936 [ # # ]: 0 : if (node_type == TXGBE_TM_NODE_TYPE_QUEUE) {
937 : 0 : cap->leaf.cman_head_drop_supported = false;
938 : 0 : cap->leaf.cman_wred_context_private_supported = true;
939 : 0 : cap->leaf.cman_wred_context_shared_n_max = 0;
940 : : } else {
941 [ # # ]: 0 : if (node_type == TXGBE_TM_NODE_TYPE_PORT)
942 : 0 : cap->nonleaf.sched_n_children_max =
943 : : TXGBE_DCB_TC_MAX;
944 : : else
945 : 0 : cap->nonleaf.sched_n_children_max =
946 : 0 : hw->mac.max_tx_queues;
947 : 0 : cap->nonleaf.sched_sp_n_priorities_max = 1;
948 : 0 : cap->nonleaf.sched_wfq_n_children_per_group_max = 0;
949 : 0 : cap->nonleaf.sched_wfq_n_groups_max = 0;
950 : 0 : cap->nonleaf.sched_wfq_weight_max = 1;
951 : : }
952 : :
953 : 0 : cap->stats_mask = 0;
954 : :
955 : 0 : return 0;
956 : : }
957 : :
958 : : static int
959 : 0 : txgbe_hierarchy_commit(struct rte_eth_dev *dev,
960 : : int clear_on_fail,
961 : : struct rte_tm_error *error)
962 : : {
963 : 0 : struct txgbe_tm_conf *tm_conf = TXGBE_DEV_TM_CONF(dev);
964 : : struct txgbe_tm_node *tm_node;
965 : : uint64_t bw;
966 : : int ret;
967 : :
968 [ # # ]: 0 : if (!error)
969 : : return -EINVAL;
970 : :
971 : : /* check the setting */
972 [ # # ]: 0 : if (!tm_conf->root)
973 : 0 : goto done;
974 : :
975 : : /* not support port max bandwidth yet */
976 [ # # ]: 0 : if (tm_conf->root->shaper_profile &&
977 [ # # ]: 0 : tm_conf->root->shaper_profile->profile.peak.rate) {
978 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
979 : 0 : error->message = "no port max bandwidth";
980 : 0 : goto fail_clear;
981 : : }
982 : :
983 : : /* HW not support TC max bandwidth */
984 [ # # ]: 0 : TAILQ_FOREACH(tm_node, &tm_conf->tc_list, node) {
985 [ # # ]: 0 : if (tm_node->shaper_profile &&
986 [ # # ]: 0 : tm_node->shaper_profile->profile.peak.rate) {
987 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
988 : 0 : error->message = "no TC max bandwidth";
989 : 0 : goto fail_clear;
990 : : }
991 : : }
992 : :
993 : : /* queue max bandwidth */
994 [ # # ]: 0 : TAILQ_FOREACH(tm_node, &tm_conf->queue_list, node) {
995 [ # # ]: 0 : if (tm_node->shaper_profile)
996 : 0 : bw = tm_node->shaper_profile->profile.peak.rate;
997 : : else
998 : : bw = 0;
999 [ # # ]: 0 : if (bw) {
1000 : : /* interpret Bps to Mbps */
1001 : 0 : bw = bw * 8 / 1000 / 1000;
1002 : 0 : ret = txgbe_set_queue_rate_limit(dev, tm_node->no, bw);
1003 [ # # ]: 0 : if (ret) {
1004 : 0 : error->type = RTE_TM_ERROR_TYPE_SHAPER_PROFILE;
1005 : 0 : error->message =
1006 : : "failed to set queue max bandwidth";
1007 : 0 : goto fail_clear;
1008 : : }
1009 : : }
1010 : : }
1011 : :
1012 : 0 : done:
1013 : 0 : tm_conf->committed = true;
1014 : 0 : return 0;
1015 : :
1016 : 0 : fail_clear:
1017 : : /* clear all the traffic manager configuration */
1018 [ # # ]: 0 : if (clear_on_fail) {
1019 : 0 : txgbe_tm_conf_uninit(dev);
1020 : 0 : txgbe_tm_conf_init(dev);
1021 : : }
1022 : : return -EINVAL;
1023 : : }
|