diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index a6cc2d3108..69dcb2d760 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -282,7 +282,7 @@ static const struct mlx5_indexed_pool_config mlx5_ipool_cfg[] = {
 		 * for meter idx, so not set grow_trunk to avoid meter index
 		 * not jump continually.
 		 */
-		.size = sizeof(struct mlx5_flow_meter),
+		.size = sizeof(struct mlx5_legacy_flow_meter),
 		.trunk_size = 64,
 		.need_lock = 1,
 		.release_mem_en = 1,
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index c4a04716f7..29fdb14e15 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -20,6 +20,7 @@
 #include <rte_interrupts.h>
 #include <rte_errno.h>
 #include <rte_flow.h>
+#include <rte_mtr.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -573,6 +574,193 @@ struct mlx5_dev_shared_port {
 	/* Aging information for per port. */
 };
 
+/*ASO flow meter structures*/
+/* Modify this value if enum rte_mtr_color changes. */
+#define RTE_MTR_DROPPED RTE_COLORS
+
+/* Meter policer statistics */
+struct mlx5_flow_policer_stats {
+	uint32_t pass_cnt;
+	/**< Color counter for pass. */
+	uint32_t drop_cnt;
+	/**< Color counter for drop. */
+};
+
+/* Meter table structure. */
+struct mlx5_meter_domain_info {
+	struct mlx5_flow_tbl_resource *tbl;
+	/**< Meter table. */
+	struct mlx5_flow_tbl_resource *sfx_tbl;
+	/**< Meter suffix table. */
+	struct mlx5_flow_dv_matcher *drop_matcher;
+	/**< Matcher for Drop. */
+	struct mlx5_flow_dv_matcher *color_matcher;
+	/**< Matcher for Color. */
+	void *jump_actn;
+	/**< Meter match action. */
+	void *green_rule;
+	/**< Meter green rule. */
+	void *drop_rule;
+	/**< Meter drop rule. */
+};
+
+/* Meter table set for TX RX FDB. */
+struct mlx5_meter_domains_infos {
+	uint32_t ref_cnt;
+	/**< Table user count. */
+	struct mlx5_meter_domain_info egress;
+	/**< TX meter table. */
+	struct mlx5_meter_domain_info ingress;
+	/**< RX meter table. */
+	struct mlx5_meter_domain_info transfer;
+	/**< FDB meter table. */
+	void *drop_actn;
+	/**< Drop action as not matched. */
+	void *green_count;
+	/**< Counters for green rule. */
+	void *drop_count;
+	/**< Counters for green rule. */
+	void *meter_action;
+	/**< Flow meter action. */
+};
+
+/* Meter parameter structure. */
+struct mlx5_flow_meter_info {
+	uint32_t meter_id;
+	/**< Meter id. */
+	struct mlx5_flow_meter_profile *profile;
+	/**< Meter profile parameters. */
+	rte_spinlock_t sl; /**< Meter action spinlock. */
+	/** Policer actions (per meter output color). */
+	enum rte_mtr_policer_action action[RTE_COLORS];
+	/** Set of stats counters to be enabled.
+	 * @see enum rte_mtr_stats_type
+	 */
+	uint32_t green_bytes:1;
+	/** Set green bytes stats to be enabled. */
+	uint32_t green_pkts:1;
+	/** Set green packets stats to be enabled. */
+	uint32_t red_bytes:1;
+	/** Set red bytes stats to be enabled. */
+	uint32_t red_pkts:1;
+	/** Set red packets stats to be enabled. */
+	uint32_t bytes_dropped:1;
+	/** Set bytes dropped stats to be enabled. */
+	uint32_t pkts_dropped:1;
+	/** Set packets dropped stats to be enabled. */
+	uint32_t active_state:1;
+	/**< Meter hw active state. */
+	uint32_t shared:1;
+	/**< Meter shared or not. */
+	uint32_t is_enable:1;
+	/**< Meter disable/enable state. */
+	uint32_t ingress:1;
+	/**< Rule applies to egress traffic. */
+	uint32_t egress:1;
+	/**
+	 * Instead of simply matching the properties of traffic as it would
+	 * appear on a given DPDK port ID, enabling this attribute transfers
+	 * a flow rule to the lowest possible level of any device endpoints
+	 * found in the pattern.
+	 *
+	 * When supported, this effectively enables an application to
+	 * re-route traffic not necessarily intended for it (e.g. coming
+	 * from or addressed to different physical ports, VFs or
+	 * applications) at the device level.
+	 *
+	 * It complements the behavior of some pattern items such as
+	 * RTE_FLOW_ITEM_TYPE_PHY_PORT and is meaningless without them.
+	 *
+	 * When transferring flow rules, ingress and egress attributes keep
+	 * their original meaning, as if processing traffic emitted or
+	 * received by the application.
+	 */
+	uint32_t transfer:1;
+	struct mlx5_meter_domains_infos *mfts;
+	/**< Flow table created for this meter. */
+	struct mlx5_flow_policer_stats policer_stats;
+	/**< Meter policer statistics. */
+	uint32_t ref_cnt;
+	/**< Use count. */
+	struct mlx5_indexed_pool *flow_ipool;
+	/**< Index pool for flow id. */
+};
+
+/* RFC2697 parameter structure. */
+struct mlx5_flow_meter_srtcm_rfc2697_prm {
+	rte_be32_t cbs_cir;
+	/*
+	 * bit 24-28: cbs_exponent, bit 16-23 cbs_mantissa,
+	 * bit 8-12: cir_exponent, bit 0-7 cir_mantissa.
+	 */
+	rte_be32_t ebs_eir;
+	/*
+	 * bit 24-28: ebs_exponent, bit 16-23 ebs_mantissa,
+	 * bit 8-12: eir_exponent, bit 0-7 eir_mantissa.
+	 */
+};
+
+/* Flow meter profile structure. */
+struct mlx5_flow_meter_profile {
+	TAILQ_ENTRY(mlx5_flow_meter_profile) next;
+	/**< Pointer to the next flow meter structure. */
+	uint32_t id; /**< Profile id. */
+	struct rte_mtr_meter_profile profile; /**< Profile detail. */
+	union {
+		struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm_prm;
+		/**< srtcm_rfc2697 struct. */
+	};
+	uint32_t ref_cnt; /**< Use count. */
+};
+
+/* 2 meters in each ASO cache line */
+#define MLX5_MTRS_CONTAINER_RESIZE 64
+/*
+ * The pool index and offset of meter in the pool array makes up the
+ * meter index. In case the meter is from pool 0 and offset 0, it
+ * should plus 1 to avoid index 0, since 0 means invalid meter index
+ * currently.
+ */
+#define MLX5_MAKE_MTR_IDX(pi, offset) \
+		((pi) * MLX5_ASO_MTRS_PER_POOL + (offset) + 1)
+
+/*aso flow meter state*/
+enum mlx5_aso_mtr_state {
+	ASO_METER_FREE, /* In free list. */
+	ASO_METER_WAIT, /* ACCESS_ASO WQE in progress. */
+	ASO_METER_READY, /* CQE received. */
+};
+
+/* Generic aso_flow_meter information. */
+struct mlx5_aso_mtr {
+	LIST_ENTRY(mlx5_aso_mtr) next;
+	struct mlx5_flow_meter_info fm;
+	/**< Pointer to the next aso flow meter structure. */
+	uint8_t state; /**< ASO flow meter state. */
+	uint8_t offset;
+};
+
+/* Generic aso_flow_meter pool structure. */
+struct mlx5_aso_mtr_pool {
+	struct mlx5_aso_mtr mtrs[MLX5_ASO_MTRS_PER_POOL];
+	/*Must be the first in pool*/
+	struct mlx5_devx_obj *devx_obj;
+	/* The devx object of the minimum aso flow meter ID. */
+	uint32_t index; /* Pool index in management structure. */
+};
+
+LIST_HEAD(aso_meter_list, mlx5_aso_mtr);
+/* Pools management structure for ASO flow meter pools. */
+struct mlx5_aso_mtr_pools_mng {
+	volatile uint16_t n_valid; /* Number of valid pools. */
+	uint16_t n; /* Number of pools. */
+	rte_spinlock_t mtrsl; /* The ASO flow meter free list lock. */
+	struct mlx5_l3t_tbl *mtr_idx_tbl; /* Meter index lookup table. */
+	struct aso_meter_list meters; /* Free ASO flow meter list. */
+	struct mlx5_aso_sq sq; /*SQ using by ASO flow meter. */
+	struct mlx5_aso_mtr_pool **pools; /* ASO flow meter pool array. */
+};
+
 /* Table key of the hash organization. */
 union mlx5_flow_tbl_key {
 	struct {
@@ -699,6 +887,7 @@ struct mlx5_dev_ctx_shared {
 	uint32_t rq_ts_format:2; /* RQ timestamp formats supported. */
 	uint32_t sq_ts_format:2; /* SQ timestamp formats supported. */
 	uint32_t qp_ts_format:2; /* QP timestamp formats supported. */
+	uint32_t meter_aso_en:1; /* Flow Meter ASO is supported. */
 	uint32_t max_port; /* Maximal IB device port index. */
 	struct mlx5_bond_info bond; /* Bonding information. */
 	void *ctx; /* Verbs/DV/DevX context. */
@@ -759,6 +948,8 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_geneve_tlv_option_resource *geneve_tlv_option_resource;
 	/* Management structure for geneve tlv option */
 	rte_spinlock_t geneve_tlv_opt_sl; /* Lock for geneve tlv resource */
+	struct mlx5_aso_mtr_pools_mng *mtrmng;
+	/* Meter pools management structure. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
 
@@ -776,7 +967,7 @@ struct mlx5_proc_priv {
 /* MTR profile list. */
 TAILQ_HEAD(mlx5_mtr_profiles, mlx5_flow_meter_profile);
 /* MTR list. */
-TAILQ_HEAD(mlx5_flow_meters, mlx5_flow_meter);
+TAILQ_HEAD(mlx5_legacy_flow_meters, mlx5_legacy_flow_meter);
 
 /* RSS description. */
 struct mlx5_flow_rss_desc {
@@ -994,7 +1185,7 @@ struct mlx5_priv {
 	uint8_t mtr_sfx_reg; /* Meter prefix-suffix flow match REG_C. */
 	uint8_t mtr_color_reg; /* Meter color match REG_C. */
 	struct mlx5_mtr_profiles flow_meter_profiles; /* MTR profile list. */
-	struct mlx5_flow_meters flow_meters; /* MTR list. */
+	struct mlx5_legacy_flow_meters flow_meters; /* MTR list. */
 	uint8_t skip_default_rss_reta; /* Skip configuration of default reta. */
 	uint8_t fdb_def_rule; /* Whether fdb jump to table 1 is configured. */
 	struct mlx5_mp_id mp_id; /* ID of a multi-process process */
@@ -1273,13 +1464,15 @@ int mlx5_pmd_socket_init(void);
 /* mlx5_flow_meter.c */
 
 int mlx5_flow_meter_ops_get(struct rte_eth_dev *dev, void *arg);
-struct mlx5_flow_meter *mlx5_flow_meter_find(struct mlx5_priv *priv,
-					     uint32_t meter_id);
+struct mlx5_flow_meter_info *mlx5_flow_meter_find(struct mlx5_priv *priv,
+		uint32_t meter_id, uint32_t *mtr_idx);
+struct mlx5_flow_meter_info *
+flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx);
 int mlx5_flow_meter_attach(struct mlx5_priv *priv,
-			   struct mlx5_flow_meter *fm,
+			   struct mlx5_flow_meter_info *fm,
 			   const struct rte_flow_attr *attr,
 			   struct rte_flow_error *error);
-void mlx5_flow_meter_detach(struct mlx5_flow_meter *fm);
+void mlx5_flow_meter_detach(struct mlx5_flow_meter_info *fm);
 
 /* mlx5_os.c */
 struct rte_pci_driver;
@@ -1324,7 +1517,7 @@ void mlx5_txpp_interrupt_handler(void *cb_arg);
 
 eth_tx_burst_t mlx5_select_tx_function(struct rte_eth_dev *dev);
 
-/* mlx5_flow_age.c */
+/* mlx5_flow_aso.c */
 
 int mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh);
 int mlx5_aso_queue_start(struct mlx5_dev_ctx_shared *sh);
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 643254e835..7f34f47e9f 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4360,6 +4360,8 @@ flow_create_split_inner(struct rte_eth_dev *dev,
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
+ * @param[in] flow
+ *   Parent flow structure pointer.
  * @param[in] fm
  *   Pointer to flow meter structure.
  * @param[in] items
@@ -4372,10 +4374,6 @@ flow_create_split_inner(struct rte_eth_dev *dev,
  *   Suffix flow actions.
  * @param[out] actions_pre
  *   Prefix flow actions.
- * @param[out] pattern_sfx
- *   The pattern items for the suffix flow.
- * @param[out] tag_sfx
- *   Pointer to suffix flow tag.
  * @param[out] error
  *   Perform verbose error reporting if not NULL.
  *
@@ -4384,7 +4382,8 @@ flow_create_split_inner(struct rte_eth_dev *dev,
  */
 static uint32_t
 flow_meter_split_prep(struct rte_eth_dev *dev,
-		      struct mlx5_flow_meter *fm,
+		      struct rte_flow *flow,
+		      struct mlx5_flow_meter_info *fm,
 		      const struct rte_flow_item items[],
 		      struct rte_flow_item sfx_items[],
 		      const struct rte_flow_action actions[],
@@ -4505,7 +4504,7 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 							    0, error),
 		.offset = mtr_id_offset,
 		.length = mtr_reg_bits,
-		.data = fm->idx,
+		.data = flow->meter,
 	};
 	/*
 	 * The color Reg bits used by flow_id are growing from
@@ -5233,9 +5232,10 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 	struct rte_flow_item *sfx_items = NULL;
 	struct mlx5_flow *dev_flow = NULL;
 	struct rte_flow_attr sfx_attr = *attr;
-	struct mlx5_flow_meter *fm = NULL;
+	struct mlx5_flow_meter_info *fm = NULL;
 	bool has_mtr = false;
 	uint32_t meter_id;
+	uint32_t mtr_idx = 0;
 	uint32_t mtr_tag_id = 0;
 	size_t act_size;
 	size_t item_size;
@@ -5247,14 +5247,13 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 						    &meter_id);
 	if (has_mtr) {
 		if (flow->meter) {
-			fm = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR],
-					    flow->meter);
+			fm = flow_dv_meter_find_by_idx(priv, flow->meter);
 			if (!fm)
 				return rte_flow_error_set(error, EINVAL,
 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
 						NULL, "Meter not found.");
 		} else {
-			fm = mlx5_flow_meter_find(priv, meter_id);
+			fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
 			if (!fm)
 				return rte_flow_error_set(error, EINVAL,
 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
@@ -5263,7 +5262,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 						     &sfx_attr, error);
 			if (ret)
 				return -rte_errno;
-			flow->meter = fm->idx;
+			flow->meter = mtr_idx;
 		}
 		wks->fm = fm;
 		/* The prefix actions: meter, decap, encap, tag, end. */
@@ -5283,9 +5282,10 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 		sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
 			     act_size);
 		pre_actions = sfx_actions + actions_n;
-		mtr_tag_id = flow_meter_split_prep(dev, fm, items, sfx_items,
-						   actions, sfx_actions,
-						   pre_actions, error);
+		mtr_tag_id = flow_meter_split_prep(dev, flow, fm, items,
+						   sfx_items, actions,
+						   sfx_actions, pre_actions,
+						   error);
 		if (!mtr_tag_id) {
 			ret = -rte_errno;
 			goto exit;
@@ -6622,7 +6622,7 @@ mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
  */
 int
 mlx5_flow_prepare_policer_rules(struct rte_eth_dev *dev,
-			       struct mlx5_flow_meter *fm,
+			       struct mlx5_flow_meter_info *fm,
 			       const struct rte_flow_attr *attr)
 {
 	const struct mlx5_flow_driver_ops *fops;
@@ -6644,7 +6644,7 @@ mlx5_flow_prepare_policer_rules(struct rte_eth_dev *dev,
  */
 int
 mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
-				struct mlx5_flow_meter *fm,
+				struct mlx5_flow_meter_info *fm,
 				const struct rte_flow_attr *attr)
 {
 	const struct mlx5_flow_driver_ops *fops;
@@ -6653,6 +6653,44 @@ mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
 	return fops->destroy_policer_rules(dev, fm, attr);
 }
 
+/**
+ * Allocate the needed aso flow meter id.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ *
+ * @return
+ *   Index to aso flow meter on success, NULL otherwise.
+ */
+uint32_t
+mlx5_flow_mtr_alloc(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_meter(dev);
+}
+
+/**
+ * Free the aso flow meter id.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_idx
+ *  Index to aso flow meter to be free.
+ *
+ * @return
+ *   0 on success.
+ */
+void
+mlx5_flow_mtr_free(struct rte_eth_dev *dev, uint32_t mtr_idx)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->free_meter(dev, mtr_idx);
+}
+
 /**
  * Allocate a counter.
  *
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 11482f178f..b0a743477c 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -827,148 +827,17 @@ struct mlx5_flow {
 #define MLX5_FLOW_METER_DISABLE 0
 #define MLX5_FLOW_METER_ENABLE 1
 
-#define MLX5_MAN_WIDTH 8
-/* Modify this value if enum rte_mtr_color changes. */
-#define RTE_MTR_DROPPED RTE_COLORS
-
-/* Meter policer statistics */
-struct mlx5_flow_policer_stats {
-	uint32_t pass_cnt;
-	/**< Color counter for pass. */
-	uint32_t drop_cnt;
-	/**< Color counter for drop. */
-};
-
-/* Meter table structure. */
-struct mlx5_meter_domain_info {
-	struct mlx5_flow_tbl_resource *tbl;
-	/**< Meter table. */
-	struct mlx5_flow_tbl_resource *sfx_tbl;
-	/**< Meter suffix table. */
-	struct mlx5_flow_dv_matcher *drop_matcher;
-	/**< Matcher for Drop. */
-	struct mlx5_flow_dv_matcher *color_matcher;
-	/**< Matcher for Color. */
-	void *jump_actn;
-	/**< Meter match action. */
-	void *green_rule;
-	/**< Meter green rule. */
-	void *drop_rule;
-	/**< Meter drop rule. */
-};
-
-/* Meter table set for TX RX FDB. */
-struct mlx5_meter_domains_infos {
-	uint32_t ref_cnt;
-	/**< Table user count. */
-	struct mlx5_meter_domain_info egress;
-	/**< TX meter table. */
-	struct mlx5_meter_domain_info ingress;
-	/**< RX meter table. */
-	struct mlx5_meter_domain_info transfer;
-	/**< FDB meter table. */
-	void *green_count;
-	/**< Counters for green rule. */
-	void *drop_count;
-	/**< Counters for green rule. */
-	uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];
-	/**< Flow meter parameter. */
-	size_t fmp_size;
-	/**< Flow meter parameter size. */
-	void *meter_action;
-	/**< Flow meter action. */
-};
+#define MLX5_ASO_CQE_RESPONSE_DELAY 10
+#define MLX5_MTR_POLL_CQE_TIMES    100000u
 
-/* Meter parameter structure. */
-struct mlx5_flow_meter {
-	TAILQ_ENTRY(mlx5_flow_meter) next;
+#define MLX5_MAN_WIDTH 8
+/* Legacy Meter parameter structure. */
+struct mlx5_legacy_flow_meter {
+	struct mlx5_flow_meter_info fm;
+	/* Must be the first in struct. */
+	TAILQ_ENTRY(mlx5_legacy_flow_meter) next;
 	/**< Pointer to the next flow meter structure. */
 	uint32_t idx; /* Index to meter object. */
-	uint32_t meter_id;
-	/**< Meter id. */
-	struct mlx5_flow_meter_profile *profile;
-	/**< Meter profile parameters. */
-
-	rte_spinlock_t sl; /**< Meter action spinlock. */
-
-	/** Policer actions (per meter output color). */
-	enum rte_mtr_policer_action action[RTE_COLORS];
-
-	uint32_t green_bytes:1;
-	/** Set green bytes stats to be enabled. */
-	uint32_t green_pkts:1;
-	/** Set green packets stats to be enabled. */
-	uint32_t red_bytes:1;
-	/** Set red bytes stats to be enabled. */
-	uint32_t red_pkts:1;
-	/** Set red packets stats to be enabled. */
-	uint32_t bytes_dropped:1;
-	/** Set bytes dropped stats to be enabled. */
-	uint32_t pkts_dropped:1;
-	/** Set packets dropped stats to be enabled. */
-
-	/**< Rule applies to ingress traffic. */
-	uint32_t ingress:1;
-
-	/**< Rule applies to egress traffic. */
-	uint32_t egress:1;
-	/**
-	 * Instead of simply matching the properties of traffic as it would
-	 * appear on a given DPDK port ID, enabling this attribute transfers
-	 * a flow rule to the lowest possible level of any device endpoints
-	 * found in the pattern.
-	 *
-	 * When supported, this effectively enables an application to
-	 * re-route traffic not necessarily intended for it (e.g. coming
-	 * from or addressed to different physical ports, VFs or
-	 * applications) at the device level.
-	 *
-	 * It complements the behavior of some pattern items such as
-	 * RTE_FLOW_ITEM_TYPE_PHY_PORT and is meaningless without them.
-	 *
-	 * When transferring flow rules, ingress and egress attributes keep
-	 * their original meaning, as if processing traffic emitted or
-	 * received by the application.
-	 */
-	uint32_t transfer:1;
-	struct mlx5_meter_domains_infos *mfts;
-	/**< Flow table created for this meter. */
-	struct mlx5_flow_policer_stats policer_stats;
-	/**< Meter policer statistics. */
-	uint32_t ref_cnt;
-	/**< Use count. */
-	uint32_t active_state:1;
-	/**< Meter state. */
-	uint32_t shared:1;
-	/**< Meter shared or not. */
-	struct mlx5_indexed_pool *flow_ipool;
-	/**< Index pool for flow id. */
-};
-
-/* RFC2697 parameter structure. */
-struct mlx5_flow_meter_srtcm_rfc2697_prm {
-	/* green_saturation_value = cbs_mantissa * 2^cbs_exponent */
-	uint32_t cbs_exponent:5;
-	uint32_t cbs_mantissa:8;
-	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent) Bytes/Sec */
-	uint32_t cir_exponent:5;
-	uint32_t cir_mantissa:8;
-	/* yellow _saturation_value = ebs_mantissa * 2^ebs_exponent */
-	uint32_t ebs_exponent:5;
-	uint32_t ebs_mantissa:8;
-};
-
-/* Flow meter profile structure. */
-struct mlx5_flow_meter_profile {
-	TAILQ_ENTRY(mlx5_flow_meter_profile) next;
-	/**< Pointer to the next flow meter structure. */
-	uint32_t meter_profile_id; /**< Profile id. */
-	struct rte_mtr_meter_profile profile; /**< Profile detail. */
-	union {
-		struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm_prm;
-		/**< srtcm_rfc2697 struct. */
-	};
-	uint32_t ref_cnt; /**< Use count. */
 };
 
 #define MLX5_MAX_TUNNELS 256
@@ -1094,7 +963,7 @@ struct rte_flow {
 	/**< Device flow handles that are part of the flow. */
 	uint32_t drv_type:2; /**< Driver type. */
 	uint32_t tunnel:1;
-	uint32_t meter:16; /**< Holds flow meter id. */
+	uint32_t meter:24; /**< Holds flow meter id. */
 	uint32_t rix_mreg_copy;
 	/**< Index to metadata register copy table resource. */
 	uint32_t counter; /**< Holds flow counter. */
@@ -1181,7 +1050,7 @@ struct mlx5_flow_workspace {
 	struct mlx5_flow_rss_desc rss_desc;
 	uint32_t rssq_num; /* Allocated queue num in rss_desc. */
 	uint32_t flow_idx; /* Intermediate device flow index. */
-	struct mlx5_flow_meter *fm; /* Pointer to the meter in flow. */
+	struct mlx5_flow_meter_info *fm; /* Pointer to the meter in flow. */
 };
 
 struct mlx5_flow_split_info {
@@ -1227,12 +1096,16 @@ typedef int (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 					struct mlx5_meter_domains_infos *tbls);
 typedef int (*mlx5_flow_create_policer_rules_t)
 					(struct rte_eth_dev *dev,
-					 struct mlx5_flow_meter *fm,
+					 struct mlx5_flow_meter_info *fm,
 					 const struct rte_flow_attr *attr);
 typedef int (*mlx5_flow_destroy_policer_rules_t)
 					(struct rte_eth_dev *dev,
-					 const struct mlx5_flow_meter *fm,
+					 const struct mlx5_flow_meter_info *fm,
 					 const struct rte_flow_attr *attr);
+typedef uint32_t (*mlx5_flow_mtr_alloc_t)
+					    (struct rte_eth_dev *dev);
+typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
+						uint32_t mtr_idx);
 typedef uint32_t (*mlx5_flow_counter_alloc_t)
 				   (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_counter_free_t)(struct rte_eth_dev *dev,
@@ -1287,6 +1160,8 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
 	mlx5_flow_create_policer_rules_t prepare_policer_rules;
 	mlx5_flow_destroy_policer_rules_t destroy_policer_rules;
+	mlx5_flow_mtr_alloc_t create_meter;
+	mlx5_flow_mtr_free_t free_meter;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1346,6 +1221,32 @@ tunnel_use_standard_attr_group_translate
 	return verdict;
 }
 
+/**
+ * Get DV flow aso meter by index.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] idx
+ *   mlx5 flow aso meter index in the container.
+ * @param[out] ppool
+ *   mlx5 flow aso meter pool in the container,
+ *
+ * @return
+ *   Pointer to the aso meter, NULL otherwise.
+ */
+static inline struct mlx5_aso_mtr *
+mlx5_aso_meter_by_idx(struct mlx5_priv *priv, uint32_t idx)
+{
+	struct mlx5_aso_mtr_pool *pool;
+	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+
+	/* Decrease to original index. */
+	idx--;
+	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < mtrmng->n);
+	pool = mtrmng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
+	return &pool->mtrs[idx % MLX5_ASO_MTRS_PER_POOL];
+}
+
 int mlx5_flow_group_to_table(struct rte_eth_dev *dev,
 			     const struct mlx5_flow_tunnel *tunnel,
 			     uint32_t group, uint32_t *table,
@@ -1489,10 +1390,10 @@ struct mlx5_meter_domains_infos *mlx5_flow_create_mtr_tbls
 int mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_meter_domains_infos *tbl);
 int mlx5_flow_prepare_policer_rules(struct rte_eth_dev *dev,
-				   struct mlx5_flow_meter *fm,
+				   struct mlx5_flow_meter_info *fm,
 				   const struct rte_flow_attr *attr);
 int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
-				    struct mlx5_flow_meter *fm,
+				    struct mlx5_flow_meter_info *fm,
 				    const struct rte_flow_attr *attr);
 int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
 			  struct rte_mtr_error *error);
@@ -1588,12 +1489,11 @@ struct mlx5_aso_age_action *flow_aso_age_get_by_idx(struct rte_eth_dev *dev,
 int flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev,
 					     const struct rte_flow_item *item,
 					     struct rte_flow_error *error);
-
 void flow_release_workspace(void *data);
 int mlx5_flow_os_init_workspace_once(void);
 void *mlx5_flow_os_get_specific_workspace(void);
 int mlx5_flow_os_set_specific_workspace(struct mlx5_flow_workspace *data);
 void mlx5_flow_os_release_workspace(void);
-
-
+uint32_t mlx5_flow_mtr_alloc(struct rte_eth_dev *dev);
+void mlx5_flow_mtr_free(struct rte_eth_dev *dev, uint32_t mtr_idx);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index dfd734353c..cf55ed6353 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -4866,7 +4866,7 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	const struct rte_flow_action_meter *am = action->conf;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_flow_meter_info *fm;
 
 	if (!am)
 		return rte_flow_error_set(error, EINVAL,
@@ -4886,7 +4886,7 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
 					  NULL,
 					  "meter action not supported");
-	fm = mlx5_flow_meter_find(priv, am->mtr_id);
+	fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL);
 	if (!fm)
 		return rte_flow_error_set(error, EINVAL,
 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
@@ -5939,6 +5939,161 @@ flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter)
 	}
 }
 
