Introduce rawdev driver support for GDTC which
can help to connect two separate hosts with each other.

Signed-off-by: Yong Zhang <zhang.yong25@zte.com.cn>
---
 .mailmap                       |   1 +
 MAINTAINERS                    |   5 +
 doc/guides/rawdevs/gdtc.rst    |  35 ++++++
 doc/guides/rawdevs/index.rst   |   1 +
 drivers/raw/gdtc/gdtc_rawdev.c | 195 +++++++++++++++++++++++++++++++++
 drivers/raw/gdtc/gdtc_rawdev.h | 103 +++++++++++++++++
 drivers/raw/gdtc/meson.build   |   5 +
 drivers/raw/meson.build        |   1 +
 8 files changed, 346 insertions(+)
 create mode 100644 doc/guides/rawdevs/gdtc.rst
 create mode 100644 drivers/raw/gdtc/gdtc_rawdev.c
 create mode 100644 drivers/raw/gdtc/gdtc_rawdev.h
 create mode 100644 drivers/raw/gdtc/meson.build

diff --git a/.mailmap b/.mailmap
index 4dbb8cf8a7..95ee83c6bf 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1768,6 +1768,7 @@ Yu Wenjun <yuwenjun@cmss.chinamobile.com> <yuwenjun0x@163.com>
 Yuying Zhang <yuying.zhang@intel.com>
 Yu Zhang <zhangyu31@baidu.com>
 Yvonne Yang <yvonnex.yang@intel.com>
+Yong Zhang <zhang.yong25@zte.com.cn>
 Zalfresso-Jundzillo <marekx.zalfresso-jundzillo@intel.com>
 Zbigniew Bodek <zbigniew.bodek@caviumnetworks.com>
 Zengmo Gao <gaozengmo@jd.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index f84ca3ea68..3c413f952b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1552,6 +1552,11 @@ M: Gagandeep Singh <g.singh@nxp.com>
 F: drivers/raw/dpaa2_cmdif/
 F: doc/guides/rawdevs/dpaa2_cmdif.rst
 
+ZTE GDTC
+M: Yong Zhang <zhang.yong25@zte.com.cn>
+F: drivers/raw/gdtc/
+F: doc/guides/rawdevs/gdtc.rst
+
 
 Packet processing
 -----------------
diff --git a/doc/guides/rawdevs/gdtc.rst b/doc/guides/rawdevs/gdtc.rst
new file mode 100644
index 0000000000..7e4e648c89
--- /dev/null
+++ b/doc/guides/rawdevs/gdtc.rst
@@ -0,0 +1,35 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+    Copyright 2024 ZTE Corporation
+
+GDTC Rawdev Driver
+======================
+
+The ``gdtc`` rawdev driver is an implementation of the rawdev API,
+that provides communication between two separate hosts.
+This is achieved via using the GDMA controller of Dinghai SoC,
+which can be configured through exposed MPF device.
+
+Device Setup
+-------------
+
+Using the GDTC PMD driver does not require the MPF device to bind
+additional user-space IO driver.
+
+Before performing actual data transmission, it is necessary to
+call ``rte_rawdev_queue_setup()`` to obtain an available queue ID.
+
+For data transfer, utilize the standard ``rte_rawdev_enqueue_buffers()`` API.
+The data transfer status can be queried via ``rte_rawdev_dequeue_buffers()``,
+which will return the number of successfully transferred data items.
+
+Initialization
+--------------
+
+The ``gdtc`` rawdev driver needs to work in IOVA PA mode.
+Consider using ``--iova-mode=pa`` in the EAL options.
+
+Platform Requirement
+~~~~~~~~~~~~~~~~~~~~
+
+This PMD is only supported on ZTE Neo Platforms:
+- Neo X510/X512
diff --git a/doc/guides/rawdevs/index.rst b/doc/guides/rawdevs/index.rst
index 8e07cf4d6c..2d8606d742 100644
--- a/doc/guides/rawdevs/index.rst
+++ b/doc/guides/rawdevs/index.rst
@@ -17,3 +17,4 @@ application through rawdev API.
     dpaa2_cmdif
     ifpga
     ntb
