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