X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmlx5%2Fmlx5.c;h=787ad00bca00e9fb5778555d5fdd6e9da3d4e7dd;hb=82e75f8323bf8544ee4756787b99bce2ae6a7cb0;hp=1adef851edb2bfe312dd71e097e52a531f6be75e;hpb=6bc327b94fe8aaf06e7eef918d4c8c32bcaa9252;p=dpdk.git diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 1adef851ed..787ad00bca 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -95,6 +95,12 @@ /* Device parameter to enable multi-packet send WQEs. */ #define MLX5_TXQ_MPW_EN "txq_mpw_en" +/* + * Device parameter to force doorbell register mapping + * to non-cahed region eliminating the extra write memory barrier. + */ +#define MLX5_TX_DB_NC "tx_db_nc" + /* * Device parameter to include 2 dsegs in the title WQEBB. * Deprecated, ignored. @@ -184,6 +190,9 @@ static pthread_mutex_t mlx5_ibv_list_mutex = PTHREAD_MUTEX_INITIALIZER; #define MLX5_FLOW_MIN_ID_POOL_SIZE 512 #define MLX5_ID_GENERATION_ARRAY_FACTOR 16 +#define MLX5_FLOW_TABLE_HLIST_ARRAY_SIZE 4096 +#define MLX5_TAGS_HLIST_ARRAY_SIZE 8192 + /** * Allocate ID pool structure. * @@ -421,6 +430,35 @@ mlx5_get_pdn(struct ibv_pd *pd __rte_unused, uint32_t *pdn __rte_unused) } #endif /* HAVE_IBV_FLOW_DV_SUPPORT */ +static int +mlx5_config_doorbell_mapping_env(const struct mlx5_dev_config *config) +{ + char *env; + int value; + + assert(rte_eal_process_type() == RTE_PROC_PRIMARY); + /* Get environment variable to store. */ + env = getenv(MLX5_SHUT_UP_BF); + value = env ? !!strcmp(env, "0") : MLX5_ARG_UNSET; + if (config->dbnc == MLX5_ARG_UNSET) + setenv(MLX5_SHUT_UP_BF, MLX5_SHUT_UP_BF_DEFAULT, 1); + else + setenv(MLX5_SHUT_UP_BF, + config->dbnc == MLX5_TXDB_NCACHED ? "1" : "0", 1); + return value; +} + +static void +mlx5_restore_doorbell_mapping_env(int value) +{ + assert(rte_eal_process_type() == RTE_PROC_PRIMARY); + /* Restore the original environment variable state. */ + if (value == MLX5_ARG_UNSET) + unsetenv(MLX5_SHUT_UP_BF); + else + setenv(MLX5_SHUT_UP_BF, value ? "1" : "0", 1); +} + /** * Allocate shared IB device context. If there is multiport device the * master and representors will share this context, if there is single @@ -434,22 +472,26 @@ mlx5_get_pdn(struct ibv_pd *pd __rte_unused, uint32_t *pdn __rte_unused) * * @param[in] spawn * Pointer to the IB device attributes (name, port, etc). + * @param[in] config + * Pointer to device configuration structure. * * @return * Pointer to mlx5_ibv_shared object on success, * otherwise NULL and rte_errno is set. */ static struct mlx5_ibv_shared * -mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn) +mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn, + const struct mlx5_dev_config *config) { struct mlx5_ibv_shared *sh; + int dbmap_env; int err = 0; uint32_t i; #ifdef HAVE_IBV_FLOW_DV_SUPPORT struct mlx5_devx_tis_attr tis_attr = { 0 }; #endif -assert(spawn); + assert(spawn); /* Secondary process should not create the shared context. */ assert(rte_eal_process_type() == RTE_PROC_PRIMARY); pthread_mutex_lock(&mlx5_ibv_list_mutex); @@ -472,18 +514,32 @@ assert(spawn); rte_errno = ENOMEM; goto exit; } + /* + * Configure environment variable "MLX5_BF_SHUT_UP" + * before the device creation. The rdma_core library + * checks the variable at device creation and + * stores the result internally. + */ + dbmap_env = mlx5_config_doorbell_mapping_env(config); /* Try to open IB device with DV first, then usual Verbs. */ errno = 0; sh->ctx = mlx5_glue->dv_open_device(spawn->ibv_dev); if (sh->ctx) { sh->devx = 1; DRV_LOG(DEBUG, "DevX is supported"); + /* The device is created, no need for environment. */ + mlx5_restore_doorbell_mapping_env(dbmap_env); } else { + /* The environment variable is still configured. */ sh->ctx = mlx5_glue->open_device(spawn->ibv_dev); - if (!sh->ctx) { - err = errno ? errno : ENODEV; + err = errno ? errno : ENODEV; + /* + * The environment variable is not needed anymore, + * all device creation attempts are completed. + */ + mlx5_restore_doorbell_mapping_env(dbmap_env); + if (!sh->ctx) goto error; - } DRV_LOG(DEBUG, "DevX is NOT supported"); } err = mlx5_glue->query_device_ex(sh->ctx, NULL, &sh->device_attr); @@ -659,6 +715,143 @@ exit: pthread_mutex_unlock(&mlx5_ibv_list_mutex); } +/** + * Destroy table hash list and all the root entries per domain. + * + * @param[in] priv + * Pointer to the private device data structure. + */ +static void +mlx5_free_table_hash_list(struct mlx5_priv *priv) +{ + struct mlx5_ibv_shared *sh = priv->sh; + struct mlx5_flow_tbl_data_entry *tbl_data; + union mlx5_flow_tbl_key table_key = { + { + .table_id = 0, + .reserved = 0, + .domain = 0, + .direction = 0, + } + }; + struct mlx5_hlist_entry *pos; + + if (!sh->flow_tbls) + return; + pos = mlx5_hlist_lookup(sh->flow_tbls, table_key.v64); + if (pos) { + tbl_data = container_of(pos, struct mlx5_flow_tbl_data_entry, + entry); + assert(tbl_data); + mlx5_hlist_remove(sh->flow_tbls, pos); + rte_free(tbl_data); + } + table_key.direction = 1; + pos = mlx5_hlist_lookup(sh->flow_tbls, table_key.v64); + if (pos) { + tbl_data = container_of(pos, struct mlx5_flow_tbl_data_entry, + entry); + assert(tbl_data); + mlx5_hlist_remove(sh->flow_tbls, pos); + rte_free(tbl_data); + } + table_key.direction = 0; + table_key.domain = 1; + pos = mlx5_hlist_lookup(sh->flow_tbls, table_key.v64); + if (pos) { + tbl_data = container_of(pos, struct mlx5_flow_tbl_data_entry, + entry); + assert(tbl_data); + mlx5_hlist_remove(sh->flow_tbls, pos); + rte_free(tbl_data); + } + mlx5_hlist_destroy(sh->flow_tbls, NULL, NULL); +} + +/** + * Initialize flow table hash list and create the root tables entry + * for each domain. + * + * @param[in] priv + * Pointer to the private device data structure. + * + * @return + * Zero on success, positive error code otherwise. + */ +static int +mlx5_alloc_table_hash_list(struct mlx5_priv *priv) +{ + struct mlx5_ibv_shared *sh = priv->sh; + char s[MLX5_HLIST_NAMESIZE]; + int err = 0; + + assert(sh); + snprintf(s, sizeof(s), "%s_flow_table", priv->sh->ibdev_name); + sh->flow_tbls = mlx5_hlist_create(s, MLX5_FLOW_TABLE_HLIST_ARRAY_SIZE); + if (!sh->flow_tbls) { + DRV_LOG(ERR, "flow tables with hash creation failed.\n"); + err = ENOMEM; + return err; + } +#ifndef HAVE_MLX5DV_DR + /* + * In case we have not DR support, the zero tables should be created + * because DV expect to see them even if they cannot be created by + * RDMA-CORE. + */ + union mlx5_flow_tbl_key table_key = { + { + .table_id = 0, + .reserved = 0, + .domain = 0, + .direction = 0, + } + }; + struct mlx5_flow_tbl_data_entry *tbl_data = rte_zmalloc(NULL, + sizeof(*tbl_data), 0); + + if (!tbl_data) { + err = ENOMEM; + goto error; + } + tbl_data->entry.key = table_key.v64; + err = mlx5_hlist_insert(sh->flow_tbls, &tbl_data->entry); + if (err) + goto error; + rte_atomic32_init(&tbl_data->tbl.refcnt); + rte_atomic32_inc(&tbl_data->tbl.refcnt); + table_key.direction = 1; + tbl_data = rte_zmalloc(NULL, sizeof(*tbl_data), 0); + if (!tbl_data) { + err = ENOMEM; + goto error; + } + tbl_data->entry.key = table_key.v64; + err = mlx5_hlist_insert(sh->flow_tbls, &tbl_data->entry); + if (err) + goto error; + rte_atomic32_init(&tbl_data->tbl.refcnt); + rte_atomic32_inc(&tbl_data->tbl.refcnt); + table_key.direction = 0; + table_key.domain = 1; + tbl_data = rte_zmalloc(NULL, sizeof(*tbl_data), 0); + if (!tbl_data) { + err = ENOMEM; + goto error; + } + tbl_data->entry.key = table_key.v64; + err = mlx5_hlist_insert(sh->flow_tbls, &tbl_data->entry); + if (err) + goto error; + rte_atomic32_init(&tbl_data->tbl.refcnt); + rte_atomic32_inc(&tbl_data->tbl.refcnt); + return err; +error: + mlx5_free_table_hash_list(priv); +#endif /* HAVE_MLX5DV_DR */ + return err; +} + /** * Initialize DR related data within private structure. * Routine checks the reference counter and does actual @@ -673,12 +866,23 @@ exit: static int mlx5_alloc_shared_dr(struct mlx5_priv *priv) { -#ifdef HAVE_MLX5DV_DR struct mlx5_ibv_shared *sh = priv->sh; - int err = 0; + char s[MLX5_HLIST_NAMESIZE]; + int err = mlx5_alloc_table_hash_list(priv); + + if (err) + return err; + /* Create tags hash list table. */ + snprintf(s, sizeof(s), "%s_tags", sh->ibdev_name); + sh->tag_table = mlx5_hlist_create(s, MLX5_TAGS_HLIST_ARRAY_SIZE); + if (!sh->tag_table) { + DRV_LOG(ERR, "tags with hash creation failed.\n"); + err = ENOMEM; + goto error; + } +#ifdef HAVE_MLX5DV_DR void *domain; - assert(sh); if (sh->dv_refcnt) { /* Shared DV/DR structures is already initialized. */ sh->dv_refcnt++; @@ -717,12 +921,12 @@ mlx5_alloc_shared_dr(struct mlx5_priv *priv) } #endif sh->pop_vlan_action = mlx5_glue->dr_create_flow_action_pop_vlan(); +#endif /* HAVE_MLX5DV_DR */ sh->dv_refcnt++; priv->dr_shared = 1; return 0; - error: - /* Rollback the created objects. */ + /* Rollback the created objects. */ if (sh->rx_domain) { mlx5_glue->dr_destroy_domain(sh->rx_domain); sh->rx_domain = NULL; @@ -743,11 +947,13 @@ error: mlx5_glue->destroy_flow_action(sh->pop_vlan_action); sh->pop_vlan_action = NULL; } + if (sh->tag_table) { + /* tags should be destroyed with flow before. */ + mlx5_hlist_destroy(sh->tag_table, NULL, NULL); + sh->tag_table = NULL; + } + mlx5_free_table_hash_list(priv); return err; -#else - (void)priv; - return 0; -#endif } /** @@ -759,7 +965,6 @@ error: static void mlx5_free_shared_dr(struct mlx5_priv *priv) { -#ifdef HAVE_MLX5DV_DR struct mlx5_ibv_shared *sh; if (!priv->dr_shared) @@ -767,6 +972,7 @@ mlx5_free_shared_dr(struct mlx5_priv *priv) priv->dr_shared = 0; sh = priv->sh; assert(sh); +#ifdef HAVE_MLX5DV_DR assert(sh->dv_refcnt); if (sh->dv_refcnt && --sh->dv_refcnt) return; @@ -793,9 +999,13 @@ mlx5_free_shared_dr(struct mlx5_priv *priv) sh->pop_vlan_action = NULL; } pthread_mutex_destroy(&sh->dv_mutex); -#else - (void)priv; -#endif +#endif /* HAVE_MLX5DV_DR */ + if (sh->tag_table) { + /* tags should be destroyed with flow before. */ + mlx5_hlist_destroy(sh->tag_table, NULL, NULL); + sh->tag_table = NULL; + } + mlx5_free_table_hash_list(priv); } /** @@ -1016,6 +1226,7 @@ mlx5_dev_close(struct rte_eth_dev *dev) mlx5_dev_interrupt_handler_devx_uninstall(dev); mlx5_traffic_disable(dev); mlx5_flow_flush(dev, NULL); + mlx5_flow_meter_flush(dev, NULL); /* Prevent crashes when queues are still in use. */ dev->rx_pkt_burst = removed_rx_burst; dev->tx_pkt_burst = removed_tx_burst; @@ -1299,6 +1510,16 @@ mlx5_args_check(const char *key, const char *val, void *opaque) DRV_LOG(WARNING, "%s: deprecated parameter, ignored", key); } else if (strcmp(MLX5_TXQ_MPW_EN, key) == 0) { config->mps = !!tmp; + } else if (strcmp(MLX5_TX_DB_NC, key) == 0) { + if (tmp != MLX5_TXDB_CACHED && + tmp != MLX5_TXDB_NCACHED && + tmp != MLX5_TXDB_HEURISTIC) { + DRV_LOG(ERR, "invalid Tx doorbell " + "mapping parameter"); + rte_errno = EINVAL; + return -rte_errno; + } + config->dbnc = tmp; } else if (strcmp(MLX5_TXQ_MPW_HDR_DSEG_EN, key) == 0) { DRV_LOG(WARNING, "%s: deprecated parameter, ignored", key); } else if (strcmp(MLX5_TXQ_MAX_INLINE_LEN, key) == 0) { @@ -1321,8 +1542,8 @@ mlx5_args_check(const char *key, const char *val, void *opaque) if (tmp != MLX5_XMETA_MODE_LEGACY && tmp != MLX5_XMETA_MODE_META16 && tmp != MLX5_XMETA_MODE_META32) { - DRV_LOG(WARNING, "invalid extensive " - "metadata parameter"); + DRV_LOG(ERR, "invalid extensive " + "metadata parameter"); rte_errno = EINVAL; return -rte_errno; } @@ -1372,6 +1593,7 @@ mlx5_args(struct mlx5_dev_config *config, struct rte_devargs *devargs) MLX5_TXQ_MPW_EN, MLX5_TXQ_MPW_HDR_DSEG_EN, MLX5_TXQ_MAX_INLINE_LEN, + MLX5_TX_DB_NC, MLX5_TX_VEC_EN, MLX5_RX_VEC_EN, MLX5_L3_VXLAN_EN, @@ -1937,7 +2159,20 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, eth_dev->tx_pkt_burst = mlx5_select_tx_function(eth_dev); return eth_dev; } - sh = mlx5_alloc_shared_ibctx(spawn); + /* + * Some parameters ("tx_db_nc" in particularly) are needed in + * advance to create dv/verbs device context. We proceed the + * devargs here to get ones, and later proceed devargs again + * to override some hardware settings. + */ + err = mlx5_args(&config, dpdk_dev->devargs); + if (err) { + err = rte_errno; + DRV_LOG(ERR, "failed to process device arguments: %s", + strerror(rte_errno)); + goto error; + } + sh = mlx5_alloc_shared_ibctx(spawn, &config); if (!sh) return NULL; config.devx = sh->devx; @@ -2122,7 +2357,8 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, err = ENOTSUP; goto error; } - } else if (devx_port.comp_mask & MLX5DV_DEVX_PORT_VPORT) { + } + if (devx_port.comp_mask & MLX5DV_DEVX_PORT_VPORT) { priv->vport_id = devx_port.vport_num; } else if (spawn->pf_bond >= 0) { DRV_LOG(ERR, "can't deduce vport index for port %d" @@ -2179,13 +2415,8 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, } own_domain_id = 1; } - err = mlx5_args(&config, dpdk_dev->devargs); - if (err) { - err = rte_errno; - DRV_LOG(ERR, "failed to process device arguments: %s", - strerror(rte_errno)); - goto error; - } + /* Override some values set by hardware configuration. */ + mlx5_args(&config, dpdk_dev->devargs); err = mlx5_dev_check_sibling_config(priv, &config); if (err) goto error; @@ -2197,7 +2428,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, !defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) DRV_LOG(DEBUG, "counters are not supported"); #endif -#ifndef HAVE_IBV_FLOW_DV_SUPPORT +#if !defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_MLX5DV_DR) if (config.dv_flow_en) { DRV_LOG(WARNING, "DV flow is not supported"); config.dv_flow_en = 0; @@ -2248,7 +2479,8 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, else config.mps = config.mps ? mps : MLX5_MPW_DISABLED; DRV_LOG(INFO, "%sMPS is %s", - config.mps == MLX5_MPW_ENHANCED ? "enhanced " : "", + config.mps == MLX5_MPW_ENHANCED ? "enhanced " : + config.mps == MLX5_MPW ? "legacy " : "", config.mps != MLX5_MPW_DISABLED ? "enabled" : "disabled"); if (config.cqe_comp && !cqe_comp) { DRV_LOG(WARNING, "Rx CQE compression isn't supported"); @@ -2293,7 +2525,25 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, #if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER) if (config.hca_attr.qos.sup && config.hca_attr.qos.srtcm_sup && config.dv_flow_en) { - priv->mtr_en = 1; + uint8_t reg_c_mask = + config.hca_attr.qos.flow_meter_reg_c_ids; + /* + * Meter needs two REG_C's for color match and pre-sfx + * flow match. Here get the REG_C for color match. + * REG_C_0 and REG_C_1 is reserved for metadata feature. + */ + reg_c_mask &= 0xfc; + if (__builtin_popcount(reg_c_mask) < 1) { + priv->mtr_en = 0; + DRV_LOG(WARNING, "No available register for" + " meter."); + } else { + priv->mtr_color_reg = ffs(reg_c_mask) - 1 + + REG_C_0; + priv->mtr_en = 1; + DRV_LOG(DEBUG, "The REG_C meter uses is %d", + priv->mtr_color_reg); + } } #endif } @@ -2385,6 +2635,8 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, mlx5_nl_mac_addr_sync(eth_dev); TAILQ_INIT(&priv->flows); TAILQ_INIT(&priv->ctrl_flows); + TAILQ_INIT(&priv->flow_meters); + TAILQ_INIT(&priv->flow_meter_profiles); /* Hint libmlx5 to use PMD allocator for data plane resources */ struct mlx5dv_ctx_allocators alctr = { .alloc = &mlx5_alloc_verbs_buf, @@ -3010,6 +3262,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, dev_config = (struct mlx5_dev_config){ .hw_padding = 0, .mps = MLX5_ARG_UNSET, + .dbnc = MLX5_ARG_UNSET, .rx_vec_en = 1, .txq_inline_max = MLX5_ARG_UNSET, .txq_inline_min = MLX5_ARG_UNSET, @@ -3024,6 +3277,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, .min_rxqs_num = MLX5_MPRQ_MIN_RXQS, }, .dv_esw_en = 1, + .dv_flow_en = 1, }; /* Device specific configuration. */ switch (pci_dev->id.device_id) {