X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmlx5%2Fmlx5_ethdev.c;h=2278b24c012253dca87ec930aa82ad4dc5d8287a;hb=5f5ccaa05c9a4423fb2c7803023ed13468034549;hp=9629cfb333b3ab8cec612817efc4a1182e940e55;hpb=17ed314c6c0b269c92941e41aee3622f5726e1fa;p=dpdk.git diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c index 9629cfb333..2278b24c01 100644 --- a/drivers/net/mlx5/mlx5_ethdev.c +++ b/drivers/net/mlx5/mlx5_ethdev.c @@ -542,7 +542,7 @@ mlx5_set_txlimit_params(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) * @param[out] info * Info structure output buffer. */ -void +int mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) { struct mlx5_priv *priv = dev->data->dev_private; @@ -580,16 +580,34 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) info->switch_info.domain_id = priv->domain_id; info->switch_info.port_id = priv->representor_id; if (priv->representor) { - unsigned int i = mlx5_dev_to_port_id(dev->device, NULL, 0); - uint16_t port_id[i]; + uint16_t port_id; - i = RTE_MIN(mlx5_dev_to_port_id(dev->device, port_id, i), i); - while (i--) { + if (priv->pf_bond >= 0) { + /* + * Switch port ID is opaque value with driver defined + * format. Push the PF index in bonding configurations + * in upper four bits of port ID. If we get too many + * representors (more than 4K) or PFs (more than 15) + * this approach must be reconsidered. + */ + if ((info->switch_info.port_id >> + MLX5_PORT_ID_BONDING_PF_SHIFT) || + priv->pf_bond > MLX5_PORT_ID_BONDING_PF_MASK) { + DRV_LOG(ERR, "can't update switch port ID" + " for bonding device"); + assert(false); + return -ENODEV; + } + info->switch_info.port_id |= + priv->pf_bond << MLX5_PORT_ID_BONDING_PF_SHIFT; + } + MLX5_ETH_FOREACH_DEV(port_id, priv->pci_dev) { struct mlx5_priv *opriv = - rte_eth_devices[port_id[i]].data->dev_private; + rte_eth_devices[port_id].data->dev_private; if (!opriv || opriv->representor || + opriv->sh != priv->sh || opriv->domain_id != priv->domain_id) continue; /* @@ -600,6 +618,7 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) break; } } + return 0; } /** @@ -715,11 +734,13 @@ mlx5_find_master_dev(struct rte_eth_dev *dev) priv = dev->data->dev_private; domain_id = priv->domain_id; assert(priv->representor); - RTE_ETH_FOREACH_DEV_OF(port_id, dev->device) { - priv = rte_eth_devices[port_id].data->dev_private; - if (priv && - priv->master && - priv->domain_id == domain_id) + MLX5_ETH_FOREACH_DEV(port_id, priv->pci_dev) { + struct mlx5_priv *opriv = + rte_eth_devices[port_id].data->dev_private; + if (opriv && + opriv->master && + opriv->domain_id == domain_id && + opriv->sh == priv->sh) return &rte_eth_devices[port_id]; } return NULL; @@ -908,7 +929,8 @@ mlx5_link_update_unlocked_gs(struct rte_eth_dev *dev, dev->data->port_id, strerror(rte_errno)); return ret; } - dev_link.link_speed = ecmd->speed; + dev_link.link_speed = (ecmd->speed == UINT32_MAX) ? ETH_SPEED_NUM_NONE : + ecmd->speed; sc = ecmd->link_mode_masks[0] | ((uint64_t)ecmd->link_mode_masks[1] << 32); priv->link_speed_capa = 0; @@ -977,6 +999,7 @@ mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete) int ret; struct rte_eth_link dev_link; time_t start_time = time(NULL); + int retry = MLX5_GET_LINK_STATUS_RETRY_COUNT; do { ret = mlx5_link_update_unlocked_gs(dev, &dev_link); @@ -985,7 +1008,7 @@ mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete) if (ret == 0) break; /* Handle wait to complete situation. */ - if (wait_to_complete && ret == -EAGAIN) { + if ((wait_to_complete || retry) && ret == -EAGAIN) { if (abs((int)difftime(time(NULL), start_time)) < MLX5_LINK_STATUS_TIMEOUT) { usleep(0); @@ -997,7 +1020,7 @@ mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete) } else if (ret < 0) { return ret; } - } while (wait_to_complete); + } while (wait_to_complete || retry-- > 0); ret = !!memcmp(&dev->data->dev_link, &dev_link, sizeof(struct rte_eth_link)); dev->data->dev_link = dev_link; @@ -1128,10 +1151,10 @@ mlx5_dev_set_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) } /** - * Get PCI information from struct ibv_device. + * Get PCI information by sysfs device path. * - * @param device - * Pointer to Ethernet device structure. + * @param dev_path + * Pointer to device sysfs folder name. * @param[out] pci_addr * PCI bus address output buffer. * @@ -1139,12 +1162,12 @@ mlx5_dev_set_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) * 0 on success, a negative errno value otherwise and rte_errno is set. */ int -mlx5_ibv_device_to_pci_addr(const struct ibv_device *device, - struct rte_pci_addr *pci_addr) +mlx5_dev_to_pci_addr(const char *dev_path, + struct rte_pci_addr *pci_addr) { FILE *file; char line[32]; - MKSTR(path, "%s/device/uevent", device->ibdev_path); + MKSTR(path, "%s/device/uevent", dev_path); file = fopen(path, "rb"); if (file == NULL) { @@ -1425,6 +1448,37 @@ mlx5_dev_shared_handler_uninstall(struct rte_eth_dev *dev) mlx5_dev_interrupt_handler, sh); sh->intr_handle.fd = 0; sh->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN; +exit: + pthread_mutex_unlock(&sh->intr_mutex); +} + +/** + * Uninstall devx shared asynchronous device events handler. + * This function is implemeted to support event sharing + * between multiple ports of single IB device. + * + * @param dev + * Pointer to Ethernet device. + */ +static void +mlx5_dev_shared_handler_devx_uninstall(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_ibv_shared *sh = priv->sh; + + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return; + pthread_mutex_lock(&sh->intr_mutex); + assert(priv->ibv_port); + assert(priv->ibv_port <= sh->max_port); + assert(dev->data->port_id < RTE_MAX_ETHPORTS); + if (sh->port[priv->ibv_port - 1].devx_ih_port_id >= RTE_MAX_ETHPORTS) + goto exit; + assert(sh->port[priv->ibv_port - 1].devx_ih_port_id == + (uint32_t)dev->data->port_id); + sh->port[priv->ibv_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS; + if (!sh->devx_intr_cnt || --sh->devx_intr_cnt) + goto exit; if (sh->intr_handle_devx.fd) { rte_intr_callback_unregister(&sh->intr_handle_devx, mlx5_dev_interrupt_handler_devx, @@ -1467,8 +1521,9 @@ mlx5_dev_shared_handler_install(struct rte_eth_dev *dev) assert(sh->intr_cnt); goto exit; } - sh->port[priv->ibv_port - 1].ih_port_id = (uint32_t)dev->data->port_id; if (sh->intr_cnt) { + sh->port[priv->ibv_port - 1].ih_port_id = + (uint32_t)dev->data->port_id; sh->intr_cnt++; goto exit; } @@ -1477,52 +1532,81 @@ mlx5_dev_shared_handler_install(struct rte_eth_dev *dev) flags = fcntl(sh->ctx->async_fd, F_GETFL); ret = fcntl(sh->ctx->async_fd, F_SETFL, flags | O_NONBLOCK); if (ret) { - DRV_LOG(INFO, "failed to change file descriptor" - " async event queue"); - goto error; + DRV_LOG(INFO, "failed to change file descriptor async event" + " queue"); + /* Indicate there will be no interrupts. */ + dev->data->dev_conf.intr_conf.lsc = 0; + dev->data->dev_conf.intr_conf.rmv = 0; + } else { + sh->intr_handle.fd = sh->ctx->async_fd; + sh->intr_handle.type = RTE_INTR_HANDLE_EXT; + rte_intr_callback_register(&sh->intr_handle, + mlx5_dev_interrupt_handler, sh); + sh->intr_cnt++; + sh->port[priv->ibv_port - 1].ih_port_id = + (uint32_t)dev->data->port_id; + } +exit: + pthread_mutex_unlock(&sh->intr_mutex); +} + +/** + * Install devx shared asyncronous device events handler. + * This function is implemeted to support event sharing + * between multiple ports of single IB device. + * + * @param dev + * Pointer to Ethernet device. + */ +static void +mlx5_dev_shared_handler_devx_install(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_ibv_shared *sh = priv->sh; + + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return; + pthread_mutex_lock(&sh->intr_mutex); + assert(priv->ibv_port); + assert(priv->ibv_port <= sh->max_port); + assert(dev->data->port_id < RTE_MAX_ETHPORTS); + if (sh->port[priv->ibv_port - 1].devx_ih_port_id < RTE_MAX_ETHPORTS) { + /* The handler is already installed for this port. */ + assert(sh->devx_intr_cnt); + goto exit; + } + if (sh->devx_intr_cnt) { + sh->devx_intr_cnt++; + sh->port[priv->ibv_port - 1].devx_ih_port_id = + (uint32_t)dev->data->port_id; + goto exit; } - sh->intr_handle.fd = sh->ctx->async_fd; - sh->intr_handle.type = RTE_INTR_HANDLE_EXT; - rte_intr_callback_register(&sh->intr_handle, - mlx5_dev_interrupt_handler, sh); if (priv->config.devx) { #ifndef HAVE_IBV_DEVX_ASYNC - goto error_unregister; + goto exit; #else sh->devx_comp = mlx5_glue->devx_create_cmd_comp(sh->ctx); if (sh->devx_comp) { - flags = fcntl(sh->devx_comp->fd, F_GETFL); - ret = fcntl(sh->devx_comp->fd, F_SETFL, + int flags = fcntl(sh->devx_comp->fd, F_GETFL); + int ret = fcntl(sh->devx_comp->fd, F_SETFL, flags | O_NONBLOCK); + if (ret) { DRV_LOG(INFO, "failed to change file descriptor" - " devx async event queue"); - goto error_unregister; + " devx async event queue"); + } else { + sh->intr_handle_devx.fd = sh->devx_comp->fd; + sh->intr_handle_devx.type = RTE_INTR_HANDLE_EXT; + rte_intr_callback_register + (&sh->intr_handle_devx, + mlx5_dev_interrupt_handler_devx, sh); + sh->devx_intr_cnt++; + sh->port[priv->ibv_port - 1].devx_ih_port_id = + (uint32_t)dev->data->port_id; } - sh->intr_handle_devx.fd = sh->devx_comp->fd; - sh->intr_handle_devx.type = RTE_INTR_HANDLE_EXT; - rte_intr_callback_register - (&sh->intr_handle_devx, - mlx5_dev_interrupt_handler_devx, sh); - } else { - DRV_LOG(INFO, "failed to create devx async command " - "completion"); - goto error_unregister; } #endif /* HAVE_IBV_DEVX_ASYNC */ } - sh->intr_cnt++; - goto exit; -error_unregister: - rte_intr_callback_unregister(&sh->intr_handle, - mlx5_dev_interrupt_handler, sh); -error: - /* Indicate there will be no interrupts. */ - dev->data->dev_conf.intr_conf.lsc = 0; - dev->data->dev_conf.intr_conf.rmv = 0; - sh->intr_handle.fd = 0; - sh->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN; - sh->port[priv->ibv_port - 1].ih_port_id = RTE_MAX_ETHPORTS; exit: pthread_mutex_unlock(&sh->intr_mutex); } @@ -1551,6 +1635,30 @@ mlx5_dev_interrupt_handler_install(struct rte_eth_dev *dev) mlx5_dev_shared_handler_install(dev); } +/** + * Devx uninstall interrupt handler. + * + * @param dev + * Pointer to Ethernet device. + */ +void +mlx5_dev_interrupt_handler_devx_uninstall(struct rte_eth_dev *dev) +{ + mlx5_dev_shared_handler_devx_uninstall(dev); +} + +/** + * Devx install interrupt handler. + * + * @param dev + * Pointer to Ethernet device. + */ +void +mlx5_dev_interrupt_handler_devx_install(struct rte_eth_dev *dev) +{ + mlx5_dev_shared_handler_devx_install(dev); +} + /** * DPDK callback to bring the link DOWN. * @@ -1627,37 +1735,44 @@ mlx5_is_removed(struct rte_eth_dev *dev) } /** - * Get port ID list of mlx5 instances sharing a common device. + * Get the E-Switch parameters by port id. * - * @param[in] dev - * Device to look for. - * @param[out] port_list - * Result buffer for collected port IDs. - * @param port_list_n - * Maximum number of entries in result buffer. If 0, @p port_list can be - * NULL. + * @param[in] port + * Device port id. + * @param[out] es_domain_id + * E-Switch domain id. + * @param[out] es_port_id + * The port id of the port in the E-Switch. * * @return - * Number of matching instances regardless of the @p port_list_n - * parameter, 0 if none were found. + * pointer to device private data structure containing data needed + * on success, NULL otherwise and rte_errno is set. */ -unsigned int -mlx5_dev_to_port_id(const struct rte_device *dev, uint16_t *port_list, - unsigned int port_list_n) +struct mlx5_priv * +mlx5_port_to_eswitch_info(uint16_t port) { - uint16_t id; - unsigned int n = 0; + struct rte_eth_dev *dev; + struct mlx5_priv *priv; - RTE_ETH_FOREACH_DEV_OF(id, dev) { - if (n < port_list_n) - port_list[n] = id; - n++; + if (port >= RTE_MAX_ETHPORTS) { + rte_errno = EINVAL; + return NULL; + } + if (!rte_eth_dev_is_valid_port(port)) { + rte_errno = ENODEV; + return NULL; } - return n; + dev = &rte_eth_devices[port]; + priv = dev->data->dev_private; + if (!(priv->representor || priv->master)) { + rte_errno = EINVAL; + return NULL; + } + return priv; } /** - * Get the E-Switch domain id this port belongs to. + * Get the E-Switch parameters by device instance. * * @param[in] port * Device port id. @@ -1667,34 +1782,20 @@ mlx5_dev_to_port_id(const struct rte_device *dev, uint16_t *port_list, * The port id of the port in the E-Switch. * * @return - * 0 on success, a negative errno value otherwise and rte_errno is set. + * pointer to device private data structure containing data needed + * on success, NULL otherwise and rte_errno is set. */ -int -mlx5_port_to_eswitch_info(uint16_t port, - uint16_t *es_domain_id, uint16_t *es_port_id) +struct mlx5_priv * +mlx5_dev_to_eswitch_info(struct rte_eth_dev *dev) { - struct rte_eth_dev *dev; struct mlx5_priv *priv; - if (port >= RTE_MAX_ETHPORTS) { - rte_errno = EINVAL; - return -rte_errno; - } - if (!rte_eth_dev_is_valid_port(port)) { - rte_errno = ENODEV; - return -rte_errno; - } - dev = &rte_eth_devices[port]; priv = dev->data->dev_private; if (!(priv->representor || priv->master)) { rte_errno = EINVAL; - return -rte_errno; + return NULL; } - if (es_domain_id) - *es_domain_id = priv->domain_id; - if (es_port_id) - *es_port_id = priv->vport_id; - return 0; + return priv; } /** @@ -1927,3 +2028,89 @@ mlx5_translate_port_name(const char *port_name_in, port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN; return; } + +/** + * DPDK callback to retrieve plug-in module EEPROM information (type and size). + * + * @param dev + * Pointer to Ethernet device structure. + * @param[out] modinfo + * Storage for plug-in module EEPROM information. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_get_module_info(struct rte_eth_dev *dev, + struct rte_eth_dev_module_info *modinfo) +{ + struct ethtool_modinfo info = { + .cmd = ETHTOOL_GMODULEINFO, + }; + struct ifreq ifr = (struct ifreq) { + .ifr_data = (void *)&info, + }; + int ret = 0; + + if (!dev || !modinfo) { + DRV_LOG(WARNING, "missing argument, cannot get module info"); + rte_errno = EINVAL; + return -rte_errno; + } + ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr); + if (ret) { + DRV_LOG(WARNING, "port %u ioctl(SIOCETHTOOL) failed: %s", + dev->data->port_id, strerror(rte_errno)); + return ret; + } + modinfo->type = info.type; + modinfo->eeprom_len = info.eeprom_len; + return ret; +} + +/** + * DPDK callback to retrieve plug-in module EEPROM data. + * + * @param dev + * Pointer to Ethernet device structure. + * @param[out] info + * Storage for plug-in module EEPROM data. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int mlx5_get_module_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *info) +{ + struct ethtool_eeprom *eeprom; + struct ifreq ifr; + int ret = 0; + + if (!dev || !info) { + DRV_LOG(WARNING, "missing argument, cannot get module eeprom"); + rte_errno = EINVAL; + return -rte_errno; + } + eeprom = rte_calloc(__func__, 1, + (sizeof(struct ethtool_eeprom) + info->length), 0); + if (!eeprom) { + DRV_LOG(WARNING, "port %u cannot allocate memory for " + "eeprom data", dev->data->port_id); + rte_errno = ENOMEM; + return -rte_errno; + } + eeprom->cmd = ETHTOOL_GMODULEEEPROM; + eeprom->offset = info->offset; + eeprom->len = info->length; + ifr = (struct ifreq) { + .ifr_data = (void *)eeprom, + }; + ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr); + if (ret) + DRV_LOG(WARNING, "port %u ioctl(SIOCETHTOOL) failed: %s", + dev->data->port_id, strerror(rte_errno)); + else + rte_memcpy(info->data, eeprom->data, info->length); + rte_free(eeprom); + return ret; +}