]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bng_en: Add devlink interface
authorVikas Gupta <vikas.gupta@broadcom.com>
Tue, 1 Jul 2025 14:35:00 +0000 (14:35 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 8 Jul 2025 01:54:00 +0000 (18:54 -0700)
Allocate a base device and devlink interface with minimal
devlink ops.
Add dsn and board related information.
Map PCIe BAR (bar0), which helps to communicate with the
firmware.

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-3-vikas.gupta@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/bnge/Makefile
drivers/net/ethernet/broadcom/bnge/bnge.h
drivers/net/ethernet/broadcom/bnge/bnge_core.c
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c [new file with mode: 0644]
drivers/net/ethernet/broadcom/bnge/bnge_devlink.h [new file with mode: 0644]

index e2c1ac91708e0308550dbad0998a4b807f39a74c..0fc10e6c6902f80e25c0b766f88dc1f0ae12f51a 100644 (file)
@@ -256,6 +256,7 @@ config BNXT_HWMON
 config BNGE
        tristate "Broadcom Ethernet device support"
        depends on PCI
+       select NET_DEVLINK
        help
          This driver supports Broadcom 50/100/200/400/800 gigabit Ethernet cards.
          The module will be called bng_en. To compile this driver as a module,
index 0c3d632805d1011b2f9694fd21c850e043159d46..e021a14d2fa078a3e4df62fa384601204b36dc12 100644 (file)
@@ -2,4 +2,5 @@
 
 obj-$(CONFIG_BNGE) += bng_en.o
 
-bng_en-y := bnge_core.o
+bng_en-y := bnge_core.o \
+           bnge_devlink.o
index b49c51b4447385f2851c9c7a03ba5c54c6b26cbd..19d85aabab4e0736a10d7d69ee407f861d8595bb 100644 (file)
@@ -13,4 +13,15 @@ enum board_idx {
        BCM57708,
 };
 
+struct bnge_dev {
+       struct device   *dev;
+       struct pci_dev  *pdev;
+       u64     dsn;
+#define BNGE_VPD_FLD_LEN       32
+       char            board_partno[BNGE_VPD_FLD_LEN];
+       char            board_serialno[BNGE_VPD_FLD_LEN];
+
+       void __iomem    *bar0;
+};
+
 #endif /* _BNGE_H_ */
index 514602555cd16de67e1c3b26fa0627f3e2b7b6f6..2596215f0639bccdba48f9d2607f98ecaa0b4b4d 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/pci.h>
 
 #include "bnge.h"
+#include "bnge_devlink.h"
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION(DRV_SUMMARY);
@@ -77,8 +78,19 @@ err_pci_disable:
        return rc;
 }
 
+static void bnge_unmap_bars(struct pci_dev *pdev)
+{
+       struct bnge_dev *bd = pci_get_drvdata(pdev);
+
+       if (bd->bar0) {
+               pci_iounmap(pdev, bd->bar0);
+               bd->bar0 = NULL;
+       }
+}
+
 static int bnge_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       struct bnge_dev *bd;
        int rc;
 
        if (pci_is_bridge(pdev))
@@ -100,13 +112,40 @@ static int bnge_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        bnge_print_device_info(pdev, ent->driver_data);
 
+       bd = bnge_devlink_alloc(pdev);
+       if (!bd) {
+               dev_err(&pdev->dev, "Devlink allocation failed\n");
+               rc = -ENOMEM;
+               goto err_pci_disable;
+       }
+
+       bd->bar0 = pci_ioremap_bar(pdev, 0);
+       if (!bd->bar0) {
+               dev_err(&pdev->dev, "Failed mapping BAR-0, aborting\n");
+               rc = -ENOMEM;
+               goto err_devl_free;
+       }
+
        pci_save_state(pdev);
 
        return 0;
