xref: /dpdk/drivers/net/mlx5/mlx5_flow_meter.c (revision 03ab51eafda992874a48c392ca66ffb577fe2b71)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright 2018 Mellanox Technologies, Ltd
4  */
5 #include <math.h>
6 
7 #include <rte_tailq.h>
8 #include <rte_malloc.h>
9 #include <rte_mtr.h>
10 #include <rte_mtr_driver.h>
11 
12 #include <mlx5_devx_cmds.h>
13 #include <mlx5_malloc.h>
14 
15 #include "mlx5.h"
16 #include "mlx5_flow.h"
17 
18 /**
19  * Create the meter action.
20  *
21  * @param priv
22  *   Pointer to mlx5_priv.
23  * @param[in] fm
24  *   Pointer to flow meter to be converted.
25  *
26  * @return
27  *   Pointer to the meter action on success, NULL otherwise.
28  */
29 static void *
30 mlx5_flow_meter_action_create(struct mlx5_priv *priv,
31 			      struct mlx5_flow_meter_info *fm)
32 {
33 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
34 	struct mlx5dv_dr_flow_meter_attr mtr_init;
35 	uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];
36 	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm =
37 						     &fm->profile->srtcm_prm;
38 	uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
39 	uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
40 	uint32_t val;
41 	enum mlx5_meter_domain domain =
42 		fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
43 			fm->egress ? MLX5_MTR_DOMAIN_EGRESS :
44 				MLX5_MTR_DOMAIN_INGRESS;
45 	struct mlx5_flow_meter_def_policy *def_policy =
46 		priv->sh->mtrmng->def_policy[domain];
47 
48 	memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
49 	MLX5_SET(flow_meter_parameters, fmp, valid, 1);
50 	MLX5_SET(flow_meter_parameters, fmp, bucket_overflow, 1);
51 	MLX5_SET(flow_meter_parameters, fmp,
52 		start_color, MLX5_FLOW_COLOR_GREEN);
53 	MLX5_SET(flow_meter_parameters, fmp, both_buckets_on_green, 0);
54 	val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
55 	MLX5_SET(flow_meter_parameters, fmp, cbs_exponent, val);
56 	val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
57 	MLX5_SET(flow_meter_parameters, fmp, cbs_mantissa, val);
58 	val = (cbs_cir >> ASO_DSEG_XIR_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
59 	MLX5_SET(flow_meter_parameters, fmp, cir_exponent, val);
60 	val = (cbs_cir & ASO_DSEG_MAN_MASK);
61 	MLX5_SET(flow_meter_parameters, fmp, cir_mantissa, val);
62 	val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
63 	MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
64 	val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
65 	MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
66 	mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj;
67 	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
68 	mtr_init.flow_meter_parameter = fmp;
69 	mtr_init.flow_meter_parameter_sz =
70 		MLX5_ST_SZ_BYTES(flow_meter_parameters);
71 	mtr_init.active = fm->active_state;
72 	return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
73 #else
74 	(void)priv;
75 	(void)fm;
76 	return NULL;
77 #endif
78 }
79 
80 /**
81  * Find meter profile by id.
82  *
83  * @param priv
84  *   Pointer to mlx5_priv.
85  * @param meter_profile_id
86  *   Meter profile id.
87  *
88  * @return
89  *   Pointer to the profile found on success, NULL otherwise.
90  */
91 static struct mlx5_flow_meter_profile *
92 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
93 {
94 	struct mlx5_flow_meter_profile *fmp;
95 	union mlx5_l3t_data data;
96 	int32_t ret;
97 
98 	if (mlx5_l3t_get_entry(priv->mtr_profile_tbl,
99 			       meter_profile_id, &data) || !data.ptr)
100 		return NULL;
101 	fmp = data.ptr;
102 	/* Remove reference taken by the mlx5_l3t_get_entry. */
103 	ret = mlx5_l3t_clear_entry(priv->mtr_profile_tbl,
104 				   meter_profile_id);
105 	if (!ret || ret == -1)
106 		return NULL;
107 	return fmp;
108 }
109 
110 /**
111  * Validate the MTR profile.
112  *
113  * @param[in] dev
114  *   Pointer to Ethernet device.
115  * @param[in] meter_profile_id
116  *   Meter profile id.
117  * @param[in] profile
118  *   Pointer to meter profile detail.
119  * @param[out] error
120  *   Pointer to the error structure.
121  *
122  * @return
123  *   0 on success, a negative errno value otherwise and rte_errno is set.
124  */
125 static int
126 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
127 				 uint32_t meter_profile_id,
128 				 struct rte_mtr_meter_profile *profile,
129 				 struct rte_mtr_error *error)
130 {
131 	struct mlx5_priv *priv = dev->data->dev_private;
132 	struct mlx5_flow_meter_profile *fmp;
133 	uint32_t ls_factor;
134 	int ret;
135 	uint64_t cir, cbs;
136 	uint64_t eir, ebs;
137 	uint64_t pir, pbs;
138 
139 	/* Profile must not be NULL. */
140 	if (profile == NULL)
141 		return -rte_mtr_error_set(error, EINVAL,
142 					  RTE_MTR_ERROR_TYPE_METER_PROFILE,
143 					  NULL, "Meter profile is null.");
144 	/* Meter profile ID must be valid. */
145 	if (meter_profile_id == UINT32_MAX)
146 		return -rte_mtr_error_set(error, EINVAL,
147 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
148 					  NULL, "Meter profile id not valid.");
149 	/* Meter profile must not exist. */
150 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
151 	if (fmp)
152 		return -rte_mtr_error_set(error, EEXIST,
153 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
154 					  NULL,
155 					  "Meter profile already exists.");
156 	if (!priv->sh->meter_aso_en) {
157 		/* Old version is even not supported. */
158 		if (!priv->config.hca_attr.qos.flow_meter_old)
159 			return -rte_mtr_error_set(error, ENOTSUP,
160 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
161 				NULL, "Metering is not supported.");
162 		/* Old FW metering only supports srTCM. */
163 		if (profile->alg != RTE_MTR_SRTCM_RFC2697) {
164 			return -rte_mtr_error_set(error, ENOTSUP,
165 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
166 				NULL, "Metering algorithm is not supported.");
167 		} else if (profile->srtcm_rfc2697.ebs) {
168 			/* EBS is not supported for old metering. */
169 			return -rte_mtr_error_set(error, ENOTSUP,
170 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
171 				NULL, "EBS is not supported.");
172 		}
173 		if (profile->packet_mode)
174 			return -rte_mtr_error_set(error, ENOTSUP,
175 				RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
176 				"Metering algorithm packet mode is not supported.");
177 	}
178 	ls_factor = profile->packet_mode ? MLX5_MTRS_PPS_MAP_BPS_SHIFT : 0;
179 	switch (profile->alg) {
180 	case RTE_MTR_SRTCM_RFC2697:
181 		cir = profile->srtcm_rfc2697.cir << ls_factor;
182 		cbs = profile->srtcm_rfc2697.cbs << ls_factor;
183 		ebs = profile->srtcm_rfc2697.ebs << ls_factor;
184 		/* EBS could be zero for old metering. */
185 		if (cir > 0 && cir <= MLX5_SRTCM_XIR_MAX &&
186 		    cbs > 0 && cbs <= MLX5_SRTCM_XBS_MAX &&
187 		    ebs <= MLX5_SRTCM_XBS_MAX) {
188 			ret = 0;
189 		} else {
190 			ret = -rte_mtr_error_set(error, ENOTSUP,
191 					RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
192 					"Profile values out of range.");
193 		}
194 		break;
195 	case RTE_MTR_TRTCM_RFC2698:
196 		cir = profile->trtcm_rfc2698.cir << ls_factor;
197 		cbs = profile->trtcm_rfc2698.cbs << ls_factor;
198 		pir = profile->trtcm_rfc2698.pir << ls_factor;
199 		pbs = profile->trtcm_rfc2698.pbs << ls_factor;
200 		if (cir > 0 && cir <= MLX5_SRTCM_XIR_MAX &&
201 		    cbs > 0 && cbs <= MLX5_SRTCM_XBS_MAX &&
202 		    pir >= cir && pir <= (MLX5_SRTCM_XIR_MAX * 2) &&
203 		    pbs >= cbs && pbs <= (MLX5_SRTCM_XBS_MAX * 2)) {
204 			ret = 0;
205 		} else {
206 			ret = -rte_mtr_error_set(error, ENOTSUP,
207 					RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
208 					"Profile values out of range.");
209 		}
210 		break;
211 	case RTE_MTR_TRTCM_RFC4115:
212 		cir = profile->trtcm_rfc4115.cir << ls_factor;
213 		cbs = profile->trtcm_rfc4115.cbs << ls_factor;
214 		eir = profile->trtcm_rfc4115.eir << ls_factor;
215 		ebs = profile->trtcm_rfc4115.ebs << ls_factor;
216 		if (cir > 0 && cir <= MLX5_SRTCM_XIR_MAX &&
217 		    cbs > 0 && cbs <= MLX5_SRTCM_XBS_MAX &&
218 		    eir <= MLX5_SRTCM_XIR_MAX && ebs <= MLX5_SRTCM_XBS_MAX) {
219 			ret = 0;
220 		} else {
221 			ret = -rte_mtr_error_set(error, ENOTSUP,
222 					RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
223 					"Profile values out of range.");
224 		}
225 		break;
226 	default:
227 		ret = -rte_mtr_error_set(error, ENOTSUP,
228 					 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
229 					 "Unknown metering algorithm.");
230 		break;
231 	}
232 	return ret;
233 }
234 
235 /*
236  * Calculate mantissa and exponent for cir / eir.
237  *
238  * @param[in] xir
239  *   Value to be calculated.
240  * @param[out] man
241  *   Pointer to the mantissa.
242  * @param[out] exp
243  *   Pointer to the exp.
244  */
245 static inline void
246 mlx5_flow_meter_xir_man_exp_calc(int64_t xir, uint8_t *man, uint8_t *exp)
247 {
248 	int64_t _xir;
249 	int64_t delta = INT64_MAX;
250 	uint8_t _man = 0;
251 	uint8_t _exp = 0;
252 	uint64_t m, e;
253 
254 	/* Special case xir == 0 ? both exp and matissa are 0. */
255 	if (xir == 0) {
256 		*man = 0;
257 		*exp = 0;
258 		return;
259 	}
260 	for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
261 		for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
262 			_xir = (1000000000ULL * m) >> e;
263 			if (llabs(xir - _xir) <= delta) {
264 				delta = llabs(xir - _xir);
265 				_man = m;
266 				_exp = e;
267 			}
268 		}
269 	}
270 	*man = _man;
271 	*exp = _exp;
272 }
273 
274 /*
275  * Calculate mantissa and exponent for xbs.
276  *
277  * @param[in] xbs
278  *   Value to be calculated.
279  * @param[out] man
280  *   Pointer to the mantissa.
281  * @param[out] exp
282  *   Pointer to the exp.
283  */
284 static inline void
285 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
286 {
287 	int _exp;
288 	double _man;
289 
290 	/* Special case xbs == 0 ? both exp and matissa are 0. */
291 	if (xbs == 0) {
292 		*man = 0;
293 		*exp = 0;
294 		return;
295 	}
296 	/* xbs = xbs_mantissa * 2^xbs_exponent */
297 	_man = frexp(xbs, &_exp);
298 	_man = _man * pow(2, MLX5_MAN_WIDTH);
299 	_exp = _exp - MLX5_MAN_WIDTH;
300 	*man = (uint8_t)ceil(_man);
301 	*exp = _exp;
302 }
303 
304 /**
305  * Fill the prm meter parameter.
306  *
307  * @param[in,out] fmp
308  *   Pointer to meter profie to be converted.
309  * @param[out] error
310  *   Pointer to the error structure.
311  *
312  * @return
313  *   0 on success, a negative errno value otherwise and rte_errno is set.
314  */
315 static int
316 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
317 			   struct rte_mtr_error *error)
318 {
319 	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
320 	uint8_t man, exp;
321 	uint32_t cbs_exp, cbs_man, cir_exp, cir_man;
322 	uint32_t eir_exp, eir_man, ebs_exp, ebs_man;
323 	uint64_t cir, cbs, eir, ebs;
324 
325 	switch (fmp->profile.alg) {
326 	case RTE_MTR_SRTCM_RFC2697:
327 		cir = fmp->profile.srtcm_rfc2697.cir;
328 		cbs = fmp->profile.srtcm_rfc2697.cbs;
329 		eir = 0;
330 		ebs = fmp->profile.srtcm_rfc2697.ebs;
331 		break;
332 	case RTE_MTR_TRTCM_RFC2698:
333 		MLX5_ASSERT(fmp->profile.trtcm_rfc2698.pir >
334 			    fmp->profile.trtcm_rfc2698.cir &&
335 			    fmp->profile.trtcm_rfc2698.pbs >
336 			    fmp->profile.trtcm_rfc2698.cbs);
337 		cir = fmp->profile.trtcm_rfc2698.cir;
338 		cbs = fmp->profile.trtcm_rfc2698.cbs;
339 		/* EIR / EBS are filled with PIR / PBS. */
340 		eir = fmp->profile.trtcm_rfc2698.pir;
341 		ebs = fmp->profile.trtcm_rfc2698.pbs;
342 		break;
343 	case RTE_MTR_TRTCM_RFC4115:
344 		cir = fmp->profile.trtcm_rfc4115.cir;
345 		cbs = fmp->profile.trtcm_rfc4115.cbs;
346 		eir = fmp->profile.trtcm_rfc4115.eir;
347 		ebs = fmp->profile.trtcm_rfc4115.ebs;
348 		break;
349 	default:
350 		return -rte_mtr_error_set(error, EINVAL,
351 				RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL,
352 				"Metering algorithm mode is invalid");
353 	}
354 	/* Adjust the values for PPS mode. */
355 	if (fmp->profile.packet_mode) {
356 		cir <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT;
357 		cbs <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT;
358 		eir <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT;
359 		ebs <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT;
360 	}
361 	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
362 	mlx5_flow_meter_xir_man_exp_calc(cir, &man, &exp);
363 	/* Check if cir mantissa is too large. */
364 	if (exp > ASO_DSEG_XIR_EXP_MASK)
365 		return -rte_mtr_error_set(error, ENOTSUP,
366 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
367 					  "meter profile parameter cir is not supported.");
368 	cir_man = man;
369 	cir_exp = exp;
370 	 /* cbs = cbs_mantissa * 2^cbs_exponent */
371 	mlx5_flow_meter_xbs_man_exp_calc(cbs, &man, &exp);
372 	/* Check if cbs mantissa is too large. */
373 	if (exp > ASO_DSEG_EXP_MASK)
374 		return -rte_mtr_error_set(error, ENOTSUP,
375 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
376 					  "meter profile parameter cbs is not supported.");
377 	cbs_man = man;
378 	cbs_exp = exp;
379 	srtcm->cbs_cir = rte_cpu_to_be_32(cbs_exp << ASO_DSEG_CBS_EXP_OFFSET |
380 					  cbs_man << ASO_DSEG_CBS_MAN_OFFSET |
381 					  cir_exp << ASO_DSEG_XIR_EXP_OFFSET |
382 					  cir_man);
383 	mlx5_flow_meter_xir_man_exp_calc(eir, &man, &exp);
384 	/* Check if eir mantissa is too large. */
385 	if (exp > ASO_DSEG_XIR_EXP_MASK)
386 		return -rte_mtr_error_set(error, ENOTSUP,
387 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
388 					  "meter profile parameter eir is not supported.");
389 	eir_man = man;
390 	eir_exp = exp;
391 	mlx5_flow_meter_xbs_man_exp_calc(ebs, &man, &exp);
392 	/* Check if ebs mantissa is too large. */
393 	if (exp > ASO_DSEG_EXP_MASK)
394 		return -rte_mtr_error_set(error, ENOTSUP,
395 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
396 					  "meter profile parameter ebs is not supported.");
397 	ebs_man = man;
398 	ebs_exp = exp;
399 	srtcm->ebs_eir = rte_cpu_to_be_32(ebs_exp << ASO_DSEG_EBS_EXP_OFFSET |
400 					  ebs_man << ASO_DSEG_EBS_MAN_OFFSET |
401 					  eir_exp << ASO_DSEG_XIR_EXP_OFFSET |
402 					  eir_man);
403 	if (srtcm->cbs_cir)
404 		fmp->g_support = 1;
405 	if (srtcm->ebs_eir)
406 		fmp->y_support = 1;
407 	return 0;
408 }
409 
410 /**
411  * Callback to get MTR capabilities.
412  *
413  * @param[in] dev
414  *   Pointer to Ethernet device.
415  * @param[out] cap
416  *   Pointer to save MTR capabilities.
417  * @param[out] error
418  *   Pointer to the error structure.
419  *
420  * @return
421  *   0 on success, a negative errno value otherwise and rte_errno is set.
422  */
423 static int
424 mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
425 		 struct rte_mtr_capabilities *cap,
426 		 struct rte_mtr_error *error __rte_unused)
427 {
428 	struct mlx5_priv *priv = dev->data->dev_private;
429 	struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
430 
431 	if (!priv->mtr_en)
432 		return -rte_mtr_error_set(error, ENOTSUP,
433 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
434 					  "Meter is not supported");
435 	memset(cap, 0, sizeof(*cap));
436 	if (priv->sh->meter_aso_en) {
437 		/* 2 meters per one ASO cache line. */
438 		cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
439 		cap->srtcm_rfc2697_packet_mode_supported = 1;
440 	} else {
441 		cap->n_max = 1 << qattr->log_max_flow_meter;
442 		cap->srtcm_rfc2697_packet_mode_supported = 0;
443 	}
444 	cap->srtcm_rfc2697_byte_mode_supported = 1;
445 	cap->n_shared_max = cap->n_max;
446 	cap->identical = 1;
447 	cap->shared_identical = 1;
448 	cap->shared_n_flows_per_mtr_max = 4 << 20;
449 	/* 2M flows can share the same meter. */
450 	cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
451 	cap->meter_srtcm_rfc2697_n_max = qattr->flow_meter_old ? cap->n_max : 0;
452 	cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
453 	cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
454 			  RTE_MTR_STATS_N_PKTS_DROPPED;
455 	return 0;
456 }
457 
458 /**
459  * Callback to add MTR profile.
460  *
461  * @param[in] dev
462  *   Pointer to Ethernet device.
463  * @param[in] meter_profile_id
464  *   Meter profile id.
465  * @param[in] profile
466  *   Pointer to meter profile detail.
467  * @param[out] error
468  *   Pointer to the error structure.
469  *
470  * @return
471  *   0 on success, a negative errno value otherwise and rte_errno is set.
472  */
473 static int
474 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
475 		       uint32_t meter_profile_id,
476 		       struct rte_mtr_meter_profile *profile,
477 		       struct rte_mtr_error *error)
478 {
479 	struct mlx5_priv *priv = dev->data->dev_private;
480 	struct mlx5_flow_meter_profile *fmp;
481 	union mlx5_l3t_data data;
482 	int ret;
483 
484 	if (!priv->mtr_en)
485 		return -rte_mtr_error_set(error, ENOTSUP,
486 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
487 					  "Meter is not supported");
488 	/* Check input params. */
489 	ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
490 					       profile, error);
491 	if (ret)
492 		return ret;
493 	/* Meter profile memory allocation. */
494 	fmp = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_flow_meter_profile),
495 			  RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
496 	if (fmp == NULL)
497 		return -rte_mtr_error_set(error, ENOMEM,
498 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
499 					  NULL, "Meter profile memory "
500 					  "alloc failed.");
501 	/* Fill profile info. */
502 	fmp->id = meter_profile_id;
503 	fmp->profile = *profile;
504 	/* Fill the flow meter parameters for the PRM. */
505 	ret = mlx5_flow_meter_param_fill(fmp, error);
506 	if (ret)
507 		goto error;
508 	data.ptr = fmp;
509 	ret = mlx5_l3t_set_entry(priv->mtr_profile_tbl,
510 				 meter_profile_id, &data);
511 	if (ret)
512 		return -rte_mtr_error_set(error, ENOTSUP,
513 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
514 					  NULL, "Meter profile insert fail.");
515 	return 0;
516 error:
517 	mlx5_free(fmp);
518 	return ret;
519 }
520 
521 /**
522  * Callback to delete MTR profile.
523  *
524  * @param[in] dev
525  *   Pointer to Ethernet device.
526  * @param[in] meter_profile_id
527  *   Meter profile id.
528  * @param[out] error
529  *   Pointer to the error structure.
530  *
531  * @return
532  *   0 on success, a negative errno value otherwise and rte_errno is set.
533  */
534 static int
535 mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
536 			  uint32_t meter_profile_id,
537 			  struct rte_mtr_error *error)
538 {
539 	struct mlx5_priv *priv = dev->data->dev_private;
540 	struct mlx5_flow_meter_profile *fmp;
541 
542 	if (!priv->mtr_en)
543 		return -rte_mtr_error_set(error, ENOTSUP,
544 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
545 					  "Meter is not supported");
546 	/* Meter profile must exist. */
547 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
548 	if (fmp == NULL)
549 		return -rte_mtr_error_set(error, ENOENT,
550 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
551 					  &meter_profile_id,
552 					  "Meter profile id is invalid.");
553 	/* Check profile is unused. */
554 	if (fmp->ref_cnt)
555 		return -rte_mtr_error_set(error, EBUSY,
556 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
557 					  NULL, "Meter profile is in use.");
558 	if (mlx5_l3t_clear_entry(priv->mtr_profile_tbl, meter_profile_id))
559 		return -rte_mtr_error_set(error, EBUSY,
560 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
561 					  NULL, "Meter profile remove fail.");
562 	mlx5_free(fmp);
563 	return 0;
564 }
565 
566 /**
567  * Find policy by id.
568  *
569  * @param[in] dev
570  *   Pointer to Ethernet device.
571  * @param policy_id
572  *   Policy id.
573  *
574  * @return
575  *   Pointer to the policy found on success, NULL otherwise.
576  */
577 struct mlx5_flow_meter_policy *
578 mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
579 			    uint32_t policy_id,
580 			    uint32_t *policy_idx)
581 {
582 	struct mlx5_priv *priv = dev->data->dev_private;
583 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
584 	union mlx5_l3t_data data;
585 
586 	if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM || !priv->policy_idx_tbl)
587 		return NULL;
588 	if (mlx5_l3t_get_entry(priv->policy_idx_tbl, policy_id, &data) ||
589 				!data.dword)
590 		return NULL;
591 	if (policy_idx)
592 		*policy_idx = data.dword;
593 	sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
594 					data.dword);
595 	/* Remove reference taken by the mlx5_l3t_get_entry. */
596 	mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id);
597 	if (sub_policy)
598 		if (sub_policy->main_policy_id)
599 			return sub_policy->main_policy;
600 	return NULL;
601 }
602 
603 /**
604  * Get the last meter's policy from one meter's policy in hierarchy.
605  *
606  * @param[in] dev
607  *   Pointer to Ethernet device.
608  * @param[in] policy
609  *   Pointer to flow meter policy.
610  *
611  * @return
612  *   Pointer to the final meter's policy, or NULL when fail.
613  */
614 struct mlx5_flow_meter_policy *
615 mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev,
616 					struct mlx5_flow_meter_policy *policy)
617 {
618 	struct mlx5_priv *priv = dev->data->dev_private;
619 	struct mlx5_flow_meter_info *next_fm;
620 	struct mlx5_flow_meter_policy *next_policy = policy;
621 
622 	while (next_policy->is_hierarchy) {
623 		next_fm = mlx5_flow_meter_find(priv,
624 		       next_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
625 		if (!next_fm || next_fm->def_policy)
626 			return NULL;
627 		next_policy = mlx5_flow_meter_policy_find(dev,
628 						next_fm->policy_id, NULL);
629 		MLX5_ASSERT(next_policy);
630 	}
631 	return next_policy;
632 }
633 
634 /**
635  * Callback to check MTR policy action validate
636  *
637  * @param[in] dev
638  *   Pointer to Ethernet device.
639  * @param[in] actions
640  *   Pointer to meter policy action detail.
641  * @param[out] error
642  *   Pointer to the error structure.
643  *
644  * @return
645  *   0 on success, a negative errno value otherwise and rte_errno is set.
646  */
647 static int
648 mlx5_flow_meter_policy_validate(struct rte_eth_dev *dev,
649 	struct rte_mtr_meter_policy_params *policy,
650 	struct rte_mtr_error *error)
651 {
652 	struct mlx5_priv *priv = dev->data->dev_private;
653 	struct rte_flow_attr attr = { .transfer =
654 			priv->config.dv_esw_en ? 1 : 0};
655 	bool is_rss = false;
656 	uint8_t policy_mode;
657 	uint8_t domain_bitmap;
658 	int ret;
659 
660 	if (!priv->mtr_en || !priv->sh->meter_aso_en)
661 		return -rte_mtr_error_set(error, ENOTSUP,
662 				RTE_MTR_ERROR_TYPE_METER_POLICY,
663 				NULL, "meter policy unsupported.");
664 	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
665 			&is_rss, &domain_bitmap, &policy_mode, error);
666 	if (ret)
667 		return ret;
668 	return 0;
669 }
670 
671 static int
672 __mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
673 			uint32_t policy_id,
674 			struct mlx5_flow_meter_policy *mtr_policy,
675 			struct rte_mtr_error *error,
676 			bool clear_l3t)
677 {
678 	struct mlx5_priv *priv = dev->data->dev_private;
679 	struct mlx5_flow_meter_sub_policy *sub_policy;
680 	uint32_t i, j;
681 	uint16_t sub_policy_num;
682 
683 	rte_spinlock_lock(&mtr_policy->sl);
684 	if (mtr_policy->ref_cnt) {
685 		rte_spinlock_unlock(&mtr_policy->sl);
686 		return -rte_mtr_error_set(error, EBUSY,
687 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
688 				 NULL,
689 				"Meter policy object is being used.");
690 	}
691 	mlx5_flow_destroy_policy_rules(dev, mtr_policy);
692 	mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
693 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
694 		sub_policy_num = (mtr_policy->sub_policy_num >>
695 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
696 			MLX5_MTR_SUB_POLICY_NUM_MASK;
697 		if (sub_policy_num) {
698 			for (j = 0; j < sub_policy_num; j++) {
699 				sub_policy = mtr_policy->sub_policys[i][j];
700 				if (sub_policy)
701 					mlx5_ipool_free
702 					(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
703 					sub_policy->idx);
704 			}
705 		}
706 	}
707 	if (priv->policy_idx_tbl && clear_l3t) {
708 		if (mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id)) {
709 			rte_spinlock_unlock(&mtr_policy->sl);
710 			return -rte_mtr_error_set(error, ENOTSUP,
711 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
712 				"Fail to delete policy in index table.");
713 		}
714 	}
715 	rte_spinlock_unlock(&mtr_policy->sl);
716 	return 0;
717 }
718 
719 /**
720  * Callback to add MTR policy.
721  *
722  * @param[in] dev
723  *   Pointer to Ethernet device.
724  * @param[out] policy_id
725  *   Pointer to policy id
726  * @param[in] actions
727  *   Pointer to meter policy action detail.
728  * @param[out] error
729  *   Pointer to the error structure.
730  *
731  * @return
732  *   0 on success, a negative errno value otherwise and rte_errno is set.
733  */
734 static int
735 mlx5_flow_meter_policy_add(struct rte_eth_dev *dev,
736 			uint32_t policy_id,
737 			struct rte_mtr_meter_policy_params *policy,
738 			struct rte_mtr_error *error)
739 {
740 	struct mlx5_priv *priv = dev->data->dev_private;
741 	struct rte_flow_attr attr = { .transfer =
742 			priv->config.dv_esw_en ? 1 : 0};
743 	uint32_t sub_policy_idx = 0;
744 	uint32_t policy_idx = 0;
745 	struct mlx5_flow_meter_policy *mtr_policy = NULL;
746 	struct mlx5_flow_meter_sub_policy *sub_policy;
747 	bool is_rss = false;
748 	uint8_t policy_mode;
749 	uint32_t i;
750 	int ret;
751 	uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy);
752 	uint16_t sub_policy_num;
753 	uint8_t domain_bitmap = 0;
754 	union mlx5_l3t_data data;
755 	bool skip_rule = false;
756 
757 	if (!priv->mtr_en)
758 		return -rte_mtr_error_set(error, ENOTSUP,
759 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
760 					  NULL, "meter policy unsupported. ");
761 	if (policy_id == MLX5_INVALID_POLICY_ID)
762 		return -rte_mtr_error_set(error, ENOTSUP,
763 					  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
764 					  NULL, "policy ID is invalid. ");
765 	if (policy_id == priv->sh->mtrmng->def_policy_id)
766 		return -rte_mtr_error_set(error, EEXIST,
767 					  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
768 					  NULL, "default policy ID exists. ");
769 	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
770 	if (mtr_policy)
771 		return -rte_mtr_error_set(error, EEXIST,
772 					  RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
773 					  NULL, "policy ID exists. ");
774 	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
775 					  &is_rss, &domain_bitmap,
776 					  &policy_mode, error);
777 	if (ret)
778 		return ret;
779 	if (!domain_bitmap)
780 		return -rte_mtr_error_set(error, ENOTSUP,
781 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
782 					  NULL, "fail to find policy domain.");
783 	if (policy_mode == MLX5_MTR_POLICY_MODE_DEF) {
784 		if (priv->sh->mtrmng->def_policy_id != MLX5_INVALID_POLICY_ID)
785 			return -rte_mtr_error_set(error, EEXIST,
786 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
787 				NULL, "a policy with similar actions "
788 				"is already configured");
789 		if (mlx5_flow_create_def_policy(dev))
790 			return -rte_mtr_error_set(error, ENOTSUP,
791 				RTE_MTR_ERROR_TYPE_METER_POLICY,
792 				NULL,
793 				"fail to create non-terminated policy.");
794 		priv->sh->mtrmng->def_policy_id = policy_id;
795 		return 0;
796 	}
797 	if (!priv->sh->meter_aso_en)
798 		return -rte_mtr_error_set(error, ENOTSUP,
799 			RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
800 			"no ASO capability to support the policy ");
801 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
802 		if (!(domain_bitmap & (1 << i)))
803 			continue;
804 		/*
805 		 * If RSS is found, it means that only the ingress domain can
806 		 * be supported. It is invalid to support RSS for one color
807 		 * and egress / transfer domain actions for another. Drop and
808 		 * jump action should have no impact.
809 		 */
810 		if (is_rss) {
811 			policy_size +=
812 				sizeof(struct mlx5_flow_meter_sub_policy *) *
813 				MLX5_MTR_RSS_MAX_SUB_POLICY;
814 			break;
815 		}
816 		policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
817 	}
818 	mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size,
819 				 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
820 	if (!mtr_policy)
821 		return -rte_mtr_error_set(error, ENOMEM,
822 				RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
823 				"Memory alloc failed for meter policy.");
824 	if (policy_mode == MLX5_MTR_POLICY_MODE_OG)
825 		mtr_policy->skip_y = 1;
826 	else if (policy_mode == MLX5_MTR_POLICY_MODE_OY)
827 		mtr_policy->skip_g = 1;
828 	policy_size = sizeof(struct mlx5_flow_meter_policy);
829 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
830 		if (!(domain_bitmap & (1 << i)))
831 			continue;
832 		if (i == MLX5_MTR_DOMAIN_INGRESS)
833 			mtr_policy->ingress = 1;
834 		if (i == MLX5_MTR_DOMAIN_EGRESS)
835 			mtr_policy->egress = 1;
836 		if (i == MLX5_MTR_DOMAIN_TRANSFER)
837 			mtr_policy->transfer = 1;
838 		sub_policy = mlx5_ipool_zmalloc
839 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
840 				 &sub_policy_idx);
841 		if (!sub_policy ||
842 		    sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
843 			goto policy_add_err;
844 		sub_policy->idx = sub_policy_idx;
845 		sub_policy->main_policy = mtr_policy;
846 		if (!policy_idx) {
847 			policy_idx = sub_policy_idx;
848 			sub_policy->main_policy_id = 1;
849 		}
850 		mtr_policy->sub_policys[i] =
851 			(struct mlx5_flow_meter_sub_policy **)
852 			((uint8_t *)mtr_policy + policy_size);
853 		mtr_policy->sub_policys[i][0] = sub_policy;
854 		sub_policy_num = (mtr_policy->sub_policy_num >>
855 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
856 			MLX5_MTR_SUB_POLICY_NUM_MASK;
857 		sub_policy_num++;
858 		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
859 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
860 		mtr_policy->sub_policy_num |=
861 			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
862 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
863 		/*
864 		 * If RSS is found, it means that only the ingress domain can
865 		 * be supported. It is invalid to support RSS for one color
866 		 * and egress / transfer domain actions for another. Drop and
867 		 * jump action should have no impact.
868 		 */
869 		if (is_rss) {
870 			mtr_policy->is_rss = 1;
871 			break;
872 		}
873 		policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
874 	}
875 	rte_spinlock_init(&mtr_policy->sl);
876 	ret = mlx5_flow_create_mtr_acts(dev, mtr_policy,
877 					policy->actions, error);
878 	if (ret)
879 		goto policy_add_err;
880 	if (mtr_policy->is_hierarchy) {
881 		struct mlx5_flow_meter_policy *final_policy;
882 
883 		final_policy =
884 		mlx5_flow_meter_hierarchy_get_final_policy(dev, mtr_policy);
885 		if (!final_policy)
886 			goto policy_add_err;
887 		skip_rule = (final_policy->is_rss || final_policy->is_queue);
888 	}
889 	/*
890 	 * If either Green or Yellow has queue / RSS action, all the policy
891 	 * rules will be created later in the flow splitting stage.
892 	 */
893 	if (!is_rss && !mtr_policy->is_queue && !skip_rule) {
894 		/* Create policy rules in HW. */
895 		ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
896 		if (ret)
897 			goto policy_add_err;
898 	}
899 	data.dword = policy_idx;
900 	if (!priv->policy_idx_tbl) {
901 		priv->policy_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
902 		if (!priv->policy_idx_tbl)
903 			goto policy_add_err;
904 	}
905 	if (mlx5_l3t_set_entry(priv->policy_idx_tbl, policy_id, &data))
906 		goto policy_add_err;
907 	return 0;
908 policy_add_err:
909 	if (mtr_policy) {
910 		ret = __mlx5_flow_meter_policy_delete(dev, policy_id,
911 			mtr_policy, error, false);
912 		mlx5_free(mtr_policy);
913 		if (ret)
914 			return ret;
915 	}
916 	return -rte_mtr_error_set(error, ENOTSUP,
917 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
918 				  NULL, "Failed to create devx policy.");
919 }
920 
921 /**
922  * Callback to delete MTR policy.
923  *
924  * @param[in] dev
925  *   Pointer to Ethernet device.
926  * @param[in] policy_id
927  *   Meter policy id.
928  * @param[out] error
929  *   Pointer to the error structure.
930  *
931  * @return
932  *   0 on success, a negative errno value otherwise and rte_errno is set.
933  */
934 static int
935 mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
936 			  uint32_t policy_id,
937 			  struct rte_mtr_error *error)
938 {
939 	struct mlx5_priv *priv = dev->data->dev_private;
940 	struct mlx5_flow_meter_policy *mtr_policy;
941 	uint32_t policy_idx;
942 	int ret;
943 
944 	if (policy_id == priv->sh->mtrmng->def_policy_id) {
945 		if (priv->sh->mtrmng->def_policy_ref_cnt > 0)
946 			return -rte_mtr_error_set(error, ENOTSUP,
947 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
948 				"Meter policy object is being used.");
949 		priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
950 		return 0;
951 	}
952 	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
953 	if (!mtr_policy)
954 		return -rte_mtr_error_set(error, ENOTSUP,
955 			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
956 			"Meter policy id is invalid. ");
957 	ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy,
958 						error, true);
959 	if (ret)
960 		return ret;
961 	mlx5_free(mtr_policy);
962 	return 0;
963 }
964 
965 /**
966  * Check meter validation.
967  *
968  * @param[in] priv
969  *   Pointer to mlx5 private data structure.
970  * @param[in] meter_id
971  *   Meter id.
972  * @param[in] params
973  *   Pointer to rte meter parameters.
974  * @param[out] error
975  *   Pointer to rte meter error structure.
976  *
977  * @return
978  *   0 on success, a negative errno value otherwise and rte_errno is set.
979  */
980 static int
981 mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
982 			 struct rte_mtr_params *params,
983 			 struct rte_mtr_error *error)
984 {
985 	/* Meter must use global drop action. */
986 	if (!priv->sh->dr_drop_action)
987 		return -rte_mtr_error_set(error, ENOTSUP,
988 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
989 					  NULL,
990 					  "No drop action ready for meter.");
991 	/* Meter params must not be NULL. */
992 	if (params == NULL)
993 		return -rte_mtr_error_set(error, EINVAL,
994 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
995 					  NULL, "Meter object params null.");
996 	/* Previous meter color is not supported. */
997 	if (params->use_prev_mtr_color)
998 		return -rte_mtr_error_set(error, ENOTSUP,
999 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
1000 					  NULL,
1001 					  "Previous meter color "
1002 					  "not supported.");
1003 	if (params->meter_policy_id == MLX5_INVALID_POLICY_ID)
1004 		return -rte_mtr_error_set(error, ENOENT,
1005 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1006 				NULL, "Meter policy id not valid.");
1007 	/* Validate meter id. */
1008 	if (mlx5_flow_meter_find(priv, meter_id, NULL))
1009 		return -rte_mtr_error_set(error, EEXIST,
1010 			RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
1011 			"Meter object already exists.");
1012 	return 0;
1013 }
1014 
1015 /**
1016  * Modify the flow meter action.
1017  *
1018  * @param[in] priv
1019  *   Pointer to mlx5 private data structure.
1020  * @param[in] fm
1021  *   Pointer to flow meter to be modified.
1022  * @param[in] srtcm
1023  *   Pointer to meter srtcm description parameter.
1024  * @param[in] modify_bits
1025  *   The bit in srtcm to be updated.
1026  * @param[in] active_state
1027  *   The state to be updated.
1028  * @return
1029  *   0 on success, o negative value otherwise.
1030  */
1031 static int
1032 mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
1033 		struct mlx5_flow_meter_info *fm,
1034 		const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
1035 		uint64_t modify_bits, uint32_t active_state, uint32_t is_enable)
1036 {
1037 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
1038 	uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
1039 	uint32_t *attr;
1040 	struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
1041 	int ret;
1042 	struct mlx5_aso_mtr *aso_mtr = NULL;
1043 	uint32_t cbs_cir, ebs_eir, val;
1044 
1045 	if (priv->sh->meter_aso_en) {
1046 		fm->is_enable = !!is_enable;
1047 		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
1048 		ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
1049 		if (ret)
1050 			return ret;
1051 		ret = mlx5_aso_mtr_wait(priv->sh, aso_mtr);
1052 		if (ret)
1053 			return ret;
1054 	} else {
1055 		/* Fill command parameters. */
1056 		mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
1057 		mod_attr.flow_meter_parameter = in;
1058 		mod_attr.flow_meter_parameter_sz =
1059 				MLX5_ST_SZ_BYTES(flow_meter_parameters);
1060 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
1061 			mod_attr.active = !!active_state;
1062 		else
1063 			mod_attr.active = 0;
1064 		attr = in;
1065 		cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
1066 		ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
1067 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
1068 			val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) &
1069 				ASO_DSEG_EXP_MASK;
1070 			MLX5_SET(flow_meter_parameters, attr,
1071 				cbs_exponent, val);
1072 			val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) &
1073 				ASO_DSEG_MAN_MASK;
1074 			MLX5_SET(flow_meter_parameters, attr,
1075 				cbs_mantissa, val);
1076 		}
1077 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
1078 			val = (cbs_cir >> ASO_DSEG_XIR_EXP_OFFSET) &
1079 				ASO_DSEG_EXP_MASK;
1080 			MLX5_SET(flow_meter_parameters, attr,
1081 				cir_exponent, val);
1082 			val = cbs_cir & ASO_DSEG_MAN_MASK;
1083 			MLX5_SET(flow_meter_parameters, attr,
1084 				cir_mantissa, val);
1085 		}
1086 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
1087 			val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) &
1088 				ASO_DSEG_EXP_MASK;
1089 			MLX5_SET(flow_meter_parameters, attr,
1090 				ebs_exponent, val);
1091 			val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) &
1092 				ASO_DSEG_MAN_MASK;
1093 			MLX5_SET(flow_meter_parameters, attr,
1094 				ebs_mantissa, val);
1095 		}
1096 		/* Apply modifications to meter only if it was created. */
1097 		if (fm->meter_action) {
1098 			ret = mlx5_glue->dv_modify_flow_action_meter
1099 					(fm->meter_action, &mod_attr,
1100 					rte_cpu_to_be_64(modify_bits));
1101 			if (ret)
1102 				return ret;
1103 		}
1104 		/* Update succeedded modify meter parameters. */
1105 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
1106 			fm->active_state = !!active_state;
1107 	}
1108 	return 0;
1109 #else
1110 	(void)priv;
1111 	(void)fm;
1112 	(void)srtcm;
1113 	(void)modify_bits;
1114 	(void)active_state;
1115 	(void)is_enable;
1116 	return -ENOTSUP;
1117 #endif
1118 }
1119 
1120 static int
1121 mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev,
1122 				struct mlx5_flow_meter_info *fm,
1123 				uint64_t stats_mask)
1124 {
1125 	fm->bytes_dropped =
1126 		(stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
1127 	fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
1128 	if (fm->bytes_dropped || fm->pkts_dropped) {
1129 		if (!fm->drop_cnt) {
1130 			/* Alloc policer counters. */
1131 			fm->drop_cnt = mlx5_counter_alloc(dev);
1132 			if (!fm->drop_cnt)
1133 				return -1;
1134 		}
1135 	} else {
1136 		if (fm->drop_cnt) {
1137 			mlx5_counter_free(dev, fm->drop_cnt);
1138 			fm->drop_cnt = 0;
1139 		}
1140 	}
1141 	return 0;
1142 }
1143 
1144 /**
1145  * Create meter rules.
1146  *
1147  * @param[in] dev
1148  *   Pointer to Ethernet device.
1149  * @param[in] meter_id
1150  *   Meter id.
1151  * @param[in] params
1152  *   Pointer to rte meter parameters.
1153  * @param[in] shared
1154  *   Meter shared with other flow or not.
1155  * @param[out] error
1156  *   Pointer to rte meter error structure.
1157  *
1158  * @return
1159  *   0 on success, a negative errno value otherwise and rte_errno is set.
1160  */
1161 static int
1162 mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
1163 		       struct rte_mtr_params *params, int shared,
1164 		       struct rte_mtr_error *error)
1165 {
1166 	struct mlx5_priv *priv = dev->data->dev_private;
1167 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1168 	struct mlx5_flow_meter_profile *fmp;
1169 	struct mlx5_flow_meter_info *fm;
1170 	struct mlx5_legacy_flow_meter *legacy_fm;
1171 	struct mlx5_flow_meter_policy *mtr_policy = NULL;
1172 	struct mlx5_indexed_pool_config flow_ipool_cfg = {
1173 		.size = 0,
1174 		.trunk_size = 64,
1175 		.need_lock = 1,
1176 		.type = "mlx5_flow_mtr_flow_id_pool",
1177 	};
1178 	struct mlx5_aso_mtr *aso_mtr;
1179 	uint32_t mtr_idx, policy_idx;
1180 	union mlx5_l3t_data data;
1181 	int ret;
1182 	uint8_t domain_bitmap;
1183 	uint8_t mtr_id_bits;
1184 	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
1185 				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
1186 
1187 	if (!priv->mtr_en)
1188 		return -rte_mtr_error_set(error, ENOTSUP,
1189 					RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1190 					"Meter is not supported");
1191 	/* Validate the parameters. */
1192 	ret = mlx5_flow_meter_validate(priv, meter_id, params, error);
1193 	if (ret)
1194 		return ret;
1195 	/* Meter profile must exist. */
1196 	fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
1197 	if (fmp == NULL)
1198 		return -rte_mtr_error_set(error, ENOENT,
1199 			RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1200 			NULL, "Meter profile id not valid.");
1201 	/* Meter policy must exist. */
1202 	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
1203 		__atomic_add_fetch
1204 			(&priv->sh->mtrmng->def_policy_ref_cnt,
1205 			1, __ATOMIC_RELAXED);
1206 		domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT;
1207 		if (!priv->config.dv_esw_en)
1208 			domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
1209 	} else {
1210 		if (!priv->sh->meter_aso_en)
1211 			return -rte_mtr_error_set(error, ENOTSUP,
1212 				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1213 				"Part of the policies cannot be "
1214 				"supported without ASO ");
1215 		mtr_policy = mlx5_flow_meter_policy_find(dev,
1216 				params->meter_policy_id, &policy_idx);
1217 		if (!mtr_policy)
1218 			return -rte_mtr_error_set(error, ENOENT,
1219 				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1220 				NULL, "Meter policy id not valid.");
1221 		domain_bitmap = (mtr_policy->ingress ?
1222 					MLX5_MTR_DOMAIN_INGRESS_BIT : 0) |
1223 				(mtr_policy->egress ?
1224 					MLX5_MTR_DOMAIN_EGRESS_BIT : 0) |
1225 				(mtr_policy->transfer ?
1226 					MLX5_MTR_DOMAIN_TRANSFER_BIT : 0);
1227 		if (fmp->g_support && mtr_policy->skip_g)
1228 			return -rte_mtr_error_set(error, ENOTSUP,
1229 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1230 					NULL, "Meter green policy is empty.");
1231 		if (fmp->y_support && mtr_policy->skip_y)
1232 			return -rte_mtr_error_set(error, ENOTSUP,
1233 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1234 					NULL, "Meter yellow policy is empty.");
1235 	}
1236 	/* Allocate the flow meter memory. */
1237 	if (priv->sh->meter_aso_en) {
1238 		mtr_idx = mlx5_flow_mtr_alloc(dev);
1239 		if (!mtr_idx)
1240 			return -rte_mtr_error_set(error, ENOMEM,
1241 				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1242 				"Memory alloc failed for meter.");
1243 		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
1244 		fm = &aso_mtr->fm;
1245 	} else {
1246 		if (fmp->y_support)
1247 			return -rte_mtr_error_set(error, ENOMEM,
1248 				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1249 				"Unsupported profile with yellow.");
1250 		legacy_fm = mlx5_ipool_zmalloc
1251 				(priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
1252 		if (legacy_fm == NULL)
1253 			return -rte_mtr_error_set(error, ENOMEM,
1254 				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1255 				"Memory alloc failed for meter.");
1256 		legacy_fm->idx = mtr_idx;
1257 		fm = &legacy_fm->fm;
1258 	}
1259 	mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
1260 	if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) >
1261 	    mtr_reg_bits) {
1262 		DRV_LOG(ERR, "Meter number exceeds max limit.");
1263 		goto error;
1264 	}
1265 	if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits)
1266 		priv->sh->mtrmng->max_mtr_bits = mtr_id_bits;
1267 	/* Fill the flow meter parameters. */
1268 	fm->meter_id = meter_id;
1269 	fm->policy_id = params->meter_policy_id;
1270 	fm->profile = fmp;
1271 	if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask))
1272 		goto error;
1273 	if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap))
1274 		goto error;
1275 	/* Add to the flow meter list. */
1276 	if (!priv->sh->meter_aso_en)
1277 		TAILQ_INSERT_TAIL(fms, legacy_fm, next);
1278 	/* Add to the flow meter list. */
1279 	fm->active_state = 1; /* Config meter starts as active. */
1280 	fm->is_enable = 1;
1281 	fm->shared = !!shared;
1282 	__atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
1283 	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
1284 		fm->def_policy = 1;
1285 		fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
1286 		if (!fm->flow_ipool)
1287 			goto error;
1288 	}
1289 	rte_spinlock_init(&fm->sl);
1290 	/* If ASO meter supported, update ASO flow meter by wqe. */
1291 	if (priv->sh->meter_aso_en) {
1292 		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
1293 		ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
1294 		if (ret)
1295 			goto error;
1296 		if (!priv->mtr_idx_tbl) {
1297 			priv->mtr_idx_tbl =
1298 				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
1299 			if (!priv->mtr_idx_tbl)
1300 				goto error;
1301 		}
1302 		data.dword = mtr_idx;
1303 		if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
1304 			goto error;
1305 	}
1306 	if (mtr_policy)
1307 		__atomic_add_fetch(&mtr_policy->ref_cnt, 1, __ATOMIC_RELAXED);
1308 	return 0;
1309 error:
1310 	mlx5_flow_destroy_mtr_tbls(dev, fm);
1311 	/* Free policer counters. */
1312 	if (fm->drop_cnt)
1313 		mlx5_counter_free(dev, fm->drop_cnt);
1314 	if (priv->sh->meter_aso_en)
1315 		mlx5_flow_mtr_free(dev, mtr_idx);
1316 	else
1317 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
1318 	return -rte_mtr_error_set(error, ENOTSUP,
1319 		RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1320 		NULL, "Failed to create devx meter.");
1321 }
1322 
1323 static int
1324 mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
1325 			struct mlx5_flow_meter_info *fm,
1326 			uint32_t mtr_idx)
1327 {
1328 	struct mlx5_priv *priv = dev->data->dev_private;
1329 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1330 	struct mlx5_flow_meter_profile *fmp;
1331 	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
1332 	struct mlx5_flow_meter_policy *mtr_policy;
1333 
1334 	/* Meter object must not have any owner. */
1335 	MLX5_ASSERT(!fm->ref_cnt);
1336 	/* Get meter profile. */
1337 	fmp = fm->profile;
1338 	if (fmp == NULL)
1339 		return -1;
1340 	/* Update dependencies. */
1341 	__atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
1342 	fm->profile = NULL;
1343 	/* Remove from list. */
1344 	if (!priv->sh->meter_aso_en) {
1345 		legacy_fm = container_of(fm,
1346 			struct mlx5_legacy_flow_meter, fm);
1347 		TAILQ_REMOVE(fms, legacy_fm, next);
1348 	}
1349 	/* Free drop counters. */
1350 	if (fm->drop_cnt)
1351 		mlx5_counter_free(dev, fm->drop_cnt);
1352 	/* Free meter flow table. */
1353 	if (fm->flow_ipool) {
1354 		mlx5_ipool_destroy(fm->flow_ipool);
1355 		fm->flow_ipool = 0;
1356 	}
1357 	mlx5_flow_destroy_mtr_tbls(dev, fm);
1358 	if (fm->def_policy)
1359 		__atomic_sub_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
1360 				1, __ATOMIC_RELAXED);
1361 	if (priv->sh->meter_aso_en) {
1362 		if (!fm->def_policy) {
1363 			mtr_policy = mlx5_flow_meter_policy_find(dev,
1364 						fm->policy_id, NULL);
1365 			if (mtr_policy)
1366 				__atomic_sub_fetch(&mtr_policy->ref_cnt,
1367 						1, __ATOMIC_RELAXED);
1368 			fm->policy_id = 0;
1369 		}
1370 		fm->def_policy = 0;
1371 		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id))
1372 			return -1;
1373 		mlx5_flow_mtr_free(dev, mtr_idx);
1374 	} else {
1375 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
1376 					legacy_fm->idx);
1377 	}
1378 	return 0;
1379 }
1380 
1381 /**
1382  * Destroy meter rules.
1383  *
1384  * @param[in] dev
1385  *   Pointer to Ethernet device.
1386  * @param[in] meter_id
1387  *   Meter id.
1388  * @param[out] error
1389  *   Pointer to rte meter error structure.
1390  *
1391  * @return
1392  *   0 on success, a negative errno value otherwise and rte_errno is set.
1393  */
1394 static int
1395 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
1396 			struct rte_mtr_error *error)
1397 {
1398 	struct mlx5_priv *priv = dev->data->dev_private;
1399 	struct mlx5_flow_meter_info *fm;
1400 	uint32_t mtr_idx = 0;
1401 
1402 	if (!priv->mtr_en)
1403 		return -rte_mtr_error_set(error, ENOTSUP,
1404 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1405 					  NULL,
1406 					  "Meter is not supported");
1407 	/* Meter object must exist. */
1408 	fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
1409 	if (fm == NULL)
1410 		return -rte_mtr_error_set(error, ENOENT,
1411 					  RTE_MTR_ERROR_TYPE_MTR_ID,
1412 					  NULL,
1413 					  "Meter object id not valid.");
1414 	/* Meter object must not have any owner. */
1415 	if (fm->ref_cnt > 0)
1416 		return -rte_mtr_error_set(error, EBUSY,
1417 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1418 					  NULL,
1419 					  "Meter object is being used.");
1420 	/* Destroy the meter profile. */
1421 	if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
1422 		return -rte_mtr_error_set(error, EINVAL,
1423 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1424 					NULL,
1425 					"MTR object meter profile invalid.");
1426 	return 0;
1427 }
1428 
1429 /**
1430  * Modify meter state.
1431  *
1432  * @param[in] priv
1433  *   Pointer to mlx5 private data structure.
1434  * @param[in] fm
1435  *   Pointer to flow meter.
1436  * @param[in] new_state
1437  *   New state to update.
1438  * @param[out] error
1439  *   Pointer to rte meter error structure.
1440  *
1441  * @return
1442  *   0 on success, a negative errno value otherwise and rte_errno is set.
1443  */
1444 static int
1445 mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
1446 			     struct mlx5_flow_meter_info *fm,
1447 			     uint32_t new_state,
1448 			     struct rte_mtr_error *error)
1449 {
1450 	static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
1451 		.cbs_cir = RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL),
1452 		.ebs_eir = 0,
1453 	};
1454 	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
1455 			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
1456 	int ret;
1457 
1458 	if (new_state == MLX5_FLOW_METER_DISABLE)
1459 		ret = mlx5_flow_meter_action_modify(priv, fm,
1460 				&srtcm, modify_bits, 0, 0);
1461 	else
1462 		ret = mlx5_flow_meter_action_modify(priv, fm,
1463 						    &fm->profile->srtcm_prm,
1464 						    modify_bits, 0, 1);
1465 	if (ret)
1466 		return -rte_mtr_error_set(error, -ret,
1467 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
1468 					  NULL,
1469 					  new_state ?
1470 					  "Failed to enable meter." :
1471 					  "Failed to disable meter.");
1472 	return 0;
1473 }
1474 
1475 /**
1476  * Callback to enable flow meter.
1477  *
1478  * @param[in] dev
1479  *   Pointer to Ethernet device.
1480  * @param[in] meter_id
1481  *   Meter id.
1482  * @param[out] error
1483  *   Pointer to rte meter error structure.
1484  *
1485  * @return
1486  *   0 on success, a negative errno value otherwise and rte_errno is set.
1487  */
1488 static int
1489 mlx5_flow_meter_enable(struct rte_eth_dev *dev,
1490 		       uint32_t meter_id,
1491 		       struct rte_mtr_error *error)
1492 {
1493 	struct mlx5_priv *priv = dev->data->dev_private;
1494 	struct mlx5_flow_meter_info *fm;
1495 	int ret;
1496 
1497 	if (!priv->mtr_en)
1498 		return -rte_mtr_error_set(error, ENOTSUP,
1499 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1500 					  "Meter is not supported");
1501 	/* Meter object must exist. */
1502 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1503 	if (fm == NULL)
1504 		return -rte_mtr_error_set(error, ENOENT,
1505 					  RTE_MTR_ERROR_TYPE_MTR_ID,
1506 					  NULL, "Meter not found.");
1507 	if (fm->active_state == MLX5_FLOW_METER_ENABLE)
1508 		return 0;
1509 	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
1510 					   error);
1511 	if (!ret)
1512 		fm->active_state = MLX5_FLOW_METER_ENABLE;
1513 	return ret;
1514 }
1515 
1516 /**
1517  * Callback to disable flow meter.
1518  *
1519  * @param[in] dev
1520  *   Pointer to Ethernet device.
1521  * @param[in] meter_id
1522  *   Meter id.
1523  * @param[out] error
1524  *   Pointer to rte meter error structure.
1525  *
1526  * @return
1527  *   0 on success, a negative errno value otherwise and rte_errno is set.
1528  */
1529 static int
1530 mlx5_flow_meter_disable(struct rte_eth_dev *dev,
1531 			uint32_t meter_id,
1532 			struct rte_mtr_error *error)
1533 {
1534 	struct mlx5_priv *priv = dev->data->dev_private;
1535 	struct mlx5_flow_meter_info *fm;
1536 	int ret;
1537 
1538 	if (!priv->mtr_en)
1539 		return -rte_mtr_error_set(error, ENOTSUP,
1540 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1541 					  "Meter is not supported");
1542 	/* Meter object must exist. */
1543 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1544 	if (fm == NULL)
1545 		return -rte_mtr_error_set(error, ENOENT,
1546 					  RTE_MTR_ERROR_TYPE_MTR_ID,
1547 					  NULL, "Meter not found.");
1548 	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
1549 		return 0;
1550 	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
1551 					   error);
1552 	if (!ret)
1553 		fm->active_state = MLX5_FLOW_METER_DISABLE;
1554 	return ret;
1555 }
1556 
1557 /**
1558  * Callback to update meter profile.
1559  *
1560  * @param[in] dev
1561  *   Pointer to Ethernet device.
1562  * @param[in] meter_id
1563  *   Meter id.
1564  * @param[in] meter_profile_id
1565  *   To be updated meter profile id.
1566  * @param[out] error
1567  *   Pointer to rte meter error structure.
1568  *
1569  * @return
1570  *   0 on success, a negative errno value otherwise and rte_errno is set.
1571  */
1572 static int
1573 mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
1574 			       uint32_t meter_id,
1575 			       uint32_t meter_profile_id,
1576 			       struct rte_mtr_error *error)
1577 {
1578 	struct mlx5_priv *priv = dev->data->dev_private;
1579 	struct mlx5_flow_meter_profile *fmp;
1580 	struct mlx5_flow_meter_profile *old_fmp;
1581 	struct mlx5_flow_meter_info *fm;
1582 	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
1583 			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
1584 	int ret;
1585 
1586 	if (!priv->mtr_en)
1587 		return -rte_mtr_error_set(error, ENOTSUP,
1588 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1589 					  "Meter is not supported");
1590 	/* Meter profile must exist. */
1591 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
1592 	if (fmp == NULL)
1593 		return -rte_mtr_error_set(error, ENOENT,
1594 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1595 					  NULL, "Meter profile not found.");
1596 	/* Meter object must exist. */
1597 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1598 	if (fm == NULL)
1599 		return -rte_mtr_error_set(error, ENOENT,
1600 					  RTE_MTR_ERROR_TYPE_MTR_ID,
1601 					  NULL, "Meter not found.");
1602 	/* MTR object already set to meter profile id. */
1603 	old_fmp = fm->profile;
1604 	if (fmp == old_fmp)
1605 		return 0;
1606 	/* Update the profile. */
1607 	fm->profile = fmp;
1608 	/* Update meter params in HW (if not disabled). */
1609 	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
1610 		return 0;
1611 	ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
1612 					      modify_bits, fm->active_state, 1);
1613 	if (ret) {
1614 		fm->profile = old_fmp;
1615 		return -rte_mtr_error_set(error, -ret,
1616 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
1617 					  NULL, "Failed to update meter"
1618 					  " parmeters in hardware.");
1619 	}
1620 	old_fmp->ref_cnt--;
1621 	fmp->ref_cnt++;
1622 	return 0;
1623 }
1624 
1625 /**
1626  * Callback to update meter stats mask.
1627  *
1628  * @param[in] dev
1629  *   Pointer to Ethernet device.
1630  * @param[in] meter_id
1631  *   Meter id.
1632  * @param[in] stats_mask
1633  *   To be updated stats_mask.
1634  * @param[out] error
1635  *   Pointer to rte meter error structure.
1636  *
1637  * @return
1638  *   0 on success, a negative errno value otherwise and rte_errno is set.
1639  */
1640 static int
1641 mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
1642 			     uint32_t meter_id,
1643 			     uint64_t stats_mask,
1644 			     struct rte_mtr_error *error)
1645 {
1646 	struct mlx5_priv *priv = dev->data->dev_private;
1647 	struct mlx5_flow_meter_info *fm;
1648 
1649 	if (!priv->mtr_en)
1650 		return -rte_mtr_error_set(error, ENOTSUP,
1651 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1652 					  "Meter is not supported");
1653 	/* Meter object must exist. */
1654 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1655 	if (fm == NULL)
1656 		return -rte_mtr_error_set(error, ENOENT,
1657 					  RTE_MTR_ERROR_TYPE_MTR_ID,
1658 					  NULL, "Meter object id not valid.");
1659 	if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask))
1660 		return -rte_mtr_error_set(error, ENOENT,
1661 					  RTE_MTR_ERROR_TYPE_MTR_ID,
1662 					  NULL, "Fail to allocate "
1663 					  "counter for meter.");
1664 	return 0;
1665 }
1666 
1667 /**
1668  * Callback to read meter statistics.
1669  *
1670  * @param[in] dev
1671  *   Pointer to Ethernet device.
1672  * @param[in] meter_id
1673  *   Meter id.
1674  * @param[out] stats
1675  *   Pointer to store the statistics.
1676  * @param[out] stats_mask
1677  *   Pointer to store the stats_mask.
1678  * @param[in] clear
1679  *   Statistic to be cleared after read or not.
1680  * @param[out] error
1681  *   Pointer to rte meter error structure.
1682  *
1683  * @return
1684  *   0 on success, a negative errno value otherwise and rte_errno is set.
1685  */
1686 static int
1687 mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
1688 			   uint32_t meter_id,
1689 			   struct rte_mtr_stats *stats,
1690 			   uint64_t *stats_mask,
1691 			   int clear,
1692 			   struct rte_mtr_error *error)
1693 {
1694 	struct mlx5_priv *priv = dev->data->dev_private;
1695 	struct mlx5_flow_meter_info *fm;
1696 	uint64_t pkts;
1697 	uint64_t bytes;
1698 	int ret = 0;
1699 
1700 	if (!priv->mtr_en)
1701 		return -rte_mtr_error_set(error, ENOTSUP,
1702 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1703 					  "Meter is not supported");
1704 	/* Meter object must exist. */
1705 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1706 	if (fm == NULL)
1707 		return -rte_mtr_error_set(error, ENOENT,
1708 					  RTE_MTR_ERROR_TYPE_MTR_ID,
1709 					  NULL, "Meter object id not valid.");
1710 	*stats_mask = 0;
1711 	if (fm->bytes_dropped)
1712 		*stats_mask |= RTE_MTR_STATS_N_BYTES_DROPPED;
1713 	if (fm->pkts_dropped)
1714 		*stats_mask |= RTE_MTR_STATS_N_PKTS_DROPPED;
1715 	memset(stats, 0, sizeof(*stats));
1716 	if (fm->drop_cnt) {
1717 		ret = mlx5_counter_query(dev, fm->drop_cnt, clear, &pkts,
1718 						 &bytes);
1719 		if (ret)
1720 			goto error;
1721 		/* If need to read the packets, set it. */
1722 		if (fm->pkts_dropped)
1723 			stats->n_pkts_dropped = pkts;
1724 		/* If need to read the bytes, set it. */
1725 		if (fm->bytes_dropped)
1726 			stats->n_bytes_dropped = bytes;
1727 	}
1728 	return 0;
1729 error:
1730 	return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
1731 				 "Failed to read meter drop counters.");
1732 }
1733 
1734 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
1735 	.capabilities_get = mlx5_flow_mtr_cap_get,
1736 	.meter_profile_add = mlx5_flow_meter_profile_add,
1737 	.meter_profile_delete = mlx5_flow_meter_profile_delete,
1738 	.meter_policy_validate = mlx5_flow_meter_policy_validate,
1739 	.meter_policy_add = mlx5_flow_meter_policy_add,
1740 	.meter_policy_delete = mlx5_flow_meter_policy_delete,
1741 	.create = mlx5_flow_meter_create,
1742 	.destroy = mlx5_flow_meter_destroy,
1743 	.meter_enable = mlx5_flow_meter_enable,
1744 	.meter_disable = mlx5_flow_meter_disable,
1745 	.meter_profile_update = mlx5_flow_meter_profile_update,
1746 	.meter_dscp_table_update = NULL,
1747 	.stats_update = mlx5_flow_meter_stats_update,
1748 	.stats_read = mlx5_flow_meter_stats_read,
1749 };
1750 
1751 /**
1752  * Get meter operations.
1753  *
1754  * @param dev
1755  *   Pointer to Ethernet device structure.
1756  * @param arg
1757  *   Pointer to set the mtr operations.
1758  *
1759  * @return
1760  *   Always 0.
1761  */
1762 int
1763 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
1764 {
1765 	*(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
1766 	return 0;
1767 }
1768 
1769 /**
1770  * Find meter by id.
1771  *
1772  * @param priv
1773  *   Pointer to mlx5_priv.
1774  * @param meter_id
1775  *   Meter id.
1776  * @param mtr_idx
1777  *   Pointer to Meter index.
1778  *
1779  * @return
1780  *   Pointer to the meter info found on success, NULL otherwise.
1781  */
1782 struct mlx5_flow_meter_info *
1783 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
1784 		uint32_t *mtr_idx)
1785 {
1786 	struct mlx5_legacy_flow_meter *legacy_fm;
1787 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1788 	struct mlx5_aso_mtr *aso_mtr;
1789 	struct mlx5_aso_mtr_pools_mng *pools_mng =
1790 				&priv->sh->mtrmng->pools_mng;
1791 	union mlx5_l3t_data data;
1792 
1793 	if (priv->sh->meter_aso_en) {
1794 		rte_spinlock_lock(&pools_mng->mtrsl);
1795 		if (!pools_mng->n_valid || !priv->mtr_idx_tbl) {
1796 			rte_spinlock_unlock(&pools_mng->mtrsl);
1797 			return NULL;
1798 		}
1799 		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
1800 			!data.dword) {
1801 			rte_spinlock_unlock(&pools_mng->mtrsl);
1802 			return NULL;
1803 		}
1804 		if (mtr_idx)
1805 			*mtr_idx = data.dword;
1806 		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
1807 		/* Remove reference taken by the mlx5_l3t_get_entry. */
1808 		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
1809 		rte_spinlock_unlock(&pools_mng->mtrsl);
1810 		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
1811 			return NULL;
1812 		return &aso_mtr->fm;
1813 	}
1814 	TAILQ_FOREACH(legacy_fm, fms, next)
1815 		if (meter_id == legacy_fm->fm.meter_id) {
1816 			if (mtr_idx)
1817 				*mtr_idx = legacy_fm->idx;
1818 			return &legacy_fm->fm;
1819 		}
1820 	return NULL;
1821 }
1822 
1823 /**
1824  * Find meter by index.
1825  *
1826  * @param priv
1827  *   Pointer to mlx5_priv.
1828  * @param idx
1829  *   Meter index.
1830  *
1831  * @return
1832  *   Pointer to the meter info found on success, NULL otherwise.
1833  */
1834 struct mlx5_flow_meter_info *
1835 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
1836 {
1837 	struct mlx5_aso_mtr *aso_mtr;
1838 
1839 	if (priv->sh->meter_aso_en) {
1840 		aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
1841 		if (!aso_mtr)
1842 			return NULL;
1843 		return &aso_mtr->fm;
1844 	} else {
1845 		return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
1846 	}
1847 }
1848 
1849 /**
1850  * Attach meter to flow.
1851  * Unidirectional Meter creation can only be done
1852  * when flow direction is known, i.e. when calling meter_attach.
1853  *
1854  * @param [in] priv
1855  *  Pointer to mlx5 private data.
1856  * @param[in] fm
1857  *   Pointer to flow meter.
1858  * @param [in] attr
1859  *  Pointer to flow attributes.
1860  * @param [out] error
1861  *  Pointer to error structure.
1862  *
1863  * @return
1864  *   0 on success, a negative errno value otherwise and rte_errno is set.
1865  */
1866 int
1867 mlx5_flow_meter_attach(struct mlx5_priv *priv,
1868 		       struct mlx5_flow_meter_info *fm,
1869 		       const struct rte_flow_attr *attr,
1870 		       struct rte_flow_error *error)
1871 {
1872 	int ret = 0;
1873 
1874 	if (priv->sh->meter_aso_en) {
1875 		struct mlx5_aso_mtr *aso_mtr;
1876 
1877 		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
1878 		if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) {
1879 			return rte_flow_error_set(error, ENOENT,
1880 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1881 					NULL,
1882 					"Timeout in meter configuration");
1883 		}
1884 		rte_spinlock_lock(&fm->sl);
1885 		if (fm->shared || !fm->ref_cnt) {
1886 			fm->ref_cnt++;
1887 		} else {
1888 			rte_flow_error_set(error, EINVAL,
1889 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1890 				   "Meter cannot be shared");
1891 			ret = -1;
1892 		}
1893 		rte_spinlock_unlock(&fm->sl);
1894 	} else {
1895 		rte_spinlock_lock(&fm->sl);
1896 		if (fm->meter_action) {
1897 			if (fm->shared &&
1898 			    attr->transfer == fm->transfer &&
1899 			    attr->ingress == fm->ingress &&
1900 			    attr->egress == fm->egress) {
1901 				fm->ref_cnt++;
1902 			} else {
1903 				rte_flow_error_set(error, EINVAL,
1904 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1905 					fm->shared ?
1906 					"Meter attr not match." :
1907 					"Meter cannot be shared.");
1908 				ret = -1;
1909 			}
1910 		} else {
1911 			fm->ingress = attr->ingress;
1912 			fm->egress = attr->egress;
1913 			fm->transfer = attr->transfer;
1914 			fm->ref_cnt = 1;
1915 			/* This also creates the meter object. */
1916 			fm->meter_action = mlx5_flow_meter_action_create(priv,
1917 									 fm);
1918 			if (!fm->meter_action) {
1919 				fm->ref_cnt = 0;
1920 				fm->ingress = 0;
1921 				fm->egress = 0;
1922 				fm->transfer = 0;
1923 				rte_flow_error_set(error, EINVAL,
1924 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1925 					"Meter action create failed.");
1926 				ret = -1;
1927 			}
1928 		}
1929 		rte_spinlock_unlock(&fm->sl);
1930 	}
1931 	return ret ? -rte_errno : 0;
1932 }
1933 
1934 /**
1935  * Detach meter from flow.
1936  *
1937  * @param [in] priv
1938  *  Pointer to mlx5 private data.
1939  * @param [in] fm
1940  *  Pointer to flow meter.
1941  */
1942 void
1943 mlx5_flow_meter_detach(struct mlx5_priv *priv,
1944 		       struct mlx5_flow_meter_info *fm)
1945 {
1946 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
1947 	rte_spinlock_lock(&fm->sl);
1948 	MLX5_ASSERT(fm->ref_cnt);
1949 	if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) {
1950 		mlx5_glue->destroy_flow_action(fm->meter_action);
1951 		fm->meter_action = NULL;
1952 		fm->ingress = 0;
1953 		fm->egress = 0;
1954 		fm->transfer = 0;
1955 	}
1956 	rte_spinlock_unlock(&fm->sl);
1957 #else
1958 	(void)priv;
1959 	(void)fm;
1960 #endif
1961 }
1962 
1963 /**
1964  * Flush meter with Rx queue configuration.
1965  *
1966  * @param[in] dev
1967  *   Pointer to Ethernet device.
1968  */
1969 void
1970 mlx5_flow_meter_rxq_flush(struct rte_eth_dev *dev)
1971 {
1972 	struct mlx5_priv *priv = dev->data->dev_private;
1973 	struct mlx5_flow_meter_sub_policy *sub_policy;
1974 	struct mlx5_flow_meter_policy *mtr_policy;
1975 	void *entry;
1976 	uint32_t i, policy_idx;
1977 
1978 	if (!priv->mtr_en)
1979 		return;
1980 	if (priv->policy_idx_tbl) {
1981 		MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
1982 			policy_idx = *(uint32_t *)entry;
1983 			sub_policy = mlx5_ipool_get
1984 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
1985 				policy_idx);
1986 			if (!sub_policy || !sub_policy->main_policy)
1987 				continue;
1988 			mtr_policy = sub_policy->main_policy;
1989 			if (mtr_policy->is_queue || mtr_policy->is_rss)
1990 				mlx5_flow_destroy_sub_policy_with_rxq(dev,
1991 					mtr_policy);
1992 		}
1993 	}
1994 }
1995 
1996 /**
1997  * Iterate a meter hierarchy and flush all meters and policies if possible.
1998  *
1999  * @param[in] dev
2000  *   Pointer to Ethernet device.
2001  * @param[in] fm
2002  *   Pointer to flow meter.
2003  * @param[in] mtr_idx
2004  *   .Meter's index
2005  * @param[out] error
2006  *   Pointer to rte meter error structure.
2007  *
2008  * @return
2009  *   0 on success, a negative errno value otherwise and rte_errno is set.
2010  */
2011 static int
2012 mlx5_flow_meter_flush_hierarchy(struct rte_eth_dev *dev,
2013 				struct mlx5_flow_meter_info *fm,
2014 				uint32_t mtr_idx,
2015 				struct rte_mtr_error *error)
2016 {
2017 	struct mlx5_priv *priv = dev->data->dev_private;
2018 	struct mlx5_flow_meter_policy *policy;
2019 	uint32_t policy_id;
2020 	struct mlx5_flow_meter_info *next_fm;
2021 	uint32_t next_mtr_idx;
2022 	struct mlx5_flow_meter_policy *next_policy = NULL;
2023 
2024 	policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
2025 	MLX5_ASSERT(policy);
2026 	while (!fm->ref_cnt && policy->is_hierarchy) {
2027 		policy_id = fm->policy_id;
2028 		next_fm = mlx5_flow_meter_find(priv,
2029 				policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
2030 				&next_mtr_idx);
2031 		if (next_fm) {
2032 			next_policy = mlx5_flow_meter_policy_find(dev,
2033 							next_fm->policy_id,
2034 							NULL);
2035 			MLX5_ASSERT(next_policy);
2036 		}
2037 		if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
2038 			return -rte_mtr_error_set(error, ENOTSUP,
2039 						RTE_MTR_ERROR_TYPE_MTR_ID,
2040 						NULL,
2041 						"Failed to flush meter.");
2042 		if (policy->ref_cnt)
2043 			break;
2044 		if (__mlx5_flow_meter_policy_delete(dev, policy_id,
2045 						policy, error, true))
2046 			return -rte_errno;
2047 		mlx5_free(policy);
2048 		if (!next_fm || !next_policy)
2049 			break;
2050 		fm = next_fm;
2051 		mtr_idx = next_mtr_idx;
2052 		policy = next_policy;
2053 	}
2054 	return 0;
2055 }
2056 
2057 /**
2058  * Flush all the hierarchy meters and their policies.
2059  *
2060  * @param[in] dev
2061  *   Pointer to Ethernet device.
2062  * @param[out] error
2063  *   Pointer to rte meter error structure.
2064  *
2065  * @return
2066  *   0 on success, a negative errno value otherwise and rte_errno is set.
2067  */
2068 static int
2069 mlx5_flow_meter_flush_all_hierarchies(struct rte_eth_dev *dev,
2070 				      struct rte_mtr_error *error)
2071 {
2072 	struct mlx5_priv *priv = dev->data->dev_private;
2073 	struct mlx5_flow_meter_info *fm;
2074 	struct mlx5_flow_meter_policy *policy;
2075 	struct mlx5_flow_meter_sub_policy *sub_policy;
2076 	struct mlx5_flow_meter_info *next_fm;
2077 	struct mlx5_aso_mtr *aso_mtr;
2078 	uint32_t mtr_idx = 0;
2079 	uint32_t i, policy_idx;
2080 	void *entry;
2081 
2082 	if (!priv->mtr_idx_tbl || !priv->policy_idx_tbl)
2083 		return 0;
2084 	MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
2085 		mtr_idx = *(uint32_t *)entry;
2086 		if (!mtr_idx)
2087 			continue;
2088 		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
2089 		fm = &aso_mtr->fm;
2090 		if (fm->ref_cnt || fm->def_policy)
2091 			continue;
2092 		if (mlx5_flow_meter_flush_hierarchy(dev, fm, mtr_idx, error))
2093 			return -rte_errno;
2094 	}
2095 	MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
2096 		policy_idx = *(uint32_t *)entry;
2097 		sub_policy = mlx5_ipool_get
2098 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
2099 				policy_idx);
2100 		if (!sub_policy)
2101 			return -rte_mtr_error_set(error,
2102 					EINVAL,
2103 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2104 					NULL, "Meter policy invalid.");
2105 		policy = sub_policy->main_policy;
2106 		if (!policy || !policy->is_hierarchy || policy->ref_cnt)
2107 			continue;
2108 		next_fm = mlx5_flow_meter_find(priv,
2109 				policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
2110 				&mtr_idx);
2111 		if (__mlx5_flow_meter_policy_delete(dev, i, policy,
2112 						    error, true))
2113 			return -rte_mtr_error_set(error,
2114 					EINVAL,
2115 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2116 					NULL, "Meter policy invalid.");
2117 		mlx5_free(policy);
2118 		if (!next_fm || next_fm->ref_cnt || next_fm->def_policy)
2119 			continue;
2120 		if (mlx5_flow_meter_flush_hierarchy(dev, next_fm,
2121 						    mtr_idx, error))
2122 			return -rte_errno;
2123 	}
2124 	return 0;
2125 }
2126 /**
2127  * Flush meter configuration.
2128  *
2129  * @param[in] dev
2130  *   Pointer to Ethernet device.
2131  * @param[out] error
2132  *   Pointer to rte meter error structure.
2133  *
2134  * @return
2135  *   0 on success, a negative errno value otherwise and rte_errno is set.
2136  */
2137 int
2138 mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
2139 {
2140 	struct mlx5_priv *priv = dev->data->dev_private;
2141 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
2142 	struct mlx5_flow_meter_profile *fmp;
2143 	struct mlx5_legacy_flow_meter *legacy_fm;
2144 	struct mlx5_flow_meter_info *fm;
2145 	struct mlx5_flow_meter_sub_policy *sub_policy;
2146 	void *tmp;
2147 	uint32_t i, mtr_idx, policy_idx;
2148 	void *entry;
2149 	struct mlx5_aso_mtr *aso_mtr;
2150 
2151 	if (!priv->mtr_en)
2152 		return 0;
2153 	if (priv->sh->meter_aso_en) {
2154 		if (mlx5_flow_meter_flush_all_hierarchies(dev, error))
2155 			return -rte_errno;
2156 		if (priv->mtr_idx_tbl) {
2157 			MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
2158 				mtr_idx = *(uint32_t *)entry;
2159 				if (mtr_idx) {
2160 					aso_mtr =
2161 					mlx5_aso_meter_by_idx(priv, mtr_idx);
2162 					fm = &aso_mtr->fm;
2163 					(void)mlx5_flow_meter_params_flush(dev,
2164 						fm, mtr_idx);
2165 				}
2166 			}
2167 			mlx5_l3t_destroy(priv->mtr_idx_tbl);
2168 			priv->mtr_idx_tbl = NULL;
2169 		}
2170 	} else {
2171 		RTE_TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
2172 			fm = &legacy_fm->fm;
2173 			if (mlx5_flow_meter_params_flush(dev, fm, 0))
2174 				return -rte_mtr_error_set(error, EINVAL,
2175 				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
2176 				NULL, "MTR object meter profile invalid.");
2177 		}
2178 	}
2179 	if (priv->policy_idx_tbl) {
2180 		MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
2181 			policy_idx = *(uint32_t *)entry;
2182 			sub_policy = mlx5_ipool_get
2183 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
2184 				policy_idx);
2185 			if (!sub_policy)
2186 				return -rte_mtr_error_set(error,
2187 						EINVAL,
2188 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2189 						NULL, "MTR object "
2190 						"meter policy invalid.");
2191 			if (__mlx5_flow_meter_policy_delete(dev, i,
2192 						sub_policy->main_policy,
2193 						error, true))
2194 				return -rte_mtr_error_set(error,
2195 						EINVAL,
2196 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2197 						NULL, "MTR object "
2198 						"meter policy invalid.");
2199 			mlx5_free(sub_policy->main_policy);
2200 		}
2201 		mlx5_l3t_destroy(priv->policy_idx_tbl);
2202 		priv->policy_idx_tbl = NULL;
2203 	}
2204 	if (priv->mtr_profile_tbl) {
2205 		MLX5_L3T_FOREACH(priv->mtr_profile_tbl, i, entry) {
2206 			fmp = entry;
2207 			if (mlx5_flow_meter_profile_delete(dev, fmp->id,
2208 							   error))
2209 				return -rte_mtr_error_set(error, EINVAL,
2210 					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
2211 						NULL, "Fail to destroy "
2212 						"meter profile.");
2213 		}
2214 		mlx5_l3t_destroy(priv->mtr_profile_tbl);
2215 		priv->mtr_profile_tbl = NULL;
2216 	}
2217 	/* Delete default policy table. */
2218 	mlx5_flow_destroy_def_policy(dev);
2219 	if (priv->sh->refcnt == 1)
2220 		mlx5_flow_destroy_mtr_drop_tbls(dev);
2221 	return 0;
2222 }
2223