]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bng_en: Initialize default configuration
authorVikas Gupta <vikas.gupta@broadcom.com>
Tue, 1 Jul 2025 14:35:07 +0000 (14:35 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 8 Jul 2025 01:54:01 +0000 (18:54 -0700)
Query resources from the firmware and, based on the
availability of resources, initialize the default
settings. The default settings include:
1. Rings and other resource reservations with the
firmware. This ensures that resources are reserved
before network and auxiliary devices are created.
2. Mapping the BAR, which helps access doorbells since
its size is known after querying the firmware.
3. Retrieving the TCs and hardware CoS queue mappings.

Signed-off-by: Vikas Gupta <vikas.gupta@broadcom.com>
Reviewed-by: Bhargava Chenna Marreddy <bhargava.marreddy@broadcom.com>
Reviewed-by: Rajashekar Hudumula <rajashekar.hudumula@broadcom.com>
Link: https://patch.msgid.link/20250701143511.280702-10-vikas.gupta@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/broadcom/bnge/bnge.h
drivers/net/ethernet/broadcom/bnge/bnge_core.c
drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c
drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h
drivers/net/ethernet/broadcom/bnge/bnge_resc.c
drivers/net/ethernet/broadcom/bnge/bnge_resc.h

index 3c161b1a9b62ccca4e88c4e1b38385d6e7f3cb0c..cef66c1e90065a1e8dfc24aaf777e53e653917e1 100644 (file)
@@ -80,6 +80,12 @@ enum {
        BNGE_RSS_CAP_ESP_V6_RSS_CAP                     = BIT(7),
 };
 
+#define BNGE_MAX_QUEUE         8
+struct bnge_queue_info {
+       u8      queue_id;
+       u8      queue_profile;
+};
+
 struct bnge_dev {
        struct device   *dev;
        struct pci_dev  *pdev;
@@ -89,6 +95,7 @@ struct bnge_dev {
        char            board_serialno[BNGE_VPD_FLD_LEN];
 
        void __iomem    *bar0;
+       void __iomem    *bar1;
 
        u16             chip_num;
        u8              chip_rev;
@@ -172,6 +179,13 @@ struct bnge_dev {
 #define BNGE_SUPPORTS_TPA(bd)  ((bd)->max_tpa_v2)
 
        u8                      num_tc;
+       u8                      max_tc;
+       u8                      max_lltc;       /* lossless TCs */
+       struct bnge_queue_info  q_info[BNGE_MAX_QUEUE];
+       u8                      tc_to_qidx[BNGE_MAX_QUEUE];
+       u8                      q_ids[BNGE_MAX_QUEUE];
+       u8                      max_q;
+       u8                      port_count;
 
        struct bnge_irq         *irq_tbl;
        u16                     irqs_acquired;
index f5c3e8a061e50d6ddb2077c1c56e8f38037ae21d..24babc8b9d35ad9a3b9b3e0b7bfdc44c12b48153 100644 (file)
@@ -54,9 +54,46 @@ static void bnge_nvm_cfg_ver_get(struct bnge_dev *bd)
                         nvm_info.nvm_cfg_ver_upd);
 }
 
+static int bnge_func_qcaps(struct bnge_dev *bd)
+{
+       int rc;
+
+       rc = bnge_hwrm_func_qcaps(bd);
+       if (rc)
+               return rc;
+
+       rc = bnge_hwrm_queue_qportcfg(bd);
+       if (rc) {
+               dev_err(bd->dev, "query qportcfg failure rc: %d\n", rc);
+               return rc;
+       }
+
+       rc = bnge_hwrm_func_resc_qcaps(bd);
+       if (rc) {
+               dev_err(bd->dev, "query resc caps failure rc: %d\n", rc);
+               return rc;
+       }
+
+       rc = bnge_hwrm_func_qcfg(bd);
+       if (rc) {
+               dev_err(bd->dev, "query config failure rc: %d\n", rc);
+               return rc;
+       }
+
+       rc = bnge_hwrm_vnic_qcaps(bd);
+       if (rc) {
+               dev_err(bd->dev, "vnic caps failure rc: %d\n", rc);
+               return rc;
+       }
+
+       return 0;
+}
+
 static void bnge_fw_unregister_dev(struct bnge_dev *bd)
 {
+       /* ctx mem free after unrgtr only */
        bnge_hwrm_func_drv_unrgtr(bd);
+       bnge_free_ctx_mem(bd);
 }
 
 static int bnge_fw_register_dev(struct bnge_dev *bd)
@@ -86,7 +123,25 @@ static int bnge_fw_register_dev(struct bnge_dev *bd)
                return rc;
        }
 
+       rc = bnge_alloc_ctx_mem(bd);
+       if (rc) {
+               dev_err(bd->dev, "Failed to allocate ctx mem rc: %d\n", rc);
+               goto err_func_unrgtr;
+       }
+
+       /* Get the resources and configuration from firmware */
+       rc = bnge_func_qcaps(bd);
+       if (rc) {
+               dev_err(bd->dev, "Failed initial configuration rc: %d\n", rc);
+               rc = -ENODEV;
+               goto err_func_unrgtr;
+       }
+
        return 0;
+
+err_func_unrgtr:
+       bnge_fw_unregister_dev(bd);
+       return rc;
 }
 
 static void bnge_pci_disable(struct pci_dev *pdev)
