mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
bng_en: Add devlink interface
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>
This commit is contained in:
parent
74715c4ab0
commit
9099bfa115
6 changed files with 211 additions and 1 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
142
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c
Normal file
142
drivers/net/ethernet/broadcom/bnge/bnge_devlink.c
Normal file
|
@ -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;
|
||||
}
|
16
drivers/net/ethernet/broadcom/bnge/bnge_devlink.h
Normal file
16
drivers/net/ethernet/broadcom/bnge/bnge_devlink.h
Normal file
|
@ -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_ */
|
Loading…
Add table
Reference in a new issue