* [PATCH 1/7] RDMA/zrdma: Add build infrastructure and module skeleton
2026-10-24 7:15 [PATCH rdma v6 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
@ 2026-10-24 7:15 ` Yanze Zhang
2026-10-24 7:34 ` sashiko-bot
2026-10-24 7:15 ` [PATCH 2/7] RDMA/zrdma: Add core data structures and ABI definitions Yanze Zhang
` (5 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Yanze Zhang @ 2026-10-24 7:15 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu, lkp
Cc: 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.
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 | 12 +++++
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, 82 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..bfe21c123217
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+config INFINIBAND_ZRDMA
+ tristate "ZTE Ethernet Protocol Driver for RDMA"
+ depends on PCI
+ depends on NETDEVICES
+ 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] 17+ messages in thread* [PATCH 2/7] RDMA/zrdma: Add core data structures and ABI definitions
2026-10-24 7:15 [PATCH rdma v6 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
2026-10-24 7:15 ` [PATCH 1/7] RDMA/zrdma: Add build infrastructure and module skeleton Yanze Zhang
@ 2026-10-24 7:15 ` Yanze Zhang
2026-10-24 7:32 ` sashiko-bot
2026-10-24 18:33 ` kernel test robot
2026-10-24 7:15 ` [PATCH 3/7] RDMA/zrdma: Add internal headers and hardware register definitions Yanze Zhang
` (4 subsequent siblings)
6 siblings, 2 replies; 17+ messages in thread
From: Yanze Zhang @ 2026-10-24 7:15 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu, lkp
Cc: 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.
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 | 81 ++++++++++++++++++++++
4 files changed, 208 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..6686a02f77a3
--- /dev/null
+++ b/include/uapi/rdma/zrdma_abi.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 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] 17+ messages in thread* Re: [PATCH 2/7] RDMA/zrdma: Add core data structures and ABI definitions
2026-10-24 7:15 ` [PATCH 2/7] RDMA/zrdma: Add core data structures and ABI definitions Yanze Zhang
@ 2026-10-24 7:32 ` sashiko-bot
2026-10-24 18:33 ` kernel test robot
1 sibling, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-10-24 7:32 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] RDMA/zrdma: missing WITH Linux-syscall-note in UAPI zrdma_abi.h SPDX header
--
commit c85ffe470e05337ffcff385d3797e8a504257235
Author: Yanze Zhang <zhang.yanze@zte.com.cn>
RDMA/zrdma: Add core data structures and ABI definitions
This patch adds core data structures, hardware control structures, and
user-space ABI definitions for the ZTE DingHai RDMA driver.
> diff --git a/include/uapi/rdma/zrdma_abi.h b/include/uapi/rdma/zrdma_abi.h
> new file mode 100644
> index 0000000000000..6686a02f77a32
> --- /dev/null
> +++ b/include/uapi/rdma/zrdma_abi.h
> @@ -0,0 +1,81 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
[Severity: Low]
Will this license header cause a build failure when installing or validating
exported user-space headers (such as via make headers_install)?
When scripts/headers_install.sh processes headers under include/uapi/, it
rejects gpl license identifiers that omit the syscall note exception:
# SPDX-License-Identifier with GPL variants must have "WITH Linux-syscall-note"
if [ -n "$(sed -n -e "/SPDX-License-Identifier:.*GPL-/{/WITH Linux-syscall-note/!p}" $INFILE)" ]; then
echo "error: $INFILE: missing \"WITH Linux-syscall-note\" for SPDX-License-Identifier" >&2
exit 1
fi
Should the first line of include/uapi/rdma/zrdma_abi.h instead be:
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR Linux-OpenIB) */
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261024071539.2182864-1-zhang.yanze@zte.com.cn?part=2
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH 2/7] RDMA/zrdma: Add core data structures and ABI definitions
2026-10-24 7:15 ` [PATCH 2/7] RDMA/zrdma: Add core data structures and ABI definitions Yanze Zhang
2026-10-24 7:32 ` sashiko-bot
@ 2026-10-24 18:33 ` kernel test robot
1 sibling, 0 replies; 17+ messages in thread
From: kernel test robot @ 2026-10-24 18:33 UTC (permalink / raw)
To: Yanze Zhang, jgg, leon, julianbraha, huangjunxian6, yanjun.zhu,
lkp
Cc: oe-kbuild-all, linux-kernel, linux-rdma, wei.quan, han.junyang,
ran.ming, han.chengfei, zhang.yanze
Hi Yanze,
kernel test robot noticed the following build errors:
[auto build test ERROR on rdma/for-next]
[also build test ERROR on linus/master v7.3 next-20261023]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Yanze-Zhang/RDMA-zrdma-Add-build-infrastructure-and-module-skeleton/20261024-151533
base: https://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git for-next
patch link: https://lore.kernel.org/r/20261024071539.2182864-3-zhang.yanze%40zte.com.cn
patch subject: [PATCH 2/7] RDMA/zrdma: Add core data structures and ABI definitions
config: x86_64-rhel-9.4-kselftests (https://download.01.org/0day-ci/archive/20261025/202610250256.rhuaT37h-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261025/202610250256.rhuaT37h-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202610250256.rhuaT37h-lkp@intel.com/
All errors (new ones prefixed by >>):
>> error: include/uapi/rdma/zrdma_abi.h: missing "WITH Linux-syscall-note" for SPDX-License-Identifier
make[3]: *** [scripts/Makefile.headersinst:63: usr/include/rdma/zrdma_abi.h] Error 1
make[3]: Target '__headers' not remade because of errors.
make[2]: *** [Makefile:1523: headers] Error 2
make[2]: Target 'prepare' not remade because of errors.
make[1]: *** [Makefile:248: __sub-make] Error 2
make[1]: Target 'prepare' not remade because of errors.
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'prepare' not remade because of errors.
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 3/7] RDMA/zrdma: Add internal headers and hardware register definitions
2026-10-24 7:15 [PATCH rdma v6 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
2026-10-24 7:15 ` [PATCH 1/7] RDMA/zrdma: Add build infrastructure and module skeleton Yanze Zhang
2026-10-24 7:15 ` [PATCH 2/7] RDMA/zrdma: Add core data structures and ABI definitions Yanze Zhang
@ 2026-10-24 7:15 ` Yanze Zhang
2026-10-24 7:31 ` sashiko-bot
2026-10-24 8:43 ` [PATCH v6? " Markus Elfring
2026-10-24 7:15 ` [PATCH 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton Yanze Zhang
` (3 subsequent siblings)
6 siblings, 2 replies; 17+ messages in thread
From: Yanze Zhang @ 2026-10-24 7:15 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu, lkp
Cc: 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.
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..060d6f627b0d
--- /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/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;
+
+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;
+ u32 netdev_speed;
+ 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)
+{
+ 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: resource [%d] allocation failed\n",
+ rsrc_num);
+ 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)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rf->rsrc_lock, flags);
+ __clear_bit(rsrc_num, rsrc_array);
+ spin_unlock_irqrestore(&rf->rsrc_lock, flags);
+}
+
+int zxdh_get_del_rdma_name(const char *sbdf, char *name);
+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] 17+ messages in thread* Re: [PATCH 3/7] RDMA/zrdma: Add internal headers and hardware register definitions
2026-10-24 7:15 ` [PATCH 3/7] RDMA/zrdma: Add internal headers and hardware register definitions Yanze Zhang
@ 2026-10-24 7:31 ` sashiko-bot
2026-10-24 8:43 ` [PATCH v6? " Markus Elfring
1 sibling, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-10-24 7:31 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.
>
> 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/20261024071539.2182864-1-zhang.yanze@zte.com.cn?part=3
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v6? 3/7] RDMA/zrdma: Add internal headers and hardware register definitions
2026-10-24 7:15 ` [PATCH 3/7] RDMA/zrdma: Add internal headers and hardware register definitions Yanze Zhang
2026-10-24 7:31 ` sashiko-bot
@ 2026-10-24 8:43 ` Markus Elfring
1 sibling, 0 replies; 17+ messages in thread
From: Markus Elfring @ 2026-10-24 8:43 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
Please specify version identifications in a consistent way.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v7.3#n711
https://lore.kernel.org/linux-rdma/20261024071539.2182864-1-zhang.yanze@zte.com.cn/
…
> +++ b/drivers/infiniband/hw/zrdma/zrdma_main.h
> @@ -0,0 +1,216 @@
…
> +static inline void zxdh_free_rsrc(struct zxdh_pci_f *rf,
> + unsigned long *rsrc_array, u32 rsrc_num)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&rf->rsrc_lock, flags);
> + __clear_bit(rsrc_num, rsrc_array);
> + spin_unlock_irqrestore(&rf->rsrc_lock, flags);
> +}
…
Under which circumstances would you become interested to apply a statement
like “guard(spinlock_irqsave)(&rf->rsrc_lock);”?
https://elixir.bootlin.com/linux/v7.3/source/include/linux/spinlock.h#L642-L645
See also:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst?h=v7.3#n977
Regards,
Markus
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton
2026-10-24 7:15 [PATCH rdma v6 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
` (2 preceding siblings ...)
2026-10-24 7:15 ` [PATCH 3/7] RDMA/zrdma: Add internal headers and hardware register definitions Yanze Zhang
@ 2026-10-24 7:15 ` Yanze Zhang
2026-10-24 7:36 ` sashiko-bot
2026-10-24 7:15 ` [PATCH 5/7] RDMA/zrdma: Add device probe and remove logic Yanze Zhang
` (2 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Yanze Zhang @ 2026-10-24 7:15 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu, lkp
Cc: 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 an empty ops structure to satisfy the requirement
that the driver must be functional and have a valid driver ID.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/Makefile | 5 +-
drivers/infiniband/hw/zrdma/zrdma_hw.c | 103 +++++++++++++++++
drivers/infiniband/hw/zrdma/zrdma_main.c | 57 ----------
drivers/infiniband/hw/zrdma/zrdma_verbs.c | 41 +++++++
drivers/infiniband/hw/zrdma/zrdma_verbs.h | 128 ++++++++++++++++++++++
5 files changed, 276 insertions(+), 58 deletions(-)
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_hw.c
delete mode 100644 drivers/infiniband/hw/zrdma/zrdma_main.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..88be835f5c5c 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
\ No newline at end of file
diff --git a/drivers/infiniband/hw/zrdma/zrdma_hw.c b/drivers/infiniband/hw/zrdma/zrdma_hw.c
new file mode 100644
index 000000000000..11c8bdac2598
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_hw.c
@@ -0,0 +1,103 @@
+// 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)
+{
+ rf->allocated_srqs = (void *)(rf->mem_rsrc);
+ rf->allocated_qps = &rf->allocated_srqs[BITS_TO_LONGS(rf->max_srq)];
+ rf->allocated_cqs = &rf->allocated_qps[BITS_TO_LONGS(rf->max_qp)];
+ rf->allocated_mrs = &rf->allocated_cqs[BITS_TO_LONGS(rf->max_cq)];
+ rf->allocated_pds = &rf->allocated_mrs[BITS_TO_LONGS(rf->max_mr)];
+ rf->allocated_ahs = &rf->allocated_pds[BITS_TO_LONGS(rf->max_pd)];
+ rf->allocated_mcgs = &rf->allocated_ahs[BITS_TO_LONGS(rf->max_ah)];
+ rf->allocated_pris = &rf->allocated_mcgs[BITS_TO_LONGS(rf->max_mcg)];
+ rf->allocated_8k_idx = &rf->allocated_pris[BITS_TO_LONGS(rf->max_pri)];
+ rf->qp_table = (struct zxdh_qp **)(&rf->allocated_8k_idx[BITS_TO_LONGS(
+ rf->max_8k_idx)]);
+ rf->cq_table = (struct zxdh_cq **)(&rf->qp_table[rf->max_qp]);
+ rf->srq_table = (struct zxdh_srq **)(&rf->cq_table[rf->max_cq]);
+
+ 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_main.c b/drivers/infiniband/hw/zrdma/zrdma_main.c
deleted file mode 100644
index af1d37be6336..000000000000
--- a/drivers/infiniband/hw/zrdma/zrdma_main.c
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
new file mode 100644
index 000000000000..6db536c94e01
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
@@ -0,0 +1,41 @@
+// 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"
+
+static 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;
+
+ ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
+
+ 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..05ce53b2777b
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.h
@@ -0,0 +1,128 @@
+/* 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/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_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_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;
+};
+
+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] 17+ messages in thread* Re: [PATCH 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton
2026-10-24 7:15 ` [PATCH 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton Yanze Zhang
@ 2026-10-24 7:36 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-10-24 7:36 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: accidental deletion of zrdma_main.c breaks build
--
commit e05483ee5929bdb338026257200504048dace255
Author: Yanze Zhang <zhang.yanze@zte.com.cn>
RDMA/zrdma: Add hardware resource initialization and verbs skeleton
This commit adds hardware resource initialization routines in zrdma_hw.c
and a minimal verbs device registration skeleton in zrdma_verbs.c and
zrdma_verbs.h.
> diff --git a/drivers/infiniband/hw/zrdma/Makefile b/drivers/infiniband/hw/zrdma/Makefile
> index 2ddf50d1fd208..88be835f5c5c2 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
> \ No newline at end of file
[ ... ]
> diff --git a/drivers/infiniband/hw/zrdma/zrdma_main.c b/drivers/infiniband/hw/zrdma/zrdma_main.c
> deleted file mode 100644
> index af1d37be63362..0000000000000
> --- a/drivers/infiniband/hw/zrdma/zrdma_main.c
> +++ /dev/null
> @@ -1,57 +0,0 @@
> -// 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>
[ ... ]
> -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);
[Severity: High]
Was drivers/infiniband/hw/zrdma/zrdma_main.c deleted here by mistake?
In drivers/infiniband/hw/zrdma/Makefile, zrdma-y still lists zrdma_main.o:
zrdma-y := \
zrdma_main.o \
zrdma_hw.o \
zrdma_verbs.o
Deleting drivers/infiniband/hw/zrdma/zrdma_main.c in this commit removes
zrdma_module_init(), zrdma_module_exit(), zxdh_probe(), and zxdh_remove(),
and causes the build to fail when building drivers/infiniband/hw/zrdma/
because there is no rule to make target zrdma_main.o.
Although a later commit in the series ("RDMA/zrdma: Add device probe and
remove logic") re-adds drivers/infiniband/hw/zrdma/zrdma_main.c, leaving it
deleted here breaks the build and git bisection at this commit.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261024071539.2182864-1-zhang.yanze@zte.com.cn?part=4
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 5/7] RDMA/zrdma: Add device probe and remove logic
2026-10-24 7:15 [PATCH rdma v6 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
` (3 preceding siblings ...)
2026-10-24 7:15 ` [PATCH 4/7] RDMA/zrdma: Add hardware resource initialization and verbs skeleton Yanze Zhang
@ 2026-10-24 7:15 ` Yanze Zhang
2026-10-24 7:38 ` sashiko-bot
2026-10-24 7:15 ` [PATCH 6/7] RDMA/zrdma: Implement context, PD, and mmap operations Yanze Zhang
2026-10-24 7:15 ` [PATCH 7/7] RDMA/zrdma: Implement device and port query operations Yanze Zhang
6 siblings, 1 reply; 17+ messages in thread
From: Yanze Zhang @ 2026-10-24 7:15 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu, lkp
Cc: 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.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/zrdma_main.c | 294 +++++++++++++++++++++++
1 file changed, 294 insertions(+)
create mode 100644 drivers/infiniband/hw/zrdma/zrdma_main.c
diff --git a/drivers/infiniband/hw/zrdma/zrdma_main.c b/drivers/infiniband/hw/zrdma/zrdma_main.c
new file mode 100644
index 000000000000..5127e56fd164
--- /dev/null
+++ b/drivers/infiniband/hw/zrdma/zrdma_main.c
@@ -0,0 +1,294 @@
+// 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>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <rdma/ib_verbs.h>
+
+#include "zrdma_main.h"
+
+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");
+
+LIST_HEAD(zxdh_handlers);
+DEFINE_SPINLOCK(zxdh_handler_lock);
+
+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;
+ u8 len = 0;
+
+ if (!sbdf || !name || !name_len)
+ return -EINVAL;
+
+ if (name_len > IB_DEVICE_NAME_MAX) {
+ pr_err("zrdma: name buffer too large\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&rdma_name_lock);
+ list_for_each_entry_safe(pos, tmp, &zxdh_rdma_list, list) {
+ len = strlen(pos->sbdf);
+ if (strlen(sbdf) == len) {
+ if (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)
+{
+ 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;
+ }
+
+ 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;
+
+ 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;
+ zdev->netdev_speed = SPEED_UNKNOWN;
+
+ rf = zdev->rf;
+ err = zxdh_ctrl_init_hw(rf);
+ if (err)
+ goto err_ctrl_init;
+
+ err = zxdh_ib_register_device(zdev);
+ if (err)
+ goto err_ib_reg;
+
+ /* 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_ib_reg:
+err_ctrl_init:
+ ib_dealloc_device(&zdev->ibdev);
+
+ return err;
+}
+
+static void zxdh_remove(struct auxiliary_device *aux_dev)
+{
+ 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,
+ .probe = zxdh_probe,
+ .remove = zxdh_remove,
+};
+
+static int __init zrdma_module_init(void)
+{
+ 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);
+module_exit(zrdma_module_exit);
--
2.27.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 5/7] RDMA/zrdma: Add device probe and remove logic
2026-10-24 7:15 ` [PATCH 5/7] RDMA/zrdma: Add device probe and remove logic Yanze Zhang
@ 2026-10-24 7:38 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-10-24 7:38 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] RDMA/zrdma: memory leaks on error paths in zxdh_probe()
--
commit 28ece0add9abc6cac3d040b5b5512cf8b3c518c3
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 callbacks for the
zrdma driver, including device initialization, hardware resource setup, and
IB device registration.
> diff --git a/drivers/infiniband/hw/zrdma/zrdma_main.c b/drivers/infiniband/hw/zrdma/zrdma_main.c
> new file mode 100644
> index 0000000000000..5127e56fd1642
> --- /dev/null
> +++ b/drivers/infiniband/hw/zrdma/zrdma_main.c
> @@ -0,0 +1,294 @@
[ ... ]
> +static int zxdh_probe(struct auxiliary_device *aux_dev,
> + const struct auxiliary_device_id *id)
> +{
> + 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;
> + }
> +
> + 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;
> +
> + 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;
> + zdev->netdev_speed = SPEED_UNKNOWN;
> +
> + rf = zdev->rf;
> + err = zxdh_ctrl_init_hw(rf);
> + if (err)
> + goto err_ctrl_init;
> +
> + err = zxdh_ib_register_device(zdev);
> + if (err)
> + goto err_ib_reg;
> +
> + /* 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_ib_reg:
> +err_ctrl_init:
> + ib_dealloc_device(&zdev->ibdev);
> +
> + return err;
> +}
[Severity: Medium]
Does zxdh_probe() leak zdev->rf, hdl, and the hardware resource buffers on its
error paths?
When kzalloc_obj(*hdl) fails, zxdh_probe() calls
ib_dealloc_device(&zdev->ibdev) and returns -ENOMEM without freeing zdev->rf
or destroying zdev->ah_list_lock initialized in zxdh_fill_device_info().
Similarly, zxdh_ctrl_init_hw() -> zxdh_initialize_hw_rsrc() allocates
rf->qp_cnt_8k_idxs and rf->mem_rsrc with vzalloc():
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 zxdh_ctrl_init_hw() or zxdh_ib_register_device() fails, jumping to
err_ctrl_init or err_ib_reg only calls ib_dealloc_device(&zdev->ibdev),
leaking hdl, zdev->rf, rf->qp_cnt_8k_idxs, and rf->mem_rsrc.
Later in the series, commit 42854f9bc8b3 ("RDMA/zrdma: Implement context, PD,
and mmap operations") wires up zxdh_ib_dealloc_device() as .dealloc_driver in
zxdh_dev_ops. However, ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops) is only
called inside zxdh_ib_register_device() -> zxdh_init_rdma_device() after the
roce_mode check. If zxdh_probe() fails at the hdl allocation, during
zxdh_ctrl_init_hw(), or before ib_set_device_ops() is reached,
zdev->ibdev.ops.dealloc_driver is still NULL when ib_dealloc_device() runs, so
zxdh_ib_dealloc_device() will not be called to clean up those allocations
(and hdl is not freed by zxdh_ib_dealloc_device() either).
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261024071539.2182864-1-zhang.yanze@zte.com.cn?part=5
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 6/7] RDMA/zrdma: Implement context, PD, and mmap operations
2026-10-24 7:15 [PATCH rdma v6 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
` (4 preceding siblings ...)
2026-10-24 7:15 ` [PATCH 5/7] RDMA/zrdma: Add device probe and remove logic Yanze Zhang
@ 2026-10-24 7:15 ` Yanze Zhang
2026-10-24 7:43 ` sashiko-bot
2026-10-24 7:15 ` [PATCH 7/7] RDMA/zrdma: Implement device and port query operations Yanze Zhang
6 siblings, 1 reply; 17+ messages in thread
From: Yanze Zhang @ 2026-10-24 7:15 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu, lkp
Cc: 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.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/zrdma_verbs.c | 364 +++++++++++++++++++++-
1 file changed, 356 insertions(+), 8 deletions(-)
diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
index 6db536c94e01..54b016ea8f5d 100644
--- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
@@ -7,24 +7,370 @@
#include "zrdma_main.h"
#include "zrdma_verbs.h"
#include "zrdma_ctrl.h"
+#include <rdma/ib_mad.h>
+#include <rdma/ib_cache.h>
+#include <rdma/ib_user_verbs.h>
+#include <linux/etherdevice.h>
-static const struct ib_device_ops zxdh_dev_ops = {
- .owner = THIS_MODULE,
- .driver_id = RDMA_DRIVER_ZRDMA,
- .uverbs_abi_ver = ZXDH_ABI_VER,
-};
+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 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;
+ /* rf == NULL => zxdh_probe early failure path; ah_list_lock
+ * not initialised, must not be destroyed.
+ */
+ mutex_destroy(&zdev->ah_list_lock);
+ }
+ kfree(zdev->hdl);
+ zdev->hdl = NULL;
+}
+
+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);
+ if (err) {
+ pr_warn("zrdma: zxdh_alloc_rsrc 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;
+}
+
+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 = {};
+
+ 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_OFFSET;
+
+ 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;
+ }
+
+ if (ucontext->abi_ver == ZXDH_CONTEXT_VER_V1 ||
+ ucontext->abi_ver == ZXDH_CONTEXT_VER_V2) {
+ ucontext->srq_db_mmap_entry =
+ zxdh_mp_mmap_entry_insert(ucontext, SRQ_DB_BAR_OFF,
+ PAGE_SIZE,
+ ZXDH_MMAP_IO_NC_BY_SIZE,
+ &uresp.srq_db_mmap_key);
+ } else {
+ 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;
-
- ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
+ zdev->ibdev.dev.parent = &pcidev->dev;
return 0;
}
+static const struct ib_device_ops zxdh_dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_ZRDMA,
+ .uverbs_abi_ver = ZXDH_ABI_VER,
+ .alloc_pd = zxdh_alloc_pd,
+ .alloc_ucontext = zxdh_alloc_ucontext,
+ .dealloc_driver = zxdh_ib_dealloc_device,
+ .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),
+};
+
int zxdh_ib_register_device(struct zxdh_device *zdev)
{
int ret;
@@ -33,6 +379,8 @@ int zxdh_ib_register_device(struct zxdh_device *zdev)
if (ret)
return ret;
+ ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
+
ret = ib_register_device(&zdev->ibdev, "zrdma%d", zdev->rf->hw.device);
if (ret)
pr_err("zrdma: Register RDMA device fail\n");
--
2.27.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 6/7] RDMA/zrdma: Implement context, PD, and mmap operations
2026-10-24 7:15 ` [PATCH 6/7] RDMA/zrdma: Implement context, PD, and mmap operations Yanze Zhang
@ 2026-10-24 7:43 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-10-24 7:43 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] RDMA/zrdma: resource leak on probe failure due to late ib_set_device_ops()
- [Medium] RDMA/zrdma: truncated SRQ doorbell mmap range in zxdh_alloc_ucontext()
--
commit 42854f9bc8b33facfd22e1942728befbae8346de
Author: Yanze Zhang <zhang.yanze@zte.com.cn>
RDMA/zrdma: Implement context, PD, and mmap operations
This commit implements protection domain allocation and deallocation, user
context management, and doorbell memory mapping for the zrdma driver. It also
adds device teardown and initialization logic for RDMA device registration.
> diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> index 6db536c94e01a..54b016ea8f5de 100644
> --- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> +++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> @@ -7,24 +7,370 @@
> #include "zrdma_main.h"
> #include "zrdma_verbs.h"
> #include "zrdma_ctrl.h"
> +#include <rdma/ib_mad.h>
> +#include <rdma/ib_cache.h>
> +#include <rdma/ib_user_verbs.h>
> +#include <linux/etherdevice.h>
>
> -static const struct ib_device_ops zxdh_dev_ops = {
> - .owner = THIS_MODULE,
> - .driver_id = RDMA_DRIVER_ZRDMA,
> - .uverbs_abi_ver = ZXDH_ABI_VER,
> -};
[ ... ]
> +static 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;
> + /* rf == NULL => zxdh_probe early failure path; ah_list_lock
> + * not initialised, must not be destroyed.
> + */
> + mutex_destroy(&zdev->ah_list_lock);
> + }
> + kfree(zdev->hdl);
> + zdev->hdl = NULL;
> +}
[ ... ]
> +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 = {};
[ ... ]
> + uresp.srq_db_bar_off = SRQ_DB_OFFSET;
[ ... ]
> + if (ucontext->abi_ver == ZXDH_CONTEXT_VER_V1 ||
> + ucontext->abi_ver == ZXDH_CONTEXT_VER_V2) {
> + ucontext->srq_db_mmap_entry =
> + zxdh_mp_mmap_entry_insert(ucontext, SRQ_DB_BAR_OFF,
> + PAGE_SIZE,
> + ZXDH_MMAP_IO_NC_BY_SIZE,
> + &uresp.srq_db_mmap_key);
> + } else {
> + 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;
[ ... ]
> +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;
[Severity: Medium]
In drivers/infiniband/hw/zrdma/zrdma_verbs.h, SRQ_DB_BAR_OFF is defined as
0x62000 and SRQ_DB_MMAP_SIZE is 0x10000:
#define ZXDH_PAGE_OFFSET_NUM (PAGE_SIZE - 1)
...
#define SRQ_DB_MMAP_SIZE 0x10000
#define SRQ_DB_BAR_OFF 0x62000
On kernels with 16KB or 64KB pages, SRQ_DB_BAR_OFF has an intra-page offset of
0x2000. When zxdh_alloc_ucontext() registers ucontext->srq_db_mmap_entry with
length SRQ_DB_MMAP_SIZE (0x10000) for ZXDH_CONTEXT_VER_V3, and zxdh_mmap()
computes:
pfn = (entry->bar_offset +
pci_resource_start(ucontext->zdev->rf->pcidev, 0)) >>
PAGE_SHIFT;
pfn is rounded down to BAR0 offset 0x60000. Mapping 0x10000 bytes from that
pfn only covers BAR0 [0x60000, 0x70000). When userspace adds srq_db_bar_off
(0x2000) to the mapped base address, won't the upper 0x2000 bytes of the SRQ
doorbell region at [0x70000, 0x72000) remain unmapped?
Also, when ucontext->abi_ver is ZXDH_CONTEXT_VER_V1 or ZXDH_CONTEXT_VER_V2,
zxdh_alloc_ucontext() inserts ucontext->srq_db_mmap_entry with length
PAGE_SIZE, but still sets uresp.srq_db_mmap_size = SRQ_DB_MMAP_SIZE. Should
uresp.srq_db_mmap_size match the registered entry size for V1 and V2 so
rdma_user_mmap_entry_get() does not reject a mapping of uresp.srq_db_mmap_size
bytes?
[ ... ]
> 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;
> -
> - ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
> + zdev->ibdev.dev.parent = &pcidev->dev;
>
> return 0;
> }
>
> +static const struct ib_device_ops zxdh_dev_ops = {
> + .owner = THIS_MODULE,
> + .driver_id = RDMA_DRIVER_ZRDMA,
> + .uverbs_abi_ver = ZXDH_ABI_VER,
> + .alloc_pd = zxdh_alloc_pd,
> + .alloc_ucontext = zxdh_alloc_ucontext,
> + .dealloc_driver = zxdh_ib_dealloc_device,
> + .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),
> +};
> +
> int zxdh_ib_register_device(struct zxdh_device *zdev)
> {
> int ret;
> @@ -33,6 +379,8 @@ int zxdh_ib_register_device(struct zxdh_device *zdev)
> if (ret)
> return ret;
>
> + ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
[Severity: High]
Does calling ib_set_device_ops() here in zxdh_ib_register_device() leak
zdev->rf, zdev->hdl, zdev->rf->qp_cnt_8k_idxs, and zdev->rf->mem_rsrc if an
earlier failure occurs during zxdh_probe()?
In drivers/infiniband/hw/zrdma/zrdma_main.c, zxdh_probe() relies on
ib_dealloc_device(&zdev->ibdev) to invoke zxdh_ib_dealloc_device() on its
error paths:
hdl = kzalloc_obj(*hdl);
if (!hdl) {
ib_dealloc_device(&zdev->ibdev);
return -ENOMEM;
}
...
rf = zdev->rf;
err = zxdh_ctrl_init_hw(rf);
if (err)
goto err_ctrl_init;
err = zxdh_ib_register_device(zdev);
if (err)
goto err_ib_reg;
...
err_ib_reg:
err_ctrl_init:
ib_dealloc_device(&zdev->ibdev);
If kzalloc_obj(*hdl), zxdh_ctrl_init_hw(), or zxdh_init_rdma_device() fails
(or even in follow-up commit 5562e1f8054b where ib_set_device_ops() is at the
end of zxdh_init_rdma_device()), zdev->ibdev.ops.dealloc_driver is still NULL
when ib_dealloc_device() runs, so zxdh_ib_dealloc_device() is never called.
Should ib_set_device_ops() be called right after ib_alloc_device() so that
zxdh_ib_dealloc_device() is always invoked on probe failure?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261024071539.2182864-1-zhang.yanze@zte.com.cn?part=6
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 7/7] RDMA/zrdma: Implement device and port query operations
2026-10-24 7:15 [PATCH rdma v6 0/7] Add ZTE DingHai Ethernet Protocol Driver for RDMA Yanze Zhang
` (5 preceding siblings ...)
2026-10-24 7:15 ` [PATCH 6/7] RDMA/zrdma: Implement context, PD, and mmap operations Yanze Zhang
@ 2026-10-24 7:15 ` Yanze Zhang
2026-10-24 7:45 ` sashiko-bot
6 siblings, 1 reply; 17+ messages in thread
From: Yanze Zhang @ 2026-10-24 7:15 UTC (permalink / raw)
To: jgg, leon, julianbraha, huangjunxian6, yanjun.zhu, lkp
Cc: linux-kernel, linux-rdma, wei.quan, han.junyang, ran.ming,
han.chengfei, zhang.yanze
Add implementation for querying device attributes, port attributes,
GID, PKey, and link layer information. Also include firmware
version string retrieval.
Signed-off-by: Yanze Zhang <zhang.yanze@zte.com.cn>
---
drivers/infiniband/hw/zrdma/zrdma_main.h | 2 +-
drivers/infiniband/hw/zrdma/zrdma_verbs.c | 398 +++++++++++++++++++++-
2 files changed, 383 insertions(+), 17 deletions(-)
diff --git a/drivers/infiniband/hw/zrdma/zrdma_main.h b/drivers/infiniband/hw/zrdma/zrdma_main.h
index 060d6f627b0d..62e52e5a23ee 100644
--- a/drivers/infiniband/hw/zrdma/zrdma_main.h
+++ b/drivers/infiniband/hw/zrdma/zrdma_main.h
@@ -208,7 +208,7 @@ static inline void zxdh_free_rsrc(struct zxdh_pci_f *rf,
spin_unlock_irqrestore(&rf->rsrc_lock, flags);
}
-int zxdh_get_del_rdma_name(const char *sbdf, char *name);
+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);
diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
index 54b016ea8f5d..a16e00e78535 100644
--- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
+++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
@@ -11,6 +11,7 @@
#include <rdma/ib_cache.h>
#include <rdma/ib_user_verbs.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
static void zxdh_sc_pd_init(struct zxdh_sc_dev *dev, struct zxdh_sc_pd *pd,
u32 pd_id, int abi_ver)
@@ -55,7 +56,8 @@ static int zxdh_alloc_pd(struct ib_pd *pd, struct ib_udata *udata)
err = zxdh_alloc_rsrc(rf, rf->allocated_pds, rf->max_pd, &pd_id,
&rf->next_pd);
if (err) {
- pr_warn("zrdma: zxdh_alloc_rsrc failed err=%d\n", err);
+ pr_warn_ratelimited("zrdma: PD allocation failed err=%d\n",
+ err);
return err;
}
@@ -157,7 +159,7 @@ static int zxdh_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
ucontext->zdev = zdev;
ucontext->abi_ver = req.userspace_ver;
- uresp.srq_db_bar_off = SRQ_DB_OFFSET;
+ 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,
@@ -332,29 +334,327 @@ static int zxdh_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
return ret;
}
-static void zxdh_init_roce_device(struct zxdh_device *zdev)
+/* Fetch the driver info for @zdev->netdev, or for its first lower device
+ * when it is a bond. adj_list.lower is rtnl_lock protected, but the core
+ * may call this from a netdev notifier already holding rtnl_lock.
+ */
+static bool zxdh_get_drvinfo(struct zxdh_device *zdev,
+ struct ethtool_drvinfo *info)
{
- zdev->ibdev.node_type = RDMA_NODE_IB_CA;
- addrconf_addr_eui48((u8 *)&zdev->ibdev.node_guid,
- zdev->netdev->dev_addr);
+ struct net_device *slave = NULL, *dev;
+ struct list_head *iter;
+ bool locked = false;
+ bool ret = false;
+
+ memset(info, 0, sizeof(*info));
+
+ if ((zdev->netdev->priv_flags & IFF_BONDING) && rtnl_trylock()) {
+ netdev_for_each_lower_dev(zdev->netdev, slave, iter)
+ break;
+ locked = true;
+ }
+
+ dev = slave ? slave : zdev->netdev;
+ if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) {
+ dev->ethtool_ops->get_drvinfo(dev, info);
+ ret = true;
+ }
+
+ if (locked)
+ rtnl_unlock();
+
+ return ret;
}
-static int zxdh_init_rdma_device(struct zxdh_device *zdev)
+static void extract_version(const char *input, char *output)
{
+ const char *v_start, *p;
+ int dots = 0;
+
+ if (!output || !input)
+ goto fail;
+
+ if (strstr(input, " (")) {
+ v_start = input;
+ for (p = v_start; *p && *p != ' '; p++) {
+ if (*p == '.' && ++dots == 4)
+ break;
+ *output++ = *p;
+ }
+ } else {
+ /* Format: "E310-V25.30.103.01" - find 'V' after last '-' */
+ const char *last_dash = strrchr(input, '-');
+
+ if (!last_dash)
+ goto fail;
+ v_start = strstr(last_dash, "V");
+ if (!v_start)
+ goto fail;
+ v_start++; /* skip 'V' */
+
+ for (p = v_start; *p && dots < 4; p++) {
+ if (*p == '.' && ++dots == 4)
+ break;
+ *output++ = *p;
+ }
+ }
+
+fail:
+ if (output)
+ *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;
+ int major, sub_major, minor, sub_minor;
+ struct ethtool_drvinfo info;
+ char extracted_version[32];
+
+ if (zxdh_get_drvinfo(zdev, &info)) {
+ extract_version(info.fw_version, extracted_version);
+ if (sscanf(extracted_version, "%d.%d.%d.%d", &major,
+ &sub_major, &minor, &sub_minor) != 4) {
+ major = 0;
+ sub_major = 0;
+ minor = 0;
+ sub_minor = 0;
+ }
+ } else {
+ major = sub_major = minor = sub_minor = 0;
+ }
- if (zdev->roce_mode)
- zxdh_init_roce_device(zdev);
+ if (udata->inlen || udata->outlen)
+ return -EINVAL;
+
+ memset(props, 0, sizeof(*props));
+ addrconf_addr_eui48((u8 *)&props->sys_image_guid,
+ zdev->netdev->dev_addr);
+ props->fw_ver = ((u64)major << 48 | (u64)sub_major << 32 |
+ (u64)minor << 16 | sub_minor);
+ 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_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, 1)) {
+ 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 u32 zxdh_get_eth_netdev_speed(struct zxdh_device *zdev, u32 port_num)
+{
+ struct ethtool_link_ksettings lksettings;
+ u32 netdev_speed = (u32)SPEED_UNKNOWN;
+ struct zxdh_pci_f *rf = zdev->rf;
+ int rc;
+
+ if (rdma_port_get_link_layer(&zdev->ibdev, port_num) !=
+ IB_LINK_LAYER_ETHERNET)
+ return -EINVAL;
+
+ if (zdev->netdev_speed != (u32)SPEED_UNKNOWN)
+ return zdev->netdev_speed;
+
+ if (rf->drv_np_cap == ZXDH_RDMA_COMMON_FUNC_CAP &&
+ rf->common_func_num_max > ZXDH_FUNC_NETDEV_SPEED_GET) {
+ rc = rf->gen_ops.zxdh_common_func(zdev->zxdh_adev->parent,
+ &netdev_speed,
+ ZXDH_FUNC_NETDEV_SPEED_GET);
+
+ if (rc || netdev_speed == (u32)SPEED_UNKNOWN)
+ netdev_speed = SPEED_1000;
+ else
+ zdev->netdev_speed = netdev_speed;
+ } else {
+ if (!rtnl_trylock())
+ return SPEED_1000;
+
+ rc = __ethtool_get_link_ksettings(zdev->netdev, &lksettings);
+ rtnl_unlock();
+
+ if (!rc &&
+ lksettings.base.speed != (u32)SPEED_UNKNOWN) {
+ netdev_speed = lksettings.base.speed;
+ zdev->netdev_speed = netdev_speed;
+ } else {
+ netdev_speed = SPEED_1000;
+ }
+ }
+
+ return netdev_speed;
+}
+
+static int zxdh_get_eth_speed(struct ib_device *dev, struct net_device *netdev,
+ u32 port_num, u16 *speed, u8 *width)
+{
+ struct zxdh_device *zdev = to_zdev(dev);
+ u32 netdev_speed;
+
+ if (zdev)
+ netdev_speed = zxdh_get_eth_netdev_speed(zdev, port_num);
else
- return -EPFNOSUPPORT;
+ netdev_speed = SPEED_1000;
+
+ if (netdev_speed <= SPEED_1000) {
+ *width = IB_WIDTH_1X;
+ *speed = IB_SPEED_SDR;
+ } else if (netdev_speed <= SPEED_10000) {
+ *width = IB_WIDTH_1X;
+ *speed = IB_SPEED_FDR10;
+ } else if (netdev_speed <= SPEED_20000) {
+ *width = IB_WIDTH_4X;
+ *speed = IB_SPEED_DDR;
+ } else if (netdev_speed <= SPEED_25000) {
+ *width = IB_WIDTH_1X;
+ *speed = IB_SPEED_EDR;
+ } else if (netdev_speed <= SPEED_40000) {
+ *width = IB_WIDTH_4X;
+ *speed = IB_SPEED_FDR10;
+ } else if (netdev_speed <= SPEED_100000) {
+ *width = IB_WIDTH_4X;
+ *speed = IB_SPEED_EDR;
+ } else {
+ *width = IB_WIDTH_4X;
+ *speed = IB_SPEED_HDR;
+ }
- zdev->ibdev.phys_port_cnt = 1;
- zdev->ibdev.num_comp_vectors = zdev->rf->ceqs_count;
- zdev->ibdev.dev.parent = &pcidev->dev;
+ 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;
+ }
+ zxdh_get_eth_speed(ibdev, netdev, port, &props->active_speed,
+ &props->active_width);
+ if (rdma_protocol_roce(ibdev, 1)) {
+ props->gid_tbl_len = 255;
+ 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_query_gid_roce(struct ib_device *ibdev, u32 port, int index,
+ union ib_gid *gid)
+{
+ int ret;
+
+ ret = rdma_query_gid(ibdev, port, index, gid);
+ if (ret == -EAGAIN) {
+ memcpy(gid, &zgid, sizeof(*gid));
+ return 0;
+ }
+
+ return ret;
+}
+
+static int zxdh_roce_port_immutable(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_immutable *immutable)
+{
+ struct ib_port_attr attr;
+ int err;
+
+ immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP |
+ RDMA_CORE_CAP_PROT_ROCE;
+ err = ib_query_port(ibdev, port_num, &attr);
+ if (err)
+ return err;
+
+ immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+ immutable->pkey_tbl_len = attr.pkey_tbl_len;
+ immutable->gid_tbl_len = attr.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);
+ strscpy(str, extracted_version, IB_FW_VERSION_NAME_MAX);
+}
+
static const struct ib_device_ops zxdh_dev_ops = {
.owner = THIS_MODULE,
.driver_id = RDMA_DRIVER_ZRDMA,
@@ -364,6 +664,13 @@ static const struct ib_device_ops zxdh_dev_ops = {
.dealloc_driver = zxdh_ib_dealloc_device,
.dealloc_pd = zxdh_dealloc_pd,
.dealloc_ucontext = zxdh_dealloc_ucontext,
+ .query_device = zxdh_query_device,
+ .query_port = zxdh_query_port,
+ .query_gid = zxdh_query_gid_roce,
+ .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,
@@ -371,19 +678,78 @@ static const struct ib_device_ops zxdh_dev_ops = {
INIT_RDMA_OBJ_SIZE(ib_ucontext, zxdh_ucontext, ibucontext),
};
+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 = &pcidev->dev;
+
+ ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
+
+ 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;
- ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
+ ret = zxdh_get_del_rdma_name(pci_name(zdev->rf->pcidev), name,
+ IB_DEVICE_NAME_MAX);
+ if (ret)
+ snprintf(name, IB_DEVICE_NAME_MAX, "%s", "zrdma%d");
- ret = ib_register_device(&zdev->ibdev, "zrdma%d", zdev->rf->hw.device);
+ ret = ib_device_set_netdev(&zdev->ibdev, zdev->netdev, 1);
if (ret)
- pr_err("zrdma: Register RDMA device fail\n");
+ 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;
}
--
2.27.0
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 7/7] RDMA/zrdma: Implement device and port query operations
2026-10-24 7:15 ` [PATCH 7/7] RDMA/zrdma: Implement device and port query operations Yanze Zhang
@ 2026-10-24 7:45 ` sashiko-bot
0 siblings, 0 replies; 17+ messages in thread
From: sashiko-bot @ 2026-10-24 7:45 UTC (permalink / raw)
To: Yanze Zhang; +Cc: linux-rdma
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] RDMA/zrdma: NULL pointer dereference of udata in zxdh_query_device()
- [Medium] RDMA/zrdma: missing max_send_sge and max_recv_sge in zxdh_query_device()
- [Medium] RDMA/zrdma: broken rtnl_trylock() fallback in zxdh_get_drvinfo()
- [Medium] RDMA/zrdma: flawed speed query and caching in zxdh_get_eth_netdev_speed()
- [Medium] RDMA/zrdma: zxdh_get_dev_fw_str() overwrites N/A fallback on parse failure
- [Medium] RDMA/zrdma: memory leak on probe error paths due to late ib_set_device_ops()
- [Low] RDMA/zrdma: dead zxdh_query_gid_roce() callback and misplaced build fixes
--
commit 5562e1f8054bd9cdd1fa5be99a78d65f32fb0baf
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, GID/PKey queries, link layer reporting, firmware
version extraction, and device registration setup.
> diff --git a/drivers/infiniband/hw/zrdma/zrdma_main.h b/drivers/infiniband/hw/zrdma/zrdma_main.h
> index 060d6f627b0dd..62e52e5a23ee3 100644
> --- a/drivers/infiniband/hw/zrdma/zrdma_main.h
> +++ b/drivers/infiniband/hw/zrdma/zrdma_main.h
> @@ -208,7 +208,7 @@ static inline void zxdh_free_rsrc(struct zxdh_pci_f *rf,
> spin_unlock_irqrestore(&rf->rsrc_lock, flags);
> }
>
> -int zxdh_get_del_rdma_name(const char *sbdf, char *name);
> +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);
> diff --git a/drivers/infiniband/hw/zrdma/zrdma_verbs.c b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> index 54b016ea8f5de..a16e00e785353 100644
> --- a/drivers/infiniband/hw/zrdma/zrdma_verbs.c
> +++ b/drivers/infiniband/hw/zrdma/zrdma_verbs.c
[ ... ]
> @@ -157,7 +159,7 @@ static int zxdh_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
> ucontext->zdev = zdev;
> ucontext->abi_ver = req.userspace_ver;
>
> - uresp.srq_db_bar_off = SRQ_DB_OFFSET;
> + 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,
> @@ -332,29 +334,327 @@ static int zxdh_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
> return ret;
> }
>
> -static void zxdh_init_roce_device(struct zxdh_device *zdev)
> +/* Fetch the driver info for @zdev->netdev, or for its first lower device
> + * when it is a bond. adj_list.lower is rtnl_lock protected, but the core
> + * may call this from a netdev notifier already holding rtnl_lock.
> + */
> +static bool zxdh_get_drvinfo(struct zxdh_device *zdev,
> + struct ethtool_drvinfo *info)
> {
> - zdev->ibdev.node_type = RDMA_NODE_IB_CA;
> - addrconf_addr_eui48((u8 *)&zdev->ibdev.node_guid,
> - zdev->netdev->dev_addr);
> + struct net_device *slave = NULL, *dev;
> + struct list_head *iter;
> + bool locked = false;
> + bool ret = false;
> +
> + memset(info, 0, sizeof(*info));
> +
> + if ((zdev->netdev->priv_flags & IFF_BONDING) && rtnl_trylock()) {
> + netdev_for_each_lower_dev(zdev->netdev, slave, iter)
> + break;
> + locked = true;
> + }
> +
> + dev = slave ? slave : zdev->netdev;
> + if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) {
> + dev->ethtool_ops->get_drvinfo(dev, info);
> + ret = true;
> + }
> +
> + if (locked)
> + rtnl_unlock();
> +
> + return ret;
> }
[Severity: Medium]
What happens in zxdh_get_drvinfo() when zdev->netdev is a bonding device and
rtnl_lock is already held by the current thread or contended by another
thread?
Because rtnl_mutex is not recursive, rtnl_trylock() returns 0 even when the
caller already holds rtnl_lock. In that case, the lower device lookup is
skipped and slave remains NULL, so dev falls back to zdev->netdev (the
bonding master) instead of the lower hardware device.
Calling dev->ethtool_ops->get_drvinfo(dev, info) on the bonding master invokes
bond_ethtool_get_drvinfo(), which fills info->fw_version with BOND_ABI_VERSION
("2") and causes zxdh_get_drvinfo() to return true. When extract_version()
parses that string, it fails and outputs an empty string, resulting in
zxdh_query_device() setting props->fw_ver = 0 and zxdh_get_dev_fw_str()
overwriting "N/A" with "".
In addition, when zdev->netdev is not a bond or when rtnl_trylock() fails,
dev->ethtool_ops->get_drvinfo() is invoked without holding rtnl_lock or the
netdev ops lock.
>
> -static int zxdh_init_rdma_device(struct zxdh_device *zdev)
> +static void extract_version(const char *input, char *output)
> {
> + const char *v_start, *p;
> + int dots = 0;
> +
> + if (!output || !input)
> + goto fail;
> +
> + if (strstr(input, " (")) {
> + v_start = input;
> + for (p = v_start; *p && *p != ' '; p++) {
> + if (*p == '.' && ++dots == 4)
> + break;
> + *output++ = *p;
> + }
> + } else {
> + /* Format: "E310-V25.30.103.01" - find 'V' after last '-' */
> + const char *last_dash = strrchr(input, '-');
> +
> + if (!last_dash)
> + goto fail;
> + v_start = strstr(last_dash, "V");
> + if (!v_start)
> + goto fail;
> + v_start++; /* skip 'V' */
> +
> + for (p = v_start; *p && dots < 4; p++) {
> + if (*p == '.' && ++dots == 4)
> + break;
> + *output++ = *p;
> + }
> + }
> +
> +fail:
> + if (output)
> + *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;
> + int major, sub_major, minor, sub_minor;
> + struct ethtool_drvinfo info;
> + char extracted_version[32];
> +
> + if (zxdh_get_drvinfo(zdev, &info)) {
> + extract_version(info.fw_version, extracted_version);
> + if (sscanf(extracted_version, "%d.%d.%d.%d", &major,
> + &sub_major, &minor, &sub_minor) != 4) {
> + major = 0;
> + sub_major = 0;
> + minor = 0;
> + sub_minor = 0;
> + }
> + } else {
> + major = sub_major = minor = sub_minor = 0;
> + }
>
> - if (zdev->roce_mode)
> - zxdh_init_roce_device(zdev);
> + if (udata->inlen || udata->outlen)
> + return -EINVAL;
[Severity: High]
Won't dereferencing udata without a NULL check in zxdh_query_device() cause a
NULL pointer dereference during device registration?
When zxdh_ib_register_device() calls ib_register_device(), setup_device() in
drivers/infiniband/core/device.c queries the device attributes with udata set
to NULL:
drivers/infiniband/core/device.c:setup_device() {
...
memset(&device->attrs, 0, sizeof(device->attrs));
ret = device->ops.query_device(device, &device->attrs, NULL);
...
}
Should this check for a non-NULL udata pointer first, for example
if (udata && (udata->inlen || udata->outlen))?
> +
> + memset(props, 0, sizeof(*props));
> + addrconf_addr_eui48((u8 *)&props->sys_image_guid,
> + zdev->netdev->dev_addr);
> + props->fw_ver = ((u64)major << 48 | (u64)sub_major << 32 |
> + (u64)minor << 16 | sub_minor);
> + 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_sge_rd = MAX_SGE_RD;
[Severity: Medium]
Should zxdh_query_device() also populate props->max_send_sge and
props->max_recv_sge here?
Because props is zeroed with memset() and neither field is assigned,
device->attrs.max_send_sge and device->attrs.max_recv_sge remain 0 after
setup_device() runs.
When userspace queries the device through ib_uverbs_query_device(),
copy_query_dev_fields() in drivers/infiniband/core/uverbs_cmd.c computes:
resp->max_sge = min(attr->max_send_sge, attr->max_recv_sge);
which reports max_sge as 0 to userspace and leaves kernel ULPs seeing 0
supported SGEs in device->attrs.
[ ... ]
> +static u32 zxdh_get_eth_netdev_speed(struct zxdh_device *zdev, u32 port_num)
> +{
> + struct ethtool_link_ksettings lksettings;
> + u32 netdev_speed = (u32)SPEED_UNKNOWN;
> + struct zxdh_pci_f *rf = zdev->rf;
> + int rc;
> +
> + if (rdma_port_get_link_layer(&zdev->ibdev, port_num) !=
> + IB_LINK_LAYER_ETHERNET)
> + return -EINVAL;
> +
> + if (zdev->netdev_speed != (u32)SPEED_UNKNOWN)
> + return zdev->netdev_speed;
> +
> + if (rf->drv_np_cap == ZXDH_RDMA_COMMON_FUNC_CAP &&
> + rf->common_func_num_max > ZXDH_FUNC_NETDEV_SPEED_GET) {
> + rc = rf->gen_ops.zxdh_common_func(zdev->zxdh_adev->parent,
> + &netdev_speed,
> + ZXDH_FUNC_NETDEV_SPEED_GET);
> +
> + if (rc || netdev_speed == (u32)SPEED_UNKNOWN)
> + netdev_speed = SPEED_1000;
> + else
> + zdev->netdev_speed = netdev_speed;
> + } else {
> + if (!rtnl_trylock())
> + return SPEED_1000;
> +
> + rc = __ethtool_get_link_ksettings(zdev->netdev, &lksettings);
> + rtnl_unlock();
> +
> + if (!rc &&
> + lksettings.base.speed != (u32)SPEED_UNKNOWN) {
> + netdev_speed = lksettings.base.speed;
> + zdev->netdev_speed = netdev_speed;
> + } else {
> + netdev_speed = SPEED_1000;
> + }
> + }
> +
> + return netdev_speed;
> +}
> +
> +static int zxdh_get_eth_speed(struct ib_device *dev, struct net_device *netdev,
> + u32 port_num, u16 *speed, u8 *width)
> +{
> + struct zxdh_device *zdev = to_zdev(dev);
> + u32 netdev_speed;
> +
> + if (zdev)
> + netdev_speed = zxdh_get_eth_netdev_speed(zdev, port_num);
> else
> - return -EPFNOSUPPORT;
> + netdev_speed = SPEED_1000;
> +
> + if (netdev_speed <= SPEED_1000) {
> + *width = IB_WIDTH_1X;
> + *speed = IB_SPEED_SDR;
> + } else if (netdev_speed <= SPEED_10000) {
> + *width = IB_WIDTH_1X;
> + *speed = IB_SPEED_FDR10;
> + } else if (netdev_speed <= SPEED_20000) {
> + *width = IB_WIDTH_4X;
> + *speed = IB_SPEED_DDR;
> + } else if (netdev_speed <= SPEED_25000) {
> + *width = IB_WIDTH_1X;
> + *speed = IB_SPEED_EDR;
> + } else if (netdev_speed <= SPEED_40000) {
> + *width = IB_WIDTH_4X;
> + *speed = IB_SPEED_FDR10;
> + } else if (netdev_speed <= SPEED_100000) {
> + *width = IB_WIDTH_4X;
> + *speed = IB_SPEED_EDR;
> + } else {
> + *width = IB_WIDTH_4X;
> + *speed = IB_SPEED_HDR;
> + }
>
> - zdev->ibdev.phys_port_cnt = 1;
> - zdev->ibdev.num_comp_vectors = zdev->rf->ceqs_count;
> - zdev->ibdev.dev.parent = &pcidev->dev;
> + return 0;
> +}
[Severity: Medium]
Can zxdh_get_eth_netdev_speed() and zxdh_get_eth_speed() report stale or
bogus link speeds in zxdh_query_port()?
First, once zxdh_get_eth_netdev_speed() writes a speed into
zdev->netdev_speed, every subsequent call returns the cached
zdev->netdev_speed immediately. Nothing in the driver ever invalidates or
updates zdev->netdev_speed when the link speed changes, and concurrent reads
and writes to zdev->netdev_speed are unsynchronized.
Second, when querying via __ethtool_get_link_ksettings(), if rtnl_trylock()
fails because rtnl_mutex is held or contended while zdev->netdev_speed is
still SPEED_UNKNOWN, zxdh_get_eth_netdev_speed() returns a fabricated
SPEED_1000 (which maps to IB_WIDTH_1X and IB_SPEED_SDR).
Third, zxdh_get_eth_netdev_speed() returns u32, so returning -EINVAL converts
to 0xffffffea, which zxdh_get_eth_speed() treats as an unsigned speed greater
than SPEED_100000 and maps to IB_WIDTH_4X and IB_SPEED_HDR. Could
ib_get_eth_speed() be used instead, or the speed queried without permanent
caching and signed-to-unsigned conversion?
[ ... ]
> +static int zxdh_query_gid_roce(struct ib_device *ibdev, u32 port, int index,
> + union ib_gid *gid)
> +{
> + int ret;
> +
> + ret = rdma_query_gid(ibdev, port, index, gid);
> + if (ret == -EAGAIN) {
> + memcpy(gid, &zgid, sizeof(*gid));
> + return 0;
> + }
> +
> + return ret;
> +}
[Severity: Low]
Is zxdh_query_gid_roce() ever called by the RDMA core?
For RoCE ports, the RDMA core manages the GID cache via roce_gid_mgmt, and
ib_cache_update() in drivers/infiniband/core/cache.c only calls
device->ops.query_gid via config_non_roce_gid_cache() when
!rdma_protocol_roce(device, port). Even if invoked, rdma_query_gid() only
returns 0, -EINVAL, or -ENOENT, so the ret == -EAGAIN branch cannot be
reached.
Also, the two changes earlier in this patch to the zxdh_get_del_rdma_name()
prototype in drivers/infiniband/hw/zrdma/zrdma_main.h and uresp.srq_db_bar_off
in zxdh_alloc_ucontext() appear to fix build errors introduced in earlier
commits in the series ("RDMA/zrdma: Add device probe and remove logic" and
"RDMA/zrdma: Implement context, PD, and mmap operations"). Should those fixes
be folded into the earlier commits to preserve bisectability?
[ ... ]
> +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);
> + strscpy(str, extracted_version, IB_FW_VERSION_NAME_MAX);
> +}
[Severity: Medium]
If extract_version() fails to match the version format in info.fw_version (for
example, when info.fw_version is empty or does not contain " (" or "-...V"),
it jumps to fail and sets extracted_version[0] = '\0'. Won't the unconditional
strscpy(str, extracted_version, IB_FW_VERSION_NAME_MAX) in
zxdh_get_dev_fw_str() overwrite the "N/A" fallback with an empty string?
Also, in zxdh_query_device(), major, sub_major, minor, and sub_minor are
parsed as signed int values with "%d.%d.%d.%d" and combined via:
props->fw_ver = ((u64)major << 48 | (u64)sub_major << 32 |
(u64)minor << 16 | sub_minor);
Should extracted_version[0] be checked before overwriting str in
zxdh_get_dev_fw_str(), and should the version components in
zxdh_query_device() be parsed as unsigned 16-bit values (or masked to 0xffff)
so negative or oversized values cannot corrupt upper bits of props->fw_ver?
[ ... ]
> +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 = &pcidev->dev;
> +
> + ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops);
> +
> + return 0;
> +}
[Severity: Medium]
Does calling ib_set_device_ops(&zdev->ibdev, &zxdh_dev_ops) here at the end of
zxdh_init_rdma_device() leak zdev->rf, zdev->hdl, rf->qp_cnt_8k_idxs, and
rf->mem_rsrc if an earlier error path is taken in zxdh_probe()?
In drivers/infiniband/hw/zrdma/zrdma_main.c:zxdh_probe(), after allocating
zdev with ib_alloc_device(), the driver allocates zdev->rf, initializes
zdev->ah_list_lock in zxdh_fill_device_info(), allocates zdev->hdl, and
allocates rf->qp_cnt_8k_idxs and rf->mem_rsrc in zxdh_ctrl_init_hw():
drivers/infiniband/hw/zrdma/zrdma_main.c:zxdh_probe() {
...
hdl = kzalloc_obj(*hdl);
if (!hdl) {
ib_dealloc_device(&zdev->ibdev);
return -ENOMEM;
}
...
err = zxdh_ctrl_init_hw(rf);
if (err)
goto err_ctrl_init;
err = zxdh_ib_register_device(zdev);
if (err)
goto err_ib_reg;
...
err_ib_reg:
err_ctrl_init:
ib_dealloc_device(&zdev->ibdev);
return err;
}
All of those failure paths (as well as the !zdev->roce_mode return path in
zxdh_init_rdma_device()) rely on ib_dealloc_device(&zdev->ibdev) invoking
zxdh_ib_dealloc_device() via zdev->ibdev.ops.dealloc_driver, which is Not set
until ib_set_device_ops() runs. Should ib_set_device_ops() be called
immediately after ib_alloc_device() in zxdh_probe() (or at the start of device
initialization) so dealloc_driver is always registered before any error path
calls ib_dealloc_device()?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261024071539.2182864-1-zhang.yanze@zte.com.cn?part=7
^ permalink raw reply [flat|nested] 17+ messages in thread