From: Junyang Han Add basic framework for ZTE DingHai ethernet PF driver, including Kconfig/Makefile build support and PCIe device probe/remove skeleton. Signed-off-by: Junyang Han --- MAINTAINERS | 6 + drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/zte/Kconfig | 20 +++ drivers/net/ethernet/zte/Makefile | 6 + drivers/net/ethernet/zte/dinghai/Kconfig | 34 ++++ drivers/net/ethernet/zte/dinghai/Makefile | 10 ++ drivers/net/ethernet/zte/dinghai/en_pf.c | 195 ++++++++++++++++++++++ drivers/net/ethernet/zte/dinghai/en_pf.h | 52 ++++++ 9 files changed, 325 insertions(+) create mode 100644 drivers/net/ethernet/zte/Kconfig create mode 100644 drivers/net/ethernet/zte/Makefile create mode 100644 drivers/net/ethernet/zte/dinghai/Kconfig create mode 100644 drivers/net/ethernet/zte/dinghai/Makefile create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.c create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.h diff --git a/MAINTAINERS b/MAINTAINERS index 2fb1c75afd16..73692b09bf7b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -29440,6 +29440,12 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git F: sound/hda/codecs/senarytech.c +ZTE DINGHAI ETHERNET DRIVER +M: Junyang Han +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/zte/ + THE REST M: Linus Torvalds L: linux-kernel@vger.kernel.org diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index b8f70e2a1763..c2b6996b0cfe 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -188,5 +188,6 @@ source "drivers/net/ethernet/wangxun/Kconfig" source "drivers/net/ethernet/wiznet/Kconfig" source "drivers/net/ethernet/xilinx/Kconfig" source "drivers/net/ethernet/xircom/Kconfig" +source "drivers/net/ethernet/zte/Kconfig" endif # ETHERNET diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 57344fec6ce0..a34bcbd4df4e 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -104,3 +104,4 @@ obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/ obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/ obj-$(CONFIG_OA_TC6) += oa_tc6.o +obj-$(CONFIG_NET_VENDOR_ZTE) += zte/ diff --git a/drivers/net/ethernet/zte/Kconfig b/drivers/net/ethernet/zte/Kconfig new file mode 100644 index 000000000000..b95c2fc7db77 --- /dev/null +++ b/drivers/net/ethernet/zte/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# ZTE driver configuration +# + +config NET_VENDOR_ZTE + bool "ZTE devices" + default y + help + If you have a network (Ethernet) card belonging to this class, say Y. + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Zte cards. If you say Y, you will be asked + for your specific card in the following questions. + +if NET_VENDOR_ZTE + +source "drivers/net/ethernet/zte/dinghai/Kconfig" + +endif # NET_VENDOR_ZTE diff --git a/drivers/net/ethernet/zte/Makefile b/drivers/net/ethernet/zte/Makefile new file mode 100644 index 000000000000..cd9929b61559 --- /dev/null +++ b/drivers/net/ethernet/zte/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the ZTE device drivers +# + +obj-$(CONFIG_DINGHAI) += dinghai/ diff --git a/drivers/net/ethernet/zte/dinghai/Kconfig b/drivers/net/ethernet/zte/dinghai/Kconfig new file mode 100644 index 000000000000..121be3bf7707 --- /dev/null +++ b/drivers/net/ethernet/zte/dinghai/Kconfig @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# ZTE DingHai Ethernet driver configuration +# + +config DINGHAI + bool "ZTE DingHai Ethernet driver" + depends on PCI + select NET_DEVLINK + help + This driver supports ZTE DingHai Ethernet devices. + + DingHai is a high-performance Ethernet controller that supports + multiple features including hardware offloading, SR-IOV, and + advanced virtualization capabilities. + + If you say Y here, you can select specific driver variants below. + + If unsure, say N. + +if DINGHAI + +config DINGHAI_PF + tristate "ZTE DingHai PF (Physical Function) driver" + help + This driver supports ZTE DingHai PCI Express Ethernet + adapters (PF). + + To compile this driver as a module, choose M here. The module + will be named dinghai10e. + + If unsure, say N. + +endif # DINGHAI diff --git a/drivers/net/ethernet/zte/dinghai/Makefile b/drivers/net/ethernet/zte/dinghai/Makefile new file mode 100644 index 000000000000..f55a8de518be --- /dev/null +++ b/drivers/net/ethernet/zte/dinghai/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for ZTE DingHai Ethernet driver +# + +ccflags-y += -I$(src) + +obj-$(CONFIG_DINGHAI_PF) += dinghai10e.o +dinghai10e-y := en_pf.o + diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.c b/drivers/net/ethernet/zte/dinghai/en_pf.c new file mode 100644 index 000000000000..034b8519a71c --- /dev/null +++ b/drivers/net/ethernet/zte/dinghai/en_pf.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ZTE DingHai Ethernet driver + * Copyright (c) 2022-2026, ZTE Corporation. + */ + +#include +#include +#include +#include +#include "en_pf.h" + +MODULE_AUTHOR("Junyang Han "); +MODULE_DESCRIPTION("ZTE DingHai series Ethernet driver"); +MODULE_LICENSE("GPL"); + +static const struct devlink_ops dh_pf_devlink_ops = {}; + +static const struct pci_device_id dh_pf_pci_table[] = { + { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_PF_DEVICE_ID) }, + { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_VF_DEVICE_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(pci, dh_pf_pci_table); + +void *dh_core_alloc_priv(struct dh_core_dev *dh_dev, size_t size) +{ + void *priv = kzalloc(size, GFP_KERNEL); + + if (priv) + dh_dev->priv = priv; + return priv; +} + +void dh_core_free_priv(struct dh_core_dev *dh_dev) +{ + kfree(dh_dev->priv); +} + +static int dh_pf_pci_init(struct dh_core_dev *dev) +{ + struct zxdh_pf_device *pf_dev = dev->priv; + int ret; + + pci_set_drvdata(dev->pdev, dev); + + ret = pci_enable_device(dev->pdev); + if (ret) { + dev_err(dev->device, "pci_enable_device failed: %d\n", ret); + return ret; + } + + ret = dma_set_mask_and_coherent(dev->device, DMA_BIT_MASK(64)); + if (ret) { + ret = dma_set_mask_and_coherent(dev->device, DMA_BIT_MASK(32)); + if (ret) { + dev_err(dev->device, "dma_set_mask_and_coherent failed: %d\n", ret); + goto err_pci; + } + } + + ret = pci_request_selected_regions(dev->pdev, + pci_select_bars(dev->pdev, IORESOURCE_MEM), + "dh-pf"); + if (ret) { + dev_err(dev->device, "pci_request_selected_regions failed: %d\n", ret); + goto err_pci; + } + + pci_set_master(dev->pdev); + ret = pci_save_state(dev->pdev); + if (ret) { + dev_err(dev->device, "pci_save_state failed: %d\n", ret); + goto err_pci_save_state; + } + + if (!(pci_resource_flags(dev->pdev, 0) & IORESOURCE_MEM)) { + ret = -ENODEV; + dev_err(dev->device, "BAR 0 is not an MMIO resource\n"); + goto err_pci_save_state; + } + + pf_dev->pci_ioremap_addr[0] = + ioremap(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); + if (!pf_dev->pci_ioremap_addr[0]) { + ret = -ENOMEM; + dev_err(dev->device, "dh pf pci ioremap failed\n"); + goto err_pci_save_state; + } + + return 0; + +err_pci_save_state: + pci_release_selected_regions(dev->pdev, + pci_select_bars(dev->pdev, IORESOURCE_MEM)); +err_pci: + pci_disable_device(dev->pdev); + return ret; +} + +void dh_pf_pci_close(struct dh_core_dev *dev) +{ + struct zxdh_pf_device *pf_dev = dev->priv; + + iounmap(pf_dev->pci_ioremap_addr[0]); + pci_release_selected_regions(dev->pdev, + pci_select_bars(dev->pdev, IORESOURCE_MEM)); + pci_disable_device(dev->pdev); +} + +static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct zxdh_pf_device *pf_dev; + struct dh_core_dev *dh_dev; + struct devlink *devlink; + int ret; + + devlink = devlink_alloc(&dh_pf_devlink_ops, sizeof(struct dh_core_dev), + &pdev->dev); + if (!devlink) { + dev_err(&pdev->dev, "dh_pf devlink alloc failed\n"); + return -ENOMEM; + } + + dh_dev = devlink_priv(devlink); + dh_dev->device = &pdev->dev; + dh_dev->pdev = pdev; + dh_dev->devlink = devlink; + + pf_dev = dh_core_alloc_priv(dh_dev, sizeof(*pf_dev)); + if (!pf_dev) { + dev_err(&pdev->dev, "dh_pf_dev alloc failed\n"); + ret = -ENOMEM; + goto err_pf_dev; + } + + pf_dev->bar_chan_valid = false; + pf_dev->vepa = false; + mutex_init(&dh_dev->lock); + mutex_init(&pf_dev->irq_lock); + + dh_dev->coredev_type = GET_COREDEV_TYPE(pdev); + + ret = dh_pf_pci_init(dh_dev); + if (ret) { + dev_err(&pdev->dev, "dh_pf_pci_init failed: %d\n", ret); + goto err_cfg_init; + } + + devlink_register(devlink); + + return 0; + +err_cfg_init: + mutex_destroy(&pf_dev->irq_lock); + mutex_destroy(&dh_dev->lock); + dh_core_free_priv(dh_dev); +err_pf_dev: + devlink_free(devlink); + return ret; +} + +static void dh_pf_remove(struct pci_dev *pdev) +{ + struct dh_core_dev *dh_dev = pci_get_drvdata(pdev); + struct devlink *devlink = priv_to_devlink(dh_dev); + struct zxdh_pf_device *pf_dev = dh_dev->priv; + + devlink_unregister(devlink); + dh_pf_pci_close(dh_dev); + mutex_destroy(&pf_dev->irq_lock); + mutex_destroy(&dh_dev->lock); + dh_core_free_priv(dh_dev); + devlink_free(devlink); + pci_set_drvdata(pdev, NULL); +} + +static void dh_pf_shutdown(struct pci_dev *pdev) +{ + if (system_state == SYSTEM_POWER_OFF) + pci_set_power_state(pdev, PCI_D3hot); + pci_disable_device(pdev); +} + +static struct pci_driver dh_pf_driver = { + .name = "dinghai10e", + .id_table = dh_pf_pci_table, + .probe = dh_pf_probe, + .remove = dh_pf_remove, + .shutdown = dh_pf_shutdown, +}; + +module_pci_driver(dh_pf_driver); diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.h b/drivers/net/ethernet/zte/dinghai/en_pf.h new file mode 100644 index 000000000000..87fa29b2d13d --- /dev/null +++ b/drivers/net/ethernet/zte/dinghai/en_pf.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * ZTE DingHai Ethernet driver - PF header + * Copyright (c) 2022-2026, ZTE Corporation. + */ + +#ifndef __ZXDH_EN_PF_H__ +#define __ZXDH_EN_PF_H__ + +#include +#include +#include +#include +#include + +#define ZXDH_PF_VENDOR_ID 0x1cf2 +#define ZXDH_PF_DEVICE_ID 0x8040 +#define ZXDH_VF_DEVICE_ID 0x8041 + +enum dh_coredev_type { + DH_COREDEV_PF, + DH_COREDEV_VF, + DH_COREDEV_SF, + DH_COREDEV_MPF +}; + +struct devlink; + +struct dh_core_dev { + struct device *device; + enum dh_coredev_type coredev_type; + struct pci_dev *pdev; + struct devlink *devlink; + struct mutex lock; /* Protects device configuration */ + void *priv; +}; + +struct zxdh_pf_device { + void __iomem *pci_ioremap_addr[6]; + bool bar_chan_valid; + bool vepa; + struct mutex irq_lock; /* Protects IRQ operations */ +}; + +#define GET_COREDEV_TYPE(pdev) \ + ((pdev)->device == ZXDH_VF_DEVICE_ID ? DH_COREDEV_VF : DH_COREDEV_PF) + +void *dh_core_alloc_priv(struct dh_core_dev *dh_dev, size_t size); +void dh_core_free_priv(struct dh_core_dev *dh_dev); +void dh_pf_pci_close(struct dh_core_dev *dev); + +#endif /* __ZXDH_EN_PF_H__ */ -- 2.27.0