1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2017 Marvell International Ltd.
3 * Copyright(c) 2017 Semihalf.
11 #include <rte_common.h>
12 #include <rte_cfgfile.h>
14 #include <rte_lcore.h>
15 #include <rte_malloc.h>
16 #include <rte_string_fns.h>
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"
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"
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"
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"
79 /** Number of tokens in range a-b = 2. */
80 #define MAX_RNG_TOKENS 2
82 /** Maximum possible value of PCP. */
85 /** Maximum possible value of DSCP. */
88 /** Global configuration. */
89 struct mrvl_cfg *mrvl_cfg;
92 * Read out-queue configuration from file.
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.
101 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
102 struct mrvl_cfg *cfg)
108 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
109 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
111 /* Skip non-existing */
112 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
115 /* Read scheduling mode */
116 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE);
118 if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP,
119 strlen(MRVL_TOK_SCHED_MODE_SP))) {
120 cfg->port[port].outq[outq].sched_mode =
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;
127 MRVL_LOG(ERR, "Unknown token: %s", entry);
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);
137 if (get_val_securely(entry, &val) < 0)
139 cfg->port[port].outq[outq].weight = val;
144 * There's no point in setting rate limiting for specific outq as
145 * global port rate limiting has priority.
147 if (cfg->port[port].rate_limit_enable) {
148 MRVL_LOG(WARNING, "Port %d rate limiting already enabled",
153 entry = rte_cfgfile_get_entry(file, sec_name,
154 MRVL_TOK_RATE_LIMIT_ENABLE);
156 if (get_val_securely(entry, &val) < 0)
158 cfg->port[port].outq[outq].rate_limit_enable = val;
161 if (!cfg->port[port].outq[outq].rate_limit_enable)
164 /* Read CBS (in kB) */
165 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE);
167 if (get_val_securely(entry, &val) < 0)
169 cfg->port[port].outq[outq].rate_limit_params.cbs = val;
172 /* Read CIR (in kbps) */
173 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT);
175 if (get_val_securely(entry, &val) < 0)
177 cfg->port[port].outq[outq].rate_limit_params.cir = val;
184 * Gets multiple-entry values and places them in table.
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.
193 * This function is purely utilitary, it does not print any error, only returns
194 * different error numbers.
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.
209 get_entry_values(const char *entry, uint8_t *tab,
210 size_t elem_sz, uint8_t max_elems, uint8_t max_val)
212 /* There should not be more tokens than max elements.
213 * Add 1 for error trap.
215 char *tokens[max_elems + 1];
217 /* Begin, End + error trap = 3. */
218 char *rng_tokens[MAX_RNG_TOKENS + 1];
221 int nb_tokens, nb_rng_tokens;
225 char entry_cpy[CFG_VALUE_LEN];
230 /* Copy the entry to safely use rte_strsplit(). */
231 strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
234 * If there are more tokens than array size, rte_strsplit will
235 * not return error, just array size.
237 nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
238 tokens, max_elems + 1, ' ');
240 /* Quick check, will be refined later. */
241 if (nb_tokens > max_elems)
244 for (i = 0; i < nb_tokens; ++i) {
245 if (strchr(tokens[i], '-') != NULL) {
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.
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)
257 /* Range and sanity checks. */
258 if (get_val_securely(rng_tokens[0], &token_val) < 0)
260 beg = (char)token_val;
261 if (get_val_securely(rng_tokens[1], &token_val) < 0)
263 end = (char)token_val;
264 if (beg < 0 || beg > UCHAR_MAX ||
265 end < 0 || end > UCHAR_MAX || end < beg)
268 for (val = beg; val <= end; ++val) {
273 tab = RTE_PTR_ADD(tab, elem_sz);
275 if (values >= max_elems)
280 if (get_val_securely(tokens[i], &token_val) < 0)
282 val = (char)token_val;
287 tab = RTE_PTR_ADD(tab, elem_sz);
289 if (values >= max_elems)
298 * Parse Traffic Class'es mapping configuration.
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.
307 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
308 struct mrvl_cfg *cfg)
314 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
315 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
317 /* Skip non-existing */
318 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
321 cfg->port[port].use_global_defaults = 0;
322 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
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),
330 MRVL_LOG(ERR, "Error %d while parsing: %s",
334 cfg->port[port].tc[tc].inqs = n;
337 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
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),
345 MRVL_LOG(ERR, "Error %d while parsing: %s",
349 cfg->port[port].tc[tc].pcps = n;
352 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
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),
360 MRVL_LOG(ERR, "Error %d while parsing: %s",
364 cfg->port[port].tc[tc].dscps = n;
367 if (!cfg->port[port].setup_policer)
370 entry = rte_cfgfile_get_entry(file, sec_name,
371 MRVL_TOK_PLCR_DEFAULT_COLOR);
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;
383 MRVL_LOG(ERR, "Error while parsing: %s", entry);
392 * Parse default port policer.
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.
401 parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
402 struct mrvl_cfg *cfg)
407 /* Read policer token unit */
408 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
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;
419 MRVL_LOG(ERR, "Unknown token: %s", entry);
424 /* Read policer color mode */
425 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
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;
436 MRVL_LOG(ERR, "Error in parsing: %s", entry);
441 /* Read policer cir */
442 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
444 if (get_val_securely(entry, &val) < 0)
446 cfg->port[port].policer_params.cir = val;
449 /* Read policer cbs */
450 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
452 if (get_val_securely(entry, &val) < 0)
454 cfg->port[port].policer_params.cbs = val;
457 /* Read policer ebs */
458 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
460 if (get_val_securely(entry, &val) < 0)
462 cfg->port[port].policer_params.ebs = val;
465 cfg->port[port].setup_policer = 1;
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.
480 parse_udf(struct rte_cfgfile *file, const char *sec_name, int udf,
481 struct mrvl_cfg *cfg)
483 struct pp2_parse_udf_params *udf_params;
484 const char *entry, *entry_field;
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)
491 udf_params = &cfg->pp2_cfg.prs_udfs.udfs[udf];
493 /* Read 'proto' field */
494 entry = rte_cfgfile_get_entry(file, sec_name,
495 MRVL_TOK_PARSER_UDF_PROTO);
497 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
498 MRVL_TOK_PARSER_UDF_PROTO);
502 /* Read 'field' field */
503 entry_field = rte_cfgfile_get_entry(file, sec_name,
504 MRVL_TOK_PARSER_UDF_FIELD);
506 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
507 MRVL_TOK_PARSER_UDF_FIELD);
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;
519 MRVL_LOG(ERR, "UDF[%d]: mismatch between '%s' proto "
520 "and '%s' field\n", udf,
521 MRVL_TOK_PARSER_UDF_PROTO_ETH,
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;
533 MRVL_LOG(ERR, "UDF[%d]: mismatch between '%s' proto "
534 "and '%s' field\n", udf,
535 MRVL_TOK_PARSER_UDF_PROTO_UDP,
540 MRVL_LOG(ERR, "UDF[%d]: Unsupported '%s' proto\n", udf, entry);
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);
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);
557 /* Read 'key' field */
558 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PARSER_UDF_KEY);
560 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
561 MRVL_TOK_PARSER_UDF_KEY);
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);
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));
578 entry += 2; /* skip the '0x' */
579 for (i = 0; i < field_size; i++) {
580 strncpy(tmp_arr, entry, 2);
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);
591 /* Read 'mask' field */
592 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PARSER_UDF_MASK);
594 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
595 MRVL_TOK_PARSER_UDF_MASK);
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);
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));
611 entry += 2; /* skip the '0x' */
612 for (i = 0; i < field_size; i++) {
613 strncpy(tmp_arr, entry, 2);
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);
625 entry = rte_cfgfile_get_entry(file, sec_name,
626 MRVL_TOK_PARSER_UDF_OFFSET);
628 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
629 MRVL_TOK_PARSER_UDF_OFFSET);
632 if (get_val_securely(entry, &val) < 0)
634 udf_params->offset = val;
640 * Parse configuration - rte_kvargs_process handler.
642 * Opens configuration file and parses its content.
645 * @param path Path to config file.
646 * @param extra_args Pointer to configuration structure.
647 * @returns 0 in case of success, exits otherwise.
650 mrvl_get_cfg(const char *key __rte_unused, const char *path, void *extra_args)
652 struct mrvl_cfg **cfg = extra_args;
653 struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
660 MRVL_LOG(ERR, "Cannot load configuration %s\n", path);
664 /* Create configuration. This is never accessed on the fast path,
665 * so we can ignore socket.
667 *cfg = rte_zmalloc("mrvl_cfg", sizeof(struct mrvl_cfg), 0);
669 MRVL_LOG(ERR, "Cannot allocate configuration %s\n", path);
673 /* PP2 configuration */
674 n = rte_cfgfile_num_sections(file, MRVL_TOK_PARSER_UDF,
675 sizeof(MRVL_TOK_PARSER_UDF) - 1);
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);
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);
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);
695 ret = parse_udf(file, sec_name, i, *cfg);
697 MRVL_LOG(ERR, "Error in parsing %s!\n", sec_name);
702 /* PP2 Ports configuration */
703 n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
704 sizeof(MRVL_TOK_PORT) - 1);
707 /* This is weird, but not bad. */
708 MRVL_LOG(WARNING, "Empty configuration file?");
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);
717 /* Use global defaults, unless an override occurs */
718 (*cfg)->port[n].use_global_defaults = 1;
720 /* Skip ports non-existing in configuration. */
721 if (rte_cfgfile_num_sections(file, sec_name,
722 strlen(sec_name)) <= 0) {
726 /* MRVL_TOK_START_HDR replaces MRVL_TOK_DSA_MODE parameter.
727 * MRVL_TOK_DSA_MODE will be supported for backward
730 entry = rte_cfgfile_get_entry(file, sec_name,
732 /* if start_hsr is missing, check if dsa_mode exist instead */
734 entry = rte_cfgfile_get_entry(file, sec_name,
737 if (!strncmp(entry, MRVL_TOK_START_HDR_NONE,
738 sizeof(MRVL_TOK_START_HDR_NONE)))
739 (*cfg)->port[n].eth_start_hdr =
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;
751 "Error in parsing %s value (%s)!\n",
752 MRVL_TOK_START_HDR, entry);
756 (*cfg)->port[n].eth_start_hdr = PP2_PPIO_HDR_ETH;
760 * Read per-port rate limiting. Setting that will
761 * disable per-queue rate limiting.
763 entry = rte_cfgfile_get_entry(file, sec_name,
764 MRVL_TOK_RATE_LIMIT_ENABLE);
766 if (get_val_securely(entry, &val) < 0)
768 (*cfg)->port[n].rate_limit_enable = val;
771 if ((*cfg)->port[n].rate_limit_enable) {
772 entry = rte_cfgfile_get_entry(file, sec_name,
773 MRVL_TOK_BURST_SIZE);
775 if (get_val_securely(entry, &val) < 0)
777 (*cfg)->port[n].rate_limit_params.cbs = val;
780 entry = rte_cfgfile_get_entry(file, sec_name,
781 MRVL_TOK_RATE_LIMIT);
783 if (get_val_securely(entry, &val) < 0)
785 (*cfg)->port[n].rate_limit_params.cir = val;
789 entry = rte_cfgfile_get_entry(file, sec_name,
790 MRVL_TOK_MAPPING_PRIORITY);
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;
811 "Error in parsing %s value (%s)!\n",
812 MRVL_TOK_MAPPING_PRIORITY, entry);
816 (*cfg)->port[n].mapping_priority =
817 PP2_CLS_QOS_TBL_NONE;
820 /* Parse policer configuration (if any) */
821 entry = rte_cfgfile_get_entry(file, sec_name,
822 MRVL_TOK_PLCR_DEFAULT);
824 (*cfg)->port[n].use_global_defaults = 0;
825 if (get_val_securely(entry, &val) < 0)
828 snprintf(sec_name, sizeof(sec_name), "%s %d",
830 ret = parse_policer(file, n, sec_name, *cfg);
835 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
836 ret = get_outq_cfg(file, n, i, *cfg);
839 "Error %d parsing port %d outq %d!\n",
845 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
846 ret = parse_tc_cfg(file, n, i, *cfg);
849 "Error %d parsing port %d tc %d!\n",
855 entry = rte_cfgfile_get_entry(file, sec_name,
856 MRVL_TOK_DEFAULT_TC);
858 if (get_val_securely(entry, &val) < 0 ||
861 (*cfg)->port[n].default_tc = (uint8_t)val;
863 if ((*cfg)->port[n].use_global_defaults == 0) {
865 "Default Traffic Class required in "
866 "custom configuration!");
876 * Setup Traffic Class.
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.
886 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
887 struct pp2_bpool *bpool, enum pp2_ppio_color color)
889 struct pp2_ppio_inq_params *inq_params;
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;
896 inq_params = rte_zmalloc_socket("inq_params",
897 inqs * sizeof(*inq_params),
902 param->num_in_qs = inqs;
904 /* Release old config if necessary. */
905 if (param->inqs_params)
906 rte_free(param->inqs_params);
908 param->inqs_params = inq_params;
914 * Setup ingress policer.
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.
922 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
928 * At this point no other policers are used which means
929 * any policer can be picked up and used as a default one.
933 sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
934 params->match = match;
936 ret = pp2_cls_plcr_init(params, &priv->default_policer);
938 MRVL_LOG(ERR, "Failed to setup %s", match);
942 priv->ppio_params.inqs_params.plcr = priv->default_policer;
943 priv->used_plcrs = BIT(0);
949 * Configure RX Queues in a given port.
951 * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
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.
959 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
964 if (mrvl_cfg == NULL ||
965 mrvl_cfg->port[portid].use_global_defaults) {
967 * No port configuration, use default: 1 TC, no QoS,
968 * TC color set to green.
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);
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;
982 /* We need only a subset of configuration. */
983 struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
985 priv->qos_tbl_params.type = port_cfg->mapping_priority;
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".
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;
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. */
1000 "Too many PCPs configured in TC %zu!", tc);
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;
1010 * The same logic goes with DSCP.
1011 * First, set all map elements to "default".
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;
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. */
1022 "Too many DSCPs configured in TC %zu!", tc);
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;
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.
1036 for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
1037 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
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)) {
1044 "Too many RX queues configured per TC %zu!",
1048 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
1049 uint8_t idx = port_cfg->tc[tc].inq[i];
1051 if (idx > RTE_DIM(priv->rxq_map)) {
1052 MRVL_LOG(ERR, "Bad queue index %d!", idx);
1056 priv->rxq_map[idx].tc = tc;
1057 priv->rxq_map[idx].inq = i;
1062 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
1063 * with no gaps. Empty TC means end of processing.
1065 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
1066 if (port_cfg->tc[i].inqs == 0)
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);
1073 priv->ppio_params.inqs_params.num_tcs = i;
1075 if (port_cfg->setup_policer)
1076 return setup_policer(priv, &port_cfg->policer_params);
1082 * Configure TX Queues in a given port.
1084 * Sets up TX queues egress scheduler and limiter.
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.
1092 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
1093 uint16_t max_queues)
1095 /* We need only a subset of configuration. */
1096 struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
1099 if (mrvl_cfg == NULL)
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;
1107 for (i = 0; i < max_queues; i++) {
1108 struct pp2_ppio_outq_params *params =
1109 &priv->ppio_params.outqs_params.outqs_params[i];
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;
1121 * Start QoS mapping.
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.
1126 * @param priv Port's private (configuration) data.
1127 * @returns 0 in case of success, exits otherwise.
1130 mrvl_start_qos_mapping(struct mrvl_priv *priv)
1134 if (priv->qos_tbl_params.type == PP2_CLS_QOS_TBL_NONE)
1137 if (priv->ppio == NULL) {
1138 MRVL_LOG(ERR, "ppio must not be NULL here!");
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;
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;
1148 /* Initialize Classifier QoS table. */
1150 return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);