dinghai: add ZTE network driver support

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>
Link: https://patch.msgid.link/202608021621043761zZMwCny1e6y0TRFLQHxx@zte.com.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Junyang Han
2026-08-02 16:21:04 +08:00
committed by Jakub Kicinski
parent 504ef04e86
commit b8180f7977
9 changed files with 278 additions and 0 deletions

View File

@@ -29869,6 +29869,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

View File

@@ -189,5 +189,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

View File

@@ -105,3 +105,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/

View File

@@ -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

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the ZTE device drivers
#
obj-$(CONFIG_DINGHAI) += dinghai/

View File

@@ -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

View File

@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for ZTE DingHai Ethernet driver
#
obj-$(CONFIG_DINGHAI_PF) += dinghai10e.o
dinghai10e-y := en_pf.o

View File

@@ -0,0 +1,174 @@
// 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 "en_pf.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;
}
dma_set_mask_and_coherent(zxdh_dev->device, DMA_BIT_MASK(64));
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);
}
static int zxdh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct zxdh_core_dev *zxdh_dev;
struct zxdh_pf_dev *pf_dev;
struct devlink *devlink;
int ret;
devlink = devlink_alloc(&zxdh_pf_devlink_ops, sizeof(struct zxdh_core_dev),
&pdev->dev);
if (!devlink)
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;
}
ret = zxdh_pf_pci_init(zxdh_dev);
if (ret) {
dev_err(&pdev->dev, "zxdh_pf_pci_init failed: %d\n", ret);
goto err_pci_init;
}
devlink_register(devlink);
return 0;
err_pci_init:
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);
devlink_unregister(devlink);
zxdh_pf_pci_close(zxdh_dev);
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);

View File

@@ -0,0 +1,29 @@
/* 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__
#define ZXDH_PF_VENDOR_ID 0x1cf2
#define ZXDH_PF_DEVICE_ID 0x8040
#define ZXDH_VF_DEVICE_ID 0x8041
struct zxdh_core_dev {
struct device *device;
struct pci_dev *pdev;
struct devlink *devlink;
void *priv;
};
struct zxdh_pf_dev {
void __iomem *pci_ioremap_addr[6];
};
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);
#endif /* __ZXDH_EN_PF_H__ */