]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/drivers/net/mvpp2/mrvl_qos.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / dpdk / drivers / net / mvpp2 / mrvl_qos.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2017 Marvell International Ltd.
3 * Copyright(c) 2017 Semihalf.
4 * All rights reserved.
5 */
6
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include <rte_common.h>
12 #include <rte_cfgfile.h>
13 #include <rte_log.h>
14 #include <rte_lcore.h>
15 #include <rte_malloc.h>
16 #include <rte_string_fns.h>
17
18 #include "mrvl_qos.h"
19
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"
34
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"
43
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"
60
61 /** Number of tokens in range a-b = 2. */
62 #define MAX_RNG_TOKENS 2
63
64 /** Maximum possible value of PCP. */
65 #define MAX_PCP 7
66
67 /** Maximum possible value of DSCP. */
68 #define MAX_DSCP 63
69
70 /** Global QoS configuration. */
71 struct mrvl_qos_cfg *mrvl_qos_cfg;
72
73 /**
74 * Convert string to uint32_t with extra checks for result correctness.
75 *
76 * @param string String to convert.
77 * @param val Conversion result.
78 * @returns 0 in case of success, negative value otherwise.
79 */
80 static int
81 get_val_securely(const char *string, uint32_t *val)
82 {
83 char *endptr;
84 size_t len = strlen(string);
85
86 if (len == 0)
87 return -1;
88
89 errno = 0;
90 *val = strtoul(string, &endptr, 0);
91 if (errno != 0 || RTE_PTR_DIFF(endptr, string) != len)
92 return -2;
93
94 return 0;
95 }
96
97 /**
98 * Read out-queue configuration from file.
99 *
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.
105 */
106 static int
107 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
108 struct mrvl_qos_cfg *cfg)
109 {
110 char sec_name[32];
111 const char *entry;
112 uint32_t val;
113
114 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
115 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
116
117 /* Skip non-existing */
118 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
119 return 0;
120
121 /* Read scheduling mode */
122 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE);
123 if (entry) {
124 if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP,
125 strlen(MRVL_TOK_SCHED_MODE_SP))) {
126 cfg->port[port].outq[outq].sched_mode =
127 PP2_PPIO_SCHED_M_SP;
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;
132 } else {
133 MRVL_LOG(ERR, "Unknown token: %s", entry);
134 return -1;
135 }
136 }
137
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);
142 if (entry) {
143 if (get_val_securely(entry, &val) < 0)
144 return -1;
145 cfg->port[port].outq[outq].weight = val;
146 }
147 }
148
149 /*
150 * There's no point in setting rate limiting for specific outq as
151 * global port rate limiting has priority.
152 */
153 if (cfg->port[port].rate_limit_enable) {
154 MRVL_LOG(WARNING, "Port %d rate limiting already enabled",
155 port);
156 return 0;
157 }
158
159 entry = rte_cfgfile_get_entry(file, sec_name,
160 MRVL_TOK_RATE_LIMIT_ENABLE);
161 if (entry) {
162 if (get_val_securely(entry, &val) < 0)
163 return -1;
164 cfg->port[port].outq[outq].rate_limit_enable = val;
165 }
166
167 if (!cfg->port[port].outq[outq].rate_limit_enable)
168 return 0;
169
170 /* Read CBS (in kB) */
171 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE);
172 if (entry) {
173 if (get_val_securely(entry, &val) < 0)
174 return -1;
175 cfg->port[port].outq[outq].rate_limit_params.cbs = val;
176 }
177
178 /* Read CIR (in kbps) */
179 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT);
180 if (entry) {
181 if (get_val_securely(entry, &val) < 0)
182 return -1;
183 cfg->port[port].outq[outq].rate_limit_params.cir = val;
184 }
185
186 return 0;
187 }
188
189 /**
190 * Gets multiple-entry values and places them in table.
191 *
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.
198 *
199 * This function is purely utilitary, it does not print any error, only returns
200 * different error numbers.
201 *
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.
213 */
214 static int
215 get_entry_values(const char *entry, uint8_t *tab,
216 size_t elem_sz, uint8_t max_elems, uint8_t max_val)
217 {
218 /* There should not be more tokens than max elements.
219 * Add 1 for error trap.
220 */
221 char *tokens[max_elems + 1];
222
223 /* Begin, End + error trap = 3. */
224 char *rng_tokens[MAX_RNG_TOKENS + 1];
225 long beg, end;
226 uint32_t token_val;
227 int nb_tokens, nb_rng_tokens;
228 int i;
229 int values = 0;
230 char val;
231 char entry_cpy[CFG_VALUE_LEN];
232
233 if (elem_sz != 1)
234 return -1;
235
236 /* Copy the entry to safely use rte_strsplit(). */
237 strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
238
239 /*
240 * If there are more tokens than array size, rte_strsplit will
241 * not return error, just array size.
242 */
243 nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
244 tokens, max_elems + 1, ' ');
245
246 /* Quick check, will be refined later. */
247 if (nb_tokens > max_elems)
248 return -2;
249
250 for (i = 0; i < nb_tokens; ++i) {
251 if (strchr(tokens[i], '-') != NULL) {
252 /*
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.
256 */
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)
261 return -3;
262
263 /* Range and sanity checks. */
264 if (get_val_securely(rng_tokens[0], &token_val) < 0)
265 return -4;
266 beg = (char)token_val;
267 if (get_val_securely(rng_tokens[1], &token_val) < 0)
268 return -4;
269 end = (char)token_val;
270 if (beg < 0 || beg > UCHAR_MAX ||
271 end < 0 || end > UCHAR_MAX || end < beg)
272 return -4;
273
274 for (val = beg; val <= end; ++val) {
275 if (val > max_val)
276 return -5;
277
278 *tab = val;
279 tab = RTE_PTR_ADD(tab, elem_sz);
280 ++values;
281 if (values >= max_elems)
282 return -2;
283 }
284 } else {
285 /* Single values. */
286 if (get_val_securely(tokens[i], &token_val) < 0)
287 return -5;
288 val = (char)token_val;
289 if (val > max_val)
290 return -5;
291
292 *tab = val;
293 tab = RTE_PTR_ADD(tab, elem_sz);
294 ++values;
295 if (values >= max_elems)
296 return -2;
297 }
298 }
299
300 return values;
301 }
302
303 /**
304 * Parse Traffic Class'es mapping configuration.
305 *
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.
311 */
312 static int
313 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
314 struct mrvl_qos_cfg *cfg)
315 {
316 char sec_name[32];
317 const char *entry;
318 int n;
319
320 snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
321 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
322
323 /* Skip non-existing */
324 if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
325 return 0;
326
327 cfg->port[port].use_global_defaults = 0;
328 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
329 if (entry) {
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),
334 MRVL_PP2_RXQ_MAX);
335 if (n < 0) {
336 MRVL_LOG(ERR, "Error %d while parsing: %s",
337 n, entry);
338 return n;
339 }
340 cfg->port[port].tc[tc].inqs = n;
341 }
342
343 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
344 if (entry) {
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),
349 MAX_PCP);
350 if (n < 0) {
351 MRVL_LOG(ERR, "Error %d while parsing: %s",
352 n, entry);
353 return n;
354 }
355 cfg->port[port].tc[tc].pcps = n;
356 }
357
358 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
359 if (entry) {
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),
364 MAX_DSCP);
365 if (n < 0) {
366 MRVL_LOG(ERR, "Error %d while parsing: %s",
367 n, entry);
368 return n;
369 }
370 cfg->port[port].tc[tc].dscps = n;
371 }
372
373 if (!cfg->port[port].setup_policer)
374 return 0;
375
376 entry = rte_cfgfile_get_entry(file, sec_name,
377 MRVL_TOK_PLCR_DEFAULT_COLOR);
378 if (entry) {
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;
388 } else {
389 MRVL_LOG(ERR, "Error while parsing: %s", entry);
390 return -1;
391 }
392 }
393
394 return 0;
395 }
396
397 /**
398 * Parse default port policer.
399 *
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.
405 */
406 static int
407 parse_policer(struct rte_cfgfile *file, int port, const char *sec_name,
408 struct mrvl_qos_cfg *cfg)
409 {
410 const char *entry;
411 uint32_t val;
412
413 /* Read policer token unit */
414 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_UNIT);
415 if (entry) {
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;
424 } else {
425 MRVL_LOG(ERR, "Unknown token: %s", entry);
426 return -1;
427 }
428 }
429
430 /* Read policer color mode */
431 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_COLOR);
432 if (entry) {
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;
441 } else {
442 MRVL_LOG(ERR, "Error in parsing: %s", entry);
443 return -1;
444 }
445 }
446
447 /* Read policer cir */
448 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CIR);
449 if (entry) {
450 if (get_val_securely(entry, &val) < 0)
451 return -1;
452 cfg->port[port].policer_params.cir = val;
453 }
454
455 /* Read policer cbs */
456 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_CBS);
457 if (entry) {
458 if (get_val_securely(entry, &val) < 0)
459 return -1;
460 cfg->port[port].policer_params.cbs = val;
461 }
462
463 /* Read policer ebs */
464 entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PLCR_EBS);
465 if (entry) {
466 if (get_val_securely(entry, &val) < 0)
467 return -1;
468 cfg->port[port].policer_params.ebs = val;
469 }
470
471 cfg->port[port].setup_policer = 1;
472
473 return 0;
474 }
475
476 /**
477 * Parse QoS configuration - rte_kvargs_process handler.
478 *
479 * Opens configuration file and parses its content.
480 *
481 * @param key Unused.
482 * @param path Path to config file.
483 * @param extra_args Pointer to configuration structure.
484 * @returns 0 in case of success, exits otherwise.
485 */
486 int
487 mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
488 void *extra_args)
489 {
490 struct mrvl_qos_cfg **cfg = extra_args;
491 struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
492 uint32_t val;
493 int n, i, ret;
494 const char *entry;
495 char sec_name[32];
496
497 if (file == NULL)
498 rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path);
499
500 /* Create configuration. This is never accessed on the fast path,
501 * so we can ignore socket.
502 */
503 *cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
504 if (*cfg == NULL)
505 rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n",
506 path);
507
508 n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
509 sizeof(MRVL_TOK_PORT) - 1);
510
511 if (n == 0) {
512 /* This is weird, but not bad. */
513 MRVL_LOG(WARNING, "Empty configuration file?");
514 return 0;
515 }
516
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);
521
522 /* Use global defaults, unless an override occurs */
523 (*cfg)->port[n].use_global_defaults = 1;
524
525 /* Skip ports non-existing in configuration. */
526 if (rte_cfgfile_num_sections(file, sec_name,
527 strlen(sec_name)) <= 0) {
528 continue;
529 }
530
531 /*
532 * Read per-port rate limiting. Setting that will
533 * disable per-queue rate limiting.
534 */
535 entry = rte_cfgfile_get_entry(file, sec_name,
536 MRVL_TOK_RATE_LIMIT_ENABLE);
537 if (entry) {
538 if (get_val_securely(entry, &val) < 0)
539 return -1;
540 (*cfg)->port[n].rate_limit_enable = val;
541 }
542
543 if ((*cfg)->port[n].rate_limit_enable) {
544 entry = rte_cfgfile_get_entry(file, sec_name,
545 MRVL_TOK_BURST_SIZE);
546 if (entry) {
547 if (get_val_securely(entry, &val) < 0)
548 return -1;
549 (*cfg)->port[n].rate_limit_params.cbs = val;
550 }
551
552 entry = rte_cfgfile_get_entry(file, sec_name,
553 MRVL_TOK_RATE_LIMIT);
554 if (entry) {
555 if (get_val_securely(entry, &val) < 0)
556 return -1;
557 (*cfg)->port[n].rate_limit_params.cir = val;
558 }
559 }
560
561 entry = rte_cfgfile_get_entry(file, sec_name,
562 MRVL_TOK_MAPPING_PRIORITY);
563 if (entry) {
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;
581 else
582 rte_exit(EXIT_FAILURE,
583 "Error in parsing %s value (%s)!\n",
584 MRVL_TOK_MAPPING_PRIORITY, entry);
585 } else {
586 (*cfg)->port[n].mapping_priority =
587 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
588 }
589
590 /* Parse policer configuration (if any) */
591 entry = rte_cfgfile_get_entry(file, sec_name,
592 MRVL_TOK_PLCR_DEFAULT);
593 if (entry) {
594 (*cfg)->port[n].use_global_defaults = 0;
595 if (get_val_securely(entry, &val) < 0)
596 return -1;
597
598 snprintf(sec_name, sizeof(sec_name), "%s %d",
599 MRVL_TOK_PLCR, val);
600 ret = parse_policer(file, n, sec_name, *cfg);
601 if (ret)
602 return -1;
603 }
604
605 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
606 ret = get_outq_cfg(file, n, i, *cfg);
607 if (ret < 0)
608 rte_exit(EXIT_FAILURE,
609 "Error %d parsing port %d outq %d!\n",
610 ret, n, i);
611 }
612
613 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
614 ret = parse_tc_cfg(file, n, i, *cfg);
615 if (ret < 0)
616 rte_exit(EXIT_FAILURE,
617 "Error %d parsing port %d tc %d!\n",
618 ret, n, i);
619 }
620
621 entry = rte_cfgfile_get_entry(file, sec_name,
622 MRVL_TOK_DEFAULT_TC);
623 if (entry) {
624 if (get_val_securely(entry, &val) < 0 ||
625 val > USHRT_MAX)
626 return -1;
627 (*cfg)->port[n].default_tc = (uint8_t)val;
628 } else {
629 if ((*cfg)->port[n].use_global_defaults == 0) {
630 MRVL_LOG(ERR,
631 "Default Traffic Class required in custom configuration!");
632 return -1;
633 }
634 }
635 }
636
637 return 0;
638 }
639
640 /**
641 * Setup Traffic Class.
642 *
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.
649 */
650 static int
651 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
652 struct pp2_bpool *bpool, enum pp2_ppio_color color)
653 {
654 struct pp2_ppio_inq_params *inq_params;
655
656 param->pkt_offset = MRVL_PKT_OFFS;
657 param->pools[0][0] = bpool;
658 param->default_color = color;
659
660 inq_params = rte_zmalloc_socket("inq_params",
661 inqs * sizeof(*inq_params),
662 0, rte_socket_id());
663 if (!inq_params)
664 return -ENOMEM;
665
666 param->num_in_qs = inqs;
667
668 /* Release old config if necessary. */
669 if (param->inqs_params)
670 rte_free(param->inqs_params);
671
672 param->inqs_params = inq_params;
673
674 return 0;
675 }
676
677 /**
678 * Setup ingress policer.
679 *
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.
684 */
685 static int
686 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
687 {
688 char match[16];
689 int ret;
690
691 /*
692 * At this point no other policers are used which means
693 * any policer can be picked up and used as a default one.
694 *
695 * Lets use 0th then.
696 */
697 sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
698 params->match = match;
699
700 ret = pp2_cls_plcr_init(params, &priv->default_policer);
701 if (ret) {
702 MRVL_LOG(ERR, "Failed to setup %s", match);
703 return -1;
704 }
705
706 priv->ppio_params.inqs_params.plcr = priv->default_policer;
707 priv->used_plcrs = BIT(0);
708
709 return 0;
710 }
711
712 /**
713 * Configure RX Queues in a given port.
714 *
715 * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
716 *
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.
721 */
722 int
723 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
724 uint16_t max_queues)
725 {
726 size_t i, tc;
727
728 if (mrvl_qos_cfg == NULL ||
729 mrvl_qos_cfg->port[portid].use_global_defaults) {
730 /*
731 * No port configuration, use default: 1 TC, no QoS,
732 * TC color set to green.
733 */
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);
737
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;
742 }
743 return 0;
744 }
745
746 /* We need only a subset of configuration. */
747 struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
748
749 priv->qos_tbl_params.type = port_cfg->mapping_priority;
750
751 /*
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".
755 */
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;
758
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. */
763 MRVL_LOG(ERR,
764 "Too many PCPs configured in TC %zu!", tc);
765 return -1;
766 }
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;
770 }
771 }
772
773 /*
774 * The same logic goes with DSCP.
775 * First, set all map elements to "default".
776 */
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;
780
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. */
785 MRVL_LOG(ERR,
786 "Too many DSCPs configured in TC %zu!", tc);
787 return -1;
788 }
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;
792 }
793 }
794
795 /*
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.
799 */
800 for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
801 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
802
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)) {
806 /* Overflow. */
807 MRVL_LOG(ERR,
808 "Too many RX queues configured per TC %zu!",
809 tc);
810 return -1;
811 }
812 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
813 uint8_t idx = port_cfg->tc[tc].inq[i];
814
815 if (idx > RTE_DIM(priv->rxq_map)) {
816 MRVL_LOG(ERR, "Bad queue index %d!", idx);
817 return -1;
818 }
819
820 priv->rxq_map[idx].tc = tc;
821 priv->rxq_map[idx].inq = i;
822 }
823 }
824
825 /*
826 * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
827 * with no gaps. Empty TC means end of processing.
828 */
829 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
830 if (port_cfg->tc[i].inqs == 0)
831 break;
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);
835 }
836
837 priv->ppio_params.inqs_params.num_tcs = i;
838
839 if (port_cfg->setup_policer)
840 return setup_policer(priv, &port_cfg->policer_params);
841
842 return 0;
843 }
844
845 /**
846 * Configure TX Queues in a given port.
847 *
848 * Sets up TX queues egress scheduler and limiter.
849 *
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.
854 */
855 int
856 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
857 uint16_t max_queues)
858 {
859 /* We need only a subset of configuration. */
860 struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
861 int i;
862
863 if (mrvl_qos_cfg == NULL)
864 return 0;
865
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;
870
871 for (i = 0; i < max_queues; i++) {
872 struct pp2_ppio_outq_params *params =
873 &priv->ppio_params.outqs_params.outqs_params[i];
874
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;
879 }
880
881 return 0;
882 }
883
884 /**
885 * Start QoS mapping.
886 *
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.
889 *
890 * @param priv Port's private (configuration) data.
891 * @returns 0 in case of success, exits otherwise.
892 */
893 int
894 mrvl_start_qos_mapping(struct mrvl_priv *priv)
895 {
896 size_t i;
897
898 if (priv->ppio == NULL) {
899 MRVL_LOG(ERR, "ppio must not be NULL here!");
900 return -1;
901 }
902
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;
905
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;
908
909 /* Initialize Classifier QoS table. */
910
911 return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);
912 }