net: add rte prefix to ether structures
[dpdk.git] / drivers / net / mlx5 / mlx5.c
index 6d56354..2798e0e 100644 (file)
 /* Allow L3 VXLAN flow creation. */
 #define MLX5_L3_VXLAN_EN "l3_vxlan_en"
 
+/* Activate DV E-Switch flow steering. */
+#define MLX5_DV_ESW_EN "dv_esw_en"
+
 /* Activate DV flow steering. */
 #define MLX5_DV_FLOW_EN "dv_flow_en"
 
@@ -144,6 +147,7 @@ struct mlx5_dev_spawn_data {
        struct mlx5_switch_info info; /**< Switch information. */
        struct ibv_device *ibv_dev; /**< Associated IB device. */
        struct rte_eth_dev *eth_dev; /**< Associated Ethernet device. */
+       struct rte_pci_device *pci_dev; /**< Backend PCI device. */
 };
 
 static LIST_HEAD(, mlx5_ibv_shared) mlx5_ibv_list = LIST_HEAD_INITIALIZER();
@@ -155,7 +159,7 @@ static pthread_mutex_t mlx5_ibv_list_mutex = PTHREAD_MUTEX_INITIALIZER;
  * port dedicated IB device, the context will be used by only given
  * port due to unification.
  *
- * Routine first searches the context for the spesified IB device name,
+ * Routine first searches the context for the specified IB device name,
  * if found the shared context assumed and reference counter is incremented.
  * If no context found the new one is created and initialized with specified
  * IB device context and parameters.
@@ -185,7 +189,7 @@ mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn)
                        goto exit;
                }
        }
-       /* No device found, we have to create new sharted context. */
+       /* No device found, we have to create new shared context. */
        assert(spawn->max_port);
        sh = rte_zmalloc("ethdev shared ib context",
                         sizeof(struct mlx5_ibv_shared) +
@@ -222,6 +226,7 @@ mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn)
                sizeof(sh->ibdev_name));
        strncpy(sh->ibdev_path, sh->ctx->device->ibdev_path,
                sizeof(sh->ibdev_path));
+       sh->pci_dev = spawn->pci_dev;
        pthread_mutex_init(&sh->intr_mutex, NULL);
        /*
         * Setting port_id to max unallowed value means
@@ -236,6 +241,22 @@ mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn)
                err = ENOMEM;
                goto error;
        }
+       /*
+        * Once the device is added to the list of memory event
+        * callback, its global MR cache table cannot be expanded
+        * on the fly because of deadlock. If it overflows, lookup
+        * should be done by searching MR list linearly, which is slow.
+        *
+        * At this point the device is not added to the memory
+        * event list yet, context is just being created.
+        */
+       err = mlx5_mr_btree_init(&sh->mr.cache,
+                                MLX5_MR_BTREE_CACHE_N * 2,
+                                sh->pci_dev->device.numa_node);
+       if (err) {
+               err = rte_errno;
+               goto error;
+       }
        LIST_INSERT_HEAD(&mlx5_ibv_list, sh, next);
 exit:
        pthread_mutex_unlock(&mlx5_ibv_list_mutex);
@@ -283,6 +304,8 @@ mlx5_free_shared_ibctx(struct mlx5_ibv_shared *sh)
        assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
        if (--sh->refcnt)
                goto exit;
+       /* Release created Memory Regions. */
+       mlx5_mr_release(sh);
        LIST_REMOVE(sh, next);
        /*
         *  Ensure there is no async event handler installed.
@@ -305,7 +328,7 @@ exit:
 /**
  * Initialize DR related data within private structure.
  * Routine checks the reference counter and does actual
- * resources creation/iniialization only if counter is zero.
+ * resources creation/initialization only if counter is zero.
  *
  * @param[in] priv
  *   Pointer to the private device data structure.
@@ -319,7 +342,7 @@ mlx5_alloc_shared_dr(struct mlx5_priv *priv)
 #ifdef HAVE_MLX5DV_DR
        struct mlx5_ibv_shared *sh = priv->sh;
        int err = 0;
-       void *ns;
+       void *domain;
 
        assert(sh);
        if (sh->dv_refcnt) {
@@ -329,33 +352,57 @@ mlx5_alloc_shared_dr(struct mlx5_priv *priv)
                return 0;
        }
        /* Reference counter is zero, we should initialize structures. */
