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 cfg
->port
[port
].use_global_defaults
= 0;
328 entry
= rte_cfgfile_get_entry(file
, sec_name
, MRVL_TOK_RXQ
);
330 n
= get_entry_values(entry
,
331 cfg
->port
[port
].tc
[tc
].inq
,
332 sizeof(cfg
->port
[port
].tc
[tc
].inq
[0]),
333 RTE_DIM(cfg
->port
[port
].tc
[tc
].inq
),
336 MRVL_LOG(ERR
, "Error %d while parsing: %s",
340 cfg
->port
[port
].tc
[tc
].inqs
= n
;
343 entry
= rte_cfgfile_get_entry(file
, sec_name
, MRVL_TOK_PCP
);
345 n
= get_entry_values(entry
,
346 cfg
->port
[port
].tc
[tc
].pcp
,
347 sizeof(cfg
->port
[port
].tc
[tc
].pcp
[0]),
348 RTE_DIM(cfg
->port
[port
].tc
[tc
].pcp
),
351 MRVL_LOG(ERR
, "Error %d while parsing: %s",
355 cfg
->port
[port
].tc
[tc
].pcps
= n
;
358 entry
= rte_cfgfile_get_entry(file
, sec_name
, MRVL_TOK_DSCP
);
360 n
= get_entry_values(entry
,
361 cfg
->port
[port
].tc
[tc
].dscp
,
362 sizeof(cfg
->port
[port
].tc
[tc
].dscp
[0]),
363 RTE_DIM(cfg
->port
[port
].tc
[tc
].dscp
),
366 MRVL_LOG(ERR
, "Error %d while parsing: %s",
370 cfg
->port
[port
].tc
[tc
].dscps
= n
;
373 if (!cfg
->port
[port
].setup_policer
)
376 entry
= rte_cfgfile_get_entry(file
, sec_name
,
377 MRVL_TOK_PLCR_DEFAULT_COLOR
);
379 if (!strncmp(entry
, MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN
,
380 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN
))) {
381 cfg
->port
[port
].tc
[tc
].color
= PP2_PPIO_COLOR_GREEN
;
382 } else if (!strncmp(entry
, MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW
,
383 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW
))) {
384 cfg
->port
[port
].tc
[tc
].color
= PP2_PPIO_COLOR_YELLOW
;
385 } else if (!strncmp(entry
, MRVL_TOK_PLCR_DEFAULT_COLOR_RED
,
386 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_RED
))) {
387 cfg
->port
[port
].tc
[tc
].color
= PP2_PPIO_COLOR_RED
;
389 MRVL_LOG(ERR
, "Error while parsing: %s", entry
);
398 * Parse default port policer.
400 * @param file Config file handle.
401 * @param sec_name Section name with policer configuration
402 * @param port Port number.
403 * @param cfg[out] Parsing results.
404 * @returns 0 in case of success, negative value otherwise.
407 parse_policer(struct rte_cfgfile
*file
, int port
, const char *sec_name
,
408 struct mrvl_qos_cfg
*cfg
)
413 /* Read policer token unit */
414 entry
= rte_cfgfile_get_entry(file
, sec_name
, MRVL_TOK_PLCR_UNIT
);
416 if (!strncmp(entry
, MRVL_TOK_PLCR_UNIT_BYTES
,
417 sizeof(MRVL_TOK_PLCR_UNIT_BYTES
))) {
418 cfg
->port
[port
].policer_params
.token_unit
=
419 PP2_CLS_PLCR_BYTES_TOKEN_UNIT
;
420 } else if (!strncmp(entry
, MRVL_TOK_PLCR_UNIT_PACKETS
,
421 sizeof(MRVL_TOK_PLCR_UNIT_PACKETS
))) {
422 cfg
->port
[port
].policer_params
.token_unit
=
423 PP2_CLS_PLCR_PACKETS_TOKEN_UNIT
;
425 MRVL_LOG(ERR
, "Unknown token: %s", entry
);
430 /* Read policer color mode */
431 entry
= rte_cfgfile_get_entry(file
, sec_name
, MRVL_TOK_PLCR_COLOR
);
433 if (!strncmp(entry
, MRVL_TOK_PLCR_COLOR_BLIND
,
434 sizeof(MRVL_TOK_PLCR_COLOR_BLIND
))) {
435 cfg
->port
[port
].policer_params
.color_mode
=
436 PP2_CLS_PLCR_COLOR_BLIND_MODE
;
437 } else if (!strncmp(entry
, MRVL_TOK_PLCR_COLOR_AWARE
,
438 sizeof(MRVL_TOK_PLCR_COLOR_AWARE
))) {
439 cfg
->port
[port
].policer_params
.color_mode
=
440 PP2_CLS_PLCR_COLOR_AWARE_MODE
;
442 MRVL_LOG(ERR
, "Error in parsing: %s", entry
);
447 /* Read policer cir */
448 entry
= rte_cfgfile_get_entry(file
, sec_name
, MRVL_TOK_PLCR_CIR
);
450 if (get_val_securely(entry
, &val
) < 0)
452 cfg
->port
[port
].policer_params
.cir
= val
;
455 /* Read policer cbs */
456 entry
= rte_cfgfile_get_entry(file
, sec_name
, MRVL_TOK_PLCR_CBS
);
458 if (get_val_securely(entry
, &val
) < 0)
460 cfg
->port
[port
].policer_params
.cbs
= val
;
463 /* Read policer ebs */
464 entry
= rte_cfgfile_get_entry(file
, sec_name
, MRVL_TOK_PLCR_EBS
);
466 if (get_val_securely(entry
, &val
) < 0)
468 cfg
->port
[port
].policer_params
.ebs
= val
;
471 cfg
->port
[port
].setup_policer
= 1;
477 * Parse QoS configuration - rte_kvargs_process handler.
479 * Opens configuration file and parses its content.
482 * @param path Path to config file.
483 * @param extra_args Pointer to configuration structure.
484 * @returns 0 in case of success, exits otherwise.
487 mrvl_get_qoscfg(const char *key __rte_unused
, const char *path
,
490 struct mrvl_qos_cfg
**cfg
= extra_args
;
491 struct rte_cfgfile
*file
= rte_cfgfile_load(path
, 0);
498 rte_exit(EXIT_FAILURE
, "Cannot load configuration %s\n", path
);
500 /* Create configuration. This is never accessed on the fast path,
501 * so we can ignore socket.
503 *cfg
= rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg
), 0);
505 rte_exit(EXIT_FAILURE
, "Cannot allocate configuration %s\n",
508 n
= rte_cfgfile_num_sections(file
, MRVL_TOK_PORT
,
509 sizeof(MRVL_TOK_PORT
) - 1);
512 /* This is weird, but not bad. */
513 MRVL_LOG(WARNING
, "Empty configuration file?");
517 /* Use the number of ports given as vdev parameters. */
518 for (n
= 0; n
< (PP2_NUM_ETH_PPIO
* PP2_NUM_PKT_PROC
); ++n
) {
519 snprintf(sec_name
, sizeof(sec_name
), "%s %d %s",
520 MRVL_TOK_PORT
, n
, MRVL_TOK_DEFAULT
);
522 /* Use global defaults, unless an override occurs */
523 (*cfg
)->port
[n
].use_global_defaults
= 1;
525 /* Skip ports non-existing in configuration. */
526 if (rte_cfgfile_num_sections(file
, sec_name
,
527 strlen(sec_name
)) <= 0) {
532 * Read per-port rate limiting. Setting that will
533 * disable per-queue rate limiting.
535 entry
= rte_cfgfile_get_entry(file
, sec_name
,
536 MRVL_TOK_RATE_LIMIT_ENABLE
);
538 if (get_val_securely(entry
, &val
) < 0)
540 (*cfg
)->port
[n
].rate_limit_enable
= val
;
543 if ((*cfg
)->port
[n
].rate_limit_enable
) {
544 entry
= rte_cfgfile_get_entry(file
, sec_name
,
545 MRVL_TOK_BURST_SIZE
);
547 if (get_val_securely(entry
, &val
) < 0)
549 (*cfg
)->port
[n
].rate_limit_params
.cbs
= val
;
552 entry
= rte_cfgfile_get_entry(file
, sec_name
,
553 MRVL_TOK_RATE_LIMIT
);
555 if (get_val_securely(entry
, &val
) < 0)
557 (*cfg
)->port
[n
].rate_limit_params
.cir
= val
;
561 entry
= rte_cfgfile_get_entry(file
, sec_name
,
562 MRVL_TOK_MAPPING_PRIORITY
);
564 (*cfg
)->port
[n
].use_global_defaults
= 0;
565 if (!strncmp(entry
, MRVL_TOK_VLAN_IP
,
566 sizeof(MRVL_TOK_VLAN_IP
)))
567 (*cfg
)->port
[n
].mapping_priority
=
568 PP2_CLS_QOS_TBL_VLAN_IP_PRI
;
569 else if (!strncmp(entry
, MRVL_TOK_IP_VLAN
,
570 sizeof(MRVL_TOK_IP_VLAN
)))
571 (*cfg
)->port
[n
].mapping_priority
=
572 PP2_CLS_QOS_TBL_IP_VLAN_PRI
;
573 else if (!strncmp(entry
, MRVL_TOK_IP
,
574 sizeof(MRVL_TOK_IP
)))
575 (*cfg
)->port
[n
].mapping_priority
=
576 PP2_CLS_QOS_TBL_IP_PRI
;
577 else if (!strncmp(entry
, MRVL_TOK_VLAN
,
578 sizeof(MRVL_TOK_VLAN
)))
579 (*cfg
)->port
[n
].mapping_priority
=
580 PP2_CLS_QOS_TBL_VLAN_PRI
;
582 rte_exit(EXIT_FAILURE
,
583 "Error in parsing %s value (%s)!\n",
584 MRVL_TOK_MAPPING_PRIORITY
, entry
);
586 (*cfg
)->port
[n
].mapping_priority
=
587 PP2_CLS_QOS_TBL_VLAN_IP_PRI
;
590 /* Parse policer configuration (if any) */
591 entry
= rte_cfgfile_get_entry(file
, sec_name
,
592 MRVL_TOK_PLCR_DEFAULT
);
594 (*cfg
)->port
[n
].use_global_defaults
= 0;
595 if (get_val_securely(entry
, &val
) < 0)
598 snprintf(sec_name
, sizeof(sec_name
), "%s %d",
600 ret
= parse_policer(file
, n
, sec_name
, *cfg
);
605 for (i
= 0; i
< MRVL_PP2_RXQ_MAX
; ++i
) {
606 ret
= get_outq_cfg(file
, n
, i
, *cfg
);
608 rte_exit(EXIT_FAILURE
,
609 "Error %d parsing port %d outq %d!\n",
613 for (i
= 0; i
< MRVL_PP2_TC_MAX
; ++i
) {
614 ret
= parse_tc_cfg(file
, n
, i
, *cfg
);
616 rte_exit(EXIT_FAILURE
,
617 "Error %d parsing port %d tc %d!\n",
621 entry
= rte_cfgfile_get_entry(file
, sec_name
,
622 MRVL_TOK_DEFAULT_TC
);
624 if (get_val_securely(entry
, &val
) < 0 ||
627 (*cfg
)->port
[n
].default_tc
= (uint8_t)val
;
629 if ((*cfg
)->port
[n
].use_global_defaults
== 0) {
631 "Default Traffic Class required in custom configuration!");
641 * Setup Traffic Class.
643 * Fill in TC parameters in single MUSDK TC config entry.
644 * @param param TC parameters entry.
645 * @param inqs Number of MUSDK in-queues in this TC.
646 * @param bpool Bpool for this TC.
647 * @param color Default color for this TC.
648 * @returns 0 in case of success, exits otherwise.
651 setup_tc(struct pp2_ppio_tc_params
*param
, uint8_t inqs
,
652 struct pp2_bpool
*bpool
, enum pp2_ppio_color color
)
654 struct pp2_ppio_inq_params
*inq_params
;
656 param
->pkt_offset
= MRVL_PKT_OFFS
;
657 param
->pools
[0][0] = bpool
;
658 param
->default_color
= color
;
660 inq_params
= rte_zmalloc_socket("inq_params",
661 inqs
* sizeof(*inq_params
),
666 param
->num_in_qs
= inqs
;
668 /* Release old config if necessary. */
669 if (param
->inqs_params
)
670 rte_free(param
->inqs_params
);
672 param
->inqs_params
= inq_params
;
678 * Setup ingress policer.
680 * @param priv Port's private data.
681 * @param params Pointer to the policer's configuration.
682 * @param plcr_id Policer id.
683 * @returns 0 in case of success, negative values otherwise.
686 setup_policer(struct mrvl_priv
*priv
, struct pp2_cls_plcr_params
*params
)
692 * At this point no other policers are used which means
693 * any policer can be picked up and used as a default one.
697 sprintf(match
, "policer-%d:%d\n", priv
->pp_id
, 0);
698 params
->match
= match
;
700 ret
= pp2_cls_plcr_init(params
, &priv
->default_policer
);
702 MRVL_LOG(ERR
, "Failed to setup %s", match
);
706 priv
->ppio_params
.inqs_params
.plcr
= priv
->default_policer
;
707 priv
->used_plcrs
= BIT(0);
713 * Configure RX Queues in a given port.
715 * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
717 * @param priv Port's private data
718 * @param portid DPDK port ID
719 * @param max_queues Maximum number of queues to configure.
720 * @returns 0 in case of success, negative value otherwise.
723 mrvl_configure_rxqs(struct mrvl_priv
*priv
, uint16_t portid
,
728 if (mrvl_qos_cfg
== NULL
||
729 mrvl_qos_cfg
->port
[portid
].use_global_defaults
) {
731 * No port configuration, use default: 1 TC, no QoS,
732 * TC color set to green.
734 priv
->ppio_params
.inqs_params
.num_tcs
= 1;
735 setup_tc(&priv
->ppio_params
.inqs_params
.tcs_params
[0],
736 max_queues
, priv
->bpool
, PP2_PPIO_COLOR_GREEN
);
738 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
739 for (i
= 0; i
< max_queues
; ++i
) {
740 priv
->rxq_map
[i
].tc
= 0;
741 priv
->rxq_map
[i
].inq
= i
;
746 /* We need only a subset of configuration. */
747 struct port_cfg
*port_cfg
= &mrvl_qos_cfg
->port
[portid
];
749 priv
->qos_tbl_params
.type
= port_cfg
->mapping_priority
;
752 * We need to reverse mapping, from tc->pcp (better from usability
753 * point of view) to pcp->tc (configurable in MUSDK).
754 * First, set all map elements to "default".
756 for (i
= 0; i
< RTE_DIM(priv
->qos_tbl_params
.pcp_cos_map
); ++i
)
757 priv
->qos_tbl_params
.pcp_cos_map
[i
].tc
= port_cfg
->default_tc
;
759 /* Then, fill in all known values. */
760 for (tc
= 0; tc
< RTE_DIM(port_cfg
->tc
); ++tc
) {
761 if (port_cfg
->tc
[tc
].pcps
> RTE_DIM(port_cfg
->tc
[0].pcp
)) {
762 /* Better safe than sorry. */
764 "Too many PCPs configured in TC %zu!", tc
);
767 for (i
= 0; i
< port_cfg
->tc
[tc
].pcps
; ++i
) {
768 priv
->qos_tbl_params
.pcp_cos_map
[
769 port_cfg
->tc
[tc
].pcp
[i
]].tc
= tc
;
774 * The same logic goes with DSCP.
775 * First, set all map elements to "default".
777 for (i
= 0; i
< RTE_DIM(priv
->qos_tbl_params
.dscp_cos_map
); ++i
)
778 priv
->qos_tbl_params
.dscp_cos_map
[i
].tc
=
779 port_cfg
->default_tc
;
781 /* Fill in all known values. */
782 for (tc
= 0; tc
< RTE_DIM(port_cfg
->tc
); ++tc
) {
783 if (port_cfg
->tc
[tc
].dscps
> RTE_DIM(port_cfg
->tc
[0].dscp
)) {
784 /* Better safe than sorry. */
786 "Too many DSCPs configured in TC %zu!", tc
);
789 for (i
= 0; i
< port_cfg
->tc
[tc
].dscps
; ++i
) {
790 priv
->qos_tbl_params
.dscp_cos_map
[
791 port_cfg
->tc
[tc
].dscp
[i
]].tc
= tc
;
796 * Surprisingly, similar logic goes with queue mapping.
797 * We need only to store qid->tc mapping,
798 * to know TC when queue is read.
800 for (i
= 0; i
< RTE_DIM(priv
->rxq_map
); ++i
)
801 priv
->rxq_map
[i
].tc
= MRVL_UNKNOWN_TC
;
803 /* Set up DPDKq->(TC,inq) mapping. */
804 for (tc
= 0; tc
< RTE_DIM(port_cfg
->tc
); ++tc
) {
805 if (port_cfg
->tc
[tc
].inqs
> RTE_DIM(port_cfg
->tc
[0].inq
)) {
808 "Too many RX queues configured per TC %zu!",
812 for (i
= 0; i
< port_cfg
->tc
[tc
].inqs
; ++i
) {
813 uint8_t idx
= port_cfg
->tc
[tc
].inq
[i
];
815 if (idx
> RTE_DIM(priv
->rxq_map
)) {
816 MRVL_LOG(ERR
, "Bad queue index %d!", idx
);
820 priv
->rxq_map
[idx
].tc
= tc
;
821 priv
->rxq_map
[idx
].inq
= i
;
826 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
827 * with no gaps. Empty TC means end of processing.
829 for (i
= 0; i
< MRVL_PP2_TC_MAX
; ++i
) {
830 if (port_cfg
->tc
[i
].inqs
== 0)
832 setup_tc(&priv
->ppio_params
.inqs_params
.tcs_params
[i
],
833 port_cfg
->tc
[i
].inqs
,
834 priv
->bpool
, port_cfg
->tc
[i
].color
);
837 priv
->ppio_params
.inqs_params
.num_tcs
= i
;
839 if (port_cfg
->setup_policer
)
840 return setup_policer(priv
, &port_cfg
->policer_params
);
846 * Configure TX Queues in a given port.
848 * Sets up TX queues egress scheduler and limiter.
850 * @param priv Port's private data
851 * @param portid DPDK port ID
852 * @param max_queues Maximum number of queues to configure.
853 * @returns 0 in case of success, negative value otherwise.
856 mrvl_configure_txqs(struct mrvl_priv
*priv
, uint16_t portid
,
859 /* We need only a subset of configuration. */
860 struct port_cfg
*port_cfg
= &mrvl_qos_cfg
->port
[portid
];
863 if (mrvl_qos_cfg
== NULL
)
866 priv
->ppio_params
.rate_limit_enable
= port_cfg
->rate_limit_enable
;
867 if (port_cfg
->rate_limit_enable
)
868 priv
->ppio_params
.rate_limit_params
=
869 port_cfg
->rate_limit_params
;
871 for (i
= 0; i
< max_queues
; i
++) {
872 struct pp2_ppio_outq_params
*params
=
873 &priv
->ppio_params
.outqs_params
.outqs_params
[i
];
875 params
->sched_mode
= port_cfg
->outq
[i
].sched_mode
;
876 params
->weight
= port_cfg
->outq
[i
].weight
;
877 params
->rate_limit_enable
= port_cfg
->outq
[i
].rate_limit_enable
;
878 params
->rate_limit_params
= port_cfg
->outq
[i
].rate_limit_params
;
887 * Finalize QoS table configuration and initialize it in SDK. It can be done
888 * only after port is started, so we have a valid ppio reference.
890 * @param priv Port's private (configuration) data.
891 * @returns 0 in case of success, exits otherwise.
894 mrvl_start_qos_mapping(struct mrvl_priv
*priv
)
898 if (priv
->ppio
== NULL
) {
899 MRVL_LOG(ERR
, "ppio must not be NULL here!");
903 for (i
= 0; i
< RTE_DIM(priv
->qos_tbl_params
.pcp_cos_map
); ++i
)
904 priv
->qos_tbl_params
.pcp_cos_map
[i
].ppio
= priv
->ppio
;
906 for (i
= 0; i
< RTE_DIM(priv
->qos_tbl_params
.dscp_cos_map
); ++i
)
907 priv
->qos_tbl_params
.dscp_cos_map
[i
].ppio
= priv
->ppio
;
909 /* Initialize Classifier QoS table. */
911 return pp2_cls_qos_tbl_init(&priv
->qos_tbl_params
, &priv
->qos_tbl
);