af0a1c18cb16cfe778379068b64848220ddca284
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_meter.c
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 }