+/**
+ * Resize a meter id container.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value and rte_errno is set.
+ */
+static int
+flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	void *old_pools = mtrmng->pools;
+	uint32_t resize = mtrmng->n + MLX5_MTRS_CONTAINER_RESIZE;
+	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
+	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
+
+	if (!pools) {
+		rte_errno = ENOMEM;
+		return -ENOMEM;
+	}
+	if (old_pools)
+		memcpy(pools, old_pools, mtrmng->n *
+				       sizeof(struct mlx5_aso_mtr_pool *));
+	mtrmng->n = resize;
+	mtrmng->pools = pools;
+	if (old_pools)
+		mlx5_free(old_pools);
+	return 0;
+}
+
+/**
+ * Prepare a new meter and/or a new meter pool.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[out] mtr_free
+ *   Where to put the pointer of a new meter.g.
+ *
+ * @return
+ *   The meter pool pointer and @mtr_free is set on success,
+ *   NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_aso_mtr_pool *
+flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
+			     struct mlx5_aso_mtr **mtr_free)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pool *pool = NULL;
+	struct mlx5_devx_obj *dcs = NULL;
+	uint32_t i;
+	uint32_t log_obj_size;
+
+	log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1);
+	dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->ctx,
+			priv->sh->pdn, log_obj_size);
+	if (!dcs) {
+		rte_errno = ENODATA;
+		return NULL;
+	}
+	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
+	if (!pool) {
+		rte_errno = ENOMEM;
+		claim_zero(mlx5_devx_cmd_destroy(dcs));
+		return NULL;
+	}
+	pool->devx_obj = dcs;
+	pool->index = mtrmng->n_valid;
+	if (pool->index == mtrmng->n && flow_dv_mtr_container_resize(dev)) {
+		mlx5_free(pool);
+		claim_zero(mlx5_devx_cmd_destroy(dcs));
+		return NULL;
+	}
+	mtrmng->pools[pool->index] = pool;
+	mtrmng->n_valid++;
+	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
+		pool->mtrs[i].offset = i;
+		pool->mtrs[i].fm.meter_id = UINT32_MAX;
+		LIST_INSERT_HEAD(&mtrmng->meters,
+						&pool->mtrs[i], next);
+	}
+	pool->mtrs[0].offset = 0;
+	pool->mtrs[0].fm.meter_id = UINT32_MAX;
+	*mtr_free = &pool->mtrs[0];
+	return pool;
+}
+
+/**
+ * Release a flow meter into pool.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_idx
+ *   Index to aso flow meter.
+ */
+static void
+flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
+
+	MLX5_ASSERT(aso_mtr);
+	rte_spinlock_lock(&mtrmng->mtrsl);
+	memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
+	aso_mtr->state = ASO_METER_FREE;
+	aso_mtr->fm.meter_id = UINT32_MAX;
+	LIST_INSERT_HEAD(&mtrmng->meters, aso_mtr, next);
+	rte_spinlock_unlock(&mtrmng->mtrsl);
+}
+
+/**
+ * Allocate a aso flow meter.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ *
+ * @return
+ *   Index to aso flow meter on success, 0 otherwise and rte_errno is set.
+ */
+static uint32_t
+flow_dv_mtr_alloc(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_aso_mtr *mtr_free = NULL;
+	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pool *pool;
+	uint32_t mtr_idx = 0;
+
+	if (!priv->config.devx) {
+		rte_errno = ENOTSUP;
+		return 0;
+	}
+	/* Allocate the flow meter memory. */
+	/* Get free meters from management. */
+	rte_spinlock_lock(&mtrmng->mtrsl);
+	mtr_free = LIST_FIRST(&mtrmng->meters);
+	if (mtr_free)
+		LIST_REMOVE(mtr_free, next);
+	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
+		rte_spinlock_unlock(&mtrmng->mtrsl);
+		return 0;
+	}
+	mtr_free->state = ASO_METER_WAIT;
+	rte_spinlock_unlock(&mtrmng->mtrsl);
+	pool = container_of(mtr_free,
+					struct mlx5_aso_mtr_pool,
+					mtrs[mtr_free->offset]);
+	mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
+	return mtr_idx;
+}
+
 /**
  * Verify the @p attributes will be correctly understood by the NIC and store
  * them in the @p flow if everything is correct.
@@ -12569,7 +12724,7 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
 {
 	struct mlx5_flow_handle *dev_handle;
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_meter *fm = NULL;
+	struct mlx5_flow_meter_info *fm = NULL;
 	uint32_t srss = 0;
 
 	if (!flow)
@@ -12580,8 +12735,7 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
 		flow->counter = 0;
 	}
 	if (flow->meter) {
-		fm = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR],
-				    flow->meter);
+		fm = flow_dv_meter_find_by_idx(priv, flow->meter);
 		if (fm)
 			mlx5_flow_meter_detach(fm);
 		flow->meter = 0;
@@ -13679,7 +13833,7 @@ flow_dv_destroy_domain_policer_rule(struct rte_eth_dev *dev,
  */
 static int
 flow_dv_destroy_policer_rules(struct rte_eth_dev *dev,
-			      const struct mlx5_flow_meter *fm,
+			      const struct mlx5_flow_meter_info *fm,
 			      const struct rte_flow_attr *attr)
 {
 	struct mlx5_meter_domains_infos *mtb = fm ? fm->mfts : NULL;
@@ -13702,6 +13856,8 @@ flow_dv_destroy_policer_rules(struct rte_eth_dev *dev,
  *   Pointer to Ethernet device.
  * @param[in] fm
  *   Pointer to flow meter structure.
+ * @param[in] mtr_idx
+ *   meter index.
  * @param[in] mtb
  *   Pointer to DV meter table set.
  * @param[out] drop_rule
@@ -13714,7 +13870,8 @@ flow_dv_destroy_policer_rules(struct rte_eth_dev *dev,
  */
 static int
 flow_dv_create_policer_forward_rule(struct rte_eth_dev *dev,
-				    struct mlx5_flow_meter *fm,
+				    struct mlx5_flow_meter_info *fm,
+				    uint32_t mtr_idx,
 				    struct mlx5_meter_domain_info *dtb,
 				    void **drop_rule,
 				    void **green_rule)
@@ -13762,7 +13919,7 @@ flow_dv_create_policer_forward_rule(struct rte_eth_dev *dev,
 	/* Create Drop flow, matching meter_id only. */
 	i = 0;
 	flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_id_reg_c,
-			       (fm->idx << mtr_id_offset), UINT32_MAX);
+			       (mtr_idx << mtr_id_offset), UINT32_MAX);
 	if (mtb->drop_count)
 		actions[i++] = mtb->drop_count;
 	actions[i++] = priv->sh->dr_drop_action;
@@ -13776,7 +13933,7 @@ flow_dv_create_policer_forward_rule(struct rte_eth_dev *dev,
 	i = 0;
 	if (priv->mtr_reg_share) {
 		flow_dv_match_meta_reg(matcher.buf, value.buf, color_reg_c,
-				       ((fm->idx << mtr_id_offset) |
+				       ((mtr_idx << mtr_id_offset) |
 					rte_col_2_mlx5_col(RTE_COLOR_GREEN)),
 				       UINT32_MAX);
 	} else {
@@ -13784,7 +13941,7 @@ flow_dv_create_policer_forward_rule(struct rte_eth_dev *dev,
 				       rte_col_2_mlx5_col(RTE_COLOR_GREEN),
 				       UINT32_MAX);
 		flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_id_reg_c,
-				       fm->idx, UINT32_MAX);
+				       mtr_idx, UINT32_MAX);
 	}
 	if (mtb->green_count)
 		actions[i++] = mtb->green_count;
@@ -13817,9 +13974,10 @@ flow_dv_create_policer_forward_rule(struct rte_eth_dev *dev,
  */
 static int
 flow_dv_prepare_policer_rules(struct rte_eth_dev *dev,
-			      struct mlx5_flow_meter *fm,
+			      struct mlx5_flow_meter_info *fm,
 			      const struct rte_flow_attr *attr)
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_meter_domains_infos *mtb = fm->mfts;
 	bool initialized = false;
 	struct mlx5_flow_counter *cnt;
@@ -13829,6 +13987,7 @@ flow_dv_prepare_policer_rules(struct rte_eth_dev *dev,
 	void *ingress_green_rule = NULL;
 	void *transfer_drop_rule = NULL;
 	void *transfer_green_rule = NULL;
+	uint32_t mtr_idx;
 	int ret;
 
 	/* Get the statistics counters for green/drop. */
@@ -13855,9 +14014,23 @@ flow_dv_prepare_policer_rules(struct rte_eth_dev *dev,
 	 */
 	if (mtb->egress.drop_rule)
 		initialized = true;
+	if (priv->sh->meter_aso_en) {
+		struct mlx5_aso_mtr *aso_mtr = NULL;
+		struct mlx5_aso_mtr_pool *pool;
+
+		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
+		pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool,
+				    mtrs[aso_mtr->offset]);
+		mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, aso_mtr->offset);
+	} else {
+		struct mlx5_legacy_flow_meter *legacy_fm;
+
+		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
+		mtr_idx = legacy_fm->idx;
+	}
 	if (attr->egress) {
 		ret = flow_dv_create_policer_forward_rule(dev,
-				fm, &mtb->egress,
+				fm, mtr_idx, &mtb->egress,
 				&egress_drop_rule, &egress_green_rule);
 		if (ret) {
 			DRV_LOG(ERR, "Failed to create egress policer.");
@@ -13866,7 +14039,7 @@ flow_dv_prepare_policer_rules(struct rte_eth_dev *dev,
 	}
 	if (attr->ingress) {
 		ret = flow_dv_create_policer_forward_rule(dev,
-				fm, &mtb->ingress,
+				fm, mtr_idx, &mtb->ingress,
 				&ingress_drop_rule, &ingress_green_rule);
 		if (ret) {
 			DRV_LOG(ERR, "Failed to create ingress policer.");
@@ -13875,7 +14048,7 @@ flow_dv_prepare_policer_rules(struct rte_eth_dev *dev,
 	}
 	if (attr->transfer) {
 		ret = flow_dv_create_policer_forward_rule(dev,
-				fm, &mtb->transfer,
+				fm, mtr_idx, &mtb->transfer,
 				&transfer_drop_rule, &transfer_green_rule);
 		if (ret) {
 			DRV_LOG(ERR, "Failed to create transfer policer.");
@@ -14215,6 +14388,8 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
 	.prepare_policer_rules = flow_dv_prepare_policer_rules,
 	.destroy_policer_rules = flow_dv_destroy_policer_rules,
+	.create_meter = flow_dv_mtr_alloc,
+	.free_meter = flow_dv_aso_mtr_release_to_pool,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 2a37decaaf..956a6c33e7 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -28,40 +28,43 @@
  */
 static void *
 mlx5_flow_meter_action_create(struct mlx5_priv *priv,
-			      struct mlx5_flow_meter *fm)
+			      struct mlx5_flow_meter_info *fm)
 {
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
 	struct mlx5dv_dr_flow_meter_attr mtr_init;
-	void *attr = fm->mfts->fmp;
+	uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];
 	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm =
 						     &fm->profile->srtcm_prm;
+	uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
+	uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
+	uint32_t val;
 
-	fm->mfts->fmp_size = MLX5_ST_SZ_BYTES(flow_meter_parameters);
-	memset(attr, 0, fm->mfts->fmp_size);
-	MLX5_SET(flow_meter_parameters, attr, valid, 1);
-	MLX5_SET(flow_meter_parameters, attr, bucket_overflow, 1);
-	MLX5_SET(flow_meter_parameters, attr,
-		 start_color, MLX5_FLOW_COLOR_GREEN);
-	MLX5_SET(flow_meter_parameters, attr, both_buckets_on_green, 0);
-	MLX5_SET(flow_meter_parameters,
-		 attr, cbs_exponent, srtcm->cbs_exponent);
-	MLX5_SET(flow_meter_parameters,
-		 attr, cbs_mantissa, srtcm->cbs_mantissa);
-	MLX5_SET(flow_meter_parameters,
-		 attr, cir_exponent, srtcm->cir_exponent);
-	MLX5_SET(flow_meter_parameters,
-		 attr, cir_mantissa, srtcm->cir_mantissa);
-	MLX5_SET(flow_meter_parameters,
-		 attr, ebs_exponent, srtcm->ebs_exponent);
-	MLX5_SET(flow_meter_parameters,
-		 attr, ebs_mantissa, srtcm->ebs_mantissa);
+	memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
+	MLX5_SET(flow_meter_parameters, fmp, valid, 1);
+	MLX5_SET(flow_meter_parameters, fmp, bucket_overflow, 1);
+	MLX5_SET(flow_meter_parameters, fmp,
+		start_color, MLX5_FLOW_COLOR_GREEN);
+	MLX5_SET(flow_meter_parameters, fmp, both_buckets_on_green, 0);
+	val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
+	MLX5_SET(flow_meter_parameters, fmp, cbs_exponent, val);
+	val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
+	MLX5_SET(flow_meter_parameters, fmp, cbs_mantissa, val);
+	val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
+	MLX5_SET(flow_meter_parameters, fmp, cir_exponent, val);
+	val = (cbs_cir & ASO_DSEG_MAN_MASK);
+	MLX5_SET(flow_meter_parameters, fmp, cir_mantissa, val);
+	val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
+	MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
+	val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
+	MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
 	mtr_init.next_table =
 		fm->transfer ? fm->mfts->transfer.tbl->obj :
-		    fm->egress ? fm->mfts->egress.tbl->obj :
-				       fm->mfts->ingress.tbl->obj;
+			fm->egress ? fm->mfts->egress.tbl->obj :
+				fm->mfts->ingress.tbl->obj;
 	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
-	mtr_init.flow_meter_parameter = fm->mfts->fmp;
-	mtr_init.flow_meter_parameter_sz = fm->mfts->fmp_size;
+	mtr_init.flow_meter_parameter = fmp;
+	mtr_init.flow_meter_parameter_sz =
+		MLX5_ST_SZ_BYTES(flow_meter_parameters);
 	mtr_init.active = fm->active_state;
 	return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
 #else
@@ -89,7 +92,7 @@ mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
 	struct mlx5_flow_meter_profile *fmp;
 
 	TAILQ_FOREACH(fmp, fmps, next)
-		if (meter_profile_id == fmp->meter_profile_id)
+		if (meter_profile_id == fmp->id)
 			return fmp;
 	return NULL;
 }
@@ -239,44 +242,51 @@ mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
 {
 	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
 	uint8_t man, exp;
+	uint32_t cbs_exp, cbs_man, cir_exp, cir_man;
+	uint32_t ebs_exp, ebs_man;
 
 	if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
 		return -rte_mtr_error_set(error, ENOTSUP,
 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
 				NULL, "Metering algorithm not supported.");
+	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
+	mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir,
+				    &man, &exp);
+	/* Check if cir mantissa is too large. */
+	if (exp > ASO_DSEG_CIR_EXP_MASK)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
+					  "meter profile parameter cir is"
+					  " not supported.");
+	cir_man = man;
+	cir_exp = exp;
 	 /* cbs = cbs_mantissa * 2^cbs_exponent */
 	mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs,
 				    &man, &exp);
-	srtcm->cbs_mantissa = man;
-	srtcm->cbs_exponent = exp;
 	/* Check if cbs mantissa is too large. */
-	if (srtcm->cbs_exponent != exp)
-		return -rte_mtr_error_set(error, EINVAL,
+	if (exp > ASO_DSEG_EXP_MASK)
+		return -rte_mtr_error_set(error, ENOTSUP,
 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
-					  "Metering profile parameter cbs is"
-					  " invalid.");
-	/* ebs = ebs_mantissa * 2^ebs_exponent */
+					  "meter profile parameter cbs is"
+					  " not supported.");
+	cbs_man = man;
+	cbs_exp = exp;
+	srtcm->cbs_cir = rte_cpu_to_be_32(cbs_exp << ASO_DSEG_CBS_EXP_OFFSET |
+				cbs_man << ASO_DSEG_CBS_MAN_OFFSET |
+				cir_exp << ASO_DSEG_CIR_EXP_OFFSET |
+				cir_man);
 	mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs,
 				    &man, &exp);
-	srtcm->ebs_mantissa = man;
-	srtcm->ebs_exponent = exp;
 	/* Check if ebs mantissa is too large. */
-	if (srtcm->ebs_exponent != exp)
-		return -rte_mtr_error_set(error, EINVAL,
-					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
-					  "Metering profile parameter ebs is"
-					  " invalid.");
-	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
-	mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir,
-				    &man, &exp);
-	srtcm->cir_mantissa = man;
-	srtcm->cir_exponent = exp;
-	/* Check if cir mantissa is too large. */
-	if (srtcm->cir_exponent != exp)
-		return -rte_mtr_error_set(error, EINVAL,
+	if (exp > ASO_DSEG_EXP_MASK)
+		return -rte_mtr_error_set(error, ENOTSUP,
 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
-					  "Metering profile parameter cir is"
-					  " invalid.");
+					  "meter profile parameter ebs is"
+					  " not supported.");
+	ebs_man = man;
+	ebs_exp = exp;
+	srtcm->ebs_eir = rte_cpu_to_be_32(ebs_exp << ASO_DSEG_EBS_EXP_OFFSET |
+					ebs_man << ASO_DSEG_EBS_MAN_OFFSET);
 	return 0;
 }
 
@@ -306,7 +316,11 @@ mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 					  "Meter is not supported");
 	memset(cap, 0, sizeof(*cap));
-	cap->n_max = 1 << qattr->log_max_flow_meter;
+	if (priv->sh->meter_aso_en)
+	    /* 2 meters per one ASO cache line. */
+		cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
+	else
+		cap->n_max = 1 << qattr->log_max_flow_meter;
 	cap->n_shared_max = cap->n_max;
 	cap->identical = 1;
 	cap->shared_identical = 1;
@@ -365,7 +379,7 @@ mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
 					  NULL, "Meter profile memory "
 					  "alloc failed.");
 	/* Fill profile info. */
