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