]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/spdk/dpdk/drivers/net/mlx5/mlx5_ethdev.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / dpdk / drivers / net / mlx5 / mlx5_ethdev.c
index 34c5b95ee6d20f4fc2c736ab249bf484ffbbc28c..a8a7eceda9d6d79a18aa44f921e1f61305f7a2a4 100644 (file)
@@ -3,8 +3,6 @@
  * Copyright 2015 Mellanox Technologies, Ltd
  */
 
-#define _GNU_SOURCE
-
 #include <stddef.h>
 #include <assert.h>
 #include <inttypes.h>
@@ -130,18 +128,17 @@ struct ethtool_link_settings {
  *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
 int
-mlx5_get_master_ifname(const struct rte_eth_dev *dev,
-                      char (*ifname)[IF_NAMESIZE])
+mlx5_get_master_ifname(const char *ibdev_path, char (*ifname)[IF_NAMESIZE])
 {
-       struct 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(ibdev_path);
        {
-               MKSTR(path, "%s/device/net", priv->ibdev_path);
+               MKSTR(path, "%s/device/net", ibdev_path);
 
                dir = opendir(path);
                if (dir == NULL) {
@@ -161,7 +158,7 @@ mlx5_get_master_ifname(const struct rte_eth_dev *dev,
                        continue;
 
                MKSTR(path, "%s/device/net/%s/%s",
-                     priv->ibdev_path, name,
+                     ibdev_path, name,
                      (dev_type ? "dev_id" : "dev_port"));
 
                file = fopen(path, "rb");
@@ -221,14 +218,19 @@ try_dev_id:
 int
 mlx5_get_ifname(const struct rte_eth_dev *dev, char (*ifname)[IF_NAMESIZE])
 {
-       struct priv *priv = dev->data->dev_private;
-       unsigned int ifindex =
-               priv->nl_socket_rdma >= 0 ?
-               mlx5_nl_ifindex(priv->nl_socket_rdma, priv->ibdev_name) : 0;
+       struct mlx5_priv *priv = dev->data->dev_private;
+       unsigned int ifindex;
 
+       assert(priv);
+       assert(priv->sh);
+       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);
+                       return mlx5_get_master_ifname(priv->sh->ibdev_path,
+                                                     ifname);
                rte_errno = ENXIO;
                return -rte_errno;
        }
@@ -270,16 +272,12 @@ mlx5_ifindex(const struct rte_eth_dev *dev)
  *   Request number to pass to ioctl().
  * @param[out] ifr
  *   Interface request structure output buffer.
- * @param master
- *   When device is a port representor, perform request on master device
- *   instead.
  *
  * @return
  *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
 int
-mlx5_ifreq(const struct rte_eth_dev *dev, int req, struct ifreq *ifr,
-          int master)
+mlx5_ifreq(const struct rte_eth_dev *dev, int req, struct ifreq *ifr)
 {
        int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
        int ret = 0;
@@ -288,10 +286,7 @@ mlx5_ifreq(const struct rte_eth_dev *dev, int req, struct ifreq *ifr,
                rte_errno = errno;
                return -rte_errno;
        }
-       if (master)
-               ret = mlx5_get_master_ifname(dev, &ifr->ifr_name);
-       else
-               ret = mlx5_get_ifname(dev, &ifr->ifr_name);
+       ret = mlx5_get_ifname(dev, &ifr->ifr_name);
        if (ret)
                goto error;
        ret = ioctl(sock, req, ifr);
@@ -321,7 +316,7 @@ int
 mlx5_get_mtu(struct rte_eth_dev *dev, uint16_t *mtu)
 {
        struct ifreq request;
-       int ret = mlx5_ifreq(dev, SIOCGIFMTU, &request, 0);
+       int ret = mlx5_ifreq(dev, SIOCGIFMTU, &request);
 
        if (ret)
                return ret;
@@ -345,7 +340,7 @@ mlx5_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
 {
        struct ifreq request = { .ifr_mtu = mtu, };
 
-       return mlx5_ifreq(dev, SIOCSIFMTU, &request, 0);
+       return mlx5_ifreq(dev, SIOCSIFMTU, &request);
 }
 
 /**
@@ -365,13 +360,13 @@ int
 mlx5_set_flags(struct rte_eth_dev *dev, unsigned int keep, unsigned int flags)
 {
        struct ifreq request;
-       int ret = mlx5_ifreq(dev, SIOCGIFFLAGS, &request, 0);
+       int ret = mlx5_ifreq(dev, SIOCGIFFLAGS, &request);
 
        if (ret)
                return ret;
        request.ifr_flags &= keep;
        request.ifr_flags |= flags & ~keep;
-       return mlx5_ifreq(dev, SIOCSIFFLAGS, &request, 0);
+       return mlx5_ifreq(dev, SIOCSIFFLAGS, &request);
 }
 
 /**
@@ -386,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;
@@ -433,28 +428,35 @@ mlx5_dev_configure(struct rte_eth_dev *dev)
                rte_errno = EINVAL;
                return -rte_errno;
        }
-       if (rxqs_n == priv->rxqs_n)
-               return 0;
-       DRV_LOG(INFO, "port %u Rx queues number update: %u -> %u",
-               dev->data->port_id, priv->rxqs_n, rxqs_n);
-       priv->rxqs_n = rxqs_n;
-       /* If the requested number of RX queues is not a power of two, use the
-        * 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->config.ind_table_max_size :
-                                    rxqs_n));
-       ret = mlx5_rss_reta_index_resize(dev, reta_idx_n);
+       if (rxqs_n != priv->rxqs_n) {
+               DRV_LOG(INFO, "port %u Rx queues number update: %u -> %u",
+                       dev->data->port_id, priv->rxqs_n, rxqs_n);
+               priv->rxqs_n = rxqs_n;
+               /*
+                * If the requested number of RX queues is not a power of two,
+                * use the 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->config.ind_table_max_size :
+                                            rxqs_n));
+               ret = mlx5_rss_reta_index_resize(dev, reta_idx_n);
+               if (ret)
+                       return ret;
+               /*
+                * When the number of RX queues is not a power of two,
+                * the remaining table entries are padded with reused WQs
+                * and hashes are not spread uniformly.
+                */
+               for (i = 0, j = 0; (i != reta_idx_n); ++i) {
+                       (*priv->reta_idx)[i] = j;
+                       if (++j == rxqs_n)
+                               j = 0;
+               }
+       }
+       ret = mlx5_proc_priv_init(dev);
        if (ret)
                return ret;
-       /* When the number of RX queues is not a power of two, the remaining
-        * table entries are padded with reused WQs and hashes are not spread
-        * uniformly. */
-       for (i = 0, j = 0; (i != reta_idx_n); ++i) {
-               (*priv->reta_idx)[i] = j;
-               if (++j == rxqs_n)
-                       j = 0;
-       }
        return 0;
 }
 
@@ -469,7 +471,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;
@@ -508,7 +510,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];
@@ -520,8 +522,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;
@@ -549,7 +551,7 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
 
                i = RTE_MIN(mlx5_dev_to_port_id(dev->device, port_id, i), i);
                while (i--) {
-                       struct priv *opriv =
+                       struct mlx5_priv *opriv =
                                rte_eth_devices[port_id[i]].data->dev_private;
 
                        if (!opriv ||
@@ -566,6 +568,32 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
        }
 }
 
+/**
+ * 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;
+}
+
 /**
  * Get supported packet types.
  *
@@ -603,6 +631,36 @@ mlx5_dev_supported_ptypes_get(struct rte_eth_dev *dev)
        return NULL;
 }
 
+/**
+ * Retrieve the master device for representor in the same switch domain.
+ *
+ * @param dev
+ *   Pointer to representor Ethernet device structure.
+ *
+ * @return
+ *   Master device structure  on success, NULL otherwise.
+ */
+
+static struct rte_eth_dev *
+mlx5_find_master_dev(struct rte_eth_dev *dev)
+{
+       struct mlx5_priv *priv;
+       uint16_t port_id;
+       uint16_t domain_id;
+
+       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)
+                       return &rte_eth_devices[port_id];
+       }
+       return NULL;
+}
+
 /**
  * DPDK callback to retrieve physical link information.
  *
@@ -618,7 +676,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. */
        };