-	fmp->meter_profile_id = meter_profile_id;
+	fmp->id = meter_profile_id;
 	fmp->profile = *profile;
 	/* Fill the flow meter parameters for the PRM. */
 	ret = mlx5_flow_meter_param_fill(fmp, error);
@@ -499,7 +513,7 @@ mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
 				 NULL,
 				 "Green color only supports recolor green action.");
 	/* Validate meter id. */
-	if (mlx5_flow_meter_find(priv, meter_id))
+	if (mlx5_flow_meter_find(priv, meter_id, NULL))
 		return -rte_mtr_error_set(error, EEXIST,
 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
 					  "Meter object already exists.");
@@ -524,7 +538,7 @@ mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
  */
 static int
 mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
-		struct mlx5_flow_meter *fm,
+		struct mlx5_flow_meter_info *fm,
 		const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
 		uint64_t modify_bits, uint32_t active_state)
 {
@@ -533,33 +547,37 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
 	uint32_t *attr;
 	struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
 	int ret;
+	uint32_t cbs_cir, ebs_eir, val;
 
 	/* Fill command parameters. */
 	mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
 	mod_attr.flow_meter_parameter = in;
-	mod_attr.flow_meter_parameter_sz = fm->mfts->fmp_size;
+	mod_attr.flow_meter_parameter_sz =
+				MLX5_ST_SZ_BYTES(flow_meter_parameters);
 	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
 		mod_attr.active = !!active_state;
 	else
 		mod_attr.active = 0;
 	attr = in;
+	cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
+	ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
 	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
-		MLX5_SET(flow_meter_parameters,
-			 attr, cbs_exponent, srtcm->cbs_exponent);
-		MLX5_SET(flow_meter_parameters,
-			 attr, cbs_mantissa, srtcm->cbs_mantissa);
+		val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
+		MLX5_SET(flow_meter_parameters, attr, cbs_exponent, val);
+		val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
+		MLX5_SET(flow_meter_parameters, attr, cbs_mantissa, val);
 	}
 	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
