| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/13 19:30 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"NET_VENDOR_ZTE",
"DINGHAI",
"DINGHAI_PF"
],
"FocusSymbols": [
"dh_pf_probe",
"dh_pf_remove",
"dh_pf_pci_init",
"dh_pf_pci_close"
],
"Reasoning": "The patch introduces a new PCI driver for ZTE DingHai Ethernet devices. The driver registers a PCI probe function which initializes the device, maps PCI memory, and registers a devlink instance. This code is reachable via the PCI subsystem and can be fuzzed using virtual PCI device injection.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/13 19:30 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit b9dba71a3aae353c54644b0ff4e4e82ceed56ffa\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jul 13 19:30:36 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 2fb1c75afd1638..73692b09bf7bab 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -29440,6 +29440,12 @@ S:\tMaintained\n T:\tgit git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git\n F:\tsound/hda/codecs/senarytech.c\n \n+ZTE DINGHAI ETHERNET DRIVER\n+M:\tJunyang Han \u003chan.junyang@zte.com.cn\u003e\n+L:\tnetdev@vger.kernel.org\n+S:\tMaintained\n+F:\tdrivers/net/ethernet/zte/\n+\n THE REST\n M:\tLinus Torvalds \u003ctorvalds@linux-foundation.org\u003e\n L:\tlinux-kernel@vger.kernel.org\ndiff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig\nindex b8f70e2a1763ad..c2b6996b0cfe1b 100644\n--- a/drivers/net/ethernet/Kconfig\n+++ b/drivers/net/ethernet/Kconfig\n@@ -188,5 +188,6 @@ source \"drivers/net/ethernet/wangxun/Kconfig\"\n source \"drivers/net/ethernet/wiznet/Kconfig\"\n source \"drivers/net/ethernet/xilinx/Kconfig\"\n source \"drivers/net/ethernet/xircom/Kconfig\"\n+source \"drivers/net/ethernet/zte/Kconfig\"\n \n endif # ETHERNET\ndiff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile\nindex 57344fec6ce047..a34bcbd4df4e92 100644\n--- a/drivers/net/ethernet/Makefile\n+++ b/drivers/net/ethernet/Makefile\n@@ -104,3 +104,4 @@ obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/\n obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/\n obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/\n obj-$(CONFIG_OA_TC6) += oa_tc6.o\n+obj-$(CONFIG_NET_VENDOR_ZTE) += zte/\ndiff --git a/drivers/net/ethernet/zte/Kconfig b/drivers/net/ethernet/zte/Kconfig\nnew file mode 100644\nindex 00000000000000..b95c2fc7db77a2\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/Kconfig\n@@ -0,0 +1,20 @@\n+# SPDX-License-Identifier: GPL-2.0-only\n+#\n+# ZTE driver configuration\n+#\n+\n+config NET_VENDOR_ZTE\n+ bool \"ZTE devices\"\n+ default y\n+ help\n+ If you have a network (Ethernet) card belonging to this class, say Y.\n+ Note that the answer to this question doesn't directly affect the\n+ kernel: saying N will just cause the configurator to skip all\n+ the questions about Zte cards. If you say Y, you will be asked\n+ for your specific card in the following questions.\n+\n+if NET_VENDOR_ZTE\n+\n+source \"drivers/net/ethernet/zte/dinghai/Kconfig\"\n+\n+endif # NET_VENDOR_ZTE\ndiff --git a/drivers/net/ethernet/zte/Makefile b/drivers/net/ethernet/zte/Makefile\nnew file mode 100644\nindex 00000000000000..cd9929b61559c6\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/Makefile\n@@ -0,0 +1,6 @@\n+# SPDX-License-Identifier: GPL-2.0-only\n+#\n+# Makefile for the ZTE device drivers\n+#\n+\n+obj-$(CONFIG_DINGHAI) += dinghai/\ndiff --git a/drivers/net/ethernet/zte/dinghai/Kconfig b/drivers/net/ethernet/zte/dinghai/Kconfig\nnew file mode 100644\nindex 00000000000000..121be3bf7707fd\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/dinghai/Kconfig\n@@ -0,0 +1,34 @@\n+# SPDX-License-Identifier: GPL-2.0-only\n+#\n+# ZTE DingHai Ethernet driver configuration\n+#\n+\n+config DINGHAI\n+ bool \"ZTE DingHai Ethernet driver\"\n+ depends on PCI\n+ select NET_DEVLINK\n+ help\n+ This driver supports ZTE DingHai Ethernet devices.\n+\n+ DingHai is a high-performance Ethernet controller that supports\n+ multiple features including hardware offloading, SR-IOV, and\n+ advanced virtualization capabilities.\n+\n+ If you say Y here, you can select specific driver variants below.\n+\n+ If unsure, say N.\n+\n+if DINGHAI\n+\n+config DINGHAI_PF\n+ tristate \"ZTE DingHai PF (Physical Function) driver\"\n+ help\n+ This driver supports ZTE DingHai PCI Express Ethernet\n+ adapters (PF).\n+\n+ To compile this driver as a module, choose M here. The module\n+ will be named dinghai10e.\n+\n+ If unsure, say N.\n+\n+endif # DINGHAI\ndiff --git a/drivers/net/ethernet/zte/dinghai/Makefile b/drivers/net/ethernet/zte/dinghai/Makefile\nnew file mode 100644\nindex 00000000000000..f55a8de518beb3\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/dinghai/Makefile\n@@ -0,0 +1,10 @@\n+# SPDX-License-Identifier: GPL-2.0-only\n+#\n+# Makefile for ZTE DingHai Ethernet driver\n+#\n+\n+ccflags-y += -I$(src)\n+\n+obj-$(CONFIG_DINGHAI_PF) += dinghai10e.o\n+dinghai10e-y := en_pf.o\n+\ndiff --git a/drivers/net/ethernet/zte/dinghai/dh_queue.h b/drivers/net/ethernet/zte/dinghai/dh_queue.h\nnew file mode 100644\nindex 00000000000000..5067c73fed33cc\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/dinghai/dh_queue.h\n@@ -0,0 +1,71 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/*\n+ * ZTE DingHai Ethernet driver - PCI capability definitions\n+ * Copyright (c) 2022-2026, ZTE Corporation.\n+ */\n+\n+#ifndef __DH_QUEUE_H__\n+#define __DH_QUEUE_H__\n+\n+/* Vector value used to disable MSI for queue */\n+#define ZXDH_MSI_NO_VECTOR 0xff\n+\n+/* Status byte for guest to report progress, and synchronize features */\n+/* We have seen device and processed generic fields */\n+#define ZXDH_CONFIG_S_ACKNOWLEDGE 1\n+/* We have found a driver for the device. */\n+#define ZXDH_CONFIG_S_DRIVER 2\n+/* Driver has used its parts of the config, and is happy */\n+#define ZXDH_CONFIG_S_DRIVER_OK 4\n+/* Driver has finished configuring features */\n+#define ZXDH_CONFIG_S_FEATURES_OK 8\n+/* Device entered invalid state, driver must reset it */\n+#define ZXDH_CONFIG_S_NEEDS_RESET 0x40\n+/* We've given up on this device */\n+#define ZXDH_CONFIG_S_FAILED 0x80\n+\n+/* This is the PCI capability header: */\n+struct zxdh_pf_pci_cap {\n+\t__u8 cap_vndr;\t\t/* Generic PCI field: PCI_CAP_ID_VNDR */\n+\t__u8 cap_next;\t\t/* Generic PCI field: next ptr. */\n+\t__u8 cap_len;\t\t/* Generic PCI field: capability length */\n+\t__u8 cfg_type;\t\t/* Identifies the structure. */\n+\t__u8 bar;\t\t/* Where to find it. */\n+\t__u8 id;\t\t/* Multiple capabilities of the same type */\n+\t__u8 padding[2];\t\t/* Pad to full dword. */\n+\t__le32 offset;\t\t/* Offset within bar. */\n+\t__le32 length;\t\t/* Length of the structure, in bytes. */\n+};\n+\n+/* Fields in ZXDH_PF_PCI_CAP_COMMON_CFG: */\n+struct zxdh_pf_pci_common_cfg {\n+\t/* About the whole device. */\n+\t__le32 device_feature_select; /* read-write */\n+\t__le32 device_feature;\t/* read-only */\n+\t__le32 guest_feature_select; /* read-write */\n+\t__le32 guest_feature;\t\t/* read-write */\n+\t__le16 msix_config;\t\t/* read-write */\n+\t__le16 num_queues;\t\t/* read-only */\n+\t__u8 device_status;\t\t/* read-write */\n+\t__u8 config_generation;\t/* read-only */\n+\n+\t/* About a specific virtqueue. */\n+\t__le16 queue_select;\t\t/* read-write */\n+\t__le16 queue_size;\t\t/* read-write, power of 2. */\n+\t__le16 queue_msix_vector;\t/* read-write */\n+\t__le16 queue_enable;\t\t/* read-write */\n+\t__le16 queue_notify_off;\t/* read-only */\n+\t__le32 queue_desc_lo;\t\t/* read-write */\n+\t__le32 queue_desc_hi;\t\t/* read-write */\n+\t__le32 queue_avail_lo;\t\t/* read-write */\n+\t__le32 queue_avail_hi;\t\t/* read-write */\n+\t__le32 queue_used_lo;\t\t/* read-write */\n+\t__le32 queue_used_hi;\t\t/* read-write */\n+};\n+\n+struct zxdh_pf_pci_notify_cap {\n+\tstruct zxdh_pf_pci_cap cap;\n+\t__le32 notify_off_multiplier; /* Multiplier for queue_notify_off. */\n+};\n+\n+#endif /* __DH_QUEUE_H__ */\ndiff --git a/drivers/net/ethernet/zte/dinghai/en_pf.c b/drivers/net/ethernet/zte/dinghai/en_pf.c\nnew file mode 100644\nindex 00000000000000..f859fd472a86fd\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c\n@@ -0,0 +1,642 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * ZTE DingHai Ethernet driver\n+ * Copyright (c) 2022-2026, ZTE Corporation.\n+ */\n+\n+#include \u003clinux/module.h\u003e\n+#include \u003clinux/pci.h\u003e\n+#include \u003cnet/devlink.h\u003e\n+#include \u003clinux/dma-mapping.h\u003e\n+#include \u003clinux/etherdevice.h\u003e\n+#include \"en_pf.h\"\n+#include \"dh_queue.h\"\n+\n+MODULE_AUTHOR(\"Junyang Han \u003chan.junyang@zte.com.cn\u003e\");\n+MODULE_DESCRIPTION(\"ZTE DingHai series Ethernet driver\");\n+MODULE_LICENSE(\"GPL\");\n+\n+static const struct devlink_ops dh_pf_devlink_ops = {};\n+\n+static const struct pci_device_id dh_pf_pci_table[] = {\n+\t{ PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_PF_DEVICE_ID) },\n+\t{ PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_VF_DEVICE_ID) },\n+\t{ }\n+};\n+\n+MODULE_DEVICE_TABLE(pci, dh_pf_pci_table);\n+\n+void *dh_core_alloc_priv(struct dh_core_dev *dh_dev, size_t size)\n+{\n+\tvoid *priv = kzalloc(size, GFP_KERNEL);\n+\n+\tif (priv)\n+\t\tdh_dev-\u003epriv = priv;\n+\treturn priv;\n+}\n+\n+void dh_core_free_priv(struct dh_core_dev *dh_dev)\n+{\n+\tkfree(dh_dev-\u003epriv);\n+}\n+\n+static int dh_pf_pci_init(struct dh_core_dev *dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dev-\u003epriv;\n+\tint ret;\n+\n+\tpci_set_drvdata(dev-\u003epdev, dev);\n+\n+\tret = pci_enable_device(dev-\u003epdev);\n+\tif (ret) {\n+\t\tdev_err(dev-\u003edevice, \"pci_enable_device failed: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = dma_set_mask_and_coherent(dev-\u003edevice, DMA_BIT_MASK(64));\n+\tif (ret) {\n+\t\tret = dma_set_mask_and_coherent(dev-\u003edevice, DMA_BIT_MASK(32));\n+\t\tif (ret) {\n+\t\t\tdev_err(dev-\u003edevice, \"dma_set_mask_and_coherent failed: %d\\n\", ret);\n+\t\t\tgoto err_pci;\n+\t\t}\n+\t}\n+\n+\tret = pci_request_selected_regions(dev-\u003epdev,\n+\t\t\t\t\t pci_select_bars(dev-\u003epdev, IORESOURCE_MEM),\n+\t\t\t\t\t \"dh-pf\");\n+\tif (ret) {\n+\t\tdev_err(dev-\u003edevice, \"pci_request_selected_regions failed: %d\\n\", ret);\n+\t\tgoto err_pci;\n+\t}\n+\n+\tpci_set_master(dev-\u003epdev);\n+\tret = pci_save_state(dev-\u003epdev);\n+\tif (ret) {\n+\t\tdev_err(dev-\u003edevice, \"pci_save_state failed: %d\\n\", ret);\n+\t\tgoto err_pci_save_state;\n+\t}\n+\n+\tif (!(pci_resource_flags(dev-\u003epdev, 0) \u0026 IORESOURCE_MEM)) {\n+\t\tret = -ENODEV;\n+\t\tdev_err(dev-\u003edevice, \"BAR 0 is not an MMIO resource\\n\");\n+\t\tgoto err_pci_save_state;\n+\t}\n+\n+\tpf_dev-\u003epci_ioremap_addr[0] =\n+\t\tioremap(pci_resource_start(dev-\u003epdev, 0),\n+\t\t\tpci_resource_len(dev-\u003epdev, 0));\n+\tif (!pf_dev-\u003epci_ioremap_addr[0]) {\n+\t\tret = -ENOMEM;\n+\t\tdev_err(dev-\u003edevice, \"dh pf pci ioremap failed\\n\");\n+\t\tgoto err_pci_save_state;\n+\t}\n+\n+\treturn 0;\n+\n+err_pci_save_state:\n+\tpci_release_selected_regions(dev-\u003epdev,\n+\t\t\t\t pci_select_bars(dev-\u003epdev, IORESOURCE_MEM));\n+err_pci:\n+\tpci_disable_device(dev-\u003epdev);\n+\treturn ret;\n+}\n+\n+void dh_pf_pci_close(struct dh_core_dev *dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dev-\u003epriv;\n+\n+\tiounmap(pf_dev-\u003epci_ioremap_addr[0]);\n+\tpci_release_selected_regions(dev-\u003epdev,\n+\t\t\t\t pci_select_bars(dev-\u003epdev, IORESOURCE_MEM));\n+\tpci_disable_device(dev-\u003epdev);\n+}\n+\n+int zxdh_pf_pci_find_capability(struct pci_dev *pdev, u8 cfg_type,\n+\t\t\t\tu32 ioresource_types, int *bars)\n+{\n+\tint pos;\n+\tu8 type;\n+\tu8 bar;\n+\n+\tfor (pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR); pos \u003e 0;\n+\t pos = pci_find_next_capability(pdev, pos, PCI_CAP_ID_VNDR)) {\n+\t\tpci_read_config_byte(pdev,\n+\t\t\t\t pos + offsetof(struct zxdh_pf_pci_cap,\n+\t\t\t\t\t\t\tcfg_type), \u0026type);\n+\t\tpci_read_config_byte(pdev,\n+\t\t\t\t pos + offsetof(struct zxdh_pf_pci_cap, bar), \u0026bar);\n+\n+\t\t/* ignore structures with reserved BAR values */\n+\t\tif (bar \u003e ZXDH_PF_MAX_BAR_VAL)\n+\t\t\tcontinue;\n+\n+\t\tif (type == cfg_type) {\n+\t\t\tif (pci_resource_len(pdev, bar) \u0026\u0026\n+\t\t\t pci_resource_flags(pdev, bar) \u0026 ioresource_types) {\n+\t\t\t\t*bars |= (1 \u003c\u003c bar);\n+\t\t\t\treturn pos;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void __iomem *zxdh_pf_map_capability(struct dh_core_dev *dh_dev, int off,\n+\t\t\t\t size_t minlen, u32 align,\n+\t\t\t\t u32 start, u32 size,\n+\t\t\t\t size_t *len, resource_size_t *pa,\n+\t\t\t\t u32 *bar_off)\n+{\n+\tstruct pci_dev *pdev = dh_dev-\u003epdev;\n+\tvoid __iomem *p;\n+\tu32 offset;\n+\tu32 length;\n+\tu8 bar;\n+\n+\tpci_read_config_byte(pdev,\n+\t\t\t off + offsetof(struct zxdh_pf_pci_cap, bar), \u0026bar);\n+\tpci_read_config_dword(pdev,\n+\t\t\t off + offsetof(struct zxdh_pf_pci_cap,\n+\t\t\t\t\t\toffset), \u0026offset);\n+\tpci_read_config_dword(pdev,\n+\t\t\t off + offsetof(struct zxdh_pf_pci_cap,\n+\t\t\t\t\t\tlength), \u0026length);\n+\n+\tif (bar_off)\n+\t\t*bar_off = offset;\n+\n+\tif (length \u003c= start) {\n+\t\tdev_err(dh_dev-\u003edevice, \"bad capability len %u (\u003e%u expected)\\n\",\n+\t\t\tlength, start);\n+\t\treturn NULL;\n+\t}\n+\n+\tif (length - start \u003c minlen) {\n+\t\tdev_err(dh_dev-\u003edevice, \"bad capability len %u (\u003e=%zu expected)\\n\",\n+\t\t\tlength, minlen);\n+\t\treturn NULL;\n+\t}\n+\n+\tlength -= start;\n+\tif (start + offset \u003c offset) {\n+\t\tdev_err(dh_dev-\u003edevice, \"map wrap-around %u+%u\\n\", start, offset);\n+\t\treturn NULL;\n+\t}\n+\n+\toffset += start;\n+\tif (offset \u0026 (align - 1)) {\n+\t\tdev_err(dh_dev-\u003edevice, \"offset %u not aligned to %u\\n\", offset, align);\n+\t\treturn NULL;\n+\t}\n+\n+\tif (length \u003e size)\n+\t\tlength = size;\n+\n+\tif (len)\n+\t\t*len = length;\n+\n+\tif (minlen + offset \u003c minlen ||\n+\t minlen + offset \u003e pci_resource_len(pdev, bar)) {\n+\t\tdev_err(dh_dev-\u003edevice,\n+\t\t\t\"map custom queue %zu@%u out of range on bar %u length %lu\\n\",\n+\t\t\tminlen, offset, bar,\n+\t\t\t(unsigned long)pci_resource_len(pdev, bar));\n+\t\treturn NULL;\n+\t}\n+\n+\tp = pci_iomap_range(pdev, bar, offset, length);\n+\tif (!p) {\n+\t\tdev_err(dh_dev-\u003edevice, \"unable to map custom queue %u@%u on bar %u\\n\",\n+\t\t\tlength, offset, bar);\n+\t} else if (pa) {\n+\t\t*pa = pci_resource_start(pdev, bar) + offset;\n+\t}\n+\n+\treturn p;\n+}\n+\n+int zxdh_pf_common_cfg_init(struct dh_core_dev *dh_dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = dh_dev-\u003epdev;\n+\tint common;\n+\n+\t/* check for a common config: if not, use legacy mode (bar 0). */\n+\tcommon = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_COMMON_CFG,\n+\t\t\t\t\t IORESOURCE_IO | IORESOURCE_MEM,\n+\t\t\t\t\t \u0026pf_dev-\u003emodern_bars);\n+\tif (!common) {\n+\t\tdev_err(dh_dev-\u003edevice,\n+\t\t\t\"missing capabilities, leaving for legacy driver\\n\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\tpf_dev-\u003ecommon = zxdh_pf_map_capability(dh_dev, common,\n+\t\t\t\t\t\tsizeof(struct zxdh_pf_pci_common_cfg),\n+\t\t\t\t\t\tZXDH_PF_ALIGN4, 0,\n+\t\t\t\t\t\tsizeof(struct zxdh_pf_pci_common_cfg),\n+\t\t\t\t\t\tNULL, NULL, NULL);\n+\tif (!pf_dev-\u003ecommon) {\n+\t\tdev_err(dh_dev-\u003edevice, \"pf_dev-\u003ecommon is null\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int zxdh_pf_notify_cfg_init(struct dh_core_dev *dh_dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = dh_dev-\u003epdev;\n+\tu32 notify_length;\n+\tu32 notify_offset;\n+\tint notify;\n+\n+\t/* If common is there, these should be too... */\n+\tnotify = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_NOTIFY_CFG,\n+\t\t\t\t\t IORESOURCE_IO | IORESOURCE_MEM,\n+\t\t\t\t\t \u0026pf_dev-\u003emodern_bars);\n+\tif (!notify) {\n+\t\tdev_err(dh_dev-\u003edevice, \"missing notify cfg capability\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tpci_read_config_dword(pdev,\n+\t\t\t notify + offsetof(struct zxdh_pf_pci_notify_cap,\n+\t\t\t\tnotify_off_multiplier),\n+\t\t\u0026pf_dev-\u003enotify_offset_multiplier);\n+\tpci_read_config_dword(pdev,\n+\t\t\t notify + offsetof(struct zxdh_pf_pci_notify_cap,\n+\t\t\t\tcap.length), \u0026notify_length);\n+\tpci_read_config_dword(pdev,\n+\t\t\t notify + offsetof(struct zxdh_pf_pci_notify_cap,\n+\t\t\t\tcap.offset), \u0026notify_offset);\n+\n+\t/* We don't know how many VQs we'll map, ahead of the time.\n+\t * If notify length is small, map it all now. Otherwise,\n+\t * map each VQ individually later.\n+\t */\n+\tif (notify_length + (notify_offset % PAGE_SIZE) \u003c= PAGE_SIZE) {\n+\t\tpf_dev-\u003enotify_base = zxdh_pf_map_capability(dh_dev, notify,\n+\t\t\t\t\t\t\t ZXDH_PF_MAP_MINLEN2,\n+\t\t\t\t\t\t\t ZXDH_PF_ALIGN2, 0,\n+\t\t\t\t\t\t\t notify_length,\n+\t\t\t\t\t\t\t \u0026pf_dev-\u003enotify_len,\n+\t\t\t\t\t\t\t \u0026pf_dev-\u003enotify_pa, NULL);\n+\t\tif (!pf_dev-\u003enotify_base) {\n+\t\t\tdev_err(dh_dev-\u003edevice, \"pf_dev-\u003enotify_base is null\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t} else {\n+\t\tpf_dev-\u003enotify_map_cap = notify;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int zxdh_pf_device_cfg_init(struct dh_core_dev *dh_dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = dh_dev-\u003epdev;\n+\tint device;\n+\n+\t/* Device capability is only mandatory for\n+\t * devices that have device-specific configuration.\n+\t */\n+\tdevice = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_DEVICE_CFG,\n+\t\t\t\t\t IORESOURCE_IO | IORESOURCE_MEM,\n+\t\t\t\t\t \u0026pf_dev-\u003emodern_bars);\n+\n+\t/* we don't know how much we should map,\n+\t * but PAGE_SIZE is more than enough for all existing devices.\n+\t */\n+\tif (device) {\n+\t\tpf_dev-\u003edevice = zxdh_pf_map_capability(dh_dev, device, 0,\n+\t\t\t\t\t\t\tZXDH_PF_ALIGN4, 0, PAGE_SIZE,\n+\t\t\t\t\t\t \u0026pf_dev-\u003edevice_len, NULL,\n+\t\t\t\t\t\t \u0026pf_dev-\u003edev_cfg_bar_off);\n+\t\tif (!pf_dev-\u003edevice) {\n+\t\t\tdev_err(dh_dev-\u003edevice, \"pf_dev-\u003edevice is null\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+void zxdh_pf_modern_cfg_uninit(struct dh_core_dev *dh_dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = dh_dev-\u003epdev;\n+\n+\tif (pf_dev-\u003edevice)\n+\t\tpci_iounmap(pdev, pf_dev-\u003edevice);\n+\tif (pf_dev-\u003enotify_base)\n+\t\tpci_iounmap(pdev, pf_dev-\u003enotify_base);\n+\tpci_iounmap(pdev, pf_dev-\u003ecommon);\n+}\n+\n+int zxdh_pf_modern_cfg_init(struct dh_core_dev *dh_dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = dh_dev-\u003epdev;\n+\tint ret;\n+\n+\tret = zxdh_pf_common_cfg_init(dh_dev);\n+\tif (ret) {\n+\t\tdev_err(dh_dev-\u003edevice, \"zxdh_pf_common_cfg_init failed: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = zxdh_pf_notify_cfg_init(dh_dev);\n+\tif (ret) {\n+\t\tdev_err(dh_dev-\u003edevice, \"zxdh_pf_notify_cfg_init failed: %d\\n\", ret);\n+\t\tgoto err_map_notify;\n+\t}\n+\n+\tret = zxdh_pf_device_cfg_init(dh_dev);\n+\tif (ret) {\n+\t\tdev_err(dh_dev-\u003edevice, \"zxdh_pf_device_cfg_init failed: %d\\n\", ret);\n+\t\tgoto err_map_device;\n+\t}\n+\n+\treturn 0;\n+\n+err_map_device:\n+\tif (pf_dev-\u003enotify_base)\n+\t\tpci_iounmap(pdev, pf_dev-\u003enotify_base);\n+err_map_notify:\n+\tpci_iounmap(pdev, pf_dev-\u003ecommon);\n+\treturn ret;\n+}\n+\n+u16 zxdh_pf_get_queue_notify_off(struct dh_core_dev *dh_dev,\n+\t\t\t\t u16 phy_index, u16 index)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\n+\tif (pf_dev-\u003epacked_status)\n+\t\tiowrite16(phy_index, \u0026pf_dev-\u003ecommon-\u003equeue_select);\n+\telse\n+\t\tiowrite16(index, \u0026pf_dev-\u003ecommon-\u003equeue_select);\n+\n+\treturn ioread16(\u0026pf_dev-\u003ecommon-\u003equeue_notify_off);\n+}\n+\n+void __iomem *zxdh_pf_map_vq_notify(struct dh_core_dev *dh_dev,\n+\t\t\t\t u16 phy_index, u16 index,\n+\t\t\t\t resource_size_t *pa)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tu16 off;\n+\n+\toff = zxdh_pf_get_queue_notify_off(dh_dev, phy_index, index);\n+\n+\tif (pf_dev-\u003enotify_base) {\n+\t\t/* offset should not wrap */\n+\t\tif ((u64)off *\n+\t\t\tpf_dev-\u003enotify_offset_multiplier + 2 \u003e pf_dev-\u003enotify_len) {\n+\t\t\tdev_err(dh_dev-\u003edevice,\n+\t\t\t\t\"bad notification offset %u (x %u) for queue %u \u003e %zu\\n\",\n+\t\t\t\toff, pf_dev-\u003enotify_offset_multiplier, phy_index,\n+\t\t\t\tpf_dev-\u003enotify_len);\n+\t\t\treturn NULL;\n+\t\t}\n+\n+\t\tif (pa)\n+\t\t\t*pa = pf_dev-\u003enotify_pa + off * pf_dev-\u003enotify_offset_multiplier;\n+\n+\t\treturn pf_dev-\u003enotify_base + off * pf_dev-\u003enotify_offset_multiplier;\n+\t} else {\n+\t\treturn zxdh_pf_map_capability(dh_dev, pf_dev-\u003enotify_map_cap, 2, 2,\n+\t\t\t\t\t off * pf_dev-\u003enotify_offset_multiplier,\n+\t\t\t\t\t 2, NULL, pa, NULL);\n+\t}\n+}\n+\n+void zxdh_pf_unmap_vq_notify(struct dh_core_dev *dh_dev, void __iomem *priv)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\n+\tif (!pf_dev-\u003enotify_base)\n+\t\tpci_iounmap(dh_dev-\u003epdev, priv);\n+}\n+\n+void zxdh_pf_set_status(struct dh_core_dev *dh_dev, u8 status)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\n+\tiowrite8(status, \u0026pf_dev-\u003ecommon-\u003edevice_status);\n+}\n+\n+u8 zxdh_pf_get_status(struct dh_core_dev *dh_dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\n+\treturn ioread8(\u0026pf_dev-\u003ecommon-\u003edevice_status);\n+}\n+\n+u8 zxdh_pf_get_cfg_gen(struct dh_core_dev *dh_dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tu8 config_generation;\n+\n+\tconfig_generation = ioread8(\u0026pf_dev-\u003ecommon-\u003econfig_generation);\n+\n+\treturn config_generation;\n+}\n+\n+void zxdh_pf_get_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tu32 DEV_MAC_L;\n+\tu16 DEV_MAC_H;\n+\n+\teth_zero_addr(mac);\n+\n+\tif (pf_dev-\u003epf_sriov_cap_base) {\n+\t\tDEV_MAC_L = ioread32(pf_dev-\u003epf_sriov_cap_base +\n+\t\t\t\t (pf_dev-\u003esriov_bar_size) * vf_id +\n+\t\t\t\t pf_dev-\u003edev_cfg_bar_off);\n+\t\tmac[0] = DEV_MAC_L \u0026 0xff;\n+\t\tmac[1] = (DEV_MAC_L \u003e\u003e 8) \u0026 0xff;\n+\t\tmac[2] = (DEV_MAC_L \u003e\u003e 16) \u0026 0xff;\n+\t\tmac[3] = (DEV_MAC_L \u003e\u003e 24) \u0026 0xff;\n+\t\tDEV_MAC_H = ioread16(pf_dev-\u003epf_sriov_cap_base +\n+\t\t\t\t (pf_dev-\u003esriov_bar_size) * vf_id +\n+\t\t\t\t pf_dev-\u003edev_cfg_bar_off +\n+\t\t\t\t ZXDH_DEV_MAC_HIGH_OFFSET);\n+\t\tmac[4] = DEV_MAC_H \u0026 0xff;\n+\t\tmac[5] = (DEV_MAC_H \u003e\u003e 8) \u0026 0xff;\n+\t}\n+}\n+\n+void zxdh_pf_set_vf_mac_reg(struct zxdh_pf_device *pf_dev,\n+\t\t\t u8 *mac, int vf_id)\n+{\n+\tu32 DEV_MAC_L;\n+\tu16 DEV_MAC_H;\n+\n+\tif (pf_dev-\u003epf_sriov_cap_base) {\n+\t\tDEV_MAC_L = mac[0] | (mac[1] \u003c\u003c 8) |\n+\t\t\t\t\t(mac[2] \u003c\u003c 16) | (mac[3] \u003c\u003c 24);\n+\t\tDEV_MAC_H = mac[4] | (mac[5] \u003c\u003c 8);\n+\t\tiowrite32(DEV_MAC_L, (pf_dev-\u003epf_sriov_cap_base +\n+\t\t\t (pf_dev-\u003esriov_bar_size) * vf_id +\n+\t\t\t pf_dev-\u003edev_cfg_bar_off));\n+\t\tiowrite16(DEV_MAC_H, (pf_dev-\u003epf_sriov_cap_base +\n+\t\t\t (pf_dev-\u003esriov_bar_size) * vf_id +\n+\t\t\t pf_dev-\u003edev_cfg_bar_off +\n+\t\t\t ZXDH_DEV_MAC_HIGH_OFFSET));\n+\t}\n+}\n+\n+void zxdh_pf_set_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\n+\tzxdh_pf_set_vf_mac_reg(pf_dev, mac, vf_id);\n+}\n+\n+void zxdh_set_mac(struct dh_core_dev *dh_dev, u8 *mac)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tu32 DEV_MAC_L;\n+\tu16 DEV_MAC_H;\n+\n+\tif (!pf_dev-\u003edevice)\n+\t\treturn;\n+\n+\tDEV_MAC_L = mac[0] | (mac[1] \u003c\u003c 8) | (mac[2] \u003c\u003c 16) | (mac[3] \u003c\u003c 24);\n+\tDEV_MAC_H = mac[4] | (mac[5] \u003c\u003c 8);\n+\tiowrite32(DEV_MAC_L, pf_dev-\u003edevice);\n+\tiowrite16(DEV_MAC_H, pf_dev-\u003edevice + ZXDH_DEV_MAC_HIGH_OFFSET);\n+}\n+\n+void zxdh_get_mac(struct dh_core_dev *dh_dev, u8 *mac)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tu32 DEV_MAC_L;\n+\tu16 DEV_MAC_H;\n+\n+\tif (!pf_dev-\u003edevice)\n+\t\treturn;\n+\n+\tDEV_MAC_L = ioread32(pf_dev-\u003edevice);\n+\tmac[0] = DEV_MAC_L \u0026 0xff;\n+\tmac[1] = (DEV_MAC_L \u003e\u003e 8) \u0026 0xff;\n+\tmac[2] = (DEV_MAC_L \u003e\u003e 16) \u0026 0xff;\n+\tmac[3] = (DEV_MAC_L \u003e\u003e 24) \u0026 0xff;\n+\tDEV_MAC_H = ioread16(pf_dev-\u003edevice + ZXDH_DEV_MAC_HIGH_OFFSET);\n+\tmac[4] = DEV_MAC_H \u0026 0xff;\n+\tmac[5] = (DEV_MAC_H \u003e\u003e 8) \u0026 0xff;\n+}\n+\n+u64 zxdh_pf_get_features(struct dh_core_dev *dh_dev)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\tu64 device_feature;\n+\n+\tiowrite32(0, \u0026pf_dev-\u003ecommon-\u003edevice_feature_select);\n+\tdevice_feature = ioread32(\u0026pf_dev-\u003ecommon-\u003edevice_feature);\n+\tiowrite32(1, \u0026pf_dev-\u003ecommon-\u003edevice_feature_select);\n+\tdevice_feature |= ((u64)ioread32(\u0026pf_dev-\u003ecommon-\u003edevice_feature)\n+\t\t\t\t\t\t\u003c\u003c 32);\n+\n+\treturn device_feature;\n+}\n+\n+void zxdh_pf_set_features(struct dh_core_dev *dh_dev, u64 features)\n+{\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\n+\tiowrite32(0, \u0026pf_dev-\u003ecommon-\u003eguest_feature_select);\n+\tiowrite32((u32)features, \u0026pf_dev-\u003ecommon-\u003eguest_feature);\n+\tiowrite32(1, \u0026pf_dev-\u003ecommon-\u003eguest_feature_select);\n+\tiowrite32(features \u003e\u003e 32, \u0026pf_dev-\u003ecommon-\u003eguest_feature);\n+}\n+\n+static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n+{\n+\tstruct zxdh_pf_device *pf_dev;\n+\tstruct dh_core_dev *dh_dev;\n+\tstruct devlink *devlink;\n+\tint ret;\n+\n+\tdevlink = devlink_alloc(\u0026dh_pf_devlink_ops, sizeof(struct dh_core_dev),\n+\t\t\t\t\u0026pdev-\u003edev);\n+\tif (!devlink) {\n+\t\tdev_err(\u0026pdev-\u003edev, \"dh_pf devlink alloc failed\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tdh_dev = devlink_priv(devlink);\n+\tdh_dev-\u003edevice = \u0026pdev-\u003edev;\n+\tdh_dev-\u003epdev = pdev;\n+\tdh_dev-\u003edevlink = devlink;\n+\n+\tpf_dev = dh_core_alloc_priv(dh_dev, sizeof(*pf_dev));\n+\tif (!pf_dev) {\n+\t\tdev_err(\u0026pdev-\u003edev, \"dh_pf_dev alloc failed\\n\");\n+\t\tret = -ENOMEM;\n+\t\tgoto err_pf_dev;\n+\t}\n+\n+\tpf_dev-\u003ebar_chan_valid = false;\n+\tpf_dev-\u003evepa = false;\n+\tmutex_init(\u0026dh_dev-\u003elock);\n+\tmutex_init(\u0026pf_dev-\u003eirq_lock);\n+\n+\tdh_dev-\u003ecoredev_type = GET_COREDEV_TYPE(pdev);\n+\n+\tret = dh_pf_pci_init(dh_dev);\n+\tif (ret) {\n+\t\tdev_err(\u0026pdev-\u003edev, \"dh_pf_pci_init failed: %d\\n\", ret);\n+\t\tgoto err_cfg_init;\n+\t}\n+\n+\tdevlink_register(devlink);\n+\n+\treturn 0;\n+\n+err_cfg_init:\n+\tmutex_destroy(\u0026pf_dev-\u003eirq_lock);\n+\tmutex_destroy(\u0026dh_dev-\u003elock);\n+\tdh_core_free_priv(dh_dev);\n+err_pf_dev:\n+\tdevlink_free(devlink);\n+\treturn ret;\n+}\n+\n+static void dh_pf_remove(struct pci_dev *pdev)\n+{\n+\tstruct dh_core_dev *dh_dev = pci_get_drvdata(pdev);\n+\tstruct devlink *devlink = priv_to_devlink(dh_dev);\n+\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n+\n+\tdevlink_unregister(devlink);\n+\tdh_pf_pci_close(dh_dev);\n+\tmutex_destroy(\u0026pf_dev-\u003eirq_lock);\n+\tmutex_destroy(\u0026dh_dev-\u003elock);\n+\tdh_core_free_priv(dh_dev);\n+\tdevlink_free(devlink);\n+\tpci_set_drvdata(pdev, NULL);\n+}\n+\n+static void dh_pf_shutdown(struct pci_dev *pdev)\n+{\n+\tif (system_state == SYSTEM_POWER_OFF)\n+\t\tpci_set_power_state(pdev, PCI_D3hot);\n+\tpci_disable_device(pdev);\n+}\n+\n+static struct pci_driver dh_pf_driver = {\n+\t.name = \"dinghai10e\",\n+\t.id_table = dh_pf_pci_table,\n+\t.probe = dh_pf_probe,\n+\t.remove = dh_pf_remove,\n+\t.shutdown = dh_pf_shutdown,\n+};\n+\n+module_pci_driver(dh_pf_driver);\ndiff --git a/drivers/net/ethernet/zte/dinghai/en_pf.h b/drivers/net/ethernet/zte/dinghai/en_pf.h\nnew file mode 100644\nindex 00000000000000..edaa79a6d6f2ab\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h\n@@ -0,0 +1,118 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/*\n+ * ZTE DingHai Ethernet driver - PF header\n+ * Copyright (c) 2022-2026, ZTE Corporation.\n+ */\n+\n+#ifndef __ZXDH_EN_PF_H__\n+#define __ZXDH_EN_PF_H__\n+\n+#include \u003clinux/types.h\u003e\n+#include \u003clinux/pci.h\u003e\n+#include \u003clinux/mutex.h\u003e\n+#include \u003clinux/device.h\u003e\n+#include \u003clinux/slab.h\u003e\n+\n+#define ZXDH_PF_VENDOR_ID\t0x1cf2\n+#define ZXDH_PF_DEVICE_ID\t0x8040\n+#define ZXDH_VF_DEVICE_ID\t0x8041\n+\n+/* Common configuration */\n+#define ZXDH_PCI_CAP_COMMON_CFG\t1\n+/* Notifications */\n+#define ZXDH_PCI_CAP_NOTIFY_CFG\t2\n+/* ISR access */\n+#define ZXDH_PCI_CAP_ISR_CFG\t\t3\n+/* Device specific configuration */\n+#define ZXDH_PCI_CAP_DEVICE_CFG\t4\n+/* PCI configuration access */\n+#define ZXDH_PCI_CAP_PCI_CFG\t\t5\n+\n+#define ZXDH_PF_MAX_BAR_VAL\t\t0x5\n+#define ZXDH_PF_ALIGN4\t\t\t4\n+#define ZXDH_PF_ALIGN2\t\t\t2\n+#define ZXDH_PF_MAP_MINLEN2\t\t2\n+\n+#define ZXDH_DEV_MAC_HIGH_OFFSET\t4\n+\n+enum dh_coredev_type {\n+\tDH_COREDEV_PF,\n+\tDH_COREDEV_VF,\n+\tDH_COREDEV_SF,\n+\tDH_COREDEV_MPF\n+};\n+\n+struct devlink;\n+\n+struct dh_core_dev {\n+\tstruct device *device;\n+\tenum dh_coredev_type coredev_type;\n+\tstruct pci_dev *pdev;\n+\tstruct devlink *devlink;\n+\tstruct mutex lock; /* Protects device configuration */\n+\tvoid *priv;\n+};\n+\n+struct zxdh_pf_device {\n+\tstruct zxdh_pf_pci_common_cfg __iomem *common;\n+\t/* Device-specific data (non-legacy mode) */\n+\t/* Base of vq notifications (non-legacy mode). */\n+\tvoid __iomem *device;\n+\tvoid __iomem *notify_base;\n+\tvoid __iomem *pf_sriov_cap_base;\n+\t/* Physical base of vq notifications */\n+\tresource_size_t notify_pa;\n+\t/* So we can sanity-check accesses. */\n+\tsize_t notify_len;\n+\tsize_t device_len;\n+\t/* Capability for when we need to map notifications per-vq. */\n+\ts32 notify_map_cap;\n+\tu32 notify_offset_multiplier;\n+\t/* Multiply queue_notify_off by this value. (non-legacy mode). */\n+\ts32 modern_bars;\n+\tvoid __iomem *pci_ioremap_addr[6];\n+\tu64 sriov_bar_size;\n+\tu32 dev_cfg_bar_off;\n+\tbool packed_status;\n+\tbool bar_chan_valid;\n+\tbool vepa;\n+\tstruct mutex irq_lock; /* Protects IRQ operations */\n+};\n+\n+#define GET_COREDEV_TYPE(pdev) \\\n+\t((pdev)-\u003edevice == ZXDH_VF_DEVICE_ID ? DH_COREDEV_VF : DH_COREDEV_PF)\n+\n+void *dh_core_alloc_priv(struct dh_core_dev *dh_dev, size_t size);\n+void dh_core_free_priv(struct dh_core_dev *dh_dev);\n+void dh_pf_pci_close(struct dh_core_dev *dev);\n+int zxdh_pf_pci_find_capability(struct pci_dev *pdev, u8 cfg_type,\n+\t\t\t\tu32 ioresource_types, int *bars);\n+void __iomem *zxdh_pf_map_capability(struct dh_core_dev *dh_dev, int off,\n+\t\t\t\t size_t minlen, u32 align,\n+\t\t\t\t u32 start, u32 size,\n+\t\t\t\t size_t *len, resource_size_t *pa,\n+\t\t\t\t u32 *bar_off);\n+int zxdh_pf_common_cfg_init(struct dh_core_dev *dh_dev);\n+int zxdh_pf_notify_cfg_init(struct dh_core_dev *dh_dev);\n+int zxdh_pf_device_cfg_init(struct dh_core_dev *dh_dev);\n+void zxdh_pf_modern_cfg_uninit(struct dh_core_dev *dh_dev);\n+int zxdh_pf_modern_cfg_init(struct dh_core_dev *dh_dev);\n+u16 zxdh_pf_get_queue_notify_off(struct dh_core_dev *dh_dev,\n+\t\t\t\t u16 phy_index, u16 index);\n+void __iomem *zxdh_pf_map_vq_notify(struct dh_core_dev *dh_dev,\n+\t\t\t\t u16 phy_index, u16 index,\n+\t\t\t\t resource_size_t *pa);\n+void zxdh_pf_unmap_vq_notify(struct dh_core_dev *dh_dev, void __iomem *priv);\n+void zxdh_pf_set_status(struct dh_core_dev *dh_dev, u8 status);\n+u8 zxdh_pf_get_status(struct dh_core_dev *dh_dev);\n+u8 zxdh_pf_get_cfg_gen(struct dh_core_dev *dh_dev);\n+void zxdh_pf_get_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id);\n+void zxdh_pf_set_vf_mac_reg(struct zxdh_pf_device *pf_dev,\n+\t\t\t u8 *mac, int vf_id);\n+void zxdh_pf_set_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id);\n+void zxdh_set_mac(struct dh_core_dev *dh_dev, u8 *mac);\n+void zxdh_get_mac(struct dh_core_dev *dh_dev, u8 *mac);\n+u64 zxdh_pf_get_features(struct dh_core_dev *dh_dev);\n+void zxdh_pf_set_features(struct dh_core_dev *dh_dev, u64 features);\n+\n+#endif /* __ZXDH_EN_PF_H__ */\n"
} |
| 2/1 | 2026/07/13 19:30 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"NET_VENDOR_ZTE",
"DINGHAI",
"DINGHAI_PF"
],
"FocusSymbols": [
"dh_pf_probe",
"dh_pf_remove",
"dh_pf_pci_init",
"dh_pf_pci_close"
],
"Reasoning": "The patch introduces a new PCI driver for ZTE DingHai Ethernet devices. The driver registers a PCI probe function which initializes the device, maps PCI memory, and registers a devlink instance. This code is reachable via the PCI subsystem and can be fuzzed using virtual PCI device injection.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit b9dba71a3aae353c54644b0ff4e4e82ceed56ffa
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jul 13 19:30:36 2026 +0000
syz-cluster: applied patch under review
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd1638..73692b09bf7bab 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 <han.junyang@zte.com.cn>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/zte/
+
THE REST
M: Linus Torvalds <torvalds@linux-foundation.org>
L: linux-kernel@vger.kernel.org
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index b8f70e2a1763ad..c2b6996b0cfe1b 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 57344fec6ce047..a34bcbd4df4e92 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 00000000000000..b95c2fc7db77a2
--- /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 00000000000000..cd9929b61559c6
--- /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 00000000000000..121be3bf7707fd
--- /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 00000000000000..f55a8de518beb3
--- /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/dh_queue.h b/drivers/net/ethernet/zte/dinghai/dh_queue.h
new file mode 100644
index 00000000000000..5067c73fed33cc
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/dh_queue.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ZTE DingHai Ethernet driver - PCI capability definitions
+ * Copyright (c) 2022-2026, ZTE Corporation.
+ */
+
+#ifndef __DH_QUEUE_H__
+#define __DH_QUEUE_H__
+
+/* Vector value used to disable MSI for queue */
+#define ZXDH_MSI_NO_VECTOR 0xff
+
+/* Status byte for guest to report progress, and synchronize features */
+/* We have seen device and processed generic fields */
+#define ZXDH_CONFIG_S_ACKNOWLEDGE 1
+/* We have found a driver for the device. */
+#define ZXDH_CONFIG_S_DRIVER 2
+/* Driver has used its parts of the config, and is happy */
+#define ZXDH_CONFIG_S_DRIVER_OK 4
+/* Driver has finished configuring features */
+#define ZXDH_CONFIG_S_FEATURES_OK 8
+/* Device entered invalid state, driver must reset it */
+#define ZXDH_CONFIG_S_NEEDS_RESET 0x40
+/* We've given up on this device */
+#define ZXDH_CONFIG_S_FAILED 0x80
+
+/* This is the PCI capability header: */
+struct zxdh_pf_pci_cap {
+ __u8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
+ __u8 cap_next; /* Generic PCI field: next ptr. */
+ __u8 cap_len; /* Generic PCI field: capability length */
+ __u8 cfg_type; /* Identifies the structure. */
+ __u8 bar; /* Where to find it. */
+ __u8 id; /* Multiple capabilities of the same type */
+ __u8 padding[2]; /* Pad to full dword. */
+ __le32 offset; /* Offset within bar. */
+ __le32 length; /* Length of the structure, in bytes. */
+};
+
+/* Fields in ZXDH_PF_PCI_CAP_COMMON_CFG: */
+struct zxdh_pf_pci_common_cfg {
+ /* About the whole device. */
+ __le32 device_feature_select; /* read-write */
+ __le32 device_feature; /* read-only */
+ __le32 guest_feature_select; /* read-write */
+ __le32 guest_feature; /* read-write */
+ __le16 msix_config; /* read-write */
+ __le16 num_queues; /* read-only */
+ __u8 device_status; /* read-write */
+ __u8 config_generation; /* read-only */
+
+ /* About a specific virtqueue. */
+ __le16 queue_select; /* read-write */
+ __le16 queue_size; /* read-write, power of 2. */
+ __le16 queue_msix_vector; /* read-write */
+ __le16 queue_enable; /* read-write */
+ __le16 queue_notify_off; /* read-only */
+ __le32 queue_desc_lo; /* read-write */
+ __le32 queue_desc_hi; /* read-write */
+ __le32 queue_avail_lo; /* read-write */
+ __le32 queue_avail_hi; /* read-write */
+ __le32 queue_used_lo; /* read-write */
+ __le32 queue_used_hi; /* read-write */
+};
+
+struct zxdh_pf_pci_notify_cap {
+ struct zxdh_pf_pci_cap cap;
+ __le32 notify_off_multiplier; /* Multiplier for queue_notify_off. */
+};
+
+#endif /* __DH_QUEUE_H__ */
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 00000000000000..f859fd472a86fd
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -0,0 +1,642 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ZTE DingHai Ethernet driver
+ * Copyright (c) 2022-2026, ZTE Corporation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <net/devlink.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include "en_pf.h"
+#include "dh_queue.h"
+
+MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
+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);
+}
+
+int zxdh_pf_pci_find_capability(struct pci_dev *pdev, u8 cfg_type,
+ u32 ioresource_types, int *bars)
+{
+ int pos;
+ u8 type;
+ u8 bar;
+
+ for (pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR); pos > 0;
+ pos = pci_find_next_capability(pdev, pos, PCI_CAP_ID_VNDR)) {
+ pci_read_config_byte(pdev,
+ pos + offsetof(struct zxdh_pf_pci_cap,
+ cfg_type), &type);
+ pci_read_config_byte(pdev,
+ pos + offsetof(struct zxdh_pf_pci_cap, bar), &bar);
+
+ /* ignore structures with reserved BAR values */
+ if (bar > ZXDH_PF_MAX_BAR_VAL)
+ continue;
+
+ if (type == cfg_type) {
+ if (pci_resource_len(pdev, bar) &&
+ pci_resource_flags(pdev, bar) & ioresource_types) {
+ *bars |= (1 << bar);
+ return pos;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void __iomem *zxdh_pf_map_capability(struct dh_core_dev *dh_dev, int off,
+ size_t minlen, u32 align,
+ u32 start, u32 size,
+ size_t *len, resource_size_t *pa,
+ u32 *bar_off)
+{
+ struct pci_dev *pdev = dh_dev->pdev;
+ void __iomem *p;
+ u32 offset;
+ u32 length;
+ u8 bar;
+
+ pci_read_config_byte(pdev,
+ off + offsetof(struct zxdh_pf_pci_cap, bar), &bar);
+ pci_read_config_dword(pdev,
+ off + offsetof(struct zxdh_pf_pci_cap,
+ offset), &offset);
+ pci_read_config_dword(pdev,
+ off + offsetof(struct zxdh_pf_pci_cap,
+ length), &length);
+
+ if (bar_off)
+ *bar_off = offset;
+
+ if (length <= start) {
+ dev_err(dh_dev->device, "bad capability len %u (>%u expected)\n",
+ length, start);
+ return NULL;
+ }
+
+ if (length - start < minlen) {
+ dev_err(dh_dev->device, "bad capability len %u (>=%zu expected)\n",
+ length, minlen);
+ return NULL;
+ }
+
+ length -= start;
+ if (start + offset < offset) {
+ dev_err(dh_dev->device, "map wrap-around %u+%u\n", start, offset);
+ return NULL;
+ }
+
+ offset += start;
+ if (offset & (align - 1)) {
+ dev_err(dh_dev->device, "offset %u not aligned to %u\n", offset, align);
+ return NULL;
+ }
+
+ if (length > size)
+ length = size;
+
+ if (len)
+ *len = length;
+
+ if (minlen + offset < minlen ||
+ minlen + offset > pci_resource_len(pdev, bar)) {
+ dev_err(dh_dev->device,
+ "map custom queue %zu@%u out of range on bar %u length %lu\n",
+ minlen, offset, bar,
+ (unsigned long)pci_resource_len(pdev, bar));
+ return NULL;
+ }
+
+ p = pci_iomap_range(pdev, bar, offset, length);
+ if (!p) {
+ dev_err(dh_dev->device, "unable to map custom queue %u@%u on bar %u\n",
+ length, offset, bar);
+ } else if (pa) {
+ *pa = pci_resource_start(pdev, bar) + offset;
+ }
+
+ return p;
+}
+
+int zxdh_pf_common_cfg_init(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ struct pci_dev *pdev = dh_dev->pdev;
+ int common;
+
+ /* check for a common config: if not, use legacy mode (bar 0). */
+ common = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_COMMON_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM,
+ &pf_dev->modern_bars);
+ if (!common) {
+ dev_err(dh_dev->device,
+ "missing capabilities, leaving for legacy driver\n");
+ return -ENODEV;
+ }
+
+ pf_dev->common = zxdh_pf_map_capability(dh_dev, common,
+ sizeof(struct zxdh_pf_pci_common_cfg),
+ ZXDH_PF_ALIGN4, 0,
+ sizeof(struct zxdh_pf_pci_common_cfg),
+ NULL, NULL, NULL);
+ if (!pf_dev->common) {
+ dev_err(dh_dev->device, "pf_dev->common is null\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int zxdh_pf_notify_cfg_init(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ struct pci_dev *pdev = dh_dev->pdev;
+ u32 notify_length;
+ u32 notify_offset;
+ int notify;
+
+ /* If common is there, these should be too... */
+ notify = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_NOTIFY_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM,
+ &pf_dev->modern_bars);
+ if (!notify) {
+ dev_err(dh_dev->device, "missing notify cfg capability\n");
+ return -EINVAL;
+ }
+
+ pci_read_config_dword(pdev,
+ notify + offsetof(struct zxdh_pf_pci_notify_cap,
+ notify_off_multiplier),
+ &pf_dev->notify_offset_multiplier);
+ pci_read_config_dword(pdev,
+ notify + offsetof(struct zxdh_pf_pci_notify_cap,
+ cap.length), ¬ify_length);
+ pci_read_config_dword(pdev,
+ notify + offsetof(struct zxdh_pf_pci_notify_cap,
+ cap.offset), ¬ify_offset);
+
+ /* We don't know how many VQs we'll map, ahead of the time.
+ * If notify length is small, map it all now. Otherwise,
+ * map each VQ individually later.
+ */
+ if (notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) {
+ pf_dev->notify_base = zxdh_pf_map_capability(dh_dev, notify,
+ ZXDH_PF_MAP_MINLEN2,
+ ZXDH_PF_ALIGN2, 0,
+ notify_length,
+ &pf_dev->notify_len,
+ &pf_dev->notify_pa, NULL);
+ if (!pf_dev->notify_base) {
+ dev_err(dh_dev->device, "pf_dev->notify_base is null\n");
+ return -EINVAL;
+ }
+ } else {
+ pf_dev->notify_map_cap = notify;
+ }
+
+ return 0;
+}
+
+int zxdh_pf_device_cfg_init(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ struct pci_dev *pdev = dh_dev->pdev;
+ int device;
+
+ /* Device capability is only mandatory for
+ * devices that have device-specific configuration.
+ */
+ device = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_DEVICE_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM,
+ &pf_dev->modern_bars);
+
+ /* we don't know how much we should map,
+ * but PAGE_SIZE is more than enough for all existing devices.
+ */
+ if (device) {
+ pf_dev->device = zxdh_pf_map_capability(dh_dev, device, 0,
+ ZXDH_PF_ALIGN4, 0, PAGE_SIZE,
+ &pf_dev->device_len, NULL,
+ &pf_dev->dev_cfg_bar_off);
+ if (!pf_dev->device) {
+ dev_err(dh_dev->device, "pf_dev->device is null\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+void zxdh_pf_modern_cfg_uninit(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ struct pci_dev *pdev = dh_dev->pdev;
+
+ if (pf_dev->device)
+ pci_iounmap(pdev, pf_dev->device);
+ if (pf_dev->notify_base)
+ pci_iounmap(pdev, pf_dev->notify_base);
+ pci_iounmap(pdev, pf_dev->common);
+}
+
+int zxdh_pf_modern_cfg_init(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ struct pci_dev *pdev = dh_dev->pdev;
+ int ret;
+
+ ret = zxdh_pf_common_cfg_init(dh_dev);
+ if (ret) {
+ dev_err(dh_dev->device, "zxdh_pf_common_cfg_init failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = zxdh_pf_notify_cfg_init(dh_dev);
+ if (ret) {
+ dev_err(dh_dev->device, "zxdh_pf_notify_cfg_init failed: %d\n", ret);
+ goto err_map_notify;
+ }
+
+ ret = zxdh_pf_device_cfg_init(dh_dev);
+ if (ret) {
+ dev_err(dh_dev->device, "zxdh_pf_device_cfg_init failed: %d\n", ret);
+ goto err_map_device;
+ }
+
+ return 0;
+
+err_map_device:
+ if (pf_dev->notify_base)
+ pci_iounmap(pdev, pf_dev->notify_base);
+err_map_notify:
+ pci_iounmap(pdev, pf_dev->common);
+ return ret;
+}
+
+u16 zxdh_pf_get_queue_notify_off(struct dh_core_dev *dh_dev,
+ u16 phy_index, u16 index)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ if (pf_dev->packed_status)
+ iowrite16(phy_index, &pf_dev->common->queue_select);
+ else
+ iowrite16(index, &pf_dev->common->queue_select);
+
+ return ioread16(&pf_dev->common->queue_notify_off);
+}
+
+void __iomem *zxdh_pf_map_vq_notify(struct dh_core_dev *dh_dev,
+ u16 phy_index, u16 index,
+ resource_size_t *pa)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ u16 off;
+
+ off = zxdh_pf_get_queue_notify_off(dh_dev, phy_index, index);
+
+ if (pf_dev->notify_base) {
+ /* offset should not wrap */
+ if ((u64)off *
+ pf_dev->notify_offset_multiplier + 2 > pf_dev->notify_len) {
+ dev_err(dh_dev->device,
+ "bad notification offset %u (x %u) for queue %u > %zu\n",
+ off, pf_dev->notify_offset_multiplier, phy_index,
+ pf_dev->notify_len);
+ return NULL;
+ }
+
+ if (pa)
+ *pa = pf_dev->notify_pa + off * pf_dev->notify_offset_multiplier;
+
+ return pf_dev->notify_base + off * pf_dev->notify_offset_multiplier;
+ } else {
+ return zxdh_pf_map_capability(dh_dev, pf_dev->notify_map_cap, 2, 2,
+ off * pf_dev->notify_offset_multiplier,
+ 2, NULL, pa, NULL);
+ }
+}
+
+void zxdh_pf_unmap_vq_notify(struct dh_core_dev *dh_dev, void __iomem *priv)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ if (!pf_dev->notify_base)
+ pci_iounmap(dh_dev->pdev, priv);
+}
+
+void zxdh_pf_set_status(struct dh_core_dev *dh_dev, u8 status)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ iowrite8(status, &pf_dev->common->device_status);
+}
+
+u8 zxdh_pf_get_status(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ return ioread8(&pf_dev->common->device_status);
+}
+
+u8 zxdh_pf_get_cfg_gen(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ u8 config_generation;
+
+ config_generation = ioread8(&pf_dev->common->config_generation);
+
+ return config_generation;
+}
+
+void zxdh_pf_get_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ u32 DEV_MAC_L;
+ u16 DEV_MAC_H;
+
+ eth_zero_addr(mac);
+
+ if (pf_dev->pf_sriov_cap_base) {
+ DEV_MAC_L = ioread32(pf_dev->pf_sriov_cap_base +
+ (pf_dev->sriov_bar_size) * vf_id +
+ pf_dev->dev_cfg_bar_off);
+ mac[0] = DEV_MAC_L & 0xff;
+ mac[1] = (DEV_MAC_L >> 8) & 0xff;
+ mac[2] = (DEV_MAC_L >> 16) & 0xff;
+ mac[3] = (DEV_MAC_L >> 24) & 0xff;
+ DEV_MAC_H = ioread16(pf_dev->pf_sriov_cap_base +
+ (pf_dev->sriov_bar_size) * vf_id +
+ pf_dev->dev_cfg_bar_off +
+ ZXDH_DEV_MAC_HIGH_OFFSET);
+ mac[4] = DEV_MAC_H & 0xff;
+ mac[5] = (DEV_MAC_H >> 8) & 0xff;
+ }
+}
+
+void zxdh_pf_set_vf_mac_reg(struct zxdh_pf_device *pf_dev,
+ u8 *mac, int vf_id)
+{
+ u32 DEV_MAC_L;
+ u16 DEV_MAC_H;
+
+ if (pf_dev->pf_sriov_cap_base) {
+ DEV_MAC_L = mac[0] | (mac[1] << 8) |
+ (mac[2] << 16) | (mac[3] << 24);
+ DEV_MAC_H = mac[4] | (mac[5] << 8);
+ iowrite32(DEV_MAC_L, (pf_dev->pf_sriov_cap_base +
+ (pf_dev->sriov_bar_size) * vf_id +
+ pf_dev->dev_cfg_bar_off));
+ iowrite16(DEV_MAC_H, (pf_dev->pf_sriov_cap_base +
+ (pf_dev->sriov_bar_size) * vf_id +
+ pf_dev->dev_cfg_bar_off +
+ ZXDH_DEV_MAC_HIGH_OFFSET));
+ }
+}
+
+void zxdh_pf_set_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ zxdh_pf_set_vf_mac_reg(pf_dev, mac, vf_id);
+}
+
+void zxdh_set_mac(struct dh_core_dev *dh_dev, u8 *mac)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ u32 DEV_MAC_L;
+ u16 DEV_MAC_H;
+
+ if (!pf_dev->device)
+ return;
+
+ DEV_MAC_L = mac[0] | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24);
+ DEV_MAC_H = mac[4] | (mac[5] << 8);
+ iowrite32(DEV_MAC_L, pf_dev->device);
+ iowrite16(DEV_MAC_H, pf_dev->device + ZXDH_DEV_MAC_HIGH_OFFSET);
+}
+
+void zxdh_get_mac(struct dh_core_dev *dh_dev, u8 *mac)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ u32 DEV_MAC_L;
+ u16 DEV_MAC_H;
+
+ if (!pf_dev->device)
+ return;
+
+ DEV_MAC_L = ioread32(pf_dev->device);
+ mac[0] = DEV_MAC_L & 0xff;
+ mac[1] = (DEV_MAC_L >> 8) & 0xff;
+ mac[2] = (DEV_MAC_L >> 16) & 0xff;
+ mac[3] = (DEV_MAC_L >> 24) & 0xff;
+ DEV_MAC_H = ioread16(pf_dev->device + ZXDH_DEV_MAC_HIGH_OFFSET);
+ mac[4] = DEV_MAC_H & 0xff;
+ mac[5] = (DEV_MAC_H >> 8) & 0xff;
+}
+
+u64 zxdh_pf_get_features(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ u64 device_feature;
+
+ iowrite32(0, &pf_dev->common->device_feature_select);
+ device_feature = ioread32(&pf_dev->common->device_feature);
+ iowrite32(1, &pf_dev->common->device_feature_select);
+ device_feature |= ((u64)ioread32(&pf_dev->common->device_feature)
+ << 32);
+
+ return device_feature;
+}
+
+void zxdh_pf_set_features(struct dh_core_dev *dh_dev, u64 features)
+{
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ iowrite32(0, &pf_dev->common->guest_feature_select);
+ iowrite32((u32)features, &pf_dev->common->guest_feature);
+ iowrite32(1, &pf_dev->common->guest_feature_select);
+ iowrite32(features >> 32, &pf_dev->common->guest_feature);
+}
+
+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 00000000000000..edaa79a6d6f2ab
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h
@@ -0,0 +1,118 @@
+/* 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 <linux/types.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#define ZXDH_PF_VENDOR_ID 0x1cf2
+#define ZXDH_PF_DEVICE_ID 0x8040
+#define ZXDH_VF_DEVICE_ID 0x8041
+
+/* Common configuration */
+#define ZXDH_PCI_CAP_COMMON_CFG 1
+/* Notifications */
+#define ZXDH_PCI_CAP_NOTIFY_CFG 2
+/* ISR access */
+#define ZXDH_PCI_CAP_ISR_CFG 3
+/* Device specific configuration */
+#define ZXDH_PCI_CAP_DEVICE_CFG 4
+/* PCI configuration access */
+#define ZXDH_PCI_CAP_PCI_CFG 5
+
+#define ZXDH_PF_MAX_BAR_VAL 0x5
+#define ZXDH_PF_ALIGN4 4
+#define ZXDH_PF_ALIGN2 2
+#define ZXDH_PF_MAP_MINLEN2 2
+
+#define ZXDH_DEV_MAC_HIGH_OFFSET 4
+
+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 {
+ struct zxdh_pf_pci_common_cfg __iomem *common;
+ /* Device-specific data (non-legacy mode) */
+ /* Base of vq notifications (non-legacy mode). */
+ void __iomem *device;
+ void __iomem *notify_base;
+ void __iomem *pf_sriov_cap_base;
+ /* Physical base of vq notifications */
+ resource_size_t notify_pa;
+ /* So we can sanity-check accesses. */
+ size_t notify_len;
+ size_t device_len;
+ /* Capability for when we need to map notifications per-vq. */
+ s32 notify_map_cap;
+ u32 notify_offset_multiplier;
+ /* Multiply queue_notify_off by this value. (non-legacy mode). */
+ s32 modern_bars;
+ void __iomem *pci_ioremap_addr[6];
+ u64 sriov_bar_size;
+ u32 dev_cfg_bar_off;
+ bool packed_status;
+ 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);
+int zxdh_pf_pci_find_capability(struct pci_dev *pdev, u8 cfg_type,
+ u32 ioresource_types, int *bars);
+void __iomem *zxdh_pf_map_capability(struct dh_core_dev *dh_dev, int off,
+ size_t minlen, u32 align,
+ u32 start, u32 size,
+ size_t *len, resource_size_t *pa,
+ u32 *bar_off);
+int zxdh_pf_common_cfg_init(struct dh_core_dev *dh_dev);
+int zxdh_pf_notify_cfg_init(struct dh_core_dev *dh_dev);
+int zxdh_pf_device_cfg_init(struct dh_core_dev *dh_dev);
+void zxdh_pf_modern_cfg_uninit(struct dh_core_dev *dh_dev);
+int zxdh_pf_modern_cfg_init(struct dh_core_dev *dh_dev);
+u16 zxdh_pf_get_queue_notify_off(struct dh_core_dev *dh_dev,
+ u16 phy_index, u16 index);
+void __iomem *zxdh_pf_map_vq_notify(struct dh_core_dev *dh_dev,
+ u16 phy_index, u16 index,
+ resource_size_t *pa);
+void zxdh_pf_unmap_vq_notify(struct dh_core_dev *dh_dev, void __iomem *priv);
+void zxdh_pf_set_status(struct dh_core_dev *dh_dev, u8 status);
+u8 zxdh_pf_get_status(struct dh_core_dev *dh_dev);
+u8 zxdh_pf_get_cfg_gen(struct dh_core_dev *dh_dev);
+void zxdh_pf_get_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id);
+void zxdh_pf_set_vf_mac_reg(struct zxdh_pf_device *pf_dev,
+ u8 *mac, int vf_id);
+void zxdh_pf_set_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id);
+void zxdh_set_mac(struct dh_core_dev *dh_dev, u8 *mac);
+void zxdh_get_mac(struct dh_core_dev *dh_dev, u8 *mac);
+u64 zxdh_pf_get_features(struct dh_core_dev *dh_dev);
+void zxdh_pf_set_features(struct dh_core_dev *dh_dev, u64 features);
+
+#endif /* __ZXDH_EN_PF_H__ */
|
| 3/2 | 2026/07/13 19:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14141 output: 25 thoughts: 512 Thoughts: **Analyzing the ZTE DingHai Ethernet Driver Patch** Okay, so I'm looking at this patch adding a new Ethernet driver for ZTE DingHai devices. The structure is pretty standard: `MAINTAINERS` update, `Kconfig` and `Makefile` changes across several directories. Specifically, this driver seems to be targeting PCI-based ZTE DingHai hardware. From the code, it's clear this driver is centered around the PCI driver `dh_pf_driver`, with `dh_pf_probe` serving as the key initialization point. Initially, I thought it was missing the crucial `net_device` registration, but then I see the patch does register a `devlink` instance using `devlink_register(devlink)`, which is definitely a positive sign, as this exposes functionality to userspace. Digging deeper, the driver implements `dh_pf_probe`, `dh_pf_remove`, and `dh_pf_shutdown`. I noticed some other functions like `zxdh_pf_modern_cfg_init`, `zxdh_pf_set_vf_mac`, etc., are defined. However, a quick scan of `en_pf.c` revealed that they aren't called anywhere in the driver itself, which is a bit puzzling. Maybe they're part of a future implementation or are meant to be called externally. I'll need to confirm if they are truly unused, likely dead code, or somehow called elsewhere (maybe a different patch?). Looking specifically at what `dh_pf_probe` does, I see it calls `devlink_alloc`, `dh_core_alloc_priv`, `dh_pf_pci_init`, and then registers the `devlink`. This is a solid foundation for a functional driver. To be thorough, I'm going to quickly grep through the code to verify that those other functions are not actually used, ensuring that they truly aren't referenced by any other code. I'll run `grepper` and see what it finds on `zxdh_pf_modern_cfg_init`. |
| 4/2 | 2026/07/13 19:30 | tool | grepper |
0mArgs:{
"Expression": "zxdh_pf_modern_cfg_init"
}Results: {
"Output": "drivers/net/ethernet/zte/dinghai/en_pf.c=328=void zxdh_pf_modern_cfg_uninit(struct dh_core_dev *dh_dev)\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-339-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:340:int zxdh_pf_modern_cfg_init(struct dh_core_dev *dh_dev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-341-{\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.h=98=void zxdh_pf_modern_cfg_uninit(struct dh_core_dev *dh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:99:int zxdh_pf_modern_cfg_init(struct dh_core_dev *dh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.h-100-u16 zxdh_pf_get_queue_notify_off(struct dh_core_dev *dh_dev,\n"
} |
| 5/2 | 2026/07/13 19:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15418 output: 18 thoughts: 142 Thoughts: **Fuzzing a New PCI Driver** Okay, so this code is currently dormant, essentially dead, but `dh_pf_probe` is still accessible, which is interesting. Should I even bother with fuzzing this? Yes, absolutely. It's a brand new PCI driver, and Syzkaller is capable of fuzzing PCI drivers using virtual PCI device injection – a great opportunity. Now, I need to figure out the right kernel configurations to enable this functionality. Let's see, based on the notes, I need `NET_VENDOR_ZTE`, `DINGHAI`, and `DINGHAI_PF`. Right, time to check `drivers/net/ethernet/zte/dinghai/Kconfig`. Okay, `DINGHAI` depends on `PCI`, so that's a good starting point. And `DINGHAI_PF` is a tristate, meaning it can be compiled as a module or built-in, or even disabled. Now, I need to confirm whether `DINGHAI` and `DINGHAI_PF` are the correct configurations to enable the driver for fuzzing. |
| 6/2 | 2026/07/13 19:30 | tool | grepper |
0mArgs:{
"Expression": "config DINGHAI"
}Results: {
"Output": "drivers/net/ethernet/zte/dinghai/Kconfig-5-\ndrivers/net/ethernet/zte/dinghai/Kconfig:6:config DINGHAI\ndrivers/net/ethernet/zte/dinghai/Kconfig-7- bool \"ZTE DingHai Ethernet driver\"\n--\ndrivers/net/ethernet/zte/dinghai/Kconfig=21=if DINGHAI\ndrivers/net/ethernet/zte/dinghai/Kconfig-22-\ndrivers/net/ethernet/zte/dinghai/Kconfig:23:config DINGHAI_PF\ndrivers/net/ethernet/zte/dinghai/Kconfig-24- tristate \"ZTE DingHai PF (Physical Function) driver\"\n"
} |
| 7/2 | 2026/07/13 19:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 15992 output: 21 thoughts: 17 Thoughts: Here's my thought process, as if I were considering that Kconfig file: **Investigating the ZTE Ethernet Driver Configuration** Okay, let's dive in. The task at hand is to understand the configuration options for the ZTE Ethernet driver. Specifically, I need to understand its build-time configurations by examining the `drivers/net/ethernet/zte/Kconfig` file. This is the place where the inclusion of the ZTE Ethernet driver is defined, along with all its features and dependencies. I expect to find `config` options, `depends on` clauses, and maybe even some `select` statements to manage relationships with other kernel components. I'll be looking for things like whether it supports specific hardware revisions, different Ethernet PHY types, power management features, or any other driver-specific configurations that might be enabled or disabled at build time. Based on the Kconfig file, I'll assess whether it might apply in a specific use case. |
| 8/2 | 2026/07/13 19:31 | tool | grepper |
0mArgs:{
"Expression": "config NET_VENDOR_ZTE"
}Results: {
"Output": "drivers/net/ethernet/zte/Kconfig-5-\ndrivers/net/ethernet/zte/Kconfig:6:config NET_VENDOR_ZTE\ndrivers/net/ethernet/zte/Kconfig-7- bool \"ZTE devices\"\n"
} |
| 9/2 | 2026/07/13 19:31 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16299 output: 46 thoughts: 194 Thoughts: **Analyzing the ZTE Dinghai Configuration**
Okay, so I'm looking at this configuration and the key is enabling these modules: `NET_VENDOR_ZTE`, `DINGHAI`, and `DINGHAI_PF`. Right, straightforward enough. Now, I need to understand the critical symbols, the entry and exit points. I see the focus is on `dh_pf_probe`, `dh_pf_remove`, `dh_pf_pci_init`, and `dh_pf_pci_close`. Ah, `dh_pf_probe` rings a bell, that looks like a PCI probe function, which makes sense given the context.
Let me just quickly verify if there are any other accessible functions in this path. Let's see... looking at `devlink_ops`, it's empty: `static const struct devlink_ops dh_pf_devlink_ops = {};` Okay, so no devlink callbacks are defined here. That helps narrow things down considerably.
So, to reiterate, the only reachable functions appear to be `dh_pf_probe`, `dh_pf_remove`, `dh_pf_shutdown`, `dh_pf_pci_init`, and `dh_pf_pci_close`. Now, I need to make sure I haven't missed anything crucial, so I'll go back and double-check exactly what `dh_pf_probe` does to confirm it's as straightforward as it seems. Gotta be thorough.
|
| 10/2 | 2026/07/13 19:31 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/zte/dinghai/en_pf.c",
"FirstLine": 560,
"LineCount": 100
}Results: {
"Contents": " 560:\tstatic int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n 561:\t{\n 562:\t\tstruct zxdh_pf_device *pf_dev;\n 563:\t\tstruct dh_core_dev *dh_dev;\n 564:\t\tstruct devlink *devlink;\n 565:\t\tint ret;\n 566:\t\n 567:\t\tdevlink = devlink_alloc(\u0026dh_pf_devlink_ops, sizeof(struct dh_core_dev),\n 568:\t\t\t\t\t\u0026pdev-\u003edev);\n 569:\t\tif (!devlink) {\n 570:\t\t\tdev_err(\u0026pdev-\u003edev, \"dh_pf devlink alloc failed\\n\");\n 571:\t\t\treturn -ENOMEM;\n 572:\t\t}\n 573:\t\n 574:\t\tdh_dev = devlink_priv(devlink);\n 575:\t\tdh_dev-\u003edevice = \u0026pdev-\u003edev;\n 576:\t\tdh_dev-\u003epdev = pdev;\n 577:\t\tdh_dev-\u003edevlink = devlink;\n 578:\t\n 579:\t\tpf_dev = dh_core_alloc_priv(dh_dev, sizeof(*pf_dev));\n 580:\t\tif (!pf_dev) {\n 581:\t\t\tdev_err(\u0026pdev-\u003edev, \"dh_pf_dev alloc failed\\n\");\n 582:\t\t\tret = -ENOMEM;\n 583:\t\t\tgoto err_pf_dev;\n 584:\t\t}\n 585:\t\n 586:\t\tpf_dev-\u003ebar_chan_valid = false;\n 587:\t\tpf_dev-\u003evepa = false;\n 588:\t\tmutex_init(\u0026dh_dev-\u003elock);\n 589:\t\tmutex_init(\u0026pf_dev-\u003eirq_lock);\n 590:\t\n 591:\t\tdh_dev-\u003ecoredev_type = GET_COREDEV_TYPE(pdev);\n 592:\t\n 593:\t\tret = dh_pf_pci_init(dh_dev);\n 594:\t\tif (ret) {\n 595:\t\t\tdev_err(\u0026pdev-\u003edev, \"dh_pf_pci_init failed: %d\\n\", ret);\n 596:\t\t\tgoto err_cfg_init;\n 597:\t\t}\n 598:\t\n 599:\t\tdevlink_register(devlink);\n 600:\t\n 601:\t\treturn 0;\n 602:\t\n 603:\terr_cfg_init:\n 604:\t\tmutex_destroy(\u0026pf_dev-\u003eirq_lock);\n 605:\t\tmutex_destroy(\u0026dh_dev-\u003elock);\n 606:\t\tdh_core_free_priv(dh_dev);\n 607:\terr_pf_dev:\n 608:\t\tdevlink_free(devlink);\n 609:\t\treturn ret;\n 610:\t}\n 611:\t\n 612:\tstatic void dh_pf_remove(struct pci_dev *pdev)\n 613:\t{\n 614:\t\tstruct dh_core_dev *dh_dev = pci_get_drvdata(pdev);\n 615:\t\tstruct devlink *devlink = priv_to_devlink(dh_dev);\n 616:\t\tstruct zxdh_pf_device *pf_dev = dh_dev-\u003epriv;\n 617:\t\n 618:\t\tdevlink_unregister(devlink);\n 619:\t\tdh_pf_pci_close(dh_dev);\n 620:\t\tmutex_destroy(\u0026pf_dev-\u003eirq_lock);\n 621:\t\tmutex_destroy(\u0026dh_dev-\u003elock);\n 622:\t\tdh_core_free_priv(dh_dev);\n 623:\t\tdevlink_free(devlink);\n 624:\t\tpci_set_drvdata(pdev, NULL);\n 625:\t}\n 626:\t\n 627:\tstatic void dh_pf_shutdown(struct pci_dev *pdev)\n 628:\t{\n 629:\t\tif (system_state == SYSTEM_POWER_OFF)\n 630:\t\t\tpci_set_power_state(pdev, PCI_D3hot);\n 631:\t\tpci_disable_device(pdev);\n 632:\t}\n 633:\t\n 634:\tstatic struct pci_driver dh_pf_driver = {\n 635:\t\t.name = \"dinghai10e\",\n 636:\t\t.id_table = dh_pf_pci_table,\n 637:\t\t.probe = dh_pf_probe,\n 638:\t\t.remove = dh_pf_remove,\n 639:\t\t.shutdown = dh_pf_shutdown,\n 640:\t};\n 641:\t\n 642:\tmodule_pci_driver(dh_pf_driver);\n"
} |
| 11/2 | 2026/07/13 19:31 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 18164 output: 145 thoughts: 155 Thoughts: **Fuzzing Target: ZTE DingHai Ethernet Driver** Okay, so I'm looking at this patch and it's introducing a new PCI driver specifically for ZTE DingHai Ethernet devices. My initial thoughts are, good, a new target! It implements the usual PCI driver lifecycle functions – `probe`, `remove`, and `shutdown` – which is what I'd expect. I'm noticing that the patch also defines some other functions like `zxdh_pf_modern_cfg_init` and `zxdh_pf_set_vf_mac`, but these don't seem to be currently utilized within the `probe` routine. Interesting… potentially a future expansion or perhaps some unused code paths. Worth keeping an eye on, but for the initial fuzzing, my primary focus will be on the core functions. Since the `probe` function is triggered via the PCI subsystem, it's definitely reachable and a prime candidate for fuzzing. I'll need to concentrate my efforts on `dh_pf_probe`, `dh_pf_remove`, `dh_pf_pci_init`, and `dh_pf_pci_close`. These are the key entry points and exit points for the driver, and fuzzing these could expose vulnerabilities in how it handles initialization, configuration, or resource management. From a configuration perspective, I'll need to ensure the following are enabled: `NET_VENDOR_ZTE`, `DINGHAI`, and `DINGHAI_PF`. This will make sure the driver is properly compiled and initialized when the device is accessed, enabling my fuzzing. Right, I'm confident I have a good handle on the target. Let's call `set-results` and move forward with the fuzzing setup. |
| 12/2 | 2026/07/13 19:31 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"NET_VENDOR_ZTE",
"DINGHAI",
"DINGHAI_PF"
],
"FocusSymbols": [
"dh_pf_probe",
"dh_pf_remove",
"dh_pf_pci_init",
"dh_pf_pci_close"
],
"Reasoning": "The patch introduces a new PCI driver for ZTE DingHai Ethernet devices. The driver registers a PCI probe function which initializes the device, maps PCI memory, and registers a devlink instance. This code is reachable via the PCI subsystem and can be fuzzed using virtual PCI device injection.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"NET_VENDOR_ZTE",
"DINGHAI",
"DINGHAI_PF"
],
"FocusSymbols": [
"dh_pf_probe",
"dh_pf_remove",
"dh_pf_pci_init",
"dh_pf_pci_close"
],
"Reasoning": "The patch introduces a new PCI driver for ZTE DingHai Ethernet devices. The driver registers a PCI probe function which initializes the device, maps PCI memory, and registers a devlink instance. This code is reachable via the PCI subsystem and can be fuzzed using virtual PCI device injection.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|