[PATCH rdma v8 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton
From: Yanze Zhang
Date: Mon Nov 02 2026 - 03:34:00 EST
Implement hardware resource initialization logic and provide a minimal
but functional verbs layer skeleton. This includes basic device
registration with the minimal set of device ops (owner, driver_id,
uverbs_abi_ver), to satisfy the requirement that the driver must be
functional and have a valid driver ID.
The hardware resources of the driver are held in a single allocation,
which carries the allocation bitmaps of the resource pools and the
tables of the queue pair, completion queue and shared receive queue
objects. The first entry of the memory region, protection domain, queue
pair, address handle and multicast group pools is reserved.
The device ops are exported so that the probe path can install them
right after ib_alloc_device(). When the resource memory cannot be
allocated, the 8K index counter array is released with a cleared
pointer, so that the dealloc hook does not free the same allocation
twice.
Signed-off-by: Yanze Zhang <zhang.yanze@xxxxxxxxxx>
---
drivers/infiniband/hw/zrdma/Makefile | 5 +-
drivers/infiniband/hw/zrdma/zrdma_ctrl.h | 2 -
drivers/infiniband/hw/zrdma/zrdma_hw.c | 129 +++++++++++++++++++++
drivers/infiniband/hw/zrdma/zrdma_verbs.c | 39 +++++++
drivers/infiniband/hw/zrdma/zrdma_verbs.h | 134 ++++++++++++++++++++++
5 files changed, 306 insertions(+), 3 deletions(-)
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_hw.c
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_verbs.c
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_verbs.h
diff --git a/drivers/infiniband/hw/zrdma/Makefile b/drivers/infiniband/hw/zrdma/Makefile
index 2ddf50d1fd208..9bc3650a8f2a9 100644
--- a/drivers/infiniband/hw/zrdma/Makefile
+++ b/drivers/infiniband/hw/zrdma/Makefile
@@ -1,4 +1,7 @@
# SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
obj-$(CONFIG_INFINIBAND_ZRDMA) += zrdma.o
-zrdma-y := zrdma_main.o
+zrdma-y := \
+ zrdma_main.o \
+ zrdma_hw.o \
+ zrdma_verbs.o
diff --git a/drivers/infiniband/hw/zrdma/zrdma_ctrl.h b/drivers/infiniband/hw/zrdma/zrdma_ctrl.h
index d25570683b614..935b4cbd3e4a9 100644
--- a/drivers/infiniband/hw/zrdma/zrdma_ctrl.h
+++ b/drivers/infiniband/hw/zrdma/zrdma_ctrl.h
@@ -8,12 +8,10 @@
#define ZRDMA_CTRL_H
struct zxdh_hw {
- u8 __iomem *hw_addr;
struct device *device;
};
struct zxdh_sc_dev {
- struct zxdh_hw *hw;
u32 max_ceqs;
u8 ep_id;
u8 driver_load;
diff --git a/drivers/infiniband/hw/zrdma/zrdma_hw.c b/drivers/infiniband/hw/zrdma/zrdma_hw.c
new file mode 100644
index 0000000000000..53280dcfb2a1f
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_hw.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#include <linux/vmalloc.h>
+#include "zrdma_hw.h"
+#include "zrdma_ctrl.h"
+#include "zrdma_main.h"
+
+static void zxdh_set_hw_rsrc(struct zxdh_pci_f *rf)
+{
+ /* The layout is walked with a byte pointer, so that every step
+ * matches the size that zxdh_calc_mem_rsrc_size() accounted for.
+ * Both functions use the same order of the resources.
+ */
+ u8 *ptr = rf->mem_rsrc;
+
+ rf->allocated_srqs = (unsigned long *)ptr;
+ ptr += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_srq);
+ rf->allocated_qps = (unsigned long *)ptr;
+ ptr += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_qp);
+ rf->allocated_cqs = (unsigned long *)ptr;
+ ptr += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_cq);
+ rf->allocated_mrs = (unsigned long *)ptr;
+ ptr += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_mr);
+ rf->allocated_pds = (unsigned long *)ptr;
+ ptr += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_pd);
+ rf->allocated_ahs = (unsigned long *)ptr;
+ ptr += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_ah);
+ rf->allocated_mcgs = (unsigned long *)ptr;
+ ptr += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_mcg);
+ rf->allocated_pris = (unsigned long *)ptr;
+ ptr += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_pri);
+ rf->allocated_8k_idx = (unsigned long *)ptr;
+ ptr += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_8k_idx);
+ rf->qp_table = (struct zxdh_qp **)ptr;
+ ptr += sizeof(struct zxdh_qp *) * rf->max_qp;
+ rf->cq_table = (struct zxdh_cq **)ptr;
+ ptr += sizeof(struct zxdh_cq *) * rf->max_cq;
+ rf->srq_table = (struct zxdh_srq **)ptr;
+
+ spin_lock_init(&rf->rsrc_lock);
+ spin_lock_init(&rf->qptable_lock);
+ spin_lock_init(&rf->cqtable_lock);
+ spin_lock_init(&rf->srqtable_lock);
+}
+
+static u32 zxdh_calc_mem_rsrc_size(struct zxdh_pci_f *rf)
+{
+ u32 rsrc_size;
+
+ rsrc_size = sizeof(unsigned long) * BITS_TO_LONGS(rf->max_srq);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_qp);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_cq);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_mr);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_pd);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_ah);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_mcg);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_pri);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_8k_idx);
+ rsrc_size += sizeof(struct zxdh_qp **) * rf->max_qp;
+ rsrc_size += sizeof(struct zxdh_cq **) * rf->max_cq;
+ rsrc_size += sizeof(struct zxdh_srq **) * rf->max_srq;
+
+ return rsrc_size;
+}
+
+static int zxdh_initialize_hw_rsrc(struct zxdh_pci_f *rf)
+{
+ u32 rsrc_size;
+ int ret;
+
+ rf->max_cqe = ZXDH_MAX_CQE;
+ rf->max_qp = ZXDH_MAX_QP;
+ rf->max_mr = ZXDH_MAX_MR;
+ rf->max_cq = ZXDH_MAX_CQ;
+ rf->max_srq = ZXDH_MAX_SRQ;
+ rf->max_pd = ZXDH_MAX_PD;
+ rf->max_ah = ZXDH_MAX_AH;
+ rf->max_mcg = ZXDH_MAX_MCG;
+ rf->max_pri = ZXDH_MAX_USER_PRIORITY;
+ rf->max_8k_idx = ZXDH_MAX_8K_IDX;
+
+ rf->qp_cnt_8k_idxs = vzalloc(rf->max_8k_idx * sizeof(u32));
+ if (!rf->qp_cnt_8k_idxs) {
+ ret = -ENOMEM;
+ goto mem_8k_qp_cnt_vmalloc_fail;
+ }
+
+ rsrc_size = zxdh_calc_mem_rsrc_size(rf);
+ rf->mem_rsrc = vzalloc(rsrc_size);
+ if (!rf->mem_rsrc) {
+ ret = -ENOMEM;
+ goto mem_rsrc_vmalloc_fail;
+ }
+
+ zxdh_set_hw_rsrc(rf);
+
+ /* The first entry of the pools that are already in use is
+ * reserved, so that a resource number of zero is not handed out.
+ * The pools of the completion queues, the shared receive queues,
+ * the user priorities and the 8K indices do not reserve an entry
+ * yet, they are not allocated from yet.
+ */
+ set_bit(0, rf->allocated_mrs);
+ set_bit(1, rf->allocated_mrs);
+ set_bit(0, rf->allocated_pds);
+ set_bit(0, rf->allocated_qps);
+ set_bit(0, rf->allocated_ahs);
+ set_bit(0, rf->allocated_mcgs);
+
+ return 0;
+
+mem_rsrc_vmalloc_fail:
+ vfree(rf->qp_cnt_8k_idxs);
+ /* Clear the pointer, the dealloc hook releases the very same
+ * allocation again when the probe path unwinds.
+ */
+ rf->qp_cnt_8k_idxs = NULL;
+mem_8k_qp_cnt_vmalloc_fail:
+ return ret;
+}
+
+int zxdh_ctrl_init_hw(struct zxdh_pci_f *rf)
+{
+ return zxdh_initialize_hw_rsrc(rf);
+}
diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
new file mode 100644
index 0000000000000..90ff9a8264918
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#include "zrdma_main.h"
+#include "zrdma_verbs.h"
+#include "zrdma_ctrl.h"
+
+const struct ib_device_ops zxdh_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_ZRDMA,
+ .uverbs_abi_ver = ZXDH_ABI_VER,
+};
+
+static int zxdh_init_rdma_device(struct zxdh_device *zdev)
+{
+ zdev->ibdev.phys_port_cnt = 1;
+ zdev->ibdev.num_comp_vectors = zdev->rf->ceqs_count;
+ zdev->ibdev.dev.parent = &zdev->rf->pcidev->dev;
+
+ return 0;
+}
+
+int zxdh_ib_register_device(struct zxdh_device *zdev)
+{
+ int ret;
+
+ ret = zxdh_init_rdma_device(zdev);
+ if (ret)
+ return ret;
+
+ ret = ib_register_device(&zdev->ibdev, "zrdma%d", zdev->rf->hw.device);
+ if (ret)
+ pr_err("zrdma: Register RDMA device fail\n");
+
+ return ret;
+}
diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.h b/drivers/infiniband/hw/zrdma/zrdma_verbs.h
new file mode 100644
index 0000000000000..a4b628651bf02
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+ *
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#ifndef ZRDMA_VERBS_H
+#define ZRDMA_VERBS_H
+
+#include <rdma/ib_umem.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/uverbs_ioctl.h>
+
+#define CHIP_VERSION 1
+#define ZXDH_PAGE_OFFSET_NUM (PAGE_SIZE - 1)
+#define MAX_HW_WQ_FRAGS 15
+#define MAX_HW_READ_SGES 15
+#define MAX_HW_INLINE 217
+#define MAX_HW_SRQ_WR 15
+#define MAX_HW_RQ_QUANTA 15
+#define MAX_HW_SRQ_QUANTA 15
+#define MAX_HW_WQ_QUANTA 15
+#define MAX_HW_SQ_CHUNK 0x8000
+#define MAX_HW_CQ_SIZE 0x200000
+#define MIN_HW_CQ_SIZE 4
+
+#define ZXDH_MTU_HEADER_RSV 102
+
+#define ZXDH_PKEY_TBL_SZ 1
+#define ZXDH_GID_TBL_LEN 255
+#define ZXDH_DEFAULT_PKEY 0xFFFF
+
+#define SQ_DB_BAR_OFF 0x4c000
+#define CQ_DB_BAR_OFF 0x43000
+#define SRQ_DB_MMAP_SIZE 0x10000
+#define SRQ_DB_BAR_OFF 0x62000
+
+#define MAX_MR_SIZE 0x200000000000
+#define MAX_QP 0x3fff
+#define MAX_QP_WR 0x1000
+#define MAX_CQ 0x3fff
+#define MAX_CQE 0x200000
+#define MAX_MR 0xfffe
+#define MAX_MW 0xfffe
+#define MAX_PD 0xfffff
+#define MAX_SEND_SGE 0xf
+#define MAX_RECV_SGE 0xf
+#define MAX_SGE_RD 0xf
+#define MAX_QP_RD_ATOM 0x10
+#define MAX_RES_RD_ATOM 0x3fff0
+#define MAX_QP_INIT_RD_ATOM 0x10
+#define MAX_SRQ 0x200
+#define MAX_SRQ_WR 0x7fff
+#define MAX_SRQ_SGE 0xf
+#define LOCAL_CA_ACK_DELAY 16
+#define HCA_CORE_CLOCK (1000 * 1000UL)
+#define MAX_WQ_TYPE_RQ 0x3fff
+#define MAX_AH 0x10000
+#define MAX_FAST_REG_PAGE_LIST_LEN 0x200
+#define MAX_CQ_MODERATION_COUNT 0xffff
+#define MAX_CQ_MODERATION_PERIOD 0x1cc
+#define TIMESTAMP_MASK 0x1ffff
+#define MAX_MSG_SZ 0x100000
+
+enum zxdh_mmap_flag {
+ ZXDH_MMAP_IO_NC,
+ ZXDH_MMAP_IO_WC,
+ ZXDH_MMAP_PFN,
+ ZXDH_MMAP_HMC,
+ ZXDH_MMAP_IO_NC_BY_SIZE,
+};
+
+struct zxdh_ucontext {
+ struct ib_ucontext ibucontext;
+ struct zxdh_device *zdev;
+ struct rdma_user_mmap_entry *sq_db_mmap_entry;
+ struct rdma_user_mmap_entry *cq_db_mmap_entry;
+ struct rdma_user_mmap_entry *srq_db_mmap_entry;
+ struct list_head cq_reg_mem_list;
+ spinlock_t cq_reg_mem_list_lock; /* protect CQ memory list */
+ struct list_head qp_reg_mem_list;
+ spinlock_t qp_reg_mem_list_lock; /* protect QP memory list */
+ struct list_head srq_reg_mem_list;
+ spinlock_t srq_reg_mem_list_lock; /* protect SRQ memory list */
+ int abi_ver;
+ atomic_t tx_port_affinity;
+};
+
+struct zxdh_pd {
+ struct ib_pd ibpd;
+ struct zxdh_sc_pd sc_pd;
+};
+
+struct zxdh_user_mmap_entry {
+ struct rdma_user_mmap_entry rdma_entry;
+ u64 bar_offset;
+ u8 mmap_flag;
+};
+
+void zxdh_ib_dealloc_device(struct ib_device *ibdev);
+
+static inline struct zxdh_pd *to_zpd(struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct zxdh_pd, ibpd);
+}
+
+static inline struct zxdh_ucontext *to_ucontext(struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct zxdh_ucontext, ibucontext);
+}
+
+static inline struct zxdh_user_mmap_entry *
+to_zxdh_mmap_entry(struct rdma_user_mmap_entry *rdma_entry)
+{
+ return container_of(rdma_entry, struct zxdh_user_mmap_entry,
+ rdma_entry);
+}
+
+static inline enum ib_mtu zxdh_mtu_int_to_enum(int mtu)
+{
+ mtu = mtu - ZXDH_MTU_HEADER_RSV;
+ if (mtu >= 4096)
+ return IB_MTU_4096;
+ else if (mtu >= 2048)
+ return IB_MTU_2048;
+ else if (mtu >= 1024)
+ return IB_MTU_1024;
+ else if (mtu >= 512)
+ return IB_MTU_512;
+ else
+ return IB_MTU_256;
+}
+
+#endif /* ZRDMA_VERBS_H */
--
2.43.5