ethdev: add namespace
[dpdk.git] / 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 = (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                         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                        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, 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 };