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  | 191 ++++++++++++++++++++++
 drivers/net/ethernet/zte/dinghai/en_pf.h  |  51 ++++++
 9 files changed, 320 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..d3a4298fa927
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ZTE DingHai Ethernet driver
+ * Copyright (c) 2022-2024, ZTE Corporation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <net/devlink.h>
+#include "en_pf.h"
+
+#define DRV_VERSION "1.0-1"
+#define DRV_SUMMARY "ZTE(R) zxdh-net driver"
+
+const char zxdh_pf_driver_version[] = DRV_VERSION;
+static const char zxdh_pf_driver_string[] = DRV_SUMMARY;
+static const char zxdh_pf_copyright[] = "Copyright (c) 2022-2024, ZTE Corporation.";
+
+MODULE_AUTHOR("ZTE");
+MODULE_DESCRIPTION(DRV_SUMMARY);
+MODULE_VERSION(DRV_VERSION);
+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)
+{
+    int ret = 0;
+    struct zxdh_pf_device *pf_dev = NULL;
+
+    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 = dh_core_priv(dev);
+    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 = dh_core_priv(dev);
+    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 zxdh_pf_device),
+                &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_priv(dh_dev);
+    pf_dev->bar_chan_valid = false;
+    pf_dev->vepa = false;
+    mutex_init(&dh_dev->lock);
+    mutex_init(&pf_dev->irq_lock);
+
+    dh_dev->coredev_type = GET_COREDEV_TYPE(pdev);
+
+    ret = dh_pf_pci_init(dh_dev);
+    if (ret)
+        goto err_cfg_init;
+
+    return 0;
+
+err_cfg_init:
+    mutex_destroy(&pf_dev->irq_lock);
+    mutex_destroy(&dh_dev->lock);
+    devlink_free(devlink);
+    pf_dev = NULL;
+    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_core_priv(dh_dev);
+
+    if (!dh_dev)
+        return;
+
+    dh_pf_pci_close(dh_dev);
+    mutex_destroy(&pf_dev->irq_lock);
+    mutex_destroy(&dh_dev->lock);
+    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_core_priv(dh_dev);
+
+    dh_pf_pci_close(dh_dev);
+    mutex_destroy(&pf_dev->irq_lock);
+    mutex_destroy(&dh_dev->lock);
+    devlink_free(devlink);
+
+    pci_set_drvdata(pdev, NULL);
+}
+
+static int dh_pf_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+    return 0;
+}
+
+static int dh_pf_resume(struct pci_dev *pdev)
+{
+    return 0;
+}
+
+static struct pci_driver dh_pf_driver = {
+    .name = "dinghai10e",
+    .id_table = dh_pf_pci_table,
+    .probe = dh_pf_probe,
+    .remove = dh_pf_remove,
+    .suspend = dh_pf_suspend,
+    .resume = dh_pf_resume,
+    .shutdown = dh_pf_shutdown,
+};
+
+static int __init dh_pf_pci_init_module(void)
+{
+    return pci_register_driver(&dh_pf_driver);
+}
+
+static void __exit dh_pf_pci_exit_module(void)
+{
+    pci_unregister_driver(&dh_pf_driver);
+}
+
+module_init(dh_pf_pci_init_module);
+module_exit(dh_pf_pci_exit_module);
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..0d3880b0aede
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ZTE DingHai Ethernet driver - PF header
+ * Copyright (c) 2022-2024, 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 */
+    char priv[] __aligned(32);
+};
+
+struct zxdh_pf_device {
+    bool bar_chan_valid;
+    bool vepa;
+    struct mutex irq_lock; /* Protects IRQ operations */
+};
+
+static inline void *dh_core_priv(struct dh_core_dev *dh_coredev)
+{
+    return &dh_coredev->priv;
+}
+
+#define GET_COREDEV_TYPE(pdev) \
+    ((pdev)->device == ZXDH_VF_DEVICE_ID ? DH_COREDEV_VF : DH_COREDEV_PF)
+
+#endif
+
-- 
2.43.0