- ret = mlx5_ifreq(dev, SIOCGIFFLAGS, &ifr);
- if (ret) {
- DRV_LOG(WARNING, "port %u ioctl(SIOCGIFFLAGS) failed: %s",
- dev->data->port_id, strerror(rte_errno));
- return ret;
- }
- 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) {
- if (ret == -ENOTSUP && priv->representor) {
- /*
- * For representors we can try to inherit link
- * settings from the master device. Actually
- * link settings do not make a lot of sense
- * for representors due to missing physical
- * link. The old kernel drivers supported
- * emulated settings query for representors,
- * the new ones do not, so we have to add
- * this code for compatibility issues.
- */
- master = mlx5_find_master_dev(dev);
- if (master) {
- ifr = (struct ifreq) {
- .ifr_data = (void *)&gcmd,
- };
- ret = mlx5_ifreq(master, SIOCETHTOOL, &ifr);
- }
- }
- if (ret) {
- DRV_LOG(DEBUG,
- "port %u ioctl(SIOCETHTOOL,"
- " ETHTOOL_GLINKSETTINGS) failed: %s",
- dev->data->port_id, strerror(rte_errno));
- return ret;
- }
-
- }
- gcmd.link_mode_masks_nwords = -gcmd.link_mode_masks_nwords;
-
- alignas(struct ethtool_link_settings)
- uint8_t data[offsetof(struct ethtool_link_settings, link_mode_masks) +
- sizeof(uint32_t) * gcmd.link_mode_masks_nwords * 3];
- struct ethtool_link_settings *ecmd = (void *)data;
-
- *ecmd = gcmd;
- ifr.ifr_data = (void *)ecmd;
- ret = mlx5_ifreq(master ? master : dev, SIOCETHTOOL, &ifr);
- if (ret) {
- DRV_LOG(DEBUG,
- "port %u ioctl(SIOCETHTOOL,"
- "ETHTOOL_GLINKSETTINGS) failed: %s",
- dev->data->port_id, strerror(rte_errno));
- return ret;
- }
- 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;
- if (sc & MLX5_BITSHIFT(ETHTOOL_LINK_MODE_Autoneg_BIT))
- priv->link_speed_capa |= ETH_LINK_SPEED_AUTONEG;
- if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_1000baseT_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT)))
- priv->link_speed_capa |= ETH_LINK_SPEED_1G;
- if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT)))
- priv->link_speed_capa |= ETH_LINK_SPEED_10G;
- if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT)))
- priv->link_speed_capa |= ETH_LINK_SPEED_20G;
- if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT)))
- priv->link_speed_capa |= ETH_LINK_SPEED_40G;
- if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT)))
- priv->link_speed_capa |= ETH_LINK_SPEED_56G;
- if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT)))
- priv->link_speed_capa |= ETH_LINK_SPEED_25G;
- if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT)))
- priv->link_speed_capa |= ETH_LINK_SPEED_50G;
- if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT) |
- MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT)))
- priv->link_speed_capa |= ETH_LINK_SPEED_100G;
- dev_link.link_duplex = ((ecmd->duplex == DUPLEX_HALF) ?
- 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))) {
- rte_errno = EAGAIN;
- return -rte_errno;
- }
- *link = dev_link;
- return 0;
-}
-
-/**
- * DPDK callback to retrieve physical link information.
- *
- * @param dev
- * Pointer to Ethernet device structure.
- * @param wait_to_complete
- * Wait for request completion.
- *
- * @return
- * 0 if link status was not updated, positive if it was, a negative errno
- * value otherwise and rte_errno is set.
- */
-int
-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);
- if (ret == -ENOTSUP)
- ret = mlx5_link_update_unlocked_gset(dev, &dev_link);
- if (ret == 0)
- break;
- /* Handle wait to complete situation. */
- if ((wait_to_complete || retry) && ret == -EAGAIN) {
- if (abs((int)difftime(time(NULL), start_time)) <
- MLX5_LINK_STATUS_TIMEOUT) {
- usleep(0);
- continue;
- } else {
- rte_errno = EBUSY;
- return -rte_errno;
- }
- } else if (ret < 0) {
- return ret;
- }
- } 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;
- return ret;
-}
-
-/**
- * DPDK callback to change the MTU.
- *
- * @param dev
- * Pointer to Ethernet device structure.
- * @param in_mtu
- * New MTU.
- *
- * @return
- * 0 on success, a negative errno value otherwise and rte_errno is set.
- */
-int
-mlx5_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
-{
- struct mlx5_priv *priv = dev->data->dev_private;
- uint16_t kern_mtu = 0;
- int ret;
-
- ret = mlx5_get_mtu(dev, &kern_mtu);
- if (ret)
- return ret;
- /* Set kernel interface MTU first. */
- ret = mlx5_set_mtu(dev, mtu);
- if (ret)
- return ret;
- ret = mlx5_get_mtu(dev, &kern_mtu);
- if (ret)
- return ret;
- if (kern_mtu == mtu) {
- priv->mtu = mtu;
- DRV_LOG(DEBUG, "port %u adapter MTU set to %u",
- dev->data->port_id, mtu);
- return 0;
- }
- rte_errno = EAGAIN;
- return -rte_errno;
-}
-
-/**
- * DPDK callback to get flow control status.
- *
- * @param dev
- * Pointer to Ethernet device structure.
- * @param[out] fc_conf
- * Flow control output buffer.
- *
- * @return
- * 0 on success, a negative errno value otherwise and rte_errno is set.
- */
-int
-mlx5_dev_get_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
-{
- struct ifreq ifr;
- struct ethtool_pauseparam ethpause = {
- .cmd = ETHTOOL_GPAUSEPARAM
- };
- int ret;
-
- ifr.ifr_data = (void *)ðpause;
- ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
- if (ret) {
- DRV_LOG(WARNING,
- "port %u ioctl(SIOCETHTOOL, ETHTOOL_GPAUSEPARAM) failed:"
- " %s",
- dev->data->port_id, strerror(rte_errno));
- return ret;
- }
- fc_conf->autoneg = ethpause.autoneg;
- if (ethpause.rx_pause && ethpause.tx_pause)
- fc_conf->mode = RTE_FC_FULL;
- else if (ethpause.rx_pause)
- fc_conf->mode = RTE_FC_RX_PAUSE;
- else if (ethpause.tx_pause)
- fc_conf->mode = RTE_FC_TX_PAUSE;
- else
- fc_conf->mode = RTE_FC_NONE;
- return 0;
-}
-
-/**
- * DPDK callback to modify flow control parameters.
- *
- * @param dev
- * Pointer to Ethernet device structure.
- * @param[in] fc_conf
- * Flow control parameters.
- *
- * @return
- * 0 on success, a negative errno value otherwise and rte_errno is set.
- */
-int
-mlx5_dev_set_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
-{
- struct ifreq ifr;
- struct ethtool_pauseparam ethpause = {
- .cmd = ETHTOOL_SPAUSEPARAM
- };
- int ret;
-
- ifr.ifr_data = (void *)ðpause;
- ethpause.autoneg = fc_conf->autoneg;
- if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
- (fc_conf->mode & RTE_FC_RX_PAUSE))
- ethpause.rx_pause = 1;
- else
- ethpause.rx_pause = 0;
-
- if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
- (fc_conf->mode & RTE_FC_TX_PAUSE))
- ethpause.tx_pause = 1;
- else
- ethpause.tx_pause = 0;
- ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
- if (ret) {
- DRV_LOG(WARNING,
- "port %u ioctl(SIOCETHTOOL, ETHTOOL_SPAUSEPARAM)"
- " failed: %s",
- dev->data->port_id, strerror(rte_errno));
- return ret;
- }
- return 0;
-}
-
-/**
- * Get PCI information by sysfs device path.
- *
- * @param dev_path
- * Pointer to device sysfs folder name.
- * @param[out] pci_addr
- * PCI bus address output buffer.
- *
- * @return
- * 0 on success, a negative errno value otherwise and rte_errno is set.
- */
-int
-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", dev_path);
-
- file = fopen(path, "rb");
- if (file == NULL) {
- rte_errno = errno;
- return -rte_errno;
- }
- while (fgets(line, sizeof(line), file) == line) {
- size_t len = strlen(line);
- int ret;
-
- /* Truncate long lines. */
- if (len == (sizeof(line) - 1))
- while (line[(len - 1)] != '\n') {
- ret = fgetc(file);
- if (ret == EOF)
- break;
- line[(len - 1)] = ret;
- }
- /* Extract information. */
- if (sscanf(line,
- "PCI_SLOT_NAME="
- "%" SCNx32 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n",
- &pci_addr->domain,
- &pci_addr->bus,
- &pci_addr->devid,
- &pci_addr->function) == 4) {
- ret = 0;
- break;
- }
- }
- fclose(file);
- return 0;
-}
-
-/**
- * Handle asynchronous removal event for entire multiport device.
- *
- * @param sh
- * Infiniband device shared context.
- */
-static void
-mlx5_dev_interrupt_device_fatal(struct mlx5_ibv_shared *sh)
-{
- uint32_t i;
-
- for (i = 0; i < sh->max_port; ++i) {
- struct rte_eth_dev *dev;
-
- if (sh->port[i].ih_port_id >= RTE_MAX_ETHPORTS) {
- /*
- * Or not existing port either no
- * handler installed for this port.
- */
- continue;
- }
- dev = &rte_eth_devices[sh->port[i].ih_port_id];
- assert(dev);
- if (dev->data->dev_conf.intr_conf.rmv)
- _rte_eth_dev_callback_process
- (dev, RTE_ETH_EVENT_INTR_RMV, NULL);
- }
-}
-
-/**
- * Handle shared asynchronous events the NIC (removal event
- * and link status change). Supports multiport IB device.
- *
- * @param cb_arg
- * Callback argument.
- */
-void
-mlx5_dev_interrupt_handler(void *cb_arg)
-{
- struct mlx5_ibv_shared *sh = cb_arg;
- struct ibv_async_event event;
-
- /* Read all message from the IB device and acknowledge them. */
- for (;;) {
- 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;
- if (!tmp && event.event_type == IBV_EVENT_DEVICE_FATAL) {
- /*
- * The DEVICE_FATAL event is called once for
- * entire device without port specifying.
- * We should notify all existing ports.
- */
- mlx5_glue->ack_async_event(&event);
- mlx5_dev_interrupt_device_fatal(sh);
- continue;
- }
- assert(tmp && (tmp <= sh->max_port));
- if (!tmp) {
- /* Unsupported devive level event. */
- mlx5_glue->ack_async_event(&event);
- DRV_LOG(DEBUG,
- "unsupported common event (type %d)",
- event.event_type);
- continue;
- }
- if (tmp > sh->max_port) {
- /* Invalid IB port index. */
- mlx5_glue->ack_async_event(&event);
- DRV_LOG(DEBUG,
- "cannot handle an event (type %d)"
- "due to invalid IB port index (%u)",
- event.event_type, tmp);
- continue;
- }
- if (sh->port[tmp - 1].ih_port_id >= RTE_MAX_ETHPORTS) {
- /* No handler installed. */
- mlx5_glue->ack_async_event(&event);
- DRV_LOG(DEBUG,
- "cannot handle an event (type %d)"
- "due to no handler installed for port %u",
- event.event_type, tmp);
- continue;
- }
- /* Retrieve ethernet device descriptor. */
- tmp = sh->port[tmp - 1].ih_port_id;
- dev = &rte_eth_devices[tmp];
- assert(dev);
- if ((event.event_type == IBV_EVENT_PORT_ACTIVE ||
- 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;
- }
- DRV_LOG(DEBUG,
- "port %u cannot handle an unknown event (type %d)",
- dev->data->port_id, event.event_type);
- mlx5_glue->ack_async_event(&event);
- }
-}
-
-/*
- * Unregister callback handler safely. The handler may be active
- * while we are trying to unregister it, in this case code -EAGAIN
- * is returned by rte_intr_callback_unregister(). This routine checks
- * the return code and tries to unregister handler again.
- *
- * @param handle
- * interrupt handle
- * @param cb_fn
- * pointer to callback routine
- * @cb_arg
- * opaque callback parameter
- */
-void
-mlx5_intr_callback_unregister(const struct rte_intr_handle *handle,
- rte_intr_callback_fn cb_fn, void *cb_arg)
-{
- /*
- * Try to reduce timeout management overhead by not calling
- * the timer related routines on the first iteration. If the
- * unregistering succeeds on first call there will be no
- * timer calls at all.
- */
- uint64_t twait = 0;
- uint64_t start = 0;
-
- do {
- int ret;
-
- ret = rte_intr_callback_unregister(handle, cb_fn, cb_arg);
- if (ret >= 0)
- return;
- if (ret != -EAGAIN) {
- DRV_LOG(INFO, "failed to unregister interrupt"
- " handler (error: %d)", ret);
- assert(false);
- return;
- }
- if (twait) {
- struct timespec onems;
-
- /* Wait one millisecond and try again. */
- onems.tv_sec = 0;
- onems.tv_nsec = NS_PER_S / MS_PER_S;
- nanosleep(&onems, 0);
- /* Check whether one second elapsed. */
- if ((rte_get_timer_cycles() - start) <= twait)
- continue;