From a9800099e328232fb5e38b8bcb1f8d2fb71c3520 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 12 Sep 2023 11:17:24 -0700 Subject: [PATCH] modules/mqnic: Add initial devlink support Signed-off-by: Alex Forencich --- modules/mqnic/Makefile | 1 + modules/mqnic/mqnic.h | 4 ++ modules/mqnic/mqnic_devlink.c | 100 ++++++++++++++++++++++++++++++++++ modules/mqnic/mqnic_main.c | 24 ++++++-- 4 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 modules/mqnic/mqnic_devlink.c diff --git a/modules/mqnic/Makefile b/modules/mqnic/Makefile index 1860a93fa..796d737f0 100644 --- a/modules/mqnic/Makefile +++ b/modules/mqnic/Makefile @@ -6,6 +6,7 @@ ifneq ($(KERNELRELEASE),) # object files to build obj-m += mqnic.o mqnic-y += mqnic_main.o +mqnic-y += mqnic_devlink.o mqnic-y += mqnic_res.o mqnic-y += mqnic_reg_block.o mqnic-y += mqnic_irq.o diff --git a/modules/mqnic/mqnic.h b/modules/mqnic/mqnic.h index 3b97747e6..58a4d4d8f 100644 --- a/modules/mqnic/mqnic.h +++ b/modules/mqnic/mqnic.h @@ -467,6 +467,10 @@ struct mqnic_priv { // mqnic_main.c +// mqnic_devlink.c +struct devlink *mqnic_devlink_alloc(struct device *dev); +void mqnic_devlink_free(struct devlink *devlink); + // mqnic_res.c struct mqnic_res *mqnic_create_res(unsigned int count, u8 __iomem *base, unsigned int stride); void mqnic_destroy_res(struct mqnic_res *res); diff --git a/modules/mqnic/mqnic_devlink.c b/modules/mqnic/mqnic_devlink.c new file mode 100644 index 000000000..a433e66ea --- /dev/null +++ b/modules/mqnic/mqnic_devlink.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: BSD-2-Clause-Views +/* + * Copyright (c) 2023 The Regents of the University of California + */ + +#include "mqnic.h" + +#include +#include + +static int mqnic_devlink_info_get(struct devlink *devlink, + struct devlink_info_req *req, struct netlink_ext_ack *extack) +{ + struct mqnic_dev *mdev = devlink_priv(devlink); + char str[32]; + int err; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0) + err = devlink_info_driver_name_put(req, KBUILD_MODNAME); + if (err) + return err; +#endif + + snprintf(str, sizeof(str), "%08x", mdev->fpga_id); + + err = devlink_info_version_fixed_put(req, "fpga.id", str); + if (err) + return err; + + snprintf(str, sizeof(str), "%08x", mdev->board_id); + + err = devlink_info_version_fixed_put(req, DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, str); + if (err) + return err; + + snprintf(str, sizeof(str), "%d.%d.%d.%d", + mdev->board_ver >> 24, (mdev->board_ver >> 16) & 0xff, + (mdev->board_ver >> 8) & 0xff, mdev->board_ver & 0xff); + + err = devlink_info_version_fixed_put(req, DEVLINK_INFO_VERSION_GENERIC_BOARD_REV, str); + if (err) + return err; + + snprintf(str, sizeof(str), "%08x", mdev->fw_id); + + err = devlink_info_version_running_put(req, "fw.id", str); + if (err) + return err; + + snprintf(str, sizeof(str), "%d.%d.%d.%d", + mdev->fw_ver >> 24, (mdev->fw_ver >> 16) & 0xff, + (mdev->fw_ver >> 8) & 0xff, mdev->fw_ver & 0xff); + + err = devlink_info_version_running_put(req, "fw.version", str); + if (err) + return err; + err = devlink_info_version_running_put(req, DEVLINK_INFO_VERSION_GENERIC_FW, str); + if (err) + return err; + + err = devlink_info_version_running_put(req, "fw.build_date", mdev->build_date_str); + if (err) + return err; + + snprintf(str, sizeof(str), "%08x", mdev->git_hash); + + err = devlink_info_version_running_put(req, "fw.git_hash", str); + if (err) + return err; + + snprintf(str, sizeof(str), "%08x", mdev->rel_info); + + err = devlink_info_version_running_put(req, "fw.rel_info", str); + if (err) + return err; + + if (mdev->app_id) { + snprintf(str, sizeof(str), "%08x", mdev->app_id); + + err = devlink_info_version_running_put(req, "fw.app.id", str); + if (err) + return err; + } + + return 0; +} + +static const struct devlink_ops mqnic_devlink_ops = { + .info_get = mqnic_devlink_info_get, +}; + +struct devlink *mqnic_devlink_alloc(struct device *dev) +{ + return devlink_alloc(&mqnic_devlink_ops, sizeof(struct mqnic_dev), dev); +} + +void mqnic_devlink_free(struct devlink *devlink) +{ + devlink_free(devlink); +} diff --git a/modules/mqnic/mqnic_main.c b/modules/mqnic/mqnic_main.c index ab0969a88..b8fad741d 100644 --- a/modules/mqnic/mqnic_main.c +++ b/modules/mqnic/mqnic_main.c @@ -9,6 +9,7 @@ #include #include #include +#include #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0) #include @@ -238,6 +239,7 @@ static void mqnic_adev_release(struct device *dev) static int mqnic_common_probe(struct mqnic_dev *mqnic) { int ret = 0; + struct devlink *devlink = priv_to_devlink(mqnic); struct device *dev = mqnic->dev; struct mqnic_reg_block *rb; struct rtc_time tm; @@ -442,6 +444,7 @@ fail_create_if: #endif // probe complete + devlink_register(devlink); return 0; // error handling @@ -458,8 +461,11 @@ fail_rb_init: static void mqnic_common_remove(struct mqnic_dev *mqnic) { + struct devlink *devlink = priv_to_devlink(mqnic); int k = 0; + devlink_unregister(devlink); + #ifdef CONFIG_AUXILIARY_BUS if (mqnic->app_adev) { auxiliary_device_delete(&mqnic->app_adev->adev); @@ -494,6 +500,7 @@ static int mqnic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent { int ret = 0; struct mqnic_dev *mqnic; + struct devlink *devlink; struct device *dev = &pdev->dev; struct pci_dev *bridge = pci_upstream_bridge(pdev); @@ -563,10 +570,11 @@ static int mqnic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent pcie_print_link_status(pdev); #endif - mqnic = devm_kzalloc(dev, sizeof(*mqnic), GFP_KERNEL); - if (!mqnic) + devlink = mqnic_devlink_alloc(dev); + if (!devlink) return -ENOMEM; + mqnic = devlink_priv(devlink); mqnic->dev = dev; mqnic->pdev = pdev; pci_set_drvdata(pdev, mqnic); @@ -676,12 +684,14 @@ fail_regions: pci_disable_device(pdev); fail_enable_device: mqnic_free_id(mqnic); + mqnic_devlink_free(devlink); return ret; } static void mqnic_pci_remove(struct pci_dev *pdev) { struct mqnic_dev *mqnic = pci_get_drvdata(pdev); + struct devlink *devlink = priv_to_devlink(mqnic); dev_info(&pdev->dev, DRIVER_NAME " PCI remove"); @@ -698,6 +708,7 @@ static void mqnic_pci_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); mqnic_free_id(mqnic); + mqnic_devlink_free(devlink); } static void mqnic_pci_shutdown(struct pci_dev *pdev) @@ -720,6 +731,7 @@ static int mqnic_platform_probe(struct platform_device *pdev) { int ret; struct mqnic_dev *mqnic; + struct devlink *devlink; struct device *dev = &pdev->dev; struct resource *res; struct reset_control *rst; @@ -730,10 +742,11 @@ static int mqnic_platform_probe(struct platform_device *pdev) dev_info(dev, " NUMA node: %d", pdev->dev.numa_node); #endif - mqnic = devm_kzalloc(dev, sizeof(*mqnic), GFP_KERNEL); - if (!mqnic) + devlink = mqnic_devlink_alloc(dev); + if (!devlink) return -ENOMEM; + mqnic = devlink_priv(devlink); mqnic->dev = dev; mqnic->pfdev = pdev; platform_set_drvdata(pdev, mqnic); @@ -822,18 +835,21 @@ static int mqnic_platform_probe(struct platform_device *pdev) // error handling fail: mqnic_free_id(mqnic); + mqnic_devlink_free(devlink); return ret; } static int mqnic_platform_remove(struct platform_device *pdev) { struct mqnic_dev *mqnic = platform_get_drvdata(pdev); + struct devlink *devlink = priv_to_devlink(mqnic); dev_info(&pdev->dev, DRIVER_NAME " platform remove"); mqnic_common_remove(mqnic); mqnic_free_id(mqnic); + mqnic_devlink_free(devlink); return 0; }