1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2021, Mellanox Technologies inc. All rights reserved. */ 3 4 #include "rx_res.h" 5 #include "channels.h" 6 #include "params.h" 7 8 #define MLX5E_MAX_NUM_RSS 16 9 10 struct mlx5e_rx_res { 11 struct mlx5_core_dev *mdev; 12 enum mlx5e_rx_res_features features; 13 unsigned int max_nch; 14 u32 drop_rqn; 15 16 struct mlx5e_rss *rss[MLX5E_MAX_NUM_RSS]; 17 bool rss_active; 18 u32 rss_rqns[MLX5E_INDIR_RQT_SIZE]; 19 unsigned int rss_nch; 20 21 struct { 22 struct mlx5e_rqt direct_rqt; 23 struct mlx5e_tir direct_tir; 24 struct mlx5e_rqt xsk_rqt; 25 struct mlx5e_tir xsk_tir; 26 } *channels; 27 28 struct { 29 struct mlx5e_rqt rqt; 30 struct mlx5e_tir tir; 31 } ptp; 32 }; 33 34 /* API for rx_res_rss_* */ 35 36 static int mlx5e_rx_res_rss_init_def(struct mlx5e_rx_res *res, 37 const struct mlx5e_lro_param *init_lro_param, 38 unsigned int init_nch) 39 { 40 bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT; 41 struct mlx5e_rss *rss; 42 int err; 43 44 if (WARN_ON(res->rss[0])) 45 return -EINVAL; 46 47 rss = mlx5e_rss_alloc(); 48 if (!rss) 49 return -ENOMEM; 50 51 err = mlx5e_rss_init(rss, res->mdev, inner_ft_support, res->drop_rqn, 52 init_lro_param); 53 if (err) 54 goto err_rss_free; 55 56 mlx5e_rss_set_indir_uniform(rss, init_nch); 57 58 res->rss[0] = rss; 59 60 return 0; 61 62 err_rss_free: 63 mlx5e_rss_free(rss); 64 return err; 65 } 66 67 int mlx5e_rx_res_rss_init(struct mlx5e_rx_res *res, u32 *rss_idx, unsigned int init_nch) 68 { 69 bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT; 70 struct mlx5e_rss *rss; 71 int err, i; 72 73 for (i = 1; i < MLX5E_MAX_NUM_RSS; i++) 74 if (!res->rss[i]) 75 break; 76 77 if (i == MLX5E_MAX_NUM_RSS) 78 return -ENOSPC; 79 80 rss = mlx5e_rss_alloc(); 81 if (!rss) 82 return -ENOMEM; 83 84 err = mlx5e_rss_init_no_tirs(rss, res->mdev, inner_ft_support, res->drop_rqn); 85 if (err) 86 goto err_rss_free; 87 88 mlx5e_rss_set_indir_uniform(rss, init_nch); 89 if (res->rss_active) 90 mlx5e_rss_enable(rss, res->rss_rqns, res->rss_nch); 91 92 res->rss[i] = rss; 93 *rss_idx = i; 94 95 return 0; 96 97 err_rss_free: 98 mlx5e_rss_free(rss); 99 return err; 100 } 101 102 static int __mlx5e_rx_res_rss_destroy(struct mlx5e_rx_res *res, u32 rss_idx) 103 { 104 struct mlx5e_rss *rss = res->rss[rss_idx]; 105 int err; 106 107 err = mlx5e_rss_cleanup(rss); 108 if (err) 109 return err; 110 111 mlx5e_rss_free(rss); 112 res->rss[rss_idx] = NULL; 113 114 return 0; 115 } 116 117 int mlx5e_rx_res_rss_destroy(struct mlx5e_rx_res *res, u32 rss_idx) 118 { 119 struct mlx5e_rss *rss; 120 121 if (rss_idx >= MLX5E_MAX_NUM_RSS) 122 return -EINVAL; 123 124 rss = res->rss[rss_idx]; 125 if (!rss) 126 return -EINVAL; 127 128 return __mlx5e_rx_res_rss_destroy(res, rss_idx); 129 } 130 131 static void mlx5e_rx_res_rss_destroy_all(struct mlx5e_rx_res *res) 132 { 133 int i; 134 135 for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) { 136 struct mlx5e_rss *rss = res->rss[i]; 137 int err; 138 139 if (!rss) 140 continue; 141 142 err = __mlx5e_rx_res_rss_destroy(res, i); 143 if (err) { 144 unsigned int refcount; 145 146 refcount = mlx5e_rss_refcnt_read(rss); 147 mlx5_core_warn(res->mdev, 148 "Failed to destroy RSS context %d, refcount = %u, err = %d\n", 149 i, refcount, err); 150 } 151 } 152 } 153 154 static void mlx5e_rx_res_rss_enable(struct mlx5e_rx_res *res) 155 { 156 int i; 157 158 res->rss_active = true; 159 160 for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) { 161 struct mlx5e_rss *rss = res->rss[i]; 162 163 if (!rss) 164 continue; 165 mlx5e_rss_enable(rss, res->rss_rqns, res->rss_nch); 166 } 167 } 168 169 static void mlx5e_rx_res_rss_disable(struct mlx5e_rx_res *res) 170 { 171 int i; 172 173 res->rss_active = false; 174 175 for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) { 176 struct mlx5e_rss *rss = res->rss[i]; 177 178 if (!rss) 179 continue; 180 mlx5e_rss_disable(rss); 181 } 182 } 183 184 /* Updates the indirection table SW shadow, does not update the HW resources yet */ 185 void mlx5e_rx_res_rss_set_indir_uniform(struct mlx5e_rx_res *res, unsigned int nch) 186 { 187 WARN_ON_ONCE(res->rss_active); 188 mlx5e_rss_set_indir_uniform(res->rss[0], nch); 189 } 190 191 int mlx5e_rx_res_rss_get_rxfh(struct mlx5e_rx_res *res, u32 rss_idx, 192 u32 *indir, u8 *key, u8 *hfunc) 193 { 194 struct mlx5e_rss *rss; 195 196 if (rss_idx >= MLX5E_MAX_NUM_RSS) 197 return -EINVAL; 198 199 rss = res->rss[rss_idx]; 200 if (!rss) 201 return -ENOENT; 202 203 return mlx5e_rss_get_rxfh(rss, indir, key, hfunc); 204 } 205 206 int mlx5e_rx_res_rss_set_rxfh(struct mlx5e_rx_res *res, u32 rss_idx, 207 const u32 *indir, const u8 *key, const u8 *hfunc) 208 { 209 struct mlx5e_rss *rss; 210 211 if (rss_idx >= MLX5E_MAX_NUM_RSS) 212 return -EINVAL; 213 214 rss = res->rss[rss_idx]; 215 if (!rss) 216 return -ENOENT; 217 218 return mlx5e_rss_set_rxfh(rss, indir, key, hfunc, res->rss_rqns, res->rss_nch); 219 } 220 221 u8 mlx5e_rx_res_rss_get_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt) 222 { 223 struct mlx5e_rss *rss = res->rss[0]; 224 225 return mlx5e_rss_get_hash_fields(rss, tt); 226 } 227 228 int mlx5e_rx_res_rss_set_hash_fields(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt, 229 u8 rx_hash_fields) 230 { 231 struct mlx5e_rss *rss = res->rss[0]; 232 233 return mlx5e_rss_set_hash_fields(rss, tt, rx_hash_fields); 234 } 235 236 int mlx5e_rx_res_rss_cnt(struct mlx5e_rx_res *res) 237 { 238 int i, cnt; 239 240 cnt = 0; 241 for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) 242 if (res->rss[i]) 243 cnt++; 244 245 return cnt; 246 } 247 248 int mlx5e_rx_res_rss_index(struct mlx5e_rx_res *res, struct mlx5e_rss *rss) 249 { 250 int i; 251 252 if (!rss) 253 return -EINVAL; 254 255 for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) 256 if (rss == res->rss[i]) 257 return i; 258 259 return -ENOENT; 260 } 261 262 struct mlx5e_rss *mlx5e_rx_res_rss_get(struct mlx5e_rx_res *res, u32 rss_idx) 263 { 264 if (rss_idx >= MLX5E_MAX_NUM_RSS) 265 return NULL; 266 267 return res->rss[rss_idx]; 268 } 269 270 /* End of API rx_res_rss_* */ 271 272 struct mlx5e_rx_res *mlx5e_rx_res_alloc(void) 273 { 274 return kvzalloc(sizeof(struct mlx5e_rx_res), GFP_KERNEL); 275 } 276 277 static int mlx5e_rx_res_channels_init(struct mlx5e_rx_res *res, 278 const struct mlx5e_lro_param *init_lro_param) 279 { 280 bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT; 281 struct mlx5e_tir_builder *builder; 282 int err = 0; 283 int ix; 284 285 builder = mlx5e_tir_builder_alloc(false); 286 if (!builder) 287 return -ENOMEM; 288 289 res->channels = kvcalloc(res->max_nch, sizeof(*res->channels), GFP_KERNEL); 290 if (!res->channels) { 291 err = -ENOMEM; 292 goto out; 293 } 294 295 for (ix = 0; ix < res->max_nch; ix++) { 296 err = mlx5e_rqt_init_direct(&res->channels[ix].direct_rqt, 297 res->mdev, false, res->drop_rqn); 298 if (err) { 299 mlx5_core_warn(res->mdev, "Failed to create a direct RQT: err = %d, ix = %u\n", 300 err, ix); 301 goto err_destroy_direct_rqts; 302 } 303 } 304 305 for (ix = 0; ix < res->max_nch; ix++) { 306 mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn, 307 mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt), 308 inner_ft_support); 309 mlx5e_tir_builder_build_lro(builder, init_lro_param); 310 mlx5e_tir_builder_build_direct(builder); 311 312 err = mlx5e_tir_init(&res->channels[ix].direct_tir, builder, res->mdev, true); 313 if (err) { 314 mlx5_core_warn(res->mdev, "Failed to create a direct TIR: err = %d, ix = %u\n", 315 err, ix); 316 goto err_destroy_direct_tirs; 317 } 318 319 mlx5e_tir_builder_clear(builder); 320 } 321 322 if (!(res->features & MLX5E_RX_RES_FEATURE_XSK)) 323 goto out; 324 325 for (ix = 0; ix < res->max_nch; ix++) { 326 err = mlx5e_rqt_init_direct(&res->channels[ix].xsk_rqt, 327 res->mdev, false, res->drop_rqn); 328 if (err) { 329 mlx5_core_warn(res->mdev, "Failed to create an XSK RQT: err = %d, ix = %u\n", 330 err, ix); 331 goto err_destroy_xsk_rqts; 332 } 333 } 334 335 for (ix = 0; ix < res->max_nch; ix++) { 336 mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn, 337 mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt), 338 inner_ft_support); 339 mlx5e_tir_builder_build_lro(builder, init_lro_param); 340 mlx5e_tir_builder_build_direct(builder); 341 342 err = mlx5e_tir_init(&res->channels[ix].xsk_tir, builder, res->mdev, true); 343 if (err) { 344 mlx5_core_warn(res->mdev, "Failed to create an XSK TIR: err = %d, ix = %u\n", 345 err, ix); 346 goto err_destroy_xsk_tirs; 347 } 348 349 mlx5e_tir_builder_clear(builder); 350 } 351 352 goto out; 353 354 err_destroy_xsk_tirs: 355 while (--ix >= 0) 356 mlx5e_tir_destroy(&res->channels[ix].xsk_tir); 357 358 ix = res->max_nch; 359 err_destroy_xsk_rqts: 360 while (--ix >= 0) 361 mlx5e_rqt_destroy(&res->channels[ix].xsk_rqt); 362 363 ix = res->max_nch; 364 err_destroy_direct_tirs: 365 while (--ix >= 0) 366 mlx5e_tir_destroy(&res->channels[ix].direct_tir); 367 368 ix = res->max_nch; 369 err_destroy_direct_rqts: 370 while (--ix >= 0) 371 mlx5e_rqt_destroy(&res->channels[ix].direct_rqt); 372 373 kvfree(res->channels); 374 375 out: 376 mlx5e_tir_builder_free(builder); 377 378 return err; 379 } 380 381 static int mlx5e_rx_res_ptp_init(struct mlx5e_rx_res *res) 382 { 383 bool inner_ft_support = res->features & MLX5E_RX_RES_FEATURE_INNER_FT; 384 struct mlx5e_tir_builder *builder; 385 int err; 386 387 builder = mlx5e_tir_builder_alloc(false); 388 if (!builder) 389 return -ENOMEM; 390 391 err = mlx5e_rqt_init_direct(&res->ptp.rqt, res->mdev, false, res->drop_rqn); 392 if (err) 393 goto out; 394 395 mlx5e_tir_builder_build_rqt(builder, res->mdev->mlx5e_res.hw_objs.td.tdn, 396 mlx5e_rqt_get_rqtn(&res->ptp.rqt), 397 inner_ft_support); 398 mlx5e_tir_builder_build_direct(builder); 399 400 err = mlx5e_tir_init(&res->ptp.tir, builder, res->mdev, true); 401 if (err) 402 goto err_destroy_ptp_rqt; 403 404 goto out; 405 406 err_destroy_ptp_rqt: 407 mlx5e_rqt_destroy(&res->ptp.rqt); 408 409 out: 410 mlx5e_tir_builder_free(builder); 411 return err; 412 } 413 414 static void mlx5e_rx_res_channels_destroy(struct mlx5e_rx_res *res) 415 { 416 unsigned int ix; 417 418 for (ix = 0; ix < res->max_nch; ix++) { 419 mlx5e_tir_destroy(&res->channels[ix].direct_tir); 420 mlx5e_rqt_destroy(&res->channels[ix].direct_rqt); 421 422 if (!(res->features & MLX5E_RX_RES_FEATURE_XSK)) 423 continue; 424 425 mlx5e_tir_destroy(&res->channels[ix].xsk_tir); 426 mlx5e_rqt_destroy(&res->channels[ix].xsk_rqt); 427 } 428 429 kvfree(res->channels); 430 } 431 432 static void mlx5e_rx_res_ptp_destroy(struct mlx5e_rx_res *res) 433 { 434 mlx5e_tir_destroy(&res->ptp.tir); 435 mlx5e_rqt_destroy(&res->ptp.rqt); 436 } 437 438 int mlx5e_rx_res_init(struct mlx5e_rx_res *res, struct mlx5_core_dev *mdev, 439 enum mlx5e_rx_res_features features, unsigned int max_nch, 440 u32 drop_rqn, const struct mlx5e_lro_param *init_lro_param, 441 unsigned int init_nch) 442 { 443 int err; 444 445 res->mdev = mdev; 446 res->features = features; 447 res->max_nch = max_nch; 448 res->drop_rqn = drop_rqn; 449 450 err = mlx5e_rx_res_rss_init_def(res, init_lro_param, init_nch); 451 if (err) 452 goto err_out; 453 454 err = mlx5e_rx_res_channels_init(res, init_lro_param); 455 if (err) 456 goto err_rss_destroy; 457 458 err = mlx5e_rx_res_ptp_init(res); 459 if (err) 460 goto err_channels_destroy; 461 462 return 0; 463 464 err_channels_destroy: 465 mlx5e_rx_res_channels_destroy(res); 466 err_rss_destroy: 467 __mlx5e_rx_res_rss_destroy(res, 0); 468 err_out: 469 return err; 470 } 471 472 void mlx5e_rx_res_destroy(struct mlx5e_rx_res *res) 473 { 474 mlx5e_rx_res_ptp_destroy(res); 475 mlx5e_rx_res_channels_destroy(res); 476 mlx5e_rx_res_rss_destroy_all(res); 477 } 478 479 void mlx5e_rx_res_free(struct mlx5e_rx_res *res) 480 { 481 kvfree(res); 482 } 483 484 u32 mlx5e_rx_res_get_tirn_direct(struct mlx5e_rx_res *res, unsigned int ix) 485 { 486 return mlx5e_tir_get_tirn(&res->channels[ix].direct_tir); 487 } 488 489 u32 mlx5e_rx_res_get_tirn_xsk(struct mlx5e_rx_res *res, unsigned int ix) 490 { 491 WARN_ON(!(res->features & MLX5E_RX_RES_FEATURE_XSK)); 492 493 return mlx5e_tir_get_tirn(&res->channels[ix].xsk_tir); 494 } 495 496 u32 mlx5e_rx_res_get_tirn_rss(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt) 497 { 498 struct mlx5e_rss *rss = res->rss[0]; 499 500 return mlx5e_rss_get_tirn(rss, tt, false); 501 } 502 503 u32 mlx5e_rx_res_get_tirn_rss_inner(struct mlx5e_rx_res *res, enum mlx5_traffic_types tt) 504 { 505 struct mlx5e_rss *rss = res->rss[0]; 506 507 return mlx5e_rss_get_tirn(rss, tt, true); 508 } 509 510 u32 mlx5e_rx_res_get_tirn_ptp(struct mlx5e_rx_res *res) 511 { 512 WARN_ON(!(res->features & MLX5E_RX_RES_FEATURE_PTP)); 513 return mlx5e_tir_get_tirn(&res->ptp.tir); 514 } 515 516 u32 mlx5e_rx_res_get_rqtn_direct(struct mlx5e_rx_res *res, unsigned int ix) 517 { 518 return mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt); 519 } 520 521 void mlx5e_rx_res_channels_activate(struct mlx5e_rx_res *res, struct mlx5e_channels *chs) 522 { 523 unsigned int nch, ix; 524 int err; 525 526 nch = mlx5e_channels_get_num(chs); 527 528 for (ix = 0; ix < chs->num; ix++) 529 mlx5e_channels_get_regular_rqn(chs, ix, &res->rss_rqns[ix]); 530 res->rss_nch = chs->num; 531 532 mlx5e_rx_res_rss_enable(res); 533 534 for (ix = 0; ix < nch; ix++) { 535 u32 rqn; 536 537 mlx5e_channels_get_regular_rqn(chs, ix, &rqn); 538 err = mlx5e_rqt_redirect_direct(&res->channels[ix].direct_rqt, rqn); 539 if (err) 540 mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to RQ %#x (channel %u): err = %d\n", 541 mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt), 542 rqn, ix, err); 543 544 if (!(res->features & MLX5E_RX_RES_FEATURE_XSK)) 545 continue; 546 547 if (!mlx5e_channels_get_xsk_rqn(chs, ix, &rqn)) 548 rqn = res->drop_rqn; 549 err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, rqn); 550 if (err) 551 mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to RQ %#x (channel %u): err = %d\n", 552 mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt), 553 rqn, ix, err); 554 } 555 for (ix = nch; ix < res->max_nch; ix++) { 556 err = mlx5e_rqt_redirect_direct(&res->channels[ix].direct_rqt, res->drop_rqn); 557 if (err) 558 mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to drop RQ %#x (channel %u): err = %d\n", 559 mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt), 560 res->drop_rqn, ix, err); 561 562 if (!(res->features & MLX5E_RX_RES_FEATURE_XSK)) 563 continue; 564 565 err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, res->drop_rqn); 566 if (err) 567 mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to drop RQ %#x (channel %u): err = %d\n", 568 mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt), 569 res->drop_rqn, ix, err); 570 } 571 572 if (res->features & MLX5E_RX_RES_FEATURE_PTP) { 573 u32 rqn; 574 575 if (!mlx5e_channels_get_ptp_rqn(chs, &rqn)) 576 rqn = res->drop_rqn; 577 578 err = mlx5e_rqt_redirect_direct(&res->ptp.rqt, rqn); 579 if (err) 580 mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to RQ %#x (PTP): err = %d\n", 581 mlx5e_rqt_get_rqtn(&res->ptp.rqt), 582 rqn, err); 583 } 584 } 585 586 void mlx5e_rx_res_channels_deactivate(struct mlx5e_rx_res *res) 587 { 588 unsigned int ix; 589 int err; 590 591 mlx5e_rx_res_rss_disable(res); 592 593 for (ix = 0; ix < res->max_nch; ix++) { 594 err = mlx5e_rqt_redirect_direct(&res->channels[ix].direct_rqt, res->drop_rqn); 595 if (err) 596 mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to drop RQ %#x (channel %u): err = %d\n", 597 mlx5e_rqt_get_rqtn(&res->channels[ix].direct_rqt), 598 res->drop_rqn, ix, err); 599 600 if (!(res->features & MLX5E_RX_RES_FEATURE_XSK)) 601 continue; 602 603 err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, res->drop_rqn); 604 if (err) 605 mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to drop RQ %#x (channel %u): err = %d\n", 606 mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt), 607 res->drop_rqn, ix, err); 608 } 609 610 if (res->features & MLX5E_RX_RES_FEATURE_PTP) { 611 err = mlx5e_rqt_redirect_direct(&res->ptp.rqt, res->drop_rqn); 612 if (err) 613 mlx5_core_warn(res->mdev, "Failed to redirect direct RQT %#x to drop RQ %#x (PTP): err = %d\n", 614 mlx5e_rqt_get_rqtn(&res->ptp.rqt), 615 res->drop_rqn, err); 616 } 617 } 618 619 int mlx5e_rx_res_xsk_activate(struct mlx5e_rx_res *res, struct mlx5e_channels *chs, 620 unsigned int ix) 621 { 622 u32 rqn; 623 int err; 624 625 if (!mlx5e_channels_get_xsk_rqn(chs, ix, &rqn)) 626 return -EINVAL; 627 628 err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, rqn); 629 if (err) 630 mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to XSK RQ %#x (channel %u): err = %d\n", 631 mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt), 632 rqn, ix, err); 633 return err; 634 } 635 636 int mlx5e_rx_res_xsk_deactivate(struct mlx5e_rx_res *res, unsigned int ix) 637 { 638 int err; 639 640 err = mlx5e_rqt_redirect_direct(&res->channels[ix].xsk_rqt, res->drop_rqn); 641 if (err) 642 mlx5_core_warn(res->mdev, "Failed to redirect XSK RQT %#x to drop RQ %#x (channel %u): err = %d\n", 643 mlx5e_rqt_get_rqtn(&res->channels[ix].xsk_rqt), 644 res->drop_rqn, ix, err); 645 return err; 646 } 647 648 int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param *lro_param) 649 { 650 struct mlx5e_tir_builder *builder; 651 int err, final_err; 652 unsigned int ix; 653 654 builder = mlx5e_tir_builder_alloc(true); 655 if (!builder) 656 return -ENOMEM; 657 658 mlx5e_tir_builder_build_lro(builder, lro_param); 659 660 final_err = 0; 661 662 for (ix = 0; ix < MLX5E_MAX_NUM_RSS; ix++) { 663 struct mlx5e_rss *rss = res->rss[ix]; 664 665 if (!rss) 666 continue; 667 668 err = mlx5e_rss_lro_set_param(rss, lro_param); 669 if (err) 670 final_err = final_err ? : err; 671 } 672 673 for (ix = 0; ix < res->max_nch; ix++) { 674 err = mlx5e_tir_modify(&res->channels[ix].direct_tir, builder); 675 if (err) { 676 mlx5_core_warn(res->mdev, "Failed to update LRO state of direct TIR %#x for channel %u: err = %d\n", 677 mlx5e_tir_get_tirn(&res->channels[ix].direct_tir), ix, err); 678 if (!final_err) 679 final_err = err; 680 } 681 } 682 683 mlx5e_tir_builder_free(builder); 684 return final_err; 685 } 686 687 struct mlx5e_rss_params_hash mlx5e_rx_res_get_current_hash(struct mlx5e_rx_res *res) 688 { 689 return mlx5e_rss_get_hash(res->rss[0]); 690 } 691