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