net/mlx5: add metadata register copy table
[dpdk.git] / drivers / net / mlx5 / mlx5.c
index 7f19133..91aaa9b 100644 (file)
 /* Activate DV flow steering. */
 #define MLX5_DV_FLOW_EN "dv_flow_en"
 
+/* Enable extensive flow metadata support. */
+#define MLX5_DV_XMETA_EN "dv_xmeta_en"
+
 /* Activate Netlink support in VF mode. */
 #define MLX5_VF_NL_EN "vf_nl_en"
 
@@ -178,6 +181,124 @@ struct mlx5_dev_spawn_data {
 static LIST_HEAD(, mlx5_ibv_shared) mlx5_ibv_list = LIST_HEAD_INITIALIZER();
 static pthread_mutex_t mlx5_ibv_list_mutex = PTHREAD_MUTEX_INITIALIZER;
 
+#define MLX5_FLOW_MIN_ID_POOL_SIZE 512
+#define MLX5_ID_GENERATION_ARRAY_FACTOR 16
+
+/**
+ * Allocate ID pool structure.
+ *
+ * @return
+ *   Pointer to pool object, NULL value otherwise.
+ */
+struct mlx5_flow_id_pool *
+mlx5_flow_id_pool_alloc(void)
+{
+       struct mlx5_flow_id_pool *pool;
+       void *mem;
+
+       pool = rte_zmalloc("id pool allocation", sizeof(*pool),
+                          RTE_CACHE_LINE_SIZE);
+       if (!pool) {
+               DRV_LOG(ERR, "can't allocate id pool");
+               rte_errno  = ENOMEM;
+               return NULL;
+       }
+       mem = rte_zmalloc("", MLX5_FLOW_MIN_ID_POOL_SIZE * sizeof(uint32_t),
+                         RTE_CACHE_LINE_SIZE);
+       if (!mem) {
+               DRV_LOG(ERR, "can't allocate mem for id pool");
+               rte_errno  = ENOMEM;
+               goto error;
+       }
+       pool->free_arr = mem;
+       pool->curr = pool->free_arr;
+       pool->last = pool->free_arr + MLX5_FLOW_MIN_ID_POOL_SIZE;
+       pool->base_index = 0;
+       return pool;
+error:
+       rte_free(pool);
+       return NULL;
+}
+
+/**
+ * Release ID pool structure.
+ *
+ * @param[in] pool
+ *   Pointer to flow id pool object to free.
+ */
+void
+mlx5_flow_id_pool_release(struct mlx5_flow_id_pool *pool)
+{
+       rte_free(pool->free_arr);
+       rte_free(pool);
+}
+
+/**
+ * Generate ID.
+ *
+ * @param[in] pool
+ *   Pointer to flow id pool.
+ * @param[out] id
+ *   The generated ID.
+ *
+ * @return
+ *   0 on success, error value otherwise.
+ */
+uint32_t
+mlx5_flow_id_get(struct mlx5_flow_id_pool *pool, uint32_t *id)
+{
+       if (pool->curr == pool->free_arr) {
+               if (pool->base_index == UINT32_MAX) {
+                       rte_errno  = ENOMEM;
+                       DRV_LOG(ERR, "no free id");
+                       return -rte_errno;
+               }
+               *id = ++pool->base_index;
+               return 0;
+       }
+       *id = *(--pool->curr);
+       return 0;
+}
+
+/**
+ * Release ID.
+ *
+ * @param[in] pool
+ *   Pointer to flow id pool.
+ * @param[out] id
+ *   The generated ID.
+ *
+ * @return
+ *   0 on success, error value otherwise.
+ */
+uint32_t
+mlx5_flow_id_release(struct mlx5_flow_id_pool *pool, uint32_t id)
+{
+       uint32_t size;
+       uint32_t size2;
+       void *mem;
+
+       if (pool->curr == pool->last) {
+               size = pool->curr - pool->free_arr;
+               size2 = size * MLX5_ID_GENERATION_ARRAY_FACTOR;
+               assert(size2 > size);
+               mem = rte_malloc("", size2 * sizeof(uint32_t), 0);
+               if (!mem) {
+                       DRV_LOG(ERR, "can't allocate mem for id pool");
+                       rte_errno  = ENOMEM;
+                       return -rte_errno;
+               }
+               memcpy(mem, pool->free_arr, size * sizeof(uint32_t));
+               rte_free(pool->free_arr);
+               pool->free_arr = mem;
+               pool->curr = pool->free_arr + size;
+               pool->last = pool->free_arr + size2;
+       }
+       *pool->curr = id;
+       pool->curr++;
+       return 0;
+}
+
 /**
  * Initialize the counters management structure.
  *
@@ -324,8 +445,11 @@ mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn)
        struct mlx5_ibv_shared *sh;
        int err = 0;
        uint32_t i;
+#ifdef HAVE_IBV_FLOW_DV_SUPPORT
+       struct mlx5_devx_tis_attr tis_attr = { 0 };
+#endif
 
-       assert(spawn);
+assert(spawn);
        /* Secondary process should not create the shared context. */
        assert(rte_eal_process_type() == RTE_PROC_PRIMARY);
        pthread_mutex_lock(&mlx5_ibv_list_mutex);
@@ -379,8 +503,10 @@ mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn)
         * there is no interrupt subhandler installed for
         * the given port index i.
         */
