New upstream version 18.08
[deb_dpdk.git] / 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 fbb3681..71856c1 100644 (file)
@@ -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 <stdint.h>
 #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;
        }