get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/90491/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 90491,
    "url": "https://patches.dpdk.org/api/patches/90491/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20210402151627.1531623-3-lizh@nvidia.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20210402151627.1531623-3-lizh@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210402151627.1531623-3-lizh@nvidia.com",
    "date": "2021-04-02T15:16:16",
    "name": "[v2,02/13] net/mlx5: fix meter statistics",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "a6c5d588bb3bc359eb3ce7b022fc37e4caac294b",
    "submitter": {
        "id": 1967,
        "url": "https://patches.dpdk.org/api/people/1967/?format=api",
        "name": "Li Zhang",
        "email": "lizh@nvidia.com"
    },
    "delegate": {
        "id": 3268,
        "url": "https://patches.dpdk.org/api/users/3268/?format=api",
        "username": "rasland",
        "first_name": "Raslan",
        "last_name": "Darawsheh",
        "email": "rasland@nvidia.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20210402151627.1531623-3-lizh@nvidia.com/mbox/",
    "series": [
        {
            "id": 16087,
            "url": "https://patches.dpdk.org/api/series/16087/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=16087",
            "date": "2021-04-02T15:16:20",
            "name": "Add ASO meter support in MLX5 PMD",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/16087/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/90491/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/90491/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 93E0CA0548;\n\tFri,  2 Apr 2021 17:17:34 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 8B25B1410CF;\n\tFri,  2 Apr 2021 17:16:46 +0200 (CEST)",
            "from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n by mails.dpdk.org (Postfix) with ESMTP id 70322141082\n for <dev@dpdk.org>; Fri,  2 Apr 2021 17:16:35 +0200 (CEST)",
            "from Internal Mail-Server by MTLPINE1 (envelope-from\n lizh@nvidia.com)\n with SMTP; 2 Apr 2021 18:16:33 +0300",
            "from nvidia.com (c-235-17-1-009.mtl.labs.mlnx [10.235.17.9])\n by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 132FGWdP028272;\n Fri, 2 Apr 2021 18:16:32 +0300"
        ],
        "From": "Li Zhang <lizh@nvidia.com>",
        "To": "dekelp@nvidia.com, orika@nvidia.com, viacheslavo@nvidia.com,\n matan@nvidia.com, shahafs@nvidia.com, Suanming Mou <suanmingm@mellanox.com>",
        "Cc": "dev@dpdk.org, thomas@monjalon.net, rasland@nvidia.com, roniba@nvidia.com,\n Shun Hao <shunh@nvidia.com>, stable@dpdk.org",
        "Date": "Fri,  2 Apr 2021 18:16:16 +0300",
        "Message-Id": "<20210402151627.1531623-3-lizh@nvidia.com>",
        "X-Mailer": "git-send-email 2.21.0",
        "In-Reply-To": "<20210402151627.1531623-1-lizh@nvidia.com>",
        "References": "<20210331073632.1443011-1-lizh@nvidia.com>\n <20210402151627.1531623-1-lizh@nvidia.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v2 02/13] net/mlx5: fix meter statistics",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Shun Hao <shunh@nvidia.com>\n\nThis fixes the meter statistics issue that when using multiple meters,\nonly one meter has stats value.\n\nTo match the correct meter in policer table, now the meter_id is also\nused in its match criteria, so only one color and one drop matcher are\nneeded. And both meter_id and flow_id will be written to related registers\nin meter prefix flow.\n\nFixes: 46a5e6bc6a (\"net/mlx5: prepare meter flow tables\")\nCc: stable@dpdk.org\n\nSigned-off-by: Shun Hao <shunh@nvidia.com>\n---\n drivers/net/mlx5/linux/mlx5_os.c   |   9 +-\n drivers/net/mlx5/mlx5.c            |   7 +-\n drivers/net/mlx5/mlx5.h            |  25 +-\n drivers/net/mlx5/mlx5_flow.c       | 182 +++++++----\n drivers/net/mlx5/mlx5_flow.h       |  40 +--\n drivers/net/mlx5/mlx5_flow_dv.c    | 489 ++++++++++++++++++-----------\n drivers/net/mlx5/mlx5_flow_meter.c |  53 +++-\n 7 files changed, 512 insertions(+), 293 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c\nindex 5e3ae9f10e..c3ae1972de 100644\n--- a/drivers/net/mlx5/linux/mlx5_os.c\n+++ b/drivers/net/mlx5/linux/mlx5_os.c\n@@ -316,7 +316,13 @@ mlx5_alloc_shared_dr(struct mlx5_priv *priv)\n \t}\n \tsh->tx_domain = domain;\n #ifdef HAVE_MLX5DV_DR_ESWITCH\n+\tsh->esw_drop_action = mlx5_glue->dr_create_flow_action_drop();\n \tif (priv->config.dv_esw_en) {\n+\t\tif (!sh->esw_drop_action) {\n+\t\t\tDRV_LOG(ERR, \"Failed to create eswitch drop action\");\n+\t\t\terr = errno;\n+\t\t\tgoto error;\n+\t\t}\n \t\tdomain  = mlx5_glue->dr_create_domain\n \t\t\t(sh->ctx, MLX5DV_DR_DOMAIN_TYPE_FDB);\n \t\tif (!domain) {\n@@ -325,7 +331,6 @@ mlx5_alloc_shared_dr(struct mlx5_priv *priv)\n \t\t\tgoto error;\n \t\t}\n \t\tsh->fdb_domain = domain;\n-\t\tsh->esw_drop_action = mlx5_glue->dr_create_flow_action_drop();\n \t}\n #endif\n \tif (!sh->tunnel_hub)\n@@ -1225,7 +1230,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,\n \t\t\t\t\t\t\t      - 1 + REG_C_0;\n \t\t\t\tpriv->mtr_en = 1;\n \t\t\t\tpriv->mtr_reg_share =\n-\t\t\t\t      config->hca_attr.qos.flow_meter;\n+\t\t\t\t\tconfig->hca_attr.qos.flow_meter;\n \t\t\t\tDRV_LOG(DEBUG, \"The REG_C meter uses is %d\",\n \t\t\t\t\tpriv->mtr_color_reg);\n \t\t\t}\ndiff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex d9372f0a00..a1744b1017 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -275,10 +275,13 @@ static const struct mlx5_indexed_pool_config mlx5_ipool_cfg[] = {\n \t},\n #endif\n \t[MLX5_IPOOL_MTR] = {\n+\t\t/**\n+\t\t * The ipool index should grow continually from small to big,\n+\t\t * for meter idx, so not set grow_trunk to avoid meter index\n+\t\t * not jump continually.\n+\t\t */\n \t\t.size = sizeof(struct mlx5_flow_meter),\n \t\t.trunk_size = 64,\n-\t\t.grow_trunk = 3,\n-\t\t.grow_shift = 2,\n \t\t.need_lock = 1,\n \t\t.release_mem_en = 1,\n \t\t.malloc = mlx5_malloc,\ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex e4963bd107..05b6a082f5 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -187,6 +187,16 @@ struct mlx5_stats_ctrl {\n /* Maximal number of segments to split. */\n #define MLX5_MAX_RXQ_NSEG (1u << MLX5_MAX_LOG_RQ_SEGS)\n \n+/* The bit size of one register. */\n+#define MLX5_REG_BITS 32\n+\n+/* Idle bits for non-color usage in color register. */\n+#define MLX5_MTR_IDLE_BITS_IN_COLOR_REG (MLX5_REG_BITS - MLX5_MTR_COLOR_BITS)\n+\n+#define UINT32_T(x) ((uint32_t)(x))\n+\n+#define LS32_MASK(bits) ((UINT32_T(1) << (bits)) - 1)\n+\n /* LRO configurations structure. */\n struct mlx5_lro_config {\n \tuint32_t supported:1; /* Whether LRO is supported. */\n@@ -928,9 +938,9 @@ struct mlx5_priv {\n \tunsigned int representor:1; /* Device is a port representor. */\n \tunsigned int master:1; /* Device is a E-Switch master. */\n \tunsigned int txpp_en:1; /* Tx packet pacing enabled. */\n+\tunsigned int sampler_en:1; /* Whether support sampler. */\n \tunsigned int mtr_en:1; /* Whether support meter. */\n \tunsigned int mtr_reg_share:1; /* Whether support meter REG_C share. */\n-\tunsigned int sampler_en:1; /* Whether support sampler. */\n \tuint16_t domain_id; /* Switch domain identifier. */\n \tuint16_t vport_id; /* Associated VF vport index (if any). */\n \tuint32_t vport_meta_tag; /* Used for vport index match ove VF LAG. */\n@@ -989,6 +999,10 @@ struct mlx5_priv {\n \tuint32_t rss_shared_actions; /* RSS shared actions. */\n \tstruct mlx5_devx_obj *q_counters; /* DevX queue counter object. */\n \tuint32_t counter_set_id; /* Queue counter ID to set in DevX objects. */\n+\tuint8_t max_mtr_bits;\n+\t/* Indicate how many bits are used by meter id at the most. */\n+\tuint8_t max_mtr_flow_bits;\n+\t/* Indicate how many bits are used by meter flow id at the most. */\n };\n \n #define PORT_ID(priv) ((priv)->dev_data->port_id)\n@@ -1246,11 +1260,10 @@ int mlx5_pmd_socket_init(void);\n int mlx5_flow_meter_ops_get(struct rte_eth_dev *dev, void *arg);\n struct mlx5_flow_meter *mlx5_flow_meter_find(struct mlx5_priv *priv,\n \t\t\t\t\t     uint32_t meter_id);\n-struct mlx5_flow_meter *mlx5_flow_meter_attach\n-\t\t\t\t\t(struct mlx5_priv *priv,\n-\t\t\t\t\t uint32_t meter_id,\n-\t\t\t\t\t const struct rte_flow_attr *attr,\n-\t\t\t\t\t struct rte_flow_error *error);\n+int mlx5_flow_meter_attach(struct mlx5_priv *priv,\n+\t\t\t   struct mlx5_flow_meter *fm,\n+\t\t\t   const struct rte_flow_attr *attr,\n+\t\t\t   struct rte_flow_error *error);\n void mlx5_flow_meter_detach(struct mlx5_flow_meter *fm);\n \n /* mlx5_os.c */\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex c347f8130e..cffd6129e8 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -764,9 +764,9 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev,\n \t\t\treturn REG_C_0;\n \t\t}\n \t\tbreak;\n-\tcase MLX5_MTR_SFX:\n+\tcase MLX5_MTR_ID:\n \t\t/*\n-\t\t * If meter color and flow match share one register, flow match\n+\t\t * If meter color and meter id share one register, flow match\n \t\t * should use the meter color register for match.\n \t\t */\n \t\tif (priv->mtr_reg_share)\n@@ -3051,7 +3051,8 @@ flow_mreg_split_qrss_release(struct rte_eth_dev *dev,\n \n \tSILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,\n \t\t       handle_idx, dev_handle, next)\n-\t\tif (dev_handle->split_flow_id)\n+\t\tif (dev_handle->split_flow_id &&\n+\t\t    !dev_handle->is_meter_flow_id)\n \t\t\tmlx5_ipool_free(priv->sh->ipool\n \t\t\t\t\t[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID],\n \t\t\t\t\tdev_handle->split_flow_id);\n@@ -3690,23 +3691,30 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],\n  *\n  * @param[in] actions\n  *   Pointer to the list of actions.\n- * @param[out] mtr\n+ * @param[out] has_mtr\n  *   Pointer to the meter exist flag.\n+ * @param[out] meter_id\n+ *   Pointer to the meter id.\n  *\n  * @return\n  *   Total number of actions.\n  */\n static int\n-flow_check_meter_action(const struct rte_flow_action actions[], uint32_t *mtr)\n+flow_check_meter_action(const struct rte_flow_action actions[],\n+\t\t\tbool *has_mtr,\n+\t\t\tuint32_t *meter_id)\n {\n+\tconst struct rte_flow_action_meter *mtr = NULL;\n \tint actions_n = 0;\n \n-\tMLX5_ASSERT(mtr);\n-\t*mtr = 0;\n+\tMLX5_ASSERT(has_mtr);\n+\t*has_mtr = false;\n \tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {\n \t\tswitch (actions->type) {\n \t\tcase RTE_FLOW_ACTION_TYPE_METER:\n-\t\t\t*mtr = 1;\n+\t\t\tmtr = actions->conf;\n+\t\t\t*meter_id = mtr->mtr_id;\n+\t\t\t*has_mtr = true;\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tbreak;\n@@ -4363,8 +4371,10 @@ flow_create_split_inner(struct rte_eth_dev *dev,\n  * header will be in the prefix sub flow, as not to take the\n  * L3 tunnel header into account.\n  *\n- * @param dev\n+ * @param[in] dev\n  *   Pointer to Ethernet device.\n+ * @param[in] fm\n+ *   Pointer to flow meter structure.\n  * @param[in] items\n  *   Pattern specification (list terminated by the END pattern item).\n  * @param[out] sfx_items\n@@ -4379,29 +4389,38 @@ flow_create_split_inner(struct rte_eth_dev *dev,\n  *   The pattern items for the suffix flow.\n  * @param[out] tag_sfx\n  *   Pointer to suffix flow tag.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n  *\n  * @return\n- *   0 on success.\n+ *   The flow id, 0 otherwise and rte_errno is set.\n  */\n-static int\n+static uint32_t\n flow_meter_split_prep(struct rte_eth_dev *dev,\n-\t\t const struct rte_flow_item items[],\n-\t\t struct rte_flow_item sfx_items[],\n-\t\t const struct rte_flow_action actions[],\n-\t\t struct rte_flow_action actions_sfx[],\n-\t\t struct rte_flow_action actions_pre[])\n+\t\t      struct mlx5_flow_meter *fm,\n+\t\t      const struct rte_flow_item items[],\n+\t\t      struct rte_flow_item sfx_items[],\n+\t\t      const struct rte_flow_action actions[],\n+\t\t      struct rte_flow_action actions_sfx[],\n+\t\t      struct rte_flow_action actions_pre[],\n+\t\t      struct rte_flow_error *error)\n {\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n \tstruct rte_flow_action *tag_action = NULL;\n \tstruct rte_flow_item *tag_item;\n \tstruct mlx5_rte_flow_action_set_tag *set_tag;\n-\tstruct rte_flow_error error;\n \tconst struct rte_flow_action_raw_encap *raw_encap;\n \tconst struct rte_flow_action_raw_decap *raw_decap;\n-\tstruct mlx5_rte_flow_item_tag *tag_spec;\n-\tstruct mlx5_rte_flow_item_tag *tag_mask;\n+\tstruct mlx5_rte_flow_item_tag *tag_item_spec;\n+\tstruct mlx5_rte_flow_item_tag *tag_item_mask;\n \tuint32_t tag_id = 0;\n \tbool copy_vlan = false;\n+\tuint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;\n+\tuint8_t mtr_reg_bits = priv->mtr_reg_share ?\n+\t\t\t\tMLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;\n+\tuint8_t flow_id_bits = 0;\n+\tint shift;\n+\tuint32_t flow_id_val = 0;\n \n \t/* Prepare the actions for prefix and suffix flow. */\n \tfor (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {\n@@ -4410,10 +4429,7 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \t\tswitch (actions->type) {\n \t\tcase RTE_FLOW_ACTION_TYPE_METER:\n \t\t\t/* Add the extra tag action first. */\n-\t\t\ttag_action = actions_pre;\n-\t\t\ttag_action->type = (enum rte_flow_action_type)\n-\t\t\t\t\t   MLX5_RTE_FLOW_ACTION_TYPE_TAG;\n-\t\t\tactions_pre++;\n+\t\t\ttag_action = actions_pre++;\n \t\t\taction_cur = &actions_pre;\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:\n@@ -4446,23 +4462,22 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \tactions_sfx->type = RTE_FLOW_ACTION_TYPE_END;\n \tactions_pre->type = RTE_FLOW_ACTION_TYPE_END;\n \tactions_pre++;\n-\t/* Set the tag. */\n-\tset_tag = (void *)actions_pre;\n-\tset_tag->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, &error);\n-\tmlx5_ipool_malloc(priv->sh->ipool[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID],\n-\t\t\t  &tag_id);\n-\tif (tag_id >= (1 << (sizeof(tag_id) * 8 - MLX5_MTR_COLOR_BITS))) {\n-\t\tDRV_LOG(ERR, \"Port %u meter flow id exceed max limit.\",\n-\t\t\tdev->data->port_id);\n-\t\tmlx5_ipool_free(priv->sh->ipool\n-\t\t\t\t[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID], tag_id);\n-\t\treturn 0;\n-\t} else if (!tag_id) {\n-\t\treturn 0;\n+\t/* Generate meter flow_id only if support multiple flows per meter. */\n+\tmlx5_ipool_malloc(fm->flow_ipool, &tag_id);\n+\tif (!tag_id)\n+\t\treturn rte_flow_error_set(error, ENOMEM,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t\"Failed to allocate meter flow id.\");\n+\tflow_id_bits = MLX5_REG_BITS - __builtin_clz(tag_id - 1);\n+\tflow_id_bits = flow_id_bits ? flow_id_bits : 1;\n+\tif ((flow_id_bits + priv->max_mtr_bits) > mtr_reg_bits) {\n+\t\tmlx5_ipool_free(fm->flow_ipool, tag_id);\n+\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\t\"Meter flow id exceeds max limit.\");\n \t}\n-\tset_tag->data = tag_id << MLX5_MTR_COLOR_BITS;\n-\tassert(tag_action);\n-\ttag_action->conf = set_tag;\n+\tif (flow_id_bits > priv->max_mtr_flow_bits)\n+\t\tpriv->max_mtr_flow_bits = flow_id_bits;\n \t/* Prepare the suffix subflow items. */\n \ttag_item = sfx_items++;\n \tfor (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {\n@@ -4491,16 +4506,34 @@ flow_meter_split_prep(struct rte_eth_dev *dev,\n \t}\n \tsfx_items->type = RTE_FLOW_ITEM_TYPE_END;\n \tsfx_items++;\n-\ttag_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;\n-\ttag_spec->data = tag_id << MLX5_MTR_COLOR_BITS;\n-\ttag_spec->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, &error);\n-\ttag_mask = tag_spec + 1;\n-\ttag_mask->data = 0xffffff00;\n+\t/* Build tag actions and items for meter_id/meter flow_id. */\n+\tassert(tag_action);\n+\tset_tag = (struct mlx5_rte_flow_action_set_tag *)actions_pre;\n+\ttag_item_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;\n+\ttag_item_mask = tag_item_spec + 1;\n+\t/*\n+\t * The color Reg bits used by flow_id are growing from\n+\t * msb to lsb, so must do bit reverse for flow_id val in RegC.\n+\t */\n+\tfor (shift = 0; shift < flow_id_bits; shift++)\n+\t\tflow_id_val = (flow_id_val << 1) |\n+\t\t\t      (((tag_id - 1) >> shift) & 0x1);\n+\t/* Both flow_id and meter_id share the same register. */\n+\tset_tag->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID, 0, error);\n+\tset_tag->data =\n+\t\t(fm->idx | (flow_id_val << (mtr_reg_bits - flow_id_bits)))\n+\t\t<< mtr_id_offset;\n+\ttag_item_spec->id = set_tag->id;\n+\ttag_item_spec->data = set_tag->data;\n+\ttag_item_mask->data = UINT32_MAX << mtr_id_offset;\n+\ttag_action->type = (enum rte_flow_action_type)\n+\t\t\t\tMLX5_RTE_FLOW_ACTION_TYPE_TAG;\n+\ttag_action->conf = set_tag;\n \ttag_item->type = (enum rte_flow_item_type)\n-\t\t\t MLX5_RTE_FLOW_ITEM_TYPE_TAG;\n-\ttag_item->spec = tag_spec;\n+\t\t\t\tMLX5_RTE_FLOW_ITEM_TYPE_TAG;\n+\ttag_item->spec = tag_item_spec;\n \ttag_item->last = NULL;\n-\ttag_item->mask = tag_mask;\n+\ttag_item->mask = tag_item_mask;\n \treturn tag_id;\n }\n \n@@ -5200,25 +5233,49 @@ flow_create_split_meter(struct rte_eth_dev *dev,\n \t\t\tstruct rte_flow_error *error)\n {\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();\n \tstruct rte_flow_action *sfx_actions = NULL;\n \tstruct rte_flow_action *pre_actions = NULL;\n \tstruct rte_flow_item *sfx_items = NULL;\n \tstruct mlx5_flow *dev_flow = NULL;\n \tstruct rte_flow_attr sfx_attr = *attr;\n-\tuint32_t mtr = 0;\n+\tstruct mlx5_flow_meter *fm = NULL;\n+\tbool has_mtr = false;\n+\tuint32_t meter_id;\n \tuint32_t mtr_tag_id = 0;\n \tsize_t act_size;\n \tsize_t item_size;\n \tint actions_n = 0;\n-\tint ret;\n+\tint ret = 0;\n \n \tif (priv->mtr_en)\n-\t\tactions_n = flow_check_meter_action(actions, &mtr);\n-\tif (mtr) {\n-\t\t/* The five prefix actions: meter, decap, encap, tag, end. */\n+\t\tactions_n = flow_check_meter_action(actions, &has_mtr,\n+\t\t\t\t\t\t    &meter_id);\n+\tif (has_mtr) {\n+\t\tif (flow->meter) {\n+\t\t\tfm = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR],\n+\t\t\t\t\t    flow->meter);\n+\t\t\tif (!fm)\n+\t\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t\tNULL, \"Meter not found.\");\n+\t\t} else {\n+\t\t\tfm = mlx5_flow_meter_find(priv, meter_id);\n+\t\t\tif (!fm)\n+\t\t\t\treturn rte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t\tNULL, \"Meter not found.\");\n+\t\t\tret = mlx5_flow_meter_attach(priv, fm,\n+\t\t\t\t\t\t     &sfx_attr, error);\n+\t\t\tif (ret)\n+\t\t\t\treturn -rte_errno;\n+\t\t\tflow->meter = fm->idx;\n+\t\t}\n+\t\twks->fm = fm;\n+\t\t/* The prefix actions: meter, decap, encap, tag, end. */\n \t\tact_size = sizeof(struct rte_flow_action) * (actions_n + 5) +\n \t\t\t   sizeof(struct mlx5_rte_flow_action_set_tag);\n-\t\t/* tag, vlan, port id, end. */\n+\t\t/* The suffix items: tag, vlan, port id, end. */\n #define METER_SUFFIX_ITEM 4\n \t\titem_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +\n \t\t\t    sizeof(struct mlx5_rte_flow_item_tag) * 2;\n@@ -5232,9 +5289,9 @@ flow_create_split_meter(struct rte_eth_dev *dev,\n \t\tsfx_items = (struct rte_flow_item *)((char *)sfx_actions +\n \t\t\t     act_size);\n \t\tpre_actions = sfx_actions + actions_n;\n-\t\tmtr_tag_id = flow_meter_split_prep(dev, items, sfx_items,\n+\t\tmtr_tag_id = flow_meter_split_prep(dev, fm, items, sfx_items,\n \t\t\t\t\t\t   actions, sfx_actions,\n-\t\t\t\t\t\t   pre_actions);\n+\t\t\t\t\t\t   pre_actions, error);\n \t\tif (!mtr_tag_id) {\n \t\t\tret = -rte_errno;\n \t\t\tgoto exit;\n@@ -5245,10 +5302,12 @@ flow_create_split_meter(struct rte_eth_dev *dev,\n \t\t\t\t\t      attr, items, pre_actions,\n \t\t\t\t\t      flow_split_info, error);\n \t\tif (ret) {\n+\t\t\tmlx5_ipool_free(fm->flow_ipool, mtr_tag_id);\n \t\t\tret = -rte_errno;\n \t\t\tgoto exit;\n \t\t}\n \t\tdev_flow->handle->split_flow_id = mtr_tag_id;\n+\t\tdev_flow->handle->is_meter_flow_id = 1;\n \t\t/* Setting the sfx group atrr. */\n \t\tsfx_attr.group = sfx_attr.transfer ?\n \t\t\t\t(MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :\n@@ -6520,20 +6579,17 @@ mlx5_flow_ops_get(struct rte_eth_dev *dev __rte_unused,\n  *\n  * @param[in] dev\n  *   Pointer to Ethernet device.\n- * @param[in] fm\n- *   Pointer to the flow meter.\n  *\n  * @return\n  *   Pointer to table set on success, NULL otherwise.\n  */\n struct mlx5_meter_domains_infos *\n-mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,\n-\t\t\t  const struct mlx5_flow_meter *fm)\n+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)\n {\n \tconst struct mlx5_flow_driver_ops *fops;\n \n \tfops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);\n-\treturn fops->create_mtr_tbls(dev, fm);\n+\treturn fops->create_mtr_tbls(dev);\n }\n \n /**\n@@ -6558,7 +6614,7 @@ mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,\n }\n \n /**\n- * Create policer rules.\n+ * Prepare policer rules.\n  *\n  * @param[in] dev\n  *   Pointer to Ethernet device.\n@@ -6571,14 +6627,14 @@ mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,\n  *   0 on success, -1 otherwise.\n  */\n int\n-mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,\n+mlx5_flow_prepare_policer_rules(struct rte_eth_dev *dev,\n \t\t\t       struct mlx5_flow_meter *fm,\n \t\t\t       const struct rte_flow_attr *attr)\n {\n \tconst struct mlx5_flow_driver_ops *fops;\n \n \tfops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);\n-\treturn fops->create_policer_rules(dev, fm, attr);\n+\treturn fops->prepare_policer_rules(dev, fm, attr);\n }\n \n /**\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nindex 8324e188e1..c92e746a04 100644\n--- a/drivers/net/mlx5/mlx5_flow.h\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -79,7 +79,7 @@ enum mlx5_feature_name {\n \tMLX5_APP_TAG,\n \tMLX5_COPY_MARK,\n \tMLX5_MTR_COLOR,\n-\tMLX5_MTR_SFX,\n+\tMLX5_MTR_ID,\n \tMLX5_ASO_FLOW_HIT,\n };\n \n@@ -655,7 +655,8 @@ struct mlx5_flow_handle {\n \tuint64_t layers;\n \t/**< Bit-fields of present layers, see MLX5_FLOW_LAYER_*. */\n \tvoid *drv_flow; /**< pointer to driver flow object. */\n-\tuint32_t split_flow_id:28; /**< Sub flow unique match flow id. */\n+\tuint32_t split_flow_id:27; /**< Sub flow unique match flow id. */\n+\tuint32_t is_meter_flow_id:1; /**< Indate if flow_id is for meter. */\n \tuint32_t mark:1; /**< Metadate rxq mark flag. */\n \tuint32_t fate_action:3; /**< Fate action type. */\n \tunion {\n@@ -842,14 +843,16 @@ struct mlx5_meter_domain_info {\n \t/**< Meter table. */\n \tstruct mlx5_flow_tbl_resource *sfx_tbl;\n \t/**< Meter suffix table. */\n-\tvoid *any_matcher;\n-\t/**< Meter color not match default criteria. */\n-\tvoid *color_matcher;\n-\t/**< Meter color match criteria. */\n+\tstruct mlx5_flow_dv_matcher *drop_matcher;\n+\t/**< Matcher for Drop. */\n+\tstruct mlx5_flow_dv_matcher *color_matcher;\n+\t/**< Matcher for Color. */\n \tvoid *jump_actn;\n \t/**< Meter match action. */\n-\tvoid *policer_rules[RTE_MTR_DROPPED + 1];\n-\t/**< Meter policer for the match. */\n+\tvoid *green_rule;\n+\t/**< Meter green rule. */\n+\tvoid *drop_rule;\n+\t/**< Meter drop rule. */\n };\n \n /* Meter table set for TX RX FDB. */\n@@ -862,10 +865,10 @@ struct mlx5_meter_domains_infos {\n \t/**< RX meter table. */\n \tstruct mlx5_meter_domain_info transfer;\n \t/**< FDB meter table. */\n-\tvoid *drop_actn;\n-\t/**< Drop action as not matched. */\n-\tvoid *count_actns[RTE_MTR_DROPPED + 1];\n-\t/**< Counters for match and unmatched statistics. */\n+\tvoid *green_count;\n+\t/**< Counters for green rule. */\n+\tvoid *drop_count;\n+\t/**< Counters for green rule. */\n \tuint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];\n \t/**< Flow meter parameter. */\n \tsize_t fmp_size;\n@@ -928,6 +931,8 @@ struct mlx5_flow_meter {\n \t/**< Meter state. */\n \tuint32_t shared:1;\n \t/**< Meter shared or not. */\n+\tstruct mlx5_indexed_pool *flow_ipool;\n+\t/**< Index pool for flow id. */\n };\n \n /* RFC2697 parameter structure. */\n@@ -1148,6 +1153,7 @@ struct mlx5_flow_workspace {\n \tstruct mlx5_flow_rss_desc rss_desc;\n \tuint32_t rssq_num; /* Allocated queue num in rss_desc. */\n \tuint32_t flow_idx; /* Intermediate device flow index. */\n+\tstruct mlx5_flow_meter *fm; /* Pointer to the meter in flow. */\n };\n \n struct mlx5_flow_split_info {\n@@ -1188,8 +1194,7 @@ typedef int (*mlx5_flow_query_t)(struct rte_eth_dev *dev,\n \t\t\t\t void *data,\n \t\t\t\t struct rte_flow_error *error);\n typedef struct mlx5_meter_domains_infos *(*mlx5_flow_create_mtr_tbls_t)\n-\t\t\t\t\t    (struct rte_eth_dev *dev,\n-\t\t\t\t\t     const struct mlx5_flow_meter *fm);\n+\t\t\t\t\t    (struct rte_eth_dev *dev);\n typedef int (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,\n \t\t\t\t\tstruct mlx5_meter_domains_infos *tbls);\n typedef int (*mlx5_flow_create_policer_rules_t)\n@@ -1252,7 +1257,7 @@ struct mlx5_flow_driver_ops {\n \tmlx5_flow_query_t query;\n \tmlx5_flow_create_mtr_tbls_t create_mtr_tbls;\n \tmlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;\n-\tmlx5_flow_create_policer_rules_t create_policer_rules;\n+\tmlx5_flow_create_policer_rules_t prepare_policer_rules;\n \tmlx5_flow_destroy_policer_rules_t destroy_policer_rules;\n \tmlx5_flow_counter_alloc_t counter_alloc;\n \tmlx5_flow_counter_free_t counter_free;\n@@ -1452,11 +1457,10 @@ int mlx5_flow_validate_item_ecpri(const struct rte_flow_item *item,\n \t\t\t\t  const struct rte_flow_item_ecpri *acc_mask,\n \t\t\t\t  struct rte_flow_error *error);\n struct mlx5_meter_domains_infos *mlx5_flow_create_mtr_tbls\n-\t\t\t\t\t(struct rte_eth_dev *dev,\n-\t\t\t\t\t const struct mlx5_flow_meter *fm);\n+\t\t\t\t\t(struct rte_eth_dev *dev);\n int mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,\n \t\t\t       struct mlx5_meter_domains_infos *tbl);\n-int mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,\n+int mlx5_flow_prepare_policer_rules(struct rte_eth_dev *dev,\n \t\t\t\t   struct mlx5_flow_meter *fm,\n \t\t\t\t   const struct rte_flow_attr *attr);\n int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,\ndiff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c\nindex 23e5849783..ce9857d3f7 100644\n--- a/drivers/net/mlx5/mlx5_flow_dv.c\n+++ b/drivers/net/mlx5/mlx5_flow_dv.c\n@@ -10982,14 +10982,12 @@ flow_dv_translate(struct rte_eth_dev *dev,\n \t\tconst struct rte_flow_action_rss *rss;\n \t\tconst struct rte_flow_action *action = actions;\n \t\tconst uint8_t *rss_key;\n-\t\tconst struct rte_flow_action_meter *mtr;\n \t\tstruct mlx5_flow_tbl_resource *tbl;\n \t\tstruct mlx5_aso_age_action *age_act;\n \t\tuint32_t port_id = 0;\n \t\tstruct mlx5_flow_dv_port_id_action_resource port_id_resource;\n \t\tint action_type = actions->type;\n \t\tconst struct rte_flow_action *found_action = NULL;\n-\t\tstruct mlx5_flow_meter *fm = NULL;\n \t\tuint32_t jump_group = 0;\n \n \t\tif (!mlx5_flow_os_action_supported(action_type))\n@@ -11414,33 +11412,13 @@ flow_dv_translate(struct rte_eth_dev *dev,\n \t\t\t\t\tMLX5_FLOW_FATE_DEFAULT_MISS;\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_METER:\n-\t\t\tmtr = actions->conf;\n-\t\t\tif (!flow->meter) {\n-\t\t\t\tfm = mlx5_flow_meter_attach(priv, mtr->mtr_id,\n-\t\t\t\t\t\t\t    attr, error);\n-\t\t\t\tif (!fm)\n-\t\t\t\t\treturn rte_flow_error_set(error,\n-\t\t\t\t\t\trte_errno,\n-\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n-\t\t\t\t\t\tNULL,\n-\t\t\t\t\t\t\"meter not found \"\n-\t\t\t\t\t\t\"or invalid parameters\");\n-\t\t\t\tflow->meter = fm->idx;\n-\t\t\t}\n+\t\t\tif (!wks->fm)\n+\t\t\t\treturn rte_flow_error_set(error, rte_errno,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t\tNULL, \"Failed to get meter in flow.\");\n \t\t\t/* Set the meter action. */\n-\t\t\tif (!fm) {\n-\t\t\t\tfm = mlx5_ipool_get(priv->sh->ipool\n-\t\t\t\t\t\t[MLX5_IPOOL_MTR], flow->meter);\n-\t\t\t\tif (!fm)\n-\t\t\t\t\treturn rte_flow_error_set(error,\n-\t\t\t\t\t\trte_errno,\n-\t\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ACTION,\n-\t\t\t\t\t\tNULL,\n-\t\t\t\t\t\t\"meter not found \"\n-\t\t\t\t\t\t\"or invalid parameters\");\n-\t\t\t}\n \t\t\tdev_flow->dv.actions[actions_n++] =\n-\t\t\t\tfm->mfts->meter_action;\n+\t\t\t\twks->fm->mfts->meter_action;\n \t\t\taction_flags |= MLX5_FLOW_ACTION_METER;\n \t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:\n@@ -12536,6 +12514,7 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)\n {\n \tstruct mlx5_flow_handle *dev_handle;\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_meter *fm = NULL;\n \tuint32_t srss = 0;\n \n \tif (!flow)\n@@ -12546,8 +12525,6 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)\n \t\tflow->counter = 0;\n \t}\n \tif (flow->meter) {\n-\t\tstruct mlx5_flow_meter *fm;\n-\n \t\tfm = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR],\n \t\t\t\t    flow->meter);\n \t\tif (fm)\n@@ -12589,6 +12566,10 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)\n \t\t\tflow_dv_fate_resource_release(dev, dev_handle);\n \t\telse if (!srss)\n \t\t\tsrss = dev_handle->rix_srss;\n+\t\tif (fm && dev_handle->is_meter_flow_id &&\n+\t\t    dev_handle->split_flow_id)\n+\t\t\tmlx5_ipool_free(fm->flow_ipool,\n+\t\t\t\t\tdev_handle->split_flow_id);\n \t\tmlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],\n \t\t\t   tmp_idx);\n \t}\n@@ -13274,49 +13255,20 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,\n \n \tif (!mtd || !priv->config.dv_flow_en)\n \t\treturn 0;\n-\tif (mtd->ingress.policer_rules[RTE_MTR_DROPPED])\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow\n-\t\t\t   (mtd->ingress.policer_rules[RTE_MTR_DROPPED]));\n-\tif (mtd->egress.policer_rules[RTE_MTR_DROPPED])\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow\n-\t\t\t   (mtd->egress.policer_rules[RTE_MTR_DROPPED]));\n-\tif (mtd->transfer.policer_rules[RTE_MTR_DROPPED])\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow\n-\t\t\t   (mtd->transfer.policer_rules[RTE_MTR_DROPPED]));\n-\tif (mtd->egress.color_matcher)\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow_matcher\n-\t\t\t   (mtd->egress.color_matcher));\n-\tif (mtd->egress.any_matcher)\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow_matcher\n-\t\t\t   (mtd->egress.any_matcher));\n \tif (mtd->egress.tbl)\n \t\tflow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.tbl);\n \tif (mtd->egress.sfx_tbl)\n \t\tflow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.sfx_tbl);\n-\tif (mtd->ingress.color_matcher)\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow_matcher\n-\t\t\t   (mtd->ingress.color_matcher));\n-\tif (mtd->ingress.any_matcher)\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow_matcher\n-\t\t\t   (mtd->ingress.any_matcher));\n \tif (mtd->ingress.tbl)\n \t\tflow_dv_tbl_resource_release(MLX5_SH(dev), mtd->ingress.tbl);\n \tif (mtd->ingress.sfx_tbl)\n \t\tflow_dv_tbl_resource_release(MLX5_SH(dev),\n \t\t\t\t\t     mtd->ingress.sfx_tbl);\n-\tif (mtd->transfer.color_matcher)\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow_matcher\n-\t\t\t   (mtd->transfer.color_matcher));\n-\tif (mtd->transfer.any_matcher)\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow_matcher\n-\t\t\t   (mtd->transfer.any_matcher));\n \tif (mtd->transfer.tbl)\n \t\tflow_dv_tbl_resource_release(MLX5_SH(dev), mtd->transfer.tbl);\n \tif (mtd->transfer.sfx_tbl)\n \t\tflow_dv_tbl_resource_release(MLX5_SH(dev),\n \t\t\t\t\t     mtd->transfer.sfx_tbl);\n-\tif (mtd->drop_actn)\n-\t\tclaim_zero(mlx5_flow_os_destroy_flow_action(mtd->drop_actn));\n \tmlx5_free(mtd);\n \treturn 0;\n }\n@@ -13335,37 +13287,17 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,\n  *   Table attribute.\n  * @param[in] transfer\n  *   Table attribute.\n- * @param[in] color_reg_c_idx\n- *   Reg C index for color match.\n  *\n  * @return\n- *   0 on success, -1 otherwise and rte_errno is set.\n+ *   0 on success, -1 otherwise.\n  */\n static int\n flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,\n \t\t\t   struct mlx5_meter_domains_infos *mtb,\n-\t\t\t   uint8_t egress, uint8_t transfer,\n-\t\t\t   uint32_t color_reg_c_idx)\n+\t\t\t   uint8_t egress, uint8_t transfer)\n {\n-\tstruct mlx5_priv *priv = dev->data->dev_private;\n-\tstruct mlx5_dev_ctx_shared *sh = priv->sh;\n-\tstruct mlx5_flow_dv_match_params mask = {\n-\t\t.size = sizeof(mask.buf),\n-\t};\n-\tstruct mlx5_flow_dv_match_params value = {\n-\t\t.size = sizeof(value.buf),\n-\t};\n-\tstruct mlx5dv_flow_matcher_attr dv_attr = {\n-\t\t.type = IBV_FLOW_ATTR_NORMAL,\n-\t\t.priority = 0,\n-\t\t.match_criteria_enable = 0,\n-\t\t.match_mask = (void *)&mask,\n-\t};\n-\tvoid *actions[METER_ACTIONS];\n-\tstruct mlx5_meter_domain_info *dtb;\n \tstruct rte_flow_error error;\n-\tint i = 0;\n-\tint ret;\n+\tstruct mlx5_meter_domain_info *dtb;\n \n \tif (transfer)\n \t\tdtb = &mtb->transfer;\n@@ -13390,41 +13322,7 @@ flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,\n \t\tDRV_LOG(ERR, \"Failed to create meter suffix table.\");\n \t\treturn -1;\n \t}\n-\t/* Create matchers, Any and Color. */\n-\tdv_attr.priority = 3;\n-\tdv_attr.match_criteria_enable = 0;\n-\tret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, dtb->tbl->obj,\n-\t\t\t\t\t       &dtb->any_matcher);\n-\tif (ret) {\n-\t\tDRV_LOG(ERR, \"Failed to create meter\"\n-\t\t\t     \" policer default matcher.\");\n-\t\tgoto error_exit;\n-\t}\n-\tdv_attr.priority = 0;\n-\tdv_attr.match_criteria_enable =\n-\t\t\t\t1 << MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;\n-\tflow_dv_match_meta_reg(mask.buf, value.buf, color_reg_c_idx,\n-\t\t\t       rte_col_2_mlx5_col(RTE_COLORS), UINT8_MAX);\n-\tret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, dtb->tbl->obj,\n-\t\t\t\t\t       &dtb->color_matcher);\n-\tif (ret) {\n-\t\tDRV_LOG(ERR, \"Failed to create meter policer color matcher.\");\n-\t\tgoto error_exit;\n-\t}\n-\tif (mtb->count_actns[RTE_MTR_DROPPED])\n-\t\tactions[i++] = mtb->count_actns[RTE_MTR_DROPPED];\n-\tactions[i++] = mtb->drop_actn;\n-\t/* Default rule: lowest priority, match any, actions: drop. */\n-\tret = mlx5_flow_os_create_flow(dtb->any_matcher, (void *)&value, i,\n-\t\t\t\t       actions,\n-\t\t\t\t       &dtb->policer_rules[RTE_MTR_DROPPED]);\n-\tif (ret) {\n-\t\tDRV_LOG(ERR, \"Failed to create meter policer drop rule.\");\n-\t\tgoto error_exit;\n-\t}\n \treturn 0;\n-error_exit:\n-\treturn -1;\n }\n \n /**\n@@ -13433,20 +13331,16 @@ flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,\n  *\n  * @param[in] dev\n  *   Pointer to Ethernet device.\n- * @param[in] fm\n- *   Pointer to the flow meter.\n  *\n  * @return\n  *   Pointer to table set on success, NULL otherwise and rte_errno is set.\n  */\n static struct mlx5_meter_domains_infos *\n-flow_dv_create_mtr_tbl(struct rte_eth_dev *dev,\n-\t\t       const struct mlx5_flow_meter *fm)\n+flow_dv_create_mtr_tbl(struct rte_eth_dev *dev)\n {\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n \tstruct mlx5_meter_domains_infos *mtb;\n \tint ret;\n-\tint i;\n \n \tif (!priv->mtr_en) {\n \t\trte_errno = ENOTSUP;\n@@ -13457,37 +13351,21 @@ flow_dv_create_mtr_tbl(struct rte_eth_dev *dev,\n \t\tDRV_LOG(ERR, \"Failed to allocate memory for meter.\");\n \t\treturn NULL;\n \t}\n-\t/* Create meter count actions */\n-\tfor (i = 0; i <= RTE_MTR_DROPPED; i++) {\n-\t\tstruct mlx5_flow_counter *cnt;\n-\t\tif (!fm->policer_stats.cnt[i])\n-\t\t\tcontinue;\n-\t\tcnt = flow_dv_counter_get_by_idx(dev,\n-\t\t      fm->policer_stats.cnt[i], NULL);\n-\t\tmtb->count_actns[i] = cnt->action;\n-\t}\n-\t/* Create drop action. */\n-\tret = mlx5_flow_os_create_flow_action_drop(&mtb->drop_actn);\n-\tif (ret) {\n-\t\tDRV_LOG(ERR, \"Failed to create drop action.\");\n-\t\tgoto error_exit;\n-\t}\n \t/* Egress meter table. */\n-\tret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0, priv->mtr_color_reg);\n+\tret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0);\n \tif (ret) {\n \t\tDRV_LOG(ERR, \"Failed to prepare egress meter table.\");\n \t\tgoto error_exit;\n \t}\n \t/* Ingress meter table. */\n-\tret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 0, priv->mtr_color_reg);\n+\tret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 0);\n \tif (ret) {\n \t\tDRV_LOG(ERR, \"Failed to prepare ingress meter table.\");\n \t\tgoto error_exit;\n \t}\n \t/* FDB meter table. */\n \tif (priv->config.dv_esw_en) {\n-\t\tret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 1,\n-\t\t\t\t\t\t priv->mtr_color_reg);\n+\t\tret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 1);\n \t\tif (ret) {\n \t\t\tDRV_LOG(ERR, \"Failed to prepare fdb meter table.\");\n \t\t\tgoto error_exit;\n@@ -13499,24 +13377,153 @@ flow_dv_create_mtr_tbl(struct rte_eth_dev *dev,\n \treturn NULL;\n }\n \n+/**\n+ * Destroy the meter table matchers.\n+ * Lock free, (mutex should be acquired by caller).\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in,out] dtb\n+ *   Pointer to DV meter table.\n+ *\n+ * @return\n+ *   Always 0.\n+ */\n+static int\n+flow_dv_destroy_mtr_matchers(struct rte_eth_dev *dev,\n+\t\t\t     struct mlx5_meter_domain_info *dtb)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_tbl_data_entry *tbl;\n+\n+\tif (!priv->config.dv_flow_en)\n+\t\treturn 0;\n+\tif (dtb->drop_matcher) {\n+\t\ttbl = container_of(dtb->drop_matcher->tbl, typeof(*tbl), tbl);\n+\t\tmlx5_cache_unregister(&tbl->matchers,\n+\t\t\t\t      &dtb->drop_matcher->entry);\n+\t\tdtb->drop_matcher = NULL;\n+\t}\n+\tif (dtb->color_matcher) {\n+\t\ttbl = container_of(dtb->color_matcher->tbl, typeof(*tbl), tbl);\n+\t\tmlx5_cache_unregister(&tbl->matchers,\n+\t\t\t\t      &dtb->color_matcher->entry);\n+\t\tdtb->color_matcher = NULL;\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * Create the matchers for meter table.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] color_reg_c_idx\n+ *   Reg C index for color match.\n+ * @param[in] mtr_id_reg_c_idx\n+ *   Reg C index for meter_id match.\n+ * @param[in] mtr_id_mask\n+ *   Mask for meter_id match criteria.\n+ * @param[in,out] dtb\n+ *   Pointer to DV meter table.\n+ * @param[out] error\n+ *   Perform verbose error reporting if not NULL.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+flow_dv_prepare_mtr_matchers(struct rte_eth_dev *dev,\n+\t\t\t     uint32_t color_reg_c_idx,\n+\t\t\t     uint32_t mtr_id_reg_c_idx,\n+\t\t\t     uint32_t mtr_id_mask,\n+\t\t\t     struct mlx5_meter_domain_info *dtb,\n+\t\t\t     struct rte_flow_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_tbl_data_entry *tbl_data;\n+\tstruct mlx5_cache_entry *entry;\n+\tstruct mlx5_flow_dv_matcher matcher = {\n+\t\t.mask = {\n+\t\t\t.size = sizeof(matcher.mask.buf) -\n+\t\t\t\tMLX5_ST_SZ_BYTES(fte_match_set_misc4),\n+\t\t},\n+\t\t.tbl = dtb->tbl,\n+\t};\n+\tstruct mlx5_flow_dv_match_params value = {\n+\t\t.size = sizeof(value.buf) -\n+\t\t\tMLX5_ST_SZ_BYTES(fte_match_set_misc4),\n+\t};\n+\tstruct mlx5_flow_cb_ctx ctx = {\n+\t\t.error = error,\n+\t\t.data = &matcher,\n+\t};\n+\n+\ttbl_data = container_of(dtb->tbl, struct mlx5_flow_tbl_data_entry, tbl);\n+\tif (!dtb->drop_matcher) {\n+\t\t/* Create matchers for Drop. */\n+\t\tflow_dv_match_meta_reg(matcher.mask.buf, value.buf,\n+\t\t\t\t       mtr_id_reg_c_idx, 0, mtr_id_mask);\n+\t\tmatcher.priority = MLX5_REG_BITS * 2 - priv->max_mtr_bits;\n+\t\tmatcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,\n+\t\t\t\t\tmatcher.mask.size);\n+\t\tentry = mlx5_cache_register(&tbl_data->matchers, &ctx);\n+\t\tif (!entry) {\n+\t\t\tDRV_LOG(ERR, \"Failed to register meter drop matcher.\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tdtb->drop_matcher =\n+\t\t\tcontainer_of(entry, struct mlx5_flow_dv_matcher, entry);\n+\t}\n+\tif (!dtb->color_matcher) {\n+\t\t/* Create matchers for Color + meter_id. */\n+\t\tif (priv->mtr_reg_share) {\n+\t\t\tflow_dv_match_meta_reg(matcher.mask.buf, value.buf,\n+\t\t\t\t\tcolor_reg_c_idx, 0,\n+\t\t\t\t\t(mtr_id_mask |\n+\t\t\t\t\t LS32_MASK(MLX5_MTR_COLOR_BITS)));\n+\t\t} else {\n+\t\t\tflow_dv_match_meta_reg(matcher.mask.buf, value.buf,\n+\t\t\t\t\tcolor_reg_c_idx, 0,\n+\t\t\t\t\tLS32_MASK(MLX5_MTR_COLOR_BITS));\n+\t\t\tflow_dv_match_meta_reg(matcher.mask.buf, value.buf,\n+\t\t\t\t\tmtr_id_reg_c_idx, 0, mtr_id_mask);\n+\t\t}\n+\t\tmatcher.priority = MLX5_REG_BITS - priv->max_mtr_bits;\n+\t\tmatcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,\n+\t\t\t\t\tmatcher.mask.size);\n+\t\tentry = mlx5_cache_register(&tbl_data->matchers, &ctx);\n+\t\tif (!entry) {\n+\t\t\tDRV_LOG(ERR, \"Failed to register meter color matcher.\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tdtb->color_matcher =\n+\t\t\tcontainer_of(entry, struct mlx5_flow_dv_matcher, entry);\n+\t}\n+\treturn 0;\n+}\n+\n /**\n  * Destroy domain policer rule.\n  *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n  * @param[in] dt\n  *   Pointer to domain table.\n  */\n static void\n-flow_dv_destroy_domain_policer_rule(struct mlx5_meter_domain_info *dt)\n+flow_dv_destroy_domain_policer_rule(struct rte_eth_dev *dev,\n+\t\t\t\t    struct mlx5_meter_domain_info *dt)\n {\n-\tint i;\n-\n-\tfor (i = 0; i < RTE_MTR_DROPPED; i++) {\n-\t\tif (dt->policer_rules[i]) {\n-\t\t\tclaim_zero(mlx5_flow_os_destroy_flow\n-\t\t\t\t   (dt->policer_rules[i]));\n-\t\t\tdt->policer_rules[i] = NULL;\n-\t\t}\n+\tif (dt->drop_rule) {\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(dt->drop_rule));\n+\t\tdt->drop_rule = NULL;\n+\t}\n+\tif (dt->green_rule) {\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(dt->green_rule));\n+\t\tdt->green_rule = NULL;\n \t}\n+\tflow_dv_destroy_mtr_matchers(dev, dt);\n \tif (dt->jump_actn) {\n \t\tclaim_zero(mlx5_flow_os_destroy_flow_action(dt->jump_actn));\n \t\tdt->jump_actn = NULL;\n@@ -13537,7 +13544,7 @@ flow_dv_destroy_domain_policer_rule(struct mlx5_meter_domain_info *dt)\n  *   Always 0.\n  */\n static int\n-flow_dv_destroy_policer_rules(struct rte_eth_dev *dev __rte_unused,\n+flow_dv_destroy_policer_rules(struct rte_eth_dev *dev,\n \t\t\t      const struct mlx5_flow_meter *fm,\n \t\t\t      const struct rte_flow_attr *attr)\n {\n@@ -13546,39 +13553,55 @@ flow_dv_destroy_policer_rules(struct rte_eth_dev *dev __rte_unused,\n \tif (!mtb)\n \t\treturn 0;\n \tif (attr->egress)\n-\t\tflow_dv_destroy_domain_policer_rule(&mtb->egress);\n+\t\tflow_dv_destroy_domain_policer_rule(dev, &mtb->egress);\n \tif (attr->ingress)\n-\t\tflow_dv_destroy_domain_policer_rule(&mtb->ingress);\n+\t\tflow_dv_destroy_domain_policer_rule(dev, &mtb->ingress);\n \tif (attr->transfer)\n-\t\tflow_dv_destroy_domain_policer_rule(&mtb->transfer);\n+\t\tflow_dv_destroy_domain_policer_rule(dev, &mtb->transfer);\n \treturn 0;\n }\n \n /**\n  * Create specify domain meter policer rule.\n  *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n  * @param[in] fm\n  *   Pointer to flow meter structure.\n  * @param[in] mtb\n  *   Pointer to DV meter table set.\n- * @param[in] mtr_reg_c\n- *   Color match REG_C.\n+ * @param[out] drop_rule\n+ *   The address of pointer saving drop rule.\n+ * @param[out] color_rule\n+ *   The address of pointer saving green rule.\n  *\n  * @return\n  *   0 on success, -1 otherwise.\n  */\n static int\n-flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,\n+flow_dv_create_policer_forward_rule(struct rte_eth_dev *dev,\n+\t\t\t\t    struct mlx5_flow_meter *fm,\n \t\t\t\t    struct mlx5_meter_domain_info *dtb,\n-\t\t\t\t    uint8_t mtr_reg_c)\n+\t\t\t\t    void **drop_rule,\n+\t\t\t\t    void **green_rule)\n {\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n \tstruct mlx5_flow_dv_match_params matcher = {\n-\t\t.size = sizeof(matcher.buf),\n+\t\t.size = sizeof(matcher.buf) -\n+\t\t\tMLX5_ST_SZ_BYTES(fte_match_set_misc4),\n \t};\n \tstruct mlx5_flow_dv_match_params value = {\n-\t\t.size = sizeof(value.buf),\n+\t\t.size = sizeof(value.buf) -\n+\t\t\tMLX5_ST_SZ_BYTES(fte_match_set_misc4),\n \t};\n \tstruct mlx5_meter_domains_infos *mtb = fm->mfts;\n+\tstruct rte_flow_error error;\n+\tuint32_t color_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR,\n+\t\t\t\t\t\t    0, &error);\n+\tuint32_t mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,\n+\t\t\t\t\t\t     0, &error);\n+\tuint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;\n+\tuint32_t mtr_id_mask = LS32_MASK(priv->max_mtr_bits) << mtr_id_offset;\n \tvoid *actions[METER_ACTIONS];\n \tint i;\n \tint ret = 0;\n@@ -13591,25 +13614,52 @@ flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,\n \t\tDRV_LOG(ERR, \"Failed to create policer jump action.\");\n \t\tgoto error;\n \t}\n-\tfor (i = 0; i < RTE_MTR_DROPPED; i++) {\n-\t\tint j = 0;\n-\n-\t\tflow_dv_match_meta_reg(matcher.buf, value.buf, mtr_reg_c,\n-\t\t\t\t       rte_col_2_mlx5_col(i), UINT8_MAX);\n-\t\tif (mtb->count_actns[i])\n-\t\t\tactions[j++] = mtb->count_actns[i];\n-\t\tif (fm->action[i] == MTR_POLICER_ACTION_DROP)\n-\t\t\tactions[j++] = mtb->drop_actn;\n-\t\telse\n-\t\t\tactions[j++] = dtb->jump_actn;\n-\t\tret = mlx5_flow_os_create_flow(dtb->color_matcher,\n-\t\t\t\t\t       (void *)&value, j, actions,\n-\t\t\t\t\t       &dtb->policer_rules[i]);\n+\t/* Prepare matchers. */\n+\tif (!dtb->drop_matcher || !dtb->color_matcher) {\n+\t\tret = flow_dv_prepare_mtr_matchers(dev, color_reg_c,\n+\t\t\t\t\t\t   mtr_id_reg_c, mtr_id_mask,\n+\t\t\t\t\t\t   dtb, &error);\n \t\tif (ret) {\n-\t\t\tDRV_LOG(ERR, \"Failed to create policer rule.\");\n+\t\t\tDRV_LOG(ERR, \"Failed to setup matchers for mtr table.\");\n \t\t\tgoto error;\n \t\t}\n \t}\n+\t/* Create Drop flow, matching meter_id only. */\n+\ti = 0;\n+\tflow_dv_match_meta_reg(matcher.buf, value.buf, mtr_id_reg_c,\n+\t\t\t       (fm->idx << mtr_id_offset), UINT32_MAX);\n+\tif (mtb->drop_count)\n+\t\tactions[i++] = mtb->drop_count;\n+\tactions[i++] = priv->sh->esw_drop_action;\n+\tret = mlx5_flow_os_create_flow(dtb->drop_matcher->matcher_object,\n+\t\t\t\t       (void *)&value, i, actions, drop_rule);\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"Failed to create meter policer drop rule.\");\n+\t\tgoto error;\n+\t}\n+\t/* Create flow matching Green color + meter_id. */\n+\ti = 0;\n+\tif (priv->mtr_reg_share) {\n+\t\tflow_dv_match_meta_reg(matcher.buf, value.buf, color_reg_c,\n+\t\t\t\t       ((fm->idx << mtr_id_offset) |\n+\t\t\t\t\trte_col_2_mlx5_col(RTE_COLOR_GREEN)),\n+\t\t\t\t       UINT32_MAX);\n+\t} else {\n+\t\tflow_dv_match_meta_reg(matcher.buf, value.buf, color_reg_c,\n+\t\t\t\t       rte_col_2_mlx5_col(RTE_COLOR_GREEN),\n+\t\t\t\t       UINT32_MAX);\n+\t\tflow_dv_match_meta_reg(matcher.buf, value.buf, mtr_id_reg_c,\n+\t\t\t\t       fm->idx, UINT32_MAX);\n+\t}\n+\tif (mtb->green_count)\n+\t\tactions[i++] = mtb->green_count;\n+\tactions[i++] = dtb->jump_actn;\n+\tret = mlx5_flow_os_create_flow(dtb->color_matcher->matcher_object,\n+\t\t\t\t       (void *)&value, i, actions, green_rule);\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"Failed to create meter policer color rule.\");\n+\t\tgoto error;\n+\t}\n \treturn 0;\n error:\n \trte_errno = errno;\n@@ -13617,7 +13667,8 @@ flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,\n }\n \n /**\n- * Create policer rules.\n+ * Prepare policer rules for all domains.\n+ * If meter already initialized, this will replace all old rules with new ones.\n  *\n  * @param[in] dev\n  *   Pointer to Ethernet device.\n@@ -13630,41 +13681,107 @@ flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,\n  *   0 on success, -1 otherwise.\n  */\n static int\n-flow_dv_create_policer_rules(struct rte_eth_dev *dev,\n-\t\t\t     struct mlx5_flow_meter *fm,\n-\t\t\t     const struct rte_flow_attr *attr)\n+flow_dv_prepare_policer_rules(struct rte_eth_dev *dev,\n+\t\t\t      struct mlx5_flow_meter *fm,\n+\t\t\t      const struct rte_flow_attr *attr)\n {\n-\tstruct mlx5_priv *priv = dev->data->dev_private;\n \tstruct mlx5_meter_domains_infos *mtb = fm->mfts;\n+\tbool initialized = false;\n+\tstruct mlx5_flow_counter *cnt;\n+\tvoid *egress_drop_rule = NULL;\n+\tvoid *egress_green_rule = NULL;\n+\tvoid *ingress_drop_rule = NULL;\n+\tvoid *ingress_green_rule = NULL;\n+\tvoid *transfer_drop_rule = NULL;\n+\tvoid *transfer_green_rule = NULL;\n \tint ret;\n \n+\t/* Get the statistics counters for green/drop. */\n+\tif (fm->policer_stats.cnt[RTE_COLOR_GREEN]) {\n+\t\tcnt = flow_dv_counter_get_by_idx(dev,\n+\t\t\t\t\tfm->policer_stats.cnt[RTE_COLOR_GREEN],\n+\t\t\t\t\tNULL);\n+\t\tmtb->green_count = cnt->action;\n+\t} else {\n+\t\tmtb->green_count = NULL;\n+\t}\n+\tif (fm->policer_stats.cnt[RTE_MTR_DROPPED]) {\n+\t\tcnt = flow_dv_counter_get_by_idx(dev,\n+\t\t\t\t\tfm->policer_stats.cnt[RTE_MTR_DROPPED],\n+\t\t\t\t\tNULL);\n+\t\tmtb->drop_count = cnt->action;\n+\t} else {\n+\t\tmtb->drop_count = NULL;\n+\t}\n+\t/**\n+\t * If flow meter has been initilized, all policer rules\n+\t * are created. So can get if meter initialized by checking\n+\t * any policer rule.\n+\t */\n+\tif (mtb->egress.drop_rule)\n+\t\tinitialized = true;\n \tif (attr->egress) {\n-\t\tret = flow_dv_create_policer_forward_rule(fm, &mtb->egress,\n-\t\t\t\t\t\tpriv->mtr_color_reg);\n+\t\tret = flow_dv_create_policer_forward_rule(dev,\n+\t\t\t\tfm, &mtb->egress,\n+\t\t\t\t&egress_drop_rule, &egress_green_rule);\n \t\tif (ret) {\n \t\t\tDRV_LOG(ERR, \"Failed to create egress policer.\");\n \t\t\tgoto error;\n \t\t}\n \t}\n \tif (attr->ingress) {\n-\t\tret = flow_dv_create_policer_forward_rule(fm, &mtb->ingress,\n-\t\t\t\t\t\tpriv->mtr_color_reg);\n+\t\tret = flow_dv_create_policer_forward_rule(dev,\n+\t\t\t\tfm, &mtb->ingress,\n+\t\t\t\t&ingress_drop_rule, &ingress_green_rule);\n \t\tif (ret) {\n \t\t\tDRV_LOG(ERR, \"Failed to create ingress policer.\");\n \t\t\tgoto error;\n \t\t}\n \t}\n \tif (attr->transfer) {\n-\t\tret = flow_dv_create_policer_forward_rule(fm, &mtb->transfer,\n-\t\t\t\t\t\tpriv->mtr_color_reg);\n+\t\tret = flow_dv_create_policer_forward_rule(dev,\n+\t\t\t\tfm, &mtb->transfer,\n+\t\t\t\t&transfer_drop_rule, &transfer_green_rule);\n \t\tif (ret) {\n \t\t\tDRV_LOG(ERR, \"Failed to create transfer policer.\");\n \t\t\tgoto error;\n \t\t}\n \t}\n+\t/* Replace old flows if existing. */\n+\tif (mtb->egress.drop_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(mtb->egress.drop_rule));\n+\tif (mtb->egress.green_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(mtb->egress.green_rule));\n+\tif (mtb->ingress.drop_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(mtb->ingress.drop_rule));\n+\tif (mtb->ingress.green_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(mtb->ingress.green_rule));\n+\tif (mtb->transfer.drop_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(mtb->transfer.drop_rule));\n+\tif (mtb->transfer.green_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(mtb->transfer.green_rule));\n+\tmtb->egress.drop_rule = egress_drop_rule;\n+\tmtb->egress.green_rule = egress_green_rule;\n+\tmtb->ingress.drop_rule = ingress_drop_rule;\n+\tmtb->ingress.green_rule = ingress_green_rule;\n+\tmtb->transfer.drop_rule = transfer_drop_rule;\n+\tmtb->transfer.green_rule = transfer_green_rule;\n \treturn 0;\n error:\n-\tflow_dv_destroy_policer_rules(dev, fm, attr);\n+\tif (egress_drop_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(egress_drop_rule));\n+\tif (egress_green_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(egress_green_rule));\n+\tif (ingress_drop_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(ingress_drop_rule));\n+\tif (ingress_green_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(ingress_green_rule));\n+\tif (transfer_drop_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(transfer_drop_rule));\n+\tif (transfer_green_rule)\n+\t\tclaim_zero(mlx5_flow_os_destroy_flow(transfer_green_rule));\n+\tif (!initialized)\n+\t\tflow_dv_destroy_policer_rules(dev, fm, attr);\n \treturn -1;\n }\n \n@@ -13960,7 +14077,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {\n \t.query = flow_dv_query,\n \t.create_mtr_tbls = flow_dv_create_mtr_tbl,\n \t.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,\n-\t.create_policer_rules = flow_dv_create_policer_rules,\n+\t.prepare_policer_rules = flow_dv_prepare_policer_rules,\n \t.destroy_policer_rules = flow_dv_destroy_policer_rules,\n \t.counter_alloc = flow_dv_counter_allocate,\n \t.counter_free = flow_dv_counter_free,\ndiff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c\nindex dbc574b508..68f5c344cf 100644\n--- a/drivers/net/mlx5/mlx5_flow_meter.c\n+++ b/drivers/net/mlx5/mlx5_flow_meter.c\n@@ -474,6 +474,12 @@ mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,\n \t\t\t\t\t       MTR_POLICER_ACTION_COLOR_RED };\n \tint i;\n \n+\t/* Meter must use global drop action. */\n+\tif (!priv->sh->esw_drop_action)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_MTR_PARAMS,\n+\t\t\t\t\t  NULL,\n+\t\t\t\t\t  \"No drop action ready for meter.\");\n \t/* Meter params must not be NULL. */\n \tif (params == NULL)\n \t\treturn -rte_mtr_error_set(error, EINVAL,\n@@ -630,9 +636,18 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,\n \t\t\t\t.egress = 1,\n \t\t\t\t.transfer = priv->config.dv_esw_en ? 1 : 0,\n \t\t\t};\n+\tstruct mlx5_indexed_pool_config flow_ipool_cfg = {\n+\t\t.size = 0,\n+\t\t.trunk_size = 64,\n+\t\t.need_lock = 1,\n+\t\t.type = \"mlx5_flow_mtr_flow_id_pool\",\n+\t};\n \tint ret;\n \tunsigned int i;\n \tuint32_t idx = 0;\n+\tuint8_t mtr_id_bits;\n+\tuint8_t mtr_reg_bits = priv->mtr_reg_share ?\n+\t\t\t\tMLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;\n \n \tif (!priv->mtr_en)\n \t\treturn -rte_mtr_error_set(error, ENOTSUP,\n@@ -654,6 +669,13 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,\n \t\treturn -rte_mtr_error_set(error, ENOMEM,\n \t\t\t\t\t  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,\n \t\t\t\t\t  \"Memory alloc failed for meter.\");\n+\tmtr_id_bits = MLX5_REG_BITS - __builtin_clz(idx);\n+\tif ((mtr_id_bits + priv->max_mtr_flow_bits) > mtr_reg_bits) {\n+\t\tDRV_LOG(ERR, \"Meter number exceeds max limit.\");\n+\t\tgoto error;\n+\t}\n+\tif (mtr_id_bits > priv->max_mtr_bits)\n+\t\tpriv->max_mtr_bits = mtr_id_bits;\n \tfm->idx = idx;\n \t/* Fill the flow meter parameters. */\n \tfm->meter_id = meter_id;\n@@ -667,10 +689,10 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,\n \t\tif (!fm->policer_stats.cnt[i])\n \t\t\tgoto error;\n \t}\n-\tfm->mfts = mlx5_flow_create_mtr_tbls(dev, fm);\n+\tfm->mfts = mlx5_flow_create_mtr_tbls(dev);\n \tif (!fm->mfts)\n \t\tgoto error;\n-\tret = mlx5_flow_create_policer_rules(dev, fm, &attr);\n+\tret = mlx5_flow_prepare_policer_rules(dev, fm, &attr);\n \tif (ret)\n \t\tgoto error;\n \t/* Add to the flow meter list. */\n@@ -679,6 +701,9 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,\n \tfm->shared = !!shared;\n \tfm->policer_stats.stats_mask = params->stats_mask;\n \tfm->profile->ref_cnt++;\n+\tfm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);\n+\tif (!fm->flow_ipool)\n+\t\tgoto error;\n \trte_spinlock_init(&fm->sl);\n \treturn 0;\n error:\n@@ -749,6 +774,8 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,\n \t\tif (fm->policer_stats.cnt[i])\n \t\t\tmlx5_counter_free(dev, fm->policer_stats.cnt[i]);\n \t/* Free meter flow table */\n+\tif (fm->flow_ipool)\n+\t\tmlx5_ipool_destroy(fm->flow_ipool);\n \tmlx5_flow_destroy_policer_rules(dev, fm, &attr);\n \tmlx5_flow_destroy_mtr_tbls(dev, fm->mfts);\n \tmlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], fm->idx);\n@@ -1153,30 +1180,24 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id)\n  *\n  * @param [in] priv\n  *  Pointer to mlx5 private data.\n- * @param [in] meter_id\n- *  Flow meter id.\n+ * @param[in] fm\n+ *   Pointer to flow meter.\n  * @param [in] attr\n  *  Pointer to flow attributes.\n  * @param [out] error\n  *  Pointer to error structure.\n  *\n- * @return the flow meter pointer, NULL otherwise.\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-struct mlx5_flow_meter *\n-mlx5_flow_meter_attach(struct mlx5_priv *priv, uint32_t meter_id,\n+int\n+mlx5_flow_meter_attach(struct mlx5_priv *priv,\n+\t\t       struct mlx5_flow_meter *fm,\n \t\t       const struct rte_flow_attr *attr,\n \t\t       struct rte_flow_error *error)\n {\n-\tstruct mlx5_flow_meter *fm;\n \tint ret = 0;\n \n-\tfm = mlx5_flow_meter_find(priv, meter_id);\n-\tif (fm == NULL) {\n-\t\trte_flow_error_set(error, ENOENT,\n-\t\t\t\t   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n-\t\t\t\t   \"Meter object id not valid\");\n-\t\treturn fm;\n-\t}\n \trte_spinlock_lock(&fm->sl);\n \tif (fm->mfts->meter_action) {\n \t\tif (fm->shared &&\n@@ -1210,7 +1231,7 @@ mlx5_flow_meter_attach(struct mlx5_priv *priv, uint32_t meter_id,\n \t\t\t\t   fm->mfts->meter_action ?\n \t\t\t\t   \"Meter attr not match\" :\n \t\t\t\t   \"Meter action create failed\");\n-\treturn ret ? NULL : fm;\n+\treturn ret ? -rte_errno : 0;\n }\n \n /**\n",
    "prefixes": [
        "v2",
        "02/13"
    ]
}