get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 116748,
    "url": "http://patches.dpdk.org/api/patches/116748/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20220923144334.27736-11-suanmingm@nvidia.com/",
    "project": {
        "id": 1,
        "url": "http://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": "<20220923144334.27736-11-suanmingm@nvidia.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20220923144334.27736-11-suanmingm@nvidia.com",
    "date": "2022-09-23T14:43:17",
    "name": "[10/27] net/mlx5: add HW steering meter action",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "8b76b178be70e3fcf6108eac08c52d19e142a6de",
    "submitter": {
        "id": 1887,
        "url": "http://patches.dpdk.org/api/people/1887/?format=api",
        "name": "Suanming Mou",
        "email": "suanmingm@nvidia.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20220923144334.27736-11-suanmingm@nvidia.com/mbox/",
    "series": [
        {
            "id": 24805,
            "url": "http://patches.dpdk.org/api/series/24805/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=24805",
            "date": "2022-09-23T14:43:07",
            "name": "net/mlx5: HW steering PMD update",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/24805/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/116748/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/116748/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 29E98A054A;\n\tFri, 23 Sep 2022 16:45:34 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 576A542BF3;\n\tFri, 23 Sep 2022 16:44:22 +0200 (CEST)",
            "from NAM11-BN8-obe.outbound.protection.outlook.com\n (mail-bn8nam11on2040.outbound.protection.outlook.com [40.107.236.40])\n by mails.dpdk.org (Postfix) with ESMTP id DD6C642BEB\n for <dev@dpdk.org>; Fri, 23 Sep 2022 16:44:19 +0200 (CEST)",
            "from DS7PR03CA0005.namprd03.prod.outlook.com (2603:10b6:5:3b8::10)\n by CH2PR12MB4213.namprd12.prod.outlook.com (2603:10b6:610:a4::24) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5654.20; Fri, 23 Sep\n 2022 14:44:16 +0000",
            "from DM6NAM11FT050.eop-nam11.prod.protection.outlook.com\n (2603:10b6:5:3b8:cafe::8b) by DS7PR03CA0005.outlook.office365.com\n (2603:10b6:5:3b8::10) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5654.20 via Frontend\n Transport; Fri, 23 Sep 2022 14:44:16 +0000",
            "from mail.nvidia.com (216.228.117.160) by\n DM6NAM11FT050.mail.protection.outlook.com (10.13.173.111) with Microsoft SMTP\n Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.5654.14 via Frontend Transport; Fri, 23 Sep 2022 14:44:16 +0000",
            "from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com\n (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 23 Sep\n 2022 07:44:06 -0700",
            "from nvidia.com (10.126.231.35) by rnnvmail201.nvidia.com\n (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 23 Sep\n 2022 07:44:04 -0700"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=jrfmgHnLOz8dCXYCY2dcoCFbjEi/c3qdLJv4CgvtWdb0t7P3FYpv7dPYLiHxJFtb6/agoKoAWfGc0VqdF52FJMA1T7gAb99senGvbB960T6lPxOUCffaRyrBbz++wXtetctgznGSdOdZ3mO1uFgHom0CMvAVlC1eSJHxQtzZUh04c28k+I3S4cRgzGzBiwHgLkfl6CSQfHmJ0l7jqnoejk74WeOIUIwI9GeG3OBOhXeEbFXOkrU4oyggQMo+0Ag/48FCf8iWMD9GjOytG64TPL3arr5JhIkjWAtOZJs2N++zNOwHVs+Q6PP7yOedjFxGyI4FqG6s0EPtWWMs9f0lyA==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector9901;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=8uGXPxZ5GCxlhC6b4GXsdYUv8YUKqoXoh2HKC6leMS0=;\n b=jITlNsvc2zUbu5aIyGKBwcB/MwW8/CUF8WYEI/KbEoY6PVqCqy0TtNE1Y+XKnPUlcq4tJtBuoQME+tMxIdiC6LWm5Ctxxjot9EAj0JVJsq/kQX9j+Ci8OyXp/mNPrUoj7EmDxaGokwPXLHv/gNw59DjcOy19gMF7kmCe+quHcidoukrW5VL0HO46WCaf7uxUVzF3jhhbU1Bz1CEy47Zd50DQqsUs9e059X9CJtu+iD8jleCzehywBXhf6gk+rnDkiY6jGENUE+y5/bcW4E5McXAidkJ5IgoS9iVhI4mQdm6etZ3zY5bbOF20t6AFfegV3FxLcyWXpsC5FdXepRUF0w==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass (sender ip is\n 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com;\n dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com;\n dkim=none (message not signed); arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com;\n s=selector2;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=8uGXPxZ5GCxlhC6b4GXsdYUv8YUKqoXoh2HKC6leMS0=;\n b=Ewu8folDhq9qfcysSw46lwUMsvh4bIyV9N2AuADtDgc3PMxtFp/XbyQvCJRX/sCCMk5tghL4XBn3XnmzzBJGCOJbsPT3tj/K/PjRu65IZEJOFQJ4roMY1tlVNBlIjKpGSThQJjcCxDAf6WumYrRxAcyTlyXgEPlkHiK0t0SQFCIKHhvbY0zmKGnsbAOCPN07KXY9xB1/kVx8uAzVbiHOynbDAlhBubpAR1xoVUSrhKl15vU4gPbPKxb+mF5AyGQKPt7wgaCRnZpwd2fhgiinn/Op8ieLcEbtOQue03OLdIGxj7iCTguDHwZQUD9sUfbYwo9qjuLWk3L6/CPoqgDxcQ==",
        "X-MS-Exchange-Authentication-Results": "spf=pass (sender IP is 216.228.117.160)\n smtp.mailfrom=nvidia.com;\n dkim=none (message not signed)\n header.d=none;dmarc=pass action=none header.from=nvidia.com;",
        "Received-SPF": "Pass (protection.outlook.com: domain of nvidia.com designates\n 216.228.117.160 as permitted sender) receiver=protection.outlook.com;\n client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C",
        "From": "Suanming Mou <suanmingm@nvidia.com>",
        "To": "Matan Azrad <matan@nvidia.com>, Viacheslav Ovsiienko\n <viacheslavo@nvidia.com>",
        "CC": "<dev@dpdk.org>, Alexander Kozyrev <akozyrev@nvidia.com>",
        "Subject": "[PATCH 10/27] net/mlx5: add HW steering meter action",
        "Date": "Fri, 23 Sep 2022 17:43:17 +0300",
        "Message-ID": "<20220923144334.27736-11-suanmingm@nvidia.com>",
        "X-Mailer": "git-send-email 2.18.1",
        "In-Reply-To": "<20220923144334.27736-1-suanmingm@nvidia.com>",
        "References": "<20220923144334.27736-1-suanmingm@nvidia.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.126.231.35]",
        "X-ClientProxiedBy": "rnnvmail201.nvidia.com (10.129.68.8) To\n rnnvmail201.nvidia.com (10.129.68.8)",
        "X-EOPAttributedMessage": "0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "DM6NAM11FT050:EE_|CH2PR12MB4213:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "25e21732-86d1-4531-c7d3-08da9d721722",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n N3XTNWHYLCGK0V3rt/zjaPvKAx3/dCmTiVdcZj3R5nqFzvtqVmNdNr0jK+1xQnRz4XBH2iFgt5lfOkdEnRp4DrnT2dF+ZBpT6LbYnRgYyf91ehAajKNsm7aao/mLJ1rR022L1ctpabmca3qQTa5NkMr6s5MTpUWAh0QKgxO/JfO+GnFZtwJyp5Bz3oht16ifKBnSTHz3xMpEn8JGAjPnLFmPlb81BRGx97o5m/zkOREZkxk/FXPq9fS5c6MsjsOP945z8lcGLtu3wwUb+2qc9R5ola/0Ex+zhtliggsWBqJVr9PSKAUbL/IajnZlKt+pH7NeBPhwJKHIvePYVzh2bP9KnR3EhRxjzE2qeLMhNyLZHmApPb+jCFIF/+/SUREokLy4hH82smrUE5TFAFvvwU+uzgx9KD4wf+gPwJOo/dwjvq5vNr1T3pTw6w5DZN1nD8iwCnxAtc0p2f8yUS4SqlFxO7gU5HTX7Z8oIA/ieoozYvJHgIonswTdTuS67zivQAiRKckPvGefgqRfPgod/7jSBkLRzVlto3fZ/3l/Htp6S+3vXdiepyoQWT02jVt+7vD9EnlBC0czxpI26/p5F3jr72b5nfrh89jS/PV8DvNRX1vzTvLOaI+Z4/VhRvhkTOUrD7FijX8Ud1NmPW3Q+YuHTbFWr2Yqf9c1PUlZJ25vVOlEBD2Mrk+1tskDfwSmoTTyKFmg6qvoXXeBtchHHiiogPe4azeNvimoaNAS8QkDgednHbprdPMO0x4Wp1K5y058sYqI0XEVMiKncjn113ZYsdPeHCJOXC6CC2v/w+Y=",
        "X-Forefront-Antispam-Report": "CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1;\n SRV:;\n IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE;\n SFS:(13230022)(4636009)(136003)(39860400002)(346002)(376002)(396003)(451199015)(36840700001)(40470700004)(46966006)(4326008)(70206006)(86362001)(8676002)(30864003)(8936002)(5660300002)(2906002)(6666004)(7696005)(41300700001)(16526019)(36860700001)(70586007)(107886003)(2616005)(336012)(47076005)(186003)(1076003)(6286002)(426003)(83380400001)(26005)(110136005)(316002)(7636003)(6636002)(356005)(82740400003)(478600001)(54906003)(36756003)(40460700003)(82310400005)(40480700001)(55016003)(579004)(559001)(309714004);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "Nvidia.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "23 Sep 2022 14:44:16.4772 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 25e21732-86d1-4531-c7d3-08da9d721722",
        "X-MS-Exchange-CrossTenant-Id": "43083d15-7273-40c1-b7db-39efd9ccc17a",
        "X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp": "\n TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160];\n Helo=[mail.nvidia.com]",
        "X-MS-Exchange-CrossTenant-AuthSource": "\n DM6NAM11FT050.eop-nam11.prod.protection.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "CH2PR12MB4213",
        "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"
    },
    "content": "From: Alexander Kozyrev <akozyrev@nvidia.com>\n\nThis commit adds meter action for HWS steering.\n\nHW steering meter is based on ASO. The number of meters will\nbe used by flows should be specified in advanced in the flow\nconfigure API.\n\nSigned-off-by: Alexander Kozyrev <akozyrev@nvidia.com>\n\nSigned-off-by: Alexander Kozyrev <akozyrev@nvidia.com>\n---\n drivers/net/mlx5/mlx5.h            |  58 +-\n drivers/net/mlx5/mlx5_flow.c       |  71 +++\n drivers/net/mlx5/mlx5_flow.h       |  50 ++\n drivers/net/mlx5/mlx5_flow_aso.c   |  30 +-\n drivers/net/mlx5/mlx5_flow_dv.c    |  25 -\n drivers/net/mlx5/mlx5_flow_hw.c    | 113 +++-\n drivers/net/mlx5/mlx5_flow_meter.c | 851 ++++++++++++++++++++++++++++-\n 7 files changed, 1138 insertions(+), 60 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex 3364c4735c..263b502d37 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -357,6 +357,9 @@ struct mlx5_hw_q {\n \tstruct mlx5_hw_q_job **job; /* LIFO header. */\n } __rte_cache_aligned;\n \n+\n+\n+\n #define MLX5_COUNTERS_PER_POOL 512\n #define MLX5_MAX_PENDING_QUERIES 4\n #define MLX5_CNT_CONTAINER_RESIZE 64\n@@ -782,15 +785,29 @@ struct mlx5_flow_meter_policy {\n \t/* Is meter action in policy table. */\n \tuint32_t hierarchy_drop_cnt:1;\n \t/* Is any meter in hierarchy contains drop_cnt. */\n+\tuint32_t skip_r:1;\n+\t/* If red color policy is skipped. */\n \tuint32_t skip_y:1;\n \t/* If yellow color policy is skipped. */\n \tuint32_t skip_g:1;\n \t/* If green color policy is skipped. */\n \tuint32_t mark:1;\n \t/* If policy contains mark action. */\n+\tuint32_t initialized:1;\n+\t/* Initialized. */\n+\tuint16_t group;\n+\t/* The group. */\n \trte_spinlock_t sl;\n \tuint32_t ref_cnt;\n \t/* Use count. */\n+\tstruct rte_flow_pattern_template *hws_item_templ;\n+\t/* Hardware steering item templates. */\n+\tstruct rte_flow_actions_template *hws_act_templ[MLX5_MTR_DOMAIN_MAX];\n+\t/* Hardware steering action templates. */\n+\tstruct rte_flow_template_table *hws_flow_table[MLX5_MTR_DOMAIN_MAX];\n+\t/* Hardware steering tables. */\n+\tstruct rte_flow *hws_flow_rule[MLX5_MTR_DOMAIN_MAX][RTE_COLORS];\n+\t/* Hardware steering rules. */\n \tstruct mlx5_meter_policy_action_container act_cnt[MLX5_MTR_RTE_COLORS];\n \t/* Policy actions container. */\n \tvoid *dr_drop_action[MLX5_MTR_DOMAIN_MAX];\n@@ -865,6 +882,7 @@ struct mlx5_flow_meter_info {\n \t */\n \tuint32_t transfer:1;\n \tuint32_t def_policy:1;\n+\tuint32_t initialized:1;\n \t/* Meter points to default policy. */\n \tuint32_t color_aware:1;\n \t/* Meter is color aware mode. */\n@@ -880,6 +898,10 @@ struct mlx5_flow_meter_info {\n \t/**< Flow meter action. */\n \tvoid *meter_action_y;\n \t/**< Flow meter action for yellow init_color. */\n+\tuint32_t meter_offset;\n+\t/**< Flow meter offset. */\n+\tuint16_t group;\n+\t/**< Flow meter group. */\n };\n \n /* PPS(packets per second) map to BPS(Bytes per second).\n@@ -914,6 +936,7 @@ struct mlx5_flow_meter_profile {\n \tuint32_t ref_cnt; /**< Use count. */\n \tuint32_t g_support:1; /**< If G color will be generated. */\n \tuint32_t y_support:1; /**< If Y color will be generated. */\n+\tuint32_t initialized:1; /**< Initialized. */\n };\n \n /* 2 meters in each ASO cache line */\n@@ -934,13 +957,20 @@ enum mlx5_aso_mtr_state {\n \tASO_METER_READY, /* CQE received. */\n };\n \n+/*aso flow meter type*/\n+enum mlx5_aso_mtr_type {\n+\tASO_METER_INDIRECT,\n+\tASO_METER_DIRECT,\n+};\n+\n /* Generic aso_flow_meter information. */\n struct mlx5_aso_mtr {\n \tLIST_ENTRY(mlx5_aso_mtr) next;\n+\tenum mlx5_aso_mtr_type type;\n \tstruct mlx5_flow_meter_info fm;\n \t/**< Pointer to the next aso flow meter structure. */\n \tuint8_t state; /**< ASO flow meter state. */\n-\tuint8_t offset;\n+\tuint32_t offset;\n };\n \n /* Generic aso_flow_meter pool structure. */\n@@ -964,6 +994,14 @@ struct mlx5_aso_mtr_pools_mng {\n \tstruct mlx5_aso_mtr_pool **pools; /* ASO flow meter pool array. */\n };\n \n+/* Bulk management structure for ASO flow meter. */\n+struct mlx5_mtr_bulk {\n+\tuint32_t size; /* Number of ASO objects. */\n+\tstruct mlx5dr_action *action; /* HWS action */\n+\tstruct mlx5_devx_obj *devx_obj; /* DEVX object. */\n+\tstruct mlx5_aso_mtr *aso; /* Array of ASO objects. */\n+};\n+\n /* Meter management structure for global flow meter resource. */\n struct mlx5_flow_mtr_mng {\n \tstruct mlx5_aso_mtr_pools_mng pools_mng;\n@@ -1017,6 +1055,7 @@ struct mlx5_flow_tbl_resource {\n #define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 3)\n #define MLX5_FLOW_TABLE_LEVEL_POLICY (MLX5_MAX_TABLES - 4)\n #define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_POLICY\n+#define MLX5_FLOW_TABLE_HWS_POLICY (MLX5_MAX_TABLES - 10)\n #define MLX5_MAX_TABLES_FDB UINT16_MAX\n #define MLX5_FLOW_TABLE_FACTOR 10\n \n@@ -1303,6 +1342,12 @@ TAILQ_HEAD(mlx5_mtr_profiles, mlx5_flow_meter_profile);\n /* MTR list. */\n TAILQ_HEAD(mlx5_legacy_flow_meters, mlx5_legacy_flow_meter);\n \n+struct mlx5_mtr_config {\n+\tuint32_t nb_meters; /**< Number of configured meters */\n+\tuint32_t nb_meter_profiles; /**< Number of configured meter profiles */\n+\tuint32_t nb_meter_policies; /**< Number of configured meter policies */\n+};\n+\n /* RSS description. */\n struct mlx5_flow_rss_desc {\n \tuint32_t level;\n@@ -1539,12 +1584,16 @@ struct mlx5_priv {\n \tstruct mlx5_nl_vlan_vmwa_context *vmwa_context; /* VLAN WA context. */\n \tstruct mlx5_hlist *mreg_cp_tbl;\n \t/* Hash table of Rx metadata register copy table. */\n+\tstruct mlx5_mtr_config mtr_config; /* Meter configuration */\n \tuint8_t mtr_sfx_reg; /* Meter prefix-suffix flow match REG_C. */\n \tuint8_t mtr_color_reg; /* Meter color match REG_C. */\n \tstruct mlx5_legacy_flow_meters flow_meters; /* MTR list. */\n \tstruct mlx5_l3t_tbl *mtr_profile_tbl; /* Meter index lookup table. */\n+\tstruct mlx5_flow_meter_profile *mtr_profile_arr; /* Profile array. */\n \tstruct mlx5_l3t_tbl *policy_idx_tbl; /* Policy index lookup table. */\n+\tstruct mlx5_flow_meter_policy *mtr_policy_arr; /* Policy array. */\n \tstruct mlx5_l3t_tbl *mtr_idx_tbl; /* Meter index lookup table. */\n+\tstruct mlx5_mtr_bulk mtr_bulk; /* Meter index mapping for HWS */\n \tuint8_t skip_default_rss_reta; /* Skip configuration of default reta. */\n \tuint8_t fdb_def_rule; /* Whether fdb jump to table 1 is configured. */\n \tstruct mlx5_mp_id mp_id; /* ID of a multi-process process */\n@@ -1579,6 +1628,7 @@ struct mlx5_priv {\n \n #define PORT_ID(priv) ((priv)->dev_data->port_id)\n #define ETH_DEV(priv) (&rte_eth_devices[PORT_ID(priv)])\n+#define CTRL_QUEUE_ID(priv) ((priv)->nb_queue - 1)\n \n struct rte_hairpin_peer_info {\n \tuint32_t qp_id;\n@@ -1890,6 +1940,10 @@ void mlx5_pmd_socket_uninit(void);\n \n /* mlx5_flow_meter.c */\n \n+int mlx5_flow_meter_init(struct rte_eth_dev *dev,\n+\t\t\t uint32_t nb_meters,\n+\t\t\t uint32_t nb_meter_profiles,\n+\t\t\t uint32_t nb_meter_policies);\n int mlx5_flow_meter_ops_get(struct rte_eth_dev *dev, void *arg);\n struct mlx5_flow_meter_info *mlx5_flow_meter_find(struct mlx5_priv *priv,\n \t\tuint32_t meter_id, uint32_t *mtr_idx);\n@@ -1964,7 +2018,7 @@ int mlx5_aso_flow_hit_queue_poll_stop(struct mlx5_dev_ctx_shared *sh);\n void mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh,\n \t\tenum mlx5_access_aso_opc_mod aso_opc_mod);\n int mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh,\n-\t\tstruct mlx5_aso_mtr *mtr);\n+\t\tstruct mlx5_aso_mtr *mtr, struct mlx5_mtr_bulk *bulk);\n int mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh,\n \t\tstruct mlx5_aso_mtr *mtr);\n int mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh,\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex b570ed7f69..fb3be940e5 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -8331,6 +8331,40 @@ mlx5_flow_port_configure(struct rte_eth_dev *dev,\n \treturn fops->configure(dev, port_attr, nb_queue, queue_attr, error);\n }\n \n+/**\n+ * Validate item template.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the rte_eth_dev structure.\n+ * @param[in] attr\n+ *   Pointer to the item template attributes.\n+ * @param[in] items\n+ *   The template item pattern.\n+ * @param[out] error\n+ *   Pointer to error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+int\n+mlx5_flow_pattern_validate(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_pattern_template_attr *attr,\n+\t\tconst struct rte_flow_item items[],\n+\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct mlx5_flow_driver_ops *fops;\n+\tstruct rte_flow_attr fattr = {0};\n+\n+\tif (flow_get_drv_type(dev, &fattr) != MLX5_FLOW_TYPE_HW) {\n+\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\"pattern validate with incorrect steering mode\");\n+\t\treturn -ENOTSUP;\n+\t}\n+\tfops = flow_get_drv_ops(MLX5_FLOW_TYPE_HW);\n+\treturn fops->pattern_validate(dev, attr, items, error);\n+}\n+\n /**\n  * Create flow item template.\n  *\n@@ -8396,6 +8430,43 @@ mlx5_flow_pattern_template_destroy(struct rte_eth_dev *dev,\n \treturn fops->pattern_template_destroy(dev, template, error);\n }\n \n+/**\n+ * Validate flow actions template.\n+ *\n+ * @param[in] dev\n+ *   Pointer to the rte_eth_dev structure.\n+ * @param[in] attr\n+ *   Pointer to the action template attributes.\n+ * @param[in] actions\n+ *   Associated actions (list terminated by the END action).\n+ * @param[in] masks\n+ *   List of actions that marks which of the action's member is constant.\n+ * @param[out] error\n+ *   Pointer to error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+int\n+mlx5_flow_actions_validate(struct rte_eth_dev *dev,\n+\t\t\tconst struct rte_flow_actions_template_attr *attr,\n+\t\t\tconst struct rte_flow_action actions[],\n+\t\t\tconst struct rte_flow_action masks[],\n+\t\t\tstruct rte_flow_error *error)\n+{\n+\tconst struct mlx5_flow_driver_ops *fops;\n+\tstruct rte_flow_attr fattr = {0};\n+\n+\tif (flow_get_drv_type(dev, &fattr) != MLX5_FLOW_TYPE_HW) {\n+\t\trte_flow_error_set(error, ENOTSUP,\n+\t\t\tRTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\"actions validate with incorrect steering mode\");\n+\t\treturn -ENOTSUP;\n+\t}\n+\tfops = flow_get_drv_ops(MLX5_FLOW_TYPE_HW);\n+\treturn fops->actions_validate(dev, attr, actions, masks, error);\n+}\n+\n /**\n  * Create flow item template.\n  *\ndiff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h\nindex 15c5826d8a..c5190b1d4f 100644\n--- a/drivers/net/mlx5/mlx5_flow.h\n+++ b/drivers/net/mlx5/mlx5_flow.h\n@@ -1653,6 +1653,11 @@ typedef int (*mlx5_flow_port_configure_t)\n \t\t\t uint16_t nb_queue,\n \t\t\t const struct rte_flow_queue_attr *queue_attr[],\n \t\t\t struct rte_flow_error *err);\n+typedef int (*mlx5_flow_pattern_validate_t)\n+\t\t\t(struct rte_eth_dev *dev,\n+\t\t\t const struct rte_flow_pattern_template_attr *attr,\n+\t\t\t const struct rte_flow_item items[],\n+\t\t\t struct rte_flow_error *error);\n typedef struct rte_flow_pattern_template *(*mlx5_flow_pattern_template_create_t)\n \t\t\t(struct rte_eth_dev *dev,\n \t\t\t const struct rte_flow_pattern_template_attr *attr,\n@@ -1662,6 +1667,12 @@ typedef int (*mlx5_flow_pattern_template_destroy_t)\n \t\t\t(struct rte_eth_dev *dev,\n \t\t\t struct rte_flow_pattern_template *template,\n \t\t\t struct rte_flow_error *error);\n+typedef int (*mlx5_flow_actions_validate_t)\n+\t\t\t(struct rte_eth_dev *dev,\n+\t\t\t const struct rte_flow_actions_template_attr *attr,\n+\t\t\t const struct rte_flow_action actions[],\n+\t\t\t const struct rte_flow_action masks[],\n+\t\t\t struct rte_flow_error *error);\n typedef struct rte_flow_actions_template *(*mlx5_flow_actions_template_create_t)\n \t\t\t(struct rte_eth_dev *dev,\n \t\t\t const struct rte_flow_actions_template_attr *attr,\n@@ -1778,8 +1789,10 @@ struct mlx5_flow_driver_ops {\n \tmlx5_flow_item_update_t item_update;\n \tmlx5_flow_info_get_t info_get;\n \tmlx5_flow_port_configure_t configure;\n+\tmlx5_flow_pattern_validate_t pattern_validate;\n \tmlx5_flow_pattern_template_create_t pattern_template_create;\n \tmlx5_flow_pattern_template_destroy_t pattern_template_destroy;\n+\tmlx5_flow_actions_validate_t actions_validate;\n \tmlx5_flow_actions_template_create_t actions_template_create;\n \tmlx5_flow_actions_template_destroy_t actions_template_destroy;\n \tmlx5_flow_table_create_t template_table_create;\n@@ -1861,6 +1874,8 @@ mlx5_aso_meter_by_idx(struct mlx5_priv *priv, uint32_t idx)\n \n \t/* Decrease to original index. */\n \tidx--;\n+\tif (priv->mtr_bulk.aso)\n+\t\treturn priv->mtr_bulk.aso + idx;\n \tMLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < pools_mng->n);\n \trte_rwlock_read_lock(&pools_mng->resize_mtrwl);\n \tpool = pools_mng->pools[idx / MLX5_ASO_MTRS_PER_POOL];\n@@ -1963,6 +1978,32 @@ mlx5_translate_tunnel_etypes(uint64_t pattern_flags)\n \n int flow_hw_q_flow_flush(struct rte_eth_dev *dev,\n \t\t\t struct rte_flow_error *error);\n+\n+/*\n+ * Convert rte_mtr_color to mlx5 color.\n+ *\n+ * @param[in] rcol\n+ *   rte_mtr_color.\n+ *\n+ * @return\n+ *   mlx5 color.\n+ */\n+static inline int\n+rte_col_2_mlx5_col(enum rte_color rcol)\n+{\n+\tswitch (rcol) {\n+\tcase RTE_COLOR_GREEN:\n+\t\treturn MLX5_FLOW_COLOR_GREEN;\n+\tcase RTE_COLOR_YELLOW:\n+\t\treturn MLX5_FLOW_COLOR_YELLOW;\n+\tcase RTE_COLOR_RED:\n+\t\treturn MLX5_FLOW_COLOR_RED;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\treturn MLX5_FLOW_COLOR_UNDEFINED;\n+}\n+\n int mlx5_flow_group_to_table(struct rte_eth_dev *dev,\n \t\t\t     const struct mlx5_flow_tunnel *tunnel,\n \t\t\t     uint32_t group, uint32_t *table,\n@@ -2346,4 +2387,13 @@ int mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev,\n \t\t\t\t\t uint32_t txq);\n int mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev);\n int mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev);\n+int mlx5_flow_actions_validate(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_actions_template_attr *attr,\n+\t\tconst struct rte_flow_action actions[],\n+\t\tconst struct rte_flow_action masks[],\n+\t\tstruct rte_flow_error *error);\n+int mlx5_flow_pattern_validate(struct rte_eth_dev *dev,\n+\t\tconst struct rte_flow_pattern_template_attr *attr,\n+\t\tconst struct rte_flow_item items[],\n+\t\tstruct rte_flow_error *error);\n #endif /* RTE_PMD_MLX5_FLOW_H_ */\ndiff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c\nindex 4129e3a9e0..60d0280367 100644\n--- a/drivers/net/mlx5/mlx5_flow_aso.c\n+++ b/drivers/net/mlx5/mlx5_flow_aso.c\n@@ -642,7 +642,8 @@ mlx5_aso_flow_hit_queue_poll_stop(struct mlx5_dev_ctx_shared *sh)\n static uint16_t\n mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh,\n \t\t\t       struct mlx5_aso_sq *sq,\n-\t\t\t       struct mlx5_aso_mtr *aso_mtr)\n+\t\t\t       struct mlx5_aso_mtr *aso_mtr,\n+\t\t\t       struct mlx5_mtr_bulk *bulk)\n {\n \tvolatile struct mlx5_aso_wqe *wqe = NULL;\n \tstruct mlx5_flow_meter_info *fm = NULL;\n@@ -653,6 +654,7 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh,\n \tuint32_t dseg_idx = 0;\n \tstruct mlx5_aso_mtr_pool *pool = NULL;\n \tuint32_t param_le;\n+\tint id;\n \n \trte_spinlock_lock(&sq->sqsl);\n \tres = size - (uint16_t)(sq->head - sq->tail);\n@@ -666,14 +668,19 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh,\n \t/* Fill next WQE. */\n \tfm = &aso_mtr->fm;\n \tsq->elts[sq->head & mask].mtr = aso_mtr;\n-\tpool = container_of(aso_mtr, struct mlx5_aso_mtr_pool,\n-\t\t\tmtrs[aso_mtr->offset]);\n-\twqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id +\n-\t\t\t(aso_mtr->offset >> 1));\n-\twqe->general_cseg.opcode = rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |\n-\t\t\t(ASO_OPC_MOD_POLICER <<\n-\t\t\tWQE_CSEG_OPC_MOD_OFFSET) |\n-\t\t\tsq->pi << WQE_CSEG_WQE_INDEX_OFFSET);\n+\tif (aso_mtr->type == ASO_METER_INDIRECT) {\n+\t\tpool = container_of(aso_mtr, struct mlx5_aso_mtr_pool,\n+\t\t\t\t    mtrs[aso_mtr->offset]);\n+\t\tid = pool->devx_obj->id;\n+\t} else {\n+\t\tid = bulk->devx_obj->id;\n+\t}\n+\twqe->general_cseg.misc = rte_cpu_to_be_32(id +\n+\t\t\t\t\t\t  (aso_mtr->offset >> 1));\n+\twqe->general_cseg.opcode =\n+\t\trte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |\n+\t\t\t(ASO_OPC_MOD_POLICER << WQE_CSEG_OPC_MOD_OFFSET) |\n+\t\t\t sq->pi << WQE_CSEG_WQE_INDEX_OFFSET);\n \t/* There are 2 meters in one ASO cache line. */\n \tdseg_idx = aso_mtr->offset & 0x1;\n \twqe->aso_cseg.data_mask =\n@@ -811,14 +818,15 @@ mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq)\n  */\n int\n mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh,\n-\t\t\tstruct mlx5_aso_mtr *mtr)\n+\t\t\tstruct mlx5_aso_mtr *mtr,\n+\t\t\tstruct mlx5_mtr_bulk *bulk)\n {\n \tstruct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;\n \tuint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;\n \n \tdo {\n \t\tmlx5_aso_mtr_completion_handle(sq);\n-\t\tif (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr))\n+\t\tif (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk))\n \t\t\treturn 0;\n \t\t/* Waiting for wqe resource. */\n \t\trte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);\ndiff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c\nindex d1f0d63fdc..80539fd75d 100644\n--- a/drivers/net/mlx5/mlx5_flow_dv.c\n+++ b/drivers/net/mlx5/mlx5_flow_dv.c\n@@ -216,31 +216,6 @@ flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,\n \tattr->valid = 1;\n }\n \n-/*\n- * Convert rte_mtr_color to mlx5 color.\n- *\n- * @param[in] rcol\n- *   rte_mtr_color.\n- *\n- * @return\n- *   mlx5 color.\n- */\n-static inline int\n-rte_col_2_mlx5_col(enum rte_color rcol)\n-{\n-\tswitch (rcol) {\n-\tcase RTE_COLOR_GREEN:\n-\t\treturn MLX5_FLOW_COLOR_GREEN;\n-\tcase RTE_COLOR_YELLOW:\n-\t\treturn MLX5_FLOW_COLOR_YELLOW;\n-\tcase RTE_COLOR_RED:\n-\t\treturn MLX5_FLOW_COLOR_RED;\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\treturn MLX5_FLOW_COLOR_UNDEFINED;\n-}\n-\n struct field_modify_info modify_eth[] = {\n \t{4,  0, MLX5_MODI_OUT_DMAC_47_16},\n \t{2,  4, MLX5_MODI_OUT_DMAC_15_0},\ndiff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c\nindex dfbf885530..959d566d68 100644\n--- a/drivers/net/mlx5/mlx5_flow_hw.c\n+++ b/drivers/net/mlx5/mlx5_flow_hw.c\n@@ -903,6 +903,38 @@ flow_hw_represented_port_compile(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+static __rte_always_inline int\n+flow_hw_meter_compile(struct rte_eth_dev *dev,\n+\t\t      const struct mlx5_flow_template_table_cfg *cfg,\n+\t\t      uint32_t  start_pos, const struct rte_flow_action *action,\n+\t\t      struct mlx5_hw_actions *acts, uint32_t *end_pos,\n+\t\t      struct rte_flow_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_aso_mtr *aso_mtr;\n+\tconst struct rte_flow_action_meter *meter = action->conf;\n+\tuint32_t pos = start_pos;\n+\tuint32_t group = cfg->attr.flow_attr.group;\n+\n+\taso_mtr = mlx5_aso_meter_by_idx(priv, meter->mtr_id);\n+\tacts->rule_acts[pos].action = priv->mtr_bulk.action;\n+\tacts->rule_acts[pos].aso_meter.offset = aso_mtr->offset;\n+\t\tacts->jump = flow_hw_jump_action_register\n+\t\t(dev, cfg, aso_mtr->fm.group, error);\n+\tif (!acts->jump) {\n+\t\t*end_pos = start_pos;\n+\t\treturn -ENOMEM;\n+\t}\n+\tacts->rule_acts[++pos].action = (!!group) ?\n+\t\t\t\t    acts->jump->hws_action :\n+\t\t\t\t    acts->jump->root_action;\n+\t*end_pos = pos;\n+\tif (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) {\n+\t\t*end_pos = start_pos;\n+\t\treturn -ENOMEM;\n+\t}\n+\treturn 0;\n+}\n /**\n  * Translate rte_flow actions to DR action.\n  *\n@@ -1131,6 +1163,21 @@ flow_hw_actions_translate(struct rte_eth_dev *dev,\n \t\t\t\tgoto err;\n \t\t\ti++;\n \t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_METER:\n+\t\t\tif (actions->conf && masks->conf &&\n+\t\t\t    ((const struct rte_flow_action_meter *)\n+\t\t\t     masks->conf)->mtr_id) {\n+\t\t\t\terr = flow_hw_meter_compile(dev, cfg,\n+\t\t\t\t\t\ti, actions, acts, &i, error);\n+\t\t\t\tif (err)\n+\t\t\t\t\tgoto err;\n+\t\t\t} else if (__flow_hw_act_data_general_append(priv, acts,\n+\t\t\t\t\t\t\tactions->type,\n+\t\t\t\t\t\t\tactions - action_start,\n+\t\t\t\t\t\t\ti))\n+\t\t\t\tgoto err;\n+\t\t\ti++;\n+\t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_END:\n \t\t\tactions_end = true;\n \t\t\tbreak;\n@@ -1461,6 +1508,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,\n \tconst struct rte_flow_action_raw_encap *raw_encap_data;\n \tconst struct rte_flow_item *enc_item = NULL;\n \tconst struct rte_flow_action_ethdev *port_action = NULL;\n+\tconst struct rte_flow_action_meter *meter = NULL;\n \tuint8_t *buf = job->encap_data;\n \tstruct rte_flow_attr attr = {\n \t\t\t.ingress = 1,\n@@ -1468,6 +1516,8 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,\n \tuint32_t ft_flag;\n \tsize_t encap_len = 0;\n \tint ret;\n+\tstruct mlx5_aso_mtr *mtr;\n+\tuint32_t mtr_id;\n \n \tmemcpy(rule_acts, hw_acts->rule_acts,\n \t       sizeof(*rule_acts) * hw_acts->acts_num);\n@@ -1587,6 +1637,29 @@ flow_hw_actions_construct(struct rte_eth_dev *dev,\n \t\t\trule_acts[act_data->action_dst].action =\n \t\t\t\t\tpriv->hw_vport[port_action->port_id];\n \t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_METER:\n+\t\t\tmeter = action->conf;\n+\t\t\tmtr_id = meter->mtr_id;\n+\t\t\tmtr = mlx5_aso_meter_by_idx(priv, mtr_id);\n+\t\t\trule_acts[act_data->action_dst].action =\n+\t\t\t\tpriv->mtr_bulk.action;\n+\t\t\trule_acts[act_data->action_dst].aso_meter.offset =\n+\t\t\t\t\t\t\t\tmtr->offset;\n+\t\t\tjump = flow_hw_jump_action_register\n+\t\t\t\t(dev, &table->cfg, mtr->fm.group, NULL);\n+\t\t\tif (!jump)\n+\t\t\t\treturn -1;\n+\t\t\tMLX5_ASSERT\n+\t\t\t\t(!rule_acts[act_data->action_dst + 1].action);\n+\t\t\trule_acts[act_data->action_dst + 1].action =\n+\t\t\t\t\t(!!attr.group) ? jump->hws_action :\n+\t\t\t\t\t\t\t jump->root_action;\n+\t\t\tjob->flow->jump = jump;\n+\t\t\tjob->flow->fate_type = MLX5_FLOW_FATE_JUMP;\n+\t\t\t(*acts_num)++;\n+\t\t\tif (mlx5_aso_mtr_wait(priv->sh, mtr))\n+\t\t\t\treturn -1;\n+\t\t\tbreak;\n \t\tdefault:\n \t\t\tbreak;\n \t\t}\n@@ -2483,7 +2556,7 @@ flow_hw_action_meta_copy_insert(const struct rte_flow_action actions[],\n }\n \n static int\n-flow_hw_action_validate(struct rte_eth_dev *dev,\n+flow_hw_actions_validate(struct rte_eth_dev *dev,\n \t\t\tconst struct rte_flow_actions_template_attr *attr,\n \t\t\tconst struct rte_flow_action actions[],\n \t\t\tconst struct rte_flow_action masks[],\n@@ -2549,6 +2622,9 @@ flow_hw_action_validate(struct rte_eth_dev *dev,\n \t\tcase RTE_FLOW_ACTION_TYPE_RAW_DECAP:\n \t\t\t/* TODO: Validation logic */\n \t\t\tbreak;\n+\t\tcase RTE_FLOW_ACTION_TYPE_METER:\n+\t\t\t/* TODO: Validation logic */\n+\t\t\tbreak;\n \t\tcase RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:\n \t\t\tret = flow_hw_validate_action_modify_field(action,\n \t\t\t\t\t\t\t\t\tmask,\n@@ -2642,7 +2718,7 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev,\n \t\t.conf = &rx_mreg_mask,\n \t};\n \n-\tif (flow_hw_action_validate(dev, attr, actions, masks, error))\n+\tif (flow_hw_actions_validate(dev, attr, actions, masks, error))\n \t\treturn NULL;\n \tif (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS &&\n \t    priv->sh->config.dv_esw_en) {\n@@ -2988,15 +3064,27 @@ flow_hw_pattern_template_destroy(struct rte_eth_dev *dev __rte_unused,\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n static int\n-flow_hw_info_get(struct rte_eth_dev *dev __rte_unused,\n-\t\t struct rte_flow_port_info *port_info __rte_unused,\n-\t\t struct rte_flow_queue_info *queue_info __rte_unused,\n+flow_hw_info_get(struct rte_eth_dev *dev,\n+\t\t struct rte_flow_port_info *port_info,\n+\t\t struct rte_flow_queue_info *queue_info,\n \t\t struct rte_flow_error *error __rte_unused)\n {\n-\t/* Nothing to be updated currently. */\n+\tuint16_t port_id = dev->data->port_id;\n+\tstruct rte_mtr_capabilities mtr_cap;\n+\tint ret;\n+\n \tmemset(port_info, 0, sizeof(*port_info));\n \t/* Queue size is unlimited from low-level. */\n+\tport_info->max_nb_queues = UINT32_MAX;\n \tqueue_info->max_size = UINT32_MAX;\n+\n+\tmemset(&mtr_cap, 0, sizeof(struct rte_mtr_capabilities));\n+\tret = rte_mtr_capabilities_get(port_id, &mtr_cap, NULL);\n+\tif (!ret) {\n+\t\tport_info->max_nb_meters = mtr_cap.n_max;\n+\t\tport_info->max_nb_meter_profiles = UINT32_MAX;\n+\t\tport_info->max_nb_meter_policies = UINT32_MAX;\n+\t}\n \treturn 0;\n }\n \n@@ -4191,6 +4279,13 @@ flow_hw_configure(struct rte_eth_dev *dev,\n \tpriv->nb_queue = nb_q_updated;\n \trte_spinlock_init(&priv->hw_ctrl_lock);\n \tLIST_INIT(&priv->hw_ctrl_flows);\n+\t/* Initialize meter library*/\n+\tif (port_attr->nb_meters)\n+\t\tif (mlx5_flow_meter_init(dev,\n+\t\t\t\t\tport_attr->nb_meters,\n+\t\t\t\t\tport_attr->nb_meter_profiles,\n+\t\t\t\t\tport_attr->nb_meter_policies))\n+\t\t\tgoto err;\n \t/* Add global actions. */\n \tfor (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {\n \t\tuint32_t act_flags = 0;\n@@ -4505,8 +4600,10 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue,\n const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {\n \t.info_get = flow_hw_info_get,\n \t.configure = flow_hw_configure,\n+\t.pattern_validate = flow_hw_pattern_validate,\n \t.pattern_template_create = flow_hw_pattern_template_create,\n \t.pattern_template_destroy = flow_hw_pattern_template_destroy,\n+\t.actions_validate = flow_hw_actions_validate,\n \t.actions_template_create = flow_hw_actions_template_create,\n \t.actions_template_destroy = flow_hw_actions_template_destroy,\n \t.template_table_create = flow_hw_template_table_create,\n@@ -4562,7 +4659,7 @@ flow_hw_create_ctrl_flow(struct rte_eth_dev *owner_dev,\n \t\t\t uint8_t action_template_idx)\n {\n \tstruct mlx5_priv *priv = proxy_dev->data->dev_private;\n-\tuint32_t queue = priv->nb_queue - 1;\n+\tuint32_t queue = CTRL_QUEUE_ID(priv);\n \tstruct rte_flow_op_attr op_attr = {\n \t\t.postpone = 0,\n \t};\n@@ -4637,7 +4734,7 @@ static int\n flow_hw_destroy_ctrl_flow(struct rte_eth_dev *dev, struct rte_flow *flow)\n {\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n-\tuint32_t queue = priv->nb_queue - 1;\n+\tuint32_t queue = CTRL_QUEUE_ID(priv);\n \tstruct rte_flow_op_attr op_attr = {\n \t\t.postpone = 0,\n \t};\ndiff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c\nindex d4aafe4eea..b69021f6a0 100644\n--- a/drivers/net/mlx5/mlx5_flow_meter.c\n+++ b/drivers/net/mlx5/mlx5_flow_meter.c\n@@ -18,6 +18,157 @@\n static int mlx5_flow_meter_disable(struct rte_eth_dev *dev,\n \t\tuint32_t meter_id, struct rte_mtr_error *error);\n \n+static void\n+mlx5_flow_meter_uninit(struct rte_eth_dev *dev)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\n+\tif (priv->mtr_policy_arr) {\n+\t\tmlx5_free(priv->mtr_policy_arr);\n+\t\tpriv->mtr_policy_arr = NULL;\n+\t}\n+\tif (priv->mtr_profile_arr) {\n+\t\tmlx5_free(priv->mtr_profile_arr);\n+\t\tpriv->mtr_profile_arr = NULL;\n+\t}\n+\tif (priv->mtr_bulk.aso) {\n+\t\tmlx5_free(priv->mtr_bulk.aso);\n+\t\tpriv->mtr_bulk.aso = NULL;\n+\t\tpriv->mtr_bulk.size = 0;\n+\t\tmlx5_aso_queue_uninit(priv->sh, ASO_OPC_MOD_POLICER);\n+\t}\n+\tif (priv->mtr_bulk.action) {\n+\t\tmlx5dr_action_destroy(priv->mtr_bulk.action);\n+\t\tpriv->mtr_bulk.action = NULL;\n+\t}\n+\tif (priv->mtr_bulk.devx_obj) {\n+\t\tclaim_zero(mlx5_devx_cmd_destroy(priv->mtr_bulk.devx_obj));\n+\t\tpriv->mtr_bulk.devx_obj = NULL;\n+\t}\n+}\n+\n+int\n+mlx5_flow_meter_init(struct rte_eth_dev *dev,\n+\t\t     uint32_t nb_meters,\n+\t\t     uint32_t nb_meter_profiles,\n+\t\t     uint32_t nb_meter_policies)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_devx_obj *dcs = NULL;\n+\tuint32_t log_obj_size;\n+\tint ret = 0;\n+\tint reg_id;\n+\tstruct mlx5_aso_mtr *aso;\n+\tuint32_t i;\n+\tstruct rte_mtr_error error;\n+\n+\tif (!nb_meters || !nb_meter_profiles || !nb_meter_policies) {\n+\t\tret = ENOTSUP;\n+\t\trte_mtr_error_set(&error, ENOMEM,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\tNULL, \"Meter configuration is invalid.\");\n+\t\tgoto err;\n+\t}\n+\tif (!priv->mtr_en || !priv->sh->meter_aso_en) {\n+\t\tret = ENOTSUP;\n+\t\trte_mtr_error_set(&error, ENOMEM,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\tNULL, \"Meter ASO is not supported.\");\n+\t\tgoto err;\n+\t}\n+\tpriv->mtr_config.nb_meters = nb_meters;\n+\tif (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {\n+\t\tret = ENOMEM;\n+\t\trte_mtr_error_set(&error, ENOMEM,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\tNULL, \"Meter ASO queue allocation failed.\");\n+\t\tgoto err;\n+\t}\n+\tlog_obj_size = rte_log2_u32(nb_meters >> 1);\n+\tdcs = mlx5_devx_cmd_create_flow_meter_aso_obj\n+\t\t(priv->sh->cdev->ctx, priv->sh->cdev->pdn,\n+\t\t\tlog_obj_size);\n+\tif (!dcs) {\n+\t\tret = ENOMEM;\n+\t\trte_mtr_error_set(&error, ENOMEM,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\tNULL, \"Meter ASO object allocation failed.\");\n+\t\tgoto err;\n+\t}\n+\tpriv->mtr_bulk.devx_obj = dcs;\n+\treg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, NULL);\n+\tif (reg_id < 0) {\n+\t\tret = ENOTSUP;\n+\t\trte_mtr_error_set(&error, ENOMEM,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\tNULL, \"Meter register is not available.\");\n+\t\tgoto err;\n+\t}\n+\tpriv->mtr_bulk.action = mlx5dr_action_create_aso_meter\n+\t\t\t(priv->dr_ctx, (struct mlx5dr_devx_obj *)dcs,\n+\t\t\t\treg_id - REG_C_0, MLX5DR_ACTION_FLAG_HWS_RX |\n+\t\t\t\tMLX5DR_ACTION_FLAG_HWS_TX |\n+\t\t\t\tMLX5DR_ACTION_FLAG_HWS_FDB);\n+\tif (!priv->mtr_bulk.action) {\n+\t\tret = ENOMEM;\n+\t\trte_mtr_error_set(&error, ENOMEM,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\tNULL, \"Meter action creation failed.\");\n+\t\tgoto err;\n+\t}\n+\tpriv->mtr_bulk.aso = mlx5_malloc(MLX5_MEM_ZERO,\n+\t\t\t\t\t\tsizeof(struct mlx5_aso_mtr) * nb_meters,\n+\t\t\t\t\t\tRTE_CACHE_LINE_SIZE,\n+\t\t\t\t\t\tSOCKET_ID_ANY);\n+\tif (!priv->mtr_bulk.aso) {\n+\t\tret = ENOMEM;\n+\t\trte_mtr_error_set(&error, ENOMEM,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\tNULL, \"Meter bulk ASO allocation failed.\");\n+\t\tgoto err;\n+\t}\n+\tpriv->mtr_bulk.size = nb_meters;\n+\taso = priv->mtr_bulk.aso;\n+\tfor (i = 0; i < priv->mtr_bulk.size; i++) {\n+\t\taso->type = ASO_METER_DIRECT;\n+\t\taso->state = ASO_METER_WAIT;\n+\t\taso->offset = i;\n+\t\taso++;\n+\t}\n+\tpriv->mtr_config.nb_meter_profiles = nb_meter_profiles;\n+\tpriv->mtr_profile_arr =\n+\t\tmlx5_malloc(MLX5_MEM_ZERO,\n+\t\t\t\tsizeof(struct mlx5_flow_meter_profile) *\n+\t\t\t\tnb_meter_profiles,\n+\t\t\t\tRTE_CACHE_LINE_SIZE,\n+\t\t\t\tSOCKET_ID_ANY);\n+\tif (!priv->mtr_profile_arr) {\n+\t\tret = ENOMEM;\n+\t\trte_mtr_error_set(&error, ENOMEM,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\tNULL, \"Meter profile allocation failed.\");\n+\t\tgoto err;\n+\t}\n+\tpriv->mtr_config.nb_meter_policies = nb_meter_policies;\n+\tpriv->mtr_policy_arr =\n+\t\tmlx5_malloc(MLX5_MEM_ZERO,\n+\t\t\t\tsizeof(struct mlx5_flow_meter_policy) *\n+\t\t\t\tnb_meter_policies,\n+\t\t\t\tRTE_CACHE_LINE_SIZE,\n+\t\t\t\tSOCKET_ID_ANY);\n+\tif (!priv->mtr_policy_arr) {\n+\t\tret = ENOMEM;\n+\t\trte_mtr_error_set(&error, ENOMEM,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\tNULL, \"Meter policy allocation failed.\");\n+\t\tgoto err;\n+\t}\n+\treturn 0;\n+err:\n+\tmlx5_flow_meter_uninit(dev);\n+\treturn ret;\n+}\n+\n /**\n  * Create the meter action.\n  *\n@@ -98,6 +249,8 @@ mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)\n \tunion mlx5_l3t_data data;\n \tint32_t ret;\n \n+\tif (priv->mtr_profile_arr)\n+\t\treturn &priv->mtr_profile_arr[meter_profile_id];\n \tif (mlx5_l3t_get_entry(priv->mtr_profile_tbl,\n \t\t\t       meter_profile_id, &data) || !data.ptr)\n \t\treturn NULL;\n@@ -145,17 +298,29 @@ mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,\n \t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_PROFILE,\n \t\t\t\t\t  NULL, \"Meter profile is null.\");\n \t/* Meter profile ID must be valid. */\n-\tif (meter_profile_id == UINT32_MAX)\n-\t\treturn -rte_mtr_error_set(error, EINVAL,\n-\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n-\t\t\t\t\t  NULL, \"Meter profile id not valid.\");\n-\t/* Meter profile must not exist. */\n-\tfmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);\n-\tif (fmp)\n-\t\treturn -rte_mtr_error_set(error, EEXIST,\n-\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n-\t\t\t\t\t  NULL,\n-\t\t\t\t\t  \"Meter profile already exists.\");\n+\tif (priv->mtr_profile_arr) {\n+\t\tif (meter_profile_id >= priv->mtr_config.nb_meter_profiles)\n+\t\t\treturn -rte_mtr_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n+\t\t\t\t\tNULL, \"Meter profile id not valid.\");\n+\t\tfmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);\n+\t\t/* Meter profile must not exist. */\n+\t\tif (fmp->initialized)\n+\t\t\treturn -rte_mtr_error_set(error, EEXIST,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n+\t\t\t\t\tNULL, \"Meter profile already exists.\");\n+\t} else {\n+\t\tif (meter_profile_id == UINT32_MAX)\n+\t\t\treturn -rte_mtr_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n+\t\t\t\t\tNULL, \"Meter profile id not valid.\");\n+\t\tfmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);\n+\t\t/* Meter profile must not exist. */\n+\t\tif (fmp)\n+\t\t\treturn -rte_mtr_error_set(error, EEXIST,\n+\t\t\t\t\tRTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n+\t\t\t\t\tNULL, \"Meter profile already exists.\");\n+\t}\n \tif (!priv->sh->meter_aso_en) {\n \t\t/* Old version is even not supported. */\n \t\tif (!priv->sh->cdev->config.hca_attr.qos.flow_meter_old)\n@@ -574,6 +739,96 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+/**\n+ * Callback to add MTR profile with HWS.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] meter_profile_id\n+ *   Meter profile id.\n+ * @param[in] profile\n+ *   Pointer to meter profile detail.\n+ * @param[out] error\n+ *   Pointer to the error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+mlx5_flow_meter_profile_hws_add(struct rte_eth_dev *dev,\n+\t\t\tuint32_t meter_profile_id,\n+\t\t\tstruct rte_mtr_meter_profile *profile,\n+\t\t\tstruct rte_mtr_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_meter_profile *fmp;\n+\tint ret;\n+\n+\tif (!priv->mtr_profile_arr)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t  NULL, \"Meter profile array is not allocated\");\n+\t/* Check input params. */\n+\tret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,\n+\t\t\t\t\t       profile, error);\n+\tif (ret)\n+\t\treturn ret;\n+\tfmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);\n+\t/* Fill profile info. */\n+\tfmp->id = meter_profile_id;\n+\tfmp->profile = *profile;\n+\tfmp->initialized = 1;\n+\t/* Fill the flow meter parameters for the PRM. */\n+\treturn mlx5_flow_meter_param_fill(fmp, error);\n+}\n+\n+/**\n+ * Callback to delete MTR profile with HWS.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] meter_profile_id\n+ *   Meter profile id.\n+ * @param[out] error\n+ *   Pointer to the error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+mlx5_flow_meter_profile_hws_delete(struct rte_eth_dev *dev,\n+\t\t\tuint32_t meter_profile_id,\n+\t\t\tstruct rte_mtr_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_meter_profile *fmp;\n+\n+\tif (!priv->mtr_profile_arr)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t  NULL, \"Meter profile array is not allocated\");\n+\t/* Meter id must be valid. */\n+\tif (meter_profile_id >= priv->mtr_config.nb_meter_profiles)\n+\t\treturn -rte_mtr_error_set(error, EINVAL,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n+\t\t\t\t\t  &meter_profile_id,\n+\t\t\t\t\t  \"Meter profile id not valid.\");\n+\t/* Meter profile must exist. */\n+\tfmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);\n+\tif (!fmp->initialized)\n+\t\treturn -rte_mtr_error_set(error, ENOENT,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n+\t\t\t\t\t  &meter_profile_id,\n+\t\t\t\t\t  \"Meter profile id is invalid.\");\n+\t/* Check profile is unused. */\n+\tif (fmp->ref_cnt)\n+\t\treturn -rte_mtr_error_set(error, EBUSY,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n+\t\t\t\t\t  NULL, \"Meter profile is in use.\");\n+\tmemset(fmp, 0, sizeof(struct mlx5_flow_meter_profile));\n+\treturn 0;\n+}\n+\n /**\n  * Find policy by id.\n  *\n@@ -594,6 +849,11 @@ mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,\n \tstruct mlx5_flow_meter_sub_policy *sub_policy = NULL;\n \tunion mlx5_l3t_data data;\n \n+\tif (priv->mtr_policy_arr) {\n+\t\tif (policy_idx)\n+\t\t\t*policy_idx = policy_id;\n+\t\treturn &priv->mtr_policy_arr[policy_id];\n+\t}\n \tif (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM || !priv->policy_idx_tbl)\n \t\treturn NULL;\n \tif (mlx5_l3t_get_entry(priv->policy_idx_tbl, policy_id, &data) ||\n@@ -710,6 +970,43 @@ mlx5_flow_meter_policy_validate(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+/**\n+ * Callback to check MTR policy action validate for HWS\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] actions\n+ *   Pointer to meter policy action detail.\n+ * @param[out] error\n+ *   Pointer to the error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+mlx5_flow_meter_policy_hws_validate(struct rte_eth_dev *dev,\n+\tstruct rte_mtr_meter_policy_params *policy,\n+\tstruct rte_mtr_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tconst struct rte_flow_actions_template_attr attr = {\n+\t\t.transfer = priv->sh->config.dv_esw_en ? 1 : 0 };\n+\tint ret;\n+\tint i;\n+\n+\tif (!priv->mtr_en || !priv->sh->meter_aso_en)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\tRTE_MTR_ERROR_TYPE_METER_POLICY,\n+\t\t\t\tNULL, \"meter policy unsupported.\");\n+\tfor (i = 0; i < RTE_COLORS; i++) {\n+\t\tret = mlx5_flow_actions_validate(dev, &attr, policy->actions[i],\n+\t\t\t\t\t\t policy->actions[i], NULL);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n static int\n __mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,\n \t\t\tuint32_t policy_id,\n@@ -1004,6 +1301,338 @@ mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n+/**\n+ * Callback to delete MTR policy for HWS.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] policy_id\n+ *   Meter policy id.\n+ * @param[out] error\n+ *   Pointer to the error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+mlx5_flow_meter_policy_hws_delete(struct rte_eth_dev *dev,\n+\t\t\t  uint32_t policy_id,\n+\t\t\t  struct rte_mtr_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_meter_policy *mtr_policy;\n+\tuint32_t i, j;\n+\tuint32_t nb_flows = 0;\n+\tint ret;\n+\tstruct rte_flow_op_attr op_attr = { .postpone = 1 };\n+\tstruct rte_flow_op_result result[RTE_COLORS * MLX5_MTR_DOMAIN_MAX];\n+\n+\tif (!priv->mtr_policy_arr)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t  NULL, \"Meter policy array is not allocated\");\n+\t/* Meter id must be valid. */\n+\tif (policy_id >= priv->mtr_config.nb_meter_policies)\n+\t\treturn -rte_mtr_error_set(error, EINVAL,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,\n+\t\t\t\t\t  &policy_id,\n+\t\t\t\t\t  \"Meter policy id not valid.\");\n+\t/* Meter policy must exist. */\n+\tmtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);\n+\tif (!mtr_policy->initialized)\n+\t\treturn -rte_mtr_error_set(error, ENOENT,\n+\t\t\tRTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,\n+\t\t\t\"Meter policy does not exists.\");\n+\t/* Check policy is unused. */\n+\tif (mtr_policy->ref_cnt)\n+\t\treturn -rte_mtr_error_set(error, EBUSY,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,\n+\t\t\t\t\t  NULL, \"Meter policy is in use.\");\n+\trte_spinlock_lock(&priv->hw_ctrl_lock);\n+\tfor (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {\n+\t\tfor (j = 0; j < RTE_COLORS; j++) {\n+\t\t\tif (mtr_policy->hws_flow_rule[i][j]) {\n+\t\t\t\tret = rte_flow_async_destroy(dev->data->port_id,\n+\t\t\t\t\tCTRL_QUEUE_ID(priv), &op_attr,\n+\t\t\t\t\tmtr_policy->hws_flow_rule[i][j],\n+\t\t\t\t\tNULL, NULL);\n+\t\t\t\tif (ret < 0)\n+\t\t\t\t\tcontinue;\n+\t\t\t\tnb_flows++;\n+\t\t\t}\n+\t\t}\n+\t}\n+\tret = rte_flow_push(dev->data->port_id, CTRL_QUEUE_ID(priv), NULL);\n+\twhile (nb_flows && (ret >= 0)) {\n+\t\tret = rte_flow_pull(dev->data->port_id,\n+\t\t\t\t\tCTRL_QUEUE_ID(priv), result,\n+\t\t\t\t\tnb_flows, NULL);\n+\t\tnb_flows -= ret;\n+\t}\n+\tfor (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {\n+\t\tif (mtr_policy->hws_flow_table[i])\n+\t\t\trte_flow_template_table_destroy(dev->data->port_id,\n+\t\t\t\t mtr_policy->hws_flow_table[i], NULL);\n+\t}\n+\tfor (i = 0; i < RTE_COLORS; i++) {\n+\t\tif (mtr_policy->hws_act_templ[i])\n+\t\t\trte_flow_actions_template_destroy(dev->data->port_id,\n+\t\t\t\t mtr_policy->hws_act_templ[i], NULL);\n+\t}\n+\tif (mtr_policy->hws_item_templ)\n+\t\trte_flow_pattern_template_destroy(dev->data->port_id,\n+\t\t\t\tmtr_policy->hws_item_templ, NULL);\n+\trte_spinlock_unlock(&priv->hw_ctrl_lock);\n+\tmemset(mtr_policy, 0, sizeof(struct mlx5_flow_meter_policy));\n+\treturn 0;\n+}\n+\n+/**\n+ * Callback to add MTR policy for HWS.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[out] policy_id\n+ *   Pointer to policy id\n+ * @param[in] actions\n+ *   Pointer to meter policy action detail.\n+ * @param[out] error\n+ *   Pointer to the error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+mlx5_flow_meter_policy_hws_add(struct rte_eth_dev *dev,\n+\t\t\tuint32_t policy_id,\n+\t\t\tstruct rte_mtr_meter_policy_params *policy,\n+\t\t\tstruct rte_mtr_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_meter_policy *mtr_policy = NULL;\n+\tconst struct rte_flow_action *act;\n+\tconst struct rte_flow_action_meter *mtr;\n+\tstruct mlx5_flow_meter_info *fm;\n+\tstruct mlx5_flow_meter_policy *plc;\n+\tuint8_t domain_color = MLX5_MTR_ALL_DOMAIN_BIT;\n+\tbool is_rss = false;\n+\tbool is_hierarchy = false;\n+\tint i, j;\n+\tuint32_t nb_colors = 0;\n+\tuint32_t nb_flows = 0;\n+\tint color;\n+\tint ret;\n+\tstruct rte_flow_pattern_template_attr pta = {0};\n+\tstruct rte_flow_actions_template_attr ata = {0};\n+\tstruct rte_flow_template_table_attr ta = { {0}, 0 };\n+\tstruct rte_flow_op_attr op_attr = { .postpone = 1 };\n+\tstruct rte_flow_op_result result[RTE_COLORS * MLX5_MTR_DOMAIN_MAX];\n+\tconst uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;\n+\tint color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR,\n+\t\t\t\t\t\t   0, NULL);\n+\tstruct rte_flow_item_tag tag_spec = {\n+\t\t.data = 0,\n+\t\t.index = color_reg_c_idx\n+\t};\n+\tstruct rte_flow_item_tag tag_mask = {\n+\t\t.data = color_mask,\n+\t\t.index = 0xff};\n+\tstruct rte_flow_item pattern[] = {\n+\t\t[0] = {\n+\t\t\t.type = (enum rte_flow_item_type)\n+\t\t\t\tMLX5_RTE_FLOW_ITEM_TYPE_TAG,\n+\t\t\t.spec = &tag_spec,\n+\t\t\t.mask = &tag_mask,\n+\t\t},\n+\t\t[1] = { .type = RTE_FLOW_ITEM_TYPE_END }\n+\t};\n+\n+\tif (!priv->mtr_policy_arr)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_POLICY,\n+\t\t\t\t\t  NULL, \"Meter policy array is not allocated.\");\n+\tif (policy_id >= priv->mtr_config.nb_meter_policies)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,\n+\t\t\t\t\t  NULL, \"Meter policy id not valid.\");\n+\tmtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);\n+\tif (mtr_policy->initialized)\n+\t\treturn -rte_mtr_error_set(error, EEXIST,\n+\t\t\tRTE_MTR_ERROR_TYPE_METER_POLICY_ID,\n+\t\t\tNULL, \"Meter policy already exists.\");\n+\tif (!policy ||\n+\t    !policy->actions[RTE_COLOR_RED] ||\n+\t    !policy->actions[RTE_COLOR_YELLOW] ||\n+\t    !policy->actions[RTE_COLOR_GREEN])\n+\t\treturn -rte_mtr_error_set(error, EINVAL,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_POLICY,\n+\t\t\t\t\t  NULL, \"Meter policy actions are not valid.\");\n+\tif (policy->actions[RTE_COLOR_RED] == RTE_FLOW_ACTION_TYPE_END)\n+\t\tmtr_policy->skip_r = 1;\n+\tif (policy->actions[RTE_COLOR_YELLOW] == RTE_FLOW_ACTION_TYPE_END)\n+\t\tmtr_policy->skip_y = 1;\n+\tif (policy->actions[RTE_COLOR_GREEN] == RTE_FLOW_ACTION_TYPE_END)\n+\t\tmtr_policy->skip_g = 1;\n+\tif (mtr_policy->skip_r && mtr_policy->skip_y && mtr_policy->skip_g)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,\n+\t\t\t\t\t  NULL, \"Meter policy actions are empty.\");\n+\tfor (i = 0; i < RTE_COLORS; i++) {\n+\t\tact = policy->actions[i];\n+\t\twhile (act && act->type != RTE_FLOW_ACTION_TYPE_END) {\n+\t\t\tswitch (act->type) {\n+\t\t\tcase RTE_FLOW_ACTION_TYPE_PORT_ID:\n+\t\t\t\t/* fall-through. */\n+\t\t\tcase RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:\n+\t\t\t\tdomain_color &= ~(MLX5_MTR_DOMAIN_INGRESS_BIT |\n+\t\t\t\t\t\t  MLX5_MTR_DOMAIN_EGRESS_BIT);\n+\t\t\t\tbreak;\n+\t\t\tcase RTE_FLOW_ACTION_TYPE_RSS:\n+\t\t\t\tis_rss = true;\n+\t\t\t\t/* fall-through. */\n+\t\t\tcase RTE_FLOW_ACTION_TYPE_QUEUE:\n+\t\t\t\tdomain_color &= ~(MLX5_MTR_DOMAIN_EGRESS_BIT |\n+\t\t\t\t\t\t  MLX5_MTR_DOMAIN_TRANSFER_BIT);\n+\t\t\t\tbreak;\n+\t\t\tcase RTE_FLOW_ACTION_TYPE_METER:\n+\t\t\t\tis_hierarchy = true;\n+\t\t\t\tmtr = act->conf;\n+\t\t\t\tfm = mlx5_flow_meter_find(priv,\n+\t\t\t\t\t\t\t  mtr->mtr_id, NULL);\n+\t\t\t\tif (!fm)\n+\t\t\t\t\treturn -rte_mtr_error_set(error, EINVAL,\n+\t\t\t\t\t\tRTE_MTR_ERROR_TYPE_MTR_ID, NULL,\n+\t\t\t\t\t\t\"Meter not found in meter hierarchy.\");\n+\t\t\t\tplc = mlx5_flow_meter_policy_find(dev,\n+\t\t\t\t\t\t\t\t  fm->policy_id,\n+\t\t\t\t\t\t\t\t  NULL);\n+\t\t\t\tMLX5_ASSERT(plc);\n+\t\t\t\tdomain_color &= MLX5_MTR_ALL_DOMAIN_BIT &\n+\t\t\t\t\t(plc->ingress <<\n+\t\t\t\t\t MLX5_MTR_DOMAIN_INGRESS);\n+\t\t\t\tdomain_color &= MLX5_MTR_ALL_DOMAIN_BIT &\n+\t\t\t\t\t(plc->egress <<\n+\t\t\t\t\t MLX5_MTR_DOMAIN_EGRESS);\n+\t\t\t\tdomain_color &= MLX5_MTR_ALL_DOMAIN_BIT &\n+\t\t\t\t\t(plc->transfer <<\n+\t\t\t\t\t MLX5_MTR_DOMAIN_TRANSFER);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tact++;\n+\t\t}\n+\t}\n+\tif (!domain_color)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,\n+\t\t\t\t\t  NULL, \"Meter policy domains are conflicting.\");\n+\tmtr_policy->is_rss = is_rss;\n+\tmtr_policy->ingress = !!(domain_color & MLX5_MTR_DOMAIN_INGRESS_BIT);\n+\tpta.ingress = mtr_policy->ingress;\n+\tmtr_policy->egress = !!(domain_color & MLX5_MTR_DOMAIN_EGRESS_BIT);\n+\tpta.egress = mtr_policy->egress;\n+\tmtr_policy->transfer = !!(domain_color & MLX5_MTR_DOMAIN_TRANSFER_BIT);\n+\tpta.transfer = mtr_policy->transfer;\n+\tmtr_policy->group = MLX5_FLOW_TABLE_HWS_POLICY - policy_id;\n+\tmtr_policy->is_hierarchy = is_hierarchy;\n+\tmtr_policy->initialized = 1;\n+\trte_spinlock_lock(&priv->hw_ctrl_lock);\n+\tmtr_policy->hws_item_templ =\n+\t\trte_flow_pattern_template_create(dev->data->port_id,\n+\t\t\t\t\t\t &pta, pattern, NULL);\n+\tif (!mtr_policy->hws_item_templ)\n+\t\tgoto policy_add_err;\n+\tfor (i = 0; i < RTE_COLORS; i++) {\n+\t\tif (mtr_policy->skip_g && i == RTE_COLOR_GREEN)\n+\t\t\tcontinue;\n+\t\tif (mtr_policy->skip_y && i == RTE_COLOR_YELLOW)\n+\t\t\tcontinue;\n+\t\tif (mtr_policy->skip_r && i == RTE_COLOR_RED)\n+\t\t\tcontinue;\n+\t\tmtr_policy->hws_act_templ[nb_colors] =\n+\t\t\trte_flow_actions_template_create(dev->data->port_id,\n+\t\t\t\t\t\t&ata, policy->actions[i],\n+\t\t\t\t\t\tpolicy->actions[i], NULL);\n+\t\tif (!mtr_policy->hws_act_templ[nb_colors])\n+\t\t\tgoto policy_add_err;\n+\t\tnb_colors++;\n+\t}\n+\tfor (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {\n+\t\tmemset(&ta, 0, sizeof(ta));\n+\t\tta.nb_flows = RTE_COLORS;\n+\t\tta.flow_attr.group = mtr_policy->group;\n+\t\tif (i == MLX5_MTR_DOMAIN_INGRESS) {\n+\t\t\tif (!mtr_policy->ingress)\n+\t\t\t\tcontinue;\n+\t\t\tta.flow_attr.ingress = 1;\n+\t\t} else if (i == MLX5_MTR_DOMAIN_EGRESS) {\n+\t\t\tif (!mtr_policy->egress)\n+\t\t\t\tcontinue;\n+\t\t\tta.flow_attr.egress = 1;\n+\t\t} else if (i == MLX5_MTR_DOMAIN_TRANSFER) {\n+\t\t\tif (!mtr_policy->transfer)\n+\t\t\t\tcontinue;\n+\t\t\tta.flow_attr.transfer = 1;\n+\t\t}\n+\t\tmtr_policy->hws_flow_table[i] =\n+\t\t\trte_flow_template_table_create(dev->data->port_id,\n+\t\t\t\t\t&ta, &mtr_policy->hws_item_templ, 1,\n+\t\t\t\t\tmtr_policy->hws_act_templ, nb_colors,\n+\t\t\t\t\tNULL);\n+\t\tif (!mtr_policy->hws_flow_table[i])\n+\t\t\tgoto policy_add_err;\n+\t\tnb_colors = 0;\n+\t\tfor (j = 0; j < RTE_COLORS; j++) {\n+\t\t\tif (mtr_policy->skip_g && j == RTE_COLOR_GREEN)\n+\t\t\t\tcontinue;\n+\t\t\tif (mtr_policy->skip_y && j == RTE_COLOR_YELLOW)\n+\t\t\t\tcontinue;\n+\t\t\tif (mtr_policy->skip_r && j == RTE_COLOR_RED)\n+\t\t\t\tcontinue;\n+\t\t\tcolor = rte_col_2_mlx5_col((enum rte_color)j);\n+\t\t\ttag_spec.data = color;\n+\t\t\tmtr_policy->hws_flow_rule[i][j] =\n+\t\t\t\trte_flow_async_create(dev->data->port_id,\n+\t\t\t\t\tCTRL_QUEUE_ID(priv), &op_attr,\n+\t\t\t\t\tmtr_policy->hws_flow_table[i],\n+\t\t\t\t\tpattern, 0, policy->actions[j],\n+\t\t\t\t\tnb_colors, NULL, NULL);\n+\t\t\tif (!mtr_policy->hws_flow_rule[i][j])\n+\t\t\t\tgoto policy_add_err;\n+\t\t\tnb_colors++;\n+\t\t\tnb_flows++;\n+\t\t}\n+\t\tret = rte_flow_push(dev->data->port_id,\n+\t\t\t\t    CTRL_QUEUE_ID(priv), NULL);\n+\t\tif (ret < 0)\n+\t\t\tgoto policy_add_err;\n+\t\twhile (nb_flows) {\n+\t\t\tret = rte_flow_pull(dev->data->port_id,\n+\t\t\t\t\t    CTRL_QUEUE_ID(priv), result,\n+\t\t\t\t\t    nb_flows, NULL);\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto policy_add_err;\n+\t\t\tfor (j = 0; j < ret; j++) {\n+\t\t\t\tif (result[j].status == RTE_FLOW_OP_ERROR)\n+\t\t\t\t\tgoto policy_add_err;\n+\t\t\t}\n+\t\t\tnb_flows -= ret;\n+\t\t}\n+\t}\n+\trte_spinlock_unlock(&priv->hw_ctrl_lock);\n+\treturn 0;\n+policy_add_err:\n+\trte_spinlock_unlock(&priv->hw_ctrl_lock);\n+\tret = mlx5_flow_meter_policy_hws_delete(dev, policy_id, error);\n+\tmemset(mtr_policy, 0, sizeof(struct mlx5_flow_meter_policy));\n+\tif (ret)\n+\t\treturn ret;\n+\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\t\t  RTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t  NULL, \"Failed to create meter policy.\");\n+}\n+\n /**\n  * Check meter validation.\n  *\n@@ -1087,7 +1716,8 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,\n \tif (priv->sh->meter_aso_en) {\n \t\tfm->is_enable = !!is_enable;\n \t\taso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);\n-\t\tret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);\n+\t\tret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr,\n+\t\t\t\t\t\t   &priv->mtr_bulk);\n \t\tif (ret)\n \t\t\treturn ret;\n \t\tret = mlx5_aso_mtr_wait(priv->sh, aso_mtr);\n@@ -1336,7 +1966,8 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,\n \t/* If ASO meter supported, update ASO flow meter by wqe. */\n \tif (priv->sh->meter_aso_en) {\n \t\taso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);\n-\t\tret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);\n+\t\tret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr,\n+\t\t\t\t\t\t   &priv->mtr_bulk);\n \t\tif (ret)\n \t\t\tgoto error;\n \t\tif (!priv->mtr_idx_tbl) {\n@@ -1369,6 +2000,90 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,\n \t\tNULL, \"Failed to create devx meter.\");\n }\n \n+/**\n+ * Create meter rules.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] meter_id\n+ *   Meter id.\n+ * @param[in] params\n+ *   Pointer to rte meter parameters.\n+ * @param[in] shared\n+ *   Meter shared with other flow or not.\n+ * @param[out] error\n+ *   Pointer to rte meter error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+mlx5_flow_meter_hws_create(struct rte_eth_dev *dev, uint32_t meter_id,\n+\t\t       struct rte_mtr_params *params, int shared,\n+\t\t       struct rte_mtr_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_flow_meter_profile *profile;\n+\tstruct mlx5_flow_meter_info *fm;\n+\tstruct mlx5_flow_meter_policy *policy = NULL;\n+\tstruct mlx5_aso_mtr *aso_mtr;\n+\tint ret;\n+\n+\tif (!priv->mtr_profile_arr ||\n+\t    !priv->mtr_policy_arr ||\n+\t    !priv->mtr_bulk.aso)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,\n+\t\t\t\"Meter bulk array is not allocated.\");\n+\t/* Meter profile must exist. */\n+\tprofile = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);\n+\tif (!profile->initialized)\n+\t\treturn -rte_mtr_error_set(error, ENOENT,\n+\t\t\tRTE_MTR_ERROR_TYPE_METER_PROFILE_ID,\n+\t\t\tNULL, \"Meter profile id not valid.\");\n+\t/* Meter policy must exist. */\n+\tpolicy = mlx5_flow_meter_policy_find(dev,\n+\t\t\tparams->meter_policy_id, NULL);\n+\tif (!policy->initialized)\n+\t\treturn -rte_mtr_error_set(error, ENOENT,\n+\t\t\tRTE_MTR_ERROR_TYPE_METER_POLICY_ID,\n+\t\t\tNULL, \"Meter policy id not valid.\");\n+\t/* Meter ID must be valid. */\n+\tif (meter_id >= priv->mtr_config.nb_meters)\n+\t\treturn -rte_mtr_error_set(error, EINVAL,\n+\t\t\tRTE_MTR_ERROR_TYPE_MTR_ID,\n+\t\t\tNULL, \"Meter id not valid.\");\n+\t/* Find ASO object. */\n+\taso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);\n+\tfm = &aso_mtr->fm;\n+\tif (fm->initialized)\n+\t\treturn -rte_mtr_error_set(error, ENOENT,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_MTR_ID,\n+\t\t\t\t\t  NULL, \"Meter object already exists.\");\n+\t/* Fill the flow meter parameters. */\n+\tfm->meter_id = meter_id;\n+\tfm->policy_id = params->meter_policy_id;\n+\tfm->profile = profile;\n+\tfm->meter_offset = meter_id;\n+\tfm->group = policy->group;\n+\t/* Add to the flow meter list. */\n+\tfm->active_state = 1; /* Config meter starts as active. */\n+\tfm->is_enable = params->meter_enable;\n+\tfm->shared = !!shared;\n+\tfm->initialized = 1;\n+\t/* Update ASO flow meter by wqe. */\n+\tret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr,\n+\t\t\t\t\t   &priv->mtr_bulk);\n+\tif (ret)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\tRTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\tNULL, \"Failed to create devx meter.\");\n+\tfm->active_state = params->meter_enable;\n+\t__atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);\n+\t__atomic_add_fetch(&policy->ref_cnt, 1, __ATOMIC_RELAXED);\n+\treturn 0;\n+}\n+\n static int\n mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,\n \t\t\tstruct mlx5_flow_meter_info *fm,\n@@ -1475,6 +2190,58 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,\n \treturn 0;\n }\n \n+/**\n+ * Destroy meter rules.\n+ *\n+ * @param[in] dev\n+ *   Pointer to Ethernet device.\n+ * @param[in] meter_id\n+ *   Meter id.\n+ * @param[out] error\n+ *   Pointer to rte meter error structure.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+mlx5_flow_meter_hws_destroy(struct rte_eth_dev *dev, uint32_t meter_id,\n+\t\t\tstruct rte_mtr_error *error)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_aso_mtr *aso_mtr;\n+\tstruct mlx5_flow_meter_info *fm;\n+\tstruct mlx5_flow_meter_policy *policy;\n+\n+\tif (!priv->mtr_profile_arr ||\n+\t    !priv->mtr_policy_arr ||\n+\t    !priv->mtr_bulk.aso)\n+\t\treturn -rte_mtr_error_set(error, ENOTSUP,\n+\t\t\tRTE_MTR_ERROR_TYPE_METER_POLICY, NULL,\n+\t\t\t\"Meter bulk array is not allocated.\");\n+\t/* Find ASO object. */\n+\taso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);\n+\tfm = &aso_mtr->fm;\n+\tif (!fm->initialized)\n+\t\treturn -rte_mtr_error_set(error, ENOENT,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_MTR_ID,\n+\t\t\t\t\t  NULL, \"Meter object id not valid.\");\n+\t/* Meter object must not have any owner. */\n+\tif (fm->ref_cnt > 0)\n+\t\treturn -rte_mtr_error_set(error, EBUSY,\n+\t\t\t\t\t  RTE_MTR_ERROR_TYPE_UNSPECIFIED,\n+\t\t\t\t\t  NULL, \"Meter object is being used.\");\n+\t/* Destroy the meter profile. */\n+\t__atomic_sub_fetch(&fm->profile->ref_cnt,\n+\t\t\t\t\t\t1, __ATOMIC_RELAXED);\n+\t/* Destroy the meter policy. */\n+\tpolicy = mlx5_flow_meter_policy_find(dev,\n+\t\t\tfm->policy_id, NULL);\n+\t__atomic_sub_fetch(&policy->ref_cnt,\n+\t\t\t\t\t\t1, __ATOMIC_RELAXED);\n+\tmemset(fm, 0, sizeof(struct mlx5_flow_meter_info));\n+\treturn 0;\n+}\n+\n /**\n  * Modify meter state.\n  *\n@@ -1798,6 +2565,23 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = {\n \t.stats_read = mlx5_flow_meter_stats_read,\n };\n \n+static const struct rte_mtr_ops mlx5_flow_mtr_hws_ops = {\n+\t.capabilities_get = mlx5_flow_mtr_cap_get,\n+\t.meter_profile_add = mlx5_flow_meter_profile_hws_add,\n+\t.meter_profile_delete = mlx5_flow_meter_profile_hws_delete,\n+\t.meter_policy_validate = mlx5_flow_meter_policy_hws_validate,\n+\t.meter_policy_add = mlx5_flow_meter_policy_hws_add,\n+\t.meter_policy_delete = mlx5_flow_meter_policy_hws_delete,\n+\t.create = mlx5_flow_meter_hws_create,\n+\t.destroy = mlx5_flow_meter_hws_destroy,\n+\t.meter_enable = mlx5_flow_meter_enable,\n+\t.meter_disable = mlx5_flow_meter_disable,\n+\t.meter_profile_update = mlx5_flow_meter_profile_update,\n+\t.meter_dscp_table_update = NULL,\n+\t.stats_update = NULL,\n+\t.stats_read = NULL,\n+};\n+\n /**\n  * Get meter operations.\n  *\n@@ -1812,7 +2596,12 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = {\n int\n mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)\n {\n-\t*(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\n+\tif (priv->sh->config.dv_flow_en == 2)\n+\t\t*(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_hws_ops;\n+\telse\n+\t\t*(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;\n \treturn 0;\n }\n \n@@ -1841,6 +2630,12 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,\n \tunion mlx5_l3t_data data;\n \tuint16_t n_valid;\n \n+\tif (priv->mtr_bulk.aso) {\n+\t\tif (mtr_idx)\n+\t\t\t*mtr_idx = meter_id;\n+\t\taso_mtr = priv->mtr_bulk.aso + meter_id;\n+\t\treturn &aso_mtr->fm;\n+\t}\n \tif (priv->sh->meter_aso_en) {\n \t\trte_rwlock_read_lock(&pools_mng->resize_mtrwl);\n \t\tn_valid = pools_mng->n_valid;\n@@ -2185,6 +2980,7 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)\n \tstruct mlx5_flow_meter_profile *fmp;\n \tstruct mlx5_legacy_flow_meter *legacy_fm;\n \tstruct mlx5_flow_meter_info *fm;\n+\tstruct mlx5_flow_meter_policy *policy;\n \tstruct mlx5_flow_meter_sub_policy *sub_policy;\n \tvoid *tmp;\n \tuint32_t i, mtr_idx, policy_idx;\n@@ -2219,6 +3015,14 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)\n \t\t\t\tNULL, \"MTR object meter profile invalid.\");\n \t\t}\n \t}\n+\tif (priv->mtr_bulk.aso) {\n+\t\tfor (i = 1; i <= priv->mtr_config.nb_meter_profiles; i++) {\n+\t\t\taso_mtr = mlx5_aso_meter_by_idx(priv, i);\n+\t\t\tfm = &aso_mtr->fm;\n+\t\t\tif (fm->initialized)\n+\t\t\t\tmlx5_flow_meter_hws_destroy(dev, i, error);\n+\t\t}\n+\t}\n \tif (priv->policy_idx_tbl) {\n \t\tMLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {\n \t\t\tpolicy_idx = *(uint32_t *)entry;\n@@ -2244,6 +3048,15 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)\n \t\tmlx5_l3t_destroy(priv->policy_idx_tbl);\n \t\tpriv->policy_idx_tbl = NULL;\n \t}\n+\tif (priv->mtr_policy_arr) {\n+\t\tfor (i = 0; i < priv->mtr_config.nb_meter_policies; i++) {\n+\t\t\tpolicy = mlx5_flow_meter_policy_find(dev, i,\n+\t\t\t\t\t\t\t     &policy_idx);\n+\t\t\tif (policy->initialized)\n+\t\t\t\tmlx5_flow_meter_policy_hws_delete(dev, i,\n+\t\t\t\t\t\t\t\t  error);\n+\t\t}\n+\t}\n \tif (priv->mtr_profile_tbl) {\n \t\tMLX5_L3T_FOREACH(priv->mtr_profile_tbl, i, entry) {\n \t\t\tfmp = entry;\n@@ -2257,9 +3070,19 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)\n \t\tmlx5_l3t_destroy(priv->mtr_profile_tbl);\n \t\tpriv->mtr_profile_tbl = NULL;\n \t}\n+\tif (priv->mtr_profile_arr) {\n+\t\tfor (i = 0; i < priv->mtr_config.nb_meter_profiles; i++) {\n+\t\t\tfmp = mlx5_flow_meter_profile_find(priv, i);\n+\t\t\tif (fmp->initialized)\n+\t\t\t\tmlx5_flow_meter_profile_hws_delete(dev, i,\n+\t\t\t\t\t\t\t\t   error);\n+\t\t}\n+\t}\n \t/* Delete default policy table. */\n \tmlx5_flow_destroy_def_policy(dev);\n \tif (priv->sh->refcnt == 1)\n \t\tmlx5_flow_destroy_mtr_drop_tbls(dev);\n+\t/* Destroy HWS configuration. */\n+\tmlx5_flow_meter_uninit(dev);\n \treturn 0;\n }\n",
    "prefixes": [
        "10/27"
    ]
}