-		MLX5_SET(flow_meter_parameters,
-			 attr, cir_exponent, srtcm->cir_exponent);
-		MLX5_SET(flow_meter_parameters,
-			 attr, cir_mantissa, srtcm->cir_mantissa);
+		val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
+		MLX5_SET(flow_meter_parameters, attr, cir_exponent, val);
+		val = cbs_cir & ASO_DSEG_MAN_MASK;
+		MLX5_SET(flow_meter_parameters, attr, cir_mantissa, val);
 	}
 	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
-		MLX5_SET(flow_meter_parameters,
-			 attr, ebs_exponent, srtcm->ebs_exponent);
-		MLX5_SET(flow_meter_parameters,
-			 attr, ebs_mantissa, srtcm->ebs_mantissa);
+		val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
+		MLX5_SET(flow_meter_parameters, attr, ebs_exponent, val);
+		val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
+		MLX5_SET(flow_meter_parameters, attr, ebs_mantissa, val);
 	}
 	/* Apply modifications to meter only if it was created. */
 	if (fm->mfts->meter_action) {
@@ -572,26 +590,6 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
 	/* Update succeedded modify meter parameters. */
 	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
 		fm->active_state = !!active_state;
-	attr = fm->mfts->fmp;
-	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
-		MLX5_SET(flow_meter_parameters,
-			 attr, cbs_exponent, srtcm->cbs_exponent);
-		MLX5_SET(flow_meter_parameters,
-			 attr, cbs_mantissa, srtcm->cbs_mantissa);
-	}
-	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
-		MLX5_SET(flow_meter_parameters,
-			 attr, cir_exponent, srtcm->cir_exponent);
-		MLX5_SET(flow_meter_parameters,
-			 attr, cir_mantissa, srtcm->cir_mantissa);
-	}
-	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
-		MLX5_SET(flow_meter_parameters,
-			 attr, ebs_exponent, srtcm->ebs_exponent);
-		MLX5_SET(flow_meter_parameters,
-			 attr, ebs_mantissa, srtcm->ebs_mantissa);
-	}
-
 	return 0;
 #else
 	(void)priv;
