+/**
+ * Destroy domain policer rule.
+ *
+ * @param[in] dt
+ * Pointer to domain table.
+ */
+static void
+flow_dv_destroy_domain_policer_rule(struct mlx5_meter_domain_info *dt)
+{
+ int i;
+
+ for (i = 0; i < RTE_MTR_DROPPED; i++) {
+ if (dt->policer_rules[i]) {
+ claim_zero(mlx5_glue->dv_destroy_flow
+ (dt->policer_rules[i]));
+ dt->policer_rules[i] = NULL;
+ }
+ }
+ if (dt->jump_actn) {
+ claim_zero(mlx5_glue->destroy_flow_action(dt->jump_actn));
+ dt->jump_actn = NULL;
+ }
+}
+
+/**
+ * Destroy policer rules.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] fm
+ * Pointer to flow meter structure.
+ * @param[in] attr
+ * Pointer to flow attributes.
+ *
+ * @return
+ * Always 0.
+ */
+static int
+flow_dv_destroy_policer_rules(struct rte_eth_dev *dev __rte_unused,
+ const struct mlx5_flow_meter *fm,
+ const struct rte_flow_attr *attr)
+{
+ struct mlx5_meter_domains_infos *mtb = fm ? fm->mfts : NULL;
+
+ if (!mtb)
+ return 0;
+ if (attr->egress)
+ flow_dv_destroy_domain_policer_rule(&mtb->egress);
+ if (attr->ingress)
+ flow_dv_destroy_domain_policer_rule(&mtb->ingress);
+ if (attr->transfer)
+ flow_dv_destroy_domain_policer_rule(&mtb->transfer);
+ return 0;
+}
+
+/**
+ * Create specify domain meter policer rule.
+ *
+ * @param[in] fm
+ * Pointer to flow meter structure.
+ * @param[in] mtb
+ * Pointer to DV meter table set.
+ * @param[in] sfx_tb
+ * Pointer to suffix table.
+ * @param[in] mtr_reg_c
+ * Color match REG_C.
+ *
+ * @return
+ * 0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,
+ struct mlx5_meter_domain_info *dtb,
+ struct mlx5_flow_tbl_resource *sfx_tb,
+ uint8_t mtr_reg_c)
+{
+ struct mlx5_flow_dv_match_params matcher = {
+ .size = sizeof(matcher.buf),
+ };
+ struct mlx5_flow_dv_match_params value = {
+ .size = sizeof(value.buf),
+ };
+ struct mlx5_meter_domains_infos *mtb = fm->mfts;
+ void *actions[METER_ACTIONS];
+ int i;
+
+ /* Create jump action. */
+ if (!sfx_tb)
+ return -1;
+ if (!dtb->jump_actn)
+ dtb->jump_actn =
+ mlx5_glue->dr_create_flow_action_dest_flow_tbl
+ (sfx_tb->obj);
+ if (!dtb->jump_actn) {
+ DRV_LOG(ERR, "Failed to create policer jump action.");
+ goto error;
+ }
+ for (i = 0; i < RTE_MTR_DROPPED; i++) {
+ int j = 0;
+
+ flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_reg_c,
+ rte_col_2_mlx5_col(i), UINT8_MAX);
+ if (mtb->count_actns[i])
+ actions[j++] = mtb->count_actns[i];
+ if (fm->params.action[i] == MTR_POLICER_ACTION_DROP)
+ actions[j++] = mtb->drop_actn;
+ else
+ actions[j++] = dtb->jump_actn;
+ dtb->policer_rules[i] =
+ mlx5_glue->dv_create_flow(dtb->color_matcher,
+ (void *)&value,
+ j, actions);
+ if (!dtb->policer_rules[i]) {
+ DRV_LOG(ERR, "Failed to create policer rule.");
+ goto error;
+ }
+ }
+ return 0;
+error:
+ rte_errno = errno;
+ return -1;
+}
+
+/**
+ * Create policer rules.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] fm
+ * Pointer to flow meter structure.
+ * @param[in] attr
+ * Pointer to flow attributes.
+ *
+ * @return
+ * 0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policer_rules(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter *fm,
+ const struct rte_flow_attr *attr)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_meter_domains_infos *mtb = fm->mfts;
+ int ret;
+
+ if (attr->egress) {
+ ret = flow_dv_create_policer_forward_rule(fm, &mtb->egress,
+ priv->sh->tx_mtr_sfx_tbl,
+ priv->mtr_color_reg);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to create egress policer.");
+ goto error;
+ }
+ }
+ if (attr->ingress) {
+ ret = flow_dv_create_policer_forward_rule(fm, &mtb->ingress,
+ priv->sh->rx_mtr_sfx_tbl,
+ priv->mtr_color_reg);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to create ingress policer.");
+ goto error;
+ }
+ }
+ if (attr->transfer) {
+ ret = flow_dv_create_policer_forward_rule(fm, &mtb->transfer,
+ priv->sh->fdb_mtr_sfx_tbl,
+ priv->mtr_color_reg);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to create transfer policer.");
+ goto error;
+ }
+ }
+ return 0;
+error:
+ flow_dv_destroy_policer_rules(dev, fm, attr);
+ return -1;
+}
+
+/**
+ * Query a devx counter.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] cnt
+ * Index to the flow counter.
+ * @param[in] clear
+ * Set to clear the counter statistics.
+ * @param[out] pkts
+ * The statistics value of packets.
+ * @param[out] bytes
+ * The statistics value of bytes.
+ *
+ * @return
+ * 0 on success, otherwise return -1.
+ */
+static int
+flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear,
+ uint64_t *pkts, uint64_t *bytes)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_flow_counter *cnt;
+ uint64_t inn_pkts, inn_bytes;
+ int ret;
+
+ if (!priv->config.devx)
+ return -1;
+
+ ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes);
+ if (ret)
+ return -1;
+ cnt = flow_dv_counter_get_by_idx(dev, counter, NULL);
+ *pkts = inn_pkts - cnt->hits;
+ *bytes = inn_bytes - cnt->bytes;
+ if (clear) {
+ cnt->hits = inn_pkts;
+ cnt->bytes = inn_bytes;
+ }
+ return 0;
+}
+