diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index e244800..6705236 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2292,6 +2292,12 @@ struct mlx5_flow_id_pool *
 			DRV_LOG(DEBUG, "LRO session timeout set to %d usec",
 				config.lro.timeout);
 		}
+#if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
+		if (config.hca_attr.qos.sup && config.hca_attr.qos.srtcm_sup &&
+		    config.dv_flow_en) {
+			priv->mtr_en = 1;
+		}
+#endif
 	}
 	if (config.mprq.enabled && mprq) {
 		if (config.mprq.stride_num_n > mprq_max_stride_num_n ||
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index e219cbc..7ed69a7 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -167,6 +167,17 @@ struct mlx5_devx_mkey_attr {
 	uint32_t pd;
 };
 
+/* HCA qos attributes. */
+struct mlx5_hca_qos_attr {
+	uint32_t sup:1;	/* Whether QOS is supported. */
+	uint32_t srtcm_sup:1; /* Whether srTCM mode is supported. */
+	uint8_t log_max_flow_meter;
+	/* Power of the maximum supported meters. */
+	uint8_t flow_meter_reg_c_ids;
+	/* Bitmap of the reg_Cs available for flow meter to use. */
+
+};
+
 /* HCA supports this number of time periods for LRO. */
 #define MLX5_LRO_NUM_SUPP_PERIODS 4
 
@@ -193,6 +204,7 @@ struct mlx5_hca_attr {
 	uint32_t log_max_hairpin_wq_data_sz:5;
 	uint32_t log_max_hairpin_num_packets:5;
 	uint32_t vhca_id:16;
+	struct mlx5_hca_qos_attr qos;
 };
 
 /* Flow list . */
@@ -690,6 +702,7 @@ struct mlx5_priv {
 	unsigned int master:1; /* Device is a E-Switch master. */
 	unsigned int dr_shared:1; /* DV/DR data is shared. */
 	unsigned int counter_fallback:1; /* Use counter fallback management. */
+	unsigned int mtr_en:1; /* Whether support meter. */
 	uint16_t domain_id; /* Switch domain identifier. */
 	uint16_t vport_id; /* Associated VF vport index (if any). */
 	uint32_t vport_meta_tag; /* Used for vport index match ove VF LAG. */
diff --git a/drivers/net/mlx5/mlx5_devx_cmds.c b/drivers/net/mlx5/mlx5_devx_cmds.c
index d6e89b6..dcb7609 100644
--- a/drivers/net/mlx5/mlx5_devx_cmds.c
+++ b/drivers/net/mlx5/mlx5_devx_cmds.c
@@ -335,6 +335,29 @@ struct mlx5_devx_obj *
 	attr->log_max_hairpin_num_packets = MLX5_GET
 		(cmd_hca_cap, hcattr, log_min_hairpin_wq_data_sz);
 	attr->vhca_id = MLX5_GET(cmd_hca_cap, hcattr, vhca_id);
+	attr->qos.sup = MLX5_GET(cmd_hca_cap, hcattr, qos);
+	if (attr->qos.sup) {
+		MLX5_SET(query_hca_cap_in, in, op_mod,
+			 MLX5_GET_HCA_CAP_OP_MOD_QOS_CAP |
+			 MLX5_HCA_CAP_OPMOD_GET_CUR);
+		rc = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in),
+						 out, sizeof(out));
+		if (rc)
+			goto error;
+		if (status) {
+			DRV_LOG(DEBUG, "Failed to query devx QOS capabilities,"
+				" status %x, syndrome = %x",
+				status, syndrome);
+			return -1;
+		}
+		hcattr = MLX5_ADDR_OF(query_hca_cap_out, out, capability);
+		attr->qos.srtcm_sup =
+				MLX5_GET(qos_cap, hcattr, flow_meter_srtcm);
+		attr->qos.log_max_flow_meter =
+				MLX5_GET(qos_cap, hcattr, log_max_flow_meter);
+		attr->qos.flow_meter_reg_c_ids =
+			MLX5_GET(qos_cap, hcattr, flow_meter_reg_id);
+	}
 	attr->eth_net_offloads = MLX5_GET(cmd_hca_cap, hcattr,
 					  eth_net_offloads);
 	attr->eth_virt = MLX5_GET(cmd_hca_cap, hcattr, eth_virt);
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 6c7a005..9103b6d 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -8,9 +8,51 @@
 #include <rte_mtr_driver.h>
 
 #include "mlx5.h"
+#include "mlx5_flow.h"
+
+/**
+ * Callback to get MTR capabilities.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[out] cap
+ *   Pointer to save MTR capabilities.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
+		 struct rte_mtr_capabilities *cap,
+		 struct rte_mtr_error *error __rte_unused)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "Meter is not support");
+	memset(cap, 0, sizeof(*cap));
+	cap->n_max = 1 << qattr->log_max_flow_meter;
+	cap->n_shared_max = cap->n_max;
+	cap->identical = 1;
+	cap->shared_identical = 1;
+	cap->shared_n_flows_per_mtr_max = 4 << 20;
+	/* 2M flows can share the same meter. */
+	cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
+	cap->meter_srtcm_rfc2697_n_max = qattr->srtcm_sup ? cap->n_max : 0;
+	cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
+	cap->policer_action_drop_supported = 1;
+	cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
+			  RTE_MTR_STATS_N_PKTS_DROPPED;
+	return 0;
+}
 
 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
-	.capabilities_get = NULL,
+	.capabilities_get = mlx5_flow_mtr_cap_get,
 	.meter_profile_add = NULL,
 	.meter_profile_delete = NULL,
 	.create = NULL,
