1 // SPDX-License-Identifier: BSD-3-Clause
3 * Copyright 2018 Mellanox Technologies, Ltd
8 #include <rte_malloc.h>
10 #include <rte_mtr_driver.h>
12 #include <mlx5_devx_cmds.h>
13 #include <mlx5_malloc.h>
16 #include "mlx5_flow.h"
19 * Create the meter action.
22 * Pointer to mlx5_priv.
24 * Pointer to flow meter to be converted.
27 * Pointer to the meter action on success, NULL otherwise.
30 mlx5_flow_meter_action_create(struct mlx5_priv *priv,
31 struct mlx5_flow_meter_info *fm)
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);
42 memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
43 MLX5_SET(flow_meter_parameters, fmp, valid, 1);
44 MLX5_SET(flow_meter_parameters, fmp, bucket_overflow, 1);
45 MLX5_SET(flow_meter_parameters, fmp,
46 start_color, MLX5_FLOW_COLOR_GREEN);
47 MLX5_SET(flow_meter_parameters, fmp, both_buckets_on_green, 0);
48 val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
49 MLX5_SET(flow_meter_parameters, fmp, cbs_exponent, val);
50 val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
51 MLX5_SET(flow_meter_parameters, fmp, cbs_mantissa, val);
52 val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
53 MLX5_SET(flow_meter_parameters, fmp, cir_exponent, val);
54 val = (cbs_cir & ASO_DSEG_MAN_MASK);
55 MLX5_SET(flow_meter_parameters, fmp, cir_mantissa, val);
56 val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK;
57 MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
58 val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
59 MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
61 fm->transfer ? fm->mfts->transfer.tbl->obj :
62 fm->egress ? fm->mfts->egress.tbl->obj :
63 fm->mfts->ingress.tbl->obj;
64 mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
65 mtr_init.flow_meter_parameter = fmp;
66 mtr_init.flow_meter_parameter_sz =
67 MLX5_ST_SZ_BYTES(flow_meter_parameters);
68 mtr_init.active = fm->active_state;
69 return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
78 * Find meter profile by id.
81 * Pointer to mlx5_priv.
82 * @param meter_profile_id
86 * Pointer to the profile found on success, NULL otherwise.
88 static struct mlx5_flow_meter_profile *
89 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
91 struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
92 struct mlx5_flow_meter_profile *fmp;
94 TAILQ_FOREACH(fmp, fmps, next)
95 if (meter_profile_id == fmp->id)
101 * Validate the MTR profile.
104 * Pointer to Ethernet device.
105 * @param[in] meter_profile_id
108 * Pointer to meter profile detail.
110 * Pointer to the error structure.
113 * 0 on success, a negative errno value otherwise and rte_errno is set.
116 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
117 uint32_t meter_profile_id,
118 struct rte_mtr_meter_profile *profile,
119 struct rte_mtr_error *error)
121 struct mlx5_priv *priv = dev->data->dev_private;
122 struct mlx5_flow_meter_profile *fmp;
124 /* Profile must not be NULL. */
126 return -rte_mtr_error_set(error, EINVAL,
127 RTE_MTR_ERROR_TYPE_METER_PROFILE,
128 NULL, "Meter profile is null.");
129 /* Meter profile ID must be valid. */
130 if (meter_profile_id == UINT32_MAX)
131 return -rte_mtr_error_set(error, EINVAL,
132 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
133 NULL, "Meter profile id not valid.");
134 /* Meter profile must not exist. */
135 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
137 return -rte_mtr_error_set(error, EEXIST,
138 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
140 "Meter profile already exists.");
141 if (profile->alg == RTE_MTR_SRTCM_RFC2697) {
142 if (priv->config.hca_attr.qos.flow_meter_old) {
143 /* Verify support for flow meter parameters. */
144 if (profile->srtcm_rfc2697.cir > 0 &&
145 profile->srtcm_rfc2697.cir <= MLX5_SRTCM_CIR_MAX &&
146 profile->srtcm_rfc2697.cbs > 0 &&
147 profile->srtcm_rfc2697.cbs <= MLX5_SRTCM_CBS_MAX &&
148 profile->srtcm_rfc2697.ebs <= MLX5_SRTCM_EBS_MAX)
151 return -rte_mtr_error_set
153 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
155 profile->srtcm_rfc2697.ebs ?
156 "Metering value ebs must be 0." :
157 "Invalid metering parameters.");
160 return -rte_mtr_error_set(error, ENOTSUP,
161 RTE_MTR_ERROR_TYPE_METER_PROFILE,
162 NULL, "Metering algorithm not supported.");
166 * Calculate mantissa and exponent for cir.
169 * Value to be calculated.
171 * Pointer to the mantissa.
173 * Pointer to the exp.
176 mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp)
179 int64_t delta = INT64_MAX;
184 for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
185 for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
186 _cir = (1000000000ULL * m) >> e;
187 if (llabs(cir - _cir) <= delta) {
188 delta = llabs(cir - _cir);
199 * Calculate mantissa and exponent for xbs.
202 * Value to be calculated.
204 * Pointer to the mantissa.
206 * Pointer to the exp.
209 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
214 /* Special case xbs == 0 ? both exp and matissa are 0. */
220 /* xbs = xbs_mantissa * 2^xbs_exponent */
221 _man = frexp(xbs, &_exp);
222 _man = _man * pow(2, MLX5_MAN_WIDTH);
223 _exp = _exp - MLX5_MAN_WIDTH;
224 *man = (uint8_t)ceil(_man);
229 * Fill the prm meter parameter.
232 * Pointer to meter profie to be converted.
234 * Pointer to the error structure.
237 * 0 on success, a negative errno value otherwise and rte_errno is set.
240 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
241 struct rte_mtr_error *error)
243 struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
245 uint32_t cbs_exp, cbs_man, cir_exp, cir_man;
246 uint32_t ebs_exp, ebs_man;
248 if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
249 return -rte_mtr_error_set(error, ENOTSUP,
250 RTE_MTR_ERROR_TYPE_METER_PROFILE,
251 NULL, "Metering algorithm not supported.");
252 /* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
253 mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir,
255 /* Check if cir mantissa is too large. */
256 if (exp > ASO_DSEG_CIR_EXP_MASK)
257 return -rte_mtr_error_set(error, ENOTSUP,
258 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
259 "meter profile parameter cir is"
263 /* cbs = cbs_mantissa * 2^cbs_exponent */
264 mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs,
266 /* Check if cbs mantissa is too large. */
267 if (exp > ASO_DSEG_EXP_MASK)
268 return -rte_mtr_error_set(error, ENOTSUP,
269 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
270 "meter profile parameter cbs is"
274 srtcm->cbs_cir = rte_cpu_to_be_32(cbs_exp << ASO_DSEG_CBS_EXP_OFFSET |
275 cbs_man << ASO_DSEG_CBS_MAN_OFFSET |
276 cir_exp << ASO_DSEG_CIR_EXP_OFFSET |
278 mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs,
280 /* Check if ebs mantissa is too large. */
281 if (exp > ASO_DSEG_EXP_MASK)
282 return -rte_mtr_error_set(error, ENOTSUP,
283 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
284 "meter profile parameter ebs is"
288 srtcm->ebs_eir = rte_cpu_to_be_32(ebs_exp << ASO_DSEG_EBS_EXP_OFFSET |
289 ebs_man << ASO_DSEG_EBS_MAN_OFFSET);
294 * Callback to get MTR capabilities.
297 * Pointer to Ethernet device.
299 * Pointer to save MTR capabilities.
301 * Pointer to the error structure.
304 * 0 on success, a negative errno value otherwise and rte_errno is set.
307 mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
308 struct rte_mtr_capabilities *cap,
309 struct rte_mtr_error *error __rte_unused)
311 struct mlx5_priv *priv = dev->data->dev_private;
312 struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
315 return -rte_mtr_error_set(error, ENOTSUP,
316 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
317 "Meter is not supported");
318 memset(cap, 0, sizeof(*cap));
319 if (priv->sh->meter_aso_en)
320 /* 2 meters per one ASO cache line. */
321 cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
323 cap->n_max = 1 << qattr->log_max_flow_meter;
324 cap->n_shared_max = cap->n_max;
326 cap->shared_identical = 1;
327 cap->shared_n_flows_per_mtr_max = 4 << 20;
328 /* 2M flows can share the same meter. */
329 cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
330 cap->meter_srtcm_rfc2697_n_max = qattr->flow_meter_old ? cap->n_max : 0;
331 cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
332 cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
333 RTE_MTR_STATS_N_PKTS_DROPPED;
338 * Callback to add MTR profile.
341 * Pointer to Ethernet device.
342 * @param[in] meter_profile_id
345 * Pointer to meter profile detail.
347 * Pointer to the error structure.
350 * 0 on success, a negative errno value otherwise and rte_errno is set.
353 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
354 uint32_t meter_profile_id,
355 struct rte_mtr_meter_profile *profile,
356 struct rte_mtr_error *error)
358 struct mlx5_priv *priv = dev->data->dev_private;
359 struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
360 struct mlx5_flow_meter_profile *fmp;
364 return -rte_mtr_error_set(error, ENOTSUP,
365 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
366 "Meter is not supported");
367 /* Check input params. */
368 ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
372 /* Meter profile memory allocation. */
373 fmp = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_flow_meter_profile),
374 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
376 return -rte_mtr_error_set(error, ENOMEM,
377 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
378 NULL, "Meter profile memory "
380 /* Fill profile info. */
381 fmp->id = meter_profile_id;
382 fmp->profile = *profile;
383 /* Fill the flow meter parameters for the PRM. */
384 ret = mlx5_flow_meter_param_fill(fmp, error);
388 TAILQ_INSERT_TAIL(fmps, fmp, next);
396 * Callback to delete MTR profile.
399 * Pointer to Ethernet device.
400 * @param[in] meter_profile_id
403 * Pointer to the error structure.
406 * 0 on success, a negative errno value otherwise and rte_errno is set.
409 mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
410 uint32_t meter_profile_id,
411 struct rte_mtr_error *error)
413 struct mlx5_priv *priv = dev->data->dev_private;
414 struct mlx5_flow_meter_profile *fmp;
417 return -rte_mtr_error_set(error, ENOTSUP,
418 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
419 "Meter is not supported");
420 /* Meter profile must exist. */
421 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
423 return -rte_mtr_error_set(error, ENOENT,
424 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
426 "Meter profile id is invalid.");
427 /* Check profile is unused. */
429 return -rte_mtr_error_set(error, EBUSY,
430 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
431 NULL, "Meter profile is in use.");
432 /* Remove from list. */
433 TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
439 * Modify the flow meter action.
442 * Pointer to mlx5 private data structure.
444 * Pointer to flow meter to be modified.
446 * Pointer to meter srtcm description parameter.
447 * @param[in] modify_bits
448 * The bit in srtcm to be updated.
449 * @param[in] active_state
450 * The state to be updated.
452 * 0 on success, o negative value otherwise.
455 mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
456 struct mlx5_flow_meter_info *fm,
457 const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
458 uint64_t modify_bits, uint32_t active_state, uint32_t is_enable)
460 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
461 uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
463 struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
465 struct mlx5_aso_mtr *aso_mtr = NULL;
466 uint32_t cbs_cir, ebs_eir, val;
468 if (priv->sh->meter_aso_en) {
469 fm->is_enable = !!is_enable;
470 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
471 ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
474 ret = mlx5_aso_mtr_wait(priv->sh, aso_mtr);
478 /* Fill command parameters. */
479 mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
480 mod_attr.flow_meter_parameter = in;
481 mod_attr.flow_meter_parameter_sz =
482 MLX5_ST_SZ_BYTES(flow_meter_parameters);
483 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
484 mod_attr.active = !!active_state;
488 cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
489 ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
490 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
491 val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) &
493 MLX5_SET(flow_meter_parameters, attr,
495 val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) &
497 MLX5_SET(flow_meter_parameters, attr,
500 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
501 val = (cbs_cir >> ASO_DSEG_CIR_EXP_OFFSET) &
503 MLX5_SET(flow_meter_parameters, attr,
505 val = cbs_cir & ASO_DSEG_MAN_MASK;
506 MLX5_SET(flow_meter_parameters, attr,
509 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
510 val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) &
512 MLX5_SET(flow_meter_parameters, attr,
514 val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) &
516 MLX5_SET(flow_meter_parameters, attr,
519 /* Apply modifications to meter only if it was created. */
520 if (fm->meter_action) {
521 ret = mlx5_glue->dv_modify_flow_action_meter
522 (fm->meter_action, &mod_attr,
523 rte_cpu_to_be_64(modify_bits));
527 /* Update succeedded modify meter parameters. */
528 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
529 fm->active_state = !!active_state;
544 mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
548 (stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
549 fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
553 mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
554 struct mlx5_flow_meter_info *fm,
557 struct mlx5_priv *priv = dev->data->dev_private;
558 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
559 struct mlx5_flow_meter_profile *fmp;
560 struct mlx5_legacy_flow_meter *legacy_fm = NULL;
562 /* Meter object must not have any owner. */
563 MLX5_ASSERT(!fm->ref_cnt);
564 /* Get meter profile. */
568 /* Update dependencies. */
569 __atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
570 /* Remove from list. */
571 if (!priv->sh->meter_aso_en) {
572 legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
573 TAILQ_REMOVE(fms, legacy_fm, next);
575 /* Free drop counters. */
577 mlx5_counter_free(dev, fm->drop_cnt);
578 /* Free meter flow table. */
580 mlx5_ipool_destroy(fm->flow_ipool);
581 mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
582 if (priv->sh->meter_aso_en)
583 mlx5_flow_mtr_free(dev, mtr_idx);
585 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
591 * Destroy meter rules.
594 * Pointer to Ethernet device.
595 * @param[in] meter_id
598 * Pointer to rte meter error structure.
601 * 0 on success, a negative errno value otherwise and rte_errno is set.
604 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
605 struct rte_mtr_error *error)
607 struct mlx5_priv *priv = dev->data->dev_private;
608 struct mlx5_flow_meter_info *fm;
609 uint32_t mtr_idx = 0;
612 return -rte_mtr_error_set(error, ENOTSUP,
613 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
614 "Meter is not supported");
615 /* Meter object must exist. */
616 fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
618 return -rte_mtr_error_set(error, ENOENT,
619 RTE_MTR_ERROR_TYPE_MTR_ID,
620 NULL, "Meter object id not valid.");
621 /* Meter object must not have any owner. */
623 return -rte_mtr_error_set(error, EBUSY,
624 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
625 NULL, "Meter object is being used.");
626 if (priv->sh->meter_aso_en) {
627 if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id))
628 return -rte_mtr_error_set(error, EBUSY,
629 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
630 "Fail to delete ASO Meter in index table.");
632 /* Destroy the meter profile. */
633 if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
634 return -rte_mtr_error_set(error, EINVAL,
635 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
636 NULL, "MTR object meter profile invalid.");
641 * Modify meter state.
644 * Pointer to mlx5 private data structure.
646 * Pointer to flow meter.
647 * @param[in] new_state
648 * New state to update.
650 * Pointer to rte meter error structure.
653 * 0 on success, a negative errno value otherwise and rte_errno is set.
656 mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
657 struct mlx5_flow_meter_info *fm,
659 struct rte_mtr_error *error)
661 static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
662 .cbs_cir = RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL),
665 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
666 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
669 if (new_state == MLX5_FLOW_METER_DISABLE)
670 ret = mlx5_flow_meter_action_modify(priv, fm,
671 &srtcm, modify_bits, 0, 0);
673 ret = mlx5_flow_meter_action_modify(priv, fm,
674 &fm->profile->srtcm_prm,
677 return -rte_mtr_error_set(error, -ret,
678 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
681 "Failed to enable meter." :
682 "Failed to disable meter.");
687 * Callback to enable flow meter.
690 * Pointer to Ethernet device.
691 * @param[in] meter_id
694 * Pointer to rte meter error structure.
697 * 0 on success, a negative errno value otherwise and rte_errno is set.
700 mlx5_flow_meter_enable(struct rte_eth_dev *dev,
702 struct rte_mtr_error *error)
704 struct mlx5_priv *priv = dev->data->dev_private;
705 struct mlx5_flow_meter_info *fm;
709 return -rte_mtr_error_set(error, ENOTSUP,
710 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
711 "Meter is not supported");
712 /* Meter object must exist. */
713 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
715 return -rte_mtr_error_set(error, ENOENT,
716 RTE_MTR_ERROR_TYPE_MTR_ID,
717 NULL, "Meter not found.");
718 if (fm->active_state == MLX5_FLOW_METER_ENABLE)
720 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
723 fm->active_state = MLX5_FLOW_METER_ENABLE;
728 * Callback to disable flow meter.
731 * Pointer to Ethernet device.
732 * @param[in] meter_id
735 * Pointer to rte meter error structure.
738 * 0 on success, a negative errno value otherwise and rte_errno is set.
741 mlx5_flow_meter_disable(struct rte_eth_dev *dev,
743 struct rte_mtr_error *error)
745 struct mlx5_priv *priv = dev->data->dev_private;
746 struct mlx5_flow_meter_info *fm;
750 return -rte_mtr_error_set(error, ENOTSUP,
751 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
752 "Meter is not supported");
753 /* Meter object must exist. */
754 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
756 return -rte_mtr_error_set(error, ENOENT,
757 RTE_MTR_ERROR_TYPE_MTR_ID,
758 NULL, "Meter not found.");
759 if (fm->active_state == MLX5_FLOW_METER_DISABLE)
761 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
764 fm->active_state = MLX5_FLOW_METER_DISABLE;
769 * Callback to update meter profile.
772 * Pointer to Ethernet device.
773 * @param[in] meter_id
775 * @param[in] meter_profile_id
776 * To be updated meter profile id.
778 * Pointer to rte meter error structure.
781 * 0 on success, a negative errno value otherwise and rte_errno is set.
784 mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
786 uint32_t meter_profile_id,
787 struct rte_mtr_error *error)
789 struct mlx5_priv *priv = dev->data->dev_private;
790 struct mlx5_flow_meter_profile *fmp;
791 struct mlx5_flow_meter_profile *old_fmp;
792 struct mlx5_flow_meter_info *fm;
793 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
794 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
798 return -rte_mtr_error_set(error, ENOTSUP,
799 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
800 "Meter is not supported");
801 /* Meter profile must exist. */
802 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
804 return -rte_mtr_error_set(error, ENOENT,
805 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
806 NULL, "Meter profile not found.");
807 /* Meter object must exist. */
808 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
810 return -rte_mtr_error_set(error, ENOENT,
811 RTE_MTR_ERROR_TYPE_MTR_ID,
812 NULL, "Meter not found.");
813 /* MTR object already set to meter profile id. */
814 old_fmp = fm->profile;
817 /* Update the profile. */
819 /* Update meter params in HW (if not disabled). */
820 if (fm->active_state == MLX5_FLOW_METER_DISABLE)
822 ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
823 modify_bits, fm->active_state, 1);
825 fm->profile = old_fmp;
826 return -rte_mtr_error_set(error, -ret,
827 RTE_MTR_ERROR_TYPE_MTR_PARAMS,
828 NULL, "Failed to update meter"
829 " parmeters in hardware.");
837 * Callback to update meter stats mask.
840 * Pointer to Ethernet device.
841 * @param[in] meter_id
843 * @param[in] stats_mask
844 * To be updated stats_mask.
846 * Pointer to rte meter error structure.
849 * 0 on success, a negative errno value otherwise and rte_errno is set.
852 mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
855 struct rte_mtr_error *error)
857 struct mlx5_priv *priv = dev->data->dev_private;
858 struct mlx5_flow_meter_info *fm;
861 return -rte_mtr_error_set(error, ENOTSUP,
862 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
863 "Meter is not supported");
864 /* Meter object must exist. */
865 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
867 return -rte_mtr_error_set(error, ENOENT,
868 RTE_MTR_ERROR_TYPE_MTR_ID,
869 NULL, "Meter object id not valid.");
870 mlx5_flow_meter_stats_enable_update(fm, stats_mask);
875 * Callback to read meter statistics.
878 * Pointer to Ethernet device.
879 * @param[in] meter_id
882 * Pointer to store the statistics.
883 * @param[out] stats_mask
884 * Pointer to store the stats_mask.
886 * Statistic to be cleared after read or not.
888 * Pointer to rte meter error structure.
891 * 0 on success, a negative errno value otherwise and rte_errno is set.
894 mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
896 struct rte_mtr_stats *stats,
897 uint64_t *stats_mask,
899 struct rte_mtr_error *error)
901 struct mlx5_priv *priv = dev->data->dev_private;
902 struct mlx5_flow_meter_info *fm;
908 return -rte_mtr_error_set(error, ENOTSUP,
909 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
910 "Meter is not supported");
911 /* Meter object must exist. */
912 fm = mlx5_flow_meter_find(priv, meter_id, NULL);
914 return -rte_mtr_error_set(error, ENOENT,
915 RTE_MTR_ERROR_TYPE_MTR_ID,
916 NULL, "Meter object id not valid.");
918 if (fm->bytes_dropped)
919 *stats_mask |= RTE_MTR_STATS_N_BYTES_DROPPED;
920 if (fm->pkts_dropped)
921 *stats_mask |= RTE_MTR_STATS_N_PKTS_DROPPED;
922 memset(stats, 0, sizeof(*stats));
924 ret = mlx5_counter_query(dev, fm->drop_cnt, clear, &pkts,
928 /* If need to read the packets, set it. */
929 if (fm->pkts_dropped)
930 stats->n_pkts_dropped = pkts;
931 /* If need to read the bytes, set it. */
932 if (fm->bytes_dropped)
933 stats->n_bytes_dropped = bytes;
937 return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
938 "Failed to read meter drop counters.");
941 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
942 .capabilities_get = mlx5_flow_mtr_cap_get,
943 .meter_profile_add = mlx5_flow_meter_profile_add,
944 .meter_profile_delete = mlx5_flow_meter_profile_delete,
945 .destroy = mlx5_flow_meter_destroy,
946 .meter_enable = mlx5_flow_meter_enable,
947 .meter_disable = mlx5_flow_meter_disable,
948 .meter_profile_update = mlx5_flow_meter_profile_update,
949 .meter_dscp_table_update = NULL,
950 .stats_update = mlx5_flow_meter_stats_update,
951 .stats_read = mlx5_flow_meter_stats_read,
955 * Get meter operations.
958 * Pointer to Ethernet device structure.
960 * Pointer to set the mtr operations.
966 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
968 *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
976 * Pointer to mlx5_priv.
980 * Pointer to Meter index.
983 * Pointer to the profile found on success, NULL otherwise.
985 struct mlx5_flow_meter_info *
986 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
989 struct mlx5_legacy_flow_meter *legacy_fm;
990 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
991 struct mlx5_aso_mtr *aso_mtr;
992 struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
993 union mlx5_l3t_data data;
995 if (priv->sh->meter_aso_en) {
996 rte_spinlock_lock(&mtrmng->mtrsl);
997 if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
999 rte_spinlock_unlock(&mtrmng->mtrsl);
1003 *mtr_idx = data.dword;
1004 aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
1005 /* Remove reference taken by the mlx5_l3t_get_entry. */
1006 mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
1007 rte_spinlock_unlock(&mtrmng->mtrsl);
1008 return &aso_mtr->fm;
1010 TAILQ_FOREACH(legacy_fm, fms, next)
1011 if (meter_id == legacy_fm->meter_id) {
1013 *mtr_idx = legacy_fm->idx;
1014 return &legacy_fm->fm;
1020 * Find meter by index.
1023 * Pointer to mlx5_priv.
1028 * Pointer to the profile found on success, NULL otherwise.
1030 struct mlx5_flow_meter_info *
1031 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
1033 struct mlx5_aso_mtr *aso_mtr;
1035 if (priv->sh->meter_aso_en) {
1036 aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
1037 return &aso_mtr->fm;
1039 return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
1044 * Attach meter to flow.
1045 * Unidirectional Meter creation can only be done
1046 * when flow direction is known, i.e. when calling meter_attach.
1049 * Pointer to mlx5 private data.
1051 * Pointer to flow meter.
1053 * Pointer to flow attributes.
1054 * @param [out] error
1055 * Pointer to error structure.
1058 * 0 on success, a negative errno value otherwise and rte_errno is set.
1061 mlx5_flow_meter_attach(struct mlx5_priv *priv,
1062 struct mlx5_flow_meter_info *fm,
1063 const struct rte_flow_attr *attr,
1064 struct rte_flow_error *error)
1068 if (priv->sh->meter_aso_en) {
1069 struct mlx5_aso_mtr *aso_mtr;
1071 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
1072 if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) {
1073 return rte_flow_error_set(error, ENOENT,
1074 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1076 "Timeout in meter configuration");
1078 rte_spinlock_lock(&fm->sl);
1079 if (fm->shared || !fm->ref_cnt) {
1082 rte_flow_error_set(error, EINVAL,
1083 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1084 "Meter cannot be shared");
1087 rte_spinlock_unlock(&fm->sl);
1089 rte_spinlock_lock(&fm->sl);
1090 if (fm->meter_action) {
1092 attr->transfer == fm->transfer &&
1093 attr->ingress == fm->ingress &&
1094 attr->egress == fm->egress) {
1097 rte_flow_error_set(error, EINVAL,
1098 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1100 "Meter attr not match." :
1101 "Meter cannot be shared.");
1105 fm->ingress = attr->ingress;
1106 fm->egress = attr->egress;
1107 fm->transfer = attr->transfer;
1109 /* This also creates the meter object. */
1110 fm->meter_action = mlx5_flow_meter_action_create(priv,
1112 if (!fm->meter_action) {
1117 rte_flow_error_set(error, EINVAL,
1118 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1119 "Meter action create failed.");
1123 rte_spinlock_unlock(&fm->sl);
1125 return ret ? -rte_errno : 0;
1129 * Detach meter from flow.
1132 * Pointer to mlx5 private data.
1134 * Pointer to flow meter.
1137 mlx5_flow_meter_detach(struct mlx5_priv *priv,
1138 struct mlx5_flow_meter_info *fm)
1140 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
1141 rte_spinlock_lock(&fm->sl);
1142 MLX5_ASSERT(fm->ref_cnt);
1143 if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) {
1144 mlx5_glue->destroy_flow_action(fm->meter_action);
1145 fm->meter_action = NULL;
1150 rte_spinlock_unlock(&fm->sl);
1158 * Flush meter configuration.
1161 * Pointer to Ethernet device.
1163 * Pointer to rte meter error structure.
1166 * 0 on success, a negative errno value otherwise and rte_errno is set.
1169 mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
1171 struct mlx5_priv *priv = dev->data->dev_private;
1172 struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
1173 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
1174 struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
1175 struct mlx5_flow_meter_profile *fmp;
1176 struct mlx5_legacy_flow_meter *legacy_fm;
1177 struct mlx5_flow_meter_info *fm;
1178 struct mlx5_aso_mtr_pool *mtr_pool;
1180 uint32_t i, offset, mtr_idx;
1182 if (priv->sh->meter_aso_en) {
1183 i = mtrmng->n_valid;
1185 mtr_pool = mtrmng->pools[i];
1186 for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
1188 fm = &mtr_pool->mtrs[offset].fm;
1189 mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
1190 if (mlx5_flow_meter_params_flush(dev,
1192 return -rte_mtr_error_set
1194 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1195 NULL, "MTR object meter profile invalid.");
1199 TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
1200 fm = &legacy_fm->fm;
1201 if (mlx5_flow_meter_params_flush(dev, fm, 0))
1202 return -rte_mtr_error_set(error, EINVAL,
1203 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1204 NULL, "MTR object meter profile invalid.");
1207 TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
1209 MLX5_ASSERT(!fmp->ref_cnt);
1210 /* Remove from list. */
1211 TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);