X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmlx5%2Fmlx5.c;h=f49d30c05cd2de0c6b84ec590efe2a9111c3639b;hb=d84c3cf7662c6abca83df803aaa5136b73d3831d;hp=b26632d2499079a132ed70ac556facd447bd6ab5;hpb=cf004fd33acca27a506b65904564eaf1cde4eea7;p=dpdk.git diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index b26632d249..f49d30c05c 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -43,9 +43,6 @@ #define MLX5_ETH_DRIVER_NAME mlx5_eth -/* Driver type key for new device global syntax. */ -#define MLX5_DRIVER_KEY "driver" - /* Device parameter to enable RX completion queue compression. */ #define MLX5_RXQ_CQE_COMP_EN "rxq_cqe_comp_en" @@ -94,12 +91,6 @@ /* 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. @@ -152,9 +143,6 @@ /* Activate Netlink support in VF mode. */ #define MLX5_VF_NL_EN "vf_nl_en" -/* Enable extending memsegs when creating a MR. */ -#define MLX5_MR_EXT_MEMSEG_EN "mr_ext_memseg_en" - /* Select port representors to instantiate. */ #define MLX5_REPRESENTOR "representor" @@ -173,17 +161,12 @@ /* Flow memory reclaim mode. */ #define MLX5_RECLAIM_MEM "reclaim_mem_mode" -/* The default memory allocator used in PMD. */ -#define MLX5_SYS_MEM_EN "sys_mem_en" /* Decap will be used or not. */ #define MLX5_DECAP_EN "decap_en" /* Device parameter to configure allow or prevent duplicate rules pattern. */ #define MLX5_ALLOW_DUPLICATE_PATTERN "allow_duplicate_pattern" -/* Device parameter to configure implicit registration of mempool memory. */ -#define MLX5_MR_MEMPOOL_REG_EN "mr_mempool_reg_en" - /* Device parameter to configure the delay drop when creating Rxqs. */ #define MLX5_DELAY_DROP "delay_drop" @@ -533,7 +516,7 @@ mlx5_flow_counter_mode_config(struct rte_eth_dev *dev __rte_unused) fallback = true; #else fallback = false; - if (!sh->cdev->config.devx || !priv->config.dv_flow_en || + if (!sh->cdev->config.devx || !sh->config.dv_flow_en || !hca_attr->flow_counters_dump || !(hca_attr->flow_counter_bulk_alloc_bitmap & 0x4) || (mlx5_flow_dv_discover_counter_offset_support(dev) == -ENOTSUP)) @@ -836,12 +819,9 @@ mlx5_flow_aso_ct_mng_close(struct mlx5_dev_ctx_shared *sh) * * @param[in] sh * Pointer to mlx5_dev_ctx_shared object. - * @param[in] config - * Pointer to user dev config. */ static void -mlx5_flow_ipool_create(struct mlx5_dev_ctx_shared *sh, - const struct mlx5_dev_config *config) +mlx5_flow_ipool_create(struct mlx5_dev_ctx_shared *sh) { uint8_t i; struct mlx5_indexed_pool_config cfg; @@ -856,12 +836,12 @@ mlx5_flow_ipool_create(struct mlx5_dev_ctx_shared *sh, * according to PCI function flow configuration. */ case MLX5_IPOOL_MLX5_FLOW: - cfg.size = config->dv_flow_en ? + cfg.size = sh->config.dv_flow_en ? sizeof(struct mlx5_flow_handle) : MLX5_FLOW_HANDLE_VERBS_SIZE; break; } - if (config->reclaim_mode) { + if (sh->config.reclaim_mode) { cfg.release_mem_en = 1; cfg.per_core_cache = 0; } else { @@ -1169,19 +1149,210 @@ mlx5_setup_tis(struct mlx5_dev_ctx_shared *sh) return 0; } +/** + * Verify and store value for share device argument. + * + * @param[in] key + * Key argument to verify. + * @param[in] val + * Value associated with key. + * @param opaque + * User data. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_dev_args_check_handler(const char *key, const char *val, void *opaque) +{ + struct mlx5_sh_config *config = opaque; + signed long tmp; + + errno = 0; + tmp = strtol(val, NULL, 0); + if (errno) { + rte_errno = errno; + DRV_LOG(WARNING, "%s: \"%s\" is not a valid integer", key, val); + return -rte_errno; + } + if (tmp < 0 && strcmp(MLX5_TX_PP, key) && strcmp(MLX5_TX_SKEW, key)) { + /* Negative values are acceptable for some keys only. */ + rte_errno = EINVAL; + DRV_LOG(WARNING, "%s: invalid negative value \"%s\"", key, val); + return -rte_errno; + } + if (strcmp(MLX5_TX_PP, key) == 0) { + unsigned long mod = tmp >= 0 ? tmp : -tmp; + + if (!mod) { + DRV_LOG(ERR, "Zero Tx packet pacing parameter."); + rte_errno = EINVAL; + return -rte_errno; + } + config->tx_pp = tmp; + } else if (strcmp(MLX5_TX_SKEW, key) == 0) { + config->tx_skew = tmp; + } else if (strcmp(MLX5_L3_VXLAN_EN, key) == 0) { + config->l3_vxlan_en = !!tmp; + } else if (strcmp(MLX5_VF_NL_EN, key) == 0) { + config->vf_nl_en = !!tmp; + } else if (strcmp(MLX5_DV_ESW_EN, key) == 0) { + config->dv_esw_en = !!tmp; + } else if (strcmp(MLX5_DV_FLOW_EN, key) == 0) { + if (tmp > 2) { + DRV_LOG(ERR, "Invalid %s parameter.", key); + rte_errno = EINVAL; + return -rte_errno; + } + config->dv_flow_en = tmp; + } else if (strcmp(MLX5_DV_XMETA_EN, key) == 0) { + if (tmp != MLX5_XMETA_MODE_LEGACY && + tmp != MLX5_XMETA_MODE_META16 && + tmp != MLX5_XMETA_MODE_META32 && + tmp != MLX5_XMETA_MODE_MISS_INFO) { + DRV_LOG(ERR, "Invalid extensive metadata parameter."); + rte_errno = EINVAL; + return -rte_errno; + } + if (tmp != MLX5_XMETA_MODE_MISS_INFO) + config->dv_xmeta_en = tmp; + else + config->dv_miss_info = 1; + } else if (strcmp(MLX5_LACP_BY_USER, key) == 0) { + config->lacp_by_user = !!tmp; + } else if (strcmp(MLX5_RECLAIM_MEM, key) == 0) { + if (tmp != MLX5_RCM_NONE && + tmp != MLX5_RCM_LIGHT && + tmp != MLX5_RCM_AGGR) { + DRV_LOG(ERR, "Unrecognize %s: \"%s\"", key, val); + rte_errno = EINVAL; + return -rte_errno; + } + config->reclaim_mode = tmp; + } else if (strcmp(MLX5_DECAP_EN, key) == 0) { + config->decap_en = !!tmp; + } else if (strcmp(MLX5_ALLOW_DUPLICATE_PATTERN, key) == 0) { + config->allow_duplicate_pattern = !!tmp; + } + return 0; +} + +/** + * Parse user device parameters and adjust them according to device + * capabilities. + * + * @param sh + * Pointer to shared device context. + * @param mkvlist + * Pointer to mlx5 kvargs control, can be NULL if there is no devargs. + * @param config + * Pointer to shared device configuration structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, + struct mlx5_kvargs_ctrl *mkvlist, + struct mlx5_sh_config *config) +{ + const char **params = (const char *[]){ + MLX5_TX_PP, + MLX5_TX_SKEW, + MLX5_L3_VXLAN_EN, + MLX5_VF_NL_EN, + MLX5_DV_ESW_EN, + MLX5_DV_FLOW_EN, + MLX5_DV_XMETA_EN, + MLX5_LACP_BY_USER, + MLX5_RECLAIM_MEM, + MLX5_DECAP_EN, + MLX5_ALLOW_DUPLICATE_PATTERN, + NULL, + }; + int ret = 0; + + /* Default configuration. */ + memset(config, 0, sizeof(*config)); + config->vf_nl_en = 1; + config->dv_esw_en = 1; + config->dv_flow_en = 1; + config->decap_en = 1; + config->allow_duplicate_pattern = 1; + if (mkvlist != NULL) { + /* Process parameters. */ + ret = mlx5_kvargs_process(mkvlist, params, + mlx5_dev_args_check_handler, config); + if (ret) { + DRV_LOG(ERR, "Failed to process device arguments: %s", + strerror(rte_errno)); + return -rte_errno; + } + } + /* Adjust parameters according to device capabilities. */ + if (config->dv_flow_en && !sh->dev_cap.dv_flow_en) { + DRV_LOG(WARNING, "DV flow is not supported."); + config->dv_flow_en = 0; + } + if (config->dv_esw_en && !sh->dev_cap.dv_esw_en) { + DRV_LOG(DEBUG, "E-Switch DV flow is not supported."); + config->dv_esw_en = 0; + } + if (config->dv_miss_info && config->dv_esw_en) + config->dv_xmeta_en = MLX5_XMETA_MODE_META16; + if (!config->dv_esw_en && + config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) { + DRV_LOG(WARNING, + "Metadata mode %u is not supported (no E-Switch).", + config->dv_xmeta_en); + config->dv_xmeta_en = MLX5_XMETA_MODE_LEGACY; + } + if (config->tx_pp && !sh->dev_cap.txpp_en) { + DRV_LOG(ERR, "Packet pacing is not supported."); + rte_errno = ENODEV; + return -rte_errno; + } + if (!config->tx_pp && config->tx_skew) { + DRV_LOG(WARNING, + "\"tx_skew\" doesn't affect without \"tx_pp\"."); + } + /* + * If HW has bug working with tunnel packet decapsulation and scatter + * FCS, and decapsulation is needed, clear the hw_fcs_strip bit. + * Then RTE_ETH_RX_OFFLOAD_KEEP_CRC bit will not be set anymore. + */ + if (sh->dev_cap.scatter_fcs_w_decap_disable && sh->config.decap_en) + config->hw_fcs_strip = 0; + else + config->hw_fcs_strip = sh->dev_cap.hw_fcs_strip; + DRV_LOG(DEBUG, "FCS stripping configuration is %ssupported", + (config->hw_fcs_strip ? "" : "not ")); + DRV_LOG(DEBUG, "\"tx_pp\" is %d.", config->tx_pp); + DRV_LOG(DEBUG, "\"tx_skew\" is %d.", config->tx_skew); + DRV_LOG(DEBUG, "\"reclaim_mode\" is %u.", config->reclaim_mode); + DRV_LOG(DEBUG, "\"dv_esw_en\" is %u.", config->dv_esw_en); + DRV_LOG(DEBUG, "\"dv_flow_en\" is %u.", config->dv_flow_en); + DRV_LOG(DEBUG, "\"dv_xmeta_en\" is %u.", config->dv_xmeta_en); + DRV_LOG(DEBUG, "\"dv_miss_info\" is %u.", config->dv_miss_info); + DRV_LOG(DEBUG, "\"l3_vxlan_en\" is %u.", config->l3_vxlan_en); + DRV_LOG(DEBUG, "\"vf_nl_en\" is %u.", config->vf_nl_en); + DRV_LOG(DEBUG, "\"lacp_by_user\" is %u.", config->lacp_by_user); + DRV_LOG(DEBUG, "\"decap_en\" is %u.", config->decap_en); + DRV_LOG(DEBUG, "\"allow_duplicate_pattern\" is %u.", + config->allow_duplicate_pattern); + return 0; +} + /** * Configure realtime timestamp format. * * @param sh * Pointer to mlx5_dev_ctx_shared object. - * @param config - * Device configuration parameters. * @param hca_attr * Pointer to DevX HCA capabilities structure. */ void mlx5_rt_timestamp_config(struct mlx5_dev_ctx_shared *sh, - struct mlx5_dev_config *config, struct mlx5_hca_attr *hca_attr) { uint32_t dw_cnt = MLX5_ST_SZ_DW(register_mtutc); @@ -1198,11 +1369,11 @@ mlx5_rt_timestamp_config(struct mlx5_dev_ctx_shared *sh, /* MTUTC register is read successfully. */ ts_mode = MLX5_GET(register_mtutc, reg, time_stamp_mode); if (ts_mode == MLX5_MTUTC_TIMESTAMP_MODE_REAL_TIME) - config->rt_timestamp = 1; + sh->dev_cap.rt_timestamp = 1; } else { /* Kernel does not support register reading. */ if (hca_attr->dev_freq_khz == (NS_PER_S / MS_PER_S)) - config->rt_timestamp = 1; + sh->dev_cap.rt_timestamp = 1; } } @@ -1219,8 +1390,8 @@ mlx5_rt_timestamp_config(struct mlx5_dev_ctx_shared *sh, * * @param[in] spawn * Pointer to the device attributes (name, port, etc). - * @param[in] config - * Pointer to device configuration structure. + * @param mkvlist + * Pointer to mlx5 kvargs control, can be NULL if there is no devargs. * * @return * Pointer to mlx5_dev_ctx_shared object on success, @@ -1228,7 +1399,7 @@ mlx5_rt_timestamp_config(struct mlx5_dev_ctx_shared *sh, */ struct mlx5_dev_ctx_shared * mlx5_alloc_shared_dev_ctx(const struct mlx5_dev_spawn_data *spawn, - const struct mlx5_dev_config *config) + struct mlx5_kvargs_ctrl *mkvlist) { struct mlx5_dev_ctx_shared *sh; int err = 0; @@ -1262,14 +1433,19 @@ mlx5_alloc_shared_dev_ctx(const struct mlx5_dev_spawn_data *spawn, sh->esw_mode = !!(spawn->info.master || spawn->info.representor); if (spawn->bond_info) sh->bond = *spawn->bond_info; - err = mlx5_os_get_dev_attr(sh->cdev, &sh->device_attr); + err = mlx5_os_capabilities_prepare(sh); if (err) { - DRV_LOG(DEBUG, "mlx5_os_get_dev_attr() failed"); + DRV_LOG(ERR, "Fail to configure device capabilities."); + goto error; + } + err = mlx5_shared_dev_ctx_args_config(sh, mkvlist, &sh->config); + if (err) { + DRV_LOG(ERR, "Failed to process device configure: %s", + strerror(rte_errno)); goto error; } sh->refcnt = 1; sh->max_port = spawn->max_port; - sh->reclaim_mode = config->reclaim_mode; strncpy(sh->ibdev_name, mlx5_os_get_ctx_device_name(sh->cdev->ctx), sizeof(sh->ibdev_name) - 1); strncpy(sh->ibdev_path, mlx5_os_get_ctx_device_path(sh->cdev->ctx), @@ -1313,7 +1489,7 @@ mlx5_alloc_shared_dev_ctx(const struct mlx5_dev_spawn_data *spawn, } mlx5_flow_aging_init(sh); mlx5_flow_counters_mng_init(sh); - mlx5_flow_ipool_create(sh, config); + mlx5_flow_ipool_create(sh); /* Add context to the global device list. */ LIST_INSERT_HEAD(&mlx5_dev_ctx_list, sh, next); rte_spinlock_init(&sh->geneve_tlv_opt_sl); @@ -1676,7 +1852,7 @@ mlx5_dev_close(struct rte_eth_dev *dev) mlx5_free(priv->rss_conf.rss_key); if (priv->reta_idx != NULL) mlx5_free(priv->reta_idx); - if (priv->config.vf) + if (priv->sh->dev_cap.vf) mlx5_os_mac_addr_flush(dev); if (priv->nl_socket_route >= 0) close(priv->nl_socket_route); @@ -1919,17 +2095,13 @@ const struct eth_dev_ops mlx5_dev_ops_isolate = { * 0 on success, a negative errno value otherwise and rte_errno is set. */ static int -mlx5_args_check(const char *key, const char *val, void *opaque) +mlx5_port_args_check_handler(const char *key, const char *val, void *opaque) { - struct mlx5_dev_config *config = opaque; - unsigned long mod; + struct mlx5_port_config *config = opaque; signed long tmp; /* No-op, port representors are processed in mlx5_dev_spawn(). */ - if (!strcmp(MLX5_DRIVER_KEY, key) || !strcmp(MLX5_REPRESENTOR, key) || - !strcmp(MLX5_SYS_MEM_EN, key) || !strcmp(MLX5_TX_DB_NC, key) || - !strcmp(MLX5_MR_MEMPOOL_REG_EN, key) || - !strcmp(MLX5_MR_EXT_MEMSEG_EN, key)) + if (!strcmp(MLX5_REPRESENTOR, key)) return 0; errno = 0; tmp = strtol(val, NULL, 0); @@ -1938,13 +2110,12 @@ mlx5_args_check(const char *key, const char *val, void *opaque) DRV_LOG(WARNING, "%s: \"%s\" is not a valid integer", key, val); return -rte_errno; } - if (tmp < 0 && strcmp(MLX5_TX_PP, key) && strcmp(MLX5_TX_SKEW, key)) { + if (tmp < 0) { /* Negative values are acceptable for some keys only. */ rte_errno = EINVAL; DRV_LOG(WARNING, "%s: invalid negative value \"%s\"", key, val); return -rte_errno; } - mod = tmp >= 0 ? tmp : -tmp; if (strcmp(MLX5_RXQ_CQE_COMP_EN, key) == 0) { if (tmp > MLX5_CQE_RESP_FORMAT_L34H_STRIDX) { DRV_LOG(ERR, "invalid CQE compression " @@ -1990,106 +2161,393 @@ mlx5_args_check(const char *key, const char *val, void *opaque) config->txq_inline_mpw = tmp; } else if (strcmp(MLX5_TX_VEC_EN, key) == 0) { DRV_LOG(WARNING, "%s: deprecated parameter, ignored", key); - } else if (strcmp(MLX5_TX_PP, key) == 0) { - if (!mod) { - DRV_LOG(ERR, "Zero Tx packet pacing parameter"); - rte_errno = EINVAL; - return -rte_errno; - } - config->tx_pp = tmp; - } else if (strcmp(MLX5_TX_SKEW, key) == 0) { - config->tx_skew = tmp; } else if (strcmp(MLX5_RX_VEC_EN, key) == 0) { config->rx_vec_en = !!tmp; - } else if (strcmp(MLX5_L3_VXLAN_EN, key) == 0) { - config->l3_vxlan_en = !!tmp; - } else if (strcmp(MLX5_VF_NL_EN, key) == 0) { - config->vf_nl_en = !!tmp; - } else if (strcmp(MLX5_DV_ESW_EN, key) == 0) { - config->dv_esw_en = !!tmp; - } else if (strcmp(MLX5_DV_FLOW_EN, key) == 0) { - config->dv_flow_en = !!tmp; - } else if (strcmp(MLX5_DV_XMETA_EN, key) == 0) { - if (tmp != MLX5_XMETA_MODE_LEGACY && - tmp != MLX5_XMETA_MODE_META16 && - tmp != MLX5_XMETA_MODE_META32 && - tmp != MLX5_XMETA_MODE_MISS_INFO) { - DRV_LOG(ERR, "invalid extensive " - "metadata parameter"); - rte_errno = EINVAL; - return -rte_errno; - } - if (tmp != MLX5_XMETA_MODE_MISS_INFO) - config->dv_xmeta_en = tmp; - else - config->dv_miss_info = 1; - } else if (strcmp(MLX5_LACP_BY_USER, key) == 0) { - config->lacp_by_user = !!tmp; } else if (strcmp(MLX5_MAX_DUMP_FILES_NUM, key) == 0) { config->max_dump_files_num = tmp; } else if (strcmp(MLX5_LRO_TIMEOUT_USEC, key) == 0) { - config->lro.timeout = tmp; - } else if (strcmp(RTE_DEVARGS_KEY_CLASS, key) == 0) { - DRV_LOG(DEBUG, "class argument is %s.", val); + config->lro_timeout = tmp; } else if (strcmp(MLX5_HP_BUF_SIZE, key) == 0) { config->log_hp_size = tmp; - } else if (strcmp(MLX5_RECLAIM_MEM, key) == 0) { - if (tmp != MLX5_RCM_NONE && - tmp != MLX5_RCM_LIGHT && - tmp != MLX5_RCM_AGGR) { - DRV_LOG(ERR, "Unrecognized %s: \"%s\"", key, val); - rte_errno = EINVAL; - return -rte_errno; - } - config->reclaim_mode = tmp; - } else if (strcmp(MLX5_DECAP_EN, key) == 0) { - config->decap_en = !!tmp; - } else if (strcmp(MLX5_ALLOW_DUPLICATE_PATTERN, key) == 0) { - config->allow_duplicate_pattern = !!tmp; } else if (strcmp(MLX5_DELAY_DROP, key) == 0) { config->std_delay_drop = !!(tmp & MLX5_DELAY_DROP_STANDARD); config->hp_delay_drop = !!(tmp & MLX5_DELAY_DROP_HAIRPIN); - } else { - DRV_LOG(WARNING, - "%s: unknown parameter, maybe it's for another class.", - key); } return 0; } /** - * Parse device parameters. + * Parse user port parameters and adjust them according to device capabilities. * + * @param priv + * Pointer to shared device context. + * @param mkvlist + * Pointer to mlx5 kvargs control, can be NULL if there is no devargs. * @param config - * Pointer to device configuration structure. - * @param devargs - * Device arguments structure. + * Pointer to port configuration structure. * * @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ int -mlx5_args(struct mlx5_dev_config *config, struct rte_devargs *devargs) +mlx5_port_args_config(struct mlx5_priv *priv, struct mlx5_kvargs_ctrl *mkvlist, + struct mlx5_port_config *config) { - struct rte_kvargs *kvlist; + struct mlx5_hca_attr *hca_attr = &priv->sh->cdev->config.hca_attr; + struct mlx5_dev_cap *dev_cap = &priv->sh->dev_cap; + bool devx = priv->sh->cdev->config.devx; + const char **params = (const char *[]){ + MLX5_RXQ_CQE_COMP_EN, + MLX5_RXQ_PKT_PAD_EN, + MLX5_RX_MPRQ_EN, + MLX5_RX_MPRQ_LOG_STRIDE_NUM, + MLX5_RX_MPRQ_LOG_STRIDE_SIZE, + MLX5_RX_MPRQ_MAX_MEMCPY_LEN, + MLX5_RXQS_MIN_MPRQ, + MLX5_TXQ_INLINE, + MLX5_TXQ_INLINE_MIN, + MLX5_TXQ_INLINE_MAX, + MLX5_TXQ_INLINE_MPW, + MLX5_TXQS_MIN_INLINE, + MLX5_TXQS_MAX_VEC, + MLX5_TXQ_MPW_EN, + MLX5_TXQ_MPW_HDR_DSEG_EN, + MLX5_TXQ_MAX_INLINE_LEN, + MLX5_TX_VEC_EN, + MLX5_RX_VEC_EN, + MLX5_REPRESENTOR, + MLX5_MAX_DUMP_FILES_NUM, + MLX5_LRO_TIMEOUT_USEC, + MLX5_HP_BUF_SIZE, + MLX5_DELAY_DROP, + NULL, + }; int ret = 0; - if (devargs == NULL) + /* Default configuration. */ + memset(config, 0, sizeof(*config)); + config->mps = MLX5_ARG_UNSET; + config->cqe_comp = 1; + config->rx_vec_en = 1; + config->txq_inline_max = MLX5_ARG_UNSET; + config->txq_inline_min = MLX5_ARG_UNSET; + config->txq_inline_mpw = MLX5_ARG_UNSET; + config->txqs_inline = MLX5_ARG_UNSET; + config->mprq.max_memcpy_len = MLX5_MPRQ_MEMCPY_DEFAULT_LEN; + config->mprq.min_rxqs_num = MLX5_MPRQ_MIN_RXQS; + config->mprq.log_stride_num = MLX5_MPRQ_DEFAULT_LOG_STRIDE_NUM; + config->log_hp_size = MLX5_ARG_UNSET; + config->std_delay_drop = 0; + config->hp_delay_drop = 0; + if (mkvlist != NULL) { + /* Process parameters. */ + ret = mlx5_kvargs_process(mkvlist, params, + mlx5_port_args_check_handler, config); + if (ret) { + DRV_LOG(ERR, "Failed to process port arguments: %s", + strerror(rte_errno)); + return -rte_errno; + } + } + /* Adjust parameters according to device capabilities. */ + if (config->hw_padding && !dev_cap->hw_padding) { + DRV_LOG(DEBUG, "Rx end alignment padding isn't supported."); + config->hw_padding = 0; + } else if (config->hw_padding) { + DRV_LOG(DEBUG, "Rx end alignment padding is enabled."); + } + /* + * MPW is disabled by default, while the Enhanced MPW is enabled + * by default. + */ + if (config->mps == MLX5_ARG_UNSET) + config->mps = (dev_cap->mps == MLX5_MPW_ENHANCED) ? + MLX5_MPW_ENHANCED : MLX5_MPW_DISABLED; + else + config->mps = config->mps ? dev_cap->mps : MLX5_MPW_DISABLED; + DRV_LOG(INFO, "%sMPS is %s", + config->mps == MLX5_MPW_ENHANCED ? "enhanced " : + config->mps == MLX5_MPW ? "legacy " : "", + config->mps != MLX5_MPW_DISABLED ? "enabled" : "disabled"); + /* LRO is supported only when DV flow enabled. */ + if (dev_cap->lro_supported && !priv->sh->config.dv_flow_en) + dev_cap->lro_supported = 0; + if (dev_cap->lro_supported) { + /* + * If LRO timeout is not configured by application, + * use the minimal supported value. + */ + if (!config->lro_timeout) + config->lro_timeout = + hca_attr->lro_timer_supported_periods[0]; + DRV_LOG(DEBUG, "LRO session timeout set to %d usec.", + config->lro_timeout); + } + if (config->cqe_comp && !dev_cap->cqe_comp) { + DRV_LOG(WARNING, "Rx CQE 128B compression is not supported."); + config->cqe_comp = 0; + } + if (config->cqe_comp_fmt == MLX5_CQE_RESP_FORMAT_FTAG_STRIDX && + (!devx || !hca_attr->mini_cqe_resp_flow_tag)) { + DRV_LOG(WARNING, + "Flow Tag CQE compression format isn't supported."); + config->cqe_comp = 0; + } + if (config->cqe_comp_fmt == MLX5_CQE_RESP_FORMAT_L34H_STRIDX && + (!devx || !hca_attr->mini_cqe_resp_l3_l4_tag)) { + DRV_LOG(WARNING, + "L3/L4 Header CQE compression format isn't supported."); + config->cqe_comp = 0; + } + DRV_LOG(DEBUG, "Rx CQE compression is %ssupported.", + config->cqe_comp ? "" : "not "); + if ((config->std_delay_drop || config->hp_delay_drop) && + !dev_cap->rq_delay_drop_en) { + config->std_delay_drop = 0; + config->hp_delay_drop = 0; + DRV_LOG(WARNING, "dev_port-%u: Rxq delay drop isn't supported.", + priv->dev_port); + } + if (config->mprq.enabled && !priv->sh->dev_cap.mprq.enabled) { + DRV_LOG(WARNING, "Multi-Packet RQ isn't supported."); + config->mprq.enabled = 0; + } + if (config->max_dump_files_num == 0) + config->max_dump_files_num = 128; + /* Detect minimal data bytes to inline. */ + mlx5_set_min_inline(priv); + DRV_LOG(DEBUG, "VLAN insertion in WQE is %ssupported.", + config->hw_vlan_insert ? "" : "not "); + DRV_LOG(DEBUG, "\"rxq_pkt_pad_en\" is %u.", config->hw_padding); + DRV_LOG(DEBUG, "\"rxq_cqe_comp_en\" is %u.", config->cqe_comp); + DRV_LOG(DEBUG, "\"cqe_comp_fmt\" is %u.", config->cqe_comp_fmt); + DRV_LOG(DEBUG, "\"rx_vec_en\" is %u.", config->rx_vec_en); + DRV_LOG(DEBUG, "Standard \"delay_drop\" is %u.", + config->std_delay_drop); + DRV_LOG(DEBUG, "Hairpin \"delay_drop\" is %u.", config->hp_delay_drop); + DRV_LOG(DEBUG, "\"max_dump_files_num\" is %u.", + config->max_dump_files_num); + DRV_LOG(DEBUG, "\"log_hp_size\" is %u.", config->log_hp_size); + DRV_LOG(DEBUG, "\"mprq_en\" is %u.", config->mprq.enabled); + DRV_LOG(DEBUG, "\"mprq_log_stride_num\" is %u.", + config->mprq.log_stride_num); + DRV_LOG(DEBUG, "\"mprq_log_stride_size\" is %u.", + config->mprq.log_stride_size); + DRV_LOG(DEBUG, "\"mprq_max_memcpy_len\" is %u.", + config->mprq.max_memcpy_len); + DRV_LOG(DEBUG, "\"rxqs_min_mprq\" is %u.", config->mprq.min_rxqs_num); + DRV_LOG(DEBUG, "\"lro_timeout_usec\" is %u.", config->lro_timeout); + DRV_LOG(DEBUG, "\"txq_mpw_en\" is %d.", config->mps); + DRV_LOG(DEBUG, "\"txqs_min_inline\" is %d.", config->txqs_inline); + DRV_LOG(DEBUG, "\"txq_inline_min\" is %d.", config->txq_inline_min); + DRV_LOG(DEBUG, "\"txq_inline_max\" is %d.", config->txq_inline_max); + DRV_LOG(DEBUG, "\"txq_inline_mpw\" is %d.", config->txq_inline_mpw); + return 0; +} + +/** + * Print the key for device argument. + * + * It is "dummy" handler whose whole purpose is to enable using + * mlx5_kvargs_process() function which set devargs as used. + * + * @param key + * Key argument. + * @param val + * Value associated with key, unused. + * @param opaque + * Unused, can be NULL. + * + * @return + * 0 on success, function cannot fail. + */ +static int +mlx5_dummy_handler(const char *key, const char *val, void *opaque) +{ + DRV_LOG(DEBUG, "\tKey: \"%s\" is set as used.", key); + RTE_SET_USED(opaque); + RTE_SET_USED(val); + return 0; +} + +/** + * Set requested devargs as used when device is already spawned. + * + * It is necessary since it is valid to ask probe again for existing device, + * if its devargs don't assign as used, mlx5_kvargs_validate() will fail. + * + * @param name + * Name of the existing device. + * @param port_id + * Port identifier of the device. + * @param mkvlist + * Pointer to mlx5 kvargs control to sign as used. + */ +void +mlx5_port_args_set_used(const char *name, uint16_t port_id, + struct mlx5_kvargs_ctrl *mkvlist) +{ + const char **params = (const char *[]){ + MLX5_RXQ_CQE_COMP_EN, + MLX5_RXQ_PKT_PAD_EN, + MLX5_RX_MPRQ_EN, + MLX5_RX_MPRQ_LOG_STRIDE_NUM, + MLX5_RX_MPRQ_LOG_STRIDE_SIZE, + MLX5_RX_MPRQ_MAX_MEMCPY_LEN, + MLX5_RXQS_MIN_MPRQ, + MLX5_TXQ_INLINE, + MLX5_TXQ_INLINE_MIN, + MLX5_TXQ_INLINE_MAX, + MLX5_TXQ_INLINE_MPW, + MLX5_TXQS_MIN_INLINE, + MLX5_TXQS_MAX_VEC, + MLX5_TXQ_MPW_EN, + MLX5_TXQ_MPW_HDR_DSEG_EN, + MLX5_TXQ_MAX_INLINE_LEN, + MLX5_TX_VEC_EN, + MLX5_RX_VEC_EN, + MLX5_REPRESENTOR, + MLX5_MAX_DUMP_FILES_NUM, + MLX5_LRO_TIMEOUT_USEC, + MLX5_HP_BUF_SIZE, + MLX5_DELAY_DROP, + NULL, + }; + + /* Secondary process should not handle devargs. */ + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return; + MLX5_ASSERT(mkvlist != NULL); + DRV_LOG(DEBUG, "Ethernet device \"%s\" for port %u " + "already exists, set devargs as used:", name, port_id); + /* This function cannot fail with this handler. */ + mlx5_kvargs_process(mkvlist, params, mlx5_dummy_handler, NULL); +} + +/** + * Check sibling device configurations when probing again. + * + * Sibling devices sharing infiniband device context should have compatible + * configurations. This regards representors and bonding device. + * + * @param cdev + * Pointer to mlx5 device structure. + * @param mkvlist + * Pointer to mlx5 kvargs control, can be NULL if there is no devargs. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_probe_again_args_validate(struct mlx5_common_device *cdev, + struct mlx5_kvargs_ctrl *mkvlist) +{ + struct mlx5_dev_ctx_shared *sh = NULL; + struct mlx5_sh_config *config; + int ret; + + /* Secondary process should not handle devargs. */ + if (rte_eal_process_type() != RTE_PROC_PRIMARY) return 0; - /* Following UGLY cast is done to pass checkpatch. */ - kvlist = rte_kvargs_parse(devargs->args, NULL); - if (kvlist == NULL) { - rte_errno = EINVAL; + pthread_mutex_lock(&mlx5_dev_ctx_list_mutex); + /* Search for IB context by common device pointer. */ + LIST_FOREACH(sh, &mlx5_dev_ctx_list, next) + if (sh->cdev == cdev) + break; + pthread_mutex_unlock(&mlx5_dev_ctx_list_mutex); + /* There is sh for this device -> it isn't probe again. */ + if (sh == NULL) + return 0; + config = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE, + sizeof(struct mlx5_sh_config), + RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); + if (config == NULL) { + rte_errno = -ENOMEM; return -rte_errno; } - /* Process parameters. */ - ret = rte_kvargs_process(kvlist, NULL, mlx5_args_check, config); + /* + * Creates a temporary IB context configure structure according to new + * devargs attached in probing again. + */ + ret = mlx5_shared_dev_ctx_args_config(sh, mkvlist, config); if (ret) { - rte_errno = EINVAL; - ret = -rte_errno; + DRV_LOG(ERR, "Failed to process device configure: %s", + strerror(rte_errno)); + mlx5_free(config); + return ret; + } + /* + * Checks the match between the temporary structure and the existing + * IB context structure. + */ + if (sh->config.dv_flow_en ^ config->dv_flow_en) { + DRV_LOG(ERR, "\"dv_flow_en\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } + if ((sh->config.dv_xmeta_en ^ config->dv_xmeta_en) || + (sh->config.dv_miss_info ^ config->dv_miss_info)) { + DRV_LOG(ERR, "\"dv_xmeta_en\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } + if (sh->config.dv_esw_en ^ config->dv_esw_en) { + DRV_LOG(ERR, "\"dv_esw_en\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } + if (sh->config.reclaim_mode ^ config->reclaim_mode) { + DRV_LOG(ERR, "\"reclaim_mode\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } + if (sh->config.allow_duplicate_pattern ^ + config->allow_duplicate_pattern) { + DRV_LOG(ERR, "\"allow_duplicate_pattern\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } + if (sh->config.l3_vxlan_en ^ config->l3_vxlan_en) { + DRV_LOG(ERR, "\"l3_vxlan_en\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } + if (sh->config.decap_en ^ config->decap_en) { + DRV_LOG(ERR, "\"decap_en\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } + if (sh->config.lacp_by_user ^ config->lacp_by_user) { + DRV_LOG(ERR, "\"lacp_by_user\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } + if (sh->config.tx_pp ^ config->tx_pp) { + DRV_LOG(ERR, "\"tx_pp\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; } - rte_kvargs_free(kvlist); - return ret; + if (sh->config.tx_skew ^ config->tx_skew) { + DRV_LOG(ERR, "\"tx_skew\" " + "configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } + mlx5_free(config); + return 0; +error: + mlx5_free(config); + rte_errno = EINVAL; + return -rte_errno; } /** @@ -2103,21 +2561,19 @@ mlx5_args(struct mlx5_dev_config *config, struct rte_devargs *devargs) * - otherwise L2 mode (18 bytes) is assumed for ConnectX-4/4 Lx * and none (0 bytes) for other NICs * - * @param spawn - * Verbs device parameters (name, port, switch_info) to spawn. - * @param config - * Device configuration parameters. + * @param priv + * Pointer to the private device data structure. */ void -mlx5_set_min_inline(struct mlx5_dev_spawn_data *spawn, - struct mlx5_dev_config *config) +mlx5_set_min_inline(struct mlx5_priv *priv) { - struct mlx5_hca_attr *hca_attr = &spawn->cdev->config.hca_attr; + struct mlx5_hca_attr *hca_attr = &priv->sh->cdev->config.hca_attr; + struct mlx5_port_config *config = &priv->config; if (config->txq_inline_min != MLX5_ARG_UNSET) { /* Application defines size of inlined data explicitly. */ - if (spawn->pci_dev != NULL) { - switch (spawn->pci_dev->id.device_id) { + if (priv->pci_dev != NULL) { + switch (priv->pci_dev->id.device_id) { case PCI_DEVICE_ID_MELLANOX_CONNECTX4: case PCI_DEVICE_ID_MELLANOX_CONNECTX4VF: if (config->txq_inline_min < @@ -2183,7 +2639,7 @@ mlx5_set_min_inline(struct mlx5_dev_spawn_data *spawn, } } } - if (spawn->pci_dev == NULL) { + if (priv->pci_dev == NULL) { config->txq_inline_min = MLX5_INLINE_HSIZE_NONE; goto exit; } @@ -2192,7 +2648,7 @@ mlx5_set_min_inline(struct mlx5_dev_spawn_data *spawn, * inline data size with DevX. Try PCI ID * to determine old NICs. */ - switch (spawn->pci_dev->id.device_id) { + switch (priv->pci_dev->id.device_id) { case PCI_DEVICE_ID_MELLANOX_CONNECTX4: case PCI_DEVICE_ID_MELLANOX_CONNECTX4VF: case PCI_DEVICE_ID_MELLANOX_CONNECTX4LX: @@ -2234,7 +2690,7 @@ mlx5_set_metadata_mask(struct rte_eth_dev *dev) uint32_t meta, mark, reg_c0; reg_c0 = ~priv->vport_meta_mask; - switch (priv->config.dv_xmeta_en) { + switch (sh->config.dv_xmeta_en) { case MLX5_XMETA_MODE_LEGACY: meta = UINT32_MAX; mark = MLX5_FLOW_MARK_MASK; @@ -2268,7 +2724,7 @@ mlx5_set_metadata_mask(struct rte_eth_dev *dev) sh->dv_meta_mask, reg_c0); else sh->dv_regc0_mask = reg_c0; - DRV_LOG(DEBUG, "metadata mode %u", priv->config.dv_xmeta_en); + DRV_LOG(DEBUG, "metadata mode %u", sh->config.dv_xmeta_en); DRV_LOG(DEBUG, "metadata MARK mask %08X", sh->dv_mark_mask); DRV_LOG(DEBUG, "metadata META mask %08X", sh->dv_meta_mask); DRV_LOG(DEBUG, "metadata reg_c0 mask %08X", sh->dv_regc0_mask); @@ -2294,61 +2750,6 @@ rte_pmd_mlx5_get_dyn_flag_names(char *names[], unsigned int n) return RTE_DIM(dynf_names); } -/** - * Check sibling device configurations. - * - * Sibling devices sharing the Infiniband device context should have compatible - * configurations. This regards representors and bonding device. - * - * @param sh - * Shared device context. - * @param config - * Configuration of the device is going to be created. - * @param dpdk_dev - * Backing DPDK device. - * - * @return - * 0 on success, EINVAL otherwise - */ -int -mlx5_dev_check_sibling_config(struct mlx5_dev_ctx_shared *sh, - struct mlx5_dev_config *config, - struct rte_device *dpdk_dev) -{ - struct mlx5_dev_config *sh_conf = NULL; - uint16_t port_id; - - MLX5_ASSERT(sh); - /* Nothing to compare for the single/first device. */ - if (sh->refcnt == 1) - return 0; - /* Find the device with shared context. */ - MLX5_ETH_FOREACH_DEV(port_id, dpdk_dev) { - struct mlx5_priv *opriv = - rte_eth_devices[port_id].data->dev_private; - - if (opriv && opriv->sh == sh) { - sh_conf = &opriv->config; - break; - } - } - if (!sh_conf) - return 0; - if (sh_conf->dv_flow_en ^ config->dv_flow_en) { - DRV_LOG(ERR, "\"dv_flow_en\" configuration mismatch" - " for shared %s context", sh->ibdev_name); - rte_errno = EINVAL; - return rte_errno; - } - if (sh_conf->dv_xmeta_en ^ config->dv_xmeta_en) { - DRV_LOG(ERR, "\"dv_xmeta_en\" configuration mismatch" - " for shared %s context", sh->ibdev_name); - rte_errno = EINVAL; - return rte_errno; - } - return 0; -} - /** * Look for the ethernet device belonging to mlx5 driver. *