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