* [PATCH net-next v2 1/3] net/ethernet: add ZTE network driver support
2026-04-22 14:48 [PATCH net-next v2 0/3] Add ZTE DingHai Ethernet PF driver Junyang Han
@ 2026-04-22 14:48 ` Junyang Han
2026-04-22 16:24 ` Andrew Lunn
2026-04-22 14:49 ` [PATCH net-next v2 2/3] net/ethernet/zte/dinghai: add logging infrastructure Junyang Han
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Junyang Han @ 2026-04-22 14:48 UTC (permalink / raw)
To: netdev
Cc: davem, andrew+netdev, edumazet, kuba, pabeni, han.junyang,
ran.ming, han.chengfei, zhang.yanze
[-- Attachment #1.1.1: Type: text/plain, Size: 11298 bytes --]
Add basic framework for ZTE DingHai ethernet PF driver, including
Kconfig/Makefile build support and PCIe device probe/remove skeleton.
Signed-off-by: Junyang Han <han.junyang@zte.com.cn>
---
MAINTAINERS | 6 +
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/zte/Kconfig | 20 +++
drivers/net/ethernet/zte/Makefile | 6 +
drivers/net/ethernet/zte/dinghai/Kconfig | 34 +++++
drivers/net/ethernet/zte/dinghai/Makefile | 10 ++
drivers/net/ethernet/zte/dinghai/en_pf.c | 162 ++++++++++++++++++++++
drivers/net/ethernet/zte/dinghai/en_pf.h | 62 +++++++++
9 files changed, 302 insertions(+)
create mode 100644 drivers/net/ethernet/zte/Kconfig
create mode 100644 drivers/net/ethernet/zte/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/Kconfig
create mode 100644 drivers/net/ethernet/zte/dinghai/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.c
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 65902b97f5df..92ddac4bb310 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29210,6 +29210,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 bdc29d143160..ecc6fbb01510 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -190,5 +190,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 6bffb60ba644..7476af77d6c8 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -106,3 +106,4 @@ obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/
obj-$(CONFIG_OA_TC6) += oa_tc6.o
+obj-$(CONFIG_NET_VENDOR_ZTE) += zte/
diff --git a/drivers/net/ethernet/zte/Kconfig b/drivers/net/ethernet/zte/Kconfig
new file mode 100644
index 000000000000..b95c2fc7db77
--- /dev/null
+++ b/drivers/net/ethernet/zte/Kconfig
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# ZTE driver configuration
+#
+
+config NET_VENDOR_ZTE
+ bool "ZTE devices"
+ default y
+ help
+ If you have a network (Ethernet) card belonging to this class, say Y.
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Zte cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_ZTE
+
+source "drivers/net/ethernet/zte/dinghai/Kconfig"
+
+endif # NET_VENDOR_ZTE
diff --git a/drivers/net/ethernet/zte/Makefile b/drivers/net/ethernet/zte/Makefile
new file mode 100644
index 000000000000..cd9929b61559
--- /dev/null
+++ b/drivers/net/ethernet/zte/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the ZTE device drivers
+#
+
+obj-$(CONFIG_DINGHAI) += dinghai/
diff --git a/drivers/net/ethernet/zte/dinghai/Kconfig b/drivers/net/ethernet/zte/dinghai/Kconfig
new file mode 100644
index 000000000000..94b5bd9b3c50
--- /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 NET_VENDOR_ZTE && PCI
+ select NET_DEVLINK
+ help
+ This driver supports ZTE DingHai Ethernet devices.
+
+ DingHai is a high-performance Ethernet controller that supports
+ multiple features including hardware offloading, SR-IOV, and
+ advanced virtualization capabilities.
+
+ If you say Y here, you can select specific driver variants below.
+
+ If unsure, say N.
+
+if DINGHAI
+
+config DINGHAI_PF
+ tristate "ZTE DingHai PF (Physical Function) driver"
+ help
+ This driver supports ZTE DingHai PCI Express Ethernet
+ adapters (PF).
+
+ To compile this driver as a module, choose M here. The module
+ will be named dinghai10e.
+
+ If unsure, say N.
+
+endif # DINGHAI
diff --git a/drivers/net/ethernet/zte/dinghai/Makefile b/drivers/net/ethernet/zte/dinghai/Makefile
new file mode 100644
index 000000000000..f55a8de518be
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for ZTE DingHai Ethernet driver
+#
+
+ccflags-y += -I$(src)
+
+obj-$(CONFIG_DINGHAI_PF) += dinghai10e.o
+dinghai10e-y := en_pf.o
+
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.c b/drivers/net/ethernet/zte/dinghai/en_pf.c
new file mode 100644
index 000000000000..5e13a8c24a28
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -0,0 +1,162 @@
+// 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 "en_pf.h"
+
+MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
+MODULE_DESCRIPTION("ZTE Corporation network adapters (DingHai series) Ethernet driver");
+MODULE_LICENSE("GPL");
+
+static const struct devlink_ops dh_pf_devlink_ops = {};
+
+const struct pci_device_id dh_pf_pci_table[] = {
+ { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_PF_DEVICE_ID), 0 },
+ { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_VF_DEVICE_ID), 0 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, dh_pf_pci_table);
+
+static int dh_pf_pci_init(struct dh_core_dev *dev)
+{
+ struct zxdh_pf_device *pf_dev = NULL;
+ int ret = 0;
+
+ pci_set_drvdata(dev->pdev, dev);
+
+ ret = pci_enable_device(dev->pdev);
+ if (ret)
+ return -ENOMEM;
+
+ 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)
+ goto err_pci;
+ }
+
+ ret = pci_request_selected_regions(dev->pdev,
+ pci_select_bars(dev->pdev, IORESOURCE_MEM),
+ "dh-pf");
+ if (ret)
+ goto err_pci;
+
+ pci_set_master(dev->pdev);
+ ret = pci_save_state(dev->pdev);
+ if (ret)
+ goto err_pci_save_state;
+
+ pf_dev = dev->priv;
+ pf_dev->pci_ioremap_addr[0] =
+ (uint64_t)ioremap(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
+ if (!pf_dev->pci_ioremap_addr[0]) {
+ ret = -ENOMEM;
+ 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 = NULL;
+
+ pf_dev = dev->priv;
+ iounmap((void *)pf_dev->pci_ioremap_addr[0]);
+ pci_release_selected_regions(dev->pdev, pci_select_bars(dev->pdev, IORESOURCE_MEM));
+ pci_disable_device(dev->pdev);
+}
+
+static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct dh_core_dev *dh_dev = NULL;
+ struct zxdh_pf_device *pf_dev = NULL;
+ struct devlink *devlink = NULL;
+ int ret = 0;
+
+ devlink = devlink_alloc(&dh_pf_devlink_ops, sizeof(struct dh_core_dev),
+ &pdev->dev);
+ if (!devlink)
+ 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)
+ return -ENOMEM;
+
+ 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)
+ goto err_cfg_init;
+
+ return 0;
+
+err_cfg_init:
+ mutex_destroy(&pf_dev->irq_lock);
+ mutex_destroy(&dh_dev->lock);
+ dh_core_free_priv(dh_dev);
+ devlink_free(devlink);
+ return -EPERM;
+}
+
+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;
+
+ 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)
+{
+ 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;
+
+ 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 struct pci_driver dh_pf_driver = {
+ .name = "dinghai10e",
+ .id_table = dh_pf_pci_table,
+ .probe = dh_pf_probe,
+ .remove = dh_pf_remove,
+ .shutdown = dh_pf_shutdown,
+};
+
+module_pci_driver(dh_pf_driver);
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.h b/drivers/net/ethernet/zte/dinghai/en_pf.h
new file mode 100644
index 000000000000..a8b324adb948
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h
@@ -0,0 +1,62 @@
+/* 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>
+
+#define ZXDH_PF_VENDOR_ID 0x1cf2
+#define ZXDH_PF_DEVICE_ID 0x8040
+#define ZXDH_VF_DEVICE_ID 0x8041
+
+enum dh_coredev_type {
+ DH_COREDEV_PF,
+ DH_COREDEV_VF,
+ DH_COREDEV_SF,
+ DH_COREDEV_MPF
+};
+
+struct devlink;
+
+struct dh_core_dev {
+ struct device *device;
+ enum dh_coredev_type coredev_type;
+ struct pci_dev *pdev;
+ struct devlink *devlink;
+ struct mutex lock; /* Protects device configuration */
+ void *priv;
+};
+
+struct zxdh_pf_device {
+ uint64_t pci_ioremap_addr[6];
+ bool bar_chan_valid;
+ bool vepa;
+ struct mutex irq_lock; /* Protects IRQ operations */
+};
+
+static inline 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;
+}
+
+static inline void dh_core_free_priv(struct dh_core_dev *dh_dev)
+{
+ kfree(dh_dev->priv);
+ dh_dev->priv = NULL;
+}
+
+#define GET_COREDEV_TYPE(pdev) \
+ ((pdev)->device == ZXDH_VF_DEVICE_ID ? DH_COREDEV_VF : DH_COREDEV_PF)
+
+#endif
+
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 21496 bytes --]
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH net-next v2 1/3] net/ethernet: add ZTE network driver support
2026-04-22 14:48 ` [PATCH net-next v2 1/3] net/ethernet: add ZTE network driver support Junyang Han
@ 2026-04-22 16:24 ` Andrew Lunn
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2026-04-22 16:24 UTC (permalink / raw)
To: Junyang Han
Cc: netdev, davem, andrew+netdev, edumazet, kuba, pabeni, ran.ming,
han.chengfei, zhang.yanze
> +MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
> +MODULE_DESCRIPTION("ZTE Corporation network adapters (DingHai series)
> Ethernet driver");
> +err_pci_save_state:
> + pci_release_selected_regions(dev->pdev, pci_select_bars(dev->
> pdev, IORESOURCE_MEM));
The email is still getting its white space changed. Please don't post
any more versions until you have sent it to yourself and got it back
again in a good state.
https://b4.docs.kernel.org/en/latest/contributor/send.html might help.
Andrew
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net-next v2 2/3] net/ethernet/zte/dinghai: add logging infrastructure
2026-04-22 14:48 [PATCH net-next v2 0/3] Add ZTE DingHai Ethernet PF driver Junyang Han
2026-04-22 14:48 ` [PATCH net-next v2 1/3] net/ethernet: add ZTE network driver support Junyang Han
@ 2026-04-22 14:49 ` Junyang Han
2026-04-22 14:49 ` [PATCH net-next v2 3/3] net/ethernet/zte/dinghai: add hardware register access and PCI capability scanning Junyang Han
2026-04-22 16:19 ` [PATCH net-next v2 0/3] Add ZTE DingHai Ethernet PF driver Andrew Lunn
3 siblings, 0 replies; 7+ messages in thread
From: Junyang Han @ 2026-04-22 14:49 UTC (permalink / raw)
To: netdev
Cc: davem, andrew+netdev, edumazet, kuba, pabeni, han.junyang,
ran.ming, han.chengfei, zhang.yanze
[-- Attachment #1.1.1: Type: text/plain, Size: 7392 bytes --]
Introduce logging macros (DH_LOG_EMERG/ALERT/CRIT/ERR/WARN/INFO/DBG)
and helper definitions for ZTE DingHai driver debugging.
Signed-off-by: Junyang Han <han.junyang@zte.com.cn>
---
drivers/net/ethernet/zte/dinghai/dh_log.h | 60 +++++++++++++++++++++++
drivers/net/ethernet/zte/dinghai/en_pf.c | 49 +++++++++++++++---
2 files changed, 101 insertions(+), 8 deletions(-)
create mode 100644 drivers/net/ethernet/zte/dinghai/dh_log.h
diff --git a/drivers/net/ethernet/zte/dinghai/dh_log.h b/drivers/net/ethernet/zte/dinghai/dh_log.h
new file mode 100644
index 000000000000..488c1968ae73
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/dh_log.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ZTE DingHai Ethernet driver - logging infrastructure
+ * Copyright (c) 2022-2026, ZTE Corporation.
+ */
+
+#ifndef __DH_LOG_H__
+#define __DH_LOG_H__
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+
+#define MODULE_CMD "zxdh_cmd"
+#define MODULE_NP "zxdh_np"
+#define MODULE_PF "zxdh_pf"
+#define MODULE_PTP "zxdh_ptp"
+#define MODULE_TSN "zxdh_tsn"
+#define MODULE_LAG "zxdh_lag"
+#define MODULE_DHTOOLS "zxdh_tool"
+#define MODULE_SEC "zxdh_sec"
+#define MODULE_MPF "zxdh_mpf"
+#define MODULE_FUC_HP "zxdh_func_hp"
+#define MODULE_UACCE "zxdh_uacce"
+#define MODULE_HEAL "zxdh_health"
+
+#define DH_LOG_EMERG(module, __dev, fmt, arg...) \
+ dev_emerg((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_ALERT(module, __dev, fmt, arg...) \
+ dev_alert((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_CRIT(module, __dev, fmt, arg...) \
+ dev_crit((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_ERR(module, __dev, fmt, arg...) \
+ dev_err((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_WARNING(module, __dev, fmt, arg...) \
+ dev_warn((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_INFO(module, __dev, fmt, arg...) \
+ dev_info((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_DEBUG(module, __dev, fmt, arg...) \
+ dev_dbg((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define LOG_ERR(__dev, fmt, arg...) DH_LOG_ERR(MODULE_PF, __dev, fmt, ##arg)
+#define LOG_INFO(__dev, fmt, arg...) DH_LOG_INFO(MODULE_PF, __dev, fmt, ##arg)
+#define LOG_DEBUG(__dev, fmt, arg...) DH_LOG_DEBUG(MODULE_PF, __dev, fmt, ##arg)
+#define LOG_WARN(__dev, fmt, arg...) DH_LOG_WARNING(MODULE_PF, __dev, fmt, ##arg)
+
+#endif /* __DH_LOG_H__ */
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.c b/drivers/net/ethernet/zte/dinghai/en_pf.c
index 5e13a8c24a28..70dad28de544 100644
--- a/drivers/net/ethernet/zte/dinghai/en_pf.c
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -8,6 +8,7 @@
#include <linux/pci.h>
#include <net/devlink.h>
#include "en_pf.h"
+#include "dh_log.h"
MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
MODULE_DESCRIPTION("ZTE Corporation network adapters (DingHai series) Ethernet driver");
@@ -31,26 +32,34 @@ static int dh_pf_pci_init(struct dh_core_dev *dev)
pci_set_drvdata(dev->pdev, dev);
ret = pci_enable_device(dev->pdev);
- if (ret)
+ if (ret) {
+ LOG_ERR(dev, "pci_enable_device failed: %d\n", ret);
return -ENOMEM;
+ }
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)
+ if (ret) {
+ LOG_ERR(dev, "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)
+ if (ret) {
+ LOG_ERR(dev, "pci_request_selected_regions failed: %d\n", ret);
goto err_pci;
+ }
pci_set_master(dev->pdev);
ret = pci_save_state(dev->pdev);
- if (ret)
+ if (ret) {
+ LOG_ERR(dev, "pci_save_state failed: %d\n", ret);
goto err_pci_save_state;
+ }
pf_dev = dev->priv;
pf_dev->pci_ioremap_addr[0] =
@@ -58,6 +67,9 @@ static int dh_pf_pci_init(struct dh_core_dev *dev)
pci_resource_len(dev->pdev, 0));
if (!pf_dev->pci_ioremap_addr[0]) {
ret = -ENOMEM;
+ LOG_ERR(dev, "ioremap(0x%llx, 0x%llx) failed\n",
+ pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
goto err_pci_save_state;
}
@@ -87,10 +99,13 @@ static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct devlink *devlink = NULL;
int ret = 0;
+ dev_info(&pdev->dev, "pf level start\n");
devlink = devlink_alloc(&dh_pf_devlink_ops, sizeof(struct dh_core_dev),
&pdev->dev);
- if (!devlink)
+ if (!devlink) {
+ dev_err(&pdev->dev, "devlink alloc failed\n");
return -ENOMEM;
+ }
dh_dev = devlink_priv(devlink);
dh_dev->device = &pdev->dev;
@@ -98,8 +113,10 @@ static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dh_dev->devlink = devlink;
pf_dev = dh_core_alloc_priv(dh_dev, sizeof(*pf_dev));
- if (!pf_dev)
- return -ENOMEM;
+ if (!pf_dev) {
+ LOG_ERR(dh_dev, "zxdh_pf_dev alloc failed\n");
+ goto err_pf_dev;
+ }
pf_dev->bar_chan_valid = false;
pf_dev->vepa = false;
@@ -107,10 +124,17 @@ static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&pf_dev->irq_lock);
dh_dev->coredev_type = GET_COREDEV_TYPE(pdev);
+ LOG_DEBUG(dh_dev, "%s device: %s\n",
+ (dh_dev->coredev_type == DH_COREDEV_PF) ? "PF" : "VF",
+ pci_name(pdev));
ret = dh_pf_pci_init(dh_dev);
- if (ret)
+ if (ret) {
+ LOG_ERR(dh_dev, "dh_pf_pci_init failed: %d\n", ret);
goto err_cfg_init;
+ }
+
+ LOG_INFO(dh_dev, "pf level completed\n");
return 0;
@@ -118,6 +142,7 @@ static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_destroy(&pf_dev->irq_lock);
mutex_destroy(&dh_dev->lock);
dh_core_free_priv(dh_dev);
+err_pf_dev:
devlink_free(devlink);
return -EPERM;
}
@@ -128,12 +153,16 @@ static void dh_pf_remove(struct pci_dev *pdev)
struct devlink *devlink = priv_to_devlink(dh_dev);
struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ LOG_INFO(dh_dev, "pf level start\n");
+
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);
+
+ LOG_INFO(dh_dev, "pf level completed\n");
}
static void dh_pf_shutdown(struct pci_dev *pdev)
@@ -142,6 +171,8 @@ static void dh_pf_shutdown(struct pci_dev *pdev)
struct devlink *devlink = priv_to_devlink(dh_dev);
struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ LOG_INFO(dh_dev, "pf level start\n");
+
dh_pf_pci_close(dh_dev);
mutex_destroy(&pf_dev->irq_lock);
mutex_destroy(&dh_dev->lock);
@@ -149,6 +180,8 @@ static void dh_pf_shutdown(struct pci_dev *pdev)
devlink_free(devlink);
pci_set_drvdata(pdev, NULL);
+
+ LOG_INFO(dh_dev, "pf level completed\n");
}
static struct pci_driver dh_pf_driver = {
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 17292 bytes --]
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH net-next v2 3/3] net/ethernet/zte/dinghai: add hardware register access and PCI capability scanning
2026-04-22 14:48 [PATCH net-next v2 0/3] Add ZTE DingHai Ethernet PF driver Junyang Han
2026-04-22 14:48 ` [PATCH net-next v2 1/3] net/ethernet: add ZTE network driver support Junyang Han
2026-04-22 14:49 ` [PATCH net-next v2 2/3] net/ethernet/zte/dinghai: add logging infrastructure Junyang Han
@ 2026-04-22 14:49 ` Junyang Han
2026-04-22 21:54 ` Vadim Fedorenko
2026-04-22 16:19 ` [PATCH net-next v2 0/3] Add ZTE DingHai Ethernet PF driver Andrew Lunn
3 siblings, 1 reply; 7+ messages in thread
From: Junyang Han @ 2026-04-22 14:49 UTC (permalink / raw)
To: netdev
Cc: davem, andrew+netdev, edumazet, kuba, pabeni, han.junyang,
ran.ming, han.chengfei, zhang.yanze
[-- Attachment #1.1.1: Type: text/plain, Size: 18761 bytes --]
Implement PCI configuration space access, BAR mapping, capability
scanning (common/notify/device), and hardware queue register
definitions for DingHai PF device.
Signed-off-by: Junyang Han <han.junyang@zte.com.cn>
---
drivers/net/ethernet/zte/dinghai/dh_queue.h | 71 ++++
drivers/net/ethernet/zte/dinghai/en_pf.c | 410 ++++++++++++++++++++
drivers/net/ethernet/zte/dinghai/en_pf.h | 38 ++
3 files changed, 519 insertions(+)
create mode 100644 drivers/net/ethernet/zte/dinghai/dh_queue.h
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 000000000000..5067c73fed33
--- /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
index 70dad28de544..0dd4dcbdefb0 100644
--- a/drivers/net/ethernet/zte/dinghai/en_pf.c
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -9,6 +9,7 @@
#include <net/devlink.h>
#include "en_pf.h"
#include "dh_log.h"
+#include "dh_queue.h"
MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
MODULE_DESCRIPTION("ZTE Corporation network adapters (DingHai series) Ethernet driver");
@@ -92,6 +93,415 @@ void dh_pf_pci_close(struct dh_core_dev *dev)
pci_disable_device(dev->pdev);
}
+int32_t zxdh_pf_pci_find_capability(struct pci_dev *pdev, uint8_t cfg_type,
+ uint32_t ioresource_types, int32_t *bars)
+{
+ int32_t pos = 0;
+ uint8_t type = 0;
+ uint8_t bar = 0;
+
+ 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, int32_t off,
+ size_t minlen, uint32_t align,
+ uint32_t start, uint32_t size,
+ size_t *len, resource_size_t *pa,
+ uint32_t *bar_off)
+{
+ struct pci_dev *pdev = dh_dev->pdev;
+ uint8_t bar = 0;
+ uint32_t offset = 0;
+ uint32_t length = 0;
+ void __iomem *p = NULL;
+
+ 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) {
+ LOG_ERR(dh_dev, "bad capability len %u (>%u expected)\n", length, start);
+ return NULL;
+ }
+
+ if (length - start < minlen) {
+ LOG_ERR(dh_dev, "bad capability len %u (>=%zu expected)\n", length, minlen);
+ return NULL;
+ }
+
+ length -= start;
+ if (start + offset < offset) {
+ LOG_ERR(dh_dev, "map wrap-around %u+%u\n", start, offset);
+ return NULL;
+ }
+
+ offset += start;
+ if (offset & (align - 1)) {
+ LOG_ERR(dh_dev, "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)) {
+ LOG_ERR(dh_dev, "map custom queue %zu@%u out of range on bar %i 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) {
+ LOG_ERR(dh_dev, "unable to map custom queue %u@%u on bar %i\n", length, offset, bar);
+ } else if (pa) {
+ *pa = pci_resource_start(pdev, bar) + offset;
+ }
+
+ return p;
+}
+
+int32_t zxdh_pf_common_cfg_init(struct dh_core_dev *dh_dev)
+{
+ int32_t common = 0;
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ struct pci_dev *pdev = dh_dev->pdev;
+
+ /* 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 == 0) {
+ LOG_ERR(dh_dev, "missing capabilities %i, leaving for legacy driver\n", common);
+ 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) {
+ LOG_ERR(dh_dev, "pf_dev->common is null\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int32_t zxdh_pf_notify_cfg_init(struct dh_core_dev *dh_dev)
+{
+ int32_t notify = 0;
+ size_t notify_length = 0;
+ size_t notify_offset = 0;
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ struct pci_dev *pdev = dh_dev->pdev;
+
+ /* 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 == 0) {
+ LOG_ERR(dh_dev, "missing capabilities %i\n", notify);
+ 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) {
+ LOG_ERR(dh_dev, "pf_dev->notify_base is null\n");
+ return -EINVAL;
+ }
+ } else {
+ pf_dev->notify_map_cap = notify;
+ }
+
+ return 0;
+}
+
+int32_t zxdh_pf_device_cfg_init(struct dh_core_dev *dh_dev)
+{
+ int32_t device = 0;
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ struct pci_dev *pdev = dh_dev->pdev;
+
+ /* 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) {
+ LOG_ERR(dh_dev, "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_core_priv(dh_dev);
+ 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);
+}
+
+int32_t zxdh_pf_modern_cfg_init(struct dh_core_dev *dh_dev)
+{
+ int32_t ret = 0;
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ struct pci_dev *pdev = dh_dev->pdev;
+
+ ret = zxdh_pf_common_cfg_init(dh_dev);
+ if (ret) {
+ LOG_ERR(dh_dev, "zxdh_pf_common_cfg_init failed: %d\n", ret);
+ return -EINVAL;
+ }
+
+ ret = zxdh_pf_notify_cfg_init(dh_dev);
+ if (ret) {
+ LOG_ERR(dh_dev, "zxdh_pf_notify_cfg_init failed: %d\n", ret);
+ goto err_map_notify;
+ }
+
+ ret = zxdh_pf_device_cfg_init(dh_dev);
+ if (ret) {
+ LOG_ERR(dh_dev, "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 -EINVAL;
+}
+
+uint16_t zxdh_pf_get_queue_notify_off(struct dh_core_dev *dh_dev,
+ uint16_t phy_index, uint16_t index)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ 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,
+ uint16_t phy_index, uint16_t index,
+ resource_size_t *pa)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ uint16_t off = 0;
+
+ off = zxdh_pf_get_queue_notify_off(dh_dev, phy_index, index);
+
+ if (pf_dev->notify_base) {
+ /* offset should not wrap */
+ if ((uint64_t)off * pf_dev->notify_offset_multiplier + 2 > pf_dev->notify_len) {
+ LOG_ERR(dh_dev, "bad notification offset %u (x %u) for queue %u > %zd",
+ 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 *priv)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ if (!pf_dev->notify_base)
+ pci_iounmap(dh_dev->pdev, priv);
+}
+
+void zxdh_pf_set_status(struct dh_core_dev *dh_dev, uint8_t status)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ iowrite8(status, &pf_dev->common->device_status);
+}
+
+uint8_t zxdh_pf_get_status(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ return ioread8(&pf_dev->common->device_status);
+}
+
+static uint8_t zxdh_pf_get_cfg_gen(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ uint8_t config_generation = 0;
+
+ config_generation = ioread8(&pf_dev->common->config_generation);
+ LOG_INFO(dh_dev, "config_generation is %d\n", config_generation);
+
+ return config_generation;
+}
+
+void zxdh_pf_get_vf_mac(struct dh_core_dev *dh_dev, uint8_t *mac, int32_t vf_id)
+{
+ uint32_t DEV_MAC_L = 0;
+ uint16_t DEV_MAC_H = 0;
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ 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, uint8_t *mac, int32_t vf_id)
+{
+ uint32_t DEV_MAC_L = 0;
+ uint16_t DEV_MAC_H = 0;
+
+ 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, uint8_t *mac, int32_t vf_id)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ zxdh_pf_set_vf_mac_reg(pf_dev, mac, vf_id);
+}
+
+void zxdh_set_mac(struct dh_core_dev *dh_dev, uint8_t *mac)
+{
+ uint32_t DEV_MAC_L = 0;
+ uint16_t DEV_MAC_H = 0;
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ 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, uint8_t *mac)
+{
+ uint32_t DEV_MAC_L = 0;
+ uint16_t DEV_MAC_H = 0;
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ 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;
+}
+
+uint64_t zxdh_pf_get_features(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ uint64_t device_feature = 0;
+
+ 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 |= ((uint64_t)ioread32(&pf_dev->common->device_feature) << 32);
+
+ return device_feature;
+}
+
+void zxdh_pf_set_features(struct dh_core_dev *dh_dev, uint64_t features)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ iowrite32(0, &pf_dev->common->guest_feature_select);
+ iowrite32((uint32_t)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 dh_core_dev *dh_dev = NULL;
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.h b/drivers/net/ethernet/zte/dinghai/en_pf.h
index a8b324adb948..0c4172c513a9 100644
--- a/drivers/net/ethernet/zte/dinghai/en_pf.h
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h
@@ -15,6 +15,24 @@
#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,
@@ -34,7 +52,27 @@ struct dh_core_dev {
};
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. */
+ int32_t notify_map_cap;
+ uint32_t notify_offset_multiplier;
+ /* Multiply queue_notify_off by this value. (non-legacy mode). */
+ int32_t modern_bars;
+
uint64_t pci_ioremap_addr[6];
+ uint64_t sriov_bar_size;
+ uint32_t dev_cfg_bar_off;
+ bool packed_status;
bool bar_chan_valid;
bool vepa;
struct mutex irq_lock; /* Protects IRQ operations */
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 45260 bytes --]
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH net-next v2 3/3] net/ethernet/zte/dinghai: add hardware register access and PCI capability scanning
2026-04-22 14:49 ` [PATCH net-next v2 3/3] net/ethernet/zte/dinghai: add hardware register access and PCI capability scanning Junyang Han
@ 2026-04-22 21:54 ` Vadim Fedorenko
0 siblings, 0 replies; 7+ messages in thread
From: Vadim Fedorenko @ 2026-04-22 21:54 UTC (permalink / raw)
To: Junyang Han, netdev
Cc: davem, andrew+netdev, edumazet, kuba, pabeni, ran.ming,
han.chengfei, zhang.yanze
On 22.04.2026 15:49, Junyang Han wrote:
> Implement PCI configuration space access, BAR mapping, capability
> scanning (common/notify/device), and hardware queue register
> definitions for DingHai PF device.
>
> Signed-off-by: Junyang Han <han.junyang@zte.com.cn>
[...]
> +
> +void __iomem *zxdh_pf_map_capability(struct dh_core_dev *dh_dev, int32_t off,
> + size_t minlen, uint32_t align,
> + uint32_t start, uint32_t size,
> + size_t *len, resource_size_t *pa,
> + uint32_t *bar_off)
> +{
> + struct pci_dev *pdev = dh_dev->pdev;
> + uint8_t bar = 0;
> + uint32_t offset = 0;
> + uint32_t length = 0;
> + void __iomem *p = NULL;
Even though the changelog says that variable declaration ordering is fixed, this
patch (as some others in the series) still has the problem.
Also, please avoid using user-space fixed size types, kernel space uses short
type names, like u32/u8 etc.
Try to avoid meaningless initialization as well.
These comments apply to the whole series, not only to this single patch
> +
> + 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;
> +
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-next v2 0/3] Add ZTE DingHai Ethernet PF driver
2026-04-22 14:48 [PATCH net-next v2 0/3] Add ZTE DingHai Ethernet PF driver Junyang Han
` (2 preceding siblings ...)
2026-04-22 14:49 ` [PATCH net-next v2 3/3] net/ethernet/zte/dinghai: add hardware register access and PCI capability scanning Junyang Han
@ 2026-04-22 16:19 ` Andrew Lunn
3 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2026-04-22 16:19 UTC (permalink / raw)
To: Junyang Han
Cc: netdev, davem, andrew+netdev, edumazet, kuba, pabeni, ran.ming,
han.chengfei, zhang.yanze
On Wed, Apr 22, 2026 at 10:48:58PM +0800, Junyang Han wrote:
> This series adds initial support for the ZTE DingHai Ethernet controller,
> a high-performance PCIe Ethernet device supporting SR-IOV, hardware
> offloading, and advanced virtualization features.
https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
Please read sections 1.3 and 1.4, particularly the bit in red.
Andrew
---
pw-bot: cr
^ permalink raw reply [flat|nested] 7+ messages in thread