+ rte_rwlock_read_lock(&priv->ind_tbls_lock);
+ LIST_FOREACH(ind_tbl, &priv->ind_tbls, next) {
+ DRV_LOG(DEBUG,
+ "port %u indirection table obj %p still referenced",
+ dev->data->port_id, (void *)ind_tbl);
+ ++ret;
+ }
+ rte_rwlock_read_unlock(&priv->ind_tbls_lock);
+ return ret;
+}
+
+/**
+ * Setup an indirection table structure fields.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param ind_table
+ * Indirection table to modify.
+ * @param ref_qs
+ * Whether to increment RxQ reference counters.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_ind_table_obj_setup(struct rte_eth_dev *dev,
+ struct mlx5_ind_table_obj *ind_tbl,
+ bool ref_qs)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ uint32_t queues_n = ind_tbl->queues_n;
+ uint16_t *queues = ind_tbl->queues;
+ unsigned int i = 0, j;
+ int ret = 0, err;
+ const unsigned int n = rte_is_power_of_2(queues_n) ?
+ log2above(queues_n) :
+ log2above(priv->sh->dev_cap.ind_table_max_size);
+
+ if (ref_qs)
+ for (i = 0; i != queues_n; ++i) {
+ if (mlx5_rxq_ref(dev, queues[i]) == NULL) {
+ ret = -rte_errno;
+ goto error;
+ }
+ }
+ ret = priv->obj_ops.ind_table_new(dev, n, ind_tbl);
+ if (ret)
+ goto error;
+ __atomic_fetch_add(&ind_tbl->refcnt, 1, __ATOMIC_RELAXED);
+ return 0;
+error:
+ if (ref_qs) {
+ err = rte_errno;
+ for (j = 0; j < i; j++)
+ mlx5_rxq_deref(dev, queues[j]);
+ rte_errno = err;
+ }
+ DRV_LOG(DEBUG, "Port %u cannot setup indirection table.",
+ dev->data->port_id);
+ return ret;
+}
+
+/**
+ * Create an indirection table.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param queues
+ * Queues entering in the indirection table.
+ * @param queues_n
+ * Number of queues in the array.
+ * @param standalone
+ * Indirection table for Standalone queue.
+ * @param ref_qs
+ * Whether to increment RxQ reference counters.
+ *
+ * @return
+ * The Verbs/DevX object initialized, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_ind_table_obj *
+mlx5_ind_table_obj_new(struct rte_eth_dev *dev, const uint16_t *queues,
+ uint32_t queues_n, bool standalone, bool ref_qs)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_ind_table_obj *ind_tbl;
+ int ret;
+
+ ind_tbl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*ind_tbl) +
+ queues_n * sizeof(uint16_t), 0, SOCKET_ID_ANY);
+ if (!ind_tbl) {
+ rte_errno = ENOMEM;
+ return NULL;
+ }
+ ind_tbl->queues_n = queues_n;
+ ind_tbl->queues = (uint16_t *)(ind_tbl + 1);
+ memcpy(ind_tbl->queues, queues, queues_n * sizeof(*queues));
+ ret = mlx5_ind_table_obj_setup(dev, ind_tbl, ref_qs);
+ if (ret < 0) {
+ mlx5_free(ind_tbl);
+ return NULL;
+ }
+ if (!standalone) {
+ rte_rwlock_write_lock(&priv->ind_tbls_lock);
+ LIST_INSERT_HEAD(&priv->ind_tbls, ind_tbl, next);
+ rte_rwlock_write_unlock(&priv->ind_tbls_lock);
+ }
+ return ind_tbl;
+}
+
+static int
+mlx5_ind_table_obj_check_standalone(struct rte_eth_dev *dev __rte_unused,
+ struct mlx5_ind_table_obj *ind_tbl)
+{
+ uint32_t refcnt;
+
+ refcnt = __atomic_load_n(&ind_tbl->refcnt, __ATOMIC_RELAXED);
+ if (refcnt <= 1)
+ return 0;
+ /*
+ * Modification of indirection tables having more than 1
+ * reference is unsupported.
+ */
+ DRV_LOG(DEBUG,
+ "Port %u cannot modify indirection table %p (refcnt %u > 1).",
+ dev->data->port_id, (void *)ind_tbl, refcnt);
+ rte_errno = EINVAL;
+ return -rte_errno;
+}
+
+/**
+ * Modify an indirection table.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param ind_table
+ * Indirection table to modify.
+ * @param queues
+ * Queues replacement for the indirection table.
+ * @param queues_n
+ * Number of queues in the array.
+ * @param standalone
+ * Indirection table for Standalone queue.
+ * @param ref_new_qs
+ * Whether to increment new RxQ set reference counters.
+ * @param deref_old_qs
+ * Whether to decrement old RxQ set reference counters.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_ind_table_obj_modify(struct rte_eth_dev *dev,
+ struct mlx5_ind_table_obj *ind_tbl,
+ uint16_t *queues, const uint32_t queues_n,
+ bool standalone, bool ref_new_qs, bool deref_old_qs)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ unsigned int i = 0, j;
+ int ret = 0, err;
+ const unsigned int n = rte_is_power_of_2(queues_n) ?
+ log2above(queues_n) :
+ log2above(priv->sh->dev_cap.ind_table_max_size);
+
+ MLX5_ASSERT(standalone);
+ RTE_SET_USED(standalone);
+ if (mlx5_ind_table_obj_check_standalone(dev, ind_tbl) < 0)
+ return -rte_errno;
+ if (ref_new_qs)
+ for (i = 0; i != queues_n; ++i) {
+ if (!mlx5_rxq_ref(dev, queues[i])) {
+ ret = -rte_errno;
+ goto error;
+ }
+ }
+ MLX5_ASSERT(priv->obj_ops.ind_table_modify);
+ ret = priv->obj_ops.ind_table_modify(dev, n, queues, queues_n, ind_tbl);
+ if (ret)
+ goto error;
+ if (deref_old_qs)
+ for (i = 0; i < ind_tbl->queues_n; i++)
+ claim_nonzero(mlx5_rxq_deref(dev, ind_tbl->queues[i]));
+ ind_tbl->queues_n = queues_n;
+ ind_tbl->queues = queues;
+ return 0;
+error:
+ if (ref_new_qs) {
+ err = rte_errno;
+ for (j = 0; j < i; j++)
+ mlx5_rxq_deref(dev, queues[j]);
+ rte_errno = err;
+ }
+ DRV_LOG(DEBUG, "Port %u cannot setup indirection table.",
+ dev->data->port_id);
+ return ret;
+}
+
+/**
+ * Attach an indirection table to its queues.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param ind_table
+ * Indirection table to attach.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_ind_table_obj_attach(struct rte_eth_dev *dev,
+ struct mlx5_ind_table_obj *ind_tbl)
+{
+ int ret;
+
+ ret = mlx5_ind_table_obj_modify(dev, ind_tbl, ind_tbl->queues,
+ ind_tbl->queues_n,
+ true /* standalone */,
+ true /* ref_new_qs */,
+ false /* deref_old_qs */);
+ if (ret != 0)
+ DRV_LOG(ERR, "Port %u could not modify indirect table obj %p",
+ dev->data->port_id, (void *)ind_tbl);
+ return ret;
+}
+
+/**
+ * Detach an indirection table from its queues.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param ind_table
+ * Indirection table to detach.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_ind_table_obj_detach(struct rte_eth_dev *dev,
+ struct mlx5_ind_table_obj *ind_tbl)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ const unsigned int n = rte_is_power_of_2(ind_tbl->queues_n) ?
+ log2above(ind_tbl->queues_n) :
+ log2above(priv->sh->dev_cap.ind_table_max_size);
+ unsigned int i;
+ int ret;
+
+ ret = mlx5_ind_table_obj_check_standalone(dev, ind_tbl);
+ if (ret != 0)
+ return ret;
+ MLX5_ASSERT(priv->obj_ops.ind_table_modify);
+ ret = priv->obj_ops.ind_table_modify(dev, n, NULL, 0, ind_tbl);
+ if (ret != 0) {
+ DRV_LOG(ERR, "Port %u could not modify indirect table obj %p",