@@ -134,14 +189,46 @@ static void bnge_unmap_bars(struct pci_dev *pdev)
 {
        struct bnge_dev *bd = pci_get_drvdata(pdev);
 
+       if (bd->bar1) {
+               pci_iounmap(pdev, bd->bar1);
+               bd->bar1 = NULL;
+       }
+
        if (bd->bar0) {
                pci_iounmap(pdev, bd->bar0);
                bd->bar0 = NULL;
        }
 }
 
+static void bnge_set_max_func_irqs(struct bnge_dev *bd,
+                                  unsigned int max_irqs)
+{
+       bd->hw_resc.max_irqs = max_irqs;
+}
+
+static int bnge_get_max_irq(struct pci_dev *pdev)
+{
+       u16 ctrl;
+
+       pci_read_config_word(pdev, pdev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
+       return (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
+}
+
+static int bnge_map_db_bar(struct bnge_dev *bd)
+{
+       if (!bd->db_size)
+               return -ENODEV;
+
+       bd->bar1 = pci_iomap(bd->pdev, 2, bd->db_size);
+       if (!bd->bar1)
+               return -ENOMEM;
+
+       return 0;
+}
+
 static int bnge_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       unsigned int max_irqs;
        struct bnge_dev *bd;
        int rc;
 
@@ -190,10 +277,42 @@ static int bnge_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        bnge_devlink_register(bd);
 
+       max_irqs = bnge_get_max_irq(pdev);
+       bnge_set_max_func_irqs(bd, max_irqs);
+
+       bnge_aux_init_dflt_config(bd);
+
+       rc = bnge_net_init_dflt_config(bd);
+       if (rc) {
+               dev_err(&pdev->dev, "Error setting up default cfg to netdev rc = %d\n",
+                       rc);
+               goto err_fw_reg;
+       }
+
+       rc = bnge_map_db_bar(bd);
+       if (rc) {
+               dev_err(&pdev->dev, "Failed mapping doorbell BAR rc = %d, aborting\n",
+                       rc);
+               goto err_config_uninit;
+       }
+
+       rc = bnge_alloc_irqs(bd);
+       if (rc) {
+               dev_err(&pdev->dev, "Error IRQ allocation rc = %d\n", rc);
+               goto err_config_uninit;
+       }
+
        pci_save_state(pdev);
 
        return 0;
 
+err_config_uninit:
+       bnge_net_uninit_dflt_config(bd);
+
+err_fw_reg:
+       bnge_devlink_unregister(bd);
+       bnge_fw_unregister_dev(bd);
+
 err_hwrm_cleanup:
        bnge_cleanup_hwrm_resources(bd);
 
@@ -212,6 +331,10 @@ static void bnge_remove_one(struct pci_dev *pdev)
 {
        struct bnge_dev *bd = pci_get_drvdata(pdev);
 
+       bnge_free_irqs(bd);
+
+       bnge_net_uninit_dflt_config(bd);
+
        bnge_devlink_unregister(bd);
 
        bnge_fw_unregister_dev(bd);
index ee2675776c143e6bf759d8938cc52976caf5358d..19091318cfddea5bdc6c524360ca03adbdceb1c0 100644 (file)
@@ -647,3 +647,57 @@ int bnge_hwrm_vnic_qcaps(struct bnge_dev *bd)
 
        return rc;
 }
+
+#define BNGE_CNPQ(q_profile)   \
+               ((q_profile) == \
+                QUEUE_QPORTCFG_RESP_QUEUE_ID0_SERVICE_PROFILE_LOSSY_ROCE_CNP)
+
+int bnge_hwrm_queue_qportcfg(struct bnge_dev *bd)
+{
+       struct hwrm_queue_qportcfg_output *resp;
+       struct hwrm_queue_qportcfg_input *req;
+       u8 i, j, *qptr;
+       bool no_rdma;
+       int rc;
+
+       rc = bnge_hwrm_req_init(bd, req, HWRM_QUEUE_QPORTCFG);
+       if (rc)
+               return rc;
+
+       resp = bnge_hwrm_req_hold(bd, req);
+       rc = bnge_hwrm_req_send(bd, req);
+       if (rc)
+               goto qportcfg_exit;
+
+       if (!resp->max_configurable_queues) {
+               rc = -EINVAL;
+               goto qportcfg_exit;
+       }
+       bd->max_tc = resp->max_configurable_queues;
+       bd->max_lltc = resp->max_configurable_lossless_queues;
+       if (bd->max_tc > BNGE_MAX_QUEUE)
+               bd->max_tc = BNGE_MAX_QUEUE;
+
+       no_rdma = !bnge_is_roce_en(bd);
+       qptr = &resp->queue_id0;
+       for (i = 0, j = 0; i < bd->max_tc; i++) {
+               bd->q_info[j].queue_id = *qptr;
+               bd->q_ids[i] = *qptr++;
+               bd->q_info[j].queue_profile = *qptr++;
+               bd->tc_to_qidx[j] = j;
+               if (!BNGE_CNPQ(bd->q_info[j].queue_profile) || no_rdma)
+                       j++;
+       }
+       bd->max_q = bd->max_tc;
+       bd->max_tc = max_t(u8, j, 1);
+
+       if (resp->queue_cfg_info & QUEUE_QPORTCFG_RESP_QUEUE_CFG_INFO_ASYM_CFG)
+               bd->max_tc = 1;
+
+       if (bd->max_lltc > bd->max_tc)
+               bd->max_lltc = bd->max_tc;
+
+qportcfg_exit:
+       bnge_hwrm_req_drop(bd, req);
+       return rc;
+}
index 59ec1899879a184d4a35413b8fa69b3a48f2c371..6c03923eb5592145ebe8786a0586b6f843f7700c 100644 (file)
@@ -22,5 +22,6 @@ int bnge_hwrm_func_qcaps(struct bnge_dev *bd);
 int bnge_hwrm_vnic_qcaps(struct bnge_dev *bd);
 int bnge_hwrm_func_qcfg(struct bnge_dev *bd);
 int bnge_hwrm_func_resc_qcaps(struct bnge_dev *bd);
+int bnge_hwrm_queue_qportcfg(struct bnge_dev *bd);
 
 #endif /* _BNGE_HWRM_LIB_H_ */
index 0e67a00016779785e8715d3ca6c4902ff12b0225..c79a3607a1b745eb0411398ddac3e4e8b5e6d45a 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/ethtool.h>
+#include <linux/netdevice.h>
 
 #include "bnge.h"
 #include "bnge_hwrm.h"
@@ -28,6 +29,16 @@ static u16 bnge_get_max_func_irqs(struct bnge_dev *bd)
        return min_t(u16, hw_resc->max_irqs, hw_resc->max_nqs);
 }
 
+static unsigned int bnge_get_max_func_stat_ctxs(struct bnge_dev *bd)
+{
+       return bd->hw_resc.max_stat_ctxs;
+}
+
+static unsigned int bnge_get_max_func_cp_rings(struct bnge_dev *bd)
+{
+       return bd->hw_resc.max_cp_rings;
+}
+
 static int bnge_aux_get_dflt_msix(struct bnge_dev *bd)
 {
        int roce_msix = BNGE_MAX_ROCE_MSIX;
@@ -68,6 +79,20 @@ static u16 bnge_func_stat_ctxs_demand(struct bnge_dev *bd)
        return bd->nq_nr_rings + bnge_aux_get_stat_ctxs(bd);
 }
 
+static int bnge_get_dflt_aux_stat_ctxs(struct bnge_dev *bd)
+{
+       int stat_ctx = 0;
+
+       if (bnge_is_roce_en(bd)) {
+               stat_ctx = BNGE_MIN_ROCE_STAT_CTXS;
+
+               if (!bd->pf.port_id && bd->port_count > 1)
+                       stat_ctx++;
+       }
+
+       return stat_ctx;
+}
+
 static u16 bnge_nqs_demand(struct bnge_dev *bd)
 {
        return bd->nq_nr_rings + bnge_aux_get_msix(bd);
@@ -395,3 +420,186 @@ void bnge_free_irqs(struct bnge_dev *bd)
        kfree(bd->irq_tbl);
        bd->irq_tbl = NULL;
 }
+
+static void _bnge_get_max_rings(struct bnge_dev *bd, u16 *max_rx,
+                               u16 *max_tx, u16 *max_nq)
+{
+       struct bnge_hw_resc *hw_resc = &bd->hw_resc;
+       u16 max_ring_grps = 0, max_cp;
+       int rc;
+
+       *max_tx = hw_resc->max_tx_rings;
+       *max_rx = hw_resc->max_rx_rings;
+       *max_nq = min_t(int, bnge_get_max_func_irqs(bd),
+                       hw_resc->max_stat_ctxs);
+       max_ring_grps = hw_resc->max_hw_ring_grps;
+       if (bnge_is_agg_reqd(bd))
+               *max_rx >>= 1;
+
+       max_cp = bnge_get_max_func_cp_rings(bd);
+
+       /* Fix RX and TX rings according to number of CPs available */
+       rc = bnge_fix_rings_count(max_rx, max_tx, max_cp, false);
+       if (rc) {
+               *max_rx = 0;
+               *max_tx = 0;
+       }
+
+       *max_rx = min_t(int, *max_rx, max_ring_grps);
+}
+
+static int bnge_get_max_rings(struct bnge_dev *bd, u16 *max_rx,
+                             u16 *max_tx, bool shared)
+{
+       u16 rx, tx, nq;
+
+       _bnge_get_max_rings(bd, &rx, &tx, &nq);
+       *max_rx = rx;
+       *max_tx = tx;
+       if (!rx || !tx || !nq)
+               return -ENOMEM;
+
+       return bnge_fix_rings_count(max_rx, max_tx, nq, shared);
+}
+
+static int bnge_get_dflt_rings(struct bnge_dev *bd, u16 *max_rx, u16 *max_tx,
+                              bool shared)
+{
+       int rc;
+
+       rc = bnge_get_max_rings(bd, max_rx, max_tx, shared);
+       if (rc) {
+               dev_info(bd->dev, "Not enough rings available\n");
+               return rc;
+       }
+
+       if (bnge_is_roce_en(bd)) {
+               int max_cp, max_stat, max_irq;
+
+               /* Reserve minimum resources for RoCE */
+               max_cp = bnge_get_max_func_cp_rings(bd);
+               max_stat = bnge_get_max_func_stat_ctxs(bd);
+               max_irq = bnge_get_max_func_irqs(bd);
+               if (max_cp <= BNGE_MIN_ROCE_CP_RINGS ||
+                   max_irq <= BNGE_MIN_ROCE_CP_RINGS ||
+                   max_stat <= BNGE_MIN_ROCE_STAT_CTXS)
+                       return 0;
+
+               max_cp -= BNGE_MIN_ROCE_CP_RINGS;
+               max_irq -= BNGE_MIN_ROCE_CP_RINGS;
+               max_stat -= BNGE_MIN_ROCE_STAT_CTXS;
+               max_cp = min_t(u16, max_cp, max_irq);
+               max_cp = min_t(u16, max_cp, max_stat);
+               rc = bnge_adjust_rings(bd, max_rx, max_tx, max_cp, shared);
+               if (rc)
+                       rc = 0;
+       }
+
+       return rc;
+}
+
+/* In initial default shared ring setting, each shared ring must have a
+ * RX/TX ring pair.
+ */
+static void bnge_trim_dflt_sh_rings(struct bnge_dev *bd)
+{
+       bd->nq_nr_rings = min_t(u16, bd->tx_nr_rings_per_tc, bd->rx_nr_rings);
+       bd->rx_nr_rings = bd->nq_nr_rings;
+       bd->tx_nr_rings_per_tc = bd->nq_nr_rings;
+       bd->tx_nr_rings = bd->tx_nr_rings_per_tc;
+}
+
+static int bnge_net_init_dflt_rings(struct bnge_dev *bd, bool sh)
+{
+       u16 dflt_rings, max_rx_rings, max_tx_rings;
+       int rc;
+
+       if (sh)
+               bd->flags |= BNGE_EN_SHARED_CHNL;
+
+       dflt_rings = netif_get_num_default_rss_queues();
+
+       rc = bnge_get_dflt_rings(bd, &max_rx_rings, &max_tx_rings, sh);
+       if (rc)
+               return rc;
+       bd->rx_nr_rings = min_t(u16, dflt_rings, max_rx_rings);
+       bd->tx_nr_rings_per_tc = min_t(u16, dflt_rings, max_tx_rings);
+       if (sh)
+               bnge_trim_dflt_sh_rings(bd);
+       else
+               bd->nq_nr_rings = bd->tx_nr_rings_per_tc + bd->rx_nr_rings;
+       bd->tx_nr_rings = bd->tx_nr_rings_per_tc;
+
+       rc = bnge_reserve_rings(bd);
+       if (rc && rc != -ENODEV)
+               dev_warn(bd->dev, "Unable to reserve tx rings\n");
+       bd->tx_nr_rings_per_tc = bd->tx_nr_rings;
+       if (sh)
+               bnge_trim_dflt_sh_rings(bd);
+
+       /* Rings may have been reduced, re-reserve them again */
+       if (bnge_need_reserve_rings(bd)) {
+               rc = bnge_reserve_rings(bd);
+               if (rc && rc != -ENODEV)
+                       dev_warn(bd->dev, "Fewer rings reservation failed\n");
+               bd->tx_nr_rings_per_tc = bd->tx_nr_rings;
+       }
+       if (rc) {
+               bd->tx_nr_rings = 0;
+               bd->rx_nr_rings = 0;
+       }
+
+       return rc;
+}
+
+static int bnge_alloc_rss_indir_tbl(struct bnge_dev *bd)
+{
+       u16 entries;
+
+       entries = BNGE_MAX_RSS_TABLE_ENTRIES;
+
+       bd->rss_indir_tbl_entries = entries;
+       bd->rss_indir_tbl =
+               kmalloc_array(entries, sizeof(*bd->rss_indir_tbl), GFP_KERNEL);
+       if (!bd->rss_indir_tbl)
+               return -ENOMEM;
+
+       return 0;
+}
+
+int bnge_net_init_dflt_config(struct bnge_dev *bd)
+{
+       struct bnge_hw_resc *hw_resc;
+       int rc;
+
+       rc = bnge_alloc_rss_indir_tbl(bd);
+       if (rc)
+               return rc;
+
+       rc = bnge_net_init_dflt_rings(bd, true);
+       if (rc)
+               goto err_free_tbl;
+
+       hw_resc = &bd->hw_resc;
+       bd->max_fltr = hw_resc->max_rx_em_flows + hw_resc->max_rx_wm_flows +
+                      BNGE_L2_FLTR_MAX_FLTR;
+
+       return 0;
+
+err_free_tbl:
+       kfree(bd->rss_indir_tbl);
+       bd->rss_indir_tbl = NULL;
+       return rc;
+}
+
+void bnge_net_uninit_dflt_config(struct bnge_dev *bd)
+{
+       kfree(bd->rss_indir_tbl);
+       bd->rss_indir_tbl = NULL;
+}
+
+void bnge_aux_init_dflt_config(struct bnge_dev *bd)
+{
+       bd->aux_num_msix = bnge_aux_get_dflt_msix(bd);
+       bd->aux_num_stat_ctxs = bnge_get_dflt_aux_stat_ctxs(bd);
+}
index 23db93e0378759eedd4c9fd093cd71bed126d878..b39fd1a7a81b7ff10670aaf6180f55b8ef53998f 100644 (file)
@@ -66,6 +66,9 @@ int bnge_reserve_rings(struct bnge_dev *bd);
 int bnge_fix_rings_count(u16 *rx, u16 *tx, u16 max, bool shared);
 int bnge_alloc_irqs(struct bnge_dev *bd);
 void bnge_free_irqs(struct bnge_dev *bd);
+int bnge_net_init_dflt_config(struct bnge_dev *bd);
+void bnge_net_uninit_dflt_config(struct bnge_dev *bd);
+void bnge_aux_init_dflt_config(struct bnge_dev *bd);
 
 static inline u32
 bnge_adjust_pow_two(u32 total_ent, u16 ent_per_blk)