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>
18 /* Unluckily, container_of is defined by both DPDK and MUSDK,
19 * we'll declare only one version.
21 * Note that it is not used in this PMD anyway.
29 /* Parsing tokens. Defined conveniently, so that any correction is easy. */
30 #define MRVL_TOK_DEFAULT "default"
31 #define MRVL_TOK_DEFAULT_TC "default_tc"
32 #define MRVL_TOK_DSCP "dscp"
33 #define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
34 #define MRVL_TOK_IP "ip"
35 #define MRVL_TOK_IP_VLAN "ip/vlan"
36 #define MRVL_TOK_PCP "pcp"
37 #define MRVL_TOK_PORT "port"
38 #define MRVL_TOK_RXQ "rxq"
39 #define MRVL_TOK_TC "tc"
40 #define MRVL_TOK_TXQ "txq"
41 #define MRVL_TOK_VLAN "vlan"
42 #define MRVL_TOK_VLAN_IP "vlan/ip"
44 /* egress specific configuration tokens */
45 #define MRVL_TOK_BURST_SIZE "burst_size"
46 #define MRVL_TOK_RATE_LIMIT "rate_limit"
47 #define MRVL_TOK_RATE_LIMIT_ENABLE "rate_limit_enable"
48 #define MRVL_TOK_SCHED_MODE "sched_mode"
49 #define MRVL_TOK_SCHED_MODE_SP "sp"
50 #define MRVL_TOK_SCHED_MODE_WRR "wrr"
51 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
53 /* policer specific configuration tokens */
54 #define MRVL_TOK_PLCR_ENABLE "policer_enable"
55 #define MRVL_TOK_PLCR_UNIT "token_unit"
56 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
57 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
58 #define MRVL_TOK_PLCR_COLOR "color_mode"
59 #define MRVL_TOK_PLCR_COLOR_BLIND "blind"
60 #define MRVL_TOK_PLCR_COLOR_AWARE "aware"
61 #define MRVL_TOK_PLCR_CIR "cir"
62 #define MRVL_TOK_PLCR_CBS "cbs"
63 #define MRVL_TOK_PLCR_EBS "ebs"
64 #define MRVL_TOK_PLCR_DEFAULT_COLOR "default_color"
65 #define MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN "green"
66 #define MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW "yellow"
67 #define MRVL_TOK_PLCR_DEFAULT_COLOR_RED "red"
69 /** Number of tokens in range a-b = 2. */
70 #define MAX_RNG_TOKENS 2
72 /** Maximum possible value of PCP. */
75 /** Maximum possible value of DSCP. */
78 /** Global QoS configuration. */
79 struct mrvl_qos_cfg *mrvl_qos_cfg;
82 * Convert string to uint32_t with extra checks for result correctness.
84 * @param string String to convert.
85 * @param val Conversion result.
86 * @returns 0 in case of success, negative value otherwise.
89 get_val_securely(const char *string, uint32_t *val)
92 size_t len = strlen(string);
98 *val = strtoul(string, &endptr, 0);
99 if (errno != 0 || RTE_PTR_DIFF(endptr, string) != len)
106 * Read out-queue configuration from file.
108 * @param file Path to the configuration file.
109 * @param port Port number.
110 * @param outq Out queue number.
111 * @param cfg Pointer to the Marvell QoS configuration structure.
112 * @returns 0 in case of success, negative value otherwise.
115 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
116 struct mrvl_qos_cfg *cfg)
122 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
123 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
125 /* Skip non-existing */
126 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
129 /* Read scheduling mode */
130 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE);
132 if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP,
133 strlen(MRVL_TOK_SCHED_MODE_SP))) {
134 cfg->port[port].outq[outq].sched_mode =
136 } else if (!strncmp(entry, MRVL_TOK_SCHED_MODE_WRR,
137 strlen(MRVL_TOK_SCHED_MODE_WRR))) {
138 cfg->port[port].outq[outq].sched_mode =
139 PP2_PPIO_SCHED_M_WRR;
141 RTE_LOG(ERR, PMD, "Unknown token: %s\n", entry);
146 /* Read wrr weight */
147 if (cfg->port[port].outq[outq].sched_mode == PP2_PPIO_SCHED_M_WRR) {
148 entry = rte_cfgfile_get_entry(file, sec_name,
149 MRVL_TOK_WRR_WEIGHT);
151 if (get_val_securely(entry, &val) < 0)
153 cfg->port[port].outq[outq].weight = val;
158 * There's no point in setting rate limiting for specific outq as
159 * global port rate limiting has priority.
161 if (cfg->port[port].rate_limit_enable) {
162 RTE_LOG(WARNING, PMD, "Port %d rate limiting already enabled\n",
167 entry = rte_cfgfile_get_entry(file, sec_name,
168 MRVL_TOK_RATE_LIMIT_ENABLE);
170 if (get_val_securely(entry, &val) < 0)
172 cfg->port[port].outq[outq].rate_limit_enable = val;
175 if (!cfg->port[port].outq[outq].rate_limit_enable)
178 /* Read CBS (in kB) */
179 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE);
181 if (get_val_securely(entry, &val) < 0)
183 cfg->port[port].outq[outq].rate_limit_params.cbs = val;
186 /* Read CIR (in kbps) */
187 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT);
189 if (get_val_securely(entry, &val) < 0)
191 cfg->port[port].outq[outq].rate_limit_params.cir = val;
198 * Gets multiple-entry values and places them in table.
200 * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
201 * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
202 * As all result table's elements are always 1-byte long, we
203 * won't overcomplicate the function, but we'll keep API generic,
204 * check if someone hasn't changed element size and make it simple
205 * to extend to other sizes.
207 * This function is purely utilitary, it does not print any error, only returns
208 * different error numbers.
210 * @param entry[in] Values string to parse.
211 * @param tab[out] Results table.
212 * @param elem_sz[in] Element size (in bytes).
213 * @param max_elems[in] Number of results table elements available.
214 * @param max val[in] Maximum value allowed.
215 * @returns Number of correctly parsed elements in case of success.
216 * @retval -1 Wrong element size.
217 * @retval -2 More tokens than result table allows.
218 * @retval -3 Wrong range syntax.
219 * @retval -4 Wrong range values.
220 * @retval -5 Maximum value exceeded.
223 get_entry_values(const char *entry, uint8_t *tab,
224 size_t elem_sz, uint8_t max_elems, uint8_t max_val)
226 /* There should not be more tokens than max elements.
227 * Add 1 for error trap.
229 char *tokens[max_elems + 1];
231 /* Begin, End + error trap = 3. */
232 char *rng_tokens[MAX_RNG_TOKENS + 1];
235 int nb_tokens, nb_rng_tokens;
239 char entry_cpy[CFG_VALUE_LEN];
244 /* Copy the entry to safely use rte_strsplit(). */
245 strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
248 * If there are more tokens than array size, rte_strsplit will
249 * not return error, just array size.
251 nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
252 tokens, max_elems + 1, ' ');
254 /* Quick check, will be refined later. */
255 if (nb_tokens > max_elems)
258 for (i = 0; i < nb_tokens; ++i) {
259 if (strchr(tokens[i], '-') != NULL) {
261 * Split to begin and end tokens.
262 * We want to catch error cases too, thus we leave
263 * option for number of tokens to be more than 2.
265 nb_rng_tokens = rte_strsplit(tokens[i],
266 strlen(tokens[i]), rng_tokens,
267 RTE_DIM(rng_tokens), '-');
268 if (nb_rng_tokens != 2)
271 /* Range and sanity checks. */
272 if (get_val_securely(rng_tokens[0], &token_val) < 0)
274 beg = (char)token_val;
275 if (get_val_securely(rng_tokens[1], &token_val) < 0)
277 end = (char)token_val;
278 if (beg < 0 || beg > UCHAR_MAX ||
279 end < 0 || end > UCHAR_MAX || end < beg)
282 for (val = beg; val <= end; ++val) {
287 tab = RTE_PTR_ADD(tab, elem_sz);
289 if (values >= max_elems)
294 if (get_val_securely(tokens[i], &token_val) < 0)
296 val = (char)token_val;
301 tab = RTE_PTR_ADD(tab, elem_sz);
303 if (values >= max_elems)
312 * Parse Traffic Class'es mapping configuration.
314 * @param file Config file handle.
315 * @param port Which port to look for.
316 * @param tc Which Traffic Class to look for.
317 * @param cfg[out] Parsing results.
318 * @returns 0 in case of success, negative value otherwise.
321 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
322 struct mrvl_qos_cfg *cfg)
328 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
329 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
331 /* Skip non-existing */
332 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
335 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
337 n = get_entry_values(entry,
338 cfg->port[port].tc[tc].inq,
339 sizeof(cfg->port[port].tc[tc].inq[0]),
340 RTE_DIM(cfg->port[port].tc[tc].inq),
343 RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
347 cfg->port[port].tc[tc].inqs = n;
350 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
352 n = get_entry_values(entry,
353 cfg->port[port].tc[tc].pcp,
354 sizeof(cfg->port[port].tc[tc].pcp[0]),
355 RTE_DIM(cfg->port[port].tc[tc].pcp),
358 RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
362 cfg->port[port].tc[tc].pcps = n;
365 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
367 n = get_entry_values(entry,
368 cfg->port[port].tc[tc].dscp,
369 sizeof(cfg->port[port].tc[tc].dscp[0]),
370 RTE_DIM(cfg->port[port].tc[tc].dscp),
373 RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
377 cfg->port[port].tc[tc].dscps = n;
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 RTE_LOG(ERR, PMD, "Error while parsing: %s\n", entry);
402 * Parse QoS configuration - rte_kvargs_process handler.
404 * Opens configuration file and parses its content.
407 * @param path Path to config file.
408 * @param extra_args Pointer to configuration structure.
409 * @returns 0 in case of success, exits otherwise.
412 mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
415 struct mrvl_qos_cfg **cfg = extra_args;
416 struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
423 rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path);
425 /* Create configuration. This is never accessed on the fast path,
426 * so we can ignore socket.
428 *cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
430 rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n",
433 n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
434 sizeof(MRVL_TOK_PORT) - 1);
437 /* This is weird, but not bad. */
438 RTE_LOG(WARNING, PMD, "Empty configuration file?\n");
442 /* Use the number of ports given as vdev parameters. */
443 for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
444 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
445 MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
447 /* Skip ports non-existing in configuration. */
448 if (rte_cfgfile_num_sections(file, sec_name,
449 strlen(sec_name)) <= 0) {
450 (*cfg)->port[n].use_global_defaults = 1;
451 (*cfg)->port[n].mapping_priority =
452 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
456 entry = rte_cfgfile_get_entry(file, sec_name,
457 MRVL_TOK_DEFAULT_TC);
459 if (get_val_securely(entry, &val) < 0 ||
462 (*cfg)->port[n].default_tc = (uint8_t)val;
465 "Default Traffic Class required in custom configuration!\n");
469 entry = rte_cfgfile_get_entry(file, sec_name,
470 MRVL_TOK_PLCR_ENABLE);
472 if (get_val_securely(entry, &val) < 0)
474 (*cfg)->port[n].policer_enable = val;
477 if ((*cfg)->port[n].policer_enable) {
478 enum pp2_cls_plcr_token_unit unit;
480 /* Read policer token unit */
481 entry = rte_cfgfile_get_entry(file, sec_name,
484 if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
485 sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
486 unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
487 } else if (!strncmp(entry,
488 MRVL_TOK_PLCR_UNIT_PACKETS,
489 sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
490 unit = PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
492 RTE_LOG(ERR, PMD, "Unknown token: %s\n",
496 (*cfg)->port[n].policer_params.token_unit =
500 /* Read policer color mode */
501 entry = rte_cfgfile_get_entry(file, sec_name,
502 MRVL_TOK_PLCR_COLOR);
504 enum pp2_cls_plcr_color_mode mode;
506 if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
507 sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
508 mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
509 } else if (!strncmp(entry,
510 MRVL_TOK_PLCR_COLOR_AWARE,
511 sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
512 mode = PP2_CLS_PLCR_COLOR_AWARE_MODE;
515 "Error in parsing: %s\n",
519 (*cfg)->port[n].policer_params.color_mode =
523 /* Read policer cir */
524 entry = rte_cfgfile_get_entry(file, sec_name,
527 if (get_val_securely(entry, &val) < 0)
529 (*cfg)->port[n].policer_params.cir = val;
532 /* Read policer cbs */
533 entry = rte_cfgfile_get_entry(file, sec_name,
536 if (get_val_securely(entry, &val) < 0)
538 (*cfg)->port[n].policer_params.cbs = val;
541 /* Read policer ebs */
542 entry = rte_cfgfile_get_entry(file, sec_name,
545 if (get_val_securely(entry, &val) < 0)
547 (*cfg)->port[n].policer_params.ebs = val;
552 * Read per-port rate limiting. Setting that will
553 * disable per-queue rate limiting.
555 entry = rte_cfgfile_get_entry(file, sec_name,
556 MRVL_TOK_RATE_LIMIT_ENABLE);
558 if (get_val_securely(entry, &val) < 0)
560 (*cfg)->port[n].rate_limit_enable = val;
563 if ((*cfg)->port[n].rate_limit_enable) {
564 entry = rte_cfgfile_get_entry(file, sec_name,
565 MRVL_TOK_BURST_SIZE);
567 if (get_val_securely(entry, &val) < 0)
569 (*cfg)->port[n].rate_limit_params.cbs = val;
572 entry = rte_cfgfile_get_entry(file, sec_name,
573 MRVL_TOK_RATE_LIMIT);
575 if (get_val_securely(entry, &val) < 0)
577 (*cfg)->port[n].rate_limit_params.cir = val;
581 entry = rte_cfgfile_get_entry(file, sec_name,
582 MRVL_TOK_MAPPING_PRIORITY);
584 if (!strncmp(entry, MRVL_TOK_VLAN_IP,
585 sizeof(MRVL_TOK_VLAN_IP)))
586 (*cfg)->port[n].mapping_priority =
587 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
588 else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
589 sizeof(MRVL_TOK_IP_VLAN)))
590 (*cfg)->port[n].mapping_priority =
591 PP2_CLS_QOS_TBL_IP_VLAN_PRI;
592 else if (!strncmp(entry, MRVL_TOK_IP,
593 sizeof(MRVL_TOK_IP)))
594 (*cfg)->port[n].mapping_priority =
595 PP2_CLS_QOS_TBL_IP_PRI;
596 else if (!strncmp(entry, MRVL_TOK_VLAN,
597 sizeof(MRVL_TOK_VLAN)))
598 (*cfg)->port[n].mapping_priority =
599 PP2_CLS_QOS_TBL_VLAN_PRI;
601 rte_exit(EXIT_FAILURE,
602 "Error in parsing %s value (%s)!\n",
603 MRVL_TOK_MAPPING_PRIORITY, entry);
605 (*cfg)->port[n].mapping_priority =
606 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
609 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
610 ret = get_outq_cfg(file, n, i, *cfg);
612 rte_exit(EXIT_FAILURE,
613 "Error %d parsing port %d outq %d!\n",
617 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
618 ret = parse_tc_cfg(file, n, i, *cfg);
620 rte_exit(EXIT_FAILURE,
621 "Error %d parsing port %d tc %d!\n",
630 * Setup Traffic Class.
632 * Fill in TC parameters in single MUSDK TC config entry.
633 * @param param TC parameters entry.
634 * @param inqs Number of MUSDK in-queues in this TC.
635 * @param bpool Bpool for this TC.
636 * @param color Default color for this TC.
637 * @returns 0 in case of success, exits otherwise.
640 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
641 struct pp2_bpool *bpool, enum pp2_ppio_color color)
643 struct pp2_ppio_inq_params *inq_params;
645 param->pkt_offset = MRVL_PKT_OFFS;
646 param->pools[0] = bpool;
647 param->default_color = color;
649 inq_params = rte_zmalloc_socket("inq_params",
650 inqs * sizeof(*inq_params),
655 param->num_in_qs = inqs;
657 /* Release old config if necessary. */
658 if (param->inqs_params)
659 rte_free(param->inqs_params);
661 param->inqs_params = inq_params;
667 * Setup ingress policer.
669 * @param priv Port's private data.
670 * @param params Pointer to the policer's configuration.
671 * @returns 0 in case of success, negative values otherwise.
674 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
679 snprintf(match, sizeof(match), "policer-%d:%d\n",
680 priv->pp_id, priv->ppio_id);
681 params->match = match;
683 ret = pp2_cls_plcr_init(params, &priv->policer);
685 RTE_LOG(ERR, PMD, "Failed to setup %s\n", match);
689 priv->ppio_params.inqs_params.plcr = priv->policer;
695 * Configure RX Queues in a given port.
697 * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
699 * @param priv Port's private data
700 * @param portid DPDK port ID
701 * @param max_queues Maximum number of queues to configure.
702 * @returns 0 in case of success, negative value otherwise.
705 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
710 if (mrvl_qos_cfg == NULL ||
711 mrvl_qos_cfg->port[portid].use_global_defaults) {
713 * No port configuration, use default: 1 TC, no QoS,
714 * TC color set to green.
716 priv->ppio_params.inqs_params.num_tcs = 1;
717 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
718 max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
720 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
721 for (i = 0; i < max_queues; ++i) {
722 priv->rxq_map[i].tc = 0;
723 priv->rxq_map[i].inq = i;
728 /* We need only a subset of configuration. */
729 struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
731 priv->qos_tbl_params.type = port_cfg->mapping_priority;
734 * We need to reverse mapping, from tc->pcp (better from usability
735 * point of view) to pcp->tc (configurable in MUSDK).
736 * First, set all map elements to "default".
738 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
739 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
741 /* Then, fill in all known values. */
742 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
743 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
744 /* Better safe than sorry. */
746 "Too many PCPs configured in TC %zu!\n", tc);
749 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
750 priv->qos_tbl_params.pcp_cos_map[
751 port_cfg->tc[tc].pcp[i]].tc = tc;
756 * The same logic goes with DSCP.
757 * First, set all map elements to "default".
759 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
760 priv->qos_tbl_params.dscp_cos_map[i].tc =
761 port_cfg->default_tc;
763 /* Fill in all known values. */
764 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
765 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
766 /* Better safe than sorry. */
768 "Too many DSCPs configured in TC %zu!\n", tc);
771 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
772 priv->qos_tbl_params.dscp_cos_map[
773 port_cfg->tc[tc].dscp[i]].tc = tc;
778 * Surprisingly, similar logic goes with queue mapping.
779 * We need only to store qid->tc mapping,
780 * to know TC when queue is read.
782 for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
783 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
785 /* Set up DPDKq->(TC,inq) mapping. */
786 for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
787 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
790 "Too many RX queues configured per TC %zu!\n",
794 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
795 uint8_t idx = port_cfg->tc[tc].inq[i];
797 if (idx > RTE_DIM(priv->rxq_map)) {
798 RTE_LOG(ERR, PMD, "Bad queue index %d!\n", idx);
802 priv->rxq_map[idx].tc = tc;
803 priv->rxq_map[idx].inq = i;
808 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
809 * with no gaps. Empty TC means end of processing.
811 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
812 if (port_cfg->tc[i].inqs == 0)
814 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
815 port_cfg->tc[i].inqs,
816 priv->bpool, port_cfg->tc[i].color);
819 priv->ppio_params.inqs_params.num_tcs = i;
821 if (port_cfg->policer_enable)
822 return setup_policer(priv, &port_cfg->policer_params);
828 * Configure TX Queues in a given port.
830 * Sets up TX queues egress scheduler and limiter.
832 * @param priv Port's private data
833 * @param portid DPDK port ID
834 * @param max_queues Maximum number of queues to configure.
835 * @returns 0 in case of success, negative value otherwise.
838 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
841 /* We need only a subset of configuration. */
842 struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
845 if (mrvl_qos_cfg == NULL)
848 priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable;
849 if (port_cfg->rate_limit_enable)
850 priv->ppio_params.rate_limit_params =
851 port_cfg->rate_limit_params;
853 for (i = 0; i < max_queues; i++) {
854 struct pp2_ppio_outq_params *params =
855 &priv->ppio_params.outqs_params.outqs_params[i];
857 params->sched_mode = port_cfg->outq[i].sched_mode;
858 params->weight = port_cfg->outq[i].weight;
859 params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable;
860 params->rate_limit_params = port_cfg->outq[i].rate_limit_params;
869 * Finalize QoS table configuration and initialize it in SDK. It can be done
870 * only after port is started, so we have a valid ppio reference.
872 * @param priv Port's private (configuration) data.
873 * @returns 0 in case of success, exits otherwise.
876 mrvl_start_qos_mapping(struct mrvl_priv *priv)
880 if (priv->ppio == NULL) {
881 RTE_LOG(ERR, PMD, "ppio must not be NULL here!\n");
885 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
886 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
888 for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
889 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
891 /* Initialize Classifier QoS table. */
893 return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);