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 * Convert string to uint32_t with extra checks for result correctness.
80 * @param string String to convert.
81 * @param val Conversion result.
82 * @returns 0 in case of success, negative value otherwise.
85 get_val_securely(const char *string, uint32_t *val)
88 size_t len = strlen(string);
94 *val = strtoul(string, &endptr, 0);
95 if (errno != 0 || RTE_PTR_DIFF(endptr, string) != len)
102 * Read out-queue configuration from file.
104 * @param file Path to the configuration file.
105 * @param port Port number.
106 * @param outq Out queue number.
107 * @param cfg Pointer to the Marvell configuration structure.
108 * @returns 0 in case of success, negative value otherwise.
111 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
112 struct mrvl_cfg *cfg)
118 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
119 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
121 /* Skip non-existing */
122 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
125 /* Read scheduling mode */
126 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE);
128 if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP,
129 strlen(MRVL_TOK_SCHED_MODE_SP))) {
130 cfg->port[port].outq[outq].sched_mode =
132 } else if (!strncmp(entry, MRVL_TOK_SCHED_MODE_WRR,
133 strlen(MRVL_TOK_SCHED_MODE_WRR))) {
134 cfg->port[port].outq[outq].sched_mode =
135 PP2_PPIO_SCHED_M_WRR;
137 MRVL_LOG(ERR, "Unknown token: %s", entry);
142 /* Read wrr weight */
143 if (cfg->port[port].outq[outq].sched_mode == PP2_PPIO_SCHED_M_WRR) {
144 entry = rte_cfgfile_get_entry(file, sec_name,
145 MRVL_TOK_WRR_WEIGHT);
147 if (get_val_securely(entry, &val) < 0)
149 cfg->port[port].outq[outq].weight = val;
154 * There's no point in setting rate limiting for specific outq as
155 * global port rate limiting has priority.
157 if (cfg->port[port].rate_limit_enable) {
158 MRVL_LOG(WARNING, "Port %d rate limiting already enabled",
163 entry = rte_cfgfile_get_entry(file, sec_name,
164 MRVL_TOK_RATE_LIMIT_ENABLE);
166 if (get_val_securely(entry, &val) < 0)
168 cfg->port[port].outq[outq].rate_limit_enable = val;
171 if (!cfg->port[port].outq[outq].rate_limit_enable)
174 /* Read CBS (in kB) */
175 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE);
177 if (get_val_securely(entry, &val) < 0)
179 cfg->port[port].outq[outq].rate_limit_params.cbs = val;
182 /* Read CIR (in kbps) */
183 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT);
185 if (get_val_securely(entry, &val) < 0)
187 cfg->port[port].outq[outq].rate_limit_params.cir = val;
194 * Gets multiple-entry values and places them in table.
196 * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
197 * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
198 * As all result table's elements are always 1-byte long, we
199 * won't overcomplicate the function, but we'll keep API generic,
200 * check if someone hasn't changed element size and make it simple
201 * to extend to other sizes.
203 * This function is purely utilitary, it does not print any error, only returns
204 * different error numbers.
206 * @param entry[in] Values string to parse.
207 * @param tab[out] Results table.
208 * @param elem_sz[in] Element size (in bytes).
209 * @param max_elems[in] Number of results table elements available.
210 * @param max val[in] Maximum value allowed.
211 * @returns Number of correctly parsed elements in case of success.
212 * @retval -1 Wrong element size.
213 * @retval -2 More tokens than result table allows.
214 * @retval -3 Wrong range syntax.
215 * @retval -4 Wrong range values.
216 * @retval -5 Maximum value exceeded.
219 get_entry_values(const char *entry, uint8_t *tab,
220 size_t elem_sz, uint8_t max_elems, uint8_t max_val)
222 /* There should not be more tokens than max elements.
223 * Add 1 for error trap.
225 char *tokens[max_elems + 1];
227 /* Begin, End + error trap = 3. */
228 char *rng_tokens[MAX_RNG_TOKENS + 1];
231 int nb_tokens, nb_rng_tokens;
235 char entry_cpy[CFG_VALUE_LEN];
240 /* Copy the entry to safely use rte_strsplit(). */
241 strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
244 * If there are more tokens than array size, rte_strsplit will
245 * not return error, just array size.
247 nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
248 tokens, max_elems + 1, ' ');
250 /* Quick check, will be refined later. */
251 if (nb_tokens > max_elems)
254 for (i = 0; i < nb_tokens; ++i) {
255 if (strchr(tokens[i], '-') != NULL) {
257 * Split to begin and end tokens.
258 * We want to catch error cases too, thus we leave
259 * option for number of tokens to be more than 2.
261 nb_rng_tokens = rte_strsplit(tokens[i],
262 strlen(tokens[i]), rng_tokens,
263 RTE_DIM(rng_tokens), '-');
264 if (nb_rng_tokens != 2)
267 /* Range and sanity checks. */
268 if (get_val_securely(rng_tokens[0], &token_val) < 0)
270 beg = (char)token_val;
271 if (get_val_securely(rng_tokens[1], &token_val) < 0)
273 end = (char)token_val;
274 if (beg < 0 || beg > UCHAR_MAX ||
275 end < 0 || end > UCHAR_MAX || end < beg)
278 for (val = beg; val <= end; ++val) {
283 tab = RTE_PTR_ADD(tab, elem_sz);
285 if (values >= max_elems)
290 if (get_val_securely(tokens[i], &token_val) < 0)
292 val = (char)token_val;
297 tab = RTE_PTR_ADD(tab, elem_sz);
299 if (values >= max_elems)
308 * Parse Traffic Class'es mapping configuration.
310 * @param file Config file handle.
311 * @param port Which port to look for.
312 * @param tc Which Traffic Class to look for.
313 * @param cfg[out] Parsing results.
314 * @returns 0 in case of success, negative value otherwise.
317 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
318 struct mrvl_cfg *cfg)
324 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
325 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
327 /* Skip non-existing */
328 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
331 cfg->port[port].use_global_defaults = 0;
332 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
334 n = get_entry_values(entry,
335 cfg->port[port].tc[tc].inq,
336 sizeof(cfg->port[port].tc[tc].inq[0]),
337 RTE_DIM(cfg->port[port].tc[tc].inq),
340 MRVL_LOG(ERR, "Error %d while parsing: %s",
344 cfg->port[port].tc[tc].inqs = n;
347 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
349 n = get_entry_values(entry,
350 cfg->port[port].tc[tc].pcp,
351 sizeof(cfg->port[port].tc[tc].pcp[0]),
352 RTE_DIM(cfg->port[port].tc[tc].pcp),
355 MRVL_LOG(ERR, "Error %d while parsing: %s",
359 cfg->port[port].tc[tc].pcps = n;
362 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
364 n = get_entry_values(entry,
365 cfg->port[port].tc[tc].dscp,
366 sizeof(cfg->port[port].tc[tc].dscp[0]),
367 RTE_DIM(cfg->port[port].tc[tc].dscp),
370 MRVL_LOG(ERR, "Error %d while parsing: %s",
374 cfg->port[port].tc[tc].dscps = n;
377 if (!cfg->port[port].setup_policer)
380 entry = rte_cfgfile_get_entry(file, sec_name,
381 MRVL_TOK_PLCR_DEFAULT_COLOR);
383 if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN,
384 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN))) {
385 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_GREEN;
386 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW,
387 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW))) {
388 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_YELLOW;
389 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_RED,
390 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_RED))) {
391 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_RED;
393 MRVL_LOG(ERR, "Error while parsing: %s", entry);
402 * Parse default port policer.
404 * @param file Config file handle.
405 * @param sec_name Section name with policer configuration
406 * @param port Port number.
407 * @param cfg[out] Parsing results.
408 * @returns 0 in case of success, negative value otherwise.
411 parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
412 struct mrvl_cfg *cfg)
417 /* Read policer token unit */
418 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
420 if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
421 sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
422 cfg->port[port].policer_params.token_unit =
423 PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
424 } else if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_PACKETS,
425 sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
426 cfg->port[port].policer_params.token_unit =
427 PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
429 MRVL_LOG(ERR, "Unknown token: %s", entry);
434 /* Read policer color mode */
435 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
437 if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
438 sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
439 cfg->port[port].policer_params.color_mode =
440 PP2_CLS_PLCR_COLOR_BLIND_MODE;
441 } else if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_AWARE,
442 sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
443 cfg->port[port].policer_params.color_mode =
444 PP2_CLS_PLCR_COLOR_AWARE_MODE;
446 MRVL_LOG(ERR, "Error in parsing: %s", entry);
451 /* Read policer cir */
452 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
454 if (get_val_securely(entry, &val) < 0)
456 cfg->port[port].policer_params.cir = val;
459 /* Read policer cbs */
460 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
462 if (get_val_securely(entry, &val) < 0)
464 cfg->port[port].policer_params.cbs = val;
467 /* Read policer ebs */
468 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
470 if (get_val_securely(entry, &val) < 0)
472 cfg->port[port].policer_params.ebs = val;
475 cfg->port[port].setup_policer = 1;
481 * Parse configuration - rte_kvargs_process handler.
483 * Opens configuration file and parses its content.
486 * @param path Path to config file.
487 * @param extra_args Pointer to configuration structure.
488 * @returns 0 in case of success, exits otherwise.
491 mrvl_get_cfg(const char *key __rte_unused, const char *path, void *extra_args)
493 struct mrvl_cfg **cfg = extra_args;
494 struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
501 MRVL_LOG(ERR, "Cannot load configuration %s\n", path);
505 /* Create configuration. This is never accessed on the fast path,
506 * so we can ignore socket.
508 *cfg = rte_zmalloc("mrvl_cfg", sizeof(struct mrvl_cfg), 0);
510 MRVL_LOG(ERR, "Cannot allocate configuration %s\n", path);
514 n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
515 sizeof(MRVL_TOK_PORT) - 1);
518 /* This is weird, but not bad. */
519 MRVL_LOG(WARNING, "Empty configuration file?");
523 /* Use the number of ports given as vdev parameters. */
524 for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
525 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
526 MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
528 /* Use global defaults, unless an override occurs */
529 (*cfg)->port[n].use_global_defaults = 1;
531 /* Skip ports non-existing in configuration. */
532 if (rte_cfgfile_num_sections(file, sec_name,
533 strlen(sec_name)) <= 0) {
537 entry = rte_cfgfile_get_entry(file, sec_name,
540 if (!strncmp(entry, MRVL_TOK_DSA_MODE_NONE,
541 sizeof(MRVL_TOK_DSA_MODE_NONE)))
542 (*cfg)->port[n].eth_start_hdr =
544 else if (!strncmp(entry, MRVL_TOK_DSA_MODE_DSA,
545 sizeof(MRVL_TOK_DSA_MODE_DSA)))
546 (*cfg)->port[n].eth_start_hdr =
547 PP2_PPIO_HDR_ETH_DSA;
548 else if (!strncmp(entry, MRVL_TOK_DSA_MODE_EXT_DSA,
549 sizeof(MRVL_TOK_DSA_MODE_EXT_DSA))) {
550 (*cfg)->port[n].eth_start_hdr =
551 PP2_PPIO_HDR_ETH_EXT_DSA;
554 "Error in parsing %s value (%s)!\n",
555 MRVL_TOK_DSA_MODE, entry);
559 (*cfg)->port[n].eth_start_hdr = PP2_PPIO_HDR_ETH;
563 * Read per-port rate limiting. Setting that will
564 * disable per-queue rate limiting.
566 entry = rte_cfgfile_get_entry(file, sec_name,
567 MRVL_TOK_RATE_LIMIT_ENABLE);
569 if (get_val_securely(entry, &val) < 0)
571 (*cfg)->port[n].rate_limit_enable = val;
574 if ((*cfg)->port[n].rate_limit_enable) {
575 entry = rte_cfgfile_get_entry(file, sec_name,
576 MRVL_TOK_BURST_SIZE);
578 if (get_val_securely(entry, &val) < 0)
580 (*cfg)->port[n].rate_limit_params.cbs = val;
583 entry = rte_cfgfile_get_entry(file, sec_name,
584 MRVL_TOK_RATE_LIMIT);
586 if (get_val_securely(entry, &val) < 0)
588 (*cfg)->port[n].rate_limit_params.cir = val;
592 entry = rte_cfgfile_get_entry(file, sec_name,
593 MRVL_TOK_MAPPING_PRIORITY);
595 (*cfg)->port[n].use_global_defaults = 0;
596 if (!strncmp(entry, MRVL_TOK_VLAN_IP,
597 sizeof(MRVL_TOK_VLAN_IP)))
598 (*cfg)->port[n].mapping_priority =
599 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
600 else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
601 sizeof(MRVL_TOK_IP_VLAN)))
602 (*cfg)->port[n].mapping_priority =
603 PP2_CLS_QOS_TBL_IP_VLAN_PRI;
604 else if (!strncmp(entry, MRVL_TOK_IP,
605 sizeof(MRVL_TOK_IP)))
606 (*cfg)->port[n].mapping_priority =
607 PP2_CLS_QOS_TBL_IP_PRI;
608 else if (!strncmp(entry, MRVL_TOK_VLAN,
609 sizeof(MRVL_TOK_VLAN))) {
610 (*cfg)->port[n].mapping_priority =
611 PP2_CLS_QOS_TBL_VLAN_PRI;
614 "Error in parsing %s value (%s)!\n",
615 MRVL_TOK_MAPPING_PRIORITY, entry);
619 (*cfg)->port[n].mapping_priority =
620 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
623 /* Parse policer configuration (if any) */
624 entry = rte_cfgfile_get_entry(file, sec_name,
625 MRVL_TOK_PLCR_DEFAULT);
627 (*cfg)->port[n].use_global_defaults = 0;
628 if (get_val_securely(entry, &val) < 0)
631 snprintf(sec_name, sizeof(sec_name), "%s %d",
633 ret = parse_policer(file, n, sec_name, *cfg);
638 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
639 ret = get_outq_cfg(file, n, i, *cfg);
642 "Error %d parsing port %d outq %d!\n",
648 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
649 ret = parse_tc_cfg(file, n, i, *cfg);
652 "Error %d parsing port %d tc %d!\n",
658 entry = rte_cfgfile_get_entry(file, sec_name,
659 MRVL_TOK_DEFAULT_TC);
661 if (get_val_securely(entry, &val) < 0 ||
664 (*cfg)->port[n].default_tc = (uint8_t)val;
666 if ((*cfg)->port[n].use_global_defaults == 0) {
668 "Default Traffic Class required in "
669 "custom configuration!");
679 * Setup Traffic Class.
681 * Fill in TC parameters in single MUSDK TC config entry.
682 * @param param TC parameters entry.
683 * @param inqs Number of MUSDK in-queues in this TC.
684 * @param bpool Bpool for this TC.
685 * @param color Default color for this TC.
686 * @returns 0 in case of success, exits otherwise.
689 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
690 struct pp2_bpool *bpool, enum pp2_ppio_color color)
692 struct pp2_ppio_inq_params *inq_params;
694 param->pkt_offset = MRVL_PKT_OFFS;
695 param->pools[0][0] = bpool;
696 param->default_color = color;
698 inq_params = rte_zmalloc_socket("inq_params",
699 inqs * sizeof(*inq_params),
704 param->num_in_qs = inqs;
706 /* Release old config if necessary. */
707 if (param->inqs_params)
708 rte_free(param->inqs_params);
710 param->inqs_params = inq_params;
716 * Setup ingress policer.
718 * @param priv Port's private data.
719 * @param params Pointer to the policer's configuration.
720 * @param plcr_id Policer id.
721 * @returns 0 in case of success, negative values otherwise.
724 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
730 * At this point no other policers are used which means
731 * any policer can be picked up and used as a default one.
735 sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
736 params->match = match;
738 ret = pp2_cls_plcr_init(params, &priv->default_policer);
740 MRVL_LOG(ERR, "Failed to setup %s", match);
744 priv->ppio_params.inqs_params.plcr = priv->default_policer;
745 priv->used_plcrs = BIT(0);
751 * Configure RX Queues in a given port.
753 * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
755 * @param priv Port's private data
756 * @param portid DPDK port ID
757 * @param max_queues Maximum number of queues to configure.
758 * @returns 0 in case of success, negative value otherwise.
761 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
766 if (mrvl_cfg == NULL ||
767 mrvl_cfg->port[portid].use_global_defaults) {
769 * No port configuration, use default: 1 TC, no QoS,
770 * TC color set to green.
772 priv->ppio_params.inqs_params.num_tcs = 1;
773 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
774 max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
776 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
777 for (i = 0; i < max_queues; ++i) {
778 priv->rxq_map[i].tc = 0;
779 priv->rxq_map[i].inq = i;
784 /* We need only a subset of configuration. */
785 struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
787 priv->qos_tbl_params.type = port_cfg->mapping_priority;
790 * We need to reverse mapping, from tc->pcp (better from usability
791 * point of view) to pcp->tc (configurable in MUSDK).
792 * First, set all map elements to "default".
794 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
795 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
797 /* Then, fill in all known values. */
798 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
799 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
800 /* Better safe than sorry. */
802 "Too many PCPs configured in TC %zu!", tc);
805 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
806 priv->qos_tbl_params.pcp_cos_map[
807 port_cfg->tc[tc].pcp[i]].tc = tc;
812 * The same logic goes with DSCP.
813 * First, set all map elements to "default".
815 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
816 priv->qos_tbl_params.dscp_cos_map[i].tc =
817 port_cfg->default_tc;
819 /* Fill in all known values. */
820 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
821 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
822 /* Better safe than sorry. */
824 "Too many DSCPs configured in TC %zu!", tc);
827 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
828 priv->qos_tbl_params.dscp_cos_map[
829 port_cfg->tc[tc].dscp[i]].tc = tc;
834 * Surprisingly, similar logic goes with queue mapping.
835 * We need only to store qid->tc mapping,
836 * to know TC when queue is read.
838 for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
839 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
841 /* Set up DPDKq->(TC,inq) mapping. */
842 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
843 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
846 "Too many RX queues configured per TC %zu!",
850 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
851 uint8_t idx = port_cfg->tc[tc].inq[i];
853 if (idx > RTE_DIM(priv->rxq_map)) {
854 MRVL_LOG(ERR, "Bad queue index %d!", idx);
858 priv->rxq_map[idx].tc = tc;
859 priv->rxq_map[idx].inq = i;
864 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
865 * with no gaps. Empty TC means end of processing.
867 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
868 if (port_cfg->tc[i].inqs == 0)
870 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
871 port_cfg->tc[i].inqs,
872 priv->bpool, port_cfg->tc[i].color);
875 priv->ppio_params.inqs_params.num_tcs = i;
877 if (port_cfg->setup_policer)
878 return setup_policer(priv, &port_cfg->policer_params);
884 * Configure TX Queues in a given port.
886 * Sets up TX queues egress scheduler and limiter.
888 * @param priv Port's private data
889 * @param portid DPDK port ID
890 * @param max_queues Maximum number of queues to configure.
891 * @returns 0 in case of success, negative value otherwise.
894 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
897 /* We need only a subset of configuration. */
898 struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
901 if (mrvl_cfg == NULL)
904 priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable;
905 if (port_cfg->rate_limit_enable)
906 priv->ppio_params.rate_limit_params =
907 port_cfg->rate_limit_params;
909 for (i = 0; i < max_queues; i++) {
910 struct pp2_ppio_outq_params *params =
911 &priv->ppio_params.outqs_params.outqs_params[i];
913 params->sched_mode = port_cfg->outq[i].sched_mode;
914 params->weight = port_cfg->outq[i].weight;
915 params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable;
916 params->rate_limit_params = port_cfg->outq[i].rate_limit_params;
925 * Finalize QoS table configuration and initialize it in SDK. It can be done
926 * only after port is started, so we have a valid ppio reference.
928 * @param priv Port's private (configuration) data.
929 * @returns 0 in case of success, exits otherwise.
932 mrvl_start_qos_mapping(struct mrvl_priv *priv)
936 if (priv->ppio == NULL) {
937 MRVL_LOG(ERR, "ppio must not be NULL here!");
941 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
942 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
944 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
945 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
947 /* Initialize Classifier QoS table. */
949 return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);