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        rte_spinlock_init(&fm->sl);
 683        return 0;
 684error:
 685        mlx5_flow_destroy_policer_rules(dev, fm, &attr);
 686        mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
 687        /* Free policer counters. */
 688        for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
 689                if (fm->policer_stats.cnt[i])
 690                        mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
 691        mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
 692        return -rte_mtr_error_set(error, -ret,
 693                                  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
 694                                  NULL, "Failed to create devx meter.");
 695}
 696
 697/**
 698 * Destroy meter rules.
 699 *
 700 * @param[in] dev
 701 *   Pointer to Ethernet device.
 702 * @param[in] meter_id
 703 *   Meter id.
 704 * @param[out] error
 705 *   Pointer to rte meter error structure.
 706 *
 707 * @return
 708 *   0 on success, a negative errno value otherwise and rte_errno is set.
 709 */
 710static int
 711mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 712                        struct rte_mtr_error *error)
 713{
 714        struct mlx5_priv *priv = dev->data->dev_private;
 715        struct mlx5_flow_meters *fms = &priv->flow_meters;
 716        struct mlx5_flow_meter_profile *fmp;
 717        struct mlx5_flow_meter *fm;
 718        const struct rte_flow_attr attr = {
 719                                .ingress = 1,
 720                                .egress = 1,
 721                                .transfer = priv->config.dv_esw_en ? 1 : 0,
 722                        };
 723        unsigned int i;
 724
 725        if (!priv->mtr_en)
 726                return -rte_mtr_error_set(error, ENOTSUP,
 727                                          RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 728                                          "Meter is not supported");
 729        /* Meter object must exist. */
 730        fm = mlx5_flow_meter_find(priv, meter_id);
 731        if (fm == NULL)
 732                return -rte_mtr_error_set(error, ENOENT,
 733                                          RTE_MTR_ERROR_TYPE_MTR_ID,
 734                                          NULL, "Meter object id not valid.");
 735        /* Meter object must not have any owner. */
 736        if (fm->ref_cnt > 0)
 737                return -rte_mtr_error_set(error, EBUSY,
 738                                          RTE_MTR_ERROR_TYPE_UNSPECIFIED,
 739                                          NULL, "Meter object is being used.");
 740        /* Get the meter profile. */
 741        fmp = fm->profile;
 742        MLX5_ASSERT(fmp);
 743        /* Update dependencies. */
 744        fmp->ref_cnt--;
 745        /* Remove from the flow meter list. */
 746        TAILQ_REMOVE(fms, fm, next);
 747        /* Free policer counters. */
 748        for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
 749                if (fm->policer_stats.cnt[i])
 750                        mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
 751        /* Free meter flow table */
 752        mlx5_flow_destroy_policer_rules(dev, fm, &attr);
 753        mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
 754        mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], fm->idx);
 755        return 0;
 756}
 757
 758/**
 759 * Modify meter state.
 760 *
 761 * @param[in] priv
 762 *   Pointer to mlx5 private data structure.
 763 * @param[in] fm
 764 *   Pointer to flow meter.
 765 * @param[in] new_state
 766 *   New state to update.
 767 * @param[out] error
 768 *   Pointer to rte meter error structure.
 769 *
 770 * @return
 771 *   0 on success, a negative errno value otherwise and rte_errno is set.
 772 */
 773static int
 774mlx5_flow_meter_modify_state(struct mlx5_priv *priv,
 775                             struct mlx5_flow_meter *fm,
 776                             uint32_t new_state,
 777                             struct rte_mtr_error *error)
 778{
 779        static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
 780                .cbs_exponent = 20,
 781                .cbs_mantissa = 191,
 782                .cir_exponent = 0,
 783                .cir_mantissa = 200,
 784                .ebs_exponent = 0,
 785                .ebs_mantissa = 0,
 786        };
 787        uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
 788                               MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
 789        int ret;
 790
 791        if (new_state == MLX5_FLOW_METER_DISABLE)
 792                ret = mlx5_flow_meter_action_modify(priv, fm, &srtcm,
 793                                                    modify_bits, 0);
 794        else
 795                ret = mlx5_flow_meter_action_modify(priv, fm,
 796                                                   &fm->profile->srtcm_prm,
 797                                                    modify_bits, 0);
 798        if (ret)
 799                return -rte_mtr_error_set(error, -ret,
 800                                          RTE_MTR_ERROR_TYPE_MTR_PARAMS,
 801                                          NULL,
 802                                          new_state ?
 803                                          "Failed to enable meter." :
 804                                          "Failed to disable meter.");
 805        return 0;
 806}
 807
 808/**
 809 * Callback to enable flow meter.
 810 *
 811 * @param[in] dev
 812 *   Pointer to Ethernet device.
 813 * @param[in] meter_id
 814 *   Meter id.
 815 * @param[out] error
 816 *   Pointer to rte meter error structure.
 817 *
 818 * @return
 819 *   0 on success, a negative errno value otherwise and rte_errno is set.
 820 */
 821static int
 822mlx5_flow_meter_enable(struct rte_eth_dev *dev,
 823                       uint32_t meter_id,
 824                       struct rte_mtr_error *error)
 825{
 826        struct mlx5_priv *priv = dev->data->dev_private;
 827        struct mlx5_flow_meter *fm;
 828        int ret;
 829
 830        if (!priv->mtr_en)
 831                return -rte_mtr_error_set(error, ENOTSUP,
 832                                          RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 833                                          "Meter is not supported");
 834        /* Meter object must exist. */
 835        fm = mlx5_flow_meter_find(priv, meter_id);
 836        if (fm == NULL)
 837                return -rte_mtr_error_set(error, ENOENT,
 838                                          RTE_MTR_ERROR_TYPE_MTR_ID,
 839                                          NULL, "Meter not found.");
 840        if (fm->active_state == MLX5_FLOW_METER_ENABLE)
 841                return 0;
 842        ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
 843                                           error);
 844        if (!ret)
 845                fm->active_state = MLX5_FLOW_METER_ENABLE;
 846        return ret;
 847}
 848
 849/**
 850 * Callback to disable flow meter.
 851 *
 852 * @param[in] dev
 853 *   Pointer to Ethernet device.
 854 * @param[in] meter_id
 855 *   Meter id.
 856 * @param[out] error
 857 *   Pointer to rte meter error structure.
 858 *
 859 * @return
 860 *   0 on success, a negative errno value otherwise and rte_errno is set.
 861 */
 862static int
 863mlx5_flow_meter_disable(struct rte_eth_dev *dev,
 864                        uint32_t meter_id,
 865                        struct rte_mtr_error *error)
 866{
 867        struct mlx5_priv *priv = dev->data->dev_private;
 868        struct mlx5_flow_meter *fm;
 869        int ret;
 870
 871        if (!priv->mtr_en)
 872                return -rte_mtr_error_set(error, ENOTSUP,
 873                                          RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 874                                          "Meter is not supported");
 875        /* Meter object must exist. */
 876        fm = mlx5_flow_meter_find(priv, meter_id);
 877        if (fm == NULL)
 878                return -rte_mtr_error_set(error, ENOENT,
 879                                          RTE_MTR_ERROR_TYPE_MTR_ID,
 880                                          NULL, "Meter not found.");
 881        if (fm->active_state == MLX5_FLOW_METER_DISABLE)
 882                return 0;
 883        ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
 884                                           error);
 885        if (!ret)
 886                fm->active_state = MLX5_FLOW_METER_DISABLE;
 887        return ret;
 888}
 889
 890/**
 891 * Callback to update meter profile.
 892 *
 893 * @param[in] dev
 894 *   Pointer to Ethernet device.
 895 * @param[in] meter_id
 896 *   Meter id.
 897 * @param[in] meter_profile_id
 898 *   To be updated meter profile id.
 899 * @param[out] error
 900 *   Pointer to rte meter error structure.
 901 *
 902 * @return
 903 *   0 on success, a negative errno value otherwise and rte_errno is set.
 904 */
 905static int
 906mlx5_flow_meter_profile_update(struct rte_eth_dev *dev,
 907                               uint32_t meter_id,
 908                               uint32_t meter_profile_id,
 909                               struct rte_mtr_error *error)
 910{
 911        struct mlx5_priv *priv = dev->data->dev_private;
 912        struct mlx5_flow_meter_profile *fmp;
 913        struct mlx5_flow_meter_profile *old_fmp;
 914        struct mlx5_flow_meter *fm;
 915        uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
 916                               MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
 917        int ret;
 918
 919        if (!priv->mtr_en)
 920                return -rte_mtr_error_set(error, ENOTSUP,
 921                                          RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 922                                          "Meter is not supported");
 923        /* Meter profile must exist. */
 924        fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
 925        if (fmp == NULL)
 926                return -rte_mtr_error_set(error, ENOENT,
 927                                          RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
 928                                          NULL, "Meter profile not found.");
 929        /* Meter object must exist. */
 930        fm = mlx5_flow_meter_find(priv, meter_id);
 931        if (fm == NULL)
 932                return -rte_mtr_error_set(error, ENOENT,
 933                                          RTE_MTR_ERROR_TYPE_MTR_ID,
 934                                          NULL, "Meter not found.");
 935        /* MTR object already set to meter profile id. */
 936        old_fmp = fm->profile;
 937        if (fmp == old_fmp)
 938                return 0;
 939        /* Update the profile. */
 940        fm->profile = fmp;
 941        /* Update meter params in HW (if not disabled). */
 942        if (fm->active_state == MLX5_FLOW_METER_DISABLE)
 943                return 0;
 944        ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
 945                                              modify_bits, fm->active_state);
 946        if (ret) {
 947                fm->profile = old_fmp;
 948                return -rte_mtr_error_set(error, -ret,
 949                                          RTE_MTR_ERROR_TYPE_MTR_PARAMS,
 950                                          NULL, "Failed to update meter"
 951                                          " parmeters in hardware.");
 952        }
 953        old_fmp->ref_cnt--;
 954        fmp->ref_cnt++;
 955        return 0;
 956}
 957
 958/**
 959 * Callback to update meter stats mask.
 960 *
 961 * @param[in] dev
 962 *   Pointer to Ethernet device.
 963 * @param[in] meter_id
 964 *   Meter id.
 965 * @param[in] stats_mask
 966 *   To be updated stats_mask.
 967 * @param[out] error
 968 *   Pointer to rte meter error structure.
 969 *
 970 * @return
 971 *   0 on success, a negative errno value otherwise and rte_errno is set.
 972 */
 973static int
 974mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
 975                             uint32_t meter_id,
 976                             uint64_t stats_mask,
 977                             struct rte_mtr_error *error)
 978{
 979        struct mlx5_priv *priv = dev->data->dev_private;
 980        struct mlx5_flow_meter *fm;
 981
 982        if (!priv->mtr_en)
 983                return -rte_mtr_error_set(error, ENOTSUP,
 984                                          RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 985                                          "Meter is not supported");
 986        /* Meter object must exist. */
 987        fm = mlx5_flow_meter_find(priv, meter_id);
 988        if (fm == NULL)
 989                return -rte_mtr_error_set(error, ENOENT,
 990                                          RTE_MTR_ERROR_TYPE_MTR_ID,
 991                                          NULL, "Meter object id not valid.");
 992        fm->policer_stats.stats_mask = stats_mask;
 993        return 0;
 994}
 995
 996/**
 997 * Callback to read meter statistics.
 998 *
 999 * @param[in] dev
1000 *   Pointer to Ethernet device.
1001 * @param[in] meter_id
1002 *   Meter id.
1003 * @param[out] stats
1004 *   Pointer to store the statistics.
1005 * @param[out] stats_mask
1006 *   Pointer to store the stats_mask.
1007 * @param[in] clear
1008 *   Statistic to be cleared after read or not.
1009 * @param[out] error
1010 *   Pointer to rte meter error structure.
1011 *
1012 * @return
1013 *   0 on success, a negative errno value otherwise and rte_errno is set.
1014 */
1015static int
1016mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
1017                           uint32_t meter_id,
1018                           struct rte_mtr_stats *stats,
1019                           uint64_t *stats_mask,
1020                           int clear,
1021                           struct rte_mtr_error *error)
1022{
1023        static uint64_t meter2mask[RTE_MTR_DROPPED + 1] = {
1024                RTE_MTR_STATS_N_PKTS_GREEN | RTE_MTR_STATS_N_BYTES_GREEN,
1025                RTE_MTR_STATS_N_PKTS_YELLOW | RTE_MTR_STATS_N_BYTES_YELLOW,
1026                RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_BYTES_RED,
1027                RTE_MTR_STATS_N_PKTS_DROPPED | RTE_MTR_STATS_N_BYTES_DROPPED
1028        };
1029        struct mlx5_priv *priv = dev->data->dev_private;
1030        struct mlx5_flow_meter *fm;
1031        struct mlx5_flow_policer_stats *ps;
1032        uint64_t pkts_dropped = 0;
1033        uint64_t bytes_dropped = 0;
1034        uint64_t pkts;
1035        uint64_t bytes;
1036        int i;
1037        int ret = 0;
1038
1039        if (!priv->mtr_en)
1040                return -rte_mtr_error_set(error, ENOTSUP,
1041                                          RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
1042                                          "Meter is not supported");
1043        /* Meter object must exist. */
1044        fm = mlx5_flow_meter_find(priv, meter_id);
1045        if (fm == NULL)
1046                return -rte_mtr_error_set(error, ENOENT,
1047                                          RTE_MTR_ERROR_TYPE_MTR_ID,
1048                                          NULL, "Meter object id not valid.");
1049        ps = &fm->policer_stats;
1050        *stats_mask = ps->stats_mask;
1051        for (i = 0; i < RTE_MTR_DROPPED; i++) {
1052                if (*stats_mask & meter2mask[i]) {
1053                        ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
1054                                                 &bytes);
1055                        if (ret)
1056                                goto error;
1057                        if (fm->action[i] == MTR_POLICER_ACTION_DROP) {
1058                                pkts_dropped += pkts;
1059                                bytes_dropped += bytes;
1060                        }
1061                        /* If need to read the packets, set it. */
1062                        if ((1 << i) & (*stats_mask & meter2mask[i]))
1063                                stats->n_pkts[i] = pkts;
1064                        /* If need to read the bytes, set it. */
1065                        if ((1 << (RTE_MTR_DROPPED + 1 + i)) &
1066                           (*stats_mask & meter2mask[i]))
1067                                stats->n_bytes[i] = bytes;
1068                }
1069        }
1070        /* Dropped packets/bytes are treated differently. */
1071        if (*stats_mask & meter2mask[i]) {
1072                ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
1073                                         &bytes);
1074                if (ret)
1075                        goto error;
1076                pkts += pkts_dropped;
1077                bytes += bytes_dropped;
1078                /* If need to read the packets, set it. */
1079                if ((*stats_mask & meter2mask[i]) &
1080                   RTE_MTR_STATS_N_PKTS_DROPPED)
1081                        stats->n_pkts_dropped = pkts;
1082                /* If need to read the bytes, set it. */
1083                if ((*stats_mask & meter2mask[i]) &
1084                   RTE_MTR_STATS_N_BYTES_DROPPED)
1085                        stats->n_bytes_dropped = bytes;
1086        }
1087        return 0;
1088error:
1089        return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
1090                                 "Failed to read policer counters.");
1091}
1092
1093static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
1094        .capabilities_get = mlx5_flow_mtr_cap_get,
1095        .meter_profile_add = mlx5_flow_meter_profile_add,
1096        .meter_profile_delete = mlx5_flow_meter_profile_delete,
1097        .create = mlx5_flow_meter_create,
1098        .destroy = mlx5_flow_meter_destroy,
1099        .meter_enable = mlx5_flow_meter_enable,
1100        .meter_disable = mlx5_flow_meter_disable,
1101        .meter_profile_update = mlx5_flow_meter_profile_update,
1102        .meter_dscp_table_update = NULL,
1103        .policer_actions_update = NULL,
1104        .stats_update = mlx5_flow_meter_stats_update,
1105        .stats_read = mlx5_flow_meter_stats_read,
1106};
1107
1108/**
1109 * Get meter operations.
1110 *
1111 * @param dev
1112 *   Pointer to Ethernet device structure.
1113 * @param arg
1114 *   Pointer to set the mtr operations.
1115 *
1116 * @return
1117 *   Always 0.
1118 */
1119int
1120mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
1121{
1122        *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
1123        return 0;
1124}
1125
1126/**
1127 * Find meter by id.
1128 *
1129 * @param priv
1130 *   Pointer to mlx5_priv.
1131 * @param meter_id
1132 *   Meter id.
1133 *
1134 * @return
1135 *   Pointer to the profile found on success, NULL otherwise.
1136 */
1137struct mlx5_flow_meter *
1138mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id)
1139{
1140        struct mlx5_flow_meters *fms = &priv->flow_meters;
1141        struct mlx5_flow_meter *fm;
1142
1143        TAILQ_FOREACH(fm, fms, next)
1144                if (meter_id == fm->meter_id)
1145                        return fm;
1146        return NULL;
1147}
1148
1149/**
1150 * Attach meter to flow.
1151 * Unidirectional Meter creation can only be done
1152 * when flow direction is known, i.e. when calling meter_attach.
1153 *
1154 * @param [in] priv
1155 *  Pointer to mlx5 private data.
1156 * @param [in] meter_id
1157 *  Flow meter id.
1158 * @param [in] attr
1159 *  Pointer to flow attributes.
1160 * @param [out] error
1161 *  Pointer to error structure.
1162 *
1163 * @return the flow meter pointer, NULL otherwise.
1164 */
1165struct mlx5_flow_meter *
1166mlx5_flow_meter_attach(struct mlx5_priv *priv, uint32_t meter_id,
1167                       const struct rte_flow_attr *attr,
1168                       struct rte_flow_error *error)
1169{
1170        struct mlx5_flow_meter *fm;
1171        int ret = 0;
1172
1173        fm = mlx5_flow_meter_find(priv, meter_id);
1174        if (fm == NULL) {
1175                rte_flow_error_set(error, ENOENT,
1176                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1177                                   "Meter object id not valid");
1178                return fm;
1179        }
1180        rte_spinlock_lock(&fm->sl);
1181        if (fm->mfts->meter_action) {
1182                if (fm->shared &&
1183                    attr->transfer == fm->transfer &&
1184                    attr->ingress == fm->ingress &&
1185                    attr->egress == fm->egress)
1186                        fm->ref_cnt++;
1187                else
1188                        ret = -1;
1189        } else {
1190                fm->ingress = attr->ingress;
1191                fm->egress = attr->egress;
1192                fm->transfer = attr->transfer;
1193                 fm->ref_cnt = 1;
1194                /* This also creates the meter object. */
1195                fm->mfts->meter_action = mlx5_flow_meter_action_create(priv,
1196                                                                       fm);
1197                if (!fm->mfts->meter_action) {
1198                        fm->ref_cnt = 0;
1199                        fm->ingress = 0;
1200                        fm->egress = 0;
1201                        fm->transfer = 0;
1202                        ret = -1;
1203                        DRV_LOG(ERR, "Meter action create failed.");
1204                }
1205        }
1206        rte_spinlock_unlock(&fm->sl);
1207        if (ret)
1208                rte_flow_error_set(error, EINVAL,
1209                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1210                                   fm->mfts->meter_action ?
1211                                   "Meter attr not match" :
1212                                   "Meter action create failed");
1213        return ret ? NULL : fm;
1214}
1215
1216/**
1217 * Detach meter from flow.
1218 *
1219 * @param [in] fm
1220 *  Pointer to flow meter.
1221 */
1222void
1223mlx5_flow_meter_detach(struct mlx5_flow_meter *fm)
1224{
1225#ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
1226        rte_spinlock_lock(&fm->sl);
1227        MLX5_ASSERT(fm->ref_cnt);
1228        if (--fm->ref_cnt == 0) {
1229                mlx5_glue->destroy_flow_action(fm->mfts->meter_action);
1230                fm->mfts->meter_action = NULL;
1231                fm->ingress = 0;
1232                fm->egress = 0;
1233                fm->transfer = 0;
1234        }
1235        rte_spinlock_unlock(&fm->sl);
1236#else
1237        (void)fm;
1238#endif
1239}
1240
1241/**
1242 * Flush meter configuration.
1243 *
1244 * @param[in] dev
1245 *   Pointer to Ethernet device.
1246 * @param[out] error
1247 *   Pointer to rte meter error structure.
1248 *
1249 * @return
1250 *   0 on success, a negative errno value otherwise and rte_errno is set.
1251 */
1252int
1253mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
1254{
1255        struct mlx5_priv *priv = dev->data->dev_private;
1256        struct mlx5_flow_meters *fms = &priv->flow_meters;
1257        struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
1258        struct mlx5_flow_meter_profile *fmp;
1259        struct mlx5_flow_meter *fm;
1260        const struct rte_flow_attr attr = {
1261                                .ingress = 1,
1262                                .egress = 1,
1263                                .transfer = priv->config.dv_esw_en ? 1 : 0,
1264                        };
1265        void *tmp;
1266        uint32_t i;
1267
1268        TAILQ_FOREACH_SAFE(fm, fms, next, tmp) {
1269                /* Meter object must not have any owner. */
1270                MLX5_ASSERT(!fm->ref_cnt);
1271                /* Get meter profile. */
1272                fmp = fm->profile;
1273                if (fmp == NULL)
1274                        return -rte_mtr_error_set(error, EINVAL,
1275                                RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
1276                                NULL, "MTR object meter profile invalid.");
1277                /* Update dependencies. */
1278                fmp->ref_cnt--;
1279                /* Remove from list. */
1280                TAILQ_REMOVE(fms, fm, next);
1281                /* Free policer counters. */
1282                for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
1283                        if (fm->policer_stats.cnt[i])
1284                                mlx5_counter_free(dev,
1285                                                  fm->policer_stats.cnt[i]);
1286                /* Free meter flow table. */
1287                mlx5_flow_destroy_policer_rules(dev, fm, &attr);
1288                mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
1289                mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], fm->idx);
1290        }
1291        TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
1292                /* Check unused. */
1293                MLX5_ASSERT(!fmp->ref_cnt);
1294                /* Remove from list. */
1295                TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
1296                mlx5_free(fmp);
1297        }
1298        return 0;
1299}
1300