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