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