#include <rte_atomic.h>
#include <rte_ethdev.h>
+#include <rte_bus_pci.h>
#include <rte_mbuf.h>
#include <rte_common.h>
#include <rte_interrupts.h>
#define ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT 39
#endif
-/**
- * Return private structure associated with an Ethernet device.
- *
- * @param dev
- * Pointer to Ethernet device structure.
- *
- * @return
- * Pointer to private structure.
- */
-struct priv *
-mlx5_get_priv(struct rte_eth_dev *dev)
-{
- return dev->data->dev_private;
-}
-
-/**
- * Check if running as a secondary process.
- *
- * @return
- * Nonzero if running as a secondary process.
- */
-inline int
-mlx5_is_secondary(void)
-{
- return rte_eal_process_type() == RTE_PROC_SECONDARY;
-}
-
/**
* Get interface name from private structure.
*
unsigned int j;
unsigned int reta_idx_n;
const uint8_t use_app_rss_key =
- !!dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key_len;
-
+ !!dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key;
+ uint64_t supp_tx_offloads = mlx5_priv_get_tx_port_offloads(priv);
+ uint64_t tx_offloads = dev->data->dev_conf.txmode.offloads;
+ uint64_t supp_rx_offloads =
+ (mlx5_priv_get_rx_port_offloads(priv) |
+ mlx5_priv_get_rx_queue_offloads(priv));
+ uint64_t rx_offloads = dev->data->dev_conf.rxmode.offloads;
+
+ if ((tx_offloads & supp_tx_offloads) != tx_offloads) {
+ ERROR("Some Tx offloads are not supported "
+ "requested 0x%" PRIx64 " supported 0x%" PRIx64,
+ tx_offloads, supp_tx_offloads);
+ return ENOTSUP;
+ }
+ if ((rx_offloads & supp_rx_offloads) != rx_offloads) {
+ ERROR("Some Rx offloads are not supported "
+ "requested 0x%" PRIx64 " supported 0x%" PRIx64,
+ rx_offloads, supp_rx_offloads);
+ return ENOTSUP;
+ }
if (use_app_rss_key &&
(dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key_len !=
rss_hash_default_key_len)) {
(void *)dev, priv->txqs_n, txqs_n);
priv->txqs_n = txqs_n;
}
- if (rxqs_n > priv->ind_table_max_size) {
+ if (rxqs_n > priv->config.ind_table_max_size) {
ERROR("cannot handle this many RX queues (%u)", rxqs_n);
return EINVAL;
}
* maximum indirection table size for better balancing.
* The result is always rounded to the next power of two. */
reta_idx_n = (1 << log2above((rxqs_n & (rxqs_n - 1)) ?
- priv->ind_table_max_size :
+ priv->config.ind_table_max_size :
rxqs_n));
if (priv_rss_reta_index_resize(priv, reta_idx_n))
return ENOMEM;
struct priv *priv = dev->data->dev_private;
int ret;
- if (mlx5_is_secondary())
- return -E_RTE_SECONDARY;
-
priv_lock(priv);
ret = dev_configure(dev);
assert(ret >= 0);
void
mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
{
- struct priv *priv = mlx5_get_priv(dev);
+ struct priv *priv = dev->data->dev_private;
+ struct mlx5_dev_config *config = &priv->config;
unsigned int max;
char ifname[IF_NAMESIZE];
info->max_rx_queues = max;
info->max_tx_queues = max;
info->max_mac_addrs = RTE_DIM(priv->mac);
- info->rx_offload_capa =
- (priv->hw_csum ?
- (DEV_RX_OFFLOAD_IPV4_CKSUM |
- DEV_RX_OFFLOAD_UDP_CKSUM |
- DEV_RX_OFFLOAD_TCP_CKSUM) :
- 0) |
- (priv->hw_vlan_strip ? DEV_RX_OFFLOAD_VLAN_STRIP : 0);
- if (!priv->mps)
- info->tx_offload_capa = DEV_TX_OFFLOAD_VLAN_INSERT;
- if (priv->hw_csum)
- info->tx_offload_capa |=
- (DEV_TX_OFFLOAD_IPV4_CKSUM |
- DEV_TX_OFFLOAD_UDP_CKSUM |
- DEV_TX_OFFLOAD_TCP_CKSUM);
- if (priv->tso)
- info->tx_offload_capa |= DEV_TX_OFFLOAD_TCP_TSO;
- if (priv->tunnel_en)
- info->tx_offload_capa |= (DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM |
- DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
- DEV_TX_OFFLOAD_GRE_TNL_TSO);
+ info->rx_queue_offload_capa =
+ mlx5_priv_get_rx_queue_offloads(priv);
+ info->rx_offload_capa = (mlx5_priv_get_rx_port_offloads(priv) |
+ info->rx_queue_offload_capa);
+ info->tx_offload_capa = mlx5_priv_get_tx_port_offloads(priv);
if (priv_get_ifname(priv, &ifname) == 0)
info->if_index = if_nametoindex(ifname);
info->reta_size = priv->reta_idx_n ?
- priv->reta_idx_n : priv->ind_table_max_size;
+ priv->reta_idx_n : config->ind_table_max_size;
info->hash_key_size = priv->rss_conf.rss_key_len;
info->speed_capa = priv->link_speed_capa;
priv_unlock(priv);
static int
mlx5_link_update_unlocked_gset(struct rte_eth_dev *dev, int wait_to_complete)
{
- struct priv *priv = mlx5_get_priv(dev);
+ struct priv *priv = dev->data->dev_private;
struct ethtool_cmd edata = {
.cmd = ETHTOOL_GSET /* Deprecated since Linux v4.5. */
};
static int
mlx5_link_update_unlocked_gs(struct rte_eth_dev *dev, int wait_to_complete)
{
- struct priv *priv = mlx5_get_priv(dev);
+ struct priv *priv = dev->data->dev_private;
struct ethtool_link_settings gcmd = { .cmd = ETHTOOL_GLINKSETTINGS };
struct ifreq ifr;
struct rte_eth_link dev_link;
sc = ecmd->link_mode_masks[0] |
((uint64_t)ecmd->link_mode_masks[1] << 32);
priv->link_speed_capa = 0;
- if (sc & ETHTOOL_LINK_MODE_Autoneg_BIT)
+ if (sc & MLX5_BITSHIFT(ETHTOOL_LINK_MODE_Autoneg_BIT))
priv->link_speed_capa |= ETH_LINK_SPEED_AUTONEG;
- if (sc & (ETHTOOL_LINK_MODE_1000baseT_Full_BIT |
- ETHTOOL_LINK_MODE_1000baseKX_Full_BIT))
+ 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 & (ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT |
- ETHTOOL_LINK_MODE_10000baseKR_Full_BIT |
- ETHTOOL_LINK_MODE_10000baseR_FEC_BIT))
+ 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 & (ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT |
- ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT))
+ 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 & (ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT |
- ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT |
- ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT |
- ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT))
+ 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 & (ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT |
- ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT |
- ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT |
- ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT))
+ 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 & (ETHTOOL_LINK_MODE_25000baseCR_Full_BIT |
- ETHTOOL_LINK_MODE_25000baseKR_Full_BIT |
- ETHTOOL_LINK_MODE_25000baseSR_Full_BIT))
+ 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 & (ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT |
- ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT))
+ 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 & (ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT |
- ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT |
- ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT |
- ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT))
+ 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);
}
/**
- * DPDK callback to retrieve physical link information.
+ * Enable receiving and transmitting traffic.
*
- * @param dev
- * Pointer to Ethernet device structure.
+ * @param priv
+ * Pointer to private structure.
+ */
+static void
+priv_link_start(struct priv *priv)
+{
+ struct rte_eth_dev *dev = priv->dev;
+ int err;
+
+ dev->tx_pkt_burst = priv_select_tx_function(priv, dev);
+ dev->rx_pkt_burst = priv_select_rx_function(priv, dev);
+ err = priv_dev_traffic_enable(priv, dev);
+ if (err)
+ ERROR("%p: error occurred while configuring control flows: %s",
+ (void *)priv, strerror(err));
+ err = priv_flow_start(priv, &priv->flows);
+ if (err)
+ ERROR("%p: error occurred while configuring flows: %s",
+ (void *)priv, strerror(err));
+}
+
+/**
+ * Disable receiving and transmitting traffic.
+ *
+ * @param priv
+ * Pointer to private structure.
+ */
+static void
+priv_link_stop(struct priv *priv)
+{
+ struct rte_eth_dev *dev = priv->dev;
+
+ priv_flow_stop(priv, &priv->flows);
+ priv_dev_traffic_disable(priv, dev);
+ dev->rx_pkt_burst = removed_rx_burst;
+ dev->tx_pkt_burst = removed_tx_burst;
+}
+
+/**
+ * Retrieve physical link information and update rx/tx_pkt_burst callbacks
+ * accordingly.
+ *
+ * @param priv
+ * Pointer to private structure.
* @param wait_to_complete
* Wait for request completion (ignored).
*/
int
-mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete)
+priv_link_update(struct priv *priv, int wait_to_complete)
{
+ struct rte_eth_dev *dev = priv->dev;
struct utsname utsname;
int ver[3];
+ int ret;
+ struct rte_eth_link dev_link = dev->data->dev_link;
if (uname(&utsname) == -1 ||
sscanf(utsname.release, "%d.%d.%d",
&ver[0], &ver[1], &ver[2]) != 3 ||
KERNEL_VERSION(ver[0], ver[1], ver[2]) < KERNEL_VERSION(4, 9, 0))
- return mlx5_link_update_unlocked_gset(dev, wait_to_complete);
- return mlx5_link_update_unlocked_gs(dev, wait_to_complete);
+ ret = mlx5_link_update_unlocked_gset(dev, wait_to_complete);
+ else
+ ret = mlx5_link_update_unlocked_gs(dev, wait_to_complete);
+ /* If lsc interrupt is disabled, should always be ready for traffic. */
+ if (!dev->data->dev_conf.intr_conf.lsc) {
+ priv_link_start(priv);
+ return ret;
+ }
+ /* Re-select burst callbacks only if link status has been changed. */
+ if (!ret && dev_link.link_status != dev->data->dev_link.link_status) {
+ if (dev->data->dev_link.link_status == ETH_LINK_UP)
+ priv_link_start(priv);
+ else
+ priv_link_stop(priv);
+ }
+ return ret;
+}
+
+/**
+ * DPDK callback to retrieve physical link information.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ * @param wait_to_complete
+ * Wait for request completion (ignored).
+ */
+int
+mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete)
+{
+ struct priv *priv = dev->data->dev_private;
+ int ret;
+
+ priv_lock(priv);
+ ret = priv_link_update(priv, wait_to_complete);
+ priv_unlock(priv);
+ return ret;
}
/**
uint16_t kern_mtu;
int ret = 0;
- if (mlx5_is_secondary())
- return -E_RTE_SECONDARY;
-
priv_lock(priv);
ret = priv_get_mtu(priv, &kern_mtu);
if (ret)
};
int ret;
- if (mlx5_is_secondary())
- return -E_RTE_SECONDARY;
-
ifr.ifr_data = (void *)ðpause;
priv_lock(priv);
if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
};
int ret;
- if (mlx5_is_secondary())
- return -E_RTE_SECONDARY;
-
ifr.ifr_data = (void *)ðpause;
ethpause.autoneg = fc_conf->autoneg;
if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
{
struct rte_eth_link *link = &priv->dev->data->dev_link;
- mlx5_link_update(priv->dev, 0);
+ priv_link_update(priv, 0);
if (((link->link_speed == 0) && link->link_status) ||
((link->link_speed != 0) && !link->link_status)) {
/*
struct priv *priv = dev->data->dev_private;
int ret;
- priv_lock(priv);
- assert(priv->pending_alarm == 1);
+ while (!priv_trylock(priv)) {
+ /* Alarm is being canceled. */
+ if (priv->pending_alarm == 0)
+ return;
+ rte_pause();
+ }
priv->pending_alarm = 0;
ret = priv_link_status_update(priv);
priv_unlock(priv);
if (!ret)
- _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL,
- NULL);
+ _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
}
/**
events = priv_dev_status_handler(priv);
priv_unlock(priv);
if (events & (1 << RTE_ETH_EVENT_INTR_LSC))
- _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL,
- NULL);
+ _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,
- NULL);
+ _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RMV, NULL);
}
/**
if (priv->primary_socket)
rte_intr_callback_unregister(&priv->intr_handle_socket,
mlx5_dev_handler_socket, dev);
- if (priv->pending_alarm)
+ if (priv->pending_alarm) {
+ priv->pending_alarm = 0;
rte_eal_alarm_cancel(mlx5_dev_link_status_handler, dev);
- priv->pending_alarm = 0;
+ }
priv->intr_handle.fd = 0;
priv->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
priv->intr_handle_socket.fd = 0;
{
int rc, flags;
- assert(!mlx5_is_secondary());
assert(priv->ctx->async_fd > 0);
flags = fcntl(priv->ctx->async_fd, F_GETFL);
rc = fcntl(priv->ctx->async_fd, F_SETFL, flags | O_NONBLOCK);
*
* @param priv
* Pointer to private data structure.
- * @param dev
- * Pointer to rte_eth_dev structure.
* @param up
* Nonzero for link up, otherwise link down.
*
* 0 on success, errno value on failure.
*/
static int
-priv_dev_set_link(struct priv *priv, struct rte_eth_dev *dev, int up)
+priv_dev_set_link(struct priv *priv, int up)
{
- int err;
-
- if (up) {
- err = priv_set_flags(priv, ~IFF_UP, IFF_UP);
- if (err)
- return err;
- priv_dev_select_tx_function(priv, dev);
- priv_dev_select_rx_function(priv, dev);
- } else {
- err = priv_set_flags(priv, ~IFF_UP, ~IFF_UP);
- if (err)
- return err;
- dev->rx_pkt_burst = removed_rx_burst;
- dev->tx_pkt_burst = removed_tx_burst;
- }
- return 0;
+ return priv_set_flags(priv, ~IFF_UP, up ? IFF_UP : ~IFF_UP);
}
/**
int err;
priv_lock(priv);
- err = priv_dev_set_link(priv, dev, 0);
+ err = priv_dev_set_link(priv, 0);
priv_unlock(priv);
return err;
}
int err;
priv_lock(priv);
- err = priv_dev_set_link(priv, dev, 1);
+ err = priv_dev_set_link(priv, 1);
priv_unlock(priv);
return err;
}
* Pointer to private data structure.
* @param dev
* Pointer to rte_eth_dev structure.
+ *
+ * @return
+ * Pointer to selected Tx burst function.
*/
-void
-priv_dev_select_tx_function(struct priv *priv, struct rte_eth_dev *dev)
+eth_tx_burst_t
+priv_select_tx_function(struct priv *priv, struct rte_eth_dev *dev)
{
+ 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;
+ int tso = !!(tx_offloads & (DEV_TX_OFFLOAD_TCP_TSO |
+ DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
+ DEV_TX_OFFLOAD_GRE_TNL_TSO));
+ int vlan_insert = !!(tx_offloads & DEV_TX_OFFLOAD_VLAN_INSERT);
+
assert(priv != NULL);
- assert(dev != NULL);
- dev->tx_pkt_burst = mlx5_tx_burst;
/* Select appropriate TX function. */
- if (priv->mps == MLX5_MPW_ENHANCED) {
- if (priv_check_vec_tx_support(priv) > 0) {
- if (priv_check_raw_vec_tx_support(priv) > 0)
- dev->tx_pkt_burst = mlx5_tx_burst_raw_vec;
+ if (vlan_insert || tso)
+ return tx_pkt_burst;
+ if (config->mps == MLX5_MPW_ENHANCED) {
+ if (priv_check_vec_tx_support(priv, dev) > 0) {
+ if (priv_check_raw_vec_tx_support(priv, dev) > 0)
+ tx_pkt_burst = mlx5_tx_burst_raw_vec;
else
- dev->tx_pkt_burst = mlx5_tx_burst_vec;
+ tx_pkt_burst = mlx5_tx_burst_vec;
DEBUG("selected Enhanced MPW TX vectorized function");
} else {
- dev->tx_pkt_burst = mlx5_tx_burst_empw;
+ tx_pkt_burst = mlx5_tx_burst_empw;
DEBUG("selected Enhanced MPW TX function");
}
- } else if (priv->mps && priv->txq_inline) {
- dev->tx_pkt_burst = mlx5_tx_burst_mpw_inline;
+ } else if (config->mps && (config->txq_inline > 0)) {
+ tx_pkt_burst = mlx5_tx_burst_mpw_inline;
DEBUG("selected MPW inline TX function");
- } else if (priv->mps) {
- dev->tx_pkt_burst = mlx5_tx_burst_mpw;
+ } else if (config->mps) {
+ tx_pkt_burst = mlx5_tx_burst_mpw;
DEBUG("selected MPW TX function");
}
+ return tx_pkt_burst;
}
/**
* Pointer to private data structure.
* @param dev
* Pointer to rte_eth_dev structure.
+ *
+ * @return
+ * Pointer to selected Rx burst function.
*/
-void
-priv_dev_select_rx_function(struct priv *priv, struct rte_eth_dev *dev)
+eth_rx_burst_t
+priv_select_rx_function(struct priv *priv, __rte_unused struct rte_eth_dev *dev)
{
+ eth_rx_burst_t rx_pkt_burst = mlx5_rx_burst;
+
assert(priv != NULL);
- assert(dev != NULL);
if (priv_check_vec_rx_support(priv) > 0) {
- dev->rx_pkt_burst = mlx5_rx_burst_vec;
+ rx_pkt_burst = mlx5_rx_burst_vec;
DEBUG("selected RX vectorized function");
- } else {
- dev->rx_pkt_burst = mlx5_rx_burst;
}
+ return rx_pkt_burst;
+}
+
+/**
+ * Check if mlx5 device was removed.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ *
+ * @return
+ * 1 when device is removed, otherwise 0.
+ */
+int
+mlx5_is_removed(struct rte_eth_dev *dev)
+{
+ struct ibv_device_attr device_attr;
+ struct priv *priv = dev->data->dev_private;
+
+ if (ibv_query_device(priv->ctx, &device_attr) == EIO)
+ return 1;
+ return 0;
}