@@ -604,7 +602,7 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
 }
 
 static void
-mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter *fm,
+mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
 				uint64_t stats_mask)
 {
 	fm->green_bytes = (stats_mask & RTE_MTR_STATS_N_BYTES_GREEN) ? 1 : 0;
@@ -639,9 +637,10 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
 		       struct rte_mtr_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_flow_meter_profile *fmp;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_legacy_flow_meter *legacy_fm;
+	struct mlx5_flow_meter_info *fm;
 	const struct rte_flow_attr attr = {
 				.ingress = 1,
 				.egress = 1,
@@ -653,8 +652,9 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
 		.need_lock = 1,
 		.type = "mlx5_flow_mtr_flow_id_pool",
 	};
+	struct mlx5_aso_mtr *aso_mtr;
+	uint32_t mtr_idx;
 	int ret;
-	uint32_t idx = 0;
 	uint8_t mtr_id_bits;
 	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
 				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
@@ -674,19 +674,31 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
 					  NULL, "Meter profile id not valid.");
 	/* Allocate the flow meter memory. */
-	fm = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MTR], &idx);
-	if (fm == NULL)
-		return -rte_mtr_error_set(error, ENOMEM,
-					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
-					  "Memory alloc failed for meter.");
-	mtr_id_bits = MLX5_REG_BITS - __builtin_clz(idx);
+	if (priv->sh->meter_aso_en) {
+		mtr_idx = mlx5_flow_mtr_alloc(dev);
+		if (!mtr_idx)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
+		fm = &aso_mtr->fm;
+	} else {
+		legacy_fm = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
+		if (legacy_fm == NULL)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		legacy_fm->idx = mtr_idx;
+		fm = &legacy_fm->fm;
+	}
+	mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
 	if ((mtr_id_bits + priv->max_mtr_flow_bits) > mtr_reg_bits) {
 		DRV_LOG(ERR, "Meter number exceeds max limit.");
 		goto error;
 	}
 	if (mtr_id_bits > priv->max_mtr_bits)
 		priv->max_mtr_bits = mtr_id_bits;
