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