rss.c (14443B)
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. 3 4#include "rss.h" 5 6#define mlx5e_rss_warn(__dev, format, ...) \ 7 dev_warn((__dev)->device, "%s:%d:(pid %d): " format, \ 8 __func__, __LINE__, current->pid, \ 9 ##__VA_ARGS__) 10 11static const struct mlx5e_rss_params_traffic_type rss_default_config[MLX5E_NUM_INDIR_TIRS] = { 12 [MLX5_TT_IPV4_TCP] = { 13 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4, 14 .l4_prot_type = MLX5_L4_PROT_TYPE_TCP, 15 .rx_hash_fields = MLX5_HASH_IP_L4PORTS, 16 }, 17 [MLX5_TT_IPV6_TCP] = { 18 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6, 19 .l4_prot_type = MLX5_L4_PROT_TYPE_TCP, 20 .rx_hash_fields = MLX5_HASH_IP_L4PORTS, 21 }, 22 [MLX5_TT_IPV4_UDP] = { 23 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4, 24 .l4_prot_type = MLX5_L4_PROT_TYPE_UDP, 25 .rx_hash_fields = MLX5_HASH_IP_L4PORTS, 26 }, 27 [MLX5_TT_IPV6_UDP] = { 28 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6, 29 .l4_prot_type = MLX5_L4_PROT_TYPE_UDP, 30 .rx_hash_fields = MLX5_HASH_IP_L4PORTS, 31 }, 32 [MLX5_TT_IPV4_IPSEC_AH] = { 33 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4, 34 .l4_prot_type = 0, 35 .rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI, 36 }, 37 [MLX5_TT_IPV6_IPSEC_AH] = { 38 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6, 39 .l4_prot_type = 0, 40 .rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI, 41 }, 42 [MLX5_TT_IPV4_IPSEC_ESP] = { 43 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4, 44 .l4_prot_type = 0, 45 .rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI, 46 }, 47 [MLX5_TT_IPV6_IPSEC_ESP] = { 48 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6, 49 .l4_prot_type = 0, 50 .rx_hash_fields = MLX5_HASH_IP_IPSEC_SPI, 51 }, 52 [MLX5_TT_IPV4] = { 53 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV4, 54 .l4_prot_type = 0, 55 .rx_hash_fields = MLX5_HASH_IP, 56 }, 57 [MLX5_TT_IPV6] = { 58 .l3_prot_type = MLX5_L3_PROT_TYPE_IPV6, 59 .l4_prot_type = 0, 60 .rx_hash_fields = MLX5_HASH_IP, 61 }, 62}; 63 64struct mlx5e_rss_params_traffic_type 65mlx5e_rss_get_default_tt_config(enum mlx5_traffic_types tt) 66{ 67 return rss_default_config[tt]; 68} 69 70struct mlx5e_rss { 71 struct mlx5e_rss_params_hash hash; 72 struct mlx5e_rss_params_indir indir; 73 u32 rx_hash_fields[MLX5E_NUM_INDIR_TIRS]; 74 struct mlx5e_tir *tir[MLX5E_NUM_INDIR_TIRS]; 75 struct mlx5e_tir *inner_tir[MLX5E_NUM_INDIR_TIRS]; 76 struct mlx5e_rqt rqt; 77 struct mlx5_core_dev *mdev; 78 u32 drop_rqn; 79 bool inner_ft_support; 80 bool enabled; 81 refcount_t refcnt; 82}; 83 84struct mlx5e_rss *mlx5e_rss_alloc(void) 85{ 86 return kvzalloc(sizeof(struct mlx5e_rss), GFP_KERNEL); 87} 88 89void mlx5e_rss_free(struct mlx5e_rss *rss) 90{ 91 kvfree(rss); 92} 93 94static void mlx5e_rss_params_init(struct mlx5e_rss *rss) 95{ 96 enum mlx5_traffic_types tt; 97 98 rss->hash.hfunc = ETH_RSS_HASH_TOP; 99 netdev_rss_key_fill(rss->hash.toeplitz_hash_key, 100 sizeof(rss->hash.toeplitz_hash_key)); 101 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) 102 rss->rx_hash_fields[tt] = 103 mlx5e_rss_get_default_tt_config(tt).rx_hash_fields; 104} 105 106static struct mlx5e_tir **rss_get_tirp(struct mlx5e_rss *rss, enum mlx5_traffic_types tt, 107 bool inner) 108{ 109 return inner ? &rss->inner_tir[tt] : &rss->tir[tt]; 110} 111 112static struct mlx5e_tir *rss_get_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt, 113 bool inner) 114{ 115 return *rss_get_tirp(rss, tt, inner); 116} 117 118static struct mlx5e_rss_params_traffic_type 119mlx5e_rss_get_tt_config(struct mlx5e_rss *rss, enum mlx5_traffic_types tt) 120{ 121 struct mlx5e_rss_params_traffic_type rss_tt; 122 123 rss_tt = mlx5e_rss_get_default_tt_config(tt); 124 rss_tt.rx_hash_fields = rss->rx_hash_fields[tt]; 125 return rss_tt; 126} 127 128static int mlx5e_rss_create_tir(struct mlx5e_rss *rss, 129 enum mlx5_traffic_types tt, 130 const struct mlx5e_packet_merge_param *init_pkt_merge_param, 131 bool inner) 132{ 133 struct mlx5e_rss_params_traffic_type rss_tt; 134 struct mlx5e_tir_builder *builder; 135 struct mlx5e_tir **tir_p; 136 struct mlx5e_tir *tir; 137 u32 rqtn; 138 int err; 139 140 if (inner && !rss->inner_ft_support) { 141 mlx5e_rss_warn(rss->mdev, 142 "Cannot create inner indirect TIR[%d], RSS inner FT is not supported.\n", 143 tt); 144 return -EINVAL; 145 } 146 147 tir_p = rss_get_tirp(rss, tt, inner); 148 if (*tir_p) 149 return -EINVAL; 150 151 tir = kvzalloc(sizeof(*tir), GFP_KERNEL); 152 if (!tir) 153 return -ENOMEM; 154 155 builder = mlx5e_tir_builder_alloc(false); 156 if (!builder) { 157 err = -ENOMEM; 158 goto free_tir; 159 } 160 161 rqtn = mlx5e_rqt_get_rqtn(&rss->rqt); 162 mlx5e_tir_builder_build_rqt(builder, rss->mdev->mlx5e_res.hw_objs.td.tdn, 163 rqtn, rss->inner_ft_support); 164 mlx5e_tir_builder_build_packet_merge(builder, init_pkt_merge_param); 165 rss_tt = mlx5e_rss_get_tt_config(rss, tt); 166 mlx5e_tir_builder_build_rss(builder, &rss->hash, &rss_tt, inner); 167 168 err = mlx5e_tir_init(tir, builder, rss->mdev, true); 169 mlx5e_tir_builder_free(builder); 170 if (err) { 171 mlx5e_rss_warn(rss->mdev, "Failed to create %sindirect TIR: err = %d, tt = %d\n", 172 inner ? "inner " : "", err, tt); 173 goto free_tir; 174 } 175 176 *tir_p = tir; 177 return 0; 178 179free_tir: 180 kvfree(tir); 181 return err; 182} 183 184static void mlx5e_rss_destroy_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt, 185 bool inner) 186{ 187 struct mlx5e_tir **tir_p; 188 struct mlx5e_tir *tir; 189 190 tir_p = rss_get_tirp(rss, tt, inner); 191 if (!*tir_p) 192 return; 193 194 tir = *tir_p; 195 mlx5e_tir_destroy(tir); 196 kvfree(tir); 197 *tir_p = NULL; 198} 199 200static int mlx5e_rss_create_tirs(struct mlx5e_rss *rss, 201 const struct mlx5e_packet_merge_param *init_pkt_merge_param, 202 bool inner) 203{ 204 enum mlx5_traffic_types tt, max_tt; 205 int err; 206 207 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) { 208 err = mlx5e_rss_create_tir(rss, tt, init_pkt_merge_param, inner); 209 if (err) 210 goto err_destroy_tirs; 211 } 212 213 return 0; 214 215err_destroy_tirs: 216 max_tt = tt; 217 for (tt = 0; tt < max_tt; tt++) 218 mlx5e_rss_destroy_tir(rss, tt, inner); 219 return err; 220} 221 222static void mlx5e_rss_destroy_tirs(struct mlx5e_rss *rss, bool inner) 223{ 224 enum mlx5_traffic_types tt; 225 226 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) 227 mlx5e_rss_destroy_tir(rss, tt, inner); 228} 229 230static int mlx5e_rss_update_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt, 231 bool inner) 232{ 233 struct mlx5e_rss_params_traffic_type rss_tt; 234 struct mlx5e_tir_builder *builder; 235 struct mlx5e_tir *tir; 236 int err; 237 238 tir = rss_get_tir(rss, tt, inner); 239 if (!tir) 240 return 0; 241 242 builder = mlx5e_tir_builder_alloc(true); 243 if (!builder) 244 return -ENOMEM; 245 246 rss_tt = mlx5e_rss_get_tt_config(rss, tt); 247 248 mlx5e_tir_builder_build_rss(builder, &rss->hash, &rss_tt, inner); 249 err = mlx5e_tir_modify(tir, builder); 250 251 mlx5e_tir_builder_free(builder); 252 return err; 253} 254 255static int mlx5e_rss_update_tirs(struct mlx5e_rss *rss) 256{ 257 enum mlx5_traffic_types tt; 258 int err, retval; 259 260 retval = 0; 261 262 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) { 263 err = mlx5e_rss_update_tir(rss, tt, false); 264 if (err) { 265 retval = retval ? : err; 266 mlx5e_rss_warn(rss->mdev, 267 "Failed to update RSS hash of indirect TIR for traffic type %d: err = %d\n", 268 tt, err); 269 } 270 271 if (!rss->inner_ft_support) 272 continue; 273 274 err = mlx5e_rss_update_tir(rss, tt, true); 275 if (err) { 276 retval = retval ? : err; 277 mlx5e_rss_warn(rss->mdev, 278 "Failed to update RSS hash of inner indirect TIR for traffic type %d: err = %d\n", 279 tt, err); 280 } 281 } 282 return retval; 283} 284 285int mlx5e_rss_init_no_tirs(struct mlx5e_rss *rss, struct mlx5_core_dev *mdev, 286 bool inner_ft_support, u32 drop_rqn) 287{ 288 rss->mdev = mdev; 289 rss->inner_ft_support = inner_ft_support; 290 rss->drop_rqn = drop_rqn; 291 292 mlx5e_rss_params_init(rss); 293 refcount_set(&rss->refcnt, 1); 294 295 return mlx5e_rqt_init_direct(&rss->rqt, mdev, true, drop_rqn); 296} 297 298int mlx5e_rss_init(struct mlx5e_rss *rss, struct mlx5_core_dev *mdev, 299 bool inner_ft_support, u32 drop_rqn, 300 const struct mlx5e_packet_merge_param *init_pkt_merge_param) 301{ 302 int err; 303 304 err = mlx5e_rss_init_no_tirs(rss, mdev, inner_ft_support, drop_rqn); 305 if (err) 306 goto err_out; 307 308 err = mlx5e_rss_create_tirs(rss, init_pkt_merge_param, false); 309 if (err) 310 goto err_destroy_rqt; 311 312 if (inner_ft_support) { 313 err = mlx5e_rss_create_tirs(rss, init_pkt_merge_param, true); 314 if (err) 315 goto err_destroy_tirs; 316 } 317 318 return 0; 319 320err_destroy_tirs: 321 mlx5e_rss_destroy_tirs(rss, false); 322err_destroy_rqt: 323 mlx5e_rqt_destroy(&rss->rqt); 324err_out: 325 return err; 326} 327 328int mlx5e_rss_cleanup(struct mlx5e_rss *rss) 329{ 330 if (!refcount_dec_if_one(&rss->refcnt)) 331 return -EBUSY; 332 333 mlx5e_rss_destroy_tirs(rss, false); 334 335 if (rss->inner_ft_support) 336 mlx5e_rss_destroy_tirs(rss, true); 337 338 mlx5e_rqt_destroy(&rss->rqt); 339 340 return 0; 341} 342 343void mlx5e_rss_refcnt_inc(struct mlx5e_rss *rss) 344{ 345 refcount_inc(&rss->refcnt); 346} 347 348void mlx5e_rss_refcnt_dec(struct mlx5e_rss *rss) 349{ 350 refcount_dec(&rss->refcnt); 351} 352 353unsigned int mlx5e_rss_refcnt_read(struct mlx5e_rss *rss) 354{ 355 return refcount_read(&rss->refcnt); 356} 357 358u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt, 359 bool inner) 360{ 361 struct mlx5e_tir *tir; 362 363 WARN_ON(inner && !rss->inner_ft_support); 364 tir = rss_get_tir(rss, tt, inner); 365 WARN_ON(!tir); 366 367 return mlx5e_tir_get_tirn(tir); 368} 369 370/* Fill the "tirn" output parameter. 371 * Create the requested TIR if it's its first usage. 372 */ 373int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss, 374 enum mlx5_traffic_types tt, 375 const struct mlx5e_packet_merge_param *init_pkt_merge_param, 376 bool inner, u32 *tirn) 377{ 378 struct mlx5e_tir *tir; 379 380 tir = rss_get_tir(rss, tt, inner); 381 if (!tir) { /* TIR doesn't exist, create one */ 382 int err; 383 384 err = mlx5e_rss_create_tir(rss, tt, init_pkt_merge_param, inner); 385 if (err) 386 return err; 387 tir = rss_get_tir(rss, tt, inner); 388 } 389 390 *tirn = mlx5e_tir_get_tirn(tir); 391 return 0; 392} 393 394static int mlx5e_rss_apply(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns) 395{ 396 int err; 397 398 err = mlx5e_rqt_redirect_indir(&rss->rqt, rqns, num_rqns, rss->hash.hfunc, &rss->indir); 399 if (err) 400 mlx5e_rss_warn(rss->mdev, "Failed to redirect RQT %#x to channels: err = %d\n", 401 mlx5e_rqt_get_rqtn(&rss->rqt), err); 402 return err; 403} 404 405void mlx5e_rss_enable(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns) 406{ 407 rss->enabled = true; 408 mlx5e_rss_apply(rss, rqns, num_rqns); 409} 410 411void mlx5e_rss_disable(struct mlx5e_rss *rss) 412{ 413 int err; 414 415 rss->enabled = false; 416 err = mlx5e_rqt_redirect_direct(&rss->rqt, rss->drop_rqn); 417 if (err) 418 mlx5e_rss_warn(rss->mdev, "Failed to redirect RQT %#x to drop RQ %#x: err = %d\n", 419 mlx5e_rqt_get_rqtn(&rss->rqt), rss->drop_rqn, err); 420} 421 422int mlx5e_rss_packet_merge_set_param(struct mlx5e_rss *rss, 423 struct mlx5e_packet_merge_param *pkt_merge_param) 424{ 425 struct mlx5e_tir_builder *builder; 426 enum mlx5_traffic_types tt; 427 int err, final_err; 428 429 builder = mlx5e_tir_builder_alloc(true); 430 if (!builder) 431 return -ENOMEM; 432 433 mlx5e_tir_builder_build_packet_merge(builder, pkt_merge_param); 434 435 final_err = 0; 436 437 for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) { 438 struct mlx5e_tir *tir; 439 440 tir = rss_get_tir(rss, tt, false); 441 if (!tir) 442 goto inner_tir; 443 err = mlx5e_tir_modify(tir, builder); 444 if (err) { 445 mlx5e_rss_warn(rss->mdev, "Failed to update packet merge state of indirect TIR %#x for traffic type %d: err = %d\n", 446 mlx5e_tir_get_tirn(tir), tt, err); 447 if (!final_err) 448 final_err = err; 449 } 450 451inner_tir: 452 if (!rss->inner_ft_support) 453 continue; 454 455 tir = rss_get_tir(rss, tt, true); 456 if (!tir) 457 continue; 458 err = mlx5e_tir_modify(tir, builder); 459 if (err) { 460 mlx5e_rss_warn(rss->mdev, "Failed to update packet merge state of inner indirect TIR %#x for traffic type %d: err = %d\n", 461 mlx5e_tir_get_tirn(tir), tt, err); 462 if (!final_err) 463 final_err = err; 464 } 465 } 466 467 mlx5e_tir_builder_free(builder); 468 return final_err; 469} 470 471int mlx5e_rss_get_rxfh(struct mlx5e_rss *rss, u32 *indir, u8 *key, u8 *hfunc) 472{ 473 unsigned int i; 474 475 if (indir) 476 for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++) 477 indir[i] = rss->indir.table[i]; 478 479 if (key) 480 memcpy(key, rss->hash.toeplitz_hash_key, 481 sizeof(rss->hash.toeplitz_hash_key)); 482 483 if (hfunc) 484 *hfunc = rss->hash.hfunc; 485 486 return 0; 487} 488 489int mlx5e_rss_set_rxfh(struct mlx5e_rss *rss, const u32 *indir, 490 const u8 *key, const u8 *hfunc, 491 u32 *rqns, unsigned int num_rqns) 492{ 493 bool changed_indir = false; 494 bool changed_hash = false; 495 struct mlx5e_rss *old_rss; 496 int err = 0; 497 498 old_rss = mlx5e_rss_alloc(); 499 if (!old_rss) 500 return -ENOMEM; 501 502 *old_rss = *rss; 503 504 if (hfunc && *hfunc != rss->hash.hfunc) { 505 switch (*hfunc) { 506 case ETH_RSS_HASH_XOR: 507 case ETH_RSS_HASH_TOP: 508 break; 509 default: 510 err = -EINVAL; 511 goto out; 512 } 513 changed_hash = true; 514 changed_indir = true; 515 rss->hash.hfunc = *hfunc; 516 } 517 518 if (key) { 519 if (rss->hash.hfunc == ETH_RSS_HASH_TOP) 520 changed_hash = true; 521 memcpy(rss->hash.toeplitz_hash_key, key, 522 sizeof(rss->hash.toeplitz_hash_key)); 523 } 524 525 if (indir) { 526 unsigned int i; 527 528 changed_indir = true; 529 530 for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++) 531 rss->indir.table[i] = indir[i]; 532 } 533 534 if (changed_indir && rss->enabled) { 535 err = mlx5e_rss_apply(rss, rqns, num_rqns); 536 if (err) { 537 *rss = *old_rss; 538 goto out; 539 } 540 } 541 542 if (changed_hash) 543 mlx5e_rss_update_tirs(rss); 544 545out: 546 mlx5e_rss_free(old_rss); 547 return err; 548} 549 550struct mlx5e_rss_params_hash mlx5e_rss_get_hash(struct mlx5e_rss *rss) 551{ 552 return rss->hash; 553} 554 555u8 mlx5e_rss_get_hash_fields(struct mlx5e_rss *rss, enum mlx5_traffic_types tt) 556{ 557 return rss->rx_hash_fields[tt]; 558} 559 560int mlx5e_rss_set_hash_fields(struct mlx5e_rss *rss, enum mlx5_traffic_types tt, 561 u8 rx_hash_fields) 562{ 563 u8 old_rx_hash_fields; 564 int err; 565 566 old_rx_hash_fields = rss->rx_hash_fields[tt]; 567 568 if (old_rx_hash_fields == rx_hash_fields) 569 return 0; 570 571 rss->rx_hash_fields[tt] = rx_hash_fields; 572 573 err = mlx5e_rss_update_tir(rss, tt, false); 574 if (err) { 575 rss->rx_hash_fields[tt] = old_rx_hash_fields; 576 mlx5e_rss_warn(rss->mdev, 577 "Failed to update RSS hash fields of indirect TIR for traffic type %d: err = %d\n", 578 tt, err); 579 return err; 580 } 581 582 if (!(rss->inner_ft_support)) 583 return 0; 584 585 err = mlx5e_rss_update_tir(rss, tt, true); 586 if (err) { 587 /* Partial update happened. Try to revert - it may fail too, but 588 * there is nothing more we can do. 589 */ 590 rss->rx_hash_fields[tt] = old_rx_hash_fields; 591 mlx5e_rss_warn(rss->mdev, 592 "Failed to update RSS hash fields of inner indirect TIR for traffic type %d: err = %d\n", 593 tt, err); 594 if (mlx5e_rss_update_tir(rss, tt, false)) 595 mlx5e_rss_warn(rss->mdev, 596 "Partial update of RSS hash fields happened: failed to revert indirect TIR for traffic type %d to the old values\n", 597 tt); 598 } 599 600 return err; 601} 602 603void mlx5e_rss_set_indir_uniform(struct mlx5e_rss *rss, unsigned int nch) 604{ 605 mlx5e_rss_params_indir_init_uniform(&rss->indir, nch); 606}