-	fm->idx = idx;
 	/* Fill the flow meter parameters. */
 	fm->meter_id = meter_id;
 	fm->profile = fmp;
@@ -712,10 +724,11 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
 	if (ret)
 		goto error;
 	/* Add to the flow meter list. */
-	TAILQ_INSERT_TAIL(fms, fm, next);
+	if (!priv->sh->meter_aso_en)
+		TAILQ_INSERT_TAIL(fms, legacy_fm, next);
 	fm->active_state = 1; /* Config meter starts as active. */
 	fm->shared = !!shared;
-	fm->profile->ref_cnt++;
+	__atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
 	fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
 	if (!fm->flow_ipool)
 		goto error;
@@ -729,12 +742,57 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
 		mlx5_counter_free(dev, fm->policer_stats.pass_cnt);
 	if (fm->policer_stats.drop_cnt)
 		mlx5_counter_free(dev, fm->policer_stats.drop_cnt);
-	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
+	if (priv->sh->meter_aso_en)
+		mlx5_flow_mtr_free(dev, mtr_idx);
+	else
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
 	return -rte_mtr_error_set(error, -ret,
 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
 				  NULL, "Failed to create devx meter.");
 }
 
+static int
+mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			const struct rte_flow_attr *attr,
+			uint32_t mtr_idx)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_flow_meter_profile *fmp;
+	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
+
+	/* Meter object must not have any owner. */
+	MLX5_ASSERT(!fm->ref_cnt);
+	/* Get meter profile. */
+	fmp = fm->profile;
+	if (fmp == NULL)
+		return -1;
+	/* Update dependencies. */
+	__atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
+	/* Remove from list. */
+	if (!priv->sh->meter_aso_en) {
+		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
+		TAILQ_REMOVE(fms, legacy_fm, next);
+	}
+	/* Free policer counters. */
+	if (fm->policer_stats.pass_cnt)
+		mlx5_counter_free(dev, fm->policer_stats.pass_cnt);
+	if (fm->policer_stats.drop_cnt)
+		mlx5_counter_free(dev, fm->policer_stats.drop_cnt);
+	/* Free meter flow table. */
+	if (fm->flow_ipool)
+		mlx5_ipool_destroy(fm->flow_ipool);
+	mlx5_flow_destroy_policer_rules(dev, fm, attr);
+	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
+	if (priv->sh->meter_aso_en)
+		mlx5_flow_mtr_free(dev, mtr_idx);
+	else
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
+					legacy_fm->idx);
+	return 0;
+}
+
 /**
  * Destroy meter rules.
  *
@@ -753,21 +811,21 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 			struct rte_mtr_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_meters *fms = &priv->flow_meters;
-	struct mlx5_flow_meter_profile *fmp;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_meter_info *fm;
 	const struct rte_flow_attr attr = {
 				.ingress = 1,
 				.egress = 1,
 				.transfer = priv->config.dv_esw_en ? 1 : 0,
 			};
+	uint32_t mtr_idx = 0;
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
-	fm = mlx5_flow_meter_find(priv, meter_id);
+	fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
@@ -777,24 +835,17 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 		return -rte_mtr_error_set(error, EBUSY,
 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
 					  NULL, "Meter object is being used.");
-	/* Get the meter profile. */
-	fmp = fm->profile;
-	MLX5_ASSERT(fmp);
-	/* Update dependencies. */
-	fmp->ref_cnt--;
-	/* Remove from the flow meter list. */
-	TAILQ_REMOVE(fms, fm, next);
-	/* Free policer counters. */
-	if (fm->policer_stats.pass_cnt)
-		mlx5_counter_free(dev, fm->policer_stats.pass_cnt);
-	if (fm->policer_stats.drop_cnt)
-		mlx5_counter_free(dev, fm->policer_stats.drop_cnt);
-	/* Free meter flow table */
-	if (fm->flow_ipool)
-		mlx5_ipool_destroy(fm->flow_ipool);
-	mlx5_flow_destroy_policer_rules(dev, fm, &attr);
-	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], fm->idx);
+	if (priv->sh->meter_aso_en) {
+		if (mlx5_l3t_clear_entry(mtrmng->mtr_idx_tbl, meter_id))
+			return -rte_mtr_error_set(error, EBUSY,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Fail to delete ASO Meter in index table.");
+	}
+	/* Destroy the meter profile. */
+	if (mlx5_flow_meter_params_flush(dev, fm, &attr, mtr_idx))
+		return -rte_mtr_error_set(error, EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					NULL, "MTR object meter profile invalid.");
 	return 0;
 }
 
