dpdk/drivers/net/mvpp2/mrvl_qos.c
<<
>>
Prefs
   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. */
  95struct 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 */
 106static int
 107get_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 */
 214static int
 215get_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 */
 312static int
 313parse_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 */
 406static int
 407parse_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 */
 485static int
 486parse_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 */
 655int
 656mrvl_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 */
 928static int
 929setup_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 */
 964static int
 965setup_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 */
1001int
1002mrvl_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 */
1134int
1135mrvl_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 */
1172int
1173mrvl_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}
1195