@@ -627,22 +685,49 @@ mlx5_link_update_unlocked_gset(struct rte_eth_dev *dev,
        int link_speed = 0;
        int ret;
 
-       ret = mlx5_ifreq(dev, SIOCGIFFLAGS, &ifr, 1);
+       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;
        }
-       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;
-       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr, 1);
+       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,
-                       "port %u ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s",
-                       dev->data->port_id, strerror(rte_errno));
-               return ret;
+               if (ret == -ENOTSUP && priv->representor) {
+                       struct rte_eth_dev *master;
+
+                       /*
+                        * 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 *)&edata,
+                               };
+                               ret = mlx5_ifreq(master, SIOCETHTOOL, &ifr);
+                       }
+               }
+               if (ret) {
+                       DRV_LOG(WARNING,
+                               "port %u ioctl(SIOCETHTOOL,"
+                               " ETHTOOL_GSET) failed: %s",
+                               dev->data->port_id, strerror(rte_errno));
+                       return ret;
+               }
        }
        link_speed = ethtool_cmd_speed(&edata);
        if (link_speed == -1)
@@ -666,8 +751,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;
        }
@@ -691,30 +776,56 @@ 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;
+       struct rte_eth_dev *master = NULL;
        uint64_t sc;
        int ret;
 
-       ret = mlx5_ifreq(dev, SIOCGIFFLAGS, &ifr, 1);
+       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;
        }
-       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;
-       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr, 1);
+       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,
-                       "port %u ioctl(SIOCETHTOOL, ETHTOOL_GLINKSETTINGS)"
-                       " failed: %s",
-                       dev->data->port_id, strerror(rte_errno));
-               return 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;
 
@@ -725,11 +836,11 @@ mlx5_link_update_unlocked_gs(struct rte_eth_dev *dev,
 
        *ecmd = gcmd;
        ifr.ifr_data = (void *)ecmd;
-       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr, 1);
+       ret = mlx5_ifreq(master ? master : dev, SIOCETHTOOL, &ifr);
        if (ret) {
                DRV_LOG(DEBUG,
-                       "port %u ioctl(SIOCETHTOOL, ETHTOOL_GLINKSETTINGS)"
-                       " failed: %s",
+                       "port %u ioctl(SIOCETHTOOL,"
+                       "ETHTOOL_GLINKSETTINGS) failed: %s",
                        dev->data->port_id, strerror(rte_errno));
                return ret;
        }
@@ -775,8 +886,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;
        }
@@ -843,7 +954,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;
 
@@ -888,7 +999,7 @@ mlx5_dev_get_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
        int ret;
 
        ifr.ifr_data = (void *)&ethpause;
-       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr, 1);
+       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
        if (ret) {
                DRV_LOG(WARNING,
                        "port %u ioctl(SIOCETHTOOL, ETHTOOL_GPAUSEPARAM) failed:"
@@ -941,7 +1052,7 @@ mlx5_dev_set_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
                ethpause.tx_pause = 1;
        else
                ethpause.tx_pause = 0;
-       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr, 0);
+       ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
        if (ret) {
                DRV_LOG(WARNING,
                        "port %u ioctl(SIOCETHTOOL, ETHTOOL_SPAUSEPARAM)"
@@ -1005,80 +1116,204 @@ mlx5_ibv_device_to_pci_addr(const struct ibv_device *device,
 }
 
 /**
- * Device status handler.
+ * Handle asynchronous removal event for entire multiport device.
  *
- * @param dev
- *   Pointer to Ethernet device.
- * @param events
- *   Pointer to event flags holder.
+ * @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.
  *
- * @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;
-               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
+               /* 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,
-                               "port %u event type %d on not handled",
-                               dev->data->port_id, event.event_type);
+                               "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);
        }
-       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);
 }
 
 /**
@@ -1090,19 +1325,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);
 }
 
 /**
@@ -1114,38 +1337,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);
 }
 
 /**
@@ -1190,7 +1382,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;
@@ -1274,9 +1466,9 @@ 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;
 }
@@ -1303,14 +1495,7 @@ mlx5_dev_to_port_id(const struct rte_device *dev, uint16_t *port_list,
        uint16_t id;
        unsigned int n = 0;
 
-       RTE_ETH_FOREACH_DEV(id) {
-               struct rte_eth_dev *ldev = &rte_eth_devices[id];
-
-               if (!ldev->device ||
-                   !ldev->device->driver ||
-                   strcmp(ldev->device->driver->name, MLX5_DRIVER_NAME) ||
-                   ldev->device != dev)
-                       continue;
+       RTE_ETH_FOREACH_DEV_OF(id, dev) {
                if (n < port_list_n)
                        port_list[n] = id;
                n++;
@@ -1318,6 +1503,47 @@ mlx5_dev_to_port_id(const struct rte_device *dev, uint16_t *port_list,
        return n;
 }
 
+/**
+ * Get the E-Switch domain id this port belongs to.
+ *
+ * @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
+ *   0 on success, a negative errno value 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 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;
+       }
+       if (es_domain_id)
+               *es_domain_id = priv->domain_id;
+       if (es_port_id)
+               *es_port_id = priv->vport_id;
+       return 0;
+}
+
 /**
  * Get switch information associated with network interface.
  *
@@ -1333,11 +1559,20 @@ 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, };
-       bool port_name_set = false;
+       struct mlx5_switch_info data = {
+               .master = 0,
+               .representor = 0,
+               .name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET,
+               .port_name = 0,
+               .switch_id = 0,
+       };
+       DIR *dir;
        bool port_switch_id_set = false;
+       bool device_dir = false;
        char c;
+       int ret;
 
        if (!if_indextoname(ifindex, ifname)) {
                rte_errno = errno;
@@ -1348,13 +1583,15 @@ mlx5_sysfs_switch_info(unsigned int ifindex, struct mlx5_switch_info *info)
              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) {
-               port_name_set =
-                       fscanf(file, "%d%c", &data.port_name, &c) == 2 &&
-                       c == '\n';
+               ret = fscanf(file, "%s", port_name);
                fclose(file);
+               if (ret == 1)
+                       mlx5_translate_port_name(port_name, &data);
        }
        file = fopen(phys_switch_id, "rb");
        if (file == NULL) {
@@ -1365,8 +1602,175 @@ mlx5_sysfs_switch_info(unsigned int ifindex, struct mlx5_switch_info *info)
                fscanf(file, "%" SCNx64 "%c", &data.switch_id, &c) == 2 &&
                c == '\n';
        fclose(file);
-       data.master = port_switch_id_set && !port_name_set;
-       data.representor = port_switch_id_set && port_name_set;
+       dir = opendir(pci_device);
+       if (dir != NULL) {
+               closedir(dir);
+               device_dir = true;
+       }
+       if (port_switch_id_set) {
+               /* We have some E-Switch configuration. */
+               mlx5_sysfs_check_switch_info(device_dir, &data);
+       }
        *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;
 }
