diff --git a/src/cndm/modules/cndm/Makefile b/src/cndm/modules/cndm/Makefile index a2a3e71..f6f7735 100644 --- a/src/cndm/modules/cndm/Makefile +++ b/src/cndm/modules/cndm/Makefile @@ -5,6 +5,7 @@ ifneq ($(KERNELRELEASE),) obj-m += cndm.o cndm-y += cndm_main.o +cndm-y += cndm_devlink.o cndm-y += cndm_netdev.o cndm-y += cndm_tx.o cndm-y += cndm_rx.o diff --git a/src/cndm/modules/cndm/cndm.h b/src/cndm/modules/cndm/cndm.h index 0855f26..5942b2b 100644 --- a/src/cndm/modules/cndm/cndm.h +++ b/src/cndm/modules/cndm/cndm.h @@ -16,6 +16,7 @@ Authors: #include #include #include +#include #define DRIVER_NAME "cndm" #define DRIVER_VERSION "0.1" @@ -122,14 +123,21 @@ struct cndm_cpl { __u8 phase; }; +// cndm_devlink.c +struct devlink *cndm_devlink_alloc(struct device *dev); +void cndm_devlink_free(struct devlink *devlink); + +// cndm_netdev.c irqreturn_t cndm_irq(int irqn, void *data); struct net_device *cndm_create_netdev(struct cndm_dev *cdev, int port, void __iomem *hw_addr); void cndm_destroy_netdev(struct net_device *ndev); +// cndm_tx.c int cndm_free_tx_buf(struct cndm_priv *priv); int cndm_poll_tx_cq(struct napi_struct *napi, int budget); int cndm_start_xmit(struct sk_buff *skb, struct net_device *ndev); +// cndm_rx.c int cndm_free_rx_buf(struct cndm_priv *priv); int cndm_refill_rx_buffers(struct cndm_priv *priv); int cndm_poll_rx_cq(struct napi_struct *napi, int budget); diff --git a/src/cndm/modules/cndm/cndm_devlink.c b/src/cndm/modules/cndm/cndm_devlink.c new file mode 100644 index 0000000..bb45859 --- /dev/null +++ b/src/cndm/modules/cndm/cndm_devlink.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL +/* + +Copyright (c) 2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +#include "cndm.h" + +#include + +static int cndm_devlink_info_get(struct devlink *devlink, + struct devlink_info_req *req, struct netlink_ext_ack *extack) +{ + struct cndm_dev *cdev = devlink_priv(devlink); + char str[32]; + int ret = 0; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0) + ret = devlink_info_driver_name_put(req, KBUILD_MODNAME); + if (ret) + return ret; +#endif + + snprintf(str, sizeof(str), "%08x", 0); // TODO + + ret = devlink_info_version_fixed_put(req, "fpga.id", str); + if (ret) + return ret; + + snprintf(str, sizeof(str), "%08x", 0); // TODO + + ret = devlink_info_version_fixed_put(req, DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, str); + if (ret) + return ret; + + snprintf(str, sizeof(str), "%08x", 0); // TODO + + ret = devlink_info_version_fixed_put(req, DEVLINK_INFO_VERSION_GENERIC_BOARD_REV, str); + if (ret) + return ret; + + snprintf(str, sizeof(str), "%08x", 0); // TODO + + ret = devlink_info_version_running_put(req, "fw.id", str); + if (ret) + return ret; + + snprintf(str, sizeof(str), "%08x", 0); // TODO + + ret = devlink_info_version_running_put(req, DEVLINK_INFO_VERSION_GENERIC_FW, str); + if (ret) + return ret; + + return ret; +} + +static const struct devlink_ops cndm_devlink_ops = { + .info_get = cndm_devlink_info_get, +}; + +struct devlink *cndm_devlink_alloc(struct device *dev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + return devlink_alloc(&cndm_devlink_ops, sizeof(struct cndm_dev), dev); +#else + return devlink_alloc(&cndm_devlink_ops, sizeof(struct cndm_dev)); +#endif +} + +void cndm_devlink_free(struct devlink *devlink) { + devlink_free(devlink); +} diff --git a/src/cndm/modules/cndm/cndm_main.c b/src/cndm/modules/cndm/cndm_main.c index 679b70b..6fdd876 100644 --- a/src/cndm/modules/cndm/cndm_main.c +++ b/src/cndm/modules/cndm/cndm_main.c @@ -11,6 +11,7 @@ Authors: #include "cndm.h" #include #include +#include MODULE_DESCRIPTION("Corundum device driver"); MODULE_AUTHOR("FPGA Ninja"); @@ -20,6 +21,7 @@ MODULE_VERSION(DRIVER_VERSION); static int cndm_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct device *dev = &pdev->dev; + struct devlink *devlink; struct cndm_dev *cdev; int ret = 0; int k; @@ -32,10 +34,11 @@ static int cndm_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pcie_print_link_status(pdev); - cdev = devm_kzalloc(dev, sizeof(struct cndm_dev), GFP_KERNEL); - if (!cdev) + devlink = cndm_devlink_alloc(dev); + if (!devlink) return -ENOMEM; + cdev = devlink_priv(devlink); cdev->pdev = pdev; cdev->dev = dev; pci_set_drvdata(pdev, cdev); @@ -76,6 +79,12 @@ static int cndm_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto fail_map_bars; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + devlink_register(devlink); +#else + devlink_register(devlink, dev); +#endif + cdev->port_count = ioread32(cdev->bar + 0x0100); cdev->port_offset = ioread32(cdev->bar + 0x0104); cdev->port_stride = ioread32(cdev->bar + 0x0108); @@ -113,6 +122,7 @@ fail_netdev: cdev->ndev[k] = NULL; } } + devlink_unregister(devlink); pci_free_irq_vectors(pdev); fail_map_bars: if (cdev->bar) @@ -122,6 +132,7 @@ fail_regions: pci_clear_master(pdev); pci_disable_device(pdev); fail_enable_device: + cndm_devlink_free(devlink); return ret; } @@ -129,6 +140,7 @@ static void cndm_pci_remove(struct pci_dev *pdev) { struct device *dev = &pdev->dev; struct cndm_dev *cdev = pci_get_drvdata(pdev); + struct devlink *devlink = priv_to_devlink(cdev); int k; dev_info(dev, DRIVER_NAME " PCI remove"); @@ -140,12 +152,14 @@ static void cndm_pci_remove(struct pci_dev *pdev) cdev->ndev[k] = NULL; } } + devlink_unregister(devlink); pci_free_irq_vectors(pdev); if (cdev->bar) pci_iounmap(pdev, cdev->bar); pci_release_regions(pdev); pci_clear_master(pdev); pci_disable_device(pdev); + cndm_devlink_free(devlink); } static const struct pci_device_id cndm_pci_id_table[] = {