[PATCH OLK-6.6] infiniband/hroce5: Add hiroce5 driver
From: maogangpin <maogangpin@huawei.com>
driver inclusion
category: feature
bugzilla:
https://atomgit.com/openeuler/kernel/issues/9708
CVE: NA
---------------------------------
Add hiroce5 driver to support hi1825 chip.
Signed-off-by: maogangpin <maogangpin@huawei.com>
Reviewed-by: Qiujun <roland.qiu@huawei.com>
Reviewed-by: chiqijun <chiqijun@huawei.com>
---
.../hw/hiroce5/drv_intf/roce_drv_msg_intf.h | 14 +
.../hw/hiroce5/kernel/CMakeLists.txt | 62 +
drivers/infiniband/hw/hiroce5/kernel/Makefile | 543 ++++
.../hw/hiroce5/kernel/base/cq/roce_cq.h | 230 ++
.../hiroce5/kernel/base/cq/roce_cq_common.c | 299 ++
.../hw/hiroce5/kernel/base/cq/roce_cq_cqe.c | 763 ++++++
.../hiroce5/kernel/base/cq/roce_cq_create.c | 636 +++++
.../hw/hiroce5/kernel/base/cq/roce_cq_ctrl.c | 964 +++++++
.../hiroce5/kernel/base/cq/roce_cq_destroy.c | 304 +++
.../hiroce5/kernel/base/cq/roce_cq_format.h | 29 +
.../hiroce5/kernel/base/cq/roce_cq_intern.c | 98 +
.../hiroce5/kernel/base/cq/roce_cq_intern.h | 24 +
.../hw/hiroce5/kernel/base/event/roce_event.c | 437 +++
.../hw/hiroce5/kernel/base/event/roce_event.h | 25 +
.../base/extension/roce_event_extension.c | 56 +
.../base/extension/roce_main_extension.c | 170 ++
.../kernel/base/extension/roce_mr_extension.c | 40 +
.../kernel/base/extension/roce_qp_extension.c | 222 ++
.../base/extension/roce_srq_extension.c | 55 +
.../hw/hiroce5/kernel/base/mr/roce_mr.c | 1281 +++++++++
.../hw/hiroce5/kernel/base/mr/roce_mr.h | 113 +
.../hw/hiroce5/kernel/base/qp/roce_post.h | 171 ++
.../hw/hiroce5/kernel/base/qp/roce_qp.h | 317 +++
.../hiroce5/kernel/base/qp/roce_qp_create.c | 1506 +++++++++++
.../kernel/base/qp/roce_qp_ctx_format.h | 278 ++
.../hiroce5/kernel/base/qp/roce_qp_destroy.c | 342 +++
.../hw/hiroce5/kernel/base/qp/roce_qp_exp.h | 80 +
.../hw/hiroce5/kernel/base/qp/roce_qp_ext.c | 39 +
.../hw/hiroce5/kernel/base/qp/roce_qp_ext.h | 19 +
.../hw/hiroce5/kernel/base/qp/roce_qp_inner.h | 17 +
.../hiroce5/kernel/base/qp/roce_qp_modify.c | 2398 +++++++++++++++++
.../kernel/base/qp/roce_qp_post_recv.c | 238 ++
.../kernel/base/qp/roce_qp_post_send.c | 1205 +++++++++
.../hw/hiroce5/kernel/base/qp/roce_qp_query.c | 543 ++++
.../hw/hiroce5/kernel/base/rdma/rdma_comp.c | 22 +
.../hw/hiroce5/kernel/base/rdma/rdma_comp.h | 166 ++
.../hiroce5/kernel/base/rdma/rdma_comp_gid.c | 489 ++++
.../hiroce5/kernel/base/rdma/rdma_comp_init.c | 443 +++
.../kernel/base/rdma/rdma_comp_mw_mr.c | 120 +
.../kernel/base/rdma/rdma_comp_mw_mr.h | 12 +
.../hiroce5/kernel/base/rdma/rdma_comp_pd.c | 51 +
.../hiroce5/kernel/base/rdma/rdma_comp_res.c | 140 +
.../hw/hiroce5/kernel/base/rdma/roce_com.h | 78 +
.../hw/hiroce5/kernel/base/rdma/roce_mix.c | 1594 +++++++++++
.../hw/hiroce5/kernel/base/rdma/roce_mix.h | 269 ++
.../hw/hiroce5/kernel/base/rdma/roce_pd.c | 138 +
.../hw/hiroce5/kernel/base/rdma/roce_pd.h | 15 +
.../hw/hiroce5/kernel/base/srq/roce_srq.h | 191 ++
.../hiroce5/kernel/base/srq/roce_srq_comm.c | 116 +
.../hiroce5/kernel/base/srq/roce_srq_create.c | 712 +++++
.../hiroce5/kernel/base/srq/roce_srq_ctrl.c | 635 +++++
.../hiroce5/kernel/base/srq/roce_srq_format.h | 36 +
.../hw/hiroce5/kernel/base/uld/roce_uld_api.c | 729 +++++
.../hiroce5/kernel/base/uld/roce_uld_inner.h | 77 +
.../hw/hiroce5/kernel/base/xrc/roce_xrc.c | 169 ++
.../hw/hiroce5/kernel/base/xrc/roce_xrc.h | 17 +
.../hw/hiroce5/kernel/dev/card/roce_card.c | 162 ++
.../hw/hiroce5/kernel/dev/card/roce_card.h | 27 +
.../hw/hiroce5/kernel/dev/cmd/roce_cmd.c | 1270 +++++++++
.../hw/hiroce5/kernel/dev/cmd/roce_cmd.h | 82 +
.../hw/hiroce5/kernel/dev/db/roce_db.c | 86 +
.../hw/hiroce5/kernel/dev/db/roce_db.h | 30 +
.../hw/hiroce5/kernel/dev/init/roce_main.c | 1701 ++++++++++++
.../hiroce5/kernel/dev/netdev/roce_netdev.c | 1082 ++++++++
.../hiroce5/kernel/dev/netdev/roce_netdev.h | 70 +
.../hiroce5/kernel/dev/netlink/roce_netlink.c | 413 +++
.../hiroce5/kernel/dev/netlink/roce_netlink.h | 53 +
.../kernel/dev/netlink/roce_netlink_process.c | 832 ++++++
.../kernel/dev/netlink/roce_netlink_process.h | 133 +
.../hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.c | 74 +
.../hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.h | 21 +
.../kernel/dev/sysfs/roce_multipath_sysfs.c | 240 ++
.../kernel/dev/sysfs/roce_multipath_sysfs.h | 30 +
.../hw/hiroce5/kernel/dev/sysfs/roce_sysfs.c | 2157 +++++++++++++++
.../hw/hiroce5/kernel/dev/sysfs/roce_sysfs.h | 241 ++
.../hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.c | 472 ++++
.../hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.h | 73 +
.../extern/chip_ext/roce_main_chip_ext.c | 13 +
.../extern/chip_ext/roce_main_chip_ext.h | 17 +
.../kernel/extern/chip_ext/roce_mr_chip_ext.c | 348 +++
.../kernel/extern/chip_ext/roce_mr_chip_ext.h | 24 +
.../kernel/extern/chip_ext/roce_qp_chip_ext.c | 44 +
.../extern/chip_ext/roce_srq_chip_ext.c | 26 +
.../extern/hyper_roce/hyper_roce_common.h | 13 +
.../extern/hyper_roce/hyper_roce_netlink.c | 511 ++++
.../extern/hyper_roce/hyper_roce_netlink.h | 82 +
.../kernel/extern/hyper_roce/hyper_roce_qp.c | 29 +
.../kernel/extern/hyper_roce/hyper_roce_qp.h | 35 +
.../extern/hyper_roce/tool/hyper_roce_tool.c | 60 +
.../extern/hyper_roce/tool/hyper_roce_tool.h | 21 +
.../hyper_roce/tool/hyper_roce_tool_pktdrop.c | 142 +
.../hyper_roce/tool/hyper_roce_tool_pktdrop.h | 23 +
.../hw/hiroce5/kernel/include/roce.h | 665 +++++
.../hw/hiroce5/kernel/include/roce_compat.h | 87 +
.../kernel/include/roce_event_extension.h | 17 +
.../hw/hiroce5/kernel/include/roce_gid.h | 48 +
.../hw/hiroce5/kernel/include/roce_infra.h | 77 +
.../kernel/include/roce_kernel_compat_gen.h | 6 +
.../kernel/include/roce_main_extension.h | 77 +
.../kernel/include/roce_mr_extension.h | 14 +
.../hiroce5/kernel/include/roce_os_compat.h | 237 ++
.../kernel/include/roce_qp_extension.h | 61 +
.../hw/hiroce5/kernel/include/roce_restore.h | 88 +
.../kernel/include/roce_srq_extension.h | 38 +
.../hw/hiroce5/kernel/include/roce_user.h | 100 +
.../kernel/include/roce_verbs_compat.h | 24 +
.../hw/hiroce5/kernel/util/bond/roce_bond.h | 79 +
.../hiroce5/kernel/util/bond/roce_bond_cfm.c | 490 ++++
.../kernel/util/bond/roce_bond_device.c | 490 ++++
.../kernel/util/bond/roce_bond_internal.h | 97 +
.../hiroce5/kernel/util/bond/roce_bond_mac.c | 260 ++
.../kernel/util/bond/roce_bond_slave.c | 459 ++++
.../hiroce5/kernel/util/bond/roce_bond_tx.c | 94 +
.../hw/hiroce5/kernel/util/debug/roce_debug.h | 25 +
.../hw/hiroce5/kernel/util/dfx/roce_dfx.c | 375 +++
.../hw/hiroce5/kernel/util/dfx/roce_dfx.h | 378 +++
.../hiroce5/kernel/util/dfx/roce_dfx_attack.c | 828 ++++++
.../hiroce5/kernel/util/dfx/roce_dfx_debug.c | 35 +
.../hiroce5/kernel/util/dfx/roce_dfx_query.c | 851 ++++++
.../kernel/util/obj_ext/roce_obj_ext.c | 83 +
.../kernel/util/obj_ext/roce_obj_ext.h | 40 +
.../hiroce5/kernel/util/option/roce_option.c | 125 +
.../hiroce5/kernel/util/option/roce_option.h | 30 +
123 files changed, 36652 insertions(+)
create mode 100644 drivers/infiniband/hw/hiroce5/drv_intf/roce_drv_msg_intf.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/CMakeLists.txt
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/Makefile
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_common.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_cqe.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_create.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_ctrl.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_destroy.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_format.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_intern.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_intern.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/event/roce_event.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/event/roce_event.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_event_extension.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_main_extension.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_mr_extension.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_qp_extension.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_srq_extension.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/mr/roce_mr.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/mr/roce_mr.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_post.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_create.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ctx_format.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_destroy.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_exp.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ext.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ext.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_inner.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_modify.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_post_recv.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_post_send.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_query.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_gid.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_init.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_mw_mr.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_mw_mr.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_pd.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_res.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_com.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_mix.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_mix.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_pd.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_pd.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_comm.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_create.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_ctrl.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_format.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/uld/roce_uld_api.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/uld/roce_uld_inner.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/xrc/roce_xrc.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/base/xrc/roce_xrc.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/card/roce_card.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/card/roce_card.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/cmd/roce_cmd.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/cmd/roce_cmd.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/db/roce_db.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/db/roce_db.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/init/roce_main.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/netdev/roce_netdev.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/netdev/roce_netdev.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink_process.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink_process.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_multipath_sysfs.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_multipath_sysfs.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_sysfs.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_sysfs.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_main_chip_ext.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_main_chip_ext.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_mr_chip_ext.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_mr_chip_ext.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_qp_chip_ext.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_srq_chip_ext.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_common.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_netlink.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_netlink.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_qp.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_qp.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool_pktdrop.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool_pktdrop.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_compat.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_event_extension.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_gid.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_infra.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_kernel_compat_gen.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_main_extension.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_mr_extension.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_os_compat.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_qp_extension.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_restore.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_srq_extension.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_user.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/include/roce_verbs_compat.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_cfm.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_device.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_internal.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_mac.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_slave.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_tx.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/debug/roce_debug.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_attack.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_debug.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_query.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/obj_ext/roce_obj_ext.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/obj_ext/roce_obj_ext.h
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/option/roce_option.c
create mode 100644 drivers/infiniband/hw/hiroce5/kernel/util/option/roce_option.h
diff --git a/drivers/infiniband/hw/hiroce5/drv_intf/roce_drv_msg_intf.h b/drivers/infiniband/hw/hiroce5/drv_intf/roce_drv_msg_intf.h
new file mode 100644
index 000000000..4875a1f1a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/drv_intf/roce_drv_msg_intf.h
@@ -0,0 +1,14 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
+
+#ifndef ROCE_DRV_MSG_INTF_H
+#define ROCE_DRV_MSG_INTF_H
+
+#include "udk_usrnl.h"
+
+typedef struct {
+ usrnl_drv_msg_hdr_s common_hdr;
+ unsigned long long card_id;
+} roce5_drv_msg_hdr_s;
+
+#endif /* ROCE_DRV_MSG_INTF_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/CMakeLists.txt b/drivers/infiniband/hw/hiroce5/kernel/CMakeLists.txt
new file mode 100644
index 000000000..e67756615
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/CMakeLists.txt
@@ -0,0 +1,62 @@
+option(ENABLE_DEBUG "Enable debug in RoCE kernel driver" OFF)
+option(ENABLE_HYPER_ROCE "Enable hyper roce" OFF)
+
+if("${BUILD_VERSION}" MATCHES "_debug$")
+ set(ENABLE_DEBUG ON)
+endif()
+
+# ubx kernel hyper_roce使能宏
+if (DEFINED ENV{build_roce_mode})
+ if ($ENV{build_roce_mode} STREQUAL "hyperroce")
+ set(ENABLE_HYPER_ROCE ON)
+ endif()
+endif()
+
+if("${BUILD_VERSION}" MATCHES "ub_ascend")
+ set(UMMU_CORE_BUILD_DIR ${UBUS_BUILD_DIR}/kernel/ummu-core-v1)
+elseif("${PRODUCT}" STREQUAL "ascend910D" OR "${PRODUCT}" STREQUAL "ascend910Desl")
+ set(UBUS_DIR ${TOP_DIR}/drivers/ubus)
+ set(KDIR ${KERNEL_WORK_DIR}/../linux-4.19)
+ set(UMMU_CORE_BUILD_DIR ${UBUS_DIR}/kernel/ummu-core-v1)
+else()
+ set(UMMU_CORE_BUILD_DIR ${UBUS_BUILD_DIR}/kernel/ummu-core)
+endif()
+
+set(UBUS_UBC_BUILD_DIR ${UBUS_BUILD_DIR}/kernel/ubus)
+set(HISDK5_BUILD_DIR ${BUILD_CACHE_TOP_DIR}/cmake/ChipSolution/src/dpu_platform_library/host/sdk/knldk/lld)
+set(HINIC5_BUILD_DIR ${BUILD_CACHE_TOP_DIR}/cmake/ChipSolution/src/dpu_platform_library/host/service/nic/linux)
+set(HIROCE5_BUILD_DIR ${BUILD_CACHE_TOP_DIR}/cmake/ChipSolution/src/dpu_platform_library/host/service/roce/linux/kernel)
+
+if("${PRODUCT}" STREQUAL "ascend910D" OR "${PRODUCT}" STREQUAL "ascend910Desl")
+ set(hiroce5_depends hisdk hinic)
+ add_device_ko(LOCAL_MODULE hiroce5
+ KO_SRC_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}
+ MAKE_ARGS "IS_ASCEND=true"
+ TARGETE_DPENDS "${hiroce5_depends}")
+else()
+ add_custom_target(hiroce5_ko
+ COMMENT echo "build ${CMAKE_CURRENT_SOURCE_DIR} start."
+ COMMAND cp -f ${CMAKE_CURRENT_SOURCE_DIR}/Makefile ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${MAKE} -j64
+ -C ${KDIR}
+ M=${CMAKE_CURRENT_BINARY_DIR}
+ src=${CMAKE_CURRENT_SOURCE_DIR}
+ UBUS_UBC_BUILD_DIR=${UBUS_UBC_BUILD_DIR}
+ HI1823_TRUNK_DIR=${TOP_DIR}/ChipSolution
+ HI1823_BUILD_DIR=${TOP_DIR}/ChipSolution/build
+ CONFIG_UBUS_DEVICE=y
+ HI1823_OS_TYPE=openEuler24.03
+ VERBOSE=1
+ HISDK5_SYMVERS=${HISDK5_BUILD_DIR}/Module.symvers
+ HINIC5_SYMVERS=${HINIC5_BUILD_DIR}/Module.symvers
+ CHIP_VERSION=hi1825v100
+ VERSION=ROCE_STANDARD
+ ENABLE_DEBUG=${ENABLE_DEBUG}
+ ENABLE_HYPER_ROCE=${ENABLE_HYPER_ROCE}
+ COMMAND cp -f *.ko ${CMAKE_INSTALL_PREFIX}/ko
+ DEPENDS kernel
+ )
+ add_dependencies(hiroce5_ko hisdk5_ko)
+ add_dependencies(hiroce5_ko hinic5_ko)
+ add_dependencies(hiroce5_ko ubus_ko)
+endif()
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/Makefile b/drivers/infiniband/hw/hiroce5/kernel/Makefile
new file mode 100644
index 000000000..0527b1b8a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/Makefile
@@ -0,0 +1,543 @@
+ifeq ($(KERNELRELEASE), )
+
+.PHONY: all kernel install_kernel install clean clean_kernel
+
+CWD=$(shell pwd)
+TOP_DIR=$(CWD)/../../../../../../..
+INSTALL_MOD_PATH=$(TOP_DIR)/ci/bin
+
+KERN_VERSION=$(shell uname -r)
+KSRC=/lib/modules/$(shell uname -r)/build
+ifeq ($(CONFIG_UB_UNIFIED_UBUS), y)
+ KERN_VERSION ?= 6.6.0-132.0.0.111.oe2403sp3.aarch64
+ KSRC=${UBUS_BUILD_KERNEL_DIR}
+endif
+
+ENABLE_DEBUG ?= OFF
+ENABLE_HYPER_ROCE ?= ON
+
+PANGEA_EULER_2107=4.19.90-vhulk2107.1.0.h699.eulerosv2r10.aarch64
+PANGEA_EULER_2108=4.19.90-vhulk2108.6.0.h832.eulerosv2r10.aarch64
+PANGEA_EULER_2202=4.19.90-vhulk2202.2.0.h1064.eulerosv2r10.aarch64
+EULER_V2R12_H1032=5.10.0-136.12.0.86.h1032.eulerosv2r12.x86_64
+EULER_V2R12_ARM_H1032=5.10.0-136.12.0.86.h1032.eulerosv2r12.aarch64
+EULER_V2R12_ARM_H1258=5.10.0-136.12.0.86.h1258.eulerosv2r12.aarch64
+EULER_V2R11_X86=5.10.0-60.18.0.50.h509.eulerosv2r11.x86_64
+EULER_V2R11_ARM=5.10.0-60.18.0.50.h665.eulerosv2r11.aarch64
+HCE_2_ARM_R865_35=5.10.0-60.18.0.50.r865_35.hce2.aarch64
+HCE_2_ARM_R1526_92=5.10.0-136.12.0.86.r1526_92.hce2.aarch64
+HCE_3_ARM_R1040_72=6.6.0-72.0.0.76.r1040_72.hce3.aarch64
+HCE_3_ARM_R1245_84=6.6.0-72.0.0.76.r1245_84.hce3.aarch64
+OPEN_EULER_153_2203_ARM=5.10.0-153.12.0.92.oe2203sp2.aarch64
+OPEN_EULER_136_2203_ARM=5.10.0-136.12.0.86.oe2203sp1.aarch64
+OPEN_EULER_2403_X86=6.6.0-28.0.0.34.oe2403.x86_64
+OPEN_EULER_2403_ARM=6.6.0-28.0.0.34.oe2403.aarch64
+OPEN_EULER_2403_SP1_ARM=6.6.0-72.0.0.76.oe2403sp1.aarch64
+OPEN_EULER_2403_SP2_ARM=6.6.0-98.0.0.103.oe2403sp2.aarch64
+OPEN_EULER_2403_SP3_ARM=6.6.0-132.0.0.111.oe2403sp3.aarch64
+EULER_V2R9_ARM=4.19.90-vhulk2009.2.0.h310.eulerosv2r9.aarch64
+
+OS_NAME := $(shell grep -E '^NAME=' /etc/os-release | cut -d= -f2 | tr -d '"')
+OS_VERSION_ID := $(shell grep -E '^VERSION_ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
+OS_VERSION := $(shell grep -E '^VERSION=' /etc/os-release | cut -d= -f2 | tr -d '"')
+
+KBUILD_EXTRA_SYMBOLS+=$(TOP_DIR)/ci/lib/SDK_Module.symvers
+KBUILD_EXTRA_SYMBOLS+=$(TOP_DIR)/ci/lib/NIC_Module.symvers
+
+# Set CFLAGS based on public macro definations
+CFLAGS += -DHW_CONVERT_ENDIAN
+CFLAGS += -DROCE_SERVICE
+CFLAGS += -DROCE_DRIVER_COMPILE
+CFLAGS += -D__ROCE_DFX__
+CFLAGS += -DROCE_CC_EN
+CFLAGS += -DRDMA_ROCE_MODULE
+CFLAGS += $(HI1823_FLAGS)
+CFLAGS += -Werror -Wall
+CFLAGS += -DROCE_DWQE_EN
+
+# Set CFLAGS, KBUILD_EXTRA_SYMBOLS and other THIRDPARTY* variables
+# from OS and kernel version information
+ifeq ($(OFED_VERSION), MLNX_OFED)
+ THIRDPARTY = /opt/buildtools/mlnx-ofa_kernel-5.8
+ KBUILD_EXTRA_SYMBOLS+=/opt/buildtools/mlnx-ofa_kernel-5.8/Module.symvers
+else ifeq ($(KERN_VERSION),$(filter $(KERN_VERSION), $(PANGEA_EULER_2107) $(PANGEA_EULER_2108) $(PANGEA_EULER_2202)))
+ KBUILD_EXTRA_SYMBOLS += $(TOP_DIR)/pangea/output/aarch64/euleros/ofed_knl/include/Module.symvers
+ THIRDPARTY_INC = $(TOP_DIR)/pangea/output/aarch64/euleros/ofed_knl/
+ CFLAGS += -DCONFIG_INFINIBAND_USER_MEM
+ CFLAGS += -DHAVE_GET_USER_PAGES_GUP_FLAGS
+ CFLAGS += -DCONFIG_MODULE_UPGRADE
+ CFLAGS += -DCONFIG_NVMF_AA
+else ifeq ($(KERN_VERSION),$(filter $(KERN_VERSION), $(EULER_V2R12_H1032) $(EULER_V2R12_ARM_H1032) $(EULER_V2R12_ARM_H1258) \
+ $(EULER_V2R11_ARM) $(OPEN_EULER_153_2203_ARM) $(HCE_2_ARM_R865_35) $(HCE_2_ARM_R1526_92) $(OPEN_EULER_136_2203_ARM) \
+ $(EULER_V2R9_ARM) $(OPEN_EULER_2403_X86) $(OPEN_EULER_2403_ARM) $(OPEN_EULER_2403_SP1_ARM) $(OPEN_EULER_2403_SP2_ARM) $(OPEN_EULER_2403_SP3_ARM) \
+ $(HCE_3_ARM_R1040_72) $(HCE_3_ARM_R1245_84)))
+ THIRDPARTY_INC = /usr/src/kernels/$(KERN_VERSION)/include
+else ifeq ($(OS_NAME),openEuler)
+ ifeq ($(OS_VERSION_ID),24.03)
+ ifneq (,$(findstring SP4,$(OS_VERSION)))
+ THIRDPARTY_INC = /usr/src/kernels/$(KERN_VERSION)/include
+ endif
+ endif
+else ifeq ($(KERN_VERSION), $(filter $(KERN_VERSION), $(EULER_V2R11_X86)))
+ THIRDPARTY =/usr/src/compat-rdma-4.17
+ KBUILD_EXTRA_SYMBOLS+=/usr/src/compat-rdma/Module.symvers
+ THIRDPARTY_INC = /usr/src/compat-rdma
+else
+ ifeq ($(CROSS_COMPILE),)
+ THIRDPARTY =/usr/src/compat-rdma-4.17
+ KBUILD_EXTRA_SYMBOLS+=/usr/src/compat-rdma/Module.symvers
+ THIRDPARTY_INC = /usr/src/compat-rdma
+# centos compat 417 need 6 para
+ CFLAGS += -DHAVE_NLA_PARSE_6_PARAMS
+ else
+ THIRDPARTY =/arm/cross_compile/install/sysroot/usr/src/compat-rdma-4.8
+ KBUILD_EXTRA_SYMBOLS+=/arm/cross_compile/install/sysroot/usr/src/compat-rdma/Module.symvers
+ THIRDPARTY_INC = /arm/cross_compile/install/sysroot/usr/src/compat-rdma
+ endif
+endif
+
+# Set CFLAGS from compiled driver version
+ifeq ($(VERSION),ROCE_STANDARD)
+ CFLAGS += -DROCE_STANDARD
+ CFLAGS += -DROCE_BONDING_EN
+ CFLAGS += -DSIGN_MTT_EN
+ CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/bond
+ CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/bond
+ CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/include/cfm/bond
+ # CFLAGS += -DROCE_LATENCY_PROF_EN #
时延统计工具,需手动开启
+else ifeq ($(VERSION),ROCE_VBS)
+ CFLAGS += -DROCE_STANDARD
+ CFLAGS += -DROCE_BONDING_EN
+ CFLAGS += -DSIGN_MTT_EN
+ CFLAGS += -DROCE_VBS_EN
+ CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/bond
+ CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/bond
+ CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/include/cfm/bond
+ CFLAGS += -I$(TOP_DIR)/test/at_test/host/service/vbs/extend/roce_kernel/
+else ifeq ($(VERSION),CHIP_TEST)
+ CFLAGS += -DROCE_CHIP_TEST
+ CFLAGS += -DSIGN_MTT_EN
+ CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/extern/chip_ext
+else ifeq ($(VERSION),ROCE_COMPUTE)
+ CFLAGS += -DROCE_STANDARD
+ CFLAGS += -DROCE_COMPUTE
+else ifeq ($(VERSION),ROCE_VROCE)
+ CFLAGS += -DROCE_VROCE_EN
+ CFLAGS += -I$(TOP_DIR)/src/dpu_extended_library/host/service/roce/linux/kernel/extern/vroce/include
+endif
+
+ifeq ($(ENABLE_DEBUG),ON)
+ CFLAGS += -DENABLE_DEBUG
+endif
+
+ifeq ($(ENABLE_HYPER_ROCE),ON)
+ CFLAGS += -DENABLE_HYPER_ROCE
+ CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/extern/hyper_roce
+ CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/extern/hyper_roce/tool
+ CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/sdk/knldk/cqm
+endif
+
+# Set CFLAGS from default file directories
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/rdma
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/include/drv_fw_msg/roce
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/include/drv_fw_msg/roce/hi182x
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/rdma/hi182x
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/cfm
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/include
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/drv_intf
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/cq
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/event
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/mr
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/qp
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/rdma
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/srq
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/xrc
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/uld
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/card
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/cmd
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/db
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/netdev
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/netlink
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/sdk_api
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/sysfs
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/include
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/dfx
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/option
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/debug
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/obj_ext
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/drv_cfm_intf/hmm
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/cfm/hmm
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/drv_sdk_intf/urts
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/drv_sdk_intf/hisdk
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/include/sdk/knldk
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/sdk/knldk/crm
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/sdk/knldk/include
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/host/cfm/rdma
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/drv_srvc_intf
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/ccp
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/public
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/cfg_mgmt
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/mpu
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/nic
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/drv_srvc_intf/nic
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/mag
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/include
+CFLAGS += -I$(TOP_DIR)/src/dpu_platform_library/include/drv_tool_msg
+CFLAGS += -I$(TOP_DIR)/platform/huawei_secure_c/include
+CFLAGS += -I$(TOP_DIR)/platform/huawei_secure_c/src
+CFLAGS += -I$(TOP_DIR)/src/dpu_develop_interface/drv_srvc_intf/roce
+CFLAGS += -DSECUREC_EXPORT_KERNEL_SYMBOL=0
+
+##Safe compilation options
+ifneq ($(HI1823_OS_TYPE), BCLINUX)
+ CFLAGS += -fstack-protector-all -Wl,-z,noexecstack
+endif
+
+# Set CFLAGS from Driver version info,
+# Currently not in use.
+CFLAGS += -D HIROCE5_DRV_VER=\"$(HIROCE5_DRV_VERSION)\"
+
+export KERN_VERSION
+export KBUILD_EXTRA_SYMBOLS
+
+DEPMOD = /sbin/depmod
+INSTALL_MOD_DIR ?= $(shell test -f /etc/redhat-release && echo extra/ofa_kernel || echo updates)
+
+##Define compilation target
+all: kernel
+
+install: install_kernel
+install_kernel: install_modules
+
+##Test whether there are autoconf.h, kconfig.h files in the kernel directory, and if so, refer to the header file later
+autoconf_h=$(shell /bin/ls -1 $(KSRC)/include/*/autoconf.h 2> /dev/null | head -1)
+kconfig_h=$(shell /bin/ls -1 $(KSRC)/include/*/kconfig.h 2> /dev/null | head -1)
+
+ifneq ($(kconfig_h),)
+ KCONFIG_H = -include $(kconfig_h)
+endif
+
+##Test whether V variable is defined. If so, "make" will print some information during subsequent compilation
+V ?= 0
+
+##KBUILD_NOCMDDEP=1, when "make" again after "make", it will not recompile
+##LINUXINCLUDE, reconfigure kernel module compilation options
+##__OFED_BUILD__, use macro definition configured by OFED instead of that configured by kernel
+
+linux_include := -include $(autoconf_h) \
+ $(KCONFIG_H) \
+ $(BACKPORT_INCLUDES) \
+ -I$(THIRDPARTY)/include \
+ -I$(THIRDPARTY)/include/uapi \
+ $$(if $$(CONFIG_XEN),-I$$(srctree)/arch/x86/include/mach-xen) \
+ $$(if $$(CONFIG_XEN),-D__XEN_INTERFACE_VERSION__=$$(CONFIG_XEN_INTERFACE_VERSION)) \
+ -I$$(srctree)/arch/$$(SRCARCH)/include \
+ -I$$(srctree)/arch/$$(SRCARCH)/include/uapi \
+ -Iarch/$$(SRCARCH)/include/generated \
+ -Iarch/$$(SRCARCH)/include/generated/uapi \
+ -Iinclude \
+ $$(if $$(KBUILD_SRC),-Iinclude2 -I$$(srctree)/include) \
+ -I$$(srctree)/include/uapi \
+ -I$$(srctree)/arch/$$(SRCARCH)/include \
+ -Iinclude/generated/uapi \
+ -Iarch/$$(SRCARCH)/include/generated
+
+#########################
+# make kernel #
+#########################
+#NB: The LINUXINCLUDE value comes from main kernel Makefile
+# with local directories prepended. This eventually affects
+# CPPFLAGS in the kernel Makefile
+kernel: $(COMPAT_CONFIG) $(COMPAT_AUTOCONF)
+ @echo '============== INFO =============='
+ @echo 'Building kernel modules'
+ @echo 'Driver Version: $(VERSION)'
+ @echo 'Kernel Version: $(KERN_VERSION)'
+ @echo 'Modules Directory: $(INSTALL_MOD_PATH)/$(MODULES_DIR)'
+ @echo 'Kernel Sources: $(KSRC)'
+ @echo 'Thirdparty Source: $(THIRDPARTY)'
+ @echo 'Thirdparty Symbols: $(KBUILD_EXTRA_SYMBOLS)'
+ @echo 'TOP_DIR: $(TOP_DIR)'
+ @echo 'HI1823_TRUNK_DIR: $(HI1823_TRUNK_DIR)'
+ @echo '=================================='
+ $(MAKE) -C $(KSRC) M="$(CWD)" V=$(V) KBUILD_NOCMDDEP=1 $(WITH_MAKE_PARAMS) EXTRA_CFLAGS="$(CFLAGS)" \
+ LINUXINCLUDE='$(linux_include)' ENABLE_DEBUG=$(ENABLE_DEBUG) ENABLE_HYPER_ROCE=$(ENABLE_HYPER_ROCE) modules
+
+#########################
+# Install kernel #
+#########################
+install_modules:
+ @echo "Installing kernel modules"
+
+ $(MAKE) -C $(KSRC) M="$(CWD)" \
+ INSTALL_MOD_PATH=$(INSTALL_MOD_PATH) \
+ INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \
+ $(WITH_MAKE_PARAMS) modules_install;
+ if [ ! -n "$(INSTALL_MOD_PATH)" ]; then $(DEPMOD) $(KERN_VERSION);fi;
+
+clean: clean_kernel
+
+clean_kernel:
+ @echo "clean kernel modules"
+ $(MAKE) -C $(KSRC) M="$(CWD)" $(WITH_MAKE_PARAMS) clean
+ @/bin/rm -f $(clean-files)
+
+clean-files := Module.symvers modules.order Module.markers compat/modules.order
+clean-files += $(COMPAT_CONFIG) $(COMPAT_AUTOCONF)
+
+help:
+ @echo
+ @echo "kernel: build kernel modules"
+ @echo "all: build kernel modules"
+ @echo
+ @echo "install_kernel: install kernel modules under $(INSTALL_MOD_PATH)/$(MODULES_DIR)"
+ @echo "install: run install_kernel"
+ @echo
+ @echo "clean: delete kernel modules binaries"
+ @echo "clean_kernel: delete kernel modules binaries"
+ @echo
+
+else
+
+obj-m += hiroce5.o
+
+ENABLE_DEBUG ?= OFF
+$(info kernel ENABLE_DEBUG: $(ENABLE_DEBUG))
+
+ifeq ($(CONFIG_UBUS_DEVICE), y)
+TOP_DIR=$(HI1823_TRUNK_DIR)
+
+GLOBAL_VERSION=$(shell cat $(HI1823_TRUNK_DIR)/src/GLOBAL_VERSION_NEW | grep driver | awk -F ':' '{print $$2}')
+ccflags-y += -DGLOBAL_VERSION_STR=\"$(GLOBAL_VERSION)\"
+ccflags-y += -DHW_CONVERT_ENDIAN
+ccflags-y += -DROCE_SERVICE
+ccflags-y += -DROCE_DRIVER_COMPILE
+ccflags-y += -D__ROCE_DFX__
+ccflags-y += -DROCE_CC_EN
+ccflags-y += -DRDMA_ROCE_MODULE
+ccflags-y += $(HI1823_FLAGS)
+# ccflags-y += -Werror -Wall
+ccflags-y += -Wall
+ccflags-y += -DROCE_DWQE_EN
+
+KBUILD_EXTRA_SYMBOLS += $(HISDK5_SYMVERS)
+KBUILD_EXTRA_SYMBOLS += $(HINIC5_SYMVERS)
+# ccflags-y = /usr/src/kernels/$(KERN_VERSION)/include
+
+ccflags-y += -DROCE_STANDARD
+ccflags-y += -DROCE_BONDING_EN
+ccflags-y += -DSIGN_MTT_EN
+
+ifeq ($(ENABLE_DEBUG),ON)
+ ccflags-y += -DENABLE_DEBUG
+endif
+ifeq ($(ENABLE_HYPER_ROCE),ON)
+ ccflags-y += -DENABLE_HYPER_ROCE
+ ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/extern/hyper_roce
+ ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/extern/hyper_roce/tool
+ ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/sdk/knldk/cqm
+endif
+
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/bond
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/bond
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/include/cfm/bond
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/rdma
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/include/drv_fw_msg/roce
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/include/drv_fw_msg/roce/hi182x
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/rdma/hi182x
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/cfm
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/include
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/drv_intf
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/cq
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/event
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/mr
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/qp
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/rdma
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/srq
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/xrc
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/base/uld
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/card
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/cmd
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/db
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/netdev
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/netlink
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/sdk_api
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/dev/sysfs
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/include
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/dfx
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/option
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/debug
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/service/roce/linux/kernel/util/obj_ext
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/drv_cfm_intf/hmm
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/cfm/hmm
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/drv_sdk_intf/urts
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/include/hwsdk
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/include/
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/cfm/rdma
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/drv_sdk_intf/hisdk
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/sdk/knldk/crm
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/sdk/knldk/include
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/include/sdk/knldk
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/ccp
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/public
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/cfg_mgmt
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/mpu
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/nic
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/drv_srvc_intf
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/drv_srvc_intf/nic
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/drv_srvc_intf/roce
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface/fw_msg_intf/mag
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/include
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/include/drv_tool_msg
+ccflags-y += -I$(TOP_DIR)/platform/huawei_secure_c/include
+ccflags-y += -I$(TOP_DIR)/platform/huawei_secure_c/src
+ccflags-y += -I$(TOP_DIR)/src/dpu_platform_library/host/knldk/rdma
+ccflags-y += -I$(TOP_DIR)/..//opensource/openeuler/kernel/olk-6.6/include/linux/
+ccflags-y += -I$(TOP_DIR)/src/dpu_develop_interface
+ccflags-y += -I$(TOP_DIR)/../opensource/openeuler/kernel/olk-6.6/include
+ccflags-y += -nostdinc
+endif
+
+# List files of release here.
+ccflags-y += -DSECUREC_EXPORT_KERNEL_SYMBOL=0
+hiroce5-y := ../../../../../../../platform/huawei_secure_c/src/securecutil.o \
+ ../../../../../../../platform/huawei_secure_c/src/secureinput_a.o \
+ ../../../../../../../platform/huawei_secure_c/src/secureprintoutput_a.o \
+ ../../../../../../../platform/huawei_secure_c/src/memset_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/memcpy_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/strncpy_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/strncat_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/sprintf_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/vsprintf_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/vsnprintf_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/snprintf_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/vsscanf_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/sscanf_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/memmove_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/strcpy_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/strcat_s.o \
+ ../../../../../../../platform/huawei_secure_c/src/strtok_s.o \
+ ../../../../cfm/hmm/hmm_buddy.o \
+ ../../../../cfm/hmm/hmm_common.o \
+ ../../../../cfm/hmm/hmm_em.o \
+ ../../../../cfm/hmm/hmm_init.o \
+ ../../../../cfm/hmm/hmm_mpt.o \
+ ../../../../cfm/hmm/hmm_mr.o \
+ ../../../../cfm/hmm/hmm_mtt.o \
+ ../../../../cfm/hmm/hmm_umem.o \
+ ../../../../cfm/rdma/rdma_bitmap.o \
+ base/cq/roce_cq_common.o \
+ base/cq/roce_cq_cqe.o \
+ base/cq/roce_cq_create.o \
+ base/cq/roce_cq_ctrl.o \
+ base/cq/roce_cq_destroy.o \
+ base/cq/roce_cq_intern.o \
+ base/extension/roce_event_extension.o \
+ base/extension/roce_main_extension.o \
+ base/extension/roce_mr_extension.o \
+ base/extension/roce_qp_extension.o \
+ base/extension/roce_srq_extension.o \
+ base/mr/roce_mr.o \
+ base/qp/roce_qp_create.o \
+ base/qp/roce_qp_destroy.o \
+ base/qp/roce_qp_ext.o \
+ base/qp/roce_qp_modify.o \
+ base/qp/roce_qp_post_recv.o \
+ base/qp/roce_qp_post_send.o \
+ base/qp/roce_qp_query.o \
+ base/rdma/rdma_comp.o \
+ base/rdma/rdma_comp_res.o \
+ base/rdma/rdma_comp_gid.o \
+ base/rdma/rdma_comp_init.o \
+ base/rdma/rdma_comp_pd.o \
+ base/rdma/rdma_comp_mw_mr.o \
+ base/rdma/roce_pd.o \
+ base/rdma/roce_mix.o \
+ base/srq/roce_srq_comm.o \
+ base/srq/roce_srq_create.o \
+ base/srq/roce_srq_ctrl.o \
+ base/xrc/roce_xrc.o \
+ base/event/roce_event.o \
+ base/uld/roce_uld_api.o \
+ dev/card/roce_card.o \
+ dev/db/roce_db.o \
+ dev/cmd/roce_cmd.o \
+ dev/init/roce_main.o \
+ dev/netdev/roce_netdev.o \
+ dev/netlink/roce_netlink_process.o \
+ dev/netlink/roce_netlink.o \
+ dev/sdk_api/roce_cqm_cmd.o \
+ dev/sysfs/roce_sysfs.o \
+ dev/sysfs/roce_ucc_sysfs.o \
+ dev/sysfs/roce_multipath_sysfs.o \
+ util/dfx/roce_dfx.o \
+ util/dfx/roce_dfx_query.o \
+ util/option/roce_option.o \
+ util/obj_ext/roce_obj_ext.o
+
+ifeq ($(ENABLE_DEBUG),ON)
+ # List debug files here.
+ hiroce5-y += util/dfx/roce_dfx_debug.o
+ hiroce5-y += util/dfx/roce_dfx_attack.o
+endif
+
+ifeq ($(ENABLE_HYPER_ROCE),ON)
+ # List hyper roce files here.
+ hiroce5-y += extern/hyper_roce/hyper_roce_netlink.o
+ hiroce5-y += extern/hyper_roce/hyper_roce_qp.o
+ hiroce5-y += extern/hyper_roce/tool/hyper_roce_tool.o
+ hiroce5-y += extern/hyper_roce/tool/hyper_roce_tool_pktdrop.o
+endif
+
+# Add hiroce5 objects from compiled driver version
+# from dpu_extended_library directories
+ifeq ($(VERSION),ROCE_STANDARD)
+ hiroce5-y +=util/bond/roce_bond_mac.o
+ hiroce5-y +=util/bond/roce_bond_slave.o
+ hiroce5-y +=util/bond/roce_bond_cfm.o
+ hiroce5-y +=util/bond/roce_bond_device.o
+ hiroce5-y +=util/bond/roce_bond_tx.o
+else ifeq ($(VERSION),ROCE_COMPUTE)
+ # hiroce5-y +=util/bond/roce_bond_common.o
+else ifeq ($(VERSION),CHIP_TEST)
+# CHIP_TEST or ROCE_VBS, as VBS driver currently runs on chip test
+ hiroce5-y +=extern/chip_ext/roce_main_chip_ext.o
+ hiroce5-y +=extern/chip_ext/roce_mr_chip_ext.o
+ hiroce5-y +=extern/chip_ext/roce_qp_chip_ext.o
+ hiroce5-y +=extern/chip_ext/roce_srq_chip_ext.o
+else ifeq ($(VERSION),ROCE_VROCE)
+ hiroce5-y +=util/bond/roce_bond_mac.o
+ hiroce5-y +=util/bond/roce_bond_slave.o
+ hiroce5-y +=util/bond/roce_bond_cfm.o
+ hiroce5-y +=util/bond/roce_bond_device.o
+ hiroce5-y +=util/bond/roce_bond_tx.o
+ hiroce5-y +=../../../../../../../src/dpu_extended_library/host/roce/vroce/roce_cmd_ext.o
+else ifeq ($(VERSION),ROCE_VBS)
+ hiroce5-y +=util/bond/roce_bond_mac.o
+ hiroce5-y +=util/bond/roce_bond_slave.o
+ hiroce5-y +=util/bond/roce_bond_cfm.o
+ hiroce5-y +=util/bond/roce_bond_device.o
+ hiroce5-y +=util/bond/roce_bond_tx.o
+ hiroce5-y +=../../../../../../../test/at_test/host/service/vbs/extend/roce_kernel/roce_vbs_qp.o
+endif
+
+# Driver Extension
+# DPU_HIROCE5_DRV_EXTEND_MK, DPU_DRV_MK_DIR, DPU_DRV_HIROCE5_EXTEND_OBJS对外提供用户使用,修改需要评审
+ifneq ($(DPU_HIROCE5_DRV_EXTEND_MK),)
+ $(info Using roce extension $(DPU_HIROCE5_DRV_EXTEND_MK))
+ export DPU_DRV_MK_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+ include $(DPU_HIROCE5_DRV_EXTEND_MK)
+ hiroce5-y += $(DPU_DRV_HIROCE5_EXTEND_OBJS)
+endif
+
+build_info:
+ mkdir -p build
+ @echo "CURDIR=$(CURDIR)" > build/build_src.txt
+ @for obj in $(hiroce5-y); do \
+ echo $$(realpath $$obj) >> build/build_src.txt; \
+ done
+
+endif
+
+include $(HI1823_BUILD_DIR)/host/linux/Makefile.ko
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq.h b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq.h
new file mode 100644
index 000000000..37562da9c
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq.h
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_CQ_H
+#define ROCE_CQ_H
+
+#include <rdma/ib_verbs.h>
+#include <linux/slab.h>
+
+#include "hinic5_hw.h"
+#include "hinic5_rdma.h"
+
+#include "roce.h"
+#include "roce_srq.h"
+
+#include "roce_option.h"
+#include "hinic5_hmm.h"
+
+#include "securec.h"
+
+/* DB type of ARM_CQ */
+enum { ROCE_CQ_DB_REQ_NOT_SOL = 1, ROCE_CQ_DB_REQ_NOT = 2 };
+
+#define CQ_DW_TO_BYTE 4
+#define ROCE_CQE_UP_THRESHOLD 1024
+
+/*
+1.Same type of operation as SQ WQE
+8'h00-Send
+8'h01-Send with Invalidate
+8'h02-Send with Immediate Data
+8'h03-reserved
+
+8'h04-RDMA Write
+8'h05-RDMA Write with Immediate Data
+8'h06-reserved
+8'h07-reserved
+
+8'h08-RDMA Read
+8'h09-reserved
+8'h0a-reserved
+8'h0b-reserved
+
+8'h0c-Atomic Compare & Swap
+8'h0d-Atomic Fetch & Add
+8'h0e-Atomic Masked Compare & Swap (Extended Atomic operation)
+8'h0f-Atomic Masked Fetch & Add (Extended Atomic operation)
+
+8'h10-Fast Register PMR
+8'h11-Local Invalidate
+8'h12-Bind Memory Window Type1/2
+8'h13-Local opreation(Extended for further local opreation)
+other-Reserved
+
+2.Receive
+00000 - RDMA Write with Immediate
+00001 - Send
+00010 - Send with Immediate
+00011 - Send & Invalidate
+
+3.The following are general
+11110 Error coding
+10110 Resize coding
+*/
+enum roce5_cqe_send_opcode {
+ ROCE_OPCODE_SEND = 0x0,
+ ROCE_OPCODE_SEND_WITH_INV = 0x1,
+ ROCE_OPCODE_SEND_WITH_IMM = 0x2,
+ /* 0x3 reserved */
+
+ ROCE_OPCODE_RDMA_WRITE = 0x4,
+ ROCE_OPCODE_RDMA_WRITE_WITH_IMM = 0x5,
+ /* 0x6 and 0x7 reserved */
+
+ ROCE_OPCODE_RDMA_READ = 0x8,
+ /* 0x9~0xb reserved */
+
+ ROCE_OPCODE_ATOMIC_COMP_AND_SWP = 0xc,
+ ROCE_OPCODE_ATOMIC_FETCH_AND_ADD = 0xd,
+ ROCE_OPCODE_ATOMIC_MASKED_COMP_AND_SWP = 0xe,
+ ROCE_OPCODE_ATOMIC_MASKED_FETCH_AND_ADD = 0xf,
+
+ ROCE_OPCODE_FAST_REG_PMR = 0x10,
+ ROCE_OPCODE_LOCAL_INV = 0x11,
+ ROCE_OPCODE_BIND_TYPE2_MW = 0x12,
+ ROCE_OPCODE_REG_SIG_MR = 0x13,
+
+ ROCE_OPCODE_RESIZE_CQE = 0x16,
+ ROCE_OPCODE_ERR = 0x1e,
+ ROCE_OPCODE_CQE_UNUSED = 0x1f /* Be used in new CQ buf when reszie cq */
+};
+
+enum roce5_cqe_recv_opcode {
+ ROCE_RECV_OPCODE_RDMA_WRITE_WITH_IMM = 0x0,
+ ROCE_RECV_OPCODE_SEND = 0x1,
+ ROCE_RECV_OPCODE_SEND_WITH_IMM = 0x2,
+ ROCE_RECV_OPCODE_SEND_WITH_INV = 0x3
+};
+
+/* Define the state type of the CQ */
+enum cq_state {
+ ROCE_CQ_STATE_INVALID = 0x0,
+ ROCE_CQ_STATE_ERR = 0x1,
+ ROCE_CQ_STATE_OVERFLOW = 0x2,
+ ROCE_CQ_STATE_VALID = 0xf,
+ ROCE_CQ_STATE_MEM_INIT = 0xa /* Initial value of Host Memory */
+};
+
+#define ROCE_CQ_TIME_OUT_CHECK_VALUE 0xe
+#define ROCE_CQ_STATE_CHECK_VALUE 0x0
+
+#define ROCE_CQE_RQ_INLINE 1
+#define ROCE_CQE_RQ_NORMAL 0
+#define ROCE_CQE_SEND_COMP 1
+#define ROCE_CQE_RECV_COMP 0
+
+#define ATOMIC_DATA_LEN 8 /* Specified as 8B by protocol */
+
+#define ROCE_CQE_INVALID_VALUE 0xff
+#define ROCE_CQ_RESIZE_POLL_TIMES 100
+
+/* roce Commands, bufs and data structures related to cq */
+struct roce5_cq_buf {
+ struct tag_cqm_buf *buf; /* pointer to describe the buf structure b cqm */
+ struct mtt
+ mtt; /* the mtt struct used by kernel mode and user mode to discribe buf */
+ int entry_size; /* the size of cqe */
+ int buf_size; /* the size of cq_buf */
+};
+
+struct roce5_cq_resize_buf {
+ struct roce5_cq_buf buf; /* the size of buf that was resized */
+ int cqe; /* the number of resized cqe */
+};
+
+#define ROCE_RCQ_ULD_DEF_LEN 64
+#define ROCE_RCQ_MAGIC 0x5a5ae0e0
+struct roce5_rcq_uld_def {
+ u8 uld_def[ROCE_RCQ_ULD_DEF_LEN];
+};
+
+struct roce5_cq {
+ struct ib_cq ibcq;
+ cqm_queue_s *cqm_cq; /* Save the handle obtained from cqm */
+ struct roce5_db
+ db; /* The address information of the software DB that stores the CI user mode/kernel mode */
+ __be32 *set_ci_db; /* Kernel-mode software DB */
+ u32 cons_index; /* consumer pointer */
+
+ u32 arm_sn; /* the serial number of arm */
+ int arm_flag; /* Used to determine whether the arm command has been sent, to avoid repeated sending */
+ u32 cqn;
+ unsigned int vector; /* associated to the eq used */
+ struct roce5_cq_buf buf; /* pointer describing the buf structure of cqm */
+ struct roce5_cq_resize_buf *resize_buf; /* resize buf struction */
+
+ spinlock_t lock; /* Need to lock when operating cq */
+ struct mutex resize_mutex; /* resize the mutex of cq */
+ struct ib_umem *umem; /* record the infomation mapped by User-mode buf */
+ struct ib_umem *
+ resize_umem; /* record the infomation mapped by buf which the User-mode resized */
+
+ struct list_head send_qp_list; /* send queue qp */
+ struct list_head recv_qp_list; /* receive queue qp */
+
+ int reset_notify_added;
+ struct list_head reset_notify;
+ u32 cqe_mask; /* mask of the cq size */
+
+ /*
+ * 'left_num' and 'wqebb_index' are only valid in the merged CQE within the RQ.
+ * 'left_num' records the remaining count of the last merged CQE.
+ * 'wqebb_index' records the wqebb index of the current CQE.
+ */
+ u32 left_num;
+ u32 wqebb_index;
+ struct roce5_option *opt;
+ u8 shadow;
+ u32 shadow_vfid;
+
+ void (*reset_flow_comp)(struct roce5_cq *);
+
+ struct roce5_rcq_uld_def
+ uld_def; /* must placed at cq_magic before, preventstop uld access memory stomping, support up to 64B space */
+ u32 rcq_magic;
+};
+
+/* Used when destroy QP */
+void roce5_cq_clean(struct roce5_cq *cq, u32 qpn, struct roce5_srq *srq);
+void roce5_cq_async_event(struct roce5_device *rdev, struct roce5_cq *cq,
+ int type);
+void roce5_cq_clean_process(struct roce5_cq *cq, u32 qpn,
+ struct roce5_srq *srq);
+void roce5_cq_put_umem(struct roce5_device *rdev, struct roce5_cq_buf *buf,
+ struct ib_umem **umem, u8 shadow_cq);
+int roce5_create_cq_common(struct ib_device *ibdev,
+ const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata, struct roce5_cq *rcq,
+ u32 index);
+int roce5_cq_get_umem(struct roce5_device *rdev, struct ib_ucontext *context,
+ struct roce5_cq *rcq, u64 buf_addr, int cqe,
+ bool is_resize);
+void *roce5_get_sw_cqe(struct roce5_cq *cq, unsigned int n);
+void *roce5_get_cqe_from_buf(struct roce5_cq_buf *buf, unsigned int n);
+void roce5_cq_set_ci(struct roce5_cq *cq);
+void roce5_cq_buf_init(struct roce5_cq_buf *buf);
+void *roce5_get_cqe(struct roce5_cq *cq, unsigned int n);
+void roce5_reset_flow_comp(struct roce5_cq *rcq);
+
+void roce5_lock_cqs(struct roce5_cq *roce5_send_cq,
+ struct roce5_cq *roce5_recv_cq)
+ __acquires(&roce5_send_cq->lock) __acquires(&roce5_recv_cq->lock);
+void roce5_unlock_cqs(struct roce5_cq *roce5_send_cq,
+ struct roce5_cq *roce5_recv_cq)
+ __releases(&roce5_send_cq->lock) __releases(&roce5_recv_cq->lock);
+
+struct roce5_cq *roce5_get_rcq_by_cqn(struct roce5_device *rdev, u32 cqn);
+void roce5_cq_completion(void *svc_hd, u32 cqn, void *cq_handler);
+
+static inline void roce5_rcq_put(struct roce5_cq *rcq)
+{
+ if (rcq == NULL) {
+ return;
+ }
+ roce5_option_put_value(rcq->opt);
+ cqm5_object_put(&rcq->cqm_cq->object);
+}
+
+#endif // ROCE_CQ_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_common.c b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_common.c
new file mode 100644
index 000000000..f212acecc
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_common.c
@@ -0,0 +1,299 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/slab.h>
+
+#include "hinic5_hw.h"
+
+#include "roce.h"
+#include "roce_srq.h"
+#include "roce_qp.h"
+#include "roce_mix.h"
+#include "roce_xrc.h"
+#include "roce_user.h"
+#include "roce_cq.h"
+#include "roce_xqe_format.h"
+#include "roce_option.h"
+#include "hinic5_hmm.h"
+#include "securec.h"
+#include "roce_os_compat.h"
+#include "roce_aeq_format.h"
+
+/* ****************************************************************************
+ Prototype : roce5_cq_async_event
+ Description : roce5_cq_async_event
+ Input : struct roce5_device *rdev
+ struct roce5_cq *cq
+ int type
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_cq_async_event(struct roce5_device *rdev, struct roce5_cq *cq,
+ int type)
+{
+ struct ib_cq *ibcq = &cq->ibcq;
+ struct ib_event event;
+ int ret;
+
+ ret = memset_s(&event, sizeof(event), 0, sizeof(event));
+ if (ret != 0) {
+ ROCE_DEV_ERR_LIMIT(rdev, "Failed to memset event.(ret:%d)",
+ ret);
+ }
+ if (type != ROCE_EVENT_TYPE_CQ_ERROR) {
+ ROCE_DEV_WARN_LIMIT(
+ rdev,
+ "Unexpected event type(0x%x) on CQ(%06x), func_id(%d)",
+ type, cq->cqn, rdev->glb_func_id);
+ return;
+ }
+
+ if (ibcq->event_handler) {
+ event.device = ibcq->device;
+ event.event = IB_EVENT_CQ_ERR;
+ event.element.cq = ibcq;
+ ibcq->event_handler(&event, ibcq->cq_context);
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_buf_init
+ Description : roce5_cq_buf_init
+ Input : struct roce5_cq_buf *buf
+ Output : None
+
+ 1.Date : 2015/11/9
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_cq_buf_init(struct roce5_cq_buf *buf)
+{
+ /* optype was initialized into ROCE_OPCODE_CQE_UNUSED(0x1f) */
+ int ret;
+ ret = memset_s(buf->buf->direct.va,
+ (unsigned long)((unsigned)buf->buf_size),
+ ROCE_CQE_INVALID_VALUE,
+ (unsigned long)((unsigned)buf->buf_size));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset va.(ret:%d)", ret);
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_put_umem
+ Description : Release umem and corresponding mtt, corresponding to put
+ Input : struct roce5_device *rdev
+ struct roce5_cq_buf *buf
+ struct ib_umem **umem
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_cq_put_umem(struct roce5_device *rdev, struct roce5_cq_buf *buf,
+ struct ib_umem **umem, u8 shadow_cq)
+{
+ if (shadow_cq != 0) {
+ return;
+ }
+ /* free MTT of Buffer */
+ hmm_mtt_free(rdev->hwdev, &buf->mtt, SERVICE_T_ROCE);
+
+ /* release umem */
+ ib_umem_release(*umem);
+}
+
+static void *roce5_cq_buf_offset(struct tag_cqm_buf *buf, unsigned int offset)
+{
+ return (void *)((char *)buf->direct.va + offset);
+}
+
+void *roce5_get_cqe_from_buf(struct roce5_cq_buf *buf, unsigned int n)
+{
+ return roce5_cq_buf_offset(buf->buf, (n * buf->entry_size));
+}
+
+void *roce5_get_cqe(struct roce5_cq *cq, unsigned int n)
+{
+ return roce5_get_cqe_from_buf(&cq->buf, n);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_get_sw_cqe
+ Description : roce5_get_sw_cqe
+ Input : struct roce5_cq *cq
+ unsigned int n
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+void *roce5_get_sw_cqe(struct roce5_cq *cq, unsigned int n)
+{
+ struct roce_cqe *cqe = NULL;
+ struct roce_cqe tmp_cqe;
+ unsigned int tmp_val;
+
+ cqe = (struct roce_cqe *)roce5_get_cqe(
+ cq, (n & ((unsigned int)cq->cqe_mask)));
+ if (cqe == NULL) {
+ ROCE_ERR("Get sw cqe failed.");
+ return NULL;
+ }
+ tmp_cqe.dw0.value = roce5_convert_cpu32(cqe->dw0.value);
+ tmp_cqe.dw1.value = roce5_convert_cpu32(cqe->dw1.value);
+
+ /* Add judgment condition: the optype of CQE cannot be UNUSED, UNUSED means that it has been initialized in resize
+ cq */
+ tmp_val = ((n & ((unsigned int)cq->ibcq.cqe + ROCE_CQE_UP_THRESHOLD)) ==
+ 0) ?
+ 1 :
+ 0;
+ if ((ROCE_LIKELY(tmp_cqe.dw1.bs.op_type != ROCE_OPCODE_CQE_UNUSED)) &&
+ ((tmp_cqe.dw0.bs.owner ^ tmp_val) != 0)) {
+ return cqe;
+ }
+
+ return NULL;
+}
+
+int roce5_cq_get_umem(struct roce5_device *rdev, struct ib_ucontext *context,
+ struct roce5_cq *rcq, u64 buf_addr, int cqe,
+ bool is_resize)
+{
+ int ret = 0;
+ u32 npages = 0;
+ int page_shift = 0;
+ int cqe_size = (int)rdev->rdma_cap.cqe_size;
+ struct roce5_cq_buf *buf = NULL;
+ struct ib_umem **umem = NULL;
+
+ if (rcq->shadow != 0) {
+ return 0;
+ }
+ if (is_resize) {
+ buf = &rcq->resize_buf->buf;
+ umem = &rcq->resize_umem;
+ } else {
+ buf = &rcq->buf;
+ umem = &rcq->umem;
+ }
+
+ *umem = roce5_umem_get(&rdev->ib_dev, context, buf_addr,
+ (unsigned long)(cqe * cqe_size),
+ IB_ACCESS_LOCAL_WRITE, 1);
+ if (IS_ERR(*umem)) {
+ ROCE_DEV_ERR(rdev, "Failed to get ib_umem, func_id(%d)",
+ rdev->glb_func_id);
+ return (int)PTR_ERR(*umem);
+ }
+
+ page_shift = (int)roce5_umem_get_buf_page_shift(rdev, *umem, buf_addr);
+ npages = roce5_umem_get_mtt_npages(rdev, *umem, page_shift);
+
+ buf->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_mtt_alloc(rdev->hwdev, npages, (u32)page_shift, &buf->mtt,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc rdma_mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_buf;
+ }
+
+ ret = roce5_umem_write_mtt(rdev, &buf->mtt, *umem, true);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write mtt for umem, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_mtt;
+ }
+
+ return 0;
+
+err_mtt:
+ hmm_mtt_free(rdev->hwdev, &buf->mtt, SERVICE_T_ROCE);
+
+err_buf:
+ ib_umem_release(*umem);
+
+ return ret;
+}
+
+void roce5_reset_flow_comp(struct roce5_cq *rcq)
+{
+ struct ib_cq *ibcq = &rcq->ibcq;
+
+ ibcq->comp_handler(ibcq, ibcq->cq_context);
+}
+
+/**
+ * @brief Get roce cq by cqn. When querying succeeded, you have to call roce5_rcq_put() to free
+ the cqm_obj and opt. But there is no need to call roce5_rcq_put() if querying failed.
+ * @return Success: return the roce cq. Failure: return NULL.
+ */
+struct roce5_cq *roce5_get_rcq_by_cqn(struct roce5_device *rdev, u32 cqn)
+{
+ cqm_object_s *cqm_obj = NULL;
+ cqm_queue_s *cqm_queue = NULL;
+ struct roce5_option *opt = NULL;
+ struct roce5_cq *rcq = NULL;
+
+ cqm_obj = cqm5_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SCQ, cqn, false);
+ if (cqm_obj == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Can't find rcq according to cqn(0x%x), func_id(%d)",
+ cqn, rdev->glb_func_id);
+ goto err_out;
+ }
+
+ cqm_queue = container_of(cqm_obj, cqm_queue_s, object);
+ opt = (struct roce5_option *)cqm_queue->priv;
+ if (opt == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to get option, priv ptr is NULL.");
+ goto err_out_cqm_put;
+ }
+
+ rcq = (struct roce5_cq *)roce5_option_get_value(opt);
+ if (rcq == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to get rcq from option.");
+ goto err_out_cqm_put;
+ }
+
+ return rcq;
+
+err_out_cqm_put:
+ cqm5_object_put(cqm_obj);
+err_out:
+ return NULL;
+}
+
+void roce5_cq_completion(void *svc_hd, u32 cqn, void *cq_handler)
+{
+ struct roce5_option *opt = NULL;
+ struct roce5_cq *rcq = NULL;
+
+ if (cq_handler == NULL) {
+ ROCE_ERR("Cq_handler is null");
+ return;
+ }
+
+ opt = (struct roce5_option *)cq_handler;
+ rcq = (struct roce5_cq *)roce5_option_get_value(opt);
+ if (rcq == NULL) {
+ ROCE_WARN("Failed to get rcq from option.");
+ return;
+ }
+
+ ++rcq->arm_sn;
+ rcq->arm_flag = 0;
+
+ rcq->ibcq.comp_handler(&rcq->ibcq, rcq->ibcq.cq_context);
+
+ roce5_option_put_value(opt);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_cqe.c b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_cqe.c
new file mode 100644
index 000000000..b79aad2dc
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_cqe.c
@@ -0,0 +1,763 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/slab.h>
+
+#include "hinic5_hw.h"
+#include "securec.h"
+
+#include "roce.h"
+#include "roce_srq.h"
+#include "roce_qp.h"
+#include "roce_mix.h"
+#include "roce_xrc.h"
+#include "roce_cq.h"
+#include "roce_restore.h"
+#include "roce_aeq_format.h"
+#include "roce_xqe_format.h"
+
+#include "roce_main_extension.h"
+
+/* ****************************************************************************
+ Prototype : roce5_next_cqe_sw
+ Description : roce5_next_cqe_sw
+ Input : struct roce5_cq *cq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static struct roce_cqe *roce5_next_cqe_sw(struct roce5_cq *cq)
+{
+ return (struct roce_cqe *)roce5_get_sw_cqe(cq, cq->cons_index);
+}
+
+static int g_error_cqe_to_wc[ROCE_COMPLETE_EVENT_MAX] = {
+ [ROCE_COMPLETE_EVENT_LOC_LEN_ERR] = IB_WC_LOC_LEN_ERR,
+ [ROCE_COMPLETE_EVENT_LOC_QP_OPERATION_ERR] = IB_WC_LOC_QP_OP_ERR,
+ [ROCE_COMPLETE_EVENT_LOC_PROTECTION_ERR] = IB_WC_LOC_PROT_ERR,
+ [ROCE_COMPLETE_EVENT_WR_FLUSH_ERR] = IB_WC_WR_FLUSH_ERR,
+
+ [ROCE_COMPLETE_EVENT_MW_BIND_ERR] = IB_WC_MW_BIND_ERR,
+ [ROCE_COMPLETE_EVENT_BAD_RESP_ERR] = IB_WC_BAD_RESP_ERR,
+
+ [ROCE_COMPLETE_EVENT_LOC_ACCESS_ERR] = IB_WC_LOC_ACCESS_ERR,
+ [ROCE_COMPLETE_EVENT_REM_INV_REQ_ERR] = IB_WC_REM_INV_REQ_ERR,
+ [ROCE_COMPLETE_EVENT_REM_ACCESS_ERR] = IB_WC_REM_ACCESS_ERR,
+ [ROCE_COMPLETE_EVENT_REM_OPERATION_ERR] = IB_WC_REM_OP_ERR,
+ [ROCE_COMPLETE_EVENT_RETRY_CTR_EXCEED_ERR] = IB_WC_RETRY_EXC_ERR,
+
+ [ROCE_COMPLETE_EVENT_RNR_RETRY_CTR_EXCEED_ERR] =
+ IB_WC_RNR_RETRY_EXC_ERR,
+
+ [ROCE_COMPLETE_EVENT_REM_ABORTED_ERR] = IB_WC_REM_ABORT_ERR,
+ [ROCE_COMPLETE_EVENT_XRC_VIOLATION_ERR] = IB_WC_REM_INV_RD_REQ_ERR,
+};
+
+/* ****************************************************************************
+ Prototype : roce5_handle_error_cqe
+ Description : roce5_handle_error_cqe
+ Input : struct roce_err_cqe *cqe
+ struct ib_wc *wc
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_handle_error_cqe(struct roce_err_cqe *cqe, struct ib_wc *wc)
+{
+ if (cqe->dw7.bs.syndrome >= ROCE_COMPLETE_EVENT_MAX) {
+ wc->status = IB_WC_GENERAL_ERR;
+ } else if (cqe->dw7.bs.syndrome > 0) {
+ wc->status = g_error_cqe_to_wc[cqe->dw7.bs.syndrome];
+ if (wc->status == 0) {
+ wc->status = IB_WC_GENERAL_ERR;
+ }
+ }
+
+ wc->vendor_err = cqe->dw7.bs.vendor_err;
+}
+
+static void roce5_get_local_opcode_from_cqe(const struct roce_cqe *cqe,
+ struct ib_wc *wc)
+{
+ switch (cqe->dw1.bs.op_type) {
+ case ROCE_OPCODE_LOCAL_INV:
+ wc->opcode = IB_WC_LOCAL_INV;
+ break;
+ case ROCE_OPCODE_REG_SIG_MR:
+ wc->opcode = IB_WC_REG_MR;
+ break;
+
+ default:
+ ROCE_WARN("Unknown cqe optype");
+ break;
+ }
+}
+
+static void roce5_get_opcode_type_part_1(struct roce_cqe *cqe, struct ib_wc *wc)
+{
+ switch (cqe->dw1.bs.op_type) {
+ case ROCE_OPCODE_RDMA_WRITE_WITH_IMM:
+ wc->opcode = IB_WC_RDMA_WRITE;
+ wc->wc_flags = (int)((u32)wc->wc_flags | IB_WC_WITH_IMM);
+ break;
+
+ case ROCE_OPCODE_RDMA_WRITE:
+ wc->opcode = IB_WC_RDMA_WRITE;
+ break;
+
+ case ROCE_OPCODE_SEND_WITH_IMM:
+ wc->opcode = IB_WC_SEND;
+ wc->wc_flags = (int)((u32)wc->wc_flags | IB_WC_WITH_IMM);
+ break;
+
+ case ROCE_OPCODE_SEND:
+ wc->opcode = IB_WC_SEND;
+ break;
+
+ case ROCE_OPCODE_SEND_WITH_INV:
+ wc->opcode = IB_WC_SEND;
+ break;
+ default:
+ roce5_get_local_opcode_from_cqe(cqe, wc);
+ break;
+ }
+}
+
+static void roce5_get_opcode_type_part_2(struct roce_cqe *cqe, struct ib_wc *wc)
+{
+ switch (cqe->dw1.bs.op_type) {
+ case ROCE_OPCODE_RDMA_READ:
+ wc->opcode = IB_WC_RDMA_READ;
+ wc->byte_len = cqe->byte_cnt;
+ break;
+
+ case ROCE_OPCODE_ATOMIC_COMP_AND_SWP:
+ wc->opcode = IB_WC_COMP_SWAP;
+ wc->byte_len = ATOMIC_DATA_LEN;
+ break;
+
+ case ROCE_OPCODE_ATOMIC_FETCH_AND_ADD:
+ wc->opcode = IB_WC_FETCH_ADD;
+ wc->byte_len = ATOMIC_DATA_LEN;
+ break;
+
+ case ROCE_OPCODE_ATOMIC_MASKED_COMP_AND_SWP:
+ wc->opcode = IB_WC_MASKED_COMP_SWAP;
+ wc->byte_len = ATOMIC_DATA_LEN;
+ break;
+
+ case ROCE_OPCODE_ATOMIC_MASKED_FETCH_AND_ADD:
+ wc->opcode = IB_WC_MASKED_FETCH_ADD;
+ wc->byte_len = ATOMIC_DATA_LEN;
+ break;
+ case ROCE_OPCODE_FAST_REG_PMR:
+ wc->opcode = IB_WC_REG_MR;
+ break;
+
+ default:
+ roce5_get_local_opcode_from_cqe(cqe, wc);
+ break;
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_get_opcode_from_scqe
+ Description : Set the opcode/flag/byte_len of wc according to the opcode of send_cqe
+ Input : struct roce_cqe *cqe
+ struct ib_wc *wc
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_get_opcode_from_scqe(struct roce_cqe *cqe, struct ib_wc *wc)
+{
+ wc->wc_flags = 0;
+
+ if (cqe->dw1.bs.op_type < ROCE_OPCODE_RDMA_READ) {
+ roce5_get_opcode_type_part_1(cqe, wc);
+ } else {
+ roce5_get_opcode_type_part_2(cqe, wc);
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_get_opcode_from_rcqe
+ Description : Set the opcode/flag/byte_len of wc according to the opcode of send_cqe
+ Input : struct roce_cqe *cqe
+ struct ib_wc *wc
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_get_opcode_from_rcqe(struct roce_cqe *cqe, struct ib_wc *wc)
+{
+ wc->byte_len = cqe->byte_cnt;
+
+ switch (cqe->dw1.bs.op_type) {
+ case ROCE_RECV_OPCODE_RDMA_WRITE_WITH_IMM:
+ wc->opcode = IB_WC_RECV_RDMA_WITH_IMM;
+ wc->wc_flags = IB_WC_WITH_IMM;
+ /* The driver does not perform big or small endian conversion for immediate data, but the incoming CQE
+ has been converted to the CPU endian, so it needs to be converted back */
+ wc->ex.imm_data = roce5_convert_be32(cqe->imm_invalid_rkey);
+ break;
+
+ case ROCE_RECV_OPCODE_SEND_WITH_INV:
+ wc->opcode = IB_WC_RECV;
+ wc->wc_flags = IB_WC_WITH_INVALIDATE;
+ wc->ex.invalidate_rkey =
+ roce5_convert_be32(cqe->imm_invalid_rkey);
+ break;
+
+ case ROCE_RECV_OPCODE_SEND:
+ wc->opcode = IB_WC_RECV;
+ wc->wc_flags = 0;
+ break;
+
+ case ROCE_RECV_OPCODE_SEND_WITH_IMM:
+ wc->opcode = IB_WC_RECV;
+ wc->wc_flags = IB_WC_WITH_IMM;
+ /* The driver does not perform big or small endian conversion for immediate data, but the incoming CQE
+ has been converted to the CPU endian, so it needs to be converted back */
+ wc->ex.imm_data = roce5_convert_be32(cqe->imm_invalid_rkey);
+ break;
+
+ default:
+ ROCE_WARN("Not supported");
+ break;
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_poll_and_resize
+ Description : roce5_cq_poll_and_resize
+ Input : struct roce5_cq *cq
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_cq_poll_and_resize(struct roce5_device *rdev,
+ struct roce5_cq *cq)
+{
+ if (ROCE_LIKELY(cq->resize_buf != NULL)) {
+ /* Release the original Buffer of CQ */
+ cqm5_object_resize_free_old(&cq->cqm_cq->object);
+ cq->buf = cq->resize_buf->buf;
+ cq->ibcq.cqe = cq->resize_buf->cqe;
+
+ kfree(cq->resize_buf);
+ cq->resize_buf = NULL;
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_get_cur_qp
+ Description : roce5_cq_get_cur_qp
+ Input : struct roce5_cq *cq
+ struct roce5_qp **cur_qp
+ struct roce_cqe *cqe
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_cq_get_cur_qp(struct roce5_cq *cq, struct roce5_qp **cur_qp,
+ struct roce_cqe *cqe)
+{
+ struct roce5_device *rdev = to_roce5_dev(cq->ibcq.device);
+
+ if ((*cur_qp == NULL) || (cqe->dw0.bs.qpn != (u32)(*cur_qp)->qpn)) {
+ if (*cur_qp != NULL) {
+ roce5_rqp_put(*cur_qp);
+ }
+
+ *cur_qp = roce5_get_rqp_by_qpn(rdev, cqe->dw0.bs.qpn);
+ if (*cur_qp == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "CQ(%06x) with entry for unknown QPN(%06x), func_id(%d)",
+ cq->cqn, cqe->dw0.bs.qpn, rdev->glb_func_id);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_get_xrc_srq
+ Description : roce5_cq_get_xrc_srq
+ Input : struct roce5_cq *cq
+ struct roce5_srq **srq
+ struct roce_cqe *cqe
+ u32 qp_type
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_cq_get_xrc_srq(struct roce5_cq *cq, struct roce5_srq **srq,
+ struct roce_cqe *cqe, u32 qp_type)
+{
+ u32 srqn = cqe->dw6.bs.srqn_rqpn;
+ struct roce5_device *rdev = to_roce5_dev(cq->ibcq.device);
+
+ if (qp_type == IB_QPT_XRC_TGT) {
+ if (*srq != NULL) {
+ roce5_rsrq_put(*srq);
+ }
+
+ *srq = roce5_get_rsrq_by_srqn(rdev, cqe->dw6.bs.srqn_rqpn);
+ if (*srq == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "CQ(%06x) with entry for unknown SRQN(%06x), func_id(%d)",
+ cq->cqn, srqn, rdev->glb_func_id);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int roce5_poll_recv_cqe(struct roce5_cq *rcq, struct roce5_qp *cur_qp,
+ struct roce5_srq *srq, struct ib_wc *wc)
+{
+ u32 wqe_ctr = rcq->wqebb_index;
+ unsigned int tail = 0;
+ struct roce5_srq *srq_tmp = NULL;
+
+ if (cur_qp->ibqp.srq) {
+ srq_tmp = to_roce5_srq(cur_qp->ibqp.srq);
+ /* Determine whether to overflow */
+ if (wqe_ctr > (int)srq_tmp->max_depth) {
+ ROCE_ERR("Get wqe index(0x%x) from cqe", wqe_ctr);
+ return -EINVAL;
+ }
+
+ wc->wr_id = srq_tmp->wrid[wqe_ctr];
+ roce5_free_srq_wqe(srq_tmp, wqe_ctr);
+ } else if (srq != NULL) {
+ /* Determine whether to overflow */
+ if (wqe_ctr > srq->max_depth) {
+ ROCE_ERR("Get wqe index(0x%x) from cqe", wqe_ctr);
+ return -EINVAL;
+ }
+
+ wc->wr_id = srq->wrid[wqe_ctr];
+ roce5_free_srq_wqe(srq, wqe_ctr);
+ } else {
+ struct roce5_wq *wq = &(cur_qp->rq);
+ tail = (u32)(wq->tail & ((unsigned int)wq->wqebb_cnt - 1));
+ wc->wr_id = wq->wrid[tail];
+ ++wq->tail;
+ }
+
+ return 0;
+}
+
+static void roce5_poll_move_tail(const struct roce5_qp *cur_qp,
+ struct roce5_wq *wq,
+ struct roce_cqe *trans_cqe)
+{
+ u16 wqe_ctr = 0;
+ if (cur_qp->sq_signal_bits == 0) {
+ wqe_ctr = trans_cqe->dw7.bs.wqe_cnt;
+ wq->tail += (u16)(wqe_ctr - (u16)wq->tail);
+ }
+}
+
+static void roce5_poll_one_get_av_info(const struct roce5_qp *cur_qp,
+ struct ib_wc *wc,
+ struct roce_cqe trans_cqe,
+ struct roce_cqe *cqe)
+{
+ int ret;
+
+ if ((cur_qp->qp_type == IB_QPT_UD) || (cur_qp->qp_type == IB_QPT_GSI)) {
+ wc->sl = trans_cqe.dw4.bs.vlan_pri;
+ wc->src_qp = trans_cqe.dw6.bs.srqn_rqpn;
+ wc->network_hdr_type = trans_cqe.dw6.bs.stp;
+ wc->smac[0] =
+ (u8)(trans_cqe.dw4.bs.smac_h >>
+ 8); /* Take the first Byte data, shift 8bit */
+ wc->smac[1] = (u8)(trans_cqe.dw4.bs.smac_h & 0xff);
+ ret = memcpy_s(&wc->smac[2], sizeof(cqe->smac_l), &cqe->smac_l,
+ sizeof(cqe->smac_l)); //2 : smac array idx
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy smac.(ret:%d)", ret);
+ }
+ wc->wc_flags = (int)((u32)wc->wc_flags | IB_WC_WITH_SMAC);
+ if (trans_cqe.dw6.bs.vlan_pre != 0) {
+ wc->vlan_id = trans_cqe.dw4.bs.vlan_id;
+ wc->wc_flags =
+ (int)((u32)wc->wc_flags | IB_WC_WITH_VLAN);
+ }
+ }
+}
+
+static int roce5_poll_one_get_qp_and_srq(struct roce5_cq *cq,
+ struct roce5_qp **cur_qp,
+ struct ib_wc *wc,
+ struct roce_cqe *trans_cqe,
+ struct roce5_srq **srq)
+{
+ int ret = 0;
+ ret = roce5_cq_get_cur_qp(cq, cur_qp, trans_cqe);
+ if (ret != 0) {
+ ROCE_ERR("Failed to get current qp");
+ return ret;
+ }
+
+ wc->qp = &((*cur_qp)->ibqp);
+
+ ret = roce5_cq_get_xrc_srq(cq, srq, trans_cqe, wc->qp->qp_type);
+ if (ret != 0) {
+ ROCE_ERR("Failed to get xrc srq");
+ return ret;
+ }
+
+ return ret;
+}
+
+static void roce5_bytes_trans(u32 *addr, int dw_num)
+{
+ u32 *dw = addr;
+ int i = 0;
+
+ for (i = 0; i < dw_num; i++) {
+ *dw = roce5_convert_cpu32(*dw);
+ dw++;
+ }
+}
+
+static int roce5_get_and_trans_cqe(struct roce5_device *rdev,
+ struct roce5_cq *cq,
+ struct roce_cqe *trans_cqe, int *is_send,
+ struct roce_cqe **cqe)
+{
+ int ret;
+
+ do {
+ *cqe = roce5_next_cqe_sw(cq);
+ if (*cqe == NULL) {
+ return -EAGAIN;
+ }
+
+ /* Later, it is necessary to perform big and small end conversion on CQE.
+ In order to avoid turning back after processing, copy a copy */
+ ret = memcpy_s((void *)trans_cqe, sizeof(struct roce_cqe),
+ (void *)*cqe, sizeof(struct roce_cqe));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy trans_cqe.(ret:%d).", ret);
+ return -ENOMEM;
+ }
+
+ /*
+ * Make sure we read CQ entry contents after we've checked the
+ * ownership bit.
+ */
+ rmb();
+
+ /* Convert the CQE into the CPU endian corresponding to the running environment */
+ roce5_bytes_trans(
+ (u32 *)(void *)trans_cqe,
+ (int)(sizeof(struct roce_cqe) / CQ_DW_TO_BYTE));
+
+ *is_send = trans_cqe->dw1.bs.s_r;
+ /* Resize CQ operation in progress */
+ if (ROCE_UNLIKELY(trans_cqe->dw1.bs.op_type ==
+ ROCE_OPCODE_RESIZE_CQE)) {
+ roce5_cq_poll_and_resize(rdev, cq);
+ }
+ } while (ROCE_UNLIKELY(trans_cqe->dw1.bs.op_type ==
+ ROCE_OPCODE_RESIZE_CQE));
+
+ return 0;
+}
+
+static void roce5_poll_send_cqe(struct roce5_qp *cur_qp,
+ struct roce_cqe *trans_cqe, struct ib_wc *wc)
+{
+ struct roce5_wq *wq = &(cur_qp->sq);
+ /* QP of type IB_SIGNAL_REQ_WR, tail needs to skip several WRs that do not generate CQE */
+ roce5_poll_move_tail(cur_qp, wq, trans_cqe);
+
+ wc->wr_id = wq->wrid[wq->tail & ((unsigned int)wq->wqebb_cnt - 1)];
+ ++wq->tail;
+
+ if (trans_cqe->dw1.bs.op_type == ROCE_OPCODE_ERR) {
+ roce5_handle_error_cqe((struct roce_err_cqe *)(void *)trans_cqe,
+ wc);
+ return;
+ }
+
+ roce5_get_opcode_from_scqe(trans_cqe, wc);
+}
+
+static void roce5_init_wc(struct roce_cqe *trans_cqe, struct ib_wc *wc)
+{
+ roce5_get_opcode_from_rcqe(trans_cqe, wc);
+ wc->wc_flags = (int)((unsigned int)wc->wc_flags | IB_WC_GRH);
+ wc->pkey_index = 0;
+ wc->vlan_id = 0xffff;
+ wc->sl = 0;
+ /* avoid cm_req_handler()->ib_lid_be16() trigger call trace */
+ wc->slid = 0;
+ return;
+}
+
+static int roce5_poll_one_cqe(struct roce5_cq *rcq, struct roce5_qp *cur_qp,
+ int is_send, struct roce_cqe *trans_cqe,
+ struct roce_cqe *cqe, struct roce5_srq *srq,
+ struct ib_wc *wc)
+{
+ int ret = 0;
+
+ wc->status = IB_WC_SUCCESS;
+ if (is_send != 0) {
+ roce5_poll_send_cqe(cur_qp, trans_cqe, wc);
+ return 0;
+ }
+
+ ret = roce5_poll_recv_cqe(rcq, cur_qp, srq, wc);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (trans_cqe->dw1.bs.op_type == ROCE_OPCODE_ERR) {
+ roce5_handle_error_cqe((struct roce_err_cqe *)(void *)trans_cqe,
+ wc);
+ return 0;
+ }
+
+ roce5_init_wc(trans_cqe, wc);
+
+ roce5_poll_one_get_av_info((cur_qp), wc, *trans_cqe, cqe);
+
+ /* Kernel mode does not support receiving inline */
+ if (trans_cqe->dw1.bs.inline_r == ROCE_CQE_RQ_INLINE) {
+ ROCE_ERR("Receive inline not supported in kernel space");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_update_cons_index(struct roce5_device *rdev,
+ struct roce5_cq *rcq,
+ struct roce_cqe *trans_cqe)
+{
+ if (trans_cqe->dw1.bs.flush_op != 0) {
+ if (trans_cqe->dw1.bs.s_r == ROCE_CQE_SEND_COMP) {
+ ROCE_DEV_ERR(rdev, "Unexpected flush operation in SQ.");
+ ++rcq->cons_index;
+ return -EBADE;
+ }
+
+ if (rcq->left_num == 0) {
+ rcq->left_num = trans_cqe->wqe_num;
+ rcq->wqebb_index = trans_cqe->dw1.bs.wqebb_cnt;
+ }
+ } else {
+ rcq->left_num = 1;
+ rcq->wqebb_index = trans_cqe->dw1.bs.wqebb_cnt;
+ }
+
+ if (rcq->left_num == 1) {
+ ++rcq->cons_index;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_poll_one
+ Description : roce5_poll_one
+ Input : struct roce5_cq *cq
+ struct roce5_qp **cur_qp
+ struct ib_wc *wc
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_poll_one(struct roce5_device *rdev, struct roce5_cq *cq,
+ struct roce5_qp **cur_qp, struct ib_wc *wc)
+{
+ int ret = 0;
+ struct roce_cqe *cqe = NULL;
+ struct roce_cqe trans_cqe;
+ struct roce5_srq *srq = NULL;
+ int is_send = 0;
+ bool need_poll = true;
+
+ while (need_poll) {
+ ret = roce5_get_and_trans_cqe(rdev, cq, &trans_cqe, &is_send,
+ &cqe);
+ if (ret != 0) {
+ goto err_out;
+ }
+
+ ret = roce5_update_cons_index(rdev, cq, &trans_cqe);
+ if (ret != 0) {
+ goto err_out;
+ }
+
+ ret = roce5_poll_one_get_qp_and_srq(cq, cur_qp, wc, &trans_cqe,
+ &srq);
+ if (ret != 0) {
+ goto err_out;
+ }
+
+ /* Poll cq exception handling, generally cq judges user state information, xrc judges wrid */
+ if ((*cur_qp) == NULL) {
+ ROCE_ERR("cur_qp is NULL when poll cq");
+ ret = -EACCES;
+ goto err_out;
+ }
+ if ((*cur_qp)->umem ||
+ ((*cur_qp)->ibqp.xrcd && srq != NULL && !(srq->wrid))) {
+ ROCE_ERR(
+ "qp(%u) create in user space , but poll cq in kernel. NOT PERMIT!",
+ (*cur_qp)->qpn);
+ ret = -EACCES;
+ goto err_out;
+ }
+
+ if (trans_cqe.dw1.bs.fake != 0) {
+ ROCE_INFO("Fake cqe go repoll.");
+ continue;
+ }
+
+ ret = roce5_poll_one_cqe(cq, *cur_qp, is_send, &trans_cqe, cqe,
+ srq, wc);
+ if (ret != 0) {
+ goto err_out;
+ }
+
+ --cq->left_num;
+ need_poll = false;
+ }
+
+err_out:
+ roce5_rsrq_put(srq);
+ return ret;
+}
+
+/* the format of cq_ci DB:the bits of ci less than 24bit */
+void roce5_cq_set_ci(struct roce5_cq *cq)
+{
+ *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff);
+}
+
+int roce5_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+ struct roce5_device *rdev = NULL;
+ struct roce5_cq *rcq = to_roce5_cq(ibcq);
+ struct roce5_qp *cur_qp = NULL;
+ unsigned long flags = 0; /* type required by kernel API */
+ int npolled = 0;
+ int ret = 0;
+
+ spin_lock_irqsave(&rcq->lock, flags);
+
+ rdev = to_roce5_dev(ibcq->device);
+
+ for (npolled = 0; npolled < num_entries; ++npolled) {
+ ret = roce5_poll_one(rdev, rcq, &cur_qp, wc + npolled);
+ if (ret != 0) {
+ break;
+ }
+ }
+
+ roce5_cq_set_ci(rcq);
+
+ spin_unlock_irqrestore(&rcq->lock, flags);
+
+ if ((ret == 0) || (ret == -EAGAIN)) {
+ ret = npolled;
+ goto err_out;
+ }
+
+err_out:
+ roce5_rqp_put(cur_qp);
+ return ret;
+}
+
+static void roce5_cq_arm(struct roce5_cq *cq, u32 cmd, void __iomem *uar_page)
+{
+ struct roce_db_cq_arm db_value;
+ int ret;
+
+ ret = memset_s(&db_value, sizeof(db_value), 0, sizeof(db_value));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset db_value.(ret:%d)", ret);
+ }
+
+ db_value.dw0.bs.type = 3;
+ db_value.dw0.bs.cos = 0; /* arm_cq don't need cos */
+ db_value.dw0.bs.cp = 1; /* 1 for cp */
+ db_value.dw0.bs.non_filter = 1;
+ db_value.dw0.bs.cqc_type = 0;
+ db_value.dw0.bs.cqn = cq->cqn;
+ db_value.dw0.value = roce5_convert_be32(db_value.dw0.value);
+
+ db_value.dw1.bs.cmd_sn = cq->arm_sn;
+ db_value.dw1.bs.cmd = cmd;
+ db_value.dw1.bs.ci = cq->cons_index;
+ db_value.dw1.value = roce5_convert_be32(db_value.dw1.value);
+
+ /*
+ * Make sure that the doorbell record in host memory is
+ * written before ringing the doorbell via PCI MMIO.
+ */
+ wmb();
+
+ roce5_write64((u32 *)(void *)&db_value, uar_page);
+}
+
+int roce5_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
+{
+ unsigned long lock_flags = 0; /* type required by kernel API */
+ struct roce5_cq *rcq = NULL;
+
+ if (CHECK_2LAYER_IS_NULL(ibcq, device)) {
+ return -EINVAL;
+ }
+
+ rcq = to_roce5_cq(ibcq);
+
+ spin_lock_irqsave(&rcq->lock, lock_flags);
+ if (rcq->arm_flag != 0) {
+ spin_unlock_irqrestore(&rcq->lock, lock_flags);
+ return 0;
+ }
+
+ rcq->arm_flag = 1;
+ spin_unlock_irqrestore(&rcq->lock, lock_flags);
+
+ /* Only 64-bit is supported, 64-bit writes are atomic, no need to lock */
+ roce5_cq_arm(rcq,
+ (((unsigned int)flags & IB_CQ_SOLICITED_MASK) ==
+ IB_CQ_SOLICITED) ?
+ ROCE_CQ_DB_REQ_NOT_SOL :
+ ROCE_CQ_DB_REQ_NOT,
+ to_roce5_dev(ibcq->device)->kernel_db_map);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_create.c b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_create.c
new file mode 100644
index 000000000..0df5d34e4
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_create.c
@@ -0,0 +1,636 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include "comm_defs.h"
+#include "roce_cq.h"
+#include "roce_npu_cmd.h"
+#include "roce_cqm_cmd.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#include "roce_os_compat.h"
+#include "roce_user.h"
+#include "roce_option.h"
+#include "roce_cq_intern.h"
+#include "roce_uld_kernel_api.h"
+#include "roce_uld_inner.h"
+
+#define ROCE_CQE_BASE_SIZE_BYTES 16
+
+/* ****************************************************************************
+ Prototype :roce5_cq_attr_assign
+ Description : Assign value to CQC
+ Input : struct roce_cq_attr *cq_attr
+ struct roce5_cq *rcq
+ int eqn
+ int page_shift
+ Output : None
+
+ 1.Date : 2019/10/13
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_cq_attr_assign(roce_verbs_cq_attr_s *cq_attr,
+ struct roce5_cq *rcq, int eqn, int page_shift)
+{
+ /* Assign value to CQ */
+ /* dw0 */
+ cq_attr->dw0.bs.size = (u32)ROCE_ILOG2(
+ (unsigned)(rcq->ibcq.cqe + ROCE_CQE_UP_THRESHOLD));
+ cq_attr->dw0.bs.page_size = (u32)page_shift;
+ cq_attr->dw0.bs.cqe_size = (u32)ROCE_ILOG2(
+ (unsigned)(rcq->buf.entry_size / ROCE_CQE_BASE_SIZE_BYTES));
+ cq_attr->dw0.bs.mtt_page_size =
+ rcq->buf.mtt.mtt_page_shift - PAGE_SHIFT_4K;
+ cq_attr->dw0.bs.tss_timer_num =
+ 7; /* 7 : The maximum number of timers supported by cq */
+ cq_attr->dw0.bs.arm_timer_en = 0;
+ cq_attr->dw0.bs.timer_mode = 0;
+ cq_attr->dw0.bs.cnt_adjust_en = 1;
+ cq_attr->dw0.bs.cnt_clear_en = 1;
+ cq_attr->dw0.bs.ci_on_chip = 0;
+ cq_attr->dw0.value = cpu_to_be32(cq_attr->dw0.value);
+
+ /* dw1 */
+ cq_attr->dw1.bs.dma_attr_idx = 0;
+ cq_attr->dw1.bs.so_ro = 0;
+ cq_attr->dw1.bs.state = ROCE_CQ_STATE_VALID;
+ cq_attr->dw1.value = cpu_to_be32(cq_attr->dw1.value);
+
+ /* dw2 */
+ cq_attr->dw2.bs.idle_max_count = 0;
+ cq_attr->dw2.bs.cqecnt_lth = 10; /* update ci threshhold: 2^10=1024 */
+ cq_attr->dw2.bs.cqecnt_rctl_en = 0;
+ cq_attr->dw2.bs.ceqe_en = 1;
+ cq_attr->dw2.bs.arm_ceqe_en = 1;
+ cq_attr->dw2.bs.ceqn = (u8)eqn;
+ cq_attr->dw2.value = cpu_to_be32(cq_attr->dw2.value);
+
+ /* dw3 */
+ cq_attr->dw3.bs.timeout =
+ 0; /* The timeout mechanism is disabled by default when CQ is created */
+ cq_attr->dw3.bs.max_cnt =
+ 0; /* The overtime mechanism is disabled by default when CQ is created */
+ cq_attr->dw3.value = cpu_to_be32(cq_attr->dw3.value);
+
+ /* dw4 - dw5 */
+ cq_attr->cqc_l0mtt_gpa = rcq->buf.mtt.mtt_paddr;
+ cq_attr->cqc_l0mtt_gpa = cpu_to_be64(cq_attr->cqc_l0mtt_gpa);
+
+ /* dw6 - dw7 */
+ cq_attr->ci_record_gpa_at_hop_num = cpu_to_be64(
+ (rcq->db.dma & (~0x3uLL)) | rcq->buf.mtt.mtt_layers);
+}
+
+static int roce5_cq_fill_create_inbuf(struct roce5_device *rdev,
+ struct roce5_cq *rcq, int vector,
+ int page_shift,
+ cqm_cmd_buf_s *cqm_cmd_inbuf)
+{
+ int eqn = 0;
+ roce_verbs_cq_attr_s *cq_attr = NULL;
+ roce_uni_cmd_create_cq_s *cq_sw2hw_inbuf = NULL;
+
+ cq_sw2hw_inbuf = (roce_uni_cmd_create_cq_s *)cqm_cmd_inbuf->buf;
+ cq_sw2hw_inbuf->com.index = cpu_to_be32(rcq->cqn);
+ cq_sw2hw_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_CQ_BITMASK));
+ if (rcq->shadow != 0) {
+ cq_sw2hw_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(
+ ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SHADOW_BITMASK));
+ cq_sw2hw_inbuf->com.dw3.bs.shadow_vfid =
+ cpu_to_be16(rcq->shadow_vfid);
+ }
+ cq_attr = &cq_sw2hw_inbuf->cq_attr;
+
+ /* Get the EQN of the CEQ based on the Vector index */
+ eqn = hinic5_vector_to_eqn(rdev->hwdev, SERVICE_T_ROCE, vector);
+ if (eqn < 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to get eqn from hinic vector, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ roce5_cq_attr_assign(cq_attr, rcq, eqn, page_shift);
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_sw2hw
+ Description : Send the cqc configuration command
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ int vector
+ int page_shift
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_cq_sw2hw(struct roce5_device *rdev, struct roce5_cq *rcq,
+ int vector, int page_shift)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_create_cq_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ ret = roce5_cq_fill_create_inbuf(rdev, rcq, vector, page_shift,
+ cqm_cmd_inbuf);
+ if (ret != 0) {
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+ }
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE, ROCE_CMD_SW2HW_CQ,
+ cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send SW2HW_CQ command, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+
+ /* CMDq times out or CMDq does not work, update the device status, notify the PCIe module to reset
+ the device through OFED */
+ if ((ret == -ETIMEDOUT) || (ret == -EPERM)) {
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+
+ ret = -1;
+ goto err_send_cmd;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ rcq->cons_index = 0;
+ rcq->arm_sn = 1;
+ rcq->arm_flag = 0;
+ rcq->vector = (u32)vector;
+
+ return 0;
+
+err_send_cmd:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_create_cq_check
+ Description : roce5_create_cq_check
+ Input : struct ib_device *ibdev
+ int entries
+ int vector
+ struct ib_ucontext *ibcontext
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_create_cq_check(struct ib_device *ibdev, int entries,
+ int vector)
+{
+ struct roce5_device *rdev = NULL;
+
+ if (ibdev == NULL) {
+ ROCE_ERR("Ibdev is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+ if ((entries < 1) || (entries > (int)rdev->rdma_cap.max_cqes)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Cqe number invalid, entries(%d), max_cqes(%d), func_id(%d)",
+ entries, (int)rdev->rdma_cap.max_cqes,
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if (vector > (int)rdev->rdma_cap.num_comp_vectors) {
+ ROCE_DEV_ERR(rdev, "Vector over range, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_check_cq_create_flags(u32 flags)
+{
+ /*
+ * It returns non-zero value for unsupported CQ
+ * create flags, otherwise it returns zero.
+ */
+ return (int)(flags & ~(IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN |
+ IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION));
+}
+
+static int roce5_cq_cqc_cfg(struct roce5_device *rdev, struct roce5_cq *rcq,
+ int vector, struct ib_udata *udata, u64 cq_buf_addr)
+{
+ int ret = 0;
+ int page_shift = (int)roce5_umem_get_buf_page_shift(rdev, rcq->umem,
+ cq_buf_addr) -
+ PAGE_SHIFT_4K;
+
+ /* configurate CQC */
+ ret = roce5_cq_sw2hw(rdev, rcq, vector, page_shift);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to handle cq sw2hw, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ /* User mode requires outgoing CQN */
+ if (ib_copy_to_udata(udata, &rcq->cqn, sizeof(u32)) != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to copy data to user space, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -EFAULT;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce5_create_user_cq(struct roce5_device *rdev, struct roce5_cq *rcq,
+ int cqe_num, const struct ib_cq_init_attr *attr,
+ struct ib_ucontext *ibcontext,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ int vector = attr->comp_vector;
+ struct roce5_create_cq_cmd ucmd = { 0 };
+ roce_user_handle_t hdl = { 0 };
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)) != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to copy from user space, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -EFAULT;
+ goto err_out;
+ }
+
+ ROCE_CONSTUCT_ULD_HDL_RCQ(&hdl, rdev, rcq, udata, &rcq->buf.mtt,
+ &rcq->db.dma, cqe_num);
+ ROCE_CONSTUCT_ULD_HDL_SHADOW(&hdl, &rcq->shadow, &rcq->shadow_vfid,
+ NULL);
+ ret = roce5_uld_cq_create((roce_uld_handle)&hdl);
+ if (ret != 0) {
+ ROCE_ERR("Failed to execute uld cq create, ret(%d)", ret);
+ goto err_out;
+ }
+ /* Entries has been decreased by one when it was input by User Mode, and it is the expected value exactly
+ after increased by one by Kernel Mode */
+ ret = roce5_cq_get_umem(rdev, ibcontext, rcq, ucmd.buf_addr, cqe_num,
+ false);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get umem, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_destroy_uld;
+ }
+
+ ret = roce5_db_map_user(to_roce5_ucontext(ibcontext),
+ (unsigned long)ucmd.db_addr, &rcq->db,
+ rcq->shadow);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to map kernel_mem to user_mem, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_free_mtt;
+ }
+
+ ret = roce5_cq_cqc_cfg(rdev, rcq, vector, udata, ucmd.buf_addr);
+ if (ret != 0) {
+ goto err_unmap_db;
+ }
+
+ return 0;
+
+err_unmap_db:
+ roce5_db_unmap_user(to_roce5_ucontext(ibcontext), &rcq->db,
+ rcq->shadow);
+
+err_free_mtt:
+ roce5_cq_put_umem(rdev, &rcq->buf, &rcq->umem, rcq->shadow);
+ rcq->umem = NULL;
+
+err_destroy_uld:
+ roce5_uld_cq_destroy((roce_uld_handle)&hdl);
+
+err_out:
+
+ return ret;
+}
+
+static void roce5_fill_rcq_info(struct roce5_cq *rcq)
+{
+ rcq->cqn = rcq->cqm_cq->index;
+ rcq->buf.buf = &rcq->cqm_cq->q_room_buf_1;
+
+ /* Initialize buf to unused */
+ roce5_cq_buf_init(&rcq->buf);
+
+ /* Software DB assignment */
+ rcq->set_ci_db = (__be32 *)(void *)(&rcq->cqm_cq->q_header_vaddr
+ ->doorbell_record);
+ *rcq->set_ci_db = 0;
+ rcq->db.db_record = (__be32 *)(void *)(&rcq->cqm_cq->q_header_vaddr
+ ->doorbell_record);
+ rcq->db.dma = rcq->cqm_cq->q_header_paddr;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_create_kernel_cq
+ Description : roce5_create_kernel_cq
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ int entries
+ int vector
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_create_kernel_cq(struct roce5_device *rdev,
+ struct roce5_cq *rcq, int entries, int vector,
+ u32 index)
+{
+ int ret = 0;
+ int page_shift = 0;
+
+ rcq->buf.buf_size = entries * (int)rdev->rdma_cap.cqe_size;
+ rcq->cqm_cq = cqm5_object_rdma_queue_create(
+ rdev->hwdev, SERVICE_T_ROCE, CQM_OBJECT_RDMA_SCQ,
+ (u32)rcq->buf.buf_size, rcq->opt, true, index, 0, 0);
+ if (rcq->cqm_cq == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create rdma_queue from cqm_object, func_id(%d), index(%d)",
+ rdev->glb_func_id, index);
+ return (-ENOMEM);
+ }
+
+ /* Buffer is obtained from room1 when the queue is just created */
+ if (rcq->cqm_cq->current_q_room != CQM_RDMA_Q_ROOM_1) {
+ ROCE_DEV_ERR(rdev, "Not use CQM_RDMA_Q_ROOM_1, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -EINVAL;
+ goto err_free_cqm_cq;
+ }
+
+ roce5_fill_rcq_info(rcq);
+
+ page_shift = ROCE_ILOG2(rcq->cqm_cq->q_room_buf_1.buf_size);
+
+ /* allocate MTT */
+ rcq->buf.mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_mtt_alloc(rdev->hwdev, rcq->buf.buf->buf_number,
+ (u32)page_shift, &rcq->buf.mtt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc rdma mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_free_cqm_cq;
+ }
+
+ /* Write the PA of the CQ Buffer to the MTT */
+ ret = roce5_buf_write_mtt(rdev, &rcq->buf.mtt, rcq->buf.buf);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write rdma mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_free_mtt;
+ }
+
+ page_shift = (int)ROCE_ILOG2(rcq->cqm_cq->q_room_buf_1.buf_size) -
+ PAGE_SHIFT_4K;
+
+ /* configurate CQC */
+ ret = roce5_cq_sw2hw(rdev, rcq, vector, page_shift);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to configure CQC, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_free_mtt;
+ }
+
+ return 0;
+
+err_free_mtt:
+ hmm_mtt_free(rdev->hwdev, &rcq->buf.mtt, SERVICE_T_ROCE);
+
+err_free_cqm_cq:
+ cqm5_object_delete(&rcq->cqm_cq->object);
+
+ return ret;
+}
+
+static int roce5_cq_depth_init(struct roce5_device *rdev, struct roce5_cq *rcq,
+ const struct ib_cq_init_attr *attr, int *cqe_num)
+{
+ u32 entries = (u32)attr->cqe;
+
+ /* The CQE queue should reserve four special CQE for the HOST CI can be updated to the CQC CI */
+ entries += ROCE_CQE_UP_THRESHOLD;
+ entries = ROCE_ROUNDUP_POW_OF_TWO(entries) & 0xffffffff;
+ /* Chip Constraints: Minimum queue depth needs to be page-aligned */
+ if ((entries * rdev->rdma_cap.cqe_size) < PAGE_SIZE) {
+ entries = (PAGE_SIZE >> ROCE_ILOG2(rdev->rdma_cap.cqe_size));
+ }
+ if (entries == 0) {
+ ROCE_DEV_ERR(rdev, "Invalid entries after align, func_id(%u)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+ rcq->cqe_mask = entries - 1;
+ /* Check if max spec is exceeded */
+ if (rdev->rdma_cap.max_cqes > UINT_MAX - ROCE_CQE_UP_THRESHOLD) {
+ ROCE_DEV_ERR(
+ rdev,
+ "max_cqes overflow detected, max_cqes(%u), func_id(%u)",
+ rdev->rdma_cap.max_cqes, rdev->glb_func_id);
+ return -EINVAL;
+ }
+ if (entries > (rdev->rdma_cap.max_cqes + ROCE_CQE_UP_THRESHOLD)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Over range after align, entries(%u), max_cqes(%u), func_id(%u)",
+ entries,
+ rdev->rdma_cap.max_cqes + ROCE_CQE_UP_THRESHOLD,
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if ((int)entries > INT_MAX) {
+ ROCE_DEV_ERR(rdev, "Bug detected: Int Overflow!");
+ return -EINVAL;
+ }
+
+ *cqe_num = (int)entries;
+ rcq->ibcq.cqe = (int)entries - ROCE_CQE_UP_THRESHOLD;
+ return 0;
+}
+
+static int roce5_do_create_cq(struct ib_device *ibdev,
+ const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata, struct roce5_cq *rcq,
+ u32 index)
+{
+ struct roce5_device *rdev = NULL;
+ struct roce5_ucontext *context = NULL;
+ int ret = 0;
+ int vector = attr->comp_vector;
+ int cqe_num = 0;
+
+ rdev = to_roce5_dev(ibdev);
+ ret = roce5_cq_depth_init(rdev, rcq, attr, &cqe_num);
+ if (ret != 0) {
+ return ret;
+ }
+
+ mutex_init(&rcq->resize_mutex);
+ spin_lock_init(&rcq->lock);
+ rcq->resize_buf = NULL;
+ rcq->resize_umem = NULL;
+ rcq->buf.entry_size = (int)rdev->rdma_cap.cqe_size;
+ rcq->rcq_magic = ROCE_RCQ_MAGIC;
+
+ rcq->opt = roce5_some(rcq);
+ if (rcq->opt == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to init some, cqn(%u).", rcq->cqn);
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&rcq->send_qp_list);
+ INIT_LIST_HEAD(&rcq->recv_qp_list);
+ if (udata != NULL) {
+ ret = roce5_create_cq_alloc_cqn(rdev, rcq, index);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm cq resource, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+ context = roce5_queue_to_ucontext((void *)(&rcq->ibcq), udata,
+ ROCE_Q_TYPE_CQ);
+ ret = roce5_create_user_cq(rdev, rcq, cqe_num, attr,
+ &context->ibucontext, udata);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to create user_cq, func_id(%d)",
+ rdev->glb_func_id);
+ cqm5_object_delete(&rcq->cqm_cq->object);
+ return ret;
+ }
+ } else {
+ ret = roce5_create_kernel_cq(rdev, rcq, cqe_num, vector, index);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to create kernel_cq, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ rcq->reset_flow_comp = roce5_reset_flow_comp;
+
+ return 0;
+}
+
+int roce5_create_cq_common(struct ib_device *ibdev,
+ const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata, struct roce5_cq *rcq,
+ u32 index)
+{
+ int ret;
+ int vector = attr->comp_vector;
+ int entries = (int)attr->cqe;
+
+ if (roce5_check_cq_create_flags(attr->flags) != 0) {
+ ROCE_ERR("Not support the cq_create flag(%x)", attr->flags);
+ return -EOPNOTSUPP;
+ }
+
+ ret = roce5_create_cq_check(ibdev, entries, vector);
+ if (ret != 0) {
+ ROCE_ERR("Failed to check cq information");
+ return ret;
+ }
+
+ return roce5_do_create_cq(ibdev, attr, udata, rcq, index);
+}
+
+int roce5_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata)
+{
+ struct roce5_cq *rcq = NULL;
+
+ if ((ibcq == NULL) || (attr == NULL)) {
+ ROCE_ERR("Input pointer is NULL");
+ return (-EINVAL);
+ }
+
+ rcq = to_roce5_cq(ibcq);
+ return roce5_create_cq_common(ibcq->device, attr, udata, rcq,
+ ROCE_CQN_INVLD);
+}
+
+struct ib_cq *roce5_create_cq_ofa(struct ib_device *ibdev,
+ const struct ib_cq_init_attr *attr,
+ struct ib_ucontext *ibcontext,
+ struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_cq *rcq = NULL;
+ struct ib_uobject uobject;
+
+ if ((ibdev == NULL) || (attr == NULL)) {
+ ROCE_ERR("ibdev or attr is NULL");
+ return ERR_PTR(-EINVAL);
+ }
+
+ uobject.context = ibcontext;
+
+ rcq = (struct roce5_cq *)kzalloc(sizeof(*rcq), GFP_KERNEL);
+ if (rcq == NULL) {
+ ret = -ENOMEM;
+ ROCE_ERR("Failed to alloc rcq");
+ goto out;
+ }
+
+ /* Unreasonable, but for code reuse, driver associate the OFED resource in advance. */
+ rcq->ibcq.device = ibdev;
+#if defined(IB_CQ_HAVE_UOBJECT)
+ rcq->ibcq.uobject = ((udata != NULL) ? &uobject : NULL);
+#endif
+ ret = roce5_create_cq(&rcq->ibcq, attr, udata);
+ if (ret != 0) {
+ kfree(rcq);
+ rcq = NULL;
+ goto out;
+ }
+
+out:
+ /* disassociate anyway */
+ if (rcq != NULL) {
+ rcq->ibcq.uobject = NULL;
+ }
+ return ((ret != 0) ? (struct ib_cq *)ERR_PTR((long)ret) : &rcq->ibcq);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_ctrl.c b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_ctrl.c
new file mode 100644
index 000000000..eaf8e22f4
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_ctrl.c
@@ -0,0 +1,964 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include "comm_defs.h"
+#include "roce_cq.h"
+#include "roce_cqm_cmd.h"
+#include "roce_npu_cmd.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#include "roce_infra.h"
+#include "roce_compat.h"
+#include "roce_os_compat.h"
+#include "roce_cqe_format.h"
+#include "roce_user.h"
+#include "roce_com.h"
+
+/* and above next is V100 adaptation data structure */
+typedef struct tag_roce_cmd_resize_cq {
+ roce_verbs_cmd_com_s com;
+
+ u32 rsvd;
+ u32 page_size; /* Size of the resize buf page. */
+ u32 log_cq_size; /* Cq depth after resize */
+ u32 mtt_layer_num; /* Number of mtt levels after resize */
+ /* DW4~5 */
+ union {
+ u64 mtt_base_addr; /* Start address of mr or mw */
+ u32 cqc_l0mtt_gpa[2];
+ };
+ u32 mtt_page_size; /* Size of the mtt page after resize. */
+ roce_xq_mtt_info_s mtt_info;
+} roce_cmd_resize_cq_s;
+
+typedef struct tag_roce_cmd_modify_cq {
+ roce_verbs_cmd_com_s com;
+ u32 max_cnt;
+ u32 timeout;
+} roce_cmd_modify_cq_s;
+
+static int roce5_uni_cmd_cq_modify(struct roce5_device *rdev,
+ struct roce5_cq *cq, u32 cnt, u32 period)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_modify_cq_s *cq_modify_inbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_modify_cq_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ cq_modify_inbuf = (roce_uni_cmd_modify_cq_s *)cqm_cmd_inbuf->buf;
+ cq_modify_inbuf->com.index = cpu_to_be32(cq->cqn);
+ cq_modify_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_CQ_BITMASK);
+ if (cq->shadow != 0) {
+ cq_modify_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(
+ ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SHADOW_BITMASK));
+ cq_modify_inbuf->com.dw3.bs.shadow_vfid =
+ cpu_to_be16(cq->shadow_vfid);
+ }
+ cq_modify_inbuf->cq_modify.max_cnt = cpu_to_be32(cnt);
+ cq_modify_inbuf->cq_modify.timeout = cpu_to_be32(period);
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_MODIFY_CQ, cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send MODIFY_CQ, cqn(0x%x), ret(%d), func_id(%hu)",
+ cq->cqn, ret, rdev->glb_func_id);
+ /* CMDq may return a positive number, so its return value cannot be used directly */
+ ret = -1;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+static int roce5_cq_modify(struct roce5_device *rdev, struct roce5_cq *cq,
+ u32 cnt, u32 period)
+{
+ if (ROCE5_SUPPORT_CQ_MODIFY_MSG_V2(rdev) != 0) {
+ return roce5_uni_cmd_cq_modify(rdev, cq, cnt, period);
+ }
+ return -EINVAL;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_modify_cq
+ Description : OFED_3_12
+ Input : struct ib_cq *ibcq
+ u16 cq_count
+ u16 cq_period
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_modify_cq(struct ib_cq *ibcq, u16 cq_count, u16 cq_period)
+{
+ int ret = 0;
+ struct roce5_cq *cq = NULL;
+ struct roce5_device *rdev = NULL;
+
+ if (ibcq == NULL) {
+ ROCE_ERR(" Ibcq is null");
+ return -EINVAL;
+ }
+
+ cq = to_roce5_cq(ibcq);
+ rdev = to_roce5_dev(ibcq->device);
+
+ ret = roce5_cq_modify(rdev, cq, cq_count, cq_period);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to modify cq, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_alloc_resize_buf
+ Description : Kernel mode applies for resize_buf, and its corresponding MTT
+ When there is an error in execution, this function ensures that all intermediate resources are released;
+ when the execution is successful, this function can confirm that all resources are acquired.
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ int entries
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_cq_alloc_resize_buf(struct roce5_device *rdev,
+ struct roce5_cq *rcq, int entries)
+{
+ int ret = 0;
+ int page_shift = 0;
+
+ if (rcq->resize_buf != NULL) {
+ ROCE_DEV_ERR(rdev, "Resize buffer is busy, func_id(%d)",
+ rdev->glb_func_id);
+ return -EBUSY;
+ }
+
+ /* Apply for resize_buf and assign it */
+ rcq->resize_buf = (struct roce5_cq_resize_buf *)kmalloc(
+ sizeof(*rcq->resize_buf), GFP_ATOMIC);
+ if (rcq->resize_buf == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc resize buffer, func_id(%d)",
+ rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ rcq->resize_buf->buf.entry_size = rcq->buf.entry_size;
+ rcq->resize_buf->buf.buf_size = entries * rcq->buf.entry_size;
+ ret = cqm5_object_resize_alloc_new(&rcq->cqm_cq->object,
+ (u32)rcq->resize_buf->buf.buf_size);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to resize cq buffer, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_resize_buf_alloc;
+ }
+
+ /* If the application is successful, record the buffer information of the new buffer */
+ rcq->resize_buf->cqe = entries - ROCE_CQE_UP_THRESHOLD;
+ rcq->resize_buf->buf.buf = &rcq->cqm_cq->q_room_buf_2;
+
+ /* Initialize new buf to unused state */
+ roce5_cq_buf_init(&rcq->resize_buf->buf);
+
+ page_shift = (int)ROCE_ILOG2(rcq->resize_buf->buf.buf->buf_size);
+
+ /* Apply MTT for resize_buf */
+ rcq->buf.mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_mtt_alloc(rdev->hwdev, rcq->resize_buf->buf.buf->buf_number,
+ (u32)page_shift, &rcq->resize_buf->buf.mtt,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc rdma mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_mtt_alloc;
+ }
+
+ /* configurate MTT, write PA of resize_buf to MTT */
+ ret = roce5_buf_write_mtt(rdev, &rcq->resize_buf->buf.mtt,
+ rcq->resize_buf->buf.buf);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write rdma mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_mtt_write;
+ }
+
+ return 0;
+
+err_mtt_write:
+ hmm_mtt_free(rdev->hwdev, &rcq->buf.mtt, SERVICE_T_ROCE);
+
+err_mtt_alloc:
+ /* free resize_buf */
+ cqm5_object_resize_free_new(&rcq->cqm_cq->object);
+
+err_resize_buf_alloc:
+ kfree(rcq->resize_buf);
+ rcq->resize_buf = NULL;
+
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_free_resize_buf
+ Description : Kernel Mode releases resize_buf and its corresponding MTT
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_cq_free_resize_buf(struct roce5_device *rdev,
+ struct roce5_cq *rcq)
+{
+ /* Release the MTT of resize_buf first */
+ hmm_mtt_free(rdev->hwdev, &(rcq->resize_buf->buf.mtt), SERVICE_T_ROCE);
+
+ /* free resize_buf */
+ cqm5_object_resize_free_new(&(rcq->cqm_cq->object));
+
+ /* free the resize_buf pointer itself */
+ kfree(rcq->resize_buf);
+ rcq->resize_buf = NULL;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_alloc_resize_umem
+ Description : User mode applies for umem of resize_buf, and MTT corresponding to user mode buf
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ int entries
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_cq_alloc_resize_umem(struct roce5_device *rdev,
+ struct roce5_cq *rcq, int entries,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_resize_cq_cmd ucmd = { 0 };
+ struct roce5_ucontext *context = roce5_queue_to_ucontext(
+ (void *)(&rcq->ibcq), udata, ROCE_Q_TYPE_CQ);
+
+ /* If a resize is being executed, it is not allowed to execute another resize at the same time */
+ if (rcq->resize_umem != NULL) {
+ ROCE_DEV_ERR(rdev, "Resize_umem is busy, func_id(%d)",
+ rdev->glb_func_id);
+ return -EBUSY;
+ }
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)) != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to copy from user space, func_id(%d)",
+ rdev->glb_func_id);
+ return -EFAULT;
+ }
+
+ rcq->resize_buf = (struct roce5_cq_resize_buf *)kmalloc(
+ sizeof(*rcq->resize_buf), GFP_ATOMIC);
+ if (rcq->resize_buf == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc cq resize buffer, func_id(%d)",
+ rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ ret = roce5_cq_get_umem(rdev, &context->ibucontext, rcq, ucmd.buf_addr,
+ entries, true);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get umem, func_id(%d)",
+ rdev->glb_func_id);
+
+ kfree(rcq->resize_buf);
+ rcq->resize_buf = NULL;
+
+ return ret;
+ }
+
+ rcq->resize_buf->buf.entry_size = rcq->buf.entry_size;
+ rcq->resize_buf->buf.buf_size = entries * rcq->buf.entry_size;
+ rcq->resize_buf->cqe = entries - ROCE_CQE_UP_THRESHOLD;
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_free_resize_umem
+ Description : User mode applies for umem of resize_buf, and MTT corresponding to user mode buf
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_cq_free_resize_umem(struct roce5_device *rdev,
+ struct roce5_cq *rcq)
+{
+ /* Free MTT and umem of resize_buf */
+ roce5_cq_put_umem(rdev, &rcq->resize_buf->buf, &rcq->resize_umem, 0);
+ rcq->resize_umem = NULL;
+
+ /* free resize_buf itself */
+ kfree(rcq->resize_buf);
+ rcq->resize_buf = NULL;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_get_outstanding_cqes
+ Description : roce5_cq_get_outstanding_cqes
+ Input : struct roce5_cq *cq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_cq_get_outstanding_cqes(struct roce5_cq *cq)
+{
+ u32 i = 0;
+
+ i = cq->cons_index;
+ while (roce5_get_sw_cqe(cq, i)) {
+ ++i;
+ }
+
+ return (int)(i - cq->cons_index);
+}
+
+static int roce5_cq_get_next_cqe(struct roce_cqe **cqe, struct roce5_cq *cq,
+ unsigned int *i, u32 *times,
+ const struct roce_cqe *start_cqe)
+{
+ do {
+ *cqe = (struct roce_cqe *)roce5_get_sw_cqe(cq, ++(*i));
+ if (*cqe == NULL) {
+ ROCE_DELAY();
+ --(*times);
+ }
+ } while ((*cqe == NULL) && (*times != 0));
+
+ if ((*cqe == start_cqe) || (*cqe == NULL)) {
+ ROCE_ERR("Failed to get resize CQE, CQN(0x%x)", cq->cqn);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_resize_copy_cqes
+ Description : roce5_cq_resize_copy_cqes
+ Input : struct roce5_cq *cq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_cq_resize_copy_cqes(struct roce5_cq *cq)
+{
+ struct roce_cqe *cqe = NULL;
+ struct roce_cqe *new_cqe = NULL;
+ struct roce_cqe *start_cqe = NULL;
+ u32 times;
+ unsigned int i = 0;
+ int ret = 0;
+
+ i = cq->cons_index;
+
+ times = ROCE_CQ_RESIZE_POLL_TIMES;
+ do {
+ cqe = (struct roce_cqe *)roce5_get_sw_cqe(cq, i);
+ if (cqe == NULL) {
+ ROCE_DELAY();
+ --times;
+ }
+ } while ((cqe == NULL) && (times != 0));
+
+ if (cqe == NULL) {
+ ROCE_ERR("Failed to get resize CQE, CQN(0x%x)", cq->cqn);
+ return -ENOMEM;
+ }
+
+ start_cqe = cqe;
+
+ /* r_cqe:resize_cqe
+ CI
+ +--------+-----+-----+-----+----------+
+ old_buf: | | CQE | CQE |R_CQE| |
+ +--------+-----+-----+-----+----------+
+ | |
+ | |
+ +--------+-----+-----+-----+----------+
+ new_buf: | | CQE | CQE | | |
+ +--------+-----+-----+-----+----------+
+ */
+ /* Convert the fields needed by CQE to little endian */
+ cqe->dw0.value = roce5_convert_cpu32(cqe->dw0.value);
+ cqe->dw1.value = roce5_convert_cpu32(cqe->dw1.value);
+ while (cqe->dw1.bs.op_type != ROCE_OPCODE_RESIZE_CQE) {
+ /* The resized PI can be inherited, and the index of the original CQE remains unchanged in resize_buf */
+ new_cqe = (struct roce_cqe *)roce5_get_cqe_from_buf(
+ &cq->resize_buf->buf,
+ (i & ((unsigned)cq->resize_buf->cqe)));
+
+ ret = memcpy_s((void *)new_cqe, sizeof(struct roce_cqe),
+ (void *)cqe, sizeof(struct roce_cqe));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy new_cqe.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ /* If the CQE has been wrapped in resize_buf, the corresponding Owner bit needs to be modified
+ to be owned by the software.
+ * The rule is: when the owner bit is owned by CQE software, the O bit is opposite to the high bit of ci;
+ when the owner bit is owned by hardware, the O bit is the same as the high bit of CI.
+ */
+ new_cqe->dw0.bs.owner = ((i & ((unsigned)cq->resize_buf->cqe +
+ ROCE_CQE_UP_THRESHOLD)) != 0) ?
+ 1 :
+ 0;
+
+ /* After processing, turn the DW0/DW1 of CQE back to big endian */
+ cqe->dw0.value = roce5_convert_be32(cqe->dw0.value);
+ cqe->dw1.value = roce5_convert_be32(cqe->dw1.value);
+
+ /* Convert DW0/DW1 of the CQE in the new queue back to big endian */
+ new_cqe->dw0.value = roce5_convert_be32(new_cqe->dw0.value);
+ new_cqe->dw1.value = roce5_convert_be32(new_cqe->dw1.value);
+
+ /* Get the next CQE */
+ ret = roce5_cq_get_next_cqe(&cqe, cq, &i, ×, start_cqe);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Convert DW0/DW1 of CQE to little endian */
+ cqe->dw0.value = roce5_convert_cpu32(cqe->dw0.value);
+ cqe->dw1.value = roce5_convert_cpu32(cqe->dw1.value);
+ }
+
+ return 0;
+}
+
+static int roce5_uni_cmd_cq_resize_inbuf_fill(struct roce5_device *rdev,
+ struct roce5_cq *rcq,
+ int page_shift,
+ cqm_cmd_buf_s **cqm_cmd_inbuf)
+{
+ int ret = 0;
+ struct dev_roce_svc_own_cap *rdma_own_cap = NULL;
+ u32 cq_size = 0;
+ u32 mtt_layer = 0;
+ u64 mtt_paddr = 0;
+ u32 mtt_page_size = 0;
+ roce_uni_cmd_resize_cq_s *cq_resize_inbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_resize_cq_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ rdma_own_cap = &rdev->rdma_cap.dev_rdma_cap.roce_own_cap;
+ cq_size = (u32)rcq->resize_buf->cqe + ROCE_CQE_UP_THRESHOLD;
+ cq_size = (u32)ROCE_ILOG2(cq_size);
+ mtt_layer = rcq->resize_buf->buf.mtt.mtt_layers;
+ mtt_paddr = rcq->resize_buf->buf.mtt.mtt_paddr;
+ mtt_page_size = rcq->resize_buf->buf.mtt.mtt_page_shift - PAGE_SHIFT_4K;
+
+ cq_resize_inbuf = (roce_uni_cmd_resize_cq_s *)(*cqm_cmd_inbuf)->buf;
+ cq_resize_inbuf->com.index = cpu_to_be32(rcq->cqn);
+ cq_resize_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_CQ_BITMASK));
+ if (rcq->shadow != 0) {
+ cq_resize_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(
+ ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SHADOW_BITMASK));
+ cq_resize_inbuf->com.dw3.bs.shadow_vfid =
+ cpu_to_be16(rcq->shadow_vfid);
+ }
+ cq_resize_inbuf->cq_resize.page_size = cpu_to_be32((u32)page_shift);
+ cq_resize_inbuf->cq_resize.log_cq_size = cpu_to_be32(cq_size);
+ cq_resize_inbuf->cq_resize.mtt_layer_num = cpu_to_be32(mtt_layer);
+ cq_resize_inbuf->cq_resize.mtt_base_addr = mtt_paddr;
+ cq_resize_inbuf->cq_resize.mtt_base_addr =
+ cpu_to_be64(cq_resize_inbuf->cq_resize.mtt_base_addr);
+ cq_resize_inbuf->cq_resize.mtt_page_size = cpu_to_be32(mtt_page_size);
+
+ cq_resize_inbuf->cq_resize.cmtt_cache.mtt_flags = 0;
+ cq_resize_inbuf->cq_resize.cmtt_cache.mtt_num = 0;
+ cq_resize_inbuf->cq_resize.cmtt_cache.mtt_cache_line_start =
+ cpu_to_be32(rdma_own_cap->cmtt_cl_start);
+ cq_resize_inbuf->cq_resize.cmtt_cache.mtt_cache_line_end =
+ cpu_to_be32(rdma_own_cap->cmtt_cl_end);
+ cq_resize_inbuf->cq_resize.cmtt_cache.mtt_cache_line_size =
+ cpu_to_be32(rdma_own_cap->cmtt_cl_sz);
+ return 0;
+}
+
+static int roce5_cq_resize(struct roce5_device *rdev, struct roce5_cq *rcq,
+ int page_shift)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+
+ if (ROCE5_SUPPORT_IB_CMD_RESIZE_CQ_MSG_V2(rdev) != 0) {
+ ret = roce5_uni_cmd_cq_resize_inbuf_fill(rdev, rcq, page_shift,
+ &cqm_cmd_inbuf);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_RESIZE_CQ, cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send RESIZE_CQ command, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+
+ /* When CMDq times out or CMDq cannot work, update the device status and notify the PCIe module to reset
+ the device through OFED */
+ if ((ret == -ETIMEDOUT) || (ret == -EPERM)) {
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+
+ ret = -1;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_user_cq_resize
+ Description : roce5_user_cq_resize
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ int entries
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_user_cq_resize(struct roce5_device *rdev, struct roce5_cq *rcq,
+ int entries, struct ib_udata *udata)
+{
+ int page_shift = 0;
+ int ret = 0;
+
+ /* Cannot exceed max size after power-of-2 alignment */
+ if (entries > ((int)rdev->rdma_cap.max_cqes + ROCE_CQE_UP_THRESHOLD)) {
+ ROCE_DEV_ERR(rdev, "Over range after align, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ ret = roce5_cq_alloc_resize_umem(rdev, rcq, entries, udata);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc resize_umem, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+#if defined(UMEM_HAVE_PAGE_SHIFT)
+ page_shift = rcq->resize_umem->page_shift - PAGE_SHIFT_4K;
+#else
+ page_shift = PAGE_SHIFT - PAGE_SHIFT_4K;
+#endif
+
+ /* Send the cq_resize command to configure CQC. After the configuration is successful, the new CQE is written to
+ resize_buf, and the old buffer may still retain the old CQE. */
+ ret = roce5_cq_resize(rdev, rcq, page_shift);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to resize cq, func_id(%d)",
+ rdev->glb_func_id);
+ roce5_cq_free_resize_umem(rdev, rcq);
+ return ret;
+ }
+
+ rcq->ibcq.cqe = rcq->resize_buf->cqe;
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_resize_user_cq
+ Description : roce5_resize_user_cq
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ int entries
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_resize_user_cq(struct roce5_device *rdev, struct roce5_cq *rcq,
+ int entries, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_resize_cq_cmd ucmd = { 0 };
+ int cqe_entries = entries;
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)) != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to copy from user space, func_id(%d)",
+ rdev->glb_func_id);
+ return -EFAULT;
+ }
+
+ mutex_lock(&rcq->resize_mutex);
+
+ if (ucmd.stage == 1) {
+ goto release_flow;
+ }
+
+ /* The CQE queue should reserve four special CQE for the HOST CI can be updated to the CQC CI */
+ cqe_entries += ROCE_CQE_UP_THRESHOLD;
+ cqe_entries =
+ (int)(ROCE_ROUNDUP_POW_OF_TWO((u32)cqe_entries) & 0xffffffff);
+ //Minimum queue depth needs to be aligned by page
+ if ((u32)(cqe_entries * (int)rdev->rdma_cap.cqe_size) < PAGE_SIZE) {
+ cqe_entries =
+ (int)(PAGE_SIZE >> (unsigned int)ROCE_ILOG2(
+ rdev->rdma_cap.cqe_size));
+ }
+ if (cqe_entries == 0) {
+ ROCE_DEV_ERR(rdev,
+ "Invalid cqe_entries after align, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -EINVAL;
+ goto out;
+ }
+ rcq->cqe_mask = cqe_entries - 1;
+
+ /* The new depth of CQ cannot be the same as the old depth. Four special CQE space is reserved when CQ is created,
+ so the value of ibcq->cqe is 4 smaller than the actual value */
+ if (cqe_entries == (rcq->ibcq.cqe + ROCE_CQE_UP_THRESHOLD)) {
+ ROCE_DEV_ERR(rdev, "No need to resize cq, func_id(%d)",
+ rdev->glb_func_id);
+ ret = 0;
+ goto out;
+ }
+
+ ret = roce5_user_cq_resize(rdev, rcq, cqe_entries, udata);
+ if (ret != 0) {
+ goto out;
+ }
+
+ mutex_unlock(&rcq->resize_mutex);
+
+ return 0;
+
+release_flow:
+ /* free old MTT */
+ hmm_mtt_free(rdev->hwdev, &rcq->buf.mtt, SERVICE_T_ROCE);
+
+ rcq->buf = rcq->resize_buf->buf;
+ ib_umem_release(rcq->umem);
+ rcq->umem = rcq->resize_umem;
+
+ kfree(rcq->resize_buf);
+ rcq->resize_buf = NULL;
+ rcq->resize_umem = NULL;
+
+out:
+ mutex_unlock(&rcq->resize_mutex);
+
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_kernel_cq_resize
+ Description : roce5_kernel_cq_resize
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ int entries
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_kernel_cq_resize(struct roce5_device *rdev,
+ struct roce5_cq *rcq, int entries)
+{
+ int outst_cqe = 0;
+ int page_shift = 0;
+ int ret = 0;
+
+ /* Cannot exceed max size after power-of-2 alignment */
+ if (entries > ((int)rdev->rdma_cap.max_cqes + ROCE_CQE_UP_THRESHOLD)) {
+ ROCE_DEV_ERR(rdev, "Over range after align, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ /* The number of resized CQEs cannot be smaller than the number of outstanding CQEs */
+ outst_cqe = roce5_cq_get_outstanding_cqes(rcq);
+ if (entries < (outst_cqe + ROCE_CQE_UP_THRESHOLD)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Can't resize, because smaller than the number of outstanding CQES, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ ret = roce5_cq_alloc_resize_buf(rdev, rcq, entries);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc resize buffer, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ page_shift = (int)ROCE_ILOG2(rcq->cqm_cq->q_room_buf_2.buf_size) -
+ PAGE_SHIFT_4K;
+
+ /* Send the cq_resize command to configure CQC. After the configuration is successful, the new CQE is written to
+ resize_buf, and the old buffer may still retain the old CQE. */
+ ret = roce5_cq_resize(rdev, rcq, page_shift);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to resize cq, func_id(%d)",
+ rdev->glb_func_id);
+ roce5_cq_free_resize_buf(rdev, rcq);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_resize_kernel_cq
+ Description : roce5_resize_kernel_cq
+ Input : struct roce5_device *rdev
+ struct roce5_cq *rcq
+ int entries
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_resize_kernel_cq(struct roce5_device *rdev,
+ struct roce5_cq *rcq, int entries)
+{
+ int ret = 0;
+ int old_cqe = 0;
+ struct mtt old_mtt;
+ int cqe_entries = entries;
+
+ mutex_lock(&rcq->resize_mutex);
+
+ cqe_entries += ROCE_CQE_UP_THRESHOLD;
+ cqe_entries =
+ (int)(ROCE_ROUNDUP_POW_OF_TWO((u32)cqe_entries) & 0xffffffff);
+ /* Minimum queue depth needs to be aligned by page */
+ if ((u32)(cqe_entries * (int)rdev->rdma_cap.cqe_size) < PAGE_SIZE) {
+ cqe_entries = (PAGE_SIZE >> (unsigned int)ROCE_ILOG2(
+ rdev->rdma_cap.cqe_size));
+ }
+
+ /* The new depth of CQ cannot be the same as the old depth. Four special CQE space is reserved when CQ is created,
+ so the value of ibcq->cqe is four smaller than the actual value */
+ if (cqe_entries == (rcq->ibcq.cqe + ROCE_CQE_UP_THRESHOLD)) {
+ ROCE_DEV_ERR(rdev, "No need to resize cq, func_id(%d)",
+ rdev->glb_func_id);
+ mutex_unlock(&rcq->resize_mutex);
+ return 0;
+ }
+
+ ret = roce5_kernel_cq_resize(rdev, rcq, cqe_entries);
+ if (ret != 0) {
+ goto out;
+ }
+
+ /* free old MTT */
+ old_mtt = rcq->buf.mtt;
+
+ /* When copying CQE from the old buffer to resize_buf, the user may be polling cqe from the old buf, so
+ it needs to be locked.If CQE of the old buffer has been polled in the polling process, polling process will
+ free old buffer and switch to new buffer.
+ */
+ spin_lock_irq(&rcq->lock);
+
+ /* If the new buf has been switched to, nothing needs to be done */
+ if (rcq->resize_buf != NULL) {
+ ret = roce5_cq_resize_copy_cqes(rcq);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Have not polled resize cqe(fuc:%d, cqn:%u, ret:%d)",
+ rdev->glb_func_id, rcq->cqn, ret);
+ roce5_cq_free_resize_buf(rdev, rcq);
+ spin_unlock_irq(&rcq->lock);
+ mutex_unlock(&rcq->resize_mutex);
+ return ret;
+ }
+ old_cqe = rcq->ibcq.cqe;
+ rcq->buf = rcq->resize_buf->buf;
+ rcq->ibcq.cqe = rcq->resize_buf->cqe;
+
+ kfree(rcq->resize_buf);
+ rcq->resize_buf = NULL;
+ }
+
+ spin_unlock_irq(&rcq->lock);
+
+ /* Non-0 means that the above resize_buf non-empty branch has been entered, the old buffer needs to be released */
+ if (old_cqe != 0) {
+ hmm_mtt_free(rdev->hwdev, &old_mtt, SERVICE_T_ROCE);
+ cqm5_object_resize_free_old(&rcq->cqm_cq->object);
+ }
+
+out:
+ mutex_unlock(&rcq->resize_mutex);
+
+ return ret;
+}
+
+static int roce5_resize_cq_check(struct ib_cq *ibcq, int entries,
+ const struct ib_udata *udata)
+{
+ struct roce5_device *rdev = NULL;
+
+ if (ibcq == NULL) {
+ ROCE_ERR("Ibcq is null");
+ return -EINVAL;
+ }
+
+ if ((ibcq->uobject != NULL) && (udata == NULL)) {
+ ROCE_ERR("Udata is null, but uobject is not null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibcq->device);
+ if ((entries < 1) || (entries > (int)rdev->rdma_cap.max_cqes)) {
+ ROCE_DEV_ERR(rdev,
+ "Resize CQEs invalid. entries(%d), func_id(%d)",
+ entries, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_resize_cq
+ Description : roce5_resize_cq
+ Input : struct ib_cq *ibcq
+ int entries
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_cq *rcq = NULL;
+ struct roce5_device *rdev = NULL;
+
+ ret = roce5_resize_cq_check(ibcq, entries, udata);
+ if (ret != 0) {
+ ROCE_ERR("Failed to check resize_cq");
+ return ret;
+ }
+
+ rcq = to_roce5_cq(ibcq);
+ rdev = to_roce5_dev(ibcq->device);
+
+ if (ibcq->uobject) {
+ ret = roce5_resize_user_cq(rdev, rcq, entries, udata);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to resize user cq, func_id(%u) ret(%d)",
+ (u32)rdev->glb_func_id, ret);
+ return ret;
+ }
+ } else {
+ ret = roce5_resize_kernel_cq(rdev, rcq, entries);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to resize kernel cq, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void roce5_lock_cqs(struct roce5_cq *roce5_send_cq,
+ struct roce5_cq *roce5_recv_cq)
+ __acquires(&roce5_send_cq->lock) __acquires(&roce5_recv_cq->lock)
+{
+ if (roce5_send_cq == roce5_recv_cq) {
+ spin_lock_irq(&roce5_send_cq->lock);
+ __acquire(&roce5_recv_cq->lock);
+ } else if (roce5_send_cq->cqn < roce5_recv_cq->cqn) {
+ spin_lock_irq(&roce5_send_cq->lock);
+ spin_lock_nested(&roce5_recv_cq->lock, SINGLE_DEPTH_NESTING);
+ } else {
+ spin_lock_irq(&roce5_recv_cq->lock);
+ spin_lock_nested(&roce5_send_cq->lock, SINGLE_DEPTH_NESTING);
+ }
+}
+
+void roce5_unlock_cqs(struct roce5_cq *roce5_send_cq,
+ struct roce5_cq *roce5_recv_cq)
+ __releases(&roce5_send_cq->lock) __releases(&roce5_recv_cq->lock)
+{
+ if (roce5_send_cq == roce5_recv_cq) {
+ __release(&roce5_recv_cq->lock);
+ spin_unlock_irq(&roce5_send_cq->lock);
+ } else if (roce5_send_cq->cqn < roce5_recv_cq->cqn) {
+ spin_unlock(&roce5_recv_cq->lock);
+ spin_unlock_irq(&roce5_send_cq->lock);
+ } else {
+ spin_unlock(&roce5_send_cq->lock);
+ spin_unlock_irq(&roce5_recv_cq->lock);
+ }
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_destroy.c b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_destroy.c
new file mode 100644
index 000000000..c4e442598
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_destroy.c
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/slab.h>
+
+#include "comm_defs.h"
+#include "hinic5_hw.h"
+
+#include "roce.h"
+#include "roce_srq.h"
+#include "roce_qp.h"
+#include "roce_mix.h"
+#include "roce_xrc.h"
+#include "roce_cq.h"
+#include "roce_cqm_cmd.h"
+#include "roce_npu_cmd.h"
+#include "hinic5_hmm.h"
+#include "securec.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#include "roce_compat.h"
+#include "roce_os_compat.h"
+#include "roce_cq_intern.h"
+#include "roce_com.h"
+#include "roce_uld_kernel_api.h"
+#include "roce_uld_inner.h"
+
+/* and above next is V100 adaptation data structure */
+typedef struct tag_roce_cmd_cq_cache_invalidate {
+ roce_verbs_cmd_com_s com;
+ roce_xq_mtt_info_s mtt_info;
+} roce_cmd_cq_cache_invalidate_s;
+#define CQC_CHECK_RESCHED_LOOP_TIMES 0xffffU
+static int roce5_check_cqc_data_state(struct roce5_device *rdev,
+ const struct roce5_cq *cq,
+ struct roce5_cq_context *cqc_data,
+ u32 check_state)
+{
+ int read_back_flag = 0;
+ u32 times = (u32)rdev->try_times;
+ struct roce5_cq_context check_cqc_data;
+ while ((times--) != 0) {
+ check_cqc_data.dw2.value = be32_to_cpu(cqc_data->dw2.value);
+ if (check_cqc_data.dw2.bs.state == check_state) {
+ read_back_flag = 1;
+ break;
+ }
+ ROCE_DELAY();
+
+ // limit schedule cond_resched count, preventstop thread schedule frequency past high
+ if ((times & CQC_CHECK_RESCHED_LOOP_TIMES) == 0) {
+ cond_resched();
+ }
+ }
+
+ if (read_back_flag == 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to read back after try %d times, Cqn(0x%x), CQ state(0x%x), func_id(%u)",
+ rdev->try_times, cq->cqn, cqc_data->dw2.value,
+ (u32)rdev->glb_func_id);
+ return -1;
+ }
+
+ return 0;
+}
+/* ****************************************************************************
+ Prototype : roce5_cq_hw2sw
+ Description : roce5_cq_hw2sw
+ Input : struct roce5_device *rdev
+ struct roce5_cq *cq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_cq_hw2sw(struct roce5_device *rdev, struct roce5_cq *cq)
+{
+ int ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ struct roce5_cq_context *cqc_data = NULL;
+ roce_uni_cmd_cq_hw2sw_s *cq_hw2sw_inbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_cq_hw2sw_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ cq_hw2sw_inbuf = (roce_uni_cmd_cq_hw2sw_s *)cqm_cmd_inbuf->buf;
+ cq_hw2sw_inbuf->com.index = cpu_to_be32((u32)cq->cqn);
+ cq_hw2sw_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_CQ_BITMASK);
+ if (cq->shadow != 0) {
+ cq_hw2sw_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(
+ ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SHADOW_BITMASK));
+ cq_hw2sw_inbuf->com.dw3.bs.shadow_vfid =
+ cpu_to_be16(cq->shadow_vfid);
+ }
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE, ROCE_CMD_HW2SW_CQ,
+ cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send HW2SW_CQ command, func_id(%u), cqn(0x%x), (ret:%d)",
+ (u32)rdev->glb_func_id, cq->cqn, ret);
+
+ ret = (-EINVAL);
+
+ if (hinic5_get_chip_present_flag(rdev->hwdev) == 0) {
+ ROCE_DEV_ERR(rdev,
+ "Card not present, return OK, func_id(%d)",
+ rdev->glb_func_id);
+ ret = 0;
+ }
+
+ /* CMDq may return a positive number, so its return value cannot be used directly */
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ /* HI1825_V100 will retry load cqc in cmdq */
+ if (ROCE5_SUPPORT_RETRY_LOAD_CQC_MSG_FEATURE(rdev) != 0) {
+ cqc_data = (struct roce5_cq_context *)((void *)cq->cqm_cq
+ ->q_ctx_vaddr);
+ return roce5_check_cqc_data_state(rdev, cq, cqc_data,
+ ROCE_CQ_TIME_OUT_CHECK_VALUE);
+ }
+ return 0;
+}
+
+static int roce5_uni_cmd_cq_cache_out(struct roce5_device *rdev,
+ struct roce5_cq *cq,
+ cqm_cmd_buf_s **cqm_cmd_inbuf)
+{
+ int ret = 0;
+ struct dev_roce_svc_own_cap *roce_own_cap = NULL;
+ roce_uni_cmd_cq_hw2sw_s *cq_cache_invld_inbuf = NULL;
+
+ /* Send the cache out command */
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_cq_hw2sw_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ roce_own_cap = &rdev->rdma_cap.dev_rdma_cap.roce_own_cap;
+ cq_cache_invld_inbuf = (roce_uni_cmd_cq_hw2sw_s *)(*cqm_cmd_inbuf)->buf;
+ cq_cache_invld_inbuf->com.index = cpu_to_be32((u32)cq->cqn);
+ cq_cache_invld_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_CQ_BITMASK));
+ if (cq->shadow != 0) {
+ cq_cache_invld_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(
+ ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SHADOW_BITMASK));
+ cq_cache_invld_inbuf->com.dw3.bs.shadow_vfid =
+ cpu_to_be16(cq->shadow_vfid);
+ }
+ cq_cache_invld_inbuf->cmtt_cache.mtt_flags = 0;
+ cq_cache_invld_inbuf->cmtt_cache.mtt_num = 0;
+ cq_cache_invld_inbuf->cmtt_cache.mtt_cache_line_start =
+ cpu_to_be32(roce_own_cap->cmtt_cl_start);
+ cq_cache_invld_inbuf->cmtt_cache.mtt_cache_line_end =
+ cpu_to_be32(roce_own_cap->cmtt_cl_end);
+ cq_cache_invld_inbuf->cmtt_cache.mtt_cache_line_size =
+ cpu_to_be32(roce_own_cap->cmtt_cl_sz);
+
+ return 0;
+}
+
+static int roce5_cq_cache_out(struct roce5_device *rdev, struct roce5_cq *cq)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+
+ if (ROCE5_SUPPORT_CQ_CACHE_OUT_MSG_V2(rdev) != 0) {
+ ret = roce5_uni_cmd_cq_cache_out(rdev, cq, &cqm_cmd_inbuf);
+ }
+
+ if (ret != 0) {
+ return ret;
+ }
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_MISC_CQ_CACHE_INVLD, cqm_cmd_inbuf,
+ NULL, NULL, ROCE_CMD_TIME_CLASS_A,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send CQ_CACHE_INVLD command, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ if (hinic5_get_chip_present_flag(rdev->hwdev) == 0) {
+ ROCE_DEV_ERR(rdev,
+ "Card not present, return OK, func_id(%d)",
+ rdev->glb_func_id);
+ return 0;
+ }
+
+ return -1;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return 0;
+}
+
+int roce5_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_device *rdev = NULL;
+ struct roce5_cq *rcq = NULL;
+ struct roce5_ucontext *ucontext = NULL;
+ char waiting_msg[ROCE_WAITING_MSG_MAX_SIZE];
+ roce_user_handle_t hdl = { 0 };
+
+ if (ibcq == NULL) {
+ ROCE_ERR("Ibcq is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibcq->device);
+ rcq = to_roce5_cq(ibcq);
+
+ ret = sprintf_s(waiting_msg, ROCE_WAITING_MSG_MAX_SIZE,
+ "Waiting for roce cq(%u) release...", rcq->cqn);
+ if (ret < 0) {
+ ROCE_DEV_WARN(rdev, "Failed to setup waiting message, ret(%d).",
+ ret);
+ }
+
+ roce5_option_unset(rcq->opt, waiting_msg, sizeof(waiting_msg));
+
+ /* Modify CQC to be owned by the software */
+ ret = roce5_cq_hw2sw(rdev, rcq);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to modify CQC, ret(%d), func_id(%d), cqn(0x%x)",
+ ret, rdev->glb_func_id, rcq->cqn);
+ return ret;
+ }
+
+ /* Send the cache out command */
+ ret = roce5_cq_cache_out(rdev, rcq);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send cache out command, ret(%d), func_id(%hu)",
+ ret, rdev->glb_func_id);
+ return ret;
+ }
+
+ ROCE_CONSTUCT_ULD_HDL_RCQ(&hdl, rdev, rcq, NULL, NULL, NULL, 0);
+ roce5_uld_cq_destroy((roce_uld_handle)&hdl);
+
+ /* If it is user mode, you also need to cancel the mapping of the corresponding software DB */
+ if (ibcq->uobject != NULL) {
+ ucontext = roce5_queue_to_ucontext((void *)ibcq, udata,
+ ROCE_Q_TYPE_CQ);
+ roce5_db_unmap_user(ucontext, &rcq->db, rcq->shadow);
+ roce5_cq_put_umem(rdev, &rcq->buf, &rcq->umem, rcq->shadow);
+ } else {
+ hmm_mtt_free(rdev->hwdev, &rcq->buf.mtt, SERVICE_T_ROCE);
+ }
+
+ roce5_destroy_cq_dealloc_cqn(rdev, rcq);
+ return 0;
+}
+
+int roce5_destroy_cq_ofa(struct ib_cq *ibcq)
+{
+ int ret = 0;
+ struct roce5_cq *rcq = NULL;
+
+ if (ibcq == NULL) {
+ ROCE_ERR("Input pointer is NULL");
+ return (-EINVAL);
+ }
+
+ ret = roce5_destroy_cq(ibcq, NULL);
+ if (ret == 0) {
+ rcq = to_roce5_cq(ibcq);
+ kfree(rcq);
+ }
+
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_format.h b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_format.h
new file mode 100644
index 000000000..3c1cb6640
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_format.h
@@ -0,0 +1,29 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_CQ_FORMAT_H
+#define ROCE_CQ_FORMAT_H
+
+#include <linux/types.h>
+
+#include "roce_qp_ctx_format.h"
+
+typedef struct roce5_cq_context {
+ u32 rsvd[2];
+ union {
+ struct {
+ u32 rsvd : 28;
+ u32 state : 4;
+ } bs;
+ u32 value;
+ } dw2;
+
+ u32 rsvd1[12];
+
+ struct roce5_qpc_timer_seg timer_seg;
+
+ u32 rsvd2[8];
+} roce5_cq_context_s;
+
+#endif /* ROCE_CQ_FORMAT_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_intern.c b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_intern.c
new file mode 100644
index 000000000..119fafba9
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_intern.c
@@ -0,0 +1,98 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/slab.h>
+
+#include "hinic5_hw.h"
+#include "securec.h"
+
+#include "roce.h"
+#include "roce_user.h"
+#include "roce_cq.h"
+#include "roce_os_compat.h"
+#include "roce_cq_intern.h"
+
+/*
+ * high performance cq, based on reserved of cq, first to firstget get.
+ * 特 point: supports 23V200 & 25V100 two types NIC, according to device type different to allocate different of cq.
+ * later get of cq so bind qp performance will has so next decrease.
+*/
+
+#define ROCE_CQN_PERF_BASE 1
+
+int roce5_create_cq_alloc_cqn(struct roce5_device *rdev, struct roce5_cq *rcq,
+ u32 index)
+{
+ u32 cqn = index;
+ u32 offset = ROCE_CQN_PERF_BASE;
+ u32 step = rdev->cqn_ctrl.rsvd_cq_step;
+ u32 rsvd_cqs = rdev->rdma_cap.dev_rdma_cap.roce_own_cap.reserved_cqs;
+
+ mutex_lock(&rdev->cqn_ctrl.cq_ctrl_mutex);
+
+ if (rdev->cqn_ctrl.alloc_cq_cnt == rdev->cqn_ctrl.high_perf_cq_cnt) {
+ /* The reserved high performance CQs have been fully allocated. */
+ goto cqn_alloc;
+ }
+
+ while (rdev->cqn_ctrl.alloc_cq_cnt < rdev->cqn_ctrl.high_perf_cq_cnt &&
+ (offset < rsvd_cqs)) {
+ if (test_and_set_bit(offset, &rdev->cqn_ctrl.cq_bitmap) != 0) {
+ offset += step;
+ continue;
+ }
+ cqn = offset;
+ rdev->cqn_ctrl.alloc_cq_cnt++;
+ ROCE_DEV_INFO(
+ rdev,
+ "Alloc High performance CQ, func_id(%d), total_high_perf_cq(%u), cqn(%d)",
+ rdev->glb_func_id, rdev->cqn_ctrl.alloc_cq_cnt, cqn);
+ break;
+ }
+
+cqn_alloc:
+ mutex_unlock(&rdev->cqn_ctrl.cq_ctrl_mutex);
+
+ rcq->cqm_cq = cqm5_object_rdma_queue_create(rdev->hwdev, SERVICE_T_ROCE,
+ CQM_OBJECT_RDMA_SCQ, 0,
+ rcq->opt, false, cqn, 0, 0);
+ if (rcq->cqm_cq == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create rdma queue from cqm object, func_id(%d), index(%d)",
+ rdev->glb_func_id, index);
+ return -ENOMEM;
+ }
+
+ rcq->cqn = rcq->cqm_cq->index;
+
+ return 0;
+}
+
+void roce5_destroy_cq_dealloc_cqn(struct roce5_device *rdev,
+ struct roce5_cq *rcq)
+{
+ u32 cqn = rcq->cqn;
+ u32 rsvd_cqs = rdev->rdma_cap.dev_rdma_cap.roce_own_cap.reserved_cqs;
+ /* Call the CQM interface to release CQN and CQC. Since there is no cq_buf and software DB in user mode,
+ it does not need to be released; since kernel mode has both, it needs to be released */
+ cqm5_object_delete(&rcq->cqm_cq->object);
+ kfree(rcq->opt);
+ rcq->opt = NULL;
+
+ mutex_lock(&rdev->cqn_ctrl.cq_ctrl_mutex);
+
+ if ((cqn < rsvd_cqs) &&
+ test_and_clear_bit(cqn, &rdev->cqn_ctrl.cq_bitmap) != 0 &&
+ rdev->cqn_ctrl.alloc_cq_cnt > 0) {
+ rdev->cqn_ctrl.alloc_cq_cnt--;
+ ROCE_DEV_INFO(
+ rdev,
+ "Dealloc High performance CQ, func_id(%d), total_high_perf_cq(%u), cqn(%d)",
+ rdev->glb_func_id, rdev->cqn_ctrl.alloc_cq_cnt, cqn);
+ }
+ mutex_unlock(&rdev->cqn_ctrl.cq_ctrl_mutex);
+
+ return;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_intern.h b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_intern.h
new file mode 100644
index 000000000..a2cb56943
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/cq/roce_cq_intern.h
@@ -0,0 +1,24 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_CQ_INTERN_H
+#define ROCE_CQ_INTERN_H
+
+#include <rdma/ib_verbs.h>
+
+#include "hinic5_hw.h"
+#include "hinic5_rdma.h"
+#include "hinic5_cqm.h"
+
+#include "roce.h"
+#include "roce_cq.h"
+
+#define ROCE_CQN_INVLD CQM_INDEX_INVALID
+
+int roce5_create_cq_alloc_cqn(struct roce5_device *rdev, struct roce5_cq *rcq,
+ u32 index);
+void roce5_destroy_cq_dealloc_cqn(struct roce5_device *rdev,
+ struct roce5_cq *rcq);
+
+#endif //ROCE_CQ_INTERN_H
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/event/roce_event.c b/drivers/infiniband/hw/hiroce5/kernel/base/event/roce_event.c
new file mode 100644
index 000000000..0ce3ffb25
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/event/roce_event.c
@@ -0,0 +1,437 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include "roce_event_extension.h"
+#include "roce_aeq_format.h"
+#include "hinic5_mt.h"
+#include "roce_restore.h"
+#include "roce_infra.h"
+#include "roce_cq.h"
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+#include "roce_event.h"
+
+static void roce5_event_report_common(const struct roce5_device *rdev,
+ int event_str_index)
+{
+ switch (event_str_index) {
+ case OFED_ET_PATH_MIG:
+ ROCE_DEV_INFO_LIMIT(rdev,
+ "OFED event: Path mig. function id: %hu",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_COMM_EST:
+ ROCE_INFO_ONCE(
+ "OFED event: Communication establish. function id: %hu",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_SQ_DRAINED:
+ ROCE_DEV_ERR_LIMIT(rdev,
+ "OFED event: Sq drained. function id: %hu",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_SRQ_QP_LAST_WQE:
+ ROCE_ERR_ONCE("OFED event: Srq/qp last wqe. function id: %hu",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_WQ_CATAS_ERR:
+ ROCE_DEV_ERR_LIMIT(
+ rdev, "OFED event: Wq catas error. function id: %hu",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_PATH_MIG_FAILED:
+ ROCE_DEV_ERR_LIMIT(
+ rdev, "OFED event: Path mig failed. function id: %u",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_WQ_INVAL_REQ_ERR:
+ ROCE_DEV_ERR_LIMIT(
+ rdev, "OFED event: Wq inval req error. function id: %u",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_WQ_ACCESS_ERR:
+ ROCE_DEV_ERR_LIMIT(
+ rdev, "OFED event: Wq access error. function id: %u",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_CQ_ERR:
+ ROCE_DEV_ERR_LIMIT(rdev,
+ "OFED event: Cq error. function id: %u",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_SRQ_LIMIT:
+ ROCE_DEV_ERR_LIMIT(rdev,
+ "OFED event: Srq limit. function id: %u",
+ rdev->glb_func_id);
+ break;
+ case OFED_ET_SRQ_CATAS_ERR:
+ ROCE_DEV_ERR_LIMIT(
+ rdev, "OFED event: Srq catas error. function id: %u",
+ rdev->glb_func_id);
+ break;
+ case NON_OFED_ET_QPC_LOOKUP_ERR:
+ ROCE_DEV_ERR_LIMIT(
+ rdev,
+ "[non ofed event type] Qpc lookup error. function id: %u",
+ rdev->glb_func_id);
+ break;
+ case NON_OFED_ET_OTHER_TYPE_ERR:
+ ROCE_ERR_ONCE(
+ "[non ofed event type] other type error. function id: %u",
+ rdev->glb_func_id);
+ break;
+ default:
+ break;
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_event_report
+ Description : roce5_event_report
+ Input : struct roce5_device *rdev
+ int event_str_index
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_event_report(struct roce5_device *rdev, u8 *val,
+ int event_str_index)
+{
+ if (event_str_index <= NON_OFED_ET_OTHER_TYPE_ERR) {
+ roce5_event_report_common(rdev, event_str_index);
+ } else {
+ roce5_event_report_extend(rdev, val, event_str_index);
+ }
+}
+
+/* ****************************************************************************
+ Prototype : to_qp_event_str_index
+ Description : to_qp_event_str_index
+ Input : u8 event_type
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int to_qp_event_str_index(u8 event_type)
+{
+ switch (event_type) {
+ case ROCE_EVENT_TYPE_PATH_MIG:
+ return OFED_ET_PATH_MIG;
+
+ case ROCE_EVENT_TYPE_COMM_EST:
+ return OFED_ET_COMM_EST;
+
+ case ROCE_EVENT_TYPE_SQ_DRAINED:
+ return OFED_ET_SQ_DRAINED;
+
+ case ROCE_EVENT_TYPE_SRQ_QP_LAST_WQE:
+ return OFED_ET_SRQ_QP_LAST_WQE;
+
+ case ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
+ return OFED_ET_WQ_CATAS_ERR;
+
+ case ROCE_EVENT_TYPE_PATH_MIG_FAILED:
+ return OFED_ET_PATH_MIG_FAILED;
+
+ case ROCE_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ return OFED_ET_WQ_INVAL_REQ_ERR;
+
+ default:
+ return OFED_ET_WQ_ACCESS_ERR;
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_handle_qp_async_event
+ Description : roce5_handle_qp_async_event
+ Input : struct roce5_device *rdev
+ u32 qpn
+ u8 event_type
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_handle_qp_async_event(struct roce5_device *rdev, u32 qpn,
+ u8 event_type)
+{
+ struct roce5_qp *rqp = NULL;
+ cqm_object_s *cqm_obj_queue = NULL;
+
+ cqm_obj_queue = cqm5_object_get(rdev->hwdev, CQM_OBJECT_SERVICE_CTX,
+ qpn, false);
+ if (cqm_obj_queue == NULL) {
+ ROCE_DEV_ERR_LIMIT(
+ rdev,
+ "Failed to get cqm obj queue, func_id(%d), qpn:%u, event_type:%u",
+ rdev->glb_func_id, qpn, event_type);
+ return;
+ }
+
+ rqp = cqmobj_to_roce_qp(cqm_obj_queue);
+ roce5_qp_async_event(rdev, rqp, (int)event_type);
+ cqm5_object_put(cqm_obj_queue);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_handle_cq_async_event
+ Description : roce5_handle_cq_async_event
+ Input : struct roce5_device *rdev
+ u32 cqn
+ u8 event_type
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_handle_cq_async_event(struct roce5_device *rdev, u32 cqn,
+ u8 event_type)
+{
+ struct roce5_cq *rcq = NULL;
+
+ rcq = roce5_get_rcq_by_cqn(rdev, cqn);
+ if (rcq == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to get roce cq by cqn(%u).", cqn);
+ return;
+ }
+
+ roce5_cq_async_event(rdev, rcq, (int)event_type);
+ roce5_rcq_put(rcq);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_handle_srq_async_event
+ Description : roce5_handle_srq_async_event
+ Input : struct roce5_device *rdev
+ u32 srqn
+ u8 event_type
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_handle_srq_async_event(struct roce5_device *rdev, u32 srqn,
+ u8 event_type)
+{
+ struct roce5_srq *rsrq = NULL;
+ cqm_object_s *cqm_obj_queue = NULL;
+
+ cqm_obj_queue =
+ cqm5_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SRQ, srqn, false);
+ if (cqm_obj_queue == NULL) {
+ ROCE_DEV_ERR_LIMIT(
+ rdev,
+ "Failed to get cqm obj queue, func_id(%d), srqn:%u, event_type:%u",
+ rdev->glb_func_id, srqn, event_type);
+ return;
+ }
+
+ rsrq = cqmobj_to_roce5_srq(cqm_obj_queue);
+ roce5_srq_async_event(rdev, rsrq, (int)event_type);
+ cqm5_object_put(cqm_obj_queue);
+}
+
+static bool roce5_async_event_need_reset(u8 event_status)
+{
+ if ((event_status == API_FORMAT_ERROR) ||
+ (event_status == UNKNOWN_RESERVED_ERROR1)) {
+ return true;
+ }
+
+ return false;
+}
+
+u8 roce5_async_event_level(void *svc_hd, u8 event_type, u8 *val)
+{
+ u8 event_level = FAULT_LEVEL_MAX;
+ u8 event_status;
+ u64 param = *((u64 *)val);
+
+ if (svc_hd == NULL) {
+ ROCE_ERR_LIMIT("Svc_hd is null");
+ return FAULT_LEVEL_SUGGESTION;
+ }
+
+ event_status = param & 0xff;
+
+ switch (event_type) {
+ case ROCE_EVENT_TYPE_PATH_MIG:
+ case ROCE_EVENT_TYPE_COMM_EST:
+ case ROCE_EVENT_TYPE_SQ_DRAINED:
+ case ROCE_EVENT_TYPE_SRQ_QP_LAST_WQE:
+ case ROCE_EVENT_TYPE_SRQ_LIMIT:
+ case ROCE_EVENT_TYPE_DEBUG:
+ event_level = FAULT_LEVEL_SUGGESTION;
+ break;
+
+ case ROCE_EVENT_TYPE_LOCAL_CATAS_ERROR:
+ case ROCE_EVENT_TYPE_WQ_INVAL_REQ_ERROR: //ROCE_AEQE_EVENT_QP_REQ_ERR
+ if (event_status == API_FORMAT_ERROR) {
+ return FAULT_LEVEL_SERIOUS_RESET;
+ }
+ break;
+
+ case ROCE_EVENT_TYPE_WQ_CATAS_ERROR: //ROCE_AEQE_EVENT_WQE_CATAS
+ if (roce5_async_event_need_reset(event_status)) {
+ return FAULT_LEVEL_SERIOUS_RESET;
+ }
+ break;
+
+ case ROCE_EVENT_TYPE_CQ_ERROR: //CQ ERR
+ if (roce5_async_event_need_reset(event_status)) {
+ return FAULT_LEVEL_SERIOUS_RESET;
+ }
+ break;
+
+ default:
+ event_level = FAULT_LEVEL_GENERAL;
+ break;
+ }
+
+ return event_level;
+}
+
+static int roce5_async_event_handle_common(u8 event_type, u8 *val,
+ struct roce5_device *rdev)
+{
+ u32 xid = 0;
+ int event_str_index = 0;
+
+ switch (event_type) {
+ case ROCE_EVENT_TYPE_PATH_MIG:
+ case ROCE_EVENT_TYPE_COMM_EST:
+ case ROCE_EVENT_TYPE_SQ_DRAINED:
+ case ROCE_EVENT_TYPE_SRQ_QP_LAST_WQE:
+ case ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
+ case ROCE_EVENT_TYPE_PATH_MIG_FAILED:
+ case ROCE_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ case ROCE_EVENT_TYPE_WQ_ACCESS_ERROR:
+ xid = *((u32 *)val);
+ roce5_handle_qp_async_event(rdev, xid, event_type);
+ event_str_index = to_qp_event_str_index(event_type);
+ break;
+
+ case ROCE_EVENT_TYPE_CQ_ERROR:
+ xid = *((u32 *)val);
+ roce5_handle_cq_async_event(rdev, xid, event_type);
+ event_str_index = OFED_ET_CQ_ERR;
+ break;
+
+ case ROCE_EVENT_TYPE_SRQ_LIMIT:
+ xid = *((u32 *)val);
+ roce5_handle_srq_async_event(rdev, xid, event_type);
+ event_str_index = OFED_ET_SRQ_LIMIT;
+ break;
+
+ case ROCE_EVENT_TYPE_SRQ_CATAS_ERROR:
+ xid = *((u32 *)val);
+ roce5_handle_srq_async_event(rdev, xid, event_type);
+ event_str_index = OFED_ET_SRQ_CATAS_ERR;
+ break;
+
+ default:
+ event_str_index = to_unkown_event_str_index(event_type, val);
+ break;
+ }
+
+ return event_str_index;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_async_event
+ Description : roce5_async_event
+ Input : void *svc_hd
+ u8 event_type
+ u64 val
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_async_event(void *svc_hd, u8 event_type, u8 *val)
+{
+ int event_str_index = 0;
+ struct roce5_device *rdev = NULL;
+
+ if (svc_hd == NULL) {
+ ROCE_ERR_LIMIT("Svc_hd is null");
+ return;
+ }
+
+ rdev = (struct roce5_device *)svc_hd;
+ if (event_type <= ROCE_EVENT_TYPE_ODP_PAGE_FAULT) {
+ event_str_index =
+ roce5_async_event_handle_common(event_type, val, rdev);
+ } else {
+ event_str_index =
+ roce5_async_event_handle_extend(event_type, val, rdev);
+ }
+
+ roce5_event_report(rdev, val, event_str_index);
+}
+
+#ifdef ROCE_BONDING_EN
+void roce5_handle_bonded_port_state_event(struct roce5_device *rdev)
+{
+ struct net_device *master = netdev_master_upper_dev_get_rcu(rdev->ndev);
+ enum ib_port_state bonded_port_state = IB_PORT_NOP;
+ struct roce5_bond_device *bond_dev = NULL;
+ enum ib_port_state curr_port_state;
+ enum ib_event_type event;
+ struct roce5_bond_slave *slave = NULL;
+ u32 i;
+
+ bond_dev = rdev->bond_dev;
+ if (bond_dev == NULL) {
+ ROCE_DEV_ERR(rdev, "No bond_dev found");
+ return;
+ }
+
+ if (master == NULL) {
+ bonded_port_state = IB_PORT_DOWN;
+ } else {
+ if (netif_running(master) != 0) {
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ slave = &bond_dev->slaves[i];
+ if (slave->netdev == NULL) {
+ continue;
+ }
+
+ curr_port_state =
+ (netif_running(slave->netdev) &&
+ netif_carrier_ok(slave->netdev)) ?
+ IB_PORT_ACTIVE :
+ IB_PORT_DOWN;
+ bonded_port_state =
+ (bonded_port_state != IB_PORT_ACTIVE) ?
+ curr_port_state :
+ IB_PORT_ACTIVE;
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+ } else {
+ bonded_port_state = IB_PORT_DOWN;
+ }
+ }
+
+ if (rdev->port_state != bonded_port_state) {
+ event = (bonded_port_state == IB_PORT_ACTIVE) ?
+ IB_EVENT_PORT_ACTIVE :
+ IB_EVENT_PORT_ERR;
+ if (rdev->port_state != IB_PORT_NOP) {
+ roce5_ifconfig_up_down_event_report(rdev, event);
+ }
+ rdev->port_state = bonded_port_state;
+ }
+}
+#endif
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/event/roce_event.h b/drivers/infiniband/hw/hiroce5/kernel/base/event/roce_event.h
new file mode 100644
index 000000000..b5acc9b15
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/event/roce_event.h
@@ -0,0 +1,25 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_EVENT_H
+#define ROCE_EVENT_H
+
+#include <linux/types.h>
+
+#define ROCE_M_DELAY 100
+#define API_FORMAT_ERROR 0x2
+#define UNKNOWN_RESERVED_ERROR1 0xe
+#define QPC_LOOKUP_ERR_VALUE 0x300d00016
+
+struct roce5_aeqe_event_data {
+ u32 xid;
+
+ //microcode side by ROCE_AEQE_EVENT construct, driver side byte order differs from microcode side
+ u32 err_code : 8;
+ u32 type : 12;
+ u32 subtype : 8;
+ u32 module_type : 4;
+};
+
+#endif /* ROCE_EVENT_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_event_extension.c b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_event_extension.c
new file mode 100644
index 000000000..c33bab11a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_event_extension.c
@@ -0,0 +1,56 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+
+
+#include <linux/types.h>
+
+#include "roce_event_extension.h"
+#include "roce_aeq_format.h"
+
+int to_unkown_event_str_index(uint8_t event_type, const uint8_t *val)
+{
+ switch (event_type) {
+ case ROCE_EVENT_TYPE_OFED_NO_DEF:
+ if (*((u64 *)val) == QPC_LOOKUP_ERR_VALUE) {
+ return NON_OFED_ET_QPC_LOOKUP_ERR;
+ }
+ return NON_OFED_ET_OTHER_TYPE_ERR;
+
+ case ROCE_EVENT_TYPE_LOCAL_CATAS_ERROR:
+ return NON_OFED_ET_OTHER_TYPE_ERR;
+
+ case ROCE_EVENT_TYPE_DEBUG:
+ return NON_OFED_ET_DEBUG_ERR;
+
+ default:
+ return INVAL_ET_ERR;
+ }
+}
+
+void roce5_event_report_extend(const struct roce5_device *rdev, u8 *val,
+ int event_str_index)
+{
+ if (event_str_index == NON_OFED_ET_DEBUG_ERR) {
+ struct roce5_aeqe_event_data *data =
+ (struct roce5_aeqe_event_data *)val;
+ /* debug subtype according to ROCE_AEQE_DEBUG_SUBTYPE_E */
+ ROCE_ERR_ONCE(
+ "[non ofed event type] Debug extend event subtype 0x%x. function id: %u",
+ data->subtype, rdev->glb_func_id);
+ return;
+ }
+
+ ROCE_ERR_ONCE(
+ "[non ofed event type] Invalid extend event type error. function id: %u",
+ rdev->glb_func_id);
+}
+
+int roce5_async_event_handle_extend(u8 event_type, u8 *val,
+ struct roce5_device *rdev)
+{
+ int event_str_index = 0;
+
+ event_str_index = to_unkown_event_str_index(event_type, val);
+
+ return event_str_index;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_main_extension.c b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_main_extension.c
new file mode 100644
index 000000000..759ba598f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_main_extension.c
@@ -0,0 +1,170 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include "roce_main_extension.h"
+#include "roce_infra.h"
+#include "roce_os_compat.h"
+#include "roce_kernel_compat_gen.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+
+static struct mutex g_rdev_mutex;
+#endif
+
+void roce5_service_init_pre(void)
+{
+#ifdef ROCE_BONDING_EN
+ mutex_init(&g_rdev_mutex);
+#endif
+
+ return;
+}
+
+void roce5_lock_rdev(void)
+{
+#ifdef ROCE_BONDING_EN
+ mutex_lock(&g_rdev_mutex);
+#endif
+}
+
+void roce5_unlock_rdev(void)
+{
+#ifdef ROCE_BONDING_EN
+ mutex_unlock(&g_rdev_mutex);
+#endif
+}
+
+int roce5_get_rdev_by_uld(struct hinic5_lld_dev *lld_dev, void *uld_dev,
+ struct roce5_device **rdev,
+ struct hinic5_event_info *event)
+{
+#ifdef ROCE_BONDING_EN
+ int ret;
+
+ ret = roce5_bond_event_cfg_rdev(lld_dev, uld_dev, rdev, false);
+ if (ret != 0) {
+ return -1;
+ }
+#else
+ *rdev = (struct roce5_device *)uld_dev;
+#endif
+ return 0;
+}
+
+#ifndef ROCE_CHIP_TEST
+void roce5_init_dev_ext_handlers(struct roce5_device *rdev)
+{
+ return;
+}
+#endif
+
+int roce5_board_cfg_check(struct roce5_device *rdev)
+{
+ int ret = 0;
+ int port_num = 0;
+ int port_speed = 0;
+
+ port_num = rdev->board_info.port_num;
+ port_speed = rdev->board_info.port_speed;
+ if ((port_num == ROCE5_2_PORT_NUM) &&
+ (port_speed == ROCE5_100G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE5_2_100G_HCA;
+ } else if ((port_num == ROCE5_4_PORT_NUM) &&
+ (port_speed == ROCE5_25G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE5_4_25G_HCA;
+ } else if ((port_num == ROCE5_2_PORT_NUM) &&
+ (port_speed == ROCE5_25G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE5_2_25G_HCA;
+ } else if ((port_num == ROCE5_1_PORT_NUM) &&
+ (port_speed == ROCE5_100G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE5_1_100G_HCA;
+ } else if ((port_num == ROCE5_2_PORT_NUM) &&
+ (port_speed == ROCE5_200G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE5_2_200G_HCA;
+ } else if ((port_num == ROCE5_2_PORT_NUM) &&
+ (port_speed == ROCE5_400G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE5_2_400G_HCA;
+ } else if ((port_num == ROCE5_4_PORT_NUM) &&
+ (port_speed == ROCE5_200G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE5_4_200G_HCA;
+ } else {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid fw cfg, port_num(%d), port_speed(%d), hca_type(%d)",
+ port_num, port_speed, rdev->hw_info.hca_type);
+ ret = (-EINVAL);
+ }
+
+ return ret;
+}
+
+void *roce5_rdev_alloc_ext(void)
+{
+#if defined(HAVE__IB_ALLOC_DEVICE)
+ return (void *)ib_alloc_device(roce5_device, ib_dev);
+#else
+ return (void *)ib_alloc_device(sizeof(struct roce5_device));
+#endif
+}
+
+int roce5_set_comm_event(const struct roce5_device *rdev,
+ const struct hinic5_event_info *event)
+{
+ ROCE_DEV_INFO(rdev, "Comm event unsupported, func_id(%d), event(%d)",
+ rdev->glb_func_id, event->type);
+ return -1;
+}
+
+struct roce5_ucontext *
+roce5_queue_to_ucontext(void *ibq, struct ib_udata *udata, int q_type)
+{
+ struct roce5_ucontext *rctx = NULL;
+
+#if defined(UVERBS_IOCTL_HAVE_RDMA_UDATA_TO_DRV_CONTEXT)
+ rctx = rdma_udata_to_drv_context(udata, struct roce5_ucontext,
+ ibucontext);
+#else
+ struct ib_qp *ibqp = NULL;
+ struct ib_cq *ibcq = NULL;
+ struct ib_srq *ibsrq = NULL;
+ switch (q_type) {
+ case ROCE_Q_TYPE_QP:
+ ibqp = (struct ib_qp *)ibq;
+ rctx = to_roce5_ucontext(ibqp->uobject->context);
+ break;
+ case ROCE_Q_TYPE_CQ:
+ ibcq = (struct ib_cq *)ibq;
+ rctx = to_roce5_ucontext(ibcq->uobject->context);
+ break;
+ case ROCE_Q_TYPE_SRQ:
+ ibsrq = (struct ib_srq *)ibq;
+ rctx = to_roce5_ucontext(ibsrq->uobject->context);
+ break;
+ default:
+ ROCE_ERR("Unknown queue type(%d)", q_type);
+ break;
+ }
+#endif
+ return rctx;
+}
+
+#ifndef ROCE_VROCE_EN
+void roce5_fill_gid_entry_ext(const struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry)
+{
+ return;
+}
+
+void roce5_cfg_info_update_ext(struct roce5_device *rdev,
+ roce_get_cfg_info_resp_s *resp)
+{
+ return;
+}
+
+int roce5_add_check_ext(const struct hinic5_lld_dev *lld_dev)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_mr_extension.c b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_mr_extension.c
new file mode 100644
index 000000000..7f2e14669
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_mr_extension.c
@@ -0,0 +1,40 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+#include "roce_mr.h"
+#include "roce_kernel_compat_gen.h"
+#include "roce_main_extension.h"
+#include "roce_mr_extension.h"
+
+#ifndef ROCE_CHIP_TEST
+int roce5_check_alloc_mr_type(enum ib_mr_type mr_type)
+{
+ int ret = 0;
+
+ if (mr_type != IB_MR_TYPE_MEM_REG) {
+ ret = -EINVAL;
+ ROCE_ERR("mr_type is invalid. mr_type:%u", mr_type);
+ }
+
+ return ret;
+}
+
+enum rdma_mr_type roce5_get_mrtype(enum ib_mr_type ib_mr_type)
+{
+ switch (ib_mr_type) {
+#if defined(IB_MR_TYPE_HAVE_USER) && defined(IB_MR_TYPE_HAVE_INTEGRITY)
+ case IB_MR_TYPE_MEM_REG:
+ return RDMA_FRMR;
+ case IB_MR_TYPE_USER:
+ return RDMA_USER_MR;
+ case IB_MR_TYPE_INTEGRITY:
+ return RDMA_SIG_MR;
+#else
+ case IB_MR_TYPE_MEM_REG:
+ return RDMA_DMA_MR;
+#endif
+ default:
+ return RDMA_DMA_MR;
+ }
+}
+#endif
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_qp_extension.c b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_qp_extension.c
new file mode 100644
index 000000000..0e0170e9d
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_qp_extension.c
@@ -0,0 +1,222 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include "roce_qp_extension.h"
+#include "roce_ctx_format.h"
+#include "roce_restore.h"
+
+#ifdef ROCE_EXTEND
+#include "roce_pd.h"
+#endif
+
+int to_roce5_qp_type(enum ib_qp_type qp_type)
+{
+ switch (qp_type) {
+ case IB_QPT_RC:
+ return ROCE_QP_ST_RC;
+
+ case IB_QPT_UC:
+ return ROCE_QP_ST_UC;
+
+ case IB_QPT_UD:
+ return ROCE_QP_ST_UD;
+
+ case IB_QPT_XRC_INI:
+ case IB_QPT_XRC_TGT:
+ return ROCE_QP_ST_XRC;
+
+ case IB_QPT_GSI:
+ return ROCE_QP_ST_UD;
+
+ default:
+ return -1;
+ }
+}
+
+bool roce5_check_qp_modify_ok(enum ib_qp_state cur_state,
+ enum ib_qp_state next_state, enum ib_qp_type type,
+ enum ib_qp_attr_mask mask,
+ enum rdma_link_layer ll)
+{
+#if defined(IB_MODIFY_QP_IS_OK_HAVE_RDMA_LINK_LAYER)
+ return (bool)ib_modify_qp_is_ok(cur_state, next_state, type, mask, ll);
+#else
+ return (bool)ib_modify_qp_is_ok(cur_state, next_state, type, mask);
+#endif
+}
+
+int roce5_is_qp_normal(struct roce5_qp *rqp, struct ib_qp_init_attr *init_attr)
+{
+ return 1;
+}
+
+#ifdef ROCE_EXTEND
+static struct roce5_qp *
+roce5_cdev_lookup_and_check_rqp(struct roce5_device *rdev, u32 qpn)
+{
+ struct roce5_qp *rqp = NULL;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ ROCE_ERR("Can't find rqp according to qpn(0x%x), func_id(%d)",
+ qpn, rdev->glb_func_id);
+ return NULL;
+ }
+
+ if (rqp->qpn >= QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC) {
+ ROCE_DEV_ERR(rdev,
+ "qpn[%u] more than sqpc num offset(%d) for sqpc.",
+ rqp->qpn, QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC);
+ roce5_rqp_put(rqp);
+ return NULL;
+ }
+
+ return rqp;
+}
+
+static int roce5_alloc_sqpc(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct roce5_vbs_qp *vbs_rqp)
+{
+ cqm_qpc_mpt_s *qpc_info = NULL;
+
+ /* Call the CQM interface to allocate QPNs and QPCs */
+ /* For SQPC, do not need to allocate QPN, QPN is directly spcified in rsvd segment */
+ qpc_info = cqm5_object_qpc_mpt_create(
+ rdev->hwdev, SERVICE_T_ROCE, CQM_OBJECT_SERVICE_CTX,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.qpc_entry_sz, NULL,
+ rqp->qpn + QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC, 0, 0);
+ if (qpc_info == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create qpc by cqm object, func_id(%d), qpn(%u)",
+ rdev->glb_func_id,
+ rqp->qpn + QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC);
+ return -ENOMEM;
+ }
+
+ if (qpc_info->xid != (rqp->qpn + QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Create qpc error, func_id(%d), expect qpn(%d), actual qpn(%d)",
+ rdev->glb_func_id,
+ rqp->qpn + QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC,
+ qpc_info->xid);
+ cqm5_object_delete(&(qpc_info->object));
+ return -EFAULT;
+ }
+
+ vbs_rqp->vbs_sqpc_info = qpc_info;
+ rqp->vbs_qp_ptr = (void *)vbs_rqp;
+
+ return 0;
+}
+
+long roce5_vbs_create_sqpc(struct roce5_device *rdev, void *buf)
+{
+ struct roce5_modify_qp_vbs_cmd cmd;
+ struct roce5_vbs_qp *vbs_rqp = NULL;
+ struct roce5_qp *rqp = NULL;
+ struct roce5_pd *pd = NULL;
+ int ret;
+
+ ret = (int)copy_from_user(&cmd, buf, sizeof(cmd));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to copy data from user");
+ return (long)ret;
+ }
+
+ rqp = roce5_cdev_lookup_and_check_rqp(rdev, cmd.qpn);
+ if (rqp == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to look up rqp");
+ return -EINVAL;
+ }
+
+ vbs_rqp = (struct roce5_vbs_qp *)kzalloc(sizeof(*vbs_rqp), GFP_KERNEL);
+ if (vbs_rqp == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc vbs_rqp, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -ENOMEM;
+ goto put_rqp;
+ }
+
+ pd = roce5_get_pd(rqp);
+ ret = roce5_db_map_user(to_roce5_ucontext(pd->ibpd.uobject->context),
+ cmd.ci_record_addr, &vbs_rqp->db, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to map db page to user, func_id(%d)",
+ rdev->glb_func_id);
+ goto free_rqp;
+ }
+
+ ret = roce5_alloc_sqpc(rdev, rqp, vbs_rqp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc sqpc, func_id(%d)",
+ rdev->glb_func_id);
+ goto free_rqp;
+ }
+
+ roce5_rqp_put(rqp);
+ return 0;
+
+free_rqp:
+ kfree(vbs_rqp);
+put_rqp:
+ roce5_rqp_put(rqp);
+ return (long)ret;
+}
+#endif
+
+#ifndef ROCE_CHIP_TEST
+void roce5_set_qp_dif_attr(struct roce5_qp *rqp,
+ const struct ib_qp_init_attr *init_attr,
+ const struct roce5_device *rdev)
+{
+ if (((unsigned int)init_attr->create_flags &
+ IB_QP_CREATE_SIGNATURE_EN) != 0) {
+ rqp->signature_en = true;
+ ROCE_DEV_INFO(rdev,
+ "func(%d) qp(%u) roce5_create_qp signature_en.",
+ rdev->glb_func_id, rqp->qpn);
+ }
+ return;
+}
+#endif
+
+#ifndef ROCE_VBS_EN
+void roce5_set_attr_ext(struct roce5_qp *rqp, const struct ib_qp_attr *attr,
+ roce_verbs_qp_attr_s *qp_attr, int attr_mask)
+{
+ return;
+}
+
+void roce5_transmit_ci_record_addr_ext(struct roce5_qp *rqp,
+ roce_verbs_qp_attr_s *qp_attr)
+{
+ return;
+}
+#endif
+
+#ifndef ROCE_VBS_EN
+int roce5_modify_qp_pre_ext(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata)
+{
+ return 0;
+}
+
+void roce5_destroy_pcqc_ext(struct roce5_qp *rqp)
+{
+ return;
+}
+
+#endif
+
+#ifndef ROCE_VROCE_EN
+
+void roce5_cos_update_ext(struct roce5_device *rdev, u8 *cos,
+ enum ib_qp_type qp_type)
+{
+ *cos = *cos & 0x7;
+}
+#endif
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_srq_extension.c b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_srq_extension.c
new file mode 100644
index 000000000..7067e8c80
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/extension/roce_srq_extension.c
@@ -0,0 +1,55 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/types.h>
+#include "roce_srq_extension.h"
+
+u8 roce5_get_container_sz(u32 container_mode)
+{
+ switch (container_mode) {
+ case ROCE_SRQ_MODE_0:
+ return ROCE_SRQ_CONT_NUM_MODE0;
+ case ROCE_SRQ_MODE_1:
+ return ROCE_SRQ_CONT_NUM_MODE1;
+ case ROCE_SRQ_MODE_2:
+ return ROCE_SRQ_CONT_NUM_MODE2;
+ case ROCE_SRQ_MODE_3:
+ return ROCE_SRQ_CONT_NUM_MODE3;
+ default:
+ return ROCE_SRQ_CONT_NUM_MODE3;
+ }
+}
+
+u8 roce5_calculate_cont_th(u32 srq_limit)
+{
+ u8 cont_th = 0;
+ u32 srq_limit_tmp = srq_limit;
+
+ srq_limit_tmp >>= 1;
+ while (srq_limit_tmp != 0) {
+ srq_limit_tmp >>= 1;
+ ++cont_th;
+ }
+
+ return cont_th;
+}
+
+#ifndef ROCE_CHIP_TEST
+void roce5_srq_container_init(struct ib_srq_init_attr *init_attr,
+ struct roce5_srq *rsrq, struct roce5_device *rdev)
+{
+ rsrq->xrc_en = (init_attr->srq_type == IB_SRQT_XRC);
+
+ if (rsrq->xrc_en != 0) {
+ rsrq->container_flag = rdev->cfg_info.srq_container_en;
+ }
+ rsrq->container_mode = (rsrq->xrc_en != 0) ?
+ rdev->cfg_info.xrc_srq_container_mode :
+ rdev->cfg_info.srq_container_mode;
+ rsrq->container_warn_th =
+ roce5_calculate_cont_th(init_attr->attr.srq_limit);
+ rsrq->rqe_cnt_th = rdev->cfg_info.warn_th;
+ rsrq->container_size = roce5_get_container_sz(rsrq->container_mode);
+}
+#endif
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/mr/roce_mr.c b/drivers/infiniband/hw/hiroce5/kernel/base/mr/roce_mr.c
new file mode 100644
index 000000000..f7f9117f4
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/mr/roce_mr.c
@@ -0,0 +1,1281 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include "roce_mr.h"
+#include "roce_mr_extension.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#include "rdma_comp_mw_mr.h"
+#include "hmm_common.h"
+#include "roce_os_compat.h"
+#include "roce_uld_kernel_api.h"
+#include "roce_uld_inner.h"
+
+/* ****************************************************************************
+ Prototype : get_key_from_index
+ Description : get_key_from_index
+ Input : u32 mpt_index
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static u32 get_key_from_index(u32 mpt_index)
+{
+ /* Algorithm of mr key is obtained by index shift calculation */
+ return (mpt_index >> MR_KEY_RIGHT_SHIFT_OFS) |
+ (mpt_index << MR_KEY_LEFT_SHIFT_OFS);
+}
+
+/* ****************************************************************************
+ Prototype : convert_ib_access
+ Description : convert ib access to rdma comp access
+ Input : int access_flag
+ Output : None
+
+ 1.Date : 2015/7/16
+ Modification : Created function
+
+**************************************************************************** */
+static u32 convert_ib_access(int access_flag)
+{
+ u32 u_access_flag = (u32)access_flag;
+ u32 access;
+
+ access = (u32)((((u_access_flag & IB_ACCESS_REMOTE_ATOMIC) != 0) ?
+ RDMA_IB_ACCESS_REMOTE_ATOMIC :
+ 0) |
+ (((u_access_flag & IB_ACCESS_REMOTE_WRITE) != 0) ?
+ RDMA_IB_ACCESS_REMOTE_WRITE :
+ 0) |
+ (((u_access_flag & IB_ACCESS_REMOTE_READ) != 0) ?
+ RDMA_IB_ACCESS_REMOTE_READ :
+ 0) |
+ (((u_access_flag & IB_ACCESS_LOCAL_WRITE) != 0) ?
+ RDMA_IB_ACCESS_LOCAL_WRITE :
+ 0) |
+ (((u_access_flag & IB_ACCESS_MW_BIND) != 0) ?
+ RDMA_IB_ACCESS_MW_BIND :
+ 0) |
+ (((u_access_flag & IB_ZERO_BASED) != 0) ?
+ RDMA_IB_ACCESS_ZERO_BASED :
+ 0));
+
+ return access;
+}
+
+/* ****************************************************************************
+ Prototype : check_ib_access
+ Description : check remote access without local write
+ Input : int access_flag
+ Output : None
+
+ 1.Date : 2017/11/18
+ Modification : Created function
+
+**************************************************************************** */
+static int check_ib_access(int access_flag)
+{
+ /*
+ * Local write permission is required if remote write or
+ * remote atomic permission is also requested.
+ */
+
+ if (((((u32)access_flag) &
+ (IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_REMOTE_WRITE)) != 0) &&
+ ((((u32)access_flag) & IB_ACCESS_LOCAL_WRITE) == 0)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+u32 roce5_get_mpt_xid_mode(struct roce5_device *rdev)
+{
+ u8 mode = rdev->mpt_xid_mode;
+
+ if (mode == ROCE_MPT_XID_SEQUENTIAL)
+ return CQM_INDEX_INVALID;
+
+ return CQM_DYNAMIC_XID_MOD(CQM_XID_SEARCH_ALL, CQM_XID_LOW_BIT_0_0_1,
+ (u32)mode);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_alloc_tpt
+ Description : alloc mpt and mtt
+ Input : struct roce5_device *rdev
+ struct hmm_rdma *mr
+ u32 npages
+ u32 page_shift
+ Output : None
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_alloc_tpt(struct roce5_device *rdev, struct hmm_rdma *mr, u32 npages,
+ u32 page_shift, u32 mpt_xid_mode)
+{
+ int ret = 0;
+
+ ret = hmm_mpt_alloc_templated(rdev->hwdev, &mr->mpt, SERVICE_T_ROCE,
+ mpt_xid_mode);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc mpt, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ return ret;
+ }
+
+ mr->enabled = RDMA_MPT_EN_SW;
+
+ /* npages = 0 is a legal case, when npages = 0 or npages = 1, MTT does not need to do address translation */
+ ret = hmm_mtt_alloc(rdev->hwdev, npages, page_shift, &mr->mtt,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc mtt, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ goto err_alloc_mtt;
+ }
+
+ return 0;
+
+err_alloc_mtt:
+ hmm_mpt_free(rdev->hwdev, &mr->mpt);
+ mr->enabled = RDMA_MPT_DISABLED;
+
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_free_tpt
+ Description : free mpt and mtt
+ Input : struct roce5_device *rdev
+ struct hmm_rdma *mr
+ Output : None
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_free_tpt(struct roce5_device *rdev, struct hmm_rdma *mr)
+{
+ hmm_mtt_free(rdev->hwdev, &mr->mtt, SERVICE_T_ROCE);
+
+ hmm_mpt_free(rdev->hwdev, &mr->mpt);
+
+ mr->enabled = RDMA_MPT_DISABLED;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_set_rdma_mr
+ Description : set the member of rdma_mr
+ Input : struct hmm_rdma *mr
+ enum rdma_mr_type mr_type
+ u32 pdn
+ u64 iova
+ u64 size
+ u32 access
+ Output : None
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_set_rdma_mr(struct hmm_rdma *mr, enum rdma_mr_type mr_type, u32 pdn,
+ u64 iova, u64 size, u32 access)
+{
+ mr->iova = iova;
+ mr->size = size;
+ mr->pdn = pdn;
+ mr->access = convert_ib_access((
+ int)access); /* Convert ib permissions to rdma component permissions */
+ mr->key = get_key_from_index(
+ mr->mpt.mpt_index); /* Convert from mpt index to key */
+ mr->type = roce5_mr_type2hmm(mr_type);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_set_rdma_mw
+ Description : set the member of rdma_mw
+ Input : struct rdma_mw *mw
+ u32 pdn
+ enum ib_mw_type type
+ Output : None
+
+ 1.Date : 2016/6/25
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_set_rdma_mw(struct rdma_mw *mw, u32 pdn, enum ib_mw_type type)
+{
+ mw->enabled = RDMA_MPT_EN_SW;
+ mw->pdn = pdn;
+ mw->key = get_key_from_index(mw->mpt.mpt_index);
+ mw->type = (type == IB_MW_TYPE_1 ? RDMA_MW_TYPE_1 : RDMA_MW_TYPE_2);
+}
+#ifdef __ROCE_DFX__
+static void roce5_store_mr_list(struct roce5_device *rdev,
+ struct list_head *node)
+{
+ struct roce5_list *roce_list = NULL;
+
+ if (rdev->device_res == NULL) {
+ ROCE_INFO("Hasn't been created resource, don't need store.");
+ return;
+ }
+
+ roce_list = &rdev->device_res->mr_list;
+ mutex_lock(&roce_list->node_lock);
+ list_add(node, &roce_list->node);
+ mutex_unlock(&roce_list->node_lock);
+}
+
+static void roce5_delete_mr_list(struct roce5_device *rdev,
+ struct list_head *node)
+{
+ struct roce5_list *roce_list = NULL;
+
+ if (rdev->device_res == NULL) {
+ ROCE_INFO("Resource has been release, don't need delete.");
+ return;
+ }
+
+ roce_list = &rdev->device_res->mr_list;
+ mutex_lock(&roce_list->node_lock);
+ list_del(node);
+ mutex_unlock(&roce_list->node_lock);
+}
+#endif //__ROCE_DFX__
+
+/* ****************************************************************************
+ Prototype : roce5_get_dma_mr
+ Description : register DMA_MR
+ Input : struct ib_pd *ibpd
+ int access
+ Output : None
+
+ 1.Date : 2015/4/24
+ Modification : Created function
+
+**************************************************************************** */
+struct ib_mr *roce5_get_dma_mr(struct ib_pd *ibpd, int access)
+{
+ int ret = 0;
+ u32 mpt_xid_mode;
+ struct roce5_mr *mr = NULL;
+ struct roce5_pd *pd = NULL;
+ struct roce5_device *rdev = NULL;
+
+ if ((ibpd == NULL) || (check_ib_access(access) != 0)) {
+ ret = -EINVAL;
+ ROCE_ERR("Invalid Param.p1:%d", access);
+ goto err_out;
+ }
+
+ pd = to_roce5_pd(ibpd);
+ rdev = to_roce5_dev(ibpd->device);
+
+ mr = (struct roce5_mr *)kzalloc(sizeof *mr, GFP_KERNEL);
+ if (mr == NULL) {
+ ret = -ENOMEM;
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc memory for dma mr, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_out;
+ }
+
+ mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE;
+ mpt_xid_mode = roce5_get_mpt_xid_mode(rdev);
+ ret = roce5_alloc_tpt(rdev, &mr->rdmamr, 0, 0, mpt_xid_mode);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc mpt and mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_alloc_tpt;
+ }
+
+ /* Set the content in rdma_mr */
+ roce5_set_rdma_mr(&mr->rdmamr, RDMA_DMA_MR, pd->pdn, 0ULL,
+ ROCE_DMA_MR_SIZE, (u32)access);
+
+ ret = hmm_rdma_enable_mpt(rdev->lld_dev, rdev->hwdev, &(mr->rdmamr),
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to enable mpt of DMA mr, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_enable_mpt;
+ }
+#ifdef __ROCE_DFX__
+ roce5_store_mr_list(rdev, &mr->node);
+#endif
+ mr->ibmr.lkey = mr->rdmamr.key;
+ mr->ibmr.rkey = mr->rdmamr.key;
+ mr->ibmr.device = ibpd->device;
+
+ ROCE_DEV_INFO(rdev, "Roce reg dma mr success, mr mpt index is %u",
+ mr->rdmamr.mpt.mpt_index);
+
+ return &mr->ibmr;
+
+err_enable_mpt:
+ roce5_free_tpt(rdev, &mr->rdmamr);
+
+err_alloc_tpt:
+ kfree(mr);
+
+err_out:
+ return (struct ib_mr *)ERR_PTR((long)ret);
+}
+
+static int roce5_alloc_priv_pages(struct ib_device *ibdev, struct roce5_mr *rmr,
+ u32 max_pages)
+{
+ int ret;
+
+ rmr->page_map_size =
+ roundup(max_pages * sizeof(u64), ROCE5_MR_PAGES_ALIGN);
+ rmr->pages = (__be64 *)(void *)(uintptr_t)get_zeroed_page(GFP_KERNEL);
+ if (rmr->pages == NULL) {
+ ROCE_ERR("Failed to alloc rmr->pages");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ rmr->page_map = dma_map_single(ibdev->dev.parent, rmr->pages,
+ rmr->page_map_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(ibdev->dev.parent, rmr->page_map) != 0) {
+ ROCE_ERR("Failed to do dma mapping");
+ ret = -ENOMEM;
+ goto err_free_pages;
+ }
+
+ return 0;
+
+err_free_pages:
+ free_page((unsigned long)(uintptr_t)(void *)rmr->pages);
+
+err_out:
+ return ret;
+}
+
+void roce5_free_frmr_umem(struct ib_umem **fumem, int fumem_nr)
+{
+ int i;
+
+ ROCE_INFO("%d frmr umems to be free.", fumem_nr);
+ for (i = 0; i < fumem_nr; i++) {
+ ib_umem_release(fumem[i]);
+ }
+}
+
+static void roce5_free_priv_pages(struct roce5_mr *rmr)
+{
+ struct ib_device *ib_dev = rmr->ibmr.device;
+
+ if (rmr->pages != NULL) {
+ ib_dev = rmr->ibmr.device;
+ dma_unmap_single(ib_dev->dev.parent, rmr->page_map,
+ rmr->page_map_size, DMA_TO_DEVICE);
+ free_page((unsigned long)(uintptr_t)(void *)rmr->pages);
+ rmr->pages = NULL;
+ }
+}
+
+static int roce5_alloc_mr_param_validate(const struct ib_pd *ibpd,
+ enum ib_mr_type mr_type,
+ u32 max_num_sg)
+{
+ int ret = 0;
+
+ if (ibpd == NULL) {
+ ret = -EINVAL;
+ ROCE_ERR("Ibpd is null");
+ goto err_out;
+ }
+
+ ret = roce5_check_alloc_mr_type(mr_type);
+ if (ret != 0) {
+ ret = -EINVAL;
+ ROCE_ERR("mr_type is invalid");
+ goto err_out;
+ }
+
+ if (max_num_sg >= ROCE_FRMR_MAX_PAGES) {
+ ROCE_ERR("Invalid max_num_sg(%d)", max_num_sg);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ return ret;
+}
+
+static int roce5_alloc_mr_param_check(struct roce5_device *rdev,
+ struct roce5_mr **mr, u32 max_num_sg)
+{
+ *mr = (struct roce5_mr *)kzalloc(sizeof(struct roce5_mr), GFP_KERNEL);
+ if ((*mr) == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc mr memory, func(%d)",
+ rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ (*mr)->max_pages = max_num_sg;
+ return 0;
+}
+/* ****************************************************************************
+ Prototype : roce5_alloc_mr
+ Description : register DMA_MR
+ Input : struct ib_pd *ibpd
+ enum ib_mr_type mr_type
+ u32 max_num_sg
+ Output : None
+
+ 1.Date : 2015/4/24
+ Modification : Created function
+
+**************************************************************************** */
+struct ib_mr *roce5_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
+ u32 max_num_sg)
+{
+ int ret = 0;
+ u16 sign_val = 0;
+ u32 mpt_xid_mode;
+ struct roce5_mr *mr = NULL;
+ struct roce5_pd *pd = NULL;
+ struct roce5_device *rdev = NULL;
+
+ ret = roce5_alloc_mr_param_validate(ibpd, mr_type, max_num_sg);
+ if (ret != 0) {
+ goto err_out;
+ }
+
+ pd = to_roce5_pd(ibpd);
+ rdev = to_roce5_dev(ibpd->device);
+
+ ret = roce5_alloc_mr_param_check(rdev, &mr, max_num_sg);
+ if (ret != 0) {
+ goto err_out;
+ }
+
+ mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE;
+ mpt_xid_mode = roce5_get_mpt_xid_mode(rdev);
+
+ ret = roce5_alloc_tpt(rdev, &mr->rdmamr, max_num_sg, 0,
+ mpt_xid_mode); //alloc mptc and mtt
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc tpt, func(%d)",
+ rdev->glb_func_id);
+ goto err_alloc_tpt;
+ }
+
+ ret = roce5_alloc_priv_pages(ibpd->device, mr,
+ max_num_sg); //alloc memory to store pa
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc memory, func(%u)",
+ rdev->glb_func_id);
+ goto err_alloc_priv_pages;
+ }
+
+ roce5_set_rdma_mr(&mr->rdmamr, roce5_get_mrtype(mr_type), pd->pdn, 0ULL,
+ max_num_sg * (1 << PAGE_SHIFT),
+ ROCE5_MR_DEFAULT_ACCESS);
+
+#ifdef SIGN_MTT_EN
+ /*
+ MTT table entry of bit[11:2] used for fill in addr_signature, to hardware used for check MTT table entry complete validity. [1:1] is vmr, indicates current page whether be swap out.
+ bit[0:0] is vld bit indicates pointed by of next one level DMTT or Data Buffer of GPA whether valid. use sign_val record [11:0] this 12bit data, exist mr in.
+ send down frmr wqe after chip will do dma use pbl table fill MTT table, here need in advance calculate check value, in roce5_set_page() in write pbl table.
+ */
+ sign_val = (u16)(hmm_gen_mtt_sign(mr->rdmamr.mtt.mtt_paddr,
+ mr->rdmamr.mtt.mtt_type) &
+ 0xffff);
+#endif
+ mr->sign_val = ((sign_val << 1) | MTT_PA_VALID);
+
+ ret = hmm_rdma_enable_mpt(rdev->lld_dev, rdev->hwdev, &(mr->rdmamr),
+ HINIC5_CHANNEL_ROCE); // send to chip by cmdq
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to enable mpt, func(%d)",
+ rdev->glb_func_id);
+ goto err_enale_mpt;
+ }
+
+#ifdef __ROCE_DFX__
+ roce5_store_mr_list(rdev, &mr->node);
+#endif
+
+ mr->ibmr.lkey = mr->rdmamr.key;
+ mr->ibmr.rkey = mr->rdmamr.key;
+
+ return &mr->ibmr;
+
+err_enale_mpt:
+ roce5_free_priv_pages(mr);
+
+err_alloc_priv_pages:
+ roce5_free_tpt(rdev, &mr->rdmamr);
+
+err_alloc_tpt:
+ kfree(mr);
+
+err_out:
+ return (struct ib_mr *)ERR_PTR((long)ret);
+}
+
+static int roce5_set_page(struct ib_mr *ibmr, u64 addr)
+{
+ struct roce5_mr *rmr = NULL;
+
+ if (ibmr == NULL) {
+ ROCE_ERR("Ibmr is null");
+ return -EINVAL;
+ }
+
+ rmr = to_roce5_mr(ibmr);
+ if (ROCE_UNLIKELY(rmr->npages >= rmr->max_pages)) {
+ ROCE_ERR("Invalid npages(0x%x), can't set page", rmr->npages);
+ return -ENOMEM;
+ }
+
+ rmr->pages[rmr->npages] = cpu_to_be64(addr | rmr->sign_val);
+ rmr->npages++;
+
+ return 0;
+}
+
+/* RoCE supports FRMR, for at privileged user, can via post send WR of way for at at free status of MR perform fast register.
+ here need in advance via input parameter of sgl available physical page
整 理 in pbl table 里, later via frmr wqe send down. */
+int roce5_map_kernel_frmr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
+ int sg_nents, unsigned int *sg_offset)
+{
+ int ret;
+ struct roce5_mr *rmr = NULL;
+
+ /* sg_offset can be null */
+ if ((ibmr == NULL) || (sg == NULL)) {
+ ROCE_ERR("Ibmr or sg is null");
+ return -EINVAL;
+ }
+
+ rmr = to_roce5_mr(ibmr);
+ rmr->npages = 0;
+
+ if (ROCE_UNLIKELY(((u32)sg_nents) > rmr->max_pages)) {
+ ROCE_ERR("Invalid sg_nents(0x%x), max(0x%x)", sg_nents,
+ rmr->max_pages);
+ return -EINVAL;
+ }
+
+ ib_dma_sync_single_for_cpu(ibmr->device, rmr->page_map,
+ rmr->page_map_size, DMA_TO_DEVICE);
+
+ ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, roce5_set_page);
+
+ ib_dma_sync_single_for_device(ibmr->device, rmr->page_map,
+ rmr->page_map_size, DMA_TO_DEVICE);
+
+ return ret;
+}
+
+static int roce5_umem_write_mtt_check(const struct roce5_device *rdev,
+ const struct mtt *mtt,
+ const struct ib_umem *umem)
+{
+ if ((rdev == NULL) || (mtt == NULL) || (umem == NULL)) {
+ ROCE_ERR("Rdev or mtt or umem is null");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_umem_write_mtt_update(struct roce5_device *rdev,
+ struct mtt *mtt, struct ib_umem *umem,
+ u64 *page_list, bool use_huge)
+{
+ int ret = 0;
+ u32 npages = 0; /* The number of recorded pages */
+ u32 start_index = 0; /* page need to be written to mtt */
+ struct ib_block_iter biter;
+
+ rdma_umem_for_each_dma_block(umem, &biter, BIT(mtt->buf_page_shift)) {
+ page_list[npages++] = rdma_block_iter_dma_address(&biter);
+ /* The size of the memory pointed to by page_list is one page, which can store up to PAGE_SIZE / sizeof(u64)
+ pas. After a page is full, mtt needs to be written */
+ if (npages == BIT(mtt->mtt_page_shift) / PA_SIZE) {
+ ret = hmm_mtt_write(rdev->hwdev, mtt, start_index,
+ npages, page_list, SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to write mtt, ret(%d), start_index(%u), func_id(%u).",
+ ret, start_index, rdev->glb_func_id);
+ goto out;
+ }
+ start_index += npages;
+ npages = 0;
+ }
+ }
+
+ if (npages != 0) {
+ ret = hmm_mtt_write(rdev->hwdev, mtt, start_index, npages,
+ page_list, SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to write mtt, ret(%d), start_index(%u), func_id(%u).",
+ ret, start_index, rdev->glb_func_id);
+ goto out;
+ }
+ }
+
+out:
+ return ret;
+}
+
+int roce5_umem_write_mtt(struct roce5_device *rdev, struct mtt *mtt,
+ struct ib_umem *umem, bool use_huge)
+{
+ int ret = 0;
+ u64 *page_list = NULL; /* page_list to write to mtt */
+
+ ret = roce5_umem_write_mtt_check(rdev, mtt, umem);
+ if (ret != 0) {
+ return ret;
+ }
+
+ page_list = (u64 *)kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (page_list == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc memory for page list, func_id(%d)",
+ rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ ret = roce5_umem_write_mtt_update(rdev, mtt, umem, page_list, use_huge);
+ if (ret != 0) {
+ ROCE_ERR("Failed to write mtt.");
+ }
+
+ kfree(page_list);
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_buf_write_mtt
+ Description : roce5_buf_write_mtt
+ Input : struct roce5_device *rdev
+ struct mtt *mtt
+ struct tag_cqm_buf *buf
+ Output : None
+
+ 1.Date : 2015/4/24
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_buf_write_mtt(struct roce5_device *rdev, struct mtt *mtt,
+ struct tag_cqm_buf *buf)
+{
+ u64 *page_list = NULL;
+ int ret = 0;
+ u32 i = 0;
+
+ if ((rdev == NULL) || (mtt == NULL) || (buf == NULL)) {
+ ROCE_ERR("Rdev or mtt or buf is null");
+ return (-EINVAL);
+ }
+
+ page_list =
+ (u64 *)kzalloc(buf->buf_number * sizeof *page_list, GFP_KERNEL);
+ if (page_list == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc memory for page list, func_id(%d)",
+ rdev->glb_func_id);
+ return (-ENOMEM);
+ }
+
+ /* Each buf is written to MTT as a page, buf_size is 2^n times PAGE_SIZE */
+ for (i = 0; i < buf->buf_number; ++i) {
+ page_list[i] = buf->buf_list[i].pa;
+ }
+
+ ret = hmm_mtt_write(rdev->hwdev, mtt, 0, buf->buf_number, page_list,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write mtt, func_id(%d)",
+ rdev->glb_func_id);
+ }
+
+ kfree(page_list);
+
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_is_umem_dma_contiguous
+ Description : Determine whether the input ib_umem occupies a contiguous
+ region in DMA address space, i.e., all scatter-gather entries
+ are adjacent in DMA addresses and the total length matches
+ umem->length.
+ Input : struct roce5_device *rdev
+ struct ib_umem *umem
+ Output : bool - true if the umem is DMA-contiguous, false otherwise
+ 1.Date : 2026/3/12
+ Modification : Created function
+**************************************************************************** */
+static inline bool roce5_is_umem_dma_contiguous(struct roce5_device *rdev,
+ struct ib_umem *umem)
+{
+ struct scatterlist *sg = NULL;
+ int i;
+ dma_addr_t expected_dma, dma;
+ uint64_t total_len = 0, len;
+
+#if defined(IB_UMEM_HAVE_SG_APPEND_TABLE)
+ sg = umem->sgt_append.sgt.sgl;
+#else
+ sg = umem->sg_head.sgl;
+#endif
+
+ expected_dma = sg_dma_address(sg);
+
+#if defined(IB_UMEM_HAVE_SG_APPEND_TABLE)
+ for_each_sg(umem->sgt_append.sgt.sgl, sg, umem->sgt_append.sgt.nents, i)
+#else
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i)
+#endif
+ {
+ dma = sg_dma_address(sg);
+ len = sg_dma_len(sg);
+
+ if (i > 0 && dma != expected_dma) {
+ ROCE_DEV_WARN(
+ rdev,
+ "Enable huge page, but discontinuity at sg[%d]: expected 0x%llx, got 0x%llx\n",
+ i, (u64)expected_dma, (u64)dma);
+ return false;
+ }
+
+ total_len += len;
+ expected_dma = dma + len;
+ }
+
+ /* Check the total length. */
+ if (total_len != umem->length) {
+ ROCE_DEV_WARN(rdev, "Total length %llu != umem length(%zu)\n",
+ total_len, umem->length);
+ return false;
+ }
+
+ return true;
+}
+
+static int roce5_get_page_info(struct roce5_device *rdev, struct ib_umem *umem,
+ u32 *npages, u32 *page_shift, u64 virt_addr)
+{
+ *page_shift = roce5_umem_get_buf_page_shift(rdev, umem, virt_addr);
+ *npages = roce5_umem_get_mtt_npages(rdev, umem, *page_shift);
+
+ if (rdev->huge_page_en && *page_shift > PAGE_SHIFT) {
+ if (*page_shift != PAGE_SHIFT_2MB) {
+ ROCE_DEV_WARN(
+ rdev,
+ "RoCE reg huge MR expect page_size(2MB), but found %lu.",
+ BIT(*page_shift));
+ }
+ ROCE_DEV_INFO(rdev,
+ "RoCE reg huge MR: npages(%u), page_shift(%u).",
+ *npages, *page_shift);
+ return ROCE_USE_HUGEPAGE;
+ }
+
+ return ROCE_NOT_USE_HUGEPAGE;
+}
+
+int roce5_user_mr_reg(struct roce5_device *rdev, struct roce5_mr *mr, u32 pdn,
+ u64 virt_addr, u64 length, int access)
+{
+ int ret = 0;
+ u32 npages = 0;
+ u32 page_shift = PAGE_SHIFT;
+ u32 mpt_xid_mode;
+ int use_huge;
+ struct hinic5_hwdev *hwdev = (struct hinic5_hwdev *)rdev->hwdev;
+
+ if (hwdev == NULL) {
+ ROCE_ERR("hwdev is null");
+ return 0;
+ }
+
+ mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE;
+
+ use_huge = roce5_get_page_info(rdev, mr->umem, &npages, &page_shift,
+ virt_addr);
+ mpt_xid_mode = roce5_get_mpt_xid_mode(rdev);
+
+ ret = roce5_alloc_tpt(rdev, &mr->rdmamr, npages, page_shift,
+ mpt_xid_mode);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc mpt and mtt, func_id(%d)",
+ hinic5_global_func_id(hwdev));
+ goto err_alloc_tpt;
+ }
+
+ roce5_set_rdma_mr(&mr->rdmamr, RDMA_USER_MR, pdn, virt_addr, length,
+ (u32)access);
+
+ ret = roce5_umem_write_mtt(rdev, &mr->rdmamr.mtt, mr->umem, use_huge);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write mtt, func_id(%d)",
+ hinic5_global_func_id(hwdev));
+ goto err_write_mtt;
+ }
+
+ ret = hmm_rdma_enable_mpt(rdev->lld_dev, hwdev, &mr->rdmamr,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to enable mpt of user mr, func_id(%d)",
+ hinic5_global_func_id(hwdev));
+ goto err_write_mtt;
+ }
+
+ return 0;
+
+err_write_mtt:
+ roce5_free_tpt(rdev, &mr->rdmamr);
+
+err_alloc_tpt:
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_reg_user_mr
+ Description : register MR for user
+ Input : struct ib_pd *ibpd
+ u64 start
+ u64 length
+ u64 virt_addr
+ int access
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2015/4/24
+ Modification : Created function
+
+**************************************************************************** */
+struct ib_mr *roce5_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length,
+ u64 virt_addr, int access,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_mr *mr = NULL;
+ struct roce5_device *rdev = NULL;
+ struct roce5_pd *rpd = to_roce5_pd(ibpd);
+ roce_user_handle_t *handle = NULL;
+
+ if (ibpd == NULL) {
+ ret = -EINVAL;
+ ROCE_ERR("Ibpd is null");
+ goto err_out;
+ }
+
+ rdev = to_roce5_dev(ibpd->device);
+
+ mr = (struct roce5_mr *)kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (mr == NULL) {
+ ret = -ENOMEM;
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc memory for roce mr, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_out;
+ }
+#if defined(IB_UMEM_GET_PEER)
+ mr->umem = roce5_mr_umem_get_peer(rdev, (size_t)length, access, start,
+ udata, true);
+#else
+ mr->umem = roce5_umem_get(&rdev->ib_dev, ibpd->uobject->context, start,
+ (size_t)length, access, 0);
+#endif
+ if (IS_ERR(mr->umem)) {
+ handle = (roce_user_handle_t *)kzalloc(
+ sizeof(roce_user_handle_t), GFP_KERNEL);
+ if (handle == NULL) {
+ ret = -ENOMEM;
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc memory for handle, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_get_umem;
+ }
+ handle->magic = ROCE_ULD_HANDLE_MAGIC_NUM;
+ handle->rdev = rdev;
+ handle->mr = mr;
+ handle->virt_addr = virt_addr;
+ handle->length = length;
+ handle->pdn = rpd->pdn;
+ handle->access = access;
+
+ mr->david_en = true;
+ mr->private_data = (void *)handle;
+
+ /* call ULD interface */
+ ret = roce5_uld_reg_user_mr((roce_uld_handle)handle);
+ if (ret != 0) {
+ ROCE_DEV_WARN(
+ rdev,
+ "Failed to reg user mr uld, func_id(%d), ret(%d), err(%d)",
+ rdev->glb_func_id, ret, (int)PTR_ERR(mr->umem));
+ ret = (int)PTR_ERR(mr->umem);
+ kfree(handle);
+ mr->private_data = NULL;
+ goto err_get_umem;
+ }
+
+ mr->umem = NULL;
+ } else {
+ ret = roce5_user_mr_reg(rdev, mr, rpd->pdn, virt_addr, length,
+ access);
+ if (ret != 0) {
+ goto err_mr_update;
+ }
+ }
+#ifdef __ROCE_DFX__
+ roce5_store_mr_list(rdev, &mr->node);
+#endif
+ mr->ibmr.lkey = mr->rdmamr.key;
+ mr->ibmr.rkey = mr->rdmamr.key;
+
+ ROCE_DEV_INFO(rdev, "Roce reg user mr success, mr mpt index is %u",
+ mr->rdmamr.mpt.mpt_index);
+
+ return &mr->ibmr;
+
+err_mr_update:
+ ib_umem_release(mr->umem);
+
+err_get_umem:
+ kfree(mr);
+
+err_out:
+ return (struct ib_mr *)ERR_PTR((long)ret);
+}
+
+int roce5_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_mr *mr = NULL;
+ struct roce5_device *rdev = NULL;
+
+ if (ibmr == NULL) {
+ ROCE_ERR("Ibmr is null");
+ return -EINVAL;
+ }
+
+ mr = to_roce5_mr(ibmr);
+ rdev = to_roce5_dev(ibmr->device);
+
+ if (mr->rdmamr.type == HMM_RDMA_FRMR) {
+ roce5_free_priv_pages(mr);
+ }
+
+ if (mr->david_en) {
+ if (mr->private_data == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid parameter, private data is NULL.");
+ return -EINVAL;
+ }
+
+ ret = roce5_uld_dereg_user_mr(
+ (roce_uld_handle)mr->private_data);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "roce dereg user mr uld failed, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ kfree(mr->private_data);
+ mr->private_data = NULL;
+ } else {
+ ret = hmm_rdma_disable_mpt(rdev->lld_dev, rdev->hwdev,
+ &mr->rdmamr, SERVICE_T_ROCE,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Mr may has mw bind on it, ret(%d), mr_key(%#x), func_id(%d)",
+ ret, mr->rdmamr.key, rdev->glb_func_id);
+ if (ret == (-CMDQ_TIMEOUT)) {
+ rdev->dev_status_to_ofed =
+ ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+ return ret;
+ }
+
+ roce5_free_tpt(rdev, &mr->rdmamr);
+
+ ib_umem_release(mr->umem);
+ }
+
+ if (mr->fumem_nr != 0) {
+ roce5_free_frmr_umem(mr->fumem, mr->fumem_nr);
+ mr->fumem_nr = 0;
+ }
+#ifdef __ROCE_DFX__
+ roce5_delete_mr_list(rdev, &mr->node);
+#endif
+
+ kfree(mr);
+
+ return 0;
+}
+
+int roce5_dereg_mr_ofa(struct ib_mr *ibmr)
+{
+ return roce5_dereg_mr(ibmr, NULL);
+}
+
+static void roce5_err_enable_mpt_handler(void *hwdev, struct roce5_mw *mw)
+{
+ hmm_mpt_free(hwdev, &mw->rdmamw.mpt);
+ mw->rdmamw.enabled = RDMA_MPT_DISABLED;
+ return;
+}
+
+static void roce5_mw2hmm_adapter(const struct rdma_mw *rdmamw,
+ struct hmm_rdma *hmmrdma)
+{
+ hmmrdma->mpt = rdmamw->mpt;
+ hmmrdma->key = rdmamw->key;
+ hmmrdma->pdn = rdmamw->pdn;
+ hmmrdma->type = (rdmamw->type == RDMA_MW_TYPE_1) ? HMM_RDMA_MW_TYPE_1 :
+ HMM_RDMA_MW_TYPE_2;
+ hmmrdma->enabled = rdmamw->enabled;
+}
+
+int roce5_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
+{
+ int ret;
+ u32 mpt_xid_mode;
+ struct roce5_mw *mw = NULL;
+ struct roce5_pd *pd = NULL;
+ struct roce5_device *rdev = NULL;
+ struct hmm_rdma hmmrdma = { 0 };
+
+ if (ibmw == NULL) {
+ ROCE_ERR("Ibmw is null");
+ return -EINVAL;
+ }
+
+ mw = to_roce5_mw(ibmw);
+ pd = to_roce5_pd(ibmw->pd);
+ rdev = to_roce5_dev(ibmw->device);
+
+ mpt_xid_mode = roce5_get_mpt_xid_mode(rdev);
+ ret = hmm_mpt_alloc_templated(rdev->hwdev, &mw->rdmamw.mpt,
+ SERVICE_T_ROCE, mpt_xid_mode);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc mpt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err;
+ }
+
+ roce5_set_rdma_mw(&mw->rdmamw, pd->pdn, ibmw->type);
+ roce5_mw2hmm_adapter(&mw->rdmamw, &hmmrdma);
+
+ ret = hmm_rdma_enable_mpt(rdev->lld_dev, rdev->hwdev, &hmmrdma,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to enable mpt of mw, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ if (ret == (-CMDQ_TIMEOUT)) {
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+ goto err_enable_mpt;
+ }
+
+ mw->rdmamw.enabled = hmmrdma.enabled;
+ mw->ibmw.rkey = mw->rdmamw.key;
+ return 0;
+err_enable_mpt:
+ roce5_err_enable_mpt_handler(rdev->hwdev, mw);
+err:
+ return ret;
+}
+
+struct ib_mw *roce5_alloc_mw_ofa(struct ib_pd *ibpd, enum ib_mw_type type,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_mw *mw = NULL;
+
+ if (ibpd == NULL) {
+ ret = -EINVAL;
+ ROCE_ERR("Ibpd is null");
+ goto out;
+ }
+
+ mw = (struct roce5_mw *)kzalloc(sizeof *mw, GFP_KERNEL);
+ if (mw == NULL) {
+ ret = -ENOMEM;
+ ROCE_ERR("Failed to alloc memory for roce mw");
+ goto out;
+ }
+
+ /* Unreasonable, but for code reuse, driver associate the OFED resource in advance. */
+ mw->ibmw.pd = ibpd;
+ mw->ibmw.device = ibpd->device;
+ mw->ibmw.type = type;
+ ret = roce5_alloc_mw(&mw->ibmw, udata);
+ if (ret != 0) {
+ kfree(mw);
+ }
+
+out:
+ return (ret != 0 ? (struct ib_mw *)ERR_PTR((long)ret) : &mw->ibmw);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_dealloc_mw
+ Description : dealloc mw and release related resource
+ Input : struct ib_mw *ibmw
+ Output : None
+
+ 1.Date : 2015/4/24
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_dealloc_mw(struct ib_mw *ibmw)
+{
+ int ret = 0;
+ struct roce5_mw *mw = NULL;
+ struct roce5_device *rdev = NULL;
+ struct hmm_rdma hmmrdma;
+
+ if (ibmw == NULL) {
+ ROCE_ERR("Ibmw is null");
+ return -EINVAL;
+ }
+
+ mw = to_roce5_mw(ibmw);
+ rdev = to_roce5_dev(ibmw->device);
+ roce5_mw2hmm_adapter(&mw->rdmamw, &hmmrdma);
+
+ ret = hmm_rdma_disable_mpt(rdev->lld_dev, rdev->hwdev, &hmmrdma,
+ SERVICE_T_ROCE, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to disable mpt of mw, func_id(%d)",
+ rdev->glb_func_id);
+ if (ret == (-CMDQ_TIMEOUT)) {
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+ return ret;
+ }
+ mw->rdmamw.enabled = hmmrdma.enabled;
+
+ hmm_mpt_free(rdev->hwdev, &mw->rdmamw.mpt);
+ mw->rdmamw.enabled = RDMA_MPT_DISABLED;
+
+ return ret;
+}
+
+int roce5_dealloc_mw_ofa(struct ib_mw *ibmw)
+{
+ int ret = 0;
+ struct roce5_mw *mw = NULL;
+
+ ret = roce5_dealloc_mw(ibmw);
+ if (ret == 0) {
+ mw = to_roce5_mw(ibmw);
+ kfree(mw);
+ }
+
+ return ret;
+}
+
+int roce5_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
+ struct ib_mr_status *mr_status)
+{
+ int ret = 0;
+ struct roce5_mr *mr = NULL;
+
+ if ((ibmr == NULL) || (mr_status == NULL)) {
+ ROCE_ERR("ibmr or mr_status is NULL ptr.");
+ return -EINVAL;
+ }
+
+ mr = to_roce5_mr(ibmr);
+ if ((check_mask & (~IB_MR_CHECK_SIG_STATUS)) != 0) {
+ ROCE_ERR("check_mask(%#x) invalid", check_mask);
+ return -EINVAL;
+ }
+
+ if (mr->signature_en == 0) {
+ ROCE_ERR("mr not configure dif info");
+ ret = -EINVAL;
+ return ret;
+ }
+
+ mr->sig.sig_status_checked = true;
+ mr_status->fail_status = 0;
+
+ /* If err does not exist, return 0 */
+ if (!mr->sig.sig_err_exists) {
+ return 0;
+ }
+
+ ret = memcpy_s((void *)&mr_status->sig_err, sizeof(struct ib_sig_err),
+ (void *)&mr->sig.sig_err_item,
+ sizeof(struct ib_sig_err));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy sig_err.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ mr->sig.sig_err_exists = false;
+ mr_status->fail_status |= IB_MR_CHECK_SIG_STATUS;
+
+ return 0;
+}
+
+/**
+ * @brief Get mpt by index. When querying succeeded, you have to call roce5_mpt_put() to free
+ the cqm_obj_mpt. But there is no need to call roce5_mpt_put() if querying failed.
+ * @return Success: return the mpt. Failure: return NULL.
+ */
+struct mpt *roce5_get_mpt_by_index(struct roce5_device *rdev, u32 mpt_index)
+{
+ cqm_object_s *cqm_obj_mpt = NULL;
+ cqm_qpc_mpt_s *cqm_mpt = NULL;
+ struct mpt *mpt = NULL;
+
+ cqm_obj_mpt =
+ cqm5_object_get(rdev->hwdev, CQM_OBJECT_MPT, mpt_index, false);
+ if (cqm_obj_mpt == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Can't find mpt according to index(0x%x), func_id(%d)",
+ mpt_index, rdev->glb_func_id);
+ return NULL;
+ }
+
+ cqm_mpt = container_of(cqm_obj_mpt, cqm_qpc_mpt_s, object);
+ mpt = (struct mpt *)cqm_mpt->priv;
+ if (mpt == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to convert obj to mpt.");
+ cqm5_object_put(cqm_obj_mpt);
+ }
+
+ return mpt;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/mr/roce_mr.h b/drivers/infiniband/hw/hiroce5/kernel/base/mr/roce_mr.h
new file mode 100644
index 000000000..3124c2470
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/mr/roce_mr.h
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_MR_H
+#define ROCE_MR_H
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_umem.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+
+#include "roce.h"
+
+#include "hinic5_hmm.h"
+#include "hinic5_rdma.h"
+#include "rdma_comp.h"
+
+#include "securec.h"
+
+#define ROCE5_MR_DEFAULT_ACCESS \
+ (IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_WRITE | \
+ IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_ATOMIC)
+
+#define ROCE5_MR_PAGES_ALIGN 64U
+#define ROCE5_FRMR_UMEM_NUM 512
+#define ROCE5_SIZE_2M (2 * 1024 * 1024)
+
+struct roce5_sig_ctx {
+ struct ib_sig_attrs sig_attrs; /* recorded when submitting WR */
+ struct ib_sig_err
+ sig_err_item; /* Get information configuration from CQE when polling CQE */
+ bool sig_status_checked; /* Indicates whether the status is checked */
+ bool sig_err_exists; /* Indicates if an error exists */
+ u32 sig_err_count; /* Count the number of wrong CQEs */
+};
+
+/* uld service can extension structure space */
+#define ROCE_MR_ULD_DEF_LEN 24
+#define ROCE_NOT_USE_HUGEPAGE 0
+#define ROCE_USE_HUGEPAGE 1
+
+/* used for verify uld access whether memory stomping */
+#define ROCE_RMR_MAGIC 0x1317F73a
+struct roce5_mr_uld_def {
+ u8 self_def[ROCE_MR_ULD_DEF_LEN];
+};
+
+struct roce5_mr {
+ struct ib_mr ibmr; /* mr structure provided by ofed */
+ struct ib_umem *
+ umem; /* Maintain the structure where the user-mode allocated buffer */
+ struct ib_umem **fumem; /* used to frmr only */
+ struct hmm_rdma rdmamr; /* mr structure provided by rdma component */
+ struct roce5_sig_ctx sig; /* Record signature related information */
+ u16 signature_en; /* Whether the logo contains signature information */
+ u16 sign_val; /* MTT entry [11:0] */
+ __be64 *pages;
+ u32 npages;
+ u32 fumem_nr;
+ u32 max_pages;
+ size_t page_map_size;
+ dma_addr_t page_map;
+#ifdef __ROCE_DFX__
+ struct list_head node;
+#endif // __ROCE_DFX__
+ bool david_en; /* Indicate whether the mr is a david mr */
+ void *private_data; /* private data for driver */
+ u32 user_data_len; /* length of user data which stored in struct hmm_rdma */
+ struct roce5_mr_uld_def uld_def;
+ u32 rmr_magic; /* preventstop uld access memory stomping, support up to 24B space */
+};
+
+struct roce5_mw {
+ struct ib_mw ibmw; /* mw structure provided by ofed */
+ struct rdma_mw rdmamw; /* mw structure provided by rdma component */
+};
+
+int roce5_alloc_tpt(struct roce5_device *rdev, struct hmm_rdma *mr, u32 npages,
+ u32 page_shift, u32 mpt_xid_mode);
+void roce5_free_tpt(struct roce5_device *rdev, struct hmm_rdma *mr);
+void roce5_set_rdma_mr(struct hmm_rdma *mr, enum rdma_mr_type mr_type, u32 pdn,
+ u64 iova, u64 size, u32 access);
+void roce5_free_frmr_umem(struct ib_umem **fumem, int fumem_nr);
+struct mpt *roce5_get_mpt_by_index(struct roce5_device *rdev, u32 mpt_index);
+static inline void roce5_mpt_put(struct mpt *rmpt)
+{
+ if (rmpt == NULL) {
+ return;
+ }
+ cqm5_object_put(&((cqm_qpc_mpt_s *)(rmpt->mpt_object))->object);
+}
+
+static inline int roce5_mr_type2hmm(enum rdma_mr_type mr_type)
+{
+ int mr_type_convert_table[] = {
+ [RDMA_DMA_MR] = HMM_RDMA_DMA_MR,
+ [RDMA_USER_MR] = HMM_RDMA_USER_MR,
+ [RDMA_FRMR] = HMM_RDMA_FRMR,
+ [RDMA_FMR] = HMM_RDMA_FMR,
+ [RDMA_PHYS_MR] = HMM_RDMA_PHYS_MR,
+ [RDMA_RSVD_LKEY] = HMM_RDMA_RSVD_LKEY,
+ [RDMA_SIG_MR] = HMM_RDMA_SIG_MR,
+ [RDMA_INDIRECT_MR] = HMM_RDMA_INDIRECT_MR,
+ [RDMA_ODP_IMPLICIT_MR] = HMM_RDMA_ODP_IMPLICIT_MR,
+ [RDMA_ODP_EXPLICIT_MR] = HMM_RDMA_ODP_EXPLICIT_MR,
+ };
+
+ return mr_type_convert_table[mr_type];
+}
+
+#endif // __ROCE_MR_H_
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_post.h b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_post.h
new file mode 100644
index 000000000..28a092b29
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_post.h
@@ -0,0 +1,171 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+
+
+#ifndef ROCE_POST_H
+#define ROCE_POST_H
+
+#include <linux/types.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "roce_wqe_format.h"
+
+#define ROCE_SQ_DOORBELL_TYPE_2 2
+#define ROCE_SQ_DOORBELL_TYPE_23 23
+#define ROCE_SQ_DOORBELL_TYPE_21 21
+
+#define ROCE_DWQE_DDB_TYPE 3 /* RoCE direct wqe of DDB type */
+
+#define ROCE_IMM_EXT_LEN 4
+#define ROCE_TASK_SEG_ALIGN 8
+
+enum roce_tsl_8_byte_aligned_size_e {
+ ROCE_SEND_LOCAL_WQE_TSL = 2,
+ ROCE_RDMA_WQE_TSL = 4,
+ ROCE_ATOMIC_CWP_WQE_TSL = 6,
+ ROCE_UD_WQE_COM_TSL = 8
+};
+
+enum {
+ ROCE_WQE_OPCODE_SEND = 0x00,
+ ROCE_WQE_OPCODE_SEND_INVAL = 0x01,
+ ROCE_WQE_OPCODE_SEND_IMM = 0x02,
+
+ ROCE_WQE_OPCODE_RDMA_WRITE = 0x04,
+ ROCE_WQE_OPCODE_RDMA_WRITE_IMM = 0x05,
+
+ ROCE_WQE_OPCODE_RDMA_READ = 0x08,
+
+ ROCE_WQE_OPCODE_ATOMIC_CMP_SWP = 0x0c,
+ ROCE_WQE_OPCODE_ATOMIC_FETCH_ADD = 0x0d,
+ ROCE_WQE_OPCODE_MASKED_ATOMIC_CMP_SWP = 0x0e,
+ ROCE_WQE_OPCODE_MASKED_ATOMIC_FETCH_ADD = 0x0f,
+
+ ROCE_WQE_OPCODE_FRMR = 0x10,
+ ROCE_WQE_OPCODE_LOCAL_INVAL = 0x11,
+ ROCE_WQE_OPCODE_BIND_MW = 0x12,
+ ROCE_WQE_OPCODE_REG_SIG_MR =
+ 0x13, /* Extended for further local opreation */
+};
+
+#define ROCE_KERNEL_OPCODE_NUM (ROCE_WQE_OPCODE_REG_SIG_MR + 1)
+
+enum {
+ ROCE_DWQE_DB_SUBTYPE_SEND = 0x1,
+ ROCE_DWQE_DB_SUBTYPE_SEND_IMM = 0x2,
+ ROCE_DWQE_DB_SUBTYPE_RDMA_WRITE = 0x3,
+ ROCE_DWQE_DB_SUBTYPE_RDMA_WRITE_IMM = 0x4,
+ ROCE_DWQE_DB_SUBTYPE_RDMA_READ = 0x5,
+ ROCE_DWQE_DB_SUBTYPE_ATOMIC_CMP_SWP = 0x6,
+ ROCE_DWQE_DB_SUBTYPE_ATOMIC_FETCH_ADD = 0x7
+};
+
+/* UD send WQE task seg1 */
+struct roce_wqe_ud_tsk_seg_cycle1 {
+ roce_wqe_tsk_com_seg_u common;
+
+ /* DW0 */
+ u32 data_len;
+
+ /* DW1 */
+ u32 immdata_invkey;
+
+ /* DW2 */
+ union {
+ struct {
+ u32 pd : 18;
+ u32 rsvd0 : 6;
+ u32 stat_rate : 4; /* 0: No limit on the static rate (100% port speed)
+ 1-6: reserved
+ 7: 2.5 Gb/s. 8: 10 Gb/s. 9: 30 Gb/s. 10: 5 Gb/s. 11: 20 Gb/s.
+ 12: 40 Gb/s. 13: 60 Gb/s. 14: 80 Gb/s.15: 120 Gb/s. */
+ u32 rsvd1 : 3;
+ u32 fl : 1;
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+ u32 hop_limit : 8;
+ u32 sgid_idx : 7;
+ u32 rsvd0 : 1;
+ u32 port : 4;
+ u32 rsvd1 : 4;
+ u32 tc : 8;
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ union {
+ struct {
+ u32 flow_label : 20;
+ u32 rsvd0 : 4;
+ u32 smac_index : 3;
+ u32 rsvd1 : 5;
+ } bs;
+ u32 value;
+ } dw4;
+
+ /* DW5~8 */
+ u8 dgid[16];
+
+ /* DW9 */
+ union {
+ struct {
+ u32 dst_qp : 24;
+ u32 rsvd : 8;
+ } bs;
+ u32 value;
+ } dw9;
+
+ /* DW10 */
+ u32 qkey;
+};
+
+/* UD send WQE task seg2; */
+struct roce_wqe_ud_tsk_seg_cycle2 {
+ /* DW0 */
+ union {
+ struct {
+ u32 dmac_h16 : 16;
+ u32 vlan_id : 12;
+ u32 cfi : 1;
+ u32 vlan_prio : 3;
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ u32 dmac_l32;
+};
+
+struct roce5_post_send_normal_param {
+ struct roce5_wqe_ctrl_seg *ctrl_seg;
+ union roce5_wqe_tsk_com_seg *tsk_com_seg;
+ u32 wqe_size;
+ u8 *wqe;
+ struct roce_wqe_data_seg *dseg;
+ u32 wr_num; /* record posted WR numbers */
+ u32 index; /* WQEBB id */
+ int inline_flag; /* Inline flag */
+ u32 data_len;
+ u32 *data_len_addr;
+ u32 sq_rmd_size;
+ s32 opcode;
+ s32 cycle;
+ u32 sq_wqe_ssn;
+ struct roce5_wqe_ctrl_seg ctrl_seg_tmp;
+
+ unsigned long flags; /* type required by kernel API */
+};
+
+typedef struct tag_roce_opcode_attr {
+ uint32_t rsvd : 31;
+ uint32_t remote_opcode : 1;
+} roce_opcode_attr_s;
+
+#endif /* ROCE_POST_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp.h b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp.h
new file mode 100644
index 000000000..7088cd550
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp.h
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_QP_H
+#define ROCE_QP_H
+
+#include <linux/types.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "hinic5_rdma.h"
+#include "hinic5_cqm.h"
+
+#include "roce.h"
+#include "roce_cq.h"
+#include "roce_db.h"
+#include "roce_pd.h"
+#include "roce_compat.h"
+#include "roce_npu_cmd_qp_defs.h"
+#include "roce_wqe_base_format.h"
+#include "roce_post.h"
+#include "roce_mix.h"
+#include "roce_xqe_format.h"
+#include "roce_qp_ctx_format.h"
+#include "roce_cq_format.h"
+#include "roce_srq_format.h"
+#include "roce_com.h"
+#include "roce_obj_ext.h"
+#include "roce_kernel_compat_gen.h"
+
+#define ROCE_RQ_MIN_SGE 4
+#define ROCE_RQ_MID_SGE 8
+#define ROCE_RQ_MAX_SGE 16
+
+#define ROCE_WQE_NEXT_SGE_INVALID (1UL << 31)
+
+#define ROCE_RDMARC_DESTROY_CHECK_VALUE 0xcece5a5a
+
+#define RDMARC_NUM_PER_CACHELINE 8
+#define RDMARC_TABLE_ENTRY_SIZE 32
+#define ROCE_QP_MAX_PFETCH_MTT_LAYER 3
+#define ROCE_QP_MAX_TIMER_NUM 5
+
+#define ROCE_QP_SMI_QP_NUM 0x0
+#define ROCE_QP_GSI_QP_NUM 0x1
+#define ROCE_QP_INVLID_QP_NUM CQM_INDEX_INVALID
+
+#define ROCE_QP_MAX_DWQE_SIZE 256
+#define ROCE_QP_DEFAULT_WQE_SHIFT 6
+
+#define ROCE_QP_MODIFY_CMD_OUT_BUF_SIZE 512
+
+#define ROCE_QP_STATE_MEM_INIT 0xa
+
+#define ROCE_UD_MAX_INLINE_LEN_SUB 48
+
+#define ROCE_QP_GPA_SIG_LEN 3
+#define ROCE_WR_MIN_NUM 2
+
+#define ROCE_QPC_PMTU_TRANSLATE(pmtu) (((1U << ((pmtu)-1)) - 1) & 0xf)
+
+#define ROCE_QP_OPTPAR_ALT_ADDR_PATH (1 << 0)
+#define ROCE_QP_OPTPAR_RRE (1 << 1)
+#define ROCE_QP_OPTPAR_RAE (1 << 2)
+#define ROCE_QP_OPTPAR_RWE (1 << 3)
+#define ROCE_QP_OPTPAR_PKEY_INDEX (1 << 4)
+#define ROCE_QP_OPTPAR_Q_KEY (1 << 5)
+#define ROCE_QP_OPTPAR_RNR_TIMEOUT (1 << 6)
+#define ROCE_QP_OPTPAR_PRIMARY_ADDR_PATH (1 << 7)
+#define ROCE_QP_OPTPAR_SRA_MAX (1 << 8)
+#define ROCE_QP_OPTPAR_RRA_MAX (1 << 9)
+#define ROCE_QP_OPTPAR_PM_STATE (1 << 10)
+#define ROCE_QP_OPTPAR_RETRY_COUNT (1 << 11)
+#define ROCE_QP_OPTPAR_RNR_RETRY (1 << 12)
+#define ROCE_QP_OPTPAR_ACK_TIMEOUT (1 << 13)
+#define ROCE_QP_OPTPAR_SCHED_QUEUE (1 << 14)
+#define ROCE_QP_OPTPAR_COUNTER_INDEX (1 << 15)
+
+#define roce5_LB1_MASK_1825V100 0x7
+
+enum roce_qp_state {
+ ROCE_QP_STATE_RST = 0,
+ ROCE_QP_STATE_INIT = 1,
+ ROCE_QP_STATE_RTR = 2,
+ ROCE_QP_STATE_RTS = 3,
+ ROCE_QP_STATE_SQER = 4,
+ ROCE_QP_STATE_SQD = 5,
+ ROCE_QP_STATE_ERR = 6,
+ ROCE_QP_STATE_SQ_DRAINING = 7,
+ ROCE_QP_STATE_NUM
+};
+
+enum {
+ ROCE_QP_PM_MIGRATED = 0x3,
+ ROCE_QP_PM_ARMED = 0x0,
+ ROCE_QP_PM_REARM = 0x1
+};
+
+enum { ROCE_QP_NO_SRQ, ROCE_QP_HAS_SRQ };
+
+enum { ROCE_QP = 0, ROCE_QP_EXT };
+
+struct roce5_wq {
+ u64 *wrid;
+ spinlock_t lock;
+ u32 wqebb_cnt;
+ u32 max_post;
+ u32 max_sge;
+ u32 offset;
+ u32 wqe_shift;
+ u32 head;
+ u32 tail;
+};
+
+struct roce5_sqp_attr {
+ int pkey_index;
+ u32 qkey;
+ u32 send_psn;
+};
+
+#define ROCE_RQP_ULD_DEF_LEN 64
+#define ROCE_RQP_MAGIC 0x5a5b5c5d
+struct roce5_rqp_uld_def {
+ u8 uld_def[ROCE_RQP_ULD_DEF_LEN];
+};
+
+struct roce5_qp {
+ struct ib_qp ibqp;
+ u32 qpn;
+ struct roce5_db db;
+ cqm_queue_s *qp_buf_info;
+ cqm_qpc_mpt_s *qpc_info;
+ struct roce5_wq rq;
+ u32 sq_signal_bits;
+ unsigned int sq_next_wqe;
+ u32 sq_max_wqes_per_wr;
+ struct roce5_wq sq;
+ struct ib_umem *umem;
+ struct mtt mtt;
+ struct roce5_buf buf;
+ int buf_size;
+ struct mutex mutex;
+ u32 xrcdn;
+ u8 port;
+ u8 atomic_rd_en;
+ u8 qp_state;
+ u8 qp_ext;
+ u32 qp_type;
+ u32 max_inline_data;
+ int max_dwqe_size;
+ u32 sq_wqe_ssn;
+ struct rdma_rdmarc rdmarc;
+ u16 rsp_depth;
+ u8 sl;
+ bool has_rq;
+ u8 *sq_head_addr;
+ u8 *sq_tail_addr;
+ bool signature_en;
+ u8 pi_on_chip;
+ u8 double_sgl_mode;
+ u8 ext_mtu;
+ u8 ext_mtu_mode;
+
+ u8 db_sgid_index;
+ u8 db_path_mtu;
+ u8 db_cos;
+ u8 shadow;
+
+ struct roce5_sqp_attr *sqp_attr;
+
+ u32 qid;
+ u32 local_comm_id; /* used by NOF AA to reuse qpn when disconnection happens */
+ u32 remote_comm_id;
+ void *wb_va; /* used for xrc */
+ dma_addr_t wb_dma; /* used for xrc */
+ u32 shadow_vfid;
+
+ /* hot-plug record */
+ struct list_head qps_list;
+ struct list_head cq_recv_list;
+ struct list_head cq_send_list;
+#if defined(ROCE_VBS_EN) || defined(ROCE_EXTEND)
+ void *vbs_qp_ptr;
+#endif
+#ifdef ROCE_BONDING_EN
+ u32 tx_hash_value;
+#endif
+
+ struct roce5_obj_ext obj_ext;
+
+ struct roce5_rqp_uld_def
+ uld_def; /* must placed at qp_magic before, preventstop uld access memory stomping, support up to 64B space */
+ u32 rqp_magic;
+};
+
+typedef struct tag_roce_modify_qp_param {
+ u32 optpar;
+ roce_verbs_qp_attr_s qp_attr;
+ roce_verbs_cmd_qp_modify_rsp_s modify_rsp;
+} roce_modify_qp_param_s;
+
+void roce5_qp_async_event(struct roce5_device *rdev, struct roce5_qp *qp,
+ int type);
+
+void roce5_free_opt_rdmarc(struct roce5_qp *rqp);
+void roce5_set_opt_rdmarc(struct rdma_rdmarc *rdmarc, u16 depth,
+ roce_verbs_qp_attr_s *qp_attr);
+void roce5_get_cqs(struct roce5_qp *rqp, struct roce5_cq **send_cq,
+ struct roce5_cq **recv_cq);
+int roce5_qp_modify_2rst_cmd(struct roce5_device *rdev, u32 qpn);
+int roce5_qp_cache_out_cmd(struct roce5_device *rdev, struct roce5_qp *rqp);
+struct roce5_pd *roce5_get_pd(struct roce5_qp *rqp);
+bool roce5_sqp_check(const struct roce5_qp *rqp);
+void *roce5_get_wqe(struct roce5_qp *rqp, u32 offset);
+int roce5_wq_overflow(struct roce5_wq *wq, u32 wr_num, struct ib_cq *ibcq);
+void roce5_set_data_seg(struct roce_wqe_data_seg *dseg, struct ib_sge *sge);
+void roce5_qpc_to_be(roce_verbs_qp_attr_s *qp_attr, struct roce5_qp *rqp,
+ u32 *be_ctx);
+void roce5_qp_rst2init(struct roce5_qp *rqp, const struct ib_qp_attr *attr,
+ roce_verbs_qp_attr_s *qp_attr);
+
+int roce5_send_qp_lb_cmd(u32 qpn, struct roce5_device *rdev, u8 cmd,
+ cqm_cmd_buf_s *buf_in, cqm_cmd_buf_s *buf_out,
+ u32 timeout);
+
+int roce5_qp_query(struct roce5_device *rdev, u32 qpn, u32 *context,
+ int qpc_size);
+int roce5_post_send_standard(struct ib_qp *ibqp, const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr);
+void qpc_seg_to_le32(struct roce5_qp_context *be_ctx,
+ struct roce5_qp_context *le_ctx, u32 srq_vld);
+void roce5_be32_2_le32(void *context, u32 *le_ctx, u32 ctx_size);
+
+int roce5_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr);
+
+int roce5_post_send_ofa(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr);
+struct roce5_qp *roce5_get_rqp_by_qpn(struct roce5_device *rdev, u32 qpn);
+static inline void roce5_rqp_put(struct roce5_qp *rqp)
+{
+ if (rqp == NULL) {
+ return;
+ }
+ cqm5_object_put(&rqp->qpc_info->object);
+}
+
+#define ROCE_UD_MTU_SHIFT 4 /* 4K mtu */
+static inline void roce5_set_sq_db(struct roce5_device *rdev,
+ struct roce5_qp *rqp,
+ struct roce_sq_db_seg *db,
+ unsigned int index)
+{
+ db->dw0.bs.qpn = rqp->qpn & 0xfffff;
+ db->dw0.bs.ctx_size = 1; /* 512B */
+ db->dw0.bs.cp_flag = 0;
+ db->dw0.bs.cos = rqp->db_cos;
+ if (ROCE5_SUPPORT_SQ_DB_TYPE_21(rdev) != 0) {
+ db->dw0.bs.type = ROCE_SQ_DOORBELL_TYPE_21;
+ } else if (ROCE5_SUPPORT_SQ_DB_TYPE_MSG_V2(rdev) != 0) {
+ db->dw0.bs.type = ROCE_SQ_DOORBELL_TYPE_23;
+ } else {
+ db->dw0.bs.type = ROCE_SQ_DOORBELL_TYPE_2;
+ }
+
+ db->dw1.bs.pi = ((index & 0xffff) >> 8) & 0xff; /* 8bits */
+ db->dw1.bs.sub_type = 0;
+ db->dw1.bs.mtu_shift = rqp->db_path_mtu & 0x7;
+ db->dw1.bs.sgid_index = rqp->db_sgid_index;
+ if (rqp->qp_type == IB_QPT_RC) {
+ } else if (rqp->qp_type == IB_QPT_UD || rqp->qp_type == IB_QPT_GSI) {
+ db->dw1.bs.mtu_shift = ROCE_UD_MTU_SHIFT;
+ } else if (rqp->qp_type == IB_QPT_XRC_INI ||
+ rqp->qp_type == IB_QPT_XRC_TGT) {
+ db->dw1.bs.xrc_vld = 1;
+ }
+
+ db->dw0.value = roce5_convert_be32(db->dw0.value);
+ db->dw1.value = roce5_convert_be32(db->dw1.value);
+}
+
+static inline int roce5_write_sq_db(struct roce5_device *rdev,
+ struct roce5_qp *rqp, u32 index,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ union roce_sq_db sq_db;
+
+ ret = memset_s(&sq_db.sq_db_val, sizeof(u64), 0, sizeof(u64));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memset sq_db.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ roce5_set_sq_db(rdev, rqp, &sq_db.sq_db_seg, index);
+
+ if (udata == NULL) {
+ *(rqp->db.db_record) = cpu_to_be32(index & 0xffff);
+ }
+
+ wmb();
+ ret = cqm5_ring_hardware_db(rdev->hwdev, SERVICE_T_ROCE, index & 0xff,
+ sq_db.sq_db_val);
+
+ /*
+ * Make sure doorbells don't leak out of SQ spinlock
+ * and reach the HCA out of order.
+ */
+ wmb();
+ return ret;
+}
+
+#if defined(IB_QP_CREATE_FLAGS_HAVE_INTEGRITY_EN)
+#define IB_QP_CREATE_SIGNATURE_EN IB_QP_CREATE_INTEGRITY_EN
+#endif
+#endif // ROCE_QP_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_create.c b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_create.c
new file mode 100644
index 000000000..6adbe787c
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_create.c
@@ -0,0 +1,1506 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "roce_compat.h"
+
+#include "roce.h"
+#include "roce_infra.h"
+#include "roce_mix.h"
+#include "roce_mr.h"
+#include "roce_user.h"
+#include "roce_xrc.h"
+#include "roce_pd.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_qp.h"
+#include "roce_qp_extension.h"
+#include "roce_main_extension.h"
+#include "roce_aeq_format.h"
+#include "roce_restore.h"
+#include "roce_os_compat.h"
+#include "roce_cc_format.h"
+#include "roce_uld_inner.h"
+#include "roce_uld_kernel_api.h"
+#include "roce_qp_inner.h"
+#include "roce_com.h"
+#include "roce_qp_ext.h"
+
+#include "hinic5_hmm.h"
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+
+#include "securec.h"
+
+/* ****************************************************************************
+ Prototype : roce5_check_rq_size
+ Description : roce5_check_rq_size
+ Input : struct roce5_device *rdev
+ struct roce5_qp *rqp
+ struct ib_qp_cap *cap
+ bool has_rq
+ Output : None
+
+ 1.Date : 2017/4/27
+ Modification : Created function
+**************************************************************************** */
+static int roce5_check_rq_size(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_qp_init_attr *init_attr, bool has_rq)
+{
+ u32 max_sge_num;
+ struct ib_qp_cap *cap = &init_attr->cap;
+
+ max_sge_num = rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_rq_sg;
+ if ((cap->max_recv_wr >
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_wqes) ||
+ (cap->max_recv_sge > max_sge_num)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to check rq size, over range, func_id(%d), attr max_recv_wr(%d), cap max_wqes(%d), \
+ attr max_recv_sge(%d), cap max_sge_num(%d)",
+ rdev->glb_func_id, cap->max_recv_wr,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_wqes,
+ cap->max_recv_sge, max_sge_num);
+ return -EINVAL;
+ }
+
+ if (has_rq && ((cap->max_recv_wr == 0) || (cap->max_recv_sge == 0))) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Has rq, cap->max_recv_wr(%d), cap->max_recv_sge(%d), func_id(%d)",
+ cap->max_recv_wr, cap->max_recv_sge, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if ((!has_rq) && (cap->max_recv_wr != 0)) {
+ ROCE_DEV_ERR(rdev,
+ "Not has rq, cap->max_recv_wr(%d), func_id(%d).",
+ cap->max_recv_wr, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_set_rq_size
+ Description : roce5_set_rq_size
+ Input : struct roce5_device *rdev
+ struct roce5_qp *rqp
+ struct ib_qp_cap *cap
+ bool is_user
+ bool has_rq
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+**************************************************************************** */
+/* ****************************************************************************
+*
+* 1 there is SQ or RQ
+* SQ/RQ depth must be power of 2
+* if max_send_wr=0, no need to alloc buf for SQ/RQ
+
+* RQ WQE SIZE equals 64 or128
+* SQ WQE SIZE equals multi of wqebb size
+
+* SQ max_gs, max 8 and min 0
+* RQ max_gs, can be 4 or 8, but can not be 0.
+
+* 2 there is no SQ or RQ
+* all related params should be 0
+*
+
+**************************************************************************** */
+static int roce5_set_rq_size(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_qp_init_attr *init_attr, bool is_user,
+ bool has_rq)
+{
+ int ret;
+ u32 wqebb_num = 0;
+ u32 sge_total_len = 0;
+ u32 page_size;
+ struct ib_qp_cap *cap = &init_attr->cap;
+
+ page_size = roce5_get_page_size(rdev, true);
+
+ ret = roce5_check_rq_size(rdev, rqp, init_attr, has_rq);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to check rq size, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ if (has_rq) {
+ wqebb_num = ROCE_MAX(2U, cap->max_recv_wr);
+ rqp->rq.wqebb_cnt =
+ (u32)(ROCE_ROUNDUP_POW_OF_TWO(wqebb_num) & 0xffffffff);
+
+ /* RQ SGE range [0,4] select 4,[5,8] select 8 */
+ rqp->rq.max_sge =
+ (cap->max_recv_sge <= ROCE_RQ_MIN_SGE) ?
+ ROCE_RQ_MIN_SGE :
+ ((cap->max_recv_sge <= ROCE_RQ_MID_SGE) ?
+ ROCE_RQ_MID_SGE :
+ ROCE_RQ_MAX_SGE);
+
+ sge_total_len = (u32)((u32)rqp->rq.max_sge *
+ sizeof(struct roce_wqe_data_seg));
+ rqp->rq.wqe_shift = (u32)ROCE_ILOG2(sge_total_len);
+
+ if ((u32)((u32)rqp->rq.wqebb_cnt
+ << (unsigned)rqp->rq.wqe_shift) < page_size) {
+ rqp->rq.wqebb_cnt =
+ (page_size >> (unsigned)rqp->rq.wqe_shift);
+ }
+
+ /* leave userspace return values as they were, so as not to break ABI */
+ if (is_user) {
+ rqp->rq.max_post =
+ ROCE_MIN(rdev->rdma_cap.dev_rdma_cap
+ .roce_own_cap.max_wqes,
+ rqp->rq.wqebb_cnt);
+ cap->max_recv_wr = (u32)rqp->rq.max_post;
+ cap->max_recv_sge = (u32)rqp->rq.max_sge;
+ } else {
+ rqp->rq.max_post =
+ ROCE_MIN(rdev->rdma_cap.dev_rdma_cap
+ .roce_own_cap.max_wqes,
+ rqp->rq.wqebb_cnt);
+ cap->max_recv_wr = (u32)rqp->rq.max_post;
+ cap->max_recv_sge =
+ ROCE_MIN((u32)rqp->rq.max_sge,
+ rdev->rdma_cap.dev_rdma_cap
+ .roce_own_cap.max_rq_sg);
+ }
+ } else {
+ rqp->rq.wqebb_cnt = 0;
+ rqp->rq.max_sge = 0;
+ rqp->rq.wqe_shift = ROCE_QP_DEFAULT_WQE_SHIFT;
+ rqp->rq.max_post = 0;
+ cap->max_recv_sge = 0;
+ }
+
+ rqp->rq.head = 0;
+ rqp->rq.tail = 0;
+
+ return 0;
+}
+
+static int roce5_set_user_sq_size_check(struct roce5_device *rdev,
+ const struct ib_qp_cap *cap,
+ const struct roce5_qp *rqp)
+{
+ u32 ud_max_inline_size;
+
+ if (cap->max_send_wr >
+ (rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_wqes)) {
+ ROCE_DEV_ERR(rdev, "Log_sq_bb_count over range, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if (rqp->qp_type == IB_QPT_UD) {
+ ud_max_inline_size =
+ (rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_sq_inline_data_sz >
+ ROCE_UD_MAX_INLINE_LEN_SUB) ?
+ (rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_sq_inline_data_sz -
+ ROCE_UD_MAX_INLINE_LEN_SUB) :
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_sq_inline_data_sz;
+ } else {
+ ud_max_inline_size = rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_sq_inline_data_sz;
+ }
+
+ /* RC:192B inline data, UD:176B */
+ if (cap->max_inline_data > ud_max_inline_size) {
+ ROCE_DEV_ERR(rdev, "SQ max inline data over range, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+/* ****************************************************************************
+ Prototype : roce5_set_user_sq_size
+ Description : roce5_set_user_sq_size
+ Input : struct roce5_device *rdev
+ struct ib_qp_cap *cap
+ struct roce5_qp *rqp
+ struct roce5_create_qp *ucmd
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_set_user_sq_size(struct roce5_device *rdev,
+ struct ib_qp_cap *cap, struct roce5_qp *rqp,
+ struct create_qp_cmd *ucmd)
+{
+ u32 tmp_max_sq_wqe_sz = 0;
+ u32 sq_buf_sz = 0;
+ int ret = 0;
+ u32 page_size;
+
+ page_size = roce5_get_page_size(rdev, true);
+
+ ret = roce5_set_user_sq_size_check(rdev, cap, rqp);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ /* between max and min */
+ tmp_max_sq_wqe_sz =
+ (u32)(ROCE_ROUNDUP_POW_OF_TWO(
+ rdev->rdma_cap.max_sq_desc_sz) &
+ 0xffffffff);
+ if ((ucmd->log_sq_stride > ROCE_ILOG2(tmp_max_sq_wqe_sz)) ||
+ (ucmd->log_sq_stride <
+ ROCE_ILOG2(rdev->rdma_cap.wqebb_size))) {
+ ROCE_DEV_ERR(
+ rdev,
+ "WQE size invalid, func_id(%d) log_sq_stride:%d wqebb_size:%d tmp_max_sq_wqe_sz:%d",
+ rdev->glb_func_id, ucmd->log_sq_stride,
+ rdev->rdma_cap.wqebb_size, tmp_max_sq_wqe_sz);
+ return -EINVAL;
+ }
+
+ rqp->sq.wqebb_cnt = (u32)(1U << ucmd->log_sq_bb_count);
+ rqp->sq.wqe_shift = ucmd->log_sq_stride;
+
+ if ((u32)((u64)rqp->sq.wqebb_cnt
+ << (unsigned)rqp->sq.wqe_shift) < page_size) {
+ rqp->sq.wqebb_cnt =
+ (page_size >> (unsigned)rqp->sq.wqe_shift);
+ }
+
+ sq_buf_sz = (u32)ROCE_ALIGN(
+ (u64)rqp->sq.wqebb_cnt << (unsigned)rqp->sq.wqe_shift,
+ page_size);
+ rqp->buf_size =
+ (int)ROCE_ALIGN(((unsigned)sq_buf_sz +
+ ((unsigned)rqp->rq.wqebb_cnt
+ << (unsigned)rqp->rq.wqe_shift)),
+ page_size);
+
+ rqp->sq.offset = 0;
+ rqp->rq.offset = sq_buf_sz;
+
+ rqp->max_inline_data = (u32)cap->max_inline_data;
+ } else {
+ rqp->sq.wqebb_cnt = 0;
+ rqp->sq.wqe_shift = ucmd->log_sq_stride;
+ rqp->buf_size = 0;
+ rqp->sq.offset = 0;
+ rqp->rq.offset = 0;
+ rqp->max_inline_data = 0;
+ cap->max_inline_data = 0;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_send_wqe_overhead
+ Description : roce5_send_wqe_overhead
+ Input : enum ib_qp_type qp_type
+ Output : None
+
+ 1.Date : 2015/5/7
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_send_wqe_overhead(enum ib_qp_type qp_type)
+{
+ switch (qp_type) {
+ case IB_QPT_RC:
+ return sizeof(struct roce5_wqe_ctrl_seg) +
+ sizeof(struct roce_wqe_frmr_tsk_seg);
+
+ case IB_QPT_UC:
+ return sizeof(struct roce5_wqe_ctrl_seg) +
+ sizeof(struct roce_wqe_send_tsk_seg);
+
+ case IB_QPT_UD:
+ return sizeof(struct roce5_wqe_ctrl_seg) +
+ sizeof(struct roce_wqe_ud_tsk_seg);
+
+ case IB_QPT_GSI:
+ return sizeof(struct roce5_wqe_ctrl_seg) +
+ sizeof(struct roce_wqe_ud_tsk_seg);
+
+ case IB_QPT_XRC_TGT:
+ return 0;
+
+ case IB_QPT_XRC_INI:
+ return sizeof(struct roce5_wqe_ctrl_seg) +
+ sizeof(struct roce_wqe_frmr_tsk_seg);
+
+ default:
+ ROCE_ERR("Not supported this qp_type(%d)", qp_type);
+ return -1;
+ }
+}
+
+static int roce5_set_kernel_sq_size_check(const struct roce5_device *rdev,
+ const struct ib_qp_cap *cap,
+ int *sq_max_wqe_size,
+ enum ib_qp_type qp_type)
+{
+ int wqe_overhead = 0;
+ int ret = 0;
+
+ if (cap->max_send_wr >
+ (u32)rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_wqes) {
+ ROCE_DEV_ERR(rdev, "SQ WR over range, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if (cap->max_send_sge > rdev->rdma_cap.max_sq_sg) {
+ ROCE_DEV_ERR(rdev, "SQ SGE over range, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if (cap->max_inline_data >
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_sq_inline_data_sz) {
+ ROCE_DEV_ERR(rdev, "SQ max inline data over range, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ wqe_overhead = roce5_send_wqe_overhead(qp_type);
+ if (wqe_overhead < 0) {
+ ROCE_DEV_ERR(rdev, "Invalid service type(%d), func_id(%d)",
+ (int)qp_type, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ *sq_max_wqe_size = ROCE_MAX((int)(cap->max_send_sge *
+ sizeof(struct roce_wqe_data_seg)),
+ (int)cap->max_inline_data) +
+ wqe_overhead;
+ if (*sq_max_wqe_size > (int)rdev->rdma_cap.max_sq_desc_sz) {
+ ROCE_DEV_ERR(
+ rdev,
+ "SQ WQE size over range, func_id(%d) max_send_sge:%u,max_inline_data:%u,"
+ "wqe_overhead:%d,sq_max_wqe_size:%d,max_sq_desc_sz:%u",
+ rdev->glb_func_id, cap->max_send_sge,
+ cap->max_inline_data, wqe_overhead, *sq_max_wqe_size,
+ rdev->rdma_cap.max_sq_desc_sz);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+/* ****************************************************************************
+ Prototype : roce5_set_kernel_sq_size
+ Description : roce5_set_kernel_sq_size
+ Input : struct roce5_device *rdev
+ struct ib_qp_cap *cap
+ enum roce5_qp_type qp_type
+ struct roce5_qp *rqp
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_set_kernel_sq_size(struct roce5_device *rdev,
+ struct ib_qp_cap *cap,
+ enum ib_qp_type qp_type,
+ struct roce5_qp *rqp)
+
+{
+ u32 sq_buf_sz = 0;
+ int sq_max_wqe_size = 0;
+ int ret = 0;
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ ret = roce5_set_kernel_sq_size_check(rdev, cap,
+ &sq_max_wqe_size, qp_type);
+ if (ret != 0) {
+ return ret;
+ }
+
+ rqp->sq.wqe_shift = (u32)ROCE_ILOG2(rdev->rdma_cap.wqebb_size);
+ rqp->sq_max_wqes_per_wr = (u32)ROCE_DIV_ROUND_UP(
+ (unsigned)sq_max_wqe_size,
+ (u32)(1UL << (unsigned)rqp->sq.wqe_shift));
+
+ /*
+ * As one wqebb ought to be reserved for invalidate wqebb, 1 is added to sq.wqebb_cnt here
+ * to satisfy the actual IB_MAD_QP_SEND_SIZE set by applications
+ */
+ rqp->sq.wqebb_cnt =
+ (u32)((u32)cap->max_send_wr * rqp->sq_max_wqes_per_wr +
+ 1);
+ rqp->sq.wqebb_cnt =
+ (u32)(ROCE_ROUNDUP_POW_OF_TWO(rqp->sq.wqebb_cnt) &
+ 0xffffffff);
+
+ if ((u32)((u64)rqp->sq.wqebb_cnt << (u32)rqp->sq.wqe_shift) <
+ PAGE_SIZE) {
+ rqp->sq.wqebb_cnt =
+ (PAGE_SIZE >> ((u32)rqp->sq.wqe_shift));
+ }
+
+ rqp->sq.max_sge =
+ (u32)(((u64)rqp->sq_max_wqes_per_wr
+ << (unsigned)rqp->sq.wqe_shift) -
+ (unsigned)roce5_send_wqe_overhead(qp_type));
+ rqp->sq.max_sge = (u32)ROCE_MIN(rdev->rdma_cap.max_sq_desc_sz,
+ rqp->sq.max_sge) /
+ (u32)sizeof(struct roce_wqe_data_seg);
+
+ sq_buf_sz = (u32)ALIGN((u64)rqp->sq.wqebb_cnt
+ << (unsigned)rqp->sq.wqe_shift,
+ PAGE_SIZE);
+ rqp->buf_size = (int)ALIGN(((unsigned)sq_buf_sz +
+ ((unsigned)rqp->rq.wqebb_cnt
+ << (unsigned)rqp->rq.wqe_shift)),
+ PAGE_SIZE);
+
+ rqp->sq.offset = 0u;
+ rqp->rq.offset = sq_buf_sz;
+
+ if (((rqp->sq.wqebb_cnt - 1) / rqp->sq_max_wqes_per_wr) == 1) {
+ ROCE_DEV_ERR(rdev,
+ "Only one WR,please check,func_id(%d)",
+ rdev->glb_func_id);
+ rqp->sq.max_post = ROCE_WR_MIN_NUM;
+ cap->max_send_wr = rqp->sq.max_post;
+ } else {
+ rqp->sq.max_post = (rqp->sq.wqebb_cnt - 1) /
+ rqp->sq_max_wqes_per_wr;
+ cap->max_send_wr = (u32)rqp->sq.max_post;
+ }
+
+ cap->max_send_sge = (u32)ROCE_MIN(rqp->sq.max_sge,
+ rdev->rdma_cap.max_sq_sg);
+ rqp->max_inline_data = (u32)cap->max_inline_data;
+ } else {
+ rqp->sq.wqebb_cnt = 0;
+ rqp->sq.wqe_shift = ROCE_QP_DEFAULT_WQE_SHIFT;
+ rqp->buf_size = 0;
+ rqp->sq.offset = 0;
+ rqp->rq.offset = 0;
+ rqp->max_inline_data = 0;
+ cap->max_inline_data = 0;
+ }
+
+ rqp->sq.head = 0;
+ rqp->sq.tail = 0;
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_qp_async_event
+ Description : roce5_qp_async_event
+ Input : struct roce5_device *rdev
+ struct roce5_qp *qp
+ int type
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_qp_async_event(struct roce5_device *rdev, struct roce5_qp *qp,
+ int type)
+{
+ struct ib_event event;
+ struct ib_qp *ibqp = &qp->ibqp;
+ int ret;
+
+ ret = memset_s(&event, sizeof(event), 0, sizeof(event));
+ if (ret != 0) {
+ ROCE_DEV_ERR_LIMIT(rdev, "Failed to memset dmac.(ret:%d)", ret);
+ return;
+ }
+
+ if (ibqp->event_handler) {
+ event.device = ibqp->device;
+ event.element.qp = ibqp;
+
+ switch (type) {
+ case ROCE_EVENT_TYPE_COMM_EST:
+ event.event = IB_EVENT_COMM_EST;
+ break;
+
+ case ROCE_EVENT_TYPE_SQ_DRAINED:
+ event.event = IB_EVENT_SQ_DRAINED;
+ break;
+
+ case ROCE_EVENT_TYPE_SRQ_QP_LAST_WQE:
+ event.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ break;
+
+ case ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
+ event.event = IB_EVENT_QP_FATAL;
+ break;
+
+ case ROCE_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
+ event.event = IB_EVENT_QP_REQ_ERR;
+ break;
+
+ case ROCE_EVENT_TYPE_WQ_ACCESS_ERROR:
+ event.event = IB_EVENT_QP_ACCESS_ERR;
+ break;
+
+ default:
+ return;
+ }
+
+ ibqp->event_handler(&event, ibqp->qp_context);
+ }
+}
+
+static void *roce5_buf_offset(struct roce5_buf *buf, u32 offset)
+{
+ return (void *)((char *)buf->direct.buf + offset);
+}
+
+void *roce5_get_wqe(struct roce5_qp *rqp, u32 offset)
+{
+ return roce5_buf_offset(&rqp->buf, offset);
+}
+
+static void *roce5_get_send_wqe_head(struct roce5_qp *rqp)
+{
+ return roce5_get_wqe(rqp, rqp->sq.offset);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_get_send_wqe_tail
+ Description : roce5_get_send_wqe_tail
+ Input : struct roce5_qp *rqp
+ Output : None
+
+ 1.Date : 2015/8/8
+ Modification : Created function
+
+**************************************************************************** */
+static void *roce5_get_send_wqe_tail(struct roce5_qp *rqp)
+{
+ return roce5_get_wqe(rqp, rqp->sq.offset + (rqp->sq.wqebb_cnt
+ << (u32)rqp->sq.wqe_shift));
+}
+
+/* ****************************************************************************
+ Prototype : roce5_sq_buf_init
+ Description : roce5_sq_buf_init
+ Input : struct roce5_qp *qp
+ Output : None
+
+ 1.Date : 2015/11/9
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_sq_buf_init(struct roce5_qp *qp)
+{
+ u32 entries = qp->rq.offset / (1U << qp->sq.wqe_shift);
+ u8 *wqe = NULL;
+ struct roce5_wqe_ctrl_seg *wqe_ctrl = NULL;
+ u32 i;
+
+ for (i = 0; i < entries; i++) {
+ wqe = (u8 *)qp->buf.direct.buf +
+ (u32)(i * (1U << ((u32)qp->sq.wqe_shift)));
+ wqe_ctrl = (struct roce5_wqe_ctrl_seg *)((void *)wqe);
+ wqe_ctrl->dw0.value = be32_to_cpu(wqe_ctrl->dw0.value);
+ wqe_ctrl->dw0.bs.owner = 1;
+ wqe_ctrl->dw0.value = cpu_to_be32(wqe_ctrl->dw0.value);
+ }
+}
+
+static int roce5_check_qp_udata(struct roce5_device *rdev,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata, struct roce5_qp *rqp,
+ struct create_qp_cmd *ucmd)
+{
+ int ret = 0;
+
+ if ((udata == NULL) ||
+ (ib_copy_from_udata(ucmd, udata, sizeof(*ucmd)) != 0)) {
+ ret = -EFAULT;
+ return ret;
+ }
+
+ ret = roce5_set_user_sq_size(rdev, &init_attr->cap, rqp, ucmd);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to set user sq_size, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ return ret;
+}
+
+static bool
+roce5_need_qpn_lb1_consistent_srqn(const struct roce5_qp *rqp,
+ const struct roce5_device *rdev,
+ const struct ib_qp_init_attr *init_attr)
+{
+ if ((init_attr->srq == NULL) || (rdev->cfg_info.lb_en == 0)) {
+ return false;
+ }
+
+ if (ROCE5_SUPPORT_QP_SRQN_LB_MSG_V2(rdev) != 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+roce5_need_qpn_lb1_consistent_scqn(struct roce5_device *rdev,
+ struct ib_qp_init_attr *init_attr)
+{
+ if ((init_attr->send_cq == NULL) || (rdev->cfg_info.lb_en == 0)) {
+ return false;
+ }
+
+ if (ROCE5_SUPPORT_ALLOC_QPC_MSG_FEATURE(rdev) != 0) {
+ return false;
+ }
+ return true;
+}
+
+static int roce5_find_free_lb_qpn(struct roce5_device *rdev)
+{
+ int idx = 0;
+ for (; idx < ROCE_LB_QPN_MAX; idx++) {
+ if (rdev->qp_lb_scqn_ctrl.qp[idx] == 0) {
+ return idx;
+ }
+ }
+ return -1;
+}
+
+static int roce5_alloc_qpc(struct roce5_qp *rqp, struct roce5_device *rdev,
+ u32 qpn, struct ib_qp_init_attr *init_attr)
+{
+ struct roce5_srq *rsrq = NULL;
+ struct roce5_cq *rcq = NULL;
+ u32 qpn_tmp = qpn;
+ u32 roce_lb_mask = 0;
+ u32 cqm_lb_mode = 0;
+ int idx = -1;
+
+ if ((rqp == NULL) || (rdev == NULL) || (init_attr == NULL)) {
+ ROCE_ERR("rqp, rdev or init_attr is NULL");
+ return -EINVAL;
+ }
+
+ if (ROCE_IS_DEV_1825V100(rdev)) {
+ cqm_lb_mode = CQM_XID_LOW_BIT_1_1_1;
+ roce_lb_mask = roce5_LB1_MASK_1825V100;
+ } else {
+ ROCE_DEV_ERR(rdev, "Unknown device type(%u), func_id(%u).",
+ rdev->device_type, rdev->glb_func_id);
+ return -EINVAL;
+ }
+ mutex_lock(&rdev->qp_lb_scqn_ctrl.qp_lb_scqn_ctrl_mutex);
+
+ if (roce5_need_qpn_lb1_consistent_srqn(rqp, rdev, init_attr)) {
+ rsrq = to_roce5_srq(init_attr->srq);
+ qpn_tmp = CQM_DYNAMIC_XID_MOD(CQM_XID_SEARCH_ALL, cqm_lb_mode,
+ rsrq->srqn);
+ } else if ((qpn != ROCE_QP_GSI_QP_NUM) &&
+ roce5_need_qpn_lb1_consistent_scqn(rdev, init_attr)) {
+ rcq = to_roce5_cq(init_attr->send_cq);
+ //if not found free of qpn, idx return -1, not need do LB
+ idx = roce5_find_free_lb_qpn(rdev);
+ if (idx >= 0) {
+ qpn_tmp = CQM_DYNAMIC_XID_MOD(CQM_XID_SEARCH_ALL,
+ cqm_lb_mode, rcq->cqn);
+ }
+ }
+
+ rqp->qpc_info = cqm5_object_qpc_mpt_create(
+ rdev->hwdev, SERVICE_T_ROCE, CQM_OBJECT_SERVICE_CTX,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.qpc_entry_sz, rqp,
+ qpn_tmp, 0, 0);
+
+ if (rqp->qpc_info == NULL && rdev->full_qp_spec) {
+ /* For subsequent QPs, XID alignment is not mandatory. */
+ rqp->qpc_info = cqm5_object_qpc_mpt_create(
+ rdev->hwdev, SERVICE_T_ROCE, CQM_OBJECT_SERVICE_CTX,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.qpc_entry_sz,
+ rqp, qpn, 0, 0);
+ } else if (rqp->qpc_info != NULL) {
+ if (idx >= 0) { //idx >= 0 indicates has emptyremaining of lb qpn bit position
+ rdev->qp_lb_scqn_ctrl.qp[idx] = rqp->qpc_info->xid;
+ ROCE_DEV_INFO(
+ rdev,
+ "RoCE create lb qpn func_id(%d), qpn(%d), idx(%d)",
+ rdev->glb_func_id, rqp->qpc_info->xid, idx);
+ }
+ }
+ mutex_unlock(&rdev->qp_lb_scqn_ctrl.qp_lb_scqn_ctrl_mutex);
+ if (rqp->qpc_info == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create qpc mpt by cqm object, func_id(%d), qpn(%u)",
+ rdev->glb_func_id, qpn_tmp);
+ return -ENOMEM;
+ }
+
+ rqp->qpn = rqp->qpc_info->xid;
+ if (roce5_need_qpn_lb1_consistent_srqn(rqp, rdev, init_attr)) {
+ if (rsrq != NULL && ((rsrq->srqn & roce_lb_mask) !=
+ (rqp->qpn & roce_lb_mask))) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create qpc LB srqn, func_id(%d), qpn(%u) srqn(%u) mask:0x%x",
+ rdev->glb_func_id, rqp->qpn, rsrq->srqn,
+ roce_lb_mask);
+ }
+ }
+
+ return 0;
+}
+
+static int roce5_create_qp_user_umem_mtt(struct roce5_device *rdev,
+ struct roce5_qp *rqp,
+ struct ib_pd *ibpd,
+ struct create_qp_cmd *ucmd)
+{
+ u32 npages = 0;
+ int ret;
+
+ if (rqp->shadow != 0) {
+ return 0;
+ }
+ rqp->umem = roce5_umem_get(&rdev->ib_dev, ibpd->uobject->context,
+ ucmd->buf_addr, (size_t)rqp->buf_size, 0, 0);
+ if (IS_ERR(rqp->umem)) {
+ ROCE_DEV_ERR(rdev, "Failed to get ib_umem, func_id(%d)",
+ rdev->glb_func_id);
+ ret = (int)PTR_ERR(rqp->umem);
+ return ret;
+ }
+
+ rqp->buf.page_shift = (int)roce5_umem_get_buf_page_shift(
+ rdev, rqp->umem, ucmd->buf_addr);
+ npages = roce5_umem_get_mtt_npages(rdev, rqp->umem,
+ (u32)rqp->buf.page_shift);
+
+ rqp->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_mtt_alloc(rdev->hwdev, npages, (u32)rqp->buf.page_shift,
+ &rqp->mtt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc rdma_mtt, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_umem;
+ }
+
+ ret = roce5_umem_write_mtt(rdev, &rqp->mtt, rqp->umem, 1);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write mtt, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_write_mtt;
+ }
+
+ return 0;
+
+err_write_mtt:
+ hmm_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+err_umem:
+ ib_umem_release(rqp->umem);
+ return ret;
+}
+
+void roce5_destroy_qp_user_umem_mtt(struct roce5_device *rdev,
+ struct roce5_qp *rqp)
+{
+ if (rqp->shadow != 0) {
+ return;
+ }
+ hmm_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+ ib_umem_release(rqp->umem);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_create_qp_user
+ Description : create qp resource for user space qp
+ Input : struct roce5_device *rdev
+ struct ib_pd *ibpd
+ struct ib_qp_init_attr *init_attr
+ struct ib_udata *udata
+ struct roce5_qp *rqp
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_create_qp_user(struct roce5_device *rdev, struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata, struct roce5_qp *rqp)
+{
+ int ret = 0;
+ struct roce5_ucontext *roce5_uctx = NULL;
+ struct create_qp_cmd ucmd = { 0 };
+ u32 qpn = ROCE_QP_INVLID_QP_NUM;
+
+ roce5_uctx = to_roce5_ucontext(ibpd->uobject->context);
+
+ ret = roce5_check_qp_udata(rdev, init_attr, udata, rqp, &ucmd);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = roce5_create_qp_user_umem_mtt(rdev, rqp, ibpd, &ucmd);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (init_attr->qp_type != IB_QPT_XRC_TGT) {
+ ret = roce5_db_map_user(roce5_uctx, ucmd.db_addr, &rqp->db,
+ rqp->shadow);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to map db page to user, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_map_db;
+ }
+ }
+
+ ret = roce5_alloc_qpc(rqp, rdev, qpn, init_attr);
+ if (ret != 0) {
+ goto err_alloc_qpc;
+ }
+
+ return 0;
+
+err_alloc_qpc:
+ if (init_attr->qp_type != IB_QPT_XRC_TGT) {
+ roce5_db_unmap_user(roce5_uctx, &rqp->db, rqp->shadow);
+ }
+
+err_map_db:
+ roce5_destroy_qp_user_umem_mtt(rdev, rqp);
+
+ return ret;
+}
+
+static void roce5_free_wrid(struct roce5_qp *rqp)
+{
+ if (rqp->rq.wrid) {
+ kvfree(rqp->rq.wrid);
+ }
+
+ if (rqp->sq.wrid) {
+ kvfree(rqp->sq.wrid);
+ }
+}
+
+static int roce5_get_wrid(struct roce5_qp *rqp, struct roce5_device *rdev)
+{
+ int ret = 0;
+
+ rqp->sq.wrid = (u64 *)kzalloc((unsigned)rqp->sq.wqebb_cnt * sizeof(u64),
+ GFP_KERNEL);
+ if (rqp->sq.wrid == NULL) {
+ rqp->sq.wrid = (u64 *)(void *)vzalloc(
+ (size_t)(rqp->sq.wqebb_cnt * sizeof(u64)));
+ }
+
+ rqp->rq.wrid = (u64 *)kzalloc((unsigned)rqp->rq.wqebb_cnt * sizeof(u64),
+ GFP_KERNEL);
+ if (rqp->rq.wrid == NULL) {
+ rqp->rq.wrid = (u64 *)(void *)vzalloc(
+ (size_t)(rqp->rq.wqebb_cnt * sizeof(u64)));
+ }
+
+ if ((rqp->sq.wrid == NULL) || (rqp->rq.wrid == NULL)) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc wrid of sq or rq, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+static void roce5_create_qp_kernel_set_attr(struct roce5_qp *rqp,
+ cqm_queue_s *qp_buf_info)
+{
+ int ret;
+ ret = memset_s(qp_buf_info->q_room_buf_1.direct.va,
+ (size_t)((unsigned)rqp->buf_size), 0,
+ (size_t)((unsigned)rqp->buf_size));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset qp_buf_info.(ret:%d)", ret);
+ return;
+ }
+ rqp->buf.direct.buf = qp_buf_info->q_room_buf_1.direct.va;
+ rqp->buf.direct.map = qp_buf_info->q_room_buf_1.direct.pa;
+ rqp->buf.page_shift =
+ (int)ROCE_ILOG2(qp_buf_info->q_room_buf_1.buf_size);
+
+ roce5_sq_buf_init(rqp);
+
+ rqp->db.db_record = (__be32 *)(void *)(&qp_buf_info->q_header_vaddr
+ ->doorbell_record);
+ rqp->db.dma = qp_buf_info->q_header_paddr;
+
+ qp_buf_info->q_header_vaddr->doorbell_record = 0;
+
+ rqp->qp_buf_info = qp_buf_info;
+
+ rqp->sq_head_addr = (u8 *)roce5_get_send_wqe_head(rqp);
+ rqp->sq_tail_addr = (u8 *)roce5_get_send_wqe_tail(rqp);
+ rqp->max_dwqe_size = 0;
+ rqp->sq_wqe_ssn = 0;
+
+ if (rqp->max_inline_data != 0) {
+ rqp->max_dwqe_size = ROCE_QP_MAX_DWQE_SIZE;
+ }
+}
+
+static int roce5_create_qp_kernel_normal(struct roce5_device *rdev,
+ struct roce5_qp *rqp)
+{
+ int ret;
+ cqm_queue_s *qp_buf_info = NULL;
+
+ qp_buf_info = cqm5_object_rdma_queue_create(
+ rdev->hwdev, SERVICE_T_ROCE, CQM_OBJECT_RDMA_QP,
+ (u32)rqp->buf_size, rqp, true, ROCE_QP_INVLID_QP_NUM, 0, 0);
+ if (qp_buf_info == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create rdma queue by cqm object, func_id(%d)",
+ rdev->glb_func_id);
+ return -1;
+ }
+
+ roce5_create_qp_kernel_set_attr(rqp, qp_buf_info);
+
+ rqp->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_mtt_alloc(rdev->hwdev, qp_buf_info->q_room_buf_1.buf_number,
+ (u32)rqp->buf.page_shift, &rqp->mtt,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc rdma mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_alloc_mtt;
+ }
+ ret = roce5_buf_write_mtt(rdev, &rqp->mtt,
+ &rqp->qp_buf_info->q_room_buf_1);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write rdma mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_write_mtt;
+ }
+
+ ret = roce5_get_wrid(rqp, rdev);
+ if (ret != 0) {
+ goto err_alloc_wrid;
+ }
+
+ return 0;
+
+err_alloc_wrid:
+ roce5_free_wrid(rqp);
+
+err_write_mtt:
+ hmm_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+
+err_alloc_mtt:
+ cqm5_object_delete(&rqp->qp_buf_info->object);
+
+ return ret;
+}
+
+static void roce5_destroy_qp_kernel_normal(struct roce5_device *rdev,
+ struct roce5_qp *rqp)
+{
+ roce5_free_wrid(rqp);
+ hmm_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+ cqm5_object_delete(&rqp->qp_buf_info->object);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_create_qp_kernel
+ Description : create qp resource for kernel space qp
+ Input : struct roce5_device *rdev
+ struct ib_qp_init_attr *init_attr
+ struct roce5_qp *rqp
+ u32 qpn
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_create_qp_kernel(struct roce5_device *rdev,
+ struct ib_qp_init_attr *init_attr,
+ struct roce5_qp *rqp, u32 qpn)
+{
+ int ret = 0;
+
+ ret = roce5_set_kernel_sq_size(rdev, &init_attr->cap,
+ (enum ib_qp_type)rqp->qp_type, rqp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set sq buffer size in kernel, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ ret = roce5_create_qp_kernel_normal(rdev, rqp);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ ret = roce5_alloc_qpc(rqp, rdev, qpn, init_attr);
+ if (ret != 0) {
+ goto err_alloc_qpc;
+ }
+
+ return 0;
+
+err_alloc_qpc:
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ roce5_destroy_qp_kernel_normal(rdev, rqp);
+ }
+
+ return ret;
+}
+
+static void roce5_qp_add_cq_list(struct ib_qp_init_attr *init_attr,
+ struct roce5_qp *rqp,
+ struct roce5_device *rdev)
+{
+ struct roce5_cq *send_rcq = to_roce5_cq(init_attr->send_cq);
+ struct roce5_cq *recv_rcq = to_roce5_cq(init_attr->recv_cq);
+ unsigned long flags = 0; /* type required by kernel API */
+
+ spin_lock_irqsave(&rdev->reset_flow_resource_lock, flags);
+ roce5_lock_cqs(send_rcq, recv_rcq);
+ list_add_tail(&rqp->qps_list, &rdev->qp_list);
+ list_add_tail(&rqp->cq_send_list, &send_rcq->send_qp_list);
+ list_add_tail(&rqp->cq_recv_list, &recv_rcq->recv_qp_list);
+ roce5_unlock_cqs(send_rcq, recv_rcq);
+ spin_unlock_irqrestore(&rdev->reset_flow_resource_lock, flags);
+}
+
+static int roce5_alloc_xrc_extra_dma(const struct roce5_device *rdev,
+ struct roce5_qp *rqp)
+{
+ dma_addr_t wb_dma = 0;
+ void *wb_va = NULL;
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ return 0;
+ }
+
+ wb_va = dma_alloc_coherent(rdev->dev, (size_t)4UL, &wb_dma, GFP_KERNEL);
+ if (wb_va == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc wb_va, func_id(%d)",
+ rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ rqp->wb_dma = wb_dma;
+ rqp->wb_va = wb_va;
+
+ return 0;
+}
+
+#define ROCE_MAX_PI_ON_CHIP_QPN 1024 /* temporarily when set PI is 1024(count word), later debug add */
+static int roce5_set_pi_on_chip(const struct roce5_device *rdev,
+ struct roce5_qp *rqp)
+{
+ /* shadow scenario next, actual use of is vf, and pi on chip function in shadow scenario not already verify, default disable */
+ if (ROCE5_SUPPORT_SET_PI_ON_CHIP_MSG_V2(rdev) != 0 &&
+ rqp->shadow == 0) {
+ /* becauseslice on store pi resource has limit, disable VF of pi_on_chip, such as need enabled, need modify configuration file in chip store store PI data, Note
审monitorslice on resource whether satisfy requirement */
+ rqp->pi_on_chip = (roce5_func_is_vf(rdev->hwdev) == false) &&
+ (rqp->qpn < ROCE_MAX_PI_ON_CHIP_QPN);
+ }
+
+ return 0;
+}
+
+static int roce5_do_create_qp(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+
+ mutex_init(&rqp->mutex);
+
+ spin_lock_init(&rqp->sq.lock);
+ spin_lock_init(&rqp->rq.lock);
+
+ rqp->qp_state = IB_QPS_RESET;
+ rqp->qp_type = init_attr->qp_type;
+ rqp->sq_signal_bits = (u32)(init_attr->sq_sig_type == IB_SIGNAL_ALL_WR);
+
+ ret = roce5_alloc_xrc_extra_dma(rdev, rqp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc xrc extra dma, func_id(%d), ret(%d).",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ if (ibpd != NULL && ibpd->uobject) {
+ ret = roce5_set_rq_size(rdev, rqp, init_attr, true,
+ rqp->has_rq);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set rq size, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto create_qp_err;
+ }
+
+ ret = roce5_create_qp_user(rdev, ibpd, init_attr, udata, rqp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create qp user, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto create_qp_err;
+ }
+ } else {
+ ret = roce5_set_rq_size(rdev, rqp, init_attr, false,
+ rqp->has_rq);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set rq size, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto create_qp_err;
+ }
+
+ ret = roce5_create_qp_kernel(rdev, init_attr, rqp,
+ ROCE_QP_INVLID_QP_NUM);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create qp kernel, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto create_qp_err;
+ }
+
+ roce5_qp_add_cq_list(init_attr, rqp, rdev);
+ }
+
+ ret = roce5_set_pi_on_chip(rdev, rqp);
+ if (ret != 0) {
+ goto create_qp_err;
+ }
+
+ ret = roce5_create_qp_ext_init(rqp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init qp extension, ret(%d).",
+ ret);
+ goto create_qp_err;
+ }
+
+ return ret;
+create_qp_err:
+ if (rqp->wb_va != NULL) {
+ dma_free_coherent(rdev->dev, sizeof(u32), rqp->wb_va,
+ rqp->wb_dma);
+ }
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_create_qp_gsi
+ Description : roce5_create_qp_gsi
+ Input : struct roce5_device *rdev
+ struct ib_pd *ibpd
+ struct ib_qp_init_attr *init_attr
+ Output : None
+
+ 1.Date : 2017/04/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_create_qp_gsi(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_qp_init_attr *init_attr)
+{
+ int ret = 0;
+
+ rqp->sqp_attr = (struct roce5_sqp_attr *)kzalloc(
+ sizeof(struct roce5_sqp_attr), GFP_KERNEL);
+ if (rqp->sqp_attr == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to allocate memory for sqp attribute.");
+ return -ENOMEM;
+ }
+
+ mutex_init(&rqp->mutex);
+
+ spin_lock_init(&rqp->sq.lock);
+ spin_lock_init(&rqp->rq.lock);
+
+ rqp->qp_state = (u8)IB_QPS_RESET;
+ rqp->qp_type = init_attr->qp_type;
+ rqp->sq_signal_bits = (u32)(init_attr->sq_sig_type == IB_SIGNAL_ALL_WR);
+ rqp->has_rq = !init_attr->srq;
+
+ ret = roce5_set_rq_size(rdev, rqp, init_attr, false, rqp->has_rq);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to set rq size, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_out;
+ }
+
+ ret = roce5_create_qp_kernel(rdev, init_attr, rqp, ROCE_QP_GSI_QP_NUM);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to create qp kernel, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_out;
+ }
+
+ rqp->qpn = ROCE_QP_GSI_QP_NUM;
+
+ roce5_qp_add_cq_list(init_attr, rqp, rdev);
+
+ return 0;
+
+err_out:
+ kfree(rqp->sqp_attr);
+
+ return ret;
+}
+
+static int roce5_create_check_init_attr(const struct ib_pd *ibpd,
+ const struct ib_qp_init_attr *init_attr,
+ const struct ib_udata *udata)
+{
+ if (init_attr == NULL) {
+ ROCE_ERR("init_attr is null");
+ return (-EINVAL);
+ }
+
+ if ((ibpd == NULL) && (init_attr->qp_type != IB_QPT_XRC_TGT)) {
+ ROCE_ERR(
+ "Ibpd is null and qp_type is not IB_QPT_XRC_TGT, qp_type(0x%x)",
+ init_attr->qp_type);
+ return (-EINVAL);
+ }
+
+ if ((udata) && (init_attr->qp_type == IB_QPT_GSI)) {
+ ROCE_ERR("Udata is not null and qp_type is IB_QPT_GSI");
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+static int roce5_set_qp_attr(struct ib_qp_init_attr *init_attr,
+ struct roce5_qp *rqp, struct roce5_device *rdev,
+ struct ib_pd **ibpd, int qp_ext)
+{
+ u16 xrcdn = 0;
+
+ rqp->qp_ext = (u8)qp_ext;
+ if (init_attr->qp_type == IB_QPT_XRC_TGT) {
+ *ibpd = to_roce5_xrcd(init_attr->xrcd)->pd;
+ xrcdn = (u16)to_roce5_xrcd(init_attr->xrcd)->xrcdn;
+ init_attr->send_cq = to_roce5_xrcd(init_attr->xrcd)->cq;
+ init_attr->recv_cq = init_attr->send_cq;
+
+ rqp->has_rq = false;
+ rqp->xrcdn = xrcdn;
+ } else if (init_attr->qp_type == IB_QPT_XRC_INI) {
+ init_attr->recv_cq = init_attr->send_cq;
+ rqp->has_rq = false;
+ } else if ((init_attr->qp_type == IB_QPT_RC) ||
+ (init_attr->qp_type == IB_QPT_UC) ||
+ (init_attr->qp_type == IB_QPT_UD)) {
+ rqp->has_rq = !init_attr->srq;
+ } else {
+ ROCE_DEV_ERR(rdev, "Unknown QP Type(%u), func_id(%d)",
+ init_attr->qp_type, rdev->glb_func_id);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+static int roce5_create_gsi_qp_result(struct roce5_device *rdev,
+ struct roce5_qp *rqp,
+ struct ib_qp_init_attr *init_attr)
+{
+ int ret;
+
+ ret = roce5_create_qp_gsi(rdev, rqp, init_attr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to create gsi qp, func_id(%d), ret(%d).",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ rqp->ibqp.qp_num = rqp->qpn;
+ return 0;
+}
+
+static int roce5_create_qp_common(struct roce5_qp *rqp,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata, int qp_ext)
+{
+ int ret;
+ int uld_ret;
+ //when init_attr->qp_type == IB_QPT_XRC_TGT, ibpd is NULL.
+ struct ib_pd *ibpd = rqp->ibqp.pd;
+ struct roce5_device *rdev =
+ to_roce5_dev(ibpd ? ibpd->device : init_attr->xrcd->device);
+ roce_user_handle_t hdl = { 0 };
+
+ if (rdev->ecn_ctx.cc_algo == ROCE_CC_LDCP_ALGO &&
+ (init_attr->qp_type == IB_QPT_XRC_TGT ||
+ init_attr->qp_type == IB_QPT_XRC_INI)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "XRC QP cant be created when LDCP is enabled, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if (init_attr->qp_type == IB_QPT_GSI) {
+ return roce5_create_gsi_qp_result(rdev, rqp, init_attr);
+ }
+
+ rqp->rqp_magic = ROCE_RQP_MAGIC;
+ ret = roce5_set_qp_attr(init_attr, rqp, rdev, &ibpd, qp_ext);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to set qp attribute, ret(%d).", ret);
+ goto err_set_attr;
+ }
+
+ ROCE_CONSTUCT_ULD_HDL_RQP(&hdl, rdev, rqp, NULL, udata, &rqp->mtt,
+ &rqp->db.dma);
+ ROCE_CONSTUCT_ULD_HDL_SHADOW(&hdl, &rqp->shadow, &rqp->shadow_vfid,
+ NULL);
+ ret = roce5_uld_qp_create((roce_uld_handle)&hdl);
+ if (ret != 0) {
+ ROCE_ERR("Failed to execute uld qp creation, ret(%d)", ret);
+ goto err_set_attr;
+ }
+ ret = roce5_do_create_qp(rdev, rqp, ibpd, init_attr, udata);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to create qp in common process, ret(%d).",
+ ret);
+ goto err_create_qp;
+ }
+
+ roce5_set_qp_dif_attr(rqp, init_attr, rdev);
+ rqp->ibqp.qp_num = rqp->qpn;
+ rqp->rsp_depth = 0;
+
+ mutex_lock(&rdev->qp_cnt.cur_qps_mutex);
+ rdev->qp_cnt.alloc_qp_cnt++;
+ mutex_unlock(&rdev->qp_cnt.cur_qps_mutex);
+
+ return 0;
+
+err_create_qp:
+ uld_ret = roce5_uld_qp_destroy((roce_uld_handle)&hdl);
+ if (uld_ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to destroy uld qp in common process, uld_ret(%d).",
+ uld_ret);
+ }
+err_set_attr:
+ return ret;
+}
+
+struct ib_qp *roce5_create_qp_compat(struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ struct roce5_qp *rqp = NULL;
+ int ret;
+
+ ret = roce5_create_check_init_attr(ibpd, init_attr, udata);
+ if (ret != 0) {
+ ROCE_ERR("Failed to check init attr");
+ return (struct ib_qp *)ERR_PTR((long)ret);
+ }
+
+ rqp = (struct roce5_qp *)kzalloc(sizeof(*rqp), GFP_KERNEL);
+ if (rqp == NULL) {
+ ROCE_ERR("Failed to alloc roce qp.");
+ return (struct ib_qp *)ERR_PTR((long)-ENOMEM);
+ }
+
+ rqp->ibqp.pd = ibpd;
+
+ ret = roce5_create_qp_common(rqp, init_attr, udata, ROCE_QP);
+ if (ret != 0) {
+ ROCE_ERR("Failed to execute common qp creation, ret(%d)", ret);
+ goto err_create_qp;
+ }
+
+ return &(rqp->ibqp);
+err_create_qp:
+ kfree(rqp);
+ return (struct ib_qp *)ERR_PTR((long)-ENOMEM);
+}
+
+int roce5_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_qp *rqp = NULL;
+
+ if (ibqp == NULL) {
+ ROCE_ERR("Invalid parameter, ibqp is NULL.");
+ return -EINVAL;
+ }
+
+ ret = roce5_create_check_init_attr(ibqp->pd, init_attr, udata);
+ if (ret != 0) {
+ ROCE_ERR("Failed to check init attr");
+ return ret;
+ }
+
+ rqp = to_roce5_qp(ibqp);
+ ret = roce5_create_qp_common(rqp, init_attr, udata, ROCE_QP);
+ if (ret != 0) {
+ ROCE_ERR("Failed to execute common qp creation, ret(%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ctx_format.h b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ctx_format.h
new file mode 100644
index 000000000..c435e7090
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ctx_format.h
@@ -0,0 +1,278 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_QP_CTX_FOMRAT_H
+#define ROCE_QP_CTX_FOMRAT_H
+
+#include <linux/types.h>
+
+/* Align each field with 4bytes. */
+#pragma pack(push)
+#pragma pack(4)
+
+struct roce5_chip_seg_rrwc {
+ u32 dw0;
+
+ union {
+ u64 rrw_curt_sge_va;
+ struct {
+ u32 rrw_curt_sge_va_hi;
+ u32 rrw_curt_sge_va_lo;
+ } dw1;
+ };
+
+ u32 rsvd[5];
+};
+
+struct roce5_chip_seg_rcc {
+ u32 dw0;
+
+ union {
+ u64 rc_curt_sge_va;
+ struct {
+ u32 rc_curt_sge_va_hi;
+ u32 rc_curt_sge_va_lo;
+ } dw1;
+ };
+
+ u32 rsvd[5];
+};
+
+struct roce5_chip_seg_sqc {
+ u32 rsvd[9];
+
+ union {
+ u64 sq_curt_sge_va;
+ struct {
+ u32 sq_curt_sge_va_hi;
+ u32 sq_curt_sge_va_lo;
+ } dw9;
+ };
+
+ u32 rsvd1[5];
+};
+
+struct roce5_chip_seg_sqac {
+ u32 rsvd[9];
+
+ union {
+ u64 sqa_curt_sge_va;
+ struct {
+ u32 sqa_curt_sge_va_hi;
+ u32 sqa_curt_sge_va_lo;
+ } dw9;
+ };
+
+ u32 rsvd1[5];
+};
+
+struct roce5_chip_seg_rqc {
+ u32 rsvd[9];
+
+ union {
+ u64 rq_curt_sge_va;
+ struct {
+ u32 rq_curt_sge_va_hi;
+ u32 rq_curt_sge_va_lo;
+ } dw9;
+ };
+
+ u32 rsvd1[5];
+};
+
+struct roce5_chip_seg_srqc {
+ u32 rsvd[9];
+
+ union {
+ u64 srq_curt_sge_va;
+ struct {
+ u32 srq_curt_sge_va_hi;
+ u32 srq_curt_sge_va_lo;
+ } dw9;
+ };
+
+ u32 rsvd1[5];
+};
+
+struct roce5_chip_seg_qpcc {
+ union {
+ u64 sq_rq_l0mtt_gpa;
+ struct {
+ u32 sq_rq_l0mtt_gpa_hi;
+ u32 sq_rq_l0mtt_gpa_lo;
+ } dw0;
+ };
+
+ union {
+ u64 sq_rq_pi_record_gpa_at_hop_num;
+ struct {
+ u32 sq_rq_pi_record_gpa_hi;
+ u32 sq_rq_pi_record_gpa_lo_at_hop_num;
+ } dw2;
+ };
+
+ u32 dw4;
+
+ union {
+ struct {
+ u32 rsvd1 : 22;
+ u32 qp_rre : 1;
+ u32 qp_rae : 1;
+ u32 qp_rwe : 1;
+ u32 rsvd : 7;
+ } bs;
+ u32 value;
+ } dw5;
+
+ u32 rsvd[2];
+};
+
+typedef struct roce5_qpc_chip_seg {
+ struct roce5_chip_seg_rrwc rrwc;
+ struct roce5_chip_seg_rcc rcc;
+ struct roce5_chip_seg_sqc sqc;
+ struct roce5_chip_seg_sqac sqac;
+ union {
+ struct roce5_chip_seg_rqc rqc;
+ struct roce5_chip_seg_srqc srqc;
+ };
+ struct roce5_chip_seg_qpcc qpcc;
+} roce5_qpc_chip_seg_s;
+
+struct roce5_qpc_timer_seg {
+ u32 rsvd[8];
+};
+
+typedef struct roce5_qpc_drv_seg {
+ union {
+ struct {
+ u32 dest_qp : 24;
+ u32 state : 4;
+ u32 rsvd : 4;
+ } bs;
+ u32 value;
+ } dw0;
+
+ u32 dw1;
+
+ union {
+ struct {
+ u32 pmtu : 3;
+ u32 rsvd : 13;
+ u32 to_retry_limit : 3;
+ u32 rnr_retry_limit : 3;
+ u32 min_rnr_nak : 5;
+ u32 ack_to : 5;
+ } bs;
+ u32 value;
+ } dw2;
+
+ union {
+ struct {
+ u32 rsvd : 26;
+ u32 rra_max : 3;
+ u32 sra_max : 3;
+ } bs;
+ u32 value;
+ } dw3;
+} roce5_qpc_drv_seg_s;
+
+typedef struct roce5_drv_path_info {
+ u32 rsvd[2];
+
+ u8 dgid[16];
+
+ union {
+ struct {
+ u32 flow_label : 20;
+ u32 tclass : 8;
+ u32 rsvd : 4;
+ } bs;
+ u32 value;
+ } dw6;
+
+ union {
+ struct {
+ u32 hoplmt : 8;
+ u32 sgid_index : 7;
+ u32 rsvd : 14;
+ u32 sl : 3;
+ } bs;
+ u32 value;
+ } dw7;
+} roce5_drv_path_info_s;
+
+typedef struct roce5_ucode_common_ctx {
+ union {
+ struct {
+ u32 rsvd1 : 20;
+ u32 port : 2;
+ u32 rsvd : 10;
+ } bs;
+ u32 value;
+ } dw0;
+
+ u32 dw1;
+
+ union {
+ u32 qkey;
+ u32 value;
+ } dw2;
+
+ u32 dw3;
+} roce5_ucode_common_ctx_s;
+
+typedef struct roce5_ucode_sq_ctx {
+ union {
+ struct {
+ u32 next_send_psn : 24;
+ u32 rsvd : 8;
+ } bs;
+ u32 value;
+ } dw8;
+
+ u32 rsvd[12];
+} roce5_ucode_sq_ctx_s;
+
+typedef struct roce5_ucode_rq_ctx {
+ union {
+ struct {
+ u32 next_rcv_psn : 24;
+ u32 rsvd : 8;
+ } bs;
+ u32 value;
+ } dw20;
+
+ u32 rsvd[9];
+} roce5_ucode_rq_ctx_s;
+
+typedef struct roce5_drv_ucode_all_info {
+ /* DW0~DW3 */
+ roce5_ucode_common_ctx_s common;
+
+ /* DW4~DW16 */
+ roce5_ucode_sq_ctx_s sq_ctx;
+
+ /* DW17~DW26 */
+ roce5_ucode_rq_ctx_s rq_ctx;
+
+ u32 rsvd;
+} roce5_drv_ucode_all_info_s;
+
+typedef struct roce5_qpc_sw_seg {
+ roce5_qpc_drv_seg_s drv_seg;
+ roce5_drv_path_info_s path_seg;
+ roce5_drv_ucode_all_info_s ucode_seg;
+ u32 rsvd[8];
+} roce5_qpc_sw_seg_s;
+
+typedef struct roce5_qp_context {
+ struct roce5_qpc_chip_seg chip_seg;
+ struct roce5_qpc_timer_seg timer_seg;
+ struct roce5_qpc_sw_seg sw_seg;
+} roce5_qp_context_s;
+
+#pragma pack(pop)
+
+#endif /* ROCE_QP_CTX_FOMRAT_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_destroy.c b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_destroy.c
new file mode 100644
index 000000000..71a77ada0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_destroy.c
@@ -0,0 +1,342 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "roce_compat.h"
+
+#include "roce.h"
+#include "roce_mix.h"
+#include "roce_mr.h"
+#include "roce_xrc.h"
+#include "roce_pd.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_qp.h"
+#include "roce_qp_ext.h"
+#include "roce_qp_extension.h"
+#include "roce_restore.h"
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+#include "hinic5_hmm.h"
+#include "securec.h"
+#include "roce_os_compat.h"
+#include "roce_uld_inner.h"
+#include "roce_uld_kernel_api.h"
+#include "roce_qp_inner.h"
+
+static void roce5_clear_lb_qpn(struct roce5_device *rdev, u32 qpn)
+{
+ int idx = 0;
+ mutex_lock(&rdev->qp_lb_scqn_ctrl.qp_lb_scqn_ctrl_mutex);
+ for (; idx < ROCE_LB_QPN_MAX; idx++) {
+ if (rdev->qp_lb_scqn_ctrl.qp[idx] == qpn) {
+ rdev->qp_lb_scqn_ctrl.qp[idx] = 0;
+ ROCE_DEV_INFO(
+ rdev,
+ "RoCE destroy lb qpn func_id(%d), qpn(%d), idx(%d)",
+ rdev->glb_func_id, qpn, idx);
+ break;
+ }
+ }
+ mutex_unlock(&rdev->qp_lb_scqn_ctrl.qp_lb_scqn_ctrl_mutex);
+}
+
+static void roce5_clean_qp_user(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_udata *udata)
+{
+ struct roce5_ucontext *ucontext = NULL;
+
+ roce5_free_opt_rdmarc(rqp);
+
+ cqm5_object_delete(&(rqp->qpc_info->object));
+
+ roce5_clear_lb_qpn(rdev, rqp->qpn);
+
+ roce5_destroy_pcqc_ext(rqp);
+
+ ucontext = roce5_queue_to_ucontext((void *)(&rqp->ibqp), udata,
+ ROCE_Q_TYPE_QP);
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ roce5_db_unmap_user(ucontext, &rqp->db, rqp->shadow);
+ }
+
+ roce5_destroy_qp_user_umem_mtt(rdev, rqp);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_cq_clean_process
+ Description : roce5_cq_clean_process
+ Input : struct roce5_cq *cq
+ u32 qpn
+ struct roce5_srq *srq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_cq_clean_process(struct roce5_cq *cq, u32 qpn, struct roce5_srq *srq)
+{
+ u32 prod_index = 0;
+ int nfreed = 0;
+ struct roce_cqe *cqe = NULL;
+ struct roce_cqe *dest = NULL;
+ u8 owner_bit = 0;
+ int ret;
+
+ /*
+ * First we need to find the current producer index, so we
+ * know where to start cleaning from. It doesn't matter if HW
+ * adds new entries after this loop -- the QP we're worried
+ * about is already in RESET, so the new entries won't come
+ * from our QP and therefore don't need to be checked.
+ */
+ for (prod_index = cq->cons_index; roce5_get_sw_cqe(cq, prod_index);
+ ++prod_index) {
+ if (prod_index == (u32)((int)cq->cons_index + cq->ibcq.cqe)) {
+ break;
+ }
+ }
+
+ /*
+ * Now sweep backwards through the CQ, removing CQ entries
+ * that match our QP by copying older entries on top of them.
+ */
+ /* xcqe:qpn's cqe.
+ CI
+ +--------+------+------+------+----------+
+ b4_clean: | | cqe1 | xcqe2| cqe3 | |
+ +--------+------+------+------+----------+
+ \
+ \
+ +---------------+------+------+----------+
+ af_clean: | | cqe1 | cqe3 | |
+ +---------------+------+------+----------+
+ */
+ while ((int)--prod_index - (int)cq->cons_index >= 0) {
+ cqe = (struct roce_cqe *)roce5_get_cqe(
+ cq, prod_index & (u32)cq->cqe_mask);
+
+ cqe->dw0.value = roce5_convert_cpu32(cqe->dw0.value);
+ cqe->dw1.value = roce5_convert_cpu32(cqe->dw1.value);
+ cqe->dw7.value = roce5_convert_cpu32(cqe->dw7.value);
+
+ if (cqe->dw0.bs.qpn == qpn) {
+ if (srq && (cqe->dw1.bs.s_r == ROCE_CQE_RECV_COMP)) {
+ roce5_free_srq_wqe(srq, cqe->dw7.bs.wqe_cnt);
+ }
+
+ ++nfreed;
+ } else if (nfreed != 0) {
+ dest = (struct roce_cqe *)roce5_get_cqe(
+ cq, (unsigned int)((int)prod_index + nfreed) &
+ (unsigned int)cq->cqe_mask);
+ dest->dw0.value = roce5_convert_cpu32(dest->dw0.value);
+ owner_bit = dest->dw0.bs.owner;
+ ret = memcpy_s((void *)dest, sizeof(struct roce_cqe),
+ (void *)cqe, sizeof(struct roce_cqe));
+ if (ret != 0) {
+ ROCE_ERR("[Failed to memcpy dest.(ret:%d)",
+ ret);
+ return;
+ }
+ dest->dw0.bs.owner = owner_bit;
+ dest->dw0.value = roce5_convert_be32(dest->dw0.value);
+ dest->dw1.value = roce5_convert_be32(dest->dw1.value);
+ dest->dw7.value = roce5_convert_be32(dest->dw7.value);
+ } else {
+ ROCE_INFO("Nothing need to do");
+ }
+
+ cqe->dw0.value = roce5_convert_be32(cqe->dw0.value);
+ cqe->dw1.value = roce5_convert_be32(cqe->dw1.value);
+ cqe->dw7.value = roce5_convert_be32(cqe->dw7.value);
+ }
+
+ if (nfreed != 0) {
+ cq->cons_index += (u32)nfreed;
+ /*
+ * Make sure update of buffer contents is done before
+ * updating consumer index.
+ */
+ wmb();
+
+ roce5_cq_set_ci(cq);
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_clean_qp_kernel
+ Description : roce5_clean_qp_kernel
+ Input : struct roce5_device *rdev
+ struct roce5_qp *rqp
+ Output : None
+
+ 1.Date : 2017/04/26
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_clean_qp_kernel(struct roce5_device *rdev,
+ struct roce5_qp *rqp)
+{
+ struct roce5_cq *send_cq = NULL;
+ struct roce5_cq *recv_cq = NULL;
+ unsigned long flags = 0; /* type required by kernel API */
+
+ roce5_free_opt_rdmarc(rqp);
+
+ roce5_get_cqs(rqp, &send_cq, &recv_cq);
+
+ spin_lock_irqsave(&rdev->reset_flow_resource_lock, flags);
+ roce5_lock_cqs(send_cq, recv_cq);
+ /* del from lists under both locks above to protect reset flow paths */
+ list_del(&rqp->qps_list);
+ list_del(&rqp->cq_send_list);
+ list_del(&rqp->cq_recv_list);
+
+ roce5_cq_clean_process(recv_cq, rqp->qpn,
+ rqp->ibqp.srq ? to_roce5_srq(rqp->ibqp.srq) :
+ NULL);
+
+ if (send_cq != recv_cq) {
+ roce5_cq_clean_process(send_cq, rqp->qpn, NULL);
+ }
+
+ roce5_unlock_cqs(send_cq, recv_cq);
+ spin_unlock_irqrestore(&rdev->reset_flow_resource_lock, flags);
+
+ cqm5_object_delete(&(rqp->qpc_info->object));
+
+ roce5_clear_lb_qpn(rdev, rqp->qpn);
+
+ if (rqp->sq.wrid) {
+ kvfree(rqp->sq.wrid);
+ rqp->sq.wrid = NULL;
+ }
+
+ if (rqp->rq.wrid) {
+ kvfree(rqp->rq.wrid);
+ rqp->rq.wrid = NULL;
+ }
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ cqm5_object_delete(&(rqp->qp_buf_info->object));
+ }
+
+ hmm_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+}
+
+static int roce5_qp_destroy(struct roce5_qp *rqp, struct roce5_device *rdev)
+{
+ int ret = 0;
+
+ ret = roce5_qp_modify_2rst_cmd(rdev, rqp->qpn);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to modify QP(0x%06x) to RESET, func_id(%d)",
+ rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce5_qp_cache_out_cmd(rdev, rqp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "QP(0x%06x) cache invalid, func_id(%d)",
+ rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce5_destroy_qp_common(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_pd *pd = roce5_get_pd(rqp);
+ roce_user_handle_t hdl = { 0 };
+
+ roce5_destroy_qp_ext_deinit(rqp);
+
+ if (rqp->wb_va != NULL) {
+ dma_free_coherent(rdev->dev, sizeof(u32), rqp->wb_va,
+ rqp->wb_dma);
+ rqp->wb_va = NULL;
+ }
+
+ if (rqp->qp_state != IB_QPS_RESET) {
+ ret = roce5_qp_destroy(rqp, rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to destroy qp, ret(%d).",
+ ret);
+ return ret;
+ }
+
+ rqp->qp_state = IB_QPS_RESET;
+ }
+
+ if (pd->ibpd.uobject) {
+ roce5_clean_qp_user(rdev, rqp, udata);
+ } else {
+ roce5_clean_qp_kernel(rdev, rqp);
+
+ if (roce5_sqp_check(rqp) != 0 && rqp->sqp_attr != NULL) {
+ kfree(rqp->sqp_attr);
+ rqp->sqp_attr = NULL;
+ }
+ }
+
+ ROCE_CONSTUCT_ULD_HDL_RQP(&hdl, rdev, rqp, NULL, NULL, NULL, NULL);
+ ret = roce5_uld_qp_destroy((roce_uld_handle)&hdl);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to destroy uld qp, ret(%d).", ret);
+ return ret;
+ }
+
+ mutex_lock(&rdev->qp_cnt.cur_qps_mutex);
+ rdev->qp_cnt.del_qp_cnt++;
+ mutex_unlock(&rdev->qp_cnt.cur_qps_mutex);
+ return 0;
+}
+
+int roce5_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
+{
+ struct roce5_qp *rqp = NULL;
+ struct roce5_device *rdev = NULL;
+ int ret;
+
+ if (ibqp == NULL) {
+ ROCE_ERR("Ibqp is null");
+ return -EINVAL;
+ }
+
+ rqp = to_roce5_qp(ibqp);
+ rdev = to_roce5_dev(ibqp->device);
+
+ ret = roce5_destroy_qp_common(rdev, rqp, udata);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Error occur when destroy qp! ret(%d).",
+ ret);
+ return ret;
+ }
+
+#if !defined(IB_DEVICE_OPS_HAVE_IB_QP_OBJ)
+ kfree(rqp);
+#endif
+ return 0;
+}
+
+int roce5_destroy_qp_ofa(struct ib_qp *ibqp)
+{
+ return roce5_destroy_qp(ibqp, NULL);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_exp.h b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_exp.h
new file mode 100644
index 000000000..646717c2a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_exp.h
@@ -0,0 +1,80 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_QP_EXP_H
+#define ROCE_QP_EXP_H
+
+#include <linux/io-mapping.h>
+#include <linux/list.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "hinic5_rdma.h"
+#include "hinic5_cqm.h"
+
+#include "roce.h"
+#include "roce_db.h"
+#include "roce_cq.h"
+#include "roce_qp.h"
+
+#define EXP_OK (0)
+#define EXP_PARAM_ERR (1)
+#define EXP_FUNC_ERR (2)
+
+#define QPC_MIN_SIZE (512)
+#define CONTX_SZ (sizeof(struct roce_qp_context) / QPC_MIN_SIZE)
+
+#define BUFFER_SZ (sizeof(struct roce_qp_context) / sizeof(u32))
+
+#define TYPE_LEN (8)
+#define DEV_NUM (32)
+#define QPN_MAX (0xFFFFF)
+#define QPN_MIN (0)
+#define IB_QP_EXP_CMD (1 << 23)
+#define ROCE_OPTPAR_EXP (1 << 16)
+#define VA_OFFSET (8)
+
+struct roce5_device_list {
+ struct ib_device *ib_dev[DEV_NUM];
+ int ib_dev_num;
+ struct mutex mutex;
+};
+
+struct ib_qp_info {
+ dma_addr_t sq_pg_base_addr[64];
+ dma_addr_t hw_doorbell_addr;
+ dma_addr_t sw_doorbell_addr;
+
+ u32 sq_depth;
+ u32 qpn;
+ u8 sq_pg_cnt;
+ u8 qp_cos;
+ u8 cntx_sz;
+ u8 sq_wqe_size;
+};
+
+struct ib_qp_attr_data {
+ u32 data_type; //plog:1
+ u32 data_len;
+ u8 *data_buf;
+};
+
+struct ib_qp_attr_exp {
+ struct ib_qp_attr qp_attr;
+ struct ib_qp_attr_data qp_attr_data;
+};
+
+struct roce5_device_list *roce5_get_plog_device_info(void);
+
+int ib_get_qp_info(char *dev_name, int qpn, struct ib_qp_info *qp_info);
+struct ib_qp *ib_get_qp(const char *dev_name, int qpn);
+int ib_put_qp(struct ib_qp *ibqp);
+int roce5_qp_modify_exp(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_qp_attr *attr, int attr_mask,
+ enum ib_qp_state cur_state, enum ib_qp_state new_state,
+ u16 vlan_id);
+int roce5_modify_extend_qp(struct ib_qp_attr *attr, int attr_mask,
+ struct ib_qp *ibqp);
+
+#endif //ROCE_QP_EXP_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ext.c b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ext.c
new file mode 100644
index 000000000..a548667ee
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ext.c
@@ -0,0 +1,39 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#include "roce_qp.h"
+#include "roce_infra.h"
+#include "roce_obj_ext.h"
+#ifdef ENABLE_HYPER_ROCE
+#include "hyper_roce_qp.h"
+#endif
+
+const struct roce5_ext_reg g_rqp_exts[] = {
+#ifdef ENABLE_HYPER_ROCE
+ {
+ .ext_id = ROCE_EXT_HYPER_ROCE,
+ .data_size = sizeof(struct roce5_qp_hyper_extend),
+ .init_func = roce5_hyper_qp_init,
+ .cleanup_func = roce5_hyper_qp_cleanup,
+ },
+#endif
+};
+
+const u8 g_rqp_exts_num = sizeof(g_rqp_exts) / sizeof(struct roce5_ext_reg);
+
+int roce5_create_qp_ext_init(struct roce5_qp *rqp)
+{
+ int ret = roce5_obj_ext_init((void *)rqp, g_rqp_exts, g_rqp_exts_num,
+ &rqp->obj_ext);
+ if (ret != 0) {
+ ROCE_ERR("Failed to init qp extension, ret(%d).", ret);
+ return ret;
+ }
+ return 0;
+}
+
+void roce5_destroy_qp_ext_deinit(struct roce5_qp *rqp)
+{
+ roce5_obj_ext_deinit((void *)rqp, g_rqp_exts, g_rqp_exts_num,
+ &rqp->obj_ext);
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ext.h b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ext.h
new file mode 100644
index 000000000..8b3e95565
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_ext.h
@@ -0,0 +1,19 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_QP_EXT_H
+#define ROCE_QP_EXT_H
+
+#include "roce_qp.h"
+#include "roce_obj_ext.h"
+
+static inline void *roce5_qp_get_ext_buf(struct roce5_qp *rqp,
+ enum ROCE_EXT_ID ext_id)
+{
+ return roce5_obj_ext_get_buf(&rqp->obj_ext, ext_id);
+}
+
+int roce5_create_qp_ext_init(struct roce5_qp *rqp);
+void roce5_destroy_qp_ext_deinit(struct roce5_qp *rqp);
+
+#endif /* ROCE_QP_EXT_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_inner.h b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_inner.h
new file mode 100644
index 000000000..c757ce2ba
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_inner.h
@@ -0,0 +1,17 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
+
+
+#ifndef ROCE_QP_INNER_H
+#define ROCE_QP_INNER_H
+
+#include <rdma/ib_verbs.h>
+#include "roce.h"
+#include "roce_qp.h"
+
+int roce5_destroy_qp_common(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_udata *udata);
+void roce5_destroy_qp_user_umem_mtt(struct roce5_device *rdev,
+ struct roce5_qp *rqp);
+
+#endif /* ROCE_QP_INNER_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_modify.c b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_modify.c
new file mode 100644
index 000000000..5a6a4ec7b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_modify.c
@@ -0,0 +1,2398 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <rdma/ib_verbs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+
+#include "comm_defs.h"
+#include "roce_compat.h"
+#include "hinic5_srv_nic.h"
+
+#include "roce.h"
+#include "roce_mix.h"
+#include "roce_mr.h"
+#include "roce_user.h"
+#include "roce_xrc.h"
+#include "roce_pd.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_cqm_cmd.h"
+#include "roce_qp.h"
+#include "roce_qp_exp.h"
+#include "roce_qp_extension.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#include "securec.h"
+#include "roce_ctx_format.h"
+#include "roce_npu_cmd.h"
+#include "roce_npu_cmd_qp_defs.h"
+#include "roce_npu_cmd_ext_defs.h"
+#include "roce_cmd.h"
+#include "roce_uld_kernel_api.h"
+#include "roce_uld_inner.h"
+#include "roce_netdev.h"
+#include "roce_os_compat.h"
+
+#ifdef ROCE_ANTI_ATTACK
+#include "roce_anti_attack.h"
+#endif
+
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+#define ROCE_MTT_GPA_VALID 0x1
+#define ROCE_WQE_PREFETCH_MAXNUM 5 //5: 8(count word) WQEBB
+#define ROCE_SQ_WQEBB_SIZE_SHIFT 4
+#define ROCE_SQ_WQEBB_SIZE_MASK 0x7
+#define ROCE_SQ_PD_MASK 0x3ffff
+#define ROCE_SQ_PAGE_SIZE_MASK 0xf
+#define ROCE_SQ_WQECNT_LTH 4
+#define ROCE_SQ_PREFETCH_MINNUM 2
+#define ROCE_SQ_PREFETCH_MAXNUM 4
+#define ROCE_SQ_SIZE_MASK 0x1f
+#define ROCE_SQ_CQN_MASK 0xfffff
+#define ROCE_RQ_WQECNT_LTH 0xe
+#define ROCE_RQ_MTT_PREFETCH_MAXLEN0 3
+#define ROCE_RQ_MTT_PREFETCH_MAXWQE 7
+#define ROCE_RQ_WQE_PREFETCH_MAXNUM 7
+#define ROCE_SRQ_INIT_STATE 0xf
+#define ROCE_MAX_PI_ON_CHIP_QPN 1024
+
+enum {
+ BIT_LENGTH_IB_MTU_256 = 8,
+ BIT_LENGTH_IB_MTU_512,
+ BIT_LENGTH_IB_MTU_1024,
+ BIT_LENGTH_IB_MTU_2048,
+ BIT_LENGTH_IB_MTU_4096,
+ BIT_LENGTH_IB_MTU_8192,
+};
+
+enum {
+ CACHE_INVLAID_ALLOC,
+ CACHE_INVLAID_CMDQ,
+ CACHE_INVLAID_RDMARC_CHECK,
+ CACHE_INVLAID_QP_CHECK,
+ MODIFY_2RST_CMDQ,
+ CMDQ_SDKCALL_BUTT
+};
+
+#define ROCE_CMDQ_TIMEOUT 1000
+#define ROCE_CMDQ_TIMEOUT_10MS 10
+
+#ifdef ROCE_SIGN_EN
+enum mtt_check_type_e { MTT_CHECK_TYPE_0 = 0, MTT_CHECK_TYPE_1 };
+
+#define ROCE_QP_QPCC_SIGN_WIDTH 5
+#define ROCE_QP_QPCC_SIGN_SPLITNUM 4
+#define ROCE_QP_QPCC_SIGN_CHECKBITS \
+ (ROCE_QP_QPCC_SIGN_WIDTH * ROCE_QP_QPCC_SIGN_SPLITNUM)
+
+#define ROCE_QP_SUB_SIGN_WIDTH 3
+#define ROCE_QP_SUB_SIGN_SPLITNUM 5
+#define ROCE_QP_SUB_SIGN_CHECKBITS \
+ (ROCE_QP_SUB_SIGN_WIDTH * ROCE_QP_SUB_SIGN_SPLITNUM)
+
+#define ROCE_QP_GPA_SIGN_WIDTH 3
+#define ROCE_QP_GPA_SIGN_SPLITNUM 11
+#define ROCE_QP_GPA_SIGN_CHECKBITS \
+ (ROCE_QP_GPA_SIGN_WIDTH * ROCE_QP_GPA_SIGN_SPLITNUM)
+
+#define ROCE_SQ_WQE_SIGN_WIDTH 8
+#define ROCE_SQ_WQE_SIGN_SPLITNUM 9
+#define ROCE_SQ_WQE_SIGN_CHECKBITS_1 32
+#define ROCE_SQ_WQE_SIGN_CHECKBITS_2 20
+#define ROCE_SQ_WQE_SIGN_CHECKBITS_12 \
+ (ROCE_SQ_WQE_SIGN_CHECKBITS_2 + ROCE_SQ_WQE_SIGN_CHECKBITS_1)
+#define ROCE_SQ_WQE_SIGN_CHECKBITS_3 20
+#define ROCE_SQ_WQE_SIGN_CHECKBITS_123 \
+ (ROCE_SQ_WQE_SIGN_CHECKBITS_3 + ROCE_SQ_WQE_SIGN_CHECKBITS_12)
+#define ROCE_SQ_WQE_SIGN_CHECKBITS \
+ (ROCE_SQ_WQE_SIGN_WIDTH * ROCE_SQ_WQE_SIGN_SPLITNUM)
+
+#define ROCE_MTT_SIGN_WIDTH 11
+#define ROCE_MTT_SIGN_SPLITNUM 5
+#define ROCE_MTT_SIGN_CHECKBITS_1 22
+#define ROCE_MTT_SIGN_CHECKBITS_2 33
+#define ROCE_MTT_SIGN_CHECKBITS_12 \
+ (ROCE_MTT_SIGN_CHECKBITS_1 + ROCE_MTT_SIGN_CHECKBITS_2)
+#define ROCE_MTT_SIGN_CHECKBITS (ROCE_MTT_SIGN_WIDTH * ROCE_MTT_SIGN_SPLITNUM)
+
+#define ROCE_MTT_BLOCK_SIGN_WIDTH 5
+#define ROCE_MTT_BLOCK_SIGN_SPLITNUM 11
+
+/* ****************************************************************************
+ Prototype : roce5_calculate_sign_bit
+ Description : roce5_calculate_signature
+ Input : u32 *check_bit
+ u32 sign_width
+ u32 sign_split
+ u32 *sign_bit
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_calculate_sign_bit(u32 *check_bit, u32 sign_width,
+ u32 sign_split, u32 *sign_bit)
+{
+ u32 i = 0;
+ u32 j = 0;
+
+ for (i = 0; i < sign_width; i++) {
+ sign_bit[i] = 0;
+ for (j = 0; j < sign_split; j++) {
+ sign_bit[i] = sign_bit[i] ^
+ check_bit[i + sign_width * j];
+ }
+
+ sign_bit[i] = (~sign_bit[i]) & 0x1;
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_calculate_signature
+ Description : roce5_calculate_signature
+ Input : u32 *sign_bit
+ u32 sign_width
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+**************************************************************************** */
+static u32 roce5_calculate_signature(u32 *sign_bit, u32 sign_width)
+{
+ u32 i = 0;
+ u32 signature = 0;
+
+ for (i = 0; i < sign_width; i++) {
+ signature |= sign_bit[i] << i;
+ }
+
+ return (signature & ((1U << sign_width) - 1));
+}
+
+/* ****************************************************************************
+ Prototype : roce5_gen_qp_rcc_sign
+ Description : Signature 3bit
+ CheckedBits = QPn[14:0]
+ Input : u32 qpn
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+**************************************************************************** */
+static u32 roce5_gen_qp_rcc_sign(u32 qpn)
+{
+ u32 i;
+ u32 signature = 0;
+ u32 sign_bit[ROCE_QP_SUB_SIGN_WIDTH] = { 0 };
+ u32 check_bit[ROCE_QP_SUB_SIGN_CHECKBITS] = { 0 };
+
+ for (i = 0; i < ROCE_QP_SUB_SIGN_CHECKBITS; i++) {
+ if (qpn & (1U << i)) {
+ check_bit[i] = 1;
+ }
+ }
+
+ roce5_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce5_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_gen_qp_sqc_sign
+ Description : Signature 3bit
+ CheckedBits = QPn[14:0]
+ Input : u32 qpn
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+**************************************************************************** */
+static u32 roce5_gen_qp_sqc_sign(u32 qpn)
+{
+ u32 i;
+ u32 signature = 0;
+ u32 sign_bit[ROCE_QP_SUB_SIGN_WIDTH] = { 0 };
+ u32 check_bit[ROCE_QP_SUB_SIGN_CHECKBITS] = { 0 };
+
+ for (i = 0; i < ROCE_QP_SUB_SIGN_CHECKBITS; i++) {
+ if (qpn & (1U << i)) {
+ check_bit[i] = 1;
+ }
+ }
+
+ roce5_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce5_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_gen_qp_sqac_sign
+ Description : Signature 3bit
+ CheckedBits = QPn[14:0]
+ Input : u32 qpn
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+**************************************************************************** */
+static u32 roce5_gen_qp_sqac_sign(u32 qpn)
+{
+ u32 i;
+ u32 signature = 0;
+ u32 sign_bit[ROCE_QP_SUB_SIGN_WIDTH] = { 0 };
+ u32 check_bit[ROCE_QP_SUB_SIGN_CHECKBITS] = { 0 };
+
+ for (i = 0; i < ROCE_QP_SUB_SIGN_CHECKBITS; i++) {
+ if (qpn & (1U << i)) {
+ check_bit[i] = 1;
+ }
+ }
+
+ roce5_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce5_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_gen_qp_rqc_sign
+ Description : Signature 3bit
+ CheckedBits = QPn[14:0]
+ Input : u32 qpn
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+**************************************************************************** */
+static u32 roce5_gen_qp_rqc_sign(u32 qpn)
+{
+ u32 i;
+ u32 signature = 0;
+ u32 sign_bit[ROCE_QP_SUB_SIGN_WIDTH] = { 0 };
+ u32 check_bit[ROCE_QP_SUB_SIGN_CHECKBITS] = { 0 };
+
+ for (i = 0; i < ROCE_QP_SUB_SIGN_CHECKBITS; i++) {
+ if (qpn & (1U << i)) {
+ check_bit[i] = 1;
+ }
+ }
+
+ roce5_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce5_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_gen_qp_rrwc_sign
+ Description : Signature 3bit
+ CheckedBits = QPn[14:0]
+ Input : u32 qpn
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+**************************************************************************** */
+static u32 roce5_gen_qp_rrwc_sign(u32 qpn)
+{
+ u32 i;
+ u32 signature = 0;
+ u32 sign_bit[ROCE_QP_SUB_SIGN_WIDTH] = { 0 };
+ u32 check_bit[ROCE_QP_SUB_SIGN_CHECKBITS] = { 0 };
+
+ for (i = 0; i < ROCE_QP_SUB_SIGN_CHECKBITS; i++) {
+ if (qpn & (1U << i)) {
+ check_bit[i] = 1;
+ }
+ }
+
+ roce5_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce5_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_gen_sq_wqe_sign
+ Description : Signature 8bit
+ CheckedBits = {QPn[19:0], WQECI[19:0], WQE.Header[31:0]}
+ Input : u32 qpn
+ u32 wqe_ci
+ u32 wqe_header
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+**************************************************************************** */
+static u32 roce5_gen_sq_wqe_sign(u32 qpn, u32 wqe_ci, u32 wqe_header)
+{
+ u32 i;
+ u32 signature = 0;
+ u32 sign_bit[ROCE_SQ_WQE_SIGN_WIDTH] = { 0 };
+ u32 check_bit[ROCE_SQ_WQE_SIGN_CHECKBITS] = { 0 };
+
+ for (i = 0; i < ROCE_SQ_WQE_SIGN_CHECKBITS_1; i++) {
+ if (wqe_header & (1U << i)) {
+ check_bit[i] = 1;
+ }
+ }
+
+ for (i = ROCE_SQ_WQE_SIGN_CHECKBITS_1;
+ i < ROCE_SQ_WQE_SIGN_CHECKBITS_12; i++) {
+ if (wqe_ci & (1U << (i - ROCE_SQ_WQE_SIGN_CHECKBITS_1))) {
+ check_bit[i] = 1;
+ }
+ }
+
+ for (i = ROCE_SQ_WQE_SIGN_CHECKBITS_12;
+ i < ROCE_SQ_WQE_SIGN_CHECKBITS_123; i++) {
+ if (qpn & (1U << (i - ROCE_SQ_WQE_SIGN_CHECKBITS_12))) {
+ check_bit[i] = 1;
+ }
+ }
+
+ roce5_calculate_sign_bit(check_bit, ROCE_SQ_WQE_SIGN_WIDTH,
+ ROCE_SQ_WQE_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce5_calculate_signature(sign_bit, ROCE_SQ_WQE_SIGN_WIDTH);
+
+ return signature;
+}
+#endif
+
+#define ROCE_BASE_GID_IDX \
+ 1 /* current IP mode supports precise push GID, reserved this field compatible old version firmware */
+static void roce5_qp_set_path(const struct roce5_qp *rqp,
+ struct rdma_ah_attr *ah_attr,
+ roce_verbs_qpc_attr_path_s *path_info)
+{
+ u8 *dmac = ah_attr->roce.dmac;
+ int ret;
+
+ path_info->dw7.bs.hoplmt = (u8)ah_attr->grh.hop_limit;
+ path_info->dw6.bs.tclass =
+ (u8)(ah_attr->grh.traffic_class | IP_ECN_PERMIT);
+ path_info->dw6.bs.flow_label = ah_attr->grh.flow_label &
+ 0xfffff; /* flow_label: 20bit */
+ path_info->dw7.bs.sgid_index = ah_attr->grh.sgid_index &
+ 0x7f; /* sgid_index: 7bit */
+
+ path_info->dw7.bs.base_sgid_n =
+ (path_info->dw7.bs.sgid_index != ROCE_BASE_GID_IDX);
+
+ ret = memcpy_s((void *)path_info->dgid, sizeof(path_info->dgid),
+ (void *)ah_attr->grh.dgid.raw, sizeof(path_info->dgid));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dgid.(ret:%d)", ret);
+ }
+
+ ret = memcpy_s((void *)&path_info->dmac_l32,
+ sizeof(path_info->dmac_l32),
+ (void *)&dmac[ROCE_RAH_DMAC_L32_START],
+ sizeof(path_info->dmac_l32));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dmac_l32.(ret:%d)", ret);
+ }
+ path_info->dmac_l32 = cpu_to_be32(path_info->dmac_l32);
+ path_info->dw0.bs.dmac_h16 = (dmac[0] << ROCE_RAH_DMAC_H16_SHIFT) |
+ dmac[1]; //shift dmac[0] left by 8 bits
+ path_info->dw7.bs.sl = (ah_attr->sl & 0x7); /* sl: 3bit */
+ path_info->dw0.bs.udp_src_port_h =
+ ((rqp->qpn >> ROCE_UDP_SRC_PORT_H8_SHIFT) & 0xff);
+ path_info->dw7.bs.udp_src_port = (rqp->qpn & 0xff);
+#ifdef ROCE_BONDING_EN
+ path_info->dw0.bs.bond_tx_hash_value = (rqp->tx_hash_value & 0xf);
+#endif
+}
+
+struct roce5_pd *roce5_get_pd(struct roce5_qp *rqp)
+{
+ if (rqp->qp_type == IB_QPT_XRC_TGT) {
+ return to_roce5_pd(to_roce5_xrcd(rqp->ibqp.xrcd)->pd);
+ } else {
+ return to_roce5_pd(rqp->ibqp.pd);
+ }
+}
+
+void roce5_get_cqs(struct roce5_qp *rqp, struct roce5_cq **send_cq,
+ struct roce5_cq **recv_cq)
+{
+ switch (rqp->qp_type) {
+ case IB_QPT_XRC_TGT:
+ *send_cq = to_roce5_cq(to_roce5_xrcd(rqp->ibqp.xrcd)->cq);
+ *recv_cq = *send_cq;
+ break;
+
+ case IB_QPT_XRC_INI:
+ *send_cq = to_roce5_cq(rqp->ibqp.send_cq);
+ *recv_cq = *send_cq;
+ break;
+
+ default:
+ *send_cq = to_roce5_cq(rqp->ibqp.send_cq);
+ *recv_cq = to_roce5_cq(rqp->ibqp.recv_cq);
+ break;
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_set_access_flags
+ Description : roce5_set_access_flags
+ Input : struct roce5_qp *rqp
+ roce_verbs_qp_attr_s *qp_attr
+ struct ib_qp_attr *attr
+ int attr_mask
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+ 2.Date : 2016/2/26
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_set_access_flags(struct roce5_qp *rqp,
+ roce_verbs_qp_attr_s *qp_attr,
+ struct ib_qp_attr *attr, int attr_mask)
+{
+ u16 dest_rd_atomic = 0;
+ u32 access_flags = 0;
+
+ if ((((u32)attr_mask) & IB_QP_MAX_DEST_RD_ATOMIC) != 0) {
+ dest_rd_atomic = attr->max_dest_rd_atomic;
+ } else {
+ dest_rd_atomic = rqp->rsp_depth;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_ACCESS_FLAGS) != 0) {
+ access_flags = (u32)attr->qp_access_flags;
+ } else {
+ access_flags = rqp->atomic_rd_en;
+ }
+
+ if (dest_rd_atomic == 0) {
+ access_flags &= IB_ACCESS_REMOTE_WRITE;
+ }
+
+ if ((access_flags & IB_ACCESS_REMOTE_READ) != 0) {
+ qp_attr->com_info.dw0.bs.rre = 1; /* rc_rre: 1bits */
+ }
+
+ if ((access_flags & IB_ACCESS_REMOTE_ATOMIC) != 0) {
+ qp_attr->com_info.dw0.bs.rae = 1; /* rc_rae: 1bits */
+ }
+
+ if ((access_flags & IB_ACCESS_REMOTE_WRITE) != 0) {
+ qp_attr->com_info.dw0.bs.rwe = 1; /* rrw_rwe: 1bits */
+ }
+}
+
+bool roce5_sqp_check(const struct roce5_qp *rqp)
+{
+ if (((rqp->qp_type == IB_QPT_GSI) &&
+ (rqp->qpn == ROCE_QP_SMI_QP_NUM)) ||
+ (rqp->qpn == ROCE_QP_GSI_QP_NUM)) {
+ return true;
+ }
+
+ return false;
+}
+
+/* ****************************************************************************
+ Prototype : store_sqp_attrs
+ Description : save the special
+ Input : struct roce5_qp *rqp
+ const struct ib_qp_attr *attr
+ int attr_mask
+ Output : int status
+
+ 1.Date : 2015/7/24
+ Modification : Created function
+
+**************************************************************************** */
+static int store_sqp_attrs(struct roce5_qp *rqp, const struct ib_qp_attr *attr,
+ int attr_mask)
+{
+ if (rqp->sqp_attr == NULL) {
+ ROCE_ERR("Error! sqp attribute is NULL, qpn(%u).", rqp->qpn);
+ return -EINVAL;
+ }
+
+ if (((u32)attr_mask & IB_QP_PKEY_INDEX) != 0) {
+ rqp->sqp_attr->pkey_index = attr->pkey_index;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_QKEY) != 0) {
+ rqp->sqp_attr->qkey = attr->qkey;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_SQ_PSN) != 0) {
+ rqp->sqp_attr->send_psn = attr->sq_psn;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : qpc_seg_to_be
+ Input : struct roce_qp_context *be_ctx
+ struct roce_qp_context *le_ctx
+ struct roce5_qp *rqp
+ Output : None
+
+ 1.Date : 2015/7/29
+ Author : zhaoxinteng
+ Modification : Created function
+
+**************************************************************************** */
+static void qpc_seg_to_be(roce_verbs_qp_attr_s *be_ctx,
+ roce_verbs_qp_attr_s *le_ctx, struct roce5_qp *rqp)
+{
+ /* DRV Seg */
+ int ret;
+
+ ret = memcpy_s((void *)be_ctx->path_info.dgid,
+ sizeof(le_ctx->path_info.dgid),
+ (void *)le_ctx->path_info.dgid,
+ sizeof(le_ctx->path_info.dgid));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dgid.(ret:%d)", ret);
+ }
+
+ /* CHIP Seg */
+ be_ctx->chip_seg.dw0.sq_rq_l0mtt_gpa =
+ cpu_to_be64(le_ctx->chip_seg.dw0.sq_rq_l0mtt_gpa);
+
+ be_ctx->chip_seg.dw2.sq_rq_pi_record_gpa_at_hop_num = cpu_to_be64(
+ le_ctx->chip_seg.dw2.sq_rq_pi_record_gpa_at_hop_num);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_qpc_to_be
+ Description : translate big endian
+ Input : roce_verbs_qp_attr_s *qp_attr
+ struct roce5_qp *rqp
+ u32 *be_ctx
+ Output : None
+
+ 1.Date : 2015/7/29
+ Author : zhaoxinteng
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_qpc_to_be(roce_verbs_qp_attr_s *qp_attr, struct roce5_qp *rqp,
+ u32 *be_ctx)
+{
+ u32 *ctx = NULL;
+ u32 *ctx1 = NULL;
+ u32 i = 0;
+ u32 ctx_size = 0;
+
+ ctx = be_ctx;
+ ctx1 = (u32 *)qp_attr;
+ ctx_size = sizeof(roce_verbs_qp_attr_s) / sizeof(u32);
+
+ for (i = 0; i < ctx_size; ++i, ++ctx1, ++ctx) {
+ *ctx = cpu_to_be32(*ctx1);
+ }
+
+ qpc_seg_to_be((roce_verbs_qp_attr_s *)((void *)be_ctx), qp_attr, rqp);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_alloc_opt_rdmarc
+ Description : alloc rdmarc when modify qp
+ Input : struct roce5_qp *rqp
+ struct ib_qp_attr *attr
+ int attr_mask
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_alloc_opt_rdmarc(struct roce5_qp *rqp,
+ const struct ib_qp_attr *attr, int attr_mask)
+{
+ int ret = 0;
+ struct roce5_device *rdev = NULL;
+ u32 response_depth = 0;
+
+ rdev = to_roce5_dev(rqp->ibqp.device);
+ response_depth = (attr->max_dest_rd_atomic == 0) ?
+ 1 :
+ (u32)ROCE_ROUNDUP_POW_OF_TWO(
+ (u32)attr->max_dest_rd_atomic);
+ if (rqp->rsp_depth != response_depth) {
+ if (rqp->rsp_depth > 0) {
+ roce5_rdma_rdmarc_free(rdev->hwdev, &rqp->rdmarc);
+ }
+
+ ret = roce5_rdma_rdmarc_alloc(rdev->hwdev, response_depth,
+ &rqp->rdmarc);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc rdma rdmarc, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ rqp->rsp_depth = (u16)response_depth;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_free_opt_rdmarc
+ Description : free rdmarc when modify qp failed or destory qp
+ Input : struct roce5_qp *rqp
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_free_opt_rdmarc(struct roce5_qp *rqp)
+{
+ struct roce5_device *rdev = NULL;
+
+ rdev = to_roce5_dev(rqp->ibqp.device);
+
+ if (rqp->rsp_depth > 0) {
+ roce5_rdma_rdmarc_free(rdev->hwdev, &rqp->rdmarc);
+ }
+
+ rqp->rsp_depth = 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_set_opt_rdmarc
+ Description : set opt rdmarc field
+ Input : struct roce5_device *rdev
+ struct roce5_qp *rqp
+ roce_verbs_qp_attr_s *qp_attr
+ Output : None
+
+ 1.Date : 2017/04/27
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_set_opt_rdmarc(struct rdma_rdmarc *rdmarc, u16 depth,
+ roce_verbs_qp_attr_s *qp_attr)
+{
+ qp_attr->chip_seg.dw10.bs.rc_page_gpa_h =
+ (rdmarc->dma_addr >> ROCE5_RDMARC_GPA_H_SHIFT) &
+ 0xffffff; /* high:24bit, 64-24= 40 */
+ qp_attr->chip_seg.rc_page_gpa_l =
+ (u32)(rdmarc->dma_addr >>
+ ROCE5_RDMARC_GPA_L_SHIFT); //bit[39:8]
+ qp_attr->chip_seg.dw4.bs.rc_size = rdmarc->order;
+ qp_attr->com_info.dw1.bs.rra_max =
+ ((u8)fls(depth - 1)) &
+ ROCE5_RDMARC_RRA_MAX_MASK; /* rra_max:3bit */
+ qp_attr->chip_seg.dw4.bs.rc_max_size =
+ rdmarc->ext_order - ROCE5_RDMARC_EXT_ORDER_SHIFT;
+}
+
+static int roce5_set_opt_mtu(struct roce5_device *rdev,
+ roce_verbs_qp_attr_s *qp_attr,
+ const struct ib_qp_attr *attr)
+{
+ enum roce5_mtu rmtu = (enum roce5_mtu)attr->path_mtu;
+ if (rmtu == ROCE_MTU_8192 && ROCE5_SUPPORT_8K_MTU(rdev) == 0) {
+ ROCE_DEV_ERR(rdev, "Not support 8K MTU.");
+ return -EINVAL;
+ }
+
+ qp_attr->com_info.dw3.bs.pmtu = (u32)rmtu & 0x7; /* 1,2,3,4,5 */
+ qp_attr->com_info.dw5.bs.mtu_code =
+ ROCE_QPC_PMTU_TRANSLATE(rmtu); /* 0,1,3,7,15 */
+ if (qp_attr->com_info.dw3.bs.pmtu == IB_MTU_1024) {
+ qp_attr->com_info.dw3.bs.base_mtu_n = 0;
+ } else {
+ qp_attr->com_info.dw3.bs.base_mtu_n = 1;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_set_opt_sra
+ Description : set opt sra
+ Input : roce_verbs_qp_attr_s *qp_attr
+ struct ib_qp_attr *attr
+ Output : None
+
+ 1.Date : 2017/04/27
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_set_opt_sra(roce_verbs_qp_attr_s *qp_attr,
+ struct ib_qp_attr *attr)
+{
+ u8 initiator_depth;
+
+ initiator_depth =
+ (attr->max_rd_atomic == 0) ?
+ 1 :
+ (u8)ROCE_ROUNDUP_POW_OF_TWO((u32)attr->max_rd_atomic);
+ qp_attr->com_info.dw1.bs.sra_max =
+ ((u32)ROCE_FLS(initiator_depth - 1)) & 0x7;
+}
+
+static void roce5_set_opt_attr_av(struct roce5_qp *rqp,
+ struct roce5_device *rdev,
+ struct ib_qp_attr *attr,
+ roce_verbs_qp_attr_s *qp_attr, u32 *optpar)
+{
+ u8 cos;
+ roce5_get_cos_inbuf_s inbuf = { 0 };
+
+ roce5_qp_set_path(rqp, &attr->ah_attr, &qp_attr->path_info);
+ qp_attr->com_info.dw3.bs.ext_mtu = rqp->ext_mtu & 0x1;
+ qp_attr->com_info.dw3.bs.ext_md = rqp->ext_mtu_mode & 0x1;
+ *optpar |= ROCE_QP_OPTPAR_PRIMARY_ADDR_PATH;
+
+ inbuf.sl = attr->ah_attr.sl;
+ inbuf.sgid_index = attr->ah_attr.grh.sgid_index;
+ inbuf.port_num = attr->ah_attr.port_num;
+ inbuf.traffic_class = attr->ah_attr.grh.traffic_class;
+
+ (void)roce5_get_dcb_cfg_cos(rdev, &inbuf, &cos, rqp->qp_type);
+
+ qp_attr->com_info.dw5.bs.cos = cos;
+
+ rqp->db_sgid_index = attr->ah_attr.grh.sgid_index & 0x7f;
+ rqp->db_cos = cos;
+}
+
+static void roce5_set_opt_field_attr(struct roce5_qp *rqp,
+ const struct ib_qp_attr *attr,
+ int attr_mask,
+ roce_verbs_qp_attr_s *qp_attr, u32 *optpar)
+{
+ /* RTR2RTS/SQD2SQD RETRY_CNT */
+ if ((((u32)attr_mask) & IB_QP_RETRY_CNT) != 0) {
+ qp_attr->com_info.dw1.bs.to_retry_limit =
+ attr->retry_cnt & 0x7; /* to_retry_limit:3 */
+ *optpar |= ROCE_QP_OPTPAR_RETRY_COUNT;
+ }
+
+ /* RTR2RTS/SQD2SQD RNR_RETRY */
+ if ((((u32)attr_mask) & IB_QP_RNR_RETRY) != 0) {
+ qp_attr->com_info.dw1.bs.rnr_retry_limit =
+ attr->rnr_retry & 0x7; /* rnr_retry_limit:3bits */
+ *optpar |= ROCE_QP_OPTPAR_RNR_RETRY;
+ }
+
+ /* INIT2RTR/SQD2SQD/RTR2RTS/RTS2RTS MIN_RNR_TIMER */
+ if ((((u32)attr_mask) & IB_QP_MIN_RNR_TIMER) != 0) {
+ qp_attr->com_info.dw2.bs.min_rnr_nak =
+ attr->min_rnr_timer & 0x1f; /* min_rnr_nak:5bits */
+ *optpar |= ROCE_QP_OPTPAR_RNR_TIMEOUT;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_SQ_PSN) != 0) {
+ qp_attr->com_info.dw8.bs.next_send_psn =
+ attr->sq_psn & 0xffffff; /* next_rcv_psn:24bit */
+ }
+
+ if ((((u32)attr_mask) & IB_QP_RQ_PSN) != 0) {
+ qp_attr->com_info.dw9.bs.next_rcv_psn =
+ attr->rq_psn & 0xffffff; /* next_rcv_psn:24bit */
+ }
+
+ if ((((u32)attr_mask) & IB_QP_DEST_QPN) != 0) {
+ qp_attr->com_info.dw0.bs.dest_qp = attr->dest_qp_num &
+ 0xffffff; /* dest_qp:24bit */
+ }
+
+ roce5_set_attr_ext(rqp, attr, qp_attr, attr_mask);
+}
+
+static s32 roce5_set_db_path_mtu(const struct ib_qp_attr *attr,
+ struct roce5_qp *rqp,
+ struct roce5_device *rdev)
+{
+ switch ((enum roce5_mtu)attr->path_mtu) {
+ case ROCE_MTU_256:
+ case ROCE_MTU_512:
+ ROCE_DEV_ERR(
+ rdev,
+ "Only support mtu larger than 1K.func_id(%d) mtu:%u",
+ rdev->glb_func_id, attr->path_mtu);
+ return -EINVAL;
+ case ROCE_MTU_1024:
+ rqp->db_path_mtu = BIT_LENGTH_IB_MTU_1024;
+ break;
+ case ROCE_MTU_2048:
+ rqp->db_path_mtu = BIT_LENGTH_IB_MTU_2048;
+ break;
+ case ROCE_MTU_4096:
+ rqp->db_path_mtu = BIT_LENGTH_IB_MTU_4096;
+ break;
+ case ROCE_MTU_8192:
+ if (ROCE5_SUPPORT_8K_MTU(rdev) != 0) {
+ rqp->db_path_mtu = BIT_LENGTH_IB_MTU_8192;
+ break;
+ }
+
+ ROCE_DEV_ERR(rdev, "Not support 8K MTU.");
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_set_opt_field(struct roce5_qp *rqp, struct ib_qp_attr *attr,
+ int attr_mask,
+ roce_modify_qp_param_s *modify_para)
+{
+ int ret = 0;
+ roce_verbs_qp_attr_s *qp_attr = &modify_para->qp_attr;
+ u32 *optpar = &modify_para->optpar;
+ struct roce5_device *rdev = to_roce5_dev(rqp->ibqp.device);
+
+ if ((((u32)attr_mask) & IB_QP_QKEY) != 0) {
+ qp_attr->com_info.q_key = attr->qkey;
+ *optpar |= ROCE_QP_OPTPAR_Q_KEY;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_AV) != 0) {
+ roce5_set_opt_attr_av(rqp, rdev, attr, qp_attr, optpar);
+ }
+
+ if ((((u32)attr_mask) & IB_QP_PORT) != 0) {
+ qp_attr->com_info.dw5.bs.port = attr->port_num &
+ 0x7; /* port: 3bits */
+ *optpar |= ROCE_QP_OPTPAR_SCHED_QUEUE;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_MAX_DEST_RD_ATOMIC) != 0) {
+ roce5_set_opt_rdmarc(&rqp->rdmarc, rqp->rsp_depth, qp_attr);
+ *optpar |= ROCE_QP_OPTPAR_RRA_MAX;
+ }
+
+ /* RTR2RTS/SQD2SQD SRA_MAX */
+ if ((((u32)attr_mask) & IB_QP_MAX_QP_RD_ATOMIC) != 0) {
+ roce5_set_opt_sra(qp_attr, attr);
+ *optpar |= ROCE_QP_OPTPAR_SRA_MAX;
+ }
+
+ /* RWE/RRE/RAE,RST2INIT */
+ if ((((u32)attr_mask) &
+ (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) != 0) {
+ roce5_set_access_flags(rqp, qp_attr, attr, attr_mask);
+ *optpar |= ROCE_QP_OPTPAR_RWE | ROCE_QP_OPTPAR_RRE |
+ ROCE_QP_OPTPAR_RAE;
+ }
+
+ /* RTR2RTS/SQD2SQD ACK TIMEOUT */
+ if ((((u32)attr_mask) & IB_QP_TIMEOUT) != 0) {
+ qp_attr->com_info.dw2.bs.ack_to = attr->timeout &
+ 0x1f; /* ack_to:5bits */
+ *optpar |= ROCE_QP_OPTPAR_ACK_TIMEOUT;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_PATH_MTU) != 0) {
+ ret = roce5_set_db_path_mtu(attr, rqp, rdev);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = roce5_set_opt_mtu(rdev, qp_attr, attr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to set MTU.");
+ return ret;
+ }
+ }
+
+ roce5_set_opt_field_attr(rqp, attr, attr_mask, qp_attr, optpar);
+ return ret;
+}
+
+static void roce5_set_qp_srq_attr(struct roce5_qp *rqp,
+ roce_verbs_qp_attr_s *qp_attr,
+ struct roce5_pd *pd,
+ const struct roce5_cq *recv_cq)
+{
+ struct roce5_srq *rsrq = to_roce5_srq(rqp->ibqp.srq);
+ struct roce5_srq_context temp;
+
+ if (rsrq->container_flag != 0) {
+ struct roce5_srq_context *srqc =
+ (struct roce5_srq_context *)((void *)rsrq->cqm_srq
+ ->q_ctx_vaddr);
+ temp.dw0.value = be32_to_cpu(srqc->dw0.value);
+ qp_attr->chip_seg.dw12.bs.srq_pd = temp.dw0.bs.pdn &
+ 0x3ffff; /* srq_pd:18bits */
+ qp_attr->chip_seg.dw12.bs.srq_wqebb_size =
+ temp.dw0.bs.wqebb_size;
+ qp_attr->chip_seg.dw12.bs.srq_page_size = temp.dw0.bs.page_size;
+ qp_attr->chip_seg.dw12.bs.srq_size = temp.dw0.bs.size;
+
+ temp.dw1.value = be32_to_cpu(srqc->dw1.value);
+ qp_attr->com_info.dw5.bs.so_ro = temp.dw1.bs_c.so_ro;
+ qp_attr->com_info.dw5.bs.dma_attr_idx =
+ temp.dw1.bs_c.dma_attr_idx;
+
+ qp_attr->chip_seg.dw9.bs.container_sz =
+ MAX_SUPPORT_CONTAINER_MODE - rsrq->container_mode;
+ qp_attr->chip_seg.dw9.bs.container_en = 1;
+
+ qp_attr->com_info.dw3.bs.srq_container = 1;
+
+ if (rsrq->rqe_cnt_th > 0) {
+ qp_attr->chip_seg.dw9.bs.srq_warth_flag = 1;
+ qp_attr->chip_seg.dw8.bs.srq_rqecnt_th =
+ rsrq->rqe_cnt_th &
+ 0xf; /* srq_rqecnt_th:4bits */
+ }
+
+ qp_attr->chip_seg.dw7.bs.srqn = rsrq->srqn &
+ 0x3ffff; /* srqn:18bits */
+ } else {
+ qp_attr->chip_seg.dw7.bs.srqn = rsrq->srqn &
+ 0x3ffff; /* srqn:18bits */
+ }
+
+ qp_attr->com_info.dw2.bs.srq_en = 1;
+ qp_attr->chip_seg.dw12.bs.srq_rkey_en = 1;
+ qp_attr->com_info.dw0.bs.rkey_en = 1;
+ qp_attr->chip_seg.dw13.bs.srq_cqn = recv_cq->cqn &
+ 0xfffff; /* rq_cqn:20bits */
+ qp_attr->chip_seg.dw9.bs.srq_mtt_prefetch_maxlen1 = 1;
+}
+
+static void roce5_set_qp_rst2init_attr(struct roce5_qp *rqp,
+ roce_verbs_qp_attr_s *qp_attr,
+ struct roce5_pd *pd,
+ struct roce5_cq *recv_cq)
+{
+ qp_attr->chip_seg.dw4.bs.rq_base_ci =
+ (u32)(ROCE_ILOG2(rqp->rq.offset >> rqp->rq.wqe_shift));
+ qp_attr->chip_seg.dw19.bs.qp_pd = pd->pdn & 0x3ffff; /* pd:18bits */
+ qp_attr->com_info.dw3.bs.dsgl_en = rqp->double_sgl_mode & 0x1;
+
+ if (rqp->ibqp.srq != NULL) {
+ roce5_set_qp_srq_attr(rqp, qp_attr, pd, recv_cq);
+ } else {
+ qp_attr->chip_seg.dw15.bs.rq_size =
+ (rqp->rq.wqebb_cnt > 0) ?
+ (((u32)ROCE_ILOG2(rqp->rq.wqebb_cnt)) & 0x1f) :
+ 0;
+ qp_attr->chip_seg.dw15.bs.rq_page_size =
+ ((u32)((u32)rqp->buf.page_shift - PAGE_SHIFT_4K)) &
+ ROCE_SQ_PAGE_SIZE_MASK;
+ qp_attr->chip_seg.dw15.bs.rq_pd = pd->pdn &
+ 0x3ffff; /* pd:18bits */
+ qp_attr->chip_seg.dw8.bs.rq_wqebb_size =
+ (u32)(rqp->rq.wqe_shift - BYTES_TO_16B_SHIFT) & 0x7;
+ qp_attr->com_info.dw7.bs.rq_cqn = recv_cq->cqn &
+ 0xfffff; /* rq_cqn:20bits */
+ qp_attr->chip_seg.dw15.bs.rq_rkey_en = 1;
+
+ qp_attr->chip_seg.dw8.bs.rq_pi_on_chip = 0;
+ qp_attr->chip_seg.dw7.bs.rq_wqecnt_lth = ROCE_RQ_WQECNT_LTH;
+ qp_attr->chip_seg.dw7.bs.rq_wqecnt_rctl_en = 0;
+ qp_attr->chip_seg.dw7.bs.rq_wqe_cache_thd_sel = 0;
+ qp_attr->chip_seg.dw7.bs.rq_wqecnt_rctl = 0;
+ qp_attr->chip_seg.dw9.bs.rq_mtt_prefetch_maxlen0 =
+ ROCE_RQ_MTT_PREFETCH_MAXLEN0;
+ qp_attr->chip_seg.dw9.bs.rq_mtt_prefetch_maxlen1 = 0;
+ qp_attr->chip_seg.dw9.bs.rq_mtt_prefetch_maxwqe =
+ ROCE_RQ_MTT_PREFETCH_MAXWQE;
+ qp_attr->chip_seg.dw7.bs.rq_wqe_prefetch_minnum = 0;
+ qp_attr->chip_seg.dw7.bs.rq_wqe_prefetch_maxnum =
+ ROCE_RQ_WQE_PREFETCH_MAXNUM;
+ }
+}
+
+static void roce5_qp_rst2init_set_qpcc(roce_verbs_qp_attr_s *qp_attr,
+ struct roce5_qp *rqp,
+ const struct roce5_device *rdev)
+{
+ qp_attr->chip_seg.dw0.sq_rq_l0mtt_gpa = rqp->mtt.mtt_paddr;
+ qp_attr->chip_seg.dw2.sq_rq_pi_record_gpa_at_hop_num =
+ rqp->db.dma & (~0x3ULL); /* bits:63-2 */
+ qp_attr->chip_seg.dw2.sq_rq_pi_record_gpa_at_hop_num |=
+ rqp->mtt.mtt_layers & 0x3; /* bits:1-0 */
+ if (rqp->qp_type == IB_QPT_XRC_TGT) {
+ qp_attr->chip_seg.dw2.sq_rq_pi_record_gpa_at_hop_num =
+ rqp->wb_dma;
+ }
+
+ qp_attr->chip_seg.dw4.bs.sq_rq_mtt_page_size =
+ rqp->mtt.mtt_page_shift - PAGE_SHIFT_4K;
+ /* rc_entry_size:2bits */
+ qp_attr->chip_seg.dw10.bs.rc_entry_size =
+ ((u32)ROCE_ILOG2(rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .rdmarc_entry_sz >>
+ BYTES_TO_16B_SHIFT) &
+ 0x3);
+ qp_attr->chip_seg.dw14.bs.qp_rkey_en = 1;
+ qp_attr->chip_seg.dw10.bs.rc_entry_prefetch_maxnum = 0;
+}
+
+static void roce5_qp_rst2init_set_sqc_sqac(roce_verbs_qp_attr_s *qp_attr,
+ const struct roce5_qp *rqp,
+ const struct roce5_pd *pd,
+ const struct roce5_cq *send_cq)
+{
+ qp_attr->chip_seg.dw5.bs.sq_pi_on_chip = rqp->pi_on_chip;
+ qp_attr->chip_seg.dw16.bs.sq_wqebb_size =
+ ((u32)(rqp->sq.wqe_shift - ROCE_SQ_WQEBB_SIZE_SHIFT)) &
+ ROCE_SQ_WQEBB_SIZE_MASK;
+ qp_attr->chip_seg.dw16.bs.sq_pd = ((u32)pd->pdn) &
+ 0x3ffff; /* pd:18bits */
+ qp_attr->chip_seg.dw16.bs.sq_page_size =
+ ((u32)(rqp->buf.page_shift - PAGE_SHIFT_4K)) &
+ ROCE_SQ_PAGE_SIZE_MASK;
+ qp_attr->chip_seg.dw5.bs.sq_inline_en = (rqp->max_inline_data > 0) ? 1 :
+ 0;
+
+ qp_attr->chip_seg.dw16.bs.sq_rkey_en = 1;
+
+ qp_attr->chip_seg.dw5.bs.sq_wqecnt_lth = ROCE_SQ_WQECNT_LTH;
+ qp_attr->chip_seg.dw5.bs.sq_wqecnt_rctl_en = 0;
+ qp_attr->chip_seg.dw5.bs.sq_wqecnt_rctl = 0;
+ qp_attr->chip_seg.dw5.bs.sq_wqe_prefetch_minnum =
+ ROCE_SQ_PREFETCH_MINNUM;
+ qp_attr->chip_seg.dw5.bs.sq_wqe_prefetch_maxnum =
+ ROCE_SQ_PREFETCH_MAXNUM;
+ qp_attr->chip_seg.dw5.bs.sq_wqe_cache_thd_sel = 0;
+ qp_attr->chip_seg.dw6.bs.sq_wqe_prefetch_mode = 0;
+ qp_attr->chip_seg.dw6.bs.sq_mtt_prefetch_maxlen = 0;
+
+ if (rqp->sq.wqebb_cnt != 0) {
+ qp_attr->chip_seg.dw5.bs.sq_size =
+ (u32)(ROCE_ILOG2((u32)rqp->sq.wqebb_cnt)) &
+ ROCE_SQ_SIZE_MASK;
+ }
+
+ qp_attr->chip_seg.dw17.bs.sqa_cqn = send_cq->cqn & ROCE_SQ_CQN_MASK;
+
+ qp_attr->chip_seg.dw5.bs.sqa_wqe_prefetch_minnum =
+ ROCE_SQ_PREFETCH_MINNUM;
+ qp_attr->chip_seg.dw5.bs.sqa_wqe_prefetch_maxnum =
+ ROCE_WQE_PREFETCH_MAXNUM;
+ qp_attr->chip_seg.dw6.bs.sqa_mtt_prefetch_maxlen = 0;
+ qp_attr->chip_seg.dw5.bs.sqa_wqe_cache_thd_sel = 0;
+}
+
+static void roce5_qp_rst2init_set_drv(roce_verbs_qp_attr_s *qp_attr,
+ struct roce5_qp *rqp,
+ struct roce5_device *rdev)
+{
+ qp_attr->com_info.dw0.bs.service_type =
+ (u32)to_roce5_qp_type((enum ib_qp_type)rqp->qp_type) & 0x7;
+ qp_attr->com_info.dw3.bs.dif_en = (u32)rqp->signature_en;
+
+ if (!rqp->ibqp.uobject) {
+ qp_attr->com_info.dw0.bs.fre = 1;
+ }
+
+ qp_attr->com_info.dw3.bs.xrc_vld =
+ (u32)(rqp->qp_type == IB_QPT_XRC_INI);
+ qp_attr->com_info.dw1.bs.local_qp = rqp->qpn &
+ 0xffffff; /* local_qp:24bits */
+ qp_attr->com_info.dw5.bs.ep = rdev->hw_info.ep_id;
+ qp_attr->chip_seg.dw4.bs.dsgl = rqp->double_sgl_mode & 0x1;
+}
+
+static void roce5_qp_rst2init_set_common(roce_verbs_qp_attr_s *qp_attr,
+ const struct roce5_pd *pd,
+ const struct roce5_qp *rqp,
+ const struct roce5_cq *recv_cq,
+ const struct roce5_cq *send_cq)
+{
+ qp_attr->chip_seg.dw18.bs.ud_pd = pd->pdn & 0x3ffff; /* pd:18bits */
+
+ if (rqp->shadow != 0) {
+ qp_attr->com_info.dw11.bs.shadow = 1;
+ if (recv_cq != NULL) {
+ qp_attr->com_info.dw11.bs.shadow_vfid =
+ recv_cq->shadow_vfid;
+ }
+
+ if (send_cq != NULL) {
+ qp_attr->com_info.dw11.bs.shadow_cq_vfid =
+ send_cq->shadow_vfid;
+ }
+ }
+}
+
+static void roce5_qp_rst2init_set_xrc_attr(const struct roce5_qp *rqp,
+ const struct ib_qp_attr *attr,
+ roce_verbs_qp_attr_s *qp_attr,
+ const struct roce5_device *rdev,
+ const struct roce5_cq *recv_cq)
+{
+ qp_attr->com_info.dw2.bs.xrc_srq_en = 1;
+
+ if ((((u32)attr->qp_access_flags & XRC_CONTAINER_FLAG) != 0) ||
+ (rdev->cfg_info.srq_container_en != 0)) {
+ qp_attr->chip_seg.dw9.bs.container_en = 1;
+ qp_attr->com_info.dw3.bs.srq_container = 1;
+ qp_attr->chip_seg.dw8.bs.xrcd = rqp->xrcdn &
+ 0xffff; /* xrcd:16bits */
+ qp_attr->com_info.dw2.bs.srq_en = 1;
+ qp_attr->chip_seg.dw8.bs.srq_rqecnt_th = 1;
+ qp_attr->com_info.dw3.bs.xrc_vld = 1;
+ qp_attr->chip_seg.dw13.bs.srq_state = ROCE_SRQ_INIT_STATE;
+ } else {
+ qp_attr->chip_seg.dw12.bs.srq_rkey_en = 1;
+ qp_attr->com_info.dw2.bs.srq_en = 1;
+ qp_attr->chip_seg.dw8.bs.xrcd = rqp->xrcdn &
+ 0xffff; /* xrcd:16bits */
+ qp_attr->chip_seg.dw9.bs.srq_mtt_prefetch_maxlen1 = 1;
+ qp_attr->com_info.dw3.bs.xrc_vld = 1;
+ qp_attr->chip_seg.dw14.bs.srq_xrcd = rqp->xrcdn &
+ 0xffff; /* xrcd:16bits */
+ }
+ if (recv_cq != NULL) {
+ qp_attr->chip_seg.dw13.bs.srq_cqn = recv_cq->cqn &
+ 0xfffff; /* rq_cqn:20bits */
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_qp_rst2init
+ Description : parameter set when QP is from RESET to INIT
+ Input : struct roce5_qp *rqp
+ const struct ib_qp_attr *attr
+ roce_verbs_qp_attr_s *qp_attr
+ Output : None
+
+ 1.Date : 2015/8/6
+ Author : zhaoxinteng
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_qp_rst2init(struct roce5_qp *rqp, const struct ib_qp_attr *attr,
+ roce_verbs_qp_attr_s *qp_attr)
+{
+ struct roce5_pd *pd = NULL;
+ struct roce5_cq *send_cq = NULL;
+ struct roce5_cq *recv_cq = NULL;
+ struct roce5_device *rdev = NULL;
+
+ rdev = to_roce5_dev(rqp->ibqp.device);
+ pd = roce5_get_pd(rqp);
+ roce5_get_cqs(rqp, &send_cq, &recv_cq);
+
+ /* CHIP_SEG: QPCC */
+ roce5_qp_rst2init_set_qpcc(qp_attr, rqp, rdev);
+
+ /* CHIP_SEG: SQC & SQAC */
+ roce5_qp_rst2init_set_sqc_sqac(qp_attr, rqp, pd, send_cq);
+
+ /* RRWC */
+ qp_attr->chip_seg.dw4.bs.rrw_mtt_prefetch_maxlen = 0;
+
+ /* RCC */
+ qp_attr->chip_seg.dw10.bs.rc_mtt_prefetch_maxlen =
+ ROCE_QP_MAX_PFETCH_MTT_LAYER;
+
+ /* TIMER_SEG */
+ qp_attr->com_info.dw3.bs.tss_timer_num = ROCE_QP_MAX_TIMER_NUM;
+
+ /* DRV_SEG */
+ roce5_qp_rst2init_set_drv(qp_attr, rqp, rdev);
+
+ /* UCODE COM_SEG */
+ roce5_qp_rst2init_set_common(qp_attr, pd, rqp, recv_cq, send_cq);
+
+ if (rqp->qp_type == IB_QPT_XRC_TGT) {
+ roce5_qp_rst2init_set_xrc_attr(rqp, attr, qp_attr, rdev,
+ recv_cq);
+ } else {
+ roce5_set_qp_rst2init_attr(rqp, qp_attr, pd, recv_cq);
+ }
+
+#ifdef ROCE_BONDING_EN
+ roce5_bond_rr_set_flow(rdev, rqp, qp_attr);
+#endif
+}
+
+/* ****************************************************************************
+ Prototype : roce5_qp_init2rtr
+ Description : init2rtr attributes modify
+ Input : struct roce5_qp *rqp
+ const struct ib_qp_attr *attr
+ roce_verbs_qp_attr_s *qp_attr
+ Output : None
+
+ 1.Date : 2015/8/1
+ Author : zhaoxinteng
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_qp_init2rtr(struct roce5_qp *rqp,
+ const struct ib_qp_attr *attr,
+ roce_verbs_qp_attr_s *qp_attr)
+{
+ if (rqp->ibqp.srq || (rqp->qp_type == IB_QPT_XRC_TGT) ||
+ (rqp->qp_type == IB_QPT_XRC_INI) || (rqp->qp_type == IB_QPT_UD) ||
+ (rqp->qp_type == IB_QPT_UC) || (rqp->qp_type == IB_QPT_GSI)) {
+ qp_attr->com_info.dw3.bs.invalid_credit = 1;
+ }
+
+ if ((rqp->qp_type == IB_QPT_GSI) || (rqp->qp_type == IB_QPT_UD)) {
+ qp_attr->com_info.dw3.bs.pmtu = IB_MTU_4096 &
+ 0x7; /* for UD, mtu = 4096 */
+ qp_attr->com_info.dw5.bs.mtu_code = ROCE_MTU_CODE_4K;
+ }
+
+ qp_attr->com_info.dw2.bs.ack_to = 0xf; /* ack_to:5bits */
+ qp_attr->com_info.dw0.bs.service_type =
+ (u32)to_roce5_qp_type((enum ib_qp_type)rqp->qp_type) &
+ 0x7; /* service_type: 3bit */
+}
+
+/* ****************************************************************************
+ Prototype : roce5_qp_rtr2rts
+ Description : roce5_qp_rtr2rts
+ Input : struct roce5_qp *rqp
+ const struct ib_qp_attr *attr
+ roce_verbs_qp_attr_s *qp_attr
+ Output : None
+
+ 1.Date : 2015/8/2
+ Author : zhaoxinteng
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_qp_rtr2rts(struct roce5_qp *rqp,
+ const struct ib_qp_attr *attr,
+ roce_verbs_qp_attr_s *qp_attr)
+{
+}
+
+static void roce5_qp_2err(struct roce5_qp *rqp, const struct ib_qp_attr *attr,
+ roce_verbs_qp_attr_s *qp_attr)
+{
+}
+
+/* ****************************************************************************
+ Prototype : roce5_set_abs_field
+ Description : set abs field to qpc
+ Input : struct roce5_qp *rqp
+ struct ib_qp_attr *attr
+ roce_verbs_qp_attr_s *qp_attr
+ enum ib_qp_state cur_state
+ enum ib_qp_state new_state
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_set_abs_field(struct roce5_qp *rqp, struct ib_qp_attr *attr,
+ int attr_mask, roce_verbs_qp_attr_s *qp_attr)
+{
+ enum ib_qp_state cur_state, new_state;
+
+ cur_state =
+ (enum ib_qp_state)(((((u32)attr_mask) & IB_QP_CUR_STATE) != 0) ?
+ attr->cur_qp_state :
+ rqp->qp_state);
+ new_state = ((((u32)attr_mask) & IB_QP_STATE) != 0) ? attr->qp_state :
+ cur_state;
+ if ((cur_state == IB_QPS_RESET) && (new_state == IB_QPS_INIT)) {
+ roce5_qp_rst2init(rqp, attr, qp_attr);
+ }
+
+ if ((cur_state == IB_QPS_INIT) && (new_state == IB_QPS_RTR)) {
+ roce5_qp_init2rtr(rqp, attr, qp_attr);
+ }
+
+ if ((cur_state == IB_QPS_RTR) && (new_state == IB_QPS_RTS)) {
+ roce5_qp_rtr2rts(rqp, attr, qp_attr);
+ }
+
+ if (new_state == IB_QPS_ERR) {
+ roce5_qp_2err(rqp, attr, qp_attr);
+ }
+ return;
+}
+
+#ifdef ROCE_LATENCY_PROF_EN
+#define ROCE_SET_LATENCY_PROF_EN 5
+static int roce5_latency_prof_en_check(struct roce5_device *rdev,
+ u32 *latency_prof_en,
+ u32 *frequency_reduction_ratio)
+{
+ roce_dfx_set_inbuf_s buf_in = { 0 };
+ roce_dfx_set_outbuf_s buf_out = { 0 };
+ u32 out_size = sizeof(buf_out);
+ int ret = 0;
+ buf_in.show = 1;
+ buf_in.cmd_type = ROCE_CMD_ROCE_SET;
+ buf_in.sub_cmd_type = ROCE_SET_LATENCY_PROF_EN;
+ ret = roce5_adm_dfx_roce_set(rdev, &buf_in, sizeof(buf_in), &buf_out,
+ &out_size);
+ if (ret != 0) {
+ ROCE_ERR("latency prof query l2d err");
+ return ret;
+ }
+ *latency_prof_en = buf_out.sub_param.latency_prof.latency_prof_en;
+ *frequency_reduction_ratio =
+ buf_out.sub_param.latency_prof.frequency_reduction_ratio;
+ return 0;
+}
+
+static int
+roce5_latency_prof_time_get(struct roce5_device *rdev,
+ struct roce5_modify_qp_ex_resp_data *resp)
+{
+ struct hinic5_hwdev *hwdev = (struct hinic5_hwdev *)rdev->hwdev;
+ u32 latency_prof_en = 0;
+ u32 frequency_reduction_ratio = 1;
+ u64 time_diff = 0;
+ int ret = 0;
+ if (hwdev == NULL) {
+ ROCE_ERR("latency prof hwdev is null");
+ return (-EINVAL);
+ }
+ ret = roce5_latency_prof_en_check(rdev, &latency_prof_en,
+ &frequency_reduction_ratio);
+ if (ret != 0) {
+ return ret;
+ }
+ if (latency_prof_en == 0) {
+ resp->latency_prof_en = 0;
+ resp->non_ptp_time_diff = 0;
+ return 0;
+ }
+ //get clock time and non_ptp_chip time of difference value, convenient at later calculate timestamp
+ ret = hinic5_get_non_ptp_time_diff(hwdev, &time_diff);
+ if (ret != 0) {
+ ROCE_ERR("Failed to read n_ptp time, ret(%d)\n", ret);
+ return ret;
+ }
+ resp->latency_prof_en = 1;
+ resp->non_ptp_time_diff = time_diff;
+ resp->frequency_reduction_ratio = frequency_reduction_ratio;
+ return 0;
+}
+#endif
+static int roce5_record_opt_field(struct roce5_qp *rqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata,
+ roce_verbs_cmd_qp_modify_rsp_s *modify_rsp)
+{
+ int ret = 0;
+ int rsp_vld = 0;
+ enum ib_qp_state cur_state, new_state;
+ struct roce5_modify_qp_ex_resp_data resp = { 0 };
+ struct roce5_device *rdev = NULL;
+
+ cur_state =
+ (enum ib_qp_state)(((((u32)attr_mask) & IB_QP_CUR_STATE) != 0) ?
+ attr->cur_qp_state :
+ rqp->qp_state);
+ new_state = ((((u32)attr_mask) & IB_QP_STATE) != 0) ? attr->qp_state :
+ cur_state;
+ rqp->qp_state = new_state;
+
+ if ((((u32)attr_mask) & IB_QP_AV) != 0) {
+ rqp->sl = attr->ah_attr.sl & 0x7;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_ACCESS_FLAGS) != 0) {
+ rqp->atomic_rd_en = (u8)attr->qp_access_flags;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_PORT) != 0) {
+ rqp->port = attr->port_num;
+ }
+
+ if (roce5_sqp_check(rqp) != 0) {
+ ret = store_sqp_attrs(rqp, attr, attr_mask);
+ if (ret != 0) {
+ ROCE_ERR("Failed to store sqp attribute.");
+ return ret;
+ }
+ }
+
+ rdev = to_roce5_dev(rqp->ibqp.device);
+
+ /*
+ * TGT QP no has update pi requirement, and db trigger microcode thread and driver no has strict timing disable system, one general in init status trigger microcode,
+ * but if XRC TGT QP migration
至 rts after again trigger microcode thread, SQ hardware none permission, fetch wqe will exception, because this TGT QP not next db
+ * but non- TGT QP i.e. make in qp rst status trigger, will go via wqe empty
终结, not will exception
+ */
+ if ((cur_state == IB_QPS_RESET) && (new_state == IB_QPS_INIT) &&
+ (rqp->pi_on_chip != 0) && (rqp->qp_type != IB_QPT_XRC_TGT)) {
+ /* avoid PI on chip when PI
残keep, primary dynamic clear to zero */
+ ret = roce5_write_sq_db(rdev, rqp, 0, udata);
+ if (ret != 0) {
+ ROCE_ERR("Failed to clear PI on chip");
+ return -1;
+ }
+ }
+
+ if ((udata != NULL) && (udata->outbuf != NULL)) {
+ if ((cur_state == IB_QPS_INIT) && (new_state == IB_QPS_RTR) &&
+ (((u32)attr_mask & IB_QP_AV) != 0)) {
+ resp.cos = rqp->db_cos;
+ resp.is_cos_valid = 1;
+ rsp_vld = 1;
+ }
+
+#ifdef ROCE_LATENCY_PROF_EN
+ if (ROCE_IS_DEV_1825V100(rdev) && (cur_state == IB_QPS_RTR) &&
+ (new_state == IB_QPS_RTS)) {
+ ret = roce5_latency_prof_time_get(rdev, &resp);
+ if (ret != 0) {
+ ROCE_ERR("Failed to get time diff, ret(%d).",
+ ret);
+ return -1;
+ }
+ }
+#endif
+ /* compatible old card not will return ssn value, driver not perform update */
+ if (modify_rsp != NULL &&
+ modify_rsp->magic == ROCE_VERBS_MODIFY_RSP_MAGIC) {
+ resp.is_ssn_valid = modify_rsp->dw1.bs.is_ssn_vld;
+ resp.ssn = modify_rsp->dw1.bs.ssn;
+ rqp->sq_wqe_ssn = resp.ssn;
+ rsp_vld = 1;
+ }
+
+ if (rsp_vld != 0) {
+ ret = ib_copy_to_udata(
+ udata, &resp,
+ sizeof(struct roce5_modify_qp_ex_resp_data));
+ if (ret != 0) {
+ ROCE_ERR("Failed to copy data to user");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_qp_modify_2rst_cmd
+ Description : cache out qpc mtt
+ Input : struct roce5_device *rdev
+ struct roce5_qp *rqp
+ Output : None
+
+ 1.Date : 2016/6/17
+ Modification : Created function
+
+ 2.Date : 2017/04/26
+ Modification : Modify function
+
+**************************************************************************** */
+int roce5_qp_modify_2rst_cmd(struct roce5_device *rdev, u32 qpn)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_qp_modify2rst_s *qp_moidfy2rst_inbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_qp_modify2rst_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ qp_moidfy2rst_inbuf =
+ (roce_uni_cmd_qp_modify2rst_s *)cqm_cmd_inbuf->buf;
+ qp_moidfy2rst_inbuf->com.index = cpu_to_be32(qpn);
+ qp_moidfy2rst_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_QP_BITMASK));
+
+ ret = roce5_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_2RST_QP, cqm_cmd_inbuf,
+ NULL, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send 2RST_QP command, qpn(0x%x), func_id(%d), ret(0x%x)",
+ qpn, rdev->glb_func_id, ret);
+
+ ret = (-EINVAL);
+
+ if (hinic5_get_chip_present_flag(rdev->hwdev) == 0) {
+ ROCE_DEV_ERR(rdev,
+ "Card not present, return OK, func_id(%d)",
+ rdev->glb_func_id);
+ ret = 0;
+ }
+ goto err_out;
+ }
+
+err_out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_qp_check_rdmarc
+ Description : roce5_qp_check_rdmarc
+ Input : struct roce5_device *rdev
+ struct roce5_qp *rqp
+ Output : None
+
+ 1.Date : 2017/04/26
+ Modification : Create function
+
+**************************************************************************** */
+static int roce5_qp_check_rdmarc(struct roce5_device *rdev,
+ struct roce5_qp *rqp, int *cost)
+{
+ int times = 0;
+ u32 rc_num = 0;
+ u32 rc_check_index = 0;
+ void *rdmarc_vaddr = NULL;
+ dma_addr_t rdmarc_paddr = 0;
+
+ rc_num =
+ (u32)(((u32)1 << rqp->rdmarc.order) / RDMARC_NUM_PER_CACHELINE);
+ rdmarc_vaddr = rqp->rdmarc.vaddr;
+ rdmarc_paddr = rqp->rdmarc.dma_addr;
+
+ times = rdev->try_times;
+ do {
+ if ((*((u32 *)rdmarc_vaddr) ==
+ ROCE_RDMARC_DESTROY_CHECK_VALUE) &&
+ (cpu_to_be32(*((u32 *)rdmarc_vaddr + 1)) == rqp->qpn) &&
+ (cpu_to_be64(*((u64 *)rdmarc_vaddr + 1)) ==
+ ((u64)rdmarc_paddr +
+ ((u64)ROCE_CACHE_LINE_SIZE * (u64)rc_check_index)))) {
+ rdmarc_vaddr = (void *)((u8 *)rdmarc_vaddr +
+ ROCE_CACHE_LINE_SIZE);
+ rc_check_index++;
+ if (rc_num == rc_check_index) {
+ break;
+ }
+ } else {
+ ROCE_DELAY();
+ times--;
+ }
+ } while (times != 0);
+
+ if (rc_num != rc_check_index) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to read rdmarc field back after try %d times, func_id(%d) rc_check_index:%u rc_num:%u",
+ ((rdev->try_times - times) + 1), rdev->glb_func_id,
+ rc_check_index, rc_num);
+ *cost = (rdev->try_times - times) + 1;
+ return -1;
+ }
+ *cost = (rdev->try_times - times) + 1;
+ return 0;
+}
+
+static int roce5_qp_check_state(struct roce5_device *rdev,
+ const struct roce5_qp *rqp, const u32 *wb_va,
+ int *cost)
+{
+ int times = 0;
+ int read_back_flag = 0;
+
+ times = rdev->try_times;
+ while ((times--) != 0) {
+ if (*(u32 *)wb_va == ROCE_QP_DESTROY_CHECK_VALUE_HIGH_4B &&
+ (*((u32 *)wb_va + 1) ==
+ ROCE_QP_DESTROY_CHECK_VALUE_LOW_4B)) {
+ read_back_flag = 1;
+ break;
+ }
+ ROCE_DELAY();
+ }
+
+ if (read_back_flag == 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to read QP field back after try %d times,qpn(0x%x), wb_data(0x%x), wb_data+1(0x%x) func_id(%d)",
+ ((rdev->try_times - times) + 1), rqp->qpn,
+ *(u32 *)wb_va, *((u32 *)wb_va + 1), rdev->glb_func_id);
+ *cost = (rdev->try_times - times) + 1;
+ return -1;
+ }
+ *cost = (rdev->try_times - times) + 1;
+ return 0;
+}
+
+static void roce5_qp_fill_cacheout_inbuf(struct roce5_device *rdev,
+ struct roce5_qp *rqp,
+ dma_addr_t wb_dma,
+ cqm_cmd_buf_s *cqm_cmd_inbuf)
+{
+ roce_uni_cmd_qp_cache_invalid_s *qp_cacheout_inbuf = NULL;
+ struct rdma_service_cap *rdma_cap = NULL;
+ u32 page_size = roce5_get_page_size(rdev, true);
+
+ qp_cacheout_inbuf =
+ (roce_uni_cmd_qp_cache_invalid_s *)(cqm_cmd_inbuf)->buf;
+ rdma_cap = &rdev->rdma_cap;
+
+ qp_cacheout_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_QP_BITMASK));
+ qp_cacheout_inbuf->com.index = cpu_to_be32(rqp->qpn);
+ qp_cacheout_inbuf->qp_cache.sq_buf_len = cpu_to_be32(
+ ALIGN(((u32)rqp->sq.wqebb_cnt) << ((u32)rqp->sq.wqe_shift),
+ page_size));
+ qp_cacheout_inbuf->qp_cache.rq_buf_len = cpu_to_be32(
+ ALIGN(((u32)rqp->rq.wqebb_cnt) << ((u32)rqp->sq.wqe_shift),
+ page_size));
+ qp_cacheout_inbuf->qp_cache.cmtt_cache.mtt_flags = 0;
+ qp_cacheout_inbuf->qp_cache.cmtt_cache.mtt_num = 0;
+ qp_cacheout_inbuf->qp_cache.cmtt_cache.mtt_cache_line_start =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_start);
+ qp_cacheout_inbuf->qp_cache.cmtt_cache.mtt_cache_line_end =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_end);
+ qp_cacheout_inbuf->qp_cache.cmtt_cache.mtt_cache_line_size =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_sz);
+ qp_cacheout_inbuf->qp_cache.wb_gpa = cpu_to_be64(wb_dma);
+ qp_cacheout_inbuf->qp_cache.wqe_cache.wqe_flags = 0;
+ qp_cacheout_inbuf->qp_cache.wqe_cache.wqe_num = 0;
+ qp_cacheout_inbuf->qp_cache.wqe_cache.wqe_cache_line_start =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.wqe_cl_start);
+ qp_cacheout_inbuf->qp_cache.wqe_cache.wqe_cache_line_end =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.wqe_cl_end);
+ qp_cacheout_inbuf->qp_cache.wqe_cache.wqe_cache_line_size =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.wqe_cl_sz);
+}
+
+static int roce5_qp_send_cache_out_cmd(struct roce5_device *rdev,
+ struct roce5_qp *rqp, void *wb_va,
+ dma_addr_t wb_dma, int *cost)
+{
+ unsigned long end;
+ int times = 0;
+ int ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_qp_cache_invalid_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ roce5_qp_fill_cacheout_inbuf(rdev, rqp, wb_dma, cqm_cmd_inbuf);
+
+ end = jiffies +
+ (unsigned long)((unsigned int)rdev->destory_flow_timeout * HZ);
+ while (time_before(jiffies, end)) {
+ times++;
+ ret = roce5_send_qp_lb_cmd(rqp->qpn, rdev,
+ ROCE_CMD_MISC_CACHE_INVLD,
+ cqm_cmd_inbuf, NULL,
+ ROCE_CMD_TIME_CLASS_C);
+ if (ret <= 0) { /* return success or exception happened */
+ break;
+ }
+ cond_resched();
+ };
+
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed MISC_CACHE_INVLD command after try %d times, ret(%d), func_id(%d) qpn(%d)",
+ times, ret, rdev->glb_func_id, rqp->qpn);
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ *cost = times;
+
+ if (hinic5_get_chip_present_flag(rdev->hwdev) == 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Card not present, return ERROR, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -ENODEV;
+ }
+ return ret;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ *cost = (rdev->try_times - times) + 1;
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_qp_cache_out_cmd
+ Description : cache out qpc mtt
+ Input : struct roce5_device *rdev
+ struct roce5_qp *rqp
+ Output : None
+
+ 1.Date : 2016/9/24
+ Modification : Created function
+
+ 2.Date : 2017/04/26
+ Modification : Modify function
+
+**************************************************************************** */
+/* roce5_dealloc_latch_resource() collect use construct temporary change amount rqp to reuse this function. such as newly added for rqp intomember of use, need
排 query whether need adaptation */
+int roce5_qp_cache_out_cmd(struct roce5_device *rdev, struct roce5_qp *rqp)
+{
+ int ret = 0;
+ int cost = 0;
+ void *wb_va = NULL;
+ dma_addr_t wb_dma = 0;
+
+ wb_va = dma_alloc_coherent(rdev->dev, (size_t)8UL, &wb_dma, GFP_KERNEL);
+ if (wb_va == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc wb_va, func_id(%d)",
+ rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ ret = roce5_qp_send_cache_out_cmd(rdev, rqp, wb_va, wb_dma, &cost);
+ if (ret != 0) {
+ goto err;
+ }
+
+ if (rqp->rsp_depth > 0) {
+ ret = roce5_qp_check_rdmarc(rdev, rqp, &cost);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to check qp rdmarc, func_id(%d)",
+ rdev->glb_func_id);
+ goto err;
+ }
+ }
+
+ ret = roce5_qp_check_state(rdev, rqp, (u32 *)wb_va, &cost);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to check qp state, func_id(%d)",
+ rdev->glb_func_id);
+ goto err;
+ }
+
+err:
+ dma_free_coherent(rdev->dev, sizeof(u32), wb_va, wb_dma);
+
+ /* At the end of the check, if the failure is caused by a chip link down, release resources on the host side. */
+ if (hinic5_get_chip_present_flag(rdev->hwdev) == 0) {
+ ROCE_DEV_ERR(rdev, "Card not present, return OK, func_id(%d)",
+ rdev->glb_func_id);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static u8 roce5_get_qp_cmdq_cmd(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_qp_attr *attr, int attr_mask)
+{
+ static u16 op[ROCE_QP_STATE_NUM][ROCE_QP_STATE_NUM];
+ enum ib_qp_state cur_state, new_state;
+
+ cur_state =
+ (enum ib_qp_state)(((((u32)attr_mask) & IB_QP_CUR_STATE) != 0) ?
+ attr->cur_qp_state :
+ rqp->qp_state);
+ new_state = ((((u32)attr_mask) & IB_QP_STATE) != 0) ? attr->qp_state :
+ cur_state;
+ if ((cur_state > IB_QPS_ERR) || (new_state > IB_QPS_ERR)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "QP state modify invalid, cur_state(%d), new_state(%d), func_id(%d)",
+ cur_state, new_state, rdev->glb_func_id);
+ return 0;
+ }
+ op[IB_QPS_RESET][IB_QPS_ERR] = ROCE_CMD_2ERR_QP;
+ op[IB_QPS_RESET][IB_QPS_INIT] = ROCE_CMD_RST2INIT_QP;
+
+ op[IB_QPS_INIT][IB_QPS_ERR] = ROCE_CMD_2ERR_QP;
+ op[IB_QPS_INIT][IB_QPS_INIT] = ROCE_CMD_INIT2INIT_QP;
+ op[IB_QPS_INIT][IB_QPS_RTR] = ROCE_CMD_INIT2RTR_QP;
+
+ op[IB_QPS_RTR][IB_QPS_ERR] = ROCE_CMD_2ERR_QP;
+ op[IB_QPS_RTR][IB_QPS_RTS] = ROCE_CMD_RTR2RTS_QP;
+
+ op[IB_QPS_RTS][IB_QPS_ERR] = ROCE_CMD_2ERR_QP;
+ op[IB_QPS_RTS][IB_QPS_RTS] = ROCE_CMD_RTS2RTS_QP;
+ op[IB_QPS_RTS][IB_QPS_SQD] = ROCE_CMD_RTS2SQD_QP;
+
+ op[IB_QPS_SQD][IB_QPS_ERR] = ROCE_CMD_2ERR_QP;
+ op[IB_QPS_SQD][IB_QPS_RTS] = ROCE_CMD_SQD2RTS_QP;
+ op[IB_QPS_SQD][IB_QPS_SQD] = ROCE_CMD_SQD2SQD_QP;
+
+ op[IB_QPS_SQE][IB_QPS_ERR] = ROCE_CMD_2ERR_QP;
+ op[IB_QPS_SQE][IB_QPS_RTS] = ROCE_CMD_SQERR2RTS_QP;
+
+ op[IB_QPS_ERR][IB_QPS_ERR] = ROCE_CMD_2ERR_QP;
+
+ return (u8)op[cur_state][new_state];
+}
+
+static int roce5_qp_rts2sqd_cmd(struct roce5_device *rdev, struct roce5_qp *rqp,
+ const struct ib_qp_attr *attr, int attr_mask)
+{
+ int ret = 0;
+ int sqd_event = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_qp_modify_rts2sqd_s *qp_rts2sqd_inbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_qp_modify_rts2sqd_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ sqd_event = ((((u32)attr_mask) & IB_QP_EN_SQD_ASYNC_NOTIFY) != 0) &&
+ (attr->en_sqd_async_notify != 0);
+ qp_rts2sqd_inbuf =
+ (roce_uni_cmd_qp_modify_rts2sqd_s *)cqm_cmd_inbuf->buf;
+ qp_rts2sqd_inbuf->com.index = cpu_to_be32(rqp->qpn);
+ qp_rts2sqd_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ qp_rts2sqd_inbuf->sqd_event_en = cpu_to_be32((u32)(sqd_event != 0));
+
+ ret = roce5_send_qp_lb_cmd(rqp->qpn, rdev, ROCE_CMD_RTS2SQD_QP,
+ cqm_cmd_inbuf, NULL, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send RTS2SQD_QP cmd, func_id(%d), ret(0x%x)",
+ rdev->glb_func_id, ret);
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return -1;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return 0;
+}
+
+static int roce5_qp_handle_err(struct roce5_device *rdev,
+ const struct roce5_qp *rqp, u8 cmd, int ret)
+{
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send MODIFY_QP command, command(%u), func_id(%d), ret(%d)",
+ cmd, rdev->glb_func_id, ret);
+
+ if ((ret == (-ETIMEDOUT)) || (ret == (-EPERM))) {
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+
+ return -1;
+}
+
+static int roce5_qp_modify_cmd(struct roce5_device *rdev, struct roce5_qp *rqp,
+ u8 cmd, roce_modify_qp_param_s *modify_para)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_modify_qpc_s *qp_modify_inbuf = NULL;
+ roce_verbs_qp_attr_s *qp_attr = &modify_para->qp_attr;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_modify_qpc_s), &cqm_cmd_outbuf,
+ ROCE_QP_MODIFY_CMD_OUT_BUF_SIZE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return (-ENOMEM);
+ }
+
+ qp_modify_inbuf = (roce_uni_cmd_modify_qpc_s *)cqm_cmd_inbuf->buf;
+
+ roce5_transmit_ci_record_addr_ext(rqp, qp_attr);
+ roce5_qpc_to_be(qp_attr, rqp, (u32 *)&qp_modify_inbuf->qp_attr);
+ qp_modify_inbuf->com.index = cpu_to_be32(rqp->qpn);
+ qp_modify_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_QP_BITMASK));
+ qp_modify_inbuf->com.opt = cpu_to_be32(modify_para->optpar);
+ ret = roce5_send_qp_lb_cmd(rqp->qpn, rdev, cmd, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ ret = roce5_qp_handle_err(rdev, rqp, cmd, ret);
+ } else {
+ roce5_be32_2_le32(
+ cqm_cmd_outbuf->buf, (u32 *)&modify_para->modify_rsp,
+ sizeof(roce_verbs_cmd_qp_modify_rsp_s) / sizeof(u32));
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+ return ret;
+}
+
+void roce5_cq_clean(struct roce5_cq *cq, u32 qpn, struct roce5_srq *srq)
+{
+ spin_lock_irq(&cq->lock);
+ roce5_cq_clean_process(cq, qpn, srq);
+ spin_unlock_irq(&cq->lock);
+}
+
+static int roce5_qp_clean_kernel_res(struct roce5_qp *rqp)
+{
+ int ret = 0;
+ struct roce5_cq *send_cq = NULL;
+ struct roce5_cq *recv_cq = NULL;
+
+ roce5_get_cqs(rqp, &send_cq, &recv_cq);
+
+ roce5_cq_clean(recv_cq, rqp->qpn,
+ rqp->ibqp.srq ? to_roce5_srq(rqp->ibqp.srq) : NULL);
+ if (send_cq != recv_cq) {
+ roce5_cq_clean(send_cq, rqp->qpn, NULL);
+ }
+
+ rqp->rq.head = 0;
+ rqp->rq.tail = 0;
+
+ rqp->sq.head = 0;
+ rqp->sq.tail = 0;
+
+ rqp->sq_next_wqe = 0;
+ rqp->sq_wqe_ssn = 0;
+
+ *(rqp->db.db_record) = 0;
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ if (rqp->has_rq && rqp->qp_buf_info->q_header_vaddr) {
+ ret = memset_s(rqp->qp_buf_info->q_header_vaddr,
+ sizeof(u64), 0, sizeof(u64));
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to memset QP(0x%06x) q_header_vaddr(ret:%d)",
+ rqp->qpn, ret);
+ return (-ENOMEM);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int roce5_qp_modify_2rst(struct roce5_device *rdev, struct roce5_qp *rqp)
+{
+ int ret = 0;
+
+ ret = roce5_qp_modify_2rst_cmd(rdev, rqp->qpn);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to modify QP(0x%06x) to RESET, func_id(%d)",
+ rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce5_qp_cache_out_cmd(rdev, rqp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "QP(0x%06x) cache invalid failed, func_id(%d)",
+ rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ rqp->qp_state = IB_QPS_RESET;
+
+ if (rqp->ibqp.uobject == NULL) {
+ ret = roce5_qp_clean_kernel_res(rqp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Clean kernel QP(0x%06x) failed, func_id(%d)",
+ rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void roce5_set_stub_field(struct roce5_device *rdev,
+ roce_verbs_qp_attr_s *qp_attr)
+{
+ qp_attr->com_info.dw6.bs.force_local = rdev->local_en;
+}
+
+static int roce5_modify_qp_cmd_process(struct roce5_device *rdev,
+ struct roce5_qp *rqp,
+ struct ib_qp_attr *attr, int attr_mask,
+ roce_modify_qp_param_s *modify_para)
+{
+ u8 cmd;
+ int ret;
+ cmd = roce5_get_qp_cmdq_cmd(rdev, rqp, attr, attr_mask);
+ if (cmd == 0) {
+ ROCE_DEV_ERR(rdev,
+ "Invalid cmd, func_id(%u), qpn(%u), cmd(%u).",
+ rdev->glb_func_id, rqp->qpn, cmd);
+ return -EINVAL;
+ }
+ if (cmd == ROCE_CMD_RTS2SQD_QP) {
+ ret = roce5_qp_rts2sqd_cmd(rdev, rqp, attr, attr_mask);
+ } else {
+ ret = roce5_qp_modify_cmd(rdev, rqp, cmd, modify_para);
+ }
+ return ret;
+}
+
+static int roce5_qp_modify(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ roce_user_handle_t hdl;
+ roce_modify_qp_param_s modify_para;
+ roce_verbs_qp_attr_s *qp_attr = &modify_para.qp_attr;
+
+ (void)memset_s(&modify_para, sizeof(roce_modify_qp_param_s), 0,
+ sizeof(roce_modify_qp_param_s));
+ if ((((u32)attr_mask) & IB_QP_MAX_DEST_RD_ATOMIC) != 0) {
+ ret = roce5_alloc_opt_rdmarc(rqp, attr, attr_mask);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc rdmarc, func(%d).",
+ rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ ret = roce5_set_opt_field(rqp, attr, attr_mask, &modify_para);
+ if (ret != 0) {
+ goto err_out;
+ }
+
+ roce5_set_abs_field(rqp, attr, attr_mask, qp_attr);
+ roce5_set_stub_field(rdev, qp_attr);
+
+ (void)memset_s(&hdl, sizeof(roce_user_handle_t), 0,
+ sizeof(roce_user_handle_t));
+ ROCE_CONSTUCT_ULD_HDL_RQP(&hdl, rdev, rqp, qp_attr, NULL, NULL, NULL);
+ ret = roce5_uld_qp_modify((roce_uld_handle)&hdl, attr, attr_mask,
+ udata);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to modify uld qp, func(%d), qpn(%d), ret(%d).",
+ rdev->glb_func_id, rqp->qpn, ret);
+ goto err_out;
+ }
+
+ ret = roce5_modify_qp_cmd_process(rdev, rqp, attr, attr_mask,
+ &modify_para);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to modify qp, func(%d), qpn(%d), ret(%d).",
+ rdev->glb_func_id, rqp->qpn, ret);
+ goto err_out;
+ }
+
+ ret = roce5_record_opt_field(rqp, attr, attr_mask, udata,
+ &modify_para.modify_rsp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to record_opt_field, func(%d), qpn(%d).",
+ rdev->glb_func_id, rqp->qpn);
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ if ((((u32)attr_mask) & IB_QP_MAX_DEST_RD_ATOMIC) != 0) {
+ roce5_free_opt_rdmarc(rqp);
+ }
+
+ return ret;
+}
+
+static int roce5_qp_get_path(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct rdma_ah_attr *ah_attr)
+{
+ int ret = 0;
+ u16 vlan_id;
+
+ if ((ah_attr->ah_flags & IB_AH_GRH) == 0) {
+ ROCE_DEV_ERR(rdev, "Not supported, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ ret = roce5_resolve_grh(rdev, ah_attr, &vlan_id, NULL);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to find dmac by grh, func_id(%u)",
+ (u32)rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+roce5_qp_modify_check_rd_and_mtu(const struct roce5_qp *rqp,
+ const struct ib_qp_attr *attr, int attr_mask,
+ const struct rdma_service_cap *rdma_cap)
+{
+ struct roce5_device *rdev = to_roce5_dev(rqp->ibqp.device);
+ enum ib_qp_state cur_state =
+ (enum ib_qp_state)(((((u32)attr_mask) & IB_QP_CUR_STATE) != 0) ?
+ attr->cur_qp_state :
+ rqp->qp_state);
+ enum ib_qp_state new_state = (enum ib_qp_state)(
+ ((((u32)attr_mask) & IB_QP_STATE) != 0) ? attr->qp_state :
+ cur_state);
+ enum roce5_mtu rmtu = (enum roce5_mtu)attr->path_mtu;
+
+ if (((((u32)attr_mask) & IB_QP_MAX_QP_RD_ATOMIC) != 0) &&
+ (attr->max_rd_atomic >
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_qp_init_rdma)) {
+ ROCE_ERR(
+ "Qpn(0x%x), max_rd_atomic (%d) too large. Transition %d to %d. qp_type(%d)",
+ rqp->ibqp.qp_num, attr->max_rd_atomic, cur_state,
+ new_state, rqp->ibqp.qp_type);
+ return -EINVAL;
+ }
+
+ if (((((u32)attr_mask) & IB_QP_MAX_DEST_RD_ATOMIC) != 0) &&
+ (attr->max_dest_rd_atomic >
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_qp_dest_rdma)) {
+ ROCE_ERR(
+ "Qpn(0x%x), max_dest_rd_atomic (%d) too large. Transition %d to %d. qp_type(%d)",
+ rqp->ibqp.qp_num, attr->max_dest_rd_atomic, cur_state,
+ new_state, rqp->ibqp.qp_type);
+ return -EINVAL;
+ }
+
+ if (((((u32)attr_mask) & IB_QP_PATH_MTU) != 0) &&
+ ((rmtu < ROCE_MTU_256) ||
+ (rmtu > ((ROCE5_SUPPORT_8K_MTU(rdev) != 0) ? ROCE_MTU_8192 :
+ ROCE_MTU_4096)))) {
+ ROCE_ERR("Input path MTU(%u) is invalid", rmtu);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_qp_modify_check(struct roce5_qp *rqp, struct ib_qp_attr *attr,
+ int attr_mask,
+ struct rdma_service_cap *rdma_cap)
+{
+ int ret;
+ enum ib_qp_state cur_state, new_state;
+ cur_state =
+ (enum ib_qp_state)(((((u32)attr_mask) & IB_QP_CUR_STATE) != 0) ?
+ attr->cur_qp_state :
+ rqp->qp_state);
+ new_state = (enum ib_qp_state)(((((u32)attr_mask) & IB_QP_STATE) != 0) ?
+ attr->qp_state :
+ cur_state);
+
+#ifndef ROCE_VBS_EN
+ if (!roce5_check_qp_modify_ok(
+ cur_state, new_state, (enum ib_qp_type)(rqp->ibqp.qp_type),
+ (enum ib_qp_attr_mask)attr_mask, IB_LINK_LAYER_ETHERNET)) {
+ ROCE_ERR(
+ "Qpn(0x%x), invalid attribute mask specified for transition %d to %d, qp_type(%d), "
+ "attr_mask(0x%x)",
+ rqp->ibqp.qp_num, cur_state, new_state,
+ rqp->ibqp.qp_type, attr_mask);
+ return (-EINVAL);
+ }
+#endif
+
+ if (((((u32)attr_mask) & IB_QP_PORT) != 0) &&
+ (attr->port_num != ROCE_DEFAULT_PORT_NUM)) {
+ ROCE_ERR(
+ "Qpn(0x%x), invalid port number(%d) specified for transition %d to %d. qp_type(%d)",
+ rqp->ibqp.qp_num, attr->port_num, cur_state, new_state,
+ rqp->ibqp.qp_type);
+ return (-EINVAL);
+ }
+
+ if ((((u32)attr_mask) & IB_QP_PKEY_INDEX) != 0) {
+ if (attr->pkey_index > 0) {
+ ROCE_ERR(
+ "Qpn(0x%x), invalid pkey index (%d) specified for transition %d to %d. "
+ "qp_type(%d)",
+ rqp->ibqp.qp_num, attr->pkey_index, cur_state,
+ new_state, rqp->ibqp.qp_type);
+ return (-EINVAL);
+ }
+ }
+
+ ret = roce5_qp_modify_check_rd_and_mtu(rqp, attr, attr_mask, rdma_cap);
+
+ return ret;
+}
+
+#define ROCE5_QP_HANDLE 0
+#define ROCE5_QP_CONTINUE 1
+static int roce5_modify_qp_pre(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_qp *rqp = NULL;
+ struct roce5_device *rdev = NULL;
+ enum ib_qp_state cur_state, new_state;
+
+ rqp = to_roce5_qp(ibqp);
+ rdev = to_roce5_dev(ibqp->device);
+ cur_state =
+ (enum ib_qp_state)(((((u32)attr_mask) & IB_QP_CUR_STATE) != 0) ?
+ attr->cur_qp_state :
+ rqp->qp_state);
+ new_state = ((((u32)attr_mask) & IB_QP_STATE) != 0) ? attr->qp_state :
+ cur_state;
+
+ ret = roce5_qp_modify_check(rqp, attr, attr_mask, &rdev->rdma_cap);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed qp modify check, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ if (new_state == IB_QPS_RESET) {
+ if (cur_state != new_state) {
+ ret = roce5_qp_modify_2rst(rdev, rqp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to modify 2rst, func_id(%d)",
+ rdev->glb_func_id);
+ }
+ }
+ return ROCE5_QP_HANDLE;
+ }
+
+ ret = roce5_modify_qp_pre_ext(rdev, rqp, attr, attr_mask, udata);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to modify qp pre ext, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ return ROCE5_QP_CONTINUE;
+}
+
+int roce5_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_qp *rqp = NULL;
+ struct roce5_device *rdev = NULL;
+
+ rqp = to_roce5_qp(ibqp);
+ rdev = to_roce5_dev(ibqp->device);
+
+ mutex_lock(&rqp->mutex);
+
+ ret = roce5_modify_qp_pre(ibqp, attr, attr_mask, udata);
+ if ((ret == ROCE5_QP_HANDLE) || (ret < 0)) {
+ goto out;
+ }
+
+ if ((((u32)attr_mask) & IB_QP_AV) != 0) {
+ ret = roce5_qp_get_path(rdev, rqp, &attr->ah_attr);
+ if (ret != 0) {
+ goto out;
+ }
+ }
+
+ ret = roce5_qp_modify(rdev, rqp, attr, attr_mask, udata);
+ if (ret != 0) {
+ goto out;
+ }
+
+out:
+ mutex_unlock(&rqp->mutex);
+ return ret;
+}
+
+static void roce5_verbs_shadow_set(struct roce5_device *rdev, u32 qpn,
+ cqm_cmd_buf_s *buf_in)
+{
+ roce_verbs_cmd_header_s *cmd_hdr =
+ (roce_verbs_cmd_header_s *)buf_in->buf;
+ struct roce5_qp *rqp = NULL;
+
+ if ((qpn == ROCE_QP_SMI_QP_NUM) || (qpn == ROCE_QP_GSI_QP_NUM)) {
+ return;
+ }
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ return;
+ }
+
+ if (rqp->shadow == 0 || cmd_hdr == NULL ||
+ cmd_hdr->dw0.bs.cmd_bitmask == VERBS_CMD_TYPE_VROCE_BITMASK) {
+ goto shadow_out;
+ }
+
+ cmd_hdr->dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_SHADOW_BITMASK);
+ cmd_hdr->dw3.bs.shadow_vfid = cpu_to_be16(rqp->shadow_vfid);
+
+shadow_out:
+ roce5_rqp_put(rqp);
+}
+
+int roce5_send_qp_lb_cmd(u32 qpn, struct roce5_device *rdev, u8 cmd,
+ cqm_cmd_buf_s *buf_in, cqm_cmd_buf_s *buf_out,
+ u32 timeout)
+{
+ int ret = 0;
+
+ roce5_verbs_shadow_set(rdev, qpn, buf_in);
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE, cmd, buf_in,
+ buf_out, NULL, timeout, HINIC5_CHANNEL_ROCE);
+
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_post_recv.c b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_post_recv.c
new file mode 100644
index 000000000..fa48a2671
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_post_recv.c
@@ -0,0 +1,238 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "roce_compat.h"
+
+#include "roce.h"
+#include "roce_mix.h"
+#include "roce_mr.h"
+#include "roce_xrc.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_qp.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+
+/* ****************************************************************************
+ Prototype : roce5_get_recv_wqe
+ Description : roce5_get_recv_wqe
+ Input : struct roce5_qp *rqp
+ int n
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+**************************************************************************** */
+static void *roce5_get_recv_wqe(struct roce5_qp *rqp, u32 n)
+{
+ return roce5_get_wqe(rqp, rqp->rq.offset +
+ (n << (unsigned)rqp->rq.wqe_shift));
+}
+
+static int roce5_post_recv_check_qp(const struct roce5_qp *qp,
+ const struct roce5_device *rdev,
+ const struct ib_recv_wr **bad_wr,
+ const struct ib_recv_wr *wr)
+{
+ if (ROCE_UNLIKELY((qp->qp_type == IB_QPT_XRC_INI) ||
+ (qp->qp_type == IB_QPT_XRC_TGT))) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Can't post WQE when TGT XRC QP, func_id(%d), qp_type(%d)",
+ rdev->glb_func_id, qp->qp_type);
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+
+ if (ROCE_UNLIKELY(qp->qp_state == IB_QPS_RESET)) {
+ ROCE_DEV_ERR(rdev,
+ "Can't post WQE when QP is RST state, func_id(%d)",
+ rdev->glb_func_id);
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_post_recv_check_wr(struct roce5_qp *qp,
+ const struct ib_recv_wr **bad_wr,
+ const struct ib_recv_wr *wr, u32 wr_num)
+{
+ if (roce5_wq_overflow(&qp->rq, wr_num, qp->ibqp.recv_cq) != 0) {
+ ROCE_ERR_ONCE("SQ is full head:%x, tali:%x, wr_num:%d",
+ (&qp->rq)->head, (&qp->rq)->tail, wr_num);
+ *bad_wr = wr;
+ return -ENOMEM;
+ }
+
+ if (ROCE_UNLIKELY(((u32)wr->num_sge) > qp->rq.max_sge)) {
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_post_recv_check_length(struct roce5_device *rdev,
+ const struct ib_recv_wr **bad_wr,
+ const struct ib_recv_wr *wr, int i)
+{
+ u32 data_len = 0;
+
+ /* single SGEָ signs data len should less than (2G-1)B */
+ if (ROCE_UNLIKELY(wr->sg_list[i].length >
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_msg_sz -
+ 1)) {
+ *bad_wr = wr;
+ ROCE_DEV_ERR(
+ rdev,
+ "Sge data len is over range, sg_list(%d), length(0x%x), max_msg_sz(0x%x), func_id(%d)",
+ i, wr->sg_list[i].length,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_msg_sz,
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ data_len += wr->sg_list[i].length;
+ /* all SGEָ signs data len should less than 2GB */
+ if (ROCE_UNLIKELY(
+ data_len >
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_msg_sz)) {
+ *bad_wr = wr;
+ ROCE_DEV_ERR(
+ rdev,
+ "Data_len is over range, data_len(%d), max_msg_sz(%d), func_id(%d)",
+ data_len,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_msg_sz,
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+static int roce5_post_recv_set_data_seg(const struct ib_recv_wr *wr,
+ struct roce5_device *rdev,
+ const struct ib_recv_wr **bad_wr,
+ struct roce5_qp *qp, u32 index)
+{
+ int i = 0;
+ int ret = 0;
+ struct roce_wqe_data_seg *dseg = NULL;
+
+ dseg = (struct roce_wqe_data_seg *)roce5_get_recv_wqe(qp, index);
+ for (i = 0; i < wr->num_sge; ++i) {
+ ret = roce5_post_recv_check_length(rdev, bad_wr, wr, i);
+ if (ret != 0) {
+ return ret;
+ }
+
+ roce5_set_data_seg(dseg, wr->sg_list + i);
+ dseg++;
+ }
+
+ if (wr->num_sge != 0) {
+ dseg--;
+ dseg->key =
+ cpu_to_be32((u32)(wr->sg_list[wr->num_sge - 1].lkey |
+ ROCE_WQE_NEXT_SGE_INVALID));
+ } else {
+ dseg->key = ROCE_WQE_NEXT_SGE_INVALID;
+ dseg->key = cpu_to_be32(dseg->key);
+ dseg->dw2.bs.len = 0;
+ }
+
+ return 0;
+}
+/* ****************************************************************************
+ Prototype : roce5_post_recv
+ Description : roce5_post_recv
+ Input : struct ib_qp *ibqp
+ struct ib_recv_wr *wr
+ struct ib_recv_wr **bad_wr
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr)
+{
+ struct roce5_qp *qp = NULL;
+ struct roce5_device *rdev = NULL;
+ unsigned long flags = 0; /* type required by kernel API */
+ int ret = 0;
+ u32 wr_num = 0;
+ u32 index = 0;
+ const struct ib_recv_wr *wr_tmp = wr;
+
+ if (ROCE_UNLIKELY(ibqp == NULL || bad_wr == NULL)) {
+ ROCE_ERR("ibqp(%d) or bad_wr(%d) is NULL.", !!ibqp, !!bad_wr);
+ return -EINVAL;
+ }
+
+ qp = to_roce5_qp(ibqp);
+ rdev = to_roce5_dev(ibqp->device);
+
+ ret = roce5_post_recv_check_qp(qp, rdev, bad_wr, wr_tmp);
+ if (ret != 0) {
+ return ret;
+ }
+
+ spin_lock_irqsave(&qp->rq.lock, flags);
+
+ index = (unsigned int)qp->rq.head &
+ ((unsigned int)qp->rq.wqebb_cnt - 1);
+
+ for (wr_num = 0; wr_tmp != NULL; ++wr_num, wr_tmp = wr_tmp->next) {
+ ret = roce5_post_recv_check_wr(qp, bad_wr, wr_tmp, wr_num);
+ if (ret != 0) {
+ goto out;
+ }
+
+ ret = roce5_post_recv_set_data_seg(wr_tmp, rdev, bad_wr, qp,
+ index);
+ if (ret != 0) {
+ goto out;
+ }
+
+ qp->rq.wrid[index] = wr_tmp->wr_id;
+
+ index = (index + 1) & (qp->rq.wqebb_cnt - 1);
+ }
+
+out:
+ if (ROCE_LIKELY(wr_num != 0)) {
+ qp->rq.head += (u32)wr_num;
+
+ wmb();
+
+ /* SQ need head 4B,RQ need tail 4B */
+ *(qp->db.db_record + 1) = cpu_to_be32(qp->rq.head & 0xffff);
+ }
+
+ spin_unlock_irqrestore(&qp->rq.lock, flags);
+
+ return ret;
+}
+
+int roce5_post_recv_ofa(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr)
+{
+ return roce5_post_recv(ibqp, (const struct ib_recv_wr *)wr,
+ (const struct ib_recv_wr **)bad_wr);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_post_send.c b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_post_send.c
new file mode 100644
index 000000000..ad1a8043a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_post_send.c
@@ -0,0 +1,1205 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <rdma/ib_verbs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include "roce_compat.h"
+
+#include "roce.h"
+#include "roce_mix.h"
+#include "roce_mr.h"
+#include "roce_user.h"
+#include "roce_xrc.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_qp.h"
+#include "roce_post.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#include "roce_kernel_compat_gen.h"
+
+#include "securec.h"
+
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+
+#define GOTO_LOCAL 1
+
+#define GOTO_OUT 2
+
+#define ROCE_NEED_JUMP 1
+
+#define BYTE_MASK 255
+
+#define ROCE_CTRL_SEG_SL 2
+/* ****************************************************************************
+ Prototype : roce5_get_send_wqe
+ Description : roce5_get_send_wqe
+ Input : struct roce5_qp *rqp
+ u32 n
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+**************************************************************************** */
+static void *roce5_get_send_wqe(struct roce5_qp *rqp, u32 n)
+{
+ u32 wqebb_index = (n & (((u32)rqp->sq.wqebb_cnt) - 1));
+ u32 wqebb_pos = wqebb_index << rqp->sq.wqe_shift;
+ return roce5_get_wqe(rqp, rqp->sq.offset + wqebb_pos);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_wq_overflow
+ Description : roce5_wq_overflow
+ Input : struct roce5_wq *wq
+ int wr_num
+ struct ib_cq *ibcq
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_wq_overflow(struct roce5_wq *wq, u32 wr_num, struct ib_cq *ibcq)
+{
+ unsigned int cur = 0;
+ struct roce5_cq *cq = NULL;
+
+ cur = wq->head - wq->tail;
+ if (ROCE_LIKELY((cur + wr_num) < (unsigned int)wq->max_post)) {
+ return 0;
+ }
+
+ cq = to_roce5_cq(ibcq);
+ spin_lock(&cq->lock);
+ cur = wq->head - wq->tail;
+ spin_unlock(&cq->lock);
+
+ return ((cur + (unsigned int)wr_num) >= (unsigned int)wq->max_post);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_ib_opcode
+ Description :
+ Input :
+ Output : None
+ Return Value :
+ Calls :
+ Called By :
+
+ History :
+ 1.Date : 2015/7/30
+ Author :
+ Modification : Created function
+
+**************************************************************************** */
+static const u32 roce5_ib_opcode[] = {
+ [IB_WR_RDMA_WRITE] = ROCE_WQE_OPCODE_RDMA_WRITE,
+ [IB_WR_RDMA_WRITE_WITH_IMM] = ROCE_WQE_OPCODE_RDMA_WRITE_IMM,
+ [IB_WR_SEND] = ROCE_WQE_OPCODE_SEND,
+ [IB_WR_SEND_WITH_IMM] = ROCE_WQE_OPCODE_SEND_IMM,
+ [IB_WR_RDMA_READ] = ROCE_WQE_OPCODE_RDMA_READ,
+ [IB_WR_ATOMIC_CMP_AND_SWP] = ROCE_WQE_OPCODE_ATOMIC_CMP_SWP,
+ [IB_WR_ATOMIC_FETCH_AND_ADD] = ROCE_WQE_OPCODE_ATOMIC_FETCH_ADD,
+ [IB_WR_SEND_WITH_INV] = ROCE_WQE_OPCODE_SEND_INVAL,
+ [IB_WR_LOCAL_INV] = ROCE_WQE_OPCODE_LOCAL_INVAL,
+ [IB_WR_REG_MR] = ROCE_WQE_OPCODE_FRMR,
+ [IB_WR_MASKED_ATOMIC_CMP_AND_SWP] =
+ ROCE_WQE_OPCODE_MASKED_ATOMIC_CMP_SWP,
+ [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD] =
+ ROCE_WQE_OPCODE_MASKED_ATOMIC_FETCH_ADD,
+ [IB_WR_REG_MR_INTEGRITY] = ROCE_WQE_OPCODE_REG_SIG_MR,
+#if defined(IB_WR_OPCODE_HAVE_BIND_MW)
+ [IB_WR_BIND_MW] = ROCE_WQE_OPCODE_BIND_MW,
+#endif
+};
+
+static const roce_opcode_attr_s g_roce5_opcode_attr[ROCE_KERNEL_OPCODE_NUM] = {
+ { .remote_opcode = 0x1 }, //ROCE_WQE_OPCODE_SEND = 0x0,
+ { .remote_opcode = 0x1 }, //ROCE_WQE_OPCODE_SEND_WITH_INV,
+ { .remote_opcode = 0x1 }, //ROCE_WQE_OPCODE_SEND_WITH_IMM,
+ { 0 }, //ROCE_WQE_OPCODE_SEND_FT_TEST
+ { .remote_opcode = 0x1 }, //ROCE_WQE_OPCODE_RDMA_WRITE = 0x4,
+ { .remote_opcode = 0x1 }, //ROCE_WQE_OPCODE_RDMA_WRITE_WITH_IMM,
+ { 0 },
+ { 0 },
+ { .remote_opcode = 0x1 }, //ROCE_WQE_OPCODE_RDMA_READ = 0x8,
+ { 0 }, //ROCE_WQE_OPCODE_ATOMIC_WRITE,
+ { 0 }, //ROCE_WQE_OPCODE_CFLUSH,
+ { .remote_opcode =
+ 0x1 }, //ROCE_WQE_OPCODE_ATOMIC_EXT_CMP_AND_SWP, /* support max 64B */
+ { .remote_opcode = 0x1 }, //ROCE_WQE_OPCODE_ATOMIC_CMP_AND_SWP = 0xc,
+ { .remote_opcode = 0x1 }, //ROCE_WQE_OPCODE_ATOMIC_FETCH_AND_ADD,
+ { .remote_opcode = 0x1 }, //ROCE_WQE_OPCODE_MASKED_ATOMIC_CMP_AND_SWP,
+ { .remote_opcode =
+ 0x1 }, //ROCE_WQE_OPCODE_MASKED_ATOMIC_FETCH_AND_ADD,
+ { 0 }, //ROCE_WQE_OPCODE_FAST_REG_PMR, /* 8'h10-Fast Register PMR is not used by userspace */
+ { 0 }, //ROCE_WQE_OPCODE_LOCAL_INV = 0x11,
+ { 0 }, //ROCE_WQE_OPCODE_BIND_MW,
+ { 0 } //ROCE_WQE_OPCODE_REG_SIG_MR = 0x13, /* 8'h13-Local opreation(Extended for further local opreation) */
+};
+
+static void roce5_set_send_seg(struct roce_wqe_send_tsk_seg *snd_tsk_seg,
+ const struct ib_send_wr *wr)
+{
+ if (wr->opcode == IB_WR_SEND_WITH_IMM) {
+ snd_tsk_seg->immdata_invkey = wr->ex.imm_data;
+ }
+
+ if (wr->opcode == IB_WR_SEND_WITH_INV) {
+ snd_tsk_seg->immdata_invkey =
+ cpu_to_be32(wr->ex.invalidate_rkey);
+ }
+}
+
+static void roce5_set_atomic_seg(struct roce_wqe_atomic_tsk_seg *atomic_tsk_seg,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_atomic_wr *atomic = atomic_wr(wr);
+
+ atomic_tsk_seg->key = cpu_to_be32(atomic->rkey);
+ atomic_tsk_seg->dw2.va = cpu_to_be64(atomic->remote_addr);
+
+ if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+ atomic_tsk_seg->dw4.swap_add_data = cpu_to_be64(atomic->swap);
+ atomic_tsk_seg->dw6.cmp_data = cpu_to_be64(atomic->compare_add);
+ } else if (wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
+ atomic_tsk_seg->dw4.swap_add_data =
+ cpu_to_be64(atomic->compare_add);
+ atomic_tsk_seg->dw6.cmp_data = 0;
+ } else {
+ /* IB_WR_MASKED_ATOMIC_FETCH_AND_ADD */
+ atomic_tsk_seg->dw4.swap_add_data =
+ cpu_to_be64(atomic->compare_add);
+ atomic_tsk_seg->dw6.cmp_data =
+ cpu_to_be64(atomic->compare_add_mask);
+ }
+}
+
+static __always_inline void
+roce5_set_rdma_seg(struct roce_wqe_rdma_tsk_seg *rdma_tsk_seg,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_rdma_wr *rdma = rdma_wr(wr);
+
+ rdma_tsk_seg->va = cpu_to_be64(rdma->remote_addr);
+ rdma_tsk_seg->rkey = cpu_to_be32(rdma->rkey);
+
+ if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
+ rdma_tsk_seg->imm_data = cpu_to_be32(wr->ex.imm_data);
+ }
+}
+
+static void
+roce5_set_local_inv_seg(struct roce_wqe_local_inv_tsk_seg *inv_tsk_seg,
+ const struct ib_send_wr *wr)
+{
+ inv_tsk_seg->inv_key = cpu_to_be32(wr->ex.invalidate_rkey);
+}
+
+static void
+roce5_set_ud_seg_cycle1(struct roce_wqe_ud_tsk_seg_cycle1 *ud_tsk_seg_cycle1,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_ud_wr *ud = ud_wr(wr);
+ struct roce5_ah *rah = to_roce5_ah(ud->ah);
+ int ret;
+
+ if (wr->opcode == IB_WR_SEND_WITH_IMM) {
+ ud_tsk_seg_cycle1->immdata_invkey = wr->ex.imm_data;
+ }
+
+ ud_tsk_seg_cycle1->dw2.value = rah->priv_ah.dw0.value;
+ ud_tsk_seg_cycle1->dw3.value = rah->priv_ah.dw1.value;
+ ud_tsk_seg_cycle1->dw4.value = rah->priv_ah.dw2.value;
+ ret = memcpy_s((void *)ud_tsk_seg_cycle1->dgid, ROCE_GID_LEN,
+ (void *)rah->priv_ah.dgid, ROCE_GID_LEN);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dgid.(ret:%d)", ret);
+ return;
+ }
+ ud_tsk_seg_cycle1->dw9.value = cpu_to_be32(ud->remote_qpn);
+ ud_tsk_seg_cycle1->qkey = cpu_to_be32(ud->remote_qkey);
+}
+
+static void
+roce5_set_ud_seg_cycle2(struct roce_wqe_ud_tsk_seg_cycle2 *ud_tsk_seg_cycle2,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_ud_wr *ud = ud_wr(wr);
+ struct roce5_ah *rah = to_roce5_ah(ud->ah);
+
+ ud_tsk_seg_cycle2->dw0.value = rah->priv_ah.dw7.value;
+ ud_tsk_seg_cycle2->dmac_l32 = rah->priv_ah.dmac_l32;
+}
+
+static void roce5_set_ud_seg(struct roce_wqe_ud_tsk_seg *ud_tsk_seg,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_ud_wr *ud = ud_wr(wr);
+ struct roce5_ah *rah = to_roce5_ah(ud->ah);
+ int ret;
+
+ if (wr->opcode == IB_WR_SEND_WITH_IMM) {
+ ud_tsk_seg->immdata_invkey = wr->ex.imm_data;
+ }
+
+ ud_tsk_seg->dw3.value = rah->priv_ah.dw0.value;
+ ud_tsk_seg->dw4.value = rah->priv_ah.dw1.value;
+ ud_tsk_seg->dw5.value = rah->priv_ah.dw2.value;
+ ret = memcpy_s((void *)ud_tsk_seg->dgid, sizeof(ud_tsk_seg->dgid),
+ (void *)rah->priv_ah.dgid, sizeof(ud_tsk_seg->dgid));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dgid.(ret:%d)", ret);
+ return;
+ }
+ ud_tsk_seg->dw10.value = cpu_to_be32(ud->remote_qpn);
+ ud_tsk_seg->qkey = cpu_to_be32(ud->remote_qkey);
+ ud_tsk_seg->dw12.value = rah->priv_ah.dw7.value;
+ ud_tsk_seg->dmac_l32 = rah->priv_ah.dmac_l32;
+}
+
+void roce5_set_data_seg(struct roce_wqe_data_seg *dseg, struct ib_sge *sge)
+{
+ dseg->addr = cpu_to_be64(sge->addr);
+
+ dseg->dw2.bs.len = sge->length & 0x7fffffff;
+ dseg->dw2.bs.rsvd = 0;
+
+ dseg->dw2.value = cpu_to_be32(dseg->dw2.value);
+
+ dseg->key = cpu_to_be32(sge->lkey);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_set_gsi_seg
+ Input : struct roce5_qp *rqp
+ struct ib_send_wr *wr
+ void *wqe
+ Output : None
+
+ 1.Date : 2015/8/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_set_gsi_seg(struct roce5_qp *rqp, const struct ib_send_wr *wr,
+ void *wqe)
+{
+ struct roce_wqe_ud_tsk_seg *ud_tsk_seg =
+ (struct roce_wqe_ud_tsk_seg *)wqe;
+ struct ib_ud_wr *ud_wr = (struct ib_ud_wr *)(void *)wr;
+ struct roce5_ah *rah = to_roce5_ah(ud_wr->ah);
+ int ret;
+
+ if (rqp->sqp_attr == NULL) {
+ ROCE_ERR("Error! sqp attribute is NULL, qpn(%u).", rqp->qpn);
+ return -EINVAL;
+ }
+
+ if (wr->opcode == IB_WR_SEND_WITH_IMM) {
+ ud_tsk_seg->immdata_invkey = wr->ex.imm_data;
+ ud_tsk_seg->dw2.bs.last_ext_len = ROCE_IMM_EXT_LEN;
+ ud_tsk_seg->dw2.value = cpu_to_be32(ud_tsk_seg->dw2.value);
+ }
+
+ ud_tsk_seg->common.bs.c = 1;
+ ud_tsk_seg->dw3.value = rah->priv_ah.dw0.value;
+ ud_tsk_seg->dw4.value = rah->priv_ah.dw1.value;
+ ud_tsk_seg->dw5.value = rah->priv_ah.dw2.value;
+ ret = memcpy_s((void *)ud_tsk_seg->dgid, sizeof(ud_tsk_seg->dgid),
+ (void *)rah->priv_ah.dgid, sizeof(ud_tsk_seg->dgid));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dgid.(ret:%d)", ret);
+ return ret;
+ }
+ ud_tsk_seg->dw10.value = cpu_to_be32(ud_wr->remote_qpn);
+ ud_tsk_seg->qkey = cpu_to_be32(
+ ((ud_wr->remote_qkey & 0x80000000) != 0) ? rqp->sqp_attr->qkey :
+ ud_wr->remote_qkey);
+ ud_tsk_seg->dw12.value = rah->priv_ah.dw7.value;
+ ud_tsk_seg->dmac_l32 = rah->priv_ah.dmac_l32;
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : write_invalid_wqe
+ Description : set the next wqe invalidate
+ Input : struct roce5_qp *qp
+ u32 index
+ Output : None
+
+ 1.Date : 2015/9/8
+ Author : qianyuanpan
+ Modification : Created function
+
+**************************************************************************** */
+static void write_invalid_wqe(struct roce5_qp *qp, u32 index)
+{
+ u32 invalid_wqe_dw0 = 0;
+ struct roce5_wqe_ctrl_seg *ctrl_seg = NULL;
+
+ ctrl_seg = (struct roce5_wqe_ctrl_seg *)roce5_get_send_wqe(qp, index);
+ invalid_wqe_dw0 = ((index & (u32)qp->sq.wqebb_cnt) == 0) ? 0xff000000 :
+ 0x7f000000;
+ ctrl_seg->dw0.value = cpu_to_be32(invalid_wqe_dw0);
+}
+
+#define ROCE5_PCIE_ATOMIC_EN 0x1
+static inline bool roce5_is_pcie_atomic(struct roce5_qp *rqp)
+{
+ struct roce5_device *rdev = to_roce5_dev(rqp->ibqp.device);
+ return (rdev->cfg_info.pcie_atomic_en == ROCE5_PCIE_ATOMIC_EN);
+}
+
+static inline bool roce5_is_extend_atomic(enum ib_wr_opcode opcode)
+{
+ return ((roce5_ib_opcode[opcode] ==
+ ROCE_WQE_OPCODE_MASKED_ATOMIC_CMP_SWP) ||
+ (roce5_ib_opcode[opcode] ==
+ ROCE_WQE_OPCODE_MASKED_ATOMIC_FETCH_ADD));
+}
+
+static inline int roce5_is_vaild_wr_opcode(struct roce5_qp *rqp,
+ enum ib_wr_opcode opcode)
+{
+ if (ROCE_UNLIKELY((opcode >= ARRAY_SIZE(roce5_ib_opcode)))) {
+ return -EINVAL;
+ }
+
+ if ((roce5_ib_opcode[opcode] == 0) && (opcode != IB_WR_SEND)) {
+ return -EINVAL;
+ }
+
+ if (roce5_is_pcie_atomic(rqp) && roce5_is_extend_atomic(opcode)) {
+ ROCE_ERR(
+ "The atomic mode is pcie atomic, but extended atomic is not supported.");
+ return -EINVAL;
+ }
+
+ return 0; /* Vaild IB opcode */
+}
+
+/* ****************************************************************************
+ Prototype : roce5_validate_wr
+ Description : roce5_validate_wr
+ Input : struct roce5_qp *rqp
+ struct ib_send_wr *wr
+ int wr_num
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_validate_wr(struct roce5_qp *rqp, const struct ib_send_wr *wr,
+ u32 wr_num)
+{
+ if (roce5_wq_overflow(&rqp->sq, wr_num, rqp->ibqp.send_cq) != 0) {
+ ROCE_ERR("SQ is full");
+ return -ENOMEM;
+ }
+
+ if (ROCE_UNLIKELY(((u32)wr->num_sge) > rqp->sq.max_sge)) {
+ ROCE_ERR(
+ "Sge num is invalide, wr->num_sge(%d), rqp->sq.max_sge(%d)",
+ wr->num_sge, rqp->sq.max_sge);
+ return -EINVAL;
+ }
+
+ if (ROCE_UNLIKELY(roce5_is_vaild_wr_opcode(rqp, wr->opcode) != 0)) {
+ ROCE_ERR("wr->opcode(%d)", wr->opcode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void
+roce5_set_rc_wqe_for_optype_send(const struct ib_send_wr *wr,
+ struct roce5_post_send_normal_param *param)
+{
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_SEND_LOCAL_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ roce5_set_send_seg((struct roce_wqe_send_tsk_seg *)param->wqe, wr);
+ param->data_len_addr =
+ &((struct roce_wqe_send_tsk_seg *)param->wqe)->data_len;
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce_wqe_send_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce_wqe_send_tsk_seg);
+}
+
+static void
+roce5_set_rc_wqe_for_optype_atomic(const struct ib_send_wr *wr,
+ struct roce5_post_send_normal_param *param)
+{
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_RDMA_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ roce5_set_atomic_seg((struct roce_wqe_atomic_tsk_seg *)param->wqe, wr);
+ param->wqe =
+ ((u8 *)param->wqe + sizeof(struct roce_wqe_atomic_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce_wqe_atomic_tsk_seg);
+}
+
+static void
+roce5_set_rc_wqe_for_optype_write(const struct ib_send_wr *wr,
+ struct roce5_post_send_normal_param *param)
+{
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_RDMA_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ roce5_set_rdma_seg((struct roce_wqe_rdma_tsk_seg *)param->wqe, wr);
+ param->data_len_addr =
+ &((struct roce_wqe_rdma_tsk_seg *)param->wqe)->data_len;
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce_wqe_rdma_tsk_seg));
+ param->wqe_size += (u32)(sizeof(struct roce_wqe_rdma_tsk_seg));
+}
+
+static void
+roce5_set_rc_wqe_for_optype_local(const struct ib_send_wr *wr,
+ struct roce5_post_send_normal_param *param)
+{
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_SEND_LOCAL_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ param->tsk_com_seg->bs.so = 1;
+ roce5_set_local_inv_seg((struct roce_wqe_local_inv_tsk_seg *)param->wqe,
+ wr);
+ param->wqe_size += (u32)sizeof(struct roce_wqe_local_inv_tsk_seg);
+ param->inline_flag = 0;
+ param->ctrl_seg_tmp.dw0.bs.df = 0;
+}
+
+static void roce5_set_wqe_last_len(u8 *wqe)
+{
+ struct roce_wqe_send_tsk_seg *snd_task =
+ (struct roce_wqe_send_tsk_seg *)(void *)wqe;
+ snd_task->dw3.value = 0;
+ snd_task->dw3.bs.last_ext_len = ROCE_IMM_EXT_LEN;
+ snd_task->dw3.value = cpu_to_be32(snd_task->dw3.value);
+}
+
+static inline u32 roce5_log2(u32 x)
+{
+ u32 shift;
+
+ for (shift = 0; (1U << shift) < x; ++shift) {
+ ;
+ }
+
+ return shift;
+}
+
+/* RoCE supports FRMR, for at privileged user, can via post send WR of way for at at free status of MR perform fast register.
+ frmr wqe contain a pbl(page buffer list) table start address, start va, length, page size etc. information.
+ 预 先 allocate of store space of start address (pa) need write pbl. only supports one level
寻 址, maximum supports 512(count word) PA. */
+static int set_frmr_wqe_section(const struct ib_send_wr *wr,
+ struct roce5_post_send_normal_param *param)
+{
+ u64 iova;
+ u32 fbo;
+ struct ib_reg_wr *frmr_reg_wr = NULL;
+ struct roce5_mr *roce5_kernel_frmr = NULL;
+ struct roce_wqe_frmr_tsk_seg *frmr_wqe_task = NULL;
+
+ frmr_reg_wr = (struct ib_reg_wr *)reg_wr((struct ib_send_wr *)wr);
+ roce5_kernel_frmr = to_roce5_mr(frmr_reg_wr->mr);
+
+ /* base section set */
+ param->wqe_size += sizeof(struct roce_wqe_frmr_tsk_seg);
+
+ frmr_wqe_task =
+ (struct roce_wqe_frmr_tsk_seg *)((void *)param->tsk_com_seg);
+ param->dseg =
+ (roce_wqe_data_seg_s *)(((u8 *)param->tsk_com_seg) +
+ sizeof(struct roce_wqe_frmr_tsk_seg));
+ param->ctrl_seg_tmp.dw0.bs.tsl =
+ sizeof(struct roce_wqe_frmr_tsk_seg) / ROCE_TASK_SEG_ALIGN;
+ /* fill wqe ctrl head section:cl bit */
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+
+ /* local invalidate associated section set */
+ param->tsk_com_seg->bs.so = 1;
+
+ iova = (u64)(void *)(uintptr_t)(frmr_reg_wr->mr->iova);
+ fbo = (u32)(iova & (FRMR_PAGE_SIZE - 1));
+ frmr_wqe_task->dw2.bs.fbo = fbo & 0x3FFFFF;
+ frmr_wqe_task->dw2.value = cpu_to_be32(frmr_wqe_task->dw2.value);
+
+ frmr_wqe_task->dw5.va =
+ (((u32)frmr_reg_wr->access & IB_ZERO_BASED) != 0) ?
+ 0 :
+ cpu_to_be64(iova);
+
+ /* fill in access permission */
+ frmr_wqe_task->dw3.bs.zbva =
+ (u32)(((u32)frmr_reg_wr->access & IB_ZERO_BASED) != 0);
+ frmr_wqe_task->dw3.bs.be =
+ (u32)(((u32)frmr_reg_wr->access & IB_ACCESS_MW_BIND) !=
+ 0); /* bind operation enable */
+ frmr_wqe_task->dw3.bs.lre = 1; /* this place read enable */
+ frmr_wqe_task->dw3.bs.lwe =
+ (u32)(((u32)frmr_reg_wr->access & IB_ACCESS_LOCAL_WRITE) !=
+ 0); /* this place write enable */
+ frmr_wqe_task->dw3.bs.rre =
+ (u32)(((u32)frmr_reg_wr->access & IB_ACCESS_REMOTE_READ) !=
+ 0); /* remote read enable */
+ frmr_wqe_task->dw3.bs.rwe =
+ (u32)(((u32)frmr_reg_wr->access & IB_ACCESS_REMOTE_WRITE) !=
+ 0); /* remote write enable */
+ frmr_wqe_task->dw3.bs.rae =
+ (u32)(((u32)frmr_reg_wr->access & IB_ACCESS_REMOTE_ATOMIC) !=
+ 0); /* remote Atomic enable */
+ frmr_wqe_task->dw3.bs.block = 1;
+ frmr_wqe_task->dw3.bs.rsvd = 0;
+ frmr_wqe_task->dw3.bs.pa_num = (roce5_kernel_frmr->npages == 0) ?
+ 1 :
+ roce5_kernel_frmr->npages;
+ /* MR memory page size. equals to (2^page_size)*4KB */
+ frmr_wqe_task->dw3.bs.page_size =
+ roce5_log2(frmr_reg_wr->mr->page_size) - 12; //12 is 4K page of shift
+ if (frmr_reg_wr->mr->page_size != PAGE_SIZE) {
+ ROCE_WARN(
+ "Frmr page size doesn't match page frame of OS! It may lead to unexpected memory translation.");
+ }
+ frmr_wqe_task->dw3.value = cpu_to_be32(frmr_wqe_task->dw3.value);
+
+ frmr_wqe_task->m_key = cpu_to_be32(frmr_reg_wr->key);
+ frmr_wqe_task->dw7.len = cpu_to_be64(frmr_reg_wr->mr->length);
+ frmr_wqe_task->dw9.pbl_addr = cpu_to_be64(roce5_kernel_frmr->page_map);
+ /* set inline and direct wqe handle section */
+ frmr_wqe_task->rsvd[0] = 0;
+ frmr_wqe_task->rsvd[1] = 0;
+
+ param->inline_flag = 0;
+ return 0;
+}
+
+static int roce5_post_send_rc(struct roce5_post_send_normal_param *param,
+ struct roce5_device *rdev,
+ const struct ib_send_wr *wr)
+{
+ int ret = 0;
+
+ switch (wr->opcode) {
+ case IB_WR_SEND_WITH_IMM:
+ case IB_WR_SEND_WITH_INV:
+ roce5_set_wqe_last_len(param->wqe);
+ roce5_set_rc_wqe_for_optype_send(wr, param);
+ break;
+ case IB_WR_SEND:
+ roce5_set_rc_wqe_for_optype_send(wr, param);
+ break;
+
+ case IB_WR_ATOMIC_CMP_AND_SWP:
+ case IB_WR_ATOMIC_FETCH_AND_ADD:
+ roce5_set_rc_wqe_for_optype_atomic(wr, param);
+ break;
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ roce5_set_wqe_last_len(param->wqe);
+ roce5_set_rc_wqe_for_optype_write(wr, param);
+ break;
+
+ case IB_WR_RDMA_READ:
+ case IB_WR_RDMA_WRITE:
+ roce5_set_rc_wqe_for_optype_write(wr, param);
+ break;
+
+ case IB_WR_LOCAL_INV:
+ roce5_set_rc_wqe_for_optype_local(wr, param);
+ ret = ROCE_NEED_JUMP;
+ break;
+
+ case IB_WR_REG_MR:
+ set_frmr_wqe_section(wr, param);
+ ret = ROCE_NEED_JUMP;
+ break;
+
+ default:
+ ROCE_DEV_ERR(rdev, "Invalid opcode(%d), func_id(%d)",
+ wr->opcode, rdev->glb_func_id);
+ break;
+ }
+
+ return ret;
+}
+
+static int roce5_post_send_uc(struct roce5_post_send_normal_param *param,
+ struct roce5_device *rdev,
+ const struct ib_send_wr *wr)
+{
+ switch (wr->opcode) {
+ case IB_WR_SEND_WITH_IMM:
+ case IB_WR_SEND:
+ if (wr->opcode == IB_WR_SEND_WITH_IMM) {
+ roce5_set_wqe_last_len(param->wqe);
+ }
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_SEND_LOCAL_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ roce5_set_send_seg((struct roce_wqe_send_tsk_seg *)param->wqe,
+ wr);
+ param->data_len_addr =
+ &((struct roce_wqe_send_tsk_seg *)param->wqe)->data_len;
+ param->wqe = ((u8 *)param->wqe +
+ sizeof(struct roce_wqe_send_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce_wqe_send_tsk_seg);
+ break;
+
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ case IB_WR_RDMA_WRITE:
+ if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
+ roce5_set_wqe_last_len(param->wqe);
+ }
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_RDMA_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ roce5_set_rdma_seg((struct roce_wqe_rdma_tsk_seg *)param->wqe,
+ wr);
+ param->data_len_addr =
+ &((struct roce_wqe_rdma_tsk_seg *)param->wqe)->data_len;
+ param->wqe = ((u8 *)param->wqe +
+ sizeof(struct roce_wqe_rdma_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce_wqe_rdma_tsk_seg);
+ break;
+
+ case IB_WR_LOCAL_INV:
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_SEND_LOCAL_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ param->tsk_com_seg->bs.so = 1;
+ roce5_set_local_inv_seg(
+ (struct roce_wqe_local_inv_tsk_seg *)param->wqe, wr);
+ param->wqe_size +=
+ (u32)sizeof(struct roce_wqe_local_inv_tsk_seg);
+ return ROCE_NEED_JUMP;
+
+ default:
+ ROCE_DEV_ERR(rdev, "Invalid opcode(%d), func_id(%d)",
+ wr->opcode, rdev->glb_func_id);
+ break;
+ }
+
+ return 0;
+}
+
+static int roce5_post_send_ud(struct roce5_post_send_normal_param *param,
+ struct roce5_device *rdev, struct roce5_qp *rqp,
+ const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr)
+{
+ struct roce_wqe_ud_tsk_seg *tsk_sg =
+ (struct roce_wqe_ud_tsk_seg *)param->wqe;
+
+ if (ROCE_UNLIKELY((wr->opcode != IB_WR_SEND) &&
+ (wr->opcode != IB_WR_SEND_WITH_IMM))) {
+ ROCE_DEV_ERR(rdev, "Wr->opcode(%d), func_id(%d)", wr->opcode,
+ rdev->glb_func_id);
+ *bad_wr = wr;
+ return ROCE_NEED_JUMP;
+ }
+
+ if (wr->opcode == IB_WR_SEND_WITH_IMM) {
+ tsk_sg->dw2.bs.last_ext_len = ROCE_IMM_EXT_LEN;
+ tsk_sg->dw2.value = cpu_to_be32(tsk_sg->dw2.value);
+ }
+
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_UD_WQE_COM_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ param->data_len_addr =
+ &((struct roce_wqe_ud_tsk_seg *)param->wqe)->data_len;
+
+ if (param->sq_rmd_size > (1UL << (unsigned int)rqp->sq.wqe_shift)) {
+ roce5_set_ud_seg((struct roce_wqe_ud_tsk_seg *)(param->wqe),
+ wr);
+ param->wqe =
+ ((u8 *)param->wqe + sizeof(struct roce_wqe_ud_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce_wqe_ud_tsk_seg);
+ } else {
+ roce5_set_ud_seg_cycle1(
+ (struct roce_wqe_ud_tsk_seg_cycle1 *)param->wqe, wr);
+ param->wqe = rqp->sq_head_addr;
+ param->wqe_size +=
+ (u32)sizeof(struct roce_wqe_ud_tsk_seg_cycle1);
+ roce5_set_ud_seg_cycle2(
+ (struct roce_wqe_ud_tsk_seg_cycle2 *)param->wqe, wr);
+ param->wqe = ((u8 *)param->wqe +
+ sizeof(struct roce_wqe_ud_tsk_seg_cycle2));
+ param->wqe_size +=
+ (u32)sizeof(struct roce_wqe_ud_tsk_seg_cycle2);
+ }
+
+ return 0;
+}
+
+static void roce5_post_send_set_normal_data_seg(const struct ib_send_wr *wr,
+ struct roce_wqe_data_seg **dseg,
+ struct roce5_qp *rqp)
+{
+ if (wr->num_sge != 0) {
+ if ((u8 *)(*dseg) == rqp->sq_head_addr) {
+ *dseg = (struct roce_wqe_data_seg *)((
+ void *)(rqp->sq_tail_addr -
+ sizeof(struct roce_wqe_data_seg)));
+ } else {
+ (*dseg)--;
+ }
+ (*dseg)->key = (u32)wr->sg_list[wr->num_sge - 1].lkey |
+ ROCE_WQE_NEXT_SGE_INVALID;
+ (*dseg)->key = cpu_to_be32((*dseg)->key);
+ }
+}
+
+static int
+roce5_post_send_set_normal_sge(struct roce5_post_send_normal_param *param,
+ struct roce5_device *rdev, struct roce5_qp *rqp,
+ const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr)
+{
+ int i;
+
+ param->data_len = 0;
+ param->dseg = (struct roce_wqe_data_seg *)param->wqe;
+ param->wqe_size +=
+ (u32)(wr->num_sge * (int)sizeof(struct roce_wqe_data_seg));
+ for (i = 0; i < wr->num_sge; ++i) {
+ if (param->sq_rmd_size < sizeof(struct roce_wqe_data_seg)) {
+ param->dseg = (struct roce_wqe_data_seg
+ *)((void *)rqp->sq_head_addr);
+ }
+
+ if (ROCE_UNLIKELY(wr->sg_list[i].length >
+ (rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_msg_sz))) {
+ *bad_wr = wr;
+ ROCE_DEV_ERR(
+ rdev,
+ "Sge_data length is over range, sg_list(%d), length(0x%x), max_msg_sz(0x%x), func_id(%d)",
+ i, wr->sg_list[i].length,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_msg_sz,
+ rdev->glb_func_id);
+ return ROCE_NEED_JUMP;
+ }
+
+ param->data_len += wr->sg_list[i].length;
+ if (ROCE_UNLIKELY(param->data_len >
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_msg_sz)) {
+ *bad_wr = wr;
+ ROCE_DEV_ERR(
+ rdev,
+ "Data len is over range, data_len(%d), max_msg_sz(%d), func_id(%d)",
+ param->data_len,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_msg_sz,
+ rdev->glb_func_id);
+ return ROCE_NEED_JUMP;
+ }
+ roce5_set_data_seg(param->dseg, wr->sg_list + i);
+
+ (param->dseg)++;
+ param->sq_rmd_size =
+ (u32)(rqp->sq_tail_addr - (u8 *)param->dseg);
+ }
+
+ return 0;
+}
+
+static void roce5_copy_inline_data(struct roce5_post_send_normal_param *param,
+ const struct ib_send_wr *wr,
+ struct roce5_qp *rqp, int i)
+{
+ int ret = 0;
+ struct ib_sge *sge = wr->sg_list + i;
+
+ if (param->sq_rmd_size >= wr->sg_list[i].length) {
+ /* Set inline data */
+ ret = memcpy_s(param->wqe, sge->length,
+ (void *)(uintptr_t)sge->addr, sge->length);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy param->wqe.(ret:%d)", ret);
+ return;
+ }
+ param->wqe = ((u8 *)param->wqe + wr->sg_list[i].length);
+ if ((u8 *)param->wqe == rqp->sq_tail_addr) {
+ param->wqe = rqp->sq_head_addr;
+ }
+ } else {
+ /* Set inline data cycle1 */
+ u32 size = param->sq_rmd_size;
+ ret = memcpy_s(param->wqe, size, (void *)(uintptr_t)sge->addr,
+ size);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy param->wqe.(ret:%d)", ret);
+ return;
+ }
+ param->wqe = rqp->sq_head_addr;
+
+ /* Set inline data cycle2 */
+ size = wr->sg_list[i].length - param->sq_rmd_size;
+ ret = memcpy_s(
+ param->wqe, size,
+ (void *)((u8 *)(void *)(uintptr_t)sge->addr + size),
+ size);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy param->wqe.(ret:%d)", ret);
+ return;
+ }
+ param->wqe = ((u8 *)param->wqe + wr->sg_list[i].length -
+ param->sq_rmd_size);
+
+ param->cycle = 1;
+ }
+}
+
+static int
+roce5_post_send_set_data_seg(struct roce5_post_send_normal_param *param,
+ struct roce5_device *rdev, struct roce5_qp *rqp,
+ const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr)
+{
+ int i;
+ int ret;
+
+ if ((((unsigned int)wr->send_flags & (unsigned int)IB_SEND_INLINE) !=
+ 0) &&
+ (wr->num_sge != 0) && (param->inline_flag != 0)) {
+ param->data_len = 0;
+
+ for (i = 0; i < wr->num_sge; ++i) {
+ param->wqe_size += wr->sg_list[i].length;
+ param->data_len += wr->sg_list[i].length;
+ if (param->data_len > rqp->max_inline_data) {
+ *bad_wr = wr;
+ ROCE_DEV_ERR(
+ rdev,
+ "Data len is too big, data_len(%d), max_inline_data(%d), func_id(%d)",
+ param->data_len, rqp->max_inline_data,
+ rdev->glb_func_id);
+ return ROCE_NEED_JUMP;
+ }
+
+ if ((u8 *)param->wqe == rqp->sq_head_addr) {
+ param->cycle = 1;
+ }
+
+ roce5_copy_inline_data(param, wr, rqp, i);
+
+ param->sq_rmd_size =
+ (u32)(rqp->sq_tail_addr - (u8 *)param->wqe);
+ }
+ param->ctrl_seg_tmp.dw0.bs.bdsl =
+ (ALIGN((u32)(param->data_len), ROCE_TASK_SEG_ALIGN) /
+ ROCE_TASK_SEG_ALIGN) &
+ 0x7ff;
+ param->ctrl_seg_tmp.dw0.bs.df = 1;
+ param->inline_flag = 1;
+ } else {
+ ret = roce5_post_send_set_normal_sge(param, rdev, rqp, wr,
+ bad_wr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ roce5_post_send_set_normal_data_seg(wr, ¶m->dseg, rqp);
+
+ param->ctrl_seg_tmp.dw0.bs.bdsl =
+ (u32)((wr->num_sge *
+ (int)sizeof(struct roce_wqe_data_seg)) /
+ ROCE_TASK_SEG_ALIGN) &
+ 0x7ff;
+ param->ctrl_seg_tmp.dw0.bs.df = 0;
+ }
+
+ return 0;
+}
+
+static void roce5_fill_task_data_len(u32 *data_len_addr, u32 data_len)
+{
+ if (data_len_addr != NULL) {
+ *data_len_addr = cpu_to_be32(data_len);
+ }
+}
+
+static int roce5_construct_wqe(struct roce5_post_send_normal_param *param,
+ struct roce5_device *rdev, struct roce5_qp *rqp,
+ const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr)
+{
+ int need_goto = 0;
+ int ret;
+
+ switch (rqp->qp_type) {
+ case IB_QPT_RC:
+ need_goto = roce5_post_send_rc(param, rdev, wr);
+ if (need_goto == ROCE_NEED_JUMP) {
+ return GOTO_LOCAL;
+ }
+ break;
+
+ case IB_QPT_UC:
+ need_goto = roce5_post_send_uc(param, rdev, wr);
+ if (need_goto == ROCE_NEED_JUMP) {
+ return GOTO_LOCAL;
+ }
+ break;
+
+ case IB_QPT_UD:
+ need_goto = roce5_post_send_ud(param, rdev, rqp, wr, bad_wr);
+ if (need_goto == ROCE_NEED_JUMP) {
+ return GOTO_OUT;
+ }
+ break;
+
+ case IB_QPT_GSI:
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_UD_WQE_COM_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+
+ ret = roce5_set_gsi_seg(rqp, wr, param->wqe);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to set gsi seg, ret(%d).",
+ ret);
+ return GOTO_OUT;
+ }
+
+ param->data_len_addr =
+ &((struct roce_wqe_ud_tsk_seg *)param->wqe)->data_len;
+ param->wqe =
+ ((u8 *)param->wqe + sizeof(struct roce_wqe_ud_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce_wqe_ud_tsk_seg);
+ break;
+
+ default:
+ ROCE_DEV_ERR(rdev, "Unknown qp type, func_id(%d)",
+ rdev->glb_func_id);
+ break;
+ }
+
+ return 0;
+}
+
+static void roce5_init_ctrl_seg(struct roce5_post_send_normal_param *param,
+ const struct ib_send_wr *wr,
+ const struct roce5_qp *rqp)
+{
+ u32 wqe_opcode = roce5_ib_opcode[wr->opcode] & 0x1f;
+ param->ctrl_seg_tmp.dw0.bs.owner =
+ ((param->index & (u32)rqp->sq.wqebb_cnt) != 0) ? 1 : 0;
+ param->ctrl_seg_tmp.dw0.bs.drvsl = 0;
+ param->ctrl_seg_tmp.dw0.bs.wf = 0;
+ param->ctrl_seg_tmp.dw0.bs.cf = 0;
+ param->ctrl_seg_tmp.dw0.bs.va = 1;
+ param->ctrl_seg_tmp.dw0.bs.df = 0; /* va:1bits, 0-sge,1-inline */
+ param->ctrl_seg_tmp.dw0.bs.cr =
+ (u32)(!(((((u32)wr->send_flags) & IB_SEND_SIGNALED) |
+ rqp->sq_signal_bits) == 0));
+ param->ctrl_seg_tmp.dw0.bs.difsl = 0;
+ param->ctrl_seg_tmp.dw0.bs.csl = 0;
+ param->ctrl_seg_tmp.dw0.bs.ctrlsl = ROCE_CTRL_SEG_SL;
+ param->ctrl_seg_tmp.dw0.bs.bdsl = 0;
+
+ param->ctrl_seg_tmp.dw0.bs.wqe_ssn = (param->sq_wqe_ssn & 0x3);
+ param->sq_wqe_ssn += (u8)g_roce5_opcode_attr[wqe_opcode].remote_opcode;
+}
+
+static void roce5_init_task_com_seg(union roce5_wqe_tsk_com_seg **tsk_com_seg,
+ u8 *wqe, const struct ib_send_wr *wr,
+ const struct roce5_qp *rqp)
+{
+ struct roce_wqe_send_tsk_seg *send_task =
+ (struct roce_wqe_send_tsk_seg *)(void *)wqe;
+ *tsk_com_seg = (union roce5_wqe_tsk_com_seg *)(void *)wqe;
+
+ send_task->dw3.value = 0;
+ (*tsk_com_seg)->bs.c = (u32)(!(
+ (((unsigned)wr->send_flags & (unsigned)IB_SEND_SIGNALED) |
+ rqp->sq_signal_bits) == 0));
+ (*tsk_com_seg)->bs.se = (u32)(!(
+ ((unsigned)wr->send_flags & (unsigned)IB_SEND_SOLICITED) == 0));
+ (*tsk_com_seg)->bs.f = (u32)(!(
+ ((unsigned)wr->send_flags & (unsigned)IB_SEND_FENCE) == 0));
+ (*tsk_com_seg)->bs.op_type = roce5_ib_opcode[wr->opcode] & 0x1f;
+}
+
+static void
+roce5_post_send_local_operation(struct roce5_post_send_normal_param *param,
+ struct roce5_qp *rqp, struct roce5_device *rdev)
+{
+ param->opcode = param->tsk_com_seg->bs.op_type;
+ param->tsk_com_seg->value = cpu_to_be32(param->tsk_com_seg->value);
+ param->ctrl_seg->dw1.value = cpu_to_be32(param->ctrl_seg_tmp.dw1.value);
+ param->index += (u32)ROCE_DIV_ROUND_UP(param->wqe_size,
+ 1U << (u32)rqp->sq.wqe_shift);
+
+ write_invalid_wqe(rqp, param->index);
+
+ /*
+ * Make sure descriptor is fully written before
+ * setting ownership bit (because HW can start
+ * executing as soon as we do).
+ */
+ wmb();
+
+ param->ctrl_seg->dw0.value = cpu_to_be32(param->ctrl_seg_tmp.dw0.value);
+}
+/* ****************************************************************************
+ Prototype : roce5_post_send_normal
+ Description : roce5_post_send_normal
+ Input : struct roce5_device *rdev
+ struct roce5_qp *rqp
+ struct ib_send_wr *wr
+ struct ib_send_wr **bad_wr
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+ 2.Date : 2015/8/8
+ Modification : Modify function
+
+**************************************************************************** */
+static int roce5_post_send_normal(struct roce5_device *rdev,
+ struct roce5_qp *rqp,
+ const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr)
+{
+ int need_goto = 0;
+ int ret = 0;
+ struct roce5_post_send_normal_param param = { 0 };
+ const struct ib_send_wr *wr_tmp = wr;
+
+ spin_lock_irqsave(&rqp->sq.lock, param.flags);
+
+ param.index = rqp->sq_next_wqe;
+ param.sq_wqe_ssn = rqp->sq_wqe_ssn;
+
+ for (param.wr_num = 0; wr_tmp != NULL;
+ ++(param.wr_num), wr_tmp = wr_tmp->next) {
+ ret = roce5_validate_wr(rqp, wr_tmp, param.wr_num);
+ if (ret != 0) {
+ *bad_wr = wr_tmp;
+ ROCE_DEV_ERR(rdev,
+ " Failed to validate wr, func(%d) qpn(%u)",
+ rdev->glb_func_id, rqp->qpn);
+ goto out;
+ }
+
+ param.wqe = (u8 *)roce5_get_send_wqe(rqp, param.index);
+ param.ctrl_seg = (struct roce5_wqe_ctrl_seg *)param.wqe;
+
+ param.sq_rmd_size = (u32)(rqp->sq_tail_addr - (u8 *)param.wqe);
+
+ rqp->sq.wrid[(rqp->sq.head + param.wr_num) &
+ (u32)(rqp->sq.wqebb_cnt - 1)] = wr_tmp->wr_id;
+
+ roce5_init_ctrl_seg(¶m, wr_tmp, rqp);
+
+ param.wqe = ((u8 *)param.wqe + sizeof(*(param.ctrl_seg)));
+ param.wqe_size = (u32)sizeof(*param.ctrl_seg);
+ roce5_init_task_com_seg(¶m.tsk_com_seg, param.wqe, wr_tmp,
+ rqp);
+
+ ret = roce5_construct_wqe(¶m, rdev, rqp, wr_tmp, bad_wr);
+ if (ret == GOTO_LOCAL) {
+ ret = 0;
+ goto local;
+ } else if (ret == GOTO_OUT) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ param.sq_rmd_size = (u32)(rqp->sq_tail_addr - (u8 *)param.wqe);
+
+ need_goto = roce5_post_send_set_data_seg(¶m, rdev, rqp,
+ wr_tmp, bad_wr);
+ if (need_goto == ROCE_NEED_JUMP) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ roce5_fill_task_data_len(param.data_len_addr, param.data_len);
+
+local:
+ roce5_post_send_local_operation(¶m, rqp, rdev);
+ }
+
+out:
+ if (ROCE_LIKELY(param.wr_num != 0)) {
+ rqp->sq.head += param.wr_num;
+
+ wmb();
+
+ ret = roce5_write_sq_db(rdev, rqp, param.index, NULL);
+ rqp->sq_next_wqe = param.index;
+ rqp->sq_wqe_ssn = param.sq_wqe_ssn;
+ }
+
+ spin_unlock_irqrestore(&rqp->sq.lock, param.flags);
+
+ return ret;
+}
+
+static int roce5_post_send_check_qp_type(const struct roce5_qp *rqp)
+{
+ if (ROCE_UNLIKELY(rqp->qp_type == IB_QPT_XRC_TGT)) {
+ ROCE_ERR("Can't post WQE when TGT XRC QP");
+ return -EINVAL;
+ }
+
+ if (ROCE_UNLIKELY(rqp->qp_type == IB_QPT_XRC_INI)) {
+ ROCE_ERR("not support xrc in kernel space");
+ return -EINVAL;
+ }
+
+ if (ROCE_UNLIKELY((rqp->qp_state == IB_QPS_RESET) ||
+ (rqp->qp_state == IB_QPS_INIT) ||
+ (rqp->qp_state == IB_QPS_RTR))) {
+ ROCE_ERR("Can't post WQE when QP is RST/INIT/RTR state");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_post_send
+ Description : roce5_post_send
+ Input : struct ib_qp *ibqp
+ struct ib_send_wr *wr
+ const struct ib_send_wr **bad_wr
+ Output : None
+**************************************************************************** */
+int roce5_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr)
+{
+ int ret = 0;
+ struct roce5_qp *rqp = to_roce5_qp(ibqp);
+ struct roce5_device *rdev = to_roce5_dev(ibqp->device);
+
+ ret = roce5_post_send_check_qp_type(rqp);
+ if (ret != 0) {
+ *bad_wr = wr;
+ ROCE_DEV_ERR(rdev, "Failed to check qp.ret(%d)", ret);
+ return ret;
+ }
+
+ ret = roce5_post_send_normal(rdev, rqp, wr, bad_wr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to post send normal wr, ret(%d)",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce5_post_send_ofa(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr)
+{
+ return roce5_post_send(ibqp, (const struct ib_send_wr *)wr,
+ (const struct ib_send_wr **)bad_wr);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_query.c b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_query.c
new file mode 100644
index 000000000..260eca49e
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/qp/roce_qp_query.c
@@ -0,0 +1,543 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "roce_compat.h"
+
+#include "hinic5_crm.h"
+
+#include "roce.h"
+#include "roce_mix.h"
+#include "roce_mr.h"
+#include "roce_xrc.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_cqm_cmd.h"
+#include "roce_qp.h"
+#include "roce_restore.h"
+#include "roce_npu_cmd.h"
+#include "roce_main_extension.h"
+#include "roce_com.h"
+#include "securec.h"
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+
+/**
+ * @brief Get roce qp by qpn. When querying succeeded, you have to call roce5_rqp_put() to free
+ the cqm_obj_qp. But there is no need to call roce5_rqp_put() if querying failed.
+ * @return Success: return the roce qp. Failure: return NULL.
+ */
+struct roce5_qp *roce5_get_rqp_by_qpn(struct roce5_device *rdev, u32 qpn)
+{
+ cqm_object_s *cqm_obj_qp = NULL;
+ struct roce5_qp *rqp = NULL;
+
+ cqm_obj_qp = cqm5_object_get(rdev->hwdev, CQM_OBJECT_SERVICE_CTX, qpn,
+ false);
+ if (cqm_obj_qp == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Can't find rqp according to qpn(0x%x), func_id(%d)",
+ qpn, rdev->glb_func_id);
+ return NULL;
+ }
+
+ rqp = cqmobj_to_roce_qp(cqm_obj_qp);
+ if (rqp == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to convert obj to rqp.");
+ cqm5_object_put(cqm_obj_qp);
+ }
+
+ return rqp;
+}
+
+static enum ib_mig_state to_ib_mig_state(int roce5_mig_state)
+{
+ switch (roce5_mig_state) {
+ case ROCE_QP_PM_ARMED:
+ return IB_MIG_ARMED;
+
+ case ROCE_QP_PM_REARM:
+ return IB_MIG_REARM;
+
+ case ROCE_QP_PM_MIGRATED:
+ return IB_MIG_MIGRATED;
+
+ default:
+ return (enum ib_mig_state)(-1);
+ }
+}
+
+static int to_ib_qp_access_flags(const roce_verbs_qp_attr_s *verbs_qp_attr)
+{
+ unsigned int ib_flags = 0;
+ u32 tmp = 0;
+
+ /* RRE */
+ if (verbs_qp_attr->com_info.dw0.bs.rre != 0) {
+ tmp = ib_flags | IB_ACCESS_REMOTE_READ;
+ ib_flags = tmp;
+ }
+
+ /* RWE */
+ if (verbs_qp_attr->com_info.dw0.bs.rwe != 0) {
+ tmp = ib_flags | IB_ACCESS_REMOTE_WRITE;
+ ib_flags = tmp;
+ }
+
+ /* RAE */
+ if (verbs_qp_attr->com_info.dw0.bs.rae != 0) {
+ tmp = ib_flags | IB_ACCESS_REMOTE_ATOMIC;
+ ib_flags = tmp;
+ }
+
+ return (int)ib_flags;
+}
+
+/* ****************************************************************************
+ Prototype : to_ib_ah_attr
+ Description : to_ib_ah_attr
+ Input : struct roce5_device *rdev
+ struct ib_ah_attr *ah_attr(struct rdma_ah_attr *ah_attr)
+ struct roce5_qp_context *context
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+**************************************************************************** */
+static void to_ib_ah_attr(struct roce5_device *rdev,
+ struct rdma_ah_attr *ah_attr,
+ roce_verbs_qp_attr_s *verbs_qp_attr)
+{
+ int ret;
+
+ ret = memset_s(ah_attr, sizeof(*ah_attr), 0, sizeof(*ah_attr));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset ah_attr.(ret:%d)", ret);
+ return;
+ }
+
+ ah_attr->port_num = verbs_qp_attr->com_info.dw5.bs.port;
+
+ ah_attr->sl = 0x7 - verbs_qp_attr->path_info.dw7.bs.sl;
+
+ ah_attr->static_rate = 0;
+
+ ah_attr->ah_flags = IB_AH_GRH;
+
+ ah_attr->grh.sgid_index = verbs_qp_attr->path_info.dw7.bs.sgid_index;
+ ah_attr->grh.hop_limit = verbs_qp_attr->path_info.dw7.bs.hoplmt;
+ ah_attr->grh.traffic_class = verbs_qp_attr->path_info.dw6.bs.tclass;
+ ah_attr->grh.flow_label = verbs_qp_attr->path_info.dw6.bs.flow_label;
+
+ ret = memcpy_s((void *)ah_attr->grh.dgid.raw,
+ sizeof(ah_attr->grh.dgid.raw),
+ (void *)verbs_qp_attr->path_info.dgid,
+ sizeof(ah_attr->grh.dgid.raw));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy dgid.(ret:%d)", ret);
+ }
+}
+
+int roce5_uni_cmd_qp_query(struct roce5_device *rdev, u32 qpn,
+ u32 *verbs_qp_attr, int qp_attr_size)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_qp_query_s *qp_query_inbuf = NULL;
+ roce_uni_cmd_qp_query_outbuf_s *qp_query_outbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_qp_query_s), &cqm_cmd_outbuf,
+ (u16)sizeof(roce_uni_cmd_qp_query_outbuf_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc cqm_cmd_inoutbuf, ret=%d",
+ ret);
+ return ret;
+ }
+
+ qp_query_inbuf = (roce_uni_cmd_qp_query_s *)cqm_cmd_inbuf->buf;
+ qp_query_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_QP_BITMASK));
+ qp_query_inbuf->com.index = cpu_to_be32(qpn);
+ ret = roce5_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_QUERY_QP, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, ROCE_CMD_TIME_CLASS_B);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to send QUERY_QP command, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -1;
+ goto free_cqm_buf;
+ }
+
+ qp_query_outbuf = (roce_uni_cmd_qp_query_outbuf_s *)cqm_cmd_outbuf->buf;
+ ret = (int)memcpy_s((void *)verbs_qp_attr, (size_t)qp_attr_size,
+ (void *)&qp_query_outbuf->qp_info.qp_attr,
+ (size_t)qp_attr_size);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy verbs_qp_attr, ret(%d).",
+ ret);
+ ret = -EINVAL;
+ }
+free_cqm_buf:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+ return ret;
+}
+
+int roce5_qp_query(struct roce5_device *rdev, u32 qpn, u32 *context,
+ int qpc_size)
+{
+ if (ROCE5_SUPPORT_IB_CMD_QUERY_QP_MSG_V2(rdev) != 0) {
+ return roce5_uni_cmd_qp_query(rdev, qpn, context, qpc_size);
+ }
+ return -EINVAL;
+}
+
+void qpc_seg_to_le32(struct roce5_qp_context *be_ctx,
+ struct roce5_qp_context *le_ctx, u32 srq_vld)
+{
+ /* DRV Seg */
+ int ret;
+
+ ret = memcpy_s((void *)le_ctx->sw_seg.path_seg.dgid,
+ sizeof(be_ctx->sw_seg.path_seg.dgid),
+ (void *)be_ctx->sw_seg.path_seg.dgid,
+ sizeof(be_ctx->sw_seg.path_seg.dgid));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dgid.(ret:%d)", ret);
+ return;
+ }
+
+ /* CHIP Seg */
+ le_ctx->chip_seg.qpcc.sq_rq_l0mtt_gpa =
+ be64_to_cpu(be_ctx->chip_seg.qpcc.sq_rq_l0mtt_gpa);
+ le_ctx->chip_seg.qpcc.sq_rq_pi_record_gpa_at_hop_num = cpu_to_be64(
+ be_ctx->chip_seg.qpcc.sq_rq_pi_record_gpa_at_hop_num);
+ le_ctx->chip_seg.rcc.rc_curt_sge_va =
+ be64_to_cpu(be_ctx->chip_seg.rcc.rc_curt_sge_va);
+ le_ctx->chip_seg.sqc.sq_curt_sge_va =
+ be64_to_cpu(be_ctx->chip_seg.sqc.sq_curt_sge_va);
+ le_ctx->chip_seg.sqac.sqa_curt_sge_va =
+ be64_to_cpu(be_ctx->chip_seg.sqac.sqa_curt_sge_va);
+
+ if (srq_vld != 0) {
+ le_ctx->chip_seg.srqc.srq_curt_sge_va =
+ be64_to_cpu(be_ctx->chip_seg.srqc.srq_curt_sge_va);
+ } else {
+ le_ctx->chip_seg.rqc.rq_curt_sge_va =
+ be64_to_cpu(be_ctx->chip_seg.rqc.rq_curt_sge_va);
+ }
+
+ le_ctx->chip_seg.rrwc.rrw_curt_sge_va =
+ be64_to_cpu(be_ctx->chip_seg.rrwc.rrw_curt_sge_va);
+}
+
+void roce5_be32_2_le32(void *context, u32 *le_ctx, u32 ctx_size)
+{
+ u32 *ctx = NULL, *ctx1 = NULL;
+ u32 i = 0;
+
+ ctx = le_ctx;
+ ctx1 = (u32 *)context;
+
+ for (i = 0; i < ctx_size; ++i, ++ctx1, ++ctx) {
+ *ctx = be32_to_cpu(*ctx1);
+ }
+
+ return;
+}
+
+static void roce5_get_ah_attr(const struct roce5_qp *rqp,
+ struct ib_qp_attr *qp_attr,
+ struct roce5_device *rdev,
+ roce_verbs_qp_attr_s *verbs_qp_attr)
+{
+ if ((rqp->qp_type == IB_QPT_RC) || (rqp->qp_type == IB_QPT_UC)) {
+ to_ib_ah_attr(rdev, &qp_attr->ah_attr, verbs_qp_attr);
+ }
+}
+
+static void roce5_query_set_common_attr(struct ib_qp_attr *qp_attr,
+ const struct ib_qp *ibqp,
+ struct roce5_qp *rqp,
+ struct ib_qp_init_attr *qp_init_attr)
+{
+ qp_attr->cur_qp_state = qp_attr->qp_state;
+ qp_attr->cap.max_recv_wr = (u32)rqp->rq.wqebb_cnt;
+ qp_attr->cap.max_recv_sge = (u32)rqp->rq.max_sge;
+
+ if (!ibqp->uobject) {
+ qp_attr->cap.max_send_wr = (u32)rqp->sq.max_post;
+ qp_attr->cap.max_send_sge = (u32)rqp->sq.max_sge;
+ } else {
+ qp_attr->cap.max_send_wr = 0;
+ qp_attr->cap.max_send_sge = 0;
+ }
+
+ qp_attr->cap.max_inline_data = rqp->max_inline_data;
+
+ qp_init_attr->cap = qp_attr->cap;
+
+ qp_init_attr->create_flags = (enum ib_qp_create_flags)0;
+
+ qp_init_attr->sq_sig_type = (rqp->sq_signal_bits == 1) ?
+ IB_SIGNAL_ALL_WR :
+ IB_SIGNAL_REQ_WR;
+}
+
+static void roce5_query_set_attr(struct ib_qp_attr *qp_attr, u8 tmp_qp_state,
+ struct roce5_qp *rqp,
+ roce_verbs_qp_attr_s *verbs_qp_attr,
+ struct roce5_device *rdev)
+{
+ qp_attr->qp_state = (enum ib_qp_state)rqp->qp_state;
+ qp_attr->path_mtu = (enum ib_mtu)verbs_qp_attr->com_info.dw3.bs.pmtu;
+ qp_attr->path_mig_state =
+ (enum ib_mig_state)to_ib_mig_state(ROCE_QP_PM_MIGRATED);
+ qp_attr->qkey = verbs_qp_attr->com_info.q_key;
+ qp_attr->rq_psn = verbs_qp_attr->com_info.dw9.bs.next_rcv_psn;
+ qp_attr->sq_psn = verbs_qp_attr->com_info.dw8.bs.next_send_psn;
+ qp_attr->dest_qp_num = verbs_qp_attr->com_info.dw0.bs.dest_qp;
+ qp_attr->qp_access_flags = to_ib_qp_access_flags(verbs_qp_attr);
+
+ roce5_get_ah_attr(rqp, qp_attr, rdev, verbs_qp_attr);
+
+ qp_attr->pkey_index = 0;
+
+ if (qp_attr->qp_state == IB_QPS_INIT) {
+ qp_attr->port_num = rqp->port;
+ } else {
+ qp_attr->port_num = verbs_qp_attr->com_info.dw5.bs.port;
+ }
+
+ /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+
+ /* SQ Draining FLAG */
+ qp_attr->sq_draining =
+ (tmp_qp_state ==
+ (u8)(enum roce_qp_state)ROCE_QP_STATE_SQ_DRAINING);
+
+ qp_attr->max_rd_atomic = (1 << verbs_qp_attr->com_info.dw1.bs.sra_max);
+ qp_attr->max_dest_rd_atomic =
+ (1 << verbs_qp_attr->com_info.dw1.bs.rra_max);
+
+ qp_attr->min_rnr_timer = verbs_qp_attr->com_info.dw2.bs.min_rnr_nak;
+ qp_attr->timeout = verbs_qp_attr->com_info.dw2.bs.ack_to;
+ qp_attr->retry_cnt = verbs_qp_attr->com_info.dw1.bs.to_retry_limit;
+ qp_attr->rnr_retry = verbs_qp_attr->com_info.dw1.bs.rnr_retry_limit;
+}
+
+static int roce5_query_qp_struct_clean(struct ib_qp_attr *qp_attr,
+ struct ib_qp_init_attr *qp_init_attr,
+ roce_verbs_qp_attr_s *verbs_qp_attr)
+{
+ int ret;
+
+ ret = memset_s(qp_attr, sizeof(struct ib_qp_attr), 0,
+ sizeof(struct ib_qp_attr));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset qp_attr.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = memset_s(qp_init_attr, sizeof(struct ib_qp_init_attr), 0,
+ sizeof(struct ib_qp_init_attr));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset qp_init_attr.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = memset_s(verbs_qp_attr, sizeof(roce_verbs_qp_attr_s), 0,
+ sizeof(roce_verbs_qp_attr_s));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset verbs_qp_attr.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void roce_qp_attr_com_info_to_le32(roce_verbs_qp_attr_s *verbs_qp_attr)
+{
+ verbs_qp_attr->com_info.dw0.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw0.value);
+ verbs_qp_attr->com_info.dw1.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw1.value);
+ verbs_qp_attr->com_info.dw2.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw2.value);
+ verbs_qp_attr->com_info.dw3.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw3.value);
+ verbs_qp_attr->com_info.q_key =
+ be32_to_cpu(verbs_qp_attr->com_info.q_key);
+ verbs_qp_attr->com_info.dw5.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw5.value);
+ verbs_qp_attr->com_info.dw6.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw6.value);
+ verbs_qp_attr->com_info.dw7.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw7.value);
+ verbs_qp_attr->com_info.dw8.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw8.value);
+ verbs_qp_attr->com_info.dw9.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw9.value);
+ verbs_qp_attr->com_info.lsn = be32_to_cpu(verbs_qp_attr->com_info.lsn);
+ verbs_qp_attr->com_info.dw11.value =
+ be32_to_cpu(verbs_qp_attr->com_info.dw11.value);
+ verbs_qp_attr->com_info.rsvd =
+ be32_to_cpu(verbs_qp_attr->com_info.rsvd);
+}
+
+static void roce_qp_attr_path_info_to_le32(roce_verbs_qp_attr_s *verbs_qp_attr)
+{
+ verbs_qp_attr->path_info.dw0.value =
+ be32_to_cpu(verbs_qp_attr->path_info.dw0.value);
+ verbs_qp_attr->path_info.dmac_l32 =
+ be32_to_cpu(verbs_qp_attr->path_info.dmac_l32);
+ verbs_qp_attr->path_info.dw6.value =
+ be32_to_cpu(verbs_qp_attr->path_info.dw6.value);
+ verbs_qp_attr->path_info.dw7.value =
+ be32_to_cpu(verbs_qp_attr->path_info.dw7.value);
+}
+
+static void roce_qp_attr_chip_seg_to_le32(roce_verbs_qp_attr_s *verbs_qp_attr)
+{
+ verbs_qp_attr->chip_seg.dw0.sq_rq_l0mtt_gpa =
+ be64_to_cpu(verbs_qp_attr->chip_seg.dw0.sq_rq_l0mtt_gpa);
+ verbs_qp_attr->chip_seg.dw2.sq_rq_pi_record_gpa_at_hop_num = be64_to_cpu(
+ verbs_qp_attr->chip_seg.dw2.sq_rq_pi_record_gpa_at_hop_num);
+ verbs_qp_attr->chip_seg.dw4.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw4.value);
+ verbs_qp_attr->chip_seg.dw5.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw5.value);
+ verbs_qp_attr->chip_seg.dw6.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw6.value);
+ verbs_qp_attr->chip_seg.dw7.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw7.value);
+ verbs_qp_attr->chip_seg.dw8.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw8.value);
+ verbs_qp_attr->chip_seg.dw9.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw9.value);
+ verbs_qp_attr->chip_seg.dw10.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw10.value);
+ verbs_qp_attr->chip_seg.rc_page_gpa_l =
+ be32_to_cpu(verbs_qp_attr->chip_seg.rc_page_gpa_l);
+ verbs_qp_attr->chip_seg.dw12.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw12.value);
+ verbs_qp_attr->chip_seg.dw13.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw13.value);
+ verbs_qp_attr->chip_seg.dw14.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw14.value);
+ verbs_qp_attr->chip_seg.dw15.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw15.value);
+ verbs_qp_attr->chip_seg.dw16.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw16.value);
+ verbs_qp_attr->chip_seg.dw17.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw17.value);
+ verbs_qp_attr->chip_seg.dw18.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw18.value);
+ verbs_qp_attr->chip_seg.dw19.value =
+ be32_to_cpu(verbs_qp_attr->chip_seg.dw19.value);
+}
+
+static void roce5_qp_attr_to_le32(roce_verbs_qp_attr_s *verbs_qp_attr)
+{
+ roce_qp_attr_com_info_to_le32(verbs_qp_attr);
+ roce_qp_attr_path_info_to_le32(verbs_qp_attr);
+ roce_qp_attr_chip_seg_to_le32(verbs_qp_attr);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_query_qp
+ Description : roce5_query_qp
+ Input : struct ib_qp *ibqp
+ struct ib_qp_attr *qp_attr
+ int qp_attr_mask
+ struct ib_qp_init_attr *qp_init_attr
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
+{
+ int ret = 0;
+ struct roce5_qp *rqp = NULL;
+ struct roce5_device *rdev = NULL;
+ roce_verbs_qp_attr_s verbs_qp_attr;
+ u32 srq_vld;
+ u8 tmp_qp_state = 0;
+
+ if ((ibqp == NULL) || (qp_attr == NULL) || (qp_init_attr == NULL)) {
+ ROCE_ERR("Input pointer is NULL");
+ return (-EINVAL);
+ }
+
+ ret = roce5_query_qp_struct_clean(qp_attr, qp_init_attr,
+ &verbs_qp_attr);
+ if (ret != 0) {
+ return ret;
+ }
+
+ rqp = to_roce5_qp(ibqp);
+ rdev = to_roce5_dev(ibqp->device);
+
+ mutex_lock(&rqp->mutex);
+
+ if (rqp->qp_state == (u8)(enum ib_qp_state)IB_QPS_RESET) {
+ qp_attr->qp_state = IB_QPS_RESET;
+ goto done;
+ }
+
+ if (ROCE5_SUPPORT_IB_CMD_QUERY_QP_MSG_V2(rdev) != 0) {
+ ret = roce5_qp_query(rdev, rqp->qpn,
+ (u32 *)(void *)(&verbs_qp_attr),
+ sizeof(verbs_qp_attr));
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to query qp with 25V100 or 23V200, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ mutex_unlock(&rqp->mutex);
+ return ret;
+ }
+ }
+
+ srq_vld = (!(rqp->ibqp.srq)) ? ROCE_QP_NO_SRQ : ROCE_QP_HAS_SRQ;
+
+ if (ROCE5_SUPPORT_IB_CMD_QUERY_QP_MSG_V2(rdev) != 0) {
+ roce5_qp_attr_to_le32(&verbs_qp_attr);
+ rqp->qp_state = verbs_qp_attr.com_info.dw6.bs
+ .state; /* 25V100 or 23V200 qp state */
+ }
+
+ tmp_qp_state = rqp->qp_state;
+ if (rqp->qp_state ==
+ (u8)(enum roce_qp_state)ROCE_QP_STATE_SQ_DRAINING) {
+ rqp->qp_state = (u8)(enum ib_qp_state)IB_QPS_SQD;
+ }
+
+ if (ROCE5_SUPPORT_IB_CMD_QUERY_QP_MSG_V2(rdev) != 0) {
+ /* 25V100 or 23V200 set attr */
+ roce5_query_set_attr(qp_attr, tmp_qp_state, rqp, &verbs_qp_attr,
+ rdev);
+ }
+
+done:
+ roce5_query_set_common_attr(qp_attr, ibqp, rqp, qp_init_attr);
+
+ mutex_unlock(&rqp->mutex);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp.c b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp.c
new file mode 100644
index 000000000..257e9a8aa
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp.c
@@ -0,0 +1,22 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic5_hw.h"
+#include "rdma_comp.h"
+
+struct rdma_comp_priv *get_rdma_comp_priv(void *hwdev)
+{
+ struct rdma_comp_priv *comp_private = NULL;
+ comp_private = (struct rdma_comp_priv *)hinic5_get_service_adapter(
+ hwdev, SERVICE_T_ROCE);
+ return comp_private;
+}
+
+void rdma_cleanup_pd_table(struct rdma_comp_priv *comp_priv)
+{
+ rdma_bitmap_cleanup(&comp_priv->pd_bitmap);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp.h b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp.h
new file mode 100644
index 000000000..8a1a8d665
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp.h
@@ -0,0 +1,166 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef RDMA_COMP_H
+#define RDMA_COMP_H
+
+/* x86 */
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 0x1234
+#endif
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#ifdef ROCE_KNL_DT
+#include <linux/compiler_types.h>
+#endif
+
+#include "hinic5_crm.h"
+#include "hinic5_cqm.h"
+#include "hinic5_rdma.h"
+
+#include "roce_gid.h"
+#include "roce_npu_cmd_defs.h"
+#include "roce.h"
+#include "roce_compat.h"
+
+#include "rdma_bitmap.h"
+#include "hmm_em_inner.h"
+#include "hmm_common.h"
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": [RDMA]" fmt
+#endif
+
+#define RDMA_DEFAULT_GID_SUBNET_PREFIX 0xFE80000000000000ULL
+
+#define RDMA_INVALID_GUID 0
+
+#define RDMA_SERVICE_TYPE_ROCE SERVICE_T_ROCE
+
+#define RDMA_BIT_SHIFT_1 1
+#define RDMA_BIT_SHIFT_2 2
+#define RDMA_BIT_SHIFT_4 4
+#define RDMA_BIT_SHIFT_8 8
+#define RDMA_BIT_SHIFT_16 16
+
+#define ROCE5_RDMARC_MIN_DEPTH 1
+#define ROCE5_RDMARC_MAX_DEPTH 512
+#define ROCE5_RDMARC_MIN_ENTRY 8 /* min entry aligned required by engine */
+#define ROCE5_RDMARC_MAX_ENTRY 128 /* max entry supported by engine */
+#define ROCE5_RDMARC_EXT_ENTRY 384 //384 /* ext tbl 12K. 12k/32 = 384 */
+
+#define ROCE5_RDMARC_GPA_H_SHIFT 40 /* high:24bit, 64-24= 40 */
+#define ROCE5_RDMARC_GPA_L_SHIFT 8 /* bit[39:8] */
+#define ROCE5_RDMARC_RRA_MAX_MASK 0x7 /* rra_max:3bit */
+#define ROCE5_RDMARC_EXT_ORDER_SHIFT 3
+
+extern u32 g_mtt_page_size;
+
+#define RDMA_EM_MIN_ORDER 2 /* rdma rc extend table at least 4 page */
+
+#define ROCE_MTT_PAGE_SIZE_4K 4096
+#define ROCE_MTT_PAGE_SIZE_64K (64 * 1024)
+#define ROCE_MTT_PAGE_SIZE_2M (2 * 1024 * 1024)
+#define ROCE_MTT_PAGE_SIZE_4K_SHIFT 12
+#define ROCE_MTT_PAGE_SIZE_64K_SHIFT 16
+#define ROCE_MTT_PAGE_SIZE_2M_SHIFT 21
+
+enum {
+ ROCE5_RDMA_MTT_PAGE_SIZE_4K = 0,
+ ROCE5_RDMA_MTT_PAGE_SIZE_64K = 1,
+ ROCE5_RDMA_MTT_PAGE_SIZE_2M = 2
+};
+
+enum {
+ ROCE5_RDMA_CMD_TIME_OUT_A = 30000,
+ ROCE5_RDMA_CMD_TIME_OUT_B = 40000,
+ ROCE5_RDMA_CMD_TIME_OUT_C = 50000
+};
+
+/**
+ * @brief struct rdma_comp_resource
+ * @details RDMA component resource structure, used to store RDMA component of related resources
+ */
+struct rdma_comp_resource {
+ struct mutex mutex; /**< gid_entry mutex used by */
+ __be64 node_guid; /**< and ibdev in of node_guid same as */
+ struct rdma_gid_entry *
+ *gid_table; /**< gid_entry in rdma component initialize when allocate memory */
+};
+
+/**
+ * @brief enum rdma_mw_type
+ * @details define an enum type, used to represent RDMA memory window of type
+ */
+enum rdma_mw_type { RDMA_MW_TYPE_1 = 1, RDMA_MW_TYPE_2 = 2 };
+
+/**
+ * @brief struct rdma_mw
+ * @details define a rdma_mw structure, used to represent a RDMA memory window
+ */
+struct rdma_mw {
+ struct mpt mpt;
+ u32 key; /**< mw corresponding to key */
+ u32 pdn; /**< mw bind of pdn */
+ enum rdma_mw_type type; /**< mw of type,type1,type2 */
+ int enabled; /**< mw of status */
+};
+
+struct rdma_comp_priv {
+ struct hmm_comp_priv hmm_priv;
+ struct rdma_comp_resource rdma_comp_res; /* gid & guid */
+ struct hmm_rdma rsvd_lkey;
+ struct hmm_rdma fixed_mr;
+ struct rdma_service_cap rdma_cap;
+
+ struct rdma_bitmap pd_bitmap;
+ struct rdma_bitmap xrcd_bitmap;
+
+ struct hmm_buddy rdmarc_buddy;
+ struct hmm_em_table rdmarc_em_table;
+};
+
+/* Only V100 use */
+struct rdma_gid_update_inbuf {
+ roce_verbs_cmd_com_s com;
+ __be32 port;
+ __be32 rsvd;
+ struct rdma_gid_entry gid_entry;
+};
+
+struct rdma_gid_clear_inbuf {
+ __be32 port;
+ __be32 gid_num;
+};
+
+typedef struct tag_roce_clear_gid {
+ roce_verbs_cmd_com_s com;
+
+ u32 port;
+ u32 gid_num;
+} roce_cmd_clear_gid_s;
+
+/* for llt to set stub */
+void rdma_cleanup_pd_table(struct rdma_comp_priv *comp_priv);
+struct rdma_comp_priv *get_rdma_comp_priv(void *hwdev);
+int rdma_gid_entry_cmp(struct rdma_gid_entry *gid_tbl_entry,
+ struct rdma_gid_entry *gid_entry);
+int roce5_update_gid_mac(struct roce5_device *rdev, u32 port, int *index,
+ struct rdma_gid_entry *gid_entry);
+int roce5_update_gid(struct roce5_device *rdev, u32 port, u32 update_index,
+ struct rdma_gid_entry *gid_entry);
+int roce5_reset_gid_table(struct roce5_device *rdev, u32 port);
+int roce5_get_gid(struct roce5_device *rdev, u32 port, u32 gid_index,
+ struct rdma_gid_entry *gid);
+
+#endif //RDMA_COMP_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_gid.c b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_gid.c
new file mode 100644
index 000000000..b7919b409
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_gid.c
@@ -0,0 +1,489 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "comm_defs.h"
+#include "hinic5_hw.h"
+#include "rdma_comp.h"
+#include "roce.h"
+#include "roce_cqm_cmd.h"
+#include "roce_npu_cmd.h"
+#include "roce_mix.h"
+#include "roce_gid.h"
+#include "securec.h"
+#include "roce_npu_cmd_gid_defs.h"
+
+#define ROCE_GID_IFID_DW_INDEX \
+ 2 /* Interface ID starts at dword index 2 in u32 gid[4] (indices 0-1: subnet_prefix, 2-3: interface_id) */
+
+static int roce5_uni_cmd_update_gid(struct roce5_device *rdev,
+ struct rdma_comp_priv *comp_priv,
+ struct rdma_gid_entry *new_gid_entry,
+ int port, int gid_index)
+{
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_update_gid_s *gid_update_inbuf = NULL;
+ int ret;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ comp_priv->hmm_priv.hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_update_gid_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_ERR("Failed to alloc cqm_cmd_inoutbuf, ret(%d)", ret);
+ return -ENOMEM;
+ }
+
+ gid_update_inbuf = (roce_uni_cmd_update_gid_s *)cqm_cmd_inbuf->buf;
+ *(u64 *)(&gid_update_inbuf->gid_attr.gid[0]) =
+ new_gid_entry->global.subnet_prefix;
+ *(u64 *)(&gid_update_inbuf->gid_attr.gid[ROCE_GID_IFID_DW_INDEX]) =
+ new_gid_entry->global.interface_id;
+ gid_update_inbuf->gid_attr.dw4.value =
+ cpu_to_be32(new_gid_entry->dw4.value);
+ gid_update_inbuf->gid_attr.dw5.value =
+ cpu_to_be32(new_gid_entry->hdr_len_value);
+ gid_update_inbuf->gid_attr.dw6.bs1.ctrl_val =
+ new_gid_entry->dw6_h.value;
+ gid_update_inbuf->gid_attr.dw6.bs1.smac_hi16 =
+ be16_to_cpu(*((u16 *)(&new_gid_entry->smac[0])));
+ gid_update_inbuf->gid_attr.dw6.value =
+ cpu_to_be32(gid_update_inbuf->gid_attr.dw6.value);
+ gid_update_inbuf->gid_attr.smac_lo32 =
+ *((u32 *)(&new_gid_entry->smac[2])); //4=lo32
+
+ gid_update_inbuf->com.index = cpu_to_be32((u32)gid_index);
+ gid_update_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_GID_BITMASK);
+ gid_update_inbuf->com.opt = cpu_to_be32((u32)port);
+ if (rdev->shadow != 0) {
+ gid_update_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_SHADOW_BITMASK);
+ gid_update_inbuf->com.dw3.bs.shadow_vfid =
+ cpu_to_be16(rdev->shadow_vfid);
+ gid_update_inbuf->gid_attr.dw10.shadow.shadow_vf_num =
+ rdev->shadow_vf_num;
+ gid_update_inbuf->gid_attr.dw10.value =
+ cpu_to_be32(gid_update_inbuf->gid_attr.dw10.value);
+ }
+
+ ROCE_PRINT_GID(rdev, new_gid_entry, "gid_index(0x%x)",
+ gid_update_inbuf->com.index);
+ ret = cqm5_send_cmd_box(comp_priv->hmm_priv.hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_UPDATE_GID, cqm_cmd_inbuf, NULL, NULL,
+ ROCE5_RDMA_CMD_TIME_OUT_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_ERR("Send cmd update_gid failed, ret(%d)", ret);
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(comp_priv->hmm_priv.hwdev, cqm_cmd_inbuf,
+ NULL);
+
+ return ret;
+}
+
+static int roce5_cmd_update_gid(struct roce5_device *rdev,
+ struct rdma_comp_priv *comp_priv,
+ struct rdma_gid_entry *new_gid_entry, int port,
+ int gid_index)
+{
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ struct rdma_gid_update_inbuf *gid_update_inbuf = NULL;
+ int ret;
+
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ return roce5_uni_cmd_update_gid(rdev, comp_priv, new_gid_entry,
+ port, gid_index);
+ }
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ comp_priv->hmm_priv.hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct rdma_gid_update_inbuf), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc cqm_cmd_inoutbuf, ret(%d)",
+ ret);
+ return -ENOMEM;
+ }
+
+ gid_update_inbuf = (struct rdma_gid_update_inbuf *)cqm_cmd_inbuf->buf;
+ gid_update_inbuf->port = cpu_to_be32((u32)port);
+ gid_update_inbuf->com.index = cpu_to_be32((u32)gid_index);
+ gid_update_inbuf->gid_entry.global.subnet_prefix =
+ new_gid_entry->global.subnet_prefix;
+ gid_update_inbuf->gid_entry.global.interface_id =
+ new_gid_entry->global.interface_id;
+ gid_update_inbuf->gid_entry.dw4.value =
+ cpu_to_be32(new_gid_entry->dw4.value);
+ gid_update_inbuf->gid_entry.dw6_h.value =
+ cpu_to_be16(new_gid_entry->dw6_h.value);
+ gid_update_inbuf->gid_entry.hdr_len_value =
+ cpu_to_be32(new_gid_entry->hdr_len_value);
+ gid_update_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_GID_BITMASK);
+
+ ret = memcpy_s(&gid_update_inbuf->gid_entry.smac[0], ETH_ALEN,
+ &new_gid_entry->smac[0], ETH_ALEN);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy_s smac.(ret:%d)", ret);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ROCE_PRINT_GID(rdev, new_gid_entry, "gid_index(0x%x) ",
+ gid_update_inbuf->com.index);
+ ret = cqm5_send_cmd_box(comp_priv->hmm_priv.hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_UPDATE_GID, cqm_cmd_inbuf, NULL, NULL,
+ ROCE5_RDMA_CMD_TIME_OUT_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Send cmd update_gid failed, ret(%d)", ret);
+ ret = -1;
+ }
+
+err:
+ roce5_cqm5_cmd_free_inoutbuf(comp_priv->hmm_priv.hwdev, cqm_cmd_inbuf,
+ NULL);
+
+ return ret;
+}
+
+int rdma_gid_entry_cmp(struct rdma_gid_entry *gid_tbl_entry,
+ struct rdma_gid_entry *gid_entry)
+{
+ struct rdma_gid_entry entry1;
+ struct rdma_gid_entry entry2;
+ int ret;
+
+ ret = memcpy_s(&entry1, sizeof(struct rdma_gid_entry), gid_tbl_entry,
+ sizeof(struct rdma_gid_entry));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy entry1.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = memcpy_s(&entry2, sizeof(struct rdma_gid_entry), gid_entry,
+ sizeof(struct rdma_gid_entry));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy entry2.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ /* compare ip+vlan, compare after clear smac */
+ ret = memset_s((void *)entry1.smac, sizeof(entry1.smac), 0,
+ sizeof(entry1.smac));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset entry1 smac.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = memset_s((void *)entry2.smac, sizeof(entry2.smac), 0,
+ sizeof(entry2.smac));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset entry2.smac.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ return memcmp((void *)&entry1, (void *)&entry2,
+ sizeof(struct rdma_gid_entry));
+}
+
+static int roce5_uni_cmd_reset_gid(struct roce5_device *rdev,
+ struct rdma_comp_priv *comp_priv, u32 port,
+ u32 gid_num)
+{
+ int ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_clear_gid_s *gid_clear_inbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ comp_priv->hmm_priv.hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_clear_gid_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_ERR("Failed to alloc cqm_cmd_inoutbuf, ret(%d)", ret);
+ return -ENOMEM;
+ }
+
+ gid_clear_inbuf = (roce_uni_cmd_clear_gid_s *)cqm_cmd_inbuf->buf;
+ gid_clear_inbuf->gid_clear.gid_num = cpu_to_be32(gid_num);
+ gid_clear_inbuf->com.index = 0;
+ gid_clear_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_GID_BITMASK);
+ gid_clear_inbuf->com.opt = cpu_to_be32((u32)port);
+
+ if (rdev->shadow != 0) {
+ gid_clear_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_SHADOW_BITMASK);
+ gid_clear_inbuf->com.dw3.bs.shadow_vfid =
+ cpu_to_be16(rdev->shadow_vfid);
+ gid_clear_inbuf->gid_clear.dw1.shadow.shadow_vf_num =
+ rdev->shadow_vf_num;
+ gid_clear_inbuf->gid_clear.dw1.value =
+ cpu_to_be32(gid_clear_inbuf->gid_clear.dw1.value);
+ }
+
+ ret = cqm5_send_cmd_box(comp_priv->hmm_priv.hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_CLEAR_GID, cqm_cmd_inbuf, NULL, NULL,
+ ROCE5_RDMA_CMD_TIME_OUT_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_ERR("Send cmd clear_gid failed, ret(%d)", ret);
+ ret = -1;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(comp_priv->hmm_priv.hwdev, cqm_cmd_inbuf,
+ NULL);
+
+ return ret;
+}
+
+static int roce5_cmd_reset_gid(struct roce5_device *rdev,
+ struct rdma_comp_priv *comp_priv, u32 port,
+ u32 gid_num)
+{
+ int ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_cmd_clear_gid_s *gid_clear_inbuf = NULL;
+
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ return roce5_uni_cmd_reset_gid(rdev, comp_priv, port, gid_num);
+ }
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(comp_priv->hmm_priv.hwdev,
+ &cqm_cmd_inbuf,
+ (u16)sizeof(roce_cmd_clear_gid_s),
+ NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc cqm_cmd_inoutbuf, ret(%d)",
+ ret);
+ return -ENOMEM;
+ }
+
+ gid_clear_inbuf = (roce_cmd_clear_gid_s *)cqm_cmd_inbuf->buf;
+ gid_clear_inbuf->port = cpu_to_be32(port);
+ gid_clear_inbuf->gid_num = cpu_to_be32(gid_num);
+ gid_clear_inbuf->com.index = 0;
+ gid_clear_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_GID_BITMASK);
+
+ ret = cqm5_send_cmd_box(comp_priv->hmm_priv.hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_CLEAR_GID, cqm_cmd_inbuf, NULL, NULL,
+ ROCE5_RDMA_CMD_TIME_OUT_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Send cmd clear_gid failed, ret(%d)", ret);
+ ret = -1;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(comp_priv->hmm_priv.hwdev, cqm_cmd_inbuf,
+ NULL);
+
+ return ret;
+}
+
+int roce5_update_gid_mac(struct roce5_device *rdev, u32 port, int *index,
+ struct rdma_gid_entry *gid_entry)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+ struct rdma_gid_entry **gid_table = NULL;
+ u32 gid_index = 0;
+ int update_index =
+ -1; /* -1 is initvalue, indicating no need to update */
+ int ret = 0;
+ if ((rdev->hwdev == NULL) || (gid_entry == NULL)) {
+ ROCE_ERR("Hwdev or gid_tbl is null");
+ return -EINVAL;
+ }
+ comp_priv = get_rdma_comp_priv(rdev->hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return -EINVAL;
+ }
+ /* port num index from zero */
+ if (port >= comp_priv->rdma_cap.num_ports) {
+ ROCE_ERR("Input port(%d) is invalid", port);
+ return -EINVAL;
+ }
+ /* invalid gid cause of with the head fe80:: of IPV6 */
+ if (cpu_to_be64(gid_entry->global.subnet_prefix) ==
+ RDMA_DEFAULT_GID_SUBNET_PREFIX) {
+ return 0;
+ }
+ gid_table = comp_priv->rdma_comp_res.gid_table;
+ mutex_lock(&comp_priv->rdma_comp_res.mutex);
+ /* loop all gid, ensure all gid cleared not exist */
+ for (gid_index = 1; gid_index < comp_priv->rdma_cap.max_gid_per_port;
+ gid_index++) {
+ if (rdma_gid_entry_cmp(&gid_table[port][gid_index],
+ gid_entry) == 0) {
+ update_index = (int)gid_index;
+ break;
+ }
+ }
+
+ if (update_index > 0) {
+ ret = roce5_cmd_update_gid(rdev, comp_priv, gid_entry,
+ (int)port, update_index);
+ if (ret != 0) {
+ ROCE_ERR("Update gid tbl failed, ret(%d)", ret);
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return ret;
+ }
+ /* update gid table after CMDQ */
+ ret = memcpy_s((void *)&gid_table[port][update_index],
+ sizeof(*gid_entry), (void *)gid_entry,
+ sizeof(*gid_entry));
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to memcpy gid_entry to gid_table.(ret:%d)",
+ ret);
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return (-ENOMEM);
+ }
+
+ *index = update_index;
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return 0;
+ }
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return 0;
+}
+
+int roce5_update_gid(struct roce5_device *rdev, u32 port, u32 update_index,
+ struct rdma_gid_entry *gid_entry)
+{
+ int ret = 0;
+ u32 port_num = 0;
+ struct rdma_comp_priv *comp_priv = NULL;
+ struct rdma_gid_entry **gid_table = NULL;
+
+ if ((rdev->hwdev == NULL) || (gid_entry == NULL)) {
+ ROCE_ERR("Hwdev or gid_tbl is null");
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(rdev->hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return -EINVAL;
+ }
+
+ gid_table = comp_priv->rdma_comp_res.gid_table;
+
+ /* port start from zero */
+ port_num = comp_priv->rdma_cap.num_ports;
+ if (port >= port_num) {
+ ROCE_DEV_ERR(rdev, "Input port(%d) is invalid", port);
+ return -EINVAL;
+ }
+
+ mutex_lock(&comp_priv->rdma_comp_res.mutex);
+ ret = roce5_cmd_update_gid(rdev, comp_priv, gid_entry, (int)port,
+ (int)update_index);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Rdma_update_gid failed");
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return ret;
+ }
+
+ ret = memcpy_s((void *)&gid_table[port][update_index],
+ sizeof(*gid_entry), (void *)gid_entry,
+ sizeof(*gid_entry));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy gid_entry.(ret:%d)", ret);
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return -ENOMEM;
+ }
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+
+ return 0;
+}
+
+int roce5_reset_gid_table(struct roce5_device *rdev, u32 port)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+ struct rdma_gid_entry **gid_table = NULL;
+ int ret = 0;
+ u32 gids_per_port = 0;
+
+ if (rdev->hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(rdev->hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return -EINVAL;
+ }
+
+ gid_table = comp_priv->rdma_comp_res.gid_table;
+ if (gid_table == NULL) {
+ ROCE_ERR("Gid_table is null");
+ return -EINVAL;
+ }
+
+ gids_per_port = comp_priv->rdma_cap.max_gid_per_port;
+
+ if (gids_per_port == 0) {
+ ROCE_ERR("Gids_per_port(%d) is invalid", gids_per_port);
+ return -EINVAL;
+ }
+
+ ret = memset_s(&gid_table[port][0],
+ gids_per_port * sizeof(struct rdma_gid_entry), 0,
+ gids_per_port * sizeof(struct rdma_gid_entry));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset gid_table.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_cmd_reset_gid(rdev, comp_priv, port, gids_per_port);
+ if (ret != 0) {
+ ROCE_ERR("Reset gid table failed, gid_num(%d), ret(%d)",
+ gids_per_port, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce5_get_gid(struct roce5_device *rdev, u32 port, u32 gid_index,
+ struct rdma_gid_entry *gid)
+{
+ struct rdma_service_cap *rdma_cap = NULL;
+ struct rdma_comp_priv *comp_priv = NULL;
+ int ret;
+
+ if (rdev->hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return -EINVAL;
+ }
+
+ if (gid == NULL) {
+ ROCE_ERR("Gid is null");
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(rdev->hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return -EINVAL;
+ }
+
+ rdma_cap = &comp_priv->rdma_cap;
+ if (port < 1 || port > rdma_cap->num_ports) {
+ ROCE_ERR("Port(%d) invalid", port);
+ return -EINVAL;
+ }
+
+ if (gid_index >= rdma_cap->max_gid_per_port) {
+ ROCE_ERR("gid_index(%d) invalid", gid_index);
+ return -EINVAL;
+ }
+
+ ret = memcpy_s(
+ (void *)gid, sizeof(*gid),
+ (void *)&comp_priv->rdma_comp_res.gid_table[port - 1][gid_index],
+ sizeof(*gid));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dmac.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_init.c b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_init.c
new file mode 100644
index 000000000..ca5e88aff
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_init.c
@@ -0,0 +1,443 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic5_hw.h"
+#include "rdma_comp.h"
+#include "roce_infra.h"
+#include "hinic5_hmm.h"
+#include "securec.h"
+
+#define ROCE_MAX_RDMA_RC_EXTEND 384 /* 12K */
+
+static int rdma_init_pd_table(struct rdma_comp_priv *comp_priv)
+{
+ int ret = 0;
+ u32 num = 0;
+ u32 reserved_bot = 0;
+
+ num = comp_priv->rdma_cap.num_pds;
+ reserved_bot = comp_priv->rdma_cap.reserved_pds;
+
+ ret = rdma_bitmap_init(&comp_priv->pd_bitmap, num, num - 1,
+ reserved_bot, 0);
+ if (ret != 0) {
+ ROCE_ERR("Can't initialize pd's bitmap, ret(%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rdma_cleanup_gid_table(struct rdma_comp_priv *comp_priv)
+{
+ struct rdma_gid_entry **gid_table = NULL;
+ int i = 0;
+ int port_num = 0;
+
+ gid_table = comp_priv->rdma_comp_res.gid_table;
+ if (gid_table == NULL) {
+ ROCE_ERR("Gid_table is null");
+ return;
+ }
+
+ port_num = (int)comp_priv->rdma_cap.num_ports;
+ for (i = 0; i < port_num; i++) {
+ if (gid_table[i]) {
+ kfree(gid_table[i]);
+ gid_table[i] = NULL;
+ }
+ }
+
+ kfree(gid_table);
+ comp_priv->rdma_comp_res.gid_table = NULL;
+
+ return;
+}
+
+static int roce5_get_gid_nums(struct rdma_comp_priv *comp_priv)
+{
+ struct hinic5_hwdev *dev = comp_priv->hmm_priv.hwdev;
+ struct service_cap *cap = &(dev->cfg_mgmt->svc_cap);
+ struct dev_roce_svc_own_cap *roce_cap =
+ &(cap->rdma_cap.dev_rdma_cap.roce_own_cap);
+
+ /* 23v100 and earlier generations: The configuration file does not contain max gid. */
+ return (roce_cap->max_gid != 0 ? roce_cap->max_gid :
+ comp_priv->rdma_cap.max_gid_per_port);
+}
+
+static int rdma_init_gid_table(struct rdma_comp_priv *comp_priv)
+{
+ struct rdma_gid_entry **gid_table = NULL;
+ u32 i = 0;
+ u32 port_num = 0;
+ u32 gids_per_port = 0;
+
+ port_num = comp_priv->rdma_cap.num_ports;
+ gids_per_port = comp_priv->rdma_cap.max_gid_per_port;
+
+ if ((port_num == 0) || (gids_per_port == 0)) {
+ ROCE_ERR(
+ "Alloc memory for gid_tbl failed, port_num(%d), gids_per_ports(%d)",
+ port_num, gids_per_port);
+ return -EINVAL;
+ }
+
+ gid_table = (struct rdma_gid_entry **)kzalloc(
+ port_num * sizeof(struct rdma_gid_entry *), GFP_KERNEL);
+ if (gid_table == NULL) {
+ ROCE_ERR(
+ "Alloc memory for gid_tbl failed, ret(%d), port_num(%d)",
+ -ENOMEM, port_num);
+ return -ENOMEM;
+ }
+
+ comp_priv->rdma_comp_res.gid_table = gid_table;
+
+ for (i = 0; i < port_num; i++) {
+ gid_table[i] = (struct rdma_gid_entry *)kzalloc(
+ gids_per_port * sizeof(struct rdma_gid_entry),
+ GFP_KERNEL);
+ if (gid_table[i] == NULL) {
+ ROCE_ERR(
+ "Alloc memory for gid_tbl[%d] failed, ret(%d), gids_per_ports(%d)",
+ i, -ENOMEM, gids_per_port);
+ goto err_out;
+ }
+ }
+ return 0;
+err_out:
+ for (i = 0; i < port_num; i++) {
+ if (gid_table[i]) {
+ kfree(gid_table[i]);
+ gid_table[i] = NULL;
+ }
+ }
+ kfree(gid_table);
+ comp_priv->rdma_comp_res.gid_table = NULL;
+
+ return -ENOMEM;
+}
+
+static int rdma_init_xrcd_table(struct rdma_comp_priv *comp_priv)
+{
+ int ret = 0;
+ u32 num = 0;
+ u32 reserved_bot = 0;
+
+ num = comp_priv->rdma_cap.max_xrcds;
+ reserved_bot = comp_priv->rdma_cap.reserved_xrcds;
+
+ ret = rdma_bitmap_init(&comp_priv->xrcd_bitmap, num, num - 1,
+ reserved_bot, 0);
+ if (ret != 0) {
+ ROCE_ERR("Can't initialize xrcd's bitmap, ret(%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rdma_cleanup_xrcd_table(struct rdma_comp_priv *comp_priv)
+{
+ rdma_bitmap_cleanup(&comp_priv->xrcd_bitmap);
+}
+
+static int rdma_init_rdmarc_table(struct rdma_comp_priv *comp_priv)
+{
+ int ret = 0;
+ u32 i = 0;
+ u32 max_order = 0; /* rdmarc buddy max priority num */
+ u32 qp_num = 0;
+ u32 rdmarc_per_qp = 0; /* rdmarc num per qp */
+ u32 rdmarc_size = 0;
+ u32 log_rdmarc_per_seg = 0; /* min num of entry, 2^log_rdmarc_per_seg */
+ u32 rdmarc_pow_of_two = 0;
+
+ qp_num = comp_priv->rdma_cap.dev_rdma_cap.roce_own_cap.max_qps;
+ rdmarc_per_qp =
+ comp_priv->rdma_cap.dev_rdma_cap.roce_own_cap.max_qp_dest_rdma +
+ ROCE_MAX_RDMA_RC_EXTEND;
+ rdmarc_size =
+ comp_priv->rdma_cap.dev_rdma_cap.roce_own_cap.rdmarc_entry_sz;
+ log_rdmarc_per_seg = comp_priv->rdma_cap.log_rdmarc_seg;
+ for (i = 1; i < qp_num * rdmarc_per_qp; i <<= 1) {
+ max_order++;
+ }
+
+ max_order = (max_order > log_rdmarc_per_seg) ?
+ (max_order - log_rdmarc_per_seg) :
+ 0;
+
+ ret = hmm_buddy_init(&comp_priv->rdmarc_buddy, max_order);
+ if (ret != 0) {
+ ROCE_ERR("Initialize rdmarc's buddy failed, ret(%d)", -ENOMEM);
+ return -ENOMEM;
+ }
+ rdmarc_pow_of_two =
+ roce_roundup_pow_of_two((u32)(qp_num * rdmarc_per_qp));
+ ret = hmm_em_init_table(comp_priv->hmm_priv.dev,
+ &comp_priv->rdmarc_em_table, rdmarc_size,
+ rdmarc_pow_of_two, 0, RDMA_EM_MIN_ORDER);
+ if (ret != 0) {
+ ROCE_ERR("Initialize rdmarc's em_table failed, ret(%d)", ret);
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ hmm_buddy_cleanup(&comp_priv->rdmarc_buddy);
+
+ return -ENOMEM;
+}
+
+static int roce5_rdma_init_pd_table(struct rdma_comp_priv *comp_priv)
+{
+ int ret = 0;
+ ret = rdma_init_pd_table(comp_priv);
+ if (ret != 0) {
+ ROCE_ERR("Initialize pd's table failed, ret(%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce5_rdma_init_mtt_table(struct rdma_comp_priv *comp_priv)
+{
+ int ret = 0;
+ ret = hmm_mtt_init((struct hmm_comp_priv *)(void *)comp_priv);
+ if (ret != 0) {
+ ROCE_ERR("Initialize mtt's table failed, ret(%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce5_rdma_init_bitmap(struct rdma_comp_priv *comp_priv)
+{
+ int ret;
+ ret = roce5_rdma_init_pd_table(comp_priv);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = roce5_rdma_init_mtt_table(comp_priv);
+ if (ret != 0) {
+ rdma_cleanup_pd_table(comp_priv);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce5_rdma_unit_bitmap(struct rdma_comp_priv *comp_priv)
+{
+ hmm_mtt_cleanup((struct hmm_comp_priv *)(void *)comp_priv);
+ rdma_cleanup_pd_table(comp_priv);
+}
+
+static int roce5_rdma_init_table(void *hwdev, struct rdma_comp_priv *comp_priv)
+{
+ int ret = 0;
+
+ ret = roce5_rdma_init_bitmap(comp_priv);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = rdma_init_gid_table(comp_priv);
+ if (ret != 0) {
+ ROCE_ERR("Initialize gid table failed, ret(%d)", ret);
+ goto err_init_gid_table;
+ }
+
+ ret = rdma_init_xrcd_table(comp_priv);
+ if (ret != 0) {
+ ROCE_ERR("Initialize xrcd's table failed, ret(%d)", ret);
+ goto err_init_xrcd;
+ }
+
+ ret = rdma_init_rdmarc_table(comp_priv);
+ if (ret != 0) {
+ ROCE_ERR("Initialize rdmarc's table failed, ret(%d)", ret);
+ goto err_init_rdmarc_table;
+ }
+
+ ROCE_INFO("Rdma init resource successful.");
+ return 0;
+
+err_init_rdmarc_table:
+ rdma_cleanup_xrcd_table(comp_priv);
+err_init_xrcd:
+ rdma_cleanup_gid_table(comp_priv);
+err_init_gid_table:
+ roce5_rdma_unit_bitmap(comp_priv);
+ return ret;
+}
+
+static void rdma_cleanup_rdmarc_table(struct rdma_comp_priv *comp_priv)
+{
+ hmm_em_cleanup_table(comp_priv->hmm_priv.dev,
+ &comp_priv->rdmarc_em_table);
+
+ hmm_buddy_cleanup(&comp_priv->rdmarc_buddy);
+
+ return;
+}
+
+static void roce5_rdma_unit_table(void *hwdev, struct rdma_comp_priv *comp_priv)
+{
+ if (hinic5_support_roce(hwdev, NULL)) {
+ rdma_cleanup_rdmarc_table(comp_priv);
+ rdma_cleanup_xrcd_table(comp_priv);
+ rdma_cleanup_gid_table(comp_priv);
+ }
+
+ roce5_rdma_unit_bitmap(comp_priv);
+}
+
+void roce5_rdma_cleanup_resource(void *hwdev)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if (hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return;
+ }
+
+ if (!hinic5_support_rdma(hwdev, NULL)) {
+ ROCE_ERR("Not support rdma service");
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return;
+ }
+
+ roce5_rdma_unit_table(hwdev, comp_priv);
+
+ kfree(comp_priv);
+
+ hinic5_unregister_service_adapter((void *)hwdev, SERVICE_T_ROCE);
+
+ ROCE_INFO("Rdma cleanup resource successful.");
+
+ return;
+}
+
+static int roce5_rdma_init_comp_priv(struct rdma_comp_priv *comp_priv,
+ void *hwdev,
+ struct rdma_service_cap *rdma_cap)
+{
+ int ret;
+
+ mutex_init(&comp_priv->rdma_comp_res.mutex);
+ comp_priv->hmm_priv.hwdev = hwdev;
+
+ comp_priv->hmm_priv.dev =
+ (struct device *)(((struct hinic5_hwdev *)hwdev)->dev_hdl);
+ if (comp_priv->hmm_priv.dev == NULL) {
+ ROCE_ERR("Failed to init, device is NULL.");
+ return -EINVAL;
+ }
+
+ ret = memcpy_s((void *)&comp_priv->rdma_cap,
+ sizeof(struct rdma_service_cap), (void *)rdma_cap,
+ sizeof(struct rdma_service_cap));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy rdma_cap.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ //to adapt hmm struct
+ comp_priv->hmm_priv.dev_cap.log_mtt = rdma_cap->log_mtt;
+ comp_priv->hmm_priv.dev_cap.num_mtts = rdma_cap->num_mtts;
+ comp_priv->hmm_priv.dev_cap.log_mtt_seg = rdma_cap->log_mtt_seg;
+ comp_priv->hmm_priv.dev_cap.mtt_entry_sz = rdma_cap->mtt_entry_sz;
+ comp_priv->hmm_priv.dev_cap.mpt_entry_sz = rdma_cap->mpt_entry_sz;
+ comp_priv->hmm_priv.dev_cap.dmtt_cl_start = rdma_cap->dmtt_cl_start;
+ comp_priv->hmm_priv.dev_cap.dmtt_cl_end = rdma_cap->dmtt_cl_end;
+ comp_priv->hmm_priv.dev_cap.dmtt_cl_sz = rdma_cap->dmtt_cl_sz;
+
+ switch (g_mtt_page_size) {
+ case ROCE5_RDMA_MTT_PAGE_SIZE_4K:
+ comp_priv->hmm_priv.mtt_page_size = ROCE_MTT_PAGE_SIZE_4K;
+ comp_priv->hmm_priv.mtt_page_shift =
+ ROCE_MTT_PAGE_SIZE_4K_SHIFT;
+ break;
+ case ROCE5_RDMA_MTT_PAGE_SIZE_64K:
+ comp_priv->hmm_priv.mtt_page_size = ROCE_MTT_PAGE_SIZE_64K;
+ comp_priv->hmm_priv.mtt_page_shift =
+ ROCE_MTT_PAGE_SIZE_64K_SHIFT;
+ break;
+ case ROCE5_RDMA_MTT_PAGE_SIZE_2M:
+ comp_priv->hmm_priv.mtt_page_size = ROCE_MTT_PAGE_SIZE_2M;
+ comp_priv->hmm_priv.mtt_page_shift =
+ ROCE_MTT_PAGE_SIZE_2M_SHIFT;
+ break;
+ default:
+ comp_priv->hmm_priv.mtt_page_size = ROCE_MTT_PAGE_SIZE_4K;
+ comp_priv->hmm_priv.mtt_page_shift =
+ ROCE_MTT_PAGE_SIZE_4K_SHIFT;
+ break;
+ }
+
+ /* Recalculate the gid num. */
+ comp_priv->rdma_cap.max_gid_per_port =
+ (u32)roce5_get_gid_nums(comp_priv);
+
+ ret = roce5_rdma_init_table(hwdev, comp_priv);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = hinic5_register_service_adapter((void *)hwdev, (void *)comp_priv,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ roce5_rdma_unit_table(hwdev, comp_priv);
+ ROCE_ERR("put rdma_comp_res failed, ret(%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce5_rdma_init_resource(void *hwdev)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+ struct rdma_service_cap rdma_cap;
+ int ret = 0;
+
+ if (hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return -EINVAL;
+ }
+
+ if (hinic5_support_rdma(hwdev, &rdma_cap) == false) {
+ ROCE_INFO("Neither ROCE nor IWARP");
+ return 0;
+ }
+
+ comp_priv = (struct rdma_comp_priv *)kzalloc(
+ sizeof(struct rdma_comp_priv), GFP_KERNEL);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Alloc memory for comp_priv failed, ret(%d)", -ENOMEM);
+ return -ENOMEM;
+ }
+
+ ret = roce5_rdma_init_comp_priv(comp_priv, hwdev, &rdma_cap);
+ if (ret != 0) {
+ kfree(comp_priv);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_mw_mr.c b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_mw_mr.c
new file mode 100644
index 000000000..aa252e2db
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_mw_mr.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic5_hw.h"
+#include "rdma_comp.h"
+#include "roce_cqm_cmd.h"
+#include "hmm_common.h"
+#include "securec.h"
+
+#include "roce.h"
+#include "roce_mix.h"
+#include "roce_main_extension.h"
+#include "roce_compat.h"
+#include "roce_mr.h"
+#include "rdma_comp_mw_mr.h"
+
+static int rdma_mpt_alloc_rsvd_lkey(struct rdma_comp_priv *comp_priv,
+ struct mpt *mpt)
+{
+ u32 mpt_entry_size = 0;
+
+ mpt_entry_size = comp_priv->hmm_priv.dev_cap.mpt_entry_sz;
+
+ /* call cqm interface allocate mpt, and mpt_index and vaddr save in rdma_mpt structure */
+ mpt->mpt_object = (void *)cqm5_object_qpc_mpt_create(
+ comp_priv->hmm_priv.hwdev, RDMA_SERVICE_TYPE_ROCE,
+ CQM_OBJECT_MPT, mpt_entry_size, mpt, mpt->mpt_index, 0, 0);
+ if (mpt->mpt_object == NULL) {
+ ROCE_ERR("Alloc mpt_object failed, err(%d)", -ENOMEM);
+ return -ENOMEM;
+ }
+
+ mpt->vaddr = (void *)((cqm_qpc_mpt_s *)mpt->mpt_object)->vaddr;
+
+ return 0;
+}
+
+int roce5_rdma_init_rsvd_lkey(struct roce5_device *rdev)
+{
+ struct hmm_rdma *mr = NULL;
+ struct rdma_service_cap *rdma_cap = NULL;
+ struct rdma_comp_priv *comp_priv = NULL;
+ int ret = 0;
+
+ if (rdev == NULL) {
+ ROCE_ERR("rdev is null");
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(rdev->hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return -EINVAL;
+ }
+
+ rdma_cap = &comp_priv->rdma_cap;
+ mr = &comp_priv->rsvd_lkey;
+ mr->mpt.mpt_index = rdma_cap->reserved_lkey >> MR_KEY_LEFT_SHIFT_OFS;
+ if (mr->mpt.mpt_index >= rdma_cap->reserved_mrws) {
+ ROCE_ERR("Cfg err, reserved_lkey(0x%x), reserved_mrws(0x%x)",
+ rdma_cap->reserved_lkey, rdma_cap->reserved_mrws);
+ return -EINVAL;
+ }
+ /* Alloc MPT */
+ ret = rdma_mpt_alloc_rsvd_lkey(comp_priv, &mr->mpt);
+ if (ret != 0) {
+ ROCE_ERR("Rdma_mpt_alloc_rsvd_lkey failed, ret(%d)", ret);
+ return ret;
+ }
+ mr->mtt.mtt_layers = 0;
+ mr->iova = 0;
+ mr->size = ~0ULL;
+ mr->key = comp_priv->rdma_cap.reserved_lkey;
+ mr->type = roce5_mr_type2hmm(RDMA_RSVD_LKEY);
+ mr->access = RDMA_IB_ACCESS_LOCAL_WRITE;
+ /* Enable MPT */
+ ret = hmm_rdma_enable_mpt(rdev->lld_dev, rdev->hwdev, mr,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_ERR("Rdma_enable_mr_mpt failed, ret(%d)", ret);
+ goto err_out;
+ }
+ return 0;
+err_out:
+ hmm_mpt_free(rdev->hwdev, &mr->mpt);
+ return ret;
+}
+
+void roce5_rdma_free_rsvd_lkey(struct roce5_device *rdev)
+{
+ struct hmm_rdma *mr = NULL;
+ struct rdma_comp_priv *comp_priv = NULL;
+ int ret = 0;
+
+ if (rdev == NULL) {
+ ROCE_ERR("rdev is null");
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(rdev->hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return;
+ }
+
+ mr = &comp_priv->rsvd_lkey;
+ ret = hmm_rdma_disable_mpt(rdev->lld_dev, rdev->hwdev, mr,
+ RDMA_SERVICE_TYPE_ROCE, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_ERR("Disable mpt of mr failed, ret(%d)", ret);
+ return;
+ }
+
+ hmm_mpt_free(rdev->hwdev, &mr->mpt);
+
+ return;
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_mw_mr.h b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_mw_mr.h
new file mode 100644
index 000000000..1e9c1132d
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_mw_mr.h
@@ -0,0 +1,12 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef RDMA_COMP_MW_MR_H
+#define RDMA_COMP_MW_MR_H
+
+#include "roce.h"
+
+int roce5_rdma_init_rsvd_lkey(struct roce5_device *rdev);
+void roce5_rdma_free_rsvd_lkey(struct roce5_device *rdev);
+
+#endif /* RDMA_COMP_MW_MR_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_pd.c b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_pd.c
new file mode 100644
index 000000000..ee3486e97
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_pd.c
@@ -0,0 +1,51 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic5_hw.h"
+#include "rdma_comp.h"
+
+int roce5_rdma_pd_alloc(void *hwdev, u32 *pdn)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if ((hwdev == NULL) || (pdn == NULL)) {
+ ROCE_ERR("Hwdev or pdn is null");
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return -EINVAL;
+ }
+
+ *pdn = rdma_bitmap_alloc(&comp_priv->pd_bitmap);
+ if (*pdn == RDMA_INVALID_INDEX) {
+ ROCE_ERR("Can't get valid pdn, err(%d)", -ENOMEM);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void roce5_rdma_pd_free(void *hwdev, u32 pdn)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if (hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return;
+ }
+
+ rdma_bitmap_free(&comp_priv->pd_bitmap, pdn);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_res.c b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_res.c
new file mode 100644
index 000000000..d1265e54e
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/rdma_comp_res.c
@@ -0,0 +1,140 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic5_hw.h"
+#include "rdma_comp.h"
+#include "hmm_em_inner.h"
+#include "hmm_buddy.h"
+
+static int roce5_rdma_rdmarc_alloc_check(struct rdma_comp_priv **comp_priv,
+ void *hwdev,
+ const struct rdma_rdmarc *rdmarc,
+ u32 *log_rdmarc_per_seg, u32 num)
+{
+ if ((hwdev == NULL) || (rdmarc == NULL)) {
+ ROCE_ERR("Hwdev or rdmarc is null");
+ return -EINVAL;
+ }
+
+ *comp_priv = get_rdma_comp_priv(hwdev);
+ if (*comp_priv == NULL || (*comp_priv)->hmm_priv.dev == NULL) {
+ ROCE_ERR("Comp_priv(%d) or PCI device is NULL.",
+ !!(*comp_priv));
+ return -EINVAL;
+ }
+
+ *log_rdmarc_per_seg = (*comp_priv)->rdma_cap.log_rdmarc_seg;
+
+ if ((num < ROCE5_RDMARC_MIN_DEPTH) || (num > ROCE5_RDMARC_MAX_DEPTH)) {
+ ROCE_ERR("Num is invalid, ret(%d)", -EINVAL);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void roce5_rdma_rdmarc_order_set(struct rdma_rdmarc *rdmarc, u32 order,
+ u32 ext_order, u32 log_rdmarc_per_seg)
+{
+ rdmarc->order = order;
+ rdmarc->ext_order = ext_order + log_rdmarc_per_seg;
+ return;
+}
+
+int roce5_rdma_rdmarc_alloc(void *hwdev, u32 num, struct rdma_rdmarc *rdmarc)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+ int ret = 0;
+ u32 i = 0;
+ u32 order = 0;
+ u32 ext_order = 0;
+ u32 ext_num = num + ROCE5_RDMARC_EXT_ENTRY;
+ u32 offset = 0;
+ void *vaddr = NULL;
+ u32 log_rdmarc_per_seg = 0;
+ u32 chip_num = (num < ROCE5_RDMARC_MIN_ENTRY) ? ROCE5_RDMARC_MIN_ENTRY :
+ num;
+ ret = roce5_rdma_rdmarc_alloc_check(&comp_priv, hwdev, rdmarc,
+ &log_rdmarc_per_seg, num);
+ if (ret != 0) {
+ return ret;
+ }
+ for (i = 1; i < chip_num; i <<= 1) {
+ order++;
+ }
+ for (i = 1; i < ext_num; i <<= 1) {
+ ext_order++;
+ }
+ ext_order = (ext_order > log_rdmarc_per_seg) ?
+ (ext_order - log_rdmarc_per_seg) :
+ 0;
+ roce5_rdma_rdmarc_order_set(rdmarc, order, ext_order,
+ log_rdmarc_per_seg);
+ offset = hmm_buddy_alloc(&comp_priv->rdmarc_buddy, ext_order);
+ if (offset == RDMA_INVALID_INDEX) {
+ ROCE_ERR("Alloc rdmarc index failed, ret(%d)", -ENOMEM);
+ return -ENOMEM;
+ }
+ rdmarc->offset = offset << log_rdmarc_per_seg;
+
+ ret = hmm_em_table_get_range(
+ comp_priv->hmm_priv.dev, &comp_priv->rdmarc_em_table,
+ rdmarc->offset, rdmarc->offset + (1U << rdmarc->ext_order) - 1);
+ if (ret != 0) {
+ ROCE_ERR("Alloc rdmarc entry failed, ret(%d)", -ENOMEM);
+ goto err_table_get;
+ }
+ vaddr = hmm_em_table_find(&comp_priv->rdmarc_em_table, rdmarc->offset,
+ &rdmarc->dma_addr);
+ if (vaddr == NULL) {
+ ret = -ENOMEM;
+ ROCE_ERR("Can't find va and pa of rdmarc entry, ret(%d)",
+ -ENOMEM);
+ goto err_rdmarc_find;
+ }
+ rdmarc->vaddr = vaddr;
+ return 0;
+
+err_rdmarc_find:
+ hmm_em_table_put_range(comp_priv->hmm_priv.dev,
+ &comp_priv->rdmarc_em_table, rdmarc->offset,
+ rdmarc->offset + (1U << rdmarc->ext_order) - 1);
+err_table_get:
+ hmm_buddy_free(&comp_priv->rdmarc_buddy, offset, ext_order);
+ return ret;
+}
+
+void roce5_rdma_rdmarc_free(void *hwdev, struct rdma_rdmarc *rdmarc)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+ u32 order = 0;
+ u32 offset = 0;
+ u32 log_rdmarc_per_seg = 0;
+
+ if ((hwdev == NULL) || (rdmarc == NULL)) {
+ ROCE_ERR("Hwdev or rdmarc is null");
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL || comp_priv->hmm_priv.dev == NULL) {
+ ROCE_ERR("Comp_priv(%d) or comp_priv->hmm_priv.dev is NULL",
+ !!comp_priv);
+ return;
+ }
+
+ hmm_em_table_put_range(comp_priv->hmm_priv.dev,
+ &comp_priv->rdmarc_em_table, rdmarc->offset,
+ rdmarc->offset + (1U << rdmarc->ext_order) - 1);
+
+ log_rdmarc_per_seg = comp_priv->rdma_cap.log_rdmarc_seg;
+
+ order = rdmarc->ext_order - log_rdmarc_per_seg;
+ offset = rdmarc->offset >> log_rdmarc_per_seg;
+
+ hmm_buddy_free(&comp_priv->rdmarc_buddy, offset, order);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_com.h b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_com.h
new file mode 100644
index 000000000..f268757a4
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_com.h
@@ -0,0 +1,78 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_COM_H
+#define ROCE_COM_H
+
+#include "roce_cfg_format.h"
+
+/* kernel mode basic capability negotiation support macro */
+#define ROCE5_SUPPORT_IB_FEATURE(rdev, feature) \
+ ((rdev)->cfg_info.feature_cap.roce_kernel_ability & \
+ (ROCE_SUPPORT_IB_##feature))
+
+#define ROCE5_SUPPORT_IB_CMD_RESIZE_CQ_MSG_V2(rdev) \
+ ROCE5_SUPPORT_IB_FEATURE(rdev, CMD_RESIZE_CQ_MSG_V2)
+#define ROCE5_SUPPORT_IB_CMD_QUERY_QP_MSG_V2(rdev) \
+ ROCE5_SUPPORT_IB_FEATURE(rdev, CMD_QUERY_QP_MSG_V2)
+#define ROCE5_SUPPORT_IB_CMD_MODIFY_SRQ_MSG_V2(rdev) \
+ ROCE5_SUPPORT_IB_FEATURE(rdev, CMD_MODIFY_SRQ_MSG_V2)
+#define ROCE5_SUPPORT_IB_CMD_DESTROY_SRQ_MSG_V2(rdev) \
+ ROCE5_SUPPORT_IB_FEATURE(rdev, CMD_DESTROY_SRQ_MSG_V2)
+
+/* kernel mode extended capability negotiation support macro */
+#define ROCE5_SUPPORT_FEATURE(rdev, feature) \
+ ((rdev)->cfg_info.feature_cap.roce_kernel_ext_ability & \
+ (ROCE_SUPPORT_##feature))
+
+#define ROCE5_SUPPORT_CQ_MODIFY_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, CQ_MODIFY_MSG_V2)
+#define ROCE5_SUPPORT_CQ_CHECK_DATA_STATE_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, CQ_CHECK_DATA_STATE_MSG_V2)
+#define ROCE5_SUPPORT_CQ_CACHE_OUT_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, CQ_CACHE_OUT_MSG_V2)
+#define ROCE5_SUPPORT_QP_SRQN_LB_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, QP_SRQN_LB_MSG_V2)
+#define ROCE5_SUPPORT_SET_PI_ON_CHIP_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, SET_PI_ON_CHIP_MSG_V2)
+#define ROCE5_SUPPORT_SQ_DB_TYPE_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, SQ_DB_TYPE_MSG_V2)
+#define ROCE5_SUPPORT_GET_QP_RX_PORT_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, GET_QP_RX_PORT_MSG_V2)
+#define ROCE5_SUPPORT_MODIFY_UDP_SRC_PORT_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, MODIFY_UDP_SRC_PORT_MSG_V2)
+#define ROCE5_SUPPORT_GET_QP_UDP_SRC_PORT_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, GET_QP_UDP_SRC_PORT_MSG_V2)
+#define ROCE5_SUPPORT_DFX_CMD_QUERY_MPT_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, DFX_CMD_QUERY_MPT_MSG_V2)
+#define ROCE5_SUPPORT_DFX_CMD_QUERY_GID_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, DFX_CMD_QUERY_GID_MSG_V2)
+#define ROCE5_SUPPORT_DFX_CMD_QUERY_PI_CI_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, DFX_CMD_QUERY_PI_CI_MSG_V2)
+#define ROCE5_SUPPORT_DFX_CMD_QUERY_CQ_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, DFX_CMD_QUERY_CQ_MSG_V2)
+#define ROCE5_SUPPORT_ALLOC_QPC_MSG_FEATURE(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, ALLOC_QPC_MSG_FEATURE)
+#define ROCE5_SUPPORT_GET_OQID_MSG_FEATURE(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, GET_OQID_MSG_FEATURE)
+#define ROCE5_SUPPORT_RETRY_LOAD_CQC_MSG_FEATURE(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, RETRY_LOAD_CQC_MSG_FEATURE)
+#define ROCE5_SUPPORT_SET_HASH_VALUE_MSG_V2(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, SET_HASH_VALUE_MSG_V2)
+#define ROCE5_SUPPORT_CC_GET_DCQCN_ENABLE(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, CC_GET_DCQCN_ENABLE)
+#define ROCE5_SUPPORT_CC_GET_LDCP_ENABLE(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, CC_GET_LDCP_ENABLE)
+#define ROCE5_SUPPORT_CC_GET_IPQCN_ENABLE(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, CC_GET_IPQCN_ENABLE)
+#define ROCE5_SUPPORT_CC_GET_USER_ALGO_ENABLE(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, CC_GET_USER_ALGO_ENABLE)
+#define ROCE5_SUPPORT_CC_PARAM_V1(rdev) ROCE5_SUPPORT_FEATURE(rdev, CC_PARAM_V1)
+#define ROCE5_SUPPORT_CC_PARAM_V2(rdev) ROCE5_SUPPORT_FEATURE(rdev, CC_PARAM_V2)
+#define ROCE5_SUPPORT_8K_MTU(rdev) ROCE5_SUPPORT_FEATURE(rdev, KERNEL_8K_MTU)
+#define ROCE5_SUPPORT_SML_MAC_TABLE(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, SML_MAC_TABLE)
+#define ROCE5_SUPPORT_SQ_DB_TYPE_21(rdev) \
+ ROCE5_SUPPORT_FEATURE(rdev, SQ_DB_TYPE_21)
+#endif /* ROCE_COM_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_mix.c b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_mix.c
new file mode 100644
index 000000000..a15e865ec
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_mix.c
@@ -0,0 +1,1594 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+#include <rdma/ib_mad.h>
+#include <rdma/ib_verbs.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "securec.h" /* Huawei secure functions; */
+
+#include "hinic5_crm.h"
+#include "hinic5_srv_nic.h"
+#include "hinic5_lld.h"
+
+#include "roce.h"
+#include "roce_compat.h"
+#include "roce_user.h"
+#include "roce_pd.h"
+#include "roce_qp.h"
+#include "roce_cmd.h"
+#include "roce_gid.h"
+#include "roce_netdev.h"
+#include "roce_main_extension.h"
+#include "roce_qp_extension.h"
+#include "roce_restore.h"
+#include "roce_infra.h"
+#include "roce_ctx_format.h"
+#include "roce_kernel_compat_gen.h"
+#include "roce5_gid_type.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+#include "roce_mix.h"
+
+uint8_t roce5_get_db_cos_from_vlan_pri(struct roce5_device *rdev,
+ uint8_t vlan_pri)
+{
+ uint8_t db_cos;
+ int ret;
+
+ ret = hinic5_get_cos_by_pri(rdev->hwdev, vlan_pri, &db_cos);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "ret:%d vlan_pri:%u", ret, vlan_pri);
+ db_cos = 0;
+ }
+
+ return db_cos;
+}
+
+struct net_device *roce5_ib_get_netdev(struct ib_device *ibdev, u32 port_num)
+{
+ struct roce5_device *rdev = NULL;
+ struct net_device *netdev = NULL;
+
+ if (ibdev == NULL) {
+ ROCE_ERR("Ibdev is null");
+ return NULL;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+
+#ifdef ROCE_BONDING_EN
+ netdev = roce5_bond_get_netdev(rdev);
+ if (netdev != NULL) {
+ return netdev;
+ }
+#endif
+
+ netdev = rdev->ndev;
+
+ dev_hold(netdev);
+
+ return netdev;
+}
+
+/* compatible version for kernel 5.10 and kernel 4.19 */
+struct net_device *roce5_ib_get_netdev_compat(struct ib_device *ibdev,
+ u8 port_num)
+{
+ return roce5_ib_get_netdev(ibdev, (u32)port_num);
+}
+
+static void roce5_parse_fw_version(struct roce5_device *rdev, u64 *fw_ver)
+{
+ int ret;
+ int i = 0;
+ struct hinic5_fw_version fw_version;
+ char *fw_str = (char *)fw_version.microcode_ver;
+ char *fw_temp = NULL;
+ u64 fw_verion[ROCE_FW_VERSION_LEN] = { 0 };
+
+ ret = hinic5_get_fw_version(rdev->hwdev, &fw_version,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_WARN("get fw version failed");
+ *fw_ver = ROCE_FW_VER;
+ return;
+ }
+ ROCE_INFO("fw ver:%s - %s - %s", fw_version.boot_ver,
+ fw_version.mgmt_ver, fw_version.microcode_ver);
+
+ while (((fw_temp = strsep(&fw_str, ".")) != NULL) &&
+ (i < ROCE_FW_VERSION_LEN)) {
+ ret = sscanf_s(fw_temp, "%llu", &fw_verion[i]);
+ if (ret != 1) {
+ ROCE_WARN("parse fw version failed ret(%d)", ret);
+ *fw_ver = ROCE_FW_VER;
+ return;
+ }
+
+ i++;
+ }
+
+ *fw_ver = (((fw_verion[0] & 0xffffffff)
+ << 32) | // 0 is fw_version array idx, 32 is offset
+ ((fw_verion[1] & 0xffff)
+ << 16) | // 1 is fw_version array idx, 16 is offset
+ ((fw_verion[2] & 0xff)
+ << 8) | // 2 is fw_version array idx, 8 is offset
+ (fw_verion[3] & 0xff)); // 3 is fw_version array idx
+}
+
+static void roce5_set_local_cap_flag(const struct rdma_service_cap *rdma_cap,
+ struct ib_device_attr *props)
+{
+ if (((rdma_cap->flags & RDMA_BMME_FLAG_LOCAL_INV) != 0) &&
+ ((rdma_cap->flags & RDMA_BMME_FLAG_REMOTE_INV) != 0) &&
+ ((rdma_cap->flags & RDMA_BMME_FLAG_FAST_REG_WR) != 0)) {
+ props->device_cap_flags = props->device_cap_flags |
+ IB_DEVICE_MEM_MGT_EXTENSIONS;
+ }
+}
+
+static void roce5_set_bmme_cap_flag(const struct rdma_service_cap *rdma_cap,
+ struct ib_device_attr *props)
+{
+ if ((rdma_cap->flags & RDMA_BMME_FLAG_TYPE_2_WIN) != 0) {
+ if ((rdma_cap->flags & RDMA_BMME_FLAG_WIN_TYPE_2B) != 0) {
+ props->device_cap_flags = props->device_cap_flags |
+ IB_DEVICE_MEM_WINDOW_TYPE_2B;
+ } else {
+ props->device_cap_flags = props->device_cap_flags |
+ IB_DEVICE_MEM_WINDOW_TYPE_2A;
+ }
+ }
+}
+
+static void roce5_query_device_props_set(struct roce5_device *rdev,
+ struct rdma_service_cap *rdma_cap,
+ struct ib_device_attr *props)
+{
+ if (rdev->lld_dev->dev_type == HINIC5_DEVICE_T_PCI) {
+ struct pci_dev *pdev =
+ container_of(rdev->dev, struct pci_dev, dev);
+ props->vendor_id = pdev->vendor;
+ props->vendor_part_id = pdev->device;
+ }
+ roce5_parse_fw_version(rdev, &props->fw_ver);
+ props->hw_ver = ROCE_HW_VER;
+
+ /* sys_image_guid equal GID */
+ props->sys_image_guid = rdev->ib_dev.node_guid;
+
+ props->max_mr_size = ~0ULL;
+ props->page_size_cap = rdma_cap->page_size_cap;
+ props->max_qp = (int)(rdma_cap->dev_rdma_cap.roce_own_cap.max_qps -
+ rdma_cap->reserved_qps);
+ props->max_qp_wr = (int)rdma_cap->dev_rdma_cap.roce_own_cap.max_wqes;
+ /* We should ensure sq's max size(max_sq_sg) as the max_sge */
+ props->max_send_sge = (int)rdma_cap->max_sq_sg;
+ props->max_recv_sge =
+ (int)rdma_cap->dev_rdma_cap.roce_own_cap.max_rq_sg;
+ props->max_cq = (int)(rdma_cap->dev_rdma_cap.roce_own_cap.max_cqs -
+ rdma_cap->reserved_cqs);
+ props->max_cqe = (int)rdma_cap->max_cqes;
+ props->max_mr = (int)(rdma_cap->dev_rdma_cap.roce_own_cap.max_mpts -
+ rdma_cap->reserved_mrws);
+ props->max_mw = props->max_mr;
+ props->max_pd = (int)(rdma_cap->num_pds - rdma_cap->reserved_pds);
+ props->max_qp_rd_atom =
+ (int)rdma_cap->dev_rdma_cap.roce_own_cap.max_qp_dest_rdma;
+ props->max_qp_init_rd_atom =
+ (int)rdma_cap->dev_rdma_cap.roce_own_cap.max_qp_init_rdma;
+ props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp;
+ props->max_srq =
+ (int)(rdma_cap->dev_rdma_cap.roce_own_cap.max_srqs -
+ rdma_cap->dev_rdma_cap.roce_own_cap.reserved_srqs);
+ props->max_srq_wr =
+ (int)rdma_cap->dev_rdma_cap.roce_own_cap.max_srq_wqes;
+ props->max_srq_sge =
+ (int)rdma_cap->dev_rdma_cap.roce_own_cap.max_srq_sge;
+ props->max_fast_reg_page_list_len = rdma_cap->max_frpl_len;
+ props->local_ca_ack_delay = (u8)rdma_cap->local_ca_ack_delay;
+ props->atomic_cap =
+ ((rdma_cap->flags & RDMA_DEV_CAP_FLAG_ATOMIC) != 0) ?
+ IB_ATOMIC_HCA :
+ IB_ATOMIC_NONE;
+ props->masked_atomic_cap = props->atomic_cap;
+ props->max_pkeys = (u16)rdma_cap->max_pkeys;
+ props->max_sge_rd = (int)rdma_cap->dev_rdma_cap.roce_own_cap.max_rq_sg;
+#if defined(IB_DEV_ATTR_HAVE_MAX_FMR)
+ props->max_fmr = props->max_map_per_fmr;
+#endif
+#if defined(IB_DEV_ATTR_HAVE_MAX_MAP_PER_FMR)
+ props->max_map_per_fmr = (int)rdma_cap->max_fmr_maps;
+#endif
+ props->max_ah = INT_MAX;
+ return;
+}
+/* ****************************************************************************
+ Prototype : roce5_query_device
+ Description : query device attribute
+ Input : struct ib_device *ibdev
+ struct ib_device_attr *props
+ struct ib_udata *uhw
+ Output : struct ib_device_attr *props
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
+ struct ib_udata *uhw)
+{
+ struct roce5_device *rdev = NULL;
+ struct rdma_service_cap *rdma_cap = NULL;
+ int ret;
+
+ if ((ibdev == NULL) || (props == NULL)) {
+ ROCE_ERR("Ibdev or props is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+
+ ret = memset_s(props, sizeof(*props), 0, sizeof(*props));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset props.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ rdma_cap = &rdev->rdma_cap;
+
+ props->device_cap_flags = IB_DEVICE_PORT_ACTIVE_EVENT |
+ IB_DEVICE_RC_RNR_NAK_GEN;
+
+ /* APM */
+ if ((rdma_cap->flags & RDMA_DEV_CAP_FLAG_APM) != 0) {
+ props->device_cap_flags = props->device_cap_flags |
+ IB_DEVICE_AUTO_PATH_MIG;
+ }
+
+ /* rsvd_lKey */
+ if ((rdma_cap->flags & RDMA_BMME_FLAG_RESERVED_LKEY) != 0) {
+#if defined(HAVE_IB_DEVICE_LOCAL_DMA_LKEY)
+ props->device_cap_flags |= IB_DEVICE_LOCAL_DMA_LKEY;
+#elif defined(HAVE_IB_KERNEL_CAP_FLAGS)
+ props->kernel_cap_flags |= IBK_LOCAL_DMA_LKEY;
+#endif
+ }
+
+ roce5_set_local_cap_flag(rdma_cap, props);
+
+ /* support XRC */
+ if ((rdma_cap->flags & RDMA_DEV_CAP_FLAG_XRC) != 0) {
+ props->device_cap_flags = props->device_cap_flags |
+ IB_DEVICE_XRC;
+ }
+
+ /* support MW */
+ if ((rdma_cap->flags & RDMA_DEV_CAP_FLAG_MEM_WINDOW) != 0) {
+ props->device_cap_flags = props->device_cap_flags |
+ IB_DEVICE_MEM_WINDOW;
+ }
+
+ roce5_set_bmme_cap_flag(rdma_cap, props);
+
+ roce5_query_device_props_set(rdev, rdma_cap, props);
+ return 0;
+}
+
+static void roce5_eth_link_get_speed(struct ib_port_attr *props,
+ enum mag_cmd_port_speed speed)
+{
+ switch (speed) {
+ /* 10G <==> 1X x 10G */
+ case PORT_SPEED_10GB:
+ props->active_width = IB_WIDTH_1X;
+ props->active_speed = IB_SPEED_QDR;
+ break;
+
+ /* 25G <==> 1X x 25G */
+ case PORT_SPEED_25GB:
+ props->active_width = IB_WIDTH_1X;
+ props->active_speed = IB_SPEED_EDR;
+ break;
+
+ /* 40G <==> 4X x 10G */
+ case PORT_SPEED_40GB:
+ props->active_width = IB_WIDTH_4X;
+ props->active_speed = IB_SPEED_QDR;
+ break;
+
+ /* 100G <==> 4X x 25G */
+ case PORT_SPEED_100GB:
+ props->active_width = IB_WIDTH_4X;
+ props->active_speed = IB_SPEED_EDR;
+ break;
+
+ /* 200G <==> 8X x 25G */
+ case PORT_SPEED_200GB:
+ props->active_width = IB_WIDTH_8X;
+ props->active_speed = IB_SPEED_EDR;
+ break;
+
+ /* 400G <==> 8X x 50G */
+ case PORT_SPEED_400GB:
+ props->active_width = IB_WIDTH_8X;
+ props->active_speed = IB_SPEED_HDR;
+ break;
+
+ default:
+ props->active_width = 0;
+ props->active_speed = 0;
+ break;
+ }
+}
+
+static void roce5_set_ib_port_attr(struct ib_port_attr *props,
+ struct roce5_device *rdev)
+{
+ struct rdma_comp_priv *comp_priv = get_rdma_comp_priv(rdev->hwdev);
+
+ if (comp_priv == NULL) {
+ ROCE_ERR("comp_priv is NULL");
+ return;
+ }
+
+ props->port_cap_flags = IB_PORT_CM_SUP;
+ props->gid_tbl_len = (int)comp_priv->rdma_cap.max_gid_per_port;
+ props->max_msg_sz = rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_msg_sz;
+ props->pkey_tbl_len = (u16)rdev->rdma_cap.max_pkeys;
+ props->max_mtu = (enum ib_mtu)((ROCE5_SUPPORT_8K_MTU(rdev) != 0) ?
+ ROCE_MTU_8192 :
+ ROCE_MTU_4096);
+ props->state = IB_PORT_DOWN;
+ props->phys_state = ROCE_PORT_PHYS_STATE_DISABLED;
+ props->active_mtu = IB_MTU_256;
+}
+
+static inline int roce5_get_port_speed_by_rdev(struct roce5_device *rdev,
+ enum mag_cmd_port_speed *speed)
+{
+ enum mag_cmd_port_speed speed_table[] = {
+ [ROCE5_4_25G_HCA] = PORT_SPEED_25GB,
+ [ROCE5_2_25G_HCA] = PORT_SPEED_25GB,
+ [ROCE5_1_100G_HCA] = PORT_SPEED_100GB,
+ [ROCE5_2_100G_HCA] = PORT_SPEED_100GB,
+ [ROCE5_2_200G_HCA] = PORT_SPEED_200GB,
+ [ROCE5_2_400G_HCA] = PORT_SPEED_400GB,
+ [ROCE5_4_200G_HCA] = PORT_SPEED_200GB,
+ };
+ int hca_type = rdev->hw_info.hca_type;
+
+ if (hca_type >= ARRAY_SIZE(speed_table) ||
+ speed_table[hca_type] == PORT_SPEED_NOT_SET) {
+ return -EINVAL;
+ }
+
+ *speed = speed_table[hca_type];
+ return 0;
+}
+
+static void roce5_eth_link_query_port(struct ib_device *ibdev,
+ struct ib_port_attr *props)
+{
+ struct roce5_device *rdev = NULL;
+ struct net_device *netdev = NULL;
+#ifdef ROCE_BONDING_EN
+ struct net_device *upper = NULL;
+#endif
+ enum roce5_mtu rmtu;
+ enum mag_cmd_port_speed speed = PORT_SPEED_10GB;
+ int ret = 0;
+
+ rdev = to_roce5_dev(ibdev);
+
+ roce5_set_ib_port_attr(props, rdev);
+
+ ret = roce5_get_port_speed_by_rdev(rdev, &speed);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to get speed, func_id(%d), hca_type(%d)",
+ rdev->glb_func_id, rdev->hw_info.hca_type);
+ props->active_width = 0;
+ props->active_speed = 0;
+ return;
+ }
+
+ roce5_eth_link_get_speed(props, speed);
+
+ netdev = roce5_ib_get_netdev(ibdev, ROCE_DEFAULT_PORT_NUM);
+ if (netdev == NULL) {
+ return;
+ }
+
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ rcu_read_lock();
+ upper = netdev_master_upper_dev_get_rcu(netdev);
+ if (upper != NULL) {
+ dev_put(netdev);
+ netdev = upper;
+ dev_hold(netdev);
+ }
+ rcu_read_unlock();
+ }
+#endif
+
+ if (netif_running(netdev) && netif_carrier_ok(netdev)) {
+ props->state = IB_PORT_ACTIVE;
+ props->phys_state = ROCE_PORT_PHYS_STATE_LINKUP;
+ }
+
+ rmtu = (ROCE5_SUPPORT_8K_MTU(rdev) != 0) ?
+ roce5_get_mtu((int)netdev->mtu) :
+ (enum roce5_mtu)iboe_get_mtu((int)netdev->mtu);
+
+ dev_put(netdev);
+
+ props->active_mtu =
+ (enum ib_mtu)ROCE_MIN((enum roce5_mtu)props->max_mtu, rmtu);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_query_port
+ Description : query port attribute
+ Input : struct ib_device *ibdev
+ u8 port
+ struct ib_port_attr *props
+ Output : struct ib_port_attr *props
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_query_port(struct ib_device *ibdev, u32 port,
+ struct ib_port_attr *props)
+{
+ int ret;
+ if ((ibdev == NULL) || (props == NULL)) {
+ ROCE_ERR("Ibdev or props is null");
+ return -EINVAL;
+ }
+
+ ret = memset_s(props, sizeof(*props), 0, sizeof(*props));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset props.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ roce5_eth_link_query_port(ibdev, props);
+
+ return 0;
+}
+
+/* compatible version for kernel 5.10 and kernel 4.19 */
+int roce5_query_port_compat(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props)
+{
+ return roce5_query_port(ibdev, (u32)port, props);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_query_gid
+ Description : query gid
+ Input : struct ib_device *ibdev
+ u8 port
+ int index
+ union ib_gid *gid
+ Output : union ib_gid *gid
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+ 2.Date : 2015/6/8
+ Modification : Modify function
+
+**************************************************************************** */
+int roce5_query_gid(struct ib_device *ibdev, u32 port, int index,
+ union ib_gid *gid)
+{
+ int ret = 0;
+ struct roce5_device *rdev = NULL;
+ struct rdma_gid_entry gid_entry;
+
+ if ((ibdev == NULL) || (gid == NULL)) {
+ ROCE_ERR("Ibdev or gid is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+
+ ret = roce5_get_gid(rdev, port, (u32)index, &gid_entry);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get gid, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = memcpy_s((void *)gid->raw, sizeof(*gid), (void *)gid_entry.raw,
+ sizeof(*gid));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy gid.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ // per per OFED of gid generation method convert GID, only IPv4 scenario need convert
+ if (gid_entry.dw6_h.bs.gid_type == ROCE_IPv4_ROCEv2_GID) {
+ // not add of gid returns directly, no need to convert
+ if ((gid->global.subnet_prefix == 0) &&
+ (gid->global.interface_id == 0)) {
+ return 0;
+ }
+ ipv6_addr_set_v4mapped(*((u32 *)(void *)gid + ROCE_GID_IP_IDX),
+ (struct in6_addr *)gid);
+ }
+
+ return 0;
+}
+
+/* compatible version for kernel 5.10 and kernel 4.19 */
+int roce5_query_gid_compat(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid)
+{
+ return roce5_query_gid(ibdev, (u32)port, index, gid);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_query_pkey
+ Description : query pkey
+ Input : struct ib_device *ibdev
+ u8 port
+ u16 index
+ u16 *pkey
+ Output : u16 *pkey
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_query_pkey(struct ib_device *ibdev, u32 port, u16 index, u16 *pkey)
+{
+ struct roce5_device *rdev = NULL;
+ if ((ibdev == NULL) || (pkey == NULL)) {
+ ROCE_ERR("Ibdev or pkey is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+
+ if (pkey == NULL) {
+ ROCE_ERR("Pkey is null");
+ return -EINVAL;
+ }
+
+ *pkey = 0xffff;
+
+ return 0;
+}
+
+/* compatible version for kernel 5.10 and kernel 4.19 */
+int roce5_query_pkey_compat(struct ib_device *ibdev, u8 port, u16 index,
+ u16 *pkey)
+{
+ return roce5_query_pkey(ibdev, (u32)port, index, pkey);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_modify_device
+ Description : modify device attribute
+ Input : struct ib_device *ibdev
+ int mask
+ struct ib_device_modify *props
+ Output : None
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_modify_device(struct ib_device *ibdev, int mask,
+ struct ib_device_modify *props)
+{
+ unsigned long flags = 0; /* type required by kernel API */
+ struct roce5_device *rdev = NULL;
+ int ret;
+
+ if ((ibdev == NULL) || (props == NULL)) {
+ ROCE_ERR("Ibdev or props is null");
+ return -EINVAL;
+ }
+
+ if (((unsigned int)mask & ~IB_DEVICE_MODIFY_NODE_DESC) != 0) {
+ ROCE_ERR("Not supported to modify node description");
+ return -EOPNOTSUPP;
+ }
+
+ if ((((u32)mask) & IB_DEVICE_MODIFY_NODE_DESC) == 0) {
+ ROCE_INFO("No need to modify node description");
+ return 0;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+
+ spin_lock_irqsave(&rdev->node_desc_lock, flags);
+ ret = memcpy_s((void *)ibdev->node_desc, IB_DEVICE_NODE_DESC_MAX,
+ (void *)props->node_desc, IB_DEVICE_NODE_DESC_MAX);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy node_desc.(ret:%d)", ret);
+ spin_unlock_irqrestore(&rdev->node_desc_lock, flags);
+ return -ENOMEM;
+ }
+ spin_unlock_irqrestore(&rdev->node_desc_lock, flags);
+
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_modify_port
+ Description : modify port attribute
+ Input : struct ib_device *ibdev
+ u8 port
+ int mask
+ struct ib_port_modify *props
+ Output : None
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_modify_port(struct ib_device *ibdev, u32 port, int mask,
+ struct ib_port_modify *props)
+{
+ int ret = 0;
+ struct ib_port_attr attr;
+ struct roce5_device *rdev = NULL;
+
+ if (ibdev == NULL) {
+ ROCE_ERR("Ibdev is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+
+ ret = memset_s(&attr, sizeof(struct ib_port_attr), 0,
+ sizeof(struct ib_port_attr));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset attr.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ mutex_lock(&rdev->cap_mask_mutex);
+
+ ret = roce5_query_port(ibdev, port, &attr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to query port, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ }
+
+ mutex_unlock(&rdev->cap_mask_mutex);
+
+ return ret;
+}
+
+/* compatible version for kernel 5.10 and kernel 4.19 */
+int roce5_modify_port_compat(struct ib_device *ibdev, u8 port, int mask,
+ struct ib_port_modify *props)
+{
+ return roce5_modify_port(ibdev, (u32)port, mask, props);
+}
+
+static int roce5_alloc_ucontext_set(struct roce5_device *rdev,
+ struct roce5_alloc_ucontext_resp *resp)
+{
+ struct rdma_service_cap *rdma_cap = NULL;
+
+ rdma_cap = &rdev->rdma_cap;
+
+ resp->num_qps = rdma_cap->dev_rdma_cap.roce_own_cap.max_qps;
+ resp->num_xsrqs = rdma_cap->dev_rdma_cap.roce_own_cap.max_srqs;
+ resp->cqe_size = rdma_cap->cqe_size;
+ resp->wqebb_size = rdma_cap->wqebb_size;
+ resp->dwqe_size = rdma_cap->direct_wqe_size;
+ resp->max_msg_size = rdma_cap->dev_rdma_cap.roce_own_cap.max_msg_sz;
+ resp->max_comp_vector = rdma_cap->num_comp_vectors;
+ resp->max_inline_size =
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_sq_inline_data_sz;
+
+ resp->storage_aa_en = 0;
+ resp->phy_port = rdev->hw_info.phy_port;
+ resp->srq_container_en = rdev->cfg_info.srq_container_en;
+ resp->srq_container_mode = rdev->cfg_info.srq_container_mode;
+ resp->xrc_srq_container_mode = rdev->cfg_info.xrc_srq_container_mode;
+ resp->warn_th = rdev->cfg_info.warn_th;
+ resp->func_id = rdev->glb_func_id;
+ resp->pcie_atomic_en = rdev->cfg_info.pcie_atomic_en;
+ resp->roce_user_ext_ability =
+ rdev->cfg_info.feature_cap.roce_user_ext_ability;
+ resp->roce_uld_ext_ability =
+ rdev->cfg_info.feature_cap.uld_feature.roce_uld_user_ext_ability;
+ resp->max_send_sge = (uint8_t)rdev->rdma_cap.max_sq_sg;
+ resp->max_recv_sge =
+ (uint8_t)rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_rq_sg;
+ resp->max_sq_wqe_len = rdev->rdma_cap.max_sq_desc_sz;
+ resp->huge_page_en = rdev->huge_page_en;
+ return hinic5_get_chip_node_id(rdev->lld_dev, &(resp->card_id));
+}
+
+static int roce5_alloc_ucontext_pre_check(struct ib_device *ibdev,
+ const struct ib_udata *udata)
+{
+ struct roce5_device *rdev = NULL;
+
+ if ((ibdev == NULL) || (udata == NULL)) {
+ ROCE_ERR("Ibdev or udata is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+ if (!rdev->ib_active) {
+ ROCE_DEV_ERR(rdev, "Device is abnormal, func_id(%d)",
+ rdev->glb_func_id);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int roce5_alloc_ucontext_return(struct roce5_device *rdev,
+ struct ib_udata *udata,
+ struct roce5_ucontext *context,
+ struct roce5_alloc_ucontext_resp *resp)
+{
+ int ret;
+
+ resp->db_offset = context->db_dma_addr & ((1 << PAGE_SHIFT) - 1);
+#ifdef ROCE_DWQE_EN
+ resp->dwqe_offset = context->dwqe_dma_addr & ((1 << PAGE_SHIFT) - 1);
+
+ if (context->dwqe_dma_addr == 0) {
+ ROCE_DEV_ERR(rdev, "dwqe_dma_addr = 0");
+ resp->dwqe_size = 0;
+ }
+#else
+ resp->dwqe_size = 0;
+#endif
+
+ INIT_LIST_HEAD(&context->db_page_list);
+ mutex_init(&context->db_page_mutex);
+
+ /* Copy data to user space */
+ ret = ib_copy_to_udata(udata, resp,
+ sizeof(struct roce5_alloc_ucontext_resp));
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to copy data to user space, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce5_alloc_ucontext(struct ib_ucontext *ibucontext, struct ib_udata *udata)
+{
+ int ret;
+
+ struct roce5_ucontext *context = to_roce5_ucontext(ibucontext);
+ struct roce5_device *rdev = to_roce5_dev(ibucontext->device);
+ struct roce5_alloc_ucontext_resp *resp = NULL;
+
+ ret = roce5_alloc_ucontext_pre_check(ibucontext->device, udata);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "pre check err, ret(%d), func_id(%d)", ret,
+ rdev->glb_func_id);
+ goto err;
+ }
+
+ resp = kzalloc(sizeof(struct roce5_alloc_ucontext_resp), GFP_KERNEL);
+ if (resp == NULL) {
+ ret = (-ENOMEM);
+ ROCE_DEV_ERR(rdev, "Failed alloc ucontext, func_id(%d)",
+ rdev->glb_func_id);
+ goto err;
+ }
+
+ ret = roce5_alloc_ucontext_set(rdev, resp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get chip node id, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_db;
+ }
+ /* Alloc user space context Doorbell and DWQE */
+ ret = hinic5_alloc_db_phy_addr(rdev->hwdev, &context->db_dma_addr,
+ &context->dwqe_dma_addr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc DB pa, ret(%d), func_id(%d)", ret,
+ rdev->glb_func_id);
+ goto err_db;
+ }
+
+ /* Copy data to user space */
+ ret = roce5_alloc_ucontext_return(rdev, udata, context, resp);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to return to user, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ goto err_return;
+ }
+
+ kfree(resp);
+#ifdef __ROCE_DFX__
+ rdev->ucontext = context;
+#endif
+ return 0;
+
+err_return:
+ hinic5_free_db_phy_addr(rdev->hwdev, context->db_dma_addr,
+ context->dwqe_dma_addr);
+err_db:
+ kfree(resp);
+err:
+ return ret;
+}
+
+void roce5_dealloc_ucontext(struct ib_ucontext *ibcontext)
+{
+ struct roce5_ucontext *context = NULL;
+ struct roce5_device *rdev = NULL;
+
+ if (ibcontext == NULL) {
+ ROCE_ERR("Ibcontext is null");
+ return;
+ }
+
+ context = to_roce5_ucontext(ibcontext);
+ rdev = to_roce5_dev(ibcontext->device);
+
+ hinic5_free_db_phy_addr(rdev->hwdev, context->db_dma_addr,
+ context->dwqe_dma_addr);
+
+ return;
+}
+
+struct ib_ucontext *roce5_alloc_ucontext_ofa(struct ib_device *ibdev,
+ struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_ucontext *context = NULL;
+
+ if (ibdev == NULL) {
+ ROCE_ERR("Ibdev is null");
+ return ERR_PTR(-EINVAL);
+ }
+
+ context = kzalloc(sizeof(struct roce5_ucontext), GFP_KERNEL);
+ if (context == NULL) {
+ ROCE_ERR("Failed to alloc ucontext");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Unreasonable, but for code reuse, driver associate the OFED resource in advance. */
+ context->ibucontext.device = ibdev;
+ ret = roce5_alloc_ucontext(&context->ibucontext, udata);
+ if (ret != 0) {
+ kfree(context);
+ return ERR_PTR(ret);
+ }
+
+ return (struct ib_ucontext *)&context->ibucontext;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_dealloc_ucontext_ofa
+ Description : dealloc ucontext
+ Input : struct ib_ucontext *ibcontext
+ Output : None
+
+ 1.Date : 2023/11/9
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_dealloc_ucontext_ofa(struct ib_ucontext *ibcontext)
+{
+ struct roce5_ucontext *context = NULL;
+
+ if (ibcontext == NULL) {
+ ROCE_ERR("Ibcontext is null");
+ return -EINVAL;
+ }
+
+ roce5_dealloc_ucontext(ibcontext);
+ context = to_roce5_ucontext(ibcontext);
+
+ kfree(context);
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_mmap
+ Description : memory map
+ Input : struct ib_ucontext *ibcontext
+ struct vm_area_struct *vma
+ Output : None
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma)
+{
+ struct roce5_device *rdev = NULL;
+ struct roce5_ucontext *ucontext = NULL;
+ unsigned long db_pfn = 0;
+ unsigned long dwqe_pfn = 0;
+
+ if ((ibcontext == NULL) || (vma == NULL)) {
+ ROCE_ERR("Ibcontext or vma is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibcontext->device);
+ ucontext = to_roce5_ucontext(ibcontext);
+ db_pfn = ucontext->db_dma_addr >> PAGE_SHIFT;
+ dwqe_pfn = ucontext->dwqe_dma_addr >> PAGE_SHIFT;
+
+ if ((vma->vm_end - vma->vm_start) != PAGE_SIZE) {
+ ROCE_DEV_ERR(
+ rdev,
+ "(Vm_end(%lu) - vm_start(%lu)) is not equal to PAGE_SIZE, func_id(%d)",
+ vma->vm_end, vma->vm_start, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ /* map hw DB to physical page from user */
+ if (vma->vm_pgoff == USR_MMAP_DB_OFFSET) {
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ /* construct vm_start~vm_start+PAGE_SIZE page table
+ * db_pfn is page number
+ * vm_page_prot means attr
+ */
+ if (io_remap_pfn_range(vma, vma->vm_start, db_pfn, PAGE_SIZE,
+ vma->vm_page_prot) != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to do db io remap, func_id(%d)",
+ rdev->glb_func_id);
+ return -EAGAIN;
+ }
+ return 0;
+ }
+
+#ifdef ROCE_DWQE_EN
+ if ((vma->vm_pgoff == USR_MMAP_DWQE_OFFSET) &&
+ (rdev->rdma_cap.direct_wqe_size != 0)) { // DWQE mmap
+#ifdef __aarch64__
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#else
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#endif
+
+ if (io_remap_pfn_range(vma, vma->vm_start, dwqe_pfn, PAGE_SIZE,
+ vma->vm_page_prot) != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to do dwqe io remap, func_id(%d)",
+ rdev->glb_func_id);
+ return -EAGAIN;
+ }
+ return 0;
+ }
+#endif
+
+ ROCE_DEV_ERR(rdev, "Not support, func_id(%d)", rdev->glb_func_id);
+ return -EINVAL;
+}
+
+enum rdma_link_layer roce5_port_link_layer(struct ib_device *ibdev,
+ u32 port_num)
+{
+ struct roce5_device *rdev = NULL;
+
+ if (ibdev == NULL) {
+ return IB_LINK_LAYER_UNSPECIFIED;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+
+ if (port_num != ROCE_DEFAULT_PORT_NUM) {
+ return IB_LINK_LAYER_UNSPECIFIED;
+ }
+
+ return IB_LINK_LAYER_ETHERNET;
+}
+
+/* compatible version for kernel 5.10 and kernel 4.19 */
+enum rdma_link_layer roce5_port_link_layer_compat(struct ib_device *ibdev,
+ u8 port_num)
+{
+ return roce5_port_link_layer(ibdev, (u32)port_num);
+}
+
+static void roce5_resolve_cb(int status, struct sockaddr *src_addr,
+ struct rdma_dev_addr *addr, void *context)
+{
+ ((struct roce5_resolve_cb_context *)context)->status = status;
+ complete(&((struct roce5_resolve_cb_context *)context)->comp);
+}
+
+static int roce5_rdma_addr_find_l2_eth_by_grh(
+ const union ib_gid *sgid, const union ib_gid *dgid, u8 *dmac,
+ const struct net_device *ndev, int *hoplimit, struct roce5_device *rdev,
+ const struct ib_gid_attr *sgid_attr)
+{
+ struct rdma_dev_addr dev_addr;
+ struct roce5_resolve_cb_context ctx;
+ union {
+ struct sockaddr_in _sockaddr_in;
+ struct sockaddr_in6 _sockaddr_in6;
+ } sgid_addr, dgid_addr;
+ int ret;
+
+ rdma_gid2ip((struct sockaddr *)&sgid_addr, sgid);
+ rdma_gid2ip((struct sockaddr *)&dgid_addr, dgid);
+
+ ret = memset_s(&dev_addr, sizeof(dev_addr), 0, sizeof(dev_addr));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset dev_addr.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ if (ndev) {
+ dev_addr.bound_dev_if = ndev->ifindex;
+ dev_addr.net = dev_net(ndev);
+ } else {
+ dev_addr.net = &init_net;
+ }
+
+ init_completion(&ctx.comp);
+#if defined(RDMA_RESOLVE_IP_HAVE_GID_ATTR)
+ dev_addr.sgid_attr = sgid_attr;
+ ret = rdma_resolve_ip((struct sockaddr *)&sgid_addr,
+ (struct sockaddr *)&dgid_addr, &dev_addr,
+ RESOLVE_IP_TIME_OUT, roce5_resolve_cb, true,
+ &ctx);
+#else
+ ret = rdma_resolve_ip((struct sockaddr *)&sgid_addr,
+ (struct sockaddr *)&dgid_addr, &dev_addr,
+ RESOLVE_IP_TIME_OUT, roce5_resolve_cb, &ctx);
+#endif
+ if (ret != 0) {
+ ROCE_ERR("rdma_resolve_ip failed. Igonore the err(%d).", ret);
+ roce5_resolve_cb(0, (struct sockaddr *)&sgid_addr, &dev_addr,
+ &ctx);
+ }
+
+ wait_for_completion(&ctx.comp);
+
+ ret = memcpy_s(dmac, ETH_ALEN, dev_addr.dst_dev_addr, ETH_ALEN);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dmac.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ if (hoplimit) {
+ *hoplimit = dev_addr.hoplimit;
+ }
+
+ return 0;
+}
+
+static int roce5_ah_valid_check(struct ib_global_route *grh, u16 *vlan_id,
+ u8 *dmac)
+{
+ u8 unicast_gid0[ROCE_GID_LEN] = { 0 };
+ u8 unicast_gid1[ROCE_GID_LEN] = { 0 };
+
+ /* check gid(unicast gid can not be 0 or 1) */
+ unicast_gid0[ROCE_GID_HIGHEST_BYTE] = 0;
+ unicast_gid1[ROCE_GID_HIGHEST_BYTE] = 1;
+
+ if ((ROCE_MEMCMP(grh->dgid.raw, unicast_gid0, sizeof(union ib_gid)) ==
+ 0) ||
+ (ROCE_MEMCMP(grh->dgid.raw, unicast_gid1, sizeof(union ib_gid)) ==
+ 0)) {
+ ROCE_ERR(
+ "Invalid unicast dgid, The ROCE_GID_HIGHEST_BYTE of unicast_dgid is: 0x%02x",
+ *(grh->dgid.raw + ROCE_GID_HIGHEST_BYTE));
+ return (-EINVAL);
+ }
+
+ if (rdma_link_local_addr((struct in6_addr *)grh->dgid.raw) != 0) {
+ rdma_get_ll_mac((struct in6_addr *)grh->dgid.raw, dmac);
+ *vlan_id = ROCE_DEFAULT_VLAN_ID;
+ }
+
+ return 0;
+}
+
+static int roce5_fill_gid_attr(struct roce5_device *rdev,
+ struct rdma_ah_attr *ah_attr, union ib_gid *sgid,
+ const struct ib_gid_attr **sgid_attr)
+{
+ int ret = 0;
+
+ ret = rdma_query_gid(&rdev->ib_dev, ah_attr->port_num,
+ ah_attr->grh.sgid_index, sgid);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to query gid func_id(%hu),port_num(%d),gid_index(%d),ret(%d)",
+ rdev->glb_func_id, ah_attr->port_num,
+ ah_attr->grh.sgid_index, ret);
+ return ret;
+ }
+
+ *sgid_attr = rdma_get_gid_attr(&rdev->ib_dev, ah_attr->port_num,
+ ah_attr->grh.sgid_index);
+ if (IS_ERR_OR_NULL(*sgid_attr)) {
+ ret = (int)PTR_ERR(*sgid_attr);
+ ROCE_PRINT_GID(rdev, sgid->raw,
+ "Failed to get sgid_attr, func_id(%hu), ret(%d)",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void roce5_release_gid_ref_cnt(const struct ib_gid_attr *sgid_attr)
+{
+ rdma_put_gid_attr(sgid_attr);
+}
+
+static struct net_device *roce5_fill_netdev(struct roce5_device *rdev,
+ union ib_gid *sgid)
+{
+ struct net_device *netdev = NULL;
+ union {
+ struct sockaddr_in _sockaddr_in;
+ struct sockaddr_in6 _sockaddr_in6;
+ } socket_addr;
+
+ rdma_gid2ip((struct sockaddr *)&socket_addr, sgid);
+
+ /* find netdev,rdev->ndevis not valid in vlan scenario */
+ netdev = ip_dev_find(&init_net,
+ socket_addr._sockaddr_in.sin_addr.s_addr);
+ if (netdev) {
+ dev_put(netdev);
+ }
+
+ return netdev;
+}
+
+int roce5_resolve_grh(struct roce5_device *rdev, struct rdma_ah_attr *ah_attr,
+ u16 *vlan_id, struct ib_udata *udata)
+{
+ int ret = 0;
+ u8 zero_mac[ETH_ALEN] = { 0 };
+ u8 *dmac = NULL;
+ union ib_gid sgid = { 0 };
+ const struct ib_gid_attr *sgid_attr = NULL;
+ struct net_device *netdev = NULL;
+
+ if ((rdev == NULL) || (ah_attr == NULL) || (vlan_id == NULL)) {
+ ROCE_ERR("Input pointer is NULL");
+ return (-EINVAL);
+ }
+
+ dmac = ah_attr->roce.dmac;
+ ret = roce5_ah_valid_check(&ah_attr->grh, vlan_id, dmac);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to check grh input, func_id(%d), ret(%d),"
+ "The grh inputs are: vlan_id(%d), dmac:%02x-%02x-%02x-%02x-%02x-%02x",
+ rdev->glb_func_id, ret, *vlan_id,
+ *((u8 *)dmac + MAC_INDEX_0),
+ *((u8 *)dmac + MAC_INDEX_1),
+ *((u8 *)dmac + MAC_INDEX_2),
+ *((u8 *)dmac + MAC_INDEX_3),
+ *((u8 *)dmac + MAC_INDEX_4),
+ *((u8 *)dmac + MAC_INDEX_5));
+ return ret;
+ }
+ if (ROCE_MEMCMP(dmac, zero_mac, ETH_ALEN) != 0) {
+ return 0;
+ }
+
+ ret = roce5_fill_gid_attr(rdev, ah_attr, &sgid, &sgid_attr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to fill gid attr, func_id(%hu), ret(%d)",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ netdev = roce5_fill_netdev(rdev, &sgid);
+
+ /* reparse dmac avoiding invalid damc from OFED */
+ ret = roce5_rdma_addr_find_l2_eth_by_grh(
+ &sgid, &ah_attr->grh.dgid, dmac, netdev, NULL, rdev, sgid_attr);
+ if (ret != 0) {
+ ROCE_PRINT_GID(
+ rdev, sgid.raw,
+ "Failed to find dmac by grh, func_id(%hu), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto resolve_grh_end;
+ }
+
+ if (ROCE_MEMCMP(dmac, zero_mac, ETH_ALEN) == 0) {
+ ROCE_DEV_ERR(rdev, "Failed to find valid dmac, func_id(%hu)",
+ rdev->glb_func_id);
+ ret = (-EINVAL);
+ goto resolve_grh_end;
+ }
+
+ if (sgid_attr != NULL && sgid_attr->ndev != NULL) {
+ *vlan_id = rdma_vlan_dev_vlan_id(sgid_attr->ndev);
+ }
+
+resolve_grh_end:
+ roce5_release_gid_ref_cnt(sgid_attr);
+
+ return ret;
+}
+
+static int roce5_ah_get_vlan_id(struct roce5_device *rdev, struct ib_pd *pd,
+ struct rdma_ah_attr *ah_attr, u32 *vlan_id)
+{
+ u32 ret = 0;
+ struct net_device *ndev = NULL;
+ rcu_read_lock();
+ ndev = rcu_dereference(ah_attr->grh.sgid_attr->ndev);
+ if (ndev == NULL) {
+ rcu_read_unlock();
+ ROCE_DEV_ERR(rdev, "Net device is NULL, func_id(%hu)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+ ret = rdma_vlan_dev_vlan_id(ndev);
+ if (ret != 0xffff) {
+ *vlan_id = ret;
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
+static int roce5_create_ib_ah_kernel(struct roce5_device *rdev,
+ struct ib_pd *pd, struct roce5_ah *rah,
+ struct rdma_ah_attr *ah_attr)
+{
+ int ret;
+ u8 *dmac = ah_attr->roce.dmac;
+ u32 vlan_id = 0;
+
+ ret = roce5_ah_get_vlan_id(rdev, pd, ah_attr, &vlan_id);
+ if (ret != 0) {
+ ROCE_ERR("Failed to get vlan_id (ret:%d)", ret);
+ return -EFAULT;
+ }
+
+ if (((u32)rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) != 0) {
+ ret = memcpy_s((void *)rah->priv_ah.dgid,
+ sizeof(rah->priv_ah.dgid),
+ (void *)ah_attr->grh.dgid.raw,
+ sizeof(rah->priv_ah.dgid));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dgid.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ rah->priv_ah.dw2.bs.flow_label = ah_attr->grh.flow_label &
+ 0xfffff;
+ rah->priv_ah.dw1.bs.sgid_index = ah_attr->grh.sgid_index & 0x7f;
+ rah->priv_ah.dw1.bs.hoplimit = ah_attr->grh.hop_limit;
+ rah->priv_ah.dw1.bs.tclass =
+ (u8)(ah_attr->grh.traffic_class | IP_ECN_PERMIT);
+ }
+ rah->priv_ah.dw0.bs.pd = to_roce5_pd(pd)->pdn & 0x3ffff;
+ rah->priv_ah.dw0.bs.wqe_cos =
+ roce5_get_db_cos_from_vlan_pri(rdev, ah_attr->sl);
+ rah->priv_ah.dw0.value = cpu_to_be32(rah->priv_ah.dw0.value);
+
+ rah->priv_ah.dw1.bs.port = ah_attr->port_num & 0xf;
+ rah->priv_ah.dw2.bs.smac_index =
+ rdev->glb_func_id; /* set global Function ID */
+ rah->priv_ah.dw2.value = cpu_to_be32(rah->priv_ah.dw2.value);
+
+ rah->priv_ah.dw1.bs.resv = 0;
+ rah->priv_ah.dw7.bs.vlan_id = vlan_id & 0xfff;
+ rah->priv_ah.dw7.bs.vlan_pri = ah_attr->sl & 0x7;
+
+ rah->priv_ah.dw1.value = cpu_to_be32(rah->priv_ah.dw1.value);
+
+ rah->priv_ah.dw7.bs.dmac_h16 = (dmac[0] << ROCE_RAH_DMAC_H16_SHIFT) |
+ dmac[1];
+ rah->priv_ah.dw7.value = cpu_to_be32(rah->priv_ah.dw7.value);
+
+ ret = memcpy_s((void *)&rah->priv_ah.dmac_l32,
+ sizeof(rah->priv_ah.dmac_l32),
+ (void *)&dmac[ROCE_RAH_DMAC_L32_START],
+ sizeof(rah->priv_ah.dmac_l32));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dmac_l32.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int roce5_create_ib_ah_user(struct roce5_device *rdev,
+ struct rdma_ah_attr *ah_attr,
+ struct ib_udata *udata)
+{
+ struct roce5_create_ah_resp resp;
+ roce5_get_cos_inbuf_s dcb_inbuf;
+ int ret;
+
+ ret = memset_s(ah_attr->roce.dmac, sizeof(ah_attr->roce.dmac), 0,
+ sizeof(ah_attr->roce.dmac));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset dmac.");
+ return (-ENOMEM);
+ }
+
+ ret = roce5_resolve_grh(rdev, ah_attr, &resp.vlan_id, udata);
+ if (ret != 0) {
+ ROCE_ERR("Failed to resolve grh");
+ return -EINVAL;
+ }
+
+ ret = memcpy_s(resp.dmac, ETH_ALEN, ah_attr->roce.dmac, ETH_ALEN);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy_s ah dmac.");
+ return (-ENOMEM);
+ }
+
+ dcb_inbuf.sl = ah_attr->sl;
+ dcb_inbuf.sgid_index = ah_attr->grh.sgid_index;
+ dcb_inbuf.port_num = ah_attr->port_num;
+ dcb_inbuf.traffic_class = ah_attr->grh.traffic_class;
+ ret = roce5_get_dcb_cfg_cos(rdev, &dcb_inbuf, &resp.cos, IB_QPT_UD);
+ if (ret != 0) {
+ ROCE_ERR("Failed to get cos from dcb info, ret:%d", ret);
+ return ret;
+ }
+
+ ret = ib_copy_to_udata(udata, &resp, sizeof(resp));
+ if (ret != 0) {
+ ROCE_ERR("Failed to copy data to user");
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce5_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_ah *rah = NULL;
+ struct roce5_device *rdev = NULL;
+ struct rdma_ah_attr *ah_attr = NULL;
+ enum rdma_ah_attr_type ah_type = 0;
+
+ if ((ibah == NULL) || (init_attr == NULL)) {
+ ROCE_ERR("Input pointer is NULL");
+ return (-EINVAL);
+ }
+
+ rah = to_roce5_ah(ibah);
+ rdev = to_roce5_dev(ibah->device);
+ ah_attr = init_attr->ah_attr;
+ ah_type = ah_attr->type;
+
+ if ((ah_type == RDMA_AH_ATTR_TYPE_ROCE) &&
+ (((u32)rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) == 0)) {
+ ROCE_DEV_ERR(rdev, "Invalid ah_type(%d)", ah_type);
+ return -EINVAL;
+ }
+
+ if (udata != NULL) {
+ ret = roce5_create_ib_ah_user(rdev, ah_attr, udata);
+ } else {
+ ret = roce5_create_ib_ah_kernel(rdev, ibah->pd, rah, ah_attr);
+ }
+ return ret;
+}
+
+struct ib_ah *roce5_create_ah_ofa(struct ib_pd *pd,
+ struct rdma_ah_attr *ah_attr,
+ struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_ah *rah = NULL;
+ struct roce5_device *rdev = NULL;
+ struct rdma_ah_init_attr init_attr;
+
+ if ((pd == NULL) || (ah_attr == NULL)) {
+ ROCE_ERR("Input pointer is NULL");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rdev = to_roce5_dev(pd->device);
+ init_attr.ah_attr = ah_attr;
+
+ rah = kzalloc(sizeof(*rah), GFP_ATOMIC);
+ if (rah == NULL) {
+ ret = -ENOMEM;
+ ROCE_DEV_ERR(rdev, "Failed to alloc ah, func_id(%d)",
+ rdev->glb_func_id);
+ goto out;
+ }
+
+ /* Unreasonable, but for code reuse, driver associate the OFED resource in advance. */
+ rah->ibah.device = pd->device;
+ rah->ibah.pd = pd;
+ ret = roce5_create_ah(&rah->ibah, &init_attr, udata);
+ if (ret != 0) {
+ kfree(rah);
+ }
+
+out:
+ return (ret != 0) ? ERR_PTR(ret) : &rah->ibah;
+}
+
+int roce5_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr)
+{
+ struct roce5_ah *ah = NULL;
+ struct roce5_priv_ah priv_ah;
+ int ret;
+
+ if ((ibah == NULL) || (ah_attr == NULL)) {
+ ROCE_ERR("Ibah or ah_attr is null");
+ return -EINVAL;
+ }
+
+ ah = to_roce5_ah(ibah);
+ ret = memset_s(ah_attr, sizeof *ah_attr, 0, sizeof *ah_attr);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset ah_attr.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ priv_ah.dw1.value = be32_to_cpu(ah->priv_ah.dw1.value);
+ priv_ah.dw2.value = be32_to_cpu(ah->priv_ah.dw2.value);
+ priv_ah.dw7.value = be32_to_cpu(ah->priv_ah.dw7.value);
+
+ ah_attr->ah_flags = IB_AH_GRH;
+ ah_attr->sl = priv_ah.dw7.bs.vlan_pri;
+ ah_attr->port_num = priv_ah.dw1.bs.port;
+ ah_attr->grh.traffic_class = priv_ah.dw1.bs.tclass;
+ ah_attr->grh.hop_limit = priv_ah.dw1.bs.hoplimit;
+ ah_attr->grh.sgid_index = priv_ah.dw1.bs.sgid_index;
+ ah_attr->grh.flow_label = priv_ah.dw2.bs.flow_label;
+
+ ret = memcpy_s((void *)ah_attr->grh.dgid.raw, sizeof(ah->priv_ah.dgid),
+ (void *)ah->priv_ah.dgid, sizeof(ah->priv_ah.dgid));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy dgid.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int roce5_destroy_ah(struct ib_ah *ibah, u32 flags)
+{
+ return 0;
+}
+
+int roce5_destroy_ah_ofa(struct ib_ah *ibah)
+{
+ struct roce5_ah *rah = NULL;
+
+ if (ibah == NULL) {
+ ROCE_ERR("Ibah is null");
+ return -EINVAL;
+ }
+
+ rah = to_roce5_ah(ibah);
+
+ kfree(rah);
+
+ return 0;
+}
+
+int roce5_port_immutable(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_immutable *immutable)
+{
+ struct ib_port_attr attr;
+ int err;
+
+ if ((ibdev == NULL) || (immutable == NULL)) {
+ ROCE_ERR("Input pointer is NULL");
+ return (-EINVAL);
+ }
+
+ immutable->core_cap_flags =
+ RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; // only rocev2
+
+#if defined(IB_QUERY_PORT_HAVE_U8_PORT)
+ err = ib_query_port(ibdev, (u8)port_num, &attr);
+#elif defined(IB_QUERY_PORT_HAVE_U32_PORT)
+ err = ib_query_port(ibdev, port_num, &attr);
+#endif
+ if (err != 0) {
+ ROCE_ERR("dev(%s) query ib port(%d) failed, err(%d)",
+ ibdev->name, port_num, err);
+ return err;
+ }
+
+ immutable->pkey_tbl_len = attr.pkey_tbl_len;
+ immutable->gid_tbl_len = attr.gid_tbl_len;
+ immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+
+ return 0;
+}
+
+/* compatible version for kernel 5.10 and kernel 4.19 */
+int roce5_port_immutable_compat(struct ib_device *ibdev, u8 port_num,
+ struct ib_port_immutable *immutable)
+{
+ return roce5_port_immutable(ibdev, (u32)port_num, immutable);
+}
+
+#define ROCE_DEFAULT_COS 3
+
+int roce5_get_dcb_cfg_cos(struct roce5_device *rdev,
+ roce5_get_cos_inbuf_s *inbuf, u8 *cos,
+ enum ib_qp_type qp_type)
+{
+ int ret;
+ u8 pri;
+ struct rdma_gid_entry gid;
+ struct hinic5_dcb_state dcb = { 0 };
+
+#if !defined(UVERBS_IOCTL_HAVE_DECLARE_UVERBS_WRITE_EX)
+ /* Note: low version of ofed in modify qp when unused udate->outbuf, cause cannot from kernel mode get db cos, therefore stub uses a fixed value. */
+ *cos = ROCE_DEFAULT_COS;
+ goto cos_success;
+#endif
+
+ ret = roce5_get_gid(rdev, inbuf->port_num, inbuf->sgid_index, &gid);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init gid info, ret(%d).", ret);
+ return -EINVAL;
+ }
+
+ ret = hinic5_get_dcb_state(rdev->hwdev, &dcb);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "hinic5_get_dcb_state failed, ret(%d).",
+ ret);
+ return -EINVAL;
+ }
+
+ *cos = dcb.default_cos;
+ gid.dw6_h.value = cpu_to_le16(gid.dw6_h.value);
+ if ((dcb.trust == ROCE5_DCB_PCP) &&
+ (gid.dw6_h.bs.tag == ROCE_GID_VLAN_INVALID)) {
+ // pcp cfg & no vlan should use default cos
+ goto cos_success;
+ }
+
+ pri = (dcb.trust == ROCE5_DCB_PCP) ?
+ inbuf->sl :
+ (inbuf->traffic_class >> ROCE5_DSCP_IDX);
+ ret = hinic5_get_cos_by_pri(rdev->hwdev, pri, cos);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "get cos failed, ret(%d), pri(%u), dcb_on(%u), trust(%u).",
+ ret, pri, dcb.dcb_on, dcb.trust);
+ return -EINVAL;
+ }
+
+cos_success:
+ roce5_cos_update_ext(rdev, cos, qp_type);
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_mix.h b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_mix.h
new file mode 100644
index 000000000..2fb0eb2b9
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_mix.h
@@ -0,0 +1,269 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_MIX_H
+#define ROCE_MIX_H
+
+#include <net/arp.h>
+#include <net/neighbour.h>
+#include <net/route.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+#include <linux/mutex.h>
+#include <linux/inetdevice.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+
+#include <rdma/ib_addr.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+
+#include "roce.h"
+
+#define ROCE_HW_VER 0ULL
+#define ROCE_FW_VER_0 1ULL
+#define ROCE_FW_VER_1 4ULL
+#define ROCE_FW_VER_2 0ULL
+#define ROCE_FW_VER_3 0ULL
+#define ROCE_FW_VER \
+ ((ROCE_FW_VER_0 << 32) | (ROCE_FW_VER_1 << 16) | \
+ (ROCE_FW_VER_2 << 8) | ROCE_FW_VER_3)
+
+#define RESOLVE_IP_TIME_OUT 1000
+#define ROCE_GID_HIGHEST_BYTE 15
+#define ROCE_FW_VERSION_LEN 4
+#define ROCE_DEFAULT_VLAN_ID 0xFFFF
+#define ROCE_RAH_TC_SHIFT 2
+#define ROCE_RAH_DMAC_H16_SHIFT 8
+#define ROCE_RAH_DMAC_L32_START 2
+#define ROCE_UDP_SRC_PORT_H8_SHIFT 8
+
+#define ROCE5_DCB_PCP 0
+#define ROCE5_DCB_DSCP 1
+
+#define ROCE5_DSCP_IDX 2 //dscp begin from bit 2 in traffic_class
+
+#define ROCE_GID_IP_IDX 3
+
+#define MAC_INDEX_0 0
+#define MAC_INDEX_1 1
+#define MAC_INDEX_2 2
+#define MAC_INDEX_3 3
+#define MAC_INDEX_4 4
+#define MAC_INDEX_5 5
+
+#define IP_INDEX_0 0
+#define IP_INDEX_1 1
+#define IP_INDEX_2 2
+#define IP_INDEX_3 3
+#define IP_INDEX_4 4
+#define IP_INDEX_5 5
+#define IP_INDEX_6 6
+#define IP_INDEX_7 7
+
+#define ROCE_MTU_256_INT 256
+#define ROCE_MTU_512_INT 512
+#define ROCE_MTU_1024_INT 1024
+#define ROCE_MTU_2048_INT 2048
+#define ROCE_MTU_4096_INT 4096
+#define ROCE_MTU_8192_INT 8192
+
+enum {
+ USR_MMAP_DB_OFFSET = 0,
+ USR_MMAP_DWQE_OFFSET,
+ USR_MMAP_DFX_OFFSET,
+ USR_MMAP_DBAR3_OFFSET
+};
+
+enum roce_port_state_e {
+ ROCE_PORT_PHYS_STATE_NO_CHANGE = 0,
+ ROCE_PORT_PHYS_STATE_SLEEP,
+ ROCE_PORT_PHYS_STATE_POLLING,
+ ROCE_PORT_PHYS_STATE_DISABLED = 3,
+ ROCE_PORT_PHYS_STATE_PORTCONFTRAIN,
+ ROCE_PORT_PHYS_STATE_LINKUP = 5,
+ ROCE_PORT_PHYS_STATE_LINKERRRECOVER,
+ ROCE_PORT_PHYS_STATE_PHYTEST
+};
+
+enum ROCE_MBOX_CMD { ROCE_MBOX_CMD_SEND_MAIL_BOX, ROCE_MBOX_CMD_MAX };
+
+enum roce5_mtu {
+ ROCE_MTU_256 = IB_MTU_256,
+ ROCE_MTU_512 = IB_MTU_512,
+ ROCE_MTU_1024 = IB_MTU_1024,
+ ROCE_MTU_2048 = IB_MTU_2048,
+ ROCE_MTU_4096 = IB_MTU_4096,
+ ROCE_MTU_8192,
+};
+
+static inline int roce5_mtu_enum_to_int(enum roce5_mtu mtu)
+{
+ switch (mtu) {
+ case ROCE_MTU_256:
+ return ROCE_MTU_256_INT;
+ case ROCE_MTU_512:
+ return ROCE_MTU_512_INT;
+ case ROCE_MTU_1024:
+ return ROCE_MTU_1024_INT;
+ case ROCE_MTU_2048:
+ return ROCE_MTU_2048_INT;
+ case ROCE_MTU_4096:
+ return ROCE_MTU_4096_INT;
+ case ROCE_MTU_8192:
+ return ROCE_MTU_8192_INT;
+ default:
+ return -1;
+ }
+}
+
+static inline enum roce5_mtu roce5_get_mtu(int mtu)
+{
+ int local_mtu = mtu - (IB_GRH_BYTES + IB_UDP_BYTES + IB_BTH_BYTES +
+ IB_EXT_XRC_BYTES + IB_EXT_ATOMICETH_BYTES +
+ IB_ICRC_BYTES);
+
+ if (local_mtu >= roce5_mtu_enum_to_int(ROCE_MTU_8192))
+ return ROCE_MTU_8192;
+ else if (local_mtu >= roce5_mtu_enum_to_int(ROCE_MTU_4096))
+ return ROCE_MTU_4096;
+ else if (local_mtu >= roce5_mtu_enum_to_int(ROCE_MTU_2048))
+ return ROCE_MTU_2048;
+ else if (local_mtu >= roce5_mtu_enum_to_int(ROCE_MTU_1024))
+ return ROCE_MTU_1024;
+ else if (local_mtu >= roce5_mtu_enum_to_int(ROCE_MTU_512))
+ return ROCE_MTU_512;
+ else if (local_mtu >= roce5_mtu_enum_to_int(ROCE_MTU_256))
+ return ROCE_MTU_256;
+ else
+ return 0;
+}
+
+struct roce5_priv_ah {
+ /* DW0 */
+ union {
+ struct {
+#if (BYTE_ORDER != BIG_ENDIAN)
+ u32 pd : 18;
+ u32 rsvd0 : 6;
+ u32 stat_rate : 4;
+ u32 wqe_cos : 3;
+ u32 fl : 1; /* forcelock flag, it is used in multicast communication */
+#else
+ u32 f1 : 1;
+ u32 wqe_cos : 3;
+ u32 stat_rate : 4;
+ u32 rsvd0 : 6;
+ u32 pd : 18;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if (BYTE_ORDER != BIG_ENDIAN)
+ u32 hoplimit : 8;
+ u32 sgid_index : 7;
+ u32 resv : 1;
+ u32 port : 4;
+ u32 rsvd1 : 4;
+ u32 tclass : 8;
+#else
+ u32 tclass : 8;
+ u32 rsvd1 : 4;
+ u32 port : 4;
+ u32 resv : 1;
+ u32 sgid_index : 7;
+ u32 hoplimit : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if (BYTE_ORDER != BIG_ENDIAN)
+ u32 flow_label : 20;
+ u32 smac_index : 10;
+ u32 rsvd : 2;
+#else
+ u32 rsvd : 2;
+ u32 smac_index : 10;
+ u32 flow_label : 20;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3~6 */
+ u8 dgid[16];
+
+ /* DW7 */
+ union {
+ struct {
+#if (BYTE_ORDER != BIG_ENDIAN)
+ u32 dmac_h16 : 16;
+ u32 vlan_id : 12;
+ u32 rsvd : 1;
+ u32 vlan_pri : 3;
+#else
+ u32 vlan_pri : 3;
+ u32 rsvd : 1;
+ u32 vlan_id : 12;
+ u32 dmac_h16 : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ /* DW8 */
+ u32 dmac_l32;
+};
+
+struct roce5_ah {
+ struct ib_ah ibah;
+ struct roce5_priv_ah priv_ah;
+};
+
+union gid_addr {
+ struct sockaddr _sockaddr;
+ struct sockaddr_in _sockaddr_in;
+ struct sockaddr_in6 _sockaddr_in6;
+};
+
+struct mailbox_header {
+ u32 dest_host_id;
+ u32 dest_global_function_id;
+};
+
+struct roce5_mail_box_buffer {
+ struct mailbox_header header;
+ u32 data[0];
+};
+
+struct roce5_resolve_cb_context {
+ struct completion comp;
+ int status;
+};
+
+typedef struct roce5_get_cos_inbuf {
+ u8 sl;
+ u8 sgid_index;
+ u8 port_num;
+ u8 traffic_class;
+} roce5_get_cos_inbuf_s;
+
+int roce5_resolve_grh(struct roce5_device *rdev, struct rdma_ah_attr *ah_attr,
+ u16 *vlan_id, struct ib_udata *udata);
+int roce5_get_dcb_cfg_cos(struct roce5_device *rdev,
+ roce5_get_cos_inbuf_s *inbuf, u8 *cos,
+ enum ib_qp_type qp_type);
+uint8_t roce5_get_db_cos_from_vlan_pri(struct roce5_device *rdev,
+ uint8_t vlan_pri);
+
+#endif /* ROCE_MIX_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_pd.c b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_pd.c
new file mode 100644
index 000000000..92a3ada97
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_pd.c
@@ -0,0 +1,138 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/slab.h>
+
+#include "roce.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#include "roce_pd.h"
+
+int roce5_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_pd *pd = NULL;
+ struct roce5_device *rdev = NULL;
+
+ if (CHECK_2LAYER_IS_NULL(ibpd, device)) {
+ ROCE_ERR(
+ "Invalid NULL parameter, ibpd or ibpd->device is NULL.");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ pd = to_roce5_pd(ibpd);
+ rdev = to_roce5_dev(ibpd->device);
+
+ ret = roce5_rdma_pd_alloc(rdev->hwdev, &pd->pdn);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc pdn, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ goto err_out;
+ }
+
+ if (udata != NULL) {
+ if (udata->outbuf == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid NULL parameter, udata->outbuf is NULL.");
+ ret = -EINVAL;
+ goto err_copy_to_user;
+ }
+
+ if (ib_copy_to_udata(udata, &pd->pdn, sizeof(u32)) != 0) {
+ ret = -EFAULT;
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to copy data to user space, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_copy_to_user;
+ }
+ }
+
+ return 0;
+
+err_copy_to_user:
+ roce5_rdma_pd_free(rdev->hwdev, pd->pdn);
+err_out:
+ return ret;
+}
+
+struct ib_pd *roce5_alloc_pd_ofa(struct ib_device *ibdev,
+ struct ib_ucontext *ibcontext,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_pd *pd = NULL;
+ struct roce5_device *rdev = NULL;
+
+ if (ibdev == NULL) {
+ ret = -EINVAL;
+ ROCE_ERR("Ibdev is null");
+ goto err_out;
+ }
+
+ rdev = to_roce5_dev(ibdev);
+
+ pd = (struct roce5_pd *)kmalloc(sizeof *pd, GFP_KERNEL);
+ if (pd == NULL) {
+ ret = -ENOMEM;
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc memory for roce pd, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_out;
+ }
+
+ /* Unreasonable, but for code reuse, driver associate the OFED resource in advance. */
+ pd->ibpd.device = ibdev;
+ ret = roce5_alloc_pd(&pd->ibpd, udata);
+ if (ret != 0) {
+ goto err_alloc_pdn;
+ }
+
+ return &pd->ibpd;
+
+err_alloc_pdn:
+ kfree(pd);
+
+err_out:
+ return (struct ib_pd *)ERR_PTR((long)ret);
+}
+
+int roce5_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
+{
+ struct roce5_pd *pd = NULL;
+ struct roce5_device *rdev = NULL;
+
+ if (ibpd == NULL) {
+ ROCE_ERR("Ibpd is null");
+ return -EINVAL;
+ }
+
+ pd = to_roce5_pd(ibpd);
+ rdev = to_roce5_dev(ibpd->device);
+
+ roce5_rdma_pd_free(rdev->hwdev, pd->pdn);
+
+ return 0;
+}
+
+int roce5_dealloc_pd_ofa(struct ib_pd *ibpd)
+{
+ int ret;
+ struct roce5_pd *pd = NULL;
+
+ if (ibpd == NULL) {
+ ROCE_ERR("Ibpd is null");
+ return -EINVAL;
+ }
+
+ pd = to_roce5_pd(ibpd);
+ ret = roce5_dealloc_pd(ibpd, NULL);
+ if (ret == 0) {
+ kfree(pd);
+ }
+
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_pd.h b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_pd.h
new file mode 100644
index 000000000..e40c5a476
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/rdma/roce_pd.h
@@ -0,0 +1,15 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_PD_H
+#define ROCE_PD_H
+
+#include <rdma/ib_verbs.h>
+
+struct roce5_pd {
+ struct ib_pd ibpd;
+ u32 pdn;
+};
+
+#endif //ROCE_PD_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq.h b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq.h
new file mode 100644
index 000000000..1886af73f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq.h
@@ -0,0 +1,191 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_SRQ_H
+#define ROCE_SRQ_H
+
+#include <linux/types.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "hinic5_rdma.h"
+#include "hinic5_cqm.h"
+
+#include "roce.h"
+#include "roce_pd.h"
+#include "roce_db.h"
+#include "roce_compat.h"
+#include "roce_wqe_format.h"
+
+/* definition SRQ SGE maximum max and minimum value */
+#define ROCE_SRQ_CONT_MAX_SGE 16
+#define ROCE_SRQ_MAX_SGE 15
+#define ROCE_SRQ_MID_SGE 7
+#define ROCE_SRQ_MIN_SGE 3
+
+#define ROCE_SRQN_INVLD CQM_INDEX_INVALID
+#define ROCE_SRQ_CONTAINER_LWM_MASK 0xFFFF
+#define ROCE_SRQ_CONTAINER_WARTH_MASK 0xF
+
+#define MAX_SUPPORT_CONTAINER_MODE 3
+#define DWORD_LEN 32
+#define XRC_CQN_FIRST_LEN 10
+#define XRC_CQN_SECOND_LEN 3
+#define SRQ_GPA_SIG_LEN 3
+#define SRQ_WQEBB_SIZE_CAL_SECTTOR \
+ 4 /* (2^rq_wqebb_size)*16B => divide 16 means shift need to minus 4 */
+#define RDMA_PREFETCH_WQE_MAX 7
+#define RDMA_PREFETCH_MTT_LEN_MAX 3
+#define ROCE_WQE_BB_SIZE_MIN 64
+
+#define LAST_SGE_NO_PRESENT \
+ 0x80000000UL /* Lbit:0 - The next SGE is present in the list \
+ * Lbit:1 - The last SGE, no SGE is present in the list */
+#define NORMAL_FMT_AND_NEXT_SGE_PRESENT \
+ 0x3FFFFFFFUL /* Ebit:b0 - Normal format, without extension. \
+ * Ebit:b1 - The pointer inside of SGE points to the next SGL. \
+ * "Length" and "Key" fields are */
+#define NORMAL_FMT_AND_LAST_SGE_NO_PRESENT 0xBFFFFFFFUL
+
+/**
+ * CHIP container_mode:
+ * chip mode: 0 -> Not container
+ * chip mode: 1 -> container_size: 2
+ * chip mode: 2 -> container_size: 4
+ * chip mode: 3 -> container_size: 8
+ * chip mode: 4 -> container_size: 16
+ */
+enum roce5_chip_srq_mode {
+ ROCE_CHIP_SRQ_MODE_N = 0,
+ ROCE_CHIP_SRQ_MODE_1,
+ ROCE_CHIP_SRQ_MODE_2,
+ ROCE_CHIP_SRQ_MODE_3,
+ ROCE_CHIP_SRQ_MODE_4
+};
+
+enum srq_state {
+ ROCE_SRQ_STATE_INVALID = 0x0,
+ ROCE_SRQ_STATE_ERR = 0x1,
+ ROCE_SRQ_STATE_VALID = 0xf,
+ ROCE_SRQ_STATE_MEM_INIT = 0xa
+};
+
+#define ROCE_SRQ_STATE_CHECK_VALUE 0x0
+
+struct roce5_wqe_srq_next_seg {
+ u16 reserved1;
+ __be16 pcnt; /* indicate the pi */
+ u8 signature;
+ u8 reserved2;
+ __be16 next_wqe_index;
+ u32 reserved3[2];
+};
+
+struct roce5_wqe_container_srq_next_seg {
+ u32 next_gpa_h;
+
+ struct {
+ u32 rsvd : 11;
+ u32 next_gpa_vd : 1;
+ u32 next_gpa_h : 20; /* indicate the pi */
+ } dw1;
+
+ struct {
+ u32 next_idx : 16;
+ u32 rsvd : 16;
+ } dw2;
+
+ struct {
+ u32 rsvd2 : 30;
+ u32 link_flag : 1;
+ u32 rsvd : 1;
+ } dw3;
+
+ struct {
+ u32 osd_next_idx : 16;
+ u32 osd_cur_idx : 16;
+ } dw4;
+};
+
+#define ROCE_SRQ_SGE_LAST 1
+#define ROCE_SRQ_SGE_NLAST 0
+
+#define ROCE_SRQ_SGE_LKEY_NOEXT 0
+#define ROCE_SRQ_SGE_LKEY_EXT 1
+
+struct roce5_srq {
+ struct ib_srq ibsrq; /* ibsrq */
+ cqm_queue_s *cqm_srq;
+
+ u32 srqn;
+ int max_depth;
+ int max_gs;
+ int wqe_shift;
+
+ cqm_buf_s *buf;
+ struct roce5_db db;
+ u64 *wrid;
+ spinlock_t lock;
+ int head;
+ int tail;
+ u16 wqe_ctr;
+ u8 xrc_en;
+ u8 rsvd;
+ struct ib_umem *umem;
+ struct mtt mtt;
+ struct mutex mutex;
+ u32 rqe_cnt_th;
+ u8 container_flag;
+ u8 container_size;
+ u8 container_mode;
+ u8 container_warn_th;
+
+ int buf_sz;
+};
+
+static inline u8 roce5_srq_get_max_sge(struct roce5_srq *rsrq)
+{
+ if (rsrq->container_flag != 0) {
+ return ROCE_SRQ_CONT_MAX_SGE;
+ }
+ return ROCE_SRQ_MAX_SGE;
+}
+
+static inline int roce5_srq_init_wqe_size(struct roce5_srq *rsrq)
+{
+ int desc_size = 0;
+
+ if (rsrq->container_flag != 0) {
+ desc_size = rsrq->max_gs * sizeof(struct roce_wqe_srq_data_seg);
+ } else {
+ desc_size = sizeof(struct roce5_wqe_srq_next_seg) +
+ rsrq->max_gs * sizeof(struct roce_wqe_srq_data_seg);
+ }
+ desc_size = (int)(ROCE_ROUNDUP_POW_OF_TWO((u32)desc_size));
+ desc_size = ROCE_MAX(ROCE_WQE_BB_SIZE_MIN, desc_size);
+
+ rsrq->wqe_shift = (int)ROCE_ILOG2((unsigned)desc_size);
+ return desc_size;
+}
+
+void roce5_free_srq_wqe(struct roce5_srq *srq, int wqe_index);
+void roce5_srq_async_event(struct roce5_device *rdev, struct roce5_srq *srq,
+ int type);
+void *roce5_srq_get_wqe(struct roce5_srq *srq, int n);
+u8 roce5_get_container_sz(u32 container_mode);
+u32 roce5_srq_max_avail_wr_set(struct roce5_srq *rsrq);
+int roce5_create_srq_common(struct roce5_device *rdev, struct roce5_srq *rsrq,
+ struct roce5_pd *pd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata, u32 index);
+struct roce5_srq *roce5_get_rsrq_by_srqn(struct roce5_device *rdev, u32 srqn);
+static inline void roce5_rsrq_put(struct roce5_srq *rsrq)
+{
+ if (rsrq == NULL) {
+ return;
+ }
+ cqm5_object_put(&rsrq->cqm_srq->object);
+}
+
+#endif //ROCE_SRQ_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_comm.c b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_comm.c
new file mode 100644
index 000000000..0a3beb338
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_comm.c
@@ -0,0 +1,116 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "roce.h"
+#include "roce_compat.h"
+#include "roce_xrc.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_aeq_format.h"
+#include "roce_srq_extension.h"
+#include "roce_restore.h"
+
+static void *roce5_srq_buf_offset(struct tag_cqm_buf *buf, int offset)
+{
+ return (void *)((char *)buf->direct.va + offset);
+}
+
+void *roce5_srq_get_wqe(struct roce5_srq *srq, int n)
+{
+ return roce5_srq_buf_offset(srq->buf,
+ (int)((u32)n << (unsigned)srq->wqe_shift));
+}
+
+void roce5_srq_async_event(struct roce5_device *rdev, struct roce5_srq *srq,
+ int type)
+{
+ struct ib_srq *ibsrq = &srq->ibsrq;
+ struct ib_event event;
+ int ret;
+
+ ret = memset_s(&event, sizeof(event), 0, sizeof(event));
+ if (ret != 0) {
+ ROCE_DEV_ERR_LIMIT(rdev, "Failed to memset event.(ret:%d)",
+ ret);
+ }
+ if (ibsrq->event_handler) {
+ event.device = ibsrq->device;
+ event.element.srq = ibsrq;
+ switch (type) {
+ case ROCE_EVENT_TYPE_SRQ_LIMIT:
+ event.event = IB_EVENT_SRQ_LIMIT_REACHED;
+ break;
+
+ case ROCE_EVENT_TYPE_SRQ_CATAS_ERROR:
+ event.event = IB_EVENT_SRQ_ERR;
+ break;
+
+ default:
+ ROCE_DEV_WARN_LIMIT(
+ rdev,
+ "unexpected event type(%d) on SRQ(%06x), func_id(%d)",
+ type, srq->srqn, rdev->glb_func_id);
+ return;
+ }
+
+ ibsrq->event_handler(&event, ibsrq->srq_context);
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_free_srq_wqe
+ Description : roce5_free_srq_wqe
+ Input : struct roce5_srq *srq
+ int wqe_index
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+void roce5_free_srq_wqe(struct roce5_srq *srq, int wqe_index)
+{
+ struct roce5_wqe_srq_next_seg *next = NULL;
+
+ spin_lock(&srq->lock);
+
+ next = (struct roce5_wqe_srq_next_seg *)roce5_srq_get_wqe(srq,
+ srq->tail);
+ next->next_wqe_index = (u16)wqe_index;
+ srq->tail = wqe_index;
+
+ spin_unlock(&srq->lock);
+}
+
+/**
+ * @brief Get roce srq by srqn. When querying succeeded, you have to call roce5_rsrq_put() to free
+ the cqm_obj_srq. But there is no need to call roce5_rsrq_put() if querying failed.
+ * @return Success: return the roce srq. Failure: return NULL.
+ */
+struct roce5_srq *roce5_get_rsrq_by_srqn(struct roce5_device *rdev, u32 srqn)
+{
+ cqm_object_s *cqm_obj_srq = NULL;
+ struct roce5_srq *rsrq = NULL;
+
+ cqm_obj_srq =
+ cqm5_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SRQ, srqn, false);
+ if (cqm_obj_srq == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Can't find srq according to srqn(%u), func_id(%d).",
+ srqn, rdev->glb_func_id);
+ return NULL;
+ }
+
+ rsrq = cqmobj_to_roce5_srq(cqm_obj_srq);
+ if (rsrq == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to convert obj to rsrq.");
+ cqm5_object_put(cqm_obj_srq);
+ }
+
+ return rsrq;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_create.c b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_create.c
new file mode 100644
index 000000000..47c86b2fa
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_create.c
@@ -0,0 +1,712 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/kernel.h>
+
+#include "comm_defs.h"
+#include "roce.h"
+#include "roce_cq.h"
+#include "roce_cqm_cmd.h"
+#include "roce_user.h"
+#include "roce_xrc.h"
+#include "roce_pd.h"
+#include "roce_srq.h"
+#include "roce_restore.h"
+#include "roce_npu_cmd_srq_defs.h"
+#include "roce_npu_cmd_defs.h"
+
+#include "roce_srq_extension.h"
+#include "roce_main_extension.h"
+#include "hinic5_hmm.h"
+#include "roce_npu_cmd.h"
+#include "securec.h"
+#include "roce_os_compat.h"
+
+/* ****************************************************************************
+ Prototype : roce5_srq_sw2hw
+ Description : roce5_srq_sw2hw
+ Input : struct roce5_device *rdev
+ struct roce5_srq *rsrq
+ u32 pdn
+ u32 cqn
+ u16 xrcdn
+ int page_shift
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+ 1.Date : 2015/7/27
+ Modification : modify function
+**************************************************************************** */
+static void roce5_srq_sw2hw_set(roce_verbs_srq_attr_s *srq_attr,
+ struct roce5_srq *rsrq, u32 pdn, u32 cqn,
+ u16 xrcdn, int page_shift)
+{
+ srq_attr->dw0.bs.size = (u32)(ROCE_ILOG2((unsigned)rsrq->max_depth));
+ srq_attr->dw0.bs.page_size = (u32)page_shift;
+ srq_attr->dw0.bs.wqebb_size =
+ (u32)rsrq->wqe_shift - SRQ_WQEBB_SIZE_CAL_SECTTOR;
+ srq_attr->dw0.bs.mtt_page_size =
+ rsrq->mtt.mtt_page_shift - PAGE_SHIFT_4K;
+ srq_attr->dw0.bs.xrcd = xrcdn;
+
+ srq_attr->dw1.bs.dma_attr_idx = 0;
+ srq_attr->dw1.bs.so_ro = 1;
+ srq_attr->dw1.bs.state = ROCE_SRQ_STATE_VALID;
+
+ srq_attr->dw3.bs.container = rsrq->container_flag;
+ srq_attr->dw3.bs.lth_pre_en =
+ (rsrq->container_flag == 0); //rdma engine prefetch
+ srq_attr->dw3.bs.pcnt_on_chip = 0;
+ srq_attr->dw3.bs.rkey_en = 1;
+ srq_attr->dw3.bs.pd = pdn;
+
+ srq_attr->srqn = cpu_to_be32(rsrq->srqn);
+ srq_attr->xrc_cqn = cpu_to_be32(cqn);
+
+ if (rsrq->container_flag == 0) { //normal srq
+ srq_attr->dw1.bs.ep = 0;
+ srq_attr->dw1.bs.cos = 0;
+
+ srq_attr->dw2.value = 0;
+ srq_attr->dw2.bs.wqe_prefetch_max_num =
+ RDMA_PREFETCH_WQE_MAX; //rdma engine wqe prefetch max num
+ srq_attr->dw2.bs.wqecnt_lth = 0xe;
+ srq_attr->dw2.bs.mtt_prefetch_maxlen =
+ 0; //rdma engine mtt prefetch max len
+
+ srq_attr->dw3.bs.lth_pre_en = 1; //rdma engine prefetch
+ srq_attr->dw3.bs.lth_gap = 0;
+ } else {
+ srq_attr->cont.dw2.bs.head_idx = 0;
+ srq_attr->cont.dw2.bs.warn_th =
+ 0; //Do NOT init warn_th until user arm srq
+ srq_attr->cont.dw2.bs.cont_size =
+ (MAX_SUPPORT_CONTAINER_MODE - rsrq->container_mode) &
+ 0x3;
+ srq_attr->cont.dw2.value =
+ cpu_to_be32(srq_attr->cont.dw2.value);
+ srq_attr->record_gpa_at_hop_num =
+ cpu_to_be64((rsrq->mtt.mtt_layers & 0x3));
+ }
+
+ srq_attr->dw0.value = cpu_to_be32(srq_attr->dw0.value);
+ srq_attr->dw1.value = cpu_to_be32(srq_attr->dw1.value);
+ srq_attr->dw2.value = cpu_to_be32(srq_attr->dw2.value);
+ srq_attr->dw3.value = cpu_to_be32(srq_attr->dw3.value);
+
+ srq_attr->l0mtt_gpa = rsrq->mtt.mtt_paddr;
+
+ srq_attr->l0mtt_gpa = cpu_to_be64(srq_attr->l0mtt_gpa);
+
+ srq_attr->record_gpa_at_hop_num =
+ cpu_to_be64(rsrq->db.dma | (rsrq->mtt.mtt_layers & 0x3));
+
+ return;
+}
+
+static int roce5_srq_sw2hw(struct roce5_device *rdev, struct roce5_srq *rsrq,
+ u32 pdn, u32 cqn, u16 xrcdn, int page_shift)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_verbs_srq_attr_s *srq_attr = NULL;
+ roce_uni_cmd_create_srq_s *srq_sw2hw_inbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_create_srq_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ srq_sw2hw_inbuf = (roce_uni_cmd_create_srq_s *)cqm_cmd_inbuf->buf;
+ srq_sw2hw_inbuf->com.index = cpu_to_be32((u32)rsrq->srqn);
+ srq_sw2hw_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SRQ_BITMASK));
+ srq_attr = &srq_sw2hw_inbuf->srq_attr;
+
+ roce5_srq_sw2hw_set(srq_attr, rsrq, pdn, cqn, xrcdn, page_shift);
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_SW2HW_SRQ, cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send SW2HW_SRQ command, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+
+ /* update dev status after cmdq timeout or exception, notify PCIe reset */
+ if ((ret == -ETIMEDOUT) || (ret == -EPERM)) {
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+
+ ret = -1;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+static int roce5_create_srq_check(const struct ib_pd *ibpd,
+ const struct ib_srq_init_attr *init_attr,
+ const struct roce5_srq *rsrq)
+{
+ struct roce5_device *rdev = NULL;
+
+ if ((ibpd == NULL) || (init_attr == NULL)) {
+ ROCE_ERR("Ibpd or init_attr is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibpd->device);
+ if ((init_attr->attr.max_wr >
+ (u32)rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_srq_wqes) ||
+ (init_attr->attr.max_sge >
+ ((u32)rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_srq_sge +
+ rsrq->container_flag))) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid input parms, max_wr(%d), max_srq_wqes(%d), max_sge(%d), max_srq_sge(%d)",
+ init_attr->attr.max_wr,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_srq_wqes,
+ init_attr->attr.max_sge,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_srq_sge);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_create_srq_write_mtt_and_db(struct roce5_device *rdev,
+ struct roce5_srq *rsrq,
+ struct roce5_create_srq_cmd *ucmd,
+ struct roce5_pd *pd)
+{
+ int ret = 0;
+
+ ret = roce5_umem_write_mtt(rdev, &rsrq->mtt, rsrq->umem, 1);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write mtt, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce5_db_map_user(to_roce5_ucontext(pd->ibpd.uobject->context),
+ ucmd->db_addr, &rsrq->db, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to map db to user space, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int roce5_create_srq_get_umem(struct roce5_create_srq_cmd *ucmd,
+ struct ib_udata *udata,
+ struct roce5_srq *rsrq,
+ struct roce5_device *rdev,
+ struct roce5_pd *pd)
+{
+ int ret = 0;
+
+ if (ib_copy_from_udata(ucmd, udata, sizeof(*ucmd)) != 0) {
+ ret = -EFAULT;
+ ROCE_DEV_ERR(rdev,
+ "Failed to copy from user space, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ rsrq->umem = roce5_umem_get(&rdev->ib_dev, pd->ibpd.uobject->context,
+ ucmd->buf_addr, (size_t)rsrq->buf_sz, 0, 0);
+ if (IS_ERR(rsrq->umem)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to get ib_umem, func_id(%d) rsrq->buf_sz:%u",
+ rdev->glb_func_id, rsrq->buf_sz);
+ ret = (int)PTR_ERR(rsrq->umem);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int roce5_create_user_srq_update(struct roce5_device *rdev,
+ struct roce5_srq *rsrq,
+ struct roce5_pd *pd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata, int page_shift)
+{
+ u32 cqn = 0;
+ u16 xrcdn = 0;
+ int ret = 0;
+
+ cqn = (u32)((init_attr->srq_type == IB_SRQT_XRC) ?
+ to_roce5_cq(init_attr->ext.cq)->cqn :
+ 0);
+ xrcdn = (init_attr->srq_type == IB_SRQT_XRC) ?
+ (u16)(to_roce5_xrcd(init_attr->ext.xrc.xrcd)->xrcdn) :
+ (u16)rdev->rdma_cap.reserved_xrcds;
+
+ /* set SRQC */
+ ret = roce5_srq_sw2hw(rdev, rsrq, pd->pdn, cqn, xrcdn,
+ (page_shift - PAGE_SHIFT_4K));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to handle srq_sw2hw, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_unmap;
+ }
+
+ rsrq->ibsrq.ext.xrc.srq_num = (u32)rsrq->srqn;
+
+ if (ib_copy_to_udata(udata, &rsrq->srqn, sizeof(u32)) != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to copy data to user space, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -EFAULT;
+ goto err_unmap;
+ }
+
+ return 0;
+
+err_unmap:
+ roce5_db_unmap_user(to_roce5_ucontext(pd->ibpd.uobject->context),
+ &rsrq->db, 0);
+ return ret;
+}
+
+u32 roce5_srq_max_avail_wr_set(struct roce5_srq *rsrq)
+{
+ u32 link_wqe_count = 0;
+
+ if (rsrq->container_flag != 0) {
+ link_wqe_count = (u32)rsrq->max_depth / rsrq->container_size;
+ return ((u32)rsrq->max_depth - link_wqe_count) -
+ (rsrq->container_size - 1);
+ } else {
+ return (u32)rsrq->max_depth - 1;
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_create_user_srq
+ Description : roce5_create_user_srq
+ Input : struct roce5_device *rdev
+ struct roce5_srq *rsrq
+ struct roce5_pd *pd
+ struct ib_srq_init_attr *init_attr
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_create_user_srq(struct roce5_device *rdev,
+ struct roce5_srq *rsrq, struct roce5_pd *pd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata, u32 index)
+{
+ int ret = 0;
+ u32 npages = 0;
+ int page_shift = 0;
+ struct roce5_create_srq_cmd ucmd = { 0 };
+
+ /* dispatch SRQN and SRQC */
+ rsrq->cqm_srq = cqm5_object_rdma_queue_create(rdev->hwdev,
+ SERVICE_T_ROCE,
+ CQM_OBJECT_RDMA_SRQ, 0,
+ rsrq, false, index, 0, 0);
+ if (rsrq->cqm_srq == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create rdma queue by cqm_object, func_id(%d) index(%d)",
+ rdev->glb_func_id, index);
+ return (-ENOMEM);
+ }
+
+ rsrq->srqn = rsrq->cqm_srq->index;
+
+ ret = roce5_create_srq_get_umem(&ucmd, udata, rsrq, rdev, pd);
+ if (ret != 0) {
+ goto err_free_cqm_srq;
+ }
+
+ page_shift =
+ roce5_umem_get_buf_page_shift(rdev, rsrq->umem, ucmd.buf_addr);
+ npages = roce5_umem_get_mtt_npages(rdev, rsrq->umem, (u32)page_shift);
+
+ rsrq->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_mtt_alloc(rdev->hwdev, npages, (u32)page_shift, &rsrq->mtt,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, " Failed to alloc rdma_mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_release_umem;
+ }
+
+ ret = roce5_create_srq_write_mtt_and_db(rdev, rsrq, &ucmd, pd);
+ if (ret != 0) {
+ goto err_free_mtt;
+ }
+
+ ret = roce5_create_user_srq_update(rdev, rsrq, pd, init_attr, udata,
+ page_shift);
+ if (ret != 0) {
+ goto err_free_mtt;
+ }
+
+ init_attr->attr.max_wr = roce5_srq_max_avail_wr_set(rsrq);
+
+ return 0;
+
+err_free_mtt:
+ hmm_mtt_free(rdev->hwdev, &rsrq->mtt, SERVICE_T_ROCE);
+
+err_release_umem:
+ ib_umem_release(rsrq->umem);
+
+err_free_cqm_srq:
+ cqm5_object_delete(&rsrq->cqm_srq->object);
+
+ return ret;
+}
+
+static void roce5_get_cqn_xrcdn(u32 *cqn, u16 *xrcdn,
+ struct ib_srq_init_attr *init_attr,
+ struct roce5_device *rdev)
+{
+ *cqn = (u32)((init_attr->srq_type == IB_SRQT_XRC) ?
+ to_roce5_cq(init_attr->ext.cq)->cqn :
+ 0);
+ *xrcdn = (init_attr->srq_type == IB_SRQT_XRC) ?
+ (u16)(to_roce5_xrcd(init_attr->ext.xrc.xrcd)->xrcdn) :
+ (u16)rdev->rdma_cap.reserved_xrcds;
+}
+
+static int roce5_create_kernel_srq_update(struct roce5_device *rdev,
+ struct roce5_srq *rsrq,
+ struct roce5_pd *pd,
+ struct ib_srq_init_attr *init_attr,
+ int page_shift)
+{
+ u32 cqn = 0;
+ u16 xrcdn = 0;
+ int ret;
+ ret = roce5_buf_write_mtt(rdev, &rsrq->mtt, rsrq->buf);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_free_mtt;
+ }
+
+ rsrq->wrid = (u64 *)kmalloc(
+ (size_t)((u32)rsrq->max_depth * sizeof(u64)), GFP_KERNEL);
+ if (rsrq->wrid == NULL) {
+ rsrq->wrid = (u64 *)vzalloc(
+ (size_t)((u32)rsrq->max_depth * sizeof(u64)));
+ if (rsrq->wrid == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc srq wrid, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -ENOMEM;
+ goto err_free_mtt;
+ }
+ }
+
+ roce5_get_cqn_xrcdn(&cqn, &xrcdn, init_attr, rdev);
+
+ ret = roce5_srq_sw2hw(rdev, rsrq, pd->pdn, cqn, xrcdn,
+ (page_shift - PAGE_SHIFT_4K));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to handle srq sw2hw, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_free_wrid;
+ }
+
+ return 0;
+
+err_free_wrid:
+ kvfree(rsrq->wrid);
+ rsrq->wrid = NULL;
+
+err_free_mtt:
+ hmm_mtt_free(rdev->hwdev, &rsrq->mtt, SERVICE_T_ROCE);
+
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_create_kernel_srq
+ Description : roce5_create_kernel_srq
+ Input : struct roce5_device *rdev
+ struct roce5_srq *rsrq
+ struct roce5_pd *pd
+ struct ib_srq_init_attr *init_attr
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_create_kernel_srq(struct roce5_device *rdev,
+ struct roce5_srq *rsrq, struct roce5_pd *pd,
+ struct ib_srq_init_attr *init_attr,
+ u32 index)
+{
+ int i = 0;
+ int ret = 0;
+ int page_shift = 0;
+ struct roce5_wqe_srq_next_seg *next = NULL;
+ struct roce_wqe_srq_data_seg *scatter = NULL;
+
+ /* alloc queue Buf/ Soft DB/SRQN/SRQC */
+ rsrq->cqm_srq = cqm5_object_rdma_queue_create(
+ rdev->hwdev, SERVICE_T_ROCE, CQM_OBJECT_RDMA_SRQ,
+ (u32)rsrq->buf_sz, rsrq, true, index, 0, 0);
+ if (rsrq->cqm_srq == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create rdma queue by cqm_object, func_id(%d)",
+ rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ rsrq->srqn = rsrq->cqm_srq->index;
+ rsrq->buf = &rsrq->cqm_srq->q_room_buf_1;
+
+ /* set Soft DB */
+ rsrq->db.db_record = (__be32 *)(void *)(&rsrq->cqm_srq->q_header_vaddr
+ ->doorbell_record);
+ rsrq->db.dma = rsrq->cqm_srq->q_header_paddr;
+ *rsrq->db.db_record = 0;
+
+ rsrq->head = 0;
+ rsrq->tail = rsrq->max_depth - 1;
+ rsrq->wqe_ctr = 0;
+
+ for (i = 0; i < rsrq->max_depth; ++i) {
+ next = (struct roce5_wqe_srq_next_seg *)roce5_srq_get_wqe(rsrq,
+ i);
+ next->next_wqe_index = cpu_to_be16(
+ (u16)((u32)(i + 1) & (u32)(rsrq->max_depth - 1)));
+
+ scatter = (struct roce_wqe_srq_data_seg *)(next + 1);
+ scatter->dw2.length = 0;
+
+ /* first SGE = last SGE */
+ scatter->dw3.lkey = LAST_SGE_NO_PRESENT;
+ scatter->dw3.lkey = cpu_to_be32(scatter->dw3.lkey);
+ }
+
+ page_shift = (int)ROCE_ILOG2(rsrq->buf->buf_size);
+ rsrq->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_mtt_alloc(rdev->hwdev, rsrq->buf->buf_number, (u32)page_shift,
+ &rsrq->mtt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc rdma rdma_mtt, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_free_cqm_srq;
+ }
+
+ ret = roce5_create_kernel_srq_update(rdev, rsrq, pd, init_attr,
+ page_shift);
+ if (ret != 0) {
+ goto err_free_cqm_srq;
+ }
+
+ rsrq->ibsrq.ext.xrc.srq_num = (u32)rsrq->srqn;
+ init_attr->attr.max_wr = (u32)rsrq->max_depth - 1;
+ return 0;
+
+err_free_cqm_srq:
+ cqm5_object_delete(&rsrq->cqm_srq->object);
+
+ return ret;
+}
+
+static void roce5_set_srq_depth(struct ib_srq_init_attr *init_attr,
+ struct roce5_srq *rsrq)
+{
+ u32 link_wqe_count = 0;
+ u32 remain_wqe_count = 0;
+
+ /*
+ * +---+---+---+---+---+---+---+---+
+ * |wqe|wqe|wqe|wqe|wqe|wqe|wqe|nil|
+ * +---+---+---+---+---+---+---+---+
+ * ^
+ * |
+ * full condition:head==tail==nil
+ */
+ if (rsrq->container_flag != 0) {
+ link_wqe_count =
+ init_attr->attr.max_wr / (rsrq->container_size - 1u);
+ remain_wqe_count =
+ init_attr->attr.max_wr % (rsrq->container_size - 1u);
+ link_wqe_count +=
+ ((remain_wqe_count == 0) ?
+ 0 :
+ (rsrq->container_size - remain_wqe_count));
+ rsrq->max_depth = (int)(init_attr->attr.max_wr +
+ link_wqe_count + rsrq->container_size);
+ } else {
+ rsrq->max_depth = (int)(init_attr->attr.max_wr + 1);
+ }
+ rsrq->max_depth =
+ (int)((ROCE_ROUNDUP_POW_OF_TWO((u32)rsrq->max_depth)) &
+ 0xffffffff);
+}
+
+static void roce5_rsrq_init(struct ib_srq_init_attr *init_attr,
+ struct roce5_srq *rsrq, struct roce5_device *rdev)
+{
+ int buf_size = 0;
+ int desc_size = 0;
+
+ roce5_srq_container_init(init_attr, rsrq, rdev);
+
+ mutex_init(&rsrq->mutex);
+ spin_lock_init(&rsrq->lock);
+
+ roce5_set_srq_depth(init_attr, rsrq);
+
+ rsrq->max_gs = (init_attr->attr.max_sge <= ROCE_SRQ_MIN_SGE) ?
+ ROCE_SRQ_MIN_SGE :
+ ((init_attr->attr.max_sge <= ROCE_SRQ_MID_SGE) ?
+ ROCE_SRQ_MID_SGE :
+ roce5_srq_get_max_sge(rsrq));
+ init_attr->attr.max_sge = (u32)rsrq->max_gs;
+
+ /* 0 <= max_gs <= 3, desc_size = 64
+ * 4 <= max_gs <= 7, desc_size = 128
+ */
+ desc_size = roce5_srq_init_wqe_size(rsrq);
+ buf_size = rsrq->max_depth * desc_size;
+
+ /* WQEBB align 1 PAGE */
+ if (buf_size < (int)PAGE_SIZE) {
+ rsrq->max_depth =
+ (int)((u64)PAGE_SIZE >> (unsigned int)rsrq->wqe_shift);
+ }
+
+ /* align with PAGE SIZE */
+ buf_size = (int)ROCE_ALIGN((u32)buf_size, PAGE_SIZE);
+ rsrq->buf_sz = buf_size;
+
+ ROCE_DEV_INFO(
+ rdev,
+ "RoCE srq mode: container_EN(%d), container_mode(%d), XRC_EN(%d), MAX_DEPTH(%d), MAX_SGE(%d), desc_size(%d)",
+ rsrq->container_flag, rsrq->container_mode, rsrq->xrc_en,
+ rsrq->max_depth, rsrq->max_gs, desc_size);
+}
+
+int roce5_create_srq_common(struct roce5_device *rdev, struct roce5_srq *rsrq,
+ struct roce5_pd *pd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata, u32 index)
+{
+ int ret;
+ roce5_rsrq_init(init_attr, rsrq, rdev);
+
+ ret = roce5_create_srq_check(&pd->ibpd, init_attr, rsrq);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to check srq info");
+ return ret;
+ }
+
+ if (rsrq->ibsrq.uobject != NULL) {
+ ret = roce5_create_user_srq(rdev, rsrq, pd, init_attr, udata,
+ index);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to create user srq, func_id(%d), index(%d)",
+ rdev->glb_func_id, index);
+ }
+ } else {
+ ret = roce5_create_kernel_srq(rdev, rsrq, pd, init_attr, index);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to create kernel srq, func_id(%d)",
+ rdev->glb_func_id);
+ }
+ }
+
+ ROCE_DEV_INFO(
+ rdev,
+ "SRQ create:srqn:%d,container_en_mode:%d_%d,xrc_en:%d,max_depth:%d",
+ rsrq->srqn, rsrq->container_flag, rsrq->container_mode,
+ rsrq->xrc_en, rsrq->max_depth);
+
+ return ret;
+}
+
+int roce5_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ struct roce5_pd *pd = NULL;
+ struct roce5_device *rdev = NULL;
+ struct roce5_srq *rsrq = NULL;
+
+ if ((ibsrq == NULL) || (init_attr == NULL)) {
+ ROCE_ERR("Input pointer is NULL");
+ return (-EINVAL);
+ }
+
+ pd = to_roce5_pd(ibsrq->pd);
+ rdev = to_roce5_dev(ibsrq->device);
+ rsrq = to_roce5_srq(ibsrq);
+
+ return roce5_create_srq_common(rdev, rsrq, pd, init_attr, udata,
+ ROCE_SRQN_INVLD);
+}
+
+struct ib_srq *roce5_create_srq_ofa(struct ib_pd *ibpd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_srq *rsrq = NULL;
+
+ if (ibpd == NULL) {
+ ROCE_ERR("Ibpd is null");
+ return ERR_PTR(-EINVAL);
+ }
+
+ rsrq = (struct roce5_srq *)kzalloc(sizeof(struct roce5_srq),
+ GFP_KERNEL);
+ if (rsrq == NULL) {
+ ROCE_ERR("Failed to alloc srq");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Unreasonable, but for code reuse, driver associate the OFED resource in advance. */
+ rsrq->ibsrq.pd = ibpd;
+ rsrq->ibsrq.device = ibpd->device;
+#if defined(IB_SRQ_HAVE_UOBJECT)
+ rsrq->ibsrq.uobject =
+ (udata ? ibpd->uobject :
+ NULL); /* udata not NULL means user srq create */
+#endif
+ ret = roce5_create_srq(&rsrq->ibsrq, init_attr, udata);
+ if (ret != 0) {
+ kfree(rsrq);
+ return ERR_PTR(ret);
+ }
+
+ return &rsrq->ibsrq;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_ctrl.c b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_ctrl.c
new file mode 100644
index 000000000..887a857ad
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_ctrl.c
@@ -0,0 +1,635 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "comm_defs.h"
+#include "roce.h"
+#include "roce_compat.h"
+#include "roce_user.h"
+#include "roce_xrc.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_mix.h"
+#include "roce_cqm_cmd.h"
+#include "roce_restore.h"
+#include "hinic5_hmm.h"
+#include "roce_main_extension.h"
+#include "roce_srq_extension.h"
+#include "roce_npu_cmd.h"
+#include "roce_com.h"
+#include "securec.h"
+#include "roce_os_compat.h"
+
+/* and above next is V100 compatible data structure */
+typedef struct tag_roce_cmd_srq_arm {
+ roce_verbs_cmd_com_s com;
+ union {
+ u32 limitwater;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 lwm : 16;
+ u32 warth : 4;
+ u32 th_up_en : 1;
+ u32 cont_en : 1;
+ u32 rsvd : 10;
+#else
+ u32 rsvd : 10;
+ u32 cont_en : 1;
+ u32 th_up_en : 1;
+ u32 warth : 4;
+ u32 lwm : 16;
+#endif
+ } bs;
+ };
+} roce_cmd_srq_arm_s;
+
+typedef struct tag_roce_cmd_srq_hw2sw {
+ roce_verbs_cmd_com_s com;
+ roce_xq_mtt_info_s mtt_info;
+ u32 srq_buf_len;
+ u32 wqe_cache_line_start;
+ u32 wqe_cache_line_end;
+ u32 wqe_cache_line_size;
+} roce_cmd_srq_hw2sw_s;
+
+static u8 roce5_cal_srq_container_num(u32 avail_wr, struct roce5_srq *srq)
+{
+ u32 container_num = 0;
+ u32 srqe_num = 0;
+
+ /* cal container_num by avail_wr from user */
+ srqe_num = srq->container_size - 1;
+
+ /* explain the formula: round up by srqe_num */
+ container_num = (avail_wr + srqe_num - 1) / srqe_num;
+ return roce5_calculate_cont_th(container_num);
+}
+
+static void roce5_srq_arm_config_cqm_cmd(cqm_cmd_buf_s *cqm_cmd_inbuf,
+ struct roce5_srq *srq, u32 srq_limit,
+ u8 *warth)
+{
+ roce_uni_cmd_srq_arm_s *srq_arm_inbuf = NULL;
+
+ srq_arm_inbuf = (roce_uni_cmd_srq_arm_s *)cqm_cmd_inbuf->buf;
+ srq_arm_inbuf->com.index = cpu_to_be32((u32)(srq->srqn));
+ srq_arm_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_SRQ_BITMASK);
+ if (srq->container_flag != 0) {
+ srq_arm_inbuf->srq_arm.bs.cont_en = srq->container_flag;
+ srq_arm_inbuf->srq_arm.bs.th_up_en =
+ 1; //Valid for setting up container warn_threshold
+ *warth = roce5_cal_srq_container_num(srq_limit, srq);
+ srq_arm_inbuf->srq_arm.bs.warth = *warth &
+ ROCE_SRQ_CONTAINER_WARTH_MASK;
+ srq_arm_inbuf->srq_arm.limitwater =
+ cpu_to_be32(srq_arm_inbuf->srq_arm.limitwater);
+ } else {
+ srq_arm_inbuf->srq_arm.bs.lwm = srq_limit;
+ srq_arm_inbuf->srq_arm.limitwater =
+ cpu_to_be32(srq_arm_inbuf->srq_arm.limitwater);
+ }
+}
+
+/* ****************************************************************************
+ Prototype : roce5_srq_arm
+ Description : roce5_srq_arm
+ Input : struct roce5_device *rdev
+ struct roce5_srq *srq
+ u32 srq_limit
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_srq_arm(struct roce5_device *rdev, struct roce5_srq *srq,
+ u32 srq_limit)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ uint8_t warth = 0;
+ uint16_t inbuf_size = 0;
+
+ if (ROCE5_SUPPORT_IB_CMD_MODIFY_SRQ_MSG_V2(rdev) != 0) {
+ inbuf_size = sizeof(roce_uni_cmd_srq_arm_s);
+ }
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ inbuf_size, NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ if (ROCE5_SUPPORT_IB_CMD_MODIFY_SRQ_MSG_V2(rdev) != 0) {
+ roce5_srq_arm_config_cqm_cmd(cqm_cmd_inbuf, srq, srq_limit,
+ &warth);
+ }
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE, ROCE_CMD_ARM_SRQ,
+ cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "send ARM_SRQ command Failed, ret(%d), func_id(%d), warth(%d)",
+ ret, rdev->glb_func_id, warth);
+
+ if ((ret == -ETIMEDOUT) || (ret == -EPERM)) {
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+ ret = -1;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_modify_srq
+ Description : roce5_modify_srq
+ Input : struct ib_srq *ibsrq
+ struct ib_srq_attr *attr
+ enum ib_srq_attr_mask attr_mask
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce5_device *rdev = NULL;
+ struct roce5_srq *srq = NULL;
+ struct roce5_modify_srq_cmd ucmd = { 0 };
+ u32 max_avail_wr = 0;
+
+ if ((ibsrq == NULL) || (attr == NULL)) {
+ ROCE_ERR("Ibsrq or attr is null");
+ return (-EINVAL);
+ }
+
+ if (((unsigned int)attr_mask & IB_SRQ_MAX_WR) != 0) {
+ ROCE_ERR("Not support resizing SRQs");
+ return (-EINVAL);
+ }
+
+ rdev = to_roce5_dev(ibsrq->device);
+ srq = to_roce5_srq(ibsrq);
+
+ if ((udata != NULL) &&
+ (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)) != 0)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "SRQN:(%d), Failed to copy from user space, func_id(%d)",
+ srq->srqn, rdev->glb_func_id);
+ return (-EFAULT);
+ }
+
+ if (((unsigned int)attr_mask & IB_SRQ_LIMIT) != 0) {
+ /* calculate max_wr */
+ max_avail_wr = roce5_srq_max_avail_wr_set(srq);
+ if (attr->srq_limit > max_avail_wr) {
+ ROCE_DEV_ERR(
+ rdev,
+ "srq_limit > max_wr, func_id(%d), max_avail_wr(%d)",
+ rdev->glb_func_id, max_avail_wr);
+ return (-EINVAL);
+ }
+
+ mutex_lock(&srq->mutex);
+ ret = roce5_srq_arm(rdev, srq, attr->srq_limit);
+ mutex_unlock(&srq->mutex);
+
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "[Failed to handle srq arm, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int roce5_cmd_srq_query(struct roce5_device *rdev, struct roce5_srq *srq,
+ u32 *srq_limit)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_srq_query_s *srq_query_inbuf = NULL;
+ roce_uni_cmd_srq_query_outbuf_s *srq_query_outbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_srq_query_s), &cqm_cmd_outbuf,
+ (u16)sizeof(roce_uni_cmd_srq_query_outbuf_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ srq_query_inbuf = (roce_uni_cmd_srq_query_s *)cqm_cmd_inbuf->buf;
+ srq_query_outbuf =
+ (roce_uni_cmd_srq_query_outbuf_s *)cqm_cmd_outbuf->buf;
+ srq_query_inbuf->com.index = cpu_to_be32((u32)srq->srqn);
+ srq_query_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SRQ_BITMASK));
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_QUERY_SRQ, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, NULL, ROCE_CMD_TIME_CLASS_A,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send QUERY_SRQ command, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ if ((ret == -ETIMEDOUT) || (ret == -EPERM)) {
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+
+ ret = -1;
+ goto err_cmd;
+ }
+
+ *srq_limit = be32_to_cpu(srq_query_outbuf->com.srq_limit);
+
+ if (srq->container_flag != 0) {
+ /* parse srqc to get warn_th */
+ u32 warn_th = be32_to_cpu(srq_query_outbuf->com.warn_th);
+ *srq_limit = (warn_th == 0) ? 0 :
+ ((u32)((srq->container_size - 1) *
+ (1U << warn_th)));
+ }
+
+err_cmd:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+
+ return ret;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_query_srq
+ Description : roce5_query_srq
+ Input : struct ib_srq *ibsrq
+ struct ib_srq_attr *srq_attr
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+int roce5_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+ int ret = 0;
+ u32 limit_water = 0;
+ struct roce5_device *rdev = NULL;
+ struct roce5_srq *rsrq = NULL;
+
+ if ((ibsrq == NULL) || (srq_attr == NULL)) {
+ ROCE_ERR("Ibsrq or srq_attr is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibsrq->device);
+ rsrq = to_roce5_srq(ibsrq);
+
+ ret = roce5_cmd_srq_query(rdev, rsrq, &limit_water);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to query srq, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ srq_attr->srq_limit = limit_water;
+ srq_attr->max_wr = roce5_srq_max_avail_wr_set(rsrq);
+ srq_attr->max_sge = (u32)rsrq->max_gs;
+
+ return 0;
+}
+
+static void roce5_srq_hw2sw_config_cqm_cmd(struct roce5_device *rdev,
+ cqm_cmd_buf_s *cqm_cmd_inbuf,
+ struct rdma_service_cap *rdma_cap,
+ struct roce5_srq *srq)
+{
+ roce_uni_cmd_srq_hw2sw_s *srq_hw2sw_inbuf = NULL;
+
+ srq_hw2sw_inbuf = (roce_uni_cmd_srq_hw2sw_s *)cqm_cmd_inbuf->buf;
+ srq_hw2sw_inbuf->com.index = cpu_to_be32((u32)srq->srqn);
+ srq_hw2sw_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SRQ_BITMASK));
+ srq_hw2sw_inbuf->srq_cache.srq_buf_len = cpu_to_be32((u32)srq->buf_sz);
+
+ srq_hw2sw_inbuf->srq_cache.cmtt_cache.mtt_flags = 0;
+ srq_hw2sw_inbuf->srq_cache.cmtt_cache.mtt_num = 0;
+ srq_hw2sw_inbuf->srq_cache.cmtt_cache.mtt_cache_line_start =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_start);
+ srq_hw2sw_inbuf->srq_cache.cmtt_cache.mtt_cache_line_end =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_end);
+ srq_hw2sw_inbuf->srq_cache.wqe_cache_line_size =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_sz);
+
+ srq_hw2sw_inbuf->srq_cache.wqe_cache_line_start =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.wqe_cl_start);
+ srq_hw2sw_inbuf->srq_cache.wqe_cache_line_end =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.wqe_cl_end);
+ srq_hw2sw_inbuf->srq_cache.wqe_cache_line_size =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.wqe_cl_sz);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_srq_hw2sw
+ Description : roce5_srq_hw2sw
+ Input : struct roce5_device *rdev
+ struct roce5_srq *srq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_srq_hw2sw(struct roce5_device *rdev, struct roce5_srq *srq)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ uint16_t inbuf_size = 0;
+
+ if (ROCE5_SUPPORT_IB_CMD_DESTROY_SRQ_MSG_V2(rdev) != 0) {
+ inbuf_size = sizeof(roce_uni_cmd_srq_hw2sw_s);
+ }
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ inbuf_size, NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ if (ROCE5_SUPPORT_IB_CMD_DESTROY_SRQ_MSG_V2(rdev) != 0) {
+ roce5_srq_hw2sw_config_cqm_cmd(rdev, cqm_cmd_inbuf,
+ &rdev->rdma_cap, srq);
+ }
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_HW2SW_SRQ, cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to send HW2SW_SRQ command, func_id(%d)",
+ rdev->glb_func_id);
+
+ ret = -1;
+
+ if (hinic5_get_chip_present_flag(rdev->hwdev) == 0) {
+ ROCE_DEV_ERR(rdev,
+ "Card not present, return OK, func_id(%d)",
+ rdev->glb_func_id);
+ ret = 0;
+ }
+
+ goto err_out;
+ }
+
+err_out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+static void roce5_free_srq(struct ib_srq *ibsrq, struct roce5_device *rdev,
+ struct roce5_srq *srq, struct ib_udata *udata)
+{
+ hmm_mtt_free(rdev->hwdev, &srq->mtt, SERVICE_T_ROCE);
+
+ if (ibsrq->uobject) {
+ struct roce5_ucontext *ucontext = roce5_queue_to_ucontext(
+ (void *)ibsrq, udata, ROCE_Q_TYPE_SRQ);
+ roce5_db_unmap_user(ucontext, &srq->db, 0);
+ ib_umem_release(srq->umem);
+ } else {
+ kfree(srq->wrid);
+ }
+
+ cqm5_object_delete(&srq->cqm_srq->object);
+}
+
+int roce5_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
+{
+ int ret = 0;
+ int times = 0;
+ struct roce5_device *rdev = NULL;
+ struct roce5_srq *rsrq = NULL;
+
+ if (ibsrq == NULL) {
+ ROCE_ERR("Ibsrq is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibsrq->device);
+ rsrq = to_roce5_srq(ibsrq);
+ times = rdev->try_times;
+
+ ret = roce5_srq_hw2sw(rdev, rsrq);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to handle srq hw2sw, func_id(%d), ret:%d",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ roce5_free_srq(ibsrq, rdev, rsrq, udata);
+ return 0;
+}
+
+int roce5_destroy_srq_ofa(struct ib_srq *ibsrq)
+{
+ int ret = roce5_destroy_srq(ibsrq, NULL);
+ if (ret == 0) {
+ kfree(ibsrq);
+ }
+
+ return ret;
+}
+
+static int roce5_check_sge_length(const struct ib_recv_wr *wr,
+ struct roce5_device *rdev,
+ const struct ib_recv_wr **bad_wr,
+ struct roce_wqe_srq_data_seg *scat)
+{
+ int i = 0;
+ int ret = 0;
+ u32 data_len = 0;
+
+ for (i = 0; i < wr->num_sge; ++i) {
+ if (ROCE_UNLIKELY(
+ wr->sg_list[i].length >
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_msg_sz -
+ 1)) {
+ ret = -EINVAL;
+ *bad_wr = wr;
+ ROCE_DEV_ERR(
+ rdev,
+ "Sge data length is over range, sg_list(%d), length(0x%x), max_msg_sz(0x%x), func_id(%d)",
+ i, wr->sg_list[i].length,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_msg_sz,
+ rdev->glb_func_id);
+
+ scat[0].dw2.length = 0;
+ scat[0].dw3.lkey = LAST_SGE_NO_PRESENT;
+ scat[0].dw3.lkey = cpu_to_be32(scat[0].dw3.lkey);
+ return ret;
+ }
+
+ data_len += wr->sg_list[i].length;
+ if (ROCE_UNLIKELY(data_len >
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_msg_sz)) {
+ ret = -EINVAL;
+ *bad_wr = wr;
+ scat[0].dw2.length = 0;
+ scat[0].dw3.lkey = LAST_SGE_NO_PRESENT;
+ scat[0].dw3.lkey = cpu_to_be32(scat[0].dw3.lkey);
+
+ ROCE_DEV_ERR(
+ rdev,
+ "Data length is over range, data_len(0x%x), max_msg_sz(0x%x), func_id(%d)",
+ data_len,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap
+ .max_msg_sz,
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ scat[i].dw2.length = cpu_to_be32(wr->sg_list[i].length);
+ scat[i].dw3.lkey =
+ cpu_to_be32((u32)(wr->sg_list[i].lkey &
+ NORMAL_FMT_AND_NEXT_SGE_PRESENT));
+ scat[i].addr = cpu_to_be64(wr->sg_list[i].addr);
+ }
+
+ if (ROCE_UNLIKELY(i == 0)) {
+ scat[0].dw3.lkey = LAST_SGE_NO_PRESENT;
+ scat[0].dw3.lkey = cpu_to_be32(scat[0].dw3.lkey);
+ scat[0].dw2.length = 0;
+ } else {
+ scat[i - 1].dw3.lkey = cpu_to_be32(
+ (u32)((wr->sg_list[i - 1].lkey | LAST_SGE_NO_PRESENT) &
+ NORMAL_FMT_AND_LAST_SGE_NO_PRESENT));
+ }
+
+ return ret;
+}
+
+static int roce5_post_srq_recv_precheck(struct ib_srq *ibsrq,
+ const struct ib_recv_wr **bad_wr)
+{
+ if (ibsrq == NULL) {
+ ROCE_ERR("Ibsrq is null");
+ return -EINVAL;
+ }
+
+ if (bad_wr == NULL) {
+ ROCE_ERR("Bad_wr is null");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce5_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr)
+{
+ int ret = 0;
+ int nreq = 0;
+ unsigned long flags = 0; /* type required by kernel API */
+ struct roce5_srq *srq = NULL;
+ struct roce5_device *rdev = NULL;
+ struct roce5_wqe_srq_next_seg *next = NULL;
+ struct roce_wqe_srq_data_seg *scat = NULL;
+ const struct ib_recv_wr *wr_tmp = wr;
+
+ ret = roce5_post_srq_recv_precheck(ibsrq, bad_wr);
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ srq = to_roce5_srq(ibsrq);
+ rdev = to_roce5_dev(ibsrq->device);
+
+ spin_lock_irqsave(&srq->lock, flags);
+
+ for (nreq = 0; wr_tmp; ++nreq, wr_tmp = wr_tmp->next) {
+ if (ROCE_UNLIKELY((wr_tmp->num_sge > srq->max_gs) ||
+ (srq->head == srq->tail))) {
+ ret = (wr_tmp->num_sge > srq->max_gs) ? (-EINVAL) :
+ (-ENOMEM);
+ *bad_wr = wr_tmp;
+ ROCE_DEV_ERR(
+ rdev,
+ "Num_sge(%d) > max_gs(%d) or srq is empty(head(%d) == tail(%d)), func_id(%d)",
+ wr_tmp->num_sge, srq->max_gs, rdev->glb_func_id,
+ srq->head, srq->tail);
+ break;
+ }
+
+ next = (struct roce5_wqe_srq_next_seg *)roce5_srq_get_wqe(
+ srq, srq->head);
+ scat = (struct roce_wqe_srq_data_seg *)(next + 1);
+
+ ret = roce5_check_sge_length(wr_tmp, rdev, bad_wr, scat);
+ if (ret != 0) {
+ goto sge_len_err;
+ }
+
+ next->pcnt = (u16)cpu_to_be16(srq->wqe_ctr + (u16)nreq);
+ srq->wrid[srq->head] = wr_tmp->wr_id;
+ srq->head = be16_to_cpu(next->next_wqe_index);
+ }
+
+sge_len_err:
+ if (ROCE_UNLIKELY(nreq != 0)) {
+ srq->wqe_ctr += (u16)nreq;
+
+ /*
+ * Make sure that descriptors are written before
+ * doorbell record.
+ */
+ wmb();
+
+ *srq->db.db_record = cpu_to_be32(srq->wqe_ctr);
+ }
+
+ spin_unlock_irqrestore(&srq->lock, flags);
+
+ return ret;
+}
+
+int roce5_post_srq_recv_ofa(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr)
+{
+ return roce5_post_srq_recv(ibsrq, (const struct ib_recv_wr *)wr,
+ (const struct ib_recv_wr **)bad_wr);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_format.h b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_format.h
new file mode 100644
index 000000000..12d501b4c
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/srq/roce_srq_format.h
@@ -0,0 +1,36 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_SRQ_FORMAT_H
+#define ROCE_SRQ_FORMAT_H
+
+#include <linux/types.h>
+
+typedef struct roce5_srq_context {
+ /* DW0 */
+ union {
+ struct {
+ u32 size : 5;
+ u32 page_size : 4;
+ u32 wqebb_size : 3;
+ u32 rsvd : 2;
+ u32 pdn : 18;
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+ u32 rsvd : 24;
+ u32 dma_attr_idx : 6;
+ u32 so_ro : 2;
+ } bs_c;
+ u32 value;
+ } dw1;
+
+ u32 rsvd[14];
+} roce5_srq_context_s;
+
+#endif /* ROCE_SRQ_FORMAT_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/uld/roce_uld_api.c b/drivers/infiniband/hw/hiroce5/kernel/base/uld/roce_uld_api.c
new file mode 100644
index 000000000..e66a99f39
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/uld/roce_uld_api.c
@@ -0,0 +1,729 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
+
+
+#include "comm_defs.h"
+#include "roce_uld_kernel_api.h"
+#include "roce_bond.h"
+#include "roce_uld_inner.h"
+#include "roce_mpu_cmd.h"
+#include "roce_cqm_cmd.h"
+
+#define PLUGIN __attribute__((__used__, __weak__, optimize("O0")))
+#define ROCE_ULD_PRINT_BUF_SIZE 256
+
+PLUGIN int roce5_uld_reg_user_mr(roce_uld_handle handle)
+{
+ return -1;
+}
+
+PLUGIN int roce5_uld_dereg_user_mr(roce_uld_handle handle)
+{
+ return 0;
+}
+
+PLUGIN int roce5_adm_dfx_uld_extend(roce_uld_handle handle, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ return 0;
+}
+
+PLUGIN int roce5_uld_qp_modify(roce_uld_handle handle, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ return 0;
+}
+
+PLUGIN void roce5_uld_rdev_remove(roce_uld_handle handle)
+{
+ return;
+}
+
+PLUGIN int roce5_uld_rdev_add(roce_uld_handle handle)
+{
+ return 0;
+}
+
+PLUGIN int roce5_uld_qp_destroy(roce_uld_handle handle)
+{
+ return 0;
+}
+
+PLUGIN int roce5_uld_qp_create(roce_uld_handle handle)
+{
+ return 0;
+}
+
+PLUGIN int roce5_uld_cq_create(roce_uld_handle handle)
+{
+ return 0;
+}
+
+PLUGIN void roce5_uld_cq_destroy(roce_uld_handle handle)
+{
+ return;
+}
+
+PLUGIN int32_t roce5_uld_user2kernel_msg_handle(roce_uld_handle handle,
+ void *buf_in, u16 buf_in_len,
+ void *buf_out, u16 buf_out_len,
+ u16 *buf_out_size)
+{
+ return 0;
+}
+
+PLUGIN int roce5_uld_service_init(void)
+{
+ return 0;
+}
+
+PLUGIN void roce5_uld_service_exit(void)
+{
+ return;
+}
+
+u64 roce5_mr_virt_addr_get(roce_uld_handle handle)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) {
+ ROCE_ERR("handle is invalid");
+ return 0;
+ }
+
+ return hdl->virt_addr;
+}
+
+int roce5_mr_virt_addr_set(roce_uld_handle handle, u64 virt_addr)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) {
+ ROCE_ERR("handle is invalid");
+ return -EINVAL;
+ }
+
+ hdl->virt_addr = virt_addr;
+
+ return 0;
+}
+
+int roce5_mr_user_data_get(roce_uld_handle handle, u8 *user_data,
+ u32 user_data_len)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ u32 cpy_len;
+
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM)) {
+ ROCE_ERR("handle is invalid");
+ return -EINVAL;
+ }
+
+ if (user_data == NULL) {
+ ROCE_ERR("user_data is NULL");
+ return -EINVAL;
+ }
+
+ cpy_len = (user_data_len > hdl->mr->user_data_len) ?
+ hdl->mr->user_data_len :
+ user_data_len;
+ (void)memcpy_s(user_data, user_data_len, hdl->mr->rdmamr.user_data,
+ cpy_len);
+
+ return cpy_len;
+}
+
+int roce5_mpt_alloc_and_init(roce_uld_handle handle, int mode, u8 *user_data,
+ u32 user_data_len, u32 mpt_xid_mode)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ struct roce5_mr *mr = NULL;
+ struct roce5_device *rdev = NULL;
+ int ret = 0;
+ u32 npages = 0;
+ u32 page_shift = PAGE_SHIFT;
+ u32 mpt_xid_create_mode;
+
+ if ((hdl == NULL) || hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) {
+ ROCE_ERR("handle is invalid");
+ return -EINVAL;
+ }
+
+ mr = hdl->mr;
+ rdev = hdl->rdev;
+ if (rdev == NULL) {
+ ROCE_ERR("rdev is NULL");
+ return -EINVAL;
+ }
+
+ if (user_data_len > HMM_USER_DATA_MAX_BYTE) {
+ ROCE_ERR(
+ "user_data_len(%u) is invalid, max user_data_len is %u",
+ user_data_len, HMM_USER_DATA_MAX_BYTE);
+ return -EINVAL;
+ }
+
+ if (mode == ROCE_ULD_MPT_NORMAL) {
+ mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE;
+ npages = (u32)ib_umem_num_pages(mr->umem);
+#if defined(UMEM_HAVE_PAGE_SHIFT)
+ page_shift = (u32)(mr->umem->page_shift);
+#endif
+ }
+
+ mpt_xid_create_mode = CQM_DYNAMIC_XID_MOD(
+ CQM_XID_SEARCH_ALL, CQM_XID_LOW_BIT_0_0_1, mpt_xid_mode);
+ ret = roce5_alloc_tpt(rdev, &mr->rdmamr, npages, page_shift,
+ mpt_xid_create_mode);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc mpt and mtt, func_id(%d), npages(%u), page_shift(%u)",
+ hinic5_global_func_id(rdev->hwdev), npages, page_shift);
+ goto err_alloc_tpt;
+ }
+
+ roce5_set_rdma_mr(&mr->rdmamr, RDMA_USER_MR, hdl->pdn, hdl->virt_addr,
+ hdl->length, hdl->access);
+
+ if (mode == ROCE_ULD_MPT_NORMAL) {
+ ret = roce5_umem_write_mtt(rdev, &mr->rdmamr.mtt, mr->umem, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to write mtt, func_id(%d)",
+ hinic5_global_func_id(rdev->hwdev));
+ goto err_write_mtt;
+ }
+ }
+
+ if (user_data != NULL) {
+ (void)memcpy_s(hdl->mr->rdmamr.user_data, user_data_len,
+ user_data, user_data_len);
+ hdl->mr->user_data_len = user_data_len;
+ } else {
+ hdl->mr->user_data_len = 0;
+ }
+
+ return 0;
+
+err_write_mtt:
+ roce5_free_tpt(rdev, &mr->rdmamr);
+
+err_alloc_tpt:
+ return ret;
+}
+
+void roce5_mpt_destroy(roce_uld_handle handle)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ struct roce5_device *rdev = NULL;
+
+ if ((hdl == NULL) || hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) {
+ ROCE_ERR("handle is invalid");
+ return;
+ }
+
+ if (hdl->mr == NULL) {
+ ROCE_ERR("mr is NULL");
+ return;
+ }
+
+ rdev = hdl->rdev;
+ if (rdev == NULL) {
+ ROCE_ERR("rdev is NULL");
+ return;
+ }
+
+ if (hdl->mr->rdmamr.enabled != RDMA_MPT_DISABLED) {
+ roce5_free_tpt(rdev, &hdl->mr->rdmamr);
+ }
+
+ return;
+}
+
+int roce5_mpt_enable(roce_uld_handle handle)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ struct roce5_device *rdev = NULL;
+ int ret;
+
+ if ((hdl == NULL) || hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) {
+ ROCE_ERR("handle is invalid");
+ return -EINVAL;
+ }
+
+ rdev = hdl->rdev;
+ if (rdev == NULL) {
+ ROCE_ERR("rdev is NULL");
+ return -EINVAL;
+ }
+
+ /* here hmm will userdata send to npu */
+ ret = hmm_rdma_enable_mpt(rdev->lld_dev, rdev->hwdev, &hdl->mr->rdmamr,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to enable mpt of user mr, func_id(%d)",
+ hinic5_global_func_id(rdev->hwdev));
+ }
+
+ return ret;
+}
+
+int roce5_uld_get_func_id(roce_uld_handle handle)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) {
+ ROCE_ERR("handle is invalid");
+ return -1;
+ }
+
+ if (hdl->rdev == NULL) {
+ ROCE_ERR("rdev is NULL");
+ return -1;
+ }
+
+ return (int)hdl->rdev->glb_func_id;
+}
+
+int roce5_uld_send_msg_to_mgmt(roce_uld_handle handle, u16 cmd, void *buf_in,
+ u16 in_size, void *buf_out, u16 *out_size)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((cmd < ROCE_MPU_CMD_ULP_START) || (cmd >= ROCE_MPU_CMD_MAX)) {
+ ROCE_ERR("cmd is invalid");
+ return -1;
+ }
+
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) ||
+ (hdl->rdev == NULL) || (buf_in == NULL) || (buf_out == NULL) ||
+ (out_size == NULL)) {
+ ROCE_ERR(
+ "handle is invalid, or buf_in(%d), buf_out(%d), out_size(%d) is invalid",
+ (buf_in == NULL), (buf_out == NULL),
+ (out_size == NULL));
+ return -1;
+ }
+
+ return hinic5_msg_to_mgmt_sync(hdl->rdev->hwdev, HINIC5_MOD_ROCE, cmd,
+ buf_in, in_size, buf_out, out_size, 0,
+ HINIC5_CHANNEL_ROCE);
+}
+
+int roce5_uld_get_qp_info(roce_uld_handle handle, roce_uld_qp_info *qp_info)
+{
+ struct roce5_qp *rqp = NULL;
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) ||
+ (hdl->rqp == NULL) || (qp_info == NULL)) {
+ ROCE_ERR("param invalid");
+ return -1;
+ }
+
+ rqp = (struct roce5_qp *)hdl->rqp;
+ qp_info->qpn = rqp->qpn;
+ qp_info->qp_type = rqp->qp_type;
+ if (hdl->qp_attr != NULL) {
+ qp_info->dgid = (u8 *)&hdl->qp_attr->path_info.dgid[0];
+ }
+ return 0;
+}
+
+int roce5_uld_modify_qp_tx_bond_hash(roce_uld_handle handle, u32 tx_bond_hash)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) ||
+ (hdl->qp_attr == NULL)) {
+ ROCE_ERR("param invalid");
+ return -1;
+ }
+
+ hdl->qp_attr->path_info.dw0.bs.bond_tx_hash_value = tx_bond_hash & 0xf;
+ return 0;
+}
+
+u8 *roce5_get_rdev_uld_def(roce_uld_handle handle)
+{
+ struct roce5_device *rdev = NULL;
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM)) {
+ return NULL;
+ }
+
+ rdev = hdl->rdev;
+ if ((rdev == NULL) || (rdev->rdev_magic != ROCE_DEVICE_MAGIC)) {
+ ROCE_ERR("handle is invalid, magic:0x%x",
+ (rdev == NULL) ? ROCE_MAGIC_NULL : rdev->rdev_magic);
+ return NULL;
+ }
+ return (u8 *)&rdev->uld_def.self_def[0];
+}
+
+void *roce5_uld_get_rdev_hwdev(roce_uld_handle handle)
+{
+ struct roce5_device *rdev = NULL;
+ void *hwdev = NULL;
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM)) {
+ return NULL;
+ }
+
+ rdev = hdl->rdev;
+ if ((rdev == NULL) || (rdev->rdev_magic != ROCE_DEVICE_MAGIC)) {
+ ROCE_ERR("handle is invalid, magic:0x%x",
+ (rdev == NULL) ? ROCE_MAGIC_NULL : rdev->rdev_magic);
+ return NULL;
+ }
+ hwdev = hdl->rdev->hwdev;
+ if (hwdev == NULL) {
+ ROCE_ERR("handle is invalid, hwdev is NULL");
+ return NULL;
+ }
+ return hwdev;
+}
+
+struct ib_device *roce5_uld_get_rdev_ibdev(roce_uld_handle handle)
+{
+ struct roce5_device *rdev = NULL;
+ struct ib_device *ib_dev = NULL;
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM)) {
+ return NULL;
+ }
+
+ rdev = hdl->rdev;
+ if ((rdev == NULL) || (rdev->rdev_magic != ROCE_DEVICE_MAGIC)) {
+ ROCE_ERR("handle is invalid, magic:0x%x",
+ (rdev == NULL) ? ROCE_MAGIC_NULL : rdev->rdev_magic);
+ return NULL;
+ }
+ ib_dev = &(hdl->rdev->ib_dev);
+ return ib_dev;
+}
+
+struct hinic5_lld_dev *roce5_uld_get_rdev_lld_dev(roce_uld_handle handle)
+{
+ struct roce5_device *rdev = NULL;
+ struct hinic5_lld_dev *lld_dev = NULL;
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM)) {
+ return NULL;
+ }
+
+ rdev = hdl->rdev;
+ if ((rdev == NULL) || (rdev->rdev_magic != ROCE_DEVICE_MAGIC)) {
+ ROCE_ERR("handle is invalid, magic:0x%x",
+ (rdev == NULL) ? ROCE_MAGIC_NULL : rdev->rdev_magic);
+ return NULL;
+ }
+ lld_dev = hdl->rdev->lld_dev;
+ if (lld_dev == NULL) {
+ ROCE_ERR("handle is invalid, lld_dev is NULL");
+ return NULL;
+ }
+ return lld_dev;
+}
+
+#ifdef ROCE_BONDING_EN
+int roce5_uld_get_rdev_bond_dev_slave_cnt(roce_uld_handle handle,
+ u32 *slave_cnt, uint8_t *bond_en)
+{
+ struct roce5_device *rdev = NULL;
+ struct roce5_bond_device *bond_dev = NULL;
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) ||
+ (slave_cnt == NULL) || (bond_en == NULL)) {
+ return -EINVAL;
+ }
+ rdev = hdl->rdev;
+ if ((rdev == NULL) || (rdev->rdev_magic != ROCE_DEVICE_MAGIC)) {
+ ROCE_ERR("handle is invalid, magic:0x%x",
+ (rdev == NULL) ? ROCE_MAGIC_NULL : rdev->rdev_magic);
+ return -EINVAL;
+ }
+ bond_dev = rdev->bond_dev;
+ if (bond_dev == NULL) {
+ *slave_cnt = 0;
+ *bond_en = 0;
+ return 0;
+ }
+ *slave_cnt = hdl->rdev->bond_dev->slave_cnt;
+ *bond_en = 1;
+ return 0;
+}
+#endif
+
+u8 *roce5_get_rqp_uld_def(roce_uld_handle handle)
+{
+ struct roce5_qp *rqp = NULL;
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM)) {
+ return NULL;
+ }
+
+ rqp = (struct roce5_qp *)hdl->rqp;
+ if ((rqp == NULL) || (rqp->rqp_magic != ROCE_RQP_MAGIC)) {
+ ROCE_ERR("handle is invalid, magic:0x%x",
+ (rqp == NULL) ? ROCE_MAGIC_NULL : rqp->rqp_magic);
+ return NULL;
+ }
+ return (u8 *)&rqp->uld_def.uld_def[0];
+}
+
+u8 *roce5_get_rcq_uld_def(roce_uld_handle handle)
+{
+ struct roce5_cq *rcq = NULL;
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM)) {
+ return NULL;
+ }
+
+ rcq = (struct roce5_cq *)hdl->rcq;
+ if ((rcq == NULL) || (rcq->rcq_magic != ROCE_RCQ_MAGIC)) {
+ ROCE_ERR("handle is invalid, magic:0x%x",
+ (rcq == NULL) ? ROCE_MAGIC_NULL : rcq->rcq_magic);
+ return NULL;
+ }
+ return (u8 *)&rcq->uld_def.uld_def[0];
+}
+
+int roce5_uld_cos_set(roce_uld_handle handle, struct ib_qp_attr *attr, u8 type,
+ u8 value)
+{
+ u8 cos;
+ roce5_get_cos_inbuf_s inbuf = { 0 };
+ struct roce5_qp *rqp = NULL;
+ roce_verbs_qp_attr_s *qp_attr = NULL;
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ int ret;
+
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) ||
+ (hdl->rqp == NULL) || (hdl->qp_attr == NULL) ||
+ (hdl->rdev == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ rqp = hdl->rqp;
+ qp_attr = hdl->qp_attr;
+
+ if (type == ROCE5_COS_SET_TYPE_CLASS) {
+ inbuf.sl = attr->ah_attr.sl;
+ inbuf.sgid_index = attr->ah_attr.grh.sgid_index;
+ inbuf.port_num = attr->ah_attr.port_num;
+ inbuf.traffic_class = value;
+
+ ret = roce5_get_dcb_cfg_cos(hdl->rdev, &inbuf, &cos,
+ rqp->qp_type);
+ if (ret != 0) {
+ ROCE_ERR("get dcb cfg cos failed");
+ return ret;
+ }
+
+ /* update tclass and cos */
+ qp_attr->path_info.dw6.bs.tclass = value;
+ qp_attr->com_info.dw5.bs.cos = cos;
+ rqp->db_cos = cos;
+ } else if (type == ROCE5_COS_SET_TYPE_COS) {
+ if (value > 7) { /* cos range is 0-7 */
+ ROCE_ERR("invalid cos(%u)", value);
+ return -EINVAL;
+ }
+ qp_attr->com_info.dw5.bs.cos = value;
+ rqp->db_cos = value;
+ } else {
+ ROCE_ERR("set type(%u) invalid", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce5_support_uld_kernel_feature(roce_uld_handle handle, u64 feature)
+{
+ roce_user_handle_t *user_handle = (roce_user_handle_t *)handle;
+ struct roce5_device *rdev = NULL;
+
+ if ((!user_handle) ||
+ (user_handle->magic != ROCE_ULD_HANDLE_MAGIC_NUM)) {
+ ROCE_ERR("Invalid RoCE handle\n");
+ return -EINVAL;
+ }
+
+ rdev = user_handle->rdev;
+
+ if (rdev == NULL) {
+ ROCE_ERR("rdev is NULL in handle\n");
+ return -EINVAL;
+ }
+
+ //return capability bit AND result
+ return (rdev)->cfg_info.feature_cap.uld_feature
+ .roce_uld_kernel_ext_ability &
+ feature;
+}
+
+int roce5_uld_set_mpt_xid_mode(roce_uld_handle handle, u8 mode)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ struct roce5_device *rdev = NULL;
+
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) ||
+ (hdl->rdev == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ rdev = hdl->rdev;
+ rdev->mpt_xid_mode = mode;
+
+ return 0;
+}
+
+int roce5_uld_get_dgid(roce_uld_handle handle, u8 **dgid)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || (hdl->qp_attr == NULL) || (dgid == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+ *dgid = hdl->qp_attr->path_info.dgid;
+ return 0;
+}
+
+int roce5_uld_set_bond_tx_hash_value(roce_uld_handle handle,
+ u32 bond_tx_hash_value)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || (hdl->qp_attr == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ hdl->qp_attr->path_info.dw0.bs.bond_tx_hash_value = bond_tx_hash_value;
+ return 0;
+}
+
+int roce5_uld_get_mr_uld_self_def(roce_uld_handle handle, u8 **self_def,
+ u32 *self_def_len)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM) ||
+ (hdl->mr == NULL) || (self_def == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ *self_def = &hdl->mr->uld_def.self_def[0];
+ if (self_def_len != NULL) {
+ *self_def_len = ROCE_MR_ULD_DEF_LEN;
+ }
+ return 0;
+}
+
+int roce5_uld_get_rdmamr(roce_uld_handle handle, struct hmm_rdma **rdmamr_ptr)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || (hdl->mr == NULL) || (rdmamr_ptr == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ *rdmamr_ptr = &(hdl->mr->rdmamr);
+ return 0;
+}
+
+int roce5_uld_set_qp_attr_ack_to(roce_uld_handle handle, u32 ack_to)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || (hdl->qp_attr == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ hdl->qp_attr->com_info.dw2.bs.ack_to = ack_to;
+ return 0;
+}
+
+int roce5_uld_get_qp_state(roce_uld_handle handle, u8 *out_qp_state)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || (hdl->rqp == NULL) || (out_qp_state == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ *out_qp_state = hdl->rqp->qp_state;
+ return 0;
+}
+
+int roce5_uld_get_config_num_ports(roce_uld_handle handle,
+ int *out_cfg_num_ports)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || (hdl->rdev == NULL) ||
+ (out_cfg_num_ports == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ *out_cfg_num_ports = hdl->rdev->hw_info.config_num_ports;
+ return 0;
+}
+
+int roce5_uld_get_handle_length(roce_uld_handle handle, u64 *length)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+
+ if ((hdl == NULL) || (length == NULL)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ *length = hdl->length;
+ return 0;
+}
+
+void roce5_uld_print_kernel_err_impl(roce_uld_handle handle, const char *func,
+ int line, const char *fmt, ...)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ va_list args;
+ char buf[ROCE_ULD_PRINT_BUF_SIZE];
+
+ va_start(args, fmt);
+ if (vsnprintf(buf, sizeof(buf), fmt, args) < 0) {
+ va_end(args);
+ return;
+ }
+ va_end(args);
+
+ if ((hdl != NULL) && (hdl->magic == ROCE_ULD_HANDLE_MAGIC_NUM) &&
+ (hdl->rdev != NULL)) {
+ ROCE_DEV_ERR(hdl->rdev, "[ULP][%s,%d]%s", func, line, buf);
+ } else {
+ ROCE_ERR("[ULP][%s,%d]%s", func, line, buf);
+ }
+}
+
+int roce5_uld_qp_get_port(roce_uld_handle handle, u8 *port)
+{
+ roce_user_handle_t *hdl = (roce_user_handle_t *)handle;
+ if ((hdl == NULL) || (hdl->rqp == NULL) || (port == NULL) ||
+ (hdl->magic != ROCE_ULD_HANDLE_MAGIC_NUM)) {
+ ROCE_ERR("param invalid");
+ return -EINVAL;
+ }
+
+ *port = hdl->rqp->port;
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/uld/roce_uld_inner.h b/drivers/infiniband/hw/hiroce5/kernel/base/uld/roce_uld_inner.h
new file mode 100644
index 000000000..e61160c2f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/uld/roce_uld_inner.h
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
+
+
+#ifndef ROCE_ULD_INNER_H
+#define ROCE_ULD_INNER_H
+
+#include "roce.h"
+#include "roce_mr.h"
+#include "roce_qp.h"
+#include "roce_cq.h"
+#include "hmm_common.h"
+#include "roce_npu_cmd_mr_defs.h"
+#include "roce_npu_cmd_qp_defs.h"
+
+#define ROCE_ULD_HANDLE_MAGIC_NUM 0x524F4345 /* "ROCE" string of ascii code */
+#define ROCE_MAGIC_NULL 0x12345678 /* used to distinguish null pointer and unassigned */
+
+typedef struct {
+ u32 magic; /* magic number, determine handle whether valid */
+ struct roce5_device *rdev;
+ struct roce5_mr *mr;
+ roce_verbs_mr_attr_s *mr_attr;
+ u64 virt_addr;
+ u64 length;
+ u32 pdn;
+ int access;
+
+ struct roce5_qp *rqp;
+ roce_verbs_qp_attr_s *qp_attr;
+
+ struct roce5_cq *rcq;
+ int cqe;
+
+ struct ib_udata *udata;
+ struct mtt *
+ mtt; /* hmm module of mtt management structure, shadow scenario page_shift and paddr mandatory, mtt_layers constraint is 0 */
+ dma_addr_t *db_dma_handle; /* software db of dma address */
+
+ u8 *shadow;
+ u32 *shadow_vfid;
+ u16 *shadow_vf_num;
+} roce_user_handle_t;
+
+#define ROCE_CONSTUCT_ULD_HDL_RQP(hdl, roce_dev, roce_qp, roce_qp_attr, \
+ roce_udata, roce_mtt, roce_db_dma_handle) \
+ do { \
+ (hdl)->magic = ROCE_ULD_HANDLE_MAGIC_NUM; \
+ (hdl)->rdev = (roce_dev); \
+ (hdl)->rqp = (roce_qp); \
+ (hdl)->qp_attr = (roce_qp_attr); \
+ (hdl)->udata = (roce_udata); \
+ (hdl)->mtt = (roce_mtt); \
+ (hdl)->db_dma_handle = (roce_db_dma_handle); \
+ } while (0)
+
+#define ROCE_CONSTUCT_ULD_HDL_RCQ(hdl, roce_dev, roce_cq, roce_udata, \
+ roce_mtt, roce_db_dma_handle, roce_cqe) \
+ do { \
+ (hdl)->magic = ROCE_ULD_HANDLE_MAGIC_NUM; \
+ (hdl)->rdev = (roce_dev); \
+ (hdl)->rcq = (roce_cq); \
+ (hdl)->udata = (roce_udata); \
+ (hdl)->mtt = (roce_mtt); \
+ (hdl)->db_dma_handle = (roce_db_dma_handle); \
+ (hdl)->cqe = (roce_cqe); \
+ } while (0)
+
+#define ROCE_CONSTUCT_ULD_HDL_SHADOW(hdl, roce_shadow, roce_shadow_vfid, \
+ roce_shadow_vf_num) \
+ do { \
+ (hdl)->shadow = (roce_shadow); \
+ (hdl)->shadow_vfid = (roce_shadow_vfid); \
+ (hdl)->shadow_vf_num = (roce_shadow_vf_num); \
+ } while (0)
+
+#endif
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/xrc/roce_xrc.c b/drivers/infiniband/hw/hiroce5/kernel/base/xrc/roce_xrc.c
new file mode 100644
index 000000000..7530a655b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/xrc/roce_xrc.c
@@ -0,0 +1,169 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/slab.h>
+
+#include "roce.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#include "roce_xrc.h"
+
+static int roce5_rdma_xrcd_alloc(void *hwdev, u32 *xrcdn)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if ((hwdev == NULL) || (xrcdn == NULL)) {
+ ROCE_ERR("Hwdev or xrcdn is null");
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return -EINVAL;
+ }
+
+ *xrcdn = rdma_bitmap_alloc(&comp_priv->xrcd_bitmap);
+ if (*xrcdn == RDMA_INVALID_INDEX) {
+ ROCE_ERR("Can't get valid xrcdn, err(%d)", -ENOMEM);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void roce5_rdma_xrcd_free(void *hwdev, u32 xrcdn)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if (hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return;
+ }
+
+ rdma_bitmap_free(&comp_priv->xrcd_bitmap, xrcdn);
+}
+
+static int roce5_init_xrcd(struct ib_device *ibdev, struct roce5_device *rdev,
+ struct roce5_xrcd *xrcd)
+{
+ int ret = 0;
+ struct ib_cq_init_attr cq_attr = { 0 };
+
+ ret = roce5_rdma_xrcd_alloc(rdev->hwdev, &xrcd->xrcdn);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc rdma xrcd, ret(%d)", ret);
+ goto err_alloc_xrcdn;
+ }
+
+ xrcd->pd = ib_alloc_pd(ibdev, 0);
+
+ if (IS_ERR(xrcd->pd)) {
+ ret = (int)PTR_ERR(xrcd->pd);
+ ROCE_DEV_ERR(rdev, "Failed to alloc pd, ret(%d)", ret);
+ goto err_alloc_pd;
+ }
+
+ cq_attr.cqe = 1;
+ xrcd->cq = ib_create_cq(ibdev, NULL, NULL, xrcd, &cq_attr);
+ if (IS_ERR(xrcd->cq)) {
+ ret = (int)PTR_ERR(xrcd->cq);
+ ROCE_DEV_ERR(rdev, "Failed to create cq, ret(%d)", ret);
+ goto err_create_cq;
+ }
+ return 0;
+
+err_create_cq:
+ ib_dealloc_pd(xrcd->pd);
+
+err_alloc_pd:
+ roce5_rdma_xrcd_free(rdev->hwdev, xrcd->xrcdn);
+
+err_alloc_xrcdn:
+ return ret;
+}
+
+int roce5_alloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata)
+{
+ struct roce5_device *rdev = NULL;
+ struct roce5_xrcd *xrcd = NULL;
+
+ if (ibxrcd == NULL) {
+ ROCE_ERR("Input pointer is NULL");
+ return (-EINVAL);
+ }
+
+ rdev = to_roce5_dev(ibxrcd->device);
+ xrcd = to_roce5_xrcd(ibxrcd);
+
+ return roce5_init_xrcd(ibxrcd->device, rdev, xrcd);
+}
+
+struct ib_xrcd *roce5_alloc_xrcd_ofa(struct ib_device *ibdev,
+ struct ib_ucontext *ibcontext,
+ struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_device *rdev = NULL;
+ struct roce5_xrcd *xrcd = NULL;
+
+ if (ibdev == NULL) {
+ ROCE_ERR("Ibdev is null");
+ return ERR_PTR(-EINVAL);
+ }
+
+ rdev = to_roce5_dev(ibdev);
+
+ xrcd = (struct roce5_xrcd *)kzalloc(sizeof(*xrcd), GFP_KERNEL);
+ if (xrcd == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc memory for xrcd");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Unreasonable, but for code reuse, driver associate the OFED resource in advance. */
+ xrcd->ibxrcd.device = ibdev;
+
+ ret = roce5_alloc_xrcd(&xrcd->ibxrcd, NULL);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init xrcd, ret(%d)", ret);
+ kfree(xrcd);
+ return ERR_PTR(ret);
+ }
+ return &xrcd->ibxrcd;
+}
+
+int roce5_dealloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata)
+{
+ struct roce5_device *rdev = NULL;
+ struct roce5_xrcd *xrcd = NULL;
+ if (ibxrcd == NULL) {
+ ROCE_ERR("Ibxrcd is null");
+ return -EINVAL;
+ }
+
+ rdev = to_roce5_dev(ibxrcd->device);
+ xrcd = to_roce5_xrcd(ibxrcd);
+ ib_destroy_cq(xrcd->cq);
+
+ ib_dealloc_pd(xrcd->pd);
+ roce5_rdma_xrcd_free(rdev->hwdev, xrcd->xrcdn);
+ return 0;
+}
+
+int roce5_dealloc_xrcd_ofa(struct ib_xrcd *ibxrcd)
+{
+ struct roce5_xrcd *xrcd = to_roce5_xrcd(ibxrcd);
+ int ret = roce5_dealloc_xrcd(ibxrcd, NULL);
+ if (ret == 0) {
+ kfree(xrcd);
+ }
+
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/base/xrc/roce_xrc.h b/drivers/infiniband/hw/hiroce5/kernel/base/xrc/roce_xrc.h
new file mode 100644
index 000000000..1a4e603ab
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/base/xrc/roce_xrc.h
@@ -0,0 +1,17 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_XRC_H
+#define ROCE_XRC_H
+
+#include <rdma/ib_verbs.h>
+
+struct roce5_xrcd {
+ struct ib_xrcd ibxrcd;
+ u32 xrcdn;
+ struct ib_pd *pd;
+ struct ib_cq *cq;
+};
+
+#endif //ROCE_XRC_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/card/roce_card.c b/drivers/infiniband/hw/hiroce5/kernel/dev/card/roce_card.c
new file mode 100644
index 000000000..d67dd0844
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/card/roce_card.c
@@ -0,0 +1,162 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
+
+#include <rdma/ib_user_verbs.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include "roce.h"
+#include "hinic5_lld.h"
+#include "roce_infra.h"
+#include "roce_card.h"
+
+static struct roce5_cards g_roce5_cards[MAX_DPU_CARD_NUM];
+
+void roce5_card_init(u16 idx, u64 card_id)
+{
+ g_roce5_cards[idx].card_status = RUNNING;
+ g_roce5_cards[idx].card_id = card_id;
+ INIT_LIST_HEAD(&g_roce5_cards[idx].rdev_list);
+ mutex_init(&g_roce5_cards[idx].card_mutex);
+}
+
+void roce5_card_deinit(u16 idx)
+{
+ g_roce5_cards[idx].card_status = INVALID;
+ g_roce5_cards[idx].card_id = 0;
+ mutex_destroy(&g_roce5_cards[idx].card_mutex);
+}
+
+int roce5_g_rdev_add(struct roce5_device *rdev)
+{
+ struct roce5_rdev_list_node *rdev_node = NULL;
+ u64 card_id;
+ u16 i;
+
+ if (hinic5_get_chip_node_id(rdev->lld_dev, &card_id) != 0) {
+ ROCE_ERR("Failed to get chip node id, func_id(%d)",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ rdev_node = kzalloc(sizeof(struct roce5_rdev_list_node), GFP_KERNEL);
+ if (rdev_node == NULL) {
+ ROCE_ERR("Failed to alloc memory.");
+ return -ENOMEM;
+ }
+ rdev_node->rdev = rdev;
+
+ for (i = 0; i < MAX_DPU_CARD_NUM; i++) {
+ if (g_roce5_cards[i].card_status == RUNNING &&
+ g_roce5_cards[i].card_id == card_id) {
+ break;
+ }
+ }
+
+ if (i >= MAX_DPU_CARD_NUM) {
+ for (i = 0; i < MAX_DPU_CARD_NUM; i++) {
+ if (g_roce5_cards[i].card_status == INVALID) {
+ roce5_card_init(i, card_id);
+ break;
+ }
+ }
+
+ if (i >= MAX_DPU_CARD_NUM) {
+ ROCE_ERR("Exceeded the MAX_DPU_CARD_NUM:0x%x",
+ MAX_DPU_CARD_NUM);
+ kfree(rdev_node);
+ return -ENOMEM;
+ }
+ }
+
+ mutex_lock(&g_roce5_cards[i].card_mutex);
+ list_add_tail(&rdev_node->node, &g_roce5_cards[i].rdev_list);
+ mutex_unlock(&g_roce5_cards[i].card_mutex);
+ return 0;
+}
+
+void roce5_g_rdev_remove(struct roce5_device *rdev)
+{
+ struct roce5_rdev_list_node *rdev_node = NULL, *rdev_next = NULL;
+ u64 card_id;
+ int i;
+
+ if (hinic5_get_chip_node_id(rdev->lld_dev, &card_id) != 0) {
+ ROCE_ERR("Failed to get chip node id, func_id(%d)",
+ rdev->glb_func_id);
+ return;
+ }
+
+ for (i = 0; i < MAX_DPU_CARD_NUM; i++) {
+ if (g_roce5_cards[i].card_status == RUNNING &&
+ g_roce5_cards[i].card_id == card_id) {
+ break;
+ }
+ }
+
+ if (i < MAX_DPU_CARD_NUM) {
+ mutex_lock(&g_roce5_cards[i].card_mutex);
+ list_for_each_entry_safe(rdev_node, rdev_next,
+ &g_roce5_cards[i].rdev_list, node) {
+ if (rdev_node->rdev == rdev) {
+ list_del(&rdev_node->node);
+ kfree(rdev_node);
+ break;
+ }
+ }
+ mutex_unlock(&g_roce5_cards[i].card_mutex);
+ /* deinit card if rdev list is empty */
+ if (list_empty(&g_roce5_cards[i].rdev_list)) {
+ roce5_card_deinit(i);
+ }
+ }
+}
+
+struct roce5_device *roce5_get_rdev_by_card_func_id(uint64_t card_id,
+ uint16_t func_id)
+{
+ struct roce5_rdev_list_node *rdev_node = NULL;
+ int i;
+
+ for (i = 0; i < MAX_DPU_CARD_NUM; i++) {
+ if (g_roce5_cards[i].card_status == RUNNING &&
+ g_roce5_cards[i].card_id == card_id) {
+ break;
+ }
+ }
+
+ if (i < MAX_DPU_CARD_NUM) {
+ list_for_each_entry(rdev_node, &g_roce5_cards[i].rdev_list,
+ node) {
+ if (rdev_node->rdev->glb_func_id == func_id) {
+ return rdev_node->rdev;
+ }
+ }
+ }
+ return NULL;
+}
+
+struct roce5_device *roce5_get_rdev_by_name(const char *dev_name)
+{
+ struct roce5_rdev_list_node *rdev_node = NULL;
+ int i;
+
+ if (dev_name == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < MAX_DPU_CARD_NUM; i++) {
+ if (g_roce5_cards[i].card_status == INVALID) {
+ continue;
+ }
+
+ list_for_each_entry(rdev_node, &g_roce5_cards[i].rdev_list,
+ node) {
+ if (strncmp(rdev_node->rdev->ib_dev.name, dev_name,
+ IB_DEVICE_NAME_MAX) == 0) {
+ return rdev_node->rdev;
+ }
+ }
+ }
+ return NULL;
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/card/roce_card.h b/drivers/infiniband/hw/hiroce5/kernel/dev/card/roce_card.h
new file mode 100644
index 000000000..5ceabdd1f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/card/roce_card.h
@@ -0,0 +1,27 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
+
+#ifndef ROCE_CARD_H
+#define ROCE_CARD_H
+
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include "roce.h"
+
+#define MAX_DPU_CARD_NUM \
+ 1024 //current SDK PCIe on current cannot identifies VM on and bare metal on is same one
张 card, temporary add specification supports start multi VM
+struct roce5_rdev_list_node {
+ struct list_head node;
+ struct roce5_device *rdev;
+};
+
+typedef enum roce5_card_status { INVALID = 0, RUNNING } roce5_card_status_e;
+
+struct roce5_cards {
+ u64 card_id;
+ roce5_card_status_e card_status;
+ struct mutex card_mutex;
+ struct list_head rdev_list;
+};
+#endif /* ROCE_CARD_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/cmd/roce_cmd.c b/drivers/infiniband/hw/hiroce5/kernel/dev/cmd/roce_cmd.c
new file mode 100644
index 000000000..2ad39f97f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/cmd/roce_cmd.c
@@ -0,0 +1,1270 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/errno.h>
+#include <linux/if_ether.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include "rdma_comp.h"
+#include "roce5_gid_type.h"
+#include "roce_compat.h"
+#include "roce_com.h"
+#include "roce_cqm_cmd.h"
+#include "roce_mpu_cmd.h"
+#include "roce_ctx_format.h"
+#include "roce_infra.h"
+#include "roce_main_extension.h"
+#include "roce_mix.h"
+#include "roce_npu_cmd.h"
+#include "roce_npu_cmd_ext_defs.h"
+#include "roce_srq_extension.h"
+#include "roce_uld_inner.h"
+#include "roce_uld_kernel_api.h"
+#include "securec.h"
+#include "roce_cmd.h"
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+#define OVS_MPU_CMD_QOS_SET_VM_POLICING 30
+#define OVS_MPU_CMD_VPORT_SET 13
+#define OVS_MPU_VPORT_SET_CMD_ATTR 2
+
+uint8_t roce5_srq_mode_chip_adapt(uint8_t cfg_mode)
+{
+ switch (cfg_mode) {
+ case ROCE_CHIP_SRQ_MODE_1:
+ return ROCE_SRQ_MODE_3;
+ case ROCE_CHIP_SRQ_MODE_2:
+ return ROCE_SRQ_MODE_2;
+ case ROCE_CHIP_SRQ_MODE_3:
+ return ROCE_SRQ_MODE_1;
+ case ROCE_CHIP_SRQ_MODE_4:
+ return ROCE_SRQ_MODE_0;
+ default:
+ return ROCE_SRQ_MODE_3;
+ }
+}
+
+int roce5_add_mac_tbl_mac_entry(struct roce5_device *rdev, u8 *mac_addr,
+ size_t mac_addr_len, u32 vlan_id, u16 func_id)
+{
+ void *hwdev = rdev->hwdev;
+ u16 er_fwd_id = rdev->glb_func_id;
+ roce_cfg_mac_cmd_s add_mac_entry_info;
+ u16 out_size = (u16)sizeof(add_mac_entry_info);
+ int ret;
+
+ if (ROCE5_SUPPORT_SML_MAC_TABLE(rdev) == 0) {
+ return 0;
+ }
+
+ if (rdev->hca_vf_mode != 0) {
+ ROCE_INFO("No need to add mac table entry.");
+ return 0;
+ }
+
+ if ((hwdev == NULL) || (mac_addr == NULL)) {
+ ROCE_ERR("Hwdev or mac_addr is null");
+ return -EINVAL;
+ }
+
+ if ((vlan_id & ROCE_VLAN_ID_MASK) >= ROCE_VLAN_N_VID) {
+ ROCE_ERR("Invalid vlan_id(%u)", vlan_id);
+ return -EINVAL;
+ }
+
+ ret = memset_s(&add_mac_entry_info, sizeof(add_mac_entry_info), 0,
+ sizeof(add_mac_entry_info));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset add_mac_entry_info.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ add_mac_entry_info.func_id = func_id;
+ add_mac_entry_info.vlan_id = vlan_id;
+ add_mac_entry_info.er_fwd_id = er_fwd_id;
+ ret = memcpy_s(add_mac_entry_info.mac, ETH_ALEN, mac_addr, ETH_ALEN);
+ if (ret != 0) {
+ ROCE_ERR("memory copy failed. ret%d", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_ADD_MAC,
+ &add_mac_entry_info,
+ sizeof(add_mac_entry_info),
+ &add_mac_entry_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ (add_mac_entry_info.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to add mac entry, err(%d), status(0x%x), out size(0x%x)",
+ ret, add_mac_entry_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce5_del_mac_tbl_mac_entry(struct roce5_device *rdev, u8 *mac_addr,
+ size_t mac_addr_len, u32 vlan_id, u16 func_id)
+{
+ void *hwdev = rdev->hwdev;
+ u16 er_fwd_id = rdev->glb_func_id;
+ roce_cfg_mac_cmd_s del_mac_tbl_info;
+ u16 out_size = (u16)sizeof(del_mac_tbl_info);
+ int ret;
+
+ if (ROCE5_SUPPORT_SML_MAC_TABLE(rdev) == 0) {
+ return 0;
+ }
+
+ if (rdev->hca_vf_mode != 0) {
+ ROCE_DEV_INFO(rdev, "No need to delete mac table entry.");
+ return 0;
+ }
+
+ if ((hwdev == NULL) || (mac_addr == NULL)) {
+ ROCE_ERR("Hwdev or mac_addr is null");
+ return -EINVAL;
+ }
+
+ if ((vlan_id & ROCE_VLAN_ID_MASK) >= ROCE_VLAN_N_VID) {
+ ROCE_ERR("Invalid vlan_id(%u)", vlan_id);
+ return -EINVAL;
+ }
+
+ ret = memset_s(&del_mac_tbl_info, sizeof(del_mac_tbl_info), 0,
+ sizeof(del_mac_tbl_info));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset del_mac_tbl_info.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ del_mac_tbl_info.func_id = func_id;
+ del_mac_tbl_info.vlan_id = vlan_id;
+ del_mac_tbl_info.er_fwd_id = er_fwd_id;
+ ret = memcpy_s(del_mac_tbl_info.mac, mac_addr_len, mac_addr,
+ mac_addr_len);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy_s dmac.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_DEL_MAC,
+ &del_mac_tbl_info,
+ sizeof(del_mac_tbl_info),
+ &del_mac_tbl_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ (del_mac_tbl_info.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to del mac entry, err(%d), status(0x%x), out size(0x%x)",
+ ret, del_mac_tbl_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void roce5_add_ipsu_tbl_mac_entry(struct roce5_device *rdev,
+ u8 mac_addr[ETH_ALEN], u32 vlan_id,
+ u16 func_id, u8 er_id, u16 src_func_id)
+{
+ void *hwdev = rdev->hwdev;
+ roce_cfg_ipsu_mac_cmd_s ipsu_add_mac_entry_info;
+ u16 out_size = (u16)sizeof(ipsu_add_mac_entry_info);
+ int ret;
+
+ if (rdev->hca_vf_mode != 0) {
+ ROCE_INFO("No need to add ipsu tbl mac entry");
+ return;
+ }
+
+#ifdef ROCE_BONDING_EN
+ if (!roce5_get_bond_ipsurx_en()) {
+ ROCE_ERR("No need to add ipsu tbl mac entry");
+ return;
+ }
+#endif
+
+ if ((hwdev == NULL) || (mac_addr == NULL)) {
+ ROCE_ERR("Hwdev or mac_addr is null");
+ return;
+ }
+
+ if ((vlan_id & ROCE_VLAN_ID_MASK) >= ROCE_VLAN_N_VID) {
+ ROCE_ERR("Invalid vlan_id(%u)", vlan_id);
+ }
+
+ ret = memset_s(&ipsu_add_mac_entry_info,
+ sizeof(ipsu_add_mac_entry_info), 0,
+ sizeof(ipsu_add_mac_entry_info));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset ipsu_add_mac_entry_info.(ret:%d)",
+ ret);
+ return;
+ }
+ ipsu_add_mac_entry_info.func_id = func_id;
+ ipsu_add_mac_entry_info.er_id = er_id;
+ ipsu_add_mac_entry_info.src_func_id = src_func_id;
+ ipsu_add_mac_entry_info.vlanid_vni = vlan_id & ROCE_VLAN_ID_MASK;
+ ipsu_add_mac_entry_info.vni_en = 0;
+ ret = memcpy_s(ipsu_add_mac_entry_info.mac, ETH_ALEN, mac_addr,
+ ETH_ALEN);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to memcpy ipsu_add_mac_entry_info.mac (ret:%d)",
+ ret);
+ return;
+ }
+
+ ret = roce5_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_ADD_IPSU_MAC,
+ &ipsu_add_mac_entry_info,
+ sizeof(ipsu_add_mac_entry_info),
+ &ipsu_add_mac_entry_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ ((ipsu_add_mac_entry_info.head.status != 0) &&
+ (ipsu_add_mac_entry_info.head.status != ERR_EXIST))) {
+ ROCE_ERR(
+ "Failed to add mac entry to IPSU, err(%d), status(0x%x), out size(0x%x)",
+ ret, ipsu_add_mac_entry_info.head.status, out_size);
+ return;
+ }
+
+ if (ipsu_add_mac_entry_info.head.status == ERR_EXIST) {
+ ROCE_INFO("This mac entry has been added to IPSU");
+ }
+
+ return;
+}
+
+static int32_t roce5_del_mac_entry_precheck(struct roce5_device *rdev,
+ void *hwdev, uint8_t *mac_addr,
+ uint32_t vlan_id)
+{
+ if (rdev->hca_vf_mode != 0) {
+ ROCE_DEV_INFO(rdev, "No need to del ipsu tbl mac entry.");
+ return -EINVAL;
+ }
+
+ if ((hwdev == NULL) || (mac_addr == NULL)) {
+ ROCE_DEV_ERR(rdev, "hwdev or mac_addr is null.");
+ return -EINVAL;
+ }
+
+#ifdef ROCE_BONDING_EN
+ if (!roce5_get_bond_ipsurx_en()) {
+ ROCE_DEV_INFO(rdev, "No need to del ipsu tbl mac entry.");
+ return -EINVAL;
+ }
+#endif
+
+ if ((vlan_id & ROCE_VLAN_ID_MASK) >= ROCE_VLAN_N_VID) {
+ ROCE_DEV_ERR(rdev, "Invalid vlan_id(%d).", vlan_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void roce5_del_ipsu_tbl_mac_entry(struct roce5_device *rdev,
+ u8 mac_addr[ETH_ALEN], size_t eth_alen,
+ u32 vlan_id, u8 er_id, u16 src_func_id)
+{
+ void *hwdev = rdev->hwdev;
+ u16 func_id = rdev->glb_func_id;
+ roce_cfg_ipsu_mac_cmd_s ipsu_del_mac_entry_info;
+ u16 out_size = (u16)sizeof(ipsu_del_mac_entry_info);
+ int ret;
+
+ ret = roce5_del_mac_entry_precheck(rdev, hwdev, mac_addr, vlan_id);
+ if (ret != 0) {
+ return;
+ }
+
+ ret = memset_s(&ipsu_del_mac_entry_info,
+ sizeof(ipsu_del_mac_entry_info), 0,
+ sizeof(ipsu_del_mac_entry_info));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset ipsu_del_mac_entry_info.(ret:%d)",
+ ret);
+ return;
+ }
+ ipsu_del_mac_entry_info.func_id = func_id;
+ ipsu_del_mac_entry_info.er_id = er_id;
+ ipsu_del_mac_entry_info.src_func_id = src_func_id;
+ ipsu_del_mac_entry_info.vlanid_vni = vlan_id & ROCE_VLAN_ID_MASK;
+ ipsu_del_mac_entry_info.vni_en = 0;
+ ret = memcpy_s(ipsu_del_mac_entry_info.mac, eth_alen, mac_addr,
+ eth_alen);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy_s dmac.(ret:%d)", ret);
+ return;
+ }
+
+ ret = roce5_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_DEL_IPSU_MAC,
+ &ipsu_del_mac_entry_info,
+ sizeof(ipsu_del_mac_entry_info),
+ &ipsu_del_mac_entry_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ ((ipsu_del_mac_entry_info.head.status != 0) &&
+ (ipsu_del_mac_entry_info.head.status != ERR_NOT_FOUND))) {
+ ROCE_ERR(
+ "Failed to del mac entry, err(%d), status(0x%x), out size(0x%x)",
+ ret, ipsu_del_mac_entry_info.head.status, out_size);
+ return;
+ }
+
+ if (ipsu_del_mac_entry_info.head.status == ERR_NOT_FOUND) {
+ ROCE_INFO("This mac entry of ipsu has been deleted");
+ }
+
+ return;
+}
+
+int roce5_add_ipsu_tbl_ip_entry(struct roce5_device *rdev,
+ struct roce_cmd_mpu_addr_info *addr_info)
+{
+ roce_cfg_ipsu_ip_cmd_s ipsu_add_ip_entry_info;
+ u16 out_size = sizeof(ipsu_add_ip_entry_info);
+ union roce_addr_info *ip = NULL;
+ int ret;
+
+ if ((rdev == NULL) || (rdev->hwdev == NULL) || (addr_info == NULL)) {
+ ROCE_ERR("rdev, hwdev or addr_info is null");
+ return -EINVAL;
+ }
+
+ ip = &addr_info->ip_addr;
+
+ ret = memset_s(&ipsu_add_ip_entry_info, sizeof(ipsu_add_ip_entry_info),
+ 0, sizeof(ipsu_add_ip_entry_info));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset ipsu_add_ip_entry_info.(ret:%d)",
+ ret);
+ return -ENOMEM;
+ }
+
+ ipsu_add_ip_entry_info.func_id = rdev->glb_func_id;
+ ipsu_add_ip_entry_info.ip_ver = addr_info->ip_ver;
+ ipsu_add_ip_entry_info.port_id = hinic5_physical_port_id(rdev->hwdev);
+ ret = memcpy_s(&ipsu_add_ip_entry_info.ip, sizeof(union roce_addr_info),
+ ip, sizeof(union roce_addr_info));
+ if (ret) {
+ ROCE_ERR("Failed to memcpy ip info.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ ROCE_INFO("funcid=%u,ipver=%u,portid=%u,ip=0x%x-%x-%x-%x",
+ ipsu_add_ip_entry_info.func_id, ipsu_add_ip_entry_info.ip_ver,
+ ipsu_add_ip_entry_info.port_id, ip->dw[0x0], ip->dw[0x1],
+ ip->dw[0x2], ip->dw[0x3]);
+
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_ADD_IPSU_IP,
+ &ipsu_add_ip_entry_info,
+ sizeof(ipsu_add_ip_entry_info),
+ &ipsu_add_ip_entry_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ ((ipsu_add_ip_entry_info.head.status != 0) &&
+ (ipsu_add_ip_entry_info.head.status != ERR_EXIST))) {
+ ROCE_ERR(
+ "Failed to add ip tbl entry to IPSU, err(%d), status(0x%x), out size(0x%x)",
+ ret, ipsu_add_ip_entry_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ if (ipsu_add_ip_entry_info.head.status == ERR_EXIST) {
+ ROCE_INFO("This ip tbl entry has been added to IPSU");
+ }
+
+ return 0;
+}
+
+int roce5_del_ipsu_tbl_ip_entry(struct roce5_device *rdev,
+ struct roce_cmd_mpu_addr_info *addr_info)
+{
+ roce_cfg_ipsu_ip_cmd_s ipsu_del_ip_entry_info;
+ u16 out_size = sizeof(ipsu_del_ip_entry_info);
+ union roce_addr_info *ip = NULL;
+ int ret;
+
+ if ((rdev == NULL) || (rdev->hwdev == NULL) || (addr_info == NULL)) {
+ ROCE_ERR("rdev, hwdev or addr_info is null");
+ return -EINVAL;
+ }
+
+ ip = &addr_info->ip_addr;
+
+ ret = memset_s(&ipsu_del_ip_entry_info, sizeof(ipsu_del_ip_entry_info),
+ 0, sizeof(ipsu_del_ip_entry_info));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset ipsu_add_ip_entry_info.(ret:%d)",
+ ret);
+ return -ENOMEM;
+ }
+
+ ipsu_del_ip_entry_info.func_id = rdev->glb_func_id;
+ ipsu_del_ip_entry_info.ip_ver = addr_info->ip_ver;
+ ipsu_del_ip_entry_info.port_id = hinic5_physical_port_id(rdev->hwdev);
+ ret = memcpy_s(&ipsu_del_ip_entry_info.ip, sizeof(union roce_addr_info),
+ ip, sizeof(union roce_addr_info));
+ if (ret) {
+ ROCE_ERR("Failed to memcpy ip info.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ ROCE_INFO("funcid=%u,ipver=%u,portid=%u,ip=0x%x-%x-%x-%x",
+ ipsu_del_ip_entry_info.func_id, ipsu_del_ip_entry_info.ip_ver,
+ ipsu_del_ip_entry_info.port_id, ip->dw[0x0], ip->dw[0x1],
+ ip->dw[0x2], ip->dw[0x3]);
+
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_DEL_IPSU_IP,
+ &ipsu_del_ip_entry_info,
+ sizeof(ipsu_del_ip_entry_info),
+ &ipsu_del_ip_entry_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ ((ipsu_del_ip_entry_info.head.status != 0) &&
+ (ipsu_del_ip_entry_info.head.status != ERR_NOT_FOUND))) {
+ ROCE_ERR(
+ "Failed to add ip tbl entry to IPSU, err(%d), status(0x%x), out size(0x%x)",
+ ret, ipsu_del_ip_entry_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ if (ipsu_del_ip_entry_info.head.status == ERR_NOT_FOUND) {
+ ROCE_INFO("This ip tbl entry of ipsu has been deleted");
+ }
+
+ return 0;
+}
+
+int roce5_modify_ipsu_tbl_ip_entry(struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry, u8 type)
+{
+ struct roce_cmd_mpu_addr_info addr_info = { 0 };
+ union roce_addr_info *ip = NULL;
+ int ret;
+
+ if ((rdev == NULL) || (rdev->hwdev == NULL) || (gid_entry == NULL)) {
+ ROCE_ERR("rdev, hwdev or gid_entry is null");
+ return -EINVAL;
+ }
+
+ ip = (union roce_addr_info *)&gid_entry->raw;
+
+ if (rdev->hca_vf_mode == 0) {
+ ROCE_INFO("No need to modify ipsu tbl ip entry");
+ return 0;
+ }
+
+ if (gid_entry->dw6_h.bs.gid_type >= ROCE_ROCEv1_GID) {
+ ROCE_ERR("gid_type:%d is unsupported",
+ gid_entry->dw6_h.bs.gid_type);
+ return -EINVAL;
+ }
+
+ ret = memcpy_s(&addr_info.ip_addr, sizeof(union roce_addr_info), ip,
+ sizeof(union roce_addr_info));
+ if (ret) {
+ ROCE_ERR("Failed to memcpy ip info.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ if (gid_entry->dw6_h.bs.gid_type == ROCE_IPv4_ROCEv2_GID) {
+ addr_info.ip_addr.dw[0x0] = 0x0;
+ addr_info.ip_addr.dw[0x1] = 0x0;
+ addr_info.ip_addr.dw[0x2] = 0x0;
+ addr_info.ip_ver = 0;
+ } else {
+ addr_info.ip_ver = 1;
+ }
+
+ if (type == ROCE_MPU_CMD_ADD_IPSU_IP) {
+ return roce5_add_ipsu_tbl_ip_entry(rdev, &addr_info);
+ }
+
+ return roce5_del_ipsu_tbl_ip_entry(rdev, &addr_info);
+}
+
+static int32_t
+roce5_add_ipsu_tcam_tbl_entry_precheck(struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry)
+{
+ if ((rdev->hwdev == NULL) || (gid_entry == NULL)) {
+ ROCE_DEV_ERR(rdev, "hwdev or gid_entry is null.");
+ return -EINVAL;
+ }
+
+ if (gid_entry->dw6_h.bs.gid_type >= ROCE_ROCEv1_GID) {
+ ROCE_DEV_ERR(rdev, "gid_type:%d is unsupported.",
+ gid_entry->dw6_h.bs.gid_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int32_t roce5_ipsu_tcam_tbl_set_entry(
+ struct roce5_device *rdev, struct rdma_gid_entry *gid_entry,
+ uint32_t gid_index, roce_cfg_ipsu_tcam_cmd_s *ipsu_add_tcam_entry_info)
+{
+ union roce_addr_info *ip = (union roce_addr_info *)&gid_entry->raw;
+ int32_t i;
+ int32_t ret;
+
+ ipsu_add_tcam_entry_info->func_id = rdev->glb_func_id;
+ ipsu_add_tcam_entry_info->ip_ver = gid_entry->dw6_h.bs.gid_type;
+ ipsu_add_tcam_entry_info->gid_idx = gid_index;
+ ret = memcpy_s(&ipsu_add_tcam_entry_info->ip,
+ sizeof(union roce_addr_info), ip,
+ sizeof(union roce_addr_info));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy ip info.(ret:%d).", ret);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 0x4; i++) {
+ ipsu_add_tcam_entry_info->ip.dw[i] =
+ htonl(ipsu_add_tcam_entry_info->ip.dw[i]);
+ }
+
+ if (gid_entry->dw6_h.bs.gid_type == ROCE_IPv4_ROCEv2_GID) {
+ ipsu_add_tcam_entry_info->ip.dw[0x0] = 0x0;
+ ipsu_add_tcam_entry_info->ip.dw[0x1] = 0x0;
+ ipsu_add_tcam_entry_info->ip.dw[0x2] = 0x0;
+ }
+
+ return 0;
+}
+
+void roce5_add_ipsu_tcam_tbl_entry(struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry,
+ u32 gid_index)
+{
+ roce_cfg_ipsu_tcam_cmd_s ipsu_add_tcam_entry_info;
+ u16 out_size = sizeof(roce_cfg_ipsu_tcam_cmd_s);
+ int ret;
+
+ ret = roce5_add_ipsu_tcam_tbl_entry_precheck(rdev, gid_entry);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to precheck params(ret:%d).", ret);
+ return;
+ }
+
+ ret = memset_s(&ipsu_add_tcam_entry_info,
+ sizeof(ipsu_add_tcam_entry_info), 0,
+ sizeof(ipsu_add_tcam_entry_info));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to memset ipsu_tcam_entry_info(ret:%d).",
+ ret);
+ return;
+ }
+
+ ret = roce5_ipsu_tcam_tbl_set_entry(rdev, gid_entry, gid_index,
+ &ipsu_add_tcam_entry_info);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to set ipsu_tcam_entry_info(ret:%d).",
+ ret);
+ return;
+ }
+
+ ROCE_DEV_INFO(rdev, "funcid=%u,ipver=%u,gid_idx=%u,ip=0x%x-%x-%x-%x.",
+ ipsu_add_tcam_entry_info.func_id,
+ ipsu_add_tcam_entry_info.ip_ver,
+ ipsu_add_tcam_entry_info.gid_idx,
+ ipsu_add_tcam_entry_info.ip.dw[0x0],
+ ipsu_add_tcam_entry_info.ip.dw[0x1],
+ ipsu_add_tcam_entry_info.ip.dw[0x2],
+ ipsu_add_tcam_entry_info.ip.dw[0x3]);
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_ADD_IPSU_TCAM,
+ &ipsu_add_tcam_entry_info,
+ sizeof(ipsu_add_tcam_entry_info),
+ &ipsu_add_tcam_entry_info, &out_size);
+ if (ipsu_add_tcam_entry_info.head.status == ERR_FULL) {
+ ROCE_DEV_INFO(rdev, "TCAM Table is full.");
+ } else if ((ret == 0) && (out_size != 0) &&
+ (ipsu_add_tcam_entry_info.head.status == ERR_EXIST)) {
+ ROCE_DEV_INFO(rdev, "This tcam entry has been added to IPSU.");
+ } else if ((ret != 0) || (out_size == 0) ||
+ ((ipsu_add_tcam_entry_info.head.status != 0))) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to add tcam tbl entry to IPSU, err(%d), status(0x%x), out size(0x%x).",
+ ret, ipsu_add_tcam_entry_info.head.status, out_size);
+ return;
+ }
+
+ return;
+}
+
+static int32_t
+roce5_del_ipsu_tcam_tbl_entry_precheck(struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry)
+{
+ if ((rdev->hwdev == NULL) || (gid_entry == NULL)) {
+ ROCE_DEV_ERR(rdev, "hwdev or gid_entry is null.");
+ return -EINVAL;
+ }
+
+ if (gid_entry->dw6_h.bs.gid_type >= ROCE_ROCEv1_GID) {
+ ROCE_DEV_ERR(rdev, "gid_type:%d is unsupported",
+ gid_entry->dw6_h.bs.gid_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void roce5_del_ipsu_tcam_tbl_entry(struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry)
+{
+ roce_cfg_ipsu_tcam_cmd_s ipsu_del_tcam_entry_info;
+ u16 out_size = sizeof(roce_cfg_ipsu_tcam_cmd_s);
+ int ret;
+
+ ret = roce5_del_ipsu_tcam_tbl_entry_precheck(rdev, gid_entry);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to precheck params(ret:%d).", ret);
+ return;
+ }
+
+ ret = memset_s(&ipsu_del_tcam_entry_info,
+ sizeof(ipsu_del_tcam_entry_info), 0,
+ sizeof(ipsu_del_tcam_entry_info));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to memset ipsu_tcam_entry_info(ret:%d).",
+ ret);
+ return;
+ }
+
+ ret = roce5_ipsu_tcam_tbl_set_entry(rdev, gid_entry, 0,
+ &ipsu_del_tcam_entry_info);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to set ipsu_tcam_entry_info(ret:%d).",
+ ret);
+ return;
+ }
+
+ ROCE_DEV_INFO(rdev, "funcid=%u,ipver=%u,gid_idx=%u,ip=0x%x-%x-%x-%x",
+ ipsu_del_tcam_entry_info.func_id,
+ ipsu_del_tcam_entry_info.ip_ver,
+ ipsu_del_tcam_entry_info.gid_idx,
+ ipsu_del_tcam_entry_info.ip.dw[0x0],
+ ipsu_del_tcam_entry_info.ip.dw[0x1],
+ ipsu_del_tcam_entry_info.ip.dw[0x2],
+ ipsu_del_tcam_entry_info.ip.dw[0x3]);
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_DEL_IPSU_TCAM,
+ &ipsu_del_tcam_entry_info,
+ sizeof(ipsu_del_tcam_entry_info),
+ &ipsu_del_tcam_entry_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ ((ipsu_del_tcam_entry_info.head.status != 0) &&
+ (ipsu_del_tcam_entry_info.head.status != ERR_NOT_FOUND))) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to del tcam entry, err(%d), status(0x%x), out size(0x%x).",
+ ret, ipsu_del_tcam_entry_info.head.status, out_size);
+ return;
+ }
+
+ if (ipsu_del_tcam_entry_info.head.status == ERR_NOT_FOUND) {
+ ROCE_DEV_INFO(rdev,
+ "This tcam entry of ipsu has been deleted.");
+ }
+ return;
+}
+
+int roce5_set_sysfs_cfg_param(void *hwdev, u16 func_id, u32 *param,
+ u32 param_len, u16 type)
+{
+ roce_cc_cfg_param_cmd_s cfg_param;
+ u16 out_size = (u16)sizeof(cfg_param);
+ int ret;
+ int param_idx = 0;
+ int param_dw_num;
+
+ if (hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return -EINVAL;
+ }
+
+ param_dw_num = (int)(param_len / sizeof(u32));
+ if (param_dw_num > ROCE_CC_CFG_PARAM_MAX_DW_NUM) {
+ ROCE_ERR("cfg_param len :%d dw_num:%d exceed max, type:0x%x",
+ param_len, param_dw_num, type);
+ return -EINVAL;
+ }
+
+ ret = memset_s(&cfg_param, sizeof(cfg_param), 0, sizeof(cfg_param));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset cfg_param.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ cfg_param.func_id = func_id;
+ for (; param_idx < param_dw_num; param_idx++) {
+ cfg_param.param[param_idx] = param[param_idx];
+ }
+
+ ret = roce5_msg_to_mgmt_sync(hwdev, type, &cfg_param, sizeof(cfg_param),
+ &cfg_param, &out_size);
+ if ((ret != 0) || (out_size == 0) || (cfg_param.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to cfg param, err(%d), status(0x%x), out size(0x%x), type(0x%x)",
+ ret, cfg_param.head.status, out_size, type);
+
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int roce5_set_func_tbl_func_state(void *hwdev, u8 func_state, u16 func_id)
+{
+ roce_set_func_state_cmd_s set_func_state_info;
+ u16 out_size = (u16)sizeof(set_func_state_info);
+ int ret;
+
+ if (hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return (-EINVAL);
+ }
+
+ ret = memset_s(&set_func_state_info, sizeof(set_func_state_info), 0,
+ sizeof(set_func_state_info));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset set_func_state_info.(ret:%d)", ret);
+ return (-ENOMEM);
+ }
+ set_func_state_info.func_id = func_id;
+ set_func_state_info.func_en = func_state;
+ ret = roce5_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_SET_FUNC_STATE,
+ &set_func_state_info,
+ sizeof(set_func_state_info),
+ &set_func_state_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ (set_func_state_info.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to set func state(%d), err(%d), status(0x%x), out size(0x%x), func_id(%d)",
+ func_state, ret, set_func_state_info.head.status,
+ out_size, func_id);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+int roce5_get_func_table(void *hwdev, u16 func_id, u32 *func_tbl_value)
+{
+ roce_get_func_table_cmd_s get_func_table;
+ roce_get_func_table_rsp_s get_func_table_rsp;
+ u16 out_size = (u16)sizeof(get_func_table_rsp);
+ int ret;
+
+ if (hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return (-EINVAL);
+ }
+
+ ret = memset_s(&get_func_table, sizeof(get_func_table), 0,
+ sizeof(get_func_table));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset get_func_table.(ret:%d)", ret);
+ return (-ENOMEM);
+ }
+ ret = memset_s(&get_func_table_rsp, out_size, 0, out_size);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset get_func_table_rsp.(ret:%d)", ret);
+ return (-ENOMEM);
+ }
+ get_func_table.func_id = func_id;
+ ret = roce5_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_GET_FUNC_TABLE,
+ &get_func_table, sizeof(get_func_table),
+ &get_func_table_rsp, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ (get_func_table_rsp.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to get func table, err(%d), status(0x%x), out size(0x%x), func_id(%d)",
+ ret, get_func_table_rsp.head.status, out_size, func_id);
+ return (-EINVAL);
+ }
+
+ *func_tbl_value = get_func_table_rsp.func_tbl_value;
+
+ return 0;
+}
+
+int roce5_set_func_tbl_cpu_endian(struct roce5_device *rdev)
+{
+ roce_set_cpu_endian_cmd_s set_cpu_endian_info;
+ u16 out_size = (u16)sizeof(set_cpu_endian_info);
+ int ret;
+
+ if (rdev->hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return -EINVAL;
+ }
+
+ ret = memset_s(&set_cpu_endian_info, sizeof(set_cpu_endian_info), 0,
+ sizeof(set_cpu_endian_info));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to memset set_cpu_endian_info.(ret:%d).",
+ ret);
+ return -ENOMEM;
+ }
+ set_cpu_endian_info.func_id = rdev->glb_func_id;
+ set_cpu_endian_info.cpu_endian = rdev->hw_info.cpu_endian;
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_SET_CPU_ENDIAN,
+ &set_cpu_endian_info,
+ sizeof(set_cpu_endian_info),
+ &set_cpu_endian_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ (set_cpu_endian_info.head.status != 0)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set func state, err(%d), status(0x%x), out size(0x%x).",
+ ret, set_cpu_endian_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void roce5_init_cfg_info_parse_resp(struct roce5_device *rdev,
+ roce_get_cfg_info_resp_s *resp)
+{
+ rdev->cfg_info.scence_id = resp->scence_id;
+ rdev->cfg_info.lb_en = resp->lb_en;
+ rdev->cfg_info.lb_mode = resp->lb_mode;
+ rdev->cfg_info.srq_container_en =
+ (resp->container_mode != ROCE_CHIP_SRQ_MODE_N);
+ rdev->cfg_info.srq_container_mode =
+ roce5_srq_mode_chip_adapt(resp->container_mode);
+ rdev->cfg_info.xrc_srq_container_mode = ROCE_SRQ_MODE_3;
+ rdev->cfg_info.warn_th = 0;
+
+ rdev->cfg_info.fake_en = resp->fake_en;
+ rdev->cfg_info.pf_start_bit = resp->pf_start_bit;
+ rdev->cfg_info.pf_end_bit = resp->pf_end_bit;
+ rdev->cfg_info.page_bit = resp->page_bit;
+
+ rdev->cfg_info.port_num = resp->port_num;
+ rdev->cfg_info.host_num = resp->host_num;
+ rdev->cfg_info.pcie_atomic_en = resp->pcie_atomic_en;
+
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_wqes = resp->max_wqe;
+ rdev->rdma_cap.max_cqes = resp->max_cqe;
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_srq_wqes =
+ resp->max_srq_wqe;
+ rdev->rdma_cap.max_sq_sg = resp->max_sq_sge;
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_rq_sg = resp->max_rq_sge;
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_srq_sge =
+ resp->max_srq_sge;
+ rdev->rdma_cap.max_sq_desc_sz = resp->max_sq_wqe_len;
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_rq_desc_sz =
+ resp->max_rq_wqe_len;
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_sq_inline_data_sz =
+ resp->max_sq_inline;
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_pd = resp->max_pd;
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_xrcd = resp->max_xrcd;
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_gid = resp->max_gid;
+
+ rdev->hca_vf_mode = resp->ip2func;
+
+ roce5_cfg_info_update_ext(rdev, resp);
+}
+
+int roce5_get_feature(struct roce5_device *rdev,
+ roce_get_chip_ability_s *roce_feature)
+{
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_verbs_cmd_header_s *cmd_hdr = NULL;
+ roce_get_chip_ability_s *resp_buf = NULL;
+ int ret = 0;
+
+ ret = memset_s(roce_feature, sizeof(*roce_feature), 0,
+ sizeof(*roce_feature));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset roce_feature, ret(%d).", ret);
+ return (-ENOMEM);
+ }
+
+ // allocate input and output buffer
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ sizeof(roce_verbs_cmd_header_s),
+ &cqm_cmd_outbuf,
+ sizeof(roce_get_chip_ability_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to allocate cqm buffers, ret = %d.",
+ ret);
+ return ret;
+ }
+
+ // fill input command
+ cmd_hdr = (roce_verbs_cmd_header_s *)cqm_cmd_inbuf->buf;
+ cmd_hdr->dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_COMM_BITMASK);
+
+ // send command and wait response
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_GET_CHIP_ABILITY, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, NULL, ROCE_CMD_TIME_CLASS_C,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to send feature cmd, ret = %d.",
+ ret);
+ goto free_buf;
+ }
+
+ // get response data
+ resp_buf = (roce_get_chip_ability_s *)cqm_cmd_outbuf->buf;
+ roce_feature->roce_kernel_ability =
+ be64_to_cpu(resp_buf->roce_kernel_ability);
+ roce_feature->roce_kernel_ext_ability =
+ be64_to_cpu(resp_buf->roce_kernel_ext_ability);
+ roce_feature->roce_user_ext_ability =
+ be64_to_cpu(resp_buf->roce_user_ext_ability);
+
+ // get on layer service supported attribute
+ roce_feature->uld_feature.roce_uld_kernel_ext_ability =
+ be64_to_cpu(resp_buf->uld_feature.roce_uld_kernel_ext_ability);
+ roce_feature->uld_feature.roce_uld_user_ext_ability =
+ be64_to_cpu(resp_buf->uld_feature.roce_uld_user_ext_ability);
+free_buf:
+ // free buffer
+ if (cqm_cmd_inbuf || cqm_cmd_outbuf) {
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+ }
+ return ret;
+}
+
+int roce5_uni_cmd_init_cfg_info(struct roce5_device *rdev)
+{
+ roce_get_cfg_info_cmd_s get_cfg_info;
+ roce_get_cfg_info_resp_s resp;
+ u16 out_size = (u16)sizeof(resp);
+ int ret = 0;
+
+ ret = memset_s(&get_cfg_info, sizeof(get_cfg_info), 0,
+ sizeof(get_cfg_info));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset get_cfg_info, ret(%d).", ret);
+ return (-ENOMEM);
+ }
+ ret = memset_s(&resp, sizeof(resp), 0, sizeof(resp));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset resp, ret(%d).", ret);
+ return (-ENOMEM);
+ }
+
+ get_cfg_info.func_id = rdev->glb_func_id;
+
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_GET_CFG_INFO,
+ &get_cfg_info, sizeof(get_cfg_info), &resp,
+ &out_size);
+ if ((ret != 0) || (out_size == 0) || (get_cfg_info.head.status != 0)) {
+ ROCE_DEV_ERR(rdev,
+ "Failed, err(%d), status(0x%x), out size(0x%x)",
+ ret, get_cfg_info.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ roce5_init_cfg_info_parse_resp(rdev, &resp);
+
+ ROCE_DEV_INFO(
+ rdev,
+ "init, func_id(%d), lb_en(%d), lb_mode(%d), srq_mode(%d), scence_id(%d), pcie_atomic_en(%d).",
+ rdev->glb_func_id, rdev->cfg_info.lb_en, rdev->cfg_info.lb_mode,
+ rdev->cfg_info.srq_container_mode, rdev->cfg_info.scence_id,
+ rdev->cfg_info.pcie_atomic_en);
+ ROCE_DEV_INFO(
+ rdev,
+ "max_wqes(0x%x), max_cqes(0x%x), max_srq_wqes(0x%x), max_sq_sg(0x%x), max_rq_sg(0x%x), "
+ "max_srq_sge(0x%x), max_sq_desc_sz(0x%x), max_rq_desc_sz(0x%x), max_sq_inline_data_sz(0x%x).",
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_wqes,
+ rdev->rdma_cap.max_cqes,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_srq_wqes,
+ rdev->rdma_cap.max_sq_sg,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_rq_sg,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_srq_sge,
+ rdev->rdma_cap.max_sq_desc_sz,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_rq_desc_sz,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_sq_inline_data_sz);
+
+ return 0;
+}
+
+int roce5_init_cfg_info(struct roce5_device *rdev)
+{
+ roce_get_cfg_info_cmd_s get_cfg_info;
+ roce_get_cfg_info_comp_resp_s resp;
+ u16 out_size = (u16)sizeof(resp);
+ int ret = 0;
+
+ if (rdev == NULL || rdev->hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return (-EINVAL);
+ }
+
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ return roce5_uni_cmd_init_cfg_info(rdev);
+ }
+
+ (void)memset_s(&get_cfg_info, sizeof(get_cfg_info), 0,
+ sizeof(get_cfg_info));
+ (void)memset_s(&resp, sizeof(resp), 0, sizeof(resp));
+
+ get_cfg_info.func_id = rdev->glb_func_id;
+
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_GET_CFG_INFO,
+ &get_cfg_info, sizeof(get_cfg_info), &resp,
+ &out_size);
+ if ((ret != 0) || (out_size == 0) || (get_cfg_info.head.status != 0)) {
+ ROCE_DEV_ERR(rdev,
+ "Failed, err(%d), status(0x%x), out size(0x%x)",
+ ret, get_cfg_info.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ rdev->cfg_info.scence_id = resp.scence_id;
+ rdev->cfg_info.lb_en = resp.lb_en;
+ rdev->cfg_info.lb_mode = resp.lb_mode;
+ rdev->cfg_info.srq_container_en =
+ (resp.container_mode != ROCE_CHIP_SRQ_MODE_N);
+ rdev->cfg_info.srq_container_mode =
+ roce5_srq_mode_chip_adapt(resp.container_mode);
+ rdev->cfg_info.xrc_srq_container_mode = ROCE_SRQ_MODE_3;
+ rdev->cfg_info.warn_th = 0;
+
+ rdev->cfg_info.fake_en = resp.fake_en;
+ rdev->cfg_info.pf_start_bit = resp.pf_start_bit;
+ rdev->cfg_info.pf_end_bit = resp.pf_end_bit;
+ rdev->cfg_info.page_bit = resp.page_bit;
+
+ rdev->cfg_info.port_num = resp.port_num;
+ rdev->cfg_info.host_num = resp.host_num;
+ rdev->cfg_info.pcie_atomic_en = resp.pcie_atomic_en;
+
+ rdev->hca_vf_mode = 0; // V100 fixed to mac mode
+
+ ROCE_DEV_INFO(
+ rdev,
+ "init, func_id(%d), lb_en(%d), lb_mode(%d), srq_mode(%d), scence_id(%d), pcie_atomic_en(%d).",
+ rdev->glb_func_id, rdev->cfg_info.lb_en, rdev->cfg_info.lb_mode,
+ rdev->cfg_info.srq_container_mode, rdev->cfg_info.scence_id,
+ rdev->cfg_info.pcie_atomic_en);
+ return 0;
+}
+
+int roce5_del_func_res(struct roce5_device *rdev)
+{
+ roce_set_func_state_cmd_s del_func_res_info;
+ u16 out_size = (u16)sizeof(del_func_res_info);
+ int ret;
+
+ if ((rdev == NULL) || (rdev->hwdev == NULL)) {
+ ROCE_ERR("rdev/Hwdev is null");
+ return (-EINVAL);
+ }
+
+ ret = memset_s(&del_func_res_info, sizeof(del_func_res_info), 0,
+ sizeof(del_func_res_info));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset del_func_res_info.(ret:%d)", ret);
+ return (-ENOMEM);
+ }
+ del_func_res_info.func_id = rdev->glb_func_id;
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_DEL_FUNC_RES,
+ &del_func_res_info,
+ sizeof(del_func_res_info),
+ &del_func_res_info, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ (del_func_res_info.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to set func state, err(%d), status(0x%x), out size(0x%x)",
+ ret, del_func_res_info.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+int roce5_set_bw_ctrl_state(struct roce5_device *rdev, u8 cmd,
+ struct roce5_bw_ctrl_inbuf *inbuf)
+{
+ int ret = 0;
+ roce_cc_cfg_bw_ctrl_cmd_s set_bw_ctrl;
+ u16 out_size = (u16)sizeof(set_bw_ctrl);
+
+ if (rdev->hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return (-EINVAL);
+ }
+
+ ret = memset_s(&set_bw_ctrl, sizeof(set_bw_ctrl), 0,
+ sizeof(set_bw_ctrl));
+ if (ret != 0) {
+ ROCE_ERR("Memset failed when set_bw_ctrl cmd");
+ return (-ENOMEM);
+ }
+
+ set_bw_ctrl.func_id = rdev->glb_func_id;
+ set_bw_ctrl.cmd = cmd;
+ set_bw_ctrl.cir = inbuf->ctrl_param.cir;
+ set_bw_ctrl.pir = inbuf->ctrl_param.pir;
+ set_bw_ctrl.cnp = inbuf->ctrl_param.cnp;
+ ROCE_INFO("func_id:%u, cmd:%u, cir:%u, pir:%u, cnp:%u",
+ rdev->glb_func_id, set_bw_ctrl.cmd, set_bw_ctrl.cir,
+ set_bw_ctrl.pir, set_bw_ctrl.cnp);
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_CC_SET_BW_CTRL,
+ &set_bw_ctrl, sizeof(set_bw_ctrl),
+ &set_bw_ctrl, &out_size);
+ if ((ret != 0) || (out_size == 0) || (set_bw_ctrl.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to set set_bw_ctrl cmd, err(%d), status(0x%x), out size(0x%x)",
+ ret, set_bw_ctrl.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+int roce5_query_bw_ctrl_state(struct roce5_device *rdev,
+ struct roce5_bw_ctrl_param *bw_ctrl_param)
+{
+ int ret = 0;
+ roce_cc_cfg_bw_ctrl_cmd_s query_bw_ctrl;
+ u16 out_size = (u16)sizeof(query_bw_ctrl);
+
+ if (rdev->hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return (-EINVAL);
+ }
+
+ ret = memset_s(&query_bw_ctrl, sizeof(query_bw_ctrl), 0,
+ sizeof(query_bw_ctrl));
+ if (ret != 0) {
+ ROCE_ERR("Memset failed when set_bw_ctrl cmd");
+ return (-ENOMEM);
+ }
+
+ query_bw_ctrl.func_id = rdev->glb_func_id;
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_CC_QUERY_BW_CTRL,
+ &query_bw_ctrl, sizeof(query_bw_ctrl),
+ &query_bw_ctrl, &out_size);
+ if ((ret != 0) || (out_size == 0) || (query_bw_ctrl.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to set query_bw_ctrl cmd, err(%d), status(0x%x), out size(0x%x)",
+ ret, query_bw_ctrl.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ ret = memcpy_s((void *)bw_ctrl_param,
+ sizeof(struct roce5_bw_ctrl_param),
+ (void *)((u8 *)(&query_bw_ctrl) + ROCE_CMD_DEFAULT_SIZE),
+ sizeof(struct roce5_bw_ctrl_param));
+ if (ret != 0) {
+ ROCE_ERR("memory copy failed. ret%d", ret);
+ return -ENOMEM;
+ }
+
+ ROCE_INFO("query_bw_ctrl_state:func_id:%u, cir:%u, pir:%u, cnp:%u",
+ rdev->glb_func_id, bw_ctrl_param->cir, bw_ctrl_param->pir,
+ bw_ctrl_param->cnp);
+
+ return 0;
+}
+
+#ifdef ROCE_CHIP_TEST
+int roce5_set_vnic_waterline_state(struct roce5_device *rdev,
+ struct roce5_vnic_waterline_ctrl_buf *inbuf,
+ struct roce5_vnic_waterline_ctrl_buf *outbuf)
+{
+ int ret = 0;
+ roce_cc_cfg_vnic_waterline_cmd_s set_vnic_waterline;
+ u16 out_size = (u16)sizeof(set_vnic_waterline);
+
+ (void)outbuf;
+ if (rdev->hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return (-EINVAL);
+ }
+
+ ret = memset_s(&set_vnic_waterline, sizeof(set_vnic_waterline), 0,
+ sizeof(set_vnic_waterline));
+ if (ret != 0) {
+ ROCE_ERR("Memset failed when set_vnic_waterline cmd");
+ return (-ENOMEM);
+ }
+
+ set_vnic_waterline.func_id = rdev->glb_func_id;
+ set_vnic_waterline.ip_ver = 0;
+ set_vnic_waterline.param.red_waterline =
+ inbuf->waterline_param.red_waterline;
+ set_vnic_waterline.param.yellow_waterline =
+ inbuf->waterline_param.yellow_waterline;
+ set_vnic_waterline.param.ip_info.ipv4.val =
+ inbuf->waterline_param.ip_val;
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev,
+ ROCE_MPU_CMD_CC_SET_VNIC_WATERLINE,
+ &set_vnic_waterline,
+ sizeof(set_vnic_waterline),
+ &set_vnic_waterline, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ (set_vnic_waterline.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to set set_vnic_waterline cmd, err(%d), status(0x%x), out size(0x%x)",
+ ret, set_vnic_waterline.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+int roce5_get_vnic_waterline_state(struct roce5_device *rdev,
+ struct roce5_vnic_waterline_ctrl_buf *inbuf,
+ struct roce5_vnic_waterline_ctrl_buf *outbuf)
+{
+ int ret = 0;
+ roce_cc_cfg_vnic_waterline_cmd_s get_vnic_waterline;
+ u16 out_size = (u16)sizeof(get_vnic_waterline);
+
+ if (rdev->hwdev == NULL) {
+ ROCE_ERR("Hwdev is null");
+ return (-EINVAL);
+ }
+
+ ret = memset_s(&get_vnic_waterline, sizeof(get_vnic_waterline), 0,
+ sizeof(get_vnic_waterline));
+ if (ret != 0) {
+ ROCE_ERR("Memset failed when get_vnic_waterline cmd");
+ return (-ENOMEM);
+ }
+
+ get_vnic_waterline.func_id = rdev->glb_func_id;
+ get_vnic_waterline.ip_ver = 0;
+ get_vnic_waterline.param.ip_info.ipv4.val =
+ inbuf->waterline_param.ip_val;
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev,
+ ROCE_MPU_CMD_CC_GET_VNIC_WATERLINE,
+ &get_vnic_waterline,
+ sizeof(get_vnic_waterline),
+ &get_vnic_waterline, &out_size);
+ if ((ret != 0) || (out_size == 0) ||
+ (get_vnic_waterline.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to set get_vnic_waterline cmd, err(%d), status(0x%x), out size(0x%x)",
+ ret, get_vnic_waterline.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ outbuf->waterline_param.red_waterline =
+ get_vnic_waterline.param.red_waterline;
+ outbuf->waterline_param.yellow_waterline =
+ get_vnic_waterline.param.yellow_waterline;
+
+ return 0;
+}
+#endif /* ROCE_CHIP_TEST */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/cmd/roce_cmd.h b/drivers/infiniband/hw/hiroce5/kernel/dev/cmd/roce_cmd.h
new file mode 100644
index 000000000..5fd787a67
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/cmd/roce_cmd.h
@@ -0,0 +1,82 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_CMD_H
+#define ROCE_CMD_H
+
+#include "comm_defs.h"
+#include "roce.h"
+#include "roce_dfx.h"
+#include "roce_srq.h"
+
+#include "roce_mpu_cmd_defs.h"
+#include "roce_cfg_format.h"
+
+#define ROCE_VLAN_ID_MASK 0x7FFF
+#define ROCE_VLAN_N_VID 4096
+
+#define ROCE_CMD_DEFAULT_SIZE 12
+
+#define ERR_EXIST 6
+#define ERR_FULL 12
+#define ERR_NOT_FOUND 13
+
+#define roce5_msg_to_mgmt_sync(hwdev, cmd, buf_in, in_size, buf_out, out_size) \
+ hinic5_msg_to_mgmt_sync(hwdev, HINIC5_MOD_ROCE, cmd, buf_in, in_size, \
+ buf_out, out_size, 0, HINIC5_CHANNEL_ROCE)
+#define roce5_msg_to_ovs_mgmt_sync(hwdev, cmd, buf_in, in_size, buf_out, \
+ out_size) \
+ hinic5_msg_to_mgmt_sync(hwdev, HINIC5_MOD_OVS, cmd, buf_in, in_size, \
+ buf_out, out_size, 90000, HINIC5_CHANNEL_OVS)
+
+int roce5_add_mac_tbl_mac_entry(struct roce5_device *rdev, u8 *mac_addr,
+ size_t mac_addr_len, u32 vlan_id, u16 func_id);
+int roce5_del_mac_tbl_mac_entry(struct roce5_device *rdev, u8 *mac_addr,
+ size_t mac_addr_len, u32 vlan_id, u16 func_id);
+typedef int (*roce5_modify_mac_tbl)(struct roce5_device *rdev,
+ u8 mac_addr[ETH_ALEN], size_t eth_alen,
+ u32 vlan_id, u16 func_id);
+void roce5_add_ipsu_tbl_mac_entry(struct roce5_device *rdev,
+ u8 mac_addr[ETH_ALEN], u32 vlan_id,
+ u16 func_id, u8 er_id, u16 src_func_id);
+void roce5_del_ipsu_tbl_mac_entry(struct roce5_device *rdev,
+ u8 mac_addr[ETH_ALEN], size_t eth_alen,
+ u32 vlan_id, u8 er_id, u16 src_func_id);
+int roce5_add_ipsu_tbl_ip_entry(struct roce5_device *rdev,
+ struct roce_cmd_mpu_addr_info *addr_info);
+int roce5_del_ipsu_tbl_ip_entry(struct roce5_device *rdev,
+ struct roce_cmd_mpu_addr_info *addr_info);
+int roce5_modify_ipsu_tbl_ip_entry(struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry, u8 type);
+void roce5_add_ipsu_tcam_tbl_entry(struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry,
+ u32 gid_index);
+void roce5_del_ipsu_tcam_tbl_entry(struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry);
+typedef void (*roce5_modify_ipsu_tbl_mac)(void *hwdev, u8 mac_addr[ETH_ALEN],
+ u32 vlan_id, u16 func_id, u8 er_id);
+
+int roce5_set_sysfs_cfg_param(void *hwdev, u16 func_id, u32 *param,
+ u32 param_len, u16 type);
+int roce5_set_bw_ctrl_state(struct roce5_device *rdev, u8 cmd,
+ struct roce5_bw_ctrl_inbuf *inbuf);
+int roce5_query_bw_ctrl_state(struct roce5_device *rdev,
+ struct roce5_bw_ctrl_param *bw_ctrl_param);
+#ifdef ROCE_CHIP_TEST
+int roce5_set_vnic_waterline_state(struct roce5_device *rdev,
+ struct roce5_vnic_waterline_ctrl_buf *inbuf,
+ struct roce5_vnic_waterline_ctrl_buf *outbuf);
+int roce5_get_vnic_waterline_state(struct roce5_device *rdev,
+ struct roce5_vnic_waterline_ctrl_buf *inbuf,
+ struct roce5_vnic_waterline_ctrl_buf *outbuf);
+#endif /* ROCE_CHIP_TEST */
+int roce5_set_func_tbl_func_state(void *hwdev, u8 func_state, u16 func_id);
+int roce5_get_func_table(void *hwdev, u16 func_id, u32 *func_tbl_value);
+int roce5_set_func_tbl_cpu_endian(struct roce5_device *rdev);
+int roce5_get_feature(struct roce5_device *rdev,
+ roce_get_chip_ability_s *roce_feature);
+int roce5_init_cfg_info(struct roce5_device *rdev);
+int roce5_del_func_res(struct roce5_device *rdev);
+
+#endif /* ROCE_CMD_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/db/roce_db.c b/drivers/infiniband/hw/hiroce5/kernel/dev/db/roce_db.c
new file mode 100644
index 000000000..11bd63d04
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/db/roce_db.c
@@ -0,0 +1,86 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/kernel.h>
+
+#include "roce.h"
+#include "roce_os_compat.h"
+
+int roce5_db_map_user(struct roce5_ucontext *context, unsigned long virt,
+ struct roce5_db *db, u8 shadow_db)
+{
+ int ret = 0;
+ struct roce5_db_page *db_page = NULL;
+
+ if ((context == NULL) || (db == NULL)) {
+ return -EINVAL;
+ }
+ if (shadow_db != 0) {
+ return ret;
+ }
+ mutex_lock(&context->db_page_mutex);
+
+ list_for_each_entry(db_page, &context->db_page_list, list) {
+ if (db_page->user_virt == (virt & PAGE_MASK)) {
+ goto found;
+ }
+ }
+
+ db_page = (struct roce5_db_page *)kmalloc(sizeof(*db_page), GFP_KERNEL);
+ if (db_page == NULL) {
+ ret = -ENOMEM;
+ ROCE_ERR("Failed to alloc DB page");
+ goto out;
+ }
+
+ db_page->user_virt = (virt & PAGE_MASK);
+ db_page->refcnt = 0;
+ db_page->umem = roce5_umem_get(context->ibucontext.device,
+ &context->ibucontext, virt & PAGE_MASK,
+ PAGE_SIZE, 0, 0);
+ if (IS_ERR(db_page->umem)) {
+ ret = (int)PTR_ERR(db_page->umem);
+ ROCE_ERR("Failed to get ib_umem ret:%d", ret);
+ kfree(db_page);
+ goto out;
+ }
+
+ list_add(&db_page->list, &context->db_page_list);
+
+found:
+#if defined(IB_UMEM_HAVE_SG_APPEND_TABLE)
+ db->dma = sg_dma_address(db_page->umem->sgt_append.sgt.sgl) +
+ (virt & ~PAGE_MASK);
+#else
+ db->dma = sg_dma_address(db_page->umem->sg_head.sgl) +
+ (virt & ~PAGE_MASK);
+#endif
+ db->user_page = db_page;
+ ++db_page->refcnt;
+
+out:
+ mutex_unlock(&context->db_page_mutex);
+
+ return ret;
+}
+
+void roce5_db_unmap_user(struct roce5_ucontext *context, struct roce5_db *db,
+ u8 shadow_db)
+{
+ if ((context == NULL) || (db == NULL)) {
+ return;
+ }
+ if (shadow_db != 0) {
+ return;
+ }
+ mutex_lock(&context->db_page_mutex);
+
+ if ((--db->user_page->refcnt) == 0) {
+ list_del(&db->user_page->list);
+ ib_umem_release(db->user_page->umem);
+ kfree(db->user_page);
+ }
+
+ mutex_unlock(&context->db_page_mutex);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/db/roce_db.h b/drivers/infiniband/hw/hiroce5/kernel/dev/db/roce_db.h
new file mode 100644
index 000000000..7232e9edc
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/db/roce_db.h
@@ -0,0 +1,30 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_DB_H
+#define ROCE_DB_H
+
+#include <rdma/ib_umem.h>
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct roce5_db_page {
+ struct list_head list;
+ struct ib_umem *umem;
+ unsigned long user_virt;
+ int refcnt;
+};
+
+struct roce5_db {
+ __be32 *db_record;
+ dma_addr_t dma;
+ struct roce5_db_page *user_page;
+};
+
+static inline void roce5_write64(u32 val[2], void __iomem *dest)
+{
+ __raw_writeq(*(u64 *)(void *)val, dest);
+}
+
+#endif //ROCE_DB_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/init/roce_main.c b/drivers/infiniband/hw/hiroce5/kernel/dev/init/roce_main.c
new file mode 100644
index 000000000..7d589afe1
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/init/roce_main.c
@@ -0,0 +1,1701 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <net/ipv6.h>
+#include <net/addrconf.h>
+#include <net/bonding.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib_user_verbs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/inetdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/security.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/sizes.h>
+
+#include "hinic5_crm.h"
+#include "hinic5_hw.h"
+#include "hinic5_mt.h"
+#include "hinic5_srv_nic.h"
+#include "hinic5_rdma.h"
+#include "hinic5_id_tbl.h"
+
+#include "roce_dfx.h"
+#include "roce_mr.h"
+#include "roce_main_extension.h"
+#include "roce_uld_inner.h"
+#include "roce_uld_kernel_api.h"
+#include "roce_netlink.h"
+#include "roce_cmd.h"
+#include "roce_qp.h"
+#include "roce_infra.h"
+#include "rdma_comp_mw_mr.h"
+#include "roce_xrc.h"
+#include "roce_com.h"
+#include "roce_kernel_compat_gen.h"
+#include "roce_netdev.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+#ifdef ENABLE_HYPER_ROCE
+#include "hyper_roce_tool.h"
+#endif
+
+#include "securec.h"
+
+MODULE_AUTHOR(HIROCE5_DRV_AUTHOR);
+MODULE_DESCRIPTION(HIROCE5_DRV_DESC);
+MODULE_VERSION(HIROCE5_DRV_VERSION);
+MODULE_LICENSE("GPL");
+
+static int g_loop_times = 50000;
+module_param(g_loop_times, int, S_IRUGO);
+MODULE_PARM_DESC(g_loop_times,
+ "default: 50000. The number must be greater than 0.");
+
+static u8 g_destory_flow_timeout = 10;
+module_param(g_destory_flow_timeout, byte, S_IRUGO);
+MODULE_PARM_DESC(g_destory_flow_timeout, "default: 10");
+
+static bool g_local_en = false; // IP mode because IP in this place need switch control whether advancein this place switch
+module_param(g_local_en, bool, S_IRUGO);
+MODULE_PARM_DESC(g_local_en, "default false");
+
+static bool g_full_qp_spec = true; // calculate standard card scenario, supports single cq create full specification qp
+module_param(g_full_qp_spec, bool, S_IRUGO);
+MODULE_PARM_DESC(
+ g_full_qp_spec,
+ "Supports creating a maximum number of QPs through a single CQ. default true.");
+
+static bool g_huge_page_en = 0;
+module_param(g_huge_page_en, bool, S_IRUGO);
+MODULE_PARM_DESC(
+ g_huge_page_en,
+ "default: 0. value: 0 or 1, set huge page en, and users need to reserve huge pages in advance.");
+
+#define ROCE_BOND_SLAVE_BIT_MASK 0xf
+
+/* ****************************************************************************
+ Prototype : get_cpu_endian
+ Description : Acquire CPU's enianness
+ Return Value : 0: little endian; 1: big endian
+
+ 1.Date : 2016/6/23
+ Modification : Created function
+
+**************************************************************************** */
+static int get_cpu_endian(void)
+{
+ int cpu_mode = 0;
+ union {
+ unsigned int i;
+ unsigned char s[4];
+ } c;
+ c.i = 0x12345678;
+
+ if (c.s[0] == 0x12) {
+ ROCE_INFO("CPU is be");
+ cpu_mode = 1;
+ } else {
+ ROCE_INFO("CPU is le");
+ cpu_mode = 0;
+ }
+
+ return cpu_mode;
+}
+
+static int roce5_alloc_hw_resource(struct roce5_device *rdev)
+{
+ int ret;
+
+ ret = roce5_rdma_init_rsvd_lkey(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to init rsvd lkey, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ /* Clear gid table before register for a new IB device */
+ ret = roce5_reset_gid_table(rdev, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to reset gid_table, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_gid_reset;
+ }
+
+ return 0;
+
+err_gid_reset:
+ roce5_rdma_free_rsvd_lkey(rdev);
+
+ return ret;
+}
+
+static void roce5_dealloc_hw_resource(struct roce5_device *rdev)
+{
+ roce5_rdma_free_rsvd_lkey(rdev);
+}
+
+/* 1825 v100 esl sub did */
+#define HI_1825_V100_SUB_DEV_ID_2X100 0x1825
+#define HI_1825_V100_SUB_DEV_ID_COMPUTE_2X200 0x40B1
+#define HI_1825_V100_SUB_DEV_ID_COMPUTE_DY_YH 0x30C4
+#define HI_1825_V100_SUB_DEV_ID_COMPUTE_UBX 0x30C8
+
+static int roce5_init_ver_attr_pci(struct hinic5_lld_dev *lld_dev,
+ struct roce5_device *rdev)
+{
+ struct pci_dev *pdev = container_of(lld_dev->dev, struct pci_dev, dev);
+
+ if ((pdev->device == HINIC5_DEV_ID_25V1_PF) ||
+ (pdev->device == HINIC5_DEV_ID_25V1_VF)) {
+ rdev->device_type = ROCE_DEV_TYPE_HI1825_V100;
+ return 0;
+ }
+
+ switch (pdev->subsystem_device) {
+ case HI_1825_V100_SUB_DEV_ID_2X100:
+ case HI_1825_V100_SUB_DEV_ID_COMPUTE_2X200:
+ case HI_1825_V100_SUB_DEV_ID_COMPUTE_DY_YH:
+ case HI_1825_V100_SUB_DEV_ID_COMPUTE_UBX:
+ rdev->device_type = ROCE_DEV_TYPE_HI1825_V100;
+ break;
+ default:
+ ROCE_DEV_ERR(rdev, "Unknown subsystem id(%u).",
+ pdev->subsystem_device);
+ rdev->device_type = ROCE_DEV_TYPE_UNKNOWN;
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int roce5_init_ver_attr(struct hinic5_lld_dev *lld_dev,
+ struct roce5_device *rdev)
+{
+ int ret;
+
+ switch (lld_dev->dev_type) {
+ case HINIC5_DEVICE_T_PCI:
+ ret = roce5_init_ver_attr_pci(lld_dev, rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to init PCI version attributes, ret(%d).",
+ ret);
+ return ret;
+ }
+ break;
+
+ case HINIC5_DEVICE_T_UB:
+ /*
+ * The 'struct ub_dev' contains a 'module' member that can be used to distinguish the version of the card
+ * under the UBC. However, this member is only available in the most recent version of 'struct ub_dev', and
+ * the current development environment does not include the updated structure definition, making it
+ * inaccessible at present. Here, the fixed version(Hi1825V100) is returned.
+ */
+ rdev->device_type = ROCE_DEV_TYPE_HI1825_V100;
+ break;
+
+ default:
+ ROCE_DEV_ERR(rdev, "Unknown low level device type(%u).",
+ lld_dev->dev_type);
+ rdev->device_type = ROCE_DEV_TYPE_UNKNOWN;
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int roce5_get_perf_cq_step(struct roce5_device *rdev)
+{
+ int perf_step = 0;
+
+ if (ROCE_IS_DEV_1825V100(rdev)) {
+ perf_step = ROCE_1825V100_STEP;
+ } else {
+ ROCE_DEV_INFO(
+ rdev,
+ "not support high performance cq, device type(%u), func_id(%u).",
+ rdev->device_type, rdev->glb_func_id);
+ }
+ return perf_step;
+}
+
+static int roce5_get_perf_cq_cnt(struct roce5_device *rdev)
+{
+ if (rdev->cqn_ctrl.rsvd_cq_step == 0) {
+ return 0;
+ }
+ /* When you insmod the driver, CQ0 is consumed by default. */
+ return (int)((rdev->rdma_cap.dev_rdma_cap.roce_own_cap.reserved_cqs -
+ 1) /
+ rdev->cqn_ctrl.rsvd_cq_step) +
+ 1;
+}
+
+void roce5_init_perf_cq_attr(struct roce5_device *rdev)
+{
+ /* Calculate the step size and number of high-performance CQs */
+ rdev->cqn_ctrl.rsvd_cq_step = roce5_get_perf_cq_step(rdev);
+ rdev->cqn_ctrl.high_perf_cq_cnt = roce5_get_perf_cq_cnt(rdev);
+#ifdef ROCE_VBS_EN
+ // VBS RoCE scenario disable high performance cq
+ rdev->cqn_ctrl.high_perf_cq_cnt = 0;
+#endif
+ rdev->cqn_ctrl.alloc_cq_cnt = 0;
+}
+
+static struct roce5_device *
+roce5_rdev_alloc(struct hinic5_lld_dev *lld_dev, void **uld_dev,
+ const struct rdma_service_cap *rdma_cap)
+{
+ struct roce5_device *rdev = NULL;
+ int ret;
+
+ rdev = (struct roce5_device *)roce5_rdev_alloc_ext();
+ if (rdev == NULL) {
+ ROCE_ERR("Failed to alloc rdev");
+ return NULL;
+ }
+
+ *uld_dev = (void *)rdev;
+ rdev->lld_dev = lld_dev;
+ rdev->hwdev = lld_dev->hwdev;
+ rdev->dev = lld_dev->dev;
+ dma_set_max_seg_size(rdev->dev, SZ_2G);
+ ret = roce5_init_ver_attr(lld_dev, rdev);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to init version attribute of the device, ret(%d)",
+ ret);
+ goto alloc_failed;
+ }
+
+ mutex_init(&rdev->qp_cnt.cur_qps_mutex);
+ mutex_init(&rdev->cqn_ctrl.cq_ctrl_mutex);
+
+ rdev->hwdev_hdl = ((struct hinic5_hwdev *)(rdev->hwdev))->dev_hdl;
+ if (memcpy_s((void *)&rdev->rdma_cap, sizeof(*rdma_cap),
+ (void *)rdma_cap, sizeof(*rdma_cap)) != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy rdma_cap.");
+ goto alloc_failed;
+ }
+
+ rdev->ndev = hinic5_get_netdev_by_lld(rdev->lld_dev);
+ if (rdev->ndev == NULL) {
+ ROCE_DEV_ERR(rdev, "roce add failed, netdev is null.");
+ goto alloc_failed;
+ }
+
+ roce5_init_perf_cq_attr(rdev);
+ rdev->rdev_magic = ROCE_DEVICE_MAGIC;
+ return rdev;
+
+alloc_failed:
+ ib_dealloc_device(&rdev->ib_dev);
+ return NULL;
+}
+
+static int roce5_board_info_get(struct roce5_device *rdev)
+{
+ int ret = 0;
+
+ ret = hinic5_get_board_info(rdev->hwdev, &rdev->board_info,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_ERR("Failed to get board info");
+ return ret;
+ }
+
+ ROCE_DEV_INFO(
+ rdev,
+ "Get board info success, board_type:0x%x, port_num:0x%x, pf_num:0x%x, vf_total_num:0x%x, "
+ "work_mode:0x%x, service_mode:0x%x, port_speed:0x%x.",
+ rdev->board_info.board_type, rdev->board_info.port_num,
+ rdev->board_info.pf_num, rdev->board_info.vf_total_num,
+ rdev->board_info.work_mode, rdev->board_info.service_mode,
+ rdev->board_info.port_speed);
+
+ ret = roce5_board_cfg_check(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to check board cfg info");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce5_fix_ibdev_name(struct roce5_device *rdev)
+{
+ int ret;
+
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ ret = strcpy_s(rdev->ib_dev.name, IB_DEVICE_NAME_MAX,
+ "hrn5_bond_%d");
+ if (ret != EOK) {
+ ROCE_DEV_ERR(rdev, "Strcpy_s error");
+ }
+ return;
+ }
+#endif
+ ret = strcpy_s(rdev->ib_dev.name, IB_DEVICE_NAME_MAX, "hrn5_%d");
+ if (ret != EOK) {
+ ROCE_DEV_ERR(rdev, "Strcpy_s error");
+ }
+}
+
+static int roce5_register_template(struct roce5_device *rdev)
+{
+ service_register_template_s svc_template;
+ int ret;
+
+ ret = memset_s(&svc_template, sizeof(svc_template), 0,
+ sizeof(svc_template));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memset svc_template.(ret:%d)",
+ ret);
+ return -ENOMEM;
+ }
+
+ svc_template.service_type = SERVICE_T_ROCE;
+ svc_template.scq_ctx_size = rdev->rdma_cap.cqc_entry_sz;
+ svc_template.srq_ctx_size =
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.srqc_entry_sz;
+ svc_template.service_handle = rdev;
+ svc_template.embedded_cq_ceq_callback = NULL;
+ svc_template.no_cq_ceq_callback = NULL;
+
+ svc_template.shared_cq_ceq_callback = roce5_cq_completion;
+ svc_template.aeq_level_callback = roce5_async_event_level;
+ svc_template.aeq_callback = roce5_async_event;
+
+ ret = cqm5_service_register(rdev->hwdev, &svc_template);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to register cqm_service, func(%d).",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Alloc CEQs and alloc CEQN */
+static int roce5_alloc_ceq(struct roce5_device *rdev)
+{
+ int ret;
+
+ ret = hinic5_alloc_ceqs(rdev->hwdev, SERVICE_T_ROCE,
+ rdev->ib_dev.num_comp_vectors, rdev->ceqn,
+ &rdev->ceq_num);
+ if (ret < 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqes, num_comp_vectors(%d), func_id(%d), ret(%d)",
+ rdev->ib_dev.num_comp_vectors, rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce5_free_ceq(struct roce5_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->ceq_num; ++i) {
+ hinic5_free_ceq(rdev->hwdev, SERVICE_T_ROCE, rdev->ceqn[i]);
+ }
+}
+
+static void roce5_init_hw_info(struct roce5_device *rdev)
+{
+ rdev->hw_info.config_num_ports = (int)rdev->rdma_cap.num_ports;
+ rdev->hw_info.ep_id = hinic5_ep_id(rdev->hwdev);
+ rdev->hw_info.phy_port = 1;
+ rdev->hw_info.is_vf = roce5_func_is_vf(rdev->hwdev);
+ rdev->hw_info.cpu_endian = (u8)get_cpu_endian();
+}
+
+static int roce5_init_dev_info(struct roce5_device *rdev)
+{
+ int ret;
+
+ ret = roce5_set_func_tbl_cpu_endian(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set func_tbl cpu_endian, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_init;
+ }
+
+ /* Set function table to ENABLE */
+ ret = roce5_set_func_tbl_func_state(rdev->hwdev, ROCE_FUNC_ENABLE,
+ rdev->glb_func_id);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to set func_tbl, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_init;
+ }
+
+ return 0;
+
+err_init:
+ return ret;
+}
+#ifdef __ROCE_DFX__
+static void device_list_lock_init(struct roce5_device_res *device_res)
+{
+ mutex_init(&device_res->mr_list.node_lock);
+ INIT_LIST_HEAD(&device_res->mr_list.node);
+}
+
+static void device_list_lock_deinit(struct roce5_device_res *device_res)
+{
+ struct roce5_mr *mr = NULL;
+ struct roce5_mr *tmp_mr = NULL;
+
+ mutex_lock(&device_res->mr_list.node_lock);
+ list_for_each_entry_safe(mr, tmp_mr, &device_res->mr_list.node, node) {
+ list_del(&(mr->node));
+ }
+ mutex_unlock(&device_res->mr_list.node_lock);
+
+ mutex_destroy(&(device_res->mr_list.node_lock));
+}
+
+static int roce5_dfx_device_init(struct roce5_device *rdev)
+{
+ rdev->device_res = kzalloc(sizeof(struct roce5_device_res), GFP_KERNEL);
+ if (rdev->device_res == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc device resource.");
+ return -ENOMEM;
+ }
+
+ device_list_lock_init(rdev->device_res);
+
+ return 0;
+}
+
+static void roce5_dfx_device_deinit(struct roce5_device *rdev)
+{
+ if (rdev->device_res != NULL) {
+ device_list_lock_deinit(rdev->device_res);
+ kfree(rdev->device_res);
+ rdev->device_res = NULL;
+ }
+}
+#endif // __ROCE_DFX__
+
+static void roce5_deinit_dev_info(struct roce5_device *rdev)
+{
+ (void)roce5_set_func_tbl_func_state(rdev->hwdev, ROCE_FUNC_DISABLE,
+ rdev->glb_func_id);
+}
+
+static int roce5_ib_register_device(struct roce5_device *rdev)
+{
+#if defined(IB_REG_DEV_HAVE_PORT_CALLBACK)
+ roce5_fix_ibdev_name(rdev);
+ return ib_register_device(&rdev->ib_dev, NULL);
+#elif defined(IB_REG_DEV_HAVE_NAME) && defined(IB_REG_DEV_HAVE_DEVICE)
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ return ib_register_device(&rdev->ib_dev, "hrn5_bond_%d",
+ rdev->dev);
+ }
+#endif
+
+ return ib_register_device(&rdev->ib_dev, "hrn5_%d", rdev->dev);
+#endif
+}
+
+static int roce5_dev_register(struct roce5_device *rdev, char *uld_dev_name)
+{
+ int ret;
+
+ ret = roce5_ib_register_device(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to reg ibdev, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_reg_dev;
+ }
+
+ ret = memcpy_s(uld_dev_name, ROCE_ULD_DEV_NAME_LEN, rdev->ib_dev.name,
+ ROCE_ULD_DEV_NAME_LEN);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy uld_dev_name.(ret:%d)",
+ ret);
+ goto err_memcpy_uld;
+ }
+
+ return 0;
+
+err_memcpy_uld:
+ ib_unregister_device(&rdev->ib_dev);
+err_reg_dev:
+ return ret;
+}
+
+static void roce5_dev_unregister(struct roce5_device *rdev)
+{
+ ib_unregister_device(&rdev->ib_dev);
+}
+
+static int roce5_handle_register_event(struct roce5_device *rdev)
+{
+ int ret;
+
+ ret = roce5_add_real_device_mac(rdev, rdev->ndev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to add real device mac, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ if (netif_running(rdev->ndev) &&
+ test_and_set_bit(ROCE5_PORT_EVENT, &rdev->status) == 0) {
+ roce5_ifconfig_up_down_event_report(rdev, IB_EVENT_PORT_ACTIVE);
+ }
+
+ return 0;
+}
+
+static int roce5_init_dev(struct roce5_device *rdev, char *uld_dev_name)
+{
+ int ret;
+
+ ret = roce5_init_dev_info(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init dev info, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_init_dev_info;
+ }
+
+ ret = roce5_alloc_hw_resource(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc hw res, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_alloc_hw_res;
+ }
+
+ ret = roce5_dev_register(rdev, uld_dev_name);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init register, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_init_register;
+ }
+
+ ret = roce5_g_rdev_add(rdev);
+ if (ret != 0) {
+ ROCE_ERR("Failed to add rdev to g_rdev");
+ goto err_add_rdev;
+ }
+
+ ret = roce5_get_feature(rdev, &rdev->cfg_info.feature_cap);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get feature, ret=%d", ret);
+ goto err_get_feature_or_init_sysfs;
+ }
+
+ ret = roce5_init_sysfs(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init sysfs, func_id(%d) ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_get_feature_or_init_sysfs;
+ }
+ rdev->ib_active = true;
+
+ ret = roce5_handle_register_event(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to handle register event, func_id(%d) ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_register_event;
+ }
+
+ ROCE_DEV_INFO(rdev, "Add init all ok, func_id(%d), dev_name(%s)",
+ rdev->glb_func_id, rdev->ib_dev.name);
+
+ return 0;
+
+err_register_event:
+ roce5_remove_sysfs(rdev);
+err_get_feature_or_init_sysfs:
+ roce5_g_rdev_remove(rdev);
+err_add_rdev:
+ roce5_dev_unregister(rdev);
+err_init_register:
+ roce5_dealloc_hw_resource(rdev);
+err_alloc_hw_res:
+ roce5_deinit_dev_info(rdev);
+err_init_dev_info:
+ return ret;
+}
+
+static void roce5_rdev_qp_lb_init(struct roce5_device *rdev)
+{
+ int i = 0;
+ mutex_init(&rdev->qp_lb_scqn_ctrl.qp_lb_scqn_ctrl_mutex);
+ for (; i < ROCE_LB_QPN_MAX; i++) {
+ rdev->qp_lb_scqn_ctrl.qp[i] = 0;
+ }
+}
+
+static int roce5_add_rdev_init(struct roce5_device *rdev)
+{
+ int ret = 0;
+
+ ret = roce5_board_info_get(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get board info");
+ return ret;
+ }
+
+#ifdef ROCE_BONDING_EN
+ ret = roce5_bond_attach(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to attach bond device.");
+ return ret;
+ }
+
+ atomic_set(&rdev->next_port, 0);
+#endif
+
+ rdev->gid_dev = (struct net_device **)kzalloc(
+ rdev->rdma_cap.max_gid_per_port * sizeof(struct net_device *),
+ GFP_KERNEL);
+ if (rdev->gid_dev == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc gid dev memory");
+ return -ENOMEM;
+ }
+
+ ret = roce5_rdma_init_resource(rdev->hwdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init rdma resources.");
+ goto err_init_resource;
+ }
+
+ rdev->glb_func_id = hinic5_global_func_id(rdev->hwdev);
+ roce5_rdev_qp_lb_init(rdev);
+
+ roce5_init_hw_info(rdev);
+
+ ret = roce5_init_cfg_info(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get roce cfg, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_init_cfg;
+ }
+
+ ROCE_DEV_INFO(rdev, "Initializing.");
+ return 0;
+
+err_init_cfg:
+ roce5_rdma_cleanup_resource(rdev->hwdev);
+
+err_init_resource:
+ if (rdev->gid_dev != NULL) {
+ kfree(rdev->gid_dev);
+ }
+ return ret;
+}
+
+static void roce5_add_rdev_unit(struct roce5_device *rdev)
+{
+ roce5_rdma_cleanup_resource(rdev->hwdev);
+ if (rdev->gid_dev != NULL) {
+ kfree(rdev->gid_dev);
+ }
+}
+
+static __be64 rdma_gen_node_guid(u8 *dev_mac)
+{
+ u8 guid[8];
+ u8 mac_addr[6];
+ __be64 node_guid = 0;
+ int ret;
+
+ if (dev_mac == NULL) {
+ ROCE_ERR("Dev_mac is null");
+ return RDMA_INVALID_GUID;
+ }
+
+ ret = memcpy_s((void *)&mac_addr[0], sizeof(mac_addr), (void *)dev_mac,
+ sizeof(mac_addr));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy mac_addr.(ret:%d)", ret);
+ return ENOMEM;
+ }
+
+ guid[0] = mac_addr[0] ^
+ DEV_ADDR_FIRST_BYTE_VAL_MASK; // 0 is mac & guid array idx
+ guid[1] = mac_addr[1]; // 1 is mac & guid array idx
+ guid[2] = mac_addr[2]; // 2 is mac & guid array idx
+ guid[3] = 0xff; // 3 is guid array idx
+ guid[4] = 0xfe; // 4 is guid array idx
+ guid[5] = mac_addr[3]; // 5 is guid array idx, 3 is mac array idx
+ guid[6] = mac_addr[4]; // 6 is guid array idx, 4 is mac array idx
+ guid[7] = mac_addr[5]; // 7 is guid array idx, 5 is mac array idx
+
+ /* node_guid is calculated by guid. */
+ node_guid =
+ ((u64)guid[0] << 56) | // 0 is guid array idx, 56 is guid offset
+ ((u64)guid[1] << 48) | // 1 is guid array idx, 48 is guid offset
+ ((u64)guid[2] << 40) | // 2 is guid array idx, 40 is guid offset
+ ((u64)guid[3] << 32) | // 3 is guid array idx, 32 is guid offset
+ ((u64)guid[4] << 24) | // 4 is guid array idx, 24 is guid offset
+ ((u64)guid[5] << 16) | // 5 is guid array idx, 16 is guid offset
+ ((u64)guid[6] << 8) | // 6 is guid array idx, 8 is guid offset
+ (u64)guid[7]; // 7 is guid array idx
+
+ return (__be64)cpu_to_be64(node_guid);
+}
+
+static __be64 roce5_rdma_init_guid(void *hwdev, struct net_device *netdev)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if ((hwdev == NULL) || (netdev == NULL)) {
+ ROCE_ERR("Hwdev or netdev is null");
+ return ~0ULL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return ~0ULL;
+ }
+
+ comp_priv->rdma_comp_res.node_guid =
+ rdma_gen_node_guid((u8 *)netdev->dev_addr);
+
+ return comp_priv->rdma_comp_res.node_guid;
+}
+
+#if defined(HAVE_IB_DEVICE_OPS)
+static const struct ib_device_ops dev_ops = {
+ .owner = THIS_MODULE,
+ .driver_id = RDMA_DRIVER_HRN,
+ .uverbs_abi_ver = ROCE_IB_UVERBS_ABI_VERSION,
+
+ .modify_qp = roce5_modify_qp,
+ .query_qp = roce5_query_qp,
+ .destroy_qp = roce5_destroy_qp,
+ .post_send = roce5_post_send,
+ .post_recv = roce5_post_recv,
+ .create_cq = roce5_create_cq,
+ .modify_cq = roce5_modify_cq,
+ .resize_cq = roce5_resize_cq,
+ .destroy_cq = roce5_destroy_cq,
+ .poll_cq = roce5_poll_cq,
+ .req_notify_cq = roce5_arm_cq,
+ .create_srq = roce5_create_srq,
+ .modify_srq = roce5_modify_srq,
+ .query_srq = roce5_query_srq,
+ .destroy_srq = roce5_destroy_srq,
+ .post_srq_recv = roce5_post_srq_recv,
+ .map_mr_sg = roce5_map_kernel_frmr_sg,
+ .get_dma_mr = roce5_get_dma_mr,
+ .reg_user_mr = roce5_reg_user_mr,
+ .dereg_mr = roce5_dereg_mr,
+ .alloc_mr = roce5_alloc_mr,
+ .alloc_mw = roce5_alloc_mw,
+ .dealloc_mw = roce5_dealloc_mw,
+ .query_device = roce5_query_device,
+ .add_gid = roce5_ib_add_gid,
+ .del_gid = roce5_ib_del_gid,
+ .modify_device = roce5_modify_device,
+ .alloc_ucontext = roce5_alloc_ucontext,
+ .dealloc_ucontext = roce5_dealloc_ucontext,
+ .mmap = roce5_mmap,
+ .alloc_pd = roce5_alloc_pd,
+ .dealloc_pd = roce5_dealloc_pd,
+ .create_ah = roce5_create_ah,
+ .query_ah = roce5_query_ah,
+ .destroy_ah = roce5_destroy_ah,
+ .alloc_xrcd = roce5_alloc_xrcd,
+ .dealloc_xrcd = roce5_dealloc_xrcd,
+
+#if defined(ROCE_CREATE_QP_INT)
+ .create_qp = roce5_create_qp,
+#elif defined(ROCE_CREATE_QP_IB_QP)
+ .create_qp = roce5_create_qp_compat,
+#endif
+
+#if defined(HAVE_ALL_ROCE_FUNCS_U32_PORT)
+ .query_port = roce5_query_port,
+#elif defined(HAVE_ALL_ROCE_FUNCS_U8_PORT)
+ .query_port = roce5_query_port_compat,
+#endif
+
+#if defined(GET_LINK_LAYER_HAVE_U32_PORT)
+ .get_link_layer = roce5_port_link_layer,
+#elif defined(GET_LINK_LAYER_HAVE_U8_PORT)
+ .get_link_layer = roce5_port_link_layer_compat,
+#endif
+
+#if defined(QUERY_GID_HAVE_U32_PORT)
+ .query_gid = roce5_query_gid,
+#elif defined(QUERY_GID_HAVE_U8_PORT)
+ .query_gid = roce5_query_gid_compat,
+#endif
+
+#if defined(QUERY_PKEY_HAVE_U32_PORT)
+ .query_pkey = roce5_query_pkey,
+#elif defined(QUERY_PKEY_HAVE_U8_PORT)
+ .query_pkey = roce5_query_pkey_compat,
+#endif
+
+#if defined(MODIFY_PORT_HAVE_U32_PORT)
+ .modify_port = roce5_modify_port,
+#elif defined(MODIFY_PORT_HAVE_U8_PORT)
+ .modify_port = roce5_modify_port_compat,
+#endif
+
+#if defined(GET_PORT_IMMUTABLE_HAVE_U32_PORT)
+ .get_port_immutable = roce5_port_immutable,
+#elif defined(GET_PORT_IMMUTABLE_HAVE_U8_PORT)
+ .get_port_immutable = roce5_port_immutable_compat,
+#endif
+
+#if defined(GET_NETDEV_HAVE_U32_PORT)
+ .get_netdev = roce5_ib_get_netdev,
+#elif defined(GET_NETDEV_HAVE_U8_PORT)
+ .get_netdev = roce5_ib_get_netdev_compat,
+#endif
+
+#if defined(IB_DEVICE_OPS_HAVE_CREATE_USER_AH)
+ .create_user_ah = roce5_create_ah,
+#endif
+
+ INIT_RDMA_OBJ_SIZE(ib_ah, roce5_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, roce5_cq, ibcq),
+ INIT_RDMA_OBJ_SIZE(ib_pd, roce5_pd, ibpd),
+ INIT_RDMA_OBJ_SIZE(ib_srq, roce5_srq, ibsrq),
+ INIT_RDMA_OBJ_SIZE(ib_ucontext, roce5_ucontext, ibucontext),
+ INIT_RDMA_OBJ_SIZE(ib_xrcd, roce5_xrcd, ibxrcd),
+ INIT_RDMA_OBJ_SIZE(ib_mw, roce5_mw, ibmw),
+#if defined(IB_DEVICE_OPS_HAVE_IB_QP_OBJ)
+ INIT_RDMA_OBJ_SIZE(ib_qp, roce5_qp, ibqp),
+#endif
+};
+
+static void roce5_add_init(struct roce5_device *rdev)
+{
+ struct ib_device *ib_dev = &rdev->ib_dev;
+
+ ib_dev->local_dma_lkey = rdev->rdma_cap.reserved_lkey;
+ ib_dev->phys_port_cnt = (u8)rdev->rdma_cap.num_ports;
+ ib_dev->num_comp_vectors =
+ (rdev->rdma_cap.num_comp_vectors <= MAX_CEQ_NEED) ?
+ (int)rdev->rdma_cap.num_comp_vectors :
+ MAX_CEQ_NEED;
+ ib_dev->node_type = RDMA_NODE_IB_CA;
+ ib_dev->node_guid = roce5_rdma_init_guid(rdev->hwdev, rdev->ndev);
+ ib_dev->dma_device = rdev->dev;
+ ib_dev->dev.parent = ib_dev->dma_device;
+ (void)strcpy_s(ib_dev->node_desc, IB_DEVICE_NODE_DESC_MAX, "hrn5");
+
+ rdev->ib_dev.uverbs_cmd_mask = ROCE_UVERBS_CMD_BASE_MASK;
+#if defined(IB_DEV_HAVE_UVERBS_EX_CMD_MASK)
+ rdev->ib_dev.uverbs_ex_cmd_mask = ROCE_UVERBS_EXT_CMD_MASK;
+#endif
+
+ ib_set_device_ops(ib_dev, &dev_ops);
+ roce5_init_dev_ext_handlers(rdev);
+}
+
+#else
+static void roce5_init_dev_qp_handlers(struct roce5_device *rdev)
+{
+ rdev->ib_dev.create_qp = roce5_create_qp_compat;
+ rdev->ib_dev.modify_qp = roce5_modify_qp;
+ rdev->ib_dev.query_qp = roce5_query_qp;
+ rdev->ib_dev.destroy_qp = roce5_destroy_qp_ofa;
+ rdev->ib_dev.post_send = roce5_post_send;
+ rdev->ib_dev.post_recv = roce5_post_recv;
+}
+
+static void roce5_init_dev_cq_handlers(struct roce5_device *rdev)
+{
+ rdev->ib_dev.create_cq = roce5_create_cq_ofa;
+ rdev->ib_dev.modify_cq = roce5_modify_cq;
+ rdev->ib_dev.resize_cq = roce5_resize_cq;
+ rdev->ib_dev.destroy_cq = roce5_destroy_cq_ofa;
+ rdev->ib_dev.poll_cq = roce5_poll_cq;
+ rdev->ib_dev.req_notify_cq = roce5_arm_cq;
+}
+
+static void roce5_init_dev_srq_handlers(struct roce5_device *rdev)
+{
+ rdev->ib_dev.create_srq = roce5_create_srq_ofa;
+ rdev->ib_dev.modify_srq = roce5_modify_srq;
+ rdev->ib_dev.query_srq = roce5_query_srq;
+ rdev->ib_dev.destroy_srq = roce5_destroy_srq_ofa;
+ rdev->ib_dev.post_srq_recv = roce5_post_srq_recv;
+}
+
+static void roce5_init_dev_mr_handlers(struct roce5_device *rdev)
+{
+ rdev->ib_dev.map_mr_sg = roce5_map_kernel_frmr_sg;
+
+ rdev->ib_dev.get_dma_mr = roce5_get_dma_mr;
+ rdev->ib_dev.reg_user_mr = roce5_reg_user_mr;
+ rdev->ib_dev.dereg_mr = roce5_dereg_mr_ofa;
+ rdev->ib_dev.alloc_mr = roce5_alloc_mr;
+
+ rdev->ib_dev.alloc_mw = roce5_alloc_mw_ofa;
+ rdev->ib_dev.dealloc_mw = roce5_dealloc_mw_ofa;
+}
+
+static void roce5_init_dev_handlers(struct roce5_device *rdev)
+{
+ rdev->ib_dev.query_device = roce5_query_device;
+ rdev->ib_dev.query_port = roce5_query_port_compat;
+ rdev->ib_dev.get_link_layer = roce5_port_link_layer_compat;
+ rdev->ib_dev.query_gid = roce5_query_gid_compat;
+ rdev->ib_dev.add_gid = roce5_ib_add_gid;
+ rdev->ib_dev.del_gid = roce5_ib_del_gid;
+ rdev->ib_dev.query_pkey = roce5_query_pkey_compat;
+ rdev->ib_dev.modify_device = roce5_modify_device;
+ rdev->ib_dev.modify_port = roce5_modify_port_compat;
+
+ rdev->ib_dev.alloc_ucontext = roce5_alloc_ucontext_ofa;
+ rdev->ib_dev.dealloc_ucontext = roce5_dealloc_ucontext_ofa;
+ rdev->ib_dev.mmap = roce5_mmap;
+
+ rdev->ib_dev.alloc_pd = roce5_alloc_pd_ofa;
+ rdev->ib_dev.dealloc_pd = roce5_dealloc_pd_ofa;
+
+ rdev->ib_dev.create_ah = roce5_create_ah_ofa;
+ rdev->ib_dev.query_ah = roce5_query_ah;
+ rdev->ib_dev.destroy_ah = roce5_destroy_ah_ofa;
+
+ roce5_init_dev_qp_handlers(rdev);
+ roce5_init_dev_cq_handlers(rdev);
+ roce5_init_dev_srq_handlers(rdev);
+ roce5_init_dev_mr_handlers(rdev);
+
+ rdev->ib_dev.alloc_xrcd = roce5_alloc_xrcd_ofa;
+ rdev->ib_dev.dealloc_xrcd = roce5_dealloc_xrcd_ofa;
+
+ rdev->ib_dev.get_port_immutable = roce5_port_immutable_compat;
+ rdev->ib_dev.get_netdev = roce5_ib_get_netdev_compat;
+}
+
+static void roce5_add_init(struct roce5_device *rdev)
+{
+ int ret;
+
+ rdev->ib_dev.owner = THIS_MODULE;
+ rdev->ib_dev.node_type = RDMA_NODE_IB_CA;
+ rdev->ib_dev.local_dma_lkey = rdev->rdma_cap.reserved_lkey;
+ rdev->ib_dev.phys_port_cnt = (u8)rdev->rdma_cap.num_ports;
+ rdev->ib_dev.num_comp_vectors =
+ (rdev->rdma_cap.num_comp_vectors <= MAX_CEQ_NEED) ?
+ (int)rdev->rdma_cap.num_comp_vectors :
+ MAX_CEQ_NEED;
+ rdev->ib_dev.dma_device = rdev->dev;
+ rdev->ib_dev.dev.parent = rdev->ib_dev.dma_device;
+ rdev->ib_dev.uverbs_abi_ver = ROCE_IB_UVERBS_ABI_VERSION;
+ rdev->ib_dev.node_guid = roce5_rdma_init_guid(rdev->hwdev, rdev->ndev);
+ ret = memcpy_s((void *)rdev->ib_dev.node_desc, ROCE_NODE_DESC_LEN,
+ "hrn5", ROCE_NODE_DESC_LEN);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy node_desc.(ret:%d)", ret);
+ return;
+ }
+
+ rdev->ib_dev.uverbs_cmd_mask = roce5_get_uverbs_cmd_mask();
+ rdev->ib_dev.uverbs_ex_cmd_mask = ROCE_UVERBS_EXT_CMD_MASK;
+
+ roce5_init_dev_handlers(rdev);
+ roce5_init_dev_ext_handlers(rdev);
+ return;
+}
+#endif
+
+static void roce5_mod_param_parse(struct roce5_device *rdev)
+{
+ if (g_loop_times <= 0) {
+ ROCE_DEV_WARN(
+ rdev,
+ "g_loop_times has been amended to 1, because original value(%d) is smaller than "
+ "or equal to 0.",
+ g_loop_times);
+ g_loop_times = 1;
+ }
+ rdev->try_times = g_loop_times;
+ rdev->destory_flow_timeout = g_destory_flow_timeout;
+ rdev->local_en = g_local_en;
+ rdev->full_qp_spec = g_full_qp_spec;
+ rdev->huge_page_en = g_huge_page_en;
+}
+
+static void roce5_init_mac_vlan(struct roce5_device *rdev)
+{
+ INIT_LIST_HEAD(&rdev->mac_vlan_list_head);
+ mutex_init(&rdev->mac_vlan_mutex);
+}
+
+static int roce5_rdev_init(struct roce5_device *rdev)
+{
+ int ret;
+
+ ret = hinic5_stateful_init(rdev->hwdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init stateful resource");
+ return ret;
+ }
+
+ roce5_init_mac_vlan(rdev);
+
+ ret = roce5_add_rdev_init(rdev);
+ if (ret != 0) {
+ goto err;
+ }
+
+ spin_lock_init(&rdev->node_desc_lock);
+ rwlock_init(&rdev->rwlock_func_tbl_bond);
+ mutex_init(&rdev->cap_mask_mutex);
+ spin_lock_init(&rdev->reset_flow_resource_lock);
+ INIT_LIST_HEAD(&rdev->qp_list);
+ roce5_mod_param_parse(rdev);
+
+ roce5_fix_ibdev_name(rdev);
+
+ return 0;
+err:
+ roce5_clean_vlan_device_mac(rdev);
+ hinic5_stateful_deinit(rdev->hwdev);
+ return ret;
+}
+
+static void roce5_rdev_unit(struct roce5_device *rdev)
+{
+ /* FLR by MPU when hotplug, don't need deinit anymore */
+ hinic5_stateful_deinit(rdev->hwdev);
+
+ roce5_add_rdev_unit(rdev);
+
+ mutex_destroy(&rdev->qp_lb_scqn_ctrl.qp_lb_scqn_ctrl_mutex);
+}
+
+static int roce5_add_do_init(struct roce5_device *rdev, char *uld_dev_name)
+{
+ int ret;
+
+ ret = roce5_rdev_init(rdev);
+ if (ret != 0) {
+ goto err_init_rdev;
+ }
+
+ ret = roce5_register_template(rdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to register cqm_service, func_id(%d) ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_cqm_register;
+ }
+
+ ret = hinic5_alloc_db_addr(rdev->hwdev, &rdev->kernel_db_map, NULL);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc db or dwqe, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_alloc_db;
+ }
+#ifdef __ROCE_DFX__
+ ret = roce5_dfx_device_init(rdev);
+ if (ret != 0) {
+ ROCE_ERR("Failed to init dfx device");
+ goto err_init_dfx;
+ }
+#endif
+ roce5_add_init(rdev);
+
+ ret = roce5_alloc_ceq(rdev);
+ if (ret < 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc ceqs, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ goto err_alloc_ceq;
+ }
+
+ ret = roce5_init_dev(rdev, uld_dev_name);
+ if (ret != 0) {
+ goto err_init_dev;
+ }
+
+ return 0;
+
+err_init_dev:
+ roce5_free_ceq(rdev);
+
+err_alloc_ceq:
+#ifdef __ROCE_DFX__
+ roce5_dfx_device_deinit(rdev);
+
+err_init_dfx:
+#endif
+ hinic5_free_db_addr(rdev->hwdev, rdev->kernel_db_map, NULL);
+
+err_alloc_db:
+ cqm5_service_unregister(rdev->hwdev, SERVICE_T_ROCE);
+
+err_cqm_register:
+ roce5_rdev_unit(rdev);
+
+err_init_rdev:
+ return ret;
+}
+
+static int roce5_add_check(const struct hinic5_lld_dev *lld_dev)
+{
+ int ret = 0;
+
+ if (lld_dev == NULL || lld_dev->hwdev == NULL) {
+ ROCE_ERR("Lld_dev is null");
+ return (-EINVAL);
+ }
+
+ ret = roce5_add_check_ext(lld_dev);
+ return ret;
+}
+
+static int roce5_stateful_init(struct hinic5_lld_dev *lld_dev)
+{
+ int ret = 0;
+ struct hinic5_lld_dev *ppf_lld_dev = NULL;
+
+ if (hinic5_func_type(lld_dev->hwdev) == TYPE_VF) {
+ return 0;
+ }
+
+ ppf_lld_dev = hinic5_get_ppf_lld_dev(lld_dev);
+ if (ppf_lld_dev == NULL) {
+ ROCE_ERR("Failed to get ppf lld dev, func id(%u).",
+ hinic5_global_func_id(lld_dev->hwdev));
+ return -EINVAL;
+ }
+
+ ret = hinic5_stateful_init(ppf_lld_dev->hwdev);
+ hinic5_lld_dev_put(ppf_lld_dev);
+
+ return ret;
+}
+
+static void roce5_stateful_deinit(struct hinic5_lld_dev *lld_dev)
+{
+ struct hinic5_lld_dev *ppf_lld_dev = NULL;
+
+ if (hinic5_func_type(lld_dev->hwdev) == TYPE_VF) {
+ return;
+ }
+
+ ppf_lld_dev = hinic5_get_ppf_lld_dev(lld_dev);
+ if (ppf_lld_dev == NULL) {
+ ROCE_ERR("Failed to get ppf lld dev, func id(%u).",
+ hinic5_global_func_id(lld_dev->hwdev));
+ return;
+ }
+
+ hinic5_stateful_deinit(ppf_lld_dev->hwdev);
+
+ hinic5_lld_dev_put(ppf_lld_dev);
+}
+
+static void roce5_do_remove(struct roce5_device *rdev, u16 glb_func_id,
+ const char *dev_name)
+{
+#ifdef __ROCE_DFX__
+ roce5_dfx_device_deinit(rdev);
+#endif
+
+ roce5_g_rdev_remove(rdev);
+
+ roce5_remove_sysfs(rdev);
+
+ ib_unregister_device(&rdev->ib_dev);
+
+ roce5_dealloc_hw_resource(rdev);
+
+ roce5_deinit_dev_info(rdev);
+
+#ifdef ROCE_BONDING_EN
+ roce5_set_bond_ipsurx_en(true);
+#endif
+
+ roce5_clean_vlan_device_mac(rdev);
+ roce5_clean_real_device_mac(rdev);
+
+ roce5_free_ceq(rdev);
+
+ hinic5_free_db_addr(rdev->hwdev, rdev->kernel_db_map, NULL);
+
+ cqm5_service_unregister(rdev->hwdev, SERVICE_T_ROCE);
+
+ roce5_del_func_res(rdev);
+ ROCE_INFO("Function level resource clear ok, func_id(%d), name(%s)",
+ glb_func_id, dev_name);
+
+ roce5_rdev_unit(rdev);
+}
+
+static void roce5_remove(struct hinic5_lld_dev *lld_dev, void *uld_dev)
+{
+ struct roce5_device *rdev = NULL;
+ char *device_name = NULL;
+ u16 glb_func_id;
+ roce_user_handle_t hdl = { 0 };
+
+ if ((uld_dev == NULL) || (lld_dev == NULL)) {
+ ROCE_ERR("input param is null");
+ return;
+ }
+
+ if (hinic5_support_roce(lld_dev->hwdev, NULL) == false) {
+ ROCE_WARN("Not support RoCE.");
+ return;
+ }
+
+ rdev = (struct roce5_device *)uld_dev;
+ rdev->ib_active = false;
+ device_name = rdev->ib_dev.name;
+ glb_func_id = rdev->glb_func_id;
+
+ ROCE_DEV_INFO(rdev, "Remove start, func_id(%d), name(%s)",
+ rdev->glb_func_id, device_name);
+
+ hdl.magic = ROCE_ULD_HANDLE_MAGIC_NUM;
+ hdl.rdev = rdev;
+ roce5_uld_rdev_remove((roce_uld_handle)&hdl);
+
+ roce5_do_remove(rdev, glb_func_id, device_name);
+
+#ifdef ROCE_BONDING_EN
+ roce5_bond_detach(rdev);
+#endif
+
+ ib_dealloc_device(&rdev->ib_dev);
+
+ roce5_stateful_deinit(lld_dev);
+
+ ROCE_INFO("Remove end, func_id(%d), name(%s)", glb_func_id,
+ device_name);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_add
+ Description : roce5_add
+ Input : struct hinic_lld_dev *lld_dev
+ void **uld_dev
+ char *uld_dev_name
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static int roce5_add(struct hinic5_lld_dev *lld_dev, void **uld_dev,
+ char *uld_dev_name)
+{
+ struct roce5_device *rdev = NULL;
+ struct rdma_service_cap rdma_cap;
+ int ret = 0;
+ roce_user_handle_t hdl = { 0 };
+
+ ret = roce5_add_check(lld_dev);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* return 0(false) if the hwdev don't support ROCE, make sure it probe success */
+ if (hinic5_support_roce(lld_dev->hwdev, &rdma_cap) == false) {
+ ROCE_WARN("Not support RoCE, func: %d",
+ hinic5_global_func_id(lld_dev->hwdev));
+ // this pf no has enable RoCE, but is not affect RoCE driver load, no need return exception value
+ ret = 0;
+ goto err_check;
+ }
+
+ ret = roce5_stateful_init(lld_dev);
+ if (ret != 0) {
+ ROCE_ERR("Failed to add ref to ppf.");
+ goto err_check;
+ }
+
+ rdev = roce5_rdev_alloc(lld_dev, uld_dev, &rdma_cap);
+ if (rdev == NULL) {
+ ROCE_ERR("Failed to alloc rdev, func: %d",
+ hinic5_global_func_id(lld_dev->hwdev));
+ ret = -EINVAL;
+ goto err_alloc;
+ }
+
+ ret = roce5_add_do_init(rdev, uld_dev_name);
+ if (ret != 0) {
+ ROCE_ERR("Failed to init rdev.");
+ goto err_do_init;
+ }
+
+ hdl.magic = ROCE_ULD_HANDLE_MAGIC_NUM;
+ hdl.rdev = rdev;
+ ROCE_CONSTUCT_ULD_HDL_SHADOW(&hdl, &rdev->shadow, &rdev->shadow_vfid,
+ &rdev->shadow_vf_num);
+ ret = roce5_uld_rdev_add((roce_uld_handle)&hdl);
+ if (ret != 0) {
+ ROCE_ERR("Failed to add uld rdev.");
+ roce5_do_remove(rdev, rdev->glb_func_id, uld_dev_name);
+ goto err_do_init;
+ }
+
+ ROCE_DEV_INFO(rdev, "Device(0x%p) init success.", rdev);
+ return 0;
+
+err_do_init:
+ ib_dealloc_device(&rdev->ib_dev);
+err_alloc:
+ roce5_stateful_deinit(lld_dev);
+err_check:
+ *uld_dev = NULL;
+ return ret;
+}
+
+static int roce5_set_nic_event(struct roce5_device *rdev,
+ const struct hinic5_event_info *event)
+{
+ switch (event->type) {
+ case EVENT_NIC_LINK_UP:
+ if (test_and_set_bit(ROCE5_PORT_EVENT, &rdev->status) != 0) {
+ return -1;
+ }
+ ROCE_DEV_INFO(rdev, "Report NIC LINK_UP, func_id(%d)",
+ rdev->glb_func_id);
+ return IB_EVENT_PORT_ACTIVE;
+
+ case EVENT_NIC_LINK_DOWN:
+ if (test_and_clear_bit(ROCE5_PORT_EVENT, &rdev->status) == 0) {
+ return -1;
+ }
+ ROCE_DEV_INFO(rdev, "RoCE report NIC LINK_DOWN, func_id(%d)",
+ rdev->glb_func_id);
+ return IB_EVENT_PORT_ERR;
+
+ case EVENT_NIC_DCB_STATE_CHANGE:
+ ROCE_DEV_INFO(
+ rdev,
+ "DCB state change no longer requires RoCE involvement, func_id(%d)",
+ rdev->glb_func_id);
+ return -1;
+
+ default:
+ ROCE_DEV_ERR(rdev,
+ "Nic event unsupported, func_id(%d), event(%d)",
+ rdev->glb_func_id, event->type);
+ return -1;
+ }
+}
+
+static int roce5_set_ib_event(struct roce5_device *rdev,
+ const struct hinic5_event_info *event)
+{
+ switch (event->service) {
+ case EVENT_SRV_NIC:
+ return roce5_set_nic_event(rdev, event);
+
+ case EVENT_SRV_COMM:
+ return roce5_set_comm_event(rdev, event);
+
+ default:
+ ROCE_DEV_ERR(
+ rdev,
+ "func_id(%d) event from svc(%d) is not supported, event(%d)",
+ rdev->glb_func_id, event->service, event->type);
+ return -1;
+ }
+}
+
+void roce5_event(struct hinic5_lld_dev *lld_dev, void *uld_dev,
+ struct hinic5_event_info *event)
+{
+ struct ib_event ibevent;
+ struct roce5_device *rdev = NULL;
+ int type, ret = 0;
+
+ if ((lld_dev == NULL) || (uld_dev == NULL)) {
+ ROCE_ERR("Input params is null");
+ goto out;
+ }
+ roce5_lock_rdev();
+
+ ret = roce5_get_rdev_by_uld(lld_dev, uld_dev, &rdev, event);
+ if ((ret != 0) || (rdev == NULL)) {
+ ROCE_ERR("find rdev failed");
+ goto err_unlock;
+ }
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ roce5_handle_bonded_port_state_event(rdev);
+ goto err_unlock;
+ }
+#endif
+ type = roce5_set_ib_event(rdev, event);
+ if (type == -1) {
+ goto err_unlock;
+ }
+
+ ibevent.event = (enum ib_event_type)type;
+ ibevent.device = &rdev->ib_dev;
+ ibevent.element.port_num = ROCE_DEFAULT_PORT_NUM;
+
+ if (rdev->ib_active) {
+ ROCE_DEV_INFO(rdev, "report event: %d.", type);
+ ib_dispatch_event(&ibevent);
+ }
+
+err_unlock:
+ roce5_unlock_rdev();
+
+out:
+ return;
+}
+
+int roce5_adm_dfx_get_dev_type(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ const struct roce5_dfx_common_inbuf *inbuf =
+ (struct roce5_dfx_common_inbuf *)buf_in;
+ union roce5_dfx_common_outbuf *outbuf =
+ (union roce5_dfx_common_outbuf *)buf_out;
+
+ struct roce5_device *find_rdev =
+ roce5_get_rdev_by_name(inbuf->dev_name);
+
+ if (in_size < sizeof(struct roce5_dfx_common_inbuf)) {
+ ROCE_ERR(
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size,
+ (int)sizeof(struct roce5_dfx_common_inbuf));
+ return -ENOMEM;
+ }
+ if (find_rdev == NULL) {
+ ROCE_ERR("Failed to find rdev by device name(%s).",
+ inbuf->dev_name);
+ return -EINVAL;
+ }
+
+ outbuf->dev_type = find_rdev->device_type;
+ *out_size = (u32)sizeof(union roce5_dfx_common_outbuf);
+ return 0;
+}
+
+static roce5_adm_cmd_proc_t g_roce5_adm_cmd_proc[] = {
+#ifdef __ROCE_DFX__
+ { ROCE_CMD_GET_QPC_FROM_CACHE, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_QPC_FROM_HOST, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_CQC_FROM_CACHE, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_CQC_FROM_HOST, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_SRQC_FROM_CACHE, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_SRQC_FROM_HOST, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_MPT_FROM_CACHE, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_MPT_FROM_HOST, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_GID_FROM_CACHE, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_QPC_CQC_PI_CI, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_QP_COUNT, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_DEV_ALGO, roce5_adm_dfx_query },
+ { ROCE_CMD_GET_DEV_TYPE, roce5_adm_dfx_get_dev_type },
+#ifdef ENABLE_DEBUG
+ { ROCE_CMD_DFX_ATTACK, roce5_dfx_attack_func },
+#endif
+#ifdef ROCE_CHIP_TEST
+ { ROCE_CMD_SET_VNIC_WATERLINE, roce5_adm_dfx_vnic_wl_ctrl },
+ { ROCE_CMD_GET_VNIC_WATERLINE, roce5_adm_dfx_vnic_wl_ctrl },
+#endif /* ROCE_CHIP_TEST */
+ { ROCE_CMD_ROCE_SET, roce5_adm_dfx_roce_set },
+ { ROCE_CMD_ROCE_SET_DEBUG, roce5_adm_dfx_roce_set_debug },
+#endif /* __ROCE_DFX__ */
+ { ROCE_CMD_ENABLE_BW_CTRL, roce5_adm_dfx_bw_ctrl },
+ { ROCE_CMD_DISABLE_BW_CTRL, roce5_adm_dfx_bw_ctrl },
+ { ROCE_CMD_CHANGE_BW_CTRL_PARAM, roce5_adm_dfx_bw_ctrl },
+ { ROCE_CMD_QUERY_BW_CTRL_PARAM, roce5_adm_dfx_bw_ctrl },
+ { ROCE_CMD_SET_LDCP_PARAM, roce5_adm_dfx_set_ldcp_param },
+ { ROCE_CMD_PORT_TRAFFIC, roce5_adm_dfx_port_traffic },
+ { ROCE_CMD_ULD_IOCTL_EXTEND,
+ (roce5_adm_func_t)roce5_adm_dfx_uld_extend },
+#ifdef ENABLE_HYPER_ROCE
+ { ROCE_CMD_HYPER, roce5_hyper_tool_dispatch },
+#endif
+};
+
+static int roce5_ioctl(void *uld_dev, u32 cmd, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size)
+{
+ struct roce5_device *rdev = (struct roce5_device *)uld_dev;
+ const roce5_adm_generic_cmd_proc_t *generic_array =
+ (const roce5_adm_generic_cmd_proc_t *)g_roce5_adm_cmd_proc;
+ int elem_count =
+ sizeof(g_roce5_adm_cmd_proc) / sizeof(g_roce5_adm_cmd_proc[0]);
+ roce5_adm_func_t roce5_adm_func = NULL;
+
+ /* check whether is root user */
+ if (!capable(CAP_SYS_ADMIN)) {
+ ROCE_ERR("Invalid permission");
+ return -EPERM; /* if not is root, return error */
+ }
+
+ if (cmd == GET_DRV_VERSION) {
+ return roce5_get_drv_version(buf_out, out_size);
+ }
+
+ if (uld_dev == NULL || buf_in == NULL || buf_out == NULL ||
+ out_size == NULL) {
+ ROCE_ERR("Input params is null");
+ return -EINVAL;
+ }
+
+ if (hinic5_support_roce(rdev->hwdev, NULL) == false) {
+ ROCE_ERR("Not support RoCE.");
+ return -EINVAL;
+ }
+
+ if (cmd == GET_DRV_VERSION) {
+ return roce5_get_drv_version(buf_out, out_size);
+ }
+
+ roce5_adm_func = (roce5_adm_func_t)roce5_adm_generic_find_cmd_func(
+ generic_array, elem_count, cmd);
+ if (roce5_adm_func == NULL) {
+ ROCE_DEV_ERR(rdev, "Not support this type(%d)", cmd);
+ return -EINVAL;
+ }
+ if (cmd == ROCE_CMD_ULD_IOCTL_EXTEND) {
+ roce_user_handle_t hdl = { 0 };
+ hdl.magic = ROCE_ULD_HANDLE_MAGIC_NUM;
+ hdl.rdev = rdev;
+ return roce5_adm_dfx_uld_extend(&hdl, buf_in, in_size, buf_out,
+ out_size);
+ } else {
+ return roce5_adm_func(rdev, buf_in, in_size, buf_out, out_size);
+ }
+}
+
+struct hinic5_uld_info roce5_info = {
+ .probe = roce5_add,
+ .remove = roce5_remove,
+ .suspend = NULL,
+ .resume = NULL,
+ .event = roce5_event,
+ .ioctl = roce5_ioctl,
+};
+
+struct hinic5_uld_info *roce5_info_get(void)
+{
+ return &roce5_info;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_service_init
+ Description :
+ Input : void
+ Output : None
+ Return Value :
+ Calls :
+ Called By :
+
+ History :
+ 1.Date : 2015/5/27
+ Author :
+ Modification : Created function
+
+**************************************************************************** */
+static int __init roce5_service_init(void)
+{
+ int ret;
+
+ roce5_service_init_pre();
+
+ ret = hinic5_register_uld(SERVICE_T_ROCE, roce5_info_get());
+ if (ret != 0) {
+ ROCE_ERR("Failed to register uld. ret(%d)", ret);
+ return ret;
+ }
+
+ ret = roce5_netlink_init();
+ if (ret != 0) {
+ ROCE_ERR("Failed to init netlink, ret(%d)", ret);
+ hinic5_unregister_uld(SERVICE_T_ROCE);
+ return ret;
+ }
+
+#ifdef ROCE_BONDING_EN
+ ret = roce5_bond_init();
+ if (ret != 0) {
+ ROCE_ERR("Failed to init RoCE Bond. ret(%d).", ret);
+ return ret;
+ }
+#endif
+
+ roce5_uld_service_init();
+
+ ret = roce5_register_netdev_notifier();
+ if (ret != 0) {
+ ROCE_ERR("Failed to register netdev notifier. ret(%d)", ret);
+ return ret;
+ }
+
+ ROCE_INFO("Register roce service successful");
+ return 0;
+}
+
+/* ****************************************************************************
+ Prototype : roce5_service_exit
+ Description : roce service disable
+ Input : void
+ Output : None
+ Return Value :
+ Calls :
+ Called By :
+
+ History :
+ 1.Date : 2015/5/27
+ Author :
+ Modification : Created function
+
+**************************************************************************** */
+static void __exit roce5_service_exit(void)
+{
+ roce5_unregister_netdev_notifier();
+
+ roce5_uld_service_exit();
+
+#ifdef ROCE_BONDING_EN
+ roce5_bond_exit();
+#endif
+
+ roce5_netlink_deinit();
+
+ hinic5_unregister_uld(SERVICE_T_ROCE);
+
+ ROCE_INFO("Unregister roce service successful");
+}
+
+module_init(roce5_service_init);
+module_exit(roce5_service_exit);
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/netdev/roce_netdev.c b/drivers/infiniband/hw/hiroce5/kernel/dev/netdev/roce_netdev.c
new file mode 100644
index 000000000..99d3b3afa
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/netdev/roce_netdev.c
@@ -0,0 +1,1082 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include "roce_netdev.h"
+#include "roce_main_extension.h"
+#include "roce_ctx_format.h"
+#include "roce_gid.h"
+#include "roce_cmd.h"
+#include "roce_mpu_cmd.h"
+#include "roce_restore.h"
+#include "rdma_comp.h"
+#include "roce_os_compat.h"
+#include "roce5_gid_type.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+#include "hinic5_srv_nic.h"
+
+static struct notifier_block g_roce5_netdev_notifier;
+
+/* ****************************************************************************
+ Prototype : roce5_fill_gid_type
+ Description : fill gid type
+ Input : struct rdma_gid_entry *gid_entry
+ Output : None
+
+ 1.Date : 2016/5/27
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_fill_gid_type(struct rdma_gid_entry *gid_entry,
+ enum roce5_gid_type new_gid_type)
+{
+ static u32 index_roce5_gid_mapping[32][4] = {
+ { 0x120E1436, 3452, 224529784, 0x180E252A },
+ { 0x120E004A, 3472, 224660876, 0x6C0E403E },
+ { 0x120E0042, 3464, 224660836, 0x840E4036 },
+ { 0x120E0042, 3464, 224398688, 0xC00E0036 },
+ { 0x1212143A, 3456, 224791932, 0x1812252E },
+ { 0x1212004E, 3476, 224923024, 0x6C124042 },
+ { 0x12120046, 3468, 224922984, 0x8412403A },
+ { 0x12120046, 3468, 224660836, 0xC012003A },
+ { 0x1216143E, 3460, 225054080, 0x18162532 },
+ { 0x12160052, 3480, 225185172, 0x6C164046 },
+ { 0x1216004A, 3472, 225185132, 0x8416403E },
+ { 0x1216004A, 3472, 224922984, 0xC016003E },
+ { 0x10301458, 3484, 226626968, 0x1830254C },
+ { 0x1030006C, 3504, 226758060, 0x6C304060 },
+ { 0x10300064, 3496, 226758020, 0x84304058 },
+ { 0x10300064, 3496, 226495872, 0xC0300058 },
+ { 0x10401468, 838864300, 227675560, 0x1840255C },
+ { 0x1040007C, 1174408640, 227806652, 0x6C404070 },
+ { 0x10400074, 1040190904, 227806612, 0x84404068 },
+ { 0x10400074, 1040190904, 227544464, 0xC0400068 },
+ { 0x1044146C, 905973168, 227937708, 0x18442560 },
+ { 0x10440080, 1241517508, 228068800, 0x6C444074 },
+ { 0x10440078, 1107299772, 228068760, 0x8444406C },
+ { 0x10440078, 1107299772, 227806612, 0xC044006C },
+ { 0x10481470, 973082036, 228199856, 0x18482564 },
+ { 0x10480084, 1308626376, 228330948, 0x6C484078 },
+ { 0x1048007C, 1174408640, 228330908, 0x84484070 },
+ { 0x1048007C, 1174408640, 228068760, 0xC0480070 },
+ { 0x1262148A, 1040190928, 230034892, 0x1862257E },
+ { 0x1262009E, 1375735268, 230165984, 0x6C624092 },
+ { 0x12620096, 1241517532, 230165944, 0x8462408A },
+ { 0x12620096, 1241517532, 229903796, 0xC062008A },
+ };
+
+ u8 i = 0;
+ gid_entry->dw6_h.bs.gid_type = new_gid_type;
+ gid_entry->dw6_h.bs.gid_update = (new_gid_type == ROCE_IPv4_ROCEv2_GID);
+
+ i = ROCE_GID_MAP_TBL_IDX_GET(gid_entry->dw6_h.bs.tag, (u8)new_gid_type);
+ gid_entry->hdr_len_value = index_roce5_gid_mapping[i][0];
+ if (new_gid_type == ROCE_IPv4_ROCEv2_GID) {
+ *((u32 *)(void *)gid_entry + 1) =
+ cpu_to_be32(index_roce5_gid_mapping[i][1]);
+ *((u32 *)(void *)gid_entry + ROCE_GID_MAP_TBL_IDX2) =
+ cpu_to_be32(
+ index_roce5_gid_mapping[i]
+ [ROCE_GID_MAP_TBL_IDX2]);
+ }
+}
+
+static void roce5_fill_gid_smac(struct net_device *net_dev,
+ struct rdma_gid_entry *gid_entry)
+{
+ int ret;
+ ret = memcpy_s((void *)gid_entry->smac, sizeof(gid_entry->smac),
+ (void *)net_dev->dev_addr, sizeof(gid_entry->smac));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy smac.(ret:%d)", ret);
+ }
+}
+
+/*
+ 2024-04-05 add rdev parameters, because is in roce driver load, via roce5_ib_add_gid to next call, roce5_fill_gid_entry_ext
+ via net_dev get to rdev is empty, function in advance return, cannot execute expected of tunnel assignment logical
+*/
+static void roce5_fill_gid_vlan(const struct roce5_device *rdev,
+ struct net_device *net_dev,
+ struct rdma_gid_entry *gid_entry)
+{
+ if (rdma_vlan_dev_vlan_id(net_dev) != 0xffff) {
+ gid_entry->dw4.bs.cvlan = rdma_vlan_dev_vlan_id(net_dev) &
+ 0xfff;
+ gid_entry->dw6_h.bs.tag = ROCE_GID_VLAN_VALID;
+ }
+
+ roce5_fill_gid_entry_ext(rdev, gid_entry);
+}
+
+/* ****************************************************************************
+ Prototype : roce5_dispatch_event
+ Description : roce5_dispatch_event
+ Input : struct roce5_device *rdev
+ int port_num
+ enum ib_event_type type
+ Output : None
+
+ 1.Date : 2016/3/29
+ Modification : Created function
+
+**************************************************************************** */
+static void roce5_dispatch_event(struct roce5_device *rdev, int port_num,
+ enum ib_event_type type)
+{
+ struct ib_event event;
+ int ret;
+
+ if (rdev == NULL) {
+ ROCE_ERR("Rdev is null");
+ return;
+ }
+
+ ret = memset_s(&event, sizeof(event), 0, sizeof(event));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memset event.(ret:%d)", ret);
+ }
+
+ event.device = &rdev->ib_dev;
+ event.element.port_num = (u8)port_num;
+ event.event = type;
+
+ ROCE_DEV_INFO(rdev, "driver dispatch event: %d.", type);
+ ib_dispatch_event(&event);
+}
+
+static int roce5_del_old_gid_entry(struct roce5_device *rdev)
+{
+ struct rdma_gid_entry old_gid_entry;
+ int ret = 0;
+ int index = 0;
+
+ ret = memset_s(&old_gid_entry, sizeof(old_gid_entry), 0,
+ sizeof(old_gid_entry));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset gid_entry.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ ret = roce5_get_gid(rdev, 1, index, &old_gid_entry);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get gid, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ ret = roce5_modify_ipsu_tbl_ip_entry(rdev, &old_gid_entry,
+ ROCE_MPU_CMD_DEL_IPSU_IP);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to del ipsu ip entry, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ roce5_del_ipsu_tcam_tbl_entry(rdev, &old_gid_entry);
+ }
+ return ret;
+}
+
+static int roce5_netdev_event_ipv4_dev_scan(struct roce5_device *rdev,
+ struct net_device *event_netdev,
+ struct rdma_gid_entry *gid_entry)
+{
+ struct in_device *in_dev = NULL;
+ int ret = 0;
+ int index = 0;
+
+ ret = roce5_del_old_gid_entry(rdev);
+ if (ret != 0) {
+ ROCE_ERR("Failed to del gid_entry.(ret:%d)", ret);
+ return ret;
+ }
+
+ in_dev = in_dev_get(event_netdev);
+ if (in_dev) {
+ for_ifa(in_dev)
+ {
+ ipv6_addr_set_v4mapped(
+ ifa->ifa_address,
+ (struct in6_addr *)gid_entry->raw);
+
+ roce5_fill_gid_vlan(rdev, event_netdev, gid_entry);
+ roce5_fill_gid_smac(event_netdev, gid_entry);
+
+ /* RoCE V2 */
+ if (rdma_protocol_roce_udp_encap(
+ &rdev->ib_dev, ROCE_DEFAULT_PORT_NUM)) {
+ roce5_fill_gid_type(gid_entry,
+ ROCE_IPv4_ROCEv2_GID);
+ ret = roce5_update_gid_mac(rdev, 0, &index,
+ gid_entry);
+ }
+
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to update type(%u) gid(IPv4) when process netdev's event, func_id(%d)",
+ gid_entry->dw6_h.bs.gid_type,
+ rdev->glb_func_id);
+ in_dev_put(in_dev);
+ return ret;
+ }
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ ret = roce5_modify_ipsu_tbl_ip_entry(
+ rdev, gid_entry,
+ ROCE_MPU_CMD_ADD_IPSU_IP);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to add ipsu ip entry, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ roce5_add_ipsu_tcam_tbl_entry(rdev, gid_entry,
+ index);
+ }
+ roce5_dispatch_event(rdev, ROCE_DEFAULT_PORT_NUM,
+ IB_EVENT_GID_CHANGE);
+ }
+ endfor_ifa(in_dev);
+ in_dev_put(in_dev);
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+struct sin6_list {
+ struct list_head list;
+ struct sockaddr_in6 sin6;
+};
+
+static int roce5_gid_fill(struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry,
+ struct net_device *event_netdev,
+ struct sin6_list *sin6_iter)
+{
+ int ret = 0;
+ int index;
+
+ ret = roce5_del_old_gid_entry(rdev);
+ if (ret != 0) {
+ ROCE_ERR("Failed to del gid_entry.(ret:%d)", ret);
+ return ret;
+ }
+
+ if (cpu_to_be64(gid_entry->global.subnet_prefix) ==
+ ROCE_DEFAULT_GID_SUBNET_PREFIX) {
+ return ret;
+ }
+
+ roce5_fill_gid_vlan(rdev, event_netdev, gid_entry);
+ roce5_fill_gid_smac(event_netdev, gid_entry);
+
+ /* RoCE V2 */
+ if (rdma_protocol_roce_udp_encap(&rdev->ib_dev,
+ ROCE_DEFAULT_PORT_NUM)) {
+ roce5_fill_gid_type(gid_entry, ROCE_IPv6_ROCEv2_GID);
+ ret = roce5_update_gid_mac(rdev, 0, &index, gid_entry);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to update V2 gid(IPv6), func_id(%d)",
+ rdev->glb_func_id);
+ list_del(&sin6_iter->list);
+ kfree(sin6_iter);
+ return ret;
+ }
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ ret = roce5_modify_ipsu_tbl_ip_entry(
+ rdev, gid_entry, ROCE_MPU_CMD_ADD_IPSU_IP);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to add ipsu ip entry, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ roce5_add_ipsu_tcam_tbl_entry(rdev, gid_entry, index);
+ }
+ }
+
+ roce5_dispatch_event(rdev, ROCE_DEFAULT_PORT_NUM, IB_EVENT_GID_CHANGE);
+
+ return ret;
+}
+
+static int roce5_netdev_event_ipv6_dev_scan(struct roce5_device *rdev,
+ struct net_device *event_netdev,
+ struct rdma_gid_entry *gid_entry)
+{
+ struct sin6_list *sin6_temp = NULL;
+ struct sin6_list *sin6_iter = NULL;
+ struct inet6_dev *in6_dev = NULL;
+ struct inet6_ifaddr *ifp = NULL;
+ struct sin6_list *entry = NULL;
+ int ret;
+
+ LIST_HEAD(sin6_init_list);
+
+ in6_dev = in6_dev_get(event_netdev);
+ if (in6_dev == NULL) {
+ return 0;
+ }
+
+ read_lock_bh(&in6_dev->lock);
+ list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (entry == NULL) {
+ continue;
+ }
+
+ entry->sin6.sin6_family = AF_INET6;
+ entry->sin6.sin6_addr = ifp->addr;
+ list_add_tail(&entry->list, &sin6_init_list);
+ }
+
+ read_unlock_bh(&in6_dev->lock);
+ in6_dev_put(in6_dev);
+
+ list_for_each_entry_safe(sin6_iter, sin6_temp, &sin6_init_list, list) {
+ if (memcpy_s((void *)gid_entry->raw, sizeof(union ib_gid),
+ (void *)&sin6_iter->sin6.sin6_addr,
+ sizeof(union ib_gid)) != 0) {
+ ROCE_WARN("Failed to do memcpy_s");
+ }
+
+ ret = roce5_gid_fill(rdev, gid_entry, event_netdev, sin6_iter);
+ if (ret != 0) {
+ goto err_free;
+ }
+
+ list_del(&sin6_iter->list);
+ kfree(sin6_iter);
+ }
+
+ return 0;
+
+err_free:
+ list_for_each_entry_safe(sin6_iter, sin6_temp, &sin6_init_list, list) {
+ list_del(&sin6_iter->list);
+ kfree(sin6_iter);
+ }
+ return ret;
+}
+#endif
+
+static int roce5_netdev_event_ip_dev_scan(struct roce5_device *rdev,
+ struct net_device *event_netdev)
+{
+ struct rdma_gid_entry gid_entry;
+ int ret;
+
+ ret = memset_s(&gid_entry, sizeof(gid_entry), 0, sizeof(gid_entry));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset gid_entry.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ ret = roce5_netdev_event_ipv4_dev_scan(rdev, event_netdev, &gid_entry);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to scan IPv4, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ ret = roce5_netdev_event_ipv6_dev_scan(rdev, event_netdev, &gid_entry);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to scan IPv6, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static struct roce5_vlan_dev_list *
+roce5_find_vlan_device_list(const struct list_head *mac_list,
+ const struct net_device *netdev)
+{
+ struct roce5_vlan_dev_list *vlan_dev_list = NULL;
+
+ list_for_each_entry(vlan_dev_list, mac_list, list) {
+ if (vlan_dev_list->net_dev == netdev) {
+ return vlan_dev_list;
+ }
+ }
+
+ return NULL;
+}
+
+static int roce5_add_vlan_device(struct roce5_device *rdev,
+ struct net_device *netdev)
+{
+ struct roce5_vlan_dev_list *new_list = NULL;
+ int ret;
+
+ new_list = (struct roce5_vlan_dev_list *)kzalloc(sizeof(*new_list),
+ GFP_KERNEL);
+ if (new_list == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Malloc mac_vlan list_head is NULL, func_id(%d)",
+ rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ new_list->ref_cnt = 1;
+ new_list->net_dev = netdev;
+ new_list->vlan_id = ROCE_GID_SET_VLAN_32BIT_VLAID(
+ ((u32)rdma_vlan_dev_vlan_id(netdev)));
+ ret = memcpy_s(new_list->mac, ROCE_MAC_ADDR_LEN, netdev->dev_addr,
+ ROCE_MAC_ADDR_LEN);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy mac.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&new_list->list);
+ list_add_tail(&new_list->list, &rdev->mac_vlan_list_head);
+
+ return 0;
+}
+
+static void roce5_del_vlan_device(struct roce5_device *rdev,
+ struct roce5_vlan_dev_list *old_list)
+{
+ list_del(&old_list->list);
+ kfree(old_list);
+}
+
+int roce5_add_vlan_device_mac(struct roce5_device *rdev,
+ struct net_device *netdev)
+{
+ int ret = 0;
+ u32 vlan_id = 0;
+
+ vlan_id = ROCE_GID_SET_VLAN_32BIT_VLAID(
+ ((u32)rdma_vlan_dev_vlan_id(netdev)));
+ ROCE_DEV_INFO(
+ rdev,
+ "enter roce5_add_vlan_device_mac, vlan_id(0x%x), func_id(%d).",
+ vlan_id, rdev->glb_func_id);
+
+ ret = roce5_add_mac_tbl_mac_entry(rdev, (u8 *)netdev->dev_addr,
+ ETH_ALEN, vlan_id, rdev->glb_func_id);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set vlan device mac, vlan_id(0x%x), func_id(%d)",
+ vlan_id, rdev->glb_func_id);
+ return ret;
+ }
+
+ roce5_add_ipsu_tbl_mac_entry(rdev, (u8 *)netdev->dev_addr, vlan_id,
+ rdev->glb_func_id,
+ hinic5_er_id(rdev->hwdev),
+ rdev->glb_func_id);
+
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ ret = roce5_add_bond_vlan_slave_mac(
+ rdev, (u8 *)netdev->dev_addr, (u16)vlan_id);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set bond vlan slave mac, vlan_id(0x%x), func_id(%d)",
+ vlan_id, rdev->glb_func_id);
+ goto err_add_bond_vlan_slave_mac;
+ }
+ }
+#endif
+
+ return ret;
+
+#ifdef ROCE_BONDING_EN
+err_add_bond_vlan_slave_mac:
+ roce5_del_ipsu_tbl_mac_entry(rdev, (u8 *)netdev->dev_addr, ETH_ALEN,
+ vlan_id, hinic5_er_id(rdev->hwdev),
+ rdev->glb_func_id);
+
+ (void)hinic5_del_mac(rdev->hwdev, (u8 *)netdev->dev_addr, (u16)vlan_id,
+ rdev->glb_func_id, HINIC5_CHANNEL_ROCE);
+
+ return ret;
+#endif
+}
+
+void roce5_del_vlan_device_mac(struct roce5_device *rdev,
+ struct roce5_vlan_dev_list *old_list)
+{
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ roce5_del_bond_vlan_slave_mac(rdev, old_list->mac,
+ (u16)old_list->vlan_id);
+ }
+#endif
+
+ roce5_del_ipsu_tbl_mac_entry(rdev, old_list->mac, ETH_ALEN,
+ old_list->vlan_id,
+ hinic5_er_id(rdev->hwdev),
+ rdev->glb_func_id);
+
+ (void)roce5_del_mac_tbl_mac_entry(rdev, old_list->mac, ETH_ALEN,
+ old_list->vlan_id, rdev->glb_func_id);
+}
+
+static int roce5_update_vlan_device_mac(struct roce5_device *rdev,
+ struct net_device *netdev)
+{
+ struct roce5_vlan_dev_list *old_list = NULL;
+ int ret;
+
+ mutex_lock(&rdev->mac_vlan_mutex);
+ old_list =
+ roce5_find_vlan_device_list(&rdev->mac_vlan_list_head, netdev);
+ if (old_list == NULL) {
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ return 0;
+ }
+
+ if (ROCE_MEMCMP(old_list->mac, netdev->dev_addr, ROCE_MAC_ADDR_LEN) !=
+ 0) {
+ roce5_del_vlan_device_mac(rdev, old_list);
+
+ ret = roce5_add_vlan_device_mac(rdev, netdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to add mac_vlan, func_id(%d)",
+ rdev->glb_func_id);
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ return ret;
+ }
+
+ ret = memcpy_s(old_list->mac, ROCE_MAC_ADDR_LEN,
+ netdev->dev_addr, ROCE_MAC_ADDR_LEN);
+ if (ret != 0) {
+ roce5_del_vlan_device_mac(rdev, old_list);
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&rdev->mac_vlan_mutex);
+
+ return 0;
+}
+
+int roce5_add_real_device_mac(struct roce5_device *rdev,
+ struct net_device *netdev)
+{
+ int ret;
+
+ roce5_add_ipsu_tbl_mac_entry(rdev, (u8 *)netdev->dev_addr, 0,
+ rdev->glb_func_id,
+ hinic5_er_id(rdev->hwdev),
+ rdev->glb_func_id);
+
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ ret = roce5_add_bond_real_slave_mac(rdev,
+ (u8 *)netdev->dev_addr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to add bond read device ipsu mac, func_id(%d)",
+ rdev->glb_func_id);
+ roce5_del_ipsu_tbl_mac_entry(
+ rdev, (u8 *)netdev->dev_addr, ETH_ALEN, 0,
+ hinic5_er_id(rdev->hwdev), rdev->glb_func_id);
+ return ret;
+ }
+ }
+#endif
+
+ ret = memcpy_s(rdev->mac, sizeof(rdev->mac), netdev->dev_addr,
+ sizeof(rdev->mac));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy mac.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void roce5_del_real_device_mac(struct roce5_device *rdev)
+{
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ roce5_del_bond_real_slave_mac(rdev);
+ }
+#endif
+
+ roce5_del_ipsu_tbl_mac_entry(rdev, rdev->mac, ETH_ALEN, 0,
+ hinic5_er_id(rdev->hwdev),
+ rdev->glb_func_id);
+}
+
+static int roce5_update_real_device_mac(struct roce5_device *rdev,
+ struct net_device *netdev)
+{
+ int ret;
+
+ roce5_del_real_device_mac(rdev);
+
+ ret = roce5_add_real_device_mac(rdev, netdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to add real device ipsu mac, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+void roce5_clean_vlan_device_mac(struct roce5_device *rdev)
+{
+ struct roce5_vlan_dev_list *pos = NULL;
+ struct roce5_vlan_dev_list *tmp = NULL;
+
+ mutex_lock(&rdev->mac_vlan_mutex);
+ list_for_each_entry_safe(pos, tmp, &rdev->mac_vlan_list_head, list) {
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ (void)roce5_del_bond_vlan_slave_mac(rdev, pos->mac,
+ (u16)pos->vlan_id);
+ }
+#endif
+ roce5_del_ipsu_tbl_mac_entry(rdev, pos->mac, ETH_ALEN,
+ pos->vlan_id,
+ hinic5_er_id(rdev->hwdev),
+ rdev->glb_func_id);
+
+ (void)roce5_del_mac_tbl_mac_entry(rdev, pos->mac, ETH_ALEN,
+ pos->vlan_id,
+ rdev->glb_func_id);
+
+ list_del(&pos->list);
+ kfree(pos);
+ }
+ mutex_unlock(&rdev->mac_vlan_mutex);
+}
+
+void roce5_clean_real_device_mac(struct roce5_device *rdev)
+{
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ (void)roce5_del_bond_real_slave_mac(rdev);
+ }
+#endif
+
+ roce5_del_ipsu_tbl_mac_entry(rdev, rdev->mac, ETH_ALEN, 0,
+ hinic5_er_id(rdev->hwdev),
+ rdev->glb_func_id);
+}
+
+void roce5_ifconfig_up_down_event_report(struct roce5_device *rdev,
+ u8 net_event)
+{
+ struct ib_event event = {};
+
+ event.device = &rdev->ib_dev;
+ event.event = net_event;
+ event.element.port_num = ROCE_DEFAULT_PORT_NUM;
+
+ ib_dispatch_event(&event);
+}
+
+static int roce5_netdev_event_raw_dev(unsigned long event,
+ struct roce5_device *rdev,
+ struct net_device *event_netdev)
+{
+ int ret;
+
+ if (event == NETDEV_CHANGEADDR) {
+ ret = roce5_update_real_device_mac(rdev, event_netdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to update real device mac, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce5_netdev_event_ip_dev_scan(rdev, event_netdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to scan ip_dev, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+#ifdef ROCE_BONDING_EN
+ if (roce5_bond_is_active(rdev)) {
+ if ((event == NETDEV_DOWN) || (event == NETDEV_UP)) {
+ roce5_handle_bonded_port_state_event(rdev);
+ }
+ return 0;
+ }
+#endif
+ if (event == NETDEV_DOWN) {
+ if (test_and_clear_bit(ROCE5_PORT_EVENT, &rdev->status) != 0) {
+ roce5_ifconfig_up_down_event_report(rdev,
+ IB_EVENT_PORT_ERR);
+ }
+ }
+
+ if (event == NETDEV_UP) {
+ if (test_and_set_bit(ROCE5_PORT_EVENT, &rdev->status) == 0) {
+ roce5_ifconfig_up_down_event_report(
+ rdev, IB_EVENT_PORT_ACTIVE);
+ }
+ }
+
+ return 0;
+}
+
+static int roce5_netdev_event_vlan_dev(unsigned long event,
+ struct roce5_device *rdev,
+ struct net_device *event_netdev)
+{
+ int ret;
+
+ if (event == NETDEV_CHANGEADDR) {
+ ret = roce5_update_vlan_device_mac(rdev, event_netdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to update vlan device mac, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce5_netdev_event_ip_dev_scan(rdev, event_netdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to scan vlan device ip list, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int roce5_netdev_event(struct notifier_block *nb, unsigned long event,
+ void *ptr)
+{
+ struct net_device *event_netdev = NULL;
+ struct roce5_device *rdev = NULL;
+ struct hinic5_lld_dev *lld_dev = NULL;
+ struct net_device *real_dev = NULL;
+ int ret;
+
+ if (nb == NULL || ptr == NULL) {
+ goto err_out;
+ }
+
+ event_netdev = netdev_notifier_info_to_dev(ptr);
+ if (event_netdev->type != ARPHRD_ETHER) {
+ goto err_out;
+ }
+
+ real_dev = (rdma_vlan_dev_real_dev(event_netdev) != 0) ?
+ rdma_vlan_dev_real_dev(event_netdev) :
+ event_netdev;
+
+ lld_dev = hinic5_get_lld_dev_by_netdev(real_dev);
+ if (lld_dev == NULL) {
+ goto err_out;
+ }
+
+ /*
+ * hinic5_get_uld_dev internal will call uld5_dev_hold add device reference count
+ * via uld5_dev_put free reference count
+ */
+ rdev = (struct roce5_device *)hinic5_get_uld_dev(lld_dev,
+ SERVICE_T_ROCE);
+
+ /*
+ * passed in of rdev is empty value when,roce5_bond_event_cfg_rdev will found lld corresponding to bond device rdev, call uld5_dev_hold add device reference count
+ * passed in of rdev non-null value when, reserved rdev original value, not will call uld5_dev_hold add device reference count
+ * via uld5_dev_put free reference count
+ */
+ ret = roce5_bond_event_cfg_rdev(lld_dev, (void *)rdev, &rdev, true);
+ if (ret != 0 || rdev == NULL) {
+ goto err_out;
+ }
+
+ /* not need extra of roce5_is_port_of_net_dev check */
+ if (real_dev == event_netdev) {
+ ret = roce5_netdev_event_raw_dev(event, rdev, event_netdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to deal with raw device, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_put;
+ }
+ } else {
+ ret = roce5_netdev_event_vlan_dev(event, rdev, event_netdev);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to deal with vlan device, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_put;
+ }
+ }
+
+err_put:
+ uld5_dev_put(rdev->lld_dev, SERVICE_T_ROCE);
+err_out:
+ return NOTIFY_DONE;
+}
+
+int roce5_register_netdev_notifier(void)
+{
+ int ret;
+
+ g_roce5_netdev_notifier.notifier_call = roce5_netdev_event;
+ ret = register_netdevice_notifier(&g_roce5_netdev_notifier);
+ if (ret != 0) {
+ ROCE_ERR("Failed to register netdev notifier, ret(%d)", ret);
+ g_roce5_netdev_notifier.notifier_call = NULL;
+ }
+
+ return ret;
+}
+
+void roce5_unregister_netdev_notifier(void)
+{
+ if (g_roce5_netdev_notifier.notifier_call != NULL) {
+ unregister_netdevice_notifier(&g_roce5_netdev_notifier);
+ g_roce5_netdev_notifier.notifier_call = NULL;
+ }
+}
+
+static int roce5_set_gid_entry(const struct ib_gid_attr *attr,
+ struct rdma_gid_entry *gid_entry)
+{
+ int ret = 0;
+ enum rdma_network_type network_type;
+ static enum roce5_gid_type gid_type_map[] = {
+ // map rdma_network_type to roce5_gid_type
+ [RDMA_NETWORK_IB] = ROCE_ROCEv1_GID,
+ [RDMA_NETWORK_ROCE_V1] = ROCE_ROCEv1_GID,
+ [RDMA_NETWORK_IPV4] = ROCE_IPv4_ROCEv2_GID,
+ [RDMA_NETWORK_IPV6] = ROCE_IPv6_ROCEv2_GID,
+ };
+
+ ret = memset_s(gid_entry, sizeof(*gid_entry), 0, sizeof(*gid_entry));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset gid_entry.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ network_type = rdma_gid_attr_network_type(attr);
+ ret = memcpy_s((void *)gid_entry->raw, sizeof(union ib_gid),
+ (void *)(&attr->gid), sizeof(union ib_gid));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy gid_entry.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ if (network_type == RDMA_NETWORK_ROCE_V1 ||
+ network_type == RDMA_NETWORK_IB) {
+ ROCE_ERR("network type(%d) is unsupported.", network_type);
+ return -EINVAL;
+ }
+
+ roce5_fill_gid_vlan(to_roce5_dev(attr->device), attr->ndev, gid_entry);
+ roce5_fill_gid_type(gid_entry, gid_type_map[network_type]);
+ roce5_fill_gid_smac(attr->ndev, gid_entry);
+
+ return 0;
+}
+
+/* add vlan_mac list or ref_cnt + 1
+ * add mac_vlan when new list add
+ */
+static int roce5_notify_vlan(struct roce5_device *rdev,
+ const struct ib_gid_attr *attr)
+{
+ int ret;
+ struct roce5_vlan_dev_list *old_list = NULL;
+
+ mutex_lock(&rdev->mac_vlan_mutex);
+ ROCE_DEV_INFO(rdev, "Add vlan: func_id(%d), netdev(%s).",
+ rdev->glb_func_id, attr->ndev->name);
+ old_list = roce5_find_vlan_device_list(&rdev->mac_vlan_list_head,
+ attr->ndev);
+ if (old_list != NULL) {
+ old_list->ref_cnt++;
+ ret = 0;
+ goto out;
+ }
+
+ ret = roce5_add_vlan_device(rdev, attr->ndev);
+ if (ret != 0) {
+ goto out;
+ }
+
+ ret = roce5_add_vlan_device_mac(rdev, attr->ndev);
+ if (ret != 0) {
+ old_list = roce5_find_vlan_device_list(
+ &rdev->mac_vlan_list_head, attr->ndev);
+ if (old_list) {
+ roce5_del_vlan_device(rdev, old_list);
+ }
+ }
+
+out:
+ mutex_unlock(&rdev->mac_vlan_mutex);
+
+ return ret;
+}
+
+int roce5_ib_add_gid_common(const struct ib_gid_attr *attr)
+{
+ int ret;
+ struct rdma_gid_entry gid_entry;
+ struct roce5_device *rdev = NULL;
+ unsigned int index;
+
+ // the input gid pointer is not needed to check on Euler OS
+ if (attr == NULL) {
+ ROCE_ERR("Input pointer is NULL");
+ return (-EINVAL);
+ }
+
+ rdev = to_roce5_dev(attr->device);
+ index = attr->index;
+
+ ret = roce5_set_gid_entry(attr, &gid_entry);
+ if (ret != 0) {
+ ROCE_ERR("Failed to set gid entry.");
+ return ret;
+ }
+
+ ret = roce5_update_gid(rdev, 0, index, &gid_entry);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to update gid. ret(%d),func_id(%d)",
+ ret, rdev->glb_func_id);
+ return ret;
+ }
+
+ rdev->gid_dev[index] = attr->ndev;
+
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ ret = roce5_modify_ipsu_tbl_ip_entry(rdev, &gid_entry,
+ ROCE_MPU_CMD_ADD_IPSU_IP);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to add ipsu ip entry, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ roce5_add_ipsu_tcam_tbl_entry(rdev, &gid_entry, index);
+ }
+
+ if (rdma_vlan_dev_real_dev(attr->ndev)) {
+ ret = roce5_notify_vlan(rdev, attr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to nofify vlan, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int roce5_ib_add_gid(const struct ib_gid_attr *attr,
+ __always_unused void **context)
+{
+ return roce5_ib_add_gid_common(attr);
+}
+
+int roce5_ib_del_gid(const struct ib_gid_attr *attr,
+ __always_unused void **context)
+{
+ struct roce5_vlan_dev_list *old_list = NULL;
+ struct roce5_device *rdev = NULL;
+ struct rdma_gid_entry gid_entry;
+ u32 index = 0;
+ int ret;
+
+ if ((attr == NULL) || (attr->device == NULL)) {
+ ROCE_ERR("Attr or attr->device is null");
+ return (-EINVAL);
+ }
+
+ rdev = to_roce5_dev(attr->device);
+ index = attr->index;
+ if (index >= rdev->rdma_cap.max_gid_per_port) {
+ ROCE_DEV_ERR(rdev, "Invalid gid index(%u), func_id(%d)", index,
+ rdev->glb_func_id);
+ return (-EINVAL);
+ }
+
+ /* del vlan_mac list or ref_cnt - 1 */
+ /* del mac_vlan when ref_cnt = 0 */
+ if (rdev->ndev != rdev->gid_dev[index]) {
+ mutex_lock(&rdev->mac_vlan_mutex);
+ old_list = roce5_find_vlan_device_list(
+ &rdev->mac_vlan_list_head, rdev->gid_dev[index]);
+ if (old_list) {
+ old_list->ref_cnt--;
+ if (old_list->ref_cnt == 0) {
+ roce5_del_vlan_device_mac(rdev, old_list);
+
+ roce5_del_vlan_device(rdev, old_list);
+ }
+ }
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ }
+
+ ret = memset_s(&gid_entry, sizeof(gid_entry), 0, sizeof(gid_entry));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset gid_entry.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ ret = roce5_get_gid(rdev, 1, index, &gid_entry);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get gid, func_id(%d), index(%u)",
+ rdev->glb_func_id, index);
+ return ret;
+ }
+
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ ret = roce5_modify_ipsu_tbl_ip_entry(rdev, &gid_entry,
+ ROCE_MPU_CMD_DEL_IPSU_IP);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to del ipsu ip entry, func_id(%d)",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ roce5_del_ipsu_tcam_tbl_entry(rdev, &gid_entry);
+ }
+
+ /*
+ * delete gid no longer send cmd to ucode which write 0s to target entry,
+ * preventing PPE from building malformed packets. */
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/netdev/roce_netdev.h b/drivers/infiniband/hw/hiroce5/kernel/dev/netdev/roce_netdev.h
new file mode 100644
index 000000000..f77f75dbc
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/netdev/roce_netdev.h
@@ -0,0 +1,70 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_NETDEV_H
+#define ROCE_NETDEV_H
+
+#include <net/ipv6.h>
+#include <net/bonding.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/inetdevice.h>
+#include <linux/if_vlan.h>
+
+#include <rdma/ib_addr.h>
+
+#include "roce.h"
+#include "roce_compat.h"
+#include "roce_mix.h"
+#include "roce_cmd.h"
+
+#ifdef ROCE_BONDING_EN
+#include "hinic5_srv_nic.h"
+#endif
+
+#include "securec.h"
+
+#define ROCE_GID_SET_VLAN_32BIT_VLAID(vlan_id) \
+ ((vlan_id) | (((u32)1) << 31)) /* the 31 bit is vlan eable bit */
+#define ROCE_MAC_ADDR_LEN 6
+
+/* ipv4 header len. unit:4B */
+#define IPV4_HDR_LEN 5
+
+#define IP_ECN_PERMIT 0x2 //ip header tclass bit[0:2]
+
+#define ROCE_DEFAULT_GID_SUBNET_PREFIX 0xFE80000000000000ULL
+
+#define ROCE_GID_MAP_TBL_IDX_GET(tag, new_gid_type) \
+ ((u8)(((tag) << 2) | (new_gid_type)))
+
+#define ROCE_GID_MAP_TBL_IDX2 2
+
+enum roce5_gid_vlan_type { ROCE_GID_VLAN_INVALID = 0, ROCE_GID_VLAN_VALID };
+
+enum roce5_gid_tunnel_type {
+ ROCE_GID_TUNNEL_INVALID = 0,
+ ROCE_GID_TUNNEL_VALID
+};
+
+struct roce5_vlan_dev_list {
+ u8 mac[ETH_ALEN];
+ u32 vlan_id;
+ u32 ref_cnt;
+ struct net_device *net_dev;
+ struct list_head list;
+};
+
+#if !defined(INETDEV_HAVE_FOR_IFA)
+#define for_ifa(in_dev) \
+ { \
+ struct in_ifaddr *ifa; \
+ for (ifa = (in_dev)->ifa_list; ifa; ifa = ifa->ifa_next)
+#define endfor_ifa(in_dev) }
+#endif
+
+int roce5_add_real_device_mac(struct roce5_device *rdev,
+ struct net_device *netdev);
+
+#endif /* ROCE_NETDEV_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink.c b/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink.c
new file mode 100644
index 000000000..6a16c7f29
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink.c
@@ -0,0 +1,413 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
+
+
+#include <linux/genetlink.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <net/genetlink.h>
+#include <net/net_namespace.h>
+#include <net/netlink.h>
+
+#include "roce.h"
+#include "hinic5_crm.h"
+#include "hinic5_lld.h"
+#include "roce_drv_msg_intf.h"
+#include "roce_infra.h"
+#include "roce_kernel_compat_gen.h"
+#include "roce_netlink_process.h"
+#include "securec.h"
+#include "udk_usrnl.h"
+#ifdef ENABLE_HYPER_ROCE
+#include "hyper_roce_netlink.h"
+#endif
+#include "roce_netlink.h"
+
+static int roce5_netlink_cmd_dispatch(struct sk_buff *skb,
+ struct genl_info *nl_info);
+
+static DEFINE_RWLOCK(g_cmd_process_rwlock); /* lock for cmd_cbs */
+static roce5_netlink_cmd_excute_callback cmd_cbs[USRNL_ROCE_CMD_NUM];
+
+static int roce5_netlink_register_cb(enum roce_usrnl_cmd cmd,
+ roce5_netlink_cmd_excute_callback cb)
+{
+ int ret = 0;
+
+ if (cmd >= USRNL_ROCE_CMD_NUM) {
+ ROCE_ERR("Invalid command(%u)", cmd);
+ return -EINVAL;
+ }
+
+ write_lock(&g_cmd_process_rwlock);
+
+ if (cmd_cbs[cmd] != NULL) {
+ ROCE_ERR(
+ "Repeated command setting, the callback of the command(%u) already exists.",
+ cmd);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cmd_cbs[cmd] = cb;
+
+out:
+ write_unlock(&g_cmd_process_rwlock);
+ return ret;
+}
+
+static void roce5_netlink_unregister_cb(enum roce_usrnl_cmd cmd)
+{
+ if (cmd >= USRNL_ROCE_CMD_NUM) {
+ ROCE_ERR("Invalid command(%u)", cmd);
+ return;
+ }
+
+ write_lock(&g_cmd_process_rwlock);
+ cmd_cbs[cmd] = NULL;
+ write_unlock(&g_cmd_process_rwlock);
+}
+
+int roce5_netlink_register_cbs(roce5_netlink_cmd_process cmd_procs[],
+ u8 cmd_num)
+{
+ int ret, i;
+
+ for (i = 0; i < cmd_num; ++i) {
+ ret = roce5_netlink_register_cb(cmd_procs[i].cmd,
+ cmd_procs[i].callback);
+ if (ret != 0) {
+ ROCE_ERR("Failed to set callback in netlink, ret(%d)",
+ ret);
+ goto err_out;
+ }
+ }
+
+ return 0;
+
+err_out:
+ for (--i; i >= 0; --i) {
+ roce5_netlink_unregister_cb(cmd_procs[i].cmd);
+ }
+ return ret;
+}
+
+static roce5_netlink_cmd_process g_cmd_process[] = {
+#ifdef ROCE_BONDING_EN
+ { USRNL_ROCE_CMD_QUERY_QP_TX_PORT, roce5_genl_query_qp_tx_port },
+ { USRNL_ROCE_CMD_SET_QP_TX_PORT, roce5_genl_set_qp_tx_port },
+ { USRNL_ROCE_CMD_QUERY_QP_RX_PORT, roce5_genl_query_qp_rx_port },
+ { USRNL_ROCE_CMD_QUERY_BOND_PORT_INFO,
+ roce5_genl_query_bond_port_info },
+ { USRNL_ROCE_CMD_SET_QP_UDP_SRC_PORT, roce5_genl_set_qp_udp_src_port },
+ { USRNL_ROCE_CMD_QUERY_QP_UDP_SRC_PORT,
+ roce5_genl_query_qp_udp_src_port },
+#endif
+ { USRNL_ROCE_CMD_QUERY_NEXT_WQE_IDX, roce5_genl_query_next_wqe_idx },
+ { USRNL_ROCE_CMD_QUERY_QPC, roce5_genl_query_qpc },
+ { USRNL_ROCE_CMD_QUERY_CQC, roce5_genl_query_cqc },
+ { USRNL_ROCE_CMD_QP_HASH_VALUE_PROCESS,
+ roce5_genl_qp_hash_value_process },
+ { USRNL_ROCE_CMD_ULD,
+ roce5_netlink_uld_process }, /* usr kernel of uld interface */
+};
+
+static int roce5_netlink_init_cbs(void)
+{
+ int ret;
+
+ ret = roce5_netlink_register_cbs(
+ g_cmd_process,
+ sizeof(g_cmd_process) / sizeof(roce5_netlink_cmd_process));
+ if (ret != 0) {
+ ROCE_ERR("Failed to register netlink callbacks, ret(%d).", ret);
+ return ret;
+ }
+
+#ifdef ENABLE_HYPER_ROCE
+ ret = roce5_hyper_netlink_init();
+ if (ret != 0) {
+ ROCE_ERR("Failed to init hyper roce in netlink, ret(%d).", ret);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+#if defined(NLA_POLICY_HAVE_MIN_MAX)
+static const struct nla_policy roce5_policy[USRNL_GENL_ATTR_MAX + 1] = {
+ [USRNL_GENL_ATTR] = { .type = NLA_BINARY,
+ .len = CMD_BUF_LEN_MAX,
+ .min = 0,
+ .max = CMD_BUF_LEN_MAX },
+};
+#else
+static const struct nla_policy roce5_policy[USRNL_GENL_ATTR_MAX + 1] = {
+ [USRNL_GENL_ATTR] = { .type = NLA_BINARY, .len = CMD_BUF_LEN_MAX },
+};
+#endif
+
+static const struct genl_ops roce5_genl_ops[] = { {
+ .cmd = USRNL_DEV_DRV_CMD_EXECUTE,
+#ifdef HAVE_GENL_OPS_FIELD_VALIDATE
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+#endif
+ .flags = GENL_ADMIN_PERM,
+ .policy = roce5_policy,
+ .doit = roce5_netlink_cmd_dispatch,
+} };
+
+static struct genl_family roce5_genl_family = {
+ .hdrsize = 0,
+ .name = ROCE_GENL_FAMILY_NAME,
+ .version = 1,
+ .maxattr = USRNL_GENL_ATTR_MAX,
+ .netnsok = true,
+ .parallel_ops = true,
+ .ops = roce5_genl_ops,
+ .n_ops = ARRAY_SIZE(roce5_genl_ops),
+};
+
+static void roce5_drv_msg_hdr_push(struct sk_buff *skb,
+ usrnl_drv_msg_hdr_s *in_msg_hdr,
+ uint16_t out_msg_data_len)
+{
+ usrnl_drv_msg_hdr_s *out_msg_hdr = NULL;
+
+ out_msg_hdr = skb_push(skb, ROCE_DRV_MSG_HDRLEN);
+ out_msg_hdr->cmd = in_msg_hdr->cmd;
+ out_msg_hdr->msg_len = ROCE_DRV_MSG_HDRLEN + out_msg_data_len;
+ out_msg_hdr->module = in_msg_hdr->module;
+ out_msg_hdr->src_func_idx = in_msg_hdr->src_func_idx;
+ out_msg_hdr->err_code = 0;
+}
+
+static void roce5_nlahdr_push(struct sk_buff *skb, uint16_t type)
+{
+ struct nlattr *nlahdr = NULL;
+ uint16_t attrlen = (uint16_t)skb->len;
+ uint32_t padlen = (uint32_t)nla_padlen(attrlen);
+
+ nlahdr = (struct nlattr *)skb_push(skb, NLA_HDRLEN);
+ nlahdr->nla_len = (uint16_t)nla_attr_size(attrlen);
+ nlahdr->nla_type = type;
+
+ if ((skb->end - skb->tail) >= padlen) {
+ (void)skb_put(skb, padlen);
+ }
+}
+
+static struct nlmsghdr *nlmsg_push(struct sk_buff *skb, uint32_t portid,
+ uint32_t seq, uint16_t type, uint32_t len,
+ uint16_t flags)
+{
+ struct nlmsghdr *nlh = NULL;
+ uint32_t size = (uint32_t)nlmsg_msg_size(len);
+
+ nlh = (struct nlmsghdr *)skb_push(skb, NLMSG_ALIGN(size));
+ if (nlh != NULL) {
+ nlh->nlmsg_type = type;
+ nlh->nlmsg_len = skb->len;
+ nlh->nlmsg_flags = flags;
+ nlh->nlmsg_pid = portid;
+ nlh->nlmsg_seq = seq;
+ if (!__builtin_constant_p(size) ||
+ NLMSG_ALIGN(size) - size != 0) {
+ (void)memset_s((char *)nlmsg_data(nlh) + len,
+ NLMSG_ALIGN(size) - size, 0,
+ NLMSG_ALIGN(size) - size);
+ }
+ }
+
+ return nlh;
+}
+
+static inline struct nlmsghdr *roce5_nlmsg_push(struct sk_buff *skb,
+ uint32_t portid, uint32_t seq,
+ uint16_t type, uint32_t payload,
+ uint16_t flags)
+{
+ if (unlikely(skb_headroom(skb) <
+ (unsigned int)nlmsg_total_size(payload))) {
+ return NULL;
+ }
+
+ return nlmsg_push(skb, portid, seq, type, payload, flags);
+}
+
+static void *roce5_genlmsg_push(struct sk_buff *skb, uint32_t portid,
+ uint32_t seq, const struct genl_family *family,
+ uint16_t flags, uint8_t cmd)
+{
+ struct nlmsghdr *nlh = NULL;
+ struct genlmsghdr *hdr = NULL;
+
+ nlh = roce5_nlmsg_push(skb, portid, seq, (int)family->id,
+ (int)(GENL_HDRLEN + family->hdrsize), flags);
+ if (nlh == NULL) {
+ return NULL;
+ }
+
+ hdr = nlmsg_data(nlh);
+ hdr->cmd = cmd;
+ hdr->version = (uint8_t)family->version;
+ hdr->reserved = 0;
+
+ return (void *)nlh;
+}
+
+static inline roce5_netlink_cmd_excute_callback
+roce5_netlink_get_callback(uint16_t cmd)
+{
+ roce5_netlink_cmd_excute_callback cb = NULL;
+
+ if (cmd >= USRNL_ROCE_CMD_NUM) {
+ ROCE_ERR("Invalid command(%u).", cmd);
+ return NULL;
+ }
+
+ read_lock(&g_cmd_process_rwlock);
+ cb = cmd_cbs[cmd];
+ read_unlock(&g_cmd_process_rwlock);
+
+ return cb;
+}
+
+static int32_t
+roce5_netlink_buf_handler(struct nlattr *cmd_attr,
+ roce5_netlink_cmd_excute_callback callback,
+ struct roce5_device *rdev, struct genl_info *nl_info,
+ struct sk_buff *reply)
+{
+ int32_t ret = 0;
+ uint16_t buf_in_len = 0;
+ uint16_t max_buf_out_len = 0;
+ uint16_t buf_out_len = 0;
+ usrnl_drv_msg_hdr_s *in_msg_hdr = NULL;
+
+ in_msg_hdr = (usrnl_drv_msg_hdr_s *)nla_data(cmd_attr);
+ if (in_msg_hdr->msg_len < ROCE_DRV_MSG_HDRLEN) {
+ ROCE_DEV_ERR(rdev, "Invalid parameter: msg_len(%d).",
+ in_msg_hdr->msg_len);
+ return -EINVAL;
+ }
+
+ buf_in_len = in_msg_hdr->msg_len - ROCE_DRV_MSG_HDRLEN;
+ max_buf_out_len =
+ NLMSG_DEFAULT_SIZE -
+ (NLMSG_HDRLEN + GENL_HDRLEN + NLA_HDRLEN + ROCE_DRV_MSG_HDRLEN);
+
+ if (buf_in_len == 0) {
+ ret = callback(rdev, NULL, 0, reply->data, max_buf_out_len,
+ &buf_out_len);
+ } else {
+ ret = callback(rdev, nla_data(cmd_attr) + ROCE_DRV_MSG_HDRLEN,
+ buf_in_len, reply->data, max_buf_out_len,
+ &buf_out_len);
+ }
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Do netlink %u cmd failed, errcode:%d",
+ nl_info->genlhdr->cmd, ret);
+ nlmsg_free(reply);
+ return -EIO;
+ }
+
+ if (buf_out_len != 0) {
+ skb_put(reply, buf_out_len);
+ }
+
+ roce5_drv_msg_hdr_push(reply, in_msg_hdr, buf_out_len);
+
+ return 0;
+}
+
+static int roce5_netlink_cmd_dispatch(struct sk_buff *skb,
+ struct genl_info *nl_info)
+{
+ int32_t ret = 0;
+ struct sk_buff *reply = NULL;
+ struct nlattr *cmd_attr = NULL;
+ roce5_drv_msg_hdr_s *in_msg_hdr = NULL;
+ roce5_netlink_cmd_excute_callback callback = NULL;
+ struct roce5_device *rdev = NULL;
+
+ cmd_attr = nl_info->attrs[USRNL_GENL_ATTR];
+ if (cmd_attr == NULL) {
+ ROCE_ERR("Do netlink cmd from portid:%u failed for NULL attr",
+ nl_info->snd_portid);
+ return -EINVAL;
+ } else if (nla_len(cmd_attr) < ROCE_DRV_MSG_HDRLEN) {
+ ROCE_ERR("Invalid parameter: nla_len(%d).", nla_len(cmd_attr));
+ return -EINVAL;
+ }
+
+ in_msg_hdr = (roce5_drv_msg_hdr_s *)nla_data(cmd_attr);
+
+ rdev = roce5_get_rdev_by_card_func_id(
+ in_msg_hdr->card_id, in_msg_hdr->common_hdr.src_func_idx);
+ if (rdev == NULL) {
+ ROCE_ERR("Invalid param: src_func_idx: %u, card_id: %llu",
+ in_msg_hdr->common_hdr.src_func_idx,
+ in_msg_hdr->card_id);
+ return -EINVAL;
+ }
+
+ callback = roce5_netlink_get_callback(in_msg_hdr->common_hdr.cmd);
+ if (callback == NULL) {
+ ROCE_DEV_ERR(rdev, "Unable to handle cmd: %u",
+ in_msg_hdr->common_hdr.cmd);
+ return -EINVAL;
+ }
+
+ reply = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (reply == NULL) {
+ ROCE_DEV_ERR(rdev, "Alloc reply buf for netlink cmd failed");
+ return -ENOMEM;
+ }
+
+ skb_reserve(reply, NLMSG_HDRLEN + GENL_HDRLEN + NLA_HDRLEN +
+ ROCE_DRV_MSG_HDRLEN);
+
+ ret = roce5_netlink_buf_handler(cmd_attr, callback, rdev, nl_info,
+ reply);
+ if (ret != 0) {
+ return ret;
+ }
+
+ roce5_nlahdr_push(reply, USRNL_GENL_ATTR);
+ roce5_genlmsg_push(reply, nl_info->snd_portid, nl_info->snd_seq,
+ &roce5_genl_family, 0, nl_info->genlhdr->cmd);
+
+ genlmsg_reply(reply, nl_info);
+
+ return 0;
+}
+
+int32_t roce5_netlink_init(void)
+{
+ int ret;
+
+ ret = roce5_netlink_init_cbs();
+ if (ret != 0) {
+ ROCE_ERR("Failed to init netlink callbacks, ret(%d).", ret);
+ return ret;
+ }
+
+ ret = genl_register_family(&roce5_genl_family);
+ if (ret != 0) {
+ ROCE_ERR("Failed to register netlink, ret(%d).", ret);
+ return ret;
+ }
+
+ ROCE_INFO("netlink init successfully.");
+ return 0;
+}
+
+void roce5_netlink_deinit(void)
+{
+ genl_unregister_family(&roce5_genl_family);
+ ROCE_INFO("netlink deinit successfully.");
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink.h b/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink.h
new file mode 100644
index 000000000..9c4cfff02
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink.h
@@ -0,0 +1,53 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2020-2023. All rights reserved.
+
+
+#ifndef ROCE5_NETLINK_H
+#define ROCE5_NETLINK_H
+
+#include <linux/types.h>
+#include "roce_drv_msg_intf.h"
+#include "roce.h"
+
+#define ROCE_GENL_FAMILY_NAME "roce5_genl"
+#define ROCE_DRV_MSG_HDRLEN (sizeof(roce5_drv_msg_hdr_s))
+#define CMD_BUF_LEN_MAX 2048
+
+typedef int32_t (*roce5_netlink_cmd_excute_callback)(struct roce5_device *rdev,
+ void *in, uint16_t in_len,
+ void *out,
+ uint16_t out_len,
+ uint16_t *out_size);
+
+enum roce_usrnl_cmd {
+ USRNL_ROCE_CMD_QUERY_QP_TX_PORT,
+ USRNL_ROCE_CMD_SET_QP_TX_PORT,
+ USRNL_ROCE_CMD_QUERY_QP_RX_PORT,
+ USRNL_ROCE_CMD_QUERY_BOND_PORT_INFO,
+ USRNL_ROCE_CMD_SET_QP_UDP_SRC_PORT,
+ USRNL_ROCE_CMD_QUERY_QP_UDP_SRC_PORT,
+ USRNL_ROCE_CMD_QUERY_NEXT_WQE_IDX,
+ USRNL_ROCE_CMD_QUERY_QPC,
+ USRNL_ROCE_CMD_QUERY_CQC,
+ USRNL_ROCE_CMD_QP_HASH_VALUE_PROCESS,
+ USRNL_ROCE_CMD_ULD, /* uld use */
+
+ /* Command number for HyperRoCE */
+ USRNL_ROCE_HYPER_ROCE_START = 16,
+ USRNL_ROCE_CMD_HYPER_QP_SET = USRNL_ROCE_HYPER_ROCE_START,
+ USRNL_ROCE_CMD_MODIFY_QP_EXTEND,
+ USRNL_ROCE_HYPER_ROCE_END = 31,
+ USRNL_ROCE_CMD_NUM
+};
+
+typedef struct {
+ enum roce_usrnl_cmd cmd;
+ roce5_netlink_cmd_excute_callback callback;
+} roce5_netlink_cmd_process;
+
+int32_t roce5_netlink_init(void);
+void roce5_netlink_deinit(void);
+int roce5_netlink_register_cbs(roce5_netlink_cmd_process cmd_procs[],
+ u8 cmd_num);
+
+#endif /* ROCE5_NETLINK_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink_process.c b/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink_process.c
new file mode 100644
index 000000000..8b7445ab0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink_process.c
@@ -0,0 +1,832 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#include <linux/types.h>
+#include <linux/semaphore.h>
+
+#include "hinic5_cqm.h"
+#include "hinic5_mt.h"
+#include "roce_cqm_cmd.h"
+#include "roce_cmd.h"
+#include "roce_com.h"
+#include "roce_dfx.h"
+#include "roce_main_extension.h"
+#include "roce_mix.h"
+#include "roce_npu_cmd.h"
+#include "roce_npu_cmd_defs.h"
+#include "roce_qp.h"
+#include "roce_restore.h"
+#include "roce_srq.h"
+#include "roce_uld_inner.h"
+#include "roce_uld_kernel_api.h"
+#include "roce_netlink_process.h"
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+static int32_t roce5_set_hash_value(struct roce5_device *rdev, uint32_t qpn,
+ uint32_t hash_type, uint32_t new_hash_value)
+{
+ int32_t ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ void *modify_hash_value = NULL;
+ size_t buf_size = 0;
+
+ if (ROCE5_SUPPORT_SET_HASH_VALUE_MSG_V2(rdev) != 0) {
+ buf_size = sizeof(roce_uni_cmd_modify_hash_s);
+ }
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (uint16_t)buf_size, NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+ modify_hash_value = cqm_cmd_inbuf->buf;
+
+ if (ROCE5_SUPPORT_SET_HASH_VALUE_MSG_V2(rdev) != 0) {
+ roce_uni_cmd_modify_hash_s *cmd =
+ (roce_uni_cmd_modify_hash_s *)modify_hash_value;
+ cmd->com.index = cpu_to_be32(qpn);
+ cmd->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ cmd->info.type = cpu_to_be32(hash_type);
+ cmd->info.hash_value = cpu_to_be32(new_hash_value);
+ }
+
+ ret = roce5_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_MODIFY_HASH_VALUE_QP,
+ cqm_cmd_inbuf, NULL, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send MODIFY_HASH_VALUE_QP command, func_id(%d), qpn(%u), type(%u), hash_value(%u), ret=%d",
+ rdev->glb_func_id, qpn, hash_type, new_hash_value, ret);
+ ret = -1;
+ }
+
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+static int32_t roce5_get_hash_value(struct roce5_device *rdev, uint32_t qpn,
+ uint32_t hash_type, uint32_t *hash_value)
+{
+ int32_t ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_get_hash_s *get_hash_value = NULL;
+ roce_verbs_qp_hash_info_s *get_hash_value_out = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (uint16_t)sizeof(roce_uni_cmd_get_hash_s), &cqm_cmd_outbuf,
+ (uint16_t)sizeof(roce_verbs_qp_hash_info_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ get_hash_value = (roce_uni_cmd_get_hash_s *)cqm_cmd_inbuf->buf;
+ get_hash_value->com.index = cpu_to_be32(qpn);
+ get_hash_value->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ get_hash_value->info.type = cpu_to_be32(hash_type);
+
+ ret = roce5_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_GET_HASH_VALUE_QP,
+ cqm_cmd_inbuf, cqm_cmd_outbuf,
+ ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send ROCE_CMD_GET_HASH_VALUE_QP command, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -1;
+ goto out;
+ }
+
+ get_hash_value_out = (roce_verbs_qp_hash_info_s *)cqm_cmd_outbuf->buf;
+ *hash_value = be32_to_cpu(get_hash_value_out->hash_value);
+
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+ return ret;
+}
+
+#ifdef ROCE_BONDING_EN
+int32_t roce5_genl_query_qp_tx_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size)
+{
+ int32_t ret = 0;
+ uint32_t slave_cnt = 0;
+ struct roce5_qp *rqp = NULL;
+ uint32_t func_tbl_value = 0;
+ struct roce5_qp_in *msg_in = NULL;
+ struct roce5_port_out *msg_out = NULL;
+
+ if (in == NULL || in_len == 0 || in_len < sizeof(struct roce5_qp_in) ||
+ out == NULL || out_len == 0 ||
+ out_len < sizeof(struct roce5_port_out) || out_size == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid param, in:%d, in_len:%u, out:%d, out_len:%u, out_size:%d",
+ !!in, in_len, !!out, out_len, !!out_size);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_qp_in *)in;
+ *out_size = sizeof(struct roce5_port_out);
+ msg_out = (struct roce5_port_out *)out;
+
+ if (!roce5_bond_is_active(rdev)) {
+ msg_out->port = 0;
+ return 0;
+ }
+
+ rqp = roce5_get_rqp_by_qpn(rdev, msg_in->qpn);
+ if (rqp == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to look up rqp");
+ return -EINVAL;
+ }
+
+ read_lock(&rdev->rwlock_func_tbl_bond);
+ func_tbl_value = rdev->func_tbl_bond;
+ slave_cnt = func_tbl_value & 0xfU;
+ if (slave_cnt != 0) {
+ msg_out->port = (func_tbl_value >>
+ (ROCE_BOND_FWD_ID_TBL_ALL_BITS -
+ ((rqp->tx_hash_value % slave_cnt + 1) *
+ ROCE_BOND_FWD_ID_TBL_PER_BITS))) &
+ ROCE_BOND_FWD_ID_TBL_PER_BITS_MASK;
+ }
+ read_unlock(&rdev->rwlock_func_tbl_bond);
+
+ if (slave_cnt == 0) {
+ ROCE_ERR("slave_cnt is 0");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+err_out:
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static int32_t roce5_set_new_tx_hash_value(struct roce5_device *rdev,
+ struct roce5_qp *rqp,
+ struct roce5_qp_port_in *msg_in)
+{
+ int32_t ret = 0;
+ uint32_t func_tbl_value = 0;
+ uint32_t slave_cnt = 0;
+ uint32_t target_hash_port = 0;
+ uint32_t old_hash_port = 0;
+ uint32_t new_tx_hash_value;
+
+ read_lock(&rdev->rwlock_func_tbl_bond);
+ func_tbl_value = rdev->func_tbl_bond;
+ read_unlock(&rdev->rwlock_func_tbl_bond);
+
+ slave_cnt = func_tbl_value & 0xfU;
+ if (slave_cnt == 0) {
+ ROCE_DEV_ERR(rdev, "slave_cnt is 0.");
+ return -EINVAL;
+ }
+ target_hash_port = msg_in->port & ROCE_BOND_FWD_ID_TBL_PER_BITS_MASK;
+ old_hash_port =
+ (func_tbl_value >> (ROCE_BOND_FWD_ID_TBL_ALL_BITS -
+ ((rqp->tx_hash_value % slave_cnt + 1) *
+ ROCE_BOND_FWD_ID_TBL_PER_BITS))) &
+ ROCE_BOND_FWD_ID_TBL_PER_BITS_MASK;
+
+ if (target_hash_port == old_hash_port) {
+ return 0;
+ }
+
+ new_tx_hash_value =
+ rqp->tx_hash_value +
+ (((slave_cnt - old_hash_port) + target_hash_port) % slave_cnt);
+ ret = roce5_set_hash_value(rdev, rqp->qpn, ROCE_VERBS_QP_HASH_TYPE_BOND,
+ new_tx_hash_value);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to modify QP(0x%06x) Bond hash value, func_id(%d)",
+ rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ rqp->tx_hash_value = new_tx_hash_value;
+
+ return 0;
+}
+
+int32_t roce5_genl_set_qp_tx_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out, uint16_t out_len,
+ uint16_t *out_size)
+{
+ int32_t ret = 0;
+ struct roce5_qp_port_in *msg_in = NULL;
+ struct roce5_qp *rqp = NULL;
+
+ if (in == NULL || in_len == 0 ||
+ in_len < sizeof(struct roce5_qp_port_in) || out_size == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Invalid param, in:%d, in_len:%u, out_size:%d",
+ !!in, in_len, !!out_size);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_qp_port_in *)in;
+
+ if (!roce5_bond_is_active(rdev)) {
+ return 0;
+ }
+
+ /* check qp exist */
+ rqp = roce5_get_rqp_by_qpn(rdev, msg_in->qpn);
+ if (rqp == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to look up rqp");
+ return -EINVAL;
+ }
+
+ ret = roce5_set_new_tx_hash_value(rdev, rqp, msg_in);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to set new tx hash value, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_out;
+ }
+
+err_out:
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static int roce5_uni_cmd_get_qp_rx_port(struct roce5_device *rdev, uint32_t qpn,
+ uint32_t *rx_port)
+{
+ int32_t ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_get_port_info_s *get_rx_port_inbuf = NULL;
+ roce_uni_cmd_get_port_info_outbuf_s *get_rx_port_outbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (uint16_t)sizeof(roce_uni_cmd_get_port_info_s), &cqm_cmd_outbuf,
+ (uint16_t)sizeof(roce_uni_cmd_get_port_info_outbuf_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ get_rx_port_inbuf = (roce_uni_cmd_get_port_info_s *)cqm_cmd_inbuf->buf;
+ get_rx_port_inbuf->com.index = cpu_to_be32(qpn);
+ get_rx_port_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_QP_BITMASK));
+ ret = roce5_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_GET_RX_PORT_QP,
+ cqm_cmd_inbuf, cqm_cmd_outbuf,
+ ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send ROCE_CMD_GET_RX_PORT_QP command, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -1;
+ goto out;
+ }
+ get_rx_port_outbuf =
+ (roce_uni_cmd_get_port_info_outbuf_s *)cqm_cmd_outbuf->buf;
+ *rx_port = be32_to_cpu(get_rx_port_outbuf->value.rx_port);
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+ return ret;
+}
+
+static int32_t roce5_get_qp_rx_port(struct roce5_device *rdev, uint32_t qpn,
+ uint32_t *rx_port)
+{
+ if (ROCE5_SUPPORT_GET_QP_RX_PORT_MSG_V2(rdev) != 0) {
+ return roce5_uni_cmd_get_qp_rx_port(rdev, qpn, rx_port);
+ }
+ return -EINVAL;
+}
+
+int32_t roce5_genl_query_qp_rx_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size)
+{
+ int32_t ret = 0;
+ uint32_t rx_port = 0;
+ struct roce5_qp *rqp = NULL;
+ struct roce5_qp_in *msg_in = NULL;
+ struct roce5_port_out *msg_out = NULL;
+
+ if (in == NULL || in_len == 0 || in_len < sizeof(struct roce5_qp_in) ||
+ out == NULL || out_len == 0 ||
+ out_len < sizeof(struct roce5_port_out) || out_size == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid param, in:%d, in_len:%u, out:%d, out_len:%u, out_size:%d",
+ !!in, in_len, !!out, out_len, !!out_size);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_qp_in *)in;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, msg_in->qpn);
+ if (rqp == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to look up rqp");
+ return -EINVAL;
+ }
+
+ if (rqp->qp_type != IB_QPT_RC) {
+ ROCE_DEV_ERR(rdev, "not support qp type(%d), only support RC.",
+ rqp->qp_type);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ *out_size = sizeof(struct roce5_port_out);
+ msg_out = (struct roce5_port_out *)out;
+
+ if (!roce5_bond_is_active(rdev)) {
+ msg_out->port = 0;
+ ret = 0;
+ goto err_out;
+ }
+
+ ret = roce5_get_qp_rx_port(rdev, msg_in->qpn, &rx_port);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get QP(0x%06x) rx port",
+ msg_in->qpn);
+ goto err_out;
+ }
+
+ msg_out->port = rx_port;
+
+err_out:
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+int32_t roce5_genl_query_bond_port_info(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size)
+{
+ uint32_t func_tbl_value = 0;
+ struct roce5_bond_device *bond_dev = NULL;
+ struct roce5_bond_port_info_out *msg_out = NULL;
+ uint32_t alive_port_num;
+ uint32_t i;
+
+ if (out == NULL || out_len == 0 ||
+ out_len < sizeof(struct roce5_bond_port_info_out) ||
+ out_size == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Invalid param, out:%d, out_len:%u, out_size:%d",
+ !!out, out_len, !!out_size);
+ return -EINVAL;
+ }
+
+ *out_size = sizeof(struct roce5_bond_port_info_out);
+ msg_out = (struct roce5_bond_port_info_out *)out;
+
+ if (!roce5_bond_is_active(rdev)) {
+ return 0;
+ }
+
+ bond_dev = rdev->bond_dev;
+
+ /* Read func_tbl_bond and derive alive port info under lock to prevent data race */
+ read_lock(&rdev->rwlock_func_tbl_bond);
+ func_tbl_value = rdev->func_tbl_bond;
+ alive_port_num = func_tbl_value & 0xfU;
+ for (i = 0; i < alive_port_num; i++) {
+ msg_out->alive_port[i] =
+ (func_tbl_value >>
+ (ROCE_BOND_FWD_ID_TBL_ALL_BITS -
+ ((i + 1) * ROCE_BOND_FWD_ID_TBL_PER_BITS))) &
+ ROCE_BOND_FWD_ID_TBL_PER_BITS_MASK;
+ }
+ read_unlock(&rdev->rwlock_func_tbl_bond);
+ msg_out->alive_port_num =
+ (int32_t)alive_port_num; /* netlink protocol field */
+
+ /* Read slave info under slave_lock (separate from rwlock to avoid sleeping in atomic context) */
+ msg_out->original_port_num =
+ (int32_t)bond_dev->slave_cnt; /* netlink protocol field */
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ msg_out->original_port[i] = bond_dev->slaves[i].func_id;
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+
+ return 0;
+}
+
+static int32_t roce5_uni_cmd_modify_udp_src_port(struct roce5_device *rdev,
+ uint32_t qpn,
+ uint32_t new_udp_src_port)
+{
+ int32_t ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_set_udp_src_port_s *modify_udp_src_port = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (uint16_t)sizeof(roce_uni_cmd_set_udp_src_port_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ modify_udp_src_port =
+ (roce_uni_cmd_set_udp_src_port_s *)cqm_cmd_inbuf->buf;
+ modify_udp_src_port->com.index = cpu_to_be32(qpn);
+ modify_udp_src_port->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ modify_udp_src_port->info.udp_src_port = cpu_to_be32(new_udp_src_port);
+
+ ret = roce5_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_MODIFY_UDP_SRC_PORT_QP,
+ cqm_cmd_inbuf, NULL, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send MODIFY_HASH_VALUE_QP command, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -1;
+ }
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+static int32_t roce5_modify_udp_src_port(struct roce5_device *rdev,
+ uint32_t qpn,
+ uint32_t new_udp_src_port)
+{
+ if (ROCE5_SUPPORT_MODIFY_UDP_SRC_PORT_MSG_V2(rdev) != 0) {
+ return roce5_uni_cmd_modify_udp_src_port(rdev, qpn,
+ new_udp_src_port);
+ }
+ return -EINVAL;
+}
+
+int32_t roce5_genl_set_qp_udp_src_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size)
+{
+ int32_t ret = 0;
+ struct roce5_qp *rqp = NULL;
+ struct roce5_qp_udp_src_port_in *msg_in = NULL;
+
+ if (in == NULL || in_len == 0 ||
+ in_len < sizeof(struct roce5_qp_udp_src_port_in) ||
+ out_size == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Invalid param, in:%d, in_len:%u, out_size:%d",
+ !!in, in_len, !!out_size);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_qp_udp_src_port_in *)in;
+
+ /* check qp exist */
+ rqp = roce5_get_rqp_by_qpn(rdev, msg_in->qpn);
+ if (rqp == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to look up rqp");
+ return -EINVAL;
+ }
+
+ ret = roce5_modify_udp_src_port(rdev, rqp->qpn, msg_in->udp_src_port);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to modify QP(0x%06x) hash value, func_id(%d)",
+ rqp->qpn, rdev->glb_func_id);
+ ret = -EIO;
+ goto err_out;
+ }
+
+err_out:
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static int32_t roce5_uni_cmd_get_qp_udp_src_port(struct roce5_device *rdev,
+ uint32_t qpn,
+ uint32_t *udp_src_port)
+{
+ int32_t ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_get_port_info_s *get_udp_src_port = NULL;
+ roce_uni_cmd_get_port_info_outbuf_s *get_udp_src_port_outbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (uint16_t)sizeof(roce_uni_cmd_get_port_info_outbuf_s),
+ &cqm_cmd_outbuf,
+ (uint16_t)sizeof(roce_uni_cmd_get_port_info_outbuf_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ get_udp_src_port = (roce_uni_cmd_get_port_info_s *)cqm_cmd_inbuf->buf;
+ get_udp_src_port->com.index = cpu_to_be32(qpn);
+ get_udp_src_port->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_QP_BITMASK));
+
+ ret = roce5_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_GET_UDP_SRC_PORT_QP,
+ cqm_cmd_inbuf, cqm_cmd_outbuf,
+ ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send ROCE_CMD_GET_UDP_SRC_PORT_QP command, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -1;
+ goto out;
+ }
+
+ get_udp_src_port_outbuf =
+ (roce_uni_cmd_get_port_info_outbuf_s *)cqm_cmd_outbuf->buf;
+ *udp_src_port =
+ be32_to_cpu(get_udp_src_port_outbuf->value.udp_src_port);
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+
+ return ret;
+}
+
+static int32_t roce5_get_qp_udp_src_port(struct roce5_device *rdev,
+ uint32_t qpn, uint32_t *udp_src_port)
+{
+ if (ROCE5_SUPPORT_GET_QP_UDP_SRC_PORT_MSG_V2(rdev) != 0) {
+ return roce5_uni_cmd_get_qp_udp_src_port(rdev, qpn,
+ udp_src_port);
+ }
+ return -EINVAL;
+}
+
+int32_t roce5_genl_query_qp_udp_src_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size)
+{
+ int32_t ret = 0;
+ uint32_t udp_src_port = 0;
+ struct roce5_qp_in *msg_in = NULL;
+ struct roce5_port_out *msg_out = NULL;
+
+ if (in == NULL || in_len == 0 || in_len < sizeof(struct roce5_qp_in) ||
+ out == NULL || out_len == 0 ||
+ out_len < sizeof(struct roce5_port_out) || out_size == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid param, in:%d, in_len:%u, out:%d, out_len:%u, out_size:%d",
+ !!in, in_len, !!out, out_len, !!out_size);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_qp_in *)in;
+
+ ret = roce5_get_qp_udp_src_port(rdev, msg_in->qpn, &udp_src_port);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to get QP(0x%06x) udp src port",
+ msg_in->qpn);
+ return ret;
+ }
+
+ *out_size = sizeof(struct roce5_port_out);
+ msg_out = (struct roce5_port_out *)out;
+
+ msg_out->port = udp_src_port;
+
+ return 0;
+}
+#endif
+
+int32_t roce5_genl_query_next_wqe_idx(struct roce5_device *rdev, void *in,
+ u16 in_len, void *out, u16 out_len,
+ u16 *out_size)
+{
+ int32_t ret = 0;
+ int32_t next_wqe_idx = 0;
+ uint32_t container_mode = 0;
+ uint32_t container_size = 0;
+ struct roce5_next_wqe_idx_in *msg_in = NULL;
+ struct roce5_next_wqe_idx_out *msg_out = NULL;
+ roce_verbs_srq_attr_s *srq_attr = NULL;
+
+ if (in == NULL || in_len == 0 ||
+ in_len < sizeof(struct roce5_next_wqe_idx_in) || out == NULL ||
+ out_len == 0 || out_len < sizeof(struct roce5_next_wqe_idx_out) ||
+ out_size == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid param, in:%d, in_len:%u, out:%d, out_len:%u, out_size:%d",
+ !!in, in_len, !!out, out_len, !!out_size);
+ return -EINVAL;
+ }
+
+ srq_attr = kmalloc(sizeof(roce_verbs_srq_attr_s), GFP_KERNEL);
+ if (srq_attr == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to allocate memory for dfx_query_outbuf");
+ return -ENOMEM;
+ }
+
+ msg_in = (struct roce5_next_wqe_idx_in *)in;
+ msg_out = (struct roce5_next_wqe_idx_out *)out;
+ ret = roce5_dfx_cmd_query_srq(rdev, msg_in->srqn, srq_attr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to do roce5_dfx_cmd_query_srq, ret(%d)",
+ ret);
+ ret = -EINVAL;
+ goto free_outbuf;
+ }
+
+ srq_attr->dw2.value = be32_to_cpu(srq_attr->dw2.value);
+ srq_attr->dw3.value = be32_to_cpu(srq_attr->dw3.value);
+ srq_attr->cont.dw2.value = be32_to_cpu(srq_attr->cont.dw2.value);
+ if (srq_attr->dw3.bs.container == 0) {
+ next_wqe_idx = (int32_t)(srq_attr->dw2.bs.next_wqe_idx);
+ } else {
+ container_mode = MAX_SUPPORT_CONTAINER_MODE -
+ srq_attr->cont.dw2.bs.cont_size;
+ container_size = roce5_get_container_sz(container_mode);
+ next_wqe_idx = (int32_t)(container_size *
+ srq_attr->cont.dw2.bs.head_idx);
+ }
+
+ msg_out->next_wqe_idx = next_wqe_idx;
+ *out_size = sizeof(struct roce5_next_wqe_idx_out);
+ ret = 0;
+
+free_outbuf:
+ kfree(srq_attr);
+ return ret;
+}
+
+int32_t roce5_genl_query_qpc(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out, uint16_t out_len,
+ uint16_t *out_size)
+{
+ int32_t ret = 0;
+ struct roce5_qp_in *msg_in = NULL;
+ roce_verbs_qp_attr_s *verbs_qp_attr = NULL;
+
+ if (in == NULL || in_len == 0 || in_len < sizeof(struct roce5_qp_in) ||
+ out == NULL || out_len == 0 ||
+ out_len < sizeof(roce_verbs_qp_attr_s) || out_size == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid param, in:%d, in_len:%u, out:%d, out_len:%u, out_size:%d",
+ !!in, in_len, !!out, out_len, !!out_size);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_qp_in *)in;
+ verbs_qp_attr = (roce_verbs_qp_attr_s *)out;
+
+ ret = roce5_qp_query(rdev, msg_in->qpn, (u32 *)(void *)verbs_qp_attr,
+ sizeof(roce_verbs_qp_attr_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to query qpc, ret(%0x)", ret);
+ return ret;
+ }
+
+ *out_size = sizeof(roce_verbs_qp_attr_s);
+ return 0;
+}
+
+int32_t roce5_genl_query_cqc(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out, uint16_t out_len,
+ uint16_t *out_size)
+{
+ int32_t ret = 0;
+ struct roce5_cq_in *msg_in = NULL;
+ roce_verbs_cq_attr_s *verbs_cq_attr = NULL;
+
+ if (in == NULL || in_len == 0 || in_len < sizeof(struct roce5_cq_in) ||
+ out == NULL || out_len == 0 ||
+ out_len < sizeof(roce_verbs_cq_attr_s) || out_size == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid param, in:%d, in_len:%u, out:%d, out_len:%u, out_size:%d",
+ !!in, in_len, !!out, out_len, !!out_size);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_cq_in *)in;
+ verbs_cq_attr = (roce_verbs_cq_attr_s *)out;
+
+ ret = roce5_dfx_query_cq(rdev, msg_in->cqn,
+ (u32 *)(void *)verbs_cq_attr,
+ sizeof(roce_verbs_cq_attr_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to query cqc, ret(%0x)", ret);
+ return ret;
+ }
+
+ *out_size = sizeof(roce_verbs_cq_attr_s);
+ return 0;
+}
+
+int32_t roce5_genl_qp_hash_value_process(struct roce5_device *rdev, void *in,
+ u16 in_len, void *out, u16 out_len,
+ u16 *out_size)
+{
+ uint32_t hash_value = 0;
+ struct roce5_qp_hash_value_in *msg_in = NULL;
+ struct roce5_qp_hash_value_out *msg_out = NULL;
+ int32_t ret;
+
+ if (in == NULL || in_len == 0 ||
+ in_len < sizeof(struct roce5_qp_hash_value_in)) {
+ ROCE_DEV_ERR(rdev, "Invalid input param, in:%d, in_len:%u",
+ !!in, in_len);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_qp_hash_value_in *)in;
+
+ if (msg_in->type == ROCE_QP_HASH_VALUE_GET) {
+ if (out == NULL || out_len == 0 ||
+ out_len < sizeof(struct roce5_qp_hash_value_out) ||
+ out_size == NULL) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Invalid output param, out:%d, out_len:%u, out_size:%d",
+ !!out, out_len, !!out_size);
+ return -EINVAL;
+ }
+ ret = roce5_get_hash_value(rdev, msg_in->qpn,
+ ROCE_VERBS_QP_HASH_TYPE_UBC,
+ &hash_value);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to get QP(0x%06x) hash value, func_id(%d)",
+ msg_in->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ *out_size = sizeof(struct roce5_qp_hash_value_out);
+ msg_out = (struct roce5_qp_hash_value_out *)out;
+ msg_out->hash_value = hash_value;
+ } else {
+ ret = roce5_set_hash_value(rdev, msg_in->qpn,
+ ROCE_VERBS_QP_HASH_TYPE_UBC,
+ msg_in->hash_value);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set QP(0x%06x) hash value, func_id(%d)",
+ msg_in->qpn, rdev->glb_func_id);
+ }
+ }
+
+ return ret;
+}
+
+int32_t roce5_netlink_uld_process(struct roce5_device *rdev, void *buf_in,
+ u16 buf_in_len, void *buf_out,
+ u16 buf_out_len, u16 *buf_out_size)
+{
+ int32_t ret = 0;
+ roce_user_handle_t handle;
+
+ handle.rdev = rdev;
+ handle.magic = ROCE_ULD_HANDLE_MAGIC_NUM;
+
+ ret = roce5_uld_user2kernel_msg_handle((void *)&handle, buf_in,
+ buf_in_len, buf_out, buf_out_len,
+ buf_out_size);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "ULD process err, func_id(%d)",
+ rdev->glb_func_id);
+ }
+ return ret;
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink_process.h b/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink_process.h
new file mode 100644
index 000000000..d09bcf733
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/netlink/roce_netlink_process.h
@@ -0,0 +1,133 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_NETLINK_PROCESS_H
+#define ROCE_NETLINK_PROCESS_H
+
+#include "roce.h"
+#include "roce_compat.h"
+
+typedef enum {
+ ROCE_QP_HASH_VALUE_SET,
+ ROCE_QP_HASH_VALUE_GET,
+} ROCE_QP_HASH_VALUE_PROC_TYPE;
+
+#ifdef ROCE_BONDING_EN
+/* and above next data structure is adaptation V100 use */
+struct roce5_get_rx_port {
+ __be32 rx_port;
+};
+
+struct roce5_get_udp_src_port {
+ __be32 udp_src_port;
+};
+
+typedef struct tag_roce_get_qp_rx_port {
+ roce_verbs_cmd_com_s com;
+} roce_get_qp_rx_port_s;
+
+typedef struct tag_roce_modify_hash_value {
+ roce_verbs_cmd_com_s com;
+ u32 hash_value;
+} roce_modify_hash_value_s;
+
+typedef struct tag_roce_modify_udp_src_port {
+ roce_verbs_cmd_com_s com;
+ u32 udp_src_port;
+} roce_modify_udp_src_port_s;
+
+typedef struct roce_get_qp_udp_src_port {
+ roce_verbs_cmd_com_s com;
+} roce_get_qp_udp_src_port_s;
+
+struct roce5_qp_port_in {
+ uint32_t qpn;
+ uint32_t port;
+};
+
+struct roce5_port_out {
+ uint32_t port;
+};
+
+struct roce5_bond_port_info_out {
+ int32_t original_port_num;
+ uint8_t original_port[8];
+ int32_t rsvd1;
+
+ int32_t alive_port_num;
+ uint8_t alive_port[8];
+ int32_t rsvd2;
+};
+
+struct roce5_qp_udp_src_port_in {
+ uint32_t qpn;
+ uint32_t udp_src_port;
+};
+
+#endif
+
+struct roce5_qp_in {
+ uint32_t qpn;
+};
+
+struct roce5_cq_in {
+ uint32_t cqn;
+};
+
+struct roce5_next_wqe_idx_in {
+ uint32_t srqn;
+};
+
+struct roce5_next_wqe_idx_out {
+ int32_t next_wqe_idx;
+};
+
+struct roce5_qp_hash_value_in {
+ uint32_t type;
+ uint32_t qpn;
+ uint32_t hash_value;
+};
+
+struct roce5_qp_hash_value_out {
+ uint32_t hash_value;
+};
+
+#ifdef ROCE_BONDING_EN
+
+int32_t roce5_genl_query_qp_tx_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size);
+int32_t roce5_genl_set_qp_tx_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out, uint16_t out_len,
+ uint16_t *out_size);
+int32_t roce5_genl_query_qp_rx_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size);
+int32_t roce5_genl_query_bond_port_info(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size);
+int32_t roce5_genl_set_qp_udp_src_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size);
+int32_t roce5_genl_query_qp_udp_src_port(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size);
+
+#endif
+
+int32_t roce5_genl_query_next_wqe_idx(struct roce5_device *rdev, void *in,
+ u16 in_len, void *out, u16 out_len,
+ u16 *out_size);
+int32_t roce5_genl_query_qpc(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out, uint16_t out_len,
+ uint16_t *out_size);
+int32_t roce5_genl_query_cqc(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out, uint16_t out_len,
+ uint16_t *out_size);
+int32_t roce5_genl_qp_hash_value_process(struct roce5_device *rdev, void *in,
+ u16 in_len, void *out, u16 out_len,
+ u16 *out_size);
+int32_t roce5_netlink_uld_process(struct roce5_device *rdev, void *buf_in,
+ u16 buf_in_len, void *buf_out,
+ u16 buf_out_len, u16 *buf_out_size);
+#endif /* ROCE_NETLINK_PROCESS_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.c b/drivers/infiniband/hw/hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.c
new file mode 100644
index 000000000..69549fbe3
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.c
@@ -0,0 +1,74 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include "securec.h"
+
+#include "roce_cqm_cmd.h"
+
+void roce5_cqm5_cmd_free_inoutbuf(void *ex_handle, cqm_cmd_buf_s *cqm_cmd_inbuf,
+ cqm_cmd_buf_s *cqm_cmd_outbuf)
+{
+ if (cqm_cmd_outbuf != NULL) {
+ cqm5_cmd_free(ex_handle, cqm_cmd_outbuf);
+ }
+
+ if (cqm_cmd_inbuf != NULL) {
+ cqm5_cmd_free(ex_handle, cqm_cmd_inbuf);
+ }
+}
+
+int roce5_cqm_cmd_zalloc_inoutbuf(void *ex_handle,
+ cqm_cmd_buf_s **cqm_cmd_inbuf, u16 inbuf_size,
+ cqm_cmd_buf_s **cqm_cmd_outbuf,
+ u16 outbuf_size)
+{
+ int ret;
+
+ if (cqm_cmd_inbuf != NULL) {
+ *cqm_cmd_inbuf = cqm5_cmd_alloc(ex_handle);
+
+ if (*cqm_cmd_inbuf == NULL) {
+ ret = -ENOMEM;
+ goto inbuf_err;
+ }
+ (*cqm_cmd_inbuf)->size = inbuf_size;
+
+ ret = memset_s((*cqm_cmd_inbuf)->buf, inbuf_size, 0,
+ inbuf_size);
+ if (ret != 0) {
+ ret = -EINVAL;
+ goto inbuf_err;
+ }
+ }
+
+ if (cqm_cmd_outbuf != NULL) {
+ *cqm_cmd_outbuf = cqm5_cmd_alloc(ex_handle);
+
+ if (*cqm_cmd_outbuf == NULL) {
+ ret = -ENOMEM;
+ goto outbuf_err;
+ }
+ (*cqm_cmd_outbuf)->size = outbuf_size;
+
+ ret = memset_s((*cqm_cmd_outbuf)->buf, outbuf_size, 0,
+ outbuf_size);
+ if (ret != 0) {
+ ret = -EINVAL;
+ goto outbuf_err;
+ }
+ }
+
+ return 0;
+outbuf_err:
+ if (cqm_cmd_outbuf != NULL) {
+ roce5_cqm5_cmd_free_inoutbuf(ex_handle, NULL, *cqm_cmd_outbuf);
+ *cqm_cmd_outbuf = NULL;
+ }
+inbuf_err:
+ if (cqm_cmd_inbuf != NULL) {
+ roce5_cqm5_cmd_free_inoutbuf(ex_handle, *cqm_cmd_inbuf, NULL);
+ *cqm_cmd_inbuf = NULL;
+ }
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.h b/drivers/infiniband/hw/hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.h
new file mode 100644
index 000000000..0130fa320
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/sdk_api/roce_cqm_cmd.h
@@ -0,0 +1,21 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_CQM_CMD_H
+#define ROCE_CQM_CMD_H
+#ifdef ROCE_KNL_DT
+#include <linux/compiler_types.h>
+#endif
+#include "hinic5_cqm.h"
+
+#include "roce.h"
+
+void roce5_cqm5_cmd_free_inoutbuf(void *ex_handle, cqm_cmd_buf_s *cqm_cmd_inbuf,
+ cqm_cmd_buf_s *cqm_cmd_outbuf);
+int roce5_cqm_cmd_zalloc_inoutbuf(void *ex_handle,
+ cqm_cmd_buf_s **cqm_cmd_inbuf, u16 inbuf_size,
+ cqm_cmd_buf_s **cqm_cmd_outbuf,
+ u16 outbuf_size);
+
+#endif //ROCE_CQM_CMD_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_multipath_sysfs.c b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_multipath_sysfs.c
new file mode 100644
index 000000000..3000c6b97
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_multipath_sysfs.c
@@ -0,0 +1,240 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
+
+#include "roce.h"
+#include "roce_sysfs.h"
+#include "roce_cc_format.h"
+
+#include "roce_cmd.h"
+#include "roce_multipath_sysfs.h"
+
+#define MAX_STRING_FORMAT_LEN 64
+#define to_roce5_ecn_multipath_ctx(_kobj) \
+ container_of(_kobj, struct roce5_ecn_multipath_ctx, ecn_multipath_root)
+
+static void roce_ecn_multipath_sysfs_release(struct kobject *kobj)
+{
+}
+
+static ssize_t roce5_show_slow_path_psn_threshold(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct roce5_ecn_multipath_ctx *ecn_multipath_ctx =
+ to_roce5_ecn_multipath_ctx(kobj);
+
+ if ((attr == NULL) || (buf == NULL)) {
+ ROCE_ERR("attr or buf is null");
+ return -EINVAL;
+ }
+
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%u\n",
+ (u32)ecn_multipath_ctx->slow_path_psn_threshold);
+}
+
+static ssize_t roce5_store_slow_path_psn_threshold(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_multipath_ctx *ecn_multipath_ctx =
+ to_roce5_ecn_multipath_ctx(kobj);
+ u32 old_slow_path_psn_threshold = 0;
+ int slow_path_psn_threshold = 0;
+ int ret;
+ char remaining;
+
+ if ((attr == NULL) || (buf == NULL)) {
+ ROCE_ERR("attr or buf is null");
+ return -EINVAL;
+ }
+
+ ret = sscanf_s(buf, "%d %c", &slow_path_psn_threshold, &remaining, 1);
+ if (ret != 1) {
+ ROCE_ERR(
+ "Invalid input, slow_path_psn_threshold should be unsigned int\n");
+ return -EIO;
+ }
+
+ if (slow_path_psn_threshold >
+ ROCE_MULTIPATH_DEFAULT_SLOW_PATH_PSN_THRESHOLD_MAX) {
+ ROCE_ERR(
+ "Invalid input, slow_path_psn_threshold(%d) over max slow_path_psn_threshold(%u), slow_path_psn_threshold",
+ slow_path_psn_threshold,
+ (u32)ROCE_MULTIPATH_DEFAULT_SLOW_PATH_PSN_THRESHOLD_MAX);
+ return -EIO;
+ }
+
+ if (ecn_multipath_ctx->slow_path_psn_threshold !=
+ (u32)slow_path_psn_threshold) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_slow_path_psn_threshold =
+ ecn_multipath_ctx->slow_path_psn_threshold;
+ ecn_multipath_ctx->slow_path_psn_threshold =
+ (u32)slow_path_psn_threshold;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Fail to update slow_path_psn_threshold(%d), ret(%d).",
+ slow_path_psn_threshold, ret);
+ ecn_multipath_ctx->slow_path_psn_threshold =
+ old_slow_path_psn_threshold;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce5_show_rtt_req_event_mode(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct roce5_ecn_multipath_ctx *ecn_multipath_ctx =
+ to_roce5_ecn_multipath_ctx(kobj);
+
+ if ((attr == NULL) || (buf == NULL)) {
+ ROCE_ERR("attr or buf is null");
+ return -EINVAL;
+ }
+
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)ecn_multipath_ctx->rtt_req_event_mode);
+}
+
+static ssize_t roce5_store_rtt_req_event_mode(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ u32 old_rtt_req_event_mode = 0;
+ u32 rtt_req_event_mode = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_multipath_ctx *ecn_multipath_ctx =
+ to_roce5_ecn_multipath_ctx(kobj);
+ char remaining;
+
+ if ((attr == NULL) || (buf == NULL)) {
+ ROCE_ERR("attr or buf is null");
+ return -EINVAL;
+ }
+
+ ret = sscanf_s(buf, "%u %c", &rtt_req_event_mode, &remaining, 1);
+ if (ret != 1) {
+ ROCE_ERR(
+ "Invalid input, rtt_req_event_mode should be unsigned int ret(%d), rtt_req_event_mode(%u)\n",
+ ret, rtt_req_event_mode);
+ return -EIO;
+ }
+
+ if ((rtt_req_event_mode & ROCE_MULTIPATH_RTT_EN_MASK) != 0) {
+ ROCE_ERR(
+ "Invalid input, rtt_req_event_mode (%u)only 0 and 1 supported\n",
+ rtt_req_event_mode);
+ return -EIO;
+ }
+
+ if (ecn_multipath_ctx->rtt_req_event_mode != (u32)rtt_req_event_mode) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_rtt_req_event_mode = ecn_multipath_ctx->rtt_req_event_mode;
+ ecn_multipath_ctx->rtt_req_event_mode = (u32)rtt_req_event_mode;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Fail to update rtt_req_event_mode(%d), ret(%d).",
+ rtt_req_event_mode, ret);
+ ecn_multipath_ctx->rtt_req_event_mode =
+ old_rtt_req_event_mode;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+ROCE_ATTR_RW(slow_path_psn_threshold, roce5_show_slow_path_psn_threshold,
+ roce5_store_slow_path_psn_threshold);
+ROCE_ATTR_RW(rtt_req_event_mode, roce5_show_rtt_req_event_mode,
+ roce5_store_rtt_req_event_mode);
+
+static struct attribute *ecn_multipath_ctx_attrs[] = {
+ ROCE_ATTR_PTR(rtt_req_event_mode),
+ ROCE_ATTR_PTR(slow_path_psn_threshold),
+ NULL,
+};
+
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+static const struct attribute_group ecn_multipath_ctx_attr_grp = {
+ .attrs = ecn_multipath_ctx_attrs,
+};
+
+static const struct attribute_group *ecn_multipath_ctx_groups[] = {
+ &ecn_multipath_ctx_attr_grp,
+ NULL,
+};
+#endif
+
+static struct kobj_type roce_ecn_multipath_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .release = roce_ecn_multipath_sysfs_release,
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+ .default_groups = ecn_multipath_ctx_groups,
+#else
+ .default_attrs = ecn_multipath_ctx_attrs,
+#endif
+};
+
+int roce5_init_ecn_multipath_sysfs(
+ struct roce5_device *rdev, struct kobject *kobj,
+ struct roce5_ecn_multipath_ctx *ecn_multipath_ctx)
+{
+ int ret = 0;
+
+ if (rdev->device_type != ROCE_DEV_TYPE_HI1825_V100) {
+ return 0;
+ }
+ if (ecn_multipath_ctx == NULL) {
+ pr_err_ratelimited(
+ "[ROCE, ERR] %s: ecn_multipath_ctx is null\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ ecn_multipath_ctx->rtt_req_event_mode =
+ ROCE_MULTIPATH_DEFAULT_RTT_EVENT_MODE;
+ ecn_multipath_ctx->slow_path_psn_threshold =
+ ROCE_MULTIPATH_DEFAULT_SLOW_PATH_PSN_THRESHOLD;
+
+ ret = kobject_init_and_add(&ecn_multipath_ctx->ecn_multipath_root,
+ &roce_ecn_multipath_ktype, kobj,
+ "roce5_multipath");
+ if (ret != 0) {
+ ROCE_ERR("Failed to add kobject roce5_ultipath.(ret:%d)\n",
+ ret);
+ kobject_put(&ecn_multipath_ctx->ecn_multipath_root);
+ return ret;
+ }
+
+ return 0;
+}
+
+void roce5_remove_ecn_multipath_sysfs(
+ struct roce5_device *rdev, struct kobject *kobj,
+ struct roce5_ecn_multipath_ctx *ecn_multipath_ctx)
+{
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ if (ecn_multipath_ctx == NULL) {
+ ROCE_ERR("ecn_multipath_ctx is null\n");
+ return;
+ }
+
+ kobject_put(&ecn_multipath_ctx->ecn_multipath_root);
+ }
+
+ return;
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_multipath_sysfs.h b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_multipath_sysfs.h
new file mode 100644
index 000000000..2a26de8e2
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_multipath_sysfs.h
@@ -0,0 +1,30 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
+
+
+#ifndef ROCE_MULTIPATH_SYSFS_H
+#define ROCE_MULTIPATH_SYSFS_H
+
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/kobject.h>
+
+struct roce5_device;
+
+#define ROCE_MULTIPATH_DEFAULT_RTT_EVENT_MODE 0
+#define ROCE_MULTIPATH_RTT_EN_MASK 0xfffffffe
+#define ROCE_MULTIPATH_DEFAULT_SLOW_PATH_PSN_THRESHOLD 1
+#define ROCE_MULTIPATH_DEFAULT_SLOW_PATH_PSN_THRESHOLD_MAX 255
+
+struct roce5_ecn_multipath_ctx {
+ struct kobject ecn_multipath_root;
+ u32 slow_path_psn_threshold;
+ u32 rtt_req_event_mode;
+};
+int roce5_init_ecn_multipath_sysfs(
+ struct roce5_device *rdev, struct kobject *kobj,
+ struct roce5_ecn_multipath_ctx *ecn_multipath_ctx);
+void roce5_remove_ecn_multipath_sysfs(
+ struct roce5_device *rdev, struct kobject *kobj,
+ struct roce5_ecn_multipath_ctx *ecn_multipath_ctx);
+#endif /* ROCE_MULTIPATH_SYSFS_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_sysfs.c b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_sysfs.c
new file mode 100644
index 000000000..869a97571
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_sysfs.c
@@ -0,0 +1,2157 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include <linux/types.h>
+#include <linux/stat.h>
+
+#include "roce.h"
+#include "ccp_algo_format.h"
+#include "hinic5_hw.h"
+#include "roce_cc_format.h"
+#include "roce_cmd.h"
+#include "roce_com.h"
+#include "roce_dfx.h"
+#include "roce_infra.h"
+#include "roce_kernel_compat_gen.h"
+#include "roce_mix.h"
+#include "roce_mpu_cmd.h"
+#include "roce_multipath_sysfs.h"
+#include "roce_npu_cmd_srq_defs.h"
+#include "roce_qp.h"
+#include "roce_ucc_sysfs.h"
+#include "securec.h"
+#include "roce_sysfs.h"
+
+#define MAX_STRING_FORMAT_LEN 64
+
+/* generic macro template: generate show/store function, used for rp_ctx parameters (with range check) */
+#define ROCE5_PARAM_SHOW_STORE_RP(_name, _member, _min_macro, _max_macro) \
+ static ssize_t roce5_show_##_name( \
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+ { \
+ struct roce5_ecn_rp_ctx *ecn_rp_ctx = \
+ to_roce5_ecn_rp_ctx(kobj); \
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n", \
+ (int)ecn_rp_ctx->_member); \
+ } \
+ static ssize_t roce5_store_##_name(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ int ret, _val; \
+ u32 _old; \
+ struct roce5_ecn_ctx *ecn_ctx = \
+ to_roce5_ecn_ctx(kobj->parent); \
+ struct roce5_ecn_rp_ctx *ecn_rp_ctx = \
+ to_roce5_ecn_rp_ctx(kobj); \
+ struct roce5_device *rdev = \
+ container_of(ecn_ctx, struct roce5_device, ecn_ctx); \
+ ret = sscanf_s(buf, "%d", &_val); \
+ if (ret != 1) \
+ return -EIO; \
+ if (ROCE5_PARAM_CHECK_BOUND( \
+ _val, \
+ g_roce_cc_ecn_param[rdev->cc_param_version] \
+ ._min_macro, \
+ g_roce_cc_ecn_param[rdev->cc_param_version] \
+ ._max_macro)) \
+ return -EIO; \
+ if (ecn_rp_ctx->_member != (u32)_val) { \
+ mutex_lock(&ecn_ctx->ecn_mutex); \
+ _old = ecn_rp_ctx->_member; \
+ ecn_rp_ctx->_member = (u32)_val; \
+ ret = roce5_update_ecn_param(ecn_ctx); \
+ if (ret != 0) { \
+ ecn_rp_ctx->_member = _old; \
+ mutex_unlock(&ecn_ctx->ecn_mutex); \
+ return -EIO; \
+ } \
+ mutex_unlock(&ecn_ctx->ecn_mutex); \
+ } \
+ return (ssize_t)count; \
+ }
+
+/* generic macro template: generate show/store function, used for np_ctx parameters (with range check) */
+#define ROCE5_PARAM_SHOW_STORE_NP(_name, _member, _min_macro, _max_macro) \
+ static ssize_t roce5_show_##_name( \
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+ { \
+ struct roce5_ecn_np_ctx *ecn_np_ctx = \
+ to_roce5_ecn_np_ctx(kobj); \
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n", \
+ (int)ecn_np_ctx->_member); \
+ } \
+ static ssize_t roce5_store_##_name(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ int ret, _val; \
+ u32 _old; \
+ struct roce5_ecn_ctx *ecn_ctx = \
+ to_roce5_ecn_ctx(kobj->parent); \
+ struct roce5_ecn_np_ctx *ecn_np_ctx = \
+ to_roce5_ecn_np_ctx(kobj); \
+ struct roce5_device *rdev = \
+ container_of(ecn_ctx, struct roce5_device, ecn_ctx); \
+ ret = sscanf_s(buf, "%d", &_val); \
+ if (ret != 1) \
+ return -EIO; \
+ if (ROCE5_PARAM_CHECK_BOUND( \
+ _val, \
+ g_roce_cc_ecn_param[rdev->cc_param_version] \
+ ._min_macro, \
+ g_roce_cc_ecn_param[rdev->cc_param_version] \
+ ._max_macro)) \
+ return -EIO; \
+ if (ecn_np_ctx->_member != (u32)_val) { \
+ mutex_lock(&ecn_ctx->ecn_mutex); \
+ _old = ecn_np_ctx->_member; \
+ ecn_np_ctx->_member = (u32)_val; \
+ ret = roce5_update_ecn_param(ecn_ctx); \
+ if (ret != 0) { \
+ ecn_np_ctx->_member = _old; \
+ mutex_unlock(&ecn_ctx->ecn_mutex); \
+ return -EIO; \
+ } \
+ mutex_unlock(&ecn_ctx->ecn_mutex); \
+ } \
+ return (ssize_t)count; \
+ }
+
+/* generic macro template: generate show/store function, used for ldcp_ctx parameters (with range check) */
+#define ROCE5_PARAM_SHOW_STORE_LDCP(_name, _member, _min_macro, _max_macro) \
+ static ssize_t roce5_show_##_name( \
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+ { \
+ struct roce5_ecn_ldcp_ctx *ecn_ldcp_ctx = \
+ to_roce5_ecn_ldcp_ctx(kobj); \
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n", \
+ (int)ecn_ldcp_ctx->_member); \
+ } \
+ static ssize_t roce5_store_##_name(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ int ret, _val; \
+ u32 _old; \
+ struct roce5_ecn_ctx *ecn_ctx = \
+ to_roce5_ecn_ctx(kobj->parent); \
+ struct roce5_ecn_ldcp_ctx *ecn_ldcp_ctx = \
+ to_roce5_ecn_ldcp_ctx(kobj); \
+ struct roce5_device *rdev = \
+ container_of(ecn_ctx, struct roce5_device, ecn_ctx); \
+ ret = sscanf_s(buf, "%d", &_val); \
+ if (ret != 1) { \
+ ROCE_ERR("Failed to get " #_member ", ret(%d).", ret); \
+ return -EIO; \
+ } \
+ if (ROCE5_PARAM_CHECK_BOUND( \
+ _val, \
+ g_roce_cc_ecn_param[rdev->cc_param_version] \
+ ._min_macro, \
+ g_roce_cc_ecn_param[rdev->cc_param_version] \
+ ._max_macro)) { \
+ ROCE_ERR(#_member "(%u) param is out bound.", _val); \
+ return -EIO; \
+ } \
+ if (ecn_ldcp_ctx->_member != (u32)_val) { \
+ mutex_lock(&ecn_ctx->ecn_mutex); \
+ _old = ecn_ldcp_ctx->_member; \
+ ecn_ldcp_ctx->_member = (u32)_val; \
+ ret = roce5_update_ecn_param(ecn_ctx); \
+ if (ret != 0) { \
+ ecn_ldcp_ctx->_member = _old; \
+ mutex_unlock(&ecn_ctx->ecn_mutex); \
+ return -EIO; \
+ } \
+ mutex_unlock(&ecn_ctx->ecn_mutex); \
+ } \
+ return (ssize_t)count; \
+ }
+
+const struct roce_cc_ecn_param g_roce_cc_ecn_param[] = {
+ { 0 }, // invalid
+ { .default_ip_enable_en = 1,
+ .default_bypass = 0,
+ .default_min_cnp_period = 16,
+ .default_alpha_dec_period = 160,
+ .default_rate_dec_period = 32,
+ .default_rate_inc_period = 480,
+ .default_factor_gita = 7,
+ .default_initial_alpha = 1023,
+ .default_rate_inc_ai = 2,
+ .default_rate_inc_hai = 8,
+ .default_rate_first_set = 1024,
+ .default_rate_target_clamp = 1,
+ .default_cnp_prio_enable = 0,
+ .default_cnp_prio = 0,
+ .default_token_period = 16,
+ .default_min_rate = 1,
+ .default_ecn_cnp_enable = 1,
+ .default_flow_ctrl_unit = 0,
+ .default_rtt_rsp_prio = 0,
+ .default_rtt_rsp_prio_enable = 0,
+ .default_rtt_version = 0,
+ .max_rtt_version = 0,
+ .min_bypass = 0,
+ .max_bypass = 0,
+ .min_rate_inc_hai = 1,
+ .max_rate_inc_hai = 255,
+ .min_rate_inc_ai = 1,
+ .max_rate_inc_ai = 63,
+ .min_initial_alpha = 1,
+ .max_initial_alpha = 1023,
+ .min_rate_inc_period = 1,
+ .max_rate_inc_period = 1023,
+ .min_alpha_dec_period = 1,
+ .max_alpha_dec_period = 1023,
+ .min_token_period = 4,
+ .max_token_period = 255,
+ .min_flow_min_rate = 1,
+ .max_flow_min_rate = 63,
+ .min_rate_dec_period = 1,
+ .max_rate_dec_period = 255,
+ .min_min_cnp_period = 1,
+ .max_min_cnp_period = 255,
+ .min_factor_gita = 1,
+ .max_factor_gita = 15,
+ .min_rate_first_set = 128,
+ .max_rate_first_set = 8191,
+ .default_ldcp_wnd_min = 5,
+ .default_ldcp_wnd_default = 1024,
+ .default_ldcp_alpha = 2,
+ .default_ldcp_beta = 12,
+ .default_ldcp_gamma = 9,
+ .default_ldcp_eta = 3,
+ .min_ldcp_wnd_min = 1,
+ .max_ldcp_wnd_min = 0x8,
+ .min_ldcp_wnd_default = 1024,
+ .max_ldcp_wnd_default = 32768,
+ .min_ldcp_alpha = 0,
+ .max_ldcp_alpha = 0xf,
+ .min_ldcp_beta = 0,
+ .max_ldcp_beta = 0xf,
+ .min_ldcp_gamma = 0,
+ .max_ldcp_gamma = 0xf,
+ .min_ldcp_eta = 0,
+ .max_ldcp_eta = 0xf }, // v1
+ { .default_ip_enable_en = 1,
+ .default_bypass = 0,
+ .default_min_cnp_period = 16,
+ .default_alpha_dec_period = 160,
+ .default_rate_dec_period = 48,
+ .default_rate_inc_period = 480,
+ .default_factor_gita = 7,
+ .default_initial_alpha = 1023,
+ .default_rate_inc_ai = 2,
+ .default_rate_inc_hai = 12,
+ .default_rate_first_set = 1024,
+ .default_rate_target_clamp = 1,
+ .default_cnp_prio_enable = 0,
+ .default_cnp_prio = 0,
+ .default_token_period = 16,
+ .default_min_rate = 1,
+ .default_ecn_cnp_enable = 1,
+ .default_flow_ctrl_unit = 0,
+ .default_rtt_rsp_prio = 0,
+ .default_rtt_rsp_prio_enable = 0,
+ .default_rtt_version = 0,
+ .max_rtt_version = 0,
+ .min_bypass = 0,
+ .max_bypass = 2,
+ .min_rate_inc_hai = 1,
+ .max_rate_inc_hai = 255,
+ .min_rate_inc_ai = 1,
+ .max_rate_inc_ai = 255,
+ .min_initial_alpha = 1,
+ .max_initial_alpha = 1023,
+ .min_rate_inc_period = 1,
+ .max_rate_inc_period = 1023,
+ .min_alpha_dec_period = 1,
+ .max_alpha_dec_period = 1023,
+ .min_token_period = 4,
+ .max_token_period = 255,
+ .min_flow_min_rate = 1,
+ .max_flow_min_rate = 4095,
+ .min_rate_dec_period = 1,
+ .max_rate_dec_period = 255,
+ .min_min_cnp_period = 1,
+ .max_min_cnp_period = 255,
+ .min_factor_gita = 1,
+ .max_factor_gita = 15,
+ .min_rate_first_set = 128,
+ .max_rate_first_set = 50000,
+ .default_ldcp_wnd_min = 5,
+ .default_ldcp_wnd_default = 1024,
+ .default_ldcp_alpha = 2,
+ .default_ldcp_beta = 9,
+ .default_ldcp_gamma = 6,
+ .default_ldcp_eta = 6,
+ .min_ldcp_wnd_min = 1,
+ .max_ldcp_wnd_min = 0x8,
+ .min_ldcp_wnd_default = 1024,
+ .max_ldcp_wnd_default = 32768,
+ .min_ldcp_alpha = 0,
+ .max_ldcp_alpha = 0xf,
+ .min_ldcp_beta = 0,
+ .max_ldcp_beta = 0xf,
+ .min_ldcp_gamma = 0,
+ .max_ldcp_gamma = 0xf,
+ .min_ldcp_eta = 0,
+ .max_ldcp_eta = 0xf }, // v2
+};
+
+static int roce5_update_ver_check(struct roce5_device *rdev, u32 cc_algo)
+{
+ u32 algo_bitmap = 0;
+ /* driver intercept not support algorithm. 1823V200 only supports LDCP algorithm, 1825V100 current only supports DCQCN, IPQCN, user custom A & B algorithm */
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ algo_bitmap = BIT(ROCE_CC_DISABLE);
+ if (ROCE5_SUPPORT_CC_GET_DCQCN_ENABLE(rdev) != 0) {
+ algo_bitmap |= BIT(ROCE_CC_DCQCN_ALGO);
+ }
+ if (ROCE5_SUPPORT_CC_GET_LDCP_ENABLE(rdev) != 0) {
+ algo_bitmap |= BIT(ROCE_CC_LDCP_ALGO);
+ }
+ if (ROCE5_SUPPORT_CC_GET_IPQCN_ENABLE(rdev) != 0) {
+ algo_bitmap |= BIT(ROCE_CC_IPQCN_ALGO);
+ }
+ if (ROCE5_SUPPORT_CC_GET_USER_ALGO_ENABLE(rdev) != 0) {
+ algo_bitmap |= BIT(ROCE_CC_USER_A_ALGO);
+ algo_bitmap |= BIT(ROCE_CC_USER_B_ALGO);
+ }
+ }
+
+ if (ROCE_CC_ALGO_TEST_BIT(algo_bitmap, cc_algo) == 0) {
+ ROCE_DEV_ERR(rdev, "func_id(0x%x), cc algo(0x%x) not support!",
+ rdev->glb_func_id, cc_algo);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int roce5_update_cfg_cc_param(struct roce5_device *rdev,
+ const struct roce5_ecn_ctx *ecn_ctx)
+{
+ roce_cc_param_s cc_param;
+ int ret;
+
+ ret = roce5_update_ver_check(rdev, ecn_ctx->cc_algo);
+ if (ret != 0) {
+ return ret;
+ }
+
+ (void)memset_s(&cc_param, sizeof(cc_param), 0, sizeof(cc_param));
+
+ cc_param.dw0.bs.bypass = ecn_ctx->rp_ctx.bypass;
+ cc_param.dw0.bs.rtt_rsp_prio = ecn_ctx->np_ctx.rtt_rsp_prio;
+ cc_param.dw0.bs.rtt_rsp_prio_enable =
+ ecn_ctx->np_ctx.rtt_rsp_prio_enable;
+ cc_param.dw0.bs.rtt_version = ecn_ctx->np_ctx.rtt_version;
+ cc_param.dw0.bs.ecn_cnp_en = ecn_ctx->np_ctx.ecn_cnp_en;
+ cc_param.dw0.bs.min_cnp_period = ecn_ctx->np_ctx.min_cnp_period;
+ cc_param.dw0.bs.cnp_prio_enable = ecn_ctx->np_ctx.cnp_prio_enable;
+ cc_param.dw0.bs.slow_path_psn_threshold =
+ ecn_ctx->multipath_ctx.slow_path_psn_threshold;
+ cc_param.dw0.bs.rtt_req_event_mode =
+ ecn_ctx->multipath_ctx.rtt_req_event_mode;
+ cc_param.dw1.bs.cnp_prio = ecn_ctx->np_ctx.cnp_prio;
+ cc_param.dw1.bs.cnp_cos =
+ roce5_get_db_cos_from_vlan_pri(rdev, cc_param.dw1.bs.cnp_prio);
+ cc_param.dw1.bs.cc_appid = ecn_ctx->cc_algo;
+
+ if (cc_param.dw1.bs.cc_appid == ROCE_CC_LDCP_ALGO) {
+ cc_param.dw0.bs.algo_mode = CCP_ALGO_MODE_CWND;
+ } else if (cc_param.dw1.bs.cc_appid == ROCE_CC_DCQCN_ALGO ||
+ cc_param.dw1.bs.cc_appid == ROCE_CC_IPQCN_ALGO) {
+ cc_param.dw0.bs.algo_mode = CCP_ALGO_MODE_RATE;
+ } else {
+ cc_param.dw0.bs.algo_mode = ecn_ctx->ucc_ctx.algo_mode;
+ }
+
+ if (cc_param.dw0.bs.algo_mode == CCP_ALGO_MODE_CWND) {
+ cc_param.dw0.bs.flow_ctrl_unit = FLOW_CTRL_UNIT_QP;
+ } else {
+ cc_param.dw0.bs.flow_ctrl_unit = ecn_ctx->np_ctx.flow_ctrl_unit;
+ }
+
+ ROCE_DEV_INFO(rdev, "set cc_appid(%u), func_id(%u).",
+ cc_param.dw1.bs.cc_appid, rdev->glb_func_id);
+
+ ret = roce5_set_sysfs_cfg_param(rdev->hwdev, rdev->glb_func_id,
+ (u32 *)&cc_param,
+ sizeof(roce_cc_param_s),
+ (u16)ROCE_MPU_CMD_CC_CFG_CC_PARAM);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to set cc param, func_id(%d) ret(%d)",
+ rdev->glb_func_id, ret);
+ }
+
+ return ret;
+}
+
+static int roce5_update_dcqcn_param(struct roce5_device *rdev,
+ const struct roce5_ecn_ctx *ecn_ctx)
+{
+ ccp_dcqcn_para_s dcqcn_param;
+ int ret;
+
+ if (ecn_ctx->cc_algo != ROCE_CC_DCQCN_ALGO) {
+ ROCE_DEV_INFO(
+ rdev,
+ "func_id(%d) cc_algo(%u) is not dcqcn, ignore update.",
+ rdev->glb_func_id, ecn_ctx->cc_algo);
+ return 0;
+ }
+
+ (void)memset_s(&dcqcn_param, sizeof(dcqcn_param), 0,
+ sizeof(dcqcn_param));
+
+ dcqcn_param.dw0.bs.token_period = ecn_ctx->rp_ctx.token_period;
+ dcqcn_param.dw0.bs.min_rate = ecn_ctx->rp_ctx.min_rate;
+ dcqcn_param.dw1.bs.rate_inc_period = ecn_ctx->rp_ctx.rate_inc_period;
+ dcqcn_param.dw1.bs.alpha_dec_period = ecn_ctx->rp_ctx.alpha_dec_period;
+ dcqcn_param.dw2.bs.rate_inc_ai = ecn_ctx->rp_ctx.rate_inc_ai;
+ dcqcn_param.dw2.bs.rate_inc_hai = ecn_ctx->rp_ctx.rate_inc_hai;
+ dcqcn_param.dw2.bs.rate_dec_period = ecn_ctx->rp_ctx.rate_dec_period;
+ dcqcn_param.dw2.bs.min_cnp_period = ecn_ctx->np_ctx.min_cnp_period;
+ dcqcn_param.dw3.bs.gita_shift = ecn_ctx->rp_ctx.factor_gita;
+ dcqcn_param.dw3.bs.rate_target_clamp =
+ ecn_ctx->rp_ctx.rate_target_clamp;
+ dcqcn_param.dw3.bs.initial_alpha = ecn_ctx->rp_ctx.initial_alpha;
+ // adjust_en
+ dcqcn_param.dw3.bs.rate_first_set = ecn_ctx->rp_ctx.rate_first_set;
+
+ ret = roce5_set_sysfs_cfg_param(rdev->hwdev, rdev->glb_func_id,
+ (u32 *)(void *)&dcqcn_param,
+ sizeof(ccp_dcqcn_para_s),
+ (u16)ROCE_MPU_CMD_CC_CFG_DCQCN_PARAM);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to set dcqcn param, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ }
+
+ return ret;
+}
+
+static int roce5_update_ldcp_param(struct roce5_device *rdev,
+ const struct roce5_ecn_ctx *ecn_ctx)
+{
+ roce_ldcp_param_s ldcp_param;
+ int ret;
+
+ if (ecn_ctx->cc_algo != ROCE_CC_LDCP_ALGO) {
+ ROCE_DEV_INFO(
+ rdev,
+ "func_id(%d) cc_algo(%u) is not ldcp, ignore update.",
+ rdev->glb_func_id, ecn_ctx->cc_algo);
+ return 0;
+ }
+
+ ROCE_DEV_INFO(
+ rdev,
+ "update ldcp param, func_id(%d), alpha(%u), beta(%u), gamma(%u), eta(%u) wnd_min(%u) wnd_default(%u)",
+ rdev->glb_func_id, ecn_ctx->ldcp_ctx.alpha,
+ ecn_ctx->ldcp_ctx.beta, ecn_ctx->ldcp_ctx.gamma,
+ ecn_ctx->ldcp_ctx.eta, ecn_ctx->ldcp_ctx.wnd_min,
+ ecn_ctx->ldcp_ctx.wnd_default);
+
+ (void)memset_s(&ldcp_param, sizeof(ldcp_param), 0, sizeof(ldcp_param));
+
+ ldcp_param.dw0.bs.alpha = ecn_ctx->ldcp_ctx.alpha;
+ ldcp_param.dw0.bs.beta = ecn_ctx->ldcp_ctx.beta;
+ ldcp_param.dw0.bs.gamma = ecn_ctx->ldcp_ctx.gamma;
+ ldcp_param.dw0.bs.eta = ecn_ctx->ldcp_ctx.eta;
+ ldcp_param.dw0.bs.wnd_min = ecn_ctx->ldcp_ctx.wnd_min;
+ ldcp_param.dw1.bs.wnd_default = ecn_ctx->ldcp_ctx.wnd_default;
+ ldcp_param.dw0.bs.set_flag = 1;
+
+ ret = roce5_set_sysfs_cfg_param(rdev->hwdev, rdev->glb_func_id,
+ (u32 *)(void *)&ldcp_param,
+ sizeof(roce_ldcp_param_s),
+ (u16)ROCE_MPU_CMD_CC_CFG_LDCP_PARAM);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to set ldcp param, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ }
+
+ return ret;
+}
+
+static int roce5_update_ipqcn_param(struct roce5_device *rdev,
+ const struct roce5_ecn_ctx *ecn_ctx)
+{
+ roce_ipqcn_param_s ipqcn_param;
+ int ret;
+
+ if (ecn_ctx->cc_algo != ROCE_CC_IPQCN_ALGO) {
+ ROCE_DEV_INFO(
+ rdev,
+ "func_id(%d) cc_algo(%u) is not ipqcn, ignore update.",
+ rdev->glb_func_id, ecn_ctx->cc_algo);
+ return 0;
+ }
+
+ (void)memset_s(&ipqcn_param, sizeof(ipqcn_param), 0,
+ sizeof(ipqcn_param));
+
+ ipqcn_param.dw0.bs.token_period = ecn_ctx->rp_ctx.token_period;
+ ipqcn_param.dw0.bs.flow_min_rate = ecn_ctx->rp_ctx.min_rate;
+ ipqcn_param.dw1.bs.rate_inc_period = ecn_ctx->rp_ctx.rate_inc_period;
+ ipqcn_param.dw1.bs.alpha_dec_period = ecn_ctx->rp_ctx.alpha_dec_period;
+ ipqcn_param.dw2.bs.rate_inc_ai = ecn_ctx->rp_ctx.rate_inc_ai;
+ ipqcn_param.dw2.bs.rate_inc_hai = ecn_ctx->rp_ctx.rate_inc_hai;
+ ipqcn_param.dw2.bs.rate_dec_period = ecn_ctx->rp_ctx.rate_dec_period;
+ ipqcn_param.dw2.bs.min_cnp_period = ecn_ctx->np_ctx.min_cnp_period;
+ ipqcn_param.dw3.bs.factor_gita = ecn_ctx->rp_ctx.factor_gita;
+ ipqcn_param.dw3.bs.rt_clamp = ecn_ctx->rp_ctx.rate_target_clamp;
+ ipqcn_param.dw3.bs.initial_alpha = ecn_ctx->rp_ctx.initial_alpha;
+ ipqcn_param.dw3.bs.rate_first_set = ecn_ctx->rp_ctx.rate_first_set;
+
+ ret = roce5_set_sysfs_cfg_param(rdev->hwdev, rdev->glb_func_id,
+ (u32 *)(void *)&ipqcn_param,
+ sizeof(roce_ipqcn_param_s),
+ (u16)ROCE_MPU_CMD_CC_CFG_IPQCN_PARAM);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to set ipqcn param, func_id(%d) ret(%d)",
+ rdev->glb_func_id, ret);
+ }
+
+ return ret;
+}
+
+typedef int (*roce5_update_param_t)(struct roce5_device *rdev,
+ const struct roce5_ecn_ctx *ecn_ctx);
+
+static roce5_update_param_t roce5_update_param_funcs[] = {
+ roce5_update_cfg_cc_param, roce5_update_dcqcn_param,
+ roce5_update_ipqcn_param, roce5_update_ldcp_param,
+ roce5_update_ucc_param,
+};
+
+int roce5_update_ecn_param(const struct roce5_ecn_ctx *ecn_ctx)
+{
+ unsigned int i;
+ int ret = 0;
+ struct roce5_device *rdev =
+ container_of(ecn_ctx, struct roce5_device, ecn_ctx);
+
+ /* current only supports LDCP algorithm, its remaining algorithm can only modify its algorithm parameters, cannot switch */
+ for (i = 0; i < (sizeof(roce5_update_param_funcs) /
+ sizeof(roce5_update_param_t));
+ i++) {
+ ret = roce5_update_param_funcs[i](rdev, ecn_ctx);
+ if (ret != 0) {
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t roce5_show_cc_algo(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj);
+
+ if ((attr == NULL) || (buf == NULL)) {
+ ROCE_ERR("attr or buf is null");
+ return -EINVAL;
+ }
+
+ switch ((int)ecn_ctx->cc_algo) {
+ case ROCE_CC_DISABLE:
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%s\n", "disable");
+ case ROCE_CC_DCQCN_ALGO:
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%s\n", "dcqcn");
+ case ROCE_CC_LDCP_ALGO:
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%s\n", "ldcp");
+ case ROCE_CC_IPQCN_ALGO:
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%s\n",
+ "hc3_1/ipqcn");
+ case ROCE_CC_USER_A_ALGO:
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%s\n",
+ "user_cc_6");
+ case ROCE_CC_USER_B_ALGO:
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%s\n",
+ "user_cc_7");
+ default:
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%s\n",
+ "error_type");
+ }
+}
+
+static ssize_t roce5_store_cc_algo(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj);
+ u32 old_cc_algo = 0;
+ int cc_algo = 0;
+ const char *ptr = NULL;
+ int ret;
+
+ if ((attr == NULL) || (buf == NULL)) {
+ ROCE_ERR("attr or buf is null");
+ return -EINVAL;
+ }
+
+ /* dcqcn -> 0x0, ldcp -> 0x2, hc3_1 -> 0x80 */
+ if (strncmp(buf, "disable", strlen("disable")) == 0) {
+ cc_algo = ROCE_CC_DISABLE;
+ } else if (strncmp(buf, "dcqcn", strlen("dcqcn")) == 0) {
+ cc_algo = ROCE_CC_DCQCN_ALGO;
+ } else if ((strncmp(buf, "ipqcn", strlen("ipqcn")) == 0) ||
+ (strncmp(buf, "hc3_1", strlen("hc3_1")) == 0)) {
+ cc_algo = ROCE_CC_IPQCN_ALGO;
+ } else if (strncmp(buf, "ldcp", strlen("ldcp")) == 0) {
+ cc_algo = ROCE_CC_LDCP_ALGO;
+ } else if (strncmp(buf, "user_cc_", strlen("user_cc_")) == 0) {
+ if (strlen(buf) > ROCE_USER_CC_ID_MAX_LEN) {
+ ROCE_ERR(
+ "Invalid buffer length, expected <= %d, got %zu, Buffer: '%s'",
+ ROCE_USER_CC_ID_MAX_LEN, strlen(buf), buf);
+ return -EINVAL;
+ }
+ ptr = buf + strlen("user_cc_");
+ cc_algo = (unsigned char)(*ptr) - CHAR_0;
+ if (cc_algo != ROCE_CC_USER_A_ALGO &&
+ cc_algo != ROCE_CC_USER_B_ALGO) {
+ ROCE_ERR("Invalid cc_algo(%d),buf(%s)", cc_algo, buf);
+ return -EINVAL;
+ }
+ } else {
+ ROCE_ERR("Invalid cc_algo(%d),buf(%s)", cc_algo, buf);
+ return -EIO;
+ }
+
+ if (ecn_ctx->cc_algo != (u32)cc_algo) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_cc_algo = ecn_ctx->cc_algo;
+ ecn_ctx->cc_algo = (u32)cc_algo;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Failed to update cc_algo(%d), ret(%d).",
+ cc_algo, ret);
+ ecn_ctx->cc_algo = old_cc_algo;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce5_show_ecn_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct roce5_prio_enable_ctx *prio_enable_ctx =
+ container_of(attr, struct roce5_prio_enable_ctx, enable);
+
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)prio_enable_ctx->prio_en);
+}
+
+static ssize_t roce5_store_ecn_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ int prio_en = 0;
+ u32 old_prio_en = 0;
+ struct roce5_ecn_rp_ctx *rp_ctx = NULL;
+ struct roce5_ecn_np_ctx *np_ctx = NULL;
+ struct roce5_ecn_ctx *ecn_ctx = NULL;
+ struct roce5_prio_enable_ctx *prio_enable_ctx =
+ container_of(attr, struct roce5_prio_enable_ctx, enable);
+ struct roce5_ecn_enable_ctx *ecn_enable_ctx =
+ (struct roce5_ecn_enable_ctx *)prio_enable_ctx->ecn_enable_ctx;
+
+ if (ecn_enable_ctx->np_rp == ROCE_DCQCN_NP) {
+ np_ctx = container_of(ecn_enable_ctx, struct roce5_ecn_np_ctx,
+ enable_ctx);
+ ecn_ctx = container_of(np_ctx, struct roce5_ecn_ctx, np_ctx);
+ } else {
+ rp_ctx = container_of(ecn_enable_ctx, struct roce5_ecn_rp_ctx,
+ enable_ctx);
+ ecn_ctx = container_of(rp_ctx, struct roce5_ecn_ctx, rp_ctx);
+ }
+
+ ret = sscanf_s(buf, "%d", &prio_en);
+ if (ret != 1) {
+ return -EIO;
+ }
+
+ if (((u32)prio_en & ROCE_ENABLE_CHECK_MASK) != 0) {
+ return -EIO;
+ }
+
+ if (prio_enable_ctx->prio_en != (u32)prio_en) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_prio_en = prio_enable_ctx->prio_en;
+ prio_enable_ctx->prio_en = (u32)prio_en;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Fail to update prio_en(%d), ret(%d).",
+ prio_en, ret);
+ prio_enable_ctx->prio_en = old_prio_en;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce5_show_ecn_ip_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct roce5_ip_prio_enable_ctx *ip_prio_enable_ctx =
+ container_of(attr, struct roce5_ip_prio_enable_ctx, ip_enable);
+
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)ip_prio_enable_ctx->prio_en);
+}
+
+static ssize_t roce5_store_ecn_ip_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ int prio_en = 0;
+ u32 old_prio_en = 0;
+ struct roce5_ip_prio_enable_ctx *ip_prio_enable_ctx =
+ container_of(attr, struct roce5_ip_prio_enable_ctx, ip_enable);
+ struct roce5_ecn_ip_enable_ctx *ip_enable_ctx =
+ (struct roce5_ecn_ip_enable_ctx *)
+ ip_prio_enable_ctx->ecn_ip_enable_ctx;
+ struct roce5_ecn_ctx *ecn_ctx = container_of(
+ ip_enable_ctx, struct roce5_ecn_ctx, ip_enable_ctx);
+
+ ret = sscanf_s(buf, "%d", &prio_en);
+ if (ret != 1) {
+ return -EIO;
+ }
+
+ if (((u32)prio_en & ROCE_ENABLE_CHECK_MASK) != 0) {
+ return -EIO;
+ }
+
+ if (ip_prio_enable_ctx->prio_en != (u32)prio_en) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_prio_en = ip_prio_enable_ctx->prio_en;
+ ip_prio_enable_ctx->prio_en = (u32)prio_en;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Fail to update prio_en(%d), ret(%d).",
+ prio_en, ret);
+ ip_prio_enable_ctx->prio_en = old_prio_en;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+/* rp_ctx parameters use macro generate show/store function */
+ROCE5_PARAM_SHOW_STORE_RP(bypass, bypass, min_bypass, max_bypass)
+ROCE5_PARAM_SHOW_STORE_RP(rate_inc_hai, rate_inc_hai, min_rate_inc_hai,
+ max_rate_inc_hai)
+ROCE5_PARAM_SHOW_STORE_RP(rate_inc_ai, rate_inc_ai, min_rate_inc_ai,
+ max_rate_inc_ai)
+ROCE5_PARAM_SHOW_STORE_RP(initial_alpha, initial_alpha, min_initial_alpha,
+ max_initial_alpha)
+ROCE5_PARAM_SHOW_STORE_RP(factor_gita, factor_gita, min_factor_gita,
+ max_factor_gita)
+ROCE5_PARAM_SHOW_STORE_RP(rate_inc_period, rate_inc_period, min_rate_inc_period,
+ max_rate_inc_period)
+ROCE5_PARAM_SHOW_STORE_RP(rate_dec_period, rate_dec_period, min_rate_dec_period,
+ max_rate_dec_period)
+ROCE5_PARAM_SHOW_STORE_RP(token_period, token_period, min_token_period,
+ max_token_period)
+ROCE5_PARAM_SHOW_STORE_RP(min_rate, min_rate, min_flow_min_rate,
+ max_flow_min_rate)
+ROCE5_PARAM_SHOW_STORE_RP(alpha_dec_period, alpha_dec_period,
+ min_alpha_dec_period, max_alpha_dec_period)
+ROCE5_PARAM_SHOW_STORE_RP(rate_first_set, rate_first_set, min_rate_first_set,
+ max_rate_first_set)
+
+/* rate_target_clamp special handle: use ROCE_ENABLE_CHECK_MASK but non- range check */
+static ssize_t roce5_show_rate_target_clamp(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct roce5_ecn_rp_ctx *ecn_rp_ctx = to_roce5_ecn_rp_ctx(kobj);
+
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)ecn_rp_ctx->rate_target_clamp);
+}
+
+static ssize_t roce5_store_rate_target_clamp(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ int rate_target_clamp = 0;
+ u32 old_rate_target_clamp = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_rp_ctx *ecn_rp_ctx = to_roce5_ecn_rp_ctx(kobj);
+
+ ret = sscanf_s(buf, "%d", &rate_target_clamp);
+ if (ret != 1) {
+ return -EIO;
+ }
+
+ if (((u32)rate_target_clamp & ROCE_ENABLE_CHECK_MASK) != 0) {
+ return -EIO;
+ }
+
+ if (ecn_rp_ctx->rate_target_clamp != (u32)rate_target_clamp) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_rate_target_clamp = ecn_rp_ctx->rate_target_clamp;
+ ecn_rp_ctx->rate_target_clamp = (u32)rate_target_clamp;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Fail to update rate_target_clamp(%d), ret(%d).",
+ rate_target_clamp, ret);
+ ecn_rp_ctx->rate_target_clamp = old_rate_target_clamp;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+/* np_ctx parameters use macro generate show/store function */
+ROCE5_PARAM_SHOW_STORE_NP(min_cnp_period, min_cnp_period, min_min_cnp_period,
+ max_min_cnp_period)
+
+/* flow_ctrl_unit special handle: use ROCE_ENABLE_CHECK_MASK check */
+static ssize_t roce5_show_flow_ctrl_unit(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)ecn_np_ctx->flow_ctrl_unit);
+}
+static ssize_t roce5_store_flow_ctrl_unit(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, _val;
+ u32 _old;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+ char remaining;
+
+ ret = sscanf_s(buf, "%d %c", &_val, &remaining, 1);
+ if (ret != 1) {
+ ROCE_ERR(
+ "Invalid input, flow_ctrl_unit should be unsigned int, ret(%d), flow_ctrl_unit(%d)",
+ ret, _val);
+ return -EIO;
+ }
+
+ if (((u32)_val & ROCE_ENABLE_CHECK_MASK) != 0) {
+ return -EIO;
+ }
+
+ if (ecn_np_ctx->flow_ctrl_unit != (u32)_val) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ _old = ecn_np_ctx->flow_ctrl_unit;
+ ecn_np_ctx->flow_ctrl_unit = (u32)_val;
+ ret = roce5_update_ecn_param(ecn_ctx);
+
+ if (ret != 0) {
+ ecn_np_ctx->flow_ctrl_unit = _old;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+ return (ssize_t)count;
+}
+
+/* rtt_version special handle: only check maximum value */
+static ssize_t roce5_show_rtt_version(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)ecn_np_ctx->rtt_version);
+}
+static ssize_t roce5_store_rtt_version(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ u32 _val, _old;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+ struct roce5_device *rdev =
+ container_of(ecn_ctx, struct roce5_device, ecn_ctx);
+ char remaining;
+
+ ret = sscanf_s(buf, "%u %c", &_val, &remaining, 1);
+ if (ret != 1) {
+ ROCE_ERR(
+ "Invalid input, rtt_version should be unsigned int, ret(%d), rtt_version(%u)",
+ ret, _val);
+ return -EIO;
+ }
+
+ if (_val >
+ g_roce_cc_ecn_param[rdev->cc_param_version].max_rtt_version) {
+ ROCE_ERR("Invalid input, rtt_version(%u) over max rtt version",
+ _val);
+ return -EIO;
+ }
+
+ if (ecn_np_ctx->rtt_version != _val) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ _old = ecn_np_ctx->rtt_version;
+ ecn_np_ctx->rtt_version = _val;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_np_ctx->rtt_version = _old;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+ return (ssize_t)count;
+}
+
+/* rtt_rsp_prio special handle: use PRI_ARRAY_LEN - 1 check */
+static ssize_t roce5_show_rtt_rsp_prio(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%u\n",
+ ecn_np_ctx->rtt_rsp_prio);
+}
+
+static ssize_t roce5_store_rtt_rsp_prio(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ u32 rtt_rsp_prio = 0;
+ u32 old_rtt_rsp_prio = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+
+ char remaining;
+ ret = sscanf_s(buf, "%u %c", &rtt_rsp_prio, &remaining, 1);
+ if (ret != 1) {
+ ROCE_ERR(
+ "Invalid input, rtt_rsp_prio should be unsigned int, ret(%d), rtt_rsp_prio(%u)\n",
+ ret, rtt_rsp_prio);
+ return -EIO;
+ }
+
+ if (rtt_rsp_prio > (PRI_ARRAY_LEN - 1)) {
+ return -EIO;
+ }
+
+ if (ecn_np_ctx->rtt_rsp_prio != (u32)rtt_rsp_prio) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_rtt_rsp_prio = ecn_np_ctx->rtt_rsp_prio;
+ ecn_np_ctx->rtt_rsp_prio = (u32)rtt_rsp_prio;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Fail to update rtt_rsp_prio(%d), ret(%d).",
+ rtt_rsp_prio, ret);
+ ecn_np_ctx->rtt_rsp_prio = old_rtt_rsp_prio;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+/* rtt_rsp_prio_enable special handle: use ROCE_ENABLE_CHECK_MASK check */
+static ssize_t roce5_show_rtt_rsp_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%u\n",
+ ecn_np_ctx->rtt_rsp_prio_enable);
+}
+
+static ssize_t roce5_store_rtt_rsp_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ u32 rtt_rsp_prio_enable = 0;
+ u32 old_rtt_rsp_prio_enable = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+
+ char remaining;
+ ret = sscanf_s(buf, "%u %c", &rtt_rsp_prio_enable, &remaining, 1);
+ if (ret != 1) {
+ ROCE_ERR(
+ "Invalid input, rtt_rsp_prio_enable should be unsigned int, ret(%d), rtt_rsp_prio_enable(%u)",
+ ret, rtt_rsp_prio_enable);
+ return -EIO;
+ }
+
+ if ((rtt_rsp_prio_enable & ROCE_ENABLE_CHECK_MASK) != 0) {
+ return -EIO;
+ }
+
+ if (ecn_np_ctx->rtt_rsp_prio_enable != (u32)rtt_rsp_prio_enable) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_rtt_rsp_prio_enable = ecn_np_ctx->rtt_rsp_prio_enable;
+ ecn_np_ctx->rtt_rsp_prio_enable = (u32)rtt_rsp_prio_enable;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Fail to update rtt_rsp_prio_enable(%d), ret(%d).",
+ rtt_rsp_prio_enable, ret);
+ ecn_np_ctx->rtt_rsp_prio_enable =
+ old_rtt_rsp_prio_enable;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+/* ecn_cnp_en special handle: use ROCE_ENABLE_CHECK_MASK check */
+static ssize_t roce5_show_ecn_cnp_en(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)ecn_np_ctx->ecn_cnp_en);
+}
+
+static ssize_t roce5_store_ecn_cnp_en(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ u32 ecn_cnp_en = 0;
+ u32 old_ecn_cnp_en = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+
+ char remaining;
+ ret = sscanf_s(buf, "%u %c", &ecn_cnp_en, &remaining, 1);
+ if (ret != 1) {
+ ROCE_ERR(
+ "Invalid input, ecn_cnp_en should be unsigned int, ret(%d), ecn_cnp_en(%u)",
+ ret, ecn_cnp_en);
+ return -EIO;
+ }
+
+ if ((ecn_cnp_en & ROCE_ENABLE_CHECK_MASK) != 0) {
+ return -EIO;
+ }
+
+ if (ecn_np_ctx->ecn_cnp_en != (u32)ecn_cnp_en) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_ecn_cnp_en = ecn_np_ctx->ecn_cnp_en;
+ ecn_np_ctx->ecn_cnp_en = (u32)ecn_cnp_en;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Fail to update ecn_cnp_en(%d), ret(%d).",
+ ecn_cnp_en, ret);
+ ecn_np_ctx->ecn_cnp_en = old_ecn_cnp_en;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+/* cnp_prio_enable special handle: use ROCE_ENABLE_CHECK_MASK check */
+static ssize_t roce5_show_cnp_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)ecn_np_ctx->cnp_prio_enable);
+}
+
+static ssize_t roce5_store_cnp_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ int cnp_prio_enable = 0;
+ u32 old_cnp_prio_enable = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+
+ ret = sscanf_s(buf, "%d", &cnp_prio_enable);
+ if (ret != 1) {
+ return -EIO;
+ }
+
+ if (((u32)cnp_prio_enable & ROCE_ENABLE_CHECK_MASK) != 0) {
+ return -EIO;
+ }
+
+ if (ecn_np_ctx->cnp_prio_enable != (u32)cnp_prio_enable) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_cnp_prio_enable = ecn_np_ctx->cnp_prio_enable;
+ ecn_np_ctx->cnp_prio_enable = (u32)cnp_prio_enable;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Fail to update cnp_prio_enable(%d), ret(%d).",
+ cnp_prio_enable, ret);
+ ecn_np_ctx->cnp_prio_enable = old_cnp_prio_enable;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+/* cnp_prio special handle: use PRI_ARRAY_LEN - 1 check */
+static ssize_t roce5_show_cnp_prio(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)ecn_np_ctx->cnp_prio);
+}
+
+static ssize_t roce5_store_cnp_prio(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ int cnp_prio = 0;
+ u32 old_cnp_prio = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_np_ctx *ecn_np_ctx = to_roce5_ecn_np_ctx(kobj);
+
+ ret = sscanf_s(buf, "%d", &cnp_prio);
+ if (ret != 1) {
+ return -EIO;
+ }
+
+ if (((u32)cnp_prio) > (PRI_ARRAY_LEN - 1)) {
+ return -EIO;
+ }
+
+ if (ecn_np_ctx->cnp_prio != (u32)cnp_prio) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_cnp_prio = ecn_np_ctx->cnp_prio;
+ ecn_np_ctx->cnp_prio = (u32)cnp_prio;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Fail to update cnp_prio(%d), ret(%d).",
+ cnp_prio, ret);
+ ecn_np_ctx->cnp_prio = old_cnp_prio;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static int
+roce5_init_ecn_enable_sysfs(struct kobject *kobj,
+ struct roce5_ecn_enable_ctx *ecn_enable_ctx)
+{
+ int ret = 0;
+ int i = 0;
+ int j = 0;
+ const char *prio_arr[8] = { "0", "1", "2", "3", "4", "5", "6", "7" };
+ struct roce5_prio_enable_ctx *prio_enable = NULL;
+
+ ecn_enable_ctx->enable_root = kobject_create_and_add("enable", kobj);
+ if (ecn_enable_ctx->enable_root == NULL) {
+ ROCE_ERR("Failed to create kobject for ecn enable.(ret:%d)",
+ ret);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < PRI_ARRAY_LEN; i++) {
+ prio_enable = &ecn_enable_ctx->prio_enable[i];
+ prio_enable->ecn_enable_ctx = (void *)ecn_enable_ctx;
+ prio_enable->prio = (u32)i;
+ prio_enable->prio_en = 1;
+ sysfs_attr_init(&prio_enable->enable.attr);
+ prio_enable->enable.attr.name = prio_arr[i];
+ prio_enable->enable.attr.mode = (S_IWUSR | S_IRUSR | S_IRGRP);
+ prio_enable->enable.show = roce5_show_ecn_prio_enable;
+ prio_enable->enable.store = roce5_store_ecn_prio_enable;
+ ret = sysfs_create_file(ecn_enable_ctx->enable_root,
+ &prio_enable->enable.attr);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to create file for ecn enable.(ret:%d)",
+ ret);
+ goto err_create_file;
+ }
+ }
+
+ return 0;
+
+err_create_file:
+ for (j = i - 1; j >= 0; j--) {
+ sysfs_remove_file(ecn_enable_ctx->enable_root,
+ &ecn_enable_ctx->prio_enable[i].enable.attr);
+ }
+
+ kobject_put(ecn_enable_ctx->enable_root);
+
+ return ret;
+}
+
+static void
+roce5_remove_ecn_enable_sysfs(struct kobject *kobj,
+ struct roce5_ecn_enable_ctx *ecn_enable_ctx)
+{
+ int i;
+
+ for (i = 0; i < PRI_ARRAY_LEN; i++) {
+ sysfs_remove_file(ecn_enable_ctx->enable_root,
+ &ecn_enable_ctx->prio_enable[i].enable.attr);
+ }
+
+ kobject_put(ecn_enable_ctx->enable_root);
+}
+
+static int
+roce5_init_ecn_ip_enable_sysfs(struct kobject *kobj,
+ struct roce5_ecn_ip_enable_ctx *ip_enable_ctx)
+{
+ int ret = 0;
+ int i = 0;
+ int j = 0;
+ const char *prio_arr[8] = { "0", "1", "2", "3", "4", "5", "6", "7" };
+ struct roce5_ip_prio_enable_ctx *ip_prio_enable = NULL;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj);
+ struct roce5_device *rdev =
+ container_of(ecn_ctx, struct roce5_device, ecn_ctx);
+ ip_enable_ctx->ip_enable_root =
+ kobject_create_and_add("ip_enable", kobj);
+ if (ip_enable_ctx->ip_enable_root == NULL) {
+ ROCE_ERR("Failed to create kobject for ecn ip enable.(ret:%d)",
+ ret);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < PRI_ARRAY_LEN; i++) {
+ ip_prio_enable = &ip_enable_ctx->ip_prio_enable[i];
+ ip_prio_enable->ecn_ip_enable_ctx = (void *)ip_enable_ctx;
+ ip_prio_enable->prio = (u32)i;
+ ip_prio_enable->prio_en =
+ g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_ip_enable_en;
+ sysfs_attr_init(&ip_prio_enable->ip_enable.attr);
+ ip_prio_enable->ip_enable.attr.name = prio_arr[i];
+ ip_prio_enable->ip_enable.attr.mode =
+ (S_IWUSR | S_IRUSR | S_IRGRP);
+ ip_prio_enable->ip_enable.show = roce5_show_ecn_ip_prio_enable;
+ ip_prio_enable->ip_enable.store =
+ roce5_store_ecn_ip_prio_enable;
+ ret = sysfs_create_file(ip_enable_ctx->ip_enable_root,
+ &ip_prio_enable->ip_enable.attr);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to create file for ecn ip enable.(ret:%d)",
+ ret);
+ goto err_create_file;
+ }
+ }
+
+ return 0;
+
+err_create_file:
+ for (j = i - 1; j >= 0; j--) {
+ sysfs_remove_file(
+ ip_enable_ctx->ip_enable_root,
+ &ip_enable_ctx->ip_prio_enable[i].ip_enable.attr);
+ }
+
+ kobject_put(ip_enable_ctx->ip_enable_root);
+
+ return ret;
+}
+
+static void
+roce5_remove_ecn_ip_enable_sysfs(struct kobject *kobj,
+ struct roce5_ecn_ip_enable_ctx *ip_enable_ctx)
+{
+ int i;
+
+ for (i = 0; i < PRI_ARRAY_LEN; i++) {
+ sysfs_remove_file(
+ ip_enable_ctx->ip_enable_root,
+ &ip_enable_ctx->ip_prio_enable[i].ip_enable.attr);
+ }
+
+ kobject_put(ip_enable_ctx->ip_enable_root);
+}
+
+ROCE_ATTR_RW(bypass, roce5_show_bypass, roce5_store_bypass);
+ROCE_ATTR_RW(alpha_dec_period, roce5_show_alpha_dec_period,
+ roce5_store_alpha_dec_period);
+ROCE_ATTR_RW(rate_dec_period, roce5_show_rate_dec_period,
+ roce5_store_rate_dec_period);
+ROCE_ATTR_RW(rate_inc_period, roce5_show_rate_inc_period,
+ roce5_store_rate_inc_period);
+ROCE_ATTR_RW(factor_gita, roce5_show_factor_gita, roce5_store_factor_gita);
+ROCE_ATTR_RW(initial_alpha, roce5_show_initial_alpha,
+ roce5_store_initial_alpha);
+ROCE_ATTR_RW(rate_inc_ai, roce5_show_rate_inc_ai, roce5_store_rate_inc_ai);
+ROCE_ATTR_RW(rate_inc_hai, roce5_show_rate_inc_hai, roce5_store_rate_inc_hai);
+ROCE_ATTR_RW(rate_first_set, roce5_show_rate_first_set,
+ roce5_store_rate_first_set);
+ROCE_ATTR_RW(rate_target_clamp, roce5_show_rate_target_clamp,
+ roce5_store_rate_target_clamp);
+ROCE_ATTR_RW(token_period, roce5_show_token_period, roce5_store_token_period);
+ROCE_ATTR_RW(min_rate, roce5_show_min_rate, roce5_store_min_rate);
+
+static struct attribute *ecn_rp_ctx_attrs[] = {
+ ROCE_ATTR_PTR(bypass),
+ ROCE_ATTR_PTR(alpha_dec_period),
+ ROCE_ATTR_PTR(rate_dec_period),
+ ROCE_ATTR_PTR(rate_inc_period),
+ ROCE_ATTR_PTR(factor_gita),
+ ROCE_ATTR_PTR(initial_alpha),
+ ROCE_ATTR_PTR(rate_inc_ai),
+ ROCE_ATTR_PTR(rate_inc_hai),
+ ROCE_ATTR_PTR(rate_first_set),
+ ROCE_ATTR_PTR(rate_target_clamp),
+ ROCE_ATTR_PTR(token_period),
+ ROCE_ATTR_PTR(min_rate),
+ NULL,
+};
+
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+static const struct attribute_group ecn_rp_ctx_attr_grp = {
+ .attrs = ecn_rp_ctx_attrs,
+};
+
+static const struct attribute_group *ecn_rp_ctx_attr_grps[] = {
+ &ecn_rp_ctx_attr_grp,
+ NULL,
+};
+#endif
+
+static void roce_ecn_rp_sysfs_release(struct kobject *kobj)
+{
+}
+
+static struct kobj_type roce_ecn_rp_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .release = roce_ecn_rp_sysfs_release,
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+ .default_groups = ecn_rp_ctx_attr_grps,
+#else
+ .default_attrs = ecn_rp_ctx_attrs,
+#endif
+};
+
+static int roce5_init_ecn_rp_sysfs(struct kobject *kobj,
+ struct roce5_ecn_rp_ctx *ecn_rp_ctx)
+{
+ int ret = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj);
+ struct roce5_device *rdev =
+ container_of(ecn_ctx, struct roce5_device, ecn_ctx);
+
+ ecn_rp_ctx->bypass =
+ g_roce_cc_ecn_param[rdev->cc_param_version].default_bypass;
+ ecn_rp_ctx->alpha_dec_period =
+ g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_alpha_dec_period;
+ ecn_rp_ctx->rate_dec_period =
+ g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_rate_dec_period;
+ ecn_rp_ctx->rate_inc_period =
+ g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_rate_inc_period;
+ ecn_rp_ctx->factor_gita =
+ g_roce_cc_ecn_param[rdev->cc_param_version].default_factor_gita;
+ ecn_rp_ctx->initial_alpha = g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_initial_alpha;
+ ecn_rp_ctx->rate_inc_ai =
+ g_roce_cc_ecn_param[rdev->cc_param_version].default_rate_inc_ai;
+ ecn_rp_ctx->rate_inc_hai =
+ g_roce_cc_ecn_param[rdev->cc_param_version].default_rate_inc_hai;
+ ecn_rp_ctx->rate_first_set = g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_rate_first_set;
+ ecn_rp_ctx->rate_target_clamp =
+ g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_rate_target_clamp;
+ ecn_rp_ctx->token_period =
+ g_roce_cc_ecn_param[rdev->cc_param_version].default_token_period;
+ ecn_rp_ctx->min_rate =
+ g_roce_cc_ecn_param[rdev->cc_param_version].default_min_rate;
+ ret = kobject_init_and_add(&ecn_rp_ctx->ecn_rp_root, &roce_ecn_rp_ktype,
+ kobj, "roce5_rp");
+ if (ret != 0) {
+ ROCE_ERR("Failed to add kobject roce5_rp.(ret:%d)", ret);
+ kobject_put(&ecn_rp_ctx->ecn_rp_root);
+ return ret;
+ }
+
+ ecn_rp_ctx->enable_ctx.np_rp = ROCE_DCQCN_RP;
+ ret = roce5_init_ecn_enable_sysfs(&ecn_rp_ctx->ecn_rp_root,
+ &ecn_rp_ctx->enable_ctx);
+ if (ret != 0) {
+ goto err_init_prio_enable_sysfs;
+ }
+
+ return 0;
+
+err_init_prio_enable_sysfs:
+ kobject_put(&ecn_rp_ctx->ecn_rp_root);
+
+ return ret;
+}
+
+static void roce5_remove_ecn_rp_sysfs(struct kobject *kobj,
+ struct roce5_ecn_rp_ctx *ecn_rp_ctx)
+{
+ roce5_remove_ecn_enable_sysfs(&ecn_rp_ctx->ecn_rp_root,
+ &ecn_rp_ctx->enable_ctx);
+
+ kobject_put(&ecn_rp_ctx->ecn_rp_root);
+}
+
+ROCE_ATTR_RW(rtt_rsp_prio, roce5_show_rtt_rsp_prio, roce5_store_rtt_rsp_prio);
+ROCE_ATTR_RW(rtt_rsp_prio_enable, roce5_show_rtt_rsp_prio_enable,
+ roce5_store_rtt_rsp_prio_enable);
+ROCE_ATTR_RW(rtt_version, roce5_show_rtt_version, roce5_store_rtt_version);
+ROCE_ATTR_RW(ecn_cnp_en, roce5_show_ecn_cnp_en, roce5_store_ecn_cnp_en);
+ROCE_ATTR_RW(flow_ctrl_unit, roce5_show_flow_ctrl_unit,
+ roce5_store_flow_ctrl_unit);
+ROCE_ATTR_RW(min_cnp_period, roce5_show_min_cnp_period,
+ roce5_store_min_cnp_period);
+ROCE_ATTR_RW(cnp_prio_enable, roce5_show_cnp_prio_enable,
+ roce5_store_cnp_prio_enable);
+ROCE_ATTR_RW(cnp_prio, roce5_show_cnp_prio, roce5_store_cnp_prio);
+
+static struct attribute *ecn_np_ctx_attrs[] = {
+ ROCE_ATTR_PTR(min_cnp_period),
+ ROCE_ATTR_PTR(cnp_prio_enable),
+ ROCE_ATTR_PTR(cnp_prio),
+ ROCE_ATTR_PTR(rtt_rsp_prio),
+ ROCE_ATTR_PTR(rtt_rsp_prio_enable),
+ ROCE_ATTR_PTR(rtt_version),
+ ROCE_ATTR_PTR(ecn_cnp_en),
+ ROCE_ATTR_PTR(flow_ctrl_unit),
+ NULL,
+};
+
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+static const struct attribute_group ecn_np_ctx_attr_grp = {
+ .attrs = ecn_np_ctx_attrs,
+};
+
+static const struct attribute_group *ecn_np_ctx_attr_grps[] = {
+ &ecn_np_ctx_attr_grp,
+ NULL,
+};
+#endif
+
+static void roce_ecn_np_sysfs_release(struct kobject *kobj)
+{
+}
+
+static struct kobj_type roce_ecn_np_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .release = roce_ecn_np_sysfs_release,
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+ .default_groups = ecn_np_ctx_attr_grps,
+#else
+ .default_attrs = ecn_np_ctx_attrs,
+#endif
+};
+
+static int roce5_init_ecn_np_sysfs(struct kobject *kobj,
+ struct roce5_ecn_np_ctx *ecn_np_ctx)
+{
+ int ret = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj);
+ struct roce5_device *rdev =
+ container_of(ecn_ctx, struct roce5_device, ecn_ctx);
+
+ ecn_np_ctx->min_cnp_period = g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_min_cnp_period;
+ ecn_np_ctx->cnp_prio_enable =
+ g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_cnp_prio_enable;
+ ecn_np_ctx->cnp_prio =
+ g_roce_cc_ecn_param[rdev->cc_param_version].default_cnp_prio;
+ ecn_np_ctx->ecn_cnp_en = g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_ecn_cnp_enable;
+ ecn_np_ctx->flow_ctrl_unit = g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_flow_ctrl_unit;
+ ecn_np_ctx->rtt_rsp_prio =
+ g_roce_cc_ecn_param[rdev->cc_param_version].default_rtt_rsp_prio;
+ ecn_np_ctx->rtt_rsp_prio_enable =
+ g_roce_cc_ecn_param[rdev->cc_param_version]
+ .default_rtt_rsp_prio_enable;
+ ecn_np_ctx->rtt_version =
+ g_roce_cc_ecn_param[rdev->cc_param_version].default_rtt_version;
+ ret = kobject_init_and_add(&ecn_np_ctx->ecn_np_root, &roce_ecn_np_ktype,
+ kobj, "roce5_np");
+ if (ret != 0) {
+ ROCE_ERR("Failed to add kobject roce5_np.(ret:%d)", ret);
+ kobject_put(&ecn_np_ctx->ecn_np_root);
+ return ret;
+ }
+
+ ecn_np_ctx->enable_ctx.np_rp = ROCE_DCQCN_NP;
+ ret = roce5_init_ecn_enable_sysfs(&ecn_np_ctx->ecn_np_root,
+ &ecn_np_ctx->enable_ctx);
+ if (ret != 0) {
+ goto err_init_prio_enable_sysfs;
+ }
+
+ return 0;
+
+err_init_prio_enable_sysfs:
+ kobject_put(&ecn_np_ctx->ecn_np_root);
+ return ret;
+}
+
+/* ldcp_ctx parameters use macro generate show/store function */
+ROCE5_PARAM_SHOW_STORE_LDCP(wnd_min, wnd_min, min_ldcp_wnd_min,
+ max_ldcp_wnd_min);
+ROCE5_PARAM_SHOW_STORE_LDCP(wnd_default, wnd_default, min_ldcp_wnd_default,
+ max_ldcp_wnd_default);
+ROCE5_PARAM_SHOW_STORE_LDCP(alpha, alpha, min_ldcp_alpha, max_ldcp_alpha);
+ROCE5_PARAM_SHOW_STORE_LDCP(beta, beta, min_ldcp_beta, max_ldcp_beta);
+ROCE5_PARAM_SHOW_STORE_LDCP(gamma, gamma, min_ldcp_gamma, max_ldcp_gamma);
+ROCE5_PARAM_SHOW_STORE_LDCP(eta, eta, min_ldcp_eta, max_ldcp_eta);
+
+ROCE_ATTR_RW(wnd_min, roce5_show_wnd_min, roce5_store_wnd_min);
+ROCE_ATTR_RW(wnd_default, roce5_show_wnd_default, roce5_store_wnd_default);
+ROCE_ATTR_RW(alpha, roce5_show_alpha, roce5_store_alpha);
+ROCE_ATTR_RW(beta, roce5_show_beta, roce5_store_beta);
+ROCE_ATTR_RW(gamma, roce5_show_gamma, roce5_store_gamma);
+ROCE_ATTR_RW(eta, roce5_show_eta, roce5_store_eta);
+
+static struct attribute *ecn_ldcp_ctx_attrs[] = {
+ ROCE_ATTR_PTR(wnd_min),
+ ROCE_ATTR_PTR(wnd_default),
+ ROCE_ATTR_PTR(alpha),
+ ROCE_ATTR_PTR(beta),
+ ROCE_ATTR_PTR(gamma),
+ ROCE_ATTR_PTR(eta),
+ NULL,
+};
+
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+static const struct attribute_group ecn_ldcp_ctx_attr_grp = {
+ .attrs = ecn_ldcp_ctx_attrs,
+};
+
+static const struct attribute_group *ecn_ldcp_ctx_attr_grps[] = {
+ &ecn_ldcp_ctx_attr_grp,
+ NULL,
+};
+#endif
+
+static void roce_ecn_ldcp_sysfs_release(struct kobject *kobj)
+{
+}
+
+static struct kobj_type roce_ecn_ldcp_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .release = roce_ecn_ldcp_sysfs_release,
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+ .default_groups = ecn_ldcp_ctx_attr_grps,
+#else
+ .default_attrs = ecn_ldcp_ctx_attrs,
+#endif
+};
+
+static int roce5_init_ecn_ldcp_sysfs(struct kobject *kobj,
+ roce5_ecn_ldcp_ctx_t *ecn_ldcp_ctx)
+{
+ int ret;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj);
+ struct roce5_device *rdev =
+ container_of(ecn_ctx, struct roce5_device, ecn_ctx);
+
+ ecn_ldcp_ctx->wnd_min =
+ g_roce_cc_ecn_param[rdev->cc_param_version].min_ldcp_wnd_min;
+ ecn_ldcp_ctx->wnd_default =
+ g_roce_cc_ecn_param[rdev->cc_param_version].min_ldcp_wnd_default;
+ ecn_ldcp_ctx->alpha =
+ g_roce_cc_ecn_param[rdev->cc_param_version].min_ldcp_alpha;
+ ecn_ldcp_ctx->beta =
+ g_roce_cc_ecn_param[rdev->cc_param_version].min_ldcp_beta;
+ ecn_ldcp_ctx->gamma =
+ g_roce_cc_ecn_param[rdev->cc_param_version].min_ldcp_gamma;
+ ecn_ldcp_ctx->eta =
+ g_roce_cc_ecn_param[rdev->cc_param_version].min_ldcp_eta;
+ ret = kobject_init_and_add(&ecn_ldcp_ctx->ecn_ldcp_root,
+ &roce_ecn_ldcp_ktype, kobj, "roce5_ldcp");
+ if (ret != 0) {
+ ROCE_ERR("Failed to add kobject roce5_ldcp.(ret:%d)", ret);
+ kobject_put(&ecn_ldcp_ctx->ecn_ldcp_root);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce5_remove_ecn_ldcp_sysfs(roce5_ecn_ldcp_ctx_t *ecn_ldcp_ctx)
+{
+ kobject_put(&ecn_ldcp_ctx->ecn_ldcp_root);
+}
+
+static void roce5_remove_ecn_np_sysfs(struct kobject *kobj,
+ struct roce5_ecn_np_ctx *ecn_np_ctx)
+{
+ roce5_remove_ecn_enable_sysfs(&ecn_np_ctx->ecn_np_root,
+ &ecn_np_ctx->enable_ctx);
+
+ kobject_put(&ecn_np_ctx->ecn_np_root);
+}
+
+static ssize_t roce5_show_ecn_ver(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj);
+
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%d\n",
+ (int)ecn_ctx->ecn_ver);
+}
+
+static ssize_t roce5_store_ecn_ver(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret = 0;
+ int ecn_ver = 0;
+ u32 old_ecn_ver = 0;
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj);
+
+ ret = sscanf_s(buf, "%d", &ecn_ver);
+ if (ret != 1) {
+ return -EIO;
+ }
+
+ if (ROCE5_PARAM_CHECK_BOUND(ecn_ver, ECN_VER_DCQCN, ECN_VER_PATHQCN)) {
+ return -EIO;
+ }
+
+ if (ecn_ctx->ecn_ver != (u32)ecn_ver) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_ecn_ver = ecn_ctx->ecn_ver;
+ ecn_ctx->ecn_ver = (u32)ecn_ver;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Fail to update ecn_ver(%d), ret(%d).",
+ ecn_ver, ret);
+ ecn_ctx->ecn_ver = old_ecn_ver;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+ROCE_ATTR_RW(ecn_ver, roce5_show_ecn_ver, roce5_store_ecn_ver);
+ROCE_ATTR_RW(cc_algo, roce5_show_cc_algo, roce5_store_cc_algo);
+
+static struct attribute *ecn_ctx_attrs[] = {
+ ROCE_ATTR_PTR(ecn_ver),
+ ROCE_ATTR_PTR(cc_algo),
+ NULL,
+};
+
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+static const struct attribute_group ecn_ctx_attr_grp = {
+ .attrs = ecn_ctx_attrs,
+};
+
+static const struct attribute_group *ecn_ctx_attr_grps[] = {
+ &ecn_ctx_attr_grp,
+ NULL,
+};
+#endif
+
+static void roce_ecn_sysfs_release(struct kobject *kobj)
+{
+}
+
+static struct kobj_type roce_ecn_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .release = roce_ecn_sysfs_release,
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+ .default_groups = ecn_ctx_attr_grps,
+#else
+ .default_attrs = ecn_ctx_attrs,
+#endif
+};
+
+static void roce5_init_cc_algo(struct roce5_device *rdev,
+ struct roce5_ecn_ctx *ecn_ctx)
+{
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ ecn_ctx->cc_algo = ROCE_CC_DCQCN_ALGO;
+ } else {
+ ecn_ctx->cc_algo = ROCE_CC_DISABLE;
+ }
+}
+
+static void roce5_init_cc_param_version(struct roce5_device *rdev)
+{
+ rdev->cc_param_version =
+ ROCE5_SUPPORT_CC_PARAM_V1(rdev) != 0 ? ROCE_CC_PARAM_V1 :
+ ROCE5_SUPPORT_CC_PARAM_V2(rdev) != 0 ? ROCE_CC_PARAM_V2 :
+ ROCE_CC_PARAM_INVALID;
+}
+
+static int roce5_init_ecn_sysfs(struct roce5_device *rdev,
+ struct roce5_ecn_ctx *ecn_ctx)
+{
+ int ret = 0;
+ struct net_device *ndev = rdev->ndev;
+
+ ret = memset_s(ecn_ctx, sizeof(*ecn_ctx), 0, sizeof(*ecn_ctx));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset ecn_ctx.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ mutex_init(&ecn_ctx->ecn_mutex);
+
+ ecn_ctx->ecn_ver = ECN_VER_DCQCN;
+ roce5_init_cc_algo(rdev, ecn_ctx);
+ roce5_init_cc_param_version(rdev);
+
+ ret = kobject_init_and_add(&ecn_ctx->ecn_root, &roce_ecn_ktype,
+ &ndev->dev.kobj, "ecn");
+ if (ret != 0) {
+ ROCE_ERR("Failed to add kobject ecn.(ret:%d)", ret);
+ kobject_put(&ecn_ctx->ecn_root);
+ return ret;
+ }
+
+ ret = roce5_init_ecn_ldcp_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->ldcp_ctx);
+ if (ret != 0) {
+ goto err_init_ldcp_sysfs;
+ }
+
+ ret = roce5_init_ecn_np_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->np_ctx);
+ if (ret != 0) {
+ goto err_init_np_sysfs;
+ }
+
+ ret = roce5_init_ecn_rp_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->rp_ctx);
+ if (ret != 0) {
+ goto err_init_rp_sysfs;
+ }
+
+ ret = roce5_init_ecn_ip_enable_sysfs(&ecn_ctx->ecn_root,
+ &ecn_ctx->ip_enable_ctx);
+ if (ret != 0) {
+ goto err_init_ip_enable_sysfs;
+ }
+
+ ret = roce5_init_ecn_ucc_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->ucc_ctx);
+ if (ret != 0) {
+ goto err_init_ecn_ucc_sysfs;
+ }
+
+ ret = roce5_init_ecn_multipath_sysfs(rdev, &ecn_ctx->ecn_root,
+ &ecn_ctx->multipath_ctx);
+ if (ret != 0) {
+ goto err_init_multipath_sysfs;
+ }
+
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ goto err_update;
+ }
+
+ return 0;
+
+err_update:
+ roce5_remove_ecn_multipath_sysfs(rdev, &ecn_ctx->ecn_root,
+ &ecn_ctx->multipath_ctx);
+err_init_multipath_sysfs:
+ roce5_remove_ecn_ucc_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->ucc_ctx);
+err_init_ecn_ucc_sysfs:
+ roce5_remove_ecn_ip_enable_sysfs(&ecn_ctx->ecn_root,
+ &ecn_ctx->ip_enable_ctx);
+err_init_ip_enable_sysfs:
+ roce5_remove_ecn_rp_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->rp_ctx);
+err_init_rp_sysfs:
+ roce5_remove_ecn_np_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->np_ctx);
+err_init_np_sysfs:
+ roce5_remove_ecn_ldcp_sysfs(&ecn_ctx->ldcp_ctx);
+err_init_ldcp_sysfs:
+ kobject_put(&ecn_ctx->ecn_root);
+ return ret;
+}
+
+static void roce5_prase_qpc(roce_verbs_qp_attr_s *qp_attr)
+{
+ qp_attr->com_info.rsvd = be32_to_cpu(qp_attr->com_info.rsvd);
+ qp_attr->ext_seg.dfx_info.dw0.value =
+ be32_to_cpu(qp_attr->ext_seg.dfx_info.dw0.value);
+ qp_attr->ext_seg.dfx_info.dw2.value =
+ be32_to_cpu(qp_attr->ext_seg.dfx_info.dw2.value);
+ qp_attr->ext_seg.dfx_info.dw4.value =
+ be32_to_cpu(qp_attr->ext_seg.dfx_info.dw4.value);
+}
+
+static ssize_t roce5_store_dfx_qpc(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ u32 qpn;
+ struct roce5_dfx_qpc_ctx *qpc_ctx = NULL;
+ struct roce5_dfx_ctx *dfx_ctx = NULL;
+ struct roce5_device *rdev = NULL;
+ roce_verbs_qp_attr_s qp_attr;
+ struct rdma_service_cap *rdma_cap = NULL;
+
+ if (kobj == NULL || attr == NULL || buf == NULL || count == 0) {
+ ROCE_ERR("Invalid input para.");
+ return -EINVAL;
+ }
+
+ qpc_ctx = container_of(attr, struct roce5_dfx_qpc_ctx, kattr);
+ dfx_ctx = container_of(qpc_ctx, struct roce5_dfx_ctx, qpc_ctx);
+ rdev = container_of(dfx_ctx, struct roce5_device, dfx_ctx);
+
+ (void)memset_s(&qp_attr, sizeof(roce_verbs_qp_attr_s), 0,
+ sizeof(roce_verbs_qp_attr_s));
+
+ ret = (int)sscanf_s(buf, "%u", &qpn);
+ if (ret != 1) {
+ ROCE_DEV_ERR(rdev, "Failed to do sscanf_s, ret(%d)", ret);
+ return -EIO;
+ }
+
+ rdma_cap = &rdev->rdma_cap;
+ if ((qpn >= rdma_cap->dev_rdma_cap.roce_own_cap.max_qps) ||
+ (qpn < ROCE_MIN_QPN)) {
+ ROCE_DEV_ERR(rdev, "Invalid qpn(%u), max_qps(%u)", qpn,
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_qps);
+ return -EIO;
+ }
+
+ ret = roce5_qp_query(rdev, qpn, (u32 *)(void *)&qp_attr,
+ sizeof(roce_verbs_qp_attr_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to query qp_attr, ret(%d)", ret);
+ return (ssize_t)ret;
+ }
+
+ roce5_prase_qpc(&qp_attr);
+
+ roce5_dfx_print("qpn(0x%x): sqc pi(0x%x), sqc ci(0x%x).", qpn,
+ qp_attr.ext_seg.dfx_info.dw0.bs.sq_pi,
+ qp_attr.ext_seg.dfx_info.dw0.bs.sq_ci);
+ roce5_dfx_print(
+ "sqac ci(0x%x), sqac wqe_prefetch_ci(0x%x), rqc pi(0x%x), rqc ci(0x%x).",
+ qp_attr.ext_seg.dfx_info.dw2.bs.sqa_ci,
+ qp_attr.ext_seg.dfx_info.dw2.bs.sqa_wqe_prefetch_ci,
+ qp_attr.ext_seg.dfx_info.dw4.bs.rq_pi,
+ qp_attr.ext_seg.dfx_info.dw4.bs.rq_ci);
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce5_store_dfx_cqc(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ u32 cqn;
+ struct roce5_dfx_cqc_ctx *cqc_ctx = NULL;
+ struct roce5_dfx_ctx *dfx_ctx = NULL;
+ struct roce5_device *rdev = NULL;
+ roce_verbs_cq_attr_s cq_attr;
+ roce5_cq_query_outbuf_s cq_query;
+ struct rdma_service_cap *rdma_cap = NULL;
+
+ if (kobj == NULL || attr == NULL || buf == NULL || count == 0) {
+ ROCE_ERR("Invalid input para.");
+ return -EINVAL;
+ }
+
+ cqc_ctx = container_of(attr, struct roce5_dfx_cqc_ctx, kattr);
+ dfx_ctx = container_of(cqc_ctx, struct roce5_dfx_ctx, cqc_ctx);
+ rdev = container_of(dfx_ctx, struct roce5_device, dfx_ctx);
+
+ (void)memset_s(&cq_query, sizeof(roce5_cq_query_outbuf_s), 0,
+ sizeof(roce5_cq_query_outbuf_s));
+
+ ret = (int)sscanf_s(buf, "%u", &cqn);
+ if (ret != 1) {
+ ROCE_DEV_ERR(rdev, "Failed to do sscanf_s, ret(%d)", ret);
+ return -EIO;
+ }
+
+ rdma_cap = &rdev->rdma_cap;
+ if (cqn >= rdma_cap->dev_rdma_cap.roce_own_cap.max_cqs) {
+ ROCE_DEV_ERR(rdev, "Invalid cqn(%u), max_cqs(%u)", cqn,
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_cqs);
+ return -EIO;
+ }
+
+ ret = roce5_dfx_query_cq(rdev, cqn, (u32 *)(void *)&cq_query,
+ sizeof(roce5_cq_query_outbuf_s));
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to query cqc, ret(%d)", ret);
+ return (ssize_t)ret;
+ }
+
+ if (rdev->device_type == ROCE_DEV_TYPE_HI1825_V100) {
+ (void)memcpy_s(&cq_attr, sizeof(roce_verbs_cq_attr_s),
+ &cq_query, sizeof(roce_verbs_cq_attr_s));
+ cq_attr.dfx_info.dw0.value =
+ be32_to_cpu(cq_attr.dfx_info.dw0.value);
+ cq_attr.dfx_info.dw1.value =
+ be32_to_cpu(cq_attr.dfx_info.dw1.value);
+ roce5_dfx_print("cqn(0x%x): pi(0x%x), ci(0x%x).", cqn,
+ cq_attr.dfx_info.dw1.bs.pi,
+ cq_attr.dfx_info.dw0.bs.ci);
+ } else {
+ ROCE_DEV_ERR(rdev,
+ "Unsupport rdev device_type, device_type(%d)",
+ rdev->device_type);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce5_store_dfx_srqc(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ u32 srqn;
+ struct roce5_dfx_srqc_ctx *srqc_ctx = NULL;
+ struct roce5_dfx_ctx *dfx_ctx = NULL;
+ struct roce5_device *rdev = NULL;
+ roce_verbs_srq_attr_s srq_attr;
+ struct rdma_service_cap *rdma_cap = NULL;
+
+ if (kobj == NULL || attr == NULL || buf == NULL || count == 0) {
+ ROCE_ERR("Invalid input para.");
+ return -EINVAL;
+ }
+
+ srqc_ctx = container_of(attr, struct roce5_dfx_srqc_ctx, kattr);
+ dfx_ctx = container_of(srqc_ctx, struct roce5_dfx_ctx, srqc_ctx);
+ rdev = container_of(dfx_ctx, struct roce5_device, dfx_ctx);
+
+ (void)memset_s(&srq_attr, sizeof(roce_verbs_srq_attr_s), 0,
+ sizeof(roce_verbs_srq_attr_s));
+
+ ret = (int)sscanf_s(buf, "%u", &srqn);
+ if (ret != 1) {
+ ROCE_DEV_ERR(rdev, "Failed to do sscanf_s, ret(%d)", ret);
+ return -EIO;
+ }
+
+ rdma_cap = &rdev->rdma_cap;
+ if (srqn >= rdma_cap->dev_rdma_cap.roce_own_cap.max_srqs) {
+ ROCE_DEV_ERR(rdev, "Invalid srqn(%u), max_srqs(%u)", srqn,
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_srqs);
+ return -EIO;
+ }
+
+ ret = roce5_dfx_cmd_query_srq(rdev, srqn, &srq_attr);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to query srq_attr, ret(%d)", ret);
+ return (ssize_t)ret;
+ }
+
+ srq_attr.dfx_info.dw0.value = be32_to_cpu(srq_attr.dfx_info.dw0.value);
+
+ roce5_dfx_print("srqn(0x%x): pcnt(0x%x), ccnt(0x%x).", srqn,
+ srq_attr.dfx_info.dw0.bs.pcnt,
+ srq_attr.dfx_info.dw0.bs.ccnt);
+
+ return (ssize_t)count;
+}
+
+static int roce5_init_dfx_sub_ctx_sysfs(struct kobject *kobj,
+ struct roce5_dfx_ctx *dfx_ctx)
+{
+ int ret;
+ struct kobj_attribute *qpc_kattr = NULL;
+ struct kobj_attribute *cqc_kattr = NULL;
+ struct kobj_attribute *srqc_kattr = NULL;
+
+ if (kobj == NULL || dfx_ctx == NULL) {
+ ROCE_ERR("Invalid kobj or dfx_ctx.");
+ return -EINVAL;
+ }
+
+ qpc_kattr = &dfx_ctx->qpc_ctx.kattr;
+ cqc_kattr = &dfx_ctx->cqc_ctx.kattr;
+ srqc_kattr = &dfx_ctx->srqc_ctx.kattr;
+
+ sysfs_attr_init(&qpc_kattr->attr);
+ qpc_kattr->attr.name = "qpc";
+ qpc_kattr->attr.mode = (S_IWUSR | S_IRUSR | S_IRGRP);
+ qpc_kattr->store = roce5_store_dfx_qpc;
+ ret = sysfs_create_file(kobj, &qpc_kattr->attr);
+ if (ret != 0) {
+ ROCE_ERR("QPC failed to do sysfs_create_file, ret(%d)", ret);
+ return ret;
+ }
+
+ sysfs_attr_init(&cqc_kattr->attr);
+ cqc_kattr->attr.name = "cqc";
+ cqc_kattr->attr.mode = (S_IWUSR | S_IRUSR | S_IRGRP);
+ cqc_kattr->store = roce5_store_dfx_cqc;
+ ret = sysfs_create_file(kobj, &cqc_kattr->attr);
+ if (ret != 0) {
+ ROCE_ERR("CQC failed to do sysfs_create_file, ret(%d)", ret);
+ goto err_create_cqc_sysfs;
+ }
+
+ sysfs_attr_init(&srqc_kattr->attr);
+ srqc_kattr->attr.name = "srqc";
+ srqc_kattr->attr.mode = (S_IWUSR | S_IRUSR | S_IRGRP);
+ srqc_kattr->store = roce5_store_dfx_srqc;
+ ret = sysfs_create_file(kobj, &srqc_kattr->attr);
+ if (ret != 0) {
+ ROCE_ERR("SRQC failed to do sysfs_create_file, ret(%d)", ret);
+ goto err_create_srqc_sysfs;
+ }
+
+ return 0;
+
+err_create_srqc_sysfs:
+ sysfs_remove_file(kobj, &cqc_kattr->attr);
+
+err_create_cqc_sysfs:
+ sysfs_remove_file(kobj, &qpc_kattr->attr);
+
+ return ret;
+}
+
+static int roce5_init_dfx_sysfs(struct net_device *ndev,
+ struct roce5_dfx_ctx *dfx_ctx)
+{
+ int ret;
+
+ (void)memset_s(dfx_ctx, sizeof(*dfx_ctx), 0, sizeof(*dfx_ctx));
+
+ dfx_ctx->dfx_root =
+ kobject_create_and_add("roce5_dfx", &ndev->dev.kobj);
+ if (dfx_ctx->dfx_root == NULL) {
+ ROCE_ERR("Failed to do kobject_create_and_add.");
+ return -ENOMEM;
+ }
+
+ ret = roce5_init_dfx_sub_ctx_sysfs(dfx_ctx->dfx_root, dfx_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Failed to init dfx sub ctx sysfs, ret(%d)", ret);
+ kobject_put(dfx_ctx->dfx_root);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce5_remove_ecn_sysfs(struct roce5_device *rdev)
+{
+ struct roce5_ecn_ctx *ecn_ctx = &rdev->ecn_ctx;
+ roce5_remove_ecn_multipath_sysfs(rdev, &ecn_ctx->ecn_root,
+ &ecn_ctx->multipath_ctx);
+
+ roce5_remove_ecn_ucc_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->ucc_ctx);
+
+ roce5_remove_ecn_ip_enable_sysfs(&ecn_ctx->ecn_root,
+ &ecn_ctx->ip_enable_ctx);
+
+ roce5_remove_ecn_rp_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->rp_ctx);
+
+ roce5_remove_ecn_np_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->np_ctx);
+
+ roce5_remove_ecn_ldcp_sysfs(&ecn_ctx->ldcp_ctx);
+
+ kobject_put(&ecn_ctx->ecn_root);
+}
+
+int roce5_init_sysfs(struct roce5_device *rdev)
+{
+ int ret;
+
+ ret = roce5_init_ecn_sysfs(rdev, &rdev->ecn_ctx);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init ecn sysfs, ret(%d)", ret);
+ return ret;
+ }
+
+ ret = roce5_init_dfx_sysfs(rdev->ndev, &rdev->dfx_ctx);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to init dfx sysfs, ret(%d)", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce5_remove_dfx_sub_sysfs(struct roce5_dfx_ctx *dfx_ctx)
+{
+ if (dfx_ctx->dfx_root != NULL) {
+ sysfs_remove_file(dfx_ctx->dfx_root,
+ &dfx_ctx->srqc_ctx.kattr.attr);
+
+ sysfs_remove_file(dfx_ctx->dfx_root,
+ &dfx_ctx->cqc_ctx.kattr.attr);
+
+ sysfs_remove_file(dfx_ctx->dfx_root,
+ &dfx_ctx->qpc_ctx.kattr.attr);
+
+ kobject_put(dfx_ctx->dfx_root);
+
+ dfx_ctx->dfx_root = NULL;
+ }
+}
+
+void roce5_remove_sysfs(struct roce5_device *rdev)
+{
+ roce5_remove_dfx_sub_sysfs(&rdev->dfx_ctx);
+ roce5_remove_ecn_sysfs(rdev);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_sysfs.h b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_sysfs.h
new file mode 100644
index 000000000..814f29ddc
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_sysfs.h
@@ -0,0 +1,241 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_SYSFS_H
+#define ROCE_SYSFS_H
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/kobject.h>
+#include "roce_ucc_sysfs.h"
+#include "roce_multipath_sysfs.h"
+
+#define ROCE_MIN_QPN 2
+#define BYTE_TO_BIT 8
+
+#define PRI_ARRAY_LEN 8
+
+#define ROCE_MAX_PORT_CNT 8
+#define ROCE_MAX_PF_NUM 32
+
+#define ROCE_ENABLE_CHECK_MASK 0xfffffffe
+
+/* ECN VER */
+#define ECN_VER_DCQCN 0
+#define ECN_VER_PATHQCN 1
+
+#define FLOW_CTRL_UNIT_QP 0
+#define FLOW_CTRL_UNIT_IP 1
+
+enum { ROCE_DCQCN_NP = 0, ROCE_DCQCN_RP = 1 };
+
+enum {
+ ROCE_CC_PARAM_INVALID = 0,
+ ROCE_CC_PARAM_V1 = 1,
+ ROCE_CC_PARAM_V2 = 2,
+};
+
+#define HRN0_K_MAGIC_NUM_3_SYSFS 3
+#define HRN0_K_MAGIC_NUM_7_SYSFS 7
+#define HRN0_K_MAGIC_NUM_8_SYSFS 8
+#define HRN0_K_MAGIC_NUM_M_SYSFS 1000000
+
+#define to_roce5_ecn_ctx(_kobj) \
+ container_of(_kobj, struct roce5_ecn_ctx, ecn_root)
+#define to_roce5_ecn_np_ctx(_kobj) \
+ container_of(_kobj, struct roce5_ecn_np_ctx, ecn_np_root)
+#define to_roce5_ecn_rp_ctx(_kobj) \
+ container_of(_kobj, struct roce5_ecn_rp_ctx, ecn_rp_root)
+#define to_roce5_ecn_ldcp_ctx(_kobj) \
+ container_of(_kobj, struct roce5_ecn_ldcp_ctx, ecn_ldcp_root)
+
+#define ROCE5_PARAM_CHECK_BOUND(val, min, max) \
+ ((val) < (min)) || ((val) > (max))
+
+#define INIT_ROCE_KOBJ_ATTR(_name, _mode, _show, _store) \
+ { \
+ .attr = { .name = __stringify(_name), .mode = _mode }, \
+ .show = (_show), .store = (_store), \
+ }
+
+#define ROCE_ATTR_RW(_name, _show, _store) \
+ static struct kobj_attribute roce_attr_##_name = INIT_ROCE_KOBJ_ATTR( \
+ _name, (S_IWUSR | S_IRUSR | S_IRGRP), (_show), (_store))
+
+#define ROCE_ATTR_PTR(_name) (&roce_attr_##_name.attr)
+
+#define ROCE_CC_ALGO_TEST_BIT(bitmap, cc_algo) (!!(bitmap & (1U << cc_algo)))
+
+struct roce5_prio_enable_ctx {
+ struct kobj_attribute enable;
+ void *ecn_enable_ctx;
+ u32 prio_en;
+ u32 prio;
+};
+
+struct roce5_ip_prio_enable_ctx {
+ struct kobj_attribute ip_enable;
+ void *ecn_ip_enable_ctx;
+ u32 prio_en;
+ u32 prio;
+};
+
+struct roce5_ecn_ip_enable_ctx {
+ struct kobject *ip_enable_root;
+ struct roce5_ip_prio_enable_ctx ip_prio_enable[PRI_ARRAY_LEN];
+};
+
+struct roce5_ecn_enable_ctx {
+ struct kobject *enable_root;
+ struct roce5_prio_enable_ctx prio_enable[PRI_ARRAY_LEN];
+ u32 np_rp;
+};
+
+struct roce5_dfx_qpc_ctx {
+ struct kobj_attribute kattr;
+};
+
+struct roce5_dfx_cqc_ctx {
+ struct kobj_attribute kattr;
+};
+
+struct roce5_dfx_srqc_ctx {
+ struct kobj_attribute kattr;
+};
+
+struct roce5_dfx_ctx {
+ struct kobject *dfx_root;
+ struct roce5_dfx_qpc_ctx qpc_ctx;
+ struct roce5_dfx_cqc_ctx cqc_ctx;
+ struct roce5_dfx_srqc_ctx srqc_ctx;
+};
+
+struct roce5_ecn_rp_ctx {
+ struct kobject ecn_rp_root;
+ u32 alpha_dec_period;
+ u32 rate_dec_period;
+ u32 rate_inc_period;
+ u32 factor_gita;
+ u32 initial_alpha;
+ u32 rate_inc_ai;
+ u32 rate_inc_hai;
+ u32 rate_first_set;
+ u32 rate_target_clamp;
+ u32 token_period;
+ u32 min_rate;
+ u32 bypass;
+ struct roce5_ecn_enable_ctx enable_ctx;
+};
+
+struct roce5_ecn_np_ctx {
+ struct kobject ecn_np_root;
+ u32 min_cnp_period;
+ u32 cnp_prio_enable;
+ u32 cnp_prio;
+ u32 rtt_rsp_prio;
+ u32 rtt_rsp_prio_enable;
+ u32 rtt_version;
+ u32 ecn_cnp_en;
+ u32 flow_ctrl_unit;
+ struct roce5_ecn_enable_ctx enable_ctx;
+};
+
+typedef struct roce5_ecn_ldcp_ctx {
+ struct kobject ecn_ldcp_root;
+ u32 wnd_min;
+ u32 wnd_default; /* initial default window size, unit: Byte */
+ u32 alpha;
+ u32 beta;
+ u32 gamma;
+ u32 eta;
+} roce5_ecn_ldcp_ctx_t;
+
+struct roce5_ecn_ctx {
+ struct kobject ecn_root;
+ struct mutex ecn_mutex;
+ u32 ecn_ver;
+ u32 cc_algo;
+ roce5_ecn_ldcp_ctx_t ldcp_ctx;
+ struct roce5_ecn_np_ctx np_ctx;
+ struct roce5_ecn_rp_ctx rp_ctx;
+ struct roce5_ecn_ip_enable_ctx ip_enable_ctx;
+ struct roce5_ecn_ucc_ctx ucc_ctx;
+ struct roce5_ecn_multipath_ctx multipath_ctx;
+};
+
+struct roce_cc_ecn_param {
+ u32 default_ip_enable_en;
+ u32 default_bypass;
+ u32 default_min_cnp_period;
+ u32 default_alpha_dec_period;
+ u32 default_rate_dec_period;
+ u32 default_rate_inc_period;
+ u32 default_factor_gita;
+ u32 default_initial_alpha;
+ u32 default_rate_inc_ai;
+ u32 default_rate_inc_hai;
+ u32 default_rate_first_set;
+ u32 default_rate_target_clamp;
+ u32 default_cnp_prio_enable;
+ u32 default_cnp_prio;
+ u32 default_token_period;
+ u32 default_min_rate;
+ u32 default_ecn_cnp_enable;
+ u32 default_flow_ctrl_unit;
+ u32 default_rtt_rsp_prio;
+ u32 default_rtt_rsp_prio_enable;
+ u32 default_rtt_version;
+
+ u32 max_rtt_version;
+ u32 min_bypass;
+ u32 max_bypass;
+ u32 min_rate_inc_hai;
+ u32 max_rate_inc_hai;
+ u32 min_rate_inc_ai;
+ u32 max_rate_inc_ai;
+ u32 min_initial_alpha;
+ u32 max_initial_alpha;
+ u32 min_rate_inc_period;
+ u32 max_rate_inc_period;
+ u32 min_alpha_dec_period;
+ u32 max_alpha_dec_period;
+ u32 min_token_period;
+ u32 max_token_period;
+ u32 min_flow_min_rate;
+ u32 max_flow_min_rate;
+ u32 min_rate_dec_period;
+ u32 max_rate_dec_period;
+ u32 min_min_cnp_period;
+ u32 max_min_cnp_period;
+ u32 min_factor_gita;
+ u32 max_factor_gita;
+ u32 min_rate_first_set;
+ u32 max_rate_first_set;
+
+ u32 default_ldcp_wnd_min;
+ u32 default_ldcp_wnd_default;
+ u32 default_ldcp_alpha;
+ u32 default_ldcp_beta;
+ u32 default_ldcp_gamma;
+ u32 default_ldcp_eta;
+
+ u32 min_ldcp_wnd_min;
+ u32 max_ldcp_wnd_min;
+ u32 min_ldcp_wnd_default;
+ u32 max_ldcp_wnd_default;
+ u32 min_ldcp_alpha;
+ u32 max_ldcp_alpha;
+ u32 min_ldcp_beta;
+ u32 max_ldcp_beta;
+ u32 min_ldcp_gamma;
+ u32 max_ldcp_gamma;
+ u32 min_ldcp_eta;
+ u32 max_ldcp_eta;
+};
+
+int roce5_update_ecn_param(const struct roce5_ecn_ctx *ecn_ctx);
+
+#endif //ROCE_SYSFS_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.c b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.c
new file mode 100644
index 000000000..e163f895b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
+
+
+#include "roce_sysfs.h"
+#include "roce_cc_format.h"
+#include "roce_mpu_cmd.h"
+#include "roce_cmd.h"
+#include "ccp_algo_format.h"
+#include "roce_kernel_compat_gen.h"
+
+#define MAX_STRING_FORMAT_LEN 64
+#define to_roce5_ecn_ucc_ctx(_kobj) \
+ container_of(_kobj, struct roce5_ecn_ucc_ctx, ecn_ucc_root)
+
+static char g_param_buffer[ROCE_UCC_MAX_PARAM_NUM][ROCE_UCC_PARAM_BUFF_LEN];
+static char g_param_show_tmp[ROCE_UCC_MAX_PARAM_NUM][ROCE_UCC_PARAM_BUFF_LEN];
+static char g_param_show_format[ROCE_UCC_MAX_PARAM_NUM][ROCE_UCC_PARAM_BUFF_LEN];
+
+static int roce5_ucc_store_input_check(struct kobject *kobj, const char *buf,
+ u8 param_index)
+{
+ if (kobj == NULL || buf == NULL) {
+ ROCE_ERR("kobj or buf is null\n");
+ return -EINVAL;
+ }
+
+ if (param_index >= ROCE_UCC_MAX_PARAM_NUM) {
+ ROCE_ERR("invalid index:%hhu.\n", param_index);
+ return -EINVAL;
+ }
+
+ if (strlen(buf) > (ROCE_UCC_PARAM_BUFF_LEN - 1)) {
+ ROCE_ERR("input buffer is beyond 1022.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int roce5_init_ucc_global_buffer(u8 param_index, const char *buf)
+{
+ int ret;
+ ret = memset_s(g_param_show_tmp[param_index],
+ sizeof(g_param_show_tmp[param_index]), 0,
+ sizeof(g_param_show_tmp[param_index]));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset buffer.(ret:%d)\n", ret);
+ return -EIO;
+ }
+
+ ret = strncpy_s(g_param_buffer[param_index],
+ sizeof(g_param_buffer[param_index]), buf,
+ sizeof(g_param_buffer[param_index]) - 1);
+ if (ret != 0) {
+ ROCE_ERR("Failed to strncpy buffer.(ret:%d)\n", ret);
+ return -EIO;
+ }
+
+ g_param_buffer[param_index][ROCE_UCC_PARAM_BUFF_LEN - 1] = '\0';
+
+ return 0;
+}
+
+static int check_key_unique(char (*pkey)[ROCE_UCC_MAX_KEY_SIZE], u8 key_num)
+{
+ u8 key_index = 0;
+
+ if (key_num >= ROCE_UCC_MAX_KEY_SIZE) {
+ ROCE_ERR("invalid key value:%hhu.\n", key_num);
+ return -EINVAL;
+ }
+
+ for (key_index = 0; key_index < key_num; key_index++) {
+ if (strcmp(pkey[key_index], pkey[key_num]) == 0) {
+ ROCE_ERR("key:%s is not unique.\n", pkey[key_num]);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int parse_each_line(char *param_line,
+ char (*pkey)[ROCE_UCC_MAX_KEY_SIZE], u8 key_num,
+ u32 *param_value, u8 *param_bits, u16 *sum_bits)
+{
+ u64 temp_value = 0;
+ u64 temp_bits = 0;
+ u64 temp_bit_sum = *sum_bits;
+ char extra = 0;
+ char value_str[ROCE_UCC_PARAM_VALUE_LEN] = { 0 };
+ char bits_str[ROCE_UCC_PARAM_BITS_LEN] = { 0 };
+
+ if (key_num >= ROCE_UCC_MAX_KEY_SIZE) {
+ ROCE_ERR("invalid key value:%hhu.\n", key_num);
+ return -EINVAL;
+ }
+
+ /* input of each line per per key:value:length perform parse, obtain value and length size, and check key whether repeat */
+ if (sscanf_s(param_line, " %31[^: ] : %10[0-9] : %2[0-9] %c",
+ pkey[key_num], (unsigned)sizeof(pkey[key_num]), value_str,
+ (unsigned)sizeof(value_str), bits_str,
+ (unsigned)sizeof(bits_str), &extra,
+ 1) == ROCE_UCC_LINE_PARAM_TH) {
+ if (kstrtoull(value_str, NUM_10, &temp_value) < 0) {
+ ROCE_ERR("invalid input value:%s.\n", value_str);
+ return -EINVAL;
+ }
+
+ if (kstrtoull(bits_str, NUM_10, &temp_bits) < 0) {
+ ROCE_ERR("invalid input bits:%s.\n", bits_str);
+ return -EINVAL;
+ }
+
+ if ((temp_bits == 0) || (temp_bits > TYPE_BITS(u32)) ||
+ (temp_value > BITS_VALUE(temp_bits))) {
+ ROCE_ERR("bits:%llu or value:%llu is invalid.\n",
+ temp_bits, temp_value);
+ return -EINVAL;
+ }
+
+ temp_bit_sum += temp_bits;
+ if (temp_bit_sum > TYPE_BITS(u32)) {
+ ROCE_ERR("the length of bits:%llu beyond 32.\n",
+ temp_bit_sum);
+ return -EINVAL;
+ }
+
+ if (check_key_unique(pkey, key_num) != 0) {
+ return -EINVAL;
+ }
+
+ *param_value = (u32)temp_value;
+ *param_bits = (u8)temp_bits;
+ *sum_bits = (u16)temp_bit_sum;
+ return 0;
+ }
+
+ ROCE_ERR("param format is wrong, please enter key:value:length param, "
+ "value less than 4294967296, length less than 33.\n");
+ return -EINVAL;
+}
+
+static int roce5_parse_ucc_param(u32 *ucc_param, char *param_buffer,
+ char *show_tmpkey)
+{
+ u8 key_num = 0;
+ u32 temp_param = 0;
+ /* param_value\param_bits used to store each line parse of values size and so occupy bit width result */
+ u32 param_value = 0;
+ u8 param_bits = 0;
+ u16 sum_bits = 0;
+ /* param_line\ppbuffer used for input parameters partinterval parse */
+ char *param_line = NULL;
+ char **ppbuffer = ¶m_buffer;
+
+ char(*pkey)[ROCE_UCC_MAX_KEY_SIZE] = NULL;
+ char arr_tempkey[ROCE_UCC_MAX_KEY_NUM][ROCE_UCC_MAX_KEY_SIZE] = { 0 };
+ char append_buff[ROCE_UCC_LINE_MAX_LEN] = { 0 };
+ pkey = arr_tempkey;
+
+ while ((param_line = strsep(ppbuffer, "\n")) != NULL) {
+ if (*param_line == '\0') {
+ break;
+ }
+ /* per per key:value:length parse input of each one line */
+ if (parse_each_line(param_line, pkey, key_num, ¶m_value,
+ ¶m_bits, &sum_bits) != 0) {
+ return -EIO;
+ }
+
+ if (snprintf_s(append_buff, ROCE_UCC_LINE_MAX_LEN,
+ ROCE_UCC_LINE_MAX_LEN - 1, "%s:%u:%hhu\n",
+ pkey[key_num], param_value, param_bits) < 0) {
+ ROCE_ERR("snprintf_s err!\n");
+ return -EIO;
+ }
+
+ if (strncat_s(show_tmpkey, ROCE_UCC_PARAM_BUFF_LEN, append_buff,
+ ROCE_UCC_PARAM_BUFF_LEN - strlen(show_tmpkey) -
+ 1) != 0) {
+ ROCE_ERR("strncat_s err!\n");
+ return -EIO;
+ }
+ key_num++;
+ temp_param = key_num > 1 ? ((temp_param << param_bits) +
+ param_value) :
+ param_value;
+ }
+
+ if (sum_bits < TYPE_BITS(u32)) {
+ temp_param = temp_param << (TYPE_BITS(u32) - sum_bits);
+ }
+
+ if (ucc_param != NULL) {
+ *ucc_param = temp_param;
+ }
+ return 0;
+}
+
+static int roce5_store_ucc_param_inner(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, u8 param_index)
+{
+ int ret = 0;
+ u32 ucc_param = 0;
+ u32 old_ucc_param = 0;
+ struct roce5_ecn_ctx *ecn_ctx = NULL;
+ struct roce5_ecn_ucc_ctx *ecn_ucc_ctx = NULL;
+
+ if (roce5_ucc_store_input_check(kobj, buf, param_index) != 0) {
+ return -EINVAL;
+ }
+
+ ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ ecn_ucc_ctx = to_roce5_ecn_ucc_ctx(kobj);
+
+ if (roce5_init_ucc_global_buffer(param_index, buf) != 0) {
+ return -EIO;
+ }
+
+ if (roce5_parse_ucc_param(&ucc_param, g_param_buffer[param_index],
+ g_param_show_tmp[param_index]) != 0) {
+ return -EIO;
+ }
+
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ if (strncpy_s(g_param_show_format[param_index],
+ sizeof(g_param_show_format[param_index]),
+ g_param_show_tmp[param_index],
+ sizeof(g_param_show_format[param_index]) - 1) != 0) {
+ ROCE_ERR("Failed to strncpy buffer.\n");
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+
+ if ((ecn_ucc_ctx != NULL) &&
+ (ecn_ucc_ctx->param[param_index] != ucc_param)) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_ucc_param = ecn_ucc_ctx->param[param_index];
+ ecn_ucc_ctx->param[param_index] = ucc_param;
+ ret = (ssize_t)roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_ucc_ctx->param[param_index] = old_ucc_param;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return 0;
+}
+
+ssize_t roce5_show_ucc_param(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct roce5_ucc_param_ctx *ucc_param =
+ (struct roce5_ucc_param_ctx *)to_roce5_ucc_param_ctx(attr);
+ return sprintf_s(buf, sizeof(g_param_show_format[ucc_param->param_id]),
+ "%s", g_param_show_format[ucc_param->param_id]);
+}
+
+ssize_t roce5_store_ucc_param(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct roce5_ucc_param_ctx *ucc_param =
+ (struct roce5_ucc_param_ctx *)to_roce5_ucc_param_ctx(attr);
+ return (roce5_store_ucc_param_inner(kobj, attr, buf,
+ ucc_param->param_id) == 0) ?
+ (ssize_t)count :
+ -EIO;
+}
+
+static ssize_t roce5_show_algo_mode(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce5_ecn_ucc_ctx *ecn_ucc_ctx = to_roce5_ecn_ucc_ctx(kobj);
+
+ if ((attr == NULL) || (buf == NULL)) {
+ ROCE_ERR("attr or buf is null");
+ return -EINVAL;
+ }
+
+ switch ((int)ecn_ucc_ctx->algo_mode) {
+ case CCP_ALGO_MODE_CWND:
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%u\n",
+ (u32)CCP_ALGO_MODE_CWND);
+ case CCP_ALGO_MODE_RATE:
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%u\n",
+ (u32)CCP_ALGO_MODE_RATE);
+ default:
+ break;
+ }
+ return sprintf_s(buf, MAX_STRING_FORMAT_LEN, "%s\n", "error_type");
+}
+
+static ssize_t roce5_store_algo_mode(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct roce5_ecn_ctx *ecn_ctx = to_roce5_ecn_ctx(kobj->parent);
+ struct roce5_ecn_ucc_ctx *ecn_ucc_ctx = to_roce5_ecn_ucc_ctx(kobj);
+ u32 old_algo_mode = 0;
+ int algo_mode = 0;
+ int ret;
+ char remaining;
+
+ if ((attr == NULL) || (buf == NULL)) {
+ ROCE_ERR("attr or buf is null");
+ return -EINVAL;
+ }
+
+ ret = sscanf_s(buf, "%d %c", &algo_mode, &remaining, 1);
+ if (ret != 1) {
+ ROCE_ERR("Invalid input, algo_mode should be unsigned int\n");
+ return -EIO;
+ }
+
+ if (algo_mode != CCP_ALGO_MODE_CWND &&
+ algo_mode != CCP_ALGO_MODE_RATE) {
+ ROCE_ERR("Invalid algo_mode(%d),buf(%s)\n", algo_mode, buf);
+ return -EIO;
+ }
+
+ if (ecn_ucc_ctx->algo_mode != (u32)algo_mode) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_algo_mode = ecn_ucc_ctx->algo_mode;
+ ecn_ucc_ctx->algo_mode = (u32)algo_mode;
+ ret = roce5_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ROCE_ERR("Failed to update algo_mode(%d), ret(%d).",
+ algo_mode, ret);
+ ecn_ucc_ctx->algo_mode = old_algo_mode;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+ROCE_UCC_PARAM_RW(param0, 0);
+ROCE_UCC_PARAM_RW(param1, 1);
+ROCE_UCC_PARAM_RW(param2, 2);
+ROCE_UCC_PARAM_RW(param3, 3);
+ROCE_UCC_PARAM_RW(param4, 4);
+ROCE_UCC_PARAM_RW(param5, 5);
+ROCE_UCC_PARAM_RW(param6, 6);
+ROCE_UCC_PARAM_RW(param7, 7);
+ROCE_UCC_PARAM_RW(param8, 8);
+ROCE_UCC_PARAM_RW(param9, 9);
+ROCE_UCC_PARAM_RW(param10, 10);
+ROCE_UCC_PARAM_RW(param11, 11);
+ROCE_UCC_PARAM_RW(param12, 12);
+ROCE_UCC_PARAM_RW(param13, 13);
+ROCE_UCC_PARAM_RW(param14, 14);
+ROCE_UCC_PARAM_RW(param15, 15);
+ROCE_ATTR_RW(algo_mode, roce5_show_algo_mode, roce5_store_algo_mode);
+
+static struct attribute *ecn_ucc_ctx_attrs[] = {
+ ROCE_UCC_PARAM_ATTR_PTR(param0), ROCE_UCC_PARAM_ATTR_PTR(param1),
+ ROCE_UCC_PARAM_ATTR_PTR(param2), ROCE_UCC_PARAM_ATTR_PTR(param3),
+ ROCE_UCC_PARAM_ATTR_PTR(param4), ROCE_UCC_PARAM_ATTR_PTR(param5),
+ ROCE_UCC_PARAM_ATTR_PTR(param6), ROCE_UCC_PARAM_ATTR_PTR(param7),
+ ROCE_UCC_PARAM_ATTR_PTR(param8), ROCE_UCC_PARAM_ATTR_PTR(param9),
+ ROCE_UCC_PARAM_ATTR_PTR(param10), ROCE_UCC_PARAM_ATTR_PTR(param11),
+ ROCE_UCC_PARAM_ATTR_PTR(param12), ROCE_UCC_PARAM_ATTR_PTR(param13),
+ ROCE_UCC_PARAM_ATTR_PTR(param14), ROCE_UCC_PARAM_ATTR_PTR(param15),
+ ROCE_ATTR_PTR(algo_mode), NULL,
+};
+
+static void roce_ecn_ucc_sysfs_release(struct kobject *kobj)
+{
+}
+
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+static const struct attribute_group ecn_ucc_ctx_attr_grp = {
+ .attrs = ecn_ucc_ctx_attrs,
+};
+
+static const struct attribute_group *ecn_ucc_ctx_groups[] = {
+ &ecn_ucc_ctx_attr_grp,
+ NULL,
+};
+#endif
+
+static struct kobj_type roce_ecn_ucc_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .release = roce_ecn_ucc_sysfs_release,
+#if defined(KBOJ_TYPE_HAVE_ATTRS_GROUP)
+ .default_groups = ecn_ucc_ctx_groups,
+#else
+ .default_attrs = ecn_ucc_ctx_attrs,
+#endif
+};
+
+int roce5_update_ucc_param(struct roce5_device *rdev,
+ const struct roce5_ecn_ctx *ecn_ctx)
+{
+ roce_ucc_param_s ucc_param;
+ int ret;
+ int param_idx = 0;
+
+ if (ecn_ctx->cc_algo != ROCE_CC_USER_A_ALGO &&
+ ecn_ctx->cc_algo != ROCE_CC_USER_B_ALGO) {
+ ROCE_DEV_INFO(
+ rdev,
+ "func_id(%d) cc_algo(%u) is not user algo, ignore update.",
+ rdev->glb_func_id, ecn_ctx->cc_algo);
+ return 0;
+ }
+ (void)memset_s(&ucc_param, sizeof(ucc_param), 0, sizeof(ucc_param));
+
+ for (; param_idx < ROCE_UCC_MAX_PARAM_NUM; param_idx++) {
+ ucc_param.param[param_idx] = ecn_ctx->ucc_ctx.param[param_idx];
+ }
+
+ ret = roce5_set_sysfs_cfg_param(rdev->hwdev, rdev->glb_func_id,
+ (u32 *)(void *)&ucc_param,
+ sizeof(roce_ucc_param_s),
+ (u16)ROCE_MPU_CMD_CC_CFG_UCC_PARAM);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set user algo param, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ }
+
+ return ret;
+}
+
+int roce5_init_ecn_ucc_sysfs(struct kobject *kobj,
+ struct roce5_ecn_ucc_ctx *ecn_ucc_ctx)
+{
+ int ret = 0;
+ int param_idx = 0;
+
+ if (ecn_ucc_ctx == NULL) {
+ pr_err_ratelimited("[ROCE, ERR] %s: ecn_ucc_ctx is null\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ ecn_ucc_ctx->algo_mode = CCP_ALGO_MODE_CWND;
+ for (; param_idx < ROCE_UCC_MAX_PARAM_NUM; param_idx++) {
+ ecn_ucc_ctx->param[param_idx] = ROCE_DEFAULT_UCC_PARAM;
+ }
+
+ ret = kobject_init_and_add(&ecn_ucc_ctx->ecn_ucc_root,
+ &roce_ecn_ucc_ktype, kobj, "roce5_ucc");
+ if (ret != 0) {
+ ROCE_ERR("Failed to add kobject roce5_ucc.(ret:%d)\n", ret);
+ kobject_put(&ecn_ucc_ctx->ecn_ucc_root);
+ return ret;
+ }
+
+ return 0;
+}
+
+void roce5_remove_ecn_ucc_sysfs(struct kobject *kobj,
+ struct roce5_ecn_ucc_ctx *ecn_ucc_ctx)
+{
+ if (ecn_ucc_ctx == NULL) {
+ ROCE_ERR("ecn_ucc_ctx is null\n");
+ return;
+ }
+
+ kobject_put(&ecn_ucc_ctx->ecn_ucc_root);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.h b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.h
new file mode 100644
index 000000000..bbbe92b30
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/dev/sysfs/roce_ucc_sysfs.h
@@ -0,0 +1,73 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
+
+
+#ifndef ROCE_UCC_SYSFS_H
+#define ROCE_UCC_SYSFS_H
+
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/kobject.h>
+
+#define ROCE_UCC_MAX_PARAM_NUM 16
+#define ROCE_UCC_PARAM_BUFF_LEN 1024
+#define ROCE_DEFAULT_UCC_PARAM 0
+#define ROCE_UCC_MAX_KEY_SIZE 32
+#define ROCE_UCC_MAX_KEY_NUM 32
+#define ROCE_UCC_LINE_MAX_LEN 64
+#define ROCE_UCC_PARAM_VALUE_LEN 11
+#define ROCE_UCC_PARAM_BITS_LEN 3
+#define ROCE_UCC_LINE_PARAM_TH 3
+
+#define CHAR_0 '0'
+#define CHAR_9 '9'
+#define NUM_10 10
+#define ROCE_USER_CC_ID_LABLE_LEN 8
+#define ROCE_USER_CC_ID_MAX_LEN (ROCE_USER_CC_ID_LABLE_LEN + 2)
+
+#define TYPE_BITS(type) (sizeof(type) * 8)
+#define BITS_VALUE(bits) (((u64)1 << (bits)) - 1)
+
+/* forward-declaration */
+struct roce5_device;
+struct roce5_ecn_ctx;
+
+typedef struct roce_ucc_param {
+ u32 param[ROCE_UCC_MAX_PARAM_NUM];
+} roce_ucc_param_s;
+
+struct roce5_ecn_ucc_ctx {
+ struct kobject ecn_ucc_root;
+ u32 algo_mode;
+ u32 param[ROCE_UCC_MAX_PARAM_NUM];
+};
+
+struct roce5_ucc_param_ctx {
+ struct kobj_attribute param;
+ u32 param_id;
+};
+
+ssize_t roce5_show_ucc_param(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf);
+ssize_t roce5_store_ucc_param(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count);
+#define ROCE_UCC_PARAM_RW(_name, _idx) \
+ static struct roce5_ucc_param_ctx roce_ucc_attr_##_name = { \
+ .param = INIT_ROCE_KOBJ_ATTR( \
+ _name, (S_IWUSR | S_IRUSR | S_IRGRP), \
+ roce5_show_ucc_param, roce5_store_ucc_param), \
+ .param_id = (_idx), \
+ }
+
+#define ROCE_UCC_PARAM_ATTR_PTR(_name) (&roce_ucc_attr_##_name.param.attr)
+#define to_roce5_ucc_param_ctx(_kattr) \
+ container_of(_kattr, struct roce5_ucc_param_ctx, param)
+
+int roce5_update_ucc_param(struct roce5_device *rdev,
+ const struct roce5_ecn_ctx *ecn_ctx);
+int roce5_init_ecn_ucc_sysfs(struct kobject *kobj,
+ struct roce5_ecn_ucc_ctx *ecn_ucc_ctx);
+void roce5_remove_ecn_ucc_sysfs(struct kobject *kobj,
+ struct roce5_ecn_ucc_ctx *ecn_ucc_ctx);
+
+#endif /* ROCE_UCC_SYSFS_H */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_main_chip_ext.c b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_main_chip_ext.c
new file mode 100644
index 000000000..145904486
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_main_chip_ext.c
@@ -0,0 +1,13 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2020-2024. All rights reserved.
+
+
+#include "roce_main_extension.h"
+#include "roce_mr_chip_ext.h"
+
+void roce5_init_dev_ext_handlers(struct roce5_device *rdev)
+{
+ rdev->ib_dev.check_mr_status = roce5_check_mr_status;
+ rdev->ib_dev.reg_user_fast_mr = roce5_reg_user_fast_mr;
+ rdev->ib_dev.map_frmr_sg = roce5_map_user_frmr_sg;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_main_chip_ext.h b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_main_chip_ext.h
new file mode 100644
index 000000000..a5f0847f8
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_main_chip_ext.h
@@ -0,0 +1,17 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_MAIN_CHIP_EXT_C
+#define ROCE_MAIN_CHIP_EXT_C
+
+#define ROCE_UVERBS_CMD_EXT_MASK \
+ ((1ULL << IB_USER_VERBS_CMD_CREATE_DCT) | \
+ (1ULL << IB_USER_VERBS_CMD_QUERY_DCT) | \
+ (1ULL << IB_USER_VERBS_CMD_ARM_DCT) | \
+ (1ULL << IB_USER_VERBS_CMD_DESTROY_DCT) | \
+ (1ULL << IB_USER_VERBS_CMD_CREATE_MR) | \
+ (1ULL << IB_USER_VERBS_CMD_REG_FAST_MR) | \
+ (1ULL << IB_USER_VERBS_CMD_DEREG_FAST_MR) | \
+ (1ULL << IB_USER_VERBS_CMD_MAP_FRMR_SG))
+
+#endif /* ROCE_MAIN_CHIP_EXT_C */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_mr_chip_ext.c b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_mr_chip_ext.c
new file mode 100644
index 000000000..c460ca8a5
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_mr_chip_ext.c
@@ -0,0 +1,348 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#include "roce_mr.h"
+#include "roce_infra.h"
+#include "roce_mr_extension.h"
+#include "roce_main_extension.h"
+#include "roce_restore.h"
+#include "hmm_common.h"
+#include "roce_user.h"
+
+int roce5_check_alloc_mr_type(enum ib_mr_type mr_type)
+{
+ int ret = 0;
+
+ if (mr_type != IB_MR_TYPE_MEM_REG && mr_type != IB_MR_INDIRECT_REG &&
+ mr_type != IB_MR_TYPE_FAST_MR) {
+ ret = -EINVAL;
+ ROCE_ERR("mr_type is invalid. mr_type:%u", mr_type);
+ }
+
+ return ret;
+}
+
+enum rdma_mr_type roce5_get_mrtype(enum ib_mr_type ib_mr_type)
+{
+ switch (ib_mr_type) {
+ case IB_MR_TYPE_MEM_REG:
+ return RDMA_DMA_MR;
+
+ case IB_MR_INDIRECT_REG:
+ return RDMA_INDIRECT_MR;
+
+ case IB_MR_TYPE_FAST_MR:
+ return RDMA_FRMR;
+
+ default:
+ return RDMA_DMA_MR;
+ }
+}
+
+static int roce5_alloc_usr_frmr(struct ib_pd *ibpd, struct ib_udata *udata,
+ struct roce5_reg_frmr_cmd *ucmd,
+ struct roce5_device **rdev,
+ struct roce5_mr **rmr)
+{
+ struct ib_umem **fumem = NULL;
+ if (ibpd == NULL) {
+ ROCE_ERR("Ibpd is null");
+ return -EINVAL;
+ }
+
+ if (udata == NULL) {
+ ROCE_ERR("Udata is null");
+ return -EINVAL;
+ }
+
+ *rdev = to_roce5_dev(ibpd->device);
+
+ if (ib_copy_from_udata(ucmd, udata, sizeof(*ucmd))) {
+ ROCE_DEV_ERR((*rdev),
+ "Failed to copy_from_udata while creating frmr");
+ return -EFAULT;
+ }
+
+ *rmr = (struct roce5_mr *)kzalloc(sizeof(struct roce5_mr), GFP_KERNEL);
+ if (*rmr == NULL) {
+ ROCE_DEV_ERR((*rdev), "Failed to alloc memory for roce mr");
+ return -ENOMEM;
+ }
+
+ fumem = (struct ib_umem **)kzalloc(
+ sizeof(struct ib_umem *) * ROCE5_FRMR_UMEM_NUM, GFP_KERNEL);
+ if (fumem == NULL) {
+ ROCE_DEV_ERR((*rdev), "Failed to alloc memory for frmr umem");
+ kfree(*rmr);
+ return -ENOMEM;
+ }
+ (*rmr)->fumem = fumem;
+ return 0;
+}
+
+static int roce5_get_frmr_umem(struct roce5_mr *rmr, struct ib_pd *ibpd,
+ struct roce5_reg_frmr_cmd *ucmd,
+ struct roce5_device *rdev)
+{
+ rmr->umem = ib_umem_get(ibpd->uobject->context, ucmd->pbl_vaddr,
+ PAGE_SIZE_4K, 0, 0);
+ if (rmr->umem == NULL) {
+ ROCE_DEV_ERR(rdev, "Rmr->umem is null");
+ return -ENOMEM;
+ }
+
+ if (IS_ERR(rmr->umem)) {
+ ROCE_DEV_ERR(rdev, "Failed to get ib umem, func_id(%d)",
+ rdev->glb_func_id);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int roce5_init_frmr_attr(u64 *pbl_paddr, struct roce5_mr *rmr,
+ struct roce5_device *rdev, struct ib_pd *ibpd)
+{
+ int ret;
+ u32 mpt_xid_mode;
+ struct roce5_pd *rpd = NULL;
+
+ *pbl_paddr = sg_dma_address(rmr->umem->sg_head.sgl);
+ if (*pbl_paddr == 0ULL) {
+ ROCE_DEV_ERR(rdev, "Invalid pbl_paddr");
+ return -EINVAL;
+ }
+
+ rmr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE;
+ mpt_xid_mode = roce5_get_mpt_xid_mode(rdev);
+ ret = roce5_alloc_tpt(rdev, &rmr->rdmamr, ROCE_FRMR_MAX_PAGES,
+ PAGE_SHIFT, mpt_xid_mode);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc mpt and mtt, ret(%d)", ret);
+ return ret;
+ }
+
+ rpd = to_roce5_pd(ibpd);
+ roce5_set_rdma_mr(&rmr->rdmamr, RDMA_FRMR, rpd->pdn, 0ULL, 0ULL,
+ ROCE5_MR_DEFAULT_ACCESS);
+
+ return 0;
+}
+
+struct ib_mr *roce5_reg_user_fast_mr(struct ib_pd *ibpd, struct ib_udata *udata)
+{
+ int ret;
+ struct roce5_device *rdev = NULL;
+ struct roce5_mr *rmr = NULL;
+ struct roce5_reg_frmr_cmd ucmd;
+ u64 pbl_paddr;
+
+ ret = roce5_alloc_usr_frmr(ibpd, udata, &ucmd, &rdev, &rmr);
+ if (ret != 0) {
+ ROCE_ERR("Failed to pre check, ret(%d)", ret);
+ goto err_out;
+ }
+
+ ret = roce5_get_frmr_umem(rmr, ibpd, &ucmd, rdev);
+ if (ret != 0) {
+ goto err_ib_umem_get;
+ }
+
+ /* Use valloc to allocate a page of memory, just need to get the first physical address */
+ ret = roce5_init_frmr_attr(&pbl_paddr, rmr, rdev, ibpd);
+ if (ret != 0) {
+ goto err_pbl_addr;
+ }
+
+ ret = hmm_rdma_enable_mpt(rdev->lld_dev, rdev->hwdev, &(rmr->rdmamr),
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to enable mpt of frmr, ret(%d)",
+ ret);
+ goto err_enable_mpt;
+ }
+
+ /* User mode also needs to send out pbl_paddr */
+ if (ib_copy_to_udata(udata, &pbl_paddr, sizeof(u64)) != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to copy data to user space, func_id(%d)",
+ rdev->glb_func_id);
+ ret = -EFAULT;
+ goto err_enable_mpt;
+ }
+
+ rmr->ibmr.lkey = rmr->rdmamr.key;
+ rmr->ibmr.rkey = rmr->rdmamr.key;
+
+ return &rmr->ibmr;
+
+err_enable_mpt:
+ roce5_free_tpt(rdev, &rmr->rdmamr);
+
+err_pbl_addr:
+ ib_umem_release(rmr->umem);
+
+err_ib_umem_get:
+ kfree(rmr->fumem, sizeof(struct ib_umem *) * ROCE5_FRMR_UMEM_NUM);
+ kfree(rmr);
+
+err_out:
+ return (struct ib_mr *)ERR_PTR((long)ret);
+}
+
+int roce5_frmr_check_user_param(struct ib_mr *ibmr, unsigned int page_num,
+ struct ib_udata *udata)
+{
+ if (ibmr == NULL) {
+ ROCE_ERR("Ibmr is null");
+ return -EINVAL;
+ }
+
+ if (page_num == 0 || page_num > ROCE5_FRMR_UMEM_NUM) {
+ ROCE_ERR("page_num(%d) is invalid", page_num);
+ return -EINVAL;
+ }
+
+ if (udata == NULL) {
+ ROCE_ERR("udata is NULL");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void roce5_frmr_free_addr_list(unsigned long long *va_list,
+ unsigned long long *pa_list)
+{
+ vfree(va_list);
+ vfree(pa_list);
+}
+
+int roce5_frmr_alloc_addr_list(struct roce5_device *rdev,
+ unsigned long long **va_list,
+ unsigned long long **pa_list, u32 len)
+{
+ int ret;
+ unsigned long long *val = NULL;
+ unsigned long long *pal = NULL;
+
+ val = (unsigned long long *)vmalloc(len);
+ if (val == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to vmalloc va_list");
+ return -EAGAIN;
+ }
+ pal = (unsigned long long *)vmalloc(len);
+ if (pal == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to vmalloc pa_list");
+ vfree(val);
+ return -EAGAIN;
+ }
+ ret = memset_s(val, len, 0, len);
+ if (ret) {
+ ROCE_DEV_ERR(rdev, "Failed to memset va_list.(ret:%d)", ret);
+ ret = -ENOMEM;
+ goto err_free;
+ }
+ ret = memset_s(pal, len, 0, len);
+ if (ret) {
+ ROCE_DEV_ERR(rdev, "Failed to memset pa_list.(ret:%d)", ret);
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ *va_list = val;
+ *pa_list = pal;
+ return 0;
+
+err_free:
+ roce5_frmr_free_addr_list(val, pal);
+ return ret;
+}
+
+static int process_va_list_and_allocate_umem(
+ struct roce5_mr *rmr, struct roce5_device *rdev, struct ib_mr *ibmr,
+ unsigned long long *va_list, unsigned long long *pa_list, u32 page_num)
+{
+ u32 i;
+ int ret;
+ for (i = 0; i < page_num; i++) {
+ ROCE_DEV_INFO(rdev, "i:%d, va(%llu)", i, va_list[i]);
+ rmr->fumem[i] = ib_umem_get(ibmr->pd->uobject->context,
+ va_list[i], FRMR_PAGE_SIZE, 0, 0);
+ if (IS_ERR(rmr->fumem[i])) {
+ ret = (int)PTR_ERR(rmr->fumem[i]);
+ roce5_free_frmr_umem(rmr->fumem, i - 1);
+ ROCE_DEV_ERR(rdev,
+ "Alloc umem failed, func_id(%d) err:%d",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ /* use valloc allocate a page of memory, only needs need get the a physical address */
+ pa_list[i] = sg_dma_address(rmr->fumem[i]->sg_head.sgl);
+ ROCE_DEV_INFO(rdev, "PA_LIST:%llu", pa_list[i]);
+ if (pa_list[i] == 0ULL) {
+ ret = -EINVAL;
+ roce5_free_frmr_umem(rmr->fumem, i);
+ ROCE_DEV_ERR(rdev, "Invalid physicaL addr index(%d)",
+ i);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+int roce5_map_user_frmr_sg(struct ib_mr *ibmr, unsigned int page_num,
+ struct ib_udata *udata)
+{
+ struct roce5_mr *rmr = NULL;
+ struct roce5_device *rdev = NULL;
+ int ret;
+ unsigned long long *va_list = NULL;
+ unsigned long long *pa_list = NULL;
+ u32 len;
+
+ ret = roce5_frmr_check_user_param(ibmr, page_num, udata);
+ if (ret) {
+ return ret;
+ }
+
+ len = page_num * sizeof(unsigned long long);
+ rmr = to_roce5_mr(ibmr);
+ rdev = to_roce5_dev(ibmr->device);
+ ret = roce5_frmr_alloc_addr_list(rdev, &va_list, &pa_list, len);
+ if (ret) {
+ return ret;
+ }
+
+ ROCE_DEV_INFO(rdev, "func_id(%d), page_num(%u)", rdev->glb_func_id,
+ page_num);
+
+ ret = ib_copy_from_udata((void *)va_list, udata, len);
+ if (ret) {
+ ROCE_DEV_ERR(rdev, "Failed to copy udata, ret(%d)", ret);
+ goto err_free;
+ }
+
+ ret = process_va_list_and_allocate_umem(rmr, rdev, ibmr, va_list,
+ pa_list, page_num);
+ if (ret != 0) {
+ goto err_free;
+ }
+
+ /* 讲 pa information pass to user mode */
+ if (ib_copy_to_udata(udata, pa_list, len)) {
+ ret = -EFAULT;
+ ROCE_DEV_ERR(rdev, "Failed to copy udata, func_id(%d)",
+ rdev->glb_func_id);
+ goto err_free;
+ }
+
+ rmr->fumem_nr = page_num;
+ roce5_frmr_free_addr_list(va_list, pa_list);
+ return 0;
+
+err_free:
+ rmr->fumem_nr = 0;
+ roce5_frmr_free_addr_list(va_list, pa_list);
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_mr_chip_ext.h b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_mr_chip_ext.h
new file mode 100644
index 000000000..c206ca7f6
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_mr_chip_ext.h
@@ -0,0 +1,24 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_MR_CHIP_EXT_H
+#define ROCE_MR_CHIP_EXT_H
+
+#include <linux/types.h>
+#include <linux/io-mapping.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_umem.h>
+
+int roce5_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
+ struct ib_mr_status *mr_status);
+struct ib_mr *roce5_reg_user_fast_mr(struct ib_pd *ibpd,
+ struct ib_udata *udata);
+int roce5_map_user_frmr_sg(struct ib_mr *ibmr, unsigned int page_num,
+ struct ib_udata *udata);
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_qp_chip_ext.c b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_qp_chip_ext.c
new file mode 100644
index 000000000..903da9898
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_qp_chip_ext.c
@@ -0,0 +1,44 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+
+
+#include "roce_qp_extension.h"
+
+void roce5_set_qp_dif_attr(struct roce5_qp *rqp,
+ const struct ib_qp_init_attr *init_attr,
+ const struct roce5_device *rdev)
+{
+ if (((unsigned int)init_attr->create_flags &
+ IB_QP_CREATE_SIGNATURE_EN) != 0) {
+ rqp->signature_en = true;
+ ROCE_DEV_INFO(rdev,
+ "func(%d) qp(%u) roce5_create_qp signature_en.",
+ rdev->glb_func_id, rqp->qpn);
+ }
+
+ if (((unsigned int)init_attr->create_flags &
+ IB_QP_CREATE_SIGNATURE_DOUBLE_SGL) != 0) {
+ rqp->double_sgl_mode = 1;
+ ROCE_DEV_INFO(
+ rdev,
+ "func(%d) qp(%u) roce5_create_qp double_sgl_mode.",
+ rdev->glb_func_id, rqp->qpn);
+ }
+
+ if (((unsigned int)init_attr->create_flags &
+ IB_QP_CREATE_SIGNATURE_EXT_MTU) != 0) {
+ rqp->ext_mtu = 1;
+ ROCE_DEV_INFO(rdev, "func(%d) qp(%u) roce5_create_qp ext_mtu.",
+ rdev->glb_func_id, rqp->qpn);
+ }
+
+ if (((unsigned int)init_attr->create_flags &
+ IB_QP_CREATE_SIGNATURE_EXT_MTU_MODE) != 0) {
+ rqp->ext_mtu_mode = 1;
+ ROCE_DEV_INFO(rdev,
+ "func(%d) qp(%u) roce5_create_qp ext_mtu_mode.",
+ rdev->glb_func_id, rqp->qpn);
+ }
+
+ return;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_srq_chip_ext.c b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_srq_chip_ext.c
new file mode 100644
index 000000000..a6323afd0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/chip_ext/roce_srq_chip_ext.c
@@ -0,0 +1,26 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2020-2024. All rights reserved.
+
+
+#include "roce_srq_extension.h"
+
+void roce5_srq_container_init(struct ib_srq_init_attr *init_attr,
+ struct roce5_srq *rsrq, struct roce5_device *rdev)
+{
+ u8 srq_cont_en = 0;
+ srq_cont_en = init_attr->container_flag;
+
+ rsrq->xrc_en = (init_attr->srq_type == IB_SRQT_XRC);
+ rsrq->container_flag = srq_cont_en ? init_attr->container_flag :
+ rdev->cfg_info.srq_container_en;
+ rsrq->container_mode =
+ srq_cont_en ?
+ init_attr->container_mode :
+ (rsrq->xrc_en ? rdev->cfg_info.xrc_srq_container_mode :
+ rdev->cfg_info.srq_container_mode);
+ rsrq->container_warn_th = init_attr->attr.srq_limit;
+ rsrq->rqe_cnt_th = srq_cont_en ? init_attr->container_warn_th :
+ rdev->cfg_info.warn_th;
+
+ rsrq->container_size = roce5_get_container_sz(rsrq->container_mode);
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_common.h b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_common.h
new file mode 100644
index 000000000..b956ce82c
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_common.h
@@ -0,0 +1,13 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef HYPER_ROCE_COMMON
+#define HYPER_ROCE_COMMON
+
+enum roce5_hyper_mode {
+ ROCE_HYPER_MODE_DISABLE,
+ ROCE_HYPER_MODE_UDP,
+ ROCE_HYPER_MODE_AR,
+};
+
+#endif /* HYPER_ROCE_COMMON */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_netlink.c b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_netlink.c
new file mode 100644
index 000000000..ca38186cc
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_netlink.c
@@ -0,0 +1,511 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#include <linux/types.h>
+#include "hinic5_rdma.h"
+#include "rdma_comp.h"
+#include "roce_hyper_npu_cmd.h"
+#include "roce_npu_cmd.h"
+#include "roce_hyper_npu_cmd.h"
+#include "comm_defs.h"
+
+#include "roce.h"
+#include "comm_defs.h"
+#include "roce_qp.h"
+#include "roce_qp_ext.h"
+#include "roce_netlink.h"
+#include "roce_cqm_cmd.h"
+#include "hyper_roce_common.h"
+#include "hyper_roce_qp.h"
+#include "hyper_roce_netlink.h"
+
+#define HYPER_ROCE_RDMARC_ENTRY_SIZE_BYTES 32
+
+static int roce5_send_cmd_set_qp_hyper_mode(struct roce5_device *rdev,
+ struct roce5_hyper_set_in *msg_in)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_enable_hyper_roce_s *input = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_enable_hyper_roce_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ input = (roce_uni_cmd_enable_hyper_roce_s *)cqm_cmd_inbuf->buf;
+ input->com.index = cpu_to_be32(msg_in->qpn);
+ input->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ input->com.opt = cpu_to_be32(RoCE_CMD_ENABLE_HYPER_ROCE_QP);
+
+ input->cmd_info.dw0.bs.hyper_mode = msg_in->mode;
+ input->cmd_info.dw0.bs.srp_en = msg_in->sack_en;
+ input->cmd_info.dw0.value = cpu_to_be32(input->cmd_info.dw0.value);
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ RoCE_CMD_HYPER_ROCE, cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send RoCE_CMD_ENABLE_HYPER_ROCE_QP command, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ goto out;
+ }
+
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+static int
+roce5_send_cmd_modify_qp_extend(struct roce5_device *rdev,
+ struct roce5_hyper_extend_config_in *msg_in)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_enable_hyper_roce_s *input = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_enable_hyper_roce_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ input = (roce_uni_cmd_enable_hyper_roce_s *)cqm_cmd_inbuf->buf;
+ input->com.index = cpu_to_be32(msg_in->qpn);
+ input->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ input->com.opt = cpu_to_be32(RoCE_CMD_ENABLE_HYPER_ROCE_QP);
+
+ switch (msg_in->attr_mask) {
+ case IBV_QP_ATTR_EXTEND_UDP_SRC_PORT:
+ input->cmd_info.dw0.bs.base_src_port = msg_in->udp_src_port;
+ break;
+ case IBV_QP_ATTR_EXTEND_HYROCE_FEATURE:
+ input->cmd_info.dw0.bs.hyper_mode = msg_in->feature.type;
+ input->cmd_info.dw0.bs.srp_en = msg_in->feature.sack_enable;
+ break;
+ case IBV_QP_ATTR_EXTEND_LB_MODE:
+ input->cmd_info.dw0.bs.lb_mode = msg_in->lb_mode;
+ break;
+ case IBV_QP_ATTR_EXTEND_MP_CONFIG:
+ input->cmd_info.dw1.bs.sport_repeat_num =
+ msg_in->mp.flowlet_pkg_num;
+ input->cmd_info.dw1.bs.path_num = msg_in->mp.path_num;
+ input->cmd_info.dw1.bs.sport_interval = msg_in->mp.interval;
+ input->cmd_info.dw1.bs.path_rr_enable =
+ msg_in->mp.path_rr_enable;
+ input->cmd_info.dw1.bs.cc_mode = msg_in->mp.cc_mode;
+ break;
+ case IBV_QP_ATTR_EXTEND_AR_CONFIG:
+ input->cmd_info.dw1.bs.port_rr_enable =
+ msg_in->ar.port_rr_enable;
+ break;
+ case IBV_QP_ATTR_EXTEND_SACK_CONFIG:
+ input->cmd_info.dw2.bs.oor_range_m = msg_in->sack.oor_range;
+ input->cmd_info.dw2.bs.srp_range_n = msg_in->sack.srp_range;
+ break;
+ default:
+ ROCE_DEV_ERR(rdev, "Unsupport attr mask!\n");
+ break;
+ }
+
+ input->cmd_info.dw0.bs.attr_ext_mask = msg_in->attr_mask;
+ input->cmd_info.dw0.value = cpu_to_be32(input->cmd_info.dw0.value);
+ input->cmd_info.dw1.value = cpu_to_be32(input->cmd_info.dw1.value);
+ input->cmd_info.dw2.value = cpu_to_be32(input->cmd_info.dw2.value);
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ RoCE_CMD_HYPER_ROCE, cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send RoCE_CMD_ENABLE_HYPER_ROCE_QP command, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ goto out;
+ }
+
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+static int
+roce5_send_cmd_set_qp_msnc(struct roce5_device *rdev, u32 qpn,
+ struct roce5_qp_hyper_extend *rqp_hyper_ext)
+{
+ int ret = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_init_msnc_s *input = NULL;
+ u64 bitmap_addr = 0;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_init_msnc_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ input = (roce_uni_cmd_init_msnc_s *)cqm_cmd_inbuf->buf;
+ input->com.index = cpu_to_be32(qpn);
+ input->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ input->com.opt = cpu_to_be32(RoCE_CMD_INIT_MSNC_QP);
+
+ input->cmd_info.dw0.bs.sack_bitmap_size =
+ HYPER_ROCE_TX_SACK_BITMAP_SIZE;
+ input->cmd_info.dw0.bs.txmsn_entry_size = HYPER_ROCE_MSN_ENTRY_SIZE;
+ input->cmd_info.dw0.bs.txmsn_table_size = HYPER_ROCE_MSN_TABLE_SIZE;
+ input->cmd_info.dw0.bs.txmsn_table_gpa_h =
+ (rqp_hyper_ext->tx_msnc.dma_addr >> ROCE5_RDMARC_GPA_H_SHIFT) &
+ 0xffffff;
+ input->cmd_info.dw0.value = cpu_to_be32(input->cmd_info.dw0.value);
+
+ input->cmd_info.txmsn_table_gpa_l =
+ cpu_to_be32((u32)(rqp_hyper_ext->tx_msnc.dma_addr >>
+ ROCE5_RDMARC_GPA_L_SHIFT));
+
+ input->cmd_info.dw2.bs.rxmsn_entry_size0 = HYPER_ROCE_MSN_ENTRY_SIZE;
+ input->cmd_info.dw2.bs.rxmsn_table_size0 = HYPER_ROCE_MSN_TABLE_SIZE;
+ input->cmd_info.dw2.bs.rxmsn_table_gpa0_h =
+ (rqp_hyper_ext->rx_msnc.dma_addr >> ROCE5_RDMARC_GPA_H_SHIFT) &
+ 0xffffff;
+ input->cmd_info.dw2.value = cpu_to_be32(input->cmd_info.dw2.value);
+
+ input->cmd_info.rxmsn_table_gpa0_l =
+ cpu_to_be32((u32)(rqp_hyper_ext->rx_msnc.dma_addr >>
+ ROCE5_RDMARC_GPA_L_SHIFT));
+
+ bitmap_addr = (u64)rqp_hyper_ext->rx_msnc.dma_addr +
+ HYPER_ROCE_MSN_RDMARC_ALLOC_SIZE *
+ HYPER_ROCE_RDMARC_ENTRY_SIZE_BYTES;
+
+ input->cmd_info.dw4.bs.sack_bitmap_size =
+ HYPER_ROCE_RX_SACK_BITMAP_SIZE;
+ input->cmd_info.dw4.bs.rxmsn_entry_size1 = HYPER_ROCE_MSN_ENTRY_SIZE;
+ input->cmd_info.dw4.bs.rxmsn_table_size1 = HYPER_ROCE_MSN_TABLE_SIZE;
+ input->cmd_info.dw4.bs.rxmsn_table_gpa1_h =
+ (bitmap_addr >> ROCE5_RDMARC_GPA_H_SHIFT) & 0xffffff;
+ input->cmd_info.dw4.value = cpu_to_be32(input->cmd_info.dw4.value);
+
+ input->cmd_info.rxmsn_table_gpa1_l =
+ cpu_to_be32((u32)(bitmap_addr >> ROCE5_RDMARC_GPA_L_SHIFT));
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ RoCE_CMD_HYPER_ROCE, cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send RoCE_CMD_INIT_MSNC_QP command, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ goto out;
+ }
+
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+static int roce5_alloc_msnc(struct roce5_device *rdev,
+ struct roce5_qp_hyper_extend *rqp_hyper_ext)
+{
+ int ret;
+ ret = roce5_rdma_rdmarc_alloc(rdev->hwdev,
+ HYPER_ROCE_MSN_RDMARC_ALLOC_SIZE,
+ &rqp_hyper_ext->tx_msnc);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc rdma rdmarc, func_id(%u).",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce5_rdma_rdmarc_alloc(
+ rdev->hwdev,
+ HYPER_ROCE_MSN_RDMARC_ALLOC_SIZE +
+ HYPER_ROCE_RXMSN_BITMAP_RDMARC_ALLOC_SIZE,
+ &rqp_hyper_ext->rx_msnc);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc rdma rdmarc, func_id(%u).",
+ rdev->glb_func_id);
+ roce5_rdma_rdmarc_free(rdev->hwdev, &rqp_hyper_ext->tx_msnc);
+ return ret;
+ }
+
+ rqp_hyper_ext->msnc_en = true;
+
+ return 0;
+}
+
+static int32_t roce5_genl_set_qp_hyper_mode(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len,
+ uint16_t *out_size)
+{
+ int32_t ret = 0;
+ struct roce5_hyper_set_in *msg_in = NULL;
+ struct roce5_qp *rqp = NULL;
+ struct roce5_qp_hyper_extend *rqp_hyper_ext = NULL;
+
+ if (in == NULL || in_len == 0 ||
+ in_len < sizeof(struct roce5_hyper_set_in) || out_size == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Invalid param, in:%d, in_len:%u, out_size:%d",
+ !!in, in_len, !!out_size);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_hyper_set_in *)in;
+
+ if (msg_in->qpn == ROCE_QP_SMI_QP_NUM ||
+ msg_in->qpn == ROCE_QP_GSI_QP_NUM) {
+ ROCE_DEV_ERR(rdev, "Invalid qpn(%u).", msg_in->qpn);
+ return -EINVAL;
+ }
+
+ rqp = roce5_get_rqp_by_qpn(rdev, msg_in->qpn);
+ if (rqp == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to look up rqp.");
+ return -EINVAL;
+ }
+
+ mutex_lock(&rqp->mutex);
+
+ if (rqp->qp_state >= IB_QPS_RTR) {
+ ROCE_DEV_ERR(rdev, "Invalid qp state, current state(%u).",
+ rqp->qp_state);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = roce5_send_cmd_set_qp_hyper_mode(rdev, msg_in);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to send CMDQ, ret(%d)", ret);
+ goto out;
+ }
+
+ rqp_hyper_ext = (struct roce5_qp_hyper_extend *)roce5_qp_get_ext_buf(
+ rqp, ROCE_EXT_HYPER_ROCE);
+ if (rqp_hyper_ext == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to the buf of qp hyper extend, qpn(%u).",
+ rqp->qpn);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rqp_hyper_ext->mode = msg_in->mode;
+ rqp_hyper_ext->sack_en = msg_in->sack_en;
+
+ /* ROCE_HYPER_MODE_DISABLE indicates not enable out-of-order receive, not need allocate rdmarc resource; enable sack_en selective retransmission, must enable out-of-order receive */
+ if (rqp_hyper_ext->mode != ROCE_HYPER_MODE_DISABLE) {
+ ret = roce5_alloc_msnc(rdev, rqp_hyper_ext);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to alloc msnc, ret(%d).",
+ ret);
+ goto out;
+ }
+
+ ret = roce5_send_cmd_set_qp_msnc(rdev, msg_in->qpn,
+ rqp_hyper_ext);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to send CMDQ, ret(%d)", ret);
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&rqp->mutex);
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static int32_t roce5_genl_set_default_multipath_config(
+ struct roce5_device *rdev, struct roce5_hyper_extend_config_in *msg_in)
+{
+ int ret = 0;
+
+ msg_in->lb_mode = HYPER_ROCE_DEFAULT_LB_MODE;
+ msg_in->mp.flowlet_pkg_num = HYPER_ROCE_DEFAULT_MULTI_PKG_NUM;
+ msg_in->mp.path_num = HYPER_ROCE_DEFAULT_MULTI_PATH_NUM;
+ msg_in->mp.interval = HYPER_ROCE_DEFAULT_MULTI_INTERVAL;
+ msg_in->mp.path_rr_enable = HYPER_ROCE_DEFAULT_MULTI_PATHRR_ENABLE;
+ msg_in->mp.cc_mode = HYPER_ROCE_DEFAULT_MULTI_CC_MODE;
+
+ msg_in->attr_mask = IBV_QP_ATTR_EXTEND_LB_MODE;
+ ret = roce5_send_cmd_modify_qp_extend(rdev, msg_in);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to send CMDQ, ret(%d)", ret);
+ return ret;
+ }
+
+ msg_in->attr_mask = IBV_QP_ATTR_EXTEND_MP_CONFIG;
+ ret = roce5_send_cmd_modify_qp_extend(rdev, msg_in);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to send CMDQ, ret(%d)", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int32_t roce5_modify_hyper_config(
+ struct roce5_device *rdev, struct roce5_hyper_extend_config_in *msg_in,
+ struct roce5_qp_hyper_extend *rqp_hyper_ext, struct roce5_qp *rqp)
+{
+ int ret = 0;
+
+ if (msg_in->attr_mask == IBV_QP_ATTR_EXTEND_HYROCE_FEATURE) {
+ ret = roce5_send_cmd_modify_qp_extend(rdev, msg_in);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to send CMDQ, ret(%d)", ret);
+ return ret;
+ }
+
+ rqp_hyper_ext->mode = (u8)msg_in->feature.type;
+ rqp_hyper_ext->version = (u8)msg_in->feature.version;
+ rqp_hyper_ext->sack_en = (u8)msg_in->feature.sack_enable;
+
+ /* ROCE_HYPER_MODE_DISABLE indicates not enable out-of-order receive, not need allocate rdmarc resource; enable sack_en selective retransmission, must enable out-of-order receive */
+ if (rqp_hyper_ext->mode != ROCE_HYPER_MODE_DISABLE) {
+ ret = roce5_alloc_msnc(rdev, rqp_hyper_ext);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to alloc msnc, ret(%d).",
+ ret);
+ return ret;
+ }
+
+ ret = roce5_send_cmd_set_qp_msnc(rdev, msg_in->qpn,
+ rqp_hyper_ext);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to send CMDQ, ret(%d)",
+ ret);
+ return ret;
+ }
+ }
+
+ ret = roce5_genl_set_default_multipath_config(rdev, msg_in);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to set default mp config, ret(%d).",
+ ret);
+ return ret;
+ }
+ } else {
+ if (rqp_hyper_ext->mode == ROCE_HYPER_MODE_DISABLE) {
+ ROCE_DEV_ERR(rdev,
+ "Hyper_roce is disable, current mode(%u).",
+ rqp_hyper_ext->mode);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ ret = roce5_send_cmd_modify_qp_extend(rdev, msg_in);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to send CMDQ, ret(%d)", ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int32_t roce5_genl_modify_qp_extend(struct roce5_device *rdev, void *in,
+ uint16_t in_len, void *out,
+ uint16_t out_len, uint16_t *out_size)
+{
+ int32_t ret = 0;
+ struct roce5_hyper_extend_config_in *msg_in = NULL;
+ struct roce5_qp *rqp = NULL;
+ struct roce5_qp_hyper_extend *rqp_hyper_ext = NULL;
+
+ if (in == NULL || in_len == 0 ||
+ in_len < sizeof(struct roce5_hyper_extend_config_in) ||
+ out_size == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Invalid param, in:%d, in_len:%u, out_size:%d",
+ !!in, in_len, !!out_size);
+ return -EINVAL;
+ }
+
+ msg_in = (struct roce5_hyper_extend_config_in *)in;
+
+ if (msg_in->qpn == ROCE_QP_SMI_QP_NUM ||
+ msg_in->qpn == ROCE_QP_GSI_QP_NUM) {
+ ROCE_DEV_ERR(rdev, "Invalid qpn(%u).", msg_in->qpn);
+ return -EINVAL;
+ }
+
+ rqp = roce5_get_rqp_by_qpn(rdev, msg_in->qpn);
+ if (rqp == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to look up rqp.");
+ return -EINVAL;
+ }
+
+ mutex_lock(&rqp->mutex);
+
+ if (rqp->qp_state >= IB_QPS_RTR) {
+ ROCE_DEV_ERR(rdev, "Invalid qp state, current state(%u).",
+ rqp->qp_state);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rqp_hyper_ext = (struct roce5_qp_hyper_extend *)roce5_qp_get_ext_buf(
+ rqp, ROCE_EXT_HYPER_ROCE);
+ if (rqp_hyper_ext == NULL) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to the buf of qp hyper extend, qpn(%u).",
+ rqp->qpn);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = roce5_modify_hyper_config(rdev, msg_in, rqp_hyper_ext, rqp);
+ if (ret) {
+ ROCE_DEV_ERR(rdev, "Failed to modify hyper roce config.");
+ }
+out:
+ mutex_unlock(&rqp->mutex);
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static roce5_netlink_cmd_process g_cmd_process[] = {
+ { USRNL_ROCE_CMD_HYPER_QP_SET, roce5_genl_set_qp_hyper_mode },
+ { USRNL_ROCE_CMD_MODIFY_QP_EXTEND, roce5_genl_modify_qp_extend },
+};
+
+int roce5_hyper_netlink_init(void)
+{
+ int ret;
+
+ ret = roce5_netlink_register_cbs(
+ g_cmd_process,
+ sizeof(g_cmd_process) / sizeof(roce5_netlink_cmd_process));
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to register hyper roce netlink callbacks, ret(%d).",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_netlink.h b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_netlink.h
new file mode 100644
index 000000000..27de1b070
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_netlink.h
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef HYPER_ROCE_NETLINK_H
+#define HYPER_ROCE_NETLINK_H
+
+#include <linux/types.h>
+
+#define HYPER_ROCE_DEFAULT_LB_MODE 1
+#define HYPER_ROCE_DEFAULT_MULTI_PKG_NUM 4
+#define HYPER_ROCE_DEFAULT_MULTI_PATH_NUM 4
+#define HYPER_ROCE_DEFAULT_MULTI_INTERVAL 1
+#define HYPER_ROCE_DEFAULT_MULTI_PATHRR_ENABLE 0
+#define HYPER_ROCE_DEFAULT_MULTI_CC_MODE 2
+
+struct roce5_hyper_set_in {
+ uint32_t qpn;
+ uint8_t mode; /* @see enum roce_hyper_mode */
+ uint8_t sack_en;
+ uint8_t rsvd[2];
+};
+
+int roce5_hyper_netlink_init(void);
+
+enum ibv_qp_attr_extend_mask {
+ IBV_QP_ATTR_EXTEND_UDP_SRC_PORT = 1 << 0, /* source UDP port number */
+ IBV_QP_ATTR_EXTEND_HYROCE_FEATURE = 1 << 1, /* high-order RoCE of feature */
+ IBV_QP_ATTR_EXTEND_LB_MODE = 1 << 2, /* load balance mode */
+ IBV_QP_ATTR_EXTEND_MP_CONFIG = 1 << 3, /* Multi-Path multipath mode configuration */
+ IBV_QP_ATTR_EXTEND_AR_CONFIG =
+ 1 << 4, /* Adaptive-Routing multipath mode configuration */
+ IBV_QP_ATTR_EXTEND_SACK_CONFIG =
+ 1 << 5, /* Selective Ack selective retransmission parameters configuration */
+};
+
+/* high-order RoCE feature configuration structure */
+struct ibv_hyroce_feature {
+ uint32_t type; /* high-order RoCE type, value range: enum ibv_hyroce_feature_type */
+ uint32_t version; /* high-order RoCE version, value range: enum ibv_hyroce_feature_version */
+ uint32_t sack_enable; /* selective retransmission switch, 0- disable, 1- enable */
+
+ uint32_t resv[32]; /* reserved field, used for not to extension feature */
+};
+
+/* multipath (Multi-Path) configuration parameters structure */
+struct ibv_mp_config {
+ uint32_t flowlet_pkg_num; /* each sub-flow (flowlet) of packet count, used for flow splitting */
+ uint32_t path_num; /* multipath of path count */
+ uint32_t interval; /* UDP port number increment interval, used for distinguish different path */
+ uint32_t path_rr_enable; /* path whether supports poll (RR) select network port, 0- not support, 1- supports */
+ uint32_t cc_mode;
+
+ uint32_t resv[32]; /* reserved field, used for not to extension */
+};
+
+/* adaptive path by (Adaptive Routing) configuration structure */
+struct ibv_ar_config {
+ uint32_t port_rr_enable; /* whether enable network port side port poll (RR) per-packet function, 0- disable, 1- enable */
+
+ uint32_t resv[32]; /* reserved field, used for not to extension */
+};
+
+/* selective retransmission (SACK - Selective Ack) configuration structure */
+struct ibv_sack_config {
+ uint32_t srp_range; /* TX(send) direction maximum repass packet count */
+ uint32_t oor_range; /* RX(receive) direction out-of-order repass window of packet count */
+
+ uint32_t resv[32]; /* reserved field, used for not to extension */
+};
+
+struct roce5_hyper_extend_config_in {
+ uint32_t qpn;
+ uint32_t udp_src_port; /* source UDP port number */
+ struct ibv_hyroce_feature feature; /* high-order RoCE feature */
+ uint32_t lb_mode; /* load balance mode, value range: enum ibv_lb_mode type */
+ struct ibv_mp_config mp; /* multipath (Multi-Path) configuration */
+ struct ibv_ar_config ar; /* adaptive path by (Adaptive Routing) configuration */
+ struct ibv_sack_config sack; /* selective retransmission (SACK) configuration */
+ enum ibv_qp_attr_extend_mask attr_mask;
+};
+
+#endif /* HYPER_ROCE_NETLINK_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_qp.c b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_qp.c
new file mode 100644
index 000000000..1cc831f16
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_qp.c
@@ -0,0 +1,29 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#include "roce_qp.h"
+#include "roce_restore.h"
+#include "hyper_roce_common.h"
+#include "hyper_roce_qp.h"
+
+int roce5_hyper_qp_init(void *parent, void *ext_data)
+{
+ struct roce5_qp_hyper_extend *hyper_qp_ext =
+ (struct roce5_qp_hyper_extend *)ext_data;
+ hyper_qp_ext->mode = ROCE_HYPER_MODE_DISABLE;
+ hyper_qp_ext->sack_en = false;
+ return 0;
+}
+
+void roce5_hyper_qp_cleanup(void *parent, void *ext_data)
+{
+ struct roce5_qp *rqp = (struct roce5_qp *)parent;
+ struct roce5_device *rdev = to_roce5_dev(rqp->ibqp.device);
+ struct roce5_qp_hyper_extend *hyper_qp_ext =
+ (struct roce5_qp_hyper_extend *)ext_data;
+
+ if (hyper_qp_ext->msnc_en) {
+ roce5_rdma_rdmarc_free(rdev->hwdev, &(hyper_qp_ext->tx_msnc));
+ roce5_rdma_rdmarc_free(rdev->hwdev, &(hyper_qp_ext->rx_msnc));
+ }
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_qp.h b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_qp.h
new file mode 100644
index 000000000..52c38f0a4
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/hyper_roce_qp.h
@@ -0,0 +1,35 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef HYPER_ROCE_QP_H
+#define HYPER_ROCE_QP_H
+
+#include <linux/types.h>
+#include "base_type.h"
+#include "hinic5_rdma.h"
+
+/* Entry_size for TXMSN/RXMSN Table 00: 32B 01: 64B Others: reserved. */
+#define HYPER_ROCE_MSN_ENTRY_SIZE 0u
+/* Entry number for TXMSN/RXMSN Table 00: 256 01: 512 10: 1024 11: 2048 Others: reserved. */
+#define HYPER_ROCE_MSN_TABLE_SIZE 0u
+/* 000: 128bit 001: 256bit 010: 512bit 011: 1024bit 100: 2048bit Others: reserved. */
+#define HYPER_ROCE_TX_SACK_BITMAP_SIZE 0u
+/* 011: 1024bit 100: 2048bit Others: reserved. */
+#define HYPER_ROCE_RX_SACK_BITMAP_SIZE 3u
+#define HYPER_ROCE_MSN_RDMARC_ALLOC_SIZE \
+ (256u << (HYPER_ROCE_MSN_ENTRY_SIZE & 0x3))
+#define HYPER_ROCE_RXMSN_BITMAP_RDMARC_ALLOC_SIZE (4)
+
+struct roce5_qp_hyper_extend {
+ u8 mode; /* @see enum roce_hyper_mode */
+ u8 version;
+ u8 sack_en;
+ struct rdma_rdmarc tx_msnc;
+ struct rdma_rdmarc rx_msnc;
+ bool msnc_en;
+};
+
+int roce5_hyper_qp_init(void *parent, void *ext_data);
+void roce5_hyper_qp_cleanup(void *parent, void *ext_data);
+
+#endif /* HYPER_ROCE_QP_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool.c b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool.c
new file mode 100644
index 000000000..fe4e5cf64
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool.c
@@ -0,0 +1,60 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#include "roce.h"
+#include "roce_dfx.h"
+#include "hyper_roce_tool_pktdrop.h"
+#include "hyper_roce_tool.h"
+
+enum roce5_hyper_cmds {
+ ROCE_HYPER_CMD_START = 1,
+ ROCE_HYPER_CMD_START_DROP_QP,
+ ROCE_HYPER_CMD_STOP_DROP_QP,
+ ROCE_HYPER_CMD_MAX
+};
+
+const roce5_adm_func_t hyper_roce5_adm_func[] = {
+ [ROCE_HYPER_CMD_START_DROP_QP] = roce5_hyper_tool_start_drop_qp,
+ [ROCE_HYPER_CMD_STOP_DROP_QP] = roce5_hyper_tool_stop_drop_qp,
+};
+
+int roce5_hyper_tool_dispatch(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ const struct roce5_hyper_cmd_head *head = NULL;
+ const void *data_ptr = NULL;
+ u32 data_len;
+ int ret;
+
+ if (in_size < ROCE_HYPER_CMD_HEAD_SIZE) {
+ ROCE_DEV_ERR(rdev, "Invalid command length(%d).", in_size);
+ return -EINVAL;
+ }
+
+ data_ptr = (void *)((char *)buf_in + ROCE_HYPER_CMD_HEAD_SIZE);
+ data_len = in_size - ROCE_HYPER_CMD_HEAD_SIZE;
+ head = data_ptr;
+
+ if (head->sub_cmd < ROCE_HYPER_CMD_START ||
+ head->sub_cmd >= ROCE_HYPER_CMD_MAX) {
+ ROCE_DEV_ERR(rdev, "Unknown hyper roce command(%d).",
+ head->sub_cmd);
+ return -EINVAL;
+ }
+
+ if (hyper_roce5_adm_func[head->sub_cmd] == NULL) {
+ ROCE_DEV_ERR(rdev, "The callback of cmd(%d) is NULL.",
+ head->sub_cmd);
+ return -EINVAL;
+ }
+
+ ret = hyper_roce5_adm_func[head->sub_cmd](rdev, buf_in, in_size,
+ buf_out, out_size);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to execute the callback of cmd(%d)",
+ head->sub_cmd);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool.h b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool.h
new file mode 100644
index 000000000..2438bbb78
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool.h
@@ -0,0 +1,21 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef HYPER_ROCE_TOOL_H
+#define HYPER_ROCE_TOOL_H
+
+#include "base_type.h"
+#include "roce.h"
+
+#define ROCE_CMD_HYPER 0x220
+
+struct roce5_hyper_cmd_head {
+ u32 sub_cmd;
+};
+
+#define ROCE_HYPER_CMD_HEAD_SIZE sizeof(struct roce5_hyper_cmd_head)
+
+int roce5_hyper_tool_dispatch(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+
+#endif /* HYPER_ROCE_TOOL_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool_pktdrop.c b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool_pktdrop.c
new file mode 100644
index 000000000..7d305e069
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool_pktdrop.c
@@ -0,0 +1,142 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#include <linux/types.h>
+#include "hinic5_rdma.h"
+#include "rdma_comp.h"
+#include "roce_npu_cmd.h"
+#include "roce_hyper_npu_cmd.h"
+#include "comm_defs.h"
+
+#include "roce.h"
+#include "roce_qp.h"
+#include "roce_qp_ext.h"
+#include "roce_netlink.h"
+#include "roce_cqm_cmd.h"
+#include "hyper_roce_tool_pktdrop.h"
+
+int roce5_hyper_tool_start_drop_qp(struct roce5_device *rdev,
+ const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size)
+{
+ int ret = 0;
+ u32 drop_pkt_ratio = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_modify_qp_drop_percent_s *input = NULL;
+ struct pktdrop_cmd_inbuf *in = NULL;
+
+ if (in_size < sizeof(struct pktdrop_cmd_inbuf)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size, (int)sizeof(struct pktdrop_cmd_inbuf));
+ return -EINVAL;
+ }
+
+ if (*out_size < sizeof(union pktdrop_outbuf)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Input parameter(out_size: %dB) is shorter than allocated buffer(allocated: %dB)",
+ (int)*out_size, (int)sizeof(union pktdrop_outbuf));
+ return -ENOMEM;
+ }
+
+ in = (struct pktdrop_cmd_inbuf *)buf_in;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_modify_qp_drop_percent_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ drop_pkt_ratio = in->data.attr.dw15.bs.drop_pkt_ratio;
+ input = (roce_uni_cmd_modify_qp_drop_percent_s *)cqm_cmd_inbuf->buf;
+ input->com.index = cpu_to_be32(in->qpn);
+ input->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ input->com.opt = cpu_to_be32(RoCE_CMD_MODIFY_QP_DROP_PERCENT);
+
+ input->cmd_info.dw0.bs.drop_precent = drop_pkt_ratio;
+ input->cmd_info.dw0.value = cpu_to_be32(input->cmd_info.dw0.value);
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ RoCE_CMD_HYPER_ROCE, cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send RoCE_CMD_ENABLE_HYPER_ROCE_QP command, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ goto out;
+ }
+
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+int roce5_hyper_tool_stop_drop_qp(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ int ret = 0;
+ u32 drop_pkt_ratio = 0;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ roce_uni_cmd_modify_qp_drop_percent_s *input = NULL;
+ struct pktdrop_cmd_inbuf *in = NULL;
+
+ if (in_size < sizeof(struct pktdrop_cmd_inbuf)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size, (int)sizeof(struct pktdrop_cmd_inbuf));
+ return -EINVAL;
+ }
+
+ if (*out_size < sizeof(union pktdrop_outbuf)) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Input parameter(out_size: %dB) is shorter than allocated buffer(allocated: %dB)",
+ (int)*out_size, (int)sizeof(union pktdrop_outbuf));
+ return -ENOMEM;
+ }
+
+ in = (struct pktdrop_cmd_inbuf *)buf_in;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_modify_qp_drop_percent_s), NULL, 0);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)",
+ rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ input = (roce_uni_cmd_modify_qp_drop_percent_s *)cqm_cmd_inbuf->buf;
+ input->com.index = cpu_to_be32(in->qpn);
+ input->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ input->com.opt = cpu_to_be32(RoCE_CMD_MODIFY_QP_DROP_PERCENT);
+
+ input->cmd_info.dw0.bs.drop_precent = drop_pkt_ratio;
+ input->cmd_info.dw0.value = cpu_to_be32(input->cmd_info.dw0.value);
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ RoCE_CMD_HYPER_ROCE, cqm_cmd_inbuf, NULL, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(
+ rdev,
+ "Failed to send RoCE_CMD_ENABLE_HYPER_ROCE_QP command, ret(%d), func_id(%d)",
+ ret, rdev->glb_func_id);
+ goto out;
+ }
+
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool_pktdrop.h b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool_pktdrop.h
new file mode 100644
index 000000000..4d3dbd1d5
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/extern/hyper_roce/tool/hyper_roce_tool_pktdrop.h
@@ -0,0 +1,23 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef HYPER_ROCE_TOOL_PKTDROP_H
+#define HYPER_ROCE_TOOL_PKTDROP_H
+#include "hyper_roce_pub_cmd.h"
+#include "roce.h"
+
+struct pktdrop_cmd_inbuf {
+ u32 cmd_type;
+ u32 hyper_roce_sub_cmd;
+ u32 mode;
+ u32 qpn;
+ u32 drop_level;
+ struct pktdrop_l2d_tbl_dfx data;
+};
+
+int roce5_hyper_tool_start_drop_qp(struct roce5_device *rdev,
+ const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size);
+int roce5_hyper_tool_stop_drop_qp(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+#endif
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce.h
new file mode 100644
index 000000000..3fbc3343b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce.h
@@ -0,0 +1,665 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_H
+#define ROCE_H
+
+#include <linux/types.h>
+#include <linux/io-mapping.h>
+#include <linux/list.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_umem.h>
+#include <rdma/uverbs_ioctl.h>
+#include "roce_verbs_compat.h"
+
+#include "hinic5_hw.h"
+#include "hinic5_crm.h"
+#include "hinic5_hw_cfg.h"
+#include "hinic5_lld.h"
+#include "hinic5_cqm.h"
+#include "hinic5_rdma.h"
+#include "nic_cfg_comm.h"
+#include "hmm_common.h"
+
+#include "roce_infra.h"
+#include "roce_db.h"
+#include "roce_sysfs.h"
+
+#include "roce_uld_kernel_api.h"
+#include "roce_npu_cmd_defs.h"
+#include "roce_npu_cmd_ext_defs.h"
+
+#define HIROCE5_DRV_NAME "roce5_drv"
+#define HIROCE5_DRV_AUTHOR "Huawei Technologies CO., Ltd"
+#define HIROCE5_DRV_DESC \
+ "Huawei(R) Intelligent Network Interface Card, RoCE Driver"
+#define HIROCE5_DRV_VERSION GLOBAL_VERSION_STR
+
+#define RDMA_DRIVER_HRN 8395
+#define ROCE_IB_UVERBS_ABI_VERSION 1
+#define ROCE_ULD_DEV_NAME_LEN 16
+
+#define MAX_CEQ_NEED 256
+
+#define DEV_ADDR_FIRST_BYTE_VAL_MASK 2
+
+#define ROCE_NODE_DESC_LEN 5
+
+#define ROCE_SQ_WQEBB_SIZE 64
+
+#define ROCE_GID_LEN 16
+
+#define ROCE_PCI_CFG_REGS_BAR0 0
+#define ROCE_PCI_CFG_REGS_BAR3 3
+
+#define DEFAULT_ROCE_DEV_NODE_PRI 0666
+
+#define ROCE_MAX_PORT_NUM 8
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 0x1234
+#endif
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#define MAX_ROCE_DEV (28 * 4)
+
+#define CHECK_1LAYER_IS_NULL(ptr) ((ptr) == NULL)
+#define CHECK_2LAYER_IS_NULL(ptr, l2_member) \
+ (CHECK_1LAYER_IS_NULL(ptr) || (((ptr)->l2_member) == NULL))
+
+static inline bool roce5_func_is_vf(void *hwdev)
+{
+ return hinic5_func_type(hwdev) == TYPE_VF;
+}
+
+static inline bool roce5_func_is_pf(void *hwdev)
+{
+ return hinic5_func_type(hwdev) == TYPE_PF;
+}
+
+enum {
+ ROCE5_1_PORT_NUM = 1, //EVB single die
形mode
+ ROCE5_2_PORT_NUM = 2,
+ ROCE5_4_PORT_NUM = 4
+};
+
+enum {
+ ROCE5_25G_PORT_SPEED = 25,
+ ROCE5_100G_PORT_SPEED = 100,
+ ROCE5_200G_PORT_SPEED = 200,
+ ROCE5_400G_PORT_SPEED =
+ 201, //because MPU bit width not
够衍generate of custom enum, refer to port_speed_mode_e
+ ROCE5_800G_PORT_SPEED = 202
+};
+
+enum {
+ ROCE5_INVALID_HCA = -1,
+ ROCE5_2_100G_HCA = 0,
+ ROCE5_4_25G_HCA = 1,
+ ROCE5_2_25G_HCA = 2,
+ ROCE5_2_200G_HCA = 3,
+ ROCE5_1_100G_HCA = 4,
+ ROCE5_2_400G_HCA = 5,
+ ROCE5_4_200G_HCA = 6
+};
+
+enum ROCE5_100G_BW_PARAM_E {
+ ROCE5_100G_CIR = 46500000,
+ ROCE5_100G_PIR = 52500000,
+ ROCE5_100G_CNP = 100
+};
+
+enum ROCE5_25G_BW_PARAM_E {
+ ROCE5_25G_CIR = 23200000,
+ ROCE5_25G_PIR = 25500000,
+ ROCE5_25G_CNP = 3
+};
+
+enum roce_bitshift_e {
+ BYTES_TO_2B_SHIFT = 1,
+ BYTES_TO_4B_SHIFT,
+ BYTES_TO_8B_SHIFT,
+ BYTES_TO_16B_SHIFT,
+ BYTES_TO_32B_SHIFT
+};
+
+/* BIG/LITTLE ENGIAN switch */
+#ifdef HW_CONVERT_ENDIAN
+#define roce5_convert_be32(val) (val)
+#define roce5_convert_cpu32(val) (val)
+#else
+#define roce5_convert_be32(val) cpu_to_be32(val)
+#define roce5_convert_cpu32(val) be32_to_cpu(val)
+#endif
+
+enum roce5_aeq_type {
+ /* ofed err */
+ OFED_ET_PATH_MIG = 0,
+ OFED_ET_COMM_EST,
+ OFED_ET_SQ_DRAINED,
+ OFED_ET_SRQ_QP_LAST_WQE,
+ OFED_ET_WQ_CATAS_ERR,
+
+ OFED_ET_PATH_MIG_FAILED = 5,
+ OFED_ET_WQ_INVAL_REQ_ERR,
+ OFED_ET_WQ_ACCESS_ERR,
+ OFED_ET_CQ_ERR,
+ OFED_ET_SRQ_LIMIT,
+ OFED_ET_SRQ_CATAS_ERR,
+
+ /* non ofed err */
+ NON_OFED_ET_QPC_LOOKUP_ERR = 11,
+ NON_OFED_ET_OTHER_TYPE_ERR,
+
+ /* non ofed extend err */
+ NON_OFED_ET_DEBUG_ERR = 32,
+
+ /* NOF AA err */
+ OFED_NOF_AA_QP_DISCONNECT = 64,
+ OFED_NOF_AA_MASTER_CHANGE,
+
+ INVAL_ET_ERR
+};
+
+enum {
+ ROCE_CMD_TIME_CLASS_A = 30000, //30s, TODO: use ASIC card after need modify is 3s
+ ROCE_CMD_TIME_CLASS_B = 40000, //40s, TODO: use ASIC card after need modify is 4s
+ ROCE_CMD_TIME_CLASS_C = 50000 //50s, TODO: use ASIC card after need modify is 5s
+};
+
+enum roce5_ctrl_status { ROCE5_PORT_EVENT = BIT(0) };
+
+#define ROCE_DEFAULT_PORT_NUM 1
+
+#define ROCE_UVERBS_CMD_BASE_MASK \
+ ((1ULL << IB_USER_VERBS_CMD_GET_CONTEXT) | \
+ (1ULL << IB_USER_VERBS_CMD_QUERY_DEVICE) | \
+ (1ULL << IB_USER_VERBS_CMD_QUERY_PORT) | \
+ (1ULL << IB_USER_VERBS_CMD_ALLOC_PD) | \
+ (1ULL << IB_USER_VERBS_CMD_DEALLOC_PD) | \
+ (1ULL << IB_USER_VERBS_CMD_CREATE_AH) | \
+ (1ULL << IB_USER_VERBS_CMD_DESTROY_AH) | \
+ (1ULL << IB_USER_VERBS_CMD_REG_MR) | \
+ (1ULL << IB_USER_VERBS_CMD_DEREG_MR) | \
+ (1ULL << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | \
+ (1ULL << IB_USER_VERBS_CMD_CREATE_CQ) | \
+ (1ULL << IB_USER_VERBS_CMD_RESIZE_CQ) | \
+ (1ULL << IB_USER_VERBS_CMD_DESTROY_CQ) | \
+ (1ULL << IB_USER_VERBS_CMD_CREATE_QP) | \
+ (1ULL << IB_USER_VERBS_CMD_MODIFY_QP) | \
+ (1ULL << IB_USER_VERBS_CMD_QUERY_QP) | \
+ (1ULL << IB_USER_VERBS_CMD_DESTROY_QP) | \
+ (1ULL << IB_USER_VERBS_CMD_CREATE_SRQ) | \
+ (1ULL << IB_USER_VERBS_CMD_MODIFY_SRQ) | \
+ (1ULL << IB_USER_VERBS_CMD_QUERY_SRQ) | \
+ (1ULL << IB_USER_VERBS_CMD_DESTROY_SRQ) | \
+ (1ULL << IB_USER_VERBS_CMD_CREATE_XSRQ) | \
+ (1ULL << IB_USER_VERBS_CMD_ALLOC_MW) | \
+ (1ULL << IB_USER_VERBS_CMD_DEALLOC_MW) | \
+ (1ULL << IB_USER_VERBS_CMD_OPEN_XRCD) | \
+ (1ULL << IB_USER_VERBS_CMD_CLOSE_XRCD) | \
+ (1ULL << IB_USER_VERBS_CMD_OPEN_QP))
+
+#define ROCE_UVERBS_EXT_CMD_MASK \
+ ((1ULL << IB_USER_VERBS_EX_CMD_MODIFY_CQ) | \
+ (1ULL << IB_USER_VERBS_EX_CMD_MODIFY_QP))
+
+enum roce5_load_balance_mode_e {
+ ROCE_LB_MODE_0 = 0,
+ ROCE_LB_MODE_1,
+ ROCE_LB_MODE_2,
+ ROCE_LB_MODE_N,
+};
+
+enum push_ofed_device_status {
+ ROCE_DEV_STATUS_NORMAL = 0,
+ ROCE_DEV_STATUS_CMDQ_TIMEOUT
+};
+
+enum roce5_func_state { ROCE_FUNC_DISABLE = 0, ROCE_FUNC_ENABLE };
+
+enum {
+ ROCE_Cl_TYPE_QPC = 0x0, /* cl_start: 0x0, cl_end: 0x7f, cl_size: 0 */
+ ROCE_CL_TYPE_MPT = 0x1, /* cl_start: 0x150, cl_end: 0x15f, cl_size: 0 */
+ ROCE_CL_TYPE_SQ_WQE =
+ 0x2, /* cl_start: 0x80, cl_end: 0xff, cl_size: 0 */
+ ROCE_CL_TYPE_RQ_WQE =
+ 0x3, /* cl_start: 0x80, cl_end: 0xff, cl_size: 0 */
+ ROCE_CL_TYPE_CQC_SRQC =
+ 0x4, /* cl_start: 0x120, cl_end: 0x13f, cl_size: 0 */
+ ROCE_CL_TYPE_RDMARC =
+ 0x5, /* cl_start: 0x120, cl_end: 0x13f, cl_size: 0 */
+ ROCE_CL_TYPE_CMTT =
+ 0x6, /* cl_start: 0x100, cl_end: 0x11f, cl_size: 0 */
+ ROCE_CL_TYPE_DMTT = 0x7 /* cl_start: 0x100, cl_end: 0x11f, cl_size: 0 */
+};
+
+#define XRC_CONTAINER_FLAG ((u32)(1L << 20))
+
+struct roce5_buf_list {
+ void *buf;
+ dma_addr_t map;
+};
+
+struct roce5_buf {
+ struct roce5_buf_list direct;
+ struct roce5_buf_list *page_list;
+ int nbufs;
+
+ int npages;
+ int page_shift;
+};
+
+struct shadow_hw_db {
+ u32 page_idx;
+ u32 refcnt;
+};
+
+struct roce5_ucontext {
+ struct ib_ucontext ibucontext;
+ void __iomem *db_map;
+ void __iomem *dwqe_map;
+ u64 db_dma_addr;
+ u64 dwqe_dma_addr;
+ struct list_head db_page_list;
+ struct mutex db_page_mutex;
+
+ struct shadow_hw_db shadow_db_ctx;
+};
+
+struct roce5_qp_cnt {
+ struct mutex cur_qps_mutex;
+ u32 alloc_qp_cnt;
+ u32 del_qp_cnt;
+};
+
+struct roce5_dev_hw_info {
+ int config_num_ports; /* Number of ports from configuration file */
+ int hca_type; /* HCA version: 4x25G or 2x100G */
+ u8 phy_port;
+ u8 ep_id; /* EP ID */
+ u8 cpu_endian;
+ u8 rsvd;
+
+ bool is_vf;
+};
+
+struct roce5_dev_cfg_info {
+ u8 scence_id; /* load scenes ID as aa_en */
+ u8 lb_en; /* load balance enable */
+ u8 lb_mode; /* load balance mode */
+ struct {
+ u8 pcie_atomic_en : 1;
+ u8 rsvd : 7;
+ };
+
+ u8 srq_container_en;
+ u8 srq_container_mode;
+ u8 xrc_srq_container_mode;
+ u8 warn_th;
+
+ u8 fake_en;
+ u8 page_bit;
+ u8 pf_start_bit;
+ u8 pf_end_bit;
+
+ u8 port_num; /* cfg data port num */
+ u8 host_num; /* cfg data host num */
+ u8 rsvd1[2];
+ roce_get_chip_ability_s feature_cap;
+};
+#define ROCE_LB_QPN_MAX \
+ 1 //less qp, same a smf on of qp will distribution to same a icq queue, because this decrease low lb of qp count
+struct roce5_qp_lb_scqn_ctrl {
+ struct mutex qp_lb_scqn_ctrl_mutex;
+ //record device in lb of qpn
+ u32 qp[ROCE_LB_QPN_MAX];
+};
+
+struct roce5_cq_ctrl {
+ struct mutex cq_ctrl_mutex;
+ u8 alloc_cq_cnt;
+ u8 high_perf_cq_cnt;
+ u8 rsvd_cq_step;
+ unsigned long cq_bitmap;
+};
+
+enum roce5_device_type { ROCE_DEV_TYPE_UNKNOWN, ROCE_DEV_TYPE_HI1825_V100 };
+
+enum roce5_perf_cq_step { ROCE_1825V100_STEP = 8 };
+
+#define ROCE_IS_DEV_1825V100(rdev) \
+ (((rdev)->device_type) == ROCE_DEV_TYPE_HI1825_V100)
+
+#ifdef __ROCE_DFX__
+struct roce5_list {
+ struct list_head node;
+ struct mutex node_lock;
+};
+struct roce5_device_res {
+ struct roce5_list mr_list;
+};
+#endif //__ROCE_DFX__
+
+//uld service can extension structure space
+#define ROCE_DEVICE_ULD_DEF_LEN 64
+#define ROCE_DEVICE_MAGIC 0xaabacada
+struct roce5_device_uld_def {
+ u8 self_def[ROCE_DEVICE_ULD_DEF_LEN];
+};
+
+struct roce5_device {
+ struct ib_device ib_dev;
+ struct hinic5_lld_dev *lld_dev;
+ struct net_device *ndev;
+ struct device *dev;
+ void *hwdev;
+ void *hwdev_hdl;
+ //struct dev_version_info dev_ver; /*version info */
+ struct hinic5_board_info board_info;
+
+ void __iomem *kernel_db_map;
+ void __iomem *kernel_dwqe_map;
+
+ spinlock_t node_desc_lock;
+ struct mutex cap_mask_mutex;
+ struct rdma_service_cap rdma_cap;
+
+ u8 mac[6]; /* Mac addr. */
+ u16 glb_func_id;
+ unsigned long status;
+ int ceq_num;
+ int ceqn[MAX_CEQ_NEED];
+ int try_times;
+ int destory_flow_timeout;
+ bool ib_active;
+ enum roce5_device_type device_type;
+
+ u8 group_rc_cos;
+ u8 group_ud_cos;
+ u8 group_xrc_cos;
+ u8 mpt_xid_mode;
+ struct roce5_qp_lb_scqn_ctrl qp_lb_scqn_ctrl;
+ struct roce5_dev_hw_info hw_info; /* Hw info read from nic/pcie */
+ struct roce5_dev_cfg_info cfg_info; /* Cfg data info read from MPU */
+
+#ifdef ROCE_BONDING_EN
+ enum ib_port_state port_state;
+ struct roce5_bond_device *bond_dev;
+ atomic_t next_port;
+#endif
+
+ struct mutex mac_vlan_mutex;
+ struct list_head mac_vlan_list_head;
+ struct net_device **gid_dev;
+
+ struct roce5_ecn_ctx ecn_ctx;
+ struct roce5_dfx_ctx dfx_ctx;
+
+ struct roce5_qp_cnt qp_cnt;
+ struct roce5_cq_ctrl cqn_ctrl;
+
+ struct srcu_struct mr_srcu;
+ atomic_t num_prefetch;
+ struct completion comp_prefetch;
+ enum push_ofed_device_status dev_status_to_ofed;
+
+ spinlock_t reset_flow_resource_lock;
+ struct list_head qp_list;
+
+ void *fake_data_buf;
+ dma_addr_t fake_data_page_addr;
+ void *pri_roce_dev
+ [ROCE_MAX_PORT_NUM]; //mailbox, ppf store all pf's roce device, to improve the effiency.
+ int hca_vf_mode; //HCA uses mode to init MAC/IP vf table
+ bool local_en; //STUB local
+ bool full_qp_spec;
+ bool huge_page_en;
+ bool is_vroce;
+ u8 cc_param_version;
+ u8 shadow;
+ u8 rsvd[2];
+ u32 shadow_vfid;
+ u16 shadow_vf_num;
+
+ rwlock_t rwlock_func_tbl_bond;
+ u32 func_tbl_bond;
+
+#ifdef __ROCE_DFX__
+ struct roce5_device_res *device_res;
+ struct roce5_ucontext *ucontext;
+#endif //__ROCE_DFX__
+
+ struct roce5_device_uld_def uld_def;
+ u32 rdev_magic; /* used for uld check, preventstop踩踏 */
+};
+
+int roce5_db_map_user(struct roce5_ucontext *context, unsigned long virt,
+ struct roce5_db *db, u8 shadow_db);
+void roce5_db_unmap_user(struct roce5_ucontext *context, struct roce5_db *db,
+ u8 shadow_db);
+
+int roce5_buf_write_mtt(struct roce5_device *rdev, struct mtt *mtt,
+ struct tag_cqm_buf *buf);
+int roce5_umem_write_mtt(struct roce5_device *rdev, struct mtt *mtt,
+ struct ib_umem *umem, bool use_huge);
+
+int roce5_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
+ struct ib_udata *uhw);
+
+int roce5_query_port_compat(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props);
+
+int roce5_query_port(struct ib_device *ibdev, u32 port,
+ struct ib_port_attr *props);
+
+enum rdma_link_layer roce5_port_link_layer_compat(struct ib_device *ibdev,
+ u8 port_num);
+
+enum rdma_link_layer roce5_port_link_layer(struct ib_device *ibdev,
+ u32 port_num);
+
+int roce5_query_gid_compat(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid);
+
+int roce5_query_gid(struct ib_device *ibdev, u32 port, int index,
+ union ib_gid *gid);
+
+int roce5_query_pkey_compat(struct ib_device *ibdev, u8 port, u16 index,
+ u16 *pkey);
+
+int roce5_query_pkey(struct ib_device *ibdev, u32 port, u16 index, u16 *pkey);
+
+int roce5_modify_device(struct ib_device *ibdev, int mask,
+ struct ib_device_modify *props);
+
+int roce5_modify_port_compat(struct ib_device *ibdev, u8 port, int mask,
+ struct ib_port_modify *props);
+
+int roce5_modify_port(struct ib_device *ibdev, u32 port, int mask,
+ struct ib_port_modify *props);
+
+int roce5_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma);
+
+int roce5_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata);
+
+int roce5_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata);
+
+int roce5_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata);
+
+int roce5_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata);
+
+int roce5_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata);
+
+void roce5_dealloc_ucontext(struct ib_ucontext *ibcontext);
+
+int roce5_alloc_ucontext(struct ib_ucontext *ibucontext,
+ struct ib_udata *udata);
+
+int roce5_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int roce5_alloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata);
+
+int roce5_dealloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata);
+int roce5_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata);
+
+int roce5_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata);
+
+int roce5_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
+int roce5_modify_cq(struct ib_cq *ibcq, u16 cq_count, u16 cq_period);
+
+int roce5_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata);
+
+int roce5_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
+
+int roce5_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
+
+struct ib_qp *roce5_create_qp_compat(struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int roce5_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int roce5_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata);
+
+int roce5_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
+
+int roce5_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr);
+
+int roce5_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int roce5_destroy_ah(struct ib_ah *ibah, u32 flags);
+
+int roce5_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr);
+
+int roce5_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr);
+
+int roce5_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
+
+int roce5_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr);
+
+struct ib_mr *roce5_get_dma_mr(struct ib_pd *ibpd, int access);
+struct ib_mr *roce5_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
+ u32 max_num_sg);
+struct ib_mr *roce5_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length,
+ u64 virt_addr, int access,
+ struct ib_udata *udata);
+
+int roce5_map_kernel_frmr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
+ int sg_nents, unsigned int *sg_offset);
+
+int roce5_dealloc_mw(struct ib_mw *ibmw);
+
+int roce5_port_immutable_compat(struct ib_device *ibdev, u8 port_num,
+ struct ib_port_immutable *immutable);
+int roce5_port_immutable(struct ib_device *ibdev, u32 port_num,
+ struct ib_port_immutable *immutable);
+int roce5_query_device_status(struct ib_device *ibdev, int *dev_status);
+
+int roce5_init_sysfs(struct roce5_device *rdev);
+void roce5_remove_sysfs(struct roce5_device *rdev);
+
+struct net_device *roce5_ib_get_netdev_compat(struct ib_device *ibdev,
+ u8 port_num);
+struct net_device *roce5_ib_get_netdev(struct ib_device *ibdev, u32 port_num);
+
+void roce5_async_event(void *svc_hd, u8 event_type, u8 *val);
+u8 roce5_async_event_level(void *svc_hd, u8 event_type, u8 *val);
+void roce5_ifconfig_up_down_event_report(struct roce5_device *rdev,
+ u8 net_event);
+int roce5_register_netdev_notifier(void);
+void roce5_unregister_netdev_notifier(void);
+void roce5_clean_vlan_device_mac(struct roce5_device *rdev);
+void roce5_clean_real_device_mac(struct roce5_device *rdev);
+
+int roce5_ib_add_gid(const struct ib_gid_attr *attr,
+ __always_unused void **context);
+
+int roce5_ib_del_gid(const struct ib_gid_attr *attr,
+ __always_unused void **context);
+
+/* OFA - OpenFabrics Alliance */
+struct ib_pd *roce5_alloc_pd_ofa(struct ib_device *ibdev,
+ struct ib_ucontext *ibcontext,
+ struct ib_udata *udata);
+
+int roce5_dealloc_pd_ofa(struct ib_pd *ibpd);
+
+struct ib_srq *roce5_create_srq_ofa(struct ib_pd *ibpd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata);
+
+struct ib_ucontext *roce5_alloc_ucontext_ofa(struct ib_device *ibdev,
+ struct ib_udata *udata);
+
+int roce5_dealloc_ucontext_ofa(struct ib_ucontext *ibcontext);
+
+struct ib_xrcd *roce5_alloc_xrcd_ofa(struct ib_device *ibdev,
+ struct ib_ucontext *ibcontext,
+ struct ib_udata *udata);
+
+int roce5_dealloc_xrcd_ofa(struct ib_xrcd *ibxrcd);
+
+int roce5_destroy_srq_ofa(struct ib_srq *ibsrq);
+
+int roce5_post_srq_recv_ofa(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr);
+
+int roce5_post_recv_ofa(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr);
+
+struct ib_cq *roce5_create_cq_ofa(struct ib_device *ibdev,
+ const struct ib_cq_init_attr *attr,
+ struct ib_ucontext *ibcontext,
+ struct ib_udata *udata);
+
+int roce5_destroy_cq_ofa(struct ib_cq *ibcq);
+
+struct ib_ah *roce5_create_ah_ofa(struct ib_pd *pd,
+ struct rdma_ah_attr *ah_attr,
+ struct ib_udata *udata);
+
+int roce5_destroy_ah_ofa(struct ib_ah *ibah);
+
+struct ib_mw *roce5_alloc_mw_ofa(struct ib_pd *ibpd, enum ib_mw_type type,
+ struct ib_udata *udata);
+
+int roce5_dealloc_mw_ofa(struct ib_mw *ibmw);
+
+int roce5_dereg_mr_ofa(struct ib_mr *ibmr);
+
+int roce5_destroy_qp_ofa(struct ib_qp *ibqp);
+
+int roce5_ib_add_gid_ofa(const union ib_gid *gid,
+ const struct ib_gid_attr *attr,
+ __always_unused void **context);
+
+int roce5_g_rdev_add(struct roce5_device *rdev);
+
+void roce5_g_rdev_remove(struct roce5_device *rdev);
+
+struct roce5_device *roce5_get_rdev_by_card_func_id(uint64_t card_id,
+ uint16_t func_id);
+
+struct roce5_device *roce5_get_rdev_by_name(const char *dev_name);
+
+#endif //ROCE_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_compat.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_compat.h
new file mode 100644
index 000000000..da2b4f65a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_compat.h
@@ -0,0 +1,87 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_COMPAT_H
+#define ROCE_COMPAT_H
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#define ROCE_LIKELY(x) likely(x)
+
+#define ROCE_UNLIKELY(x) unlikely(x)
+
+static inline u32 roce_ilog2(u32 n)
+{
+ return ilog2(n);
+}
+#define ROCE_ILOG2(n) roce_ilog2(n)
+
+static inline u32 roce_roundup_pow_of_two(u32 n)
+{
+ return roundup_pow_of_two(n);
+}
+#define ROCE_ROUNDUP_POW_OF_TWO(n) roce_roundup_pow_of_two(n)
+
+#ifndef _lint
+#define ROCE_MDELAY(n) mdelay(n)
+#define ROCE_UDELAY(n) udelay(n)
+#else
+#define ROCE_MDELAY(n) ((void)n)
+#define ROCE_UDELAY(n) ((void)n)
+#endif
+
+#define US_PERF_DELAY 100
+#define ROCE_DELAY() ROCE_UDELAY(US_PERF_DELAY)
+
+#define ROCE_ALIGN(a, b) ALIGN(a, b)
+#define ROCE_MAX(a, b) max(a, b)
+#define ROCE_MIN(a, b) min(a, b)
+#define ROCE_DIV_ROUND_UP(a, b) DIV_ROUND_UP(a, b)
+#define ROCE_FLS(n) fls(n)
+
+#define ROCE_MEMCMP(a, b, count) memcmp(a, b, count)
+#define ROCE_IO_MAPPING_MAP_WC(mapping, offset) \
+ io_mapping_map_wc(mapping, offset)
+#define ROCE_IOREMAP(phys_addr, size) ioremap(phys_addr, size)
+#define ROCE_IOUNMAP(addr) iounmap(addr)
+#define ROCE_IO_MAPPING_UNMAP(vaddr) io_mapping_unmap(vaddr)
+
+#ifndef wc_wmb
+
+#if defined(__i386__)
+#define wc_wmb() asm volatile("lock; addl $0,0(%%esp) " ::: "memory")
+#elif defined(__x86_64__)
+#define wc_wmb() asm volatile("sfence" ::: "memory")
+#elif defined(__ia64__)
+#define wc_wmb() asm volatile("fwb" ::: "memory")
+#else
+#define wc_wmb() wmb()
+#endif
+
+#endif
+
+typedef struct tag_roce_verbs_cmd_com {
+ union {
+ u32 value;
+
+ struct {
+ u32 version : 8;
+ u32 rsvd : 8;
+ u32 cmd_bitmask : 16; //CMD_TYPE_BITMASK_E
+ } bs;
+ } dw0;
+
+ u32 index; //qpn/cqn/srqn/mpt_index/gid idx
+} roce_verbs_cmd_com_s;
+
+typedef struct tag_roce_xq_mtt_info {
+ u32 mtt_flags; /* Indicates whether to kick out cache. by queue (0) or VF(1). */
+ u32 mtt_num; /* Number of cmtt, which needs to be assigned by the driver when the is kicked out by queue. */
+ u32 mtt_cache_line_start; /* The driver needs to read the driver from the configuration file. */
+ u32 mtt_cache_line_end; /* The driver needs to read the driver from the configuration file. */
+ u32 mtt_cache_line_size; /* 0:256B,1:512B */
+} roce_xq_mtt_info_s;
+
+#endif //ROCE_COMPAT_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_event_extension.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_event_extension.h
new file mode 100644
index 000000000..649a4275b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_event_extension.h
@@ -0,0 +1,17 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+
+
+#ifndef ROCE_EVENT_EXTENSION_H
+#define ROCE_EVENT_EXTENSION_H
+
+#include "roce.h"
+#include "roce_event.h"
+
+int to_unkown_event_str_index(uint8_t event_type, const uint8_t *val);
+void roce5_event_report_extend(const struct roce5_device *rdev, u8 *val,
+ int event_str_index);
+int roce5_async_event_handle_extend(u8 event_type, u8 *val,
+ struct roce5_device *rdev);
+
+#endif /* ROCE_EVENT_EXTENSION_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_gid.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_gid.h
new file mode 100644
index 000000000..54cfc7bf6
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_gid.h
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
+
+
+#ifndef ROCE_GID_H
+#define ROCE_GID_H
+
+#include <linux/types.h>
+
+struct rdma_gid_entry {
+ union {
+ u8 raw[16];
+ struct {
+ __be64 subnet_prefix;
+ __be64 interface_id;
+ } global;
+ };
+ union {
+ struct {
+ u32 rsvd : 8;
+ u32 cvlan : 12; /* in layer vlan customer vlan */
+ u32 svlan : 12; /* outside layer vlan */
+ } bs;
+ u32 value;
+ } dw4;
+
+ union {
+ u32 hdr_len_value;
+ };
+
+ union {
+ struct {
+ u16 tag : 2; /* 0: no has vlan; 1: one layer vlan; 2: 2 layer vlan; 3: stag */
+ u16 tunnel : 1; // rsvd for ppe, don't use. 'tunnel'
+ u16 gid_type : 2;
+ u16 ppe_rsvd1 : 1;
+ u16 outer_tag : 2; // rsvd for ppe, don't use. 'outer_tag'
+ u16 ppe_rsvd3 : 1; // rsvd for ppe, don't use. 'stag'
+ u16 gid_update : 1;
+ u16 rsvd : 6;
+ } bs;
+ u16 value;
+ } dw6_h;
+
+ u8 smac[6];
+};
+
+#endif // ROCE_GID_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_infra.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_infra.h
new file mode 100644
index 000000000..b055d5c92
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_infra.h
@@ -0,0 +1,77 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
+
+
+#ifndef ROCE_INFRA_H
+#define ROCE_INFRA_H
+
+#include <linux/kern_levels.h>
+#include <linux/sched.h>
+
+#define ROCE_INFO(format, ...) \
+ printk(KERN_INFO "[ROCE, INFO][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_WARN(format, ...) \
+ printk(KERN_WARNING "[ROCE, WARN][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_ERR(format, ...) \
+ printk(KERN_ERR "[ROCE, ERR][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+
+#define ROCE_INFO_LIMIT(format, ...) \
+ printk_ratelimited(KERN_INFO "[ROCE, INFO][tid:%x][%s,%d]:" format \
+ "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_WARN_LIMIT(format, ...) \
+ printk_ratelimited(KERN_WARNING "[ROCE, WARN][tid:%x][%s,%d]:" format \
+ "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_ERR_LIMIT(format, ...) \
+ printk_ratelimited(KERN_ERR "[ROCE, ERR][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+
+#define ROCE_INFO_ONCE(format, ...) \
+ printk_once(KERN_INFO "[ROCE, INFO][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_WARN_ONCE(format, ...) \
+ printk_once(KERN_WARNING "[ROCE, WARN][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_ERR_ONCE(format, ...) \
+ printk_once(KERN_ERR "[ROCE, ERR][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+
+/* Importent, ensure dev is not null pointer when using ROCE_DEV_XXX() !!! */
+#define ROCE_DEV_INFO(dev, format, ...) \
+ dev_info((dev)->hwdev_hdl, "[ROCE, INFO][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_DEV_WARN(dev, format, ...) \
+ dev_warn((dev)->hwdev_hdl, "[ROCE, WARN][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_DEV_ERR(dev, format, ...) \
+ dev_err((dev)->hwdev_hdl, "[ROCE, ERR][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+
+#define ROCE_DEV_INFO_LIMIT(dev, format, ...) \
+ dev_info_ratelimited((dev)->hwdev_hdl, \
+ "[ROCE, INFO][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_DEV_WARN_LIMIT(dev, format, ...) \
+ dev_warn_ratelimited((dev)->hwdev_hdl, \
+ "[ROCE, WARN][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+#define ROCE_DEV_ERR_LIMIT(dev, format, ...) \
+ dev_err_ratelimited((dev)->hwdev_hdl, \
+ "[ROCE, ERR][tid:%x][%s,%d]:" format "\n", \
+ current->pid, __func__, __LINE__, ##__VA_ARGS__)
+
+#define ROCE_PRINT_GID(dev, raw, format, ...) \
+ ROCE_DEV_WARN( \
+ (dev), \
+ "gid:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x==>" format, \
+ *((u16 *)(raw) + IP_INDEX_0), *((u16 *)(raw) + IP_INDEX_1), \
+ *((u16 *)(raw) + IP_INDEX_2), *((u16 *)(raw) + IP_INDEX_3), \
+ *((u16 *)(raw) + IP_INDEX_4), *((u16 *)(raw) + IP_INDEX_5), \
+ *((u16 *)(raw) + IP_INDEX_6), *((u16 *)(raw) + IP_INDEX_7), \
+ ##__VA_ARGS__)
+
+#endif //ROCE_INFRA_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_kernel_compat_gen.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_kernel_compat_gen.h
new file mode 100644
index 000000000..b1bca23b0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_kernel_compat_gen.h
@@ -0,0 +1,6 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_KERNEL_COMPAT_GEN_H
+#define ROCE_KERNEL_COMPAT_GEN_H
+#endif /* ROCE_KERNEL_COMPAT_GEN_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_main_extension.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_main_extension.h
new file mode 100644
index 000000000..2244bb236
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_main_extension.h
@@ -0,0 +1,77 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_MAIN_EXTENSION_H
+#define ROCE_MAIN_EXTENSION_H
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include "hinic5_hw.h"
+#include "hinic5_crm.h"
+#include "hinic5_lld.h"
+#include "hinic5_srv_nic.h"
+
+#include "roce.h"
+#include "roce_mix.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_qp.h"
+#include "roce_dfx.h"
+#include "roce_cmd.h"
+#include "roce_user.h"
+#include "rdma_comp.h"
+#ifdef ROCE_CHIP_TEST
+#include "roce_main_chip_ext.h"
+#endif
+
+#define ROCE_MAX_WQES_COMPUTE (4 * K_UNIT - 1)
+#define RDMA_MAX_SQ_DESC_SZ_COMPUTE 512
+#define ROCE_MAX_SQ_INLINE_DATA_SZ_COMPUTE 448
+
+#define ROCE5_ULP_CMD(rdev, bitmask) \
+ (((rdev)->is_vroce) ? (VERBS_CMD_TYPE_VROCE_BITMASK) : (bitmask))
+
+static inline u64 roce5_get_uverbs_cmd_mask(void)
+{
+ u64 mask = 0;
+ mask |= ROCE_UVERBS_CMD_BASE_MASK;
+#ifdef ROCE_CHIP_TEST
+ mask |= ROCE_UVERBS_CMD_EXT_MASK;
+#endif
+ return mask;
+}
+
+struct hinic5_uld_info *roce5_info_get(void);
+
+void roce5_service_init_pre(void);
+
+void roce5_lock_rdev(void);
+
+void roce5_unlock_rdev(void);
+
+int roce5_get_rdev_by_uld(struct hinic5_lld_dev *lld_dev, void *uld_dev,
+ struct roce5_device **rdev,
+ struct hinic5_event_info *event);
+
+void roce5_init_dev_ext_handlers(struct roce5_device *rdev);
+
+int roce5_board_cfg_check(struct roce5_device *rdev);
+
+void roce5_remove_clean_res_ext(struct roce5_device *rdev);
+
+int roce5_set_comm_event(const struct roce5_device *rdev,
+ const struct hinic5_event_info *event);
+
+void *roce5_rdev_alloc_ext(void);
+
+void roce5_fill_gid_entry_ext(const struct roce5_device *rdev,
+ struct rdma_gid_entry *gid_entry);
+
+void roce5_cfg_info_update_ext(struct roce5_device *rdev,
+ roce_get_cfg_info_resp_s *resp);
+
+int roce5_add_check_ext(const struct hinic5_lld_dev *lld_dev);
+
+#endif /* ROCE_MAIN_EXTENSION_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_mr_extension.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_mr_extension.h
new file mode 100644
index 000000000..ff0464a31
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_mr_extension.h
@@ -0,0 +1,14 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_MR_EXTEND_H
+#define ROCE_MR_EXTEND_H
+
+#include <rdma/ib_verbs.h>
+#include "roce.h"
+
+int roce5_check_alloc_mr_type(enum ib_mr_type mr_type);
+enum rdma_mr_type roce5_get_mrtype(enum ib_mr_type ib_mr_type);
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_os_compat.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_os_compat.h
new file mode 100644
index 000000000..6b8a3113a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_os_compat.h
@@ -0,0 +1,237 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_OS_COMPAT_H
+#define ROCE_OS_COMPAT_H
+#include <rdma/ib_verbs.h>
+#include "roce.h"
+#include "roce_restore.h"
+#include "roce_verbs_compat.h"
+#include "roce_kernel_compat_gen.h"
+#if defined(UVERBS_IOCTL_HAVE_RDMA_UDATA_TO_DRV_CONTEXT)
+#include <rdma/uverbs_ioctl.h>
+#endif
+
+#define PAGE_SIZE_4KB (1ULL << PAGE_SHIFT_4KB)
+#define PAGE_SIZE_64KB (1ULL << PAGE_SHIFT_64KB)
+#define PAGE_SIZE_2MB (1ULL << PAGE_SHIFT_2MB)
+
+#define BIT_NUM_PER_BYTE (8)
+#define PAGE_SHIFT_4KB (12)
+#define PAGE_SHIFT_64KB (16)
+#define PAGE_SHIFT_2MB (21)
+
+#if !defined(HAVE_IB_UMEM_NUM_DMA_BLOCKS)
+static inline size_t ib_umem_num_dma_blocks(struct ib_umem *umem,
+ unsigned long pgsz)
+{
+ return (size_t)((ALIGN(umem->address + umem->length, pgsz) -
+ ALIGN_DOWN(umem->address, pgsz))) /
+ pgsz;
+}
+#endif
+
+#if !defined(HAVE_RDMA_UMEM_FOR_EACH_DMA_BLOCK)
+#define rdma_umem_for_each_dma_block(umem, biter, pgsz) \
+ for (__rdma_umem_block_iter_start(biter, umem, pgsz); \
+ __rdma_block_iter_next(biter);)
+
+static inline void __rdma_umem_block_iter_start(struct ib_block_iter *biter,
+ struct ib_umem *umem,
+ unsigned long pgsz)
+{
+ __rdma_block_iter_start(biter, umem->sg_head.sgl, umem->nmap, pgsz);
+}
+static inline bool __rdma_umem_block_iter_next(struct ib_block_iter *biter)
+{
+ return __rdma_block_iter_next(biter) && biter->__sg_numblocks--;
+}
+#endif
+
+#if defined(IB_UMEM_NEED_IB_UMEM_FIND_BEST_PGSZ)
+static inline unsigned int rdma_find_pg_bit(unsigned long addr,
+ unsigned long pgsz_bitmap)
+{
+ unsigned long align;
+ unsigned long pgsz;
+
+ align = addr & -addr;
+
+ pgsz = pgsz_bitmap & ~(-align << 1);
+ if (!pgsz)
+ return __ffs(pgsz_bitmap);
+
+ return __fls(pgsz);
+}
+
+static inline unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
+ unsigned long pgsz_bitmap,
+ unsigned long virt)
+{
+ struct scatterlist *sg;
+ unsigned int best_pg_bit;
+ unsigned long va, pgoff;
+ dma_addr_t mask;
+ int i;
+
+ if (WARN_ON(!(pgsz_bitmap & GENMASK(PAGE_SHIFT, 0))))
+ return 0;
+
+ va = virt;
+ mask = roundup_pow_of_two(umem->length);
+ pgoff = umem->address & ~PAGE_MASK;
+
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i) {
+ mask |= (sg_dma_address(sg) + pgoff) ^ va;
+ if (i && i != (umem->nmap - 1))
+ mask |= sg_dma_len(sg);
+ va += sg_dma_len(sg) - pgoff;
+ pgoff = 0;
+ }
+ best_pg_bit = rdma_find_pg_bit(mask, pgsz_bitmap);
+
+ return BIT_ULL(best_pg_bit);
+}
+#endif
+
+static inline u32 roce5_umem_get_page_count(struct ib_umem *umem)
+{
+#if defined(HAVE_IB_UMEM_PAGE_COUNT)
+ return (u32)ib_umem_page_count(umem);
+#elif defined(HAVE_IB_UMEM_NUM_PAGES)
+ return (u32)ib_umem_num_pages(umem);
+#endif
+}
+
+static inline u32 roce5_umem_get_page_shift(struct ib_umem *umem)
+{
+#if defined(UMEM_HAVE_PAGE_SHIFT)
+ return umem->page_shift;
+#else
+ return PAGE_SHIFT;
+#endif
+}
+
+static inline u32 roce5_umem_get_page_size(struct ib_umem *umem)
+{
+#if defined(UMEM_HAVE_PAGE_SHIFT)
+ return BIT((unsigned int)umem->page_shift);
+#else
+ return PAGE_SIZE;
+#endif
+}
+
+static inline u32 roce5_get_page_size(struct roce5_device *rdev, bool use_huge)
+{
+ if (use_huge && rdev->huge_page_en) {
+ return PAGE_SIZE_2MB;
+ }
+ return PAGE_SIZE;
+}
+
+static inline size_t roce5_get_page_size_cap(size_t page_size_cap,
+ size_t length)
+{
+ size_t max_shift;
+
+ if (length == 0) {
+ return 0;
+ }
+
+ max_shift = fls_long(length) - 1;
+ if (max_shift == sizeof(size_t) * BIT_NUM_PER_BYTE - 1)
+ return page_size_cap;
+ else
+ return page_size_cap & (((size_t)1 << (max_shift + 1)) - 1);
+}
+
+static inline u32 roce5_umem_get_buf_page_shift(struct roce5_device *rdev,
+ struct ib_umem *umem,
+ u64 buf_addr)
+{
+ u32 real_page_size_cap, page_shift;
+
+ real_page_size_cap = (u32)roce5_get_page_size_cap(
+ (size_t)rdev->rdma_cap.page_size_cap, umem->length);
+
+ if (rdev->huge_page_en) {
+ page_shift = (u32)order_base_2(ib_umem_find_best_pgsz(
+ umem, real_page_size_cap, buf_addr));
+ } else {
+ page_shift = roce5_umem_get_page_shift(umem);
+ }
+
+ return page_shift;
+}
+
+static inline u32 roce5_umem_get_mtt_npages(struct roce5_device *rdev,
+ struct ib_umem *umem,
+ u32 page_shift)
+{
+ u32 npages;
+
+ if (rdev->huge_page_en) {
+ npages = ib_umem_num_dma_blocks(umem, BIT(page_shift));
+ } else {
+ npages = roce5_umem_get_page_count(umem);
+ }
+
+ return npages;
+}
+
+/* These APIs can be reused by different OSs */
+static inline struct ib_umem *roce5_umem_get(struct ib_device *ibdev,
+ struct ib_ucontext *context,
+ unsigned long addr, size_t size,
+ int access, int dmasync)
+{
+#if (!defined(IB_UMEM_GET_HAVE_IB_UCONTEXT) && \
+ !defined(MMU_INTERVAL_NOTIFIER)) || \
+ (!defined(IB_UMEM_GET_HAVE_IB_UCONTEXT) && \
+ !defined(IB_UMEM_GET_HAVE_IB_DEVICE))
+ struct uverbs_attr_bundle *attrs;
+#endif
+
+#if (!defined(IB_UMEM_GET_HAVE_IB_UCONTEXT) && \
+ !defined(MMU_INTERVAL_NOTIFIER)) || \
+ (!defined(IB_UMEM_GET_HAVE_IB_UCONTEXT) && \
+ !defined(IB_UMEM_GET_HAVE_IB_DEVICE))
+ attrs = container_of(&context, struct uverbs_attr_bundle, context);
+#endif
+
+#if defined(IB_UMEM_GET_HAVE_IB_UCONTEXT)
+ return ib_umem_get(context, addr, size, access, dmasync);
+#elif defined(IB_UMEM_GET_HAVE_IB_DEVICE) && defined(MMU_INTERVAL_NOTIFIER)
+ return ib_umem_get(ibdev, addr, size, access);
+#elif defined(IB_UMEM_GET_HAVE_DMASYNC)
+ return ib_umem_get(&attrs->driver_udata, addr, size, access, dmasync);
+#else
+ return ib_umem_get(&attrs->driver_udata, addr, size, access);
+#endif
+}
+
+#if defined(IB_UMEM_GET_PEER)
+static inline struct ib_umem *
+roce5_mr_umem_get_peer(struct roce5_device *rdev, size_t length, int access,
+ u64 addr, struct ib_udata *udata, bool use_huge)
+{
+ u64 page_size = PAGE_SIZE;
+ size_t buf_size = length;
+
+ page_size = roce5_get_page_size(rdev, use_huge);
+ buf_size = (size_t)ROCE_ALIGN(buf_size, page_size);
+
+#if defined(IB_UMEM_GET_PEER_HAVE_IBDEVICE) && defined(MMU_INTERVAL_NOTIFIER)
+ return ib_umem_get_peer(&rdev->ib_dev, addr, buf_size, access,
+ (IB_PEER_MEM_ALLOW | IB_PEER_MEM_INVAL_SUPP));
+#else
+ return ib_umem_get_peer(udata, addr, buf_size, access,
+ (IB_PEER_MEM_ALLOW | IB_PEER_MEM_INVAL_SUPP));
+#endif
+}
+#endif
+
+struct roce5_ucontext *
+roce5_queue_to_ucontext(void *ibq, struct ib_udata *udata, int q_type);
+
+#endif
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_qp_extension.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_qp_extension.h
new file mode 100644
index 000000000..2cbcd5d71
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_qp_extension.h
@@ -0,0 +1,61 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_QP_EXTENSION_H
+#define ROCE_QP_EXTENSION_H
+
+#include <rdma/ib_verbs.h>
+
+#include "roce_qp.h"
+#include "roce_qp_exp.h"
+
+int to_roce5_qp_type(enum ib_qp_type qp_type);
+
+bool roce5_check_qp_modify_ok(enum ib_qp_state cur_state,
+ enum ib_qp_state next_state, enum ib_qp_type type,
+ enum ib_qp_attr_mask mask,
+ enum rdma_link_layer ll);
+
+int roce5_is_qp_normal(struct roce5_qp *rqp, struct ib_qp_init_attr *init_attr);
+
+void roce5_set_qp_dif_attr(struct roce5_qp *rqp,
+ const struct ib_qp_init_attr *init_attr,
+ const struct roce5_device *rdev);
+
+#ifdef ROCE_EXTEND
+
+#define ROCE_QP_VBS_FLAG (1U << 22)
+#define ROCE_QP_OSD_FLAG (1U << 23)
+#define QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC 204800 //200K
+
+struct roce5_set_qp_ext_attr_cmd {
+ u32 qpn;
+ u32 attr_mask;
+};
+
+struct roce5_modify_qp_vbs_cmd {
+ u32 qpn;
+ u64 ci_record_addr;
+};
+
+struct roce5_vbs_qp {
+ cqm_qpc_mpt_s *vbs_sqpc_info; /* vbs private data */
+ struct roce5_db db; /* to record ci_record_pa */
+};
+
+long roce5_vbs_create_sqpc(struct roce5_device *rdev, void *buf);
+#endif
+
+void roce5_destroy_pcqc_ext(struct roce5_qp *rqp);
+int roce5_modify_qp_pre_ext(struct roce5_device *rdev, struct roce5_qp *rqp,
+ struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata);
+void roce5_set_attr_ext(struct roce5_qp *rqp, const struct ib_qp_attr *attr,
+ roce_verbs_qp_attr_s *qp_attr, int attr_mask);
+void roce5_transmit_ci_record_addr_ext(struct roce5_qp *rqp,
+ roce_verbs_qp_attr_s *qp_attr);
+void roce5_cos_update_ext(struct roce5_device *rdev, u8 *cos,
+ enum ib_qp_type qp_type);
+
+#endif /* ROCE_QP_EXTENSION_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_restore.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_restore.h
new file mode 100644
index 000000000..c772472a6
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_restore.h
@@ -0,0 +1,88 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_RESTORE_H
+#define ROCE_RESTORE_H
+#include <rdma/ib_verbs.h>
+
+#include "roce.h"
+#include "roce_qp.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_mr.h"
+#include "roce_mix.h"
+#include "roce_pd.h"
+#include "roce_xrc.h"
+#include "hinic5_cqm.h"
+
+static inline struct roce5_device *to_roce5_dev(const struct ib_device *ibdev)
+{
+ return container_of(ibdev, struct roce5_device, ib_dev);
+}
+
+static inline struct roce5_ucontext *
+to_roce5_ucontext(const struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct roce5_ucontext, ibucontext);
+}
+
+static inline struct roce5_qp *to_roce5_qp(const struct ib_qp *ibqp)
+{
+ return container_of(ibqp, struct roce5_qp, ibqp);
+}
+
+static inline struct roce5_qp *cqmobj_to_roce_qp(const cqm_object_s *object)
+{
+ cqm_qpc_mpt_s *qpc_info = NULL;
+ qpc_info = container_of(object, cqm_qpc_mpt_s, object);
+ return (struct roce5_qp *)qpc_info->priv;
+}
+
+static inline struct roce5_srq *to_roce5_srq(const struct ib_srq *ibsrq)
+{
+ return container_of(ibsrq, struct roce5_srq, ibsrq);
+}
+
+static inline struct roce5_srq *cqmobj_to_roce5_srq(const cqm_object_s *object)
+{
+ cqm_queue_s *cqm_srq = NULL;
+ cqm_srq = container_of(object, cqm_queue_s, object);
+ return (struct roce5_srq *)cqm_srq->priv;
+}
+
+static inline struct roce5_cq *to_roce5_cq(const struct ib_cq *ibcq)
+{
+ return container_of(ibcq, struct roce5_cq, ibcq);
+}
+
+static inline struct roce5_mr *to_roce5_mr(const struct ib_mr *ibmr)
+{
+ return container_of(ibmr, struct roce5_mr, ibmr);
+}
+
+static inline struct roce5_mw *to_roce5_mw(const struct ib_mw *ibmw)
+{
+ return container_of(ibmw, struct roce5_mw, ibmw);
+}
+
+static inline struct roce5_mr *
+rdma_mr_to_roce5_mr(const struct hmm_rdma *rdmamr)
+{
+ return container_of(rdmamr, struct roce5_mr, rdmamr);
+}
+
+static inline struct roce5_ah *to_roce5_ah(const struct ib_ah *ibah)
+{
+ return container_of(ibah, struct roce5_ah, ibah);
+}
+
+static inline struct roce5_pd *to_roce5_pd(const struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct roce5_pd, ibpd);
+}
+
+static inline struct roce5_xrcd *to_roce5_xrcd(const struct ib_xrcd *ibxrcd)
+{
+ return container_of(ibxrcd, struct roce5_xrcd, ibxrcd);
+}
+#endif
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_srq_extension.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_srq_extension.h
new file mode 100644
index 000000000..b931f9426
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_srq_extension.h
@@ -0,0 +1,38 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_SRQ_EXTENSION_H
+#define ROCE_SRQ_EXTENSION_H
+
+#include <linux/types.h>
+#include "roce_srq.h"
+
+/**
+ * container_mode:
+ * mode: 0 -> container_size: 16
+ * mode: 1 -> container_size: 8
+ * mode: 2 -> container_size: 4
+ * mode: 3 -> container_size: 2
+ */
+enum roce5_srq_mode {
+ ROCE_SRQ_MODE_0 = 0,
+ ROCE_SRQ_MODE_1,
+ ROCE_SRQ_MODE_2,
+ ROCE_SRQ_MODE_3
+};
+
+enum roce5_srq_cont_num_mode {
+ ROCE_SRQ_CONT_NUM_MODE3 = 2,
+ ROCE_SRQ_CONT_NUM_MODE2 = 4,
+ ROCE_SRQ_CONT_NUM_MODE1 = 8,
+ ROCE_SRQ_CONT_NUM_MODE0 = 16
+};
+
+u8 roce5_get_container_sz(u32 container_mode);
+u8 roce5_calculate_cont_th(u32 srq_limit);
+void roce5_srq_container_init(struct ib_srq_init_attr *init_attr,
+ struct roce5_srq *rsrq,
+ struct roce5_device *rdev);
+
+#endif /* ROCE_SRQ_EXTENSION_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_user.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_user.h
new file mode 100644
index 000000000..81effef16
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_user.h
@@ -0,0 +1,100 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_USER_H
+#define ROCE_USER_H
+
+#include <linux/types.h>
+
+struct roce5_alloc_ucontext_resp {
+ uint32_t num_qps; /* the maximum of qps */
+ uint32_t num_xsrqs; /* the maximum of xsrqs */
+ uint32_t cqe_size; /* the cqe entry size that device support, the valid value is 32B or 64B; */
+ uint32_t wqebb_size; /* the wqebb entry size that device support, the valid value is 64B or 128B */
+ uint32_t dwqe_size; /* the direct maximum wqe size that device support, 256B */
+ uint32_t max_msg_size; /* the maximum message size that device support, (2G -1)B */
+ uint32_t max_comp_vector; /* the maximum completion vector */
+ uint32_t max_inline_size; /* the maximum of qp inline size that device support */
+ uint32_t dev_caps;
+ uint8_t phy_port;
+ uint8_t storage_aa_en;
+ uint16_t func_id;
+ uint64_t card_id;
+ uint16_t db_offset;
+ uint16_t dwqe_offset;
+ struct {
+ uint16_t pcie_atomic_en : 1;
+ uint16_t rsvd1 : 15;
+ };
+ uint8_t srq_container_en;
+ uint8_t srq_container_mode;
+ uint8_t xrc_srq_container_mode;
+ uint8_t warn_th;
+ uint8_t huge_page_en;
+ uint8_t rsvd;
+ uint8_t max_send_sge; /* the maximum of sq sge */
+ uint8_t max_recv_sge; /* the maximum of rq sge */
+ uint32_t max_sq_wqe_len; /* the maximum sq wqe length that device support */
+ uint64_t roce_user_ext_ability;
+ uint64_t roce_uld_ext_ability;
+};
+
+struct roce5_create_cq_cmd {
+ u64 buf_addr;
+ u64 db_addr;
+};
+
+struct roce5_resize_cq_cmd {
+ u64 buf_addr; /* resize cq's 'buf va */
+ u64 stage; /* describe the resize stage,0 or 1; */
+};
+
+struct roce5_create_srq_cmd {
+ u64 buf_addr;
+ u64 db_addr;
+ u32 rsvd;
+};
+
+struct create_qp_cmd {
+ u64 buf_addr; /* describe the qp buf address that used to store cqe; */
+ u64 db_addr; /* describe the qp sw db address */
+ u32 comp_mask; /* kernel can judge whether handle receive inline through comp_mask */
+ u8 log_sq_bb_count; /* wqebb number = 2 << log_sq_bb_count */
+ u8 log_sq_stride; /* wqebb size = 2 << log_sq_stride */
+ u16 reserved; /* reserved is used to aligned cmd */
+};
+
+struct roce5_modify_srq_cmd {
+ u8 container_flag;
+ u8 container_warn_th;
+ u16 rsvd;
+};
+
+struct roce5_reg_frmr_cmd {
+ u64 pbl_vaddr;
+};
+
+struct roce5_modify_qp_ex_resp_data {
+ u8 is_cos_valid;
+ u8 cos;
+ u8 is_ssn_valid;
+ u8 rsvd0;
+ u32 ssn;
+ u32 rsvd[6];
+#ifdef ROCE_LATENCY_PROF_EN
+ uint8_t latency_prof_en;
+ uint8_t rsvd1[3];
+ uint32_t frequency_reduction_ratio;
+ uint64_t non_ptp_time_diff;
+#endif
+};
+
+struct roce5_create_ah_resp {
+ u8 dmac[ETH_ALEN];
+ u16 vlan_id;
+ u8 cos;
+ u8 rsvd[3];
+};
+
+#endif //ROCE_USER_H
diff --git a/drivers/infiniband/hw/hiroce5/kernel/include/roce_verbs_compat.h b/drivers/infiniband/hw/hiroce5/kernel/include/roce_verbs_compat.h
new file mode 100644
index 000000000..cd87856ea
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/include/roce_verbs_compat.h
@@ -0,0 +1,24 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_VERBS_COMPAT_H
+#define ROCE_VERBS_COMPAT_H
+
+#include <rdma/ib_verbs.h>
+#include "roce_kernel_compat_gen.h"
+
+enum { ROCE_Q_TYPE_QP, ROCE_Q_TYPE_SRQ, ROCE_Q_TYPE_CQ };
+
+#if !defined(HAVE_RDMA_AH_INIT_ATTR)
+/* kernel 4.19 not defined but kernel 5.10 defined, reused for ah creating */
+struct rdma_ah_init_attr {
+ struct rdma_ah_attr *ah_attr;
+};
+
+enum ib_wr_opcode_compat {
+ IB_WR_REG_MR_INTEGRITY = IB_WR_REG_SIG_MR,
+};
+
+#endif
+
+#endif /* ROCE_VERBS_COMPAT_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond.h b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond.h
new file mode 100644
index 000000000..099b76a1a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond.h
@@ -0,0 +1,79 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
+
+
+#ifndef ROCE_BOND_H
+#define ROCE_BOND_H
+
+#include <net/bonding.h>
+#include <linux/netdevice.h>
+
+#include "hinic5_lld.h"
+#include "drv_bond_api.h"
+
+#include "roce.h"
+#include "roce_qp.h"
+#include "roce_cmd.h"
+
+#define ROCE_BOND_MIN_SLAVE 1
+#define ROCE_BOND_MAX_SLAVE BOND_PORT_MAX_NUM
+
+#define ROCE_BOND_RSVD_VLAN_ID 4095
+
+#define ROCE_BOND_FWD_ID_TBL_ALL_BITS 32U
+#define ROCE_BOND_FWD_ID_TBL_PER_BITS 3U
+#define ROCE_BOND_FWD_ID_TBL_PER_BITS_MASK 0x7U
+
+struct roce5_bond_slave {
+ struct net_device *netdev;
+ struct hinic5_lld_dev *lld_dev;
+ struct netdev_lag_lower_state_info netdev_state;
+ u32 update_cnt;
+ u16 func_id;
+ u8 er_id;
+};
+
+struct roce5_bond_transition_res {
+ struct hinic5_lld_dev *ppf_lld;
+};
+
+struct roce5_bond_device {
+ char name[IFNAMSIZ]; /* the name of nic bond device */
+ struct list_head entry;
+ struct hinic5_lld_dev *bond_lld_dev;
+ struct roce5_bond_slave slaves[ROCE_BOND_MAX_SLAVE];
+ struct mutex slave_lock; /* lock for slaves */
+ u32 slave_cnt;
+ atomic_t next_port;
+ struct work_struct detach_work;
+ struct roce5_device *attached_rdev;
+ struct bond_attr attr;
+ struct roce5_bond_transition_res transition_res;
+ u8 need_clean_on_remove;
+};
+
+bool roce5_bond_is_active(struct roce5_device *rdev);
+void roce5_bond_detach(struct roce5_device *rdev);
+struct net_device *roce5_bond_get_netdev(struct roce5_device *rdev);
+
+int roce5_add_bond_real_slave_mac(struct roce5_device *rdev, u8 *mac);
+int roce5_add_bond_vlan_slave_mac(struct roce5_device *rdev, u8 *mac,
+ u16 vlan_id);
+void roce5_del_bond_real_slave_mac(struct roce5_device *rdev);
+void roce5_del_bond_vlan_slave_mac(struct roce5_device *rdev, u8 *mac,
+ u16 vlan_id);
+
+void roce5_bond_rr_set_flow(struct roce5_device *rdev, struct roce5_qp *rqp,
+ roce_verbs_qp_attr_s *qp_attr);
+
+int roce5_bond_event_cfg_rdev(struct hinic5_lld_dev *lld_dev, void *uld_dev,
+ struct roce5_device **rdev, bool hold_rdev);
+void roce5_handle_bonded_port_state_event(struct roce5_device *rdev);
+
+bool roce5_get_bond_ipsurx_en(void);
+void roce5_set_bond_ipsurx_en(bool ipsurx_en);
+
+int roce5_bond_attach(struct roce5_device *rdev);
+int roce5_bond_init(void);
+void roce5_bond_exit(void);
+#endif
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_cfm.c b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_cfm.c
new file mode 100644
index 000000000..f295f241d
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_cfm.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
+
+
+#ifdef ROCE_BONDING_EN
+
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+#include <net/bonding.h>
+
+#include "securec.h"
+
+#include "bond_common_defs.h"
+#include "hinic5_hw.h"
+#include "hinic5_srv_nic.h"
+
+#include "roce_bond.h"
+#include "roce_bond_internal.h"
+#include "roce_cmd.h"
+#include "roce_mpu_cmd.h"
+#include "roce_netdev.h"
+#include "roce_infra.h"
+
+static int roce5_bond_check_slave_port(struct hinic5_lld_dev *lld_dev,
+ u8 slave_ports[], u8 slave_ports_num,
+ bool *result)
+{
+ int ret, i;
+ roce_bond_check_slave_port_req_s req = { 0 };
+ roce_bond_check_slave_port_rsp_s rsp = { 0 };
+ u16 out_size = (u16)sizeof(rsp);
+
+ for (i = 0; i < slave_ports_num; ++i) {
+ req.slave_ports[i] = slave_ports[i];
+ }
+ req.slave_ports_num = slave_ports_num;
+
+ ret = roce5_msg_to_mgmt_sync(lld_dev->hwdev,
+ ROCE_MPU_CMD_BOND_CHECK_SLAVE_PORT, &req,
+ sizeof(req), &rsp, &out_size);
+ if ((ret != 0) || (out_size == 0) || (rsp.head.status != 0)) {
+ ROCE_ERR(
+ "Failed to check slave port, ret(%d), out size(%u), status(%u)",
+ ret, out_size, rsp.head.status);
+ return -EINVAL;
+ }
+
+ *result = false;
+ for (i = 0; i < slave_ports_num; ++i) {
+ *result |= (rsp.slave_ports_result[i] != false) ? true : false;
+ }
+
+ return 0;
+}
+
+/*
+ * roce5_can_do_bond - Check if RoCE can attach to bond device
+ * @bond: bond device to check
+ * Return: true if can attach, false otherwise
+ */
+bool roce5_can_do_bond(struct bonding *bond)
+{
+ bool ret = false;
+ int slave_cnt = 0;
+ int err;
+ struct slave *slave = NULL;
+ struct list_head *iter = NULL;
+ struct hinic5_lld_dev *lld_dev = NULL;
+ char chip_name[IFNAMSIZ] = { 0 };
+ u8 slave_ports[ROCE_BOND_PORT_MAX_NUM];
+ bool result;
+
+ if (bond == NULL) {
+ ROCE_ERR("Invalid Parameter, ptr is NULL.");
+ return false;
+ }
+
+ if (roce5_bond_mode_is_supported(bond->params.mode) == false) {
+ ROCE_ERR("Invalid bond mode(%u).", bond->params.mode);
+ return false;
+ }
+
+ rcu_read_lock();
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ lld_dev = hinic5_get_lld_dev_by_netdev(slave->dev);
+ if (lld_dev == NULL) {
+ goto out;
+ }
+
+ if (hinic5_func_type(lld_dev->hwdev) == TYPE_VF) {
+ ROCE_WARN("VF device %s skipped", slave->dev->name);
+ continue;
+ }
+
+ err = roce5_bond_slave_check(lld_dev, chip_name,
+ sizeof(chip_name));
+ if (err != 0) {
+ ROCE_ERR("Bond slave check err %d.", err);
+ goto out;
+ }
+
+ if (slave_cnt < ROCE_BOND_PORT_MAX_NUM) {
+ slave_ports[slave_cnt] =
+ hinic5_physical_port_id(lld_dev->hwdev);
+ }
+
+ slave_cnt++;
+ ROCE_INFO("can do bond? slave_cnt(%d), slave_name(%s).",
+ slave_cnt, slave->dev->name);
+ }
+
+ if (((slave_cnt >= ROCE_BOND_MIN_SLAVE) &&
+ (slave_cnt <= ROCE_BOND_MAX_SLAVE)) == false) {
+ goto out;
+ }
+
+ if (lld_dev == NULL) {
+ ROCE_INFO("lld dev is NULL.");
+ goto out;
+ }
+
+ err = roce5_bond_check_slave_port(lld_dev, slave_ports, slave_cnt,
+ &result);
+ if (err != 0) {
+ ROCE_ERR("Failed to check slave ports, err(%d).", err);
+ goto out;
+ }
+
+ if (result == false) {
+ ROCE_INFO("Ports don't meet requirements.");
+ goto out;
+ }
+
+ ret = true;
+
+out:
+ rcu_read_unlock();
+ return ret;
+}
+
+static int
+roce5_bond_create_transition_store(struct roce5_bond_device *bond_dev,
+ const struct bond_tracker *tracker)
+{
+ int ret;
+ struct hinic5_lld_dev *ppf_lld = NULL;
+
+ ppf_lld = roce5_bond_get_ppf_lld(tracker);
+ if (ppf_lld == NULL) {
+ ROCE_ERR("Failed to get lld of the PPF.");
+ return -EINVAL;
+ }
+
+ ret = roce5_bond_transition_store(bond_dev, ppf_lld);
+ if (ret != 0) {
+ ROCE_ERR("Failed to store resources of transition, ret(%d).",
+ ret);
+ hinic5_lld_dev_put(ppf_lld);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void
+roce5_bond_create_transition_free(struct roce5_bond_device *bond_dev)
+{
+ roce5_bond_transition_free(bond_dev);
+}
+
+/*
+ * roce5_before_bond_active - Pre-active callback for bond creation
+ * @bond_name: name of bond device
+ * @attr: bond attributes
+ * @err: error code from previous operation
+ */
+void roce5_before_bond_active(const char *bond_name, struct bond_attr *attr,
+ int err)
+{
+ struct roce5_bond_device *bond_dev = NULL;
+ struct bond_tracker tracker;
+ u16 bond_id;
+ int i, slave_cnt;
+ int ret;
+
+ if (bond_name == NULL || attr == NULL) {
+ ROCE_ERR(
+ "Invalid parameter, roce bond_name(%d) or attr(%d) is NULL.",
+ !!bond_name, !!attr);
+ return;
+ }
+
+ bond_id = attr->bond_id;
+ ret = hinic5_bond_get_tracker_by_name(bond_name, &tracker);
+ if (ret != 0) {
+ ROCE_ERR("Failed to get bond tracker, bond name(%s), ret(%d).",
+ bond_name, ret);
+ goto err;
+ }
+
+ if (roce5_bond_before_active_check(&tracker, attr) == false) {
+ ROCE_ERR("Failed to check before active bond.");
+ goto err;
+ }
+
+ bond_dev = roce5_bond_create_bond_device(bond_name);
+ if (IS_ERR(bond_dev)) {
+ ROCE_ERR("Failed to create roce bond device.");
+ goto err;
+ }
+
+ /* Store transition resources during the bond creating period to prevent abnormal resources using. */
+ ret = roce5_bond_create_transition_store(bond_dev, &tracker);
+ if (ret != 0) {
+ ROCE_ERR("Failed to store resources of transition.");
+ goto err;
+ }
+
+ /* Remove the functions of slaves. */
+ for (i = 0, slave_cnt = 0;
+ i < BOND_PORT_MAX_NUM && slave_cnt < tracker.cnt; ++i) {
+ if (tracker.ndev[i] == NULL) {
+ continue;
+ }
+
+ ret = roce5_bond_add_slave(bond_dev, tracker.ndev[i],
+ &tracker.netdev_state[i], false);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to add slave, name(%s), slave name(%s).",
+ bond_dev->name, tracker.ndev[i]->name);
+ goto err_with_transition;
+ }
+
+ ++slave_cnt;
+ }
+
+ /* Free transition resources during the bond creating period. */
+ roce5_bond_create_transition_free(bond_dev);
+ bond_dev->attr = *attr;
+
+ return;
+
+err_with_transition:
+ roce5_bond_create_transition_free(bond_dev);
+err:
+ roce5_bond_destroy(bond_name, bond_id);
+}
+
+/*
+ * roce5_after_bond_active - Post-active callback for bond creation
+ * @bond_name: name of bond device
+ * @attr: bond attributes
+ * @err: error code from previous operation
+ */
+void roce5_after_bond_active(const char *bond_name, struct bond_attr *attr,
+ int err)
+{
+ struct roce5_bond_device *bond_dev = NULL;
+
+ if (bond_name == NULL || attr == NULL) {
+ ROCE_ERR(
+ "Invalid parameter, bond name(%d) or attr(%d) is NULL.",
+ !!bond_name, !!attr);
+ return;
+ }
+
+ bond_dev = roce5_get_bond_dev_by_name(bond_name);
+ if (bond_dev == NULL) {
+ ROCE_ERR("Can't find roce bond device by name(%s).", bond_name);
+ return;
+ }
+
+ roce5_update_rdev_func_val(bond_dev);
+}
+
+/*
+ * roce5_before_bond_modify - Pre-modify callback for bond modification
+ * @bond_name: name of bond device
+ * @attr: new bond attributes
+ * @err: error code from previous operation
+ */
+void roce5_before_bond_modify(const char *bond_name, struct bond_attr *attr,
+ int err)
+{
+ int ret;
+ struct roce5_bond_device *bond_dev = NULL;
+ struct bond_tracker tracker;
+
+ if (bond_name == NULL || attr == NULL) {
+ ROCE_ERR("roce bond_name or attr is NULL.");
+ return;
+ }
+
+ bond_dev = roce5_get_bond_dev_by_name(bond_name);
+ if (bond_dev == NULL) {
+ ROCE_ERR("Can't find roce bond device by name(%s).", bond_name);
+ return;
+ }
+
+ ret = hinic5_bond_get_tracker_by_name(bond_name, &tracker);
+ if (ret != 0) {
+ ROCE_ERR("Failed to get bond tracker, bond name(%s), ret(%d).",
+ bond_name, ret);
+ return;
+ }
+
+ ret = roce5_handle_diff_slave(bond_dev, &tracker);
+ if (ret != 0) {
+ ROCE_ERR("Failed to handle different slave.");
+ return;
+ }
+
+ return;
+}
+
+/*
+ * roce5_after_bond_modify - Post-modify callback for bond modification
+ * @bond_name: name of bond device
+ * @attr: new bond attributes
+ * @err: error code from previous operation
+ */
+void roce5_after_bond_modify(const char *bond_name, struct bond_attr *attr,
+ int err)
+{
+ struct roce5_bond_device *bond_dev = NULL;
+
+ if (bond_name == NULL || attr == NULL) {
+ ROCE_ERR("roce bond_name or attr is NULL.");
+ return;
+ }
+
+ bond_dev = roce5_get_bond_dev_by_name(bond_name);
+ if (bond_dev == NULL) {
+ ROCE_ERR("can't find bond device by name(%s).", bond_name);
+ return;
+ }
+
+ bond_dev->attr = *attr;
+
+ roce5_update_rdev_func_val(bond_dev);
+}
+
+/*
+ * roce5_before_bond_deactive - Pre-deactive callback for bond deletion
+ * @bond_name: name of bond device
+ * @attr: bond attributes
+ * @err: error code from previous operation
+ */
+void roce5_before_bond_deactive(const char *bond_name, struct bond_attr *attr,
+ int err)
+{
+ struct roce5_bond_device *bond_dev = NULL;
+
+ bond_dev = roce5_get_bond_dev_by_name(bond_name);
+ if (bond_dev == NULL) {
+ ROCE_ERR("can't find bond device by name(%s).", bond_name);
+ return;
+ }
+
+ roce5_bond_destroy(bond_dev->name, attr->bond_id);
+}
+
+/*
+ * roce5_after_bond_deactive - Post-deactive callback for bond deletion
+ * @bond_name: name of bond device
+ * @attr: bond attributes
+ * @err: error code from previous operation
+ */
+void roce5_after_bond_deactive(const char *bond_name, struct bond_attr *attr,
+ int err)
+{
+ /* destroy switch thread handle, bond device may already be delete, current thread not disable care handle result */
+}
+
+/*
+ * roce5_bond_mode_is_supported - Check if bond mode is supported
+ * @bond_mode: bond mode to check
+ * Return: true if supported, false otherwise
+ */
+bool roce5_bond_mode_is_supported(u16 bond_mode)
+{
+ if (bond_mode != BOND_MODE_8023AD && bond_mode != BOND_MODE_XOR &&
+ bond_mode != BOND_MODE_ACTIVEBACKUP) {
+ ROCE_ERR(
+ "Bond mode only support 802.3ad/xor/active-backup, current bond mode(%u).",
+ bond_mode);
+ return false;
+ }
+ return true;
+}
+
+/*
+ * roce5_bond_slave_check - Check if slave device is valid for RoCE bond
+ * @lld_dev: LLD device to check
+ * @chip_name: buffer to store chip name
+ * @chip_name_size: size of chip_name buffer
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_bond_slave_check(struct hinic5_lld_dev *lld_dev, char *chip_name,
+ size_t chip_name_size)
+{
+ int err;
+ char tmp_name[IFNAMSIZ] = { 0 };
+
+ if (lld_dev == NULL) {
+ ROCE_ERR("get lld dev err.");
+ return -ENODEV;
+ }
+
+ if (roce5_func_is_vf(lld_dev->hwdev)) {
+ ROCE_ERR("Bond Slave device is VF.");
+ return -EINVAL;
+ }
+
+ err = hinic5_get_chip_name(lld_dev, tmp_name, sizeof(tmp_name));
+ if (err != 0) {
+ ROCE_ERR("Bond Slave get chip name err %d.", err);
+ return err;
+ }
+
+ if (strlen(chip_name) == 0) {
+ err = memcpy_s(chip_name, chip_name_size, tmp_name,
+ sizeof(tmp_name));
+ if (err != 0) {
+ ROCE_ERR("Failed to memcpy chip_name.(ret:%d)", err);
+ return -ENOMEM;
+ }
+ } else if (strcmp(tmp_name, chip_name) != 0) {
+ ROCE_ERR(
+ "Creating bond cross cards is not supported, bond dev chip_name %s, slave chip name %s.",
+ chip_name, tmp_name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * roce5_bond_before_active_check - Pre-active check for bond creation
+ * @tracker: bond tracker from CFM framework
+ * @attr: bond attributes
+ * Return: true if check passes, false otherwise
+ */
+bool roce5_bond_before_active_check(struct bond_tracker *tracker,
+ struct bond_attr *attr)
+{
+ int i, slave_cnt;
+ int err;
+ struct hinic5_lld_dev *lld_dev = NULL;
+ char chip_name[IFNAMSIZ] = { 0 };
+
+ if (roce5_bond_mode_is_supported(attr->bond_mode) == false) {
+ ROCE_ERR("Invalid bond mode(%u).", attr->bond_mode);
+ return false;
+ }
+
+ if (tracker->cnt < ROCE_BOND_MIN_SLAVE ||
+ tracker->cnt > ROCE_BOND_MAX_SLAVE) {
+ ROCE_ERR("Not support the slave number(%u) of the bond.",
+ tracker->cnt);
+ return false;
+ }
+
+ for (i = 0, slave_cnt = 0;
+ i < BOND_PORT_MAX_NUM && slave_cnt < tracker->cnt; ++i) {
+ if (tracker->ndev[i] == NULL) {
+ continue;
+ }
+
+ lld_dev = hinic5_get_lld_dev_by_netdev(tracker->ndev[i]);
+ if (lld_dev == NULL) {
+ ROCE_ERR("get lld dev err.");
+ return false;
+ }
+
+ err = roce5_bond_slave_check(lld_dev, chip_name,
+ sizeof(chip_name));
+ if (err != 0) {
+ ROCE_ERR("Bond slave check err %d.", err);
+ return false;
+ }
+
+ ++slave_cnt;
+ }
+ return true;
+}
+
+#endif /* ROCE_BONDING_EN */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_device.c b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_device.c
new file mode 100644
index 000000000..cb3612778
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_device.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
+
+
+#ifdef ROCE_BONDING_EN
+
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+#include <net/bonding.h>
+
+#include "securec.h"
+
+#include "bond_common_defs.h"
+#include "hinic5_hw.h"
+#include "hinic5_srv_nic.h"
+
+#include "roce_bond.h"
+#include "roce_bond_internal.h"
+#include "roce_cmd.h"
+#include "roce_netdev.h"
+#include "roce_infra.h"
+
+/* Global variables: g_roce5_bond_mutex protects g_roce5_bond_list */
+LIST_HEAD(g_roce5_bond_list);
+DEFINE_MUTEX(g_roce5_bond_mutex);
+
+static bool g_roce5_bond_ipsurx_en = true;
+
+int roce5_bond_transition_store(struct roce5_bond_device *bond_dev,
+ struct hinic5_lld_dev *ppf_lld)
+{
+ int ret = 0;
+
+ ret = hinic5_stateful_init(ppf_lld->hwdev);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to init stateful resource of the PPF, ret(%d).",
+ ret);
+ goto out;
+ }
+
+ bond_dev->transition_res.ppf_lld = ppf_lld;
+out:
+ return ret;
+}
+
+void roce5_bond_transition_free(struct roce5_bond_device *bond_dev)
+{
+ if (bond_dev->transition_res.ppf_lld == NULL) {
+ return;
+ }
+
+ hinic5_stateful_deinit(bond_dev->transition_res.ppf_lld->hwdev);
+ hinic5_lld_dev_put(bond_dev->transition_res.ppf_lld);
+ bond_dev->transition_res.ppf_lld = NULL;
+}
+
+/*
+ * Caller has to call hinic5_lld_dev_put() to free resource when finish using ppf lld.
+ * There's no need to call hinic5_lld_dev_put() to free resource when this function return NULL.
+ */
+struct hinic5_lld_dev *
+roce5_bond_get_ppf_lld(const struct bond_tracker *tracker)
+{
+ int i;
+ struct net_device *first_slave = NULL;
+ struct hinic5_lld_dev *first_slave_lld = NULL, *ppf_lld = NULL;
+
+ for (i = 0; i < BOND_PORT_MAX_NUM; ++i) {
+ if (tracker->ndev[i] != NULL) {
+ first_slave = tracker->ndev[i];
+ break;
+ }
+ }
+
+ if (first_slave == NULL) {
+ ROCE_ERR("Failed to get net device of the first slave.");
+ return NULL;
+ }
+
+ first_slave_lld = hinic5_get_lld_dev_by_netdev(first_slave);
+ if (first_slave_lld == NULL) {
+ ROCE_ERR("Failed to get lld of the first slave.");
+ return NULL;
+ }
+
+ ppf_lld = hinic5_get_ppf_lld_dev(first_slave_lld);
+ if (ppf_lld == NULL) {
+ ROCE_ERR("Failed to get lld of the PPF.");
+ return NULL;
+ }
+
+ return ppf_lld;
+}
+
+/*
+ * roce5_get_bond_dev - Get bond device by name (internal)
+ * @bond_name: name of bond device
+ * Return: pointer to roce5_bond_device if found, NULL otherwise
+ * Lock: caller must hold g_roce5_bond_mutex
+ */
+struct roce5_bond_device *roce5_get_bond_dev(const char *bond_name)
+{
+ struct roce5_bond_device *bdev = NULL;
+
+ list_for_each_entry(bdev, &g_roce5_bond_list, entry) {
+ if (strcmp(bdev->name, bond_name) == 0) {
+ return bdev;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * roce5_get_bond_dev_by_name - Get bond device by name (public wrapper)
+ * @bond_name: name of bond device
+ * Return: pointer to roce5_bond_device if found, NULL otherwise
+ */
+struct roce5_bond_device *roce5_get_bond_dev_by_name(const char *bond_name)
+{
+ struct roce5_bond_device *bdev = NULL;
+
+ mutex_lock(&g_roce5_bond_mutex);
+ bdev = roce5_get_bond_dev(bond_name);
+ mutex_unlock(&g_roce5_bond_mutex);
+ return bdev;
+}
+
+struct roce5_bond_device *roce5_bond_create_bond_device(const char *bond_name)
+{
+ struct roce5_bond_device *rbdev = NULL;
+ errno_t ret;
+
+ if (bond_name == NULL) {
+ ROCE_ERR("Invalid parameter, ptr is NULL.");
+ return ERR_PTR(-EINVAL);
+ }
+
+ rbdev = roce5_get_bond_dev_by_name(bond_name);
+ if (rbdev != NULL) {
+ ROCE_ERR("Bond device(%s) already exists.", bond_name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ rbdev = kzalloc(sizeof *rbdev, GFP_KERNEL);
+ if (rbdev == NULL) {
+ ROCE_ERR("Failed to alloc memory.");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = strncpy_s(rbdev->name, IFNAMSIZ, bond_name, strlen(bond_name));
+ if (ret != EOK) {
+ ROCE_ERR("Failed to copy string, ret(%d).", ret);
+ kfree(rbdev);
+ return ERR_PTR(-EFAULT);
+ }
+
+ rbdev->need_clean_on_remove = true;
+ mutex_init(&rbdev->slave_lock);
+
+ mutex_lock(&g_roce5_bond_mutex);
+ list_add_tail(&rbdev->entry, &g_roce5_bond_list);
+ mutex_unlock(&g_roce5_bond_mutex);
+
+ return rbdev;
+}
+
+static int
+roce5_bond_destroy_transition_store(struct roce5_bond_device *bond_dev)
+{
+ int ret;
+ struct hinic5_lld_dev *ppf_lld = NULL;
+
+ if (bond_dev->slave_cnt == 0) {
+ ROCE_WARN("There's no slave in roce bond.");
+ return 0;
+ }
+
+ ppf_lld = hinic5_get_ppf_lld_dev(bond_dev->slaves[0].lld_dev);
+ if (ppf_lld == NULL) {
+ ROCE_ERR("Failed to get lld of the PPF.");
+ return -EINVAL;
+ }
+
+ ret = roce5_bond_transition_store(bond_dev, ppf_lld);
+ if (ret != 0) {
+ ROCE_ERR("Failed to store resources of transition, ret(%d).",
+ ret);
+ hinic5_lld_dev_put(ppf_lld);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void
+roce5_bond_destroy_transition_free(struct roce5_bond_device *bond_dev)
+{
+ roce5_bond_transition_free(bond_dev);
+}
+/*
+ * roce5_bond_destroy - Destroy bond device
+ * @bond_name: name of bond device
+ * @bond_id: bond ID
+ */
+void roce5_bond_destroy(const char *bond_name, u16 bond_id)
+{
+ int ret;
+ u32 i;
+ struct roce5_bond_device *bond_dev = NULL;
+
+ mutex_lock(&g_roce5_bond_mutex);
+ bond_dev = roce5_get_bond_dev(bond_name);
+ if (bond_dev == NULL) {
+ /* destroy switch thread handle, bond device may already be delete, current thread not disable care handle result */
+ ROCE_INFO("bond name(%s) has been detached", bond_name);
+ mutex_unlock(&g_roce5_bond_mutex);
+ return;
+ }
+
+ list_del(&bond_dev->entry);
+ mutex_unlock(&g_roce5_bond_mutex);
+
+ if (bond_dev->bond_lld_dev != NULL) {
+ ret = roce5_bond_destroy_transition_store(bond_dev);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to store transition resources on destroy.");
+ }
+
+ bond_dev->need_clean_on_remove = false;
+ hinic5_detach_service(bond_dev->bond_lld_dev, SERVICE_T_ROCE);
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ ret = hinic5_attach_service(bond_dev->slaves[i].lld_dev,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to attach roce device, ret(%d).",
+ ret);
+ }
+ }
+ bond_dev->slave_cnt = 0;
+ roce5_bond_destroy_transition_free(bond_dev);
+ mutex_unlock(&bond_dev->slave_lock);
+ }
+
+ kfree(bond_dev);
+ return;
+}
+
+/*
+ * roce5_bond_attach - Attach bond device to RoCE
+ * @rdev: RoCE device to attach
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_bond_attach(struct roce5_device *rdev)
+{
+ u32 i;
+ int ret = 0;
+ struct roce5_bond_device *bond_dev = NULL;
+
+ mutex_lock(&g_roce5_bond_mutex);
+ list_for_each_entry(bond_dev, &g_roce5_bond_list, entry) {
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ if (rdev->ndev != bond_dev->slaves[i].netdev) {
+ continue;
+ }
+
+ if (bond_dev->attached_rdev == NULL) {
+ bond_dev->attached_rdev = rdev;
+ rdev->bond_dev = bond_dev;
+ } else {
+ ret = -EEXIST;
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+ goto out;
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+ }
+out:
+ mutex_unlock(&g_roce5_bond_mutex);
+ return ret;
+}
+
+/*
+ * roce5_bond_is_active - Check if bond is active for RoCE device
+ * @rdev: RoCE device to check
+ * Return: true if bond is active, false otherwise
+ */
+bool roce5_bond_is_active(struct roce5_device *rdev)
+{
+ return (rdev->bond_dev != NULL);
+}
+
+void roce5_bond_detach(struct roce5_device *rdev)
+{
+ int ret;
+ u32 i;
+ struct roce5_bond_device *bond_dev = NULL;
+
+ mutex_lock(&g_roce5_bond_mutex);
+ bond_dev = rdev->bond_dev;
+ if (bond_dev == NULL) {
+ mutex_unlock(&g_roce5_bond_mutex);
+ ROCE_INFO("bond_dev is NULL.");
+ return;
+ }
+
+ if (bond_dev->need_clean_on_remove == false) {
+ mutex_unlock(&g_roce5_bond_mutex);
+ ROCE_INFO("bond_dev no need to detached on roce remove.");
+ return;
+ }
+
+ if (roce5_get_bond_dev(bond_dev->name) == bond_dev) {
+ list_del(&bond_dev->entry);
+ }
+
+ mutex_unlock(&g_roce5_bond_mutex);
+ ret = roce5_bond_destroy_transition_store(bond_dev);
+ if (ret != 0) {
+ ROCE_ERR("Failed to store transition resources on destroy.");
+ }
+ hinic5_bond_detach(bond_dev->attr.bond_id, HINIC5_BOND_USER_ROCE);
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ if (bond_dev->bond_lld_dev == bond_dev->slaves[i].lld_dev) {
+ continue;
+ }
+ ret = hinic5_attach_service(bond_dev->slaves[i].lld_dev,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_ERR("Failed to attach roce device, ret(%d).", ret);
+ }
+ }
+ bond_dev->slave_cnt = 0;
+ mutex_unlock(&bond_dev->slave_lock);
+ roce5_bond_destroy_transition_free(bond_dev);
+ mutex_lock(&g_roce5_bond_mutex);
+ kfree(bond_dev);
+ rdev->bond_dev = NULL;
+ mutex_unlock(&g_roce5_bond_mutex);
+}
+/*
+ * roce5_bond_event_cfg_rdev - Configure RoCE device for bond events
+ * @lld_dev: LLD device
+ * @uld_dev: ULD device
+ * @rdev: pointer to RoCE device pointer (output)
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_bond_event_cfg_rdev(struct hinic5_lld_dev *lld_dev, void *uld_dev,
+ struct roce5_device **rdev, bool hold_rdev)
+{
+ u32 i = 0;
+ struct roce5_bond_device *bond_dev = NULL;
+
+ if (lld_dev == NULL) {
+ ROCE_ERR("lld_dev is null.");
+ return -EINVAL;
+ }
+
+ if (uld_dev != NULL) {
+ *rdev = (struct roce5_device *)uld_dev;
+ return 0;
+ }
+
+ mutex_lock(&g_roce5_bond_mutex);
+ list_for_each_entry(bond_dev, &g_roce5_bond_list, entry) {
+ if (bond_dev == NULL) {
+ ROCE_ERR("bond_dev is null");
+ continue;
+ }
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ if (bond_dev->slaves[i].lld_dev == lld_dev) {
+ *rdev = bond_dev->attached_rdev;
+ if (hold_rdev == true && *rdev != NULL) {
+ uld5_dev_hold((*rdev)->lld_dev,
+ SERVICE_T_ROCE);
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+ goto out;
+ }
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+ }
+
+out:
+ mutex_unlock(&g_roce5_bond_mutex);
+ return *rdev ? 0 : -EINVAL;
+}
+
+/*
+ * roce5_update_rdev_func_val - Update function table values for RoCE device
+ * @bond_dev: bond device
+ */
+void roce5_update_rdev_func_val(struct roce5_bond_device *bond_dev)
+{
+ struct roce5_device *rdev = NULL;
+ u32 func_tbl_bond;
+ int ret;
+
+ if (bond_dev->bond_lld_dev == NULL) {
+ return;
+ }
+
+ rdev = hinic5_get_uld_dev(bond_dev->bond_lld_dev, SERVICE_T_ROCE);
+ if (rdev == NULL) {
+ ROCE_ERR("Failed to find roce device.");
+ return;
+ }
+
+ ret = roce5_get_func_table(rdev->hwdev, rdev->glb_func_id,
+ &func_tbl_bond);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev,
+ "Failed to get func table value, func_id(%d).",
+ rdev->glb_func_id);
+ uld5_dev_put(bond_dev->bond_lld_dev, SERVICE_T_ROCE);
+ return;
+ }
+
+ write_lock(&rdev->rwlock_func_tbl_bond);
+ rdev->func_tbl_bond = func_tbl_bond;
+ write_unlock(&rdev->rwlock_func_tbl_bond);
+
+ uld5_dev_put(bond_dev->bond_lld_dev, SERVICE_T_ROCE);
+}
+
+bool roce5_get_bond_ipsurx_en(void)
+{
+ return g_roce5_bond_ipsurx_en;
+}
+
+void roce5_set_bond_ipsurx_en(bool ipsurx_en)
+{
+ g_roce5_bond_ipsurx_en = ipsurx_en;
+}
+
+/*
+ * roce5_bond_init - Initialize RoCE bond module
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_bond_init(void)
+{
+ int ret;
+ struct bond_srv_func roce_func = {
+ .before_active = roce5_before_bond_active,
+ .after_active = roce5_after_bond_active,
+ .before_modify = roce5_before_bond_modify,
+ .after_modify = roce5_after_bond_modify,
+ .before_deactive = roce5_before_bond_deactive,
+ .after_deactive = roce5_after_bond_deactive,
+ .can_attach = roce5_can_do_bond,
+ };
+
+ ret = hinic5_bond_register(HINIC5_BOND_USER_ROCE, &roce_func);
+ if (ret != 0) {
+ ROCE_ERR("Failed to register bond, ret(%d).", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+void roce5_bond_exit(void)
+{
+ int ret;
+ struct roce5_bond_device *bond_dev = NULL;
+
+ mutex_lock(&g_roce5_bond_mutex);
+ list_for_each_entry(bond_dev, &g_roce5_bond_list, entry) {
+ bond_dev->need_clean_on_remove = false;
+ }
+ mutex_unlock(&g_roce5_bond_mutex);
+
+ ret = hinic5_bond_unregister(HINIC5_BOND_USER_ROCE);
+ if (ret != 0) {
+ ROCE_ERR("Failed to unregister service func, ret(%d).", ret);
+ }
+}
+
+#endif /* ROCE_BONDING_EN */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_internal.h b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_internal.h
new file mode 100644
index 000000000..fd9853215
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_internal.h
@@ -0,0 +1,97 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
+
+
+#ifndef ROCE_BOND_INTERNAL_H
+#define ROCE_BOND_INTERNAL_H
+
+#ifdef ROCE_BONDING_EN
+
+#include <net/bonding.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include "hinic5_lld.h"
+#include "drv_bond_api.h"
+#include "bond_common_defs.h"
+#include "roce_bond.h"
+
+/* Slave synchronization structure for bond modify */
+struct roce5_bond_slave_sync {
+ bool exist_arr
+ [ROCE_BOND_MAX_SLAVE]; /* Indicate which slave need to be deleted */
+ struct net_device *
+ new_ndev[ROCE_BOND_MAX_SLAVE]; /* New slaves need to be added */
+ struct netdev_lower_state_info new_ndev_state[BOND_PORT_MAX_NUM];
+ u32 new_ndev_num;
+};
+
+/* Global variables declaration */
+extern struct list_head g_roce5_bond_list; //TODO: later via interface access
+extern struct mutex g_roce5_bond_mutex; //TODO: later via interface access
+extern struct workqueue_struct *g_bond_wq; //TODO: later via interface access
+
+/* CFM Interface Layer - Internal Functions */
+bool roce5_bond_mode_is_supported(u16 bond_mode);
+int roce5_bond_slave_check(struct hinic5_lld_dev *lld_dev, char *chip_name,
+ size_t chip_name_size);
+bool roce5_bond_before_active_check(struct bond_tracker *tracker,
+ struct bond_attr *attr);
+bool roce5_can_do_bond(struct bonding *bond);
+
+/* CFM Callback Functions (called by CFM framework) */
+void roce5_before_bond_active(const char *bond_name, struct bond_attr *attr,
+ int err);
+void roce5_after_bond_active(const char *bond_name, struct bond_attr *attr,
+ int err);
+void roce5_before_bond_modify(const char *bond_name, struct bond_attr *attr,
+ int err);
+void roce5_after_bond_modify(const char *bond_name, struct bond_attr *attr,
+ int err);
+void roce5_before_bond_deactive(const char *bond_name, struct bond_attr *attr,
+ int err);
+void roce5_after_bond_deactive(const char *bond_name, struct bond_attr *attr,
+ int err);
+
+/* Device Management Layer - Internal Functions */
+struct roce5_bond_device *roce5_get_bond_dev(const char *bond_name);
+struct roce5_bond_device *roce5_get_bond_dev_by_name(const char *bond_name);
+void roce5_bond_destroy(const char *bond_name, u16 bond_id);
+void roce5_update_rdev_func_val(struct roce5_bond_device *bond_dev);
+struct hinic5_lld_dev *
+roce5_bond_get_ppf_lld(const struct bond_tracker *tracker);
+struct roce5_bond_device *roce5_bond_create_bond_device(const char *bond_name);
+
+/* Slave Management Layer - Internal Functions */
+struct roce5_bond_slave *
+roce5_find_next_slave_slot(struct roce5_bond_device *rbdev);
+int roce5_get_bond_slave_index_by_ndev(struct roce5_bond_device *rbdev,
+ struct net_device *ndev);
+int roce5_bond_add_slave(struct roce5_bond_device *rbdev,
+ struct net_device *ndev,
+ struct netdev_lower_state_info *ndev_info,
+ bool is_update_table);
+int roce5_bond_del_slave(struct roce5_bond_device *rbdev, u32 slave_index);
+int roce5_find_same_slave_and_update(struct roce5_bond_device *rbdev,
+ struct bond_tracker *tracker,
+ struct roce5_bond_slave_sync *slave_sync);
+int roce5_handle_diff_slave(struct roce5_bond_device *rbdev,
+ struct bond_tracker *tracker);
+
+/* MAC Table Operation Layer - Internal Functions */
+int roce5_bond_add_slave_table(struct roce5_bond_device *rbdev, u8 slave_er_id,
+ u16 slave_func_id);
+int roce5_bond_del_slave_table(struct roce5_bond_device *rbdev, u8 slave_er_id,
+ u16 slave_func_id);
+
+/* TX Port Selection Layer - Internal Functions (declared in roce_bond.h as public) */
+
+int roce5_bond_transition_store(struct roce5_bond_device *bond_dev,
+ struct hinic5_lld_dev *ppf_lld);
+void roce5_bond_transition_free(struct roce5_bond_device *bond_dev);
+
+#endif /* ROCE_BONDING_EN */
+
+#endif /* ROCE_BOND_INTERNAL_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_mac.c b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_mac.c
new file mode 100644
index 000000000..75264917f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_mac.c
@@ -0,0 +1,260 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
+
+
+#ifdef ROCE_BONDING_EN
+
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+#include <net/bonding.h>
+
+#include "securec.h"
+
+#include "hinic5_hw.h"
+#include "hinic5_srv_nic.h"
+
+#include "roce_bond.h"
+#include "roce_bond_internal.h"
+#include "roce_cmd.h"
+#include "roce_netdev.h"
+#include "roce_infra.h"
+
+/*
+ * roce5_add_bond_real_slave_mac - Add real slave MAC to table
+ * @rdev: RoCE device
+ * @mac: MAC address to add
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_add_bond_real_slave_mac(struct roce5_device *rdev, u8 *mac)
+{
+ struct roce5_bond_device *bond_dev = rdev->bond_dev;
+ struct roce5_bond_slave *slave = NULL;
+ int ret;
+ u32 i;
+
+ if (bond_dev == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to find bond_dev, func_id(%u).",
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ slave = &bond_dev->slaves[i];
+
+ ret = roce5_add_mac_tbl_mac_entry(rdev, mac, ETH_ALEN,
+ ROCE_BOND_RSVD_VLAN_ID,
+ slave->func_id);
+ if (ret != 0) {
+ mutex_unlock(&bond_dev->slave_lock);
+ ROCE_DEV_ERR(rdev,
+ "Failed to add mac_vlan entry, ret(%d).",
+ ret);
+ return ret;
+ }
+
+ if (slave->func_id != rdev->glb_func_id) {
+ /* The IPSU MAC table is used for fast forwarding. Even if the addition fails, the forwarding information
+ can still be obtained by checking the MAC table later, without judging the execution result. */
+ roce5_add_ipsu_tbl_mac_entry(rdev, mac, 0,
+ rdev->glb_func_id,
+ slave->er_id,
+ slave->func_id);
+ }
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+
+ return 0;
+}
+
+/*
+ * roce5_add_bond_vlan_slave_mac - Add VLAN slave Mac to table
+ * @rdev: RoCE device
+ * @mac: MAC address to add
+ * @vlan_id: VLAN ID
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_add_bond_vlan_slave_mac(struct roce5_device *rdev, u8 *mac,
+ u16 vlan_id)
+{
+ struct roce5_bond_device *bond_dev = rdev->bond_dev;
+ struct roce5_bond_slave *slave = NULL;
+ int ret;
+ u32 i;
+
+ if (bond_dev == NULL) {
+ ROCE_DEV_ERR(rdev, "Failed to find bond_dev");
+ return -EINVAL;
+ }
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ slave = &bond_dev->slaves[i];
+ if (slave->func_id == rdev->glb_func_id) {
+ continue;
+ }
+
+ ret = roce5_add_mac_tbl_mac_entry(rdev, mac, ETH_ALEN, vlan_id,
+ slave->func_id);
+ if (ret != 0) {
+ mutex_unlock(&bond_dev->slave_lock);
+ ROCE_DEV_ERR(rdev,
+ "Failed to add mac_vlan entry, ret(%d).",
+ ret);
+ return ret;
+ }
+
+ /* The IPSU MAC table is used for fast forwarding. Even if the addition fails, the forwarding information
+ can still be obtained by checking the MAC table later, without judging the execution result. */
+ roce5_add_ipsu_tbl_mac_entry(rdev, mac, vlan_id,
+ rdev->glb_func_id, slave->er_id,
+ slave->func_id);
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+
+ return 0;
+}
+
+/*
+ * roce5_del_bond_real_slave_mac - Delete real slave Mac from table
+ * @rdev: RoCE device
+ */
+void roce5_del_bond_real_slave_mac(struct roce5_device *rdev)
+{
+ u32 i;
+ struct roce5_bond_slave *slave = NULL;
+ struct roce5_bond_device *bond_dev = rdev->bond_dev;
+
+ if (bond_dev == NULL) {
+ return;
+ }
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ slave = &bond_dev->slaves[i];
+ if (slave->func_id != rdev->glb_func_id) {
+ roce5_del_ipsu_tbl_mac_entry(rdev, rdev->mac, ETH_ALEN,
+ 0, slave->er_id,
+ slave->func_id);
+ }
+
+ (void)roce5_del_mac_tbl_mac_entry(rdev, rdev->mac, ETH_ALEN,
+ ROCE_BOND_RSVD_VLAN_ID,
+ slave->func_id);
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+}
+
+/*
+ * roce5_del_bond_vlan_slave_mac - Delete VLAN slave Mac from table
+ * @rdev: RoCE device
+ * @mac: MAC address to delete
+ * @vlan_id: VLAN ID
+ */
+void roce5_del_bond_vlan_slave_mac(struct roce5_device *rdev, u8 *mac,
+ u16 vlan_id)
+{
+ u32 i;
+ struct roce5_bond_slave *slave = NULL;
+ struct roce5_bond_device *bond_dev = rdev->bond_dev;
+
+ if (bond_dev == NULL) {
+ return;
+ }
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ slave = &bond_dev->slaves[i];
+ if (slave->func_id == rdev->glb_func_id) {
+ continue;
+ }
+
+ roce5_del_ipsu_tbl_mac_entry(rdev, mac, ETH_ALEN, vlan_id,
+ slave->er_id, slave->func_id);
+
+ (void)roce5_del_mac_tbl_mac_entry(rdev, mac, ETH_ALEN, vlan_id,
+ slave->func_id);
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+}
+
+/*
+ * roce5_bond_add_slave_table - Add slave table entry
+ * @rbdev: bond device
+ * @slave_er_id: slave ER ID
+ * @slave_func_id: slave function ID
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_bond_add_slave_table(struct roce5_bond_device *rbdev, u8 slave_er_id,
+ u16 slave_func_id)
+{
+ struct roce5_device *rdev = rbdev->attached_rdev;
+ struct roce5_vlan_dev_list *vlan_dev_list = NULL;
+
+ if ((rdev == NULL) || (rdev->hwdev == NULL)) {
+ ROCE_ERR("Missing attached roce device.");
+ return -EINVAL;
+ }
+
+ /* Add entry of non-vlan device */
+ roce5_add_ipsu_tbl_mac_entry(rdev, (u8 *)rdev->mac, 0,
+ rdev->glb_func_id, slave_er_id,
+ slave_func_id);
+ /* Add entries of vlan device */
+ mutex_lock(&rdev->mac_vlan_mutex);
+ if (rdev->mac_vlan_list_head.next == NULL) {
+ ROCE_ERR("mac vlan list not init.");
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ return -EINVAL;
+ }
+ list_for_each_entry(vlan_dev_list, &rdev->mac_vlan_list_head, list) {
+ roce5_add_ipsu_tbl_mac_entry(rdev, (u8 *)rdev->mac,
+ vlan_dev_list->vlan_id,
+ rdev->glb_func_id, slave_er_id,
+ slave_func_id);
+ }
+ mutex_unlock(&rdev->mac_vlan_mutex);
+
+ return 0;
+}
+
+/*
+ * roce5_bond_del_slave_table - Delete slave table entry
+ * @rbdev: bond device
+ * @slave_er_id: slave ER ID
+ * @slave_func_id: slave function ID
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_bond_del_slave_table(struct roce5_bond_device *rbdev, u8 slave_er_id,
+ u16 slave_func_id)
+{
+ struct roce5_device *rdev = rbdev->attached_rdev;
+ struct roce5_vlan_dev_list *vlan_dev_list = NULL;
+
+ if ((rdev == NULL) || (rdev->hwdev == NULL)) {
+ ROCE_ERR("Missing attached roce device.");
+ return -EINVAL;
+ }
+
+ /* Delete entry of non-vlan device */
+ roce5_del_ipsu_tbl_mac_entry(rdev, rdev->mac, ETH_ALEN, 0, slave_er_id,
+ slave_func_id);
+ /* Delete entries of vlan device */
+ mutex_lock(&rdev->mac_vlan_mutex);
+ if (rdev->mac_vlan_list_head.next == NULL) {
+ ROCE_ERR("mac vlan list not init.");
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ return -EINVAL;
+ }
+ list_for_each_entry(vlan_dev_list, &rdev->mac_vlan_list_head, list) {
+ roce5_del_ipsu_tbl_mac_entry(rdev, rdev->mac, ETH_ALEN,
+ vlan_dev_list->vlan_id,
+ slave_er_id, slave_func_id);
+ }
+ mutex_unlock(&rdev->mac_vlan_mutex);
+
+ return 0;
+}
+
+#endif /* ROCE_BONDING_EN */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_slave.c b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_slave.c
new file mode 100644
index 000000000..a0fee96a4
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_slave.c
@@ -0,0 +1,459 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
+
+
+#ifdef ROCE_BONDING_EN
+
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+#include <net/bonding.h>
+
+#include "securec.h"
+
+#include "bond_common_defs.h"
+#include "hinic5_hw.h"
+#include "hinic5_srv_nic.h"
+
+#include "roce_bond.h"
+#include "roce_bond_internal.h"
+#include "roce_cmd.h"
+#include "roce_netdev.h"
+#include "roce_infra.h"
+
+/*
+ * roce5_find_next_slave_slot - Find next available slave slot
+ * @rbdev: bond device
+ * Return: pointer to available slave slot, NULL if no slot available
+ * Lock: caller must hold rbdev->slave_lock
+ */
+struct roce5_bond_slave *
+roce5_find_next_slave_slot(struct roce5_bond_device *rbdev)
+{
+ if (rbdev->slave_cnt >= ROCE_BOND_MAX_SLAVE) {
+ ROCE_ERR(
+ "RoCE bond device slave slots are full, max number of slaves is %d.",
+ ROCE_BOND_MAX_SLAVE);
+ return NULL;
+ }
+
+ if (rbdev->slaves[rbdev->slave_cnt].netdev != NULL) {
+ ROCE_ERR("Error occur! Slave slot is broken, slot index(%d).",
+ rbdev->slave_cnt);
+ return NULL;
+ }
+
+ return &rbdev->slaves[rbdev->slave_cnt];
+}
+
+/*
+ * roce5_get_bond_slave_index_by_ndev - Get slave index by netdev
+ * @rbdev: bond device
+ * @ndev: netdev to search for
+ * Return: slave index if found, negative error code otherwise
+ * Lock: caller must hold rbdev->slave_lock
+ */
+int roce5_get_bond_slave_index_by_ndev(struct roce5_bond_device *rbdev,
+ struct net_device *ndev)
+{
+ u32 index;
+
+ for (index = 0; index < rbdev->slave_cnt; ++index) {
+ if (rbdev->slaves[index].netdev == ndev) {
+ return (int)index;
+ }
+ }
+
+ return -ENODEV;
+}
+
+static void roce5_bond_slave_init(struct roce5_bond_slave *slave,
+ struct net_device *ndev,
+ struct hinic5_lld_dev *ndev_lld,
+ struct netdev_lower_state_info *ndev_info,
+ bool is_update_table,
+ struct roce5_bond_device *rbdev)
+{
+ int ret;
+
+ slave->netdev = ndev;
+ slave->netdev_state.link_up = ndev_info->link_up;
+ slave->netdev_state.tx_enabled = ndev_info->tx_enabled;
+
+ slave->lld_dev = ndev_lld;
+ slave->func_id = hinic5_global_func_id(slave->lld_dev->hwdev);
+ slave->er_id = hinic5_er_id(slave->lld_dev->hwdev);
+
+ hinic5_detach_service(slave->lld_dev, SERVICE_T_ROCE);
+
+ if (is_update_table) {
+ ret = roce5_bond_add_slave_table(rbdev, slave->er_id,
+ slave->func_id);
+ if (ret != 0) {
+ ROCE_WARN(
+ "Failed to add table entries of slave(%u), ret(%d).",
+ slave->func_id, ret);
+ }
+ }
+}
+
+static void roce5_bond_slave_deinit(struct roce5_bond_slave *slave,
+ bool is_update_table,
+ struct roce5_bond_device *rbdev)
+{
+ int ret;
+
+ if (is_update_table) {
+ ret = roce5_bond_del_slave_table(rbdev, slave->er_id,
+ slave->func_id);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to delete slave table entries, ret(%d).",
+ ret);
+ }
+ }
+
+ ret = hinic5_attach_service(slave->lld_dev, SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to attach roce function, func_id(%u), ret(%d).",
+ slave->func_id, ret);
+ }
+}
+
+/*
+ * roce5_bond_add_slave - Add slave to bond device
+ * @rbdev: bond device
+ * @ndev: slave netdev
+ * @ndev_info: slave state info
+ * @is_update_table: whether to update MAC table
+ * Return: 0 on success, negative error code on failure
+ * Lock: caller must hold rbdev->slave_lock
+ */
+int roce5_bond_add_slave(struct roce5_bond_device *rbdev,
+ struct net_device *ndev,
+ struct netdev_lower_state_info *ndev_info,
+ bool is_update_table)
+{
+ int ret, err_ret;
+ struct hinic5_lld_dev *ndev_lld = NULL;
+ struct roce5_bond_slave *slave = NULL;
+ struct roce5_bond_slave slave_temp;
+
+ ndev_lld = hinic5_get_lld_dev_by_netdev(ndev);
+ if (ndev_lld == NULL) {
+ ROCE_ERR("Failed to get lld dev by netdev %s.", ndev->name);
+ return -ENODEV;
+ }
+
+ if (hinic5_support_roce(ndev_lld->hwdev, NULL) == false) {
+ return 0;
+ }
+
+ roce5_bond_slave_init(&slave_temp, ndev, ndev_lld, ndev_info,
+ is_update_table, rbdev);
+
+ /* Add slave to roce bond device. */
+ mutex_lock(&rbdev->slave_lock);
+
+ slave = roce5_find_next_slave_slot(rbdev);
+ if (slave == NULL) {
+ ROCE_ERR("Failed to find next slave slot.");
+ ret = -ENXIO;
+ mutex_unlock(&rbdev->slave_lock);
+ goto err_without_slot;
+ }
+
+ *slave = slave_temp;
+ ++rbdev->slave_cnt;
+
+ mutex_unlock(&rbdev->slave_lock);
+
+ /* Try to attach roce device to roce bond device. */
+ if (rbdev->attached_rdev == NULL) {
+ if (rbdev->bond_lld_dev != NULL) {
+ ROCE_ERR("Impossible situation! bond lld isn't NULL.");
+ ret = -EINVAL;
+ goto err_check;
+ }
+
+ rbdev->bond_lld_dev = ndev_lld;
+
+ ret = hinic5_attach_service(rbdev->bond_lld_dev,
+ SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to attach roce service, ret(%d), bond name(%s).",
+ ret, rbdev->name);
+ ret = -EINVAL;
+ goto err_attach;
+ }
+
+ if (rbdev->attached_rdev == NULL) {
+ ROCE_ERR(
+ "Failed to attach roce bond device with roce device, bond name(%s).",
+ rbdev->name);
+ ret = -EINVAL;
+ goto err_attach_bond;
+ }
+ }
+
+ return 0;
+
+err_attach_bond:
+ hinic5_detach_service(rbdev->bond_lld_dev, SERVICE_T_ROCE);
+err_attach:
+ rbdev->bond_lld_dev = NULL;
+err_check:
+ mutex_lock(&rbdev->slave_lock);
+ err_ret = memset_s(slave, sizeof(struct roce5_bond_slave), 0,
+ sizeof(struct roce5_bond_slave));
+ if (err_ret != 0) {
+ ROCE_ERR("Failed to clean memory of slave, ret(%d).", err_ret);
+ }
+ --rbdev->slave_cnt;
+ mutex_unlock(&rbdev->slave_lock);
+err_without_slot:
+ roce5_bond_slave_deinit(&slave_temp, is_update_table, rbdev);
+ return ret;
+}
+
+/*
+ * roce5_bond_del_slave - Delete slave from bond device
+ * @rbdev: bond device
+ * @slave_index: index of slave to delete
+ * Return: 0 on success, negative error code on failure
+ * Lock: caller must hold rbdev->slave_lock
+ */
+int roce5_bond_del_slave(struct roce5_bond_device *rbdev, u32 slave_index)
+{
+ int ret;
+ struct roce5_bond_slave *slave = NULL;
+ struct roce5_bond_slave slave_temp;
+ size_t mem_copy_len;
+
+ mutex_lock(&rbdev->slave_lock);
+
+ if (slave_index >= rbdev->slave_cnt) {
+ ROCE_ERR("Invalid parameter, slave index(%u), slave count(%u).",
+ slave_index, rbdev->slave_cnt);
+ ret = -EINVAL;
+ mutex_unlock(&rbdev->slave_lock);
+ goto err_out;
+ }
+
+ slave = &rbdev->slaves[slave_index];
+ if (rbdev->bond_lld_dev != NULL &&
+ slave->lld_dev == rbdev->bond_lld_dev) {
+ ROCE_WARN(
+ "Slave(%s) lld dev is the same as the roce bond device(%s), skip removing.",
+ slave->netdev->name,
+ (rbdev->attached_rdev != NULL) ?
+ rbdev->attached_rdev->ib_dev.name :
+ "NULL");
+ ret = 0;
+ mutex_unlock(&rbdev->slave_lock);
+ goto err_out;
+ }
+
+ slave_temp = *slave;
+
+ ret = memset_s(slave, sizeof(struct roce5_bond_slave), 0,
+ sizeof(struct roce5_bond_slave));
+ if (ret != 0) {
+ ROCE_WARN("Failed to clear slave information.");
+ }
+
+ if (slave_index != ROCE_BOND_MAX_SLAVE - 1) {
+ mem_copy_len = sizeof(struct roce5_bond_slave) *
+ (ROCE_BOND_MAX_SLAVE - slave_index - 1);
+ ret = memmove_s((void *)&rbdev->slaves[slave_index],
+ mem_copy_len,
+ (void *)&rbdev->slaves[slave_index + 1],
+ mem_copy_len);
+ if (ret != EOK) {
+ ROCE_ERR("Failed to execute memmove, ret(%d).", ret);
+ mutex_unlock(&rbdev->slave_lock);
+ goto err_out;
+ }
+ }
+
+ ret = memset_s((void *)&rbdev->slaves[ROCE_BOND_MAX_SLAVE - 1],
+ sizeof(struct roce5_bond_slave), 0,
+ sizeof(struct roce5_bond_slave));
+ if (ret != 0) {
+ ROCE_ERR("Failed to execute memmove, ret(%d).", ret);
+ mutex_unlock(&rbdev->slave_lock);
+ goto err_out;
+ }
+
+ --rbdev->slave_cnt;
+
+ mutex_unlock(&rbdev->slave_lock);
+
+ if (rbdev->slave_cnt == 0 && rbdev->attached_rdev != NULL) {
+ if (rbdev->bond_lld_dev == NULL) {
+ ROCE_ERR("Impossible situation! bond lld is NULL.");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ hinic5_detach_service(rbdev->bond_lld_dev, SERVICE_T_ROCE);
+ if (rbdev->attached_rdev != NULL) {
+ ROCE_ERR(
+ "Failed to detach roce service, bond name(%s).",
+ rbdev->name);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ rbdev->bond_lld_dev = NULL;
+ }
+
+ ret = roce5_bond_del_slave_table(rbdev, slave_temp.er_id,
+ slave_temp.func_id);
+ if (ret != 0) {
+ ROCE_WARN(
+ "Failed to delete table entries of slave(%u), ret(%d).",
+ slave_temp.func_id, ret);
+ ret = 0;
+ }
+
+ ret = hinic5_attach_service(slave_temp.lld_dev, SERVICE_T_ROCE);
+ if (ret != 0) {
+ ROCE_ERR("Failed to attach roce function, func_id(%u).",
+ slave_temp.func_id);
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ return ret;
+}
+
+/*
+ * roce5_find_same_slave_and_update - Find and update existing slave
+ * @rbdev: bond device
+ * @tracker: bond tracker from CFM framework
+ * @slave_sync: slave synchronization info
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_find_same_slave_and_update(struct roce5_bond_device *rbdev,
+ struct bond_tracker *tracker,
+ struct roce5_bond_slave_sync *slave_sync)
+{
+ int ret = 0;
+ int i;
+ int roce_slave_index;
+ int tracker_slave_cnt = 0;
+ struct hinic5_lld_dev *lld_dev = NULL;
+ char chip_name[IFNAMSIZ] = { 0 };
+ int err;
+
+ ret = memset_s(slave_sync, sizeof(struct roce5_bond_slave_sync), 0,
+ sizeof(struct roce5_bond_slave_sync));
+ if (ret != 0) {
+ ROCE_ERR("Failed to init slave sync info, ret(%d).", ret);
+ return ret;
+ }
+
+ mutex_lock(&rbdev->slave_lock);
+
+ if (rbdev->bond_lld_dev != NULL) {
+ err = hinic5_get_chip_name(rbdev->bond_lld_dev, chip_name,
+ sizeof(chip_name));
+ if (err != 0) {
+ ROCE_ERR("Bond dev get chip name err %d.", err);
+ mutex_unlock(&rbdev->slave_lock);
+ return err;
+ }
+ }
+
+ for (i = 0; i < BOND_PORT_MAX_NUM && tracker_slave_cnt < tracker->cnt;
+ ++i) {
+ if (tracker->ndev[i] == NULL) {
+ continue;
+ }
+
+ roce_slave_index = roce5_get_bond_slave_index_by_ndev(
+ rbdev, tracker->ndev[i]);
+ if (roce_slave_index == -ENODEV) {
+ lld_dev =
+ hinic5_get_lld_dev_by_netdev(tracker->ndev[i]);
+ err = roce5_bond_slave_check(lld_dev, chip_name,
+ sizeof(chip_name));
+ if (err != 0) {
+ ROCE_ERR("Bond slave check err %d.", err);
+ mutex_unlock(&rbdev->slave_lock);
+ return err;
+ }
+
+ slave_sync->new_ndev[slave_sync->new_ndev_num] =
+ tracker->ndev[i];
+ slave_sync->new_ndev_state[slave_sync->new_ndev_num] =
+ tracker->netdev_state[i];
+ ++slave_sync->new_ndev_num;
+ } else {
+ slave_sync->exist_arr[roce_slave_index] = true;
+
+ /* update state of the slave */
+ rbdev->slaves[roce_slave_index].netdev_state.link_up =
+ tracker->netdev_state[i].link_up;
+ rbdev->slaves[roce_slave_index].netdev_state.tx_enabled =
+ tracker->netdev_state[i].tx_enabled;
+ }
+
+ ++tracker_slave_cnt;
+ }
+
+ mutex_unlock(&rbdev->slave_lock);
+
+ return ret;
+}
+
+/*
+ * roce5_handle_diff_slave - Handle different slaves during bond modify
+ * @rbdev: bond device
+ * @tracker: bond tracker from CFM framework
+ * Return: 0 on success, negative error code on failure
+ */
+int roce5_handle_diff_slave(struct roce5_bond_device *rbdev,
+ struct bond_tracker *tracker)
+{
+ u32 i;
+ int ret = 0;
+ struct roce5_bond_slave_sync slave_sync;
+
+ ret = roce5_find_same_slave_and_update(rbdev, tracker, &slave_sync);
+ if (ret != 0) {
+ ROCE_ERR("Failed to find same netdev.");
+ return ret;
+ }
+
+ /* delete slaves */
+ for (i = rbdev->slave_cnt; i > 0; --i) {
+ if (slave_sync.exist_arr[i - 1] == false) {
+ ret = roce5_bond_del_slave(rbdev, i - 1);
+ if (ret != 0) {
+ ROCE_ERR("Failed to delete slave, ret(%d).",
+ ret);
+ return ret;
+ }
+ }
+ }
+
+ /* add new slaves */
+ for (i = 0; i < slave_sync.new_ndev_num; ++i) {
+ ret = roce5_bond_add_slave(rbdev, slave_sync.new_ndev[i],
+ &slave_sync.new_ndev_state[i], true);
+ if (ret != 0) {
+ ROCE_ERR("Failed to add new slave, ret(%d).", ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+#endif /* ROCE_BONDING_EN */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_tx.c b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_tx.c
new file mode 100644
index 000000000..dd34d319e
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/bond/roce_bond_tx.c
@@ -0,0 +1,94 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
+
+
+#ifdef ROCE_BONDING_EN
+
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+#include <net/bonding.h>
+#include <linux/atomic.h>
+
+#include "securec.h"
+
+#include "hinic5_hw.h"
+#include "hinic5_srv_nic.h"
+
+#include "roce_bond.h"
+#include "roce_bond_internal.h"
+#include "roce_cmd.h"
+#include "roce_netdev.h"
+#include "roce_infra.h"
+
+/*
+ * roce5_bond_get_netdev - Get bond netdev for TX
+ * @rdev: RoCE device
+ * Return: netdev with increased reference count, NULL if no bond
+ * Refcount: caller must call dev_put() when done
+ */
+struct net_device *roce5_bond_get_netdev(struct roce5_device *rdev)
+{
+ u32 i;
+ struct roce5_bond_device *bond_dev = rdev->bond_dev;
+ struct net_device *ret_dev = NULL;
+ struct slave *slave = NULL;
+
+ mutex_lock(&g_roce5_bond_mutex);
+ if (bond_dev == NULL) {
+ mutex_unlock(&g_roce5_bond_mutex);
+ return ret_dev;
+ }
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ rcu_read_lock();
+ slave = bond_slave_get_rcu(bond_dev->slaves[i].netdev);
+ rcu_read_unlock();
+ if (slave == NULL) {
+ continue;
+ }
+ if (bond_is_active_slave(slave)) {
+ if (netif_running(bond_dev->slaves[i].netdev) &&
+ netif_carrier_ok(bond_dev->slaves[i].netdev)) {
+ ret_dev = bond_dev->slaves[i].netdev;
+ } else if (netif_running(
+ bond_dev->slaves[(i + 1) %
+ bond_dev->slave_cnt]
+ .netdev) &&
+ netif_carrier_ok(
+ bond_dev->slaves[(i + 1) %
+ bond_dev->slave_cnt]
+ .netdev)) {
+ ret_dev = bond_dev->slaves[(i + 1) %
+ bond_dev->slave_cnt]
+ .netdev;
+ } else {
+ ret_dev = bond_dev->slaves[i].netdev;
+ }
+ dev_hold(ret_dev);
+ mutex_unlock(&bond_dev->slave_lock);
+ mutex_unlock(&g_roce5_bond_mutex);
+ return ret_dev;
+ }
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+ mutex_unlock(&g_roce5_bond_mutex);
+ return ret_dev;
+}
+
+/*
+ * roce5_bond_rr_set_flow - Set flow hash for round-robin TX selection
+ * @rdev: RoCE device
+ * @rqp: RoCE QP
+ * @qp_attr: QP attributes
+ */
+void roce5_bond_rr_set_flow(struct roce5_device *rdev, struct roce5_qp *rqp,
+ roce_verbs_qp_attr_s *qp_attr)
+{
+ rqp->tx_hash_value = (u32)atomic_add_return(1, &rdev->next_port);
+ qp_attr->path_info.dw0.bs.bond_tx_hash_value =
+ (rqp->tx_hash_value & 0xf);
+}
+
+#endif /* ROCE_BONDING_EN */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/debug/roce_debug.h b/drivers/infiniband/hw/hiroce5/kernel/util/debug/roce_debug.h
new file mode 100644
index 000000000..6b919d753
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/debug/roce_debug.h
@@ -0,0 +1,25 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_DEBUG_H
+#define ROCE_DEBUG_H
+
+/*
+ * DEBUG_ONLY: statement is only valid in debug mode.
+ *
+ * RELEASE_ONLY: statement is only valid in release mode.
+ *
+ * DEBUG_REPLACE: used in functions of release to indicate the function may be replaced by another function with the
+ * same name defined in the debug mode.
+ */
+#ifdef ENABLE_DEBUG
+#define DEBUG_ONLY(statement) statement
+#define RELEASE_ONLY(statement)
+#define DEBUG_REPLACE __attribute__((weak))
+#else
+#define DEBUG_ONLY(statement)
+#define RELEASE_ONLY(statement) statement
+#define DEBUG_REPLACE
+#endif
+
+#endif /* ROCE_DEBUG_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx.c b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx.c
new file mode 100644
index 000000000..787a86791
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx.c
@@ -0,0 +1,375 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved.
+
+
+#ifdef __ROCE_DFX__
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+#include "roce.h"
+#include "hinic5_mt.h"
+#include "roce_cc_format.h"
+#include "roce_cmd.h"
+#include "roce_mpu_cmd.h"
+#include "roce_mpu_cmd_defs.h"
+#include "securec.h"
+#include "roce_dfx.h"
+
+int roce5_get_drv_version(void *buf_out, u32 *out_size)
+{
+ struct drv_version_info *ver_info = buf_out;
+ int rc;
+
+ if (!buf_out || !out_size) {
+ ROCE_ERR("Input params is NULL.");
+ return -EINVAL;
+ }
+
+ if (*out_size != sizeof(*ver_info)) {
+ ROCE_ERR("Unexpect out buf size from user :%u, expect: %lu",
+ *out_size, sizeof(*ver_info));
+ return -EINVAL;
+ }
+
+ rc = snprintf_s(ver_info->ver, sizeof(ver_info->ver),
+ sizeof(ver_info->ver) - 1, "%s %s",
+ HIROCE5_DRV_VERSION, __TIME_STR__);
+ if (rc == -1) {
+ ROCE_ERR("Snprintf roce version err");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+void *
+roce5_adm_generic_find_cmd_func(const roce5_adm_generic_cmd_proc_t *cmd_array,
+ int elem_count, u32 target_cmd)
+{
+ int i;
+
+ if (cmd_array == NULL || elem_count <= 0) {
+ return NULL;
+ }
+
+ for (i = 0; i < elem_count; i++) {
+ if (cmd_array[i].cmd_type == target_cmd &&
+ cmd_array[i].proc_func != NULL) {
+ return cmd_array[i].proc_func;
+ }
+ }
+ return NULL;
+}
+
+static int roce5_dfx_enable_bw_ctrl(struct roce5_device *rdev,
+ struct roce5_bw_ctrl_inbuf *inbuf,
+ struct roce5_bw_ctrl_outbuf *outbuf)
+{
+ if (rdev->hw_info.hca_type == ROCE5_2_100G_HCA) {
+ inbuf->ctrl_param.cir = ROCE5_100G_CIR;
+ inbuf->ctrl_param.pir = ROCE5_100G_PIR;
+ inbuf->ctrl_param.cnp = ROCE5_100G_CNP;
+ } else {
+ inbuf->ctrl_param.cir = ROCE5_25G_CIR;
+ inbuf->ctrl_param.pir = ROCE5_25G_PIR;
+ inbuf->ctrl_param.cnp = ROCE5_25G_CNP;
+ }
+ return roce5_set_bw_ctrl_state(rdev, ROCE_BW_CTRL_EN, inbuf);
+}
+
+static int roce5_dfx_disable_bw_ctrl(struct roce5_device *rdev,
+ struct roce5_bw_ctrl_inbuf *inbuf,
+ struct roce5_bw_ctrl_outbuf *outbuf)
+{
+ inbuf->ctrl_param.cir = 0;
+ inbuf->ctrl_param.pir = 0;
+ inbuf->ctrl_param.cnp = 0;
+ return roce5_set_bw_ctrl_state(rdev, ROCE_BW_CTRL_DIS, inbuf);
+}
+
+static int roce5_dfx_change_bw_ctrl_param(struct roce5_device *rdev,
+ struct roce5_bw_ctrl_inbuf *inbuf,
+ struct roce5_bw_ctrl_outbuf *outbuf)
+{
+ return roce5_set_bw_ctrl_state(rdev, ROCE_BW_CTRL_RESET, inbuf);
+}
+
+static int roce5_dfx_query_bw_ctrl_param(struct roce5_device *rdev,
+ struct roce5_bw_ctrl_inbuf *inbuf,
+ struct roce5_bw_ctrl_outbuf *outbuf)
+{
+ return roce5_query_bw_ctrl_state(rdev, &outbuf->bw_ctrl_param);
+}
+
+static const roce5_adm_dfx_bw_ctrl_cmd_proc_t
+ g_roce5_adm_dfx_bw_ctrl_cmd_proc[] = {
+ { ROCE_CMD_ENABLE_BW_CTRL, roce5_dfx_enable_bw_ctrl },
+ { ROCE_CMD_DISABLE_BW_CTRL, roce5_dfx_disable_bw_ctrl },
+ { ROCE_CMD_CHANGE_BW_CTRL_PARAM,
+ roce5_dfx_change_bw_ctrl_param },
+ { ROCE_CMD_QUERY_BW_CTRL_PARAM, roce5_dfx_query_bw_ctrl_param },
+ };
+
+int roce5_adm_dfx_bw_ctrl(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ int ret;
+ struct roce5_bw_ctrl_inbuf *inbuf =
+ (struct roce5_bw_ctrl_inbuf *)buf_in;
+ struct roce5_bw_ctrl_outbuf *outbuf =
+ (struct roce5_bw_ctrl_outbuf *)buf_out;
+ const roce5_adm_generic_cmd_proc_t *generic_array =
+ (const roce5_adm_generic_cmd_proc_t *)
+ g_roce5_adm_dfx_bw_ctrl_cmd_proc;
+ int elem_count = sizeof(g_roce5_adm_dfx_bw_ctrl_cmd_proc) /
+ sizeof(g_roce5_adm_dfx_bw_ctrl_cmd_proc[0]);
+ roce5_adm_dfx_bw_ctrl_func_t roce5_adm_dfx_bw_ctrl_func = NULL;
+
+ if (in_size < sizeof(struct roce5_bw_ctrl_inbuf)) {
+ ROCE_ERR(
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size, (int)sizeof(struct roce5_bw_ctrl_inbuf));
+ return -ENOMEM;
+ }
+ if (*out_size < sizeof(struct roce5_bw_ctrl_outbuf)) {
+ ROCE_ERR(
+ "Input parameter(out_zise: %dB) is shorter than allocated buffer(allocated: %dB)",
+ (int)*out_size,
+ (int)sizeof(struct roce5_bw_ctrl_outbuf));
+ return -ENOMEM;
+ }
+ ret = memset_s(buf_out, sizeof(struct roce5_bw_ctrl_outbuf), 0,
+ sizeof(struct roce5_bw_ctrl_outbuf));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset buf_out.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ *out_size = sizeof(struct roce5_bw_ctrl_outbuf);
+
+ if (inbuf->cmd_type >= VM_COMPAT_TEST) {
+ ROCE_DEV_ERR(rdev, "Not support this type(%d)",
+ inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ roce5_adm_dfx_bw_ctrl_func =
+ (roce5_adm_dfx_bw_ctrl_func_t)roce5_adm_generic_find_cmd_func(
+ generic_array, elem_count, inbuf->cmd_type);
+ if (roce5_adm_dfx_bw_ctrl_func == NULL) {
+ ROCE_DEV_ERR(rdev, "Not support this type(%d)",
+ inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ return roce5_adm_dfx_bw_ctrl_func(rdev, inbuf, outbuf);
+}
+
+int roce5_adm_dfx_set_ldcp_param(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ int ret;
+ roce_ldcp_param_s ldcp_param;
+ const struct roce5_ldcp_param *inbuf =
+ (struct roce5_ldcp_param *)buf_in;
+
+ if (in_size < sizeof(struct roce5_ldcp_param)) {
+ ROCE_ERR(
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size, (int)sizeof(struct roce5_ldcp_param));
+ return -ENOMEM;
+ }
+ if (inbuf->cmd_type != ROCE_CMD_SET_LDCP_PARAM) {
+ ROCE_DEV_ERR(rdev, "Not support this type(%d)",
+ inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ ldcp_param.dw0.bs.alpha = inbuf->ldcp_param.alpha & 0xf;
+ ldcp_param.dw0.bs.beta = inbuf->ldcp_param.beta & 0xf;
+ ldcp_param.dw0.bs.gamma = inbuf->ldcp_param.gamma & 0xf;
+ ldcp_param.dw0.bs.eta = inbuf->ldcp_param.eta & 0xf;
+ ldcp_param.dw0.bs.set_flag = inbuf->ldcp_param.set_flag & 0x1;
+
+ ret = roce5_set_sysfs_cfg_param(rdev->hwdev, rdev->glb_func_id,
+ (u32 *)(void *)&ldcp_param,
+ sizeof(roce_ldcp_param_s),
+ (u16)ROCE_MPU_CMD_CC_CFG_LDCP_PARAM);
+ if (ret != 0) {
+ ROCE_ERR("Failed to set ldcp param.(ret:%d)", ret);
+ } else {
+ ROCE_WARN("Set ldcp param 0x%x", ldcp_param.dw0.value);
+ }
+ return ret;
+}
+
+int roce5_adm_dfx_port_traffic(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ roce_mpu_port_statics_cmd_inbuf_t inbuf;
+ roce_port_sta_outbuf_t *outbuf = (roce_port_sta_outbuf_t *)buf_out;
+ int ret;
+
+ memset_s(&inbuf, sizeof(inbuf), 0, sizeof(inbuf));
+ inbuf.cmd = *(roce_port_sta_inbuf_t *)buf_in;
+ outbuf->head.status = 0xFF;
+
+ if (in_size < sizeof(roce_port_sta_inbuf_t)) {
+ ROCE_ERR(
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size, (int)sizeof(roce_port_sta_inbuf_t));
+ return -ENOMEM;
+ }
+ if (inbuf.cmd.cmd_type != ROCE_CMD_PORT_TRAFFIC) {
+ ROCE_DEV_ERR(rdev, "Not support this type(%d).",
+ inbuf.cmd.cmd_type);
+ return -EINVAL;
+ }
+
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_DFX_PORT_TRAFFIC,
+ (void *)&inbuf, (u16)sizeof(inbuf),
+ buf_out, (u16 *)(void *)out_size);
+ if ((ret != 0) || (*out_size == 0) || (outbuf->head.status != 0)) {
+ ROCE_ERR(
+ "Failed to query port traffic, err(%d), out size(0x%x) status(0x%x)",
+ ret, *out_size, outbuf->head.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#ifdef ROCE_CHIP_TEST
+static const roce5_adm_dfx_vnic_waterline_cmd_proc_t
+ g_roce5_adm_dfx_vnic_wl_cmd_proc[] = {
+ { ROCE_CMD_SET_VNIC_WATERLINE, roce5_set_vnic_waterline_state },
+ { ROCE_CMD_GET_VNIC_WATERLINE, roce5_get_vnic_waterline_state },
+ };
+
+int roce5_adm_dfx_vnic_wl_ctrl(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ int ret;
+ struct roce5_vnic_waterline_ctrl_buf *inbuf =
+ (struct roce5_vnic_waterline_ctrl_buf *)buf_in;
+ struct roce5_vnic_waterline_ctrl_buf *outbuf =
+ (struct roce5_vnic_waterline_ctrl_buf *)buf_out;
+ const roce5_adm_generic_cmd_proc_t *generic_array =
+ (const roce5_adm_generic_cmd_proc_t *)
+ g_roce5_adm_dfx_vnic_wl_cmd_proc;
+ int elem_count = sizeof(g_roce5_adm_dfx_vnic_wl_cmd_proc) /
+ sizeof(g_roce5_adm_dfx_vnic_wl_cmd_proc[0]);
+ roce5_adm_dfx_vnic_waterline_ctrl_func_t roce5_adm_dfx_vnic_wl_ctrl_func;
+
+ if (in_size < sizeof(struct roce5_vnic_waterline_ctrl_buf)) {
+ ROCE_ERR(
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size,
+ (int)sizeof(struct roce5_vnic_waterline_ctrl_buf));
+ return -EINVAL;
+ }
+
+ if (inbuf->cmd_type >= VM_COMPAT_TEST) {
+ ROCE_DEV_ERR(rdev, "Not support this type(%d)",
+ inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ ret = memset_s(buf_out, sizeof(struct roce5_vnic_waterline_ctrl_buf), 0,
+ sizeof(struct roce5_vnic_waterline_ctrl_buf));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset buf_out.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ roce5_adm_dfx_vnic_wl_ctrl_func =
+ (roce5_adm_dfx_vnic_waterline_ctrl_func_t)
+ roce5_adm_generic_find_cmd_func(
+ generic_array, elem_count, inbuf->cmd_type);
+ if (roce5_adm_dfx_vnic_wl_ctrl_func == NULL) {
+ ROCE_DEV_ERR(rdev, "Not support this type(%d)",
+ inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ return roce5_adm_dfx_vnic_wl_ctrl_func(rdev, inbuf, outbuf);
+}
+
+#endif /* ROCE_CHIP_TEST */
+
+int roce5_adm_dfx_roce_set(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+
+{
+ roce_dfx_set_cmd_s inbuf;
+ roce_dfx_set_outbuf_s *outbuf = (roce_dfx_set_outbuf_s *)buf_out;
+ int ret;
+
+ if (in_size < sizeof(roce_dfx_set_inbuf_s)) {
+ ROCE_ERR(
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size, (int)sizeof(roce_dfx_set_inbuf_s));
+ return -ENOMEM;
+ }
+
+ memset_s(&inbuf, sizeof(inbuf), 0, sizeof(inbuf));
+ inbuf.cmd = *(roce_dfx_set_inbuf_s *)buf_in;
+ inbuf.cmd.func_id = rdev->glb_func_id;
+
+ if (inbuf.cmd.cmd_type != ROCE_CMD_ROCE_SET) {
+ ROCE_DEV_ERR(rdev, "Not support this type(%d).",
+ inbuf.cmd.cmd_type);
+ return -EINVAL;
+ }
+
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev, ROCE_MPU_CMD_DFX_ROCE_SET,
+ (void *)&inbuf, (u16)sizeof(inbuf), outbuf,
+ (u16 *)(void *)out_size);
+ if ((ret != 0) || (*out_size == 0) || (outbuf->head.status != 0)) {
+ ROCE_ERR(
+ "Failed to set roce configs, err(%d), out size(0x%x) status(0x%x)",
+ ret, *out_size, outbuf->head.status);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int roce5_adm_dfx_roce_set_debug(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+
+{
+ roce_dfx_set_debug_cmd_s inbuf;
+ roce_dfx_set_debug_outbuf_s *outbuf =
+ (roce_dfx_set_debug_outbuf_s *)buf_out;
+ int ret;
+
+ if (in_size < sizeof(roce_dfx_set_debug_inbuf_s)) {
+ ROCE_ERR(
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size, (int)sizeof(roce_dfx_set_debug_inbuf_s));
+ return -ENOMEM;
+ }
+
+ memset_s(&inbuf, sizeof(inbuf), 0, sizeof(inbuf));
+ inbuf.cmd = *(roce_dfx_set_debug_inbuf_s *)buf_in;
+ inbuf.cmd.func_id = rdev->glb_func_id;
+
+ if (inbuf.cmd.cmd_type != ROCE_CMD_ROCE_SET_DEBUG) {
+ ROCE_DEV_ERR(rdev, "Not support this type(%d).",
+ inbuf.cmd.cmd_type);
+ return -EINVAL;
+ }
+
+ ret = roce5_msg_to_mgmt_sync(rdev->hwdev,
+ ROCE_MPU_CMD_DFX_ROCE_SET_DEBUG,
+ (void *)&inbuf, (u16)sizeof(inbuf), outbuf,
+ (u16 *)(void *)out_size);
+ if ((ret != 0) || (*out_size == 0) || (outbuf->head.status != 0)) {
+ ROCE_ERR(
+ "Failed to set roce configs, err(%d), out size(0x%x) status(0x%x)",
+ ret, *out_size, outbuf->head.status);
+ return -EINVAL;
+ }
+ return 0;
+}
+#endif /* __ROCE_DFX__ */
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx.h b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx.h
new file mode 100644
index 000000000..139867581
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx.h
@@ -0,0 +1,378 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved.
+
+
+#ifndef ROCE_DFX_H
+#define ROCE_DFX_H
+
+#include <linux/types.h>
+
+#include "hinic5_rdma.h"
+
+#include "roce_sysfs.h"
+#include "roce.h"
+#include "roce_gid.h"
+#include "roce_compat.h"
+#include "roce_pub_cmd.h"
+#include "roce_npu_cmd_dfx_defs.h"
+#include "roce_debug.h"
+
+#include "securec.h"
+
+#define MR_KEY_2_INDEX_SHIFT 8
+
+#define ROCE_IO_DFX_CFG_VADDR_ID 0
+#define ROCE_IO_DFX_CFG_PADDR_ID 1
+#define ROCE_IO_DFX_CFG_ADDR_NUM 2
+
+#define roce5_dfx_print(fmt, args...) \
+ do { \
+ (void)printk("[roce5_dfx] : " fmt "\n", ##args); \
+ } while (0)
+
+typedef struct tag_roce_cmd_mpt_query {
+ roce_verbs_cmd_com_s com;
+} roce_cmd_mpt_query_s;
+
+typedef struct roce5_mpt_query_outbuf {
+ u32 value[16];
+} roce5_mpt_query_outbuf_s;
+
+typedef struct tag_roce_cmd_roce_cq_query {
+ roce_verbs_cmd_com_s com;
+} roce_cmd_cq_query_s;
+
+typedef struct roce5_cq_query_outbuf {
+ u32 value[32];
+} roce5_cq_query_outbuf_s;
+
+typedef struct tag_roce_cmd_qp_query {
+ roce_verbs_cmd_com_s com;
+} roce_cmd_qp_query_s;
+
+typedef struct roce5_qp_query_outbuf {
+ u32 context[128];
+} roce5_qp_query_outbuf_s;
+
+typedef struct roce5_srq_query_outbuf {
+ u32 value[24];
+} roce5_srq_query_outbuf_s;
+
+struct roce5_dfx_query_inbuf {
+ u32 cmd_type;
+ union {
+ u32 qpn;
+ u32 cqn;
+ u32 srqn;
+ u32 mpt_key;
+ u32 gid_index;
+ struct {
+ u32 qpn;
+ u32 cqn;
+ } query_pi_ci;
+ };
+};
+
+#define ROCE_DEV_NAME_LEN_MAX 64
+
+struct roce5_dfx_dbg_inbuf {
+ u32 cmd_type;
+ union {
+ u32 qpn;
+ u32 srqn;
+ };
+ char dev_name[ROCE_DEV_NAME_LEN_MAX];
+};
+
+#define ROCE_CTX_MAX_SIZE 512 // adaptation lock store referencein of structure
+
+union roce5_dfx_dbg_outbuf {
+ roce_verbs_qp_attr_s qp_attr;
+ roce_verbs_srq_attr_dfx_s srq_attr;
+ u32 buf[ROCE_CTX_MAX_SIZE];
+ u32 algo_type;
+ u32 dev_type;
+};
+
+struct roce5_dfx_common_inbuf {
+ u32 cmd_type;
+ char dev_name[ROCE_DEV_NAME_LEN_MAX];
+};
+
+union roce5_dfx_common_outbuf {
+ u32 dev_type;
+};
+
+struct roce5_dfx_pi_ci {
+ u32 qpc_sq_pi_on_chip;
+ u32 qpc_sq_pi;
+ u32 qpc_sq_load_pi;
+ u32 qpc_rq_pi_on_chip;
+ u32 qpc_rq_load_pi;
+ u32 qpc_rq_pi;
+ u32 qpc_rc_pi;
+ u32 qpc_sq_ci;
+ u32 qpc_sq_wqe_prefetch_ci;
+ u32 qpc_sq_mtt_prefetch_wqe_ci;
+ u32 qpc_sqa_ci;
+ u32 qpc_sqa_wqe_prefetch_ci;
+ u32 qpc_rq_ci;
+ u32 qpc_rq_wqe_prefetch_ci;
+ u32 qpc_rq_mtt_prefetch_wqe_ci;
+ u32 qpc_rq_base_ci;
+ u32 qpc_rc_ci;
+ u32 qpc_rc_prefetch_ci;
+ u32 cq_ci_on_chip;
+ u32 cq_ci;
+ u32 cq_load_ci;
+ u64 cq_ci_record_gpa_at_hop_num;
+ u32 cq_last_solicited_pi;
+ u32 cq_pi;
+ u32 cq_last_notified_pi;
+};
+
+struct roce5_dfx_qp_count {
+ u32 qp_alloced;
+ u32 qp_deleted;
+ u32 qp_alive;
+};
+
+#define ROCE_GID_ENTRY_NUM 17 // 1 host fe + 16 shadow fe
+union roce5_dfx_query_outbuf {
+ /* query cache context */
+ roce_verbs_qp_attr_s qp_attr;
+ roce_verbs_cq_attr_s cq_attr;
+ roce_verbs_srq_attr_s srq_attr;
+ roce_verbs_mr_attr_s mr_attr;
+ /* query host context */
+ roce5_qp_query_outbuf_s qp_query;
+ roce5_cq_query_outbuf_s cq_query;
+ roce5_srq_query_outbuf_s srq_query;
+ struct roce_mpt_context mpt;
+ struct rdma_gid_entry gid_entry[ROCE_GID_ENTRY_NUM];
+ struct roce5_dfx_pi_ci pi_ci;
+ struct roce5_dfx_qp_count qp_count;
+ u32 algo_type;
+ struct roce_uni_cmd_latch_data latch_data_outbuf;
+};
+
+enum roce5_bw_ctrl_cmd_e {
+ ROCE_BW_CTRL_DIS,
+ ROCE_BW_CTRL_EN,
+ ROCE_BW_CTRL_RESET
+};
+
+enum roce5_qos_wl_ctrl_cmd_e {
+ ROCE_QOS_WL_CTRL_CMD_SET,
+ ROCE_QOS_WL_CTRL_CMD_GET
+};
+
+struct rdma_gid_query_outbuf {
+ struct rdma_gid_entry gid_entry[ROCE_GID_ENTRY_NUM];
+};
+
+struct roce5_bw_ctrl_inbuf {
+ u32 cmd_type;
+ struct {
+ u32 cir;
+ u32 pir;
+ u32 cnp;
+ } ctrl_param;
+};
+
+struct roce5_bw_set_inbuf {
+ u32 cmd_type;
+ struct {
+ u32 mod;
+ u32 cir;
+ u32 cbs;
+ u32 pir;
+ u32 pbs;
+ } set_param;
+};
+
+struct roce5_bw_ctrl_param {
+ u8 color_type;
+ u16 ptype;
+ u8 hw_wred_mode;
+
+ u32 cir;
+ u32 pir;
+ u32 cbs;
+ u32 xbs;
+ u32 cnp;
+ u32 enable;
+};
+
+struct roce5_bw_set_param {
+ u16 ptype;
+ u8 color_type;
+ u8 hw_wred_mode;
+
+ u32 cir;
+ u32 cbs;
+ u32 pir;
+ u32 pbs;
+ u32 enable;
+};
+
+struct roce5_ldcp_param {
+ u32 cmd_type;
+ struct {
+ u8 alpha;
+ u8 beta;
+ u8 gamma;
+ u8 eta;
+ u8 set_flag;
+ } ldcp_param;
+};
+
+struct roce5_bw_ctrl_outbuf {
+ struct roce5_bw_ctrl_param bw_ctrl_param;
+};
+
+struct roce5_bw_set_outbuf {
+ struct roce5_bw_set_param bw_set_param;
+};
+
+enum roce5_dfx_io_cmd_type { ROCE_IO_CTRL_DIS, ROCE_IO_CTRL_EN };
+
+struct roce5_dfx_io_alarm {
+ enum roce5_dfx_io_cmd_type en_flag;
+ u16 pf_id;
+ u16 rsvd;
+ u16 io_latency_thd;
+ u16 exec_time;
+ u32 exp_qpn;
+ void *rcd_uaddr;
+ struct timespec64 start;
+ struct mutex io_alarm_mutex;
+};
+
+struct roce5_dfx_io_inbuf {
+ u32 cmd_type;
+ struct roce5_dfx_io_alarm io_alarm;
+};
+
+struct roce5_dfx_io_outbuf {
+ struct roce5_dfx_io_alarm io_alarm;
+};
+
+typedef struct roce5_adm_generic_cmd_proc {
+ u32 cmd_type;
+ void *proc_func;
+} roce5_adm_generic_cmd_proc_t;
+
+typedef int (*roce5_adm_func_t)(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+
+typedef struct roce5_adm_cmd_proc {
+ u32 cmd_type;
+ roce5_adm_func_t proc_func;
+} roce5_adm_cmd_proc_t;
+
+typedef int (*roce5_adm_dfx_dbg_t)(struct roce5_device *rdev,
+ const struct roce5_dfx_dbg_inbuf *inbuf,
+ union roce5_dfx_dbg_outbuf *outbuf);
+
+typedef struct roce5_adm_dfx_dbg_cmd_proc {
+ u32 cmd_type;
+ roce5_adm_dfx_dbg_t proc_func;
+} roce5_adm_dfx_dbg_cmd_proc_t;
+
+typedef int (*roce5_adm_dfx_query_t)(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf);
+
+typedef struct roce5_adm_dfx_query_cmd_proc {
+ u32 cmd_type;
+ roce5_adm_dfx_query_t proc_func;
+} roce5_adm_dfx_query_cmd_proc_t;
+
+typedef int (*roce5_adm_dfx_bw_ctrl_func_t)(struct roce5_device *rdev,
+ struct roce5_bw_ctrl_inbuf *inbuf,
+ struct roce5_bw_ctrl_outbuf *outbuf);
+
+typedef struct roce5_adm_dfx_bw_ctrl_cmd_proc {
+ u32 cmd_type;
+ roce5_adm_dfx_bw_ctrl_func_t proc_func;
+} roce5_adm_dfx_bw_ctrl_cmd_proc_t;
+
+#ifdef ROCE_CHIP_TEST
+typedef struct roce5_vnic_waterline_ctrl_param {
+ u16 red_waterline;
+ u16 yellow_waterline;
+ u32 ip_val;
+} roce5_vnic_waterline_ctrl_param_s;
+
+struct roce5_vnic_waterline_ctrl_buf {
+ u32 cmd_type;
+ roce5_vnic_waterline_ctrl_param_s waterline_param;
+};
+
+typedef int (*roce5_adm_dfx_vnic_waterline_ctrl_func_t)(
+ struct roce5_device *rdev, struct roce5_vnic_waterline_ctrl_buf *inbuf,
+ struct roce5_vnic_waterline_ctrl_buf *outbuf);
+
+typedef struct roce5_adm_dfx_vnic_waterline_cmd_proc {
+ u32 cmd;
+ roce5_adm_dfx_vnic_waterline_ctrl_func_t proc_func;
+} roce5_adm_dfx_vnic_waterline_cmd_proc_t;
+
+int roce5_adm_dfx_vnic_wl_ctrl(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+#endif /* ROCE_CHIP_TEST */
+
+/* and above next is V100 compatible data structure */
+typedef struct tag_roce_qurey_gid {
+ roce_verbs_cmd_com_s com;
+ __be32 port;
+} roce_cmd_query_gid_s;
+
+typedef int (*roce_adm_dfx_attack_func_t)(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct roce_attack_outbuf *outbuf);
+struct roce_dfx_attack_cmd_func {
+ u32 cmd_id;
+ roce_adm_dfx_attack_func_t cmd_func;
+};
+
+DEBUG_REPLACE int roce5_get_drv_version(void *buf_out, u32 *out_size);
+void *
+roce5_adm_generic_find_cmd_func(const roce5_adm_generic_cmd_proc_t *cmd_array,
+ int elem_count, u32 target_cmd);
+int roce5_adm_dfx_query(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+int roce5_adm_dfx_bw_ctrl(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+int roce5_adm_dfx_set_ldcp_param(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+int roce5_adm_dfx_port_traffic(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+int roce5_adm_dfx_dbg(struct roce5_device *rdev, const void *buf_in,
+ void *buf_out, u32 *out_size);
+int roce5_adm_dfx_roce_set(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+int roce5_adm_dfx_roce_set_debug(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+
+int roce5_dfx_attack_func(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+
+void roce5_dfx_clean_up(struct roce5_device *rdev);
+
+void *global_roce5_io_alarm_va_get(void);
+
+void global_roce5_io_alarm_va_set(u64 va);
+
+void global_roce5_io_alarm_pa_set(dma_addr_t pa);
+
+dma_addr_t global_roce5_io_alarm_pa_get(void);
+
+int roce5_dfx_query_cq(struct roce5_device *rdev, u32 cqn, u32 *context,
+ int cqc_size);
+
+int roce5_dfx_cmd_query_srq(struct roce5_device *rdev, u32 srqn,
+ roce_verbs_srq_attr_s *srq_attr);
+
+#endif // __ROCE_DFX_H__
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_attack.c b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_attack.c
new file mode 100644
index 000000000..84cc1455b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_attack.c
@@ -0,0 +1,828 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
+
+
+#include <linux/semaphore.h>
+
+#include "hinic5_hw.h"
+#include "hinic5_hwdev.h"
+#include "hisdk5_hwif.h"
+#include "hinic5_mt.h"
+#include "rdma_comp.h"
+#include "roce.h"
+#include "roce_qp.h"
+#include "roce_infra.h"
+#include "roce_mr.h"
+#include "roce_dfx.h"
+#include "roce_kernel_compat_gen.h"
+
+#define DB_BUFF_SIZE 2048
+#define DWQE_SIZE 256
+#define DWQE_TYPE_NUM 4
+#define ALIGN_UP_8B(length) (((length) + 7) >> 3)
+#define ALIGN_DOWN_8B(offset) ((offset)&0xfffffff8)
+#define IS_OFFSET_8B_ALIGN(offset) (((offset)&7) != 0)
+#define UPPER_HALF_BIT_OFFSET 32
+#define U32S_PER_U64 2
+
+static void roce5_copy_mask_attack_value_to_addr(u32 *addr, u32 attack_value,
+ u32 mask)
+{
+ u32 val;
+
+ val = *addr;
+ val &= ~mask;
+ val |= (attack_value & mask);
+ *addr = val;
+}
+
+static void roce5_copy_mask_attack_value_to_u64_addr(u64 *addr,
+ u32 attack_value, u32 mask,
+ bool is_upper_half)
+{
+ u64 val;
+
+ val = *addr;
+
+ if (is_upper_half) {
+ val &= ~((u64)mask << UPPER_HALF_BIT_OFFSET);
+ val |= ((u64)(attack_value & mask) << UPPER_HALF_BIT_OFFSET);
+ } else {
+ val &= ~mask;
+ val |= (attack_value & mask);
+ }
+
+ *addr = val;
+}
+
+static int roce5_copy_data_to_page(struct roce5_device *rdev, const u32 *val,
+ struct ib_umem *umem, u32 copy_len,
+ u32 offset, u32 attack_len, u32 mask)
+{
+ struct scatterlist *sg = NULL;
+ u32 *inbuf_tmp = NULL;
+ u32 sg_len;
+ u32 page_copy_len = 0;
+ u32 copied_len = 0;
+ u32 sgl_offset = 0;
+ u64 buf_offset = 0;
+ void *va = NULL;
+ u32 i = 0;
+ int ret;
+
+ inbuf_tmp = (u32 *)kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (inbuf_tmp == NULL) {
+ ROCE_ERR("Failed to alloc inbuf temp.");
+ return -ENOMEM;
+ }
+
+ if (mask == 0) {
+ for (i = 0; i < PAGE_SIZE / sizeof(u32); i++) {
+ inbuf_tmp[i] = val[i % attack_len];
+ }
+ }
+
+ ROCE_INFO(
+ "copy_data_to_page va:%lx, length:%lu, offset:%u, copy_len:%u",
+ umem->address, umem->length, offset, copy_len);
+
+#if defined(IB_UMEM_HAVE_SG_APPEND_TABLE)
+ for_each_sg(umem->sgt_append.sgt.sgl, sg, umem->sgt_append.sgt.nents, i)
+#else
+ //scatterlist of traverse use nents, orig_nents >= nents >= nmap
+ for_each_sg(umem->sg_head.sgl, sg, umem->sg_head.nents, i)
+#endif
+ {
+ sg_len = sg->length;
+ if (buf_offset + sg_len <=
+ offset) { //not found offset of scatterlist, accumulate sg_len, continue
往 next find
+ buf_offset += sg_len;
+ } else { //found offset of scatterlist
+ sgl_offset =
+ offset -
+ (u32)buf_offset; //get based on current scatterlist of offset
+ buf_offset =
+ offset; //found current page after, later of page of offset all max at offset
+
+ va = sg_virt(sg);
+ if (va == NULL) {
+ ROCE_ERR("Failed to get va");
+ kfree(inbuf_tmp);
+ return -ENOMEM;
+ }
+
+ va += sgl_offset;
+ page_copy_len = ((copy_len - copied_len) <
+ (sg_len - sgl_offset)) ?
+ (copy_len - copied_len) :
+ (sg_len - sgl_offset);
+
+ if (mask != 0) {
+ roce5_copy_mask_attack_value_to_addr(
+ (u32 *)va, val[0], mask);
+ ROCE_INFO(
+ "copy mask data to buf, buf_offset:%llu, sgl_offset:%u, mask_val:%u\n",
+ buf_offset, sgl_offset,
+ (val[0] & mask));
+ break;
+ }
+
+ ret = memcpy_s(va, page_copy_len, inbuf_tmp,
+ page_copy_len);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to memcpy attack value, ret(%d)",
+ ret);
+ kfree(inbuf_tmp);
+ return -EFAULT;
+ }
+
+ ROCE_INFO(
+ "copy_data_from_page buf_offset:%llu, sgl_offset:%u, copied_len:%u, page_copy_len:%u, i:%u\n",
+ buf_offset, sgl_offset, copied_len,
+ page_copy_len, i);
+
+ copied_len += page_copy_len;
+ if (copied_len >= copy_len) {
+ break;
+ }
+ }
+ }
+
+ kfree(inbuf_tmp);
+ return 0;
+}
+
+static void roce5_copy_attack_value_to_addr(u64 *addr, u64 attack_value,
+ u32 length)
+{
+ int i;
+ int count = ALIGN_UP_8B(length);
+
+ for (i = 0; i < count; i++) {
+ wmb();
+ *((u64 *)addr + i) = attack_value;
+ wmb();
+ }
+}
+
+static int roce5_dfx_attack_sqdb_hard(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct roce_attack_outbuf *outbuf)
+{
+ struct roce5_ucontext *ucontext = NULL;
+ u64 db_phy_start;
+ void __iomem *db_virt_start = NULL;
+ void __iomem *db_virt_offset = NULL;
+ void *hwdev = NULL;
+ struct roce5_qp *rqp = NULL;
+ u32 qpn = inbuf->qpn;
+ union roce_sq_db sq_db;
+ u32 db_offset;
+ u32 db_8B_offset;
+ bool is_upper_half;
+ u32 length;
+
+ hwdev = rdev->hwdev;
+ if (hwdev == NULL) {
+ ROCE_ERR("Roce hwdev is NULL");
+ return -ENOMEM;
+ }
+
+ ucontext = rdev->ucontext;
+ if (ucontext == NULL) {
+ ROCE_ERR("Roce device context is null");
+ return -ENOMEM;
+ }
+
+ db_offset = inbuf->offset;
+ if (db_offset >= DB_BUFF_SIZE) {
+ ROCE_ERR(
+ "roce attack sqdb_hard offset is too large, should be less than %u",
+ DB_BUFF_SIZE);
+ return -EINVAL;
+ }
+
+ db_8B_offset = ALIGN_DOWN_8B(db_offset);
+ db_phy_start = ucontext->db_dma_addr;
+ db_virt_start = (db_phy_start -
+ (((struct hinic5_hwdev *)hwdev)->hwif)->db_base_phy) +
+ (((struct hinic5_hwdev *)hwdev)->hwif)->db_base;
+ db_virt_offset = db_virt_start + db_8B_offset;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ ROCE_ERR("Failed to get roce qp, qpn:0x%x", qpn);
+ return -EINVAL;
+ }
+
+ if (inbuf->mask != 0) {
+ is_upper_half = IS_OFFSET_8B_ALIGN(db_offset);
+ roce5_copy_mask_attack_value_to_u64_addr((u64 *)db_virt_offset,
+ inbuf->attack_value[0],
+ inbuf->mask,
+ is_upper_half);
+ ROCE_INFO("roce attack sqdb, mask_val:0x%x, offset:%u",
+ (inbuf->attack_value[0] & inbuf->mask), db_offset);
+ } else {
+ sq_db.sq_db_val = 0;
+ sq_db.sq_db_seg.dw0.value =
+ roce5_convert_be32(inbuf->attack_value[0]);
+ sq_db.sq_db_seg.dw1.value =
+ roce5_convert_be32(inbuf->attack_value[1]);
+
+ length = (db_offset + inbuf->length > DB_BUFF_SIZE) ?
+ (DB_BUFF_SIZE - db_offset) :
+ inbuf->length;
+ roce5_copy_attack_value_to_addr((u64 *)db_virt_offset,
+ sq_db.sq_db_val, length);
+
+ ROCE_INFO("roce attack sqdb length:%u, offset:%u", length,
+ db_offset);
+ ROCE_INFO("roce attack sqdb type:%u, cos:%u, qpn:%u\n",
+ sq_db.sq_db_seg.dw0.bs.type,
+ sq_db.sq_db_seg.dw0.bs.cos,
+ sq_db.sq_db_seg.dw0.bs.qpn);
+ ROCE_INFO("roce attack sqdb mtu_shift:%u, pi:%u\n",
+ sq_db.sq_db_seg.dw1.bs.mtu_shift,
+ sq_db.sq_db_seg.dw1.bs.pi);
+ }
+
+ roce5_rqp_put(rqp);
+ return 0;
+}
+
+static int roce5_copy_attack_value_to_dwqe_addr(u64 *addr, const u32 *val,
+ u32 length, u32 attack_len)
+{
+ int i;
+ int count = ALIGN_UP_8B(length);
+ u64 *inbuf_tmp = NULL;
+ u32 step = 2;
+
+ inbuf_tmp = (u64 *)kzalloc(DWQE_SIZE, GFP_KERNEL);
+ if (inbuf_tmp == NULL) {
+ ROCE_ERR("Failed to alloc inbuf temp.");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < count * U32S_PER_U64; i += step) {
+ inbuf_tmp[i / step] = ((u64)val[(i + 1) % attack_len]
+ << UPPER_HALF_BIT_OFFSET) |
+ val[i % attack_len];
+ }
+
+ for (i = 0; i < count; i++) {
+ wmb();
+ *((u64 *)addr + i) = inbuf_tmp[i];
+ wmb();
+ }
+
+ kfree(inbuf_tmp);
+ return 0;
+}
+
+static int roce5_dfx_attack_dwqe(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct roce_attack_outbuf *outbuf)
+{
+ struct roce5_ucontext *ucontext = NULL;
+ u64 dwqe_phy_start;
+ void __iomem *dwqe_virt_start = NULL;
+ void __iomem *dwqe_virt_offset = NULL;
+ void *hwdev = NULL;
+ struct roce5_qp *rqp = NULL;
+ u32 qpn = inbuf->qpn;
+ u32 dwqe_offset;
+ u32 length;
+ u32 dwqe_8B_offset;
+ bool is_upper_half;
+ int i;
+ int ret;
+
+ hwdev = rdev->hwdev;
+ if (hwdev == NULL) {
+ ROCE_ERR("Roce hwdev is NULL");
+ return -ENOMEM;
+ }
+
+ ucontext = rdev->ucontext;
+ if (ucontext == NULL) {
+ ROCE_ERR("Roce device context is null");
+ return -ENOMEM;
+ }
+
+ dwqe_offset = inbuf->offset;
+ if (dwqe_offset >= DWQE_SIZE) {
+ ROCE_ERR(
+ "roce attack dwqe offset is too large, should be less than %u",
+ DWQE_SIZE);
+ return -EINVAL;
+ }
+
+ dwqe_phy_start = ucontext->dwqe_dma_addr;
+ //dwqe physical base address and virtual base address all is based on db perform offset of offset, so corresponding when at db of va basebase on to before offset offset
+ dwqe_virt_start =
+ (dwqe_phy_start -
+ (((struct hinic5_hwdev *)hwdev)->hwif)->db_base_phy) +
+ (((struct hinic5_hwdev *)hwdev)->hwif)->db_base;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ ROCE_ERR("Failed to get roce qp, qpn:0x%x", qpn);
+ return -EINVAL;
+ }
+
+ length = (dwqe_offset + inbuf->length > DWQE_SIZE) ?
+ (DWQE_SIZE - dwqe_offset) :
+ (inbuf->length);
+ dwqe_8B_offset = ALIGN_DOWN_8B(dwqe_offset);
+ for (i = 0; i < DWQE_TYPE_NUM; i++) {
+ dwqe_virt_offset =
+ dwqe_virt_start + i * DWQE_SIZE + dwqe_8B_offset;
+ if (inbuf->mask != 0) {
+ is_upper_half = IS_OFFSET_8B_ALIGN(dwqe_offset);
+ roce5_copy_mask_attack_value_to_u64_addr(
+ (u64 *)dwqe_virt_offset, inbuf->attack_value[0],
+ inbuf->mask, is_upper_half);
+ } else {
+ ret = roce5_copy_attack_value_to_dwqe_addr(
+ (u64 *)dwqe_virt_offset, inbuf->attack_value,
+ length, inbuf->attack_len);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to copy attack value to dwqe, ret(%d)",
+ ret);
+ return -EFAULT;
+ }
+ }
+ }
+
+ if (inbuf->mask != 0) {
+ ROCE_INFO("roce attack dwqe, mask_val:0x%x, offset:%u",
+ (inbuf->attack_value[0] & inbuf->mask), dwqe_offset);
+ } else {
+ ROCE_INFO("roce attack dwqe, length:%u, offset:%u", length,
+ dwqe_offset);
+ }
+
+ roce5_rqp_put(rqp);
+ return 0;
+}
+
+static int roce5_dfx_attack_sqwqe(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct roce_attack_outbuf *outbuf)
+{
+ struct roce5_qp *rqp = NULL;
+ int ret = 0;
+ u32 qpn = inbuf->qpn;
+ u32 sq_buf_sz;
+ u32 length;
+ u32 sq_wqe_offset;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ ROCE_ERR("Failed to get roce qp, qpn:0x%x", qpn);
+ return -EINVAL;
+ }
+
+ sq_buf_sz = (u32)ROCE_ALIGN((u64)rqp->sq.wqebb_cnt
+ << (unsigned)rqp->sq.wqe_shift,
+ PAGE_SIZE);
+ sq_wqe_offset = inbuf->offset;
+ if (sq_wqe_offset >= sq_buf_sz) {
+ ROCE_ERR(
+ "roce attack sq wqe offset is too large, should be less than %u",
+ sq_buf_sz);
+ ret = -EINVAL;
+ goto sq_wqe_err;
+ }
+
+ length = (sq_wqe_offset + inbuf->length > sq_buf_sz) ?
+ (sq_buf_sz - sq_wqe_offset) :
+ inbuf->length;
+ ret = roce5_copy_data_to_page(rdev, inbuf->attack_value, rqp->umem,
+ length, sq_wqe_offset, inbuf->attack_len,
+ inbuf->mask);
+ if (ret != 0) {
+ ROCE_ERR("Failed to copy to sq page, qpn:0x%x", qpn);
+ }
+
+sq_wqe_err:
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static int roce5_dfx_attack_rqwqe(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct roce_attack_outbuf *outbuf)
+{
+ struct roce5_qp *rqp = NULL;
+ int ret = 0;
+ u32 qpn = inbuf->qpn;
+ u32 rq_buf_sz;
+ u32 length;
+ u32 rq_attack_offset;
+ u32 rq_wqe_offset;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ ROCE_ERR("Failed to get roce qp, qpn:0x%x", qpn);
+ return -EINVAL;
+ }
+
+ rq_buf_sz = (u32)ROCE_ALIGN((u64)rqp->rq.wqebb_cnt
+ << (unsigned)rqp->rq.wqe_shift,
+ PAGE_SIZE);
+ rq_attack_offset = inbuf->offset;
+ if (rq_attack_offset >= rq_buf_sz) {
+ ROCE_ERR(
+ "roce attack rq wqe offset is too large, should be less than %u",
+ rq_buf_sz);
+ ret = -EINVAL;
+ goto rq_wqe_err;
+ }
+
+ length = (rq_attack_offset + inbuf->length > rq_buf_sz) ?
+ (rq_buf_sz - rq_attack_offset) :
+ inbuf->length;
+ rq_wqe_offset = rqp->rq.offset + rq_attack_offset;
+ ret = roce5_copy_data_to_page(rdev, inbuf->attack_value, rqp->umem,
+ length, rq_wqe_offset, inbuf->attack_len,
+ inbuf->mask);
+ if (ret != 0) {
+ ROCE_ERR("Failed to copy to rq page, qpn:0x%x", qpn);
+ }
+
+rq_wqe_err:
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static int roce5_dfx_attack_mtt(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct mtt *roce_mtt)
+{
+ struct hmm_comp_priv *comp_priv = NULL;
+ u64 *mtts = NULL;
+ u64 *mtts_offset = NULL;
+ u64 page_size;
+ u32 mtt_offset;
+ u32 length;
+ u64 val = ((u64)inbuf->attack_value[1] << 32) |
+ (u64)inbuf->attack_value[0];
+ u32 mtt_8B_offset;
+ bool is_upper_half;
+
+ if (roce_mtt == NULL) {
+ ROCE_ERR("roce qp mtt is null");
+ return -ENOMEM;
+ }
+
+ if (roce_mtt->mtt_vaddr == NULL) {
+ ROCE_ERR("roce mtt vaddr is null, layers:%u",
+ roce_mtt->mtt_layers);
+ return -ENOMEM;
+ }
+
+ comp_priv = get_hmm_comp_priv(rdev->hwdev, SERVICE_T_ROCE);
+ if (comp_priv == NULL) {
+ ROCE_ERR("Comp_priv is null");
+ return -ENOMEM;
+ }
+
+ mtts = (u64 *)hmm_em_table_find(
+ &comp_priv->mtt_em_table,
+ roce_mtt->mtt_seg[roce_mtt->mtt_layers - 1]->offset, NULL);
+ if (mtts == NULL) {
+ ROCE_ERR("Can't find va and pa of mtt entry");
+ return -ENOMEM;
+ }
+
+ page_size = 1L << roce_mtt->mtt_page_shift;
+ mtt_offset = inbuf->offset;
+ if (mtt_offset >= page_size) {
+ ROCE_ERR(
+ "roce attack mtt offset is too large, should be less than %llu",
+ page_size);
+ return -EINVAL;
+ }
+
+ mtt_8B_offset = ALIGN_DOWN_8B(mtt_offset);
+ mtts_offset = mtts + mtt_8B_offset / sizeof(u64);
+ if (inbuf->mask != 0) {
+ is_upper_half = IS_OFFSET_8B_ALIGN(mtt_offset);
+ roce5_copy_mask_attack_value_to_u64_addr(mtts_offset,
+ inbuf->attack_value[0],
+ inbuf->mask,
+ is_upper_half);
+ ROCE_INFO("roce attack mtt, mask_val:0x%x, offset:%u\n",
+ (inbuf->attack_value[0] & inbuf->mask), mtt_offset);
+ } else {
+ length = (inbuf->length + mtt_offset > page_size) ?
+ (page_size - mtt_offset) :
+ inbuf->length;
+ roce5_copy_attack_value_to_addr(mtts_offset, val, length);
+ ROCE_INFO("roce attack mtt, attack_len:%u, offset:%u", length,
+ mtt_offset);
+ }
+
+ return 0;
+}
+
+static int roce5_dfx_attack_cmtt(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct roce_attack_outbuf *outbuf)
+{
+ struct roce5_qp *rqp = NULL;
+ int ret = 0;
+ u32 qpn = inbuf->qpn;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ ROCE_ERR("Failed to get roce qp, qpn:0x%x", qpn);
+ return -EINVAL;
+ }
+
+ ret = roce5_dfx_attack_mtt(rdev, inbuf, &(rqp->mtt));
+ if (ret != 0) {
+ ROCE_ERR("Failed to attack cmtt");
+ }
+
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+struct roce5_mr *roce5_mr_find(struct roce5_device *rdev, u32 key_id)
+{
+ struct roce5_mr *mr = NULL;
+
+ mutex_lock(&rdev->device_res->mr_list.node_lock);
+ list_for_each_entry(mr, &rdev->device_res->mr_list.node, node) {
+ if (mr->rdmamr.mpt.mpt_index == key_id) {
+ mutex_unlock(&rdev->device_res->mr_list.node_lock);
+ ROCE_INFO("Find mr, it's mpt index is %u",
+ mr->rdmamr.mpt.mpt_index);
+ return mr;
+ }
+ }
+
+ mutex_unlock(&rdev->device_res->mr_list.node_lock);
+ ROCE_ERR("Don't find correct mr, key_id:%u", key_id);
+
+ return NULL;
+}
+
+static int roce5_dfx_attack_dmtt(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct roce_attack_outbuf *outbuf)
+{
+ struct roce5_mr *mr = NULL;
+ int ret = 0;
+
+ mr = roce5_mr_find(rdev, inbuf->mpt_index);
+ if (mr == NULL) {
+ ROCE_ERR(
+ "Failed to attack dmtt, don't find valid mr, mpt_index:%u",
+ inbuf->mpt_index);
+ return -EINVAL;
+ }
+
+ ret = roce5_dfx_attack_mtt(rdev, inbuf, &(mr->rdmamr.mtt));
+ if (ret != 0) {
+ ROCE_ERR("Failed to attack dmtt");
+ }
+
+ return ret;
+}
+
+static void roce5_attack_value_to_rdmarc(u32 *vaddr, u32 length, const u32 *val,
+ u32 attack_len)
+{
+ int cnt = (length + 3) >> 2;
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ vaddr[i] = val[i % attack_len];
+ }
+}
+
+static int roce5_dfx_attack_rdmarc(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct roce_attack_outbuf *outbuf)
+{
+ struct roce5_qp *rqp = NULL;
+ u32 qpn = inbuf->qpn;
+ struct rdma_rdmarc *rdmarc = NULL;
+ void *rdmarc_vaddr = NULL;
+ u32 *rdmarc_offset_vaddr = NULL;
+ u32 rdmarc_entry_num;
+ u32 rdmarc_offset;
+ u32 rdmarc_size;
+ u32 length;
+ int ret = 0;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ ROCE_ERR("Failed to get roce qp, qpn:0x%x", qpn);
+ return -EINVAL;
+ }
+
+ rdmarc = &(rqp->rdmarc);
+ rdmarc_vaddr = rdmarc->vaddr;
+ if (rdmarc_vaddr == NULL) {
+ ROCE_ERR("Rdmarc vaddr is null");
+ ret = -ENOMEM;
+ goto rdmarc_err;
+ }
+
+ rdmarc_entry_num = (1 << rdmarc->order);
+ rdmarc_size = rdmarc_entry_num * ROCE_RDMARC_ENTRY_SZ;
+ rdmarc_offset = inbuf->offset;
+ if (rdmarc_offset >= rdmarc_size) {
+ ROCE_ERR(
+ "roce attack rdmarc offset is too large, should be less than %u",
+ rdmarc_size);
+ ret = -EINVAL;
+ goto rdmarc_err;
+ }
+
+ rdmarc_offset_vaddr = (u32 *)((u8 *)rdmarc_vaddr + rdmarc_offset);
+
+ if (inbuf->mask != 0) {
+ roce5_copy_mask_attack_value_to_addr(rdmarc_offset_vaddr,
+ inbuf->attack_value[0],
+ inbuf->mask);
+ ROCE_INFO("roce attack rdmarc, mask_val:0x%x, offset:%u",
+ (inbuf->attack_value[0] & inbuf->mask),
+ rdmarc_offset);
+ } else {
+ length = (rdmarc_offset + inbuf->length > rdmarc_size) ?
+ (rdmarc_size - rdmarc_offset) :
+ inbuf->length;
+ roce5_attack_value_to_rdmarc(rdmarc_offset_vaddr, length,
+ inbuf->attack_value,
+ inbuf->attack_len);
+ ROCE_INFO("roce attack rdmarc, attack_length:%u, offset:%u",
+ length, rdmarc_offset);
+ }
+
+rdmarc_err:
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static int roce5_dfx_attack_cq(struct roce5_cq *cq, struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf)
+{
+ u32 ret;
+ u32 cq_attack_offset;
+ u32 cq_buf_sz;
+ u32 length;
+ u32 cq_depth = cq->cqe_mask + 1;
+ u32 cqe_size = rdev->rdma_cap.cqe_size;
+
+ cq_buf_sz = cqe_size * cq_depth;
+ if (inbuf->offset >= cq_buf_sz) {
+ ROCE_ERR(
+ "Roce attack cq cqe offset is too large, should be less than %u",
+ cq_buf_sz);
+ return -EINVAL;
+ }
+
+ cq_attack_offset = inbuf->offset;
+ length = ((cq_attack_offset + inbuf->length) > cq_buf_sz) ?
+ (cq_buf_sz - cq_attack_offset) :
+ inbuf->length;
+ ret = roce5_copy_data_to_page(rdev, inbuf->attack_value, cq->umem,
+ length, cq_attack_offset,
+ inbuf->attack_len, inbuf->mask);
+ if (ret != 0) {
+ ROCE_ERR("Failed to copy to cq page");
+ }
+
+ return ret;
+}
+
+static int roce5_dfx_attack_cqe(struct roce5_device *rdev,
+ const struct roce_attack_inbuf *inbuf,
+ struct roce_attack_outbuf *outbuf)
+{
+ struct roce5_qp *rqp = NULL;
+ int ret = 0;
+ u32 qpn = inbuf->qpn;
+ struct roce5_cq *send_cq = NULL;
+ struct roce5_cq *recv_cq = NULL;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ ROCE_ERR("Failed to get roce qp, qpn:0x%x", qpn);
+ return -EINVAL;
+ }
+
+ roce5_get_cqs(rqp, &send_cq, &recv_cq);
+ if (send_cq != NULL) {
+ ret = roce5_dfx_attack_cq(send_cq, rdev, inbuf);
+ if (ret != 0) {
+ ROCE_ERR("Failed to attack send_cq, qpn:0x%x", qpn);
+ goto cq_wqe_err;
+ }
+ }
+
+ if (recv_cq != NULL) {
+ ret = roce5_dfx_attack_cq(recv_cq, rdev, inbuf);
+ if (ret != 0) {
+ ROCE_ERR("Failed to attack recv_cq, qpn:0x%x", qpn);
+ goto cq_wqe_err;
+ }
+ }
+
+cq_wqe_err:
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static struct roce_dfx_attack_cmd_func g_roce_attack_cmd_funcs[] = {
+ { ROCE_ATTACK_TYPE_SQDB_HARD, roce5_dfx_attack_sqdb_hard },
+ { ROCE_ATTACK_TYPE_DWQE, roce5_dfx_attack_dwqe },
+ { ROCE_ATTACK_TYPE_SQWQE, roce5_dfx_attack_sqwqe },
+ { ROCE_ATTACK_TYPE_RQWQE, roce5_dfx_attack_rqwqe },
+ { ROCE_ATTACK_TYPE_CMTT, roce5_dfx_attack_cmtt },
+ { ROCE_ATTACK_TYPE_DMTT, roce5_dfx_attack_dmtt },
+ { ROCE_ATTACK_TYPE_RDMARC, roce5_dfx_attack_rdmarc },
+ { ROCE_ATTACK_TYPE_CQE, roce5_dfx_attack_cqe },
+};
+
+void roce5_cpu_to_be32(void *data, u32 len)
+{
+ u32 chunk_sz = sizeof(u32);
+ u32 *mem = (u32 *)data;
+ u32 data_len;
+ u32 i;
+
+ if (data == NULL)
+ return;
+
+ data_len = len / chunk_sz;
+
+ for (i = 0; i < data_len; i++) {
+ *mem = cpu_to_be32(*mem);
+ mem++;
+ }
+}
+
+int roce5_dfx_attack_func(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ struct roce_attack_inbuf *inbuf = (struct roce_attack_inbuf *)buf_in;
+ struct roce_attack_outbuf *outbuf =
+ (struct roce_attack_outbuf *)buf_out;
+ roce_adm_dfx_attack_func_t func = NULL;
+ u32 cmd_type;
+ u32 i;
+
+ if ((inbuf == NULL) || (outbuf == NULL)) {
+ ROCE_ERR("Roce dfx attack buf in or buf out is null.");
+ return -EINVAL;
+ }
+
+ /* check in and out buf size */
+ if (in_size < (u32)sizeof(struct roce_attack_inbuf)) {
+ ROCE_ERR("roce dfx attack buffer in size too small");
+ return -EINVAL;
+ }
+ if (*out_size < (u32)sizeof(struct roce_attack_outbuf)) {
+ ROCE_ERR("roce dfx attack buffer out size too small");
+ return -EINVAL;
+ }
+
+ *out_size = 0;
+
+ if (inbuf->convert_endian != 0)
+ roce5_cpu_to_be32(&(inbuf->attack_value),
+ sizeof(inbuf->attack_value));
+
+ for (i = 0; i < sizeof(g_roce_attack_cmd_funcs) /
+ sizeof(g_roce_attack_cmd_funcs[0]);
+ i++) {
+ cmd_type = g_roce_attack_cmd_funcs[i].cmd_id;
+ if (cmd_type == inbuf->attack_type) {
+ func = g_roce_attack_cmd_funcs[i].cmd_func;
+ if (func == NULL) {
+ ROCE_ERR(
+ "function of attack cmd(0x%x) is not supported.",
+ cmd_type);
+ return -EINVAL;
+ }
+
+ *out_size = sizeof(struct roce_attack_outbuf);
+
+ return func(rdev, inbuf, outbuf);
+ }
+ }
+
+ ROCE_ERR("attack cmd(0x%x) does't exist.", cmd_type);
+
+ return -EINVAL;
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_debug.c b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_debug.c
new file mode 100644
index 000000000..371fa3211
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_debug.c
@@ -0,0 +1,35 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#include <linux/semaphore.h>
+#include "hinic5_mt.h"
+#include "securec.h"
+#include "roce_infra.h"
+#include "roce.h"
+
+int roce5_get_drv_version(void *buf_out, u32 *out_size)
+{
+ struct drv_version_info *ver_info = buf_out;
+ int rc;
+
+ if (!buf_out) {
+ ROCE_ERR("Buf_out is NULL.");
+ return -EINVAL;
+ }
+
+ if (*out_size != sizeof(*ver_info)) {
+ ROCE_ERR("Unexpect out buf size from user :%u, expect: %lu",
+ *out_size, sizeof(*ver_info));
+ return -EINVAL;
+ }
+
+ rc = snprintf_s(ver_info->ver, sizeof(ver_info->ver),
+ sizeof(ver_info->ver) - 1, "%s %s(debug)",
+ HIROCE5_DRV_VERSION, __TIME_STR__);
+ if (rc == -1) {
+ ROCE_ERR("Snprintf roce version err");
+ return -EFAULT;
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_query.c b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_query.c
new file mode 100644
index 000000000..ef4b2da57
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/dfx/roce_dfx_query.c
@@ -0,0 +1,851 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved.
+
+
+#ifdef __ROCE_DFX__
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "comm_defs.h"
+#include "hinic5_hw.h"
+#include "hinic5_mt.h"
+
+#include "roce_compat.h"
+#include "roce.h"
+#include "roce_dfx.h"
+#include "roce_srq.h"
+#include "roce_qp.h"
+#include "roce_cq.h"
+#include "roce_cmd.h"
+#include "roce_mix.h"
+#include "roce_infra.h"
+#include "roce_npu_cmd.h"
+#include "roce_cqm_cmd.h"
+#include "roce_restore.h"
+#include "roce_main_extension.h"
+#include "roce_com.h"
+#include "securec.h"
+#include "hmm_common.h"
+#include "roce_npu_cmd_gid_defs.h"
+
+static int roce5_dfx_get_dev_algo(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ u32 cc_algo;
+ struct roce5_ecn_ctx ecn_ctx;
+ u32 *algo_type = &outbuf->algo_type;
+
+ if (rdev == NULL) {
+ ROCE_ERR("Failed to get roce device.");
+ return -EINVAL;
+ }
+ ecn_ctx = rdev->ecn_ctx;
+ cc_algo = ecn_ctx.cc_algo;
+ *algo_type = cc_algo;
+
+ return 0;
+}
+
+static int roce5_dfx_get_qp_count(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ struct roce5_dfx_qp_count *qp_count = &outbuf->qp_count;
+
+ qp_count->qp_alloced = rdev->qp_cnt.alloc_qp_cnt;
+ qp_count->qp_deleted = rdev->qp_cnt.del_qp_cnt;
+ qp_count->qp_alive =
+ rdev->qp_cnt.alloc_qp_cnt - rdev->qp_cnt.del_qp_cnt;
+
+ return 0;
+}
+
+/* QPC is statically allocated, so it is not necessary to judge whether it exists when querying the cache content */
+static int roce5_dfx_query_cache_qpc(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ u32 qpn = inbuf->qpn;
+ roce_verbs_qp_attr_s *qp_attr = &outbuf->qp_attr;
+
+ ret = memset_s(qp_attr, sizeof(roce_verbs_qp_attr_s), 0,
+ sizeof(roce_verbs_qp_attr_s));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset qp_attr.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_qp_query(rdev, qpn, (u32 *)(void *)qp_attr,
+ sizeof(roce_verbs_qp_attr_s));
+ if (ret != 0) {
+ roce5_dfx_print("Failed to query QPC from cache!");
+ roce5_dfx_print(
+ "******************From Cache: qpn(%#x) ********************",
+ qpn);
+ roce5_dfx_print(
+ ">>>>>>>>>>>>>>>> QUERY QPC FROM CACHE FAILED <<<<<<<<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Cache: qpn(%#x) ********************",
+ qpn);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce5_dfx_query_host_qpc(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ struct roce5_qp *rqp = NULL;
+ int ret = 0;
+ u32 qpn = inbuf->qpn;
+ roce5_qp_query_outbuf_s *qp_query = &outbuf->qp_query;
+
+ rqp = roce5_get_rqp_by_qpn(rdev, qpn);
+ if (rqp == NULL) {
+ roce5_dfx_print("Failed to get roce qp.");
+ roce5_dfx_print(
+ "******************From Host: qpn(%#x) ********************",
+ qpn);
+ roce5_dfx_print(
+ ">>>>>>>>>>> QUERY QPC FROM HOST FAILED, NOT EXIST <<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Host: qpn(%#x) ********************",
+ qpn);
+ return -EINVAL;
+ }
+
+ ret = memcpy_s(qp_query, sizeof(roce5_qp_query_outbuf_s),
+ rqp->qpc_info->vaddr, sizeof(roce5_qp_query_outbuf_s));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy qp_ctx, ret(%d).", ret);
+ goto err_out;
+ }
+
+err_out:
+ roce5_rqp_put(rqp);
+ return ret;
+}
+
+static int roce5_dfx_uni_cmd_query_cq(struct roce5_device *rdev, u32 cqn,
+ u32 *verbs_cq_attr, int cq_attr_size)
+{
+ int ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_cq_query_s *cq_query_inbuf = NULL;
+ roce_uni_cmd_cq_query_outbuf_s *cq_query_outbuf = NULL;
+ struct roce5_cq *rcq = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_cq_query_s), &cqm_cmd_outbuf,
+ (u16)sizeof(roce_uni_cmd_cq_query_outbuf_s));
+ if (ret != 0) {
+ roce5_dfx_print("Failed to alloc cqm_cmd_inoutbuf, ret=%d",
+ ret);
+ return ret;
+ }
+
+ rcq = roce5_get_rcq_by_cqn(rdev, cqn);
+ if (rcq == NULL) {
+ roce5_dfx_print("Failed to get roce cq.");
+ goto err_rcq;
+ }
+ cq_query_inbuf = (roce_uni_cmd_cq_query_s *)cqm_cmd_inbuf->buf;
+ cq_query_inbuf->com.index = cpu_to_be32(cqn);
+ cq_query_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_CQ_BITMASK));
+ if (rcq->shadow != 0) {
+ cq_query_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(
+ ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SHADOW_BITMASK));
+ cq_query_inbuf->com.dw3.bs.shadow_vfid =
+ cpu_to_be16(rcq->shadow_vfid);
+ }
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE, ROCE_CMD_QUERY_CQ,
+ cqm_cmd_inbuf, cqm_cmd_outbuf, NULL,
+ ROCE_CMD_TIME_CLASS_B, HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ roce5_dfx_print("Failed to send cmd QUERY_CQ, ret=%d", ret);
+ ret = -1;
+ goto out;
+ }
+
+ cq_query_outbuf = (roce_uni_cmd_cq_query_outbuf_s *)cqm_cmd_outbuf->buf;
+ ret = memcpy_s((void *)verbs_cq_attr, (size_t)cq_attr_size,
+ (void *)&cq_query_outbuf->cq_info.context[0],
+ (size_t)cq_attr_size);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy verbs_cq_attr.(ret:%d)", ret);
+ ret = -EINVAL;
+ goto out;
+ }
+out:
+ roce5_rcq_put(rcq);
+err_rcq:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+
+ return ret;
+}
+
+int roce5_dfx_query_cq(struct roce5_device *rdev, u32 cqn, u32 *context,
+ int cqc_size)
+{
+ if (ROCE5_SUPPORT_DFX_CMD_QUERY_CQ_MSG_V2(rdev) != 0) {
+ return roce5_dfx_uni_cmd_query_cq(rdev, cqn, context, cqc_size);
+ }
+ return -EINVAL;
+}
+
+/* CQC is dynamic allocation. When querying cache content, you need to determine whether it exists or not. */
+static int roce5_dfx_query_cache_cqc(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ cqm_object_s *cqm_obj_cq = NULL;
+ u32 cqn = inbuf->cqn;
+ roce5_cq_query_outbuf_s *cq_query = &outbuf->cq_query;
+
+ cqm_obj_cq =
+ cqm5_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SCQ, cqn, false);
+ if (cqm_obj_cq == NULL) {
+ roce5_dfx_print("Failed to get cqm_obj_cq.");
+ roce5_dfx_print(
+ "******************From Cache: cqn(%#x) ********************",
+ cqn);
+ roce5_dfx_print(
+ ">>>>>>>>>>> QUERY CQC FROM CACHE FAILED, NOT EXIST <<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Cache: cqn(%#x) ********************",
+ cqn);
+
+ return -EINVAL;
+ }
+
+ cqm5_object_put(cqm_obj_cq);
+
+ ret = memset_s(cq_query, sizeof(roce5_cq_query_outbuf_s), 0,
+ sizeof(roce5_cq_query_outbuf_s));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset cq_context.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_dfx_query_cq(rdev, cqn, (u32 *)(void *)cq_query,
+ sizeof(roce5_cq_query_outbuf_s));
+ if (ret != 0) {
+ roce5_dfx_print("Failed to query cq from cache!");
+ roce5_dfx_print(
+ "******************From Cache: cqn(%#x) ********************",
+ cqn);
+ roce5_dfx_print(
+ ">>>>>>>>>>>>>>>> QUERY CQC FROM CACHE FAILED <<<<<<<<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Cache: cqn(%#x) ********************",
+ cqn);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_dfx_query_host_cqc(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ struct roce5_cq *rcq = NULL;
+ int ret = 0;
+ u32 cqn = inbuf->cqn;
+ roce5_cq_query_outbuf_s *cq_query = &outbuf->cq_query;
+
+ rcq = roce5_get_rcq_by_cqn(rdev, cqn);
+ if (rcq == NULL) {
+ roce5_dfx_print("Failed to get roce cq.");
+ roce5_dfx_print(
+ "******************From Host: cqn(%#x) ********************",
+ cqn);
+ roce5_dfx_print(
+ ">>>>>>>>>>> QUERY CQC FROM HOST FAILED, NOT EXIST <<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Host: cqn(%#x) ********************",
+ cqn);
+
+ return -EINVAL;
+ }
+
+ ret = memcpy_s(cq_query, sizeof(roce5_cq_query_outbuf_s),
+ rcq->cqm_cq->q_ctx_vaddr,
+ sizeof(roce5_cq_query_outbuf_s));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy cq_ctx.(ret:%d)", ret);
+ goto err_out;
+ }
+
+err_out:
+ roce5_rcq_put(rcq);
+ return ret;
+}
+
+int roce5_dfx_cmd_query_srq(struct roce5_device *rdev, u32 srqn,
+ roce_verbs_srq_attr_s *srq_attr)
+{
+ int ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_srq_query_s *srq_query_inbuf = NULL;
+ roce_uni_cmd_srq_query_outbuf_s *srq_query_outbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_srq_query_s), &cqm_cmd_outbuf,
+ (u16)sizeof(roce_uni_cmd_srq_query_outbuf_s));
+ if (ret != 0) {
+ roce5_dfx_print("Failed to alloc cqm_cmd_inoutbuf, ret=%d",
+ ret);
+ return ret;
+ }
+
+ srq_query_inbuf = (roce_uni_cmd_srq_query_s *)cqm_cmd_inbuf->buf;
+ srq_query_inbuf->com.index = cpu_to_be32(srqn);
+ srq_query_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SRQ_BITMASK));
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_QUERY_SRQ, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, NULL, ROCE_CMD_TIME_CLASS_B,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ roce5_dfx_print("Failed to send cmd QUERY_SRQ, ret=%d", ret);
+ ret = -1;
+ goto out;
+ }
+
+ srq_query_outbuf =
+ (roce_uni_cmd_srq_query_outbuf_s *)cqm_cmd_outbuf->buf;
+ ret = memcpy_s(srq_attr, sizeof(roce_verbs_srq_attr_s),
+ &srq_query_outbuf->com.srq_attr,
+ sizeof(roce_verbs_srq_attr_s));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy srq_attr.(ret:%d)", ret);
+ ret = -EINVAL;
+ goto out;
+ }
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+
+ return ret;
+}
+
+/* SRQC is dynamic allocation. When querying the cache content, you need to determine whether it exists or not. */
+static int roce5_dfx_query_cache_srqc(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ cqm_object_s *cqm_obj_srq = NULL;
+ u32 srqn = inbuf->srqn;
+ roce_verbs_srq_attr_s *srq_attr = &outbuf->srq_attr;
+
+ cqm_obj_srq =
+ cqm5_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SRQ, srqn, false);
+ if (cqm_obj_srq == NULL) {
+ roce5_dfx_print("Failed to get cqm_obj_srq");
+ roce5_dfx_print(
+ "******************From Cache: srqn(%#x) ********************",
+ srqn);
+ roce5_dfx_print(
+ ">>>>>>>>>>> QUERY SRQC FROM CACHE FAILED, NOT EXIST <<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Cache: srqn(%#x) ********************",
+ srqn);
+
+ return -EINVAL;
+ }
+
+ cqm5_object_put(cqm_obj_srq);
+
+ ret = memset_s(srq_attr, sizeof(roce_verbs_srq_attr_s), 0,
+ sizeof(roce_verbs_srq_attr_s));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset srq_attr.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_dfx_cmd_query_srq(rdev, srqn, srq_attr);
+ if (ret != 0) {
+ roce5_dfx_print("Failed to query srq from cache");
+ roce5_dfx_print(
+ "******************From Cache: srqn(%#x) ********************",
+ srqn);
+ roce5_dfx_print(
+ ">>>>>>>>>>>>>>>> QUERY SRQC FROM CACHE FAILED <<<<<<<<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Cache: srqn(%#x) ********************",
+ srqn);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce5_dfx_query_host_srqc(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ struct roce5_srq *rsrq = NULL;
+ int ret = 0;
+ u32 srqn = inbuf->srqn;
+ roce5_srq_query_outbuf_s *srq_query = &outbuf->srq_query;
+
+ rsrq = roce5_get_rsrq_by_srqn(rdev, srqn);
+ if (rsrq == NULL) {
+ roce5_dfx_print("Failed to get roce srq.");
+ roce5_dfx_print(
+ "******************From Host: srqn(%#x) ********************",
+ srqn);
+ roce5_dfx_print(
+ ">>>>>>>>>>> QUERY SRQC FROM HOST FAILED, NOT EXIST <<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Host: srqn(%#x) ********************",
+ srqn);
+
+ return -EINVAL;
+ }
+
+ ret = memcpy_s(srq_query, sizeof(roce5_srq_query_outbuf_s),
+ rsrq->cqm_srq->q_ctx_vaddr,
+ sizeof(roce5_srq_query_outbuf_s));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy srq_ctx.(ret:%d)", ret);
+ goto err_out;
+ }
+
+err_out:
+ roce5_rsrq_put(rsrq);
+ return ret;
+}
+
+static int roce5_dfx_uni_cmd_query_mpt(struct roce5_device *rdev, u32 key,
+ struct roce_mpt_context *mpt_entry)
+{
+ int ret;
+ u32 mpt_index;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_mpt_query_s *mpt_query_inbuf = NULL;
+ roce_uni_cmd_mpt_query_outbuf_s *mpt_query_outbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_mpt_query_s), &cqm_cmd_outbuf,
+ (u16)sizeof(roce_uni_cmd_mpt_query_outbuf_s));
+ if (ret != 0) {
+ roce5_dfx_print("Failed to alloc cqm_cmd_inoutbuf, ret=%d",
+ ret);
+ return ret;
+ }
+
+ mpt_query_inbuf = (roce_uni_cmd_mpt_query_s *)cqm_cmd_inbuf->buf;
+ mpt_index = (key >> MR_KEY_2_INDEX_SHIFT) & 0xFFFFFF;
+ mpt_query_inbuf->com.index = cpu_to_be32(mpt_index);
+ mpt_query_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_MR_BITMASK));
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_QUERY_MPT, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, NULL, ROCE_CMD_TIME_CLASS_B,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ roce5_dfx_print("Failed to send cmd QUERY_MPT");
+ ret = -1;
+ goto out;
+ }
+
+ mpt_query_outbuf =
+ (roce_uni_cmd_mpt_query_outbuf_s *)cqm_cmd_outbuf->buf;
+ ret = memcpy_s(mpt_entry, sizeof(struct roce_mpt_context),
+ &mpt_query_outbuf->mpt_info.context[0],
+ sizeof(struct roce_mpt_context));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy mpt_entry.(ret:%d)", ret);
+ ret = -EINVAL;
+ goto out;
+ }
+
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+ return ret;
+}
+
+static int roce5_dfx_query_mpt(struct roce5_device *rdev, u32 key,
+ struct roce_mpt_context *mpt_entry)
+{
+ if (ROCE5_SUPPORT_DFX_CMD_QUERY_MPT_MSG_V2(rdev) != 0) {
+ return roce5_dfx_uni_cmd_query_mpt(rdev, key, mpt_entry);
+ }
+ return -EINVAL;
+}
+
+static int roce5_dfx_uni_cmd_query_gid(struct roce5_device *rdev, u32 port,
+ u32 gid_index,
+ struct rdma_gid_entry *gid_entry)
+{
+ int ret;
+ cqm_cmd_buf_s *cqm_cmd_inbuf = NULL;
+ cqm_cmd_buf_s *cqm_cmd_outbuf = NULL;
+ roce_uni_cmd_query_gid_s *gid_query_inbuf = NULL;
+ struct rdma_gid_query_outbuf *gid_query_outbuf = NULL;
+
+ ret = roce5_cqm_cmd_zalloc_inoutbuf(
+ rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(roce_uni_cmd_query_gid_s), &cqm_cmd_outbuf,
+ (u16)sizeof(struct rdma_gid_query_outbuf));
+ if (ret != 0) {
+ roce5_dfx_print("Failed to alloc cqm_cmd_inoutbuf, ret=%d",
+ ret);
+ return ret;
+ }
+
+ gid_query_inbuf = (roce_uni_cmd_query_gid_s *)cqm_cmd_inbuf->buf;
+ gid_query_inbuf->com.index = cpu_to_be32(gid_index);
+ gid_query_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_GID_BITMASK));
+ gid_query_inbuf->com.opt = cpu_to_be32(port);
+
+ if (rdev->shadow != 0) {
+ gid_query_inbuf->com.dw3.bs.shadow_vfid =
+ cpu_to_be16(rdev->shadow_vfid);
+ gid_query_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(
+ ROCE5_ULP_CMD(rdev, VERBS_CMD_TYPE_SHADOW_BITMASK));
+ gid_query_inbuf->gid_query.dw0.shadow.shadow_vf_num =
+ rdev->shadow_vf_num;
+ gid_query_inbuf->gid_query.dw0.value =
+ cpu_to_be32(gid_query_inbuf->gid_query.dw0.value);
+ }
+
+ ret = cqm5_send_cmd_box(rdev->hwdev, HINIC5_MOD_ROCE,
+ ROCE_CMD_QUERY_GID, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, NULL, ROCE_CMD_TIME_CLASS_B,
+ HINIC5_CHANNEL_ROCE);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to send cmd QUERY_GID, ret(%d)",
+ ret);
+ ret = -1;
+ goto out;
+ }
+
+ gid_query_outbuf = (struct rdma_gid_query_outbuf *)cqm_cmd_outbuf->buf;
+ ret = memcpy_s(gid_entry,
+ sizeof(struct rdma_gid_entry) * ROCE_GID_ENTRY_NUM,
+ gid_query_outbuf->gid_entry,
+ sizeof(struct rdma_gid_entry) * ROCE_GID_ENTRY_NUM);
+ if (ret != 0) {
+ ROCE_DEV_ERR(rdev, "Failed to memcpy gid_entry.(ret:%d)", ret);
+ }
+out:
+ roce5_cqm5_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf,
+ cqm_cmd_outbuf);
+
+ return ret;
+}
+
+static int roce5_dfx_query_gid(struct roce5_device *rdev, u32 port,
+ u32 gid_index, struct rdma_gid_entry *gid_entry)
+{
+ if (ROCE5_SUPPORT_DFX_CMD_QUERY_GID_MSG_V2(rdev) != 0) {
+ return roce5_dfx_uni_cmd_query_gid(rdev, port, gid_index,
+ gid_entry);
+ }
+ return -EINVAL;
+}
+
+/* MPT is statically allocated, so it is not necessary to judge whether it exists when querying the cache content */
+static int roce5_dfx_query_cache_mpt(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ u32 mpt_key = inbuf->mpt_key;
+ struct roce_mpt_context *mpt_entry = &outbuf->mpt;
+
+ ret = memset_s(mpt_entry, sizeof(struct roce_mpt_context), 0,
+ sizeof(struct roce_mpt_context));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset mpt_entry.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_dfx_query_mpt(rdev, mpt_key, mpt_entry);
+ if (ret != 0) {
+ roce5_dfx_print("Failed to query mpt from cache!");
+ roce5_dfx_print(
+ "******************From Cache: mpt_key(%#x) ********************",
+ mpt_key);
+ roce5_dfx_print(
+ ">>>>>>>>>>>>>>>> QUERY MPT FROM CACHE FAILED <<<<<<<<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Cache: mpt_key(%#x) ********************",
+ mpt_key);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce5_dfx_query_host_mpt(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ u32 mpt_index = 0;
+ struct mpt *rmpt = NULL;
+ int ret = 0;
+ u32 mpt_key = inbuf->mpt_key;
+ struct roce_mpt_context *mpt_entry = &outbuf->mpt;
+
+ mpt_index = (mpt_key >> MR_KEY_2_INDEX_SHIFT) & 0xFFFFFF;
+ rmpt = roce5_get_mpt_by_index(rdev, mpt_index);
+ if (rmpt == NULL) {
+ roce5_dfx_print("Failed to get roce mpt.");
+ roce5_dfx_print(
+ "******************From Host: mpt_key(%#x) ********************",
+ mpt_key);
+ roce5_dfx_print(
+ ">>>>>>>>>>> QUERY MPT FROM HOST FAILED, NOT EXIST <<<<<<<<<<<");
+ roce5_dfx_print(
+ "******************From Host: mpt_key(%#x) ********************",
+ mpt_key);
+
+ return -EINVAL;
+ }
+
+ ret = memcpy_s(mpt_entry, sizeof(struct roce_mpt_context), rmpt->vaddr,
+ sizeof(struct roce_mpt_context));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memcpy mpt_entry.(ret:%d)", ret);
+ goto err_out;
+ }
+
+err_out:
+ roce5_mpt_put(rmpt);
+ return ret;
+}
+
+static int roce5_dfx_query_cache_gid(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ u32 gid_index = inbuf->gid_index;
+ struct rdma_gid_entry *gid_entry = outbuf->gid_entry;
+
+ ret = memset_s(gid_entry,
+ sizeof(struct rdma_gid_entry) * ROCE_GID_ENTRY_NUM, 0,
+ sizeof(struct rdma_gid_entry) * ROCE_GID_ENTRY_NUM);
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset gid_entry.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_dfx_query_gid(rdev, 0, gid_index, gid_entry);
+ if (ret != 0) {
+ roce5_dfx_print(
+ "***************port(1), gid_index(%d) *****************",
+ gid_index);
+ roce5_dfx_print("Failed to query gid from cache!");
+ roce5_dfx_print(
+ "***************port(1), gid_index(%d) *****************",
+ gid_index);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void roce5_dfx_query_pi_ci_set(const roce_verbs_qp_attr_s *qp_attr,
+ struct roce5_dfx_pi_ci *pi_ci)
+{
+ pi_ci->qpc_sq_pi_on_chip = qp_attr->chip_seg.dw5.bs.sq_pi_on_chip;
+ pi_ci->qpc_sq_pi = qp_attr->ext_seg.dfx_info.dw0.bs.sq_pi;
+ pi_ci->qpc_sq_load_pi = qp_attr->ext_seg.dfx_info.dw1.bs.sq_load_pi;
+ pi_ci->qpc_rq_pi_on_chip = qp_attr->chip_seg.dw8.bs.rq_pi_on_chip;
+ pi_ci->qpc_rq_load_pi = qp_attr->ext_seg.dfx_info.dw1.bs.rq_load_pi;
+ pi_ci->qpc_rq_pi = qp_attr->ext_seg.dfx_info.dw4.bs.rq_pi;
+ pi_ci->qpc_rc_pi = qp_attr->ext_seg.dfx_info.dw5.bs.rc_pi;
+ pi_ci->qpc_sq_ci = qp_attr->ext_seg.dfx_info.dw0.bs.sq_ci;
+ pi_ci->qpc_sq_wqe_prefetch_ci =
+ qp_attr->ext_seg.dfx_info.dw1.bs.sq_wqe_prefetch_ci;
+ pi_ci->qpc_sq_mtt_prefetch_wqe_ci =
+ qp_attr->ext_seg.dfx_info.dw3.bs.sq_mtt_prefetch_wqe_ci;
+ pi_ci->qpc_sqa_ci = qp_attr->ext_seg.dfx_info.dw2.bs.sqa_ci;
+ pi_ci->qpc_sqa_wqe_prefetch_ci =
+ qp_attr->ext_seg.dfx_info.dw2.bs.sqa_wqe_prefetch_ci;
+ pi_ci->qpc_rq_ci = qp_attr->ext_seg.dfx_info.dw4.bs.rq_ci;
+ pi_ci->qpc_rq_wqe_prefetch_ci =
+ qp_attr->ext_seg.dfx_info.dw5.bs.rq_wqe_prefetch_ci;
+ pi_ci->qpc_rq_mtt_prefetch_wqe_ci =
+ qp_attr->ext_seg.dfx_info.dw3.bs.rq_mtt_prefetch_wqe_ci;
+ pi_ci->qpc_rq_base_ci = qp_attr->chip_seg.dw4.bs.rq_base_ci;
+ pi_ci->qpc_rc_ci = qp_attr->ext_seg.dfx_info.dw5.bs.rc_ci;
+ pi_ci->qpc_rc_prefetch_ci =
+ qp_attr->ext_seg.dfx_info.dw1.bs.rc_prefetch_ci;
+}
+
+static int roce5_dfx_query_pi_ci(const struct roce5_dfx_query_inbuf *inbuf,
+ struct roce5_device *rdev,
+ union roce5_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ roce_verbs_qp_attr_s be_attr; /* BE context structure */
+ roce_verbs_qp_attr_s qp_attr; /* LE context structure */
+ roce_verbs_cq_attr_s cq_attr;
+ roce5_cq_query_outbuf_s cq_query;
+ u32 qpn = inbuf->query_pi_ci.qpn;
+ u32 cqn = inbuf->query_pi_ci.cqn;
+ struct roce5_dfx_pi_ci *pi_ci = &outbuf->pi_ci;
+
+ ret = memset_s(pi_ci, sizeof(struct roce5_dfx_pi_ci), 0,
+ sizeof(struct roce5_dfx_pi_ci));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset pi_ci.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+
+ ret = memset_s(&qp_attr, sizeof(qp_attr), 0, sizeof(qp_attr));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset qp_attr.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_qp_query(rdev, qpn, (u32 *)(void *)&be_attr,
+ sizeof(roce_verbs_qp_attr_s));
+ if (ret != 0) {
+ return ret;
+ }
+
+ roce5_be32_2_le32(&be_attr, (u32 *)(void *)&qp_attr,
+ (sizeof(roce_verbs_qp_attr_s) / sizeof(u32)));
+
+ roce5_dfx_query_pi_ci_set(&qp_attr, pi_ci);
+
+ ret = memset_s(&cq_query, sizeof(roce5_cq_query_outbuf_s), 0,
+ sizeof(roce5_cq_query_outbuf_s));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset cq_query.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ ret = roce5_dfx_query_cq(rdev, cqn, (u32 *)(void *)&cq_query,
+ sizeof(roce5_cq_query_outbuf_s));
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (ROCE5_SUPPORT_DFX_CMD_QUERY_PI_CI_MSG_V2(rdev) != 0) {
+ (void)memcpy_s(&cq_attr, sizeof(roce_verbs_cq_attr_s),
+ &cq_query, sizeof(roce_verbs_cq_attr_s));
+ cq_attr.dw0.value = be32_to_cpu(cq_attr.dw0.value);
+ cq_attr.dfx_info.dw0.value =
+ be32_to_cpu(cq_attr.dfx_info.dw0.value);
+ cq_attr.dfx_info.dw1.value =
+ be32_to_cpu(cq_attr.dfx_info.dw1.value);
+ cq_attr.dfx_info.dw2.value =
+ be32_to_cpu(cq_attr.dfx_info.dw2.value);
+ cq_attr.dfx_info.dw3.value =
+ be32_to_cpu(cq_attr.dfx_info.dw3.value);
+ cq_attr.ci_record_gpa_at_hop_num =
+ be64_to_cpu(cq_attr.ci_record_gpa_at_hop_num);
+
+ pi_ci->cq_ci_on_chip = cq_attr.dw0.bs.ci_on_chip;
+ pi_ci->cq_ci = cq_attr.dfx_info.dw0.bs.ci;
+ pi_ci->cq_load_ci = cq_attr.dfx_info.dw2.bs.load_ci;
+ pi_ci->cq_ci_record_gpa_at_hop_num =
+ cq_attr.ci_record_gpa_at_hop_num;
+ pi_ci->cq_last_solicited_pi =
+ cq_attr.dfx_info.dw2.bs.last_solicited_pi;
+ pi_ci->cq_pi = cq_attr.dfx_info.dw1.bs.pi;
+ pi_ci->cq_last_notified_pi =
+ cq_attr.dfx_info.dw3.bs.last_notified_pi;
+ }
+ return 0;
+}
+
+static roce5_adm_dfx_query_cmd_proc_t g_roce5_adm_dfx_query_cmd_proc[] = {
+ { ROCE_CMD_GET_QPC_FROM_CACHE, roce5_dfx_query_cache_qpc },
+ { ROCE_CMD_GET_QPC_FROM_HOST, roce5_dfx_query_host_qpc },
+ { ROCE_CMD_GET_CQC_FROM_CACHE, roce5_dfx_query_cache_cqc },
+ { ROCE_CMD_GET_CQC_FROM_HOST, roce5_dfx_query_host_cqc },
+ { ROCE_CMD_GET_SRQC_FROM_CACHE, roce5_dfx_query_cache_srqc },
+ { ROCE_CMD_GET_SRQC_FROM_HOST, roce5_dfx_query_host_srqc },
+ { ROCE_CMD_GET_MPT_FROM_CACHE, roce5_dfx_query_cache_mpt },
+ { ROCE_CMD_GET_MPT_FROM_HOST, roce5_dfx_query_host_mpt },
+ { ROCE_CMD_GET_GID_FROM_CACHE, roce5_dfx_query_cache_gid },
+ { ROCE_CMD_GET_QPC_CQC_PI_CI, roce5_dfx_query_pi_ci },
+ { ROCE_CMD_GET_QP_COUNT, roce5_dfx_get_qp_count },
+ { ROCE_CMD_GET_DEV_ALGO, roce5_dfx_get_dev_algo },
+};
+
+int roce5_adm_dfx_query(struct roce5_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ int ret;
+ const struct roce5_dfx_query_inbuf *inbuf =
+ (struct roce5_dfx_query_inbuf *)buf_in;
+ union roce5_dfx_query_outbuf *outbuf =
+ (union roce5_dfx_query_outbuf *)buf_out;
+ const roce5_adm_generic_cmd_proc_t *generic_array =
+ (const roce5_adm_generic_cmd_proc_t *)
+ g_roce5_adm_dfx_query_cmd_proc;
+ int elem_count = sizeof(g_roce5_adm_dfx_query_cmd_proc) /
+ sizeof(g_roce5_adm_dfx_query_cmd_proc[0]);
+ roce5_adm_dfx_query_t roce5_adm_dfx_query_func = NULL;
+
+ if (in_size < sizeof(struct roce5_dfx_query_inbuf)) {
+ ROCE_ERR(
+ "Input parameter(in_size: %dB) is shorter than input buffer(allocated: %dB)",
+ (int)in_size,
+ (int)sizeof(struct roce5_dfx_query_inbuf));
+ return -ENOMEM;
+ }
+ if (*out_size < sizeof(union roce5_dfx_query_outbuf)) {
+ ROCE_ERR(
+ "Input parameter(out_size: %dB) is shorter than allocated buffer(allocated: %dB)",
+ (int)*out_size,
+ (int)sizeof(union roce5_dfx_query_outbuf));
+ return -ENOMEM;
+ }
+ ret = memset_s(buf_out, sizeof(union roce5_dfx_query_outbuf), 0,
+ sizeof(union roce5_dfx_query_outbuf));
+ if (ret != 0) {
+ ROCE_ERR("Failed to memset buf_out.(ret:%d)", ret);
+ return -ENOMEM;
+ }
+ *out_size = (u32)sizeof(union roce5_dfx_query_outbuf);
+
+ if (inbuf->cmd_type >= VM_COMPAT_TEST) {
+ roce5_dfx_print("Not support this type(%d)", inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ roce5_adm_dfx_query_func =
+ (roce5_adm_dfx_query_t)roce5_adm_generic_find_cmd_func(
+ generic_array, elem_count, inbuf->cmd_type);
+ if (roce5_adm_dfx_query_func == NULL) {
+ roce5_dfx_print("Not support this type(%d)", inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ return roce5_adm_dfx_query_func(inbuf, rdev, outbuf);
+}
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/obj_ext/roce_obj_ext.c b/drivers/infiniband/hw/hiroce5/kernel/util/obj_ext/roce_obj_ext.c
new file mode 100644
index 000000000..7c641f422
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/obj_ext/roce_obj_ext.c
@@ -0,0 +1,83 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#include <linux/slab.h>
+#include "securec.h"
+#include "roce_infra.h"
+#include "roce_obj_ext.h"
+
+int roce5_obj_ext_init(void *parent, const struct roce5_ext_reg *reg_items,
+ u8 item_num, struct roce5_obj_ext *obj_ext)
+{
+ int i, ret;
+
+ ret = memset_s(obj_ext->bufs, sizeof(void *) * ROCE_EXT_FEATURE_MAX, 0,
+ sizeof(void *) * ROCE_EXT_FEATURE_MAX);
+ if (ret != 0) {
+ ROCE_ERR(
+ "Failed to execute memset to object extension buffer, ret(%d).",
+ ret);
+ return ret;
+ }
+
+ for (i = 0; i < item_num; ++i) {
+ if (reg_items[i].ext_id >= ROCE_EXT_FEATURE_MAX) {
+ ROCE_ERR("Invalid extension id(%u).",
+ reg_items[i].ext_id);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (obj_ext->bufs[reg_items[i].ext_id] != NULL) {
+ ROCE_ERR("Repeated register, extension id(%u).",
+ reg_items[i].ext_id);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ obj_ext->bufs[reg_items[i].ext_id] =
+ kzalloc(reg_items[i].data_size, GFP_KERNEL);
+ if (obj_ext->bufs[reg_items[i].ext_id] == NULL) {
+ ROCE_ERR("Failed alloc memory for extension.");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ ret = reg_items[i].init_func(
+ parent, obj_ext->bufs[reg_items[i].ext_id]);
+ if (ret != 0) {
+ ROCE_ERR("Failed to init extension, ret(%d).", ret);
+ goto err_out;
+ }
+ }
+
+ return 0;
+
+err_out:
+ if (obj_ext->bufs[reg_items[i].ext_id] != NULL) {
+ kfree(obj_ext->bufs[reg_items[i].ext_id]);
+ }
+
+ for (--i; i >= 0; --i) {
+ reg_items[i].cleanup_func(parent,
+ obj_ext->bufs[reg_items[i].ext_id]);
+ kfree(obj_ext->bufs[reg_items[i].ext_id]);
+ }
+ return ret;
+}
+
+void roce5_obj_ext_deinit(void *parent, const struct roce5_ext_reg *reg_items,
+ u8 item_num, struct roce5_obj_ext *obj_ext)
+{
+ int i;
+ for (i = 0; i < item_num; ++i) {
+ if (reg_items[i].ext_id >= ROCE_EXT_FEATURE_MAX ||
+ obj_ext->bufs[reg_items[i].ext_id] == NULL) {
+ continue;
+ }
+
+ reg_items[i].cleanup_func(parent,
+ obj_ext->bufs[reg_items[i].ext_id]);
+ kfree(obj_ext->bufs[reg_items[i].ext_id]);
+ }
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/obj_ext/roce_obj_ext.h b/drivers/infiniband/hw/hiroce5/kernel/util/obj_ext/roce_obj_ext.h
new file mode 100644
index 000000000..3e5f7196c
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/obj_ext/roce_obj_ext.h
@@ -0,0 +1,40 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_OBJ_EXT_H
+#define ROCE_OBJ_EXT_H
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+
+typedef int (*ext_init_func)(void *parent, void *ext_data);
+typedef void (*ext_cleanup_func)(void *parent, void *ext_data);
+
+enum ROCE_EXT_ID { ROCE_EXT_HYPER_ROCE, ROCE_EXT_FEATURE_MAX };
+
+struct roce5_ext_reg {
+ u8 ext_id;
+ size_t data_size;
+ ext_init_func init_func;
+ ext_cleanup_func cleanup_func;
+};
+
+struct roce5_obj_ext {
+ void *bufs[ROCE_EXT_FEATURE_MAX];
+};
+
+static inline void *roce5_obj_ext_get_buf(struct roce5_obj_ext *obj_ext,
+ enum ROCE_EXT_ID ext_id)
+{
+ if (ext_id >= ROCE_EXT_FEATURE_MAX) {
+ return NULL;
+ }
+ return obj_ext->bufs[ext_id];
+}
+
+int roce5_obj_ext_init(void *parent, const struct roce5_ext_reg *reg_items,
+ u8 item_num, struct roce5_obj_ext *obj_ext);
+void roce5_obj_ext_deinit(void *parent, const struct roce5_ext_reg *reg_items,
+ u8 item_num, struct roce5_obj_ext *obj_ext);
+
+#endif /* ROCE_OBJ_EXT_H */
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/option/roce_option.c b/drivers/infiniband/hw/hiroce5/kernel/util/option/roce_option.c
new file mode 100644
index 000000000..6cfed12be
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/option/roce_option.c
@@ -0,0 +1,125 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/jiffies.h>
+
+#include "roce_infra.h"
+#include "securec.h"
+#include "roce_option.h"
+
+#define ROCE_WAIT_TIME_SEC 60
+
+struct roce5_option *roce5_some(void *value)
+{
+ int ret;
+
+ struct roce5_option *opt =
+ kmalloc(sizeof(struct roce5_option), GFP_KERNEL);
+ if (opt == NULL) {
+ ROCE_ERR("Failed to alloc memory.");
+ return NULL;
+ }
+
+ ret = strcpy_s(opt->waiting_msg, ROCE_WAITING_MSG_MAX_SIZE,
+ "Waiting for object release...");
+ if (ret != EOK) {
+ ROCE_ERR("Failed to init waiting message.");
+ kfree(opt);
+ return NULL;
+ }
+
+ spin_lock_init(&opt->spin_lock);
+ kref_init(&opt->refcount);
+ opt->value = value;
+
+ return opt;
+}
+
+static void roce5_wait_release(struct kref *refcount)
+{
+ struct roce5_option *opt =
+ container_of(refcount, struct roce5_option, refcount);
+
+ opt->value = NULL;
+ complete(&opt->release_comp);
+}
+
+static void roce5_timer_print_wait_msg(struct timer_list *tl)
+{
+ struct roce5_option *opt = from_timer(opt, tl, msg_timer);
+
+ ROCE_WARN("%s", opt->waiting_msg);
+
+ mod_timer(&opt->msg_timer, jiffies + ROCE_WAIT_TIME_SEC * HZ);
+}
+
+void roce5_option_unset(struct roce5_option *opt, char *waiting_msg,
+ size_t waiting_msg_size)
+{
+ int ret;
+ unsigned long flags; /* type required by kernel API */
+
+ if (opt == NULL) {
+ ROCE_ERR("Invalid parameter, opt is NULL.");
+ return;
+ }
+
+ if (waiting_msg != NULL && waiting_msg_size > 0) {
+ ret = strcpy_s(opt->waiting_msg, ROCE_WAITING_MSG_MAX_SIZE,
+ waiting_msg);
+ if (ret != EOK) {
+ ROCE_WARN("Failed to set waiting message, ret(%d).",
+ ret);
+ }
+ }
+
+ init_completion(&opt->release_comp);
+
+ timer_setup(&opt->msg_timer, roce5_timer_print_wait_msg, 0);
+ mod_timer(&opt->msg_timer, jiffies + ROCE_WAIT_TIME_SEC * HZ);
+
+ spin_lock_irqsave(&opt->spin_lock, flags);
+ kref_put(&opt->refcount, roce5_wait_release);
+ spin_unlock_irqrestore(&opt->spin_lock, flags);
+
+ wait_for_completion(&opt->release_comp);
+
+ del_timer_sync(&opt->msg_timer);
+}
+
+void *roce5_option_get_value(struct roce5_option *opt)
+{
+ void *ans = NULL;
+ unsigned long flags; /* type required by kernel API */
+
+ if (opt == NULL) {
+ ROCE_ERR("Invalid parameter, opt is NULL.");
+ return NULL;
+ }
+
+ spin_lock_irqsave(&opt->spin_lock, flags);
+ if (opt->value != NULL) {
+ kref_get(&opt->refcount);
+ ans = opt->value;
+ }
+ spin_unlock_irqrestore(&opt->spin_lock, flags);
+
+ return ans;
+}
+
+void roce5_option_put_value(struct roce5_option *opt)
+{
+ unsigned long flags; /* type required by kernel API */
+ if (opt == NULL) {
+ ROCE_ERR("Invalid parameter, opt is NULL.");
+ return;
+ }
+
+ spin_lock_irqsave(&opt->spin_lock, flags);
+ if (opt->value != NULL) {
+ kref_put(&opt->refcount, roce5_wait_release);
+ }
+ spin_unlock_irqrestore(&opt->spin_lock, flags);
+}
\ No newline at end of file
diff --git a/drivers/infiniband/hw/hiroce5/kernel/util/option/roce_option.h b/drivers/infiniband/hw/hiroce5/kernel/util/option/roce_option.h
new file mode 100644
index 000000000..dba51cd68
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce5/kernel/util/option/roce_option.h
@@ -0,0 +1,30 @@
+//SPDX-License-Identifier: GPL-2.0
+//Copyright (c) Huawei Technologies Co., Ltd. All rights reserved.
+
+#ifndef ROCE_OPTION_H
+#define ROCE_OPTION_H
+
+#include <linux/kref.h>
+#include <linux/completion.h>
+#include <linux/timer.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
+#define ROCE_WAITING_MSG_MAX_SIZE 100
+
+struct roce5_option {
+ spinlock_t spin_lock;
+ struct kref refcount; /* count for the value ptr. */
+ struct completion release_comp;
+ struct timer_list msg_timer;
+ char waiting_msg[ROCE_WAITING_MSG_MAX_SIZE];
+ void *value;
+};
+
+struct roce5_option *roce5_some(void *value);
+void roce5_option_unset(struct roce5_option *opt, char *waiting_msg,
+ size_t waiting_msg_size);
+void *roce5_option_get_value(struct roce5_option *opt);
+void roce5_option_put_value(struct roce5_option *opt);
+
+#endif /* ROCE_OPTION_H */
--
2.37.7
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/25657 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/VVE... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/25657 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/VVE...
participants (2)
-
Maogangpin -
patchwork bot