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