| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/20 14:32 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch introduces a new PCI driver for a specific hardware device (ZTE DingHai Ethernet controller). There is no software emulation for this hardware in QEMU or the kernel. The driver's probe function relies on finding specific vendor-specific PCI capabilities, meaning it cannot be successfully force-bound to other virtual PCI devices. Therefore, the code paths are impossible to reach in virtualized environments like GCE or QEMU.",
"WorthFuzzing": false
} |
| 1/1 | 2026/07/20 14:32 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 6abd03922dbfe8b0cb047169e6f932fcef4c7911\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jul 20 14:32:22 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..10df4eb79e80e1\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/dinghai/Makefile\n@@ -0,0 +1,9 @@\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\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..afac67f7147cb9\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/dinghai/dh_queue.h\n@@ -0,0 +1,54 @@\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+/* 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..ae5a77ddaca569\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c\n@@ -0,0 +1,465 @@\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 zxdh_pf_devlink_ops = {};\n+\n+static const struct pci_device_id zxdh_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, zxdh_pf_pci_table);\n+\n+void *zxdh_core_alloc_priv(struct zxdh_core_dev *zxdh_dev, size_t size)\n+{\n+\tvoid *priv = kzalloc(size, GFP_KERNEL);\n+\n+\tif (priv)\n+\t\tzxdh_dev-\u003epriv = priv;\n+\treturn priv;\n+}\n+\n+void zxdh_core_free_priv(struct zxdh_core_dev *zxdh_dev)\n+{\n+\tkfree(zxdh_dev-\u003epriv);\n+}\n+\n+static int zxdh_pf_pci_init(struct zxdh_core_dev *zxdh_dev)\n+{\n+\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\n+\tint ret;\n+\n+\tpci_set_drvdata(zxdh_dev-\u003epdev, zxdh_dev);\n+\n+\tret = pci_enable_device(zxdh_dev-\u003epdev);\n+\tif (ret) {\n+\t\tdev_err(zxdh_dev-\u003edevice, \"pci_enable_device failed: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = dma_set_mask_and_coherent(zxdh_dev-\u003edevice, DMA_BIT_MASK(64));\n+\tif (ret) {\n+\t\tret = dma_set_mask_and_coherent(zxdh_dev-\u003edevice, DMA_BIT_MASK(32));\n+\t\tif (ret) {\n+\t\t\tdev_err(zxdh_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(zxdh_dev-\u003epdev,\n+\t\t\t\t\t pci_select_bars(zxdh_dev-\u003epdev, IORESOURCE_MEM),\n+\t\t\t\t\t \"dh-pf\");\n+\tif (ret) {\n+\t\tdev_err(zxdh_dev-\u003edevice, \"pci_request_selected_regions failed: %d\\n\", ret);\n+\t\tgoto err_pci;\n+\t}\n+\n+\tpci_set_master(zxdh_dev-\u003epdev);\n+\tret = pci_save_state(zxdh_dev-\u003epdev);\n+\tif (ret) {\n+\t\tdev_err(zxdh_dev-\u003edevice, \"pci_save_state failed: %d\\n\", ret);\n+\t\tgoto err_pci_save_state;\n+\t}\n+\n+\tif (!(pci_resource_flags(zxdh_dev-\u003epdev, 0) \u0026 IORESOURCE_MEM)) {\n+\t\tret = -ENODEV;\n+\t\tdev_err(zxdh_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(zxdh_dev-\u003epdev, 0),\n+\t\t\tpci_resource_len(zxdh_dev-\u003epdev, 0));\n+\tif (!pf_dev-\u003epci_ioremap_addr[0]) {\n+\t\tret = -ENOMEM;\n+\t\tdev_err(zxdh_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(zxdh_dev-\u003epdev,\n+\t\t\t\t pci_select_bars(zxdh_dev-\u003epdev, IORESOURCE_MEM));\n+err_pci:\n+\tpci_disable_device(zxdh_dev-\u003epdev);\n+\treturn ret;\n+}\n+\n+void zxdh_pf_pci_close(struct zxdh_core_dev *zxdh_dev)\n+{\n+\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\n+\n+\tiounmap(pf_dev-\u003epci_ioremap_addr[0]);\n+\tpci_release_selected_regions(zxdh_dev-\u003epdev,\n+\t\t\t\t pci_select_bars(zxdh_dev-\u003epdev, IORESOURCE_MEM));\n+\tpci_disable_device(zxdh_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 zxdh_core_dev *zxdh_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 = zxdh_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(zxdh_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(zxdh_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(zxdh_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(zxdh_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(zxdh_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(zxdh_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 zxdh_core_dev *zxdh_dev)\n+{\n+\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = zxdh_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(zxdh_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(zxdh_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(zxdh_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 zxdh_core_dev *zxdh_dev)\n+{\n+\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = zxdh_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(zxdh_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(zxdh_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(zxdh_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 zxdh_core_dev *zxdh_dev)\n+{\n+\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = zxdh_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(zxdh_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(zxdh_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 zxdh_core_dev *zxdh_dev)\n+{\n+\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = zxdh_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 zxdh_core_dev *zxdh_dev)\n+{\n+\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\n+\tstruct pci_dev *pdev = zxdh_dev-\u003epdev;\n+\tint ret;\n+\n+\tret = zxdh_pf_common_cfg_init(zxdh_dev);\n+\tif (ret) {\n+\t\tdev_err(zxdh_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(zxdh_dev);\n+\tif (ret) {\n+\t\tdev_err(zxdh_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(zxdh_dev);\n+\tif (ret) {\n+\t\tdev_err(zxdh_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+static int zxdh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n+{\n+\tstruct zxdh_pf_dev *pf_dev;\n+\tstruct zxdh_core_dev *zxdh_dev;\n+\tstruct devlink *devlink;\n+\tint ret;\n+\n+\tdevlink = devlink_alloc(\u0026zxdh_pf_devlink_ops, sizeof(struct zxdh_core_dev),\n+\t\t\t\t\u0026pdev-\u003edev);\n+\tif (!devlink) {\n+\t\tdev_err(\u0026pdev-\u003edev, \"zxdh_pf devlink alloc failed\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tzxdh_dev = devlink_priv(devlink);\n+\tzxdh_dev-\u003edevice = \u0026pdev-\u003edev;\n+\tzxdh_dev-\u003epdev = pdev;\n+\tzxdh_dev-\u003edevlink = devlink;\n+\n+\tpf_dev = zxdh_core_alloc_priv(zxdh_dev, sizeof(*pf_dev));\n+\tif (!pf_dev) {\n+\t\tdev_err(\u0026pdev-\u003edev, \"zxdh_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(\u0026zxdh_dev-\u003elock);\n+\tmutex_init(\u0026pf_dev-\u003eirq_lock);\n+\n+\tzxdh_dev-\u003ecoredev_type = GET_COREDEV_TYPE(pdev);\n+\n+\tret = zxdh_pf_pci_init(zxdh_dev);\n+\tif (ret) {\n+\t\tdev_err(\u0026pdev-\u003edev, \"zxdh_pf_pci_init failed: %d\\n\", ret);\n+\t\tgoto err_pf_init;\n+\t}\n+\n+\tret = zxdh_pf_modern_cfg_init(zxdh_dev);\n+\tif (ret) {\n+\t\tdev_err(\u0026pdev-\u003edev, \"zxdh_pf_modern_cfg_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+\tzxdh_pf_pci_close(zxdh_dev);\n+err_pf_init:\n+\tmutex_destroy(\u0026pf_dev-\u003eirq_lock);\n+\tmutex_destroy(\u0026zxdh_dev-\u003elock);\n+\tzxdh_core_free_priv(zxdh_dev);\n+err_pf_dev:\n+\tdevlink_free(devlink);\n+\treturn ret;\n+}\n+\n+static void zxdh_pf_remove(struct pci_dev *pdev)\n+{\n+\tstruct zxdh_core_dev *zxdh_dev = pci_get_drvdata(pdev);\n+\tstruct devlink *devlink = priv_to_devlink(zxdh_dev);\n+\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\n+\n+\tdevlink_unregister(devlink);\n+\tzxdh_pf_modern_cfg_uninit(zxdh_dev);\n+\tzxdh_pf_pci_close(zxdh_dev);\n+\tmutex_destroy(\u0026pf_dev-\u003eirq_lock);\n+\tmutex_destroy(\u0026zxdh_dev-\u003elock);\n+\tzxdh_core_free_priv(zxdh_dev);\n+\tdevlink_free(devlink);\n+\tpci_set_drvdata(pdev, NULL);\n+}\n+\n+static void zxdh_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 zxdh_pf_driver = {\n+\t.name = \"dinghai10e\",\n+\t.id_table = zxdh_pf_pci_table,\n+\t.probe = zxdh_pf_probe,\n+\t.remove = zxdh_pf_remove,\n+\t.shutdown = zxdh_pf_shutdown,\n+};\n+\n+module_pci_driver(zxdh_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..58c5da9a09ffcc\n--- /dev/null\n+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h\n@@ -0,0 +1,101 @@\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 zxdh_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 zxdh_core_dev {\n+\tstruct device *device;\n+\tenum zxdh_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_dev {\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 *zxdh_core_alloc_priv(struct zxdh_core_dev *zxdh_dev, size_t size);\n+void zxdh_core_free_priv(struct zxdh_core_dev *zxdh_dev);\n+void zxdh_pf_pci_close(struct zxdh_core_dev *zxdh_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 zxdh_core_dev *zxdh_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 zxdh_core_dev *zxdh_dev);\n+int zxdh_pf_notify_cfg_init(struct zxdh_core_dev *zxdh_dev);\n+int zxdh_pf_device_cfg_init(struct zxdh_core_dev *zxdh_dev);\n+void zxdh_pf_modern_cfg_uninit(struct zxdh_core_dev *zxdh_dev);\n+int zxdh_pf_modern_cfg_init(struct zxdh_core_dev *zxdh_dev);\n+\n+#endif /* __ZXDH_EN_PF_H__ */\n"
} |
| 2/1 | 2026/07/20 14:32 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch introduces a new PCI driver for a specific hardware device (ZTE DingHai Ethernet controller). There is no software emulation for this hardware in QEMU or the kernel. The driver's probe function relies on finding specific vendor-specific PCI capabilities, meaning it cannot be successfully force-bound to other virtual PCI devices. Therefore, the code paths are impossible to reach in virtualized environments like GCE or QEMU.",
"WorthFuzzing": false
}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 6abd03922dbfe8b0cb047169e6f932fcef4c7911
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jul 20 14:32:22 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..10df4eb79e80e1
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/Makefile
@@ -0,0 +1,9 @@
+# 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..afac67f7147cb9
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/dh_queue.h
@@ -0,0 +1,54 @@
+/* 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__
+
+/* 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..ae5a77ddaca569
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -0,0 +1,465 @@
+// 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 zxdh_pf_devlink_ops = {};
+
+static const struct pci_device_id zxdh_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, zxdh_pf_pci_table);
+
+void *zxdh_core_alloc_priv(struct zxdh_core_dev *zxdh_dev, size_t size)
+{
+ void *priv = kzalloc(size, GFP_KERNEL);
+
+ if (priv)
+ zxdh_dev->priv = priv;
+ return priv;
+}
+
+void zxdh_core_free_priv(struct zxdh_core_dev *zxdh_dev)
+{
+ kfree(zxdh_dev->priv);
+}
+
+static int zxdh_pf_pci_init(struct zxdh_core_dev *zxdh_dev)
+{
+ struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
+ int ret;
+
+ pci_set_drvdata(zxdh_dev->pdev, zxdh_dev);
+
+ ret = pci_enable_device(zxdh_dev->pdev);
+ if (ret) {
+ dev_err(zxdh_dev->device, "pci_enable_device failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = dma_set_mask_and_coherent(zxdh_dev->device, DMA_BIT_MASK(64));
+ if (ret) {
+ ret = dma_set_mask_and_coherent(zxdh_dev->device, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(zxdh_dev->device, "dma_set_mask_and_coherent failed: %d\n", ret);
+ goto err_pci;
+ }
+ }
+
+ ret = pci_request_selected_regions(zxdh_dev->pdev,
+ pci_select_bars(zxdh_dev->pdev, IORESOURCE_MEM),
+ "dh-pf");
+ if (ret) {
+ dev_err(zxdh_dev->device, "pci_request_selected_regions failed: %d\n", ret);
+ goto err_pci;
+ }
+
+ pci_set_master(zxdh_dev->pdev);
+ ret = pci_save_state(zxdh_dev->pdev);
+ if (ret) {
+ dev_err(zxdh_dev->device, "pci_save_state failed: %d\n", ret);
+ goto err_pci_save_state;
+ }
+
+ if (!(pci_resource_flags(zxdh_dev->pdev, 0) & IORESOURCE_MEM)) {
+ ret = -ENODEV;
+ dev_err(zxdh_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(zxdh_dev->pdev, 0),
+ pci_resource_len(zxdh_dev->pdev, 0));
+ if (!pf_dev->pci_ioremap_addr[0]) {
+ ret = -ENOMEM;
+ dev_err(zxdh_dev->device, "dh pf pci ioremap failed\n");
+ goto err_pci_save_state;
+ }
+
+ return 0;
+
+err_pci_save_state:
+ pci_release_selected_regions(zxdh_dev->pdev,
+ pci_select_bars(zxdh_dev->pdev, IORESOURCE_MEM));
+err_pci:
+ pci_disable_device(zxdh_dev->pdev);
+ return ret;
+}
+
+void zxdh_pf_pci_close(struct zxdh_core_dev *zxdh_dev)
+{
+ struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
+
+ iounmap(pf_dev->pci_ioremap_addr[0]);
+ pci_release_selected_regions(zxdh_dev->pdev,
+ pci_select_bars(zxdh_dev->pdev, IORESOURCE_MEM));
+ pci_disable_device(zxdh_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 zxdh_core_dev *zxdh_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 = zxdh_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(zxdh_dev->device, "bad capability len %u (>%u expected)\n",
+ length, start);
+ return NULL;
+ }
+
+ if (length - start < minlen) {
+ dev_err(zxdh_dev->device, "bad capability len %u (>=%zu expected)\n",
+ length, minlen);
+ return NULL;
+ }
+
+ length -= start;
+ if (start + offset < offset) {
+ dev_err(zxdh_dev->device, "map wrap-around %u+%u\n", start, offset);
+ return NULL;
+ }
+
+ offset += start;
+ if (offset & (align - 1)) {
+ dev_err(zxdh_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(zxdh_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(zxdh_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 zxdh_core_dev *zxdh_dev)
+{
+ struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
+ struct pci_dev *pdev = zxdh_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(zxdh_dev->device,
+ "missing capabilities, leaving for legacy driver\n");
+ return -ENODEV;
+ }
+
+ pf_dev->common = zxdh_pf_map_capability(zxdh_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(zxdh_dev->device, "pf_dev->common is null\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int zxdh_pf_notify_cfg_init(struct zxdh_core_dev *zxdh_dev)
+{
+ struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
+ struct pci_dev *pdev = zxdh_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(zxdh_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(zxdh_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(zxdh_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 zxdh_core_dev *zxdh_dev)
+{
+ struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
+ struct pci_dev *pdev = zxdh_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(zxdh_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(zxdh_dev->device, "pf_dev->device is null\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+void zxdh_pf_modern_cfg_uninit(struct zxdh_core_dev *zxdh_dev)
+{
+ struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
+ struct pci_dev *pdev = zxdh_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 zxdh_core_dev *zxdh_dev)
+{
+ struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
+ struct pci_dev *pdev = zxdh_dev->pdev;
+ int ret;
+
+ ret = zxdh_pf_common_cfg_init(zxdh_dev);
+ if (ret) {
+ dev_err(zxdh_dev->device, "zxdh_pf_common_cfg_init failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = zxdh_pf_notify_cfg_init(zxdh_dev);
+ if (ret) {
+ dev_err(zxdh_dev->device, "zxdh_pf_notify_cfg_init failed: %d\n", ret);
+ goto err_map_notify;
+ }
+
+ ret = zxdh_pf_device_cfg_init(zxdh_dev);
+ if (ret) {
+ dev_err(zxdh_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;
+}
+
+static int zxdh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct zxdh_pf_dev *pf_dev;
+ struct zxdh_core_dev *zxdh_dev;
+ struct devlink *devlink;
+ int ret;
+
+ devlink = devlink_alloc(&zxdh_pf_devlink_ops, sizeof(struct zxdh_core_dev),
+ &pdev->dev);
+ if (!devlink) {
+ dev_err(&pdev->dev, "zxdh_pf devlink alloc failed\n");
+ return -ENOMEM;
+ }
+
+ zxdh_dev = devlink_priv(devlink);
+ zxdh_dev->device = &pdev->dev;
+ zxdh_dev->pdev = pdev;
+ zxdh_dev->devlink = devlink;
+
+ pf_dev = zxdh_core_alloc_priv(zxdh_dev, sizeof(*pf_dev));
+ if (!pf_dev) {
+ dev_err(&pdev->dev, "zxdh_pf_dev alloc failed\n");
+ ret = -ENOMEM;
+ goto err_pf_dev;
+ }
+
+ pf_dev->bar_chan_valid = false;
+ pf_dev->vepa = false;
+ mutex_init(&zxdh_dev->lock);
+ mutex_init(&pf_dev->irq_lock);
+
+ zxdh_dev->coredev_type = GET_COREDEV_TYPE(pdev);
+
+ ret = zxdh_pf_pci_init(zxdh_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "zxdh_pf_pci_init failed: %d\n", ret);
+ goto err_pf_init;
+ }
+
+ ret = zxdh_pf_modern_cfg_init(zxdh_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "zxdh_pf_modern_cfg_init failed: %d\n", ret);
+ goto err_cfg_init;
+ }
+
+ devlink_register(devlink);
+
+ return 0;
+
+err_cfg_init:
+ zxdh_pf_pci_close(zxdh_dev);
+err_pf_init:
+ mutex_destroy(&pf_dev->irq_lock);
+ mutex_destroy(&zxdh_dev->lock);
+ zxdh_core_free_priv(zxdh_dev);
+err_pf_dev:
+ devlink_free(devlink);
+ return ret;
+}
+
+static void zxdh_pf_remove(struct pci_dev *pdev)
+{
+ struct zxdh_core_dev *zxdh_dev = pci_get_drvdata(pdev);
+ struct devlink *devlink = priv_to_devlink(zxdh_dev);
+ struct zxdh_pf_dev *pf_dev = zxdh_dev->priv;
+
+ devlink_unregister(devlink);
+ zxdh_pf_modern_cfg_uninit(zxdh_dev);
+ zxdh_pf_pci_close(zxdh_dev);
+ mutex_destroy(&pf_dev->irq_lock);
+ mutex_destroy(&zxdh_dev->lock);
+ zxdh_core_free_priv(zxdh_dev);
+ devlink_free(devlink);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static void zxdh_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 zxdh_pf_driver = {
+ .name = "dinghai10e",
+ .id_table = zxdh_pf_pci_table,
+ .probe = zxdh_pf_probe,
+ .remove = zxdh_pf_remove,
+ .shutdown = zxdh_pf_shutdown,
+};
+
+module_pci_driver(zxdh_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..58c5da9a09ffcc
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h
@@ -0,0 +1,101 @@
+/* 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 zxdh_coredev_type {
+ DH_COREDEV_PF,
+ DH_COREDEV_VF,
+ DH_COREDEV_SF,
+ DH_COREDEV_MPF
+};
+
+struct devlink;
+
+struct zxdh_core_dev {
+ struct device *device;
+ enum zxdh_coredev_type coredev_type;
+ struct pci_dev *pdev;
+ struct devlink *devlink;
+ struct mutex lock; /* Protects device configuration */
+ void *priv;
+};
+
+struct zxdh_pf_dev {
+ 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 *zxdh_core_alloc_priv(struct zxdh_core_dev *zxdh_dev, size_t size);
+void zxdh_core_free_priv(struct zxdh_core_dev *zxdh_dev);
+void zxdh_pf_pci_close(struct zxdh_core_dev *zxdh_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 zxdh_core_dev *zxdh_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 zxdh_core_dev *zxdh_dev);
+int zxdh_pf_notify_cfg_init(struct zxdh_core_dev *zxdh_dev);
+int zxdh_pf_device_cfg_init(struct zxdh_core_dev *zxdh_dev);
+void zxdh_pf_modern_cfg_uninit(struct zxdh_core_dev *zxdh_dev);
+int zxdh_pf_modern_cfg_init(struct zxdh_core_dev *zxdh_dev);
+
+#endif /* __ZXDH_EN_PF_H__ */
|
| 3/2 | 2026/07/20 14:32 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11396 output: 27 thoughts: 2749 Thoughts: **Unreachable Code Paths: The ZTE DingHai Ethernet Driver** Okay, so we have this new Ethernet driver for ZTE DingHai devices, which seems to be a PCI driver. It implements the standard PCI probe, remove, and shutdown functions. It's registered with `pci_register_driver` and includes the necessary Kconfig and Makefile entries, plus the core driver files. The driver specifically targets a PCI Ethernet controller from ZTE (Vendor ID 0x1cf2, Device ID 0x8040). My immediate concern, as always, is fuzzing. Given it's a PCI driver, it should be fuzzable. The question is how to get the `zxdh_pf_probe` function to run. I immediately start thinking about syzkaller. Does syzkaller have good PCI fuzzing capabilities? Syzkaller supports PCI fuzzing, right? Syzkaller uses `syz_pci` pseudo-syscalls or something similar for PCI fuzzing, or does it rely on QEMU PCI emulation? Let's be sure, `syz_pci_device_add` or similar. I'm trying to remember the specifics of syzkaller's PCI support. Then I come back to the prompt, which highlights the difficulty of reaching drivers for specific hardware in virtualized environments like GCE or QEMU. That's a key point. This DingHai device *is* specific hardware. There's probably no QEMU emulation for this device. No, no `syz_pci`. The prompt is right. So, can we even probe this thing without the physical hardware? No. The next thing that jumps to my mind is: can we exploit some kind of software emulation for this device? Is there a virtio-like structure? Let's check. Yes, the driver interacts with the PCI config space. It specifically looks for vendor-specific capabilities. The more I look, the more it resembles a virtio-net implementation but through vendor-specific PCI capabilities. But the driver requires a very specific Vendor and Device ID. Standard virtio-net devices (Vendor 0x1af4, Device 0x1000/0x1041) will not trigger this driver. So it's a dead end if we are running in QEMU. And syzkaller has a real problem. Syzkaller cannot create the PCI device by itself. The `zxdh_pf_probe` will never be called if the PCI subsystem can't find a device with ID 0x1cf2:0x8040. There is no such device in QEMU, so it looks impossible to reach. Wait, can we inject a PCI device with the `new_id` sysfs attribute? Nope, it can only *bind* the driver to *existing* devices. It doesn't create new ones. We still need the right kind of PCI device. If we bound it to another device, it would trigger `zxdh_pf_probe` but it is unlikely to match the exact structure. I'm starting to remember that syzkaller has to rely on QEMU's PCI emulation or `vfio`. If the device is not emulated, the code is unreachable. This is bad news, it is hard to fuzz without device emulation. It will not work. Is there any way? Does the driver register a `devlink` instance? Yes, but only *inside* `zxdh_pf_probe`. So if the probe function isn't called, we can't reach the `devlink` instance either. So it won't be reachable via netlink either. Is there any way to emulate the driver by using something like a virtual host bridge? No, there is no generic PCI host bridge in the kernel that would allow to inject this specific device. I've got to face the music: without specific emulation for this ZTE DingHai card, this driver is effectively unreachable in GCE/QEMU, thus making effective fuzzing problematic, if not impossible. We need a way to emulate this specific device, so it can be reached. This seems to be a hardware driver. |
| 4/2 | 2026/07/20 14:32 | tool | grepper |
0mArgs:{
"Expression": "zxdh",
"PathPrefix": "drivers/net/"
}Results: {
"Output": "drivers/net/ethernet/zte/dinghai/dh_queue.h-10-/* This is the PCI capability header: */\ndrivers/net/ethernet/zte/dinghai/dh_queue.h:11:struct zxdh_pf_pci_cap {\ndrivers/net/ethernet/zte/dinghai/dh_queue.h-12-\t__u8 cap_vndr;\t\t/* Generic PCI field: PCI_CAP_ID_VNDR */\n--\ndrivers/net/ethernet/zte/dinghai/dh_queue.h-23-/* Fields in ZXDH_PF_PCI_CAP_COMMON_CFG: */\ndrivers/net/ethernet/zte/dinghai/dh_queue.h:24:struct zxdh_pf_pci_common_cfg {\ndrivers/net/ethernet/zte/dinghai/dh_queue.h-25-\t/* About the whole device. */\n--\ndrivers/net/ethernet/zte/dinghai/dh_queue.h-48-\ndrivers/net/ethernet/zte/dinghai/dh_queue.h:49:struct zxdh_pf_pci_notify_cap {\ndrivers/net/ethernet/zte/dinghai/dh_queue.h:50:\tstruct zxdh_pf_pci_cap cap;\ndrivers/net/ethernet/zte/dinghai/dh_queue.h-51-\t__le32 notify_off_multiplier; /* Multiplier for queue_notify_off. */\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c=17=MODULE_LICENSE(\"GPL\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-18-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:19:static const struct devlink_ops zxdh_pf_devlink_ops = {};\ndrivers/net/ethernet/zte/dinghai/en_pf.c-20-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:21:static const struct pci_device_id zxdh_pf_pci_table[] = {\ndrivers/net/ethernet/zte/dinghai/en_pf.c-22-\t{ PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_PF_DEVICE_ID) },\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-26-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:27:MODULE_DEVICE_TABLE(pci, zxdh_pf_pci_table);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-28-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:29:void *zxdh_core_alloc_priv(struct zxdh_core_dev *zxdh_dev, size_t size)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-30-{\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-33-\tif (priv)\ndrivers/net/ethernet/zte/dinghai/en_pf.c:34:\t\tzxdh_dev-\u003epriv = priv;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-35-\treturn priv;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-37-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:38:void zxdh_core_free_priv(struct zxdh_core_dev *zxdh_dev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-39-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:40:\tkfree(zxdh_dev-\u003epriv);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-41-}\ndrivers/net/ethernet/zte/dinghai/en_pf.c-42-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:43:static int zxdh_pf_pci_init(struct zxdh_core_dev *zxdh_dev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-44-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:45:\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-46-\tint ret;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-47-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:48:\tpci_set_drvdata(zxdh_dev-\u003epdev, zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-49-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:50:\tret = pci_enable_device(zxdh_dev-\u003epdev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-51-\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:52:\t\tdev_err(zxdh_dev-\u003edevice, \"pci_enable_device failed: %d\\n\", ret);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-53-\t\treturn ret;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-55-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:56:\tret = dma_set_mask_and_coherent(zxdh_dev-\u003edevice, DMA_BIT_MASK(64));\ndrivers/net/ethernet/zte/dinghai/en_pf.c-57-\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:58:\t\tret = dma_set_mask_and_coherent(zxdh_dev-\u003edevice, DMA_BIT_MASK(32));\ndrivers/net/ethernet/zte/dinghai/en_pf.c-59-\t\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:60:\t\t\tdev_err(zxdh_dev-\u003edevice, \"dma_set_mask_and_coherent failed: %d\\n\", ret);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-61-\t\t\tgoto err_pci;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-64-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:65:\tret = pci_request_selected_regions(zxdh_dev-\u003epdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:66:\t\t\t\t\t pci_select_bars(zxdh_dev-\u003epdev, IORESOURCE_MEM),\ndrivers/net/ethernet/zte/dinghai/en_pf.c-67-\t\t\t\t\t \"dh-pf\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-68-\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:69:\t\tdev_err(zxdh_dev-\u003edevice, \"pci_request_selected_regions failed: %d\\n\", ret);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-70-\t\tgoto err_pci;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-72-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:73:\tpci_set_master(zxdh_dev-\u003epdev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:74:\tret = pci_save_state(zxdh_dev-\u003epdev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-75-\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:76:\t\tdev_err(zxdh_dev-\u003edevice, \"pci_save_state failed: %d\\n\", ret);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-77-\t\tgoto err_pci_save_state;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-79-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:80:\tif (!(pci_resource_flags(zxdh_dev-\u003epdev, 0) \u0026 IORESOURCE_MEM)) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c-81-\t\tret = -ENODEV;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:82:\t\tdev_err(zxdh_dev-\u003edevice, \"BAR 0 is not an MMIO resource\\n\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-83-\t\tgoto err_pci_save_state;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-86-\tpf_dev-\u003epci_ioremap_addr[0] =\ndrivers/net/ethernet/zte/dinghai/en_pf.c:87:\t\tioremap(pci_resource_start(zxdh_dev-\u003epdev, 0),\ndrivers/net/ethernet/zte/dinghai/en_pf.c:88:\t\t\tpci_resource_len(zxdh_dev-\u003epdev, 0));\ndrivers/net/ethernet/zte/dinghai/en_pf.c-89-\tif (!pf_dev-\u003epci_ioremap_addr[0]) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c-90-\t\tret = -ENOMEM;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:91:\t\tdev_err(zxdh_dev-\u003edevice, \"dh pf pci ioremap failed\\n\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-92-\t\tgoto err_pci_save_state;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-97-err_pci_save_state:\ndrivers/net/ethernet/zte/dinghai/en_pf.c:98:\tpci_release_selected_regions(zxdh_dev-\u003epdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:99:\t\t\t\t pci_select_bars(zxdh_dev-\u003epdev, IORESOURCE_MEM));\ndrivers/net/ethernet/zte/dinghai/en_pf.c-100-err_pci:\ndrivers/net/ethernet/zte/dinghai/en_pf.c:101:\tpci_disable_device(zxdh_dev-\u003epdev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-102-\treturn ret;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-104-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:105:void zxdh_pf_pci_close(struct zxdh_core_dev *zxdh_dev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-106-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:107:\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-108-\ndrivers/net/ethernet/zte/dinghai/en_pf.c-109-\tiounmap(pf_dev-\u003epci_ioremap_addr[0]);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:110:\tpci_release_selected_regions(zxdh_dev-\u003epdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:111:\t\t\t\t pci_select_bars(zxdh_dev-\u003epdev, IORESOURCE_MEM));\ndrivers/net/ethernet/zte/dinghai/en_pf.c:112:\tpci_disable_device(zxdh_dev-\u003epdev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-113-}\ndrivers/net/ethernet/zte/dinghai/en_pf.c-114-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:115:int zxdh_pf_pci_find_capability(struct pci_dev *pdev, u8 cfg_type,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-116-\t\t\t\tu32 ioresource_types, int *bars)\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-124-\t\tpci_read_config_byte(pdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:125:\t\t\t\t pos + offsetof(struct zxdh_pf_pci_cap,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-126-\t\t\t\t\t\t\tcfg_type), \u0026type);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-127-\t\tpci_read_config_byte(pdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:128:\t\t\t\t pos + offsetof(struct zxdh_pf_pci_cap, bar), \u0026bar);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-129-\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-145-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:146:void __iomem *zxdh_pf_map_capability(struct zxdh_core_dev *zxdh_dev, int off,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-147-\t\t\t\t size_t minlen, u32 align,\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-151-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:152:\tstruct pci_dev *pdev = zxdh_dev-\u003epdev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-153-\tvoid __iomem *p;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-158-\tpci_read_config_byte(pdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:159:\t\t\t off + offsetof(struct zxdh_pf_pci_cap, bar), \u0026bar);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-160-\tpci_read_config_dword(pdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:161:\t\t\t off + offsetof(struct zxdh_pf_pci_cap,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-162-\t\t\t\t\t\toffset), \u0026offset);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-163-\tpci_read_config_dword(pdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:164:\t\t\t off + offsetof(struct zxdh_pf_pci_cap,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-165-\t\t\t\t\t\tlength), \u0026length);\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-170-\tif (length \u003c= start) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:171:\t\tdev_err(zxdh_dev-\u003edevice, \"bad capability len %u (\u003e%u expected)\\n\",\ndrivers/net/ethernet/zte/dinghai/en_pf.c-172-\t\t\tlength, start);\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-176-\tif (length - start \u003c minlen) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:177:\t\tdev_err(zxdh_dev-\u003edevice, \"bad capability len %u (\u003e=%zu expected)\\n\",\ndrivers/net/ethernet/zte/dinghai/en_pf.c-178-\t\t\tlength, minlen);\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-183-\tif (start + offset \u003c offset) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:184:\t\tdev_err(zxdh_dev-\u003edevice, \"map wrap-around %u+%u\\n\", start, offset);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-185-\t\treturn NULL;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-189-\tif (offset \u0026 (align - 1)) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:190:\t\tdev_err(zxdh_dev-\u003edevice, \"offset %u not aligned to %u\\n\", offset, align);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-191-\t\treturn NULL;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-201-\t minlen + offset \u003e pci_resource_len(pdev, bar)) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:202:\t\tdev_err(zxdh_dev-\u003edevice,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-203-\t\t\t\"map custom queue %zu@%u out of range on bar %u length %lu\\n\",\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-210-\tif (!p) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:211:\t\tdev_err(zxdh_dev-\u003edevice, \"unable to map custom queue %u@%u on bar %u\\n\",\ndrivers/net/ethernet/zte/dinghai/en_pf.c-212-\t\t\tlength, offset, bar);\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-219-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:220:int zxdh_pf_common_cfg_init(struct zxdh_core_dev *zxdh_dev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-221-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:222:\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:223:\tstruct pci_dev *pdev = zxdh_dev-\u003epdev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-224-\tint common;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-226-\t/* check for a common config: if not, use legacy mode (bar 0). */\ndrivers/net/ethernet/zte/dinghai/en_pf.c:227:\tcommon = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_COMMON_CFG,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-228-\t\t\t\t\t IORESOURCE_IO | IORESOURCE_MEM,\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-230-\tif (!common) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:231:\t\tdev_err(zxdh_dev-\u003edevice,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-232-\t\t\t\"missing capabilities, leaving for legacy driver\\n\");\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-235-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:236:\tpf_dev-\u003ecommon = zxdh_pf_map_capability(zxdh_dev, common,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:237:\t\t\t\t\t\tsizeof(struct zxdh_pf_pci_common_cfg),\ndrivers/net/ethernet/zte/dinghai/en_pf.c-238-\t\t\t\t\t\tZXDH_PF_ALIGN4, 0,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:239:\t\t\t\t\t\tsizeof(struct zxdh_pf_pci_common_cfg),\ndrivers/net/ethernet/zte/dinghai/en_pf.c-240-\t\t\t\t\t\tNULL, NULL, NULL);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-241-\tif (!pf_dev-\u003ecommon) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:242:\t\tdev_err(zxdh_dev-\u003edevice, \"pf_dev-\u003ecommon is null\\n\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-243-\t\treturn -EINVAL;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-248-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:249:int zxdh_pf_notify_cfg_init(struct zxdh_core_dev *zxdh_dev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-250-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:251:\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:252:\tstruct pci_dev *pdev = zxdh_dev-\u003epdev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-253-\tu32 notify_length;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-257-\t/* If common is there, these should be too... */\ndrivers/net/ethernet/zte/dinghai/en_pf.c:258:\tnotify = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_NOTIFY_CFG,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-259-\t\t\t\t\t IORESOURCE_IO | IORESOURCE_MEM,\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-261-\tif (!notify) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:262:\t\tdev_err(zxdh_dev-\u003edevice, \"missing notify cfg capability\\n\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-263-\t\treturn -EINVAL;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-266-\tpci_read_config_dword(pdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:267:\t\t\t notify + offsetof(struct zxdh_pf_pci_notify_cap,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-268-\t\t\t\tnotify_off_multiplier),\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-270-\tpci_read_config_dword(pdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:271:\t\t\t notify + offsetof(struct zxdh_pf_pci_notify_cap,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-272-\t\t\t\tcap.length), \u0026notify_length);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-273-\tpci_read_config_dword(pdev,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:274:\t\t\t notify + offsetof(struct zxdh_pf_pci_notify_cap,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-275-\t\t\t\tcap.offset), \u0026notify_offset);\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-281-\tif (notify_length + (notify_offset % PAGE_SIZE) \u003c= PAGE_SIZE) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:282:\t\tpf_dev-\u003enotify_base = zxdh_pf_map_capability(zxdh_dev, notify,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-283-\t\t\t\t\t\t\t ZXDH_PF_MAP_MINLEN2,\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-288-\t\tif (!pf_dev-\u003enotify_base) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:289:\t\t\tdev_err(zxdh_dev-\u003edevice, \"pf_dev-\u003enotify_base is null\\n\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-290-\t\t\treturn -EINVAL;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-298-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:299:int zxdh_pf_device_cfg_init(struct zxdh_core_dev *zxdh_dev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-300-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:301:\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:302:\tstruct pci_dev *pdev = zxdh_dev-\u003epdev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-303-\tint device;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-307-\t */\ndrivers/net/ethernet/zte/dinghai/en_pf.c:308:\tdevice = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_DEVICE_CFG,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-309-\t\t\t\t\t IORESOURCE_IO | IORESOURCE_MEM,\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-315-\tif (device) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:316:\t\tpf_dev-\u003edevice = zxdh_pf_map_capability(zxdh_dev, device, 0,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-317-\t\t\t\t\t\t\tZXDH_PF_ALIGN4, 0, PAGE_SIZE,\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-320-\t\tif (!pf_dev-\u003edevice) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:321:\t\t\tdev_err(zxdh_dev-\u003edevice, \"pf_dev-\u003edevice is null\\n\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-322-\t\t\treturn -EINVAL;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-327-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:328:void zxdh_pf_modern_cfg_uninit(struct zxdh_core_dev *zxdh_dev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-329-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:330:\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:331:\tstruct pci_dev *pdev = zxdh_dev-\u003epdev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-332-\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 zxdh_core_dev *zxdh_dev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-341-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:342:\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:343:\tstruct pci_dev *pdev = zxdh_dev-\u003epdev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-344-\tint ret;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-345-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:346:\tret = zxdh_pf_common_cfg_init(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-347-\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:348:\t\tdev_err(zxdh_dev-\u003edevice, \"zxdh_pf_common_cfg_init failed: %d\\n\", ret);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-349-\t\treturn ret;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-351-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:352:\tret = zxdh_pf_notify_cfg_init(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-353-\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:354:\t\tdev_err(zxdh_dev-\u003edevice, \"zxdh_pf_notify_cfg_init failed: %d\\n\", ret);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-355-\t\tgoto err_map_notify;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-357-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:358:\tret = zxdh_pf_device_cfg_init(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-359-\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:360:\t\tdev_err(zxdh_dev-\u003edevice, \"zxdh_pf_device_cfg_init failed: %d\\n\", ret);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-361-\t\tgoto err_map_device;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-373-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:374:static int zxdh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-375-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:376:\tstruct zxdh_pf_dev *pf_dev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:377:\tstruct zxdh_core_dev *zxdh_dev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-378-\tstruct devlink *devlink;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-380-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:381:\tdevlink = devlink_alloc(\u0026zxdh_pf_devlink_ops, sizeof(struct zxdh_core_dev),\ndrivers/net/ethernet/zte/dinghai/en_pf.c-382-\t\t\t\t\u0026pdev-\u003edev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-383-\tif (!devlink) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:384:\t\tdev_err(\u0026pdev-\u003edev, \"zxdh_pf devlink alloc failed\\n\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-385-\t\treturn -ENOMEM;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-387-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:388:\tzxdh_dev = devlink_priv(devlink);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:389:\tzxdh_dev-\u003edevice = \u0026pdev-\u003edev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:390:\tzxdh_dev-\u003epdev = pdev;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:391:\tzxdh_dev-\u003edevlink = devlink;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-392-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:393:\tpf_dev = zxdh_core_alloc_priv(zxdh_dev, sizeof(*pf_dev));\ndrivers/net/ethernet/zte/dinghai/en_pf.c-394-\tif (!pf_dev) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:395:\t\tdev_err(\u0026pdev-\u003edev, \"zxdh_pf_dev alloc failed\\n\");\ndrivers/net/ethernet/zte/dinghai/en_pf.c-396-\t\tret = -ENOMEM;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-401-\tpf_dev-\u003evepa = false;\ndrivers/net/ethernet/zte/dinghai/en_pf.c:402:\tmutex_init(\u0026zxdh_dev-\u003elock);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-403-\tmutex_init(\u0026pf_dev-\u003eirq_lock);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-404-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:405:\tzxdh_dev-\u003ecoredev_type = GET_COREDEV_TYPE(pdev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-406-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:407:\tret = zxdh_pf_pci_init(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-408-\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:409:\t\tdev_err(\u0026pdev-\u003edev, \"zxdh_pf_pci_init failed: %d\\n\", ret);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-410-\t\tgoto err_pf_init;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-412-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:413:\tret = zxdh_pf_modern_cfg_init(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-414-\tif (ret) {\ndrivers/net/ethernet/zte/dinghai/en_pf.c:415:\t\tdev_err(\u0026pdev-\u003edev, \"zxdh_pf_modern_cfg_init failed: %d\\n\", ret);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-416-\t\tgoto err_cfg_init;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-423-err_cfg_init:\ndrivers/net/ethernet/zte/dinghai/en_pf.c:424:\tzxdh_pf_pci_close(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-425-err_pf_init:\ndrivers/net/ethernet/zte/dinghai/en_pf.c-426-\tmutex_destroy(\u0026pf_dev-\u003eirq_lock);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:427:\tmutex_destroy(\u0026zxdh_dev-\u003elock);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:428:\tzxdh_core_free_priv(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-429-err_pf_dev:\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-433-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:434:static void zxdh_pf_remove(struct pci_dev *pdev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-435-{\ndrivers/net/ethernet/zte/dinghai/en_pf.c:436:\tstruct zxdh_core_dev *zxdh_dev = pci_get_drvdata(pdev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:437:\tstruct devlink *devlink = priv_to_devlink(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:438:\tstruct zxdh_pf_dev *pf_dev = zxdh_dev-\u003epriv;\ndrivers/net/ethernet/zte/dinghai/en_pf.c-439-\ndrivers/net/ethernet/zte/dinghai/en_pf.c-440-\tdevlink_unregister(devlink);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:441:\tzxdh_pf_modern_cfg_uninit(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:442:\tzxdh_pf_pci_close(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-443-\tmutex_destroy(\u0026pf_dev-\u003eirq_lock);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:444:\tmutex_destroy(\u0026zxdh_dev-\u003elock);\ndrivers/net/ethernet/zte/dinghai/en_pf.c:445:\tzxdh_core_free_priv(zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.c-446-\tdevlink_free(devlink);\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-449-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:450:static void zxdh_pf_shutdown(struct pci_dev *pdev)\ndrivers/net/ethernet/zte/dinghai/en_pf.c-451-{\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.c-456-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:457:static struct pci_driver zxdh_pf_driver = {\ndrivers/net/ethernet/zte/dinghai/en_pf.c-458-\t.name = \"dinghai10e\",\ndrivers/net/ethernet/zte/dinghai/en_pf.c:459:\t.id_table = zxdh_pf_pci_table,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:460:\t.probe = zxdh_pf_probe,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:461:\t.remove = zxdh_pf_remove,\ndrivers/net/ethernet/zte/dinghai/en_pf.c:462:\t.shutdown = zxdh_pf_shutdown,\ndrivers/net/ethernet/zte/dinghai/en_pf.c-463-};\ndrivers/net/ethernet/zte/dinghai/en_pf.c-464-\ndrivers/net/ethernet/zte/dinghai/en_pf.c:465:module_pci_driver(zxdh_pf_driver);\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.h-37-\ndrivers/net/ethernet/zte/dinghai/en_pf.h:38:enum zxdh_coredev_type {\ndrivers/net/ethernet/zte/dinghai/en_pf.h-39-\tDH_COREDEV_PF,\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.h=45=struct devlink;\ndrivers/net/ethernet/zte/dinghai/en_pf.h-46-\ndrivers/net/ethernet/zte/dinghai/en_pf.h:47:struct zxdh_core_dev {\ndrivers/net/ethernet/zte/dinghai/en_pf.h-48-\tstruct device *device;\ndrivers/net/ethernet/zte/dinghai/en_pf.h:49:\tenum zxdh_coredev_type coredev_type;\ndrivers/net/ethernet/zte/dinghai/en_pf.h-50-\tstruct pci_dev *pdev;\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.h-55-\ndrivers/net/ethernet/zte/dinghai/en_pf.h:56:struct zxdh_pf_dev {\ndrivers/net/ethernet/zte/dinghai/en_pf.h:57:\tstruct zxdh_pf_pci_common_cfg __iomem *common;\ndrivers/net/ethernet/zte/dinghai/en_pf.h-58-\t/* Device-specific data (non-legacy mode) */\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.h-84-\ndrivers/net/ethernet/zte/dinghai/en_pf.h:85:void *zxdh_core_alloc_priv(struct zxdh_core_dev *zxdh_dev, size_t size);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:86:void zxdh_core_free_priv(struct zxdh_core_dev *zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:87:void zxdh_pf_pci_close(struct zxdh_core_dev *zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:88:int zxdh_pf_pci_find_capability(struct pci_dev *pdev, u8 cfg_type,\ndrivers/net/ethernet/zte/dinghai/en_pf.h-89-\t\t\t\tu32 ioresource_types, int *bars);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:90:void __iomem *zxdh_pf_map_capability(struct zxdh_core_dev *zxdh_dev, int off,\ndrivers/net/ethernet/zte/dinghai/en_pf.h-91-\t\t\t\t size_t minlen, u32 align,\n--\ndrivers/net/ethernet/zte/dinghai/en_pf.h-94-\t\t\t\t u32 *bar_off);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:95:int zxdh_pf_common_cfg_init(struct zxdh_core_dev *zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:96:int zxdh_pf_notify_cfg_init(struct zxdh_core_dev *zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:97:int zxdh_pf_device_cfg_init(struct zxdh_core_dev *zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:98:void zxdh_pf_modern_cfg_uninit(struct zxdh_core_dev *zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.h:99:int zxdh_pf_modern_cfg_init(struct zxdh_core_dev *zxdh_dev);\ndrivers/net/ethernet/zte/dinghai/en_pf.h-100-\n"
} |
| 5/2 | 2026/07/20 14:33 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 26664 output: 118 thoughts: 313 Thoughts: **Unreachable Driver in a Virtualized Environment** Okay, so I've taken a look at this driver – it's a PCI driver specifically for the ZTE DingHai Ethernet controller. The key thing here is that there's no software emulation of this device in either QEMU or within the kernel itself. That immediately raises a red flag. The `zxdh_pf_probe` function is the entry point, and it's only going to be invoked if it detects a PCI device with a very specific Vendor ID (0x1cf2) and Device ID (0x8040 or 0x8041). I could try to force it to bind to a different PCI device using `new_id`, but I know that won't work. The probe function explicitly checks for some vendor-specific PCI capabilities (`ZXDH_PCI_CAP_COMMON_CFG`, and so on) that won't be present on any other hardware. Essentially, the driver expects *that* specific hardware. Therefore, under no circumstances will this driver's code paths be reachable in environments like Google Compute Engine or QEMU. It's a hardware-dependent driver, and we don't have that hardware available in these virtualized contexts. Just to be absolutely sure, I've double-checked. Is there a "zxdh" virtual device? Nope. Is there a netlink interface I might leverage that doesn't depend on the device being probed first? No luck there either. The devlink interface, that's registered within `zxdh_pf_probe`, so it requires probe to succeed. So there is no way around this. The probe needs those specific PCI capabilities, and that's the hard stop. So, I'm confident in saying that this is not worth fuzzing. I'm setting `WorthFuzzing=false` and that's that. |
| 6/2 | 2026/07/20 14:33 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch introduces a new PCI driver for a specific hardware device (ZTE DingHai Ethernet controller). There is no software emulation for this hardware in QEMU or the kernel. The driver's probe function relies on finding specific vendor-specific PCI capabilities, meaning it cannot be successfully force-bound to other virtual PCI devices. Therefore, the code paths are impossible to reach in virtualized environments like GCE or QEMU.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch introduces a new PCI driver for a specific hardware device (ZTE DingHai Ethernet controller). There is no software emulation for this hardware in QEMU or the kernel. The driver's probe function relies on finding specific vendor-specific PCI capabilities, meaning it cannot be successfully force-bound to other virtual PCI devices. Therefore, the code paths are impossible to reach in virtualized environments like GCE or QEMU.",
"WorthFuzzing": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|