net/mvpp2: change default policer configuration
[dpdk.git] / drivers / net / mvpp2 / mrvl_qos.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Marvell International Ltd.
3  * Copyright(c) 2017 Semihalf.
4  * All rights reserved.
5  */
6
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include <rte_common.h>
12 #include <rte_cfgfile.h>
13 #include <rte_log.h>
14 #include <rte_lcore.h>
15 #include <rte_malloc.h>
16 #include <rte_string_fns.h>
17
18 #include "mrvl_qos.h"
19
20 /* Parsing tokens. Defined conveniently, so that any correction is easy. */
21 #define MRVL_TOK_DEFAULT "default"
22 #define MRVL_TOK_DEFAULT_TC "default_tc"
23 #define MRVL_TOK_DSCP "dscp"
24 #define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
25 #define MRVL_TOK_IP "ip"
26 #define MRVL_TOK_IP_VLAN "ip/vlan"
27 #define MRVL_TOK_PCP "pcp"
28 #define MRVL_TOK_PORT "port"
29 #define MRVL_TOK_RXQ "rxq"
30 #define MRVL_TOK_TC "tc"
31 #define MRVL_TOK_TXQ "txq"
32 #define MRVL_TOK_VLAN "vlan"
33 #define MRVL_TOK_VLAN_IP "vlan/ip"
34
35 /* egress specific configuration tokens */
36 #define MRVL_TOK_BURST_SIZE "burst_size"
37 #define MRVL_TOK_RATE_LIMIT "rate_limit"
38 #define MRVL_TOK_RATE_LIMIT_ENABLE "rate_limit_enable"
39 #define MRVL_TOK_SCHED_MODE "sched_mode"
40 #define MRVL_TOK_SCHED_MODE_SP "sp"
41 #define MRVL_TOK_SCHED_MODE_WRR "wrr"
42 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
43
44 /* policer specific configuration tokens */
45 #define MRVL_TOK_PLCR "policer"
46 #define MRVL_TOK_PLCR_DEFAULT "default_policer"
47 #define MRVL_TOK_PLCR_UNIT "token_unit"
48 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
49 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
50 #define MRVL_TOK_PLCR_COLOR "color_mode"
51 #define MRVL_TOK_PLCR_COLOR_BLIND "blind"
52 #define MRVL_TOK_PLCR_COLOR_AWARE "aware"
53 #define MRVL_TOK_PLCR_CIR "cir"
54 #define MRVL_TOK_PLCR_CBS "cbs"
55 #define MRVL_TOK_PLCR_EBS "ebs"
56 #define MRVL_TOK_PLCR_DEFAULT_COLOR "default_color"
57 #define MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN "green"
58 #define MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW "yellow"
59 #define MRVL_TOK_PLCR_DEFAULT_COLOR_RED "red"
60
61 /** Number of tokens in range a-b = 2. */
62 #define MAX_RNG_TOKENS 2
63
64 /** Maximum possible value of PCP. */
65 #define MAX_PCP 7
66
67 /** Maximum possible value of DSCP. */
68 #define MAX_DSCP 63
69
70 /** Global QoS configuration. */
71 struct mrvl_qos_cfg *mrvl_qos_cfg;
72
73 /**
74  * Convert string to uint32_t with extra checks for result correctness.
75  *
76  * @param string String to convert.
77  * @param val Conversion result.
78  * @returns 0 in case of success, negative value otherwise.
79  */
80 static int
81 get_val_securely(const char *string, uint32_t *val)
82 {
83         char *endptr;
84         size_t len = strlen(string);
85
86         if (len == 0)
87                 return -1;
88
89         errno = 0;
90         *val = strtoul(string, &endptr, 0);
91         if (errno != 0 || RTE_PTR_DIFF(endptr, string) != len)
92                 return -2;
93
94         return 0;
95 }
96
97 /**
98  * Read out-queue configuration from file.
99  *
100  * @param file Path to the configuration file.
101  * @param port Port number.
102  * @param outq Out queue number.
103  * @param cfg Pointer to the Marvell QoS configuration structure.
104  * @returns 0 in case of success, negative value otherwise.
105  */
106 static int
107 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
108                 struct mrvl_qos_cfg *cfg)
109 {
110         char sec_name[32];
111         const char *entry;
112         uint32_t val;
113
114         snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
115                 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
116
117         /* Skip non-existing */
118         if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
119                 return 0;
120
121         /* Read scheduling mode */
122         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE);
123         if (entry) {
124                 if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP,
125                                         strlen(MRVL_TOK_SCHED_MODE_SP))) {
126                         cfg->port[port].outq[outq].sched_mode =
127                                 PP2_PPIO_SCHED_M_SP;
128                 } else if (!strncmp(entry, MRVL_TOK_SCHED_MODE_WRR,
129                                         strlen(MRVL_TOK_SCHED_MODE_WRR))) {
130                         cfg->port[port].outq[outq].sched_mode =
131                                 PP2_PPIO_SCHED_M_WRR;
132                 } else {
133                         MRVL_LOG(ERR, "Unknown token: %s", entry);
134                         return -1;
135                 }
136         }
137
138         /* Read wrr weight */
139         if (cfg->port[port].outq[outq].sched_mode == PP2_PPIO_SCHED_M_WRR) {
140                 entry = rte_cfgfile_get_entry(file, sec_name,
141                                 MRVL_TOK_WRR_WEIGHT);
142                 if (entry) {
143                         if (get_val_securely(entry, &val) < 0)
144                                 return -1;
145                         cfg->port[port].outq[outq].weight = val;
146                 }
147         }
148
149         /*
150          * There's no point in setting rate limiting for specific outq as
151          * global port rate limiting has priority.
152          */
153         if (cfg->port[port].rate_limit_enable) {
154                 MRVL_LOG(WARNING, "Port %d rate limiting already enabled",
155                         port);
156                 return 0;
157         }
158
159         entry = rte_cfgfile_get_entry(file, sec_name,
160                         MRVL_TOK_RATE_LIMIT_ENABLE);
161         if (entry) {
162                 if (get_val_securely(entry, &val) < 0)
163                         return -1;
164                 cfg->port[port].outq[outq].rate_limit_enable = val;
165         }
166
167         if (!cfg->port[port].outq[outq].rate_limit_enable)
168                 return 0;
169
170         /* Read CBS (in kB) */
171         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE);
172         if (entry) {
173                 if (get_val_securely(entry, &val) < 0)
174                         return -1;
175                 cfg->port[port].outq[outq].rate_limit_params.cbs = val;
176         }
177
178         /* Read CIR (in kbps) */
179         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT);
180         if (entry) {
181                 if (get_val_securely(entry, &val) < 0)
182                         return -1;
183                 cfg->port[port].outq[outq].rate_limit_params.cir = val;
184         }
185
186         return 0;
187 }
188
189 /**
190  * Gets multiple-entry values and places them in table.
191  *
192  * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
193  * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
194  * As all result table's elements are always 1-byte long, we
195  * won't overcomplicate the function, but we'll keep API generic,
196  * check if someone hasn't changed element size and make it simple
197  * to extend to other sizes.
198  *
199  * This function is purely utilitary, it does not print any error, only returns
200  * different error numbers.
201  *
202  * @param entry[in] Values string to parse.
203  * @param tab[out] Results table.
204  * @param elem_sz[in] Element size (in bytes).
205  * @param max_elems[in] Number of results table elements available.
206  * @param max val[in] Maximum value allowed.
207  * @returns Number of correctly parsed elements in case of success.
208  * @retval -1 Wrong element size.
209  * @retval -2 More tokens than result table allows.
210  * @retval -3 Wrong range syntax.
211  * @retval -4 Wrong range values.
212  * @retval -5 Maximum value exceeded.
213  */
214 static int
215 get_entry_values(const char *entry, uint8_t *tab,
216         size_t elem_sz, uint8_t max_elems, uint8_t max_val)
217 {
218         /* There should not be more tokens than max elements.
219          * Add 1 for error trap.
220          */
221         char *tokens[max_elems + 1];
222
223         /* Begin, End + error trap = 3. */
224         char *rng_tokens[MAX_RNG_TOKENS + 1];
225         long beg, end;
226         uint32_t token_val;
227         int nb_tokens, nb_rng_tokens;
228         int i;
229         int values = 0;
230         char val;
231         char entry_cpy[CFG_VALUE_LEN];
232
233         if (elem_sz != 1)
234                 return -1;
235
236         /* Copy the entry to safely use rte_strsplit(). */
237         strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
238
239         /*
240          * If there are more tokens than array size, rte_strsplit will
241          * not return error, just array size.
242          */
243         nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
244                 tokens, max_elems + 1, ' ');
245
246         /* Quick check, will be refined later. */
247         if (nb_tokens > max_elems)
248                 return -2;
249
250         for (i = 0; i < nb_tokens; ++i) {
251                 if (strchr(tokens[i], '-') != NULL) {
252                         /*
253                          * Split to begin and end tokens.
254                          * We want to catch error cases too, thus we leave
255                          * option for number of tokens to be more than 2.
256                          */
257                         nb_rng_tokens = rte_strsplit(tokens[i],
258                                         strlen(tokens[i]), rng_tokens,
259                                         RTE_DIM(rng_tokens), '-');
260                         if (nb_rng_tokens != 2)
261                                 return -3;
262
263                         /* Range and sanity checks. */
264                         if (get_val_securely(rng_tokens[0], &token_val) < 0)
265                                 return -4;
266                         beg = (char)token_val;
267                         if (get_val_securely(rng_tokens[1], &token_val) < 0)
268                                 return -4;
269                         end = (char)token_val;
270                         if (beg < 0 || beg > UCHAR_MAX ||
271                                 end < 0 || end > UCHAR_MAX || end < beg)
272                                 return -4;
273
274                         for (val = beg; val <= end; ++val) {
275                                 if (val > max_val)
276                                         return -5;
277
278                                 *tab = val;
279                                 tab = RTE_PTR_ADD(tab, elem_sz);
280                                 ++values;
281                                 if (values >= max_elems)
282                                         return -2;
283                         }
284                 } else {
285                         /* Single values. */
286                         if (get_val_securely(tokens[i], &token_val) < 0)
287                                 return -5;
288                         val = (char)token_val;
289                         if (val > max_val)
290                                 return -5;
291
292                         *tab = val;
293                         tab = RTE_PTR_ADD(tab, elem_sz);
294                         ++values;
295                         if (values >= max_elems)
296                                 return -2;
297                 }
298         }
299
300         return values;
301 }
302
303 /**
304  * Parse Traffic Class'es mapping configuration.
305  *
306  * @param file Config file handle.
307  * @param port Which port to look for.
308  * @param tc Which Traffic Class to look for.
309  * @param cfg[out] Parsing results.
310  * @returns 0 in case of success, negative value otherwise.
311  */
312 static int
313 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
314                 struct mrvl_qos_cfg *cfg)
315 {
316         char sec_name[32];
317         const char *entry;
318         int n;
319
320         snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
321                 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
322
323         /* Skip non-existing */
324         if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
325                 return 0;
326
327         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
328         if (entry) {
329                 n = get_entry_values(entry,
330                         cfg->port[port].tc[tc].inq,
331                         sizeof(cfg->port[port].tc[tc].inq[0]),
332                         RTE_DIM(cfg->port[port].tc[tc].inq),
333                         MRVL_PP2_RXQ_MAX);
334                 if (n < 0) {
335                         MRVL_LOG(ERR, "Error %d while parsing: %s",
336                                 n, entry);
337                         return n;
338                 }
339                 cfg->port[port].tc[tc].inqs = n;
340         }
341
342         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
343         if (entry) {
344                 n = get_entry_values(entry,
345                         cfg->port[port].tc[tc].pcp,
346                         sizeof(cfg->port[port].tc[tc].pcp[0]),
347                         RTE_DIM(cfg->port[port].tc[tc].pcp),
348                         MAX_PCP);
349                 if (n < 0) {
350                         MRVL_LOG(ERR, "Error %d while parsing: %s",
351                                 n, entry);
352                         return n;
353                 }
354                 cfg->port[port].tc[tc].pcps = n;
355         }
356
357         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
358         if (entry) {
359                 n = get_entry_values(entry,
360                         cfg->port[port].tc[tc].dscp,
361                         sizeof(cfg->port[port].tc[tc].dscp[0]),
362                         RTE_DIM(cfg->port[port].tc[tc].dscp),
363                         MAX_DSCP);
364                 if (n < 0) {
365                         MRVL_LOG(ERR, "Error %d while parsing: %s",
366                                 n, entry);
367                         return n;
368                 }
369                 cfg->port[port].tc[tc].dscps = n;
370         }
371
372         if (!cfg->port[port].setup_policer)
373                 return 0;
374
375         entry = rte_cfgfile_get_entry(file, sec_name,
376                         MRVL_TOK_PLCR_DEFAULT_COLOR);
377         if (entry) {
378                 if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN,
379                                 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN))) {
380                         cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_GREEN;
381                 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW,
382                                 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW))) {
383                         cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_YELLOW;
384                 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_RED,
385                                 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_RED))) {
386                         cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_RED;
387                 } else {
388                         MRVL_LOG(ERR, "Error while parsing: %s", entry);
389                         return -1;
390                 }
391         }
392
393         return 0;
394 }
395
396 /**
397  * Parse default port policer.
398  *
399  * @param file Config file handle.
400  * @param sec_name Section name with policer configuration
401  * @param port Port number.
402  * @param cfg[out] Parsing results.
403  * @returns 0 in case of success, negative value otherwise.
404  */
405 static int
406 parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
407                 struct mrvl_qos_cfg *cfg)
408 {
409         const char *entry;
410         uint32_t val;
411
412         /* Read policer token unit */
413         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
414         if (entry) {
415                 if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
416                                         sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
417                         cfg->port[port].policer_params.token_unit =
418                                 PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
419                 } else if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_PACKETS,
420                                         sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
421                         cfg->port[port].policer_params.token_unit =
422                                 PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
423                 } else {
424                         RTE_LOG(ERR, PMD, "Unknown token: %s\n", entry);
425                         return -1;
426                 }
427         }
428
429         /* Read policer color mode */
430         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
431         if (entry) {
432                 if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
433                                         sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
434                         cfg->port[port].policer_params.color_mode =
435                                 PP2_CLS_PLCR_COLOR_BLIND_MODE;
436                 } else if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_AWARE,
437                                         sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
438                         cfg->port[port].policer_params.color_mode =
439                                 PP2_CLS_PLCR_COLOR_AWARE_MODE;
440                 } else {
441                         RTE_LOG(ERR, PMD, "Error in parsing: %s\n", entry);
442                         return -1;
443                 }
444         }
445
446         /* Read policer cir */
447         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
448         if (entry) {
449                 if (get_val_securely(entry, &val) < 0)
450                         return -1;
451                 cfg->port[port].policer_params.cir = val;
452         }
453
454         /* Read policer cbs */
455         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
456         if (entry) {
457                 if (get_val_securely(entry, &val) < 0)
458                         return -1;
459                 cfg->port[port].policer_params.cbs = val;
460         }
461
462         /* Read policer ebs */
463         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
464         if (entry) {
465                 if (get_val_securely(entry, &val) < 0)
466                         return -1;
467                 cfg->port[port].policer_params.ebs = val;
468         }
469
470         cfg->port[port].setup_policer = 1;
471
472         return 0;
473 }
474
475 /**
476  * Parse QoS configuration - rte_kvargs_process handler.
477  *
478  * Opens configuration file and parses its content.
479  *
480  * @param key Unused.
481  * @param path Path to config file.
482  * @param extra_args Pointer to configuration structure.
483  * @returns 0 in case of success, exits otherwise.
484  */
485 int
486 mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
487                 void *extra_args)
488 {
489         struct mrvl_qos_cfg **cfg = extra_args;
490         struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
491         uint32_t val;
492         int n, i, ret;
493         const char *entry;
494         char sec_name[32];
495
496         if (file == NULL)
497                 rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path);
498
499         /* Create configuration. This is never accessed on the fast path,
500          * so we can ignore socket.
501          */
502         *cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
503         if (*cfg == NULL)
504                 rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n",
505                         path);
506
507         n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
508                 sizeof(MRVL_TOK_PORT) - 1);
509
510         if (n == 0) {
511                 /* This is weird, but not bad. */
512                 MRVL_LOG(WARNING, "Empty configuration file?");
513                 return 0;
514         }
515
516         /* Use the number of ports given as vdev parameters. */
517         for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
518                 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
519                         MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
520
521                 /* Skip ports non-existing in configuration. */
522                 if (rte_cfgfile_num_sections(file, sec_name,
523                                 strlen(sec_name)) <= 0) {
524                         (*cfg)->port[n].use_global_defaults = 1;
525                         (*cfg)->port[n].mapping_priority =
526                                 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
527                         continue;
528                 }
529
530                 entry = rte_cfgfile_get_entry(file, sec_name,
531                                 MRVL_TOK_DEFAULT_TC);
532                 if (entry) {
533                         if (get_val_securely(entry, &val) < 0 ||
534                                 val > USHRT_MAX)
535                                 return -1;
536                         (*cfg)->port[n].default_tc = (uint8_t)val;
537                 } else {
538                         MRVL_LOG(ERR,
539                                 "Default Traffic Class required in custom configuration!");
540                         return -1;
541                 }
542
543                 /*
544                  * Read per-port rate limiting. Setting that will
545                  * disable per-queue rate limiting.
546                  */
547                 entry = rte_cfgfile_get_entry(file, sec_name,
548                                 MRVL_TOK_RATE_LIMIT_ENABLE);
549                 if (entry) {
550                         if (get_val_securely(entry, &val) < 0)
551                                 return -1;
552                         (*cfg)->port[n].rate_limit_enable = val;
553                 }
554
555                 if ((*cfg)->port[n].rate_limit_enable) {
556                         entry = rte_cfgfile_get_entry(file, sec_name,
557                                         MRVL_TOK_BURST_SIZE);
558                         if (entry) {
559                                 if (get_val_securely(entry, &val) < 0)
560                                         return -1;
561                                 (*cfg)->port[n].rate_limit_params.cbs = val;
562                         }
563
564                         entry = rte_cfgfile_get_entry(file, sec_name,
565                                         MRVL_TOK_RATE_LIMIT);
566                         if (entry) {
567                                 if (get_val_securely(entry, &val) < 0)
568                                         return -1;
569                                 (*cfg)->port[n].rate_limit_params.cir = val;
570                         }
571                 }
572
573                 entry = rte_cfgfile_get_entry(file, sec_name,
574                                 MRVL_TOK_MAPPING_PRIORITY);
575                 if (entry) {
576                         if (!strncmp(entry, MRVL_TOK_VLAN_IP,
577                                 sizeof(MRVL_TOK_VLAN_IP)))
578                                 (*cfg)->port[n].mapping_priority =
579                                         PP2_CLS_QOS_TBL_VLAN_IP_PRI;
580                         else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
581                                 sizeof(MRVL_TOK_IP_VLAN)))
582                                 (*cfg)->port[n].mapping_priority =
583                                         PP2_CLS_QOS_TBL_IP_VLAN_PRI;
584                         else if (!strncmp(entry, MRVL_TOK_IP,
585                                 sizeof(MRVL_TOK_IP)))
586                                 (*cfg)->port[n].mapping_priority =
587                                         PP2_CLS_QOS_TBL_IP_PRI;
588                         else if (!strncmp(entry, MRVL_TOK_VLAN,
589                                 sizeof(MRVL_TOK_VLAN)))
590                                 (*cfg)->port[n].mapping_priority =
591                                         PP2_CLS_QOS_TBL_VLAN_PRI;
592                         else
593                                 rte_exit(EXIT_FAILURE,
594                                         "Error in parsing %s value (%s)!\n",
595                                         MRVL_TOK_MAPPING_PRIORITY, entry);
596                 } else {
597                         (*cfg)->port[n].mapping_priority =
598                                 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
599                 }
600
601                 /* Parse policer configuration (if any) */
602                 entry = rte_cfgfile_get_entry(file, sec_name,
603                                 MRVL_TOK_PLCR_DEFAULT);
604                 if (entry) {
605                         if (get_val_securely(entry, &val) < 0)
606                                 return -1;
607
608                         snprintf(sec_name, sizeof(sec_name), "%s %d",
609                                         MRVL_TOK_PLCR, val);
610                         ret = parse_policer(file, n, sec_name, *cfg);
611                         if (ret)
612                                 return -1;
613                 }
614
615                 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
616                         ret = get_outq_cfg(file, n, i, *cfg);
617                         if (ret < 0)
618                                 rte_exit(EXIT_FAILURE,
619                                         "Error %d parsing port %d outq %d!\n",
620                                         ret, n, i);
621                 }
622
623                 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
624                         ret = parse_tc_cfg(file, n, i, *cfg);
625                         if (ret < 0)
626                                 rte_exit(EXIT_FAILURE,
627                                         "Error %d parsing port %d tc %d!\n",
628                                         ret, n, i);
629                 }
630         }
631
632         return 0;
633 }
634
635 /**
636  * Setup Traffic Class.
637  *
638  * Fill in TC parameters in single MUSDK TC config entry.
639  * @param param TC parameters entry.
640  * @param inqs Number of MUSDK in-queues in this TC.
641  * @param bpool Bpool for this TC.
642  * @param color Default color for this TC.
643  * @returns 0 in case of success, exits otherwise.
644  */
645 static int
646 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
647         struct pp2_bpool *bpool, enum pp2_ppio_color color)
648 {
649         struct pp2_ppio_inq_params *inq_params;
650
651         param->pkt_offset = MRVL_PKT_OFFS;
652         param->pools[0] = bpool;
653         param->default_color = color;
654
655         inq_params = rte_zmalloc_socket("inq_params",
656                 inqs * sizeof(*inq_params),
657                 0, rte_socket_id());
658         if (!inq_params)
659                 return -ENOMEM;
660
661         param->num_in_qs = inqs;
662
663         /* Release old config if necessary. */
664         if (param->inqs_params)
665                 rte_free(param->inqs_params);
666
667         param->inqs_params = inq_params;
668
669         return 0;
670 }
671
672 /**
673  * Setup ingress policer.
674  *
675  * @param priv Port's private data.
676  * @param params Pointer to the policer's configuration.
677  * @param plcr_id Policer id.
678  * @returns 0 in case of success, negative values otherwise.
679  */
680 static int
681 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
682 {
683         char match[16];
684         int ret;
685
686         /*
687          * At this point no other policers are used which means
688          * any policer can be picked up and used as a default one.
689          *
690          * Lets use 0th then.
691          */
692         sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
693         params->match = match;
694
695         ret = pp2_cls_plcr_init(params, &priv->default_policer);
696         if (ret) {
697                 MRVL_LOG(ERR, "Failed to setup %s", match);
698                 return -1;
699         }
700
701         priv->ppio_params.inqs_params.plcr = priv->default_policer;
702         priv->used_plcrs = BIT(0);
703
704         return 0;
705 }
706
707 /**
708  * Configure RX Queues in a given port.
709  *
710  * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
711  *
712  * @param priv Port's private data
713  * @param portid DPDK port ID
714  * @param max_queues Maximum number of queues to configure.
715  * @returns 0 in case of success, negative value otherwise.
716  */
717 int
718 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
719         uint16_t max_queues)
720 {
721         size_t i, tc;
722
723         if (mrvl_qos_cfg == NULL ||
724                 mrvl_qos_cfg->port[portid].use_global_defaults) {
725                 /*
726                  * No port configuration, use default: 1 TC, no QoS,
727                  * TC color set to green.
728                  */
729                 priv->ppio_params.inqs_params.num_tcs = 1;
730                 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
731                         max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
732
733                 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
734                 for (i = 0; i < max_queues; ++i) {
735                         priv->rxq_map[i].tc = 0;
736                         priv->rxq_map[i].inq = i;
737                 }
738                 return 0;
739         }
740
741         /* We need only a subset of configuration. */
742         struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
743
744         priv->qos_tbl_params.type = port_cfg->mapping_priority;
745
746         /*
747          * We need to reverse mapping, from tc->pcp (better from usability
748          * point of view) to pcp->tc (configurable in MUSDK).
749          * First, set all map elements to "default".
750          */
751         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
752                 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
753
754         /* Then, fill in all known values. */
755         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
756                 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
757                         /* Better safe than sorry. */
758                         MRVL_LOG(ERR,
759                                 "Too many PCPs configured in TC %zu!", tc);
760                         return -1;
761                 }
762                 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
763                         priv->qos_tbl_params.pcp_cos_map[
764                           port_cfg->tc[tc].pcp[i]].tc = tc;
765                 }
766         }
767
768         /*
769          * The same logic goes with DSCP.
770          * First, set all map elements to "default".
771          */
772         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
773                 priv->qos_tbl_params.dscp_cos_map[i].tc =
774                         port_cfg->default_tc;
775
776         /* Fill in all known values. */
777         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
778                 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
779                         /* Better safe than sorry. */
780                         MRVL_LOG(ERR,
781                                 "Too many DSCPs configured in TC %zu!", tc);
782                         return -1;
783                 }
784                 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
785                         priv->qos_tbl_params.dscp_cos_map[
786                           port_cfg->tc[tc].dscp[i]].tc = tc;
787                 }
788         }
789
790         /*
791          * Surprisingly, similar logic goes with queue mapping.
792          * We need only to store qid->tc mapping,
793          * to know TC when queue is read.
794          */
795         for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
796                 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
797
798         /* Set up DPDKq->(TC,inq) mapping. */
799         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
800                 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
801                         /* Overflow. */
802                         MRVL_LOG(ERR,
803                                 "Too many RX queues configured per TC %zu!",
804                                 tc);
805                         return -1;
806                 }
807                 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
808                         uint8_t idx = port_cfg->tc[tc].inq[i];
809
810                         if (idx > RTE_DIM(priv->rxq_map)) {
811                                 MRVL_LOG(ERR, "Bad queue index %d!", idx);
812                                 return -1;
813                         }
814
815                         priv->rxq_map[idx].tc = tc;
816                         priv->rxq_map[idx].inq = i;
817                 }
818         }
819
820         /*
821          * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
822          * with no gaps. Empty TC means end of processing.
823          */
824         for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
825                 if (port_cfg->tc[i].inqs == 0)
826                         break;
827                 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
828                                 port_cfg->tc[i].inqs,
829                                 priv->bpool, port_cfg->tc[i].color);
830         }
831
832         priv->ppio_params.inqs_params.num_tcs = i;
833
834         if (port_cfg->setup_policer)
835                 return setup_policer(priv, &port_cfg->policer_params);
836
837         return 0;
838 }
839
840 /**
841  * Configure TX Queues in a given port.
842  *
843  * Sets up TX queues egress scheduler and limiter.
844  *
845  * @param priv Port's private data
846  * @param portid DPDK port ID
847  * @param max_queues Maximum number of queues to configure.
848  * @returns 0 in case of success, negative value otherwise.
849  */
850 int
851 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
852                 uint16_t max_queues)
853 {
854         /* We need only a subset of configuration. */
855         struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
856         int i;
857
858         if (mrvl_qos_cfg == NULL)
859                 return 0;
860
861         priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable;
862         if (port_cfg->rate_limit_enable)
863                 priv->ppio_params.rate_limit_params =
864                         port_cfg->rate_limit_params;
865
866         for (i = 0; i < max_queues; i++) {
867                 struct pp2_ppio_outq_params *params =
868                         &priv->ppio_params.outqs_params.outqs_params[i];
869
870                 params->sched_mode = port_cfg->outq[i].sched_mode;
871                 params->weight = port_cfg->outq[i].weight;
872                 params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable;
873                 params->rate_limit_params = port_cfg->outq[i].rate_limit_params;
874         }
875
876         return 0;
877 }
878
879 /**
880  * Start QoS mapping.
881  *
882  * Finalize QoS table configuration and initialize it in SDK. It can be done
883  * only after port is started, so we have a valid ppio reference.
884  *
885  * @param priv Port's private (configuration) data.
886  * @returns 0 in case of success, exits otherwise.
887  */
888 int
889 mrvl_start_qos_mapping(struct mrvl_priv *priv)
890 {
891         size_t i;
892
893         if (priv->ppio == NULL) {
894                 MRVL_LOG(ERR, "ppio must not be NULL here!");
895                 return -1;
896         }
897
898         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
899                 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
900
901         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
902                 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
903
904         /* Initialize Classifier QoS table. */
905
906         return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);
907 }