X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmlx5%2Fmlx5_ethdev.c;h=9ae9dddd3ce8c5ed73a8bb69623acb99efbd0c22;hb=cbb66daa3c85;hp=271d94a5b85e0a170be4b2e5c9e561eebc3e4ada;hpb=32d4246c90172f353c80a23fb83db9a52cce9d98;p=dpdk.git diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c index 271d94a5b8..9ae9dddd3c 100644 --- a/drivers/net/mlx5/mlx5_ethdev.c +++ b/drivers/net/mlx5/mlx5_ethdev.c @@ -3,8 +3,6 @@ * Copyright 2015 Mellanox Technologies, Ltd */ -#define _GNU_SOURCE - #include #include #include @@ -34,12 +32,39 @@ #include #include #include +#include #include "mlx5.h" #include "mlx5_glue.h" #include "mlx5_rxtx.h" #include "mlx5_utils.h" +/* Supported speed values found in /usr/include/linux/ethtool.h */ +#ifndef HAVE_SUPPORTED_40000baseKR4_Full +#define SUPPORTED_40000baseKR4_Full (1 << 23) +#endif +#ifndef HAVE_SUPPORTED_40000baseCR4_Full +#define SUPPORTED_40000baseCR4_Full (1 << 24) +#endif +#ifndef HAVE_SUPPORTED_40000baseSR4_Full +#define SUPPORTED_40000baseSR4_Full (1 << 25) +#endif +#ifndef HAVE_SUPPORTED_40000baseLR4_Full +#define SUPPORTED_40000baseLR4_Full (1 << 26) +#endif +#ifndef HAVE_SUPPORTED_56000baseKR4_Full +#define SUPPORTED_56000baseKR4_Full (1 << 27) +#endif +#ifndef HAVE_SUPPORTED_56000baseCR4_Full +#define SUPPORTED_56000baseCR4_Full (1 << 28) +#endif +#ifndef HAVE_SUPPORTED_56000baseSR4_Full +#define SUPPORTED_56000baseSR4_Full (1 << 29) +#endif +#ifndef HAVE_SUPPORTED_56000baseLR4_Full +#define SUPPORTED_56000baseLR4_Full (1 << 30) +#endif + /* Add defines in case the running kernel is not the same as user headers. */ #ifndef ETHTOOL_GLINKSETTINGS struct ethtool_link_settings { @@ -92,7 +117,7 @@ struct ethtool_link_settings { #endif /** - * Get interface name from private structure. + * Get master interface name from private structure. * * @param[in] dev * Pointer to Ethernet device. @@ -102,18 +127,21 @@ struct ethtool_link_settings { * @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -int -mlx5_get_ifname(const struct rte_eth_dev *dev, char (*ifname)[IF_NAMESIZE]) +static int +mlx5_get_master_ifname(const struct rte_eth_dev *dev, + char (*ifname)[IF_NAMESIZE]) { - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; DIR *dir; struct dirent *dent; unsigned int dev_type = 0; unsigned int dev_port_prev = ~0u; char match[IF_NAMESIZE] = ""; + assert(priv); + assert(priv->sh); { - MKSTR(path, "%s/device/net", priv->ibdev_path); + MKSTR(path, "%s/device/net", priv->sh->ibdev_path); dir = opendir(path); if (dir == NULL) { @@ -133,7 +161,7 @@ mlx5_get_ifname(const struct rte_eth_dev *dev, char (*ifname)[IF_NAMESIZE]) continue; MKSTR(path, "%s/device/net/%s/%s", - priv->ibdev_path, name, + priv->sh->ibdev_path, name, (dev_type ? "dev_id" : "dev_port")); file = fopen(path, "rb"); @@ -165,7 +193,7 @@ try_dev_id: if (dev_port == dev_port_prev) goto try_dev_id; dev_port_prev = dev_port; - if (dev_port == (priv->port - 1u)) + if (dev_port == 0) strlcpy(match, name, sizeof(match)); } closedir(dir); @@ -178,30 +206,61 @@ try_dev_id: } /** - * Get the interface index from device name. + * Get interface name from private structure. + * + * This is a port representor-aware version of mlx5_get_master_ifname(). * * @param[in] dev * Pointer to Ethernet device. + * @param[out] ifname + * Interface name output buffer. * * @return - * Interface index on success, a negative errno value otherwise and - * rte_errno is set. + * 0 on success, a negative errno value otherwise and rte_errno is set. */ int +mlx5_get_ifname(const struct rte_eth_dev *dev, char (*ifname)[IF_NAMESIZE]) +{ + struct mlx5_priv *priv = dev->data->dev_private; + unsigned int ifindex = + priv->nl_socket_rdma >= 0 ? + mlx5_nl_ifindex(priv->nl_socket_rdma, + priv->sh->ibdev_name, + priv->ibv_port) : 0; + + if (!ifindex) { + if (!priv->representor) + return mlx5_get_master_ifname(dev, ifname); + rte_errno = ENXIO; + return -rte_errno; + } + if (if_indextoname(ifindex, &(*ifname)[0])) + return 0; + rte_errno = errno; + return -rte_errno; +} + +/** + * Get the interface index from device name. + * + * @param[in] dev + * Pointer to Ethernet device. + * + * @return + * Nonzero interface index on success, zero otherwise and rte_errno is set. + */ +unsigned int mlx5_ifindex(const struct rte_eth_dev *dev) { char ifname[IF_NAMESIZE]; - int ret; + unsigned int ifindex; - ret = mlx5_get_ifname(dev, &ifname); - if (ret) - return ret; - ret = if_nametoindex(ifname); - if (ret == -1) { + if (mlx5_get_ifname(dev, &ifname)) + return 0; + ifindex = if_nametoindex(ifname); + if (!ifindex) rte_errno = errno; - return -rte_errno; - } - return ret; + return ifindex; } /** @@ -322,7 +381,7 @@ mlx5_set_flags(struct rte_eth_dev *dev, unsigned int keep, unsigned int flags) int mlx5_dev_configure(struct rte_eth_dev *dev) { - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; unsigned int rxqs_n = dev->data->nb_rx_queues; unsigned int txqs_n = dev->data->nb_tx_queues; unsigned int i; @@ -330,41 +389,19 @@ mlx5_dev_configure(struct rte_eth_dev *dev) unsigned int reta_idx_n; const uint8_t use_app_rss_key = !!dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key; - uint64_t supp_tx_offloads = mlx5_get_tx_port_offloads(dev); - uint64_t tx_offloads = dev->data->dev_conf.txmode.offloads; - uint64_t supp_rx_offloads = - (mlx5_get_rx_port_offloads() | - mlx5_get_rx_queue_offloads(dev)); - uint64_t rx_offloads = dev->data->dev_conf.rxmode.offloads; int ret = 0; - if ((tx_offloads & supp_tx_offloads) != tx_offloads) { - DRV_LOG(ERR, - "port %u some Tx offloads are not supported requested" - " 0x%" PRIx64 " supported 0x%" PRIx64, - dev->data->port_id, tx_offloads, supp_tx_offloads); - rte_errno = ENOTSUP; - return -rte_errno; - } - if ((rx_offloads & supp_rx_offloads) != rx_offloads) { - DRV_LOG(ERR, - "port %u some Rx offloads are not supported requested" - " 0x%" PRIx64 " supported 0x%" PRIx64, - dev->data->port_id, rx_offloads, supp_rx_offloads); - rte_errno = ENOTSUP; - return -rte_errno; - } if (use_app_rss_key && (dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key_len != - rss_hash_default_key_len)) { - DRV_LOG(ERR, "port %u RSS key len must be %zu Bytes long", - dev->data->port_id, rss_hash_default_key_len); + MLX5_RSS_HASH_KEY_LEN)) { + DRV_LOG(ERR, "port %u RSS key len must be %s Bytes long", + dev->data->port_id, RTE_STR(MLX5_RSS_HASH_KEY_LEN)); rte_errno = EINVAL; return -rte_errno; } priv->rss_conf.rss_key = rte_realloc(priv->rss_conf.rss_key, - rss_hash_default_key_len, 0); + MLX5_RSS_HASH_KEY_LEN, 0); if (!priv->rss_conf.rss_key) { DRV_LOG(ERR, "port %u cannot allocate RSS hash key memory (%u)", dev->data->port_id, rxqs_n); @@ -375,8 +412,8 @@ mlx5_dev_configure(struct rte_eth_dev *dev) use_app_rss_key ? dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key : rss_hash_default_key, - rss_hash_default_key_len); - priv->rss_conf.rss_key_len = rss_hash_default_key_len; + MLX5_RSS_HASH_KEY_LEN); + priv->rss_conf.rss_key_len = MLX5_RSS_HASH_KEY_LEN; priv->rss_conf.rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf; priv->rxqs = (void *)dev->data->rx_queues; priv->txqs = (void *)dev->data->tx_queues; @@ -427,7 +464,7 @@ mlx5_dev_configure(struct rte_eth_dev *dev) static void mlx5_set_default_params(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) { - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; /* Minimum CPU utilization. */ info->default_rxportconf.ring_size = 256; @@ -466,7 +503,7 @@ mlx5_set_default_params(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) void mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) { - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_dev_config *config = &priv->config; unsigned int max; char ifname[IF_NAMESIZE]; @@ -478,8 +515,8 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) * Since we need one CQ per QP, the limit is the minimum number * between the two values. */ - max = RTE_MIN(priv->device_attr.orig_attr.max_cq, - priv->device_attr.orig_attr.max_qp); + max = RTE_MIN(priv->sh->device_attr.orig_attr.max_cq, + priv->sh->device_attr.orig_attr.max_qp); /* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */ if (max >= 65535) max = 65535; @@ -494,10 +531,60 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) info->if_index = if_nametoindex(ifname); info->reta_size = priv->reta_idx_n ? priv->reta_idx_n : config->ind_table_max_size; - info->hash_key_size = rss_hash_default_key_len; + info->hash_key_size = MLX5_RSS_HASH_KEY_LEN; info->speed_capa = priv->link_speed_capa; info->flow_type_rss_offloads = ~MLX5_RSS_HF_MASK; mlx5_set_default_params(dev, info); + info->switch_info.name = dev->data->name; + 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]; + + i = RTE_MIN(mlx5_dev_to_port_id(dev->device, port_id, i), i); + while (i--) { + struct mlx5_priv *opriv = + rte_eth_devices[port_id[i]].data->dev_private; + + if (!opriv || + opriv->representor || + opriv->domain_id != priv->domain_id) + continue; + /* + * Override switch name with that of the master + * device. + */ + info->switch_info.name = opriv->dev_data->name; + break; + } + } +} + +/** + * Get firmware version of a device. + * + * @param dev + * Ethernet device port. + * @param fw_ver + * String output allocated by caller. + * @param fw_size + * Size of the output string, including terminating null byte. + * + * @return + * 0 on success, or the size of the non truncated string if too big. + */ +int mlx5_fw_version_get(struct rte_eth_dev *dev, char *fw_ver, size_t fw_size) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct ibv_device_attr *attr = &priv->sh->device_attr.orig_attr; + size_t size = strnlen(attr->fw_ver, sizeof(attr->fw_ver)) + 1; + + if (fw_size < size) + return size; + if (fw_ver != NULL) + strlcpy(fw_ver, attr->fw_ver, fw_size); + return 0; } /** @@ -531,6 +618,7 @@ mlx5_dev_supported_ptypes_get(struct rte_eth_dev *dev) }; if (dev->rx_pkt_burst == mlx5_rx_burst || + dev->rx_pkt_burst == mlx5_rx_burst_mprq || dev->rx_pkt_burst == mlx5_rx_burst_vec) return ptypes; return NULL; @@ -551,7 +639,7 @@ static int mlx5_link_update_unlocked_gset(struct rte_eth_dev *dev, struct rte_eth_link *link) { - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; struct ethtool_cmd edata = { .cmd = ETHTOOL_GSET /* Deprecated since Linux v4.5. */ }; @@ -566,10 +654,13 @@ mlx5_link_update_unlocked_gset(struct rte_eth_dev *dev, dev->data->port_id, strerror(rte_errno)); return ret; } - memset(&dev_link, 0, sizeof(dev_link)); - dev_link.link_status = ((ifr.ifr_flags & IFF_UP) && - (ifr.ifr_flags & IFF_RUNNING)); - ifr.ifr_data = (void *)&edata; + dev_link = (struct rte_eth_link) { + .link_status = ((ifr.ifr_flags & IFF_UP) && + (ifr.ifr_flags & IFF_RUNNING)), + }; + ifr = (struct ifreq) { + .ifr_data = (void *)&edata, + }; ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr); if (ret) { DRV_LOG(WARNING, @@ -599,8 +690,8 @@ mlx5_link_update_unlocked_gset(struct rte_eth_dev *dev, ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX); dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED); - if ((dev_link.link_speed && !dev_link.link_status) || - (!dev_link.link_speed && dev_link.link_status)) { + if (((dev_link.link_speed && !dev_link.link_status) || + (!dev_link.link_speed && dev_link.link_status))) { rte_errno = EAGAIN; return -rte_errno; } @@ -624,7 +715,7 @@ mlx5_link_update_unlocked_gs(struct rte_eth_dev *dev, struct rte_eth_link *link) { - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; struct ethtool_link_settings gcmd = { .cmd = ETHTOOL_GLINKSETTINGS }; struct ifreq ifr; struct rte_eth_link dev_link; @@ -637,10 +728,13 @@ mlx5_link_update_unlocked_gs(struct rte_eth_dev *dev, dev->data->port_id, strerror(rte_errno)); return ret; } - memset(&dev_link, 0, sizeof(dev_link)); - dev_link.link_status = ((ifr.ifr_flags & IFF_UP) && - (ifr.ifr_flags & IFF_RUNNING)); - ifr.ifr_data = (void *)&gcmd; + dev_link = (struct rte_eth_link) { + .link_status = ((ifr.ifr_flags & IFF_UP) && + (ifr.ifr_flags & IFF_RUNNING)), + }; + ifr = (struct ifreq) { + .ifr_data = (void *)&gcmd, + }; ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr); if (ret) { DRV_LOG(DEBUG, @@ -708,8 +802,8 @@ mlx5_link_update_unlocked_gs(struct rte_eth_dev *dev, ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX); dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED); - if ((dev_link.link_speed && !dev_link.link_status) || - (!dev_link.link_speed && dev_link.link_status)) { + if (((dev_link.link_speed && !dev_link.link_status) || + (!dev_link.link_speed && dev_link.link_status))) { rte_errno = EAGAIN; return -rte_errno; } @@ -776,7 +870,7 @@ mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete) int mlx5_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu) { - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; uint16_t kern_mtu = 0; int ret; @@ -938,80 +1032,157 @@ mlx5_ibv_device_to_pci_addr(const struct ibv_device *device, } /** - * Device status handler. + * Handle shared asynchronous events the NIC (removal event + * and link status change). Supports multiport IB device. * - * @param dev - * Pointer to Ethernet device. - * @param events - * Pointer to event flags holder. - * - * @return - * Events bitmap of callback process which can be called immediately. + * @param cb_arg + * Callback argument. */ -static uint32_t -mlx5_dev_status_handler(struct rte_eth_dev *dev) +void +mlx5_dev_interrupt_handler(void *cb_arg) { - struct priv *priv = dev->data->dev_private; + struct mlx5_ibv_shared *sh = cb_arg; struct ibv_async_event event; - uint32_t ret = 0; - if (mlx5_link_update(dev, 0) == -EAGAIN) { - usleep(0); - return 0; - } - /* Read all message and acknowledge them. */ + /* Read all message from the IB device and acknowledge them. */ for (;;) { - if (mlx5_glue->get_async_event(priv->ctx, &event)) + struct rte_eth_dev *dev; + uint32_t tmp; + + if (mlx5_glue->get_async_event(sh->ctx, &event)) break; + /* Retrieve and check IB port index. */ + tmp = (uint32_t)event.element.port_num; + assert(tmp && (tmp <= sh->max_port)); + if (!tmp || + tmp > sh->max_port || + sh->port[tmp - 1].ih_port_id >= RTE_MAX_ETHPORTS) { + /* + * Invalid IB port index or no handler + * installed for this port. + */ + mlx5_glue->ack_async_event(&event); + continue; + } + /* Retrieve ethernet device descriptor. */ + tmp = sh->port[tmp - 1].ih_port_id; + dev = &rte_eth_devices[tmp]; + tmp = 0; + assert(dev); if ((event.event_type == IBV_EVENT_PORT_ACTIVE || - event.event_type == IBV_EVENT_PORT_ERR) && - (dev->data->dev_conf.intr_conf.lsc == 1)) - ret |= (1 << RTE_ETH_EVENT_INTR_LSC); - else if (event.event_type == IBV_EVENT_DEVICE_FATAL && - dev->data->dev_conf.intr_conf.rmv == 1) - ret |= (1 << RTE_ETH_EVENT_INTR_RMV); - else - DRV_LOG(DEBUG, - "port %u event type %d on not handled", - dev->data->port_id, event.event_type); + event.event_type == IBV_EVENT_PORT_ERR) && + dev->data->dev_conf.intr_conf.lsc) { + mlx5_glue->ack_async_event(&event); + if (mlx5_link_update(dev, 0) == -EAGAIN) { + usleep(0); + continue; + } + _rte_eth_dev_callback_process + (dev, RTE_ETH_EVENT_INTR_LSC, NULL); + continue; + } + if (event.event_type == IBV_EVENT_DEVICE_FATAL && + dev->data->dev_conf.intr_conf.rmv) { + mlx5_glue->ack_async_event(&event); + _rte_eth_dev_callback_process + (dev, RTE_ETH_EVENT_INTR_RMV, NULL); + continue; + } + DRV_LOG(DEBUG, + "port %u event type %d on not handled", + dev->data->port_id, event.event_type); mlx5_glue->ack_async_event(&event); } - return ret; } /** - * Handle interrupts from the NIC. + * Uninstall shared asynchronous device events handler. + * This function is implemeted to support event sharing + * between multiple ports of single IB device. * - * @param[in] intr_handle - * Interrupt handler. - * @param cb_arg - * Callback argument. + * @param dev + * Pointer to Ethernet device. */ -void -mlx5_dev_interrupt_handler(void *cb_arg) +static void +mlx5_dev_shared_handler_uninstall(struct rte_eth_dev *dev) { - struct rte_eth_dev *dev = cb_arg; - uint32_t events; - - events = mlx5_dev_status_handler(dev); - if (events & (1 << RTE_ETH_EVENT_INTR_LSC)) - _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL); - if (events & (1 << RTE_ETH_EVENT_INTR_RMV)) - _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RMV, NULL); + 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].ih_port_id >= RTE_MAX_ETHPORTS) + goto exit; + assert(sh->port[priv->ibv_port - 1].ih_port_id == + (uint32_t)dev->data->port_id); + assert(sh->intr_cnt); + sh->port[priv->ibv_port - 1].ih_port_id = RTE_MAX_ETHPORTS; + if (!sh->intr_cnt || --sh->intr_cnt) + goto exit; + rte_intr_callback_unregister(&sh->intr_handle, + 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); } /** - * Handle interrupts from the socket. + * Install shared asyncronous device events handler. + * This function is implemeted to support event sharing + * between multiple ports of single IB device. * - * @param cb_arg - * Callback argument. + * @param dev + * Pointer to Ethernet device. */ static void -mlx5_dev_handler_socket(void *cb_arg) +mlx5_dev_shared_handler_install(struct rte_eth_dev *dev) { - struct rte_eth_dev *dev = cb_arg; + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_ibv_shared *sh = priv->sh; + int ret; + int flags; - mlx5_socket_handle(dev); + 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].ih_port_id < RTE_MAX_ETHPORTS) { + /* The handler is already installed for this port. */ + 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->intr_cnt++; + goto exit; + } + /* No shared handler installed. */ + assert(sh->ctx->async_fd > 0); + 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"); + /* Indicate there will be no interrupts. */ + dev->data->dev_conf.intr_conf.lsc = 0; + dev->data->dev_conf.intr_conf.rmv = 0; + sh->port[priv->ibv_port - 1].ih_port_id = RTE_MAX_ETHPORTS; + 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); + sh->intr_cnt++; +exit: + pthread_mutex_unlock(&sh->intr_mutex); } /** @@ -1023,19 +1194,7 @@ mlx5_dev_handler_socket(void *cb_arg) void mlx5_dev_interrupt_handler_uninstall(struct rte_eth_dev *dev) { - struct priv *priv = dev->data->dev_private; - - if (dev->data->dev_conf.intr_conf.lsc || - dev->data->dev_conf.intr_conf.rmv) - rte_intr_callback_unregister(&priv->intr_handle, - mlx5_dev_interrupt_handler, dev); - if (priv->primary_socket) - rte_intr_callback_unregister(&priv->intr_handle_socket, - mlx5_dev_handler_socket, dev); - priv->intr_handle.fd = 0; - priv->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN; - priv->intr_handle_socket.fd = 0; - priv->intr_handle_socket.type = RTE_INTR_HANDLE_UNKNOWN; + mlx5_dev_shared_handler_uninstall(dev); } /** @@ -1047,38 +1206,7 @@ mlx5_dev_interrupt_handler_uninstall(struct rte_eth_dev *dev) void mlx5_dev_interrupt_handler_install(struct rte_eth_dev *dev) { - struct priv *priv = dev->data->dev_private; - int ret; - int flags; - - assert(priv->ctx->async_fd > 0); - flags = fcntl(priv->ctx->async_fd, F_GETFL); - ret = fcntl(priv->ctx->async_fd, F_SETFL, flags | O_NONBLOCK); - if (ret) { - DRV_LOG(INFO, - "port %u failed to change file descriptor async event" - " queue", - dev->data->port_id); - dev->data->dev_conf.intr_conf.lsc = 0; - dev->data->dev_conf.intr_conf.rmv = 0; - } - if (dev->data->dev_conf.intr_conf.lsc || - dev->data->dev_conf.intr_conf.rmv) { - priv->intr_handle.fd = priv->ctx->async_fd; - priv->intr_handle.type = RTE_INTR_HANDLE_EXT; - rte_intr_callback_register(&priv->intr_handle, - mlx5_dev_interrupt_handler, dev); - } - ret = mlx5_socket_init(dev); - if (ret) - DRV_LOG(ERR, "port %u cannot initialise socket: %s", - dev->data->port_id, strerror(rte_errno)); - else if (priv->primary_socket) { - priv->intr_handle_socket.fd = priv->primary_socket; - priv->intr_handle_socket.type = RTE_INTR_HANDLE_EXT; - rte_intr_callback_register(&priv->intr_handle_socket, - mlx5_dev_handler_socket, dev); - } + mlx5_dev_shared_handler_install(dev); } /** @@ -1123,7 +1251,7 @@ mlx5_set_link_up(struct rte_eth_dev *dev) eth_tx_burst_t mlx5_select_tx_function(struct rte_eth_dev *dev) { - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; eth_tx_burst_t tx_pkt_burst = mlx5_tx_burst; struct mlx5_dev_config *config = &priv->config; uint64_t tx_offloads = dev->data->dev_conf.txmode.offloads; @@ -1188,6 +1316,8 @@ mlx5_select_rx_function(struct rte_eth_dev *dev) rx_pkt_burst = mlx5_rx_burst_vec; DRV_LOG(DEBUG, "port %u selected Rx vectorized function", dev->data->port_id); + } else if (mlx5_mprq_enabled(dev)) { + rx_pkt_burst = mlx5_rx_burst_mprq; } return rx_pkt_burst; } @@ -1205,9 +1335,157 @@ int mlx5_is_removed(struct rte_eth_dev *dev) { struct ibv_device_attr device_attr; - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; - if (mlx5_glue->query_device(priv->ctx, &device_attr) == EIO) + if (mlx5_glue->query_device(priv->sh->ctx, &device_attr) == EIO) return 1; return 0; } + +/** + * Get port ID list of mlx5 instances sharing a common device. + * + * @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. + * + * @return + * Number of matching instances regardless of the @p port_list_n + * parameter, 0 if none were found. + */ +unsigned int +mlx5_dev_to_port_id(const struct rte_device *dev, uint16_t *port_list, + unsigned int port_list_n) +{ + uint16_t id; + unsigned int n = 0; + + RTE_ETH_FOREACH_DEV_OF(id, dev) { + if (n < port_list_n) + port_list[n] = id; + n++; + } + return n; +} + +/** + * Get switch information associated with network interface. + * + * @param ifindex + * Network interface index. + * @param[out] info + * Switch information object, populated in case of success. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_sysfs_switch_info(unsigned int ifindex, struct mlx5_switch_info *info) +{ + char ifname[IF_NAMESIZE]; + char port_name[IF_NAMESIZE]; + FILE *file; + struct mlx5_switch_info data = { + .master = 0, + .representor = 0, + .port_name_new = 0, + .port_name = 0, + .switch_id = 0, + }; + DIR *dir; + bool port_name_set = false; + bool port_switch_id_set = false; + bool device_dir = false; + char c; + int ret; + + if (!if_indextoname(ifindex, ifname)) { + rte_errno = errno; + return -rte_errno; + } + + MKSTR(phys_port_name, "/sys/class/net/%s/phys_port_name", + ifname); + MKSTR(phys_switch_id, "/sys/class/net/%s/phys_switch_id", + ifname); + MKSTR(pci_device, "/sys/class/net/%s/device", + ifname); + + file = fopen(phys_port_name, "rb"); + if (file != NULL) { + ret = fscanf(file, "%s", port_name); + fclose(file); + if (ret == 1) + port_name_set = mlx5_translate_port_name(port_name, + &data); + } + file = fopen(phys_switch_id, "rb"); + if (file == NULL) { + rte_errno = errno; + return -rte_errno; + } + port_switch_id_set = + fscanf(file, "%" SCNx64 "%c", &data.switch_id, &c) == 2 && + c == '\n'; + fclose(file); + dir = opendir(pci_device); + if (dir != NULL) { + closedir(dir); + device_dir = true; + } + data.master = port_switch_id_set && (!port_name_set || device_dir); + data.representor = port_switch_id_set && port_name_set && !device_dir; + *info = data; + assert(!(data.master && data.representor)); + if (data.master && data.representor) { + DRV_LOG(ERR, "ifindex %u device is recognized as master" + " and as representor", ifindex); + rte_errno = ENODEV; + return -rte_errno; + } + return 0; +} + +/** + * Extract port name, as a number, from sysfs or netlink information. + * + * @param[in] port_name_in + * String representing the port name. + * @param[out] port_info_out + * Port information, including port name as a number. + * + * @return + * true on success, false otherwise. + */ +bool +mlx5_translate_port_name(const char *port_name_in, + struct mlx5_switch_info *port_info_out) +{ + char pf_c1, pf_c2, vf_c1, vf_c2; + char *end; + int32_t pf_num; + bool port_name_set = false; + + /* + * Check for port-name as a string of the form pf0vf0 + * (support kernel ver >= 5.0) + */ + port_name_set = (sscanf(port_name_in, "%c%c%d%c%c%d", &pf_c1, &pf_c2, + &pf_num, &vf_c1, &vf_c2, + &port_info_out->port_name) == 6); + if (port_name_set) { + port_info_out->port_name_new = 1; + } else { + /* Check for port-name as a number (support kernel ver < 5.0 */ + errno = 0; + port_info_out->port_name = strtol(port_name_in, &end, 0); + if (!errno && + (size_t)(end - port_name_in) == strlen(port_name_in)) + port_name_set = true; + } + return port_name_set; +}