net/mlx5: fix meter policy ID table container
[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         enum mlx5_meter_domain domain =
42                 fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
43                         fm->egress ? MLX5_MTR_DOMAIN_EGRESS :
44                                 MLX5_MTR_DOMAIN_INGRESS;
45         struct mlx5_flow_meter_def_policy *def_policy =
46                 priv->sh->mtrmng->def_policy[domain];
47
48         memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
49         MLX5_SET(flow_meter_parameters, fmp, valid, 1);
50         MLX5_SET(flow_meter_parameters, fmp, bucket_overflow, 1);
51         MLX5_SET(flow_meter_parameters, fmp,
52                 start_color, MLX5_FLOW_COLOR_GREEN);
53         MLX5_SET(flow_meter_parameters, fmp, both_buckets_on_green, 0);
54         val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
55         MLX5_SET(flow_meter_parameters, fmp, cbs_exponent, val);
56         val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
57         MLX5_SET(flow_meter_parameters, fmp, cbs_mantissa, val);
58         val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
59         MLX5_SET(flow_meter_parameters, fmp, cir_exponent, val);
60         val = (cbs_cir & ASO_DSEG_MAN_MASK);
61         MLX5_SET(flow_meter_parameters, fmp, cir_mantissa, val);
62         val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
63         MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
64         val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
65         MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
66         mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj;
67         mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
68         mtr_init.flow_meter_parameter = fmp;
69         mtr_init.flow_meter_parameter_sz =
70                 MLX5_ST_SZ_BYTES(flow_meter_parameters);
71         mtr_init.active = fm->active_state;
72         return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
73 #else
74         (void)priv;
75         (void)fm;
76         return NULL;
77 #endif
78 }
79
80 /**
81  * Find meter profile by id.
82  *
83  * @param priv
84  *   Pointer to mlx5_priv.
85  * @param meter_profile_id
86  *   Meter profile id.
87  *
88  * @return
89  *   Pointer to the profile found on success, NULL otherwise.
90  */
91 static struct mlx5_flow_meter_profile *
92 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
93 {
94         struct mlx5_flow_meter_profile *fmp;
95         union mlx5_l3t_data data;
96         int32_t ret;
97
98         if (mlx5_l3t_get_entry(priv->mtr_profile_tbl,
99                                meter_profile_id, &data) || !data.ptr)
100                 return NULL;
101         fmp = data.ptr;
102         /* Remove reference taken by the mlx5_l3t_get_entry. */
103         ret = mlx5_l3t_clear_entry(priv->mtr_profile_tbl,
104                                    meter_profile_id);
105         if (!ret || ret == -1)
106                 return NULL;
107         return fmp;
108 }
109
110 /**
111  * Validate the MTR profile.
112  *
113  * @param[in] dev
114  *   Pointer to Ethernet device.
115  * @param[in] meter_profile_id
116  *   Meter profile id.
117  * @param[in] profile
118  *   Pointer to meter profile detail.
119  * @param[out] error
120  *   Pointer to the error structure.
121  *
122  * @return
123  *   0 on success, a negative errno value otherwise and rte_errno is set.
124  */
125 static int
126 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
127                                  uint32_t meter_profile_id,
128                                  struct rte_mtr_meter_profile *profile,
129                                  struct rte_mtr_error *error)
130 {
131         struct mlx5_priv *priv = dev->data->dev_private;
132         struct mlx5_flow_meter_profile *fmp;
133
134         /* Profile must not be NULL. */
135         if (profile == NULL)
136                 return -rte_mtr_error_set(error, EINVAL,
137                                           RTE_MTR_ERROR_TYPE_METER_PROFILE,
138                                           NULL, "Meter profile is null.");
139         /* Meter profile ID must be valid. */
140         if (meter_profile_id == UINT32_MAX)
141                 return -rte_mtr_error_set(error, EINVAL,
142                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
143                                           NULL, "Meter profile id not valid.");
144         /* Meter profile must not exist. */
145         fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
146         if (fmp)
147                 return -rte_mtr_error_set(error, EEXIST,
148                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
149                                           NULL,
150                                           "Meter profile already exists.");
151         if (profile->alg == RTE_MTR_SRTCM_RFC2697) {
152                 if (priv->config.hca_attr.qos.flow_meter_old) {
153                         /* Verify support for flow meter parameters. */
154                         if (priv->sh->meter_aso_en && profile->packet_mode) {
155                                 if (profile->srtcm_rfc2697.cir > 0 &&
156                                         (profile->srtcm_rfc2697.cir <<
157                                         MLX5_MTRS_PPS_MAP_BPS_SHIFT)
158                                         <= MLX5_SRTCM_CIR_MAX &&
159                                         profile->srtcm_rfc2697.cbs > 0 &&
160                                         (profile->srtcm_rfc2697.cbs <<
161                                         MLX5_MTRS_PPS_MAP_BPS_SHIFT)
162                                         <= MLX5_SRTCM_CBS_MAX &&
163                                         (profile->srtcm_rfc2697.ebs <<
164                                         MLX5_MTRS_PPS_MAP_BPS_SHIFT)
165                                         <= MLX5_SRTCM_EBS_MAX)
166                                         return 0;
167                                 return -rte_mtr_error_set
168                                              (error, ENOTSUP,
169                                               RTE_MTR_ERROR_TYPE_MTR_PARAMS,
170                                               NULL,
171                                               profile->srtcm_rfc2697.ebs ?
172                                               "Metering value ebs must be 0." :
173                                               "Invalid metering parameters.");
174                         }
175                         if (profile->srtcm_rfc2697.cir > 0 &&
176                                 profile->srtcm_rfc2697.cir <=
177                                                 MLX5_SRTCM_CIR_MAX &&
178                                 profile->srtcm_rfc2697.cbs > 0 &&
179                                 profile->srtcm_rfc2697.cbs <=
180                                                 MLX5_SRTCM_CBS_MAX &&
181                                 profile->srtcm_rfc2697.ebs <=
182                                                 MLX5_SRTCM_EBS_MAX)
183                                 return 0;
184                         return -rte_mtr_error_set(error, ENOTSUP,
185                                         RTE_MTR_ERROR_TYPE_MTR_PARAMS,
186                                         NULL,
187                                         profile->srtcm_rfc2697.ebs ?
188                                         "Metering value ebs must be 0." :
189                                         "Invalid metering parameters.");
190                 }
191         }
192         return -rte_mtr_error_set(error, ENOTSUP,
193                                   RTE_MTR_ERROR_TYPE_METER_PROFILE,
194                                   NULL, "Metering algorithm not supported.");
195 }
196
197 /**
198  * Calculate mantissa and exponent for cir.
199  *
200  * @param[in] cir
201  *   Value to be calculated.
202  * @param[out] man
203  *   Pointer to the mantissa.
204  * @param[out] exp
205  *   Pointer to the exp.
206  */
207 static void
208 mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp)
209 {
210         int64_t _cir;
211         int64_t delta = INT64_MAX;
212         uint8_t _man = 0;
213         uint8_t _exp = 0;
214         uint64_t m, e;
215
216         for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
217                 for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
218                         _cir = (1000000000ULL * m) >> e;
219                         if (llabs(cir - _cir) <= delta) {
220                                 delta = llabs(cir - _cir);
221                                 _man = m;
222                                 _exp = e;
223                         }
224                 }
225         }
226         *man = _man;
227         *exp = _exp;
228 }
229
230 /**
231  * Calculate mantissa and exponent for xbs.
232  *
233  * @param[in] xbs
234  *   Value to be calculated.
235  * @param[out] man
236  *   Pointer to the mantissa.
237  * @param[out] exp
238  *   Pointer to the exp.
239  */
240 static void
241 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
242 {
243         int _exp;
244         double _man;
245
246         /* Special case xbs == 0 ? both exp and matissa are 0. */
247         if (xbs == 0) {
248                 *man = 0;
249                 *exp = 0;
250                 return;
251         }
252         /* xbs = xbs_mantissa * 2^xbs_exponent */
253         _man = frexp(xbs, &_exp);
254         _man = _man * pow(2, MLX5_MAN_WIDTH);
255         _exp = _exp - MLX5_MAN_WIDTH;
256         *man = (uint8_t)ceil(_man);
257         *exp = _exp;
258 }
259
260 /**
261  * Fill the prm meter parameter.
262  *
263  * @param[in,out] fmp
264  *   Pointer to meter profie to be converted.
265  * @param[out] error
266  *   Pointer to the error structure.
267  *
268  * @return
269  *   0 on success, a negative errno value otherwise and rte_errno is set.
270  */
271 static int
272 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
273                         struct mlx5_priv *priv, struct rte_mtr_error *error)
274 {
275         struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
276         uint8_t man, exp;
277         uint32_t cbs_exp, cbs_man, cir_exp, cir_man;
278         uint32_t ebs_exp, ebs_man;
279         uint64_t cir, cbs, ebs;
280
281         if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
282                 return -rte_mtr_error_set(error, ENOTSUP,
283                                 RTE_MTR_ERROR_TYPE_METER_PROFILE,
284                                 NULL, "Metering algorithm not supported.");
285         if (!priv->sh->meter_aso_en && fmp->profile.packet_mode)
286                 return -rte_mtr_error_set(error, ENOTSUP,
287                         RTE_MTR_ERROR_TYPE_METER_PROFILE,
288                         NULL, "Metering algorithm packet mode not supported.");
289         if (priv->sh->meter_aso_en && fmp->profile.packet_mode) {
290                 cir = fmp->profile.srtcm_rfc2697.cir <<
291                                 MLX5_MTRS_PPS_MAP_BPS_SHIFT;
292                 cbs = fmp->profile.srtcm_rfc2697.cbs <<
293                                 MLX5_MTRS_PPS_MAP_BPS_SHIFT;
294                 ebs = fmp->profile.srtcm_rfc2697.ebs <<
295                                 MLX5_MTRS_PPS_MAP_BPS_SHIFT;
296         } else {
297                 cir = fmp->profile.srtcm_rfc2697.cir;
298                 cbs = fmp->profile.srtcm_rfc2697.cbs;
299                 ebs = fmp->profile.srtcm_rfc2697.ebs;
300         }
301         /* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
302         mlx5_flow_meter_cir_man_exp_calc(cir, &man, &exp);
303         /* Check if cir mantissa is too large. */
304         if (exp > ASO_DSEG_CIR_EXP_MASK)
305                 return -rte_mtr_error_set(error, ENOTSUP,
306                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
307                                           "meter profile parameter cir is"
308                                           " not supported.");
309         cir_man = man;
310         cir_exp = exp;
311          /* cbs = cbs_mantissa * 2^cbs_exponent */
312         mlx5_flow_meter_xbs_man_exp_calc(cbs, &man, &exp);
313         /* Check if cbs mantissa is too large. */
314         if (exp > ASO_DSEG_EXP_MASK)
315                 return -rte_mtr_error_set(error, ENOTSUP,
316                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
317                                           "meter profile parameter cbs is"
318                                           " not supported.");
319         cbs_man = man;
320         cbs_exp = exp;
321         srtcm->cbs_cir = rte_cpu_to_be_32(cbs_exp << ASO_DSEG_CBS_EXP_OFFSET |
322                                 cbs_man << ASO_DSEG_CBS_MAN_OFFSET |
323                                 cir_exp << ASO_DSEG_CIR_EXP_OFFSET |
324                                 cir_man);
325         mlx5_flow_meter_xbs_man_exp_calc(ebs, &man, &exp);
326         /* Check if ebs mantissa is too large. */
327         if (exp > ASO_DSEG_EXP_MASK)
328                 return -rte_mtr_error_set(error, ENOTSUP,
329                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
330                                           "meter profile parameter ebs is"
331                                           " not supported.");
332         ebs_man = man;
333         ebs_exp = exp;
334         srtcm->ebs_eir = rte_cpu_to_be_32(ebs_exp << ASO_DSEG_EBS_EXP_OFFSET |
335                                         ebs_man << ASO_DSEG_EBS_MAN_OFFSET);
336         return 0;
337 }
338
339 /**
340  * Callback to get MTR capabilities.
341  *
342  * @param[in] dev
343  *   Pointer to Ethernet device.
344  * @param[out] cap
345  *   Pointer to save MTR capabilities.
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_mtr_cap_get(struct rte_eth_dev *dev,
354                  struct rte_mtr_capabilities *cap,
355                  struct rte_mtr_error *error __rte_unused)
356 {
357         struct mlx5_priv *priv = dev->data->dev_private;
358         struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
359
360         if (!priv->mtr_en)
361                 return -rte_mtr_error_set(error, ENOTSUP,
362                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
363                                           "Meter is not supported");
364         memset(cap, 0, sizeof(*cap));
365         if (priv->sh->meter_aso_en) {
366                 /* 2 meters per one ASO cache line. */
367                 cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
368                 cap->srtcm_rfc2697_packet_mode_supported = 1;
369         } else {
370                 cap->n_max = 1 << qattr->log_max_flow_meter;
371                 cap->srtcm_rfc2697_packet_mode_supported = 0;
372         }
373         cap->srtcm_rfc2697_byte_mode_supported = 1;
374         cap->n_shared_max = cap->n_max;
375         cap->identical = 1;
376         cap->shared_identical = 1;
377         cap->shared_n_flows_per_mtr_max = 4 << 20;
378         /* 2M flows can share the same meter. */
379         cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
380         cap->meter_srtcm_rfc2697_n_max = qattr->flow_meter_old ? cap->n_max : 0;
381         cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
382         cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
383                           RTE_MTR_STATS_N_PKTS_DROPPED;
384         return 0;
385 }
386
387 /**
388  * Callback to add MTR profile.
389  *
390  * @param[in] dev
391  *   Pointer to Ethernet device.
392  * @param[in] meter_profile_id
393  *   Meter profile id.
394  * @param[in] profile
395  *   Pointer to meter profile detail.
396  * @param[out] error
397  *   Pointer to the error structure.
398  *
399  * @return
400  *   0 on success, a negative errno value otherwise and rte_errno is set.
401  */
402 static int
403 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
404                        uint32_t meter_profile_id,
405                        struct rte_mtr_meter_profile *profile,
406                        struct rte_mtr_error *error)
407 {
408         struct mlx5_priv *priv = dev->data->dev_private;
409         struct mlx5_flow_meter_profile *fmp;
410         union mlx5_l3t_data data;
411         int ret;
412
413         if (!priv->mtr_en)
414                 return -rte_mtr_error_set(error, ENOTSUP,
415                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
416                                           "Meter is not supported");
417         /* Check input params. */
418         ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
419                                                profile, error);
420         if (ret)
421                 return ret;
422         /* Meter profile memory allocation. */
423         fmp = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_flow_meter_profile),
424                          RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
425         if (fmp == NULL)
426                 return -rte_mtr_error_set(error, ENOMEM,
427                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED,
428                                           NULL, "Meter profile memory "
429                                           "alloc failed.");
430         /* Fill profile info. */
431         fmp->id = meter_profile_id;
432         fmp->profile = *profile;
433         /* Fill the flow meter parameters for the PRM. */
434         ret = mlx5_flow_meter_param_fill(fmp, priv, error);
435         if (ret)
436                 goto error;
437         data.ptr = fmp;
438         ret = mlx5_l3t_set_entry(priv->mtr_profile_tbl,
439                                  meter_profile_id, &data);
440         if (ret)
441                 return -rte_mtr_error_set(error, ENOTSUP,
442                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED,
443                                           NULL, "Meter profile insert fail.");
444         return 0;
445 error:
446         mlx5_free(fmp);
447         return ret;
448 }
449
450 /**
451  * Callback to delete MTR profile.
452  *
453  * @param[in] dev
454  *   Pointer to Ethernet device.
455  * @param[in] meter_profile_id
456  *   Meter profile id.
457  * @param[out] error
458  *   Pointer to the error structure.
459  *
460  * @return
461  *   0 on success, a negative errno value otherwise and rte_errno is set.
462  */
463 static int
464 mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
465                           uint32_t meter_profile_id,
466                           struct rte_mtr_error *error)
467 {
468         struct mlx5_priv *priv = dev->data->dev_private;
469         struct mlx5_flow_meter_profile *fmp;
470
471         if (!priv->mtr_en)
472                 return -rte_mtr_error_set(error, ENOTSUP,
473                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
474                                           "Meter is not supported");
475         /* Meter profile must exist. */
476         fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
477         if (fmp == NULL)
478                 return -rte_mtr_error_set(error, ENOENT,
479                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
480                                           &meter_profile_id,
481                                           "Meter profile id is invalid.");
482         /* Check profile is unused. */
483         if (fmp->ref_cnt)
484                 return -rte_mtr_error_set(error, EBUSY,
485                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
486                                           NULL, "Meter profile is in use.");
487         if (mlx5_l3t_clear_entry(priv->mtr_profile_tbl, meter_profile_id))
488                 return -rte_mtr_error_set(error, EBUSY,
489                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
490                                           NULL, "Meter profile remove fail.");
491         mlx5_free(fmp);
492         return 0;
493 }
494
495 /**
496  * Find policy by id.
497  *
498  * @param[in] dev
499  *   Pointer to Ethernet device.
500  * @param policy_id
501  *   Policy id.
502  *
503  * @return
504  *   Pointer to the policy found on success, NULL otherwise.
505  */
506 struct mlx5_flow_meter_policy *
507 mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
508                             uint32_t policy_id,
509                             uint32_t *policy_idx)
510 {
511         struct mlx5_priv *priv = dev->data->dev_private;
512         struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
513         union mlx5_l3t_data data;
514
515         if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM || !priv->policy_idx_tbl)
516                 return NULL;
517         if (mlx5_l3t_get_entry(priv->policy_idx_tbl, policy_id, &data) ||
518                                 !data.dword)
519                 return NULL;
520         if (policy_idx)
521                 *policy_idx = data.dword;
522         sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
523                                         data.dword);
524         /* Remove reference taken by the mlx5_l3t_get_entry. */
525         mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id);
526         if (sub_policy)
527                 if (sub_policy->main_policy_id)
528                         return sub_policy->main_policy;
529         return NULL;
530 }
531
532 /**
533  * Callback to check MTR policy action validate
534  *
535  * @param[in] dev
536  *   Pointer to Ethernet device.
537  * @param[in] actions
538  *   Pointer to meter policy action detail.
539  * @param[out] error
540  *   Pointer to the error structure.
541  *
542  * @return
543  *   0 on success, a negative errno value otherwise and rte_errno is set.
544  */
545 static int
546 mlx5_flow_meter_policy_validate(struct rte_eth_dev *dev,
547         struct rte_mtr_meter_policy_params *policy,
548         struct rte_mtr_error *error)
549 {
550         struct mlx5_priv *priv = dev->data->dev_private;
551         struct rte_flow_attr attr = { .transfer =
552                         priv->config.dv_esw_en ? 1 : 0};
553         bool is_rss = false;
554         bool is_def_policy = false;
555         uint8_t domain_bitmap;
556         int ret;
557
558         if (!priv->mtr_en || !priv->sh->meter_aso_en)
559                 return -rte_mtr_error_set(error, ENOTSUP,
560                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
561                                 NULL, "meter policy unsupported.");
562         ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
563                         &is_rss, &domain_bitmap, &is_def_policy, error);
564         if (ret)
565                 return ret;
566         return 0;
567 }
568
569 static int
570 __mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
571                         uint32_t policy_id,
572                         struct mlx5_flow_meter_policy *mtr_policy,
573                         struct rte_mtr_error *error,
574                         bool clear_l3t)
575 {
576         struct mlx5_priv *priv = dev->data->dev_private;
577         struct mlx5_flow_meter_sub_policy *sub_policy;
578         uint32_t i, j;
579         uint16_t sub_policy_num;
580
581         rte_spinlock_lock(&mtr_policy->sl);
582         if (mtr_policy->ref_cnt) {
583                 rte_spinlock_unlock(&mtr_policy->sl);
584                 return -rte_mtr_error_set(error, EBUSY,
585                                 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
586                                  NULL,
587                                 "Meter policy object is being used.");
588         }
589         mlx5_flow_destroy_policy_rules(dev, mtr_policy);
590         mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
591         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
592                 sub_policy_num = (mtr_policy->sub_policy_num >>
593                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
594                         MLX5_MTR_SUB_POLICY_NUM_MASK;
595                 if (sub_policy_num) {
596                         for (j = 0; j < sub_policy_num; j++) {
597                                 sub_policy = mtr_policy->sub_policys[i][j];
598                                 if (sub_policy)
599                                         mlx5_ipool_free
600                                         (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
601                                         sub_policy->idx);
602                         }
603                 }
604         }
605         if (priv->policy_idx_tbl && clear_l3t) {
606                 if (mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id)) {
607                         rte_spinlock_unlock(&mtr_policy->sl);
608                         return -rte_mtr_error_set(error, ENOTSUP,
609                                 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
610                                 "Fail to delete policy in index table.");
611                 }
612         }
613         rte_spinlock_unlock(&mtr_policy->sl);
614         return 0;
615 }
616
617 /**
618  * Callback to add MTR policy.
619  *
620  * @param[in] dev
621  *   Pointer to Ethernet device.
622  * @param[out] policy_id
623  *   Pointer to policy id
624  * @param[in] actions
625  *   Pointer to meter policy action detail.
626  * @param[out] error
627  *   Pointer to the error structure.
628  *
629  * @return
630  *   0 on success, a negative errno value otherwise and rte_errno is set.
631  */
632 static int
633 mlx5_flow_meter_policy_add(struct rte_eth_dev *dev,
634                         uint32_t policy_id,
635                         struct rte_mtr_meter_policy_params *policy,
636                         struct rte_mtr_error *error)
637 {
638         struct mlx5_priv *priv = dev->data->dev_private;
639         struct rte_flow_attr attr = { .transfer =
640                         priv->config.dv_esw_en ? 1 : 0};
641         uint32_t sub_policy_idx = 0;
642         uint32_t policy_idx = 0;
643         struct mlx5_flow_meter_policy *mtr_policy = NULL;
644         struct mlx5_flow_meter_sub_policy *sub_policy;
645         bool is_rss = false;
646         bool is_def_policy = false;
647         uint32_t i;
648         int ret;
649         uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy);
650         uint16_t sub_policy_num;
651         uint8_t domain_bitmap = 0;
652         union mlx5_l3t_data data;
653
654         if (!priv->mtr_en)
655                 return -rte_mtr_error_set(error, ENOTSUP,
656                                           RTE_MTR_ERROR_TYPE_METER_POLICY,
657                                           NULL, "meter policy unsupported.");
658         if (policy_id == MLX5_INVALID_POLICY_ID)
659                 return -rte_mtr_error_set(error, ENOTSUP,
660                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
661                         "policy ID is invalid. ");
662         if (policy_id == priv->sh->mtrmng->def_policy_id)
663                 return -rte_mtr_error_set(error, EEXIST,
664                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
665                         "policy ID exists. ");
666         mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id,
667                                 &policy_idx);
668         if (mtr_policy)
669                 return -rte_mtr_error_set(error, EEXIST,
670                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
671                         "policy ID exists. ");
672         ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
673                         &is_rss, &domain_bitmap, &is_def_policy, error);
674         if (ret)
675                 return ret;
676         if (!domain_bitmap)
677                 return -rte_mtr_error_set(error, ENOTSUP,
678                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
679                                 NULL, "fail to find policy domain.");
680         if (is_def_policy) {
681                 if (priv->sh->mtrmng->def_policy_id != MLX5_INVALID_POLICY_ID)
682                         return -rte_mtr_error_set(error, EEXIST,
683                                 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
684                                 NULL, "a policy with similar actions "
685                                 "is already configured");
686                 if (mlx5_flow_create_def_policy(dev))
687                         return -rte_mtr_error_set(error, ENOTSUP,
688                                 RTE_MTR_ERROR_TYPE_METER_POLICY,
689                                 NULL,
690                                 "fail to create non-terminated policy.");
691                 priv->sh->mtrmng->def_policy_id = policy_id;
692                 return 0;
693         }
694         if (!priv->sh->meter_aso_en)
695                 return -rte_mtr_error_set(error, ENOTSUP,
696                         RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
697                         "no ASO capability to support the policy ");
698         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
699                 if (!(domain_bitmap & (1 << i)))
700                         continue;
701                 if (is_rss) {
702                         policy_size +=
703                         sizeof(struct mlx5_flow_meter_sub_policy *) *
704                         MLX5_MTR_RSS_MAX_SUB_POLICY;
705                         break;
706                 }
707                 policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
708         }
709         mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size,
710                          RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
711         if (!mtr_policy)
712                 return -rte_mtr_error_set(error, ENOMEM,
713                                 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
714                                 "Memory alloc failed for meter policy.");
715         policy_size = sizeof(struct mlx5_flow_meter_policy);
716         for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
717                 if (!(domain_bitmap & (1 << i)))
718                         continue;
719                 if (i == MLX5_MTR_DOMAIN_INGRESS)
720                         mtr_policy->ingress = 1;
721                 if (i == MLX5_MTR_DOMAIN_EGRESS)
722                         mtr_policy->egress = 1;
723                 if (i == MLX5_MTR_DOMAIN_TRANSFER)
724                         mtr_policy->transfer = 1;
725                 sub_policy = mlx5_ipool_zmalloc
726                                 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
727                                 &sub_policy_idx);
728                 if (!sub_policy)
729                         goto policy_add_err;
730                 if (sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
731                         goto policy_add_err;
732                 sub_policy->idx = sub_policy_idx;
733                 sub_policy->main_policy = mtr_policy;
734                 if (!policy_idx) {
735                         policy_idx = sub_policy_idx;
736                         sub_policy->main_policy_id = 1;
737                 }
738                 mtr_policy->sub_policys[i] =
739                 (struct mlx5_flow_meter_sub_policy **)
740                         ((uint8_t *)mtr_policy + policy_size);
741                 mtr_policy->sub_policys[i][0] = sub_policy;
742                 sub_policy_num = (mtr_policy->sub_policy_num >>
743                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
744                         MLX5_MTR_SUB_POLICY_NUM_MASK;
745                 sub_policy_num++;
746                 mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
747                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
748                 mtr_policy->sub_policy_num |=
749                         (sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
750                         (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
751                 if (is_rss) {
752                         mtr_policy->is_rss = 1;
753                         break;
754                 }
755                 policy_size += sizeof(struct mlx5_flow_meter_sub_policy  *);
756         }
757         rte_spinlock_init(&mtr_policy->sl);
758         ret = mlx5_flow_create_mtr_acts(dev, mtr_policy,
759                                         policy->actions, error);
760         if (ret)
761                 goto policy_add_err;
762         if (!is_rss && !mtr_policy->is_queue) {
763                 /* Create policy rules in HW. */
764                 ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
765                 if (ret)
766                         goto policy_add_err;
767         }
768         data.dword = policy_idx;
769         if (!priv->policy_idx_tbl) {
770                 priv->policy_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
771                 if (!priv->policy_idx_tbl)
772                         goto policy_add_err;
773         }
774         if (mlx5_l3t_set_entry(priv->policy_idx_tbl, policy_id, &data))
775                 goto policy_add_err;
776         return 0;
777 policy_add_err:
778         if (mtr_policy) {
779                 ret = __mlx5_flow_meter_policy_delete(dev, policy_id,
780                         mtr_policy, error, false);
781                 mlx5_free(mtr_policy);
782                 if (ret)
783                         return ret;
784         }
785         return -rte_mtr_error_set(error, ENOTSUP,
786                                   RTE_MTR_ERROR_TYPE_UNSPECIFIED,
787                                   NULL, "Failed to create devx policy.");
788 }
789
790 /**
791  * Callback to delete MTR policy.
792  *
793  * @param[in] dev
794  *   Pointer to Ethernet device.
795  * @param[in] policy_id
796  *   Meter policy id.
797  * @param[out] error
798  *   Pointer to the error structure.
799  *
800  * @return
801  *   0 on success, a negative errno value otherwise and rte_errno is set.
802  */
803 static int
804 mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
805                           uint32_t policy_id,
806                           struct rte_mtr_error *error)
807 {
808         struct mlx5_priv *priv = dev->data->dev_private;
809         struct mlx5_flow_meter_policy *mtr_policy;
810         uint32_t policy_idx;
811         int ret;
812
813         if (policy_id == priv->sh->mtrmng->def_policy_id) {
814                 if (priv->sh->mtrmng->def_policy_ref_cnt > 0)
815                         return -rte_mtr_error_set(error, ENOTSUP,
816                                 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
817                                 "Meter policy object is being used.");
818                 priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
819                 return 0;
820         }
821         mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
822         if (!mtr_policy)
823                 return -rte_mtr_error_set(error, ENOTSUP,
824                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
825                         "Meter policy id is invalid. ");
826         ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy,
827                                                 error, true);
828         if (ret)
829                 return ret;
830         mlx5_free(mtr_policy);
831         return 0;
832 }
833
834 /**
835  * Check meter validation.
836  *
837  * @param[in] priv
838  *   Pointer to mlx5 private data structure.
839  * @param[in] meter_id
840  *   Meter id.
841  * @param[in] params
842  *   Pointer to rte meter parameters.
843  * @param[out] error
844  *   Pointer to rte meter error structure.
845  *
846  * @return
847  *   0 on success, a negative errno value otherwise and rte_errno is set.
848  */
849 static int
850 mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
851                          struct rte_mtr_params *params,
852                          struct rte_mtr_error *error)
853 {
854         /* Meter must use global drop action. */
855         if (!priv->sh->dr_drop_action)
856                 return -rte_mtr_error_set(error, ENOTSUP,
857                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
858                                           NULL,
859                                           "No drop action ready for meter.");
860         /* Meter params must not be NULL. */
861         if (params == NULL)
862                 return -rte_mtr_error_set(error, EINVAL,
863                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
864                                           NULL, "Meter object params null.");
865         /* Previous meter color is not supported. */
866         if (params->use_prev_mtr_color)
867                 return -rte_mtr_error_set(error, ENOTSUP,
868                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
869                                           NULL,
870                                           "Previous meter color "
871                                           "not supported.");
872         if (params->meter_policy_id == MLX5_INVALID_POLICY_ID)
873                 return -rte_mtr_error_set(error, ENOENT,
874                                 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
875                                 NULL, "Meter policy id not valid.");
876         /* Validate meter id. */
877         if (mlx5_flow_meter_find(priv, meter_id, NULL))
878                 return -rte_mtr_error_set(error, EEXIST,
879                         RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
880                         "Meter object already exists.");
881         return 0;
882 }
883
884 /**
885  * Modify the flow meter action.
886  *
887  * @param[in] priv
888  *   Pointer to mlx5 private data structure.
889  * @param[in] fm
890  *   Pointer to flow meter to be modified.
891  * @param[in] srtcm
892  *   Pointer to meter srtcm description parameter.
893  * @param[in] modify_bits
894  *   The bit in srtcm to be updated.
895  * @param[in] active_state
896  *   The state to be updated.
897  * @return
898  *   0 on success, o negative value otherwise.
899  */
900 static int
901 mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
902                 struct mlx5_flow_meter_info *fm,
903                 const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
904                 uint64_t modify_bits, uint32_t active_state, uint32_t is_enable)
905 {
906 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
907         uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
908         uint32_t *attr;
909         struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
910         int ret;
911         struct mlx5_aso_mtr *aso_mtr = NULL;
912         uint32_t cbs_cir, ebs_eir, val;
913
914         if (priv->sh->meter_aso_en) {
915                 fm->is_enable = !!is_enable;
916                 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
917                 ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
918                 if (ret)
919                         return ret;
920                 ret = mlx5_aso_mtr_wait(priv->sh, aso_mtr);
921                 if (ret)
922                         return ret;
923         } else {
924                 /* Fill command parameters. */
925                 mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
926                 mod_attr.flow_meter_parameter = in;
927                 mod_attr.flow_meter_parameter_sz =
928                                 MLX5_ST_SZ_BYTES(flow_meter_parameters);
929                 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
930                         mod_attr.active = !!active_state;
931                 else
932                         mod_attr.active = 0;
933                 attr = in;
934                 cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
935                 ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
936                 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
937                         val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) &
938                                 ASO_DSEG_EXP_MASK;
939                         MLX5_SET(flow_meter_parameters, attr,
940                                 cbs_exponent, val);
941                         val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) &
942                                 ASO_DSEG_MAN_MASK;
943                         MLX5_SET(flow_meter_parameters, attr,
944                                 cbs_mantissa, val);
945                 }
946                 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
947                         val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) &
948                                 ASO_DSEG_EXP_MASK;
949                         MLX5_SET(flow_meter_parameters, attr,
950                                 cir_exponent, val);
951                         val = cbs_cir & ASO_DSEG_MAN_MASK;
952                         MLX5_SET(flow_meter_parameters, attr,
953                                 cir_mantissa, val);
954                 }
955                 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
956                         val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) &
957                                 ASO_DSEG_EXP_MASK;
958                         MLX5_SET(flow_meter_parameters, attr,
959                                 ebs_exponent, val);
960                         val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) &
961                                 ASO_DSEG_MAN_MASK;
962                         MLX5_SET(flow_meter_parameters, attr,
963                                 ebs_mantissa, val);
964                 }
965                 /* Apply modifications to meter only if it was created. */
966                 if (fm->meter_action) {
967                         ret = mlx5_glue->dv_modify_flow_action_meter
968                                         (fm->meter_action, &mod_attr,
969                                         rte_cpu_to_be_64(modify_bits));
970                         if (ret)
971                                 return ret;
972                 }
973                 /* Update succeedded modify meter parameters. */
974                 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
975                         fm->active_state = !!active_state;
976         }
977         return 0;
978 #else
979         (void)priv;
980         (void)fm;
981         (void)srtcm;
982         (void)modify_bits;
983         (void)active_state;
984         (void)is_enable;
985         return -ENOTSUP;
986 #endif
987 }
988
989 static int
990 mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev,
991                                 struct mlx5_flow_meter_info *fm,
992                                 uint64_t stats_mask)
993 {
994         fm->bytes_dropped =
995                 (stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
996         fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
997         if (fm->bytes_dropped || fm->pkts_dropped) {
998                 if (!fm->drop_cnt) {
999                         /* Alloc policer counters. */
1000                         fm->drop_cnt = mlx5_counter_alloc(dev);
1001                         if (!fm->drop_cnt)
1002                                 return -1;
1003                 }
1004         } else {
1005                 if (fm->drop_cnt) {
1006                         mlx5_counter_free(dev, fm->drop_cnt);
1007                         fm->drop_cnt = 0;
1008                 }
1009         }
1010         return 0;
1011 }
1012
1013 /**
1014  * Create meter rules.
1015  *
1016  * @param[in] dev
1017  *   Pointer to Ethernet device.
1018  * @param[in] meter_id
1019  *   Meter id.
1020  * @param[in] params
1021  *   Pointer to rte meter parameters.
1022  * @param[in] shared
1023  *   Meter shared with other flow or not.
1024  * @param[out] error
1025  *   Pointer to rte meter error structure.
1026  *
1027  * @return
1028  *   0 on success, a negative errno value otherwise and rte_errno is set.
1029  */
1030 static int
1031 mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
1032                        struct rte_mtr_params *params, int shared,
1033                        struct rte_mtr_error *error)
1034 {
1035         struct mlx5_priv *priv = dev->data->dev_private;
1036         struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1037         struct mlx5_flow_meter_profile *fmp;
1038         struct mlx5_flow_meter_info *fm;
1039         struct mlx5_legacy_flow_meter *legacy_fm;
1040         struct mlx5_flow_meter_policy *mtr_policy = NULL;
1041         struct mlx5_indexed_pool_config flow_ipool_cfg = {
1042                 .size = 0,
1043                 .trunk_size = 64,
1044                 .need_lock = 1,
1045                 .type = "mlx5_flow_mtr_flow_id_pool",
1046         };
1047         struct mlx5_aso_mtr *aso_mtr;
1048         uint32_t mtr_idx, policy_idx;
1049         union mlx5_l3t_data data;
1050         int ret;
1051         uint8_t domain_bitmap;
1052         uint8_t mtr_id_bits;
1053         uint8_t mtr_reg_bits = priv->mtr_reg_share ?
1054                                 MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
1055
1056         if (!priv->mtr_en)
1057                 return -rte_mtr_error_set(error, ENOTSUP,
1058                                         RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1059                                         "Meter is not supported");
1060         /* Validate the parameters. */
1061         ret = mlx5_flow_meter_validate(priv, meter_id, params, error);
1062         if (ret)
1063                 return ret;
1064         /* Meter profile must exist. */
1065         fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
1066         if (fmp == NULL)
1067                 return -rte_mtr_error_set(error, ENOENT,
1068                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1069                         NULL, "Meter profile id not valid.");
1070         /* Meter policy must exist. */
1071         if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
1072                 __atomic_add_fetch
1073                         (&priv->sh->mtrmng->def_policy_ref_cnt,
1074                         1, __ATOMIC_RELAXED);
1075                 domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT;
1076                 if (!priv->config.dv_esw_en)
1077                         domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
1078         } else {
1079                 mtr_policy = mlx5_flow_meter_policy_find(dev,
1080                                 params->meter_policy_id, &policy_idx);
1081                 if (!priv->sh->meter_aso_en)
1082                         return -rte_mtr_error_set(error, ENOTSUP,
1083                                 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1084                                 "Part of the policies cannot be "
1085                                 "supported without ASO ");
1086                 if (!mtr_policy)
1087                         return -rte_mtr_error_set(error, ENOENT,
1088                                 RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1089                                 NULL, "Meter policy id not valid.");
1090                 domain_bitmap = (mtr_policy->ingress ?
1091                                         MLX5_MTR_DOMAIN_INGRESS_BIT : 0) |
1092                                 (mtr_policy->egress ?
1093                                         MLX5_MTR_DOMAIN_EGRESS_BIT : 0) |
1094                                 (mtr_policy->transfer ?
1095                                         MLX5_MTR_DOMAIN_TRANSFER_BIT : 0);
1096         }
1097         /* Allocate the flow meter memory. */
1098         if (priv->sh->meter_aso_en) {
1099                 mtr_idx = mlx5_flow_mtr_alloc(dev);
1100                 if (!mtr_idx)
1101                         return -rte_mtr_error_set(error, ENOMEM,
1102                                 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1103                                 "Memory alloc failed for meter.");
1104                 aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
1105                 fm = &aso_mtr->fm;
1106         } else {
1107                 legacy_fm = mlx5_ipool_zmalloc
1108                                 (priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
1109                 if (legacy_fm == NULL)
1110                         return -rte_mtr_error_set(error, ENOMEM,
1111                                 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1112                                 "Memory alloc failed for meter.");
1113                 legacy_fm->idx = mtr_idx;
1114                 fm = &legacy_fm->fm;
1115         }
1116         mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
1117         if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) >
1118             mtr_reg_bits) {
1119                 DRV_LOG(ERR, "Meter number exceeds max limit.");
1120                 goto error;
1121         }
1122         if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits)
1123                 priv->sh->mtrmng->max_mtr_bits = mtr_id_bits;
1124         /* Fill the flow meter parameters. */
1125         fm->meter_id = meter_id;
1126         fm->policy_id = params->meter_policy_id;
1127         fm->profile = fmp;
1128         if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask))
1129                 goto error;
1130         if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap))
1131                 goto error;
1132         /* Add to the flow meter list. */
1133         if (!priv->sh->meter_aso_en)
1134                 TAILQ_INSERT_TAIL(fms, legacy_fm, next);
1135         /* Add to the flow meter list. */
1136         fm->active_state = 1; /* Config meter starts as active. */
1137         fm->is_enable = 1;
1138         fm->shared = !!shared;
1139         __atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
1140         if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
1141                 fm->def_policy = 1;
1142                 fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
1143                 if (!fm->flow_ipool)
1144                         goto error;
1145         }
1146         rte_spinlock_init(&fm->sl);
1147         /* If ASO meter supported, update ASO flow meter by wqe. */
1148         if (priv->sh->meter_aso_en) {
1149                 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
1150                 ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
1151                 if (ret)
1152                         goto error;
1153                 if (!priv->mtr_idx_tbl) {
1154                         priv->mtr_idx_tbl =
1155                                 mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
1156                         if (!priv->mtr_idx_tbl)
1157                                 goto error;
1158                 }
1159                 data.dword = mtr_idx;
1160                 if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
1161                         goto error;
1162         }
1163         if (mtr_policy)
1164                 __atomic_add_fetch(&mtr_policy->ref_cnt, 1, __ATOMIC_RELAXED);
1165         return 0;
1166 error:
1167         mlx5_flow_destroy_mtr_tbls(dev, fm);
1168         /* Free policer counters. */
1169         if (fm->drop_cnt)
1170                 mlx5_counter_free(dev, fm->drop_cnt);
1171         if (priv->sh->meter_aso_en)
1172                 mlx5_flow_mtr_free(dev, mtr_idx);
1173         else
1174                 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
1175         return -rte_mtr_error_set(error, ENOTSUP,
1176                 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1177                 NULL, "Failed to create devx meter.");
1178 }
1179
1180 static int
1181 mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
1182                         struct mlx5_flow_meter_info *fm,
1183                         uint32_t mtr_idx)
1184 {
1185         struct mlx5_priv *priv = dev->data->dev_private;
1186         struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1187         struct mlx5_flow_meter_profile *fmp;
1188         struct mlx5_legacy_flow_meter *legacy_fm = NULL;
1189         struct mlx5_flow_meter_policy *mtr_policy;
1190
1191         /* Meter object must not have any owner. */
1192         MLX5_ASSERT(!fm->ref_cnt);
1193         /* Get meter profile. */
1194         fmp = fm->profile;
1195         if (fmp == NULL)
1196                 return -1;
1197         /* Update dependencies. */
1198         __atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
1199         fm->profile = NULL;
1200         /* Remove from list. */
1201         if (!priv->sh->meter_aso_en) {
1202                 legacy_fm = container_of(fm,
1203                         struct mlx5_legacy_flow_meter, fm);
1204                 TAILQ_REMOVE(fms, legacy_fm, next);
1205         }
1206         /* Free drop counters. */
1207         if (fm->drop_cnt)
1208                 mlx5_counter_free(dev, fm->drop_cnt);
1209         /* Free meter flow table. */
1210         if (fm->flow_ipool) {
1211                 mlx5_ipool_destroy(fm->flow_ipool);
1212                 fm->flow_ipool = 0;
1213         }
1214         mlx5_flow_destroy_mtr_tbls(dev, fm);
1215         if (fm->def_policy)
1216                 __atomic_sub_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
1217                                 1, __ATOMIC_RELAXED);
1218         if (priv->sh->meter_aso_en) {
1219                 if (!fm->def_policy) {
1220                         mtr_policy = mlx5_flow_meter_policy_find(dev,
1221                                                 fm->policy_id, NULL);
1222                         if (mtr_policy)
1223                                 __atomic_sub_fetch(&mtr_policy->ref_cnt,
1224                                                 1, __ATOMIC_RELAXED);
1225                         fm->policy_id = 0;
1226                 }
1227                 fm->def_policy = 0;
1228                 if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id))
1229                         return -1;
1230                 mlx5_flow_mtr_free(dev, mtr_idx);
1231         } else {
1232                 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
1233                                         legacy_fm->idx);
1234         }
1235         return 0;
1236 }
1237
1238 /**
1239  * Destroy meter rules.
1240  *
1241  * @param[in] dev
1242  *   Pointer to Ethernet device.
1243  * @param[in] meter_id
1244  *   Meter id.
1245  * @param[out] error
1246  *   Pointer to rte meter error structure.
1247  *
1248  * @return
1249  *   0 on success, a negative errno value otherwise and rte_errno is set.
1250  */
1251 static int
1252 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
1253                         struct rte_mtr_error *error)
1254 {
1255         struct mlx5_priv *priv = dev->data->dev_private;
1256         struct mlx5_flow_meter_info *fm;
1257         uint32_t mtr_idx = 0;
1258
1259         if (!priv->mtr_en)
1260                 return -rte_mtr_error_set(error, ENOTSUP,
1261                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1262                                           NULL,
1263                                           "Meter is not supported");
1264         /* Meter object must exist. */
1265         fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
1266         if (fm == NULL)
1267                 return -rte_mtr_error_set(error, ENOENT,
1268                                           RTE_MTR_ERROR_TYPE_MTR_ID,
1269                                           NULL,
1270                                           "Meter object id not valid.");
1271         /* Meter object must not have any owner. */
1272         if (fm->ref_cnt > 0)
1273                 return -rte_mtr_error_set(error, EBUSY,
1274                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED,
1275                                           NULL,
1276                                           "Meter object is being used.");
1277         /* Destroy the meter profile. */
1278         if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
1279                 return -rte_mtr_error_set(error, EINVAL,
1280                                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1281                                         NULL,
1282                                         "MTR object meter profile invalid.");
1283         return 0;
1284 }
1285
1286 /**
1287  * Modify meter state.
1288  *
1289  * @param[in] priv
1290  *   Pointer to mlx5 private data structure.
1291  * @param[in] fm
1292  *   Pointer to flow meter.
1293  * @param[in] new_state
1294  *   New state to update.
1295  * @param[out] error
1296  *   Pointer to rte meter error structure.
1297  *
1298  * @return
1299  *   0 on success, a negative errno value otherwise and rte_errno is set.
1300  */
1301 static int
1302 mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
1303                              struct mlx5_flow_meter_info *fm,
1304                              uint32_t new_state,
1305                              struct rte_mtr_error *error)
1306 {
1307         static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
1308                 .cbs_cir = RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL),
1309                 .ebs_eir = 0,
1310         };
1311         uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
1312                                MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
1313         int ret;
1314
1315         if (new_state == MLX5_FLOW_METER_DISABLE)
1316                 ret = mlx5_flow_meter_action_modify(priv, fm,
1317                                 &srtcm, modify_bits, 0, 0);
1318         else
1319                 ret = mlx5_flow_meter_action_modify(priv, fm,
1320                                                    &fm->profile->srtcm_prm,
1321                                                     modify_bits, 0, 1);
1322         if (ret)
1323                 return -rte_mtr_error_set(error, -ret,
1324                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
1325                                           NULL,
1326                                           new_state ?
1327                                           "Failed to enable meter." :
1328                                           "Failed to disable meter.");
1329         return 0;
1330 }
1331
1332 /**
1333  * Callback to enable flow meter.
1334  *
1335  * @param[in] dev
1336  *   Pointer to Ethernet device.
1337  * @param[in] meter_id
1338  *   Meter id.
1339  * @param[out] error
1340  *   Pointer to rte meter error structure.
1341  *
1342  * @return
1343  *   0 on success, a negative errno value otherwise and rte_errno is set.
1344  */
1345 static int
1346 mlx5_flow_meter_enable(struct rte_eth_dev *dev,
1347                        uint32_t meter_id,
1348                        struct rte_mtr_error *error)
1349 {
1350         struct mlx5_priv *priv = dev->data->dev_private;
1351         struct mlx5_flow_meter_info *fm;
1352         int ret;
1353
1354         if (!priv->mtr_en)
1355                 return -rte_mtr_error_set(error, ENOTSUP,
1356                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1357                                           "Meter is not supported");
1358         /* Meter object must exist. */
1359         fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1360         if (fm == NULL)
1361                 return -rte_mtr_error_set(error, ENOENT,
1362                                           RTE_MTR_ERROR_TYPE_MTR_ID,
1363                                           NULL, "Meter not found.");
1364         if (fm->active_state == MLX5_FLOW_METER_ENABLE)
1365                 return 0;
1366         ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
1367                                            error);
1368         if (!ret)
1369                 fm->active_state = MLX5_FLOW_METER_ENABLE;
1370         return ret;
1371 }
1372
1373 /**
1374  * Callback to disable flow meter.
1375  *
1376  * @param[in] dev
1377  *   Pointer to Ethernet device.
1378  * @param[in] meter_id
1379  *   Meter id.
1380  * @param[out] error
1381  *   Pointer to rte meter error structure.
1382  *
1383  * @return
1384  *   0 on success, a negative errno value otherwise and rte_errno is set.
1385  */
1386 static int
1387 mlx5_flow_meter_disable(struct rte_eth_dev *dev,
1388                         uint32_t meter_id,
1389                         struct rte_mtr_error *error)
1390 {
1391         struct mlx5_priv *priv = dev->data->dev_private;
1392         struct mlx5_flow_meter_info *fm;
1393         int ret;
1394
1395         if (!priv->mtr_en)
1396                 return -rte_mtr_error_set(error, ENOTSUP,
1397                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1398                                           "Meter is not supported");
1399         /* Meter object must exist. */
1400         fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1401         if (fm == NULL)
1402                 return -rte_mtr_error_set(error, ENOENT,
1403                                           RTE_MTR_ERROR_TYPE_MTR_ID,
1404                                           NULL, "Meter not found.");
1405         if (fm->active_state == MLX5_FLOW_METER_DISABLE)
1406                 return 0;
1407         ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
1408                                            error);
1409         if (!ret)
1410                 fm->active_state = MLX5_FLOW_METER_DISABLE;
1411         return ret;
1412 }
1413
1414 /**
1415  * Callback to update meter profile.
1416  *
1417  * @param[in] dev
1418  *   Pointer to Ethernet device.
1419  * @param[in] meter_id
1420  *   Meter id.
1421  * @param[in] meter_profile_id
1422  *   To be updated meter profile id.
1423  * @param[out] error
1424  *   Pointer to rte meter error structure.
1425  *
1426  * @return
1427  *   0 on success, a negative errno value otherwise and rte_errno is set.
1428  */
1429 static int
1430 mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
1431                                uint32_t meter_id,
1432                                uint32_t meter_profile_id,
1433                                struct rte_mtr_error *error)
1434 {
1435         struct mlx5_priv *priv = dev->data->dev_private;
1436         struct mlx5_flow_meter_profile *fmp;
1437         struct mlx5_flow_meter_profile *old_fmp;
1438         struct mlx5_flow_meter_info *fm;
1439         uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
1440                                MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
1441         int ret;
1442
1443         if (!priv->mtr_en)
1444                 return -rte_mtr_error_set(error, ENOTSUP,
1445                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1446                                           "Meter is not supported");
1447         /* Meter profile must exist. */
1448         fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
1449         if (fmp == NULL)
1450                 return -rte_mtr_error_set(error, ENOENT,
1451                                           RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1452                                           NULL, "Meter profile not found.");
1453         /* Meter object must exist. */
1454         fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1455         if (fm == NULL)
1456                 return -rte_mtr_error_set(error, ENOENT,
1457                                           RTE_MTR_ERROR_TYPE_MTR_ID,
1458                                           NULL, "Meter not found.");
1459         /* MTR object already set to meter profile id. */
1460         old_fmp = fm->profile;
1461         if (fmp == old_fmp)
1462                 return 0;
1463         /* Update the profile. */
1464         fm->profile = fmp;
1465         /* Update meter params in HW (if not disabled). */
1466         if (fm->active_state == MLX5_FLOW_METER_DISABLE)
1467                 return 0;
1468         ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
1469                                               modify_bits, fm->active_state, 1);
1470         if (ret) {
1471                 fm->profile = old_fmp;
1472                 return -rte_mtr_error_set(error, -ret,
1473                                           RTE_MTR_ERROR_TYPE_MTR_PARAMS,
1474                                           NULL, "Failed to update meter"
1475                                           " parmeters in hardware.");
1476         }
1477         old_fmp->ref_cnt--;
1478         fmp->ref_cnt++;
1479         return 0;
1480 }
1481
1482 /**
1483  * Callback to update meter stats mask.
1484  *
1485  * @param[in] dev
1486  *   Pointer to Ethernet device.
1487  * @param[in] meter_id
1488  *   Meter id.
1489  * @param[in] stats_mask
1490  *   To be updated stats_mask.
1491  * @param[out] error
1492  *   Pointer to rte meter error structure.
1493  *
1494  * @return
1495  *   0 on success, a negative errno value otherwise and rte_errno is set.
1496  */
1497 static int
1498 mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
1499                              uint32_t meter_id,
1500                              uint64_t stats_mask,
1501                              struct rte_mtr_error *error)
1502 {
1503         struct mlx5_priv *priv = dev->data->dev_private;
1504         struct mlx5_flow_meter_info *fm;
1505
1506         if (!priv->mtr_en)
1507                 return -rte_mtr_error_set(error, ENOTSUP,
1508                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1509                                           "Meter is not supported");
1510         /* Meter object must exist. */
1511         fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1512         if (fm == NULL)
1513                 return -rte_mtr_error_set(error, ENOENT,
1514                                           RTE_MTR_ERROR_TYPE_MTR_ID,
1515                                           NULL, "Meter object id not valid.");
1516         if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask))
1517                 return -rte_mtr_error_set(error, ENOENT,
1518                                           RTE_MTR_ERROR_TYPE_MTR_ID,
1519                                           NULL, "Fail to allocate "
1520                                           "counter for meter.");
1521         return 0;
1522 }
1523
1524 /**
1525  * Callback to read meter statistics.
1526  *
1527  * @param[in] dev
1528  *   Pointer to Ethernet device.
1529  * @param[in] meter_id
1530  *   Meter id.
1531  * @param[out] stats
1532  *   Pointer to store the statistics.
1533  * @param[out] stats_mask
1534  *   Pointer to store the stats_mask.
1535  * @param[in] clear
1536  *   Statistic to be cleared after read or not.
1537  * @param[out] error
1538  *   Pointer to rte meter error structure.
1539  *
1540  * @return
1541  *   0 on success, a negative errno value otherwise and rte_errno is set.
1542  */
1543 static int
1544 mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
1545                            uint32_t meter_id,
1546                            struct rte_mtr_stats *stats,
1547                            uint64_t *stats_mask,
1548                            int clear,
1549                            struct rte_mtr_error *error)
1550 {
1551         struct mlx5_priv *priv = dev->data->dev_private;
1552         struct mlx5_flow_meter_info *fm;
1553         uint64_t pkts;
1554         uint64_t bytes;
1555         int ret = 0;
1556
1557         if (!priv->mtr_en)
1558                 return -rte_mtr_error_set(error, ENOTSUP,
1559                                           RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1560                                           "Meter is not supported");
1561         /* Meter object must exist. */
1562         fm = mlx5_flow_meter_find(priv, meter_id, NULL);
1563         if (fm == NULL)
1564                 return -rte_mtr_error_set(error, ENOENT,
1565                                           RTE_MTR_ERROR_TYPE_MTR_ID,
1566                                           NULL, "Meter object id not valid.");
1567         *stats_mask = 0;
1568         if (fm->bytes_dropped)
1569                 *stats_mask |= RTE_MTR_STATS_N_BYTES_DROPPED;
1570         if (fm->pkts_dropped)
1571                 *stats_mask |= RTE_MTR_STATS_N_PKTS_DROPPED;
1572         memset(stats, 0, sizeof(*stats));
1573         if (fm->drop_cnt) {
1574                 ret = mlx5_counter_query(dev, fm->drop_cnt, clear, &pkts,
1575                                                  &bytes);
1576                 if (ret)
1577                         goto error;
1578                 /* If need to read the packets, set it. */
1579                 if (fm->pkts_dropped)
1580                         stats->n_pkts_dropped = pkts;
1581                 /* If need to read the bytes, set it. */
1582                 if (fm->bytes_dropped)
1583                         stats->n_bytes_dropped = bytes;
1584         }
1585         return 0;
1586 error:
1587         return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
1588                                  "Failed to read meter drop counters.");
1589 }
1590
1591 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
1592         .capabilities_get = mlx5_flow_mtr_cap_get,
1593         .meter_profile_add = mlx5_flow_meter_profile_add,
1594         .meter_profile_delete = mlx5_flow_meter_profile_delete,
1595         .meter_policy_validate = mlx5_flow_meter_policy_validate,
1596         .meter_policy_add = mlx5_flow_meter_policy_add,
1597         .meter_policy_delete = mlx5_flow_meter_policy_delete,
1598         .create = mlx5_flow_meter_create,
1599         .destroy = mlx5_flow_meter_destroy,
1600         .meter_enable = mlx5_flow_meter_enable,
1601         .meter_disable = mlx5_flow_meter_disable,
1602         .meter_profile_update = mlx5_flow_meter_profile_update,
1603         .meter_dscp_table_update = NULL,
1604         .stats_update = mlx5_flow_meter_stats_update,
1605         .stats_read = mlx5_flow_meter_stats_read,
1606 };
1607
1608 /**
1609  * Get meter operations.
1610  *
1611  * @param dev
1612  *   Pointer to Ethernet device structure.
1613  * @param arg
1614  *   Pointer to set the mtr operations.
1615  *
1616  * @return
1617  *   Always 0.
1618  */
1619 int
1620 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
1621 {
1622         *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
1623         return 0;
1624 }
1625
1626 /**
1627  * Find meter by id.
1628  *
1629  * @param priv
1630  *   Pointer to mlx5_priv.
1631  * @param meter_id
1632  *   Meter id.
1633  * @param mtr_idx
1634  *   Pointer to Meter index.
1635  *
1636  * @return
1637  *   Pointer to the meter info found on success, NULL otherwise.
1638  */
1639 struct mlx5_flow_meter_info *
1640 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
1641                 uint32_t *mtr_idx)
1642 {
1643         struct mlx5_legacy_flow_meter *legacy_fm;
1644         struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1645         struct mlx5_aso_mtr *aso_mtr;
1646         struct mlx5_aso_mtr_pools_mng *pools_mng =
1647                                 &priv->sh->mtrmng->pools_mng;
1648         union mlx5_l3t_data data;
1649
1650         if (priv->sh->meter_aso_en) {
1651                 rte_spinlock_lock(&pools_mng->mtrsl);
1652                 if (!pools_mng->n_valid || !priv->mtr_idx_tbl) {
1653                         rte_spinlock_unlock(&pools_mng->mtrsl);
1654                         return NULL;
1655                 }
1656                 if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
1657                         !data.dword) {
1658                         rte_spinlock_unlock(&pools_mng->mtrsl);
1659                         return NULL;
1660                 }
1661                 if (mtr_idx)
1662                         *mtr_idx = data.dword;
1663                 aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
1664                 /* Remove reference taken by the mlx5_l3t_get_entry. */
1665                 mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
1666                 rte_spinlock_unlock(&pools_mng->mtrsl);
1667                 if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
1668                         return NULL;
1669                 return &aso_mtr->fm;
1670         }
1671         TAILQ_FOREACH(legacy_fm, fms, next)
1672                 if (meter_id == legacy_fm->fm.meter_id) {
1673                         if (mtr_idx)
1674                                 *mtr_idx = legacy_fm->idx;
1675                         return &legacy_fm->fm;
1676                 }
1677         return NULL;
1678 }
1679
1680 /**
1681  * Find meter by index.
1682  *
1683  * @param priv
1684  *   Pointer to mlx5_priv.
1685  * @param idx
1686  *   Meter index.
1687  *
1688  * @return
1689  *   Pointer to the meter info found on success, NULL otherwise.
1690  */
1691 struct mlx5_flow_meter_info *
1692 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
1693 {
1694         struct mlx5_aso_mtr *aso_mtr;
1695
1696         if (priv->sh->meter_aso_en) {
1697                 aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
1698                 if (!aso_mtr)
1699                         return NULL;
1700                 return &aso_mtr->fm;
1701         } else {
1702                 return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
1703         }
1704 }
1705
1706 /**
1707  * Attach meter to flow.
1708  * Unidirectional Meter creation can only be done
1709  * when flow direction is known, i.e. when calling meter_attach.
1710  *
1711  * @param [in] priv
1712  *  Pointer to mlx5 private data.
1713  * @param[in] fm
1714  *   Pointer to flow meter.
1715  * @param [in] attr
1716  *  Pointer to flow attributes.
1717  * @param [out] error
1718  *  Pointer to error structure.
1719  *
1720  * @return
1721  *   0 on success, a negative errno value otherwise and rte_errno is set.
1722  */
1723 int
1724 mlx5_flow_meter_attach(struct mlx5_priv *priv,
1725                        struct mlx5_flow_meter_info *fm,
1726                        const struct rte_flow_attr *attr,
1727                        struct rte_flow_error *error)
1728 {
1729         int ret = 0;
1730
1731         if (priv->sh->meter_aso_en) {
1732                 struct mlx5_aso_mtr *aso_mtr;
1733
1734                 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
1735                 if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) {
1736                         return rte_flow_error_set(error, ENOENT,
1737                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1738                                         NULL,
1739                                         "Timeout in meter configuration");
1740                 }
1741                 rte_spinlock_lock(&fm->sl);
1742                 if (fm->shared || !fm->ref_cnt) {
1743                         fm->ref_cnt++;
1744                 } else {
1745                         rte_flow_error_set(error, EINVAL,
1746                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1747                                    "Meter cannot be shared");
1748                         ret = -1;
1749                 }
1750                 rte_spinlock_unlock(&fm->sl);
1751         } else {
1752                 rte_spinlock_lock(&fm->sl);
1753                 if (fm->meter_action) {
1754                         if (fm->shared &&
1755                             attr->transfer == fm->transfer &&
1756                             attr->ingress == fm->ingress &&
1757                             attr->egress == fm->egress) {
1758                                 fm->ref_cnt++;
1759                         } else {
1760                                 rte_flow_error_set(error, EINVAL,
1761                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1762                                         fm->shared ?
1763                                         "Meter attr not match." :
1764                                         "Meter cannot be shared.");
1765                                 ret = -1;
1766                         }
1767                 } else {
1768                         fm->ingress = attr->ingress;
1769                         fm->egress = attr->egress;
1770                         fm->transfer = attr->transfer;
1771                         fm->ref_cnt = 1;
1772                         /* This also creates the meter object. */
1773                         fm->meter_action = mlx5_flow_meter_action_create(priv,
1774                                                                          fm);
1775                         if (!fm->meter_action) {
1776                                 fm->ref_cnt = 0;
1777                                 fm->ingress = 0;
1778                                 fm->egress = 0;
1779                                 fm->transfer = 0;
1780                                 rte_flow_error_set(error, EINVAL,
1781                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1782                                         "Meter action create failed.");
1783                                 ret = -1;
1784                         }
1785                 }
1786                 rte_spinlock_unlock(&fm->sl);
1787         }
1788         return ret ? -rte_errno : 0;
1789 }
1790
1791 /**
1792  * Detach meter from flow.
1793  *
1794  * @param [in] priv
1795  *  Pointer to mlx5 private data.
1796  * @param [in] fm
1797  *  Pointer to flow meter.
1798  */
1799 void
1800 mlx5_flow_meter_detach(struct mlx5_priv *priv,
1801                        struct mlx5_flow_meter_info *fm)
1802 {
1803 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
1804         rte_spinlock_lock(&fm->sl);
1805         MLX5_ASSERT(fm->ref_cnt);
1806         if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) {
1807                 mlx5_glue->destroy_flow_action(fm->meter_action);
1808                 fm->meter_action = NULL;
1809                 fm->ingress = 0;
1810                 fm->egress = 0;
1811                 fm->transfer = 0;
1812         }
1813         rte_spinlock_unlock(&fm->sl);
1814 #else
1815         (void)priv;
1816         (void)fm;
1817 #endif
1818 }
1819
1820 /**
1821  * Flush meter with Rx queue configuration.
1822  *
1823  * @param[in] dev
1824  *   Pointer to Ethernet device.
1825  */
1826 void
1827 mlx5_flow_meter_rxq_flush(struct rte_eth_dev *dev)
1828 {
1829         struct mlx5_priv *priv = dev->data->dev_private;
1830         struct mlx5_flow_meter_sub_policy *sub_policy;
1831         struct mlx5_flow_meter_policy *mtr_policy;
1832         void *entry;
1833         uint32_t i, policy_idx;
1834
1835         if (!priv->mtr_en)
1836                 return;
1837         if (priv->policy_idx_tbl) {
1838                 MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
1839                         policy_idx = *(uint32_t *)entry;
1840                         sub_policy = mlx5_ipool_get
1841                                 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
1842                                 policy_idx);
1843                         if (!sub_policy || !sub_policy->main_policy)
1844                                 continue;
1845                         mtr_policy = sub_policy->main_policy;
1846                         if (mtr_policy->is_queue || mtr_policy->is_rss)
1847                                 mlx5_flow_destroy_sub_policy_with_rxq(dev,
1848                                         mtr_policy);
1849                 }
1850         }
1851 }
1852
1853 /**
1854  * Flush meter configuration.
1855  *
1856  * @param[in] dev
1857  *   Pointer to Ethernet device.
1858  * @param[out] error
1859  *   Pointer to rte meter error structure.
1860  *
1861  * @return
1862  *   0 on success, a negative errno value otherwise and rte_errno is set.
1863  */
1864 int
1865 mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
1866 {
1867         struct mlx5_priv *priv = dev->data->dev_private;
1868         struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1869         struct mlx5_flow_meter_profile *fmp;
1870         struct mlx5_legacy_flow_meter *legacy_fm;
1871         struct mlx5_flow_meter_info *fm;
1872         struct mlx5_flow_meter_sub_policy *sub_policy;
1873         void *tmp;
1874         uint32_t i, mtr_idx, policy_idx;
1875         void *entry;
1876         struct mlx5_aso_mtr *aso_mtr;
1877
1878         if (!priv->mtr_en)
1879                 return 0;
1880         if (priv->sh->meter_aso_en) {
1881                 if (priv->mtr_idx_tbl) {
1882                         MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
1883                                 mtr_idx = *(uint32_t *)entry;
1884                                 if (mtr_idx) {
1885                                         aso_mtr =
1886                                         mlx5_aso_meter_by_idx(priv, mtr_idx);
1887                                         fm = &aso_mtr->fm;
1888                                         (void)mlx5_flow_meter_params_flush(dev,
1889                                                 fm, mtr_idx);
1890                                 }
1891                         }
1892                         mlx5_l3t_destroy(priv->mtr_idx_tbl);
1893                         priv->mtr_idx_tbl = NULL;
1894                 }
1895         } else {
1896                 TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
1897                         fm = &legacy_fm->fm;
1898                         if (mlx5_flow_meter_params_flush(dev, fm, 0))
1899                                 return -rte_mtr_error_set(error, EINVAL,
1900                                 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1901                                 NULL, "MTR object meter profile invalid.");
1902                 }
1903         }
1904         if (priv->policy_idx_tbl) {
1905                 MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
1906                         policy_idx = *(uint32_t *)entry;
1907                         sub_policy = mlx5_ipool_get
1908                                 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
1909                                 policy_idx);
1910                         if (!sub_policy)
1911                                 return -rte_mtr_error_set(error,
1912                                                 EINVAL,
1913                                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1914                                                 NULL, "MTR object "
1915                                                 "meter policy invalid.");
1916                         if (__mlx5_flow_meter_policy_delete(dev, i,
1917                                                 sub_policy->main_policy,
1918                                                 error, true))
1919                                 return -rte_mtr_error_set(error,
1920                                                 EINVAL,
1921                                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1922                                                 NULL, "MTR object "
1923                                                 "meter policy invalid.");
1924                         mlx5_free(sub_policy->main_policy);
1925                 }
1926                 mlx5_l3t_destroy(priv->policy_idx_tbl);
1927                 priv->policy_idx_tbl = NULL;
1928         }
1929         if (priv->mtr_profile_tbl) {
1930                 MLX5_L3T_FOREACH(priv->mtr_profile_tbl, i, entry) {
1931                         fmp = entry;
1932                         if (mlx5_flow_meter_profile_delete(dev, fmp->id,
1933                                                            error))
1934                                 return -rte_mtr_error_set(error, EINVAL,
1935                                         RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
1936                                                 NULL, "Fail to destroy "
1937                                                 "meter profile.");
1938                 }
1939                 mlx5_l3t_destroy(priv->mtr_profile_tbl);
1940                 priv->mtr_profile_tbl = NULL;
1941         }
1942         /* Delete default policy table. */
1943         mlx5_flow_destroy_def_policy(dev);
1944         if (priv->sh->refcnt == 1)
1945                 mlx5_flow_destroy_mtr_drop_tbls(dev);
1946         return 0;
1947 }