diff options
author | Luca Boccassi <luca.boccassi@gmail.com> | 2018-08-14 18:52:30 +0100 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@gmail.com> | 2018-08-14 18:53:17 +0100 |
commit | b63264c8342e6a1b6971c79550d2af2024b6a4de (patch) | |
tree | 83114aac64286fe616506c0b3dfaec2ab86ef835 /drivers/net/mrvl/mrvl_qos.c | |
parent | ca33590b6af032bff57d9cc70455660466a654b2 (diff) |
New upstream version 18.08upstream/18.08
Change-Id: I32fdf5e5016556d9c0a6d88ddaf1fc468961790a
Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
Diffstat (limited to 'drivers/net/mrvl/mrvl_qos.c')
-rw-r--r-- | drivers/net/mrvl/mrvl_qos.c | 636 |
1 files changed, 0 insertions, 636 deletions
diff --git a/drivers/net/mrvl/mrvl_qos.c b/drivers/net/mrvl/mrvl_qos.c deleted file mode 100644 index fbb36813..00000000 --- a/drivers/net/mrvl/mrvl_qos.c +++ /dev/null @@ -1,636 +0,0 @@ -/*- - * 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. - */ - -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include <rte_common.h> -#include <rte_cfgfile.h> -#include <rte_log.h> -#include <rte_lcore.h> -#include <rte_malloc.h> -#include <rte_string_fns.h> - -/* Unluckily, container_of is defined by both DPDK and MUSDK, - * we'll declare only one version. - * - * Note that it is not used in this PMD anyway. - */ -#ifdef container_of -#undef container_of -#endif - -#include "mrvl_qos.h" - -/* Parsing tokens. Defined conveniently, so that any correction is easy. */ -#define MRVL_TOK_DEFAULT "default" -#define MRVL_TOK_DEFAULT_TC "default_tc" -#define MRVL_TOK_DSCP "dscp" -#define MRVL_TOK_MAPPING_PRIORITY "mapping_priority" -#define MRVL_TOK_IP "ip" -#define MRVL_TOK_IP_VLAN "ip/vlan" -#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" - -/** Number of tokens in range a-b = 2. */ -#define MAX_RNG_TOKENS 2 - -/** Maximum possible value of PCP. */ -#define MAX_PCP 7 - -/** Maximum possible value of DSCP. */ -#define MAX_DSCP 63 - -/** Global QoS configuration. */ -struct mrvl_qos_cfg *mrvl_qos_cfg; - -/** - * Convert string to uint32_t with extra checks for result correctness. - * - * @param string String to convert. - * @param val Conversion result. - * @returns 0 in case of success, negative value otherwise. - */ -static int -get_val_securely(const char *string, uint32_t *val) -{ - char *endptr; - size_t len = strlen(string); - - if (len == 0) - return -1; - - errno = 0; - *val = strtoul(string, &endptr, 0); - if (errno != 0 || RTE_PTR_DIFF(endptr, string) != len) - return -2; - - return 0; -} - -/** - * Read out-queue configuration from file. - * - * @param file Path to the configuration file. - * @param port Port number. - * @param outq Out queue number. - * @param cfg Pointer to the Marvell QoS configuration structure. - * @returns 0 in case of success, negative value otherwise. - */ -static int -get_outq_cfg(struct rte_cfgfile *file, int port, int outq, - struct mrvl_qos_cfg *cfg) -{ - char sec_name[32]; - const char *entry; - uint32_t val; - - snprintf(sec_name, sizeof(sec_name), "%s %d %s %d", - MRVL_TOK_PORT, port, MRVL_TOK_TXQ, outq); - - /* Skip non-existing */ - if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0) - return 0; - - entry = rte_cfgfile_get_entry(file, sec_name, - MRVL_TOK_WEIGHT); - if (entry) { - if (get_val_securely(entry, &val) < 0) - return -1; - cfg->port[port].outq[outq].weight = (uint8_t)val; - } - - return 0; -} - -/** - * Gets multiple-entry values and places them in table. - * - * Entry can be anything, e.g. "1 2-3 5 6 7-9". This needs to be converted to - * table entries, respectively: {1, 2, 3, 5, 6, 7, 8, 9}. - * As all result table's elements are always 1-byte long, we - * won't overcomplicate the function, but we'll keep API generic, - * check if someone hasn't changed element size and make it simple - * to extend to other sizes. - * - * This function is purely utilitary, it does not print any error, only returns - * different error numbers. - * - * @param entry[in] Values string to parse. - * @param tab[out] Results table. - * @param elem_sz[in] Element size (in bytes). - * @param max_elems[in] Number of results table elements available. - * @param max val[in] Maximum value allowed. - * @returns Number of correctly parsed elements in case of success. - * @retval -1 Wrong element size. - * @retval -2 More tokens than result table allows. - * @retval -3 Wrong range syntax. - * @retval -4 Wrong range values. - * @retval -5 Maximum value exceeded. - */ -static int -get_entry_values(const char *entry, uint8_t *tab, - size_t elem_sz, uint8_t max_elems, uint8_t max_val) -{ - /* There should not be more tokens than max elements. - * Add 1 for error trap. - */ - char *tokens[max_elems + 1]; - - /* Begin, End + error trap = 3. */ - char *rng_tokens[MAX_RNG_TOKENS + 1]; - long beg, end; - uint32_t token_val; - int nb_tokens, nb_rng_tokens; - int i; - int values = 0; - char val; - char entry_cpy[CFG_VALUE_LEN]; - - if (elem_sz != 1) - return -1; - - /* Copy the entry to safely use rte_strsplit(). */ - snprintf(entry_cpy, RTE_DIM(entry_cpy), "%s", entry); - - /* - * If there are more tokens than array size, rte_strsplit will - * not return error, just array size. - */ - nb_tokens = rte_strsplit(entry_cpy, strlen(entry_cpy), - tokens, max_elems + 1, ' '); - - /* Quick check, will be refined later. */ - if (nb_tokens > max_elems) - return -2; - - for (i = 0; i < nb_tokens; ++i) { - if (strchr(tokens[i], '-') != NULL) { - /* - * Split to begin and end tokens. - * We want to catch error cases too, thus we leave - * option for number of tokens to be more than 2. - */ - nb_rng_tokens = rte_strsplit(tokens[i], - strlen(tokens[i]), rng_tokens, - RTE_DIM(rng_tokens), '-'); - if (nb_rng_tokens != 2) - return -3; - - /* Range and sanity checks. */ - if (get_val_securely(rng_tokens[0], &token_val) < 0) - return -4; - beg = (char)token_val; - if (get_val_securely(rng_tokens[1], &token_val) < 0) - return -4; - end = (char)token_val; - if (beg < 0 || beg > UCHAR_MAX || - end < 0 || end > UCHAR_MAX || end < beg) - return -4; - - for (val = beg; val <= end; ++val) { - if (val > max_val) - return -5; - - *tab = val; - tab = RTE_PTR_ADD(tab, elem_sz); - ++values; - if (values >= max_elems) - return -2; - } - } else { - /* Single values. */ - if (get_val_securely(tokens[i], &token_val) < 0) - return -5; - val = (char)token_val; - if (val > max_val) - return -5; - - *tab = val; - tab = RTE_PTR_ADD(tab, elem_sz); - ++values; - if (values >= max_elems) - return -2; - } - } - - return values; -} - -/** - * Parse Traffic Class'es mapping configuration. - * - * @param file Config file handle. - * @param port Which port to look for. - * @param tc Which Traffic Class to look for. - * @param cfg[out] Parsing results. - * @returns 0 in case of success, negative value otherwise. - */ -static int -parse_tc_cfg(struct rte_cfgfile *file, int port, int tc, - struct mrvl_qos_cfg *cfg) -{ - char sec_name[32]; - const char *entry; - int n; - - snprintf(sec_name, sizeof(sec_name), "%s %d %s %d", - MRVL_TOK_PORT, port, MRVL_TOK_TC, tc); - - /* Skip non-existing */ - if (rte_cfgfile_num_sections(file, sec_name, strlen(sec_name)) <= 0) - return 0; - - entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_RXQ); - if (entry) { - n = get_entry_values(entry, - cfg->port[port].tc[tc].inq, - sizeof(cfg->port[port].tc[tc].inq[0]), - 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", - n, entry); - return n; - } - cfg->port[port].tc[tc].inqs = n; - } - - entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_PCP); - if (entry) { - n = get_entry_values(entry, - cfg->port[port].tc[tc].pcp, - sizeof(cfg->port[port].tc[tc].pcp[0]), - RTE_DIM(cfg->port[port].tc[tc].pcp), - MAX_PCP); - if (n < 0) { - RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n", - n, entry); - return n; - } - cfg->port[port].tc[tc].pcps = n; - } - - entry = rte_cfgfile_get_entry(file, sec_name, MRVL_TOK_DSCP); - if (entry) { - n = get_entry_values(entry, - cfg->port[port].tc[tc].dscp, - sizeof(cfg->port[port].tc[tc].dscp[0]), - RTE_DIM(cfg->port[port].tc[tc].dscp), - MAX_DSCP); - if (n < 0) { - RTE_LOG(ERR, PMD, "Error %d while parsing: %s\n", - n, entry); - return n; - } - cfg->port[port].tc[tc].dscps = n; - } - return 0; -} - -/** - * Parse QoS configuration - rte_kvargs_process handler. - * - * Opens configuration file and parses its content. - * - * @param key Unused. - * @param path Path to config file. - * @param extra_args Pointer to configuration structure. - * @returns 0 in case of success, exits otherwise. - */ -int -mrvl_get_qoscfg(const char *key __rte_unused, const char *path, - void *extra_args) -{ - struct mrvl_qos_cfg **cfg = extra_args; - struct rte_cfgfile *file = rte_cfgfile_load(path, 0); - uint32_t val; - int n, i, ret; - const char *entry; - char sec_name[32]; - - if (file == NULL) - rte_exit(EXIT_FAILURE, "Cannot load configuration %s\n", path); - - /* Create configuration. This is never accessed on the fast path, - * so we can ignore socket. - */ - *cfg = rte_zmalloc("mrvl_qos_cfg", sizeof(struct mrvl_qos_cfg), 0); - if (*cfg == NULL) - rte_exit(EXIT_FAILURE, "Cannot allocate configuration %s\n", - path); - - n = rte_cfgfile_num_sections(file, MRVL_TOK_PORT, - sizeof(MRVL_TOK_PORT) - 1); - - if (n == 0) { - /* This is weird, but not bad. */ - RTE_LOG(WARNING, PMD, "Empty configuration file?\n"); - return 0; - } - - /* Use the number of ports given as vdev parameters. */ - for (n = 0; n < (PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC); ++n) { - snprintf(sec_name, sizeof(sec_name), "%s %d %s", - MRVL_TOK_PORT, n, MRVL_TOK_DEFAULT); - - /* Skip ports non-existing in configuration. */ - if (rte_cfgfile_num_sections(file, sec_name, - strlen(sec_name)) <= 0) { - (*cfg)->port[n].use_global_defaults = 1; - (*cfg)->port[n].mapping_priority = - PP2_CLS_QOS_TBL_VLAN_IP_PRI; - continue; - } - - entry = rte_cfgfile_get_entry(file, sec_name, - MRVL_TOK_DEFAULT_TC); - if (entry) { - if (get_val_securely(entry, &val) < 0 || - val > USHRT_MAX) - return -1; - (*cfg)->port[n].default_tc = (uint8_t)val; - } else { - RTE_LOG(ERR, PMD, - "Default Traffic Class required in custom configuration!\n"); - return -1; - } - - entry = rte_cfgfile_get_entry(file, sec_name, - MRVL_TOK_MAPPING_PRIORITY); - if (entry) { - if (!strncmp(entry, MRVL_TOK_VLAN_IP, - sizeof(MRVL_TOK_VLAN_IP))) - (*cfg)->port[n].mapping_priority = - PP2_CLS_QOS_TBL_VLAN_IP_PRI; - else if (!strncmp(entry, MRVL_TOK_IP_VLAN, - sizeof(MRVL_TOK_IP_VLAN))) - (*cfg)->port[n].mapping_priority = - PP2_CLS_QOS_TBL_IP_VLAN_PRI; - else if (!strncmp(entry, MRVL_TOK_IP, - sizeof(MRVL_TOK_IP))) - (*cfg)->port[n].mapping_priority = - PP2_CLS_QOS_TBL_IP_PRI; - else if (!strncmp(entry, MRVL_TOK_VLAN, - sizeof(MRVL_TOK_VLAN))) - (*cfg)->port[n].mapping_priority = - PP2_CLS_QOS_TBL_VLAN_PRI; - else - rte_exit(EXIT_FAILURE, - "Error in parsing %s value (%s)!\n", - MRVL_TOK_MAPPING_PRIORITY, entry); - } else { - (*cfg)->port[n].mapping_priority = - PP2_CLS_QOS_TBL_VLAN_IP_PRI; - } - - for (i = 0; i < MRVL_PP2_RXQ_MAX; ++i) { - ret = get_outq_cfg(file, n, i, *cfg); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Error %d parsing port %d outq %d!\n", - ret, n, i); - } - - for (i = 0; i < MRVL_PP2_TC_MAX; ++i) { - ret = parse_tc_cfg(file, n, i, *cfg); - if (ret < 0) - rte_exit(EXIT_FAILURE, - "Error %d parsing port %d tc %d!\n", - ret, n, i); - } - } - - return 0; -} - -/** - * Setup Traffic Class. - * - * Fill in TC parameters in single MUSDK TC config entry. - * @param param TC parameters entry. - * @param inqs Number of MUSDK in-queues in this TC. - * @param bpool Bpool 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_ppio_inq_params *inq_params; - - param->pkt_offset = MRVL_PKT_OFFS; - param->pools[0] = bpool; - - inq_params = rte_zmalloc_socket("inq_params", - inqs * sizeof(*inq_params), - 0, rte_socket_id()); - if (!inq_params) - return -ENOMEM; - - param->num_in_qs = inqs; - - /* Release old config if necessary. */ - if (param->inqs_params) - rte_free(param->inqs_params); - - param->inqs_params = inq_params; - - return 0; -} - -/** - * Configure RX Queues in a given port. - * - * Sets up RX queues, their Traffic Classes and DPDK rxq->(TC,inq) mapping. - * - * @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_rxqs(struct mrvl_priv *priv, uint16_t portid, - uint16_t max_queues) -{ - size_t i, tc; - - if (mrvl_qos_cfg == NULL || - mrvl_qos_cfg->port[portid].use_global_defaults) { - /* No port configuration, use default: 1 TC, no QoS. */ - priv->ppio_params.inqs_params.num_tcs = 1; - setup_tc(&priv->ppio_params.inqs_params.tcs_params[0], - max_queues, priv->bpool); - - /* Direct mapping of queues i.e. 0->0, 1->1 etc. */ - for (i = 0; i < max_queues; ++i) { - priv->rxq_map[i].tc = 0; - priv->rxq_map[i].inq = i; - } - return 0; - } - - /* We need only a subset of configuration. */ - struct port_cfg *port_cfg = &mrvl_qos_cfg->port[portid]; - - priv->qos_tbl_params.type = port_cfg->mapping_priority; - - /* - * We need to reverse mapping, from tc->pcp (better from usability - * point of view) to pcp->tc (configurable in MUSDK). - * First, set all map elements to "default". - */ - for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i) - priv->qos_tbl_params.pcp_cos_map[i].tc = port_cfg->default_tc; - - /* Then, fill in all known values. */ - 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); - return -1; - } - for (i = 0; i < port_cfg->tc[tc].pcps; ++i) { - priv->qos_tbl_params.pcp_cos_map[ - port_cfg->tc[tc].pcp[i]].tc = tc; - } - } - - /* - * The same logic goes with DSCP. - * First, set all map elements to "default". - */ - for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i) - priv->qos_tbl_params.dscp_cos_map[i].tc = - port_cfg->default_tc; - - /* Fill in all known values. */ - 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); - return -1; - } - for (i = 0; i < port_cfg->tc[tc].dscps; ++i) { - priv->qos_tbl_params.dscp_cos_map[ - port_cfg->tc[tc].dscp[i]].tc = tc; - } - } - - /* - * Surprisingly, similar logic goes with queue mapping. - * We need only to store qid->tc mapping, - * to know TC when queue is read. - */ - for (i = 0; i < RTE_DIM(priv->rxq_map); ++i) - priv->rxq_map[i].tc = MRVL_UNKNOWN_TC; - - /* Set up DPDKq->(TC,inq) mapping. */ - 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", - tc); - return -1; - } - for (i = 0; i < port_cfg->tc[tc].inqs; ++i) { - 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); - return -1; - } - - priv->rxq_map[idx].tc = tc; - priv->rxq_map[idx].inq = i; - } - } - - /* - * Set up TC configuration. TCs need to be sequenced: 0, 1, 2 - * with no gaps. Empty TC means end of processing. - */ - for (i = 0; i < MRVL_PP2_TC_MAX; ++i) { - if (port_cfg->tc[i].inqs == 0) - break; - setup_tc(&priv->ppio_params.inqs_params.tcs_params[i], - port_cfg->tc[i].inqs, - priv->bpool); - } - - priv->ppio_params.inqs_params.num_tcs = i; - - return 0; -} - -/** - * Start QoS mapping. - * - * Finalize QoS table configuration and initialize it in SDK. It can be done - * only after port is started, so we have a valid ppio reference. - * - * @param priv Port's private (configuration) data. - * @returns 0 in case of success, exits otherwise. - */ -int -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"); - return -1; - } - - for (i = 0; i < RTE_DIM(priv->qos_tbl_params.pcp_cos_map); ++i) - priv->qos_tbl_params.pcp_cos_map[i].ppio = priv->ppio; - - for (i = 0; i < RTE_DIM(priv->qos_tbl_params.dscp_cos_map); ++i) - priv->qos_tbl_params.dscp_cos_map[i].ppio = priv->ppio; - - /* Initialize Classifier QoS table. */ - - return pp2_cls_qos_tbl_init(&priv->qos_tbl_params, &priv->qos_tbl); -} |