net/bnxt: fail init when mbuf allocation fails
[dpdk.git] / 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_DSA_MODE "dsa_mode"
23 #define MRVL_TOK_START_HDR "start_hdr"
24 #define MRVL_TOK_START_HDR_NONE "none"
25 #define MRVL_TOK_START_HDR_DSA "dsa"
26 #define MRVL_TOK_START_HDR_CUSTOM "custom"
27 #define MRVL_TOK_START_HDR_EXT_DSA "ext_dsa"
28 #define MRVL_TOK_DEFAULT_TC "default_tc"
29 #define MRVL_TOK_DSCP "dscp"
30 #define MRVL_TOK_MAPPING_PRIORITY "mapping_priority"
31 #define MRVL_TOK_IP "ip"
32 #define MRVL_TOK_IP_VLAN "ip/vlan"
33 #define MRVL_TOK_PCP "pcp"
34 #define MRVL_TOK_PORT "port"
35 #define MRVL_TOK_RXQ "rxq"
36 #define MRVL_TOK_TC "tc"
37 #define MRVL_TOK_TXQ "txq"
38 #define MRVL_TOK_VLAN "vlan"
39 #define MRVL_TOK_VLAN_IP "vlan/ip"
40 #define MRVL_TOK_PARSER_UDF "parser udf"
41
42 /* egress specific configuration tokens */
43 #define MRVL_TOK_BURST_SIZE "burst_size"
44 #define MRVL_TOK_RATE_LIMIT "rate_limit"
45 #define MRVL_TOK_RATE_LIMIT_ENABLE "rate_limit_enable"
46 #define MRVL_TOK_SCHED_MODE "sched_mode"
47 #define MRVL_TOK_SCHED_MODE_SP "sp"
48 #define MRVL_TOK_SCHED_MODE_WRR "wrr"
49 #define MRVL_TOK_WRR_WEIGHT "wrr_weight"
50
51 /* policer specific configuration tokens */
52 #define MRVL_TOK_PLCR "policer"
53 #define MRVL_TOK_PLCR_DEFAULT "default_policer"
54 #define MRVL_TOK_PLCR_UNIT "token_unit"
55 #define MRVL_TOK_PLCR_UNIT_BYTES "bytes"
56 #define MRVL_TOK_PLCR_UNIT_PACKETS "packets"
57 #define MRVL_TOK_PLCR_COLOR "color_mode"
58 #define MRVL_TOK_PLCR_COLOR_BLIND "blind"
59 #define MRVL_TOK_PLCR_COLOR_AWARE "aware"
60 #define MRVL_TOK_PLCR_CIR "cir"
61 #define MRVL_TOK_PLCR_CBS "cbs"
62 #define MRVL_TOK_PLCR_EBS "ebs"
63 #define MRVL_TOK_PLCR_DEFAULT_COLOR "default_color"
64 #define MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN "green"
65 #define MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW "yellow"
66 #define MRVL_TOK_PLCR_DEFAULT_COLOR_RED "red"
67
68 /* parser udf specific configuration tokens */
69 #define MRVL_TOK_PARSER_UDF_PROTO "proto"
70 #define MRVL_TOK_PARSER_UDF_FIELD "field"
71 #define MRVL_TOK_PARSER_UDF_KEY "key"
72 #define MRVL_TOK_PARSER_UDF_MASK "mask"
73 #define MRVL_TOK_PARSER_UDF_OFFSET "offset"
74 #define MRVL_TOK_PARSER_UDF_PROTO_ETH "eth"
75 #define MRVL_TOK_PARSER_UDF_FIELD_ETH_TYPE "type"
76 #define MRVL_TOK_PARSER_UDF_PROTO_UDP "udp"
77 #define MRVL_TOK_PARSER_UDF_FIELD_UDP_DPORT "dport"
78
79 /* parser forward bad frames tokens */
80 #define MRVL_TOK_FWD_BAD_FRAMES "forward_bad_frames"
81
82 /* parse fill bpool buffers tokens */
83 #define MRVL_TOK_FILL_BPOOL_BUFFS "fill_bpool_buffs"
84
85 /** Number of tokens in range a-b = 2. */
86 #define MAX_RNG_TOKENS 2
87
88 /** Maximum possible value of PCP. */
89 #define MAX_PCP 7
90
91 /** Maximum possible value of DSCP. */
92 #define MAX_DSCP 63
93
94 /** Global configuration. */
95 struct mrvl_cfg *mrvl_cfg;
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 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_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_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_qos_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_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 parser udf.
478  *
479  * @param file Config file handle.
480  * @param sec_name section name
481  * @param udf udf index
482  * @param cfg[out] Parsing results.
483  * @returns 0 in case of success, negative value otherwise.
484  */
485 static int
486 parse_udf(struct rte_cfgfile *file, const char *sec_name, int udf,
487           struct mrvl_cfg *cfg)
488 {
489         struct pp2_parse_udf_params *udf_params;
490         const char *entry, *entry_field;
491         uint32_t val, i;
492         uint8_t field_size;
493         char malloc_name[32], tmp_arr[3];
494         /* field len in chars equal to '0x' + rest of data */
495 #define FIELD_LEN_IN_CHARS(field_size)  (uint32_t)(2 + (field_size) * 2)
496
497         udf_params = &cfg->pp2_cfg.prs_udfs.udfs[udf];
498
499         /* Read 'proto' field */
500         entry = rte_cfgfile_get_entry(file, sec_name,
501                                       MRVL_TOK_PARSER_UDF_PROTO);
502         if (!entry) {
503                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
504                          MRVL_TOK_PARSER_UDF_PROTO);
505                 return -1;
506         }
507
508         /* Read 'field' field */
509         entry_field = rte_cfgfile_get_entry(file, sec_name,
510                                        MRVL_TOK_PARSER_UDF_FIELD);
511         if (!entry_field) {
512                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
513                          MRVL_TOK_PARSER_UDF_FIELD);
514                 return -1;
515         }
516
517         if (!strncmp(entry, MRVL_TOK_PARSER_UDF_PROTO_ETH,
518                                 sizeof(MRVL_TOK_PARSER_UDF_PROTO_ETH))) {
519                 udf_params->match_proto = MV_NET_PROTO_ETH;
520                 if (!strncmp(entry_field, MRVL_TOK_PARSER_UDF_FIELD_ETH_TYPE,
521                              sizeof(MRVL_TOK_PARSER_UDF_FIELD_ETH_TYPE))) {
522                         udf_params->match_field.eth = MV_NET_ETH_F_TYPE;
523                         field_size = 2;
524                 } else {
525                         MRVL_LOG(ERR, "UDF[%d]: mismatch between '%s' proto "
526                                  "and '%s' field\n", udf,
527                                  MRVL_TOK_PARSER_UDF_PROTO_ETH,
528                                  entry_field);
529                         return -1;
530                 }
531         } else if (!strncmp(entry, MRVL_TOK_PARSER_UDF_PROTO_UDP,
532                                 sizeof(MRVL_TOK_PARSER_UDF_PROTO_UDP))) {
533                 udf_params->match_proto = MV_NET_PROTO_UDP;
534                 if (!strncmp(entry_field, MRVL_TOK_PARSER_UDF_FIELD_UDP_DPORT,
535                              sizeof(MRVL_TOK_PARSER_UDF_FIELD_UDP_DPORT))) {
536                         udf_params->match_field.udp = MV_NET_UDP_F_DP;
537                         field_size = 2;
538                 } else {
539                         MRVL_LOG(ERR, "UDF[%d]: mismatch between '%s' proto "
540                                  "and '%s' field\n", udf,
541                                  MRVL_TOK_PARSER_UDF_PROTO_UDP,
542                                  entry_field);
543                         return -1;
544                 }
545         } else {
546                 MRVL_LOG(ERR, "UDF[%d]: Unsupported '%s' proto\n", udf, entry);
547                 return -1;
548         }
549
550         snprintf(malloc_name, sizeof(malloc_name), "mrvl_udf_%d_key", udf);
551         udf_params->match_key = rte_zmalloc(malloc_name, field_size, 0);
552         if (udf_params->match_key == NULL) {
553                 MRVL_LOG(ERR, "Cannot allocate udf %d key\n", udf);
554                 return -1;
555         }
556         snprintf(malloc_name, sizeof(malloc_name), "mrvl_udf_%d_mask", udf);
557         udf_params->match_mask = rte_zmalloc(malloc_name, field_size, 0);
558         if (udf_params->match_mask == NULL) {
559                 MRVL_LOG(ERR, "Cannot allocate udf %d mask\n", udf);
560                 return -1;
561         }
562
563         /* Read 'key' field */
564         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PARSER_UDF_KEY);
565         if (!entry) {
566                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
567                          MRVL_TOK_PARSER_UDF_KEY);
568                 return -1;
569         }
570
571         if (strncmp(entry, "0x", 2) != 0)  {
572                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must start with '0x'\n",
573                          udf, MRVL_TOK_PARSER_UDF_KEY);
574                 return -EINVAL;
575         }
576
577         if (strlen(entry) != FIELD_LEN_IN_CHARS(field_size)) {
578                 MRVL_LOG(ERR, "UDF[%d]: '%s' field's len must be %d\n", udf,
579                          MRVL_TOK_PARSER_UDF_KEY,
580                          FIELD_LEN_IN_CHARS(field_size));
581                 return -EINVAL;
582         }
583
584         entry += 2; /* skip the '0x' */
585         for (i = 0; i < field_size; i++) {
586                 strncpy(tmp_arr, entry, 2);
587                 tmp_arr[2] = '\0';
588                 if (get_val_securely8(tmp_arr, 16,
589                                       &udf_params->match_key[i]) < 0) {
590                         MRVL_LOG(ERR, "UDF[%d]: '%s' field's value is not in "
591                                 "hex format\n", udf, MRVL_TOK_PARSER_UDF_KEY);
592                         return -EINVAL;
593                 }
594                 entry += 2;
595         }
596
597         /* Read 'mask' field */
598         entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PARSER_UDF_MASK);
599         if (!entry) {
600                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
601                          MRVL_TOK_PARSER_UDF_MASK);
602                 return -1;
603         }
604         if (strncmp(entry, "0x", 2) != 0) {
605                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must start with '0x'\n",
606                          udf, MRVL_TOK_PARSER_UDF_MASK);
607                 return -EINVAL;
608         }
609
610         if (strlen(entry) != FIELD_LEN_IN_CHARS(field_size)) {
611                 MRVL_LOG(ERR, "UDF[%d]: '%s' field's len must be %d\n", udf,
612                          MRVL_TOK_PARSER_UDF_MASK,
613                          FIELD_LEN_IN_CHARS(field_size));
614                 return -EINVAL;
615         }
616
617         entry += 2; /* skip the '0x' */
618         for (i = 0; i < field_size; i++) {
619                 strncpy(tmp_arr, entry, 2);
620                 tmp_arr[2] = '\0';
621                 if (get_val_securely8(tmp_arr, 16,
622                                       &udf_params->match_mask[i]) < 0) {
623                         MRVL_LOG(ERR, "UDF[%d]: '%s' field's value is not in "
624                                 "hex format\n", udf, MRVL_TOK_PARSER_UDF_MASK);
625                         return -EINVAL;
626                 }
627                 entry += 2;
628         }
629
630         /* Read offset */
631         entry = rte_cfgfile_get_entry(file, sec_name,
632                                       MRVL_TOK_PARSER_UDF_OFFSET);
633         if (!entry) {
634                 MRVL_LOG(ERR, "UDF[%d]: '%s' field must be set\n", udf,
635                          MRVL_TOK_PARSER_UDF_OFFSET);
636                 return -1;
637         }
638         if (get_val_securely(entry, &val) < 0)
639                 return -1;
640         udf_params->offset = val;
641
642         return 0;
643 }
644
645 /**
646  * Parse configuration - rte_kvargs_process handler.
647  *
648  * Opens configuration file and parses its content.
649  *
650  * @param key Unused.
651  * @param path Path to config file.
652  * @param extra_args Pointer to configuration structure.
653  * @returns 0 in case of success, exits otherwise.
654  */
655 int
656 mrvl_get_cfg(const char *key __rte_unused, const char *path, void *extra_args)
657 {
658         struct mrvl_cfg **cfg = extra_args;
659         struct rte_cfgfile *file = rte_cfgfile_load(path, 0);
660         uint32_t val;
661         int n, i, ret;
662         const char *entry;
663         char sec_name[32];
664
665         if (file == NULL) {
666                 MRVL_LOG(ERR, "Cannot load configuration %s\n", path);
667                 return -1;
668         }
669
670         /* Create configuration. This is never accessed on the fast path,
671          * so we can ignore socket.
672          */
673         *cfg = rte_zmalloc("mrvl_cfg", sizeof(struct mrvl_cfg), 0);
674         if (*cfg == NULL) {
675                 MRVL_LOG(ERR, "Cannot allocate configuration %s\n", path);
676                 return -1;
677         }
678
679         /* PP2 configuration */
680         n = rte_cfgfile_num_sections(file, MRVL_TOK_PARSER_UDF,
681                 sizeof(MRVL_TOK_PARSER_UDF) - 1);
682
683         if (n && n > PP2_MAX_UDFS_SUPPORTED) {
684                 MRVL_LOG(ERR, "found %d udf sections, but only %d are supported\n",
685                          n, PP2_MAX_UDFS_SUPPORTED);
686                 return -1;
687         }
688         (*cfg)->pp2_cfg.prs_udfs.num_udfs = n;
689         for (i = 0; i < n; i++) {
690                 snprintf(sec_name, sizeof(sec_name), "%s %d",
691                                 MRVL_TOK_PARSER_UDF, i);
692
693                 /* udf sections must be sequential. */
694                 if (rte_cfgfile_num_sections(file, sec_name,
695                                 strlen(sec_name)) <= 0) {
696                         MRVL_LOG(ERR, "udf sections must be sequential (0 - %d)\n",
697                                  PP2_MAX_UDFS_SUPPORTED - 1);
698                         return -1;
699                 }
700
701                 ret = parse_udf(file, sec_name, i, *cfg);
702                 if (ret) {
703                         MRVL_LOG(ERR, "Error in parsing %s!\n", sec_name);
704                         return -1;
705                 }
706         }
707
708         /* PP2 Ports configuration */
709         n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT,
710                 sizeof(MRVL_TOK_PORT) - 1);
711
712         if (n == 0) {
713                 /* This is weird, but not bad. */
714                 MRVL_LOG(WARNING, "Empty configuration file?");
715                 return 0;
716         }
717
718         /* Use the number of ports given as vdev parameters. */
719         for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) {
720                 snprintf(sec_name, sizeof(sec_name), "%s %d %s",
721                         MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT);
722
723                 /* Use global defaults, unless an override occurs */
724                 (*cfg)->port[n].use_qos_global_defaults = 1;
725
726                 /* Set non-zero defaults before the decision to continue to next
727                  * port or to parse the port section in config file
728                  */
729                 (*cfg)->port[n].fill_bpool_buffs = MRVL_BURST_SIZE;
730
731                 /* Skip ports non-existing in configuration. */
732                 if (rte_cfgfile_num_sections(file, sec_name,
733                                 strlen(sec_name)) <= 0) {
734                         continue;
735                 }
736
737                 /* MRVL_TOK_START_HDR replaces MRVL_TOK_DSA_MODE parameter.
738                  * MRVL_TOK_DSA_MODE will be supported for backward
739                  * compatibillity.
740                  */
741                 entry = rte_cfgfile_get_entry(file, sec_name,
742                                 MRVL_TOK_START_HDR);
743                 /* if start_hsr is missing, check if dsa_mode exist instead */
744                 if (entry == NULL)
745                         entry = rte_cfgfile_get_entry(file, sec_name,
746                                 MRVL_TOK_DSA_MODE);
747                 if (entry) {
748                         if (!strncmp(entry, MRVL_TOK_START_HDR_NONE,
749                                 sizeof(MRVL_TOK_START_HDR_NONE)))
750                                 (*cfg)->port[n].eth_start_hdr =
751                                 PP2_PPIO_HDR_ETH;
752                         else if (!strncmp(entry, MRVL_TOK_START_HDR_DSA,
753                                 sizeof(MRVL_TOK_START_HDR_DSA)))
754                                 (*cfg)->port[n].eth_start_hdr =
755                                 PP2_PPIO_HDR_ETH_DSA;
756                         else if (!strncmp(entry, MRVL_TOK_START_HDR_CUSTOM,
757                                 sizeof(MRVL_TOK_START_HDR_CUSTOM)))
758                                 (*cfg)->port[n].eth_start_hdr =
759                                 PP2_PPIO_HDR_ETH_CUSTOM;
760                         else if (!strncmp(entry, MRVL_TOK_START_HDR_EXT_DSA,
761                                 sizeof(MRVL_TOK_START_HDR_EXT_DSA))) {
762                                 (*cfg)->port[n].eth_start_hdr =
763                                 PP2_PPIO_HDR_ETH_EXT_DSA;
764                         } else {
765                                 MRVL_LOG(ERR,
766                                         "Error in parsing %s value (%s)!\n",
767                                         MRVL_TOK_START_HDR, entry);
768                                 return -1;
769                         }
770                 } else {
771                         (*cfg)->port[n].eth_start_hdr = PP2_PPIO_HDR_ETH;
772                 }
773
774                 /*
775                  * Read per-port rate limiting. Setting that will
776                  * disable per-queue rate limiting.
777                  */
778                 entry = rte_cfgfile_get_entry(file, sec_name,
779                                 MRVL_TOK_RATE_LIMIT_ENABLE);
780                 if (entry) {
781                         if (get_val_securely(entry, &val) < 0)
782                                 return -1;
783                         (*cfg)->port[n].rate_limit_enable = val;
784                 }
785
786                 if ((*cfg)->port[n].rate_limit_enable) {
787                         entry = rte_cfgfile_get_entry(file, sec_name,
788                                         MRVL_TOK_BURST_SIZE);
789                         if (entry) {
790                                 if (get_val_securely(entry, &val) < 0)
791                                         return -1;
792                                 (*cfg)->port[n].rate_limit_params.cbs = val;
793                         }
794
795                         entry = rte_cfgfile_get_entry(file, sec_name,
796                                         MRVL_TOK_RATE_LIMIT);
797                         if (entry) {
798                                 if (get_val_securely(entry, &val) < 0)
799                                         return -1;
800                                 (*cfg)->port[n].rate_limit_params.cir = val;
801                         }
802                 }
803
804                 entry = rte_cfgfile_get_entry(file, sec_name,
805                                 MRVL_TOK_MAPPING_PRIORITY);
806                 if (entry) {
807                         (*cfg)->port[n].use_qos_global_defaults = 0;
808                         if (!strncmp(entry, MRVL_TOK_VLAN_IP,
809                                 sizeof(MRVL_TOK_VLAN_IP)))
810                                 (*cfg)->port[n].mapping_priority =
811                                         PP2_CLS_QOS_TBL_VLAN_IP_PRI;
812                         else if (!strncmp(entry, MRVL_TOK_IP_VLAN,
813                                 sizeof(MRVL_TOK_IP_VLAN)))
814                                 (*cfg)->port[n].mapping_priority =
815                                         PP2_CLS_QOS_TBL_IP_VLAN_PRI;
816                         else if (!strncmp(entry, MRVL_TOK_IP,
817                                 sizeof(MRVL_TOK_IP)))
818                                 (*cfg)->port[n].mapping_priority =
819                                         PP2_CLS_QOS_TBL_IP_PRI;
820                         else if (!strncmp(entry, MRVL_TOK_VLAN,
821                                 sizeof(MRVL_TOK_VLAN))) {
822                                 (*cfg)->port[n].mapping_priority =
823                                         PP2_CLS_QOS_TBL_VLAN_PRI;
824                         } else {
825                                 MRVL_LOG(ERR,
826                                         "Error in parsing %s value (%s)!\n",
827                                         MRVL_TOK_MAPPING_PRIORITY, entry);
828                                 return -1;
829                         }
830                 } else {
831                         (*cfg)->port[n].mapping_priority =
832                                 PP2_CLS_QOS_TBL_NONE;
833                 }
834
835                 /* Parse policer configuration (if any) */
836                 entry = rte_cfgfile_get_entry(file, sec_name,
837                                 MRVL_TOK_PLCR_DEFAULT);
838                 if (entry) {
839                         (*cfg)->port[n].use_qos_global_defaults = 0;
840                         if (get_val_securely(entry, &val) < 0)
841                                 return -1;
842
843                         snprintf(sec_name, sizeof(sec_name), "%s %d",
844                                         MRVL_TOK_PLCR, val);
845                         ret = parse_policer(file, n, sec_name, *cfg);
846                         if (ret)
847                                 return -1;
848                 }
849
850                 for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) {
851                         ret = get_outq_cfg(file, n, i, *cfg);
852                         if (ret < 0) {
853                                 MRVL_LOG(ERR,
854                                         "Error %d parsing port %d outq %d!\n",
855                                         ret, n, i);
856                                 return -1;
857                         }
858                 }
859
860                 for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
861                         ret = parse_tc_cfg(file, n, i, *cfg);
862                         if (ret < 0) {
863                                 MRVL_LOG(ERR,
864                                         "Error %d parsing port %d tc %d!\n",
865                                         ret, n, i);
866                                 return -1;
867                         }
868                 }
869
870                 entry = rte_cfgfile_get_entry(file, sec_name,
871                                               MRVL_TOK_DEFAULT_TC);
872                 if (entry) {
873                         if (get_val_securely(entry, &val) < 0 ||
874                             val > USHRT_MAX)
875                                 return -1;
876                         (*cfg)->port[n].default_tc = (uint8_t)val;
877                 } else {
878                         if ((*cfg)->port[n].use_qos_global_defaults == 0) {
879                                 MRVL_LOG(ERR,
880                                          "Default Traffic Class required in "
881                                          "custom configuration!");
882                                 return -1;
883                         }
884                 }
885
886                 /* Parse forward bad frames option */
887                 entry = rte_cfgfile_get_entry(file, sec_name,
888                                 MRVL_TOK_FWD_BAD_FRAMES);
889                 if (entry) {
890                         if (get_val_securely(entry, &val) < 0) {
891                                 MRVL_LOG(ERR,
892                                         "Error in parsing %s value (%s)!\n",
893                                         MRVL_TOK_FWD_BAD_FRAMES, entry);
894                                 return -1;
895                         }
896                         (*cfg)->port[n].forward_bad_frames = (uint8_t)val;
897                 } else {
898                         (*cfg)->port[n].forward_bad_frames = 0;
899                 }
900
901                 /* Parse fill bpool buffs option */
902                 entry = rte_cfgfile_get_entry(file, sec_name,
903                                 MRVL_TOK_FILL_BPOOL_BUFFS);
904                 if (entry) {
905                         if (get_val_securely(entry, &val) < 0) {
906                                 MRVL_LOG(ERR,
907                                         "Error in parsing %s value (%s)!\n",
908                                         MRVL_TOK_FILL_BPOOL_BUFFS, entry);
909                                 return -1;
910                         }
911                         (*cfg)->port[n].fill_bpool_buffs = val;
912                 }
913         }
914
915         return 0;
916 }
917
918 /**
919  * Setup Traffic Class.
920  *
921  * Fill in TC parameters in single MUSDK TC config entry.
922  * @param param TC parameters entry.
923  * @param inqs Number of MUSDK in-queues in this TC.
924  * @param bpool Bpool for this TC.
925  * @param color Default color for this TC.
926  * @returns 0 in case of success, exits otherwise.
927  */
928 static int
929 setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs,
930         struct pp2_bpool *bpool, enum pp2_ppio_color color)
931 {
932         struct pp2_ppio_inq_params *inq_params;
933
934         param->pkt_offset = MRVL_PKT_OFFS;
935         param->pools[0][0] = bpool;
936         param->pools[0][1] = dummy_pool[bpool->pp2_id];
937         param->default_color = color;
938
939         inq_params = rte_zmalloc_socket("inq_params",
940                 inqs * sizeof(*inq_params),
941                 0, rte_socket_id());
942         if (!inq_params)
943                 return -ENOMEM;
944
945         param->num_in_qs = inqs;
946
947         /* Release old config if necessary. */
948         if (param->inqs_params)
949                 rte_free(param->inqs_params);
950
951         param->inqs_params = inq_params;
952
953         return 0;
954 }
955
956 /**
957  * Setup ingress policer.
958  *
959  * @param priv Port's private data.
960  * @param params Pointer to the policer's configuration.
961  * @param plcr_id Policer id.
962  * @returns 0 in case of success, negative values otherwise.
963  */
964 static int
965 setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params)
966 {
967         char match[16];
968         int ret;
969
970         /*
971          * At this point no other policers are used which means
972          * any policer can be picked up and used as a default one.
973          *
974          * Lets use 0th then.
975          */
976         sprintf(match, "policer-%d:%d\n", priv->pp_id, 0);
977         params->match = match;
978
979         ret = pp2_cls_plcr_init(params, &priv->default_policer);
980         if (ret) {
981                 MRVL_LOG(ERR, "Failed to setup %s", match);
982                 return -1;
983         }
984
985         priv->ppio_params.inqs_params.plcr = priv->default_policer;
986         priv->used_plcrs = BIT(0);
987
988         return 0;
989 }
990
991 /**
992  * Configure RX Queues in a given port.
993  *
994  * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping.
995  *
996  * @param priv Port's private data
997  * @param portid DPDK port ID
998  * @param max_queues Maximum number of queues to configure.
999  * @returns 0 in case of success, negative value otherwise.
1000  */
1001 int
1002 mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid,
1003         uint16_t max_queues)
1004 {
1005         size_t i, tc;
1006
1007         if (mrvl_cfg == NULL ||
1008                 mrvl_cfg->port[portid].use_qos_global_defaults) {
1009                 /*
1010                  * No port configuration, use default: 1 TC, no QoS,
1011                  * TC color set to green.
1012                  */
1013                 priv->ppio_params.inqs_params.num_tcs = 1;
1014                 setup_tc(&priv->ppio_params.inqs_params.tcs_params[0],
1015                         max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN);
1016
1017                 /* Direct mapping of queues i.e. 0->0, 1->1 etc. */
1018                 for (i = 0; i < max_queues; ++i) {
1019                         priv->rxq_map[i].tc = 0;
1020                         priv->rxq_map[i].inq = i;
1021                 }
1022                 return 0;
1023         }
1024
1025         /* We need only a subset of configuration. */
1026         struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
1027
1028         priv->qos_tbl_params.type = port_cfg->mapping_priority;
1029
1030         /*
1031          * We need to reverse mapping, from tc->pcp (better from usability
1032          * point of view) to pcp->tc (configurable in MUSDK).
1033          * First, set all map elements to "default".
1034          */
1035         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
1036                 priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc;
1037
1038         /* Then, fill in all known values. */
1039         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
1040                 if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) {
1041                         /* Better safe than sorry. */
1042                         MRVL_LOG(ERR,
1043                                 "Too many PCPs configured in TC %zu!", tc);
1044                         return -1;
1045                 }
1046                 for (i = 0; i < port_cfg->tc[tc].pcps; ++i) {
1047                         priv->qos_tbl_params.pcp_cos_map[
1048                           port_cfg->tc[tc].pcp[i]].tc = tc;
1049                 }
1050         }
1051
1052         /*
1053          * The same logic goes with DSCP.
1054          * First, set all map elements to "default".
1055          */
1056         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
1057                 priv->qos_tbl_params.dscp_cos_map[i].tc =
1058                         port_cfg->default_tc;
1059
1060         /* Fill in all known values. */
1061         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
1062                 if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) {
1063                         /* Better safe than sorry. */
1064                         MRVL_LOG(ERR,
1065                                 "Too many DSCPs configured in TC %zu!", tc);
1066                         return -1;
1067                 }
1068                 for (i = 0; i < port_cfg->tc[tc].dscps; ++i) {
1069                         priv->qos_tbl_params.dscp_cos_map[
1070                           port_cfg->tc[tc].dscp[i]].tc = tc;
1071                 }
1072         }
1073
1074         /*
1075          * Surprisingly, similar logic goes with queue mapping.
1076          * We need only to store qid->tc mapping,
1077          * to know TC when queue is read.
1078          */
1079         for (i = 0; i < RTE_DIM(priv->rxq_map); ++i)
1080                 priv->rxq_map[i].tc = MRVL_UNKNOWN_TC;
1081
1082         /* Set up DPDKq->(TC,inq) mapping. */
1083         for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) {
1084                 if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) {
1085                         /* Overflow. */
1086                         MRVL_LOG(ERR,
1087                                 "Too many RX queues configured per TC %zu!",
1088                                 tc);
1089                         return -1;
1090                 }
1091                 for (i = 0; i < port_cfg->tc[tc].inqs; ++i) {
1092                         uint8_t idx = port_cfg->tc[tc].inq[i];
1093
1094                         if (idx > RTE_DIM(priv->rxq_map)) {
1095                                 MRVL_LOG(ERR, "Bad queue index %d!", idx);
1096                                 return -1;
1097                         }
1098
1099                         priv->rxq_map[idx].tc = tc;
1100                         priv->rxq_map[idx].inq = i;
1101                 }
1102         }
1103
1104         /*
1105          * Set up TC configuration. TCs need to be sequenced: 0, 1, 2
1106          * with no gaps. Empty TC means end of processing.
1107          */
1108         for (i = 0; i < MRVL_PP2_TC_MAX; ++i) {
1109                 if (port_cfg->tc[i].inqs == 0)
1110                         break;
1111                 setup_tc(&priv->ppio_params.inqs_params.tcs_params[i],
1112                                 port_cfg->tc[i].inqs,
1113                                 priv->bpool, port_cfg->tc[i].color);
1114         }
1115
1116         priv->ppio_params.inqs_params.num_tcs = i;
1117
1118         if (port_cfg->setup_policer)
1119                 return setup_policer(priv, &port_cfg->policer_params);
1120
1121         return 0;
1122 }
1123
1124 /**
1125  * Configure TX Queues in a given port.
1126  *
1127  * Sets up TX queues egress scheduler and limiter.
1128  *
1129  * @param priv Port's private data
1130  * @param portid DPDK port ID
1131  * @param max_queues Maximum number of queues to configure.
1132  * @returns 0 in case of success, negative value otherwise.
1133  */
1134 int
1135 mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid,
1136                 uint16_t max_queues)
1137 {
1138         /* We need only a subset of configuration. */
1139         struct port_cfg *port_cfg = &mrvl_cfg->port[portid];
1140         int i;
1141
1142         if (mrvl_cfg == NULL)
1143                 return 0;
1144
1145         priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable;
1146         if (port_cfg->rate_limit_enable)
1147                 priv->ppio_params.rate_limit_params =
1148                         port_cfg->rate_limit_params;
1149
1150         for (i = 0; i < max_queues; i++) {
1151                 struct pp2_ppio_outq_params *params =
1152                         &priv->ppio_params.outqs_params.outqs_params[i];
1153
1154                 params->sched_mode = port_cfg->outq[i].sched_mode;
1155                 params->weight = port_cfg->outq[i].weight;
1156                 params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable;
1157                 params->rate_limit_params = port_cfg->outq[i].rate_limit_params;
1158         }
1159
1160         return 0;
1161 }
1162
1163 /**
1164  * Start QoS mapping.
1165  *
1166  * Finalize QoS table configuration and initialize it in SDK. It can be done
1167  * only after port is started, so we have a valid ppio reference.
1168  *
1169  * @param priv Port's private (configuration) data.
1170  * @returns 0 in case of success, exits otherwise.
1171  */
1172 int
1173 mrvl_start_qos_mapping(struct mrvl_priv *priv)
1174 {
1175         size_t i;
1176
1177         if (priv->qos_tbl_params.type == PP2_CLS_QOS_TBL_NONE)
1178                 return 0;
1179
1180         if (priv->ppio == NULL) {
1181                 MRVL_LOG(ERR, "ppio must not be NULL here!");
1182                 return -1;
1183         }
1184
1185         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i)
1186                 priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio;
1187
1188         for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i)
1189                 priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio;
1190
1191         /* Initialize Classifier QoS table. */
1192
1193         return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl);
1194 }