+#include "mlx5_rx.h"
+
+#define VERBS_SPEC_INNER(item_flags) \
+ (!!((item_flags) & MLX5_FLOW_LAYER_TUNNEL) ? IBV_FLOW_SPEC_INNER : 0)
+
+/* Verbs specification header. */
+struct ibv_spec_header {
+ enum ibv_flow_spec_type type;
+ uint16_t size;
+};
+
+/**
+ * Discover the maximum number of priority available.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] vprio
+ * Expected result variants.
+ * @param[in] vprio_n
+ * Number of entries in @p vprio array.
+ * @return
+ * Number of supported flow priority on success, a negative errno
+ * value otherwise and rte_errno is set.
+ */
+static int
+flow_verbs_discover_priorities(struct rte_eth_dev *dev,
+ const uint16_t *vprio, int vprio_n)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct {
+ struct ibv_flow_attr attr;
+ struct ibv_flow_spec_eth eth;
+ struct ibv_flow_spec_action_drop drop;
+ } flow_attr = {
+ .attr = {
+ .num_of_specs = 2,
+ .port = (uint8_t)priv->dev_port,
+ },
+ .eth = {
+ .type = IBV_FLOW_SPEC_ETH,
+ .size = sizeof(struct ibv_flow_spec_eth),
+ },
+ .drop = {
+ .size = sizeof(struct ibv_flow_spec_action_drop),
+ .type = IBV_FLOW_SPEC_ACTION_DROP,
+ },
+ };
+ struct ibv_flow *flow;
+ struct mlx5_hrxq *drop = priv->drop_queue.hrxq;
+ int i;
+ int priority = 0;
+
+#if defined(HAVE_MLX5DV_DR_DEVX_PORT) || defined(HAVE_MLX5DV_DR_DEVX_PORT_V35)
+ /* If DevX supported, driver must support 16 verbs flow priorities. */
+ priority = 16;
+ goto out;
+#endif
+ if (!drop->qp) {
+ rte_errno = ENOTSUP;
+ return -rte_errno;
+ }
+ for (i = 0; i != vprio_n; i++) {
+ flow_attr.attr.priority = vprio[i] - 1;
+ flow = mlx5_glue->create_flow(drop->qp, &flow_attr.attr);
+ if (!flow)
+ break;
+ claim_zero(mlx5_glue->destroy_flow(flow));
+ priority = vprio[i];
+ }
+#if defined(HAVE_MLX5DV_DR_DEVX_PORT) || defined(HAVE_MLX5DV_DR_DEVX_PORT_V35)
+out:
+#endif
+ DRV_LOG(INFO, "port %u supported flow priorities:"
+ " 0-%d for ingress or egress root table,"
+ " 0-%d for non-root table or transfer root table.",
+ dev->data->port_id, priority - 2,
+ MLX5_NON_ROOT_FLOW_MAX_PRIO - 1);
+ return priority;
+}
+
+/**
+ * Get Verbs flow counter by index.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] idx
+ * mlx5 flow counter index in the container.
+ * @param[out] ppool
+ * mlx5 flow counter pool in the container,
+ *
+ * @return
+ * A pointer to the counter, NULL otherwise.
+ */
+static struct mlx5_flow_counter *
+flow_verbs_counter_get_by_idx(struct rte_eth_dev *dev,
+ uint32_t idx,
+ struct mlx5_flow_counter_pool **ppool)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
+ struct mlx5_flow_counter_pool *pool;
+
+ idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
+ pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
+ MLX5_ASSERT(pool);
+ if (ppool)
+ *ppool = pool;
+ return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
+}