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 static int mlx5_flow_meter_disable(struct rte_eth_dev *dev, 19 uint32_t meter_id, struct rte_mtr_error *error); 20 21 /** 22 * Create the meter action. 23 * 24 * @param priv 25 * Pointer to mlx5_priv. 26 * @param[in] fm 27 * Pointer to flow meter to be converted. 28 * 29 * @return 30 * Pointer to the meter action on success, NULL otherwise. 31 */ 32 static void * 33 mlx5_flow_meter_action_create(struct mlx5_priv *priv, 34 struct mlx5_flow_meter_info *fm) 35 { 36 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER 37 struct mlx5dv_dr_flow_meter_attr mtr_init; 38 uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)]; 39 struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = 40 &fm->profile->srtcm_prm; 41 uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir); 42 uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir); 43 uint32_t val; 44 enum mlx5_meter_domain domain = 45 fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER : 46 fm->egress ? MLX5_MTR_DOMAIN_EGRESS : 47 MLX5_MTR_DOMAIN_INGRESS; 48 struct mlx5_flow_meter_def_policy *def_policy = 49 priv->sh->mtrmng->def_policy[domain]; 50 51 memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters)); 52 MLX5_SET(flow_meter_parameters, fmp, valid, 1); 53 MLX5_SET(flow_meter_parameters, fmp, bucket_overflow, 1); 54 MLX5_SET(flow_meter_parameters, fmp, 55 start_color, MLX5_FLOW_COLOR_GREEN); 56 MLX5_SET(flow_meter_parameters, fmp, both_buckets_on_green, 0); 57 val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK; 58 MLX5_SET(flow_meter_parameters, fmp, cbs_exponent, val); 59 val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK; 60 MLX5_SET(flow_meter_parameters, fmp, cbs_mantissa, val); 61 val = (cbs_cir >> ASO_DSEG_XIR_EXP_OFFSET) & ASO_DSEG_EXP_MASK; 62 MLX5_SET(flow_meter_parameters, fmp, cir_exponent, val); 63 val = (cbs_cir & ASO_DSEG_MAN_MASK); 64 MLX5_SET(flow_meter_parameters, fmp, cir_mantissa, val); 65 val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & ASO_DSEG_EXP_MASK; 66 MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val); 67 val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK; 68 MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val); 69 mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj; 70 mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0; 71 mtr_init.flow_meter_parameter = fmp; 72 mtr_init.flow_meter_parameter_sz = 73 MLX5_ST_SZ_BYTES(flow_meter_parameters); 74 mtr_init.active = fm->active_state; 75 return mlx5_glue->dv_create_flow_action_meter(&mtr_init); 76 #else 77 (void)priv; 78 (void)fm; 79 return NULL; 80 #endif 81 } 82 83 /** 84 * Find meter profile by id. 85 * 86 * @param priv 87 * Pointer to mlx5_priv. 88 * @param meter_profile_id 89 * Meter profile id. 90 * 91 * @return 92 * Pointer to the profile found on success, NULL otherwise. 93 */ 94 static struct mlx5_flow_meter_profile * 95 mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id) 96 { 97 struct mlx5_flow_meter_profile *fmp; 98 union mlx5_l3t_data data; 99 int32_t ret; 100 101 if (mlx5_l3t_get_entry(priv->mtr_profile_tbl, 102 meter_profile_id, &data) || !data.ptr) 103 return NULL; 104 fmp = data.ptr; 105 /* Remove reference taken by the mlx5_l3t_get_entry. */ 106 ret = mlx5_l3t_clear_entry(priv->mtr_profile_tbl, 107 meter_profile_id); 108 if (!ret || ret == -1) 109 return NULL; 110 return fmp; 111 } 112 113 /** 114 * Validate the MTR profile. 115 * 116 * @param[in] dev 117 * Pointer to Ethernet device. 118 * @param[in] meter_profile_id 119 * Meter profile id. 120 * @param[in] profile 121 * Pointer to meter profile detail. 122 * @param[out] error 123 * Pointer to the error structure. 124 * 125 * @return 126 * 0 on success, a negative errno value otherwise and rte_errno is set. 127 */ 128 static int 129 mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev, 130 uint32_t meter_profile_id, 131 struct rte_mtr_meter_profile *profile, 132 struct rte_mtr_error *error) 133 { 134 struct mlx5_priv *priv = dev->data->dev_private; 135 struct mlx5_flow_meter_profile *fmp; 136 uint32_t ls_factor; 137 int ret; 138 uint64_t cir, cbs; 139 uint64_t eir, ebs; 140 uint64_t pir, pbs; 141 142 /* Profile must not be NULL. */ 143 if (profile == NULL) 144 return -rte_mtr_error_set(error, EINVAL, 145 RTE_MTR_ERROR_TYPE_METER_PROFILE, 146 NULL, "Meter profile is null."); 147 /* Meter profile ID must be valid. */ 148 if (meter_profile_id == UINT32_MAX) 149 return -rte_mtr_error_set(error, EINVAL, 150 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 151 NULL, "Meter profile id not valid."); 152 /* Meter profile must not exist. */ 153 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); 154 if (fmp) 155 return -rte_mtr_error_set(error, EEXIST, 156 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 157 NULL, 158 "Meter profile already exists."); 159 if (!priv->sh->meter_aso_en) { 160 /* Old version is even not supported. */ 161 if (!priv->sh->cdev->config.hca_attr.qos.flow_meter_old) 162 return -rte_mtr_error_set(error, ENOTSUP, 163 RTE_MTR_ERROR_TYPE_METER_PROFILE, 164 NULL, "Metering is not supported."); 165 /* Old FW metering only supports srTCM. */ 166 if (profile->alg != RTE_MTR_SRTCM_RFC2697) { 167 return -rte_mtr_error_set(error, ENOTSUP, 168 RTE_MTR_ERROR_TYPE_METER_PROFILE, 169 NULL, "Metering algorithm is not supported."); 170 } else if (profile->srtcm_rfc2697.ebs) { 171 /* EBS is not supported for old metering. */ 172 return -rte_mtr_error_set(error, ENOTSUP, 173 RTE_MTR_ERROR_TYPE_METER_PROFILE, 174 NULL, "EBS is not supported."); 175 } 176 if (profile->packet_mode) 177 return -rte_mtr_error_set(error, ENOTSUP, 178 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL, 179 "Metering algorithm packet mode is not supported."); 180 } 181 ls_factor = profile->packet_mode ? MLX5_MTRS_PPS_MAP_BPS_SHIFT : 0; 182 switch (profile->alg) { 183 case RTE_MTR_SRTCM_RFC2697: 184 cir = profile->srtcm_rfc2697.cir << ls_factor; 185 cbs = profile->srtcm_rfc2697.cbs << ls_factor; 186 ebs = profile->srtcm_rfc2697.ebs << ls_factor; 187 /* EBS could be zero for old metering. */ 188 if (cir > 0 && cir <= MLX5_SRTCM_XIR_MAX && 189 cbs > 0 && cbs <= MLX5_SRTCM_XBS_MAX && 190 ebs <= MLX5_SRTCM_XBS_MAX) { 191 ret = 0; 192 } else { 193 ret = -rte_mtr_error_set(error, ENOTSUP, 194 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 195 "Profile values out of range."); 196 } 197 break; 198 case RTE_MTR_TRTCM_RFC2698: 199 cir = profile->trtcm_rfc2698.cir << ls_factor; 200 cbs = profile->trtcm_rfc2698.cbs << ls_factor; 201 pir = profile->trtcm_rfc2698.pir << ls_factor; 202 pbs = profile->trtcm_rfc2698.pbs << ls_factor; 203 if (cir > 0 && cir <= MLX5_SRTCM_XIR_MAX && 204 cbs > 0 && cbs <= MLX5_SRTCM_XBS_MAX && 205 pir >= cir && pir <= (MLX5_SRTCM_XIR_MAX * 2) && 206 pbs >= cbs && pbs <= (MLX5_SRTCM_XBS_MAX * 2)) { 207 ret = 0; 208 } else { 209 ret = -rte_mtr_error_set(error, ENOTSUP, 210 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 211 "Profile values out of range."); 212 } 213 break; 214 case RTE_MTR_TRTCM_RFC4115: 215 cir = profile->trtcm_rfc4115.cir << ls_factor; 216 cbs = profile->trtcm_rfc4115.cbs << ls_factor; 217 eir = profile->trtcm_rfc4115.eir << ls_factor; 218 ebs = profile->trtcm_rfc4115.ebs << ls_factor; 219 if (cir > 0 && cir <= MLX5_SRTCM_XIR_MAX && 220 cbs > 0 && cbs <= MLX5_SRTCM_XBS_MAX && 221 eir <= MLX5_SRTCM_XIR_MAX && ebs <= MLX5_SRTCM_XBS_MAX) { 222 ret = 0; 223 } else { 224 ret = -rte_mtr_error_set(error, ENOTSUP, 225 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 226 "Profile values out of range."); 227 } 228 break; 229 default: 230 ret = -rte_mtr_error_set(error, ENOTSUP, 231 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 232 "Unknown metering algorithm."); 233 break; 234 } 235 return ret; 236 } 237 238 /* 239 * Calculate mantissa and exponent for cir / eir. 240 * 241 * @param[in] xir 242 * Value to be calculated. 243 * @param[out] man 244 * Pointer to the mantissa. 245 * @param[out] exp 246 * Pointer to the exp. 247 */ 248 static inline void 249 mlx5_flow_meter_xir_man_exp_calc(int64_t xir, uint8_t *man, uint8_t *exp) 250 { 251 int64_t _xir; 252 int64_t delta = INT64_MAX; 253 uint8_t _man = 0; 254 uint8_t _exp = 0; 255 uint64_t m, e; 256 257 /* Special case xir == 0 ? both exp and mantissa are 0. */ 258 if (xir == 0) { 259 *man = 0; 260 *exp = 0; 261 return; 262 } 263 for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */ 264 for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */ 265 _xir = (1000000000ULL * m) >> e; 266 if (llabs(xir - _xir) <= delta) { 267 delta = llabs(xir - _xir); 268 _man = m; 269 _exp = e; 270 } 271 } 272 } 273 *man = _man; 274 *exp = _exp; 275 } 276 277 /* 278 * Calculate mantissa and exponent for xbs. 279 * 280 * @param[in] xbs 281 * Value to be calculated. 282 * @param[out] man 283 * Pointer to the mantissa. 284 * @param[out] exp 285 * Pointer to the exp. 286 */ 287 static inline void 288 mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp) 289 { 290 int _exp; 291 double _man; 292 293 /* Special case xbs == 0 ? both exp and mantissa are 0. */ 294 if (xbs == 0) { 295 *man = 0; 296 *exp = 0; 297 return; 298 } 299 /* xbs = xbs_mantissa * 2^xbs_exponent */ 300 _man = frexp(xbs, &_exp); 301 if (_exp >= MLX5_MAN_WIDTH) { 302 _man = _man * pow(2, MLX5_MAN_WIDTH); 303 _exp = _exp - MLX5_MAN_WIDTH; 304 } 305 *man = (uint8_t)ceil(_man); 306 *exp = _exp; 307 } 308 309 /** 310 * Fill the prm meter parameter. 311 * 312 * @param[in,out] fmp 313 * Pointer to meter profile to be converted. 314 * @param[out] error 315 * Pointer to the error structure. 316 * 317 * @return 318 * 0 on success, a negative errno value otherwise and rte_errno is set. 319 */ 320 static int 321 mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp, 322 struct rte_mtr_error *error) 323 { 324 struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm; 325 uint8_t man, exp; 326 uint32_t cbs_exp, cbs_man, cir_exp, cir_man; 327 uint32_t eir_exp, eir_man, ebs_exp, ebs_man; 328 uint64_t cir, cbs, eir, ebs; 329 330 switch (fmp->profile.alg) { 331 case RTE_MTR_SRTCM_RFC2697: 332 cir = fmp->profile.srtcm_rfc2697.cir; 333 cbs = fmp->profile.srtcm_rfc2697.cbs; 334 eir = 0; 335 ebs = fmp->profile.srtcm_rfc2697.ebs; 336 break; 337 case RTE_MTR_TRTCM_RFC2698: 338 MLX5_ASSERT(fmp->profile.trtcm_rfc2698.pir > 339 fmp->profile.trtcm_rfc2698.cir && 340 fmp->profile.trtcm_rfc2698.pbs > 341 fmp->profile.trtcm_rfc2698.cbs); 342 cir = fmp->profile.trtcm_rfc2698.cir; 343 cbs = fmp->profile.trtcm_rfc2698.cbs; 344 /* EIR / EBS are filled with PIR / PBS. */ 345 eir = fmp->profile.trtcm_rfc2698.pir; 346 ebs = fmp->profile.trtcm_rfc2698.pbs; 347 break; 348 case RTE_MTR_TRTCM_RFC4115: 349 cir = fmp->profile.trtcm_rfc4115.cir; 350 cbs = fmp->profile.trtcm_rfc4115.cbs; 351 eir = fmp->profile.trtcm_rfc4115.eir; 352 ebs = fmp->profile.trtcm_rfc4115.ebs; 353 break; 354 default: 355 return -rte_mtr_error_set(error, EINVAL, 356 RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL, 357 "Metering algorithm mode is invalid"); 358 } 359 /* Adjust the values for PPS mode. */ 360 if (fmp->profile.packet_mode) { 361 cir <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT; 362 cbs <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT; 363 eir <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT; 364 ebs <<= MLX5_MTRS_PPS_MAP_BPS_SHIFT; 365 } 366 /* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */ 367 mlx5_flow_meter_xir_man_exp_calc(cir, &man, &exp); 368 /* Check if cir mantissa is too large. */ 369 if (exp > ASO_DSEG_XIR_EXP_MASK) 370 return -rte_mtr_error_set(error, ENOTSUP, 371 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 372 "meter profile parameter cir is not supported."); 373 cir_man = man; 374 cir_exp = exp; 375 /* cbs = cbs_mantissa * 2^cbs_exponent */ 376 mlx5_flow_meter_xbs_man_exp_calc(cbs, &man, &exp); 377 /* Check if cbs mantissa is too large. */ 378 if (exp > ASO_DSEG_EXP_MASK) 379 return -rte_mtr_error_set(error, ENOTSUP, 380 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 381 "meter profile parameter cbs is not supported."); 382 cbs_man = man; 383 cbs_exp = exp; 384 srtcm->cbs_cir = rte_cpu_to_be_32(cbs_exp << ASO_DSEG_CBS_EXP_OFFSET | 385 cbs_man << ASO_DSEG_CBS_MAN_OFFSET | 386 cir_exp << ASO_DSEG_XIR_EXP_OFFSET | 387 cir_man); 388 mlx5_flow_meter_xir_man_exp_calc(eir, &man, &exp); 389 /* Check if eir mantissa is too large. */ 390 if (exp > ASO_DSEG_XIR_EXP_MASK) 391 return -rte_mtr_error_set(error, ENOTSUP, 392 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 393 "meter profile parameter eir is not supported."); 394 eir_man = man; 395 eir_exp = exp; 396 mlx5_flow_meter_xbs_man_exp_calc(ebs, &man, &exp); 397 /* Check if ebs mantissa is too large. */ 398 if (exp > ASO_DSEG_EXP_MASK) 399 return -rte_mtr_error_set(error, ENOTSUP, 400 RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL, 401 "meter profile parameter ebs is not supported."); 402 ebs_man = man; 403 ebs_exp = exp; 404 srtcm->ebs_eir = rte_cpu_to_be_32(ebs_exp << ASO_DSEG_EBS_EXP_OFFSET | 405 ebs_man << ASO_DSEG_EBS_MAN_OFFSET | 406 eir_exp << ASO_DSEG_XIR_EXP_OFFSET | 407 eir_man); 408 if (srtcm->cbs_cir) 409 fmp->g_support = 1; 410 if (srtcm->ebs_eir) 411 fmp->y_support = 1; 412 return 0; 413 } 414 415 /** 416 * Callback to get MTR capabilities. 417 * 418 * @param[in] dev 419 * Pointer to Ethernet device. 420 * @param[out] cap 421 * Pointer to save MTR capabilities. 422 * @param[out] error 423 * Pointer to the error structure. 424 * 425 * @return 426 * 0 on success, a negative errno value otherwise and rte_errno is set. 427 */ 428 static int 429 mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev, 430 struct rte_mtr_capabilities *cap, 431 struct rte_mtr_error *error __rte_unused) 432 { 433 struct mlx5_priv *priv = dev->data->dev_private; 434 struct mlx5_hca_qos_attr *qattr = &priv->sh->cdev->config.hca_attr.qos; 435 436 if (!priv->mtr_en) 437 return -rte_mtr_error_set(error, ENOTSUP, 438 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 439 "Meter is not supported"); 440 memset(cap, 0, sizeof(*cap)); 441 if (priv->sh->meter_aso_en) { 442 /* 2 meters per one ASO cache line. */ 443 cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1); 444 cap->srtcm_rfc2697_packet_mode_supported = 1; 445 cap->trtcm_rfc2698_packet_mode_supported = 1; 446 cap->trtcm_rfc4115_packet_mode_supported = 1; 447 } else { 448 cap->n_max = 1 << qattr->log_max_flow_meter; 449 } 450 cap->srtcm_rfc2697_byte_mode_supported = 1; 451 cap->trtcm_rfc2698_byte_mode_supported = 1; 452 cap->trtcm_rfc4115_byte_mode_supported = 1; 453 cap->n_shared_max = cap->n_max; 454 cap->identical = 1; 455 cap->shared_identical = 1; 456 cap->shared_n_flows_per_mtr_max = 4 << 20; 457 /* 2M flows can share the same meter. */ 458 cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */ 459 cap->meter_srtcm_rfc2697_n_max = qattr->flow_meter_old ? cap->n_max : 0; 460 cap->meter_trtcm_rfc2698_n_max = qattr->flow_meter_old ? cap->n_max : 0; 461 cap->meter_trtcm_rfc4115_n_max = qattr->flow_meter_old ? cap->n_max : 0; 462 cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */ 463 cap->meter_policy_n_max = cap->n_max; 464 cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED | 465 RTE_MTR_STATS_N_PKTS_DROPPED; 466 return 0; 467 } 468 469 /** 470 * Callback to add MTR profile. 471 * 472 * @param[in] dev 473 * Pointer to Ethernet device. 474 * @param[in] meter_profile_id 475 * Meter profile id. 476 * @param[in] profile 477 * Pointer to meter profile detail. 478 * @param[out] error 479 * Pointer to the error structure. 480 * 481 * @return 482 * 0 on success, a negative errno value otherwise and rte_errno is set. 483 */ 484 static int 485 mlx5_flow_meter_profile_add(struct rte_eth_dev *dev, 486 uint32_t meter_profile_id, 487 struct rte_mtr_meter_profile *profile, 488 struct rte_mtr_error *error) 489 { 490 struct mlx5_priv *priv = dev->data->dev_private; 491 struct mlx5_flow_meter_profile *fmp; 492 union mlx5_l3t_data data; 493 int ret; 494 495 if (!priv->mtr_en) 496 return -rte_mtr_error_set(error, ENOTSUP, 497 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 498 "Meter is not supported"); 499 /* Check input params. */ 500 ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id, 501 profile, error); 502 if (ret) 503 return ret; 504 /* Meter profile memory allocation. */ 505 fmp = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_flow_meter_profile), 506 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 507 if (fmp == NULL) 508 return -rte_mtr_error_set(error, ENOMEM, 509 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 510 NULL, "Meter profile memory " 511 "alloc failed."); 512 /* Fill profile info. */ 513 fmp->id = meter_profile_id; 514 fmp->profile = *profile; 515 /* Fill the flow meter parameters for the PRM. */ 516 ret = mlx5_flow_meter_param_fill(fmp, error); 517 if (ret) 518 goto error; 519 data.ptr = fmp; 520 ret = mlx5_l3t_set_entry(priv->mtr_profile_tbl, 521 meter_profile_id, &data); 522 if (ret) 523 return -rte_mtr_error_set(error, ENOTSUP, 524 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 525 NULL, "Meter profile insert fail."); 526 return 0; 527 error: 528 mlx5_free(fmp); 529 return ret; 530 } 531 532 /** 533 * Callback to delete MTR profile. 534 * 535 * @param[in] dev 536 * Pointer to Ethernet device. 537 * @param[in] meter_profile_id 538 * Meter profile id. 539 * @param[out] error 540 * Pointer to the error structure. 541 * 542 * @return 543 * 0 on success, a negative errno value otherwise and rte_errno is set. 544 */ 545 static int 546 mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev, 547 uint32_t meter_profile_id, 548 struct rte_mtr_error *error) 549 { 550 struct mlx5_priv *priv = dev->data->dev_private; 551 struct mlx5_flow_meter_profile *fmp; 552 553 if (!priv->mtr_en) 554 return -rte_mtr_error_set(error, ENOTSUP, 555 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 556 "Meter is not supported"); 557 /* Meter profile must exist. */ 558 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); 559 if (fmp == NULL) 560 return -rte_mtr_error_set(error, ENOENT, 561 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 562 &meter_profile_id, 563 "Meter profile id is invalid."); 564 /* Check profile is unused. */ 565 if (fmp->ref_cnt) 566 return -rte_mtr_error_set(error, EBUSY, 567 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 568 NULL, "Meter profile is in use."); 569 if (mlx5_l3t_clear_entry(priv->mtr_profile_tbl, meter_profile_id)) 570 return -rte_mtr_error_set(error, EBUSY, 571 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 572 NULL, "Meter profile remove fail."); 573 mlx5_free(fmp); 574 return 0; 575 } 576 577 /** 578 * Find policy by id. 579 * 580 * @param[in] dev 581 * Pointer to Ethernet device. 582 * @param policy_id 583 * Policy id. 584 * 585 * @return 586 * Pointer to the policy found on success, NULL otherwise. 587 */ 588 struct mlx5_flow_meter_policy * 589 mlx5_flow_meter_policy_find(struct rte_eth_dev *dev, 590 uint32_t policy_id, 591 uint32_t *policy_idx) 592 { 593 struct mlx5_priv *priv = dev->data->dev_private; 594 struct mlx5_flow_meter_sub_policy *sub_policy = NULL; 595 union mlx5_l3t_data data; 596 597 if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM || !priv->policy_idx_tbl) 598 return NULL; 599 if (mlx5_l3t_get_entry(priv->policy_idx_tbl, policy_id, &data) || 600 !data.dword) 601 return NULL; 602 if (policy_idx) 603 *policy_idx = data.dword; 604 sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 605 data.dword); 606 /* Remove reference taken by the mlx5_l3t_get_entry. */ 607 mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id); 608 if (sub_policy) 609 if (sub_policy->main_policy_id) 610 return sub_policy->main_policy; 611 return NULL; 612 } 613 614 /** 615 * Get the next meter from one meter's policy in hierarchy chain. 616 * Lock free, mutex should be acquired by caller. 617 * 618 * @param[in] priv 619 * Pointer to mlx5_priv. 620 * @param[in] policy 621 * Pointer to flow meter policy. 622 * @param[out] mtr_idx 623 * Pointer to Meter index. 624 * 625 * @return 626 * Pointer to the next meter, or NULL when fail. 627 */ 628 struct mlx5_flow_meter_info * 629 mlx5_flow_meter_hierarchy_next_meter(struct mlx5_priv *priv, 630 struct mlx5_flow_meter_policy *policy, 631 uint32_t *mtr_idx) 632 { 633 int i; 634 635 for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) { 636 if (policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) 637 return mlx5_flow_meter_find(priv, 638 policy->act_cnt[i].next_mtr_id, 639 mtr_idx); 640 } 641 return NULL; 642 } 643 644 /** 645 * Get the last meter's policy from one meter's policy in hierarchy. 646 * 647 * @param[in] dev 648 * Pointer to Ethernet device. 649 * @param[in] policy 650 * Pointer to flow meter policy. 651 * 652 * @return 653 * Pointer to the final meter's policy, or NULL when fail. 654 */ 655 struct mlx5_flow_meter_policy * 656 mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev, 657 struct mlx5_flow_meter_policy *policy) 658 { 659 struct mlx5_priv *priv = dev->data->dev_private; 660 struct mlx5_flow_meter_info *next_fm; 661 struct mlx5_flow_meter_policy *next_policy = policy; 662 663 while (next_policy->is_hierarchy) { 664 rte_spinlock_lock(&next_policy->sl); 665 next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, next_policy, NULL); 666 rte_spinlock_unlock(&next_policy->sl); 667 if (!next_fm || next_fm->def_policy) 668 return NULL; 669 next_policy = mlx5_flow_meter_policy_find(dev, 670 next_fm->policy_id, NULL); 671 MLX5_ASSERT(next_policy); 672 } 673 return next_policy; 674 } 675 676 /** 677 * Callback to check MTR policy action validate 678 * 679 * @param[in] dev 680 * Pointer to Ethernet device. 681 * @param[in] actions 682 * Pointer to meter policy action detail. 683 * @param[out] error 684 * Pointer to the error structure. 685 * 686 * @return 687 * 0 on success, a negative errno value otherwise and rte_errno is set. 688 */ 689 static int 690 mlx5_flow_meter_policy_validate(struct rte_eth_dev *dev, 691 struct rte_mtr_meter_policy_params *policy, 692 struct rte_mtr_error *error) 693 { 694 struct mlx5_priv *priv = dev->data->dev_private; 695 struct rte_flow_attr attr = { .transfer = priv->sh->config.dv_esw_en ? 696 1 : 0 }; 697 bool is_rss = false; 698 uint8_t policy_mode; 699 uint8_t domain_bitmap; 700 int ret; 701 702 if (!priv->mtr_en || !priv->sh->meter_aso_en) 703 return -rte_mtr_error_set(error, ENOTSUP, 704 RTE_MTR_ERROR_TYPE_METER_POLICY, 705 NULL, "meter policy unsupported."); 706 ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr, 707 &is_rss, &domain_bitmap, &policy_mode, error); 708 if (ret) 709 return ret; 710 return 0; 711 } 712 713 static int 714 __mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev, 715 uint32_t policy_id, 716 struct mlx5_flow_meter_policy *mtr_policy, 717 struct rte_mtr_error *error, 718 bool clear_l3t) 719 { 720 struct mlx5_priv *priv = dev->data->dev_private; 721 struct mlx5_flow_meter_sub_policy *sub_policy; 722 uint32_t i, j; 723 uint16_t sub_policy_num; 724 725 rte_spinlock_lock(&mtr_policy->sl); 726 if (mtr_policy->ref_cnt) { 727 rte_spinlock_unlock(&mtr_policy->sl); 728 return -rte_mtr_error_set(error, EBUSY, 729 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 730 NULL, 731 "Meter policy object is being used."); 732 } 733 mlx5_flow_destroy_policy_rules(dev, mtr_policy); 734 mlx5_flow_destroy_mtr_acts(dev, mtr_policy); 735 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 736 sub_policy_num = (mtr_policy->sub_policy_num >> 737 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 738 MLX5_MTR_SUB_POLICY_NUM_MASK; 739 if (sub_policy_num) { 740 for (j = 0; j < sub_policy_num; j++) { 741 sub_policy = mtr_policy->sub_policys[i][j]; 742 if (sub_policy) 743 mlx5_ipool_free 744 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 745 sub_policy->idx); 746 } 747 } 748 } 749 if (priv->policy_idx_tbl && clear_l3t) { 750 if (mlx5_l3t_clear_entry(priv->policy_idx_tbl, policy_id)) { 751 rte_spinlock_unlock(&mtr_policy->sl); 752 return -rte_mtr_error_set(error, ENOTSUP, 753 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL, 754 "Fail to delete policy in index table."); 755 } 756 } 757 rte_spinlock_unlock(&mtr_policy->sl); 758 return 0; 759 } 760 761 /** 762 * Callback to add MTR policy. 763 * 764 * @param[in] dev 765 * Pointer to Ethernet device. 766 * @param[out] policy_id 767 * Pointer to policy id 768 * @param[in] actions 769 * Pointer to meter policy action detail. 770 * @param[out] error 771 * Pointer to the error structure. 772 * 773 * @return 774 * 0 on success, a negative errno value otherwise and rte_errno is set. 775 */ 776 static int 777 mlx5_flow_meter_policy_add(struct rte_eth_dev *dev, 778 uint32_t policy_id, 779 struct rte_mtr_meter_policy_params *policy, 780 struct rte_mtr_error *error) 781 { 782 struct mlx5_priv *priv = dev->data->dev_private; 783 struct rte_flow_attr attr = { .transfer = priv->sh->config.dv_esw_en ? 784 1 : 0 }; 785 uint32_t sub_policy_idx = 0; 786 uint32_t policy_idx = 0; 787 struct mlx5_flow_meter_policy *mtr_policy = NULL; 788 struct mlx5_flow_meter_sub_policy *sub_policy; 789 bool is_rss = false; 790 uint8_t policy_mode; 791 uint32_t i; 792 int ret; 793 uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy); 794 uint16_t sub_policy_num; 795 uint8_t domain_bitmap = 0; 796 union mlx5_l3t_data data; 797 bool skip_rule = false; 798 799 if (!priv->mtr_en) 800 return -rte_mtr_error_set(error, ENOTSUP, 801 RTE_MTR_ERROR_TYPE_METER_POLICY, 802 NULL, "meter policy unsupported. "); 803 if (policy_id == MLX5_INVALID_POLICY_ID) 804 return -rte_mtr_error_set(error, ENOTSUP, 805 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 806 NULL, "policy ID is invalid. "); 807 if (policy_id == priv->sh->mtrmng->def_policy_id) 808 return -rte_mtr_error_set(error, EEXIST, 809 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 810 NULL, "default policy ID exists. "); 811 mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx); 812 if (mtr_policy) 813 return -rte_mtr_error_set(error, EEXIST, 814 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 815 NULL, "policy ID exists. "); 816 ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr, 817 &is_rss, &domain_bitmap, 818 &policy_mode, error); 819 if (ret) 820 return ret; 821 if (!domain_bitmap) 822 return -rte_mtr_error_set(error, ENOTSUP, 823 RTE_MTR_ERROR_TYPE_METER_POLICY, 824 NULL, "fail to find policy domain."); 825 if (policy_mode == MLX5_MTR_POLICY_MODE_DEF) { 826 if (priv->sh->mtrmng->def_policy_id != MLX5_INVALID_POLICY_ID) 827 return -rte_mtr_error_set(error, EEXIST, 828 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 829 NULL, "a policy with similar actions " 830 "is already configured"); 831 if (mlx5_flow_create_def_policy(dev)) 832 return -rte_mtr_error_set(error, ENOTSUP, 833 RTE_MTR_ERROR_TYPE_METER_POLICY, 834 NULL, 835 "fail to create non-terminated policy."); 836 priv->sh->mtrmng->def_policy_id = policy_id; 837 return 0; 838 } 839 if (!priv->sh->meter_aso_en) 840 return -rte_mtr_error_set(error, ENOTSUP, 841 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, 842 "no ASO capability to support the policy "); 843 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 844 if (!(domain_bitmap & (1 << i))) 845 continue; 846 /* 847 * If RSS is found, it means that only the ingress domain can 848 * be supported. It is invalid to support RSS for one color 849 * and egress / transfer domain actions for another. Drop and 850 * jump action should have no impact. 851 */ 852 if (is_rss) { 853 policy_size += 854 sizeof(struct mlx5_flow_meter_sub_policy *) * 855 MLX5_MTR_RSS_MAX_SUB_POLICY; 856 break; 857 } 858 policy_size += sizeof(struct mlx5_flow_meter_sub_policy *); 859 } 860 mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size, 861 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); 862 if (!mtr_policy) 863 return -rte_mtr_error_set(error, ENOMEM, 864 RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, 865 "Memory alloc failed for meter policy."); 866 if (policy_mode == MLX5_MTR_POLICY_MODE_OG) 867 mtr_policy->skip_y = 1; 868 else if (policy_mode == MLX5_MTR_POLICY_MODE_OY) 869 mtr_policy->skip_g = 1; 870 policy_size = sizeof(struct mlx5_flow_meter_policy); 871 for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { 872 if (!(domain_bitmap & (1 << i))) 873 continue; 874 if (i == MLX5_MTR_DOMAIN_INGRESS) 875 mtr_policy->ingress = 1; 876 if (i == MLX5_MTR_DOMAIN_EGRESS) 877 mtr_policy->egress = 1; 878 if (i == MLX5_MTR_DOMAIN_TRANSFER) 879 mtr_policy->transfer = 1; 880 sub_policy = mlx5_ipool_zmalloc 881 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 882 &sub_policy_idx); 883 if (!sub_policy || 884 sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) 885 goto policy_add_err; 886 sub_policy->idx = sub_policy_idx; 887 sub_policy->main_policy = mtr_policy; 888 if (!policy_idx) { 889 policy_idx = sub_policy_idx; 890 sub_policy->main_policy_id = 1; 891 } 892 mtr_policy->sub_policys[i] = 893 (struct mlx5_flow_meter_sub_policy **) 894 ((uint8_t *)mtr_policy + policy_size); 895 mtr_policy->sub_policys[i][0] = sub_policy; 896 sub_policy_num = (mtr_policy->sub_policy_num >> 897 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) & 898 MLX5_MTR_SUB_POLICY_NUM_MASK; 899 sub_policy_num++; 900 mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK << 901 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)); 902 mtr_policy->sub_policy_num |= 903 (sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) << 904 (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i); 905 /* 906 * If RSS is found, it means that only the ingress domain can 907 * be supported. It is invalid to support RSS for one color 908 * and egress / transfer domain actions for another. Drop and 909 * jump action should have no impact. 910 */ 911 if (is_rss) { 912 mtr_policy->is_rss = 1; 913 break; 914 } 915 policy_size += sizeof(struct mlx5_flow_meter_sub_policy *); 916 } 917 rte_spinlock_init(&mtr_policy->sl); 918 ret = mlx5_flow_create_mtr_acts(dev, mtr_policy, 919 policy->actions, &attr, error); 920 if (ret) 921 goto policy_add_err; 922 if (mtr_policy->is_hierarchy) { 923 struct mlx5_flow_meter_policy *final_policy; 924 925 final_policy = 926 mlx5_flow_meter_hierarchy_get_final_policy(dev, mtr_policy); 927 if (!final_policy) 928 goto policy_add_err; 929 skip_rule = (final_policy->is_rss || final_policy->is_queue); 930 } 931 /* 932 * If either Green or Yellow has queue / RSS action, all the policy 933 * rules will be created later in the flow splitting stage. 934 */ 935 if (!is_rss && !mtr_policy->is_queue && !skip_rule) { 936 /* Create policy rules in HW. */ 937 ret = mlx5_flow_create_policy_rules(dev, mtr_policy); 938 if (ret) 939 goto policy_add_err; 940 } 941 data.dword = policy_idx; 942 if (!priv->policy_idx_tbl) { 943 priv->policy_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD); 944 if (!priv->policy_idx_tbl) 945 goto policy_add_err; 946 } 947 if (mlx5_l3t_set_entry(priv->policy_idx_tbl, policy_id, &data)) 948 goto policy_add_err; 949 return 0; 950 policy_add_err: 951 if (mtr_policy) { 952 ret = __mlx5_flow_meter_policy_delete(dev, policy_id, 953 mtr_policy, error, false); 954 mlx5_free(mtr_policy); 955 if (ret) 956 return ret; 957 } 958 return -rte_mtr_error_set(error, ENOTSUP, 959 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 960 NULL, "Failed to create devx policy."); 961 } 962 963 /** 964 * Callback to delete MTR policy. 965 * 966 * @param[in] dev 967 * Pointer to Ethernet device. 968 * @param[in] policy_id 969 * Meter policy id. 970 * @param[out] error 971 * Pointer to the error structure. 972 * 973 * @return 974 * 0 on success, a negative errno value otherwise and rte_errno is set. 975 */ 976 static int 977 mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev, 978 uint32_t policy_id, 979 struct rte_mtr_error *error) 980 { 981 struct mlx5_priv *priv = dev->data->dev_private; 982 struct mlx5_flow_meter_policy *mtr_policy; 983 uint32_t policy_idx; 984 int ret; 985 986 if (policy_id == priv->sh->mtrmng->def_policy_id) { 987 if (priv->sh->mtrmng->def_policy_ref_cnt > 0) 988 return -rte_mtr_error_set(error, ENOTSUP, 989 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL, 990 "Meter policy object is being used."); 991 priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID; 992 return 0; 993 } 994 mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx); 995 if (!mtr_policy) 996 return -rte_mtr_error_set(error, ENOTSUP, 997 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL, 998 "Meter policy id is invalid. "); 999 ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy, 1000 error, true); 1001 if (ret) 1002 return ret; 1003 mlx5_free(mtr_policy); 1004 return 0; 1005 } 1006 1007 /** 1008 * Check meter validation. 1009 * 1010 * @param[in] priv 1011 * Pointer to mlx5 private data structure. 1012 * @param[in] meter_id 1013 * Meter id. 1014 * @param[in] params 1015 * Pointer to rte meter parameters. 1016 * @param[out] error 1017 * Pointer to rte meter error structure. 1018 * 1019 * @return 1020 * 0 on success, a negative errno value otherwise and rte_errno is set. 1021 */ 1022 static int 1023 mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id, 1024 struct rte_mtr_params *params, 1025 struct rte_mtr_error *error) 1026 { 1027 /* Meter must use global drop action. */ 1028 if (!priv->sh->dr_drop_action) 1029 return -rte_mtr_error_set(error, ENOTSUP, 1030 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 1031 NULL, 1032 "No drop action ready for meter."); 1033 /* Meter params must not be NULL. */ 1034 if (params == NULL) 1035 return -rte_mtr_error_set(error, EINVAL, 1036 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 1037 NULL, "Meter object params null."); 1038 /* Previous meter color is not supported. */ 1039 if (params->use_prev_mtr_color && !priv->sh->meter_aso_en) 1040 return -rte_mtr_error_set(error, ENOTSUP, 1041 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 1042 NULL, 1043 "Previous meter color " 1044 "not supported."); 1045 if (params->meter_policy_id == MLX5_INVALID_POLICY_ID) 1046 return -rte_mtr_error_set(error, ENOENT, 1047 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 1048 NULL, "Meter policy id not valid."); 1049 /* Validate meter id. */ 1050 if (mlx5_flow_meter_find(priv, meter_id, NULL)) 1051 return -rte_mtr_error_set(error, EEXIST, 1052 RTE_MTR_ERROR_TYPE_MTR_ID, NULL, 1053 "Meter object already exists."); 1054 return 0; 1055 } 1056 1057 /** 1058 * Modify the flow meter action. 1059 * 1060 * @param[in] priv 1061 * Pointer to mlx5 private data structure. 1062 * @param[in] fm 1063 * Pointer to flow meter to be modified. 1064 * @param[in] srtcm 1065 * Pointer to meter srtcm description parameter. 1066 * @param[in] modify_bits 1067 * The bit in srtcm to be updated. 1068 * @param[in] active_state 1069 * The state to be updated. 1070 * @return 1071 * 0 on success, o negative value otherwise. 1072 */ 1073 static int 1074 mlx5_flow_meter_action_modify(struct mlx5_priv *priv, 1075 struct mlx5_flow_meter_info *fm, 1076 const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm, 1077 uint64_t modify_bits, uint32_t active_state, uint32_t is_enable) 1078 { 1079 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER 1080 uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 }; 1081 uint32_t *attr; 1082 struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 }; 1083 int ret; 1084 struct mlx5_aso_mtr *aso_mtr = NULL; 1085 uint32_t cbs_cir, ebs_eir, val; 1086 1087 if (priv->sh->meter_aso_en) { 1088 fm->is_enable = !!is_enable; 1089 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); 1090 ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr); 1091 if (ret) 1092 return ret; 1093 ret = mlx5_aso_mtr_wait(priv->sh, aso_mtr); 1094 if (ret) 1095 return ret; 1096 } else { 1097 /* Fill command parameters. */ 1098 mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0; 1099 mod_attr.flow_meter_parameter = in; 1100 mod_attr.flow_meter_parameter_sz = 1101 MLX5_ST_SZ_BYTES(flow_meter_parameters); 1102 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE) 1103 mod_attr.active = !!active_state; 1104 else 1105 mod_attr.active = 0; 1106 attr = in; 1107 cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir); 1108 ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir); 1109 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) { 1110 val = (cbs_cir >> ASO_DSEG_CBS_EXP_OFFSET) & 1111 ASO_DSEG_EXP_MASK; 1112 MLX5_SET(flow_meter_parameters, attr, 1113 cbs_exponent, val); 1114 val = (cbs_cir >> ASO_DSEG_CBS_MAN_OFFSET) & 1115 ASO_DSEG_MAN_MASK; 1116 MLX5_SET(flow_meter_parameters, attr, 1117 cbs_mantissa, val); 1118 } 1119 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) { 1120 val = (cbs_cir >> ASO_DSEG_XIR_EXP_OFFSET) & 1121 ASO_DSEG_EXP_MASK; 1122 MLX5_SET(flow_meter_parameters, attr, 1123 cir_exponent, val); 1124 val = cbs_cir & ASO_DSEG_MAN_MASK; 1125 MLX5_SET(flow_meter_parameters, attr, 1126 cir_mantissa, val); 1127 } 1128 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) { 1129 val = (ebs_eir >> ASO_DSEG_EBS_EXP_OFFSET) & 1130 ASO_DSEG_EXP_MASK; 1131 MLX5_SET(flow_meter_parameters, attr, 1132 ebs_exponent, val); 1133 val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & 1134 ASO_DSEG_MAN_MASK; 1135 MLX5_SET(flow_meter_parameters, attr, 1136 ebs_mantissa, val); 1137 } 1138 /* Apply modifications to meter only if it was created. */ 1139 if (fm->meter_action_g) { 1140 ret = mlx5_glue->dv_modify_flow_action_meter 1141 (fm->meter_action_g, &mod_attr, 1142 rte_cpu_to_be_64(modify_bits)); 1143 if (ret) 1144 return ret; 1145 } 1146 /* Update succeeded modify meter parameters. */ 1147 if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE) 1148 fm->active_state = !!active_state; 1149 } 1150 return 0; 1151 #else 1152 (void)priv; 1153 (void)fm; 1154 (void)srtcm; 1155 (void)modify_bits; 1156 (void)active_state; 1157 (void)is_enable; 1158 return -ENOTSUP; 1159 #endif 1160 } 1161 1162 static int 1163 mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev, 1164 struct mlx5_flow_meter_info *fm, 1165 uint64_t stats_mask) 1166 { 1167 fm->bytes_dropped = 1168 (stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0; 1169 fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0; 1170 if (fm->bytes_dropped || fm->pkts_dropped) { 1171 if (!fm->drop_cnt) { 1172 /* Alloc policer counters. */ 1173 fm->drop_cnt = mlx5_counter_alloc(dev); 1174 if (!fm->drop_cnt) 1175 return -1; 1176 } 1177 } else { 1178 if (fm->drop_cnt) { 1179 mlx5_counter_free(dev, fm->drop_cnt); 1180 fm->drop_cnt = 0; 1181 } 1182 } 1183 return 0; 1184 } 1185 1186 /** 1187 * Create meter rules. 1188 * 1189 * @param[in] dev 1190 * Pointer to Ethernet device. 1191 * @param[in] meter_id 1192 * Meter id. 1193 * @param[in] params 1194 * Pointer to rte meter parameters. 1195 * @param[in] shared 1196 * Meter shared with other flow or not. 1197 * @param[out] error 1198 * Pointer to rte meter error structure. 1199 * 1200 * @return 1201 * 0 on success, a negative errno value otherwise and rte_errno is set. 1202 */ 1203 static int 1204 mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id, 1205 struct rte_mtr_params *params, int shared, 1206 struct rte_mtr_error *error) 1207 { 1208 struct mlx5_priv *priv = dev->data->dev_private; 1209 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters; 1210 struct mlx5_flow_meter_profile *fmp; 1211 struct mlx5_flow_meter_info *fm; 1212 /* GCC fails to infer legacy_fm is set when !priv->sh->meter_aso_en. */ 1213 struct mlx5_legacy_flow_meter *legacy_fm = NULL; 1214 struct mlx5_flow_meter_policy *mtr_policy = NULL; 1215 struct mlx5_indexed_pool_config flow_ipool_cfg = { 1216 .size = 0, 1217 .trunk_size = 64, 1218 .need_lock = 1, 1219 .type = "mlx5_flow_mtr_flow_id_pool", 1220 }; 1221 struct mlx5_aso_mtr *aso_mtr; 1222 uint32_t mtr_idx, policy_idx; 1223 union mlx5_l3t_data data; 1224 int ret; 1225 uint8_t domain_bitmap; 1226 uint8_t mtr_id_bits; 1227 uint8_t mtr_reg_bits = priv->mtr_reg_share ? 1228 MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS; 1229 1230 if (!priv->mtr_en) 1231 return -rte_mtr_error_set(error, ENOTSUP, 1232 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1233 "Meter is not supported"); 1234 /* Validate the parameters. */ 1235 ret = mlx5_flow_meter_validate(priv, meter_id, params, error); 1236 if (ret) 1237 return ret; 1238 /* Meter profile must exist. */ 1239 fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id); 1240 if (fmp == NULL) 1241 return -rte_mtr_error_set(error, ENOENT, 1242 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 1243 NULL, "Meter profile id not valid."); 1244 /* Meter policy must exist. */ 1245 if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) { 1246 __atomic_add_fetch 1247 (&priv->sh->mtrmng->def_policy_ref_cnt, 1248 1, __ATOMIC_RELAXED); 1249 domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT; 1250 if (!priv->sh->config.dv_esw_en) 1251 domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT; 1252 } else { 1253 if (!priv->sh->meter_aso_en) 1254 return -rte_mtr_error_set(error, ENOTSUP, 1255 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1256 "Part of the policies cannot be " 1257 "supported without ASO "); 1258 mtr_policy = mlx5_flow_meter_policy_find(dev, 1259 params->meter_policy_id, &policy_idx); 1260 if (!mtr_policy) 1261 return -rte_mtr_error_set(error, ENOENT, 1262 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 1263 NULL, "Meter policy id not valid."); 1264 domain_bitmap = (mtr_policy->ingress ? 1265 MLX5_MTR_DOMAIN_INGRESS_BIT : 0) | 1266 (mtr_policy->egress ? 1267 MLX5_MTR_DOMAIN_EGRESS_BIT : 0) | 1268 (mtr_policy->transfer ? 1269 MLX5_MTR_DOMAIN_TRANSFER_BIT : 0); 1270 if (fmp->g_support && mtr_policy->skip_g) 1271 return -rte_mtr_error_set(error, ENOTSUP, 1272 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 1273 NULL, "Meter green policy is empty."); 1274 if (fmp->y_support && mtr_policy->skip_y) 1275 return -rte_mtr_error_set(error, ENOTSUP, 1276 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 1277 NULL, "Meter yellow policy is empty."); 1278 } 1279 /* Allocate the flow meter memory. */ 1280 if (priv->sh->meter_aso_en) { 1281 mtr_idx = mlx5_flow_mtr_alloc(dev); 1282 if (!mtr_idx) 1283 return -rte_mtr_error_set(error, ENOMEM, 1284 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1285 "Memory alloc failed for meter."); 1286 aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx); 1287 fm = &aso_mtr->fm; 1288 } else { 1289 if (fmp->y_support) 1290 return -rte_mtr_error_set(error, ENOMEM, 1291 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1292 "Unsupported profile with yellow."); 1293 legacy_fm = mlx5_ipool_zmalloc 1294 (priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx); 1295 if (legacy_fm == NULL) 1296 return -rte_mtr_error_set(error, ENOMEM, 1297 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1298 "Memory alloc failed for meter."); 1299 legacy_fm->idx = mtr_idx; 1300 fm = &legacy_fm->fm; 1301 } 1302 mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx); 1303 if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) > 1304 mtr_reg_bits) { 1305 DRV_LOG(ERR, "Meter number exceeds max limit."); 1306 goto error; 1307 } 1308 if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits) 1309 priv->sh->mtrmng->max_mtr_bits = mtr_id_bits; 1310 /* Fill the flow meter parameters. */ 1311 fm->meter_id = meter_id; 1312 fm->policy_id = params->meter_policy_id; 1313 fm->profile = fmp; 1314 if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask)) 1315 goto error; 1316 if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap)) 1317 goto error; 1318 /* Add to the flow meter list. */ 1319 if (!priv->sh->meter_aso_en) { 1320 MLX5_ASSERT(legacy_fm != NULL); 1321 TAILQ_INSERT_TAIL(fms, legacy_fm, next); 1322 } 1323 /* Add to the flow meter list. */ 1324 fm->active_state = 1; /* Config meter starts as active. */ 1325 fm->is_enable = params->meter_enable; 1326 fm->shared = !!shared; 1327 fm->color_aware = !!params->use_prev_mtr_color; 1328 __atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED); 1329 if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) { 1330 fm->def_policy = 1; 1331 fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg); 1332 if (!fm->flow_ipool) 1333 goto error; 1334 } 1335 rte_spinlock_init(&fm->sl); 1336 /* If ASO meter supported, update ASO flow meter by wqe. */ 1337 if (priv->sh->meter_aso_en) { 1338 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); 1339 ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr); 1340 if (ret) 1341 goto error; 1342 if (!priv->mtr_idx_tbl) { 1343 priv->mtr_idx_tbl = 1344 mlx5_l3t_create(MLX5_L3T_TYPE_DWORD); 1345 if (!priv->mtr_idx_tbl) 1346 goto error; 1347 } 1348 data.dword = mtr_idx; 1349 if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data)) 1350 goto error; 1351 } else if (!params->meter_enable && mlx5_flow_meter_disable(dev, meter_id, error)) { 1352 goto error; 1353 } 1354 fm->active_state = params->meter_enable; 1355 if (mtr_policy) 1356 __atomic_add_fetch(&mtr_policy->ref_cnt, 1, __ATOMIC_RELAXED); 1357 return 0; 1358 error: 1359 mlx5_flow_destroy_mtr_tbls(dev, fm); 1360 /* Free policer counters. */ 1361 if (fm->drop_cnt) 1362 mlx5_counter_free(dev, fm->drop_cnt); 1363 if (priv->sh->meter_aso_en) 1364 mlx5_flow_mtr_free(dev, mtr_idx); 1365 else 1366 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx); 1367 return -rte_mtr_error_set(error, ENOTSUP, 1368 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 1369 NULL, "Failed to create devx meter."); 1370 } 1371 1372 static int 1373 mlx5_flow_meter_params_flush(struct rte_eth_dev *dev, 1374 struct mlx5_flow_meter_info *fm, 1375 uint32_t mtr_idx) 1376 { 1377 struct mlx5_priv *priv = dev->data->dev_private; 1378 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters; 1379 struct mlx5_flow_meter_profile *fmp; 1380 struct mlx5_legacy_flow_meter *legacy_fm = NULL; 1381 struct mlx5_flow_meter_policy *mtr_policy; 1382 1383 /* Meter object must not have any owner. */ 1384 MLX5_ASSERT(!fm->ref_cnt); 1385 /* Get meter profile. */ 1386 fmp = fm->profile; 1387 if (fmp == NULL) 1388 return -1; 1389 /* Update dependencies. */ 1390 __atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED); 1391 fm->profile = NULL; 1392 /* Remove from list. */ 1393 if (!priv->sh->meter_aso_en) { 1394 legacy_fm = container_of(fm, 1395 struct mlx5_legacy_flow_meter, fm); 1396 TAILQ_REMOVE(fms, legacy_fm, next); 1397 } 1398 /* Free drop counters. */ 1399 if (fm->drop_cnt) 1400 mlx5_counter_free(dev, fm->drop_cnt); 1401 /* Free meter flow table. */ 1402 if (fm->flow_ipool) { 1403 mlx5_ipool_destroy(fm->flow_ipool); 1404 fm->flow_ipool = 0; 1405 } 1406 mlx5_flow_destroy_mtr_tbls(dev, fm); 1407 if (fm->def_policy) 1408 __atomic_sub_fetch(&priv->sh->mtrmng->def_policy_ref_cnt, 1409 1, __ATOMIC_RELAXED); 1410 if (priv->sh->meter_aso_en) { 1411 if (!fm->def_policy) { 1412 mtr_policy = mlx5_flow_meter_policy_find(dev, 1413 fm->policy_id, NULL); 1414 if (mtr_policy) 1415 __atomic_sub_fetch(&mtr_policy->ref_cnt, 1416 1, __ATOMIC_RELAXED); 1417 fm->policy_id = 0; 1418 } 1419 fm->def_policy = 0; 1420 if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id)) 1421 return -1; 1422 mlx5_flow_mtr_free(dev, mtr_idx); 1423 } else { 1424 mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], 1425 legacy_fm->idx); 1426 } 1427 return 0; 1428 } 1429 1430 /** 1431 * Destroy meter rules. 1432 * 1433 * @param[in] dev 1434 * Pointer to Ethernet device. 1435 * @param[in] meter_id 1436 * Meter id. 1437 * @param[out] error 1438 * Pointer to rte meter error structure. 1439 * 1440 * @return 1441 * 0 on success, a negative errno value otherwise and rte_errno is set. 1442 */ 1443 static int 1444 mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id, 1445 struct rte_mtr_error *error) 1446 { 1447 struct mlx5_priv *priv = dev->data->dev_private; 1448 struct mlx5_flow_meter_info *fm; 1449 uint32_t mtr_idx = 0; 1450 1451 if (!priv->mtr_en) 1452 return -rte_mtr_error_set(error, ENOTSUP, 1453 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 1454 NULL, 1455 "Meter is not supported"); 1456 /* Meter object must exist. */ 1457 fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx); 1458 if (fm == NULL) 1459 return -rte_mtr_error_set(error, ENOENT, 1460 RTE_MTR_ERROR_TYPE_MTR_ID, 1461 NULL, 1462 "Meter object id not valid."); 1463 /* Meter object must not have any owner. */ 1464 if (fm->ref_cnt > 0) 1465 return -rte_mtr_error_set(error, EBUSY, 1466 RTE_MTR_ERROR_TYPE_UNSPECIFIED, 1467 NULL, 1468 "Meter object is being used."); 1469 /* Destroy the meter profile. */ 1470 if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx)) 1471 return -rte_mtr_error_set(error, EINVAL, 1472 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 1473 NULL, 1474 "MTR object meter profile invalid."); 1475 return 0; 1476 } 1477 1478 /** 1479 * Modify meter state. 1480 * 1481 * @param[in] priv 1482 * Pointer to mlx5 private data structure. 1483 * @param[in] fm 1484 * Pointer to flow meter. 1485 * @param[in] new_state 1486 * New state to update. 1487 * @param[out] error 1488 * Pointer to rte meter error structure. 1489 * 1490 * @return 1491 * 0 on success, a negative errno value otherwise and rte_errno is set. 1492 */ 1493 static int 1494 mlx5_flow_meter_modify_state(struct mlx5_priv *priv, 1495 struct mlx5_flow_meter_info *fm, 1496 uint32_t new_state, 1497 struct rte_mtr_error *error) 1498 { 1499 static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = { 1500 .cbs_cir = RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL), 1501 .ebs_eir = 0, 1502 }; 1503 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS | 1504 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR; 1505 int ret; 1506 1507 if (new_state == MLX5_FLOW_METER_DISABLE) 1508 ret = mlx5_flow_meter_action_modify(priv, fm, 1509 &srtcm, modify_bits, 0, 0); 1510 else 1511 ret = mlx5_flow_meter_action_modify(priv, fm, 1512 &fm->profile->srtcm_prm, 1513 modify_bits, 0, 1); 1514 if (ret) 1515 return -rte_mtr_error_set(error, -ret, 1516 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 1517 NULL, 1518 new_state ? 1519 "Failed to enable meter." : 1520 "Failed to disable meter."); 1521 return 0; 1522 } 1523 1524 /** 1525 * Callback to enable flow meter. 1526 * 1527 * @param[in] dev 1528 * Pointer to Ethernet device. 1529 * @param[in] meter_id 1530 * Meter id. 1531 * @param[out] error 1532 * Pointer to rte meter error structure. 1533 * 1534 * @return 1535 * 0 on success, a negative errno value otherwise and rte_errno is set. 1536 */ 1537 static int 1538 mlx5_flow_meter_enable(struct rte_eth_dev *dev, 1539 uint32_t meter_id, 1540 struct rte_mtr_error *error) 1541 { 1542 struct mlx5_priv *priv = dev->data->dev_private; 1543 struct mlx5_flow_meter_info *fm; 1544 int ret; 1545 1546 if (!priv->mtr_en) 1547 return -rte_mtr_error_set(error, ENOTSUP, 1548 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1549 "Meter is not supported"); 1550 /* Meter object must exist. */ 1551 fm = mlx5_flow_meter_find(priv, meter_id, NULL); 1552 if (fm == NULL) 1553 return -rte_mtr_error_set(error, ENOENT, 1554 RTE_MTR_ERROR_TYPE_MTR_ID, 1555 NULL, "Meter not found."); 1556 if (fm->active_state == MLX5_FLOW_METER_ENABLE) 1557 return 0; 1558 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE, 1559 error); 1560 if (!ret) 1561 fm->active_state = MLX5_FLOW_METER_ENABLE; 1562 return ret; 1563 } 1564 1565 /** 1566 * Callback to disable flow meter. 1567 * 1568 * @param[in] dev 1569 * Pointer to Ethernet device. 1570 * @param[in] meter_id 1571 * Meter id. 1572 * @param[out] error 1573 * Pointer to rte meter error structure. 1574 * 1575 * @return 1576 * 0 on success, a negative errno value otherwise and rte_errno is set. 1577 */ 1578 static int 1579 mlx5_flow_meter_disable(struct rte_eth_dev *dev, 1580 uint32_t meter_id, 1581 struct rte_mtr_error *error) 1582 { 1583 struct mlx5_priv *priv = dev->data->dev_private; 1584 struct mlx5_flow_meter_info *fm; 1585 int ret; 1586 1587 if (!priv->mtr_en) 1588 return -rte_mtr_error_set(error, ENOTSUP, 1589 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1590 "Meter is not supported"); 1591 /* Meter object must exist. */ 1592 fm = mlx5_flow_meter_find(priv, meter_id, NULL); 1593 if (fm == NULL) 1594 return -rte_mtr_error_set(error, ENOENT, 1595 RTE_MTR_ERROR_TYPE_MTR_ID, 1596 NULL, "Meter not found."); 1597 if (fm->active_state == MLX5_FLOW_METER_DISABLE) 1598 return 0; 1599 ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE, 1600 error); 1601 if (!ret) 1602 fm->active_state = MLX5_FLOW_METER_DISABLE; 1603 return ret; 1604 } 1605 1606 /** 1607 * Callback to update meter profile. 1608 * 1609 * @param[in] dev 1610 * Pointer to Ethernet device. 1611 * @param[in] meter_id 1612 * Meter id. 1613 * @param[in] meter_profile_id 1614 * To be updated meter profile id. 1615 * @param[out] error 1616 * Pointer to rte meter error structure. 1617 * 1618 * @return 1619 * 0 on success, a negative errno value otherwise and rte_errno is set. 1620 */ 1621 static int 1622 mlx5_flow_meter_profile_update(struct rte_eth_dev *dev, 1623 uint32_t meter_id, 1624 uint32_t meter_profile_id, 1625 struct rte_mtr_error *error) 1626 { 1627 struct mlx5_priv *priv = dev->data->dev_private; 1628 struct mlx5_flow_meter_profile *fmp; 1629 struct mlx5_flow_meter_profile *old_fmp; 1630 struct mlx5_flow_meter_info *fm; 1631 uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS | 1632 MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR; 1633 int ret; 1634 1635 if (!priv->mtr_en) 1636 return -rte_mtr_error_set(error, ENOTSUP, 1637 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1638 "Meter is not supported"); 1639 /* Meter profile must exist. */ 1640 fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); 1641 if (fmp == NULL) 1642 return -rte_mtr_error_set(error, ENOENT, 1643 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 1644 NULL, "Meter profile not found."); 1645 /* Meter object must exist. */ 1646 fm = mlx5_flow_meter_find(priv, meter_id, NULL); 1647 if (fm == NULL) 1648 return -rte_mtr_error_set(error, ENOENT, 1649 RTE_MTR_ERROR_TYPE_MTR_ID, 1650 NULL, "Meter not found."); 1651 /* MTR object already set to meter profile id. */ 1652 old_fmp = fm->profile; 1653 if (fmp == old_fmp) 1654 return 0; 1655 /* Update the profile. */ 1656 fm->profile = fmp; 1657 /* Update meter params in HW (if not disabled). */ 1658 if (fm->active_state == MLX5_FLOW_METER_DISABLE) 1659 goto dec_ref_cnt; 1660 ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm, 1661 modify_bits, fm->active_state, 1); 1662 if (ret) { 1663 fm->profile = old_fmp; 1664 return -rte_mtr_error_set(error, -ret, 1665 RTE_MTR_ERROR_TYPE_MTR_PARAMS, 1666 NULL, "Failed to update meter" 1667 " parameters in hardware."); 1668 } 1669 dec_ref_cnt: 1670 old_fmp->ref_cnt--; 1671 fmp->ref_cnt++; 1672 return 0; 1673 } 1674 1675 /** 1676 * Callback to update meter stats mask. 1677 * 1678 * @param[in] dev 1679 * Pointer to Ethernet device. 1680 * @param[in] meter_id 1681 * Meter id. 1682 * @param[in] stats_mask 1683 * To be updated stats_mask. 1684 * @param[out] error 1685 * Pointer to rte meter error structure. 1686 * 1687 * @return 1688 * 0 on success, a negative errno value otherwise and rte_errno is set. 1689 */ 1690 static int 1691 mlx5_flow_meter_stats_update(struct rte_eth_dev *dev, 1692 uint32_t meter_id, 1693 uint64_t stats_mask, 1694 struct rte_mtr_error *error) 1695 { 1696 struct mlx5_priv *priv = dev->data->dev_private; 1697 struct mlx5_flow_meter_info *fm; 1698 1699 if (!priv->mtr_en) 1700 return -rte_mtr_error_set(error, ENOTSUP, 1701 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1702 "Meter is not supported"); 1703 /* Meter object must exist. */ 1704 fm = mlx5_flow_meter_find(priv, meter_id, NULL); 1705 if (fm == NULL) 1706 return -rte_mtr_error_set(error, ENOENT, 1707 RTE_MTR_ERROR_TYPE_MTR_ID, 1708 NULL, "Meter object id not valid."); 1709 if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask)) 1710 return -rte_mtr_error_set(error, ENOENT, 1711 RTE_MTR_ERROR_TYPE_MTR_ID, 1712 NULL, "Fail to allocate " 1713 "counter for meter."); 1714 return 0; 1715 } 1716 1717 /** 1718 * Callback to read meter statistics. 1719 * 1720 * @param[in] dev 1721 * Pointer to Ethernet device. 1722 * @param[in] meter_id 1723 * Meter id. 1724 * @param[out] stats 1725 * Pointer to store the statistics. 1726 * @param[out] stats_mask 1727 * Pointer to store the stats_mask. 1728 * @param[in] clear 1729 * Statistic to be cleared after read or not. 1730 * @param[out] error 1731 * Pointer to rte meter error structure. 1732 * 1733 * @return 1734 * 0 on success, a negative errno value otherwise and rte_errno is set. 1735 */ 1736 static int 1737 mlx5_flow_meter_stats_read(struct rte_eth_dev *dev, 1738 uint32_t meter_id, 1739 struct rte_mtr_stats *stats, 1740 uint64_t *stats_mask, 1741 int clear, 1742 struct rte_mtr_error *error) 1743 { 1744 struct mlx5_priv *priv = dev->data->dev_private; 1745 struct mlx5_flow_meter_info *fm; 1746 uint64_t pkts; 1747 uint64_t bytes; 1748 int ret = 0; 1749 1750 if (!priv->mtr_en) 1751 return -rte_mtr_error_set(error, ENOTSUP, 1752 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, 1753 "Meter is not supported"); 1754 /* Meter object must exist. */ 1755 fm = mlx5_flow_meter_find(priv, meter_id, NULL); 1756 if (fm == NULL) 1757 return -rte_mtr_error_set(error, ENOENT, 1758 RTE_MTR_ERROR_TYPE_MTR_ID, 1759 NULL, "Meter object id not valid."); 1760 *stats_mask = 0; 1761 if (fm->bytes_dropped) 1762 *stats_mask |= RTE_MTR_STATS_N_BYTES_DROPPED; 1763 if (fm->pkts_dropped) 1764 *stats_mask |= RTE_MTR_STATS_N_PKTS_DROPPED; 1765 memset(stats, 0, sizeof(*stats)); 1766 if (fm->drop_cnt) { 1767 ret = mlx5_counter_query(dev, fm->drop_cnt, clear, &pkts, 1768 &bytes, NULL); 1769 if (ret) 1770 goto error; 1771 /* If need to read the packets, set it. */ 1772 if (fm->pkts_dropped) 1773 stats->n_pkts_dropped = pkts; 1774 /* If need to read the bytes, set it. */ 1775 if (fm->bytes_dropped) 1776 stats->n_bytes_dropped = bytes; 1777 } 1778 return 0; 1779 error: 1780 return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL, 1781 "Failed to read meter drop counters."); 1782 } 1783 1784 static const struct rte_mtr_ops mlx5_flow_mtr_ops = { 1785 .capabilities_get = mlx5_flow_mtr_cap_get, 1786 .meter_profile_add = mlx5_flow_meter_profile_add, 1787 .meter_profile_delete = mlx5_flow_meter_profile_delete, 1788 .meter_policy_validate = mlx5_flow_meter_policy_validate, 1789 .meter_policy_add = mlx5_flow_meter_policy_add, 1790 .meter_policy_delete = mlx5_flow_meter_policy_delete, 1791 .create = mlx5_flow_meter_create, 1792 .destroy = mlx5_flow_meter_destroy, 1793 .meter_enable = mlx5_flow_meter_enable, 1794 .meter_disable = mlx5_flow_meter_disable, 1795 .meter_profile_update = mlx5_flow_meter_profile_update, 1796 .meter_dscp_table_update = NULL, 1797 .stats_update = mlx5_flow_meter_stats_update, 1798 .stats_read = mlx5_flow_meter_stats_read, 1799 }; 1800 1801 /** 1802 * Get meter operations. 1803 * 1804 * @param dev 1805 * Pointer to Ethernet device structure. 1806 * @param arg 1807 * Pointer to set the mtr operations. 1808 * 1809 * @return 1810 * Always 0. 1811 */ 1812 int 1813 mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg) 1814 { 1815 *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops; 1816 return 0; 1817 } 1818 1819 /** 1820 * Find meter by id. 1821 * 1822 * @param priv 1823 * Pointer to mlx5_priv. 1824 * @param meter_id 1825 * Meter id. 1826 * @param mtr_idx 1827 * Pointer to Meter index. 1828 * 1829 * @return 1830 * Pointer to the meter info found on success, NULL otherwise. 1831 */ 1832 struct mlx5_flow_meter_info * 1833 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id, 1834 uint32_t *mtr_idx) 1835 { 1836 struct mlx5_legacy_flow_meter *legacy_fm; 1837 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters; 1838 struct mlx5_aso_mtr *aso_mtr; 1839 struct mlx5_aso_mtr_pools_mng *pools_mng = 1840 &priv->sh->mtrmng->pools_mng; 1841 union mlx5_l3t_data data; 1842 uint16_t n_valid; 1843 1844 if (priv->sh->meter_aso_en) { 1845 rte_rwlock_read_lock(&pools_mng->resize_mtrwl); 1846 n_valid = pools_mng->n_valid; 1847 rte_rwlock_read_unlock(&pools_mng->resize_mtrwl); 1848 if (!n_valid || !priv->mtr_idx_tbl || 1849 (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) || 1850 !data.dword)) 1851 return NULL; 1852 if (mtr_idx) 1853 *mtr_idx = data.dword; 1854 aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword); 1855 /* Remove reference taken by the mlx5_l3t_get_entry. */ 1856 mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id); 1857 if (!aso_mtr || aso_mtr->state == ASO_METER_FREE) 1858 return NULL; 1859 return &aso_mtr->fm; 1860 } 1861 TAILQ_FOREACH(legacy_fm, fms, next) 1862 if (meter_id == legacy_fm->fm.meter_id) { 1863 if (mtr_idx) 1864 *mtr_idx = legacy_fm->idx; 1865 return &legacy_fm->fm; 1866 } 1867 return NULL; 1868 } 1869 1870 /** 1871 * Find meter by index. 1872 * 1873 * @param priv 1874 * Pointer to mlx5_priv. 1875 * @param idx 1876 * Meter index. 1877 * 1878 * @return 1879 * Pointer to the meter info found on success, NULL otherwise. 1880 */ 1881 struct mlx5_flow_meter_info * 1882 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx) 1883 { 1884 struct mlx5_aso_mtr *aso_mtr; 1885 1886 if (priv->sh->meter_aso_en) { 1887 aso_mtr = mlx5_aso_meter_by_idx(priv, idx); 1888 if (!aso_mtr) 1889 return NULL; 1890 return &aso_mtr->fm; 1891 } else { 1892 return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx); 1893 } 1894 } 1895 1896 /** 1897 * Attach meter to flow. 1898 * Unidirectional Meter creation can only be done 1899 * when flow direction is known, i.e. when calling meter_attach. 1900 * 1901 * @param [in] priv 1902 * Pointer to mlx5 private data. 1903 * @param[in] fm 1904 * Pointer to flow meter. 1905 * @param [in] attr 1906 * Pointer to flow attributes. 1907 * @param [out] error 1908 * Pointer to error structure. 1909 * 1910 * @return 1911 * 0 on success, a negative errno value otherwise and rte_errno is set. 1912 */ 1913 int 1914 mlx5_flow_meter_attach(struct mlx5_priv *priv, 1915 struct mlx5_flow_meter_info *fm, 1916 const struct rte_flow_attr *attr, 1917 struct rte_flow_error *error) 1918 { 1919 int ret = 0; 1920 1921 if (priv->sh->meter_aso_en) { 1922 struct mlx5_aso_mtr *aso_mtr; 1923 1924 aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); 1925 if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) { 1926 return rte_flow_error_set(error, ENOENT, 1927 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, 1928 NULL, 1929 "Timeout in meter configuration"); 1930 } 1931 rte_spinlock_lock(&fm->sl); 1932 if (fm->shared || !fm->ref_cnt) { 1933 fm->ref_cnt++; 1934 } else { 1935 rte_flow_error_set(error, EINVAL, 1936 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1937 "Meter cannot be shared"); 1938 ret = -1; 1939 } 1940 rte_spinlock_unlock(&fm->sl); 1941 } else { 1942 rte_spinlock_lock(&fm->sl); 1943 if (fm->meter_action_g) { 1944 if (fm->shared && 1945 attr->transfer == fm->transfer && 1946 attr->ingress == fm->ingress && 1947 attr->egress == fm->egress) { 1948 fm->ref_cnt++; 1949 } else { 1950 rte_flow_error_set(error, EINVAL, 1951 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1952 fm->shared ? 1953 "Meter attr not match." : 1954 "Meter cannot be shared."); 1955 ret = -1; 1956 } 1957 } else { 1958 fm->ingress = attr->ingress; 1959 fm->egress = attr->egress; 1960 fm->transfer = attr->transfer; 1961 fm->ref_cnt = 1; 1962 /* This also creates the meter object. */ 1963 fm->meter_action_g = mlx5_flow_meter_action_create(priv, 1964 fm); 1965 if (!fm->meter_action_g) { 1966 fm->ref_cnt = 0; 1967 fm->ingress = 0; 1968 fm->egress = 0; 1969 fm->transfer = 0; 1970 rte_flow_error_set(error, EINVAL, 1971 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1972 "Meter action create failed."); 1973 ret = -1; 1974 } 1975 } 1976 rte_spinlock_unlock(&fm->sl); 1977 } 1978 return ret ? -rte_errno : 0; 1979 } 1980 1981 /** 1982 * Detach meter from flow. 1983 * 1984 * @param [in] priv 1985 * Pointer to mlx5 private data. 1986 * @param [in] fm 1987 * Pointer to flow meter. 1988 */ 1989 void 1990 mlx5_flow_meter_detach(struct mlx5_priv *priv, 1991 struct mlx5_flow_meter_info *fm) 1992 { 1993 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER 1994 rte_spinlock_lock(&fm->sl); 1995 MLX5_ASSERT(fm->ref_cnt); 1996 if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) { 1997 mlx5_glue->destroy_flow_action(fm->meter_action_g); 1998 fm->meter_action_g = NULL; 1999 fm->ingress = 0; 2000 fm->egress = 0; 2001 fm->transfer = 0; 2002 } 2003 rte_spinlock_unlock(&fm->sl); 2004 #else 2005 (void)priv; 2006 (void)fm; 2007 #endif 2008 } 2009 2010 /** 2011 * Flush meter with Rx queue configuration. 2012 * 2013 * @param[in] dev 2014 * Pointer to Ethernet device. 2015 */ 2016 void 2017 mlx5_flow_meter_rxq_flush(struct rte_eth_dev *dev) 2018 { 2019 struct mlx5_priv *priv = dev->data->dev_private; 2020 struct mlx5_flow_meter_sub_policy *sub_policy; 2021 struct mlx5_flow_meter_policy *mtr_policy; 2022 void *entry; 2023 uint32_t i, policy_idx; 2024 2025 if (!priv->mtr_en) 2026 return; 2027 if (priv->policy_idx_tbl) { 2028 MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) { 2029 policy_idx = *(uint32_t *)entry; 2030 sub_policy = mlx5_ipool_get 2031 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 2032 policy_idx); 2033 if (!sub_policy || !sub_policy->main_policy) 2034 continue; 2035 mtr_policy = sub_policy->main_policy; 2036 if (mtr_policy->is_queue || mtr_policy->is_rss) 2037 mlx5_flow_destroy_sub_policy_with_rxq(dev, 2038 mtr_policy); 2039 } 2040 } 2041 } 2042 2043 /** 2044 * Iterate a meter hierarchy and flush all meters and policies if possible. 2045 * 2046 * @param[in] dev 2047 * Pointer to Ethernet device. 2048 * @param[in] fm 2049 * Pointer to flow meter. 2050 * @param[in] mtr_idx 2051 * .Meter's index 2052 * @param[out] error 2053 * Pointer to rte meter error structure. 2054 * 2055 * @return 2056 * 0 on success, a negative errno value otherwise and rte_errno is set. 2057 */ 2058 static int 2059 mlx5_flow_meter_flush_hierarchy(struct rte_eth_dev *dev, 2060 struct mlx5_flow_meter_info *fm, 2061 uint32_t mtr_idx, 2062 struct rte_mtr_error *error) 2063 { 2064 struct mlx5_priv *priv = dev->data->dev_private; 2065 struct mlx5_flow_meter_policy *policy; 2066 uint32_t policy_id; 2067 struct mlx5_flow_meter_info *next_fm; 2068 uint32_t next_mtr_idx; 2069 struct mlx5_flow_meter_policy *next_policy = NULL; 2070 2071 policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL); 2072 MLX5_ASSERT(policy); 2073 while (!fm->ref_cnt && policy->is_hierarchy) { 2074 policy_id = fm->policy_id; 2075 next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, &next_mtr_idx); 2076 if (next_fm) { 2077 next_policy = mlx5_flow_meter_policy_find(dev, 2078 next_fm->policy_id, 2079 NULL); 2080 MLX5_ASSERT(next_policy); 2081 } 2082 if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx)) 2083 return -rte_mtr_error_set(error, ENOTSUP, 2084 RTE_MTR_ERROR_TYPE_MTR_ID, 2085 NULL, 2086 "Failed to flush meter."); 2087 if (policy->ref_cnt) 2088 break; 2089 if (__mlx5_flow_meter_policy_delete(dev, policy_id, 2090 policy, error, true)) 2091 return -rte_errno; 2092 mlx5_free(policy); 2093 if (!next_fm || !next_policy) 2094 break; 2095 fm = next_fm; 2096 mtr_idx = next_mtr_idx; 2097 policy = next_policy; 2098 } 2099 return 0; 2100 } 2101 2102 /** 2103 * Flush all the hierarchy meters and their policies. 2104 * 2105 * @param[in] dev 2106 * Pointer to Ethernet device. 2107 * @param[out] error 2108 * Pointer to rte meter error structure. 2109 * 2110 * @return 2111 * 0 on success, a negative errno value otherwise and rte_errno is set. 2112 */ 2113 static int 2114 mlx5_flow_meter_flush_all_hierarchies(struct rte_eth_dev *dev, 2115 struct rte_mtr_error *error) 2116 { 2117 struct mlx5_priv *priv = dev->data->dev_private; 2118 struct mlx5_flow_meter_info *fm; 2119 struct mlx5_flow_meter_policy *policy; 2120 struct mlx5_flow_meter_sub_policy *sub_policy; 2121 struct mlx5_flow_meter_info *next_fm; 2122 struct mlx5_aso_mtr *aso_mtr; 2123 uint32_t mtr_idx = 0; 2124 uint32_t i, policy_idx; 2125 void *entry; 2126 2127 if (!priv->mtr_idx_tbl || !priv->policy_idx_tbl) 2128 return 0; 2129 MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) { 2130 mtr_idx = *(uint32_t *)entry; 2131 if (!mtr_idx) 2132 continue; 2133 aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx); 2134 fm = &aso_mtr->fm; 2135 if (fm->ref_cnt || fm->def_policy) 2136 continue; 2137 if (mlx5_flow_meter_flush_hierarchy(dev, fm, mtr_idx, error)) 2138 return -rte_errno; 2139 } 2140 MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) { 2141 policy_idx = *(uint32_t *)entry; 2142 sub_policy = mlx5_ipool_get 2143 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 2144 policy_idx); 2145 if (!sub_policy) 2146 return -rte_mtr_error_set(error, 2147 EINVAL, 2148 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 2149 NULL, "Meter policy invalid."); 2150 policy = sub_policy->main_policy; 2151 if (!policy || !policy->is_hierarchy || policy->ref_cnt) 2152 continue; 2153 next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, &mtr_idx); 2154 if (__mlx5_flow_meter_policy_delete(dev, i, policy, 2155 error, true)) 2156 return -rte_mtr_error_set(error, 2157 EINVAL, 2158 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 2159 NULL, "Meter policy invalid."); 2160 mlx5_free(policy); 2161 if (!next_fm || next_fm->ref_cnt || next_fm->def_policy) 2162 continue; 2163 if (mlx5_flow_meter_flush_hierarchy(dev, next_fm, 2164 mtr_idx, error)) 2165 return -rte_errno; 2166 } 2167 return 0; 2168 } 2169 /** 2170 * Flush meter configuration. 2171 * 2172 * @param[in] dev 2173 * Pointer to Ethernet device. 2174 * @param[out] error 2175 * Pointer to rte meter error structure. 2176 * 2177 * @return 2178 * 0 on success, a negative errno value otherwise and rte_errno is set. 2179 */ 2180 int 2181 mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error) 2182 { 2183 struct mlx5_priv *priv = dev->data->dev_private; 2184 struct mlx5_legacy_flow_meters *fms = &priv->flow_meters; 2185 struct mlx5_flow_meter_profile *fmp; 2186 struct mlx5_legacy_flow_meter *legacy_fm; 2187 struct mlx5_flow_meter_info *fm; 2188 struct mlx5_flow_meter_sub_policy *sub_policy; 2189 void *tmp; 2190 uint32_t i, mtr_idx, policy_idx; 2191 void *entry; 2192 struct mlx5_aso_mtr *aso_mtr; 2193 2194 if (!priv->mtr_en) 2195 return 0; 2196 if (priv->sh->meter_aso_en) { 2197 if (mlx5_flow_meter_flush_all_hierarchies(dev, error)) 2198 return -rte_errno; 2199 if (priv->mtr_idx_tbl) { 2200 MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) { 2201 mtr_idx = *(uint32_t *)entry; 2202 if (mtr_idx) { 2203 aso_mtr = 2204 mlx5_aso_meter_by_idx(priv, mtr_idx); 2205 fm = &aso_mtr->fm; 2206 (void)mlx5_flow_meter_params_flush(dev, 2207 fm, mtr_idx); 2208 } 2209 } 2210 mlx5_l3t_destroy(priv->mtr_idx_tbl); 2211 priv->mtr_idx_tbl = NULL; 2212 } 2213 } else { 2214 RTE_TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) { 2215 fm = &legacy_fm->fm; 2216 if (mlx5_flow_meter_params_flush(dev, fm, 0)) 2217 return -rte_mtr_error_set(error, EINVAL, 2218 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, 2219 NULL, "MTR object meter profile invalid."); 2220 } 2221 } 2222 if (priv->policy_idx_tbl) { 2223 MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) { 2224 policy_idx = *(uint32_t *)entry; 2225 sub_policy = mlx5_ipool_get 2226 (priv->sh->ipool[MLX5_IPOOL_MTR_POLICY], 2227 policy_idx); 2228 if (!sub_policy) 2229 return -rte_mtr_error_set(error, 2230 EINVAL, 2231 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 2232 NULL, "MTR object " 2233 "meter policy invalid."); 2234 if (__mlx5_flow_meter_policy_delete(dev, i, 2235 sub_policy->main_policy, 2236 error, true)) 2237 return -rte_mtr_error_set(error, 2238 EINVAL, 2239 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 2240 NULL, "MTR object " 2241 "meter policy invalid."); 2242 mlx5_free(sub_policy->main_policy); 2243 } 2244 mlx5_l3t_destroy(priv->policy_idx_tbl); 2245 priv->policy_idx_tbl = NULL; 2246 } 2247 if (priv->mtr_profile_tbl) { 2248 MLX5_L3T_FOREACH(priv->mtr_profile_tbl, i, entry) { 2249 fmp = entry; 2250 if (mlx5_flow_meter_profile_delete(dev, fmp->id, 2251 error)) 2252 return -rte_mtr_error_set(error, EINVAL, 2253 RTE_MTR_ERROR_TYPE_METER_POLICY_ID, 2254 NULL, "Fail to destroy " 2255 "meter profile."); 2256 } 2257 mlx5_l3t_destroy(priv->mtr_profile_tbl); 2258 priv->mtr_profile_tbl = NULL; 2259 } 2260 /* Delete default policy table. */ 2261 mlx5_flow_destroy_def_policy(dev); 2262 if (priv->sh->refcnt == 1) 2263 mlx5_flow_destroy_mtr_drop_tbls(dev); 2264 return 0; 2265 } 2266