FILE
bnge_resc.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/broadcom/bnge/bnge_resc.c
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (c) 2025 Broadcom. 3 4#include <linux/init.h> 5#include <linux/module.h> 6#include <linux/pci.h> 7#include <linux/ethtool.h> 8#include <linux/netdevice.h> 9 10#include "bnge.h" 11#include "bnge_hwrm.h" 12#include "bnge_hwrm_lib.h" 13#include "bnge_resc.h" 14 15static u16 bnge_num_tx_to_cp(struct bnge_dev *bd, u16 tx) 16{ 17 u16 tcs = bd->num_tc; 18 19 if (!tcs) 20 tcs = 1; 21 22 return tx / tcs; 23} 24 25static u16 bnge_get_max_func_irqs(struct bnge_dev *bd) 26{ 27 struct bnge_hw_resc *hw_resc = &bd->hw_resc; 28 29 return min_t(u16, hw_resc->max_irqs, hw_resc->max_nqs); 30} 31 32static unsigned int bnge_get_max_func_stat_ctxs(struct bnge_dev *bd) 33{ 34 return bd->hw_resc.max_stat_ctxs; 35} 36 37bool bnge_aux_has_enough_resources(struct bnge_dev *bd) 38{ 39 unsigned int max_stat_ctxs; 40 41 max_stat_ctxs = bnge_get_max_func_stat_ctxs(bd); 42 if (max_stat_ctxs <= BNGE_MIN_ROCE_STAT_CTXS || 43 bd->nq_nr_rings == max_stat_ctxs) 44 return false; 45 46 return true; 47} 48 49static unsigned int bnge_get_max_func_cp_rings(struct bnge_dev *bd) 50{ 51 return bd->hw_resc.max_cp_rings; 52} 53 54static int bnge_aux_get_dflt_msix(struct bnge_dev *bd) 55{ 56 int roce_msix = BNGE_MAX_ROCE_MSIX; 57 58 return min_t(int, roce_msix, num_online_cpus() + 1); 59} 60 61u16 bnge_aux_get_msix(struct bnge_dev *bd) 62{ 63 if (bnge_is_roce_en(bd)) 64 return bd->aux_num_msix; 65 66 return 0; 67} 68 69static void bnge_aux_set_msix_num(struct bnge_dev *bd, u16 num) 70{ 71 if (bnge_is_roce_en(bd)) 72 bd->aux_num_msix = num; 73} 74 75static u16 bnge_aux_get_stat_ctxs(struct bnge_dev *bd) 76{ 77 if (bnge_is_roce_en(bd)) 78 return bd->aux_num_stat_ctxs; 79 80 return 0; 81} 82 83static void bnge_aux_set_stat_ctxs(struct bnge_dev *bd, u16 num_aux_ctx) 84{ 85 if (bnge_is_roce_en(bd)) 86 bd->aux_num_stat_ctxs = num_aux_ctx; 87} 88 89static u16 bnge_func_stat_ctxs_demand(struct bnge_dev *bd) 90{ 91 return bd->nq_nr_rings + bnge_aux_get_stat_ctxs(bd); 92} 93 94static int bnge_get_dflt_aux_stat_ctxs(struct bnge_dev *bd) 95{ 96 int stat_ctx = 0; 97 98 if (bnge_is_roce_en(bd)) { 99 stat_ctx = BNGE_MIN_ROCE_STAT_CTXS; 100 101 if (!bd->pf.port_id && bd->port_count > 1) 102 stat_ctx++; 103 } 104 105 return stat_ctx; 106} 107 108static u16 bnge_nqs_demand(struct bnge_dev *bd) 109{ 110 return bd->nq_nr_rings + bnge_aux_get_msix(bd); 111} 112 113static u16 bnge_cprs_demand(struct bnge_dev *bd) 114{ 115 return bd->tx_nr_rings + bd->rx_nr_rings; 116} 117 118static u16 bnge_get_avail_msix(struct bnge_dev *bd, int num) 119{ 120 u16 max_irq = bnge_get_max_func_irqs(bd); 121 u16 total_demand = bd->nq_nr_rings + num; 122 123 if (max_irq < total_demand) { 124 num = max_irq - bd->nq_nr_rings; 125 if (num <= 0) 126 return 0; 127 } 128 129 return num; 130} 131 132static u16 bnge_num_cp_to_tx(struct bnge_dev *bd, u16 tx_chunks) 133{ 134 return tx_chunks * bd->num_tc; 135} 136 137int bnge_fix_rings_count(u16 *rx, u16 *tx, u16 max, bool shared) 138{ 139 u16 _rx = *rx, _tx = *tx; 140 141 if (shared) { 142 *rx = min_t(u16, _rx, max); 143 *tx = min_t(u16, _tx, max); 144 } else { 145 if (max < 2) 146 return -ENOMEM; 147 while (_rx + _tx > max) { 148 if (_rx > _tx && _rx > 1) 149 _rx--; 150 else if (_tx > 1) 151 _tx--; 152 } 153 *rx = _rx; 154 *tx = _tx; 155 } 156 157 return 0; 158} 159 160static int bnge_adjust_rings(struct bnge_dev *bd, u16 *rx, 161 u16 *tx, u16 max_nq, bool sh) 162{ 163 u16 tx_chunks = bnge_num_tx_to_cp(bd, *tx); 164 165 if (tx_chunks != *tx) { 166 u16 tx_saved = tx_chunks, rc; 167 168 rc = bnge_fix_rings_count(rx, &tx_chunks, max_nq, sh); 169 if (rc) 170 return rc; 171 if (tx_chunks != tx_saved) 172 *tx = bnge_num_cp_to_tx(bd, tx_chunks); 173 return 0; 174 } 175 176 return bnge_fix_rings_count(rx, tx, max_nq, sh); 177} 178 179int bnge_cal_nr_rss_ctxs(u16 rx_rings) 180{ 181 if (!rx_rings) 182 return 0; 183 184 return bnge_adjust_pow_two(rx_rings - 1, 185 BNGE_RSS_TABLE_ENTRIES); 186} 187 188static u16 bnge_rss_ctxs_in_use(struct bnge_dev *bd, 189 struct bnge_hw_rings *hwr) 190{ 191 return bnge_cal_nr_rss_ctxs(hwr->grp); 192} 193 194static u16 bnge_get_total_vnics(struct bnge_dev *bd, u16 rx_rings) 195{ 196 return 1; 197} 198 199u32 bnge_get_rxfh_indir_size(struct bnge_dev *bd) 200{ 201 return bnge_cal_nr_rss_ctxs(bd->rx_nr_rings) * 202 BNGE_RSS_TABLE_ENTRIES; 203} 204 205static void bnge_set_dflt_rss_indir_tbl(struct bnge_dev *bd) 206{ 207 u16 max_entries, pad; 208 u32 *rss_indir_tbl; 209 int i; 210 211 max_entries = bnge_get_rxfh_indir_size(bd); 212 rss_indir_tbl = &bd->rss_indir_tbl[0]; 213 214 for (i = 0; i < max_entries; i++) 215 rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, 216 bd->rx_nr_rings); 217 218 pad = bd->rss_indir_tbl_entries - max_entries; 219 if (pad) 220 memset(&rss_indir_tbl[i], 0, pad * sizeof(*rss_indir_tbl)); 221} 222 223static void bnge_copy_reserved_rings(struct bnge_dev *bd, 224 struct bnge_hw_rings *hwr) 225{ 226 struct bnge_hw_resc *hw_resc = &bd->hw_resc; 227 228 hwr->tx = hw_resc->resv_tx_rings; 229 hwr->rx = hw_resc->resv_rx_rings; 230 hwr->nq = hw_resc->resv_irqs; 231 hwr->cmpl = hw_resc->resv_cp_rings; 232 hwr->grp = hw_resc->resv_hw_ring_grps; 233 hwr->vnic = hw_resc->resv_vnics; 234 hwr->stat = hw_resc->resv_stat_ctxs; 235 hwr->rss_ctx = hw_resc->resv_rsscos_ctxs; 236} 237 238static bool bnge_rings_ok(struct bnge_hw_rings *hwr) 239{ 240 return hwr->tx && hwr->rx && hwr->nq && hwr->grp && hwr->vnic && 241 hwr->stat && hwr->cmpl; 242} 243 244static bool bnge_need_reserve_rings(struct bnge_dev *bd) 245{ 246 struct bnge_hw_resc *hw_resc = &bd->hw_resc; 247 u16 cprs = bnge_cprs_demand(bd); 248 u16 rx = bd->rx_nr_rings, stat; 249 u16 nqs = bnge_nqs_demand(bd); 250 u16 vnic; 251 252 if (hw_resc->resv_tx_rings != bd->tx_nr_rings) 253 return true; 254 255 vnic = bnge_get_total_vnics(bd, rx); 256 257 if (bnge_is_agg_reqd(bd)) 258 rx <<= 1; 259 stat = bnge_func_stat_ctxs_demand(bd); 260 if (hw_resc->resv_rx_rings != rx || hw_resc->resv_cp_rings != cprs || 261 hw_resc->resv_vnics != vnic || hw_resc->resv_stat_ctxs != stat) 262 return true; 263 if (hw_resc->resv_irqs != nqs) 264 return true; 265 266 return false; 267} 268 269int bnge_reserve_rings(struct bnge_dev *bd) 270{ 271 u16 aux_dflt_msix = bnge_aux_get_dflt_msix(bd); 272 struct bnge_hw_rings hwr = {0}; 273 u16 rx_rings, old_rx_rings; 274 u16 nq = bd->nq_nr_rings; 275 u16 aux_msix = 0; 276 bool sh = false; 277 u16 tx_cp; 278 int rc; 279 280 if (!bnge_need_reserve_rings(bd)) 281 return 0; 282 283 if (!bnge_aux_registered(bd)) { 284 aux_msix = bnge_get_avail_msix(bd, aux_dflt_msix); 285 if (!aux_msix) 286 bnge_aux_set_stat_ctxs(bd, 0); 287 288 if (aux_msix > aux_dflt_msix) 289 aux_msix = aux_dflt_msix; 290 hwr.nq = nq + aux_msix; 291 } else { 292 hwr.nq = bnge_nqs_demand(bd); 293 } 294 295 hwr.tx = bd->tx_nr_rings; 296 hwr.rx = bd->rx_nr_rings; 297 if (bd->flags & BNGE_EN_SHARED_CHNL) 298 sh = true; 299 hwr.cmpl = hwr.rx + hwr.tx; 300 301 hwr.vnic = bnge_get_total_vnics(bd, hwr.rx); 302 303 if (bnge_is_agg_reqd(bd)) 304 hwr.rx <<= 1; 305 hwr.grp = bd->rx_nr_rings; 306 hwr.rss_ctx = bnge_rss_ctxs_in_use(bd, &hwr); 307 hwr.stat = bnge_func_stat_ctxs_demand(bd); 308 old_rx_rings = bd->hw_resc.resv_rx_rings; 309 310 rc = bnge_hwrm_reserve_rings(bd, &hwr); 311 if (rc) 312 return rc; 313 314 bnge_copy_reserved_rings(bd, &hwr); 315 316 rx_rings = hwr.rx; 317 if (bnge_is_agg_reqd(bd)) { 318 if (hwr.rx >= 2) 319 rx_rings = hwr.rx >> 1; 320 else 321 return -ENOMEM; 322 } 323 324 rx_rings = min_t(u16, rx_rings, hwr.grp); 325 hwr.nq = min_t(u16, hwr.nq, bd->nq_nr_rings); 326 if (hwr.stat > bnge_aux_get_stat_ctxs(bd)) 327 hwr.stat -= bnge_aux_get_stat_ctxs(bd); 328 hwr.nq = min_t(u16, hwr.nq, hwr.stat); 329 330 /* Adjust the rings */ 331 rc = bnge_adjust_rings(bd, &rx_rings, &hwr.tx, hwr.nq, sh); 332 if (bnge_is_agg_reqd(bd)) 333 hwr.rx = rx_rings << 1; 334 tx_cp = hwr.tx; 335 hwr.nq = sh ? max_t(u16, tx_cp, rx_rings) : tx_cp + rx_rings; 336 bd->tx_nr_rings = hwr.tx; 337 338 if (rx_rings != bd->rx_nr_rings) 339 dev_warn(bd->dev, "RX rings resv reduced to %d than earlier %d requested\n", 340 rx_rings, bd->rx_nr_rings); 341 342 bd->rx_nr_rings = rx_rings; 343 bd->nq_nr_rings = hwr.nq; 344 345 if (!bnge_rings_ok(&hwr)) 346 return -ENOMEM; 347 348 if (old_rx_rings != bd->hw_resc.resv_rx_rings) 349 bnge_set_dflt_rss_indir_tbl(bd); 350 351 if (!bnge_aux_registered(bd)) { 352 u16 resv_msix, resv_ctx, aux_ctxs; 353 struct bnge_hw_resc *hw_resc; 354 355 hw_resc = &bd->hw_resc; 356 resv_msix = hw_resc->resv_irqs - bd->nq_nr_rings; 357 aux_msix = min_t(u16, resv_msix, aux_msix); 358 bnge_aux_set_msix_num(bd, aux_msix); 359 resv_ctx = hw_resc->resv_stat_ctxs - bd->nq_nr_rings; 360 aux_ctxs = min(resv_ctx, bnge_aux_get_stat_ctxs(bd)); 361 bnge_aux_set_stat_ctxs(bd, aux_ctxs); 362 } 363 364 return rc; 365} 366 367int bnge_alloc_irqs(struct bnge_dev *bd) 368{ 369 u16 aux_msix, tx_cp, num_entries; 370 int i, irqs_demand, rc; 371 u16 max, min = 1; 372 373 irqs_demand = bnge_nqs_demand(bd); 374 max = bnge_get_max_func_irqs(bd); 375 if (irqs_demand > max) 376 irqs_demand = max; 377 378 if (!(bd->flags & BNGE_EN_SHARED_CHNL)) 379 min = 2; 380 381 irqs_demand = pci_alloc_irq_vectors(bd->pdev, min, irqs_demand, 382 PCI_IRQ_MSIX); 383 aux_msix = bnge_aux_get_msix(bd); 384 if (irqs_demand < 0 || irqs_demand < aux_msix) { 385 rc = -ENODEV; 386 goto err_free_irqs; 387 } 388 389 num_entries = irqs_demand; 390 if (pci_msix_can_alloc_dyn(bd->pdev)) 391 num_entries = max; 392 bd->irq_tbl = kcalloc(num_entries, sizeof(*bd->irq_tbl), GFP_KERNEL); 393 if (!bd->irq_tbl) { 394 rc = -ENOMEM; 395 goto err_free_irqs; 396 } 397 398 for (i = 0; i < irqs_demand; i++) 399 bd->irq_tbl[i].vector = pci_irq_vector(bd->pdev, i); 400 401 bd->irqs_acquired = irqs_demand; 402 /* Reduce rings based upon num of vectors allocated. 403 * We dont need to consider NQs as they have been calculated 404 * and must be more than irqs_demand. 405 */ 406 rc = bnge_adjust_rings(bd, &bd->rx_nr_rings, 407 &bd->tx_nr_rings, 408 irqs_demand - aux_msix, min == 1); 409 if (rc) 410 goto err_free_irqs; 411 412 tx_cp = bnge_num_tx_to_cp(bd, bd->tx_nr_rings); 413 bd->nq_nr_rings = (min == 1) ? 414 max_t(u16, tx_cp, bd->rx_nr_rings) : 415 tx_cp + bd->rx_nr_rings; 416 417 /* Readjust tx_nr_rings_per_tc */ 418 if (!bd->num_tc) 419 bd->tx_nr_rings_per_tc = bd->tx_nr_rings; 420 421 return 0; 422 423err_free_irqs: 424 dev_err(bd->dev, "Failed to allocate IRQs err = %d\n", rc); 425 bnge_free_irqs(bd); 426 return rc; 427} 428 429void bnge_free_irqs(struct bnge_dev *bd) 430{ 431 pci_free_irq_vectors(bd->pdev); 432 kfree(bd->irq_tbl); 433 bd->irq_tbl = NULL; 434} 435 436static void _bnge_get_max_rings(struct bnge_dev *bd, u16 *max_rx, 437 u16 *max_tx, u16 *max_nq) 438{ 439 struct bnge_hw_resc *hw_resc = &bd->hw_resc; 440 u16 max_ring_grps = 0, max_cp; 441 int rc; 442 443 *max_tx = hw_resc->max_tx_rings; 444 *max_rx = hw_resc->max_rx_rings; 445 *max_nq = min_t(int, bnge_get_max_func_irqs(bd), 446 hw_resc->max_stat_ctxs); 447 max_ring_grps = hw_resc->max_hw_ring_grps; 448 if (bnge_is_agg_reqd(bd)) 449 *max_rx >>= 1; 450 451 max_cp = bnge_get_max_func_cp_rings(bd); 452 453 /* Fix RX and TX rings according to number of CPs available */ 454 rc = bnge_fix_rings_count(max_rx, max_tx, max_cp, false); 455 if (rc) { 456 *max_rx = 0; 457 *max_tx = 0; 458 } 459 460 *max_rx = min_t(int, *max_rx, max_ring_grps); 461} 462 463static int bnge_get_max_rings(struct bnge_dev *bd, u16 *max_rx, 464 u16 *max_tx, bool shared) 465{ 466 u16 rx, tx, nq; 467 468 _bnge_get_max_rings(bd, &rx, &tx, &nq); 469 *max_rx = rx; 470 *max_tx = tx; 471 if (!rx || !tx || !nq) 472 return -ENOMEM; 473 474 return bnge_fix_rings_count(max_rx, max_tx, nq, shared); 475} 476 477static int bnge_get_dflt_rings(struct bnge_dev *bd, u16 *max_rx, u16 *max_tx, 478 bool shared) 479{ 480 int rc; 481 482 rc = bnge_get_max_rings(bd, max_rx, max_tx, shared); 483 if (rc) { 484 dev_info(bd->dev, "Not enough rings available\n"); 485 return rc; 486 } 487 488 if (bnge_is_roce_en(bd)) { 489 int max_cp, max_stat, max_irq; 490 491 /* Reserve minimum resources for RoCE */ 492 max_cp = bnge_get_max_func_cp_rings(bd); 493 max_stat = bnge_get_max_func_stat_ctxs(bd); 494 max_irq = bnge_get_max_func_irqs(bd); 495 if (max_cp <= BNGE_MIN_ROCE_CP_RINGS || 496 max_irq <= BNGE_MIN_ROCE_CP_RINGS || 497 max_stat <= BNGE_MIN_ROCE_STAT_CTXS) 498 return 0; 499 500 max_cp -= BNGE_MIN_ROCE_CP_RINGS; 501 max_irq -= BNGE_MIN_ROCE_CP_RINGS; 502 max_stat -= BNGE_MIN_ROCE_STAT_CTXS; 503 max_cp = min_t(u16, max_cp, max_irq); 504 max_cp = min_t(u16, max_cp, max_stat); 505 rc = bnge_adjust_rings(bd, max_rx, max_tx, max_cp, shared); 506 if (rc) 507 rc = 0; 508 } 509 510 return rc; 511} 512 513/* In initial default shared ring setting, each shared ring must have a 514 * RX/TX ring pair. 515 */ 516static void bnge_trim_dflt_sh_rings(struct bnge_dev *bd) 517{ 518 bd->nq_nr_rings = min_t(u16, bd->tx_nr_rings_per_tc, bd->rx_nr_rings); 519 bd->rx_nr_rings = bd->nq_nr_rings; 520 bd->tx_nr_rings_per_tc = bd->nq_nr_rings; 521 bd->tx_nr_rings = bd->tx_nr_rings_per_tc; 522} 523 524static int bnge_net_init_dflt_rings(struct bnge_dev *bd, bool sh) 525{ 526 u16 dflt_rings, max_rx_rings, max_tx_rings; 527 int rc; 528 529 if (sh) 530 bd->flags |= BNGE_EN_SHARED_CHNL; 531 532 dflt_rings = netif_get_num_default_rss_queues(); 533 534 rc = bnge_get_dflt_rings(bd, &max_rx_rings, &max_tx_rings, sh); 535 if (rc) 536 return rc; 537 bd->rx_nr_rings = min_t(u16, dflt_rings, max_rx_rings); 538 bd->tx_nr_rings_per_tc = min_t(u16, dflt_rings, max_tx_rings); 539 if (sh) 540 bnge_trim_dflt_sh_rings(bd); 541 else 542 bd->nq_nr_rings = bd->tx_nr_rings_per_tc + bd->rx_nr_rings; 543 bd->tx_nr_rings = bd->tx_nr_rings_per_tc; 544 545 rc = bnge_reserve_rings(bd); 546 if (rc && rc != -ENODEV) 547 dev_warn(bd->dev, "Unable to reserve tx rings\n"); 548 bd->tx_nr_rings_per_tc = bd->tx_nr_rings; 549 if (sh) 550 bnge_trim_dflt_sh_rings(bd); 551 552 /* Rings may have been reduced, re-reserve them again */ 553 if (bnge_need_reserve_rings(bd)) { 554 rc = bnge_reserve_rings(bd); 555 if (rc && rc != -ENODEV) 556 dev_warn(bd->dev, "Fewer rings reservation failed\n"); 557 bd->tx_nr_rings_per_tc = bd->tx_nr_rings; 558 } 559 if (rc) { 560 bd->tx_nr_rings = 0; 561 bd->rx_nr_rings = 0; 562 } 563 564 return rc; 565} 566 567static int bnge_alloc_rss_indir_tbl(struct bnge_dev *bd) 568{ 569 u16 entries; 570 571 entries = BNGE_MAX_RSS_TABLE_ENTRIES; 572 573 bd->rss_indir_tbl_entries = entries; 574 bd->rss_indir_tbl = 575 kmalloc_array(entries, sizeof(*bd->rss_indir_tbl), GFP_KERNEL); 576 if (!bd->rss_indir_tbl) 577 return -ENOMEM; 578 579 return 0; 580} 581 582int bnge_net_init_dflt_config(struct bnge_dev *bd) 583{ 584 struct bnge_hw_resc *hw_resc; 585 int rc; 586 587 rc = bnge_alloc_rss_indir_tbl(bd); 588 if (rc) 589 return rc; 590 591 rc = bnge_net_init_dflt_rings(bd, true); 592 if (rc) 593 goto err_free_tbl; 594 595 hw_resc = &bd->hw_resc; 596 bd->max_fltr = hw_resc->max_rx_em_flows + hw_resc->max_rx_wm_flows + 597 BNGE_L2_FLTR_MAX_FLTR; 598 599 return 0; 600 601err_free_tbl: 602 kfree(bd->rss_indir_tbl); 603 bd->rss_indir_tbl = NULL; 604 return rc; 605} 606 607void bnge_net_uninit_dflt_config(struct bnge_dev *bd) 608{ 609 kfree(bd->rss_indir_tbl); 610 bd->rss_indir_tbl = NULL; 611} 612 613void bnge_aux_init_dflt_config(struct bnge_dev *bd) 614{ 615 bd->aux_num_msix = bnge_aux_get_dflt_msix(bd); 616 bd->aux_num_stat_ctxs = bnge_get_dflt_aux_stat_ctxs(bd); 617}
~/
Read-only file preview.