+    gdtc
diff --git a/drivers/raw/gdtc/gdtc_rawdev.c b/drivers/raw/gdtc/gdtc_rawdev.c
new file mode 100644
index 0000000000..6f20ecdad6
--- /dev/null
+++ b/drivers/raw/gdtc/gdtc_rawdev.c
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2024 ZTE Corporation
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <bus_pci_driver.h>
+#include <rte_atomic.h>
+#include <rte_common.h>
+#include <rte_dev.h>
+#include <rte_eal_paging.h>
+#include <rte_errno.h>
+#include <rte_lcore.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_pci.h>
+#include <rte_rawdev.h>
+#include <rte_rawdev_pmd.h>
+#include <rte_spinlock.h>
+#include <rte_branch_prediction.h>
+
+#include "gdtc_rawdev.h"
+
+/* Register offset */
+#define ZXDH_GDMA_BASE_OFFSET                   0x100000
+
+#define ZXDH_GDMA_CHAN_SHIFT                    0x80
+char zxdh_gdma_driver_name[] = "rawdev_zxdh_gdma";
+char dev_name[] = "zxdh_gdma";
+
+static inline struct zxdh_gdma_rawdev *
+zxdh_gdma_rawdev_get_priv(const struct rte_rawdev *rawdev)
+{
+    return rawdev->dev_private;
+}
+
+static const struct rte_rawdev_ops zxdh_gdma_rawdev_ops = {
+};
+
+static int
+zxdh_gdma_map_resource(struct rte_pci_device *dev)
+{
+    int fd = -1;
+    char devname[PATH_MAX];
+    void *mapaddr = NULL;
+    struct rte_pci_addr *loc;
+
+    loc = &dev->addr;
+    snprintf(devname, sizeof(devname), "%s/" PCI_PRI_FMT "/resource0",
+        rte_pci_get_sysfs_path(),
+        loc->domain, loc->bus, loc->devid,
+        loc->function);
+
+        fd = open(devname, O_RDWR);
+        if (fd < 0) {
+            ZXDH_PMD_LOG(ERR, "Cannot open %s: %s", devname, strerror(errno));
+            return -1;
+        }
+
+    /* Map the PCI memory resource of device */
+    mapaddr = rte_mem_map(NULL, (size_t)dev->mem_resource[0].len,
+                RTE_PROT_READ | RTE_PROT_WRITE,
+                RTE_MAP_SHARED, fd, 0);
+    if (mapaddr == NULL) {
+        ZXDH_PMD_LOG(ERR, "cannot map resource(%d, 0x%zx): %s (%p)",
+                fd, (size_t)dev->mem_resource[0].len,
+                rte_strerror(rte_errno), mapaddr);
+        close(fd);
+        return -1;
+    }
+
+    close(fd);
+    dev->mem_resource[0].addr = mapaddr;
+
+    return 0;
+}
+
+static void
+zxdh_gdma_unmap_resource(void *requested_addr, size_t size)
+{
+    if (requested_addr == NULL)
+        return;
+
+    /* Unmap the PCI memory resource of device */
+    if (rte_mem_unmap(requested_addr, size))
+        ZXDH_PMD_LOG(ERR, "cannot mem unmap(%p, %#zx): %s",
+            requested_addr, size, rte_strerror(rte_errno));
+    else
+        ZXDH_PMD_LOG(DEBUG, "PCI memory unmapped at %p", requested_addr);
+}
+
+static int
+zxdh_gdma_rawdev_probe(struct rte_pci_driver *pci_drv __rte_unused,
+            struct rte_pci_device *pci_dev)
+{
+    struct rte_rawdev *dev = NULL;
+    struct zxdh_gdma_rawdev *gdmadev = NULL;
+    struct zxdh_gdma_queue *queue = NULL;
+    uint8_t i = 0;
+    int ret;
+
+    if (pci_dev->mem_resource[0].phys_addr == 0) {
+        ZXDH_PMD_LOG(ERR, "PCI bar0 resource is invalid");
+        return -1;
+    }
+
+    ret = zxdh_gdma_map_resource(pci_dev);
+    if (ret != 0) {
+        ZXDH_PMD_LOG(ERR, "Failed to mmap pci device(%s)", pci_dev->name);
+        return -1;
+    }
+    ZXDH_PMD_LOG(INFO, "%s bar0 0x%"PRIx64" mapped at %p",
+                pci_dev->name, pci_dev->mem_resource[0].phys_addr,
+                pci_dev->mem_resource[0].addr);
+
+    dev = rte_rawdev_pmd_allocate(dev_name, sizeof(struct zxdh_gdma_rawdev), rte_socket_id());
+    if (dev == NULL) {
+        ZXDH_PMD_LOG(ERR, "Unable to allocate gdma rawdev");
+        goto err_out;
+    }
+    ZXDH_PMD_LOG(INFO, "Init %s on NUMA node %d, dev_id is %d",
+            dev_name, rte_socket_id(), dev->dev_id);
+
+    dev->dev_ops = &zxdh_gdma_rawdev_ops;
+    dev->device = &pci_dev->device;
+    dev->driver_name = zxdh_gdma_driver_name;
+    gdmadev = zxdh_gdma_rawdev_get_priv(dev);
+    gdmadev->device_state = ZXDH_GDMA_DEV_STOPPED;
+    gdmadev->rawdev = dev;
+    gdmadev->queue_num = ZXDH_GDMA_TOTAL_CHAN_NUM;
+    gdmadev->used_num = 0;
+    gdmadev->base_addr = (uintptr_t)pci_dev->mem_resource[0].addr + ZXDH_GDMA_BASE_OFFSET;
+
+    for (i = 0; i < ZXDH_GDMA_TOTAL_CHAN_NUM; i++) {
+        queue = &(gdmadev->vqs[i]);
+        queue->enable = 0;
+        queue->queue_size = ZXDH_GDMA_QUEUE_SIZE;
+        rte_spinlock_init(&(queue->enqueue_lock));
+    }
+
+    return 0;
+
+err_out:
+    zxdh_gdma_unmap_resource(pci_dev->mem_resource[0].addr,
+        (size_t)pci_dev->mem_resource[0].len);
+    return -1;
+}
+
+static int
+zxdh_gdma_rawdev_remove(struct rte_pci_device *pci_dev)
+{
+    struct rte_rawdev *dev = NULL;
+    int ret = 0;
+
+    dev = rte_rawdev_pmd_get_named_dev(dev_name);
+    if (dev == NULL)
+        return -EINVAL;
+
+    /* rte_rawdev_close is called by pmd_release */
+    ret = rte_rawdev_pmd_release(dev);
+    if (ret != 0) {
+        ZXDH_PMD_LOG(ERR, "Device cleanup failed");
+        return -1;
+    }
+
+    zxdh_gdma_unmap_resource(pci_dev->mem_resource[0].addr,
+        (size_t)pci_dev->mem_resource[0].len);
+
+    ZXDH_PMD_LOG(DEBUG, "rawdev %s remove done!", dev_name);
+
+    return ret;
+}
+
+static const struct rte_pci_id zxdh_gdma_rawdev_map[] = {
+    { RTE_PCI_DEVICE(ZXDH_GDMA_VENDORID, ZXDH_GDMA_DEVICEID) },
+    { .vendor_id = 0, /* sentinel */ },
+};
+
+static struct rte_pci_driver zxdh_gdma_rawdev_pmd = {
+    .id_table = zxdh_gdma_rawdev_map,
+    .drv_flags = 0,
+    .probe = zxdh_gdma_rawdev_probe,
+    .remove = zxdh_gdma_rawdev_remove,
+};
+
+RTE_PMD_REGISTER_PCI(zxdh_gdma_rawdev_pci_driver, zxdh_gdma_rawdev_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(zxdh_gdma_rawdev_pci_driver, zxdh_gdma_rawdev_map);
+RTE_LOG_REGISTER_DEFAULT(zxdh_gdma_rawdev_logtype, NOTICE);
diff --git a/drivers/raw/gdtc/gdtc_rawdev.h b/drivers/raw/gdtc/gdtc_rawdev.h
new file mode 100644
index 0000000000..9f943c49c6
--- /dev/null
+++ b/drivers/raw/gdtc/gdtc_rawdev.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2024 ZTE Corporation
+ */
+
+#ifndef __GDTC_RAWDEV_H__
+#define __GDTC_RAWDEV_H__
+
+#include <stdint.h>
+#include <rte_log.h>
+#include <rte_common.h>
+#include <generic/rte_spinlock.h>
+
+extern int zxdh_gdma_rawdev_logtype;
+#define RTE_LOGTYPE_ZXDH_GDMA                   zxdh_gdma_rawdev_logtype
+
+#define ZXDH_PMD_LOG(level, ...) \
+    RTE_LOG_LINE_PREFIX(level, ZXDH_GDMA, \
+        "%s() line %u: ", __func__ RTE_LOG_COMMA __LINE__, __VA_ARGS__)
+
+#define ZXDH_GDMA_VENDORID                      0x1cf2
+#define ZXDH_GDMA_DEVICEID                      0x8044
+
+#define ZXDH_GDMA_TOTAL_CHAN_NUM                58
+#define ZXDH_GDMA_QUEUE_SIZE                    16384
+#define ZXDH_GDMA_RING_SIZE                     32768
+
+enum zxdh_gdma_device_state {
+    ZXDH_GDMA_DEV_RUNNING,
+    ZXDH_GDMA_DEV_STOPPED
+};
+
+struct zxdh_gdma_buff_desc {
+    uint32_t SrcAddr_L;
+    uint32_t DstAddr_L;
+    uint32_t Xpara;
+    uint32_t ZY_para;
+    uint32_t ZY_SrcStep;
+    uint32_t ZY_DstStep;
+    uint32_t ExtAddr;
+    uint32_t LLI_Addr_L;
+    uint32_t LLI_Addr_H;
+    uint32_t ChCont;
+    uint32_t LLI_User;
+    uint32_t ErrAddr;
+    uint32_t Control;
+    uint32_t SrcAddr_H;
+    uint32_t DstAddr_H;
+    uint32_t Reserved;
+};
+
+struct zxdh_gdma_job {
+    uint64_t src;
+    uint64_t dest;
+    uint32_t len;
+    uint32_t flags;
+    uint64_t cnxt;
+    uint16_t status;
+    uint16_t vq_id;
+    void *usr_elem;
+    uint8_t ep_id;
+    uint8_t pf_id;
+    uint16_t vf_id;
+};
+
+struct zxdh_gdma_queue {
+    uint8_t   enable;
+    uint8_t   is_txq;
+    uint16_t  vq_id;
+    uint16_t  queue_size;
+    /* 0:GDMA needs to be configured through the APB interface */
+    uint16_t  flag;
+    uint32_t  user;
+    uint16_t  tc_cnt;
+    rte_spinlock_t enqueue_lock;
+    struct {
+        uint16_t avail_idx;
+        uint16_t last_avail_idx;
+        rte_iova_t ring_mem;
+        const struct rte_memzone *ring_mz;
+        struct zxdh_gdma_buff_desc *desc;
+    } ring;
+    struct {
+        uint16_t  free_cnt;
+        uint16_t  deq_cnt;
+        uint16_t  pend_cnt;
+        uint16_t  enq_idx;
+        uint16_t  deq_idx;
+        uint16_t  used_idx;
+        struct zxdh_gdma_job **job;
+    } sw_ring;
+};
+
+struct zxdh_gdma_rawdev {
+    struct rte_device *device;
+    struct rte_rawdev *rawdev;
+    uintptr_t base_addr;
+    uint8_t queue_num; /* total queue num */
+    uint8_t used_num;  /* used  queue num */
+    enum zxdh_gdma_device_state device_state;
+    struct zxdh_gdma_queue vqs[ZXDH_GDMA_TOTAL_CHAN_NUM];
+};
+
+#endif /* __GDTC_RAWDEV_H__ */
diff --git a/drivers/raw/gdtc/meson.build b/drivers/raw/gdtc/meson.build
new file mode 100644
index 0000000000..3e748ca58d
--- /dev/null
+++ b/drivers/raw/gdtc/meson.build
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2024 ZTE Corporation
+
+deps += ['rawdev', 'kvargs', 'mbuf', 'bus_pci']
+sources = files('gdtc_rawdev.c')
diff --git a/drivers/raw/meson.build b/drivers/raw/meson.build
index 54221643d5..9cc2cba9e1 100644
--- a/drivers/raw/meson.build
+++ b/drivers/raw/meson.build
@@ -13,5 +13,6 @@ drivers = [
         'ifpga',
         'ntb',
         'skeleton',
+        'gdtc',
 ]
 std_deps = ['rawdev']
-- 
2.43.0