net/mvpp2: introduce fixup for FIFO overrun
[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_DSA_MODE "dsa_mode"
23 #define MRVL_TOK_DSA_MODE_NONE "none"
24 #define MRVL_TOK_DSA_MODE_DSA "dsa"
25 #define MRVL_TOK_DSA_MODE_EXT_DSA "ext_dsa"
26 #define MRVL_TOK_DEFAULT_TC "default_tc"
27 #define MRVL_TOK_DSCP "dscp"
28 #define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
29 #define MRVL_TOK_IP "ip"
30 #define MRVL_TOK_IP_VLAN "ip/vlan"
31 #define MRVL_TOK_PCP "pcp"
32 #define MRVL_TOK_PORT "port"
33 #define MRVL_TOK_RXQ "rxq"
34 #define MRVL_TOK_TC "tc"
35 #define MRVL_TOK_TXQ "txq"
36 #define MRVL_TOK_VLAN "vlan"
37 #define MRVL_TOK_VLAN_IP "vlan/ip"
38 #define MRVL_TOK_PARSER_UDF "parser udf"
39
40 /* egress specific configuration tokens */
41 #define MRVL_TOK_BURST_SIZE "burst_size"
42 #define MRVL_TOK_RATE_LIMIT "rate_limit"
43 #define MRVL_TOK_RATE_LIMIT_ENABLE "rate_limit_enable"
44 #define MRVL_TOK_SCHED_MODE "sched_mode"
45 #define MRVL_TOK_SCHED_MODE_SP "sp"
46 #define MRVL_TOK_SCHED_MODE_WRR "wrr"
47 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
48
49 /* policer specific configuration tokens */
50 #define MRVL_TOK_PLCR "policer"
51 #define MRVL_TOK_PLCR_DEFAULT "default_policer"
52 #define MRVL_TOK_PLCR_UNIT "token_unit"
53 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
54 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
55 #define MRVL_TOK_PLCR_COLOR "color_mode"
56 #define MRVL_TOK_PLCR_COLOR_BLIND "blind"
57 #define MRVL_TOK_PLCR_COLOR_AWARE "aware"
58 #define MRVL_TOK_PLCR_CIR "cir"
59 #define MRVL_TOK_PLCR_CBS "cbs"
60 #define MRVL_TOK_PLCR_EBS "ebs"
61 #define MRVL_TOK_PLCR_DEFAULT_COLOR "default_color"
62 #define MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN "green"
63 #define MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW "yellow"
64 #define MRVL_TOK_PLCR_DEFAULT_COLOR_RED "red"
65
66 /* parser udf specific configuration tokens */
67 #define MRVL_TOK_PARSER_UDF_PROTO "proto"
68 #define MRVL_TOK_PARSER_UDF_FIELD "field"
69 #define MRVL_TOK_PARSER_UDF_KEY "key"
70 #define MRVL_TOK_PARSER_UDF_MASK "mask"
71 #define MRVL_TOK_PARSER_UDF_OFFSET "offset"
72 #define MRVL_TOK_PARSER_UDF_PROTO_ETH "eth"
73 #define MRVL_TOK_PARSER_UDF_FIELD_ETH_TYPE "type"
74 #define MRVL_TOK_PARSER_UDF_PROTO_UDP "udp"
75 #define MRVL_TOK_PARSER_UDF_FIELD_UDP_DPORT "dport"
76
77
78 /** Number of tokens in range a-b = 2. */
79 #define MAX_RNG_TOKENS 2
80
81 /** Maximum possible value of PCP. */
82 #define MAX_PCP 7
83
84 /** Maximum possible value of DSCP. */
85 #define MAX_DSCP 63
86
87 /** Global configuration. */
88 struct mrvl_cfg *mrvl_cfg;
89
90 /**
91  * Read out-queue configuration from file.
92  *
93  * @param file Path to the configuration file.
94  * @param port Port number.
95  * @param outq Out queue number.
96  * @param cfg Pointer to the Marvell configuration structure.
97  * @returns 0 in case of success, negative value otherwise.
98  */
99 static int
100 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
101                 struct mrvl_cfg *cfg)
102 {
103         char sec_name[32];
104         const char *entry;
105         uint32_t val;
106
107         snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
108                 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
109
110         /* Skip non-existing */
111         if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
112                 return 0;
113
114         /* Read scheduling mode */
115         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE);
116         if (entry) {
117                 if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP,
118                                         strlen(MRVL_TOK_SCHED_MODE_SP))) {
119                         cfg->port[port].outq[outq].sched_mode =
120                                 PP2_PPIO_SCHED_M_SP;
121                 } else if (!strncmp(entry, MRVL_TOK_SCHED_MODE_WRR,
122                                         strlen(MRVL_TOK_SCHED_MODE_WRR))) {
123                         cfg->port[port].outq[outq].sched_mode =
124                                 PP2_PPIO_SCHED_M_WRR;
125                 } else {
126                         MRVL_LOG(ERR, "Unknown token: %s", entry);
127                         return -1;
128                 }
129         }
130
131         /* Read wrr weight */
132         if (cfg->port[port].outq[outq].sched_mode == PP2_PPIO_SCHED_M_WRR) {
133                 entry = rte_cfgfile_get_entry(file, sec_name,
134                                 MRVL_TOK_WRR_WEIGHT);
135                 if (entry) {
136                         if (get_val_securely(entry, &val) < 0)
137                                 return -1;
138                         cfg->port[port].outq[outq].weight = val;
139                 }
140         }
141
142         /*
143          * There's no point in setting rate limiting for specific outq as
144          * global port rate limiting has priority.
145          */
146         if (cfg->port[port].rate_limit_enable) {
147                 MRVL_LOG(WARNING, "Port %d rate limiting already enabled",
148                         port);
149                 return 0;
150         }
151
152         entry = rte_cfgfile_get_entry(file, sec_name,
153                         MRVL_TOK_RATE_LIMIT_ENABLE);
154         if (entry) {
155                 if (get_val_securely(entry, &val) < 0)
156                         return -1;
157                 cfg->port[port].outq[outq].rate_limit_enable = val;
158         }
159
160         if (!cfg->port[port].outq[outq].rate_limit_enable)
161                 return 0;
162
163         /* Read CBS (in kB) */
164         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE);
165         if (entry) {
166                 if (get_val_securely(entry, &val) < 0)
167                         return -1;
168                 cfg->port[port].outq[outq].rate_limit_params.cbs = val;
169         }
170
171         /* Read CIR (in kbps) */
172         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT);
173         if (entry) {
174                 if (get_val_securely(entry, &val) < 0)
175                         return -1;
176                 cfg->port[port].outq[outq].rate_limit_params.cir = val;
177         }
178
179         return 0;
180 }
181
182 /**
183  * Gets multiple-entry values and places them in table.
184  *
185  * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
186  * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
187  * As all result table's elements are always 1-byte long, we
188  * won't overcomplicate the function, but we'll keep API generic,
189  * check if someone hasn't changed element size and make it simple
190  * to extend to other sizes.
191  *
192  * This function is purely utilitary, it does not print any error, only returns
193  * different error numbers.
194  *
195  * @param entry[in] Values string to parse.
196  * @param tab[out] Results table.
197  * @param elem_sz[in] Element size (in bytes).
198  * @param max_elems[in] Number of results table elements available.
199  * @param max val[in] Maximum value allowed.
200  * @returns Number of correctly parsed elements in case of success.
201  * @retval -1 Wrong element size.
202  * @retval -2 More tokens than result table allows.
203  * @retval -3 Wrong range syntax.
204  * @retval -4 Wrong range values.
205  * @retval -5 Maximum value exceeded.
206  */
207 static int
208 get_entry_values(const char *entry, uint8_t *tab,
209         size_t elem_sz, uint8_t max_elems, uint8_t max_val)
210 {
211         /* There should not be more tokens than max elements.
212          * Add 1 for error trap.
213          */
214         char *tokens[max_elems + 1];
215
216         /* Begin, End + error trap = 3. */
217         char *rng_tokens[MAX_RNG_TOKENS + 1];
218         long beg, end;
219         uint32_t token_val;
220         int nb_tokens, nb_rng_tokens;
221         int i;
222         int values = 0;
223         char val;
224         char entry_cpy[CFG_VALUE_LEN];
225
226         if (elem_sz != 1)
227                 return -1;
228
229         /* Copy the entry to safely use rte_strsplit(). */
230         strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
231
232         /*
233          * If there are more tokens than array size, rte_strsplit will
234          * not return error, just array size.
235          */
236         nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
237                 tokens, max_elems + 1, ' ');
238
239         /* Quick check, will be refined later. */
240         if (nb_tokens > max_elems)
241                 return -2;
242
243         for (i = 0; i < nb_tokens; ++i) {
244                 if (strchr(tokens[i], '-') != NULL) {
245                         /*
246                          * Split to begin and end tokens.
247                          * We want to catch error cases too, thus we leave
248                          * option for number of tokens to be more than 2.
249                          */
250                         nb_rng_tokens = rte_strsplit(tokens[i],
251                                         strlen(tokens[i]), rng_tokens,
252                                         RTE_DIM(rng_tokens), '-');
253                         if (nb_rng_tokens != 2)
254                                 return -3;
255
256                         /* Range and sanity checks. */
257                         if (get_val_securely(rng_tokens[0], &token_val) < 0)
258                                 return -4;
259                         beg = (char)token_val;
260                         if (get_val_securely(rng_tokens[1], &token_val) < 0)
261                                 return -4;
262                         end = (char)token_val;
263                         if (beg < 0 || beg > UCHAR_MAX ||
264                                 end < 0 || end > UCHAR_MAX || end < beg)
265                                 return -4;
266
267                         for (val = beg; val <= end; ++val) {
268                                 if (val > max_val)
269                                         return -5;
270
271                                 *tab = val;
272                                 tab = RTE_PTR_ADD(tab, elem_sz);
273                                 ++values;
274                                 if (values >= max_elems)
275                                         return -2;
276                         }
277                 } else {
278                         /* Single values. */
279                         if (get_val_securely(tokens[i], &token_val) < 0)
280                                 return -5;
281                         val = (char)token_val;
282                         if (val > max_val)
283                                 return -5;
284
285                         *tab = val;
286                         tab = RTE_PTR_ADD(tab, elem_sz);
287                         ++values;
288                         if (values >= max_elems)
289                                 return -2;
290                 }
291         }
292
293         return values;
294 }
295
296 /**
297  * Parse Traffic Class'es mapping configuration.
298  *
299  * @param file Config file handle.
300  * @param port Which port to look for.
301  * @param tc Which Traffic Class to look for.
302  * @param cfg[out] Parsing results.
303  * @returns 0 in case of success, negative value otherwise.
304  */
305 static int
306 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
307                 struct mrvl_cfg *cfg)
308 {
309         char sec_name[32];
310         const char *entry;
311         int n;
312
313         snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
314                 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
315
316         /* Skip non-existing */
317         if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
318                 return 0;
319
320         cfg->port[port].use_global_defaults = 0;
321         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
322         if (entry) {
323                 n = get_entry_values(entry,
324                         cfg->port[port].tc[tc].inq,
325                         sizeof(cfg->port[port].tc[tc].inq[0]),
326                         RTE_DIM(cfg->port[port].tc[tc].inq),
327                         MRVL_PP2_RXQ_MAX);
328                 if (n < 0) {
329                         MRVL_LOG(ERR, "Error %d while parsing: %s",
330                                 n, entry);
331                         return n;
332                 }
333                 cfg->port[port].tc[tc].inqs = n;
334         }
335
336         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
337         if (entry) {
338                 n = get_entry_values(entry,
339                         cfg->port[port].tc[tc].pcp,
340                         sizeof(cfg->port[port].tc[tc].pcp[0]),
341                         RTE_DIM(cfg->port[port].tc[tc].pcp),
342                         MAX_PCP);
343                 if (n < 0) {
344                         MRVL_LOG(ERR, "Error %d while parsing: %s",
345                                 n, entry);
346                         return n;
347                 }
348                 cfg->port[port].tc[tc].pcps = n;
349         }
350
351         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
352         if (entry) {
353                 n = get_entry_values(entry,
354                         cfg->port[port].tc[tc].dscp,
355                         sizeof(cfg->port[port].tc[tc].dscp[0]),
356                         RTE_DIM(cfg->port[port].tc[tc].dscp),
357                         MAX_DSCP);
358                 if (n < 0) {
359                         MRVL_LOG(ERR, "Error %d while parsing: %s",
360                                 n, entry);
361                         return n;
362                 }
363                 cfg->port[port].tc[tc].dscps = n;
364         }
365
366         if (!cfg->port[port].setup_policer)
367                 return 0;
368
369         entry = rte_cfgfile_get_entry(file, sec_name,
370                         MRVL_TOK_PLCR_DEFAULT_COLOR);
371         if (entry) {
372                 if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN,
373                                 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN))) {
374                         cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_GREEN;
375                 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW,
376                                 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW))) {
377                         cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_YELLOW;
378                 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_RED,
379                                 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_RED))) {
380                         cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_RED;
381                 } else {
382                         MRVL_LOG(ERR, "Error while parsing: %s", entry);
383                         return -1;
384                 }
385         }
386
387         return 0;
388 }
389
390 /**
391  * Parse default port policer.
392  *
393  * @param file Config file handle.
394  * @param sec_name Section name with policer configuration
395  * @param port Port number.
396  * @param cfg[out] Parsing results.
397  * @returns 0 in case of success, negative value otherwise.
398  */
399 static int
400 parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
401                 struct mrvl_cfg *cfg)
402 {
403         const char *entry;
404         uint32_t val;
405
406         /* Read policer token unit */
407         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
408         if (entry) {
409                 if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
410                                         sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
411                         cfg->port[port].policer_params.token_unit =
412                                 PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
413                 } else if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_PACKETS,
414                                         sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
415                         cfg->port[port].policer_params.token_unit =
416                                 PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
417                 } else {
418                         MRVL_LOG(ERR, "Unknown token: %s", entry);
419                         return -1;
420                 }
421         }
422
423         /* Read policer color mode */
424         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
425         if (entry) {
426                 if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
427                                         sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
428                         cfg->port[port].policer_params.color_mode =
429                                 PP2_CLS_PLCR_COLOR_BLIND_MODE;
430                 } else if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_AWARE,
431                                         sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
432                         cfg->port[port].policer_params.color_mode =
433                                 PP2_CLS_PLCR_COLOR_AWARE_MODE;
434                 } else {
435                         MRVL_LOG(ERR, "Error in parsing: %s", entry);
436                         return -1;
437                 }
438         }
439
440         /* Read policer cir */
441         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
442         if (entry) {
443                 if (get_val_securely(entry, &val) < 0)
444                         return -1;
445                 cfg->port[port].policer_params.cir = val;
446         }
447
448         /* Read policer cbs */
449         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
450         if (entry) {
451                 if (get_val_securely(entry, &val) < 0)
452                         return -1;
453                 cfg->port[port].policer_params.cbs = val;
454         }
455
456         /* Read policer ebs */
457         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
458         if (entry) {
459                 if (get_val_securely(entry, &val) < 0)
460                         return -1;
461                 cfg->port[port].policer_params.ebs = val;
462         }
463
464         cfg->port[port].setup_policer = 1;
465
466         return 0;
467 }
468
469 /**
470  * Parse parser udf.
471  *
472  * @param file Config file handle.
473  * @param sec_name section name
474  * @param udf udf index
475  * @param cfg[out] Parsing results.
476  * @returns 0 in case of success, negative value otherwise.
477  */
478 static int
479 parse_udf(struct rte_cfgfile *file, const char *sec_name, int udf,
480           struct mrvl_cfg *cfg)
481 {
482         struct pp2_parse_udf_params *udf_params;
483         const char *entry, *entry_field;
484         uint32_t val, i;
485         uint8_t field_size;
486         char malloc_name[32], tmp_arr[3];
487         /* field len in chars equal to '0x' + rest of data */
488 #define FIELD_LEN_IN_CHARS(field_size)  (uint32_t)(2 + (field_size) * 2)
489
490         udf_params = &cfg->pp2_cfg.prs_udfs.udfs[udf];
491
492         /* Read 'proto' field */
493         entry = rte_cfgfile_get_entry(file, sec_name,
494                                       MRVL_TOK_PARSER_UDF_PROTO);
495         if (!entry) {
496                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
497                          MRVL_TOK_PARSER_UDF_PROTO);
498                 return -1;
499         }
500
501         /* Read 'field' field */
502         entry_field = rte_cfgfile_get_entry(file, sec_name,
503                                        MRVL_TOK_PARSER_UDF_FIELD);
504         if (!entry_field) {
505                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
506                          MRVL_TOK_PARSER_UDF_FIELD);
507                 return -1;
508         }
509
510         if (!strncmp(entry, MRVL_TOK_PARSER_UDF_PROTO_ETH,
511                                 sizeof(MRVL_TOK_PARSER_UDF_PROTO_ETH))) {
512                 udf_params->match_proto = MV_NET_PROTO_ETH;
513                 if (!strncmp(entry_field, MRVL_TOK_PARSER_UDF_FIELD_ETH_TYPE,
514                              sizeof(MRVL_TOK_PARSER_UDF_FIELD_ETH_TYPE))) {
515                         udf_params->match_field.eth = MV_NET_ETH_F_TYPE;
516                         field_size = 2;
517                 } else {
518                         MRVL_LOG(ERR, "UDF[%d]: mismatch between '%s' proto "
519                                  "and '%s' field\n", udf,
520                                  MRVL_TOK_PARSER_UDF_PROTO_ETH,
521                                  entry_field);
522                         return -1;
523                 }
524         } else if (!strncmp(entry, MRVL_TOK_PARSER_UDF_PROTO_UDP,
525                                 sizeof(MRVL_TOK_PARSER_UDF_PROTO_UDP))) {
526                 udf_params->match_proto = MV_NET_PROTO_UDP;
527                 if (!strncmp(entry_field, MRVL_TOK_PARSER_UDF_FIELD_UDP_DPORT,
528                              sizeof(MRVL_TOK_PARSER_UDF_FIELD_UDP_DPORT))) {
529                         udf_params->match_field.udp = MV_NET_UDP_F_DP;
530                         field_size = 2;
531                 } else {
532                         MRVL_LOG(ERR, "UDF[%d]: mismatch between '%s' proto "
533                                  "and '%s' field\n", udf,
534                                  MRVL_TOK_PARSER_UDF_PROTO_UDP,
535                                  entry_field);
536                         return -1;
537                 }
538         } else {
539                 MRVL_LOG(ERR, "UDF[%d]: Unsupported '%s' proto\n", udf, entry);
540                 return -1;
541         }
542
543         snprintf(malloc_name, sizeof(malloc_name), "mrvl_udf_%d_key", udf);
544         udf_params->match_key = rte_zmalloc(malloc_name, field_size, 0);
545         if (udf_params->match_key == NULL) {
546                 MRVL_LOG(ERR, "Cannot allocate udf %d key\n", udf);
547                 return -1;
548         }
549         snprintf(malloc_name, sizeof(malloc_name), "mrvl_udf_%d_mask", udf);
550         udf_params->match_mask = rte_zmalloc(malloc_name, field_size, 0);
551         if (udf_params->match_mask == NULL) {
552                 MRVL_LOG(ERR, "Cannot allocate udf %d mask\n", udf);
553                 return -1;
554         }
555
556         /* Read 'key' field */
557         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PARSER_UDF_KEY);
558         if (!entry) {
559                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
560                          MRVL_TOK_PARSER_UDF_KEY);
561                 return -1;
562         }
563
564         if (strncmp(entry, "0x", 2) != 0)  {
565                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must start with '0x'\n",
566                          udf, MRVL_TOK_PARSER_UDF_KEY);
567                 return -EINVAL;
568         }
569
570         if (strlen(entry) != FIELD_LEN_IN_CHARS(field_size)) {
571                 MRVL_LOG(ERR, "UDF[%d]: '%s' field's len must be %d\n", udf,
572                          MRVL_TOK_PARSER_UDF_KEY,
573                          FIELD_LEN_IN_CHARS(field_size));
574                 return -EINVAL;
575         }
576
577         entry += 2; /* skip the '0x' */
578         for (i = 0; i < field_size; i++) {
579                 strncpy(tmp_arr, entry, 2);
580                 tmp_arr[2] = '\0';
581                 if (get_val_securely8(tmp_arr, 16,
582                                       &udf_params->match_key[i]) < 0) {
583                         MRVL_LOG(ERR, "UDF[%d]: '%s' field's value is not in "
584                                 "hex format\n", udf, MRVL_TOK_PARSER_UDF_KEY);
585                         return -EINVAL;
586                 }
587                 entry += 2;
588         }
589
590         /* Read 'mask' field */
591         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PARSER_UDF_MASK);
592         if (!entry) {
593                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
594                          MRVL_TOK_PARSER_UDF_MASK);
595                 return -1;
596         }
597         if (strncmp(entry, "0x", 2) != 0) {
598                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must start with '0x'\n",
599                          udf, MRVL_TOK_PARSER_UDF_MASK);
600                 return -EINVAL;
601         }
602
603         if (strlen(entry) != FIELD_LEN_IN_CHARS(field_size)) {
604                 MRVL_LOG(ERR, "UDF[%d]: '%s' field's len must be %d\n", udf,
605                          MRVL_TOK_PARSER_UDF_MASK,
606                          FIELD_LEN_IN_CHARS(field_size));
607                 return -EINVAL;
608         }
609
610         entry += 2; /* skip the '0x' */
611         for (i = 0; i < field_size; i++) {
612                 strncpy(tmp_arr, entry, 2);
613                 tmp_arr[2] = '\0';
614                 if (get_val_securely8(tmp_arr, 16,
615                                       &udf_params->match_mask[i]) < 0) {
616                         MRVL_LOG(ERR, "UDF[%d]: '%s' field's value is not in "
617                                 "hex format\n", udf, MRVL_TOK_PARSER_UDF_MASK);
618                         return -EINVAL;
619                 }
620                 entry += 2;
621         }
622
623         /* Read offset */
624         entry = rte_cfgfile_get_entry(file, sec_name,
625                                       MRVL_TOK_PARSER_UDF_OFFSET);
626         if (!entry) {
627                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
628                          MRVL_TOK_PARSER_UDF_OFFSET);
629                 return -1;
630         }
631         if (get_val_securely(entry, &val) < 0)
632                 return -1;
633         udf_params->offset = val;
634
635         return 0;
636 }
637
638 /**
639  * Parse configuration - rte_kvargs_process handler.
640  *
641  * Opens configuration file and parses its content.
642  *
643  * @param key Unused.
644  * @param path Path to config file.
645  * @param extra_args Pointer to configuration structure.
646  * @returns 0 in case of success, exits otherwise.
647  */
648 int
649 mrvl_get_cfg(const char *key __rte_unused, const char *path, void *extra_args)
650 {
651         struct mrvl_cfg **cfg = extra_args;
652         struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
653         uint32_t val;
654         int n, i, ret;
655         const char *entry;
656         char sec_name[32];
657
658         if (file == NULL) {
659                 MRVL_LOG(ERR, "Cannot load configuration %s\n", path);
660                 return -1;
661         }
662
663         /* Create configuration. This is never accessed on the fast path,
664          * so we can ignore socket.
665          */
666         *cfg = rte_zmalloc("mrvl_cfg", sizeof(struct mrvl_cfg), 0);
667         if (*cfg == NULL) {
668                 MRVL_LOG(ERR, "Cannot allocate configuration %s\n", path);
669                 return -1;
670         }
671
672         /* PP2 configuration */
673         n = rte_cfgfile_num_sections(file, MRVL_TOK_PARSER_UDF,
674                 sizeof(MRVL_TOK_PARSER_UDF) - 1);
675
676         if (n && n > PP2_MAX_UDFS_SUPPORTED) {
677                 MRVL_LOG(ERR, "found %d udf sections, but only %d are supported\n",
678                          n, PP2_MAX_UDFS_SUPPORTED);
679                 return -1;
680         }
681         (*cfg)->pp2_cfg.prs_udfs.num_udfs = n;
682         for (i = 0; i < n; i++) {
683                 snprintf(sec_name, sizeof(sec_name), "%s %d",
684                                 MRVL_TOK_PARSER_UDF, i);
685
686                 /* udf sections must be sequential. */
687                 if (rte_cfgfile_num_sections(file, sec_name,
688                                 strlen(sec_name)) <= 0) {
689                         MRVL_LOG(ERR, "udf sections must be sequential (0 - %d)\n",
690                                  PP2_MAX_UDFS_SUPPORTED - 1);
691                         return -1;
692                 }
693
694                 ret = parse_udf(file, sec_name, i, *cfg);
695                 if (ret) {
696                         MRVL_LOG(ERR, "Error in parsing %s!\n", sec_name);
697                         return -1;
698                 }
699         }
700
701         /* PP2 Ports configuration */
702         n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
703                 sizeof(MRVL_TOK_PORT) - 1);
704
705         if (n == 0) {
706                 /* This is weird, but not bad. */
707                 MRVL_LOG(WARNING, "Empty configuration file?");
708                 return 0;
709         }
710
711         /* Use the number of ports given as vdev parameters. */
712         for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
713                 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
714                         MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
715
716                 /* Use global defaults, unless an override occurs */
717                 (*cfg)->port[n].use_global_defaults = 1;
718
719                 /* Skip ports non-existing in configuration. */
720                 if (rte_cfgfile_num_sections(file, sec_name,
721                                 strlen(sec_name)) <= 0) {
722                         continue;
723                 }
724
725                 entry = rte_cfgfile_get_entry(file, sec_name,
726                                 MRVL_TOK_DSA_MODE);
727                 if (entry) {
728                         if (!strncmp(entry, MRVL_TOK_DSA_MODE_NONE,
729                                 sizeof(MRVL_TOK_DSA_MODE_NONE)))
730                                 (*cfg)->port[n].eth_start_hdr =
731                                 PP2_PPIO_HDR_ETH;
732                         else if (!strncmp(entry, MRVL_TOK_DSA_MODE_DSA,
733                                 sizeof(MRVL_TOK_DSA_MODE_DSA)))
734                                 (*cfg)->port[n].eth_start_hdr =
735                                 PP2_PPIO_HDR_ETH_DSA;
736                         else if (!strncmp(entry, MRVL_TOK_DSA_MODE_EXT_DSA,
737                                 sizeof(MRVL_TOK_DSA_MODE_EXT_DSA))) {
738                                 (*cfg)->port[n].eth_start_hdr =
739                                 PP2_PPIO_HDR_ETH_EXT_DSA;
740                         } else {
741                                 MRVL_LOG(ERR,
742                                         "Error in parsing %s value (%s)!\n",
743                                         MRVL_TOK_DSA_MODE, entry);
744                                 return -1;
745                         }
746                 } else {
747                         (*cfg)->port[n].eth_start_hdr = PP2_PPIO_HDR_ETH;
748                 }
749
750                 /*
751                  * Read per-port rate limiting. Setting that will
752                  * disable per-queue rate limiting.
753                  */
754                 entry = rte_cfgfile_get_entry(file, sec_name,
755                                 MRVL_TOK_RATE_LIMIT_ENABLE);
756                 if (entry) {
757                         if (get_val_securely(entry, &val) < 0)
758                                 return -1;
759                         (*cfg)->port[n].rate_limit_enable = val;
760                 }
761
762                 if ((*cfg)->port[n].rate_limit_enable) {
763                         entry = rte_cfgfile_get_entry(file, sec_name,
764                                         MRVL_TOK_BURST_SIZE);
765                         if (entry) {
766                                 if (get_val_securely(entry, &val) < 0)
767                                         return -1;
768                                 (*cfg)->port[n].rate_limit_params.cbs = val;
769                         }
770
771                         entry = rte_cfgfile_get_entry(file, sec_name,
772                                         MRVL_TOK_RATE_LIMIT);
773                         if (entry) {
774                                 if (get_val_securely(entry, &val) < 0)
775                                         return -1;
776                                 (*cfg)->port[n].rate_limit_params.cir = val;
777                         }
778                 }
779
780                 entry = rte_cfgfile_get_entry(file, sec_name,
781                                 MRVL_TOK_MAPPING_PRIORITY);
782                 if (entry) {
783                         (*cfg)->port[n].use_global_defaults = 0;
784                         if (!strncmp(entry, MRVL_TOK_VLAN_IP,
785                                 sizeof(MRVL_TOK_VLAN_IP)))
786                                 (*cfg)->port[n].mapping_priority =
787                                         PP2_CLS_QOS_TBL_VLAN_IP_PRI;
788                         else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
789                                 sizeof(MRVL_TOK_IP_VLAN)))
790                                 (*cfg)->port[n].mapping_priority =
791                                         PP2_CLS_QOS_TBL_IP_VLAN_PRI;
792                         else if (!strncmp(entry, MRVL_TOK_IP,
793                                 sizeof(MRVL_TOK_IP)))
794                                 (*cfg)->port[n].mapping_priority =
795                                         PP2_CLS_QOS_TBL_IP_PRI;
796                         else if (!strncmp(entry, MRVL_TOK_VLAN,
797                                 sizeof(MRVL_TOK_VLAN))) {
798                                 (*cfg)->port[n].mapping_priority =
799                                         PP2_CLS_QOS_TBL_VLAN_PRI;
800                         } else {
801                                 MRVL_LOG(ERR,
802                                         "Error in parsing %s value (%s)!\n",
803                                         MRVL_TOK_MAPPING_PRIORITY, entry);
804                                 return -1;
805                         }
806                 } else {
807                         (*cfg)->port[n].mapping_priority =
808                                 PP2_CLS_QOS_TBL_NONE;
809                 }
810
811                 /* Parse policer configuration (if any) */
812                 entry = rte_cfgfile_get_entry(file, sec_name,
813                                 MRVL_TOK_PLCR_DEFAULT);
814                 if (entry) {
815                         (*cfg)->port[n].use_global_defaults = 0;
816                         if (get_val_securely(entry, &val) < 0)
817                                 return -1;
818
819                         snprintf(sec_name, sizeof(sec_name), "%s %d",
820                                         MRVL_TOK_PLCR, val);
821                         ret = parse_policer(file, n, sec_name, *cfg);
822                         if (ret)
823                                 return -1;
824                 }
825
826                 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
827                         ret = get_outq_cfg(file, n, i, *cfg);
828                         if (ret < 0) {
829                                 MRVL_LOG(ERR,
830                                         "Error %d parsing port %d outq %d!\n",
831                                         ret, n, i);
832                                 return -1;
833                         }
834                 }
835
836                 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
837                         ret = parse_tc_cfg(file, n, i, *cfg);
838                         if (ret < 0) {
839                                 MRVL_LOG(ERR,
840                                         "Error %d parsing port %d tc %d!\n",
841                                         ret, n, i);
842                                 return -1;
843                         }
844                 }
845
846                 entry = rte_cfgfile_get_entry(file, sec_name,
847                                               MRVL_TOK_DEFAULT_TC);
848                 if (entry) {
849                         if (get_val_securely(entry, &val) < 0 ||
850                             val > USHRT_MAX)
851                                 return -1;
852                         (*cfg)->port[n].default_tc = (uint8_t)val;
853                 } else {
854                         if ((*cfg)->port[n].use_global_defaults == 0) {
855                                 MRVL_LOG(ERR,
856                                          "Default Traffic Class required in "
857                                          "custom configuration!");
858                                 return -1;
859                         }
860                 }
861         }
862
863         return 0;
864 }
865
866 /**
867  * Setup Traffic Class.
868  *
869  * Fill in TC parameters in single MUSDK TC config entry.
870  * @param param TC parameters entry.
871  * @param inqs Number of MUSDK in-queues in this TC.
872  * @param bpool Bpool for this TC.
873  * @param color Default color for this TC.
874  * @returns 0 in case of success, exits otherwise.
875  */
876 static int
877 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
878         struct pp2_bpool *bpool, enum pp2_ppio_color color)
879 {
880         struct pp2_ppio_inq_params *inq_params;
881
882         param->pkt_offset = MRVL_PKT_OFFS;
883         param->pools[0][0] = bpool;
884         param->pools[0][1] = dummy_pool[bpool->pp2_id];
885         param->default_color = color;
886
887         inq_params = rte_zmalloc_socket("inq_params",
888                 inqs * sizeof(*inq_params),
889                 0, rte_socket_id());
890         if (!inq_params)
891                 return -ENOMEM;
892
893         param->num_in_qs = inqs;
894
895         /* Release old config if necessary. */
896         if (param->inqs_params)
897                 rte_free(param->inqs_params);
898
899         param->inqs_params = inq_params;
900
901         return 0;
902 }
903
904 /**
905  * Setup ingress policer.
906  *
907  * @param priv Port's private data.
908  * @param params Pointer to the policer's configuration.
909  * @param plcr_id Policer id.
910  * @returns 0 in case of success, negative values otherwise.
911  */
912 static int
913 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
914 {
915         char match[16];
916         int ret;
917
918         /*
919          * At this point no other policers are used which means
920          * any policer can be picked up and used as a default one.
921          *
922          * Lets use 0th then.
923          */
924         sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
925         params->match = match;
926
927         ret = pp2_cls_plcr_init(params, &priv->default_policer);
928         if (ret) {
929                 MRVL_LOG(ERR, "Failed to setup %s", match);
930                 return -1;
931         }
932
933         priv->ppio_params.inqs_params.plcr = priv->default_policer;
934         priv->used_plcrs = BIT(0);
935
936         return 0;
937 }
938
939 /**
940  * Configure RX Queues in a given port.
941  *
942  * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
943  *
944  * @param priv Port's private data
945  * @param portid DPDK port ID
946  * @param max_queues Maximum number of queues to configure.
947  * @returns 0 in case of success, negative value otherwise.
948  */
949 int
950 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
951         uint16_t max_queues)
952 {
953         size_t i, tc;
954
955         if (mrvl_cfg == NULL ||
956                 mrvl_cfg->port[portid].use_global_defaults) {
957                 /*
958                  * No port configuration, use default: 1 TC, no QoS,
959                  * TC color set to green.
960                  */
961                 priv->ppio_params.inqs_params.num_tcs = 1;
962                 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
963                         max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
964
965                 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
966                 for (i = 0; i < max_queues; ++i) {
967                         priv->rxq_map[i].tc = 0;
968                         priv->rxq_map[i].inq = i;
969                 }
970                 return 0;
971         }
972
973         /* We need only a subset of configuration. */
974         struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
975
976         priv->qos_tbl_params.type = port_cfg->mapping_priority;
977
978         /*
979          * We need to reverse mapping, from tc->pcp (better from usability
980          * point of view) to pcp->tc (configurable in MUSDK).
981          * First, set all map elements to "default".
982          */
983         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
984                 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
985
986         /* Then, fill in all known values. */
987         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
988                 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
989                         /* Better safe than sorry. */
990                         MRVL_LOG(ERR,
991                                 "Too many PCPs configured in TC %zu!", tc);
992                         return -1;
993                 }
994                 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
995                         priv->qos_tbl_params.pcp_cos_map[
996                           port_cfg->tc[tc].pcp[i]].tc = tc;
997                 }
998         }
999
1000         /*
1001          * The same logic goes with DSCP.
1002          * First, set all map elements to "default".
1003          */
1004         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
1005                 priv->qos_tbl_params.dscp_cos_map[i].tc =
1006                         port_cfg->default_tc;
1007
1008         /* Fill in all known values. */
1009         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
1010                 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
1011                         /* Better safe than sorry. */
1012                         MRVL_LOG(ERR,
1013                                 "Too many DSCPs configured in TC %zu!", tc);
1014                         return -1;
1015                 }
1016                 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
1017                         priv->qos_tbl_params.dscp_cos_map[
1018                           port_cfg->tc[tc].dscp[i]].tc = tc;
1019                 }
1020         }
1021
1022         /*
1023          * Surprisingly, similar logic goes with queue mapping.
1024          * We need only to store qid->tc mapping,
1025          * to know TC when queue is read.
1026          */
1027         for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
1028                 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
1029
1030         /* Set up DPDKq->(TC,inq) mapping. */
1031         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
1032                 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
1033                         /* Overflow. */
1034                         MRVL_LOG(ERR,
1035                                 "Too many RX queues configured per TC %zu!",
1036                                 tc);
1037                         return -1;
1038                 }
1039                 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
1040                         uint8_t idx = port_cfg->tc[tc].inq[i];
1041
1042                         if (idx > RTE_DIM(priv->rxq_map)) {
1043                                 MRVL_LOG(ERR, "Bad queue index %d!", idx);
1044                                 return -1;
1045                         }
1046
1047                         priv->rxq_map[idx].tc = tc;
1048                         priv->rxq_map[idx].inq = i;
1049                 }
1050         }
1051
1052         /*
1053          * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
1054          * with no gaps. Empty TC means end of processing.
1055          */
1056         for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
1057                 if (port_cfg->tc[i].inqs == 0)
1058                         break;
1059                 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
1060                                 port_cfg->tc[i].inqs,
1061                                 priv->bpool, port_cfg->tc[i].color);
1062         }
1063
1064         priv->ppio_params.inqs_params.num_tcs = i;
1065
1066         if (port_cfg->setup_policer)
1067                 return setup_policer(priv, &port_cfg->policer_params);
1068
1069         return 0;
1070 }
1071
1072 /**
1073  * Configure TX Queues in a given port.
1074  *
1075  * Sets up TX queues egress scheduler and limiter.
1076  *
1077  * @param priv Port's private data
1078  * @param portid DPDK port ID
1079  * @param max_queues Maximum number of queues to configure.
1080  * @returns 0 in case of success, negative value otherwise.
1081  */
1082 int
1083 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
1084                 uint16_t max_queues)
1085 {
1086         /* We need only a subset of configuration. */
1087         struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
1088         int i;
1089
1090         if (mrvl_cfg == NULL)
1091                 return 0;
1092
1093         priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable;
1094         if (port_cfg->rate_limit_enable)
1095                 priv->ppio_params.rate_limit_params =
1096                         port_cfg->rate_limit_params;
1097
1098         for (i = 0; i < max_queues; i++) {
1099                 struct pp2_ppio_outq_params *params =
1100                         &priv->ppio_params.outqs_params.outqs_params[i];
1101
1102                 params->sched_mode = port_cfg->outq[i].sched_mode;
1103                 params->weight = port_cfg->outq[i].weight;
1104                 params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable;
1105                 params->rate_limit_params = port_cfg->outq[i].rate_limit_params;
1106         }
1107
1108         return 0;
1109 }
1110
1111 /**
1112  * Start QoS mapping.
1113  *
1114  * Finalize QoS table configuration and initialize it in SDK. It can be done
1115  * only after port is started, so we have a valid ppio reference.
1116  *
1117  * @param priv Port's private (configuration) data.
1118  * @returns 0 in case of success, exits otherwise.
1119  */
1120 int
1121 mrvl_start_qos_mapping(struct mrvl_priv *priv)
1122 {
1123         size_t i;
1124
1125         if (priv->qos_tbl_params.type == PP2_CLS_QOS_TBL_NONE)
1126                 return 0;
1127
1128         if (priv->ppio == NULL) {
1129                 MRVL_LOG(ERR, "ppio must not be NULL here!");
1130                 return -1;
1131         }
1132
1133         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
1134                 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
1135
1136         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
1137                 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
1138
1139         /* Initialize Classifier QoS table. */
1140
1141         return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);
1142 }