net/mlx5: split hairpin flows
[dpdk.git] / drivers / net / mlx5 / mlx5.c
index 365d5da..0bbc8d1 100644 (file)
@@ -178,6 +178,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 +442,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);
@@ -390,9 +511,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 */
@@ -426,10 +568,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;
@@ -495,8 +643,14 @@ mlx5_free_shared_ibctx(struct mlx5_ibv_shared *sh)
        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);
@@ -987,6 +1141,7 @@ const struct eth_dev_ops mlx5_dev_ops = {
        .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,
@@ -1012,6 +1167,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. */
@@ -1054,6 +1210,7 @@ const struct eth_dev_ops mlx5_dev_ops_isolate = {
        .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,
@@ -1073,6 +1230,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,
 };
 
 /**