New upstream version 18.11-rc1
[deb_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 = 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 };