]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/drivers/net/mvpp2/mrvl_tm.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / seastar / dpdk / drivers / net / mvpp2 / mrvl_tm.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Marvell International Ltd.
3 * Copyright(c) 2018 Semihalf.
4 * All rights reserved.
5 */
6
7 #include <rte_malloc.h>
8
9 #include <linux/ethtool.h>
10 #include <linux/sockios.h>
11 #include <net/if.h>
12 #include <sys/ioctl.h>
13
14 #include "mrvl_tm.h"
15
16 /** Minimum rate value in Bytes/s */
17 #define MRVL_RATE_MIN (PP2_PPIO_MIN_CIR * 1000 / 8)
18
19 /** Minimum burst size in Bytes */
20 #define MRVL_BURST_MIN (PP2_PPIO_MIN_CBS * 1000)
21
22 /** Maximum burst size in Bytes */
23 #define MRVL_BURST_MAX 256000000
24
25 /** Maximum WRR weight */
26 #define MRVL_WEIGHT_MAX 255
27
28 /**
29 * Get maximum port rate in Bytes/s.
30 *
31 * @param dev Pointer to the device.
32 * @param rate Pointer to the rate.
33 * @returns 0 on success, negative value otherwise.
34 */
35 static int
36 mrvl_get_max_rate(struct rte_eth_dev *dev, uint64_t *rate)
37 {
38 struct ethtool_cmd edata;
39 struct ifreq req;
40 int ret, fd;
41
42 memset(&edata, 0, sizeof(edata));
43 memset(&req, 0, sizeof(req));
44 edata.cmd = ETHTOOL_GSET;
45 strcpy(req.ifr_name, dev->data->name);
46 req.ifr_data = (void *)&edata;
47
48 fd = socket(AF_INET, SOCK_DGRAM, 0);
49 if (fd == -1)
50 return -1;
51
52 ret = ioctl(fd, SIOCETHTOOL, &req);
53 if (ret == -1) {
54 close(fd);
55 return -1;
56 }
57
58 close(fd);
59
60 *rate = ethtool_cmd_speed(&edata) * 1000 * 1000 / 8;
61
62 return 0;
63 }
64
65 /**
66 * Initialize traffic manager related data.
67 *
68 * @param dev Pointer to the device.
69 * @returns 0 on success, failure otherwise.
70 */
71 int
72 mrvl_tm_init(struct rte_eth_dev *dev)
73 {
74 struct mrvl_priv *priv = dev->data->dev_private;
75
76 LIST_INIT(&priv->shaper_profiles);
77 LIST_INIT(&priv->nodes);
78
79 if (priv->rate_max)
80 return 0;
81
82 return mrvl_get_max_rate(dev, &priv->rate_max);
83 }
84
85 /**
86 * Cleanup traffic manager related data.
87 *
88 * @param dev Pointer to the device.
89 */
90 void mrvl_tm_deinit(struct rte_eth_dev *dev)
91 {
92 struct mrvl_priv *priv = dev->data->dev_private;
93 struct mrvl_tm_shaper_profile *profile =
94 LIST_FIRST(&priv->shaper_profiles);
95 struct mrvl_tm_node *node = LIST_FIRST(&priv->nodes);
96
97 while (profile) {
98 struct mrvl_tm_shaper_profile *next = LIST_NEXT(profile, next);
99
100 LIST_REMOVE(profile, next);
101 rte_free(profile);
102 profile = next;
103 }
104
105 while (node) {
106 struct mrvl_tm_node *next = LIST_NEXT(node, next);
107
108 LIST_REMOVE(node, next);
109 rte_free(node);
110 node = next;
111 }
112 }
113
114 /**
115 * Get node using its id.
116 *
117 * @param priv Pointer to the port's private data.
118 * @param node_id Id used by this node.
119 * @returns Pointer to the node if exists, NULL otherwise.
120 */
121 static struct mrvl_tm_node *
122 mrvl_node_from_id(struct mrvl_priv *priv, uint32_t node_id)
123 {
124 struct mrvl_tm_node *node;
125
126 LIST_FOREACH(node, &priv->nodes, next)
127 if (node->id == node_id)
128 return node;
129
130 return NULL;
131 }
132
133 /**
134 * Check whether node is leaf or root.
135 *
136 * @param dev Pointer to the device.
137 * @param node_id Id used by this node.
138 * @param is_leaf Pointer to flag indicating whether node is a leaf.
139 * @param error Pointer to the error.
140 * @returns 0 on success, negative value otherwise.
141 */
142 static int
143 mrvl_node_type_get(struct rte_eth_dev *dev, uint32_t node_id, int *is_leaf,
144 struct rte_tm_error *error)
145 {
146 struct mrvl_priv *priv = dev->data->dev_private;
147 struct mrvl_tm_node *node;
148
149 if (!is_leaf)
150 return -rte_tm_error_set(error, EINVAL,
151 RTE_TM_ERROR_TYPE_UNSPECIFIED,
152 NULL, NULL);
153
154 node = mrvl_node_from_id(priv, node_id);
155 if (!node)
156 return -rte_tm_error_set(error, ENODEV,
157 RTE_TM_ERROR_TYPE_NODE_ID,
158 NULL, "Node id does not exist\n");
159
160 *is_leaf = node->type == MRVL_NODE_QUEUE ? 1 : 0;
161
162 return 0;
163 }
164
165 /**
166 * Get traffic manager capabilities.
167 *
168 * @param dev Pointer to the device (unused).
169 * @param cap Pointer to the capabilities.
170 * @param error Pointer to the error.
171 * @returns 0 on success, negative value otherwise.
172 */
173 static int
174 mrvl_capabilities_get(struct rte_eth_dev *dev,
175 struct rte_tm_capabilities *cap,
176 struct rte_tm_error *error)
177 {
178 struct mrvl_priv *priv = dev->data->dev_private;
179
180 if (!cap)
181 return -rte_tm_error_set(error, EINVAL,
182 RTE_TM_ERROR_TYPE_UNSPECIFIED,
183 NULL, "Capabilities are missing\n");
184
185 memset(cap, 0, sizeof(*cap));
186
187 cap->n_nodes_max = 1 + dev->data->nb_tx_queues; /* port + txqs number */
188 cap->n_levels_max = 2; /* port level + txqs level */
189 cap->non_leaf_nodes_identical = 1;
190 cap->leaf_nodes_identical = 1;
191
192 cap->shaper_n_max = cap->n_nodes_max;
193 cap->shaper_private_n_max = cap->shaper_n_max;
194 cap->shaper_private_rate_min = MRVL_RATE_MIN;
195 cap->shaper_private_rate_max = priv->rate_max;
196
197 cap->sched_n_children_max = dev->data->nb_tx_queues;
198 cap->sched_sp_n_priorities_max = dev->data->nb_tx_queues;
199 cap->sched_wfq_n_children_per_group_max = dev->data->nb_tx_queues;
200 cap->sched_wfq_n_groups_max = 1;
201 cap->sched_wfq_weight_max = MRVL_WEIGHT_MAX;
202
203 cap->dynamic_update_mask = RTE_TM_UPDATE_NODE_SUSPEND_RESUME |
204 RTE_TM_UPDATE_NODE_STATS;
205 cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
206
207 return 0;
208 }
209
210 /**
211 * Get traffic manager hierarchy level capabilities.
212 *
213 * @param dev Pointer to the device.
214 * @param level_id Id of the level.
215 * @param cap Pointer to the level capabilities.
216 * @param error Pointer to the error.
217 * @returns 0 on success, negative value otherwise.
218 */
219 static int
220 mrvl_level_capabilities_get(struct rte_eth_dev *dev,
221 uint32_t level_id,
222 struct rte_tm_level_capabilities *cap,
223 struct rte_tm_error *error)
224 {
225 struct mrvl_priv *priv = dev->data->dev_private;
226
227 if (!cap)
228 return -rte_tm_error_set(error, EINVAL,
229 RTE_TM_ERROR_TYPE_UNSPECIFIED,
230 NULL, NULL);
231
232 memset(cap, 0, sizeof(*cap));
233
234 if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
235 return -rte_tm_error_set(error, EINVAL,
236 RTE_TM_ERROR_TYPE_LEVEL_ID,
237 NULL, "Wrong level id\n");
238
239 if (level_id == MRVL_NODE_PORT) {
240 cap->n_nodes_max = 1;
241 cap->n_nodes_nonleaf_max = 1;
242 cap->non_leaf_nodes_identical = 1;
243
244 cap->nonleaf.shaper_private_supported = 1;
245 cap->nonleaf.shaper_private_rate_min = MRVL_RATE_MIN;
246 cap->nonleaf.shaper_private_rate_max = priv->rate_max;
247
248 cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
249 cap->nonleaf.sched_sp_n_priorities_max = 1;
250 cap->nonleaf.sched_wfq_n_children_per_group_max =
251 dev->data->nb_tx_queues;
252 cap->nonleaf.sched_wfq_n_groups_max = 1;
253 cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
254 cap->nonleaf.stats_mask = RTE_TM_STATS_N_PKTS |
255 RTE_TM_STATS_N_BYTES;
256 } else { /* level_id == MRVL_NODE_QUEUE */
257 cap->n_nodes_max = dev->data->nb_tx_queues;
258 cap->n_nodes_leaf_max = dev->data->nb_tx_queues;
259 cap->leaf_nodes_identical = 1;
260
261 cap->leaf.shaper_private_supported = 1;
262 cap->leaf.shaper_private_rate_min = MRVL_RATE_MIN;
263 cap->leaf.shaper_private_rate_max = priv->rate_max;
264 cap->leaf.stats_mask = RTE_TM_STATS_N_PKTS;
265 }
266
267 return 0;
268 }
269
270 /**
271 * Get node capabilities.
272 *
273 * @param dev Pointer to the device.
274 * @param node_id Id of the node.
275 * @param cap Pointer to the capabilities.
276 * @param error Pointer to the error.
277 * @returns 0 on success, negative value otherwise.
278 */
279 static int
280 mrvl_node_capabilities_get(struct rte_eth_dev *dev, uint32_t node_id,
281 struct rte_tm_node_capabilities *cap,
282 struct rte_tm_error *error)
283 {
284 struct mrvl_priv *priv = dev->data->dev_private;
285 struct mrvl_tm_node *node;
286
287 if (!cap)
288 return -rte_tm_error_set(error, EINVAL,
289 RTE_TM_ERROR_TYPE_UNSPECIFIED,
290 NULL, NULL);
291
292 memset(cap, 0, sizeof(*cap));
293
294 node = mrvl_node_from_id(priv, node_id);
295 if (!node)
296 return -rte_tm_error_set(error, ENODEV,
297 RTE_TM_ERROR_TYPE_NODE_ID,
298 NULL, "Node id does not exist\n");
299
300 cap->shaper_private_supported = 1;
301 cap->shaper_private_rate_min = MRVL_RATE_MIN;
302 cap->shaper_private_rate_max = priv->rate_max;
303
304 if (node->type == MRVL_NODE_PORT) {
305 cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
306 cap->nonleaf.sched_sp_n_priorities_max = 1;
307 cap->nonleaf.sched_wfq_n_children_per_group_max =
308 dev->data->nb_tx_queues;
309 cap->nonleaf.sched_wfq_n_groups_max = 1;
310 cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
311 cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
312 } else {
313 cap->stats_mask = RTE_TM_STATS_N_PKTS;
314 }
315
316 return 0;
317 }
318
319 /**
320 * Get shaper profile using its id.
321 *
322 * @param priv Pointer to the port's private data.
323 * @param shaper_profile_id Id used by the shaper.
324 * @returns Pointer to the shaper profile if exists, NULL otherwise.
325 */
326 static struct mrvl_tm_shaper_profile *
327 mrvl_shaper_profile_from_id(struct mrvl_priv *priv, uint32_t shaper_profile_id)
328 {
329 struct mrvl_tm_shaper_profile *profile;
330
331 LIST_FOREACH(profile, &priv->shaper_profiles, next)
332 if (profile->id == shaper_profile_id)
333 return profile;
334
335 return NULL;
336 }
337
338 /**
339 * Add a new shaper profile.
340 *
341 * @param dev Pointer to the device.
342 * @param shaper_profile_id Id of the new profile.
343 * @param params Pointer to the shaper profile parameters.
344 * @param error Pointer to the error.
345 * @returns 0 on success, negative value otherwise.
346 */
347 static int
348 mrvl_shaper_profile_add(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
349 struct rte_tm_shaper_params *params,
350 struct rte_tm_error *error)
351 {
352 struct mrvl_priv *priv = dev->data->dev_private;
353 struct mrvl_tm_shaper_profile *profile;
354
355 if (!params)
356 return -rte_tm_error_set(error, EINVAL,
357 RTE_TM_ERROR_TYPE_UNSPECIFIED,
358 NULL, NULL);
359
360 if (params->committed.rate)
361 return -rte_tm_error_set(error, EINVAL,
362 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE,
363 NULL, "Committed rate not supported\n");
364
365 if (params->committed.size)
366 return -rte_tm_error_set(error, EINVAL,
367 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE,
368 NULL, "Committed bucket size not supported\n");
369
370 if (params->peak.rate < MRVL_RATE_MIN ||
371 params->peak.rate > priv->rate_max)
372 return -rte_tm_error_set(error, EINVAL,
373 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
374 NULL, "Peak rate is out of range\n");
375
376 if (params->peak.size < MRVL_BURST_MIN ||
377 params->peak.size > MRVL_BURST_MAX)
378 return -rte_tm_error_set(error, EINVAL,
379 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE,
380 NULL, "Peak size is out of range\n");
381
382 if (shaper_profile_id == RTE_TM_SHAPER_PROFILE_ID_NONE)
383 return -rte_tm_error_set(error, EINVAL,
384 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
385 NULL, "Wrong shaper profile id\n");
386
387 profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
388 if (profile)
389 return -rte_tm_error_set(error, EEXIST,
390 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
391 NULL, "Profile id already exists\n");
392
393 profile = rte_zmalloc_socket(NULL, sizeof(*profile), 0,
394 rte_socket_id());
395 if (!profile)
396 return -rte_tm_error_set(error, ENOMEM,
397 RTE_TM_ERROR_TYPE_UNSPECIFIED,
398 NULL, NULL);
399
400 profile->id = shaper_profile_id;
401 rte_memcpy(&profile->params, params, sizeof(profile->params));
402
403 LIST_INSERT_HEAD(&priv->shaper_profiles, profile, next);
404
405 return 0;
406 }
407
408 /**
409 * Remove a shaper profile.
410 *
411 * @param dev Pointer to the device.
412 * @param shaper_profile_id Id of the shaper profile.
413 * @param error Pointer to the error.
414 * @returns 0 on success, negative value otherwise.
415 */
416 static int
417 mrvl_shaper_profile_delete(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
418 struct rte_tm_error *error)
419 {
420 struct mrvl_priv *priv = dev->data->dev_private;
421 struct mrvl_tm_shaper_profile *profile;
422
423 profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
424 if (!profile)
425 return -rte_tm_error_set(error, ENODEV,
426 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
427 NULL, "Profile id does not exist\n");
428
429 if (profile->refcnt)
430 return -rte_tm_error_set(error, EPERM,
431 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
432 NULL, "Profile is used\n");
433
434 LIST_REMOVE(profile, next);
435 rte_free(profile);
436
437 return 0;
438 }
439
440 /**
441 * Check node parameters.
442 *
443 * @param dev Pointer to the device.
444 * @param node_id Id used by the node.
445 * @param priority Priority value.
446 * @param weight Weight value.
447 * @param level_id Id of the level.
448 * @param params Pointer to the node parameters.
449 * @param error Pointer to the error.
450 * @returns 0 on success, negative value otherwise.
451 */
452 static int
453 mrvl_node_check_params(struct rte_eth_dev *dev, uint32_t node_id,
454 uint32_t priority, uint32_t weight, uint32_t level_id,
455 struct rte_tm_node_params *params,
456 struct rte_tm_error *error)
457 {
458 if (node_id == RTE_TM_NODE_ID_NULL)
459 return -rte_tm_error_set(error, EINVAL, RTE_TM_NODE_ID_NULL,
460 NULL, "Node id is invalid\n");
461
462 if (priority)
463 return -rte_tm_error_set(error, EINVAL,
464 RTE_TM_ERROR_TYPE_NODE_PRIORITY,
465 NULL, "Priority should be 0\n");
466
467 if (weight > MRVL_WEIGHT_MAX)
468 return -rte_tm_error_set(error, EINVAL,
469 RTE_TM_ERROR_TYPE_NODE_WEIGHT,
470 NULL, "Weight is out of range\n");
471
472 if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
473 return -rte_tm_error_set(error, EINVAL,
474 RTE_TM_ERROR_TYPE_LEVEL_ID,
475 NULL, "Wrong level id\n");
476
477 if (!params)
478 return -rte_tm_error_set(error, EINVAL,
479 RTE_TM_ERROR_TYPE_UNSPECIFIED,
480 NULL, NULL);
481
482 if (params->shared_shaper_id)
483 return -rte_tm_error_set(error, EINVAL,
484 RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID,
485 NULL, "Shared shaper is not supported\n");
486
487 if (params->n_shared_shapers)
488 return -rte_tm_error_set(error, EINVAL,
489 RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS,
490 NULL, "Shared shaper is not supported\n");
491
492 /* verify port (root node) settings */
493 if (node_id >= dev->data->nb_tx_queues) {
494 if (params->nonleaf.wfq_weight_mode)
495 return -rte_tm_error_set(error, EINVAL,
496 RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE,
497 NULL, "WFQ is not supported\n");
498
499 if (params->nonleaf.n_sp_priorities != 1)
500 return -rte_tm_error_set(error, EINVAL,
501 RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES,
502 NULL, "SP is not supported\n");
503
504 if (params->stats_mask & ~(RTE_TM_STATS_N_PKTS |
505 RTE_TM_STATS_N_BYTES))
506 return -rte_tm_error_set(error, EINVAL,
507 RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
508 NULL,
509 "Requested port stats are not supported\n");
510
511 return 0;
512 }
513
514 /* verify txq (leaf node) settings */
515 if (params->leaf.cman)
516 return -rte_tm_error_set(error, EINVAL,
517 RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN,
518 NULL,
519 "Congestion mngmt is not supported\n");
520
521 if (params->leaf.wred.wred_profile_id)
522 return -rte_tm_error_set(error, EINVAL,
523 RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID,
524 NULL, "WRED is not supported\n");
525
526 if (params->leaf.wred.shared_wred_context_id)
527 return -rte_tm_error_set(error, EINVAL,
528 RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID,
529 NULL, "WRED is not supported\n");
530
531 if (params->leaf.wred.n_shared_wred_contexts)
532 return -rte_tm_error_set(error, EINVAL,
533 RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS,
534 NULL, "WRED is not supported\n");
535
536 if (params->stats_mask & ~RTE_TM_STATS_N_PKTS)
537 return -rte_tm_error_set(error, EINVAL,
538 RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
539 NULL,
540 "Requested txq stats are not supported\n");
541
542 return 0;
543 }
544
545 /**
546 * Add a new node.
547 *
548 * @param dev Pointer to the device.
549 * @param node_id Id of the node.
550 * @param parent_node_id Id of the parent node.
551 * @param priority Priority value.
552 * @param weight Weight value.
553 * @param level_id Id of the level.
554 * @param params Pointer to the node parameters.
555 * @param error Pointer to the error.
556 * @returns 0 on success, negative value otherwise.
557 */
558 static int
559 mrvl_node_add(struct rte_eth_dev *dev, uint32_t node_id,
560 uint32_t parent_node_id, uint32_t priority, uint32_t weight,
561 uint32_t level_id, struct rte_tm_node_params *params,
562 struct rte_tm_error *error)
563 {
564 struct mrvl_priv *priv = dev->data->dev_private;
565 struct mrvl_tm_shaper_profile *profile = NULL;
566 struct mrvl_tm_node *node, *parent = NULL;
567 int ret;
568
569 if (priv->ppio)
570 return -rte_tm_error_set(error, EPERM,
571 RTE_TM_ERROR_TYPE_UNSPECIFIED,
572 NULL, "Port is already started\n");
573
574 ret = mrvl_node_check_params(dev, node_id, priority, weight, level_id,
575 params, error);
576 if (ret)
577 return ret;
578
579 if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE) {
580 profile = mrvl_shaper_profile_from_id(priv,
581 params->shaper_profile_id);
582 if (!profile)
583 return -rte_tm_error_set(error, ENODEV,
584 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
585 NULL, "Shaper id does not exist\n");
586 }
587
588 if (parent_node_id == RTE_TM_NODE_ID_NULL) {
589 LIST_FOREACH(node, &priv->nodes, next) {
590 if (node->type != MRVL_NODE_PORT)
591 continue;
592
593 return -rte_tm_error_set(error, EINVAL,
594 RTE_TM_ERROR_TYPE_UNSPECIFIED,
595 NULL, "Root node exists\n");
596 }
597 } else {
598 parent = mrvl_node_from_id(priv, parent_node_id);
599 if (!parent)
600 return -rte_tm_error_set(error, EINVAL,
601 RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
602 NULL, "Node id does not exist\n");
603 }
604
605 node = mrvl_node_from_id(priv, node_id);
606 if (node)
607 return -rte_tm_error_set(error, ENODEV,
608 RTE_TM_ERROR_TYPE_NODE_ID,
609 NULL, "Node id already exists\n");
610
611 node = rte_zmalloc_socket(NULL, sizeof(*node), 0, rte_socket_id());
612 if (!node)
613 return -rte_tm_error_set(error, ENOMEM,
614 RTE_TM_ERROR_TYPE_UNSPECIFIED,
615 NULL, NULL);
616
617 node->id = node_id;
618 node->type = parent_node_id == RTE_TM_NODE_ID_NULL ? MRVL_NODE_PORT :
619 MRVL_NODE_QUEUE;
620
621 if (parent) {
622 node->parent = parent;
623 parent->refcnt++;
624 }
625
626 if (profile) {
627 node->profile = profile;
628 profile->refcnt++;
629 }
630
631 node->weight = weight;
632 node->stats_mask = params->stats_mask;
633
634 LIST_INSERT_HEAD(&priv->nodes, node, next);
635
636 return 0;
637 }
638
639 /**
640 * Delete a node.
641 *
642 * @param dev Pointer to the device.
643 * @param node_id Id of the node.
644 * @param error Pointer to the error.
645 * @returns 0 on success, negative value otherwise.
646 */
647 static int
648 mrvl_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
649 struct rte_tm_error *error)
650 {
651 struct mrvl_priv *priv = dev->data->dev_private;
652 struct mrvl_tm_node *node;
653
654 if (priv->ppio) {
655 return -rte_tm_error_set(error, EPERM,
656 RTE_TM_ERROR_TYPE_UNSPECIFIED,
657 NULL, "Port is already started\n");
658 }
659
660 node = mrvl_node_from_id(priv, node_id);
661 if (!node)
662 return -rte_tm_error_set(error, ENODEV,
663 RTE_TM_ERROR_TYPE_NODE_ID,
664 NULL, "Node id does not exist\n");
665
666 if (node->refcnt)
667 return -rte_tm_error_set(error, EPERM,
668 RTE_TM_ERROR_TYPE_NODE_ID,
669 NULL, "Node id is used\n");
670
671 if (node->parent)
672 node->parent->refcnt--;
673
674 if (node->profile)
675 node->profile->refcnt--;
676
677 LIST_REMOVE(node, next);
678 rte_free(node);
679
680 return 0;
681 }
682
683 /**
684 * Helper for suspending specific tx queue.
685 *
686 * @param dev Pointer to the device.
687 * @param node_id Id used by this node.
688 * @returns 0 on success, negative value otherwise.
689 */
690 static int mrvl_node_suspend_one(struct rte_eth_dev *dev, uint32_t node_id,
691 struct rte_tm_error *error)
692 {
693 int ret = dev->dev_ops->tx_queue_stop(dev, node_id);
694 if (ret)
695 return -rte_tm_error_set(error, ret,
696 RTE_TM_ERROR_TYPE_UNSPECIFIED,
697 NULL, "Failed to suspend a txq\n");
698
699 return 0;
700 }
701
702 /**
703 * Suspend a node.
704 *
705 * @param dev Pointer to the device.
706 * @param node_id Id of the node.
707 * @param error Pointer to the error.
708 * returns 0 on success, negative value otherwise.
709 */
710 static int
711 mrvl_node_suspend(struct rte_eth_dev *dev, uint32_t node_id,
712 struct rte_tm_error *error)
713 {
714 struct mrvl_priv *priv = dev->data->dev_private;
715 struct mrvl_tm_node *node, *tmp;
716 int ret;
717
718 node = mrvl_node_from_id(priv, node_id);
719 if (!node)
720 return -rte_tm_error_set(error, ENODEV,
721 RTE_TM_ERROR_TYPE_NODE_ID,
722 NULL, "Node id does not exist\n");
723
724 if (!node->parent) {
725 LIST_FOREACH(tmp, &priv->nodes, next) {
726 if (!tmp->parent)
727 continue;
728
729 if (node != tmp->parent)
730 continue;
731
732 ret = mrvl_node_suspend_one(dev, tmp->id, error);
733 if (ret)
734 return ret;
735 }
736
737 return 0;
738 }
739
740 return mrvl_node_suspend_one(dev, node_id, error);
741 }
742
743 /**
744 * Resume a node.
745 *
746 * @param dev Pointer to the device.
747 * @param node_id Id of the node.
748 * @param error Pointer to the error.
749 * returns 0 on success, negative value otherwise.
750 */
751 static int
752 mrvl_node_resume(struct rte_eth_dev *dev, uint32_t node_id,
753 struct rte_tm_error *error)
754 {
755 struct mrvl_priv *priv = dev->data->dev_private;
756 struct mrvl_tm_node *node;
757 int ret;
758
759 node = mrvl_node_from_id(priv, node_id);
760 if (!node)
761 return -rte_tm_error_set(error, ENODEV,
762 RTE_TM_ERROR_TYPE_NODE_ID,
763 NULL, "Node id does not exist\n");
764
765
766 if (!node->parent)
767 return -rte_tm_error_set(error, EPERM,
768 RTE_TM_ERROR_TYPE_NODE_ID,
769 NULL, "Cannot suspend a port\n");
770
771 ret = dev->dev_ops->tx_queue_start(dev, node_id);
772 if (ret)
773 return -rte_tm_error_set(error, ret,
774 RTE_TM_ERROR_TYPE_UNSPECIFIED,
775 NULL, "Failed to resume a txq\n");
776 return 0;
777 }
778
779 /**
780 * Apply traffic manager hierarchy.
781 *
782 * @param dev Pointer to the device.
783 * @param clear_on_fail Flag indicating whether to do cleanup on the failure.
784 * @param error Pointer to the error.
785 * @returns 0 on success, negative value otherwise.
786 */
787 static int
788 mrvl_hierarchy_commit(struct rte_eth_dev *dev, int clear_on_fail,
789 struct rte_tm_error *error)
790 {
791 struct mrvl_priv *priv = dev->data->dev_private;
792 struct mrvl_tm_node *node;
793 int ret;
794
795 if (priv->ppio) {
796 ret = -rte_tm_error_set(error, EPERM,
797 RTE_TM_ERROR_TYPE_UNSPECIFIED,
798 NULL, "Port is already started\n");
799 goto out;
800 }
801
802 LIST_FOREACH(node, &priv->nodes, next) {
803 struct pp2_ppio_outq_params *p;
804
805 if (node->type == MRVL_NODE_PORT) {
806 if (!node->profile)
807 continue;
808
809 priv->ppio_params.rate_limit_enable = 1;
810 priv->ppio_params.rate_limit_params.cir =
811 node->profile->params.peak.rate * 8 / 1000;
812 priv->ppio_params.rate_limit_params.cbs =
813 node->profile->params.peak.size / 1000;
814
815 MRVL_LOG(INFO,
816 "Port rate limit overrides txqs rate limit");
817
818 continue;
819 }
820
821 if (node->id >= dev->data->nb_tx_queues) {
822 ret = -rte_tm_error_set(error, EINVAL,
823 RTE_TM_ERROR_TYPE_NODE_ID, NULL,
824 "Not enough txqs are configured\n");
825 goto out;
826 }
827
828 p = &priv->ppio_params.outqs_params.outqs_params[node->id];
829
830 if (node->weight) {
831 p->sched_mode = PP2_PPIO_SCHED_M_WRR;
832 p->weight = node->weight;
833 } else {
834 p->sched_mode = PP2_PPIO_SCHED_M_SP;
835 p->weight = 0;
836 }
837
838 if (node->profile) {
839 p->rate_limit_enable = 1;
840 /* convert Bytes/s to kilo bits/s */
841 p->rate_limit_params.cir =
842 node->profile->params.peak.rate * 8 / 1000;
843 /* convert bits to kilo bits */
844 p->rate_limit_params.cbs =
845 node->profile->params.peak.size / 1000;
846 } else {
847 p->rate_limit_enable = 0;
848 p->rate_limit_params.cir = 0;
849 p->rate_limit_params.cbs = 0;
850 }
851 }
852
853 /* reset to defaults in case applied tm hierarchy is empty */
854 if (LIST_EMPTY(&priv->nodes)) {
855 int i;
856
857 for (i = 0; i < priv->ppio_params.outqs_params.num_outqs; i++) {
858 struct pp2_ppio_outq_params *p =
859 &priv->ppio_params.outqs_params.outqs_params[i];
860
861 p->sched_mode = PP2_PPIO_SCHED_M_WRR;
862 p->weight = 0;
863 p->rate_limit_enable = 0;
864 p->rate_limit_params.cir = 0;
865 p->rate_limit_params.cbs = 0;
866 }
867 }
868
869 return 0;
870 out:
871 if (clear_on_fail) {
872 mrvl_tm_deinit(dev);
873 mrvl_tm_init(dev);
874 }
875
876 return ret;
877 }
878
879 /**
880 * Read statistics counters for current node.
881 *
882 * @param dev Pointer to the device.
883 * @param node_id Id of the node.
884 * @param stats Pointer to the statistics counters.
885 * @param stats_mask Pointer to mask of enabled statistics counters
886 * that are retrieved.
887 * @param clear Flag indicating whether to clear statistics.
888 * Non-zero value clears statistics.
889 * @param error Pointer to the error.
890 * @returns 0 on success, negative value otherwise.
891 */
892 static int
893 mrvl_node_stats_read(struct rte_eth_dev *dev, uint32_t node_id,
894 struct rte_tm_node_stats *stats, uint64_t *stats_mask,
895 int clear, struct rte_tm_error *error)
896 {
897 struct mrvl_priv *priv = dev->data->dev_private;
898 struct mrvl_tm_node *node;
899 int ret;
900
901 if (!priv->ppio) {
902 return -rte_tm_error_set(error, EPERM,
903 RTE_TM_ERROR_TYPE_UNSPECIFIED,
904 NULL, "Port is not started\n");
905 }
906
907 node = mrvl_node_from_id(priv, node_id);
908 if (!node)
909 return -rte_tm_error_set(error, ENODEV,
910 RTE_TM_ERROR_TYPE_NODE_ID,
911 NULL, "Node id does not exist\n");
912
913 if (stats_mask)
914 *stats_mask = node->stats_mask;
915
916 if (!stats)
917 return 0;
918
919 memset(stats, 0, sizeof(*stats));
920
921 if (!node->parent) {
922 struct pp2_ppio_statistics s;
923
924 memset(&s, 0, sizeof(s));
925 ret = pp2_ppio_get_statistics(priv->ppio, &s, clear);
926 if (ret)
927 return -rte_tm_error_set(error, -ret,
928 RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
929 "Failed to read port statistics\n");
930
931 if (node->stats_mask & RTE_TM_STATS_N_PKTS)
932 stats->n_pkts = s.tx_packets;
933
934 if (node->stats_mask & RTE_TM_STATS_N_BYTES)
935 stats->n_bytes = s.tx_bytes;
936 } else {
937 struct pp2_ppio_outq_statistics s;
938
939 memset(&s, 0, sizeof(s));
940 ret = pp2_ppio_outq_get_statistics(priv->ppio, node_id, &s,
941 clear);
942 if (ret)
943 return -rte_tm_error_set(error, -ret,
944 RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
945 "Failed to read txq statistics\n");
946
947 if (node->stats_mask & RTE_TM_STATS_N_PKTS)
948 stats->n_pkts = s.deq_desc;
949 }
950
951 return 0;
952 }
953
954 /**
955 * Update node statistics.
956 *
957 * @param dev Pointer to the device.
958 * @param node_id Id of the node.
959 * @param stats_mask Bitmask of statistics counters to be enabled.
960 * @param error Pointer to the error.
961 * @returns 0 on success, negative value otherwise.
962 */
963 static int
964 mrvl_node_stats_update(struct rte_eth_dev *dev, uint32_t node_id,
965 uint64_t stats_mask, struct rte_tm_error *error)
966 {
967 struct mrvl_priv *priv = dev->data->dev_private;
968 struct mrvl_tm_node *node;
969
970 node = mrvl_node_from_id(priv, node_id);
971 if (!node)
972 return -rte_tm_error_set(error, ENODEV,
973 RTE_TM_ERROR_TYPE_NODE_ID,
974 NULL, "Node id does not exist\n");
975
976 if (!node->parent) {
977 if (stats_mask & ~(RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES))
978 return -rte_tm_error_set(error, EINVAL,
979 RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
980 NULL,
981 "Requested port stats are not supported\n");
982 } else {
983 if (stats_mask & ~RTE_TM_STATS_N_PKTS)
984 return -rte_tm_error_set(error, EINVAL,
985 RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
986 NULL,
987 "Requested txq stats are not supported\n");
988 }
989
990 node->stats_mask = stats_mask;
991
992 return 0;
993 }
994
995 const struct rte_tm_ops mrvl_tm_ops = {
996 .node_type_get = mrvl_node_type_get,
997 .capabilities_get = mrvl_capabilities_get,
998 .level_capabilities_get = mrvl_level_capabilities_get,
999 .node_capabilities_get = mrvl_node_capabilities_get,
1000 .shaper_profile_add = mrvl_shaper_profile_add,
1001 .shaper_profile_delete = mrvl_shaper_profile_delete,
1002 .node_add = mrvl_node_add,
1003 .node_delete = mrvl_node_delete,
1004 .node_suspend = mrvl_node_suspend,
1005 .node_resume = mrvl_node_resume,
1006 .hierarchy_commit = mrvl_hierarchy_commit,
1007 .node_stats_update = mrvl_node_stats_update,
1008 .node_stats_read = mrvl_node_stats_read,
1009 };