xref: /dpdk/drivers/net/mlx5/mlx5_flow_meter.c (revision 0bac9fc7)
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 
42 	memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
43 	MLX5_SET(flow_meter_parameters, fmp, valid, 1);
44 	MLX5_SET(flow_meter_parameters, fmp, bucket_overflow, 1);
45 	MLX5_SET(flow_meter_parameters, fmp,
46 		start_color, MLX5_FLOW_COLOR_GREEN);
47 	MLX5_SET(flow_meter_parameters, fmp, both_buckets_on_green, 0);
48 	val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
49 	MLX5_SET(flow_meter_parameters, fmp, cbs_exponent, val);
50 	val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
51 	MLX5_SET(flow_meter_parameters, fmp, cbs_mantissa, val);
52 	val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
53 	MLX5_SET(flow_meter_parameters, fmp, cir_exponent, val);
54 	val = (cbs_cir & ASO_DSEG_MAN_MASK);
55 	MLX5_SET(flow_meter_parameters, fmp, cir_mantissa, val);
56 	val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
57 	MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
58 	val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
59 	MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
60 	mtr_init.next_table =
61 		fm->transfer ? fm->mfts->transfer.tbl->obj :
62 			fm->egress ? fm->mfts->egress.tbl->obj :
63 				fm->mfts->ingress.tbl->obj;
64 	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
65 	mtr_init.flow_meter_parameter = fmp;
66 	mtr_init.flow_meter_parameter_sz =
67 		MLX5_ST_SZ_BYTES(flow_meter_parameters);
68 	mtr_init.active = fm->active_state;
69 	return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
70 #else
71 	(void)priv;
72 	(void)fm;
73 	return NULL;
74 #endif
75 }
76 
77 /**
78  * Find meter profile by id.
79  *
80  * @param priv
81  *   Pointer to mlx5_priv.
82  * @param meter_profile_id
83  *   Meter profile id.
84  *
85  * @return
86  *   Pointer to the profile found on success, NULL otherwise.
87  */
88 static struct mlx5_flow_meter_profile *
89 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
90 {
91 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
92 	struct mlx5_flow_meter_profile *fmp;
93 
94 	TAILQ_FOREACH(fmp, fmps, next)
95 		if (meter_profile_id == fmp->id)
96 			return fmp;
97 	return NULL;
98 }
99 
100 /**
101  * Validate the MTR profile.
102  *
103  * @param[in] dev
104  *   Pointer to Ethernet device.
105  * @param[in] meter_profile_id
106  *   Meter profile id.
107  * @param[in] profile
108  *   Pointer to meter profile detail.
109  * @param[out] error
110  *   Pointer to the error structure.
111  *
112  * @return
113  *   0 on success, a negative errno value otherwise and rte_errno is set.
114  */
115 static int
116 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
117 				 uint32_t meter_profile_id,
118 				 struct rte_mtr_meter_profile *profile,
119 				 struct rte_mtr_error *error)
120 {
121 	struct mlx5_priv *priv = dev->data->dev_private;
122 	struct mlx5_flow_meter_profile *fmp;
123 
124 	/* Profile must not be NULL. */
125 	if (profile == NULL)
126 		return -rte_mtr_error_set(error, EINVAL,
127 					  RTE_MTR_ERROR_TYPE_METER_PROFILE,
128 					  NULL, "Meter profile is null.");
129 	/* Meter profile ID must be valid. */
130 	if (meter_profile_id == UINT32_MAX)
131 		return -rte_mtr_error_set(error, EINVAL,
132 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
133 					  NULL, "Meter profile id not valid.");
134 	/* Meter profile must not exist. */
135 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
136 	if (fmp)
137 		return -rte_mtr_error_set(error, EEXIST,
138 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
139 					  NULL,
140 					  "Meter profile already exists.");
141 	if (profile->alg == RTE_MTR_SRTCM_RFC2697) {
142 		if (priv->config.hca_attr.qos.flow_meter_old) {
143 			/* Verify support for flow meter parameters. */
144 			if (profile->srtcm_rfc2697.cir > 0 &&
145 			    profile->srtcm_rfc2697.cir <= MLX5_SRTCM_CIR_MAX &&
146 			    profile->srtcm_rfc2697.cbs > 0 &&
147 			    profile->srtcm_rfc2697.cbs <= MLX5_SRTCM_CBS_MAX &&
148 			    profile->srtcm_rfc2697.ebs <= MLX5_SRTCM_EBS_MAX)
149 				return 0;
150 			else
151 				return -rte_mtr_error_set
152 					     (error, ENOTSUP,
153 					      RTE_MTR_ERROR_TYPE_MTR_PARAMS,
154 					      NULL,
155 					      profile->srtcm_rfc2697.ebs ?
156 					      "Metering value ebs must be 0." :
157 					      "Invalid metering parameters.");
158 		}
159 	}
160 	return -rte_mtr_error_set(error, ENOTSUP,
161 				  RTE_MTR_ERROR_TYPE_METER_PROFILE,
162 				  NULL, "Metering algorithm not supported.");
163 }
164 
165 /**
166  * Calculate mantissa and exponent for cir.
167  *
168  * @param[in] cir
169  *   Value to be calculated.
170  * @param[out] man
171  *   Pointer to the mantissa.
172  * @param[out] exp
173  *   Pointer to the exp.
174  */
175 static void
176 mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp)
177 {
178 	int64_t _cir;
179 	int64_t delta = INT64_MAX;
180 	uint8_t _man = 0;
181 	uint8_t _exp = 0;
182 	uint64_t m, e;
183 
184 	for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
185 		for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
186 			_cir = (1000000000ULL * m) >> e;
187 			if (llabs(cir - _cir) <= delta) {
188 				delta = llabs(cir - _cir);
189 				_man = m;
190 				_exp = e;
191 			}
192 		}
193 	}
194 	*man = _man;
195 	*exp = _exp;
196 }
197 
198 /**
199  * Calculate mantissa and exponent for xbs.
200  *
201  * @param[in] xbs
202  *   Value to be calculated.
203  * @param[out] man
204  *   Pointer to the mantissa.
205  * @param[out] exp
206  *   Pointer to the exp.
207  */
208 static void
209 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
210 {
211 	int _exp;
212 	double _man;
213 
214 	/* Special case xbs == 0 ? both exp and matissa are 0. */
215 	if (xbs == 0) {
216 		*man = 0;
217 		*exp = 0;
218 		return;
219 	}
220 	/* xbs = xbs_mantissa * 2^xbs_exponent */
221 	_man = frexp(xbs, &_exp);
222 	_man = _man * pow(2, MLX5_MAN_WIDTH);
223 	_exp = _exp - MLX5_MAN_WIDTH;
224 	*man = (uint8_t)ceil(_man);
225 	*exp = _exp;
226 }
227 
228 /**
229  * Fill the prm meter parameter.
230  *
231  * @param[in,out] fmp
232  *   Pointer to meter profie to be converted.
233  * @param[out] error
234  *   Pointer to the error structure.
235  *
236  * @return
237  *   0 on success, a negative errno value otherwise and rte_errno is set.
238  */
239 static int
240 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
241 			  struct rte_mtr_error *error)
242 {
243 	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
244 	uint8_t man, exp;
245 	uint32_t cbs_exp, cbs_man, cir_exp, cir_man;
246 	uint32_t ebs_exp, ebs_man;
247 
248 	if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
249 		return -rte_mtr_error_set(error, ENOTSUP,
250 				RTE_MTR_ERROR_TYPE_METER_PROFILE,
251 				NULL, "Metering algorithm not supported.");
252 	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
253 	mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir,
254 				    &man, &exp);
255 	/* Check if cir mantissa is too large. */
256 	if (exp > ASO_DSEG_CIR_EXP_MASK)
257 		return -rte_mtr_error_set(error, ENOTSUP,
258 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
259 					  "meter profile parameter cir is"
260 					  " not supported.");
261 	cir_man = man;
262 	cir_exp = exp;
263 	 /* cbs = cbs_mantissa * 2^cbs_exponent */
264 	mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs,
265 				    &man, &exp);
266 	/* Check if cbs mantissa is too large. */
267 	if (exp > ASO_DSEG_EXP_MASK)
268 		return -rte_mtr_error_set(error, ENOTSUP,
269 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
270 					  "meter profile parameter cbs is"
271 					  " not supported.");
272 	cbs_man = man;
273 	cbs_exp = exp;
274 	srtcm->cbs_cir = rte_cpu_to_be_32(cbs_exp << ASO_DSEG_CBS_EXP_OFFSET |
275 				cbs_man << ASO_DSEG_CBS_MAN_OFFSET |
276 				cir_exp << ASO_DSEG_CIR_EXP_OFFSET |
277 				cir_man);
278 	mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs,
279 				    &man, &exp);
280 	/* Check if ebs mantissa is too large. */
281 	if (exp > ASO_DSEG_EXP_MASK)
282 		return -rte_mtr_error_set(error, ENOTSUP,
283 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
284 					  "meter profile parameter ebs is"
285 					  " not supported.");
286 	ebs_man = man;
287 	ebs_exp = exp;
288 	srtcm->ebs_eir = rte_cpu_to_be_32(ebs_exp << ASO_DSEG_EBS_EXP_OFFSET |
289 					ebs_man << ASO_DSEG_EBS_MAN_OFFSET);
290 	return 0;
291 }
292 
293 /**
294  * Callback to get MTR capabilities.
295  *
296  * @param[in] dev
297  *   Pointer to Ethernet device.
298  * @param[out] cap
299  *   Pointer to save MTR capabilities.
300  * @param[out] error
301  *   Pointer to the error structure.
302  *
303  * @return
304  *   0 on success, a negative errno value otherwise and rte_errno is set.
305  */
306 static int
307 mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
308 		 struct rte_mtr_capabilities *cap,
309 		 struct rte_mtr_error *error __rte_unused)
310 {
311 	struct mlx5_priv *priv = dev->data->dev_private;
312 	struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
313 
314 	if (!priv->mtr_en)
315 		return -rte_mtr_error_set(error, ENOTSUP,
316 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
317 					  "Meter is not supported");
318 	memset(cap, 0, sizeof(*cap));
319 	if (priv->sh->meter_aso_en)
320 	    /* 2 meters per one ASO cache line. */
321 		cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
322 	else
323 		cap->n_max = 1 << qattr->log_max_flow_meter;
324 	cap->n_shared_max = cap->n_max;
325 	cap->identical = 1;
326 	cap->shared_identical = 1;
327 	cap->shared_n_flows_per_mtr_max = 4 << 20;
328 	/* 2M flows can share the same meter. */
329 	cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
330 	cap->meter_srtcm_rfc2697_n_max = qattr->flow_meter_old ? cap->n_max : 0;
331 	cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
332 	cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
333 			  RTE_MTR_STATS_N_PKTS_DROPPED;
334 	return 0;
335 }
336 
337 /**
338  * Callback to add MTR profile.
339  *
340  * @param[in] dev
341  *   Pointer to Ethernet device.
342  * @param[in] meter_profile_id
343  *   Meter profile id.
344  * @param[in] profile
345  *   Pointer to meter profile detail.
346  * @param[out] error
347  *   Pointer to the error structure.
348  *
349  * @return
350  *   0 on success, a negative errno value otherwise and rte_errno is set.
351  */
352 static int
353 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
354 		       uint32_t meter_profile_id,
355 		       struct rte_mtr_meter_profile *profile,
356 		       struct rte_mtr_error *error)
357 {
358 	struct mlx5_priv *priv = dev->data->dev_private;
359 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
360 	struct mlx5_flow_meter_profile *fmp;
361 	int ret;
362 
363 	if (!priv->mtr_en)
364 		return -rte_mtr_error_set(error, ENOTSUP,
365 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
366 					  "Meter is not supported");
367 	/* Check input params. */
368 	ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
369 					       profile, error);
370 	if (ret)
371 		return ret;
372 	/* Meter profile memory allocation. */
373 	fmp = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_flow_meter_profile),
374 			 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
375 	if (fmp == NULL)
376 		return -rte_mtr_error_set(error, ENOMEM,
377 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
378 					  NULL, "Meter profile memory "
379 					  "alloc failed.");
380 	/* Fill profile info. */
381 	fmp->id = meter_profile_id;
382 	fmp->profile = *profile;
383 	/* Fill the flow meter parameters for the PRM. */
384 	ret = mlx5_flow_meter_param_fill(fmp, error);
385 	if (ret)
386 		goto error;
387 	/* Add to list. */
388 	TAILQ_INSERT_TAIL(fmps, fmp, next);
389 	return 0;
390 error:
391 	mlx5_free(fmp);
392 	return ret;
393 }
394 
395 /**
396  * Callback to delete MTR profile.
397  *
398  * @param[in] dev
399  *   Pointer to Ethernet device.
400  * @param[in] meter_profile_id
401  *   Meter profile id.
402  * @param[out] error
403  *   Pointer to the error structure.
404  *
405  * @return
406  *   0 on success, a negative errno value otherwise and rte_errno is set.
407  */
408 static int
409 mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
410 			  uint32_t meter_profile_id,
411 			  struct rte_mtr_error *error)
412 {
413 	struct mlx5_priv *priv = dev->data->dev_private;
414 	struct mlx5_flow_meter_profile *fmp;
415 
416 	if (!priv->mtr_en)
417 		return -rte_mtr_error_set(error, ENOTSUP,
418 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
419 					  "Meter is not supported");
420 	/* Meter profile must exist. */
421 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
422 	if (fmp == NULL)
423 		return -rte_mtr_error_set(error, ENOENT,
424 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
425 					  &meter_profile_id,
426 					  "Meter profile id is invalid.");
427 	/* Check profile is unused. */
428 	if (fmp->ref_cnt)
429 		return -rte_mtr_error_set(error, EBUSY,
430 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
431 					  NULL, "Meter profile is in use.");
432 	/* Remove from list. */
433 	TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
434 	mlx5_free(fmp);
435 	return 0;
436 }
437 
438 /**
439  * Modify the flow meter action.
440  *
441  * @param[in] priv
442  *   Pointer to mlx5 private data structure.
443  * @param[in] fm
444  *   Pointer to flow meter to be modified.
445  * @param[in] srtcm
446  *   Pointer to meter srtcm description parameter.
447  * @param[in] modify_bits
448  *   The bit in srtcm to be updated.
449  * @param[in] active_state
450  *   The state to be updated.
451  * @return
452  *   0 on success, o negative value otherwise.
453  */
454 static int
455 mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
456 		struct mlx5_flow_meter_info *fm,
457 		const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
458 		uint64_t modify_bits, uint32_t active_state, uint32_t is_enable)
459 {
460 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
461 	uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
462 	uint32_t *attr;
463 	struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
464 	int ret;
465 	struct mlx5_aso_mtr *aso_mtr = NULL;
466 	uint32_t cbs_cir, ebs_eir, val;
467 
468 	if (priv->sh->meter_aso_en) {
469 		fm->is_enable = !!is_enable;
470 		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
471 		ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
472 		if (ret)
473 			return ret;
474 		ret = mlx5_aso_mtr_wait(priv->sh, aso_mtr);
475 		if (ret)
476 			return ret;
477 	} else {
478 		/* Fill command parameters. */
479 		mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
480 		mod_attr.flow_meter_parameter = in;
481 		mod_attr.flow_meter_parameter_sz =
482 				MLX5_ST_SZ_BYTES(flow_meter_parameters);
483 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
484 			mod_attr.active = !!active_state;
485 		else
486 			mod_attr.active = 0;
487 		attr = in;
488 		cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
489 		ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
490 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
491 			val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) &
492 				ASO_DSEG_EXP_MASK;
493 			MLX5_SET(flow_meter_parameters, attr,
494 				cbs_exponent, val);
495 			val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) &
496 				ASO_DSEG_MAN_MASK;
497 			MLX5_SET(flow_meter_parameters, attr,
498 				cbs_mantissa, val);
499 		}
500 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
501 			val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) &
502 				ASO_DSEG_EXP_MASK;
503 			MLX5_SET(flow_meter_parameters, attr,
504 				cir_exponent, val);
505 			val = cbs_cir & ASO_DSEG_MAN_MASK;
506 			MLX5_SET(flow_meter_parameters, attr,
507 				cir_mantissa, val);
508 		}
509 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
510 			val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) &
511 				ASO_DSEG_EXP_MASK;
512 			MLX5_SET(flow_meter_parameters, attr,
513 				ebs_exponent, val);
514 			val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) &
515 				ASO_DSEG_MAN_MASK;
516 			MLX5_SET(flow_meter_parameters, attr,
517 				ebs_mantissa, val);
518 		}
519 		/* Apply modifications to meter only if it was created. */
520 		if (fm->meter_action) {
521 			ret = mlx5_glue->dv_modify_flow_action_meter
522 					(fm->meter_action, &mod_attr,
523 					rte_cpu_to_be_64(modify_bits));
524 			if (ret)
525 				return ret;
526 		}
527 		/* Update succeedded modify meter parameters. */
528 		if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
529 			fm->active_state = !!active_state;
530 	}
531 	return 0;
532 #else
533 	(void)priv;
534 	(void)fm;
535 	(void)srtcm;
536 	(void)modify_bits;
537 	(void)active_state;
538 	(void)is_enable;
539 	return -ENOTSUP;
540 #endif
541 }
542 
543 static void
544 mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
545 				uint64_t stats_mask)
546 {
547 	fm->bytes_dropped =
548 		(stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
549 	fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
550 }
551 
552 static int
553 mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
554 			struct mlx5_flow_meter_info *fm,
555 			uint32_t mtr_idx)
556 {
557 	struct mlx5_priv *priv = dev->data->dev_private;
558 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
559 	struct mlx5_flow_meter_profile *fmp;
560 	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
561 
562 	/* Meter object must not have any owner. */
563 	MLX5_ASSERT(!fm->ref_cnt);
564 	/* Get meter profile. */
565 	fmp = fm->profile;
566 	if (fmp == NULL)
567 		return -1;
568 	/* Update dependencies. */
569 	__atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
570 	/* Remove from list. */
571 	if (!priv->sh->meter_aso_en) {
572 		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
573 		TAILQ_REMOVE(fms, legacy_fm, next);
574 	}
575 	/* Free drop counters. */
576 	if (fm->drop_cnt)
577 		mlx5_counter_free(dev, fm->drop_cnt);
578 	/* Free meter flow table. */
579 	if (fm->flow_ipool)
580 		mlx5_ipool_destroy(fm->flow_ipool);
581 	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
582 	if (priv->sh->meter_aso_en)
583 		mlx5_flow_mtr_free(dev, mtr_idx);
584 	else
585 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
586 					legacy_fm->idx);
587 	return 0;
588 }
589 
590 /**
591  * Destroy meter rules.
592  *
593  * @param[in] dev
594  *   Pointer to Ethernet device.
595  * @param[in] meter_id
596  *   Meter id.
597  * @param[out] error
598  *   Pointer to rte meter error structure.
599  *
600  * @return
601  *   0 on success, a negative errno value otherwise and rte_errno is set.
602  */
603 static int
604 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
605 			struct rte_mtr_error *error)
606 {
607 	struct mlx5_priv *priv = dev->data->dev_private;
608 	struct mlx5_flow_meter_info *fm;
609 	uint32_t mtr_idx = 0;
610 
611 	if (!priv->mtr_en)
612 		return -rte_mtr_error_set(error, ENOTSUP,
613 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
614 					  "Meter is not supported");
615 	/* Meter object must exist. */
616 	fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
617 	if (fm == NULL)
618 		return -rte_mtr_error_set(error, ENOENT,
619 					  RTE_MTR_ERROR_TYPE_MTR_ID,
620 					  NULL, "Meter object id not valid.");
621 	/* Meter object must not have any owner. */
622 	if (fm->ref_cnt > 0)
623 		return -rte_mtr_error_set(error, EBUSY,
624 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
625 					  NULL, "Meter object is being used.");
626 	if (priv->sh->meter_aso_en) {
627 		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id))
628 			return -rte_mtr_error_set(error, EBUSY,
629 				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
630 				"Fail to delete ASO Meter in index table.");
631 	}
632 	/* Destroy the meter profile. */
633 	if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
634 		return -rte_mtr_error_set(error, EINVAL,
635 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
636 					NULL, "MTR object meter profile invalid.");
637 	return 0;
638 }
639 
640 /**
641  * Modify meter state.
642  *
643  * @param[in] priv
644  *   Pointer to mlx5 private data structure.
645  * @param[in] fm
646  *   Pointer to flow meter.
647  * @param[in] new_state
648  *   New state to update.
649  * @param[out] error
650  *   Pointer to rte meter error structure.
651  *
652  * @return
653  *   0 on success, a negative errno value otherwise and rte_errno is set.
654  */
655 static int
656 mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
657 			     struct mlx5_flow_meter_info *fm,
658 			     uint32_t new_state,
659 			     struct rte_mtr_error *error)
660 {
661 	static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
662 		.cbs_cir = RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL),
663 		.ebs_eir = 0,
664 	};
665 	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
666 			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
667 	int ret;
668 
669 	if (new_state == MLX5_FLOW_METER_DISABLE)
670 		ret = mlx5_flow_meter_action_modify(priv, fm,
671 				&srtcm, modify_bits, 0, 0);
672 	else
673 		ret = mlx5_flow_meter_action_modify(priv, fm,
674 						   &fm->profile->srtcm_prm,
675 						    modify_bits, 0, 1);
676 	if (ret)
677 		return -rte_mtr_error_set(error, -ret,
678 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
679 					  NULL,
680 					  new_state ?
681 					  "Failed to enable meter." :
682 					  "Failed to disable meter.");
683 	return 0;
684 }
685 
686 /**
687  * Callback to enable flow meter.
688  *
689  * @param[in] dev
690  *   Pointer to Ethernet device.
691  * @param[in] meter_id
692  *   Meter id.
693  * @param[out] error
694  *   Pointer to rte meter error structure.
695  *
696  * @return
697  *   0 on success, a negative errno value otherwise and rte_errno is set.
698  */
699 static int
700 mlx5_flow_meter_enable(struct rte_eth_dev *dev,
701 		       uint32_t meter_id,
702 		       struct rte_mtr_error *error)
703 {
704 	struct mlx5_priv *priv = dev->data->dev_private;
705 	struct mlx5_flow_meter_info *fm;
706 	int ret;
707 
708 	if (!priv->mtr_en)
709 		return -rte_mtr_error_set(error, ENOTSUP,
710 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
711 					  "Meter is not supported");
712 	/* Meter object must exist. */
713 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
714 	if (fm == NULL)
715 		return -rte_mtr_error_set(error, ENOENT,
716 					  RTE_MTR_ERROR_TYPE_MTR_ID,
717 					  NULL, "Meter not found.");
718 	if (fm->active_state == MLX5_FLOW_METER_ENABLE)
719 		return 0;
720 	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
721 					   error);
722 	if (!ret)
723 		fm->active_state = MLX5_FLOW_METER_ENABLE;
724 	return ret;
725 }
726 
727 /**
728  * Callback to disable flow meter.
729  *
730  * @param[in] dev
731  *   Pointer to Ethernet device.
732  * @param[in] meter_id
733  *   Meter id.
734  * @param[out] error
735  *   Pointer to rte meter error structure.
736  *
737  * @return
738  *   0 on success, a negative errno value otherwise and rte_errno is set.
739  */
740 static int
741 mlx5_flow_meter_disable(struct rte_eth_dev *dev,
742 			uint32_t meter_id,
743 			struct rte_mtr_error *error)
744 {
745 	struct mlx5_priv *priv = dev->data->dev_private;
746 	struct mlx5_flow_meter_info *fm;
747 	int ret;
748 
749 	if (!priv->mtr_en)
750 		return -rte_mtr_error_set(error, ENOTSUP,
751 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
752 					  "Meter is not supported");
753 	/* Meter object must exist. */
754 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
755 	if (fm == NULL)
756 		return -rte_mtr_error_set(error, ENOENT,
757 					  RTE_MTR_ERROR_TYPE_MTR_ID,
758 					  NULL, "Meter not found.");
759 	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
760 		return 0;
761 	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
762 					   error);
763 	if (!ret)
764 		fm->active_state = MLX5_FLOW_METER_DISABLE;
765 	return ret;
766 }
767 
768 /**
769  * Callback to update meter profile.
770  *
771  * @param[in] dev
772  *   Pointer to Ethernet device.
773  * @param[in] meter_id
774  *   Meter id.
775  * @param[in] meter_profile_id
776  *   To be updated meter profile id.
777  * @param[out] error
778  *   Pointer to rte meter error structure.
779  *
780  * @return
781  *   0 on success, a negative errno value otherwise and rte_errno is set.
782  */
783 static int
784 mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
785 			       uint32_t meter_id,
786 			       uint32_t meter_profile_id,
787 			       struct rte_mtr_error *error)
788 {
789 	struct mlx5_priv *priv = dev->data->dev_private;
790 	struct mlx5_flow_meter_profile *fmp;
791 	struct mlx5_flow_meter_profile *old_fmp;
792 	struct mlx5_flow_meter_info *fm;
793 	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
794 			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
795 	int ret;
796 
797 	if (!priv->mtr_en)
798 		return -rte_mtr_error_set(error, ENOTSUP,
799 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
800 					  "Meter is not supported");
801 	/* Meter profile must exist. */
802 	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
803 	if (fmp == NULL)
804 		return -rte_mtr_error_set(error, ENOENT,
805 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
806 					  NULL, "Meter profile not found.");
807 	/* Meter object must exist. */
808 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
809 	if (fm == NULL)
810 		return -rte_mtr_error_set(error, ENOENT,
811 					  RTE_MTR_ERROR_TYPE_MTR_ID,
812 					  NULL, "Meter not found.");
813 	/* MTR object already set to meter profile id. */
814 	old_fmp = fm->profile;
815 	if (fmp == old_fmp)
816 		return 0;
817 	/* Update the profile. */
818 	fm->profile = fmp;
819 	/* Update meter params in HW (if not disabled). */
820 	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
821 		return 0;
822 	ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
823 					      modify_bits, fm->active_state, 1);
824 	if (ret) {
825 		fm->profile = old_fmp;
826 		return -rte_mtr_error_set(error, -ret,
827 					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
828 					  NULL, "Failed to update meter"
829 					  " parmeters in hardware.");
830 	}
831 	old_fmp->ref_cnt--;
832 	fmp->ref_cnt++;
833 	return 0;
834 }
835 
836 /**
837  * Callback to update meter stats mask.
838  *
839  * @param[in] dev
840  *   Pointer to Ethernet device.
841  * @param[in] meter_id
842  *   Meter id.
843  * @param[in] stats_mask
844  *   To be updated stats_mask.
845  * @param[out] error
846  *   Pointer to rte meter error structure.
847  *
848  * @return
849  *   0 on success, a negative errno value otherwise and rte_errno is set.
850  */
851 static int
852 mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
853 			     uint32_t meter_id,
854 			     uint64_t stats_mask,
855 			     struct rte_mtr_error *error)
856 {
857 	struct mlx5_priv *priv = dev->data->dev_private;
858 	struct mlx5_flow_meter_info *fm;
859 
860 	if (!priv->mtr_en)
861 		return -rte_mtr_error_set(error, ENOTSUP,
862 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
863 					  "Meter is not supported");
864 	/* Meter object must exist. */
865 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
866 	if (fm == NULL)
867 		return -rte_mtr_error_set(error, ENOENT,
868 					  RTE_MTR_ERROR_TYPE_MTR_ID,
869 					  NULL, "Meter object id not valid.");
870 	mlx5_flow_meter_stats_enable_update(fm, stats_mask);
871 	return 0;
872 }
873 
874 /**
875  * Callback to read meter statistics.
876  *
877  * @param[in] dev
878  *   Pointer to Ethernet device.
879  * @param[in] meter_id
880  *   Meter id.
881  * @param[out] stats
882  *   Pointer to store the statistics.
883  * @param[out] stats_mask
884  *   Pointer to store the stats_mask.
885  * @param[in] clear
886  *   Statistic to be cleared after read or not.
887  * @param[out] error
888  *   Pointer to rte meter error structure.
889  *
890  * @return
891  *   0 on success, a negative errno value otherwise and rte_errno is set.
892  */
893 static int
894 mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
895 			   uint32_t meter_id,
896 			   struct rte_mtr_stats *stats,
897 			   uint64_t *stats_mask,
898 			   int clear,
899 			   struct rte_mtr_error *error)
900 {
901 	struct mlx5_priv *priv = dev->data->dev_private;
902 	struct mlx5_flow_meter_info *fm;
903 	uint64_t pkts;
904 	uint64_t bytes;
905 	int ret = 0;
906 
907 	if (!priv->mtr_en)
908 		return -rte_mtr_error_set(error, ENOTSUP,
909 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
910 					  "Meter is not supported");
911 	/* Meter object must exist. */
912 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
913 	if (fm == NULL)
914 		return -rte_mtr_error_set(error, ENOENT,
915 					  RTE_MTR_ERROR_TYPE_MTR_ID,
916 					  NULL, "Meter object id not valid.");
917 	*stats_mask = 0;
918 	if (fm->bytes_dropped)
919 		*stats_mask |= RTE_MTR_STATS_N_BYTES_DROPPED;
920 	if (fm->pkts_dropped)
921 		*stats_mask |= RTE_MTR_STATS_N_PKTS_DROPPED;
922 	memset(stats, 0, sizeof(*stats));
923 	if (fm->drop_cnt) {
924 		ret = mlx5_counter_query(dev, fm->drop_cnt, clear, &pkts,
925 						 &bytes);
926 		if (ret)
927 			goto error;
928 		/* If need to read the packets, set it. */
929 		if (fm->pkts_dropped)
930 			stats->n_pkts_dropped = pkts;
931 		/* If need to read the bytes, set it. */
932 		if (fm->bytes_dropped)
933 			stats->n_bytes_dropped = bytes;
934 	}
935 	return 0;
936 error:
937 	return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
938 				 "Failed to read meter drop counters.");
939 }
940 
941 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
942 	.capabilities_get = mlx5_flow_mtr_cap_get,
943 	.meter_profile_add = mlx5_flow_meter_profile_add,
944 	.meter_profile_delete = mlx5_flow_meter_profile_delete,
945 	.destroy = mlx5_flow_meter_destroy,
946 	.meter_enable = mlx5_flow_meter_enable,
947 	.meter_disable = mlx5_flow_meter_disable,
948 	.meter_profile_update = mlx5_flow_meter_profile_update,
949 	.meter_dscp_table_update = NULL,
950 	.stats_update = mlx5_flow_meter_stats_update,
951 	.stats_read = mlx5_flow_meter_stats_read,
952 };
953 
954 /**
955  * Get meter operations.
956  *
957  * @param dev
958  *   Pointer to Ethernet device structure.
959  * @param arg
960  *   Pointer to set the mtr operations.
961  *
962  * @return
963  *   Always 0.
964  */
965 int
966 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
967 {
968 	*(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
969 	return 0;
970 }
971 
972 /**
973  * Find meter by id.
974  *
975  * @param priv
976  *   Pointer to mlx5_priv.
977  * @param meter_id
978  *   Meter id.
979  * @param mtr_idx
980  *   Pointer to Meter index.
981  *
982  * @return
983  *   Pointer to the profile found on success, NULL otherwise.
984  */
985 struct mlx5_flow_meter_info *
986 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
987 		uint32_t *mtr_idx)
988 {
989 	struct mlx5_legacy_flow_meter *legacy_fm;
990 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
991 	struct mlx5_aso_mtr *aso_mtr;
992 	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
993 	union mlx5_l3t_data data;
994 
995 	if (priv->sh->meter_aso_en) {
996 		rte_spinlock_lock(&mtrmng->mtrsl);
997 		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
998 			!data.dword) {
999 			rte_spinlock_unlock(&mtrmng->mtrsl);
1000 			return NULL;
1001 		}
1002 		if (mtr_idx)
1003 			*mtr_idx = data.dword;
1004 		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
1005 		/* Remove reference taken by the mlx5_l3t_get_entry. */
1006 		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
1007 		rte_spinlock_unlock(&mtrmng->mtrsl);
1008 		return &aso_mtr->fm;
1009 	}
1010 	TAILQ_FOREACH(legacy_fm, fms, next)
1011 		if (meter_id == legacy_fm->meter_id) {
1012 			if (mtr_idx)
1013 				*mtr_idx = legacy_fm->idx;
1014 			return &legacy_fm->fm;
1015 		}
1016 	return NULL;
1017 }
1018 
1019 /**
1020  * Find meter by index.
1021  *
1022  * @param priv
1023  *   Pointer to mlx5_priv.
1024  * @param idx
1025  *   Meter index.
1026  *
1027  * @return
1028  *   Pointer to the profile found on success, NULL otherwise.
1029  */
1030 struct mlx5_flow_meter_info *
1031 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
1032 {
1033 	struct mlx5_aso_mtr *aso_mtr;
1034 
1035 	if (priv->sh->meter_aso_en) {
1036 		aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
1037 		return &aso_mtr->fm;
1038 	} else {
1039 		return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
1040 	}
1041 }
1042 
1043 /**
1044  * Attach meter to flow.
1045  * Unidirectional Meter creation can only be done
1046  * when flow direction is known, i.e. when calling meter_attach.
1047  *
1048  * @param [in] priv
1049  *  Pointer to mlx5 private data.
1050  * @param[in] fm
1051  *   Pointer to flow meter.
1052  * @param [in] attr
1053  *  Pointer to flow attributes.
1054  * @param [out] error
1055  *  Pointer to error structure.
1056  *
1057  * @return
1058  *   0 on success, a negative errno value otherwise and rte_errno is set.
1059  */
1060 int
1061 mlx5_flow_meter_attach(struct mlx5_priv *priv,
1062 		       struct mlx5_flow_meter_info *fm,
1063 		       const struct rte_flow_attr *attr,
1064 		       struct rte_flow_error *error)
1065 {
1066 	int ret = 0;
1067 
1068 	if (priv->sh->meter_aso_en) {
1069 		struct mlx5_aso_mtr *aso_mtr;
1070 
1071 		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
1072 		if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) {
1073 			return rte_flow_error_set(error, ENOENT,
1074 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1075 					NULL,
1076 					"Timeout in meter configuration");
1077 		}
1078 		rte_spinlock_lock(&fm->sl);
1079 		if (fm->shared || !fm->ref_cnt) {
1080 			fm->ref_cnt++;
1081 		} else {
1082 			rte_flow_error_set(error, EINVAL,
1083 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1084 				   "Meter cannot be shared");
1085 			ret = -1;
1086 		}
1087 		rte_spinlock_unlock(&fm->sl);
1088 	} else {
1089 		rte_spinlock_lock(&fm->sl);
1090 		if (fm->meter_action) {
1091 			if (fm->shared &&
1092 			    attr->transfer == fm->transfer &&
1093 			    attr->ingress == fm->ingress &&
1094 			    attr->egress == fm->egress) {
1095 				fm->ref_cnt++;
1096 			} else {
1097 				rte_flow_error_set(error, EINVAL,
1098 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1099 					fm->shared ?
1100 					"Meter attr not match." :
1101 					"Meter cannot be shared.");
1102 				ret = -1;
1103 			}
1104 		} else {
1105 			fm->ingress = attr->ingress;
1106 			fm->egress = attr->egress;
1107 			fm->transfer = attr->transfer;
1108 			fm->ref_cnt = 1;
1109 			/* This also creates the meter object. */
1110 			fm->meter_action = mlx5_flow_meter_action_create(priv,
1111 									 fm);
1112 			if (!fm->meter_action) {
1113 				fm->ref_cnt = 0;
1114 				fm->ingress = 0;
1115 				fm->egress = 0;
1116 				fm->transfer = 0;
1117 				rte_flow_error_set(error, EINVAL,
1118 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1119 					"Meter action create failed.");
1120 				ret = -1;
1121 			}
1122 		}
1123 		rte_spinlock_unlock(&fm->sl);
1124 	}
1125 	return ret ? -rte_errno : 0;
1126 }
1127 
1128 /**
1129  * Detach meter from flow.
1130  *
1131  * @param [in] priv
1132  *  Pointer to mlx5 private data.
1133  * @param [in] fm
1134  *  Pointer to flow meter.
1135  */
1136 void
1137 mlx5_flow_meter_detach(struct mlx5_priv *priv,
1138 		       struct mlx5_flow_meter_info *fm)
1139 {
1140 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
1141 	rte_spinlock_lock(&fm->sl);
1142 	MLX5_ASSERT(fm->ref_cnt);
1143 	if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) {
1144 		mlx5_glue->destroy_flow_action(fm->meter_action);
1145 		fm->meter_action = NULL;
1146 		fm->ingress = 0;
1147 		fm->egress = 0;
1148 		fm->transfer = 0;
1149 	}
1150 	rte_spinlock_unlock(&fm->sl);
1151 #else
1152 	(void)priv;
1153 	(void)fm;
1154 #endif
1155 }
1156 
1157 /**
1158  * Flush meter configuration.
1159  *
1160  * @param[in] dev
1161  *   Pointer to Ethernet device.
1162  * @param[out] error
1163  *   Pointer to rte meter error structure.
1164  *
1165  * @return
1166  *   0 on success, a negative errno value otherwise and rte_errno is set.
1167  */
1168 int
1169 mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
1170 {
1171 	struct mlx5_priv *priv = dev->data->dev_private;
1172 	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
1173 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1174 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
1175 	struct mlx5_flow_meter_profile *fmp;
1176 	struct mlx5_legacy_flow_meter *legacy_fm;
1177 	struct mlx5_flow_meter_info *fm;
1178 	struct mlx5_aso_mtr_pool *mtr_pool;
1179 	void *tmp;
1180 	uint32_t i, offset, mtr_idx;
1181 
1182 	if (priv->sh->meter_aso_en) {
1183 		i = mtrmng->n_valid;
1184 		while (i--) {
1185 			mtr_pool = mtrmng->pools[i];
1186 			for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
1187 				offset++) {
1188 				fm = &mtr_pool->mtrs[offset].fm;
1189 				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
1190 				if (mlx5_flow_meter_params_flush(dev,
1191 						fm, mtr_idx))
1192 					return -rte_mtr_error_set
1193 					(error, EINVAL,
1194 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1195 					NULL, "MTR object meter profile invalid.");
1196 			}
1197 		}
1198 	} else {
1199 		TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
1200 			fm = &legacy_fm->fm;
1201 			if (mlx5_flow_meter_params_flush(dev, fm, 0))
1202 				return -rte_mtr_error_set(error, EINVAL,
1203 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1204 					NULL, "MTR object meter profile invalid.");
1205 		}
1206 	}
1207 	TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
1208 		/* Check unused. */
1209 		MLX5_ASSERT(!fmp->ref_cnt);
1210 		/* Remove from list. */
1211 		TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
1212 		mlx5_free(fmp);
1213 	}
1214 	return 0;
1215 }
1216