xref: /dpdk/drivers/net/mvpp2/mrvl_tm.c (revision 3953323852dfe399c0e6bdf2d35f88005b8a2135)
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 = (uint64_t)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 (!priv->configured)
150 		return -rte_tm_error_set(error, ENODEV,
151 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
152 					 NULL, "Port didn't configured\n");
153 
154 	if (!is_leaf)
155 		return -rte_tm_error_set(error, EINVAL,
156 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
157 					 NULL, NULL);
158 
159 	node = mrvl_node_from_id(priv, node_id);
160 	if (!node)
161 		return -rte_tm_error_set(error, ENODEV,
162 					 RTE_TM_ERROR_TYPE_NODE_ID,
163 					 NULL, "Node id does not exist\n");
164 
165 	*is_leaf = node->type == MRVL_NODE_QUEUE ? 1 : 0;
166 
167 	return 0;
168 }
169 
170 /**
171  * Get traffic manager capabilities.
172  *
173  * @param dev Pointer to the device (unused).
174  * @param cap Pointer to the capabilities.
175  * @param error Pointer to the error.
176  * @returns 0 on success, negative value otherwise.
177  */
178 static int
179 mrvl_capabilities_get(struct rte_eth_dev *dev,
180 		      struct rte_tm_capabilities *cap,
181 		      struct rte_tm_error *error)
182 {
183 	struct mrvl_priv *priv = dev->data->dev_private;
184 
185 	if (!priv->configured)
186 		return -rte_tm_error_set(error, ENODEV,
187 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
188 					 NULL, "Port didn't configured\n");
189 
190 	if (!cap)
191 		return -rte_tm_error_set(error, EINVAL,
192 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
193 					 NULL, "Capabilities are missing\n");
194 
195 	memset(cap, 0, sizeof(*cap));
196 
197 	cap->n_nodes_max = 1 + dev->data->nb_tx_queues; /* port + txqs number */
198 	cap->n_levels_max = 2; /* port level + txqs level */
199 	cap->non_leaf_nodes_identical = 1;
200 	cap->leaf_nodes_identical = 1;
201 
202 	cap->shaper_n_max = cap->n_nodes_max;
203 	cap->shaper_private_n_max = cap->shaper_n_max;
204 	cap->shaper_private_rate_min = MRVL_RATE_MIN;
205 	cap->shaper_private_rate_max = priv->rate_max;
206 	cap->shaper_private_packet_mode_supported = 0;
207 	cap->shaper_private_byte_mode_supported = 1;
208 
209 	cap->sched_n_children_max = dev->data->nb_tx_queues;
210 	cap->sched_sp_n_priorities_max = dev->data->nb_tx_queues;
211 	cap->sched_wfq_n_children_per_group_max = dev->data->nb_tx_queues;
212 	cap->sched_wfq_n_groups_max = 1;
213 	cap->sched_wfq_weight_max = MRVL_WEIGHT_MAX;
214 	cap->sched_wfq_packet_mode_supported = 0;
215 	cap->sched_wfq_byte_mode_supported = 1;
216 
217 	cap->dynamic_update_mask = RTE_TM_UPDATE_NODE_SUSPEND_RESUME |
218 				   RTE_TM_UPDATE_NODE_STATS;
219 	cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
220 
221 	return 0;
222 }
223 
224 /**
225  * Get traffic manager hierarchy level capabilities.
226  *
227  * @param dev Pointer to the device.
228  * @param level_id Id of the level.
229  * @param cap Pointer to the level capabilities.
230  * @param error Pointer to the error.
231  * @returns 0 on success, negative value otherwise.
232  */
233 static int
234 mrvl_level_capabilities_get(struct rte_eth_dev *dev,
235 			    uint32_t level_id,
236 			    struct rte_tm_level_capabilities *cap,
237 			    struct rte_tm_error *error)
238 {
239 	struct mrvl_priv *priv = dev->data->dev_private;
240 
241 	if (!priv->configured)
242 		return -rte_tm_error_set(error, ENODEV,
243 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
244 					 NULL, "Port didn't configured\n");
245 
246 	if (!cap)
247 		return -rte_tm_error_set(error, EINVAL,
248 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
249 					 NULL, NULL);
250 
251 	memset(cap, 0, sizeof(*cap));
252 
253 	if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
254 		return -rte_tm_error_set(error, EINVAL,
255 					 RTE_TM_ERROR_TYPE_LEVEL_ID,
256 					 NULL, "Wrong level id\n");
257 
258 	if (level_id == MRVL_NODE_PORT) {
259 		cap->n_nodes_max = 1;
260 		cap->n_nodes_nonleaf_max = 1;
261 		cap->non_leaf_nodes_identical = 1;
262 
263 		cap->nonleaf.shaper_private_supported = 1;
264 		cap->nonleaf.shaper_private_rate_min = MRVL_RATE_MIN;
265 		cap->nonleaf.shaper_private_rate_max = priv->rate_max;
266 		cap->nonleaf.shaper_private_packet_mode_supported = 0;
267 		cap->nonleaf.shaper_private_byte_mode_supported = 1;
268 
269 		cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
270 		cap->nonleaf.sched_sp_n_priorities_max = 1;
271 		cap->nonleaf.sched_wfq_n_children_per_group_max =
272 			dev->data->nb_tx_queues;
273 		cap->nonleaf.sched_wfq_n_groups_max = 1;
274 		cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
275 		cap->nonleaf.sched_wfq_packet_mode_supported = 0;
276 		cap->nonleaf.sched_wfq_byte_mode_supported = 1;
277 		cap->nonleaf.stats_mask = RTE_TM_STATS_N_PKTS |
278 					  RTE_TM_STATS_N_BYTES;
279 	} else { /* level_id == MRVL_NODE_QUEUE */
280 		cap->n_nodes_max = dev->data->nb_tx_queues;
281 		cap->n_nodes_leaf_max = dev->data->nb_tx_queues;
282 		cap->leaf_nodes_identical = 1;
283 
284 		cap->leaf.shaper_private_supported = 1;
285 		cap->leaf.shaper_private_rate_min = MRVL_RATE_MIN;
286 		cap->leaf.shaper_private_rate_max = priv->rate_max;
287 		cap->leaf.shaper_private_packet_mode_supported = 0;
288 		cap->leaf.shaper_private_byte_mode_supported = 1;
289 		cap->leaf.stats_mask = RTE_TM_STATS_N_PKTS;
290 	}
291 
292 	return 0;
293 }
294 
295 /**
296  * Get node capabilities.
297  *
298  * @param dev Pointer to the device.
299  * @param node_id Id of the node.
300  * @param cap Pointer to the capabilities.
301  * @param error Pointer to the error.
302  * @returns 0 on success, negative value otherwise.
303  */
304 static int
305 mrvl_node_capabilities_get(struct rte_eth_dev *dev, uint32_t node_id,
306 			   struct rte_tm_node_capabilities *cap,
307 			   struct rte_tm_error *error)
308 {
309 	struct mrvl_priv *priv = dev->data->dev_private;
310 	struct mrvl_tm_node *node;
311 
312 	if (!priv->configured)
313 		return -rte_tm_error_set(error, ENODEV,
314 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
315 					 NULL, "Port didn't configured\n");
316 
317 	if (!cap)
318 		return -rte_tm_error_set(error, EINVAL,
319 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
320 					 NULL, NULL);
321 
322 	memset(cap, 0, sizeof(*cap));
323 
324 	node = mrvl_node_from_id(priv, node_id);
325 	if (!node)
326 		return -rte_tm_error_set(error, ENODEV,
327 					 RTE_TM_ERROR_TYPE_NODE_ID,
328 					 NULL, "Node id does not exist\n");
329 
330 	cap->shaper_private_supported = 1;
331 	cap->shaper_private_rate_min = MRVL_RATE_MIN;
332 	cap->shaper_private_rate_max = priv->rate_max;
333 	cap->shaper_private_packet_mode_supported = 0;
334 	cap->shaper_private_byte_mode_supported = 1;
335 
336 	if (node->type == MRVL_NODE_PORT) {
337 		cap->nonleaf.sched_n_children_max = dev->data->nb_tx_queues;
338 		cap->nonleaf.sched_sp_n_priorities_max = 1;
339 		cap->nonleaf.sched_wfq_n_children_per_group_max =
340 			dev->data->nb_tx_queues;
341 		cap->nonleaf.sched_wfq_n_groups_max = 1;
342 		cap->nonleaf.sched_wfq_weight_max = MRVL_WEIGHT_MAX;
343 		cap->nonleaf.sched_wfq_packet_mode_supported = 0;
344 		cap->nonleaf.sched_wfq_byte_mode_supported = 1;
345 		cap->stats_mask = RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES;
346 	} else {
347 		cap->stats_mask = RTE_TM_STATS_N_PKTS;
348 	}
349 
350 	return 0;
351 }
352 
353 /**
354  * Get shaper profile using its id.
355  *
356  * @param priv Pointer to the port's private data.
357  * @param shaper_profile_id Id used by the shaper.
358  * @returns Pointer to the shaper profile if exists, NULL otherwise.
359  */
360 static struct mrvl_tm_shaper_profile *
361 mrvl_shaper_profile_from_id(struct mrvl_priv *priv, uint32_t shaper_profile_id)
362 {
363 	struct mrvl_tm_shaper_profile *profile;
364 
365 	LIST_FOREACH(profile, &priv->shaper_profiles, next)
366 		if (profile->id == shaper_profile_id)
367 			return profile;
368 
369 	return NULL;
370 }
371 
372 /**
373  * Add a new shaper profile.
374  *
375  * @param dev Pointer to the device.
376  * @param shaper_profile_id Id of the new profile.
377  * @param params Pointer to the shaper profile parameters.
378  * @param error Pointer to the error.
379  * @returns 0 on success, negative value otherwise.
380  */
381 static int
382 mrvl_shaper_profile_add(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
383 			const struct rte_tm_shaper_params *params,
384 			struct rte_tm_error *error)
385 {
386 	struct mrvl_priv *priv = dev->data->dev_private;
387 	struct mrvl_tm_shaper_profile *profile;
388 
389 	if (!priv->configured)
390 		return -rte_tm_error_set(error, ENODEV,
391 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
392 					 NULL, "Port didn't configured\n");
393 
394 	if (!params)
395 		return -rte_tm_error_set(error, EINVAL,
396 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
397 					 NULL, NULL);
398 
399 	if (params->committed.rate)
400 		return -rte_tm_error_set(error, EINVAL,
401 				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE,
402 				NULL, "Committed rate not supported\n");
403 
404 	if (params->committed.size)
405 		return -rte_tm_error_set(error, EINVAL,
406 				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE,
407 				NULL, "Committed bucket size not supported\n");
408 
409 	if (params->peak.rate < MRVL_RATE_MIN ||
410 	    params->peak.rate > priv->rate_max)
411 		return -rte_tm_error_set(error, EINVAL,
412 				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE,
413 				NULL, "Peak rate is out of range\n");
414 
415 	if (params->peak.size < MRVL_BURST_MIN ||
416 	    params->peak.size > MRVL_BURST_MAX)
417 		return -rte_tm_error_set(error, EINVAL,
418 				RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE,
419 				NULL, "Peak size is out of range\n");
420 
421 	if (shaper_profile_id == RTE_TM_SHAPER_PROFILE_ID_NONE)
422 		return -rte_tm_error_set(error, EINVAL,
423 					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
424 					 NULL, "Wrong shaper profile id\n");
425 
426 	profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
427 	if (profile)
428 		return -rte_tm_error_set(error, EEXIST,
429 					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
430 					 NULL, "Profile id already exists\n");
431 
432 	profile = rte_zmalloc_socket(NULL, sizeof(*profile), 0,
433 				     rte_socket_id());
434 	if (!profile)
435 		return -rte_tm_error_set(error, ENOMEM,
436 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
437 					 NULL, NULL);
438 
439 	profile->id = shaper_profile_id;
440 	rte_memcpy(&profile->params, params, sizeof(profile->params));
441 
442 	LIST_INSERT_HEAD(&priv->shaper_profiles, profile, next);
443 
444 	return 0;
445 }
446 
447 /**
448  * Remove a shaper profile.
449  *
450  * @param dev Pointer to the device.
451  * @param shaper_profile_id Id of the shaper profile.
452  * @param error Pointer to the error.
453  * @returns 0 on success, negative value otherwise.
454  */
455 static int
456 mrvl_shaper_profile_delete(struct rte_eth_dev *dev, uint32_t shaper_profile_id,
457 			   struct rte_tm_error *error)
458 {
459 	struct mrvl_priv *priv = dev->data->dev_private;
460 	struct mrvl_tm_shaper_profile *profile;
461 
462 	if (!priv->configured)
463 		return -rte_tm_error_set(error, ENODEV,
464 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
465 					 NULL, "Port didn't configured\n");
466 
467 	profile = mrvl_shaper_profile_from_id(priv, shaper_profile_id);
468 	if (!profile)
469 		return -rte_tm_error_set(error, ENODEV,
470 					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
471 					 NULL, "Profile id does not exist\n");
472 
473 	if (profile->refcnt)
474 		return -rte_tm_error_set(error, EPERM,
475 					 RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
476 					 NULL, "Profile is used\n");
477 
478 	LIST_REMOVE(profile, next);
479 	rte_free(profile);
480 
481 	return 0;
482 }
483 
484 /**
485  * Check node parameters.
486  *
487  * @param dev Pointer to the device.
488  * @param node_id Id used by the node.
489  * @param priority Priority value.
490  * @param weight Weight value.
491  * @param level_id Id of the level.
492  * @param params Pointer to the node parameters.
493  * @param error Pointer to the error.
494  * @returns 0 on success, negative value otherwise.
495  */
496 static int
497 mrvl_node_check_params(struct rte_eth_dev *dev, uint32_t node_id,
498 		       uint32_t priority, uint32_t weight, uint32_t level_id,
499 		       const struct rte_tm_node_params *params,
500 		       struct rte_tm_error *error)
501 {
502 	if (node_id == RTE_TM_NODE_ID_NULL)
503 		return -rte_tm_error_set(error, EINVAL, RTE_TM_NODE_ID_NULL,
504 					 NULL, "Node id is invalid\n");
505 
506 	if (priority)
507 		return -rte_tm_error_set(error, EINVAL,
508 					 RTE_TM_ERROR_TYPE_NODE_PRIORITY,
509 					 NULL, "Priority should be 0\n");
510 
511 	if (weight > MRVL_WEIGHT_MAX)
512 		return -rte_tm_error_set(error, EINVAL,
513 					 RTE_TM_ERROR_TYPE_NODE_WEIGHT,
514 					 NULL, "Weight is out of range\n");
515 
516 	if (level_id != MRVL_NODE_PORT && level_id != MRVL_NODE_QUEUE)
517 		return -rte_tm_error_set(error, EINVAL,
518 					 RTE_TM_ERROR_TYPE_LEVEL_ID,
519 					 NULL, "Wrong level id\n");
520 
521 	if (!params)
522 		return -rte_tm_error_set(error, EINVAL,
523 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
524 					 NULL, NULL);
525 
526 	if (params->shared_shaper_id)
527 		return -rte_tm_error_set(error, EINVAL,
528 				RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID,
529 				NULL, "Shared shaper is not supported\n");
530 
531 	if (params->n_shared_shapers)
532 		return -rte_tm_error_set(error, EINVAL,
533 				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS,
534 				NULL, "Shared shaper is not supported\n");
535 
536 	/* verify port (root node) settings */
537 	if (node_id >= dev->data->nb_tx_queues) {
538 		if (params->nonleaf.wfq_weight_mode)
539 			return -rte_tm_error_set(error, EINVAL,
540 				RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE,
541 				NULL, "WFQ is not supported\n");
542 
543 		if (params->nonleaf.n_sp_priorities != 1)
544 			return -rte_tm_error_set(error, EINVAL,
545 				RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES,
546 				NULL, "SP is not supported\n");
547 
548 		if (params->stats_mask & ~(RTE_TM_STATS_N_PKTS |
549 					   RTE_TM_STATS_N_BYTES))
550 			return -rte_tm_error_set(error, EINVAL,
551 				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
552 				NULL,
553 				"Requested port stats are not supported\n");
554 
555 		return 0;
556 	}
557 
558 	/* verify txq (leaf node) settings */
559 	if (params->leaf.cman)
560 		return -rte_tm_error_set(error, EINVAL,
561 					 RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN,
562 					 NULL,
563 					 "Congestion mngmt is not supported\n");
564 
565 	if (params->leaf.wred.wred_profile_id)
566 		return -rte_tm_error_set(error, EINVAL,
567 				RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID,
568 				NULL, "WRED is not supported\n");
569 
570 	if (params->leaf.wred.shared_wred_context_id)
571 		return -rte_tm_error_set(error, EINVAL,
572 			RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID,
573 			NULL, "WRED is not supported\n");
574 
575 	if (params->leaf.wred.n_shared_wred_contexts)
576 		return -rte_tm_error_set(error, EINVAL,
577 			RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS,
578 			NULL, "WRED is not supported\n");
579 
580 	if (params->stats_mask & ~RTE_TM_STATS_N_PKTS)
581 		return -rte_tm_error_set(error, EINVAL,
582 			RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
583 			NULL,
584 			"Requested txq stats are not supported\n");
585 
586 	return 0;
587 }
588 
589 /**
590  * Add a new node.
591  *
592  * @param dev Pointer to the device.
593  * @param node_id Id of the node.
594  * @param parent_node_id Id of the parent node.
595  * @param priority Priority value.
596  * @param weight Weight value.
597  * @param level_id Id of the level.
598  * @param params Pointer to the node parameters.
599  * @param error Pointer to the error.
600  * @returns 0 on success, negative value otherwise.
601  */
602 static int
603 mrvl_node_add(struct rte_eth_dev *dev, uint32_t node_id,
604 	      uint32_t parent_node_id, uint32_t priority, uint32_t weight,
605 	      uint32_t level_id, const struct rte_tm_node_params *params,
606 	      struct rte_tm_error *error)
607 {
608 	struct mrvl_priv *priv = dev->data->dev_private;
609 	struct mrvl_tm_shaper_profile *profile = NULL;
610 	struct mrvl_tm_node *node, *parent = NULL;
611 	int ret;
612 
613 	if (!priv->configured)
614 		return -rte_tm_error_set(error, ENODEV,
615 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
616 					 NULL, "Port didn't configured\n");
617 
618 	if (priv->ppio)
619 		return -rte_tm_error_set(error, EPERM,
620 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
621 					 NULL, "Port is already started\n");
622 
623 	ret = mrvl_node_check_params(dev, node_id, priority, weight, level_id,
624 				     params, error);
625 	if (ret)
626 		return ret;
627 
628 	if (params->shaper_profile_id != RTE_TM_SHAPER_PROFILE_ID_NONE) {
629 		profile = mrvl_shaper_profile_from_id(priv,
630 						 params->shaper_profile_id);
631 		if (!profile)
632 			return -rte_tm_error_set(error, ENODEV,
633 					RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID,
634 					NULL, "Shaper id does not exist\n");
635 	}
636 
637 	if (parent_node_id == RTE_TM_NODE_ID_NULL) {
638 		LIST_FOREACH(node, &priv->nodes, next) {
639 			if (node->type != MRVL_NODE_PORT)
640 				continue;
641 
642 			return -rte_tm_error_set(error, EINVAL,
643 						 RTE_TM_ERROR_TYPE_UNSPECIFIED,
644 						 NULL, "Root node exists\n");
645 		}
646 	} else {
647 		parent = mrvl_node_from_id(priv, parent_node_id);
648 		if (!parent)
649 			return -rte_tm_error_set(error, EINVAL,
650 					RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID,
651 					NULL, "Node id does not exist\n");
652 	}
653 
654 	node = mrvl_node_from_id(priv, node_id);
655 	if (node)
656 		return -rte_tm_error_set(error, ENODEV,
657 					 RTE_TM_ERROR_TYPE_NODE_ID,
658 					 NULL, "Node id already exists\n");
659 
660 	node = rte_zmalloc_socket(NULL, sizeof(*node), 0, rte_socket_id());
661 	if (!node)
662 		return -rte_tm_error_set(error, ENOMEM,
663 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
664 					 NULL, NULL);
665 
666 	node->id = node_id;
667 	node->type = parent_node_id == RTE_TM_NODE_ID_NULL ? MRVL_NODE_PORT :
668 							     MRVL_NODE_QUEUE;
669 
670 	if (parent) {
671 		node->parent = parent;
672 		parent->refcnt++;
673 	}
674 
675 	if (profile) {
676 		node->profile = profile;
677 		profile->refcnt++;
678 	}
679 
680 	node->weight = weight;
681 	node->stats_mask = params->stats_mask;
682 
683 	LIST_INSERT_HEAD(&priv->nodes, node, next);
684 
685 	return 0;
686 }
687 
688 /**
689  * Delete a node.
690  *
691  * @param dev Pointer to the device.
692  * @param node_id Id of the node.
693  * @param error Pointer to the error.
694  * @returns 0 on success, negative value otherwise.
695  */
696 static int
697 mrvl_node_delete(struct rte_eth_dev *dev, uint32_t node_id,
698 		 struct rte_tm_error *error)
699 {
700 	struct mrvl_priv *priv = dev->data->dev_private;
701 	struct mrvl_tm_node *node;
702 
703 	if (!priv->configured)
704 		return -rte_tm_error_set(error, ENODEV,
705 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
706 					 NULL, "Port didn't configured\n");
707 
708 	if (priv->ppio) {
709 		return -rte_tm_error_set(error, EPERM,
710 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
711 					 NULL, "Port is already started\n");
712 	}
713 
714 	node = mrvl_node_from_id(priv, node_id);
715 	if (!node)
716 		return -rte_tm_error_set(error, ENODEV,
717 					 RTE_TM_ERROR_TYPE_NODE_ID,
718 					 NULL, "Node id does not exist\n");
719 
720 	if (node->refcnt)
721 		return -rte_tm_error_set(error, EPERM,
722 					 RTE_TM_ERROR_TYPE_NODE_ID,
723 					 NULL, "Node id is used\n");
724 
725 	if (node->parent)
726 		node->parent->refcnt--;
727 
728 	if (node->profile)
729 		node->profile->refcnt--;
730 
731 	LIST_REMOVE(node, next);
732 	rte_free(node);
733 
734 	return 0;
735 }
736 
737 /**
738  * Helper for suspending specific tx queue.
739  *
740  * @param dev Pointer to the device.
741  * @param node_id Id used by this node.
742  * @returns 0 on success, negative value otherwise.
743  */
744 static int mrvl_node_suspend_one(struct rte_eth_dev *dev, uint32_t node_id,
745 				 struct rte_tm_error *error)
746 {
747 	int ret = dev->dev_ops->tx_queue_stop(dev, node_id);
748 	if (ret)
749 		return -rte_tm_error_set(error, ret,
750 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
751 					 NULL, "Failed to suspend a txq\n");
752 
753 	return 0;
754 }
755 
756 /**
757  * Suspend a node.
758  *
759  * @param dev Pointer to the device.
760  * @param node_id Id of the node.
761  * @param error Pointer to the error.
762  * returns 0 on success, negative value otherwise.
763  */
764 static int
765 mrvl_node_suspend(struct rte_eth_dev *dev, uint32_t node_id,
766 		  struct rte_tm_error *error)
767 {
768 	struct mrvl_priv *priv = dev->data->dev_private;
769 	struct mrvl_tm_node *node, *tmp;
770 	int ret;
771 
772 	if (!priv->configured)
773 		return -rte_tm_error_set(error, ENODEV,
774 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
775 					 NULL, "Port didn't configured\n");
776 
777 	node = mrvl_node_from_id(priv, node_id);
778 	if (!node)
779 		return -rte_tm_error_set(error, ENODEV,
780 					 RTE_TM_ERROR_TYPE_NODE_ID,
781 					 NULL, "Node id does not exist\n");
782 
783 	if (!node->parent) {
784 		LIST_FOREACH(tmp, &priv->nodes, next) {
785 			if (!tmp->parent)
786 				continue;
787 
788 			if (node != tmp->parent)
789 				continue;
790 
791 			ret = mrvl_node_suspend_one(dev, tmp->id, error);
792 			if (ret)
793 				return ret;
794 		}
795 
796 		return 0;
797 	}
798 
799 	return mrvl_node_suspend_one(dev, node_id, error);
800 }
801 
802 /**
803  * Resume a node.
804  *
805  * @param dev Pointer to the device.
806  * @param node_id Id of the node.
807  * @param error Pointer to the error.
808  * returns 0 on success, negative value otherwise.
809  */
810 static int
811 mrvl_node_resume(struct rte_eth_dev *dev, uint32_t node_id,
812 		 struct rte_tm_error *error)
813 {
814 	struct mrvl_priv *priv = dev->data->dev_private;
815 	struct mrvl_tm_node *node;
816 	int ret;
817 
818 	if (!priv->configured)
819 		return -rte_tm_error_set(error, ENODEV,
820 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
821 					 NULL, "Port didn't configured\n");
822 
823 	node = mrvl_node_from_id(priv, node_id);
824 	if (!node)
825 		return -rte_tm_error_set(error, ENODEV,
826 					 RTE_TM_ERROR_TYPE_NODE_ID,
827 					 NULL, "Node id does not exist\n");
828 
829 
830 	if (!node->parent)
831 		return -rte_tm_error_set(error, EPERM,
832 					 RTE_TM_ERROR_TYPE_NODE_ID,
833 					 NULL, "Cannot suspend a port\n");
834 
835 	ret = dev->dev_ops->tx_queue_start(dev, node_id);
836 	if (ret)
837 		return -rte_tm_error_set(error, ret,
838 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
839 					 NULL, "Failed to resume a txq\n");
840 	return 0;
841 }
842 
843 /**
844  * Apply traffic manager hierarchy.
845  *
846  * @param dev Pointer to the device.
847  * @param clear_on_fail Flag indicating whether to do cleanup on the failure.
848  * @param error Pointer to the error.
849  * @returns 0 on success, negative value otherwise.
850  */
851 static int
852 mrvl_hierarchy_commit(struct rte_eth_dev *dev, int clear_on_fail,
853 		      struct rte_tm_error *error)
854 {
855 	struct mrvl_priv *priv = dev->data->dev_private;
856 	struct mrvl_tm_node *node;
857 	int ret;
858 
859 	if (!priv->configured)
860 		return -rte_tm_error_set(error, ENODEV,
861 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
862 					 NULL, "Port didn't configured\n");
863 
864 	if (priv->ppio) {
865 		ret = -rte_tm_error_set(error, EPERM,
866 					RTE_TM_ERROR_TYPE_UNSPECIFIED,
867 					NULL, "Port is already started\n");
868 		goto out;
869 	}
870 
871 	LIST_FOREACH(node, &priv->nodes, next) {
872 		struct pp2_ppio_outq_params *p;
873 
874 		if (node->type == MRVL_NODE_PORT) {
875 			if (!node->profile)
876 				continue;
877 
878 			priv->ppio_params.rate_limit_enable = 1;
879 			priv->ppio_params.rate_limit_params.cir =
880 				node->profile->params.peak.rate * 8 / 1000;
881 			priv->ppio_params.rate_limit_params.cbs =
882 				node->profile->params.peak.size / 1000;
883 
884 			MRVL_LOG(INFO,
885 				"Port rate limit overrides txqs rate limit");
886 
887 			continue;
888 		}
889 
890 		if (node->id >= dev->data->nb_tx_queues) {
891 			ret = -rte_tm_error_set(error, EINVAL,
892 					RTE_TM_ERROR_TYPE_NODE_ID, NULL,
893 					"Not enough txqs are configured\n");
894 			goto out;
895 		}
896 
897 		p = &priv->ppio_params.outqs_params.outqs_params[node->id];
898 
899 		if (node->weight) {
900 			p->sched_mode = PP2_PPIO_SCHED_M_WRR;
901 			p->weight = node->weight;
902 		} else {
903 			p->sched_mode = PP2_PPIO_SCHED_M_SP;
904 			p->weight = 0;
905 		}
906 
907 		if (node->profile) {
908 			p->rate_limit_enable = 1;
909 			/* convert Bytes/s to kilo bits/s */
910 			p->rate_limit_params.cir =
911 				node->profile->params.peak.rate * 8 / 1000;
912 			/* convert bits to kilo bits */
913 			p->rate_limit_params.cbs =
914 				node->profile->params.peak.size / 1000;
915 		} else {
916 			p->rate_limit_enable = 0;
917 			p->rate_limit_params.cir = 0;
918 			p->rate_limit_params.cbs = 0;
919 		}
920 	}
921 
922 	/* reset to defaults in case applied tm hierarchy is empty */
923 	if (LIST_EMPTY(&priv->nodes)) {
924 		int i;
925 
926 		for (i = 0; i < priv->ppio_params.outqs_params.num_outqs; i++) {
927 			struct pp2_ppio_outq_params *p =
928 				&priv->ppio_params.outqs_params.outqs_params[i];
929 
930 			p->sched_mode = PP2_PPIO_SCHED_M_WRR;
931 			p->weight = 0;
932 			p->rate_limit_enable = 0;
933 			p->rate_limit_params.cir = 0;
934 			p->rate_limit_params.cbs = 0;
935 		}
936 	}
937 
938 	return 0;
939 out:
940 	if (clear_on_fail) {
941 		mrvl_tm_deinit(dev);
942 		mrvl_tm_init(dev);
943 	}
944 
945 	return ret;
946 }
947 
948 /**
949  * Read statistics counters for current node.
950  *
951  * @param dev Pointer to the device.
952  * @param node_id Id of the node.
953  * @param stats Pointer to the statistics counters.
954  * @param stats_mask Pointer to mask of enabled statistics counters
955  *                   that are retrieved.
956  * @param clear Flag indicating whether to clear statistics.
957  *              Non-zero value clears statistics.
958  * @param error Pointer to the error.
959  * @returns 0 on success, negative value otherwise.
960  */
961 static int
962 mrvl_node_stats_read(struct rte_eth_dev *dev, uint32_t node_id,
963 		     struct rte_tm_node_stats *stats, uint64_t *stats_mask,
964 		     int clear, struct rte_tm_error *error)
965 {
966 	struct mrvl_priv *priv = dev->data->dev_private;
967 	struct mrvl_tm_node *node;
968 	int ret;
969 
970 	if (!priv->configured)
971 		return -rte_tm_error_set(error, ENODEV,
972 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
973 					 NULL, "Port didn't configured\n");
974 
975 	if (!priv->ppio) {
976 		return -rte_tm_error_set(error, EPERM,
977 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
978 					 NULL, "Port is not started\n");
979 	}
980 
981 	node = mrvl_node_from_id(priv, node_id);
982 	if (!node)
983 		return -rte_tm_error_set(error, ENODEV,
984 					 RTE_TM_ERROR_TYPE_NODE_ID,
985 					 NULL, "Node id does not exist\n");
986 
987 	if (stats_mask)
988 		*stats_mask = node->stats_mask;
989 
990 	if (!stats)
991 		return 0;
992 
993 	memset(stats, 0, sizeof(*stats));
994 
995 	if (!node->parent) {
996 		struct pp2_ppio_statistics s;
997 
998 		memset(&s, 0, sizeof(s));
999 		ret = pp2_ppio_get_statistics(priv->ppio, &s, clear);
1000 		if (ret)
1001 			return -rte_tm_error_set(error, -ret,
1002 					RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
1003 					"Failed to read port statistics\n");
1004 
1005 		if (node->stats_mask & RTE_TM_STATS_N_PKTS)
1006 			stats->n_pkts = s.tx_packets;
1007 
1008 		if (node->stats_mask & RTE_TM_STATS_N_BYTES)
1009 			stats->n_bytes = s.tx_bytes;
1010 	} else {
1011 		struct pp2_ppio_outq_statistics s;
1012 
1013 		memset(&s, 0, sizeof(s));
1014 		ret = pp2_ppio_outq_get_statistics(priv->ppio, node_id, &s,
1015 						   clear);
1016 		if (ret)
1017 			return -rte_tm_error_set(error, -ret,
1018 					RTE_TM_ERROR_TYPE_UNSPECIFIED, NULL,
1019 					"Failed to read txq statistics\n");
1020 
1021 		if (node->stats_mask & RTE_TM_STATS_N_PKTS)
1022 			stats->n_pkts = s.deq_desc;
1023 	}
1024 
1025 	return 0;
1026 }
1027 
1028 /**
1029  * Update node statistics.
1030  *
1031  * @param dev Pointer to the device.
1032  * @param node_id Id of the node.
1033  * @param stats_mask Bitmask of statistics counters to be enabled.
1034  * @param error Pointer to the error.
1035  * @returns 0 on success, negative value otherwise.
1036  */
1037 static int
1038 mrvl_node_stats_update(struct rte_eth_dev *dev, uint32_t node_id,
1039 		       uint64_t stats_mask, struct rte_tm_error *error)
1040 {
1041 	struct mrvl_priv *priv = dev->data->dev_private;
1042 	struct mrvl_tm_node *node;
1043 
1044 	if (!priv->configured)
1045 		return -rte_tm_error_set(error, ENODEV,
1046 					 RTE_TM_ERROR_TYPE_UNSPECIFIED,
1047 					 NULL, "Port didn't configured\n");
1048 
1049 	node = mrvl_node_from_id(priv, node_id);
1050 	if (!node)
1051 		return -rte_tm_error_set(error, ENODEV,
1052 					 RTE_TM_ERROR_TYPE_NODE_ID,
1053 					 NULL, "Node id does not exist\n");
1054 
1055 	if (!node->parent) {
1056 		if (stats_mask & ~(RTE_TM_STATS_N_PKTS | RTE_TM_STATS_N_BYTES))
1057 			return -rte_tm_error_set(error, EINVAL,
1058 				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
1059 				NULL,
1060 				"Requested port stats are not supported\n");
1061 	} else {
1062 		if (stats_mask & ~RTE_TM_STATS_N_PKTS)
1063 			return -rte_tm_error_set(error, EINVAL,
1064 				RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS,
1065 				NULL,
1066 				"Requested txq stats are not supported\n");
1067 	}
1068 
1069 	node->stats_mask = stats_mask;
1070 
1071 	return 0;
1072 }
1073 
1074 const struct rte_tm_ops mrvl_tm_ops = {
1075 	.node_type_get = mrvl_node_type_get,
1076 	.capabilities_get = mrvl_capabilities_get,
1077 	.level_capabilities_get = mrvl_level_capabilities_get,
1078 	.node_capabilities_get = mrvl_node_capabilities_get,
1079 	.shaper_profile_add = mrvl_shaper_profile_add,
1080 	.shaper_profile_delete = mrvl_shaper_profile_delete,
1081 	.node_add = mrvl_node_add,
1082 	.node_delete = mrvl_node_delete,
1083 	.node_suspend = mrvl_node_suspend,
1084 	.node_resume = mrvl_node_resume,
1085 	.hierarchy_commit = mrvl_hierarchy_commit,
1086 	.node_stats_update = mrvl_node_stats_update,
1087 	.node_stats_read = mrvl_node_stats_read,
1088 };
1089