-       for (i = 0; i < sh->max_port; i++)
+       for (i = 0; i < sh->max_port; i++) {
                sh->port[i].ih_port_id = RTE_MAX_ETHPORTS;
+               sh->port[i].devx_ih_port_id = RTE_MAX_ETHPORTS;
+       }
        sh->pd = mlx5_glue->alloc_pd(sh->ctx);
        if (sh->pd == NULL) {
                DRV_LOG(ERR, "PD allocation failure");
@@ -388,9 +514,30 @@ mlx5_alloc_shared_ibctx(const struct mlx5_dev_spawn_data *spawn)
                goto error;
        }
 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
-       err = mlx5_get_pdn(sh->pd, &sh->pdn);
-       if (err) {
-               DRV_LOG(ERR, "Fail to extract pdn from PD");
+       if (sh->devx) {
+               err = mlx5_get_pdn(sh->pd, &sh->pdn);
+               if (err) {
+                       DRV_LOG(ERR, "Fail to extract pdn from PD");
+                       goto error;
+               }
+               sh->td = mlx5_devx_cmd_create_td(sh->ctx);
+               if (!sh->td) {
+                       DRV_LOG(ERR, "TD allocation failure");
+                       err = ENOMEM;
+                       goto error;
+               }
+               tis_attr.transport_domain = sh->td->id;
+               sh->tis = mlx5_devx_cmd_create_tis(sh->ctx, &tis_attr);
+               if (!sh->tis) {
+                       DRV_LOG(ERR, "TIS allocation failure");
+                       err = ENOMEM;
+                       goto error;
+               }
+       }
+       sh->flow_id_pool = mlx5_flow_id_pool_alloc();
+       if (!sh->flow_id_pool) {
+               DRV_LOG(ERR, "can't create flow id pool");
+               err = ENOMEM;
                goto error;
        }
 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
@@ -424,10 +571,16 @@ exit:
 error:
        pthread_mutex_unlock(&mlx5_ibv_list_mutex);
        assert(sh);
+       if (sh->tis)
+               claim_zero(mlx5_devx_cmd_destroy(sh->tis));
+       if (sh->td)
+               claim_zero(mlx5_devx_cmd_destroy(sh->td));
        if (sh->pd)
                claim_zero(mlx5_glue->dealloc_pd(sh->pd));
        if (sh->ctx)
                claim_zero(mlx5_glue->close_device(sh->ctx));
+       if (sh->flow_id_pool)
+               mlx5_flow_id_pool_release(sh->flow_id_pool);
        rte_free(sh);
        assert(err > 0);
        rte_errno = err;
@@ -481,11 +634,26 @@ mlx5_free_shared_ibctx(struct mlx5_ibv_shared *sh)
        if (sh->intr_cnt)
                mlx5_intr_callback_unregister
                        (&sh->intr_handle, mlx5_dev_interrupt_handler, sh);
+#ifdef HAVE_MLX5_DEVX_ASYNC_SUPPORT
+       if (sh->devx_intr_cnt) {
+               if (sh->intr_handle_devx.fd)
+                       rte_intr_callback_unregister(&sh->intr_handle_devx,
+                                         mlx5_dev_interrupt_handler_devx, sh);
+               if (sh->devx_comp)
+                       mlx5dv_devx_destroy_cmd_comp(sh->devx_comp);
+       }
+#endif
        pthread_mutex_destroy(&sh->intr_mutex);
        if (sh->pd)
                claim_zero(mlx5_glue->dealloc_pd(sh->pd));
+       if (sh->tis)
+               claim_zero(mlx5_devx_cmd_destroy(sh->tis));
+       if (sh->td)
+               claim_zero(mlx5_devx_cmd_destroy(sh->td));
        if (sh->ctx)
                claim_zero(mlx5_glue->close_device(sh->ctx));
+       if (sh->flow_id_pool)
+               mlx5_flow_id_pool_release(sh->flow_id_pool);
        rte_free(sh);
 exit:
        pthread_mutex_unlock(&mlx5_ibv_list_mutex);
@@ -654,7 +822,7 @@ mlx5_init_shared_data(void)
                                                 SOCKET_ID_ANY, 0);
                        if (mz == NULL) {
                                DRV_LOG(ERR,
-                                       "Cannot allocate mlx5 shared data\n");
+                                       "Cannot allocate mlx5 shared data");
                                ret = -rte_errno;
                                goto error;
                        }
