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_DSA_MODE_NONE "none"
24 #define MRVL_TOK_DSA_MODE_DSA "dsa"
25 #define MRVL_TOK_DSA_MODE_EXT_DSA "ext_dsa"
26 #define MRVL_TOK_DEFAULT_TC "default_tc"
27 #define MRVL_TOK_DSCP "dscp"
28 #define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
29 #define MRVL_TOK_IP "ip"
30 #define MRVL_TOK_IP_VLAN "ip/vlan"
31 #define MRVL_TOK_PCP "pcp"
32 #define MRVL_TOK_PORT "port"
33 #define MRVL_TOK_RXQ "rxq"
34 #define MRVL_TOK_TC "tc"
35 #define MRVL_TOK_TXQ "txq"
36 #define MRVL_TOK_VLAN "vlan"
37 #define MRVL_TOK_VLAN_IP "vlan/ip"
38 #define MRVL_TOK_PARSER_UDF "parser udf"
40 /* egress specific configuration tokens */
41 #define MRVL_TOK_BURST_SIZE "burst_size"
42 #define MRVL_TOK_RATE_LIMIT "rate_limit"
43 #define MRVL_TOK_RATE_LIMIT_ENABLE "rate_limit_enable"
44 #define MRVL_TOK_SCHED_MODE "sched_mode"
45 #define MRVL_TOK_SCHED_MODE_SP "sp"
46 #define MRVL_TOK_SCHED_MODE_WRR "wrr"
47 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
49 /* policer specific configuration tokens */
50 #define MRVL_TOK_PLCR "policer"
51 #define MRVL_TOK_PLCR_DEFAULT "default_policer"
52 #define MRVL_TOK_PLCR_UNIT "token_unit"
53 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
54 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
55 #define MRVL_TOK_PLCR_COLOR "color_mode"
56 #define MRVL_TOK_PLCR_COLOR_BLIND "blind"
57 #define MRVL_TOK_PLCR_COLOR_AWARE "aware"
58 #define MRVL_TOK_PLCR_CIR "cir"
59 #define MRVL_TOK_PLCR_CBS "cbs"
60 #define MRVL_TOK_PLCR_EBS "ebs"
61 #define MRVL_TOK_PLCR_DEFAULT_COLOR "default_color"
62 #define MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN "green"
63 #define MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW "yellow"
64 #define MRVL_TOK_PLCR_DEFAULT_COLOR_RED "red"
66 /* parser udf specific configuration tokens */
67 #define MRVL_TOK_PARSER_UDF_PROTO "proto"
68 #define MRVL_TOK_PARSER_UDF_FIELD "field"
69 #define MRVL_TOK_PARSER_UDF_KEY "key"
70 #define MRVL_TOK_PARSER_UDF_MASK "mask"
71 #define MRVL_TOK_PARSER_UDF_OFFSET "offset"
72 #define MRVL_TOK_PARSER_UDF_PROTO_ETH "eth"
73 #define MRVL_TOK_PARSER_UDF_FIELD_ETH_TYPE "type"
74 #define MRVL_TOK_PARSER_UDF_PROTO_UDP "udp"
75 #define MRVL_TOK_PARSER_UDF_FIELD_UDP_DPORT "dport"
78 /** Number of tokens in range a-b = 2. */
79 #define MAX_RNG_TOKENS 2
81 /** Maximum possible value of PCP. */
84 /** Maximum possible value of DSCP. */
87 /** Global configuration. */
88 struct mrvl_cfg *mrvl_cfg;
91 * Read out-queue configuration from file.
93 * @param file Path to the configuration file.
94 * @param port Port number.
95 * @param outq Out queue number.
96 * @param cfg Pointer to the Marvell configuration structure.
97 * @returns 0 in case of success, negative value otherwise.
100 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
101 struct mrvl_cfg *cfg)
107 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
108 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
110 /* Skip non-existing */
111 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
114 /* Read scheduling mode */
115 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE);
117 if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP,
118 strlen(MRVL_TOK_SCHED_MODE_SP))) {
119 cfg->port[port].outq[outq].sched_mode =
121 } else if (!strncmp(entry, MRVL_TOK_SCHED_MODE_WRR,
122 strlen(MRVL_TOK_SCHED_MODE_WRR))) {
123 cfg->port[port].outq[outq].sched_mode =
124 PP2_PPIO_SCHED_M_WRR;
126 MRVL_LOG(ERR, "Unknown token: %s", entry);
131 /* Read wrr weight */
132 if (cfg->port[port].outq[outq].sched_mode == PP2_PPIO_SCHED_M_WRR) {
133 entry = rte_cfgfile_get_entry(file, sec_name,
134 MRVL_TOK_WRR_WEIGHT);
136 if (get_val_securely(entry, &val) < 0)
138 cfg->port[port].outq[outq].weight = val;
143 * There's no point in setting rate limiting for specific outq as
144 * global port rate limiting has priority.
146 if (cfg->port[port].rate_limit_enable) {
147 MRVL_LOG(WARNING, "Port %d rate limiting already enabled",
152 entry = rte_cfgfile_get_entry(file, sec_name,
153 MRVL_TOK_RATE_LIMIT_ENABLE);
155 if (get_val_securely(entry, &val) < 0)
157 cfg->port[port].outq[outq].rate_limit_enable = val;
160 if (!cfg->port[port].outq[outq].rate_limit_enable)
163 /* Read CBS (in kB) */
164 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE);
166 if (get_val_securely(entry, &val) < 0)
168 cfg->port[port].outq[outq].rate_limit_params.cbs = val;
171 /* Read CIR (in kbps) */
172 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT);
174 if (get_val_securely(entry, &val) < 0)
176 cfg->port[port].outq[outq].rate_limit_params.cir = val;
183 * Gets multiple-entry values and places them in table.
185 * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
186 * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
187 * As all result table's elements are always 1-byte long, we
188 * won't overcomplicate the function, but we'll keep API generic,
189 * check if someone hasn't changed element size and make it simple
190 * to extend to other sizes.
192 * This function is purely utilitary, it does not print any error, only returns
193 * different error numbers.
195 * @param entry[in] Values string to parse.
196 * @param tab[out] Results table.
197 * @param elem_sz[in] Element size (in bytes).
198 * @param max_elems[in] Number of results table elements available.
199 * @param max val[in] Maximum value allowed.
200 * @returns Number of correctly parsed elements in case of success.
201 * @retval -1 Wrong element size.
202 * @retval -2 More tokens than result table allows.
203 * @retval -3 Wrong range syntax.
204 * @retval -4 Wrong range values.
205 * @retval -5 Maximum value exceeded.
208 get_entry_values(const char *entry, uint8_t *tab,
209 size_t elem_sz, uint8_t max_elems, uint8_t max_val)
211 /* There should not be more tokens than max elements.
212 * Add 1 for error trap.
214 char *tokens[max_elems + 1];
216 /* Begin, End + error trap = 3. */
217 char *rng_tokens[MAX_RNG_TOKENS + 1];
220 int nb_tokens, nb_rng_tokens;
224 char entry_cpy[CFG_VALUE_LEN];
229 /* Copy the entry to safely use rte_strsplit(). */
230 strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
233 * If there are more tokens than array size, rte_strsplit will
234 * not return error, just array size.
236 nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
237 tokens, max_elems + 1, ' ');
239 /* Quick check, will be refined later. */
240 if (nb_tokens > max_elems)
243 for (i = 0; i < nb_tokens; ++i) {
244 if (strchr(tokens[i], '-') != NULL) {
246 * Split to begin and end tokens.
247 * We want to catch error cases too, thus we leave
248 * option for number of tokens to be more than 2.
250 nb_rng_tokens = rte_strsplit(tokens[i],
251 strlen(tokens[i]), rng_tokens,
252 RTE_DIM(rng_tokens), '-');
253 if (nb_rng_tokens != 2)
256 /* Range and sanity checks. */
257 if (get_val_securely(rng_tokens[0], &token_val) < 0)
259 beg = (char)token_val;
260 if (get_val_securely(rng_tokens[1], &token_val) < 0)
262 end = (char)token_val;
263 if (beg < 0 || beg > UCHAR_MAX ||
264 end < 0 || end > UCHAR_MAX || end < beg)
267 for (val = beg; val <= end; ++val) {
272 tab = RTE_PTR_ADD(tab, elem_sz);
274 if (values >= max_elems)
279 if (get_val_securely(tokens[i], &token_val) < 0)
281 val = (char)token_val;
286 tab = RTE_PTR_ADD(tab, elem_sz);
288 if (values >= max_elems)
297 * Parse Traffic Class'es mapping configuration.
299 * @param file Config file handle.
300 * @param port Which port to look for.
301 * @param tc Which Traffic Class to look for.
302 * @param cfg[out] Parsing results.
303 * @returns 0 in case of success, negative value otherwise.
306 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
307 struct mrvl_cfg *cfg)
313 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
314 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
316 /* Skip non-existing */
317 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
320 cfg->port[port].use_global_defaults = 0;
321 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
323 n = get_entry_values(entry,
324 cfg->port[port].tc[tc].inq,
325 sizeof(cfg->port[port].tc[tc].inq[0]),
326 RTE_DIM(cfg->port[port].tc[tc].inq),
329 MRVL_LOG(ERR, "Error %d while parsing: %s",
333 cfg->port[port].tc[tc].inqs = n;
336 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
338 n = get_entry_values(entry,
339 cfg->port[port].tc[tc].pcp,
340 sizeof(cfg->port[port].tc[tc].pcp[0]),
341 RTE_DIM(cfg->port[port].tc[tc].pcp),
344 MRVL_LOG(ERR, "Error %d while parsing: %s",
348 cfg->port[port].tc[tc].pcps = n;
351 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
353 n = get_entry_values(entry,
354 cfg->port[port].tc[tc].dscp,
355 sizeof(cfg->port[port].tc[tc].dscp[0]),
356 RTE_DIM(cfg->port[port].tc[tc].dscp),
359 MRVL_LOG(ERR, "Error %d while parsing: %s",
363 cfg->port[port].tc[tc].dscps = n;
366 if (!cfg->port[port].setup_policer)
369 entry = rte_cfgfile_get_entry(file, sec_name,
370 MRVL_TOK_PLCR_DEFAULT_COLOR);
372 if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN,
373 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN))) {
374 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_GREEN;
375 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW,
376 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW))) {
377 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_YELLOW;
378 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_RED,
379 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_RED))) {
380 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_RED;
382 MRVL_LOG(ERR, "Error while parsing: %s", entry);
391 * Parse default port policer.
393 * @param file Config file handle.
394 * @param sec_name Section name with policer configuration
395 * @param port Port number.
396 * @param cfg[out] Parsing results.
397 * @returns 0 in case of success, negative value otherwise.
400 parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
401 struct mrvl_cfg *cfg)
406 /* Read policer token unit */
407 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
409 if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
410 sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
411 cfg->port[port].policer_params.token_unit =
412 PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
413 } else if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_PACKETS,
414 sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
415 cfg->port[port].policer_params.token_unit =
416 PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
418 MRVL_LOG(ERR, "Unknown token: %s", entry);
423 /* Read policer color mode */
424 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
426 if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
427 sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
428 cfg->port[port].policer_params.color_mode =
429 PP2_CLS_PLCR_COLOR_BLIND_MODE;
430 } else if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_AWARE,
431 sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
432 cfg->port[port].policer_params.color_mode =
433 PP2_CLS_PLCR_COLOR_AWARE_MODE;
435 MRVL_LOG(ERR, "Error in parsing: %s", entry);
440 /* Read policer cir */
441 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
443 if (get_val_securely(entry, &val) < 0)
445 cfg->port[port].policer_params.cir = val;
448 /* Read policer cbs */
449 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
451 if (get_val_securely(entry, &val) < 0)
453 cfg->port[port].policer_params.cbs = val;
456 /* Read policer ebs */
457 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
459 if (get_val_securely(entry, &val) < 0)
461 cfg->port[port].policer_params.ebs = val;
464 cfg->port[port].setup_policer = 1;
472 * @param file Config file handle.
473 * @param sec_name section name
474 * @param udf udf index
475 * @param cfg[out] Parsing results.
476 * @returns 0 in case of success, negative value otherwise.
479 parse_udf(struct rte_cfgfile *file, const char *sec_name, int udf,
480 struct mrvl_cfg *cfg)
482 struct pp2_parse_udf_params *udf_params;
483 const char *entry, *entry_field;
486 char malloc_name[32], tmp_arr[3];
487 /* field len in chars equal to '0x' + rest of data */
488 #define FIELD_LEN_IN_CHARS(field_size) (uint32_t)(2 + (field_size) * 2)
490 udf_params = &cfg->pp2_cfg.prs_udfs.udfs[udf];
492 /* Read 'proto' field */
493 entry = rte_cfgfile_get_entry(file, sec_name,
494 MRVL_TOK_PARSER_UDF_PROTO);
496 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
497 MRVL_TOK_PARSER_UDF_PROTO);
501 /* Read 'field' field */
502 entry_field = rte_cfgfile_get_entry(file, sec_name,
503 MRVL_TOK_PARSER_UDF_FIELD);
505 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
506 MRVL_TOK_PARSER_UDF_FIELD);
510 if (!strncmp(entry, MRVL_TOK_PARSER_UDF_PROTO_ETH,
511 sizeof(MRVL_TOK_PARSER_UDF_PROTO_ETH))) {
512 udf_params->match_proto = MV_NET_PROTO_ETH;
513 if (!strncmp(entry_field, MRVL_TOK_PARSER_UDF_FIELD_ETH_TYPE,
514 sizeof(MRVL_TOK_PARSER_UDF_FIELD_ETH_TYPE))) {
515 udf_params->match_field.eth = MV_NET_ETH_F_TYPE;
518 MRVL_LOG(ERR, "UDF[%d]: mismatch between '%s' proto "
519 "and '%s' field\n", udf,
520 MRVL_TOK_PARSER_UDF_PROTO_ETH,
524 } else if (!strncmp(entry, MRVL_TOK_PARSER_UDF_PROTO_UDP,
525 sizeof(MRVL_TOK_PARSER_UDF_PROTO_UDP))) {
526 udf_params->match_proto = MV_NET_PROTO_UDP;
527 if (!strncmp(entry_field, MRVL_TOK_PARSER_UDF_FIELD_UDP_DPORT,
528 sizeof(MRVL_TOK_PARSER_UDF_FIELD_UDP_DPORT))) {
529 udf_params->match_field.udp = MV_NET_UDP_F_DP;
532 MRVL_LOG(ERR, "UDF[%d]: mismatch between '%s' proto "
533 "and '%s' field\n", udf,
534 MRVL_TOK_PARSER_UDF_PROTO_UDP,
539 MRVL_LOG(ERR, "UDF[%d]: Unsupported '%s' proto\n", udf, entry);
543 snprintf(malloc_name, sizeof(malloc_name), "mrvl_udf_%d_key", udf);
544 udf_params->match_key = rte_zmalloc(malloc_name, field_size, 0);
545 if (udf_params->match_key == NULL) {
546 MRVL_LOG(ERR, "Cannot allocate udf %d key\n", udf);
549 snprintf(malloc_name, sizeof(malloc_name), "mrvl_udf_%d_mask", udf);
550 udf_params->match_mask = rte_zmalloc(malloc_name, field_size, 0);
551 if (udf_params->match_mask == NULL) {
552 MRVL_LOG(ERR, "Cannot allocate udf %d mask\n", udf);
556 /* Read 'key' field */
557 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PARSER_UDF_KEY);
559 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
560 MRVL_TOK_PARSER_UDF_KEY);
564 if (strncmp(entry, "0x", 2) != 0) {
565 MRVL_LOG(ERR, "UDF[%d]: '%s' field must start with '0x'\n",
566 udf, MRVL_TOK_PARSER_UDF_KEY);
570 if (strlen(entry) != FIELD_LEN_IN_CHARS(field_size)) {
571 MRVL_LOG(ERR, "UDF[%d]: '%s' field's len must be %d\n", udf,
572 MRVL_TOK_PARSER_UDF_KEY,
573 FIELD_LEN_IN_CHARS(field_size));
577 entry += 2; /* skip the '0x' */
578 for (i = 0; i < field_size; i++) {
579 strncpy(tmp_arr, entry, 2);
581 if (get_val_securely8(tmp_arr, 16,
582 &udf_params->match_key[i]) < 0) {
583 MRVL_LOG(ERR, "UDF[%d]: '%s' field's value is not in "
584 "hex format\n", udf, MRVL_TOK_PARSER_UDF_KEY);
590 /* Read 'mask' field */
591 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PARSER_UDF_MASK);
593 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
594 MRVL_TOK_PARSER_UDF_MASK);
597 if (strncmp(entry, "0x", 2) != 0) {
598 MRVL_LOG(ERR, "UDF[%d]: '%s' field must start with '0x'\n",
599 udf, MRVL_TOK_PARSER_UDF_MASK);
603 if (strlen(entry) != FIELD_LEN_IN_CHARS(field_size)) {
604 MRVL_LOG(ERR, "UDF[%d]: '%s' field's len must be %d\n", udf,
605 MRVL_TOK_PARSER_UDF_MASK,
606 FIELD_LEN_IN_CHARS(field_size));
610 entry += 2; /* skip the '0x' */
611 for (i = 0; i < field_size; i++) {
612 strncpy(tmp_arr, entry, 2);
614 if (get_val_securely8(tmp_arr, 16,
615 &udf_params->match_mask[i]) < 0) {
616 MRVL_LOG(ERR, "UDF[%d]: '%s' field's value is not in "
617 "hex format\n", udf, MRVL_TOK_PARSER_UDF_MASK);
624 entry = rte_cfgfile_get_entry(file, sec_name,
625 MRVL_TOK_PARSER_UDF_OFFSET);
627 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
628 MRVL_TOK_PARSER_UDF_OFFSET);
631 if (get_val_securely(entry, &val) < 0)
633 udf_params->offset = val;
639 * Parse configuration - rte_kvargs_process handler.
641 * Opens configuration file and parses its content.
644 * @param path Path to config file.
645 * @param extra_args Pointer to configuration structure.
646 * @returns 0 in case of success, exits otherwise.
649 mrvl_get_cfg(const char *key __rte_unused, const char *path, void *extra_args)
651 struct mrvl_cfg **cfg = extra_args;
652 struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
659 MRVL_LOG(ERR, "Cannot load configuration %s\n", path);
663 /* Create configuration. This is never accessed on the fast path,
664 * so we can ignore socket.
666 *cfg = rte_zmalloc("mrvl_cfg", sizeof(struct mrvl_cfg), 0);
668 MRVL_LOG(ERR, "Cannot allocate configuration %s\n", path);
672 /* PP2 configuration */
673 n = rte_cfgfile_num_sections(file, MRVL_TOK_PARSER_UDF,
674 sizeof(MRVL_TOK_PARSER_UDF) - 1);
676 if (n && n > PP2_MAX_UDFS_SUPPORTED) {
677 MRVL_LOG(ERR, "found %d udf sections, but only %d are supported\n",
678 n, PP2_MAX_UDFS_SUPPORTED);
681 (*cfg)->pp2_cfg.prs_udfs.num_udfs = n;
682 for (i = 0; i < n; i++) {
683 snprintf(sec_name, sizeof(sec_name), "%s %d",
684 MRVL_TOK_PARSER_UDF, i);
686 /* udf sections must be sequential. */
687 if (rte_cfgfile_num_sections(file, sec_name,
688 strlen(sec_name)) <= 0) {
689 MRVL_LOG(ERR, "udf sections must be sequential (0 - %d)\n",
690 PP2_MAX_UDFS_SUPPORTED - 1);
694 ret = parse_udf(file, sec_name, i, *cfg);
696 MRVL_LOG(ERR, "Error in parsing %s!\n", sec_name);
701 /* PP2 Ports configuration */
702 n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
703 sizeof(MRVL_TOK_PORT) - 1);
706 /* This is weird, but not bad. */
707 MRVL_LOG(WARNING, "Empty configuration file?");
711 /* Use the number of ports given as vdev parameters. */
712 for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
713 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
714 MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
716 /* Use global defaults, unless an override occurs */
717 (*cfg)->port[n].use_global_defaults = 1;
719 /* Skip ports non-existing in configuration. */
720 if (rte_cfgfile_num_sections(file, sec_name,
721 strlen(sec_name)) <= 0) {
725 entry = rte_cfgfile_get_entry(file, sec_name,
728 if (!strncmp(entry, MRVL_TOK_DSA_MODE_NONE,
729 sizeof(MRVL_TOK_DSA_MODE_NONE)))
730 (*cfg)->port[n].eth_start_hdr =
732 else if (!strncmp(entry, MRVL_TOK_DSA_MODE_DSA,
733 sizeof(MRVL_TOK_DSA_MODE_DSA)))
734 (*cfg)->port[n].eth_start_hdr =
735 PP2_PPIO_HDR_ETH_DSA;
736 else if (!strncmp(entry, MRVL_TOK_DSA_MODE_EXT_DSA,
737 sizeof(MRVL_TOK_DSA_MODE_EXT_DSA))) {
738 (*cfg)->port[n].eth_start_hdr =
739 PP2_PPIO_HDR_ETH_EXT_DSA;
742 "Error in parsing %s value (%s)!\n",
743 MRVL_TOK_DSA_MODE, entry);
747 (*cfg)->port[n].eth_start_hdr = PP2_PPIO_HDR_ETH;
751 * Read per-port rate limiting. Setting that will
752 * disable per-queue rate limiting.
754 entry = rte_cfgfile_get_entry(file, sec_name,
755 MRVL_TOK_RATE_LIMIT_ENABLE);
757 if (get_val_securely(entry, &val) < 0)
759 (*cfg)->port[n].rate_limit_enable = val;
762 if ((*cfg)->port[n].rate_limit_enable) {
763 entry = rte_cfgfile_get_entry(file, sec_name,
764 MRVL_TOK_BURST_SIZE);
766 if (get_val_securely(entry, &val) < 0)
768 (*cfg)->port[n].rate_limit_params.cbs = val;
771 entry = rte_cfgfile_get_entry(file, sec_name,
772 MRVL_TOK_RATE_LIMIT);
774 if (get_val_securely(entry, &val) < 0)
776 (*cfg)->port[n].rate_limit_params.cir = val;
780 entry = rte_cfgfile_get_entry(file, sec_name,
781 MRVL_TOK_MAPPING_PRIORITY);
783 (*cfg)->port[n].use_global_defaults = 0;
784 if (!strncmp(entry, MRVL_TOK_VLAN_IP,
785 sizeof(MRVL_TOK_VLAN_IP)))
786 (*cfg)->port[n].mapping_priority =
787 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
788 else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
789 sizeof(MRVL_TOK_IP_VLAN)))
790 (*cfg)->port[n].mapping_priority =
791 PP2_CLS_QOS_TBL_IP_VLAN_PRI;
792 else if (!strncmp(entry, MRVL_TOK_IP,
793 sizeof(MRVL_TOK_IP)))
794 (*cfg)->port[n].mapping_priority =
795 PP2_CLS_QOS_TBL_IP_PRI;
796 else if (!strncmp(entry, MRVL_TOK_VLAN,
797 sizeof(MRVL_TOK_VLAN))) {
798 (*cfg)->port[n].mapping_priority =
799 PP2_CLS_QOS_TBL_VLAN_PRI;
802 "Error in parsing %s value (%s)!\n",
803 MRVL_TOK_MAPPING_PRIORITY, entry);
807 (*cfg)->port[n].mapping_priority =
808 PP2_CLS_QOS_TBL_NONE;
811 /* Parse policer configuration (if any) */
812 entry = rte_cfgfile_get_entry(file, sec_name,
813 MRVL_TOK_PLCR_DEFAULT);
815 (*cfg)->port[n].use_global_defaults = 0;
816 if (get_val_securely(entry, &val) < 0)
819 snprintf(sec_name, sizeof(sec_name), "%s %d",
821 ret = parse_policer(file, n, sec_name, *cfg);
826 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
827 ret = get_outq_cfg(file, n, i, *cfg);
830 "Error %d parsing port %d outq %d!\n",
836 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
837 ret = parse_tc_cfg(file, n, i, *cfg);
840 "Error %d parsing port %d tc %d!\n",
846 entry = rte_cfgfile_get_entry(file, sec_name,
847 MRVL_TOK_DEFAULT_TC);
849 if (get_val_securely(entry, &val) < 0 ||
852 (*cfg)->port[n].default_tc = (uint8_t)val;
854 if ((*cfg)->port[n].use_global_defaults == 0) {
856 "Default Traffic Class required in "
857 "custom configuration!");
867 * Setup Traffic Class.
869 * Fill in TC parameters in single MUSDK TC config entry.
870 * @param param TC parameters entry.
871 * @param inqs Number of MUSDK in-queues in this TC.
872 * @param bpool Bpool for this TC.
873 * @param color Default color for this TC.
874 * @returns 0 in case of success, exits otherwise.
877 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
878 struct pp2_bpool *bpool, enum pp2_ppio_color color)
880 struct pp2_ppio_inq_params *inq_params;
882 param->pkt_offset = MRVL_PKT_OFFS;
883 param->pools[0][0] = bpool;
884 param->pools[0][1] = dummy_pool[bpool->pp2_id];
885 param->default_color = color;
887 inq_params = rte_zmalloc_socket("inq_params",
888 inqs * sizeof(*inq_params),
893 param->num_in_qs = inqs;
895 /* Release old config if necessary. */
896 if (param->inqs_params)
897 rte_free(param->inqs_params);
899 param->inqs_params = inq_params;
905 * Setup ingress policer.
907 * @param priv Port's private data.
908 * @param params Pointer to the policer's configuration.
909 * @param plcr_id Policer id.
910 * @returns 0 in case of success, negative values otherwise.
913 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
919 * At this point no other policers are used which means
920 * any policer can be picked up and used as a default one.
924 sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
925 params->match = match;
927 ret = pp2_cls_plcr_init(params, &priv->default_policer);
929 MRVL_LOG(ERR, "Failed to setup %s", match);
933 priv->ppio_params.inqs_params.plcr = priv->default_policer;
934 priv->used_plcrs = BIT(0);
940 * Configure RX Queues in a given port.
942 * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
944 * @param priv Port's private data
945 * @param portid DPDK port ID
946 * @param max_queues Maximum number of queues to configure.
947 * @returns 0 in case of success, negative value otherwise.
950 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
955 if (mrvl_cfg == NULL ||
956 mrvl_cfg->port[portid].use_global_defaults) {
958 * No port configuration, use default: 1 TC, no QoS,
959 * TC color set to green.
961 priv->ppio_params.inqs_params.num_tcs = 1;
962 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
963 max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
965 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
966 for (i = 0; i < max_queues; ++i) {
967 priv->rxq_map[i].tc = 0;
968 priv->rxq_map[i].inq = i;
973 /* We need only a subset of configuration. */
974 struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
976 priv->qos_tbl_params.type = port_cfg->mapping_priority;
979 * We need to reverse mapping, from tc->pcp (better from usability
980 * point of view) to pcp->tc (configurable in MUSDK).
981 * First, set all map elements to "default".
983 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
984 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
986 /* Then, fill in all known values. */
987 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
988 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
989 /* Better safe than sorry. */
991 "Too many PCPs configured in TC %zu!", tc);
994 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
995 priv->qos_tbl_params.pcp_cos_map[
996 port_cfg->tc[tc].pcp[i]].tc = tc;
1001 * The same logic goes with DSCP.
1002 * First, set all map elements to "default".
1004 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
1005 priv->qos_tbl_params.dscp_cos_map[i].tc =
1006 port_cfg->default_tc;
1008 /* Fill in all known values. */
1009 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
1010 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
1011 /* Better safe than sorry. */
1013 "Too many DSCPs configured in TC %zu!", tc);
1016 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
1017 priv->qos_tbl_params.dscp_cos_map[
1018 port_cfg->tc[tc].dscp[i]].tc = tc;
1023 * Surprisingly, similar logic goes with queue mapping.
1024 * We need only to store qid->tc mapping,
1025 * to know TC when queue is read.
1027 for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
1028 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
1030 /* Set up DPDKq->(TC,inq) mapping. */
1031 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
1032 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
1035 "Too many RX queues configured per TC %zu!",
1039 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
1040 uint8_t idx = port_cfg->tc[tc].inq[i];
1042 if (idx > RTE_DIM(priv->rxq_map)) {
1043 MRVL_LOG(ERR, "Bad queue index %d!", idx);
1047 priv->rxq_map[idx].tc = tc;
1048 priv->rxq_map[idx].inq = i;
1053 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
1054 * with no gaps. Empty TC means end of processing.
1056 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
1057 if (port_cfg->tc[i].inqs == 0)
1059 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
1060 port_cfg->tc[i].inqs,
1061 priv->bpool, port_cfg->tc[i].color);
1064 priv->ppio_params.inqs_params.num_tcs = i;
1066 if (port_cfg->setup_policer)
1067 return setup_policer(priv, &port_cfg->policer_params);
1073 * Configure TX Queues in a given port.
1075 * Sets up TX queues egress scheduler and limiter.
1077 * @param priv Port's private data
1078 * @param portid DPDK port ID
1079 * @param max_queues Maximum number of queues to configure.
1080 * @returns 0 in case of success, negative value otherwise.
1083 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
1084 uint16_t max_queues)
1086 /* We need only a subset of configuration. */
1087 struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
1090 if (mrvl_cfg == NULL)
1093 priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable;
1094 if (port_cfg->rate_limit_enable)
1095 priv->ppio_params.rate_limit_params =
1096 port_cfg->rate_limit_params;
1098 for (i = 0; i < max_queues; i++) {
1099 struct pp2_ppio_outq_params *params =
1100 &priv->ppio_params.outqs_params.outqs_params[i];
1102 params->sched_mode = port_cfg->outq[i].sched_mode;
1103 params->weight = port_cfg->outq[i].weight;
1104 params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable;
1105 params->rate_limit_params = port_cfg->outq[i].rate_limit_params;
1112 * Start QoS mapping.
1114 * Finalize QoS table configuration and initialize it in SDK. It can be done
1115 * only after port is started, so we have a valid ppio reference.
1117 * @param priv Port's private (configuration) data.
1118 * @returns 0 in case of success, exits otherwise.
1121 mrvl_start_qos_mapping(struct mrvl_priv *priv)
1125 if (priv->qos_tbl_params.type == PP2_CLS_QOS_TBL_NONE)
1128 if (priv->ppio == NULL) {
1129 MRVL_LOG(ERR, "ppio must not be NULL here!");
1133 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
1134 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
1136 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
1137 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
1139 /* Initialize Classifier QoS table. */
1141 return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);