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