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 *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 */ 85 static struct mlx5_flow_meter_profile * 86 mlx5_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 */ 112 static int 113 mlx5_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.flow_meter_old) { 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 */ 172 static void 173 mlx5_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 */ 205 static void 206 mlx5_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 */ 236 static int 237 mlx5_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 */ 296 static int 297 mlx5_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->flow_meter_old ? 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 */ 339 static int 340 mlx5_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; 377 error: 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 */ 395 static int 396 mlx5_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 */ 434 static inline enum rte_mtr_error_type 435 action2error(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 */ 465 static int 466 mlx5_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 */ 521 static int 522 mlx5_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 */ 619 static int 620 mlx5_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; 684 error: 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 */ 710 static int 711 mlx5_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 */ 773 static int 774 mlx5_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 */ 821 static int 822 mlx5_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 */ 862 static int 863 mlx5_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 */ 905 static int 906 mlx5_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 */ 973 static int 974 mlx5_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 */ 1015 static int 1016 mlx5_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; 1088 error: 1089 return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL, 1090 "Failed to read policer counters."); 1091 } 1092 1093 static 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 */ 1119 int 1120 mlx5_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 */ 1137 struct mlx5_flow_meter * 1138 mlx5_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 */ 1165 struct mlx5_flow_meter * 1166 mlx5_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 */ 1222 void 1223 mlx5_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 */ 1252 int 1253 mlx5_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