* [PATCH rdma v7 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA
@ 2026-10-27 2:11 Yanze Zhang
2026-10-27 2:11 ` [PATCH rdma v7 1/7] RDMA/zrdma: Add build infrastructure and module skeleton Yanze Zhang
` (6 more replies)
0 siblings, 7 replies; 16+ messages in thread
From: Yanze Zhang @ 2026-10-27 2:11 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu
Cc: Markus.Elfring, lkp, linux-kernel, linux-rdma, wei.quan,
han.junyang, ran.ming, han.chengfei, zhang.yanze
Hi,
This is v7 of the ZTE DingHai (ZXDH) RDMA driver, providing RoCEv2
support for ZTE DingHai network adapters.
The DingHai Ethernet PF driver this RDMA driver attaches to is being
merged through net-next. The first batch, which introduces the DINGHAI
Kconfig symbol and the "dinghai10e" PF driver, is already in net-next
[1]; the second batch is still under review [2]. The auxiliary device
that this driver binds to is created by a patch that is still being
prepared and has not been posted yet; this series is therefore posted
for review ahead of that patch, and the driver will not probe on the
upstream baseline until it lands. This series is based on an
rdma/for-next baseline that already contains the first batch, so
"depends on DINGHAI" resolves. The driver registers as an auxiliary
driver and matches the auxiliary device by name only, so it cannot bind
to an unrelated PCI function.
v7 folds the review feedback on v6 [3] back into the patch that
introduced the affected code. Each change below was verified against
the reported issue before being applied:
- Patch 2/7: tag the UAPI header with the Linux-syscall-note SPDX
identifier, which is required for a header that is installed to
userspace.
- Patch 3/7: pass the name buffer length to zxdh_get_del_rdma_name()
and use guard(spinlock_irqsave) in zxdh_free_rsrc(); zxdh_alloc_rsrc()
keeps the explicit lock because of its multiple early exits.
- Patch 4/7: keep zrdma_main.c in place. v6 removed it in the middle
of the series, which broke both bisection and the build of that
single commit; the probe implementation now modifies the file
instead.
- Patch 5/7: install the device ops right after ib_alloc_device(), so
the dealloc_driver hook is in place before any resource is taken.
The hook releases the pci function, the handler and the resource
bitmaps, and it only destroys the ah_list_lock when it was actually
initialised.
- Patch 6/7: report the SRQ doorbell offset like the SQ and CQ
doorbells, and extend the SRQ mapping so that it covers the whole
doorbell area on 16K and 64K page systems. The size handed to
userspace is the very same length that is registered, otherwise
rdma_user_mmap_entry_get() rejects the mmap.
- Patch 7/7: accept a NULL udata in query_device(), which is how the
core calls it during registration; report the number of send and
receive SGEs; parse the firmware version as unsigned values and
keep the "N/A" placeholder when no version can be extracted; read
the driver info with rtnl held, taking the lock only when the
caller does not hold it already; take the port speed from
ib_get_eth_speed() instead of caching a value that goes stale on a
link change; fill in the immutable port information directly, so
that it does not depend on the port query being run while the
device is still being registered; pass the port number to
rdma_protocol_roce() instead of hard coding it; drop the query_gid
callback, as the RoCE GID cache is owned by the core.
In short, v7 additionally fixes:
- The UAPI SPDX identifier, which headers_install rejected because the
header is installed to userspace.
- The probe error paths, which leaked the pci function, the handler and
the hardware resource buffers because dealloc_driver was not
registered early enough.
- The deletion of zrdma_main.c in the middle of the series, which broke
both bisection and the build of that single commit.
- The NULL dereference of udata in query_device(), which
ib_register_device() passes as NULL.
- The missing max_send_sge and max_recv_sge, the SRQ doorbell page
offset on 16K and 64K page systems, and the misuse of
rtnl_trylock() in get_drvinfo().
- The immutable port information, which was taken from the port query
while the device was still being registered.
rmmod stress-testing also found a refcount_underflow in
ib_device.refcount: ib_unregister_device_and_put() performs an extra
put, but the auxiliary-bus probe path never takes a 'get'. The driver
uses plain ib_unregister_device(); ib_dealloc_device() still runs
.dealloc_driver via the normal refcount-release path. The issue was
reproduced before the fix, and the fix was verified with repeated
load/unload cycles on v6. v7 keeps the very same plain
ib_unregister_device() path, so the fix itself is unchanged.
Testing in this version focuses on the review fixes: the driver
builds, probes on DingHai hardware, and 'rdma link' / 'ibv_devinfo'
enumerate the device. The hardware testing was done with a PF driver
that already creates the auxiliary device, because the baseline that
this series is based on only has the first batch, which does not create
it yet. The build was tested with CONFIG_DINGHAI=y, because the Kconfig
now depends on it, and every commit of the series was built on its own
to make sure that the series stays bisectable. Perftest (QP/CQ/MR
creation and the data path) is covered by the parallel network driver
series, so we did not want to hold these review fixes on it. Functional
verbs testing will be reported once both series are merged.
Two items raised in review are deliberately left out because they
need input we do not have yet:
- The common_func() opcode for the IRQ capability query: needs
confirmation against the firmware interface document; the current
opcode works on the tested firmware.
- The shutdown-vs-quiesce semantics and the doorbell isolation
mechanism: these need the hardware team's confirmation.
Two other points are noted for completeness. An __iomem annotation on
mem_rsrc is moot, since it is plain vzalloc'd memory rather than a BAR
mapping. Replacing the resource bitmaps with XArray/IDA is a cleanup
that does not change behaviour and will follow separately. Neither of
them affects probe/remove or the verbs that are implemented here.
[1] https://lore.kernel.org/netdev/178598040988.599522.8462097247667886071.git-patchwork-notify@kernel.org/
[2] https://lore.kernel.org/netdev/20261014151200489685SCIlolykW0NGfL5EtQ@zte.com.cn/
[3] https://lore.kernel.org/linux-rdma/20261024071539.2182864-1-zhang.yanze@zte.com.cn/
Yanze Zhang (7):
RDMA/zrdma: Add build infrastructure and module skeleton
RDMA/zrdma: Add core data structures and ABI definitions
RDMA/zrdma: Add internal headers and hardware register definitions
RDMA/zrdma: Add hardware resource initialization and verbs skeleton
RDMA/zrdma: Add device probe and remove logic
RDMA/zrdma: Implement context, PD, and mmap operations
RDMA/zrdma: Implement device and port query operations
MAINTAINERS | 6 +
drivers/infiniband/Kconfig | 1 +
drivers/infiniband/hw/Makefile | 1 +
drivers/infiniband/hw/zrdma/Kconfig | 11 +
drivers/infiniband/hw/zrdma/Makefile | 7 +
drivers/infiniband/hw/zrdma/zrdma_ctrl.h | 22 +
drivers/infiniband/hw/zrdma/zrdma_defs.h | 19 +
drivers/infiniband/hw/zrdma/zrdma_hw.c | 118 ++++
drivers/infiniband/hw/zrdma/zrdma_hw.h | 21 +
drivers/infiniband/hw/zrdma/zrdma_main.c | 305 ++++++++++
drivers/infiniband/hw/zrdma/zrdma_main.h | 216 +++++++
drivers/infiniband/hw/zrdma/zrdma_type.h | 86 +++
drivers/infiniband/hw/zrdma/zrdma_verbs.c | 697 ++++++++++++++++++++++
drivers/infiniband/hw/zrdma/zrdma_verbs.h | 134 +++++
include/uapi/rdma/ib_user_ioctl_verbs.h | 1 +
include/uapi/rdma/zrdma_abi.h | 80 +++
16 files changed, 1725 insertions(+)
create mode 100644 drivers/infiniband/hw/zrdma/Kconfig
create mode 100644 drivers/infiniband/hw/zrdma/Makefile
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_ctrl.h
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_defs.h
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_hw.c
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_hw.h
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_main.c
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_main.h
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_type.h
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_verbs.c
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_verbs.h
create mode 100644 include/uapi/rdma/zrdma_abi.h
--
2.27.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH rdma v7 1/7] RDMA/zrdma: Add build infrastructure and module skeleton
2026-10-27 2:11 [PATCH rdma v7 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
@ 2026-10-27 2:11 ` Yanze Zhang
2026-10-27 2:30 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 2/7] RDMA/zrdma: Add core data structures and ABI definitions Yanze Zhang
` (5 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Yanze Zhang @ 2026-10-27 2:11 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu
Cc: Markus.Elfring, lkp, linux-kernel, linux-rdma, wei.quan,
han.junyang, ran.ming, han.chengfei, zhang.yanze
Add MAINTAINERS entry, Kconfig, and Makefile entries for the ZTE DingHai
RDMA driver. Include a minimal module skeleton with auxiliary driver
registration structure to ensure the build system works and the module
can be loaded.
The driver depends on DINGHAI because it binds to the auxiliary device
that the DingHai PF driver will create. The DINGHAI symbol itself is
already present in the rdma/for-next baseline this series is based on,
so the dependency resolves.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
MAINTAINERS | 6 +++
drivers/infiniband/Kconfig | 1 +
drivers/infiniband/hw/Makefile | 1 +
drivers/infiniband/hw/zrdma/Kconfig | 11 +++++
drivers/infiniband/hw/zrdma/Makefile | 4 ++
drivers/infiniband/hw/zrdma/zrdma_main.c | 57 ++++++++++++++++++++++++
include/uapi/rdma/ib_user_ioctl_verbs.h | 1 +
7 files changed, 81 insertions(+)
create mode 100644 drivers/infiniband/hw/zrdma/Kconfig
create mode 100644 drivers/infiniband/hw/zrdma/Makefile
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_main.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 2a6e6ec629e0..84a2c6fc3699 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -30193,6 +30193,12 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/zte/
+ZTE DINGHAI ZRDMA DRIVER
+M: Yanze Zhang <zhang.yanze@zte.com.cn>
+L: linux-rdma@vger.kernel.org
+S: Supported
+F: drivers/infiniband/hw/zrdma/
+
THE REST
M: Linus Torvalds <torvalds@linux-foundation.org>
L: linux-kernel@vger.kernel.org
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 086195758a8a..419dbf742f38 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -100,6 +100,7 @@ source "drivers/infiniband/hw/ocrdma/Kconfig"
source "drivers/infiniband/hw/qedr/Kconfig"
source "drivers/infiniband/hw/usnic/Kconfig"
source "drivers/infiniband/hw/vmw_pvrdma/Kconfig"
+source "drivers/infiniband/hw/zrdma/Kconfig"
source "drivers/infiniband/sw/rdmavt/Kconfig"
endif # !UML
source "drivers/infiniband/sw/rxe/Kconfig"
diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile
index c42b22ac3303..a86b867c56d4 100644
--- a/drivers/infiniband/hw/Makefile
+++ b/drivers/infiniband/hw/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_INFINIBAND_BNXT_RE) += bnxt_re/
obj-$(CONFIG_INFINIBAND_BNG_RE) += bng_re/
obj-$(CONFIG_INFINIBAND_ERDMA) += erdma/
obj-$(CONFIG_INFINIBAND_IONIC) += ionic/
+obj-$(CONFIG_INFINIBAND_ZRDMA) += zrdma/
diff --git a/drivers/infiniband/hw/zrdma/Kconfig b/drivers/infiniband/hw/zrdma/Kconfig
new file mode 100644
index 000000000000..43cb55ae9c93
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+config INFINIBAND_ZRDMA
+ tristate "ZTE Ethernet Protocol Driver for RDMA"
+ depends on DINGHAI
+ select AUXILIARY_BUS
+ help
+ Say Y or M here to enable support for the ZTE DingHai (ZXDH) Ethernet
+ Protocol Driver for RDMA. This driver provides RDMA over Converged
+ Ethernet (RoCE) functionality for ZTE DingHai network adapters.
+ If you choose to build this driver as a module, it will be built as
+ a module named zrdma.
diff --git a/drivers/infiniband/hw/zrdma/Makefile b/drivers/infiniband/hw/zrdma/Makefile
new file mode 100644
index 000000000000..2ddf50d1fd20
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+
+obj-$(CONFIG_INFINIBAND_ZRDMA) += zrdma.o
+zrdma-y := zrdma_main.o
diff --git a/drivers/infiniband/hw/zrdma/zrdma_main.c b/drivers/infiniband/hw/zrdma/zrdma_main.c
new file mode 100644
index 000000000000..af1d37be6336
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_main.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/auxiliary_bus.h>
+
+#define ZXDH_PF_NAME "dinghai10e"
+#define ZXDH_RDMA_DEV_NAME "rdma_aux"
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Yanze Zhang <zhang.yanze@zte.com.cn>");
+MODULE_DESCRIPTION("ZTE Ethernet Protocol Driver for RDMA");
+
+static const struct auxiliary_device_id zxdh_auxiliary_id_table[] = {
+ {
+ .name = ZXDH_PF_NAME "." ZXDH_RDMA_DEV_NAME,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(auxiliary, zxdh_auxiliary_id_table);
+
+static int zxdh_probe(struct auxiliary_device *aux_dev,
+ const struct auxiliary_device_id *id)
+{
+ /* Placeholder: Real probe logic will be added in subsequent patches */
+ dev_info(&aux_dev->dev, "ZTE DingHai RDMA device detected (stub)\n");
+ return 0;
+}
+
+static void zxdh_remove(struct auxiliary_device *aux_dev)
+{
+ dev_info(&aux_dev->dev, "ZTE DingHai RDMA device removed (stub)\n");
+}
+
+static struct auxiliary_driver zxdh_auxiliary_drv = {
+ .name = ZXDH_RDMA_DEV_NAME,
+ .id_table = zxdh_auxiliary_id_table,
+ .probe = zxdh_probe,
+ .remove = zxdh_remove,
+};
+
+static int __init zrdma_module_init(void)
+{
+ return auxiliary_driver_register(&zxdh_auxiliary_drv);
+}
+
+static void __exit zrdma_module_exit(void)
+{
+ auxiliary_driver_unregister(&zxdh_auxiliary_drv);
+}
+
+module_init(zrdma_module_init);
+module_exit(zrdma_module_exit);
diff --git a/include/uapi/rdma/ib_user_ioctl_verbs.h b/include/uapi/rdma/ib_user_ioctl_verbs.h
index 21f86cc7bb1f..98dcea207357 100644
--- a/include/uapi/rdma/ib_user_ioctl_verbs.h
+++ b/include/uapi/rdma/ib_user_ioctl_verbs.h
@@ -257,6 +257,7 @@ enum rdma_driver_id {
RDMA_DRIVER_ERDMA,
RDMA_DRIVER_MANA,
RDMA_DRIVER_IONIC,
+ RDMA_DRIVER_ZRDMA,
};
enum ib_uverbs_gid_type {
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH rdma v7 2/7] RDMA/zrdma: Add core data structures and ABI definitions
2026-10-27 2:11 [PATCH rdma v7 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
2026-10-27 2:11 ` [PATCH rdma v7 1/7] RDMA/zrdma: Add build infrastructure and module skeleton Yanze Zhang
@ 2026-10-27 2:11 ` Yanze Zhang
2026-10-27 2:28 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 3/7] RDMA/zrdma: Add internal headers and hardware register definitions Yanze Zhang
` (4 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Yanze Zhang @ 2026-10-27 2:11 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu
Cc: Markus.Elfring, lkp, linux-kernel, linux-rdma, wei.quan,
han.junyang, ran.ming, han.chengfei, zhang.yanze
Add fundamental data structures, hardware control structures, and
user-space ABI definitions required by the driver. These headers
provide the type definitions for the subsequent implementation patches.
The UAPI header is installed to userspace, so it carries the
Linux-syscall-note SPDX tag that headers_install requires for a
GPL-licensed UAPI header.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/zrdma_ctrl.h | 22 ++++++
drivers/infiniband/hw/zrdma/zrdma_defs.h | 19 ++++++
drivers/infiniband/hw/zrdma/zrdma_type.h | 86 ++++++++++++++++++++++++
include/uapi/rdma/zrdma_abi.h | 80 ++++++++++++++++++++++
4 files changed, 207 insertions(+)
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_ctrl.h
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_defs.h
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_type.h
create mode 100644 include/uapi/rdma/zrdma_abi.h
diff --git a/drivers/infiniband/hw/zrdma/zrdma_ctrl.h b/drivers/infiniband/hw/zrdma/zrdma_ctrl.h
new file mode 100644
index 000000000000..d25570683b61
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_ctrl.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+ *
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#ifndef ZRDMA_CTRL_H
+#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;
+};
+
+#endif
diff --git a/drivers/infiniband/hw/zrdma/zrdma_defs.h b/drivers/infiniband/hw/zrdma/zrdma_defs.h
new file mode 100644
index 000000000000..208f1f60bbae
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_defs.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+ *
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#ifndef ZRDMA_DEFS_H
+#define ZRDMA_DEFS_H
+
+#include <linux/bitfield.h>
+#include <rdma/ib_verbs.h>
+
+#define ZXDH_FEATURE_RTS_AE 1ULL
+#define ZXDH_FEATURE_CQ_RESIZE 2ULL
+#define ZXDH_FEATURE_64_BYTE_CQE 128ULL
+
+#define ZXDH_MAX_USER_PRIORITY 8
+
+#endif /* ZRDMA_DEFS_H */
diff --git a/drivers/infiniband/hw/zrdma/zrdma_type.h b/drivers/infiniband/hw/zrdma/zrdma_type.h
new file mode 100644
index 000000000000..ded405245345
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_type.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+ *
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#ifndef ZRDMA_TYPE_H
+#define ZRDMA_TYPE_H
+
+#include <linux/auxiliary_bus.h>
+#include <linux/msi.h>
+
+enum zxdh_rdma_reset_type {
+ ZXDH_RDMA_PFR,
+ ZXDH_RDMA_CORER,
+ ZXDH_RDMA_GLOBR,
+};
+
+enum zxdh_function_type {
+ ZXDH_FUNCTION_TYPE_PF,
+ ZXDH_FUNCTION_TYPE_VF,
+};
+
+struct zxdh_rdma_core_dev;
+
+struct zxdh_rdma_core_ops {
+ int (*request_reset)(struct zxdh_rdma_core_dev *cdev,
+ enum zxdh_rdma_reset_type reset_type);
+ int (*zxdh_common_func)(void *in_param, void *out_param, u32 opcode);
+};
+
+struct zxdh_rdma_ver_info {
+ u16 major;
+ u16 minor;
+ u64 support; /* 0~7:net_major,8~15:net_minor,16~23:rdma_minor,24~63:rscv */
+};
+
+enum zxdh_rdma_protocol {
+ ZXDH_RDMA_PROTOCOL_IWARP = BIT(0),
+ ZXDH_RDMA_PROTOCOL_ROCEV2 = BIT(1),
+};
+
+struct zxdh_qos_params {
+ u8 num_tc;
+};
+
+struct zxdh_rdma_core_dev {
+ struct pci_dev *pdev;
+ struct auxiliary_device *adev;
+ u8 __iomem *hw_addr;
+ int zdev_info_id;
+ struct zxdh_rdma_ver_info ver;
+ void *auxiliary_priv;
+ enum zxdh_function_type ftype;
+ u16 vport_id;
+ u16 slot_id;
+ enum zxdh_rdma_protocol rdma_protocol;
+
+ struct zxdh_qos_params qos_info;
+ struct msix_entry *msix_entries;
+ u16 msix_count;
+ const struct zxdh_rdma_core_ops *ops;
+ void *dh_dev;
+};
+
+struct zxdh_rdma_if {
+ void *(*get_rdma_netdev)(void *dh_dev);
+};
+
+struct zxdh_auxiliary_dev {
+ struct auxiliary_device adev;
+ struct zxdh_rdma_core_dev *zxdh_info;
+ struct zxdh_rdma_if *rdma_ops;
+ void *ops;
+ void *parent;
+ s32 aux_id;
+ void *auxiliary_ops[18];
+};
+
+struct zxdh_sc_pd {
+ struct zxdh_sc_dev *dev;
+ u32 pd_id;
+ int abi_ver;
+};
+
+#endif /* ZRDMA_TYPE_H */
diff --git a/include/uapi/rdma/zrdma_abi.h b/include/uapi/rdma/zrdma_abi.h
new file mode 100644
index 000000000000..ac7bc023cf16
--- /dev/null
+++ b/include/uapi/rdma/zrdma_abi.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR Linux-OpenIB)
+ *
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#ifndef ZRDMA_ABI_H
+#define ZRDMA_ABI_H
+
+#include <linux/types.h>
+
+/* user-space whose last ABI ver is 5 */
+#define ZXDH_ABI_VER 5
+#define ZXDH_CONTEXT_VER_V1 5
+#define ZXDH_CONTEXT_VER_V2 6
+#define ZXDH_CONTEXT_VER_V3 7
+
+enum zxdh_rdma_tool_flags {
+ ZXDH_QP_EXTEND_OP = 1 << 0,
+ ZXDH_CAPTURE = 1 << 1,
+ ZXDH_GET_HW_DATA = 1 << 2,
+ ZXDH_GET_HW_OBJECT_DATA = 1 << 3,
+ ZXDH_CHECK_HW_HEALTH = 1 << 4,
+ ZXDH_RDMA_TOOL_CFG_DEV_PARAM = 1 << 5,
+ ZXDH_RDMA_TOOL_READ_RAM = 1 << 6,
+ ZXDH_RDMA_TOOL_DEVX_MODIFY_CQ = 1 << 7,
+ ZXDH_RDMA_SET_CREDIT_CAP = 1 << 8,
+ ZXDH_RDMA_SWITCH = 1 << 9,
+ ZXDH_RDMA_TOOL_DEVX_EXT_MEM = 1 << 10,
+ ZXDH_RDMA_TOOL_PRIV_EXT = 1 << 11,
+ ZXDH_RDMA_TOOL_IOVA_CAP = 1 << 12,
+};
+
+enum zxdh_db_addr_type {
+ ZXDH_DB_ADDR_PHY = 0,
+ ZXDH_DB_ADDR_BAR = 1,
+};
+
+struct zxdh_alloc_ucontext_req {
+ __u32 rsvd32;
+ __u8 userspace_ver;
+ __u8 rsvd8[3];
+};
+
+struct zxdh_alloc_ucontext_resp {
+ __u32 max_pds;
+ __u32 max_qps;
+ __u32 wq_size; /* size of the WQs (SQ+RQ) in the mmaped area */
+ __u8 kernel_ver;
+ __u8 db_addr_type;
+ __u16 rdma_tool_flags;
+ __aligned_u64 feature_flags;
+ __aligned_u64 sq_db_mmap_key;
+ __aligned_u64 cq_db_mmap_key;
+ __u32 max_hw_wq_frags;
+ __u32 max_hw_read_sges;
+ __u32 max_hw_inline;
+ __u32 max_hw_rq_quanta;
+ __u32 max_hw_srq_quanta;
+ __u32 max_hw_wq_quanta;
+ __u32 max_hw_srq_wr;
+ __u32 min_hw_cq_size;
+ __u32 max_hw_cq_size;
+ __u16 max_hw_sq_chunk;
+ __u8 hw_rev;
+ __u8 chip_rev;
+ __aligned_u64 srq_db_mmap_key;
+ __aligned_u64 sq_db_bar_off;
+ __aligned_u64 cq_db_bar_off;
+ __aligned_u64 srq_db_bar_off;
+ __u32 srq_db_mmap_size;
+ __u16 rsv[6];
+};
+
+struct zxdh_alloc_pd_resp {
+ __u32 pd_id;
+ __u8 rsvd[4];
+};
+
+#endif /* ZRDMA_ABI_H */
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH rdma v7 3/7] RDMA/zrdma: Add internal headers and hardware register definitions
2026-10-27 2:11 [PATCH rdma v7 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
2026-10-27 2:11 ` [PATCH rdma v7 1/7] RDMA/zrdma: Add build infrastructure and module skeleton Yanze Zhang
2026-10-27 2:11 ` [PATCH rdma v7 2/7] RDMA/zrdma: Add core data structures and ABI definitions Yanze Zhang
@ 2026-10-27 2:11 ` Yanze Zhang
2026-10-27 2:26 ` sashiko-bot
2026-10-27 7:10 ` Markus Elfring
2026-10-27 2:11 ` [PATCH rdma v7 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton Yanze Zhang
` (3 subsequent siblings)
6 siblings, 2 replies; 16+ messages in thread
From: Yanze Zhang @ 2026-10-27 2:11 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu
Cc: Markus.Elfring, lkp, linux-kernel, linux-rdma, wei.quan,
han.junyang, ran.ming, han.chengfei, zhang.yanze
Add internal header files for main driver logic and hardware registers.
These headers define the structures and constants used by the subsequent
implementation patches.
zxdh_free_rsrc() uses guard(spinlock_irqsave), so the lock is released on
every exit path. zxdh_alloc_rsrc() keeps the explicit locking, as it has
several early return paths, and takes a pool name so that the exhaustion
log identifies the affected pool.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/zrdma_hw.h | 21 +++
drivers/infiniband/hw/zrdma/zrdma_main.h | 216 +++++++++++++++++++++++
2 files changed, 237 insertions(+)
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_hw.h
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_main.h
diff --git a/drivers/infiniband/hw/zrdma/zrdma_hw.h b/drivers/infiniband/hw/zrdma/zrdma_hw.h
new file mode 100644
index 000000000000..16c5041ac075
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_hw.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+ *
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#ifndef ZRDMA_HW_H
+#define ZRDMA_HW_H
+#include "zrdma_main.h"
+
+#define ZXDH_MAX_CQE 0x200000
+#define ZXDH_MAX_QP 0x4000
+#define ZXDH_MAX_MR 0x10000
+#define ZXDH_MAX_CQ 0x4000
+#define ZXDH_MAX_SRQ 0x2000
+#define ZXDH_MAX_PD 0x100000
+#define ZXDH_MAX_AH 0x10000
+#define ZXDH_MAX_MCG 0x4000
+#define ZXDH_MAX_8K_IDX 0x1c0
+
+#endif /* ZRDMA_HW_H */
diff --git a/drivers/infiniband/hw/zrdma/zrdma_main.h b/drivers/infiniband/hw/zrdma/zrdma_main.h
new file mode 100644
index 000000000000..30bb195b0c56
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_main.h
@@ -0,0 +1,216 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+ *
+ * ZTE DingHai Rdma driver
+ * Copyright (c) 2022-2026, ZTE Corporation
+ */
+
+#ifndef ZRDMA_MAIN_H
+#define ZRDMA_MAIN_H
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/zrdma_abi.h>
+#include <net/addrconf.h>
+
+#include "zrdma_type.h"
+#include "zrdma_ctrl.h"
+#include "zrdma_defs.h"
+
+#define ZXDH_PF_NAME "dinghai10e"
+#define ZXDH_RDMA_DEV_NAME "rdma_aux"
+
+#define ZXDH_FUNC_TYPE(vport_id) (((vport_id) >> 11) & 0x1)
+#define ZXDH_PF_ID(vport_id) (((vport_id) >> 8) & 0x7)
+#define ZXDH_EP_ID(vport_id) (((vport_id) >> 12) & 0x7)
+
+#define PCI_SBDF_SAFE_LEN 64
+#define ZXDH_RST_TIMEOUT_HZ 4
+
+#define ZXDH_RDMA_COMMON_FUNC_CAP 1
+#define ZXDH_RDMA_COMM_FUNC BIT_ULL(24)
+
+extern struct list_head zxdh_handlers;
+extern spinlock_t zxdh_handler_lock;
+extern const struct ib_device_ops zxdh_dev_ops;
+
+struct zxdh_pci_f;
+
+struct zxdh_rdma_node {
+ char name[IB_DEVICE_NAME_MAX];
+ char sbdf[PCI_SBDF_SAFE_LEN];
+ struct list_head list;
+};
+
+enum zxdh_func_type {
+ ZXDH_FUNC_NUM_REQUIRE = 0,
+ ZXDH_FUNC_NP_MAC = 1,
+ ZXDH_FUNC_IRQ_REQUEST = 2,
+ ZXDH_FUNC_IRQ_FREE = 3,
+ ZXDH_FUNC_PMTU_INFO_ADD = 4,
+ ZXDH_FUNC_PMTU_INFO_DEL = 5,
+ ZXDH_FUNC_QP_INFO_DEL_WX = 6,
+ ZXDH_FUNC_NETDEV_SPEED_GET = 7,
+ ZXDH_FUNC_SEARCH_MAC_FROM_FW = 8,
+ ZXDH_COMM_FUNC_GET_TRUST_TYPE = 9,
+ ZXDH_FUNC_VF_VLAN_GET = 10,
+ ZXDH_FUNC_NUM_MAX,
+};
+
+enum init_completion_state {
+ INVALID_STATE = 0,
+ INITIAL_STATE,
+ CQP_CREATED,
+ SMMU_PAGETABLE_INITIALIZED,
+ DATA_CAP_CREATED,
+ HMC_OBJS_CREATED,
+ HW_RSRC_INITIALIZED,
+ CQP_QP_CREATED,
+ AEQ_CREATED,
+ CCQ_CREATED,
+ CEQ0_CREATED,
+ CEQS_CREATED,
+ PBLE_CHUNK_MEM,
+};
+
+enum zxdh_rdma_vers {
+ ZXDH_GEN_RSVD,
+ ZXDH_GEN_1,
+ ZXDH_GEN_2,
+};
+
+struct zxdh_handler {
+ struct list_head list;
+ struct zxdh_device *zdev;
+};
+
+struct zxdh_gen_ops {
+ void (*request_reset)(struct zxdh_pci_f *rf);
+ int (*zxdh_common_func)(void *in_param, void *out_param, u32 opcode);
+};
+
+struct zxdh_pci_f {
+ u8 ftype : 1;
+ u8 *mem_rsrc;
+ u8 rdma_ver;
+ u8 rst_to;
+ u8 pf_id;
+ u8 ep_id;
+ u32 msix_count;
+ u32 max_mr;
+ u32 max_qp;
+ u32 max_cq;
+ u32 max_ah;
+ u32 max_mcg;
+ u32 max_pd;
+ u32 next_pd;
+ u32 max_cqe;
+ u32 max_srq;
+ u32 max_pri;
+ u16 max_8k_idx;
+ u32 *qp_cnt_8k_idxs;
+ u32 ceqs_count;
+
+ unsigned long *allocated_qps;
+ unsigned long *allocated_cqs;
+ unsigned long *allocated_mrs;
+ unsigned long *allocated_pds;
+ unsigned long *allocated_mcgs;
+ unsigned long *allocated_ahs;
+ unsigned long *allocated_srqs;
+ unsigned long *allocated_pris;
+ unsigned long *allocated_8k_idx;
+
+ struct zxdh_sc_dev sc_dev;
+ struct pci_dev *pcidev;
+ struct zxdh_rdma_core_dev *zdev_info;
+ struct zxdh_hw hw;
+
+ spinlock_t rsrc_lock; /* protects resource allocation arrays */
+ spinlock_t qptable_lock; /* protects qp_table access */
+ spinlock_t cqtable_lock; /* protects cq_table access */
+ struct zxdh_qp **qp_table;
+ struct zxdh_cq **cq_table;
+ spinlock_t srqtable_lock; /* protects srq_table access */
+ struct zxdh_srq **srq_table;
+
+ struct msix_entry *msix_entries;
+ struct zxdh_gen_ops gen_ops;
+ struct zxdh_device *zdev;
+ u16 pcie_id;
+ u16 qp_index;
+ u32 srq_mem_size;
+ bool drv_np_cap;
+ bool net_irq_cap;
+ int common_func_num_max;
+ void *dh_dev;
+};
+
+struct zxdh_device {
+ struct ib_device ibdev;
+ struct zxdh_pci_f *rf;
+ struct net_device *netdev;
+ struct net_device *source_netdev;
+ struct zxdh_handler *hdl;
+ struct list_head ah_list;
+ struct mutex ah_list_lock; /* protects ah_list operations */
+ u8 ibdev_status;
+ u8 roce_mode : 1;
+ enum init_completion_state init_state;
+ struct zxdh_auxiliary_dev *zxdh_adev;
+ atomic_t tx_port_affinity;
+ atomic_t sport_counter;
+};
+
+static inline struct zxdh_device *to_zdev(struct ib_device *ibdev)
+{
+ return container_of(ibdev, struct zxdh_device, ibdev);
+}
+
+static inline int zxdh_alloc_rsrc(struct zxdh_pci_f *rf,
+ unsigned long *rsrc_array, u32 max_rsrc,
+ u32 *req_rsrc_num, u32 *next,
+ const char *rsrc_name)
+{
+ unsigned long flags;
+ u32 rsrc_num;
+
+ spin_lock_irqsave(&rf->rsrc_lock, flags);
+ rsrc_num = find_next_zero_bit(rsrc_array, max_rsrc, *next);
+ if (rsrc_num >= max_rsrc) {
+ rsrc_num = find_first_zero_bit(rsrc_array, max_rsrc);
+ if (rsrc_num >= max_rsrc) {
+ spin_unlock_irqrestore(&rf->rsrc_lock, flags);
+ pr_err("zrdma: %s pool exhausted (capacity %u)\n",
+ rsrc_name, max_rsrc);
+ return -EOVERFLOW;
+ }
+ }
+ __set_bit(rsrc_num, rsrc_array);
+ *next = rsrc_num + 1;
+ if (*next == max_rsrc)
+ *next = 0;
+ *req_rsrc_num = rsrc_num;
+ spin_unlock_irqrestore(&rf->rsrc_lock, flags);
+
+ return 0;
+}
+
+static inline void zxdh_free_rsrc(struct zxdh_pci_f *rf,
+ unsigned long *rsrc_array, u32 rsrc_num)
+{
+ guard(spinlock_irqsave)(&rf->rsrc_lock);
+
+ __clear_bit(rsrc_num, rsrc_array);
+}
+
+int zxdh_get_del_rdma_name(const char *sbdf, char *name, size_t name_len);
+int zxdh_ctrl_init_hw(struct zxdh_pci_f *rf);
+int zxdh_ib_register_device(struct zxdh_device *zdev);
+void zxdh_del_handler(struct zxdh_handler *hdl);
+
+#endif /* ZRDMA_MAIN_H */
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH rdma v7 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton
2026-10-27 2:11 [PATCH rdma v7 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
` (2 preceding siblings ...)
2026-10-27 2:11 ` [PATCH rdma v7 3/7] RDMA/zrdma: Add internal headers and hardware register definitions Yanze Zhang
@ 2026-10-27 2:11 ` Yanze Zhang
2026-10-27 2:33 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 5/7] RDMA/zrdma: Add device probe and remove logic Yanze Zhang
` (2 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Yanze Zhang @ 2026-10-27 2:11 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu
Cc: Markus.Elfring, lkp, linux-kernel, linux-rdma, wei.quan,
han.junyang, ran.ming, han.chengfei, zhang.yanze
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 device ops are exported so that the probe path can install them
right after ib_alloc_device(), which makes the dealloc_driver hook
effective for every later failure path.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/Makefile | 5 +-
drivers/infiniband/hw/zrdma/zrdma_hw.c | 118 +++++++++++++++++++
drivers/infiniband/hw/zrdma/zrdma_verbs.c | 39 +++++++
drivers/infiniband/hw/zrdma/zrdma_verbs.h | 134 ++++++++++++++++++++++
4 files changed, 295 insertions(+), 1 deletion(-)
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 2ddf50d1fd20..9bc3650a8f2a 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_hw.c b/drivers/infiniband/hw/zrdma/zrdma_hw.c
new file mode 100644
index 000000000000..068d9aea7c71
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_hw.c
@@ -0,0 +1,118 @@
+// 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.
+ */
+ 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_mr);
+ rsrc_size += sizeof(unsigned long) * BITS_TO_LONGS(rf->max_cq);
+ 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);
+
+ 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);
+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 000000000000..90ff9a826491
--- /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 000000000000..a4b628651bf0
--- /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.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH rdma v7 5/7] RDMA/zrdma: Add device probe and remove logic
2026-10-27 2:11 [PATCH rdma v7 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
` (3 preceding siblings ...)
2026-10-27 2:11 ` [PATCH rdma v7 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton Yanze Zhang
@ 2026-10-27 2:11 ` Yanze Zhang
2026-10-27 2:37 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 6/7] RDMA/zrdma: Implement context, PD, and mmap operations Yanze Zhang
2026-10-27 2:11 ` [PATCH rdma v7 7/7] RDMA/zrdma: Implement device and port query operations Yanze Zhang
6 siblings, 1 reply; 16+ messages in thread
From: Yanze Zhang @ 2026-10-27 2:11 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu
Cc: Markus.Elfring, lkp, linux-kernel, linux-rdma, wei.quan,
han.junyang, ran.ming, han.chengfei, zhang.yanze
Implement the auxiliary bus probe and remove functions, including device
initialization, hardware resource setup, and IB device registration.
This replaces the stub probe from the initial skeleton patch. The file
is modified rather than deleted, so every commit of the series builds on
its own.
The device ops are installed right after ib_alloc_device(), so the
dealloc_driver hook is in place before any resource is allocated and
every error path releases what it has taken. The hook itself is NULL
safe and only destroys the ah_list_lock when it was actually
initialised.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/zrdma_main.c | 276 ++++++++++++++++++++--
drivers/infiniband/hw/zrdma/zrdma_verbs.c | 29 +++
2 files changed, 291 insertions(+), 14 deletions(-)
diff --git a/drivers/infiniband/hw/zrdma/zrdma_main.c b/drivers/infiniband/hw/zrdma/zrdma_main.c
index af1d37be6336..14c36531cc45 100644
--- a/drivers/infiniband/hw/zrdma/zrdma_main.c
+++ b/drivers/infiniband/hw/zrdma/zrdma_main.c
@@ -6,36 +6,262 @@
#include <linux/module.h>
#include <linux/auxiliary_bus.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <rdma/ib_verbs.h>
-#define ZXDH_PF_NAME "dinghai10e"
-#define ZXDH_RDMA_DEV_NAME "rdma_aux"
+#include "zrdma_main.h"
+#include "zrdma_verbs.h"
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("zrdma");
MODULE_AUTHOR("Yanze Zhang <zhang.yanze@zte.com.cn>");
MODULE_DESCRIPTION("ZTE Ethernet Protocol Driver for RDMA");
+MODULE_LICENSE("Dual BSD/GPL");
-static const struct auxiliary_device_id zxdh_auxiliary_id_table[] = {
- {
- .name = ZXDH_PF_NAME "." ZXDH_RDMA_DEV_NAME,
- },
- {},
-};
+LIST_HEAD(zxdh_handlers);
+DEFINE_SPINLOCK(zxdh_handler_lock);
-MODULE_DEVICE_TABLE(auxiliary, zxdh_auxiliary_id_table);
+static struct mutex rdma_name_lock;
+static struct list_head zxdh_rdma_list;
+
+static void zxdh_add_handler(struct zxdh_handler *hdl)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&zxdh_handler_lock, flags);
+ list_add(&hdl->list, &zxdh_handlers);
+ spin_unlock_irqrestore(&zxdh_handler_lock, flags);
+}
+
+void zxdh_del_handler(struct zxdh_handler *hdl)
+{
+ unsigned long flags;
+
+ if (!hdl)
+ return;
+
+ spin_lock_irqsave(&zxdh_handler_lock, flags);
+ list_del(&hdl->list);
+ spin_unlock_irqrestore(&zxdh_handler_lock, flags);
+}
+
+int zxdh_get_del_rdma_name(const char *sbdf, char *name, size_t name_len)
+{
+ struct zxdh_rdma_node *pos, *tmp;
+ size_t len, sbdf_len;
+
+ if (!sbdf || !name || !name_len)
+ return -EINVAL;
+
+ if (name_len > IB_DEVICE_NAME_MAX) {
+ pr_err("zrdma: name buffer too large\n");
+ return -EINVAL;
+ }
+
+ sbdf_len = strlen(sbdf);
+
+ mutex_lock(&rdma_name_lock);
+ list_for_each_entry_safe(pos, tmp, &zxdh_rdma_list, list) {
+ len = strlen(pos->sbdf);
+ if (sbdf_len == len &&
+ strncasecmp(sbdf, pos->sbdf, len) == 0) {
+ snprintf(name, name_len, "%s", pos->name);
+ list_del(&pos->list);
+ kfree(pos);
+ mutex_unlock(&rdma_name_lock);
+ return 0;
+ }
+ }
+ mutex_unlock(&rdma_name_lock);
+ return -ENOENT;
+}
+
+/* Must be called after zxdh_get_common_func_num_max(). */
+static void zxdh_get_net_irq_cap(struct zxdh_pci_f *rf)
+{
+ if (rf->common_func_num_max > ZXDH_FUNC_IRQ_FREE &&
+ rf->common_func_num_max != 0xFF)
+ rf->net_irq_cap = true;
+}
+
+static void zxdh_get_common_func_num_max(struct zxdh_pci_f *rf)
+{
+ int num_max;
+
+ if (rf->gen_ops.zxdh_common_func) {
+ num_max = rf->gen_ops.zxdh_common_func(NULL, NULL,
+ ZXDH_FUNC_NUM_REQUIRE);
+ if (num_max >= 0 && num_max != 0xFF) {
+ rf->common_func_num_max = num_max;
+ return;
+ }
+ }
+ rf->common_func_num_max = -1;
+}
+
+static void zxdh_fill_device_info(struct zxdh_device *zdev,
+ struct zxdh_rdma_core_dev *zdev_info)
+{
+ struct zxdh_pci_f *rf = zdev->rf;
+
+ rf->ftype = ZXDH_FUNC_TYPE(zdev_info->vport_id);
+ rf->pf_id = ZXDH_PF_ID(zdev_info->vport_id);
+ rf->sc_dev.ep_id = ZXDH_EP_ID(zdev_info->vport_id);
+ rf->ep_id = rf->sc_dev.ep_id;
+ rf->sc_dev.driver_load = true;
+
+ rf->zdev_info = zdev_info;
+ rf->pcidev = zdev_info->pdev;
+
+ rf->msix_count = zdev_info->msix_count;
+ rf->msix_entries = zdev_info->msix_entries;
+ if (rf->msix_count)
+ rf->sc_dev.max_ceqs = (rf->msix_count - 1);
+ else
+ rf->sc_dev.max_ceqs = 0;
+ rf->rdma_ver = ZXDH_GEN_2;
+ rf->rst_to = ZXDH_RST_TIMEOUT_HZ;
+ rf->qp_index = 0;
+ rf->gen_ops.zxdh_common_func = NULL;
+ rf->net_irq_cap = false;
+ rf->dh_dev = NULL;
+ rf->drv_np_cap =
+ (bool)FIELD_GET(ZXDH_RDMA_COMM_FUNC, zdev_info->ver.support);
+ if (rf->drv_np_cap == ZXDH_RDMA_COMMON_FUNC_CAP) {
+ if (zdev_info->ops && zdev_info->ops->zxdh_common_func)
+ rf->gen_ops.zxdh_common_func =
+ zdev_info->ops->zxdh_common_func;
+ }
+
+ zxdh_get_common_func_num_max(rf);
+ zxdh_get_net_irq_cap(rf);
+
+ rf->zdev = zdev;
+
+ atomic_set(&zdev->tx_port_affinity, 0);
+ atomic_set(&zdev->sport_counter, 0);
+
+ INIT_LIST_HEAD(&zdev->ah_list);
+ mutex_init(&zdev->ah_list_lock);
+ zdev->init_state = INITIAL_STATE;
+ zdev->roce_mode = true;
+}
static int zxdh_probe(struct auxiliary_device *aux_dev,
const struct auxiliary_device_id *id)
{
- /* Placeholder: Real probe logic will be added in subsequent patches */
- dev_info(&aux_dev->dev, "ZTE DingHai RDMA device detected (stub)\n");
+ struct zxdh_auxiliary_dev *zxdh_adev =
+ container_of(aux_dev, struct zxdh_auxiliary_dev, adev);
+ struct zxdh_handler *hdl;
+ struct zxdh_device *zdev;
+ struct zxdh_pci_f *rf;
+ struct net_device *netdev;
+ int err;
+
+ if (!zxdh_adev->rdma_ops || !zxdh_adev->rdma_ops->get_rdma_netdev) {
+ pr_err("zrdma: rdma_ops or get_rdma_netdev is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!zxdh_adev->zxdh_info) {
+ pr_err("zrdma: zxdh_info is NULL\n");
+ return -EINVAL;
+ }
+
+ netdev = zxdh_adev->rdma_ops->get_rdma_netdev(zxdh_adev->parent);
+ if (!netdev) {
+ pr_err("zrdma: failed to get netdev\n");
+ return -ENODEV;
+ }
+
+ zdev = ib_alloc_device(zxdh_device, ibdev);
+ if (!zdev)
+ return -ENOMEM;
+
+ /* Install the device ops before anything can fail, so that every
+ * ib_dealloc_device() below runs the dealloc_driver hook and the
+ * resources allocated so far are released.
+ */
+ ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
+
+ zdev->zxdh_adev = zxdh_adev;
+ zdev->netdev = netdev;
+
+ zdev->rf = kzalloc_obj(*zdev->rf);
+ if (!zdev->rf) {
+ ib_dealloc_device(&zdev->ibdev);
+ return -ENOMEM;
+ }
+
+ zxdh_fill_device_info(zdev, zxdh_adev->zxdh_info);
+
+ hdl = kzalloc_obj(*hdl);
+ if (!hdl) {
+ ib_dealloc_device(&zdev->ibdev);
+ return -ENOMEM;
+ }
+
+ hdl->zdev = zdev;
+ zdev->hdl = hdl;
+
+ rf = zdev->rf;
+ err = zxdh_ctrl_init_hw(rf);
+ if (err)
+ goto err_dealloc;
+
+ err = zxdh_ib_register_device(zdev);
+ if (err)
+ goto err_dealloc;
+
+ /* Publish the handler only after the device is registered, so a
+ * failed probe cannot leave a freed handler on the global list.
+ */
+ zxdh_add_handler(hdl);
+
+ dev_set_drvdata(&aux_dev->dev, zdev);
+
return 0;
+
+err_dealloc:
+ ib_dealloc_device(&zdev->ibdev);
+
+ return err;
}
static void zxdh_remove(struct auxiliary_device *aux_dev)
{
- dev_info(&aux_dev->dev, "ZTE DingHai RDMA device removed (stub)\n");
+ struct zxdh_device *zdev = dev_get_drvdata(&aux_dev->dev);
+ struct zxdh_handler *hdl;
+
+ if (!zdev) {
+ dev_err(&aux_dev->dev, "%s: zdev is NULL\n", __func__);
+ return;
+ }
+
+ /* Detach the handler before ib_unregister_device() so it is not
+ * visible to new callers during unregister.
+ */
+ hdl = zdev->hdl;
+ zdev->hdl = NULL;
+ zxdh_del_handler(hdl);
+ kfree(hdl);
+
+ /* No 'get' on the ib_device, so the _and_put variant would
+ * underflow ib_device.refcount; see cover letter.
+ */
+ ib_unregister_device(&zdev->ibdev);
}
+static const struct auxiliary_device_id zxdh_auxiliary_id_table[] = {
+ {
+ .name = ZXDH_PF_NAME "." ZXDH_RDMA_DEV_NAME,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(auxiliary, zxdh_auxiliary_id_table);
+
static struct auxiliary_driver zxdh_auxiliary_drv = {
.name = ZXDH_RDMA_DEV_NAME,
.id_table = zxdh_auxiliary_id_table,
@@ -45,12 +271,34 @@ static struct auxiliary_driver zxdh_auxiliary_drv = {
static int __init zrdma_module_init(void)
{
- return auxiliary_driver_register(&zxdh_auxiliary_drv);
+ int ret;
+
+ INIT_LIST_HEAD(&zxdh_rdma_list);
+ mutex_init(&rdma_name_lock);
+
+ ret = auxiliary_driver_register(&zxdh_auxiliary_drv);
+ if (ret) {
+ pr_err("zrdma: failed to register auxiliary driver\n");
+ return ret;
+ }
+
+ return 0;
}
static void __exit zrdma_module_exit(void)
{
+ struct zxdh_rdma_node *pos, *tmp;
+
auxiliary_driver_unregister(&zxdh_auxiliary_drv);
+
+ mutex_lock(&rdma_name_lock);
+ list_for_each_entry_safe(pos, tmp, &zxdh_rdma_list, list) {
+ list_del(&pos->list);
+ kfree(pos);
+ }
+ mutex_unlock(&rdma_name_lock);
+
+ mutex_destroy(&rdma_name_lock);
}
module_init(zrdma_module_init);
diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
index 90ff9a826491..d47dfafa717a 100644
--- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
@@ -12,8 +12,37 @@ const struct ib_device_ops zxdh_dev_ops = {
.owner = THIS_MODULE,
.driver_id = RDMA_DRIVER_ZRDMA,
.uverbs_abi_ver = ZXDH_ABI_VER,
+ .dealloc_driver = zxdh_ib_dealloc_device,
};
+/* Release everything the probe path may have allocated. The hook is
+ * called from ib_dealloc_device(), so it must tolerate a partially
+ * initialised device.
+ */
+void zxdh_ib_dealloc_device(struct ib_device *ibdev)
+{
+ struct zxdh_device *zdev = to_zdev(ibdev);
+
+ if (!zdev)
+ return;
+
+ if (zdev->rf) {
+ kvfree(zdev->rf->qp_cnt_8k_idxs);
+ kvfree(zdev->rf->mem_rsrc);
+ kfree(zdev->rf);
+ zdev->rf = NULL;
+ }
+
+ /* ah_list_lock is only initialised by zxdh_fill_device_info(),
+ * which is skipped when the probe fails earlier.
+ */
+ if (zdev->init_state != INVALID_STATE)
+ mutex_destroy(&zdev->ah_list_lock);
+
+ kfree(zdev->hdl);
+ zdev->hdl = NULL;
+}
+
static int zxdh_init_rdma_device(struct zxdh_device *zdev)
{
zdev->ibdev.phys_port_cnt = 1;
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH rdma v7 6/7] RDMA/zrdma: Implement context, PD, and mmap operations
2026-10-27 2:11 [PATCH rdma v7 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
` (4 preceding siblings ...)
2026-10-27 2:11 ` [PATCH rdma v7 5/7] RDMA/zrdma: Add device probe and remove logic Yanze Zhang
@ 2026-10-27 2:11 ` Yanze Zhang
2026-10-27 2:39 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 7/7] RDMA/zrdma: Implement device and port query operations Yanze Zhang
6 siblings, 1 reply; 16+ messages in thread
From: Yanze Zhang @ 2026-10-27 2:11 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu
Cc: Markus.Elfring, lkp, linux-kernel, linux-rdma, wei.quan,
han.junyang, ran.ming, han.chengfei, zhang.yanze
Add implementation for allocation/deallocation of Protection Domains (PD),
User Contexts, and memory mapping (mmap) for doorbells. This patch also
includes the basic device initialization logic required for registration.
The SRQ doorbell area is not page aligned on 16K and 64K page systems, so
the mapping length is extended to the page boundary and the size
reported to userspace is the very same length. Otherwise the tail of the
doorbell area would fall outside of the mapping and the mmap would be
rejected by rdma_user_mmap_entry_get().
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/zrdma_verbs.c | 355 +++++++++++++++++++++-
1 file changed, 347 insertions(+), 8 deletions(-)
diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
index d47dfafa717a..abac97e69413 100644
--- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
@@ -7,13 +7,10 @@
#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,
- .dealloc_driver = zxdh_ib_dealloc_device,
-};
+#include <rdma/ib_mad.h>
+#include <rdma/ib_cache.h>
+#include <rdma/ib_user_verbs.h>
+#include <linux/etherdevice.h>
/* Release everything the probe path may have allocated. The hook is
* called from ib_dealloc_device(), so it must tolerate a partially
@@ -43,11 +40,337 @@ void zxdh_ib_dealloc_device(struct ib_device *ibdev)
zdev->hdl = NULL;
}
+static void zxdh_sc_pd_init(struct zxdh_sc_dev *dev, struct zxdh_sc_pd *pd,
+ u32 pd_id, int abi_ver)
+{
+ pd->pd_id = pd_id;
+ pd->abi_ver = abi_ver;
+ pd->dev = dev;
+}
+
+static int zxdh_alloc_pd(struct ib_pd *pd, struct ib_udata *udata)
+{
+ struct zxdh_device *zdev = to_zdev(pd->device);
+ struct zxdh_sc_dev *dev = &zdev->rf->sc_dev;
+ struct zxdh_alloc_pd_resp uresp = {};
+ struct zxdh_pd *zpd = to_zpd(pd);
+ struct zxdh_pci_f *rf = zdev->rf;
+ struct zxdh_sc_pd *sc_pd;
+ u32 pd_id;
+ int err;
+
+ err = zxdh_alloc_rsrc(rf, rf->allocated_pds, rf->max_pd, &pd_id,
+ &rf->next_pd, "PD");
+ if (err) {
+ pr_warn_ratelimited("zrdma: PD allocation failed err=%d\n",
+ err);
+ return err;
+ }
+
+ sc_pd = &zpd->sc_pd;
+ if (udata) {
+ struct zxdh_ucontext *ucontext;
+
+ ucontext = rdma_udata_to_drv_context(udata,
+ struct zxdh_ucontext,
+ ibucontext);
+
+ zxdh_sc_pd_init(dev, sc_pd, pd_id, ucontext->abi_ver);
+ uresp.pd_id = pd_id;
+ if (ib_copy_to_udata(udata, &uresp,
+ min(sizeof(uresp), udata->outlen))) {
+ err = -EFAULT;
+ goto error;
+ }
+ } else {
+ zxdh_sc_pd_init(dev, sc_pd, pd_id, ZXDH_ABI_VER);
+ }
+
+ return 0;
+
+error:
+ zxdh_free_rsrc(rf, rf->allocated_pds, pd_id);
+
+ return err;
+}
+
+static struct rdma_user_mmap_entry *
+zxdh_user_mmap_entry_insert(struct zxdh_ucontext *ucontext, u64 bar_offset,
+ enum zxdh_mmap_flag mmap_flag, u64 *mmap_offset)
+{
+ struct zxdh_user_mmap_entry *entry =
+ kzalloc(sizeof(*entry), GFP_KERNEL);
+ int ret;
+
+ if (!entry)
+ return NULL;
+
+ entry->bar_offset = bar_offset;
+ entry->mmap_flag = mmap_flag;
+
+ ret = rdma_user_mmap_entry_insert(&ucontext->ibucontext,
+ &entry->rdma_entry, PAGE_SIZE);
+ if (ret) {
+ kfree(entry);
+ return NULL;
+ }
+ *mmap_offset = rdma_user_mmap_get_offset(&entry->rdma_entry);
+
+ return &entry->rdma_entry;
+}
+
+static struct rdma_user_mmap_entry *
+zxdh_mp_mmap_entry_insert(struct zxdh_ucontext *ucontext, u64 phy_addr,
+ size_t length, enum zxdh_mmap_flag mmap_flag,
+ u64 *mmap_offset)
+{
+ struct zxdh_user_mmap_entry *entry =
+ kzalloc(sizeof(*entry), GFP_KERNEL);
+ int ret;
+
+ if (!entry)
+ return NULL;
+
+ entry->bar_offset = phy_addr;
+ entry->mmap_flag = mmap_flag;
+
+ ret = rdma_user_mmap_entry_insert(&ucontext->ibucontext,
+ &entry->rdma_entry, length);
+ if (ret) {
+ kfree(entry);
+ return NULL;
+ }
+ *mmap_offset = rdma_user_mmap_get_offset(&entry->rdma_entry);
+
+ return &entry->rdma_entry;
+}
+
+/* The SRQ doorbell area starts at SRQ_DB_BAR_OFF, which is not page
+ * aligned once the page size is 16K or 64K. The mapping therefore has to
+ * start at the page holding the doorbell and has to be large enough to
+ * cover the whole doorbell area.
+ */
+static u64 zxdh_get_srq_db_mmap_size(void)
+{
+ return round_up((SRQ_DB_BAR_OFF & ZXDH_PAGE_OFFSET_NUM) +
+ SRQ_DB_MMAP_SIZE, PAGE_SIZE);
+}
+
+static int zxdh_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
+{
+ struct zxdh_ucontext *ucontext = to_ucontext(uctx);
+ struct zxdh_alloc_ucontext_resp uresp = {};
+ struct ib_device *ibdev = uctx->device;
+ struct zxdh_device *zdev = to_zdev(ibdev);
+ struct zxdh_alloc_ucontext_req req = {};
+ u64 srq_db_mmap_size;
+
+ if (ib_copy_from_udata(&req, udata, min(sizeof(req), udata->inlen)))
+ return -EINVAL;
+
+ if (req.userspace_ver != ZXDH_CONTEXT_VER_V1 &&
+ req.userspace_ver != ZXDH_CONTEXT_VER_V2 &&
+ req.userspace_ver != ZXDH_CONTEXT_VER_V3) {
+ pr_err("zrdma: Invalid userspace_ver%d\n", req.userspace_ver);
+ return -EINVAL;
+ }
+ ucontext->zdev = zdev;
+ ucontext->abi_ver = req.userspace_ver;
+
+ uresp.srq_db_bar_off = SRQ_DB_BAR_OFF & ZXDH_PAGE_OFFSET_NUM;
+
+ ucontext->sq_db_mmap_entry =
+ zxdh_user_mmap_entry_insert(ucontext, SQ_DB_BAR_OFF,
+ ZXDH_MMAP_IO_NC,
+ &uresp.sq_db_mmap_key);
+ if (!ucontext->sq_db_mmap_entry)
+ return -ENOMEM;
+
+ ucontext->cq_db_mmap_entry =
+ zxdh_user_mmap_entry_insert(ucontext, CQ_DB_BAR_OFF,
+ ZXDH_MMAP_IO_NC,
+ &uresp.cq_db_mmap_key);
+ if (!ucontext->cq_db_mmap_entry) {
+ rdma_user_mmap_entry_remove(ucontext->sq_db_mmap_entry);
+ return -ENOMEM;
+ }
+
+ /* The mapping length and the size reported to userspace have to
+ * match, otherwise rdma_user_mmap_entry_get() rejects the mmap.
+ */
+ if (ucontext->abi_ver == ZXDH_CONTEXT_VER_V1 ||
+ ucontext->abi_ver == ZXDH_CONTEXT_VER_V2)
+ srq_db_mmap_size = PAGE_SIZE;
+ else
+ srq_db_mmap_size = zxdh_get_srq_db_mmap_size();
+
+ ucontext->srq_db_mmap_entry =
+ zxdh_mp_mmap_entry_insert(ucontext, SRQ_DB_BAR_OFF,
+ srq_db_mmap_size,
+ ZXDH_MMAP_IO_NC_BY_SIZE,
+ &uresp.srq_db_mmap_key);
+ if (!ucontext->srq_db_mmap_entry) {
+ rdma_user_mmap_entry_remove(ucontext->sq_db_mmap_entry);
+ rdma_user_mmap_entry_remove(ucontext->cq_db_mmap_entry);
+ pr_err("zrdma: srq_db_mmap_entry is NULL!\n");
+ return -ENOMEM;
+ }
+
+ uresp.srq_db_mmap_size = srq_db_mmap_size;
+ uresp.kernel_ver = ZXDH_CONTEXT_VER_V3;
+ uresp.hw_rev = ZXDH_GEN_2;
+ uresp.chip_rev = CHIP_VERSION;
+ uresp.rdma_tool_flags =
+ ZXDH_QP_EXTEND_OP | ZXDH_CAPTURE | ZXDH_GET_HW_DATA |
+ ZXDH_GET_HW_OBJECT_DATA | ZXDH_CHECK_HW_HEALTH |
+ ZXDH_RDMA_TOOL_CFG_DEV_PARAM | ZXDH_RDMA_TOOL_READ_RAM |
+ ZXDH_RDMA_TOOL_DEVX_MODIFY_CQ | ZXDH_RDMA_SET_CREDIT_CAP |
+ ZXDH_RDMA_SWITCH | ZXDH_RDMA_TOOL_DEVX_EXT_MEM |
+ ZXDH_RDMA_TOOL_PRIV_EXT |
+ ZXDH_RDMA_TOOL_IOVA_CAP;
+
+ uresp.feature_flags = ZXDH_FEATURE_RTS_AE | ZXDH_FEATURE_CQ_RESIZE |
+ ZXDH_FEATURE_64_BYTE_CQE;
+ uresp.max_hw_wq_frags = MAX_HW_WQ_FRAGS;
+ uresp.max_hw_read_sges = MAX_HW_READ_SGES;
+ uresp.max_hw_inline = MAX_HW_INLINE;
+ uresp.max_hw_srq_wr = MAX_HW_SRQ_WR;
+ uresp.max_hw_rq_quanta = MAX_HW_RQ_QUANTA;
+ uresp.max_hw_srq_quanta = MAX_HW_SRQ_QUANTA;
+ uresp.max_hw_wq_quanta = MAX_HW_WQ_QUANTA;
+ uresp.max_hw_sq_chunk = MAX_HW_SQ_CHUNK;
+ uresp.max_hw_cq_size = MAX_HW_CQ_SIZE;
+ uresp.min_hw_cq_size = MIN_HW_CQ_SIZE;
+ uresp.db_addr_type = ZXDH_DB_ADDR_BAR;
+ uresp.sq_db_bar_off = SQ_DB_BAR_OFF & ZXDH_PAGE_OFFSET_NUM;
+ uresp.cq_db_bar_off = CQ_DB_BAR_OFF & ZXDH_PAGE_OFFSET_NUM;
+
+ if (ib_copy_to_udata(udata, &uresp,
+ min(sizeof(uresp), udata->outlen))) {
+ rdma_user_mmap_entry_remove(ucontext->sq_db_mmap_entry);
+ rdma_user_mmap_entry_remove(ucontext->cq_db_mmap_entry);
+ rdma_user_mmap_entry_remove(ucontext->srq_db_mmap_entry);
+ return -EFAULT;
+ }
+
+ atomic_set(&ucontext->tx_port_affinity,
+ atomic_add_return(1, &zdev->tx_port_affinity));
+
+ INIT_LIST_HEAD(&ucontext->cq_reg_mem_list);
+ spin_lock_init(&ucontext->cq_reg_mem_list_lock);
+ INIT_LIST_HEAD(&ucontext->qp_reg_mem_list);
+ spin_lock_init(&ucontext->qp_reg_mem_list_lock);
+ INIT_LIST_HEAD(&ucontext->srq_reg_mem_list);
+ spin_lock_init(&ucontext->srq_reg_mem_list_lock);
+
+ return 0;
+}
+
+static int zxdh_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
+{
+ struct zxdh_pd *zpd = to_zpd(ibpd);
+ struct zxdh_device *zdev = to_zdev(ibpd->device);
+
+ zxdh_free_rsrc(zdev->rf, zdev->rf->allocated_pds, zpd->sc_pd.pd_id);
+ return 0;
+}
+
+static void zxdh_dealloc_ucontext(struct ib_ucontext *context)
+{
+ struct zxdh_ucontext *ucontext = to_ucontext(context);
+
+ if (!ucontext)
+ return;
+
+ if (ucontext->sq_db_mmap_entry)
+ rdma_user_mmap_entry_remove(ucontext->sq_db_mmap_entry);
+ if (ucontext->cq_db_mmap_entry)
+ rdma_user_mmap_entry_remove(ucontext->cq_db_mmap_entry);
+ if (ucontext->srq_db_mmap_entry)
+ rdma_user_mmap_entry_remove(ucontext->srq_db_mmap_entry);
+}
+
+static void zxdh_mmap_free(struct rdma_user_mmap_entry *entry)
+{
+ struct zxdh_user_mmap_entry *zentry = to_zxdh_mmap_entry(entry);
+
+ kfree(zentry);
+}
+
+static int zxdh_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ struct rdma_user_mmap_entry *rdma_entry;
+ struct zxdh_user_mmap_entry *entry;
+ struct zxdh_ucontext *ucontext;
+ u64 pfn;
+ int ret;
+
+ ucontext = to_ucontext(context);
+
+ rdma_entry = rdma_user_mmap_entry_get(&ucontext->ibucontext, vma);
+ if (!rdma_entry) {
+ pr_err("zrdma: pgoff[0x%lx] does not have valid entry\n",
+ vma->vm_pgoff);
+ return -EINVAL;
+ }
+
+ entry = to_zxdh_mmap_entry(rdma_entry);
+
+ pfn = (entry->bar_offset +
+ pci_resource_start(ucontext->zdev->rf->pcidev, 0)) >>
+ PAGE_SHIFT;
+
+ switch (entry->mmap_flag) {
+ case ZXDH_MMAP_IO_NC:
+ ret = rdma_user_mmap_io(context, vma, pfn, PAGE_SIZE,
+ pgprot_noncached(vma->vm_page_prot),
+ rdma_entry);
+ break;
+ case ZXDH_MMAP_IO_NC_BY_SIZE:
+ ret = rdma_user_mmap_io(context, vma, pfn,
+ vma->vm_end - vma->vm_start,
+ pgprot_noncached(vma->vm_page_prot),
+ rdma_entry);
+ break;
+ case ZXDH_MMAP_IO_WC:
+ ret = rdma_user_mmap_io(context, vma, pfn, PAGE_SIZE,
+ pgprot_writecombine(vma->vm_page_prot),
+ rdma_entry);
+ break;
+ default:
+ pr_err("[zxdh_rdma] VERBS: unsupported mmap_flag[%d]\n",
+ entry->mmap_flag);
+ ret = -EINVAL;
+ }
+
+ if (ret)
+ pr_err("[zxdh_rdma] VERBS: bar_offset [0x%llx] mmap_flag[%d] err[%d]\n",
+ entry->bar_offset, entry->mmap_flag, ret);
+
+ rdma_user_mmap_entry_put(rdma_entry);
+
+ return ret;
+}
+
+static void zxdh_init_roce_device(struct zxdh_device *zdev)
+{
+ zdev->ibdev.node_type = RDMA_NODE_IB_CA;
+ addrconf_addr_eui48((u8 *)&zdev->ibdev.node_guid,
+ zdev->netdev->dev_addr);
+}
+
static int zxdh_init_rdma_device(struct zxdh_device *zdev)
{
+ struct pci_dev *pcidev = zdev->rf->pcidev;
+
+ if (zdev->roce_mode)
+ zxdh_init_roce_device(zdev);
+ else
+ return -EPFNOSUPPORT;
+
zdev->ibdev.phys_port_cnt = 1;
zdev->ibdev.num_comp_vectors = zdev->rf->ceqs_count;
- zdev->ibdev.dev.parent = &zdev->rf->pcidev->dev;
+ zdev->ibdev.dev.parent = &pcidev->dev;
return 0;
}
@@ -66,3 +389,19 @@ int zxdh_ib_register_device(struct zxdh_device *zdev)
return ret;
}
+
+const struct ib_device_ops zxdh_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_ZRDMA,
+ .uverbs_abi_ver = ZXDH_ABI_VER,
+ .dealloc_driver = zxdh_ib_dealloc_device,
+ .alloc_pd = zxdh_alloc_pd,
+ .alloc_ucontext = zxdh_alloc_ucontext,
+ .dealloc_pd = zxdh_dealloc_pd,
+ .dealloc_ucontext = zxdh_dealloc_ucontext,
+ .mmap = zxdh_mmap,
+ .mmap_free = zxdh_mmap_free,
+
+ INIT_RDMA_OBJ_SIZE(ib_pd, zxdh_pd, ibpd),
+ INIT_RDMA_OBJ_SIZE(ib_ucontext, zxdh_ucontext, ibucontext),
+};
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH rdma v7 7/7] RDMA/zrdma: Implement device and port query operations
2026-10-27 2:11 [PATCH rdma v7 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
` (5 preceding siblings ...)
2026-10-27 2:11 ` [PATCH rdma v7 6/7] RDMA/zrdma: Implement context, PD, and mmap operations Yanze Zhang
@ 2026-10-27 2:11 ` Yanze Zhang
2026-10-27 2:33 ` sashiko-bot
6 siblings, 1 reply; 16+ messages in thread
From: Yanze Zhang @ 2026-10-27 2:11 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu
Cc: Markus.Elfring, lkp, linux-kernel, linux-rdma, wei.quan,
han.junyang, ran.ming, han.chengfei, zhang.yanze
Add implementation for querying device attributes, port attributes,
PKey, and link layer information. Also include firmware version string
retrieval.
- query_device() accepts a NULL udata, which is how the core calls it
while the device is being registered, and it reports the number of
send and receive SGEs the hardware supports.
- The firmware version is parsed as unsigned values and masked to 16
bits, and the version string keeps its "N/A" placeholder when no
version can be extracted from the driver info. A model prefix is
skipped whether or not the network driver appends the vendor in
parentheses, so that a firmware string carrying both a model prefix
and a vendor suffix still yields a non-zero fw_ver.
- The driver info is read with rtnl held, taking the lock only when
the caller does not hold it already, so a bond never falls back to
the bond device itself. The driver info is only read from process
context, through query_device() and get_dev_fw_str(), so taking the
rtnl lock there cannot sleep in atomic context.
- The port speed is taken from ib_get_eth_speed(), which reads the
current link settings instead of caching a stale value.
- The immutable port information is filled in directly rather than
taken from the port query, so that it does not depend on the port
query being run while the device is still being registered.
- The port number is passed to rdma_protocol_roce() instead of being
hard coded, so that the query stays correct if more ports are added.
- The RoCE GID cache is owned by the core, so the driver does not
provide a query_gid callback.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/zrdma_verbs.c | 294 +++++++++++++++++++++-
1 file changed, 292 insertions(+), 2 deletions(-)
diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
index abac97e69413..ceaad155fc5a 100644
--- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
@@ -10,7 +10,9 @@
#include <rdma/ib_mad.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_user_verbs.h>
+#include <linux/ctype.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
/* Release everything the probe path may have allocated. The hook is
* called from ib_dealloc_device(), so it must tolerate a partially
@@ -352,6 +354,252 @@ static int zxdh_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
return ret;
}
+/* Fetch the driver info for @zdev->netdev, or for its first lower device
+ * when it is a bond. The lower device list is protected by rtnl_lock, and
+ * the core may call this from a netdev notifier that already holds the
+ * lock, so it is only taken when it is not held already.
+ */
+static bool zxdh_get_drvinfo(struct zxdh_device *zdev,
+ struct ethtool_drvinfo *info)
+{
+ struct net_device *slave = NULL, *dev;
+ struct list_head *iter;
+ bool locked;
+ bool ret = true;
+
+ memset(info, 0, sizeof(*info));
+
+ locked = !rtnl_is_locked();
+ if (locked)
+ rtnl_lock();
+
+ if (zdev->netdev->priv_flags & IFF_BONDING)
+ netdev_for_each_lower_dev(zdev->netdev, slave, iter)
+ break;
+
+ dev = slave ? slave : zdev->netdev;
+ if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo)
+ dev->ethtool_ops->get_drvinfo(dev, info);
+ else
+ ret = false;
+
+ if (locked)
+ rtnl_unlock();
+
+ return ret;
+}
+
+static void extract_version(const char *input, char *output)
+{
+ const char *v_start, *p;
+ int dots = 0;
+
+ if (!output)
+ return;
+
+ *output = '\0';
+
+ if (!input)
+ return;
+
+ /* The version is preceded by the model, e.g. "E310-V25.30.103.01".
+ * Skip the model, so that only the version itself is reported.
+ */
+ v_start = input;
+ for (p = input; *p; p++) {
+ if (p[0] == '-' && p[1] == 'V' && isdigit((unsigned char)p[2])) {
+ v_start = p + 2;
+ break;
+ }
+ }
+
+ /* Cut the vendor suffix, if any, and keep at most four dot
+ * separated fields, which is what the fw_ver layout can hold.
+ */
+ for (p = v_start; *p && *p != ' '; p++) {
+ if (*p == '.' && ++dots == 4)
+ break;
+ *output++ = *p;
+ }
+
+ *output = '\0';
+}
+
+static int zxdh_query_device(struct ib_device *ibdev,
+ struct ib_device_attr *props,
+ struct ib_udata *udata)
+{
+ struct zxdh_device *zdev = to_zdev(ibdev);
+ struct pci_dev *pcidev = zdev->rf->pcidev;
+ unsigned int major, sub_major, minor, sub_minor;
+ struct ethtool_drvinfo info;
+ char extracted_version[32] = {};
+
+ /* The core calls this without udata while the device is being
+ * registered, so udata is only inspected when it is there.
+ */
+ if (udata && (udata->inlen || udata->outlen))
+ return -EINVAL;
+
+ memset(props, 0, sizeof(*props));
+
+ if (zxdh_get_drvinfo(zdev, &info)) {
+ extract_version(info.fw_version, extracted_version);
+ if (sscanf(extracted_version, "%u.%u.%u.%u", &major,
+ &sub_major, &minor, &sub_minor) != 4) {
+ major = 0;
+ sub_major = 0;
+ minor = 0;
+ sub_minor = 0;
+ }
+ } else {
+ major = 0;
+ sub_major = 0;
+ minor = 0;
+ sub_minor = 0;
+ }
+
+ addrconf_addr_eui48((u8 *)&props->sys_image_guid,
+ zdev->netdev->dev_addr);
+ props->fw_ver = ((u64)(major & 0xffff) << 48 |
+ (u64)(sub_major & 0xffff) << 32 |
+ (u64)(minor & 0xffff) << 16 |
+ (sub_minor & 0xffff));
+ props->device_cap_flags =
+ IB_DEVICE_MEM_WINDOW | IB_DEVICE_MEM_MGT_EXTENSIONS |
+ IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SYS_IMAGE_GUID |
+ IB_DEVICE_RC_RNR_NAK_GEN | IB_DEVICE_N_NOTIFY_CQ;
+ props->vendor_id = pcidev->vendor;
+ props->vendor_part_id = pcidev->device;
+ props->hw_ver = pcidev->revision;
+ props->page_size_cap = SZ_4K | SZ_2M | SZ_1G;
+ props->max_mr_size = MAX_MR_SIZE;
+ props->max_qp = MAX_QP;
+ props->max_qp_wr = MAX_QP_WR;
+ props->max_cq = MAX_CQ;
+ props->max_cqe = MAX_CQE;
+ props->max_mr = MAX_MR;
+ props->max_mw = MAX_MW;
+ props->max_pd = MAX_PD;
+ props->max_send_sge = MAX_SEND_SGE;
+ props->max_recv_sge = MAX_RECV_SGE;
+ props->max_sge_rd = MAX_SGE_RD;
+ props->max_qp_rd_atom = MAX_QP_RD_ATOM;
+ props->max_res_rd_atom = MAX_RES_RD_ATOM;
+ props->max_qp_init_rd_atom = MAX_QP_INIT_RD_ATOM;
+ props->max_srq = MAX_SRQ;
+ props->max_srq_wr = MAX_SRQ_WR;
+ props->max_srq_sge = MAX_SRQ_SGE;
+ props->local_ca_ack_delay = LOCAL_CA_ACK_DELAY;
+ props->hca_core_clock = HCA_CORE_CLOCK;
+ props->max_wq_type_rq = MAX_WQ_TYPE_RQ;
+ if (rdma_protocol_roce(ibdev, rdma_start_port(ibdev))) {
+ props->max_pkeys = ZXDH_PKEY_TBL_SZ;
+ props->max_ah = MAX_AH;
+ props->max_mcast_grp = 0;
+ props->max_mcast_qp_attach = 0;
+ props->max_total_mcast_qp_attach = 0;
+ }
+ props->max_fast_reg_page_list_len = MAX_FAST_REG_PAGE_LIST_LEN;
+ props->cq_caps.max_cq_moderation_count = MAX_CQ_MODERATION_COUNT;
+ props->cq_caps.max_cq_moderation_period = MAX_CQ_MODERATION_PERIOD;
+ props->timestamp_mask = TIMESTAMP_MASK;
+
+ return 0;
+}
+
+static int zxdh_query_port(struct ib_device *ibdev, u32 port,
+ struct ib_port_attr *props)
+{
+ struct zxdh_device *zdev = to_zdev(ibdev);
+ struct net_device *netdev = zdev->netdev;
+
+ props->max_mtu = IB_MTU_4096;
+ props->active_mtu = zxdh_mtu_int_to_enum(netdev->mtu);
+ props->lid = 0;
+ props->lmc = 0;
+ props->sm_lid = 0;
+ props->sm_sl = 0;
+ if (netif_carrier_ok(netdev) && netif_running(netdev)) {
+ props->state = IB_PORT_ACTIVE;
+ props->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
+ } else {
+ props->state = IB_PORT_DOWN;
+ props->phys_state = IB_PORT_PHYS_STATE_DISABLED;
+ }
+
+ /* The link speed is read from the netdev on every query, so a
+ * link change is never reported with a stale value.
+ */
+ if (ib_get_eth_speed(ibdev, port, &props->active_speed,
+ &props->active_width))
+ pr_warn_ratelimited("zrdma: failed to get the port speed\n");
+
+ if (rdma_protocol_roce(ibdev, port)) {
+ props->gid_tbl_len = ZXDH_GID_TBL_LEN;
+ props->ip_gids = true;
+ props->pkey_tbl_len = ZXDH_PKEY_TBL_SZ;
+ } else {
+ props->gid_tbl_len = 1;
+ }
+ props->port_cap_flags |= IB_PORT_CM_SUP;
+ props->max_msg_sz = MAX_MSG_SZ;
+ props->qkey_viol_cntr = 0;
+
+ return 0;
+}
+
+static enum rdma_link_layer zxdh_get_link_layer(struct ib_device *ibdev,
+ u32 port_num)
+{
+ return IB_LINK_LAYER_ETHERNET;
+}
+
+static int zxdh_query_pkey(struct ib_device *ibdev, u32 port, u16 index,
+ u16 *pkey)
+{
+ if (index >= ZXDH_PKEY_TBL_SZ)
+ return -EINVAL;
+
+ *pkey = ZXDH_DEFAULT_PKEY;
+ return 0;
+}
+
+static int zxdh_roce_port_immutable(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_immutable *immutable)
+{
+ /* The core passes a pointer to port_data[port_num].immutable, so
+ * the values are visible to rdma_protocol_roce() as soon as they
+ * are written here. They are filled in directly instead of asking
+ * zxdh_query_port(), because that helper is only meant for a
+ * device that is already registered.
+ */
+ immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP |
+ RDMA_CORE_CAP_PROT_ROCE;
+ immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+ immutable->pkey_tbl_len = ZXDH_PKEY_TBL_SZ;
+ immutable->gid_tbl_len = ZXDH_GID_TBL_LEN;
+
+ return 0;
+}
+
+static void zxdh_get_dev_fw_str(struct ib_device *dev, char *str)
+{
+ struct zxdh_device *zdev = to_zdev(dev);
+ struct ethtool_drvinfo info;
+ char extracted_version[32];
+
+ strscpy(str, "N/A", IB_FW_VERSION_NAME_MAX);
+
+ if (!zxdh_get_drvinfo(zdev, &info))
+ return;
+
+ extract_version(info.fw_version, extracted_version);
+ /* Keep the placeholder when no version could be extracted. */
+ if (extracted_version[0])
+ strscpy(str, extracted_version, IB_FW_VERSION_NAME_MAX);
+}
+
static void zxdh_init_roce_device(struct zxdh_device *zdev)
{
zdev->ibdev.node_type = RDMA_NODE_IB_CA;
@@ -375,17 +623,53 @@ static int zxdh_init_rdma_device(struct zxdh_device *zdev)
return 0;
}
+static void zxdh_port_ibevent(struct zxdh_device *zdev)
+{
+ struct ib_event event;
+
+ event.device = &zdev->ibdev;
+ event.element.port_num = 1;
+ event.event = zdev->ibdev_status ? IB_EVENT_PORT_ACTIVE :
+ IB_EVENT_PORT_ERR;
+ ib_dispatch_event(&event);
+}
+
int zxdh_ib_register_device(struct zxdh_device *zdev)
{
+ char name[IB_DEVICE_NAME_MAX] = {};
int ret;
ret = zxdh_init_rdma_device(zdev);
if (ret)
return ret;
- ret = ib_register_device(&zdev->ibdev, "zrdma%d", zdev->rf->hw.device);
+ ret = zxdh_get_del_rdma_name(pci_name(zdev->rf->pcidev), name,
+ IB_DEVICE_NAME_MAX);
if (ret)
- pr_err("zrdma: Register RDMA device fail\n");
+ snprintf(name, IB_DEVICE_NAME_MAX, "%s", "zrdma%d");
+
+ ret = ib_device_set_netdev(&zdev->ibdev, zdev->netdev, 1);
+ if (ret)
+ goto error;
+
+ zdev->rf->hw.device = &zdev->rf->pcidev->dev;
+ dma_set_max_seg_size(zdev->rf->hw.device, SZ_1G);
+
+ /* Publish the link state before the device becomes visible to
+ * userspace, so a racing ULP never observes a stale status.
+ */
+ zdev->ibdev_status = 1;
+
+ ret = ib_register_device(&zdev->ibdev, name, zdev->rf->hw.device);
+ if (ret)
+ goto error;
+
+ zxdh_port_ibevent(zdev);
+
+ return 0;
+
+error:
+ pr_err("zrdma: Register RDMA device fail, ret=%d\n", ret);
return ret;
}
@@ -399,6 +683,12 @@ const struct ib_device_ops zxdh_dev_ops = {
.alloc_ucontext = zxdh_alloc_ucontext,
.dealloc_pd = zxdh_dealloc_pd,
.dealloc_ucontext = zxdh_dealloc_ucontext,
+ .query_device = zxdh_query_device,
+ .query_port = zxdh_query_port,
+ .query_pkey = zxdh_query_pkey,
+ .get_link_layer = zxdh_get_link_layer,
+ .get_port_immutable = zxdh_roce_port_immutable,
+ .get_dev_fw_str = zxdh_get_dev_fw_str,
.mmap = zxdh_mmap,
.mmap_free = zxdh_mmap_free,
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH rdma v7 3/7] RDMA/zrdma: Add internal headers and hardware register definitions
2026-10-27 2:11 ` [PATCH rdma v7 3/7] RDMA/zrdma: Add internal headers and hardware register definitions Yanze Zhang
@ 2026-10-27 2:26 ` sashiko-bot
2026-10-27 7:10 ` Markus Elfring
1 sibling, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-10-27 2:26 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
> Add internal header files for main driver logic and hardware registers.
> These headers define the structures and constants used by the subsequent
> implementation patches.
>
> zxdh_free_rsrc() uses guard(spinlock_irqsave), so the lock is released on
> every exit path. zxdh_alloc_rsrc() keeps the explicit locking, as it has
> several early return paths, and takes a pool name so that the exhaustion
> log identifies the affected pool.
>
> Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261027021119.2325798-1-zhang.yanze@zte.com.cn?part=3
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH rdma v7 2/7] RDMA/zrdma: Add core data structures and ABI definitions
2026-10-27 2:11 ` [PATCH rdma v7 2/7] RDMA/zrdma: Add core data structures and ABI definitions Yanze Zhang
@ 2026-10-27 2:28 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-10-27 2:28 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
> Add fundamental data structures, hardware control structures, and
> user-space ABI definitions required by the driver. These headers
> provide the type definitions for the subsequent implementation patches.
>
> The UAPI header is installed to userspace, so it carries the
> Linux-syscall-note SPDX tag that headers_install requires for a
> GPL-licensed UAPI header.
>
> Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261027021119.2325798-1-zhang.yanze@zte.com.cn?part=2
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH rdma v7 1/7] RDMA/zrdma: Add build infrastructure and module skeleton
2026-10-27 2:11 ` [PATCH rdma v7 1/7] RDMA/zrdma: Add build infrastructure and module skeleton Yanze Zhang
@ 2026-10-27 2:30 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-10-27 2:30 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
> Add MAINTAINERS entry, Kconfig, and Makefile entries for the ZTE DingHai
> RDMA driver. Include a minimal module skeleton with auxiliary driver
> registration structure to ensure the build system works and the module
> can be loaded.
>
> The driver depends on DINGHAI because it binds to the auxiliary device
> that the DingHai PF driver will create. The DINGHAI symbol itself is
> already present in the rdma/for-next baseline this series is based on,
> so the dependency resolves.
>
> Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261027021119.2325798-1-zhang.yanze@zte.com.cn?part=1
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH rdma v7 7/7] RDMA/zrdma: Implement device and port query operations
2026-10-27 2:11 ` [PATCH rdma v7 7/7] RDMA/zrdma: Implement device and port query operations Yanze Zhang
@ 2026-10-27 2:33 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-10-27 2:33 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] RDMA/zrdma: broken conditional RTNL locking in zxdh_get_drvinfo()
--
commit f5a32e13f5abe916870114665b95d03769a17e3b
Author: Yanze Zhang <zhang.yanze@zte.com.cn>
RDMA/zrdma: Implement device and port query operations
This commit implements RDMA device and port query callbacks, including device
attributes, port attributes, PKey, link layer, port immutable data, and
firmware version string extraction for the zrdma driver.
> diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> index abac97e694138..ceaad155fc5ae 100644
> --- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> +++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
[ ... ]
> @@ -352,6 +354,252 @@ static int zxdh_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
> return ret;
> }
>
> +/* Fetch the driver info for @zdev->netdev, or for its first lower device
> + * when it is a bond. The lower device list is protected by rtnl_lock, and
> + * the core may call this from a netdev notifier that already holds the
> + * lock, so it is only taken when it is not held already.
> + */
> +static bool zxdh_get_drvinfo(struct zxdh_device *zdev,
> + struct ethtool_drvinfo *info)
> +{
> + struct net_device *slave = NULL, *dev;
> + struct list_head *iter;
> + bool locked;
> + bool ret = true;
> +
> + memset(info, 0, sizeof(*info));
> +
> + locked = !rtnl_is_locked();
> + if (locked)
> + rtnl_lock();
> +
> + if (zdev->netdev->priv_flags & IFF_BONDING)
> + netdev_for_each_lower_dev(zdev->netdev, slave, iter)
> + break;
> +
> + dev = slave ? slave : zdev->netdev;
> + if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo)
> + dev->ethtool_ops->get_drvinfo(dev, info);
> + else
> + ret = false;
> +
> + if (locked)
> + rtnl_unlock();
[Severity: High]
Can this conditional locking in zxdh_get_drvinfo() cause an unlocked
traversal of zdev->netdev->adj_list.lower and a use-after-free on slave when
another task holds rtnl_mutex?
In net/core/rtnetlink.c, rtnl_is_locked() checks whether any task on any cpu
currently holds rtnl_mutex, rather than whether current owns it:
int rtnl_is_locked(void)
{
return mutex_is_locked(&rtnl_mutex);
}
When zxdh_get_drvinfo() is called through zxdh_query_device() or
zxdh_get_dev_fw_str() while another task on another cpu holds rtnl_mutex
(for example, while unlinking a bonding lower device via
netdev_upper_dev_unlink() or unregistering a slave net_device),
rtnl_is_locked() returns true.
As a result, zxdh_get_drvinfo() skips rtnl_lock() and calls
netdev_for_each_lower_dev() -> netdev_lower_get_next() and
dev->ethtool_ops->get_drvinfo(dev, info) without holding rtnl_mutex, racing
directly with the task modifying the lower device list or tearing down the
slave device.
Since zxdh_get_drvinfo() is only called from process context through
zxdh_query_device() and zxdh_get_dev_fw_str(), neither of which holds
rtnl_mutex, should zxdh_get_drvinfo() unconditionally call rtnl_lock() and
rtnl_unlock()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261027021119.2325798-1-zhang.yanze@zte.com.cn?part=7
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH rdma v7 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton
2026-10-27 2:11 ` [PATCH rdma v7 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton Yanze Zhang
@ 2026-10-27 2:33 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-10-27 2:33 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] RDMA/zrdma: double free of rf->qp_cnt_8k_idxs in zxdh_initialize_hw_rsrc()
--
commit 3b69f0f7bdc773fc9fcdb598091be138d4e8e28a
Author: Yanze Zhang <zhang.yanze@zte.com.cn>
RDMA/zrdma: Add hardware resource initialization and verbs skeleton
This patch adds hardware resource initialization logic and a minimal verbs
layer skeleton, including device registration and initial ib_device_ops.
> diff --git a/drivers/infiniband/hw/zrdma/zrdma_hw.c b/drivers/infiniband/hw/zrdma/zrdma_hw.c
> new file mode 100644
> index 0000000000000..068d9aea7c711
> --- /dev/null
> +++ b/drivers/infiniband/hw/zrdma/zrdma_hw.c
[ ... ]
> +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);
> +
> + 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);
> +mem_8k_qp_cnt_vmalloc_fail:
> + return ret;
> +}
[Severity: High]
Can this cause a double free of rf->qp_cnt_8k_idxs if allocating
rf->mem_rsrc fails?
In zxdh_initialize_hw_rsrc(), if vzalloc() succeeds for rf->qp_cnt_8k_idxs
but fails for rf->mem_rsrc, the mem_rsrc_vmalloc_fail error path calls
vfree(rf->qp_cnt_8k_idxs) without clearing rf->qp_cnt_8k_idxs to NULL.
In the follow-up commit ("RDMA/zrdma: Add device probe and remove logic"),
zxdh_probe() calls zxdh_ctrl_init_hw() -> zxdh_initialize_hw_rsrc(). On
failure, zxdh_probe() jumps to err_dealloc and calls
ib_dealloc_device(&zdev->ibdev), which invokes the .dealloc_driver callback
zxdh_ib_dealloc_device(). Because rf->qp_cnt_8k_idxs is still non-NULL,
zxdh_ib_dealloc_device() calls kvfree(zdev->rf->qp_cnt_8k_idxs) on the
dangling pointer and frees it a second time.
Should rf->qp_cnt_8k_idxs be set to NULL after vfree(), or should freeing it
be left solely to zxdh_ib_dealloc_device()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261027021119.2325798-1-zhang.yanze@zte.com.cn?part=4
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH rdma v7 5/7] RDMA/zrdma: Add device probe and remove logic
2026-10-27 2:11 ` [PATCH rdma v7 5/7] RDMA/zrdma: Add device probe and remove logic Yanze Zhang
@ 2026-10-27 2:37 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-10-27 2:37 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] RDMA/zrdma: uninitialized ceqs_count and hw.device in zxdh_probe()
- [High] RDMA/zrdma: un-cleared pointer in zxdh_initialize_hw_rsrc() causes double free
- [Low] RDMA/zrdma: unpopulated zxdh_rdma_list and unused zxdh_handlers list
--
commit 63daa22995c515a9faef7a5a084166c75b7006ce
Author: Yanze Zhang <zhang.yanze@zte.com.cn>
RDMA/zrdma: Add device probe and remove logic
This commit implements the auxiliary bus probe and remove functions for the
zrdma driver, including device initialization, hardware resource setup,
handler list management, and IB device registration and deallocation.
> diff --git a/drivers/infiniband/hw/zrdma/zrdma_main.c b/drivers/infiniband/hw/zrdma/zrdma_main.c
> index af1d37be63362..14c36531cc453 100644
> --- a/drivers/infiniband/hw/zrdma/zrdma_main.c
> +++ b/drivers/infiniband/hw/zrdma/zrdma_main.c
[ ... ]
> +LIST_HEAD(zxdh_handlers);
> +DEFINE_SPINLOCK(zxdh_handler_lock);
>
> -MODULE_DEVICE_TABLE(auxiliary, zxdh_auxiliary_id_table);
> +static struct mutex rdma_name_lock;
> +static struct list_head zxdh_rdma_list;
> +
> +static void zxdh_add_handler(struct zxdh_handler *hdl)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&zxdh_handler_lock, flags);
> + list_add(&hdl->list, &zxdh_handlers);
> + spin_unlock_irqrestore(&zxdh_handler_lock, flags);
> +}
> +
> +void zxdh_del_handler(struct zxdh_handler *hdl)
> +{
> + unsigned long flags;
> +
> + if (!hdl)
> + return;
> +
> + spin_lock_irqsave(&zxdh_handler_lock, flags);
> + list_del(&hdl->list);
> + spin_unlock_irqrestore(&zxdh_handler_lock, flags);
> +}
> +
> +int zxdh_get_del_rdma_name(const char *sbdf, char *name, size_t name_len)
> +{
> + struct zxdh_rdma_node *pos, *tmp;
> + size_t len, sbdf_len;
> +
> + if (!sbdf || !name || !name_len)
> + return -EINVAL;
> +
> + if (name_len > IB_DEVICE_NAME_MAX) {
> + pr_err("zrdma: name buffer too large\n");
> + return -EINVAL;
> + }
> +
> + sbdf_len = strlen(sbdf);
> +
> + mutex_lock(&rdma_name_lock);
> + list_for_each_entry_safe(pos, tmp, &zxdh_rdma_list, list) {
> + len = strlen(pos->sbdf);
> + if (sbdf_len == len &&
> + strncasecmp(sbdf, pos->sbdf, len) == 0) {
> + snprintf(name, name_len, "%s", pos->name);
> + list_del(&pos->list);
> + kfree(pos);
> + mutex_unlock(&rdma_name_lock);
> + return 0;
> + }
> + }
> + mutex_unlock(&rdma_name_lock);
> + return -ENOENT;
> +}
[Severity: Low]
Are zxdh_rdma_list and zxdh_handlers used anywhere in the driver?
zxdh_rdma_list is static to zrdma_main.c and initialized in
zrdma_module_init(), but nothing in the driver or patch series ever inserts
a struct zxdh_rdma_node into it. As a result, zxdh_get_del_rdma_name() can
only return -EINVAL or -ENOENT, and the list traversal here and in
zrdma_module_exit() cannot match any entry.
In addition, zxdh_get_del_rdma_name() rejects caller buffers when
name_len > IB_DEVICE_NAME_MAX, and zrdma_module_init() initializes
rdma_name_lock dynamically without calling mutex_destroy(&rdma_name_lock) if
auxiliary_driver_register() fails.
Similarly, zxdh_probe() allocates struct zxdh_handler and adds it to
zxdh_handlers via zxdh_add_handler(), and zxdh_remove() removes and frees
it, but nothing in the series ever reads or iterates zxdh_handlers.
Could these unused lists and helpers be dropped until they have users?
[ ... ]
> +static void zxdh_fill_device_info(struct zxdh_device *zdev,
> + struct zxdh_rdma_core_dev *zdev_info)
> +{
> + struct zxdh_pci_f *rf = zdev->rf;
> +
> + rf->ftype = ZXDH_FUNC_TYPE(zdev_info->vport_id);
> + rf->pf_id = ZXDH_PF_ID(zdev_info->vport_id);
> + rf->sc_dev.ep_id = ZXDH_EP_ID(zdev_info->vport_id);
> + rf->ep_id = rf->sc_dev.ep_id;
> + rf->sc_dev.driver_load = true;
> +
> + rf->zdev_info = zdev_info;
> + rf->pcidev = zdev_info->pdev;
> +
> + rf->msix_count = zdev_info->msix_count;
> + rf->msix_entries = zdev_info->msix_entries;
> + if (rf->msix_count)
> + rf->sc_dev.max_ceqs = (rf->msix_count - 1);
> + else
> + rf->sc_dev.max_ceqs = 0;
[ ... ]
> +static int zxdh_probe(struct auxiliary_device *aux_dev,
> + const struct auxiliary_device_id *id)
> +{
[ ... ]
> + rf = zdev->rf;
> + err = zxdh_ctrl_init_hw(rf);
> + if (err)
> + goto err_dealloc;
> +
> + err = zxdh_ib_register_device(zdev);
> + if (err)
> + goto err_dealloc;
[Severity: High]
Where is zdev->rf->ceqs_count initialized before zxdh_ib_register_device() is
called?
In zxdh_probe(), zdev->rf is allocated with kzalloc_obj(*zdev->rf), and
zxdh_fill_device_info() sets rf->msix_count and rf->sc_dev.max_ceqs, but
neither zxdh_fill_device_info() nor zxdh_ctrl_init_hw() sets rf->ceqs_count.
When zxdh_probe() calls zxdh_ib_register_device(zdev),
zxdh_init_rdma_device() sets:
drivers/infiniband/hw/zrdma/zrdma_verbs.c:zxdh_init_rdma_device() {
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;
}
With zdev->rf->ceqs_count left at 0 (even at the end of the patch series),
ibdev.num_comp_vectors is registered as 0, which causes uverbs CQ creation to
reject all completion vectors with -EINVAL and causes ib_cq_pool_get() to
divide by zero (% dev->num_comp_vectors).
Additionally, at this point in the series (prior to commit "RDMA/zrdma:
Implement device and port query operations"), zdev->rf->hw.device is still
NULL and mandatory ib_device_ops callbacks (get_port_immutable and
query_device) are not yet installed when zxdh_ib_register_device() passes
zdev->rf->hw.device to ib_register_device().
> diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> index 90ff9a8264918..d47dfafa717ad 100644
> --- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> +++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> @@ -12,8 +12,37 @@ const struct ib_device_ops zxdh_dev_ops = {
> .owner = THIS_MODULE,
> .driver_id = RDMA_DRIVER_ZRDMA,
> .uverbs_abi_ver = ZXDH_ABI_VER,
> + .dealloc_driver = zxdh_ib_dealloc_device,
> };
>
> +/* Release everything the probe path may have allocated. The hook is
> + * called from ib_dealloc_device(), so it must tolerate a partially
> + * initialised device.
> + */
> +void zxdh_ib_dealloc_device(struct ib_device *ibdev)
> +{
> + struct zxdh_device *zdev = to_zdev(ibdev);
> +
> + if (!zdev)
> + return;
> +
> + if (zdev->rf) {
> + kvfree(zdev->rf->qp_cnt_8k_idxs);
> + kvfree(zdev->rf->mem_rsrc);
> + kfree(zdev->rf);
> + zdev->rf = NULL;
> + }
[Severity: High]
Can this double-free zdev->rf->qp_cnt_8k_idxs if zxdh_ctrl_init_hw() fails?
In zxdh_probe()->zxdh_ctrl_init_hw()->zxdh_initialize_hw_rsrc(), if the
first vzalloc() succeeds for rf->qp_cnt_8k_idxs and the second vzalloc()
fails for rf->mem_rsrc, zxdh_initialize_hw_rsrc() frees rf->qp_cnt_8k_idxs
without clearing the pointer:
drivers/infiniband/hw/zrdma/zrdma_hw.c:zxdh_initialize_hw_rsrc() {
...
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;
}
...
mem_rsrc_vmalloc_fail:
vfree(rf->qp_cnt_8k_idxs);
mem_8k_qp_cnt_vmalloc_fail:
return ret;
}
zxdh_probe() then jumps to err_dealloc and calls ib_dealloc_device(), which
invokes zxdh_ib_dealloc_device() and calls kvfree(zdev->rf->qp_cnt_8k_idxs) a
second time on the dangling pointer.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261027021119.2325798-1-zhang.yanze@zte.com.cn?part=5
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH rdma v7 6/7] RDMA/zrdma: Implement context, PD, and mmap operations
2026-10-27 2:11 ` [PATCH rdma v7 6/7] RDMA/zrdma: Implement context, PD, and mmap operations Yanze Zhang
@ 2026-10-27 2:39 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-10-27 2:39 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
> Add implementation for allocation/deallocation of Protection Domains (PD),
> User Contexts, and memory mapping (mmap) for doorbells. This patch also
> includes the basic device initialization logic required for registration.
>
> The SRQ doorbell area is not page aligned on 16K and 64K page systems, so
> the mapping length is extended to the page boundary and the size
> reported to userspace is the very same length. Otherwise the tail of the
> doorbell area would fall outside of the mapping and the mmap would be
> rejected by rdma_user_mmap_entry_get().
>
> Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261027021119.2325798-1-zhang.yanze@zte.com.cn?part=6
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH rdma v7 3/7] RDMA/zrdma: Add internal headers and hardware register definitions
2026-10-27 2:11 ` [PATCH rdma v7 3/7] RDMA/zrdma: Add internal headers and hardware register definitions Yanze Zhang
2026-10-27 2:26 ` sashiko-bot
@ 2026-10-27 7:10 ` Markus Elfring
1 sibling, 0 replies; 16+ messages in thread
From: Markus Elfring @ 2026-10-27 7:10 UTC (permalink / raw)
To: Yanze Zhang, linux-rdma, Jason Gunthorpe, Julian Braha,
Junxian Huang, Leon Romanovsky, Zhu Yanjun
Cc: lkp, LKML, Chengfei Han, Junyang Han, Ming Ran, Quan Wei
…
> zxdh_free_rsrc() uses guard(spinlock_irqsave), so the lock is released on
> every exit path. zxdh_alloc_rsrc() keeps the explicit locking, as it has
> several early return paths, and takes a pool name so that the exhaustion
> log identifies the affected pool.
How do you think about to move such hints behind the marker line?
…
> ---
> drivers/infiniband/hw/zrdma/zrdma_hw.h | 21 +++
> drivers/infiniband/hw/zrdma/zrdma_main.h | 216 +++++++++++++++++++++++
…
> +++ b/drivers/infiniband/hw/zrdma/zrdma_main.h
> @@ -0,0 +1,216 @@
…
> +static inline int zxdh_alloc_rsrc(struct zxdh_pci_f *rf,
> + unsigned long *rsrc_array, u32 max_rsrc,
> + u32 *req_rsrc_num, u32 *next,
> + const char *rsrc_name)
> +{
> + unsigned long flags;
> + u32 rsrc_num;
> +
> + spin_lock_irqsave(&rf->rsrc_lock, flags);
> + rsrc_num = find_next_zero_bit(rsrc_array, max_rsrc, *next);
…
> + *req_rsrc_num = rsrc_num;
> + spin_unlock_irqrestore(&rf->rsrc_lock, flags);
> +
> + return 0;
> +}
…
I imagine that a lock guard would be helpful also for this function implementation.
Regards,
Markus
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-10-27 7:11 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-27 2:11 [PATCH rdma v7 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
2026-10-27 2:11 ` [PATCH rdma v7 1/7] RDMA/zrdma: Add build infrastructure and module skeleton Yanze Zhang
2026-10-27 2:30 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 2/7] RDMA/zrdma: Add core data structures and ABI definitions Yanze Zhang
2026-10-27 2:28 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 3/7] RDMA/zrdma: Add internal headers and hardware register definitions Yanze Zhang
2026-10-27 2:26 ` sashiko-bot
2026-10-27 7:10 ` Markus Elfring
2026-10-27 2:11 ` [PATCH rdma v7 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton Yanze Zhang
2026-10-27 2:33 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 5/7] RDMA/zrdma: Add device probe and remove logic Yanze Zhang
2026-10-27 2:37 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 6/7] RDMA/zrdma: Implement context, PD, and mmap operations Yanze Zhang
2026-10-27 2:39 ` sashiko-bot
2026-10-27 2:11 ` [PATCH rdma v7 7/7] RDMA/zrdma: Implement device and port query operations Yanze Zhang
2026-10-27 2:33 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox