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