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 QoS configuration. */
75 struct mrvl_qos_cfg *mrvl_qos_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 QoS 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_qos_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_qos_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_qos_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 QoS 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_qoscfg(const char *key __rte_unused, const char *path,
494 struct mrvl_qos_cfg **cfg = extra_args;
495 struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
502 MRVL_LOG(ERR, "Cannot load configuration %s\n", path);
506 /* Create configuration. This is never accessed on the fast path,
507 * so we can ignore socket.
509 *cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
511 MRVL_LOG(ERR, "Cannot allocate configuration %s\n", path);
515 n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
516 sizeof(MRVL_TOK_PORT) - 1);
519 /* This is weird, but not bad. */
520 MRVL_LOG(WARNING, "Empty configuration file?");
524 /* Use the number of ports given as vdev parameters. */
525 for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
526 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
527 MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
529 /* Use global defaults, unless an override occurs */
530 (*cfg)->port[n].use_global_defaults = 1;
532 /* Skip ports non-existing in configuration. */
533 if (rte_cfgfile_num_sections(file, sec_name,
534 strlen(sec_name)) <= 0) {
538 entry = rte_cfgfile_get_entry(file, sec_name,
541 if (!strncmp(entry, MRVL_TOK_DSA_MODE_NONE,
542 sizeof(MRVL_TOK_DSA_MODE_NONE)))
543 (*cfg)->port[n].eth_start_hdr =
545 else if (!strncmp(entry, MRVL_TOK_DSA_MODE_DSA,
546 sizeof(MRVL_TOK_DSA_MODE_DSA)))
547 (*cfg)->port[n].eth_start_hdr =
548 PP2_PPIO_HDR_ETH_DSA;
549 else if (!strncmp(entry, MRVL_TOK_DSA_MODE_EXT_DSA,
550 sizeof(MRVL_TOK_DSA_MODE_EXT_DSA))) {
551 (*cfg)->port[n].eth_start_hdr =
552 PP2_PPIO_HDR_ETH_EXT_DSA;
555 "Error in parsing %s value (%s)!\n",
556 MRVL_TOK_DSA_MODE, entry);
560 (*cfg)->port[n].eth_start_hdr = PP2_PPIO_HDR_ETH;
564 * Read per-port rate limiting. Setting that will
565 * disable per-queue rate limiting.
567 entry = rte_cfgfile_get_entry(file, sec_name,
568 MRVL_TOK_RATE_LIMIT_ENABLE);
570 if (get_val_securely(entry, &val) < 0)
572 (*cfg)->port[n].rate_limit_enable = val;
575 if ((*cfg)->port[n].rate_limit_enable) {
576 entry = rte_cfgfile_get_entry(file, sec_name,
577 MRVL_TOK_BURST_SIZE);
579 if (get_val_securely(entry, &val) < 0)
581 (*cfg)->port[n].rate_limit_params.cbs = val;
584 entry = rte_cfgfile_get_entry(file, sec_name,
585 MRVL_TOK_RATE_LIMIT);
587 if (get_val_securely(entry, &val) < 0)
589 (*cfg)->port[n].rate_limit_params.cir = val;
593 entry = rte_cfgfile_get_entry(file, sec_name,
594 MRVL_TOK_MAPPING_PRIORITY);
596 (*cfg)->port[n].use_global_defaults = 0;
597 if (!strncmp(entry, MRVL_TOK_VLAN_IP,
598 sizeof(MRVL_TOK_VLAN_IP)))
599 (*cfg)->port[n].mapping_priority =
600 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
601 else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
602 sizeof(MRVL_TOK_IP_VLAN)))
603 (*cfg)->port[n].mapping_priority =
604 PP2_CLS_QOS_TBL_IP_VLAN_PRI;
605 else if (!strncmp(entry, MRVL_TOK_IP,
606 sizeof(MRVL_TOK_IP)))
607 (*cfg)->port[n].mapping_priority =
608 PP2_CLS_QOS_TBL_IP_PRI;
609 else if (!strncmp(entry, MRVL_TOK_VLAN,
610 sizeof(MRVL_TOK_VLAN))) {
611 (*cfg)->port[n].mapping_priority =
612 PP2_CLS_QOS_TBL_VLAN_PRI;
615 "Error in parsing %s value (%s)!\n",
616 MRVL_TOK_MAPPING_PRIORITY, entry);
620 (*cfg)->port[n].mapping_priority =
621 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
624 /* Parse policer configuration (if any) */
625 entry = rte_cfgfile_get_entry(file, sec_name,
626 MRVL_TOK_PLCR_DEFAULT);
628 (*cfg)->port[n].use_global_defaults = 0;
629 if (get_val_securely(entry, &val) < 0)
632 snprintf(sec_name, sizeof(sec_name), "%s %d",
634 ret = parse_policer(file, n, sec_name, *cfg);
639 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
640 ret = get_outq_cfg(file, n, i, *cfg);
643 "Error %d parsing port %d outq %d!\n",
649 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
650 ret = parse_tc_cfg(file, n, i, *cfg);
653 "Error %d parsing port %d tc %d!\n",
659 entry = rte_cfgfile_get_entry(file, sec_name,
660 MRVL_TOK_DEFAULT_TC);
662 if (get_val_securely(entry, &val) < 0 ||
665 (*cfg)->port[n].default_tc = (uint8_t)val;
667 if ((*cfg)->port[n].use_global_defaults == 0) {
669 "Default Traffic Class required in "
670 "custom configuration!");
680 * Setup Traffic Class.
682 * Fill in TC parameters in single MUSDK TC config entry.
683 * @param param TC parameters entry.
684 * @param inqs Number of MUSDK in-queues in this TC.
685 * @param bpool Bpool for this TC.
686 * @param color Default color for this TC.
687 * @returns 0 in case of success, exits otherwise.
690 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
691 struct pp2_bpool *bpool, enum pp2_ppio_color color)
693 struct pp2_ppio_inq_params *inq_params;
695 param->pkt_offset = MRVL_PKT_OFFS;
696 param->pools[0][0] = bpool;
697 param->default_color = color;
699 inq_params = rte_zmalloc_socket("inq_params",
700 inqs * sizeof(*inq_params),
705 param->num_in_qs = inqs;
707 /* Release old config if necessary. */
708 if (param->inqs_params)
709 rte_free(param->inqs_params);
711 param->inqs_params = inq_params;
717 * Setup ingress policer.
719 * @param priv Port's private data.
720 * @param params Pointer to the policer's configuration.
721 * @param plcr_id Policer id.
722 * @returns 0 in case of success, negative values otherwise.
725 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
731 * At this point no other policers are used which means
732 * any policer can be picked up and used as a default one.
736 sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
737 params->match = match;
739 ret = pp2_cls_plcr_init(params, &priv->default_policer);
741 MRVL_LOG(ERR, "Failed to setup %s", match);
745 priv->ppio_params.inqs_params.plcr = priv->default_policer;
746 priv->used_plcrs = BIT(0);
752 * Configure RX Queues in a given port.
754 * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
756 * @param priv Port's private data
757 * @param portid DPDK port ID
758 * @param max_queues Maximum number of queues to configure.
759 * @returns 0 in case of success, negative value otherwise.
762 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
767 if (mrvl_qos_cfg == NULL ||
768 mrvl_qos_cfg->port[portid].use_global_defaults) {
770 * No port configuration, use default: 1 TC, no QoS,
771 * TC color set to green.
773 priv->ppio_params.inqs_params.num_tcs = 1;
774 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
775 max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
777 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
778 for (i = 0; i < max_queues; ++i) {
779 priv->rxq_map[i].tc = 0;
780 priv->rxq_map[i].inq = i;
785 /* We need only a subset of configuration. */
786 struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
788 priv->qos_tbl_params.type = port_cfg->mapping_priority;
791 * We need to reverse mapping, from tc->pcp (better from usability
792 * point of view) to pcp->tc (configurable in MUSDK).
793 * First, set all map elements to "default".
795 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
796 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
798 /* Then, fill in all known values. */
799 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
800 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
801 /* Better safe than sorry. */
803 "Too many PCPs configured in TC %zu!", tc);
806 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
807 priv->qos_tbl_params.pcp_cos_map[
808 port_cfg->tc[tc].pcp[i]].tc = tc;
813 * The same logic goes with DSCP.
814 * First, set all map elements to "default".
816 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
817 priv->qos_tbl_params.dscp_cos_map[i].tc =
818 port_cfg->default_tc;
820 /* Fill in all known values. */
821 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
822 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
823 /* Better safe than sorry. */
825 "Too many DSCPs configured in TC %zu!", tc);
828 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
829 priv->qos_tbl_params.dscp_cos_map[
830 port_cfg->tc[tc].dscp[i]].tc = tc;
835 * Surprisingly, similar logic goes with queue mapping.
836 * We need only to store qid->tc mapping,
837 * to know TC when queue is read.
839 for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
840 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
842 /* Set up DPDKq->(TC,inq) mapping. */
843 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
844 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
847 "Too many RX queues configured per TC %zu!",
851 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
852 uint8_t idx = port_cfg->tc[tc].inq[i];
854 if (idx > RTE_DIM(priv->rxq_map)) {
855 MRVL_LOG(ERR, "Bad queue index %d!", idx);
859 priv->rxq_map[idx].tc = tc;
860 priv->rxq_map[idx].inq = i;
865 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
866 * with no gaps. Empty TC means end of processing.
868 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
869 if (port_cfg->tc[i].inqs == 0)
871 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
872 port_cfg->tc[i].inqs,
873 priv->bpool, port_cfg->tc[i].color);
876 priv->ppio_params.inqs_params.num_tcs = i;
878 if (port_cfg->setup_policer)
879 return setup_policer(priv, &port_cfg->policer_params);
885 * Configure TX Queues in a given port.
887 * Sets up TX queues egress scheduler and limiter.
889 * @param priv Port's private data
890 * @param portid DPDK port ID
891 * @param max_queues Maximum number of queues to configure.
892 * @returns 0 in case of success, negative value otherwise.
895 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
898 /* We need only a subset of configuration. */
899 struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
902 if (mrvl_qos_cfg == NULL)
905 priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable;
906 if (port_cfg->rate_limit_enable)
907 priv->ppio_params.rate_limit_params =
908 port_cfg->rate_limit_params;
910 for (i = 0; i < max_queues; i++) {
911 struct pp2_ppio_outq_params *params =
912 &priv->ppio_params.outqs_params.outqs_params[i];
914 params->sched_mode = port_cfg->outq[i].sched_mode;
915 params->weight = port_cfg->outq[i].weight;
916 params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable;
917 params->rate_limit_params = port_cfg->outq[i].rate_limit_params;
926 * Finalize QoS table configuration and initialize it in SDK. It can be done
927 * only after port is started, so we have a valid ppio reference.
929 * @param priv Port's private (configuration) data.
930 * @returns 0 in case of success, exits otherwise.
933 mrvl_start_qos_mapping(struct mrvl_priv *priv)
937 if (priv->ppio == NULL) {
938 MRVL_LOG(ERR, "ppio must not be NULL here!");
942 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
943 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
945 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
946 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
948 /* Initialize Classifier QoS table. */
950 return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);