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"
39 /* egress specific configuration tokens */
40 #define MRVL_TOK_BURST_SIZE "burst_size"
41 #define MRVL_TOK_RATE_LIMIT "rate_limit"
42 #define MRVL_TOK_RATE_LIMIT_ENABLE "rate_limit_enable"
43 #define MRVL_TOK_SCHED_MODE "sched_mode"
44 #define MRVL_TOK_SCHED_MODE_SP "sp"
45 #define MRVL_TOK_SCHED_MODE_WRR "wrr"
46 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
48 /* policer specific configuration tokens */
49 #define MRVL_TOK_PLCR "policer"
50 #define MRVL_TOK_PLCR_DEFAULT "default_policer"
51 #define MRVL_TOK_PLCR_UNIT "token_unit"
52 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
53 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
54 #define MRVL_TOK_PLCR_COLOR "color_mode"
55 #define MRVL_TOK_PLCR_COLOR_BLIND "blind"
56 #define MRVL_TOK_PLCR_COLOR_AWARE "aware"
57 #define MRVL_TOK_PLCR_CIR "cir"
58 #define MRVL_TOK_PLCR_CBS "cbs"
59 #define MRVL_TOK_PLCR_EBS "ebs"
60 #define MRVL_TOK_PLCR_DEFAULT_COLOR "default_color"
61 #define MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN "green"
62 #define MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW "yellow"
63 #define MRVL_TOK_PLCR_DEFAULT_COLOR_RED "red"
65 /** Number of tokens in range a-b = 2. */
66 #define MAX_RNG_TOKENS 2
68 /** Maximum possible value of PCP. */
71 /** Maximum possible value of DSCP. */
74 /** Global configuration. */
75 struct mrvl_cfg *mrvl_cfg;
78 * Read out-queue configuration from file.
80 * @param file Path to the configuration file.
81 * @param port Port number.
82 * @param outq Out queue number.
83 * @param cfg Pointer to the Marvell configuration structure.
84 * @returns 0 in case of success, negative value otherwise.
87 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
94 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
95 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
97 /* Skip non-existing */
98 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
101 /* Read scheduling mode */
102 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE);
104 if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP,
105 strlen(MRVL_TOK_SCHED_MODE_SP))) {
106 cfg->port[port].outq[outq].sched_mode =
108 } else if (!strncmp(entry, MRVL_TOK_SCHED_MODE_WRR,
109 strlen(MRVL_TOK_SCHED_MODE_WRR))) {
110 cfg->port[port].outq[outq].sched_mode =
111 PP2_PPIO_SCHED_M_WRR;
113 MRVL_LOG(ERR, "Unknown token: %s", entry);
118 /* Read wrr weight */
119 if (cfg->port[port].outq[outq].sched_mode == PP2_PPIO_SCHED_M_WRR) {
120 entry = rte_cfgfile_get_entry(file, sec_name,
121 MRVL_TOK_WRR_WEIGHT);
123 if (get_val_securely(entry, &val) < 0)
125 cfg->port[port].outq[outq].weight = val;
130 * There's no point in setting rate limiting for specific outq as
131 * global port rate limiting has priority.
133 if (cfg->port[port].rate_limit_enable) {
134 MRVL_LOG(WARNING, "Port %d rate limiting already enabled",
139 entry = rte_cfgfile_get_entry(file, sec_name,
140 MRVL_TOK_RATE_LIMIT_ENABLE);
142 if (get_val_securely(entry, &val) < 0)
144 cfg->port[port].outq[outq].rate_limit_enable = val;
147 if (!cfg->port[port].outq[outq].rate_limit_enable)
150 /* Read CBS (in kB) */
151 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE);
153 if (get_val_securely(entry, &val) < 0)
155 cfg->port[port].outq[outq].rate_limit_params.cbs = val;
158 /* Read CIR (in kbps) */
159 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT);
161 if (get_val_securely(entry, &val) < 0)
163 cfg->port[port].outq[outq].rate_limit_params.cir = val;
170 * Gets multiple-entry values and places them in table.
172 * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
173 * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
174 * As all result table's elements are always 1-byte long, we
175 * won't overcomplicate the function, but we'll keep API generic,
176 * check if someone hasn't changed element size and make it simple
177 * to extend to other sizes.
179 * This function is purely utilitary, it does not print any error, only returns
180 * different error numbers.
182 * @param entry[in] Values string to parse.
183 * @param tab[out] Results table.
184 * @param elem_sz[in] Element size (in bytes).
185 * @param max_elems[in] Number of results table elements available.
186 * @param max val[in] Maximum value allowed.
187 * @returns Number of correctly parsed elements in case of success.
188 * @retval -1 Wrong element size.
189 * @retval -2 More tokens than result table allows.
190 * @retval -3 Wrong range syntax.
191 * @retval -4 Wrong range values.
192 * @retval -5 Maximum value exceeded.
195 get_entry_values(const char *entry, uint8_t *tab,
196 size_t elem_sz, uint8_t max_elems, uint8_t max_val)
198 /* There should not be more tokens than max elements.
199 * Add 1 for error trap.
201 char *tokens[max_elems + 1];
203 /* Begin, End + error trap = 3. */
204 char *rng_tokens[MAX_RNG_TOKENS + 1];
207 int nb_tokens, nb_rng_tokens;
211 char entry_cpy[CFG_VALUE_LEN];
216 /* Copy the entry to safely use rte_strsplit(). */
217 strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
220 * If there are more tokens than array size, rte_strsplit will
221 * not return error, just array size.
223 nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
224 tokens, max_elems + 1, ' ');
226 /* Quick check, will be refined later. */
227 if (nb_tokens > max_elems)
230 for (i = 0; i < nb_tokens; ++i) {
231 if (strchr(tokens[i], '-') != NULL) {
233 * Split to begin and end tokens.
234 * We want to catch error cases too, thus we leave
235 * option for number of tokens to be more than 2.
237 nb_rng_tokens = rte_strsplit(tokens[i],
238 strlen(tokens[i]), rng_tokens,
239 RTE_DIM(rng_tokens), '-');
240 if (nb_rng_tokens != 2)
243 /* Range and sanity checks. */
244 if (get_val_securely(rng_tokens[0], &token_val) < 0)
246 beg = (char)token_val;
247 if (get_val_securely(rng_tokens[1], &token_val) < 0)
249 end = (char)token_val;
250 if (beg < 0 || beg > UCHAR_MAX ||
251 end < 0 || end > UCHAR_MAX || end < beg)
254 for (val = beg; val <= end; ++val) {
259 tab = RTE_PTR_ADD(tab, elem_sz);
261 if (values >= max_elems)
266 if (get_val_securely(tokens[i], &token_val) < 0)
268 val = (char)token_val;
273 tab = RTE_PTR_ADD(tab, elem_sz);
275 if (values >= max_elems)
284 * Parse Traffic Class'es mapping configuration.
286 * @param file Config file handle.
287 * @param port Which port to look for.
288 * @param tc Which Traffic Class to look for.
289 * @param cfg[out] Parsing results.
290 * @returns 0 in case of success, negative value otherwise.
293 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
294 struct mrvl_cfg *cfg)
300 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
301 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
303 /* Skip non-existing */
304 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
307 cfg->port[port].use_global_defaults = 0;
308 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
310 n = get_entry_values(entry,
311 cfg->port[port].tc[tc].inq,
312 sizeof(cfg->port[port].tc[tc].inq[0]),
313 RTE_DIM(cfg->port[port].tc[tc].inq),
316 MRVL_LOG(ERR, "Error %d while parsing: %s",
320 cfg->port[port].tc[tc].inqs = n;
323 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
325 n = get_entry_values(entry,
326 cfg->port[port].tc[tc].pcp,
327 sizeof(cfg->port[port].tc[tc].pcp[0]),
328 RTE_DIM(cfg->port[port].tc[tc].pcp),
331 MRVL_LOG(ERR, "Error %d while parsing: %s",
335 cfg->port[port].tc[tc].pcps = n;
338 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
340 n = get_entry_values(entry,
341 cfg->port[port].tc[tc].dscp,
342 sizeof(cfg->port[port].tc[tc].dscp[0]),
343 RTE_DIM(cfg->port[port].tc[tc].dscp),
346 MRVL_LOG(ERR, "Error %d while parsing: %s",
350 cfg->port[port].tc[tc].dscps = n;
353 if (!cfg->port[port].setup_policer)
356 entry = rte_cfgfile_get_entry(file, sec_name,
357 MRVL_TOK_PLCR_DEFAULT_COLOR);
359 if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN,
360 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN))) {
361 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_GREEN;
362 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW,
363 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW))) {
364 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_YELLOW;
365 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_RED,
366 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_RED))) {
367 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_RED;
369 MRVL_LOG(ERR, "Error while parsing: %s", entry);
378 * Parse default port policer.
380 * @param file Config file handle.
381 * @param sec_name Section name with policer configuration
382 * @param port Port number.
383 * @param cfg[out] Parsing results.
384 * @returns 0 in case of success, negative value otherwise.
387 parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
388 struct mrvl_cfg *cfg)
393 /* Read policer token unit */
394 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
396 if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
397 sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
398 cfg->port[port].policer_params.token_unit =
399 PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
400 } else if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_PACKETS,
401 sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
402 cfg->port[port].policer_params.token_unit =
403 PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
405 MRVL_LOG(ERR, "Unknown token: %s", entry);
410 /* Read policer color mode */
411 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
413 if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
414 sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
415 cfg->port[port].policer_params.color_mode =
416 PP2_CLS_PLCR_COLOR_BLIND_MODE;
417 } else if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_AWARE,
418 sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
419 cfg->port[port].policer_params.color_mode =
420 PP2_CLS_PLCR_COLOR_AWARE_MODE;
422 MRVL_LOG(ERR, "Error in parsing: %s", entry);
427 /* Read policer cir */
428 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
430 if (get_val_securely(entry, &val) < 0)
432 cfg->port[port].policer_params.cir = val;
435 /* Read policer cbs */
436 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
438 if (get_val_securely(entry, &val) < 0)
440 cfg->port[port].policer_params.cbs = val;
443 /* Read policer ebs */
444 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
446 if (get_val_securely(entry, &val) < 0)
448 cfg->port[port].policer_params.ebs = val;
451 cfg->port[port].setup_policer = 1;
457 * Parse configuration - rte_kvargs_process handler.
459 * Opens configuration file and parses its content.
462 * @param path Path to config file.
463 * @param extra_args Pointer to configuration structure.
464 * @returns 0 in case of success, exits otherwise.
467 mrvl_get_cfg(const char *key __rte_unused, const char *path, void *extra_args)
469 struct mrvl_cfg **cfg = extra_args;
470 struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
477 MRVL_LOG(ERR, "Cannot load configuration %s\n", path);
481 /* Create configuration. This is never accessed on the fast path,
482 * so we can ignore socket.
484 *cfg = rte_zmalloc("mrvl_cfg", sizeof(struct mrvl_cfg), 0);
486 MRVL_LOG(ERR, "Cannot allocate configuration %s\n", path);
490 n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
491 sizeof(MRVL_TOK_PORT) - 1);
494 /* This is weird, but not bad. */
495 MRVL_LOG(WARNING, "Empty configuration file?");
499 /* Use the number of ports given as vdev parameters. */
500 for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
501 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
502 MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
504 /* Use global defaults, unless an override occurs */
505 (*cfg)->port[n].use_global_defaults = 1;
507 /* Skip ports non-existing in configuration. */
508 if (rte_cfgfile_num_sections(file, sec_name,
509 strlen(sec_name)) <= 0) {
513 entry = rte_cfgfile_get_entry(file, sec_name,
516 if (!strncmp(entry, MRVL_TOK_DSA_MODE_NONE,
517 sizeof(MRVL_TOK_DSA_MODE_NONE)))
518 (*cfg)->port[n].eth_start_hdr =
520 else if (!strncmp(entry, MRVL_TOK_DSA_MODE_DSA,
521 sizeof(MRVL_TOK_DSA_MODE_DSA)))
522 (*cfg)->port[n].eth_start_hdr =
523 PP2_PPIO_HDR_ETH_DSA;
524 else if (!strncmp(entry, MRVL_TOK_DSA_MODE_EXT_DSA,
525 sizeof(MRVL_TOK_DSA_MODE_EXT_DSA))) {
526 (*cfg)->port[n].eth_start_hdr =
527 PP2_PPIO_HDR_ETH_EXT_DSA;
530 "Error in parsing %s value (%s)!\n",
531 MRVL_TOK_DSA_MODE, entry);
535 (*cfg)->port[n].eth_start_hdr = PP2_PPIO_HDR_ETH;
539 * Read per-port rate limiting. Setting that will
540 * disable per-queue rate limiting.
542 entry = rte_cfgfile_get_entry(file, sec_name,
543 MRVL_TOK_RATE_LIMIT_ENABLE);
545 if (get_val_securely(entry, &val) < 0)
547 (*cfg)->port[n].rate_limit_enable = val;
550 if ((*cfg)->port[n].rate_limit_enable) {
551 entry = rte_cfgfile_get_entry(file, sec_name,
552 MRVL_TOK_BURST_SIZE);
554 if (get_val_securely(entry, &val) < 0)
556 (*cfg)->port[n].rate_limit_params.cbs = val;
559 entry = rte_cfgfile_get_entry(file, sec_name,
560 MRVL_TOK_RATE_LIMIT);
562 if (get_val_securely(entry, &val) < 0)
564 (*cfg)->port[n].rate_limit_params.cir = val;
568 entry = rte_cfgfile_get_entry(file, sec_name,
569 MRVL_TOK_MAPPING_PRIORITY);
571 (*cfg)->port[n].use_global_defaults = 0;
572 if (!strncmp(entry, MRVL_TOK_VLAN_IP,
573 sizeof(MRVL_TOK_VLAN_IP)))
574 (*cfg)->port[n].mapping_priority =
575 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
576 else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
577 sizeof(MRVL_TOK_IP_VLAN)))
578 (*cfg)->port[n].mapping_priority =
579 PP2_CLS_QOS_TBL_IP_VLAN_PRI;
580 else if (!strncmp(entry, MRVL_TOK_IP,
581 sizeof(MRVL_TOK_IP)))
582 (*cfg)->port[n].mapping_priority =
583 PP2_CLS_QOS_TBL_IP_PRI;
584 else if (!strncmp(entry, MRVL_TOK_VLAN,
585 sizeof(MRVL_TOK_VLAN))) {
586 (*cfg)->port[n].mapping_priority =
587 PP2_CLS_QOS_TBL_VLAN_PRI;
590 "Error in parsing %s value (%s)!\n",
591 MRVL_TOK_MAPPING_PRIORITY, entry);
595 (*cfg)->port[n].mapping_priority =
596 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
599 /* Parse policer configuration (if any) */
600 entry = rte_cfgfile_get_entry(file, sec_name,
601 MRVL_TOK_PLCR_DEFAULT);
603 (*cfg)->port[n].use_global_defaults = 0;
604 if (get_val_securely(entry, &val) < 0)
607 snprintf(sec_name, sizeof(sec_name), "%s %d",
609 ret = parse_policer(file, n, sec_name, *cfg);
614 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
615 ret = get_outq_cfg(file, n, i, *cfg);
618 "Error %d parsing port %d outq %d!\n",
624 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
625 ret = parse_tc_cfg(file, n, i, *cfg);
628 "Error %d parsing port %d tc %d!\n",
634 entry = rte_cfgfile_get_entry(file, sec_name,
635 MRVL_TOK_DEFAULT_TC);
637 if (get_val_securely(entry, &val) < 0 ||
640 (*cfg)->port[n].default_tc = (uint8_t)val;
642 if ((*cfg)->port[n].use_global_defaults == 0) {
644 "Default Traffic Class required in "
645 "custom configuration!");
655 * Setup Traffic Class.
657 * Fill in TC parameters in single MUSDK TC config entry.
658 * @param param TC parameters entry.
659 * @param inqs Number of MUSDK in-queues in this TC.
660 * @param bpool Bpool for this TC.
661 * @param color Default color for this TC.
662 * @returns 0 in case of success, exits otherwise.
665 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
666 struct pp2_bpool *bpool, enum pp2_ppio_color color)
668 struct pp2_ppio_inq_params *inq_params;
670 param->pkt_offset = MRVL_PKT_OFFS;
671 param->pools[0][0] = bpool;
672 param->default_color = color;
674 inq_params = rte_zmalloc_socket("inq_params",
675 inqs * sizeof(*inq_params),
680 param->num_in_qs = inqs;
682 /* Release old config if necessary. */
683 if (param->inqs_params)
684 rte_free(param->inqs_params);
686 param->inqs_params = inq_params;
692 * Setup ingress policer.
694 * @param priv Port's private data.
695 * @param params Pointer to the policer's configuration.
696 * @param plcr_id Policer id.
697 * @returns 0 in case of success, negative values otherwise.
700 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
706 * At this point no other policers are used which means
707 * any policer can be picked up and used as a default one.
711 sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
712 params->match = match;
714 ret = pp2_cls_plcr_init(params, &priv->default_policer);
716 MRVL_LOG(ERR, "Failed to setup %s", match);
720 priv->ppio_params.inqs_params.plcr = priv->default_policer;
721 priv->used_plcrs = BIT(0);
727 * Configure RX Queues in a given port.
729 * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
731 * @param priv Port's private data
732 * @param portid DPDK port ID
733 * @param max_queues Maximum number of queues to configure.
734 * @returns 0 in case of success, negative value otherwise.
737 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
742 if (mrvl_cfg == NULL ||
743 mrvl_cfg->port[portid].use_global_defaults) {
745 * No port configuration, use default: 1 TC, no QoS,
746 * TC color set to green.
748 priv->ppio_params.inqs_params.num_tcs = 1;
749 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
750 max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
752 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
753 for (i = 0; i < max_queues; ++i) {
754 priv->rxq_map[i].tc = 0;
755 priv->rxq_map[i].inq = i;
760 /* We need only a subset of configuration. */
761 struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
763 priv->qos_tbl_params.type = port_cfg->mapping_priority;
766 * We need to reverse mapping, from tc->pcp (better from usability
767 * point of view) to pcp->tc (configurable in MUSDK).
768 * First, set all map elements to "default".
770 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
771 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
773 /* Then, fill in all known values. */
774 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
775 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
776 /* Better safe than sorry. */
778 "Too many PCPs configured in TC %zu!", tc);
781 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
782 priv->qos_tbl_params.pcp_cos_map[
783 port_cfg->tc[tc].pcp[i]].tc = tc;
788 * The same logic goes with DSCP.
789 * First, set all map elements to "default".
791 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
792 priv->qos_tbl_params.dscp_cos_map[i].tc =
793 port_cfg->default_tc;
795 /* Fill in all known values. */
796 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
797 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
798 /* Better safe than sorry. */
800 "Too many DSCPs configured in TC %zu!", tc);
803 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
804 priv->qos_tbl_params.dscp_cos_map[
805 port_cfg->tc[tc].dscp[i]].tc = tc;
810 * Surprisingly, similar logic goes with queue mapping.
811 * We need only to store qid->tc mapping,
812 * to know TC when queue is read.
814 for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
815 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
817 /* Set up DPDKq->(TC,inq) mapping. */
818 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
819 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
822 "Too many RX queues configured per TC %zu!",
826 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
827 uint8_t idx = port_cfg->tc[tc].inq[i];
829 if (idx > RTE_DIM(priv->rxq_map)) {
830 MRVL_LOG(ERR, "Bad queue index %d!", idx);
834 priv->rxq_map[idx].tc = tc;
835 priv->rxq_map[idx].inq = i;
840 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
841 * with no gaps. Empty TC means end of processing.
843 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
844 if (port_cfg->tc[i].inqs == 0)
846 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
847 port_cfg->tc[i].inqs,
848 priv->bpool, port_cfg->tc[i].color);
851 priv->ppio_params.inqs_params.num_tcs = i;
853 if (port_cfg->setup_policer)
854 return setup_policer(priv, &port_cfg->policer_params);
860 * Configure TX Queues in a given port.
862 * Sets up TX queues egress scheduler and limiter.
864 * @param priv Port's private data
865 * @param portid DPDK port ID
866 * @param max_queues Maximum number of queues to configure.
867 * @returns 0 in case of success, negative value otherwise.
870 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
873 /* We need only a subset of configuration. */
874 struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
877 if (mrvl_cfg == NULL)
880 priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable;
881 if (port_cfg->rate_limit_enable)
882 priv->ppio_params.rate_limit_params =
883 port_cfg->rate_limit_params;
885 for (i = 0; i < max_queues; i++) {
886 struct pp2_ppio_outq_params *params =
887 &priv->ppio_params.outqs_params.outqs_params[i];
889 params->sched_mode = port_cfg->outq[i].sched_mode;
890 params->weight = port_cfg->outq[i].weight;
891 params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable;
892 params->rate_limit_params = port_cfg->outq[i].rate_limit_params;
901 * Finalize QoS table configuration and initialize it in SDK. It can be done
902 * only after port is started, so we have a valid ppio reference.
904 * @param priv Port's private (configuration) data.
905 * @returns 0 in case of success, exits otherwise.
908 mrvl_start_qos_mapping(struct mrvl_priv *priv)
912 if (priv->ppio == NULL) {
913 MRVL_LOG(ERR, "ppio must not be NULL here!");
917 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
918 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
920 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
921 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
923 /* Initialize Classifier QoS table. */
925 return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);