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_DEFAULT_TC "default_tc"
23 #define MRVL_TOK_DSCP "dscp"
24 #define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
25 #define MRVL_TOK_IP "ip"
26 #define MRVL_TOK_IP_VLAN "ip/vlan"
27 #define MRVL_TOK_PCP "pcp"
28 #define MRVL_TOK_PORT "port"
29 #define MRVL_TOK_RXQ "rxq"
30 #define MRVL_TOK_TC "tc"
31 #define MRVL_TOK_TXQ "txq"
32 #define MRVL_TOK_VLAN "vlan"
33 #define MRVL_TOK_VLAN_IP "vlan/ip"
35 /* egress specific configuration tokens */
36 #define MRVL_TOK_BURST_SIZE "burst_size"
37 #define MRVL_TOK_RATE_LIMIT "rate_limit"
38 #define MRVL_TOK_RATE_LIMIT_ENABLE "rate_limit_enable"
39 #define MRVL_TOK_SCHED_MODE "sched_mode"
40 #define MRVL_TOK_SCHED_MODE_SP "sp"
41 #define MRVL_TOK_SCHED_MODE_WRR "wrr"
42 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
44 /* policer specific configuration tokens */
45 #define MRVL_TOK_PLCR "policer"
46 #define MRVL_TOK_PLCR_DEFAULT "default_policer"
47 #define MRVL_TOK_PLCR_UNIT "token_unit"
48 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
49 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
50 #define MRVL_TOK_PLCR_COLOR "color_mode"
51 #define MRVL_TOK_PLCR_COLOR_BLIND "blind"
52 #define MRVL_TOK_PLCR_COLOR_AWARE "aware"
53 #define MRVL_TOK_PLCR_CIR "cir"
54 #define MRVL_TOK_PLCR_CBS "cbs"
55 #define MRVL_TOK_PLCR_EBS "ebs"
56 #define MRVL_TOK_PLCR_DEFAULT_COLOR "default_color"
57 #define MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN "green"
58 #define MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW "yellow"
59 #define MRVL_TOK_PLCR_DEFAULT_COLOR_RED "red"
61 /** Number of tokens in range a-b = 2. */
62 #define MAX_RNG_TOKENS 2
64 /** Maximum possible value of PCP. */
67 /** Maximum possible value of DSCP. */
70 /** Global QoS configuration. */
71 struct mrvl_qos_cfg *mrvl_qos_cfg;
74 * Convert string to uint32_t with extra checks for result correctness.
76 * @param string String to convert.
77 * @param val Conversion result.
78 * @returns 0 in case of success, negative value otherwise.
81 get_val_securely(const char *string, uint32_t *val)
84 size_t len = strlen(string);
90 *val = strtoul(string, &endptr, 0);
91 if (errno != 0 || RTE_PTR_DIFF(endptr, string) != len)
98 * Read out-queue configuration from file.
100 * @param file Path to the configuration file.
101 * @param port Port number.
102 * @param outq Out queue number.
103 * @param cfg Pointer to the Marvell QoS configuration structure.
104 * @returns 0 in case of success, negative value otherwise.
107 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
108 struct mrvl_qos_cfg *cfg)
114 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
115 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
117 /* Skip non-existing */
118 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
121 /* Read scheduling mode */
122 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE);
124 if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP,
125 strlen(MRVL_TOK_SCHED_MODE_SP))) {
126 cfg->port[port].outq[outq].sched_mode =
128 } else if (!strncmp(entry, MRVL_TOK_SCHED_MODE_WRR,
129 strlen(MRVL_TOK_SCHED_MODE_WRR))) {
130 cfg->port[port].outq[outq].sched_mode =
131 PP2_PPIO_SCHED_M_WRR;
133 MRVL_LOG(ERR, "Unknown token: %s", entry);
138 /* Read wrr weight */
139 if (cfg->port[port].outq[outq].sched_mode == PP2_PPIO_SCHED_M_WRR) {
140 entry = rte_cfgfile_get_entry(file, sec_name,
141 MRVL_TOK_WRR_WEIGHT);
143 if (get_val_securely(entry, &val) < 0)
145 cfg->port[port].outq[outq].weight = val;
150 * There's no point in setting rate limiting for specific outq as
151 * global port rate limiting has priority.
153 if (cfg->port[port].rate_limit_enable) {
154 MRVL_LOG(WARNING, "Port %d rate limiting already enabled",
159 entry = rte_cfgfile_get_entry(file, sec_name,
160 MRVL_TOK_RATE_LIMIT_ENABLE);
162 if (get_val_securely(entry, &val) < 0)
164 cfg->port[port].outq[outq].rate_limit_enable = val;
167 if (!cfg->port[port].outq[outq].rate_limit_enable)
170 /* Read CBS (in kB) */
171 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE);
173 if (get_val_securely(entry, &val) < 0)
175 cfg->port[port].outq[outq].rate_limit_params.cbs = val;
178 /* Read CIR (in kbps) */
179 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT);
181 if (get_val_securely(entry, &val) < 0)
183 cfg->port[port].outq[outq].rate_limit_params.cir = val;
190 * Gets multiple-entry values and places them in table.
192 * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
193 * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
194 * As all result table's elements are always 1-byte long, we
195 * won't overcomplicate the function, but we'll keep API generic,
196 * check if someone hasn't changed element size and make it simple
197 * to extend to other sizes.
199 * This function is purely utilitary, it does not print any error, only returns
200 * different error numbers.
202 * @param entry[in] Values string to parse.
203 * @param tab[out] Results table.
204 * @param elem_sz[in] Element size (in bytes).
205 * @param max_elems[in] Number of results table elements available.
206 * @param max val[in] Maximum value allowed.
207 * @returns Number of correctly parsed elements in case of success.
208 * @retval -1 Wrong element size.
209 * @retval -2 More tokens than result table allows.
210 * @retval -3 Wrong range syntax.
211 * @retval -4 Wrong range values.
212 * @retval -5 Maximum value exceeded.
215 get_entry_values(const char *entry, uint8_t *tab,
216 size_t elem_sz, uint8_t max_elems, uint8_t max_val)
218 /* There should not be more tokens than max elements.
219 * Add 1 for error trap.
221 char *tokens[max_elems + 1];
223 /* Begin, End + error trap = 3. */
224 char *rng_tokens[MAX_RNG_TOKENS + 1];
227 int nb_tokens, nb_rng_tokens;
231 char entry_cpy[CFG_VALUE_LEN];
236 /* Copy the entry to safely use rte_strsplit(). */
237 strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
240 * If there are more tokens than array size, rte_strsplit will
241 * not return error, just array size.
243 nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
244 tokens, max_elems + 1, ' ');
246 /* Quick check, will be refined later. */
247 if (nb_tokens > max_elems)
250 for (i = 0; i < nb_tokens; ++i) {
251 if (strchr(tokens[i], '-') != NULL) {
253 * Split to begin and end tokens.
254 * We want to catch error cases too, thus we leave
255 * option for number of tokens to be more than 2.
257 nb_rng_tokens = rte_strsplit(tokens[i],
258 strlen(tokens[i]), rng_tokens,
259 RTE_DIM(rng_tokens), '-');
260 if (nb_rng_tokens != 2)
263 /* Range and sanity checks. */
264 if (get_val_securely(rng_tokens[0], &token_val) < 0)
266 beg = (char)token_val;
267 if (get_val_securely(rng_tokens[1], &token_val) < 0)
269 end = (char)token_val;
270 if (beg < 0 || beg > UCHAR_MAX ||
271 end < 0 || end > UCHAR_MAX || end < beg)
274 for (val = beg; val <= end; ++val) {
279 tab = RTE_PTR_ADD(tab, elem_sz);
281 if (values >= max_elems)
286 if (get_val_securely(tokens[i], &token_val) < 0)
288 val = (char)token_val;
293 tab = RTE_PTR_ADD(tab, elem_sz);
295 if (values >= max_elems)
304 * Parse Traffic Class'es mapping configuration.
306 * @param file Config file handle.
307 * @param port Which port to look for.
308 * @param tc Which Traffic Class to look for.
309 * @param cfg[out] Parsing results.
310 * @returns 0 in case of success, negative value otherwise.
313 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
314 struct mrvl_qos_cfg *cfg)
320 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
321 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
323 /* Skip non-existing */
324 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
327 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
329 n = get_entry_values(entry,
330 cfg->port[port].tc[tc].inq,
331 sizeof(cfg->port[port].tc[tc].inq[0]),
332 RTE_DIM(cfg->port[port].tc[tc].inq),
335 MRVL_LOG(ERR, "Error %d while parsing: %s",
339 cfg->port[port].tc[tc].inqs = n;
342 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
344 n = get_entry_values(entry,
345 cfg->port[port].tc[tc].pcp,
346 sizeof(cfg->port[port].tc[tc].pcp[0]),
347 RTE_DIM(cfg->port[port].tc[tc].pcp),
350 MRVL_LOG(ERR, "Error %d while parsing: %s",
354 cfg->port[port].tc[tc].pcps = n;
357 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
359 n = get_entry_values(entry,
360 cfg->port[port].tc[tc].dscp,
361 sizeof(cfg->port[port].tc[tc].dscp[0]),
362 RTE_DIM(cfg->port[port].tc[tc].dscp),
365 MRVL_LOG(ERR, "Error %d while parsing: %s",
369 cfg->port[port].tc[tc].dscps = n;
372 if (!cfg->port[port].setup_policer)
375 entry = rte_cfgfile_get_entry(file, sec_name,
376 MRVL_TOK_PLCR_DEFAULT_COLOR);
378 if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN,
379 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN))) {
380 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_GREEN;
381 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW,
382 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW))) {
383 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_YELLOW;
384 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_RED,
385 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_RED))) {
386 cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_RED;
388 MRVL_LOG(ERR, "Error while parsing: %s", entry);
397 * Parse default port policer.
399 * @param file Config file handle.
400 * @param sec_name Section name with policer configuration
401 * @param port Port number.
402 * @param cfg[out] Parsing results.
403 * @returns 0 in case of success, negative value otherwise.
406 parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
407 struct mrvl_qos_cfg *cfg)
412 /* Read policer token unit */
413 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
415 if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
416 sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
417 cfg->port[port].policer_params.token_unit =
418 PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
419 } else if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_PACKETS,
420 sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
421 cfg->port[port].policer_params.token_unit =
422 PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
424 RTE_LOG(ERR, PMD, "Unknown token: %s\n", entry);
429 /* Read policer color mode */
430 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
432 if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
433 sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
434 cfg->port[port].policer_params.color_mode =
435 PP2_CLS_PLCR_COLOR_BLIND_MODE;
436 } else if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_AWARE,
437 sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
438 cfg->port[port].policer_params.color_mode =
439 PP2_CLS_PLCR_COLOR_AWARE_MODE;
441 RTE_LOG(ERR, PMD, "Error in parsing: %s\n", entry);
446 /* Read policer cir */
447 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
449 if (get_val_securely(entry, &val) < 0)
451 cfg->port[port].policer_params.cir = val;
454 /* Read policer cbs */
455 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
457 if (get_val_securely(entry, &val) < 0)
459 cfg->port[port].policer_params.cbs = val;
462 /* Read policer ebs */
463 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
465 if (get_val_securely(entry, &val) < 0)
467 cfg->port[port].policer_params.ebs = val;
470 cfg->port[port].setup_policer = 1;
476 * Parse QoS configuration - rte_kvargs_process handler.
478 * Opens configuration file and parses its content.
481 * @param path Path to config file.
482 * @param extra_args Pointer to configuration structure.
483 * @returns 0 in case of success, exits otherwise.
486 mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
489 struct mrvl_qos_cfg **cfg = extra_args;
490 struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
497 rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path);
499 /* Create configuration. This is never accessed on the fast path,
500 * so we can ignore socket.
502 *cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
504 rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n",
507 n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
508 sizeof(MRVL_TOK_PORT) - 1);
511 /* This is weird, but not bad. */
512 MRVL_LOG(WARNING, "Empty configuration file?");
516 /* Use the number of ports given as vdev parameters. */
517 for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
518 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
519 MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
521 /* Skip ports non-existing in configuration. */
522 if (rte_cfgfile_num_sections(file, sec_name,
523 strlen(sec_name)) <= 0) {
524 (*cfg)->port[n].use_global_defaults = 1;
525 (*cfg)->port[n].mapping_priority =
526 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
530 entry = rte_cfgfile_get_entry(file, sec_name,
531 MRVL_TOK_DEFAULT_TC);
533 if (get_val_securely(entry, &val) < 0 ||
536 (*cfg)->port[n].default_tc = (uint8_t)val;
539 "Default Traffic Class required in custom configuration!");
544 * Read per-port rate limiting. Setting that will
545 * disable per-queue rate limiting.
547 entry = rte_cfgfile_get_entry(file, sec_name,
548 MRVL_TOK_RATE_LIMIT_ENABLE);
550 if (get_val_securely(entry, &val) < 0)
552 (*cfg)->port[n].rate_limit_enable = val;
555 if ((*cfg)->port[n].rate_limit_enable) {
556 entry = rte_cfgfile_get_entry(file, sec_name,
557 MRVL_TOK_BURST_SIZE);
559 if (get_val_securely(entry, &val) < 0)
561 (*cfg)->port[n].rate_limit_params.cbs = val;
564 entry = rte_cfgfile_get_entry(file, sec_name,
565 MRVL_TOK_RATE_LIMIT);
567 if (get_val_securely(entry, &val) < 0)
569 (*cfg)->port[n].rate_limit_params.cir = val;
573 entry = rte_cfgfile_get_entry(file, sec_name,
574 MRVL_TOK_MAPPING_PRIORITY);
576 if (!strncmp(entry, MRVL_TOK_VLAN_IP,
577 sizeof(MRVL_TOK_VLAN_IP)))
578 (*cfg)->port[n].mapping_priority =
579 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
580 else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
581 sizeof(MRVL_TOK_IP_VLAN)))
582 (*cfg)->port[n].mapping_priority =
583 PP2_CLS_QOS_TBL_IP_VLAN_PRI;
584 else if (!strncmp(entry, MRVL_TOK_IP,
585 sizeof(MRVL_TOK_IP)))
586 (*cfg)->port[n].mapping_priority =
587 PP2_CLS_QOS_TBL_IP_PRI;
588 else if (!strncmp(entry, MRVL_TOK_VLAN,
589 sizeof(MRVL_TOK_VLAN)))
590 (*cfg)->port[n].mapping_priority =
591 PP2_CLS_QOS_TBL_VLAN_PRI;
593 rte_exit(EXIT_FAILURE,
594 "Error in parsing %s value (%s)!\n",
595 MRVL_TOK_MAPPING_PRIORITY, entry);
597 (*cfg)->port[n].mapping_priority =
598 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
601 /* Parse policer configuration (if any) */
602 entry = rte_cfgfile_get_entry(file, sec_name,
603 MRVL_TOK_PLCR_DEFAULT);
605 if (get_val_securely(entry, &val) < 0)
608 snprintf(sec_name, sizeof(sec_name), "%s %d",
610 ret = parse_policer(file, n, sec_name, *cfg);
615 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
616 ret = get_outq_cfg(file, n, i, *cfg);
618 rte_exit(EXIT_FAILURE,
619 "Error %d parsing port %d outq %d!\n",
623 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
624 ret = parse_tc_cfg(file, n, i, *cfg);
626 rte_exit(EXIT_FAILURE,
627 "Error %d parsing port %d tc %d!\n",
636 * Setup Traffic Class.
638 * Fill in TC parameters in single MUSDK TC config entry.
639 * @param param TC parameters entry.
640 * @param inqs Number of MUSDK in-queues in this TC.
641 * @param bpool Bpool for this TC.
642 * @param color Default color for this TC.
643 * @returns 0 in case of success, exits otherwise.
646 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
647 struct pp2_bpool *bpool, enum pp2_ppio_color color)
649 struct pp2_ppio_inq_params *inq_params;
651 param->pkt_offset = MRVL_PKT_OFFS;
652 param->pools[0] = bpool;
653 param->default_color = color;
655 inq_params = rte_zmalloc_socket("inq_params",
656 inqs * sizeof(*inq_params),
661 param->num_in_qs = inqs;
663 /* Release old config if necessary. */
664 if (param->inqs_params)
665 rte_free(param->inqs_params);
667 param->inqs_params = inq_params;
673 * Setup ingress policer.
675 * @param priv Port's private data.
676 * @param params Pointer to the policer's configuration.
677 * @param plcr_id Policer id.
678 * @returns 0 in case of success, negative values otherwise.
681 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
687 * At this point no other policers are used which means
688 * any policer can be picked up and used as a default one.
692 sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
693 params->match = match;
695 ret = pp2_cls_plcr_init(params, &priv->default_policer);
697 MRVL_LOG(ERR, "Failed to setup %s", match);
701 priv->ppio_params.inqs_params.plcr = priv->default_policer;
702 priv->used_plcrs = BIT(0);
708 * Configure RX Queues in a given port.
710 * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
712 * @param priv Port's private data
713 * @param portid DPDK port ID
714 * @param max_queues Maximum number of queues to configure.
715 * @returns 0 in case of success, negative value otherwise.
718 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
723 if (mrvl_qos_cfg == NULL ||
724 mrvl_qos_cfg->port[portid].use_global_defaults) {
726 * No port configuration, use default: 1 TC, no QoS,
727 * TC color set to green.
729 priv->ppio_params.inqs_params.num_tcs = 1;
730 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
731 max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
733 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
734 for (i = 0; i < max_queues; ++i) {
735 priv->rxq_map[i].tc = 0;
736 priv->rxq_map[i].inq = i;
741 /* We need only a subset of configuration. */
742 struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
744 priv->qos_tbl_params.type = port_cfg->mapping_priority;
747 * We need to reverse mapping, from tc->pcp (better from usability
748 * point of view) to pcp->tc (configurable in MUSDK).
749 * First, set all map elements to "default".
751 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
752 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
754 /* Then, fill in all known values. */
755 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
756 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
757 /* Better safe than sorry. */
759 "Too many PCPs configured in TC %zu!", tc);
762 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
763 priv->qos_tbl_params.pcp_cos_map[
764 port_cfg->tc[tc].pcp[i]].tc = tc;
769 * The same logic goes with DSCP.
770 * First, set all map elements to "default".
772 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
773 priv->qos_tbl_params.dscp_cos_map[i].tc =
774 port_cfg->default_tc;
776 /* Fill in all known values. */
777 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
778 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
779 /* Better safe than sorry. */
781 "Too many DSCPs configured in TC %zu!", tc);
784 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
785 priv->qos_tbl_params.dscp_cos_map[
786 port_cfg->tc[tc].dscp[i]].tc = tc;
791 * Surprisingly, similar logic goes with queue mapping.
792 * We need only to store qid->tc mapping,
793 * to know TC when queue is read.
795 for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
796 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
798 /* Set up DPDKq->(TC,inq) mapping. */
799 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
800 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
803 "Too many RX queues configured per TC %zu!",
807 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
808 uint8_t idx = port_cfg->tc[tc].inq[i];
810 if (idx > RTE_DIM(priv->rxq_map)) {
811 MRVL_LOG(ERR, "Bad queue index %d!", idx);
815 priv->rxq_map[idx].tc = tc;
816 priv->rxq_map[idx].inq = i;
821 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
822 * with no gaps. Empty TC means end of processing.
824 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
825 if (port_cfg->tc[i].inqs == 0)
827 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
828 port_cfg->tc[i].inqs,
829 priv->bpool, port_cfg->tc[i].color);
832 priv->ppio_params.inqs_params.num_tcs = i;
834 if (port_cfg->setup_policer)
835 return setup_policer(priv, &port_cfg->policer_params);
841 * Configure TX Queues in a given port.
843 * Sets up TX queues egress scheduler and limiter.
845 * @param priv Port's private data
846 * @param portid DPDK port ID
847 * @param max_queues Maximum number of queues to configure.
848 * @returns 0 in case of success, negative value otherwise.
851 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
854 /* We need only a subset of configuration. */
855 struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
858 if (mrvl_qos_cfg == NULL)
861 priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable;
862 if (port_cfg->rate_limit_enable)
863 priv->ppio_params.rate_limit_params =
864 port_cfg->rate_limit_params;
866 for (i = 0; i < max_queues; i++) {
867 struct pp2_ppio_outq_params *params =
868 &priv->ppio_params.outqs_params.outqs_params[i];
870 params->sched_mode = port_cfg->outq[i].sched_mode;
871 params->weight = port_cfg->outq[i].weight;
872 params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable;
873 params->rate_limit_params = port_cfg->outq[i].rate_limit_params;
882 * Finalize QoS table configuration and initialize it in SDK. It can be done
883 * only after port is started, so we have a valid ppio reference.
885 * @param priv Port's private (configuration) data.
886 * @returns 0 in case of success, exits otherwise.
889 mrvl_start_qos_mapping(struct mrvl_priv *priv)
893 if (priv->ppio == NULL) {
894 MRVL_LOG(ERR, "ppio must not be NULL here!");
898 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
899 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
901 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
902 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
904 /* Initialize Classifier QoS table. */
906 return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);