@@ -666,7 +834,7 @@ mlx5_init_shared_data(void)
                        mz = rte_memzone_lookup(MZ_MLX5_PMD_SHARED_DATA);
                        if (mz == NULL) {
                                DRV_LOG(ERR,
-                                       "Cannot attach mlx5 shared data\n");
+                                       "Cannot attach mlx5 shared data");
                                ret = -rte_errno;
                                goto error;
                        }
@@ -845,6 +1013,7 @@ mlx5_dev_close(struct rte_eth_dev *dev)
                ((priv->sh->ctx != NULL) ? priv->sh->ctx->device->name : ""));
        /* In case mlx5_dev_stop() has not been called. */
        mlx5_dev_interrupt_handler_uninstall(dev);
+       mlx5_dev_interrupt_handler_devx_uninstall(dev);
        mlx5_traffic_disable(dev);
        mlx5_flow_flush(dev, NULL);
        /* Prevent crashes when queues are still in use. */
@@ -870,6 +1039,8 @@ mlx5_dev_close(struct rte_eth_dev *dev)
                priv->txqs = NULL;
        }
        mlx5_proc_priv_uninit(dev);
+       if (priv->mreg_cp_tbl)
+               mlx5_hlist_destroy(priv->mreg_cp_tbl, NULL, NULL);
        mlx5_mprq_free_mp(dev);
        mlx5_free_shared_dr(priv);
        if (priv->rss_conf.rss_key != NULL)
@@ -910,7 +1081,7 @@ mlx5_dev_close(struct rte_eth_dev *dev)
        if (ret)
                DRV_LOG(WARNING, "port %u some Rx queues still remain",
                        dev->data->port_id);
-       ret = mlx5_txq_ibv_verify(dev);
+       ret = mlx5_txq_obj_verify(dev);
        if (ret)
                DRV_LOG(WARNING, "port %u some Verbs Tx queue still remain",
                        dev->data->port_id);
@@ -926,7 +1097,7 @@ mlx5_dev_close(struct rte_eth_dev *dev)
                unsigned int c = 0;
                uint16_t port_id;
 
-               RTE_ETH_FOREACH_DEV_OF(port_id, dev->device) {
+               MLX5_ETH_FOREACH_DEV(port_id, priv->pci_dev) {
                        struct mlx5_priv *opriv =
                                rte_eth_devices[port_id].data->dev_private;
 
@@ -935,6 +1106,7 @@ mlx5_dev_close(struct rte_eth_dev *dev)
                            &rte_eth_devices[port_id] == dev)
                                continue;
                        ++c;
+                       break;
                }
                if (!c)
                        claim_zero(rte_eth_switch_domain_free(priv->domain_id));