+
+/**
+ * Analyze gathered port parameters via Netlink to recognize master
+ * and representor devices for E-Switch configuration.
+ *
+ * @param[in] num_vf_set
+ *   flag of presence of number of VFs port attribute.
+ * @param[inout] switch_info
+ *   Port information, including port name as a number and port name
+ *   type if recognized
+ *
+ * @return
+ *   master and representor flags are set in switch_info according to
+ *   recognized parameters (if any).
+ */
+void
+mlx5_nl_check_switch_info(bool num_vf_set,
+                         struct mlx5_switch_info *switch_info)
+{
+       switch (switch_info->name_type) {
+       case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN:
+               /*
+                * Name is not recognized, assume the master,
+                * check the number of VFs key presence.
+                */
+               switch_info->master = num_vf_set;
+               break;
+       case MLX5_PHYS_PORT_NAME_TYPE_NOTSET:
+               /*
+                * Name is not set, this assumes the legacy naming
+                * schema for master, just check if there is a
+                * number of VFs key.
+                */
+               switch_info->master = num_vf_set;
+               break;
+       case MLX5_PHYS_PORT_NAME_TYPE_UPLINK:
+               /* New uplink naming schema recognized. */
+               switch_info->master = 1;
+               break;
+       case MLX5_PHYS_PORT_NAME_TYPE_LEGACY:
+               /* Legacy representors naming schema. */
+               switch_info->representor = !num_vf_set;
+               break;
+       case MLX5_PHYS_PORT_NAME_TYPE_PFVF:
+               /* New representors naming schema. */
+               switch_info->representor = 1;
+               break;
+       }
+}
+
+/**
+ * Analyze gathered port parameters via sysfs to recognize master
+ * and representor devices for E-Switch configuration.
+ *
+ * @param[in] device_dir
+ *   flag of presence of "device" directory under port device key.
+ * @param[inout] switch_info
+ *   Port information, including port name as a number and port name
+ *   type if recognized
+ *
+ * @return
+ *   master and representor flags are set in switch_info according to
+ *   recognized parameters (if any).
+ */
+void
+mlx5_sysfs_check_switch_info(bool device_dir,
+                            struct mlx5_switch_info *switch_info)
+{
+       switch (switch_info->name_type) {
+       case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN:
+               /*
+                * Name is not recognized, assume the master,
+                * check the device directory presence.
+                */
+               switch_info->master = device_dir;
+               break;
+       case MLX5_PHYS_PORT_NAME_TYPE_NOTSET:
+               /*
+                * Name is not set, this assumes the legacy naming
+                * schema for master, just check if there is
+                * a device directory.
+                */
+               switch_info->master = device_dir;
+               break;
+       case MLX5_PHYS_PORT_NAME_TYPE_UPLINK:
+               /* New uplink naming schema recognized. */
+               switch_info->master = 1;
+               break;
+       case MLX5_PHYS_PORT_NAME_TYPE_LEGACY:
+               /* Legacy representors naming schema. */
+               switch_info->representor = !device_dir;
+               break;
+       case MLX5_PHYS_PORT_NAME_TYPE_PFVF:
+               /* New representors naming schema. */
+               switch_info->representor = 1;
+               break;
+       }
+}
+
+/**
+ * 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 and port name
+ *   type if recognized
+ *
+ * @return
+ *   port_name field set according to recognized name format.
+ */
+void
+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;
+       int sc_items;
+
+       /*
+        * Check for port-name as a string of the form pf0vf0
+        * (support kernel ver >= 5.0 or OFED ver >= 4.6).
+        */
+       sc_items = sscanf(port_name_in, "%c%c%d%c%c%d",
+                         &pf_c1, &pf_c2, &port_info_out->pf_num,
+                         &vf_c1, &vf_c2, &port_info_out->port_name);
+       if (sc_items == 6 &&
+           pf_c1 == 'p' && pf_c2 == 'f' &&
+           vf_c1 == 'v' && vf_c2 == 'f') {
+               port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_PFVF;
+               return;
+       }
+       /*
+        * Check for port-name as a string of the form p0
+        * (support kernel ver >= 5.0, or OFED ver >= 4.6).
+        */
+       sc_items = sscanf(port_name_in, "%c%d",
+                         &pf_c1, &port_info_out->port_name);
+       if (sc_items == 2 && pf_c1 == 'p') {
+               port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_UPLINK;
+               return;
+       }
+       /* 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_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_LEGACY;
+               return;
+       }
+       port_info_out->name_type = MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN;
+       return;
+}