+
+err_devl_free:
+       bnge_devlink_free(bd);
+
+err_pci_disable:
+       bnge_pci_disable(pdev);
+       return rc;
 }
 
 static void bnge_remove_one(struct pci_dev *pdev)
 {
+       struct bnge_dev *bd = pci_get_drvdata(pdev);
+
+       bnge_unmap_bars(pdev);
+
+       bnge_devlink_free(bd);
+
        bnge_pci_disable(pdev);
 }
 
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_devlink.c b/drivers/net/ethernet/broadcom/bnge/bnge_devlink.c
new file mode 100644 (file)
index 0000000..d01cc32
--- /dev/null
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2025 Broadcom.
+
+#include <linux/unaligned.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <net/devlink.h>
+
+#include "bnge.h"
+#include "bnge_devlink.h"
+
+static int bnge_dl_info_put(struct bnge_dev *bd, struct devlink_info_req *req,
+                           enum bnge_dl_version_type type, const char *key,
+                           char *buf)
+{
+       if (!strlen(buf))
+               return 0;
+
+       switch (type) {
+       case BNGE_VERSION_FIXED:
+               return devlink_info_version_fixed_put(req, key, buf);
+       case BNGE_VERSION_RUNNING:
+               return devlink_info_version_running_put(req, key, buf);
+       case BNGE_VERSION_STORED:
+               return devlink_info_version_stored_put(req, key, buf);
+       }
+
+       return 0;
+}
+
+static void bnge_vpd_read_info(struct bnge_dev *bd)
+{
+       struct pci_dev *pdev = bd->pdev;
+       unsigned int vpd_size, kw_len;
+       int pos, size;
+       u8 *vpd_data;
+
+       vpd_data = pci_vpd_alloc(pdev, &vpd_size);
+       if (IS_ERR(vpd_data)) {
+               pci_warn(pdev, "Unable to read VPD\n");
+               return;
+       }
+
+       pos = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size,
+                                          PCI_VPD_RO_KEYWORD_PARTNO, &kw_len);
+       if (pos < 0)
+               goto read_sn;
+
+       size = min_t(int, kw_len, BNGE_VPD_FLD_LEN - 1);
+       memcpy(bd->board_partno, &vpd_data[pos], size);
+
+read_sn:
+       pos = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size,
+                                          PCI_VPD_RO_KEYWORD_SERIALNO,
+                                          &kw_len);
+       if (pos < 0)
+               goto exit;
+
+       size = min_t(int, kw_len, BNGE_VPD_FLD_LEN - 1);
+       memcpy(bd->board_serialno, &vpd_data[pos], size);
+
+exit:
+       kfree(vpd_data);
+}
+
+static int bnge_devlink_info_get(struct devlink *devlink,
+                                struct devlink_info_req *req,
+                                struct netlink_ext_ack *extack)
+{
+       struct bnge_dev *bd = devlink_priv(devlink);
+       int rc;
+
+       if (bd->dsn) {
+               char buf[32];
+               u8 dsn[8];
+               int rc;
+
+               put_unaligned_le64(bd->dsn, dsn);
+               sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
+                       dsn[7], dsn[6], dsn[5], dsn[4],
+                       dsn[3], dsn[2], dsn[1], dsn[0]);
+               rc = devlink_info_serial_number_put(req, buf);
+               if (rc) {
+                       NL_SET_ERR_MSG_MOD(extack, "Failed to set dsn");
+                       return rc;
+               }
+       }
+
+       if (strlen(bd->board_serialno)) {
+               rc = devlink_info_board_serial_number_put(req,
+                                                         bd->board_serialno);
+               if (rc) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Failed to set board serial number");
+                       return rc;
+               }
+       }
+
+       rc = bnge_dl_info_put(bd, req, BNGE_VERSION_FIXED,
+                             DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
+                             bd->board_partno);
+       if (rc) {
+               NL_SET_ERR_MSG_MOD(extack, "Failed to set board part number");
+               return rc;
+       }
+
+       return rc;
+}
+
+static const struct devlink_ops bnge_devlink_ops = {
+       .info_get = bnge_devlink_info_get,
+};
+
+void bnge_devlink_free(struct bnge_dev *bd)
+{
+       struct devlink *devlink = priv_to_devlink(bd);
+
+       devlink_free(devlink);
+}
+
+struct bnge_dev *bnge_devlink_alloc(struct pci_dev *pdev)
+{
+       struct devlink *devlink;
+       struct bnge_dev *bd;
+
+       devlink = devlink_alloc(&bnge_devlink_ops, sizeof(*bd), &pdev->dev);
+       if (!devlink)
+               return NULL;
+
+       bd = devlink_priv(devlink);
+       pci_set_drvdata(pdev, bd);
+       bd->dev = &pdev->dev;
+       bd->pdev = pdev;
+
+       bd->dsn = pci_get_dsn(pdev);
+       if (!bd->dsn)
+               pci_warn(pdev, "Failed to get DSN\n");
+
+       bnge_vpd_read_info(bd);
+
+       return bd;
+}
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_devlink.h b/drivers/net/ethernet/broadcom/bnge/bnge_devlink.h
new file mode 100644 (file)
index 0000000..4975439
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2025 Broadcom */
+
+#ifndef _BNGE_DEVLINK_H_
+#define _BNGE_DEVLINK_H_
+
+enum bnge_dl_version_type {
+       BNGE_VERSION_FIXED,
+       BNGE_VERSION_RUNNING,
+       BNGE_VERSION_STORED,
+};
+
+void bnge_devlink_free(struct bnge_dev *bd);
+struct bnge_dev *bnge_devlink_alloc(struct pci_dev *pdev);
+
+#endif /* _BNGE_DEVLINK_H_ */