@@ -972,7 +1144,9 @@ const struct eth_dev_ops mlx5_dev_ops = {
        .dev_supported_ptypes_get = mlx5_dev_supported_ptypes_get,
        .vlan_filter_set = mlx5_vlan_filter_set,
        .rx_queue_setup = mlx5_rx_queue_setup,
+       .rx_hairpin_queue_setup = mlx5_rx_hairpin_queue_setup,
        .tx_queue_setup = mlx5_tx_queue_setup,
+       .tx_hairpin_queue_setup = mlx5_tx_hairpin_queue_setup,
        .rx_queue_release = mlx5_rx_queue_release,
        .tx_queue_release = mlx5_tx_queue_release,
        .flow_ctrl_get = mlx5_dev_get_flow_ctrl,
@@ -998,6 +1172,7 @@ const struct eth_dev_ops mlx5_dev_ops = {
        .udp_tunnel_port_add  = mlx5_udp_tunnel_port_add,
        .get_module_info = mlx5_get_module_info,
        .get_module_eeprom = mlx5_get_module_eeprom,
+       .hairpin_cap_get = mlx5_hairpin_cap_get,
 };
 
 /* Available operations from secondary process. */
@@ -1038,7 +1213,9 @@ const struct eth_dev_ops mlx5_dev_ops_isolate = {
        .dev_supported_ptypes_get = mlx5_dev_supported_ptypes_get,
        .vlan_filter_set = mlx5_vlan_filter_set,
        .rx_queue_setup = mlx5_rx_queue_setup,
+       .rx_hairpin_queue_setup = mlx5_rx_hairpin_queue_setup,
        .tx_queue_setup = mlx5_tx_queue_setup,
+       .tx_hairpin_queue_setup = mlx5_tx_hairpin_queue_setup,
        .rx_queue_release = mlx5_rx_queue_release,
        .tx_queue_release = mlx5_tx_queue_release,
        .flow_ctrl_get = mlx5_dev_get_flow_ctrl,
@@ -1058,6 +1235,7 @@ const struct eth_dev_ops mlx5_dev_ops_isolate = {
        .is_removed = mlx5_is_removed,
        .get_module_info = mlx5_get_module_info,
        .get_module_eeprom = mlx5_get_module_eeprom,
+       .hairpin_cap_get = mlx5_hairpin_cap_get,
 };
 
 /**
@@ -1137,6 +1315,16 @@ mlx5_args_check(const char *key, const char *val, void *opaque)
                config->dv_esw_en = !!tmp;
        } else if (strcmp(MLX5_DV_FLOW_EN, key) == 0) {
                config->dv_flow_en = !!tmp;
+       } else if (strcmp(MLX5_DV_XMETA_EN, key) == 0) {
+               if (tmp != MLX5_XMETA_MODE_LEGACY &&
+                   tmp != MLX5_XMETA_MODE_META16 &&
+                   tmp != MLX5_XMETA_MODE_META32) {
+                       DRV_LOG(WARNING, "invalid extensive "
+                                        "metadata parameter");
+                       rte_errno = EINVAL;
+                       return -rte_errno;
+               }
+               config->dv_xmeta_en = tmp;
        } else if (strcmp(MLX5_MR_EXT_MEMSEG_EN, key) == 0) {
                config->mr_ext_memseg_en = !!tmp;
        } else if (strcmp(MLX5_MAX_DUMP_FILES_NUM, key) == 0) {
@@ -1188,6 +1376,7 @@ mlx5_args(struct mlx5_dev_config *config, struct rte_devargs *devargs)
                MLX5_VF_NL_EN,
                MLX5_DV_ESW_EN,
                MLX5_DV_FLOW_EN,
+               MLX5_DV_XMETA_EN,
                MLX5_MR_EXT_MEMSEG_EN,
                MLX5_REPRESENTOR,
                MLX5_MAX_DUMP_FILES_NUM,
@@ -1396,6 +1585,60 @@ exit:
        DRV_LOG(DEBUG, "min tx inline configured: %d", config->txq_inline_min);
 }
 
+/**
+ * Configures the metadata mask fields in the shared context.
+ *
+ * @param [in] dev
+ *   Pointer to Ethernet device.
+ */
+static void
+mlx5_set_metadata_mask(struct rte_eth_dev *dev)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_ibv_shared *sh = priv->sh;
+       uint32_t meta, mark, reg_c0;
+
+       reg_c0 = ~priv->vport_meta_mask;
+       switch (priv->config.dv_xmeta_en) {
+       case MLX5_XMETA_MODE_LEGACY:
+               meta = UINT32_MAX;
+               mark = MLX5_FLOW_MARK_MASK;
+               break;
+       case MLX5_XMETA_MODE_META16:
+               meta = reg_c0 >> rte_bsf32(reg_c0);
+               mark = MLX5_FLOW_MARK_MASK;
+               break;
+       case MLX5_XMETA_MODE_META32:
+               meta = UINT32_MAX;
+               mark = (reg_c0 >> rte_bsf32(reg_c0)) & MLX5_FLOW_MARK_MASK;
+               break;
+       default:
+               meta = 0;
+               mark = 0;
+               assert(false);
+               break;
+       }
+       if (sh->dv_mark_mask && sh->dv_mark_mask != mark)
+               DRV_LOG(WARNING, "metadata MARK mask mismatche %08X:%08X",
+                                sh->dv_mark_mask, mark);
+       else
+               sh->dv_mark_mask = mark;
+       if (sh->dv_meta_mask && sh->dv_meta_mask != meta)
+               DRV_LOG(WARNING, "metadata META mask mismatche %08X:%08X",
+                                sh->dv_meta_mask, meta);
+       else
+               sh->dv_meta_mask = meta;
+       if (sh->dv_regc0_mask && sh->dv_regc0_mask != reg_c0)
+               DRV_LOG(WARNING, "metadata reg_c0 mask mismatche %08X:%08X",
+                                sh->dv_meta_mask, reg_c0);
+       else
+               sh->dv_regc0_mask = reg_c0;
+       DRV_LOG(DEBUG, "metadata mode %u", priv->config.dv_xmeta_en);
+       DRV_LOG(DEBUG, "metadata MARK mask %08X", sh->dv_mark_mask);
+       DRV_LOG(DEBUG, "metadata META mask %08X", sh->dv_meta_mask);
+       DRV_LOG(DEBUG, "metadata reg_c0 mask %08X", sh->dv_regc0_mask);
+}
+
 /**
  * Allocate page of door-bells and register it using DevX API.
  *
@@ -1516,6 +1759,59 @@ mlx5_release_dbr(struct rte_eth_dev *dev, uint32_t umem_id, uint64_t offset)
        return ret;
 }
 
+/**
+ * Check sibling device configurations.
+ *
+ * Sibling devices sharing the Infiniband device context
+ * should have compatible configurations. This regards
+ * representors and bonding slaves.
+ *
+ * @param priv
+ *   Private device descriptor.
+ * @param config
+ *   Configuration of the device is going to be created.
+ *
+ * @return
+ *   0 on success, EINVAL otherwise
+ */
+static int
+mlx5_dev_check_sibling_config(struct mlx5_priv *priv,
+                             struct mlx5_dev_config *config)
+{
+       struct mlx5_ibv_shared *sh = priv->sh;
+       struct mlx5_dev_config *sh_conf = NULL;
+       uint16_t port_id;
+
+       assert(sh);
+       /* Nothing to compare for the single/first device. */
+       if (sh->refcnt == 1)
+               return 0;
+       /* Find the device with shared context. */
+       MLX5_ETH_FOREACH_DEV(port_id, priv->pci_dev) {
+               struct mlx5_priv *opriv =
+                       rte_eth_devices[port_id].data->dev_private;
+
+               if (opriv && opriv != priv && opriv->sh == sh) {
+                       sh_conf = &opriv->config;
+                       break;
+               }
+       }
+       if (!sh_conf)
+               return 0;
+       if (sh_conf->dv_flow_en ^ config->dv_flow_en) {
+               DRV_LOG(ERR, "\"dv_flow_en\" configuration mismatch"
+                            " for shared %s context", sh->ibdev_name);
+               rte_errno = EINVAL;
+               return rte_errno;
+       }
+       if (sh_conf->dv_xmeta_en ^ config->dv_xmeta_en) {
+               DRV_LOG(ERR, "\"dv_xmeta_en\" configuration mismatch"
+                            " for shared %s context", sh->ibdev_name);
+               rte_errno = EINVAL;
+               return rte_errno;
+       }
+       return 0;
+}
 /**
  * Spawn an Ethernet device from Verbs information.
  *
@@ -1562,6 +1858,9 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
        int own_domain_id = 0;
        uint16_t port_id;
        unsigned int i;
+#ifdef HAVE_MLX5DV_DR_DEVX_PORT
+       struct mlx5dv_devx_port devx_port = { .comp_mask = 0 };
+#endif
 
        /* Determine if this port representor is supposed to be spawned. */
        if (switch_info->representor && dpdk_dev->devargs) {
@@ -1782,8 +2081,61 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
        priv->representor = !!switch_info->representor;
        priv->master = !!switch_info->master;
        priv->domain_id = RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID;
+       priv->vport_meta_tag = 0;
+       priv->vport_meta_mask = 0;
+       priv->pf_bond = spawn->pf_bond;
+#ifdef HAVE_MLX5DV_DR_DEVX_PORT
+       /*
+        * The DevX port query API is implemented. E-Switch may use
+        * either vport or reg_c[0] metadata register to match on
+        * vport index. The engaged part of metadata register is
+        * defined by mask.
+        */
+       if (switch_info->representor || switch_info->master) {
+               devx_port.comp_mask = MLX5DV_DEVX_PORT_VPORT |
+                                     MLX5DV_DEVX_PORT_MATCH_REG_C_0;
+               err = mlx5_glue->devx_port_query(sh->ctx, spawn->ibv_port,
+                                                &devx_port);
+               if (err) {
+                       DRV_LOG(WARNING,
+                               "can't query devx port %d on device %s",
+                               spawn->ibv_port, spawn->ibv_dev->name);
+                       devx_port.comp_mask = 0;
+               }
+       }
+       if (devx_port.comp_mask & MLX5DV_DEVX_PORT_MATCH_REG_C_0) {
+               priv->vport_meta_tag = devx_port.reg_c_0.value;
+               priv->vport_meta_mask = devx_port.reg_c_0.mask;
+               if (!priv->vport_meta_mask) {
+                       DRV_LOG(ERR, "vport zero mask for port %d"
+                                    " on bonding device %s",
+                                    spawn->ibv_port, spawn->ibv_dev->name);
+                       err = ENOTSUP;
+                       goto error;
+               }
+               if (priv->vport_meta_tag & ~priv->vport_meta_mask) {
+                       DRV_LOG(ERR, "invalid vport tag for port %d"
+                                    " on bonding device %s",
+                                    spawn->ibv_port, spawn->ibv_dev->name);
+                       err = ENOTSUP;
+                       goto error;
+               }
+       } else if (devx_port.comp_mask & MLX5DV_DEVX_PORT_VPORT) {
+               priv->vport_id = devx_port.vport_num;
+       } else if (spawn->pf_bond >= 0) {
+               DRV_LOG(ERR, "can't deduce vport index for port %d"
+                            " on bonding device %s",
+                            spawn->ibv_port, spawn->ibv_dev->name);
+               err = ENOTSUP;
+               goto error;
+       } else {
+               /* Suppose vport index in compatible way. */
+               priv->vport_id = switch_info->representor ?
+                                switch_info->port_name + 1 : -1;
+       }
+#else
        /*
-        * Currently we support single E-Switch per PF configurations
+        * Kernel/rdma_core 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 example, let's have the IB device port 10, it has
@@ -1795,18 +2147,20 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
         */
        priv->vport_id = switch_info->representor ?
                         switch_info->port_name + 1 : -1;
-       /* representor_id field keeps the unmodified port/VF index. */
+#endif
+       /* representor_id field keeps the unmodified VF index. */
        priv->representor_id = switch_info->representor ?
                               switch_info->port_name : -1;
        /*
         * Look for sibling devices in order to reuse their switch domain
         * if any, otherwise allocate one.
         */
-       RTE_ETH_FOREACH_DEV_OF(port_id, dpdk_dev) {
+       MLX5_ETH_FOREACH_DEV(port_id, priv->pci_dev) {
                const struct mlx5_priv *opriv =
                        rte_eth_devices[port_id].data->dev_private;
 
                if (!opriv ||
+                   opriv->sh != priv->sh ||
                        opriv->domain_id ==
                        RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID)
                        continue;
@@ -1830,6 +2184,9 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
                        strerror(rte_errno));
                goto error;
        }
+       err = mlx5_dev_check_sibling_config(priv, &config);
+       if (err)
+               goto error;
        config.hw_csum = !!(sh->device_attr.device_cap_flags_ex &
                            IBV_DEVICE_RAW_IP_CSUM);
        DRV_LOG(DEBUG, "checksum offloading is %ssupported",
@@ -1914,9 +2271,10 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
                priv->counter_fallback = 1;
 #endif
                if (priv->counter_fallback)
-                       DRV_LOG(INFO, "Use fall-back DV counter management\n");
+                       DRV_LOG(INFO, "Use fall-back DV counter management");
                /* Check for LRO support. */
-               if (config.dest_tir && config.hca_attr.lro_cap) {
+               if (config.dest_tir && config.hca_attr.lro_cap &&
+                   config.dv_flow_en) {
                        /* TBD check tunnel lro caps. */
                        config.lro.supported = config.hca_attr.lro_cap;
                        DRV_LOG(DEBUG, "Device supports LRO");
@@ -2055,6 +2413,12 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
                err = mlx5_alloc_shared_dr(priv);
                if (err)
                        goto error;
+               priv->qrss_id_pool = mlx5_flow_id_pool_alloc();
+               if (!priv->qrss_id_pool) {
+                       DRV_LOG(ERR, "can't create flow id pool");
+                       err = ENOMEM;
+                       goto error;
+               }
        }
        /* Supported Verbs flow priority number detection. */
        err = mlx5_flow_discover_priorities(eth_dev);
@@ -2063,9 +2427,55 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
                goto error;
        }
        priv->config.flow_prio = err;
+       if (!priv->config.dv_esw_en &&
+           priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
+               DRV_LOG(WARNING, "metadata mode %u is not supported "
+                                "(no E-Switch)", priv->config.dv_xmeta_en);
+               priv->config.dv_xmeta_en = MLX5_XMETA_MODE_LEGACY;
+       }
+       mlx5_set_metadata_mask(eth_dev);
+       if (priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
+           !priv->sh->dv_regc0_mask) {
+               DRV_LOG(ERR, "metadata mode %u is not supported "
+                            "(no metadata reg_c[0] is available)",
+                            priv->config.dv_xmeta_en);
+                       err = ENOTSUP;
+                       goto error;
+       }
+       /* Query availibility of metadata reg_c's. */
+       err = mlx5_flow_discover_mreg_c(eth_dev);
+       if (err < 0) {
+               err = -err;
+               goto error;
+       }
+       if (!mlx5_flow_ext_mreg_supported(eth_dev)) {
+               DRV_LOG(DEBUG,
+                       "port %u extensive metadata register is not supported",
+                       eth_dev->data->port_id);
+               if (priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
+                       DRV_LOG(ERR, "metadata mode %u is not supported "
+                                    "(no metadata registers available)",
+                                    priv->config.dv_xmeta_en);
+                       err = ENOTSUP;
+                       goto error;
+               }
+       }
+       if (priv->config.dv_flow_en &&
+           priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
+           mlx5_flow_ext_mreg_supported(eth_dev) &&
+           priv->sh->dv_regc0_mask) {
+               priv->mreg_cp_tbl = mlx5_hlist_create(MLX5_FLOW_MREG_HNAME,
+                                                     MLX5_FLOW_MREG_HTABLE_SZ);
+               if (!priv->mreg_cp_tbl) {
+                       err = ENOMEM;
+                       goto error;
+               }
+       }
        return eth_dev;
 error:
        if (priv) {
+               if (priv->mreg_cp_tbl)
+                       mlx5_hlist_destroy(priv->mreg_cp_tbl, NULL, NULL);
                if (priv->sh)
                        mlx5_free_shared_dr(priv);
                if (priv->nl_socket_route >= 0)
@@ -2074,6 +2484,8 @@ error:
                        close(priv->nl_socket_rdma);
                if (priv->vmwa_context)
                        mlx5_vlan_vmwa_exit(priv->vmwa_context);
+               if (priv->qrss_id_pool)
+                       mlx5_flow_id_pool_release(priv->qrss_id_pool);
                if (own_domain_id)
                        claim_zero(rte_eth_switch_domain_free(priv->domain_id));
                rte_free(priv);
@@ -2613,6 +3025,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
        case PCI_DEVICE_ID_MELLANOX_CONNECTX5EXVF:
        case PCI_DEVICE_ID_MELLANOX_CONNECTX5BFVF:
        case PCI_DEVICE_ID_MELLANOX_CONNECTX6VF:
+       case PCI_DEVICE_ID_MELLANOX_CONNECTX6DXVF:
                dev_config.vf = 1;
                break;
        default:
@@ -2634,6 +3047,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
                rte_eth_copy_pci_info(list[i].eth_dev, pci_dev);
                /* Restore non-PCI flags cleared by the above call. */
                list[i].eth_dev->data->dev_flags |= restore;
+               mlx5_dev_interrupt_handler_devx_install(list[i].eth_dev);
                rte_eth_dev_probing_finish(list[i].eth_dev);
        }
        if (i != ns) {
@@ -2676,6 +3090,41 @@ exit:
        return ret;
 }
 
+/**
+ * Look for the ethernet device belonging to mlx5 driver.
+ *
+ * @param[in] port_id
+ *   port_id to start looking for device.
+ * @param[in] pci_dev
+ *   Pointer to the hint PCI device. When device is being probed
+ *   the its siblings (master and preceding representors might
+ *   not have assigned driver yet (because the mlx5_pci_probe()
+ *   is not completed yet, for this case match on hint PCI
+ *   device may be used to detect sibling device.
+ *
+ * @return
+ *   port_id of found device, RTE_MAX_ETHPORT if not found.
+ */
+uint16_t
+mlx5_eth_find_next(uint16_t port_id, struct rte_pci_device *pci_dev)
+{
+       while (port_id < RTE_MAX_ETHPORTS) {
+               struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+               if (dev->state != RTE_ETH_DEV_UNUSED &&
+                   dev->device &&
+                   (dev->device == &pci_dev->device ||
+                    (dev->device->driver &&
+                    dev->device->driver->name &&
+                    !strcmp(dev->device->driver->name, MLX5_DRIVER_NAME))))
+                       break;
+               port_id++;
+       }
+       if (port_id >= RTE_MAX_ETHPORTS)
+               return RTE_MAX_ETHPORTS;
+       return port_id;
+}
+
 /**
  * DPDK callback to remove a PCI device.
  *
@@ -2746,6 +3195,14 @@ static const struct rte_pci_id mlx5_pci_id_map[] = {
                RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
                                PCI_DEVICE_ID_MELLANOX_CONNECTX6VF)
        },
+       {
+               RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
+                               PCI_DEVICE_ID_MELLANOX_CONNECTX6DX)
+       },
+       {
+               RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
+                               PCI_DEVICE_ID_MELLANOX_CONNECTX6DXVF)
+       },
        {
                .vendor_id = 0
        }