X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fnet%2Fmvpp2%2Fmrvl_qos.c;fp=drivers%2Fnet%2Fmrvl%2Fmrvl_qos.c;h=71856c1ab4f01518e67238978737dead8dadbe3e;hb=b63264c8342e6a1b6971c79550d2af2024b6a4de;hp=fbb3681312963f789c68e02c7c7888cd9ecae6f2;hpb=ca33590b6af032bff57d9cc70455660466a654b2;p=deb_dpdk.git diff --git a/drivers/net/mrvl/mrvl_qos.c b/drivers/net/mvpp2/mrvl_qos.c similarity index 62% rename from drivers/net/mrvl/mrvl_qos.c rename to drivers/net/mvpp2/mrvl_qos.c index fbb36813..71856c1a 100644 --- a/drivers/net/mrvl/mrvl_qos.c +++ b/drivers/net/mvpp2/mrvl_qos.c @@ -1,35 +1,7 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2017 Marvell International Ltd. - * Copyright(c) 2017 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2017 Marvell International Ltd. + * Copyright(c) 2017 Semihalf. + * All rights reserved. */ #include @@ -64,12 +36,35 @@ #define MRVL_TOK_PCP "pcp" #define MRVL_TOK_PORT "port" #define MRVL_TOK_RXQ "rxq" -#define MRVL_TOK_SP "SP" #define MRVL_TOK_TC "tc" #define MRVL_TOK_TXQ "txq" #define MRVL_TOK_VLAN "vlan" #define MRVL_TOK_VLAN_IP "vlan/ip" -#define MRVL_TOK_WEIGHT "weight" + +/* egress specific configuration tokens */ +#define MRVL_TOK_BURST_SIZE "burst_size" +#define MRVL_TOK_RATE_LIMIT "rate_limit" +#define MRVL_TOK_RATE_LIMIT_ENABLE "rate_limit_enable" +#define MRVL_TOK_SCHED_MODE "sched_mode" +#define MRVL_TOK_SCHED_MODE_SP "sp" +#define MRVL_TOK_SCHED_MODE_WRR "wrr" +#define MRVL_TOK_WRR_WEIGHT "wrr_weight" + +/* policer specific configuration tokens */ +#define MRVL_TOK_PLCR_ENABLE "policer_enable" +#define MRVL_TOK_PLCR_UNIT "token_unit" +#define MRVL_TOK_PLCR_UNIT_BYTES "bytes" +#define MRVL_TOK_PLCR_UNIT_PACKETS "packets" +#define MRVL_TOK_PLCR_COLOR "color_mode" +#define MRVL_TOK_PLCR_COLOR_BLIND "blind" +#define MRVL_TOK_PLCR_COLOR_AWARE "aware" +#define MRVL_TOK_PLCR_CIR "cir" +#define MRVL_TOK_PLCR_CBS "cbs" +#define MRVL_TOK_PLCR_EBS "ebs" +#define MRVL_TOK_PLCR_DEFAULT_COLOR "default_color" +#define MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN "green" +#define MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW "yellow" +#define MRVL_TOK_PLCR_DEFAULT_COLOR_RED "red" /** Number of tokens in range a-b = 2. */ #define MAX_RNG_TOKENS 2 @@ -131,12 +126,69 @@ get_outq_cfg(struct rte_cfgfile *file, int port, int outq, if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0) return 0; + /* Read scheduling mode */ + entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_SCHED_MODE); + if (entry) { + if (!strncmp(entry, MRVL_TOK_SCHED_MODE_SP, + strlen(MRVL_TOK_SCHED_MODE_SP))) { + cfg->port[port].outq[outq].sched_mode = + PP2_PPIO_SCHED_M_SP; + } else if (!strncmp(entry, MRVL_TOK_SCHED_MODE_WRR, + strlen(MRVL_TOK_SCHED_MODE_WRR))) { + cfg->port[port].outq[outq].sched_mode = + PP2_PPIO_SCHED_M_WRR; + } else { + MRVL_LOG(ERR, "Unknown token: %s", entry); + return -1; + } + } + + /* Read wrr weight */ + if (cfg->port[port].outq[outq].sched_mode == PP2_PPIO_SCHED_M_WRR) { + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_WRR_WEIGHT); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + cfg->port[port].outq[outq].weight = val; + } + } + + /* + * There's no point in setting rate limiting for specific outq as + * global port rate limiting has priority. + */ + if (cfg->port[port].rate_limit_enable) { + MRVL_LOG(WARNING, "Port %d rate limiting already enabled", + port); + return 0; + } + entry = rte_cfgfile_get_entry(file, sec_name, - MRVL_TOK_WEIGHT); + MRVL_TOK_RATE_LIMIT_ENABLE); if (entry) { if (get_val_securely(entry, &val) < 0) return -1; - cfg->port[port].outq[outq].weight = (uint8_t)val; + cfg->port[port].outq[outq].rate_limit_enable = val; + } + + if (!cfg->port[port].outq[outq].rate_limit_enable) + return 0; + + /* Read CBS (in kB) */ + entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_BURST_SIZE); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + cfg->port[port].outq[outq].rate_limit_params.cbs = val; + } + + /* Read CIR (in kbps) */ + entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RATE_LIMIT); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + cfg->port[port].outq[outq].rate_limit_params.cir = val; } return 0; @@ -190,7 +242,7 @@ get_entry_values(const char *entry, uint8_t *tab, return -1; /* Copy the entry to safely use rte_strsplit(). */ - snprintf(entry_cpy, RTE_DIM(entry_cpy), "%s", entry); + strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy)); /* * If there are more tokens than array size, rte_strsplit will @@ -288,7 +340,7 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc, RTE_DIM(cfg->port[port].tc[tc].inq), MRVL_PP2_RXQ_MAX); if (n < 0) { - RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n", + MRVL_LOG(ERR, "Error %d while parsing: %s", n, entry); return n; } @@ -303,7 +355,7 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc, RTE_DIM(cfg->port[port].tc[tc].pcp), MAX_PCP); if (n < 0) { - RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n", + MRVL_LOG(ERR, "Error %d while parsing: %s", n, entry); return n; } @@ -318,12 +370,31 @@ parse_tc_cfg(struct rte_cfgfile *file, int port, int tc, RTE_DIM(cfg->port[port].tc[tc].dscp), MAX_DSCP); if (n < 0) { - RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n", + MRVL_LOG(ERR, "Error %d while parsing: %s", n, entry); return n; } cfg->port[port].tc[tc].dscps = n; } + + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_PLCR_DEFAULT_COLOR); + if (entry) { + if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN, + sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_GREEN))) { + cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_GREEN; + } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW, + sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_YELLOW))) { + cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_YELLOW; + } else if (!strncmp(entry, MRVL_TOK_PLCR_DEFAULT_COLOR_RED, + sizeof(MRVL_TOK_PLCR_DEFAULT_COLOR_RED))) { + cfg->port[port].tc[tc].color = PP2_PPIO_COLOR_RED; + } else { + MRVL_LOG(ERR, "Error while parsing: %s", entry); + return -1; + } + } + return 0; } @@ -364,7 +435,7 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path, if (n == 0) { /* This is weird, but not bad. */ - RTE_LOG(WARNING, PMD, "Empty configuration file?\n"); + MRVL_LOG(WARNING, "Empty configuration file?"); return 0; } @@ -390,11 +461,123 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path, return -1; (*cfg)->port[n].default_tc = (uint8_t)val; } else { - RTE_LOG(ERR, PMD, - "Default Traffic Class required in custom configuration!\n"); + MRVL_LOG(ERR, + "Default Traffic Class required in custom configuration!"); return -1; } + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_PLCR_ENABLE); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + (*cfg)->port[n].policer_enable = val; + } + + if ((*cfg)->port[n].policer_enable) { + enum pp2_cls_plcr_token_unit unit; + + /* Read policer token unit */ + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_PLCR_UNIT); + if (entry) { + if (!strncmp(entry, MRVL_TOK_PLCR_UNIT_BYTES, + sizeof(MRVL_TOK_PLCR_UNIT_BYTES))) { + unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT; + } else if (!strncmp(entry, + MRVL_TOK_PLCR_UNIT_PACKETS, + sizeof(MRVL_TOK_PLCR_UNIT_PACKETS))) { + unit = PP2_CLS_PLCR_PACKETS_TOKEN_UNIT; + } else { + MRVL_LOG(ERR, "Unknown token: %s", + entry); + return -1; + } + (*cfg)->port[n].policer_params.token_unit = + unit; + } + + /* Read policer color mode */ + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_PLCR_COLOR); + if (entry) { + enum pp2_cls_plcr_color_mode mode; + + if (!strncmp(entry, MRVL_TOK_PLCR_COLOR_BLIND, + sizeof(MRVL_TOK_PLCR_COLOR_BLIND))) { + mode = PP2_CLS_PLCR_COLOR_BLIND_MODE; + } else if (!strncmp(entry, + MRVL_TOK_PLCR_COLOR_AWARE, + sizeof(MRVL_TOK_PLCR_COLOR_AWARE))) { + mode = PP2_CLS_PLCR_COLOR_AWARE_MODE; + } else { + MRVL_LOG(ERR, + "Error in parsing: %s", + entry); + return -1; + } + (*cfg)->port[n].policer_params.color_mode = + mode; + } + + /* Read policer cir */ + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_PLCR_CIR); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + (*cfg)->port[n].policer_params.cir = val; + } + + /* Read policer cbs */ + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_PLCR_CBS); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + (*cfg)->port[n].policer_params.cbs = val; + } + + /* Read policer ebs */ + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_PLCR_EBS); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + (*cfg)->port[n].policer_params.ebs = val; + } + } + + /* + * Read per-port rate limiting. Setting that will + * disable per-queue rate limiting. + */ + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_RATE_LIMIT_ENABLE); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + (*cfg)->port[n].rate_limit_enable = val; + } + + if ((*cfg)->port[n].rate_limit_enable) { + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_BURST_SIZE); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + (*cfg)->port[n].rate_limit_params.cbs = val; + } + + entry = rte_cfgfile_get_entry(file, sec_name, + MRVL_TOK_RATE_LIMIT); + if (entry) { + if (get_val_securely(entry, &val) < 0) + return -1; + (*cfg)->port[n].rate_limit_params.cir = val; + } + } + entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_MAPPING_PRIORITY); if (entry) { @@ -450,16 +633,18 @@ mrvl_get_qoscfg(const char *key __rte_unused, const char *path, * @param param TC parameters entry. * @param inqs Number of MUSDK in-queues in this TC. * @param bpool Bpool for this TC. + * @param color Default color for this TC. * @returns 0 in case of success, exits otherwise. */ static int setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs, - struct pp2_bpool *bpool) + struct pp2_bpool *bpool, enum pp2_ppio_color color) { struct pp2_ppio_inq_params *inq_params; param->pkt_offset = MRVL_PKT_OFFS; param->pools[0] = bpool; + param->default_color = color; inq_params = rte_zmalloc_socket("inq_params", inqs * sizeof(*inq_params), @@ -478,6 +663,34 @@ setup_tc(struct pp2_ppio_tc_params *param, uint8_t inqs, return 0; } +/** + * Setup ingress policer. + * + * @param priv Port's private data. + * @param params Pointer to the policer's configuration. + * @returns 0 in case of success, negative values otherwise. + */ +static int +setup_policer(struct mrvl_priv *priv, struct pp2_cls_plcr_params *params) +{ + char match[16]; + int ret; + + snprintf(match, sizeof(match), "policer-%d:%d\n", + priv->pp_id, priv->ppio_id); + params->match = match; + + ret = pp2_cls_plcr_init(params, &priv->policer); + if (ret) { + MRVL_LOG(ERR, "Failed to setup %s", match); + return -1; + } + + priv->ppio_params.inqs_params.plcr = priv->policer; + + return 0; +} + /** * Configure RX Queues in a given port. * @@ -496,10 +709,13 @@ mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid, if (mrvl_qos_cfg == NULL || mrvl_qos_cfg->port[portid].use_global_defaults) { - /* No port configuration, use default: 1 TC, no QoS. */ + /* + * No port configuration, use default: 1 TC, no QoS, + * TC color set to green. + */ priv->ppio_params.inqs_params.num_tcs = 1; setup_tc(&priv->ppio_params.inqs_params.tcs_params[0], - max_queues, priv->bpool); + max_queues, priv->bpool, PP2_PPIO_COLOR_GREEN); /* Direct mapping of queues i.e. 0->0, 1->1 etc. */ for (i = 0; i < max_queues; ++i) { @@ -526,8 +742,8 @@ mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid, for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) { if (port_cfg->tc[tc].pcps > RTE_DIM(port_cfg->tc[0].pcp)) { /* Better safe than sorry. */ - RTE_LOG(ERR, PMD, - "Too many PCPs configured in TC %zu!\n", tc); + MRVL_LOG(ERR, + "Too many PCPs configured in TC %zu!", tc); return -1; } for (i = 0; i < port_cfg->tc[tc].pcps; ++i) { @@ -548,8 +764,8 @@ mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid, for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) { if (port_cfg->tc[tc].dscps > RTE_DIM(port_cfg->tc[0].dscp)) { /* Better safe than sorry. */ - RTE_LOG(ERR, PMD, - "Too many DSCPs configured in TC %zu!\n", tc); + MRVL_LOG(ERR, + "Too many DSCPs configured in TC %zu!", tc); return -1; } for (i = 0; i < port_cfg->tc[tc].dscps; ++i) { @@ -570,8 +786,8 @@ mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid, for (tc = 0; tc < RTE_DIM(port_cfg->tc); ++tc) { if (port_cfg->tc[tc].inqs > RTE_DIM(port_cfg->tc[0].inq)) { /* Overflow. */ - RTE_LOG(ERR, PMD, - "Too many RX queues configured per TC %zu!\n", + MRVL_LOG(ERR, + "Too many RX queues configured per TC %zu!", tc); return -1; } @@ -579,7 +795,7 @@ mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid, uint8_t idx = port_cfg->tc[tc].inq[i]; if (idx > RTE_DIM(priv->rxq_map)) { - RTE_LOG(ERR, PMD, "Bad queue index %d!\n", idx); + MRVL_LOG(ERR, "Bad queue index %d!", idx); return -1; } @@ -597,11 +813,53 @@ mrvl_configure_rxqs(struct mrvl_priv *priv, uint16_t portid, break; setup_tc(&priv->ppio_params.inqs_params.tcs_params[i], port_cfg->tc[i].inqs, - priv->bpool); + priv->bpool, port_cfg->tc[i].color); } priv->ppio_params.inqs_params.num_tcs = i; + if (port_cfg->policer_enable) + return setup_policer(priv, &port_cfg->policer_params); + + return 0; +} + +/** + * Configure TX Queues in a given port. + * + * Sets up TX queues egress scheduler and limiter. + * + * @param priv Port's private data + * @param portid DPDK port ID + * @param max_queues Maximum number of queues to configure. + * @returns 0 in case of success, negative value otherwise. + */ +int +mrvl_configure_txqs(struct mrvl_priv *priv, uint16_t portid, + uint16_t max_queues) +{ + /* We need only a subset of configuration. */ + struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid]; + int i; + + if (mrvl_qos_cfg == NULL) + return 0; + + priv->ppio_params.rate_limit_enable = port_cfg->rate_limit_enable; + if (port_cfg->rate_limit_enable) + priv->ppio_params.rate_limit_params = + port_cfg->rate_limit_params; + + for (i = 0; i < max_queues; i++) { + struct pp2_ppio_outq_params *params = + &priv->ppio_params.outqs_params.outqs_params[i]; + + params->sched_mode = port_cfg->outq[i].sched_mode; + params->weight = port_cfg->outq[i].weight; + params->rate_limit_enable = port_cfg->outq[i].rate_limit_enable; + params->rate_limit_params = port_cfg->outq[i].rate_limit_params; + } + return 0; } @@ -620,7 +878,7 @@ mrvl_start_qos_mapping(struct mrvl_priv *priv) size_t i; if (priv->ppio == NULL) { - RTE_LOG(ERR, PMD, "ppio must not be NULL here!\n"); + MRVL_LOG(ERR, "ppio must not be NULL here!"); return -1; }