@@ -815,17 +866,13 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
  */
 static int
 mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
-			     struct mlx5_flow_meter *fm,
+			     struct mlx5_flow_meter_info *fm,
 			     uint32_t new_state,
 			     struct rte_mtr_error *error)
 {
 	static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
-		.cbs_exponent = 20,
-		.cbs_mantissa = 191,
-		.cir_exponent = 0,
-		.cir_mantissa = 200,
-		.ebs_exponent = 0,
-		.ebs_mantissa = 0,
+		.cbs_cir = RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL),
+		.ebs_eir = 0,
 	};
 	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
 			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
@@ -867,7 +914,7 @@ mlx5_flow_meter_enable(struct rte_eth_dev *dev,
 		       struct rte_mtr_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_flow_meter_info *fm;
 	int ret;
 
 	if (!priv->mtr_en)
@@ -875,7 +922,7 @@ mlx5_flow_meter_enable(struct rte_eth_dev *dev,
 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
-	fm = mlx5_flow_meter_find(priv, meter_id);
+	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
@@ -908,7 +955,7 @@ mlx5_flow_meter_disable(struct rte_eth_dev *dev,
 			struct rte_mtr_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_flow_meter_info *fm;
 	int ret;
 
 	if (!priv->mtr_en)
@@ -916,7 +963,7 @@ mlx5_flow_meter_disable(struct rte_eth_dev *dev,
 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
-	fm = mlx5_flow_meter_find(priv, meter_id);
+	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
@@ -954,7 +1001,7 @@ mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_flow_meter_profile *old_fmp;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_flow_meter_info *fm;
 	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
 			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
 	int ret;
@@ -970,7 +1017,7 @@ mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
 					  NULL, "Meter profile not found.");
 	/* Meter object must exist. */
-	fm = mlx5_flow_meter_find(priv, meter_id);
+	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
@@ -1020,7 +1067,7 @@ mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
 			     struct rte_mtr_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_flow_meter_info *fm;
 	const struct rte_flow_attr attr = {
 				.ingress = 1,
 				.egress = 1,
@@ -1034,7 +1081,7 @@ mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
-	fm = mlx5_flow_meter_find(priv, meter_id);
+	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
@@ -1134,7 +1181,7 @@ mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
 			   struct rte_mtr_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_flow_meter_info *fm;
 	struct mlx5_flow_policer_stats *ps;
 	uint64_t pkts;
 	uint64_t bytes;
@@ -1145,7 +1192,7 @@ mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
-	fm = mlx5_flow_meter_find(priv, meter_id);
+	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
@@ -1239,18 +1286,68 @@ mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
  * @return
  *   Pointer to the profile found on success, NULL otherwise.
  */
-struct mlx5_flow_meter *
-mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id)
+struct mlx5_flow_meter_info *
+mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
+		uint32_t *mtr_idx)
 {
-	struct mlx5_flow_meters *fms = &priv->flow_meters;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_legacy_flow_meter *legacy_fm;
+	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_aso_mtr *aso_mtr;
+	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	union mlx5_l3t_data data;
 
-	TAILQ_FOREACH(fm, fms, next)
-		if (meter_id == fm->meter_id)
-			return fm;
+	if (priv->sh->meter_aso_en) {
+		rte_spinlock_lock(&mtrmng->mtrsl);
+		if (!mtrmng->n_valid) {
+			rte_spinlock_unlock(&mtrmng->mtrsl);
+			return NULL;
+		}
+		if (mlx5_l3t_get_entry(mtrmng->mtr_idx_tbl, meter_id, &data) ||
+			!data.dword) {
+			rte_spinlock_unlock(&mtrmng->mtrsl);
+			return NULL;
+		}
+		if (mtr_idx)
+			*mtr_idx = data.dword;
+		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+		mlx5_l3t_clear_entry(mtrmng->mtr_idx_tbl, meter_id);
+		if (meter_id == aso_mtr->fm.meter_id) {
+			rte_spinlock_unlock(&mtrmng->mtrsl);
+			return &aso_mtr->fm;
+		}
+		rte_spinlock_unlock(&mtrmng->mtrsl);
+	} else {
+		TAILQ_FOREACH(legacy_fm, fms, next)
+			if (meter_id == legacy_fm->fm.meter_id)
+				return &legacy_fm->fm;
+	}
 	return NULL;
 }
 
+/**
+ * Find meter by index.
+ *
+ * @param priv
+ *   Pointer to mlx5_priv.
+ * @param idx
+ *   Meter index.
+ *
+ * @return
+ *   Pointer to the profile found on success, NULL otherwise.
+ */
+struct mlx5_flow_meter_info *
+flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
+{
+	struct mlx5_aso_mtr *aso_mtr;
+
+	if (priv->sh->meter_aso_en) {
+		aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
+		return &aso_mtr->fm;
+	} else {
+		return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
+	}
+}
+
 /**
  * Attach meter to flow.
  * Unidirectional Meter creation can only be done
@@ -1270,7 +1367,7 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id)
  */
 int
 mlx5_flow_meter_attach(struct mlx5_priv *priv,
-		       struct mlx5_flow_meter *fm,
+		       struct mlx5_flow_meter_info *fm,
 		       const struct rte_flow_attr *attr,
 		       struct rte_flow_error *error)
 {
@@ -1319,7 +1416,7 @@ mlx5_flow_meter_attach(struct mlx5_priv *priv,
  *  Pointer to flow meter.
  */
 void
-mlx5_flow_meter_detach(struct mlx5_flow_meter *fm)
+mlx5_flow_meter_detach(struct mlx5_flow_meter_info *fm)
 {
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
 	rte_spinlock_lock(&fm->sl);
@@ -1352,39 +1449,46 @@ int
 mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
 	struct mlx5_flow_meter_profile *fmp;
-	struct mlx5_flow_meter *fm;
+	struct mlx5_legacy_flow_meter *legacy_fm;
+	struct mlx5_flow_meter_info *fm;
+	struct mlx5_aso_mtr_pool *mtr_pool;
 	const struct rte_flow_attr attr = {
 				.ingress = 1,
 				.egress = 1,
 				.transfer = priv->config.dv_esw_en ? 1 : 0,
 			};
 	void *tmp;
+	uint32_t i, offset, mtr_idx;
 
-	TAILQ_FOREACH_SAFE(fm, fms, next, tmp) {
-		/* Meter object must not have any owner. */
-		MLX5_ASSERT(!fm->ref_cnt);
-		/* Get meter profile. */
-		fmp = fm->profile;
-		if (fmp == NULL)
-			return -rte_mtr_error_set(error, EINVAL,
-				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-				NULL, "MTR object meter profile invalid.");
-		/* Update dependencies. */
-		fmp->ref_cnt--;
-		/* Remove from list. */
-		TAILQ_REMOVE(fms, fm, next);
-		/* Free policer counters. */
-		if (fm->policer_stats.pass_cnt)
-			mlx5_counter_free(dev, fm->policer_stats.pass_cnt);
-		if (fm->policer_stats.drop_cnt)
-			mlx5_counter_free(dev, fm->policer_stats.drop_cnt);
-		/* Free meter flow table. */
-		mlx5_flow_destroy_policer_rules(dev, fm, &attr);
-		mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], fm->idx);
+	if (priv->sh->meter_aso_en) {
+		i = mtrmng->n_valid;
+		while (i--) {
+			mtr_pool = mtrmng->pools[i];
+			for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
+				offset++) {
+				fm = &mtr_pool->mtrs[offset].fm;
+				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
+				if (fm->meter_id != UINT32_MAX &&
+					mlx5_flow_meter_params_flush(dev,
+						fm, &attr, mtr_idx))
+					return -rte_mtr_error_set
+					(error, EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					NULL, "MTR object meter profile invalid.");
+			}
+		}
+	} else {
+		TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
+			fm = &legacy_fm->fm;
+			if (mlx5_flow_meter_params_flush(dev, fm, &attr, 0))
+				return -rte_mtr_error_set(error, EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					NULL, "MTR object meter profile invalid.");
+		}
 	}
 	TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
 		/* Check unused. */
