c4d28b282ed62e766194b0d9a52a01ca15af7b24
[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.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 }