-       ns = mlx5dv_dr_create_ns(sh->ctx, MLX5DV_DR_NS_DOMAIN_INGRESS_BYPASS);
-       if (!ns) {
-               DRV_LOG(ERR, "ingress mlx5dv_dr_create_ns failed");
+       domain = mlx5_glue->dr_create_domain(sh->ctx,
+                                            MLX5DV_DR_DOMAIN_TYPE_NIC_RX);
+       if (!domain) {
+               DRV_LOG(ERR, "ingress mlx5dv_dr_create_domain failed");
                err = errno;
                goto error;
        }
-       priv->rx_ns = ns;
-       ns = mlx5dv_dr_create_ns(sh->ctx, MLX5DV_DR_NS_DOMAIN_EGRESS_BYPASS);
-       if (!ns) {
-               DRV_LOG(ERR, "egress mlx5dv_dr_create_ns failed");
+       sh->rx_domain = domain;
+       domain = mlx5_glue->dr_create_domain(sh->ctx,
+                                            MLX5DV_DR_DOMAIN_TYPE_NIC_TX);
+       if (!domain) {
+               DRV_LOG(ERR, "egress mlx5dv_dr_create_domain failed");
                err = errno;
                goto error;
        }
-       priv->tx_ns = ns;
+       pthread_mutex_init(&sh->dv_mutex, NULL);
+       sh->tx_domain = domain;
+#ifdef HAVE_MLX5DV_DR_ESWITCH
+       if (priv->config.dv_esw_en) {
+               domain  = mlx5_glue->dr_create_domain
+                       (sh->ctx, MLX5DV_DR_DOMAIN_TYPE_FDB);
+               if (!domain) {
+                       DRV_LOG(ERR, "FDB mlx5dv_dr_create_domain failed");
+                       err = errno;
+                       goto error;
+               }
+               sh->fdb_domain = domain;
+               sh->esw_drop_action = mlx5_glue->dr_create_flow_action_drop();
+       }
+#endif
        sh->dv_refcnt++;
        priv->dr_shared = 1;
        return 0;
 
 error:
        /* Rollback the created objects. */
-       if (priv->rx_ns) {
-               mlx5dv_dr_destroy_ns(priv->rx_ns);
-               priv->rx_ns = NULL;
+       if (sh->rx_domain) {
+               mlx5_glue->dr_destroy_domain(sh->rx_domain);
+               sh->rx_domain = NULL;
+       }
+       if (sh->tx_domain) {
+               mlx5_glue->dr_destroy_domain(sh->tx_domain);
+               sh->tx_domain = NULL;
+       }
+       if (sh->fdb_domain) {
+               mlx5_glue->dr_destroy_domain(sh->fdb_domain);
+               sh->fdb_domain = NULL;
        }
-       if (priv->tx_ns) {
-               mlx5dv_dr_destroy_ns(priv->tx_ns);
-               priv->tx_ns = NULL;
+       if (sh->esw_drop_action) {
+               mlx5_glue->destroy_flow_action(sh->esw_drop_action);
+               sh->esw_drop_action = NULL;
        }
        return err;
 #else
@@ -384,14 +431,25 @@ mlx5_free_shared_dr(struct mlx5_priv *priv)
        assert(sh->dv_refcnt);
        if (sh->dv_refcnt && --sh->dv_refcnt)
                return;
-       if (priv->rx_ns) {
-               mlx5dv_dr_destroy_ns(priv->rx_ns);
-               priv->rx_ns = NULL;
+       if (sh->rx_domain) {
+               mlx5_glue->dr_destroy_domain(sh->rx_domain);
+               sh->rx_domain = NULL;
        }
-       if (priv->tx_ns) {
-               mlx5dv_dr_destroy_ns(priv->tx_ns);
-               priv->tx_ns = NULL;
+       if (sh->tx_domain) {
+               mlx5_glue->dr_destroy_domain(sh->tx_domain);
+               sh->tx_domain = NULL;
        }
+#ifdef HAVE_MLX5DV_DR_ESWITCH
+       if (sh->fdb_domain) {
+               mlx5_glue->dr_destroy_domain(sh->fdb_domain);
+               sh->fdb_domain = NULL;
+       }
+       if (sh->esw_drop_action) {
+               mlx5_glue->destroy_flow_action(sh->esw_drop_action);
+               sh->esw_drop_action = NULL;
+       }
+#endif
+       pthread_mutex_destroy(&sh->dv_mutex);
 #else
        (void)priv;
 #endif
@@ -446,30 +504,6 @@ error:
        return ret;
 }
 
-/**
- * Uninitialize shared data between primary and secondary process.
- *
- * The pointer of secondary process is dereferenced and primary process frees
- * the memzone.
- */
-static void
-mlx5_uninit_shared_data(void)
-{
-       const struct rte_memzone *mz;
-
-       rte_spinlock_lock(&mlx5_shared_data_lock);
-       if (mlx5_shared_data) {
-               if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
-                       mz = rte_memzone_lookup(MZ_MLX5_PMD_SHARED_DATA);
-                       rte_memzone_free(mz);
-               } else {
-                       memset(&mlx5_local_data, 0, sizeof(mlx5_local_data));
-               }
-               mlx5_shared_data = NULL;
-       }
-       rte_spinlock_unlock(&mlx5_shared_data_lock);
-}
-
 /**
  * Retrieve integer value from environment variable.
  *
@@ -543,6 +577,54 @@ mlx5_free_verbs_buf(void *ptr, void *data __rte_unused)
        rte_free(ptr);
 }
 
+/**
+ * Initialize process private data structure.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_proc_priv_init(struct rte_eth_dev *dev)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_proc_priv *ppriv;
+       size_t ppriv_size;
+
+       /*
+        * UAR register table follows the process private structure. BlueFlame
+        * registers for Tx queues are stored in the table.
+        */
+       ppriv_size =
+               sizeof(struct mlx5_proc_priv) + priv->txqs_n * sizeof(void *);
+       ppriv = rte_malloc_socket("mlx5_proc_priv", ppriv_size,
+                                 RTE_CACHE_LINE_SIZE, dev->device->numa_node);
+       if (!ppriv) {
+               rte_errno = ENOMEM;
+               return -rte_errno;
+       }
+       ppriv->uar_table_sz = ppriv_size;
+       dev->process_private = ppriv;
+       return 0;
+}
+
+/**
+ * Un-initialize process private data structure.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ */
+static void
+mlx5_proc_priv_uninit(struct rte_eth_dev *dev)
+{
+       if (!dev->process_private)
+               return;
+       rte_free(dev->process_private);
+       dev->process_private = NULL;
+}
+
 /**
  * DPDK callback to close the device.
  *
@@ -587,13 +669,14 @@ mlx5_dev_close(struct rte_eth_dev *dev)
                priv->txqs_n = 0;
                priv->txqs = NULL;
        }
+       mlx5_proc_priv_uninit(dev);
        mlx5_mprq_free_mp(dev);
-       mlx5_mr_release(dev);
+       /* Remove from memory callback device list. */
+       rte_rwlock_write_lock(&mlx5_shared_data->mem_event_rwlock);
        assert(priv->sh);
+       LIST_REMOVE(priv->sh, mem_event_cb);
+       rte_rwlock_write_unlock(&mlx5_shared_data->mem_event_rwlock);
        mlx5_free_shared_dr(priv);
-       if (priv->sh)
-               mlx5_free_shared_ibctx(priv->sh);
-       priv->sh = NULL;
        if (priv->rss_conf.rss_key != NULL)
                rte_free(priv->rss_conf.rss_key);
        if (priv->reta_idx != NULL)
@@ -606,6 +689,16 @@ mlx5_dev_close(struct rte_eth_dev *dev)
                close(priv->nl_socket_rdma);
        if (priv->tcf_context)
                mlx5_flow_tcf_context_destroy(priv->tcf_context);
+       if (priv->sh) {
+               /*
+                * Free the shared context in last turn, because the cleanup
+                * routines above may use some shared fields, like
+                * mlx5_nl_mac_addr_flush() uses ibdev_path for retrieveing
+                * ifindex if Netlink fails.
+                */
+               mlx5_free_shared_ibctx(priv->sh);
+               priv->sh = NULL;
+       }
        ret = mlx5_hrxq_ibv_verify(dev);
        if (ret)
                DRV_LOG(WARNING, "port %u some hash Rx queue still remain",
@@ -827,6 +920,8 @@ mlx5_args_check(const char *key, const char *val, void *opaque)
                config->l3_vxlan_en = !!tmp;
        } else if (strcmp(MLX5_VF_NL_EN, key) == 0) {
                config->vf_nl_en = !!tmp;
+       } else if (strcmp(MLX5_DV_ESW_EN, key) == 0) {
+               config->dv_esw_en = !!tmp;
        } else if (strcmp(MLX5_DV_FLOW_EN, key) == 0) {
                config->dv_flow_en = !!tmp;
        } else if (strcmp(MLX5_MR_EXT_MEMSEG_EN, key) == 0) {
@@ -871,6 +966,7 @@ mlx5_args(struct mlx5_dev_config *config, struct rte_devargs *devargs)
                MLX5_RX_VEC_EN,
                MLX5_L3_VXLAN_EN,
                MLX5_VF_NL_EN,
+               MLX5_DV_ESW_EN,
                MLX5_DV_FLOW_EN,
                MLX5_MR_EXT_MEMSEG_EN,
                MLX5_REPRESENTOR,
@@ -904,132 +1000,6 @@ mlx5_args(struct mlx5_dev_config *config, struct rte_devargs *devargs)
 
 static struct rte_pci_driver mlx5_driver;
 
-static int
-find_lower_va_bound(const struct rte_memseg_list *msl,
-               const struct rte_memseg *ms, void *arg)
-{
-       void **addr = arg;
-
-       if (msl->external)
-               return 0;
-       if (*addr == NULL)
-               *addr = ms->addr;
-       else
-               *addr = RTE_MIN(*addr, ms->addr);
-
-       return 0;
-}
-
-/**
- * Reserve UAR address space for primary process.
- *
- * Process local resource is used by both primary and secondary to avoid
- * duplicate reservation. The space has to be available on both primary and
- * secondary process, TXQ UAR maps to this area using fixed mmap w/o double
- * check.
- *
- * @return
- *   0 on success, a negative errno value otherwise and rte_errno is set.
- */
-static int
-mlx5_uar_init_primary(void)
-{
-       struct mlx5_shared_data *sd = mlx5_shared_data;
-       void *addr = (void *)0;
-
-       if (sd->uar_base)
-               return 0;
-       /* find out lower bound of hugepage segments */
-       rte_memseg_walk(find_lower_va_bound, &addr);
-       /* keep distance to hugepages to minimize potential conflicts. */
-       addr = RTE_PTR_SUB(addr, (uintptr_t)(MLX5_UAR_OFFSET + MLX5_UAR_SIZE));
-       /* anonymous mmap, no real memory consumption. */
-       addr = mmap(addr, MLX5_UAR_SIZE,
-                   PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-       if (addr == MAP_FAILED) {
-               DRV_LOG(ERR,
-                       "Failed to reserve UAR address space, please"
-                       " adjust MLX5_UAR_SIZE or try --base-virtaddr");
-               rte_errno = ENOMEM;
-               return -rte_errno;
-       }
-       /* Accept either same addr or a new addr returned from mmap if target
-        * range occupied.
-        */
-       DRV_LOG(INFO, "Reserved UAR address space: %p", addr);
-       sd->uar_base = addr; /* for primary and secondary UAR re-mmap. */
-       return 0;
-}
-
-/**
- * Unmap UAR address space reserved for primary process.
- */
-static void
-mlx5_uar_uninit_primary(void)
-{
-       struct mlx5_shared_data *sd = mlx5_shared_data;
-
-       if (!sd->uar_base)
-               return;
-       munmap(sd->uar_base, MLX5_UAR_SIZE);
-       sd->uar_base = NULL;
-}
-
-/**
- * Reserve UAR address space for secondary process, align with primary process.
- *
- * @return
- *   0 on success, a negative errno value otherwise and rte_errno is set.
- */
-static int
-mlx5_uar_init_secondary(void)
-{
-       struct mlx5_shared_data *sd = mlx5_shared_data;
-       struct mlx5_local_data *ld = &mlx5_local_data;
-       void *addr;
-
-       if (ld->uar_base) { /* Already reserved. */
-               assert(sd->uar_base == ld->uar_base);
-               return 0;
-       }
-       assert(sd->uar_base);
-       /* anonymous mmap, no real memory consumption. */
-       addr = mmap(sd->uar_base, MLX5_UAR_SIZE,
-                   PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-       if (addr == MAP_FAILED) {
-               DRV_LOG(ERR, "UAR mmap failed: %p size: %llu",
-                       sd->uar_base, MLX5_UAR_SIZE);
-               rte_errno = ENXIO;
-               return -rte_errno;
-       }
-       if (sd->uar_base != addr) {
-               DRV_LOG(ERR,
-                       "UAR address %p size %llu occupied, please"
-                       " adjust MLX5_UAR_OFFSET or try EAL parameter"
-                       " --base-virtaddr",
-                       sd->uar_base, MLX5_UAR_SIZE);
-               rte_errno = ENXIO;
-               return -rte_errno;
-       }
-       ld->uar_base = addr;
-       DRV_LOG(INFO, "Reserved UAR address space: %p", addr);
-       return 0;
-}
-
-/**
- * Unmap UAR address space reserved for secondary process.
- */
-static void
-mlx5_uar_uninit_secondary(void)
-{
-       struct mlx5_local_data *ld = &mlx5_local_data;
-
-       if (!ld->uar_base)
-               return;
-       munmap(ld->uar_base, MLX5_UAR_SIZE);
-       ld->uar_base = NULL;
-}
-
 /**
  * PMD global initialization.
  *
@@ -1045,7 +1015,6 @@ mlx5_init_once(void)
 {
        struct mlx5_shared_data *sd;
        struct mlx5_local_data *ld = &mlx5_local_data;
-       int ret;
 
        if (mlx5_init_shared_data())
                return -rte_errno;
@@ -1061,18 +1030,12 @@ mlx5_init_once(void)
                rte_mem_event_callback_register("MLX5_MEM_EVENT_CB",
                                                mlx5_mr_mem_event_cb, NULL);
                mlx5_mp_init_primary();
-               ret = mlx5_uar_init_primary();
-               if (ret)
-                       goto error;
                sd->init_done = true;
                break;
        case RTE_PROC_SECONDARY:
                if (ld->init_done)
                        break;
                mlx5_mp_init_secondary();
-               ret = mlx5_uar_init_secondary();
-               if (ret)
-                       goto error;
                ++sd->secondary_cnt;
                ld->init_done = true;
                break;
@@ -1081,23 +1044,6 @@ mlx5_init_once(void)
        }
        rte_spinlock_unlock(&sd->lock);
        return 0;
-error:
-       switch (rte_eal_process_type()) {
-       case RTE_PROC_PRIMARY:
-               mlx5_uar_uninit_primary();
-               mlx5_mp_uninit_primary();
-               rte_mem_event_callback_unregister("MLX5_MEM_EVENT_CB", NULL);
-               break;
-       case RTE_PROC_SECONDARY:
-               mlx5_uar_uninit_secondary();
-               mlx5_mp_uninit_secondary();
-               break;
-       default:
-               break;
-       }
-       rte_spinlock_unlock(&sd->lock);
-       mlx5_uninit_shared_data();
-       return -rte_errno;
 }
 
 /**
@@ -1141,7 +1087,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
        unsigned int mprq_max_stride_size_n = 0;
        unsigned int mprq_min_stride_num_n = 0;
        unsigned int mprq_max_stride_num_n = 0;
-       struct ether_addr mac;
+       struct rte_ether_addr mac;
        char name[RTE_ETH_NAME_MAX_LEN];
        int own_domain_id = 0;
        uint16_t port_id;
@@ -1188,12 +1134,15 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
                }
                eth_dev->device = dpdk_dev;
                eth_dev->dev_ops = &mlx5_dev_sec_ops;
+               err = mlx5_proc_priv_init(eth_dev);
+               if (err)
+                       return NULL;
                /* Receive command fd from primary process */
                err = mlx5_mp_req_verbs_cmd_fd(eth_dev);
                if (err < 0)
                        return NULL;
                /* Remap UAR for Tx queues. */
-               err = mlx5_tx_uar_remap(eth_dev, err);
+               err = mlx5_tx_uar_init_secondary(eth_dev, err);
                if (err)
                        return NULL;
                /*
@@ -1351,7 +1300,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
         * Currently we support single E-Switch per PF configurations
         * only and vport_id field contains the vport index for
         * associated VF, which is deduced from representor port name.
-        * For exapmple, let's have the IB device port 10, it has
+        * For example, let's have the IB device port 10, it has
         * attached network device eth0, which has port name attribute
         * pf0vf2, we can deduce the VF number as 2, and set vport index
         * as 3 (2+1). This assigning schema should be changed if the
@@ -1571,11 +1520,6 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
                        priv->tcf_context = NULL;
                }
        }
-       if (config.dv_flow_en) {
-               err = mlx5_alloc_shared_dr(priv);
-               if (err)
-                       goto error;
-       }
        TAILQ_INIT(&priv->flows);
        TAILQ_INIT(&priv->ctrl_flows);
        /* Hint libmlx5 to use PMD allocator for data plane resources */
@@ -1593,12 +1537,33 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
        mlx5_set_link_up(eth_dev);
        /*
         * Even though the interrupt handler is not installed yet,
-        * interrupts will still trigger on the asyn_fd from
+        * interrupts will still trigger on the async_fd from
         * Verbs context returned by ibv_open_device().
         */
        mlx5_link_update(eth_dev, 0);
+#ifdef HAVE_IBV_DEVX_OBJ
+       if (config.devx) {
+               err = mlx5_devx_cmd_query_hca_attr(sh->ctx, &config.hca_attr);
+               if (err) {
+                       err = -err;
+                       goto error;
+               }
+       }
+#endif
+#ifdef HAVE_MLX5DV_DR_ESWITCH
+       if (!(config.hca_attr.eswitch_manager && config.dv_flow_en &&
+             (switch_info->representor || switch_info->master)))
+               config.dv_esw_en = 0;
+#else
+       config.dv_esw_en = 0;
+#endif
        /* Store device configuration on private structure. */
        priv->config = config;
+       if (config.dv_flow_en) {
+               err = mlx5_alloc_shared_dr(priv);
+               if (err)
+                       goto error;
+       }
        /* Supported Verbs flow priority number detection. */
        err = mlx5_flow_discover_priorities(eth_dev);
        if (err < 0) {
@@ -1606,23 +1571,10 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
                goto error;
        }
        priv->config.flow_prio = err;
-       /*
-        * Once the device is added to the list of memory event
-        * callback, its global MR cache table cannot be expanded
-        * on the fly because of deadlock. If it overflows, lookup
-        * should be done by searching MR list linearly, which is slow.
-        */
-       err = mlx5_mr_btree_init(&priv->mr.cache,
-                                MLX5_MR_BTREE_CACHE_N * 2,
-                                eth_dev->device->numa_node);
-       if (err) {
-               err = rte_errno;
-               goto error;
-       }
        /* Add device to memory callback list. */
        rte_rwlock_write_lock(&mlx5_shared_data->mem_event_rwlock);
        LIST_INSERT_HEAD(&mlx5_shared_data->mem_event_cb_list,
-                        priv, mem_event_cb);
+                        sh, mem_event_cb);
        rte_rwlock_write_unlock(&mlx5_shared_data->mem_event_rwlock);
        return eth_dev;
 error:
@@ -1770,7 +1722,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
        }
        ibv_match[nd] = NULL;
        if (!nd) {
-               /* No device macthes, just complain and bail out. */
+               /* No device matches, just complain and bail out. */
                mlx5_glue->free_device_list(ibv_list);
                DRV_LOG(WARNING,
                        "no Verbs device matches PCI device " PCI_PRI_FMT ","
@@ -1803,7 +1755,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 
        if (np > 1) {
                /*
-                * Signle IB device with multiple ports found,
+                * Single IB device with multiple ports found,
                 * it may be E-Switch master device and representors.
                 * We have to perform identification trough the ports.
                 */
@@ -1815,6 +1767,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
                        list[ns].ibv_port = i;
                        list[ns].ibv_dev = ibv_match[0];
                        list[ns].eth_dev = NULL;
+                       list[ns].pci_dev = pci_dev;
                        list[ns].ifindex = mlx5_nl_ifindex
                                        (nl_rdma, list[ns].ibv_dev->name, i);
                        if (!list[ns].ifindex) {
@@ -1881,17 +1834,46 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
                        list[ns].ibv_port = 1;
                        list[ns].ibv_dev = ibv_match[i];
                        list[ns].eth_dev = NULL;
+                       list[ns].pci_dev = pci_dev;
                        list[ns].ifindex = 0;
                        if (nl_rdma >= 0)
                                list[ns].ifindex = mlx5_nl_ifindex
                                        (nl_rdma, list[ns].ibv_dev->name, 1);
                        if (!list[ns].ifindex) {
+                               char ifname[IF_NAMESIZE];
+
                                /*
-                                * No network interface index found for the
-                                * specified device, it means there it is not
-                                * a representor/master.
+                                * Netlink failed, it may happen with old
+                                * ib_core kernel driver (before 4.16).
+                                * We can assume there is old driver because
+                                * here we are processing single ports IB
+                                * devices. Let's try sysfs to retrieve
+                                * the ifindex. The method works for
+                                * master device only.
                                 */
-                               continue;
+                               if (nd > 1) {
+                                       /*
+                                        * Multiple devices found, assume
+                                        * representors, can not distinguish
+                                        * master/representor and retrieve
+                                        * ifindex via sysfs.
+                                        */
+                                       continue;
+                               }
+                               ret = mlx5_get_master_ifname
+                                       (ibv_match[i]->ibdev_path, &ifname);
+                               if (!ret)
+                                       list[ns].ifindex =
+                                               if_nametoindex(ifname);
+                               if (!list[ns].ifindex) {
+                                       /*
+                                        * No network interface index found
+                                        * for the specified device, it means
+                                        * there it is neither representor
+                                        * nor master.
+                                        */
+                                       continue;
+                               }
                        }
                        ret = -1;
                        if (nl_route >= 0)
@@ -1961,6 +1943,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
                        .max_memcpy_len = MLX5_MPRQ_MEMCPY_DEFAULT_LEN,
                        .min_rxqs_num = MLX5_MPRQ_MIN_RXQS,
                },
+               .dv_esw_en = 1,
        };
        /* Device specific configuration. */
        switch (pci_dev->id.device_id) {
@@ -2049,14 +2032,9 @@ static int
 mlx5_pci_remove(struct rte_pci_device *pci_dev)
 {
        uint16_t port_id;
-       struct rte_eth_dev *port;
 
-       for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
-               port = &rte_eth_devices[port_id];
-               if (port->state != RTE_ETH_DEV_UNUSED &&
-                               port->device == &pci_dev->device)
-                       rte_eth_dev_close(port_id);
-       }
+       RTE_ETH_FOREACH_DEV_OF(port_id, &pci_dev->device)
+               rte_eth_dev_close(port_id);
        return 0;
 }