f66a141f429763a6004ede3513f9e50dbb193f04
[dpdk.git] / drivers / net / mrvl / 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 /* Unluckily, container_of is defined by both DPDK and MUSDK,
19  * we'll declare only one version.
20  *
21  * Note that it is not used in this PMD anyway.
22  */
23 #ifdef container_of
24 #undef container_of
25 #endif
26
27 #include "mrvl_qos.h"
28
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_SP "SP"
40 #define MRVL_TOK_TC "tc"
41 #define MRVL_TOK_TXQ "txq"
42 #define MRVL_TOK_VLAN "vlan"
43 #define MRVL_TOK_VLAN_IP "vlan/ip"
44 #define MRVL_TOK_WEIGHT "weight"
45
46 /* policer specific configuration tokens */
47 #define MRVL_TOK_PLCR_ENABLE "policer_enable"
48 #define MRVL_TOK_PLCR_UNIT "token_unit"
49 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
50 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
51 #define MRVL_TOK_PLCR_COLOR "color_mode"
52 #define MRVL_TOK_PLCR_COLOR_BLIND "blind"
53 #define MRVL_TOK_PLCR_COLOR_AWARE "aware"
54 #define MRVL_TOK_PLCR_CIR "cir"
55 #define MRVL_TOK_PLCR_CBS "cbs"
56 #define MRVL_TOK_PLCR_EBS "ebs"
57 #define MRVL_TOK_PLCR_DEFAULT_COLOR "default_color"
58 #define MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN "green"
59 #define MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW "yellow"
60 #define MRVL_TOK_PLCR_DEFAULT_COLOR_RED "red"
61
62 /** Number of tokens in range a-b = 2. */
63 #define MAX_RNG_TOKENS 2
64
65 /** Maximum possible value of PCP. */
66 #define MAX_PCP 7
67
68 /** Maximum possible value of DSCP. */
69 #define MAX_DSCP 63
70
71 /** Global QoS configuration. */
72 struct mrvl_qos_cfg *mrvl_qos_cfg;
73
74 /**
75  * Convert string to uint32_t with extra checks for result correctness.
76  *
77  * @param string String to convert.
78  * @param val Conversion result.
79  * @returns 0 in case of success, negative value otherwise.
80  */
81 static int
82 get_val_securely(const char *string, uint32_t *val)
83 {
84         char *endptr;
85         size_t len = strlen(string);
86
87         if (len == 0)
88                 return -1;
89
90         errno = 0;
91         *val = strtoul(string, &endptr, 0);
92         if (errno != 0 || RTE_PTR_DIFF(endptr, string) != len)
93                 return -2;
94
95         return 0;
96 }
97
98 /**
99  * Read out-queue configuration from file.
100  *
101  * @param file Path to the configuration file.
102  * @param port Port number.
103  * @param outq Out queue number.
104  * @param cfg Pointer to the Marvell QoS configuration structure.
105  * @returns 0 in case of success, negative value otherwise.
106  */
107 static int
108 get_outq_cfg(struct rte_cfgfile *file, int port, int outq,
109                 struct mrvl_qos_cfg *cfg)
110 {
111         char sec_name[32];
112         const char *entry;
113         uint32_t val;
114
115         snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
116                 MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq);
117
118         /* Skip non-existing */
119         if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
120                 return 0;
121
122         entry = rte_cfgfile_get_entry(file, sec_name,
123                         MRVL_TOK_WEIGHT);
124         if (entry) {
125                 if (get_val_securely(entry, &val) < 0)
126                         return -1;
127                 cfg->port[port].outq[outq].weight = (uint8_t)val;
128         }
129
130         return 0;
131 }
132
133 /**
134  * Gets multiple-entry values and places them in table.
135  *
136  * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to
137  * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}.
138  * As all result table's elements are always 1-byte long, we
139  * won't overcomplicate the function, but we'll keep API generic,
140  * check if someone hasn't changed element size and make it simple
141  * to extend to other sizes.
142  *
143  * This function is purely utilitary, it does not print any error, only returns
144  * different error numbers.
145  *
146  * @param entry[in] Values string to parse.
147  * @param tab[out] Results table.
148  * @param elem_sz[in] Element size (in bytes).
149  * @param max_elems[in] Number of results table elements available.
150  * @param max val[in] Maximum value allowed.
151  * @returns Number of correctly parsed elements in case of success.
152  * @retval -1 Wrong element size.
153  * @retval -2 More tokens than result table allows.
154  * @retval -3 Wrong range syntax.
155  * @retval -4 Wrong range values.
156  * @retval -5 Maximum value exceeded.
157  */
158 static int
159 get_entry_values(const char *entry, uint8_t *tab,
160         size_t elem_sz, uint8_t max_elems, uint8_t max_val)
161 {
162         /* There should not be more tokens than max elements.
163          * Add 1 for error trap.
164          */
165         char *tokens[max_elems + 1];
166
167         /* Begin, End + error trap = 3. */
168         char *rng_tokens[MAX_RNG_TOKENS + 1];
169         long beg, end;
170         uint32_t token_val;
171         int nb_tokens, nb_rng_tokens;
172         int i;
173         int values = 0;
174         char val;
175         char entry_cpy[CFG_VALUE_LEN];
176
177         if (elem_sz != 1)
178                 return -1;
179
180         /* Copy the entry to safely use rte_strsplit(). */
181         snprintf(entry_cpy, RTE_DIM(entry_cpy), "%s", entry);
182
183         /*
184          * If there are more tokens than array size, rte_strsplit will
185          * not return error, just array size.
186          */
187         nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy),
188                 tokens, max_elems + 1, ' ');
189
190         /* Quick check, will be refined later. */
191         if (nb_tokens > max_elems)
192                 return -2;
193
194         for (i = 0; i < nb_tokens; ++i) {
195                 if (strchr(tokens[i], '-') != NULL) {
196                         /*
197                          * Split to begin and end tokens.
198                          * We want to catch error cases too, thus we leave
199                          * option for number of tokens to be more than 2.
200                          */
201                         nb_rng_tokens = rte_strsplit(tokens[i],
202                                         strlen(tokens[i]), rng_tokens,
203                                         RTE_DIM(rng_tokens), '-');
204                         if (nb_rng_tokens != 2)
205                                 return -3;
206
207                         /* Range and sanity checks. */
208                         if (get_val_securely(rng_tokens[0], &token_val) < 0)
209                                 return -4;
210                         beg = (char)token_val;
211                         if (get_val_securely(rng_tokens[1], &token_val) < 0)
212                                 return -4;
213                         end = (char)token_val;
214                         if (beg < 0 || beg > UCHAR_MAX ||
215                                 end < 0 || end > UCHAR_MAX || end < beg)
216                                 return -4;
217
218                         for (val = beg; val <= end; ++val) {
219                                 if (val > max_val)
220                                         return -5;
221
222                                 *tab = val;
223                                 tab = RTE_PTR_ADD(tab, elem_sz);
224                                 ++values;
225                                 if (values >= max_elems)
226                                         return -2;
227                         }
228                 } else {
229                         /* Single values. */
230                         if (get_val_securely(tokens[i], &token_val) < 0)
231                                 return -5;
232                         val = (char)token_val;
233                         if (val > max_val)
234                                 return -5;
235
236                         *tab = val;
237                         tab = RTE_PTR_ADD(tab, elem_sz);
238                         ++values;
239                         if (values >= max_elems)
240                                 return -2;
241                 }
242         }
243
244         return values;
245 }
246
247 /**
248  * Parse Traffic Class'es mapping configuration.
249  *
250  * @param file Config file handle.
251  * @param port Which port to look for.
252  * @param tc Which Traffic Class to look for.
253  * @param cfg[out] Parsing results.
254  * @returns 0 in case of success, negative value otherwise.
255  */
256 static int
257 parse_tc_cfg(struct rte_cfgfile *file, int port, int tc,
258                 struct mrvl_qos_cfg *cfg)
259 {
260         char sec_name[32];
261         const char *entry;
262         int n;
263
264         snprintf(sec_name, sizeof(sec_name), "%s %d %s %d",
265                 MRVL_TOK_PORT, port, MRVL_TOK_TC, tc);
266
267         /* Skip non-existing */
268         if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0)
269                 return 0;
270
271         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ);
272         if (entry) {
273                 n = get_entry_values(entry,
274                         cfg->port[port].tc[tc].inq,
275                         sizeof(cfg->port[port].tc[tc].inq[0]),
276                         RTE_DIM(cfg->port[port].tc[tc].inq),
277                         MRVL_PP2_RXQ_MAX);
278                 if (n < 0) {
279                         RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
280                                 n, entry);
281                         return n;
282                 }
283                 cfg->port[port].tc[tc].inqs = n;
284         }
285
286         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP);
287         if (entry) {
288                 n = get_entry_values(entry,
289                         cfg->port[port].tc[tc].pcp,
290                         sizeof(cfg->port[port].tc[tc].pcp[0]),
291                         RTE_DIM(cfg->port[port].tc[tc].pcp),
292                         MAX_PCP);
293                 if (n < 0) {
294                         RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
295                                 n, entry);
296                         return n;
297                 }
298                 cfg->port[port].tc[tc].pcps = n;
299         }
300
301         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP);
302         if (entry) {
303                 n = get_entry_values(entry,
304                         cfg->port[port].tc[tc].dscp,
305                         sizeof(cfg->port[port].tc[tc].dscp[0]),
306                         RTE_DIM(cfg->port[port].tc[tc].dscp),
307                         MAX_DSCP);
308                 if (n < 0) {
309                         RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n",
310                                 n, entry);
311                         return n;
312                 }
313                 cfg->port[port].tc[tc].dscps = n;
314         }
315
316         entry = rte_cfgfile_get_entry(file, sec_name,
317                         MRVL_TOK_PLCR_DEFAULT_COLOR);
318         if (entry) {
319                 if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN,
320                                 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN))) {
321                         cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_GREEN;
322                 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW,
323                                 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW))) {
324                         cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_YELLOW;
325                 } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_RED,
326                                 sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_RED))) {
327                         cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_RED;
328                 } else {
329                         RTE_LOG(ERR, PMD, "Error while parsing: %s\n", entry);
330                         return -1;
331                 }
332         }
333
334         return 0;
335 }
336
337 /**
338  * Parse QoS configuration - rte_kvargs_process handler.
339  *
340  * Opens configuration file and parses its content.
341  *
342  * @param key Unused.
343  * @param path Path to config file.
344  * @param extra_args Pointer to configuration structure.
345  * @returns 0 in case of success, exits otherwise.
346  */
347 int
348 mrvl_get_qoscfg(const char *key __rte_unused, const char *path,
349                 void *extra_args)
350 {
351         struct mrvl_qos_cfg **cfg = extra_args;
352         struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
353         uint32_t val;
354         int n, i, ret;
355         const char *entry;
356         char sec_name[32];
357
358         if (file == NULL)
359                 rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path);
360
361         /* Create configuration. This is never accessed on the fast path,
362          * so we can ignore socket.
363          */
364         *cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0);
365         if (*cfg == NULL)
366                 rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n",
367                         path);
368
369         n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
370                 sizeof(MRVL_TOK_PORT) - 1);
371
372         if (n == 0) {
373                 /* This is weird, but not bad. */
374                 RTE_LOG(WARNING, PMD, "Empty configuration file?\n");
375                 return 0;
376         }
377
378         /* Use the number of ports given as vdev parameters. */
379         for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
380                 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
381                         MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
382
383                 /* Skip ports non-existing in configuration. */
384                 if (rte_cfgfile_num_sections(file, sec_name,
385                                 strlen(sec_name)) <= 0) {
386                         (*cfg)->port[n].use_global_defaults = 1;
387                         (*cfg)->port[n].mapping_priority =
388                                 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
389                         continue;
390                 }
391
392                 entry = rte_cfgfile_get_entry(file, sec_name,
393                                 MRVL_TOK_DEFAULT_TC);
394                 if (entry) {
395                         if (get_val_securely(entry, &val) < 0 ||
396                                 val > USHRT_MAX)
397                                 return -1;
398                         (*cfg)->port[n].default_tc = (uint8_t)val;
399                 } else {
400                         RTE_LOG(ERR, PMD,
401                                 "Default Traffic Class required in custom configuration!\n");
402                         return -1;
403                 }
404
405                 entry = rte_cfgfile_get_entry(file, sec_name,
406                                 MRVL_TOK_PLCR_ENABLE);
407                 if (entry) {
408                         if (get_val_securely(entry, &val) < 0)
409                                 return -1;
410                         (*cfg)->port[n].policer_enable = val;
411                 }
412
413                 if ((*cfg)->port[n].policer_enable) {
414                         enum pp2_cls_plcr_token_unit unit;
415
416                         /* Read policer token unit */
417                         entry = rte_cfgfile_get_entry(file, sec_name,
418                                         MRVL_TOK_PLCR_UNIT);
419                         if (entry) {
420                                 if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES,
421                                         sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) {
422                                         unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
423                                 } else if (!strncmp(entry,
424                                                 MRVL_TOK_PLCR_UNIT_PACKETS,
425                                         sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) {
426                                         unit = PP2_CLS_PLCR_PACKETS_TOKEN_UNIT;
427                                 } else {
428                                         RTE_LOG(ERR, PMD, "Unknown token: %s\n",
429                                                 entry);
430                                         return -1;
431                                 }
432                                 (*cfg)->port[n].policer_params.token_unit =
433                                         unit;
434                         }
435
436                         /* Read policer color mode */
437                         entry = rte_cfgfile_get_entry(file, sec_name,
438                                         MRVL_TOK_PLCR_COLOR);
439                         if (entry) {
440                                 enum pp2_cls_plcr_color_mode mode;
441
442                                 if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND,
443                                         sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) {
444                                         mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
445                                 } else if (!strncmp(entry,
446                                                 MRVL_TOK_PLCR_COLOR_AWARE,
447                                         sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) {
448                                         mode = PP2_CLS_PLCR_COLOR_AWARE_MODE;
449                                 } else {
450                                         RTE_LOG(ERR, PMD,
451                                                 "Error in parsing: %s\n",
452                                                 entry);
453                                         return -1;
454                                 }
455                                 (*cfg)->port[n].policer_params.color_mode =
456                                         mode;
457                         }
458
459                         /* Read policer cir */
460                         entry = rte_cfgfile_get_entry(file, sec_name,
461                                         MRVL_TOK_PLCR_CIR);
462                         if (entry) {
463                                 if (get_val_securely(entry, &val) < 0)
464                                         return -1;
465                                 (*cfg)->port[n].policer_params.cir = val;
466                         }
467
468                         /* Read policer cbs */
469                         entry = rte_cfgfile_get_entry(file, sec_name,
470                                         MRVL_TOK_PLCR_CBS);
471                         if (entry) {
472                                 if (get_val_securely(entry, &val) < 0)
473                                         return -1;
474                                 (*cfg)->port[n].policer_params.cbs = val;
475                         }
476
477                         /* Read policer ebs */
478                         entry = rte_cfgfile_get_entry(file, sec_name,
479                                         MRVL_TOK_PLCR_EBS);
480                         if (entry) {
481                                 if (get_val_securely(entry, &val) < 0)
482                                         return -1;
483                                 (*cfg)->port[n].policer_params.ebs = val;
484                         }
485                 }
486
487                 entry = rte_cfgfile_get_entry(file, sec_name,
488                                 MRVL_TOK_MAPPING_PRIORITY);
489                 if (entry) {
490                         if (!strncmp(entry, MRVL_TOK_VLAN_IP,
491                                 sizeof(MRVL_TOK_VLAN_IP)))
492                                 (*cfg)->port[n].mapping_priority =
493                                         PP2_CLS_QOS_TBL_VLAN_IP_PRI;
494                         else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
495                                 sizeof(MRVL_TOK_IP_VLAN)))
496                                 (*cfg)->port[n].mapping_priority =
497                                         PP2_CLS_QOS_TBL_IP_VLAN_PRI;
498                         else if (!strncmp(entry, MRVL_TOK_IP,
499                                 sizeof(MRVL_TOK_IP)))
500                                 (*cfg)->port[n].mapping_priority =
501                                         PP2_CLS_QOS_TBL_IP_PRI;
502                         else if (!strncmp(entry, MRVL_TOK_VLAN,
503                                 sizeof(MRVL_TOK_VLAN)))
504                                 (*cfg)->port[n].mapping_priority =
505                                         PP2_CLS_QOS_TBL_VLAN_PRI;
506                         else
507                                 rte_exit(EXIT_FAILURE,
508                                         "Error in parsing %s value (%s)!\n",
509                                         MRVL_TOK_MAPPING_PRIORITY, entry);
510                 } else {
511                         (*cfg)->port[n].mapping_priority =
512                                 PP2_CLS_QOS_TBL_VLAN_IP_PRI;
513                 }
514
515                 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
516                         ret = get_outq_cfg(file, n, i, *cfg);
517                         if (ret < 0)
518                                 rte_exit(EXIT_FAILURE,
519                                         "Error %d parsing port %d outq %d!\n",
520                                         ret, n, i);
521                 }
522
523                 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
524                         ret = parse_tc_cfg(file, n, i, *cfg);
525                         if (ret < 0)
526                                 rte_exit(EXIT_FAILURE,
527                                         "Error %d parsing port %d tc %d!\n",
528                                         ret, n, i);
529                 }
530         }
531
532         return 0;
533 }
534
535 /**
536  * Setup Traffic Class.
537  *
538  * Fill in TC parameters in single MUSDK TC config entry.
539  * @param param TC parameters entry.
540  * @param inqs Number of MUSDK in-queues in this TC.
541  * @param bpool Bpool for this TC.
542  * @param color Default color for this TC.
543  * @returns 0 in case of success, exits otherwise.
544  */
545 static int
546 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
547         struct pp2_bpool *bpool, enum pp2_ppio_color color)
548 {
549         struct pp2_ppio_inq_params *inq_params;
550
551         param->pkt_offset = MRVL_PKT_OFFS;
552         param->pools[0] = bpool;
553         param->default_color = color;
554
555         inq_params = rte_zmalloc_socket("inq_params",
556                 inqs * sizeof(*inq_params),
557                 0, rte_socket_id());
558         if (!inq_params)
559                 return -ENOMEM;
560
561         param->num_in_qs = inqs;
562
563         /* Release old config if necessary. */
564         if (param->inqs_params)
565                 rte_free(param->inqs_params);
566
567         param->inqs_params = inq_params;
568
569         return 0;
570 }
571
572 /**
573  * Setup ingress policer.
574  *
575  * @param priv Port's private data.
576  * @param params Pointer to the policer's configuration.
577  * @returns 0 in case of success, negative values otherwise.
578  */
579 static int
580 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
581 {
582         char match[16];
583         int ret;
584
585         snprintf(match, sizeof(match), "policer-%d:%d\n",
586                         priv->pp_id, priv->ppio_id);
587         params->match = match;
588
589         ret = pp2_cls_plcr_init(params, &priv->policer);
590         if (ret) {
591                 RTE_LOG(ERR, PMD, "Failed to setup %s\n", match);
592                 return -1;
593         }
594
595         priv->ppio_params.inqs_params.plcr = priv->policer;
596
597         return 0;
598 }
599
600 /**
601  * Configure RX Queues in a given port.
602  *
603  * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
604  *
605  * @param priv Port's private data
606  * @param portid DPDK port ID
607  * @param max_queues Maximum number of queues to configure.
608  * @returns 0 in case of success, negative value otherwise.
609  */
610 int
611 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
612         uint16_t max_queues)
613 {
614         size_t i, tc;
615
616         if (mrvl_qos_cfg == NULL ||
617                 mrvl_qos_cfg->port[portid].use_global_defaults) {
618                 /*
619                  * No port configuration, use default: 1 TC, no QoS,
620                  * TC color set to green.
621                  */
622                 priv->ppio_params.inqs_params.num_tcs = 1;
623                 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
624                         max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
625
626                 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
627                 for (i = 0; i < max_queues; ++i) {
628                         priv->rxq_map[i].tc = 0;
629                         priv->rxq_map[i].inq = i;
630                 }
631                 return 0;
632         }
633
634         /* We need only a subset of configuration. */
635         struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid];
636
637         priv->qos_tbl_params.type = port_cfg->mapping_priority;
638
639         /*
640          * We need to reverse mapping, from tc->pcp (better from usability
641          * point of view) to pcp->tc (configurable in MUSDK).
642          * First, set all map elements to "default".
643          */
644         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
645                 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
646
647         /* Then, fill in all known values. */
648         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
649                 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
650                         /* Better safe than sorry. */
651                         RTE_LOG(ERR, PMD,
652                                 "Too many PCPs configured in TC %zu!\n", tc);
653                         return -1;
654                 }
655                 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
656                         priv->qos_tbl_params.pcp_cos_map[
657                           port_cfg->tc[tc].pcp[i]].tc = tc;
658                 }
659         }
660
661         /*
662          * The same logic goes with DSCP.
663          * First, set all map elements to "default".
664          */
665         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
666                 priv->qos_tbl_params.dscp_cos_map[i].tc =
667                         port_cfg->default_tc;
668
669         /* Fill in all known values. */
670         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
671                 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
672                         /* Better safe than sorry. */
673                         RTE_LOG(ERR, PMD,
674                                 "Too many DSCPs configured in TC %zu!\n", tc);
675                         return -1;
676                 }
677                 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
678                         priv->qos_tbl_params.dscp_cos_map[
679                           port_cfg->tc[tc].dscp[i]].tc = tc;
680                 }
681         }
682
683         /*
684          * Surprisingly, similar logic goes with queue mapping.
685          * We need only to store qid->tc mapping,
686          * to know TC when queue is read.
687          */
688         for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
689                 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
690
691         /* Set up DPDKq->(TC,inq) mapping. */
692         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
693                 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
694                         /* Overflow. */
695                         RTE_LOG(ERR, PMD,
696                                 "Too many RX queues configured per TC %zu!\n",
697                                 tc);
698                         return -1;
699                 }
700                 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
701                         uint8_t idx = port_cfg->tc[tc].inq[i];
702
703                         if (idx > RTE_DIM(priv->rxq_map)) {
704                                 RTE_LOG(ERR, PMD, "Bad queue index %d!\n", idx);
705                                 return -1;
706                         }
707
708                         priv->rxq_map[idx].tc = tc;
709                         priv->rxq_map[idx].inq = i;
710                 }
711         }
712
713         /*
714          * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
715          * with no gaps. Empty TC means end of processing.
716          */
717         for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
718                 if (port_cfg->tc[i].inqs == 0)
719                         break;
720                 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
721                                 port_cfg->tc[i].inqs,
722                                 priv->bpool, port_cfg->tc[i].color);
723         }
724
725         priv->ppio_params.inqs_params.num_tcs = i;
726
727         if (port_cfg->policer_enable)
728                 return setup_policer(priv, &port_cfg->policer_params);
729
730         return 0;
731 }
732
733 /**
734  * Start QoS mapping.
735  *
736  * Finalize QoS table configuration and initialize it in SDK. It can be done
737  * only after port is started, so we have a valid ppio reference.
738  *
739  * @param priv Port's private (configuration) data.
740  * @returns 0 in case of success, exits otherwise.
741  */
742 int
743 mrvl_start_qos_mapping(struct mrvl_priv *priv)
744 {
745         size_t i;
746
747         if (priv->ppio == NULL) {
748                 RTE_LOG(ERR, PMD, "ppio must not be NULL here!\n");
749                 return -1;
750         }
751
752         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
753                 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
754
755         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
756                 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
757
758         /* Initialize Classifier QoS table. */
759
760         return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);
761 }