aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoropeneuler-ci-bot <george@openeuler.sh>2024-04-30 06:35:01 +0000
committerGitee <noreply@gitee.com>2024-04-30 06:35:01 +0000
commitae52f9c522ddf14090fc55bfe6f466c29c68bc95 (patch)
tree3a63d1d5b31fea7d5b5d14dd732a8264ae84319f
parent25d9fa98bac87f2cbc5868182135639be8234ad2 (diff)
parente25b6f88da8c5fc529ab1c588068a6fce36e5bfe (diff)
downloadopenEuler-kernel-OLK-5.10.tar.gz
!6684 infiniband/hw/hiroce3: Add Huawei Intelligent Network Card RDMA DriverOLK-5.10
Merge Pull Request from: @ci-robot PR sync from: Shuai Wu <wushuai51@huawei.com> https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/JYQQHXWW4WX7GBALUHAGAMHYLGTFKTYM/ The RDMA driver supports the following features: Supports Huawei SP600 series NICs; Supports RoCEv2; Supports RoCE UC, RC, and UD local switching; Supports RoCE MR, PD, CQ, QoS, QP, and SRQ management; Supports RoCE congestion control; Supports RoCE Bond; Supports RoCE FLR; Supports RoCE entry specifications; Supports RoCE error detection and reporting; Shuai Wu (2): net/ethernet/huawei/hinic3: Add the CQM on which the RDMA depends infiniband/hw/hiroce3: Add Huawei Intelligent Network Card RDMA Driver https://gitee.com/openeuler/kernel/issues/I9H643 Link:https://gitee.com/openeuler/kernel/pulls/6684 Reviewed-by: Yue Haibing <yuehaibing@huawei.com> Reviewed-by: Liu Chao <liuchao173@huawei.com> Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com>
-rw-r--r--Documentation/networking/hinic3.txt15
-rw-r--r--arch/arm64/configs/openeuler_defconfig1
-rw-r--r--arch/x86/configs/openeuler_defconfig1
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/hw/Makefile1
-rw-r--r--drivers/infiniband/hw/hiroce3/Kconfig14
-rw-r--r--drivers/infiniband/hw/hiroce3/Makefile98
-rw-r--r--drivers/infiniband/hw/hiroce3/bond/roce_bond.h147
-rw-r--r--drivers/infiniband/hw/hiroce3/bond/roce_bond_common.c938
-rw-r--r--drivers/infiniband/hw/hiroce3/cq/roce_cq.h250
-rw-r--r--drivers/infiniband/hw/hiroce3/cq/roce_cq_common.c195
-rw-r--r--drivers/infiniband/hw/hiroce3/cq/roce_cq_cqe.c744
-rw-r--r--drivers/infiniband/hw/hiroce3/cq/roce_cq_create.c629
-rw-r--r--drivers/infiniband/hw/hiroce3/cq/roce_cq_ctrl.c930
-rw-r--r--drivers/infiniband/hw/hiroce3/cq/roce_cq_destroy.c247
-rw-r--r--drivers/infiniband/hw/hiroce3/dfx/roce_dfx.c122
-rw-r--r--drivers/infiniband/hw/hiroce3/dfx/roce_dfx.h177
-rw-r--r--drivers/infiniband/hw/hiroce3/dfx/roce_dfx_cap.c688
-rw-r--r--drivers/infiniband/hw/hiroce3/dfx/roce_dfx_cap.h181
-rw-r--r--drivers/infiniband/hw/hiroce3/dfx/roce_dfx_query.c643
-rw-r--r--drivers/infiniband/hw/hiroce3/extension/roce_cdev_extension.c11
-rw-r--r--drivers/infiniband/hw/hiroce3/extension/roce_event_extension.c23
-rw-r--r--drivers/infiniband/hw/hiroce3/extension/roce_main_extension.c188
-rw-r--r--drivers/infiniband/hw/hiroce3/extension/roce_mr_extension.c31
-rw-r--r--drivers/infiniband/hw/hiroce3/extension/roce_netdev_extension.c121
-rw-r--r--drivers/infiniband/hw/hiroce3/extension/roce_qp_extension.c241
-rw-r--r--drivers/infiniband/hw/hiroce3/extension/roce_qp_post_send_extension.c11
-rw-r--r--drivers/infiniband/hw/hiroce3/extension/roce_srq_extension.c27
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_buddy.c161
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_buddy.h32
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp.c164
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp.h228
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_init.c123
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_mtt.c494
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_mw_mr.c220
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_res.c58
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_em.c348
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_em.h47
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_mr.c429
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_mr.h32
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_umem.c273
-rw-r--r--drivers/infiniband/hw/hiroce3/host/hmm/hmm_umem.h124
-rw-r--r--drivers/infiniband/hw/hiroce3/include/hinic3_hmm.h93
-rw-r--r--drivers/infiniband/hw/hiroce3/include/hinic3_rdma.h202
-rw-r--r--drivers/infiniband/hw/hiroce3/include/nic/nic_mpu_cmd.h181
-rw-r--r--drivers/infiniband/hw/hiroce3/include/nic/nic_npu_cmd.h29
-rw-r--r--drivers/infiniband/hw/hiroce3/include/nic/nic_npu_cmd_defs.h134
-rw-r--r--drivers/infiniband/hw/hiroce3/include/node_id.h52
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/rdma_context_format.h5181
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/rdma_ext_ctx_format.h379
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_ccf_format.h722
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_compile_macro.h66
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_ctx_api.h258
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_dif_format.h492
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_err_type.h122
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_hmm_context.h210
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_mpu_common.h234
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_pub.h259
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_pub_cmd.h261
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_ulp.h178
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_vbs_format.h206
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_attr.h413
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_attr_qpc_chip.h360
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_cmd.h248
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_cq_attr.h196
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_ext_attr.h48
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_format.h132
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_gid_attr.h111
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_mr_attr.h330
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_pub.h225
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_srq_attr.h264
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_ulp_format.h91
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_wqe_format.h930
-rw-r--r--drivers/infiniband/hw/hiroce3/include/rdma/roce_xqe_format.h722
-rw-r--r--drivers/infiniband/hw/hiroce3/include/roce_cdev_extension.h13
-rw-r--r--drivers/infiniband/hw/hiroce3/include/roce_event_extension.h13
-rw-r--r--drivers/infiniband/hw/hiroce3/include/roce_main_extension.h78
-rw-r--r--drivers/infiniband/hw/hiroce3/include/roce_mr_extension.h17
-rw-r--r--drivers/infiniband/hw/hiroce3/include/roce_netdev_extension.h19
-rw-r--r--drivers/infiniband/hw/hiroce3/include/roce_qp_extension.h64
-rw-r--r--drivers/infiniband/hw/hiroce3/include/roce_qp_post_send_extension.h13
-rw-r--r--drivers/infiniband/hw/hiroce3/include/roce_srq_extension.h14
-rw-r--r--drivers/infiniband/hw/hiroce3/mr/roce_mr.c949
-rw-r--r--drivers/infiniband/hw/hiroce3/mr/roce_mr.h97
-rw-r--r--drivers/infiniband/hw/hiroce3/qp/roce_post.h167
-rw-r--r--drivers/infiniband/hw/hiroce3/qp/roce_qp.h244
-rw-r--r--drivers/infiniband/hw/hiroce3/qp/roce_qp_create.c1239
-rw-r--r--drivers/infiniband/hw/hiroce3/qp/roce_qp_destroy.c260
-rw-r--r--drivers/infiniband/hw/hiroce3/qp/roce_qp_exp.h80
-rw-r--r--drivers/infiniband/hw/hiroce3/qp/roce_qp_modify.c2243
-rw-r--r--drivers/infiniband/hw/hiroce3/qp/roce_qp_post_recv.c223
-rw-r--r--drivers/infiniband/hw/hiroce3/qp/roce_qp_post_send.c1315
-rw-r--r--drivers/infiniband/hw/hiroce3/qp/roce_qp_query.c393
-rw-r--r--drivers/infiniband/hw/hiroce3/rdma/rdma_bitmap.c129
-rw-r--r--drivers/infiniband/hw/hiroce3/rdma/rdma_bitmap.h36
-rw-r--r--drivers/infiniband/hw/hiroce3/rdma/rdma_comp.c22
-rw-r--r--drivers/infiniband/hw/hiroce3/rdma/rdma_comp.h131
-rw-r--r--drivers/infiniband/hw/hiroce3/rdma/rdma_comp_gid.c281
-rw-r--r--drivers/infiniband/hw/hiroce3/rdma/rdma_comp_init.c366
-rw-r--r--drivers/infiniband/hw/hiroce3/rdma/rdma_comp_mw_mr.c242
-rw-r--r--drivers/infiniband/hw/hiroce3/rdma/rdma_comp_pd.c50
-rw-r--r--drivers/infiniband/hw/hiroce3/rdma/rdma_comp_res.c245
-rw-r--r--drivers/infiniband/hw/hiroce3/roce.h574
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_cdev.c1259
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_cmd.c722
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_cmd.h74
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_compat.h60
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_cqm_cmd.c52
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_cqm_cmd.h17
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_db.c88
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_db.h29
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_event.c566
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_event.h36
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_k_ioctl.h89
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_main.c1609
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_mix.c1194
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_mix.h205
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_netdev.c786
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_netdev.h59
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_netlink.c352
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_netlink.h164
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_pd.c66
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_pd.h24
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_sysfs.c1800
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_sysfs.h108
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_user.h65
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_xrc.c128
-rw-r--r--drivers/infiniband/hw/hiroce3/roce_xrc.h23
-rw-r--r--drivers/infiniband/hw/hiroce3/srq/roce_srq.h201
-rw-r--r--drivers/infiniband/hw/hiroce3/srq/roce_srq_comm.c93
-rw-r--r--drivers/infiniband/hw/hiroce3/srq/roce_srq_create.c635
-rw-r--r--drivers/infiniband/hw/hiroce3/srq/roce_srq_ctrl.c570
-rw-r--r--drivers/net/ethernet/huawei/hinic3/Makefile22
-rw-r--r--drivers/net/ethernet/huawei/hinic3/bond/hinic3_bond.c1042
-rw-r--r--drivers/net/ethernet/huawei/hinic3/bond/hinic3_bond.h98
-rw-r--r--drivers/net/ethernet/huawei/hinic3/comm_msg_intf.h565
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_bat_cla.c2056
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_bat_cla.h214
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_bitmap_table.c1454
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_bitmap_table.h66
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_bloomfilter.c535
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_bloomfilter.h53
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_cmd.c250
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_cmd.h39
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_db.c506
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_db.h36
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_define.h54
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_main.c1743
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_main.h380
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_memsec.c665
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_memsec.h23
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_object.c1664
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_object.h714
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_object_intern.c1467
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/cqm_object_intern.h93
-rw-r--r--drivers/net/ethernet/huawei/hinic3/cqm/readme.txt3
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hinic3_crm.h110
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hinic3_dbg.c2
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hinic3_hw.h51
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hinic3_mag_cfg.c4
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h377
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hinic3_nic.h1
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h1
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hinic3_srv_nic.h5
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.c33
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.h7
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_csr.h1
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_devlink.h24
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_eqs.c35
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c155
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h17
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.c148
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.h2
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_mt.c39
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.c212
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.h33
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwif.c54
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.c113
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.h82
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.c76
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.h5
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_multi_host_mgmt.c1231
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_multi_host_mgmt.h124
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c1
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/hinic3_pci_id_tbl.h30
-rw-r--r--drivers/net/ethernet/huawei/hinic3/hw/ossl_knl_linux.c20
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/bond/bond_common_defs.h69
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd.h12
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h212
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/cqm/cqm_npu_cmd.h31
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/cqm/cqm_npu_cmd_defs.h61
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/hinic3_common.h181
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/hinic3_cqm.h364
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/hinic3_cqm_define.h52
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/hinic3_lld.h223
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/hinic3_profile.h148
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/mpu/mag_mpu_cmd.h70
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_board_defs.h71
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_cmd_base_defs.h116
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_inband_cmd.h187
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_inband_cmd_defs.h1078
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_outband_ncsi_cmd_defs.h205
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/mpu/nic_cfg_comm.h55
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/ossl_types.h144
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/public/npu_cmdq_base_defs.h232
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/readme.txt1
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/vmsec/vmsec_mpu_common.h107
-rw-r--r--drivers/net/ethernet/huawei/hinic3/include/vram_common.h65
-rw-r--r--drivers/net/ethernet/huawei/hinic3/mag_cmd.h272
-rw-r--r--drivers/net/ethernet/huawei/hinic3/ossl_knl.h4
-rw-r--r--drivers/net/ethernet/huawei/hinic3/ossl_knl_linux.h29
-rw-r--r--openEuler/MAINTAINERS18
212 files changed, 62945 insertions, 1125 deletions
diff --git a/Documentation/networking/hinic3.txt b/Documentation/networking/hinic3.txt
index af874f9ba2a7e..be7803301e804 100644
--- a/Documentation/networking/hinic3.txt
+++ b/Documentation/networking/hinic3.txt
@@ -81,6 +81,21 @@ Data. (hinic3_hw_qp.c, hinic3_hw_qp.h, hinic3_hw_qp_ctxt.h)
IO - de/constructs all the IO components. (hinic3_hw_io.c, hinic3_hw_io.h)
+CQM components:
+==========
+
+The CQM module organizes the memory in the large system in a format (CLA table)
+and allocates the memory to the chip (BAT table). The chip can use the memory in
+the large system to save context information and queue information (SCQ\SRQ).
+(cqm_bat_cla.c, cqm_bat_cla.h, cqm_bitmap_table.c, cqm_bitmap_table.h)
+
+When a packet is transmitted from the PCIe link, the chip parses the 5-tuple
+such as sid, did, and hostid. Fill the parsed data in the queue
+(in the form of scqe). In this way, the driver can directly obtain data from the
+queue (through MPDK polling) and then process the data. In this way, the
+uninstallation is implemented.
+(cqm_main.c, cqm_main.h, cqm_db.c, cqm_db.h)
+
HW device:
==========
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig
index cb4f5e03dccd3..34061d75a0d21 100644
--- a/arch/arm64/configs/openeuler_defconfig
+++ b/arch/arm64/configs/openeuler_defconfig
@@ -5647,6 +5647,7 @@ CONFIG_INFINIBAND_HNS_HIP08=y
CONFIG_INFINIBAND_BNXT_RE=m
CONFIG_INFINIBAND_QEDR=m
CONFIG_INFINIBAND_XSC=m
+CONFIG_HIROCE3=m
CONFIG_RDMA_RXE=m
# CONFIG_RDMA_SIW is not set
CONFIG_INFINIBAND_IPOIB=m
diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig
index 39ec74f1e670e..b43404447d162 100644
--- a/arch/x86/configs/openeuler_defconfig
+++ b/arch/x86/configs/openeuler_defconfig
@@ -6280,6 +6280,7 @@ CONFIG_INFINIBAND_HFI1=m
CONFIG_INFINIBAND_QEDR=m
CONFIG_INFINIBAND_XSC=m
CONFIG_INFINIBAND_RDMAVT=m
+CONFIG_HIROCE3=m
CONFIG_RDMA_RXE=m
# CONFIG_RDMA_SIW is not set
CONFIG_INFINIBAND_IPOIB=m
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index ec00b4f72fb73..194e824832d6b 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -92,6 +92,7 @@ source "drivers/infiniband/hw/bnxt_re/Kconfig"
source "drivers/infiniband/hw/hfi1/Kconfig"
source "drivers/infiniband/hw/qedr/Kconfig"
source "drivers/infiniband/hw/xsc/Kconfig"
+source "drivers/infiniband/hw/hiroce3/Kconfig"
source "drivers/infiniband/sw/rdmavt/Kconfig"
source "drivers/infiniband/sw/rxe/Kconfig"
source "drivers/infiniband/sw/siw/Kconfig"
diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile
index 478dc420a612e..af9b9b87c7721 100644
--- a/drivers/infiniband/hw/Makefile
+++ b/drivers/infiniband/hw/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_INFINIBAND_HNS) += hns/
obj-$(CONFIG_INFINIBAND_QEDR) += qedr/
obj-$(CONFIG_INFINIBAND_BNXT_RE) += bnxt_re/
obj-$(CONFIG_INFINIBAND_XSC) += xsc/
+obj-$(CONFIG_HIROCE3) += hiroce3/
diff --git a/drivers/infiniband/hw/hiroce3/Kconfig b/drivers/infiniband/hw/hiroce3/Kconfig
new file mode 100644
index 0000000000000..9e351bf100225
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Huawei driver configuration
+#
+
+config HIROCE3
+ tristate "Huawei Intelligent Network Interface Card RDMA Driver"
+ depends on HINIC3 && PCI_MSI && NUMA && PCI_IOV && DCB && (X86 || ARM64)
+ help
+ This driver supports HiROCE PCIE Ethernet cards.
+ To compile this driver as part of the kernel, choose Y here.
+ If unsure, choose N.
+ The default is N.
+
diff --git a/drivers/infiniband/hw/hiroce3/Makefile b/drivers/infiniband/hw/hiroce3/Makefile
new file mode 100644
index 0000000000000..379bcb8aafb9f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/Makefile
@@ -0,0 +1,98 @@
+EXPORT_SYMBOL := true
+
+OFED_VERSION := OFED_MLNX_5_8
+KBUILD_EXTRA_SYMBOLS += $(srctree)/drivers/net/ethernet/huawei/hinic3/Module.symvers
+
+ccflags-y += -DHW_CONVERT_ENDIAN
+ccflags-y += -DROCE_SERVICE
+ccflags-y += -D__ROCE_DFX__
+ccflags-y += -DROCE_CC_EN
+ccflags-y += -D$(OFED_VERSION)
+ccflags-y += -DROCE_COMPUTE
+ccflags-y += -DROCE_BONDING_EN
+ccflags-y += -DROCE_STANDARD
+ccflags-y += -DOFED_MLNX_5_8
+
+# Set CFLAGS from default file directories
+ccflags-y += -I$(srctree)/include/linux
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/host/hmm
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/bond
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/cq
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/dfx
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/extension
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/include
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/include/nic
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/include/rdma
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/include/mag
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/mr
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/qp
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/rdma
+ccflags-y += -I$(srctree)/drivers/infiniband/hw/hiroce3/srq
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/hw
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/bond
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/mpu
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/bond
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cqm
+
+obj-$(CONFIG_HIROCE3) += hiroce3.o
+
+hiroce3-y := cq/roce_cq_common.o \
+ cq/roce_cq_cqe.o \
+ cq/roce_cq_create.o \
+ cq/roce_cq_ctrl.o \
+ cq/roce_cq_destroy.o \
+ extension/roce_event_extension.o \
+ extension/roce_main_extension.o \
+ extension/roce_mr_extension.o \
+ extension/roce_netdev_extension.o \
+ extension/roce_qp_extension.o \
+ extension/roce_qp_post_send_extension.o \
+ extension/roce_srq_extension.o \
+ extension/roce_cdev_extension.o \
+ roce_db.o \
+ roce_main.o \
+ roce_netlink.o \
+ roce_event.o \
+ roce_netdev.o \
+ roce_mix.o \
+ mr/roce_mr.o \
+ roce_pd.o \
+ qp/roce_qp_create.o \
+ qp/roce_qp_destroy.o \
+ qp/roce_qp_modify.o \
+ qp/roce_qp_post_recv.o \
+ qp/roce_qp_post_send.o \
+ qp/roce_qp_query.o \
+ roce_xrc.o \
+ dfx/roce_dfx.o \
+ dfx/roce_dfx_query.o \
+ dfx/roce_dfx_cap.o \
+ roce_cdev.o \
+ roce_sysfs.o \
+ roce_cmd.o \
+ roce_cqm_cmd.o \
+ bond/roce_bond_common.o \
+ rdma/rdma_bitmap.o \
+ rdma/rdma_comp.o \
+ rdma/rdma_comp_res.o \
+ rdma/rdma_comp_gid.o \
+ rdma/rdma_comp_init.o \
+ rdma/rdma_comp_pd.o \
+ rdma/rdma_comp_mw_mr.o \
+ srq/roce_srq_comm.o \
+ srq/roce_srq_create.o \
+ srq/roce_srq_ctrl.o \
+ host/hmm/hmm_buddy.o \
+ host/hmm/hmm_comp.o \
+ host/hmm/hmm_comp_init.o \
+ host/hmm/hmm_comp_mtt.o \
+ host/hmm/hmm_comp_mw_mr.o \
+ host/hmm/hmm_comp_res.o \
+ host/hmm/hmm_em.o \
+ host/hmm/hmm_mr.o \
+ host/hmm/hmm_umem.o
+
diff --git a/drivers/infiniband/hw/hiroce3/bond/roce_bond.h b/drivers/infiniband/hw/hiroce3/bond/roce_bond.h
new file mode 100644
index 0000000000000..5406893bfe100
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/bond/roce_bond.h
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_BOND_H
+#define ROCE_BOND_H
+
+#include <net/bonding.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_bond.h"
+
+#include "roce.h"
+#include "roce_qp.h"
+#include "roce_cmd.h"
+#include "roce_verbs_attr.h"
+
+#define ROCE_BOND_MAX_GROUPS 2
+#define ROCE_BOND_2_100G_MAX_GROUPS 1
+#define ROCE_BOND_4_25G_MAX_GROUPS 2
+
+/* Adding two roce at a time consumes one bit of the array.
+ * Currently, a maximum of 33 nodes are supported, and at least 17.
+ * To support roce hot swap, the code logic needs to be reconstructed.
+ */
+#define ROCE_BOND_HCA_NUM 17
+
+#define ROCE_BOND_MAX_PORTS 4
+#define ROCE_BOND_MAX_FUNCS 4
+
+#define ROCE_BOND_NO_VLAN_ID 0
+#define ROCE_BOND_RSVD_VLAN_ID 4095
+
+#define ROCE_BOND_PORT_ENABLE 1
+#define ROCE_BOND_PORT_DISABLE 0
+
+#define ROCE_BOND_ADD_MAC_TBL 1
+#define ROCE_BOND_DEL_MAC_TBL 0
+
+#define ROCE_BOND_FWD_ID_TBL_ALL_BITS 32
+#define ROCE_BOND_FWD_ID_TBL_PER_BITS 3
+#define ROCE_BOND_FWD_ID_TBL_PER_BITS_MASK 0x7
+
+#define ROCE_BOND_MAX_ACX_QP_NUM 32
+#define ROCE_BOND_ACX_QP_ENABLE 1
+#define ROCE_BOND_ACX_QP_DISABLE 0
+
+#define ROCE_BOND_WAIT_ACTIVE_500MS 500
+enum {
+ ROCE_BOND_FUNC_OWN_FLAG = (1 << 0)
+};
+
+enum {
+ ROCE_BOND_FLAG = (1 << 0)
+};
+
+enum {
+ ROCE_BOND_WANT_TWO_SLAVES = 2, /* 2 slaves per bond_dev */
+ ROCE_BOND_WANT_THREE_SLAVES = 3, /* 3 slaves per bond_dev */
+ ROCE_BOND_WANT_FOUR_SLAVES = 4 /* 4 slaves per bond_dev */
+};
+
+enum {
+ ROCE_BOND_WANT_TWO_SLAVES_MASK = 0x3,
+ ROCE_BOND_WANT_THREE_SLAVES_MASK = 0x7,
+ ROCE_BOND_WANT_FOUR_SLAVES_MASK = 0xf
+};
+
+enum {
+ ROCE_BOND_2_PORT_NUM = 2,
+ ROCE_BOND_4_PORT_NUM = 4
+};
+
+enum {
+ ROCE_BOND_25G_PORT_SPEED = 25,
+ ROCE_BOND_100G_PORT_SPEED = 100
+};
+
+enum {
+ ROCE_BOND_2_FUNC_NUM = 2,
+ ROCE_BOND_4_FUNC_NUM = 4
+};
+
+enum {
+ ROCE_BOND_INVALID_HCA = -1,
+ ROCE_BOND_2_100G_HCA = 0,
+ ROCE_BOND_4_25G_HCA = 1,
+ ROCE_BOND_2_25G_HCA = 2
+};
+
+#define SDI_BOND_SUPPORT_ROCE_FUNC_BIT 1
+#define SDI_BOND_SUPPORT_ROCE_FUNC_CNT 1
+#define SDI_BOND_SLAVES_FUNC_NUM 2
+
+struct roce3_bond_slave {
+ struct net_device *netdev;
+ struct hinic3_lld_dev *lld_dev;
+ struct hinic3_lld_dev *ppf_dev;
+ struct netdev_lag_lower_state_info netdev_state;
+ u32 update_cnt;
+ u16 func_id;
+ u8 er_id;
+ bool is_ppf;
+};
+
+typedef void (*roce3_bond_service_func)(const char *bond_name, struct bond_attr *attr);
+
+struct roce3_bond_device {
+ char name[IFNAMSIZ];
+ struct list_head entry;
+ struct roce3_bond_slave slaves[ROCE_BOND_MAX_FUNCS];
+ struct mutex slave_lock;
+ u32 slave_cnt;
+ atomic_t next_port;
+ struct work_struct detach_work;
+ struct roce3_device *attached_rdev;
+ struct bond_attr attr;
+};
+
+bool roce3_bond_is_active(struct roce3_device *rdev);
+struct net_device *roce3_bond_get_netdev(struct roce3_device *rdev);
+
+int roce3_add_bond_real_slave_mac(struct roce3_device *rdev, u8 *mac);
+int roce3_add_bond_vlan_slave_mac(struct roce3_device *rdev, u8 *mac, u16 vlan_id);
+void roce3_del_bond_real_slave_mac(struct roce3_device *rdev);
+void roce3_del_bond_vlan_slave_mac(struct roce3_device *rdev, u8 *mac, u16 vlan_id);
+
+int roce3_bond_is_eth_port_of_netdev(struct roce3_device *rdev,
+ struct net_device *event_ndev);
+
+void roce3_bond_rr_set_flow(struct roce3_device *rdev,
+ struct roce3_qp *rqp, struct tag_roce_verbs_qp_attr *qp_attr);
+
+int roce3_bond_event_cfg_rdev(struct hinic3_lld_dev *lld_dev,
+ void *uld_dev, struct roce3_device **rdev);
+int roce3_bonded_port_event_report(struct roce3_device *rdev,
+ const struct hinic3_event_info *event);
+void roce3_handle_bonded_port_state_event(struct roce3_device *rdev);
+
+bool roce3_get_bond_ipsurx_en(void);
+void roce3_set_bond_ipsurx_en(bool ipsurx_en);
+
+int roce3_bond_attach(struct roce3_device *rdev);
+int roce3_bond_init(void);
+void roce3_bond_pre_exit(void);
+void roce3_bond_exit(void);
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/bond/roce_bond_common.c b/drivers/infiniband/hw/hiroce3/bond/roce_bond_common.c
new file mode 100644
index 0000000000000..8b9db6ca92d78
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/bond/roce_bond_common.c
@@ -0,0 +1,938 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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 "bond_common_defs.h"
+
+#include "hinic3_hw.h"
+#include "hinic3_srv_nic.h"
+
+#include "roce_bond.h"
+#include "roce_cmd.h"
+#include "roce_netdev.h"
+
+static bool g_roce3_bond_ipsurx_en = true;
+
+static LIST_HEAD(g_roce3_bond_list);
+static DEFINE_MUTEX(g_roce3_bond_mutex);
+
+static struct workqueue_struct *g_bond_wq;
+
+struct roce3_detach_work {
+ u16 bond_id;
+ struct work_struct work;
+};
+
+struct roce3_bond_work {
+ char name[IFNAMSIZ];
+ struct work_struct work;
+};
+
+bool roce3_get_bond_ipsurx_en(void)
+{
+ return g_roce3_bond_ipsurx_en;
+}
+
+void roce3_set_bond_ipsurx_en(bool ipsurx_en)
+{
+ g_roce3_bond_ipsurx_en = ipsurx_en;
+}
+
+static enum netdev_lag_tx_type roce3_get_tx_type_by_bond_mode(u16 bond_mode)
+{
+ switch (bond_mode) {
+ case BOND_MODE_8023AD:
+ case BOND_MODE_XOR:
+ return NETDEV_LAG_TX_TYPE_HASH;
+ case BOND_MODE_ACTIVEBACKUP:
+ return NETDEV_LAG_TX_TYPE_ACTIVEBACKUP;
+ default:
+ return NETDEV_LAG_TX_TYPE_UNKNOWN;
+ }
+}
+
+static bool roce3_bond_mode_is_supported(u16 bond_mode)
+{
+ enum netdev_lag_tx_type tx_type = roce3_get_tx_type_by_bond_mode(bond_mode);
+
+ if ((tx_type != NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) && (tx_type != NETDEV_LAG_TX_TYPE_HASH)) {
+ pr_err("[ROCE, ERR] %s: Failed to support bond mode(%d)\n", __func__, tx_type);
+ return false;
+ }
+ return true;
+}
+
+static bool is_hinic3_netdev(struct net_device *netdev)
+{
+ return (hinic3_get_lld_dev_by_netdev(netdev) != NULL);
+}
+
+static bool roce3_can_do_bond(struct bonding *bond)
+{
+ bool ret = false;
+ int slave_cnt = 0;
+ struct slave *slave = NULL;
+ struct list_head *iter = NULL;
+ struct hinic3_lld_dev *lld_dev = NULL;
+ struct hinic3_lld_dev *ppf_dev = NULL;
+
+ if (!bond || !roce3_bond_mode_is_supported(bond->params.mode))
+ return ret;
+
+ rcu_read_lock();
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ lld_dev = hinic3_get_lld_dev_by_netdev(slave->dev);
+ if (!lld_dev)
+ goto out;
+
+ if (!hinic3_support_roce(lld_dev->hwdev, NULL))
+ goto out;
+
+ if (!ppf_dev) {
+ ppf_dev = hinic3_get_ppf_lld_dev(lld_dev);
+ if (!ppf_dev)
+ goto out;
+ }
+
+ if (hinic3_get_ppf_lld_dev(lld_dev) != ppf_dev)
+ goto out;
+
+ slave_cnt++;
+ pr_info("%s:can do bond? slave_cnt(%d), slave_name(%s)",
+ __func__, slave_cnt, slave->dev->name);
+ }
+
+ ret = (slave_cnt == ROCE_BOND_2_FUNC_NUM);
+out:
+ rcu_read_unlock();
+ return ret;
+}
+
+struct net_device *roce3_bond_get_netdev(struct roce3_device *rdev)
+{
+ int i;
+ struct roce3_bond_device *bond_dev = rdev->bond_dev;
+ struct net_device *ret_dev = NULL;
+ struct slave *slave = NULL;
+
+ mutex_lock(&g_roce3_bond_mutex);
+ if (!bond_dev) {
+ mutex_unlock(&g_roce3_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)
+ 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_roce3_bond_mutex);
+ return ret_dev;
+ }
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+ mutex_unlock(&g_roce3_bond_mutex);
+ return ret_dev;
+}
+
+void roce3_bond_rr_set_flow(struct roce3_device *rdev, struct roce3_qp *rqp,
+ struct tag_roce_verbs_qp_attr *qp_attr)
+{
+ u32 bond_tx_hash;
+ struct roce3_bond_device *bond_dev = rdev->bond_dev;
+
+ if (!bond_dev)
+ return;
+
+ bond_tx_hash = (u32)atomic_add_return(1, &bond_dev->next_port);
+ rqp->tx_hash_value = bond_tx_hash;
+
+ qp_attr->path_info.dw0.bs.bond_tx_hash_value = (u16)bond_tx_hash;
+}
+
+static int roce3_bond_modify_mac_tbl_for_sdi(struct roce3_device *rdev, u8 *mac,
+ roce3_modify_mac_tbl modify_mac_tbl)
+{
+ u16 func_id;
+ int ret;
+
+ for (func_id = 0; func_id < SDI_BOND_SLAVES_FUNC_NUM; func_id++) {
+ if (func_id == rdev->glb_func_id)
+ continue;
+
+ ret = modify_mac_tbl(rdev->hwdev, mac, ROCE_BOND_RSVD_VLAN_ID,
+ rdev->glb_func_id, func_id);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to modify mac table, ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int roce3_add_bond_real_slave_mac(struct roce3_device *rdev, u8 *mac)
+{
+ struct roce3_bond_device *bond_dev = rdev->bond_dev;
+ struct roce3_bond_slave *slave = NULL;
+ int ret;
+ int i;
+
+ if (!bond_dev) {
+ pr_err("[ROCE, ERR] %s: Failed to find bond_dev\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ slave = &bond_dev->slaves[i];
+ ret = roce3_add_mac_tbl_mac_entry(rdev->hwdev, mac, ROCE_BOND_RSVD_VLAN_ID,
+ rdev->glb_func_id, slave->func_id);
+ if (ret != 0) {
+ mutex_unlock(&bond_dev->slave_lock);
+ pr_err("[ROCE, ERR] %s: Failed to add mac_vlan entry, ret(%d)\n",
+ __func__, 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.
+ */
+ (void)roce3_add_ipsu_tbl_mac_entry(rdev->hwdev, mac, 0,
+ rdev->glb_func_id, slave->er_id);
+ }
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+
+ if (rdev->sdi_bond_name != NULL) {
+ ret = roce3_bond_modify_mac_tbl_for_sdi(rdev, mac, roce3_add_mac_tbl_mac_entry);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to modify mac table of sdi, ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int roce3_add_bond_vlan_slave_mac(struct roce3_device *rdev, u8 *mac, u16 vlan_id)
+{
+ struct roce3_bond_device *bond_dev = rdev->bond_dev;
+ struct roce3_bond_slave *slave = NULL;
+ int ret;
+ int i;
+
+ if (!bond_dev) {
+ pr_err("[ROCE, ERR] %s: Failed to find bond_dev\n", __func__);
+ 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 = roce3_add_mac_tbl_mac_entry(rdev->hwdev, mac, vlan_id,
+ slave->func_id, slave->func_id);
+ if (ret != 0) {
+ mutex_unlock(&bond_dev->slave_lock);
+ pr_err("[ROCE, ERR] %s: Failed to add mac_vlan entry, ret(%d)\n",
+ __func__, 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.
+ */
+ (void)roce3_add_ipsu_tbl_mac_entry(rdev->hwdev, mac, vlan_id,
+ rdev->glb_func_id, slave->er_id);
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+
+ return 0;
+}
+
+void roce3_del_bond_real_slave_mac(struct roce3_device *rdev)
+{
+ int i;
+ struct roce3_bond_slave *slave = NULL;
+ struct roce3_bond_device *bond_dev = rdev->bond_dev;
+
+ if (!bond_dev)
+ 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) {
+ (void)roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, rdev->mac, 0,
+ rdev->glb_func_id, slave->er_id);
+ }
+
+ (void)roce3_del_mac_tbl_mac_entry(rdev->hwdev, rdev->mac, ROCE_BOND_RSVD_VLAN_ID,
+ rdev->glb_func_id, slave->func_id);
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+
+ if (rdev->sdi_bond_name != NULL) {
+ (void)roce3_bond_modify_mac_tbl_for_sdi(rdev, rdev->mac,
+ roce3_del_mac_tbl_mac_entry);
+ }
+}
+
+void roce3_del_bond_vlan_slave_mac(struct roce3_device *rdev, u8 *mac, u16 vlan_id)
+{
+ int i;
+ struct roce3_bond_slave *slave = NULL;
+ struct roce3_bond_device *bond_dev = rdev->bond_dev;
+
+ if (!bond_dev)
+ 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;
+
+ roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, mac, vlan_id,
+ slave->func_id, slave->er_id);
+
+ (void)roce3_del_mac_tbl_mac_entry(rdev->hwdev, mac, vlan_id,
+ rdev->glb_func_id, slave->er_id);
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+}
+
+bool roce3_bond_is_active(struct roce3_device *rdev)
+{
+ return (rdev->bond_dev != NULL);
+}
+
+int roce3_bond_event_cfg_rdev(struct hinic3_lld_dev *lld_dev, void *uld_dev,
+ struct roce3_device **rdev)
+{
+ int i;
+ struct roce3_bond_device *bond_dev = NULL;
+
+ if (lld_dev == NULL) {
+ pr_err("[ROCE, ERR] %s: Lld_dev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (uld_dev != NULL) {
+ *rdev = (struct roce3_device *)uld_dev;
+ return 0;
+ }
+
+ mutex_lock(&g_roce3_bond_mutex);
+ list_for_each_entry(bond_dev, &g_roce3_bond_list, entry) {
+ 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;
+ mutex_unlock(&bond_dev->slave_lock);
+ goto out;
+ }
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+ }
+
+out:
+ mutex_unlock(&g_roce3_bond_mutex);
+ return *rdev ? 0 : -EINVAL;
+}
+
+int roce3_bonded_port_event_report(struct roce3_device *rdev, const struct hinic3_event_info *event)
+{
+ u32 type = HINIC3_SRV_EVENT_TYPE(event->service, event->type);
+
+ if ((type != HINIC3_SRV_EVENT_TYPE(EVENT_SRV_NIC, EVENT_NIC_LINK_UP)) &&
+ (type != HINIC3_SRV_EVENT_TYPE(EVENT_SRV_NIC, EVENT_NIC_LINK_DOWN))) {
+ pr_err("[ROCE] %s: event_service(%d), type(%d)\n",
+ __func__, event->service, event->type);
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+int roce3_bond_is_eth_port_of_netdev(struct roce3_device *rdev, struct net_device *event_ndev)
+{
+ struct roce3_bond_device *bond_dev = rdev->bond_dev;
+ struct net_device *tmp_ndev = NULL;
+ int ret;
+ int i;
+ /* judge current net device */
+ tmp_ndev = rdev->ndev;
+ ret = roce3_is_eth_port_of_netdev(tmp_ndev, event_ndev);
+ if (ret != 0)
+ return 1;
+
+ if (!bond_dev)
+ return 0;
+
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ if (roce3_is_eth_port_of_netdev(bond_dev->slaves[i].netdev, event_ndev)) {
+ mutex_unlock(&bond_dev->slave_lock);
+ return 1;
+ }
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+
+ return 0;
+}
+
+struct roce3_bond_device *roce3_get_bond_dev(const char *bond_name)
+{
+ struct roce3_bond_device *bdev = NULL;
+
+ list_for_each_entry(bdev, &g_roce3_bond_list, entry) {
+ if (!strcmp(bdev->name, bond_name))
+ return bdev;
+ }
+
+ return NULL;
+}
+
+struct roce3_bond_device *roce3_get_bond_dev_by_name(const char *bond_name)
+{
+ struct roce3_bond_device *bdev = NULL;
+
+ mutex_lock(&g_roce3_bond_mutex);
+ bdev = roce3_get_bond_dev(bond_name);
+ mutex_unlock(&g_roce3_bond_mutex);
+ return bdev;
+}
+
+void roce3_bond_init_slave(struct roce3_bond_slave *slave, struct bond_tracker *tracker, int index,
+ struct bond_attr *attr)
+{
+ void *hwdev;
+
+ slave->func_id = index;
+ slave->netdev = tracker->ndev[index];
+
+ dev_hold(slave->netdev);
+ pr_info("[ROCE, INFO] %s: dev_hold: name(%s),tracker_cnt(%d)\n",
+ __func__, slave->netdev->name, tracker->cnt);
+ slave->lld_dev = hinic3_get_lld_dev_by_netdev(slave->netdev);
+ slave->ppf_dev = hinic3_get_ppf_lld_dev(slave->lld_dev);
+ hwdev = slave->lld_dev->hwdev;
+ slave->is_ppf = hinic3_func_type(hwdev) == TYPE_PPF;
+ slave->er_id = hinic3_er_id(hwdev);
+ slave->netdev_state.link_up = tracker->netdev_state[index].link_up;
+ slave->netdev_state.tx_enabled = tracker->netdev_state[index].tx_enabled;
+
+ if (slave->is_ppf)
+ attr->first_roce_func = slave->func_id;
+ else
+ hinic3_detach_service(slave->lld_dev, SERVICE_T_ROCE);
+}
+
+bool roce3_bond_before_active_check(struct bond_tracker *tracker, struct bond_attr *attr)
+{
+ int i;
+ struct hinic3_lld_dev *lld_dev = NULL;
+ struct hinic3_lld_dev *ppf_dev = NULL;
+
+ if (!roce3_bond_mode_is_supported(attr->bond_mode))
+ return false;
+
+ for (i = 0; i < ROCE_BOND_2_FUNC_NUM; i++) {
+ lld_dev = hinic3_get_lld_dev_by_netdev(tracker->ndev[i]);
+ if (!lld_dev) {
+ pr_err("[ROCE, ERR] %s: get lld dev err\n", __func__);
+ return false;
+ }
+
+ if (!hinic3_support_roce(lld_dev->hwdev, NULL)) {
+ pr_err("[ROCE, ERR] %s: Not support roce\n", __func__);
+ return false;
+ }
+
+ if (!ppf_dev) {
+ ppf_dev = hinic3_get_ppf_lld_dev(lld_dev);
+ if (!ppf_dev) {
+ pr_err("[ROCE, ERR] %s: get ppf dev err\n", __func__);
+ return false;
+ }
+ }
+
+ if (hinic3_get_ppf_lld_dev(lld_dev) != ppf_dev)
+ return false;
+ }
+
+ return true;
+}
+
+void roce3_detach_nic_bond_work(struct work_struct *work)
+{
+ struct roce3_detach_work *detach_work = container_of(work, struct roce3_detach_work, work);
+
+ hinic3_bond_detach(detach_work->bond_id, HINIC3_BOND_USER_ROCE);
+
+ kfree(detach_work);
+}
+
+static void roce3_attach_bond_work(struct work_struct *_work)
+{
+ u16 bond_id;
+ struct roce3_bond_work *work = container_of(_work, struct roce3_bond_work, work);
+
+ pr_info("roce_attach: %s: work_name(%s)\n", __func__, work->name);
+ hinic3_bond_attach(work->name, HINIC3_BOND_USER_ROCE, &bond_id);
+
+ kfree(work);
+}
+void roce3_deatch_bond(u16 bond_id)
+{
+ struct roce3_detach_work *detach_work = NULL;
+
+ detach_work = kmalloc(sizeof(*detach_work), GFP_KERNEL);
+ if (!detach_work)
+ return;
+
+ detach_work->bond_id = bond_id;
+ INIT_WORK(&detach_work->work, roce3_detach_nic_bond_work);
+ queue_work(g_bond_wq, &detach_work->work);
+}
+
+bool roce3_bond_tracker_get(const char *bond_name, struct bond_tracker *tracker)
+{
+ int ret = 0;
+
+ ret = hinic3_get_bond_tracker_by_name(bond_name, tracker);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: get bond tracker failed name(%s), ret(%d)\n",
+ __func__, bond_name, ret);
+ return false;
+ }
+ if (!tracker->is_bonded) {
+ pr_err("[ROCE, ERR] %s: tracker is NOT bond (%s)\n", __func__, bond_name);
+ return false;
+ }
+ if (tracker->cnt == ROCE_BOND_2_FUNC_NUM)
+ return true;
+
+ pr_err("[ROCE, ERR] %s: get tracker cnt fail, cnt(%d) name(%s)\n",
+ __func__, tracker->cnt, bond_name);
+ return false;
+}
+
+void roce3_before_bond_active(const char *bond_name, struct bond_attr *attr)
+{
+ struct roce3_bond_device *bond_dev = NULL;
+ struct roce3_bond_slave *slave = NULL;
+ struct bond_tracker tracker;
+ int i;
+
+ if (!roce3_bond_tracker_get(bond_name, &tracker)) {
+ pr_err("[ROCE, ERR] %s: get bond tracker failed\n", __func__);
+ goto err;
+ }
+
+ if (!roce3_bond_before_active_check(&tracker, attr)) {
+ pr_err("[ROCE, ERR] %s: active check failed\n", __func__);
+ goto err;
+ }
+
+ bond_dev = roce3_get_bond_dev_by_name(bond_name);
+ if (bond_dev) {
+ pr_info("[ROCE, INFO] %s: Find exist bond device\n", __func__);
+ return;
+ }
+
+ bond_dev = kzalloc(sizeof(*bond_dev), GFP_KERNEL);
+ if (!bond_dev)
+ goto err;
+
+ strscpy(bond_dev->name, bond_name, sizeof(bond_dev->name));
+
+ bond_dev->attr = *attr;
+ bond_dev->slave_cnt = tracker.cnt;
+ mutex_init(&bond_dev->slave_lock);
+
+ for (i = 0; i < ROCE_BOND_2_FUNC_NUM; i++) {
+ slave = &bond_dev->slaves[i];
+ roce3_bond_init_slave(slave, &tracker, i, attr);
+ }
+
+ hinic3_detach_service(bond_dev->slaves[0].ppf_dev, SERVICE_T_ROCE);
+ mutex_lock(&g_roce3_bond_mutex);
+ list_add_tail(&bond_dev->entry, &g_roce3_bond_list);
+ mutex_unlock(&g_roce3_bond_mutex);
+ return;
+err:
+ roce3_deatch_bond(attr->bond_id);
+}
+
+void roce3_after_bond_active(const char *bond_name, struct bond_attr *attr)
+{
+ int ret;
+ struct roce3_bond_device *bond_dev = NULL;
+
+ bond_dev = roce3_get_bond_dev_by_name(bond_name);
+ if (!bond_dev) {
+ pr_err("[ROCE, ERR] %s: not find bond device by name(%s)\n", __func__, bond_name);
+ return;
+ }
+
+ ret = hinic3_attach_service(bond_dev->slaves[0].ppf_dev, SERVICE_T_ROCE);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to attach roce device, ret(%d), bond name(%s)\n",
+ __func__, ret, bond_name);
+ }
+}
+
+void roce3_after_bond_modify(const char *bond_name, struct bond_attr *attr)
+{
+ struct roce3_bond_device *bond_dev = NULL;
+ struct bond_tracker tracker;
+ int i;
+ int j;
+
+ bond_dev = roce3_get_bond_dev_by_name(bond_name);
+ if (!bond_dev) {
+ pr_err("[ROCE, ERR] %s: not find bond device by name(%s)\n", __func__, bond_name);
+ return;
+ }
+
+ if (hinic3_get_bond_tracker_by_name(bond_name, &tracker) != 0) {
+ pr_err("[ROCE, ERR] %s: get bond tracker failed\n", __func__);
+ return;
+ }
+
+ bond_dev->attr = *attr;
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < BOND_PORT_MAX_NUM; i++) {
+ for (j = 0; j < bond_dev->slave_cnt; j++) {
+ if (bond_dev->slaves[j].netdev != tracker.ndev[i])
+ continue;
+
+ bond_dev->slaves[j].netdev_state.link_up = tracker.netdev_state[i].link_up;
+ bond_dev->slaves[j].netdev_state.tx_enabled =
+ tracker.netdev_state[i].tx_enabled;
+ break;
+ }
+ }
+ mutex_unlock(&bond_dev->slave_lock);
+}
+
+void roce3_before_bond_deactive(const char *bond_name, struct bond_attr *attr)
+{
+}
+
+void roce3_after_bond_deactive(const char *bond_name, struct bond_attr *attr)
+{
+}
+
+void roce3_bond_destroy(const char *bond_name)
+{
+ int ret;
+ int i;
+ struct roce3_bond_device *bond_dev = NULL;
+
+ mutex_lock(&g_roce3_bond_mutex);
+ bond_dev = roce3_get_bond_dev(bond_name);
+ if (bond_dev)
+ list_del(&bond_dev->entry);
+
+ if (!bond_dev) {
+ pr_err("[ROCE, ERR] %s: not find bond device by name(%s)\n", __func__, bond_name);
+ mutex_unlock(&g_roce3_bond_mutex);
+ return;
+ }
+ if (bond_dev->attached_rdev != NULL)
+ bond_dev->attached_rdev->bond_dev = NULL;
+
+ mutex_unlock(&g_roce3_bond_mutex);
+
+ hinic3_detach_service(bond_dev->slaves[0].ppf_dev, SERVICE_T_ROCE);
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ ret = hinic3_attach_service(bond_dev->slaves[i].lld_dev, SERVICE_T_ROCE);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to attach roce device, ret(%d)\n",
+ __func__, ret);
+ }
+ dev_put(bond_dev->slaves[i].netdev);
+ pr_info("[ROCE, INFO] %s: dev_put: name(%s),slave_cnt(%d), slave_name(%s)\n",
+ __func__, bond_name, bond_dev->slave_cnt, bond_dev->slaves[i].netdev->name);
+ }
+ bond_dev->slave_cnt = 0;
+ mutex_unlock(&bond_dev->slave_lock);
+
+ hinic3_bond_detach(bond_dev->attr.bond_id, HINIC3_BOND_USER_ROCE);
+ kfree(bond_dev);
+}
+
+void roce3_before_bond_modify(const char *bond_name, struct bond_attr *attr)
+{
+ struct roce3_bond_device *bond_dev = NULL;
+ struct bond_tracker tracker;
+ int i;
+
+ bond_dev = roce3_get_bond_dev_by_name(bond_name);
+ if (!bond_dev) {
+ pr_err("[ROCE, ERR] %s: not find bond device by name(%s)\n", __func__, bond_name);
+ return;
+ }
+
+ if (hinic3_get_bond_tracker_by_name(bond_name, &tracker) != 0) {
+ pr_err("[ROCE, ERR] %s: get bond tracker failed\n", __func__);
+ return;
+ }
+
+ if (tracker.cnt == bond_dev->slave_cnt) {
+ bond_dev->attr = *attr;
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ if (bond_dev->slaves[i].is_ppf) {
+ attr->first_roce_func = bond_dev->slaves[i].func_id;
+ break;
+ }
+ }
+ return;
+ }
+
+ if (tracker.cnt > bond_dev->slave_cnt) {
+ pr_err("[ROCE, ERR] %s: Add slave is not support, bond name(%s)\n",
+ __func__, bond_name);
+ return;
+ }
+
+ if (tracker.cnt < ROCE_BOND_2_FUNC_NUM) {
+ roce3_bond_destroy(bond_dev->name);
+ return;
+ }
+}
+
+static roce3_bond_service_func g_roce3_bond_proc[] = {
+ roce3_before_bond_active,
+ roce3_after_bond_active,
+ roce3_before_bond_modify,
+ roce3_after_bond_modify,
+ roce3_before_bond_deactive,
+ roce3_after_bond_deactive,
+};
+
+void roce3_bond_service_proc(const char *bond_name, void *bond_attr, enum bond_service_proc_pos pos)
+{
+ struct bond_attr *attr = (struct bond_attr *)bond_attr;
+
+ if (bond_name == NULL) {
+ pr_err("[ROCE, ERR] %s: Bond_name is NULL\n", __func__);
+ return;
+ }
+
+ if (pos >= BOND_POS_MAX) {
+ pr_err("[ROCE, ERR] %s: The pos is out of the range of proc_func\n", __func__);
+ return;
+ }
+
+ if (g_roce3_bond_proc[pos] != NULL)
+ g_roce3_bond_proc[pos](bond_name, attr);
+}
+
+int roce3_bond_attach(struct roce3_device *rdev)
+{
+ int i;
+ int ret = 0;
+ struct roce3_bond_device *bond_dev;
+
+ mutex_lock(&g_roce3_bond_mutex);
+ list_for_each_entry(bond_dev, &g_roce3_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_roce3_bond_mutex);
+ return ret;
+}
+
+static void roce3_detach_bond_work(struct work_struct *_work)
+{
+ struct roce3_bond_work *work = container_of(_work, struct roce3_bond_work, work);
+
+ roce3_bond_destroy(work->name);
+
+ kfree(work);
+}
+
+void roce3_queue_bond_work(struct net_device *upper_netdev, work_func_t func)
+{
+ struct roce3_bond_work *work;
+ struct bonding *bond = netdev_priv(upper_netdev);
+
+ if (!bond) {
+ pr_info("%s: (name:%s) has no bond dev.\n", __func__, upper_netdev->name);
+ return;
+ }
+
+ work = kzalloc(sizeof(*work), GFP_KERNEL);
+ if (!work)
+ return;
+
+ strscpy(work->name, upper_netdev->name, sizeof(work->name));
+ INIT_WORK(&work->work, func);
+ queue_work(g_bond_wq, &work->work);
+}
+
+int roce3_bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *net_dev = NULL;
+ struct netdev_notifier_changeupper_info *info = NULL;
+ struct net_device *upper_netdev = NULL;
+
+ info = (struct netdev_notifier_changeupper_info *)ptr;
+ net_dev = netdev_notifier_info_to_dev(ptr);
+ if (net_eq(dev_net(net_dev), &init_net) == 0)
+ return NOTIFY_DONE;
+
+ if (event != NETDEV_CHANGEUPPER)
+ return NOTIFY_DONE;
+
+ if (!is_hinic3_netdev(net_dev))
+ return NOTIFY_DONE;
+
+ upper_netdev = info->upper_dev;
+ if (upper_netdev == NULL)
+ return NOTIFY_DONE;
+
+ if (!netif_is_lag_master(upper_netdev))
+ return NOTIFY_DONE;
+
+ if (!roce3_can_do_bond(netdev_priv(upper_netdev))) {
+ roce3_queue_bond_work(upper_netdev, roce3_detach_bond_work);
+ return NOTIFY_DONE;
+ }
+
+ roce3_queue_bond_work(upper_netdev, roce3_attach_bond_work);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block nb_netdevice = {
+ .notifier_call = roce3_bond_netdev_event
+};
+
+int roce3_bond_init(void)
+{
+ int ret;
+ struct net_device *upper_netdev;
+
+ g_bond_wq = alloc_ordered_workqueue("roce3-bond-wq", 0);
+ if (!g_bond_wq) {
+ pr_err("[ROCE, ERR] %s: Failed to alloc workqueue\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = register_netdevice_notifier(&nb_netdevice);
+ if (ret) {
+ pr_err("[ROCE, ERR] %s: Failed to register netdevice notifier(%d)\n",
+ __func__, ret);
+ goto nb_err;
+ }
+
+ ret = hinic3_bond_register_service_func(HINIC3_BOND_USER_ROCE, roce3_bond_service_proc);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to register bond(%d)\n", __func__, ret);
+ goto err;
+ }
+
+ rtnl_lock();
+ for_each_netdev(&init_net, upper_netdev) {
+ if (netif_is_bond_master(upper_netdev) &&
+ roce3_can_do_bond(netdev_priv(upper_netdev))) {
+ roce3_queue_bond_work(upper_netdev, roce3_attach_bond_work);
+ }
+ }
+ rtnl_unlock();
+
+ return 0;
+err:
+ unregister_netdevice_notifier(&nb_netdevice);
+nb_err:
+ destroy_workqueue(g_bond_wq);
+ return ret;
+}
+
+void roce3_bond_pre_exit(void)
+{
+ int ret;
+
+ ret = hinic3_bond_unregister_service_func(HINIC3_BOND_USER_ROCE);
+ if (ret != 0)
+ pr_err("[ROCE, ERR] %s: Failed to unregister service func(%d)\n", __func__, ret);
+
+ unregister_netdevice_notifier(&nb_netdevice);
+ destroy_workqueue(g_bond_wq);
+}
+
+void roce3_bond_exit(void)
+{
+ struct roce3_bond_device *bond_dev = NULL;
+ int i;
+
+ while (!list_empty(&g_roce3_bond_list)) {
+ bond_dev = list_first_entry(&g_roce3_bond_list, struct roce3_bond_device, entry);
+ list_del(&bond_dev->entry);
+ for (i = 0; i < bond_dev->slave_cnt; i++) {
+ pr_info("[ROCE, INFO] %s: EXIT dev_put: bond_name(%s),slave_cnt(%d), slave_name(%s)\n",
+ __func__, bond_dev->name, bond_dev->slave_cnt,
+ bond_dev->slaves[i].netdev->name);
+ dev_put(bond_dev->slaves[i].netdev);
+ }
+ hinic3_bond_detach(bond_dev->attr.bond_id, HINIC3_BOND_USER_ROCE);
+ kfree(bond_dev);
+ }
+}
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/cq/roce_cq.h b/drivers/infiniband/hw/hiroce3/cq/roce_cq.h
new file mode 100644
index 0000000000000..63909fac073c0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/cq/roce_cq.h
@@ -0,0 +1,250 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_CQ_H
+#define ROCE_CQ_H
+
+#include <rdma/ib_verbs.h>
+#include <linux/slab.h>
+
+#include "hinic3_hw.h"
+#include "hinic3_rdma.h"
+
+#include "rdma_context_format.h"
+
+#include "roce.h"
+#include "roce_compat.h"
+#include "roce_srq.h"
+#include "roce_xrc.h"
+#include "roce_user.h"
+#include "hinic3_hmm.h"
+
+#define ROCE_CQN_INVLD 0xFFFFFFFF
+
+/* DB type of ARM_CQ */
+enum {
+ ROCE_CQ_DB_REQ_NOT_SOL = 1,
+ ROCE_CQ_DB_REQ_NOT = 2
+};
+
+#define CQ_GPA_SIG_LEN 3
+#define CQ_DW_TO_BYTE 4
+
+/* the type of err cqe
+ * IB compliant completion with error syndrome:
+ * 0x01 - Local Length Error ()
+ * 0x02 - Local QP Operation Error
+ * 0x04 - Local Protection Error
+ * 0x05 - Work Request Flushed Error
+ * 0x06 - Memory Window Bind Error
+ * 0x10 - Bad Response Error
+ * 0x11 - Local Access Error
+ * 0x12 - Remote Invalid Request Error
+ * 0x13 - Remote Access Error
+ * 0x14 - Remote Operation Error
+ * 0x15 - Transport Retry Counter Exceeded
+ * 0x16 - RNR Retry Counter Exceeded
+ * 0x22 - Remote Aborted Error
+ * other - reserved
+ * Syndrome is defined according to the InfiniBand Architecture Specification,
+ * Volume 1. For a detailed explanation of the syndromes, refer to the Software
+ * Transport Interface and Software Transport Verbs chapters of the IB specifica-tion.
+ */
+enum roce3_cqe_syndrome {
+ ROCE_CQE_SYNDROME_LOCAL_LENGTH_ERR = 0x01,
+ ROCE_CQE_SYNDROME_LOCAL_QP_OP_ERR = 0x02,
+ ROCE_CQE_SYNDROME_LOCAL_PROT_ERR = 0x04,
+ ROCE_CQE_SYNDROME_WR_FLUSH_ERR = 0x05,
+
+ ROCE_CQE_SYNDROME_MW_BIND_ERR = 0x06,
+ ROCE_CQE_SYNDROME_BAD_RESP_ERR = 0x10,
+
+ ROCE_CQE_SYNDROME_LOCAL_ACCESS_ERR = 0x11,
+ ROCE_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12,
+ ROCE_CQE_SYNDROME_REMOTE_ACCESS_ERR = 0x13,
+ ROCE_CQE_SYNDROME_REMOTE_OP_ERR = 0x14,
+ ROCE_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR = 0x15,
+
+ ROCE_CQE_SYNDROME_RNR_RETRY_EXC_ERR = 0x16,
+
+ ROCE_CQE_SYNDROME_REMOTE_ABORTED_ERR = 0x22,
+ ROCE_CQE_SYNDROME_MAX = 0x23
+};
+
+/*
+ * 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 roce3_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 roce3_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 roce3_cq_query_outbuf {
+ struct roce_cq_context cqc;
+};
+
+struct roce3_cq_buf {
+ struct tag_cqm_buf *buf; /* pointer to describe the buf structure b cqm */
+ /* the mtt struct used by kernel mode and user mode to discribe buf */
+ struct rdma_mtt mtt;
+ int entry_size; /* the size of cqe */
+ int buf_size; /* the size of cq_buf */
+};
+
+struct roce3_cq_resize_buf {
+ struct roce3_cq_buf buf; /* the size of buf that was resized */
+ int cqe; /* the number of resized cqe */
+};
+
+struct roce3_cq {
+ struct ib_cq ibcq;
+ struct tag_cqm_queue *cqm_cq; /* Save the handle obtained from cqm */
+ /* The address information of the software DB that stores the CI user mode/kernel mode */
+ struct roce3_db db;
+ __be32 *set_ci_db; /* Kernel-mode software DB */
+ u32 cons_index; /* consumer pointer */
+
+ u32 arm_sn; /* the serial number of arm */
+ /* Used to determine whether the arm command has been sent, to avoid repeated sending */
+ int arm_flag;
+ u32 cqn;
+ unsigned int vector; /* associated to the eq used */
+ struct roce3_cq_buf buf; /* pointer describing the buf structure of cqm */
+ struct roce3_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 information mapped by User-mode buf */
+ /* record the information mapped by buf which the User-mode resized */
+ struct ib_umem *resize_umem;
+
+ 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;
+
+ void (*reset_flow_comp)(struct roce3_cq *cq);
+};
+
+/* cross ibcroce3_e_cq */
+static inline struct roce3_cq *to_roce3_cq(const struct ib_cq *ibcq)
+{
+ return container_of(ibcq, struct roce3_cq, ibcq);
+}
+
+/* obroce3_roce_cq crossing cqm */
+static inline struct roce3_cq *cqmobj_to_roce3_cq(const struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *cqm_cq;
+
+ cqm_cq = container_of(object, struct tag_cqm_queue, object);
+ return (struct roce3_cq *)cqm_cq->priv;
+}
+
+/* Used when destroy QP */
+void roce3_cq_clean(struct roce3_cq *cq, u32 qpn, struct roce3_srq *srq);
+void roce3_cq_async_event(struct roce3_device *rdev, struct roce3_cq *cq, int type);
+void roce3_cq_clean_process(struct roce3_cq *cq, u32 qpn, struct roce3_srq *srq);
+void roce3_cq_put_umem(struct roce3_device *rdev, struct roce3_cq_buf *buf, struct ib_umem **umem);
+
+int roce3_cq_get_umem(struct roce3_device *rdev, struct ib_udata *udata, struct roce3_cq_buf *buf,
+ struct ib_umem **umem, u64 buf_addr, int cqe);
+int roce3_create_cq_common(struct ib_device *ibdev, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata, struct roce3_cq *rcq, u32 index);
+
+void *roce3_get_sw_cqe(struct roce3_cq *cq, unsigned int n);
+void *roce3_get_cqe_from_buf(struct roce3_cq_buf *buf, unsigned int n);
+void roce3_cq_set_ci(struct roce3_cq *cq);
+void roce3_cq_buf_init(struct roce3_cq_buf *buf);
+void *roce3_get_cqe(struct roce3_cq *cq, unsigned int n);
+void roce_reset_flow_comp(struct roce3_cq *rcq);
+
+void roce3_lock_cqs(struct roce3_cq *roce3_send_cq, struct roce3_cq *roce3_recv_cq)
+ __acquires(&roce3_send_cq->lock) __acquires(&roce3_recv_cq->lock);
+void roce3_unlock_cqs(struct roce3_cq *roce3_send_cq, struct roce3_cq *roce3_recv_cq)
+ __releases(&roce3_send_cq->lock) __releases(&roce3_recv_cq->lock);
+
+#endif // ROCE_CQ_H
diff --git a/drivers/infiniband/hw/hiroce3/cq/roce_cq_common.c b/drivers/infiniband/hw/hiroce3/cq/roce_cq_common.c
new file mode 100644
index 0000000000000..ece655612d45a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/cq/roce_cq_common.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/slab.h>
+
+#include "hinic3_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_pub_cmd.h"
+#include "hinic3_hmm.h"
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_async_event
+ Description : roce3_cq_async_event
+ Input : struct roce3_device *rdev
+ struct roce3_cq *cq
+ int type
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_cq_async_event(struct roce3_device *rdev, struct roce3_cq *cq, int type)
+{
+ struct ib_cq *ibcq = &cq->ibcq;
+ struct ib_event event;
+
+ memset(&event, 0, sizeof(event));
+ if (type != ROCE_EVENT_TYPE_CQ_ERROR) {
+ dev_warn_ratelimited(rdev->hwdev_hdl,
+ "[ROCE] %s: Unexpected event type(0x%x) on CQ(%06x), func_id(%d)\n",
+ __func__, 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 : roce3_cq_buf_init
+ Description : roce3_cq_buf_init
+ Input : struct roce3_cq_buf *buf
+ Output : None
+
+ 1.Date : 2015/11/9
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_cq_buf_init(struct roce3_cq_buf *buf)
+{
+ /* optype was initialized into ROCE_OPCODE_CQE_UNUSED(0x1f) */
+ memset(buf->buf->direct.va, ROCE_CQE_INVALID_VALUE,
+ (unsigned long)((unsigned int)buf->buf_size));
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_put_umem
+ Description : Release umem and corresponding mtt, corresponding to put
+ Input : struct roce3_device *rdev
+ struct roce3_cq_buf *buf
+ struct ib_umem **umem
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_cq_put_umem(struct roce3_device *rdev, struct roce3_cq_buf *buf, struct ib_umem **umem)
+{
+ /* free MTT of Buffer */
+ hmm_rdma_mtt_free(rdev->hwdev, &buf->mtt, SERVICE_T_ROCE);
+
+ /* release umem */
+ ib_umem_release(*umem);
+}
+
+static void *roce3_cq_buf_offset(struct tag_cqm_buf *buf, unsigned int offset)
+{
+ return (void *)((char *)buf->direct.va + offset);
+}
+
+void *roce3_get_cqe_from_buf(struct roce3_cq_buf *buf, unsigned int n)
+{
+ return roce3_cq_buf_offset(buf->buf, (n * buf->entry_size));
+}
+
+void *roce3_get_cqe(struct roce3_cq *cq, unsigned int n)
+{
+ return roce3_get_cqe_from_buf(&cq->buf, n);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_get_sw_cqe
+ Description : roce3_get_sw_cqe
+ Input : struct roce3_cq *cq
+ unsigned int n
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+void *roce3_get_sw_cqe(struct roce3_cq *cq, unsigned int n)
+{
+ struct roce_cqe *cqe = (struct roce_cqe *)roce3_get_cqe(
+ cq, (n & ((unsigned int)cq->ibcq.cqe)));
+ struct roce_cqe tmp_cqe;
+ unsigned int tmp_val;
+
+ tmp_cqe.dw0.value = roce3_convert_cpu32(cqe->dw0.value);
+ tmp_cqe.dw1.value = roce3_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 + 1)) == 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 roce3_cq_get_umem(struct roce3_device *rdev, struct ib_udata *udata, struct roce3_cq_buf *buf,
+ struct ib_umem **umem, u64 buf_addr, int cqe)
+{
+ int ret = 0;
+ u32 npages = 0;
+ int page_shift = 0;
+ int cqe_size = (int)rdev->rdma_cap.cqe_size;
+
+ *umem = ib_umem_get(&rdev->ib_dev, buf_addr,
+ (unsigned long)(cqe * cqe_size), IB_ACCESS_LOCAL_WRITE);
+ if (IS_ERR(*umem)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to get ib_umem, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return (int)PTR_ERR(*umem);
+ }
+
+ npages = (u32)ib_umem_num_pages(*umem);
+ page_shift = PAGE_SHIFT;
+
+ buf->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_rdma_mtt_alloc(rdev->hwdev, npages, (u32)page_shift, &buf->mtt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc rdma_mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_buf;
+ }
+
+ ret = roce3_umem_write_mtt(rdev, &buf->mtt, *umem);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to write mtt for umem, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_mtt;
+ }
+
+ return 0;
+
+err_mtt:
+ hmm_rdma_mtt_free(rdev->hwdev, &buf->mtt, SERVICE_T_ROCE);
+
+err_buf:
+ ib_umem_release(*umem);
+
+ return ret;
+}
+
+void roce_reset_flow_comp(struct roce3_cq *rcq)
+{
+ struct ib_cq *ibcq = &rcq->ibcq;
+
+ ibcq->comp_handler(ibcq, ibcq->cq_context);
+}
diff --git a/drivers/infiniband/hw/hiroce3/cq/roce_cq_cqe.c b/drivers/infiniband/hw/hiroce3/cq/roce_cq_cqe.c
new file mode 100644
index 0000000000000..2db4653777725
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/cq/roce_cq_cqe.c
@@ -0,0 +1,744 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#include <linux/slab.h>
+
+#include "hinic3_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_main_extension.h"
+
+/*
+ ****************************************************************************
+ Prototype : roce3_next_cqe_sw
+ Description : roce3_next_cqe_sw
+ Input : struct roce3_cq *cq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static struct roce_cqe *roce3_next_cqe_sw(struct roce3_cq *cq)
+{
+ return (struct roce_cqe *)roce3_get_sw_cqe(cq, cq->cons_index);
+}
+
+/*lint -e26*/
+static int g_error_cqe_to_wc[ROCE_CQE_SYNDROME_MAX] = {
+ [ROCE_CQE_SYNDROME_LOCAL_LENGTH_ERR] = IB_WC_LOC_LEN_ERR,
+ [ROCE_CQE_SYNDROME_LOCAL_QP_OP_ERR] = IB_WC_LOC_QP_OP_ERR,
+ [ROCE_CQE_SYNDROME_LOCAL_PROT_ERR] = IB_WC_LOC_PROT_ERR,
+ [ROCE_CQE_SYNDROME_WR_FLUSH_ERR] = IB_WC_WR_FLUSH_ERR,
+
+ [ROCE_CQE_SYNDROME_MW_BIND_ERR] = IB_WC_MW_BIND_ERR,
+ [ROCE_CQE_SYNDROME_BAD_RESP_ERR] = IB_WC_BAD_RESP_ERR,
+
+ [ROCE_CQE_SYNDROME_LOCAL_ACCESS_ERR] = IB_WC_LOC_ACCESS_ERR,
+ [ROCE_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR] = IB_WC_REM_INV_REQ_ERR,
+ [ROCE_CQE_SYNDROME_REMOTE_ACCESS_ERR] = IB_WC_REM_ACCESS_ERR,
+ [ROCE_CQE_SYNDROME_REMOTE_OP_ERR] = IB_WC_REM_OP_ERR,
+ [ROCE_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR] = IB_WC_RETRY_EXC_ERR,
+
+ [ROCE_CQE_SYNDROME_RNR_RETRY_EXC_ERR] = IB_WC_RNR_RETRY_EXC_ERR,
+
+ [ROCE_CQE_SYNDROME_REMOTE_ABORTED_ERR] = IB_WC_REM_ABORT_ERR,
+};
+/*lint +e26*/
+
+/*
+ ****************************************************************************
+ Prototype : roce3_handle_error_cqe
+ Description : roce3_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 roce3_handle_error_cqe(struct roce_err_cqe *cqe, struct ib_wc *wc)
+{
+ if (cqe->dw7.bs.syndrome >= ROCE_CQE_SYNDROME_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 roce3_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:
+ pr_warn("[ROCE] %s: Unknown cqe optype\n", __func__);
+ break;
+ }
+}
+
+static void roce3_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:
+ roce3_get_local_opcode_from_cqe(cqe, wc);
+ break;
+ }
+}
+
+static void roce3_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:
+ roce3_get_local_opcode_from_cqe(cqe, wc);
+ break;
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_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)
+ roce3_get_opcode_type_part_1(cqe, wc);
+ else
+ roce3_get_opcode_type_part_2(cqe, wc);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_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 = roce3_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 = 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 = roce3_convert_be32(cqe->imm_invalid_rkey);
+ break;
+
+ default:
+ pr_warn("[ROCE] %s: Not supported\n", __func__);
+ break;
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_poll_and_resize
+ Description : roce3_cq_poll_and_resize
+ Input : struct roce3_cq *cq
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_cq_poll_and_resize(struct roce3_device *rdev, struct roce3_cq *cq)
+{
+ if (ROCE_LIKELY(cq->resize_buf != NULL)) {
+ /* Release the original Buffer of CQ */
+ hiudk_cqm_object_resize_free_old(rdev->hwdev, &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;
+ }
+
+ --cq->cons_index;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_get_cur_qp
+ Description : roce3_cq_get_cur_qp
+ Input : struct roce3_cq *cq
+ struct roce3_qp **cur_qp
+ struct roce_cqe *cqe
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_cq_get_cur_qp(struct roce3_cq *cq, struct roce3_qp **cur_qp, struct roce_cqe *cqe)
+{
+ struct roce3_device *rdev = NULL;
+ struct tag_cqm_object *cqm_obj_qp = NULL;
+
+ if ((!*cur_qp) || (cqe->dw0.bs.qpn != (u32)(*cur_qp)->qpn)) {
+ /*
+ * We do not have to take the QP table lock here,
+ * because CQs will be locked while QPs are removed
+ * from the table.
+ */
+ rdev = to_roce3_dev(cq->ibcq.device);
+ cqm_obj_qp = cqm_object_get(rdev->hwdev, CQM_OBJECT_SERVICE_CTX,
+ cqe->dw0.bs.qpn, false);
+ if (cqm_obj_qp == NULL) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: CQ(%06x) with entry for unknown QPN(%06x), func_id(%d)\n",
+ __func__, cq->cqn, cqe->dw0.bs.qpn, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ *cur_qp = cqmobj_to_roce_qp(cqm_obj_qp);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_qp);
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_get_xrc_srq
+ Description : roce3_cq_get_xrc_srq
+ Input : struct roce3_cq *cq
+ struct roce3_srq **srq
+ struct roce_cqe *cqe
+ u32 qp_type
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_cq_get_xrc_srq(struct roce3_cq *cq, struct roce3_srq **srq,
+ struct roce_cqe *cqe, u32 qp_type)
+{
+ u32 srq_num = 0;
+ struct roce3_device *rdev = NULL;
+ struct tag_cqm_object *cqm_obj_srq = NULL;
+
+ if (qp_type == IB_QPT_XRC_TGT) {
+ srq_num = cqe->dw6.bs.srqn_rqpn;
+
+ /* SRQ is also in the radix tree */
+ rdev = to_roce3_dev(cq->ibcq.device);
+ cqm_obj_srq = cqm_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SRQ, srq_num, false);
+ if (cqm_obj_srq == NULL) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: CQ(%06x) with entry for unknown SRQN(%06x), func_id(%d)\n",
+ __func__, cq->cqn, srq_num, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ /* Get roce3__srq structure through cqm object */
+ *srq = cqmobj_to_roce3_srq(cqm_obj_srq);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_srq);
+ }
+
+ return 0;
+}
+
+static int roce3_poll_recv_cqe(struct roce3_qp *cur_qp, struct roce3_srq *srq,
+ struct roce_cqe trans_cqe, struct ib_wc *wc)
+{
+ u16 wqe_ctr = 0;
+ unsigned int tail = 0;
+ struct roce3_srq *srq_tmp;
+
+ if (cur_qp->ibqp.srq) {
+ srq_tmp = to_roce3_srq(cur_qp->ibqp.srq);
+
+ wqe_ctr = (u16)trans_cqe.dw1.bs.wqebb_cnt;
+ /* Determine whether to overflow */
+ if (wqe_ctr > srq_tmp->max_depth) {
+ pr_err("[ROCE, ERR] %s: Get wqe index(0x%x) from cqe\n", __func__, wqe_ctr);
+ return -EINVAL;
+ }
+
+ wc->wr_id = srq_tmp->wrid[wqe_ctr];
+ roce3_free_srq_wqe(srq_tmp, wqe_ctr);
+ } else if (srq) {
+ wqe_ctr = (u16)trans_cqe.dw1.bs.wqebb_cnt;
+ /* Determine whether to overflow */
+ if (wqe_ctr > srq->max_depth) {
+ pr_err("[ROCE, ERR] %s: Get wqe index(0x%x) from cqe\n", __func__, wqe_ctr);
+ return -EINVAL;
+ }
+
+ wc->wr_id = srq->wrid[wqe_ctr];
+ roce3_free_srq_wqe(srq, wqe_ctr);
+ } else {
+ struct roce3_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 roce3_poll_move_tail(const struct roce3_qp *cur_qp, struct roce3_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 roce3_poll_one_get_av_info(const struct roce3_qp *cur_qp, struct ib_wc *wc,
+ struct roce_cqe trans_cqe, struct roce_cqe *cqe)
+{
+ 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;
+ /* Take the first Byte data, shift 8bit */
+ wc->smac[0] = (u8)(trans_cqe.dw4.bs.smac_h >> 8);
+ wc->smac[1] = (u8)(trans_cqe.dw4.bs.smac_h & 0xff);
+ memcpy(&wc->smac[2], &cqe->smac_l, sizeof(cqe->smac_l)); // 2 : smac array idx
+ 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 roce3_poll_one_get_qp_and_srq(struct roce3_cq *cq, struct roce3_qp **cur_qp,
+ struct ib_wc *wc, struct roce_cqe *trans_cqe, struct roce3_srq **srq)
+{
+ int ret = 0;
+
+ ret = roce3_cq_get_cur_qp(cq, cur_qp, trans_cqe);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get current qp\n", __func__);
+ return ret;
+ }
+
+ wc->qp = &((*cur_qp)->ibqp);
+
+ ret = roce3_cq_get_xrc_srq(cq, srq, trans_cqe, wc->qp->qp_type);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get xrc srq\n", __func__);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void roce3_bytes_trans(u32 *addr, int dw_num)
+{
+ u32 *dw = addr;
+ int i = 0;
+
+ for (i = 0; i < dw_num; i++) {
+ *dw = roce3_convert_cpu32(*dw);
+ dw++;
+ }
+}
+
+static int roce3_get_and_trans_cqe(struct roce3_device *rdev, struct roce3_cq *cq,
+ struct roce_cqe *trans_cqe, int *is_send, struct roce_cqe **cqe)
+{
+ do {
+ *cqe = roce3_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
+ */
+ memcpy((void *)trans_cqe, (void *)*cqe, sizeof(struct roce_cqe));
+ ++cq->cons_index;
+
+ /*
+ * 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 */
+ roce3_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))
+ roce3_cq_poll_and_resize(rdev, cq);
+ } while (ROCE_UNLIKELY(trans_cqe->dw1.bs.op_type == ROCE_OPCODE_RESIZE_CQE));
+
+ return 0;
+}
+
+static void roce3_poll_send_cqe(struct roce3_qp *cur_qp, struct roce_cqe *trans_cqe,
+ struct ib_wc *wc)
+{
+ struct roce3_wq *wq = &(cur_qp->sq);
+ /* QP of type IB_SIGNAL_REQ_WR, tail needs to skip several WRs that do not generate CQE */
+ roce3_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) {
+ roce3_handle_error_cqe((struct roce_err_cqe *)(void *)trans_cqe, wc);
+ return;
+ }
+
+ roce3_get_opcode_from_scqe(trans_cqe, wc);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_poll_one
+ Description : roce3_poll_one
+ Input : struct roce3_cq *cq
+ struct roce3_qp **cur_qp
+ struct ib_wc *wc
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_poll_one(struct roce3_device *rdev, struct roce3_cq *cq,
+ struct roce3_qp **cur_qp, struct ib_wc *wc)
+{
+ int ret = 0;
+ struct roce_cqe *cqe = NULL;
+ struct roce_cqe trans_cqe;
+ struct roce3_srq *srq = NULL;
+ int is_send = 0;
+ bool need_poll = true;
+
+ while (need_poll) {
+ ret = roce3_get_and_trans_cqe(rdev, cq, &trans_cqe, &is_send, &cqe);
+ if (ret != 0)
+ return -EAGAIN;
+
+ ret = roce3_poll_one_get_qp_and_srq(cq, cur_qp, wc, &trans_cqe, &srq);
+ if (ret != 0)
+ return ret;
+
+ /*
+ * Poll cq exception handling, generally cq judges
+ * user state information, xrc judges wrid
+ */
+ if ((*cur_qp)->umem || ((*cur_qp)->ibqp.xrcd && !(srq->wrid))) {
+ pr_err("[ROCE, ERR] %s: qp(%u) create in user space , but poll cq in kernel. NOT PERMIT!\n",
+ __func__, (*cur_qp)->qpn);
+ return -EACCES;
+ }
+
+ if (trans_cqe.dw1.bs.fake != 0) {
+ pr_info("[ROCE] %s: Fake cqe go repoll.\n", __func__);
+ continue;
+ }
+
+ wc->status = IB_WC_SUCCESS;
+ if (is_send != 0) {
+ roce3_poll_send_cqe(*cur_qp, &trans_cqe, wc);
+ return 0;
+ }
+ ret = roce3_poll_recv_cqe(*cur_qp, srq, trans_cqe, wc);
+ if (ret != 0)
+ return ret;
+
+ if (trans_cqe.dw1.bs.op_type == ROCE_OPCODE_ERR) {
+ roce3_handle_error_cqe((struct roce_err_cqe *)(void *)&trans_cqe, wc);
+ return 0;
+ }
+
+ roce3_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;
+
+ roce3_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) {
+ pr_err("[ROCE, ERR] %s: Receive inline not supported in kernel space\n",
+ __func__);
+ return -EINVAL;
+ }
+ need_poll = false;
+ }
+
+ return 0;
+}
+
+static int sw_send_comp(struct roce3_qp *rqp, int num_entries, int *npolled, struct ib_wc *wc)
+{
+ struct roce3_wq *wq = &rqp->sq;
+ unsigned int cur = wq->head - wq->tail;
+ unsigned int i;
+
+ if (cur == 0)
+ goto out;
+
+ for (i = 0; (i < cur) && (*npolled < num_entries); i++) {
+ wc[*npolled].wr_id = wq->wrid[wq->tail & (wq->wqebb_cnt - 1)];
+ wc[*npolled].status = IB_WC_WR_FLUSH_ERR;
+ wc[*npolled].vendor_err = ROCE_CQE_SYNDROME_WR_FLUSH_ERR;
+ wc[*npolled].qp = &rqp->ibqp;
+ wq->tail++;
+ (*npolled)++;
+ }
+
+out:
+ return (*npolled >= num_entries);
+}
+
+static int sw_recv_comp(struct roce3_qp *rqp, int num_entries, int *npolled, struct ib_wc *wc)
+{
+ struct roce3_wq *wq = &rqp->rq;
+ unsigned int cur = wq->head - wq->tail;
+ unsigned int i;
+
+ if (cur == 0)
+ goto out;
+
+ for (i = 0; (i < cur) && (*npolled < num_entries); i++) {
+ wc[*npolled].wr_id = wq->wrid[wq->tail & (wq->wqebb_cnt - 1)];
+ wc[*npolled].status = IB_WC_WR_FLUSH_ERR;
+ wc[*npolled].vendor_err = ROCE_CQE_SYNDROME_WR_FLUSH_ERR;
+ wc[*npolled].qp = &rqp->ibqp;
+ wq->tail++;
+ (*npolled)++;
+ }
+
+out:
+ return (*npolled >= num_entries);
+}
+
+static int roce_poll_sw_comp(const struct roce3_cq *rcq, int num_entries, struct ib_wc *wc)
+{
+ struct roce3_qp *rqp = NULL;
+ int npolled = 0;
+
+ list_for_each_entry(rqp, &rcq->send_qp_list, cq_send_list) {
+ if (sw_send_comp(rqp, num_entries, &npolled, wc) != 0)
+ return npolled;
+ }
+
+ list_for_each_entry(rqp, &rcq->recv_qp_list, cq_recv_list) {
+ if (sw_recv_comp(rqp, num_entries, &npolled, wc) != 0)
+ return npolled;
+ }
+
+ return npolled;
+}
+
+/* the format of cq_ci DB:the bits of ci less than 24bit */
+void roce3_cq_set_ci(struct roce3_cq *cq)
+{
+ *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff);
+}
+
+int roce3_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+ struct roce3_device *rdev = NULL;
+ struct roce3_cq *rcq = to_roce3_cq(ibcq);
+ struct roce3_qp *cur_qp = NULL;
+ unsigned long flags = 0;
+ int npolled = 0;
+ int ret = 0;
+
+ spin_lock_irqsave(&rcq->lock, flags);
+
+ rdev = to_roce3_dev(ibcq->device);
+ if (roce3_hca_is_present(rdev) == 0) {
+ npolled = roce_poll_sw_comp(rcq, num_entries, wc);
+ goto poll_out;
+ }
+
+ for (npolled = 0; npolled < num_entries; ++npolled) {
+ ret = roce3_poll_one(rdev, rcq, &cur_qp, wc + npolled);
+ if (ret != 0)
+ break;
+ }
+
+ roce3_cq_set_ci(rcq);
+
+poll_out:
+ spin_unlock_irqrestore(&rcq->lock, flags);
+
+ if ((ret == 0) || (ret == -EAGAIN))
+ return npolled;
+
+ return ret;
+}
+
+static void roce3_cq_arm(struct roce3_cq *cq, u32 cmd, void __iomem *uar_page)
+{
+ struct roce_db_cq_arm db_value;
+
+ memset(&db_value, 0, sizeof(db_value));
+
+ 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 = roce3_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 = roce3_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();
+
+ roce3_write64((u32 *)(void *)&db_value, uar_page);
+}
+
+int roce3_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
+{
+ unsigned long lock_flags = 0;
+ struct roce3_cq *cq = to_roce3_cq(ibcq);
+
+ spin_lock_irqsave(&cq->lock, lock_flags);
+ if (cq->arm_flag != 0) {
+ spin_unlock_irqrestore(&cq->lock, lock_flags);
+ return 0;
+ }
+
+ cq->arm_flag = 1;
+ spin_unlock_irqrestore(&cq->lock, lock_flags);
+
+ /* Only 64-bit is supported, 64-bit writes are atomic, no need to lock */
+ roce3_cq_arm(to_roce3_cq(ibcq),
+ (((unsigned int)flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED) ?
+ ROCE_CQ_DB_REQ_NOT_SOL : ROCE_CQ_DB_REQ_NOT,
+ to_roce3_dev(ibcq->device)->kernel_db_map);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/cq/roce_cq_create.c b/drivers/infiniband/hw/hiroce3/cq/roce_cq_create.c
new file mode 100644
index 0000000000000..775f6a0bda5da
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/cq/roce_cq_create.c
@@ -0,0 +1,629 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_cq.h"
+#include "roce_pub_cmd.h"
+#include "roce_cqm_cmd.h"
+#include "roce_main_extension.h"
+
+/*
+ ****************************************************************************
+ Prototype : roce_cq_attr_assign
+ Description : Assign value to CQC
+ Input : struct roce_cq_attr *cq_attr
+ struct roce3_cq *rcq
+ int eqn
+ int page_shift
+ Output : None
+
+ 1.Date : 2019/10/13
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce_cq_attr_assign(struct roce_verbs_cq_attr *cq_attr, struct roce3_cq *rcq,
+ int eqn, int page_shift)
+{
+ /* Assign value to CQ */
+ /* dw0 */
+ cq_attr->dw0.bs.size = (u32)ROCE_ILOG2((unsigned int)(rcq->ibcq.cqe + 1));
+ cq_attr->dw0.bs.page_size = (u32)page_shift;
+ /* entry_size=(2^cq_cqe_size)*16B. */
+ cq_attr->dw0.bs.cqe_size =
+ (u32)ROCE_ILOG2((unsigned int)(rcq->buf.entry_size / 16));
+ 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 = 6; /* update ci threshold: 2^6=64 */
+ 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 */
+ /* The timeout mechanism is disabled by default when CQ is created */
+ cq_attr->dw3.bs.timeout = 0;
+ /* The overtime mechanism is disabled by default when CQ is created */
+ cq_attr->dw3.bs.max_cnt = 0;
+ 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 roce3_cq_fill_create_inbuf(struct roce3_device *rdev, struct roce3_cq *rcq,
+ int vector, int page_shift, struct tag_cqm_cmd_buf *cqm_cmd_inbuf)
+{
+ int eqn = 0;
+ struct roce_verbs_cq_attr *cq_attr = NULL;
+ struct tag_roce_uni_cmd_creat_cq *cq_sw2hw_inbuf = NULL;
+
+ cq_sw2hw_inbuf = (struct tag_roce_uni_cmd_creat_cq *)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(VERBS_CMD_TYPE_CQ_BITMASK); //lint !e778
+ cq_attr = &cq_sw2hw_inbuf->cq_attr;
+
+ /* Get the EQN of the CEQ based on the Vector index */
+ eqn = hinic3_vector_to_eqn(rdev->hwdev, SERVICE_T_ROCE, vector);
+ if (eqn < 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to get eqn from hinic vector, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ roce_cq_attr_assign(cq_attr, rcq, eqn, page_shift);
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_sw2hw
+ Description : Send the cqc configuration command
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ int vector
+ int page_shift
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_cq_sw2hw(struct roce3_device *rdev, struct roce3_cq *rcq,
+ int vector, int page_shift)
+{
+ int ret = 0;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_uni_cmd_creat_cq), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ ret = roce3_cq_fill_create_inbuf(rdev, rcq, vector, page_shift, cqm_cmd_inbuf);
+ if (ret != 0) {
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+ }
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_SW2HW_CQ, cqm_cmd_inbuf,
+ NULL, NULL, ROCE_CMD_TIME_CLASS_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to send SW2HW_CQ command, ret(%d), func_id(%d)\n",
+ __func__, ret, rdev->glb_func_id);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA is present(SW2HW_CQ), CQN(0x%x), func_id(%u)\n",
+ __func__, rcq->cqn, 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;
+ }
+
+ roce3_cqm_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:
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_create_cq_check
+ Description : roce3_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 roce3_create_cq_check(struct ib_device *ibdev, int entries, int vector,
+ const struct ib_ucontext *ibcontext, const struct ib_udata *udata)
+{
+ struct roce3_device *rdev = NULL;
+
+ if (ibdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((ibcontext != NULL) && (udata == NULL)) {
+ pr_err("[ROCE, ERR] %s: Udata is null ptr, but ibcontext is not null ptr\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibdev);
+ if ((entries < 1) || (entries > (int)rdev->rdma_cap.max_cqes)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Cqe number invalid, entries(%d), func_id(%d)\n",
+ __func__, entries, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if (vector > (int)rdev->rdma_cap.num_comp_vectors) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Vector over range, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce3_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)); /*lint !e40*/
+}
+
+static int roce3_cq_cqc_cfg(struct roce3_device *rdev, struct roce3_cq *rcq, int vector,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ int page_shift = 0;
+
+ /* configurate CQC */
+ ret = roce3_cq_sw2hw(rdev, rcq, vector, page_shift);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to handle cq sw2hw, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ /* User mode requires outgoing CQN */
+ if (ib_copy_to_udata(udata, &rcq->cqn, sizeof(u32)) != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to copy data to user space, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ ret = -EFAULT;
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_create_user_cq
+ Description : roce3_create_user_cq
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ int entries
+ int vector
+ struct ib_ucontext *ibcontext
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_create_user_cq(struct roce3_device *rdev, struct roce3_cq *rcq, int entries,
+ int vector, struct ib_ucontext *ibcontext, struct ib_udata *udata, u32 index)
+{
+ int ret = 0;
+ struct roce3_create_cq_cmd ucmd = { 0 };
+
+ rcq->cqm_cq = cqm_object_rdma_queue_create(rdev->hwdev, SERVICE_T_ROCE,
+ CQM_OBJECT_RDMA_SCQ, 0, rcq, false, index);
+ if (rcq->cqm_cq == NULL) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create rdma queue from cqm object, func_id(%d), index(%d)\n",
+ __func__, rdev->glb_func_id, index);
+ return -ENOMEM;
+ }
+
+ /* record CQN */
+ rcq->cqn = rcq->cqm_cq->index;
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)) != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to copy from user space, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ ret = -EFAULT;
+ goto err_free_cqm_cq;
+ }
+
+ /*
+ * 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
+ */
+#if defined(OFED_MLNX_5_8)
+ ret = roce3_cq_get_umem(rdev, udata, &rcq->buf, &rcq->umem, ucmd.buf_addr, entries);
+#else
+ ret = roce3_cq_get_umem(rdev, ibcontext, &rcq->buf, &rcq->umem, ucmd.buf_addr, entries);
+#endif
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to get umem, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_free_cqm_cq;
+ }
+
+ ret = roce3_db_map_user(to_roce3_ucontext(ibcontext),
+ (unsigned long)ucmd.db_addr, &rcq->db);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to map kernel_mem to user_mem, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_free_mtt;
+ }
+
+ ret = roce3_cq_cqc_cfg(rdev, rcq, vector, udata);
+ if (ret != 0)
+ goto err_unmap_db;
+
+ return 0;
+
+err_unmap_db:
+ roce3_db_unmap_user(to_roce3_ucontext(ibcontext), &rcq->db);
+
+err_free_mtt:
+ roce3_cq_put_umem(rdev, &rcq->buf, &rcq->umem);
+ rcq->umem = NULL;
+
+err_free_cqm_cq:
+ hiudk_cqm_object_delete(rdev->hwdev, &rcq->cqm_cq->object);
+
+ return ret;
+}
+
+static void roce3_fill_rcq_info(struct roce3_cq *rcq)
+{
+ rcq->cqn = rcq->cqm_cq->index;
+ rcq->buf.buf = &rcq->cqm_cq->q_room_buf_1;
+
+ /* Initialize buf to unused */
+ roce3_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 : roce3_create_kernel_cq
+ Description : roce3_create_kernel_cq
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ int entries
+ int vector
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_create_kernel_cq(struct roce3_device *rdev, struct roce3_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 = cqm_object_rdma_queue_create(rdev->hwdev, SERVICE_T_ROCE,
+ CQM_OBJECT_RDMA_SCQ, (u32)rcq->buf.buf_size, rcq, true, index);
+ if (rcq->cqm_cq == NULL) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create rdma_queue from cqm_object, func_id(%d), index(%d)\n",
+ __func__, 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) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Not use CQM_RDMA_Q_ROOM_1, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ ret = -EINVAL;
+ goto err_free_cqm_cq;
+ }
+
+ roce3_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_rdma_mtt_alloc(rdev->hwdev, rcq->buf.buf->buf_number, (u32)page_shift,
+ &rcq->buf.mtt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc rdma mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_free_cqm_cq;
+ }
+
+ /* Write the PA of the CQ Buffer to the MTT */
+ ret = roce3_buf_write_mtt(rdev, &rcq->buf.mtt, rcq->buf.buf);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to write rdma mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_free_mtt;
+ }
+
+ /*lint -e834*/
+ page_shift = ROCE_ILOG2(rcq->cqm_cq->q_room_buf_1.buf_size) - PAGE_SHIFT_4K;
+ /*lint +e834*/
+
+ /* configurate CQC */
+ ret = roce3_cq_sw2hw(rdev, rcq, vector, page_shift);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to configure CQC, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_free_mtt;
+ }
+
+ return 0;
+
+err_free_mtt:
+ hmm_rdma_mtt_free(rdev->hwdev, &rcq->buf.mtt, SERVICE_T_ROCE);
+
+err_free_cqm_cq:
+ hiudk_cqm_object_delete(rdev->hwdev, &rcq->cqm_cq->object);
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_do_create_cq
+ Description : OFED_3_12
+ Input : struct ib_device *ibdev
+ struct ib_ucontext *ibcontext
+ struct ib_ucontext *ibcontext
+ struct ib_udata *udata
+ struct roce3_cq *rcq
+ u32 index
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+ 2.Date : 2015/8/10
+ Modification : modify function
+ 3.Date : 2017/11/10
+ Modification : modify function
+
+****************************************************************************
+*/
+static int roce3_do_create_cq(struct ib_device *ibdev, const struct ib_cq_init_attr *attr,
+ struct ib_ucontext *ibcontext, struct ib_udata *udata, struct roce3_cq *rcq, u32 index)
+{
+ struct roce3_device *rdev = NULL;
+ int ret = 0;
+ int vector = attr->comp_vector;
+ int entries = (int)attr->cqe;
+
+ /* The CQE queue should reserve a special CQE for resize cq */
+ entries++;
+ entries = (int)(ROCE_ROUNDUP_POW_OF_TWO((u32)entries) & 0xffffffff); /*lint !e587*/
+
+ rdev = to_roce3_dev(ibdev);
+ /* Chip Constraints: Minimum queue depth needs to be page-aligned */
+ if ((u32)((u32)entries * rdev->rdma_cap.cqe_size) < PAGE_SIZE)
+ entries = (PAGE_SIZE >> (u32)ROCE_ILOG2(rdev->rdma_cap.cqe_size));
+
+ /* Check if max spec is exceeded */
+ if (entries > ((int)rdev->rdma_cap.max_cqes + 1)) {
+ ret = (-EINVAL);
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Over range after align, entries(%d), max_cqes(%d), func_id(%d)\n",
+ __func__, entries, rdev->rdma_cap.max_cqes + 1, rdev->glb_func_id);
+ return ret;
+ }
+
+ rcq->ibcq.cqe = entries - 1;
+ mutex_init(&rcq->resize_mutex);
+ /*lint -e708*/
+ spin_lock_init(&rcq->lock);
+ /*lint +e708*/
+ rcq->resize_buf = NULL;
+ rcq->resize_umem = NULL;
+ rcq->buf.entry_size = (int)rdev->rdma_cap.cqe_size;
+
+ INIT_LIST_HEAD(&rcq->send_qp_list);
+ INIT_LIST_HEAD(&rcq->recv_qp_list);
+ if (ibcontext) {
+ ret = roce3_create_user_cq(rdev, rcq, entries, vector, ibcontext, udata, index);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to create user_cq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ } else {
+ ret = roce3_create_kernel_cq(rdev, rcq, entries, vector, index);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to create kernel_cq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ rcq->reset_flow_comp = roce_reset_flow_comp;
+
+ return 0;
+}
+
+#if defined(OFED_MLNX_5_8)
+int roce3_create_cq_common(struct ib_device *ibdev, const struct ib_cq_init_attr *attr,
+ struct ib_udata *udata, struct roce3_cq *rcq, u32 index)
+{
+ int ret;
+ struct roce3_device *rdev = to_roce3_dev(ibdev);
+ struct roce3_ucontext *context = rdma_udata_to_drv_context(
+ udata, struct roce3_ucontext, ibucontext);
+ int vector = attr->comp_vector;
+ int entries = (int)attr->cqe;
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ if (roce3_check_cq_create_flags(attr->flags) != 0) {
+ pr_err("[ROCE, ERR] %s: Not support the cq_create flag(%x)\n",
+ __func__, attr->flags);
+ return -EOPNOTSUPP;
+ }
+
+ ret = roce3_create_cq_check(ibdev, entries, vector, &context->ibucontext, udata);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to check cq information\n", __func__);
+ return ret;
+ }
+
+ return roce3_do_create_cq(ibdev, attr, &context->ibucontext, udata, rcq, index);
+}
+
+int roce3_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, struct ib_udata *udata)
+{
+ struct roce3_cq *rcq = to_roce3_cq(ibcq);
+
+ return roce3_create_cq_common(ibcq->device, attr, udata, rcq, ROCE_CQN_INVLD);
+}
+#else
+struct ib_cq *roce3_create_cq_common(struct ib_device *ibdev, const struct ib_cq_init_attr *attr,
+ struct ib_ucontext *ibcontext, struct ib_udata *udata, u32 index)
+{
+ int ret = 0;
+ struct roce3_cq *rcq = NULL;
+ int vector = attr->comp_vector;
+ int entries = (int)attr->cqe;
+ struct roce3_device *rdev = to_roce3_dev(ibdev);
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return ERR_PTR((long)-EPERM);
+ }
+
+ if (roce3_check_cq_create_flags(attr->flags) != 0) {
+ pr_err("[ROCE, ERR] %s: Not support the cq_create flag(%x)\n",
+ __func__, attr->flags);
+ return ERR_PTR((long)(-EOPNOTSUPP));
+ }
+
+ ret = roce3_create_cq_check(ibdev, entries, vector, ibcontext, udata);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to check cq information\n", __func__);
+ goto err_out;
+ }
+
+ rcq = kzalloc(sizeof(*rcq), GFP_KERNEL);
+ if (rcq == NULL) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ ret = roce3_do_create_cq(ibdev, attr, ibcontext, udata, rcq, index);
+ if (ret != 0)
+ goto err_free_cq;
+
+ return &rcq->ibcq;
+
+err_free_cq:
+ kfree(rcq);
+
+err_out:
+ return (struct ib_cq *)ERR_PTR((long)ret);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_create_cq
+ Description : OFED_3_12
+ Input : struct ib_device *ibdev
+ struct ib_cq_init_attr *attr(flags for exp)
+ struct ib_ucontext *ibcontext
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+ 2.Date : 2015/8/10
+ Modification : modify function
+ 3.Date : 2017/11/10
+ Modification : modify function
+ 4.Date : 2021/1/7
+ Modification : modified function
+
+****************************************************************************
+*/
+struct ib_cq *roce3_create_cq(struct ib_device *ibdev, const struct ib_cq_init_attr *attr,
+ struct ib_ucontext *ibcontext, struct ib_udata *udata)
+{
+ return roce3_create_cq_common(ibdev, attr, ibcontext, udata, ROCE_CQN_INVLD);
+}
+#endif
+
diff --git a/drivers/infiniband/hw/hiroce3/cq/roce_cq_ctrl.c b/drivers/infiniband/hw/hiroce3/cq/roce_cq_ctrl.c
new file mode 100644
index 0000000000000..19489bcece715
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/cq/roce_cq_ctrl.c
@@ -0,0 +1,930 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_cq.h"
+#include "roce_cqm_cmd.h"
+#include "roce_pub_cmd.h"
+#include "roce_main_extension.h"
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_modify
+ Description : Send the command of cq_modify
+ Input : struct roce3_device *rdev
+ struct roce3_cq *cq
+ u32 cnt
+ u32 period
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_cq_modify(struct roce3_device *rdev, struct roce3_cq *cq, u32 cnt, u32 period)
+{
+ int ret = 0;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_cmd_modify_cq *cq_modify_inbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_modify_cq), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ cq_modify_inbuf = (struct tag_roce_cmd_modify_cq *)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); //lint !e778
+ cq_modify_inbuf->max_cnt = cpu_to_be32(cnt);
+ cq_modify_inbuf->timeout = cpu_to_be32(period);
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_MODIFY_CQ, cqm_cmd_inbuf,
+ NULL, NULL, ROCE_CMD_TIME_CLASS_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to send MODIFY_CQ, cqn(0x%x), ret(%d), func_id(%u)\n",
+ __func__, cq->cqn, ret, rdev->glb_func_id);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA is present(MODIFY_CQ), cqn(0x%x), func_id(%u)\n",
+ __func__, cq->cqn, 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;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ /* CMDq may return a positive number, so its return value cannot be used directly */
+ return -1;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_modify_cq(struct ib_cq *ibcq, u16 cq_count, u16 cq_period)
+{
+ int ret = 0;
+ struct roce3_cq *cq = NULL;
+ struct roce3_device *rdev = NULL;
+
+ if (ibcq == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibcq is null\n", __func__);
+ return -EINVAL;
+ }
+
+ cq = to_roce3_cq(ibcq);
+ rdev = to_roce3_dev(ibcq->device);
+
+ ret = roce3_cq_modify(rdev, cq, cq_count, cq_period);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to modify cq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_device *rdev
+ struct roce3_cq *rcq
+ int entries
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_cq_alloc_resize_buf(struct roce3_device *rdev, struct roce3_cq *rcq, int entries)
+{
+ int ret = 0;
+ int page_shift = 0;
+
+ if (rcq->resize_buf) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Resize buffer is busy, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EBUSY;
+ }
+
+ /* Apply for resize_buf and assign it */
+ rcq->resize_buf = kmalloc(sizeof(*rcq->resize_buf), GFP_ATOMIC);
+ if (rcq->resize_buf == NULL)
+ return -ENOMEM;
+
+ rcq->resize_buf->buf.entry_size = rcq->buf.entry_size;
+ rcq->resize_buf->buf.buf_size = entries * rcq->buf.entry_size;
+ ret = hiudk_cqm_object_resize_alloc_new(rdev->hwdev, &rcq->cqm_cq->object,
+ (u32)rcq->resize_buf->buf.buf_size);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to resize cq buffer, func_id(%d)\n",
+ __func__, 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 - 1;
+ rcq->resize_buf->buf.buf = &rcq->cqm_cq->q_room_buf_2;
+
+ /* Initialize new buf to unused state */
+ roce3_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_rdma_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) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc rdma mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_mtt_alloc;
+ }
+
+ /* configurate MTT, write PA of resize_buf to MTT */
+ ret = roce3_buf_write_mtt(rdev, &rcq->resize_buf->buf.mtt, rcq->resize_buf->buf.buf);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to write rdma mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_mtt_write;
+ }
+
+ return 0;
+
+err_mtt_write:
+ hmm_rdma_mtt_free(rdev->hwdev, &rcq->buf.mtt, SERVICE_T_ROCE);
+
+err_mtt_alloc:
+ /* free resize_buf */
+ hiudk_cqm_object_resize_free_new(rdev->hwdev, &rcq->cqm_cq->object);
+
+err_resize_buf_alloc:
+ kfree(rcq->resize_buf);
+ rcq->resize_buf = NULL;
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_free_resize_buf
+ Description : Kernel Mode releases resize_buf and its corresponding MTT
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_cq_free_resize_buf(struct roce3_device *rdev, struct roce3_cq *rcq)
+{
+ /* Release the MTT of resize_buf first */
+ hmm_rdma_mtt_free(rdev->hwdev, &rcq->buf.mtt, SERVICE_T_ROCE);
+
+ /* free resize_buf */
+ hiudk_cqm_object_resize_free_new(rdev->hwdev, &rcq->cqm_cq->object);
+
+ /* free the resize_buf pointer itself */
+ kfree(rcq->resize_buf);
+ rcq->resize_buf = NULL;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_alloc_resize_umem
+ Description : User mode applies for umem of
+ resize_buf,and MTT corresponding to user mode buf
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ int entries
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_cq_alloc_resize_umem(struct roce3_device *rdev, struct roce3_cq *rcq, int entries,
+ struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce3_resize_cq_cmd ucmd = { 0 };
+
+ /*
+ * If a resize is being executed, it is not allowed
+ * to execute another resize at the same time
+ */
+ if (rcq->resize_umem) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Resize_umem is busy, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EBUSY;
+ }
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)) != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to copy from user space, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EFAULT;
+ }
+
+ rcq->resize_buf = kmalloc(sizeof(*rcq->resize_buf), GFP_ATOMIC);
+ if (rcq->resize_buf == NULL)
+ return -ENOMEM;
+
+ ret = roce3_cq_get_umem(rdev, udata, &rcq->resize_buf->buf,
+ &rcq->resize_umem, ucmd.buf_addr, entries);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to get umem, func_id(%d)\n",
+ __func__, 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 - 1;
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_free_resize_umem
+ Description : User mode applies for umem of resize_buf, and MTT corresponding to user mode buf
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_cq_free_resize_umem(struct roce3_device *rdev, struct roce3_cq *rcq)
+{
+ /* Free MTT and umem of resize_buf */
+ roce3_cq_put_umem(rdev, &rcq->resize_buf->buf, &rcq->resize_umem);
+ rcq->resize_umem = NULL;
+
+ /* free resize_buf itself */
+ kfree(rcq->resize_buf);
+ rcq->resize_buf = NULL;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_get_outstanding_cqes
+ Description : roce3_cq_get_outstanding_cqes
+ Input : struct roce3_cq *cq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_cq_get_outstanding_cqes(struct roce3_cq *cq)
+{
+ u32 i = 0;
+
+ i = cq->cons_index;
+ while (roce3_get_sw_cqe(cq, i))
+ ++i;
+
+ return (int)(i - cq->cons_index);
+}
+
+static int roce3_cq_get_next_cqe(struct roce_cqe **cqe, struct roce3_cq *cq,
+ unsigned int *i, u32 *times, const struct roce_cqe *start_cqe)
+{
+ int ret = 0;
+
+ do {
+ *cqe = (struct roce_cqe *)roce3_get_sw_cqe(cq, ++(*i));
+ if (*cqe == NULL) {
+ ROCE_MDELAY(MS_DELAY);
+ --(*times);
+ }
+ } while ((*cqe == NULL) && (*times != 0));
+
+ if ((*cqe == start_cqe) || (*cqe == NULL)) {
+ pr_err("[ROCE, ERR] %s: Failed to get resize CQE, CQN(0x%x)\n", __func__, cq->cqn);
+ return -ENOMEM;
+ }
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_resize_copy_cqes
+ Description : roce3_cq_resize_copy_cqes
+ Input : struct roce3_cq *cq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_cq_resize_copy_cqes(struct roce3_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 *)roce3_get_sw_cqe(cq, i);
+ if (cqe == NULL) {
+ ROCE_MDELAY(MS_DELAY);
+ --times;
+ }
+ } while ((cqe == NULL) && (times != 0));
+
+ if (cqe == NULL) {
+ pr_err("[ROCE, ERR] %s: Failed to get resize CQE, CQN(0x%x)\n", __func__, 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 = roce3_convert_cpu32(cqe->dw0.value);
+ cqe->dw1.value = roce3_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 *)roce3_get_cqe_from_buf(&cq->resize_buf->buf,
+ (i & ((unsigned int)cq->resize_buf->cqe)));
+
+ memcpy((void *)new_cqe, (void *)cqe, sizeof(struct roce_cqe));
+
+ /* 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 int)cq->resize_buf->cqe + 1)) != 0) ? 1 : 0;
+
+ /* After processing, turn the DW0/DW1 of CQE back to big endian */
+ cqe->dw0.value = roce3_convert_be32(cqe->dw0.value);
+ cqe->dw1.value = roce3_convert_be32(cqe->dw1.value);
+
+ /* Convert DW0/DW1 of the CQE in the new queue back to big endian */
+ new_cqe->dw0.value = roce3_convert_be32(new_cqe->dw0.value);
+ new_cqe->dw1.value = roce3_convert_be32(new_cqe->dw1.value);
+
+ /* Get the next CQE */
+ ret = roce3_cq_get_next_cqe(&cqe, cq, &i, &times, start_cqe);
+ if (ret != 0)
+ return ret;
+
+ /* Convert DW0/DW1 of CQE to little endian */
+ cqe->dw0.value = roce3_convert_cpu32(cqe->dw0.value);
+ cqe->dw1.value = roce3_convert_cpu32(cqe->dw1.value);
+ }
+
+ return 0;
+}
+
+static void roce3_cq_fill_resize_inbuf(struct roce3_device *rdev, struct roce3_cq *rcq,
+ int page_shift, struct tag_cqm_cmd_buf *cqm_cmd_inbuf)
+{
+ struct rdma_service_cap *rdma_cap = NULL;
+ u32 cq_size = 0;
+ u32 mtt_layer = 0;
+ u64 mtt_paddr = 0;
+ u32 mtt_page_size = 0;
+ struct tag_roce_cmd_resize_cq *cq_resize_inbuf = NULL;
+
+ rdma_cap = &rdev->rdma_cap;
+ cq_size = (u32)rcq->resize_buf->cqe + 1;
+ 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 = (struct tag_roce_cmd_resize_cq *)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(VERBS_CMD_TYPE_CQ_BITMASK); //lint !e778
+ cq_resize_inbuf->page_size = cpu_to_be32((u32)page_shift);
+ cq_resize_inbuf->log_cq_size = cpu_to_be32(cq_size);
+ cq_resize_inbuf->mtt_layer_num = cpu_to_be32(mtt_layer);
+ cq_resize_inbuf->mtt_base_addr = mtt_paddr;
+ cq_resize_inbuf->mtt_base_addr = cpu_to_be64(cq_resize_inbuf->mtt_base_addr);
+ cq_resize_inbuf->mtt_page_size = cpu_to_be32(mtt_page_size);
+
+ cq_resize_inbuf->mtt_info.mtt_flags = 0;
+ cq_resize_inbuf->mtt_info.mtt_num = 0;
+ cq_resize_inbuf->mtt_info.mtt_cache_line_start =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_start);
+ cq_resize_inbuf->mtt_info.mtt_cache_line_end =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_end);
+ cq_resize_inbuf->mtt_info.mtt_cache_line_size =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_sz);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_resize
+ Description : roce3_cq_resize
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ int page_shift
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_cq_resize(struct roce3_device *rdev, struct roce3_cq *rcq, int page_shift)
+{
+ int ret = 0;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_resize_cq), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ roce3_cq_fill_resize_inbuf(rdev, rcq, page_shift, cqm_cmd_inbuf);
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_RESIZE_CQ, cqm_cmd_inbuf,
+ NULL, NULL, ROCE_CMD_TIME_CLASS_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to send RESIZE_CQ command, ret(%d), func_id(%d)\n",
+ __func__, ret, rdev->glb_func_id);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA is present(RESIZE_CQ), cqn(0x%x), func_id(%u)\n",
+ __func__, rcq->cqn, 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;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_user_cq_resize
+ Description : roce3_user_cq_resize
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ int entries
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_user_cq_resize(struct roce3_device *rdev, struct roce3_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 + 1)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Over range after align, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ ret = roce3_cq_alloc_resize_umem(rdev, rcq, entries, udata);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc resize_umem, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ /*
+ * 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 = roce3_cq_resize(rdev, rcq, page_shift);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to resize cq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ roce3_cq_free_resize_umem(rdev, rcq);
+ return ret;
+ }
+
+ rcq->ibcq.cqe = rcq->resize_buf->cqe;
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_resize_user_cq
+ Description : roce3_resize_user_cq
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ int entries
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_resize_user_cq(struct roce3_device *rdev, struct roce3_cq *rcq,
+ int entries, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce3_resize_cq_cmd ucmd = { 0 };
+ int cqe_entries = entries;
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)) != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to copy from user space, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EFAULT;
+ }
+
+ if (ucmd.stage == 1)
+ goto release_flow;
+
+ mutex_lock(&rcq->resize_mutex);
+
+ cqe_entries++;
+ cqe_entries = (int)(ROCE_ROUNDUP_POW_OF_TWO((u32)cqe_entries) & 0xffffffff); /*lint !e587*/
+ // 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));
+
+ /*
+ * The new depth of CQ cannot be the same as the old
+ * depth. A special CQE space is reserved when CQ is created,
+ * so the value of ibcq->cqe is 1 smaller than the actual value
+ */
+ if (cqe_entries == (rcq->ibcq.cqe + 1)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: No need to resize cq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ ret = 0;
+ goto out;
+ }
+
+ ret = roce3_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_rdma_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 : roce3_kernel_cq_resize
+ Description : roce3_kernel_cq_resize
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ int entries
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_kernel_cq_resize(struct roce3_device *rdev, struct roce3_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 + 1)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Over range after align, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ /* The number of resized CQEs cannot be smaller than the number of outstanding CQEs */
+ outst_cqe = roce3_cq_get_outstanding_cqes(rcq);
+ if (entries < (outst_cqe + 1)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Can't resize, because smaller than the number of outstanding CQES, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ ret = roce3_cq_alloc_resize_buf(rdev, rcq, entries);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc resize buffer, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ /*lint -e834*/
+ page_shift = ROCE_ILOG2(rcq->cqm_cq->q_room_buf_2.buf_size) - PAGE_SHIFT_4K;
+ /*lint +e834*/
+
+ /*
+ * 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 = roce3_cq_resize(rdev, rcq, page_shift);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to resize cq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ roce3_cq_free_resize_buf(rdev, rcq);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_resize_kernel_cq
+ Description : roce3_resize_kernel_cq
+ Input : struct roce3_device *rdev
+ struct roce3_cq *rcq
+ int entries
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_resize_kernel_cq(struct roce3_device *rdev, struct roce3_cq *rcq, int entries)
+{
+ int ret = 0;
+ int tmp_cqe = 0;
+ int cqe_entries = entries;
+
+ mutex_lock(&rcq->resize_mutex);
+
+ cqe_entries++;
+ cqe_entries = (int)(ROCE_ROUNDUP_POW_OF_TWO((u32)cqe_entries) & 0xffffffff); /*lint !e587*/
+ /* 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. A special CQE space is reserved when CQ is created,
+ * so the value of ibcq->cqe is 1 smaller than the actual value
+ */
+ if (cqe_entries == (rcq->ibcq.cqe + 1)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: No need to resize cq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ mutex_unlock(&rcq->resize_mutex);
+ return 0;
+ }
+
+ ret = roce3_kernel_cq_resize(rdev, rcq, cqe_entries);
+ if (ret != 0)
+ goto out;
+
+ /* free old MTT */
+ hmm_rdma_mtt_free(rdev->hwdev, &rcq->buf.mtt, SERVICE_T_ROCE);
+
+ /*
+ * 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) {
+ ret = roce3_cq_resize_copy_cqes(rcq);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Have not polled resize cqe(fuc:%d, cqn:%u, ret:%d)\n",
+ __func__, rdev->glb_func_id, rcq->cqn, ret);
+ spin_unlock_irq(&rcq->lock);
+ mutex_unlock(&rcq->resize_mutex);
+ return ret;
+ }
+ tmp_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 (tmp_cqe != 0)
+ hiudk_cqm_object_resize_free_old(rdev->hwdev, &rcq->cqm_cq->object);
+
+out:
+ mutex_unlock(&rcq->resize_mutex);
+
+ return ret;
+}
+
+static int roce3_resize_cq_check(struct ib_cq *ibcq, int entries, const struct ib_udata *udata)
+{
+ struct roce3_device *rdev = NULL;
+
+ if (ibcq == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibcq is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((ibcq->uobject != NULL) && (udata == NULL)) {
+ pr_err("[ROCE, ERR] %s: Udata is null, but uobject is not null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibcq->device);
+ if ((entries < 1) || (entries > (int)rdev->rdma_cap.max_cqes)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: resize CQEs invalid. entries(%d), func_id(%d)\n",
+ __func__, entries, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_resize_cq
+ Description : roce3_resize_cq
+ Input : struct ib_cq *ibcq
+ int entries
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce3_cq *rcq = NULL;
+ struct roce3_device *rdev = NULL;
+
+ ret = roce3_resize_cq_check(ibcq, entries, udata);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: failed to check resize_cq\n", __func__);
+ return ret;
+ }
+
+ rcq = to_roce3_cq(ibcq);
+ rdev = to_roce3_dev(ibcq->device);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -1;
+ }
+
+ if (ibcq->uobject) {
+ ret = roce3_resize_user_cq(rdev, rcq, entries, udata);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to resize user cq, func_id(%u) ret(%d)\n",
+ __func__, (u32)rdev->glb_func_id, ret);
+ return ret;
+ }
+ } else {
+ ret = roce3_resize_kernel_cq(rdev, rcq, entries);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to resize kernel cq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void roce3_lock_cqs(struct roce3_cq *roce3_send_cq, struct roce3_cq *roce3_recv_cq)
+ __acquires(&roce3_send_cq->lock) __acquires(&roce3_recv_cq->lock)
+{
+ if (roce3_send_cq == roce3_recv_cq) {
+ spin_lock_irq(&roce3_send_cq->lock);
+ __acquire(&roce3_recv_cq->lock);
+ } else if (roce3_send_cq->cqn < roce3_recv_cq->cqn) {
+ spin_lock_irq(&roce3_send_cq->lock);
+ spin_lock_nested(&roce3_recv_cq->lock, SINGLE_DEPTH_NESTING);
+ } else {
+ spin_lock_irq(&roce3_recv_cq->lock);
+ spin_lock_nested(&roce3_send_cq->lock, SINGLE_DEPTH_NESTING);
+ }
+}
+
+void roce3_unlock_cqs(struct roce3_cq *roce3_send_cq, struct roce3_cq *roce3_recv_cq)
+ __releases(&roce3_send_cq->lock) __releases(&roce3_recv_cq->lock)
+{
+ if (roce3_send_cq == roce3_recv_cq) {
+ __release(&roce3_recv_cq->lock);
+ spin_unlock_irq(&roce3_send_cq->lock);
+ } else if (roce3_send_cq->cqn < roce3_recv_cq->cqn) {
+ spin_unlock(&roce3_recv_cq->lock);
+ spin_unlock_irq(&roce3_send_cq->lock);
+ } else {
+ spin_unlock(&roce3_send_cq->lock);
+ spin_unlock_irq(&roce3_recv_cq->lock);
+ }
+}
diff --git a/drivers/infiniband/hw/hiroce3/cq/roce_cq_destroy.c b/drivers/infiniband/hw/hiroce3/cq/roce_cq_destroy.c
new file mode 100644
index 0000000000000..c9e555ce0a55d
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/cq/roce_cq_destroy.c
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/slab.h>
+
+#include "hinic3_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_pub_cmd.h"
+#include "hinic3_hmm.h"
+#include "roce_main_extension.h"
+
+static int roce3_check_cqc_data_state(struct roce3_device *rdev, const struct roce3_cq *cq,
+ struct roce_cq_context *cqc_data, u32 check_state)
+{
+ int read_back_flag = 0;
+ int times = rdev->try_times;
+ struct roce_cq_context check_cqc_data;
+
+ while ((times--) != 0) {
+ if (roce3_hca_is_present(rdev) == 0)
+ return 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_UDELAY(US_PERF_DELAY);
+ }
+
+ if (read_back_flag == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to read back after try %d times, CQ state(0x%x), func_id(%u)\n",
+ __func__, rdev->try_times, cqc_data->dw2.value, (u32)rdev->glb_func_id);
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Cqn(0x%x), timer_dw(0x%x), func_id(%u)\n",
+ __func__, cq->cqn, cqc_data->dw2.value, (u32)rdev->glb_func_id);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_hw2sw
+ Description : roce3_cq_hw2sw
+ Input : struct roce3_device *rdev
+ struct roce3_cq *cq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_cq_hw2sw(struct roce3_device *rdev, struct roce3_cq *cq)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct roce_cq_context *cqc_data = NULL;
+ struct tag_roce_cmd_cq_hw2sw *cq_hw2sw_inbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_cq_hw2sw), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ cq_hw2sw_inbuf = (struct tag_roce_cmd_cq_hw2sw *)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); //lint !e778
+
+ cqc_data = (struct roce_cq_context *)((void *)cq->cqm_cq->q_ctx_vaddr);
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_HW2SW_CQ,
+ cqm_cmd_inbuf, NULL, NULL, ROCE_CMD_TIME_CLASS_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to send HW2SW_CQ command, func_id(%u), cqn(0x%x), (ret:%d)\n",
+ __func__, (u32)rdev->glb_func_id, cq->cqn, ret);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA is present(HW2SW_CQ), cqn(0x%x), func_id(%u)\n",
+ __func__, cq->cqn, 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;
+ }
+
+ /* CMDq may return a positive number, so its return value cannot be used directly */
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return -1;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return roce3_check_cqc_data_state(rdev, cq, cqc_data, ROCE_CQ_TIME_OUT_CHECK_VALUE);
+}
+
+static int roce3_cq_cache_out(struct roce3_device *rdev, struct roce3_cq *cq)
+{
+ int ret = 0;
+ struct rdma_service_cap *rdma_cap = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_cmd_cq_cache_invalidate *cq_cache_invld_inbuf = NULL;
+
+ /* Send the cache out command */
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_cq_cache_invalidate), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ dev_dbg(rdev->hwdev_hdl, "[ROCE, INFO] %s: func_id(%d) cqn(%d)\n",
+ __func__, rdev->glb_func_id, cq->cqn);
+ rdma_cap = &rdev->rdma_cap;
+ cq_cache_invld_inbuf = (struct tag_roce_cmd_cq_cache_invalidate *)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(VERBS_CMD_TYPE_CQ_BITMASK); //lint !e778
+ cq_cache_invld_inbuf->mtt_info.mtt_flags = 0;
+ cq_cache_invld_inbuf->mtt_info.mtt_num = 0;
+ cq_cache_invld_inbuf->mtt_info.mtt_cache_line_start =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_start);
+ cq_cache_invld_inbuf->mtt_info.mtt_cache_line_end =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_end);
+ cq_cache_invld_inbuf->mtt_info.mtt_cache_line_size =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_sz);
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_MISC_CQ_CACHE_INVLD,
+ cqm_cmd_inbuf, NULL, NULL, ROCE_CMD_TIME_CLASS_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to send CQ_CACHE_INVLD command, ret(%d), func_id(%d)\n",
+ __func__, ret, rdev->glb_func_id);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA is present(CQ_CACHE_INVLD), cqn(0x%x), func_id(%u)\n",
+ __func__, cq->cqn, rdev->glb_func_id);
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ /*
+ * 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;
+
+ return -1;
+ }
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return 0;
+}
+
+static void destroy_cq_user(struct roce3_cq *cq, struct ib_udata *udata)
+{
+ struct roce3_ucontext *context = rdma_udata_to_drv_context(
+ udata, struct roce3_ucontext, ibucontext);
+
+ roce3_db_unmap_user(context, &cq->db);
+ ib_umem_release(cq->umem);
+}
+
+int roce3_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce3_device *rdev = NULL;
+ struct roce3_cq *cq = NULL;
+ struct roce_cq_context *cqc_data = NULL;
+
+ if (ibcq == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibcq is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibcq->device);
+ cq = to_roce3_cq(ibcq);
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return ok), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_roce_cq_free;
+ }
+
+ /* Modify CQC to be owned by the software */
+ ret = roce3_cq_hw2sw(rdev, cq);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to modify CQC, ret(%d), func_id(%u), cqn(0x%x)\n",
+ __func__, ret, rdev->glb_func_id, cq->cqn);
+ return ret;
+ }
+
+ /* Send the cache out command */
+ ret = roce3_cq_cache_out(rdev, cq);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to modify cqc, ret(%d), func_id(%u)\n",
+ __func__, ret, rdev->glb_func_id);
+ return ret;
+ }
+
+ cqc_data = (struct roce_cq_context *)((void *)cq->cqm_cq->q_ctx_vaddr);
+ ret = roce3_check_cqc_data_state(rdev, cq, cqc_data, ROCE_CQ_STATE_CHECK_VALUE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: check cqc data state fail, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+err_roce_cq_free:
+ /* Release the MTT corresponding to cq_buf */
+ hmm_rdma_mtt_free(rdev->hwdev, &cq->buf.mtt, SERVICE_T_ROCE);
+
+ /*
+ * 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
+ */
+ hiudk_cqm_object_delete(rdev->hwdev, &cq->cqm_cq->object);
+
+ /*
+ * If it is user mode, you also need to cancel
+ * the mapping of the corresponding software DB
+ */
+ if (ibcq->uobject)
+ destroy_cq_user(cq, udata);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/dfx/roce_dfx.c b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx.c
new file mode 100644
index 0000000000000..ab9bee80989b7
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#ifdef __ROCE_DFX__
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+#include "hinic3_mt.h"
+
+#include "roce.h"
+#include "roce_cmd.h"
+#include "roce_pub_cmd.h"
+#include "roce_dfx.h"
+
+
+void roce3_dfx_clean_up(struct roce3_device *rdev)
+{
+#ifdef ROCE_PKT_CAP_EN
+ (void)roce3_dfx_stop_cap_pkt(rdev, NULL, NULL);
+#endif
+}
+
+int roce3_get_drv_version(struct roce3_device *rdev, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size)
+{
+ struct drv_version_info *ver_info = buf_out;
+ int rc;
+
+ if (!buf_out) {
+ pr_err("Buf_out is NULL.\n");
+ return -EINVAL;
+ }
+
+ if (*out_size != sizeof(*ver_info)) {
+ pr_err("Unexpect out buf size from user :%u, expect: %lu\n",
+ *out_size, sizeof(*ver_info));
+ return -EINVAL;
+ }
+
+ rc = snprintf(ver_info->ver, sizeof(ver_info->ver), "%s %s",
+ HIROCE3_DRV_VERSION, "2024-04-16_15:14:30");
+ if (rc == -1) {
+ pr_err("Snprintf roce version err\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int roce3_dfx_enable_bw_ctrl(struct roce3_device *rdev, struct roce3_bw_ctrl_inbuf *inbuf,
+ struct roce3_bw_ctrl_outbuf *outbuf)
+{
+ if (rdev->hw_info.hca_type == ROCE3_2_100G_HCA) {
+ inbuf->ctrl_param.cir = ROCE3_100G_CIR;
+ inbuf->ctrl_param.pir = ROCE3_100G_PIR;
+ inbuf->ctrl_param.cnp = ROCE3_100G_CNP;
+ } else {
+ inbuf->ctrl_param.cir = ROCE3_25G_CIR;
+ inbuf->ctrl_param.pir = ROCE3_25G_PIR;
+ inbuf->ctrl_param.cnp = ROCE3_25G_CNP;
+ }
+ return roce3_set_bw_ctrl_state(rdev, ROCE_BW_CTRL_EN, inbuf);
+}
+
+static int roce3_dfx_disable_bw_ctrl(struct roce3_device *rdev, struct roce3_bw_ctrl_inbuf *inbuf,
+ struct roce3_bw_ctrl_outbuf *outbuf)
+{
+ inbuf->ctrl_param.cir = 0;
+ inbuf->ctrl_param.pir = 0;
+ inbuf->ctrl_param.cnp = 0;
+ return roce3_set_bw_ctrl_state(rdev, ROCE_BW_CTRL_DIS, inbuf);
+}
+
+static int roce3_dfx_change_bw_ctrl_param(struct roce3_device *rdev,
+ struct roce3_bw_ctrl_inbuf *inbuf, struct roce3_bw_ctrl_outbuf *outbuf)
+{
+ return roce3_set_bw_ctrl_state(rdev, ROCE_BW_CTRL_RESET, inbuf);
+}
+
+static int roce3_dfx_query_bw_ctrl_param(struct roce3_device *rdev,
+ struct roce3_bw_ctrl_inbuf *inbuf, struct roce3_bw_ctrl_outbuf *outbuf)
+{
+ return roce3_query_bw_ctrl_state(rdev, &outbuf->bw_ctrl_param);
+}
+
+typedef int (*roce3_adm_dfx_bw_ctrl_func_t)(struct roce3_device *rdev,
+ struct roce3_bw_ctrl_inbuf *inbuf, struct roce3_bw_ctrl_outbuf *outbuf);
+
+/*lint -e26*/
+static roce3_adm_dfx_bw_ctrl_func_t g_roce3_adm_dfx_bw_ctrl_funcs[COMMON_CMD_VM_COMPAT_TEST] = {
+ [ROCE_CMD_ENABLE_BW_CTRL] = roce3_dfx_enable_bw_ctrl,
+ [ROCE_CMD_DISABLE_BW_CTRL] = roce3_dfx_disable_bw_ctrl,
+ [ROCE_CMD_CHANGE_BW_CTRL_PARAM] = roce3_dfx_change_bw_ctrl_param,
+ [ROCE_CMD_QUERY_BW_CTRL_PARAM] = roce3_dfx_query_bw_ctrl_param,
+};
+/*lint +e26*/
+
+int roce3_adm_dfx_bw_ctrl(struct roce3_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size)
+{
+ struct roce3_bw_ctrl_inbuf *inbuf = (struct roce3_bw_ctrl_inbuf *)buf_in;
+ struct roce3_bw_ctrl_outbuf *outbuf = (struct roce3_bw_ctrl_outbuf *)buf_out;
+ roce3_adm_dfx_bw_ctrl_func_t roce3_adm_dfx_bw_ctrl_func;
+
+ memset(buf_out, 0, sizeof(struct roce3_bw_ctrl_outbuf));
+ *out_size = sizeof(struct roce3_bw_ctrl_outbuf);
+
+ if (inbuf->cmd_type >= COMMON_CMD_VM_COMPAT_TEST) {
+ dev_err(rdev->hwdev_hdl, "Not support this type(%d)\n", inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ roce3_adm_dfx_bw_ctrl_func = g_roce3_adm_dfx_bw_ctrl_funcs[inbuf->cmd_type];
+ if (roce3_adm_dfx_bw_ctrl_func == NULL) {
+ dev_err(rdev->hwdev_hdl, "Not support this type(%d)\n", inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ return roce3_adm_dfx_bw_ctrl_func(rdev, inbuf, outbuf);
+}
+#endif /* __ROCE_DFX__ */
diff --git a/drivers/infiniband/hw/hiroce3/dfx/roce_dfx.h b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx.h
new file mode 100644
index 0000000000000..b61f6fa9702b8
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx.h
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_DFX_H
+#define ROCE_DFX_H
+
+#include <linux/types.h>
+
+#include "hinic3_rdma.h"
+
+#include "roce_sysfs.h"
+#include "roce.h"
+#include "roce_verbs_cmd.h"
+#include "rdma_context_format.h"
+
+#ifdef ROCE_PKT_CAP_EN
+#include "roce_dfx_cap.h"
+#endif
+
+#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
+
+struct roce3_mpt_query_outbuf {
+ struct roce_mpt_context mpt_entry;
+};
+
+#define roce3_dfx_print pr_info
+
+struct roce3_dfx_query_inbuf {
+ u32 cmd_type;
+ /*lint -e658*/
+ union {
+ u32 qpn;
+ u32 cqn;
+ u32 srqn;
+ u32 mpt_key;
+ u32 gid_index;
+ struct {
+ u32 qpn;
+ u32 cqn;
+ } query_pi_ci;
+ };
+ /*lint +e658*/
+};
+
+struct roce3_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 roce3_dfx_qp_count {
+ u32 qp_alloced;
+ u32 qp_deleted;
+ u32 qp_alive;
+};
+
+union roce3_dfx_query_outbuf {
+ struct roce_qp_context qp_ctx;
+ struct roce_cq_context cq_ctx;
+ struct roce_srq_context srq_ctx;
+ struct roce_mpt_context mpt;
+ struct rdma_gid_entry gid_entry;
+ struct roce3_dfx_pi_ci pi_ci;
+ struct roce3_dfx_qp_count qp_count;
+ u32 algo_type;
+};
+
+enum roce3_bw_ctrl_cmd_e {
+ ROCE_BW_CTRL_DIS,
+ ROCE_BW_CTRL_EN,
+ ROCE_BW_CTRL_RESET
+};
+struct rdma_gid_query_outbuf {
+ struct rdma_gid_entry gid_entry;
+};
+
+struct roce3_bw_ctrl_inbuf {
+ u32 cmd_type;
+ struct {
+ u32 cir;
+ u32 pir;
+ u32 cnp;
+ } ctrl_param;
+};
+
+struct roce3_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 roce3_bw_ctrl_outbuf {
+ struct roce3_bw_ctrl_param bw_ctrl_param;
+};
+
+enum roce3_dfx_io_cmd_type {
+ ROCE_IO_CTRL_DIS,
+ ROCE_IO_CTRL_EN
+};
+
+struct roce3_dfx_io_alarm {
+ enum roce3_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 roce3_dfx_io_inbuf {
+ u32 cmd_type;
+ struct roce3_dfx_io_alarm io_alarm;
+};
+
+struct roce3_dfx_io_outbuf {
+ struct roce3_dfx_io_alarm io_alarm;
+};
+
+int roce3_get_drv_version(struct roce3_device *rdev, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size);
+int roce3_adm_dfx_query(struct roce3_device *rdev, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size);
+int roce3_adm_dfx_bw_ctrl(struct roce3_device *rdev, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size);
+void roce3_dfx_clean_up(struct roce3_device *rdev);
+
+void *global_roce3_io_alarm_va_get(void);
+
+void global_roce3_io_alarm_va_set(u64 va);
+
+void global_roce3_io_alarm_pa_set(dma_addr_t pa);
+
+dma_addr_t global_roce3_io_alarm_pa_get(void);
+
+int roce3_dfx_cmd_query_qp(struct roce3_device *rdev, u32 qpn, struct roce_qp_context *qp_ctx);
+
+int roce3_dfx_cmd_query_cq(struct roce3_device *rdev, u32 cqn, struct roce_cq_context *cq_ctx);
+
+int roce3_dfx_cmd_query_srq(struct roce3_device *rdev, u32 srqn, struct roce_srq_context *srq_ctx);
+
+#endif // __ROCE_DFX_H__
diff --git a/drivers/infiniband/hw/hiroce3/dfx/roce_dfx_cap.c b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx_cap.c
new file mode 100644
index 0000000000000..cdc75962f03fe
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx_cap.c
@@ -0,0 +1,688 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#ifdef ROCE_PKT_CAP_EN
+
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/etherdevice.h>
+#include <rdma/ib_verbs.h>
+
+#include "hinic3_hw.h"
+
+#include "roce.h"
+#include "roce_cmd.h"
+#include "roce_pub_cmd.h"
+#include "roce_dfx.h"
+#include "roce_dfx_cap.h"
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+static struct roce3_cap_block_num_attr g_nattr[8] = {
+ { .block_num_idx = 0, .shift = 4, .num = 16 },
+ { .block_num_idx = 1, .shift = 5, .num = 32 },
+ { .block_num_idx = 2, .shift = 6, .num = 64 },
+ { .block_num_idx = 3, .shift = 7, .num = 128 },
+ { .block_num_idx = 4, .shift = 8, .num = 256 },
+ { .block_num_idx = 5, .shift = 9, .num = 512 },
+ { .block_num_idx = 6, .shift = 10, .num = 1024 },
+ { .block_num_idx = 7, .shift = 11, .num = 2048 },
+};
+
+struct roce3_pkt_cap_info g_roce3_cap_info = {
+ .cap_status = ROCE_CAPTURE_STOP,
+ .cap_mode = 1,
+ .poll_ci = 0,
+ .rdev = NULL,
+ .func_id = 0,
+ // Configurable, currently using 4, when modifying,
+ // the size of cfg bl needs to be modified synchronously
+ .block_num_idx = 4,
+ .mode = 0,
+ .qp_list_cnt = 0,
+ .qp_list_head = LIST_HEAD_INIT(g_roce3_cap_info.qp_list_head),
+};
+
+static void roce3_stop_thread(struct sdk_thread_info *thread_info)
+{
+ if (thread_info->thread_obj) {
+ (void)kthread_stop(thread_info->thread_obj);
+ thread_info->thread_obj = NULL;
+ }
+}
+
+static int roce3_linux_thread_func(void *thread)
+{
+ struct sdk_thread_info *info = (struct sdk_thread_info *)thread;
+
+ while (!kthread_should_stop()) {
+ info->thread_fn(info->data);
+
+ // Warning: kernel thread should reschedule
+ schedule();
+ }
+
+ return 0;
+}
+#ifdef ROCE_BONDING_EN
+static struct net_device *roce3_get_roce_bond_ndev(struct roce3_device *rdev)
+{
+ struct bonding *bond = NULL;
+ struct slave *slave = NULL;
+ struct net_device *netdev = rdev->ndev;
+
+ if (netif_is_lag_master(netdev)) {
+ bond = netdev_priv(netdev);
+ } else if (netif_is_bond_slave(netdev)) {
+ rcu_read_lock();
+ slave = bond_slave_get_rcu(netdev);
+ rcu_read_unlock();
+ if (slave)
+ bond = bond_get_bond_by_slave(slave);
+ }
+
+ if ((bond == NULL) || (bond->dev == NULL)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Bond/bond->dev is NULL\n", __func__);
+ return NULL;
+ }
+
+ return bond->dev;
+}
+#endif
+static void roce3_netif_skb_info(struct roce3_device *rdev, const char *pkt, u8 len)
+{
+ struct sk_buff *skb = NULL;
+ unsigned char *packet = NULL;
+ struct net_device *netdev = rdev->ndev;
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev)) {
+ netdev = roce3_get_roce_bond_ndev(rdev);
+ if (netdev == NULL) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to get roce_bond ndev\n",
+ __func__);
+ return;
+ }
+ }
+#endif
+ /* alloc skb and set skb->dev */
+ skb = netdev_alloc_skb_ip_align(netdev, CAP_NUM_PER_BLOCK + 1);
+ if (unlikely(skb == NULL)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc skb\n", __func__);
+ return;
+ }
+
+ skb_reserve(skb, CAP_COUNTER_TWO);
+
+ /* put space for pkt */
+ packet = (unsigned char *)skb_put(skb, len);
+ if (packet == NULL) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to get packet\n", __func__);
+ kfree_skb(skb);
+ return;
+ }
+
+ /* copy pkt hdr */
+ memcpy(packet, pkt, len);
+
+ prefetchw(skb->data);
+
+ /* resolve protocol and type */
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ /* force to host */
+ skb->pkt_type = 0;
+
+ netif_receive_skb(skb);
+}
+
+static int roce3_set_cap_func_disable(struct roce3_device *rdev)
+{
+ int ret;
+
+ ret = hinic3_set_func_capture_en(rdev->hwdev, rdev->glb_func_id, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to set capture disable, ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce3_create_thread(struct sdk_thread_info *thread_info)
+{
+ thread_info->thread_obj = kthread_run(roce3_linux_thread_func,
+ thread_info, thread_info->name);
+ if (!thread_info->thread_obj) {
+ pr_err("[ROCE, ERR] %s: Failed to create thread\n", __func__);
+ return (-EFAULT);
+ }
+
+ return 0;
+}
+
+static int roce3_set_cap_func_en(struct roce3_device *rdev)
+{
+ int ret;
+
+ ret = hinic3_set_func_capture_en(rdev->hwdev, rdev->glb_func_id, 1);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to set capture func enable, ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce3_pkt_cap_poll_check(struct roce3_device *rdev)
+{
+ if (rdev == NULL) {
+ pr_err("[ROCE] %s: Rdev is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ if (rdev->hwdev == NULL) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Rdev->hwdev is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ if (g_roce3_cap_info.cap_status == ROCE_CAPTURE_STOP) {
+ /* Don't add log here */
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+static int roce3_cap_hdr_vld(const roce3_cap_hdr_u *cap_hdr)
+{
+ return (cap_hdr->value != 0);
+}
+
+static void roce3_fill_cap_cfg(struct roce3_dfx_cap_cfg_tbl *cfg_info,
+ u32 state, u32 ci_index, u8 mode)
+{
+ cfg_info->ci_index = ci_index;
+
+ cfg_info->dw1.bs.cap_block_num_shift =
+ (u8)g_nattr[g_roce3_cap_info.block_num_idx].shift; // 8
+ cfg_info->dw1.bs.cap_mode = (u8)g_roce3_cap_info.cap_mode;
+ cfg_info->dw1.bs.qp_mode = mode;
+
+ cfg_info->dw2.bs.state = state;
+ cfg_info->dw2.bs.cap_func = g_roce3_cap_info.func_id;
+
+ cfg_info->maxnum = g_nattr[g_roce3_cap_info.block_num_idx].num * CAP_NUM_PER_BLOCK;
+}
+
+static void roce3_pkt_cap_poll_hdr(struct roce3_pkt_cap_info *cap_info,
+ union roce3_cap_hdr **cap_hdr, union roce3_cap_hdr *hdr_value)
+{
+ u32 lt_index;
+ u32 lt_offset;
+ u8 sel;
+ u32 block_num_per_entry = g_nattr[g_roce3_cap_info.block_num_idx].num;
+ u32 block_num_shift = g_nattr[g_roce3_cap_info.block_num_idx].shift;
+
+ /* resolve index and offset */
+ lt_index = (((cap_info->poll_ci) / block_num_per_entry) % CAP_PA_TBL_ENTRY_NUM);
+ lt_offset = ((cap_info->poll_ci) % (block_num_per_entry >> 1));
+ sel = ((cap_info->poll_ci >> (block_num_shift - 1)) & 0x1);
+
+ *cap_hdr = (roce3_cap_hdr_u *)(cap_info->que_addr[sel][0][lt_index] +
+ (lt_offset * CAP_PKT_ITEM_SIZE));
+
+ hdr_value->value = (*cap_hdr)->value;
+ /* First, execute big endian and small endian switch operation for ctrl information */
+ hdr_value->value = ntohl(hdr_value->value);
+}
+
+static void roce3_pkt_cap_poll(void *data)
+{
+ int ret;
+ u32 count = 0;
+ struct roce3_dfx_cap_cfg_tbl cfg_info = { 0 };
+ union roce3_cap_hdr hdr_value = { { 0 } };
+ struct roce3_pkt_cap_info *cap_info = (struct roce3_pkt_cap_info *)data;
+ struct roce3_device *rdev = cap_info->rdev;
+ union roce3_cap_hdr *cap_hdr = NULL;
+
+ if (roce3_pkt_cap_poll_check(rdev) != 0)
+ return;
+
+ roce3_pkt_cap_poll_hdr(cap_info, &cap_hdr, &hdr_value);
+
+ if (roce3_cap_hdr_vld(&hdr_value) == 0)
+ return;
+
+ do {
+ if (g_roce3_cap_info.cap_status == ROCE_CAPTURE_STOP) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Cap is stopped\n", __func__);
+ return;
+ }
+
+ roce3_netif_skb_info(rdev, ((u8 *)cap_hdr + CAP_HDR_OFFSET +
+ hdr_value.cap_ctrl_info.pad), CAP_SKB_LEN);
+
+ /* reset to 0 */
+ cap_hdr->value = 0;
+ cap_info->poll_ci++;
+
+ if (g_roce3_cap_info.cap_mode != 0) {
+ count++;
+ if (count >= (FILL_CAP_CFG_PKT_NUM)) {
+ roce3_fill_cap_cfg(&cfg_info, 0, cap_info->poll_ci, 0);
+
+ (void)roce3_set_cap_cfg(rdev->hwdev, CAP_PA_TBL_ENTRY_NUM,
+ (u32 *)&cfg_info);
+
+ count = 0;
+ }
+ }
+
+ roce3_pkt_cap_poll_hdr(cap_info, &cap_hdr, &hdr_value);
+
+ if (unlikely(kthread_should_stop()))
+ break;
+
+ schedule();
+ } while (roce3_cap_hdr_vld(&hdr_value) != 0);
+
+ roce3_fill_cap_cfg(&cfg_info, 0, cap_info->poll_ci, 0);
+
+ ret = roce3_set_cap_cfg(rdev->hwdev, CAP_PA_TBL_ENTRY_NUM, (u32 *)&cfg_info);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to set cap cfg, ret(%d)\n",
+ __func__, ret);
+ return;
+ }
+}
+
+static int roce3_dfx_dma_alloc_addr(struct roce3_device *rdev, int cap_index, int que_index,
+ struct roce3_dfx_cap_tbl *pa_info)
+{
+ u64 v_addr;
+ u64 p_addr = 0;
+
+ v_addr = dma_alloc_coherent(&rdev->pdev->dev,
+ (unsigned long)(CAP_PKT_ITEM_SIZE *
+ ((g_nattr[g_roce3_cap_info.block_num_idx].num) >> 1)), &p_addr, GFP_KERNEL);
+ if (v_addr == 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to alloc v_addr for que_index %d\n",
+ __func__, que_index);
+ return -ENOMEM;
+ }
+
+ g_roce3_cap_info.que_addr[que_index][0][cap_index] = v_addr;
+ g_roce3_cap_info.que_addr[que_index][1][cap_index] = p_addr;
+
+ pa_info->pa[que_index].wr_init_pc_h32 =
+ (u32)((p_addr >> CAP_ADDR_COMBIN_SHIFT) & 0xffffffff);
+ pa_info->pa[que_index].wr_init_pc_l32 = (u32)(p_addr & 0xffffffff);
+
+ dev_info(rdev->hwdev_hdl, "[ROCE] %s: v_addr que_index(%d), cap_index(%d), PA:0x%x %x\n",
+ __func__, que_index, cap_index,
+ pa_info->pa[que_index].wr_init_pc_h32, pa_info->pa[que_index].wr_init_pc_l32);
+
+ return 0;
+}
+
+static void roce3_dfx_dma_free_addr(struct roce3_device *rdev, int cap_index, int que_index)
+{
+ u64 v_addr;
+ u64 p_addr;
+
+ v_addr = g_roce3_cap_info.que_addr[que_index][0][cap_index];
+ p_addr = g_roce3_cap_info.que_addr[que_index][1][cap_index];
+ dma_free_coherent(&rdev->pdev->dev,
+ (unsigned long)(CAP_PKT_ITEM_SIZE *
+ ((g_nattr[g_roce3_cap_info.block_num_idx].num) >> 1)), (void *)v_addr,
+ (dma_addr_t)p_addr);
+}
+
+static int roce3_dfx_alloc_mem_for_one_cap(struct roce3_device *rdev, int cap_index)
+{
+ struct roce3_dfx_cap_tbl pa_info;
+ int ret;
+
+ memset(&pa_info, 0x0, sizeof(pa_info));
+
+ ret = roce3_dfx_dma_alloc_addr(rdev, cap_index, 0, &pa_info);
+ if (ret != 0)
+ return ret;
+
+ ret = roce3_dfx_dma_alloc_addr(rdev, cap_index, 1, &pa_info);
+ if (ret != 0)
+ goto err_dma_mem_alloc_free_1;
+
+ ret = roce3_set_cap_cfg(rdev->hwdev, (u16)cap_index, (u32 *)&pa_info);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to set cap cfg, ret(%d)\n",
+ __func__, ret);
+ goto err_dma_mem_alloc_free;
+ }
+
+ return 0;
+
+err_dma_mem_alloc_free:
+ roce3_dfx_dma_free_addr(rdev, cap_index, 1);
+
+err_dma_mem_alloc_free_1:
+ roce3_dfx_dma_free_addr(rdev, cap_index, 0);
+ return ret;
+}
+
+static void roce3_dfx_free_mem_for_one_cap(struct roce3_device *rdev, int cap_index)
+{
+ roce3_dfx_dma_free_addr(rdev, cap_index, 1);
+ roce3_dfx_dma_free_addr(rdev, cap_index, 0);
+}
+
+static int roce3_dfx_alloc_cap(struct roce3_device *rdev)
+{
+ u32 counter, times;
+ int ret;
+ int i;
+
+ /* alloc lt memory resource */
+ for (i = 0; i < CAP_PA_TBL_ENTRY_NUM; i++) {
+ ret = roce3_dfx_alloc_mem_for_one_cap(rdev, i);
+ if (ret != 0)
+ goto err_dma_mem_alloc_free;
+ }
+
+ for (times = 0; times < CLEAR_CAP_TRYING_TIMES; times++) {
+ if (times == CLEAR_CAP_TRYING_TIMES - 1) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to clear pi\n", __func__);
+ goto err_dma_mem_alloc_free;
+ }
+
+ /* clear pi */
+ ret = roce3_clear_cap_counter(rdev->hwdev, ROCE_CAP_COUNTER_INDEX, &counter);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to read counter(lt index %x), ret(%d)\n",
+ __func__, ROCE_CAP_COUNTER_INDEX, ret);
+ goto err_dma_mem_alloc_free;
+ }
+
+ if (counter == 0)
+ break;
+
+ msleep(CLEAR_SLEEP_TIME);
+ }
+
+ return 0;
+
+err_dma_mem_alloc_free:
+ for (i--; i >= 0; i--)
+ roce3_dfx_free_mem_for_one_cap(rdev, i);
+
+ return ret;
+}
+
+static void roce3_dfx_free_cap(struct roce3_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < CAP_PA_TBL_ENTRY_NUM; i++)
+ roce3_dfx_free_mem_for_one_cap(rdev, i);
+}
+
+static void roce3_dfx_init_g_cap_info(struct roce3_device *rdev,
+ const struct roce3_dfx_capture_inbuf *inbuf)
+{
+ u32 mode = inbuf->mode;
+
+ g_roce3_cap_info.func_id = rdev->glb_func_id;
+ g_roce3_cap_info.task.data = &g_roce3_cap_info;
+ g_roce3_cap_info.task.thread_fn = roce3_pkt_cap_poll;
+ g_roce3_cap_info.task.name = "capture_thread";
+ g_roce3_cap_info.rdev = rdev;
+ g_roce3_cap_info.poll_ci = 0;
+ g_roce3_cap_info.block_num_per_entry = g_nattr[g_roce3_cap_info.block_num_idx].num;
+ g_roce3_cap_info.maxnum =
+ (g_nattr[g_roce3_cap_info.block_num_idx].num) * CAP_PA_TBL_ENTRY_NUM;
+ g_roce3_cap_info.mode = mode;
+ g_roce3_cap_info.qp_list_cnt = 0;
+}
+
+static int roce3_dfx_start_cap_pkt(struct roce3_device *rdev,
+ const struct roce3_dfx_capture_inbuf *inbuf, union roce3_dfx_capture_outbuf *outbuf)
+{
+ struct roce3_dfx_cap_cfg_tbl cfg_info;
+ int ret;
+
+ mutex_lock(&cap_mutex);
+ if (g_roce3_cap_info.cap_status == ROCE_CAPTURE_START) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Capture is running\n", __func__);
+ mutex_unlock(&cap_mutex);
+ return (-EBUSY);
+ }
+
+ ret = roce3_dfx_alloc_cap(rdev);
+ if (ret != 0) {
+ mutex_unlock(&cap_mutex);
+ return ret;
+ }
+
+ roce3_dfx_init_g_cap_info(rdev, inbuf);
+
+ memset(&cfg_info, 0, sizeof(cfg_info));
+ roce3_fill_cap_cfg(&cfg_info, 0, 0, 0);
+
+ ret = roce3_set_cap_cfg(rdev->hwdev, CAP_PA_TBL_ENTRY_NUM, (u32 *)&cfg_info);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to set cap cfg, ret(%d)\n",
+ __func__, ret);
+ goto err_alloc_cap;
+ }
+
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: roce create thread\n", __func__);
+ ret = roce3_create_thread(&(g_roce3_cap_info.task));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to create thread, ret(%d)\n",
+ __func__, ret);
+ goto err_alloc_cap;
+ }
+
+ ret = roce3_set_cap_func_en(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to set cap enable, ret(%d)\n",
+ __func__, ret);
+ goto err_thread_release;
+ }
+
+ g_roce3_cap_info.cap_status = ROCE_CAPTURE_START;
+ INIT_LIST_HEAD(&g_roce3_cap_info.qp_list_head);
+ mutex_unlock(&cap_mutex);
+
+ dev_info(rdev->hwdev_hdl, "[ROCE] %s: Start to capture pkt, func(%u)\n",
+ __func__, g_roce3_cap_info.func_id);
+ return 0;
+
+err_thread_release:
+ roce3_stop_thread(&(g_roce3_cap_info.task));
+ msleep(CAP_STOP_SLEEP_TIME);
+
+err_alloc_cap:
+ roce3_dfx_free_cap(rdev);
+
+ g_roce3_cap_info.cap_status = ROCE_CAPTURE_STOP;
+ mutex_unlock(&cap_mutex);
+
+ return ret;
+}
+
+static int roce3_clear_cap_counter_encap(struct roce3_device *rdev, u16 lt_index)
+{
+ int ret;
+ u32 counter = 0;
+ u32 times;
+
+ for (times = 0; times < CLEAR_CAP_TRYING_TIMES; times++) {
+ if (times == CLEAR_CAP_TRYING_TIMES - 1) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to clear pi\n", __func__);
+ return -EFAULT;
+ }
+
+ ret = roce3_clear_cap_counter(rdev->hwdev, lt_index, &counter);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to clear cap counter(lt index 1), ret(%d)\n",
+ __func__, ret);
+ return -EFAULT;
+ }
+
+ if (counter == 0)
+ break;
+
+ msleep(CLEAR_SLEEP_TIME);
+ }
+
+ return 0;
+}
+
+int roce3_dfx_stop_cap_pkt(struct roce3_device *rdev, const struct roce3_dfx_capture_inbuf *inbuf,
+ union roce3_dfx_capture_outbuf *outbuf)
+{
+ int ret = 0;
+
+ dev_info(rdev->hwdev_hdl, "[ROCE] %s: start to stop cap,\n", __func__);
+
+ mutex_lock(&cap_mutex);
+ if (g_roce3_cap_info.cap_status != ROCE_CAPTURE_START) { // 1:RUNNING
+ mutex_unlock(&cap_mutex);
+ return 0;
+ }
+
+ if (g_roce3_cap_info.func_id != rdev->glb_func_id) {
+ mutex_unlock(&cap_mutex);
+ return 0;
+ }
+
+ roce3_stop_thread(&(g_roce3_cap_info.task));
+
+ /* stop cap */
+ ret = roce3_set_cap_func_disable(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to set cap enable, ret(%d)\n",
+ __func__, ret);
+ ret = -EFAULT;
+ goto err;
+ }
+
+ msleep(CAP_STOP_SLEEP_TIME);
+
+ /* release lt mem resource */
+ roce3_dfx_free_cap(rdev);
+
+ /* lt index_1 */
+ ret = roce3_clear_cap_counter_encap(rdev, ROCE_CAP_COUNTER_INDEX);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Failed to clear pi(lt index %x), ret(%d)\n",
+ __func__, ROCE_CAP_COUNTER_INDEX, ret);
+ goto err;
+ }
+
+ g_roce3_cap_info.cap_status = ROCE_CAPTURE_STOP;
+ g_roce3_cap_info.poll_ci = 0;
+ g_roce3_cap_info.func_id = 0;
+ g_roce3_cap_info.rdev = NULL;
+ dev_info(rdev->hwdev_hdl, "[ROCE] %s: Stop capture pkt, func(%d)\n",
+ __func__, rdev->glb_func_id);
+
+err:
+ mutex_unlock(&cap_mutex);
+ return ret;
+}
+
+static int roce3_dfx_query_cap_pkt(struct roce3_device *rdev,
+ const struct roce3_dfx_capture_inbuf *inbuf, union roce3_dfx_capture_outbuf *outbuf)
+{
+ int ret;
+ u32 pi = 0;
+ u32 total = 0;
+ struct roce3_dfx_cap_cfg_tbl cfg_info;
+ struct roce3_dfx_capture_info *capture_info = &outbuf->capture_info;
+
+ memset(&cfg_info, 0, sizeof(cfg_info));
+ ret = roce3_get_cap_cfg(rdev->hwdev, CAP_NUM_PER_BLOCK, (u32 *)&cfg_info);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to read table, ret(%d)\n",
+ __func__, ret);
+ return -EFAULT;
+ }
+
+ ret = roce3_read_cap_counter(rdev->hwdev, CAP_COUNTER_TWO, &total);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to read counter(lt index 2), ret(%d)\n",
+ __func__, ret);
+ return -EFAULT;
+ }
+
+ ret = roce3_read_cap_counter(rdev->hwdev, ROCE_CAP_COUNTER_INDEX, &pi);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to read counter(lt index %x), ret(%d)\n",
+ __func__, ROCE_CAP_COUNTER_INDEX, ret);
+ return -EFAULT;
+ }
+
+ capture_info->cap_status = g_roce3_cap_info.cap_status;
+ capture_info->cap_mode = cfg_info.dw1.bs.cap_mode;
+ capture_info->qp_mode = cfg_info.dw1.bs.qp_mode;
+ capture_info->cap_block_num_shift = cfg_info.dw1.bs.cap_block_num_shift;
+ capture_info->cap_func = cfg_info.dw2.bs.cap_func;
+ capture_info->cap_state = cfg_info.dw2.bs.state;
+ capture_info->cap_max_num = cfg_info.maxnum;
+ capture_info->cap_ci = g_roce3_cap_info.poll_ci;
+ capture_info->cap_pi = pi;
+ capture_info->cap_total = total;
+
+ return 0;
+}
+
+typedef int (*roce3_adm_dfx_capture_func_t)(struct roce3_device *rdev,
+ const struct roce3_dfx_capture_inbuf *inbuf, union roce3_dfx_capture_outbuf *outbuf);
+
+/*lint -e26*/
+static roce3_adm_dfx_capture_func_t g_roce3_adm_dfx_capture_funcs[COMMON_CMD_VM_COMPAT_TEST] = {
+ [ROCE_CMD_START_CAP_PACKET] = roce3_dfx_start_cap_pkt,
+ [ROCE_CMD_STOP_CAP_PACKET] = roce3_dfx_stop_cap_pkt,
+ [ROCE_CMD_QUERY_CAP_INFO] = roce3_dfx_query_cap_pkt,
+ [ROCE_CMD_ENABLE_QP_CAP_PACKET] = NULL,
+ [ROCE_CMD_DISABLE_QP_CAP_PACKET] = NULL,
+ [ROCE_CMD_QUERY_QP_CAP_INFO] = NULL,
+};
+/*lint +e26*/
+
+int roce3_adm_dfx_capture(struct roce3_device *rdev, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size)
+{
+ int ret;
+ const struct roce3_dfx_capture_inbuf *inbuf = (struct roce3_dfx_capture_inbuf *)buf_in;
+ union roce3_dfx_capture_outbuf *outbuf = (union roce3_dfx_capture_outbuf *)buf_out;
+ roce3_adm_dfx_capture_func_t roce3_adm_dfx_capture_func;
+
+ memset(buf_out, 0, sizeof(union roce3_dfx_capture_outbuf));
+ *out_size = sizeof(union roce3_dfx_capture_outbuf);
+
+ if (inbuf->cmd_type >= COMMON_CMD_VM_COMPAT_TEST) {
+ dev_err(rdev->hwdev_hdl, "Not support this type(%d)\n", inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ roce3_adm_dfx_capture_func = g_roce3_adm_dfx_capture_funcs[inbuf->cmd_type];
+ if (roce3_adm_dfx_capture_func == NULL) {
+ dev_err(rdev->hwdev_hdl, "Not support this type(%d)\n", inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ return roce3_adm_dfx_capture_func(rdev, inbuf, outbuf);
+}
+
+#endif /* ROCE_PKT_CAP_EN */
diff --git a/drivers/infiniband/hw/hiroce3/dfx/roce_dfx_cap.h b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx_cap.h
new file mode 100644
index 0000000000000..acd3c407c5036
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx_cap.h
@@ -0,0 +1,181 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_DFX_CAP_H
+#define ROCE_DFX_CAP_H
+
+#include <linux/types.h>
+
+#include "hinic3_rdma.h"
+
+#include "roce_sysfs.h"
+#include "roce.h"
+
+#define CAP_PKT_ITEM_SIZE 128
+
+#define CAP_NUM_PER_BLOCK 255
+
+#define CAP_SKB_LEN 120
+
+#define CAP_HDR_OFFSET 4
+
+#define FILL_CAP_CFG_PKT_NUM 8192
+
+#define CAP_LOOP 255
+
+#define CLEAR_MAX_TRY_TIME 10
+
+#define CLEAR_SLEEP_TIME 2
+
+#define CAP_STOP_SLEEP_TIME 50
+
+#define CAP_COUNTER_TWO 2
+
+#define CAP_PA_TBL_ENTRY_NUM 255
+
+#define CAP_ADDR_COMBIN_SHIFT 32
+
+#define CLEAR_CAP_TRYING_TIMES 10
+
+#define ROCE_CAP_COUNTER_INDEX 0x39ff
+
+union roce3_cap_hdr {
+ struct {
+ u32 rsvd : 16;
+ u32 pad : 8;
+ u32 rsvd0 : 2;
+ u32 col_num : 4;
+ u32 tx_rx : 1;
+ u32 vld : 1;
+ } cap_ctrl_info;
+ u32 value;
+};
+
+struct roce3_dfx_cap_pa_entry {
+ u32 wr_init_pc_h32;
+ u32 wr_init_pc_l32;
+};
+
+struct roce3_dfx_cap_tbl {
+ struct roce3_dfx_cap_pa_entry pa[2];
+};
+
+struct roce3_dfx_cap_cfg_tbl {
+ u32 ci_index;
+
+ union {
+ struct {
+ /*
+ * Driver configurate bit offset by the number of per
+ * pa block, for example, 7 means 128, 8 means 256
+ */
+ u8 cap_block_num_shift;
+ u8 cap_mode; /* Packet Capture mode */
+ u8 qp_mode; /* according to qp Packet Capture */
+ u8 rsvd; /* reserved */
+ } bs;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+ u32 state : 8; /* Packet Capture rate control */
+ u32 rsvd : 8;
+ u32 cap_func : 16; /* Packet Capture function */
+ } bs;
+ u32 value;
+ } dw2;
+
+ u32 maxnum;
+};
+
+struct roce3_qp_cap_pkt_list {
+ u32 xid;
+ struct list_head list;
+};
+
+struct roce3_cap_block_num_attr {
+ u32 block_num_idx;
+ u32 shift;
+ u32 num;
+};
+
+struct sdk_thread_info {
+ struct task_struct *thread_obj;
+ char *name;
+ void (*thread_fn)(void *unused);
+ void *thread_event;
+ void *data;
+};
+
+struct roce3_pkt_cap_info {
+ struct roce3_device *rdev;
+ u32 func_id;
+ u32 poll_ci;
+ u32 cap_mode; /* 0 : drop mode 1: overwrite mode */
+ u32 mode; /* 0 : func mode 1: qp mode */
+ u32 cap_status; /* 0 : stopped 1: running */
+ u32 block_num_idx;
+ u32 block_num_per_entry;
+ u32 maxnum;
+ struct sdk_thread_info task;
+ char thread_name[20];
+ u64 que_addr[2][2][256];
+ struct list_head qp_list_head; /* Based on qp Packet Capture linked list */
+ u32 qp_list_cnt;
+};
+
+#define ROCE_DFX_MAX_CAPTURE_QP_NUM 511
+
+struct roce3_qp_cap_pkt {
+ __be32 xid;
+};
+
+struct roce3_dfx_capture_inbuf {
+ u32 cmd_type;
+ u32 mode;
+ u32 qpn;
+};
+
+struct roce3_dfx_capture_info {
+ u32 cap_status;
+ u32 cap_mode;
+ u32 qp_mode;
+ u32 cap_block_num_shift;
+ u32 cap_func;
+ u32 cap_state;
+ u32 cap_max_num;
+ u32 cap_pi;
+ u32 cap_ci;
+ u32 cap_total;
+};
+
+struct roce3_dfx_qp_capture_info {
+ u32 qp_num;
+ u32 qpn[ROCE_DFX_MAX_CAPTURE_QP_NUM];
+};
+
+union roce3_dfx_capture_outbuf {
+ struct roce3_dfx_capture_info capture_info;
+ struct roce3_dfx_qp_capture_info qp_capture_info;
+};
+
+enum roce3_dfx_capture_mode {
+ ROCE_CAPTURE_MODE_CAP_FUNC = 0,
+ ROCE_CAPTURE_MODE_CAP_QP,
+};
+
+enum roce3_dfx_capture_state {
+ ROCE_CAPTURE_START = 0,
+ ROCE_CAPTURE_STOP,
+};
+
+extern int hinic3_set_func_capture_en(void *hwdev, u16 func_id, bool cap_en);
+
+int roce3_adm_dfx_capture(struct roce3_device *rdev, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size);
+int roce3_dfx_stop_cap_pkt(struct roce3_device *rdev, const struct roce3_dfx_capture_inbuf *inbuf,
+ union roce3_dfx_capture_outbuf *outbuf);
+static DEFINE_MUTEX(cap_mutex);
+
+#endif /* ROCE_DFX_CAP_H */
diff --git a/drivers/infiniband/hw/hiroce3/dfx/roce_dfx_query.c b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx_query.c
new file mode 100644
index 0000000000000..1058ba0ac5b81
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/dfx/roce_dfx_query.c
@@ -0,0 +1,643 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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 "roce_compat.h"
+#include "roce.h"
+#include "roce_dfx.h"
+#include "roce_srq.h"
+#include "roce_qp.h"
+#include "roce_cq.h"
+#include "hinic3_hw.h"
+#include "roce_cmd.h"
+#include "roce_pub_cmd.h"
+#include "roce_cqm_cmd.h"
+
+int roce3_dfx_cmd_query_qp(struct roce3_device *rdev, u32 qpn, struct roce_qp_context *qp_ctx)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct tag_roce_cmd_qp_query *qp_query_inbuf = NULL;
+ struct roce3_qp_query_outbuf *qp_query_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_qp_query), &cqm_cmd_outbuf,
+ (u16)sizeof(struct roce3_qp_query_outbuf));
+ if (ret != 0) {
+ roce3_dfx_print("Failed to alloc cqm_cmd_inoutbuf, ret=%d", ret);
+ return ret;
+ }
+
+ qp_query_inbuf = (struct tag_roce_cmd_qp_query *)cqm_cmd_inbuf->buf;
+ qp_query_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ qp_query_inbuf->com.index = cpu_to_be32(qpn);
+
+ if ((rdev->cfg_info.lb_en != 0) && (rdev->cfg_info.lb_mode == ROCE_LB_MODE_1)) {
+ u8 cos = qpn & 0x3;
+
+ roce3_dfx_print("%s: lb_mode1 func_id(%d) qpn:%u cos:%u\n",
+ __func__, rdev->glb_func_id, qpn, cos);
+ ret = cqm_lb_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_QUERY_QP,
+ cos, cqm_cmd_inbuf, cqm_cmd_outbuf,
+ NULL, ROCE_CMD_TIME_CLASS_B, HINIC3_CHANNEL_ROCE);
+ } else {
+ roce3_dfx_print("%s: Not lb_mode1 func_id(%d) qpn:%u\n",
+ __func__, rdev->glb_func_id, qpn);
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_QUERY_QP,
+ cqm_cmd_inbuf, cqm_cmd_outbuf, NULL,
+ ROCE_CMD_TIME_CLASS_B, HINIC3_CHANNEL_ROCE);
+ }
+
+ if (ret != 0) {
+ roce3_dfx_print("Failed to send cmd QUERY_QP");
+ ret = -1;
+ goto out;
+ }
+
+ qp_query_outbuf = (struct roce3_qp_query_outbuf *)cqm_cmd_outbuf->buf;
+ memcpy(qp_ctx, &qp_query_outbuf->qpc, sizeof(struct roce_qp_context));
+out:
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+ return ret;
+}
+
+static int roce3_dfx_get_dev_algo(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ u32 cc_algo;
+ struct roce3_ecn_ctx ecn_ctx;
+ u32 *algo_type = &outbuf->algo_type;
+
+ if (rdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Failed to get roce device.\n", __func__);
+ return -EINVAL;
+ }
+ ecn_ctx = rdev->ecn_ctx;
+ cc_algo = ecn_ctx.cc_algo;
+ *algo_type = cc_algo;
+
+ return 0;
+}
+
+static int roce3_dfx_get_qp_count(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ struct roce3_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 roce3_dfx_query_cache_qpc(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ u32 qpn = inbuf->qpn;
+ struct roce_qp_context *qp_ctx = &outbuf->qp_ctx;
+
+ memset(qp_ctx, 0, sizeof(struct roce_qp_context));
+ ret = roce3_dfx_cmd_query_qp(rdev, qpn, qp_ctx);
+ if (ret != 0) {
+ roce3_dfx_print("Failed to query QPC from cache!");
+ roce3_dfx_print("******************From Cache: qpn(%#x) ********************", qpn);
+ roce3_dfx_print(">>>>>>>>>>>>>>>> QUERY QPC FROM CACHE FAILED <<<<<<<<<<<<<<<<<");
+ roce3_dfx_print("******************From Cache: qpn(%#x) ********************", qpn);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce3_dfx_query_host_qpc(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ struct tag_cqm_object *cqm_obj_qp = NULL;
+ struct roce3_qp *rqp = NULL;
+ u32 qpn = inbuf->qpn;
+ struct roce_qp_context *qp_ctx = &outbuf->qp_ctx;
+
+ cqm_obj_qp = cqm_object_get(rdev->hwdev, CQM_OBJECT_SERVICE_CTX, qpn, false);
+ if (cqm_obj_qp == NULL) {
+ roce3_dfx_print("Failed to get cqm_obj_qp.");
+ roce3_dfx_print("******************From Host: qpn(%#x) ********************", qpn);
+ roce3_dfx_print(">>>>>>>>>>> QUERY QPC FROM HOST FAILED, NOT EXIST <<<<<<<<<<<");
+ roce3_dfx_print("******************From Host: qpn(%#x) ********************", qpn);
+
+ return -EINVAL;
+ }
+
+ rqp = cqmobj_to_roce_qp(cqm_obj_qp);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_qp);
+
+ memcpy(qp_ctx, rqp->qpc_info->vaddr, sizeof(struct roce_qp_context));
+
+ return 0;
+}
+
+int roce3_dfx_cmd_query_cq(struct roce3_device *rdev, u32 cqn, struct roce_cq_context *cq_ctx)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct tag_roce_cmd_roce_cq_query *cq_query_inbuf = NULL;
+ struct roce3_cq_query_outbuf *cq_query_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_roce_cq_query), &cqm_cmd_outbuf,
+ (u16)sizeof(struct roce3_cq_query_outbuf));
+ if (ret != 0) {
+ roce3_dfx_print("Failed to alloc cqm_cmd_inoutbuf, ret=%d", ret);
+ return ret;
+ }
+
+ cq_query_inbuf = (struct tag_roce_cmd_roce_cq_query *)cqm_cmd_inbuf->buf;
+ cq_query_inbuf->com.index = cpu_to_be32(cqn);
+ cq_query_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_CQ_BITMASK);
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_QUERY_CQ, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, NULL, ROCE_CMD_TIME_CLASS_B, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ roce3_dfx_print("Failed to send cmd QUERY_CQ, ret=%d", ret);
+ ret = -1;
+ goto out;
+ }
+
+ cq_query_outbuf = (struct roce3_cq_query_outbuf *)cqm_cmd_outbuf->buf;
+ memcpy(cq_ctx, &cq_query_outbuf->cqc, sizeof(struct roce_cq_context));
+out:
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+
+ return ret;
+}
+
+/*
+ * CQC is dynamic allocation. When querying cache content,
+ * you need to determine whether it exists or not.
+ */
+static int roce3_dfx_query_cache_cqc(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ struct tag_cqm_object *cqm_obj_cq = NULL;
+ u32 cqn = inbuf->cqn;
+ struct roce_cq_context *cq_ctx = &outbuf->cq_ctx;
+
+ cqm_obj_cq = cqm_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SCQ, cqn, false);
+ if (cqm_obj_cq == NULL) {
+ roce3_dfx_print("Failed to get cqm_obj_cq.");
+ roce3_dfx_print("******************From Cache: cqn(%#x) ********************", cqn);
+ roce3_dfx_print(">>>>>>>>>>> QUERY CQC FROM CACHE FAILED, NOT EXIST <<<<<<<<<<<");
+ roce3_dfx_print("******************From Cache: cqn(%#x) ********************", cqn);
+
+ return -EINVAL;
+ }
+
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_cq);
+
+ memset(cq_ctx, 0, sizeof(struct roce_cq_context));
+ ret = roce3_dfx_cmd_query_cq(rdev, cqn, cq_ctx);
+ if (ret != 0) {
+ roce3_dfx_print("Failed to query cq from cache!");
+ roce3_dfx_print("******************From Cache: cqn(%#x) ********************", cqn);
+ roce3_dfx_print(">>>>>>>>>>>>>>>> QUERY CQC FROM CACHE FAILED <<<<<<<<<<<<<<<<<");
+ roce3_dfx_print("******************From Cache: cqn(%#x) ********************", cqn);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce3_dfx_query_host_cqc(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ struct tag_cqm_object *cqm_obj_cq = NULL;
+ struct roce3_cq *rcq = NULL;
+ u32 cqn = inbuf->cqn;
+ struct roce_cq_context *cq_ctx = &outbuf->cq_ctx;
+
+ cqm_obj_cq = cqm_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SCQ, cqn, false);
+ if (cqm_obj_cq == NULL) {
+ roce3_dfx_print("Failed to get cqm_obj_cq.");
+ roce3_dfx_print("******************From Host: cqn(%#x) ********************", cqn);
+ roce3_dfx_print(">>>>>>>>>>> QUERY CQC FROM HOST FAILED, NOT EXIST <<<<<<<<<<<");
+ roce3_dfx_print("******************From Host: cqn(%#x) ********************", cqn);
+
+ return -EINVAL;
+ }
+
+ rcq = cqmobj_to_roce3_cq(cqm_obj_cq);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_cq);
+
+ memcpy(cq_ctx, rcq->cqm_cq->q_ctx_vaddr, sizeof(struct roce_cq_context));
+
+ return 0;
+}
+
+int roce3_dfx_cmd_query_srq(struct roce3_device *rdev, u32 srqn, struct roce_srq_context *srq_ctx)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct tag_roce_cmd_srq_query *srq_query_inbuf = NULL;
+ struct roce3_srq_query_outbuf *srq_query_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_srq_query), &cqm_cmd_outbuf,
+ (u16)sizeof(struct roce3_srq_query_outbuf));
+ if (ret != 0) {
+ roce3_dfx_print("Failed to alloc cqm_cmd_inoutbuf, ret=%d", ret);
+ return ret;
+ }
+
+ srq_query_inbuf = (struct tag_roce_cmd_srq_query *)cqm_cmd_inbuf->buf;
+ srq_query_inbuf->com.index = cpu_to_be32(srqn);
+ srq_query_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_SRQ_BITMASK);
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_QUERY_SRQ,
+ cqm_cmd_inbuf, cqm_cmd_outbuf, NULL, ROCE_CMD_TIME_CLASS_B, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ roce3_dfx_print("Failed to send cmd QUERY_SRQ, ret=%d", ret);
+ ret = -1;
+ goto out;
+ }
+
+ srq_query_outbuf = (struct roce3_srq_query_outbuf *)cqm_cmd_outbuf->buf;
+ memcpy(srq_ctx, srq_query_outbuf,
+ sizeof(struct roce3_srq_query_outbuf));
+out:
+ roce3_cqm_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 roce3_dfx_query_cache_srqc(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ struct tag_cqm_object *cqm_obj_srq = NULL;
+ u32 srqn = inbuf->srqn;
+ struct roce_srq_context *srq_ctx = &outbuf->srq_ctx;
+
+ cqm_obj_srq = cqm_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SRQ, srqn, false);
+ if (cqm_obj_srq == NULL) {
+ roce3_dfx_print("Failed to get cqm_obj_srq");
+ roce3_dfx_print("******************From Cache: srqn(%#x) ********************",
+ srqn);
+ roce3_dfx_print(">>>>>>>>>>> QUERY CQC FROM CACHE FAILED, NOT EXIST <<<<<<<<<<<");
+ roce3_dfx_print("******************From Cache: srqn(%#x) ********************",
+ srqn);
+
+ return -EINVAL;
+ }
+
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_srq);
+
+ memset(srq_ctx, 0, sizeof(struct roce_srq_context));
+ ret = roce3_dfx_cmd_query_srq(rdev, srqn, srq_ctx);
+ if (ret != 0) {
+ roce3_dfx_print("Failed to query srq from cache");
+ roce3_dfx_print("******************From Cache: srqn(%#x) ********************",
+ srqn);
+ roce3_dfx_print(">>>>>>>>>>>>>>>> QUERY SRQC FROM CACHE FAILED <<<<<<<<<<<<<<<<<");
+ roce3_dfx_print("******************From Cache: srqn(%#x) ********************",
+ srqn);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce3_dfx_query_host_srqc(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ struct tag_cqm_object *cqm_obj_srq = NULL;
+ struct roce3_srq *rsrq = NULL;
+ u32 srqn = inbuf->srqn;
+ struct roce_srq_context *srq_ctx = &outbuf->srq_ctx;
+
+ cqm_obj_srq = cqm_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SRQ, srqn, false);
+ if (cqm_obj_srq == NULL) {
+ roce3_dfx_print("Failed to get cqm_obj_srq.");
+ roce3_dfx_print("******************From Host: srqn(%#x) ********************",
+ srqn);
+ roce3_dfx_print(">>>>>>>>>>> QUERY SRQC FROM HOST FAILED, NOT EXIST <<<<<<<<<<<");
+ roce3_dfx_print("******************From Host: srqn(%#x) ********************",
+ srqn);
+
+ return -EINVAL;
+ }
+
+ rsrq = cqmobj_to_roce3_srq(cqm_obj_srq);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_srq);
+
+ memcpy(srq_ctx, rsrq->cqm_srq->q_ctx_vaddr, sizeof(struct roce_srq_context));
+
+ return 0;
+}
+
+static int roce3_dfx_cmd_query_mpt(struct roce3_device *rdev, u32 key,
+ struct roce_mpt_context *mpt_entry)
+{
+ int ret;
+ u32 mpt_index;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct tag_roce_cmd_mpt_query *mpt_query_inbuf = NULL;
+ struct roce3_mpt_query_outbuf *mpt_query_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_mpt_query), &cqm_cmd_outbuf,
+ (u16)sizeof(struct roce3_mpt_query_outbuf));
+ if (ret != 0) {
+ roce3_dfx_print("Failed to alloc cqm_cmd_inoutbuf, ret=%d", ret);
+ return ret;
+ }
+
+ mpt_query_inbuf = (struct tag_roce_cmd_mpt_query *)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(VERBS_CMD_TYPE_MR_BITMASK);
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_QUERY_MPT,
+ cqm_cmd_inbuf, cqm_cmd_outbuf, NULL, ROCE_CMD_TIME_CLASS_B, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ roce3_dfx_print("Failed to send cmd QUERY_MPT");
+ ret = -1;
+ goto out;
+ }
+
+ mpt_query_outbuf = (struct roce3_mpt_query_outbuf *)cqm_cmd_outbuf->buf;
+ memcpy(mpt_entry, &mpt_query_outbuf->mpt_entry,
+ sizeof(struct roce_mpt_context));
+out:
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+ return ret;
+}
+
+static int roce3_dfx_cmd_query_gid(struct roce3_device *rdev, u32 port, u32 gid_index,
+ struct rdma_gid_entry *gid_entry)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct tag_roce_qurey_gid *gid_query_inbuf = NULL;
+ struct rdma_gid_query_outbuf *gid_query_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_qurey_gid), &cqm_cmd_outbuf,
+ (u16)sizeof(struct rdma_gid_query_outbuf));
+ if (ret != 0) {
+ roce3_dfx_print("Failed to alloc cqm_cmd_inoutbuf, ret=%d", ret);
+ return ret;
+ }
+
+ gid_query_inbuf = (struct tag_roce_qurey_gid *)cqm_cmd_inbuf->buf;
+ gid_query_inbuf->port = cpu_to_be32(port);
+ gid_query_inbuf->com.index = cpu_to_be32(gid_index);
+ gid_query_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_GID_BITMASK);
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_QUERY_GID, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, NULL, ROCE_CMD_TIME_CLASS_B, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ roce3_dfx_print("Failed to send cmd QUERY_GID");
+ ret = -1;
+ goto out;
+ }
+
+ gid_query_outbuf = (struct rdma_gid_query_outbuf *)cqm_cmd_outbuf->buf;
+ memcpy(gid_entry, &gid_query_outbuf->gid_entry, sizeof(struct rdma_gid_entry));
+out:
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+
+ return ret;
+}
+
+/*
+ * MPT is statically allocated, so it is not necessary to
+ * judge whether it exists when querying the cache content
+ */
+static int roce3_dfx_query_cache_mpt(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ u32 mpt_key = inbuf->mpt_key;
+ struct roce_mpt_context *mpt_entry = &outbuf->mpt;
+
+ memset(mpt_entry, 0, sizeof(struct roce_mpt_context));
+ ret = roce3_dfx_cmd_query_mpt(rdev, mpt_key, mpt_entry);
+ if (ret != 0) {
+ roce3_dfx_print("Failed to query mpt from cache!");
+ roce3_dfx_print("******************From Cache: mpt_key(%#x) ********************",
+ mpt_key);
+ roce3_dfx_print(">>>>>>>>>>>>>>>> QUERY MPT FROM CACHE FAILED <<<<<<<<<<<<<<<<<");
+ roce3_dfx_print("******************From Cache: mpt_key(%#x) ********************",
+ mpt_key);
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce3_dfx_query_host_mpt(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ u32 mpt_index = 0;
+ struct tag_cqm_object *cqm_obj_mpt = NULL;
+ struct tag_cqm_qpc_mpt *cqm_mpt = NULL;
+ struct rdma_mpt *rmpt = NULL;
+ u32 mpt_key = inbuf->mpt_key;
+ struct roce_mpt_context *mpt_entry = &outbuf->mpt;
+
+ mpt_index = (mpt_key >> MR_KEY_2_INDEX_SHIFT) & 0xFFFFFF;
+ cqm_obj_mpt = cqm_object_get(rdev->hwdev, CQM_OBJECT_MPT, mpt_index, false);
+ if (cqm_obj_mpt == NULL) {
+ roce3_dfx_print("Failed to get cqm_obj_mpt.");
+ roce3_dfx_print("******************From Host: mpt_key(%#x) ********************",
+ mpt_key);
+ roce3_dfx_print(">>>>>>>>>>> QUERY MPT FROM HOST FAILED, NOT EXIST <<<<<<<<<<<");
+ roce3_dfx_print("******************From Host: mpt_key(%#x) ********************",
+ mpt_key);
+
+ return -EINVAL;
+ }
+
+ cqm_mpt = container_of(cqm_obj_mpt, struct tag_cqm_qpc_mpt, object);
+ rmpt = (struct rdma_mpt *)cqm_mpt->priv;
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_mpt);
+
+ memcpy(mpt_entry, rmpt->vaddr, sizeof(struct roce_mpt_context));
+
+ return 0;
+}
+
+static int roce3_dfx_query_cache_gid(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ u32 gid_index = inbuf->gid_index;
+ struct rdma_gid_entry *gid_entry = &outbuf->gid_entry;
+
+ memset(gid_entry, 0, sizeof(struct rdma_gid_entry));
+ ret = roce3_dfx_cmd_query_gid(rdev, 0, gid_index, gid_entry);
+ if (ret != 0) {
+ roce3_dfx_print("***************port(1), gid_index(%d) *****************",
+ gid_index);
+ roce3_dfx_print("Failed to query gid from cache!");
+ roce3_dfx_print("***************port(1), gid_index(%d) *****************",
+ gid_index);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void roce3_dfx_query_pi_ci_b32_to_cpu(struct roce_qp_context *qp_ctx)
+{
+ qp_ctx->chip_seg.sqc.dw0.value = be32_to_cpu(qp_ctx->chip_seg.sqc.dw0.value);
+ qp_ctx->chip_seg.sqc.dw2.value = be32_to_cpu(qp_ctx->chip_seg.sqc.dw2.value);
+ qp_ctx->chip_seg.sqc.dw3.value = be32_to_cpu(qp_ctx->chip_seg.sqc.dw3.value);
+ qp_ctx->chip_seg.sqc.dw7.value = be32_to_cpu(qp_ctx->chip_seg.sqc.dw7.value);
+ qp_ctx->chip_seg.sqc.dw14.value = be32_to_cpu(qp_ctx->chip_seg.sqc.dw14.value);
+ qp_ctx->chip_seg.rqc.dw0.value = be32_to_cpu(qp_ctx->chip_seg.rqc.dw0.value);
+ qp_ctx->chip_seg.rqc.dw3.value = be32_to_cpu(qp_ctx->chip_seg.rqc.dw3.value);
+ qp_ctx->chip_seg.rqc.dw7.value = be32_to_cpu(qp_ctx->chip_seg.rqc.dw7.value);
+ qp_ctx->chip_seg.rqc.dw14.value = be32_to_cpu(qp_ctx->chip_seg.rqc.dw14.value);
+ qp_ctx->chip_seg.sqac.dw3.value = be32_to_cpu(qp_ctx->chip_seg.sqac.dw3.value);
+ qp_ctx->chip_seg.sqac.dw7.value = be32_to_cpu(qp_ctx->chip_seg.sqac.dw7.value);
+ qp_ctx->chip_seg.rcc.dw5.value = be32_to_cpu(qp_ctx->chip_seg.rcc.dw5.value);
+ qp_ctx->chip_seg.rcc.dw6.value = be32_to_cpu(qp_ctx->chip_seg.rcc.dw6.value);
+ qp_ctx->chip_seg.rcc.dw7.value = be32_to_cpu(qp_ctx->chip_seg.rcc.dw7.value);
+ qp_ctx->chip_seg.qpcc.dw4.value = be32_to_cpu(qp_ctx->chip_seg.qpcc.dw4.value);
+}
+
+static void roce3_dfx_query_pi_ci_set(struct roce_qp_context qp_ctx, struct roce3_dfx_pi_ci *pi_ci)
+{
+ pi_ci->qpc_sq_pi_on_chip = qp_ctx.chip_seg.sqc.dw0.bs.sq_pi_on_chip;
+ pi_ci->qpc_sq_pi = qp_ctx.chip_seg.sqc.dw2.bs.sq_pi;
+ pi_ci->qpc_sq_load_pi = qp_ctx.chip_seg.sqc.dw3.bs.sq_load_pi;
+ pi_ci->qpc_rq_pi_on_chip = qp_ctx.chip_seg.rqc.dw0.bs.rq_pi_on_chip;
+ pi_ci->qpc_rq_load_pi = qp_ctx.chip_seg.rqc.dw3.bs.rq_load_pi;
+ pi_ci->qpc_rq_pi = qp_ctx.chip_seg.rqc.dw7.bs.rq_pi;
+ pi_ci->qpc_rc_pi = qp_ctx.chip_seg.rcc.dw5.bs.rc_pi;
+ pi_ci->qpc_sq_ci = qp_ctx.chip_seg.sqc.dw3.bs.sq_ci;
+ pi_ci->qpc_sq_wqe_prefetch_ci = qp_ctx.chip_seg.sqc.dw7.bs.sq_wqe_prefetch_ci;
+ pi_ci->qpc_sq_mtt_prefetch_wqe_ci = qp_ctx.chip_seg.sqc.dw14.bs.sq_mtt_prefetch_wqe_ci;
+ pi_ci->qpc_sqa_ci = qp_ctx.chip_seg.sqac.dw3.bs.sqa_ci;
+ pi_ci->qpc_sqa_wqe_prefetch_ci = qp_ctx.chip_seg.sqac.dw7.bs.sqa_wqe_prefetch_ci;
+ pi_ci->qpc_rq_ci = qp_ctx.chip_seg.rqc.dw3.bs.rq_ci;
+ pi_ci->qpc_rq_wqe_prefetch_ci = qp_ctx.chip_seg.rqc.dw7.bs.rq_wqe_prefetch_ci;
+ pi_ci->qpc_rq_mtt_prefetch_wqe_ci = qp_ctx.chip_seg.rqc.dw14.bs.rq_mtt_prefetch_wqe_ci;
+ pi_ci->qpc_rq_base_ci = qp_ctx.chip_seg.qpcc.dw4.bs.rq_base_ci;
+ pi_ci->qpc_rc_ci = qp_ctx.chip_seg.rcc.dw6.bs.rc_ci;
+ pi_ci->qpc_rc_prefetch_ci = qp_ctx.chip_seg.rcc.dw7.bs.rc_prefetch_ci;
+}
+
+static int roce3_dfx_query_pi_ci(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf)
+{
+ int ret;
+ struct roce_qp_context qp_ctx;
+ struct roce_cq_context cq_ctx;
+ u32 qpn = inbuf->query_pi_ci.qpn;
+ u32 cqn = inbuf->query_pi_ci.cqn;
+ struct roce3_dfx_pi_ci *pi_ci = &outbuf->pi_ci;
+
+ memset(pi_ci, 0, sizeof(struct roce3_dfx_pi_ci));
+
+ memset(&qp_ctx, 0, sizeof(qp_ctx));
+ ret = roce3_dfx_cmd_query_qp(rdev, qpn, &qp_ctx);
+ if (ret != 0)
+ return ret;
+
+ roce3_dfx_query_pi_ci_b32_to_cpu(&qp_ctx);
+ roce3_dfx_query_pi_ci_set(qp_ctx, pi_ci);
+
+ memset(&cq_ctx, 0, sizeof(cq_ctx));
+ ret = roce3_dfx_cmd_query_cq(rdev, cqn, &cq_ctx);
+ if (ret != 0)
+ return ret;
+
+ cq_ctx.dw0.value = be32_to_cpu(cq_ctx.dw0.value);
+ cq_ctx.dw1.value = be32_to_cpu(cq_ctx.dw1.value);
+ cq_ctx.dw2.value = be32_to_cpu(cq_ctx.dw2.value);
+ cq_ctx.dw3.value = be32_to_cpu(cq_ctx.dw3.value);
+ cq_ctx.dw9.value = be32_to_cpu(cq_ctx.dw9.value);
+ cq_ctx.ci_record_gpa_at_hop_num = be32_to_cpu(cq_ctx.ci_record_gpa_at_hop_num);
+
+ pi_ci->cq_ci_on_chip = cq_ctx.dw0.bs.ci_on_chip;
+ pi_ci->cq_ci = cq_ctx.dw1.bs.ci;
+ pi_ci->cq_load_ci = cq_ctx.dw3.bs.load_ci;
+ pi_ci->cq_ci_record_gpa_at_hop_num = cq_ctx.ci_record_gpa_at_hop_num;
+ pi_ci->cq_last_solicited_pi = cq_ctx.dw0.bs.last_solicited_pi;
+ pi_ci->cq_pi = cq_ctx.dw2.bs.pi;
+ pi_ci->cq_last_notified_pi = cq_ctx.dw9.bs.last_notified_pi;
+
+ return 0;
+}
+
+typedef int (*roce3_adm_dfx_query_t)(const struct roce3_dfx_query_inbuf *inbuf,
+ struct roce3_device *rdev, union roce3_dfx_query_outbuf *outbuf);
+
+static roce3_adm_dfx_query_t roce3_adm_dfx_query_funcs[COMMON_CMD_VM_COMPAT_TEST] = {
+ [ROCE_CMD_GET_QPC_FROM_CACHE] = roce3_dfx_query_cache_qpc,
+ [ROCE_CMD_GET_QPC_FROM_HOST] = roce3_dfx_query_host_qpc,
+ [ROCE_CMD_GET_CQC_FROM_CACHE] = roce3_dfx_query_cache_cqc,
+ [ROCE_CMD_GET_CQC_FROM_HOST] = roce3_dfx_query_host_cqc,
+ [ROCE_CMD_GET_SRQC_FROM_CACHE] = roce3_dfx_query_cache_srqc,
+ [ROCE_CMD_GET_SRQC_FROM_HOST] = roce3_dfx_query_host_srqc,
+ [ROCE_CMD_GET_MPT_FROM_CACHE] = roce3_dfx_query_cache_mpt,
+ [ROCE_CMD_GET_MPT_FROM_HOST] = roce3_dfx_query_host_mpt,
+ [ROCE_CMD_GET_GID_FROM_CACHE] = roce3_dfx_query_cache_gid,
+ [ROCE_CMD_GET_QPC_CQC_PI_CI] = roce3_dfx_query_pi_ci,
+ [ROCE_CMD_GET_QP_COUNT] = roce3_dfx_get_qp_count,
+ [ROCE_CMD_GET_DEV_ALGO] = roce3_dfx_get_dev_algo,
+};
+
+int roce3_adm_dfx_query(struct roce3_device *rdev, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size)
+{
+ const struct roce3_dfx_query_inbuf *inbuf = (struct roce3_dfx_query_inbuf *)buf_in;
+ union roce3_dfx_query_outbuf *outbuf = (union roce3_dfx_query_outbuf *)buf_out;
+ roce3_adm_dfx_query_t roce3_adm_dfx_query_func;
+
+ memset(buf_out, 0, sizeof(union roce3_dfx_query_outbuf));
+ *out_size = (u32)sizeof(union roce3_dfx_query_outbuf);
+
+ if (inbuf->cmd_type >= COMMON_CMD_VM_COMPAT_TEST) {
+ roce3_dfx_print("Not support this type(%d)", inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ roce3_adm_dfx_query_func = roce3_adm_dfx_query_funcs[inbuf->cmd_type];
+ if (roce3_adm_dfx_query_func == NULL) {
+ roce3_dfx_print("Not support this type(%d)", inbuf->cmd_type);
+ return -EINVAL;
+ }
+
+ return roce3_adm_dfx_query_func(inbuf, rdev, outbuf);
+}
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/extension/roce_cdev_extension.c b/drivers/infiniband/hw/hiroce3/extension/roce_cdev_extension.c
new file mode 100644
index 0000000000000..c27cf826e6e9f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/extension/roce_cdev_extension.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+#ifndef PANGEA_NOF
+
+#include "roce_cdev_extension.h"
+
+long ioctl_non_bonding_extend(unsigned int cmd, struct roce3_device *rdev, unsigned long arg)
+{
+ return NOT_SUPOORT_TYPE;
+}
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/extension/roce_event_extension.c b/drivers/infiniband/hw/hiroce3/extension/roce_event_extension.c
new file mode 100644
index 0000000000000..cd881052d5851
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/extension/roce_event_extension.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_event_extension.h"
+
+#ifndef PANGEA_NOF
+void roce3_event_report_extend(const struct roce3_device *rdev, int event_str_index)
+{
+ /*lint -e160 -e522*/
+ roce3_pr_err_once("[ROCE] %s: [non ofed event type] Invalid extend event type error. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ /*lint +e160 +e522*/
+}
+
+int roce3_async_event_handle_extend(u8 event_type, u8 *val, struct roce3_device *rdev)
+{
+ int event_str_index = 0;
+
+ event_str_index = to_unknown_event_str_index(event_type, val);
+
+ return event_str_index;
+}
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/extension/roce_main_extension.c b/drivers/infiniband/hw/hiroce3/extension/roce_main_extension.c
new file mode 100644
index 0000000000000..d3885af3f35d1
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/extension/roce_main_extension.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_main_extension.h"
+
+#ifndef PANGEA_NOF
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+
+static struct mutex g_rdev_mutex;
+#endif
+
+void roce3_service_init_pre(void)
+{
+#ifdef ROCE_BONDING_EN
+ mutex_init(&g_rdev_mutex);
+#endif
+
+}
+
+void roce3_service_init_ext(void)
+{
+}
+
+void roce3_lock_rdev(void)
+{
+#ifdef ROCE_BONDING_EN
+ mutex_lock(&g_rdev_mutex);
+#endif
+
+}
+
+void roce3_unlock_rdev(void)
+{
+#ifdef ROCE_BONDING_EN
+ mutex_unlock(&g_rdev_mutex);
+#endif
+}
+
+int roce3_get_rdev_by_uld(struct hinic3_lld_dev *lld_dev, void *uld_dev, struct roce3_device **rdev,
+ struct hinic3_event_info *event)
+{
+#ifdef ROCE_BONDING_EN
+ int ret;
+
+ ret = roce3_bond_event_cfg_rdev(lld_dev, uld_dev, rdev);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Cfg bond rdev failed(%d)\n", __func__, ret);
+ return ret;
+ }
+ ret = roce3_bonded_port_event_report(*rdev, event);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Report bond event failed(%d)\n", __func__, ret);
+ return ret;
+ }
+#else
+ if ((lld_dev == NULL) || (uld_dev == NULL)) {
+ pr_err("[ROCE] %s: Input params is null\n", __func__);
+ return -ENODEV;
+ }
+ *rdev = (struct roce3_device *)uld_dev;
+#endif
+ return 0;
+}
+#endif /* !PANGEA_NOF */
+
+#ifdef ROCE_STANDARD
+void roce3_init_dev_ext_handlers(struct roce3_device *rdev)
+{
+}
+#endif /* ROCE_STANDARD */
+
+#ifndef PANGEA_NOF
+void roce3_remove_clean_res_ext(struct roce3_device *rdev)
+{
+#ifdef __ROCE_DFX__
+ roce3_dfx_clean_up(rdev);
+#endif
+}
+#endif /* PANGEA_NOF */
+
+#ifndef PANGEA_NOF
+int roce3_board_cfg_check(struct roce3_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 == ROCE3_2_PORT_NUM) && (port_speed == ROCE3_100G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE3_2_100G_HCA;
+ } else if ((port_num == ROCE3_4_PORT_NUM) && (port_speed == ROCE3_25G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE3_4_25G_HCA;
+ } else if ((port_num == ROCE3_2_PORT_NUM) && (port_speed == ROCE3_25G_PORT_SPEED)) {
+ rdev->hw_info.hca_type = ROCE3_2_25G_HCA;
+ } else {
+ pr_err("[ROCE] %s: Invalid fw cfg\n", __func__);
+ ret = (-EINVAL);
+ }
+
+ return ret;
+}
+
+int roce3_mmap_ext(struct roce3_device *rdev, struct roce3_ucontext *ucontext,
+ struct vm_area_struct *vma)
+{
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Not support, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+}
+
+int roce3_dfx_mem_alloc(struct roce3_device *rdev)
+{
+ return 0;
+}
+
+void roce3_dfx_mem_free(struct roce3_device *rdev)
+{
+}
+
+void *roce3_ucontext_alloc_ext(void)
+{
+ return kzalloc(sizeof(struct roce3_ucontext), GFP_KERNEL);
+}
+
+void *roce3_resp_alloc_ext(void)
+{
+ return kzalloc(sizeof(struct roce3_alloc_ucontext_resp), GFP_KERNEL);
+}
+
+void roce3_resp_set_ext(struct roce3_device *rdev, struct roce3_alloc_ucontext_resp *resp)
+{
+}
+
+void roce3_ucontext_set_ext(struct roce3_device *rdev, struct roce3_ucontext *context)
+{
+}
+
+void *roce3_rdev_alloc_ext(void)
+{
+ return (void *)ib_alloc_device(roce3_device, ib_dev);
+}
+
+void roce3_rdev_set_ext(struct roce3_device *rdev)
+{
+}
+
+int ib_copy_to_udata_ext(struct ib_udata *udata, struct roce3_alloc_ucontext_resp *resp)
+{
+ return ib_copy_to_udata(udata, resp, sizeof(struct roce3_alloc_ucontext_resp));
+}
+
+int roce3_set_comm_event(const struct roce3_device *rdev, const struct hinic3_event_info *event)
+{
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Comm event unsupported, func_id(%d), event(%d)\n",
+ __func__, rdev->glb_func_id, event->type);
+ return -1;
+}
+
+bool roce3_hca_is_present(const struct roce3_device *rdev)
+{
+ return true;
+}
+#endif /* PANGEA_NOF */
+
+#if !defined(NOF_AA)
+int roce3_init_dev_ext(struct roce3_device *rdev)
+{
+ return 0;
+}
+
+#if defined(EULER_2_10_OFED_4_19) || defined(KY10_OFED_4_19)
+void roce3_rdma_cap_ext(struct rdma_service_cap *rdma_cap)
+{
+ rdma_cap->max_sq_desc_sz = RDMA_MAX_SQ_DESC_SZ_COMPUTE;
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_wqes = ROCE_MAX_WQES_COMPUTE;
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_sq_inline_data_sz =
+ ROCE_MAX_SQ_INLINE_DATA_SZ_COMPUTE;
+}
+#else
+void roce3_rdma_cap_ext(struct rdma_service_cap *rdma_cap)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/extension/roce_mr_extension.c b/drivers/infiniband/hw/hiroce3/extension/roce_mr_extension.c
new file mode 100644
index 0000000000000..c27dbda091dd0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/extension/roce_mr_extension.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+#include "roce_mr.h"
+#include "roce_main_extension.h"
+#include "roce_mr_extension.h"
+
+#ifdef ROCE_STANDARD
+int roce3_check_alloc_mr_type(enum ib_mr_type mr_type)
+{
+ int ret = 0;
+
+ if (mr_type != IB_MR_TYPE_MEM_REG) {
+ ret = -EINVAL;
+ pr_err("[ROCE, ERR] %s: mr_type is invalid. mr_type:%u\n", __func__, mr_type);
+ }
+
+ return ret;
+}
+
+enum rdma_mr_type roce3_get_mrtype(enum ib_mr_type ib_mr_type)
+{
+ switch (ib_mr_type) {
+ case IB_MR_TYPE_MEM_REG:
+ return RDMA_DMA_MR;
+
+ default:
+ return RDMA_DMA_MR;
+ }
+}
+#endif
+
diff --git a/drivers/infiniband/hw/hiroce3/extension/roce_netdev_extension.c b/drivers/infiniband/hw/hiroce3/extension/roce_netdev_extension.c
new file mode 100644
index 0000000000000..99d86861397a7
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/extension/roce_netdev_extension.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_netdev_extension.h"
+#include "roce_mpu_common.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+#ifndef PANGEA_NOF
+int roce3_add_real_device_mac(struct roce3_device *rdev, struct net_device *netdev)
+{
+ int ret;
+ u32 vlan_id = 0;
+
+ /*
+ * no need to configure IPSURX vf table for vroce here,
+ * this action has been done in vroce driver
+ */
+ roce3_add_ipsu_tbl_mac_entry(rdev->hwdev, (u8 *)netdev->dev_addr, vlan_id,
+ rdev->glb_func_id, hinic3_er_id(rdev->hwdev));
+
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev)) {
+ ret = roce3_add_bond_real_slave_mac(rdev, (u8 *)netdev->dev_addr);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to add bond ipsu mac, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, (u8 *)netdev->dev_addr, 0,
+ rdev->glb_func_id, hinic3_er_id(rdev->hwdev));
+ return ret;
+ }
+ }
+#endif
+
+ memcpy(rdev->mac, netdev->dev_addr, sizeof(rdev->mac));
+
+ return 0;
+}
+
+int roce3_add_vlan_device_mac(struct roce3_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)));
+ dev_info(rdev->hwdev_hdl, "[ROCE] %s: enter add vlan, vlan_id(0x%x), func_id(%d)\n",
+ __func__, vlan_id, rdev->glb_func_id);
+ ret = roce3_add_mac_tbl_mac_entry(rdev->hwdev, (u8 *)netdev->dev_addr,
+ vlan_id, rdev->glb_func_id, rdev->glb_func_id);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to set vlan mac, vlan_id(0x%x), func_id(%d)\n",
+ __func__, vlan_id, rdev->glb_func_id);
+ return ret;
+ }
+
+ roce3_add_ipsu_tbl_mac_entry(rdev->hwdev, (u8 *)netdev->dev_addr, vlan_id,
+ rdev->glb_func_id, hinic3_er_id(rdev->hwdev));
+
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev)) {
+ ret = roce3_add_bond_vlan_slave_mac(rdev, (u8 *)netdev->dev_addr, (u16)vlan_id);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to set bond, vlan_id(0x%x), func_id(%d)\n",
+ __func__, 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:
+ roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, (u8 *)netdev->dev_addr,
+ vlan_id, rdev->glb_func_id, hinic3_er_id(rdev->hwdev));
+
+ (void)hinic3_del_mac(rdev->hwdev, (u8 *)netdev->dev_addr, (u16)vlan_id,
+ rdev->glb_func_id, HINIC3_CHANNEL_ROCE);
+
+ return ret;
+#endif
+}
+
+void roce3_del_real_device_mac(struct roce3_device *rdev)
+{
+ u32 vlan_id = 0;
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev))
+ roce3_del_bond_real_slave_mac(rdev);
+#endif
+
+ roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, rdev->mac, vlan_id,
+ rdev->glb_func_id, hinic3_er_id(rdev->hwdev));
+}
+
+void roce3_del_vlan_device_mac(struct roce3_device *rdev, struct roce3_vlan_dev_list *old_list)
+{
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev))
+ roce3_del_bond_vlan_slave_mac(rdev, old_list->mac, (u16)old_list->vlan_id);
+#endif
+
+ roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, old_list->mac, old_list->vlan_id,
+ rdev->glb_func_id, hinic3_er_id(rdev->hwdev));
+
+ (void)roce3_del_mac_tbl_mac_entry(rdev->hwdev, old_list->mac, old_list->vlan_id,
+ rdev->glb_func_id, rdev->glb_func_id);
+}
+
+void roce3_event_up_extend(struct roce3_device *rdev)
+{
+ if (test_and_set_bit(ROCE3_PORT_EVENT, &rdev->status) == 0)
+ roce3_ifconfig_up_down_event_report(rdev, IB_EVENT_PORT_ACTIVE);
+}
+
+#endif /* PANGEA_NOF */
diff --git a/drivers/infiniband/hw/hiroce3/extension/roce_qp_extension.c b/drivers/infiniband/hw/hiroce3/extension/roce_qp_extension.c
new file mode 100644
index 0000000000000..50170d77905f4
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/extension/roce_qp_extension.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_qp_extension.h"
+#include "cfg_mgmt_mpu_cmd_defs.h"
+
+#ifdef ROCE_EXTEND
+#include "roce_ctx_api.h"
+#include "roce_pd.h"
+#endif
+
+int to_roce3_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 roce3_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)
+{
+ return ib_modify_qp_is_ok(cur_state, next_state, type, mask);
+}
+
+#ifndef PANGEA_NOF
+int roce3_create_qp_pre_ext(struct roce3_device *rdev, struct roce3_qp *rqp,
+ struct ib_qp_init_attr *init_attr)
+{
+ return 0;
+}
+
+int roce3_create_qp_user_pre_ext(struct ib_qp_init_attr *init_attr, struct roce3_qp *rqp, u32 *qpn)
+{
+ *qpn = ROCE_QP_INVLID_QP_NUM;
+
+ return 0;
+}
+
+int roce3_create_qp_user_post_ext(struct ib_pd *ibpd, struct roce3_device *rdev,
+ struct roce3_qp *rqp, struct ib_qp_init_attr *init_attr)
+{
+ return 0;
+}
+
+int roce3_qp_modify_cmd_ext(struct tag_cqm_cmd_buf *cqm_cmd_inbuf, struct roce3_qp *rqp,
+ struct tag_roce_verbs_qp_attr *qp_attr, u32 optpar)
+{
+ return 0;
+}
+
+bool roce3_need_qpn_lb1_consistent_srqn(const struct roce3_qp *rqp, const struct roce3_device *rdev,
+ const struct ib_qp_init_attr *init_attr)
+{
+ if (init_attr->srq == NULL)
+ return false;
+
+ if ((rdev->cfg_info.scence_id == SCENES_ID_CLOUD) ||
+ (rdev->cfg_info.scence_id == SCENES_ID_COMPUTE_ROCE) ||
+ (rdev->cfg_info.scence_id == SCENES_ID_COMPUTE_STANDARD))
+ return true;
+
+ return false;
+}
+
+int roce3_is_qp_normal(struct roce3_qp *rqp, struct ib_qp_init_attr *init_attr)
+{
+ return 1;
+}
+
+#ifdef ROCE_EXTEND
+static struct roce3_qp *roce3_cdev_lookup_and_check_rqp(struct roce3_device *rdev, u32 qpn)
+{
+ struct tag_cqm_object *cqm_obj_qp = NULL;
+ struct roce3_qp *rqp = NULL;
+
+ cqm_obj_qp = cqm_object_get(rdev->hwdev, CQM_OBJECT_SERVICE_CTX, qpn, false);
+ if (cqm_obj_qp == NULL) {
+ pr_err("[ROCE, ERR] %s: Can't find rqp according to qpn(0x%x), func_id(%d)\n",
+ __func__, qpn, rdev->glb_func_id);
+ return NULL;
+ }
+
+ rqp = cqmobj_to_roce_qp(cqm_obj_qp);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_qp);
+
+ if (rqp->qpn >= QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC) {
+ dev_err(rdev->hwdev_hdl, "[ROCE_VBS, ERR] %s: qpn[%u] more than sqpc num offset(%d) for sqpc.\n",
+ __func__, rqp->qpn, QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC);
+ return NULL;
+ }
+
+ return rqp;
+}
+
+static int roce3_alloc_sqpc(struct roce3_device *rdev, struct roce3_qp *rqp,
+ struct roce3_vbs_qp *vbs_rqp)
+{
+ struct tag_cqm_qpc_mpt *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 = cqm_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, false);
+ if (qpc_info == NULL) {
+ dev_err(rdev->hwdev_hdl, "[ROCE_VBS, ERR] %s: Failed to create qpc by cqm object, func_id(%d), qpn(%u)\n",
+ __func__, 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)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE_VBS, ERR] %s: Create qpc error, func_id(%d), expect qpn(%d), actual qpn(%d)\n",
+ __func__, rdev->glb_func_id,
+ rqp->qpn + QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC, qpc_info->xid);
+ hiudk_cqm_object_delete(rdev->hwdev, &(qpc_info->object));
+ return -EFAULT;
+ }
+
+ vbs_rqp->vbs_sqpc_info = qpc_info;
+ rqp->vbs_qp_ptr = (void *)vbs_rqp;
+
+ return 0;
+}
+
+long roce3_set_qp_ext_attr(struct roce3_device *rdev, void *buf)
+{
+ int ret;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_set_qp_ext_attr_cmd cmd;
+ struct roce_qp_context *context = NULL;
+
+ ret = (int)copy_from_user(&cmd, buf, sizeof(cmd));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to copy data from user\n",
+ __func__);
+ return (long)ret;
+ }
+
+ rqp = roce3_cdev_lookup_and_check_rqp(rdev, cmd.qpn);
+ if (rqp == NULL) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to look up rqp\n", __func__);
+ return -EINVAL;
+ }
+
+ context = (struct roce_qp_context *)((void *)rqp->qpc_info->vaddr);
+ if (((cmd.attr_mask) & ROCE_QP_VBS_FLAG) != 0) { /* IBV_QP_VBS_OSD_FLAG */
+ context->sw_seg.ucode_seg.common.dw0.bs.ulp_type = ROCE_ULP_VBS;
+ }
+
+ return (long)ret;
+}
+
+long roce3_vbs_create_sqpc(struct roce3_device *rdev, void *buf)
+{
+ struct roce3_modify_qp_vbs_cmd cmd;
+ struct roce3_vbs_qp *vbs_rqp = NULL;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_pd *pd = NULL;
+ int ret;
+
+ ret = (int)copy_from_user(&cmd, buf, sizeof(cmd));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to copy data from user\n",
+ __func__);
+ return (long)ret;
+ }
+
+ rqp = roce3_cdev_lookup_and_check_rqp(rdev, cmd.qpn);
+ if (rqp == NULL) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to look up rqp\n", __func__);
+ return -EINVAL;
+ }
+
+ vbs_rqp = kzalloc(sizeof(*vbs_rqp), GFP_KERNEL);
+ if (vbs_rqp == NULL)
+ return -ENOMEM;
+
+ pd = roce3_get_pd(rqp);
+ ret = roce3_db_map_user(to_roce3_ucontext(pd->ibpd.uobject->context),
+ cmd.ci_record_addr, &vbs_rqp->db);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE_VBS, ERR] %s: Failed to map db page to user, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto free_rqp;
+ }
+
+ ret = roce3_alloc_sqpc(rdev, rqp, vbs_rqp);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE_VBS, ERR] %s: Failed to alloc sqpc, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto free_rqp;
+ }
+
+ return 0;
+
+free_rqp:
+ kfree(vbs_rqp);
+
+ return (long)ret;
+}
+#endif
+
+#endif /* !PANGEA_NOF */
+
+#ifndef ROCE_CHIP_TEST
+void roce3_set_qp_dif_attr(struct roce3_qp *rqp, const struct ib_qp_init_attr *init_attr,
+ const struct roce3_device *rdev)
+{
+ if (((unsigned int)init_attr->create_flags & IB_QP_CREATE_SIGNATURE_EN) != 0) {
+ rqp->signature_en = true;
+ dev_info(rdev->hwdev_hdl, "[ROCE] %s: func(%d) qp(%u) roce3_create_qp signature_en.\n",
+ __func__, rdev->glb_func_id, rqp->qpn);
+ }
+}
+#endif
+
+#ifndef ROCE_VBS_EN
+int roce3_qp_modify_pre_extend(struct roce3_qp *rqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/extension/roce_qp_post_send_extension.c b/drivers/infiniband/hw/hiroce3/extension/roce_qp_post_send_extension.c
new file mode 100644
index 0000000000000..25b599020f339
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/extension/roce_qp_post_send_extension.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_qp_post_send_extension.h"
+
+int roce3_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr)
+{
+ return roce3_post_send_standard(ibqp, (const struct ib_send_wr *)wr,
+ (const struct ib_send_wr **)bad_wr);
+}
diff --git a/drivers/infiniband/hw/hiroce3/extension/roce_srq_extension.c b/drivers/infiniband/hw/hiroce3/extension/roce_srq_extension.c
new file mode 100644
index 0000000000000..b701f014caf63
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/extension/roce_srq_extension.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_srq_extension.h"
+
+#ifndef ROCE_CHIP_TEST
+void roce3_srq_container_init(struct ib_srq_init_attr *init_attr, struct roce3_srq *rsrq,
+ struct roce3_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 = roce3_calculate_cont_th(init_attr->attr.srq_limit);
+ rsrq->rqe_cnt_th = rdev->cfg_info.warn_th;
+ rsrq->container_size = roce3_get_container_sz(rsrq->container_mode);
+}
+#endif
+
+#ifndef PANGEA_NOF
+void roce3_create_user_srq_update_ext(u32 *cqn, u32 srqn)
+{
+}
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_buddy.c b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_buddy.c
new file mode 100644
index 0000000000000..89b321ebea5b5
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_buddy.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include "hinic3_hw.h"
+#include "hmm_comp.h"
+#include "hmm_buddy.h"
+
+
+u32 hmm_buddy_alloc(struct hmm_buddy *buddy, u32 order)
+{
+ u32 first_index = 0;
+ u32 cur_order = 0;
+ u32 cur_bit_num = 0;
+
+ if (buddy == NULL) {
+ pr_err("%s: Buddy is null\n", __func__);
+ return HMM_INVALID_INDEX;
+ }
+ if (order > buddy->max_order) {
+ pr_err("%s: Order(%d) is bigger than max order(%d)\n",
+ __func__, order, buddy->max_order);
+ return HMM_INVALID_INDEX;
+ }
+ spin_lock(&buddy->lock);
+
+ for (cur_order = order; cur_order <= buddy->max_order; ++cur_order) {
+ if (buddy->num_free[cur_order] != 0) {
+ cur_bit_num = 1U << (buddy->max_order - cur_order);
+ first_index = (u32)find_first_bit(buddy->bits[cur_order],
+ (unsigned long)cur_bit_num);
+ if (first_index < cur_bit_num)
+ goto found;
+ }
+ }
+ spin_unlock(&buddy->lock);
+ pr_err("%s: Get a invalid index\n", __func__);
+ return HMM_INVALID_INDEX;
+
+found:
+ clear_bit((int)first_index, buddy->bits[cur_order]);
+ --buddy->num_free[cur_order];
+
+ while (cur_order > order) {
+ --cur_order;
+ first_index <<= 1;
+ set_bit(first_index ^ 1, buddy->bits[cur_order]);
+ ++buddy->num_free[cur_order];
+ }
+ first_index <<= order;
+ spin_unlock(&buddy->lock);
+ return first_index;
+}
+
+void hmm_buddy_free(struct hmm_buddy *buddy, u32 first_index, u32 order)
+{
+ u32 tmp_first_index = first_index;
+ u32 tmp_order = order;
+
+ if (buddy == NULL) {
+ pr_err("%s: Buddy is null\n", __func__);
+ return;
+ }
+ if (tmp_order > buddy->max_order) {
+ pr_err("%s: Order(%d) is bigger than max order(%d)\n",
+ __func__, tmp_order, buddy->max_order);
+ return;
+ }
+ tmp_first_index >>= tmp_order;
+ spin_lock(&buddy->lock);
+ while (test_bit((int)(tmp_first_index ^ 1), buddy->bits[tmp_order]) != 0) {
+ clear_bit((int)(tmp_first_index ^ 1), buddy->bits[tmp_order]);
+ --buddy->num_free[tmp_order];
+ tmp_first_index >>= 1;
+ ++tmp_order;
+ }
+ set_bit(tmp_first_index, buddy->bits[tmp_order]);
+ ++buddy->num_free[tmp_order];
+ spin_unlock(&buddy->lock);
+}
+
+static void hmm_buddy_alloc_bitmap_fail(struct hmm_buddy *buddy, u32 i)
+{
+ u32 j = 0;
+
+ for (j = 0; j < i; j++) {
+ if (is_vmalloc_addr(buddy->bits[j]))
+ vfree(buddy->bits[j]);
+ else
+ kfree(buddy->bits[j]);
+ buddy->bits[j] = NULL;
+ }
+ kfree(buddy->bits);
+ buddy->bits = NULL;
+}
+
+int hmm_buddy_init(struct hmm_buddy *buddy, u32 max_order)
+{
+ u32 i = 0;
+ u32 bit_num = 0;
+
+ if (buddy == NULL) {
+ pr_err("%s: Buddy is null\n", __func__);
+ return -EINVAL;
+ }
+ buddy->max_order = max_order;
+ /*lint -e708*/
+ spin_lock_init(&buddy->lock);
+ /*lint +e708*/
+ buddy->num_free = kcalloc(
+ (unsigned long)(buddy->max_order + 1UL), sizeof(int), GFP_KERNEL);
+ if (buddy->num_free == NULL)
+ return -ENOMEM;
+ buddy->bits = kcalloc(
+ (unsigned long)(buddy->max_order + 1UL), sizeof(long *), GFP_KERNEL);
+ if (buddy->bits == NULL)
+ goto alloc_bits_fail;
+
+ for (i = 0; i <= buddy->max_order; i++) {
+ bit_num = (u32)BITS_TO_LONGS(1UL << (buddy->max_order - i));
+ buddy->bits[i] = kcalloc(
+ (unsigned long)bit_num, sizeof(long), GFP_KERNEL | __GFP_NOWARN);
+ if (buddy->bits[i] == NULL) {
+ buddy->bits[i] = vzalloc((unsigned long)bit_num * sizeof(long));
+ if (buddy->bits[i] == NULL)
+ goto alloc_bitmap_fail;
+ }
+ }
+ set_bit(0, buddy->bits[buddy->max_order]);
+ buddy->num_free[buddy->max_order] = 1;
+ return 0;
+
+alloc_bitmap_fail:
+ hmm_buddy_alloc_bitmap_fail(buddy, i);
+alloc_bits_fail:
+ kfree(buddy->num_free);
+ buddy->num_free = NULL;
+ return -ENOMEM;
+}
+
+void hmm_buddy_cleanup(struct hmm_buddy *buddy)
+{
+ u32 i;
+
+ if (buddy == NULL) {
+ pr_err("%s: Buddy is null\n", __func__);
+ return;
+ }
+ for (i = 0; i <= buddy->max_order; i++) {
+ if (is_vmalloc_addr(buddy->bits[i]))
+ vfree(buddy->bits[i]);
+ else
+ kfree(buddy->bits[i]);
+ buddy->bits[i] = NULL;
+ }
+ kfree(buddy->bits);
+ buddy->bits = NULL;
+ kfree(buddy->num_free);
+ buddy->num_free = NULL;
+}
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_buddy.h b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_buddy.h
new file mode 100644
index 0000000000000..303de57bae935
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_buddy.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef HMM_BUDDY_H
+#define HMM_BUDDY_H
+
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+
+#if defined(__i386__)
+#include <linux/highmem.h>
+#endif
+
+#ifndef HMM_INVALID_INDEX
+#define HMM_INVALID_INDEX 0xFFFFFFFF
+#endif
+
+struct hmm_buddy {
+ unsigned long **bits; /* 指向多级bitmap的内存 */
+ unsigned int *num_free; /* 指示各级bitmap中可用的索引个数 */
+ u32 max_order; /* 指bitmap的级数 */
+ spinlock_t lock; /* buddy的自旋锁 */
+};
+
+u32 hmm_buddy_alloc(struct hmm_buddy *buddy, u32 order);
+void hmm_buddy_free(struct hmm_buddy *buddy, u32 first_index, u32 order);
+
+int hmm_buddy_init(struct hmm_buddy *buddy, u32 max_order);
+void hmm_buddy_cleanup(struct hmm_buddy *buddy);
+
+
+#endif // HMM_BUDDY_H
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp.c b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp.c
new file mode 100644
index 0000000000000..c66ac63c5fa7d
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include "hinic3_hw.h"
+#include "hmm_comp.h"
+
+
+struct hmm_comp_priv *get_hmm_comp_priv(void *hwdev, u32 service_type)
+{
+ return (struct hmm_comp_priv *)hinic3_get_service_adapter(hwdev,
+ (enum hinic3_service_type)service_type);
+}
+
+static void assemble_mpt_hw2sw(struct rdma_mpt_hw2sw_inbuf **mpt_hw2sw_inbuf,
+ struct hmm_comp_priv *comp_priv, struct tag_cqm_cmd_buf *cqm_cmd_inbuf)
+{
+ *mpt_hw2sw_inbuf = (struct rdma_mpt_hw2sw_inbuf *)cqm_cmd_inbuf->buf;
+ memset(*mpt_hw2sw_inbuf, 0, sizeof(struct rdma_mpt_hw2sw_inbuf));
+
+ (*mpt_hw2sw_inbuf)->dmtt_flags = 0; /* 默认按VF踢除cache */
+ (*mpt_hw2sw_inbuf)->dmtt_num = 0;
+ (*mpt_hw2sw_inbuf)->dmtt_cache_line_start = cpu_to_be32(comp_priv->rdma_cap.dmtt_cl_start);
+ (*mpt_hw2sw_inbuf)->dmtt_cache_line_end = cpu_to_be32(comp_priv->rdma_cap.dmtt_cl_end);
+ (*mpt_hw2sw_inbuf)->dmtt_cache_line_size = cpu_to_be32(comp_priv->rdma_cap.dmtt_cl_sz);
+}
+
+int hmm_enable_roce_mpt(void *hwdev, struct tag_cqm_cmd_buf *cqm_cmd_inbuf, u16 channel)
+{
+ int ret;
+
+ ret = cqm_send_cmd_box(hwdev, HINIC3_MOD_ROCE, RDMA_ROCE_CMD_SW2HW_MPT,
+ cqm_cmd_inbuf, NULL, NULL, RDMA_CMD_TIME_OUT_A, channel);
+ if (ret != 0) {
+ if (hinic3_get_heartbeat_status(hwdev) != PCIE_LINK_DOWN) {
+ pr_err("%s: Send cmd rdma_roce_cmd_sw2hw_mpt failed, ret(%d)\n",
+ __func__, ret);
+ if ((ret == (-ETIMEDOUT)) || (ret == (-EPERM)))
+ return -RDMA_CMDQ_TIMEOUT;
+
+ return -RDMA_CMDQ_ERR;
+ }
+ pr_err("%s: Card not present, return err\n", __func__);
+ return -RDMA_CMDQ_ERR;
+ }
+
+ return 0;
+}
+
+static int hmm_mpt_read_back_test(struct hmm_comp_priv *comp_priv, struct rdma_mpt *mpt)
+{
+ int retry;
+ struct rdma_mpt_entry *mpt_entry = NULL;
+ struct rdma_mpt_entry check_mpt_entry;
+
+ /* 获取Host MPT内容 */
+ mpt_entry = (struct rdma_mpt_entry *)mpt->vaddr;
+ for (retry = 0; retry < RDMA_MAX_RETRY; retry++) {
+ if (hinic3_get_heartbeat_status(comp_priv->hwdev) == PCIE_LINK_DOWN) {
+ pr_err("%s: Card not present, return ok\n", __func__);
+ return 0;
+ }
+ /*
+ * Confirm that the chip operation is complete by comparing the MPT State field.
+ * If the readback status is correct, the loop exits. Otherwise,
+ * the loop continues to read and compare data after a forcible
+ * delay until the loop ends.
+ */
+ check_mpt_entry.roce_mpt_ctx.dw2.value =
+ be32_to_cpu(mpt_entry->roce_mpt_ctx.dw2.value);
+ if (check_mpt_entry.roce_mpt_ctx.dw2.bs.status == RDMA_MPT_STATUS_INVALID)
+ return 0;
+
+ /*lint -e160 -e506*/
+ mdelay(RDMA_MS_DELAY);
+ }
+
+ pr_err("%s: RoCE mpt state read times(%d), mpt_index(0x%x), state_dw(0x%x)\n",
+ __func__, retry, mpt->mpt_index, mpt_entry->roce_mpt_ctx.dw2.value);
+ return -RDMA_CMDQ_ERR;
+}
+
+int hmm_disable_roce_mpt(struct hmm_comp_priv *comp_priv, struct rdma_mpt *mpt, u16 channel)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct rdma_mpt_hw2sw_inbuf *mpt_hw2sw_inbuf = NULL;
+
+ cqm_cmd_inbuf = cqm_cmd_alloc(comp_priv->hwdev);
+ if (cqm_cmd_inbuf == NULL) {
+ pr_err("%s: RoCE alloc cmd_buf failed, err(%d)\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+ cqm_cmd_inbuf->size = (u16)sizeof(struct rdma_mpt_hw2sw_inbuf);
+ assemble_mpt_hw2sw(&mpt_hw2sw_inbuf, comp_priv, cqm_cmd_inbuf);
+ mpt_hw2sw_inbuf->com.index = cpu_to_be32(mpt->mpt_index);
+ mpt_hw2sw_inbuf->com.dw0.bs.cmd_bitmask = (u16)cpu_to_be16(VERBS_CMD_TYPE_MR_BITMASK);
+ ret = cqm_send_cmd_box(comp_priv->hwdev, HINIC3_MOD_ROCE, RDMA_ROCE_CMD_HW2SW_MPT,
+ cqm_cmd_inbuf, NULL, NULL, RDMA_CMD_TIME_OUT_A, channel);
+ if (ret != 0) {
+ if (hinic3_get_heartbeat_status(comp_priv->hwdev) != PCIE_LINK_DOWN) {
+ pr_err("%s: Send cmd rdma_roce_cmd_hw2sw_mpt failed, ret(%d)\n",
+ __func__, ret);
+ cqm_cmd_free(comp_priv->hwdev, cqm_cmd_inbuf);
+ if ((ret == (-ETIMEDOUT)) || (ret == (-EPERM)))
+ return -RDMA_CMDQ_TIMEOUT;
+
+ return -RDMA_CMDQ_ERR;
+ }
+ pr_err("%s: Card not present, return ok\n", __func__);
+ cqm_cmd_free(comp_priv->hwdev, cqm_cmd_inbuf);
+ return 0;
+ }
+ cqm_cmd_free(comp_priv->hwdev, cqm_cmd_inbuf);
+
+ ret = hmm_mpt_read_back_test(comp_priv, mpt);
+ return ret;
+}
+
+
+int hmm_modify_roce_mpt(void *hwdev, u32 mpt_index, u32 new_key, u64 length, u64 iova, u16 channel)
+{
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf;
+ struct rdma_mpt_modify_inbuf *mpt_modify_inbuf = NULL;
+ int ret;
+
+ cqm_cmd_inbuf = cqm_cmd_alloc(hwdev);
+ if (cqm_cmd_inbuf == NULL) {
+ pr_err("%s: RoCE alloc cmd_buf failed, err(%d)\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+
+ cqm_cmd_inbuf->size = (u16)sizeof(struct rdma_mpt_modify_inbuf);
+ mpt_modify_inbuf = (struct rdma_mpt_modify_inbuf *)cqm_cmd_inbuf->buf;
+ memset(mpt_modify_inbuf, 0, sizeof(*mpt_modify_inbuf));
+
+ mpt_modify_inbuf->com.dw0.bs.cmd_bitmask = (u16)cpu_to_be16(VERBS_CMD_TYPE_MR_BITMASK);
+ mpt_modify_inbuf->com.index = cpu_to_be32(mpt_index);
+ mpt_modify_inbuf->new_key = cpu_to_be32(new_key);
+ mpt_modify_inbuf->length = cpu_to_be64(length);
+ mpt_modify_inbuf->iova = cpu_to_be64(iova);
+
+ ret = cqm_send_cmd_box(hwdev, HINIC3_MOD_ROCE, RDMA_ROCE_CMD_MODIFY_MPT,
+ cqm_cmd_inbuf, NULL, NULL, RDMA_CMD_TIME_OUT_A, channel);
+ if (ret != 0) {
+ if (hinic3_get_heartbeat_status(hwdev) != PCIE_LINK_DOWN) {
+ pr_err("%s: Send cmd rdma_roce_cmd_modify_mpt failed, ret(%d)\n",
+ __func__, ret);
+ cqm_cmd_free(hwdev, cqm_cmd_inbuf);
+ if ((ret == (-ETIMEDOUT)) || (ret == (-EPERM)))
+ return -RDMA_CMDQ_TIMEOUT;
+
+ return -RDMA_CMDQ_ERR;
+ }
+ pr_err("%s: Card not present, return ok\n", __func__);
+ cqm_cmd_free(hwdev, cqm_cmd_inbuf);
+ return 0;
+ }
+
+ cqm_cmd_free(hwdev, cqm_cmd_inbuf);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp.h b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp.h
new file mode 100644
index 0000000000000..a509d701f2e23
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp.h
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef HMM_COMP_H
+#define HMM_COMP_H
+
+#ifndef ROCE_SERVICE
+#include "ossl_knl.h"
+#endif
+#include <linux/delay.h>
+#include <linux/types.h>
+#include "roce_hmm_context.h"
+#include "hinic3_crm.h"
+#include "hinic3_cqm.h"
+#include "hinic3_rdma.h"
+#include "hmm_buddy.h"
+#include "hmm_em.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
+
+#define PCIE_LINK_DOWN 0xFFFFFFFF
+
+#define RDMA_MPT_STATUS_INVALID 0xf
+#define RDMA_MPT_STATUS_FREE 0x3
+#define RDMA_MPT_STATUS_VALID 0x1
+#define RDMA_MPT_STATUS_MEM_INIT 0xa
+
+#define RDMA_MS_DELAY 5
+#define RDMA_MAX_RETRY 200
+
+#define RDMA_MPT_DMA_ATTR_IDX 0
+#define RDMA_MPT_SO_RO 0x1
+
+#define RDMA_PA_SIZE ((u32)sizeof(dma_addr_t))
+
+#define PAGE_SIZE_4k 4096 /* page size is 4K */
+#define PAGE_SHIFT_4K 12 /* page size is 1 left shift 12 */
+
+#define PAGE_SIZE_64k (64 * 4096) /* page size is 64K */
+#define PAGE_SHIFT_64K 16 /* page size is 1 left shift 16 */
+
+#define PAGE_SIZE_2M (2 * 1024 * 1024) /* page size is 2M */
+#define PAGE_SHIFT_2M 21 /* page size is 1 left shift 21 */
+
+#define RDMA_MTT_PA_VALID 0x1
+
+#define HMM_MTT_NUM_PER_CACHELINE 32 /* 256B Cache line has 32 records */
+
+#define BLOCK_SIZE_DEVIDE_SECTOR 8 /* Chip logic: 8 */
+
+
+#define MPT_GPA_SIG_LEN 3
+
+#define RDMA_CMDQ_ERR 1
+#define RDMA_CMDQ_TIMEOUT 2
+
+#ifndef VERBS_CMD_TYPE_MR_BITMASK
+#define VERBS_CMD_TYPE_MR_BITMASK (1u << 12) /* verbs_mr_bitmask */
+#endif
+
+enum {
+ RDMA_MTT_PAGE_SIZE_4K = 0,
+ RDMA_MTT_PAGE_SIZE_64K = 1,
+ RDMA_MTT_PAGE_SIZE_2M = 2
+};
+
+#ifdef __EMU_X86__
+enum {
+ RDMA_CMD_TIME_OUT_A = 30000000,
+ RDMA_CMD_TIME_OUT_B = 40000000,
+ RDMA_CMD_TIME_OUT_C = 50000000
+};
+#else
+enum {
+ RDMA_CMD_TIME_OUT_A = 30000,
+ RDMA_CMD_TIME_OUT_B = 40000,
+ RDMA_CMD_TIME_OUT_C = 50000
+};
+#endif
+
+enum rdma_mr_mw {
+ RDMA_MPT_MW = 0,
+ RDMA_MPT_MR = 1
+};
+
+enum rdma_roce_cmd {
+ RDMA_ROCE_CMD_SW2HW_MPT = 0x70,
+ RDMA_ROCE_CMD_HW2SW_MPT = 0x71,
+ RDMA_ROCE_CMD_MODIFY_MPT = 0x72,
+ RDMA_ROCE_CMD_QUERY_MPT = 0x73,
+ RDMA_ROCE_CMD_FLUSH_TPT = 0x74,
+ RDMA_ROCE_CMD_SYNC_TPT = 0x75
+};
+
+
+enum mtt_layer {
+ RDMA_MTT_NO_LAYER = -1, /* dma mr needs no mtt */
+ RDMA_MTT_ZERO_LAYER = 0, /* 1 page mr has 0 level mtt */
+ RDMA_MTT_ONE_LAYER = 1,
+ RDMA_MTT_TWO_LAYER = 2,
+ RDMA_MTT_THREE_LAYER = 3
+};
+
+struct rdma_verbs_cmd_com {
+ union {
+ __be32 value;
+
+ struct {
+ __be32 version : 8;
+ __be32 rsvd : 8;
+ __be32 cmd_bitmask : 16;
+ } bs;
+ } dw0;
+
+ __be32 index;
+};
+
+struct hmm_service_cap {
+ struct dev_rdma_svc_cap dev_rdma_cap;
+ /*
+ * 1. the number of MTT PA must be integer power of 2
+ * 2. represented by logarithm. Each MTT table can
+ * contain 1, 2, 4, 8, and 16 PA)
+ */
+ u8 log_mtt;
+ /* todo: need to check whether related to max_mtt_seg */
+ /*
+ * Number of MTT table (4M),
+ * is actually MTT seg number
+ */
+ u32 num_mtts;
+ /* todo: max value needs to be confirmed */
+ /* MTT table number of Each MTT seg(3) */
+ u32 log_mtt_seg;
+ u32 mtt_entry_sz; /* MTT table size 8B, including 1 PA(64bits) */
+ u32 mpt_entry_sz; /* MPT table size (64B) */
+
+ u32 dmtt_cl_start;
+ u32 dmtt_cl_end;
+ u32 dmtt_cl_sz;
+ u32 mtt_page_size; /* 4K, 8K, 16K, 32K */
+ u32 mtt_page_shift; /* 12, 13, 14, 15 */
+};
+
+
+struct hmm_comp_priv {
+ struct rdma_comp_resource rdma_comp_res; /* gid & guid */
+ struct hmm_buddy mtt_buddy;
+ struct hmm_em_table mtt_em_table;
+ void *hwdev;
+ struct pci_dev *pdev;
+ struct rdma_mr rsvd_lkey;
+ struct rdma_mr fixed_mr;
+ u32 mtt_page_size; /* 4K, 8K, 16K, 32K */
+ u32 mtt_page_shift; /* 12, 13, 14, 15 */
+
+ struct hmm_service_cap rdma_cap;
+};
+
+struct rdma_mpt_entry {
+ struct roce_mpt_context roce_mpt_ctx;
+};
+
+struct rdma_mpt_sw2hw_inbuf {
+ struct rdma_verbs_cmd_com com;
+ struct rdma_mpt_entry mpt_entry;
+};
+
+struct rdma_mpt_hw2sw_inbuf {
+ struct rdma_verbs_cmd_com com;
+
+ __be32 dmtt_flags;
+ __be32 dmtt_num;
+ __be32 dmtt_cache_line_start;
+ __be32 dmtt_cache_line_end;
+ __be32 dmtt_cache_line_size;
+};
+
+struct rdma_mpt_modify_inbuf {
+ struct rdma_verbs_cmd_com com;
+ __be32 new_key;
+ __be64 length;
+ __be64 iova;
+};
+
+
+/* for llt to set stub */
+int hmm_disable_roce_mpt(struct hmm_comp_priv *comp_priv, struct rdma_mpt *mpt, u16 channel);
+
+int hmm_modify_roce_mpt(void *hwdev, u32 mpt_index,
+ u32 new_key, u64 length, u64 iova, u16 channel);
+
+struct hmm_comp_priv *get_hmm_comp_priv(void *hwdev, u32 service_type);
+
+int hmm_rdma_mpt_alloc(void *hwdev, struct rdma_mpt *mpt, u32 service_type);
+
+int hmm_enable_roce_mpt(void *hwdev, struct tag_cqm_cmd_buf *cqm_cmd_inbuf, u16 channel);
+
+#ifdef RDMA_SIGN_MTT_EN
+u64 hmm_gen_mtt_sign(u64 mtt_base_gpa, enum mtt_data_type_e type);
+
+#define RDMA_CMTT_SIGN_MASK 0x7ff
+#define RDMA_CMTT_SIGN_SHIFT0 3
+#define RDMA_CMTT_SIGN_SHIFT1 14
+#define RDMA_CMTT_SIGN_SHIFT2 25
+
+#define RDMA_DMTT_SIGN_MASK 0x3ff
+
+#define RDMA_DMTT_ADD_SHIFT0 7
+#define RDMA_DMTT_SIGN_SHIFT0 3
+#define RDMA_DMTT_SIGN_SHIFT1 6
+#define RDMA_DMTT_SIGN_SHIFT2 16
+#define RDMA_DMTT_SIGN_SHIFT3 26
+
+#endif
+
+#endif // HMM_COMP_H
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_init.c b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_init.c
new file mode 100644
index 0000000000000..7e913f221002e
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_init.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include "hinic3_hw.h"
+#include "hinic3_hw_cfg.h"
+#include "hinic3_crm.h"
+
+#include "hmm_comp.h"
+#include "hinic3_hmm.h"
+
+#define ROCE_MAX_RDMA_RC_EXTEND 384 /* 扩展表为12K */
+
+u32 g_mtt_page_size;
+module_param(g_mtt_page_size, uint, 0444);
+MODULE_PARM_DESC(g_mtt_page_size, "0:4K,1:64K,2:2M,default:4K");
+
+static int hmm_init_table(void *hwdev, struct hmm_comp_priv *comp_priv, u32 srv_type)
+{
+ int ret;
+
+ ret = hmm_init_mtt_table(comp_priv);
+ if (ret != 0) {
+ pr_err("%s: Initialize mtt's table failed, ret(%d)\n", __func__, ret);
+ kfree(comp_priv);
+ return ret;
+ }
+
+ ret = hinic3_register_service_adapter((void *)hwdev, (void *)comp_priv,
+ (enum hinic3_service_type)srv_type);
+ if (ret != 0) {
+ pr_err("%s: put hmm_comp_res failed, ret(%d)\n", __func__, ret);
+ goto err_init;
+ }
+ pr_info("%s: Hmm init resource successful\n", __func__);
+ return 0;
+
+err_init:
+ hmm_cleanup_mtt_table(comp_priv);
+ kfree(comp_priv);
+ return ret;
+}
+
+void hmm_cleanup_resource(void *hwdev, u32 service_type)
+{
+ struct rdma_service_cap rdma_cap;
+ struct hmm_comp_priv *comp_priv = NULL;
+
+ if (hwdev == NULL) {
+ pr_err("%s: Hwdev is null\n", __func__);
+ return;
+ }
+
+ if (!hinic3_support_rdma(hwdev, &rdma_cap)) {
+ pr_err("%s: Not support rdma service\n", __func__);
+ return;
+ }
+
+ comp_priv = get_hmm_comp_priv(hwdev, service_type);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return;
+ }
+
+ hmm_cleanup_mtt_table(comp_priv);
+
+ kfree(comp_priv);
+
+ hinic3_unregister_service_adapter((void *)hwdev, (enum hinic3_service_type)service_type);
+
+ pr_info("%s: Rdma cleanup resource successful", __func__);
+}
+
+int hmm_init_resource(void *hwdev, u32 service_type)
+{
+ struct hmm_comp_priv *comp_priv = NULL;
+ struct rdma_service_cap rdma_cap;
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("%s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+ if (!hinic3_support_rdma(hwdev, &rdma_cap)) {
+ pr_info("%s: Don't support hmm dev\n", __func__);
+ return 0;
+ }
+ comp_priv = kzalloc(sizeof(struct hmm_comp_priv), GFP_KERNEL);
+ if (comp_priv == NULL)
+ return -ENOMEM;
+ comp_priv->hwdev = hwdev;
+ comp_priv->pdev = (struct pci_dev *)((struct hinic3_hwdev *)hwdev)->pcidev_hdl;
+ comp_priv->rdma_cap.log_mtt = rdma_cap.log_mtt;
+ comp_priv->rdma_cap.log_mtt_seg = rdma_cap.log_mtt_seg;
+ comp_priv->rdma_cap.mtt_entry_sz = rdma_cap.mtt_entry_sz;
+ comp_priv->rdma_cap.mpt_entry_sz = rdma_cap.mpt_entry_sz;
+ comp_priv->rdma_cap.num_mtts = rdma_cap.num_mtts;
+
+ comp_priv->rdma_cap.dmtt_cl_start = rdma_cap.dev_rdma_cap.roce_own_cap.dmtt_cl_start;
+ comp_priv->rdma_cap.dmtt_cl_end = rdma_cap.dev_rdma_cap.roce_own_cap.dmtt_cl_end;
+ comp_priv->rdma_cap.dmtt_cl_sz = rdma_cap.dev_rdma_cap.roce_own_cap.dmtt_cl_sz;
+
+ switch (g_mtt_page_size) {
+ case RDMA_MTT_PAGE_SIZE_4K:
+ comp_priv->mtt_page_size = PAGE_SIZE_4k; /* page size is 4K */
+ comp_priv->mtt_page_shift = PAGE_SHIFT_4K; /* page size is 1 left shift 12 */
+ break;
+ case RDMA_MTT_PAGE_SIZE_64K:
+ comp_priv->mtt_page_size = PAGE_SIZE_64k; /* page size is 64K */
+ comp_priv->mtt_page_shift = PAGE_SHIFT_64K; /* page size is 1 left shift 16 */
+ break;
+ case RDMA_MTT_PAGE_SIZE_2M:
+ comp_priv->mtt_page_size = PAGE_SIZE_2M; /* page size is 2M */
+ comp_priv->mtt_page_shift = PAGE_SHIFT_2M; /* page size is 1 left shift 21 */
+ break;
+ default:
+ comp_priv->mtt_page_size = PAGE_SIZE_4k; /* page size is 4K */
+ comp_priv->mtt_page_shift = PAGE_SHIFT_4K; /* page size is 1 left shift 12 */
+ break;
+ }
+ ret = hmm_init_table(hwdev, comp_priv, service_type);
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_mtt.c b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_mtt.c
new file mode 100644
index 0000000000000..906ca476e840a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_mtt.c
@@ -0,0 +1,494 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_hw.h"
+#include "hinic3_rdma.h"
+#include "hmm_comp.h"
+#include "hmm_mr.h"
+
+static int hmm_set_mtt_layer(const struct hmm_comp_priv *comp_priv,
+ struct rdma_mtt *mtt, u32 npages)
+{
+ u32 one_layer_flag = 0;
+ u64 two_layer_flag = 0;
+ u64 three_layer_flag = 0;
+
+ one_layer_flag = comp_priv->mtt_page_size / RDMA_PA_SIZE;
+ two_layer_flag = ((u64)one_layer_flag) * ((u64)one_layer_flag);
+ three_layer_flag = (u64)one_layer_flag * two_layer_flag;
+
+ if (npages <= 1) {
+ mtt->mtt_layers = RDMA_MTT_ZERO_LAYER;
+ return 0;
+ } else if (npages <= one_layer_flag) {
+ mtt->mtt_layers = RDMA_MTT_ONE_LAYER;
+ } else if (npages <= two_layer_flag) {
+ mtt->mtt_layers = RDMA_MTT_TWO_LAYER;
+ } else if ((u64)npages <= three_layer_flag) {
+ mtt->mtt_layers = RDMA_MTT_THREE_LAYER;
+ } else {
+ pr_err("%s: Npages(0x%x) over range, ret(%d)\n", __func__, npages, -EINVAL);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#ifdef RDMA_SIGN_MTT_EN
+
+u16 hmm_gen_cmtt_sign(u64 mtt_base_gpa)
+{
+ u16 sign0 = (mtt_base_gpa >> RDMA_CMTT_SIGN_SHIFT0) & RDMA_CMTT_SIGN_MASK;
+ u16 sign1 = (mtt_base_gpa >> RDMA_CMTT_SIGN_SHIFT1) & RDMA_CMTT_SIGN_MASK;
+ u16 sign2 = (mtt_base_gpa >> RDMA_CMTT_SIGN_SHIFT2) & RDMA_CMTT_SIGN_MASK;
+ u16 cmtt_sign = ~(sign0 ^ sign1 ^ sign2);
+
+ cmtt_sign &= RDMA_CMTT_SIGN_MASK;
+ return cmtt_sign;
+}
+
+u16 hmm_gen_dmtt_sign(u64 mtt_base_gpa)
+{
+ u16 sign0 = ((u16)(mtt_base_gpa >> RDMA_DMTT_SIGN_SHIFT0) <<
+ RDMA_DMTT_ADD_SHIFT0) & RDMA_DMTT_SIGN_MASK;
+ u16 sign1 = (mtt_base_gpa >> RDMA_DMTT_SIGN_SHIFT1) & RDMA_DMTT_SIGN_MASK;
+ u16 sign2 = (mtt_base_gpa >> RDMA_DMTT_SIGN_SHIFT2) & RDMA_DMTT_SIGN_MASK;
+ u16 sign3 = (mtt_base_gpa >> RDMA_DMTT_SIGN_SHIFT3) & RDMA_DMTT_SIGN_MASK;
+ u16 dmtt_sign = ~(sign0 ^ sign1 ^ sign2 ^ sign3);
+
+ dmtt_sign &= RDMA_DMTT_SIGN_MASK;
+ return dmtt_sign;
+}
+
+
+u64 hmm_gen_mtt_sign(u64 mtt_base_gpa, enum mtt_data_type_e type)
+{
+ if (type == MTT_CMTT_TYPE)
+ return hmm_gen_cmtt_sign(mtt_base_gpa);
+
+ return (u64)hmm_gen_dmtt_sign(mtt_base_gpa) << 1;
+}
+
+#endif
+
+static int hmm_find_mtt_page_list(struct hmm_comp_priv *comp_priv, struct rdma_mtt_seg *mtt_seg,
+ u32 npages, u64 *page_list)
+{
+ void *vaddr = NULL;
+ u32 i = 0;
+ u32 mtt_index = 0;
+ u32 mtts_per_page = 0;
+
+ mtts_per_page = comp_priv->mtt_page_size / RDMA_PA_SIZE;
+ if ((mtt_seg->offset % mtts_per_page) != 0) {
+ pr_err("%s: First mtt isn't in the head of page, ret(%d)\n", __func__, -EINVAL);
+ return -EINVAL;
+ }
+
+ mtt_index = mtt_seg->offset;
+ for (i = 0; i < npages; i++) {
+ vaddr = hmm_em_table_find(&comp_priv->mtt_em_table, mtt_index, &page_list[i]);
+ if (vaddr == NULL) {
+ pr_err("%s: Can't find va and pa of mtt entry, ret(%d)\n",
+ __func__, -EINVAL);
+ return -EINVAL;
+ }
+
+ mtt_index += comp_priv->mtt_page_size / RDMA_PA_SIZE;
+ }
+
+ return 0;
+}
+
+static int hmm_write_mtt_chunk(struct hmm_comp_priv *comp_priv, struct rdma_mtt *mtt,
+ u32 mtt_level_index, u32 start_index, u32 npages, const u64 *page_list)
+{
+ u32 i = 0;
+ u16 sign_val = 0;
+ __be64 *mtts = NULL;
+
+ mtts = (__be64 *)hmm_em_table_find(&comp_priv->mtt_em_table,
+ mtt->mtt_seg[mtt_level_index]->offset + start_index, NULL);
+ if (mtts == NULL) {
+ pr_err("%s: Can't find va and pa of mtt entry, ret(%d)\n", __func__, -EINVAL);
+ return -EINVAL;
+ }
+#ifdef RDMA_SIGN_MTT_EN
+ sign_val = hmm_gen_mtt_sign(mtt->mtt_paddr, mtt->mtt_type);
+#endif
+ for (i = 0; i < npages; i++)
+ mtts[i] = cpu_to_be64(page_list[i] | RDMA_MTT_PA_VALID | (sign_val << 1));
+
+ return 0;
+}
+
+static int hmm_write_mtt_seg(struct hmm_comp_priv *comp_priv, struct rdma_mtt *mtt,
+ u32 mtt_level_index, u32 start_index, u32 npages, u64 *page_list)
+{
+ int ret = 0;
+ u32 chunk = 0;
+ u32 mtts_per_page = 0;
+ u32 max_mtts_first_page = 0;
+ u32 tmp_npages = npages;
+ u32 tmp_start_index = start_index;
+ u64 *tmp_page_list = page_list;
+
+ /* calculate how may mtts fit in the first page */
+ mtts_per_page = comp_priv->mtt_page_size / RDMA_PA_SIZE;
+ max_mtts_first_page = mtts_per_page - ((mtt->mtt_seg[mtt_level_index]->offset
+ + tmp_start_index) % mtts_per_page);
+
+ chunk = (tmp_npages < max_mtts_first_page) ? tmp_npages : max_mtts_first_page;
+
+ while ((int)tmp_npages > 0) {
+ ret = hmm_write_mtt_chunk(comp_priv, mtt, mtt_level_index,
+ tmp_start_index, chunk, tmp_page_list);
+ if (ret != 0) {
+ pr_err("%s: Write mtt chunk failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ tmp_npages -= chunk;
+ tmp_start_index += chunk;
+ tmp_page_list += chunk;
+
+ chunk = (tmp_npages < mtts_per_page) ? tmp_npages : mtts_per_page;
+ }
+
+ return 0;
+}
+
+static int hmm_alloc_mtt_seg(struct hmm_comp_priv *comp_priv, struct rdma_mtt_seg *mtt_seg)
+{
+ int ret = 0;
+ u32 seg_offset = 0;
+ u32 seg_order = 0;
+ u32 log_mtts_per_seg = 0;
+
+ log_mtts_per_seg = comp_priv->rdma_cap.log_mtt_seg;
+
+ seg_order = (mtt_seg->order > log_mtts_per_seg) ? (mtt_seg->order - log_mtts_per_seg) : 0;
+ mtt_seg->order = seg_order + log_mtts_per_seg;
+
+ seg_offset = hmm_buddy_alloc(&comp_priv->mtt_buddy, seg_order);
+ if (seg_offset == HMM_INVALID_INDEX) {
+ pr_err("%s: Alloc mtt index failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ mtt_seg->offset = seg_offset << log_mtts_per_seg;
+
+ ret = hmm_em_table_get_range(comp_priv->pdev, &comp_priv->mtt_em_table, mtt_seg->offset,
+ mtt_seg->offset + (u32)(1U << mtt_seg->order) - 1);
+ if (ret != 0) {
+ pr_err("%s: Alloc mtt entry failed, ret(%d)\n", __func__, ret);
+ goto err_get_entry;
+ }
+
+ mtt_seg->vaddr = hmm_em_table_find(&comp_priv->mtt_em_table, mtt_seg->offset,
+ &mtt_seg->paddr);
+ if (mtt_seg->vaddr == NULL) {
+ pr_err("%s: Can't find start address of mtt_seg\n", __func__);
+ goto err_find_entry;
+ }
+
+ return 0;
+
+err_find_entry:
+ hmm_em_table_put_range(comp_priv->pdev, &comp_priv->mtt_em_table, mtt_seg->offset,
+ mtt_seg->offset + (u32)(1U << mtt_seg->order) - 1);
+
+err_get_entry:
+ hmm_buddy_free(&comp_priv->mtt_buddy, seg_offset, seg_order);
+
+ return -ENOMEM;
+}
+
+static void hmm_free_mtt_seg(struct hmm_comp_priv *comp_priv, struct rdma_mtt_seg *mtt_seg)
+{
+ u32 seg_offset = 0;
+ u32 seg_order = 0;
+ int log_mtts_per_seg = 0;
+
+ hmm_em_table_put_range(comp_priv->pdev, &comp_priv->mtt_em_table, mtt_seg->offset,
+ mtt_seg->offset + (1U << mtt_seg->order) - 1);
+
+ log_mtts_per_seg = (int)comp_priv->rdma_cap.log_mtt_seg;
+ seg_order = mtt_seg->order - (u32)log_mtts_per_seg;
+ seg_offset = mtt_seg->offset >> (unsigned int)log_mtts_per_seg;
+
+ hmm_buddy_free(&comp_priv->mtt_buddy, seg_offset, seg_order);
+}
+
+static int hmm_init_mtt_seg(struct hmm_comp_priv *comp_priv, struct rdma_mtt *mtt, u32 npages)
+{
+ u32 i;
+ int ret;
+
+ if ((comp_priv == NULL) || (mtt == NULL)) {
+ pr_err("%s: Comp_priv or mtt is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (npages >= comp_priv->rdma_cap.num_mtts) {
+ pr_err("%s: Npages(0x%x) over range, ret(%d)\n", __func__, npages, -EINVAL);
+ return -EINVAL;
+ }
+
+ ret = hmm_set_mtt_layer(comp_priv, mtt, npages);
+ if (ret != 0)
+ return ret;
+
+ mtt->mtt_seg = kcalloc(mtt->mtt_layers, sizeof(struct rdma_mtt_seg *), GFP_KERNEL);
+ if (mtt->mtt_seg == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < mtt->mtt_layers; i++) {
+ mtt->mtt_seg[i] = kzalloc(sizeof(struct rdma_mtt_seg), GFP_KERNEL);
+ if (mtt->mtt_seg[i] == NULL)
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ for (i = 0; i < mtt->mtt_layers; i++) {
+ kfree(mtt->mtt_seg[i]);
+ mtt->mtt_seg[i] = NULL;
+ }
+
+ kfree(mtt->mtt_seg);
+ mtt->mtt_seg = NULL;
+
+ return -ENOMEM;
+}
+
+static int hmm_rdma_mtt_alloc_prepare(void *hwdev, u32 npages, struct rdma_mtt *mtt,
+ struct hmm_comp_priv **comp_priv, u32 service_type)
+{
+ int ret = 0;
+
+ if ((hwdev == NULL) || (mtt == NULL)) {
+ pr_err("%s: Hwdev or mtt is null\n", __func__);
+ return -EINVAL;
+ }
+
+ *comp_priv = get_hmm_comp_priv(hwdev, service_type);
+ if (*comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = hmm_init_mtt_seg(*comp_priv, mtt, npages);
+ if (ret != 0) {
+ pr_err("%s: Initialize mtt_seg failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int hmm_enable_mtt_related(struct hmm_comp_priv *comp_priv, struct rdma_mtt *mtt,
+ u32 low_layer_index)
+{
+ u64 *page_list = NULL;
+ struct rdma_mtt_seg *low_mtt_seg = NULL;
+ u32 npages = 0;
+ int ret = 0;
+
+ low_mtt_seg = mtt->mtt_seg[low_layer_index];
+ npages = (u32)((1UL << low_mtt_seg->order) / (comp_priv->mtt_page_size / RDMA_PA_SIZE));
+ page_list = kzalloc(npages * RDMA_PA_SIZE, GFP_KERNEL);
+ if (page_list == NULL)
+ return -ENOMEM;
+
+ ret = hmm_find_mtt_page_list(comp_priv, low_mtt_seg, npages, page_list);
+ if (ret != 0) {
+ pr_err("%s: Can't find page_list of mtt_seg, ret(%d)\n", __func__, ret);
+ goto out;
+ }
+
+ ret = hmm_write_mtt_seg(comp_priv, mtt, low_layer_index + 1, 0, npages, page_list);
+ if (ret != 0) {
+ pr_err("%s: Write mtt_seg failed, ret(%d)\n", __func__, ret);
+ goto out;
+ }
+
+out:
+ kfree(page_list);
+
+ return ret;
+}
+
+static void hmm_cleanup_mtt_seg(struct rdma_mtt *mtt)
+{
+ u32 i = 0;
+
+ for (i = 0; i < mtt->mtt_layers; i++) {
+ kfree(mtt->mtt_seg[i]);
+ mtt->mtt_seg[i] = NULL;
+ }
+
+ kfree(mtt->mtt_seg);
+ mtt->mtt_seg = NULL;
+}
+
+int hmm_rdma_mtt_alloc(void *hwdev, u32 npages, u32 page_shift, struct rdma_mtt *mtt,
+ u32 service_type)
+{
+ struct hmm_comp_priv *comp_priv = NULL;
+ int ret = 0;
+ u32 i = 0;
+ u32 cur_layer = 0;
+ u32 order = 0;
+ u32 tmp_npages = npages;
+
+ ret = hmm_rdma_mtt_alloc_prepare(hwdev, npages, mtt, &comp_priv, service_type);
+ if (ret != 0)
+ return ret;
+
+ for (cur_layer = 1; cur_layer <= mtt->mtt_layers; cur_layer++) {
+ tmp_npages = (tmp_npages < HMM_MTT_NUM_PER_CACHELINE) ?
+ HMM_MTT_NUM_PER_CACHELINE : tmp_npages;
+ for (i = 1; i < tmp_npages; i <<= 1)
+ order++;
+
+ mtt->mtt_seg[cur_layer - 1]->order = order;
+ ret = hmm_alloc_mtt_seg(comp_priv, mtt->mtt_seg[cur_layer - 1]);
+ if (ret != 0) {
+ pr_err("%s: Alloc mtt_seg failed, npages(%d), ret(%d)\n",
+ __func__, tmp_npages, ret);
+ goto err_out;
+ }
+
+ tmp_npages = (u32)(1U << mtt->mtt_seg[cur_layer - 1]->order) /
+ (comp_priv->mtt_page_size / RDMA_PA_SIZE);
+ order = 0;
+ }
+ if (mtt->mtt_layers > 0) {
+ mtt->mtt_vaddr = (__be64 *)mtt->mtt_seg[mtt->mtt_layers - 1]->vaddr;
+ mtt->mtt_paddr = mtt->mtt_seg[mtt->mtt_layers - 1]->paddr;
+ }
+ for (i = 1; i < mtt->mtt_layers; i++) {
+ ret = hmm_enable_mtt_related(comp_priv, mtt, i - 1);
+ if (ret != 0) {
+ pr_err("%s: Cant't get multi mtt_seg related, i(%d), ret(%d)\n",
+ __func__, i, ret);
+ goto err_out;
+ }
+ }
+ mtt->buf_page_shift = page_shift;
+ mtt->mtt_page_shift = comp_priv->mtt_page_shift;
+ return 0;
+err_out:
+ for (i = cur_layer - 1; i > 0; i--)
+ hmm_free_mtt_seg(comp_priv, mtt->mtt_seg[i - 1]);
+
+ hmm_cleanup_mtt_seg(mtt);
+ return -ENOMEM;
+}
+
+void hmm_rdma_mtt_free(void *hwdev, struct rdma_mtt *mtt, u32 service_type)
+{
+ struct hmm_comp_priv *comp_priv = NULL;
+ u32 i = 0;
+
+ if ((hwdev == NULL) || (mtt == NULL)) {
+ pr_err("%s: Hwdev or mtt is null\n", __func__);
+ return;
+ }
+
+ comp_priv = get_hmm_comp_priv(hwdev, service_type);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return;
+ }
+
+ if (mtt->mtt_layers == 0)
+ return;
+
+ for (i = 0; i < mtt->mtt_layers; i++)
+ hmm_free_mtt_seg(comp_priv, mtt->mtt_seg[i]);
+
+ hmm_cleanup_mtt_seg(mtt);
+}
+
+int hmm_rdma_write_mtt(void *hwdev, struct rdma_mtt *mtt, u32 start_index, u32 npages,
+ u64 *page_list, u32 service_type)
+{
+ struct hmm_comp_priv *comp_priv = NULL;
+ int ret = 0;
+
+ if ((hwdev == NULL) || (mtt == NULL)) {
+ pr_err("%s: Hwdev or mtt is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_hmm_comp_priv(hwdev, service_type);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (mtt->mtt_layers == 0) {
+ mtt->mtt_paddr = page_list[0];
+ return 0;
+ }
+
+ ret = hmm_write_mtt_seg(comp_priv, mtt, 0, start_index, npages, page_list);
+ if (ret != 0) {
+ pr_err("%s: Write mtt seg failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int hmm_init_mtt_table(struct hmm_comp_priv *comp_priv)
+{
+ int ret = 0;
+ u32 i = 0;
+ u32 max_order = 0;
+ u32 mtt_num = 0;
+ u32 mtt_size = 0;
+ u32 log_mtts_per_seg = 0;
+
+ mtt_num = comp_priv->rdma_cap.num_mtts;
+ log_mtts_per_seg = comp_priv->rdma_cap.log_mtt_seg;
+ mtt_size = comp_priv->rdma_cap.mtt_entry_sz;
+
+ for (i = 1; i < mtt_num; i <<= 1)
+ max_order++;
+
+ max_order = (max_order > log_mtts_per_seg) ? (max_order - log_mtts_per_seg) : 0;
+
+ ret = hmm_buddy_init(&comp_priv->mtt_buddy, max_order);
+ if (ret != 0) {
+ pr_err("%s: Initialize mtt's buddy failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ ret = hmm_em_init_table(comp_priv->pdev, &comp_priv->mtt_em_table, mtt_size, mtt_num, 0,
+ (int)(comp_priv->mtt_page_shift - PAGE_SHIFT_4K));
+ if (ret != 0) {
+ pr_err("%s: Initialize mtt's em_table failed, ret(%d)\n", __func__, ret);
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ hmm_buddy_cleanup(&comp_priv->mtt_buddy);
+
+ return ret;
+}
+
+void hmm_cleanup_mtt_table(struct hmm_comp_priv *comp_priv)
+{
+ hmm_em_cleanup_table(comp_priv->pdev, &comp_priv->mtt_em_table);
+
+ hmm_buddy_cleanup(&comp_priv->mtt_buddy);
+}
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_mw_mr.c b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_mw_mr.c
new file mode 100644
index 0000000000000..fce8f5c016a55
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_mw_mr.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_hw.h"
+#include "hmm_comp.h"
+
+static void hmm_roce_mpt_to_big_endian(struct roce_mpt_context *mpt_ctx)
+{
+ mpt_ctx->dw0.value = cpu_to_be32(mpt_ctx->dw0.value);
+ mpt_ctx->dw1.value = cpu_to_be32(mpt_ctx->dw1.value);
+ mpt_ctx->dw2.value = cpu_to_be32(mpt_ctx->dw2.value);
+ mpt_ctx->dw3.value = cpu_to_be32(mpt_ctx->dw3.value);
+ mpt_ctx->iova = cpu_to_be64(mpt_ctx->iova);
+ mpt_ctx->length = cpu_to_be64(mpt_ctx->length);
+ mpt_ctx->mtt_base_addr = cpu_to_be64(mpt_ctx->mtt_base_addr);
+ mpt_ctx->mtt_sz = cpu_to_be32(mpt_ctx->mtt_sz);
+}
+
+static void hmm_set_roce_mr_access(struct roce_mpt_context *mpt_ctx, const struct rdma_mr *mr)
+{
+ mpt_ctx->dw0.bs.access_lr = 1; /* Local access enabled by default */
+
+ if ((RDMA_IB_ACCESS_LOCAL_WRITE & mr->access) != 0)
+ mpt_ctx->dw0.bs.access_lw = 1;
+
+ if ((RDMA_IB_ACCESS_REMOTE_READ & mr->access) != 0)
+ mpt_ctx->dw0.bs.access_rr = 1;
+
+ if ((RDMA_IB_ACCESS_REMOTE_WRITE & mr->access) != 0)
+ mpt_ctx->dw0.bs.access_rw = 1;
+
+ if ((RDMA_IB_ACCESS_REMOTE_ATOMIC & mr->access) != 0)
+ mpt_ctx->dw0.bs.access_ra = 1;
+
+ if ((RDMA_IB_ACCESS_MW_BIND & mr->access) != 0)
+ mpt_ctx->dw0.bs.access_bind = 1;
+}
+
+static void hmm_set_mptc_type_above_phy_mr(struct roce_mpt_context *mpt_ctx, struct rdma_mr *mr)
+{
+ switch (mr->mr_type) {
+ case RDMA_PHYS_MR:
+ mpt_ctx->mtt_base_addr = mr->mtt.mtt_paddr;
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_VALID;
+ break;
+
+ case RDMA_RSVD_LKEY:
+ mpt_ctx->dw0.bs.rkey = 1;
+ mpt_ctx->dw0.bs.bpd = 0;
+ mpt_ctx->dw0.bs.invalid_en = 0;
+ mpt_ctx->dw0.bs.remote_invalid_en = 0;
+ mpt_ctx->dw0.bs.pa = 1;
+ mpt_ctx->mtt_base_addr = 0;
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_VALID;
+ break;
+
+ case RDMA_SIG_MR:
+ mpt_ctx->mtt_base_addr = mr->mtt.mtt_paddr;
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_FREE;
+ break;
+
+ case RDMA_INDIRECT_MR:
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_FREE;
+ break;
+ default:
+ pr_err("%s: RoCE unsupport mr type(%d)\n", __func__, mr->mr_type);
+ break;
+ }
+}
+
+static void hmm_set_mptc_type_below_phy_mr(struct roce_mpt_context *mpt_ctx, struct rdma_mr *mr)
+{
+ switch (mr->mr_type) {
+ case RDMA_DMA_MR:
+ mpt_ctx->dw0.bs.pa = 1;
+ mpt_ctx->mtt_base_addr = 0;
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_VALID;
+ break;
+
+ case RDMA_USER_MR:
+ mpt_ctx->mtt_base_addr = mr->mtt.mtt_paddr;
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_VALID;
+ break;
+
+ case RDMA_FRMR:
+ mpt_ctx->mtt_base_addr = mr->mtt.mtt_paddr;
+ mpt_ctx->dw0.bs.fast_reg_en = 1;
+ mpt_ctx->dw0.bs.remote_access_en = 1;
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_FREE;
+ mpt_ctx->mtt_sz = (mr->mtt.mtt_layers > 0) ? 1U <<
+ mr->mtt.mtt_seg[mr->mtt.mtt_layers - 1]->order : 0;
+ break;
+
+ case RDMA_FMR:
+ mpt_ctx->mtt_base_addr = mr->mtt.mtt_paddr;
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_VALID;
+ break;
+ default:
+ pr_err("%s: RoCE unsupport mr type(%d)\n", __func__, mr->mr_type);
+ break;
+ }
+}
+
+static void hmm_set_mptc_according_to_mr_type(struct roce_mpt_context *mpt_ctx, struct rdma_mr *mr)
+{
+ if (mr->mr_type < RDMA_PHYS_MR)
+ hmm_set_mptc_type_below_phy_mr(mpt_ctx, mr);
+ else
+ hmm_set_mptc_type_above_phy_mr(mpt_ctx, mr);
+}
+
+static void hmm_set_roce_mr_cmd_buf(struct roce_mpt_context *mpt_ctx, struct rdma_mr *mr)
+{
+ hmm_set_roce_mr_access(mpt_ctx, mr);
+
+ mpt_ctx->dw0.bs.invalid_en = 1;
+ mpt_ctx->dw0.bs.remote_invalid_en = 1;
+ mpt_ctx->dw0.bs.r_w = RDMA_MPT_MR;
+ mpt_ctx->dw0.bs.bpd = 1;
+ mpt_ctx->dw2.bs.pdn = mr->pdn & 0x3ffff;
+
+ if (mr->mr_type != RDMA_INDIRECT_MR) {
+ mpt_ctx->dw0.bs.mtt_page_size =
+ (mr->mtt.mtt_page_shift > PAGE_SHIFT_4K) ?
+ (mr->mtt.mtt_page_shift - PAGE_SHIFT_4K) : 0;
+ mpt_ctx->dw0.bs.mtt_layer_num = mr->mtt.mtt_layers;
+ mpt_ctx->dw0.bs.buf_page_size =
+ (mr->mtt.buf_page_shift > PAGE_SHIFT_4K) ?
+ (mr->mtt.buf_page_shift - PAGE_SHIFT_4K) : 0;
+ mpt_ctx->dw1.bs.dma_attr_idx = RDMA_MPT_DMA_ATTR_IDX;
+ mpt_ctx->dw1.bs.so_ro = 0;
+ mpt_ctx->dw2.bs.block_size = (mr->block_size / BLOCK_SIZE_DEVIDE_SECTOR) & 0x3f;
+ if (mr->block_size > 0)
+ mpt_ctx->dw3.bs.page_mode = 1;
+
+ mpt_ctx->iova = mr->iova;
+ mpt_ctx->length = mr->size;
+ mpt_ctx->dw3.bs.fbo = 0;
+ if ((mr->access & RDMA_IB_ACCESS_ZERO_BASED) != 0) {
+ mpt_ctx->dw0.bs.zbva = 1;
+ mpt_ctx->dw3.bs.fbo = mr->iova & PAGE_MASK;
+ mpt_ctx->iova = 0;
+ }
+ } else {
+ mpt_ctx->dw2.bs.indirect_mr = 1;
+ }
+
+ mpt_ctx->dw3.bs.mkey = mr->key & 0xFF;
+
+ hmm_set_mptc_according_to_mr_type(mpt_ctx, mr);
+ hmm_roce_mpt_to_big_endian(mpt_ctx);
+}
+
+int hmm_rdma_disable_mr_mpt(void *hwdev, struct rdma_mr *mr, u32 service_type, u16 channel)
+{
+ struct hmm_comp_priv *comp_priv = NULL;
+ int ret = 0;
+
+ if ((hwdev == NULL) || (mr == NULL)) {
+ pr_err("%s: Hwdev or mr is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_hmm_comp_priv(hwdev, service_type);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (mr->enabled == RDMA_MPT_EN_HW) {
+ ret = hmm_disable_roce_mpt(comp_priv, &mr->mpt, channel);
+ if (ret != 0) {
+ pr_err("%s: Disable mr's mpt failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ mr->enabled = RDMA_MPT_EN_SW;
+ }
+ return 0;
+}
+
+int hmm_rdma_enable_mr_mpt(void *hwdev, struct rdma_mr *mr, u16 channel)
+{
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct rdma_mpt_entry *mpt_entry = NULL;
+ struct rdma_mpt_sw2hw_inbuf *mpt_sw2hw_inbuf = NULL;
+ int ret = 0;
+
+ if ((hwdev == NULL) || (mr == NULL)) {
+ pr_err("%s: Hwdev or mr is null\n", __func__);
+ return -EINVAL;
+ }
+
+ cqm_cmd_inbuf = cqm_cmd_alloc(hwdev);
+ if (cqm_cmd_inbuf == NULL) {
+ pr_err("%s: Alloc cmd_buf failed, err(%d)\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+
+ cqm_cmd_inbuf->size = (u16)sizeof(struct rdma_mpt_sw2hw_inbuf);
+ mpt_sw2hw_inbuf = (struct rdma_mpt_sw2hw_inbuf *)cqm_cmd_inbuf->buf;
+ memset(mpt_sw2hw_inbuf, 0, sizeof(*mpt_sw2hw_inbuf));
+ mpt_sw2hw_inbuf->com.dw0.bs.cmd_bitmask = (u16)cpu_to_be16(VERBS_CMD_TYPE_MR_BITMASK);
+ mpt_sw2hw_inbuf->com.index = cpu_to_be32(mr->mpt.mpt_index);
+ mpt_entry = &mpt_sw2hw_inbuf->mpt_entry;
+
+ hmm_set_roce_mr_cmd_buf(&mpt_entry->roce_mpt_ctx, mr);
+ ret = hmm_enable_roce_mpt(hwdev, cqm_cmd_inbuf, channel);
+ if (ret != 0) {
+ pr_err("%s: Enable mr's mpt failed, ret(%d)\n", __func__, ret);
+ goto out;
+ }
+ mr->enabled = RDMA_MPT_EN_HW;
+out:
+ cqm_cmd_free(hwdev, cqm_cmd_inbuf);
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_res.c b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_res.c
new file mode 100644
index 0000000000000..84f4c37d9e848
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_comp_res.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_hw.h"
+#include "hmm_comp.h"
+
+int hmm_rdma_mpt_alloc(void *hwdev, struct rdma_mpt *mpt, u32 service_type)
+{
+ struct hmm_comp_priv *comp_priv = NULL;
+ struct rdma_mpt_entry *mpt_entry = NULL;
+ u32 mpt_entry_size = 0;
+
+ if ((hwdev == NULL) || (mpt == NULL)) {
+ pr_err("%s: Hwdev or mpt is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_hmm_comp_priv(hwdev, service_type);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+ mpt_entry_size = comp_priv->rdma_cap.mpt_entry_sz;
+
+ mpt->mpt_object =
+ (void *)cqm_object_qpc_mpt_create(hwdev, service_type, CQM_OBJECT_MPT,
+ mpt_entry_size, mpt, CQM_INDEX_INVALID, false);
+ if (mpt->mpt_object == NULL) {
+ pr_err("%s: Alloc mpt_object failed, err(%d)\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+
+ mpt->mpt_index = ((struct tag_cqm_qpc_mpt *)mpt->mpt_object)->xid;
+ mpt->vaddr = (void *)((struct tag_cqm_qpc_mpt *)mpt->mpt_object)->vaddr;
+ if (!cqm_need_secure_mem(hwdev)) {
+ memset(mpt->vaddr, 0, sizeof(struct rdma_mpt_entry));
+
+ mpt_entry = (struct rdma_mpt_entry *)mpt->vaddr;
+ mpt_entry->roce_mpt_ctx.dw2.bs.status = RDMA_MPT_STATUS_MEM_INIT;
+ mpt_entry->roce_mpt_ctx.dw2.value = cpu_to_be32(mpt_entry->roce_mpt_ctx.dw2.value);
+ }
+ return 0;
+}
+
+
+void hmm_rdma_mpt_free(void *hwdev, struct rdma_mpt *mpt)
+{
+ if ((hwdev == NULL) || (mpt == NULL)) {
+ pr_err("%s: Hwdev or mpt is null\n", __func__);
+ return;
+ }
+ hiudk_cqm_object_delete(hwdev, &((struct tag_cqm_qpc_mpt *)mpt->mpt_object)->object);
+ mpt->vaddr = NULL;
+ mpt->mpt_object = NULL;
+}
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_em.c b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_em.c
new file mode 100644
index 0000000000000..6830725c41d79
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_em.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+
+#include "hmm_em.h"
+
+static void hmm_em_chunk_free(struct pci_dev *pdev, struct hmm_em_chunk *em_chunk)
+{
+ struct hmm_em_buf *cur_buf = NULL;
+ struct hmm_em_buf *next_buf = NULL;
+
+ cur_buf = &em_chunk->em_buf_list;
+ next_buf = cur_buf->next_buf;
+
+ while (next_buf != NULL) {
+ cur_buf = next_buf;
+ next_buf = cur_buf->next_buf;
+
+ if ((cur_buf->buf != NULL) && (cur_buf->length > 0)) {
+ memset(cur_buf->buf, 0, cur_buf->length);
+ dma_free_coherent(&pdev->dev, (unsigned long)cur_buf->length,
+ cur_buf->buf, cur_buf->dma_addr);
+ cur_buf->buf = NULL;
+ cur_buf->length = 0;
+ }
+
+ kfree(cur_buf);
+ cur_buf = NULL;
+ }
+
+ kfree(em_chunk);
+}
+
+static int hmm_em_chunk_alloc_npages(struct pci_dev *pdev, struct hmm_em_chunk *em_chunk,
+ int min_order)
+{
+ int cur_order = 0;
+ int npages = 0;
+ unsigned int chunk_size = HMM_EM_CHUNK_SIZE;
+ struct hmm_em_buf *cur_buf = &em_chunk->em_buf_list;
+ struct hmm_em_buf *next_buf = NULL;
+
+ cur_buf->next_buf = NULL;
+ cur_buf->length = 0;
+ cur_order = get_order(chunk_size); //lint !e834 !e587
+ npages = (int)(1U << (unsigned int)cur_order);
+ while (npages > 0) {
+ if (next_buf == NULL) {
+ next_buf = kzalloc(sizeof(struct hmm_em_buf), GFP_KERNEL);
+ if (next_buf == NULL)
+ return (-ENOMEM);
+
+ next_buf->length = 0;
+ next_buf->next_buf = NULL;
+ }
+ cur_buf->next_buf = next_buf;
+
+ next_buf->buf = dma_alloc_coherent(&pdev->dev, (size_t)HMM_EM_PAGE_SIZE <<
+ (unsigned int)cur_order, &next_buf->dma_addr, GFP_KERNEL);
+ if (next_buf->buf == NULL) {
+ cur_order--;
+ if (cur_order < min_order) {
+ dev_err(&pdev->dev,
+ "[HMM] %s:em_chunk alloc dma buf failed, err(%d)\n",
+ __func__, -ENOMEM);
+ return (-ENOMEM);
+ }
+ dev_err(&pdev->dev,
+ "[HMM, WARN] %s: em_chunk alloc %d dma failed, alloc small mem\n",
+ __func__, cur_order);
+ continue;
+ }
+
+ next_buf->length = (u32)HMM_EM_PAGE_SIZE << (unsigned int)cur_order;
+ em_chunk->buf_num++;
+ npages -= (int)(1U << (unsigned int)cur_order);
+
+ cur_buf = next_buf;
+ next_buf = NULL;
+ }
+
+ return 0;
+}
+static struct hmm_em_chunk *hmm_em_chunk_alloc(struct pci_dev *pdev, int min_order)
+{
+ struct hmm_em_chunk *em_chunk = NULL;
+ int ret;
+
+ em_chunk = kzalloc(sizeof(struct hmm_em_chunk), GFP_KERNEL);
+ if (em_chunk == NULL)
+ return (struct hmm_em_chunk *)ERR_PTR((long)-ENOMEM);
+
+ em_chunk->buf_num = 0;
+ ret = hmm_em_chunk_alloc_npages(pdev, em_chunk, min_order);
+ if (ret != 0) {
+ hmm_em_chunk_free(pdev, em_chunk);
+ return (struct hmm_em_chunk *)ERR_PTR((long)ret);
+ }
+
+ em_chunk->refcount = 0;
+
+ return em_chunk;
+}
+
+static void hmm_em_table_put(struct pci_dev *pdev, struct hmm_em_table *em_table, u32 obj)
+{
+ u32 i = 0;
+
+ if (obj >= em_table->obj_num) {
+ dev_err(&pdev->dev, "[HMM] %s: Obj over range, obj(0x%x), max(0x%x)\n",
+ __func__, obj, em_table->obj_num - 1);
+ return;
+ }
+
+ i = obj / (HMM_EM_CHUNK_SIZE / em_table->obj_size);
+
+ mutex_lock(&em_table->mutex);
+
+ if ((em_table->em_chunk[i] == NULL) || (IS_ERR(em_table->em_chunk[i]))) {
+ dev_err(&pdev->dev, "[HMM] %s: Em_table->em_chunk[%d] not alloced, obj(0x%x)\n",
+ __func__, i, obj);
+ mutex_unlock(&em_table->mutex);
+ return;
+ }
+
+ if (em_table->em_chunk[i]->refcount == 1) {
+ em_table->em_chunk[i]->refcount = 0;
+ hmm_em_chunk_free(pdev, em_table->em_chunk[i]);
+ em_table->em_chunk[i] = NULL;
+ } else {
+ --em_table->em_chunk[i]->refcount;
+ }
+
+ mutex_unlock(&em_table->mutex);
+}
+
+static int hmm_em_table_get(struct pci_dev *pdev, struct hmm_em_table *em_table, u32 obj)
+{
+ int ret = 0;
+ u32 i;
+
+ if (obj >= em_table->obj_num) {
+ dev_err(&pdev->dev, "[HMM] %s: Obj over range, obj(0x%x), max(0x%x)\n",
+ __func__, obj, em_table->obj_num - 1);
+ return -EINVAL;
+ }
+
+ i = obj / (HMM_EM_CHUNK_SIZE / em_table->obj_size);
+
+ mutex_lock(&em_table->mutex);
+
+ if (em_table->em_chunk[i]) {
+ ++em_table->em_chunk[i]->refcount;
+ goto out;
+ }
+
+ em_table->em_chunk[i] = hmm_em_chunk_alloc(pdev, em_table->min_order);
+ if (IS_ERR(em_table->em_chunk[i])) {
+ ret = (int)PTR_ERR(em_table->em_chunk[i]);
+ dev_err(&pdev->dev, "[HMM] %s: Alloc em_chunk failed, ret(%d)\n",
+ __func__, ret);
+ goto out;
+ }
+
+ ++em_table->em_chunk[i]->refcount;
+
+out:
+ mutex_unlock(&em_table->mutex);
+
+ return ret;
+}
+
+void *hmm_em_table_find(struct hmm_em_table *em_table, u32 obj, dma_addr_t *dma_handle)
+{
+ void *vaddr = NULL;
+ struct hmm_em_chunk *em_chunk = NULL;
+ struct hmm_em_buf *cur_buf = NULL;
+ struct hmm_em_buf *next_buf = NULL;
+ u64 table_offset;
+ u32 offset;
+
+ if (em_table == NULL) {
+ pr_err("%s: Em_table is null, err(%d)\n", __func__, -EINVAL);
+ return NULL;
+ }
+
+ if (obj >= em_table->obj_num) {
+ pr_err("%s: Obj over range, obj(0x%x), max(0x%x)\n",
+ __func__, obj, em_table->obj_num - 1);
+ return NULL;
+ }
+
+ mutex_lock(&em_table->mutex);
+
+ table_offset = (u64)obj * em_table->obj_size;
+ em_chunk = em_table->em_chunk[table_offset / HMM_EM_CHUNK_SIZE];
+ offset = table_offset % HMM_EM_CHUNK_SIZE;
+
+ if (em_chunk == NULL) {
+ pr_err("%s: Em_chunk has not been alloced, err(%d)\n", __func__, -EINVAL);
+ goto err_out;
+ }
+
+ cur_buf = &em_chunk->em_buf_list;
+ next_buf = cur_buf->next_buf;
+
+ while (next_buf != NULL) {
+ cur_buf = next_buf;
+ if (offset < cur_buf->length) {
+ if (dma_handle)
+ *dma_handle = cur_buf->dma_addr + offset;
+
+ vaddr = (void *)((char *)(cur_buf->buf) + offset);
+ mutex_unlock(&em_table->mutex);
+ return vaddr;
+ }
+
+ offset -= cur_buf->length;
+ next_buf = cur_buf->next_buf;
+ }
+
+err_out:
+ mutex_unlock(&em_table->mutex);
+
+ return NULL;
+}
+
+void hmm_em_table_put_range(struct pci_dev *pdev, struct hmm_em_table *em_table,
+ u32 start, u32 end)
+{
+ int i = 0;
+ int inc = 0;
+
+ if ((pdev == NULL) || (em_table == NULL)) {
+ dev_err(&pdev->dev, "[HMM] %s: Pdev or em_table is null, err(%d)\n",
+ __func__, -EINVAL);
+ return;
+ }
+
+ inc = (int)(HMM_EM_CHUNK_SIZE / em_table->obj_size);
+ for (i = (int)start; i <= (int)end; i += inc)
+ hmm_em_table_put(pdev, em_table, (u32)i);
+}
+
+int hmm_em_table_get_range(struct pci_dev *pdev, struct hmm_em_table *em_table, u32 start, u32 end)
+{
+ int ret = 0;
+ int i = 0;
+ int inc = 0;
+
+ if ((pdev == NULL) || (em_table == NULL)) {
+ dev_err(&pdev->dev, "[HMM] %s: Pdev or em_table is null, err(%d)\n",
+ __func__, -EINVAL);
+ return -EINVAL;
+ }
+
+ inc = (int)(HMM_EM_CHUNK_SIZE / em_table->obj_size);
+
+ for (i = (int)start; i <= (int)end; i += inc) {
+ ret = hmm_em_table_get(pdev, em_table, (u32)i);
+ if (ret != 0) {
+ dev_err(&pdev->dev,
+ "[HMM] %s: Get entry failed, start(%d), end(%d), i(%d), ret(%d)\n",
+ __func__, start, end, i, ret);
+ goto err_out;
+ }
+ }
+
+ return 0;
+
+err_out:
+ while (i > (int)start) {
+ i -= inc;
+ hmm_em_table_put(pdev, em_table, (u32)i);
+ }
+
+ return ret;
+}
+
+int hmm_em_init_table(struct pci_dev *pdev, struct hmm_em_table *em_table, u32 obj_size,
+ u32 nobj, u32 reserved_bot, int min_order)
+{
+ u32 obj_per_chunk = 0;
+ u32 chunk_num = 0;
+
+ if ((pdev == NULL) || (em_table == NULL)) {
+ dev_err(&pdev->dev, "[HMM] %s: Pdev or em_table is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (nobj == 0) {
+ dev_err(&pdev->dev, "[HMM] %s: Nobj is invalid\n", __func__);
+ return -EINVAL;
+ }
+
+ /*lint -e587 */
+ if (nobj != HMM_EM_ROUNDUP_POW_OF_TWO(nobj)) {
+ dev_err(&pdev->dev, "[HMM] %s: Obj isn't pow of two, nobj(0x%x)\n",
+ __func__, nobj);
+ return -EINVAL;
+ }
+
+ if (obj_size != HMM_EM_ROUNDUP_POW_OF_TWO(obj_size)) {
+ dev_err(&pdev->dev, "[HMM] %s: Obj_size isn't pow of two, obj_size(0x%x)\n",
+ __func__, obj_size);
+ return -EINVAL;
+ }
+ /*lint +e587 */
+
+ obj_per_chunk = HMM_EM_CHUNK_SIZE / obj_size;
+ chunk_num = (nobj + obj_per_chunk - 1) / obj_per_chunk;
+
+ em_table->em_chunk = kcalloc((size_t)chunk_num,
+ sizeof(struct hmm_em_chunk *), GFP_KERNEL);
+ if (em_table->em_chunk == NULL)
+ return -ENOMEM;
+
+ em_table->chunk_num = chunk_num;
+ em_table->obj_num = nobj;
+ em_table->obj_size = obj_size;
+ em_table->min_order = min_order;
+
+ mutex_init(&em_table->mutex);
+
+ return 0;
+}
+
+void hmm_em_cleanup_table(struct pci_dev *pdev, struct hmm_em_table *em_table)
+{
+ u32 i = 0;
+
+ if ((pdev == NULL) || (em_table == NULL)) {
+ dev_err(&pdev->dev, "[HMM] %s: Pdev or em_table is null\n", __func__);
+ return;
+ }
+
+ for (i = 0; i < em_table->chunk_num; i++) {
+ if (em_table->em_chunk[i]) {
+ hmm_em_chunk_free(pdev, em_table->em_chunk[i]);
+ em_table->em_chunk[i] = NULL;
+ }
+ }
+
+ kfree(em_table->em_chunk);
+ em_table->em_chunk = NULL;
+}
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_em.h b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_em.h
new file mode 100644
index 0000000000000..328a28fef9947
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_em.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef HMM_EM_H
+#define HMM_EM_H
+
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include "hmm_umem.h"
+
+#define HMM_EM_CHUNK_SIZE (1 << 21)
+#define HMM_EM_PAGE_SIZE PAGE_SIZE // (4096UL)
+
+#define HMM_EM_ROUNDUP_POW_OF_TWO roundup_pow_of_two
+
+struct hmm_em_buf {
+ u32 length;
+ void *buf;
+ dma_addr_t dma_addr;
+ struct hmm_em_buf *next_buf;
+};
+
+struct hmm_em_chunk {
+ u32 buf_num;
+ u32 refcount;
+ struct hmm_em_buf em_buf_list;
+};
+
+struct hmm_em_table {
+ u32 chunk_num;
+ u32 obj_num;
+ u32 obj_size;
+ int min_order;
+ struct mutex mutex;
+ struct hmm_em_chunk **em_chunk;
+};
+
+
+void *hmm_em_table_find(struct hmm_em_table *em_table, u32 obj, dma_addr_t *dma_handle);
+void hmm_em_table_put_range(struct pci_dev *pdev, struct hmm_em_table *em_table,
+ u32 start, u32 end);
+int hmm_em_table_get_range(struct pci_dev *pdev, struct hmm_em_table *em_table, u32 start, u32 end);
+int hmm_em_init_table(struct pci_dev *pdev, struct hmm_em_table *em_table,
+ u32 obj_size, u32 nobj, u32 reserved_bot, int min_order);
+void hmm_em_cleanup_table(struct pci_dev *pdev, struct hmm_em_table *em_table);
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_mr.c b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_mr.c
new file mode 100644
index 0000000000000..3dd48a511a666
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_mr.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/semaphore.h>
+
+#include "hinic3_crm.h"
+#include "hmm_umem.h"
+#include "hmm_comp.h"
+#include "hinic3_hmm.h"
+#include "hmm_mr.h"
+
+/*
+ ****************************************************************************
+ Prototype : get_key_from_index
+ Description : mr key的计算算法,通过index移位计算得到
+ Input : u32 mpt_index
+ Output : None
+****************************************************************************
+*/
+static u32 get_key_from_index(u32 mpt_index)
+{
+ return (mpt_index >> MR_KEY_RIGHT_SHIFT_OFS) | (mpt_index << MR_KEY_LEFT_SHIFT_OFS);
+}
+
+/*
+ ****************************************************************************
+ Prototype : hmm_alloc_tpt
+ Description : alloc mpt and mtt
+ Input : struct hinic3_hwdev *hwdev
+ struct rdma_mr *mr
+ u32 npages
+ u32 page_shift
+ Output : None
+****************************************************************************
+*/
+static int hmm_alloc_tpt(struct hinic3_hwdev *hwdev, struct rdma_mr *mr,
+ u32 npages, u32 page_shift, u32 service_type)
+{
+ int ret;
+
+ ret = hmm_rdma_mpt_alloc(hwdev, &mr->mpt, service_type);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to alloc mpt, ret(%d), func_id(%d)\n",
+ __func__, __LINE__, ret, hinic3_global_func_id(hwdev));
+ return ret;
+ }
+ mr->enabled = RDMA_MPT_EN_SW;
+
+ /* npages = 0 or 1, means not need mtt */
+ ret = hmm_rdma_mtt_alloc(hwdev, npages, page_shift, &mr->mtt, service_type);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to alloc mtt, ret(%d), func_id(%d)\n",
+ __func__, __LINE__, ret, hinic3_global_func_id(hwdev));
+ goto err_alloc_mtt;
+ }
+ return 0;
+
+err_alloc_mtt:
+ hmm_rdma_mpt_free(hwdev, &mr->mpt);
+ mr->enabled = HMM_MPT_DISABLED;
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : hmm_free_tpt
+ Description : free mpt and mtt
+ Input : struct hinic3_hwdev *hwdev
+ struct rdma_mr *mr
+****************************************************************************
+*/
+void hmm_free_tpt(void *hwdev, struct rdma_mr *mr, u32 service_type)
+{
+ hmm_rdma_mtt_free(hwdev, &mr->mtt, service_type);
+ hmm_rdma_mpt_free(hwdev, &mr->mpt);
+ mr->enabled = HMM_MPT_DISABLED;
+}
+
+/*
+ ****************************************************************************
+ Prototype : hmm_set_rdma_mr
+ Description : set the member of rdma_mr
+ Input : struct rdma_mr *mr
+ enum rdma_mr_type mr_type
+ u32 pdn
+ u64 iova
+ u64 size
+ u32 access
+ Output : None
+****************************************************************************
+*/
+static void hmm_set_rdma_mr(struct rdma_mr *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 = access;
+ mr->key = get_key_from_index(mr->mpt.mpt_index); /* 由mpt index转换为key */
+ mr->mr_type = mr_type;
+}
+
+/*
+ ****************************************************************************
+ Prototype : hmm_alloc_mr
+ Description : register DMA_MR
+ Input : struct hinic3_hwdev *hwdev
+ enum rdma_mr_type mr_type
+ u32 max_num_sg
+ u32 service_type
+ Output : None
+****************************************************************************
+*/
+struct hmm_mr *hmm_alloc_mr(struct hinic3_hwdev *hwdev, u32 pdn, enum rdma_mr_type mr_type,
+ u32 max_num_sg, u32 service_type, u16 channel)
+{
+ u32 access_flag;
+ int ret = 0;
+ struct hmm_mr *mr = NULL;
+
+ if (hwdev == NULL) {
+ ret = -EINVAL;
+ pr_err("[HMM, ERR] %s(%d): dev is null\n", __func__, __LINE__);
+ goto err_out;
+ }
+#ifndef PANGEA_V6
+ if (mr_type != RDMA_DMA_MR && mr_type != RDMA_INDIRECT_MR) {
+#else
+ if (mr_type != RDMA_DMA_MR) {
+#endif
+ ret = -EINVAL;
+ pr_err("[HMM, ERR] %s(%d): mr_type is invalid\n", __func__, __LINE__);
+ goto err_out;
+ }
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (mr == NULL) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ ret = hmm_alloc_tpt(hwdev->dev_hdl, &mr->rdmamr, 0, 0, service_type);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to alloc mpt and mtt, func_id(%d)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto err_alloc_tpt;
+ }
+
+ access_flag = (RDMA_IB_ACCESS_REMOTE_READ | RDMA_IB_ACCESS_REMOTE_WRITE |
+ RDMA_IB_ACCESS_LOCAL_WRITE | RDMA_IB_ACCESS_REMOTE_ATOMIC);
+
+ hmm_set_rdma_mr(&mr->rdmamr, mr_type, pdn, 0ULL, ROCE_DMA_MR_SIZE, access_flag);
+
+ ret = hmm_rdma_enable_mr_mpt(hwdev->dev_hdl, &(mr->rdmamr), channel);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to enable mpt of DMA mr, func_id(%d)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto err_enable_mpt;
+ }
+
+ return mr;
+
+err_enable_mpt:
+ hmm_free_tpt(hwdev->dev_hdl, &mr->rdmamr, service_type);
+
+err_alloc_tpt:
+ kfree(mr);
+
+err_out:
+ return (struct hmm_mr *)ERR_PTR((long)ret);
+}
+
+static int hmm_umem_write_mtt_check(const void *hwdev, const struct rdma_mtt *mtt,
+ const struct hmm_umem *umem)
+{
+ if ((hwdev == NULL) || (mtt == NULL) || (umem == NULL)) {
+ pr_err("[HMM, ERR] %s(%d): hwdev or mtt or umem is null\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int hmm_umem_write_mtt_update(struct hinic3_hwdev *hwdev, struct rdma_mtt *mtt,
+ struct hmm_umem *umem, u64 *page_list, u32 service_type)
+{
+ int ret = 0;
+ int i = 0;
+ u32 j = 0;
+ u32 pages_in_chunk = 0; /* umem_chunk中单个内存块的页个数 */
+ u32 npages = 0; /* 已经记录的页个数 */
+ u32 start_index = 0; /* 要写入mtt的页 */
+ struct scatterlist *sg = NULL;
+ u64 page_size = 0;
+
+ page_size = BIT((unsigned int)umem->page_shift);
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i) {
+ /* cal page num in truck */
+ pages_in_chunk = sg_dma_len(sg) >> mtt->buf_page_shift;
+ for (j = 0; j < pages_in_chunk; ++j) {
+ page_list[npages] = sg_dma_address(sg) + (page_size * j);
+ npages++;
+
+ /* one page can hold (PAGE_SIZE / sizeof(u64)) addrs */
+ if (npages == (PAGE_SIZE / sizeof(u64))) {
+ ret = hmm_rdma_write_mtt(hwdev, mtt, start_index,
+ npages, page_list, service_type);
+ start_index += npages;
+ npages = 0;
+ }
+ if ((npages == (PAGE_SIZE / sizeof(u64))) && (ret != 0)) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to write mtt, func_id(%d)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto out;
+ }
+ }
+ }
+
+ if (npages != 0) {
+ ret = hmm_rdma_write_mtt(hwdev, mtt, start_index, npages, page_list, service_type);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl, "[HMM, ERR] %s(%d): Failed to write mtt, ret(%d), start_index(%d), func_id(%d)\n",
+ __func__, __LINE__, ret, start_index, hinic3_global_func_id(hwdev));
+ goto out;
+ }
+ }
+
+out:
+ kfree(page_list);
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : hmm_umem_write_mtt
+ Description : write mtt for umem(get from memory alloced by user)
+ Input : struct hinic3_hwdev *hwdev
+ struct rdma_mtt *mtt
+ struct hmm_umem *umem
+ Output : None
+****************************************************************************
+*/
+int hmm_umem_write_mtt(struct hinic3_hwdev *hwdev, struct rdma_mtt *mtt,
+ struct hmm_umem *umem, u32 service_type)
+{
+ int ret;
+ u64 *page_list = NULL; /* 要写入mtt的page_list */
+
+ ret = hmm_umem_write_mtt_check(hwdev, mtt, umem);
+ if (ret != 0)
+ return ret;
+
+ page_list = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (page_list == NULL)
+ return -ENOMEM;
+ ret = hmm_umem_write_mtt_update(hwdev, mtt, umem, page_list, service_type);
+ return ret;
+}
+
+int hmm_reg_user_mr_update(struct hinic3_hwdev *hwdev, struct hmm_mr *mr, u32 pdn,
+ u64 length, u64 virt_addr, int access, u32 service_type, u16 channel)
+{
+ int ret = 0;
+ u32 npages = 0;
+ u32 page_shift = 0;
+
+ if (hwdev == NULL) {
+ pr_err("[HMM, ERR] %s(%d): hwdev is null\n", __func__, __LINE__);
+ return 0;
+ }
+ mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE;
+ npages = (u32)hmm_umem_page_count(mr->umem);
+ page_shift = (u32)(mr->umem->page_shift);
+ ret = hmm_alloc_tpt(hwdev, &mr->rdmamr, npages, page_shift, service_type);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to alloc mpt and mtt, func_id(%d)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto err_alloc_tpt;
+ }
+
+ hmm_set_rdma_mr(&mr->rdmamr, RDMA_USER_MR, pdn, virt_addr, length, (u32)access);
+
+ ret = hmm_umem_write_mtt(hwdev, &mr->rdmamr.mtt, mr->umem, service_type);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to write mtt, func_id(%d)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto err_write_mtt;
+ }
+
+ ret = hmm_rdma_enable_mr_mpt(hwdev, &mr->rdmamr, channel);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to enable mpt of user mr, func_id(%d)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto err_write_mtt;
+ }
+
+ return 0;
+
+err_write_mtt:
+ hmm_free_tpt(hwdev, &mr->rdmamr, service_type);
+
+err_alloc_tpt:
+ return ret;
+}
+
+int hmm_dereg_mr_update(struct hinic3_hwdev *hwdev, struct rdma_mr *mr,
+ u32 service_type, u16 channel)
+{
+ int ret = 0;
+
+ ret = hmm_rdma_disable_mr_mpt(hwdev, mr, service_type, channel);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to disable mpt of mr, ret(%d)\n",
+ __func__, __LINE__, ret);
+ return ret;
+ }
+
+ hmm_free_tpt(hwdev, mr, service_type);
+ return ret;
+}
+
+#ifndef ROCE_SERVICE
+/*
+ ****************************************************************************
+ Prototype : hmm_reg_user_mr
+ Description : register MR for user
+ Input : struct hinic3_hwdev *hwdev
+ u64 start
+ u64 length
+ u64 virt_addr
+ int hmm_access
+ Output : None
+****************************************************************************
+*/
+struct hmm_mr *hmm_reg_user_mr(struct hinic3_hwdev *hwdev, u64 start, u32 pd,
+ u64 length, u64 virt_addr, int hmm_access, u32 service_type, u16 channel)
+{
+ int ret = 0;
+ struct hmm_mr *mr = NULL;
+
+ if (hwdev == NULL) {
+ pr_err("[HMM, ERR] %s(%d): hwdev is null\n", __func__, __LINE__);
+ goto err_out;
+ }
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (mr == NULL) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ mr->hwdev = hwdev;
+ mr->rdmamr.iova = virt_addr;
+ mr->umem = hmm_umem_get(hwdev->dev_hdl, start, (size_t)length, hmm_access, 0);
+ if (IS_ERR(mr->umem)) {
+ ret = (int)PTR_ERR(mr->umem);
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to get ib umem, func_id(%d)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto err_empty;
+ }
+
+ rcu_read_lock();
+ mr->umem->context->tgid = get_task_pid(current->group_leader, PIDTYPE_PID);
+ rcu_read_unlock();
+ ret = hmm_reg_user_mr_update(hwdev, mr, pd, length, virt_addr,
+ hmm_access, service_type, channel);
+ if (ret != 0)
+ goto err_get_umem;
+
+ return mr;
+
+err_get_umem:
+ hmm_umem_release(mr->umem);
+err_empty:
+ kfree(mr);
+
+err_out:
+ return (struct hmm_mr *)ERR_PTR((long)ret);
+}
+
+/*
+ ****************************************************************************
+ Prototype : hmm_dereg_mr
+ Description : dereg DMA_MR, user_MR or FRMR
+ Input : struct hmm_mr *mr
+ Output : None
+
+****************************************************************************
+*/
+int hmm_dereg_mr(struct hmm_mr *mr, u32 service_type, u16 channel)
+{
+ int ret = 0;
+ struct hinic3_hwdev *hwdev = NULL;
+
+ if (mr == NULL) {
+ pr_err("[HMM, ERR] %s(%d): Ibmr is null\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ hwdev = (struct hinic3_hwdev *)mr->hwdev;
+ ret = hmm_dereg_mr_update(hwdev, &(mr->rdmamr), service_type, channel);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[HMM, ERR] %s(%d): Failed to de-reg mr update, ret(%d), func_id(%d)\n",
+ __func__, __LINE__, ret, hinic3_global_func_id(hwdev));
+ return ret;
+ }
+
+ if (mr->umem)
+ hmm_umem_release(mr->umem);
+
+ kfree(mr);
+ return ret;
+}
+#endif
+
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_mr.h b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_mr.h
new file mode 100644
index 0000000000000..90a2b5e955939
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_mr.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef HMM_MR_H
+#define HMM_MR_H
+
+#include "hmm_umem.h"
+#include "hmm_comp.h"
+
+
+#define ROCE_DMA_MR_SIZE (~0ULL)
+#define ROCE_FRMR_MAX_PAGES 512
+#define MR_KEY_RIGHT_SHIFT_OFS 24
+#define MR_KEY_LEFT_SHIFT_OFS 8
+
+struct hmm_mr {
+ struct hmm_umem *umem;
+ struct rdma_mr rdmamr;
+ void *hwdev;
+};
+
+int hmm_rdma_enable_mr_mpt(void *hwdev, struct rdma_mr *mr, u16 channel);
+
+int hmm_rdma_disable_mr_mpt(void *hwdev, struct rdma_mr *mr, u32 service_type, u16 channel);
+
+void hmm_rdma_mpt_free(void *hwdev, struct rdma_mpt *mpt);
+
+int hmm_init_resource(void *hwdev, u32 service_type);
+
+void hmm_cleanup_resource(void *hwdev, u32 service_type);
+
+#endif // HMM_MR_H_
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_umem.c b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_umem.c
new file mode 100644
index 0000000000000..c3a296568f9e4
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_umem.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/signal.h>
+#include <linux/sched/mm.h>
+#include <linux/sched/signal.h>
+#include <linux/hugetlb.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include "hinic3_rdma.h"
+#include "hmm_umem.h"
+
+#ifndef ROCE_SERVICE
+static void hmm_umemsg_release(struct device *device, struct hmm_umem *hmm_umem, int dirty)
+{
+ struct scatterlist *sg = NULL;
+ struct page *page = NULL;
+ int i;
+
+ if (hmm_umem->nmap > 0)
+ dma_unmap_sg(device, hmm_umem->sg_head.sgl, hmm_umem->npages, DMA_BIDIRECTIONAL);
+
+ for_each_sg(hmm_umem->sg_head.sgl, sg, hmm_umem->npages, i) {
+ page = sg_page(sg);
+ if (!PageDirty(page) && hmm_umem->writable && dirty)
+ set_page_dirty_lock(page);
+ put_page(page);
+ }
+
+ sg_free_table(&hmm_umem->sg_head);
+}
+
+/**
+ * hmm_umem_get - Pin and DMA map userspace memory.
+ *
+ * If access flags indicate ODP memory, avoid pinning. Instead, stores
+ * the mm for future page fault handling in conjunction with MMU notifiers.
+ *
+ * @context: userspace context to pin memory for
+ * @addr: userspace virtual address to start at
+ * @size: length of region to pin
+ * @access: RDMA_IB_ACCESS_xxx flags for memory being pinned
+ * @dmasync: flush in-flight DMA when the memory region is written
+ */
+struct hmm_umem *hmm_umem_get(struct device *device, unsigned long addr,
+ size_t size, int access, int dmasync)
+{
+ int ret;
+ int i;
+ struct hmm_umem *hmem = NULL;
+ struct page **page_list = NULL;
+ struct vm_area_struct **vma_list = NULL;
+ unsigned long locked_pages;
+ unsigned long lock_limit;
+ unsigned long current_base;
+ unsigned long npages;
+
+#ifdef HAVE_STRUCT_DMA_ATTRS
+ DEFINE_DMA_ATTRS(dma_attrs);
+#else
+ unsigned long dma_attrs = 0;
+#endif
+ struct scatterlist *sg = NULL, *sg_list_start = NULL;
+ int need_release = 0;
+#ifdef HAVE_GET_USER_PAGES_GUP_FLAGS
+ unsigned int gup_flags = FOLL_WRITE;
+#endif
+
+ /*
+ * If the combination of the addr and size requested for this memory
+ * region causes an integer overflow, return error.
+ */
+ if (((addr + size) < addr) || PAGE_ALIGN(addr + size) < (addr + size))
+ return ERR_PTR(-EINVAL);
+
+ if (can_do_mlock() == 0)
+ return ERR_PTR(-EPERM);
+
+ hmem = kzalloc(sizeof(*hmem), GFP_KERNEL);
+ if (hmem == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ hmem->context = kzalloc(sizeof(*(hmem->context)), GFP_KERNEL);
+ if ((hmem->context) == NULL) {
+ kfree(hmem);
+ return ERR_PTR(-ENOMEM);
+ }
+ hmem->context->device = device;
+ hmem->length = size;
+ hmem->address = addr;
+ hmem->page_shift = PAGE_SHIFT;
+ /*
+ * We ask for writable memory if any of the following
+ * access flags are set. "Local write" and "remote write"
+ * obviously require write access. "Remote atomic" can do
+ * things like fetch and add, which will modify memory, and
+ * "MW bind" can change permissions by binding a window.
+ */
+ hmem->writable = !!(access & (RDMA_IB_ACCESS_LOCAL_WRITE | RDMA_IB_ACCESS_REMOTE_WRITE |
+ RDMA_IB_ACCESS_REMOTE_ATOMIC | RDMA_IB_ACCESS_MW_BIND));
+
+ if ((access & RDMA_IB_ACCESS_ON_DEMAND) != 0) {
+ kfree(hmem->context);
+ kfree(hmem);
+ dev_err(device, "[HMM, ERR] %s(%d): don't support odp\n", __func__, __LINE__);
+ return ERR_PTR(-ENOMEM);
+ }
+ hmem->odp_data = NULL;
+
+ /* We assume the memory is from hugetlb until proved otherwise */
+ hmem->hugetlb = 1;
+ page_list = (struct page **)__get_free_page(GFP_KERNEL);
+ if (page_list == NULL) {
+ kfree(hmem->context);
+ kfree(hmem);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /*
+ * if we can't alloc the vma_list, it's not so bad;
+ * just assume the memory is not hugetlb memory
+ */
+ vma_list = (struct vm_area_struct **)__get_free_page(GFP_KERNEL);
+ if (vma_list == NULL)
+ hmem->hugetlb = 0;
+
+ npages = hmm_umem_num_pages(hmem);
+ mmap_write_lock(current->mm);
+ locked_pages = npages + atomic64_read(&current->mm->pinned_vm);
+ lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+ if ((locked_pages > lock_limit) && !capable(CAP_IPC_LOCK)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ current_base = addr & PAGE_MASK;
+ if (npages == 0 || npages > UINT_MAX) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = sg_alloc_table(&hmem->sg_head, (unsigned int)npages, GFP_KERNEL);
+ if (ret != 0)
+ goto out;
+
+#ifdef HAVE_GET_USER_PAGES_GUP_FLAGS
+ if (hmem->writable == 0)
+ gup_flags |= FOLL_FORCE;
+#endif
+
+ need_release = 1;
+ sg_list_start = hmem->sg_head.sgl;
+
+ while (npages != 0) {
+#ifdef HAVE_GET_USER_PAGES_8_PARAMS
+ ret = get_user_pages(current, current->mm, current_base,
+ min_t(unsigned long, npages, PAGE_SIZE / sizeof(struct page *)),
+ 1, !hmem->writable, page_list, vma_list);
+#else
+#ifdef HAVE_GET_USER_PAGES_LONGTERM
+ ret = get_user_pages(current_base,
+#else
+ ret = get_user_pages(current_base,
+#endif
+ min_t(unsigned long, npages, PAGE_SIZE / sizeof(struct page *)),
+#ifdef HAVE_GET_USER_PAGES_GUP_FLAGS
+ gup_flags, page_list, vma_list);
+#else
+ 1, !hmem->writable, page_list, vma_list);
+#endif
+#endif
+
+ if (ret < 0)
+ goto out;
+
+ hmem->npages += ret;
+ current_base += ret * PAGE_SIZE;
+ npages = (unsigned long)(npages - ret);
+
+ for_each_sg(sg_list_start, sg, ret, i) {
+ if (vma_list != NULL && !is_vm_hugetlb_page(vma_list[i]))
+ hmem->hugetlb = 0;
+
+ sg_set_page(sg, page_list[i], PAGE_SIZE, 0);
+ }
+
+ /* preparing for next loop */
+ sg_list_start = sg;
+ }
+
+ hmem->nmap = dma_map_sg_attrs(device, hmem->sg_head.sgl, hmem->npages, DMA_BIDIRECTIONAL,
+#ifdef HAVE_STRUCT_DMA_ATTRS
+ &dma_attrs);
+#else
+ dma_attrs);
+#endif
+ if (hmem->nmap <= 0) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = 0;
+
+out:
+ if (ret < 0) {
+ if (need_release != 0)
+ hmm_umemsg_release(device, hmem, 0);
+
+ kfree(hmem->context);
+ kfree(hmem);
+ } else {
+ atomic64_set(&current->mm->pinned_vm, locked_pages);
+ }
+
+ mmap_write_unlock(current->mm);
+ if (vma_list != NULL)
+ free_page((unsigned long)(uintptr_t)vma_list);
+
+ free_page((unsigned long)(uintptr_t)page_list);
+ return (ret < 0) ? ERR_PTR(ret) : hmem;
+}
+
+/**
+ * hmm_umem_release - release memory pinned with ib_umem_get
+ * @hmem: umem struct to release
+ */
+void hmm_umem_release(struct hmm_umem *hmem)
+{
+ struct ib_ucontext *context = hmem->context;
+ struct mm_struct *mm = NULL;
+ struct task_struct *task = NULL;
+ unsigned long diff;
+
+ if (hmem->odp_data) {
+ pr_err("[HMM, ERR] %s(%d): Don't support odp\n", __func__, __LINE__);
+ return;
+ }
+
+ hmm_umemsg_release(context->device, hmem, 1);
+ task = get_pid_task(context->tgid, PIDTYPE_PID);
+ if (task == NULL)
+ goto out;
+
+ mm = get_task_mm(task);
+ put_task_struct(task);
+ if (mm == NULL)
+ goto out;
+
+ diff = hmm_umem_num_pages(hmem);
+ mmap_write_lock(mm);
+ atomic64_sub(diff, &mm->pinned_vm);
+ mmap_write_unlock(mm);
+ mmput(mm);
+out:
+ kfree(context);
+ kfree(hmem);
+}
+#endif
+
+u32 hmm_umem_page_count(struct hmm_umem *hmem)
+{
+ u32 i;
+ u32 n;
+ struct scatterlist *sg = NULL;
+
+ if (hmem->odp_data)
+ return (u32)(hmm_umem_num_pages(hmem));
+
+ n = 0;
+ for_each_sg(hmem->sg_head.sgl, sg, hmem->nmap, i) n += sg_dma_len(sg) >>
+ ((u32)hmem->page_shift);
+
+ return n;
+}
diff --git a/drivers/infiniband/hw/hiroce3/host/hmm/hmm_umem.h b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_umem.h
new file mode 100644
index 0000000000000..61cc59f6e9c90
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/host/hmm/hmm_umem.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef HMM_UMEM_H
+#define HMM_UMEM_H
+
+#include <linux/list.h>
+#include <linux/scatterlist.h>
+#include <linux/workqueue.h>
+#include <linux/uaccess.h>
+#include <linux/types.h>
+#include <linux/mmu_notifier.h>
+#include <linux/kernel.h>
+
+#ifdef ROCE_SERVICE
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_umem.h>
+#endif
+
+
+#ifndef ROCE_SERVICE
+
+enum rdma_remove_reason {
+ /* Userspace requested uobject deletion. Call could fail */
+ RDMA_REMOVE_DESTROY,
+ /* Context deletion. This call should delete the actual object itself */
+ RDMA_REMOVE_CLOSE,
+ /* Driver is being hot-unplugged. This call should delete the actual object itself */
+ RDMA_REMOVE_DRIVER_REMOVE,
+ /* Context is being cleaned-up, but commit was just completed */
+ RDMA_REMOVE_DURING_CLEANUP,
+};
+
+struct ib_uverbs_file;
+struct ib_rdmacg_object {};
+struct rb_root_cached_struct {
+ struct rb_node *rb_root;
+ struct rb_node *rb_leftmost;
+};
+
+struct ib_ucontext {
+ struct device *device;
+ struct ib_uverbs_file *ufile;
+ int closing;
+
+ /* locking the uobjects_list */
+ struct mutex uobjects_lock;
+ struct list_head uobjects;
+ /* protects cleanup process from other actions */
+ struct rw_semaphore cleanup_rwsem;
+ enum rdma_remove_reason cleanup_reason;
+
+ struct pid *tgid;
+ struct rb_root_cached_struct umem_tree;
+ /*
+ * Protects .umem_rbroot and tree, as well as odp_mrs_count and
+ * mmu notifiers registration.
+ */
+ struct rw_semaphore umem_rwsem;
+ void (*invalidate_range)(void *umem, unsigned long start, unsigned long end);
+
+ struct mmu_notifier mn;
+ atomic_t notifier_count;
+ /* A list of umems that don't have private mmu notifier counters yet. */
+ struct list_head no_private_counters;
+ int odp_mrs_count;
+
+ struct ib_rdmacg_object cg_obj;
+};
+
+struct ib_umem_odp;
+
+struct hmm_umem *hmm_umem_get(struct device *device, unsigned long addr,
+ size_t size, int access, int dmasync);
+
+void hmm_umem_release(struct hmm_umem *hmem);
+
+#endif
+
+struct hmm_umem {
+ struct ib_ucontext *context;
+ size_t length;
+ unsigned long address;
+ int page_shift;
+ int writable;
+ int hugetlb;
+ struct work_struct work;
+ struct mm_struct *mm;
+ unsigned long diff;
+ struct ib_umem_odp *odp_data;
+ struct sg_table sg_head;
+ int nmap;
+ int npages;
+};
+
+
+/* Returns the offset of the umem start relative to the first page. */
+static inline int hmm_umem_offset(const struct hmm_umem *umem)
+{
+ return umem->address & ~PAGE_MASK;
+}
+
+/* Returns the first page of an ODP umem. */
+static inline unsigned long hmm_umem_start(struct hmm_umem *umem)
+{
+ return umem->address - hmm_umem_offset(umem);
+}
+
+/* Returns the address of the page after the last one of an ODP umem. */
+static inline unsigned long hmm_umem_end(const struct hmm_umem *umem)
+{
+ return ALIGN(umem->address + umem->length, BIT((unsigned int)umem->page_shift));
+}
+
+static inline size_t hmm_umem_num_pages(struct hmm_umem *umem)
+{
+ return (size_t)(((unsigned long)(hmm_umem_end(umem) -
+ hmm_umem_start(umem))) >> (unsigned long)umem->page_shift);
+}
+
+u32 hmm_umem_page_count(struct hmm_umem *hmem);
+
+
+#endif /* HMM_UMEM_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/hinic3_hmm.h b/drivers/infiniband/hw/hiroce3/include/hinic3_hmm.h
new file mode 100644
index 0000000000000..986b0b6fd4b12
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/hinic3_hmm.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC_HMM_H__
+#define HINIC_HMM_H__
+
+/* has no mpt entry */
+#define HMM_MPT_EN_SW 1 /* has mpt, state INVALID */
+#define HMM_MPT_EN_HW 2 /* has mpt, state FREE or VALID */
+#define HMM_MPT_DISABLED 0 /* has no mpt entry */
+#define HMM_MPT_FIX_BUG_LKEY 0
+
+#include "hinic3_cqm.h"
+#include "hinic3_hwdev.h"
+#include "hmm_comp.h"
+#include "hmm_mr.h"
+
+/*
+ ****************************************************************************
+ Prototype : hmm_reg_user_mr_update
+ Description : MR注册生成和更新MPT和MTT表
+ Input : struct hinic3_hwdev *hwdev
+ hmm_mr *mr MR结构,包含已
+ 经完成用户态内存的物理地址获取umem
+ u32 pdn PD号,如果不支持的pd的特性直接填0.
+ u64 length 需要注册的用户态地址长度
+ u64 virt_addr 需要注册的IOV虚拟地址首地址
+ int hmm_access填入enum rdma_ib_access的值
+ u32 service_type enum hinic3_service_type的值
+ Output : None
+****************************************************************************
+*/
+int hmm_reg_user_mr_update(struct hinic3_hwdev *hwdev, struct hmm_mr *mr, u32 pdn, u64 length,
+ u64 virt_addr, int access, u32 service_type, u16 channel);
+
+
+/*
+ ****************************************************************************
+ Prototype : hmm_reg_user_mr_update
+ Description : MR去注册删除MPT和MTT表
+ Input : struct hinic3_hwdev *hwdev
+ rdma_mr *mr MR结构
+ u32 service_type enum hinic3_service_type的值
+ Output : None
+****************************************************************************
+*/
+int hmm_dereg_mr_update(struct hinic3_hwdev *hwdev, struct rdma_mr *mr,
+ u32 service_type, u16 channel);
+
+#ifndef ROCE_SERVICE
+/*
+ ****************************************************************************
+ Prototype : hmm_reg_user_mr
+ Description : register MR for user
+ Input : struct hinic3_hwdev *hwdev
+ u32 pdn PD��
+ u64 start ע��memory����ʼ��ַ
+ u64 length ע���ڴ�ij���
+ u64 virt_addr io�������ַ
+ int hmm_access ����enum rdma_ib_access��ֵ
+ u32 service_type enum hinic3_service_type��ֵ
+ Output : None
+****************************************************************************
+*/
+struct hmm_mr *hmm_reg_user_mr(struct hinic3_hwdev *hwdev, u64 start, u32 pdn, u64 length,
+ u64 virt_addr, int hmm_access, u32 service_type, u16 channel);
+
+/*
+ ****************************************************************************
+ Prototype : hmm_dereg_mr
+ Description : dereg DMA_MR, user_MR or FRMR
+ Input : struct hmm_mr *mr
+ : u32 service_type enum hinic3_service_type的值
+ Output : None
+
+****************************************************************************
+*/
+int hmm_dereg_mr(struct hmm_mr *mr, u32 service_type, u16 channel);
+#endif
+
+int hmm_rdma_write_mtt(void *hwdev, struct rdma_mtt *mtt, u32 start_index, u32 npages,
+ u64 *page_list, u32 service_type);
+
+int hmm_rdma_mtt_alloc(void *hwdev, u32 npages, u32 page_shift,
+ struct rdma_mtt *mtt, u32 service_type);
+
+void hmm_rdma_mtt_free(void *hwdev, struct rdma_mtt *mtt, u32 service_type);
+
+int hmm_init_mtt_table(struct hmm_comp_priv *comp_priv);
+
+void hmm_cleanup_mtt_table(struct hmm_comp_priv *comp_priv);
+
+#endif /* HINIC_RDMA_H__ */
diff --git a/drivers/infiniband/hw/hiroce3/include/hinic3_rdma.h b/drivers/infiniband/hw/hiroce3/include/hinic3_rdma.h
new file mode 100644
index 0000000000000..1de8ba98f8589
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/hinic3_rdma.h
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC_RDMA_H__
+#define HINIC_RDMA_H__
+
+#define RDMA_ROCE_ENABLE 1
+#define RDMA_IWARP_ENABLE 1
+#define RDMA_ROCE_DISABLE 0
+#define RDMA_IWARP_DISABLE 0
+
+#define RDMA_MPT_DISABLED 0 /* has no mpt entry */
+#define RDMA_MPT_EN_SW 1 /* has mpt, state INVALID */
+#define RDMA_MPT_EN_HW 2 /* has mpt, state FREE or VALID */
+
+#define RDMA_MPT_FIX_BUG_LKEY 0
+
+struct mutex;
+struct tag_cqm_qpc_mpt;
+struct tag_cqm_object;
+struct net_device;
+struct rdma_gid_entry;
+
+#include "hinic3_cqm.h"
+
+enum mtt_check_type_e {
+ MTT_CHECK_TYPE_0 = 0,
+ MTT_CHECK_TYPE_1
+};
+
+enum mtt_data_type_e {
+ MTT_DMTT_TYPE = 0,
+ MTT_CMTT_TYPE
+};
+
+enum rdma_ib_access {
+ RDMA_IB_ACCESS_LOCAL_WRITE = 1,
+ RDMA_IB_ACCESS_REMOTE_WRITE = (1 << 1),
+ RDMA_IB_ACCESS_REMOTE_READ = (1 << 2),
+ RDMA_IB_ACCESS_REMOTE_ATOMIC = (1 << 3),
+ RDMA_IB_ACCESS_MW_BIND = (1 << 4),
+ RDMA_IB_ACCESS_ZERO_BASED = (1 << 5),
+ RDMA_IB_ACCESS_ON_DEMAND = (1 << 6),
+};
+
+struct rdma_gid_entry {
+ union {
+ u8 raw[16];
+ struct {
+ __be64 subnet_prefix;
+ __be64 interface_id;
+ } global;
+ };
+ union {
+ struct {
+ u32 rsvd : 7;
+ u32 is_vroce : 1;
+ u32 cvlan : 12; /* 内层vlan customer vlan */
+ u32 svlan : 12; /* 外层vlan */
+ } bs;
+ u32 value;
+ } dw4;
+
+ union {
+ u32 hdr_len_value;
+ };
+
+ union {
+ struct {
+ /* 0:没有vlan; 1:一层vlan; 2: 2层vlan; 3:stag */
+ u16 tag : 2;
+ 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];
+};
+
+struct rdma_comp_resource {
+ struct mutex mutex; /* gid_entry使用的互斥量 */
+ __be64 node_guid; /* 与ibdev中的node_guid一致 */
+ struct rdma_gid_entry **gid_table; /* gid_entry在rdma组件初始化时分配内存 */
+};
+
+struct rdma_mpt {
+ u32 mpt_index; /* 封装cqm提供的mpt_index */
+ void *vaddr; /* 封装cqm提供的mpt_entry的虚拟地址 */
+ void *mpt_object; /* 封装的cqm提供的指针 */
+};
+
+
+struct rdma_mtt_seg {
+ u32 offset; /* 分配连续索引的首个索引 */
+ u32 order; /* mtt索引个数为1<<order,每个索引对应一个mtt entry */
+ void *vaddr; /* mtt_seg第一个MTT的起始虚拟地址 */
+ dma_addr_t paddr; /* mtt_seg第一个MTT的起始物理地址 */
+};
+
+struct rdma_mtt {
+ /* mtt的级数,该值为0时表示不使用mtt做地址转换 */
+ u32 mtt_layers;
+ u32 mtt_page_shift; /* MTT的页大小 */
+ u32 buf_page_shift; /* buffer页大小 */
+ dma_addr_t mtt_paddr; /* 写入context中的物理地址 */
+ __be64 *mtt_vaddr; /* 写入context中的虚拟地址 */
+ struct rdma_mtt_seg **mtt_seg; /* 指向多级mtt */
+ enum mtt_data_type_e mtt_type;
+};
+
+enum rdma_mr_type {
+ RDMA_DMA_MR = 0,
+ RDMA_USER_MR = 1,
+ RDMA_FRMR = 2,
+ RDMA_FMR = 3,
+ RDMA_PHYS_MR = 4,
+ RDMA_RSVD_LKEY = 5,
+ RDMA_SIG_MR = 6,
+ RDMA_INDIRECT_MR = 8,
+ RDMA_ODP_IMPLICIT_MR = 9,
+ RDMA_ODP_EXPLICIT_MR = 10,
+};
+
+struct rdma_mr {
+ struct rdma_mpt mpt;
+ struct rdma_mtt mtt;
+ u64 iova; /* mr指向内存的起始地址(虚拟地址,ZBVA时为0) */
+ u64 size; /* mr指向内存的大小 */
+ u32 key; /* mr对应的key */
+ u32 pdn; /* mr绑定的pdn */
+ u32 access; /* mr的访问权限 */
+ int enabled; /* mr的状态,DISABLE、EN_SW、EN_HW */
+ int mr_type; /* mr类型 */
+ u32 block_size;
+};
+
+enum rdma_mw_type {
+ RDMA_MW_TYPE_1 = 1,
+ RDMA_MW_TYPE_2 = 2
+};
+
+struct rdma_mw {
+ struct rdma_mpt mpt;
+ u32 key; /* mw对应的key */
+ u32 pdn; /* mw绑定的pdn */
+ enum rdma_mw_type type; /* mw的类型,type1,type2 */
+ int enabled; /* mw的状态 */
+};
+
+struct rdma_fmr {
+ struct rdma_mr mr;
+ u32 max_pages; /* fmr的最大映射页个数 */
+ u32 max_maps; /* fmr的最大映射次数 */
+ u32 maps; /* fmr的当前映射次数 */
+ u32 page_shift; /* fmr指定的页偏移 */
+};
+
+struct rdma_rdmarc {
+ u32 offset; /* 分配连续索引的首个索引 */
+ u32 order; /* 分配的rdmarc的order,代表了个数 */
+ u32 ext_order; /* 包含rc表和扩展表的个数 */
+ dma_addr_t dma_addr;
+ void *vaddr;
+};
+
+int roce3_rdma_pd_alloc(void *hwdev, u32 *pdn);
+
+void roce3_rdma_pd_free(void *hwdev, u32 pdn);
+
+int roce3_rdma_enable_mw_mpt(void *hwdev, struct rdma_mw *mw, u32 service_type);
+
+int roce3_rdma_disable_mw_mpt(void *hwdev, struct rdma_mw *mw, u32 service_type);
+
+int roce3_rdma_map_phys_fmr(void *hwdev, struct rdma_fmr *fmr, u64 *page_list,
+ int npages, u64 iova, u32 service_type);
+
+int roce3_rdma_unmap_fmr(void *hwdev, struct rdma_fmr *fmr, u32 service_type);
+
+int roce3_rdma_rdmarc_alloc(void *hwdev, u32 num, struct rdma_rdmarc *rdmarc);
+
+void roce3_rdma_rdmarc_free(void *hwdev, struct rdma_rdmarc *rdmarc);
+
+int roce3_rdma_update_gid_mac(void *hwdev, u32 port, struct rdma_gid_entry *gid_entry);
+int roce3_rdma_update_gid(void *hwdev, u32 port, u32 update_index,
+ struct rdma_gid_entry *gid_entry);
+int roce3_rdma_reset_gid_table(void *hwdev, u32 port);
+
+int roce3_rdma_get_gid(void *hwdev, u32 port, u32 gid_index, struct rdma_gid_entry *gid);
+
+/* 该接口在pf初始化时调用 */
+int roce3_rdma_init_resource(void *hwdev);
+
+/* 该接口在pf卸载时调用 */
+void roce3_rdma_cleanup_resource(void *hwdev);
+
+#endif /* HINIC_RDMA_H__ */
diff --git a/drivers/infiniband/hw/hiroce3/include/nic/nic_mpu_cmd.h b/drivers/infiniband/hw/hiroce3/include/nic/nic_mpu_cmd.h
new file mode 100644
index 0000000000000..dbee090f382d1
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/nic/nic_mpu_cmd.h
@@ -0,0 +1,181 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef NIC_MPU_CMD_H
+#define NIC_MPU_CMD_H
+
+/** Commands between NIC to MPU
+ */
+enum hinic3_nic_cmd {
+ HINIC3_NIC_CMD_VF_REGISTER = 0, /**< Only for PFD and VFD @see > hinic3_cmd_register_vf */
+
+ /** FUNC CFG */
+ HINIC3_NIC_CMD_SET_FUNC_TBL = 5, /**< Set function table @see > hinic3_cmd_set_func_tbl */
+ HINIC3_NIC_CMD_SET_VPORT_ENABLE, /**< Enable a vport @see > hinic3_vport_state */
+ HINIC3_NIC_CMD_SET_RX_MODE, /**< Set nic rx mode. @see > hinic3_rx_mode_config */
+ HINIC3_NIC_CMD_SQ_CI_ATTR_SET, /**< Set SQ CI attr @see > hinic3_cmd_cons_idx_attr */
+ /**< Get vport stat @see > hinic3_port_stats_info, < hinic3_cmd_vport_stats */
+ HINIC3_NIC_CMD_GET_VPORT_STAT,
+ /**< Clean vport stat @see > hinic3_cmd_clear_vport_stats */
+ HINIC3_NIC_CMD_CLEAN_VPORT_STAT,
+ /**< Clean queue pair resource @see > hinic3_cmd_clear_qp_resource */
+ HINIC3_NIC_CMD_CLEAR_QP_RESOURCE,
+ HINIC3_NIC_CMD_CFG_FLEX_QUEUE, /**< Set flex queue @see > hinic3_cmd_cfg_qps */
+ /** LRO CFG */
+ HINIC3_NIC_CMD_CFG_RX_LRO, /**< Set rx LRO @see > hinic3_cmd_lro_config */
+ HINIC3_NIC_CMD_CFG_LRO_TIMER, /**< Set LRO timer @see > hinic3_cmd_lro_timer */
+ /**< negotiate features @see > hinic3_cmd_feature_nego */
+ HINIC3_NIC_CMD_FEATURE_NEGO,
+ /**< Configure local LRO state @see > hinic3_cmd_local_lro_state */
+ HINIC3_NIC_CMD_CFG_LOCAL_LRO_STATE,
+
+ /**< Cache out queue pair resource @see > hinic3_cmd_cache_out_qp_resource */
+ HINIC3_NIC_CMD_CACHE_OUT_QP_RES,
+
+ /** MAC & VLAN CFG */
+ HINIC3_NIC_CMD_GET_MAC = 20, /**< Get mac address @see > hinic3_port_mac_set */
+ HINIC3_NIC_CMD_SET_MAC, /**< Set mac address @see > hinic3_port_mac_set */
+ HINIC3_NIC_CMD_DEL_MAC, /**< Delete mac address @see > hinic3_port_mac_set */
+ /**< Update mac address @see > hinic3_port_mac_update */
+ HINIC3_NIC_CMD_UPDATE_MAC,
+ /**< Get all default mac address @see > cmd_mac_info_get_s */
+ HINIC3_NIC_CMD_GET_ALL_DEFAULT_MAC,
+
+ /**< Configure function vlan @see > hinic3_cmd_vlan_config */
+ HINIC3_NIC_CMD_CFG_FUNC_VLAN,
+ /**< Enable vlan filter @see > hinic3_cmd_set_vlan_filter */
+ HINIC3_NIC_CMD_SET_VLAN_FILTER_EN,
+ /**< Set rx vlan offload @see > hinic3_cmd_vlan_offload */
+ HINIC3_NIC_CMD_SET_RX_VLAN_OFFLOAD,
+ HINIC3_NIC_CMD_SMAC_CHECK_STATE,
+
+ /** SR-IOV */
+ /**< Configure vf vlan @see > hinic3_cmd_vf_vlan_config */
+ HINIC3_NIC_CMD_CFG_VF_VLAN = 40,
+ /**< Set snoopchk state @see > hinic3_cmd_spoofchk_set */
+ HINIC3_NIC_CMD_SET_SPOOPCHK_STATE,
+ /* RATE LIMIT */
+ /**< Set rate limit @see > HINIC3_NIC_CMD_SET_MAX_MIN_RATE */
+ HINIC3_NIC_CMD_SET_MAX_MIN_RATE,
+
+ /** RSS CFG */
+ HINIC3_NIC_CMD_RSS_CFG = 60, /**< Set rss config @see > hinic3_cmd_rss_config */
+ HINIC3_NIC_CMD_RSS_TEMP_MGR, /**< TODO: delete after implement nego cmd */
+ HINIC3_NIC_CMD_GET_RSS_CTX_TBL, /**< TODO: delete: move to ucode cmd */
+ /**< Set rss hash key @see > hinic3_cmd_rss_hash_key */
+ HINIC3_NIC_CMD_CFG_RSS_HASH_KEY,
+ /**< Set rss hash engine type @see > hinic3_cmd_rss_engine_type */
+ HINIC3_NIC_CMD_CFG_RSS_HASH_ENGINE,
+ /**< Set rss context table info @see > hinic3_rss_context_table */
+ HINIC3_NIC_CMD_SET_RSS_CTX_TBL_INTO_FUNC,
+ /** IP checksum error packets, enable rss quadruple hash */
+ /**< Set rss config @see > hinic3_ipcs_err_rss_enable_operation_s */
+ HINIC3_NIC_CMD_IPCS_ERR_RSS_ENABLE_OP = 66,
+
+ /** PPA/FDIR */
+ HINIC3_NIC_CMD_ADD_TC_FLOW = 80, /**< Add tc flow @see > nic_cmd_fdir_add_rule */
+ HINIC3_NIC_CMD_DEL_TC_FLOW, /**< Delete tc flow @see > nic_cmd_fdir_del_rules */
+ HINIC3_NIC_CMD_GET_TC_FLOW, /**< Get tc flow @see > nic_cmd_fdir_get_rule */
+ HINIC3_NIC_CMD_FLUSH_TCAM, /**< Flush TCAM @see > nic_cmd_flush_tcam_rules */
+ /**< Configure TCAM block @see > nic_cmd_ctrl_tcam_block_out */
+ HINIC3_NIC_CMD_CFG_TCAM_BLOCK,
+ /**< Enable TCAM @see > nic_cmd_set_tcam_enable */
+ HINIC3_NIC_CMD_ENABLE_TCAM,
+ /**< Get TCAM block @see > nic_cmd_dfx_fdir_tcam_block_table */
+ HINIC3_NIC_CMD_GET_TCAM_BLOCK,
+ /**< Configure PPA table id @see > hinic3_ppa_cfg_table_id_cmd */
+ HINIC3_NIC_CMD_CFG_PPA_TABLE_ID,
+ /**< Set PPA enable @see > hinic3_ppa_cfg_ppa_en_cmd */
+ HINIC3_NIC_CMD_SET_PPA_EN = 88,
+ /**< Configure PPA mode @see > hinic3_ppa_cfg_mode_cmd */
+ HINIC3_NIC_CMD_CFG_PPA_MODE,
+ /**< Configure PPA flush @see > hinic3_ppa_cfg_flush_cmd */
+ HINIC3_NIC_CMD_CFG_PPA_FLUSH,
+ /**< Set FDIR status @see > hinic3_set_fdir_ethertype_rule */
+ HINIC3_NIC_CMD_SET_FDIR_STATUS,
+ /**< Get PPA counter @see > hinic3_ppa_fdir_query_cmd */
+ HINIC3_NIC_CMD_GET_PPA_COUNTER,
+ /**< Set flow bifur status @see > cmd_flow_bifur_func_handle */
+ HINIC3_NIC_CMD_SET_FUNC_FLOW_BIFUR_ENABLE,
+ /**< Set flow bifur bond @see > cmd_flow_bifur_bond_handle */
+ HINIC3_NIC_CMD_SET_BOND_MASK,
+ /**< Get func tcam table @see > get_fdir_func_tcam_table */
+ HINIC3_NIC_CMD_GET_BLOCK_TC_FLOWS,
+ /**< Get flow bifur bond @see > cmd_flow_bifur_bond_handle */
+ HINIC3_NIC_CMD_GET_BOND_MASK,
+
+ /** PORT CFG */
+ HINIC3_NIC_CMD_SET_PORT_ENABLE = 100, /**< set port enable @see > hinic3_port_state */
+ HINIC3_NIC_CMD_CFG_PAUSE_INFO, /**< Configure pause info @see > hinic3_cmd_pause_config */
+
+ HINIC3_NIC_CMD_SET_PORT_CAR, /**< Set port Car @see > hinic3_cmd_set_port_car */
+ HINIC3_NIC_CMD_SET_ER_DROP_PKT, /**< Unused */
+
+ HINIC3_NIC_CMD_VF_COS, /**< Get vf CoS @see > hinic3_cmd_vf_dcb_state */
+ HINIC3_NIC_CMD_SETUP_COS_MAPPING, /**< Unused */
+ HINIC3_NIC_CMD_SET_ETS, /**< Unused */
+ HINIC3_NIC_CMD_SET_PFC, /**< Unused */
+ HINIC3_NIC_CMD_QOS_ETS, /**< Set QoS ETS @see > hinic3_cmd_ets_cfg */
+ HINIC3_NIC_CMD_QOS_PFC, /**< Set QoS PFC @see > hinic3_cmd_set_pfc */
+ HINIC3_NIC_CMD_QOS_DCB_STATE, /**< Get QoS DCB state @see > hinic3_cmd_set_dcb_state */
+ HINIC3_NIC_CMD_QOS_PORT_CFG, /**< Get QoS port cfg @see > hinic3_cmd_qos_port_cfg */
+ HINIC3_NIC_CMD_QOS_MAP_CFG, /**< Get QoS map cfg @see > hinic3_cmd_qos_map_cfg */
+ HINIC3_NIC_CMD_FORCE_PKT_DROP, /**< Force pkt drop @see > hinic3_force_pkt_drop */
+ /**< Configure nic tx promisc skip @see > hinic3_tx_promisc_cfg */
+ HINIC3_NIC_CMD_CFG_TX_PROMISC_SKIP = 114,
+ /**< Set flow bifur port switch @see > cmd_flow_bifur_port_handle */
+ HINIC3_NIC_CMD_SET_PORT_FLOW_BIFUR_ENABLE = 117,
+ /**< Set tx pause exc notice @see > nic_cmd_tx_pause_notice */
+ HINIC3_NIC_CMD_TX_PAUSE_EXCP_NOTICE = 118,
+ /**< Inquirt pause cfg @see > nic_cmd_pause_inquiry_cfg_s */
+ HINIC3_NIC_CMD_INQUIRT_PAUSE_CFG = 119,
+
+ /** MISC */
+ HINIC3_NIC_CMD_BIOS_CFG = 120, /**< Set QoS ETS @see > nic_cmd_bios_cfg */
+ HINIC3_NIC_CMD_SET_FIRMWARE_CUSTOM_PACKETS_MSG, /**< Set QoS ETS @see > fault_msg_st */
+
+ /** BOND */
+ /**< Create bond device @see > hinic3_cmd_create_bond */
+ HINIC3_NIC_CMD_BOND_DEV_CREATE = 134,
+ HINIC3_NIC_CMD_BOND_DEV_DELETE, /**< Delete bond device @see > hinic3_cmd_delete_bond */
+ /**<Open/close bond dev @see > hinic3_cmd_open_close_bond */
+ HINIC3_NIC_CMD_BOND_DEV_OPEN_CLOSE,
+ HINIC3_NIC_CMD_BOND_INFO_GET, /**< Set QoS ETS @see > hinic3_bond_status_info */
+ /**< Get bond active info @see > hinic3_bond_active_report_info */
+ HINIC3_NIC_CMD_BOND_ACTIVE_INFO_GET,
+ /**< Bond active notice report @see > nic_cmd_bond_active_report_info */
+ HINIC3_NIC_CMD_BOND_ACTIVE_NOTICE,
+
+ /** DFX */
+ HINIC3_NIC_CMD_GET_SM_TABLE = 140, /**< Get sm table @see > nic_cmd_dfx_sm_table */
+ /**< Set RD line table @see > nic_mpu_lt_opera, < nic_mpu_lt_opera */
+ HINIC3_NIC_CMD_RD_LINE_TBL,
+
+ HINIC3_NIC_CMD_SET_UCAPTURE_OPT = 160, /**< TODO: move to roce */
+ HINIC3_NIC_CMD_SET_VHD_CFG, /**< Set VHD configuration @see > hinic3_set_vhd_mode */
+
+ /** TODO: move to HILINK */
+ /**< Get port stat @see > hinic3_port_stats_info, < hinic3_port_stats */
+ HINIC3_NIC_CMD_GET_PORT_STAT = 200,
+ HINIC3_NIC_CMD_CLEAN_PORT_STAT, /**< Unused */
+ HINIC3_NIC_CMD_CFG_LOOPBACK_MODE, /**< Unused */
+ HINIC3_NIC_CMD_GET_SFP_QSFP_INFO, /**< Unused */
+ HINIC3_NIC_CMD_SET_SFP_STATUS, /**< Unused */
+ HINIC3_NIC_CMD_GET_LIGHT_MODULE_ABS, /**< Unused */
+ HINIC3_NIC_CMD_GET_LINK_INFO, /**< Unused */
+ HINIC3_NIC_CMD_CFG_AN_TYPE, /**< Unused */
+ HINIC3_NIC_CMD_GET_PORT_INFO, /**< Get port info @see > hinic3_cmd_port_info */
+ HINIC3_NIC_CMD_SET_LINK_SETTINGS, /**< Unused */
+ HINIC3_NIC_CMD_ACTIVATE_BIOS_LINK_CFG, /**< Unused */
+ HINIC3_NIC_CMD_RESTORE_LINK_CFG, /**< Unused */
+ HINIC3_NIC_CMD_SET_LINK_FOLLOW, /**< Unused */
+ HINIC3_NIC_CMD_GET_LINK_STATE, /**< Unused */
+ HINIC3_NIC_CMD_LINK_STATUS_REPORT, /**< Unused */
+ HINIC3_NIC_CMD_CABLE_PLUG_EVENT, /**< Unused */
+ HINIC3_NIC_CMD_LINK_ERR_EVENT, /**< Unused */
+ HINIC3_NIC_CMD_SET_LED_STATUS, /**< Unused */
+
+ HINIC3_NIC_CMD_MAX = 256,
+};
+
+#endif /* NIC_MPU_CMD_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/nic/nic_npu_cmd.h b/drivers/infiniband/hw/hiroce3/include/nic/nic_npu_cmd.h
new file mode 100644
index 0000000000000..65b243a0e13c6
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/nic/nic_npu_cmd.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef NIC_NPU_CMD_H
+#define NIC_NPU_CMD_H
+
+/* NIC CMDQ MODE */
+enum hinic3_ucode_cmd {
+ /**< Modify queue context. @see > hinic3_sq_ctxt_block */
+ HINIC3_UCODE_CMD_MODIFY_QUEUE_CTX = 0,
+ /**< Clean queue context. @see > hinic3_clean_queue_ctxt */
+ HINIC3_UCODE_CMD_CLEAN_QUEUE_CONTEXT,
+ HINIC3_UCODE_CMD_ARM_SQ, /**< Unused */
+ HINIC3_UCODE_CMD_ARM_RQ, /**< Unused */
+ /**< Set RSS indir table. @see > nic_rss_indirect_tbl */
+ HINIC3_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ /**< Set RSS indir table. @see > nic_rss_context_tbl */
+ HINIC3_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+ HINIC3_UCODE_CMD_GET_RSS_INDIR_TABLE,
+ HINIC3_UCODE_CMD_GET_RSS_CONTEXT_TABLE, /**< Unused */
+ HINIC3_UCODE_CMD_SET_IQ_ENABLE, /**< Unused */
+ HINIC3_UCODE_CMD_SET_RQ_FLUSH = 10, /**< Set RQ flush. @see > hinic3_cmd_set_rq_flush */
+ HINIC3_UCODE_CMD_MODIFY_VLAN_CTX, /**< Get rxq info. @see > nic_vlan_ctx */
+ HINIC3_UCODE_CMD_PPA_HASH_TABLE,
+ /**< Get rxq info. @see > hinic3_rxq_hw, < rxq_check_info */
+ HINIC3_UCODE_CMD_RXQ_INFO_GET = 13,
+};
+
+#endif /* NIC_NPU_CMD_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/nic/nic_npu_cmd_defs.h b/drivers/infiniband/hw/hiroce3/include/nic/nic_npu_cmd_defs.h
new file mode 100644
index 0000000000000..f128ba80dae2a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/nic/nic_npu_cmd_defs.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef NIC_NPU_CMD_DEFS_H
+#define NIC_NPU_CMD_DEFS_H
+
+#include "typedef.h"
+#include "nic_cfg_comm.h"
+
+/*
+ * NIC Command Queue Header
+ * queues context follow this header should be consecutive
+ */
+struct nic_cmdq_header {
+ union {
+ struct {
+#if (BYTE_ORDER == BIG_ENDIAN)
+ /* 0x0:SQ, 0x1:RQ */
+ u16 queue_type;
+ /* queue number in buffer follow this header */
+ u16 queue_num;
+#else
+ u16 queue_num;
+ u16 queue_type;
+#endif
+ } cmdq_ctx_dw0;
+
+ u32 ctx_dw0;
+ };
+
+#if (BYTE_ORDER == BIG_ENDIAN)
+ u16 rsvd;
+ u16 start_qid;
+#else
+ u16 start_qid;
+ u16 rsvd;
+#endif
+};
+
+struct nic_cmdq_context_modify_s {
+ struct nic_cmdq_header hdr;
+ u8 data[2016];
+};
+
+struct nic_cmdq_clean_q_space {
+ /*
+ * queue_type = 0, TSO
+ * queue_type = 1, LRO
+ */
+ union {
+ struct {
+#if (BYTE_ORDER == BIG_ENDIAN)
+ u16 queue_type;
+ u16 queue_num;
+#else
+ u16 queue_num;
+ u16 queue_type;
+#endif
+ } cmdq_space_dw0;
+
+ u32 space_dw0;
+ };
+
+#if (BYTE_ORDER == BIG_ENDIAN)
+ u16 rsvd;
+ u16 start_qid;
+#else
+ u16 start_qid;
+ u16 rsvd;
+#endif
+
+ u32 rsvd1;
+};
+
+struct nic_cmdq_flush_rq_task {
+ union {
+ struct {
+#if (BYTE_ORDER == BIG_ENDIAN)
+ u16 q_id;
+ u16 glb_rq_id;
+#else
+ u16 glb_rq_id;
+ u16 q_id;
+#endif
+ } bs;
+
+ u32 value;
+ } dw0;
+};
+
+/* arm sq/rq */
+union nic_cmdq_arm {
+ struct cmdq_arm_dw0_s {
+#if (BYTE_ORDER == BIG_ENDIAN)
+ u16 qpn;
+ u16 pi;
+#else
+ u16 pi;
+ u16 qpn;
+#endif
+ } dw0;
+
+ u32 arm_dw0;
+};
+
+
+/* rss */
+struct nic_rss_indirect_tbl {
+ u32 rsvd[4]; // Make sure that 16B beyond entry[]
+ u16 entry[NIC_RSS_INDIR_SIZE];
+};
+
+struct nic_rss_glb_qid_indirect_tbl {
+ u32 group_index;
+ u32 offset;
+ u32 size;
+ u32 rsvd; /* Make sure that 16B beyond entry[] */
+ u16 entry[NIC_RSS_INDIR_SIZE];
+};
+
+struct nic_rss_context_tbl {
+ u32 rsvd[4];
+ u32 ctx;
+};
+
+struct nic_vlan_ctx {
+ u32 func_id;
+ u32 qid; /* if qid = 0xFFFF, config current function all queue */
+ u32 vlan_id;
+ u32 vlan_mode;
+ u32 vlan_sel;
+};
+
+#endif /* NIC_NPU_CMD_DEFS_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/node_id.h b/drivers/infiniband/hw/hiroce3/include/node_id.h
new file mode 100644
index 0000000000000..84d276873fb3f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/node_id.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+#ifndef NODE_ID_H
+#define NODE_ID_H
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C"{
+#endif
+#endif /* __cplusplus */
+
+/** RING NODE ID */
+enum {
+ NODE_ID_CPI = 0,
+ NODE_ID_MQM = 1,
+ NODE_ID_QUF = 2,
+ NODE_ID_Reserved0 = 3,
+ NODE_ID_SMF0 = 4,
+ NODE_ID_TILE_F0 = 5,
+ NODE_ID_TILE_F1 = 6,
+ NODE_ID_SMF1 = 7,
+ NODE_ID_DP_NETWORK = 8,
+ NODE_ID_CPB = 9,
+ NODE_ID_QUL = 10,
+ NODE_ID_TS = 11,
+ NODE_ID_TILE_L1 = 12,
+ NODE_ID_SML1 = 13,
+ NODE_ID_SML0 = 14,
+ NODE_ID_TILE_L0 = 15,
+ NODE_ID_SMF2 = 16,
+ NODE_ID_TILE_F2 = 17,
+ NODE_ID_TILE_F3 = 18,
+ NODE_ID_SMF3 = 19,
+ NODE_ID_TILE_L3 = 20,
+ NODE_ID_SML3 = 21,
+ NODE_ID_SML2 = 22,
+ NODE_ID_TILE_L2 = 23,
+ NODE_ID_CRYPTO = 24,
+ NODE_ID_LCAM = 25,
+ NODE_ID_MPU = 26,
+ NODE_ID_DP_HOST = 27,
+ NODE_ID_UP_HOST = 31 /* Used for API chain function in the CPI */
+};
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif /* NODE_ID_H */
+
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/rdma_context_format.h b/drivers/infiniband/hw/hiroce3/include/rdma/rdma_context_format.h
new file mode 100644
index 0000000000000..d68648540d300
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/rdma_context_format.h
@@ -0,0 +1,5181 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef RDMA_CONTEXT_FORMAT_H
+#define RDMA_CONTEXT_FORMAT_H
+
+#include "roce_hmm_context.h"
+#include "rdma_ext_ctx_format.h"
+
+
+/* Align each field with 4bytes. */
+#pragma pack(4)
+
+/* **************** Macro Definition ****************** */
+#define ROCE_BASE_GID_IDX 1
+#define RDMA_SGID_TBL_KEY_VFID_OFFSET (4)
+#define RDMA_SGID_TBL_KEY_SGIDIDX_OFFSET (0)
+#define ROCE_SPU_HOST_ID (4)
+#define ROCE_SPU_OQID_HOST_ID (5)
+#define ROCE_SDI_SHOST_HOST_ID 0
+#define ROCE_SDI_MHOST_HOST_ID 1
+#define QU_OQID_RW_CHANNEL 1
+#define ROCE_GET_HOST_OQID(host_id, xid) \
+ ((((128U * (host_id) + ((xid) & 0x7f)) << 2) & 0x7ff) | \
+ (((host_id) & 0x7) << 11U) | (((xid) & 0x1) + 1))
+#define ROCE_GET_SPU_HOST_OQID(host_id, fid, xid) \
+ (((((fid) & 0x1ff) << 2) & 0x7FF) | (((host_id) & 0x7) << 11U) | (QU_OQID_RW_CHANNEL))
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 0x1234
+#endif
+
+#define ETH_ADDR_LEN (6)
+
+/* **************** Data Structure Definition ****************** */
+/* * QPC Format start */
+
+/* Send Queue Context 64B */
+struct chip_seg_sqc {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_pd : 18;
+ u32 sq_inline_en : 1;
+ u32 sq_pi_on_chip : 1;
+ u32 sq_wqebb_size : 3;
+ u32 sq_page_size : 4;
+ u32 sq_size : 5;
+#else
+ /*
+ * Send WQ size is (2^sq_size)*WQEBBs; the
+ * maximum SQ size is 16K WQEs, so this field
+ * doesn't exceed 14. They have same configuration
+ * value: SQC.sq_size and SQAC.sq_size.
+ * Configured by Driver
+ */
+ u32 sq_size : 5;
+
+ /*
+ * Page size of SQ and RQ, equals to (2^sq_page_size)*4KB.
+ * The following three Page size have same configuration
+ * value: SQC.sq_page_size,
+ * SQAC.sq_page_size and RQC.rq_page_size. Configured by Driver
+ */
+ u32 sq_page_size : 4;
+ /*
+ * Send WQE Basic Block (WQEBB) size in
+ * bytes is 16*(2^sq_weqbb_size).
+ * for the SQ, this field should be fixed to 2.
+ * They have same configuration value: SQC.sq_wqebb_size
+ * and SQAC.sq_wqebb_size.
+ * Configured by Driver
+ */
+ u32 sq_wqebb_size : 3;
+ /*
+ * If set, the counter (PI index) of Send Queue is
+ * stored in the chip, the counter is
+ * absolute value. Configured by Driver
+ */
+ u32 sq_pi_on_chip : 1;
+ /*
+ * Indicates if the SQ supports inline data operation.
+ * Configured by Driver
+ */
+ u32 sq_inline_en : 1;
+ /*
+ * Protection Domain.
+ * The following five Protection Domains have
+ * same configuration value: QCC.rc_pd,
+ * QC.sq_pd, SQAC.sq_pd, RQC.rq_pd and RRWC.rrw_pd.
+ * Configured by Driver
+ */
+ u32 sq_pd : 18;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_so_ro : 2;
+ u32 sq_dma_attr_idx : 6;
+ u32 sq_wqecnt_rctl : 1;
+ u32 sq_prewqe_mode : 1;
+ u32 sq_pi_vld : 1;
+ u32 sq_wqecnt_rctl_en : 1;
+ u32 sq_wqecnt_lth : 4;
+ u32 rsvd : 16;
+#else
+ u32 rsvd : 16;
+ /*
+ * WQE Counter Low Threshold, equals to (2^sq_wqecnt_lth).
+ * Configured by Driver
+ */
+ u32 sq_wqecnt_lth : 4;
+ /*
+ * If this field is equal to zero, the SQ
+ * PI updating should be not controlled by
+ * the "sq_wqecnt_rctl" field; else the SQ
+ * RI updating can be performed only if
+ * the "sq_wqecnt_rctl" is equal to one.
+ * Configured by Driver
+ */
+ u32 sq_wqecnt_rctl_en : 1;
+ /*
+ * If set, the SQ should use the Index Mechanism,
+ * else the SQ uses the Owner Bit
+ * Mechanism. Configured by Driver
+ */
+ u32 sq_pi_vld : 1;
+ /*
+ * If set,the engine just performs prefetch WQE
+ * processing after completing the current WQE in
+ * the SQ_DMA_GEN_API flow.
+ */
+ u32 sq_prewqe_mode : 1;
+ /*
+ * The hardware clear it to zero when performing a SQ
+ * PI updating, and driver set it
+ * to one to indicate the hardware can performing SQ PI updating.
+ * N/A
+ */
+ u32 sq_wqecnt_rctl : 1;
+ /*
+ * bit[05:00] It specifies the outbound PCIe TLP
+ * header attribute of the DMA
+ * operation. This filed is only valid when processing
+ * SQ's WQEs. The following two
+ * "dma_attr_idx" have same configuration value:
+ * SQC.sq_dma_attr_idx and
+ * SQAC.sq_dma_attr_idx. Configured by Driver
+ */
+ u32 sq_dma_attr_idx : 6;
+ /*
+ * It specifies the ATTR[1:0] bits in the outbound
+ * PCIe TLP headers of the DMA operation.
+ * This field is only valid when processing SQ's WQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ * The following two "so_ro" have same configuration value:
+ * SQC.sq_so_ro and
+ * SQAC.sq_so_ro. Configured by Driver
+ */
+ u32 sq_so_ro : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_state : 4;
+ u32 rsvd2 : 4;
+ u32 sq_rkey_en : 1;
+ u32 sq_wqe_check_en : 1;
+ u32 rsvd1 : 6;
+ u32 sq_pi : 16;
+#else
+ /* The Producer Index (PI) of Send Queue (Step: WQEBB) 0x0 */
+ u32 sq_pi : 16;
+ u32 rsvd1 : 6;
+ u32 sq_wqe_check_en : 1;
+ u32 sq_rkey_en : 1;
+ u32 rsvd2 : 4;
+ /*
+ * Send Queue State.0x0:ok;0x1:error;
+ * 0xf:hardware has no access right.Other:reserved.
+ * 0x0
+ */
+ u32 sq_state : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_ci : 16;
+ u32 rsvd : 3;
+ u32 dsgl_en : 1; /* Whether to work in dual sgl mode */
+ u32 sq_load_pi : 1;
+ u32 sq_load_page_gpa : 1;
+ u32 sq_wqe_curt_page_vld : 1;
+ u32 sq_wqe_next_page_vld : 1;
+ u32 sq_wqe_curt_page_gpa_h : 8;
+#else
+ /*
+ * bit[63:56] Indicates the GPA of current SQ
+ * buffer's page pointed by
+ * "sq_ci". 0x0
+ */
+ u32 sq_wqe_curt_page_gpa_h : 8;
+ /* Indicates if the "sq_wqe_next_page_gpa" field is valid. */
+ u32 sq_wqe_next_page_vld : 1;
+ /*
+ * Indicates if the "sq_wqe_curt_page_gpa" field is valid.
+ * 1: it is valid;0: it is invalid.
+ * 0x0
+ */
+ u32 sq_wqe_curt_page_vld : 1;
+ /*
+ * Indicates the thread is performing a
+ * prefetch for GPA of WQE page. 0x0
+ */
+ u32 sq_load_page_gpa : 1;
+ /* Indicates the thread is performing a PI prefetch processing */
+ u32 sq_load_pi : 1;
+ u32 dsgl_en : 1;
+ u32 rsvd : 3;
+ /* bit[19:00] The CI index of Send Queue (Step: WQEBB) 0x0 */
+ u32 sq_ci : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ u32 sq_wqe_curt_page_gpa_m; /* bit[55:24] */
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_wqe_curt_page_gpa_l : 12;
+ u32 sq_wqe_next_page_gpa_h : 20;
+#else
+ u32 sq_wqe_next_page_gpa_h : 20; /* bit[63:44] */
+ u32 sq_wqe_curt_page_gpa_l : 12; /* bit[23:12] */
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ /*
+ * bit[43:12] Indicates the page GPA of next
+ * SQ buffer's page pointed by "sq_ci". 0x0
+ */
+ u32 sq_wqe_next_page_gpa_l;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_wqe_prefetch_ci : 16;
+ u32 rsvd : 4;
+ u32 sq_signature : 3;
+ u32 sq_wqe_prefetch_curtmax : 3;
+ u32 sq_wqe_prefetch_maxnum : 3;
+ u32 sq_wqe_prefetch_minnum : 3;
+#else
+ u32 sq_wqe_prefetch_minnum : 3;
+ u32 sq_wqe_prefetch_maxnum : 3;
+ u32 sq_wqe_prefetch_curtmax : 3;
+ u32 sq_signature : 3;
+ u32 rsvd : 4;
+ /*
+ * bit[15:00] The prefetch CI index of
+ * Send Queue (Step: WQEBB).0x0
+ */
+ u32 sq_wqe_prefetch_ci : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ /* DW8 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_curt_sge_vld : 1;
+ u32 rsvd : 3;
+ u32 sq_curt_sge_lkey : 28;
+#else
+ /*
+ * bit[27:00] Indicates the L_Key of current SGE.
+ * Using sq_curt_sge_lkey[27:8] to
+ * access the corresponding MPT. 0x0
+ */
+ u32 sq_curt_sge_lkey : 28;
+ u32 rsvd : 3;
+ /*
+ * Indicates current SGE information is valid.
+ * The remaining sq_curt_sge_* field are
+ * only valid when the sq_curt_sge_vld is
+ * asserted.1: SGE is valid;,0: SGE is
+ * invalid. 0x0
+ */
+ u32 sq_curt_sge_vld : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw8;
+
+ /* DW9~10 */
+ union {
+ u64 sq_curt_sge_va; /* hi:bit[63:32],lo:bit[31:00] */
+ struct {
+ u32 sq_curt_sge_va_hi;
+ u32 sq_curt_sge_va_lo;
+ } dw9;
+ };
+
+ /* DW11 */
+ /* bit[31:00] Indicates the remaining memory space of current SGE. 0x0 */
+ u32 sq_curt_sge_remain_len;
+
+ /* DW12 */
+ /*
+ * bit[63:32] Indicates the GPA of current data buffer page pointed by
+ * "sq_curt_sge_va".0x0
+ */
+ u32 sq_curt_sge_dbuff_gpa_h;
+
+ /* DW13 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_curt_sge_dbuff_gpa_l : 20;
+ u32 sq_curt_sge_dbuff_gpa_vld : 1;
+ u32 sq_curt_sge_dsgl : 1;
+ u32 sq_curt_sge_used : 1;
+ u32 sq_curt_sge_last : 1;
+ u32 rsvd : 8;
+#else
+ u32 rsvd : 8;
+ /*
+ * Indicates the current SGE is the
+ * last SGE for the current WQE. 0x0
+ */
+ u32 sq_curt_sge_last : 1;
+ u32 sq_curt_sge_used : 1;
+ u32 sq_curt_sge_dsgl : 1;
+ /*
+ * Indicates if the "sq_curt_sge_dbuff_gpa"
+ * field is valid. 1: it is
+ * valid;0:it is invalid.
+ */
+ u32 sq_curt_sge_dbuff_gpa_vld : 1;
+ /*
+ * bit[31:12] Indicates the GPA of current
+ * data buffer page pointed by
+ * "sq_curt_sge_va".0x0
+ */
+ u32 sq_curt_sge_dbuff_gpa_l : 20;
+#endif
+ } bs;
+ u32 value;
+ } dw13;
+
+ /* DW14 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_mtt_prefetch_cline_num : 5;
+ u32 sq_mtt_prefetch_cline_ptr : 6;
+ u32 sq_wqe_prefetch_finish : 1;
+ u32 rsvd : 4;
+ u32 sq_mtt_prefetch_wqe_ci : 16;
+#else
+ /* bit[15:0] Indicates the WQE index of prefetch MTTs operation */
+ u32 sq_mtt_prefetch_wqe_ci : 16;
+ u32 rsvd : 4;
+ u32 sq_wqe_prefetch_finish : 1;
+ u32 sq_mtt_prefetch_cline_ptr : 6;
+ u32 sq_mtt_prefetch_cline_num : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw14;
+
+ /* DW15 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_wqe_cache_thd_sel : 2;
+ u32 sq_mtt_prefetch_maxlen : 3;
+ u32 sq_wqe_prefetch_mode : 1;
+ u32 sq_prefetch_one_wqe : 1;
+ u32 sq_curt_sge_idx : 6;
+ u32 rsvd : 8;
+ u32 sq_mtt_prefetch_sge_idx : 6;
+ u32 sq_load_wqe : 1;
+ u32 sq_load_mtt : 1;
+ u32 sq_load_dbuff : 1;
+ u32 sq_prefetch_thread_num : 2;
+#else
+ u32 sq_prefetch_thread_num : 2;
+ u32 sq_load_dbuff : 1;
+ u32 sq_load_mtt : 1;
+ u32 sq_load_wqe : 1;
+ u32 sq_mtt_prefetch_sge_idx : 6;
+ u32 rsvd : 8;
+ /* The SGE index of current accessed WQE. 0x0 */
+ u32 sq_curt_sge_idx : 6;
+ u32 sq_prefetch_one_wqe : 1;
+ u32 sq_wqe_prefetch_mode : 1;
+ u32 sq_mtt_prefetch_maxlen : 3;
+ u32 sq_wqe_cache_thd_sel : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw15;
+};
+
+/* Send Queue ACK Context 64B */
+struct chip_seg_sqac {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_pd : 18;
+ u32 rsvd : 1;
+ u32 vbs_sqa_pi_on_chip : 1;
+ u32 sq_wqebb_size : 3;
+ u32 sq_page_size : 4;
+ u32 sq_size : 5;
+#else
+ /*
+ * Send WQ size is (2^sq_size)*WQEBBs; the maximum
+ * SQ size is 16K WQEs, so this field
+ * doesn't exceed 14. They have same configuration
+ * value: SQC.sq_size and SQAC.sq_size.
+ * Configured by Driver
+ */
+ u32 sq_size : 5;
+
+ /*
+ * Page size of SQ and RQ, equals to (2^sq_page_size)*4KB.
+ * The following three Page size have same configuration
+ * value: SQC.sq_page_size,
+ * SQAC.sq_page_size and RQC.rq_page_size. Configured by Driver
+ */
+ u32 sq_page_size : 4;
+ /* Send WQE Basic Block (WQEBB) size in bytes is 16*(2^sq_weqbb_size).
+ * for the SQ, this field should be fixed to 2.
+ * They have same configuration value: SQC.
+ * sq_wqebb_size and SQAC.sq_wqebb_size.
+ * Configured by Driver
+ */
+ u32 sq_wqebb_size : 3;
+ u32 vbs_sqa_pi_on_chip : 1;
+ u32 rsvd : 1;
+ /*
+ * Protection Domain.
+ * The following five Protection Domains have same
+ * configuration value: QCC.rc_pd,
+ * SQC.sq_pd, SQAC.sq_pd, RQC.rq_pd and RRWC.rrw_pd.
+ * Configured by Driver
+ */
+ u32 sq_pd : 18;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_so_ro : 2;
+ u32 sq_dma_attr_idx : 6;
+ u32 rsvd2 : 1;
+ u32 sqa_prewqe_mode : 1;
+ u32 vbs_sqa_pi_vld : 1;
+ u32 rsvd1 : 1;
+ u32 sqa_cqn : 20;
+#else
+ /* bit[19:00] SQ's Completion Queue Number. */
+ u32 sqa_cqn : 20;
+ u32 rsvd1 : 1;
+ u32 vbs_sqa_pi_vld : 1;
+ u32 sqa_prewqe_mode : 1;
+ u32 rsvd2 : 1;
+ /*
+ * bit[05:00] It specifies the outbound PCIe
+ * TLP header attribute of the DMA
+ * operation. This filed is only valid when
+ * processing SQ's WQEs. The following two
+ * "dma_attr_idx"have same configuration value:
+ * SQC. sq_dma_attr_idx and
+ * SQAC.sq_dma_attr_idx. Configured by Driver
+ */
+ u32 sq_dma_attr_idx : 6;
+ u32 sq_so_ro : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqa_state : 4;
+ u32 rsvd2 : 4;
+ u32 sq_rkey_en : 1;
+ u32 sq_wqe_check_en : 1;
+ u32 rsvd1 : 6;
+ u32 sqa_wqe_index : 16;
+#else
+ u32 sqa_wqe_index : 16; /* bit[15:00] */
+ u32 rsvd1 : 6;
+ u32 sq_wqe_check_en : 1;
+ u32 sq_rkey_en : 1;
+ u32 rsvd2 : 4;
+ u32 sqa_state : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqa_ci : 16;
+ u32 rsvd1 : 3;
+ u32 dsgl_en : 1;
+ u32 rsvd : 1;
+ u32 sqa_load_page_gpa : 1;
+ u32 sqa_wqe_curt_page_vld : 1;
+ u32 sqa_wqe_next_page_vld : 1;
+ u32 sqa_wqe_curt_page_gpa_h : 8;
+#else
+ u32 sqa_wqe_curt_page_gpa_h : 8; /* bit[63:56] */
+ u32 sqa_wqe_next_page_vld : 1;
+ u32 sqa_wqe_curt_page_vld : 1;
+ u32 sqa_load_page_gpa : 1;
+ u32 rsvd : 1;
+ u32 dsgl_en : 1;
+ u32 rsvd1 : 3;
+ u32 sqa_ci : 16; /* bit[15:00] */
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ u32 sqa_wqe_curt_page_gpa_m; /* bit[55:24] */
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqa_wqe_curt_page_gpa_l : 12;
+ u32 sqa_wqe_next_page_gpa_h : 20;
+#else
+ u32 sqa_wqe_next_page_gpa_h : 20; /* bit[63:44] */
+ u32 sqa_wqe_curt_page_gpa_l : 12; /* bit[23:12] */
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ u32 sqa_wqe_next_page_gpa_l; /* bit[43:12] */
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqa_wqe_prefetch_ci : 16;
+ u32 rsvd2 : 4;
+ u32 sqa_signature : 3;
+ u32 rsvd1 : 3;
+ u32 sqa_wqe_prefetch_maxnum : 3;
+ u32 sqa_wqe_prefetch_minnum : 3;
+#else
+ u32 sqa_wqe_prefetch_minnum : 3;
+ u32 sqa_wqe_prefetch_maxnum : 3;
+ u32 rsvd1 : 3;
+ u32 sqa_signature : 3;
+ u32 rsvd2 : 4;
+ u32 sqa_wqe_prefetch_ci : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ /* DW8 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqa_curt_sge_vld : 1;
+ u32 rsvd : 3;
+ u32 sqa_curt_sge_lkey : 28;
+#else
+ u32 sqa_curt_sge_lkey : 28; /* bit[27:00] */
+ u32 rsvd : 3;
+ u32 sqa_curt_sge_vld : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw8;
+
+ /* DW9~10 */
+ union {
+ u64 sqa_curt_sge_va; /* hi:bit[63:32],lo:bit[31:00] */
+ struct {
+ u32 sqa_curt_sge_va_hi;
+ u32 sqa_curt_sge_va_lo;
+ } dw9;
+ };
+
+ /* DW11 */
+ u32 sqa_curt_sge_remain_len; /* bit[31:00] */
+
+ /* DW12 */
+ u32 sqa_curt_sge_dbuff_gpa_h; /* bit[63:32] */
+
+ /* DW13 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqa_curt_sge_dbuff_gpa_l : 20;
+ u32 sqa_curt_sge_dbuff_gpa_vld : 1;
+ u32 sqa_curt_sge_dsgl : 1;
+ u32 sqa_curt_sge_used : 1;
+ u32 sqa_curt_sge_last : 1;
+ u32 rsvd : 8;
+#else
+ u32 rsvd : 8;
+ u32 sqa_curt_sge_last : 1;
+ u32 sqa_curt_sge_used : 1;
+ u32 sqa_curt_sge_dsgl : 1;
+ u32 sqa_curt_sge_dbuff_gpa_vld : 1;
+ u32 sqa_curt_sge_dbuff_gpa_l : 20; /* bit[31:12] */
+#endif
+ } bs;
+ u32 value;
+ } dw13;
+
+ /* DW14 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqa_mtt_prefetch_cline_num : 5;
+ u32 sqa_mtt_prefetch_cline_ptr : 6;
+ u32 sqa_mtt_prefetch_finish : 1;
+ u32 rsvd : 4;
+ u32 sqa_mtt_prefetch_wqe_ci : 16;
+#else
+ u32 sqa_mtt_prefetch_wqe_ci : 16;
+ u32 rsvd : 4;
+ u32 sqa_mtt_prefetch_finish : 1;
+ u32 sqa_mtt_prefetch_cline_ptr : 6;
+ u32 sqa_mtt_prefetch_cline_num : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw14;
+
+ /* DW15 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqa_wqe_cache_thd_sel : 2;
+ u32 sqa_mtt_prefetch_maxlen : 3;
+ u32 rsvd2 : 2;
+ u32 sqa_curt_sge_idx : 6;
+ u32 rsvd1 : 8;
+ u32 sqa_mtt_prefetch_sge_idx : 6;
+ u32 sqa_load_wqe : 1;
+ u32 sqa_load_mtt : 1;
+ u32 sqa_load_dbuff : 1;
+ u32 sqa_prefetch_thread_num : 2;
+#else
+ u32 sqa_prefetch_thread_num : 2;
+ u32 sqa_load_dbuff : 1;
+ u32 sqa_load_mtt : 1;
+ u32 sqa_load_wqe : 1;
+ u32 sqa_mtt_prefetch_sge_idx : 6;
+ u32 rsvd1 : 8;
+ u32 sqa_curt_sge_idx : 6;
+ u32 rsvd2 : 2;
+ u32 sqa_mtt_prefetch_maxlen : 3;
+ u32 sqa_wqe_cache_thd_sel : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw15;
+};
+
+/* Receive Queue Context 64B */
+struct chip_seg_rqc {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_pd : 18;
+ u32 rq_inline_en : 1;
+ u32 rq_pi_on_chip : 1;
+ u32 rq_wqebb_size : 3;
+ u32 rq_page_size : 4;
+ u32 rq_size : 5;
+#else
+ /*
+ * Receive Queue size, equals to (2^rq_size)*WQEBB.
+ * The maximum RQ size is 16K WQEs,
+ * so this field doesn't exceed 14.
+ * Configured by Driver
+ */
+ u32 rq_size : 5;
+ /*
+ * Page size of SQ and RQ, equals to (2^rq_page_size)*4KB.
+ * Configured by Driver
+ */
+ u32 rq_page_size : 4;
+ /*
+ * Receive WQE Basic Block (WQEBB) size
+ * in bytes is (2^rq_wqebb_size)*16B.
+ * The minimum size is 16B and the values 4, 5, 6, 7 are reserved.
+ * Configured by Driver
+ */
+ u32 rq_wqebb_size : 3;
+ /*
+ * If set, the counter (PI index) of Receive
+ * Queue is stored in the chip, the counter
+ * is absolute value. Configured by Driver
+ */
+ u32 rq_pi_on_chip : 1;
+ /*
+ * If set, in-line scatter is enabled for this RQ.
+ * Configured by Driver
+ */
+ u32 rq_inline_en : 1;
+ /*
+ * bit[17:00] Protection Domain.The following five
+ * Protection Domains have same configuration
+ * value: QCC.rc_pd, SQC.sq_pd, SQAC.sq_pd,
+ * RQC.rq_pd and RRWC.rrw_pd. Configured by
+ * Driver
+ */
+ u32 rq_pd : 18;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_so_ro : 2;
+ u32 rq_dma_attr_idx : 6;
+ u32 rq_rkey_en : 1;
+ u32 rq_signature : 3;
+ u32 rq_cqn : 20;
+#else
+ /*
+ * bit[19:00] Receive Queue completions are
+ * to be reported to this CQ number.
+ * Configured by Driver
+ */
+ u32 rq_cqn : 20;
+ u32 rq_signature : 3;
+ u32 rq_rkey_en : 1;
+ /*
+ * bit[05:00] It specifies the outbound PCIe
+ * TLP header attribute of the DMA
+ * operation. This filed is only valid when
+ * processing RQ's WQEs. Configured by
+ * Driver
+ */
+ u32 rq_dma_attr_idx : 6;
+ /* It specifies the ATTR[1:0] bits in the outbound
+ * PCIe TLP headers of the DMA operation.
+ * This field is only valid when processing RQ's WQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ * Configured by Driver
+ */
+ u32 rq_so_ro : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_state : 4;
+ u32 rsvd2 : 13;
+ u32 rq_wqe_cache_thd_sel : 2;
+ u32 rq_inlin_len : 4;
+ u32 rq_wqecnt_rctl : 1;
+ u32 rsvd1 : 2;
+ u32 rq_wqecnt_rctl_en : 1;
+ u32 rq_wqecnt_lth : 4;
+ u32 rq_srq_en : 1;
+#else
+ /*
+ * If set, indicates it should use SRQ as the receive queue.
+ * Configured by Driver
+ */
+ u32 rq_srq_en : 1;
+ /*
+ * WQE Counter Low Threshold, equals to (2^rq_wqecnt_lth).
+ * Configured by Driver
+ */
+ u32 rq_wqecnt_lth : 4;
+ /*
+ * If this field is equal to zero, the RQ PI updating
+ * should be not controlled by
+ * the "rq_wqecnt_rctl" field; else the RQ RI updating
+ * can be performed only if
+ * the "rq_wqecnt_rctl" is equal to one. Configured by Driver
+ */
+ u32 rq_wqecnt_rctl_en : 1;
+ u32 rsvd1 : 2;
+ /*
+ * The hardware clear it to zero when performing
+ * a RQ PI updating, and driver set it
+ * to one to indicate the hardware can performing
+ * RQ PI updating. N/A
+ */
+ u32 rq_wqecnt_rctl : 1;
+ /*
+ * Inline Data Length, equals to (2^rq_inline_len) bytes.
+ * Configured by Driver
+ */
+ u32 rq_inlin_len : 4;
+ u32 rq_wqe_cache_thd_sel : 2;
+ u32 rsvd2 : 13;
+ /*
+ * Receive Queue State.0xf: ok;0x1: error;0x0:
+ * hardware has no access right.Other:
+ * reserved. 0x0
+ */
+ u32 rq_state : 4;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_state : 4;
+ u32 rsvd : 2;
+ u32 container_en : 1;
+ u32 rsvd0 : 1;
+ u32 rq_srqn : 18;
+ u32 rsvd1 : 5;
+ u32 rq_srq_en : 1;
+#else
+ u32 rq_srq_en : 1;
+ u32 rsvd1 : 5;
+ u32 rq_srqn : 18;
+ u32 rsvd0 : 1;
+ u32 container_en : 1;
+ u32 rsvd : 2;
+ u32 rq_state : 4;
+#endif
+ } srq;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_state : 4;
+ u32 container_size : 2;
+ u32 container_en : 1;
+ u32 rsvd : 6;
+ u32 rq_srqn : 18;
+ u32 rq_srq_en : 1;
+#else
+ u32 rq_srq_en : 1;
+ u32 rq_srqn : 18;
+ u32 rsvd : 6;
+ u32 container_en : 1;
+ u32 container_size : 2;
+ u32 rq_state : 4;
+#endif
+ } srq_c;
+
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_ci : 16;
+ u32 rsvd : 4;
+ u32 rq_load_pi : 1;
+ u32 rq_load_page_gpa : 1;
+ u32 rq_wqe_curt_page_vld : 1;
+ u32 rq_wqe_next_page_vld : 1;
+ u32 rq_wqe_curt_page_gpa_h : 8;
+#else
+ /*
+ * bit[63:56] Indicates the GPA of current
+ * RQ buffer's page pointed by
+ * "rq_ci". 0x0
+ */
+ u32 rq_wqe_curt_page_gpa_h : 8;
+ /*
+ * Indicates if the "rq_wqe_curt_page_gpa" field is valid.
+ * 1: it is valid;0: it is invalid.
+ * 0x0
+ */
+ u32 rq_wqe_next_page_vld : 1;
+ /*
+ * Indicates if the "rq_wqe_curt_page_gpa" field is valid.
+ * 1: it is valid;0: it is invalid.
+ * 0x0
+ */
+ u32 rq_wqe_curt_page_vld : 1;
+ /*
+ * Indicates the thread is performing a
+ * prefetch for GPA of WQE page.0x0
+ */
+ u32 rq_load_page_gpa : 1;
+ u32 rq_load_pi : 1;
+ u32 rsvd : 4;
+ /* bit[15:00] The CI index of Receive Queue (Step: WQEBB) 0x0 */
+ u32 rq_ci : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ u32 rq_wqe_curt_page_gpa_m; /* bit[55:24] */
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_wqe_curt_page_gpa_l : 12; /* bit[23:12] */
+ u32 rq_wqe_next_page_gpa_h : 20; /* bit[63:44] */
+#else
+ u32 rq_wqe_next_page_gpa_h : 20; /* bit[63:44] */
+ u32 rq_wqe_curt_page_gpa_l : 12; /* bit[23:12] */
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ u32 rq_wqe_next_page_gpa_l; /* bit[43:12] */
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_pi : 16;
+ u32 rq_wqe_prefetch_ci : 16;
+#else
+ /*
+ * bit[15:00] The prefetch CI index of
+ * Receive Queue (Step: WQEBB).0x0
+ */
+ u32 rq_wqe_prefetch_ci : 16;
+ /*
+ * bit[15:00] The Producer Index (PI) of
+ * Receive Queue (Step: WQEBB).0x0
+ */
+ u32 rq_pi : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ /* DW8 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_curt_sge_vld : 1;
+ u32 rsvd : 3;
+ u32 rq_curt_sge_lkey : 28;
+#else
+ /*
+ * bit[27:00] Indicates the L_Key of current SGE.
+ * Using rq_curt_sge_lkey[27:8] to
+ * access the corresponding MPT.0x0
+ */
+ u32 rq_curt_sge_lkey : 28;
+ u32 rsvd : 3;
+ /*
+ * Indicates current SGE information is valid. The remaining
+ * rq_curt_sge_* field are
+ * only valid when the rq_curt_sge_vld is asserted.
+ * 1: SGE is valid;0: SGE is
+ * invalid.0x0
+ */
+ u32 rq_curt_sge_vld : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw8;
+
+ /* DW9~10 */
+ union {
+ u64 rq_curt_sge_va; /* hi:bit[63:32],lo:bit[31:00] */
+ struct {
+ u32 rq_curt_sge_va_hi;
+ u32 rq_curt_sge_va_lo;
+ } dw9;
+ };
+
+ /* DW11 */
+ /* bit[31:00] Indicates the remaining memory space of current SGE.0x0 */
+ u32 rq_curt_sge_remain_len;
+
+ /* DW12 */
+ /*
+ * bit[63:32] Indicates the GPA of current data buffer page pointed by
+ * "rq_curt_sge_va".0x0
+ */
+ u32 rq_curt_sge_dbuff_gpa_h;
+
+ /* DW13 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_curt_sge_dbuff_gpa_l : 20; /* bit[51:32] */
+ /*
+ * Indicates if the "rq_curt_sge_dbuff_gpa" field is valid.1: it is
+ * valid;0: it is invalid.0x0
+ */
+ u32 rq_curt_sge_dbuff_gpa_vld : 1;
+ u32 rq_curt_sge_dsgl : 1;
+ u32 rq_curt_sge_used : 1;
+ /* Indicates the current SGE is the last SGE for the current WQE.0x0 */
+ u32 rq_curt_sge_last : 1;
+ /*
+ * Indicates the current Receive WQE's status.
+ * 0: the Receive WQE don't be
+ * accessed; 1: the Receive WQE has been accessed.0x0
+ */
+ u32 rq_curt_wqe_status : 1;
+ u32 rsvd : 3;
+ u32 rq_mtt_prefetch_sge_idx : 4;
+#else
+ u32 rq_mtt_prefetch_sge_idx : 4;
+ u32 rsvd : 3;
+ u32 rq_curt_wqe_status : 1;
+ u32 rq_curt_sge_last : 1;
+ u32 rq_curt_sge_used : 1;
+ u32 rq_curt_sge_dsgl : 1;
+ u32 rq_curt_sge_dbuff_gpa_vld : 1;
+ u32 rq_curt_sge_dbuff_gpa_l : 20; /* bit[31:12] */
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_curt_sge_remain_len : 17;
+ u32 rq_curt_sge_meta_lkey : 3;
+ u32 rsvd1 : 1;
+ u32 rq_curt_sge_dsgl : 1;
+ u32 rq_curt_sge_used : 1;
+ u32 rq_curt_sge_last : 1;
+
+ u32 rq_curt_meta_used : 1;
+ u32 rq_curt_meta_last : 1;
+ u32 rq_curt_meta_vld : 1;
+ u32 rq_prefetch_thread_num : 2;
+ u32 rq_curt_meta_lkey : 3;
+#else
+
+ u32 rq_curt_meta_lkey : 3;
+ u32 rq_prefetch_thread_num : 2;
+ u32 rq_curt_meta_vld : 1;
+ u32 rq_curt_meta_last : 1;
+ u32 rq_curt_meta_used : 1;
+
+ u32 rq_curt_sge_last : 1;
+ u32 rq_curt_sge_used : 1;
+ u32 rq_curt_sge_dsgl : 1;
+ u32 rsvd1 : 1;
+ u32 rq_curt_sge_meta_lkey : 3;
+ u32 rq_curt_sge_remain_len : 17;
+#endif
+ } bs_dsgl;
+ u32 value;
+ } dw13;
+
+ /* DW14 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_prefetch_thread_num : 2;
+ u32 rq_mtt_prefetch_cline_num : 4;
+ u32 rq_mtt_prefetch_cline_ptr : 6;
+ u32 rq_mtt_prefetch_finish : 1;
+ u32 rsvd : 3;
+ u32 rq_mtt_prefetch_wqe_ci : 16;
+#else
+ u32 rq_mtt_prefetch_wqe_ci : 16;
+ u32 rsvd : 3;
+ u32 rq_mtt_prefetch_finish : 1;
+ u32 rq_mtt_prefetch_cline_ptr : 6;
+ u32 rq_mtt_prefetch_cline_num : 4;
+ u32 rq_prefetch_thread_num : 2;
+#endif
+ } bs;
+ struct {
+ } bc_c;
+ u32 value;
+ } dw14;
+
+ /* DW15 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_wqe_prefetch_maxnum : 3;
+ u32 rq_wqe_prefetch_minnum : 3;
+ u32 rq_mtt_prefetch_maxwqe : 3;
+ u32 rq_mtt_prefetch_maxlen0 : 2;
+ u32 rq_mtt_prefetch_maxlen1 : 2;
+ u32 rq_curt_sge_idx : 4;
+ u32 rsvd : 11;
+ u32 rq_load_next_mtt : 1;
+ u32 rq_load_wqe : 1;
+ u32 rq_load_curt_mtt : 1;
+ u32 rq_load_dbuff : 1;
+#else
+ u32 rq_load_dbuff : 1;
+ u32 rq_load_curt_mtt : 1;
+ u32 rq_load_wqe : 1;
+ u32 rq_load_next_mtt : 1;
+ u32 rsvd : 11;
+ /* The SGE index of current accessed WQE.0x0 */
+ u32 rq_curt_sge_idx : 4;
+ u32 rq_mtt_prefetch_maxlen1 : 2;
+ u32 rq_mtt_prefetch_maxlen0 : 2;
+ u32 rq_mtt_prefetch_maxwqe : 3;
+ u32 rq_wqe_prefetch_minnum : 3;
+ u32 rq_wqe_prefetch_maxnum : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw15;
+};
+
+/* SRQ info in QPC */
+struct chip_seg_srqc {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 srq_pd : 18;
+ u32 rsvd : 2;
+ u32 srq_wqebb_size : 3;
+ u32 srq_page_size : 4;
+ u32 srq_size : 5;
+#else
+ u32 srq_size : 5;
+ u32 srq_page_size : 4;
+ /*
+ * Shared Receive WQE Basic Block (WQEBB) size in bytes is
+ * (2^rq_srq_wqebb_size)*16B. The minimum size is 32B and
+ * the values 0, 4, 5, 6, 7 are reserved.
+ * This field is updated by SRQC.srq_wqebb_size.
+ * 0x0
+ */
+ u32 srq_wqebb_size : 3;
+ u32 rsvd : 2;
+ /*
+ * bit[17:00]Protection Domain. If the QP is a
+ * XRC transport service type,
+ * this filed should be updated by the "srq_pd"
+ * in the SRQ context
+ * pointed by XRCSRQ; else this field is updated
+ * by the "srq_pd" in the
+ * SRQ context associated with the QP.
+ * The following five Protection Domains have
+ * same configuration value:
+ * QCC.rc_pd, SQC.sq_pd, SQAC.sq_pd, RQC.rq_pd and RRWC.rrw_pd.
+ * 0x0
+ */
+ u32 srq_pd : 18;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 srq_so_ro : 2;
+ u32 srq_dma_attr_idx : 6;
+ u32 srq_rkey_en : 1;
+ u32 srq_signature : 3;
+ u32 srq_cqn : 20;
+#else
+ /*
+ * bit[19:00] Receive Queue completions are
+ * to be reported to this CQ number.
+ * If the QP is a XRC transport service type,
+ * this filed should be updated
+ * by the "srq_xrc_cqn" in the SRQ context
+ * pointed by XRCSRQ; else this
+ * field is configured by the driver.
+ * Configured by Driver
+ */
+ u32 srq_cqn : 20;
+ u32 srq_signature : 3;
+ u32 srq_rkey_en : 1;
+ u32 srq_dma_attr_idx : 6; /* bit[05:00] */
+ /*
+ * It specifies the ATTR[1:0] bits in the
+ * outbound PCIe TLP headers of the
+ * DMA operation. This field is only valid when processing SRQ's WQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ * This field is updated by SRQC.srq_so_ro.
+ * 0x0
+ */
+ u32 srq_so_ro : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 srq_state : 4;
+ u32 rsvd2 : 4;
+ u32 srqn : 18;
+ u32 rsvd1 : 5;
+ u32 srq_en : 1;
+#else
+ /*
+ * If set, indicates it should use SRQ as the receive queue.
+ * Configured by Driver
+ */
+ u32 srq_en : 1;
+ u32 rsvd1 : 5;
+ /*
+ * SRQ number. If the QP is a XRC transport service type, this
+ * filed should be updated by the XRCSRQ; else this field is
+ * configured by the driver. Configured by Driver
+ */
+ u32 srqn : 18;
+ u32 rsvd2 : 4;
+ /*
+ * Receive Queue State.
+ * 0x0: hardware has no access right;0x1: error;0xf: ok.Other: reserved.
+ * 0x0
+ */
+ u32 srq_state : 4;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 state : 4;
+ u32 container_sz : 2;
+ u32 container_en : 1;
+ u32 ep : 3;
+ u32 cos : 3;
+ u32 rq_srqn : 18;
+ u32 rq_srq_en : 1;
+#else
+ u32 rq_srq_en : 1;
+ u32 rq_srqn : 18;
+ u32 cos : 3;
+ u32 ep : 3;
+ u32 container_en : 1;
+ u32 container_sz : 2;
+ u32 state : 4;
+#endif
+ } bs_c;
+
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 16;
+ u32 srq_xrcd : 16;
+#else
+ u32 srq_xrcd : 16;
+ u32 rsvd : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ u32 rsvd_dw4;
+
+ /* DW5 */
+ u32 srq_curt_wqe_gpa_h;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 srq_curt_wqe_gpa_l : 24; /* bit[15:00] */
+ u32 rsvd : 8;
+#else
+ u32 rsvd : 8; /* bit[15:00] */
+ u32 srq_curt_wqe_gpa_l : 24;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 wqe_gpa : 20;
+ u32 gpa_vld : 1; /* bit[15:00] */
+ u32 wqe_gpa_flag : 1;
+ u32 warth_flag : 1;
+ u32 last_op_wqe : 1;
+ u32 link_wqe : 1;
+ u32 rqe_cnt_th : 4;
+ u32 rsvd : 3;
+#else
+ u32 rsvd : 3;
+ u32 rqe_cnt_th : 4;
+ u32 link_wqe : 1;
+ u32 last_op_wqe : 1;
+ u32 warth_flag : 1;
+ u32 wqe_gpa_flag : 1;
+ u32 gpa_vld : 1;
+ u32 wqe_gpa : 20;
+#endif
+ } bs_c;
+ u32 value;
+ } dw6;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 pre_ci : 16; /* bit[15:00] */
+ u32 pi : 16;
+#else
+ u32 pi : 16; /* bit[15:00] */
+ u32 pre_ci : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ /* DW8 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 srq_curt_sge_vld : 1;
+ u32 srq_curt_sge_idx : 3;
+ u32 srq_curt_sge_lkey : 28; /* bit[27:00] */
+#else
+ u32 srq_curt_sge_lkey : 28; /* bit[27:00] */
+ u32 srq_curt_sge_idx : 3;
+ u32 srq_curt_sge_vld : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw8;
+
+ /* DW9~10 */
+ union {
+ u64 srq_curt_sge_va; /* lo:bit[31:00],hi:bit[63:32] */
+ struct {
+ u32 srq_curt_sge_va_hi;
+ u32 srq_curt_sge_va_lo;
+ } dw9;
+ };
+
+ /* DW11 */
+ u32 srq_curt_sge_remain_len; /* bit[31:00] */
+
+ /* DW12 */
+ u32 srq_curt_sge_dbuff_gpa_h; /* bit[63:32] */
+
+ /* DW13 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 srq_curt_sge_dbuff_gpa_l : 20;
+ u32 srq_curt_sge_dbuff_gpa_vld : 1;
+ u32 srq_curt_sge_dsgl : 1;
+ u32 srq_curt_sge_used : 1;
+ u32 srq_curt_sge_last : 1;
+ u32 rsvd : 8;
+#else
+ u32 rsvd : 8;
+ u32 srq_curt_sge_last : 1;
+ u32 srq_curt_sge_used : 1;
+ u32 srq_curt_sge_dsgl : 1;
+ u32 srq_curt_sge_dbuff_gpa_vld : 1;
+ u32 srq_curt_sge_dbuff_gpa_l : 20; /* bit[31:12] */
+#endif
+ } bs;
+ u32 value;
+ } dw13;
+
+ /* DW14 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 srq_prefetch_thread_num : 2;
+ u32 srq_mtt_prefetch_cline_num : 4;
+ u32 srq_mtt_prefetch_cline_ptr : 6;
+ u32 srq_mtt_prefetch_finish : 1;
+ u32 srq_mtt_prefetch_sge_idx : 3;
+ u32 rsvd : 16;
+#else
+ u32 rsvd : 16;
+ u32 srq_mtt_prefetch_sge_idx : 3;
+ u32 srq_mtt_prefetch_finish : 1;
+ u32 srq_mtt_prefetch_cline_ptr : 6;
+ u32 srq_mtt_prefetch_cline_num : 4;
+ u32 srq_prefetch_thread_num : 2;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 prefetch_thread_num : 2;
+ u32 mtt_page_size : 4;
+ u32 rsvd1 : 10;
+ u32 xrcd : 16;
+#else
+ u32 xrcd : 16;
+ u32 rsvd1 : 10;
+ u32 mtt_page_size : 4;
+ u32 prefetch_thread_num : 2;
+#endif
+ } bs_c;
+
+ u32 value;
+ } dw14;
+
+ /* DW15 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd2 : 11;
+ u32 srq_mtt_prefetch_maxlen1 : 2;
+ u32 rsvd1 : 17;
+ u32 srq_load_mtt : 1;
+ u32 srq_load_dbuff : 1;
+#else
+ u32 srq_load_dbuff : 1;
+ u32 srq_load_mtt : 1;
+ u32 rsvd1 : 17;
+ u32 srq_mtt_prefetch_maxlen1 : 2;
+ u32 rsvd2 : 11;
+#endif
+ } bs;
+
+ u32 value;
+ } dw15;
+};
+
+/* Queue Pair Common Context Format */
+struct chip_seg_qpcc {
+ /* DW0~1 */
+ union {
+ /* hi[63:32],lo[31:03],sq_rq_gpa_sign[02:00] */
+ u64 sq_rq_l0mtt_gpa;
+ struct {
+ u32 sq_rq_l0mtt_gpa_hi;
+ u32 sq_rq_l0mtt_gpa_lo;
+ } dw0;
+ };
+
+ /* DW2~3 */
+ union {
+ /* hi[63:32],lo[31:02],sq_rq_at_hop_num[01:00] */
+ 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; /* at_hop_num: bit[01:00] */
+ } dw2;
+ };
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_base_ci : 5;
+ u32 rsvd : 2;
+ u32 rc_max_size : 3;
+ u32 sq_rq_mtt_page_size : 4;
+ u32 qp_pd : 18;
+#else
+ u32 qp_pd : 18;
+ u32 sq_rq_mtt_page_size : 4;
+ u32 rc_max_size : 3;
+ u32 rsvd : 2;
+ u32 rq_base_ci : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw4;
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rc_entry_size : 2;
+ u32 rc_size : 4;
+ u32 qp_rkey_en : 1;
+ u32 qp_rwe : 1;
+ u32 qp_rae : 1;
+ u32 qp_rre : 1;
+ u32 rsvd : 1;
+ u32 qp_signature : 5;
+ u32 qp_xrcd : 16;
+#else
+ u32 qp_xrcd : 16;
+ u32 qp_signature : 5;
+ u32 rsvd : 1;
+ u32 qp_rre : 1;
+ u32 qp_rae : 1;
+ u32 qp_rwe : 1;
+ u32 qp_rkey_en : 1;
+ /*
+ * RDMARC table size, equals to (2^rc_size)*Entry Size.
+ * 0x0: the depth of table is equal to 1;
+ * 0x1: the depth of table is equal to 2;
+ * 0x2: the depth of table is equal to 4;
+ * ...
+ * 0x7: the depth of table is equal to 128;
+ * Others: reserved.
+ * Configured by Driver
+ */
+ u32 rc_size : 4;
+ /*
+ * Entry size of RDMARC table in bytes is (2^rc_entry_size)*16B.
+ * The minimum size is 32B and the maximum size is 64B;
+ * so the values 0 and 3 are
+ * reserved. Configured by Driver
+ */
+ u32 rc_entry_size : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rc_entry_prefetch_maxnum : 3;
+ u32 rsvd : 5;
+ u32 rc_page_gpa_h : 24;
+#else
+ /*
+ * bit[63:40] Indicates the start GPA of RDMARC table.
+ * The driver needs to allocate
+ * continuous physical address for the RDMARC table.
+ * Configured by Driver
+ */
+ u32 rc_page_gpa_h : 24;
+ u32 rsvd : 5;
+ /*
+ * Maximum number of prefetch Entries for RDMARC table.
+ * 000: prefetch number
+ * equals to zero; Others: prefetch number equals to
+ * (2^(rc_entry_prefetch_maxnum-1)). Configured by Driver
+ */
+ u32 rc_entry_prefetch_maxnum : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ u32 rc_page_gpa_l; /* bit[39:8] */
+};
+
+/* RDMARC Context Format */
+struct chip_seg_rcc {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rc_curt_sge_vld : 1;
+ u32 rsvd : 3;
+ u32 rc_curt_sge_rkey : 28;
+#else
+ /*
+ * bit[27:00] Indicates the R_Key of current SGE.
+ * Using rc_curt_sge_rkey[27:8] to
+ * access the corresponding MPT.0x0
+ */
+ u32 rc_curt_sge_rkey : 28;
+ u32 rsvd : 3;
+ /*
+ * Indicates current SGE information is valid.
+ * The remaining rc_curt_sge_* field are
+ * only valid when the rc_curt_sge_vld is asserted.
+ * 1: SGE is valid;0: SGE is
+ * invalid.
+ */
+ u32 rc_curt_sge_vld : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1~2 */
+ union {
+ u64 rc_curt_sge_va;
+ struct {
+ u32 rc_curt_sge_va_hi;
+ u32 rc_curt_sge_va_lo;
+ } dw1;
+ };
+
+ /* DW3 */
+ /* bit[31:00]Indicates the remaining memory space of current SGE.0x0 */
+ u32 rc_curt_sge_remain_len;
+
+ /* DW4 */
+ u32 rc_curt_sge_dbuff_gpa_h; /* bit[63:32] */
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rc_curt_sge_dbuff_gpa_l : 20; /* bit[31:12] */
+ u32 rc_curt_sge_dbuff_gpa_vld : 1;
+ u32 rc_curt_sge_dsgl : 1;
+ u32 rc_curt_sge_used : 1;
+ u32 dsgl_en : 1;
+ u32 rc_pi : 8;
+#else
+ /*
+ * bit[07:00] The Producer Index (PI) of
+ * RDMARC table (Step: Entry Size).0x0
+ */
+ u32 rc_pi : 8;
+ u32 dsgl_en : 1;
+ u32 rc_curt_sge_used : 1;
+ u32 rc_curt_sge_dsgl : 1;
+ /*
+ * Indicates if the "rc_curt_sge_dbuff_gpa" field is valid.1: it is
+ * valid;0: it is invalid.0x0
+ */
+ u32 rc_curt_sge_dbuff_gpa_vld : 1;
+ u32 rc_curt_sge_dbuff_gpa_l : 20; /* bit[31:12] */
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rc_pd : 18;
+ u32 rc_signature : 3;
+ u32 rsvd : 3;
+ u32 rc_ci : 8;
+#else
+ /*
+ * bit[07:00] The Consumer Index (CI) of
+ * RDMARC table (Step: Entry Size).
+ */
+ u32 rc_ci : 8;
+ u32 rsvd : 3;
+ u32 rc_signature : 3;
+ /*
+ * bit[17:00] Protection Domain. If the QP is a XRC transport
+ * service type, this filed should
+ * be updated by the "srq_pd" in the SRQ context pointed by
+ * XRCSRQ; else this field should
+ * be equal to QCC.rc_pd.0x0
+ */
+ u32 rc_pd : 18;
+#endif
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rc_state : 4;
+ u32 rc_rae : 1;
+ u32 rc_rre : 1;
+ u32 rsvd2 : 1;
+ u32 rc_mtt_prefetch_maxlen : 2;
+ u32 rc_prefetch_thread_num : 2;
+ u32 rc_load_entry : 1;
+ u32 rc_load_mtt : 1;
+ u32 rc_load_dbuff : 1;
+ u32 rc_mtt_prefetch_finish : 1;
+ u32 rc_mtt_prefetch_cline_num : 4;
+ u32 rsvd1 : 5;
+ u32 rc_prefetch_ci : 8;
+#else
+ u32 rc_prefetch_ci : 8;
+ u32 rsvd1 : 5;
+ u32 rc_mtt_prefetch_cline_num : 4;
+ u32 rc_mtt_prefetch_finish : 1;
+ u32 rc_load_dbuff : 1;
+ u32 rc_load_mtt : 1;
+ u32 rc_load_entry : 1;
+ u32 rc_prefetch_thread_num : 2;
+ u32 rc_mtt_prefetch_maxlen : 2;
+ u32 rsvd2 : 1;
+ u32 rc_rre : 1;
+ u32 rc_rae : 1;
+ u32 rc_state : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+};
+
+/* RQ RDMA Write Context */
+struct chip_seg_rrwc {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rrw_curt_sge_vld : 1;
+ u32 rsvd : 3;
+ u32 rrw_curt_sge_rkey : 28;
+#else
+ u32 rrw_curt_sge_rkey : 28; /* bit[27:00] */
+ u32 rsvd : 3; /* bit[30:28] */
+ u32 rrw_curt_sge_vld : 1; /* bit[31] */
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1~2 */
+ union {
+ u64 rrw_curt_sge_va; /* hi:bit[63:32],lo:bit[31:00] */
+ struct {
+ u32 rrw_curt_sge_va_hi;
+ u32 rrw_curt_sge_va_lo;
+ } dw1;
+ };
+
+ /* DW3 */
+ u32 rrw_curt_sge_remain_len; /* bit[31:00] */
+
+ /* DW4 */
+ u32 rrw_curt_sge_dbuff_gpa_h; /* bit[63:32] */
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rrw_curt_sge_dbuff_gpa_l : 20; /* bit[31:12] */
+ u32 rrw_curt_sge_dbuff_gpa_vld : 1;
+ u32 rrw_curt_sge_dsgl : 1;
+ u32 rrw_curt_sge_used : 1;
+ u32 rsvd : 9;
+#else
+ u32 rsvd : 9;
+ u32 rrw_curt_sge_used : 1;
+ u32 rrw_curt_sge_dsgl : 1;
+ u32 rrw_curt_sge_dbuff_gpa_vld : 1;
+ u32 rrw_curt_sge_dbuff_gpa_l : 20; /* bit[31:12] */
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rrw_pd : 18;
+ u32 rrw_signature : 3;
+ u32 rsvd : 11;
+#else
+ u32 rsvd : 11;
+ u32 rrw_signature : 3;
+ u32 rrw_pd : 18;
+
+#endif
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rrw_state : 4;
+ u32 rrw_rwe : 1;
+ u32 rsvd3 : 2;
+ u32 rrw_mtt_prefetch_maxlen : 2;
+ u32 rrw_prefetch_thread_num : 2;
+ u32 rsvd2 : 1;
+ u32 rrw_load_mtt : 1;
+ u32 rrw_load_dbuff : 1;
+ u32 rrw_mtt_prefetch_finish : 1;
+ u32 rrw_mtt_prefetch_cline_num : 4;
+ u32 rsvd1 : 13;
+#else
+ u32 rsvd1 : 13;
+ u32 rrw_mtt_prefetch_cline_num : 4;
+ u32 rrw_mtt_prefetch_finish : 1;
+ u32 rrw_load_dbuff : 1;
+ u32 rrw_load_mtt : 1;
+ u32 rsvd2 : 1;
+ u32 rrw_prefetch_thread_num : 2;
+ u32 rrw_mtt_prefetch_maxlen : 2;
+ u32 rsvd3 : 2;
+ u32 rrw_rwe : 1;
+ u32 rrw_state : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+};
+
+/*
+ *****************************************************************************
+ Data Structure: SQPC
+ Description:
+*****************************************************************************
+*/
+struct chip_seg_sqpc {
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqp_signature : 5;
+ u32 rsvd0 : 14;
+ u32 sqp_ci_on_chip : 1;
+ u32 sqp_wqe_size : 3;
+ u32 sqp_page_size : 4;
+ u32 sqp_size : 5;
+#else
+ u32 sqp_size : 5;
+ u32 sqp_page_size : 4;
+ u32 sqp_wqe_size : 3;
+ u32 sqp_ci_on_chip : 1;
+ u32 rsvd0 : 14;
+ u32 sqp_signature : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqp_so_ro : 2;
+ u32 sqp_dma_attr_idx : 6;
+ u32 rsvd0 : 8;
+ u32 sqp_ci : 16;
+#else
+ u32 sqp_ci : 16;
+ u32 rsvd0 : 8;
+ u32 sqp_dma_attr_idx : 6;
+ u32 sqp_so_ro : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqp_state : 4;
+ u32 rsvd0 : 12;
+ u32 sqp_pi : 16;
+#else
+ u32 sqp_pi : 16;
+ u32 rsvd0 : 12;
+ u32 sqp_state : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqp_wqecnt_lth : 4;
+ u32 sqp_wqecnt_rctl_en : 1;
+ u32 rsvd0 : 15;
+ u32 sqp_load_ci : 1;
+ u32 sqp_load_page_gpa : 1;
+ u32 sqp_wqe_curt_page_vld : 1;
+ u32 sqp_wqe_next_page_vld : 1;
+ u32 sqp_wqe_curt_page_gpa_h : 8;
+#else
+ u32 sqp_wqe_curt_page_gpa_h : 8;
+ u32 sqp_wqe_next_page_vld : 1;
+ u32 sqp_wqe_curt_page_vld : 1;
+ u32 sqp_load_page_gpa : 1;
+ u32 sqp_load_ci : 1;
+ u32 rsvd0 : 15;
+ u32 sqp_wqecnt_rctl_en : 1;
+ u32 sqp_wqecnt_lth : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ u32 sqp_wqe_curt_page_gpa_m;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqp_wqe_curt_page_gpa_l : 12;
+ u32 sqp_wqe_next_page_gpa_h : 20;
+#else
+ u32 sqp_wqe_next_page_gpa_h : 20;
+ u32 sqp_wqe_curt_page_gpa_l : 12;
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ u32 sqp_wqe_next_page_gpa_l;
+
+ u32 rsvd_dw7;
+
+ u32 rsvd_dw8;
+
+ u32 rsvd_dw9;
+
+ u32 rsvd_dw10;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd0 : 16;
+ u32 sqp_prefetch_thread_num : 2;
+ u32 rsvd1 : 10;
+ u32 sqp_mtt_page_size : 4;
+#else
+ u32 sqp_mtt_page_size : 4;
+ u32 rsvd1 : 10;
+ u32 sqp_prefetch_thread_num : 2;
+ u32 rsvd0 : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw11;
+
+ u32 sqp_l0mtt_gpa_h;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqp_l0mtt_gpa_l : 29;
+ u32 sqp_gpa_sign : 3;
+#else
+ u32 sqp_gpa_sign : 3;
+ u32 sqp_l0mtt_gpa_l : 29;
+#endif
+ } bs;
+ u32 value;
+ } dw13;
+
+ u32 sqp_pi_record_gpa_h;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sqp_pi_record_gpa_l : 30;
+ u32 sqp_at_hop_num : 2;
+#else
+ u32 sqp_at_hop_num : 2;
+ u32 sqp_pi_record_gpa_l : 30;
+#endif
+ } bs;
+ u32 value;
+ } dw15;
+};
+
+/* Queue Pair Context */
+struct qpc_chip_seg {
+ /* RQ RDMA Write Context (32B) */
+ struct chip_seg_rrwc rrwc;
+ /* RDMARDC Context (32B) */
+ struct chip_seg_rcc rcc;
+
+ /* Send Queue Context (64B) */
+ struct chip_seg_sqc sqc;
+ /* Send Queue ACK Context (64B) */
+ struct chip_seg_sqac sqac;
+ union {
+ /* Receive Queue Context (64B) */
+ struct chip_seg_rqc rqc;
+ /* RQC Shared Receive Queue Mode(64B) */
+ struct chip_seg_srqc srqc;
+ };
+
+ /* Queue Pair Common Context (32B) */
+ struct chip_seg_qpcc qpcc;
+};
+
+/* Timer Section(32B) */
+struct qpc_timer_seg {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd3 : 1;
+ /*
+ * Indicate how many timers this timer section
+ * supports:0:rsvd,X:support up to X timers
+ */
+ u32 tss_timer_num : 3;
+ /*
+ * Lock flag indicates whether this timer
+ * section is locked by one API or not
+ * 1: locked 0: unlock
+ */
+ u32 tss_lock_flag : 1;
+ /*
+ * Modify flag indicates whether this timer section
+ * has been modified by other API
+ * without lock or not. 1: has been modified,0: has not been modified
+ */
+ u32 tss_modify_flag : 1;
+ u32 rsvd2 : 1;
+ /*
+ * close flag indicates this connection needs to close
+ * and this XID context will be
+ * de-allocated by control plane; 0: not close,1:
+ * close,this timer section will be
+ * picked off from timer wheel and issue a special
+ * time-out API to tell ucode this
+ * context resource can be de-allocated.
+ */
+ u32 tss_close_flag : 1;
+ u32 rsvd1 : 3;
+ u32 rsvd0 : 2;
+ /*
+ * Timer link valid,
+ * 1: this timer section is hung in timing wheel
+ * 0: this timer section is not hung in any timing wheel
+ */
+ u32 tlwi_lv : 1;
+ /* indicate which timer is hung in timing wheel */
+ u32 tlwi_timer_id : 3;
+ /* indicate which timing wheel this timer section is hung in */
+ u32 tlwi_wheel_id : 3;
+ /* indicate which fire spoke this timer section is hung in */
+ u32 tlwi_link_spoke : 12;
+#else
+ u32 tlwi_link_spoke : 12;
+ u32 tlwi_wheel_id : 3;
+ u32 tlwi_timer_id : 3;
+ u32 tlwi_lv : 1;
+ u32 rsvd0 : 2;
+ u32 rsvd1 : 3;
+
+ u32 tss_cl : 1;
+ u32 rsvd2 : 1;
+ u32 tss_modify_flag : 1;
+ u32 tss_lock_flag : 1;
+ u32 tss_timer_num : 3;
+ u32 rsvd3 : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ /*
+ * Previous link pointer, data structure is referred
+ * to timer pointer data structure
+ */
+ u32 pre_link_ptr0;
+
+ /* DW2 */
+ u32 pre_link_ptr1;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 pre_link_ptr : 8;
+ u32 next_link_ptr : 24;
+#else
+ u32 next_link_ptr : 24;
+ u32 pre_link_ptr : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ /*
+ * Next link pointer, data structure is referred
+ * to timer pointer data structure
+ */
+ u32 next_link_ptr1;
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 next_link_ptr : 16;
+ u32 rsvd : 16;
+#else
+ u32 rsvd : 16;
+ u32 next_link_ptr : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ u32 ts_rsvd[2]; /* reserve 2DW */
+};
+
+union ucode_rq_last {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_last_optype : 1;
+ u32 rq_last_opcode : 1;
+ u32 rsvd : 1;
+ u32 atomic_aloc_fail : 1;
+ u32 comm_est : 1;
+ u32 rnr_state : 1;
+ u32 err_state : 1;
+ u32 rq_ready_n : 1;
+ u32 last_msn : 24;
+#else
+ u32 last_msn : 24;
+ u32 rq_ready_n : 1;
+ u32 err_state : 1;
+ u32 rnr_state : 1;
+ u32 comm_est : 1;
+ u32 atomic_aloc_fail : 1;
+ u32 rsvd : 1;
+ u32 rq_last_opcode : 1;
+ u32 rq_last_optype : 1;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_last_op : 2;
+ u32 rsv_com : 30;
+#else
+ u32 rsv_com : 30;
+ u32 rq_last_op : 2;
+#endif
+ } bs1;
+
+ u32 value;
+};
+
+/* * sq ack ctx */
+struct ucode_sq_ack_ctx {
+ /* DW12 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 time_interval : 6;
+ u32 timestamp : 26;
+#else
+ u32 timestamp : 26;
+ u32 time_interval : 6; // timer update interval
+#endif
+ } bs;
+ u32 value;
+ } dw12;
+
+ /* DW13 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 last_md_nrcv : 1;
+ u32 nof_sw : 1;
+ u32 rx_port : 3;
+ u32 credit_nlimit : 1;
+ u32 rsvd : 2;
+ u32 lsn : 24;
+#else
+ u32 lsn : 24;
+ u32 rsvd : 2;
+ u32 credit_nlimit : 1;
+ u32 rx_port : 3;
+ u32 nof_sw : 1;
+ u32 last_md_nrcv : 1; // last metadata flag in dif
+#endif
+ } bs;
+ u32 value;
+ } dw13;
+
+ /* DW14 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 timer_type : 1;
+ u32 timer_en : 1;
+ u32 rnr_retry_cnt : 3;
+ u32 retry_cnt : 3;
+ u32 sq_rcv_psn : 24;
+#else
+ u32 sq_rcv_psn : 24;
+ u32 retry_cnt : 3;
+ u32 rnr_retry_cnt : 3;
+ u32 timer_en : 1;
+ u32 timer_type : 1;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsv_com : 2;
+ u32 retry_reset : 6;
+ u32 rsv_com1 : 24;
+#else
+ u32 rsv_com1 : 24;
+ u32 retry_reset : 6;
+ u32 rsv_com : 2;
+#endif
+ } bs1;
+ u32 value;
+ } dw14;
+
+ /* DW15 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 next_rdat : 1;
+ u32 sq_db : 1;
+ u32 rnr_state : 1;
+ u32 retry_state : 1;
+ u32 rsvd : 2;
+ u32 err_state : 1;
+ u32 sqa_ready_n : 1;
+ u32 sq_rcv_msn : 24;
+#else
+ u32 sq_rcv_msn : 24;
+ u32 sqa_ready_n : 1;
+ u32 err_state : 1;
+ u32 rsvd : 2;
+ u32 retry_state : 1;
+ u32 rnr_state : 1;
+ u32 sq_db : 1;
+ u32 next_rdat : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw15;
+
+ /* DW16 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sra_ack_cnt : 8;
+ u32 wqe_first_psn : 24;
+#else
+ u32 wqe_first_psn : 24;
+ u32 sra_ack_cnt : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw16;
+
+ /* DW17 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 lcn : 8;
+ u32 max_fwd_psn : 24;
+#else
+ u32 max_fwd_psn : 24;
+ u32 lcn : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw18;
+
+ /* DW18 */
+ u32 sq_rcv_len;
+
+ /* DW19 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 18;
+ u32 task_tag : 14;
+#else
+ u32 task_tag : 14;
+ u32 rsvd : 18;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 wqe2host_ci : 8;
+ u32 last_nak_psn : 24;
+#else
+ u32 last_nak_psn : 24;
+ u32 wqe2host_ci : 8;
+#endif
+ } nofaa;
+ u32 value;
+ } dw17;
+};
+
+struct ucode_sq_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sra_cnt : 8;
+ u32 next_send_psn : 24;
+#else
+ /*
+ * Initial value of the driver in BTH Packet
+ * Sequence Number(initial)RTR2RTS mode
+ */
+ u32 next_send_psn : 24;
+ u32 sra_cnt : 8; /* Initiator depth count value */
+#endif
+ } bs;
+ u32 value;
+ } dw8;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 lcn : 8;
+ u32 ssn : 24;
+#else
+ u32 ssn : 24;
+ u32 lcn : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw9;
+
+ /* DW2 */
+ u32 send_left_len;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 17;
+ u32 last_md_nst : 1;
+ u32 task_tag : 14;
+#else
+ u32 task_tag : 14;
+ u32 last_md_nst : 1;
+ u32 rsvd : 17;
+#endif
+ } dif;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 10;
+ u32 dci_state : 2;
+ u32 drctn : 20;
+#else
+ u32 drctn : 20;
+ u32 dci_state : 2;
+ u32 rsvd : 10;
+#endif
+ } drc;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sticky : 1;
+ u32 work_queue : 2;
+ u32 wqe2host_pi : 8;
+ u32 rsvd : 21;
+#else
+ u32 rsvd : 21;
+ u32 wqe2host_pi : 8;
+ u32 work_queue : 2;
+ u32 sticky : 1;
+#endif
+ } nofaa;
+ u8 vbs_sq[4];
+ u32 value;
+ } dw11;
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sync : 1;
+ u32 credit_ignore : 1;
+ u32 err_state : 1;
+ u32 sq_ready_n : 1;
+ u32 sq_flush_wait : 1;
+ u32 port_err : 1;
+ u32 ud_last_time : 26;
+#else
+ u32 ud_last_time : 26;
+ u32 port_err : 1;
+ u32 sq_flush_wait : 1;
+ u32 sq_ready_n : 1;
+ u32 err_state : 1;
+ u32 credit_ignore : 1;
+ u32 sync : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw12;
+
+ struct ucode_sq_ack_ctx ack_ctx;
+};
+
+/* * rq ack ctx */
+struct ucode_rq_ack_ctx {
+ /* DW24 */
+ u32 rq_rsp_left;
+
+ /* DW25 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rra_ack_cnt : 8;
+ u32 next_ack_psn : 24;
+#else
+ u32 next_ack_psn : 24;
+ u32 rra_ack_cnt : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw25;
+
+ /* DW26 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rqa_last_optype : 1;
+ u32 port_err : 1;
+ u32 nxt_rdat : 1;
+ u32 repeat_flag : 1;
+ u32 nak_rsp : 1;
+ u32 err_state : 1;
+ u32 rqa_ready_n : 1;
+ u32 remote_db : 1;
+ u32 last_ackpsn_low : 8;
+ u32 atomic_aloc_fail : 1;
+ u32 rq_flush_wait : 1;
+ u32 last_wqe_reached : 1;
+ u32 rq_recv_psn_cnt : 5;
+ u32 syndrome : 8;
+#else
+ u32 syndrome : 8;
+ u32 rq_recv_psn_cnt : 5;
+ u32 last_wqe_reached : 1;
+ u32 rq_flush_wait : 1;
+ u32 atomic_aloc_fail : 1;
+ u32 last_ackpsn_low : 8;
+ u32 remote_db : 1;
+ u32 rqa_ready_n : 1;
+ u32 err_state : 1;
+ u32 nak_rsp : 1;
+ u32 repeat_flag : 1;
+ u32 nxt_rdat : 1;
+ u32 port_err : 1;
+ u32 rqa_last_optype : 1;
+#endif
+ } bs;
+
+ u32 value;
+ } dw26;
+
+ /* DW27 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 1;
+ u32 credit : 7;
+ u32 msn : 24;
+#else
+ u32 msn : 24;
+ u32 credit : 7;
+ u32 rsvd : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw27;
+
+ /* DW28 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 32;
+#else
+ u32 rsvd : 32;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd0 : 3;
+ u32 back_len : 13;
+ u32 last_md_nst : 1;
+ u32 rsvd1 : 1;
+ u32 task_tag : 14;
+#else
+ u32 task_tag : 14;
+ u32 rsvd1 : 1;
+ u32 last_md_nst : 1;
+ u32 back_len : 13;
+ u32 rsvd0 : 3;
+#endif
+ } dif;
+ u32 value;
+ } dw28;
+};
+
+struct ucode_rq_ctx {
+ /* DW20 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rra_cnt : 8;
+ u32 next_rcv_psn : 24;
+#else
+ u32 next_rcv_psn : 24;
+ u32 rra_cnt : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw20;
+
+ /* DW21 */
+ union {
+ u32 rq_rcv_len;
+ } dw21;
+
+ /* DW22 */
+ union ucode_rq_last dw22;
+
+ /* DW23 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 last_md_nrcv : 1;
+ u32 rsvd : 7;
+ u32 mpt_index : 24;
+#else
+ u32 mpt_index : 24;
+ u32 rsvd : 7;
+ u32 last_md_nrcv : 1; // last metadata flag in dif
+#endif
+ } bs;
+ u32 value;
+ } dw23;
+ /* DW24 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 18;
+ u32 task_tag : 14;
+#else
+ u32 task_tag : 14;
+ u32 rsvd : 18;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ctrl_rcv : 2;
+ u32 repeat : 1;
+ u32 rsvd : 29;
+#else
+ u32 rsvd : 29;
+ u32 repeat : 1;
+ u32 ctrl_rcv : 2;
+#endif
+ } nofaa;
+ u32 value;
+ } dw24;
+ /* DW24~27 */
+ struct ucode_rq_ack_ctx ack_ctx;
+};
+
+struct ucode_dcqcn_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cnp_flag : 1;
+ u32 f_cnt : 3;
+ u32 cnp_receive : 1;
+ u32 ai_cnt : 3;
+ u32 reinq_times : 12;
+ u32 rsvd : 2;
+ u32 alpha : 10;
+#else
+ u32 alpha : 10;
+ u32 rsvd : 2;
+ u32 reinq_times : 12;
+ u32 ai_cnt : 3;
+ u32 cnp_receive : 1;
+ u32 f_cnt : 3;
+ u32 cnp_flag : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 token_period : 4;
+ u32 rate_period : 4;
+ u32 cur_rate : 24;
+#else
+ u32 cur_rate : 24;
+ u32 rate_period : 4;
+ u32 token_period : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 target_rate : 24;
+#else
+ u32 target_rate : 24;
+ u32 rsvd : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 token : 24; /* valid token */
+#else
+ u32 token : 24;
+ u32 rsvd : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ u32 rcnp_timestamp; /* last receive cnp */
+ u32 alpha_timestamp; /* last update alpha */
+ u32 rate_timestamp; /* last update rate */
+};
+
+struct ucode_common_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsp_ready_n : 1;
+ u32 req_ready_n : 1;
+ u32 rq_flush : 1;
+ u32 sq_flush : 1;
+ u32 rsvd : 3;
+ u32 ccf_appid : 3;
+ u32 port : 2;
+ /* for user plugin extension */
+ u32 ulp_type : 4;
+ u32 fake : 1;
+ /* Cq overflow Indicates whether WQ CATAS is generated. */
+ u32 cq_ovl_flag : 1;
+ u32 sqd_event : 1;
+ u32 vf_id : 13;
+#else
+ u32 vf_id : 13;
+ u32 sqd_event : 1;
+ /* Cq overflow Indicates whether WQ CATAS is generated. */
+ u32 cq_ovl_flag : 1;
+ u32 fake : 1;
+ u32 ulp_type : 4;
+ u32 port : 2;
+ u32 ccf_appid : 3;
+ u32 rsvd : 3;
+ u32 sq_flush : 1;
+ u32 rq_flush : 1;
+ u32 req_ready_n : 1;
+ u32 rsp_ready_n : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 unit_time : 8;
+ u32 rsvd : 11;
+ u32 dst_vfid : 13;
+#else
+ u32 dst_vfid : 13;
+ u32 rsvd : 11;
+ u32 unit_time : 8;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 14;
+ u32 pd : 18;
+#else
+ u32 pd : 18;
+ u32 rsvd : 14;
+#endif
+ } ud;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 12;
+ u32 drcin : 20;
+#else
+ u32 drcin : 20;
+ u32 rsvd : 12;
+#endif
+ } drct;
+ u32 drci_drc_key_h;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ u32 qkey;
+ u32 drci_drc_key_l;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cnp_tx_filter_ts : 12;
+ u32 rq_cqn : 20;
+#else
+ u32 rq_cqn : 20;
+ u32 cnp_tx_filter_ts : 12;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+};
+
+struct drv_ucode_all_info {
+ /* DW0~DW4 */
+ struct ucode_common_ctx common;
+
+ /* DW5~DW18 */
+ struct ucode_sq_ctx sq_ctx;
+
+ /* DW19~DW27 */
+ struct ucode_rq_ctx rq_ctx;
+};
+
+struct drv_path_info {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 bond_tx_hash_value : 16;
+ u32 dmac_h16 : 16;
+#else
+ u32 dmac_h16 : 16;
+ u32 bond_tx_hash_value : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ u32 dmac_l32;
+
+ /* DW2~5 */
+ u8 dgid[16];
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ext_mtu : 1;
+ u32 ext_md : 1;
+ u32 rcq_lb1 : 1;
+ u32 scq_lb1 : 1;
+ u32 tclass : 8;
+ u32 flow_label : 20;
+#else
+ u32 flow_label : 20; /* GRH flow lable */
+ u32 tclass : 8;
+ u32 scq_lb1 : 1;
+ u32 rcq_lb1 : 1;
+ u32 ext_md : 1;
+ u32 ext_mtu : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sl : 3;
+ u32 loop : 1;
+ u32 udp_src_port : 8;
+ u32 rsvd : 4;
+ u32 base_sgid_n : 1;
+ u32 sgid_index : 7;
+ u32 hoplmt : 8;
+#else
+ u32 hoplmt : 8;
+ u32 sgid_index : 7;
+ u32 base_sgid_n : 1;
+ u32 rsvd : 4;
+ u32 udp_src_port : 8;
+ u32 loop : 1;
+ u32 sl : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+};
+
+/* Driver use segment ,16B */
+struct qpc_drv_seg {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 service_type : 3;
+ u32 fre : 1;
+ u32 state : 4;
+ u32 dest_qp : 24;
+#else
+ /*
+ * Destination QP number, which is extended to 24
+ * bits in consideration of interconnection
+ * with commercial devices.
+ */
+ u32 dest_qp : 24;
+ /*
+ * QP state 0000:RST 0001:INIT 0010:RTR 0011:RTS 0100:SQEr
+ * 0101:SQD(Drained) 0110:ERR
+ * 0111:Draining This field is not modified for the
+ * *1XXX:Reserved driver verbs and is
+ * modified by the microcode based on the command type.
+ */
+ u32 state : 4;
+ /* Indicates whether the local FRPMR is enabled. */
+ u32 fre : 1;
+ /*
+ * Transmission Type
+ * 000:RC
+ * 001:UC
+ * 010:RD
+ * 011 UD
+ * 101:XRC
+ * Other:Reserved
+ */
+ u32 service_type : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rc_flag : 1;
+ u32 dif_en : 1;
+ u32 datagram : 1;
+ u32 local_trans : 1;
+ u32 srq_en : 1;
+ u32 drc : 1;
+ u32 vroce_en : 1;
+ u32 rsvd : 1;
+ u32 xrc_vld : 1;
+ u32 ep : 4;
+ u32 db_cos : 3;
+ u32 host_oqid : 16;
+#else
+ u32 host_oqid : 16;
+ u32 db_cos : 3;
+ u32 ep : 4;
+ u32 xrc_vld : 1;
+ u32 rsvd : 1;
+ u32 vroce_en : 1;
+ u32 drc : 1;
+ u32 srq_en : 1;
+ u32 local_trans : 1;
+ u32 datagram : 1;
+ u32 dif_en : 1;
+ u32 rc_flag : 1; /* Reliable service : */
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ack_to : 5;
+ /*
+ * NAK code of RNR. This parameter is mandatory when INIT2RNR and
+ * RTR2RTS\SQE2RTS\SQD2SQD\SQD2RTS is optional.
+ */
+ u32 min_rnr_nak : 5;
+ /*
+ * The maximum number of RNR retransmissions is 7.
+ * The value 7 indicates that the
+ * maximum number of retransmissions is 7,
+ * and the value 0 indicates that the
+ * retransmission is not performed.
+ */
+ u32 rnr_retry_limit : 3;
+ /*
+ * Number of ACK retransmissions. The value 7
+ * indicates unlimited times, and the
+ * value 0 indicates no retransmission.
+ */
+ u32 to_retry_limit : 3;
+ u32 ack_timer_step : 6;
+ u32 rsvd : 2;
+ u32 base_mtu_n : 1;
+ u32 mtu_code : 4;
+ u32 pmtu : 3;
+#else
+ u32 pmtu : 3;
+ u32 mtu_code : 4;
+ u32 base_mtu_n : 1;
+ u32 rsvd : 2;
+ u32 ack_timer_step : 6;
+ u32 to_retry_limit : 3;
+ u32 rnr_retry_limit : 3;
+ u32 min_rnr_nak : 5;
+ u32 ack_to : 5;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 com_rsvd0 : 10;
+ u32 retry_reset : 6;
+ u32 com_rsvd : 16;
+#else
+ u32 com_rsvd : 16;
+ u32 retry_reset : 6;
+ u32 com_rsvd0 : 10;
+#endif
+ } bs1;
+
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /* The maximum value of initiator depth is 128. */
+ u32 sra_max : 3;
+ /* The maximum value of responser resource is 128. */
+ u32 rra_max : 3;
+ /*
+ * Indicates whether the RQ disables the credit.
+ * The SRQ is disabled by default and
+ * must be set to 1.
+ */
+ u32 invalid_credit : 1;
+ u32 ackto_overstep : 1;
+ u32 rsvd : 2;
+ u32 srq_container : 1;
+ u32 dsgl : 1;
+ u32 local_qp : 20; /* Local QP number */
+#else
+ u32 local_qp : 20;
+ u32 dsgl : 1;
+ u32 srq_container : 1;
+ u32 rsvd : 2;
+ u32 ackto_overstep : 1;
+ u32 invalid_credit : 1;
+ u32 rra_max : 3;
+ u32 sra_max : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+};
+
+/* QPC Struct */
+struct qpc_sw_seg {
+ /* driver seg, DW0 ~ DW3 */
+ struct qpc_drv_seg drv_seg;
+
+ /* path seg, DW4 ~ DW11 */
+ struct drv_path_info path_seg;
+
+ /* 112B(DW12~DW39) */
+ struct drv_ucode_all_info ucode_seg;
+
+ /* 32B(DW40~DW47) */
+ struct ucode_ext_ctx ext_seg;
+};
+
+/* QPC Struct */
+struct roce_qp_context {
+ struct qpc_chip_seg chip_seg;
+ struct qpc_timer_seg timer_seg;
+ struct qpc_sw_seg sw_seg;
+};
+
+struct roce_aa_qp_context {
+ struct qpc_chip_seg chip_seg;
+ struct qpc_timer_seg timer_seg;
+ struct qpc_sw_seg sw_seg;
+ struct ucode_nofaa_ctx nofaa;
+};
+
+/* *QPC Format end */
+
+/* * SRQC Format start */
+struct roce_srq_context {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 pdn : 18; /* Protection Domain. */
+ u32 lth_pre_en : 1;
+ /*
+ * If set, the producer counter of Shared Receive Queue
+ * is stored in the chip, the counter is absolute value.
+ */
+ u32 pcnt_on_chip : 1;
+ /*
+ * Shared Receive WQE Basic Block (WQEBB) size
+ * in bytes is (2^rq_wqebb_size)*16B.
+ * The minimum size is 32B and the
+ * values 0, 4, 5, 6, 7 are reserved
+ */
+ u32 wqebb_size : 3;
+ /* Page size of SRQ, equals to (2^srq_page_size)*4KB */
+ u32 page_size : 4;
+ /*
+ * Shared Receive Queue size, equals to (2^srq_size)*WQEBB,
+ * the maximum SRQ size is 16K WQEs, so this field doesn't exceed 14.
+ */
+ u32 size : 5;
+#else
+ /*
+ * Shared Receive Queue size, equals to (2^srq_size)*WQEBB,
+ * the maximum SRQ size is 16K WQEs, so this field doesn't exceed 14.
+ */
+ u32 size : 5;
+ /* Page size of SRQ, equals to (2^srq_page_size)*4KB */
+ u32 page_size : 4;
+ /*
+ * Shared Receive WQE Basic Block (WQEBB) size
+ * in bytes is (2^rq_wqebb_size)*16B.
+ * The minimum size is 32B and the
+ * values 0, 4, 5, 6, 7 are reserved
+ */
+ u32 wqebb_size : 3;
+ /*
+ * If set, the producer counter of Shared Receive Queue
+ * is stored in the chip, the counter is absolute value.
+ */
+ u32 pcnt_on_chip : 1;
+ u32 lth_pre_en : 1;
+ u32 pdn : 18; /* Protection Domain. */
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * It specifies the ATTR[1:0] bits in the outbound
+ * PCIe TLP headers of the DMA operation.
+ * This field is only valid when processing SRQ's WQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ */
+ u32 so_ro : 2;
+ /*
+ * It specifies the outbound PCIe TLP header
+ * attribute of the DMA operation.
+ * This filed is only valid when processing SRQ's WQEs.
+ */
+ u32 dma_attr_idx : 6;
+ u32 rkey_en : 1;
+ u32 srq_wqe_check_en : 1;
+ u32 rsvd : 2;
+ /*
+ * Completion Queue to report XRC messages
+ * directed to this SRQ (XRC only)
+ */
+ u32 xrc_cqn : 20;
+#else
+ /*
+ * Completion Queue to report XRC messages
+ * directed to this SRQ (XRC only)
+ */
+ u32 xrc_cqn : 20;
+ u32 rsvd : 2;
+ u32 srq_wqe_check_en : 1;
+ u32 rkey_en : 1;
+ /*
+ * It specifies the outbound PCIe TLP header
+ * attribute of the DMA operation.
+ * This filed is only valid when processing SRQ's WQEs.
+ */
+ u32 dma_attr_idx : 6;
+ /*
+ * It specifies the ATTR[1:0] bits in the outbound
+ * PCIe TLP headers of the DMA operation.
+ * This field is only valid when processing SRQ's WQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ */
+ u32 so_ro : 2;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * It specifies the ATTR[1:0] bits in the outbound
+ * PCIe TLP headers of the DMA operation.
+ * This field is only valid when processing SRQ's WQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ */
+ u32 so_ro : 2;
+ /*
+ * It specifies the outbound PCIe TLP header
+ * attribute of the DMA operation.
+ * his filed is only valid when processing SRQ's WQEs.
+ */
+ u32 dma_attr_idx : 6;
+ u32 rkey_en : 1;
+ u32 xrc_cqn2 : 7;
+ u32 ccnt : 16;
+#else
+ u32 ccnt : 16;
+ u32 xrc_cqn2 : 7;
+ u32 rkey_en : 1;
+ /*
+ * It specifies the outbound PCIe TLP header
+ * attribute of the DMA operation.
+ * This filed is only valid when processing SRQ's WQEs.
+ */
+ u32 dma_attr_idx : 6;
+ /*
+ * It specifies the ATTR[1:0] bits in the outbound
+ * PCIe TLP headers of the DMA operation.
+ * This field is only valid when processing SRQ's WQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ */
+ u32 so_ro : 2;
+#endif
+ } bs_c;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * SRQ status.
+ * 0x0: hardware has no access right;
+ * 0x1: error;
+ * 0xf: ok.
+ * Other: reserved.
+ */
+ u32 state : 4;
+ u32 rsvd2 : 2;
+ u32 container_en : 1;
+ u32 ep : 3;
+ u32 cos : 3;
+ u32 rsvd1 : 1;
+ u32 srqn : 18; /* SRQ number. */
+#else
+ u32 srqn : 18; /* SRQ number. */
+ u32 rsvd1 : 1;
+ u32 cos : 3;
+ u32 ep : 3;
+ u32 container_en : 1;
+ u32 rsvd2 : 2;
+ /*
+ * SRQ status.
+ * 0x0: hardware has no access right;
+ * 0x1: error;
+ * 0xf: ok.
+ * Other: reserved.
+ */
+ u32 state : 4;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * SRQ status.
+ * 0x0: hardware has no access right;
+ * 0x1: error;
+ * 0xf: ok.
+ * Other: reserved.
+ */
+ u32 state : 4;
+ /*
+ * 0:15 normal + 1 link wqe; 1:7 normal + 1 linkwqe
+ * 2:3normal + 1 linkwqe 3:1
+ * normal + 1 linkwqe
+ */
+ u32 container_size : 2;
+ u32 container_en : 1;
+ u32 xrc_cqn1 : 3;
+ u32 warn_th : 4; /* warn thresthod */
+ u32 srqn : 18; /* SRQ number. */
+#else
+ u32 srqn : 18; /* SRQ number. */
+ u32 warn_th : 4;
+ u32 xrc_cqn1 : 3;
+ u32 container_en : 1;
+ /*
+ * 0:15 normal + 1 link wqe; 1:7 normal + 1 linkwqe
+ * 2:3normal + 1 linkwqe 3:1
+ * normal + 1 linkwqe
+ */
+ u32 container_size : 2;
+ /*
+ * SRQ status.
+ * 0x0: hardware has no access right;
+ * 0x1: error;
+ * 0xf: ok.
+ * Other: reserved.
+ */
+ u32 state : 4;
+#endif
+ } bs_c;
+
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * Limit Threshold. If the "srq_lth" is not zero, and the "srq_wqe_cnt"
+ * drops below the "srq_lth" when a WQE is de-queued from the SRQ,
+ * then an SRQ
+ * limit event is fired and the "srq_lth" is set to zero.
+ */
+ u32 lth : 16;
+ /*
+ * The Scalable RC Domain. The received message
+ * can be served only if the XRC
+ * Domain of the transport QP of received message
+ * matches this field.
+ */
+ u32 xrcd : 16;
+#else
+ /*
+ * The Scalable RC Domain. The received message
+ * can be served only if the XRC
+ * Domain of the transport QP of received message
+ * matches this field.
+ */
+ u32 xrcd : 16;
+ /*
+ * Limit Threshold. If the "srq_lth" is not
+ * zero, and the "srq_wqe_cnt"
+ * drops below the "srq_lth" when a WQE is
+ * de-queued from the SRQ, then an SRQ
+ * limit event is fired and the "srq_lth" is set to zero.
+ */
+ u32 lth : 16;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /* Limit Threshold. If the "srq_lth" is not zero,
+ * and the "srq_wqe_cnt"
+ * drops below the "srq_lth" when a WQE is de-queued from the
+ * SRQ, then an SRQ
+ * limit event is fired and the "srq_lth" is set to zero.
+ */
+ u32 head_index : 16;
+ /*
+ * The Scalable RC Domain. The received
+ * message can be served only if the XRC
+ * Domain of the transport QP of received
+ * message matches this field.
+ */
+ u32 pcnt : 16;
+#else
+ /*
+ * The Scalable RC Domain. The received message
+ * can be served only if the XRC
+ * Domain of the transport QP of
+ * received message matches this field.
+ */
+ u32 pcnt : 16;
+ /*
+ * Limit Threshold. If the "srq_lth" is
+ * not zero, and the "srq_wqe_cnt"
+ * drops below the "srq_lth" when a WQE is
+ * de-queued from the SRQ, then an SRQ
+ * limit event is fired and the "srq_lth" is set to zero.
+ */
+ u32 head_index : 16;
+#endif
+ } bs_c;
+
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * A 16-bit counter incremented for
+ * each WQE posted to the SRQ.
+ */
+ u32 pcnt : 16;
+ u32 ccnt : 16; /* WQE count on the SRQ. */
+#else
+ u32 ccnt : 16; /* WQE count on the SRQ. */
+ /*
+ * A 16-bit counter incremented for
+ * each WQE posted to the SRQ.
+ */
+ u32 pcnt : 16;
+#endif
+ } bs;
+
+ u32 head_gpa;
+
+ u32 value;
+ } dw4;
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 wqe_prefetch_ccnt : 16;
+ /*
+ * The current WQE index; uses this field to
+ * get the corresponding WQE from SRQ.
+ */
+ u32 next_wqe_idx : 16;
+#else
+ /*
+ * The current WQE index; uses this field
+ * to get the corresponding WQE from SRQ.
+ */
+ u32 next_wqe_idx : 16;
+ u32 wqe_prefetch_ccnt : 16;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 head_gpa : 20;
+ u32 rsvd : 1;
+ u32 pcnt_on_chip : 1;
+ u32 xrc_cqn0 : 10;
+#else
+ u32 xrc_cqn0 : 10;
+ u32 pcnt_on_chip : 1;
+ u32 rsvd : 1;
+ u32 head_gpa : 20;
+#endif
+ } bs_c;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 head_gpa : 24;
+ u32 rsvd : 1;
+ u32 pcnt_on_chip : 1;
+ /*
+ * The current WQE index; uses this field to
+ * get the corresponding WQE from SRQ.
+ */
+ u32 resd : 6;
+#else
+ u32 resd : 6;
+ u32 pcnt_on_chip : 1;
+ /*
+ * The current WQE index; uses this field to
+ * get the corresponding WQE from SRQ.
+ */
+ u32 rsvd : 1;
+ u32 head_gpa : 24;
+#endif
+ } bs_osd;
+
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ union {
+ u32 next_wqe_gpa; /* bit[63:32] */
+ u32 pcnt_record_gpa_h; /* bit[63:32] */
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 next_wqe_gpa : 20;
+ u32 next_wqe_gpa_vld : 1;
+ u32 load_wqe_gpa : 1;
+ u32 load_pcnt : 1;
+ u32 rsvd : 4;
+ u32 wqecnt_lth : 4;
+ u32 wqecnt_ctrl_en : 1;
+#else
+ u32 wqecnt_ctrl_en : 1;
+ u32 wqecnt_lth : 4;
+ u32 rsvd : 4;
+ u32 load_pcnt : 1;
+ u32 load_wqe_gpa : 1;
+ u32 next_wqe_gpa_vld : 1;
+ u32 next_wqe_gpa : 20;
+
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 pcnt_record_gpa_l : 30;
+ u32 rsvd : 2;
+#else
+ u32 rsvd : 30;
+ u32 pcnt_record_gpa_l : 2;
+#endif
+ } bs_c;
+ u32 value;
+ } dw7;
+
+ /* DW8~9 */
+ union {
+ /*
+ * The GPA of Layer 0 MTT. It may point to the SRQ's buffer directly.
+ * low 3bits srq_gpa_sign
+ */
+ u64 l0mtt_gpa;
+ struct {
+ u32 l0mtt_gpa_hi;
+ u32 l0mtt_gpa_lo;
+ } dw8;
+ };
+
+ /* DW10~11 */
+ union {
+ /*
+ * bit[63:2]:The GPA of stored producer counters of Shared Receive Queue.
+ * bit[1:0]: Address translation hop numbers.
+ * 0x0: the "srq_l0mtt_gpa" points to the buffer of SRQ directly.
+ * 0x1: it need to perform one hop address translation to get the
+ * buffer's address of SRQ; 0x2: there is two hop address translation to get
+ * the buffer's address of SRQ; 0x3: reserved.
+ */
+ u64 pcnt_record_gpa_at_hop_num;
+ struct {
+ u32 pcnt_record_gpa_hi;
+ /* bit[1:0]: Address translation hop numbers. */
+ u32 pcnt_record_gpa_lo_at_hop_num;
+ } dw10;
+
+ struct {
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 16;
+ u32 xrcd : 16;
+#else
+ u32 xrcd : 16;
+ u32 rsvd : 16;
+#endif
+ } bs;
+
+ u32 value;
+ } dw10;
+
+ u32 dw11;
+ } dw10_container;
+ };
+
+ /* DW12 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * The hardware clear it to zero when performing
+ * a SRQ PCnt updating, and driver
+ * set it to one to indicate the hardware can performing SRQ PCnt updating.
+ */
+ u32 wqecnt_rctl : 1;
+ u32 rsvd3 : 7;
+ /*
+ * Maximum number of prefetch WQEBBs for SRQ.
+ * 000: prefetch number equals to zero;
+ * Others: prefetch number equals to (2^srq_wqe_prefetch_maxnum).
+ */
+ u32 wqe_prefetch_max_num : 3;
+ /*
+ * Minimum number of prefetch WQEBBs for SRQ.
+ * 000: prefetch number equals to zero;
+ * Others: prefetch number equals to (2^(srq_wqe_prefetch_minnum-1)).
+ */
+ u32 wqe_prefetch_min_num : 3;
+ /*
+ * Maximum length of prefetch MTTs for SRQ.
+ * 000: prefetch length equals to zero;
+ * Others: prefetch length equals to
+ * (2^(srq_mtt_prefetch_maxlen-1)*1KB).
+ */
+ u32 wqe_cache_thd_sel : 2;
+ u32 mtt_prefetch_maxlen : 2;
+ u32 rsvd2 : 5;
+ /* Page size of MTT for SRQ, equals to (2^srq_mtt_page_size)*4KB. */
+ u32 mtt_page_size : 4;
+ u32 rsvd1 : 4;
+ u32 load_wqe : 1;
+#else
+ u32 load_wqe : 1;
+ u32 rsvd1 : 4;
+ /* Page size of MTT for SRQ, equals to (2^srq_mtt_page_size)*4KB. */
+ u32 mtt_page_size : 4;
+ u32 rsvd2 : 5;
+ u32 mtt_prefetch_maxlen : 2;
+ u32 wqe_cache_thd_sel : 2;
+ /*
+ * Minimum number of prefetch WQEBBs for SRQ.
+ * 000: prefetch number equals to zero;
+ * Others: prefetch number equals to (2^(srq_wqe_prefetch_minnum-1)).
+ */
+ u32 wqe_prefetch_min_num : 3;
+ /*
+ * Maximum number of prefetch WQEBBs for SRQ.
+ * 000: prefetch number equals to zero;
+ * Others: prefetch number equals to (2^srq_wqe_prefetch_maxnum).
+ */
+ u32 wqe_prefetch_max_num : 3;
+ u32 rsvd3 : 7;
+ /*
+ * The hardware clear it to zero when performing
+ * a SRQ PCnt updating, and driver
+ * set it to one to indicate the hardware can performing SRQ PCnt updating.
+ */
+ u32 wqecnt_rctl : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw12;
+
+ /* DW13 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 16;
+ u32 wqe_prefetch_idx : 16; /* The WQE index of prefetch MTTs operation. */
+#else
+ u32 wqe_prefetch_idx : 16; /* The WQE index of prefetch MTTs operation. */
+ u32 rsvd : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw13;
+
+ /* DW14 */
+ u32 srq_prefetch_wqe_gpa_hi; /* bit[63:32] */
+
+ /* DW15 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 mtt_prefetch_wqe_gpa_lo : 20;
+ u32 srq_prefetch_wqe_gpa_vld : 1;
+ u32 rsvd : 9;
+ u32 srq_prefetch_thread_num : 2;
+#else
+ u32 srq_prefetch_thread_num : 2;
+ u32 rsvd : 9;
+ u32 srq_prefetch_wqe_gpa_vld : 1;
+ u32 mtt_prefetch_wqe_gpa_lo : 20; /* bit[31:12] */
+#endif
+ } bs;
+ u32 value;
+ } dw15;
+};
+
+/* *SRQC Format end */
+
+struct roce_ssgl_mpt_context {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+ u32 mtt_layer_num : 3; /* Mtt level */
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 rsvd2 : 4;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /*
+ * The value 1 indicates that the local
+ * write permission is supported.
+ */
+ u32 access_lw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ /* 1: The remote write permission is supported. */
+ u32 access_rw : 1;
+ /*
+ * The value 1 indicates that the remote
+ * Atomic permission is supported.
+ */
+ u32 access_ra : 1;
+ u32 bpd : 1; /* 1: Bound to pd */
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 dif_mode : 1;
+ u32 rkey : 1;
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ /* Mr or mw. The value 1 indicates MR, and the value 0 indicates MW. */
+ u32 r_w : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ /* Whether the mr supports the binding of the mw */
+ u32 access_bind : 1;
+#else
+ /* Whether the mr supports the binding of the mw */
+ u32 access_bind : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ u32 r_w : 1; /* Mr or mw */
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ u32 rkey : 1;
+ u32 dif_mode : 1;
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 bpd : 1; /* 1: Bound to pd */
+ /*
+ * The value 1 indicates that the remote
+ * Atomic permission is supported.
+ */
+ u32 access_ra : 1;
+ /* 1: The remote write permission is supported. */
+ u32 access_rw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ u32 rsvd2 : 4;
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 mtt_layer_num : 3; /* Number of mtt levels */
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 so_ro : 2; /* Dma sequence preserving flag */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 ep : 3;
+ u32 qpn : 20; /* Qp bound to the mw. */
+#else
+ u32 qpn : 20; /* Qp bound to mw */
+ u32 ep : 3;
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 so_ro : 2; /* Dma order-preserving flag */
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+ u32 rsvd : 1;
+ u32 cos : 3;
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 pdn : 18; /* Pd bound to mr or mw */
+#else
+ u32 pdn : 18; /* Pd bound to mr or mw */
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 cos : 3;
+ u32 rsvd : 1;
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 mkey : 8; /* The index is not included. */
+ u32 sgl_mode : 1; /* If set, indicates this MPT is double SGL type. */
+ u32 page_mode : 1;
+ u32 fbo : 22;
+#else
+ u32 fbo : 22;
+ u32 page_mode : 1;
+ u32 sgl_mode : 1; /* If set, indicates this MPT is double SGL type. */
+ u32 mkey : 8; /* The index is not included. */
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4~5 */
+ union {
+ u64 iova; /* Start address of mr or mw */
+ struct {
+ u32 iova_hi; /* Upper 32 bits of the start address of mr or mw */
+ u32 iova_lo; /* Lower 32 bits of the start address of mr or mw */
+ } dw4;
+ };
+
+ /* DW6~7 */
+ union {
+ u64 length; /* Length of mr or mw */
+ struct {
+ u32 length_hi; /* Length of mr or mw */
+ u32 length_lo; /* Length of mr or mw */
+ } dw6;
+ };
+
+ /* DW8~9 */
+ union {
+ u64 mtt_base_addr; /* Mtt base address (pa) */
+ struct {
+ u32 mtt_base_addr_hi; /* Mtt base address (pa) upper 32 bits */
+ u32 mtt_base_addr_lo; /* Lower 32 bits of mtt base address (pa) */
+ } dw8;
+ };
+
+ /* DW10 */
+ union {
+ u32 mr_mkey; /* This parameter is valid for MW. */
+ u32 mw_cnt; /* This parameter is valid when the MR is used. */
+ u32 task_id;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 9;
+ u32 ext_mtu : 1;
+ u32 tp2_fst_sct : 1;
+ u32 smd_size : 1; /* metadata size[0]:0 is 512, 1'b1 is 4096 */
+ u32 smd_type : 4; /* smd_type[3:2]:reserved. */
+ u32 task_id : 16; /* This parameter is valid when SIG MR. */
+#else
+ u32 task_id : 16; /* This parameter is valid when SIG MR. */
+ /*
+ * This is sector metadata type: 2b'0x is 8B;
+ * 2b'10 is [8B+56B];2b'11 is [56B+8B]
+ */
+ u32 smd_type : 4;
+ u32 smd_size : 1; /* metadata size[0]:0 is 512, 1'b1 is 4096 */
+ u32 tp2_fst_sct : 1;
+ u32 ext_mtu : 1;
+ u32 rsvd : 9;
+#endif
+ } dw10;
+ };
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 w_cmp_app_tag_msk : 16;
+ u32 m_cmp_app_tag_msk : 16;
+#else
+ u32 m_cmp_app_tag_msk : 16;
+ u32 w_cmp_app_tag_msk : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw11;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 w_app_tag : 16;
+ u32 m_app_tag : 16;
+#else
+ u32 m_app_tag : 16;
+ u32 w_app_tag : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw12;
+
+ u32 m_ref_tag;
+ u32 w_ref_tag;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 w_dif_en : 1; /* Dif enable in the wire domain */
+ u32 rx_w_dif_type : 2; /* type 0 ~ 3,def:1 */
+ u32 rx_m_dif_type : 2; /* type 0 ~ 3,def:1 */
+ u32 rx_dif_en : 1; /* IO_1ST_SCT 1 */
+ u32 w_app_esc : 1;
+ u32 w_ref_esc : 1;
+
+ u32 m_dif_en : 1; /* mem */
+ u32 tx_m_dif_type : 2; /* type 0 ~ 3,def:1 */
+ u32 tx_w_dif_type : 2; /* type 0 ~ 3,def:1 */
+ u32 tx_dif_en : 1; /* IO_1ST_SCT 1 */
+ u32 m_app_esc : 1;
+ u32 m_ref_esc : 1;
+
+ u32 grd_verify : 1; /* Indicates whether to verify the guard. */
+ u32 grd_ctrl : 2; /* guard tag ctrl */
+ /* The host memory is CRC(0) or IP CheckSum(1). */
+ u32 m_bg_type : 1;
+ /* Indicates whether the line is CRC(0) or IP CheckSum(1). */
+ u32 w_bg_type : 1;
+ u32 grd_agm_ini_ctl : 3; /* GRD_AGM_INI_CTRL */
+
+ u32 ref_tag_verify : 1; /* Indicates whether to verify the ref_tag. */
+ u32 ref_ctrl : 2; /* ref tag ctrl */
+ u32 m_ref_tag_mode : 1; /* Obtained from mem.dif.ref_remap */
+ u32 w_ref_tag_mode : 1; /* Obtained from wire.dif.ref_remap */
+ u32 app_tag_verify : 1; /* Indicates whether to verify the app_tag. */
+ u32 app_ctrl : 2; /* app tag ctrl */
+#else
+ u32 app_ctrl : 2; /* app tag ctrl */
+ u32 app_tag_verify : 1; /* Indicates whether to verify the app_tag. */
+ u32 w_ref_tag_mode : 1; /* Obtained from wire.dif.ref_remap */
+ u32 m_ref_tag_mode : 1; /* Obtained from mem.dif.ref_remap */
+ u32 ref_ctrl : 2; /* ref tag ctrl */
+ u32 ref_tag_verify : 1; /* Indicates whether to verify the ref_tag. */
+
+ u32 grd_agm_ini_ctl : 3; /* GRD_AGM_INI_CTRL */
+ u32 w_bg_type : 1; /* Is CRC(0) or IP CheckSum(1) on the line? */
+ /* The host memory is CRC(0) or IP CheckSum(1). */
+ u32 m_bg_type : 1;
+ u32 grd_ctrl : 2; /* guard tag ctrl */
+ u32 grd_verify : 1; /* Indicates whether to verify the guard. */
+
+ u32 m_ref_esc : 1;
+ u32 m_app_esc : 1;
+ u32 tx_dif_en : 1; /* IO_1ST_SCT 1 */
+ u32 tx_w_dif_type : 2; /* type 0 ~ 3,def:1 */
+ u32 tx_m_dif_type : 2; /* type 0 ~ 3,def:1 */
+ u32 m_dif_en : 1; /* mem */
+
+ u32 w_ref_esc : 1;
+ u32 w_app_esc : 1;
+ u32 rx_dif_en : 1; /* IO_1ST_SCT 1 */
+ u32 rx_m_dif_type : 2; /* type 0 ~ 3,def:1 */
+ u32 rx_w_dif_type : 2; /* type 0 ~ 3,def:1 */
+ /* Indicates whether dif is enabled in the wire domain. */
+ u32 w_dif_en : 1;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u8 w_dif_ctl;
+ u8 m_dif_ctl;
+ u8 m_grd_ctl;
+ u8 m_ref_ctl;
+#else
+ u8 m_ref_ctl;
+ u8 m_grd_ctl;
+ u8 m_dif_ctl;
+ u8 w_dif_ctl;
+#endif
+ } ctrl;
+ u32 value;
+ } dw15;
+};
+
+struct roce_dsgl_mpt_context {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+ u32 mtt_layer_num : 3; /* Number of mtt levels */
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 signature : 4;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ /* The value 1 indicates that the remote Atomic permission is supported. */
+ u32 access_ra : 1;
+ u32 bpd : 1; /* 1: Bound to pd */
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 dif_mode : 1;
+ u32 rkey : 1;
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ /* Mr or mw. The value 1 indicates MR, and the value 0 indicates MW. */
+ u32 r_w : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ u32 access_bind : 1; /* Whether mr can be bound to mw */
+#else
+ /* Whether the mr supports the binding of the mw */
+ u32 access_bind : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ u32 r_w : 1; /* Mr or mw */
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ u32 rkey : 1;
+ u32 dif_mode : 1;
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 bpd : 1; /* 1: Bound to pd */
+ /*
+ * The value 1 indicates that the remote
+ * Atomic permission is supported.
+ */
+ u32 access_ra : 1;
+ /* 1: The remote write permission is supported. */
+ u32 access_rw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ /*
+ * The value 1 indicates that the local
+ * write permission is supported.
+ */
+ u32 access_lw : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ u32 signature : 4;
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 mtt_layer_num : 3; /* Mtt level */
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 so_ro : 2; /* Dma order-preserving flag */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 ep : 3;
+ u32 qpn : 20; /* Qp bound to mw */
+#else
+ u32 qpn : 20; /* Qp bound to mw */
+ u32 ep : 3;
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 so_ro : 2; /* Dma order-preserving flag */
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+ u32 indirect_mr : 1;
+ u32 cos : 3;
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 pdn : 18; /* Pd bound to mr or mw */
+#else
+ u32 pdn : 18; /* Pd bound to mr or mw */
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 cos : 3;
+ u32 indirect_mr : 1;
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 mkey : 8; /* The index is not included. */
+ u32 sgl_mode : 1; /* If set, indicates this MPT is double SGL type. */
+ u32 page_mode : 1;
+ u32 sectfbo : 22;
+#else
+ u32 sectfbo : 22;
+ u32 page_mode : 1;
+ u32 sgl_mode : 1; /* If set, indicates this MPT is double SGL type. */
+ u32 mkey : 8; /* The index is not included. */
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 4;
+ u32 data_mr_key : 28;
+#else
+ u32 data_mr_key : 28;
+ u32 rsvd : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw4;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 4;
+ u32 mtt_offset : 28;
+#else
+ u32 mtt_offset : 28;
+ u32 rsvd : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6~DW9 */
+ u32 rsvd[4];
+
+ /* DW10 */
+ union {
+ u32 mr_mkey; /* This parameter is valid for MW. */
+ u32 mw_cnt; /* This parameter is valid when the MR is used. */
+ u32 task_id;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 12;
+ u32 smd_type : 4; /* smd_type[3:2]:reserved. */
+ u32 task_id : 16; /* This parameter is valid when SIG MR. */
+#else
+
+ u32 task_id : 16; /* This parameter is valid when SIG MR. */
+ /*
+ * This is sector metadata type: 2b'0x is 8B;
+ * 2b'10 is [8B+56B];2b'11 is [56B+8B]
+ */
+ u32 smd_type : 4;
+ u32 rsvd : 12;
+
+#endif
+ } dw10;
+ };
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 w_cmp_app_tag_msk : 16;
+ u32 m_cmp_app_tag_msk : 16;
+#else
+ u32 m_cmp_app_tag_msk : 16;
+ u32 w_cmp_app_tag_msk : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw11;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 w_app_tag : 16;
+ u32 m_app_tag : 16;
+#else
+ /*
+ * TX: Verify ref tag domain
+ * RX: Insert&replace ref tag domain
+ */
+ u32 m_app_tag : 16;
+
+ /*
+ * TX: Insert&replace ref tag domain
+ * RX: Verify ref tag domain
+ */
+ u32 w_app_tag : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw12;
+
+ /*
+ * TX: Verify ref tag domain
+ * RX: Insert&replace ref tag domain
+ */
+ u32 m_ref_tag;
+
+ /*
+ * TX: Insert&replace ref tag domain
+ * RX: Verify ref tag domain
+ */
+ u32 w_ref_tag;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 w_dif_en : 1; // Wire domain dif enable
+ u32 rx_w_dif_type : 2; // type 0 ~ 3,def:1
+ u32 rx_m_dif_type : 2; // type 0 ~ 3,def:1
+ u32 rx_dif_en : 1; // IO_1ST_SCT 1
+ u32 w_app_esc : 1;
+ u32 w_ref_esc : 1;
+
+ u32 m_dif_en : 1; // mem
+ u32 tx_m_dif_type : 2; // type 0 ~ 3,def:1
+ u32 tx_w_dif_type : 2; // type 0 ~ 3,def:1
+ u32 tx_dif_en : 1; // IO_1ST_SCT 1
+ u32 m_app_esc : 1;
+ u32 m_ref_esc : 1;
+
+ u32 grd_verify : 1; // Indicates whether to verify the guard.
+ u32 grd_ctrl : 2; // guard tag ctrl; ucode
+ u32 m_bg_type : 1; // The host memory is CRC(0) or IP CheckSum(1).
+ // Indicates whether the line is CRC(0) or IP CheckSum(1).
+ u32 w_bg_type : 1;
+ u32 grd_agm_ini_ctl : 3; // GRD_AGM_INI_CTRL
+
+ u32 ref_tag_verify : 1; // Indicates whether to verify the ref_tag.
+ u32 ref_ctrl : 2; // ref tag ctrl; ucode
+ u32 m_ref_tag_mode : 1; // Obtained from mem.dif.ref_remap
+ u32 w_ref_tag_mode : 1; // Obtained from wire.dif.ref_remap
+ u32 app_tag_verify : 1; // Indicates whether to verify the app_tag.
+ u32 app_ctrl : 2; // app tag ctrl; ucode
+#else
+ /* REF APP CTRL segment */
+ u32 app_ctrl : 2; // app tag ctrl
+ u32 app_tag_verify : 1; // Indicates whether to verify the app_tag.
+ u32 w_ref_tag_mode : 1; // Obtained from wire.dif.ref_remap
+ u32 m_ref_tag_mode : 1; // Obtained from mem.dif.ref_remap
+ u32 ref_ctrl : 2; // ref tag ctrl
+ u32 ref_tag_verify : 1; // Indicates whether to verify the ref_tag.
+
+ /* GRD CTRL segment */
+ u32 grd_agm_ini_ctl : 3; // GRD_AGM_INI_CTRL
+ u32 w_bg_type : 1; // Is CRC(0) or IP CheckSum(1) on the line?
+ u32 m_bg_type : 1; // The host memory is CRC(0) or IP CheckSum(1).
+ u32 grd_ctrl : 2; // guard tag ctrl
+ u32 grd_verify : 1; // Indicates whether to verify the guard.
+
+ u32 m_ref_esc : 1;
+ u32 m_app_esc : 1;
+ u32 tx_dif_en : 1; // IO_1ST_SCT 1
+ u32 tx_w_dif_type : 2; // type 0 ~ 3,def:1
+ u32 tx_m_dif_type : 2; // type 0 ~ 3,def:1
+ u32 m_dif_en : 1; // mem
+
+ u32 w_ref_esc : 1;
+ u32 w_app_esc : 1;
+ u32 rx_dif_en : 1; // IO_1ST_SCT 1
+ u32 rx_m_dif_type : 2; // type 0 ~ 3,def:1
+ u32 rx_w_dif_type : 2; // type 0 ~ 3,def:1
+ u32 w_dif_en : 1; // Dif enable in the wire domain
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u8 w_dif_ctl;
+ u8 m_dif_ctl;
+ u8 m_grd_ctl;
+ u8 m_ref_ctl;
+#else
+ u8 m_ref_ctl;
+ u8 m_grd_ctl;
+ u8 m_dif_ctl;
+ u8 w_dif_ctl;
+
+#endif
+ } ctrl;
+ u32 value;
+ } dw15;
+};
+
+struct iw_mpt_context {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+ u32 mtt_layer_num : 3; /* Mtt level */
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 rsvd2 : 4;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /*
+ * The value 1 indicates that the local
+ * write permission is supported.
+ */
+ u32 access_lw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ /*
+ * The value 1 indicates that the remote
+ * Atomic permission is supported.
+ */
+ u32 access_ra : 1;
+ u32 bpd : 1; /* 1: Bound to pd */
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 rsvd1 : 1;
+ u32 rkey : 1;
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ /* Mr or mw. The value 1 indicates MR, and the value 0 indicates MW. */
+ u32 r_w : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ u32 access_bind : 1; /* Can mr be bound to mw? */
+#else
+ /* Whether the mr supports the binding of the mw */
+ u32 access_bind : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ u32 r_w : 1; /* Mr or mw */
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ u32 rkey : 1;
+ u32 rsvd1 : 1;
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 bpd : 1; /* 1: Bound to pd */
+ /*
+ * The value 1 indicates that the remote
+ * Atomic permission is supported.
+ */
+ u32 access_ra : 1;
+ /* 1: The remote write permission is supported. */
+ u32 access_rw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ /*
+ * The value 1 indicates that the local
+ * write permission is supported.
+ */
+ u32 access_lw : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ u32 rsvd2 : 4;
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 mtt_layer_num : 3; /* Number of mtt levels */
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 so_ro : 2; /* Dma order-preserving flag */
+ u32 dma_attr_idx : 6; /* Indicates the dma attribute index. */
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 rsvd : 3;
+ u32 qpn : 20; /* Qp bound to mw */
+#else
+ u32 qpn : 20; /* Qp bound to mw */
+ u32 rsvd : 3;
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 so_ro : 2; /* Dma order-preserving flag */
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+ u32 rsvd : 4;
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 pdn : 18; /* Pd bound to mr or mw */
+#else
+ u32 pdn : 18; /* Pd bound to mr or mw */
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 rsvd : 4;
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 mkey : 8; /* The index is not included. */
+ u32 sgl_mode : 1; /* If set, indicates this MPT is double SGL type. */
+ u32 page_mode : 1;
+ u32 fbo : 22;
+#else
+ u32 fbo : 22;
+ u32 page_mode : 1;
+ u32 sgl_mode : 1; /* If set, indicates this MPT is double SGL type. */
+ u32 mkey : 8; /* The index is not included. */
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4~5 */
+ union {
+ u64 iova; /* Start address of mr or mw */
+
+ struct {
+ u32 iova_hi; /* Upper 32 bits of the start address of mr or mw */
+ u32 iova_lo; /* Lower 32 bits of the start address of mr or mw */
+ } dw4;
+ };
+
+ /* DW6~7 */
+ union {
+ u64 length; /* Length of mr or mw */
+
+ struct {
+ u32 length_hi; /* Length of mr or mw */
+ u32 length_lo; /* Length of mr or mw */
+ } dw6;
+ };
+
+ /* DW8~9 */
+ union {
+ u64 mtt_base_addr; /* Mtt base address (pa) */
+
+ struct {
+ u32 mtt_base_addr_hi; /* Upper 32 bits of the base address (pa) of mtt */
+ u32 mtt_base_addr_lo; /* Lower 32 bits of mtt base address (pa) */
+ } dw8;
+ };
+
+ /* DW10 */
+ union {
+ u32 mr_mkey; /* This parameter is valid for MW. */
+ u32 mw_cnt; /* This parameter is valid when the MR is used. */
+ };
+
+ /* DW11 */
+ u32 mtt_sz; /* This parameter is valid when FRMR. */
+
+ /* DW12 ~ DW13 */
+ u32 rsvd[2];
+
+ /* DW14 */
+ u32 mw_base_addr_hi;
+ u32 mw_base_addr_lo;
+};
+
+/* * MPT Format end */
+
+/* * CQC Format start */
+struct roce_cq_context {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 signature : 5;
+ u32 last_solicited_pi : 9;
+ u32 ceqn_low : 5;
+ u32 ci_on_chip : 1;
+ u32 cqe_size : 3;
+ u32 page_size : 4;
+ u32 size : 5;
+#else
+ /*
+ * Completion Queue size, equals to (2^cq_size)*CQE.
+ * The maximum CQ size is 2^23 CQEs.
+ */
+ u32 size : 5;
+ u32 page_size : 4; /* Page size of CQ, equals to (2^cq_page_size)*4KB. */
+ /*
+ * Completion Queue Entry (CQE) size in bytes is (2^cq_cqe_size)*16B.
+ * The minimum size is 32B and the values 0, 3, 4, 5, 6, 7 are reserved.
+ */
+ u32 cqe_size : 3;
+ /*
+ * If set, the CI of Complete Queue is stored in the chip,
+ * the counter is absolute value.
+ */
+ u32 ci_on_chip : 1;
+ /*
+ * Completion Event Queue, this CQ reports
+ * Completion Events to this CQE (cq_ceqn[04:00])
+ */
+ u32 ceqn_low : 5;
+ u32 last_solicited_pi : 9; /* bit[23:15] */
+ u32 signature : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 so_ro : 2;
+ u32 dma_attr_idx : 6;
+ u32 ci : 24;
+#else
+ /* The CI index of Receive Queue (Step: CQE). */
+ u32 ci : 24;
+ /*
+ * It specifies the outbound PCIe TLP header attribute
+ * of the DMA operation.
+ * This filed is only valid when processing CQ's CQEs.
+ */
+ u32 dma_attr_idx : 6;
+ /*
+ * It specifies the ATTR[1:0] bits in the outbound
+ * PCIe TLP headers of the DMA operation.
+ * This field is only valid when processing CQ's CQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ */
+ u32 so_ro : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 state : 4;
+ u32 rsvd : 1;
+ u32 ceqn_high : 3;
+ u32 pi : 24;
+#else
+ /* The PI index of Completion Queue (Step: CQE) */
+ u32 pi : 24;
+ /*
+ * Completion Event Queue, this CQ reports
+ * Completion Events to this CQE (cq_ceqn[07:05])
+ */
+ u32 ceqn_high : 3;
+ u32 rsvd : 1;
+ /*
+ * CQ status.
+ * 0x0: hardware has no access right;
+ * 0x1: CQ is error;
+ * 0x2: CQ is overflow;
+ * 0xf: ok.
+ * Other: reserved.
+ */
+ u32 state : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cqecnt_lth : 4;
+ u32 cqecnt_rctl_en : 1;
+ u32 last_solicited_pi : 15;
+ u32 load_ci : 1;
+ u32 load_page_gpa : 1;
+ u32 cqe_cur_pg_vld : 1;
+ u32 cqe_next_pg_vld : 1;
+ u32 cqe_cur_pg_gpa_h : 8;
+#else
+ u32 cqe_cur_pg_gpa_h : 8; /* curt_pg_gpa[63:56]bit */
+ /*
+ * Indicates if the "cq_cqe_next_page_gpa" field is valid.
+ * 1: it is valid;
+ * 0: it is invalid.
+ */
+ u32 cqe_next_pg_vld : 1;
+ /*
+ * Indicates if the "cq_cqe_curt_page_gpa" field is valid.
+ * 1: it is valid;
+ * 0: it is invalid.
+ */
+ u32 cqe_cur_pg_vld : 1;
+ /* Indicates the thread is performing a prefetch for GPA of CQE page. */
+ u32 load_page_gpa : 1;
+ u32 load_ci : 1;
+ u32 last_solicited_pi : 15; /* bit[14:00] */
+ u32 cqecnt_rctl_en : 1;
+ u32 cqecnt_lth : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ /*
+ * Indicates the page GPA of current CQ buffer's page pointed by "cq_pi".
+ * curt_pg_gpa[55:24]bit
+ */
+ u32 cqe_curt_pg_gpa_m;
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cqe_curt_pg_gpa_l : 12; /* curt_pg_gpa[23:12]bit */
+ u32 cqe_next_pg_gpa_h : 20; /* next_pg_gpa[63:44]bit */
+#else
+ u32 cqe_next_pg_gpa_h : 20; /* next_pg_gpa[63:44]bit */
+ u32 cqe_curt_pg_gpa_l : 12; /* curt_pg_gpa[23:12]bit */
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ /*
+ * Indicates the page GPA of next CQ buffer's page pointed by "cq_pi".
+ * next_pg_gpa[43:12]bit
+ */
+ u32 cqe_next_pg_gpa_l;
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * Completion Event Moderation counters.
+ * 0x0: interrupt moderation disabled.
+ */
+ u32 max_cnt : 16;
+ /*
+ * Completion Event Moderation timer in microseconds.
+ * 0x0: interrupt moderation disabled.
+ */
+ u32 timeout : 16;
+#else
+ /*
+ * Completion Event Moderation timer in microseconds.
+ * 0x0: interrupt moderation disabled.
+ */
+ u32 timeout : 16;
+ /*
+ * Completion Event Moderation counters.
+ * 0x0: interrupt moderation disabled.
+ */
+ u32 max_cnt : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ /* DW8 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cmd_sn : 2;
+ u32 arm_state : 2;
+ u32 rsvd : 12;
+ u32 cqe_cnt : 16;
+#else
+ u32 cqe_cnt : 16;
+ u32 rsvd : 12;
+ /*
+ * The CQ ARM State machine.
+ * 0x0: idle state;
+ * 0x1: solicited state;
+ * 0x2: next state;
+ * Others: reserved.
+ */
+ u32 arm_state : 2;
+ u32 cmd_sn : 2; /* The last received command sequence number. */
+#endif
+ } bs;
+ u32 value;
+ } dw8;
+
+ /* DW9 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 timer_mode : 1;
+ u32 arm_timer_en : 1;
+ u32 solicited_cqe_en : 1;
+ u32 rsvd : 3;
+ u32 cnt_clear_en : 1;
+ u32 cnt_adjust_en : 1;
+ u32 last_notified_pi : 24; /* The last notified PI of CQ. */
+#else
+ u32 last_notified_pi : 24; /* The last notified PI of CQ. bit[23:00] */
+ u32 cnt_adjust_en : 1;
+ u32 cnt_clear_en : 1;
+ u32 rsvd : 3;
+ u32 solicited_cqe_en : 1;
+ u32 arm_timer_en : 1;
+ u32 timer_mode : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw9;
+
+ /* DW10 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 16;
+ u32 idle_max_count : 16;
+#else
+ u32 idle_max_count : 16;
+ u32 rsvd : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw10;
+
+ /* DW11 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cqecnt_rctl : 1;
+ u32 rsvd3 : 15;
+ u32 prefetch_thread_num : 2;
+ u32 rsvd2 : 6;
+ u32 ceqe_en : 1;
+ u32 arm_ceqe_en : 1;
+ u32 rsvd1 : 2;
+ u32 mtt_page_size : 4;
+#else
+ u32 mtt_page_size : 4;
+ u32 rsvd1 : 2;
+ u32 arm_ceqe_en : 1;
+ u32 ceqe_en : 1;
+ u32 rsvd2 : 6;
+ u32 prefetch_thread_num : 2;
+ u32 rsvd3 : 15;
+ u32 cqecnt_rctl : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw11;
+
+ /* DW12~13 */
+ union {
+ /*
+ * The GPA of Layer 0 MTT. It may point to the CQ's buffer directly.
+ * low 3bits(cq_gpa_sign)
+ */
+ u64 cqc_l0mtt_gpa;
+ struct {
+ u32 cqc_l0mtt_gpa_hi;
+ u32 cqc_l0mtt_gpa_lo;
+ } dw12;
+ };
+
+ /* DW14 */
+ union {
+ /*
+ * The GPA of stored CI of Complete Queue.
+ * Address translation hop numbers.
+ * 0x0: the "cq_l0mtt_gpa" points to the buffer of CQ directly.
+ * 0x1: it need to perform one hop address translation to get the buffer's
+ * address of CQ; 0x2: there is two hop address translation to get the buffer's
+ * address of CQ; 0x3: reserved.
+ */
+ u64 ci_record_gpa_at_hop_num;
+ struct {
+ u32 ci_record_gpa_hi;
+ /* bit[1:0] Address translation hop numbers */
+ u32 ci_record_gpa_lo_at_hop_num;
+ } dw14;
+ };
+
+ /* timer seg info */
+ struct qpc_timer_seg timer_seg;
+
+ u32 rsvd[8]; /* The 32B is reserved, and the entire CQC is aligned with the 128B. */
+};
+/* * CQC Format end */
+
+/* * GID Format start */
+struct roce_gid_context {
+ /* DW0~3 */
+ u32 gid[4];
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 svlan : 12; /* outer vlan */
+ u32 cvlan : 12; /* inner vlan */
+ u32 is_vroce : 1;
+ u32 rsvd : 7;
+#else
+ u32 rsvd : 7;
+ u32 is_vroce : 1;
+ u32 ppe_rsvd0 : 12;
+ u32 svlan : 12;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 svlan : 12; /* outer vlan */
+ u32 cvlan : 12; /* inner vlan */
+ u32 rsvd : 4;
+ u32 ip_ctrl_bmp : 4;
+#else
+ u32 ip_ctrl_bmp : 4;
+ u32 rsvd : 4;
+ u32 ppe_rsvd0 : 12;
+ u32 svlan : 12;
+#endif
+ } nofaa_master_gid;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 svlan : 12; /* outer vlan */
+ u32 ppe_rsvd0 : 12; /* inner vlan */
+ u32 rsvd : 1;
+ u32 master_gid_index : 7;
+#else
+ u32 master_gid_index : 7;
+ u32 rsvd : 1;
+ u32 ppe_rsvd0 : 12;
+ u32 svlan : 12;
+#endif
+ } nofaa_slave_gid;
+
+ u32 value;
+ } dw4;
+
+ /* DW5 */
+ union {
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 add_value : 6;
+ u32 gid_update : 1;
+ u32 ppe_rsvd3 : 1;
+ u32 outer_tag : 2;
+ u32 ppe_rsvd1 : 1;
+ u32 gid_type : 2;
+ u32 tunnel : 1;
+ u32 tag : 2;
+ u32 smac_hi16 : 16;
+#else
+ u32 smac_hi16 : 16;
+ u32 tag : 2;
+ u32 tunnel : 1; // tunnel
+ u32 gid_type : 2;
+ u32 ppe_rsvd1 : 1; // outer_ip_type
+ u32 outer_tag : 2; // outer_tag
+ u32 ppe_rsvd3 : 1; // stag
+ u32 gid_update : 1;
+ u32 add_value : 6;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd_com : 8;
+ u32 outer_value : 3;
+ u32 misc_idx : 5;
+ u32 smac_hi16 : 16;
+#else
+ u32 smac_hi16 : 16;
+ u32 misc_idx : 5;
+ u32 outer_value : 3;
+ u32 rsvd_com : 8;
+#endif
+ } bs1;
+ u32 value;
+ } dw6;
+
+ u32 smac_lo32;
+};
+/* * GID Format end */
+
+/* * sqrq db Format start */
+struct roce_sqrq_db {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 16;
+ u32 _wqe_counter : 16;
+#else
+ u32 _wqe_counter : 16;
+ u32 rsvd : 16;
+#endif
+};
+/* * sqrq db Format end */
+
+/* * srq db Format start */
+struct roce_srq_db {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 16;
+ u32 _wqe_counter : 16;
+#else
+ u32 _wqe_counter : 16;
+ u32 rsvd : 16;
+#endif
+};
+/* * srq db Format end */
+
+/* * VTEP Format start */
+struct roce_vtep_context {
+ u32 dmac_h32;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 dmac_l16 : 16;
+ u32 smac_h16 : 16;
+#else
+ u32 smac_h16 : 16;
+ u32 dmac_l16 : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ u32 smac_l32;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 portid : 8;
+ u32 vni : 24;
+#else
+ u32 vni : 24;
+ u32 portid : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ u32 sip[4]; // dw4 ~ 7
+ u32 dip[4]; // dw8 ~ 11
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 src_port : 16;
+ u32 dst_port : 16;
+#else
+ u32 dst_port : 16;
+ u32 src_port : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw12;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 base_id : 8; /* vf cfg id */
+ u32 cvlan : 12;
+ u32 svlan : 12;
+#else
+ u32 svlan : 12;
+ u32 cvlan : 12;
+ u32 base_id : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw13;
+
+ u32 racl_id;
+
+ /* DW15 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 5;
+ u32 vm_dp_capture_en : 1;
+ u32 vm_dp_chk_en : 1;
+ u32 vm_dp_chk_invld : 1;
+ u32 dscp_rc : 8;
+ u32 dscp_ud : 8;
+ u32 dscp_xrc : 8;
+#else
+ u32 dscp_xrc : 8;
+ u32 dscp_ud : 8;
+ u32 dscp_rc : 8;
+ u32 vm_dp_chk_invld : 1;
+ u32 vm_dp_chk_en : 1;
+ u32 vm_dp_capture_en : 1;
+ u32 rsvd : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw15;
+};
+/* * vtep Format end */
+
+union tag_roce_qu_db_dw4 {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sub_type : 4;
+ u32 udf_3 : 12;
+ u32 rsvd0 : 8;
+ u32 pi : 8;
+#else
+ u32 pi : 8;
+ u32 rsvd0 : 8;
+ u32 udf_3 : 12;
+ u32 sub_type : 4;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sub_type : 4;
+ u32 sgid_index : 7;
+ u32 mtu_shift : 3; /* 256B:0;512B:1;1024B:2;2048B:3;4096B:4 */
+ u32 rsvd : 1;
+ u32 xrc_vld : 1;
+ u32 rsvd0 : 8;
+ u32 pi : 8;
+#else
+ u32 pi : 8;
+ u32 rsvd0 : 8;
+ u32 xrc_vld : 1;
+ u32 rsvd : 1;
+ u32 mtu_shift : 3;
+ u32 sgid_index : 7;
+ u32 sub_type : 4;
+#endif
+ } bs1;
+ u32 value;
+};
+
+struct tag_roce_cq_mtt_info {
+ /* Indicates whether to kick out cache. by queue (0) or VF(1). */
+ u32 mtt_flags;
+ /*
+ * Number of cmtt, which needs to be assigned by the
+ * driver when the is kicked out by queue.
+ */
+ u32 mtt_num;
+ /* The driver needs to read the driver from the configuration file. */
+ u32 mtt_cache_line_start;
+ /* The driver needs to read the driver from the configuration file. */
+ u32 mtt_cache_line_end;
+ u32 mtt_cache_line_size; /* 0:256B,1:512B */
+};
+
+struct tag_timer_section {
+ union {
+ u32 value;
+ struct {
+ u32 timer_num : 4; // last immeth+cmdlen
+ u32 rsvd : 9;
+ u32 lv : 1;
+ u32 link_timer_id : 3;
+ u32 link_wheel_id : 3;
+ u32 link_spoke : 12;
+ } bs;
+ } dw0;
+
+ union {
+ u32 value;
+ struct {
+ u32 v : 1; // last immeth+cmdlen
+ u32 service_type : 5;
+ u32 rsvd : 9;
+ u32 instance_id : 5;
+ u32 vf : 12;
+ } bs;
+ } dw1;
+ union {
+ u32 value;
+ struct {
+ u32 xid : 20;
+ u32 cid : 12;
+ } bs;
+ } dw2;
+ union {
+ u32 value;
+ struct {
+ u32 cid : 8;
+ u32 v : 1; // last immeth+cmdlen
+ u32 service_type : 5;
+ u32 rsvd : 9;
+ u32 instance_id : 5;
+ u32 vf : 4;
+ } bs;
+ } dw3;
+ union {
+ u32 value;
+ struct {
+ u32 vf : 8;
+ u32 xid : 20;
+ u32 cid : 4;
+ } bs;
+ } dw4;
+
+ u16 cid;
+ u16 te0;
+ u16 te1;
+ u16 te2;
+ u16 te3;
+ u16 te4;
+};
+
+struct tag_spoke_info {
+ union {
+ u32 value;
+ struct {
+ u32 v : 1;
+ u32 rsvd : 19;
+ u32 vf : 12;
+ } bs;
+ } dw0;
+
+ union {
+ u32 value;
+ struct {
+ u32 xid : 20;
+ u32 cid : 12;
+ } bs;
+ } dw1;
+ union {
+ u32 value;
+ struct {
+ u32 cid : 8;
+ u32 v : 1; // last immeth+cmdlen
+ u32 service_type : 5;
+ u32 rsvd : 9;
+ u32 instance_id : 5;
+ u32 vf : 4;
+ } bs;
+ } dw2;
+ union {
+ u32 value;
+ struct {
+ u32 vf : 8;
+ u32 xid : 20;
+ u32 cid : 4;
+ } bs;
+ } dw3;
+
+ u16 cid;
+ u16 rsvd;
+ u32 total_cnt;
+ u32 scan_cnt;
+ u32 rsvd1;
+};
+
+struct racl_value_rsp {
+ u32 vni;
+ u32 vtep_ip;
+ u16 vf_id;
+ u8 mode;
+ u8 gw_mac[ETH_ADDR_LEN];
+ u8 vm_mac[ETH_ADDR_LEN];
+ u8 rsvd;
+};
+
+struct racl_value {
+ u32 vip;
+ u32 vni;
+ u32 vtep_ip;
+
+ union {
+ struct {
+ u32 gw_mac_h : 16;
+ u32 gw_mac_m : 16;
+ } bs;
+ u32 value;
+ } dw3;
+
+ union {
+ struct {
+ u32 gw_mac_l : 16;
+ u32 vf_id : 8;
+ u32 rsv0 : 7;
+ u32 mode : 1;
+ } bs;
+ u32 value;
+ } dw4;
+};
+#pragma pack(0)
+
+#endif // RDMA_CONTEXT_FORMAT_H
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/rdma_ext_ctx_format.h b/drivers/infiniband/hw/hiroce3/include/rdma/rdma_ext_ctx_format.h
new file mode 100644
index 0000000000000..7d02528496080
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/rdma_ext_ctx_format.h
@@ -0,0 +1,379 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef RDMA_EXT_CTX_FORMAT_H
+#define RDMA_EXT_CTX_FORMAT_H
+
+#include "roce_compile_macro.h"
+
+#include "roce_ccf_format.h"
+
+#ifdef ROCE_VBS_EN
+#include "roce_vbs_format.h"
+#endif
+
+#include "roce_dif_format.h"
+/* Align each field with 4bytes. */
+#pragma pack(4)
+
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 0x1234
+#endif
+
+/***********************************/
+struct ucode_dcc_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 back_token : 9;
+ u32 token : 13;
+ u32 alpha : 10;
+#else
+ u32 alpha : 10;
+ u32 token : 13;
+ u32 back_token : 9;
+#endif
+ } dcqcn;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 less_mtu_cnt : 2;
+ u32 alpha : 2;
+ u32 beta : 2;
+ u32 set_flag : 1;
+ u32 rsvd : 1;
+ u32 sw_wnd_fraction : 12;
+ u32 sw_wnd : 12;
+#else
+ u32 sw_wnd : 12;
+ u32 sw_wnd_fraction : 12;
+ u32 rsvd : 1;
+ u32 set_flag : 1;
+ u32 beta : 2;
+ u32 alpha : 2;
+ u32 less_mtu_cnt : 2;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ccf_en : 1;
+ u32 cnp_receive : 1;
+ u32 cur_rate : 15;
+ u32 target_rate : 15;
+#else
+ u32 target_rate : 15;
+ u32 cur_rate : 15;
+ u32 cnp_receive : 1;
+ u32 ccf_en : 1;
+#endif
+ } dcqcn;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ccf_en : 1;
+ u32 dip_valid : 1;
+ u32 dip_index : 16;
+ u32 rsvd : 14;
+#else
+ u32 rsvd : 14;
+ u32 dip_index : 16;
+ u32 dip_valid : 1;
+ u32 ccf_en : 1;
+#endif
+ } ipqcn;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ccf_en : 1;
+ u32 mtu_thr_cnt : 2;
+ u32 rsvd : 3;
+ u32 sw_wnd_just_halve : 1;
+ u32 rr_wnd_just_halve : 1;
+ u32 rr_wnd_fraction : 12;
+ u32 rr_wnd : 12;
+#else
+ u32 rr_wnd : 12;
+ u32 rr_wnd_fraction : 12;
+ u32 rr_wnd_just_halve : 1;
+ u32 sw_wnd_just_halve : 1;
+ u32 rsvd : 3;
+ u32 mtu_thr_cnt : 2;
+ u32 ccf_en : 1;
+#endif
+ } ldcpw;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ccf_en : 1;
+ u32 rsvd : 31;
+#else
+ u32 rsvd : 31;
+ u32 ccf_en : 1;
+#endif
+ } cc_common;
+
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rate_timestamp : 13;
+ u32 alpha_timestamp : 13;
+ u32 cal_token_l : 6;
+#else
+ u32 cal_token_l : 6;
+ u32 alpha_timestamp : 13;
+ u32 rate_timestamp : 13;
+#endif
+ } dcqcn;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sw_left_ce_num : 12;
+ u32 last_ack_event_timestamp : 20;
+#else
+ u32 last_ack_event_timestamp : 20;
+ u32 sw_left_ce_num : 12;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rcnp_timestamp : 13;
+ u32 token_timestamp : 13;
+ u32 f_cnt : 4;
+ u32 cal_token_h : 2;
+#else
+ u32 cal_token_h : 2;
+ u32 f_cnt : 4;
+ u32 token_timestamp : 13;
+ u32 rcnp_timestamp : 13;
+#endif
+ } dcqcn;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 wnd_ctrl_rtt : 16;
+ u32 rr_left_ce_num : 12;
+ u32 gamma : 2;
+ u32 eta : 2;
+#else
+ u32 eta : 2;
+ u32 gamma : 2;
+ u32 rr_left_ce_num : 12;
+ u32 wnd_ctrl_rtt : 16;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw3;
+};
+
+/*************************************/
+union ucode_ext_sq_ctx {
+ struct ucode_ccf_sq_ctx ccf_sq;
+
+ u32 rsvd;
+};
+
+union ucode_ext_sqa_ctx {
+ struct ucode_ccf_sqa_ctx ccf_sqa;
+
+ u32 rsvd[2];
+};
+
+union ucode_ext_rq_ctx {
+ struct ucode_ccf_rq_ctx ccf_rq;
+ u8 vbs_rq[4];
+ u32 rsvd;
+};
+
+union ucode_ext_rqa_ctx {
+ struct ucode_ccf_rqa_ctx ccf_rqa;
+
+ u32 rsvd;
+};
+
+struct ucode_ext_ctx {
+ /* DW0 */
+ union ucode_ext_sq_ctx sq;
+
+ /* DW1~2 */
+ union ucode_ext_sqa_ctx sqa;
+
+ /* DW3 */
+ union ucode_ext_rq_ctx rq;
+
+ /* DW4 */
+ union ucode_ext_rqa_ctx rqa;
+
+ /* DW5~8 */
+ struct ucode_dcc_ctx dcc;
+};
+
+struct tag_nofaa_io_qpn_entry {
+ u32 rsvd : 8;
+ u32 io_qpn_2 : 12;
+ u32 io_qpn_1 : 12;
+};
+
+struct ucode_nofaa_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 admin_qp : 1;
+ u32 rts_bmp : 4;
+ u32 nof_bmp : 4;
+ u32 disconn : 1;
+ u32 rsvd : 6;
+ u32 cm_bmp : 16;
+#else
+ u32 cm_bmp : 16;
+ u32 rsvd : 6;
+ u32 disconn : 1;
+ u32 nof_bmp : 4;
+ u32 rts_bmp : 4;
+ u32 admin_qp : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 nof_vport : 2;
+ u32 gid_index_3 : 6;
+ u32 rsvd2 : 2;
+ u32 gid_index_2 : 6;
+ u32 rsvd1 : 2;
+ u32 gid_index_1 : 6;
+ u32 rsvd0 : 2;
+ u32 gid_index_0 : 6;
+#else
+ u32 gid_index_0 : 6;
+ u32 rsvd0 : 2;
+ u32 gid_index_1 : 6;
+ u32 rsvd1 : 2;
+ u32 gid_index_2 : 6;
+ u32 rsvd2 : 2;
+ u32 gid_index_3 : 6;
+ u32 nof_vport : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 io_qpn_2 : 12;
+ u32 io_qpn_1 : 12;
+#else
+ u32 io_qpn_1 : 12;
+ u32 io_qpn_2 : 12;
+ u32 rsvd : 8;
+#endif
+ } admin_q;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 admin_qpn : 20;
+ u32 rsvd : 4;
+ u32 qid : 8;
+#else
+ u32 qid : 8;
+ u32 rsvd : 4;
+ u32 admin_qpn : 20;
+#endif
+ } io_q;
+ u32 value;
+ } dw2;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 io_qpn_4 : 12;
+ u32 io_qpn_3 : 12;
+#else
+ u32 io_qpn_3 : 12;
+ u32 io_qpn_4 : 12;
+ u32 rsvd : 8;
+#endif
+ } admin_q;
+ struct {
+ u32 rsvd;
+ } io_q;
+ u32 value;
+ } dw3;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 io_qpn_6 : 12;
+ u32 io_qpn_5 : 12;
+#else
+ u32 io_qpn_5 : 12;
+ u32 io_qpn_6 : 12;
+ u32 rsvd : 8;
+#endif
+ } admin_q;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd;
+#else
+ u32 rsvd;
+#endif
+ } io_q;
+ u32 value;
+ } dw4;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 io_qpn_8 : 12;
+ u32 io_qpn_7 : 12;
+#else
+ u32 io_qpn_7 : 12;
+ u32 io_qpn_8 : 12;
+ u32 rsvd : 8;
+#endif
+ } admin_q;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd;
+#else
+ u32 rsvd;
+#endif
+ } io_q;
+ u32 value;
+ } dw5;
+
+ u32 rsvd[2];
+};
+
+#pragma pack(0)
+
+#endif // RDMA_EXT_CTX_FORMAT_H
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_ccf_format.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_ccf_format.h
new file mode 100644
index 0000000000000..cc8c6f55ee8ec
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_ccf_format.h
@@ -0,0 +1,722 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_CCF_FORMAT_H
+#define ROCE_CCF_FORMAT_H
+
+/* Align each field with 4bytes. */
+#pragma pack(4)
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 0x1234
+#endif
+
+enum ROCE3_CCF_PARAM_ALGO_ID {
+ ROCE_CCF_ALGO_ID,
+ ROCE_DCQCN_ALGO_ID,
+ ROCE_HC3_2_0_ALGO_ID,
+ ROCE_LDCP_ALGO_ID,
+ ROCE_MIBO_ALGO_ID,
+ ROCE_BW_CTRL_ALGO_ID,
+ ROCE_CCF_PARAM_MAX_ID = 7
+};
+#define ROCE_IPQCN_ALGO_ID ROCE_DCQCN_ALGO_ID
+#define ROCE_CCF_PARAM_INDEX_GET(vf_id, algo_id) (((vf_id) << 3) | (algo_id))
+
+enum ROCE_CC_ALGO_E {
+ ROCE_CC_DISABLE = 0,
+ ROCE_CC_DCQCN_ALGO,
+ ROCE_CC_LDCP_ALGO,
+ ROCE_CC_IPQCN_ALGO,
+ ROCE_CC_MIBO_ALGO
+};
+
+#define CTX_TBL_WR_KEY_OFFSET 16
+#define CTX_TBL_CPY_BYTE_TYPE 48
+
+/* *************************** EVENT *************************** */
+enum dcc_event {
+ DCC_EVENT_NEW_FLOW = 0,
+ DCC_EVENT_DATA_TX = 1,
+ DCC_EVENT_RETRANSMIT,
+ DCC_EVENT_NACK,
+ DCC_EVENT_RTT_RESP,
+ DCC_EVENT_CNP_TX = 5,
+ DCC_EVENT_CNP_RX,
+ DCC_EVENT_ACK = 7,
+ DCC_EVENT_REPEAT_READ,
+ DCC_EVENT_NORMAL_READ,
+ DCC_EVENT_RSVD4 = 10,
+ DCC_EVENT_RSVD5,
+ DCC_EVENT_TIMER,
+ DCC_EVENT_RX,
+ DCC_EVENT_ACK_TX,
+ DCC_EVENT_ACK_DATA_TX = 15,
+ DCC_EVENT_ACK_DATA_RX,
+ DCC_EVENT_LESS_MTU_TX,
+ DCC_EVENT_LESS_MTU_RSPTX,
+ DCC_EVENT_UPDATE_TOKEN,
+ DCC_EVENT_VERBS_INIT = 20,
+ DCC_EVENT_VERBS_DEINIT,
+ DCC_EVENT_RSVD1,
+ DCC_EVENT_RSVD2,
+ DCC_EVENT_RSVD3,
+
+ DCC_MATCH_RX_CTL = 25,
+ DCC_MOD_TX_SW,
+ DCC_MOD_TX_READ,
+ DCC_MOD_ACK_TX_ACK,
+ DCC_MOD_ACK_TX_RR,
+ DCC_CTR_AVA_WND = 30,
+ DCC_PKT_ACK_EXT,
+ DCC_PKT_DATA_EXT,
+ DCC_PKT_ACK_DATA_EXT,
+ DCC_PKT_ACK_EXT_RX,
+ DCC_PKT_DATA_EXT_RX = 35,
+ DCC_PKT_ACK_DATA_EXT_RX
+};
+
+/* *************************** QPC *************************** */
+struct ucode_ccf_sq_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 12;
+ u32 retrans_read_req : 1;
+ u32 retrans_mark : 1;
+ u32 sw_send_sn : 16;
+ u32 sw_wnd_timer_stat : 2;
+#else
+ u32 sw_wnd_timer_stat : 2;
+ u32 sw_send_sn : 16;
+ u32 retrans_mark : 1;
+ u32 retrans_read_req : 1;
+ u32 rsvd : 12;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw0;
+};
+
+struct ucode_ccf_sqa_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 6;
+ u32 sw_zero_avail_wnd : 1;
+ u32 rr_zero_avail_wnd : 1;
+ u32 change2rqa_stg_cnt : 8;
+ u32 rr_rcv_sn : 16;
+#else
+ u32 rr_rcv_sn : 16;
+ u32 change2rqa_stg_cnt : 8;
+ u32 rr_zero_avail_wnd : 1;
+ u32 sw_zero_avail_wnd : 1;
+ u32 rsvd : 6;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sw_ack_sn : 16;
+ u32 rr_ack_sn : 16;
+#else
+ u32 rr_ack_sn : 16;
+ u32 sw_ack_sn : 16;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw1;
+};
+
+struct ucode_ccf_rq_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sw_rcv_sn : 16;
+ u32 rcv_timestamp : 16;
+#else
+ u32 rcv_timestamp : 16;
+ u32 sw_rcv_sn : 16;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw0;
+};
+
+struct ucode_ccf_rqa_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rr_send_sn : 16;
+ u32 rr_send_ce_sn : 11;
+ u32 rr_rsp_ack_cnt : 1;
+ u32 rcv_read_rsp : 1;
+ u32 ext_hdr_flip : 1;
+ u32 rr_wnd_timer_stat : 2;
+#else
+ u32 rr_wnd_timer_stat : 2;
+ u32 ext_hdr_flip : 1;
+ u32 rcv_read_rsp : 1;
+ u32 rr_rsp_ack_cnt : 1;
+ u32 rr_send_ce_sn : 11;
+ u32 rr_send_sn : 16;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw0;
+};
+
+/* *************************** EXT TABLE *************************** */
+/* ccf common param tbl */
+struct roce_ccf_param {
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 np_enable : 8;
+ u32 rp_enable : 8;
+ u32 ecn_ver : 4;
+ u32 cnp_prio_enable : 1;
+ u32 ip_enable : 8;
+ u32 port_mode : 1;
+ u32 rsvd : 2;
+#else
+ u32 rsvd : 2;
+ u32 port_mode : 1;
+ u32 ip_enable : 8;
+ u32 cnp_prio_enable : 1;
+ u32 ecn_ver : 4;
+ u32 rp_enable : 8;
+ u32 np_enable : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cnp_cos : 3;
+ u32 cnp_prio : 3;
+ u32 ccf_appid : 8;
+ u32 rsvd : 18;
+#else
+ u32 rsvd : 18;
+ u32 ccf_appid : 8;
+ u32 cnp_prio : 3;
+ u32 cnp_cos : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ u32 rsvd[2];
+};
+
+struct roce_dcqcn_param {
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 18;
+ u32 flow_min_rate : 6;
+ u32 token_period : 8;
+#else
+ u32 token_period : 8;
+ u32 flow_min_rate : 6;
+ u32 rsvd : 18;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rate_inc_period : 10;
+ u32 rsvd : 3;
+ u32 cnp_cnt_threshold : 4;
+ u32 alpha_dec_period : 10;
+ u32 alpha_threshold : 5;
+#else
+ u32 alpha_threshold : 5;
+ u32 alpha_dec_period : 10;
+ u32 cnp_cnt_threshold : 4;
+ u32 rsvd : 3;
+ u32 rate_inc_period : 10;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rate_inc_period : 16;
+ u32 alpha_dec_period : 16;
+#else
+ u32 alpha_dec_period : 16;
+ u32 rate_inc_period : 16;
+#endif
+ } bs1;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rate_inc_ai : 8;
+ u32 rate_inc_hai : 8;
+ u32 rate_dec_period : 8;
+ u32 min_cnp_period : 8;
+#else
+ u32 min_cnp_period : 8;
+ u32 rate_dec_period : 8;
+ u32 rate_inc_hai : 8;
+ u32 rate_inc_ai : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 factor_gita : 4;
+ u32 rt_clamp : 1;
+ u32 rsvd : 1;
+ u32 initial_alpha : 10;
+ u32 rate_first_set : 16;
+#else
+ u32 rate_first_set : 16;
+ u32 initial_alpha : 10;
+ u32 rsvd : 1;
+ u32 rt_clamp : 1;
+ u32 factor_gita : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+};
+
+struct roce_ipqcn_param {
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 18;
+ u32 flow_min_rate : 6;
+ u32 token_period : 8;
+#else
+ u32 token_period : 8;
+ u32 flow_min_rate : 6;
+ u32 rsvd : 18;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rate_inc_period : 10;
+ u32 rsvd : 3;
+ u32 cnp_cnt_threshold : 4;
+ u32 alpha_dec_period : 10;
+ u32 alpha_threshold : 5;
+#else
+ u32 alpha_threshold : 5;
+ u32 alpha_dec_period : 10;
+ u32 cnp_cnt_threshold : 4;
+ u32 rsvd : 3;
+ u32 rate_inc_period : 10;
+#endif
+ } bs;
+
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rate_inc_period : 16;
+ u32 alpha_dec_period : 16;
+#else
+ u32 alpha_dec_period : 16;
+ u32 rate_inc_period : 16;
+#endif
+ } bs1;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rate_inc_ai : 8;
+ u32 rate_inc_hai : 8;
+ u32 rate_dec_period : 8;
+ u32 min_cnp_period : 8;
+#else
+ u32 min_cnp_period : 8;
+ u32 rate_dec_period : 8;
+ u32 rate_inc_hai : 8;
+ u32 rate_inc_ai : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 factor_gita : 4;
+ u32 rt_clamp : 1;
+ u32 rsvd : 1;
+ u32 initial_alpha : 10;
+ u32 rate_first_set : 16;
+#else
+ u32 rate_first_set : 16;
+ u32 initial_alpha : 10;
+ u32 rsvd : 1;
+ u32 rt_clamp : 1;
+ u32 factor_gita : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+};
+
+struct roce_ldcp_param {
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 alpha : 2;
+ u32 beta : 2;
+ u32 gamma : 2;
+ u32 eta : 2;
+ u32 set_flag : 1;
+ u32 rsvd : 23;
+#else
+ u32 rsvd : 23;
+ u32 set_flag : 1;
+ u32 eta : 2;
+ u32 gamma : 2;
+ u32 beta : 2;
+ u32 alpha : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ u32 rsvd1[3];
+};
+
+struct ucode_dcc_ip_table_rate_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 alpha : 14;
+ u32 ip_rate : 18; /* cur_rate, unit:1M */
+#else
+ u32 ip_rate : 18; /* cur_rate, unit:1M */
+ u32 alpha : 14;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cnp_flag : 1;
+ u32 rsvd : 6;
+ u32 cnp_receive : 1;
+ u32 f_cnt : 3;
+ u32 ai_cnt : 3;
+ u32 ip_target_rate : 18;
+#else
+ u32 ip_target_rate : 18;
+ u32 ai_cnt : 3;
+ u32 f_cnt : 3;
+ u32 cnp_receive : 1;
+ u32 rsvd : 6;
+ u32 cnp_flag : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 alpha_timestamp : 16;
+ u32 rate_timestamp : 16; /* last update rate */
+#else
+ u32 rate_timestamp : 16; /* last update rate */
+ u32 alpha_timestamp : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rcnp_timestamp : 32;
+#else
+ u32 rcnp_timestamp : 32;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+};
+
+struct ucode_dcc_bw_ctrl_ctx {
+ union {
+ struct {
+ u32 bw_ctrl_thd_def : 32;
+ } bs;
+
+ u32 value;
+ } dw0;
+
+ u32 rsvd1[3];
+};
+
+/* *************************** RC EXT TABLE *************************** */
+/* dcc ext qpc table struct */
+struct ucode_ext_table_sq_ctx {
+ /* DW0 */
+ union {
+ u32 ldcpw_rsvd;
+
+ u32 value;
+ } dw0;
+
+ u32 rsvd;
+};
+
+struct ucode_ext_table_sqa_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 21;
+ u32 rr_rcv_ce_sn : 11;
+#else
+ u32 rr_rcv_ce_sn : 11;
+ u32 rsvd : 21;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw0;
+
+ u32 rsvd;
+};
+
+struct ucode_ext_table_rq_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 20;
+ u32 sw_rcv_ce_sn : 12;
+#else
+ u32 sw_rcv_ce_sn : 12;
+ u32 rsvd : 20;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw0;
+
+ u32 rsvd;
+};
+
+struct ucode_ext_table_rqa_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 20;
+ u32 sw_send_ce_sn : 12;
+#else
+ u32 sw_send_ce_sn : 12;
+ u32 rsvd : 20;
+#endif
+ } ldcpw;
+
+ u32 value;
+ } dw0;
+
+ u32 rsvd;
+};
+
+struct ucode_ext_table_dcc_ctx {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 alpha : 12;
+ u32 cur_rate : 20;
+#else
+ u32 cur_rate : 20;
+ u32 alpha : 12;
+#endif
+ } hc3_1_0;
+
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 target_rate : 20;
+ u32 ai_cnt : 3;
+ u32 f_cnt : 3;
+ u32 flow_min_rate : 6;
+#else
+ u32 flow_min_rate : 6;
+ u32 f_cnt : 3;
+ u32 ai_cnt : 3;
+ u32 target_rate : 20;
+#endif
+ } hc3_1_0;
+
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 alpha_timestamp : 16;
+ u32 rate_timestamp : 16;
+#else
+ u32 rate_timestamp : 16;
+ u32 alpha_timestamp : 16;
+#endif
+ } hc3_1_0;
+
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 14;
+ u32 cnp_flag : 1;
+ u32 cnp_receive : 1;
+ u32 rcnp_timestamp : 16;
+#else
+ u32 rcnp_timestamp : 16;
+ u32 cnp_receive : 1;
+ u32 cnp_flag : 1;
+ u32 rsvd : 14;
+#endif
+ } hc3_1_0;
+
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 16;
+ u32 token_timestamp : 16;
+#else
+ u32 token_timestamp : 16;
+ u32 rsvd : 16;
+#endif
+ } hc3_1_0;
+
+ u32 value;
+ } dw4;
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 16;
+ u32 cnp_tx_filter_ts : 16;
+#else
+ u32 cnp_tx_filter_ts : 16;
+ u32 rsvd : 16;
+#endif
+ } hc3_1_0;
+
+ u32 value;
+ } dw5;
+};
+
+struct smf_rdma_dcc_ip_table {
+ struct ucode_dcc_ip_table_rate_ctx algo_para; // dw0-dw3
+};
+
+struct ucode_ext_table_qpc_ctx {
+ struct ucode_ext_table_sq_ctx sq;
+ struct ucode_ext_table_sqa_ctx sqa;
+ struct ucode_ext_table_rq_ctx rq;
+ struct ucode_ext_table_rqa_ctx rqa;
+};
+
+
+struct tag_iqpcn_hash_entry {
+ u32 dw0;
+ union {
+ struct {
+ u32 rsvd_key[7];
+ u8 dgid[16];
+ u32 srctagl;
+ } bs;
+ u32 value[12];
+ } key;
+ union {
+ struct {
+ u32 rsvd : 4;
+ u32 cnt : 28;
+ } bs;
+ u32 item;
+ } dw13;
+};
+
+struct tag_ipqcn_hash_value {
+ union {
+ struct {
+ u32 code : 2;
+ u32 subcode : 2;
+ u32 rsvd : 13;
+ u32 node_index : 15;
+ } bs;
+ u32 value;
+ } dw0;
+ union {
+ struct {
+ u32 w : 1;
+ u32 sm_id : 3;
+ u32 cnt : 28;
+ } bs;
+ u32 value;
+ } dw1;
+ u32 rsvd[2];
+};
+
+#pragma pack(0)
+
+#endif // ROCE_CCF_FORMAT_H
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_compile_macro.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_compile_macro.h
new file mode 100644
index 0000000000000..54eb98cb641a5
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_compile_macro.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_COMPILE_MACRO_H
+#define ROCE_COMPILE_MACRO_H
+
+#include "node_id.h"
+
+#ifdef ROCE_LB_MODE1_EN
+#define ROCE_LBF_MODE1
+#endif
+
+#ifdef ROCE_LB_MODE0_EN
+#define ROCE_LBF_MODE0
+#endif
+
+#ifdef TBL_ID_ROCE_QDFX_CTR_SM_NODE
+#define ROCE_SRQ_QDFX_EN
+#endif
+
+/* ******************************************************** */
+enum ROCE_LBF_E {
+ ROCE_LBF_DIS = 0,
+ ROCE_LBF_TYPE1,
+ ROCE_LBF_TYPE2,
+};
+
+#ifdef ROCE_LB_MODE1_ECO_EN
+#define ROCE_LB_XID_MASK 0x1
+#else
+#define ROCE_LB_XID_MASK 0x3
+#endif
+
+#if defined(ROCE_LBF_MODE0) || defined(ROCE_LBF_MODE1)
+
+#ifdef ROCE_LB_MODE1_ECO_EN
+#define NODE_SMF_0 NODE_ID_SMF0
+#define NODE_SMF_1 NODE_ID_SMF0
+#define NODE_SMF_2 NODE_ID_SMF2
+#define NODE_SMF_3 NODE_ID_SMF2
+#else
+#define NODE_SMF_0 NODE_ID_SMF0
+#define NODE_SMF_1 NODE_ID_SMF1
+#define NODE_SMF_2 NODE_ID_SMF2
+#define NODE_SMF_3 NODE_ID_SMF3
+#endif /* ROCE_LB_MODE1_ECO_EN */
+
+#define ROCE_LBF_MODE ROCE_LBF_TYPE1
+#else
+#define NODE_SMF_0 NODE_ID_SMF0
+#define NODE_SMF_1 NODE_ID_SMF0
+#define NODE_SMF_2 NODE_ID_SMF0
+#define NODE_SMF_3 NODE_ID_SMF0
+
+#define ROCE_LBF_MODE ROCE_LBF_DIS
+#endif /* defined(ROCE_LBF_MODE0) || defined(ROCE_LBF_MODE1) */
+
+#define ROCE_LBF_INLINE_SMFPG23(idx) ((0 == ((idx) & 0x2)) ? NODE_SMF_2 : NODE_SMF_3)
+#define ROCE_LBF_INLINE_SMFPG01(idx) ((0 == ((idx) & 0x2)) ? NODE_SMF_0 : NODE_SMF_1)
+#define ROCE_LBF_INLINE_SMFID(idx) ((0 == ((idx) & 0x1)) ? \
+ ROCE_LBF_INLINE_SMFPG01(idx) : ROCE_LBF_INLINE_SMFPG23(idx))
+/* ******************************************************** */
+
+#define ROCE_FUNC_CHECK(roce_en) ((roce_en) ^ 0x1)
+
+#endif /* ROCE_COMPILE_MACRO_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_ctx_api.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_ctx_api.h
new file mode 100644
index 0000000000000..7ac693aad3d24
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_ctx_api.h
@@ -0,0 +1,258 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_CTX_API_H
+#define ROCE_CTX_API_H
+
+#include "roce_compile_macro.h"
+#include "roce_wqe_format.h"
+#include "roce_xqe_format.h"
+#include "rdma_context_format.h"
+
+
+enum ROCE_TIMER_ID_E {
+ ROCE_TIMER_ID_ACK = 0,
+ ROCE_TIMER_ID_DCQCN_RCNP,
+ ROCE_TIMER_ID_WND_LESS_THAN_MTU,
+ ROCE_TIMER_ID_MAX = 4,
+ ROCE_TIMER_ID_QP_DEL = 7
+};
+
+enum roce_qpc_ulp_type {
+ ROCE_ULP_STD = 0,
+ ROCE_ULP_PLOG,
+ ROCE_ULP_VBS,
+ ROCE_ULP_OSD,
+ ROCE_ULP_NOFAA
+};
+
+enum roce_req_rsp_side {
+ ROCE_REQ_SIDE = 0,
+ ROCE_RSP_SIDE
+};
+
+enum roce_rq_cqe_mask {
+ ROCE_CQEMASK_WRITE = 0,
+ ROCE_CQEMASK_SEND
+};
+
+enum ROCE_FLOWID_E {
+ ROCE_FLOWID_0 = 0,
+ ROCE_FLOWID_1,
+ ROCE_FLOWID_2
+};
+
+enum ROCE_STGID_E {
+ ROCE_STGID_0 = 0,
+ ROCE_STGID_1,
+ ROCE_STGID_2,
+ ROCE_STGID_3,
+ ROCE_STGID_4,
+ ROCE_STGID_5,
+ ROCE_STGID_6,
+ ROCE_STGID_7
+};
+
+enum ROCE_EVENT_STG_E {
+ ROCE_EVENT_STG_SQ = 0,
+ ROCE_EVENT_STG_SQA,
+ ROCE_EVENT_STG_RQ,
+ ROCE_EVENT_STG_RQA,
+ ROCE_EVENT_STG_SQA_2HOST,
+ ROCE_EVENT_STG_DCC,
+ ROCE_EVENT_STG_VERBS,
+ ROCE_EVENT_STG_NO
+};
+
+#define ROCE_SQ_STGID ROCE_STGID_0
+#define ROCE_RQ_STGID ROCE_STGID_1
+#define ROCE_VERBS_STGID ROCE_STGID_2
+#define ROCE_DCC_STGID ROCE_STGID_3
+#define ROCE_RQ_ACK_STGID ROCE_STGID_4
+#define ROCE_SQ_ACK_STGID ROCE_STGID_5
+#define ROCE_SQA_2HOST_STGID ROCE_STGID_6
+#define ROCE_REBIND_STGID QU_STG_ID_RSVD
+
+/* *********TABLE SIZE******* */
+#define WQEBB_SIZE_SHIFT 6 // 64b
+#define ROCE_GET_WQBB_NUM_PERWQE(wqe_len_8b) (BYTE8_TO_BYTES(wqe_len_8b) >> WQEBB_SIZE_SHIFT)
+
+#define ROCE_GID_TABLE_SIZE (32)
+#define ROCE_MPT_TABLE_SIZE (64)
+#define ROCE_MTT_TABLE_SIZE (8)
+#define ROCE_CQC_TABLE_SIZE (128)
+#define ROCE_SRQC_TABLE_SIZE (64)
+#define ROCE_RDMARC_TABLE_SIZE (32)
+#define ROCE_QPC_TABLE_SIZE (512)
+#define ROCE_WQE_MAX_SIZE (256)
+#define ROCE_CM_MAD_MEG_LEN (64)
+
+#define ROCE_MTT_QUERY_SIZE (16)
+#define ROCE_PCNT_QUERY_SIZE (16)
+
+#define ROCE_CQE_LEN (64)
+#define ROCE_CQE_LEN_SHIFT (6)
+#define ROCE_RESIZE_CQE_LEN (64)
+
+#define ROCE_QPC_RRWC_SEG_SIZE (32)
+#define ROCE_QPC_RCC_SEG_SIZE (32)
+#define ROCE_QPC_SQPC_SEG_SIZE (64)
+#define ROCE_QPC_SQC_SEG_SIZE (64)
+#define ROCE_QPC_SQAC_SEG_SIZE (64)
+#define ROCE_QPC_RQC_SEG_SIZE (64)
+#define ROCE_QPC_QPCC_SEG_SIZE (32)
+#define ROCE_QPC_HW_SEG_SIZE (ROCE_QPC_RRWC_SEG_SIZE + ROCE_QPC_RCC_SEG_SIZE + \
+ ROCE_QPC_SQC_SEG_SIZE + ROCE_QPC_SQAC_SEG_SIZE + ROCE_QPC_RQC_SEG_SIZE + \
+ ROCE_QPC_QPCC_SEG_SIZE)
+#define ROCE_QPC_TIMER_SEG_SIZE (32)
+#define ROCE_QPC_SW_SEG_SIZE (192)
+#define ROCE_QPC_SW_DCQCN_SIZE (16)
+#define ROCE_QPC_SW_NOFAA_SIZE ROCE_QPC_QPCC_SEG_SIZE
+#define ROCE_QPC_SW_SQC_SIZE (20)
+#define ROCE_QPC_SW_SQAC_SIZE (36)
+#define ROCE_QPC_SW_RQC_SIZE (20)
+#define ROCE_QPC_SW_RQAC_SIZE (20)
+#define ROCE_QPC_SW_STGID_SIZE (68)
+
+#define ROCE_QPC_EXT_SW_SEG_SIZE (32)
+
+#define ROCE_QPC_RRWC_DW_SIZE (8)
+#define ROCE_QPC_RCC_DW_SIZE (8)
+#define ROCE_QPC_SQPC_DW_SIZE (16)
+#define ROCE_QPC_SQC_DW_SIZE (16)
+#define ROCE_QPC_SQAC_DW_SIZE (16)
+#define ROCE_QPC_RQC_DW_SIZE (16)
+#define ROCE_QPC_QPCC_DW_SIZE (8)
+#define ROCE_QPC_TIMER_DW_SIZE (8)
+#define ROCE_QPC_SW_DW_SIZE (48)
+#define ROCE_QPC_SW_DCQCN_DW_SIZE (8)
+#define ROCE_QPC_SW_NOFAA_DW_SIZE ROCE_QPC_QPCC_DW_SIZE
+
+#define ROCE_QPC_SW_SEG_DWORD_LEN (ROCE_QPC_SW_SEG_SIZE >> 2)
+#define ROCE_QPC_HW_SEG_DWORD_LEN (ROCE_QPC_HW_SEG_SIZE >> 2)
+#define ROCE_QPC_SW_DCQCN_DWORD_LEN (ROCE_QPC_SW_DCQCN_SIZE >> 2)
+#define ROCE_QPC_SW_NOFAA_DWORD_LEN (ROCE_QPC_SW_NOFAA_SIZE >> 2)
+#define ROCE_QPC_SW_STGID_DWORD_LEN (ROCE_QPC_SW_STGID_SIZE >> 2)
+#define ROCE_QPC_DWORD_LEN (ROCE_QPC_TABLE_SIZE >> 2)
+#define ROCE_MPT_DWORD_LEN (ROCE_MPT_TABLE_SIZE >> 2)
+#define ROCE_CQC_DWORD_LEN (ROCE_CQC_TABLE_SIZE >> 2)
+#define ROCE_SRQC_DWORD_LEN (ROCE_SRQC_TABLE_SIZE >> 2)
+#define ROCE_GID_DWORD_LEN (ROCE_GID_TABLE_SIZE >> 2)
+#define ROCE_CM_MAD_DWORD_LEN (ROCE_CM_MAD_MEG_LEN >> 2)
+
+#define ROCE_RDMARC_MAX_DATA_DW_LEN (ROCE_RDMARC_TABLE_SIZE >> 2)
+
+#define ROCE_SQ_WQE_SEND_TASK_SEG_LEN (16)
+#define ROCE_SQ_WQE_UD_SEND_TASK_SEG_LEN (64)
+#define ROCE_SQ_WQE_RDMA_TASK_SEG_LEN (32)
+#define ROCE_SQ_WQE_ATOMIC_TASK_SEG_LEN (32)
+#define ROCE_SQ_WQE_MASK_ATOMIC_CMPSWP_TASK_SEG_LEN (48)
+#define ROCE_SQ_WQE_SEND_WRITE_COM_TASK_SEG_LEN (16)
+
+/* ******************************************************** */
+enum ROCE_QP_CTX_OFF_E {
+ ROCE_CTX_RRWC_OFF = 0,
+ ROCE_CTX_RCC_OFF = 32,
+ ROCE_CTX_SQC_OFF = 64,
+ ROCE_CTX_SQAC_OFF = 128,
+ ROCE_CTX_RQC_OFF = 192,
+ ROCE_CTX_QPCC_OFF = 256,
+ ROCE_CTX_TIMER_OFF = 288,
+ ROCE_CTX_SW_OFF = 320,
+ ROCE_CTX_SW_SQC_OFF = 400,
+ ROCE_CTX_SW_SQAC_OFF = 416,
+ ROCE_CTX_SW_RQC_OFF = 448,
+ ROCE_CTX_SW_RQAC_OFF = 464
+};
+#define ROCE_CTX_SQPC_OFF ROCE_CTX_RRWC_OFF
+
+#define ROCE_MISC_RRWC_OFFSET_16B_ALIGN (ROCE_CTX_RRWC_OFF >> 4)
+#define ROCE_MISC_RCC_OFFSET_16B_ALIGN (ROCE_CTX_RCC_OFF >> 4)
+#define ROCE_MISC_SQC_OFFSET_16B_ALIGN (ROCE_CTX_SQC_OFF >> 4)
+#define ROCE_MISC_SQAC_OFFSET_16B_ALIGN (ROCE_CTX_SQAC_OFF >> 4)
+#define ROCE_MISC_RQC_OFFSET_16B_ALIGN (ROCE_CTX_RQC_OFF >> 4)
+#define ROCE_MISC_QPCC_OFFSET_16B_ALIGN (ROCE_CTX_QPCC_OFF >> 4)
+#define ROCE_MISC_TIMERC_OFFSET_16B_ALIGN (ROCE_CTX_TIMER_OFF >> 4)
+#define ROCE_MISC_SW_OFFSET_16B_ALIGN (ROCE_CTX_SW_OFF >> 4)
+#define ROCE_MISC_SW_OFFSET64_16B_ALIGN ((ROCE_CTX_SW_OFF + 64) >> 4)
+#define ROCE_MISC_SW_OFFSET128_16B_ALIGN ((ROCE_CTX_SW_OFF + 128) >> 4)
+#define ROCE_MISC_SQPC_OFFSET_16B_ALIGN (ROCE_CTX_SQPC_OFF >> 4)
+
+#ifdef NOF_ROCE_AA_MODE_EN
+#define ROCE_WB_CTX_SIZE QU_WB_CTX_SIZE_224
+#else
+#define ROCE_WB_CTX_SIZE QU_WB_CTX_SIZE_192
+#endif
+
+#define ROCE_RDMARC_ATOMIC_DATA_LEN (8)
+
+#define ROCE_RDMARC_ATOMIC_DATA_DW_LEN (16 >> 2)
+#define ROCE_RDMARC_ATOMIC_STATUS_DW_LEN (4 >> 2)
+#define ROCE_RDMARC_ATOMIC_DATA_DW_OFF (16 >> 2)
+#define ROCE_RDMARC_ATOMIC_STATUS_DW_OFF (28 >> 2)
+/* ************************************************* */
+#define ROCE_QPCC_RXE_DW_OFF (4)
+#define ROCE_QPCC_RXE_DW_BITMASK (0X01C00000)
+#define ROCE_RCC_RXE_DW_OFF (7)
+#define ROCE_RRWC_RXE_DW_OFF (7)
+#define ROCE_RCC_RAE_DW_BITMASK (~0X08000000)
+#define ROCE_RCC_RRE_DW_BITMASK (~0X04000000)
+#define ROCE_RRWC_RWE_DW_BITMASK (~0X08000000)
+
+#define ROCE_QP_QPCC_GPAH_DW_OFF (6)
+#define ROCE_QP_QPCC_GPAH_DW_BITMASK (~0X00FFFFFF)
+#define ROCE_QP_QPCC_GPAL_DW_BITMASK (~0XFFFFFFFF)
+
+#define ROCE_QP_RCC_RCPI_DW_OFF (5)
+#define ROCE_QP_RCC_RCPI_DW_BITMASK (~0X000000FF)
+#define ROCE_QP_RCC_RCCI_DW_BITMASK (~0X000000FF)
+
+#define ROCE_QP_COM_STATE_DW_BITMASK (~0Xf0000000)
+
+#define ROCE_QP_RCC_STATE_DW_OFF (7)
+#define ROCE_QP_RCC_STATE_DW_BITMASK (~0Xf0000000)
+
+#define ROCE_QP_SQC_STATE_DW_OFF (2)
+#define ROCE_QP_SQC_STATE_DW_BITMASK (~0Xf0000000)
+
+#define ROCE_QP_SQAC_STATE_DW_OFF (2)
+#define ROCE_QP_SQAC_STATE_DW_BITMASK (~0Xf0000000)
+
+#define ROCE_QP_SQAC_WQEIDX_DW_OFF (2)
+#define ROCE_QP_SQAC_WQEIDX_DW_BITMASK (~0X0000ffff)
+
+#define ROCE_QP_RQC_STATE_DW_OFF (2)
+#define ROCE_QP_RQC_STATE_DW_BITMASK (~0Xf0000000)
+
+#define ROCE_QP_RRWC_STATE_DW_OFF (7)
+#define ROCE_QP_RRWC_STATE_DW_BITMASK (~0Xf0000000)
+
+#define ROCE_QP_RQC_SGEVLD_DW_OFF (0)
+#define ROCE_QP_RQC_SGEVLD_DW_BITMASK (~0X80000000)
+
+#define ROCE_MPT_STATE_DW_OFF (2)
+#define ROCE_MPT_STATE_DW_BITMASK (~0Xf0000000)
+
+#define ROCE_MPT_MWCNT_DW_OFF (10)
+#define ROCE_MPT_MWCNT_DW_BITMASK (~0Xffffffff)
+
+#define ROCE_SRQC_STATE_DW_OFF (2)
+#define ROCE_SRQC_STATE_DW_BITMASK (~0Xf0000000)
+
+#define ROCE_CQC_STATE_DW_OFF (2)
+#define ROCE_CQC_STATE_DW_BITMASK (~0Xf0000000)
+
+#define ROCE_CQC_TIMEOUT_DW7_OFF (7)
+#define ROCE_CQC_TIMEOUT_DW7_BITMASK (~0Xffffffff)
+
+#define ROCE_CQC_TMR_TWID_DW10_OFF (10)
+#define ROCE_CQC_TMR_TWID_DW_BITMASK (~0Xffff0000)
+
+#define ROCE_SRQC_ERR_STATE (0x10000000)
+#define ROCE_QPC_RQ_COMM_EST_OFF (27) /* *keep the same with qpc rq DW22 */
+
+#define ROCE_RRWC_SGE_VLD (0x80000000)
+
+#define ROCE_VLAN 1
+
+#endif /* ROCE_CTX_API_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_dif_format.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_dif_format.h
new file mode 100644
index 0000000000000..87e4e303f6842
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_dif_format.h
@@ -0,0 +1,492 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_DIF_FORMAT_H
+#define ROCE_DIF_FORMAT_H
+
+#include "roce_wqe_format.h"
+#include "roce_xqe_format.h"
+#include "roce_verbs_mr_attr.h"
+
+struct tag_roce_dif_cqe_s {
+ // roce_cqe_s roce_cqe;
+ u32 common[8]; /* dif multiplexes the first 32 Bits of standard cqe */
+ u32 timestamp_h;
+ u32 timestamp_l;
+ u32 mr_lkey;
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd1 : 4;
+ u32 app_err : 1;
+ u32 ref_err : 1;
+ u32 grd_err : 1;
+ u32 rsvd2 : 17;
+ u32 rcv_pi_vb : 8;
+#else
+ u32 rcv_pi_vb : 8;
+ u32 rsvd2 : 17;
+ u32 grd_err : 1;
+ u32 ref_err : 1;
+ u32 app_err : 1;
+ u32 rsvd1 : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw11;
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rcv_pi_h;
+ u32 rcv_pi_l;
+#else
+ u32 rcv_pi_l;
+ u32 rcv_pi_h;
+#endif
+ } bs;
+ u64 value;
+ } rcv_pi;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 vrf_agm_imm : 16;
+ u32 ri_agm_imm : 16;
+#else
+ u32 ri_agm_imm : 16;
+ u32 vrf_agm_imm : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw14;
+ u32 rsvd3;
+};
+
+struct tag_roce_dif_com_s {
+ struct tag_roce_dif_user_data_s *dif_data;
+
+ u32 sd_pdu_ofs;
+ u32 sd_pdu_len;
+
+ u16 difx_cnt;
+ u16 mss;
+ u16 metadata_len;
+ u16 sector_len;
+};
+
+union tag_roce_dif_misc_rx_s {
+ struct {
+ u32 rsvd : 18;
+ u32 fst_bt_tp : 1;
+ u32 fst_sector : 1;
+ u32 fst_bt_ofs : 12;
+ } bs;
+ u32 value;
+};
+
+struct tag_roce_dif_wqe_rdma_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 data_len;
+
+ /* DW2 */
+ u32 imm_data;
+
+ /* DW3 */
+ u32 rsvd1;
+
+ /* DW4~5 */
+ union {
+ u64 va;
+ struct {
+ u32 va_h32;
+ u32 va_l32;
+ } dw4;
+ };
+
+ /* DW6 */
+ u32 rkey;
+ struct tag_roce_dif_user_data_s dif_data;
+ /* DW7 */
+ // u32 sig_key;
+};
+
+struct tag_roce_dif_wqe_snd_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW0 */
+ u32 data_len; /* Length of the data sent by the SQ WQE */
+
+ /* DW1 */
+ /* This parameter is valid for the immediate data operation or SEND invalidate. */
+ u32 immdata_invkey;
+
+ struct tag_roce_dif_user_data_s dif_data;
+};
+
+
+/* REG SIG MR Local WQE */
+struct roce_wqe_reg_sig_mr_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rre : 1; /* Remote read enable */
+ u32 rwe : 1; /* Remote write enable */
+ u32 lwe : 1; /* Local write enable */
+ u32 sgl_mode : 1; /* 0: Single SGL, 1: Dual SGL */
+ u32 sector_size : 1; /* 0 : 512B, 1: 4096B */
+ u32 rsvd1 : 3;
+ /* Block size, which is the same as the MPT data definition. */
+ u32 block_size : 6;
+ u32 rsvd2 : 18;
+#else
+ u32 rsvd2 : 18;
+ /* Block size, which is the same as the MPT data definition. */
+ u32 block_size : 6;
+ u32 rsvd1 : 3;
+ u32 sector_size : 1; /* 0 : 512B, 1: 4096B */
+ u32 sgl_mode : 1; /* 0: Single SGL, 1: Dual SGL */
+ u32 lwe : 1; /* Local write enable */
+ u32 rwe : 1; /* Remote write enable */
+ u32 rre : 1; /* Remote read enable */
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ u32 sig_mr_mkey;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 10;
+ u32 mtt_offset : 22;
+#else
+ u32 mtt_offset : 22;
+ u32 rsvd : 10;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+ struct tag_roce_dif_user_data_s dif_data;
+ u32 data_mr_key;
+ u32 metadata_mr_key;
+ u32 rsvd1;
+};
+
+
+struct roce_wqe_reg_mr_dsgl_seg {
+ struct roce_wqe_reg_sig_mr_seg reg_mr_seg;
+ struct roce3_sge_info data_sge;
+ struct roce3_sge_info prot_sge;
+};
+
+struct roce_dif_ssgl_mpt_context {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+ u32 mtt_layer_num : 3; /* Mtt level */
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 rsvd2 : 4;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ /* The value 1 indicates that the remote Atomic permission is supported. */
+ u32 access_ra : 1;
+ u32 bpd : 1; /* 1: Bound to pd */
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 rsvd1 : 1;
+ u32 rkey : 1;
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ /* Mr or mw. The value 1 indicates MR, and the value 0 indicates MW. */
+ u32 r_w : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ /* Whether the mr supports the binding of the mw */
+ u32 access_bind : 1;
+#else
+ /* Whether the mr supports the binding of the mw */
+ u32 access_bind : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ u32 r_w : 1; /* Mr or mw */
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ u32 rkey : 1;
+ u32 rsvd1 : 1;
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 bpd : 1; /* 1: Bound to pd */
+ /* The value 1 indicates that the remote Atomic permission is supported. */
+ u32 access_ra : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ u32 rsvd2 : 4;
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 mtt_layer_num : 3; /* Number of mtt levels */
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 so_ro : 2; /* Dma sequence preserving flag */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 ep : 3;
+ u32 qpn : 20; /* Qp bound to the mw. */
+#else
+ u32 qpn : 20; /* Qp bound to mw */
+ u32 ep : 3;
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 so_ro : 2; /* Dma order-preserving flag */
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+ u32 indirect_mr : 1;
+ u32 cos : 3;
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 pdn : 18; /* Pd bound to mr or mw */
+#else
+ u32 pdn : 18; /* Pd bound to mr or mw */
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 cos : 3;
+ u32 indirect_mr : 1; /* If set, indicates this MPT is double SGL type. */
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 mkey : 8; /* The index is not included. */
+ u32 sw_dif_en : 1; /* If set, indicates dif mode. */
+ u32 page_mode : 1;
+ u32 fbo : 22;
+#else
+ u32 fbo : 22;
+ u32 page_mode : 1;
+ u32 sw_dif_en : 1; /* If set, indicates dif mode. */
+ u32 mkey : 8; /* The index is not included. */
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4~5 */
+ union {
+ u64 iova; /* Start address of mr or mw */
+ struct {
+ u32 iova_hi; /* Upper 32 bits of the start address of mr or mw */
+ u32 iova_lo; /* Lower 32 bits of the start address of mr or mw */
+ } dw4;
+ };
+
+ /* DW6~7 */
+ union {
+ u64 length; /* Length of mr or mw */
+ struct {
+ u32 length_hi; /* Length of mr or mw */
+ u32 length_lo; /* Length of mr or mw */
+ } dw6;
+ };
+
+ /* DW8~9 */
+ union {
+ u64 mtt_base_addr; /* Mtt base address (pa) */
+ struct {
+ u32 mtt_base_addr_hi; /* Mtt base address (pa) upper 32 bits */
+ u32 mtt_base_addr_lo; /* Lower 32 bits of mtt base address (pa) */
+ } dw8;
+ };
+
+ /* DW10 */
+ union {
+ u32 mr_mkey; /* This parameter is valid for MW. */
+ u32 mw_cnt; /* This parameter is valid when the MR is used. */
+ };
+ struct tag_roce_dif_user_data_s dif_data;
+};
+
+struct roce_dif_dsgl_mpt_context {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd6 : 11;
+ u32 signature : 4;
+ u32 rsvd5 : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ u32 rsvd4 : 1;
+ u32 bpd : 1; /* 1: Bound to pd */
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 rsvd3 : 1;
+ u32 rkey : 1;
+ u32 rsvd2 : 1;
+ /* Mr or mw. The value 1 indicates MR, and the value 0 indicates MW. */
+ u32 r_w : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ u32 rsvd0 : 1;
+ u32 rsvd1 : 1;
+ u32 access_bind : 1; /* Whether mr can be bound to mw */
+#else
+ u32 access_bind : 1; /* Whether the mr supports the binding of the mw */
+ u32 rsvd0 : 1;
+ u32 rsvd1 : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ u32 r_w : 1; /* Mr or mw */
+ u32 rsvd2 : 1;
+ u32 rkey : 1;
+ u32 rsvd3 : 1;
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 bpd : 1; /* 1: Bound to pd */
+ u32 rsvd4 : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ u32 rsvd5 : 1;
+ u32 signature : 4;
+ u32 rsvd6 : 11;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+ u32 rsvd;
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+ u32 status : 4;
+ u32 indirect_mr : 1; /* If set, indicates this MPT is double SGL type. */
+ u32 rsvd : 27;
+#else
+ u32 rsvd : 27;
+ u32 indirect_mr : 1; /* If set, indicates this MPT is double SGL type. */
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 mkey : 8; /* The index is not included. */
+ u32 sw_dif_en : 1; /* If set, indicates dif mode. */
+ u32 rsvd : 23;
+#else
+ u32 rsvd : 23;
+ u32 sw_dif_en : 1; /* If set, indicates dif mode. */
+ u32 mkey : 8; /* The index is not included. */
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 4;
+ u32 data_mr_key : 28;
+#else
+ u32 data_mr_key : 28;
+ u32 rsvd : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw4;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 4;
+ u32 metadata_mr_key : 28;
+#else
+ u32 metadata_mr_key : 28;
+ u32 rsvd : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6~DW9 */
+ u32 rsvd[4];
+
+ /* DW10 */
+ union {
+ u32 mr_mkey; /* This parameter is valid for MW. */
+ u32 mw_cnt; /* This parameter is valid when the MR is used. */
+ };
+ struct tag_roce_dif_user_data_s dif_data;
+};
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_err_type.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_err_type.h
new file mode 100644
index 0000000000000..f0a84b8ae58c0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_err_type.h
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_ERR_TYPE_H
+#define ROCE_ERR_TYPE_H
+
+#include "typedef.h"
+#include "roce_pub_cmd.h"
+#include "roce_api.h"
+
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif
+#endif /* __cplusplus */
+
+/* **********************macro define************************ */
+enum ROCE_ERR_STATE_E {
+ ROCE_AEQE_NOERR_STATE = 0,
+ ROCE_AEQE_ERR_STATE,
+};
+
+enum ROCE_QP_ERR_STATE_E {
+ ROCE_QP_NOERR_STATE = 0,
+ ROCE_QP_ERR_STATE,
+};
+
+/* *********ROCE_AEQE_SUBTYPE_E******* */
+enum ROCE_AEQE_SUBTYPE_E {
+ ROCE_AEQE_SUBTYPE_PATH_MIGRATED = 0, /* * APM */
+ ROCE_AEQE_SUBTYPE_COMM_ESTABLISHED, /* *RQ RTR RCV FIRST PKT */
+ ROCE_AEQE_SUBTYPE_SQ_DRAINED, /* * sq empty and change to SQ DRANNING STATE */
+ ROCE_AEQE_SUBTYPE_SRQ_LIMIT_REACHED, /* *SRQ LIMIT_REACHED from RXDMA api rsp */
+ ROCE_AEQE_SUBTYPE_QP_LAST_WQE_REACHED, /* *srq en & LAST_WQE_REACHED */
+ ROCE_AEQE_SUBTYPE_CQ_ERR, /* *api rsp cq err */
+ ROCE_AEQE_SUBTYPE_QP_FATAL, /* *LOC_WORK_QUEUE_CATASTROPHIC_ERR */
+ ROCE_AEQE_SUBTYPE_QP_REQ_ERR, /* *INVALID_REQ_LOC_WORK_QUEUE_ERR */
+ ROCE_AEQE_SUBTYPE_QP_ACCESS_ERR, /* *LOC_ACCESS_VIOLATION_WORK_QUEUE_ERR */
+ ROCE_AEQE_SUBTYPE_PATH_MIG_ERR,
+ ROCE_AEQE_SUBTYPE_GID_CHANGE_EVENT,
+ ROCE_AEQE_SUBTYPE_CQ_OVERRUN,
+ ROCE_AEQE_SUBTYPE_SRQ_CATASTROPHIC_ERR,
+ ROCE_AEQE_SUBTYPE_CFG_ERR,
+ ROCE_AEQE_SUBTYPE_CHIP_ERR,
+ ROCE_AEQE_SUBTYPE_DIF_ERR,
+ ROCE_AEQE_SUBTYPE_XRC_DOMAIN_VIOLATION_ERR,
+ ROCE_AEQE_SUBTYPE_INVALID_XRCETH_ERR,
+ ROCE_AEQE_SUBTYPE_UCODE_FATAL_ERR,
+ ROCE_AEQE_SUBTYPE_ODP_PAGE_FAULT,
+ ROCE_AEQE_SUBTYPE_RSVD,
+};
+
+/* *********ROCE SQ ERR type******* */
+enum ROCE_COMPLETION_EVENT_ERR_TYPE_E {
+ ROCE_COMPLTE_EVENT_NO_ERR = 0,
+ ROCE_COMPLTE_EVENT_LOC_LEN_ERR = 0x1,
+ ROCE_COMPLTE_EVENT_LOC_QP_OPERATION_ERR,
+ ROCE_COMPLTE_EVENT_LOC_PROTECTION_ERR = 0x4,
+ ROCE_COMPLTE_EVENT_LOC_MEM_MANAGEMENT_ERR = 0x4,
+ ROCE_COMPLTE_EVENT_WR_FLUSH_ERR,
+ ROCE_COMPLTE_EVENT_MW_BIND_ERR,
+ ROCE_COMPLTE_EVENT_BAD_RESP_ERR = 0x10,
+ ROCE_COMPLTE_EVENT_LOC_ACCESS_ERR,
+ ROCE_COMPLTE_EVENT_REM_INV_REQ_ERR,
+ ROCE_COMPLTE_EVENT_REM_ACCESS_ERR,
+ ROCE_COMPLTE_EVENT_REM_OPERATION_ERR,
+ ROCE_COMPLTE_EVENT_RETRY_CTR_EXCEED_ERR,
+ ROCE_COMPLTE_EVENT_RNR_RETRY_CTR_EXCEED_ERR,
+ ROCE_COMPLTE_EVENT_REM_ABORTED_ERR = 0x22,
+ ROCE_COMPLTE_EVENT_XRC_VIOLATION_ERR,
+};
+
+enum ROCE_AEQE_EVENT_ERR_TYPE_E {
+ ROCE_AEQE_QP_FATAL_SQ_FETCH_WQE_STATUS_ERR = 0,
+ ROCE_AEQE_QP_FATAL_SQ_DMA_GEN_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_SQ_DMA_GEN_MPT_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_SQ_DMA_GEN_CQ_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_SQ_COMPLETE_WQE_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_SQ_COMPLETE_CQ_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_RQ_RXDMA_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_RQ_RXDMA_MPT_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_RQ_RXDMA_CQ_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_RQ_RXDMA_SRQ_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_RQ_RDMA_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_RQ_RDMA_MPT_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_CQ_CQE_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_CQ_ARM_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_SRQ_ARM_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_RDMARC_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_RDMARC_RSP_PSN_ERR = 0x10,
+ ROCE_AEQE_QP_FATAL_MINVLD_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_CQ_RESIZE_STATUS_ERR,
+ ROCE_AEQE_QP_FATAL_CQ_OVERFLOW,
+ ROCE_AEQE_CFG_TYPE_STATELESS_MAC = 0x20,
+ ROCE_AEQE_CFG_TYPE_STATELESS_FUNC,
+ ROCE_AEQE_CFG_TYPE_QPC_PREFETCH_RSP_ERR,
+ ROCE_AEQE_CFG_TYPE_QPC_STATE_ERR,
+ ROCE_AEQE_CFG_TYPE_QPC_STATE_NOT_RTS,
+ ROCE_AEQE_CHIP_TYPE_CPB_BUF_FULL,
+ ROCE_AEQE_CHIP_TYPE_IPSU_RSP_ERR,
+ ROCE_AEQE_CHIP_TYPE_QU_QUERY_RSP_ERR,
+ ROCE_AEQE_LOC_QP_REQ_ERR_TOO_MANY_READ_ATOMIC = 0x30,
+ ROCE_AEQE_LOC_QP_REQ_ERR_OPCODE_MISMATCH,
+ ROCE_AEQE_LOC_QP_REQ_ERR_LEN_ERR,
+ ROCE_AEQE_LOC_QP_OPERATION_ERR,
+ ROCE_AEQE_LOC_QP_NUM_RANGE_ERR,
+ ROCE_AEQE_MPT_NUM_RANGE_ERR,
+ ROCE_AEQE_MASTER_QP_MODIFY_ERR,
+};
+
+#define ROCE_AEQE_EVENT(module_type, subtype, type, err_code) \
+ (((u32)(module_type) << 28) | ((subtype) << 20) | ((type) << 8) | (err_code))
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+
+#endif /* ROCE_ERR_TYPE_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_hmm_context.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_hmm_context.h
new file mode 100644
index 0000000000000..93cdad34e3ed0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_hmm_context.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_HMM_CONTEXT_H
+#define ROCE_HMM_CONTEXT_H
+
+/* **************** Macro Definition ****************** */
+#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
+
+/* **************** Data Structure Definition ****************** */
+/* * MPT Format start */
+struct roce_mpt_context {
+ /* DW0 */
+ union {
+ struct {
+#if (BYTE_ORDER != BIG_ENDIAN)
+ u32 access_bind : 1; /* Whether mr can be bound to mw */
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ u32 r_w : 1; /* Mr or mw */
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ u32 rkey : 1;
+ u32 dif_mode : 1;
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 bpd : 1; /* 1: Bound to pd */
+ /* The value 1 indicates that the remote Atomic permission is supported. */
+ u32 access_ra : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ u32 signature : 4;
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 mtt_layer_num : 3; /* Mtt level */
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+#else
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+ u32 mtt_layer_num : 3; /* Number of mtt levels */
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 signature : 4;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ /* The value 1 indicates that the remote Atomic permission is supported. */
+ u32 access_ra : 1;
+ u32 bpd : 1; /* 1: Bound to pd */
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 dif_mode : 1;
+ u32 rkey : 1;
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ /* Mr or mw. The value 1 indicates MR, and the value 0 indicates MW. */
+ u32 r_w : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether the FRMR can specify the remote authority. */
+ u32 remote_access_en : 1;
+ u32 access_bind : 1; /* Whether mr can be bound to mw */
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if (BYTE_ORDER != BIG_ENDIAN)
+ u32 qpn : 20; /* Qp bound to mw */
+ u32 ep : 3;
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 so_ro : 2; /* Dma order-preserving flag */
+#else
+ u32 so_ro : 2; /* Dma sequence preserving flag */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 ep : 3;
+ u32 qpn : 20; /* Qp bound to mw */
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if (BYTE_ORDER != BIG_ENDIAN)
+ u32 pdn : 18; /* Pd bound to mr or mw */
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 cos : 3;
+ u32 indirect_mr : 1;
+ /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+ u32 status : 4;
+#else
+ /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+ u32 status : 4;
+ u32 indirect_mr : 1; /* indirect mr flag */
+ u32 cos : 3;
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 pdn : 18; /* Pd bound to mr or mw */
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if (BYTE_ORDER != BIG_ENDIAN)
+ u32 fbo : 22;
+ u32 page_mode : 1;
+ u32 sgl_mode : 1; /* Set indicates this MPT is double SGL type. */
+ u32 mkey : 8; /* The index is not included. */
+#else
+ u32 mkey : 8; /* The index is not included. */
+ u32 sgl_mode : 1; /* Set indicates this MPT is double SGL type. */
+ u32 page_mode : 1;
+ u32 fbo : 22;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4~5 */
+ union {
+ u64 iova; /* Start address of mr or mw */
+ struct {
+ u32 iova_hi; /* Upper 32 bits of the start address of mr or mw */
+ u32 iova_lo; /* Lower 32 bits of the start address of mr or mw */
+ } dw4;
+ };
+
+ /* DW6~7 */
+ union {
+ u64 length; /* Length of mr or mw */
+ struct {
+ u32 length_hi; /* Length of mr or mw */
+ u32 length_lo; /* Length of mr or mw */
+ } dw6;
+ };
+
+ /* DW8~9 */
+ union {
+ /* Mtt base address (pa)hi:bit[63:32], lo:bit[31:03], gpa_sign[02:00] */
+ u64 mtt_base_addr;
+ struct {
+ u32 mtt_base_addr_hi; /* Mtt base address (pa) upper 32 bits */
+ u32 mtt_base_addr_lo; /* Mtt base address (pa) lower 32 bits */
+ } dw8;
+ };
+
+ /* DW10 */
+ union {
+ u32 mr_mkey; /* This parameter is valid for MW. */
+ u32 mw_cnt; /* This parameter is valid when the MR is used. */
+ };
+
+ /* DW11 */
+ u32 mtt_sz; /* This parameter is valid when FRMR. */
+
+ /* DW12~DW13 */
+ u32 rsvd[2];
+
+ /* DW14~15 */
+ union {
+ /* Mtt base address (pa)hi:bit[63:32], lo:bit[31:03], gpa_sign[02:00] */
+ u64 mw_vaddr;
+ struct {
+ u32 mw_vaddr_hi; /* Mtt base address (pa) upper 32 bits */
+ u32 mw_vaddr_lo; /* Mtt base address (pa) lower 32 bits */
+ } dw14;
+ struct {
+ u32 mw_vaddr_hi; /* Mtt base address (pa) upper 32 bits */
+ u32 mw_vaddr_lo; /* Mtt base address (pa) lower 32 bits */
+ } dw15;
+ };
+};
+
+#endif
+
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_mpu_common.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_mpu_common.h
new file mode 100644
index 0000000000000..13bc6ef88e5ef
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_mpu_common.h
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_MPU_COMMON_H
+#define ROCE_MPU_COMMON_H
+
+#include "mpu_cmd_base_defs.h"
+
+enum {
+ /* FUNC CFG */
+ ROCE_MPU_CMD_SET_FUNC_STATE = 0,
+ ROCE_MPU_CMD_SET_CPU_ENDIAN,
+ ROCE_MPU_CMD_GET_CFG_INFO,
+ ROCE_MPU_CMD_DEL_FUNC_RES,
+ ROCE_MPU_CMD_GET_FUNC_TABLE,
+ ROCE_MPU_CMD_ADD_MAC = 10,
+ ROCE_MPU_CMD_DEL_MAC,
+ ROCE_MPU_CMD_ADD_IPSU_MAC,
+ ROCE_MPU_CMD_DEL_IPSU_MAC,
+ ROCE_MPU_CMD_GET_MAC_VNI,
+
+ /* BOND */
+ ROCE_MPU_CMD_BOND_SET_STATE = 20,
+ ROCE_MPU_CMD_BOND_GET_ER_FWD_ID,
+ ROCE_MPU_CMD_BOND_SET_ER_FWD_ID,
+ ROCE_MPU_CMD_BOND_ER_FWD_ID_COMBINE,
+ ROCE_MPU_CMD_BOND_ER_FWD_ID_COMPACT,
+ ROCE_MPU_CMD_GET_GROUP_ID,
+
+ /* CC */
+ ROCE_MPU_CMD_CC_CFG_CCF_PARAM = 40,
+ ROCE_MPU_CMD_CC_CFG_DCQCN_PARAM,
+ ROCE_MPU_CMD_CC_CFG_IPQCN_PARAM,
+ ROCE_MPU_CMD_CC_CFG_LDCP_PARAM,
+ ROCE_MPU_CMD_CC_SET_BW_CTRL,
+ ROCE_MPU_CMD_CC_QUERY_BW_CTRL,
+
+ /* DFX */
+ ROCE_MPU_CMD_DFX_CACHE_OUT = 55,
+ ROCE_MPU_CMD_DFX_SET_CAP_CFG,
+ ROCE_MPU_CMD_DFX_GET_CAP_CFG,
+ ROCE_MPU_CMD_DFX_READ_CAP_CTR,
+ ROCE_MPU_CMD_DFX_CLEAR_CAP_CTR,
+
+ /* ULP */
+ ROCE_MPU_CMD_ULP_AA_SET_DD_CFG = 128,
+ ROCE_MPU_CMD_ULP_AA_CTRL_READY,
+ ROCE_MPU_CMD_ULP_AA_SWITCH_IO,
+ ROCE_MPU_CMD_ULP_AA_FAKE_DATA,
+ ROCE_MPU_CMD_ULP_AA_CLAER_ACT_CTRL_BMP,
+
+ ROCE_MPU_CMD_MAX
+};
+
+#define MAX_ROCE_PHY_PORT 8
+
+/* *********************** Func cmd between driver and mpu ************************** */
+struct roce_set_func_state_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u8 func_en;
+ u8 tag;
+};
+
+struct roce_get_func_table_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u8 rsvd[2];
+};
+
+struct roce_get_func_table_rsp {
+ struct comm_info_head head;
+ u32 func_tbl_value;
+};
+
+struct roce_get_cfg_info_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u8 rsvd[2];
+};
+
+struct roce_get_cfg_info_resp {
+ struct comm_info_head head;
+
+ u8 scence_id;
+ u8 lb_en;
+ u8 lb_mode;
+ u8 container_mode;
+
+ u8 fake_en;
+ u8 pf_start_bit;
+ u8 pf_end_bit;
+ u8 page_bit;
+
+ u8 port_num;
+ u8 host_num;
+ u16 rsvd;
+};
+
+struct roce_set_cpu_endian_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u8 cpu_endian;
+ u8 rsvd;
+};
+
+struct roce_cfg_mac_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u16 rsvd;
+ u16 er_fwd_id;
+ u8 mac[6];
+ u8 vni_en;
+ u32 vlan_id;
+};
+
+struct roce_cfg_ipsu_mac_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u8 er_id;
+ u8 vni_en; /* vni enable */
+ u8 mac[6];
+ u8 rsvd[2];
+ u32 vlanid_vni;
+};
+
+struct vroce_mac_cfg_vni_info {
+ struct comm_info_head head;
+ u16 func_id;
+ u16 rsvd;
+
+ u32 vlan_vni : 24;
+ u32 vni_en : 8;
+};
+
+/* ************************* Bond cmd between driver and mpu ************************* */
+struct roce_bond_cfg_state_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u8 bond_en;
+ u8 rsvd;
+};
+
+struct roce_bond_set_ipsu_mac_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u16 vlan_id;
+ u16 er_fwd_id;
+ u8 mac[6];
+};
+
+struct roce_bond_cfg_er_fwd_id_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u16 er_fwd_id;
+ u32 bond_tbl_val;
+};
+
+struct roce_bond_combine_er_fwd_id_cmd {
+ struct comm_info_head head;
+ u16 func_id_src;
+ u16 func_id_dst;
+ u16 er_fwd_id;
+ u8 rsvd[2];
+};
+
+struct roce_bond_compact_er_fwd_id_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u16 rsvd;
+ u32 value; /* dw14 value */
+};
+
+/* ************************* CC cmd between driver and mpu ************************** */
+struct roce_cc_cfg_param_cmd {
+ struct comm_info_head head;
+ u16 func_id;
+ u16 rsvd;
+ u32 param[4];
+};
+
+struct roce_cc_cfg_bw_ctrl_cmd {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u8 cmd;
+ u8 rsvd;
+
+ u8 color_type;
+ u16 ptype;
+ u8 hw_wred_mode;
+
+ u32 cir;
+ u32 pir;
+ u32 cbs;
+ u32 xbs;
+ u32 cnp;
+ u32 enable;
+};
+
+/* *************************** DFX cmd between driver and mpu ***************************** */
+struct roce_dfx_cache_out_cmd {
+ struct comm_info_head head;
+
+ u16 func_idx;
+ u8 cache_index;
+ u8 rsvd;
+};
+
+struct roce_dfx_cfg_cap_param_cmd {
+ struct comm_info_head head;
+ u16 index;
+ u16 rsvd;
+ u32 param[4];
+};
+
+struct roce_dfx_cap_ctr_cmd {
+ struct comm_info_head head;
+ u16 index;
+ u16 rsvd;
+ u32 value;
+};
+
+#endif /* ROCE_MPU_COMMON_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_pub.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_pub.h
new file mode 100644
index 0000000000000..dfcc6e7bc0998
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_pub.h
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_PUB_H
+#define ROCE_PUB_H
+
+#include "rdma_context_format.h"
+
+
+/* ********************** sync info ************************ */
+#define ROCE_SQC_RST_STATE (0x0)
+#define ROCE_SQAC_RST_STATE (0x0)
+#define ROCE_RQC_RST_STATE (0x0)
+#define ROCE_RCC_RST_STATE (0x0)
+#define ROCE_RRWC_RST_STATE (0x0)
+
+#define ROCE_QPC_DELED_STATE (0xCE)
+#define ROCE_RC_KICKOFF_VALUE (0x5a5acece)
+#define ROCE_CACHE_LINE_SIZE (0x100)
+
+#define ROCE_CQC_MID_STATE_VALUE (0xe)
+#define ROCE_CQC_MID_STATE (0xe0000000)
+
+#define ROCE_CPU_ENDIAN_LITTLE 0
+
+#define ROCE_MAX_ARM_SN_NUM 4
+
+#define ROCE_MKEY_MPT_IDX_OFF (8)
+#define ROCE_MKEY_GET_MPT_IDX(mkey) ((mkey) >> ROCE_MKEY_MPT_IDX_OFF)
+
+#define ROCE_PAGE_SIZE 4096
+#define ROCE_RC_ENTRY_NUM_PER_CACELINE 8
+#define ROCE_MTT_BUFLEN_TOTAL(mtt_num) ((mtt_num) << 3)
+
+#define ROCE_SQWQE_CI_MASK (0xffff)
+
+#define ROCE_GID_LEN 16
+
+#define ROCE_LOCAL_DEFAULT_PMTU 5
+#define ROCE_LOCAL_DEFAULT_MTU_CODE 0xf
+
+enum {
+ ROCE_QP_ST_RC = 0x0, /* 000 */
+ ROCE_QP_ST_UC = 0x1, /* 001 */
+ ROCE_QP_ST_RD = 0x2, /* 010 */
+ ROCE_QP_ST_UD = 0x3, /* 011 */
+ ROCE_QP_ST_XRC = 0x6, /* 110 */
+ ROCE_QP_ST_PRIV = 0x7 /* 111 */
+};
+/* ********************** Macro Definition ************************ */
+
+enum ROCE_SERVICE_TYPE_E {
+ ROCE_RC_TYPE = 0,
+ ROCE_UC_TYPE,
+ ROCE_RD_TYPE,
+ ROCE_UD_TYPE,
+ ROCE_RSVD_TYPE,
+ ROCE_XRC_5_TYPE = 0x5,
+ ROCE_XRC_TYPE = 0x6,
+ ROCE_XRC_6_TYPE = 0x6
+};
+
+enum ROCE_RC_FLAG_E {
+ ROCE_UC_UD = 0,
+ ROCE_RC_XRC
+};
+
+/* Description of parameters in the *********ROCE table ******* */
+/* the same with stp */
+enum ROCE_GID_TYPE_E {
+ ROCE_GID_TYPE_V2_IPV4 = 0,
+ ROCE_GID_TYPE_V2_IPV6 = 1,
+ ROCE_GID_TYPE_V1 = 2
+};
+
+enum ROCE_SQWQE_MSGTYPE_E {
+ ROCE_TX_MSGTYPE_SEND = 0,
+ ROCE_TX_MSGTYPE_WRITE,
+ ROCE_TX_MSGTYPE_READ,
+ ROCE_TX_MSGTYPE_ATOMIC,
+ ROCE_TX_MSGTYPE_LOCAL,
+ ROCE_TX_MSGTYPE_RESIZECQ = 5,
+ ROCE_TX_MSGTYPE_RSVD6 = 6,
+ ROCE_TX_MSGTYPE_ERR = 7
+};
+
+enum ROCE_SQWQE_OPTYPE_E {
+ ROCE_TX_SEND = 0,
+ ROCE_TX_SEND_INVALIDATE,
+ ROCE_TX_SEND_IMMEDIATE,
+ ROCE_TX_OPTYPE_RSVD3,
+
+ ROCE_TX_WRITE = 4,
+ ROCE_TX_WRITE_IMMEDIATE,
+ ROCE_TX_OPTYPE_RSVD6,
+ ROCE_TX_OPTYPE_RSVD7,
+
+ ROCE_TX_READ = 8,
+ ROCE_TX_OPTYPE_RSVD9,
+ ROCE_TX_OPTYPE_RSVD10,
+ ROCE_TX_EXT_ATOMIC_COMPARE_SWAP,
+
+ ROCE_TX_ATOMIC_COMPARE_SWAP = 0xc,
+ ROCE_TX_ATOMIC_FETCH_ADD,
+ ROCE_TX_ATOMIC_MASKED_COMPARE_SWAP,
+ ROCE_TX_ATOMIC_MASKED_FETCH_ADD,
+
+ ROCE_FAST_REG_PMR = 0x10,
+ ROCE_LOCAL_INVALIDATE,
+ ROCE_BIND_MW_TYPE1_TYPE2,
+ ROCE_REG_SIG_MR,
+ ROCE_LOCAL_EXT,
+ ROCE_TX_OPTYPE_RSVD15,
+ ROCE_RESIZE_TYPE = 0x16,
+ ROCE_TX_OPTYPE_RSVD17,
+ ROCE_TX_OPTYPE_RSVD18,
+ ROCE_TX_OPTYPE_RSVD19,
+ ROCE_TX_OPTYPE_RSVD1A,
+ ROCE_TX_OPTYPE_RSVD1B,
+ ROCE_TX_OPTYPE_RSVD1C,
+ ROCE_TX_OPTYPE_RSVD1D,
+ ROCE_ERR_TYPE = 0x1e,
+ ROCE_TX_OPTYPE_RSVD1F
+};
+
+enum ROCE_SQPC_STATE_E {
+ ROCE_SQPC_STATE_SW = 0,
+ ROCE_SQPC_STATE_ERR = 1,
+ ROCE_SQPC_STATE_HW = 0xF
+};
+
+enum ROCE_SRQC_STATE_E {
+ ROCE_SRQC_STATE_SW = 0,
+ ROCE_SRQC_STATE_ERR = 1,
+ ROCE_SRQC_STATE_HW = 0xF
+};
+
+enum ROCE_CQC_STATE_E {
+ ROCE_CQC_STATE_SW = 0,
+ ROCE_CQC_STATE_ERR = 1,
+ ROCE_CQC_STATE_OVERFLOW = 2,
+ ROCE_CQC_STATE_HW = 0xF
+};
+
+enum ROCE_MPT_STATE_E {
+ ROCE_MPT_STATE_VALID = 1,
+ ROCE_MPT_STATE_FREE = 3,
+ ROCE_MPT_STATE_ABORT = 4,
+ ROCE_MPT_STATE_INVALID = 0xF
+};
+
+enum ROCE_MPT_R_W_E {
+ ROCE_MPT_MW = 0,
+ ROCE_MPT_MR
+};
+
+enum ROCE_MPT_BQP_E {
+ ROCE_MPT_BQP_TYPE1 = 0,
+ ROCE_MPT_BQP_TYPE2B
+};
+
+enum ROCE_MPT_DIF_MODE_E {
+ ROCE_MPT_DIF_MODE_INS = 0,
+ ROCE_MPT_DIF_MODE_DEL,
+ ROCE_MPT_DIF_MODE_FWD
+};
+
+enum ROCE_MPT_SECTOR_SIZE_E {
+ ROCE_MPT_SECTOR_SIZE_512 = 0,
+ ROCE_MPT_SECTOR_SIZE_4KB
+};
+
+enum ROCE_MPT_METEDATA_SIZE_E {
+ ROCE_MPT_METEDATA_SIZE_8 = 0,
+ ROCE_MPT_METEDATA_SIZE_64
+};
+
+
+enum ROCE_MPT_SGL_MODE_E {
+ ROCE_MPT_SGL_MODE_SINGLE = 0,
+ ROCE_MPT_SGL_MODE_DOUBLE
+};
+
+enum ROCE_QPC_STATE_E {
+ ROCE_QPC_STATE_RST = 0,
+ ROCE_QPC_STATE_INIT,
+ ROCE_QPC_STATE_RTR,
+ ROCE_QPC_STATE_RTS,
+ ROCE_QPC_STATE_SQD,
+ ROCE_QPC_STATE_SQEr,
+ ROCE_QPC_STATE_ERR,
+ ROCE_QPC_STATE_DRAINING,
+ ROCE_QPC_STATE_RSV
+};
+
+
+enum ROCE_MTT_LAYER_NUM_E {
+ ROCE_MTT_LAYER_NUM_0 = 0,
+ ROCE_MTT_LAYER_NUM_1,
+ ROCE_MTT_LAYER_NUM_2,
+ ROCE_MTT_LAYER_NUM_3,
+ ROCE_MTT_LAYER_NUM_RSVD
+};
+
+enum ROCE_CQE_TYPE_E {
+ /* *1-Send Completion; 0-Receive Completion */
+ ROCE_RQ_CQE = 0,
+ ROCE_SQ_CQE
+};
+
+enum ROCE_CQE_SIZE_E {
+ ROCE_CQE_SIZE_0 = 0, /* * 4B */
+ ROCE_CQE_SIZE_1 = 1, /* * 8B */
+ ROCE_CQE_SIZE_2 = 2, /* * 16B */
+ ROCE_CQE_SIZE_3 = 3 /* * 32B, RoCE fix 3 */
+};
+
+enum ROCE_CQE_RQ_OPTYPE_E {
+ ROCE_CQE_RQ_OPTYPE_WRITE_IMMEDIATE = 0,
+ ROCE_CQE_RQ_OPTYPE_SEND,
+ ROCE_CQE_RQ_OPTYPE_SEND_IMMEDIATE,
+ ROCE_CQE_RQ_OPTYPE_SEND_INVALIDATE,
+ ROCE_CQE_RQ_OPTYPE_WRITE,
+ ROCE_CQE_RQ_OPTYPE_READ
+};
+
+enum ROCE_CQE_COMMON_OPTYPE_E {
+ ROCE_CQE_COMMON_OPTYPE_RESIZE = 0x16,
+ ROCE_CQE_COMMON_OPTYPE_ERR = 0x1e
+};
+
+enum ROCE_QPC_MTU_E {
+ ROCE_PMTU_256B = 1,
+ ROCE_PMTU_512B = 2,
+ ROCE_PMTU_1KB = 3,
+ ROCE_PMTU_2KB = 4,
+ ROCE_PMTU_4KB = 5
+};
+
+enum {
+ ROCE_DB_MTU_256B_SHIFT = 0,
+ ROCE_DB_MTU_512B_SHIFT = 1,
+ ROCE_DB_MTU_1K_SHIFT = 2,
+ ROCE_DB_MTU_2K_SHIFT = 3,
+ ROCE_DB_MTU_4K_SHIFT = 4,
+};
+
+enum ROCE_FLOW_ID_E {
+ ROCE_STL_TIMER_FLOW = 0,
+ ROCE_PKT_FLOW = 1,
+ ROCE_DB_FLOW = 2,
+ ROCE_TIMER_FLOW = 3,
+ ROCE_ARM_FLOW = 4,
+ ROCE_CMDQ_FLOW = 5,
+ ROCE_NRET_FLOW = 6,
+ ROCE_STL2STF_FLOW = 7,
+};
+
+#endif /* ROCE_PUB_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_pub_cmd.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_pub_cmd.h
new file mode 100644
index 0000000000000..eefd53404cb75
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_pub_cmd.h
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_PUB_CMD_H
+#define ROCE_PUB_CMD_H
+
+#ifndef CQM_AEQ_BASE_T_ROCE
+#define CQM_AEQ_BASE_T_ROCE 16
+#endif
+
+/* RoCE EVENT */
+enum {
+ ROCE_EVENT_TYPE_OFED_NO_DEF = (CQM_AEQ_BASE_T_ROCE + 0x00),
+ ROCE_EVENT_TYPE_PATH_MIG = (CQM_AEQ_BASE_T_ROCE + 0x01), /* RSVD */
+ ROCE_EVENT_TYPE_COMM_EST = (CQM_AEQ_BASE_T_ROCE + 0x02),
+ ROCE_EVENT_TYPE_SQ_DRAINED = (CQM_AEQ_BASE_T_ROCE + 0x03),
+ ROCE_EVENT_TYPE_SRQ_QP_LAST_WQE = (CQM_AEQ_BASE_T_ROCE + 0x04),
+
+ /* 5 */
+ ROCE_EVENT_TYPE_WQ_CATAS_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x05),
+ ROCE_EVENT_TYPE_PATH_MIG_FAILED = (CQM_AEQ_BASE_T_ROCE + 0x06),
+ ROCE_EVENT_TYPE_WQ_INVAL_REQ_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x07),
+ ROCE_EVENT_TYPE_WQ_ACCESS_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x08),
+ ROCE_EVENT_TYPE_CQ_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x09),
+
+ /* 10 */
+ ROCE_EVENT_TYPE_SRQ_LIMIT = (CQM_AEQ_BASE_T_ROCE + 0x0a),
+ ROCE_EVENT_TYPE_SRQ_CATAS_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x0b),
+ ROCE_EVENT_TYPE_LOCAL_CATAS_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x0c), /* RSVD */
+ ROCE_EVENT_TYPE_MR_SIG_ERR = (CQM_AEQ_BASE_T_ROCE + 0x0e),
+
+ ROCE_EVENT_TYPE_ODP_PAGE_FAULT = (CQM_AEQ_BASE_T_ROCE + 0x0f),
+ /* ROCE NOF AA */
+ ROCE_EVENT_TYPE_SWITCH_HOST = (CQM_AEQ_BASE_T_ROCE + 0x10),
+ ROCE_EVENT_TYPE_HOST_FAILOVER = (CQM_AEQ_BASE_T_ROCE + 0x11),
+ ROCE_EVENT_NOFAA_STUB = (CQM_AEQ_BASE_T_ROCE + 0x12),
+
+ /* * RSVE */
+ ROCE_EVENT_TYPE_EEC_CATAS_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x30),
+ ROCE_EVENT_TYPE_PORT_CHANGE = (CQM_AEQ_BASE_T_ROCE + 0x31),
+ ROCE_EVENT_TYPE_ECC_DETECT = (CQM_AEQ_BASE_T_ROCE + 0x32),
+ ROCE_EVENT_TYPE_VEP_UPDATE = (CQM_AEQ_BASE_T_ROCE + 0x33),
+ ROCE_EVENT_TYPE_FATAL_WARNING = (CQM_AEQ_BASE_T_ROCE + 0x34),
+ ROCE_EVENT_TYPE_FLR_EVENT = (CQM_AEQ_BASE_T_ROCE + 0x35),
+ ROCE_EVENT_TYPE_PORT_MNG_CHG_EVENT = (CQM_AEQ_BASE_T_ROCE + 0x36),
+ ROCE_EVENT_TYPE_XRC_DOMAIN_VIOLATION_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x37),
+ ROCE_EVENT_TYPE_INVALID_XRCETH_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x38),
+ ROCE_EVENT_TYPE_FLUSH_WQE_ERROR = (CQM_AEQ_BASE_T_ROCE + 0x39),
+
+ ROCE_EVENT_TYPE_EQ_OVERFLOW = (CQM_AEQ_BASE_T_ROCE + 0x40),
+ ROCE_EVENT_TYPE_CMD = (CQM_AEQ_BASE_T_ROCE + 0x41),
+ ROCE_EVENT_TYPE_COMM_CHANNEL = (CQM_AEQ_BASE_T_ROCE + 0x42),
+ ROCE_EVENT_TYPE_OP_REQUIRED = (CQM_AEQ_BASE_T_ROCE + 0x43),
+
+ ROCE_EVENT_TYPE_NONE = (CQM_AEQ_BASE_T_ROCE + 0x50)
+};
+
+
+enum {
+ /* GID CMD */
+ ROCE_CMD_UPDATE_GID = 0x60,
+ ROCE_CMD_QUERY_GID = 0x61,
+ ROCE_CMD_CLEAR_GID = 0x62,
+
+ /* IP CMD */
+ ROCE_CMD_ADD_IP_ENTRY = 0x68,
+ ROCE_CMD_DEL_IP_ENTRY = 0x69,
+ ROCE_CMD_LOOKUP_IP_ENTRY = 0x6a,
+ ROCE_CMD_UPDATE_IP_ENTRY = 0x6b,
+
+ /* TPT CMD */
+ ROCE_CMD_SW2HW_MPT = 0x70,
+ ROCE_CMD_HW2SW_MPT = 0x71,
+ ROCE_CMD_MODIFY_MPT = 0x72,
+ ROCE_CMD_QUERY_MPT = 0x73,
+ ROCE_CMD_FLUSH_TPT = 0x74,
+ ROCE_CMD_SYNC_TPT = 0x75,
+
+ /* CQ CMD */
+ ROCE_CMD_SW2HW_CQ = 0x80,
+ ROCE_CMD_RESIZE_CQ = 0x81,
+ ROCE_CMD_MODIFY_CQ = 0x82,
+ ROCE_CMD_HW2SW_CQ = 0x83,
+ ROCE_CMD_QUERY_CQ = 0x84,
+
+ /* SRQ CMD */
+ ROCE_CMD_SW2HW_SRQ = 0x90,
+ ROCE_CMD_ARM_SRQ = 0x91,
+ ROCE_CMD_HW2SW_SRQ = 0x92,
+ ROCE_CMD_QUERY_SRQ = 0x93,
+
+ /* QP CMD */
+ ROCE_CMD_QP_BASE = 0xa0,
+ ROCE_CMD_RST2INIT_QP = 0xa0,
+ ROCE_CMD_INIT2INIT_QP = 0xa1,
+ ROCE_CMD_INIT2RTR_QP = 0xa2,
+ ROCE_CMD_RTR2RTS_QP = 0xa3,
+ ROCE_CMD_RTS2RTS_QP = 0xa4,
+ ROCE_CMD_SQERR2RTS_QP = 0xa5,
+ ROCE_CMD_2ERR_QP = 0xa6,
+ ROCE_CMD_RTS2SQD_QP = 0xa7,
+ ROCE_CMD_SQD2SQD_QP = 0xa8,
+ ROCE_CMD_SQD2RTS_QP = 0xa9,
+ ROCE_CMD_2RST_QP = 0xaa,
+ ROCE_CMD_QUERY_QP = 0xab,
+ ROCE_CMD_MIRROR_QP = 0xac, /* DFX RoCE +/- packet mirroring */
+ ROCE_CMD_MODIFY_HASH_VALUE_QP = 0xad,
+ ROCE_CMD_GET_QP_RX_PORT = 0xae,
+ ROCE_CMD_MODIFY_UDP_SRC_PORT_QP = 0xaf,
+ ROCE_CMD_GET_UDP_SRC_PORT_QP = 0xb0,
+ ROCE_CMD_GET_QP_FUNC_TABLE = 0xb1,
+ ROCE_CMD_QP_MAX = 0xb1,
+ /* Miscellaneous CMD */
+ // ROCE_CMD_NOP = 0xb0,
+
+ /* MTT commands */
+ ROCE_CMD_QUERY_MTT = 0xc0,
+
+ ROCE_CMD_MODIFY_CONTEXT = 0xd0,
+ ROCE_CMD_EN_QP_CAP_PKT = 0xd1,
+ ROCE_CMD_DIS_QP_CAP_PKT = 0xd2,
+
+ ROCE_CMD_MISC_CACHE_INVLD = 0xe0,
+
+ ROCE_CMD_MISC_CQ_CACHE_INVLD = 0xf0,
+
+ ROCE_CMD_CREAT_SLAVE_QP = 0xf1,
+ ROCE_CMD_QUERY_MASTER_QP_BITMAP = 0xf2,
+ ROCE_CMD_GET_MASTER_QPN = 0xf3,
+ ROCE_CMD_SET_CONN_STAT = 0xf4,
+ ROCE_CMD_DISCONNECT_QP = 0xf5,
+ ROCE_CMD_SET_SHARD_CFG = 0xf6
+};
+
+enum roce3_cmd_type {
+ COMMON_CMD_TX_INFO = 1,
+ COMMON_CMD_Q_NUM,
+ COMMON_CMD_TX_WQE_INFO,
+ COMMON_CMD_TX_MAPPING,
+ COMMON_CMD_RX_INFO,
+ COMMON_CMD_RX_WQE_INFO,
+ COMMON_CMD_RX_CQE_INFO,
+ COMMON_CMD_UPRINT_FUNC_EN,
+ COMMON_CMD_UPRINT_FUNC_RESET,
+ COMMON_CMD_UPRINT_SET_PATH,
+ COMMON_CMD_UPRINT_GET_STATISTICS,
+ COMMON_CMD_FUNC_TYPE,
+ COMMON_CMD_GET_FUNC_IDX,
+ COMMON_CMD_GET_INTER_NUM,
+ COMMON_CMD_CLOSE_TX_STREAM,
+ COMMON_CMD_GET_DRV_VERSION,
+ COMMON_CMD_CLEAR_FUNC_STASTIC,
+ COMMON_CMD_GET_HW_STATS,
+ COMMON_CMD_CLEAR_HW_STATS,
+ COMMON_CMD_GET_SELF_TEST_RES,
+ COMMON_CMD_GET_CHIP_FAULT_STATS,
+ COMMON_CMD_NIC_RSVD1,
+ COMMON_CMD_NIC_RSVD2,
+ COMMON_CMD_NIC_RSVD3,
+ COMMON_CMD_GET_CHIP_ID,
+ COMMON_CMD_GET_SINGLE_CARD_INFO,
+ COMMON_CMD_GET_FIRMWARE_ACTIVE_STATUS,
+ COMMON_CMD_ROCE_DFX_FUNC,
+ COMMON_CMD_GET_DEVICE_ID,
+ COMMON_CMD_GET_PF_DEV_INFO,
+ COMMON_CMD_CMD_FREE_MEM,
+ COMMON_CMD_GET_LOOPBACK_MODE = 32,
+ COMMON_CMD_SET_LOOPBACK_MODE,
+ COMMON_CMD_SET_LINK_MODE,
+ COMMON_CMD_SET_PF_BW_LIMIT,
+ COMMON_CMD_GET_PF_BW_LIMIT,
+ COMMON_CMD_ROCE_CMD,
+ COMMON_CMD_GET_POLL_WEIGHT,
+ COMMON_CMD_SET_POLL_WEIGHT,
+ COMMON_CMD_GET_HOMOLOGUE,
+ COMMON_CMD_SET_HOMOLOGUE,
+ COMMON_CMD_GET_SSET_COUNT,
+ COMMON_CMD_GET_SSET_ITEMS,
+ COMMON_CMD_IS_DRV_IN_VM,
+ COMMON_CMD_LRO_ADPT_MGMT,
+ COMMON_CMD_SET_INTER_COAL_PARAM,
+ COMMON_CMD_GET_INTER_COAL_PARAM,
+ COMMON_CMD_GET_CHIP_INFO,
+ COMMON_CMD_GET_NIC_STATS_LEN,
+ COMMON_CMD_GET_NIC_STATS_STRING,
+ COMMON_CMD_GET_NIC_STATS_INFO,
+ COMMON_CMD_GET_PF_ID,
+ COMMON_CMD_NIC_RSVD4,
+ COMMON_CMD_NIC_RSVD5,
+ COMMON_CMD_DCB_QOS_INFO,
+ COMMON_CMD_DCB_PFC_STATE,
+ COMMON_CMD_DCB_ETS_STATE,
+ COMMON_CMD_DCB_STATE,
+ COMMON_CMD_QOS_DEV,
+ COMMON_CMD_NIC_RSVD7,
+ COMMON_CMD_GET_ULD_DEV_NAME,
+
+ COMMON_CMD_RSS_CFG = 0x40,
+ COMMON_CMD_RSS_INDIR,
+ COMMON_CMD_PORT_ID,
+
+ COMMON_CMD_GET_FUNC_CAP = 0x50,
+
+ COMMON_CMD_GET_WIN_STAT = 0x60,
+ COMMON_CMD_WIN_CSR_READ = 0x61,
+ COMMON_CMD_WIN_CSR_WRITE = 0x62,
+ COMMON_CMD_WIN_API_CMD_RD = 0x63,
+
+ ROCE_CMD_GET_QPC_FROM_CACHE = 0x80,
+ ROCE_CMD_GET_QPC_FROM_HOST = 0x81,
+ ROCE_CMD_GET_CQC_FROM_CACHE = 0x82,
+ ROCE_CMD_GET_CQC_FROM_HOST = 0x83,
+ ROCE_CMD_GET_SRQC_FROM_CACHE = 0x84,
+ ROCE_CMD_GET_SRQC_FROM_HOST = 0x85,
+ ROCE_CMD_GET_MPT_FROM_CACHE = 0x86,
+ ROCE_CMD_GET_MPT_FROM_HOST = 0x87,
+ ROCE_CMD_GET_GID_FROM_CACHE = 0x88,
+ ROCE_CMD_GET_QPC_CQC_PI_CI = 0x89,
+ ROCE_CMD_GET_QP_COUNT = 0x8a,
+ ROCE_CMD_GET_DEV_ALGO = 0x8b,
+
+ ROCE_CMD_START_CAP_PACKET = 0x90,
+ ROCE_CMD_STOP_CAP_PACKET = 0x91,
+ ROCE_CMD_QUERY_CAP_INFO = 0x92,
+ ROCE_CMD_ENABLE_QP_CAP_PACKET = 0x93,
+ ROCE_CMD_DISABLE_QP_CAP_PACKET = 0x94,
+ ROCE_CMD_QUERY_QP_CAP_INFO = 0x95,
+
+ ROCE_CMD_ENABLE_BW_CTRL = 0xa0,
+ ROCE_CMD_DISABLE_BW_CTRL = 0xa1,
+ ROCE_CMD_CHANGE_BW_CTRL_PARAM = 0xa2,
+ ROCE_CMD_QUERY_BW_CTRL_PARAM = 0xa3,
+
+ ROCE_CMD_TIMEOUT_ALARM = 0xb0,
+ COMMON_CMD_VM_COMPAT_TEST = 0xFF
+};
+
+enum roce3_cmd_ctx_type {
+ ROCE_CMD_CTX_MODIFY_QPC = 0X0,
+ ROCE_CMD_CTX_MODIFY_MPT = 0X1,
+ ROCE_CMD_CTX_MODIFY_CQC = 0X2,
+ ROCE_CMD_CTX_MODIFY_SRQC = 0X3,
+ ROCE_CMD_CTX_MODIFY_WQE_PI_CI = 0X4,
+ ROCE_CMD_CTX_FETCH_WQE = 0X5,
+ ROCE_CMD_CTX_DEL_TIMER = 0X6,
+ ROCE_CMD_CTX_LB_SQDB = 0X7
+};
+
+enum roce3_modify_fetch_wqe_cmd_type {
+ ROCE_CMD_FCH_WQE_ACKCI = 1,
+ ROCE_CMD_FCH_WQE_UPDATE = 2
+};
+
+enum roce3_gid_type {
+ ROCE_IPv4_ROCEv2_GID = 0,
+ ROCE_IPv6_ROCEv2_GID = 1,
+ ROCE_ROCEv1_GID = 2,
+ ROCE_INV_GID
+};
+
+#endif /* ROCE_PUB_CMD_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_ulp.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_ulp.h
new file mode 100644
index 0000000000000..bc1b9cb0131da
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_ulp.h
@@ -0,0 +1,178 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_ULP_H
+#define ROCE_ULP_H
+
+#include "pub_base_defs.h"
+
+/* *********ECN alpha SHIFT******* */
+#define ECN_ALPHA_MAGNIFICATION_SHIFT (21)
+
+/* ********************** NOFAA start ************************ */
+enum ROCE_NOFAA_QP_CTX_OFF_E {
+ ROCE_NOFAA_CTX_TIMER_OFF = 0,
+ ROCE_NOFAA_CTX_SW_OFF = 32,
+ ROCE_NOFAA_CTX_SW_SQC_OFF = 96,
+ ROCE_NOFAA_CTX_SW_SQAC_OFF = 116,
+ ROCE_NOFAA_CTX_SW_RQC_OFF = 148,
+ ROCE_NOFAA_CTX_SW_RQAC_OFF = 168
+};
+
+#define ROCE_VERBS_NOFAA_TIMERC_OFFSET_16B_ALIGN (ROCE_NOFAA_CTX_TIMER_OFF >> 4)
+#define ROCE_VERBS_NOFAA_SW_OFFSET_16B_ALIGN (ROCE_NOFAA_CTX_SW_OFF >> 4)
+
+/* API */
+#define ROCE_NOFAA_WQE2HOST_SM_NODE NODE_ID_SMF0
+#define ROCE_NOFAA_CMIDINFO_SM_MODE NODE_ID_SMF0
+#define SML_INST_MASTER_QPC 20
+
+#define ROCE_BMP_LOAD_BYTE 64
+#define ROCE_BMP_ENTRY_BY_64B ((ROCE_QPC_TABLE_SIZE>>6) + 1)
+#define ROCE_BMP_RSVD_BYTE 32
+#define ROCE_NOFAA_QPN_RSVD 0x2
+#define ROCE_REVERSE_PER_64B_SHIFT 4
+
+#define ROCE_MQP_LT_RSVD 100 // (64 + 12kbit / 8) / 16
+#define ROCE_ACT_HOST_LT_RSVD 4 // (64) / 16
+#define ROCE_HASH_LT_RSVD 17920 // (0xA1000 - 0x5B000) / 16
+#define ROCE_SHARD_HASH_LT_RSVD 8960 // (0x8DC00 - 0x6AC00) / 16
+#define ROCE_HASH_LT_RSVD_MUL_SML (ROCE_HASH_LT_RSVD >> ROCE_NOFAA_PORT_NUM_SHIFT)
+#define ROCE_LT_64B_IDX_SHIFT 2
+#define ROCE_LT_64B_ENTRY_NUM 4
+
+#define ROCE_NOFAA_HASH_WORD_EN 0x400
+#define ROCE_NOFAA_HASH_API_KEY_LEN 4
+#define ROCE_NOFAA_BITHEAP_ID0 0
+#define ROCE_NOFAA_RSVD_BMPIDX_NUM 2
+#define ROCE_NOFAA_MASTER_BMPIDX_BASE 0x3002
+#define ROCE_NOFAA_CM_QPN_INDEX 0x3001
+#define ROCE_NOFAA_FLR_STUB_INDEX 0x2fff
+#define ROCE_NOFAA_QPN2BMPIDX(xid) ((xid) + ROCE_NOFAA_MASTER_BMPIDX_BASE - ROCE_NOFAA_QPN_RSVD)
+#define ROCE_NOFAA_BMPIDX2QPN(bmp_idx) \
+ ((bmp_idx) + ROCE_NOFAA_QPN_RSVD - ROCE_NOFAA_MASTER_BMPIDX_BASE)
+#define ROCE_NOFAA_GET_ACT_HOST_IDX(xid, host_id) (((xid) << 2) + (((host_id) & 0x3) ^ 0x3))
+
+#define ROCE_NOFAA_GIDIDX_MASK 0x3f
+#define ROCE_NOFAA_GIDIDX_RSVD_MASK 0xc0
+
+/* cfg */
+#define NOFAA_SRC_TAG_L (global_share_space.global_config.dw6.bs.master_func)
+#define ROCE_NOFAA_HOSTID_MASK (global_share_space.global_config.dw6.bs.host_mask)
+#define ROCE_NOFAA_HOST_NUM (global_share_space.global_config.dw6.bs.host_num)
+#define ROCE_NOFAA_PORT_NUM (global_share_space.global_config.dw6.bs.port_num)
+#define ROCE_NOFAA_HOST_NUM_SHIFT (global_share_space.global_config.dw6.bs.host_shift)
+#define ROCE_NOFAA_PORT_NUM_SHIFT (global_share_space.global_config.dw6.bs.port_shift)
+#define ROCE_NOFAA_PORT_NUM_MASK (global_share_space.global_config.dw6.bs.port_mask)
+#define ROCE_NOFAA_MAX_HOST_NUM 4
+#define ROCE_NOFAA_HASH_POOL_IO_NUM (ROCE_NOFAA_MAX_HASH_NUM >> ROCE_NOFAA_PORT_NUM_SHIFT)
+#define ROCE_NOFAA_SRQN_BASE 2
+#define ROCE_NOFAA_SRQN_MASK 0x7
+#define ROCE_NOFAA_SRQN_NUM 8
+
+#define ROCE_NOFAA_MAX_QPN_SHIFT 12
+#define ROCE_NOFAA_PORT_QP_NUM_SHIFT (ROCE_NOFAA_MAX_QPN_SHIFT - ROCE_NOFAA_PORT_NUM_SHIFT)
+#define ROCE_NOFAA_PORT_QP_NUM (1u << ROCE_NOFAA_PORT_QP_NUM_SHIFT)
+#define ROCE_NOFAA_PORT_QP_NUM_MASK (ROCE_NOFAA_PORT_QP_NUM - 1)
+#define ROCE_AA_SWITCH_QP_NUM 4
+#define ROCE_AA_SWITCH_QPN (4095 + 1)
+#define ROCE_AA_SWITCH_MAX_QPN (ROCE_AA_SWITCH_QPN + ROCE_AA_SWITCH_QP_NUM)
+#define ROCE_QP0 0x0
+#define ROCE_CM_QPN 0x1
+#define ROCE_AA_QID_NUM 9
+#define ROCE_NVME_QID_GP_SHIFT 1
+#define ROCE_NVME_QID_GP_MASK 1
+
+#define NEXT_IO_SPF_GET(start_spf, index) ((start_spf) + ((index) << 7))
+#define NEXT_SPF_GET(start_spf, index) ((start_spf) + ((index) << 6))
+
+#define ROCE_NOFAA_VFID2HOSTIDX(vf_id) \
+ (((vf_id) >> ROCE_NOFAA_PORT_NUM_SHIFT) & ROCE_NOFAA_HOSTID_MASK)
+#define ROCE_NOFAA_VFID2PORTID(vf_id) ((vf_id) & ROCE_NOFAA_PORT_NUM_MASK)
+#define ROCE_NOFAA_SLAVE_ALIVE_GET(active_bmp, slave_id) \
+ ((active_bmp) & (1u << ((slave_id) & ROCE_NOFAA_HOSTID_MASK)))
+#define ROCE_AA_SRCCHNL2HOST(src_chnl) (((src_chnl) >> 3) & 0x3)
+#define ROCE_NOFAA_GET_GID_IDX(qpc, host_id) \
+ (*((u8 *)&((qpc)->nofaa_ctx.dw1.value) + (host_id)) & 0x3f)
+/* ROCE NOFAA(QPC512):CID[19:0] = {XID[12:4],XID[12:4],XID[3:2]} */
+#define roce_nofaa_calc_cid_by_xid(xid) ((((xid)&0x3ffe0) << 6) | (((xid)&0x7ff8) >> 3))
+#define ROCE_NOFAA_BITMAP_CLEAR(bmp, idx) ((bmp) &= ((1u << (idx)) ^ 0xffffffff))
+#define ROCE_NOFAA_BITMAP_SET(bmp, idx) ((bmp) |= (1u << (idx)))
+#define ROCE_NOFAA_BITMAP_GET(bmp, idx) ((bmp) & (1u << (idx)))
+#define ROCE_NOFAA_BITWISE_COMPARE(x, y) ((x) ^ (y))
+/* GET CMINFO TABLE */
+#define ROCE_GET_CMINFO_ADDR(sp_addr, index) \
+ ((struct tag_roce_nof_cm_ctx *)(sp_addr) + \
+ (((index) >> ROCE_LT_XID_LB_SHIFT) & ROCE_CMINFO_PER_16B_MASK))
+
+#define ROCE_NOFAA_QUERY_BMP_SIZE ((ROCE_NOFAA_PORT_QP_NUM) >> 3)
+#define ROCE_NOFAA_GET_PORT_QPNUM_BYTE(port_id) \
+ ((u32)((port_id) << ROCE_NOFAA_PORT_QP_NUM_SHIFT) >> 3)
+
+/* switch */
+#define ROCE_SWITCH_COUNTER_BASE 0x4000
+
+/* timer */
+#define ROCE_NOFAA_TIME_DLY_STEP 2047
+#define ROCEAA_TIMER_DLY_STEP(dly_step) (((dly_step) < ROCE_NOFAA_TIME_DLY_STEP) ? \
+ (dly_step) : ROCE_NOFAA_TIME_DLY_STEP)
+
+/* data struct */
+struct tag_roce_nof_cm_ctx {
+ u32 local_comm_id;
+ u32 remote_comm_id;
+};
+
+struct tag_nofaa_shard_hash_key {
+ u32 xid : 16;
+ u32 lun_id : 16;
+};
+
+struct tag_nofaa_shard_hash_item {
+ struct {
+ u32 volume_id : 24;
+ u32 dd_id : 8;
+ } bs;
+
+ u8 hash_low_cnt;
+ u8 hash_high_cnt;
+ u8 hash_low_offset;
+ u8 hash_high_offset;
+};
+
+struct tag_nofaa_shard_hash_entry {
+ struct tag_nofaa_shard_hash_key key;
+ struct tag_nofaa_shard_hash_item item;
+};
+
+struct tag_nofaa_shard_hash_value {
+ union {
+ struct {
+ u32 code : 2;
+ u32 rsvd0 : 30;
+ } bs;
+ u32 value;
+ } dw0;
+ u32 rsvd0;
+ struct tag_nofaa_shard_hash_item item;
+};
+
+struct tag_nofaa_shard_lt_value {
+ union {
+ struct {
+ u32 v : 1;
+ u32 s : 1;
+ u32 b : 1;
+ u32 rsvd0 : 5;
+ u32 hash_value : 16;
+ u32 rsvd1 : 8;
+ } bs;
+ u32 value;
+ } dw0;
+ struct tag_nofaa_shard_hash_key key;
+ struct tag_nofaa_shard_hash_item item;
+};
+
+/* ********************** NOFAA end ************************ */
+
+#endif /* ROCE_ULP_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_vbs_format.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_vbs_format.h
new file mode 100644
index 0000000000000..f43accd09208d
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_vbs_format.h
@@ -0,0 +1,206 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VBS_FORMAT_H
+#define ROCE_VBS_FORMAT_H
+
+#include "roce_wqe_format.h"
+#include "roce_xqe_format.h"
+
+#ifdef ROCE_VBS_EN
+
+struct roce_wqe_vbs_rdma_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 data_len; /* Length of the data sent by the SQ WQE */
+
+ /* DW2 */
+ u32 dw2;
+
+ /* DW3 */
+ union roce3_wqe_tsk_misc_seg dw3;
+};
+#else
+
+union roce_wqe_vbs_tsk_misc_seg {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 request_id : 16;
+ u32 xts_vld : 1;
+ u32 rq_buf_shift : 4;
+ u32 sio_grp_num : 3;
+ u32 sio_grp4_len : 8;
+
+ u32 sio_grp3_len : 8;
+ u32 sio_grp2_len : 8;
+ u32 sio_grp1_len : 8;
+ u32 sio_grp0_len : 8;
+#else
+ u32 sio_grp0_len : 8;
+ u32 sio_grp1_len : 8;
+ u32 sio_grp2_len : 8;
+ u32 sio_grp3_len : 8;
+
+ u32 sio_grp4_len : 8;
+ u32 sio_grp_num : 3;
+ u32 rq_buf_shift : 4;
+ u32 xts_vld : 1;
+ u32 request_id : 16;
+#endif
+ } bs;
+ u64 value;
+};
+
+struct roce_wqe_vbs_aad_seg {
+ union {
+ struct {
+ u32 pdu_difx_en : 1;
+ u32 pad_len_vld : 1;
+ u32 pdu_pad_len : 2;
+ u32 smd_tp : 4;
+ u32 rsvd0 : 1;
+ u32 msg_hdr_vld : 1;
+ u32 msg_hdr_len : 2;
+ u32 rd_difx_rslt : 1;
+ u32 vbs_difx : 1;
+ u32 rsvd1 : 1;
+ u32 pdu_difx_cnt : 9;
+ u32 rsvd2 : 4;
+ u32 sio_num : 4;
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+ u32 fst_pdu : 1;
+ u32 fst_sct : 1;
+ u32 last_pdu : 1;
+ u32 rsp_indiv : 1;
+ u32 sct_sz : 1;
+ u32 dsgl : 1;
+ u32 rsp_vld : 1;
+ u32 rsp_len : 5;
+ u32 app_esc : 1;
+ u32 ref_esc : 1;
+ u32 sct_v_tp : 2;
+ u32 grd_v_en : 1;
+ u32 grd_rid : 2;
+ u32 grd_v_agm : 1;
+ u32 grd_ri_agm : 1;
+ u32 grd_agm_ini : 1;
+ u32 crc16_ini : 1;
+ u32 ipcs_ini : 1;
+ u32 ref_v_en : 1;
+ u32 ref_rid : 2;
+ u32 ref_v_inc : 1;
+ u32 ref_ri_inc : 1;
+ u32 app_v_en : 1;
+ u32 app_rid : 2;
+ } bs;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+ u32 task_tag : 16;
+ u32 rep_app_tag : 16;
+ } bs;
+ u32 value;
+ } dw2;
+
+ union {
+ struct {
+ u32 cmp_app_tag : 16;
+ u32 cmp_app_tag_msk : 16;
+ } bs;
+ u32 value;
+ } dw3;
+
+ u32 cmp_ref_tag;
+
+ u32 rep_ref_tag;
+
+ union {
+ struct {
+ u32 pdu_sd_ofs : 13;
+ u32 rsvd0 : 1;
+ u32 pdu_sd_len : 18;
+ } bs;
+ u32 value;
+ } dw6;
+};
+
+struct roce_wqe_vbs_subinfo {
+ union {
+ struct {
+ u32 sio0_size : 4;
+ u32 sio1_size : 4;
+ u32 sio2_size : 4;
+ u32 sio3_size : 4;
+ u32 sio4_size : 4;
+ u32 sio5_size : 4;
+ u32 sio6_size : 4;
+ u32 sio7_size : 4;
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+ u32 sio0_crc2_ini : 16;
+ u32 sio1_crc2_ini : 16;
+ } bs;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+ u32 sio2_crc2_ini : 16;
+ u32 sio3_crc2_ini : 16;
+ } bs;
+ u32 value;
+ } dw2;
+
+ union {
+ struct {
+ u32 sio4_crc2_ini : 16;
+ u32 sio5_crc2_ini : 16;
+ } bs;
+ u32 value;
+ } dw3;
+
+ union {
+ struct {
+ u32 sio6_crc2_ini : 16;
+ u32 sio7_crc2_ini : 16;
+ } bs;
+ u32 value;
+ } dw4;
+};
+
+struct roce_wqe_vbs_rdma_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 data_len; /* Length of the data sent by the SQ WQE */
+
+ /* DW2 */
+ /* This parameter is valid for the immediate data operation or SEND invalidate. */
+ u32 wqe_ext_len;
+
+ /* DW3 */
+ union roce3_wqe_tsk_misc_seg dw3;
+
+ /* DW4~5 */
+ union roce_wqe_vbs_tsk_misc_seg misc;
+
+ u32 rsvd[2];
+
+ struct roce_wqe_vbs_aad_seg vbs_aad;
+};
+
+#endif
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_attr.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_attr.h
new file mode 100644
index 0000000000000..05b3363c0e5a7
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_attr.h
@@ -0,0 +1,413 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_ATTR_H
+#define ROCE_VERBS_ATTR_H
+
+#include "roce_verbs_mr_attr.h"
+#include "roce_verbs_gid_attr.h"
+#include "roce_verbs_cq_attr.h"
+#include "roce_verbs_srq_attr.h"
+#include "roce_verbs_attr_qpc_chip.h"
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#define ROCE_VERBS_SQ_WQEBB_SIZE (2)
+#define ROCE_VERBS_SQ_PI_VLD (1)
+
+#pragma pack(4)
+/* qpc_attr_com info ,12*4B */
+struct tag_roce_verbs_qpc_attr_com {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 service_type : 3;
+ u32 fre : 1;
+ u32 rwe : 1;
+ u32 rre : 1;
+ u32 rae : 1;
+ u32 rkey_en : 1;
+ u32 dest_qp : 24;
+#else
+ /*
+ * Destination QP number, which is extended to 24 bits in
+ * consideration of interconnection with commercial devices.
+ */
+ u32 dest_qp : 24;
+ u32 rkey_en : 1;
+ u32 rae : 1;
+ u32 rre : 1;
+ u32 rwe : 1;
+ /* Indicates whether the local FRPMR is enabled. */
+ u32 fre : 1;
+ /* Transmission Type
+ * 000:RC
+ * 001:UC
+ * 010:RD
+ * 011 UD
+ * 101:XRC
+ * Other:Reserved
+ */
+ u32 service_type : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sra_max : 3;
+ u32 rra_max : 3;
+ u32 rnr_retry_limit : 3;
+ u32 to_retry_limit : 3;
+ u32 local_qp : 20;
+#else
+ u32 local_qp : 20; /* Local QP number */
+ /*
+ * Number of ACK retransmissions. The value 7 indicates unlimited
+ * times, and the value 0 indicates no retransmission.
+ */
+ u32 to_retry_limit : 3;
+ /*
+ * The maximum number of RNR retransmissions is 7. The value 7
+ * indicates that the maximum number of retransmissions is 7, and
+ * the value 0 indicates that the retransmission is not performed.
+ */
+ u32 rnr_retry_limit : 3;
+ /* The maximum value of responser resource is 128. */
+ u32 rra_max : 3;
+ /* The maximum value of initiator depth is 128. */
+ u32 sra_max : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ack_to : 5;
+ u32 min_rnr_nak : 5;
+ u32 cont_size : 2;
+ u32 cont_en : 1;
+ u32 srq_en : 1;
+ u32 xrc_srq_en : 1;
+ u32 vroce_en : 1;
+ u32 host_oqid : 16;
+#else
+ u32 host_oqid : 16;
+ u32 vroce_en : 1;
+ u32 xrc_srq_en : 1;
+ u32 srq_en : 1;
+ u32 cont_en : 1;
+ u32 cont_size : 2;
+ /*
+ * NAK code of RNR. This parameter is mandatory when INIT2RNR and
+ * RTR2RTS\SQE2RTS\SQD2SQD\SQD2RTS is optional.
+ */
+ u32 min_rnr_nak : 5;
+ u32 ack_to : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 tss_timer_num : 3;
+ u32 xrc_vld : 1;
+ u32 srq_container : 1;
+ u32 invalid_credit : 1;
+ u32 ext_md : 1;
+ u32 ext_mtu : 1;
+ u32 dsgl_en : 1;
+ u32 dif_en : 1;
+ u32 pmtu : 3;
+ u32 base_mtu_n : 1;
+ u32 pd : 18;
+#else
+ u32 pd : 18;
+ u32 base_mtu_n : 1;
+ u32 pmtu : 3;
+ u32 dif_en : 1;
+ u32 dsgl_en : 1;
+ u32 ext_mtu : 1;
+ u32 ext_md : 1;
+ u32 invalid_credit : 1;
+ u32 srq_container : 1;
+ u32 xrc_vld : 1;
+ u32 tss_timer_num : 3;
+#endif
+ } bs;
+
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ u32 q_key;
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ulp_type : 8;
+ u32 oor_en : 1;
+ u32 capture_en : 1;
+ u32 rsvd : 1;
+ u32 acx_mark : 1;
+ u32 mtu_code : 4;
+ u32 port : 2;
+ u32 ep : 3;
+ u32 cos : 3;
+ u32 so_ro : 2;
+ u32 dma_attr_idx : 6;
+#else
+ u32 dma_attr_idx : 6;
+ u32 so_ro : 2;
+ u32 cos : 3;
+ u32 ep : 3;
+ u32 port : 2;
+ u32 mtu_code : 4;
+ u32 acx_mark : 1;
+ u32 rsvd : 1;
+ u32 capture_en : 1;
+ u32 oor_en : 1;
+ u32 ulp_type : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sd_mpt_idx : 12;
+ u32 rsvd : 20;
+#else
+ u32 rsvd : 20;
+ u32 sd_mpt_idx : 12;
+#endif
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 10;
+ u32 sq_cqn_lb : 1;
+ u32 rq_cqn_lb : 1;
+ u32 rq_cqn : 20;
+#else
+ u32 rq_cqn : 20;
+ u32 rq_cqn_lb : 1;
+ u32 sq_cqn_lb : 1;
+ u32 rsvd : 10;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 next_send_psn : 24;
+#else
+ u32 next_send_psn : 24;
+ u32 rsvd : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw8;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 next_rcv_psn : 24;
+#else
+ u32 next_rcv_psn : 24;
+ u32 rsvd : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw9;
+
+ /* DW10 */
+ u32 lsn;
+
+ /* DW11 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 17;
+ u32 set_mpt_indx : 1;
+ u32 fake : 1;
+ u32 vf_id : 13;
+#else
+ u32 vf_id : 13;
+ u32 fake : 1;
+ u32 set_mpt_indx : 1;
+ u32 rsvd : 17;
+#endif
+ } bs;
+ u32 value;
+ } dw11;
+
+ /* DW12 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ccf_app_id : 8;
+ u32 rsvd : 24;
+#else
+ u32 rsvd : 24;
+ u32 ccf_app_id : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw12;
+};
+
+struct tag_roce_verbs_qpc_attr_path {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 bond_tx_hash_value : 16;
+ u32 dmac_h16 : 16;
+#else
+ u32 dmac_h16 : 16;
+ u32 bond_tx_hash_value : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ u32 dmac_l32;
+
+ /* DW2~5 */
+ u8 dgid[16];
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 4;
+ u32 tclass : 8;
+ u32 flow_label : 20;
+#else
+ u32 flow_label : 20; /* GRH flow lable */
+ u32 tclass : 8;
+ u32 rsvd : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sl : 3;
+ u32 loop : 1;
+ u32 udp_src_port : 8;
+ u32 rsvd : 4;
+ u32 base_sgid_n : 1;
+ u32 sgid_index : 7;
+ u32 hoplmt : 8;
+#else
+ u32 hoplmt : 8;
+ u32 sgid_index : 7;
+ u32 base_sgid_n : 1;
+ u32 rsvd : 4;
+ u32 udp_src_port : 8;
+ u32 loop : 1;
+ u32 sl : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+};
+
+struct roce_verbs_qpc_attr_nof_aa {
+ u32 gid_index;
+ u32 qid;
+ u32 local_comm_id;
+ u32 remote_comm_id;
+};
+
+struct roce_verbs_qpc_attr_vbs {
+ u32 sqpc_ci_record_addr_h;
+ u32 sqpc_ci_record_addr_l;
+};
+
+struct roce_verbs_qpc_attr_ext {
+ struct roce_verbs_qpc_attr_nof_aa nof_aa_info;
+ struct roce_verbs_qpc_attr_vbs vbs_info;
+};
+
+/* QPC Struct */
+struct tag_roce_verbs_qp_attr {
+ /* com seg, DW0 ~ DW11 */
+ struct tag_roce_verbs_qpc_attr_com com_info;
+
+ /* path seg, DW0 ~ DW7 */
+ struct tag_roce_verbs_qpc_attr_path path_info;
+
+ /* chip seg, DW0 ~ DW19 */
+ struct tag_roce_verbs_qpc_attr_chip chip_seg;
+
+ /* ext seg */
+ struct roce_verbs_qpc_attr_ext ext_seg;
+};
+
+
+struct tag_roce_verbs_qp_hw2sw_info {
+ /* DW0~1 */
+ u32 sq_buf_len; /* Buffer length of the SQ queue */
+ u32 rq_buf_len; /* Buffer length of the RQ queue */
+
+ /* DW2~6 */
+ struct tag_roce_verbs_mtt_cacheout_info cmtt_cache;
+
+ /* DW7~8 */
+ union {
+ u64 wb_gpa; /* Address written back by the ucode after processing */
+
+ struct {
+ u32 syn_gpa_hi32; /* Upper 32 bits of the start address of mr or mw */
+ u32 syn_gpa_lo32; /* Lower 32 bits of the start address of mr or mw */
+ } gpa_dw;
+ };
+ union {
+ struct {
+ u32 rsvd : 16;
+ u32 host_oqid : 16;
+ } bs;
+
+ u32 value;
+ } dw9;
+ struct tag_roce_verbs_wqe_cacheout_info wqe_cache;
+};
+
+struct tag_roce_verbs_modify_ctx_info {
+ u32 ctx_type;
+ u32 offset;
+ u32 value;
+ u32 mask;
+};
+
+#pragma pack()
+
+#endif /* ROCE_VERBS_ATTR_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_attr_qpc_chip.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_attr_qpc_chip.h
new file mode 100644
index 0000000000000..8eb2dcf6fad47
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_attr_qpc_chip.h
@@ -0,0 +1,360 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_ATTR_QPC_CHIP_H
+#define ROCE_VERBS_ATTR_QPC_CHIP_H
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#pragma pack(4)
+struct tag_roce_verbs_qpc_attr_chip {
+ /* DW0~1 */
+ union {
+ u64 sq_rq_l0mtt_gpa; /* hi[63:32],lo[31:03],sq_rq_gpa_sign[02:00] */
+ struct {
+ u32 sq_rq_l0mtt_gpa_hi;
+ u32 sq_rq_l0mtt_gpa_lo;
+ } bs;
+ } dw0;
+
+ /* DW2~3 */
+ union {
+ /* hi[63:32],lo[31:02],sq_rq_at_hop_num[01:00] */
+ 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; /* at_hop_num: bit[01:00] */
+ } bs;
+ } dw2;
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 qp_page_size : 4;
+ u32 sq_rq_mtt_page_size : 4;
+ u32 rsvd1 : 3;
+ u32 qp_signature : 5;
+ u32 rsvd0 : 1;
+ u32 dsgl : 1;
+ u32 rrw_mtt_prefetch_maxlen : 2;
+ u32 rc_size : 4;
+ u32 rc_max_size : 3;
+ u32 rq_base_ci : 5;
+#else
+ u32 rq_base_ci : 5;
+ u32 rc_max_size : 3;
+ u32 rc_size : 4;
+ u32 rrw_mtt_prefetch_maxlen : 2;
+ u32 dsgl : 1;
+ u32 rsvd0 : 1;
+ u32 qp_signature : 5;
+ u32 rsvd1 : 3;
+ u32 sq_rq_mtt_page_size : 4;
+ u32 qp_page_size : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw4;
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_wqe_prefetch_maxnum : 3;
+ u32 sq_wqe_prefetch_minnum : 3;
+ u32 sq_wqe_cache_thd_sel : 2;
+ u32 sq_wqecnt_lth : 4;
+ u32 sq_wqecnt_rctl_en : 1;
+ u32 sq_wqecnt_rctl : 1;
+ u32 sq_prefetch_one_wqe : 1;
+ u32 sq_prewqe_mode : 1;
+ u32 sqa_wqe_prefetch_maxnum : 3;
+ u32 sqa_wqe_prefetch_minnum : 3;
+ u32 sqa_wqe_cache_thd_sel : 2;
+ u32 sq_wqe_check_en : 1;
+ u32 sq_pi_on_chip : 1;
+ u32 sq_inline_en : 1;
+ u32 sq_size : 5;
+#else
+ u32 sq_size : 5;
+ u32 sq_inline_en : 1;
+ u32 sq_pi_on_chip : 1;
+ u32 sq_wqe_check_en : 1;
+ u32 sqa_wqe_cache_thd_sel : 2;
+ u32 sqa_wqe_prefetch_minnum : 3;
+ u32 sqa_wqe_prefetch_maxnum : 3;
+ u32 sq_prewqe_mode : 1;
+ u32 sq_prefetch_one_wqe : 1;
+ u32 sq_wqecnt_rctl : 1;
+ u32 sq_wqecnt_rctl_en : 1;
+ u32 sq_wqecnt_lth : 4;
+ u32 sq_wqe_cache_thd_sel : 2;
+ u32 sq_wqe_prefetch_minnum : 3;
+ u32 sq_wqe_prefetch_maxnum : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sq_wqe_prefetch_mode : 1;
+ u32 sq_mtt_prefetch_maxlen : 3;
+ u32 sqa_mtt_prefetch_maxlen : 3;
+ u32 srq_pd : 18;
+ u32 rsvd : 7;
+#else
+ u32 rsvd : 7;
+ u32 srq_pd : 18;
+ u32 sqa_mtt_prefetch_maxlen : 3;
+ u32 sq_mtt_prefetch_maxlen : 3;
+ u32 sq_wqe_prefetch_mode : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rq_wqe_prefetch_maxnum : 3;
+ u32 rq_wqe_prefetch_minnum : 3;
+ u32 rq_wqe_cache_thd_sel : 2;
+ u32 rq_wqecnt_lth : 4;
+ u32 rq_wqecnt_rctl_en : 1;
+ u32 rq_wqecnt_rctl : 1;
+ u32 srqn : 18;
+#else
+ u32 srqn : 18;
+ u32 rq_wqecnt_rctl : 1;
+ u32 rq_wqecnt_rctl_en : 1;
+ u32 rq_wqecnt_lth : 4;
+ u32 rq_wqe_cache_thd_sel : 2;
+ u32 rq_wqe_prefetch_minnum : 3;
+ u32 rq_wqe_prefetch_maxnum : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ /* DW8 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 srq_wqe_rthd_sel : 2;
+ u32 srq_rqecnt_th : 4;
+ u32 rq_pi_on_chip : 1;
+ u32 rq_inline_en : 1;
+ u32 rq_wqebb_size : 3;
+ u32 rq_size : 5;
+ u32 xrcd : 16;
+#else
+ u32 xrcd : 16;
+ u32 rq_size : 5;
+ u32 rq_wqebb_size : 3;
+ u32 rq_inline_en : 1;
+ u32 rq_pi_on_chip : 1;
+ u32 srq_rqecnt_th : 4;
+ u32 srq_wqe_rthd_sel : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw8;
+
+ /* DW9 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 container_en : 1;
+ u32 container_sz : 2;
+ u32 srq_warth_flag : 1;
+ u32 srq_mtt_prefetch_maxlen1 : 2;
+ u32 rq_mtt_prefetch_maxwqe : 3;
+ u32 rq_mtt_prefetch_maxlen0 : 2;
+ u32 rq_mtt_prefetch_maxlen1 : 2;
+ u32 rsvd : 19;
+#else
+ u32 rsvd : 19;
+ u32 rq_mtt_prefetch_maxlen1 : 2;
+ u32 rq_mtt_prefetch_maxlen0 : 2;
+ u32 rq_mtt_prefetch_maxwqe : 3;
+ u32 srq_mtt_prefetch_maxlen1 : 2;
+ u32 srq_warth_flag : 1;
+ u32 container_sz : 2;
+ u32 container_en : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw9;
+
+ /* DW10 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rc_entry_prefetch_maxnum : 3;
+ u32 rc_mtt_prefetch_maxlen : 2;
+ u32 rsvd : 1;
+ u32 rc_entry_size : 2;
+ u32 rc_page_gpa_h : 24;
+#else
+ /*
+ * bit[63:40] Indicates the start GPA of RDMARC table.
+ * The driver needs to allocate continuous physical address for
+ * the RDMARC table.Configured by Driver
+ */
+ u32 rc_page_gpa_h : 24;
+ u32 rc_entry_size : 2;
+ u32 rsvd : 1;
+ u32 rc_mtt_prefetch_maxlen : 2;
+ /*
+ * Maximum number of prefetch Entries for RDMARC table.000: prefetch
+ * number equals to zero; Others: prefetch number equals to
+ * (2^(rc_entry_prefetch_maxnum-1)). Configured by Driver
+ */
+ u32 rc_entry_prefetch_maxnum : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw10;
+
+ /* DW11 */
+ u32 rc_page_gpa_l; /* bit[39:8] */
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 1;
+ u32 srq_pd : 18;
+ u32 srq_wqebb_size : 3;
+ u32 srq_page_size : 4;
+ u32 srq_size : 5;
+ u32 srq_rkey_en : 1;
+#else
+ u32 srq_rkey_en : 1;
+ u32 srq_size : 5;
+ u32 srq_page_size : 4;
+ u32 srq_wqebb_size : 3;
+ u32 srq_pd : 18;
+ u32 rsvd : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw12;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 srq_cqn : 20;
+ u32 srq_state : 4;
+#else
+ u32 srq_state : 4;
+ u32 srq_cqn : 20;
+ u32 rsvd : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw13;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 15;
+ u32 qp_rkey_en : 1;
+ u32 srq_xrcd : 16;
+#else
+ u32 srq_xrcd : 16;
+ u32 qp_rkey_en : 1;
+ u32 rsvd : 15;
+#endif
+ } bs;
+ u32 value;
+ } dw14;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 4;
+ u32 rq_page_size : 4;
+ u32 rq_pd : 18;
+ u32 rq_rkey_en : 1;
+ u32 rq_size : 5;
+#else
+ u32 rq_size : 5;
+ u32 rq_rkey_en : 1;
+ u32 rq_pd : 18;
+ u32 rq_page_size : 4;
+ u32 rsvd : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw15;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 6;
+ u32 sq_wqebb_size : 3;
+ u32 sq_pd : 18;
+ u32 sq_page_size : 4;
+ u32 sq_rkey_en : 1;
+#else
+ u32 sq_rkey_en : 1;
+ u32 sq_page_size : 4;
+ u32 sq_pd : 18;
+ u32 sq_wqebb_size : 3;
+ u32 rsvd : 6;
+#endif
+ } bs;
+ u32 value;
+ } dw16;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 12;
+ u32 sqa_cqn : 20;
+#else
+ u32 sqa_cqn : 20;
+ u32 rsvd : 12;
+#endif
+ } bs;
+ u32 value;
+ } dw17;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 14;
+ u32 ud_pd : 18;
+#else
+ u32 ud_pd : 18;
+ u32 rsvd : 14;
+#endif
+ } bs;
+ u32 value;
+ } dw18;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 14;
+ u32 qp_pd : 18;
+#else
+ u32 qp_pd : 18;
+ u32 rsvd : 14;
+#endif
+ } bs;
+ u32 value;
+ } dw19;
+};
+
+#pragma pack()
+
+#endif /* ROCE_VERBS_ATTR_QPC_CHIP_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_cmd.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_cmd.h
new file mode 100644
index 0000000000000..422995c863bc6
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_cmd.h
@@ -0,0 +1,248 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_CMD_H
+#define ROCE_VERBS_CMD_H
+
+#include "rdma_context_format.h"
+#include "roce_verbs_pub.h"
+
+
+/* ************************************************* */
+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
+};
+
+struct tag_roce_cmd_gid {
+ struct tag_roce_verbs_cmd_com com;
+
+ u32 port;
+ u32 rsvd;
+ struct roce_gid_context gid_entry;
+};
+
+struct tag_roce_clear_gid {
+ struct tag_roce_verbs_cmd_com com;
+
+ u32 port;
+ u32 gid_num;
+};
+
+struct tag_roce_qurey_gid {
+ struct tag_roce_verbs_cmd_com com;
+
+ u32 port;
+ u32 rsvd;
+};
+
+struct tag_roce_flush_mpt {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_cmd_flush_mpt {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_cmd_mpt_query {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_sw2hw_mpt {
+ struct tag_roce_verbs_cmd_com com;
+ /* When creating a MR/MW, you need to enter the content of the MPT Context. */
+ struct roce_mpt_context mpt_entry;
+};
+
+struct tag_roce_cmd_modify_mpt {
+ struct tag_roce_verbs_cmd_com com;
+
+ u32 new_key;
+
+ /* DW2~3 */
+ union {
+ u64 length; /* Length of mr or mw */
+
+ struct {
+ u32 length_hi; /* Length of mr or mw */
+ u32 length_lo; /* Length of mr or mw */
+ } dw2;
+ };
+
+ /* DW4~5 */
+ union {
+ u64 iova; /* Start address of mr or mw */
+
+ struct {
+ u32 iova_hi; /* Upper 32 bits of the start address of mr or mw */
+ u32 iova_lo; /* Lower 32 bits of the start address of mr or mw */
+ } dw4;
+ };
+};
+
+struct tag_roce_cmd_mpt_hw2sw {
+ struct tag_roce_verbs_cmd_com com;
+
+ u32 dmtt_flags;
+ u32 dmtt_num;
+ u32 dmtt_cache_line_start;
+ u32 dmtt_cache_line_end;
+ u32 dmtt_cache_line_size;
+};
+
+struct tag_roce_cmd_query_mtt {
+ struct tag_roce_verbs_cmd_com com;
+
+ u32 mtt_addr_start_hi32;
+ u32 mtt_addr_start_lo32;
+ u32 mtt_num;
+ u32 rsvd;
+};
+
+struct tag_roce_cmd_creat_cq {
+ struct tag_roce_verbs_cmd_com com;
+ struct roce_cq_context cqc;
+};
+
+struct tag_roce_cmd_resize_cq {
+ struct tag_roce_verbs_cmd_com 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. */
+ struct tag_roce_cq_mtt_info mtt_info;
+};
+
+struct tag_roce_cmd_modify_cq {
+ struct tag_roce_verbs_cmd_com com;
+ u32 max_cnt;
+ u32 timeout;
+};
+
+struct tag_roce_cmd_cq_hw2sw {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_cmd_cq_cache_invalidate {
+ struct tag_roce_verbs_cmd_com com;
+ struct tag_roce_cq_mtt_info mtt_info;
+};
+
+struct tag_roce_cmd_roce_cq_query {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_cmd_creat_srq {
+ struct tag_roce_verbs_cmd_com com;
+ struct roce_srq_context srqc;
+};
+
+struct tag_roce_cmd_srq_arm {
+ struct tag_roce_verbs_cmd_com 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;
+ };
+};
+
+struct tag_roce_cmd_srq_hw2sw {
+ struct tag_roce_verbs_cmd_com com;
+ struct tag_roce_cq_mtt_info mtt_info;
+ u32 srq_buf_len;
+ u32 wqe_cache_line_start;
+ u32 wqe_cache_line_end;
+ u32 wqe_cache_line_size;
+};
+
+struct tag_roce_cmd_srq_query {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_cmd_modify_qpc {
+ struct tag_roce_verbs_cmd_com com;
+
+ u32 opt;
+ u32 rsvd[3];
+ struct roce_qp_context qpc;
+};
+
+struct tag_roce_cmd_qp_modify2rst {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_cmd_qp_modify_rts2sqd {
+ struct tag_roce_verbs_cmd_com com;
+
+ u32 sqd_event_en;
+ u32 rsvd;
+};
+
+struct tag_roce_cmd_qp_query {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_cmd_modify_ctx {
+ struct tag_roce_verbs_cmd_com com;
+ u32 ctx_type;
+ u32 offset;
+ u32 value;
+ u32 mask;
+};
+
+struct tag_roce_cmd_cap_pkt {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_modify_hash_value {
+ struct tag_roce_verbs_cmd_com com;
+ u32 hash_value;
+};
+
+struct tag_roce_modify_udp_src_port {
+ struct tag_roce_verbs_cmd_com com;
+ u32 udp_src_port;
+};
+
+struct roce_get_qp_udp_src_port {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_get_qp_rx_port {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_get_qp_func_table {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+#endif /* ROCE_VERBS_CMD_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_cq_attr.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_cq_attr.h
new file mode 100644
index 0000000000000..19c27502467eb
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_cq_attr.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_CQ_ATTR_H
+#define ROCE_VERBS_CQ_ATTR_H
+
+#include "roce_verbs_mr_attr.h"
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#pragma pack(4)
+struct roce_verbs_cq_attr {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 signature : 5;
+ u32 ci_on_chip : 1;
+ u32 cnt_clear_en : 1;
+ u32 cnt_adjust_en : 1;
+ u32 rsvd : 3;
+ u32 timer_mode : 1;
+ u32 arm_timer_en : 1;
+ u32 tss_timer_num : 3;
+ u32 mtt_page_size : 4;
+ u32 cqe_size : 3;
+ u32 page_size : 4;
+ u32 size : 5;
+#else
+ /*
+ * Completion Queue size, equals to (2^cq_size)*CQE.
+ * The maximum CQ size is 2^23 CQEs.
+ */
+ u32 size : 5;
+ u32 page_size : 4; /* Page size of CQ, equals to (2^cq_page_size)*4KB. */
+ /*
+ * Completion Queue Entry (CQE) size in bytes is (2^cq_cqe_size)*16B.
+ * The minimum size is 32B and the values 0, 3, 4, 5, 6, 7 are reserved.
+ */
+ u32 cqe_size : 3;
+ u32 mtt_page_size : 4;
+ u32 tss_timer_num : 3;
+ u32 arm_timer_en : 1;
+ u32 timer_mode : 1;
+ u32 rsvd : 3;
+ u32 cnt_adjust_en : 1;
+ u32 cnt_clear_en : 1;
+ /*
+ * If set, the CI of Complete Queue is stored in the chip,
+ * the counter is absolute value.
+ */
+ u32 ci_on_chip : 1;
+ u32 signature : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 state : 4;
+ u32 rsvd : 14;
+ u32 ep : 3;
+ u32 cos : 3;
+ u32 so_ro : 2;
+ u32 dma_attr_idx : 6;
+#else
+ /*
+ * It specifies the outbound PCIe TLP header attribute of the
+ * DMA operation.This filed is only valid when processing CQ's CQEs.
+ */
+ u32 dma_attr_idx : 6;
+ /*
+ * It specifies the ATTR[1:0] bits in the outbound PCIe
+ * TLP headers of the DMA operation.
+ * This field is only valid when processing CQ's CQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ */
+ u32 so_ro : 2;
+ u32 cos : 3;
+ u32 ep : 3;
+ u32 rsvd : 14;
+ u32 state : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ceqn : 8;
+ u32 rsvd : 1;
+ u32 arm_ceqe_en : 1;
+ u32 ceqe_en : 1;
+ u32 cqecnt_rctl_en : 1;
+ u32 cqecnt_lth : 4;
+ u32 idle_max_count : 16;
+#else
+ u32 idle_max_count : 16;
+ u32 cqecnt_lth : 4;
+ u32 cqecnt_rctl_en : 1;
+ u32 ceqe_en : 1;
+ u32 arm_ceqe_en : 1;
+ u32 rsvd : 1;
+ u32 ceqn : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 max_cnt : 16;
+ u32 timeout : 16;
+#else
+ /*
+ * Completion Event Moderation timer in microseconds.
+ * 0x0: interrupt moderation disabled.
+ */
+ u32 timeout : 16;
+ /*
+ * Completion Event Moderation counters.
+ * 0x0: interrupt moderation disabled.
+ */
+ u32 max_cnt : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 - DW5 */
+ union {
+ /*
+ * The GPA of Layer 0 MTT. It may point to the CQ's buffer directly.
+ * low 3bits(cq_gpa_sign)
+ */
+ u64 cqc_l0mtt_gpa;
+ struct {
+ u32 cqc_l0mtt_gpa_hi;
+ u32 cqc_l0mtt_gpa_lo;
+ } dw4_dw5;
+ };
+
+ /* DW6 - DW7 */
+ union {
+ /* The GPA of stored CI of Complete Queue.
+ * Address translation hop numbers.
+ * 0x0: the 'cq_l0mtt_gpa' points to the buffer of CQ directly.
+ * 0x1: it need to perform one hop address translation to get the buffer's
+ * address of CQ; 0x2: there is two hop address translation to get the buffer's
+ * address of CQ; 0x3: reserved.
+ */
+ u64 ci_record_gpa_at_hop_num;
+ struct {
+ u32 ci_record_gpa_hi;
+ /* bit[1:0] Address translation hop numbers */
+ u32 ci_record_gpa_lo_at_hop_num;
+ } dw6_dw7;
+ };
+};
+
+struct tag_roce_verbs_cq_resize_info {
+ /* DW0~3 */
+ u32 mtt_page_size; /* Size of the mtt page after resize. */
+ 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];
+ };
+
+ /* DW6~10 */
+ struct tag_roce_verbs_mtt_cacheout_info cmtt_cache;
+};
+
+struct tag_roce_verbs_modify_cq_info {
+ u32 max_cnt;
+ u32 timeout;
+};
+#pragma pack()
+
+#endif /* ROCE_VERBS_CQ_ATTR_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_ext_attr.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_ext_attr.h
new file mode 100644
index 0000000000000..471824a0f78b0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_ext_attr.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_EXT_ATTR_H
+#define ROCE_VERBS_EXT_ATTR_H
+
+#include "roce_verbs_pub.h"
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+enum VERBS_ATTR_EXT_TYPE_E {
+ VERBS_ATTR_EXT_TYPE_NONE = 0,
+ VERBS_ATTR_EXT_TYPE_SQP,
+ VERBS_ATTR_EXT_TYPE_RSVD = 0xff
+};
+
+#define ROCE_VERBS_SQP_WQE_SIZE (2)
+
+#pragma pack(4)
+
+struct tag_roce_verbs_sqp_attr {
+ /* DW0 */
+ union tag_roce_verbs_seg_hdr seg_hdr;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd0 : 26;
+ u32 sqp_wqecnt_lth : 4;
+ u32 sqp_wqecnt_rctl_en : 1;
+ u32 sqp_ci_on_chip : 1;
+#else
+ u32 sqp_ci_on_chip : 1;
+ u32 sqp_wqecnt_rctl_en : 1;
+ u32 sqp_wqecnt_lth : 4;
+ u32 rsvd0 : 26;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+};
+
+#pragma pack()
+
+#endif /* ROCE_VERBS_EXT_ATTR_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_format.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_format.h
new file mode 100644
index 0000000000000..75b14cc254ed8
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_format.h
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_FORMAT_H
+#define ROCE_VERBS_FORMAT_H
+
+#include "roce_verbs_pub.h"
+#include "roce_verbs_attr.h"
+
+
+/* ********************************************************************************** */
+/* * verbs struct */
+struct tag_roce_uni_cmd_gid {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_gid_attr gid_attr;
+};
+
+struct tag_roce_uni_cmd_clear_gid {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_clear_gid_info gid_clear;
+};
+
+struct tag_roce_uni_cmd_qurey_gid {
+ struct tag_roce_verbs_cmd_header com;
+};
+
+struct tag_roce_uni_cmd_flush_mpt {
+ struct tag_roce_verbs_cmd_header com;
+};
+
+struct tag_roce_uni_cmd_mpt_query {
+ struct tag_roce_verbs_cmd_header com;
+};
+
+struct tag_roce_uni_cmd_sw2hw_mpt {
+ struct tag_roce_verbs_cmd_header com;
+ /* When creating a MR/MW, you need to enter the content of the MPT Context. */
+ struct tag_roce_verbs_mr_attr mr_attr;
+};
+
+struct tag_roce_uni_cmd_modify_mpt {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_mr_sge mr_sge;
+};
+
+struct tag_roce_uni_cmd_mpt_hw2sw {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_mtt_cacheout_info dmtt_cache;
+};
+
+struct tag_roce_uni_cmd_query_mtt {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_query_mtt_info mtt_query;
+};
+
+struct tag_roce_uni_cmd_creat_cq {
+ struct tag_roce_verbs_cmd_header com;
+ struct roce_verbs_cq_attr cq_attr;
+};
+
+struct tag_roce_uni_cmd_resize_cq {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_cq_resize_info cq_resize;
+};
+
+struct tag_roce_uni_cmd_modify_cq {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_modify_cq_info cq_modify;
+};
+
+struct tag_roce_uni_cmd_cq_hw2sw {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_mtt_cacheout_info cmtt_cache;
+};
+
+struct tag_roce_uni_cmd_roce_cq_query {
+ struct tag_roce_verbs_cmd_header com;
+};
+
+struct tag_roce_uni_cmd_creat_srq {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_srq_attr srq_attr;
+};
+
+struct tag_roce_uni_cmd_srq_arm {
+ struct tag_roce_verbs_cmd_header com;
+ union tag_roce_verbs_arm_srq_info srq_arm;
+};
+
+struct tag_roce_uni_cmd_srq_hw2sw {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_srq_hw2sw_info srq_cache;
+};
+
+struct tag_roce_uni_cmd_srq_query {
+ struct tag_roce_verbs_cmd_header com;
+};
+
+struct tag_roce_uni_cmd_modify_qpc {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_qp_attr qp_attr;
+};
+
+struct tag_roce_uni_cmd_qp_modify2rst {
+ struct tag_roce_verbs_cmd_header com;
+};
+
+struct tag_roce_uni_cmd_qp_modify_rts2sqd {
+ struct tag_roce_verbs_cmd_header com;
+ u32 sqd_event_en;
+};
+
+struct tag_roce_uni_cmd_qp_query {
+ struct tag_roce_verbs_cmd_header com;
+};
+
+struct tag_roce_uni_cmd_qp_cache_invalid {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_qp_hw2sw_info qp_cache;
+};
+
+struct tag_roce_uni_cmd_modify_ctx {
+ struct tag_roce_verbs_cmd_header com;
+ struct tag_roce_verbs_modify_ctx_info ctx_modify;
+};
+
+struct tag_roce_uni_cmd_cap_pkt {
+ struct tag_roce_verbs_cmd_header com;
+};
+
+
+#endif /* ROCE_VERBS_FORMAT_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_gid_attr.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_gid_attr.h
new file mode 100644
index 0000000000000..b4d58bd8ddf74
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_gid_attr.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_GID_ATTR_H
+#define ROCE_VERBS_GID_ATTR_H
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#pragma pack(4)
+struct tag_roce_verbs_gid_ipv4_attr {
+ /* DW0 */
+ union {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 udpudp_len_gap : 8;
+ u32 rsvd : 8;
+ u32 bth_addr : 16;
+#else
+ u32 bth_addr : 16;
+ u32 rsvd : 8;
+ u32 udpudp_len_gap : 8;
+#endif
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ip_addr : 16;
+ u32 udp_addr : 16;
+#else
+ u32 udp_addr : 16;
+ u32 ip_addr : 16;
+#endif
+ u32 value;
+ } dw1;
+};
+
+struct tag_roce_verbs_gid_attr {
+ /* DW0~3 */
+ u32 gid[4];
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd0 : 12;
+ u32 cvlan : 12;
+ u32 rsvd : 8;
+#else
+ u32 rsvd : 8;
+ u32 cvlan : 12;
+ u32 rsvd0 : 12;
+#endif
+ } bs;
+ u32 value;
+ } dw4;
+
+ /* DW5 */
+ union {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ppersp_pad_len : 8;
+ u32 l2_len : 8;
+ u32 ipv4_hdr_len : 8;
+ u32 pkthdr_len : 8;
+#else
+ u32 pkthdr_len : 8;
+ u32 ipv4_hdr_len : 8;
+ u32 l2_len : 8;
+ u32 ppersp_pad_len : 8;
+#endif
+ u32 value;
+ } dw5;
+
+ /* DW6 */
+ union {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 7;
+ u32 o_ip_type : 1;
+ u32 o_tag : 2;
+ u32 gid_update : 1;
+ u32 rsvd0 : 1;
+ u32 gid_type : 2;
+ u32 tag : 2;
+ u32 smac_hi16 : 16;
+#else
+ u32 smac_hi16 : 16;
+ u32 tag : 2;
+ /* 0:ROCE V1; 1:ROCE V2 IPV4; 2:ROCE V2 IPV6; other:rsvd */
+ u32 gid_type : 2;
+ u32 rsvd0 : 1;
+ u32 gid_update : 1;
+ u32 o_tag : 2;
+ u32 o_ip_type : 1;
+ u32 rsvd : 7;
+#endif
+ u32 value;
+ } dw6;
+
+ u32 smac_lo32;
+
+ struct tag_roce_verbs_gid_ipv4_attr ipv4;
+};
+
+struct tag_roce_verbs_clear_gid_info {
+ u32 gid_num;
+};
+#pragma pack()
+
+#endif /* ROCE_VERBS_GID_ATTR_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_mr_attr.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_mr_attr.h
new file mode 100644
index 0000000000000..d684dd77866a2
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_mr_attr.h
@@ -0,0 +1,330 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_MR_ATTR_H
+#define ROCE_VERBS_MR_ATTR_H
+
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#pragma pack(4)
+struct tag_roce_verbs_mr_sge {
+ u32 rsvd;
+ u32 new_key;
+
+ /* DW2~3 */
+ union {
+ u64 length; /* Length of mr or mw */
+
+ struct {
+ u32 length_hi; /* Length of mr or mw */
+ u32 length_lo; /* Length of mr or mw */
+ } dw2;
+ };
+
+ /* DW4~5 */
+ union {
+ u64 iova; /* Start address of mr or mw */
+
+ struct {
+ u32 iova_hi; /* Upper 32 bits of the start address of mr or mw */
+ u32 iova_lo; /* Lower 32 bits of the start address of mr or mw */
+ } dw4;
+ };
+};
+
+struct tag_roce_verbs_mtt_cacheout_info {
+ u32 mtt_flags; /* Indicates whether to kick out cache. by queue (0) or VF(1). */
+ /*
+ * Number of cmtt, which needs to be assigned by
+ * the driver when the is kicked out by queue.
+ */
+ u32 mtt_num;
+ /* The driver needs to read the driver from the configuration file. */
+ u32 mtt_cache_line_start;
+ /* The driver needs to read the driver from the configuration file. */
+ u32 mtt_cache_line_end;
+ u32 mtt_cache_line_size; /* 0:256B,1:512B */
+};
+
+struct tag_roce_verbs_wqe_cacheout_info {
+ u32 wqe_flags; /* Indicates whether to kick out cache. by queue (0) or VF(1). */
+ /*
+ * Number of wqe, which needs to be assigned by the
+ * driver when the is kicked out by queue.
+ */
+ u32 wqe_num;
+ /* The driver needs to read the driver from the configuration file. */
+ u32 wqe_cache_line_start;
+ /* The driver needs to read the driver from the configuration file. */
+ u32 wqe_cache_line_end;
+ u32 wqe_cache_line_size; /* 0:256B,1:512B */
+};
+
+
+struct tag_roce_verbs_query_mtt_info {
+ u32 mtt_addr_start_hi32;
+ u32 mtt_addr_start_lo32;
+ u32 mtt_num;
+ u32 rsvd;
+};
+
+struct tag_roce_dif_user_data_s {
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 smd_tp : 2;
+ u32 app_esc : 1;
+ u32 ref_esc : 1;
+ u32 sct_v_tp : 2;
+ u32 sct_sz : 1;
+ u32 md_sz : 1;
+ u32 hdr_vld : 1;
+ u32 sec_num : 23;
+#else
+ u32 sec_num : 23;
+ u32 hdr_vld : 1; // tx: 0->no nvme hdr, 1: hdr
+ u32 md_sz : 1;
+ u32 sct_sz : 1;
+ u32 sct_v_tp : 2;
+ u32 ref_esc : 1;
+ u32 app_esc : 1;
+ u32 smd_tp : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rep_app_tag : 16;
+ u32 grd_v_en : 1;
+ u32 grd_rid : 2;
+ u32 grd_v_agm : 1;
+ u32 grd_ri_agm : 1;
+ u32 grd_agm_ini : 1;
+ u32 crc16_ini : 1;
+ u32 ipcs_ini : 1;
+ u32 ref_v_en : 1;
+ u32 ref_rid : 2;
+ u32 ref_v_inc : 1;
+ u32 ref_ri_inc : 1;
+ u32 app_v_en : 1;
+ u32 app_rid : 2;
+#else
+ u32 app_rid : 2;
+ u32 app_v_en : 1;
+ u32 ref_ri_inc : 1;
+ u32 ref_v_inc : 1;
+ u32 ref_rid : 2;
+ u32 ref_v_en : 1;
+ u32 ipcs_ini : 1;
+ u32 crc16_ini : 1;
+ u32 grd_agm_ini : 1;
+ u32 grd_ri_agm : 1;
+ u32 grd_v_agm : 1;
+ u32 grd_rid : 2;
+ u32 grd_v_en : 1;
+ u32 rep_app_tag : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cmp_app_tag : 16;
+ u32 cmp_app_tag_mask : 16;
+#else
+ u32 cmp_app_tag_mask : 16;
+ u32 cmp_app_tag : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ u32 cmp_ref_tag;
+ u32 rep_ref_tag;
+};
+
+struct tag_roce_verbs_mr_attr {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+ u32 mtt_layer_num : 3; /* Mtt level */
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 rsvd2 : 4;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ /* The value 1 indicates that the remote Atomic permission is supported. */
+ u32 access_ra : 1;
+ u32 bpd : 1; /* 1: Bound to pd */
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 dif_mode : 1;
+ u32 rkey : 1;
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ /* Mr or mw. The value 1 indicates MR, and the value 0 indicates MW. */
+ u32 r_w : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ /* Whether the mr supports the binding of the mw */
+ u32 access_bind : 1;
+#else
+ /* Whether the mr supports the binding of the mw */
+ u32 access_bind : 1;
+ /* Indicates whether the FRMR can specify remote rights. */
+ u32 remote_access_en : 1;
+ /* Indicates whether the FRMR operation is supported. */
+ u32 fast_reg_en : 1;
+ /* Indicates whether to support the INVALID operation. */
+ u32 invalid_en : 1;
+ /* Indicates whether to support the remote INVALID operation. */
+ u32 remote_invalid_en : 1;
+ u32 r_w : 1; /* Mr or mw */
+ u32 pa : 1; /* Flag bit of DMA_MR */
+ u32 rkey : 1;
+ u32 dif_mode : 1;
+ u32 bqp : 1; /* 1: Bound to qp */
+ u32 bpd : 1; /* 1: Bound to pd */
+ /* The value 1 indicates that the remote Atomic permission is supported. */
+ u32 access_ra : 1;
+ u32 access_rw : 1; /* 1: The remote write permission is supported. */
+ /* 1: Indicates that the remote read permission is supported. */
+ u32 access_rr : 1;
+ /* The value 1 indicates that the local write permission is supported. */
+ u32 access_lw : 1;
+ /* 1: Indicates that the local read permission is supported. */
+ u32 access_lr : 1;
+ /* The value 1 indicates that ZBVA is supported, that is, iova = 0. */
+ u32 zbva : 1;
+ u32 rsvd2 : 4;
+ u32 mtt_page_size : 4; /* Page_size of mtt */
+ u32 mtt_layer_num : 3; /* Number of mtt levels */
+ u32 buf_page_size : 4; /* Page_size of the buffer */
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 so_ro : 2;
+ u32 dma_attr_idx : 6;
+ u32 sector_size : 1;
+ u32 ep : 3;
+ u32 qpn : 20;
+#else
+ u32 qpn : 20; /* Qp bound to mw */
+ u32 ep : 3;
+ u32 sector_size : 1; /* 0:512B, 1:4KB */
+ u32 dma_attr_idx : 6; /* Dma attribute index */
+ u32 so_ro : 2; /* Dma order-preserving flag */
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 status : 4;
+ u32 indirect_mr : 1;
+ u32 cos : 3;
+ u32 block_size : 6;
+ u32 pdn : 18;
+#else
+ u32 pdn : 18; /* Pd bound to mr or mw */
+ u32 block_size : 6; /* 2^(page_size+12) + 8*block_size */
+ u32 cos : 3;
+ u32 indirect_mr : 1;
+ u32 status : 4; /* Mpt status. Valid values are VALID, FREE, and INVALID. */
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 mkey : 8;
+ u32 sw_dif_en : 1;
+ u32 page_mode : 1;
+ u32 fbo : 22;
+#else
+ u32 fbo : 22;
+ u32 page_mode : 1;
+ u32 sw_dif_en : 1;
+ u32 mkey : 8; /* The index is not included. */
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4~5 */
+ union {
+ u64 iova; /* Start address of mr or mw */
+ struct {
+ u32 iova_hi; /* Upper 32 bits of the start address of mr or mw */
+ u32 iova_lo; /* Lower 32 bits of the start address of mr or mw */
+ } dw4;
+ };
+
+ /* DW6~7 */
+ union {
+ u64 length; /* Length of mr or mw */
+ struct {
+ u32 length_hi; /* Length of mr or mw */
+ u32 length_lo; /* Length of mr or mw */
+ } dw6;
+ };
+
+ /* DW8~9 */
+ union {
+ u64 mtt_base_addr; /* Mtt base address (pa),low 3bits(gpa_sign) */
+ struct {
+ u32 mtt_base_addr_hi; /* Mtt base address (pa) upper 32 bits */
+ /* Lower 32 bits of mtt base address (pa),low 3bits(gpa_sign) */
+ u32 mtt_base_addr_lo;
+ } dw8;
+ };
+
+ /* DW10 */
+ union {
+ u32 mr_mkey; /* This parameter is valid for MW. */
+ u32 mw_cnt; /* This parameter is valid when the MR is used. */
+ };
+
+ /* DW11 */
+ u32 mtt_sz;
+
+ /* DW12~16 */
+ struct tag_roce_dif_user_data_s dif_info;
+
+ /* DW17 */
+ u32 rsvd;
+};
+#pragma pack()
+
+#endif /* ROCE_VERBS_MR_ATTR_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_pub.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_pub.h
new file mode 100644
index 0000000000000..77bf316942e65
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_pub.h
@@ -0,0 +1,225 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_PUB_H
+#define ROCE_VERBS_PUB_H
+
+
+enum CMD_TYPE_BITMASK_E {
+ CMD_TYPE_BITMASK_EXT = 0,
+ CMD_TYPE_BITMASK_RSVD1,
+ CMD_TYPE_BITMASK_RSVD0,
+ CMD_TYPE_BITMASK_PLUGIN_RET,
+ CMD_TYPE_BITMASK_VBS,
+ CMD_TYPE_BITMASK_DSW,
+ CMD_TYPE_BITMASK_NOFAA,
+ CMD_TYPE_BITMASK_PLOG,
+ CMD_TYPE_BITMASK_DBG = 8,
+ CMD_TYPE_BITMASK_VROCE,
+ CMD_TYPE_BITMASK_CCF,
+ CMD_TYPE_BITMASK_GID,
+ CMD_TYPE_BITMASK_MR,
+ CMD_TYPE_BITMASK_SRQ,
+ CMD_TYPE_BITMASK_CQ,
+ CMD_TYPE_BITMASK_QP = 15
+};
+
+#define VERBS_CMD_TYPE_QP_BITMASK (1u << CMD_TYPE_BITMASK_QP)
+#define VERBS_CMD_TYPE_CQ_BITMASK (1u << CMD_TYPE_BITMASK_CQ)
+#define VERBS_CMD_TYPE_SRQ_BITMASK (1u << CMD_TYPE_BITMASK_SRQ)
+#define VERBS_CMD_TYPE_MR_BITMASK (1u << CMD_TYPE_BITMASK_MR)
+#define VERBS_CMD_TYPE_GID_BITMASK (1u << CMD_TYPE_BITMASK_GID)
+#define VERBS_CMD_TYPE_CCF_BITMASK (1u << CMD_TYPE_BITMASK_CCF)
+#define VERBS_CMD_TYPE_VROCE_BITMASK (1u << CMD_TYPE_BITMASK_VROCE)
+#define VERBS_CMD_TYPE_DEBUG_BITMASK (1u << CMD_TYPE_BITMASK_DBG)
+#define VERBS_CMD_TYPE_PLOG_BITMASK (1u << CMD_TYPE_BITMASK_PLOG)
+#define VERBS_CMD_TYPE_NOFAA_BITMASK (1u << CMD_TYPE_BITMASK_NOFAA)
+#define VERBS_CMD_TYPE_DSW_BITMASK (1u << CMD_TYPE_BITMASK_DSW)
+#define VERBS_CMD_TYPE_VBS_BITMASK (1u << CMD_TYPE_BITMASK_VBS)
+#define VERBS_CMD_TYPE_EXT_BITMASK (1u << CMD_TYPE_BITMASK_EXT)
+
+enum roce3_cmd_ret_status {
+ ROCE_CMD_RET_SUCCESS = 0x0,
+
+ ROCE_CMD_RET_FLR_ERR = 0x1,
+ ROCE_CMD_RET_FUNC_INVLD,
+ ROCE_CMD_RET_CMDMISC_UNSUPPORT,
+ ROCE_CMD_RET_CMDTYPE_UNSUPPORT,
+ ROCE_CMD_RET_RET_ADDR_INVLD,
+ ROCE_CMD_RET_INDEX_INVLD,
+ ROCE_CMD_RET_LOCAL_UNSUPPORT,
+ ROCE_CMD_RET_QPC_RSP_ERR = 0x10,
+ ROCE_CMD_RET_QPC_STATE_UNEXPECT,
+ ROCE_CMD_RET_MODIFY_QP_OPT_ERR,
+ ROCE_CMD_RET_MODIFY_QP_EXTEND_OP_API_ERR,
+ ROCE_CMD_RET_SQD_QP_FETCH_WQE_ERR,
+ ROCE_CMD_RET_RDMARC_SYNC_EXTEND_OP_API_ERR,
+ ROCE_CMD_RET_MODIFY_QP_OQID_ERR,
+ ROCE_CMD_RET_CQC_STATE_UNEXPECT = 0x18,
+ ROCE_CMD_RET_CQC_MISC_API_ERR,
+ ROCE_CMD_RET_CQC_CREATE_CACHE_OUT_ERR,
+ ROCE_CMD_RET_CQ_RESIZE_API_ERR,
+ ROCE_CMD_RET_CQ_EXTEND_OP_API_ERR,
+ ROCE_CMD_RET_CQ_TIEMR_DEL_ERR,
+ ROCE_CMD_RET_CQ_TIEMR_REM_ERR,
+ ROCE_CMD_RET_SRQC_STATE_UNEXPECT = 0x20,
+ ROCE_CMD_RET_SRQ_ARM_SRQ_CONT_EN_ERR,
+ ROCE_CMD_RET_SRQ_ARM_SRQ_API_ERR,
+ ROCE_CMD_RET_SRQ_EXTEND_OP_API_ERR,
+ ROCE_CMD_RET_MR_STATE_ERR = 0x28,
+ ROCE_CMD_RET_MR_BIND_MW_API_ERR,
+ ROCE_CMD_RET_MR_EXTEND_OP_API_ERR,
+ ROCE_CMD_RET_MR_MISC_LOAD_API_ERR,
+ ROCE_CMD_RET_MR_MPTC_SYNC_ERR,
+ ROCE_CMD_RET_MR_MISC_STORE_API_ERR,
+ ROCE_CMD_RET_MR_CACHE_OUT_MPT_ERR,
+ ROCE_CMD_RET_MR_CACHE_OUT_MTT_ERR,
+ ROCE_CMD_RET_DBG_EXTEND_OP_API_ERR = 0x30,
+ ROCE_CMD_RET_DBG_WQE_UPDATE_PI_ERR,
+ ROCE_CMD_RET_QU_FLUSH_API_ERR,
+ ROCE_CMD_RET_CC_HASH_API_ERR,
+ ROCE_CMD_RET_CMD_OP_LB_ERR,
+ ROCE_CMD_RET_CMD_OP_SRQN_ERR,
+ ROCE_CMD_RET_DIF_TASKID_ALLOC_ERR,
+ ROCE_CMD_RET_QP_EXTEND_OP_ERR,
+ ROCE_CMD_RET_LOAD_ERR,
+ ROCE_CMD_RET_STORE_ERR,
+ ROCE_CMD_RET_LOAD_HOST_GPA_ERR,
+ ROCE_CMD_RET_CACHE_OUT_ERR,
+ ROCE_CMD_RET_CACHE_OUT_MTT_ERR,
+ ROCE_CMD_RET_BANK_GPA_FLUSH_ERR,
+ ROCE_CMD_RET_INVALID_PARAM_ERR,
+ ROCE_CMD_RET_RSVD_ERR = 0xff,
+};
+
+enum roce3_cmd_ret_extend_op_err {
+ ROCE_CMD_RET_EXTEND_OP_NONE = 0x0,
+
+ ROCE_CMD_RET_EXTEND_OP_RCC_RRE = 0x1,
+ ROCE_CMD_RET_EXTEND_OP_RCC_RAE,
+ ROCE_CMD_RET_EXTEND_OP_RRWC_RWE,
+ ROCE_CMD_RET_EXTEND_OP_RRWC_STA,
+ ROCE_CMD_RET_EXTEND_OP_RCC_STA,
+ ROCE_CMD_RET_EXTEND_OP_SQC_STA,
+ ROCE_CMD_RET_EXTEND_OP_SQAC_STA,
+ ROCE_CMD_RET_EXTEND_OP_RQC_STA,
+ ROCE_CMD_RET_EXTEND_OP_CQC_TIMEOUT = 0x10,
+ ROCE_CMD_RET_EXTEND_OP_CQC_STA,
+ ROCE_CMD_RET_EXTEND_OP_SRQC_STA = 0x18,
+ ROCE_CMD_RET_EXTEND_OP_MPT_STA = 0x20,
+ ROCE_CMD_RET_EXTEND_OP_QPC_DBG_EDIT = 0x28,
+ ROCE_CMD_RET_EXTEND_OP_CQC_SRQC_DBG_EDIT
+};
+
+/* Mask description of *********ROCE verbs modify qp ******* */
+/*
+ ******************************************************************
+opt INIT2INIT INIT2RTR RTR2RTS RTS2RTS SQERR2RTS SQD2SQD SQD2RTS
+QP_OPTPAR_ALT_ADDR_PATH 0 √ √ √ √ √
+QP_OPTPAR_RRE 1 √ √ √ √ √ √ √
+QP_OPTPAR_RAE 2 √ √ √ √ √ √ √
+QP_OPTPAR_RWE 3 √ √ √ √ √ √ √
+QP_OPTPAR_PKEY_INDEX 4
+QP_OPTPAR_Q_KEY 5 √ √ √ √ √ √ √
+QP_OPTPAR_RNR_TIMEOUT 6 √ √ √ √ √
+QP_OPTPAR_PRIMARY_ADDR_PATH 7 √ √
+QP_OPTPAR_SRA_MAX 8 √ √
+QP_OPTPAR_RRA_MAX 9 √ √
+QP_OPTPAR_PM_STATE 10 √ √ √ √
+QP_OPTPAR_RETRY_COUNT 11 √ √
+QP_OPTPAR_RNR_RETRY 12 √ √
+QP_OPTPAR_ACK_TIMEOUT 13 √ √
+QP_OPTPAR_SCHED_QUEUE 14
+QP_OPTPAR_COUNTER_INDEX 15
+********************************************************************
+*/
+enum QP_OPTPAR_E {
+ QP_OPTPAR_ALT_ADDR_PATH = 0,
+ QP_OPTPAR_RRE,
+ QP_OPTPAR_RAE,
+ QP_OPTPAR_RWE,
+ QP_OPTPAR_PKEY_INDEX,
+ QP_OPTPAR_Q_KEY,
+ QP_OPTPAR_RNR_TIMEOUT,
+ QP_OPTPAR_PRIMARY_ADDR_PATH,
+ QP_OPTPAR_SRA_MAX = 8,
+ QP_OPTPAR_RRA_MAX,
+ QP_OPTPAR_PM_STATE,
+ QP_OPTPAR_RETRY_COUNT,
+ QP_OPTPAR_RNR_RETRY,
+ QP_OPTPAR_ACK_TIMEOUT,
+ QP_OPTPAR_SCHED_QUEUE,
+ QP_OPTPAR_COUNTER_INDEX = 15
+};
+
+#define ROCE_QP_ALT_ADDR_PATH_OPT (1u << QP_OPTPAR_ALT_ADDR_PATH)
+#define ROCE_QP_RRE_OPT (1u << QP_OPTPAR_RRE)
+#define ROCE_QP_RAE_OPT (1u << QP_OPTPAR_RAE)
+#define ROCE_QP_RWE_OPT (1u << QP_OPTPAR_RWE)
+#define ROCE_QP_PKEY_INDEX_OPT (1u << QP_OPTPAR_PKEY_INDEX)
+#define ROCE_QP_Q_KEY_OPT (1u << QP_OPTPAR_Q_KEY)
+#define ROCE_QP_RNR_TIMEOUT_OPT (1u << QP_OPTPAR_RNR_TIMEOUT)
+#define ROCE_QP_PRIMARY_ADDR_PATH_OPT (1u << QP_OPTPAR_PRIMARY_ADDR_PATH)
+#define ROCE_QP_SRA_MAX_OPT (1u << QP_OPTPAR_SRA_MAX)
+#define ROCE_QP_RRA_MAX_OPT (1u << QP_OPTPAR_RRA_MAX)
+#define ROCE_QP_PM_STATE_OPT (1u << QP_OPTPAR_PM_STATE)
+#define ROCE_QP_RETRY_COUNT_OPT (1u << QP_OPTPAR_RETRY_COUNT)
+#define ROCE_QP_RNR_RETRY_OPT (1u << QP_OPTPAR_RNR_RETRY)
+#define ROCE_QP_ACK_TIMEOUT_OPT (1u << QP_OPTPAR_ACK_TIMEOUT)
+#define ROCE_QP_SCHED_QUEUE_OPT (1u << QP_OPTPAR_SCHED_QUEUE)
+#define ROCE_QP_COUNTER_INDEX_OPT (1u << QP_OPTPAR_COUNTER_INDEX)
+
+#define ROCE_MODIFY_QP_INIT2INIT_OPT (~0x402e)
+#define ROCE_MODIFY_QP_INIT2RTR_OPT (~0x2ee)
+#define ROCE_MODIFY_QP_RTR2RTS_OPT (~0x3d6e)
+#define ROCE_MODIFY_QP_RTS2RTS_OPT (~0x46e)
+#define ROCE_MODIFY_QP_SQERR2RTS_OPT (~0x2e)
+#define ROCE_MODIFY_QP_SQD2SQD_OPT (~0x7fee)
+#define ROCE_MODIFY_QP_SQD2RTS_OPT (~0x46e)
+#define ROCE_MODIFY_QP_RTS2RTS_EXP_OPT (~0x10000)
+
+#define ROCE_MODIFY_QP_RTS2SQD_SQD_EVENT_OPT (0x80000000)
+/* ************************************************* */
+
+#pragma pack(4)
+struct tag_roce_verbs_cmd_header {
+ 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
+
+ u32 opt; //
+
+ union {
+ u32 value;
+
+ struct {
+ u32 cmd_type : 8;
+ u32 rsvd : 7;
+ u32 seg_ext : 1;
+ u32 cmd_len : 16; // verbs cmd total len(include cmd_com),unit:byte
+ } bs;
+ } dw3;
+};
+
+union tag_roce_verbs_seg_hdr {
+ u32 value;
+
+ struct {
+ u32 seg_type : 16;
+ u32 rsvd : 7;
+ u32 last_seg : 1;
+ u32 seg_len : 8; // seg info len,unit:4B
+ } bs;
+};
+
+#pragma pack()
+
+#endif /* ROCE_VERBS_PUB_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_srq_attr.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_srq_attr.h
new file mode 100644
index 0000000000000..a0e6412f50ea9
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_srq_attr.h
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_SRQ_ATTR_H
+#define ROCE_VERBS_SRQ_ATTR_H
+
+#include "roce_verbs_mr_attr.h"
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 0x4321
+#endif
+
+#pragma pack(4)
+struct tag_roce_verbs_srq_cont_attr {
+ /* DW0 */
+ u32 head_gpa_h;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 head_gpa_l : 20;
+ u32 rsvd : 11;
+ u32 head_gpa_vld : 1;
+#else
+ u32 head_gpa_vld : 1;
+ u32 rsvd : 11;
+ u32 head_gpa_l : 20;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cont_size : 2;
+ u32 rsvd : 10;
+ u32 warn_th : 4;
+ u32 head_idx : 16;
+#else
+ u32 head_idx : 16;
+ u32 warn_th : 4;
+ u32 rsvd : 10;
+ u32 cont_size : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+};
+
+struct tag_roce_verbs_srq_attr {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 xrcd : 16;
+ u32 mtt_page_size : 4;
+ u32 wqebb_size : 3;
+ u32 page_size : 4;
+ u32 size : 5;
+#else
+ /*
+ * Shared Receive Queue size, equals to (2^srq_size)*WQEBB,
+ * the maximum SRQ size is 16K WQEs, so this field doesn't exceed 14.
+ */
+ u32 size : 5;
+ /* Page size of SRQ, equals to (2^srq_page_size)*4KB */
+ u32 page_size : 4;
+ /*
+ * Shared Receive WQE Basic Block (WQEBB) size in bytes
+ * is (2^rq_wqebb_size)*16B.
+ * The minimum size is 32B and the values 0, 4, 5, 6, 7 are reserved
+ */
+ u32 wqebb_size : 3;
+ /* Page size of MTT for SRQ, equals to (2^srq_mtt_page_size)*4KB. */
+ u32 mtt_page_size : 4;
+ u32 xrcd : 16;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 state : 4;
+ u32 rsvd : 14;
+ u32 ep : 3;
+ u32 cos : 3;
+ u32 so_ro : 2;
+ u32 dma_attr_idx : 6;
+#else
+ /*
+ * It specifies the outbound PCIe TLP header attribute of the
+ * DMA operation.This filed is only valid when processing CQ's CQEs.
+ */
+ u32 dma_attr_idx : 6;
+ /* It specifies the ATTR[1:0] bits in the outbound PCIe TLP headers
+ * of the DMA operation.This field is only valid when processing
+ * CQ's CQEs.
+ * 2'b00: Strict Ordering;
+ * 2'b01: Relaxed Ordering;
+ * 2'b10: ID Based Ordering;
+ * 2'b11: Both Relaxed Ordering and ID Based Ordering.
+ */
+ u32 so_ro : 2;
+ u32 cos : 3;
+ u32 ep : 3;
+ u32 rsvd : 14;
+ u32 state : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 wqe_prefetch_max_num : 3;
+ u32 wqe_prefetch_min_num : 3;
+ u32 wqe_cache_thd_sel : 2;
+ u32 wqecnt_lth : 4;
+ u32 wqecnt_ctrl_en : 1;
+ u32 wqecnt_rctl : 1;
+ u32 mtt_prefetch_maxlen : 2;
+ u32 next_wqe_idx : 16;
+#else
+ /*
+ * The current WQE index; uses this field to get
+ * the corresponding WQE from SRQ.
+ */
+ u32 next_wqe_idx : 16;
+ u32 mtt_prefetch_maxlen : 2;
+ /*
+ * The hardware clear it to zero when performing a SRQ PCnt updating,
+ * and driver set it to one to indicate the hardware can performing
+ * SRQ PCnt updating.
+ */
+ u32 wqecnt_rctl : 1;
+ u32 wqecnt_ctrl_en : 1;
+ u32 wqecnt_lth : 4;
+ /*
+ * Maximum length of prefetch MTTs for SRQ.
+ * 000: prefetch length equals to zero;
+ * Others: prefetch length equals to
+ * (2^(srq_mtt_prefetch_maxlen-1)*1KB).
+ */
+ u32 wqe_cache_thd_sel : 2;
+ /*
+ * Minimum number of prefetch WQEBBs for SRQ.
+ * 000: prefetch number equals to zero;
+ * Others: prefetch number equals to (2^(srq_wqe_prefetch_minnum-1)).
+ */
+ u32 wqe_prefetch_min_num : 3;
+ /*
+ * Maximum number of prefetch WQEBBs for SRQ.
+ * 000: prefetch number equals to zero;
+ * Others: prefetch number equals to (2^srq_wqe_prefetch_maxnum).
+ */
+ u32 wqe_prefetch_max_num : 3;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 container : 1;
+ u32 pcnt_on_chip : 1;
+ u32 lth_pre_en : 1;
+ u32 rkey_en : 1;
+ u32 wqe_check_en : 1;
+ u32 lth_gap : 4;
+ u32 rsvd : 5;
+ u32 pd : 18;
+#else
+ u32 pd : 18;
+ u32 rsvd : 5;
+ u32 lth_gap : 4;
+ u32 wqe_check_en : 1;
+ u32 rkey_en : 1;
+ u32 lth_pre_en : 1;
+ u32 pcnt_on_chip : 1;
+ u32 container : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ u32 srqn;
+
+ /* DW5 */
+ u32 xrc_cqn;
+
+ /* DW6~7 */
+ union {
+ /*
+ * The GPA of Layer 0 MTT. It may point to the CQ's buffer directly.
+ * low 3bits(cq_gpa_sign)
+ */
+ u64 l0mtt_gpa;
+ struct {
+ u32 l0mtt_gpa_hi;
+ u32 l0mtt_gpa_lo;
+ } dw6_dw7;
+ };
+
+ /* DW8~9 */
+ union {
+ /*
+ * The GPA of stored CI of Complete Queue.
+ * Address translation hop numbers.
+ * 0x0: the 'cq_l0mtt_gpa' points to the buffer of CQ directly.
+ * 0x1: it need to perform one hop address translation to get the buffer's
+ * address of CQ; 0x2: there is two hop address translation to get the buffer's
+ * address of CQ; 0x3: reserved.
+ */
+ u64 record_gpa_at_hop_num;
+ struct {
+ u32 record_gpa_hi;
+ u32 record_gpa_lo_at_hop_num; /* bit[1:0] Address translation hop numbers */
+ } dw8_dw9;
+ };
+
+ struct tag_roce_verbs_srq_cont_attr cont;
+};
+
+struct tag_roce_verbs_srq_hw2sw_info {
+ /* DW0~3 */
+ u32 srq_buf_len;
+ u32 wqe_cache_line_start;
+ u32 wqe_cache_line_end;
+ u32 wqe_cache_line_size;
+
+ /* DW4~8 */
+ struct tag_roce_verbs_mtt_cacheout_info cmtt_cache;
+};
+
+union tag_roce_verbs_arm_srq_info {
+ 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;
+};
+#pragma pack()
+
+#endif /* ROCE_VERBS_SRQ_ATTR_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_ulp_format.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_ulp_format.h
new file mode 100644
index 0000000000000..fc49948a073f7
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_verbs_ulp_format.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_VERBS_ULP_FORMAT_H
+#define ROCE_VERBS_ULP_FORMAT_H
+#include "roce_verbs_cmd.h"
+#include "roce_ccf_format.h"
+
+/*******************AA*******************/
+struct tag_roce_aa_master_modify_qpc {
+ struct tag_roce_verbs_cmd_com com;
+ u32 opt;
+ u32 qid;
+ u32 local_comm_id;
+ u32 remote_comm_id;
+
+ struct roce_qp_context qpc;
+};
+
+struct tag_roce_aa_slave_modify_qpc {
+ struct tag_roce_verbs_cmd_com com;
+ u32 gid_index;
+ u32 qid;
+ u32 local_comm_id;
+ u32 remote_comm_id;
+
+ struct roce_qp_context qpc;
+};
+
+struct roce_aa_set_conn_stat_inbuf {
+ struct tag_roce_verbs_cmd_com com;
+ u32 qid;
+ u32 io_qpn[9];
+};
+
+struct roce_aa_get_master_qpn_inbuf {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct roce_aa_disconnect_inbuf {
+ struct tag_roce_verbs_cmd_com com;
+ u32 tid_h;
+ u32 tid_l;
+ u32 rsvd4;
+ u32 rsvd5;
+ u32 local_cmid;
+ u32 remote_cmid;
+ u32 remote_qpn;
+};
+
+struct roce_shard_map_entry {
+ u32 volume_id;
+ u32 hash_low_cnt : 8;
+ u32 dd_id : 8;
+ u32 lun_id : 16;
+
+ u32 rsvd : 8;
+ u32 hash_high_offset : 8;
+ u32 hash_low_offset : 8;
+ u32 hash_high_cnt : 8;
+ u32 admin_qpn;
+};
+
+struct roce_aa_set_shard_cfg_inbuf {
+ struct tag_roce_verbs_cmd_com com;
+ u32 op;
+ u32 entry_num;
+ struct roce_shard_map_entry shard_info[64];
+};
+
+struct roce_master_qp_modify2rst_inbuf {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+struct tag_roce_aa_query_master_qp_bitmap {
+ struct tag_roce_verbs_cmd_com com;
+};
+
+/*******************VBS*******************/
+struct tag_roce_vbs_master_modify_qpc {
+ struct tag_roce_verbs_cmd_com com;
+
+ u32 opt;
+ u32 sqpc_ci_record_addr_h;
+ u32 sqpc_ci_record_addr_l;
+ u32 rsvd;
+
+ struct roce_qp_context qpc;
+};
+
+#endif /* ROCE_VERBS_ULP_FORMAT_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_wqe_format.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_wqe_format.h
new file mode 100644
index 0000000000000..7e964a8cd5ce9
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_wqe_format.h
@@ -0,0 +1,930 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_WQE_FORMAT_H
+#define ROCE_WQE_FORMAT_H
+
+/* **************************************************************** */
+struct roce3_wqe_ctrl_seg {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 owner : 1;
+ u32 ctrlsl : 2;
+ u32 csl : 2;
+ u32 difsl : 3;
+ u32 cr : 1;
+ u32 df : 1;
+ u32 va : 1;
+ u32 tsl : 5;
+ u32 cf : 1;
+ u32 wf : 1;
+ u32 rsvd : 4;
+ u32 drvsl : 2;
+ u32 bdsl : 8;
+#else
+ /*
+ * Data segment length, in the unit of 1B. When inline is used,
+ * the length of inline is described. The total length of the
+ * data segment must be aligned to 8B.
+ */
+ u32 bdsl : 8;
+ /*
+ * Indicates the length of the driver section. The value is
+ * counted by 8B, and the value of RoCE is 0.
+ */
+ u32 drvsl : 2;
+ u32 rsvd : 4;
+ /* 0-Normal WQE, 1-link WQE */
+ u32 wf : 1;
+ /*
+ * Complete segment format flag. The 0-complete segment directly
+ * contains the status information. 1: SGL
+ */
+ u32 cf : 1;
+ /*
+ * Length of the task segment. The value ranges from 8 to 48.
+ * The value of RoCE ranges from 8 to 48.
+ */
+ u32 tsl : 5;
+ /*
+ * SGE address format flag. The 0-SGE contains the physical
+ * address and length. The 1-SGE contains the virtual address,
+ * length, and key. The value of RoCE is 1.
+ */
+ u32 va : 1;
+ /*
+ * Data segment format flag bit. 0-describes data in SGE format.
+ * 1: Data is described in inline format.
+ */
+ u32 df : 1;
+ /*
+ * The CQE generates the request flag. The 0-does not
+ * generate the CQE. 1: Generate CQE
+ */
+ u32 cr : 1;
+ /*
+ * DIF segment length. The value is counted by 8 bytes.
+ * The value of RoCE is 0.
+ */
+ u32 difsl : 3;
+ /*
+ * Length of the completed segment. The value is counted by 8B.
+ * The value of RoCE is 0.
+ */
+ u32 csl : 2;
+ /*
+ * Length of the control segment. The value is 8 bytes
+ * and the value of RoCE is 16.
+ */
+ u32 ctrlsl : 2;
+ /*
+ * Owner bit. The value 1 indicates all hardware, and the value 0
+ * indicates all software. The meaning of the queue owner bit is
+ * reversed every time the queue owner is traversed.
+ */
+ u32 owner : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 cl : 4;
+ u32 signature : 8;
+ u32 rsvd : 4;
+ u32 mask_pi : 16;
+#else
+ /*
+ * Pi is the value of the queue depth mask.
+ * It is valid when direct wqe.
+ */
+ u32 mask_pi : 16;
+ u32 rsvd : 4;
+ u32 signature : 8;
+ u32 cl : 4; /* The length of CQE is generated in the task segment. */
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 type : 2;
+ u32 rsvd1 : 3;
+ u32 cos : 3;
+ u32 cp_flag : 1;
+ u32 rsvd : 1;
+ u32 ctx_size : 2;
+ u32 qpn : 20;
+#else
+ u32 qpn : 20;
+ u32 ctx_size : 2; /* RoCE QPC size, 512B */
+ u32 rsvd : 1;
+ u32 cp_flag : 1; /* control plane flag */
+ u32 cos : 3; /* Scheduling priority. The value source is SL. */
+ u32 rsvd1 : 3;
+ u32 type : 2; /* Set RoCE SQ Doorbell to 2 and RoCE Arm CQ Doorbell to 3. */
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sub_type : 4; /* */
+ u32 sgid_index : 7; /* gid index */
+ /* 256B:0;512B:1;1024B:2;2048B:3;4096B:4 */
+ u32 mtu_shift : 3;
+ u32 rsvd : 1;
+ /* 1:XRC service type */
+ u32 xrc_vld : 1;
+ /* host sw write the sq produce index high 8bit to this section; */
+ u32 pi : 16;
+#else
+ /* host sw write the sq produce index high 8bit to this section; */
+ u32 pi : 16;
+ u32 xrc_vld : 1;
+ u32 rsvd : 1;
+ u32 mtu_shift : 3;
+ u32 sgid_index : 7;
+ u32 sub_type : 4;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 queue_id : 4;
+ u32 rsvd : 12;
+ u32 pi : 16;
+#else
+ u32 pi : 16;
+ u32 rsvd : 12;
+ u32 queue_id : 4;
+#endif
+ } bs1;
+ u32 value;
+ } dw3;
+};
+
+union roce3_wqe_tsk_com_seg {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 se : 1;
+ u32 f : 1;
+ u32 c : 1;
+ u32 op_type : 5;
+ u32 so : 1;
+ u32 cs_len_mul : 3;
+ u32 dif_en : 1;
+ u32 ext_vld : 1;
+ u32 xrc_srqn : 18;
+#else
+ /* The XRC is valid, and the remote SRQN is specified. */
+ u32 xrc_srqn : 18;
+ u32 ext_vld : 1;
+ u32 dif_en : 1;
+ /* * atomic cmp swap N len:atomic datalen=8*(cs_len_mul + 1) */
+ u32 cs_len_mul : 3;
+ /*
+ * Strong order-preserving flag, valid only for Local invalidate\Type
+ * 2 Bind MW and FRPMR (consider the implementation at the bottom layer)
+ */
+ u32 so : 1;
+ /*
+ * Operation type of the SQ WQE.
+ * 8'h00-Send
+ * 8'h01-Send with Invalidate
+ * 8'h02-Send with Immediate Data
+ * 8'h03-rsvd
+ * 8'h04-RDMA Write
+ * 8'h05-RDMA Write with Immediate Data
+ * 8'h06-RDMA WRITE CMD64
+ * 8'h07-rsvd
+ * 8'h08-RDMA READ
+ * 8'h09-ATOMIC WRITE
+ * 8'h0a-FLUSH
+ * 8'h0b-rsvd
+ * 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 operation(extended for further local operation)
+ * other-Reserved
+ */
+ u32 op_type : 5;
+ /*
+ * Indicates whether the SQ generates the CQE,
+ * which is required by the microcode.
+ */
+ u32 c : 1;
+ /* Indicates whether the SQ requires order-preserving. */
+ u32 f : 1;
+ /* Indicates whether the packet carries the SE flag. */
+ u32 se : 1;
+#endif
+ } bs;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 se : 1;
+ u32 f : 1;
+ u32 c : 1;
+ u32 op_type : 5;
+ u32 so : 1;
+ u32 rsvd : 2;
+ u32 vbs_vld : 1;
+ u32 dif_en : 1;
+ u32 ext_vld : 1;
+ u32 xrc_srqn : 18;
+#else
+ u32 xrc_srqn : 18;
+ u32 ext_vld : 1;
+ u32 dif_en : 1;
+ u32 vbs_vld : 1;
+ u32 rsvd : 2;
+ u32 so : 1;
+ u32 op_type : 5;
+ u32 c : 1;
+ u32 f : 1;
+ u32 se : 1;
+#endif
+ } bs1;
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 14;
+ u32 sticky : 1;
+ u32 repeat : 1;
+ u32 cmdid : 16;
+#else
+ u32 cmdid : 16;
+ u32 repeat : 1;
+ u32 sticky : 1;
+ u32 rsvd : 14;
+#endif
+ } nofaa;
+ u32 value;
+};
+
+union roce3_wqe_tsk_misc_seg {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 ext_last : 1;
+ u32 nxt_ext_hdr : 7;
+ u32 cmd_len : 8;
+ u32 rsvd : 8;
+ u32 last_ext_len : 8;
+#else
+ u32 last_ext_len : 8;
+ u32 rsvd : 8;
+ u32 cmd_len : 8;
+ u32 nxt_ext_hdr : 7;
+ u32 ext_last : 1;
+#endif
+ } bs;
+
+ u32 value;
+};
+
+struct roce3_wqe_tsk_rdma_sge_seg {
+ /* DW4~5 */
+ union {
+ u64 va;
+ struct {
+ u32 va_h32;
+ u32 va_l32;
+ } dw4;
+ };
+
+ /* DW6 */
+ u32 rkey;
+
+ /* DW7 */
+ u32 sig_key;
+};
+
+/* *
+ * Struct name: sq_wqe_task_remote_common.
+ * @brief : SQ WQE common.
+ * Description:
+ */
+struct tag_sq_wqe_task_remote_common {
+ union roce3_wqe_tsk_com_seg common;
+
+ u32 data_len; /* SQ WQE DMA LEN */
+
+ u32 immdata_invkey; /* SEND invalidate or immediate */
+
+ union roce3_wqe_tsk_misc_seg dw3;
+};
+
+/* Send WQE/Send with imme WQE/Send with invalid(inline or not inline) */
+struct roce3_wqe_send_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 data_len; /* Length of the data sent by the SQ WQE */
+
+ /* DW2 */
+ /*
+ * This parameter is valid for the immediate
+ * data operation or SEND invalidate.
+ */
+ u32 immdata_invkey;
+
+ /* DW3 */
+ union roce3_wqe_tsk_misc_seg dw3;
+};
+
+/* RDMA Read WQE/RDMA Write WQE/RDMA Write with imme WQE(inline or non-inline) */
+struct roce3_wqe_rdma_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 data_len;
+
+ /* DW2 */
+ u32 imm_data;
+
+ /* DW3 */
+ union roce3_wqe_tsk_misc_seg dw3;
+
+ /* DW4~5 */
+ union {
+ u64 va;
+ struct {
+ u32 va_h32;
+ u32 va_l32;
+ } dw4;
+ };
+
+ /* DW6 */
+ u32 rkey;
+
+ /* DW7 */
+ u32 sig_key;
+};
+
+/* RDMA Read WQE/RDMA Write WQE/RDMA Write with imme WQE(inline or non-inline) */
+struct roce3_wqe_rdma_ext_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 data_len;
+
+ /* DW2 */
+ u32 imm_data;
+
+ /* DW3 */
+ union roce3_wqe_tsk_misc_seg dw3;
+
+ /* DW4~5 */
+ struct roce3_wqe_tsk_rdma_sge_seg rdma;
+
+ u32 ulp_cmd[24];
+};
+
+/* Atomic WQE */
+struct roce3_wqe_atomic_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 key;
+
+ /* DW2~3 */
+ union {
+ u64 va;
+ struct {
+ u32 va_h32;
+ u32 va_l32;
+ } dw2;
+ };
+
+ /* DW4~5 */
+ union {
+ u64 swap_add_data;
+ struct {
+ u32 swap_add_data_h32;
+ u32 swap_add_data_l32;
+ } dw4;
+ };
+
+ /* DW6~7 */
+ union {
+ u64 cmp_data;
+ struct {
+ u32 cmp_data_h32;
+ u32 cmp_data_l32;
+ } dw6;
+ };
+};
+
+/* ext Atomic WQE */
+#define ROCE_WQE_ATOMIC_DATA_SIZE 32
+#define ROCE_WQE_ATOMIC_DATA_SIZE_2B_ALIGN (ROCE_WQE_ATOMIC_DATA_SIZE >> 1)
+struct roce3_wqe_ext_atomic_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 key;
+
+ /* DW2~3 */
+ union {
+ u64 va;
+ struct {
+ u32 va_h32;
+ u32 va_l32;
+ } dw2;
+ };
+
+ u32 atomic_data[ROCE_WQE_ATOMIC_DATA_SIZE];
+};
+
+/* Mask Atomic WQE */
+struct roce3_wqe_mask_atomic_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 rkey;
+
+ /* DW2~3 */
+ union {
+ u64 va;
+ struct {
+ u32 va_h32;
+ u32 va_l32;
+ } dw2;
+ };
+
+ /* DW4~5 */
+ union {
+ u64 swap_add_data;
+ struct {
+ u32 swap_add_data_h32;
+ u32 swap_add_data_l32;
+ } dw4;
+ };
+
+ /* DW6~7 */
+ union {
+ u64 cmp_data;
+ struct {
+ u32 cmp_data_h32;
+ u32 cmp_data_l32;
+ } dw6;
+ };
+
+ /* DW8~9 */
+ union {
+ u64 swap_msk;
+ struct {
+ u32 swap_msk_h32;
+ u32 swap_msk_l32;
+ } dw8;
+ };
+
+ /* DW9~10 */
+ union {
+ u64 cmp_msk;
+ struct {
+ u32 cmp_msk_h32;
+ u32 cmp_msk_l32;
+ } dw10;
+ };
+};
+
+/* UD send WQE */
+struct roce3_wqe_ud_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW1 */
+ u32 data_len;
+
+ /* DW2 */
+ u32 immdata_invkey;
+
+ union roce3_wqe_tsk_misc_seg dw2;
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 fl : 1;
+ /* DB cos or Path cos or MQM cos */
+ u32 wqe_cos : 3;
+ u32 stat_rate : 4;
+ u32 rsvd : 6;
+ u32 pd : 18;
+#else
+ u32 pd : 18; /* Used to verify the PD in the QPC. */
+ u32 rsvd : 6;
+ /* Maximum static rate control 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 stat_rate : 4;
+ /* DB cos or Path cos or MQM cos */
+ u32 wqe_cos : 3;
+ u32 fl : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 tc : 8;
+ u32 rsvd : 4;
+ u32 port : 4;
+ u32 vlan_en : 1;
+ u32 sgid_idx : 7;
+ u32 hop_limit : 8;
+#else
+ u32 hop_limit : 8;
+ u32 sgid_idx : 7;
+ u32 vlan_en : 1;
+ u32 port : 4;
+ u32 rsvd : 4;
+ u32 tc : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw4;
+
+ /* DW5 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 2;
+ u32 smac_index : 10;
+ u32 flow_label : 20;
+#else
+ u32 flow_label : 20;
+ u32 smac_index : 10;
+ u32 rsvd : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw5;
+
+ /* DW6~9 */
+ u8 dgid[16];
+
+ /* DW10 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ u32 dst_qp : 24;
+#else
+ u32 dst_qp : 24;
+ u32 rsvd : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw10;
+
+ /* DW11 */
+ u32 qkey;
+
+ /* DW12 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 vlan_pri : 3; /* send pkt pri */
+ u32 cfi : 1;
+ u32 vlan_id : 12;
+ u32 dmac_h16 : 16;
+#else
+ u32 dmac_h16 : 16;
+ u32 vlan_id : 12;
+ u32 cfi : 1;
+ u32 vlan_pri : 3; /* send pkt pri */
+#endif
+ } bs;
+ u32 value;
+ } dw12;
+
+ /* DW14 */
+ u32 dmac_l32;
+
+ /* DW15 */
+ u32 rsvd;
+};
+
+struct roce3_wqe_data_seg {
+ /* DW0~1 */
+ union {
+ u64 addr;
+ struct {
+ u32 addr_h32;
+ u32 addr_l32;
+ } bs;
+ };
+
+ /* DW2~3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 1;
+ u32 len : 31;
+#else
+ u32 len : 31;
+ u32 rsvd : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW4 */
+ u32 key;
+};
+
+/* Type1/2 MW Bind WQE */
+struct roce3_wqe_bind_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW0~2 */
+ u32 rsvd0[3];
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rae : 1;
+ u32 rwe : 1;
+ u32 rre : 1;
+ u32 type : 1;
+ u32 rsvd : 28;
+#else
+ u32 rsvd : 28;
+ /* MW type: 0-Type1 Window 1-Type2B Window */
+ u32 type : 1;
+ u32 rre : 1; /* Remote read enable */
+ u32 rwe : 1; /* Remote write enable */
+ /* Indicates whether remote Atomic is enabled. */
+ u32 rae : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ /*
+ * The MW corresponds to the MPT key and is indexed to the MPT
+ * through the New_Rkey. For the type1 MW, This parameter is
+ * valid only when the value of New_Rkey is the same as the
+ * value of mem_key in the MPT. For type 2 MW, it is valid only
+ * when New_Rkey is equal to mem_key+1 in MPT. If this parameter
+ * is valid, the corresponding field in the MPT is replaced with
+ * the entire section.
+ */
+ u32 new_rkey;
+
+ /* DW5 */
+ /* Indicates the mem_key of the MR bound to the MW. */
+ u32 lkey;
+
+ /* DW6 */
+ u32 rsvd1;
+
+ /* DW7~8 */
+ union {
+ /* Indicates the start virtual IP address of the MW. */
+ u64 va;
+ struct {
+ u32 va_h32;
+ u32 va_l32;
+ } bs;
+ } dw7;
+
+ /* DW9~10 */
+ union {
+ /* Indicates the length of the data corresponding to the MW. */
+ u64 len;
+ struct {
+ u32 len_h32;
+ u32 len_l32;
+ } bs;
+ } dw9;
+};
+
+/* Fast Register PMR WQE */
+struct roce3_wqe_frmr_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW0~1 */
+ u32 rsvd[2];
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 fbo : 22;
+ u32 rsvd : 10;
+#else
+ u32 rsvd : 10;
+ /* This parameter is valid when ZERO_BASE is set to 1. */
+ u32 fbo : 22;
+#endif
+ } bs;
+ u32 value;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rae : 1;
+ u32 rwe : 1;
+ u32 rre : 1;
+ u32 lwe : 1;
+ u32 lre : 1;
+ u32 be : 1;
+ u32 zbva : 1;
+ u32 block : 1;
+ u32 rsvd : 2;
+ u32 page_size : 6;
+ u32 pa_num : 16;
+#else
+ /*
+ * Number of registered PAs, which is calculated
+ * by the length/page_size.
+ */
+ u32 pa_num : 16;
+ u32 page_size : 6; /* Memory Region page size */
+ u32 rsvd : 2;
+ u32 block : 1;
+ u32 zbva : 1; /* ZERO_BASED Permission */
+ /* Indicates whether the binding operation is enabled. */
+ u32 be : 1;
+ u32 lre : 1; /* Local read enable */
+ u32 lwe : 1; /* Local write enable */
+ u32 rre : 1; /* Remote read enable */
+ u32 rwe : 1; /* Remote write enable */
+ /* Indicates whether remote Atomic is enabled. */
+ u32 rae : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw3;
+
+ /* DW4 */
+ u32 m_key; /* Key of the Memory Region. */
+
+ /* DW5~6 */
+ union {
+ /*
+ * Start virtual address of Memory Region.
+ * This parameter is valid only when ZBVA is not set to 1.
+ */
+ u64 va;
+ struct {
+ u32 va_h32;
+ u32 va_l32;
+ } bs;
+ } dw5;
+
+ /* DW7~8 */
+ union {
+ u64 len; /* Length of Memory Region */
+ struct {
+ u32 len_h32;
+ u32 len_l32;
+ } bs;
+ } dw7;
+
+ /* DW9~10 */
+ union {
+ /* Physical address for storing the cache of the PA table. */
+ u64 pbl_addr;
+ struct {
+ u32 pbl_addr_h32;
+ u32 pbl_addr_l32;
+ } bs;
+ } dw9;
+};
+
+struct roce3_sge_info {
+ union {
+ u64 sge_vaddr;
+ struct {
+ u32 sge_vaddr_hi;
+ u32 sge_vaddr_lo;
+ } bs;
+ } dw0;
+
+ u32 sge_length;
+ u32 sge_key;
+};
+
+
+/* Local Invalidate WQE */
+struct roce3_wqe_local_inv_tsk_seg {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW0 */
+ u32 rsvd;
+
+ /* DW1 */
+ u32 inv_key; /* Mem_Key for invalidate */
+
+ /* DW2 */
+ u32 rsvd1;
+};
+
+/* * SRQ Data Format start */
+struct roce3_wqe_srq_data_seg {
+ /* DW0~1 */
+ union {
+ u64 addr;
+
+ struct {
+ u32 addr_h32;
+ u32 addr_l32;
+ } bs;
+ };
+
+ /* DW2 */
+ union {
+ struct {
+ /* Reserved field */
+ u32 rsv : 1;
+ /* Data length. The value can be [0 or 2G-1]. */
+ u32 len : 31;
+ } bs;
+ u32 length;
+ } dw2;
+
+ /* DW3 */
+ union {
+ struct {
+ /*
+ * Last flag. The 0-also has the next SGE.
+ * 1: The current SGE is the last one.
+ */
+ u32 last : 1;
+ /*
+ * Extended flag. The value 0-is normal and does not need to be extended.
+ * 1: Extended mode. The address of the current SGE points to SGL.
+ * The key and len are invalid. For RoCE, the value is fixed to 0.
+ */
+ u32 ext : 1;
+ /*
+ * Local_key. The least significant eight bits are keys,
+ * and the most significant 22 bits are
+ * indexes. The most significant two bits are reserved and only
+ * 20 bits are used.
+ */
+ u32 key : 30;
+ } bs;
+ u32 lkey;
+ } dw3;
+};
+/* * SRQ Data Format end */
+
+struct roce_osd_srq_link_wqe {
+ u32 cont_gpa_h;
+
+ union {
+ struct {
+ u32 cont_gpa_l : 24;
+ u32 rsvd : 8;
+ } bs;
+ u32 value;
+ } dw1;
+
+ u32 rsvd;
+
+ union {
+ struct {
+ u32 rsvd : 1;
+ u32 link_flag : 1;
+ u32 rsvd1 : 30;
+ } bs;
+ u32 value;
+ } dw3;
+
+ union {
+ struct {
+ u32 cur_container_idx : 16;
+ u32 container_idx : 16;
+ } bs;
+ u32 value;
+ } dw4;
+};
+
+
+#endif // ROCE_WQE_FORMAT_H
diff --git a/drivers/infiniband/hw/hiroce3/include/rdma/roce_xqe_format.h b/drivers/infiniband/hw/hiroce3/include/rdma/roce_xqe_format.h
new file mode 100644
index 0000000000000..4ad437ec21297
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/rdma/roce_xqe_format.h
@@ -0,0 +1,722 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_XQE_FORMAT_H
+#define ROCE_XQE_FORMAT_H
+
+/* * SQ DB Format start */
+struct roce_sq_db_seg {
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 type : 5;
+ u32 cos : 3;
+ u32 cp_flag : 1;
+ u32 rsvd : 1;
+ u32 ctx_size : 2;
+ u32 qpn : 20;
+#else
+ u32 qpn : 20;
+ /* RoCE QPC size, 512B */
+ u32 ctx_size : 2;
+ u32 rsvd : 1;
+ /* control plane flag */
+ u32 cp_flag : 1;
+ /* Scheduling priority. The value source is SL. */
+ u32 cos : 3;
+ /* Set RoCE SQ Doorbell to 2 and RoCE Arm CQ Doorbell to 3. */
+ u32 type : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 sub_type : 4;
+ /* gid index */
+ u32 sgid_index : 7;
+ /* 256B:0;512B:1;1024B:2;2048B:3;4096B:4 */
+ u32 mtu_shift : 3;
+ u32 rsvd : 1;
+ /* 1:XRC service type */
+ u32 xrc_vld : 1;
+ u32 resv : 8;
+ /* host sw write the sq produce index high 8bit to this section; */
+ u32 pi : 8;
+#else
+ /* host sw write the sq produce index high 8bit to this section; */
+ u32 pi : 8;
+ u32 resv : 8;
+ u32 xrc_vld : 1;
+ u32 rsvd : 1;
+ u32 mtu_shift : 3;
+ u32 sgid_index : 7;
+ u32 sub_type : 4;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+};
+
+union roce_sq_db {
+ struct roce_sq_db_seg sq_db_seg;
+ union {
+ u64 sq_db_val;
+ struct {
+ u32 sq_db_val_h32;
+ u32 sq_db_val_l32;
+ } dw2;
+ };
+};
+
+/* *SQ DB Format end */
+
+/* * ARM CQ DB Format start */
+struct roce_db_cq_arm {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /* dB type. The value of RoCE ARM CQ DB is 3. */
+ u32 type : 5;
+ /* ARM CQ DB Not required */
+ u32 cos : 3;
+ /* the control plane flag of a DB */
+ u32 cp : 1;
+ u32 non_filter : 1;
+ /* Cq type, 0: RDMA/1:T/IFOE/2.3: Rsv */
+ u32 cqc_type : 2;
+ u32 cqn : 20;
+#else
+ u32 cqn : 20;
+ /* Cq type, 0: RDMA/1:T/IFOE/2.3: Rsv */
+ u32 cqc_type : 2;
+ u32 non_filter : 1;
+ /* the control plane flag of a DB */
+ u32 cp : 1;
+ /* ARM CQ DB Not required */
+ u32 cos : 3;
+ /* dB type. The value of RoCE ARM CQ DB is 3. */
+ u32 type : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * The ArmCQ DB carries the CmdSn, which is compared with the CmdSn in the
+ * chip. If the values are different, the is valid. If the values are the
+ * same, the needs to be checked. -- Each time a CEQE is generated,
+ * the CmdSn of the chip is updated to the CmdSn of the latest ArmCq DB.
+ */
+ u32 cmd_sn : 2;
+ /*
+ * Run the Arm command. 0-non-Arm After receiving the next CQE with the SE,
+ * the 1-ARM SOLICITED generates the CEQE. The * 2-ARM NEXT generates the
+ * CEQE after receiving the next CQE.
+ */
+ u32 cmd : 2;
+ u32 rsv1 : 4;
+ /* Consumer pointer */
+ u32 ci : 24;
+#else
+ /* Consumer pointer */
+ u32 ci : 24;
+ u32 rsv1 : 4;
+ /*
+ * Run the Arm command. 0-non-Arm After receiving the next CQE with the SE,
+ * the 1-ARM SOLICITED generates the CEQE. The * 2-ARM NEXT generates the
+ * CEQE after receiving the next CQE.
+ */
+ u32 cmd : 2;
+ /*
+ * The ArmCQ DB carries the CmdSn, which is compared with the CmdSn in the
+ * chip. If the values are different, the is valid. If the values are the
+ * same, the needs to be checked. -- Each time a CEQE is generated,
+ * the CmdSn of the chip is updated to the CmdSn of the latest ArmCq DB.
+ */
+ u32 cmd_sn : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+};
+/* * ARM CQ DB Format end */
+
+/* * CQE Format start */
+struct roce_cqe {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * Owner bit. During initialization, 0 indicates all hardware,
+ * and 1 indicates all software.
+ * This bit is modified when the hardware writes the CQE.
+ * The meaning of each queue owner bit is reversed.
+ */
+ u32 owner : 1;
+ /* For roce, this field is reserved. */
+ u32 size : 2;
+ /* For roce, this field is reserved. */
+ u32 dif_en : 1;
+ /* For roce, this field is reserved. */
+ u32 wq_id : 4;
+ /* For roce, this field is reserved. */
+ u32 error_code : 4;
+ /*
+ * Local QPN, which is used in all cases.
+ * The driver finds the software QPC based on the QPN.
+ */
+ u32 qpn : 20;
+#else
+ /*
+ * Local QPN, which is used in all cases.
+ * The driver finds the software QPC based on the QPN.
+ */
+ u32 qpn : 20;
+ /* For roce, this field is reserved. */
+ u32 error_code : 4;
+ /* For roce, this field is reserved. */
+ u32 wq_id : 4;
+ /* For roce, this field is reserved. */
+ u32 dif_en : 1;
+ /* For roce, this field is reserved. */
+ u32 size : 2;
+ /*
+ * Owner bit. During initialization, 0 indicates all hardware,
+ * and 1 indicates all software.
+ * This bit is modified when the hardware writes the CQE.
+ * The meaning of each queue owner bit is reversed.
+ */
+ u32 owner : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * The same as what is for SQ WQE. For details,
+ * see the enumeration roce_cqe_opcode
+ */
+ u32 op_type : 5;
+ /* Indicates SQ CQE or RQ CQE. 1-Send Completion; 0-Receive Completion */
+ u32 s_r : 1;
+ /* Indicates whether RQ inline; SQ ignores this bit */
+ u32 inline_r : 1;
+ u32 flush_op : 1;
+ /*
+ * Indicates whether the CQE is a fake one.
+ * When fake, optype & syndronme should be 0
+ */
+ u32 fake : 1;
+ u32 rsvd : 3;
+ /* The WQEBB index and SQ/RQ/SRQ are valid. */
+ u32 wqebb_cnt : 20;
+#else
+ /* The WQEBB index and SQ/RQ/SRQ are valid. */
+ u32 wqebb_cnt : 20;
+ u32 rsvd : 3;
+ /*
+ * Indicates whether the CQE is a fake one.
+ * When fake, optype & syndronme should be 0
+ */
+ u32 fake : 1;
+ u32 flush_op : 1;
+ /* Indicates whether RQ inline; SQ ignores this bit */
+ u32 inline_r : 1;
+ /* Indicates SQ CQE or RQ CQE. 1-Send Completion; 0-Receive Completion */
+ u32 s_r : 1;
+ /*
+ * The same as what is for SQ WQE. For details,
+ * see the enumeration roce_cqe_opcode
+ */
+ u32 op_type : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ /*
+ * Indicates the number of transmitted bytes. This field is valid
+ * for the RDMA read and receive
+ * operations. For the recv of RDMA write imm, the value is 0.
+ */
+ u32 byte_cnt;
+
+ /* DW3 */
+ u32 imm_invalid_rkey; /* The receiving is complete and valid. */
+
+ /* DW4 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 vlan_id : 12;
+ u32 rsvd : 1;
+ u32 vlan_pri : 3;
+ u32 smac_h : 16;
+#else
+ u32 smac_h : 16;
+ u32 vlan_pri : 3;
+ u32 rsvd : 1;
+ u32 vlan_id : 12;
+#endif
+ } bs; /* for ud only */
+ u32 value;
+ } dw4;
+
+ /* DW5 */
+ u32 smac_l;
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * The for ud only:UD receive end is valid.
+ * The 00-packet does not contain a VLAN ID. The
+ * 01-packet contains a VLAN ID.
+ */
+ u32 vlan_pre : 2;
+ /* This field is valid only for UD. Force loopback */
+ u32 fl : 1;
+ u32 stp : 2;
+ u32 rsvd : 3;
+ /*
+ * The XRC at the receive end is valid. When the XRCSRQ at
+ * the receive end is received, the ;UD at the remote end
+ * refers to the QPN at the remote end.
+ */
+ u32 srqn_rqpn : 24;
+#else
+ /*
+ * The XRC at the receive end is valid. When the XRCSRQ at
+ * the receive end is received, the ;UD at the remote end
+ * refers to the QPN at the remote end.
+ */
+ u32 srqn_rqpn : 24;
+ u32 rsvd : 3;
+ u32 stp : 2;
+ /* This field is valid only for UD. Force loopback */
+ u32 fl : 1;
+ /*
+ * The for ud only:UD receive end is valid.
+ * The 00-packet does not contain a VLAN ID. The
+ * 01-packet contains a VLAN ID.
+ */
+ u32 vlan_pre : 2;
+#endif
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 wqe_cnt : 16; /* WQE index, valid SQ */
+ u32 rsvd : 8;
+ /*
+ * 0 indicates that the operation is complete. This parameter
+ * is valid when Op_type is set to ROCE_OPCODE_ERR.
+ * For details about the definition, see the enumeration
+ * roce_cqe_syndrome.
+ */
+ u32 syndrome : 8;
+#else
+ /*
+ * 0 indicates that the operation is complete. This parameter
+ * is valid when Op_type is set to ROCE_OPCODE_ERR.
+ * For details about the definition, see the enumeration
+ * roce_cqe_syndrome.
+ */
+ u32 syndrome : 8;
+ u32 rsvd : 8;
+ u32 wqe_cnt : 16; /* WQE index, valid SQ */
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ u32 timestamp_h;
+ u32 timestamp_l;
+ u32 common_rsvd[6];
+};
+
+struct roce_resize_cqe {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * Owner bit. During initialization, 0 indicates all hardware,
+ * and 1 indicates all software.
+ * This bit is overwritten when the hardware writes the CQE.
+ * The meaning of the queue owner
+ * bit is reversed every time the queue owner is traversed.
+ */
+ u32 owner : 1;
+ u32 rsvd : 31;
+#else
+ u32 rsvd : 31;
+ /*
+ * Owner bit. During initialization, 0 indicates all hardware,
+ * and 1 indicates all software.
+ * This bit is overwritten when the hardware writes the CQE.
+ * The meaning of the queue owner
+ * bit is reversed every time the queue owner is traversed.
+ */
+ u32 owner : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * The operation type is the same as that of SQ WQE.
+ * For details, see the enumeration
+ * roce_cqe_opcode.
+ */
+ u32 op_type : 5;
+ /*
+ * Indicates whether SQ CQE or RQ CQE is used.
+ * 1-Send Completion; 0-Receive Completion
+ */
+ u32 s_r : 1;
+ u32 rsvd : 26;
+#else
+ u32 rsvd : 26;
+ /*
+ * Indicates whether SQ CQE or RQ CQE is used.
+ * 1-Send Completion; 0-Receive Completion
+ */
+ u32 s_r : 1;
+ /*
+ * The operation type is the same as that of SQ WQE.
+ * For details, see the enumeration
+ * roce_cqe_opcode.
+ */
+ u32 op_type : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2~7 */
+ u32 rsvd[6];
+
+ u32 common_rsvd[8];
+};
+
+struct roce_err_cqe {
+ /* DW0 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * Owner bit. During initialization, 0 indicates all hardware,
+ * and 1 indicates all software. This bit is overwritten when
+ * the hardware writes the CQE. The meaning of the queue owner
+ * bit is reversed every time the queue owner is traversed.
+ */
+ u32 owner : 1;
+ u32 rsvd : 11; /* For RoCE, this field is reserved. */
+ /*
+ * Local QPN, which is used in all cases.
+ * The driver finds the software QPC based on the QPN.
+ */
+ u32 qpn : 20;
+#else
+ /*
+ * Local QPN, which is used in all cases.
+ * The driver finds the software QPC based on the QPN.
+ */
+ u32 qpn : 20;
+ u32 rsvd : 11; /* For roce, this field is reserved. */
+ /*
+ * Owner bit. During initialization, 0 indicates all hardware,
+ * and 1 indicates all software.
+ * This bit is overwritten when the hardware writes the CQE.
+ * The meaning of the queue owner
+ * bit is reversed every time the queue owner is traversed.
+ */
+ u32 owner : 1;
+#endif
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * The operation type is the same as that of SQ WQE.
+ * For details, see roce_cqe_opcode.
+ */
+ u32 op_type : 5;
+ /*
+ * Indicates the SQ CQE or RQ CQE. 1-Send Completion;
+ * 0-Receive Completion
+ */
+ u32 s_r : 1;
+ u32 inline_r : 1;
+ u32 flush_op : 1;
+ u32 fake : 1;
+ u32 rsvd : 3;
+ u32 wqebb_cnt : 20; /* The WQEBB index and SQ/RQ/SRQ are valid. */
+#else
+ u32 wqebb_cnt : 20; /* The WQEBB index and SQ/RQ/SRQ are valid. */
+ u32 rsvd : 3;
+ u32 fake : 1;
+ /*
+ * Indicates whether this CQE is a fake cqe or not.when fake = 1,
+ * optype & syndronme should be 0
+ */
+ u32 flush_op : 1;
+ u32 inline_r : 1;
+ /*
+ * Indicates the SQ CQE or RQ CQE. 1-Send Completion;
+ * 0-Receive Completion
+ */
+ u32 s_r : 1;
+ /*
+ * The operation type is the same as that of SQ WQE.
+ * For details, see roce_cqe_opcode.
+ */
+ u32 op_type : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2~5 */
+ u32 rsvd[3];
+
+ u32 wqe_num;
+
+ /* DW6 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 rsvd : 8;
+ /* The XRC at the receive end is valid, which is XRCSRQ. */
+ u32 srqn : 24;
+#else
+ /* The XRC at the receive end is valid, which is the XRCSRQ number. */
+ u32 srqn : 24;
+ u32 rsvd : 8;
+#endif
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ u32 wqe_cnt : 16; /* WQE index: Indicates that the SQ is valid. */
+ u32 vendor_err : 8;
+ /*
+ * 0 indicates that the operation is successful. The value is
+ * valid when Op_type is ROCE_OPCODE_ERR. For details, see the
+ * enumeration roce_cqe_syndrome.
+ */
+ u32 syndrome : 8;
+#else
+ /*
+ * 0 indicates that the operation is complete. This parameter
+ * is valid when Op_type is set to ROCE_OPCODE_ERR. For details
+ * about the definition, see the enumeration
+ * roce_cqe_syndrome.
+ */
+ u32 syndrome : 8;
+ u32 vendor_err : 8;
+ u32 wqe_cnt : 16; /* WQE index, valid SQ */
+#endif
+ } bs;
+ u32 value;
+ } dw7;
+
+ u32 timestamp_h;
+ u32 timestamp_l;
+ u32 common_rsvd[6];
+};
+
+
+struct roce_vbs_cqe {
+ /* DW0 */
+ union {
+ struct {
+ u32 owner : 1;
+ u32 size : 2;
+ u32 dif_en : 1;
+ u32 wq_id : 4;
+ u32 error_code : 4;
+ u32 qpn : 20;
+ } bs;
+ u32 value;
+ } dw0;
+
+ /* DW1 */
+ union {
+ struct {
+ /*
+ * The operation type is the same as that of SQ WQE.
+ * For details, see the enumeration roce_cqe_opcode.
+ */
+ u32 op_type : 5;
+ /*
+ * Indicates whether SQ CQE or RQ CQE is used.
+ * 1-Send Completion; 0-Receive Completion
+ */
+ u32 s_r : 1;
+ u32 inline_r : 1; /* Indicates whether the RQ inline;SQ ignores this bit. */
+ u32 rsvd : 5;
+ u32 msg_fst_wqe_ci : 20;
+ } bs;
+ u32 value;
+ } dw1;
+
+ /* DW2 */
+ /*
+ * Indicates the number of transmitted bytes. This field is valid
+ * for the RDMA read and receive
+ * operations. For the recv of RDMA write imm, the value is 0.
+ */
+ u32 byte_cnt;
+
+ /* DW3 */
+ u32 imm_invalid_rkey; /* The receiving is complete and valid. */
+
+ /* DW4 */
+ u32 rsvd;
+
+ /* DW5 */
+ u32 wqe_num;
+
+ /* DW6 */
+ union {
+ struct {
+ /*
+ * The for ud only:UD receive end is valid. The 00-packet does
+ * not contain a VLAN ID. The
+ * 01-packet contains a VLAN ID.
+ */
+ u32 vlan_pre : 2;
+ u32 fl : 1; /* This field is valid only for UD. Force loopback */
+ u32 stp : 2;
+ u32 rsvd : 3;
+ /*
+ * The XRC at the receive end is valid. When the XRCSRQ at
+ * the receive end is received,
+ * the ;UD at the remote end refers to the QPN at the remote end.
+ */
+ u32 srqn_rqpn : 24;
+ } bs;
+ u32 value;
+ } dw6;
+
+ /* DW7 */
+ union {
+ struct {
+ u32 wqe_cnt : 16; /* WQE index, valid SQ */
+ u32 vendor_err : 8;
+ /*
+ * 0 indicates that the operation is complete. This parameter is
+ * valid when Op_type is set to ROCE_OPCODE_ERR.
+ * For details about the definition, see the enumeration
+ * roce_cqe_syndrome.
+ */
+ u32 syndrome : 8;
+ } bs;
+ u32 value;
+ } dw7;
+
+ u16 srq_container_idx[16];
+};
+
+struct roce_nofaa_cqe {
+ /* DW0 */
+ u32 common_dw0;
+
+ /* DW1 */
+ union {
+ struct {
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && ((BYTE_ORDER == BIG_ENDIAN))
+ /*
+ * The operation type is the same as that of SQ WQE.
+ * For details, see the enumeration
+ * roce_cqe_opcode.
+ */
+ u32 op_type : 5;
+ /*
+ * Indicates whether SQ CQE or RQ CQE is used.
+ * 1-Send Completion; 0-Receive Completion
+ */
+ u32 s_r : 1;
+ /* Indicates whether the RQ inline;SQ ignores this bit. */
+ u32 inline_r : 1;
+ u32 flush_op : 1;
+ u32 fake : 1;
+ u32 repeat : 1;
+ u32 host_id : 2;
+ /* The WQEBB index and SQ/RQ/SRQ are valid. */
+ u32 wqebb_cnt : 20;
+#else
+ /* The WQEBB index and SQ/RQ/SRQ are valid. */
+ u32 wqebb_cnt : 20;
+ u32 host_id : 2;
+ u32 repeat : 1;
+ /*
+ * Indicates whether this CQE is a fake cqe or not.
+ * when fake = 1, optype & syndronme should be 0
+ */
+ u32 fake : 1;
+ u32 flush_op : 1;
+ /* Indicates whether RQ inline;SQ ignores this bit. */
+ u32 inline_r : 1;
+ /*
+ * Indicates the SQ CQE or RQ CQE. 1-Send Completion;
+ * 0-Receive Completion
+ */
+ u32 s_r : 1;
+ /*
+ * The operation type is the same as that of SQ WQE.
+ * For details, see the enumeration roce_cqe_opcode.
+ */
+ u32 op_type : 5;
+#endif
+ } bs;
+ u32 value;
+ } dw1;
+
+ u32 common_rsvd[13];
+
+ union {
+ struct {
+ u32 rsvd : 4;
+ u32 sw_times : 2;
+ u32 sw_slave_id : 6;
+ u32 io_time : 20;
+ } bs;
+ u32 value;
+ } io_status;
+};
+
+#endif // RDMA_XQE_FORMAT_H
diff --git a/drivers/infiniband/hw/hiroce3/include/roce_cdev_extension.h b/drivers/infiniband/hw/hiroce3/include/roce_cdev_extension.h
new file mode 100644
index 0000000000000..4e5e323696fda
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/roce_cdev_extension.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_CDEV_EXTENSION_H
+#define ROCE_CDEV_EXTENSION_H
+
+#include "roce.h"
+
+#define NOT_SUPOORT_TYPE 0xFFFFFFFF
+
+long ioctl_non_bonding_extend(unsigned int cmd, struct roce3_device *rdev, unsigned long arg);
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/include/roce_event_extension.h b/drivers/infiniband/hw/hiroce3/include/roce_event_extension.h
new file mode 100644
index 0000000000000..a6ea2a79c055a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/roce_event_extension.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_EVENT_EXTENSION_H
+#define ROCE_EVENT_EXTENSION_H
+
+#include "roce_event.h"
+
+void roce3_event_report_extend(const struct roce3_device *rdev, int event_str_index);
+
+int roce3_async_event_handle_extend(u8 event_type, u8 *val, struct roce3_device *rdev);
+
+#endif /* ROCE_EVENT_EXTENSION_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/roce_main_extension.h b/drivers/infiniband/hw/hiroce3/include/roce_main_extension.h
new file mode 100644
index 0000000000000..d55983ca18cc3
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/roce_main_extension.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_MAIN_EXTENSION_H
+#define ROCE_MAIN_EXTENSION_H
+
+#include <linux/pci.h>
+
+#include "hinic3_hw.h"
+#include "hinic3_crm.h"
+#include "hinic3_lld.h"
+#include "hinic3_mbox.h"
+#include "hinic3_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 "rdma_comp.h"
+#include "hmm_mr.h"
+#include "roce_qp_post_send_extension.h"
+
+#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
+
+struct hinic3_uld_info *roce3_info_get(void);
+
+void roce3_service_init_pre(void);
+
+void roce3_service_init_ext(void);
+
+void roce3_lock_rdev(void);
+
+void roce3_unlock_rdev(void);
+
+int roce3_get_rdev_by_uld(struct hinic3_lld_dev *lld_dev, void *uld_dev, struct roce3_device **rdev,
+ struct hinic3_event_info *event);
+
+void roce3_init_dev_ext_handlers(struct roce3_device *rdev);
+
+int roce3_board_cfg_check(struct roce3_device *rdev);
+
+int roce3_init_dev_ext(struct roce3_device *rdev);
+
+void roce3_remove_clean_res_ext(struct roce3_device *rdev);
+
+int roce3_set_comm_event(const struct roce3_device *rdev, const struct hinic3_event_info *event);
+
+bool roce3_hca_is_present(const struct roce3_device *rdev);
+
+int roce3_mmap_ext(struct roce3_device *rdev, struct roce3_ucontext *ucontext,
+ struct vm_area_struct *vma);
+
+int roce3_dfx_mem_alloc(struct roce3_device *rdev);
+
+void roce3_dfx_mem_free(struct roce3_device *rdev);
+
+int ib_copy_to_udata_ext(struct ib_udata *udata, struct roce3_alloc_ucontext_resp *resp);
+
+void *roce3_ucontext_alloc_ext(void);
+
+void roce3_resp_set_ext(struct roce3_device *rdev, struct roce3_alloc_ucontext_resp *resp);
+
+void *roce3_resp_alloc_ext(void);
+
+void roce3_ucontext_set_ext(struct roce3_device *rdev, struct roce3_ucontext *context);
+
+void *roce3_rdev_alloc_ext(void);
+
+void roce3_rdev_set_ext(struct roce3_device *rdev);
+
+void roce3_rdma_cap_ext(struct rdma_service_cap *rdma_cap);
+
+#endif /* ROCE_MAIN_EXTENSION_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/roce_mr_extension.h b/drivers/infiniband/hw/hiroce3/include/roce_mr_extension.h
new file mode 100644
index 0000000000000..114b03f2dad05
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/roce_mr_extension.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_MR_EXTEND_H
+#define ROCE_MR_EXTEND_H
+
+#include <rdma/ib_verbs.h>
+
+#include "hinic3_rdma.h"
+
+#include "roce.h"
+
+int roce3_check_alloc_mr_type(enum ib_mr_type mr_type);
+enum rdma_mr_type roce3_get_mrtype(enum ib_mr_type ib_mr_type);
+
+#endif
+
diff --git a/drivers/infiniband/hw/hiroce3/include/roce_netdev_extension.h b/drivers/infiniband/hw/hiroce3/include/roce_netdev_extension.h
new file mode 100644
index 0000000000000..d97d1b0d5a897
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/roce_netdev_extension.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_NETDEV_EXTENSION_H
+#define ROCE_NETDEV_EXTENSION_H
+
+#include "roce_netdev.h"
+
+int roce3_add_real_device_mac(struct roce3_device *rdev, struct net_device *netdev);
+
+int roce3_add_vlan_device_mac(struct roce3_device *rdev, struct net_device *netdev);
+
+void roce3_del_real_device_mac(struct roce3_device *rdev);
+
+void roce3_del_vlan_device_mac(struct roce3_device *rdev, struct roce3_vlan_dev_list *old_list);
+
+void roce3_event_up_extend(struct roce3_device *rdev);
+
+#endif /* ROCE_NETDEV_EXTENSION_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/roce_qp_extension.h b/drivers/infiniband/hw/hiroce3/include/roce_qp_extension.h
new file mode 100644
index 0000000000000..9667039c32e47
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/roce_qp_extension.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#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_roce3_qp_type(enum ib_qp_type qp_type);
+
+bool roce3_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 roce3_create_qp_pre_ext(struct roce3_device *rdev, struct roce3_qp *rqp,
+ struct ib_qp_init_attr *init_attr);
+
+int roce3_create_qp_user_pre_ext(struct ib_qp_init_attr *init_attr, struct roce3_qp *rqp, u32 *qpn);
+
+int roce3_create_qp_user_post_ext(struct ib_pd *ibpd, struct roce3_device *rdev,
+ struct roce3_qp *rqp, struct ib_qp_init_attr *init_attr);
+
+int roce3_qp_modify_cmd_ext(struct tag_cqm_cmd_buf *cqm_cmd_inbuf, struct roce3_qp *rqp,
+ struct tag_roce_verbs_qp_attr *qp_attr, u32 optpar);
+
+bool roce3_need_qpn_lb1_consistent_srqn(const struct roce3_qp *rqp, const struct roce3_device *rdev,
+ const struct ib_qp_init_attr *init_attr);
+
+int roce3_is_qp_normal(struct roce3_qp *rqp, struct ib_qp_init_attr *init_attr);
+
+void roce3_set_qp_dif_attr(struct roce3_qp *rqp, const struct ib_qp_init_attr *init_attr,
+ const struct roce3_device *rdev);
+
+int roce3_qp_modify_pre_extend(struct roce3_qp *rqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata);
+
+#ifdef ROCE_EXTEND
+
+#define QPC_ROCE_VBS_QPC_OFFSET_FOR_SQPC 204800 // 200K
+
+#define ROCE_QP_VBS_FLAG (1U << 22)
+
+struct roce3_set_qp_ext_attr_cmd {
+ u32 qpn;
+ u32 attr_mask;
+};
+
+struct roce3_modify_qp_vbs_cmd {
+ u32 qpn;
+ u64 ci_record_addr;
+};
+
+struct roce3_vbs_qp {
+ struct tag_cqm_cmd_buf *vbs_sqpc_info; /* vbs private data */
+ struct roce3_db db; /* to record ci_record_pa */
+};
+
+long roce3_set_qp_ext_attr(struct roce3_device *rdev, void *buf);
+long roce3_vbs_create_sqpc(struct roce3_device *rdev, void *buf);
+#endif
+
+#endif /* ROCE_QP_EXTENSION_H */
diff --git a/drivers/infiniband/hw/hiroce3/include/roce_qp_post_send_extension.h b/drivers/infiniband/hw/hiroce3/include/roce_qp_post_send_extension.h
new file mode 100644
index 0000000000000..966c94a6a4f2b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/roce_qp_post_send_extension.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_QP_POST_SEND_EXTEND_H
+#define ROCE_QP_POST_SEND_EXTEND_H
+
+#include <rdma/ib_verbs.h>
+#include "roce_qp.h"
+
+int roce3_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
+const struct ib_send_wr **bad_wr);
+
+#endif // ROCE_QP_POST_SEND_EXTEND_H
diff --git a/drivers/infiniband/hw/hiroce3/include/roce_srq_extension.h b/drivers/infiniband/hw/hiroce3/include/roce_srq_extension.h
new file mode 100644
index 0000000000000..bf2d73cca6600
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/include/roce_srq_extension.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_SRQ_EXTENSION_H
+#define ROCE_SRQ_EXTENSION_H
+
+#include "roce_srq.h"
+
+void roce3_srq_container_init(struct ib_srq_init_attr *init_attr,
+struct roce3_srq *rsrq, struct roce3_device *rdev);
+
+void roce3_create_user_srq_update_ext(u32 *cqn, u32 srqn);
+
+#endif /* ROCE_SRQ_EXTENSION_H */
diff --git a/drivers/infiniband/hw/hiroce3/mr/roce_mr.c b/drivers/infiniband/hw/hiroce3/mr/roce_mr.c
new file mode 100644
index 0000000000000..62ee3ac9eb9f8
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/mr/roce_mr.c
@@ -0,0 +1,949 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_mr.h"
+#include "roce_mr_extension.h"
+#include "roce_main_extension.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;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_alloc_tpt
+ Description : alloc mpt and mtt
+ Input : struct roce3_device *rdev
+ struct rdma_mr *mr
+ u32 npages
+ u32 page_shift
+ Output : None
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_alloc_tpt(struct roce3_device *rdev, struct rdma_mr *mr, u32 npages, u32 page_shift)
+{
+ int ret = 0;
+
+ ret = hmm_rdma_mpt_alloc(rdev->hwdev, &mr->mpt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc mpt, ret(%d), func_id(%d)\n",
+ __func__, 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_rdma_mtt_alloc(rdev->hwdev, npages, page_shift, &mr->mtt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc mtt, ret(%d), func_id(%d)\n",
+ __func__, ret, rdev->glb_func_id);
+ goto err_alloc_mtt;
+ }
+
+ return 0;
+
+err_alloc_mtt:
+ hmm_rdma_mpt_free(rdev->hwdev, &mr->mpt);
+ mr->enabled = RDMA_MPT_DISABLED;
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_free_tpt
+ Description : free mpt and mtt
+ Input : struct roce3_device *rdev
+ struct rdma_mr *mr
+ Output : None
+
+ 1.Date : 2015/5/8
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_free_tpt(struct roce3_device *rdev, struct rdma_mr *mr)
+{
+ hmm_rdma_mtt_free(rdev->hwdev, &mr->mtt, SERVICE_T_ROCE);
+
+ hmm_rdma_mpt_free(rdev->hwdev, &mr->mpt);
+
+ mr->enabled = RDMA_MPT_DISABLED;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_rdma_mr
+ Description : set the member of rdma_mr
+ Input : struct rdma_mr *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 roce3_set_rdma_mr(struct rdma_mr *mr, enum rdma_mr_type mr_type, u32 pdn,
+ u64 iova, u64 size, u32 access)
+{
+ mr->iova = iova;
+ mr->size = size;
+ mr->pdn = pdn;
+ /* Convert ib permissions to rdma component permissions */
+ mr->access = convert_ib_access((int)access);
+ /* Convert from mpt index to key */
+ mr->key = get_key_from_index(mr->mpt.mpt_index);
+ mr->mr_type = mr_type;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_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);
+
+ if (type == IB_MW_TYPE_1)
+ mw->type = RDMA_MW_TYPE_1;
+ else
+ mw->type = RDMA_MW_TYPE_2;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 *roce3_get_dma_mr(struct ib_pd *ibpd, int access)
+{
+ int ret = 0;
+ struct roce3_mr *mr = NULL;
+ struct roce3_pd *pd = NULL;
+ struct roce3_device *rdev = NULL;
+
+ if ((ibpd == NULL) || (check_ib_access(access) != 0)) {
+ ret = -EINVAL;
+ pr_err("[ROCE, ERR] %s: Invalid Param.p1:%d\n", __func__, access);
+ goto err_out;
+ }
+
+ pd = to_roce3_pd(ibpd);
+ rdev = to_roce3_dev(ibpd->device);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ ret = -EPERM;
+ goto err_out;
+ }
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (mr == NULL) {
+ ret = -ENOMEM;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc memory for dma mr, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_out;
+ }
+
+ mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE;
+ ret = roce3_alloc_tpt(rdev, &mr->rdmamr, 0, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc mpt and mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_alloc_tpt;
+ }
+
+ /* Set the content in rdma_mr */
+ roce3_set_rdma_mr(&mr->rdmamr, RDMA_DMA_MR, pd->pdn, 0ULL, ROCE_DMA_MR_SIZE, (u32)access);
+
+ ret = hmm_rdma_enable_mr_mpt(rdev->hwdev, &(mr->rdmamr), HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to enable mpt of DMA mr, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_enable_mpt;
+ }
+
+ mr->ibmr.lkey = mr->rdmamr.key;
+ mr->ibmr.rkey = mr->rdmamr.key;
+
+ return &mr->ibmr;
+
+err_enable_mpt:
+ roce3_free_tpt(rdev, &mr->rdmamr);
+
+err_alloc_tpt:
+ kfree(mr);
+
+err_out:
+ return (struct ib_mr *)ERR_PTR((long)ret);
+}
+
+static int roce3_alloc_priv_pages(struct ib_device *ibdev, struct roce3_mr *rmr, u32 max_pages)
+{
+ int ret;
+
+#ifndef __PC_LINT__
+ rmr->page_map_size = roundup(max_pages * sizeof(u64), ROCE3_MR_PAGES_ALIGN);
+#endif
+ rmr->pages = (__be64 *)(void *)(uintptr_t)get_zeroed_page(GFP_KERNEL);
+ if (rmr->pages == NULL) {
+ pr_err("[ROCE] %s: Failed to alloc rmr->pages\n", __func__);
+ 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) {
+ pr_err("[ROCE] %s: Failed to do dma mapping\n", __func__);
+ ret = -ENOMEM;
+ goto err_free_pages;
+ }
+
+ return 0;
+
+err_free_pages:
+ free_page((unsigned long)(uintptr_t)(void *)rmr->pages);
+
+err_out:
+ return ret;
+}
+
+static void roce3_free_priv_pages(struct roce3_mr *rmr)
+{
+ struct ib_device *ib_dev = rmr->ibmr.device;
+
+ if (rmr->pages) {
+ 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 roce3_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;
+ pr_err("[ROCE, ERR] %s: Ibpd is null\n", __func__);
+ goto err_out;
+ }
+
+ /*lint -e746*/
+ ret = roce3_check_alloc_mr_type(mr_type);
+ /*lint +e746*/
+ if (ret != 0) {
+ ret = -EINVAL;
+ pr_err("[ROCE, ERR] %s: mr_type is invalid\n", __func__);
+ goto err_out;
+ }
+
+ if (max_num_sg >= ROCE_FRMR_MAX_PAGES) {
+ pr_err("[ROCE] %s: Invalid max_num_sg(%d)\n", __func__, max_num_sg);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ return ret;
+}
+
+static int roce3_alloc_mr_param_check(struct roce3_device *rdev,
+ struct roce3_mr **mr, u32 max_num_sg)
+{
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ *mr = kzalloc(sizeof(struct roce3_mr), GFP_KERNEL);
+ if ((*mr) == NULL) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc mr memory, func(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -ENOMEM;
+ }
+
+ (*mr)->max_pages = max_num_sg;
+ return 0;
+}
+/*
+ ****************************************************************************
+ Prototype : roce3_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 *roce3_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type, u32 max_num_sg)
+{
+ int ret = 0;
+ struct roce3_mr *mr = NULL;
+ struct roce3_pd *pd = NULL;
+ struct roce3_device *rdev = NULL;
+
+ ret = roce3_alloc_mr_param_validate(ibpd, mr_type, max_num_sg);
+ if (ret != 0)
+ goto err_out;
+
+ pd = to_roce3_pd(ibpd);
+ rdev = to_roce3_dev(ibpd->device);
+
+ ret = roce3_alloc_mr_param_check(rdev, &mr, max_num_sg);
+ if (ret != 0)
+ goto err_out;
+
+ mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE;
+ ret = roce3_alloc_tpt(rdev, &mr->rdmamr, max_num_sg, 0); // alloc mptc and mtt
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc tpt, func(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_alloc_tpt;
+ }
+
+ ret = roce3_alloc_priv_pages(ibpd->device, mr, max_num_sg); // alloc memory to store pa
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: Failed to alloc memory, func(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_alloc_priv_pages;
+ }
+
+ /*lint -e746*/
+ roce3_set_rdma_mr(&mr->rdmamr, RDMA_FRMR, pd->pdn, 0ULL, 0, 0);
+ /*lint +e746*/
+ /* send to chip by cmdq */
+ ret = hmm_rdma_enable_mr_mpt(rdev->hwdev, &(mr->rdmamr), HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to enable mpt, func(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_enale_mpt;
+ }
+
+ mr->ibmr.lkey = mr->rdmamr.key;
+ mr->ibmr.rkey = mr->rdmamr.key;
+
+ return &mr->ibmr;
+
+err_enale_mpt:
+ roce3_free_priv_pages(mr);
+
+err_alloc_priv_pages:
+ roce3_free_tpt(rdev, &mr->rdmamr);
+
+err_alloc_tpt:
+ kfree(mr);
+
+err_out:
+ return (struct ib_mr *)ERR_PTR((long)ret);
+}
+
+static int roce3_set_page(struct ib_mr *ibmr, u64 addr)
+{
+ struct roce3_mr *rmr = NULL;
+
+ if (ibmr == NULL) {
+ pr_err("[ROCE] %s: Ibmr is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rmr = to_roce3_mr(ibmr);
+ if (ROCE_UNLIKELY(rmr->npages >= rmr->max_pages)) {
+ pr_err("[ROCE] %s: Invalid npages(0x%x), can't set page\n", __func__, rmr->npages);
+ return -ENOMEM;
+ }
+
+ rmr->pages[rmr->npages] = cpu_to_be64(addr | 0x1);
+ rmr->npages++;
+
+ return 0;
+}
+
+int roce3_map_kernel_frmr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
+ int sg_nents, unsigned int *sg_offset)
+{
+ int ret;
+ struct roce3_mr *rmr = NULL;
+
+ /* sg_offset can be null */
+ if ((ibmr == NULL) || (sg == NULL)) {
+ pr_err("[ROCE] %s: Ibmr or sg is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rmr = to_roce3_mr(ibmr);
+ rmr->npages = 0;
+
+ if (ROCE_UNLIKELY(((u32)sg_nents) >= rmr->max_pages)) {
+ pr_err("[ROCE] %s: Invalid sg_nents(0x%x), ,max(0x%x)\n",
+ __func__, 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, roce3_set_page);
+
+ ib_dma_sync_single_for_device(ibmr->device, rmr->page_map,
+ rmr->page_map_size, DMA_TO_DEVICE);
+
+ return ret;
+}
+
+static int roce3_umem_write_mtt_check(const struct roce3_device *rdev, const struct rdma_mtt *mtt,
+ const struct ib_umem *umem)
+{
+ if ((rdev == NULL) || (mtt == NULL) || (umem == NULL)) {
+ pr_err("[ROCE, ERR] %s: Rdev or mtt or umem is null\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce3_umem_write_mtt_update(struct roce3_device *rdev,
+ struct rdma_mtt *mtt, struct ib_umem *umem, u64 *page_list)
+{
+ int ret = 0;
+ int i = 0;
+ u32 j = 0;
+ u32 pages_in_chunk = 0; /* The number of pages of a single memory block in umem_chunk */
+ u32 npages = 0; /* The number of recorded pages */
+ u32 start_index = 0; /* page need to be written to mtt */
+ struct scatterlist *sg = NULL;
+ u64 page_size = BIT(mtt->buf_page_shift);
+ u64 page_mask = ~(page_size - 1);
+ u64 dma_addr;
+
+ for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i) {
+ /*
+ * Calculate the number of pages in a memory block,
+ * the page size is 1 << page_shift
+ */
+ dma_addr = sg_dma_address(sg) & page_mask;
+ pages_in_chunk = DIV_ROUND_UP(sg_dma_len(sg), page_size);
+ for (j = 0; j < pages_in_chunk; ++j) {
+ page_list[npages] = dma_addr + (page_size * j);
+ npages++;
+ /*
+ * 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, else continue
+ */
+ if (npages != PAGE_SIZE / sizeof(u64))
+ continue;
+
+ ret = hmm_rdma_write_mtt(rdev->hwdev, mtt, start_index,
+ npages, page_list, SERVICE_T_ROCE);
+ if (ret) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to write mtt, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ start_index += npages;
+ npages = 0;
+ }
+ }
+
+ if (npages != 0) {
+ ret = hmm_rdma_write_mtt(rdev->hwdev, mtt, start_index, npages,
+ page_list, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to write mtt, ret(%d), start_index(%u), func_id(%u)\n",
+ __func__, ret, start_index, rdev->glb_func_id);
+ }
+ }
+
+ return ret;
+}
+
+int roce3_umem_write_mtt(struct roce3_device *rdev, struct rdma_mtt *mtt, struct ib_umem *umem)
+{
+ int ret = 0;
+ u64 *page_list = NULL; /* page_list to write to mtt */
+
+ ret = roce3_umem_write_mtt_check(rdev, mtt, umem);
+ if (ret != 0)
+ return ret;
+
+ page_list = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (page_list == NULL)
+ return -ENOMEM;
+
+ ret = roce3_umem_write_mtt_update(rdev, mtt, umem, page_list);
+ kfree(page_list);
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_buf_write_mtt
+ Description : roce3_buf_write_mtt
+ Input : struct roce3_device *rdev
+ struct rdma_mtt *mtt
+ struct tag_cqm_buf *buf
+ Output : None
+
+ 1.Date : 2015/4/24
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_buf_write_mtt(struct roce3_device *rdev, struct rdma_mtt *mtt, struct tag_cqm_buf *buf)
+{
+ u64 *page_list = NULL;
+ int ret = 0;
+ u32 i = 0;
+
+ if ((rdev == NULL) || (mtt == NULL) || (buf == NULL)) {
+ pr_err("[ROCE, ERR] %s: Rdev or mtt or buf is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ page_list = kzalloc(buf->buf_number * sizeof(*page_list), GFP_KERNEL);
+ if (page_list == NULL)
+ 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_rdma_write_mtt(rdev->hwdev, mtt, 0, buf->buf_number, page_list, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to write mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ }
+
+ kfree(page_list);
+
+ return ret;
+}
+
+int roce3_user_mr_reg(struct roce3_device *rdev, struct roce3_mr *mr, u32 pdn, u64 virt_addr,
+ u64 length, int access)
+{
+ int ret = 0;
+ u32 npages = 0;
+ u32 page_shift = PAGE_SHIFT;
+ struct hinic3_hwdev *hwdev = (struct hinic3_hwdev *)rdev->hwdev;
+
+ if (hwdev == NULL) {
+ pr_err("[HMM, ERR] %s(%d): hwdev is null\n", __func__, __LINE__);
+ return 0;
+ }
+
+ mr->rdmamr.mtt.mtt_type = MTT_DMTT_TYPE;
+ npages = (u32)ib_umem_num_pages(mr->umem);
+#ifdef CONFIG_CENTRALIZED_STORAGE
+ if (mr->umem->is_umm_mem) {
+ page_shift = PAGE_SHIFT_2M;
+ npages = ib_umem_num_dma_blocks(mr->umem, BIT(page_shift));
+ }
+#endif
+ ret = roce3_alloc_tpt(rdev, &mr->rdmamr, npages, page_shift);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[ROCE, ERR] %s(%d): Failed to alloc mpt and mtt, func_id(%u)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto err_alloc_tpt;
+ }
+
+ roce3_set_rdma_mr(&mr->rdmamr, RDMA_USER_MR, pdn, virt_addr, length, (u32)access);
+
+ ret = roce3_umem_write_mtt(rdev, &mr->rdmamr.mtt, mr->umem);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[ROCE, ERR] %s(%d): Failed to write mtt, func_id(%u)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto err_write_mtt;
+ }
+
+ ret = hmm_rdma_enable_mr_mpt(hwdev, &mr->rdmamr, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(hwdev->dev_hdl,
+ "[ROCE, ERR] %s(%d): Failed to enable mpt of user mr, func_id(%u)\n",
+ __func__, __LINE__, hinic3_global_func_id(hwdev));
+ goto err_write_mtt;
+ }
+
+ return 0;
+
+err_write_mtt:
+ roce3_free_tpt(rdev, &mr->rdmamr);
+
+err_alloc_tpt:
+ return ret;
+}
+
+static int roce3_check_mr_param(struct ib_pd *ibpd)
+{
+ struct roce3_device *rdev = NULL;
+
+ if (ibpd == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibpd is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibpd->device);
+ if (roce3_hca_is_present(rdev) == 0) {
+ pr_err("[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 *roce3_reg_user_mr(struct ib_pd *ibpd, u64 start,
+ u64 length, u64 virt_addr, int access, struct ib_udata *udata)
+{
+ int ret;
+ struct roce3_mr *mr = NULL;
+ struct roce3_device *rdev = NULL;
+ struct roce3_pd *pd;
+
+ ret = roce3_check_mr_param(ibpd);
+ if (ret != 0)
+ goto err_out;
+
+ pd = to_roce3_pd(ibpd);
+ rdev = to_roce3_dev(ibpd->device);
+
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
+ if (mr == NULL) {
+ ret = -ENOMEM;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc memory for roce mr, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_out;
+ }
+
+ mr->umem = ib_umem_get(&rdev->ib_dev, start, (size_t)length, access);
+ if (IS_ERR(mr->umem)) {
+ ret = (int)PTR_ERR(mr->umem);
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to get ib umem, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_get_umem;
+ }
+
+ ret = roce3_user_mr_reg(rdev, mr, pd->pdn, virt_addr, length, access);
+ if (ret != 0)
+ goto err_mr_update;
+
+ mr->ibmr.lkey = mr->rdmamr.key;
+ mr->ibmr.rkey = mr->rdmamr.key;
+
+ 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 roce3_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce3_mr *mr = NULL;
+ struct roce3_device *rdev = NULL;
+
+ if (ibmr == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibmr is null\n", __func__);
+ return -EINVAL;
+ }
+
+ mr = to_roce3_mr(ibmr);
+ rdev = to_roce3_dev(ibmr->device);
+
+ roce3_free_priv_pages(mr);
+
+ ret = hmm_rdma_disable_mr_mpt(rdev->hwdev, &mr->rdmamr, SERVICE_T_ROCE,
+ HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to disable mpt of mr, ret(%d), func_id(%d)\n",
+ __func__, ret, rdev->glb_func_id);
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Mr may has mw bind on it, mr_key(%#x), func_id(%d)\n",
+ __func__, mr->rdmamr.key, rdev->glb_func_id);
+ if (ret == (-RDMA_CMDQ_TIMEOUT))
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+
+ return ret;
+ }
+
+ roce3_free_tpt(rdev, &mr->rdmamr);
+
+ if (mr->umem)
+ ib_umem_release(mr->umem);
+
+ return 0;
+}
+
+static void roce3_err_enable_mpt_handler(void *hwdev, struct roce3_mw *mw)
+{
+ hmm_rdma_mpt_free(hwdev, &mw->rdmamw.mpt);
+ mw->rdmamw.enabled = RDMA_MPT_DISABLED;
+}
+
+int roce3_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
+{
+ int ret;
+ struct roce3_mw *mw = to_roce3_mw(ibmw);
+ struct roce3_pd *pd = to_roce3_pd(ibmw->pd);
+ struct roce3_device *rdev = to_roce3_dev(ibmw->device);
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ ret = hmm_rdma_mpt_alloc(rdev->hwdev, &mw->rdmamw.mpt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc mpt, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err;
+ }
+
+ roce3_set_rdma_mw(&mw->rdmamw, pd->pdn, ibmw->type);
+ ret = roce3_rdma_enable_mw_mpt(rdev->hwdev, &mw->rdmamw, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to enable mpt of mw, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ if (ret == (-RDMA_CMDQ_TIMEOUT))
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+
+ goto err_enable_mpt;
+ }
+
+ mw->ibmw.rkey = mw->rdmamw.key;
+ return 0;
+err_enable_mpt:
+ roce3_err_enable_mpt_handler(rdev->hwdev, mw);
+err:
+ return ret;
+}
+
+int roce3_dealloc_mw(struct ib_mw *ibmw)
+{
+ int ret = 0;
+ struct roce3_mw *mw = NULL;
+ struct roce3_device *rdev = NULL;
+
+ if (ibmw == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibmw is null\n", __func__);
+ return -EINVAL;
+ }
+
+ mw = to_roce3_mw(ibmw);
+ rdev = to_roce3_dev(ibmw->device);
+ ret = roce3_rdma_disable_mw_mpt(rdev->hwdev, &mw->rdmamw, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to disable mpt of mw, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ if (ret == (-RDMA_CMDQ_TIMEOUT))
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+
+ return ret;
+ }
+
+ hmm_rdma_mpt_free(rdev->hwdev, &mw->rdmamw.mpt);
+
+ mw->rdmamw.enabled = RDMA_MPT_DISABLED;
+
+ return 0;
+}
+
+int roce3_check_mr_status(struct ib_mr *ibmr, u32 check_mask, struct ib_mr_status *mr_status)
+{
+ int ret = 0;
+ struct roce3_mr *mr = NULL;
+
+ if ((ibmr == NULL) || (mr_status == NULL)) {
+ pr_err("[ROCE, ERR] ibmr or mr_status is NULL ptr.\n");
+ return -EINVAL;
+ }
+
+ mr = to_roce3_mr(ibmr);
+ if ((check_mask & (~IB_MR_CHECK_SIG_STATUS)) != 0) {
+ pr_err("[ROCE, ERR] check_mask(%#x) invalid\n", check_mask);
+ return -EINVAL;
+ }
+
+ if (!mr->signature_en) {
+ pr_err("[ROCE, ERR] mr not configure dif info\n");
+ 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;
+
+ memcpy((void *)&mr_status->sig_err, (void *)&mr->sig.sig_err_item,
+ sizeof(struct ib_sig_err));
+ mr->sig.sig_err_exists = false;
+ mr_status->fail_status |= IB_MR_CHECK_SIG_STATUS;
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/mr/roce_mr.h b/drivers/infiniband/hw/hiroce3/mr/roce_mr.h
new file mode 100644
index 0000000000000..8f894b22cc169
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/mr/roce_mr.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#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 "hinic3_rdma.h"
+
+#include "roce.h"
+#include "roce_compat.h"
+#include "roce_pd.h"
+#include "roce_user.h"
+
+#include "hmm_mr.h"
+#include "hmm_comp.h"
+#include "hinic3_hmm.h"
+
+#define ROCE3_MR_DEFAULT_ACCESS \
+ (IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_WRITE | \
+ IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_ATOMIC)
+
+#define ROCE3_MR_PAGES_ALIGN 64
+#define ROCE3_MIN_PAGE 2
+
+#define FRMR_PAGE_SIZE 4096
+
+struct roce3_sig_ctx {
+ /* recorded when submitting WR */
+ struct ib_sig_attrs sig_attrs;
+ /* Get information configuration from CQE when polling CQE */
+ struct ib_sig_err sig_err_item;
+ /* Indicates whether the status is checked */
+ bool sig_status_checked;
+ /* Indicates if an error exists */
+ bool sig_err_exists;
+ /* Count the number of wrong CQEs */
+ u32 sig_err_count;
+};
+
+struct roce3_mr {
+ /* mr structure provided by ofed */
+ struct ib_mr ibmr;
+ /* Maintain the structure where the user-mode allocated buffer */
+ struct ib_umem *umem;
+ /* mr structure provided by rdma component */
+ struct rdma_mr rdmamr;
+ /* Record signature related information */
+ struct roce3_sig_ctx sig;
+ /* Whether the logo contains signature information */
+ bool signature_en;
+ __be64 *pages;
+ u32 npages;
+ u32 max_pages;
+ size_t page_map_size;
+ dma_addr_t page_map;
+};
+
+struct roce3_mw {
+ /* mw structure provided by ofed */
+ struct ib_mw ibmw;
+ /* mw structure provided by rdma component */
+ struct rdma_mw rdmamw;
+};
+
+/* through ibmroce3_e_mr */
+static inline struct roce3_mr *to_roce3_mr(const struct ib_mr *ibmr)
+{
+ return container_of(ibmr, struct roce3_mr, ibmr);
+}
+
+/* through ibmroce3_e_mw */
+static inline struct roce3_mw *to_roce3_mw(const struct ib_mw *ibmw)
+{
+ return container_of(ibmw, struct roce3_mw, ibmw);
+}
+
+/* through rdmam find roce3_mr */
+static inline struct roce3_mr *rdma_mr_to_roce3_mr(const struct rdma_mr *rdmamr)
+{
+ return container_of(rdmamr, struct roce3_mr, rdmamr);
+}
+
+int roce3_alloc_tpt(struct roce3_device *rdev, struct rdma_mr *mr, u32 npages, u32 page_shift);
+void roce3_free_tpt(struct roce3_device *rdev, struct rdma_mr *mr);
+void roce3_set_rdma_mr(struct rdma_mr *mr, enum rdma_mr_type mr_type,
+ u32 pdn, u64 iova, u64 size, u32 access);
+
+int roce3_user_mr_reg(struct roce3_device *rdev, struct roce3_mr *mr, u32 pdn, u64 virt_addr,
+ u64 length, int access);
+
+#endif // __ROCE_MR_H_
diff --git a/drivers/infiniband/hw/hiroce3/qp/roce_post.h b/drivers/infiniband/hw/hiroce3/qp/roce_post.h
new file mode 100644
index 0000000000000..c1b622cee45b8
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/qp/roce_post.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_POST_H
+#define ROCE_POST_H
+
+#include <linux/types.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "roce_wqe_format.h"
+#include "roce_xqe_format.h"
+
+#define ROCE_SQ_DB_TYPE 2
+#define ROCE_UD_MTU_SHIFT 3 /* 4K mtu */
+#define ROCE_IMM_EXT_LEN 4
+#define ROCE_TASK_SEG_ALIGN 8
+
+#define ROCE_ATOMIC_WR atomic_wr
+#define ROCE_RDMA_WR rdma_wr
+#define ROCE_REG_WR reg_wr
+#define ROCE_UD_WR ud_wr
+
+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 */
+};
+
+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 roce3_wqe_ud_tsk_seg_cycle1 {
+ union roce3_wqe_tsk_com_seg common;
+
+ /* DW0 */
+ u32 data_len;
+
+ /* DW1 */
+ u32 immdata_invkey;
+
+ /* DW2 */
+/*
+ * 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.
+ */
+ union {
+ struct {
+ u32 pd : 18;
+ u32 rsvd0 : 6;
+ u32 stat_rate : 4;
+ 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 roce3_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 roce3_post_send_normal_param {
+ struct roce3_wqe_ctrl_seg *ctrl_seg;
+ union roce3_wqe_tsk_com_seg *tsk_com_seg;
+ u32 wqe_size;
+ u8 *wqe;
+ struct roce3_wqe_data_seg *dseg;
+ union roce_sq_db sq_db;
+ 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;
+ struct roce3_wqe_ctrl_seg ctrl_seg_tmp;
+
+ unsigned long flags;
+};
+
+#endif /* ROCE_POST_H */
diff --git a/drivers/infiniband/hw/hiroce3/qp/roce_qp.h b/drivers/infiniband/hw/hiroce3/qp/roce_qp.h
new file mode 100644
index 0000000000000..a76a464a56f1a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/qp/roce_qp.h
@@ -0,0 +1,244 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_QP_H
+#define ROCE_QP_H
+
+#include <linux/types.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "hinic3_rdma.h"
+#include "hinic3_cqm.h"
+
+#include "roce.h"
+#include "roce_cq.h"
+#include "roce_db.h"
+#include "roce_pd.h"
+
+#include "rdma_context_format.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_QP_TIMER_CHECK_VALUE 0xce
+#define ROCE_QP_DESTROY_CHECK_VALUE 0xffffffff
+#define ROCE_RDMARC_DESTROY_CHECK_VALUE 0xcece5a5a
+#define ROCE_CACHE_LINE_SIZE 256
+#define RDMARC_NUM_PER_CACHELINE 8
+#define RDMARC_TABLE_ENTRY_SIZE 32
+#define ROCE_STATIC_RDMARC_NUM 65536
+#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 (40)
+
+#define ROCE_QP_GPA_SIG_LEN 3
+#define ROCE_WR_MIN_NUM 2
+
+#define ROCE_QPC_PMTU_TRANSLATE(pmtu) ((1U << ((pmtu) - 1)) - 1)
+
+#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 ROCE3_LB1_MASK 0x3
+#define ROCE3_QPN_BIT_INDEX 29U
+#define ROCE3_QPN_CTRL_BIT_NUM 3U
+
+#define ROCE_VLAN_DIS 0xFFFF
+
+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_fake_vf_start_e {
+ ROCE_VLD_PF_NUM_10 = 10,
+ ROCE_VLD_PF_NUM_11 = 11,
+ ROCE_VLD_PF_NUM_12 = 12
+};
+
+enum {
+ ROCE_QP_PM_MIGRATED = 0x3,
+ ROCE_QP_PM_ARMED = 0x0,
+ ROCE_QP_PM_REARM = 0x1
+};
+
+enum {
+ ROCE_QP_ST_RC = 0x0, /* 000 */
+ ROCE_QP_ST_UC = 0x1, /* 001 */
+ ROCE_QP_ST_RD = 0x2, /* 010 */
+ ROCE_QP_ST_UD = 0x3, /* 011 */
+ ROCE_QP_ST_XRC = 0x6, /* 110 */
+ ROCE_QP_ST_PRIV = 0x7 /* 111 */
+};
+
+enum {
+ ROCE_QP_NO_SRQ,
+ ROCE_QP_HAS_SRQ
+};
+
+enum {
+ ROCE_QP = 0,
+ ROCE_QP_EXT
+};
+
+struct roce3_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 roce3_qp {
+ struct ib_qp ibqp;
+ u32 qpn;
+ struct roce3_db db;
+ struct tag_cqm_queue *qp_buf_info;
+ struct tag_cqm_qpc_mpt *qpc_info;
+ struct roce3_wq rq;
+ u32 sq_signal_bits;
+ unsigned int sq_next_wqe;
+ u32 sq_max_wqes_per_wr;
+ struct roce3_wq sq;
+ struct ib_umem *umem;
+ struct rdma_mtt mtt;
+ struct roce3_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;
+ struct rdma_rdmarc rdmarc;
+ u16 rsp_depth;
+ u8 sl;
+ bool has_rq;
+ u8 *sq_head_addr;
+ u8 *sq_tail_addr;
+ bool signature_en;
+ u8 double_sgl_mode;
+ u8 ext_mtu;
+ u8 ext_mtu_mode;
+
+ u8 db_sgid_index;
+ u8 db_path_mtu;
+
+ u32 qid;
+ u32 local_comm_id; /* used by NOF AA to reuse qpn when disconnection happens */
+ u32 remote_comm_id;
+
+ /* 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 roce3_sqp {
+ struct roce3_qp qp;
+ int pkey_index;
+ u32 qkey;
+ u32 send_psn;
+};
+
+static inline struct roce3_qp *to_roce3_qp(const struct ib_qp *ibqp)
+{
+ return container_of(ibqp, struct roce3_qp, ibqp);
+}
+
+static inline struct roce3_qp *cqmobj_to_roce_qp(const struct tag_cqm_object *object)
+{
+ struct tag_cqm_qpc_mpt *qpc_info;
+
+ qpc_info = container_of(object, struct tag_cqm_qpc_mpt, object);
+ return (struct roce3_qp *)qpc_info->priv;
+}
+
+static inline struct roce3_sqp *to_roce3_sqp(const struct roce3_qp *rqp)
+{
+ return container_of(rqp, struct roce3_sqp, qp);
+}
+
+struct roce3_qp_query_outbuf {
+ struct roce_qp_context qpc;
+};
+
+void roce3_qp_async_event(struct roce3_device *rdev, struct roce3_qp *qp, int type);
+u8 roce3_get_db_cos_from_vlan_pri(struct roce3_device *rdev, u8 vlan_pri);
+
+void roce3_free_opt_rdmarc(struct roce3_qp *rqp);
+void roce3_get_cqs(struct roce3_qp *rqp, struct roce3_cq **send_cq, struct roce3_cq **recv_cq);
+int roce3_qp_modify_2rst_cmd(struct roce3_device *rdev, u32 qpn);
+int roce3_qp_cache_out_cmd(struct roce3_device *rdev, struct roce3_qp *rqp);
+struct roce3_pd *roce3_get_pd(struct roce3_qp *rqp);
+int roce3_sqp_check(const struct roce3_qp *qp);
+void *roce3_get_wqe(struct roce3_qp *rqp, u32 offset);
+int roce3_wq_overflow(struct roce3_wq *wq, u32 wr_num, struct ib_cq *ibcq);
+void roce3_set_data_seg(struct roce3_wqe_data_seg *dseg, struct ib_sge *sge);
+void roce3_qpc_to_be(struct tag_roce_verbs_qp_attr *qp_attr, struct roce3_qp *rqp, u32 *be_ctx);
+void roce3_qp_rst2init(struct roce3_qp *rqp, const struct ib_qp_attr *attr,
+ struct tag_roce_verbs_qp_attr *qp_attr);
+struct ib_qp *roce3_create_qp_common(struct ib_pd *ibpd, struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata, int qp_ext);
+int roce3_send_qp_lb_cmd(u32 qpn, struct roce3_device *rdev, u8 cmd,
+ struct tag_cqm_cmd_buf *buf_in, struct tag_cqm_cmd_buf *buf_out, u32 timeout);
+
+int roce3_qp_query(struct roce3_device *rdev, u32 qpn, u32 *context, int qpc_size);
+int roce3_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 roce_qp_context *be_ctx, struct roce_qp_context *le_ctx, u32 srq_vld);
+void roce3_be32_2_le32(void *context, u32 *le_ctx, u32 ctx_size);
+
+#define IB_QP_CREATE_SIGNATURE_EN IB_QP_CREATE_INTEGRITY_EN
+
+#endif // ROCE_QP_H
diff --git a/drivers/infiniband/hw/hiroce3/qp/roce_qp_create.c b/drivers/infiniband/hw/hiroce3/qp/roce_qp_create.c
new file mode 100644
index 0000000000000..b88d4a5682aab
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/qp/roce_qp_create.c
@@ -0,0 +1,1239 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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_user.h"
+#include "roce_xrc.h"
+#include "roce_pd.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_qp.h"
+#include "roce_pub_cmd.h"
+#include "roce_qp_extension.h"
+#include "roce_main_extension.h"
+
+#include "hinic3_hmm.h"
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+
+/*
+ ****************************************************************************
+ Prototype : roce3_check_rq_size
+ Description : roce3_check_rq_size
+ Input : struct roce3_device *rdev
+ struct roce3_qp *rqp
+ struct ib_qp_cap *cap
+ bool has_rq
+ Output : None
+
+ 1.Date : 2017/4/27
+ Modification : Created function
+****************************************************************************
+*/
+static int roce3_check_rq_size(struct roce3_device *rdev, struct roce3_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 = (u32)ROCE_MIN(rdev->rdma_cap.max_sq_sg,
+ 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)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to check rq size, over range, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if (has_rq && ((cap->max_recv_wr == 0) || (cap->max_recv_sge == 0))) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Has rq, max_recv_wr(%d), max_recv_sge(%d), func_id(%d)\n",
+ __func__, cap->max_recv_wr, cap->max_recv_sge, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if ((!has_rq) && (cap->max_recv_wr != 0)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Not has rq, cap->max_recv_wr(%d), func_id(%d)\n",
+ __func__, cap->max_recv_wr, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_rq_size
+ Description : roce3_set_rq_size
+ Input : struct roce3_device *rdev
+ struct roce3_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 roce3_set_rq_size(struct roce3_device *rdev, struct roce3_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 sge_num = 0;
+ struct ib_qp_cap *cap = &init_attr->cap;
+
+ ret = roce3_check_rq_size(rdev, rqp, init_attr, has_rq);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to check rq size, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ if (has_rq) {
+ wqebb_num = ROCE_MAX(2U, cap->max_recv_wr);
+ /*lint -e587*/
+ rqp->rq.wqebb_cnt = (u32)(ROCE_ROUNDUP_POW_OF_TWO(wqebb_num) & 0xffffffff);
+ /*lint +e587*/
+
+ /* 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 roce3_wqe_data_seg));
+ rqp->rq.wqe_shift = (u32)ROCE_ILOG2(sge_total_len);
+
+ if ((u32)((u32)rqp->rq.wqebb_cnt << (unsigned int)rqp->rq.wqe_shift) < PAGE_SIZE)
+ rqp->rq.wqebb_cnt = (PAGE_SIZE >> (unsigned int)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;
+ sge_num = ROCE_MIN(rdev->rdma_cap.max_sq_sg,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_rq_sg);
+ cap->max_recv_sge = ROCE_MIN((u32)rqp->rq.max_sge, sge_num);
+ }
+ } 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 roce3_set_user_sq_size_check(struct roce3_device *rdev, const struct ib_qp_cap *cap,
+ const struct roce3_qp *rqp)
+{
+ u32 ud_max_inline_size;
+
+ if (cap->max_send_wr > (rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_wqes)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Log_sq_bb_count over range, func_id(%d)\n",
+ __func__, 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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: SQ max inline data over range, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+/*
+ ****************************************************************************
+ Prototype : roce3_set_user_sq_size
+ Description : roce3_set_user_sq_size
+ Input : struct roce3_device *rdev
+ struct ib_qp_cap *cap
+ struct roce3_qp *rqp
+ struct roce3_create_qp *ucmd
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_set_user_sq_size(struct roce3_device *rdev, struct ib_qp_cap *cap,
+ struct roce3_qp *rqp, struct create_qp_cmd *ucmd)
+{
+ u32 tmp_max_sq_wqe_sz = 0;
+ u32 sq_buf_sz = 0;
+ int ret = 0;
+
+ ret = roce3_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 */
+ /*lint -e587*/
+ tmp_max_sq_wqe_sz = (u32)(
+ ROCE_ROUNDUP_POW_OF_TWO(rdev->rdma_cap.max_sq_desc_sz) & 0xffffffff);
+ /*lint +e587*/
+ if ((ucmd->log_sq_stride > ROCE_ILOG2(tmp_max_sq_wqe_sz)) ||
+ (ucmd->log_sq_stride < ROCE_ILOG2(rdev->rdma_cap.wqebb_size))) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: WQE err, func_id(%d) log_sq:%d wqebb:%d max:%d\n",
+ __func__, 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 int)rqp->sq.wqe_shift) < PAGE_SIZE)
+ rqp->sq.wqebb_cnt = (PAGE_SIZE >> (unsigned int)rqp->sq.wqe_shift);
+
+ sq_buf_sz = (u32)ROCE_ALIGN((u64)rqp->sq.wqebb_cnt <<
+ (unsigned int)rqp->sq.wqe_shift, PAGE_SIZE);
+ rqp->buf_size = (int)ROCE_ALIGN(
+ ((unsigned int)sq_buf_sz + ((unsigned int)rqp->rq.wqebb_cnt <<
+ (unsigned int)rqp->rq.wqe_shift)), PAGE_SIZE);
+
+ rqp->sq.offset = 0;
+ rqp->rq.offset = sq_buf_sz;
+
+ rqp->max_inline_data = 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 : roce3_send_wqe_overhead
+ Description : roce3_send_wqe_overhead
+ Input : enum ib_qp_type qp_type
+ Output : None
+
+ 1.Date : 2015/5/7
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_send_wqe_overhead(enum ib_qp_type qp_type)
+{
+ switch (qp_type) {
+ case IB_QPT_RC:
+ return sizeof(struct roce3_wqe_ctrl_seg) +
+ sizeof(struct roce3_wqe_mask_atomic_tsk_seg);
+
+ case IB_QPT_UC:
+ return sizeof(struct roce3_wqe_ctrl_seg) + sizeof(struct roce3_wqe_send_tsk_seg);
+
+ case IB_QPT_UD:
+ return sizeof(struct roce3_wqe_ctrl_seg) + sizeof(struct roce3_wqe_ud_tsk_seg);
+
+ case IB_QPT_GSI:
+ return sizeof(struct roce3_wqe_ctrl_seg) + sizeof(struct roce3_wqe_ud_tsk_seg);
+
+ case IB_QPT_XRC_TGT:
+ return 0;
+
+ case IB_QPT_XRC_INI:
+ return sizeof(struct roce3_wqe_ctrl_seg) +
+ sizeof(struct roce3_wqe_mask_atomic_tsk_seg);
+
+ default:
+ pr_err("[ROCE, ERR] %s: Not supported this qp_type\n", __func__);
+ return -1;
+ }
+}
+
+static int roce3_set_kernel_sq_size_check(const struct roce3_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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: SQ WR over range, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ if (cap->max_send_sge >
+ (u32)ROCE_MIN(rdev->rdma_cap.max_sq_sg,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_rq_sg)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: SQ SGE over range, func_id(%d)\n",
+ __func__, 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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: SQ max inline data over range, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ wqe_overhead = roce3_send_wqe_overhead(qp_type);
+ if (wqe_overhead < 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Invalid service type(%d), func_id(%d)\n",
+ __func__, (int)qp_type, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ *sq_max_wqe_size =
+ ROCE_MAX((int)(cap->max_send_sge * sizeof(struct roce3_wqe_data_seg)),
+ (int)cap->max_inline_data) + wqe_overhead;
+ if (*sq_max_wqe_size > (int)rdev->rdma_cap.max_sq_desc_sz) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: SQ WQE size over range, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+/*
+ ****************************************************************************
+ Prototype : roce3_set_kernel_sq_size
+ Description : roce3_set_kernel_sq_size
+ Input : struct roce3_device *rdev
+ struct ib_qp_cap *cap
+ enum roce3_qp_type qp_type
+ struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_set_kernel_sq_size(struct roce3_device *rdev,
+ struct ib_qp_cap *cap, enum ib_qp_type qp_type, struct roce3_qp *rqp)
+
+{
+ u32 sq_buf_sz = 0;
+ int sq_max_wqe_size = 0;
+ int ret = 0;
+
+ ret = roce3_set_kernel_sq_size_check(rdev, cap, &sq_max_wqe_size, qp_type);
+ if (ret != 0)
+ return ret;
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ rqp->sq.wqe_shift = (u32)ROCE_ILOG2(rdev->rdma_cap.wqebb_size);
+ rqp->sq_max_wqes_per_wr =
+ (u32)ROCE_DIV_ROUND_UP((unsigned int)sq_max_wqe_size,
+ (u32)(1UL << (unsigned int)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)((int)cap->max_send_wr * rqp->sq_max_wqes_per_wr + 1);
+ /*lint -e587*/
+ rqp->sq.wqebb_cnt = (u32)(ROCE_ROUNDUP_POW_OF_TWO(rqp->sq.wqebb_cnt) & 0xffffffff);
+ /*lint +e587*/
+
+ 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 int)rqp->sq.wqe_shift) -
+ (unsigned int)roce3_send_wqe_overhead(qp_type));
+ rqp->sq.max_sge =
+ (u32)ROCE_MIN(rdev->rdma_cap.max_sq_desc_sz, rqp->sq.max_sge) /
+ (int)sizeof(struct roce3_wqe_data_seg);
+
+ sq_buf_sz = (u32)ALIGN((u64)rqp->sq.wqebb_cnt <<
+ (unsigned int)rqp->sq.wqe_shift, PAGE_SIZE);
+ rqp->buf_size = (int)ALIGN(((unsigned int)sq_buf_sz +
+ ((unsigned int)rqp->rq.wqebb_cnt << (unsigned int)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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s:Only one WR,please check,func_id(%d)\n",
+ __func__, 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(rdev->rdma_cap.max_sq_sg,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_rq_sg);
+ cap->max_send_sge = (u32)ROCE_MIN(rqp->sq.max_sge, cap->max_send_sge);
+ rqp->max_inline_data = 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 : roce3_qp_async_event
+ Description : roce3_qp_async_event
+ Input : struct roce3_device *rdev
+ struct roce3_qp *qp
+ int type
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_qp_async_event(struct roce3_device *rdev, struct roce3_qp *qp, int type)
+{
+ struct ib_event event;
+ struct ib_qp *ibqp = &qp->ibqp;
+
+ memset(&event, 0, sizeof(event));
+
+ 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 *roce3_buf_offset(struct roce3_buf *buf, u32 offset)
+{
+ return (void *)((char *)buf->direct.buf + offset);
+}
+
+void *roce3_get_wqe(struct roce3_qp *rqp, u32 offset)
+{
+ return roce3_buf_offset(&rqp->buf, offset);
+}
+
+static void *roce3_get_send_wqe_head(struct roce3_qp *rqp)
+{
+ return roce3_get_wqe(rqp, rqp->sq.offset);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_get_send_wqe_tail
+ Description : roce3_get_send_wqe_tail
+ Input : struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2015/8/8
+ Modification : Created function
+
+****************************************************************************
+*/
+static void *roce3_get_send_wqe_tail(struct roce3_qp *rqp)
+{
+ return roce3_get_wqe(rqp, rqp->sq.offset + (rqp->sq.wqebb_cnt << (u32)rqp->sq.wqe_shift));
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_sq_buf_init
+ Description : roce3_sq_buf_init
+ Input : struct roce3_qp *qp
+ Output : None
+
+ 1.Date : 2015/11/9
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_sq_buf_init(struct roce3_qp *qp)
+{
+ u32 entries = qp->rq.offset / (1U << qp->sq.wqe_shift);
+ u8 *wqe = NULL;
+ struct roce3_wqe_ctrl_seg *wqe_ctrl = NULL;
+ u32 i;
+
+ for (i = 0; i < entries; i++) {
+ wqe = (u8 *)qp->buf.direct.buf + (int)(i * (int)(1U << ((u32)qp->sq.wqe_shift)));
+ wqe_ctrl = (struct roce3_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 roce3_check_and_get_umem(struct roce3_device *rdev,
+ struct ib_pd *ibpd, struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata, struct roce3_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 = roce3_set_user_sq_size(rdev, &init_attr->cap, rqp, ucmd);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to set user sq_size, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ rqp->umem = ib_umem_get(&rdev->ib_dev, ucmd->buf_addr, (size_t)rqp->buf_size, 0);
+ if (IS_ERR(rqp->umem)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to get ib_umem, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ ret = (int)PTR_ERR(rqp->umem);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int roce3_alloc_qpc(struct roce3_qp *rqp, struct roce3_device *rdev,
+ u32 qpn, struct ib_qp_init_attr *init_attr)
+{
+ struct tag_cqm_qpc_mpt *qpc_info = NULL;
+ int ret;
+ struct roce3_srq *rsrq;
+ u32 qpn_tmp = qpn;
+ bool low2bit_align_en = false;
+
+ if (roce3_need_qpn_lb1_consistent_srqn(rqp, rdev, init_attr)) {
+ rsrq = to_roce3_srq(init_attr->srq);
+ qpn_tmp = ((rsrq->srqn & ROCE3_LB1_MASK) << ROCE3_QPN_BIT_INDEX) |
+ qpn_tmp >> ROCE3_QPN_CTRL_BIT_NUM;
+ low2bit_align_en = true;
+ }
+
+ qpc_info = cqm_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,
+ low2bit_align_en);
+ if (qpc_info == NULL) {
+ ret = -ENOMEM;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create qpc mpt, func_id(%d), qpn(%u)\n",
+ __func__, rdev->glb_func_id, qpn_tmp);
+ return ret;
+ }
+
+ rqp->qpc_info = qpc_info;
+ rqp->qpn = rqp->qpc_info->xid;
+ if (roce3_need_qpn_lb1_consistent_srqn(rqp, rdev, init_attr)) {
+ rsrq = to_roce3_srq(init_attr->srq);
+ if ((rsrq->srqn & ROCE3_LB1_MASK) != (rqp->qpn & ROCE3_LB1_MASK)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Wrong srqn, func_id(%d), qpn(%u) srqn(%u)\n",
+ __func__, rdev->glb_func_id, rqp->qpn, rsrq->srqn);
+ }
+ }
+ return 0;
+}
+
+static int roce3_create_qp_user_mtt(struct roce3_device *rdev, struct roce3_qp *rqp)
+{
+ u32 npages;
+ int ret;
+
+ npages = (u32)ib_umem_num_pages(rqp->umem);
+ rqp->buf.page_shift = PAGE_SHIFT;
+
+ rqp->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_rdma_mtt_alloc(rdev->hwdev, npages, (u32)rqp->buf.page_shift,
+ &rqp->mtt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc rdma_mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_umem_write_mtt(rdev, &rqp->mtt, rqp->umem);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to write mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_write_mtt;
+ }
+
+ return 0;
+
+err_write_mtt:
+ hmm_rdma_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+ return ret;
+}
+
+static void roce3_destroy_qp_user_mtt(struct roce3_device *rdev, struct roce3_qp *rqp)
+{
+ hmm_rdma_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_create_qp_user
+ Description : create qp resource for user space qp
+ Input : struct roce3_device *rdev
+ struct ib_pd *ibpd
+ struct ib_qp_init_attr *init_attr
+ struct ib_udata *udata
+ struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_create_qp_user(struct roce3_device *rdev, struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr, struct ib_udata *udata, struct roce3_qp *rqp)
+{
+ int ret = 0;
+ struct roce3_ucontext *roce3_uctx = NULL;
+ struct create_qp_cmd ucmd = { 0 };
+ u32 qpn = 0;
+
+ ret = roce3_create_qp_user_pre_ext(init_attr, rqp, &qpn);
+ if (ret != 0)
+ return ret;
+
+ roce3_uctx = to_roce3_ucontext(ibpd->uobject->context);
+
+ ret = roce3_check_and_get_umem(rdev, ibpd, init_attr, udata, rqp, &ucmd);
+ if (ret != 0)
+ return ret;
+
+ ret = roce3_create_qp_user_mtt(rdev, rqp);
+ if (ret != 0)
+ goto err_create_mtt;
+
+ if (init_attr->qp_type != IB_QPT_XRC_TGT) {
+ ret = roce3_db_map_user(roce3_uctx, ucmd.db_addr, &rqp->db);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to map db page to user, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_map_db;
+ }
+ }
+
+ ret = roce3_alloc_qpc(rqp, rdev, qpn, init_attr);
+ if (ret != 0)
+ goto err_alloc_qpc;
+
+ ret = roce3_create_qp_user_post_ext(ibpd, rdev, rqp, init_attr);
+ if (ret != 0)
+ goto err_extend_post;
+
+ return 0;
+
+err_extend_post:
+ hiudk_cqm_object_delete(rdev->hwdev, &(rqp->qpc_info->object));
+
+err_alloc_qpc:
+ if (init_attr->qp_type != IB_QPT_XRC_TGT)
+ roce3_db_unmap_user(roce3_uctx, &rqp->db);
+
+err_map_db:
+ roce3_destroy_qp_user_mtt(rdev, rqp);
+
+err_create_mtt:
+ ib_umem_release(rqp->umem);
+
+ return ret;
+}
+
+static void roce3_free_wrid(struct roce3_qp *rqp)
+{
+ if (rqp->rq.wrid)
+ kvfree(rqp->rq.wrid);
+
+ if (rqp->sq.wrid)
+ kvfree(rqp->sq.wrid);
+}
+
+static int roce3_get_wrid(struct roce3_qp *rqp, struct roce3_device *rdev)
+{
+ int ret = 0;
+
+ rqp->sq.wrid = kcalloc((unsigned int)rqp->sq.wqebb_cnt, sizeof(u64), GFP_KERNEL);
+ if (rqp->sq.wrid == NULL)
+ rqp->sq.wrid = vzalloc((size_t)(rqp->sq.wqebb_cnt * sizeof(u64)));
+
+ rqp->rq.wrid = kcalloc((unsigned int)rqp->rq.wqebb_cnt, sizeof(u64), GFP_KERNEL);
+ if (rqp->rq.wrid == NULL)
+ rqp->rq.wrid = vzalloc((size_t)(rqp->rq.wqebb_cnt * sizeof(u64)));
+
+ if ((rqp->sq.wrid == NULL) || (rqp->rq.wrid == NULL)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc wrid of sq or rq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+static void roce3_create_qp_kernel_set_attr(struct roce3_qp *rqp,
+ struct tag_cqm_queue *qp_buf_info)
+{
+ memset(qp_buf_info->q_room_buf_1.direct.va, 0,
+ (size_t)((unsigned int)rqp->buf_size));
+ 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 = ROCE_ILOG2(qp_buf_info->q_room_buf_1.buf_size);
+
+ roce3_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 *)roce3_get_send_wqe_head(rqp);
+ rqp->sq_tail_addr = (u8 *)roce3_get_send_wqe_tail(rqp);
+ rqp->max_dwqe_size = 0;
+
+ if (rqp->max_inline_data != 0)
+ rqp->max_dwqe_size = ROCE_QP_MAX_DWQE_SIZE;
+}
+
+static int roce3_create_qp_kernel_normal(struct roce3_device *rdev, struct roce3_qp *rqp)
+{
+ int ret;
+ struct tag_cqm_queue *qp_buf_info = NULL;
+
+ qp_buf_info = cqm_object_rdma_queue_create(rdev->hwdev, SERVICE_T_ROCE,
+ CQM_OBJECT_RDMA_QP, (u32)rqp->buf_size, rqp, true, ROCE_QP_INVLID_QP_NUM);
+ if (qp_buf_info == NULL) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create rdma queue by cqm object, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -1;
+ }
+
+ roce3_create_qp_kernel_set_attr(rqp, qp_buf_info);
+
+ rqp->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_rdma_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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc rdma mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_alloc_mtt;
+ }
+ ret = roce3_buf_write_mtt(rdev, &rqp->mtt, &rqp->qp_buf_info->q_room_buf_1);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to write rdma mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_write_mtt;
+ }
+
+ ret = roce3_get_wrid(rqp, rdev);
+ if (ret != 0)
+ goto err_alloc_wrid;
+
+ return 0;
+
+err_alloc_wrid:
+ roce3_free_wrid(rqp);
+
+err_write_mtt:
+ hmm_rdma_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+
+err_alloc_mtt:
+ hiudk_cqm_object_delete(rdev->hwdev, &rqp->qp_buf_info->object);
+
+ return ret;
+}
+
+static void roce3_destroy_qp_kernel_normal(struct roce3_device *rdev, struct roce3_qp *rqp)
+{
+ roce3_free_wrid(rqp);
+ hmm_rdma_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+ hiudk_cqm_object_delete(rdev->hwdev, &rqp->qp_buf_info->object);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_create_qp_kernel
+ Description : create qp resource for kernel space qp
+ Input : struct roce3_device *rdev
+ struct ib_qp_init_attr *init_attr
+ struct roce3_qp *rqp
+ u32 qpn
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_create_qp_kernel(struct roce3_device *rdev,
+ struct ib_qp_init_attr *init_attr, struct roce3_qp *rqp, u32 qpn)
+{
+ int ret = 0;
+
+ ret = roce3_set_kernel_sq_size(rdev, &init_attr->cap, (enum ib_qp_type)rqp->qp_type, rqp);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to set sq buffer size in kernel, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ ret = roce3_create_qp_kernel_normal(rdev, rqp);
+ if (ret != 0)
+ return ret;
+ }
+
+ ret = roce3_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)
+ roce3_destroy_qp_kernel_normal(rdev, rqp);
+
+ return ret;
+}
+
+static void roce3_qp_add_cq_list(struct ib_qp_init_attr *init_attr,
+ struct roce3_qp *rqp, struct roce3_device *rdev)
+{
+ struct roce3_cq *send_rcq = to_roce3_cq(init_attr->send_cq);
+ struct roce3_cq *recv_rcq = to_roce3_cq(init_attr->recv_cq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rdev->reset_flow_resource_lock, flags);
+ roce3_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);
+ roce3_unlock_cqs(send_rcq, recv_rcq);
+ spin_unlock_irqrestore(&rdev->reset_flow_resource_lock, flags);
+}
+
+static void roce3_init_qp_state(struct roce3_qp *rqp, struct roce3_device *rdev)
+{
+ struct roce_qp_context *qpc = (struct roce_qp_context *)((void *)rqp->qpc_info->vaddr);
+
+ if (!cqm_need_secure_mem(rdev->hwdev)) {
+ qpc->sw_seg.drv_seg.dw0.bs.state = ROCE_QP_STATE_MEM_INIT;
+ qpc->sw_seg.drv_seg.dw0.value = cpu_to_be32(qpc->sw_seg.drv_seg.dw0.value);
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_create_qp_common
+ Description : roce3_create_qp_common
+ Input : struct roce3_device *rdev
+ struct roce3_qp *rqp
+ struct ib_pd *ibpd
+ struct ib_qp_init_attr *init_attr
+ struct ib_udata *udata
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_do_create_qp(struct roce3_device *rdev, struct roce3_qp *rqp, struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr, struct ib_udata *udata)
+{
+ int ret = 0;
+
+ mutex_init(&rqp->mutex);
+ /*lint -e708 -e413 */
+ spin_lock_init(&rqp->sq.lock);
+ spin_lock_init(&rqp->rq.lock);
+ /*lint +e708 +e413 */
+
+ 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);
+
+ if (ibpd->uobject) {
+ ret = roce3_set_rq_size(rdev, rqp, init_attr, true, rqp->has_rq);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to set rq size, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_create_qp_pre_ext(rdev, rqp, init_attr);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] : Failed to handle qp create pre extension, func_id(%d)\n",
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_create_qp_user(rdev, ibpd, init_attr, udata, rqp);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] : Failed to create qp user, func_id(%d)\n",
+ rdev->glb_func_id);
+ return ret;
+ }
+ } else {
+ ret = roce3_set_rq_size(rdev, rqp, init_attr, false, rqp->has_rq);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to set rq size, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_create_qp_kernel(rdev, init_attr, rqp, ROCE_QP_INVLID_QP_NUM);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create qp kernel, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ roce3_qp_add_cq_list(init_attr, rqp, rdev);
+ }
+
+ if (roce3_is_qp_normal(rqp, init_attr) != 0)
+ roce3_init_qp_state(rqp, rdev);
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_create_qp_gsi
+ Description : roce3_create_qp_gsi
+ Input : struct roce3_device *rdev
+ struct ib_pd *ibpd
+ struct ib_qp_init_attr *init_attr
+ Output : None
+
+ 1.Date : 2017/04/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static struct roce3_qp *roce3_create_qp_gsi(struct roce3_device *rdev, struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr)
+{
+ int ret;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_sqp *sqp = NULL;
+
+ sqp = kzalloc(sizeof(struct roce3_sqp), GFP_KERNEL);
+ if (sqp == NULL)
+ return (struct roce3_qp *)ERR_PTR((long)-ENOMEM);
+
+ rqp = &sqp->qp;
+
+ mutex_init(&rqp->mutex);
+ /*lint -e708*/
+ spin_lock_init(&rqp->sq.lock);
+ spin_lock_init(&rqp->rq.lock);
+ /*lint +e708*/
+ 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 = roce3_set_rq_size(rdev, rqp, init_attr, false, rqp->has_rq);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to set rq size, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_out;
+ }
+
+ ret = roce3_create_qp_kernel(rdev, init_attr, rqp, ROCE_QP_GSI_QP_NUM);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create qp kernel, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_out;
+ }
+
+ rqp->qpn = ROCE_QP_GSI_QP_NUM;
+
+ roce3_init_qp_state(rqp, rdev);
+ roce3_qp_add_cq_list(init_attr, rqp, rdev);
+
+ return rqp;
+
+err_out:
+ kfree(sqp);
+
+ return (struct roce3_qp *)ERR_PTR((long)ret);
+}
+
+static int roce3_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) {
+ pr_err("[ROCE, ERR] %s: init_attr is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ if ((ibpd == NULL) && (init_attr->qp_type != IB_QPT_XRC_TGT)) {
+ pr_err("[ROCE, ERR] %s: Ibpd is null and qp_type is not IB_QPT_XRC_TGT\n",
+ __func__);
+ return (-EINVAL);
+ }
+
+ if ((udata) && (init_attr->qp_type == IB_QPT_GSI)) {
+ pr_err("[ROCE, ERR] %s: Udata is not null and qp_type is IB_QPT_GSI\n", __func__);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+static int roce3_set_qp_attr(struct ib_qp_init_attr *init_attr, struct roce3_qp *rqp,
+ struct roce3_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_roce3_xrcd(init_attr->xrcd)->pd;
+ xrcdn = (u16)to_roce3_xrcd(init_attr->xrcd)->xrcdn;
+ init_attr->send_cq = to_roce3_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) &&
+ roce3_is_roceaa(rdev->cfg_info.scence_id)) {
+ init_attr->recv_cq = init_attr->send_cq;
+ rqp->has_rq = false;
+ } else if (init_attr->qp_type == IB_QPT_XRC_INI) {
+ init_attr->recv_cq = init_attr->send_cq;
+ rqp->has_rq = false;
+ if (rdev->is_vroce)
+ rqp->sl = rdev->group_xrc_cos;
+ } 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;
+ if (init_attr->qp_type == IB_QPT_RC && rdev->is_vroce)
+ rqp->sl = rdev->group_rc_cos;
+ else if (rdev->is_vroce)
+ rqp->sl = rdev->group_ud_cos;
+ } else {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Unknown QP Type(%u), func_id(%d)\n",
+ __func__, init_attr->qp_type, rdev->glb_func_id);
+ return (-EINVAL);
+ }
+ return 0;
+}
+
+static struct ib_qp *roce3_create_gsi_qp_result(struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr, struct roce3_device *rdev)
+{
+ int ret;
+ struct roce3_qp *rqp = NULL;
+
+ rqp = roce3_create_qp_gsi(rdev, ibpd, init_attr);
+ if (IS_ERR(rqp)) {
+ ret = (int)PTR_ERR(rqp);
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create qp gsi, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return (struct ib_qp *)ERR_PTR((long)ret);
+ }
+
+ rqp->ibqp.qp_num = rqp->qpn;
+ return &rqp->ibqp;
+}
+
+struct ib_qp *roce3_create_qp_common(struct ib_pd *ibpd, struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata, int qp_ext)
+{
+ int ret = 0;
+ struct roce3_qp *rqp = NULL;
+ struct ib_device *ibdev = NULL;
+ struct roce3_device *rdev = NULL;
+
+ ret = roce3_create_check_init_attr(ibpd, init_attr, udata);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to check init attr\n", __func__);
+ return (struct ib_qp *)ERR_PTR((long)ret);
+ }
+
+ ibdev = ibpd ? ibpd->device : init_attr->xrcd->device;
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return (struct ib_qp *)ERR_PTR((long)-EPERM);
+ }
+
+ if (init_attr->qp_type == IB_QPT_GSI)
+ return roce3_create_gsi_qp_result(ibpd, init_attr, rdev);
+
+ rqp = kzalloc(sizeof(*rqp), GFP_KERNEL);
+ if (rqp == NULL)
+ return (struct ib_qp *)ERR_PTR((long)-ENOMEM);
+
+ ret = roce3_set_qp_attr(init_attr, rqp, rdev, &ibpd, qp_ext);
+ if (ret != 0)
+ goto err_create_qp;
+
+ ret = roce3_do_create_qp(rdev, rqp, ibpd, init_attr, udata);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create qp in common process, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_create_qp;
+ }
+
+ roce3_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 &rqp->ibqp;
+
+err_create_qp:
+ kfree(rqp);
+
+ return (struct ib_qp *)ERR_PTR((long)ret);
+}
+
+struct ib_qp *roce3_create_qp(struct ib_pd *ibpd, struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ return roce3_create_qp_common(ibpd, init_attr, udata, ROCE_QP);
+}
diff --git a/drivers/infiniband/hw/hiroce3/qp/roce_qp_destroy.c b/drivers/infiniband/hw/hiroce3/qp/roce_qp_destroy.c
new file mode 100644
index 0000000000000..be000e744d9e5
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/qp/roce_qp_destroy.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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"
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+#include "hinic3_hmm.h"
+
+#ifdef ROCE_VBS_EN
+#include "roce_vbs_qp.h"
+#endif
+
+static void roce3_clean_qp_user(struct roce3_device *rdev, struct roce3_qp *rqp,
+ struct roce3_ucontext *ucontext)
+{
+ roce3_free_opt_rdmarc(rqp);
+
+ hiudk_cqm_object_delete(rdev->hwdev, &(rqp->qpc_info->object));
+
+#ifdef ROCE_VBS_EN
+ if (rqp->vbs_qp_ptr)
+ roce3_vbs_destroy_sqpc(rdev->hwdev, rqp);
+#endif
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT)
+ roce3_db_unmap_user(ucontext, &rqp->db);
+
+ hmm_rdma_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+
+ ib_umem_release(rqp->umem);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_clean_process
+ Description : roce3_cq_clean_process
+ Input : struct roce3_cq *cq
+ u32 qpn
+ struct roce3_srq *srq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_cq_clean_process(struct roce3_cq *cq, u32 qpn, struct roce3_srq *srq)
+{
+ u32 prod_index = 0;
+ int nfreed = 0;
+ struct roce_cqe *cqe = NULL;
+ struct roce_cqe *dest = NULL;
+ u8 owner_bit = 0;
+
+ /*
+ * 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; roce3_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 *)roce3_get_cqe(cq, prod_index & (u32)cq->ibcq.cqe);
+
+ cqe->dw0.value = roce3_convert_cpu32(cqe->dw0.value);
+ cqe->dw1.value = roce3_convert_cpu32(cqe->dw1.value);
+ cqe->dw7.value = roce3_convert_cpu32(cqe->dw7.value);
+
+ if (cqe->dw0.bs.qpn == qpn) {
+ if (srq && (cqe->dw1.bs.s_r == ROCE_CQE_RECV_COMP))
+ roce3_free_srq_wqe(srq, cqe->dw7.bs.wqe_cnt);
+
+ ++nfreed;
+ } else if (nfreed != 0) {
+ dest = (struct roce_cqe *)roce3_get_cqe(cq,
+ (unsigned int)((int)prod_index + nfreed) &
+ (unsigned int)cq->ibcq.cqe);
+ dest->dw0.value = roce3_convert_cpu32(dest->dw0.value);
+ owner_bit = dest->dw0.bs.owner;
+ memcpy((void *)dest, (void *)cqe, sizeof(struct roce_cqe));
+ dest->dw0.bs.owner = owner_bit;
+ dest->dw0.value = roce3_convert_be32(dest->dw0.value);
+ dest->dw1.value = roce3_convert_be32(dest->dw1.value);
+ dest->dw7.value = roce3_convert_be32(dest->dw7.value);
+ } else {
+ pr_info("[ROCE] %s: Nothing need to do\n", __func__);
+ }
+
+ cqe->dw0.value = roce3_convert_be32(cqe->dw0.value);
+ cqe->dw1.value = roce3_convert_be32(cqe->dw1.value);
+ cqe->dw7.value = roce3_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();
+
+ roce3_cq_set_ci(cq);
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_clean_qp_kernel
+ Description : roce3_clean_qp_kernel
+ Input : struct roce3_device *rdev
+ struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2017/04/26
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_clean_qp_kernel(struct roce3_device *rdev, struct roce3_qp *rqp)
+{
+ struct roce3_cq *send_cq = NULL;
+ struct roce3_cq *recv_cq = NULL;
+ unsigned long flags;
+
+ roce3_free_opt_rdmarc(rqp);
+
+ roce3_get_cqs(rqp, &send_cq, &recv_cq);
+
+ spin_lock_irqsave(&rdev->reset_flow_resource_lock, flags);
+ roce3_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);
+
+ roce3_cq_clean_process(recv_cq, rqp->qpn, rqp->ibqp.srq ?
+ to_roce3_srq(rqp->ibqp.srq) : NULL);
+
+ if (send_cq != recv_cq)
+ roce3_cq_clean_process(send_cq, rqp->qpn, NULL);
+
+ roce3_unlock_cqs(send_cq, recv_cq);
+ spin_unlock_irqrestore(&rdev->reset_flow_resource_lock, flags);
+
+ hiudk_cqm_object_delete(rdev->hwdev, &(rqp->qpc_info->object));
+
+ 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)
+ hiudk_cqm_object_delete(rdev->hwdev, &(rqp->qp_buf_info->object));
+
+ hmm_rdma_mtt_free(rdev->hwdev, &rqp->mtt, SERVICE_T_ROCE);
+}
+
+static int roce3_qp_destroy(struct roce3_qp *rqp, struct roce3_device *rdev)
+{
+ int ret = 0;
+
+ ret = roce3_qp_modify_2rst_cmd(rdev, rqp->qpn);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to modify QP(0x%06x) to RESET, func_id(%d)\n",
+ __func__, rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_qp_cache_out_cmd(rdev, rqp);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: QP(0x%06x) cache invalid, func_id(%d)\n",
+ __func__, rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce3_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_device *rdev = NULL;
+ struct roce3_ucontext *ucontext = NULL;
+
+ if (ibqp == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibqp is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rqp = to_roce3_qp(ibqp);
+ rdev = to_roce3_dev(ibqp->device);
+
+ if (rqp->qp_state != IB_QPS_RESET) {
+ ret = roce3_qp_destroy(rqp, rdev);
+ if (ret != 0)
+ return ret;
+
+ rqp->qp_state = IB_QPS_RESET;
+ }
+
+ if (ibqp->uobject) {
+ ucontext = rdma_udata_to_drv_context(udata, struct roce3_ucontext, ibucontext);
+ roce3_clean_qp_user(rdev, rqp, ucontext);
+ goto out;
+ }
+
+ roce3_clean_qp_kernel(rdev, rqp);
+out:
+ mutex_lock(&rdev->qp_cnt.cur_qps_mutex);
+ rdev->qp_cnt.del_qp_cnt++;
+ mutex_unlock(&rdev->qp_cnt.cur_qps_mutex);
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/qp/roce_qp_exp.h b/drivers/infiniband/hw/hiroce3/qp/roce_qp_exp.h
new file mode 100644
index 0000000000000..d477e03caaadb
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/qp/roce_qp_exp.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_QP_EXP_H
+#define ROCE_QP_EXP_H
+
+#include <linux/io-mapping.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "hinic3_rdma.h"
+#include "hinic3_cqm.h"
+
+#include "rdma_context_format.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 roce3_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 roce3_device_list *roce3_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 roce3_qp_modify_exp(struct roce3_device *rdev, struct roce3_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 roce3_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/hiroce3/qp/roce_qp_modify.c b/drivers/infiniband/hw/hiroce3/qp/roce_qp_modify.c
new file mode 100644
index 0000000000000..c40f508c1d4a0
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/qp/roce_qp_modify.c
@@ -0,0 +1,2243 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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 "hinic3_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_pub_cmd.h"
+#include "roce_verbs_attr.h"
+#include "roce_verbs_ext_attr.h"
+#include "rdma_context_format.h"
+
+#ifdef ROCE_VBS_EN
+#include "roce_vbs_qp.h"
+#endif
+
+#ifdef ROCE_ANTI_ATTACK
+#include "roce_anti_attack.h"
+#include "roce_cmd.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 4
+#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 {
+ ROCE_IPSUTX_CHANNEL_5 = 0x0, /* 00 */
+ ROCE_IPSUTX_CHANNEL_10 = 0x1, /* 01 */
+ ROCE_IPSUTX_CHANNEL_15 = 0x2, /* 10 */
+ ROCE_IPSUTX_CHANNEL_20 = 0x3, /* 01 */
+};
+
+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
+};
+
+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_COMPUTE
+static int g_sq_cqn_lb;
+module_param(g_sq_cqn_lb, int, 0444); //lint !e806
+MODULE_PARM_DESC(g_sq_cqn_lb, "default: 0");
+
+static int g_rq_cqn_lb;
+module_param(g_rq_cqn_lb, int, 0444); //lint !e806
+MODULE_PARM_DESC(g_rq_cqn_lb, "default: 0");
+#else
+static int g_sq_cqn_lb = 1;
+module_param(g_sq_cqn_lb, int, 0444); //lint !e806
+MODULE_PARM_DESC(g_sq_cqn_lb, "default: 1");
+
+static int g_rq_cqn_lb = 1;
+module_param(g_rq_cqn_lb, int, 0444); //lint !e806
+MODULE_PARM_DESC(g_rq_cqn_lb, "default: 1");
+#endif
+
+static void roce3_timeout_check(struct roce3_device *rdev, const struct timespec64 *tv_start,
+ int func_id, int times)
+{
+ uint64_t cost;
+ struct timespec64 delta;
+ struct timespec64 tv_end = { 0 };
+
+ ktime_get_ts64(&tv_end);
+ delta = timespec64_sub(tv_end, *tv_start);
+ cost = delta.tv_sec * USEC_PER_SEC + delta.tv_nsec / NSEC_PER_USEC;
+
+ if (cost >= ROCE_CMDQ_TIMEOUT) {
+ dev_warn_ratelimited(rdev->hwdev_hdl,
+ "[ROCE, WARN] %s:destroy qp exec too long, func_id(%d), cost(%llu), times:%d\n",
+ __func__, func_id, cost, times);
+ }
+}
+
+#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 : roce3_calculate_sign_bit
+ Description : roce3_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 roce3_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 : roce3_calculate_signature
+ Description : roce3_calculate_signature
+ Input : u32 *sign_bit
+ u32 sign_width
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+****************************************************************************
+*/
+static u32 roce3_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 : roce3_gen_sq_rq_gpa_sign
+ Description : Signature 3bit
+ CheckedBits = sq_rq_l0mtt_gpa[32:00]
+ Input : u64 sq_rq_l0mtt_gpa
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+****************************************************************************
+*/
+static u32 roce3_gen_sq_rq_gpa_sign(u64 sq_rq_l0mtt_gpa)
+{
+ u32 i;
+ u32 signature = 0;
+ u32 sign_bit[ROCE_QP_GPA_SIGN_WIDTH] = {0};
+ u32 check_bit[ROCE_QP_GPA_SIGN_CHECKBITS] = {0};
+
+ for (i = 0; i < ROCE_QP_GPA_SIGN_CHECKBITS; i++) {
+ if ((sq_rq_l0mtt_gpa >> ROCE_QP_GPA_SIG_LEN) & (1ULL << i))
+ check_bit[i] = 1;
+ }
+
+ roce3_calculate_sign_bit(check_bit, ROCE_QP_GPA_SIGN_WIDTH,
+ ROCE_QP_GPA_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce3_calculate_signature(sign_bit, ROCE_QP_GPA_SIGN_WIDTH);
+
+ return signature;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_gen_qp_qpcc_sign
+ Description : Signature 5bit
+ CheckedBits = QPn[19:0]
+ Input : u32 qpn
+ Output : None
+
+ 1.Date : 2017/4/1
+ Modification : Created function
+
+****************************************************************************
+*/
+static u32 roce3_gen_qp_qpcc_sign(u32 qpn)
+{
+ u32 i;
+ u32 signature = 0;
+ u32 sign_bit[ROCE_QP_QPCC_SIGN_WIDTH] = {0};
+ u32 check_bit[ROCE_QP_QPCC_SIGN_CHECKBITS] = {0};
+
+ for (i = 0; i < ROCE_QP_QPCC_SIGN_CHECKBITS; i++) {
+ if (qpn & (1U << i))
+ check_bit[i] = 1;
+ }
+
+ roce3_calculate_sign_bit(check_bit, ROCE_QP_QPCC_SIGN_WIDTH,
+ ROCE_QP_QPCC_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce3_calculate_signature(sign_bit, ROCE_QP_QPCC_SIGN_WIDTH);
+
+ return signature;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_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;
+ }
+
+ roce3_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce3_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_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;
+ }
+
+ roce3_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce3_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_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;
+ }
+
+ roce3_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce3_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_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;
+ }
+
+ roce3_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce3_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_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;
+ }
+
+ roce3_calculate_sign_bit(check_bit, ROCE_QP_SUB_SIGN_WIDTH,
+ ROCE_QP_SUB_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce3_calculate_signature(sign_bit, ROCE_QP_SUB_SIGN_WIDTH);
+
+ return signature;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_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;
+ }
+
+ roce3_calculate_sign_bit(check_bit, ROCE_SQ_WQE_SIGN_WIDTH,
+ ROCE_SQ_WQE_SIGN_SPLITNUM, sign_bit);
+
+ signature = roce3_calculate_signature(sign_bit, ROCE_SQ_WQE_SIGN_WIDTH);
+
+ return signature;
+}
+#endif
+
+static void roce3_qp_set_path(const struct roce3_device *rdev, struct rdma_ah_attr *ah_attr,
+ struct tag_roce_verbs_qpc_attr_path *path_info)
+{
+ u8 *dmac = ah_attr->roce.dmac;
+
+ path_info->dw7.bs.hoplmt = (u8)ah_attr->grh.hop_limit;
+ path_info->dw6.bs.tclass = (u8)(ah_attr->grh.traffic_class | 0x2);
+ 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);
+
+ memcpy((void *)path_info->dgid, (void *)ah_attr->grh.dgid.raw,
+ sizeof(path_info->dgid));
+
+ memcpy((void *)&path_info->dmac_l32, (void *)&dmac[ROCE_RAH_DMAC_L32_START],
+ sizeof(path_info->dmac_l32));
+ path_info->dmac_l32 = cpu_to_be32(path_info->dmac_l32);
+ // shift dmac[0] left by 8 bits
+ path_info->dw0.bs.dmac_h16 = (dmac[0] << ROCE_RAH_DMAC_H16_SHIFT) | dmac[1];
+ path_info->dw7.bs.sl = (ah_attr->sl & 0x7); /* sl: 3bit */
+}
+
+struct roce3_pd *roce3_get_pd(struct roce3_qp *rqp)
+{
+ if (rqp->qp_type == IB_QPT_XRC_TGT)
+ return to_roce3_pd(to_roce3_xrcd(rqp->ibqp.xrcd)->pd);
+ else
+ return to_roce3_pd(rqp->ibqp.pd);
+}
+
+void roce3_get_cqs(struct roce3_qp *rqp, struct roce3_cq **send_cq, struct roce3_cq **recv_cq)
+{
+ switch (rqp->qp_type) {
+ case IB_QPT_XRC_TGT:
+ *send_cq = to_roce3_cq(to_roce3_xrcd(rqp->ibqp.xrcd)->cq);
+ *recv_cq = *send_cq;
+ break;
+
+ case IB_QPT_XRC_INI:
+ *send_cq = to_roce3_cq(rqp->ibqp.send_cq);
+ *recv_cq = *send_cq;
+ break;
+
+ default:
+ *send_cq = to_roce3_cq(rqp->ibqp.send_cq);
+ *recv_cq = to_roce3_cq(rqp->ibqp.recv_cq);
+ break;
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_access_flags
+ Description : roce3_set_access_flags
+ Input : struct roce3_qp *rqp
+ struct tag_roce_verbs_qp_attr *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 roce3_set_access_flags(struct roce3_qp *rqp, struct tag_roce_verbs_qp_attr *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 */
+}
+
+int roce3_sqp_check(const struct roce3_qp *qp)
+{
+ if (((qp->qp_type == IB_QPT_GSI) && (qp->qpn == ROCE_QP_SMI_QP_NUM)) ||
+ (qp->qpn == ROCE_QP_GSI_QP_NUM))
+ return 1;
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : store_sqp_attrs
+ Description : save the special
+ Input : struct roce3_sqp *sqp
+ const struct ib_qp_attr *attr
+ int attr_mask
+ Output : None
+
+ 1.Date : 2015/7/24
+ Modification : Created function
+
+****************************************************************************
+*/
+static void store_sqp_attrs(struct roce3_sqp *sqp, const struct ib_qp_attr *attr, int attr_mask)
+{
+ if (((u32)attr_mask & IB_QP_PKEY_INDEX) != 0)
+ sqp->pkey_index = attr->pkey_index;
+
+ if ((((u32)attr_mask) & IB_QP_QKEY) != 0)
+ sqp->qkey = attr->qkey;
+
+ if ((((u32)attr_mask) & IB_QP_SQ_PSN) != 0)
+ sqp->send_psn = attr->sq_psn;
+}
+
+/*
+ ****************************************************************************
+ Prototype : qpc_seg_to_be
+ Input : struct roce_qp_context *be_ctx
+ struct roce_qp_context *le_ctx
+ struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2015/7/29
+ Modification : Created function
+
+****************************************************************************
+*/
+static void qpc_seg_to_be(struct tag_roce_verbs_qp_attr *be_ctx,
+ struct tag_roce_verbs_qp_attr *le_ctx, struct roce3_qp *rqp)
+{
+ /* DRV Seg */
+ memcpy((void *)be_ctx->path_info.dgid, (void *)le_ctx->path_info.dgid,
+ sizeof(le_ctx->path_info.dgid));
+
+ /* 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 : roce3_qpc_to_be
+ Description : translate big endian
+ Input : struct tag_roce_verbs_qp_attr *qp_attr
+ struct roce3_qp *rqp
+ u32 *be_ctx
+ Output : None
+
+ 1.Date : 2015/7/29
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_qpc_to_be(struct tag_roce_verbs_qp_attr *qp_attr, struct roce3_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(struct tag_roce_verbs_qp_attr) / sizeof(u32);
+
+ for (i = 0; i < ctx_size; ++i, ++ctx1, ++ctx)
+ *ctx = cpu_to_be32(*ctx1);
+
+ qpc_seg_to_be((struct tag_roce_verbs_qp_attr *)((void *)be_ctx), qp_attr, rqp);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_alloc_opt_rdmarc
+ Description : alloc rdmarc when modify qp
+ Input : struct roce3_qp *rqp
+ struct ib_qp_attr *attr
+ int attr_mask
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_alloc_opt_rdmarc(struct roce3_qp *rqp,
+ const struct ib_qp_attr *attr, int attr_mask)
+{
+ int ret = 0;
+ struct roce3_device *rdev = NULL;
+ u32 response_depth = 0;
+
+ rdev = to_roce3_dev(rqp->ibqp.device);
+ /*lint -e587*/
+ response_depth = (attr->max_dest_rd_atomic == 0) ?
+ 1 : (u32)ROCE_ROUNDUP_POW_OF_TWO((u32)attr->max_dest_rd_atomic);
+ /*lint +e587*/
+ if (rqp->rsp_depth != response_depth) {
+ if (rqp->rsp_depth > 0)
+ roce3_rdma_rdmarc_free(rdev->hwdev, &rqp->rdmarc);
+
+ ret = roce3_rdma_rdmarc_alloc(rdev->hwdev, response_depth, &rqp->rdmarc);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc rdma rdmarc, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ rqp->rsp_depth = (u16)response_depth;
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_free_opt_rdmarc
+ Description : free rdmarc when modify qp failed or destroy qp
+ Input : struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_free_opt_rdmarc(struct roce3_qp *rqp)
+{
+ struct roce3_device *rdev = NULL;
+
+ rdev = to_roce3_dev(rqp->ibqp.device);
+
+ if (rqp->rsp_depth > 0)
+ roce3_rdma_rdmarc_free(rdev->hwdev, &rqp->rdmarc);
+
+ rqp->rsp_depth = 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_opt_rdmarc
+ Description : set opt rdmarc field
+ Input : struct roce3_device *rdev
+ struct roce3_qp *rqp
+ struct tag_roce_verbs_qp_attr *qp_attr
+ Output : None
+
+ 1.Date : 2017/04/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_set_opt_rdmarc(struct roce3_device *rdev, struct roce3_qp *rqp,
+ struct tag_roce_verbs_qp_attr *qp_attr)
+{
+ qp_attr->chip_seg.dw10.bs.rc_page_gpa_h =
+ (rqp->rdmarc.dma_addr >> 40) & 0xffffff; /* high:24bit, 64-24= 40 */
+ qp_attr->chip_seg.rc_page_gpa_l = (u32)(rqp->rdmarc.dma_addr >> 8); // bit[39:8]
+ qp_attr->chip_seg.dw4.bs.rc_size = rqp->rdmarc.order;
+ qp_attr->com_info.dw1.bs.rra_max = ((u8)fls(rqp->rsp_depth - 1)) & 0x7; /* rra_max:3bit */
+ qp_attr->chip_seg.dw4.bs.rc_max_size = rqp->rdmarc.ext_order - 3;
+}
+
+static void roce3_set_opt_mtu(struct tag_roce_verbs_qp_attr *qp_attr, const struct ib_qp_attr *attr)
+{
+ u32 pmtu = (u32)attr->path_mtu & 0x7;
+
+ qp_attr->com_info.dw3.bs.pmtu = pmtu; /* 1,2,3,4,5 */
+ qp_attr->com_info.dw5.bs.mtu_code =
+ ROCE_QPC_PMTU_TRANSLATE(pmtu); /* 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;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_opt_sra
+ Description : set opt sra
+ Input : struct tag_roce_verbs_qp_attr *qp_attr
+ struct ib_qp_attr *attr
+ Output : None
+
+ 1.Date : 2017/04/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_set_opt_sra(struct tag_roce_verbs_qp_attr *qp_attr, struct ib_qp_attr *attr)
+{
+ u8 initiator_depth;
+
+ /*lint -e587*/
+ initiator_depth = (attr->max_rd_atomic == 0) ? 1 :
+ (u8)ROCE_ROUNDUP_POW_OF_TWO((u32)attr->max_rd_atomic);
+ /*lint +e587*/
+ qp_attr->com_info.dw1.bs.sra_max =
+ ((u32)ROCE_FLS(initiator_depth - 1)) & 0x7; /* sra_max:3bit */
+}
+
+u8 roce3_get_db_cos_from_vlan_pri(struct roce3_device *rdev, u8 vlan_pri)
+{
+ u8 db_cos;
+ int ret;
+
+ ret = hinic3_get_cos_by_pri(rdev->hwdev, vlan_pri, &db_cos);
+ if (ret != 0) {
+ pr_info("%s, ret:%d vlan_pri:%u\n", __func__, ret, vlan_pri);
+ db_cos = 0;
+ }
+
+ return db_cos;
+}
+
+static void roce3_set_opt_attr_av(struct roce3_qp *rqp, struct roce3_device *rdev,
+ struct ib_qp_attr *attr, struct tag_roce_verbs_qp_attr *qp_attr, u32 *optpar)
+{
+ u8 cos;
+ struct roce3_get_cos_inbuf inbuf = { 0 };
+
+ roce3_qp_set_path(rdev, &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;
+ qp_attr->com_info.dw2.bs.vroce_en = (u32)rdev->is_vroce;
+ *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)roce3_get_dcb_cfg_cos(rdev, &inbuf, &cos);
+ if (rdev->is_vroce)
+ cos = rqp->sl;
+
+ qp_attr->com_info.dw5.bs.cos = cos & 0x7;
+
+ rqp->db_sgid_index = attr->ah_attr.grh.sgid_index & 0x7f;
+}
+
+static void roce3_set_opt_field_attr(struct roce3_qp *rqp, const struct ib_qp_attr *attr,
+ int attr_mask, struct tag_roce_verbs_qp_attr *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 */
+ }
+
+#ifdef ROCE_VBS_EN
+ if ((((u32)attr_mask) & ROCE_QP_VBS_FLAG) != 0) { /* IBV_QP_VBS_OSD_FLAG */
+ roce3_vbs_set_attr(rqp, qp_attr, attr_mask);
+ }
+#endif
+}
+
+static s32 roce3_set_db_path_mtu(const struct ib_qp_attr *attr,
+ struct roce3_qp *rqp, struct roce3_device *rdev)
+{
+ switch (attr->path_mtu) {
+ case IB_MTU_256:
+ case IB_MTU_512:
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s:Only support mtu larger than 1K.func_id(%d) mtu:%u\n",
+ __func__, rdev->glb_func_id, attr->path_mtu);
+ return -EINVAL;
+ case IB_MTU_1024:
+ rqp->db_path_mtu = BIT_LENGTH_IB_MTU_1024;
+ break;
+ case IB_MTU_2048:
+ rqp->db_path_mtu = BIT_LENGTH_IB_MTU_2048;
+ break;
+ case IB_MTU_4096:
+ rqp->db_path_mtu = BIT_LENGTH_IB_MTU_4096;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce3_set_opt_field(struct roce3_qp *rqp, struct ib_qp_attr *attr, int attr_mask,
+ struct tag_roce_verbs_qp_attr *qp_attr, u32 *optpar)
+{
+ struct roce3_device *rdev = to_roce3_dev(rqp->ibqp.device);
+ int ret = 0;
+
+ 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) {
+ if (rdev->is_vroce) {
+ if (rqp->qp_type == (u32)IB_QPT_RC) {
+ attr->ah_attr.sl = rdev->group_rc_cos;
+ rqp->sl = rdev->group_rc_cos;
+ } else if (rqp->qp_type == (u32)IB_QPT_UD) {
+ attr->ah_attr.sl = rdev->group_ud_cos;
+ rqp->sl = rdev->group_ud_cos;
+ } else {
+ attr->ah_attr.sl = rdev->group_xrc_cos;
+ rqp->sl = rdev->group_xrc_cos;
+ }
+ }
+ roce3_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) {
+ roce3_set_opt_rdmarc(rdev, rqp, qp_attr);
+ *optpar |= ROCE_QP_OPTPAR_RRA_MAX;
+ }
+
+ /* RTR2RTS/SQD2SQD SRA_MAX */
+ if ((((u32)attr_mask) & IB_QP_MAX_QP_RD_ATOMIC) != 0) {
+ roce3_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) {
+ roce3_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 = roce3_set_db_path_mtu(attr, rqp, rdev);
+ if (ret != 0)
+ return ret;
+
+ roce3_set_opt_mtu(qp_attr, attr);
+ }
+
+ roce3_set_opt_field_attr(rqp, attr, attr_mask, qp_attr, optpar);
+ return ret;
+}
+
+static void roce3_set_qp_srq_attr(struct roce3_qp *rqp, struct tag_roce_verbs_qp_attr *qp_attr,
+ struct roce3_pd *pd, const struct roce3_cq *recv_cq)
+{
+ struct roce3_srq *rsrq = to_roce3_srq(rqp->ibqp.srq);
+ struct roce_srq_context temp;
+
+ if (rsrq->container_flag != 0) {
+ struct roce_srq_context *srqc = (struct roce_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 roce3_set_qp_rst2init_attr(struct roce3_qp *rqp,
+ struct tag_roce_verbs_qp_attr *qp_attr, struct roce3_pd *pd, struct roce3_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) {
+ roce3_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->com_info.dw7.bs.rq_cqn_lb = g_rq_cqn_lb;
+ 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 roce3_qp_rst2init_set_qpcc(struct tag_roce_verbs_qp_attr *qp_attr,
+ const struct roce3_qp *rqp, const struct roce3_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->qpc_info->paddr & (~0x3ULL); /* bits:63-2 */
+ }
+
+ 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 roce3_qp_rst2init_set_sqc_sqac(struct tag_roce_verbs_qp_attr *qp_attr,
+ const struct roce3_qp *rqp, const struct roce3_pd *pd, const struct roce3_cq *send_cq)
+{
+#ifdef ROCE_COMPUTE
+ u8 sq_pi_on_chip = (u8)((rqp->qpn <= ROCE_MAX_PI_ON_CHIP_QPN) &&
+ (rqp->qp_type != IB_QPT_UD));
+
+ qp_attr->chip_seg.dw5.bs.sq_pi_on_chip = sq_pi_on_chip;
+#else
+ qp_attr->chip_seg.dw5.bs.sq_pi_on_chip = 0;
+#endif
+ 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->com_info.dw7.bs.sq_cqn_lb = g_sq_cqn_lb;
+ 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 roce3_qp_rst2init_set_drv(struct tag_roce_verbs_qp_attr *qp_attr,
+ struct roce3_qp *rqp, struct roce3_device *rdev)
+{
+ u16 host_oqid = 0;
+ u8 host_id = 0;
+
+ host_id = hinic3_host_id(rdev->hwdev);
+ if (host_id == ROCE_SPU_HOST_ID) {
+ host_id = ROCE_SPU_OQID_HOST_ID;
+ host_oqid = (u16)ROCE_GET_SPU_HOST_OQID(host_id, rdev->glb_func_id, rqp->qpn);
+ } else {
+ host_oqid = (u16)ROCE_GET_HOST_OQID(host_id, rqp->qpn);
+ }
+
+ qp_attr->com_info.dw0.bs.service_type =
+ (u32)to_roce3_qp_type((enum ib_qp_type)rqp->qp_type) & 0x7;
+ if (rdev->is_vroce) {
+ if (qp_attr->com_info.dw0.bs.service_type == ROCE_QP_ST_RC) {
+ qp_attr->path_info.dw7.bs.sl = rdev->group_rc_cos;
+ rqp->sl = rdev->group_rc_cos;
+ } else if (qp_attr->com_info.dw0.bs.service_type == ROCE_QP_ST_UD) {
+ qp_attr->path_info.dw7.bs.sl = rdev->group_ud_cos;
+ rqp->sl = rdev->group_ud_cos;
+ } else {
+ qp_attr->path_info.dw7.bs.sl = rdev->group_xrc_cos;
+ rqp->sl = rdev->group_xrc_cos;
+ }
+ }
+ qp_attr->com_info.dw3.bs.dif_en = (u32)rqp->signature_en;
+ qp_attr->com_info.dw2.bs.vroce_en = (u32)rdev->is_vroce;
+
+ 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;
+ if (rdev->is_vroce)
+ qp_attr->com_info.dw2.bs.host_oqid = (host_oqid & 0xfffc) | ROCE_IPSUTX_CHANNEL_15;
+ else
+ qp_attr->com_info.dw2.bs.host_oqid = host_oqid & 0xffff; /* host_oqid:16bits */
+
+
+ qp_attr->chip_seg.dw4.bs.dsgl = rqp->double_sgl_mode & 0x1;
+ qp_attr->path_info.dw7.bs.udp_src_port = (qp_attr->com_info.dw1.bs.local_qp & 0xff);
+}
+
+static void roce3_qp_rst2init_set_common(struct tag_roce_verbs_qp_attr *qp_attr,
+ const struct roce3_pd *pd)
+{
+ qp_attr->com_info.dw12.bs.ccf_app_id = ROCE_CC_DISABLE; // STUB
+ qp_attr->chip_seg.dw18.bs.ud_pd = pd->pdn & 0x3ffff; /* pd:18bits */
+}
+
+static void roce3_qp_rst2init_set_dcqcn(struct tag_roce_verbs_qp_attr *qp_attr)
+{
+/* ecn ver
+ * b300 nic do not support the func
+ * context->sw_seg.ucode_seg.common.dw1.bs.ecn_ver = rdev->ecn_ctx.ecn_ver & 0xf;
+ */
+}
+
+static void roce3_qp_rst2init_set_fake_vf(const struct roce3_device *rdev,
+ const struct roce3_pd *pd, struct tag_roce_verbs_qp_attr *qp_attr)
+{
+ u32 fake_vf_id = 0;
+ struct roce3_ucontext *roce3_uctx = NULL;
+ u32 db_offset;
+
+ fake_vf_id = ((u32)rdev->glb_func_id) << rdev->cfg_info.pf_start_bit;
+ if (rdev->cfg_info.pf_end_bit < ROCE_VLD_PF_NUM_10)
+ fake_vf_id |= 0x1C00; /* 12 11 10 bit 1 */
+ else if (rdev->cfg_info.pf_end_bit < ROCE_VLD_PF_NUM_11)
+ fake_vf_id |= 0x1800; /* 12 11 bit 1 */
+ else if (rdev->cfg_info.pf_end_bit < ROCE_VLD_PF_NUM_12)
+ fake_vf_id |= 0x1000; /* 12 bit 1 */
+
+ if (pd->ibpd.uobject) {
+ roce3_uctx = to_roce3_ucontext(pd->ibpd.uobject->context);
+ db_offset = (u32)((roce3_uctx->db_dma_addr >> (12UL + rdev->cfg_info.page_bit)) &
+ ((1UL << rdev->cfg_info.pf_start_bit) - 1));
+ qp_attr->com_info.dw11.bs.vf_id = fake_vf_id | db_offset;
+ pr_info("[ROCE] func_id:%u The fake_id:%u ,start:%u end:%u page_bit:%u roce3_uctx->db_dma_addr:%llu\n",
+ rdev->glb_func_id, qp_attr->com_info.dw11.bs.vf_id,
+ rdev->cfg_info.pf_start_bit, rdev->cfg_info.pf_end_bit,
+ rdev->cfg_info.page_bit, roce3_uctx->db_dma_addr);
+ qp_attr->com_info.dw11.bs.fake = 1;
+ } else {
+ pr_info("[ROCE] kernel not support fake_vf currently. func:%u\n",
+ rdev->glb_func_id);
+ }
+}
+
+static void roce3_qp_rst2init_set_xrc_attr(const struct roce3_qp *rqp,
+ const struct ib_qp_attr *attr, struct tag_roce_verbs_qp_attr *qp_attr,
+ const struct roce3_device *rdev, const struct roce3_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 : roce3_qp_rst2init
+ Description : parameter set when QP is from RESET to INIT
+ Input : struct roce3_qp *rqp
+ const struct ib_qp_attr *attr
+ struct tag_roce_verbs_qp_attr *qp_attr
+ Output : None
+
+ 1.Date : 2015/8/6
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_qp_rst2init(struct roce3_qp *rqp, const struct ib_qp_attr *attr,
+ struct tag_roce_verbs_qp_attr *qp_attr)
+{
+ struct roce3_pd *pd = NULL;
+ struct roce3_cq *send_cq = NULL;
+ struct roce3_cq *recv_cq = NULL;
+ struct roce3_device *rdev = NULL;
+
+ rdev = to_roce3_dev(rqp->ibqp.device);
+ pd = roce3_get_pd(rqp);
+ roce3_get_cqs(rqp, &send_cq, &recv_cq);
+
+ /* CHIP_SEG: QPCC */
+ roce3_qp_rst2init_set_qpcc(qp_attr, rqp, rdev);
+
+ /* CHIP_SEG: SQC & SQAC */
+ roce3_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 */
+ roce3_qp_rst2init_set_drv(qp_attr, rqp, rdev);
+
+ /* UCODE COM_SEG */
+ roce3_qp_rst2init_set_common(qp_attr, pd);
+
+ /* EXT DCQCN SEG */
+ roce3_qp_rst2init_set_dcqcn(qp_attr);
+
+ if (rdev->cfg_info.fake_en != 0)
+ roce3_qp_rst2init_set_fake_vf(rdev, pd, qp_attr);
+
+ if (rqp->qp_type == IB_QPT_XRC_TGT)
+ roce3_qp_rst2init_set_xrc_attr(rqp, attr, qp_attr, rdev, recv_cq);
+ else
+ roce3_set_qp_rst2init_attr(rqp, qp_attr, pd, recv_cq);
+
+#ifdef ROCE_BONDING_EN
+ roce3_bond_rr_set_flow(rdev, rqp, qp_attr);
+#endif
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_qp_init2rtr
+ Description : init2rtr attributes modify
+ Input : struct roce3_qp *rqp
+ const struct ib_qp_attr *attr
+ struct tag_roce_verbs_qp_attr *qp_attr
+ Output : None
+
+ 1.Date : 2015/8/1
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_qp_init2rtr(struct roce3_qp *rqp, const struct ib_qp_attr *attr,
+ struct tag_roce_verbs_qp_attr *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_roce3_qp_type((enum ib_qp_type)rqp->qp_type) & 0x7; /* service_type: 3bit */
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_qp_rtr2rts
+ Description : roce3_qp_rtr2rts
+ Input : struct roce3_qp *rqp
+ const struct ib_qp_attr *attr
+ struct tag_roce_verbs_qp_attr *qp_attr
+ Output : None
+
+ 1.Date : 2015/8/2
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_qp_rtr2rts(struct roce3_qp *rqp, const struct ib_qp_attr *attr,
+ struct tag_roce_verbs_qp_attr *qp_attr)
+{
+}
+
+static void roce3_qp_2err(struct roce3_qp *rqp, const struct ib_qp_attr *attr,
+ struct tag_roce_verbs_qp_attr *qp_attr)
+{
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_abs_field
+ Description : set abs field to qpc
+ Input : struct roce3_qp *rqp
+ struct ib_qp_attr *attr
+ struct tag_roce_verbs_qp_attr *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 roce3_set_abs_field(struct roce3_qp *rqp, struct ib_qp_attr *attr, int attr_mask,
+ struct tag_roce_verbs_qp_attr *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))
+ roce3_qp_rst2init(rqp, attr, qp_attr);
+
+ if ((cur_state == IB_QPS_INIT) && (new_state == IB_QPS_RTR))
+ roce3_qp_init2rtr(rqp, attr, qp_attr);
+
+ if ((cur_state == IB_QPS_RTR) && (new_state == IB_QPS_RTS))
+ roce3_qp_rtr2rts(rqp, attr, qp_attr);
+
+ if (new_state == IB_QPS_ERR)
+ roce3_qp_2err(rqp, attr, qp_attr);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_record_opt_field
+ Description : set opt field to roce3_qp after send cmd modify_qp
+ Input : struct roce3_qp *rqp
+ struct ib_qp_attr *attr
+ int attr_mask
+ Output : None
+
+ 1.Date : 2016/01/30
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_record_opt_field(struct roce3_qp *rqp, struct ib_qp_attr *attr, int attr_mask)
+{
+ 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;
+ 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 (roce3_sqp_check(rqp) != 0)
+ store_sqp_attrs(to_roce3_sqp(rqp), attr, attr_mask);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_qp_modify_2rst_cmd
+ Description : cache out qpc mtt
+ Input : struct roce3_device *rdev
+ struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2016/6/17
+ Modification : Created function
+
+ 2.Date : 2017/04/26
+ Modification : Modify function
+
+****************************************************************************
+*/
+int roce3_qp_modify_2rst_cmd(struct roce3_device *rdev, u32 qpn)
+{
+ int ret = 0;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_uni_cmd_qp_modify2rst *qp_moidfy2rst_inbuf = NULL;
+ struct timespec64 tv_start;
+
+ ktime_get_ts64(&tv_start);
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_uni_cmd_qp_modify2rst), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ qp_moidfy2rst_inbuf = (struct tag_roce_uni_cmd_qp_modify2rst *)cqm_cmd_inbuf->buf;
+ qp_moidfy2rst_inbuf->com.index = cpu_to_be32(qpn);
+ if (!roce3_is_roceaa(rdev->cfg_info.scence_id)) {
+ qp_moidfy2rst_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK); //lint !e778
+ } else {
+ qp_moidfy2rst_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_NOFAA_BITMASK); //lint !e778
+ }
+
+ ret = roce3_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_2RST_QP,
+ cqm_cmd_inbuf, NULL, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to send 2RST_QP command, qpn(0x%x), func_id(%d), ret(0x%x)\n",
+ __func__, qpn, rdev->glb_func_id, ret);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA is present(2RST_QP), qpn(0x%x), func_id(%u)\n",
+ __func__, qpn, rdev->glb_func_id);
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ if ((ret == -ETIMEDOUT) || (ret == -EPERM))
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+
+ return -1;
+ }
+ }
+ roce3_timeout_check(rdev, &tv_start, MODIFY_2RST_CMDQ, 0);
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_qp_check_rdmarc
+ Description : roce3_qp_check_rdmarc
+ Input : struct roce3_device *rdev
+ struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2017/04/26
+ Modification : Create function
+
+****************************************************************************
+*/
+static int roce3_qp_check_rdmarc(struct roce3_device *rdev, struct roce3_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 (roce3_hca_is_present(rdev) == 0)
+ return 0;
+
+ 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_UDELAY(US_PERF_DELAY);
+ times--;
+ }
+ } while (times != 0);
+
+ if (rc_num != rc_check_index) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to read rdmarc field back after try %d times, func_id(%d) rc_check_index:%u rc_num:%u\n",
+ __func__, ((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 roce3_qp_check_state(struct roce3_device *rdev,
+ const struct roce3_qp *rqp, const u32 *wb_va, int *cost)
+{
+ int times = 0;
+ int read_back_flag = 0;
+
+ times = rdev->try_times;
+ while ((times--) != 0) {
+ if (roce3_hca_is_present(rdev) == 0)
+ return 0;
+
+ if (*(u32 *)wb_va == ROCE_QP_DESTROY_CHECK_VALUE) {
+ read_back_flag = 1;
+ break;
+ }
+ ROCE_UDELAY(US_PERF_DELAY);
+ }
+
+ if (read_back_flag == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to read QP field back after try %d times,qpn(0x%x), wb_data(0x%x), func_id(%d)\n",
+ __func__, ((rdev->try_times - times) + 1), rqp->qpn,
+ *(u32 *)wb_va, rdev->glb_func_id);
+ *cost = (rdev->try_times - times) + 1;
+ return -1;
+ }
+ *cost = (rdev->try_times - times) + 1;
+ return 0;
+}
+
+static void roce3_qp_fill_cacheout_inbuf(struct roce3_device *rdev,
+ struct roce3_qp *rqp, dma_addr_t wb_dma, struct tag_cqm_cmd_buf *cqm_cmd_inbuf)
+{
+ struct tag_roce_uni_cmd_qp_cache_invalid *qp_cacheout_inbuf = NULL;
+ struct rdma_service_cap *rdma_cap = NULL;
+ u16 host_oqid = 0;
+ u8 host_id = 0;
+
+ host_id = hinic3_host_id(rdev->hwdev);
+ if (host_id == ROCE_SPU_HOST_ID) {
+ host_id = ROCE_SPU_OQID_HOST_ID;
+ host_oqid = (u16)ROCE_GET_SPU_HOST_OQID(host_id, rdev->glb_func_id, rqp->qpn);
+ } else {
+ host_oqid = (u16)ROCE_GET_HOST_OQID(host_id, rqp->qpn);
+ }
+
+ qp_cacheout_inbuf = (struct tag_roce_uni_cmd_qp_cache_invalid *)(cqm_cmd_inbuf)->buf;
+ rdma_cap = &rdev->rdma_cap;
+
+ if (!roce3_is_roceaa(rdev->cfg_info.scence_id)) {
+ qp_cacheout_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK); //lint !e778
+ } else {
+ qp_cacheout_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_NOFAA_BITMASK); //lint !e778
+ }
+
+ 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.dw9.bs.host_oqid = cpu_to_be16(host_oqid);
+ 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 roce3_qp_send_cache_out_cmd(struct roce3_device *rdev,
+ struct roce3_qp *rqp, void *wb_va, dma_addr_t wb_dma, int *cost)
+{
+ unsigned long end;
+ int times = 0;
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_uni_cmd_qp_cache_invalid), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ roce3_qp_fill_cacheout_inbuf(rdev, rqp, wb_dma, cqm_cmd_inbuf);
+
+ end = jiffies + (ROCE_CMDQ_TIMEOUT_10MS * HZ);
+ while (time_before(jiffies, end)) {
+ times++;
+ ret = roce3_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;
+ }
+
+ /*lint -e160 -e522*/
+ cond_resched();
+ /*lint +e160 +e522*/
+ };
+
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed MISC_CACHE_INVLD command after try %d times, ret(%d), func_id(%d) qpn(%d)\n",
+ __func__, times, ret, rdev->glb_func_id, rqp->qpn);
+ /* Card not present need to return OK */
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return ok), QPN(0x%x), ret(%d), func_id(%d)\n",
+ __func__, rqp->qpn, ret, rdev->glb_func_id);
+ goto out;
+ }
+
+ if ((ret == (-ETIMEDOUT)) || (ret == (-EPERM))) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: CMDq timeout, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ *cost = times;
+ return (-EINVAL);
+ }
+
+out:
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ *cost = (rdev->try_times - times) + 1;
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_qp_cache_out_cmd
+ Description : cache out qpc mtt
+ Input : struct roce3_device *rdev
+ struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2016/9/24
+ Modification : Created function
+
+ 2.Date : 2017/04/26
+ Modification : Modify function
+
+****************************************************************************
+*/
+int roce3_qp_cache_out_cmd(struct roce3_device *rdev, struct roce3_qp *rqp)
+{
+ int ret = 0;
+ int cost = 0;
+ void *wb_va = NULL;
+ dma_addr_t wb_dma = 0;
+ struct timespec64 tv_start;
+
+ ktime_get_ts64(&tv_start);
+ wb_va = dma_alloc_coherent(&rdev->pdev->dev, (size_t)4UL, &wb_dma, GFP_KERNEL);
+ if (wb_va == NULL) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc wb_va, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -ENOMEM;
+ }
+ roce3_timeout_check(rdev, &tv_start, CACHE_INVLAID_ALLOC, cost);
+
+ ret = roce3_qp_send_cache_out_cmd(rdev, rqp, wb_va, wb_dma, &cost);
+ if (ret != 0)
+ goto err;
+
+ roce3_timeout_check(rdev, &tv_start, CACHE_INVLAID_CMDQ, cost);
+ if (rqp->rsp_depth > 0) {
+ ret = roce3_qp_check_rdmarc(rdev, rqp, &cost);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to check qp rdmarc, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err;
+ }
+ roce3_timeout_check(rdev, &tv_start, CACHE_INVLAID_RDMARC_CHECK, cost);
+ }
+ ret = roce3_qp_check_state(rdev, rqp, (u32 *)wb_va, &cost);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to check qp state, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err;
+ }
+ roce3_timeout_check(rdev, &tv_start, CACHE_INVLAID_QP_CHECK, cost);
+
+err:
+ dma_free_coherent(&rdev->pdev->dev, sizeof(u32), wb_va, wb_dma);
+
+ return ret;
+}
+
+static u8 roce3_get_qp_cmdq_cmd(struct roce3_device *rdev, struct roce3_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)) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: QP state modify invalid, cur_state(%d), new_state(%d), func_id(%d)\n",
+ __func__, 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 roce3_qp_rts2sqd_cmd(struct roce3_device *rdev, struct roce3_qp *rqp,
+ const struct ib_qp_attr *attr, int attr_mask)
+{
+ int ret = 0;
+ int sqd_event = 0;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_uni_cmd_qp_modify_rts2sqd *qp_rts2sqd_inbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_uni_cmd_qp_modify_rts2sqd), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, 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 = (struct tag_roce_uni_cmd_qp_modify_rts2sqd *)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); //lint !e778
+ qp_rts2sqd_inbuf->sqd_event_en = cpu_to_be32((u32)(sqd_event != 0));
+
+ ret = roce3_send_qp_lb_cmd(rqp->qpn, rdev, ROCE_CMD_RTS2SQD_QP,
+ cqm_cmd_inbuf, NULL, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to send RTS2SQD_QP cmd, func_id(%d), ret(0x%x)\n",
+ __func__, rdev->glb_func_id, ret);
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return -1;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return 0;
+}
+
+static void roce3_qp_fill_modify_inbuf(struct tag_cqm_cmd_buf *cqm_cmd_inbuf, struct roce3_qp *rqp,
+ struct tag_roce_verbs_qp_attr *qp_attr, u32 optpar)
+{
+ struct tag_roce_uni_cmd_modify_qpc *qp_modify_inbuf = NULL;
+
+ qp_modify_inbuf = (struct tag_roce_uni_cmd_modify_qpc *)cqm_cmd_inbuf->buf;
+ roce3_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(VERBS_CMD_TYPE_QP_BITMASK); //lint !e778
+ qp_modify_inbuf->com.opt = cpu_to_be32(optpar);
+
+#ifdef ROCE_VBS_EN
+ if (rqp->vbs_qp_ptr) { // vbs_en, transmit record addr to ucode
+ roce3_vbs_transmit_sqpc_ci_record_addr(rqp, cqm_cmd_inbuf->buf);
+ }
+#endif
+
+}
+
+static int roce3_qp_handle_err(struct roce3_device *rdev, const struct roce3_qp *rqp, int ret)
+{
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to send MODIFY_QP command, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA is present(MODIFY_QP), qpn(0x%x), func_id(%u)\n",
+ __func__, rqp->qpn, rdev->glb_func_id);
+
+ if ((ret == (-ETIMEDOUT)) || (ret == (-EPERM)))
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static int roce3_qp_modify_cmd(struct roce3_device *rdev, struct roce3_qp *rqp, u8 cmd,
+ struct tag_roce_verbs_qp_attr *qp_attr, u32 optpar)
+{
+ int ret = 0;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_uni_cmd_modify_qpc),
+ &cqm_cmd_outbuf, ROCE_QP_MODIFY_CMD_OUT_BUF_SIZE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return (-ENOMEM);
+ }
+
+ if (!roce3_is_roceaa(rdev->cfg_info.scence_id))
+ roce3_qp_fill_modify_inbuf(cqm_cmd_inbuf, rqp, qp_attr, optpar);
+ else
+ roce3_qp_modify_cmd_ext(cqm_cmd_inbuf, rqp, qp_attr, optpar);
+
+ ret = roce3_send_qp_lb_cmd(rqp->qpn, rdev, cmd, cqm_cmd_inbuf,
+ cqm_cmd_outbuf, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0)
+ ret = roce3_qp_handle_err(rdev, rqp, ret);
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+ return ret;
+}
+
+void roce3_cq_clean(struct roce3_cq *cq, u32 qpn, struct roce3_srq *srq)
+{
+ spin_lock_irq(&cq->lock);
+ roce3_cq_clean_process(cq, qpn, srq);
+ spin_unlock_irq(&cq->lock);
+}
+
+static int roce3_qp_clean_kernel_res(struct roce3_qp *rqp)
+{
+ struct roce3_cq *send_cq = NULL;
+ struct roce3_cq *recv_cq = NULL;
+
+ roce3_get_cqs(rqp, &send_cq, &recv_cq);
+
+ roce3_cq_clean(recv_cq, rqp->qpn, rqp->ibqp.srq ? to_roce3_srq(rqp->ibqp.srq) : NULL);
+ if (send_cq != recv_cq)
+ roce3_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->db.db_record) = 0;
+
+ if (rqp->qp_type != IB_QPT_XRC_TGT) {
+ if (rqp->has_rq && rqp->qp_buf_info->q_header_vaddr)
+ memset(rqp->qp_buf_info->q_header_vaddr, 0, sizeof(u64));
+ }
+
+ return 0;
+}
+
+static int roce3_qp_modify_2rst(struct roce3_device *rdev, struct roce3_qp *rqp)
+{
+ int ret = 0;
+
+ ret = roce3_qp_modify_2rst_cmd(rdev, rqp->qpn);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to modify QP(0x%06x) to RESET, func_id(%d)\n",
+ __func__, rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_qp_cache_out_cmd(rdev, rqp);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: QP(0x%06x) cache invalid failed, func_id(%d)\n",
+ __func__, rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+
+ rqp->qp_state = IB_QPS_RESET;
+
+ if (rqp->ibqp.uobject == NULL) {
+ ret = roce3_qp_clean_kernel_res(rqp);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Clean kernel QP(0x%06x) failed, func_id(%d)\n",
+ __func__, rqp->qpn, rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int roce3_qp_modify(struct roce3_device *rdev, struct roce3_qp *rqp,
+ struct ib_qp_attr *attr, int attr_mask)
+{
+ int ret = 0;
+ u32 optpar = 0;
+ struct tag_roce_verbs_qp_attr qp_attr;
+ u8 cmd = 0;
+
+ memset(&qp_attr, 0, sizeof(qp_attr));
+
+ if ((((u32)attr_mask) & IB_QP_MAX_DEST_RD_ATOMIC) != 0) {
+ ret = roce3_alloc_opt_rdmarc(rqp, attr, attr_mask);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc rdmarc, func(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ ret = roce3_set_opt_field(rqp, attr, attr_mask, &qp_attr, &optpar);
+ if (ret != 0)
+ goto err_out;
+
+ roce3_set_abs_field(rqp, attr, attr_mask, &qp_attr);
+
+ cmd = roce3_get_qp_cmdq_cmd(rdev, rqp, attr, attr_mask);
+ if (cmd == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Invalid cmd, func_id(%d), qpn(%d), cmd(%d)\n",
+ __func__, rdev->glb_func_id, rqp->qpn, cmd);
+ ret = (-EINVAL);
+ goto err_out;
+ }
+ if (cmd == ROCE_CMD_RTS2SQD_QP)
+ ret = roce3_qp_rts2sqd_cmd(rdev, rqp, attr, attr_mask);
+ else
+ ret = roce3_qp_modify_cmd(rdev, rqp, cmd, &qp_attr, optpar);
+
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to send modify cmd(%d), func(%d), qpn(%d), ret(%d)\n",
+ __func__, cmd, rdev->glb_func_id, rqp->qpn, ret);
+ goto err_out;
+ }
+
+ roce3_record_opt_field(rqp, attr, attr_mask);
+ return 0;
+
+err_out:
+ if ((((u32)attr_mask) & IB_QP_MAX_DEST_RD_ATOMIC) != 0)
+ roce3_free_opt_rdmarc(rqp);
+
+ return ret;
+}
+
+static int roce3_qp_get_path(struct roce3_device *rdev, struct roce3_qp *rqp,
+ struct rdma_ah_attr *ah_attr)
+{
+ return 0;
+}
+
+static int roce3_qp_modify_check_rd_and_mtu(const struct roce3_qp *rqp,
+ const struct ib_qp_attr *attr, int attr_mask, const struct rdma_service_cap *rdma_cap)
+{
+ 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);
+
+ 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)) {
+ pr_err(
+ "[ROCE, ERR] %s: Qpn(0x%x), max_rd_atomic (%d) too large. Transition %d to %d. qp_type(%d)\n",
+ __func__, 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)) {
+ pr_err("[ROCE, ERR] %s: Qpn(0x%x), max_dest_rd_atomic (%d) too large. Transition %d to %d. qp_type(%d)\n",
+ __func__, 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) &&
+ ((attr->path_mtu < IB_MTU_256) || (attr->path_mtu > IB_MTU_4096))) {
+ pr_err("[ROCE, ERR] %s: Input path MTU(%u) is invalid\n", __func__, attr->path_mtu);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce3_qp_modify_check(struct roce3_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);
+
+ if (!roce3_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)) {
+ pr_err(
+ "[ROCE, ERR] %s: Qpn(0x%x), invalid attribute mask specified for transition %d to %d, qp_type(%d), attr_mask(0x%x)\n",
+ __func__, rqp->ibqp.qp_num, cur_state, new_state,
+ rqp->ibqp.qp_type, attr_mask);
+ return (-EINVAL);
+ }
+
+ if (((((u32)attr_mask) & IB_QP_PORT) != 0) && (attr->port_num != ROCE_DEFAULT_PORT_NUM)) {
+ pr_err("[ROCE, ERR] %s: Qpn(0x%x), invalid port number(%d) specified for transition %d to %d. qp_type(%d)\n",
+ __func__, 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) {
+ pr_err(
+ "[ROCE, ERR] %s: Qpn(0x%x), invalid pkey index (%d) specified for transition %d to %d. qp_type(%d)\n",
+ __func__, rqp->ibqp.qp_num, attr->pkey_index, cur_state,
+ new_state, rqp->ibqp.qp_type);
+ return (-EINVAL);
+ }
+ }
+
+ ret = roce3_qp_modify_check_rd_and_mtu(rqp, attr, attr_mask, rdma_cap);
+
+ return ret;
+}
+
+#define ROCE3_QP_HANDLE 0
+#define ROCE3_QP_CONTINUE 1
+static int roce3_modify_qp_pre(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ int ret;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_device *rdev = NULL;
+ enum ib_qp_state cur_state, new_state;
+
+ rqp = to_roce3_qp(ibqp);
+ rdev = to_roce3_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 = roce3_qp_modify_check(rqp, attr, attr_mask, &rdev->rdma_cap);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed qp modify check, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ if (new_state == IB_QPS_RESET) {
+ if (cur_state != new_state) {
+ ret = roce3_qp_modify_2rst(rdev, rqp);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to modify 2rst, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ }
+ }
+ return ROCE3_QP_HANDLE;
+ }
+
+ ret = roce3_qp_modify_pre_extend(rqp, attr, attr_mask, udata);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to modify extend qp, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ return ROCE3_QP_CONTINUE;
+}
+
+int roce3_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ int ret = 0;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_device *rdev = NULL;
+
+ rqp = to_roce3_qp(ibqp);
+ rdev = to_roce3_dev(ibqp->device);
+
+ mutex_lock(&rqp->mutex);
+
+ ret = roce3_modify_qp_pre(ibqp, attr, attr_mask, udata);
+ if ((ret == ROCE3_QP_HANDLE) || (ret < 0))
+ goto out;
+
+ if ((((u32)attr_mask) & IB_QP_AV) != 0) {
+ ret = roce3_qp_get_path(rdev, rqp, &attr->ah_attr);
+ if (ret != 0)
+ goto out;
+ }
+
+ ret = roce3_qp_modify(rdev, rqp, attr, attr_mask);
+ if (ret != 0)
+ goto out;
+
+out:
+ mutex_unlock(&rqp->mutex);
+ return ret;
+}
+
+int roce3_send_qp_lb_cmd(u32 qpn, struct roce3_device *rdev, u8 cmd,
+ struct tag_cqm_cmd_buf *buf_in, struct tag_cqm_cmd_buf *buf_out, u32 timeout)
+{
+ int ret = 0;
+ struct timespec64 tv_start;
+
+ ktime_get_ts64(&tv_start);
+ if ((rdev->cfg_info.lb_en != 0) && (rdev->cfg_info.lb_mode == ROCE_LB_MODE_1)) {
+ u8 cos = qpn & 0x3;
+
+ ret = cqm_lb_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, cmd, cos,
+ buf_in, buf_out, NULL, timeout, HINIC3_CHANNEL_ROCE);
+ } else {
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, cmd, buf_in,
+ buf_out, NULL, timeout, HINIC3_CHANNEL_ROCE);
+ }
+
+ roce3_timeout_check(rdev, &tv_start, CMDQ_SDKCALL_BUTT, 0);
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce3/qp/roce_qp_post_recv.c b/drivers/infiniband/hw/hiroce3/qp/roce_qp_post_recv.c
new file mode 100644
index 0000000000000..d449da4d25d01
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/qp/roce_qp_post_recv.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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"
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+
+/*
+ ****************************************************************************
+ Prototype : roce3_get_recv_wqe
+ Description : roce3_get_recv_wqe
+ Input : struct roce3_qp *rqp
+ int n
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+static void *roce3_get_recv_wqe(struct roce3_qp *rqp, u32 n)
+{
+ return roce3_get_wqe(rqp, rqp->rq.offset + (n << (unsigned int)rqp->rq.wqe_shift));
+}
+
+static int roce3_post_recv_check_qp(const struct roce3_qp *qp, const struct roce3_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))) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Can't post WQE when TGT XRC QP, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+
+ if (ROCE_UNLIKELY(qp->qp_state == IB_QPS_RESET)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Can't post WQE when QP is RST state, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int roce3_post_recv_check_wr(struct roce3_qp *qp, const struct ib_recv_wr **bad_wr,
+ const struct ib_recv_wr *wr, u32 wr_num)
+{
+ if (roce3_wq_overflow(&qp->rq, wr_num, qp->ibqp.recv_cq) != 0) {
+ /*lint -e160 -e522*/
+ pr_err_once("[ROCE, ERR] %s: SQ is full head:%x, tali:%x, wr_num:%d\n",
+ __func__, (&qp->rq)->head, (&qp->rq)->tail, wr_num);
+ /*lint +e160 +e522*/
+ *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 roce3_post_recv_check_length(struct roce3_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;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Sge data len is over range, sg_list(%d), length(0x%x), max_msg_sz(0x%x), func_id(%d)\n",
+ __func__, 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;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Data_len is over range, data_len(%d), max_msg_sz(%d), func_id(%d)\n",
+ __func__, data_len, rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_msg_sz,
+ rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce3_post_recv_set_data_seg(const struct ib_recv_wr *wr, struct roce3_device *rdev,
+ const struct ib_recv_wr **bad_wr, struct roce3_qp *qp, u32 index)
+{
+ int i = 0;
+ int ret = 0;
+ struct roce3_wqe_data_seg *dseg = NULL;
+
+ dseg = (struct roce3_wqe_data_seg *)roce3_get_recv_wqe(qp, index);
+ for (i = 0; i < wr->num_sge; ++i) {
+ ret = roce3_post_recv_check_length(rdev, bad_wr, wr, i);
+ if (ret != 0)
+ return ret;
+
+ roce3_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 : roce3_post_recv
+ Description : roce3_post_recv
+ Input : struct ib_qp *ibqp
+ struct ib_recv_wr *wr
+ struct ib_recv_wr **bad_wr
+ Output : None
+ Return Value :
+ Calls :
+ Called By :
+
+ History :
+ 1.Date : 2015/4/29
+ Author :
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr)
+{
+ struct roce3_qp *qp = to_roce3_qp(ibqp);
+
+ struct roce3_device *rdev = to_roce3_dev(ibqp->device);
+ unsigned long flags = 0;
+ int ret = 0;
+ u32 wr_num = 0;
+ u32 index = 0;
+ const struct ib_recv_wr *wr_tmp = wr;
+
+ ret = roce3_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 = roce3_post_recv_check_wr(qp, bad_wr, wr_tmp, wr_num);
+ if (ret != 0)
+ goto out;
+
+ ret = roce3_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(); /* Memory barrier before write db */
+
+ /* 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;
+}
+
+void roce3_drain_rq(struct ib_qp *ibqp)
+{
+
+}
diff --git a/drivers/infiniband/hw/hiroce3/qp/roce_qp_post_send.c b/drivers/infiniband/hw/hiroce3/qp/roce_qp_post_send.c
new file mode 100644
index 0000000000000..2e4f2ee0d3f3f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/qp/roce_qp_post_send.c
@@ -0,0 +1,1315 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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_dif_format.h"
+#include "roce_main_extension.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 : roce3_get_send_wqe
+ Description : roce3_get_send_wqe
+ Input : struct roce3_qp *rqp
+ u32 n
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+static void *roce3_get_send_wqe(struct roce3_qp *rqp, u32 n)
+{
+ u32 wqebb_index = (n & (((u32)rqp->sq.wqebb_cnt) - 1));
+ u32 wqebb_pos = wqebb_index << rqp->sq.wqe_shift;
+
+ return roce3_get_wqe(rqp, rqp->sq.offset + wqebb_pos);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_wq_overflow
+ Description : roce3_wq_overflow
+ Input : struct roce3_wq *wq
+ int wr_num
+ struct ib_cq *ibcq
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_wq_overflow(struct roce3_wq *wq, u32 wr_num, struct ib_cq *ibcq)
+{
+ unsigned int cur = 0;
+ struct roce3_cq *cq = NULL;
+
+ cur = wq->head - wq->tail;
+ if (ROCE_LIKELY((cur + wr_num) < (unsigned int)wq->max_post))
+ return 0;
+
+ cq = to_roce3_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 : roce3_ib_opcode
+ Description :
+ Input :
+ Output : None
+ Return Value :
+ Calls :
+ Called By :
+
+ History :
+ 1.Date : 2015/7/30
+ Author :
+ Modification : Created function
+
+****************************************************************************
+*/
+static const u32 roce3_ib_opcode[] = {
+ ROCE_WQE_OPCODE_RDMA_WRITE, /* [IB_WR_RDMA_WRITE] : 0 */
+ ROCE_WQE_OPCODE_RDMA_WRITE_IMM, /* [IB_WR_RDMA_WRITE_WITH_IMM] : 1 */
+ ROCE_WQE_OPCODE_SEND, /* [IB_WR_SEND] : 2 */
+ ROCE_WQE_OPCODE_SEND_IMM, /* [IB_WR_SEND_WITH_IMM] : 3 */
+ ROCE_WQE_OPCODE_RDMA_READ, /* [IB_WR_RDMA_READ] : 4 */
+ ROCE_WQE_OPCODE_ATOMIC_CMP_SWP, /* [IB_WR_ATOMIC_CMP_AND_SWP] : 5 */
+ ROCE_WQE_OPCODE_ATOMIC_FETCH_ADD, /* [IB_WR_ATOMIC_FETCH_AND_ADD] : 6 */
+ 0, /* [IB_WR_LSO] : 7 NO SUPPORT */
+ ROCE_WQE_OPCODE_SEND_INVAL, /* [IB_WR_SEND_WITH_INV] : 8 */
+ 0, /* [IB_WR_RDMA_READ_WITH_INV] : 9 */
+ ROCE_WQE_OPCODE_LOCAL_INVAL, /* [IB_WR_LOCAL_INV] : 10 */
+ ROCE_WQE_OPCODE_FRMR, /* [IB_WR_REG_MR] : 11 */
+ ROCE_WQE_OPCODE_MASKED_ATOMIC_CMP_SWP, /* [IBV_EXP_WR_EXT_MASKED_ATOMIC_CMP_AND_SWP] : 12 */
+ /* [IBV_EXP_WR_EXT_MASKED_ATOMIC_FETCH_AND_ADD] : 13 */
+ ROCE_WQE_OPCODE_MASKED_ATOMIC_FETCH_ADD,
+ ROCE_WQE_OPCODE_REG_SIG_MR, /* [IB_WR_REG_SIG_MR] : 14 */
+
+ /* 15-64 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, /* IBV_EXP_WR_SEND_ENABLE 96 */
+ 0, /* IBV_EXP_WR_RECV_ENABLE 97 */
+ 0, /* IBV_EXP_WR_CQE_WAIT 98 */
+
+ /* ex */
+ ROCE_WQE_OPCODE_FRMR, /* [IB_WR_FAST_REG_MR] : 11 */
+};
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_send_seg
+ Description : roce3_set_send_seg
+ Input : struct roce3_wqe_snd_tsk_seg *snd_tsk_seg
+ struct ib_send_wr *wr
+ Output : None
+
+ 1.Date : 2017/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_set_send_seg(struct roce3_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);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_atomic_seg
+ Description : roce3_set_atomic_seg
+ Input : struct roce3_wqe_atomic_tsk_seg *atomic_tsk_seg
+ struct ib_send_wr *wr
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+
+static void roce3_set_atomic_seg(struct roce3_wqe_atomic_tsk_seg *atomic_tsk_seg,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_atomic_wr *atomic = ROCE_ATOMIC_WR(wr);
+
+ atomic_tsk_seg->key = cpu_to_be32(atomic->rkey);
+ atomic_tsk_seg->va = cpu_to_be64(atomic->remote_addr);
+
+ if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+ atomic_tsk_seg->swap_add_data = cpu_to_be64(atomic->swap);
+ atomic_tsk_seg->cmp_data = cpu_to_be64(atomic->compare_add);
+ } else if (wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
+ atomic_tsk_seg->swap_add_data = cpu_to_be64(atomic->compare_add);
+ atomic_tsk_seg->cmp_data = 0;
+ } else {
+ /* IB_WR_MASKED_ATOMIC_FETCH_AND_ADD */
+ atomic_tsk_seg->swap_add_data = cpu_to_be64(atomic->compare_add);
+ atomic_tsk_seg->cmp_data = cpu_to_be64(atomic->compare_add_mask);
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_masked_atomic_seg
+ Description : roce3_set_masked_atomic_seg
+ Input : struct roce3_wqe_mask_atomic_tsk_seg *mask_atomic_tsk_seg
+ struct ib_send_wr *wr
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_set_masked_atomic_seg(struct roce3_wqe_mask_atomic_tsk_seg *mask_atomic_tsk_seg,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_atomic_wr *atomic = ROCE_ATOMIC_WR(wr);
+
+ mask_atomic_tsk_seg->rkey = cpu_to_be32(atomic->rkey);
+ mask_atomic_tsk_seg->va = cpu_to_be64(atomic->remote_addr);
+
+ mask_atomic_tsk_seg->swap_add_data = cpu_to_be64(atomic->swap);
+ mask_atomic_tsk_seg->swap_msk = cpu_to_be64(atomic->swap_mask);
+ mask_atomic_tsk_seg->cmp_data = cpu_to_be64(atomic->compare_add);
+ mask_atomic_tsk_seg->cmp_msk = cpu_to_be64(atomic->compare_add_mask);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_rdma_seg
+ Description : roce3_set_rdma_seg
+ Input : struct roce3_wqe_rdma_tsk_seg *rdma_tsk_seg
+ struct ib_send_wr *wr
+ Output : None
+ Return Value :
+ Calls :
+ Called By :
+
+ History :
+ 1.Date : 2015/5/26
+ Author :
+ Modification : Created function
+
+****************************************************************************
+*/
+static __always_inline void roce3_set_rdma_seg(struct roce3_wqe_rdma_tsk_seg *rdma_tsk_seg,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_rdma_wr *rdma = ROCE_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 = wr->ex.imm_data;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_local_inv_seg
+ Description : roce3_set_local_inv_seg
+ Input : struct roce3_wqe_local_inv_tsk_seg *inv_tsk_seg
+ struct ib_send_wr *wr
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_set_local_inv_seg(struct roce3_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);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_ud_seg_cycle1
+ Description : set ud type task segment before cycled
+ Input : struct roce3_wqe_ud_tsk_seg_cycle1 *ud_tsk_seg_cycle1
+ struct ib_send_wr *wr
+ Output : None
+
+ 1.Date : 2015/8/8
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_set_ud_seg_cycle1(struct roce3_wqe_ud_tsk_seg_cycle1 *ud_tsk_seg_cycle1,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_ud_wr *ud = ROCE_UD_WR(wr);
+ struct roce3_ah *rah = to_roce3_ah(ud->ah);
+
+ 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;
+ memcpy((void *)ud_tsk_seg_cycle1->dgid, (void *)rah->priv_ah.dgid, ROCE_GID_LEN);
+ ud_tsk_seg_cycle1->dw9.value = cpu_to_be32(ud->remote_qpn);
+ ud_tsk_seg_cycle1->qkey = cpu_to_be32(ud->remote_qkey);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_ud_seg_cycle2
+ Description : set ud type task segment after cycled
+ Input : struct roce3_wqe_ud_tsk_seg_cycle2 *ud_tsk_seg_cycle2
+ struct ib_send_wr *wr
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_set_ud_seg_cycle2(struct roce3_wqe_ud_tsk_seg_cycle2 *ud_tsk_seg_cycle2,
+ const struct ib_send_wr *wr)
+{
+ const struct ib_ud_wr *ud = ROCE_UD_WR(wr);
+ struct roce3_ah *rah = to_roce3_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;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_ud_seg
+ Description : roce3_set_ud_seg
+ Input : struct roce3_wqe_ud_tsk_seg *ud_tsk_seg
+ struct ib_send_wr *wr
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_set_ud_seg(struct roce3_wqe_ud_tsk_seg *ud_tsk_seg, const struct ib_send_wr *wr)
+{
+ const struct ib_ud_wr *ud = ROCE_UD_WR(wr);
+ struct roce3_ah *rah = to_roce3_ah(ud->ah);
+
+ 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;
+ memcpy((void *)ud_tsk_seg->dgid, (void *)rah->priv_ah.dgid,
+ sizeof(ud_tsk_seg->dgid));
+ 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;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_data_seg
+ Description : roce3_set_data_seg
+ Input : struct roce3_wqe_data_seg *dseg
+ struct ib_sge *sge
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_set_data_seg(struct roce3_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);
+}
+
+static void roce3_set_dwqe_db(struct roce3_qp *qp, struct roce3_wqe_ctrl_seg *ctrl_seg,
+ unsigned int index)
+{
+ struct roce3_device *rdev = to_roce3_dev(qp->ibqp.device);
+
+ ctrl_seg->dw2.bs.qpn = qp->qpn & 0xfffff;
+ ctrl_seg->dw2.bs.ctx_size = 1; /* 512B */
+ ctrl_seg->dw2.bs.cp_flag = 0;
+ ctrl_seg->dw2.bs.cos = roce3_get_db_cos_from_vlan_pri(rdev, qp->sl & 0x7);
+ ctrl_seg->dw2.bs.type = ROCE_SQ_DB_TYPE;
+
+ ctrl_seg->dw3.bs.pi = index & 0xffff;
+ ctrl_seg->dw3.bs.sub_type = 0;
+
+ ctrl_seg->dw3.bs.mtu_shift = qp->db_path_mtu;
+ ctrl_seg->dw3.bs.sgid_index = qp->db_sgid_index;
+ if (qp->qp_type == IB_QPT_RC) {
+ // ctrl_seg->dw3.bs.rc_flag = 1;
+ } else if (qp->qp_type == IB_QPT_UD) {
+ // ctrl_seg->dw3.bs.ud_vld = 1;
+ ctrl_seg->dw3.bs.mtu_shift = 3;
+ } else if (qp->qp_type == IB_QPT_XRC_INI || qp->qp_type == IB_QPT_XRC_TGT) {
+ ctrl_seg->dw3.bs.xrc_vld = 1;
+ // ctrl_seg->dw3.bs.rc_flag = 1;
+ }
+ // ctrl_seg->dw3.bs.local_trans = 0;
+
+ ctrl_seg->dw1.value = cpu_to_be32(ctrl_seg->dw1.value);
+ ctrl_seg->dw2.value = cpu_to_be32(ctrl_seg->dw2.value);
+ ctrl_seg->dw3.value = cpu_to_be32(ctrl_seg->dw3.value);
+}
+
+static void roce3_set_sq_db(struct roce3_qp *qp, struct roce_sq_db_seg *db, unsigned int index)
+{
+ struct roce3_device *rdev = to_roce3_dev(qp->ibqp.device);
+
+ db->dw0.bs.qpn = qp->qpn & 0xfffff;
+ db->dw0.bs.ctx_size = 1; /* 512B */
+ db->dw0.bs.cp_flag = 0;
+ db->dw0.bs.cos = roce3_get_db_cos_from_vlan_pri(rdev, qp->sl & 0x7);
+ db->dw0.bs.type = ROCE_SQ_DB_TYPE;
+
+ db->dw1.bs.pi = ((index & 0xffff) >> 8) & 0xff; /* 8bits */
+ db->dw1.bs.sub_type = 0;
+ db->dw1.bs.mtu_shift = qp->db_path_mtu;
+ db->dw1.bs.sgid_index = qp->db_sgid_index;
+ if (qp->qp_type != IB_QPT_RC) {
+ if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI)
+ db->dw1.bs.mtu_shift = ROCE_UD_MTU_SHIFT;
+ else if (qp->qp_type == IB_QPT_XRC_INI || qp->qp_type == IB_QPT_XRC_TGT)
+ db->dw1.bs.xrc_vld = 1;
+ }
+
+ db->dw0.value = roce3_convert_be32(db->dw0.value);
+ db->dw1.value = roce3_convert_be32(db->dw1.value);
+}
+
+static void roce3_set_inline_data(void *start_addr, struct ib_sge *sge)
+{
+ memcpy(start_addr, (void *)(uintptr_t)sge->addr, sge->length);
+}
+
+static void roce3_set_inline_data_cycle1(void *start_addr, struct ib_sge *sge, u32 size)
+{
+ memcpy(start_addr, (void *)(uintptr_t)sge->addr, size);
+}
+
+static void roce3_set_inline_data_cycle2(void *start_addr, struct ib_sge *sge, u32 size)
+{
+ memcpy(start_addr, (void *)((u8 *)(void *)(uintptr_t)sge->addr + size), size);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_dwqe_copy
+ Description : roce3_dwqe_copy
+ Input : unsigned long *dst
+ unsigned long *src
+ unsigned int bytecnt
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+/*
+ * Avoid using memcpy() to copy to DWQE Page, since memcpy()
+ * implementations may use move-string-buffer assembler instructions,
+ * which do not guarantee order of copying.
+ * Assume that the DWQE page header address is VA, the WQE size is size, and the WQE address is wqe
+ size=64, iowrite64_copy(va + 256, wqe, size)
+ size=128, iowrite64_copy(va + 256*2, wqe, size)
+ size=192, iowrite64_copy(va + 256*3, wqe, size)
+ The current chip supports this function, but the software wqe_size is aligned by
+ the power of 2. Therefore, this function is not used and can be ignored.
+ size=256, __iowrite64_copy(va, wqe, size)
+
+ formula:
+ __iowrite64_copy(va + ((size & 255) << 2), wqe, size)
+ */
+static void roce3_dwqe_copy(unsigned long *dst, unsigned long *src, unsigned int bytecnt)
+{
+ unsigned long *src_tmp = src;
+ unsigned int bytecnt_tmp = bytecnt;
+ unsigned long *dst_tmp = (unsigned long *)(
+ (u64)dst + ((bytecnt_tmp & BYTE_MASK) << 2)); // 2 is addr offset
+
+ while ((int)bytecnt_tmp > 0) {
+ wmb(); /* Sequential write memory barrier */
+ *dst_tmp++ = *src_tmp++;
+ bytecnt_tmp -= (unsigned int)sizeof(u64);
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_set_gsi_seg
+ Input : struct roce3_sqp *sqp
+ struct ib_send_wr *wr
+ void *wqe
+ Output : None
+
+ 1.Date : 2015/8/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_set_gsi_seg(struct roce3_sqp *sqp, const struct ib_send_wr *wr, void *wqe)
+{
+ struct roce3_wqe_ud_tsk_seg *ud_tsk_seg = (struct roce3_wqe_ud_tsk_seg *)wqe;
+ struct ib_ud_wr *ud_wr = (struct ib_ud_wr *)(void *)wr;
+ struct roce3_ah *rah = to_roce3_ah(ud_wr->ah);
+
+ 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;
+ memcpy((void *)ud_tsk_seg->dgid, (void *)rah->priv_ah.dgid,
+ sizeof(ud_tsk_seg->dgid));
+ 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) ?
+ sqp->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;
+}
+
+/*
+ ****************************************************************************
+ Prototype : write_invalid_wqe
+ Description : set the next wqe invalidate
+ Input : struct roce3_qp *qp
+ u32 index
+ Output : None
+
+ 1.Date : 2015/9/8
+ Modification : Created function
+
+****************************************************************************
+*/
+static void write_invalid_wqe(struct roce3_qp *qp, u32 index)
+{
+ u32 invalid_wqe_dw0 = 0;
+ struct roce3_wqe_ctrl_seg *ctrl_seg = NULL;
+
+ ctrl_seg = (struct roce3_wqe_ctrl_seg *)roce3_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);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_validate_wr
+ Description : roce3_validate_wr
+ Input : struct roce3_qp *rqp
+ struct ib_send_wr *wr
+ int wr_num
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_validate_wr(struct roce3_qp *rqp, const struct ib_send_wr *wr, u32 wr_num)
+{
+#define IB_WR_REG_SIG_MR IB_WR_REG_MR_INTEGRITY
+ if (roce3_wq_overflow(&rqp->sq, wr_num, rqp->ibqp.send_cq) != 0) {
+ pr_err("[ROCE] %s: SQ is full\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (ROCE_UNLIKELY(((u32)wr->num_sge) > rqp->sq.max_sge)) {
+ pr_err("[ROCE, ERR] %s: Sge num is invalid, wr->num_sge(%d), rqp->sq.max_sge(%d)\n",
+ __func__, wr->num_sge, rqp->sq.max_sge);
+ return -EINVAL;
+ }
+
+ if (ROCE_UNLIKELY((wr->opcode == IB_WR_LSO) || (wr->opcode > IB_WR_REG_SIG_MR))) {
+ pr_err("[ROCE, ERR] %s: wr->opcode(%d)\n", __func__, wr->opcode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void roce3_set_rc_wqe_for_optype_send(const struct ib_send_wr *wr,
+ struct roce3_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;
+ roce3_set_send_seg((struct roce3_wqe_send_tsk_seg *)param->wqe, wr);
+ param->data_len_addr = &((struct roce3_wqe_send_tsk_seg *)param->wqe)->data_len;
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce3_wqe_send_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce3_wqe_send_tsk_seg);
+}
+
+static void roce3_set_rc_wqe_for_optype_atomic(const struct ib_send_wr *wr,
+ struct roce3_post_send_normal_param *param)
+{
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_RDMA_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ roce3_set_atomic_seg((struct roce3_wqe_atomic_tsk_seg *)param->wqe, wr);
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce3_wqe_atomic_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce3_wqe_atomic_tsk_seg);
+}
+
+static void roce3_set_rc_wqe_for_optype_cmp_and_swap(const struct ib_send_wr *wr,
+ struct roce3_post_send_normal_param *param)
+{
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_ATOMIC_CWP_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ roce3_set_masked_atomic_seg((struct roce3_wqe_mask_atomic_tsk_seg *)param->wqe, wr);
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce3_wqe_mask_atomic_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce3_wqe_atomic_tsk_seg);
+}
+
+static void roce3_set_rc_wqe_for_optype_write(const struct ib_send_wr *wr,
+ struct roce3_post_send_normal_param *param)
+{
+ param->ctrl_seg_tmp.dw0.bs.tsl = ROCE_RDMA_WQE_TSL;
+ param->ctrl_seg_tmp.dw1.bs.cl = 1;
+ roce3_set_rdma_seg((struct roce3_wqe_rdma_tsk_seg *)param->wqe, wr);
+ param->data_len_addr = &((struct roce3_wqe_rdma_tsk_seg *)param->wqe)->data_len;
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce3_wqe_rdma_tsk_seg));
+ param->wqe_size += (u32)(sizeof(struct roce3_wqe_rdma_tsk_seg));
+}
+
+static void roce3_set_rc_wqe_for_optype_local(const struct ib_send_wr *wr,
+ struct roce3_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;
+ roce3_set_local_inv_seg((struct roce3_wqe_local_inv_tsk_seg *)param->wqe, wr);
+ param->wqe_size += (u32)sizeof(struct roce3_wqe_local_inv_tsk_seg);
+ param->inline_flag = 0;
+ param->ctrl_seg_tmp.dw0.bs.df = 0;
+}
+
+static void roce3_set_wqe_last_len(u8 *wqe)
+{
+ struct roce3_wqe_send_tsk_seg *snd_task = (struct roce3_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 roce3_log2(u32 x)
+{
+ u32 shift;
+
+ for (shift = 0; (1U << shift) < x; ++shift)
+ ;
+
+ return shift;
+}
+
+static int set_frmr_wqe_section(const struct ib_send_wr *wr,
+ struct roce3_post_send_normal_param *param)
+{
+ u64 iova;
+ u32 fbo;
+ u32 page_num;
+ struct ib_reg_wr *frmr_reg_wr = NULL;
+ struct roce3_mr *roce3_kernel_frmr = NULL;
+ struct roce3_wqe_frmr_tsk_seg *frmr_wqe_task = NULL;
+
+ frmr_reg_wr = (struct ib_reg_wr *)reg_wr(wr); //lint !e605
+
+ roce3_kernel_frmr = to_roce3_mr(frmr_reg_wr->mr);
+ page_num = (u32)((frmr_reg_wr->mr->length +
+ frmr_reg_wr->mr->page_size - 1) / frmr_reg_wr->mr->page_size);
+ if (page_num > ROCE_FRMR_MAX_PAGES)
+ return -EINVAL;
+
+ /* base section set */
+ param->wqe_size += sizeof(struct roce3_wqe_frmr_tsk_seg);
+
+ frmr_wqe_task = (struct roce3_wqe_frmr_tsk_seg *)((void *)param->tsk_com_seg);
+
+ param->dseg = (struct roce3_wqe_data_seg *)
+ (((u8 *)param->tsk_com_seg) + sizeof(struct roce3_wqe_frmr_tsk_seg));
+
+ param->ctrl_seg_tmp.dw0.bs.tsl =
+ sizeof(struct roce3_wqe_frmr_tsk_seg) / ROCE_TASK_SEG_ALIGN;
+ /* fill wqe ctrl head section:cl bit */
+ param->ctrl_seg_tmp.dw1.bs.cl = 1; //lint !e572 !e778 !e845
+
+ /* local invalidate associated section set */
+ param->tsk_com_seg->bs.so = 1;
+
+ iova = (u64)(void *)(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 : cpu_to_be64(iova);
+
+ /* 填写访问权限 */
+ frmr_wqe_task->dw3.bs.zbva = (u32)(!!((u32)frmr_reg_wr->access & IB_ZERO_BASED));
+ /* 绑定操作使能 */
+ frmr_wqe_task->dw3.bs.be = (u32)(!!((u32)frmr_reg_wr->access & IB_ACCESS_MW_BIND));
+ /* 本地读使能 */
+ frmr_wqe_task->dw3.bs.lre = 1;
+ /* 本地写使能 */
+ frmr_wqe_task->dw3.bs.lwe = (u32)(!!((u32)frmr_reg_wr->access & IB_ACCESS_LOCAL_WRITE));
+ /* 远端读使能 */
+ frmr_wqe_task->dw3.bs.rre = (u32)(!!((u32)frmr_reg_wr->access & IB_ACCESS_REMOTE_READ));
+ /* 远端写使能 */
+ frmr_wqe_task->dw3.bs.rwe = (u32)(!!((u32)frmr_reg_wr->access & IB_ACCESS_REMOTE_WRITE));
+ /* 远端Atomic使能 */
+ frmr_wqe_task->dw3.bs.rae = (u32)(!!((u32)frmr_reg_wr->access & IB_ACCESS_REMOTE_ATOMIC));
+ frmr_wqe_task->dw3.bs.block = 1;
+ frmr_wqe_task->dw3.bs.rsvd = 0;
+ frmr_wqe_task->dw3.bs.pa_num = page_num;
+ /* MR内存页大小。equals to (2^page_size)*4KB */
+ frmr_wqe_task->dw3.bs.page_size = roce3_log2(frmr_reg_wr->mr->page_size) - PAGE_4K_SHIFT;
+ 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(roce3_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 roce3_post_send_rc(struct roce3_post_send_normal_param *param, struct roce3_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:
+ roce3_set_wqe_last_len(param->wqe);
+ roce3_set_rc_wqe_for_optype_send(wr, param);
+ break;
+ case IB_WR_SEND:
+ roce3_set_rc_wqe_for_optype_send(wr, param);
+ break;
+
+ case IB_WR_ATOMIC_CMP_AND_SWP:
+ case IB_WR_ATOMIC_FETCH_AND_ADD:
+ case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD:
+ roce3_set_rc_wqe_for_optype_atomic(wr, param);
+ break;
+
+ case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
+ roce3_set_rc_wqe_for_optype_cmp_and_swap(wr, param);
+ break;
+
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ roce3_set_wqe_last_len(param->wqe);
+ roce3_set_rc_wqe_for_optype_write(wr, param);
+ break;
+
+ case IB_WR_RDMA_READ:
+ case IB_WR_RDMA_WRITE:
+ roce3_set_rc_wqe_for_optype_write(wr, param);
+ break;
+
+ case IB_WR_LOCAL_INV:
+ roce3_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:
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Invalid opcode, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ break;
+ }
+
+ return ret;
+}
+
+static int roce3_post_send_uc(struct roce3_post_send_normal_param *param, struct roce3_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)
+ roce3_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;
+ roce3_set_send_seg((struct roce3_wqe_send_tsk_seg *)param->wqe, wr);
+ param->data_len_addr = &((struct roce3_wqe_send_tsk_seg *)param->wqe)->data_len;
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce3_wqe_send_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce3_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)
+ roce3_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;
+ roce3_set_rdma_seg((struct roce3_wqe_rdma_tsk_seg *)param->wqe, wr);
+ param->data_len_addr = &((struct roce3_wqe_rdma_tsk_seg *)param->wqe)->data_len;
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce3_wqe_rdma_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce3_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;
+ roce3_set_local_inv_seg((struct roce3_wqe_local_inv_tsk_seg *)param->wqe, wr);
+ param->wqe_size += (u32)sizeof(struct roce3_wqe_local_inv_tsk_seg);
+ return ROCE_NEED_JUMP;
+
+ default:
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Invalid opcode, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ break;
+ }
+
+ return 0;
+}
+
+static int roce3_post_send_ud(struct roce3_post_send_normal_param *param, struct roce3_device *rdev,
+ struct roce3_qp *rqp, const struct ib_send_wr *wr, const struct ib_send_wr **bad_wr)
+{
+ struct roce3_wqe_ud_tsk_seg *tsk_sg = (struct roce3_wqe_ud_tsk_seg *)param->wqe;
+
+ if (ROCE_UNLIKELY((wr->opcode != IB_WR_SEND) && (wr->opcode != IB_WR_SEND_WITH_IMM))) {
+ // ret = -EINVAL;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Wr->opcode(%d), func_id(%d)\n",
+ __func__, 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 roce3_wqe_ud_tsk_seg *)param->wqe)->data_len;
+
+ if (param->sq_rmd_size > (1UL << (unsigned int)rqp->sq.wqe_shift)) {
+ roce3_set_ud_seg((struct roce3_wqe_ud_tsk_seg *)(param->wqe), wr);
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce3_wqe_ud_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce3_wqe_ud_tsk_seg);
+ } else {
+ roce3_set_ud_seg_cycle1((struct roce3_wqe_ud_tsk_seg_cycle1 *)param->wqe, wr);
+ param->wqe = rqp->sq_head_addr;
+ param->wqe_size += (u32)sizeof(struct roce3_wqe_ud_tsk_seg_cycle1);
+ roce3_set_ud_seg_cycle2((struct roce3_wqe_ud_tsk_seg_cycle2 *)param->wqe, wr);
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce3_wqe_ud_tsk_seg_cycle2));
+ param->wqe_size += (u32)sizeof(struct roce3_wqe_ud_tsk_seg_cycle2);
+ }
+
+ return 0;
+}
+
+static void roce3_post_send_set_normal_data_seg(const struct ib_send_wr *wr,
+ struct roce3_wqe_data_seg **dseg, struct roce3_qp *rqp)
+{
+ if (wr->num_sge != 0) {
+ if ((u8 *)(*dseg) == rqp->sq_head_addr) {
+ *dseg = (struct roce3_wqe_data_seg *)(
+ (void *)(rqp->sq_tail_addr - sizeof(struct roce3_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 roce3_post_send_set_normal_sge(struct roce3_post_send_normal_param *param,
+ struct roce3_device *rdev, struct roce3_qp *rqp,
+ const struct ib_send_wr *wr, const struct ib_send_wr **bad_wr)
+{
+ int i;
+
+ param->data_len = 0;
+ param->dseg = (struct roce3_wqe_data_seg *)param->wqe;
+ param->wqe_size += (u32)(wr->num_sge * (int)sizeof(struct roce3_wqe_data_seg));
+ for (i = 0; i < wr->num_sge; ++i) {
+ if (param->sq_rmd_size < sizeof(struct roce3_wqe_data_seg))
+ param->dseg = (struct roce3_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;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Sge_data length is over range, sg_list(%d), length(0x%x), max_msg_sz(0x%x), func_id(%d)\n",
+ __func__, 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;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Data len is over range, data_len(%d), max_msg_sz(%d), func_id(%d)\n",
+ __func__, param->data_len,
+ rdev->rdma_cap.dev_rdma_cap.roce_own_cap.max_msg_sz,
+ rdev->glb_func_id);
+ return ROCE_NEED_JUMP;
+ }
+ roce3_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 roce3_copy_inline_data(struct roce3_post_send_normal_param *param,
+ const struct ib_send_wr *wr, struct roce3_qp *rqp, int i)
+{
+ if (param->sq_rmd_size >= wr->sg_list[i].length) {
+ roce3_set_inline_data(param->wqe, wr->sg_list + i);
+ 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 {
+ roce3_set_inline_data_cycle1(param->wqe, wr->sg_list + i, param->sq_rmd_size);
+ param->wqe = rqp->sq_head_addr;
+
+ roce3_set_inline_data_cycle2(param->wqe, wr->sg_list + i,
+ wr->sg_list[i].length - param->sq_rmd_size);
+ param->wqe = ((u8 *)param->wqe + wr->sg_list[i].length - param->sq_rmd_size);
+
+ param->cycle = 1;
+ }
+}
+
+static int roce3_post_send_set_data_seg(struct roce3_post_send_normal_param *param,
+ struct roce3_device *rdev, struct roce3_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;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Data len is too big, data_len(%d), max_inline_data(%d), func_id(%d)\n",
+ __func__, 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;
+
+ roce3_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 = roce3_post_send_set_normal_sge(param, rdev, rqp, wr, bad_wr);
+ if (ret != 0)
+ return ret;
+
+ roce3_post_send_set_normal_data_seg(wr, &param->dseg, rqp);
+
+ param->ctrl_seg_tmp.dw0.bs.bdsl =
+ (u32)((wr->num_sge * (int)sizeof(struct roce3_wqe_data_seg)) /
+ ROCE_TASK_SEG_ALIGN) & 0x7ff;
+ param->ctrl_seg_tmp.dw0.bs.df = 0;
+ }
+
+ return 0;
+}
+
+static int roce3_post_send_ring_db(struct roce3_post_send_normal_param *param,
+ struct roce3_device *rdev, struct roce3_qp *rqp)
+{
+ int ret = 0;
+
+ if ((rdev->kernel_dwqe_map != NULL) && (param->wr_num == 1) && (param->inline_flag != 0) &&
+ (param->wqe_size > (u32)sizeof(struct roce3_wqe_ctrl_seg)) &&
+ ((int)param->wqe_size <= rqp->max_dwqe_size) &&
+ (param->cycle == 0)) {
+ wmb(); /* Ring db memory barrier */
+
+ param->ctrl_seg->dw1.value = be32_to_cpu(param->ctrl_seg->dw1.value);
+ param->ctrl_seg->dw1.bs.mask_pi =
+ (u32)((param->index & ((unsigned int)rqp->sq.wqebb_cnt - 1)) & 0xfffff);
+
+ roce3_set_dwqe_db(rqp, param->ctrl_seg, param->index);
+
+ param->wqe_size = ALIGN((u32)param->wqe_size, ROCE_SQ_WQEBB_SIZE);
+
+ *(rqp->db.db_record) = cpu_to_be32(param->index);
+
+ wmb(); /* Ring db memory barrier */
+
+ ++rqp->sq.head;
+ roce3_dwqe_copy((unsigned long *)rdev->kernel_dwqe_map,
+ (unsigned long *)param->ctrl_seg, (u32)param->wqe_size);
+ wc_wmb(); /* Ring db memory barrier */
+ } else if (param->wr_num != 0) {
+ rqp->sq.head += param->wr_num;
+
+ wmb(); /* Ring db memory barrier */
+
+ memset(&(param->sq_db.sq_db_val), 0, sizeof(u64));
+ roce3_set_sq_db(rqp, &(param->sq_db.sq_db_seg), param->index);
+
+ *(rqp->db.db_record) = cpu_to_be32(param->index & 0xffff);
+
+ wmb(); /* Ring db memory barrier */
+ ret = cqm_ring_hardware_db(rdev->hwdev, SERVICE_T_ROCE,
+ param->index & 0xff, param->sq_db.sq_db_val);
+ wmb(); /* Ring db memory barrier */
+ }
+
+ return ret;
+}
+
+static void roce3_fill_task_data_len(u32 *data_len_addr, u32 data_len)
+{
+ if (data_len_addr)
+ *data_len_addr = cpu_to_be32(data_len);
+}
+
+static int roce3_construct_wqe(struct roce3_post_send_normal_param *param,
+ struct roce3_device *rdev, struct roce3_qp *rqp,
+ const struct ib_send_wr *wr, const struct ib_send_wr **bad_wr)
+{
+ int need_goto = 0;
+
+ switch (rqp->qp_type) {
+ case IB_QPT_RC:
+ need_goto = roce3_post_send_rc(param, rdev, wr);
+ if (need_goto == ROCE_NEED_JUMP)
+ return GOTO_LOCAL;
+ break;
+
+ case IB_QPT_UC:
+ need_goto = roce3_post_send_uc(param, rdev, wr);
+ if (need_goto == ROCE_NEED_JUMP)
+ return GOTO_LOCAL;
+ break;
+
+ case IB_QPT_UD:
+ need_goto = roce3_post_send_ud(param, rdev, rqp, wr, bad_wr);
+ if (need_goto == ROCE_NEED_JUMP) {
+ // ret = -EINVAL;
+ 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;
+
+ roce3_set_gsi_seg(to_roce3_sqp(rqp), wr, param->wqe);
+
+ param->data_len_addr = &((struct roce3_wqe_ud_tsk_seg *)param->wqe)->data_len;
+ param->wqe = ((u8 *)param->wqe + sizeof(struct roce3_wqe_ud_tsk_seg));
+ param->wqe_size += (u32)sizeof(struct roce3_wqe_ud_tsk_seg);
+ break;
+
+ default:
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Unknown qp type, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ break;
+ }
+
+ return 0;
+}
+
+static void roce3_init_ctrl_seg(struct roce3_post_send_normal_param *param,
+ const struct ib_send_wr *wr, const struct roce3_qp *rqp)
+{
+ 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;
+}
+
+static void roce3_init_task_com_seg(union roce3_wqe_tsk_com_seg **tsk_com_seg, u8 *wqe,
+ const struct ib_send_wr *wr, const struct roce3_qp *rqp)
+{
+ *tsk_com_seg = (union roce3_wqe_tsk_com_seg *)(void *)wqe;
+
+ (*tsk_com_seg)->bs.c =
+ (u32)(!((((unsigned int)wr->send_flags &
+ (unsigned int)IB_SEND_SIGNALED) | rqp->sq_signal_bits) == 0));
+ (*tsk_com_seg)->bs.se =
+ (u32)(!(((unsigned int)wr->send_flags & (unsigned int)IB_SEND_SOLICITED) == 0));
+ (*tsk_com_seg)->bs.f = (u32)(!(((unsigned int)wr->send_flags &
+ (unsigned int)IB_SEND_FENCE) == 0));
+ (*tsk_com_seg)->bs.op_type = roce3_ib_opcode[wr->opcode] & 0x1f;
+ if (wr->opcode == IB_WR_REG_MR)
+ (*tsk_com_seg)->bs.op_type = ROCE_WQE_OPCODE_FRMR;
+}
+
+static void roce3_post_send_local_operation(struct roce3_post_send_normal_param *param,
+ struct roce3_qp *rqp, struct roce3_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)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 : roce3_post_send_normal
+ Description : roce3_post_send_normal
+ Input : struct roce3_device *rdev
+ struct roce3_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 roce3_post_send_normal(struct roce3_device *rdev, struct roce3_qp *rqp,
+ const struct ib_send_wr *wr, const struct ib_send_wr **bad_wr)
+{
+ int need_goto = 0;
+ int ret = 0;
+ struct roce3_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;
+
+ for (param.wr_num = 0; wr_tmp != NULL; ++(param.wr_num), wr_tmp = wr_tmp->next) {
+ ret = roce3_validate_wr(rqp, wr_tmp, param.wr_num);
+ if (ret != 0) {
+ *bad_wr = wr_tmp;
+ pr_err("[ROCE, ERR] %s: Failed to validate wr, func(%d) qpn(%u)\n",
+ __func__, rdev->glb_func_id, rqp->qpn);
+ goto out;
+ }
+
+ param.wqe = (u8 *)roce3_get_send_wqe(rqp, param.index);
+ param.ctrl_seg = (struct roce3_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;
+
+ roce3_init_ctrl_seg(&param, wr_tmp, rqp);
+
+ param.wqe = ((u8 *)param.wqe + sizeof(*(param.ctrl_seg)));
+ param.wqe_size = (u32)sizeof(*param.ctrl_seg);
+ roce3_init_task_com_seg(&param.tsk_com_seg, param.wqe, wr_tmp, rqp);
+
+ ret = roce3_construct_wqe(&param, 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 = roce3_post_send_set_data_seg(&param, rdev, rqp, wr_tmp, bad_wr);
+ if (need_goto == ROCE_NEED_JUMP) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ roce3_fill_task_data_len(param.data_len_addr, param.data_len);
+
+local:
+ roce3_post_send_local_operation(&param, rqp, rdev);
+ }
+
+out:
+
+ ret = roce3_post_send_ring_db(&param, rdev, rqp);
+
+ if (ROCE_LIKELY(param.wr_num != 0))
+ rqp->sq_next_wqe = param.index;
+
+ spin_unlock_irqrestore(&rqp->sq.lock, param.flags);
+
+ return ret;
+}
+
+static int roce3_post_send_check_qp_type(const struct roce3_qp *rqp)
+{
+ if (ROCE_UNLIKELY(rqp->qp_type == IB_QPT_XRC_TGT)) {
+ pr_err("[ROCE, ERR] %s: Can't post WQE when TGT XRC QP\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ROCE_UNLIKELY(rqp->qp_type == IB_QPT_XRC_INI)) {
+ pr_err("[ROCE, ERR] %s: not support xrc in kernel space\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ROCE_UNLIKELY((rqp->qp_state == IB_QPS_RESET) || (rqp->qp_state == IB_QPS_INIT) ||
+ (rqp->qp_state == IB_QPS_RTR))) {
+ pr_err("[ROCE, ERR] %s: Can't post WQE when QP is RST/INIT/RTR state\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_post_send
+ Description : roce3_post_send
+ Input : struct ib_qp *ibqp
+ struct ib_send_wr *wr
+ const struct ib_send_wr **bad_wr
+ Output : None
+****************************************************************************
+*/
+int roce3_post_send_standard(struct ib_qp *ibqp, const struct ib_send_wr *wr,
+ const struct ib_send_wr **bad_wr)
+{
+ int ret = 0;
+ struct roce3_qp *rqp = to_roce3_qp(ibqp);
+ struct roce3_device *rdev = to_roce3_dev(ibqp->device);
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ ret = roce3_post_send_check_qp_type(rqp);
+ if (ret != 0) {
+ *bad_wr = wr;
+ pr_err("[ROCE, ERR] %s: Failed to check qp.ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ ret = roce3_post_send_normal(rdev, rqp, wr, bad_wr);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to post send normal wr, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/qp/roce_qp_query.c b/drivers/infiniband/hw/hiroce3/qp/roce_qp_query.c
new file mode 100644
index 0000000000000..f73cb0cbfe6ba
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/qp/roce_qp_query.c
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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 "hinic3_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_pub_cmd.h"
+#include "roce_main_extension.h"
+#ifdef __ROCE_DFX__
+#include "roce_dfx.h"
+#endif
+
+static enum ib_mig_state to_ib_mig_state(int roce3_mig_state)
+{
+ switch (roce3_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 struct roce_qp_context *context)
+{
+ unsigned int ib_flags = 0;
+ u32 tmp = 0;
+
+ /* RRE */
+ if (context->chip_seg.qpcc.dw5.bs.qp_rre != 0) {
+ tmp = ib_flags | IB_ACCESS_REMOTE_READ;
+ ib_flags = tmp;
+ }
+
+ /* RWE */
+ if (context->chip_seg.qpcc.dw5.bs.qp_rwe != 0) {
+ tmp = ib_flags | IB_ACCESS_REMOTE_WRITE;
+ ib_flags = tmp;
+ }
+
+ /* RAE */
+ if (context->chip_seg.qpcc.dw5.bs.qp_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 roce3_device *rdev
+ struct ib_ah_attr *ah_attr(struct rdma_ah_attr *ah_attr)
+ struct roce_qp_context *context
+ Output : None
+ Return Value :
+ Calls :
+ Called By :
+
+ History :
+ 1.Date : 2015/5/26
+ Author :
+ Modification : Created function
+
+****************************************************************************
+*/
+static void to_ib_ah_attr(struct roce3_device *rdev,
+ struct rdma_ah_attr *ah_attr, struct roce_qp_context *context)
+{
+ struct drv_path_info *path_seg = &context->sw_seg.path_seg;
+
+ memset(ah_attr, 0, sizeof(*ah_attr));
+
+ ah_attr->port_num = context->sw_seg.ucode_seg.common.dw0.bs.port;
+
+ ah_attr->sl = 0x7 - path_seg->dw7.bs.sl;
+
+ ah_attr->static_rate = 0;
+
+ ah_attr->ah_flags = IB_AH_GRH;
+
+ ah_attr->grh.sgid_index = path_seg->dw7.bs.sgid_index;
+ ah_attr->grh.hop_limit = path_seg->dw7.bs.hoplmt;
+ ah_attr->grh.traffic_class = path_seg->dw6.bs.tclass;
+ ah_attr->grh.flow_label = path_seg->dw6.bs.flow_label;
+
+ memcpy((void *)ah_attr->grh.dgid.raw, (void *)path_seg->dgid,
+ sizeof(ah_attr->grh.dgid.raw));
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_qp_query
+ Description : roce3_qp_query
+ Input : struct roce3_device *rdev
+ struct roce3_qp *qp
+ struct roce_qp_context *context
+ Output : None
+
+ 1.Date : 2015/5/26
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_qp_query(struct roce3_device *rdev, u32 qpn, u32 *context, int qpc_size)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct tag_roce_cmd_qp_query *qp_query_inbuf = NULL;
+ struct roce3_qp_query_outbuf *qp_query_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_qp_query), &cqm_cmd_outbuf,
+ (u16)sizeof(struct roce3_qp_query_outbuf));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ qp_query_inbuf = (struct tag_roce_cmd_qp_query *)cqm_cmd_inbuf->buf;
+ qp_query_outbuf = (struct roce3_qp_query_outbuf *)cqm_cmd_outbuf->buf;
+ qp_query_inbuf->com.index = cpu_to_be32(qpn);
+ qp_query_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK); //lint !e778
+ ret = roce3_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_QUERY_QP,
+ cqm_cmd_inbuf, cqm_cmd_outbuf, ROCE_CMD_TIME_CLASS_B);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to send QUERY_QP command, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA is present(QUERY_QP), qpn(0x%x), func_id(%u)\n",
+ __func__, qpn, rdev->glb_func_id);
+
+ if ((ret == -ETIMEDOUT) || (ret == -EPERM))
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+
+ ret = -1;
+ goto free_cqm_buf;
+ }
+
+ memcpy((void *)context, (void *)&qp_query_outbuf->qpc, (size_t)qpc_size);
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+ return 0;
+
+free_cqm_buf:
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : qpc_seg_to_le32
+ Input : struct roce_qp_context *le_ctx
+ struct roce_qp_context *be_ctx
+ struct roce3_qp *rqp
+ Output : None
+
+ 1.Date : 2015/8/15
+ Modification : Created function
+
+****************************************************************************
+*/
+void qpc_seg_to_le32(struct roce_qp_context *be_ctx, struct roce_qp_context *le_ctx, u32 srq_vld)
+{
+ /* DRV Seg */
+ memcpy((void *)le_ctx->sw_seg.path_seg.dgid,
+ (void *)be_ctx->sw_seg.path_seg.dgid, sizeof(be_ctx->sw_seg.path_seg.dgid));
+
+ /* 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);
+
+ le_ctx->chip_seg.rrwc.rrw_curt_sge_va = be64_to_cpu(be_ctx->chip_seg.rrwc.rrw_curt_sge_va);
+}
+
+void roce3_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);
+}
+
+static void roce3_get_ah_attr(const struct roce3_qp *rqp, struct ib_qp_attr *qp_attr,
+ struct roce3_device *rdev, struct roce_qp_context *context)
+{
+ if ((rqp->qp_type == IB_QPT_RC) || (rqp->qp_type == IB_QPT_UC))
+ to_ib_ah_attr(rdev, &qp_attr->ah_attr, context);
+}
+
+static void roce3_query_set_common_attr(struct ib_qp_attr *qp_attr,
+ const struct ib_qp *ibqp, struct roce3_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 roce3_query_set_attr(struct ib_qp_attr *qp_attr, u8 tmp_qp_state, struct roce3_qp *rqp,
+ struct roce_qp_context context, struct roce3_device *rdev)
+{
+ qp_attr->qp_state = (enum ib_qp_state)rqp->qp_state;
+ qp_attr->path_mtu = (enum ib_mtu)context.sw_seg.drv_seg.dw2.bs.pmtu;
+ qp_attr->path_mig_state = (enum ib_mig_state)to_ib_mig_state(ROCE_QP_PM_MIGRATED);
+ qp_attr->qkey = context.sw_seg.ucode_seg.common.dw2.qkey;
+ qp_attr->rq_psn = context.sw_seg.ucode_seg.rq_ctx.dw20.bs.next_rcv_psn;
+ qp_attr->sq_psn = context.sw_seg.ucode_seg.sq_ctx.dw8.bs.next_send_psn;
+ qp_attr->dest_qp_num = context.sw_seg.drv_seg.dw0.bs.dest_qp;
+ qp_attr->qp_access_flags = to_ib_qp_access_flags(&context);
+
+ roce3_get_ah_attr(rqp, qp_attr, rdev, &context);
+
+ qp_attr->pkey_index = 0;
+
+ if (qp_attr->qp_state == IB_QPS_INIT)
+ qp_attr->port_num = rqp->port;
+ else
+ qp_attr->port_num = context.sw_seg.ucode_seg.common.dw0.bs.port;
+
+ /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+
+ /* SQ Draining FLAG */
+ qp_attr->sq_draining = (tmp_qp_state == ROCE_QP_STATE_SQ_DRAINING);
+
+ qp_attr->max_rd_atomic = (1 << context.sw_seg.drv_seg.dw3.bs.sra_max);
+ qp_attr->max_dest_rd_atomic = (1 << context.sw_seg.drv_seg.dw3.bs.rra_max);
+
+ qp_attr->min_rnr_timer = context.sw_seg.drv_seg.dw2.bs.min_rnr_nak;
+ qp_attr->timeout = context.sw_seg.drv_seg.dw2.bs.ack_to;
+ qp_attr->retry_cnt = context.sw_seg.drv_seg.dw2.bs.to_retry_limit;
+ qp_attr->rnr_retry = context.sw_seg.drv_seg.dw2.bs.rnr_retry_limit;
+}
+
+static int roce3_query_qp_struct_clean(struct ib_qp_attr *qp_attr,
+ struct ib_qp_init_attr *qp_init_attr, struct roce_qp_context *be_ctx,
+ struct roce_qp_context *context)
+{
+ memset(qp_attr, 0, sizeof(struct ib_qp_attr));
+ memset(qp_init_attr, 0, sizeof(struct ib_qp_init_attr));
+ memset(be_ctx, 0, sizeof(struct roce_qp_context));
+ memset(context, 0, sizeof(struct roce_qp_context));
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_query_qp
+ Description : roce3_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 roce3_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 roce3_qp *rqp = NULL;
+ struct roce3_device *rdev = NULL;
+ struct roce_qp_context be_ctx; /* BE context structure */
+ struct roce_qp_context context; /* LE context structure */
+ u32 srq_vld;
+ u8 tmp_qp_state = 0;
+
+ ret = roce3_query_qp_struct_clean(qp_attr, qp_init_attr, &be_ctx, &context);
+ if (ret != 0)
+ return ret;
+
+ rqp = to_roce3_qp(ibqp);
+ rdev = to_roce3_dev(ibqp->device);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ mutex_lock(&rqp->mutex);
+
+ if (rqp->qp_state == IB_QPS_RESET) {
+ qp_attr->qp_state = IB_QPS_RESET;
+ goto done;
+ }
+
+ ret = roce3_qp_query(rdev, rqp->qpn, (u32 *)(void *)(&be_ctx), sizeof(be_ctx));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to query qp, ret(%d), func_id(%d)\n",
+ __func__, ret, rdev->glb_func_id);
+ mutex_unlock(&rqp->mutex);
+ return ret;
+ }
+
+ srq_vld = (!(rqp->ibqp.srq)) ? ROCE_QP_NO_SRQ : ROCE_QP_HAS_SRQ;
+ roce3_be32_2_le32(&be_ctx, (u32 *)(void *)&context,
+ sizeof(struct roce_qp_context) / sizeof(u32));
+
+ qpc_seg_to_le32(&be_ctx, &context, srq_vld);
+
+ rqp->qp_state = context.sw_seg.drv_seg.dw0.bs.state; /* state:4bits */
+
+ tmp_qp_state = rqp->qp_state;
+ if (rqp->qp_state == ROCE_QP_STATE_SQ_DRAINING)
+ rqp->qp_state = IB_QPS_SQD;
+
+ roce3_query_set_attr(qp_attr, tmp_qp_state, rqp, context, rdev);
+
+done:
+ roce3_query_set_common_attr(qp_attr, ibqp, rqp, qp_init_attr);
+
+ mutex_unlock(&rqp->mutex);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/rdma/rdma_bitmap.c b/drivers/infiniband/hw/hiroce3/rdma/rdma_bitmap.c
new file mode 100644
index 0000000000000..92988da70b7e2
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/rdma/rdma_bitmap.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/slab.h>
+
+#include "rdma_comp.h"
+#include "rdma_bitmap.h"
+
+u32 rdma_bitmap_alloc(struct rdma_bitmap *bitmap)
+{
+ u32 index = 0;
+
+ if (bitmap == NULL) {
+ pr_err("%s: Bitmap is null\n", __func__);
+ return RDMA_INVALID_INDEX;
+ }
+
+ spin_lock(&bitmap->lock);
+
+ index = (u32)find_next_zero_bit(bitmap->table,
+ (unsigned long)bitmap->max_num, (unsigned long)bitmap->last);
+ if (index >= bitmap->max_num) {
+ bitmap->top = (bitmap->top + bitmap->max_num + bitmap->reserved_top) & bitmap->mask;
+ index = (u32)find_first_zero_bit(bitmap->table, (unsigned long)bitmap->max_num);
+ }
+
+ if (index < bitmap->max_num) {
+ set_bit(index, bitmap->table);
+ bitmap->last = index + 1;
+ if (bitmap->last == bitmap->max_num)
+ bitmap->last = 0;
+
+ index |= bitmap->top;
+ --bitmap->avail;
+ } else {
+ pr_err("%s: Get a invalid index\n", __func__);
+ spin_unlock(&bitmap->lock);
+ return RDMA_INVALID_INDEX;
+ }
+
+ spin_unlock(&bitmap->lock);
+
+ return index;
+}
+
+void rdma_bitmap_free(struct rdma_bitmap *bitmap, u32 index)
+{
+ u32 index_tmp = index;
+
+ if (bitmap == NULL) {
+ pr_err("%s: Bitmap is null\n", __func__);
+ return;
+ }
+
+ if (index_tmp >= bitmap->max_num) {
+ pr_err("%s: Index(%d) is bigger or equal than max(%d)\n",
+ __func__, index_tmp, bitmap->max_num);
+ return;
+ }
+
+ index_tmp &= bitmap->max_num + bitmap->reserved_top - 1;
+
+ spin_lock(&bitmap->lock);
+
+ bitmap->last = min(bitmap->last, index_tmp);
+ bitmap->top = (bitmap->top + bitmap->max_num + bitmap->reserved_top) & bitmap->mask;
+
+ bitmap_clear(bitmap->table, (int)index_tmp, 1);
+ ++bitmap->avail;
+ spin_unlock(&bitmap->lock);
+}
+
+int rdma_bitmap_init(struct rdma_bitmap *bitmap, u32 num, u32 mask,
+ u32 reserved_bot, u32 reserved_top)
+{
+ if (bitmap == NULL) {
+ pr_err("%s: Bitmap is null\n", __func__);
+ return -EINVAL;
+ }
+
+ /*lint -e587 */
+ if (num != (u32)(ROCE_BITMAP_ROUNDUP_POW_OF_TWO(num) & 0xffffffff)) {
+ pr_err("%s: Num(%d) isn't pow of two, err(%d)\n", __func__, num, -EINVAL);
+ return -EINVAL;
+ }
+ /*lint +e587 */
+
+ if (num <= (reserved_bot + reserved_top)) {
+ pr_err("%s: Reserved num is bigger than total num, err(%d)\n",
+ __func__, -EINVAL);
+ return -EINVAL;
+ }
+
+ bitmap->last = 0;
+ bitmap->top = 0;
+ bitmap->max_num = num - reserved_top;
+ bitmap->mask = mask;
+ bitmap->reserved_top = reserved_top;
+ bitmap->avail = (num - reserved_top) - reserved_bot;
+
+ /*lint -e708*/
+ spin_lock_init(&bitmap->lock);
+ /*lint +e708*/
+ bitmap->table = kcalloc(BITS_TO_LONGS(bitmap->max_num), sizeof(long), GFP_KERNEL);
+ if (bitmap->table == NULL) {
+ bitmap->table = vzalloc((size_t)(BITS_TO_LONGS(bitmap->max_num) * sizeof(long)));
+ if (bitmap->table == NULL)
+ return -ENOMEM;
+ }
+
+ bitmap_set(bitmap->table, 0, (int)reserved_bot);
+
+ return 0;
+}
+
+void rdma_bitmap_cleanup(struct rdma_bitmap *bitmap)
+{
+ if (bitmap == NULL) {
+ pr_err("%s: Bitmap is null\n", __func__);
+ return;
+ }
+
+ if (is_vmalloc_addr(bitmap->table))
+ vfree(bitmap->table);
+ else
+ kfree(bitmap->table);
+
+ bitmap->table = NULL;
+}
diff --git a/drivers/infiniband/hw/hiroce3/rdma/rdma_bitmap.h b/drivers/infiniband/hw/hiroce3/rdma/rdma_bitmap.h
new file mode 100644
index 0000000000000..8072dd458b0d2
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/rdma/rdma_bitmap.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef RDMA_BITMAP_H
+#define RDMA_BITMAP_H
+
+#include <linux/spinlock.h>
+
+#ifndef RDMA_INVALID_INDEX
+#define RDMA_INVALID_INDEX 0xFFFFFFFF
+#endif
+
+#define ROCE_BITMAP_ROUNDUP_POW_OF_TWO(n) (roundup_pow_of_two(n))
+
+struct rdma_bitmap {
+ u32 last; /* bottom of available id */
+ u32 top; /* top value of non zone of id */
+ u32 max_num; /* max id num */
+ u32 reserved_top; /* unavailable top num */
+ u32 mask; /* mask of id */
+ u32 avail; /* num of available id */
+ spinlock_t lock; /* spinlock of bitmap */
+ unsigned long *table; /* memory of bitmap */
+};
+
+u32 rdma_bitmap_alloc(struct rdma_bitmap *bitmap);
+
+void rdma_bitmap_free(struct rdma_bitmap *bitmap, u32 index);
+
+int rdma_bitmap_init(struct rdma_bitmap *bitmap, u32 num, u32 mask,
+ u32 reserved_bot, u32 reserved_top);
+
+void rdma_bitmap_cleanup(struct rdma_bitmap *bitmap);
+
+#endif // __RDMA_BITMAP_H__
+
diff --git a/drivers/infiniband/hw/hiroce3/rdma/rdma_comp.c b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp.c
new file mode 100644
index 0000000000000..c2b4d06a47b85
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_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 *)hinic3_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/hiroce3/rdma/rdma_comp.h b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp.h
new file mode 100644
index 0000000000000..d214860331627
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#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>
+
+#include "rdma_context_format.h"
+#include "hinic3_crm.h"
+#include "hinic3_cqm.h"
+#include "hinic3_rdma.h"
+
+#include "roce_verbs_cmd.h"
+#include "roce_verbs_ulp_format.h"
+
+#include "rdma_bitmap.h"
+#include "hmm_buddy.h"
+#include "hmm_em.h"
+#include "hmm_comp.h"
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": [RDMA]" fmt
+#endif
+
+#define RDMA_DEFAULT_GID_SUBNET_PREFIX 0xFE80000000000000ULL
+
+#define RDMA_KEY_MASK 0xFFFFFF00
+
+#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 ROCE3_RDMARC_MIN_DEPTH 1
+#define ROCE3_RDMARC_MAX_DEPTH 512
+#define ROCE3_RDMARC_MIN_ENTRY 8 /* min entry aligned required by engine */
+#define ROCE3_RDMARC_EXT_ENTRY 384 // 384 /* ext tbl 12K. 12k/32 = 384 */
+
+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 {
+ ROCE3_RDMA_MTT_PAGE_SIZE_4K = 0,
+ ROCE3_RDMA_MTT_PAGE_SIZE_64K = 1,
+ ROCE3_RDMA_MTT_PAGE_SIZE_2M = 2
+};
+
+enum {
+ ROCE3_RDMA_CMD_TIME_OUT_A = 30000,
+ ROCE3_RDMA_CMD_TIME_OUT_B = 40000,
+ ROCE3_RDMA_CMD_TIME_OUT_C = 50000
+};
+
+enum rdma_roce3_cmd {
+ RDMA_ROCE_CMD_UPDATE_GID = 0x60,
+ RDMA_ROCE_CMD_QUERY_GID = 0x61,
+ RDMA_ROCE_CMD_CLEAR_GID = 0x62
+};
+
+struct rdma_comp_priv {
+ struct rdma_comp_resource rdma_comp_res; /* gid & guid */
+
+ struct hmm_buddy mtt_buddy;
+ struct hmm_em_table mtt_em_table;
+ void *hwdev;
+ struct pci_dev *pdev;
+ struct rdma_mr rsvd_lkey;
+ struct rdma_mr fixed_mr;
+ u32 mtt_page_size; /* 4K, 8K, 16K, 32K */
+ u32 mtt_page_shift; /* 12, 13, 14, 15 */
+ 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;
+};
+
+struct rdma_gid_update_inbuf {
+ struct tag_roce_verbs_cmd_com com;
+ __be32 port;
+ __be32 rsvd;
+ struct rdma_gid_entry gid_entry;
+};
+
+struct rdma_gid_clear_inbuf {
+ __be32 port;
+ __be32 gid_num;
+};
+
+/* 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 roce3_rdma_init_rsvd_lkey(void *hwdev);
+
+void roce3_rdma_free_rsvd_lkey(void *hwdev);
+
+#endif // RDMA_COMP_H
diff --git a/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_gid.c b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_gid.c
new file mode 100644
index 0000000000000..89cb351944f69
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_gid.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_hw.h"
+#include "rdma_comp.h"
+#include "roce.h"
+#include "roce_cqm_cmd.h"
+
+static int rdma_update_gid(struct rdma_comp_priv *comp_priv,
+ struct rdma_gid_entry *new_gid_entry, int port, int gid_index)
+{
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct rdma_gid_update_inbuf *gid_update_inbuf = NULL;
+ int ret;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(comp_priv->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct rdma_gid_update_inbuf), NULL, 0);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, ret(%d)\n",
+ __func__, 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); //lint !e778
+
+ memcpy(&gid_update_inbuf->gid_entry.smac[0], &new_gid_entry->smac[0], ETH_ALEN);
+
+ pr_info("[ROCE] %s:gid_index:0x%x gid:0x%x %x %x %x %x %x %x %x\n",
+ __func__, gid_update_inbuf->com.index,
+ *((u32 *)(void *)new_gid_entry + 0),
+ *((u32 *)(void *)new_gid_entry + 1), // 0 1 is gid array idx
+ *((u32 *)(void *)new_gid_entry + 2),
+ *((u32 *)(void *)new_gid_entry + 3), // 2 3 is gid array idx
+ *((u32 *)(void *)new_gid_entry + 4),
+ *((u32 *)(void *)new_gid_entry + 5), // 4 5 is gid array idx
+ *((u32 *)(void *)new_gid_entry + 6),
+ *((u32 *)(void *)new_gid_entry + 7)); // 6 7 is gid array idx
+ ret = cqm_send_cmd_box(comp_priv->hwdev, HINIC3_MOD_ROCE,
+ RDMA_ROCE_CMD_UPDATE_GID, cqm_cmd_inbuf, NULL, NULL,
+ ROCE3_RDMA_CMD_TIME_OUT_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ pr_err("%s: Send cmd update_gid failed, ret(%d)\n", __func__, ret);
+ ret = -1;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(comp_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;
+
+ memcpy(&entry1, gid_tbl_entry, sizeof(struct rdma_gid_entry));
+ memcpy(&entry2, gid_entry, sizeof(struct rdma_gid_entry));
+
+ /* compare ip+vlan, compare after clear smac */
+ memset((void *)entry1.smac, 0, sizeof(entry1.smac));
+ memset((void *)entry2.smac, 0, sizeof(entry2.smac));
+ return memcmp((void *)&entry1, (void *)&entry2, sizeof(struct rdma_gid_entry));
+}
+
+static int rdma_reset_gid(struct rdma_comp_priv *comp_priv, u32 port, u32 gid_num)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_clear_gid *gid_clear_inbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(comp_priv->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_clear_gid), NULL, 0);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, ret(%d)\n",
+ __func__, ret);
+ return -ENOMEM;
+ }
+
+ gid_clear_inbuf = (struct tag_roce_clear_gid *)cqm_cmd_inbuf->buf;
+ gid_clear_inbuf->port = cpu_to_be32(port);
+ gid_clear_inbuf->com.index = 0; // cpu_to_be32(gid_num);
+ gid_clear_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_GID_BITMASK); //lint !e778
+
+ ret = cqm_send_cmd_box(comp_priv->hwdev, HINIC3_MOD_ROCE,
+ RDMA_ROCE_CMD_CLEAR_GID, cqm_cmd_inbuf, NULL, NULL,
+ ROCE3_RDMA_CMD_TIME_OUT_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ pr_err("%s: Send cmd clear_gid failed, ret(%d)\n", __func__, ret);
+ ret = -1;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(comp_priv->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+int roce3_rdma_update_gid_mac(void *hwdev, u32 port, 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 ((hwdev == NULL) || (gid_entry == NULL)) {
+ pr_err("%s: Hwdev or gid_tbl is null\n", __func__);
+ return -EINVAL;
+ }
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+ /* port num index from zero */
+ if (port >= comp_priv->rdma_cap.num_ports) {
+ pr_err("%s: Input port(%d) is invalid\n", __func__, 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 = rdma_update_gid(comp_priv, gid_entry, (int)port, update_index);
+ if (ret != 0) {
+ pr_err("%s: Update gid tbl failed, ret(%d)\n", __func__, ret);
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return ret;
+ }
+ /* update gid table after CMDQ */
+ memcpy((void *)&gid_table[port][update_index], (void *)gid_entry,
+ sizeof(*gid_entry));
+
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return 0;
+ }
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return 0;
+}
+
+int roce3_rdma_update_gid(void *hwdev, 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;
+
+ if ((hwdev == NULL) || (gid_entry == NULL)) {
+ pr_err("%s: Hwdev or gid_tbl is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ 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) {
+ pr_err("%s: Input port(%d) is invalid\n", __func__, port);
+ return -EINVAL;
+ }
+
+ mutex_lock(&comp_priv->rdma_comp_res.mutex);
+ ret = rdma_update_gid(comp_priv, gid_entry, (int)port, (int)update_index);
+ if (ret != 0) {
+ pr_err("%s: Rdma_update_gid failed\n", __func__);
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+ return ret;
+ }
+
+ memcpy((void *)&gid_table[port][update_index], (void *)gid_entry, sizeof(*gid_entry));
+ mutex_unlock(&comp_priv->rdma_comp_res.mutex);
+
+ return 0;
+}
+
+int roce3_rdma_reset_gid_table(void *hwdev, 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 (hwdev == NULL) {
+ pr_err("%s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ gid_table = comp_priv->rdma_comp_res.gid_table;
+ if (gid_table == NULL) {
+ pr_err("%s: Gid_table is null\n", __func__);
+ return -EINVAL;
+ }
+
+ gids_per_port = comp_priv->rdma_cap.max_gid_per_port;
+ if (gids_per_port == 0) {
+ pr_err("%s: Gids_per_port(%d) is invalid\n", __func__, gids_per_port);
+ return -EINVAL;
+ }
+
+ memset(&gid_table[port][0], 0,
+ gids_per_port * sizeof(struct rdma_gid_entry));
+ ret = rdma_reset_gid(comp_priv, port, gids_per_port);
+ if (ret != 0) {
+ pr_err("%s: Reset gid table failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce3_rdma_get_gid(void *hwdev, u32 port, u32 gid_index, struct rdma_gid_entry *gid)
+{
+ struct rdma_service_cap *rdma_cap = NULL;
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if (hwdev == NULL) {
+ pr_err("%s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (gid == NULL) {
+ pr_err("%s: Gid is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdma_cap = &comp_priv->rdma_cap;
+ if (port < 1 || port > rdma_cap->num_ports) {
+ pr_err("%s: Port(%d) invalid\n", __func__, port);
+ return -EINVAL;
+ }
+
+ if (gid_index >= rdma_cap->max_gid_per_port) {
+ pr_err("%s: gid_index(%d) invalid\n", __func__, gid_index);
+ return -EINVAL;
+ }
+
+ memcpy((void *)gid, (void *)&comp_priv->rdma_comp_res.gid_table[port - 1][gid_index],
+ sizeof(*gid));
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_init.c b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_init.c
new file mode 100644
index 0000000000000..895bb5b788025
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_init.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_hw.h"
+#include "rdma_comp.h"
+#include "hinic3_hmm.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) {
+ pr_err("%s: Can't initialize pd's bitmap, ret(%d)\n", __func__, 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) {
+ pr_err("%s: Gid_table is null\n", __func__);
+ return;
+ }
+
+ port_num = (int)comp_priv->rdma_cap.num_ports;
+ for (i = 0; i < port_num; i++) {
+ kfree(gid_table[i]);
+ gid_table[i] = NULL;
+ }
+
+ kfree(gid_table);
+ comp_priv->rdma_comp_res.gid_table = NULL;
+}
+
+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)) {
+ pr_err("%s: Alloc memory for gid_tbl failed, port_num(%d), gids_per_ports(%d)\n",
+ __func__, port_num, gids_per_port);
+ return -EINVAL;
+ }
+
+ gid_table = kcalloc(port_num, sizeof(struct rdma_gid_entry *), GFP_KERNEL);
+ if (gid_table == NULL)
+ return -ENOMEM;
+
+ comp_priv->rdma_comp_res.gid_table = gid_table;
+
+ for (i = 0; i < port_num; i++) {
+ gid_table[i] = kcalloc(gids_per_port, sizeof(struct rdma_gid_entry), GFP_KERNEL);
+ if (gid_table[i] == NULL)
+ goto err_out;
+ }
+ return 0;
+err_out:
+ for (i = 0; i < port_num; 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) {
+ pr_err("%s: Can't initialize xrcd's bitmap!, ret(%d)\n", __func__, 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) {
+ pr_err("%s: Initialize rdmarc's buddy failed, ret(%d)\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+ /*lint -e587*/
+ rdmarc_pow_of_two = (u32)(HMM_EM_ROUNDUP_POW_OF_TWO(
+ (u32)(qp_num * rdmarc_per_qp)) & 0xffffffff);
+ /*lint +e587*/
+ ret = hmm_em_init_table(comp_priv->pdev, &comp_priv->rdmarc_em_table,
+ rdmarc_size, rdmarc_pow_of_two, 0, RDMA_EM_MIN_ORDER);
+ if (ret != 0) {
+ pr_err("%s: Initialize rdmarc's em_table failed, ret(%d)\n", __func__, ret);
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ hmm_buddy_cleanup(&comp_priv->rdmarc_buddy);
+
+ return -ENOMEM;
+}
+
+static int roce3_rdma_init_pd_table(struct rdma_comp_priv *comp_priv)
+{
+ int ret = 0;
+
+ ret = rdma_init_pd_table(comp_priv);
+ if (ret != 0) {
+ pr_err("%s: Initialize pd's table failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce3_rdma_init_mtt_table(struct rdma_comp_priv *comp_priv)
+{
+ int ret = 0;
+
+ ret = hmm_init_mtt_table((struct hmm_comp_priv *)(void *)comp_priv);
+ if (ret != 0) {
+ pr_err("%s: Initialize mtt's table failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce3_rdma_init_bitmap(struct rdma_comp_priv *comp_priv)
+{
+ int ret;
+
+ ret = roce3_rdma_init_pd_table(comp_priv);
+ if (ret != 0)
+ return ret;
+
+ ret = roce3_rdma_init_mtt_table(comp_priv);
+ if (ret != 0) {
+ rdma_cleanup_pd_table(comp_priv);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce3_rdma_unit_bitmap(struct rdma_comp_priv *comp_priv)
+{
+ hmm_cleanup_mtt_table((struct hmm_comp_priv *)(void *)comp_priv);
+ rdma_cleanup_pd_table(comp_priv);
+}
+
+static int roce3_rdma_init_table(void *hwdev, struct rdma_comp_priv *comp_priv)
+{
+ int ret = 0;
+
+ ret = roce3_rdma_init_bitmap(comp_priv);
+ if (ret != 0)
+ return ret;
+
+ if (hinic3_support_roce(hwdev, NULL)) {
+ ret = rdma_init_gid_table(comp_priv);
+ if (ret != 0) {
+ pr_err("%s: Initialize gid table failed, ret(%d)\n", __func__, ret);
+ goto err_init_gid_table;
+ }
+ ret = rdma_init_xrcd_table(comp_priv);
+ if (ret != 0) {
+ pr_err("%s: Initialize xrcd's table failed, ret(%d)\n", __func__, ret);
+ goto err_init_xrcd;
+ }
+ ret = rdma_init_rdmarc_table(comp_priv);
+ if (ret != 0) {
+ pr_err("%s: Initialize rdmarc's table failed, ret(%d)\n",
+ __func__, ret);
+ goto err_init_rdmarc_table;
+ }
+ }
+
+ pr_info("%s: Rdma init resource successful\n", __func__);
+ 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:
+ roce3_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->pdev, &comp_priv->rdmarc_em_table);
+
+ hmm_buddy_cleanup(&comp_priv->rdmarc_buddy);
+}
+
+static void roce3_rdma_unit_table(void *hwdev, struct rdma_comp_priv *comp_priv)
+{
+ if (hinic3_support_roce(hwdev, NULL)) {
+ rdma_cleanup_rdmarc_table(comp_priv);
+ rdma_cleanup_xrcd_table(comp_priv);
+ rdma_cleanup_gid_table(comp_priv);
+ }
+
+ roce3_rdma_unit_bitmap(comp_priv);
+}
+
+void roce3_rdma_cleanup_resource(void *hwdev)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if (hwdev == NULL) {
+ pr_err("%s: Hwdev is null\n", __func__);
+ return;
+ }
+
+ if (!hinic3_support_rdma(hwdev, NULL)) {
+ pr_err("%s: Not support rdma service\n", __func__);
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return;
+ }
+
+ roce3_rdma_unit_table(hwdev, comp_priv);
+
+ kfree(comp_priv);
+
+ hinic3_unregister_service_adapter((void *)hwdev, SERVICE_T_ROCE);
+
+ pr_info("%s: Rdma cleanup resource successful", __func__);
+}
+
+static int roce3_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->hwdev = hwdev;
+ comp_priv->pdev = (struct pci_dev *)((struct hinic3_hwdev *)hwdev)->pcidev_hdl;
+ memcpy((void *)&comp_priv->rdma_cap, (void *)rdma_cap,
+ sizeof(struct rdma_service_cap));
+ // to adapt hmm struct
+ comp_priv->rdma_cap.dmtt_cl_start = rdma_cap->dev_rdma_cap.roce_own_cap.dmtt_cl_start;
+ comp_priv->rdma_cap.dmtt_cl_end = rdma_cap->dev_rdma_cap.roce_own_cap.dmtt_cl_end;
+ comp_priv->rdma_cap.dmtt_cl_sz = rdma_cap->dev_rdma_cap.roce_own_cap.dmtt_cl_sz;
+
+ switch (g_mtt_page_size) {
+ case ROCE3_RDMA_MTT_PAGE_SIZE_4K:
+ comp_priv->mtt_page_size = ROCE_MTT_PAGE_SIZE_4K;
+ comp_priv->mtt_page_shift = ROCE_MTT_PAGE_SIZE_4K_SHIFT;
+ break;
+ case ROCE3_RDMA_MTT_PAGE_SIZE_64K:
+ comp_priv->mtt_page_size = ROCE_MTT_PAGE_SIZE_64K;
+ comp_priv->mtt_page_shift = ROCE_MTT_PAGE_SIZE_64K_SHIFT;
+ break;
+ case ROCE3_RDMA_MTT_PAGE_SIZE_2M:
+ comp_priv->mtt_page_size = ROCE_MTT_PAGE_SIZE_2M;
+ comp_priv->mtt_page_shift = ROCE_MTT_PAGE_SIZE_2M_SHIFT;
+ break;
+ default:
+ comp_priv->mtt_page_size = ROCE_MTT_PAGE_SIZE_4K;
+ comp_priv->mtt_page_shift = ROCE_MTT_PAGE_SIZE_4K_SHIFT;
+ break;
+ }
+ ret = roce3_rdma_init_table(hwdev, comp_priv);
+ if (ret != 0)
+ return ret;
+
+ ret = hinic3_register_service_adapter((void *)hwdev, (void *)comp_priv, SERVICE_T_ROCE);
+ if (ret != 0) {
+ roce3_rdma_unit_table(hwdev, comp_priv);
+ pr_err("%s: put rdma_comp_res failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+ return ret;
+}
+
+int roce3_rdma_init_resource(void *hwdev)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+ struct rdma_service_cap rdma_cap;
+ int ret = 0;
+
+ if (hwdev == NULL) {
+ pr_err("%s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!hinic3_support_rdma(hwdev, &rdma_cap)) {
+ pr_info("%s: Neither ROCE nor IWARP\n", __func__);
+ return 0;
+ }
+
+ comp_priv = kzalloc(sizeof(struct rdma_comp_priv), GFP_KERNEL);
+ if (comp_priv == NULL)
+ return -ENOMEM;
+
+ ret = roce3_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/hiroce3/rdma/rdma_comp_mw_mr.c b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_mw_mr.c
new file mode 100644
index 0000000000000..4701a8ca4c762
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_mw_mr.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_hw.h"
+#include "rdma_comp.h"
+#include "roce_cqm_cmd.h"
+#include "hmm_mr.h"
+
+static void rdma_roce3_mpt_to_big_endian(struct roce_mpt_context *mpt_ctx)
+{
+ mpt_ctx->dw0.value = cpu_to_be32(mpt_ctx->dw0.value);
+ mpt_ctx->dw1.value = cpu_to_be32(mpt_ctx->dw1.value);
+ mpt_ctx->dw2.value = cpu_to_be32(mpt_ctx->dw2.value);
+ mpt_ctx->dw3.value = cpu_to_be32(mpt_ctx->dw3.value);
+ mpt_ctx->iova = cpu_to_be64(mpt_ctx->iova);
+ mpt_ctx->length = cpu_to_be64(mpt_ctx->length);
+ mpt_ctx->mtt_base_addr = cpu_to_be64(mpt_ctx->mtt_base_addr);
+ mpt_ctx->mtt_sz = cpu_to_be32(mpt_ctx->mtt_sz);
+}
+
+static void rdma_set_roce3_mw_cmd_buf(struct roce_mpt_context *mpt_ctx, struct rdma_mw *mw)
+{
+ /* fill mpt_entry */
+ mpt_ctx->dw0.bs.bpd = 1;
+ mpt_ctx->dw0.bs.r_w = RDMA_MPT_MW;
+ mpt_ctx->dw0.bs.access_lr = 1;
+ mpt_ctx->dw0.bs.access_lw = 1;
+
+ mpt_ctx->dw1.bs.dma_attr_idx = RDMA_MPT_DMA_ATTR_IDX;
+ mpt_ctx->dw1.bs.so_ro = RDMA_MPT_SO_RO;
+
+ mpt_ctx->dw2.bs.pdn = mw->pdn;
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_VALID;
+
+ mpt_ctx->dw3.bs.mkey = mw->key & 0xFF;
+
+ /* only type2 mw binds with QP and suppoort invalid operation, init value is FREE */
+ if (mw->type == RDMA_MW_TYPE_2) {
+ mpt_ctx->dw0.bs.invalid_en = 1;
+ mpt_ctx->dw0.bs.remote_invalid_en = 1;
+ mpt_ctx->dw0.bs.bqp = 1;
+
+ mpt_ctx->dw2.bs.status = RDMA_MPT_STATUS_FREE;
+ }
+
+ rdma_roce3_mpt_to_big_endian(mpt_ctx);
+}
+
+int roce3_rdma_enable_mw_mpt(void *hwdev, struct rdma_mw *mw, u32 service_type)
+{
+ int ret = 0;
+ struct rdma_comp_priv *comp_priv = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct roce_mpt_context *mpt_entry = NULL;
+ struct tag_roce_sw2hw_mpt *mpt_sw2hw_inbuf = NULL;
+
+ if ((hwdev == NULL) || (mw == NULL)) {
+ pr_err("%s: Hwdev or mw is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (service_type != RDMA_SERVICE_TYPE_ROCE) {
+ pr_err("%s: service_type not support\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_sw2hw_mpt), NULL, 0);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, ret(%d)\n",
+ __func__, ret);
+ return -ENOMEM;
+ }
+
+ /* cmd_buf: mpt_index + mpt_entry */
+ mpt_sw2hw_inbuf = (struct tag_roce_sw2hw_mpt *)cqm_cmd_inbuf->buf;
+ mpt_sw2hw_inbuf->com.index = cpu_to_be32(mw->mpt.mpt_index);
+ mpt_sw2hw_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_MR_BITMASK); //lint !e778
+ mpt_entry = &mpt_sw2hw_inbuf->mpt_entry;
+ rdma_set_roce3_mw_cmd_buf(mpt_entry, mw);
+ ret = hmm_enable_roce_mpt(hwdev, cqm_cmd_inbuf, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ pr_err("%s: Enable mr's mpt failed, ret(%d)\n", __func__, ret);
+ goto out;
+ }
+ mw->enabled = RDMA_MPT_EN_HW;
+out:
+ roce3_cqm_cmd_free_inoutbuf(hwdev, cqm_cmd_inbuf, NULL);
+ return ret;
+}
+
+int roce3_rdma_disable_mw_mpt(void *hwdev, struct rdma_mw *mw, u32 service_type)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+ int ret = 0;
+
+ if ((hwdev == NULL) || (mw == NULL)) {
+ pr_err("%s: Hwdev or mw is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (mw->enabled == RDMA_MPT_EN_HW) {
+ if (service_type == RDMA_SERVICE_TYPE_ROCE) {
+ ret = hmm_disable_roce_mpt((struct hmm_comp_priv *)(void *)comp_priv,
+ &mw->mpt, HINIC3_CHANNEL_ROCE);
+ } else {
+ pr_err("%s: service_type not support\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ret != 0) {
+ pr_err("%s: Disable mw's mpt failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ mw->enabled = RDMA_MPT_EN_SW;
+ }
+
+ return 0;
+}
+
+static int rdma_mpt_alloc_rsvd_lkey(struct rdma_comp_priv *comp_priv, struct rdma_mpt *mpt)
+{
+ struct rdma_mpt_entry *mpt_entry = NULL;
+ u32 mpt_entry_size = 0;
+
+ mpt_entry_size = comp_priv->rdma_cap.mpt_entry_sz;
+
+ /* 调用cqm接口分配mpt,并将mpt_index和vaddr保存在rdma_mpt结构 */
+ mpt->mpt_object = (void *)cqm_object_qpc_mpt_create(comp_priv->hwdev,
+ RDMA_SERVICE_TYPE_ROCE, CQM_OBJECT_MPT,
+ mpt_entry_size, mpt, mpt->mpt_index, false);
+ if (mpt->mpt_object == NULL) {
+ pr_err("[ROCE, ERR]%s: Alloc mpt_object failed, err(%d)\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+
+ mpt->vaddr = (void *)((struct tag_cqm_qpc_mpt *)mpt->mpt_object)->vaddr;
+ if (!cqm_need_secure_mem(comp_priv->hwdev)) {
+ memset(mpt->vaddr, 0, sizeof(struct rdma_mpt_entry));
+
+ mpt_entry = (struct rdma_mpt_entry *)mpt->vaddr;
+ mpt_entry->roce_mpt_ctx.dw2.bs.status = RDMA_MPT_STATUS_MEM_INIT;
+ mpt_entry->roce_mpt_ctx.dw2.value = cpu_to_be32(mpt_entry->roce_mpt_ctx.dw2.value);
+ }
+
+ return 0;
+}
+
+int roce3_rdma_init_rsvd_lkey(void *hwdev)
+{
+ struct rdma_mr *mr = NULL;
+ struct rdma_service_cap *rdma_cap = NULL;
+ struct rdma_comp_priv *comp_priv = NULL;
+ int ret = 0;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR]%s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("[ROCE, ERR]%s: Comp_priv is null\n", __func__);
+ 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) {
+ pr_err("[ROCE, ERR]%s: Cfg err, reserved_lkey(0x%x), reserved_mrws(0x%x)\n",
+ __func__, 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) {
+ pr_err("[ROCE, ERR]%s: Rdma_mpt_alloc_rsvd_lkey failed, ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ mr->mtt.mtt_layers = 0;
+ mr->iova = 0;
+ mr->size = ~0ULL;
+ mr->key = comp_priv->rdma_cap.reserved_lkey;
+ mr->mr_type = RDMA_RSVD_LKEY;
+ mr->access = RDMA_IB_ACCESS_LOCAL_WRITE;
+ /* Enable MPT */
+ ret = hmm_rdma_enable_mr_mpt(hwdev, mr, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR]%s: Rdma_enable_mr_mpt failed, ret(%d)\n", __func__, ret);
+ goto err_out;
+ }
+ return 0;
+err_out:
+ hmm_rdma_mpt_free(hwdev, &mr->mpt);
+ return ret;
+}
+
+void roce3_rdma_free_rsvd_lkey(void *hwdev)
+{
+ struct rdma_mr *mr = NULL;
+ struct rdma_comp_priv *comp_priv = NULL;
+ int ret = 0;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR]%s: Hwdev is null\n", __func__);
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("[ROCE, ERR]%s: Comp_priv is null\n", __func__);
+ return;
+ }
+
+ mr = &comp_priv->rsvd_lkey;
+ ret = hmm_rdma_disable_mr_mpt(hwdev, mr, RDMA_SERVICE_TYPE_ROCE, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR]%s: Disable mpt of mr failed, ret(%d)\n", __func__, ret);
+ return;
+ }
+
+ hmm_rdma_mpt_free(hwdev, &mr->mpt);
+}
diff --git a/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_pd.c b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_pd.c
new file mode 100644
index 0000000000000..6aba6ea1b3a12
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_pd.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_hw.h"
+#include "rdma_comp.h"
+
+int roce3_rdma_pd_alloc(void *hwdev, u32 *pdn)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if ((hwdev == NULL) || (pdn == NULL)) {
+ pr_err("%s: Hwdev or pdn is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ *pdn = rdma_bitmap_alloc(&comp_priv->pd_bitmap);
+ if (*pdn == RDMA_INVALID_INDEX) {
+ pr_err("%s: Can't get valid pdn, err(%d)\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void roce3_rdma_pd_free(void *hwdev, u32 pdn)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if (hwdev == NULL) {
+ pr_err("%s: Hwdev is null\n", __func__);
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return;
+ }
+
+ rdma_bitmap_free(&comp_priv->pd_bitmap, pdn);
+}
diff --git a/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_res.c b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_res.c
new file mode 100644
index 0000000000000..23b42a3693cd6
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/rdma/rdma_comp_res.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "hinic3_hw.h"
+#include "rdma_comp.h"
+#include "hmm_em.h"
+#include "hmm_buddy.h"
+
+static int rdma_check_map_param(const void *hwdev, const struct rdma_fmr *fmr,
+ const u64 *page_list, int npages,
+ u64 iova)
+{
+ u32 page_mask = 0;
+
+ if ((hwdev == NULL) || (fmr == NULL) || (page_list == NULL)) {
+ pr_err("%s: Hwdev or fmr or page_list is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((u32)npages > fmr->max_pages) {
+ pr_err("%s: Npages is bigger than fmr->max_pages, ret(%d)\n",
+ __func__, -EINVAL);
+ return -EINVAL;
+ }
+
+ page_mask = (1U << fmr->page_shift) - 1;
+ if ((iova & (u64)page_mask) != 0) {
+ pr_err("%s: Iova isn't page aligned, ret(%d)\n", __func__, -EINVAL);
+ return -EINVAL;
+ }
+
+ if (fmr->maps >= fmr->max_maps) {
+ pr_err("%s: Maps over range(fmr->max_maps), ret(%d)\n", __func__, -EINVAL);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_rdma_map_phys_fmr(void *hwdev, struct rdma_fmr *fmr, u64 *page_list,
+ int npages, u64 iova, u32 service_type)
+{
+ __be64 *mtt_vaddr = NULL;
+ struct rdma_comp_priv *comp_priv = NULL;
+ int ret = 0;
+ int i = 0;
+ u32 mpt_index = 0;
+ u64 length = 0;
+ u32 new_key = 0;
+ u64 iova_tmp = iova;
+ u16 sign_val = 0;
+
+ ret = rdma_check_map_param(hwdev, fmr, page_list, npages, iova_tmp);
+ if (ret != 0) {
+ pr_err("%s: Rdma check map param failed\n", __func__);
+ return ret;
+ }
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ fmr->mr.enabled = RDMA_MPT_EN_SW;
+ mpt_index = fmr->mr.mpt.mpt_index;
+ length = (u64)((unsigned int)npages * (1UL << fmr->page_shift));
+ if ((fmr->mr.access & RDMA_IB_ACCESS_ZERO_BASED) != 0)
+ iova_tmp = 0;
+
+ new_key = (fmr->mr.key & (~0xFF)) | ((fmr->mr.key + 1) & 0xFF);
+ ret = hmm_modify_roce_mpt(hwdev, mpt_index, new_key, length, iova_tmp, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ pr_err("%s: Modify mpt failed, ret(%d), new_key(%d)\n", __func__, ret, new_key);
+ return ret;
+ }
+#ifdef RDMA_SIGN_MTT_EN
+ sign_val = hmm_gen_mtt_sign(fmr->mr.mtt.mtt_paddr, fmr->mr.mtt.mtt_type);
+#endif
+ mtt_vaddr = fmr->mr.mtt.mtt_vaddr;
+ for (i = 0; i < npages; i++)
+ mtt_vaddr[i] = cpu_to_be64(page_list[i] | RDMA_MTT_PA_VALID | (sign_val << 1));
+
+ fmr->maps++;
+ fmr->mr.key = new_key;
+ fmr->mr.enabled = RDMA_MPT_EN_HW;
+ return 0;
+}
+
+int roce3_rdma_unmap_fmr(void *hwdev, struct rdma_fmr *fmr, u32 service_type)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+ int ret = 0;
+ u32 new_key = 0;
+
+ if ((hwdev == NULL) || (fmr == NULL)) {
+ pr_err("%s: Hwdev or fmr is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (fmr->maps == 0)
+ return 0;
+
+ new_key = fmr->mr.key & RDMA_KEY_MASK;
+
+ if (service_type == RDMA_SERVICE_TYPE_ROCE) {
+ ret = hmm_modify_roce_mpt(hwdev, fmr->mr.mpt.mpt_index, new_key, 0ULL,
+ 0ULL, HINIC3_CHANNEL_ROCE);
+ } else {
+ pr_err("%s: service_type not support\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ret != 0) {
+ pr_err("%s: Modify mpt failed, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ fmr->maps = 0;
+ fmr->mr.key = new_key;
+
+ return 0;
+}
+
+static int roce3_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)) {
+ pr_err("%s: Hwdev or rdmarc is null\n", __func__);
+ return -EINVAL;
+ }
+
+ *comp_priv = get_rdma_comp_priv(hwdev);
+ if (*comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ *log_rdmarc_per_seg = (*comp_priv)->rdma_cap.log_rdmarc_seg;
+
+ if ((num < ROCE3_RDMARC_MIN_DEPTH) || (num > ROCE3_RDMARC_MAX_DEPTH)) {
+ pr_err("%s: Num is invalid, ret(%d)\n", __func__, -EINVAL);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void roce3_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;
+}
+
+int roce3_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 + ROCE3_RDMARC_EXT_ENTRY;
+ u32 offset = 0;
+ void *vaddr = NULL;
+ u32 log_rdmarc_per_seg = 0;
+ u32 chip_num = (num < ROCE3_RDMARC_MIN_ENTRY) ? ROCE3_RDMARC_MIN_ENTRY : num;
+
+ ret = roce3_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;
+ roce3_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) {
+ pr_err("%s: Alloc rdmarc index failed, ret(%d)\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+ rdmarc->offset = offset << log_rdmarc_per_seg;
+ ret = hmm_em_table_get_range(comp_priv->pdev, &comp_priv->rdmarc_em_table, rdmarc->offset,
+ rdmarc->offset + (1U << rdmarc->ext_order) - 1);
+ if (ret != 0) {
+ pr_err("%s: Alloc rdmarc entry failed, ret(%d)\n", __func__, -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;
+ pr_err("%s: Can't find va and pa of rdmarc entry, ret(%d)\n",
+ __func__, -ENOMEM);
+ goto err_rdmarc_find;
+ }
+ rdmarc->vaddr = vaddr;
+ return 0;
+err_rdmarc_find:
+ hmm_em_table_put_range(comp_priv->pdev, &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 roce3_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)) {
+ pr_err("%s: Hwdev or rdmarc is null\n", __func__);
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return;
+ }
+
+ hmm_em_table_put_range(comp_priv->pdev, &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/hiroce3/roce.h b/drivers/infiniband/hw/hiroce3/roce.h
new file mode 100644
index 0000000000000..436d3f836db0b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce.h
@@ -0,0 +1,574 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_H
+#define ROCE_H
+
+#include <linux/types.h>
+#include <linux/io-mapping.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_umem.h>
+#include <rdma/uverbs_ioctl.h>
+
+#include "hinic3_hw.h"
+#include "hinic3_crm.h"
+#include "hinic3_hw_cfg.h"
+#include "hinic3_lld.h"
+#include "hinic3_cqm.h"
+#include "hinic3_rdma.h"
+
+#include "hinic3_mgmt_interface.h"
+
+#include "roce_db.h"
+#include "roce_sysfs.h"
+
+#include "roce_verbs_cmd.h"
+#include "roce_verbs_format.h"
+#include "roce_verbs_ulp_format.h"
+
+#define HIROCE3_DRV_NAME "roce3_drv"
+#define HIROCE3_DRV_AUTHOR "Huawei Technologies CO., Ltd"
+#define HIROCE3_DRV_DESC "Huawei(R) Intelligent Network Interface Card, RoCE Driver"
+#define HIROCE3_DRV_VERSION ""
+
+#define ROCE_IB_UVERBS_ABI_VERSION 1
+#define ROCE_ULD_DEV_NAME_LEN 16
+
+#define MAX_CEQ_NEED 256
+#define MS_DELAY 5
+#define US_PERF_DELAY 100
+
+#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 0640
+
+#define ALPHA_THREADHOLD_UNIT_SHIFT 3
+
+#define PAGE_4K_SHIFT 12
+
+#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)
+
+enum {
+ ROCE3_2_PORT_NUM = 2,
+ ROCE3_4_PORT_NUM = 4
+};
+
+enum {
+ ROCE3_25G_PORT_SPEED = 25,
+ ROCE3_100G_PORT_SPEED = 100
+};
+
+enum {
+ ROCE3_INVALID_HCA = -1,
+ ROCE3_2_100G_HCA = 0,
+ ROCE3_4_25G_HCA = 1,
+ ROCE3_2_25G_HCA = 2
+};
+
+enum ROCE3_100G_BW_PARAM_E {
+ ROCE3_100G_CIR = 46500000,
+ ROCE3_100G_PIR = 52500000,
+ ROCE3_100G_CNP = 100
+};
+
+enum ROCE3_25G_BW_PARAM_E {
+ ROCE3_25G_CIR = 23200000,
+ ROCE3_25G_PIR = 25500000,
+ ROCE3_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
+};
+
+#define roce3_pr_err_once pr_err_once
+
+/* BIG/LITTLE ENGIAN switch */
+#ifdef HW_CONVERT_ENDIAN
+#define roce3_convert_be32(val) (val)
+#define roce3_convert_cpu32(val) (val)
+#define roce3_more_be32(val) cpu_to_be32(val)
+#else
+#define roce3_convert_be32(val) cpu_to_be32(val)
+#define roce3_convert_cpu32(val) be32_to_cpu(val)
+#define roce3_more_be32(val) (val)
+#endif
+
+enum roce3_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,
+
+ /* NOF AA err */
+ OFED_NOF_AA_QP_DISCONNECT = 64,
+ OFED_NOF_AA_MASTER_CHANGE,
+
+ INVAL_ET_ERR
+};
+
+enum {
+ ROCE_CMD_TIME_CLASS_A = 3000,
+ ROCE_CMD_TIME_CLASS_B = 4000,
+ ROCE_CMD_TIME_CLASS_C = 5000
+};
+
+enum roce3_sgl_mode {
+ ROCE_DOUBLE_SGL = 0,
+ ROCE_SINGLE_SGL
+};
+
+enum roce3_qpc_mtucode {
+ ROCE_MTU_CODE_256 = 0x0,
+ ROCE_MTU_CODE_512 = 0x1,
+ ROCE_MTU_CODE_1K = 0x3,
+ ROCE_MTU_CODE_2K = 0x7,
+ ROCE_MTU_CODE_4K = 0xf
+};
+
+enum roce3_ctrl_status {
+ ROCE3_PORT_EVENT = BIT(0)
+};
+
+#define ROCE_DEFAULT_PORT_NUM 1
+
+#if defined(ROCE_VBS_EN) || defined(ROCE_CHIP_TEST)
+#define ROCE_UVERBS_CMD_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_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) | \
+ (1ULL << IB_USER_VERBS_CMD_OPEN_QP))
+#else
+#define ROCE_UVERBS_CMD_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_REREG_MR) | \
+ (1ULL << IB_USER_VERBS_CMD_DEREG_MR) | \
+ (1ULL << IB_USER_VERBS_CMD_ALLOC_MW) | \
+ (1ULL << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | \
+ (1ULL << IB_USER_VERBS_CMD_DEALLOC_MW) | \
+ (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_ATTACH_MCAST) | \
+ (1ULL << IB_USER_VERBS_CMD_DETACH_MCAST) | \
+ (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_OPEN_XRCD) | \
+ (1ULL << IB_USER_VERBS_CMD_CLOSE_XRCD) | \
+ (1ULL << IB_USER_VERBS_CMD_CREATE_XSRQ) | \
+ (1ULL << IB_USER_VERBS_CMD_OPEN_QP))
+#endif
+
+#define ROCE_UVERBS_EXT_CMD_MASK (1ULL << IB_USER_VERBS_EX_CMD_MODIFY_CQ)
+
+enum roce3_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 roce3_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 ((int)(1L << 20))
+
+struct roce3_notifier {
+ struct notifier_block nb;
+ struct notifier_block nb_inet;
+ struct notifier_block nb_inet6;
+};
+
+struct roce3_buf_list {
+ void *buf;
+ dma_addr_t map;
+};
+
+struct roce3_buf {
+ struct roce3_buf_list direct;
+ struct roce3_buf_list *page_list;
+ int nbufs;
+
+ int npages;
+ int page_shift;
+};
+
+struct roce3_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 roce3_qp_cnt {
+ struct mutex cur_qps_mutex;
+ u32 alloc_qp_cnt;
+ u32 del_qp_cnt;
+};
+
+struct roce3_cdev_file {
+ struct roce3_cdev *cdev;
+};
+
+struct roce3_cdev {
+ struct cdev cdev;
+ /*lint -e104 -e808*/
+ struct class *cdev_class;
+ /*lint +e104 +e808*/
+ struct device *dev;
+ int dev_num;
+ dev_t dev_major;
+};
+
+struct roce3_netlink {
+ int dev_num;
+};
+
+struct roce3_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;
+};
+
+bool roce3_is_roceaa(u8 scence_id);
+
+struct roce3_dev_cfg_info {
+ u8 scence_id; /* load scenes ID as aa_en */
+ u8 lb_en; /* load balance enable */
+ u8 lb_mode; /* load balance mode */
+ u8 rsvd;
+
+ 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 master_func; /* nofaa master func */
+ u8 rsvd1;
+};
+
+struct roce3_device {
+ struct ib_device ib_dev;
+ struct hinic3_lld_dev *lld_dev;
+ struct net_device *ndev;
+ struct pci_dev *pdev;
+ void *hwdev;
+ void *hwdev_hdl;
+ // struct dev_version_info dev_ver; /*version info */
+ struct hinic3_board_info board_info;
+ struct roce3_cdev cdev;
+ struct roce3_netlink netlink_dev;
+
+ struct roce3_notifier notifier;
+ 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;
+ bool ib_active;
+
+ u8 group_rc_cos;
+ u8 group_ud_cos;
+ u8 group_xrc_cos;
+
+ struct roce3_dev_hw_info hw_info; /* Hw info read from nic/pcie */
+ struct roce3_dev_cfg_info cfg_info; /* Cfg data info read from MPU */
+
+#ifdef ROCE_BONDING_EN
+ int want_bond_slave_cnt;
+ int want_bond_slave_bits[2]; /* The maximum number of bonds supported is 2 */
+ enum ib_port_state port_state;
+ struct hinic3_dcb_state dcb_info;
+ char *sdi_bond_name;
+ struct roce3_bond_device *bond_dev;
+#endif
+
+ struct mutex mac_vlan_mutex;
+ struct list_head mac_vlan_list_head;
+ struct net_device **gid_dev;
+
+ struct roce3_ecn_ctx ecn_ctx;
+ struct roce3_dfx_ctx dfx_ctx;
+
+ struct roce3_qp_cnt qp_cnt;
+
+ 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;
+ // mailbox, ppf store all pf's roce device, to improve the effiency.
+ void *pri_roce_dev[ROCE_MAX_PORT_NUM];
+ bool is_vroce;
+};
+
+static inline struct roce3_device *to_roce3_dev(const struct ib_device *ibdev)
+{
+ return container_of(ibdev, struct roce3_device, ib_dev);
+}
+
+static inline struct roce3_ucontext *to_roce3_ucontext(const struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct roce3_ucontext, ibucontext);
+}
+
+int roce3_db_map_user(struct roce3_ucontext *context, unsigned long virt, struct roce3_db *db);
+void roce3_db_unmap_user(struct roce3_ucontext *context, struct roce3_db *db);
+
+int roce3_buf_write_mtt(struct roce3_device *rdev, struct rdma_mtt *mtt, struct tag_cqm_buf *buf);
+int roce3_umem_write_mtt(struct roce3_device *rdev, struct rdma_mtt *mtt, struct ib_umem *umem);
+
+int roce3_query_device(struct ib_device *ibdev, struct ib_device_attr *props, struct ib_udata *uhw);
+
+int roce3_modify_device(struct ib_device *ibdev, int mask, struct ib_device_modify *props);
+
+int roce3_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma);
+
+int roce3_create_cq(struct ib_cq *cq, const struct ib_cq_init_attr *attr, struct ib_udata *udata);
+
+int roce3_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
+
+int roce3_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata);
+
+int roce3_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int roce3_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata);
+
+int roce3_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata);
+
+int roce3_alloc_ucontext(struct ib_ucontext *ibucontext, struct ib_udata *udata);
+
+void roce3_dealloc_ucontext(struct ib_ucontext *ibcontext);
+
+int roce3_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata);
+
+int roce3_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata);
+
+int roce3_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int roce3_destroy_ah(struct ib_ah *ibah, u32 flags);
+
+int roce3_alloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata);
+
+int roce3_dealloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata);
+
+int roce3_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata);
+
+int roce3_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr);
+
+
+int roce3_query_port(struct ib_device *device, u8 port_num, struct ib_port_attr *port_attr);
+
+int roce3_query_gid(struct ib_device *ibdev, u8 port, int index, union ib_gid *gid);
+
+int roce3_modify_port(struct ib_device *ibdev, u8 port, int mask, struct ib_port_modify *props);
+
+int roce3_port_immutable(struct ib_device *ibdev, u8 port_num,
+ struct ib_port_immutable *immutable);
+
+struct net_device *roce3_ib_get_netdev(struct ib_device *ibdev, u8 port_num);
+
+enum rdma_link_layer roce3_port_link_layer(struct ib_device *ibdev, u8 port_num);
+
+int roce3_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey);
+
+struct ib_qp *roce3_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *qp_init_attr,
+ struct ib_udata *udata);
+
+
+int roce3_modify_cq(struct ib_cq *ibcq, u16 cq_count, u16 cq_period);
+
+int roce3_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata);
+
+int roce3_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
+
+int roce3_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
+
+
+int roce3_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata);
+
+int roce3_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 roce3_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr);
+int roce3_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr);
+
+void roce3_drain_rq(struct ib_qp *ibqp);
+
+int roce3_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
+
+int roce3_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr);
+
+struct ib_mr *roce3_get_dma_mr(struct ib_pd *ibpd, int access);
+struct ib_mr *roce3_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type, u32 max_num_sg);
+struct ib_mr *roce3_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length,
+ u64 virt_addr, int access, struct ib_udata *udata);
+
+int roce3_map_kernel_frmr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
+ int sg_nents, unsigned int *sg_offset);
+
+int roce3_dealloc_mw(struct ib_mw *ibmw);
+
+int roce3_query_device_status(struct ib_device *ibdev, int *dev_status);
+int roce3_init_cdev(struct roce3_device *rdev);
+void roce3_remove_cdev(struct roce3_device *rdev);
+int roce3_bond_get_dcb_info(struct roce3_device *rdev);
+
+int roce3_init_sysfs(struct roce3_device *rdev);
+void roce3_remove_sysfs(struct roce3_device *rdev);
+
+int roce3_is_eth_port_of_netdev(struct net_device *rdma_ndev, struct net_device *cookie);
+
+void roce3_async_event(void *svc_hd, u8 event_type, u8 *val);
+u8 roce3_async_event_level(void *svc_hd, u8 event_type, u8 *val);
+void roce3_cq_completion(void *svc_hd, u32 cqn, void *cq_handler);
+void roce3_unregister_netdev_event(struct roce3_device *rdev);
+int roce3_ifconfig_up_down_event_report(struct roce3_device *rdev, u8 net_event);
+int roce3_register_netdev_event(struct roce3_device *rdev);
+void roce3_clean_vlan_device_mac(struct roce3_device *rdev);
+void roce3_clean_real_device_mac(struct roce3_device *rdev);
+
+int roce3_ib_add_gid(const struct ib_gid_attr *attr, __always_unused void **context);
+
+int roce3_ib_del_gid(const struct ib_gid_attr *attr, __always_unused void **context);
+
+void roce3_remove_dev_file(struct roce3_device *rdev);
+int roce3_init_dev_file(struct roce3_device *rdev);
+
+#endif // ROCE_H
diff --git a/drivers/infiniband/hw/hiroce3/roce_cdev.c b/drivers/infiniband/hw/hiroce3/roce_cdev.c
new file mode 100644
index 0000000000000..93a6cfe868812
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_cdev.c
@@ -0,0 +1,1259 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/if_ether.h>
+
+#include "hinic3_hw.h"
+#include "hinic3_srv_nic.h"
+
+#include "roce.h"
+#include "roce_compat.h"
+#include "roce_mix.h"
+#include "roce_netdev.h"
+#include "roce_k_ioctl.h"
+#include "roce_cqm_cmd.h"
+#include "roce_pub_cmd.h"
+#include "roce_cdev_extension.h"
+#include "roce_verbs_cmd.h"
+#include "roce_cmd.h"
+#include "roce_srq.h"
+#include "roce_qp.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+#ifdef ROCE_EXTEND
+#include "roce_qp_extension.h"
+#endif
+
+#define P2PCOS_MAX_VALUE 2
+#define MAX_COS_NUM 0x7
+
+static long roce3_cdev_create_ah(struct roce3_device *rdev, void *buf)
+{
+ long ret;
+ struct rdma_ah_attr attr;
+ union roce3_create_ah_buf ah_buf;
+ struct ib_udata udata;
+
+ ret = (long)copy_from_user(&ah_buf, buf, sizeof(ah_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data from user\n", __func__);
+ return ret;
+ }
+
+ attr.sl = ah_buf.cmd.attr.sl;
+ attr.static_rate = ah_buf.cmd.attr.static_rate;
+ attr.ah_flags = (ah_buf.cmd.attr.is_global != 0) ? IB_AH_GRH : 0;
+ attr.port_num = ah_buf.cmd.attr.port_num;
+ attr.grh.flow_label = ah_buf.cmd.attr.grh.flow_label;
+ attr.grh.sgid_index = ah_buf.cmd.attr.grh.sgid_index;
+ attr.grh.hop_limit = ah_buf.cmd.attr.grh.hop_limit;
+ attr.grh.traffic_class = ah_buf.cmd.attr.grh.traffic_class;
+ memset(attr.roce.dmac, 0, sizeof(attr.roce.dmac));
+ memcpy(attr.grh.dgid.raw, ah_buf.cmd.attr.grh.dgid, ROCE_GID_LEN);
+
+ memset(&udata, 0, sizeof(struct ib_udata));
+ if (roce3_resolve_grh(rdev, &attr, &ah_buf.resp.vlan_id, &udata) != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to resolve grh\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(ah_buf.resp.dmac, attr.roce.dmac, ETH_ALEN);
+
+ ret = (long)copy_to_user((void __user *)buf, &ah_buf, sizeof(ah_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data to user\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+#ifdef ROCE_BONDING_EN
+
+struct roce3_get_rx_port {
+ __be32 rx_port;
+};
+
+struct roce3_get_func_table {
+ __be32 func_table_val;
+};
+
+struct roce3_get_udp_src_port {
+ __be32 udp_src_port;
+};
+
+static struct roce3_qp *roce3_cdev_lookup_rqp(struct roce3_device *rdev, u32 qpn)
+{
+ struct tag_cqm_object *cqm_obj_qp = NULL;
+ struct roce3_qp *rqp = NULL;
+
+ cqm_obj_qp = cqm_object_get(rdev->hwdev, CQM_OBJECT_SERVICE_CTX, qpn, false);
+ if (cqm_obj_qp == NULL) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Can't find rqp according to qpn(0x%x), func_id(%d)\n",
+ __func__, qpn, rdev->glb_func_id);
+ return NULL;
+ }
+
+ rqp = cqmobj_to_roce_qp(cqm_obj_qp);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_qp);
+
+ return rqp;
+}
+
+static int roce3_get_qp_func_table(struct roce3_device *rdev, u32 qpn, u32 *func_table_val)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct tag_roce_get_qp_func_table *get_func_tbl_inbuf = NULL;
+ struct roce3_get_func_table *get_func_tbl_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev,
+ &cqm_cmd_inbuf, (u16)sizeof(struct tag_roce_get_qp_func_table),
+ &cqm_cmd_outbuf, (u16)sizeof(struct tag_roce_get_qp_func_table));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ get_func_tbl_inbuf = (struct tag_roce_get_qp_func_table *)cqm_cmd_inbuf->buf;
+ get_func_tbl_inbuf->com.index = cpu_to_be32(qpn);
+ get_func_tbl_inbuf->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ ret = roce3_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_GET_QP_FUNC_TABLE,
+ cqm_cmd_inbuf, cqm_cmd_outbuf, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to send ROCE_CMD_GET_QP_FUNC_TABLE command, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+ return -1;
+ }
+ get_func_tbl_outbuf = (struct roce3_get_func_table *)cqm_cmd_outbuf->buf;
+ *func_table_val = be32_to_cpu(get_func_tbl_outbuf->func_table_val);
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+ return 0;
+}
+
+static long roce3_cdev_query_qp_tx_port(struct roce3_device *rdev, void *buf)
+{
+ long ret;
+ u32 slave_cnt;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_qp_port_buf qp_port_buf;
+ u32 func_tbl_value = 0;
+
+ memset(&qp_port_buf, 0, sizeof(qp_port_buf));
+ ret = (long)copy_from_user(&qp_port_buf, buf, sizeof(qp_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data from user\n", __func__);
+ return ret;
+ }
+
+ rqp = roce3_cdev_lookup_rqp(rdev, qp_port_buf.qpn);
+ if (rqp == NULL) {
+ pr_err("[ROCE, ERR] %s: Failed to look up rqp\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!roce3_bond_is_active(rdev)) {
+ qp_port_buf.port = 0;
+
+ ret = (long)copy_to_user((void __user *)buf, &qp_port_buf, sizeof(qp_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data to user\n", __func__);
+ return ret;
+ }
+
+ return 0;
+ }
+
+ ret = (long)roce3_get_qp_func_table(rdev, qp_port_buf.qpn, &func_tbl_value);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to get func_tbl, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ slave_cnt = func_tbl_value & 0xf;
+ if (slave_cnt == 0) {
+ pr_err("[ROCE, ERR] %s: slave_cnt is 0\n", __func__);
+ return -EINVAL;
+ }
+
+ qp_port_buf.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;
+
+ ret = (long)copy_to_user((void __user *)buf, &qp_port_buf, sizeof(qp_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data to user\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce3_modify_bond_hash_value(struct roce3_device *rdev, u32 qpn, u32 new_hash_value)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_modify_hash_value *modify_hash_value = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_modify_hash_value), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ modify_hash_value = (struct tag_roce_modify_hash_value *)cqm_cmd_inbuf->buf;
+
+ modify_hash_value->com.index = cpu_to_be32(qpn);
+ modify_hash_value->com.dw0.bs.cmd_bitmask = cpu_to_be16(VERBS_CMD_TYPE_QP_BITMASK);
+ modify_hash_value->hash_value = cpu_to_be32(new_hash_value);
+
+ ret = roce3_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_MODIFY_HASH_VALUE_QP,
+ cqm_cmd_inbuf, NULL, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to send MODIFY_HASH_VALUE_QP command, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return -1;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return 0;
+}
+
+static long roce3_cdev_set_qp_tx_port(struct roce3_device *rdev, const void *buf)
+{
+ long ret;
+ u32 new_tx_hash_value;
+ u32 slave_cnt;
+ u32 target_hash_port;
+ u32 old_hash_port;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_qp_port_buf qp_port_buf;
+ u32 func_tbl_value = 0;
+
+ ret = (long)copy_from_user(&qp_port_buf, buf, sizeof(qp_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data from user\n", __func__);
+ return ret;
+ }
+
+ /* check qp exist */
+ rqp = roce3_cdev_lookup_rqp(rdev, qp_port_buf.qpn);
+ if (rqp == NULL) {
+ pr_err("[ROCE, ERR] %s: Failed to look up rqp\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!roce3_bond_is_active(rdev))
+ return 0;
+
+ ret = (long)roce3_get_qp_func_table(rdev, qp_port_buf.qpn, &func_tbl_value);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to get func_tbl, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ slave_cnt = func_tbl_value & 0xf;
+ if (slave_cnt == 0) {
+ pr_err("[ROCE, ERR] %s: slave_cnt is 0\n", __func__);
+ return -EINVAL;
+ }
+ target_hash_port = qp_port_buf.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 = (long)roce3_modify_bond_hash_value(rdev, rqp->qpn, new_tx_hash_value);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to modify QP(0x%06x) hash value, func_id(%d)\n",
+ __func__, rqp->qpn, rdev->glb_func_id);
+ return -EIO;
+ }
+
+ rqp->tx_hash_value = new_tx_hash_value;
+
+ return 0;
+}
+
+static int roce3_get_qp_rx_port(struct roce3_device *rdev, u32 qpn, u32 *rx_port)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct tag_roce_get_qp_rx_port *get_rx_port_inbuf = NULL;
+ struct roce3_get_rx_port *get_rx_port_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev,
+ &cqm_cmd_inbuf, (u16)sizeof(struct tag_roce_get_qp_rx_port),
+ &cqm_cmd_outbuf, (u16)sizeof(struct tag_roce_get_qp_rx_port));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ get_rx_port_inbuf = (struct tag_roce_get_qp_rx_port *)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(VERBS_CMD_TYPE_QP_BITMASK);
+ ret = roce3_send_qp_lb_cmd(qpn, rdev, ROCE_CMD_GET_QP_RX_PORT,
+ cqm_cmd_inbuf, cqm_cmd_outbuf, ROCE_CMD_TIME_CLASS_A);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to send ROCE_CMD_GET_QP_RX_PORT command, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+ return -1;
+ }
+ get_rx_port_outbuf = (struct roce3_get_rx_port *)cqm_cmd_outbuf->buf;
+ *rx_port = be32_to_cpu(get_rx_port_outbuf->rx_port);
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+
+ return 0;
+}
+
+static long roce3_cdev_query_qp_rx_port(struct roce3_device *rdev, void *buf)
+{
+ long ret;
+ u32 rx_port = 0;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_qp_port_buf qp_port_buf;
+
+ memset(&qp_port_buf, 0, sizeof(qp_port_buf));
+ ret = (long)copy_from_user(&qp_port_buf, buf, sizeof(qp_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data from user\n", __func__);
+ return ret;
+ }
+
+ rqp = roce3_cdev_lookup_rqp(rdev, qp_port_buf.qpn);
+ if (rqp == NULL) {
+ pr_err("[ROCE, ERR] %s: Failed to look up rqp\n", __func__);
+ return -EINVAL;
+ }
+
+ if (rqp->qp_type != IB_QPT_RC) {
+ pr_err("[ROCE, ERR] %s: not support qp type(%d), only support RC.\n",
+ __func__, rqp->qp_type);
+ return -EINVAL;
+ }
+
+ if (!roce3_bond_is_active(rdev)) {
+ qp_port_buf.port = 0;
+
+ ret = (long)copy_to_user((void __user *)buf, &qp_port_buf, sizeof(qp_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data to user\n", __func__);
+ return ret;
+ }
+
+ return 0;
+ }
+
+ ret = (long)roce3_get_qp_rx_port(rdev, qp_port_buf.qpn, &rx_port);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get QP(0x%06x) rx port\n",
+ __func__, qp_port_buf.qpn);
+ return ret;
+ }
+
+ qp_port_buf.port = rx_port;
+
+ ret = (long)copy_to_user((void __user *)buf, &qp_port_buf, sizeof(qp_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data to user\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static long roce3_cdev_query_next_wqe_idx(struct roce3_device *rdev, void *buf)
+{
+ long ret;
+ int ret_adm;
+ struct roce3_dfx_query_inbuf dfx_query_inbuf = {0};
+ u32 out_size = (u32)sizeof(union roce3_dfx_query_outbuf);
+ union roce3_dfx_query_outbuf dfx_query_outbuf;
+ int next_wqe_idx;
+
+ ret = (long)copy_from_user(&dfx_query_inbuf, buf, sizeof(dfx_query_inbuf));
+ if (ret != 0) {
+ (void)pr_err("[ROCE] %s: Failed to copy data from user, ret(%lux)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ dfx_query_inbuf.cmd_type = ROCE_CMD_GET_SRQC_FROM_CACHE;
+ ret_adm = roce3_adm_dfx_query(rdev, &dfx_query_inbuf, sizeof(dfx_query_inbuf),
+ &dfx_query_outbuf, &out_size);
+ if (ret_adm != 0) {
+ (void)pr_err("[ROCE] %s: Failed to do roce_adm_dfx_query, ret(%d)\n",
+ __func__, ret_adm);
+ return -EINVAL;
+ }
+
+ dfx_query_outbuf.srq_ctx.dw2.value = be32_to_cpu(dfx_query_outbuf.srq_ctx.dw2.value);
+ dfx_query_outbuf.srq_ctx.dw3.value = be32_to_cpu(dfx_query_outbuf.srq_ctx.dw3.value);
+ dfx_query_outbuf.srq_ctx.dw5.value = be32_to_cpu(dfx_query_outbuf.srq_ctx.dw5.value);
+
+ if (dfx_query_outbuf.srq_ctx.dw2.bs.container_en == 0) {
+ next_wqe_idx = (int)(dfx_query_outbuf.srq_ctx.dw5.bs.next_wqe_idx);
+ } else {
+ u32 container_mode = MAX_SUPPORT_CONTAINER_MODE -
+ dfx_query_outbuf.srq_ctx.dw2.bs_c.container_size;
+ u32 container_size = roce3_get_container_sz(container_mode);
+
+ next_wqe_idx = (int)(container_size *
+ dfx_query_outbuf.srq_ctx.dw3.bs_c.head_index);
+ }
+ ret = (long)copy_to_user((void __user *)buf, &next_wqe_idx, sizeof(int));
+ if (ret != 0) {
+ (void)pr_err(
+ "[ROCE] %s: Failed to copy next_wqe_idx to user, ret(0x%lx)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce3_cdev_set_bond_port_info(struct roce3_bond_device *bond_dev,
+ u32 func_tbl_value, struct roce3_bond_port_info_buf *bond_port_info_buf)
+{
+ u32 i;
+
+ bond_port_info_buf->original_port_num = bond_dev->slave_cnt;
+ mutex_lock(&bond_dev->slave_lock);
+ for (i = 0; i < bond_dev->slave_cnt; i++)
+ bond_port_info_buf->original_port[i] = bond_dev->slaves[i].func_id;
+
+ mutex_unlock(&bond_dev->slave_lock);
+
+ bond_port_info_buf->alive_port_num = func_tbl_value & 0xf;
+ for (i = 0; i < bond_port_info_buf->alive_port_num; i++) {
+ bond_port_info_buf->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;
+ }
+}
+
+static long roce3_cdev_query_bond_port_info(struct roce3_device *rdev, void *buf)
+{
+ long ret;
+ struct roce3_bond_device *bond_dev = NULL;
+ struct roce3_bond_port_info_buf bond_port_info_buf;
+ u32 func_tbl_value = 0;
+
+ memset(&bond_port_info_buf, 0, sizeof(bond_port_info_buf));
+
+ if (!roce3_bond_is_active(rdev)) {
+ ret = (long)copy_to_user((void __user *)buf, &bond_port_info_buf,
+ sizeof(bond_port_info_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data to user\n", __func__);
+ return ret;
+ }
+
+ return 0;
+ }
+
+ bond_dev = rdev->bond_dev;
+ if (bond_dev == NULL) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Can't find bond_dev, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ ret = roce3_get_func_table(rdev->hwdev, rdev->glb_func_id, &func_tbl_value);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to get func_tbl, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ roce3_cdev_set_bond_port_info(bond_dev, func_tbl_value, &bond_port_info_buf);
+
+ ret = (long)copy_to_user((void __user *)buf, &bond_port_info_buf,
+ sizeof(bond_port_info_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data to user\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce3_modify_udp_src_port(struct roce3_device *rdev, u32 qpn, u32 new_udp_src_port)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_modify_udp_src_port *modify_udp_src_port = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_modify_udp_src_port),
+ NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ modify_udp_src_port = (struct tag_roce_modify_udp_src_port *)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->udp_src_port = cpu_to_be32(new_udp_src_port);
+
+ ret = roce3_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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to send MODIFY_HASH_VALUE_QP command, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+ return -1;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return 0;
+}
+
+static long roce3_cdev_set_qp_udp_src_port(struct roce3_device *rdev, const void *buf)
+{
+ long ret;
+ struct roce3_qp *rqp = NULL;
+ struct roce3_qp_udp_src_port_buf qp_udp_src_port_buf;
+
+ ret = (long)copy_from_user(&qp_udp_src_port_buf, buf, sizeof(qp_udp_src_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data from user\n", __func__);
+ return ret;
+ }
+
+ /* check qp exist */
+ rqp = roce3_cdev_lookup_rqp(rdev, qp_udp_src_port_buf.qpn);
+ if (rqp == NULL) {
+ pr_err("[ROCE, ERR] %s: Failed to look up rqp\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = (long)roce3_modify_udp_src_port(rdev, rqp->qpn, qp_udp_src_port_buf.udp_src_port);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to modify QP(0x%06x) hash value, func_id(%d)\n",
+ __func__, rqp->qpn, rdev->glb_func_id);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int roce3_get_qp_udp_src_port(struct roce3_device *rdev, u32 qpn, u32 *udp_src_port)
+{
+ int ret;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct roce_get_qp_udp_src_port *get_udp_src_port = NULL;
+ struct roce3_get_udp_src_port *get_udp_src_port_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev,
+ &cqm_cmd_inbuf, (u16)sizeof(struct roce_get_qp_udp_src_port),
+ &cqm_cmd_outbuf, (u16)sizeof(struct roce_get_qp_udp_src_port));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ get_udp_src_port = (struct roce_get_qp_udp_src_port *)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(VERBS_CMD_TYPE_QP_BITMASK);
+
+ ret = roce3_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) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to send ROCE_CMD_GET_QP_RX_PORT command, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+ return -1;
+ }
+
+ get_udp_src_port_outbuf = (struct roce3_get_udp_src_port *)cqm_cmd_outbuf->buf;
+ *udp_src_port = be32_to_cpu(get_udp_src_port_outbuf->udp_src_port);
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+
+ return 0;
+}
+
+static long roce3_cdev_query_qp_udp_src_port(struct roce3_device *rdev, void *buf)
+{
+ long ret;
+ u32 udp_src_port = 0;
+ struct roce3_qp_udp_src_port_buf qp_udp_src_port_buf;
+
+ memset(&qp_udp_src_port_buf, 0, sizeof(qp_udp_src_port_buf));
+ ret = (long)copy_from_user(&qp_udp_src_port_buf, buf, sizeof(qp_udp_src_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data from user\n", __func__);
+ return ret;
+ }
+
+ ret = (long)roce3_get_qp_udp_src_port(rdev, qp_udp_src_port_buf.qpn, &udp_src_port);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get QP(0x%06x) udp src port\n",
+ __func__, qp_udp_src_port_buf.qpn);
+ return ret;
+ }
+
+ qp_udp_src_port_buf.udp_src_port = udp_src_port;
+
+ ret = (long)copy_to_user((void __user *)buf,
+ &qp_udp_src_port_buf, sizeof(qp_udp_src_port_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data to user\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+#endif
+
+static int roce3_cdev_open(struct inode *inode, struct file *filp)
+{
+ struct roce3_cdev *dev = NULL;
+ struct roce3_cdev_file *file = NULL;
+
+ file = kzalloc(sizeof(*file), GFP_KERNEL);
+ if (file == NULL)
+ return -ENOMEM;
+
+ dev = container_of(inode->i_cdev, struct roce3_cdev, cdev);
+ file->cdev = dev;
+ filp->private_data = file;
+
+ return 0;
+}
+
+static int roce3_cdev_close(struct inode *inode, struct file *filp)
+{
+ struct roce3_cdev_file *file = filp->private_data;
+
+ kfree(file);
+
+ return 0;
+}
+
+static ssize_t roce3_cdev_read(struct file *fp, char __user *buf, size_t size, loff_t *pos)
+{
+ (void)(fp);
+ (void)(buf);
+ (void)(size);
+ (void)(pos);
+ return -EOPNOTSUPP;
+}
+
+static ssize_t roce3_cdev_write(struct file *fp, const char __user *buf, size_t size, loff_t *pos)
+{
+ (void)(fp);
+ (void)(buf);
+ (void)(size);
+ (void)(pos);
+ return -EOPNOTSUPP;
+}
+
+#ifdef ROCE_BONDING_EN
+static long roce3_cdev_bonding_ioctl_part_1(unsigned int cmd,
+ unsigned long arg, struct roce3_device *rdev)
+{
+ long ret = 0;
+
+ switch (cmd) {
+ case ROCE_CMD_QUERY_QP_TX_PORT:
+ ret = roce3_cdev_query_qp_tx_port(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: roce3_cdev_query_qp_tx_port failed.\n", __func__);
+ return ret;
+ }
+ break;
+
+ case ROCE_CMD_SET_QP_TX_PORT:
+ ret = roce3_cdev_set_qp_tx_port(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: roce3_cdev_set_qp_tx_port failed.\n", __func__);
+ return ret;
+ }
+ break;
+ case ROCE_CMD_QUERY_QP_RX_PORT:
+ ret = roce3_cdev_query_qp_rx_port(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: roce3_cdev_query_qp_rx_port failed.\n", __func__);
+ return ret;
+ }
+ break;
+ default:
+ pr_err("[ROCE, ERR] %s: Not supported cmd(%d).\n", __func__, cmd);
+ ret = -1;
+ return ret;
+ }
+
+ return ret;
+}
+
+static long roce3_cdev_bonding_ioctl_part_2(unsigned int cmd,
+ unsigned long arg, struct roce3_device *rdev)
+{
+ long ret = 0;
+
+ switch (cmd) {
+ case ROCE_CMD_QUERY_BOND_PORT_INFO:
+ ret = roce3_cdev_query_bond_port_info(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: roce3_cdev_query_qp_tx_port failed.\n", __func__);
+ return ret;
+ }
+ break;
+
+ case ROCE_CMD_SET_QP_UDP_SRC_PORT:
+ ret = roce3_cdev_set_qp_udp_src_port(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: roce3_cdev_set_qp_tx_port failed.\n", __func__);
+ return ret;
+ }
+ break;
+ case ROCE_CMD_QUERY_QP_UDP_SRC_PORT:
+ ret = roce3_cdev_query_qp_udp_src_port(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: roce3_cdev_query_qp_rx_port failed.\n", __func__);
+ return ret;
+ }
+ break;
+
+ case ROCE_CMD_QUERY_NEXT_WQE_IDX:
+ ret = roce3_cdev_query_next_wqe_idx(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: roce3_cdev_query_next_wqe_idx failed.\n", __func__);
+ return ret;
+ }
+ break;
+
+ default:
+ pr_err("[ROCE, ERR] %s: Not supported cmd(%d).\n", __func__, cmd);
+ ret = -1;
+ return ret;
+ }
+
+ return ret;
+}
+static long roce3_cdev_ioctl_bonding(unsigned int cmd, unsigned long arg, struct roce3_device *rdev)
+{
+ long ret = 0;
+
+ if (cmd < ROCE_CMD_QUERY_BOND_PORT_INFO) {
+ ret = roce3_cdev_bonding_ioctl_part_1(cmd, arg, rdev);
+ if (ret != 0)
+ return ret;
+ } else {
+ ret = roce3_cdev_bonding_ioctl_part_2(cmd, arg, rdev);
+ if (ret != 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int roce3_bond_get_dcb_info_from_buddy(struct roce3_device *rdev,
+ struct roce3_bond_device *bond_dev)
+{
+ int i;
+ int ret;
+ struct roce3_bond_slave *slave = NULL;
+ struct hinic3_lld_dev *lld_dev = NULL;
+ struct hinic3_dcb_state dcb_info, buddy_dcb_info;
+
+ 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;
+
+ if ((bond_dev->attr.active_slaves & (1U << slave->func_id)) == 0)
+ continue;
+
+ memset(&buddy_dcb_info, 0, sizeof(buddy_dcb_info));
+
+ lld_dev = hinic3_get_lld_dev_by_netdev(slave->netdev);
+ if (!lld_dev) {
+ mutex_unlock(&bond_dev->slave_lock);
+ return -ENODEV;
+ }
+ ret = hinic3_get_dcb_state(lld_dev->hwdev, &buddy_dcb_info);
+ if (ret != 0) {
+ mutex_unlock(&bond_dev->slave_lock);
+ pr_err("[ROCE, ERR] %s: Failed to get dcb state, ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ memset(&dcb_info, 0, sizeof(dcb_info));
+
+ ret = hinic3_get_dcb_state(rdev->hwdev, &dcb_info);
+ if (ret != 0) {
+ mutex_unlock(&bond_dev->slave_lock);
+ pr_err("[ROCE, ERR] %s: Failed to get dcb state, ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ buddy_dcb_info.default_cos = dcb_info.default_cos;
+ for (i = 0; i < NIC_DCB_UP_MAX; i++) {
+ if (buddy_dcb_info.pcp2cos[i] > P2PCOS_MAX_VALUE)
+ buddy_dcb_info.pcp2cos[i] = dcb_info.default_cos;
+ }
+
+ memcpy(&rdev->dcb_info, &buddy_dcb_info, sizeof(buddy_dcb_info));
+
+ mutex_unlock(&bond_dev->slave_lock);
+ return ret;
+ }
+
+ mutex_unlock(&bond_dev->slave_lock);
+ return 0;
+}
+
+int roce3_bond_get_dcb_info(struct roce3_device *rdev)
+{
+ bool bond_dev_up;
+ int ret;
+ struct roce3_bond_device *bond_dev = rdev->bond_dev;
+
+ if (!roce3_bond_is_active(rdev))
+ return 0;
+
+ bond_dev_up = (bond_dev->attr.active_slaves & (1U << rdev->glb_func_id)) != 0;
+ if (!bond_dev_up) {
+ ret = hinic3_get_dcb_state(rdev->hwdev, &rdev->dcb_info);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get dcb state, ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ } else {
+ ret = roce3_bond_get_dcb_info_from_buddy(rdev, bond_dev);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get dcb state from buddy, ret(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static long roce3_cdev_query_dcb(struct roce3_device *rdev, void *buf)
+{
+ union roce3_query_dcb_buf dcb_buf;
+ long ret;
+ int get_group_id;
+ struct roce_group_id group_id = {0};
+ u8 cos;
+
+ ret = (long)copy_from_user(&dcb_buf, buf, sizeof(dcb_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data from user\n", __func__);
+ return ret;
+ }
+
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_get_dcb_info(rdev) != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get dcb info, ret(%lu)\n", __func__, ret);
+ return (-EINVAL);
+ }
+#endif
+
+ ret = (long)roce3_get_dcb_cfg_cos(rdev,
+ (struct roce3_get_cos_inbuf *)(void *)(&dcb_buf), &cos);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get cos from dcb, ret:%ld\n", __func__, ret);
+ return ret;
+ }
+
+ dcb_buf.resp.cos = cos;
+
+ if (rdev->is_vroce) {
+ get_group_id = roce3_get_group_id(rdev->glb_func_id, rdev->hwdev, &group_id);
+ if (get_group_id != 0) {
+ pr_warn("Failed to get group id, ret(%d)", get_group_id);
+ } else {
+ rdev->group_rc_cos = group_id.group_rc_cos;
+ rdev->group_ud_cos = group_id.group_ud_cos;
+ rdev->group_xrc_cos = group_id.group_xrc_cos;
+ }
+ if (dcb_buf.cmd.dscp_type == (u8)IB_QPT_RC)
+ dcb_buf.resp.cos = rdev->group_rc_cos & MAX_COS_NUM;
+ else if (dcb_buf.cmd.dscp_type == (u8)IB_QPT_UD)
+ dcb_buf.resp.cos = rdev->group_ud_cos & MAX_COS_NUM;
+ else
+ dcb_buf.resp.cos = rdev->group_xrc_cos & MAX_COS_NUM;
+ }
+
+ ret = (long)copy_to_user((void __user *)buf, &dcb_buf, sizeof(dcb_buf));
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to copy data to user\n", __func__);
+ return ret;
+ }
+ return 0;
+}
+
+static long roce3_cdev_ioctl_non_bonding(unsigned int cmd,
+ struct roce3_device *rdev, unsigned long arg)
+{
+ long ret = 0;
+
+ switch (cmd) {
+ case ROCE_CMD_QUERY_DCB:
+ ret = roce3_cdev_query_dcb(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: roce3_cdev_query_dcb failed.\n", __func__);
+ return ret;
+ }
+ break;
+
+ case ROCE_CMD_CREATE_AH:
+ ret = roce3_cdev_create_ah(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: roce3_cdev_create_ah failed.\n", __func__);
+ return ret;
+ }
+ break;
+
+ default:
+ ret = ioctl_non_bonding_extend(cmd, rdev, arg);
+ if (ret != NOT_SUPOORT_TYPE)
+ return ret;
+
+ pr_err("[ROCE, ERR] %s: Not supported cmd(%d).\n", __func__, cmd);
+ ret = -1;
+ return ret;
+ }
+
+ return ret;
+}
+
+static long roce3_ioctrl_version(struct roce3_device *rdev, void *buf);
+static long roce3_ioctrl_reserved_1(struct roce3_device *rdev, void *buf);
+static long roce3_ioctrl_reserved_2(struct roce3_device *rdev, void *buf);
+static long roce3_ioctrl_reserved_3(struct roce3_device *rdev, void *buf);
+static long roce3_ioctrl_reserved_4(struct roce3_device *rdev, void *buf);
+static long roce3_ioctrl_reserved_5(struct roce3_device *rdev, void *buf);
+static long roce3_ioctrl_reserved_6(struct roce3_device *rdev, void *buf);
+
+struct tag_HW_ROCE_IOCTL_ACTION {
+ unsigned int cmd;
+ long (*action_func)(struct roce3_device *rdev, void *buf);
+};
+
+static struct tag_HW_ROCE_IOCTL_ACTION ioctl_reserved_tbl[] = {
+ {HW_ROCE_CMD_VERSION, roce3_ioctrl_version},
+ {HW_ROCE_CMD_RESERVED_1, roce3_ioctrl_reserved_1},
+ {HW_ROCE_CMD_RESERVED_2, roce3_ioctrl_reserved_2},
+ {HW_ROCE_CMD_RESERVED_3, roce3_ioctrl_reserved_3},
+ {HW_ROCE_CMD_RESERVED_4, roce3_ioctrl_reserved_4},
+ {HW_ROCE_CMD_RESERVED_5, roce3_ioctrl_reserved_5},
+ {HW_ROCE_CMD_RESERVED_6, roce3_ioctrl_reserved_6},
+};
+
+static long roce3_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ long ret = 0;
+ struct roce3_device *rdev = NULL;
+ struct roce3_cdev_file *cdev_file = NULL;
+ unsigned int idx = 0;
+
+ if (_IOC_TYPE(cmd) != ROCE_IOCTL_MAGIC) {
+ pr_err("[ROCE, ERR] %s: ROCE_IOCTL_MAGIC check failed.\n", __func__);
+ return -EINVAL;
+ }
+
+ cdev_file = filp->private_data;
+ rdev = container_of(cdev_file->cdev, struct roce3_device, cdev);
+
+ if (cmd < ROCE_CMD_QUERY_QP_TX_PORT) {
+ ret = roce3_cdev_ioctl_non_bonding(cmd, rdev, arg);
+ return ret;
+ }
+#ifdef ROCE_BONDING_EN
+ else if (cmd < ROCE_CMD_MAX) {
+ ret = roce3_cdev_ioctl_bonding(cmd, arg, rdev);
+ return ret;
+ }
+#endif
+#ifdef ROCE_EXTEND
+ else if (cmd == HW_ROCE_EXT_CMD_SET_QP_ATTR) {
+ ret = (long)roce3_set_qp_ext_attr(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0)
+ pr_err("[ROCE, ERR] %s: roce3_set_qp_ext_attr failed.\n", __func__);
+
+ return ret;
+ } else if (cmd == HW_ROCE_EXT_CMD_CREATE_SQPC) {
+ ret = (long)roce3_vbs_create_sqpc(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0)
+ pr_err("[ROCE, ERR] %s: roce3_vbs_create_sqpc failed.\n", __func__);
+
+ return ret;
+ }
+#endif
+
+ for (idx = 0; idx < sizeof(ioctl_reserved_tbl) / sizeof((ioctl_reserved_tbl)[0]); idx++) {
+ if (cmd == ioctl_reserved_tbl[idx].cmd &&
+ ioctl_reserved_tbl[idx].action_func != NULL) {
+ ret = ioctl_reserved_tbl[idx].action_func(rdev, (void *)(uintptr_t)arg);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: cmd 0x%x ioctl action failed ret %ld.\n",
+ __func__, cmd, ret);
+ }
+ return ret; // cmd excute end
+ }
+ }
+ // unsupport cmd
+ pr_err("[ROCE, ERR] %s: Not supported cmd(%d).\n", __func__, cmd);
+ return -EOPNOTSUPP;
+}
+
+static const struct file_operations roce3_cdev_fops = {
+ .owner = THIS_MODULE,
+ .open = roce3_cdev_open,
+ .release = roce3_cdev_close,
+ .read = roce3_cdev_read,
+ .write = roce3_cdev_write,
+ .unlocked_ioctl = roce3_cdev_ioctl,
+};
+
+#define ROCE_BASE_CDEV_MAJOR 232
+#define ROCE_BASE_CDEV_MINOR 256
+#define ROCE_MAX_DEVICES 256
+
+/*lint -e708*/
+static DEFINE_SPINLOCK(map_lock);
+/*lint +e708*/
+static DECLARE_BITMAP(dev_map, ROCE_MAX_DEVICES);
+
+static char *roce3_devnode(struct device *dev, umode_t *mode)
+{
+ if (mode)
+ *mode = DEFAULT_ROCE_DEV_NODE_PRI;
+
+ return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
+}
+
+static int roce3_init_cdev_info(struct roce3_device *rdev)
+{
+ int ret;
+
+ cdev_init(&rdev->cdev.cdev, &roce3_cdev_fops);
+ rdev->cdev.cdev.owner = THIS_MODULE;
+ rdev->cdev.cdev.ops = &roce3_cdev_fops;
+
+ ret = cdev_add(&rdev->cdev.cdev, rdev->cdev.dev_major, 1);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Add cdev failed, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_add_cdev;
+ }
+
+ /*lint -e160*/
+ rdev->cdev.cdev_class = class_create(THIS_MODULE, rdev->ib_dev.name);
+ /*lint +e160*/
+ if (IS_ERR(rdev->cdev.cdev_class)) {
+ ret = (int)PTR_ERR(rdev->cdev.cdev_class);
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Create class failed, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_create_class;
+ }
+
+ /*lint -e10 -e40 -e63*/
+ rdev->cdev.cdev_class->devnode = roce3_devnode;
+ /*lint +e10 +e40 +e63*/
+
+ rdev->cdev.dev = device_create(rdev->cdev.cdev_class, NULL,
+ rdev->cdev.dev_major, NULL, "%s", rdev->ib_dev.name);
+ if (IS_ERR(rdev->cdev.dev)) {
+ ret = (int)PTR_ERR(rdev->cdev.dev);
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Create device failed, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_create_device;
+ }
+
+ return 0;
+
+err_create_device:
+ class_destroy(rdev->cdev.cdev_class);
+
+err_create_class:
+ cdev_del(&rdev->cdev.cdev);
+
+err_add_cdev:
+ return ret;
+}
+
+int roce3_init_cdev(struct roce3_device *rdev)
+{
+ int ret;
+
+ spin_lock(&map_lock);
+ rdev->cdev.dev_num = (int)find_first_zero_bit(dev_map, ROCE_MAX_DEVICES);
+ if (rdev->cdev.dev_num >= ROCE_MAX_DEVICES) {
+ spin_unlock(&map_lock);
+ return -ENOMEM;
+ }
+
+ rdev->cdev.dev_major = MKDEV(ROCE_BASE_CDEV_MAJOR,
+ (u32)rdev->cdev.dev_num + ROCE_BASE_CDEV_MINOR);
+ set_bit((u32)rdev->cdev.dev_num, dev_map);
+ spin_unlock(&map_lock);
+
+ ret = register_chrdev_region(rdev->cdev.dev_major, 1, rdev->ib_dev.name);
+ if (ret == -EBUSY) {
+ /* alloc dynamic cdev by OS */
+ ret = alloc_chrdev_region(&(rdev->cdev.dev_major),
+ ROCE_BASE_CDEV_MINOR, 1, rdev->ib_dev.name);
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: alloc cdev region, major(%d), minor(%d), func_id(%d), ret(%d)\n",
+ __func__, MAJOR(rdev->cdev.dev_major),
+ MINOR(rdev->cdev.dev_major), rdev->glb_func_id, ret);
+ }
+
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Register region failed, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ goto err_register_region;
+ }
+
+ ret = roce3_init_cdev_info(rdev);
+ if (ret != 0)
+ goto err_init_cdev_info;
+
+ return 0;
+
+err_init_cdev_info:
+ unregister_chrdev_region(rdev->cdev.dev_major, 1);
+
+err_register_region:
+ clear_bit(rdev->cdev.dev_num, dev_map);
+
+ return ret;
+}
+
+void roce3_remove_cdev(struct roce3_device *rdev)
+{
+ device_destroy(rdev->cdev.cdev_class, rdev->cdev.dev_major);
+
+ class_destroy(rdev->cdev.cdev_class);
+
+ cdev_del(&rdev->cdev.cdev);
+
+ unregister_chrdev_region(rdev->cdev.dev_major, 1);
+
+ clear_bit(rdev->cdev.dev_num, dev_map);
+}
+
+// get version
+static long roce3_ioctrl_version(struct roce3_device *rdev, void *buf)
+{
+ char ver[VERSION_LEN] = "1.01";
+ long ret = copy_to_user(buf, ver, VERSION_LEN);
+ return ret;
+}
+
+static long roce3_ioctrl_reserved_1(struct roce3_device *rdev, void *buf)
+{
+ (void)(rdev);
+ (void)(buf);
+ return NOT_SUPOORT_TYPE;
+}
+
+static long roce3_ioctrl_reserved_2(struct roce3_device *rdev, void *buf)
+{
+ (void)(rdev);
+ (void)(buf);
+ return NOT_SUPOORT_TYPE;
+}
+
+static long roce3_ioctrl_reserved_3(struct roce3_device *rdev, void *buf)
+{
+ (void)(rdev);
+ (void)(buf);
+ return NOT_SUPOORT_TYPE;
+}
+
+static long roce3_ioctrl_reserved_4(struct roce3_device *rdev, void *buf)
+{
+ (void)(rdev);
+ (void)(buf);
+ return NOT_SUPOORT_TYPE;
+}
+
+static long roce3_ioctrl_reserved_5(struct roce3_device *rdev, void *buf)
+{
+ (void)(rdev);
+ (void)(buf);
+ return NOT_SUPOORT_TYPE;
+}
+
+static long roce3_ioctrl_reserved_6(struct roce3_device *rdev, void *buf)
+{
+ (void)(rdev);
+ (void)(buf);
+ return NOT_SUPOORT_TYPE;
+}
+
diff --git a/drivers/infiniband/hw/hiroce3/roce_cmd.c b/drivers/infiniband/hw/hiroce3/roce_cmd.c
new file mode 100644
index 0000000000000..33335131914bf
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_cmd.c
@@ -0,0 +1,722 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/errno.h>
+#include <linux/if_ether.h>
+#include <linux/moduleparam.h>
+
+#include "rdma_comp.h"
+#include "roce_compat.h"
+#include "roce_mpu_common.h"
+#include "roce_cmd.h"
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+int roce3_cfg_func_tbl_er_fwd_id_compact(void *hwdev, u32 bond_tbl_val, u16 func_id)
+{
+ struct roce_bond_cfg_er_fwd_id_cmd cfg_er_fwd_id_comp_info;
+ u16 out_size = (u16)sizeof(cfg_er_fwd_id_comp_info);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&cfg_er_fwd_id_comp_info, 0, sizeof(cfg_er_fwd_id_comp_info));
+ cfg_er_fwd_id_comp_info.func_id = func_id;
+ cfg_er_fwd_id_comp_info.bond_tbl_val = bond_tbl_val;
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_BOND_ER_FWD_ID_COMPACT,
+ &cfg_er_fwd_id_comp_info, sizeof(cfg_er_fwd_id_comp_info),
+ &cfg_er_fwd_id_comp_info, &out_size);
+ if ((ret != 0) || (out_size == 0) || (cfg_er_fwd_id_comp_info.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to cfg func er_fwd_id(compact), err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, cfg_er_fwd_id_comp_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_set_port_tbl_bond_state(void *hwdev, u8 bond_state, u16 func_id)
+{
+ struct roce_bond_cfg_state_cmd set_bond_state_info;
+ u16 out_size = (u16)sizeof(set_bond_state_info);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&set_bond_state_info, 0, sizeof(set_bond_state_info));
+ set_bond_state_info.func_id = func_id;
+ set_bond_state_info.bond_en = bond_state;
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_BOND_SET_STATE, &set_bond_state_info,
+ sizeof(set_bond_state_info), &set_bond_state_info, &out_size);
+ if ((ret != 0) || (out_size == 0) || (set_bond_state_info.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to cfg bond state, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, set_bond_state_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_add_mac_tbl_mac_entry(void *hwdev, u8 *mac_addr, u32 vlan_id, u16 er_fwd_id, u16 func_id)
+{
+ struct roce_cfg_mac_cmd add_mac_entry_info;
+ u16 out_size = (u16)sizeof(add_mac_entry_info);
+ int ret;
+
+ if ((hwdev == NULL) || (mac_addr == NULL)) {
+ pr_err("[ROCE, ERR] %s: Hwdev or mac_addr is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((vlan_id & ROCE_VLAN_ID_MASK) >= ROCE_VLAN_N_VID) {
+ pr_err("[ROCE, ERR] %s: Invalid vlan_id(%d)\n", __func__, vlan_id);
+ return -EINVAL;
+ }
+
+ memset(&add_mac_entry_info, 0, sizeof(add_mac_entry_info));
+ add_mac_entry_info.vni_en = 0;
+ 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;
+ memcpy(add_mac_entry_info.mac, mac_addr, ETH_ALEN);
+ ret = roce3_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)) {
+ pr_err("[ROCE, ERR] %s: Failed to add mac entry, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, add_mac_entry_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_del_mac_tbl_mac_entry(void *hwdev, u8 *mac_addr, u32 vlan_id, u16 er_fwd_id, u16 func_id)
+{
+ struct roce_cfg_mac_cmd del_mac_tbl_info;
+ u16 out_size = (u16)sizeof(del_mac_tbl_info);
+ int ret;
+
+ if ((hwdev == NULL) || (mac_addr == NULL)) {
+ pr_err("[ROCE, ERR] %s: Hwdev or mac_addr is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((vlan_id & ROCE_VLAN_ID_MASK) >= ROCE_VLAN_N_VID) {
+ pr_err("[ROCE, ERR] %s: Invalid vlan_id(%d)\n", __func__, vlan_id);
+ return -EINVAL;
+ }
+
+ memset(&del_mac_tbl_info, 0, sizeof(del_mac_tbl_info));
+ del_mac_tbl_info.vni_en = 0;
+ 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;
+ memcpy(del_mac_tbl_info.mac, mac_addr, ETH_ALEN);
+ ret = roce3_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)) {
+ pr_err("[ROCE, ERR] %s: Failed to del mac entry, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, del_mac_tbl_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void roce3_add_ipsu_tbl_mac_entry(void *hwdev, u8 *mac_addr, u32 vlan_id, u16 func_id, u8 er_id)
+{
+ struct roce_cfg_ipsu_mac_cmd ipsu_add_mac_entry_info;
+ u16 out_size = (u16)sizeof(ipsu_add_mac_entry_info);
+ int ret;
+
+#ifdef ROCE_BONDING_EN
+ if (!roce3_get_bond_ipsurx_en()) {
+ pr_err("[ROCE, INFO] %s: No need to add ipsu tbl mac entry\n", __func__);
+ return;
+ }
+#endif
+
+ if ((hwdev == NULL) || (mac_addr == NULL)) {
+ pr_err("[ROCE, ERR] %s: Hwdev or mac_addr is null\n", __func__);
+ return;
+ }
+
+ if ((vlan_id & ROCE_VLAN_ID_MASK) >= ROCE_VLAN_N_VID)
+ pr_err("[ROCE, ERR] %s: Invalid vlan_id(%d)\n", __func__, vlan_id);
+
+ memset(&ipsu_add_mac_entry_info, 0, sizeof(ipsu_add_mac_entry_info));
+ ipsu_add_mac_entry_info.func_id = func_id;
+ ipsu_add_mac_entry_info.vlanid_vni = vlan_id & ROCE_VLAN_ID_MASK;
+ ipsu_add_mac_entry_info.vni_en = 0;
+ memcpy(ipsu_add_mac_entry_info.mac, mac_addr, ETH_ALEN);
+ ipsu_add_mac_entry_info.er_id = er_id;
+ ret = roce3_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))) {
+ pr_err("[ROCE, ERR] %s: Failed to add mac entry to IPSU, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, ipsu_add_mac_entry_info.head.status, out_size);
+ return;
+ }
+
+ if (ipsu_add_mac_entry_info.head.status == ERR_EXIST)
+ pr_info("[ROCE, INFO] %s: This mac entry has been added to IPSU\n", __func__);
+}
+
+void roce3_del_ipsu_tbl_mac_entry(void *hwdev, u8 *mac_addr, u32 vlan_id, u16 func_id, u8 er_id)
+{
+ struct roce_cfg_ipsu_mac_cmd ipsu_del_mac_entry_info;
+ u16 out_size = (u16)sizeof(ipsu_del_mac_entry_info);
+ int ret;
+
+ if ((hwdev == NULL) || (mac_addr == NULL)) {
+ pr_err("[ROCE, ERR] %s: Hwdev or mac_addr is null\n", __func__);
+ return;
+ }
+
+#ifdef ROCE_BONDING_EN
+ if (!roce3_get_bond_ipsurx_en()) {
+ pr_err("[ROCE, INFO] %s: No need to del ipsu tbl mac entry\n", __func__);
+ return;
+ }
+#endif
+
+ if ((vlan_id & ROCE_VLAN_ID_MASK) >= ROCE_VLAN_N_VID) {
+ pr_err("[ROCE, ERR] %s: Invalid vlan_id(%d)\n", __func__, vlan_id);
+ return;
+ }
+
+ memset(&ipsu_del_mac_entry_info, 0, sizeof(ipsu_del_mac_entry_info));
+ ipsu_del_mac_entry_info.func_id = func_id;
+ ipsu_del_mac_entry_info.vlanid_vni = vlan_id & ROCE_VLAN_ID_MASK;
+ ipsu_del_mac_entry_info.vni_en = 0;
+ memcpy(ipsu_del_mac_entry_info.mac, mac_addr, ETH_ALEN);
+ ipsu_del_mac_entry_info.er_id = er_id;
+ ret = roce3_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))) {
+ pr_err("[ROCE, ERR] %s: Failed to del mac entry, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, ipsu_del_mac_entry_info.head.status, out_size);
+ return;
+ }
+
+ if (ipsu_del_mac_entry_info.head.status == ERR_NOT_FOUND)
+ pr_info("[ROCE, INFO] %s: This mac entry of ipsu has been deleted\n", __func__);
+}
+
+int roce3_do_cache_out(void *hwdev, u8 cl_id, u16 func_id)
+{
+ struct roce_dfx_cache_out_cmd cache_out_info;
+ u16 out_size = (u16)sizeof(cache_out_info);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&cache_out_info, 0, sizeof(cache_out_info));
+ cache_out_info.func_idx = func_id;
+ cache_out_info.cache_index = cl_id;
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_DFX_CACHE_OUT,
+ &cache_out_info, sizeof(cache_out_info), &cache_out_info, &out_size);
+ if ((ret != 0) || (out_size == 0) || (cache_out_info.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to cache out, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, cache_out_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_set_cfg_ccf_param(void *hwdev, u16 func_id, u32 *ccf_param)
+{
+ struct roce_cc_cfg_param_cmd cfg_ccf_param;
+ u16 out_size = (u16)sizeof(cfg_ccf_param);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&cfg_ccf_param, 0, sizeof(cfg_ccf_param));
+ cfg_ccf_param.func_id = func_id;
+ cfg_ccf_param.param[0] = ccf_param[0]; // 0 is param array idx
+ cfg_ccf_param.param[1] = ccf_param[1]; // 1 is param array idx
+ cfg_ccf_param.param[2] = ccf_param[2]; // 2 is param array idx
+ cfg_ccf_param.param[3] = ccf_param[3]; // 3 is param array idx
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_CC_CFG_CCF_PARAM,
+ &cfg_ccf_param, sizeof(cfg_ccf_param), &cfg_ccf_param, &out_size);
+ if ((ret != 0) || (out_size == 0) || (cfg_ccf_param.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to cfg ccf param, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, cfg_ccf_param.head.status, out_size);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_set_cfg_dcqcn_param(void *hwdev, u16 func_id, u32 *dcqcn_param)
+{
+ struct roce_cc_cfg_param_cmd cfg_dcqcn_param;
+ u16 out_size = (u16)sizeof(cfg_dcqcn_param);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&cfg_dcqcn_param, 0, sizeof(cfg_dcqcn_param));
+ cfg_dcqcn_param.func_id = func_id;
+ cfg_dcqcn_param.param[0] = dcqcn_param[0]; // 0 is param array idx
+ cfg_dcqcn_param.param[1] = dcqcn_param[1]; // 1 is param array idx
+ cfg_dcqcn_param.param[2] = dcqcn_param[2]; // 2 is param array idx
+ cfg_dcqcn_param.param[3] = dcqcn_param[3]; // 3 is param array idx
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_CC_CFG_DCQCN_PARAM,
+ &cfg_dcqcn_param, sizeof(cfg_dcqcn_param), &cfg_dcqcn_param, &out_size);
+ if ((ret != 0) || (out_size == 0) || (cfg_dcqcn_param.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to cfg dcqcn param, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, cfg_dcqcn_param.head.status, out_size);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_set_cfg_ipqcn_param(void *hwdev, u16 func_id, u32 *ipqcn_param)
+{
+ struct roce_cc_cfg_param_cmd cfg_ipqcn_param;
+ u16 out_size = (u16)sizeof(cfg_ipqcn_param);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&cfg_ipqcn_param, 0, sizeof(cfg_ipqcn_param));
+ cfg_ipqcn_param.func_id = func_id;
+ cfg_ipqcn_param.param[0] = ipqcn_param[0]; // 0 is param array idx
+ cfg_ipqcn_param.param[1] = ipqcn_param[1]; // 1 is param array idx
+ cfg_ipqcn_param.param[2] = ipqcn_param[2]; // 2 is param array idx
+ cfg_ipqcn_param.param[3] = ipqcn_param[3]; // 3 is param array idx
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_CC_CFG_IPQCN_PARAM,
+ &cfg_ipqcn_param, sizeof(cfg_ipqcn_param), &cfg_ipqcn_param, &out_size);
+ if ((ret != 0) || (out_size == 0) || (cfg_ipqcn_param.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to cfg ipqcn param, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, cfg_ipqcn_param.head.status, out_size);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_set_cfg_ldcp_param(void *hwdev, u16 func_id, u32 *ldcp_param)
+{
+ struct roce_cc_cfg_param_cmd cfg_ldcp_param;
+ u16 out_size = (u16)sizeof(cfg_ldcp_param);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&cfg_ldcp_param, 0, sizeof(cfg_ldcp_param));
+ cfg_ldcp_param.func_id = func_id;
+ cfg_ldcp_param.param[0] = ldcp_param[0]; // 0 is param array idx
+ cfg_ldcp_param.param[1] = ldcp_param[1]; // 1 is param array idx
+ cfg_ldcp_param.param[2] = ldcp_param[2]; // 2 is param array idx
+ cfg_ldcp_param.param[3] = ldcp_param[3]; // 3 is param array idx
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_CC_CFG_LDCP_PARAM,
+ &cfg_ldcp_param, sizeof(cfg_ldcp_param), &cfg_ldcp_param, &out_size);
+ if ((ret != 0) || (out_size == 0) || (cfg_ldcp_param.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to cfg ldcp param, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, cfg_ldcp_param.head.status, out_size);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_set_cap_cfg(void *hwdev, u16 index, u32 *cap_cfg)
+{
+ struct roce_dfx_cfg_cap_param_cmd set_cap_cfg;
+ u16 out_size = (u16)sizeof(set_cap_cfg);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&set_cap_cfg, 0, sizeof(set_cap_cfg));
+ set_cap_cfg.index = index;
+ set_cap_cfg.param[0] = cap_cfg[0]; // 0 is param array idx
+ set_cap_cfg.param[1] = cap_cfg[1]; // 1 is param array idx
+ set_cap_cfg.param[2] = cap_cfg[2]; // 2 is param array idx
+ set_cap_cfg.param[3] = cap_cfg[3]; // 3 is param array idx
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_DFX_SET_CAP_CFG,
+ &set_cap_cfg, sizeof(set_cap_cfg), &set_cap_cfg, &out_size);
+ if ((ret != 0) || (out_size == 0) || (set_cap_cfg.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to set cap cfg, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, set_cap_cfg.head.status, out_size);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_get_cap_cfg(void *hwdev, u16 index, u32 *cap_cfg)
+{
+ struct roce_dfx_cfg_cap_param_cmd get_cap_cfg;
+ u16 out_size = (u16)sizeof(get_cap_cfg);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&get_cap_cfg, 0, sizeof(get_cap_cfg));
+ get_cap_cfg.index = index;
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_DFX_GET_CAP_CFG,
+ &get_cap_cfg, sizeof(get_cap_cfg), &get_cap_cfg, &out_size);
+ if ((ret != 0) || (out_size == 0) || (get_cap_cfg.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to get cap cfg, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, get_cap_cfg.head.status, out_size);
+
+ return -EINVAL;
+ }
+
+ memcpy(cap_cfg, get_cap_cfg.param, sizeof(get_cap_cfg.param));
+
+ return 0;
+}
+
+int roce3_clear_cap_counter(void *hwdev, u16 index, u32 *value)
+{
+ struct roce_dfx_cap_ctr_cmd clear_cap_counter;
+ u16 out_size = (u16)sizeof(clear_cap_counter);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&clear_cap_counter, 0, sizeof(clear_cap_counter));
+ clear_cap_counter.index = index;
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_DFX_CLEAR_CAP_CTR,
+ &clear_cap_counter, sizeof(clear_cap_counter),
+ &clear_cap_counter, &out_size);
+ if ((ret != 0) || (out_size == 0) || (clear_cap_counter.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to clear cap counter, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, clear_cap_counter.head.status, out_size);
+
+ return -EINVAL;
+ }
+
+ *value = clear_cap_counter.value;
+
+ return 0;
+}
+
+int roce3_read_cap_counter(void *hwdev, u16 index, u32 *value)
+{
+ struct roce_dfx_cap_ctr_cmd read_cap_counter;
+ u16 out_size = (u16)sizeof(read_cap_counter);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&read_cap_counter, 0, sizeof(read_cap_counter));
+ read_cap_counter.index = index;
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_DFX_READ_CAP_CTR, &read_cap_counter,
+ sizeof(read_cap_counter), &read_cap_counter, &out_size);
+ if ((ret != 0) || (out_size == 0) || (read_cap_counter.head.status != 0)) {
+ pr_err("[ROCE, ERR] %s: Failed to read cap counter, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, read_cap_counter.head.status, out_size);
+
+ return -EINVAL;
+ }
+
+ *value = read_cap_counter.value;
+
+ return 0;
+}
+
+int roce3_set_func_tbl_func_state(struct roce3_device *rdev, u8 func_state)
+{
+ void *hwdev = rdev->hwdev;
+ u16 func_id = rdev->glb_func_id;
+ struct roce_set_func_state_cmd set_func_state_info;
+ u16 out_size = (u16)sizeof(set_func_state_info);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ memset(&set_func_state_info, 0, sizeof(set_func_state_info));
+ set_func_state_info.func_id = func_id;
+ set_func_state_info.func_en = func_state;
+ set_func_state_info.tag = 0;
+ ret = roce3_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)) {
+ pr_err("[ROCE, ERR] %s: Failed to set func state(%d), err(%d), status(0x%x), out size(0x%x), func_id(%d)\n",
+ __func__, func_state, ret, set_func_state_info.head.status,
+ out_size, func_id);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+int roce3_get_func_table(void *hwdev, u16 func_id, u32 *func_tbl_value)
+{
+ struct roce_get_func_table_cmd get_func_table;
+ struct roce_get_func_table_rsp get_func_table_rsp;
+ u16 out_size = (u16)sizeof(get_func_table_rsp);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ memset(&get_func_table, 0, sizeof(get_func_table));
+ memset(&get_func_table_rsp, 0, out_size);
+ get_func_table.func_id = func_id;
+ ret = roce3_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)) {
+ pr_err("[ROCE, ERR] %s: Failed to get func table, err(%d), status(0x%x), out size(0x%x), func_id(%d)\n",
+ __func__, 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 roce3_set_func_tbl_cpu_endian(void *hwdev, u8 cpu_endian, u16 func_id)
+{
+ struct roce_set_cpu_endian_cmd set_cpu_endian_info;
+ u16 out_size = (u16)sizeof(set_cpu_endian_info);
+ int ret;
+
+ if (hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&set_cpu_endian_info, 0, sizeof(set_cpu_endian_info));
+ set_cpu_endian_info.func_id = func_id;
+ set_cpu_endian_info.cpu_endian = cpu_endian;
+ ret = roce3_msg_to_mgmt_sync(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)) {
+ pr_err("[ROCE, ERR] %s: Failed to set func state, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, set_cpu_endian_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int roce3_init_cfg_info(struct roce3_device *rdev)
+{
+ struct roce_get_cfg_info_cmd get_cfg_info;
+ struct roce_get_cfg_info_resp resp;
+ u16 out_size = (u16)sizeof(resp);
+ int ret = 0;
+
+ if (rdev->hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ memset(&get_cfg_info, 0, sizeof(get_cfg_info));
+ memset(&resp, 0, sizeof(resp));
+
+ get_cfg_info.func_id = rdev->glb_func_id;
+
+ ret = roce3_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)) {
+ pr_err("[ROCE, ERR] %s: Failed to init cfg info, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, 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 = roce3_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.master_func = (u8)(resp.port_num * resp.host_num);
+
+ dev_info(rdev->hwdev_hdl, "[ROCE] %s: RoCE init,func_id(%d),lb_en(%d),lb_mode(%d),srq_mode(%d),aa_en(%d)\n",
+ __func__, 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);
+ return 0;
+}
+
+int roce3_get_group_id(u16 func_id, void *hwdev, struct roce_group_id *group_id)
+{
+ struct roce_cmd_get_group_id group_id_info;
+ u16 out_size = (u16)sizeof(group_id_info);
+ int ret;
+
+ if (hwdev == NULL) {
+ (void)pr_err("[ROCE] %s(%d): Hwdev is null\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ /* 组命令并下发给uP */
+ memset(&group_id_info, 0, sizeof(group_id_info));
+ group_id_info.func_id = func_id;
+ ret = roce3_msg_to_mgmt_sync(hwdev, ROCE_MPU_CMD_GET_GROUP_ID,
+ &group_id_info, sizeof(group_id_info), &group_id_info, &out_size);
+ if (!!ret || (!out_size) || !!group_id_info.status) {
+ (void)pr_err(
+ "[ROCE] %s(%d): Failed to get group id, ret(%d), status(%u), out size(0x%x)\n",
+ __func__, __LINE__, ret, group_id_info.status, out_size);
+ return -EINVAL;
+ }
+
+ group_id->group_rc_cos = group_id_info.group_rc_cos;
+ group_id->group_ud_cos = group_id_info.group_ud_cos;
+ group_id->group_xrc_cos = group_id_info.group_xrc_cos;
+
+ return 0;
+}
+
+int roce3_del_func_res(struct roce3_device *rdev)
+{
+ struct roce_set_func_state_cmd del_func_res_info;
+ u16 out_size = (u16)sizeof(del_func_res_info);
+ int ret;
+
+ if ((rdev == NULL) || (rdev->hwdev == NULL)) {
+ pr_err("[ROCE, ERR] %s: rdev/Hwdev is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ memset(&del_func_res_info, 0, sizeof(del_func_res_info));
+ del_func_res_info.func_id = rdev->glb_func_id;
+ ret = roce3_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)) {
+ pr_err("[ROCE, ERR] %s: Failed to set func state, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, del_func_res_info.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+int roce3_set_bw_ctrl_state(struct roce3_device *rdev, u8 cmd, struct roce3_bw_ctrl_inbuf *inbuf)
+{
+ int ret = 0;
+ struct roce_cc_cfg_bw_ctrl_cmd set_bw_ctrl;
+ u16 out_size = (u16)sizeof(set_bw_ctrl);
+
+ if (rdev->hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ memset(&set_bw_ctrl, 0, sizeof(set_bw_ctrl));
+
+ 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;
+ pr_info("[ROCE, DEBUG] %s: func_id:%u, cmd:%u, cir:%u, pir:%u, cnp:%u\n",
+ __func__, rdev->glb_func_id, set_bw_ctrl.cmd, set_bw_ctrl.cir,
+ set_bw_ctrl.pir, set_bw_ctrl.cnp);
+ ret = roce3_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)) {
+ pr_err("[ROCE, ERR] %s: Failed to set set_bw_ctrl cmd, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, set_bw_ctrl.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+int roce3_query_bw_ctrl_state(struct roce3_device *rdev, struct roce3_bw_ctrl_param *bw_ctrl_param)
+{
+ int ret = 0;
+ struct roce_cc_cfg_bw_ctrl_cmd query_bw_ctrl;
+ u16 out_size = (u16)sizeof(query_bw_ctrl);
+
+ if (rdev->hwdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Hwdev is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ memset(&query_bw_ctrl, 0, sizeof(query_bw_ctrl));
+
+ query_bw_ctrl.func_id = rdev->glb_func_id;
+ ret = roce3_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)) {
+ pr_err("[ROCE, ERR] %s: Failed to set query_bw_ctrl cmd, err(%d), status(0x%x), out size(0x%x)\n",
+ __func__, ret, query_bw_ctrl.head.status, out_size);
+ return (-EINVAL);
+ }
+
+ memcpy((void *)bw_ctrl_param,
+ (void *)((u8 *)(&query_bw_ctrl) + ROCE_CMD_DEFAULT_SIZE),
+ sizeof(struct roce3_bw_ctrl_param));
+
+ pr_info("[ROCE, DEBUG] %s: query_bw_ctrl_state:func_id:%u, cir:%u, pir:%u, cnp:%u\n",
+ __func__, rdev->glb_func_id, bw_ctrl_param->cir,
+ bw_ctrl_param->pir, bw_ctrl_param->cnp);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/roce_cmd.h b/drivers/infiniband/hw/hiroce3/roce_cmd.h
new file mode 100644
index 0000000000000..ce598e0590af8
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_cmd.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_CMD_H
+#define ROCE_CMD_H
+
+#include "roce.h"
+#include "roce_dfx.h"
+#include "roce_srq.h"
+
+#define ROCE_VLAN_ID_MASK 0x7FFF
+#define ROCE_VLAN_N_VID 4096
+#define ROCE_VNI_N_VID 0xFFFFFF
+#define ROCE_CMD_DEFAULT_SIZE 12
+
+#define ERR_EXIST 6
+#define ERR_NOT_FOUND 13
+struct roce_cmd_get_group_id {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 group_rc_cos;
+ u8 group_ud_cos;
+ u8 group_xrc_cos;
+};
+
+struct roce_group_id {
+ u8 group_rc_cos;
+ u8 group_ud_cos;
+ u8 group_xrc_cos;
+ u8 rsvd;
+};
+
+#define roce3_msg_to_mgmt_sync(hwdev, cmd, buf_in, in_size, buf_out, out_size) \
+ (hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_ROCE, cmd, buf_in, in_size, \
+ buf_out, out_size, 0, HINIC3_CHANNEL_ROCE))
+
+int roce3_cfg_func_tbl_er_fwd_id_compact(void *hwdev, u32 bond_tbl_val, u16 func_id);
+
+int roce3_set_port_tbl_bond_state(void *hwdev, u8 bond_state, u16 func_id);
+
+int roce3_add_mac_tbl_mac_entry(void *hwdev, u8 *mac_addr, u32 vlan_id, u16 er_fwd_id, u16 func_id);
+int roce3_del_mac_tbl_mac_entry(void *hwdev, u8 *mac_addr, u32 vlan_id, u16 er_fwd_id, u16 func_id);
+typedef int (*roce3_modify_mac_tbl)(void *hwdev, u8 *mac_addr, u32 vlan_id,
+ u16 er_fwd_id, u16 func_id);
+void roce3_add_ipsu_tbl_mac_entry(void *hwdev, u8 *mac_addr, u32 vlan_id, u16 func_id, u8 er_id);
+void roce3_del_ipsu_tbl_mac_entry(void *hwdev, u8 *mac_addr, u32 vlan_id, u16 func_id, u8 er_id);
+typedef void (*roce3_modify_ipsu_tbl_mac)(void *hwdev, u8 *mac_addr,
+ u32 vlan_id, u16 func_id, u8 er_id);
+
+int roce3_do_cache_out(void *hwdev, u8 cl_id, u16 func_id);
+
+int roce3_set_cfg_ccf_param(void *hwdev, u16 func_id, u32 *ccf_param);
+int roce3_set_cfg_ipqcn_param(void *hwdev, u16 func_id, u32 *ipqcn_param);
+int roce3_set_cfg_ldcp_param(void *hwdev, u16 func_id, u32 *ldcp_param);
+int roce3_set_cfg_dcqcn_param(void *hwdev, u16 func_id, u32 *dcqcn_param);
+int roce3_set_bw_ctrl_state(struct roce3_device *rdev, u8 cmd, struct roce3_bw_ctrl_inbuf *inbuf);
+int roce3_query_bw_ctrl_state(struct roce3_device *rdev, struct roce3_bw_ctrl_param *bw_ctrl_param);
+
+int roce3_set_cap_cfg(void *hwdev, u16 index, u32 *cap_cfg);
+int roce3_get_cap_cfg(void *hwdev, u16 index, u32 *cap_cfg);
+int roce3_clear_cap_counter(void *hwdev, u16 index, u32 *value);
+int roce3_read_cap_counter(void *hwdev, u16 index, u32 *value);
+
+int roce3_set_func_tbl_func_state(struct roce3_device *rdev, u8 func_state);
+int roce3_get_func_table(void *hwdev, u16 func_id, u32 *func_tbl_value);
+int roce3_set_func_tbl_cpu_endian(void *hwdev, u8 cpu_endian, u16 func_id);
+int roce3_init_cfg_info(struct roce3_device *rdev);
+int roce3_del_func_res(struct roce3_device *rdev);
+int roce3_get_group_id(u16 func_id, void *hwdev, struct roce_group_id *group_id);
+
+#endif /* ROCE_CMD_H */
diff --git a/drivers/infiniband/hw/hiroce3/roce_compat.h b/drivers/infiniband/hw/hiroce3/roce_compat.h
new file mode 100644
index 0000000000000..92e64512d51fa
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_compat.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_COMPAT_H
+#define ROCE_COMPAT_H
+
+#include <linux/delay.h>
+
+#define ROCE_LIKELY(x) /*lint -e730*/ likely(x) /*lint +e730*/
+
+#define ROCE_UNLIKELY(x) /*lint -e730*/ unlikely(x) /*lint +e730*/
+
+#define ROCE_ILOG2(n) /*lint -e866*/ ilog2(n) /*lint +e866*/
+
+#define ROCE_ROUNDUP_POW_OF_TWO(n) /*lint -e866*/ roundup_pow_of_two(n) /*lint +e866*/
+
+/*lint -e506 -e160 -e522*/
+#define ROCE_MDELAY(n) mdelay(n)
+#define ROCE_UDELAY(n) udelay(n)
+
+#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__)
+static inline void wc_wmb(void)
+{
+ asm volatile("lock; addl $0,0(%%esp) " ::: "memory");
+}
+#elif defined(__x86_64__)
+static inline void wc_wmb(void)
+{
+ asm volatile("sfence" ::: "memory");
+}
+#elif defined(__ia64__)
+static inline void wc_wmb(void)
+{
+ asm volatile("fwb" ::: "memory");
+}
+#else
+static inline void wc_wmb(void)
+{
+ /* Write memory barrier in aarch64 */
+ wmb();
+}
+#endif
+
+#endif
+
+#endif // ROCE_COMPAT_H
diff --git a/drivers/infiniband/hw/hiroce3/roce_cqm_cmd.c b/drivers/infiniband/hw/hiroce3/roce_cqm_cmd.c
new file mode 100644
index 0000000000000..3e1e2d7ad94bd
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_cqm_cmd.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_cqm_cmd.h"
+
+void roce3_cqm_cmd_free_inoutbuf(void *ex_handle, struct tag_cqm_cmd_buf *cqm_cmd_inbuf,
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf)
+{
+ if (cqm_cmd_outbuf != NULL)
+ cqm_cmd_free(ex_handle, cqm_cmd_outbuf);
+
+ if (cqm_cmd_inbuf != NULL)
+ cqm_cmd_free(ex_handle, cqm_cmd_inbuf);
+}
+
+int roce3_cqm_cmd_zalloc_inoutbuf(void *ex_handle, struct tag_cqm_cmd_buf **cqm_cmd_inbuf,
+ u16 inbuf_size, struct tag_cqm_cmd_buf **cqm_cmd_outbuf,
+ u16 outbuf_size)
+{
+ int ret;
+
+ if (cqm_cmd_inbuf != NULL) {
+ *cqm_cmd_inbuf = cqm_cmd_alloc(ex_handle);
+
+ if (*cqm_cmd_inbuf == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ (*cqm_cmd_inbuf)->size = inbuf_size;
+
+ memset((*cqm_cmd_inbuf)->buf, 0, inbuf_size);
+ }
+
+ if (cqm_cmd_outbuf != NULL) {
+ *cqm_cmd_outbuf = cqm_cmd_alloc(ex_handle);
+
+ if (*cqm_cmd_outbuf == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ (*cqm_cmd_outbuf)->size = outbuf_size;
+
+ memset((*cqm_cmd_outbuf)->buf, 0, outbuf_size);
+ }
+
+ return 0;
+err:
+ roce3_cqm_cmd_free_inoutbuf(ex_handle, *cqm_cmd_inbuf, *cqm_cmd_outbuf);
+ *cqm_cmd_inbuf = NULL;
+ *cqm_cmd_outbuf = NULL;
+ return ret;
+}
diff --git a/drivers/infiniband/hw/hiroce3/roce_cqm_cmd.h b/drivers/infiniband/hw/hiroce3/roce_cqm_cmd.h
new file mode 100644
index 0000000000000..72932ae0f87e9
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_cqm_cmd.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_CQM_CMD_H
+#define ROCE_CQM_CMD_H
+
+#include "hinic3_cqm.h"
+
+#include "roce.h"
+
+void roce3_cqm_cmd_free_inoutbuf(void *ex_handle, struct tag_cqm_cmd_buf *cqm_cmd_inbuf,
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf);
+int roce3_cqm_cmd_zalloc_inoutbuf(void *ex_handle, struct tag_cqm_cmd_buf **cqm_cmd_inbuf,
+ u16 inbuf_size, struct tag_cqm_cmd_buf **cqm_cmd_outbuf,
+ u16 outbuf_size);
+
+#endif // ROCE_CQM_CMD_H
diff --git a/drivers/infiniband/hw/hiroce3/roce_db.c b/drivers/infiniband/hw/hiroce3/roce_db.c
new file mode 100644
index 0000000000000..0869fe0ac14e4
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_db.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/kernel.h>
+
+#include "roce.h"
+
+/*
+ ****************************************************************************
+ Prototype : roce3_db_map_user
+ Description : roce3_db_map_user
+ Input : struct roce3_ucontext *context
+ unsigned long virt
+ struct roce3_db *db
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_db_map_user(struct roce3_ucontext *context, unsigned long virt, struct roce3_db *db)
+{
+ int ret = 0;
+ struct roce3_db_page *db_page = NULL;
+
+ 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 = kmalloc(sizeof(*db_page), GFP_KERNEL);
+ if (db_page == NULL) {
+ ret = -ENOMEM;
+ pr_err("[ROCE, ERR] %s: Failed to alloc DB page\n", __func__);
+ goto out;
+ }
+
+ db_page->user_virt = (virt & PAGE_MASK);
+ db_page->refcnt = 0;
+ db_page->umem = ib_umem_get(context->ibucontext.device, virt & PAGE_MASK, PAGE_SIZE, 0);
+ if (IS_ERR(db_page->umem)) {
+ ret = (int)PTR_ERR(db_page->umem);
+ pr_err("[ROCE, ERR] %s: Failed to get ib_umem ret:%d\n", __func__, ret);
+ kfree(db_page);
+ goto out;
+ }
+
+ list_add(&db_page->list, &context->db_page_list);
+
+found:
+ db->dma = sg_dma_address(db_page->umem->sg_head.sgl) + (virt & ~PAGE_MASK);
+ db->user_page = db_page;
+ ++db_page->refcnt;
+
+out:
+ mutex_unlock(&context->db_page_mutex);
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_db_unmap_user
+ Description : roce3_db_unmap_user
+ Input : struct roce3_ucontext *context
+ struct roce3_db *db
+ Output : None
+
+ 1.Date : 2015/4/29
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_db_unmap_user(struct roce3_ucontext *context, struct roce3_db *db)
+{
+ 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/hiroce3/roce_db.h b/drivers/infiniband/hw/hiroce3/roce_db.h
new file mode 100644
index 0000000000000..c4a3abb92404a
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_db.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_DB_H
+#define ROCE_DB_H
+
+#include <rdma/ib_umem.h>
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct roce3_db_page {
+ struct list_head list;
+ struct ib_umem *umem;
+ unsigned long user_virt;
+ int refcnt;
+};
+
+struct roce3_db {
+ __be32 *db_record;
+ dma_addr_t dma;
+ struct roce3_db_page *user_page;
+};
+
+static inline void roce3_write64(u32 val[2], void __iomem *dest)
+{
+ __raw_writeq(*(u64 *)(void *)val, dest);
+}
+
+#endif // ROCE_DB_H
diff --git a/drivers/infiniband/hw/hiroce3/roce_event.c b/drivers/infiniband/hw/hiroce3/roce_event.c
new file mode 100644
index 0000000000000..717cb8adffa7d
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_event.c
@@ -0,0 +1,566 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_event.h"
+#include "roce_event_extension.h"
+#include "roce_pub_cmd.h"
+#include "hinic3_mt.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+static void roce3_event_report_common_a(const struct roce3_device *rdev, int event_str_index)
+{
+ switch (event_str_index) {
+ case OFED_ET_PATH_MIG:
+ pr_err_ratelimited("[ROCE] %s: [ofed event type] Path mig. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+
+ case OFED_ET_COMM_EST:
+ /*lint -e160 -e522*/
+ roce3_pr_err_once("[ROCE] %s: [ofed event type] Communication establish. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ /*lint +e160 +e522*/
+ break;
+
+ case OFED_ET_SQ_DRAINED:
+ pr_err_ratelimited("[ROCE] %s: [ofed event type] Sq drained. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+
+ case OFED_ET_SRQ_QP_LAST_WQE:
+ /*lint -e160 -e522*/
+ roce3_pr_err_once("[ROCE] %s: [ofed event type] Srq/qp last wqe. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ /*lint +e160 +e522*/
+ break;
+
+ case OFED_ET_WQ_CATAS_ERR:
+ pr_err_ratelimited("[ROCE] %s: [ofed event type] Wq catas error. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+
+ case OFED_ET_PATH_MIG_FAILED:
+ pr_err_ratelimited("[ROCE] %s: [ofed event type] Path mig failed. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+ default:
+ break;
+ }
+}
+
+static void roce3_event_report_common_b(const struct roce3_device *rdev, int event_str_index)
+{
+ switch (event_str_index) {
+ case OFED_ET_WQ_INVAL_REQ_ERR:
+ pr_err_ratelimited("[ROCE] %s: [ofed event type] Wq inval req error. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+
+ case OFED_ET_WQ_ACCESS_ERR:
+ pr_err_ratelimited("[ROCE] %s: [ofed event type] Wq access error. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+
+ case OFED_ET_CQ_ERR:
+ pr_err_ratelimited("[ROCE] %s: [ofed event type] Cq error. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+
+ case OFED_ET_SRQ_LIMIT:
+ pr_err_ratelimited("[ROCE] %s: [ofed event type] Srq limit. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+
+ case OFED_ET_SRQ_CATAS_ERR:
+ pr_err_ratelimited("[ROCE] %s: [ofed event type] Srq catas error. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+
+ case NON_OFED_ET_QPC_LOOKUP_ERR:
+ pr_err_ratelimited("[ROCE] %s: [non ofed event type] Qpc lookup error. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ break;
+
+ case NON_OFED_ET_OTHER_TYPE_ERR:
+ /*lint -e160 -e522*/
+ roce3_pr_err_once("[ROCE] %s: [non ofed event type] other type error. function id: %u\n",
+ __func__, rdev->glb_func_id);
+ /*lint +e160 +e522*/
+ break;
+ default:
+ break;
+ }
+}
+
+static void roce3_event_report_common(const struct roce3_device *rdev, int event_str_index)
+{
+ if (event_str_index <= OFED_ET_PATH_MIG_FAILED)
+ roce3_event_report_common_a(rdev, event_str_index);
+ else
+ roce3_event_report_common_b(rdev, event_str_index);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_event_report
+ Description : roce3_event_report
+ Input : struct roce3_device *rdev
+ int event_str_index
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_event_report(struct roce3_device *rdev, int event_str_index)
+{
+ if (event_str_index <= NON_OFED_ET_OTHER_TYPE_ERR)
+ roce3_event_report_common(rdev, event_str_index);
+ else
+ roce3_event_report_extend(rdev, 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;
+ }
+}
+
+int to_unknown_event_str_index(u8 event_type, const u8 *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;
+
+ default:
+ return INVAL_ET_ERR;
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_handle_qp_async_event
+ Description : roce3_handle_qp_async_event
+ Input : struct roce3_device *rdev
+ u32 qpn
+ u8 event_type
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_handle_qp_async_event(struct roce3_device *rdev, u32 qpn, u8 event_type)
+{
+ struct roce3_qp *rqp = NULL;
+ struct tag_cqm_object *cqm_obj_queue = NULL;
+
+ cqm_obj_queue = cqm_object_get(rdev->hwdev, CQM_OBJECT_SERVICE_CTX, qpn, false);
+ if (cqm_obj_queue == NULL) {
+ dev_err_ratelimited(rdev->hwdev_hdl,
+ "[ROCE] %s: Failed to get cqm obj queue, func_id(%d), qpn:%u, event_type:%u\n",
+ __func__, rdev->glb_func_id, qpn, event_type);
+ return;
+ }
+
+ rqp = cqmobj_to_roce_qp(cqm_obj_queue);
+ roce3_qp_async_event(rdev, rqp, (int)event_type);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_queue);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_handle_cq_async_event
+ Description : roce3_handle_cq_async_event
+ Input : struct roce3_device *rdev
+ u32 cqn
+ u8 event_type
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_handle_cq_async_event(struct roce3_device *rdev, u32 cqn, u8 event_type)
+{
+ struct roce3_cq *rcq = NULL;
+ struct tag_cqm_object *cqm_obj_queue = NULL;
+
+ cqm_obj_queue = cqm_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SCQ, cqn, false);
+ if (cqm_obj_queue == NULL) {
+ dev_err_ratelimited(rdev->hwdev_hdl,
+ "[ROCE] %s: Failed to get cqm obj queue, func_id(%d), cqn:%u, event_type:%u\n",
+ __func__, rdev->glb_func_id, cqn, event_type);
+ return;
+ }
+
+ rcq = cqmobj_to_roce3_cq(cqm_obj_queue);
+ roce3_cq_async_event(rdev, rcq, (int)event_type);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_queue);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_handle_srq_async_event
+ Description : roce3_handle_srq_async_event
+ Input : struct roce3_device *rdev
+ u32 srqn
+ u8 event_type
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_handle_srq_async_event(struct roce3_device *rdev, u32 srqn, u8 event_type)
+{
+ struct roce3_srq *rsrq = NULL;
+ struct tag_cqm_object *cqm_obj_queue = NULL;
+
+ cqm_obj_queue = cqm_object_get(rdev->hwdev, CQM_OBJECT_RDMA_SRQ, srqn, false);
+ if (cqm_obj_queue == NULL) {
+ dev_err_ratelimited(rdev->hwdev_hdl,
+ "[ROCE] %s: Failed to get cqm obj queue, func_id(%d), srqn:%u, event_type:%u\n",
+ __func__, rdev->glb_func_id, srqn, event_type);
+ return;
+ }
+
+ rsrq = cqmobj_to_roce3_srq(cqm_obj_queue);
+ roce3_srq_async_event(rdev, rsrq, (int)event_type);
+ hiudk_cqm_object_put(rdev->hwdev, cqm_obj_queue);
+}
+
+static bool roce3_async_event_need_reset(u8 event_status)
+{
+ if ((event_status == API_FORMAT_ERROR) || (event_status == UNKNOWN_RESERVED_ERROR1))
+ return true;
+
+ return false;
+}
+
+u8 roce3_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) {
+ pr_err("[ROCE, ERR] %s: Svc_hd is null\n", __func__);
+ 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_PORT_MNG_CHG_EVENT:
+ case ROCE_EVENT_TYPE_PORT_CHANGE:
+ case ROCE_EVENT_TYPE_ECC_DETECT:
+ case ROCE_EVENT_TYPE_CMD:
+ case ROCE_EVENT_TYPE_COMM_CHANNEL:
+ case ROCE_EVENT_TYPE_OP_REQUIRED:
+ 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 (roce3_async_event_need_reset(event_status))
+ return FAULT_LEVEL_SERIOUS_RESET;
+ break;
+
+ case ROCE_EVENT_TYPE_CQ_ERROR: // CQ ERR
+ if (roce3_async_event_need_reset(event_status))
+ return FAULT_LEVEL_SERIOUS_RESET;
+ break;
+
+ default:
+ event_level = FAULT_LEVEL_GENERAL;
+ break;
+ }
+
+ return event_level;
+}
+
+static int roce3_async_event_handle_common(u8 event_type, u8 *val, struct roce3_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);
+ roce3_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);
+ roce3_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);
+ roce3_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);
+ roce3_handle_srq_async_event(rdev, xid, event_type);
+ event_str_index = OFED_ET_SRQ_CATAS_ERR;
+ break;
+
+ default:
+ event_str_index = to_unknown_event_str_index(event_type, val);
+ break;
+ }
+
+ return event_str_index;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_async_event
+ Description : roce3_async_event
+ Input : void *svc_hd
+ u8 event_type
+ u64 val
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_async_event(void *svc_hd, u8 event_type, u8 *val)
+{
+ int event_str_index = 0;
+ struct roce3_device *rdev = NULL;
+
+ if (svc_hd == NULL) {
+ pr_err_ratelimited("[ROCE, ERR] %s: Svc_hd is null\n", __func__);
+ return;
+ }
+
+ rdev = (struct roce3_device *)svc_hd;
+ if (event_type <= ROCE_EVENT_TYPE_ODP_PAGE_FAULT)
+ event_str_index = roce3_async_event_handle_common(event_type, val, rdev);
+ else
+ event_str_index = roce3_async_event_handle_extend(event_type, val, rdev);
+
+ roce3_event_report(rdev, event_str_index);
+}
+
+static void roce3_handle_sq_hot_plug(struct roce3_qp *rqp, unsigned long flags_qp,
+ struct list_head *cq_notify_list)
+{
+ struct roce3_cq *send_rcq = NULL;
+ unsigned long flags_cq = 0;
+ unsigned long flags_qp_tmp = flags_qp;
+
+ spin_lock_irqsave(&rqp->sq.lock, flags_qp_tmp);
+ if (rqp->sq.tail == rqp->sq.head)
+ goto roce_sq_hot_plug_end;
+
+ send_rcq = to_roce3_cq(rqp->ibqp.send_cq);
+ spin_lock_irqsave(&send_rcq->lock, flags_cq);
+ if (send_rcq->reset_flow_comp && rqp->ibqp.send_cq->comp_handler) {
+ if (send_rcq->reset_notify_added == 0) {
+ send_rcq->reset_notify_added = 1;
+ list_add_tail(&send_rcq->reset_notify, cq_notify_list);
+ }
+ }
+ spin_unlock_irqrestore(&send_rcq->lock, flags_cq);
+
+roce_sq_hot_plug_end:
+ spin_unlock_irqrestore(&rqp->sq.lock, flags_qp_tmp);
+}
+
+static void roce3_handle_rq_hot_plug(struct roce3_qp *rqp, unsigned long flags_qp,
+ struct list_head *cq_notify_list)
+{
+ struct roce3_cq *recv_rcq = NULL;
+ unsigned long flags_cq = 0;
+ unsigned long flags_qp_tmp = flags_qp;
+
+ spin_lock_irqsave(&rqp->rq.lock, flags_qp_tmp);
+ /* no handling is needed for SRQ */
+ if (rqp->ibqp.srq != NULL)
+ goto roce_rq_hot_plug_end;
+ else if (rqp->rq.tail == rqp->rq.head)
+ goto roce_rq_hot_plug_end;
+
+ recv_rcq = to_roce3_cq(rqp->ibqp.recv_cq);
+ spin_lock_irqsave(&recv_rcq->lock, flags_cq);
+ if (recv_rcq->reset_flow_comp && rqp->ibqp.recv_cq->comp_handler) {
+ if (recv_rcq->reset_notify_added == 0) {
+ recv_rcq->reset_notify_added = 1;
+ list_add_tail(&recv_rcq->reset_notify, cq_notify_list);
+ }
+ }
+ spin_unlock_irqrestore(&recv_rcq->lock, flags_cq);
+roce_rq_hot_plug_end:
+ spin_unlock_irqrestore(&rqp->rq.lock, flags_qp_tmp);
+}
+
+void roce3_handle_hotplug_arm_cq(struct roce3_device *rdev)
+{
+ struct roce3_qp *rqp = NULL;
+ struct roce3_cq *rcq = NULL;
+ unsigned long flags_qp = 0;
+ unsigned long flags = 0;
+ struct list_head cq_notify_list;
+
+ pr_err("[ROCE, ERR] %s: Hotplug arm cq start:\n", __func__);
+
+ INIT_LIST_HEAD(&cq_notify_list);
+
+ /* Go over qp list reside on that rdev, sync with create/destroy qp */
+ spin_lock_irqsave(&rdev->reset_flow_resource_lock, flags);
+ list_for_each_entry(rqp, &rdev->qp_list, qps_list) {
+ roce3_handle_sq_hot_plug(rqp, flags_qp, &cq_notify_list);
+ roce3_handle_rq_hot_plug(rqp, flags_qp, &cq_notify_list);
+ }
+
+ list_for_each_entry(rcq, &cq_notify_list, reset_notify) {
+ rcq->reset_flow_comp(rcq);
+ }
+ spin_unlock_irqrestore(&rdev->reset_flow_resource_lock, flags);
+
+ pr_err("[ROCE, ERR] %s: Hotplug arm cq end!\n", __func__);
+}
+
+void roce3_kernel_hotplug_event_trigger(struct roce3_device *rdev)
+{
+ int carrier_ok = 0;
+
+ if (rdev->ndev) {
+ carrier_ok = netif_carrier_ok(rdev->ndev);
+ if (carrier_ok != 0) {
+ dev_info(rdev->hwdev_hdl, "[ROCE] %s: Turn off, func_id(%u), name(%s), pci(%s),\n",
+ __func__, rdev->glb_func_id,
+ rdev->ib_dev.name, pci_name(rdev->pdev));
+ netif_carrier_off(rdev->ndev);
+ }
+
+ ROCE_MDELAY(ROCE_M_DELAY);
+ return;
+ }
+
+ dev_info(rdev->hwdev_hdl, "[ROCE] %s: rdev->ndev is NULL\n", __func__);
+}
+
+#ifdef ROCE_BONDING_EN
+void roce3_handle_bonded_port_state_event(struct roce3_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 roce3_bond_device *bond_dev = NULL;
+ enum ib_port_state curr_port_state;
+ enum ib_event_type event;
+ struct roce3_bond_slave *slave = NULL;
+ int i;
+
+ if (master == NULL)
+ return;
+
+ bond_dev = rdev->bond_dev;
+ if (bond_dev == NULL) {
+ pr_err("[ROCE, ERR] %s: No bond_dev found\n", __func__);
+ return;
+ }
+
+ 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 (roce3_ifconfig_up_down_event_report(rdev, event) != 0)
+ return;
+ rdev->port_state = bonded_port_state;
+ }
+}
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/roce_event.h b/drivers/infiniband/hw/hiroce3/roce_event.h
new file mode 100644
index 0000000000000..c111a54fa9383
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_event.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_EVENT_H
+#define ROCE_EVENT_H
+
+#include <net/ipv6.h>
+#include <net/addrconf.h>
+#include <net/bonding.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/inetdevice.h>
+#include <linux/if_vlan.h>
+
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+
+#include "roce.h"
+#include "roce_srq.h"
+#include "roce_cq.h"
+#include "roce_qp.h"
+#include "roce_cmd.h"
+
+#define ROCE_M_DELAY 100
+#define API_FORMAT_ERROR 0x2
+#define UNKNOWN_RESERVED_ERROR1 0xe
+#define QPC_LOOKUP_ERR_VALUE 0x300d00016
+
+int to_unknown_event_str_index(u8 event_type, const u8 *val);
+
+void roce3_handle_hotplug_arm_cq(struct roce3_device *rdev);
+void roce3_kernel_hotplug_event_trigger(struct roce3_device *rdev);
+
+#endif /* ROCE_EVENT_H */
diff --git a/drivers/infiniband/hw/hiroce3/roce_k_ioctl.h b/drivers/infiniband/hw/hiroce3/roce_k_ioctl.h
new file mode 100644
index 0000000000000..a000b9fba1a71
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_k_ioctl.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_K_IOCTL_H
+#define ROCE_K_IOCTL_H
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+
+#define ROCE_IOCTL_MAGIC 'R'
+#define ROCE_CMD_QUERY_DCB _IO(ROCE_IOCTL_MAGIC, 0)
+#define ROCE_CMD_CREATE_AH _IO(ROCE_IOCTL_MAGIC, 1)
+
+#define ROCE_CMD_QUERY_QP_TX_PORT _IO(ROCE_IOCTL_MAGIC, 3)
+#define ROCE_CMD_SET_QP_TX_PORT _IO(ROCE_IOCTL_MAGIC, 4)
+#define ROCE_CMD_QUERY_QP_RX_PORT _IO(ROCE_IOCTL_MAGIC, 5)
+#define ROCE_CMD_QUERY_BOND_PORT_INFO _IO(ROCE_IOCTL_MAGIC, 6)
+#define ROCE_CMD_SET_QP_UDP_SRC_PORT _IO(ROCE_IOCTL_MAGIC, 7)
+#define ROCE_CMD_QUERY_QP_UDP_SRC_PORT _IO(ROCE_IOCTL_MAGIC, 8)
+#define ROCE_CMD_QUERY_NEXT_WQE_IDX _IO(ROCE_IOCTL_MAGIC, 9)
+
+#define ROCE_CMD_MAX _IO(ROCE_IOCTL_MAGIC, 10)
+
+#ifdef ROCE_EXTEND
+#define HW_ROCE_EXT_CMD_SET_QP_ATTR _IO(ROCE_IOCTL_MAGIC, 11)
+#define HW_ROCE_EXT_CMD_CREATE_SQPC _IO(ROCE_IOCTL_MAGIC, 12)
+#endif
+
+// roce3_ioctrl_version
+#define VERSION_LEN (20)
+#define HW_ROCE_CMD_VERSION _IO(ROCE_IOCTL_MAGIC, 20)
+// reserved op code
+#define HW_ROCE_CMD_RESERVED_1 _IO(ROCE_IOCTL_MAGIC, 21)
+#define HW_ROCE_CMD_RESERVED_2 _IO(ROCE_IOCTL_MAGIC, 22)
+#define HW_ROCE_CMD_RESERVED_3 _IO(ROCE_IOCTL_MAGIC, 23)
+#define HW_ROCE_CMD_RESERVED_4 _IO(ROCE_IOCTL_MAGIC, 24)
+#define HW_ROCE_CMD_RESERVED_5 _IO(ROCE_IOCTL_MAGIC, 25)
+#define HW_ROCE_CMD_RESERVED_6 _IO(ROCE_IOCTL_MAGIC, 26)
+
+#define ROCE_DEV_NAME_MAX 64
+
+union roce3_query_dcb_buf {
+ struct roce3_query_dcb_cmd {
+ u8 sl;
+ u8 sgid_idx;
+ u8 port;
+ u8 traffic_class; // dscp
+ u8 dscp_type;
+ u8 rsvd[3];
+ } cmd;
+
+ struct roce3_query_dcb_resp {
+ u8 cos;
+ u8 rsvd[7];
+ } resp;
+};
+
+union roce3_create_ah_buf {
+ struct roce3_create_ah_cmd {
+ struct ib_uverbs_ah_attr attr;
+ } cmd;
+
+ struct roce3_create_ah_resp {
+ u8 dmac[ETH_ALEN];
+ u16 vlan_id;
+ } resp;
+};
+
+struct roce3_qp_port_buf {
+ u32 qpn;
+ u32 port;
+};
+
+struct roce3_bond_port_info_buf {
+ int original_port_num;
+ char original_port[8];
+ int rsvd1;
+
+ int alive_port_num;
+ char alive_port[8];
+ int rsvd2;
+};
+
+struct roce3_qp_udp_src_port_buf {
+ u32 qpn;
+ u32 udp_src_port;
+};
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/roce_main.c b/drivers/infiniband/hw/hiroce3/roce_main.c
new file mode 100644
index 0000000000000..1f252161e3b64
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_main.c
@@ -0,0 +1,1609 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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 "hinic3_crm.h"
+#include "hinic3_hw.h"
+#include "hinic3_hwdev.h"
+#include "hinic3_srv_nic.h"
+#include "hinic3_rdma.h"
+#include "hinic3_bond.h"
+#include "hinic3_pci_id_tbl.h"
+
+#include "roce_event.h"
+#include "roce_compat.h"
+#include "roce_dfx.h"
+#include "roce_mr.h"
+#include "roce_main_extension.h"
+
+#ifdef ROCE_NETLINK_EN
+#include "roce_netlink.h"
+#endif
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+#include "roce_pub_cmd.h"
+
+MODULE_AUTHOR(HIROCE3_DRV_AUTHOR);
+MODULE_DESCRIPTION(HIROCE3_DRV_DESC);
+MODULE_VERSION(HIROCE3_DRV_VERSION);
+MODULE_LICENSE("GPL");
+
+static int g_loop_times = 50000;
+module_param(g_loop_times, int, 0444); //lint !e806
+MODULE_PARM_DESC(g_loop_times, "default: 50000");
+
+static bool g_ppf_stateful_init;
+static u8 g_vf_stateful_num;
+
+#ifdef ROCE_BONDING_EN
+static int g_want_bond_slave_cnt = ROCE_BOND_WANT_TWO_SLAVES;
+module_param(g_want_bond_slave_cnt, int, 0444);
+MODULE_PARM_DESC(g_want_bond_slave_cnt, "default: 2, 2: two slaves, 3: three slaves, 4: four slaves");
+
+static int g_want_bond0_slave_bits = 0x3; /* 0011 */
+module_param(g_want_bond0_slave_bits, int, 0444);
+MODULE_PARM_DESC(g_want_bond0_slave_bits, "default: 0x3(PF0+PF1), 4bits");
+
+static char *g_bond_name;
+module_param(g_bond_name, charp, 0444);
+MODULE_PARM_DESC(g_bond_name, "bond name for sdi");
+#endif
+
+struct roce3_func_info {
+ u16 func_id;
+ struct list_head node;
+};
+
+LIST_HEAD(g_roce_device_list);
+static void roce3_remove_device_from_list(struct hinic3_lld_dev *lld_dev);
+static int roce3_add_device_to_list(struct hinic3_lld_dev *lld_dev);
+static void roce3_wait_probe(struct hinic3_lld_dev *lld_dev);
+DECLARE_WAIT_QUEUE_HEAD(g_roce_probe_queue);
+
+/*
+ ****************************************************************************
+ Prototype : roce3_cq_completion
+ Description : RoCE's callback function for CQ's completion events on ARM CQs
+ Input : void *svc_hd
+ u32 cqn
+ void *cq_handler
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_cq_completion(void *svc_hd, u32 cqn, void *cq_handler)
+{
+ struct roce3_cq *cq = NULL;
+ struct ib_cq *ibcq = NULL;
+
+ if (cq_handler == NULL) {
+ pr_err("[ROCE, ERR] %s: Cq_handler is null\n", __func__);
+ return;
+ }
+
+ cq = (struct roce3_cq *)cq_handler;
+
+ ++cq->arm_sn;
+ cq->arm_flag = 0;
+
+ ibcq = &cq->ibcq;
+
+ ibcq->comp_handler(ibcq, ibcq->cq_context);
+}
+
+/*
+ ****************************************************************************
+ 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) {
+ pr_info("[ROCE] %s: CPU is be\n", __func__);
+ cpu_mode = 1;
+ } else {
+ pr_info("[ROCE] %s: CPU is le\n", __func__);
+ cpu_mode = 0;
+ }
+
+ return cpu_mode;
+}
+
+static int roce3_alloc_hw_resource(struct roce3_device *rdev)
+{
+ int ret;
+
+ ret = roce3_rdma_init_rsvd_lkey(rdev->hwdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to init rsvd lkey, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_rdma_reset_gid_table(rdev->hwdev, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR]: Failed to reset gid_table, func_id(%u)\n",
+ rdev->glb_func_id);
+ goto err_gid_reset;
+ }
+
+ return 0;
+
+err_gid_reset:
+ roce3_rdma_free_rsvd_lkey(rdev->hwdev);
+
+ return ret;
+}
+
+static void roce3_dealloc_hw_resource(struct roce3_device *rdev)
+{
+ roce3_rdma_free_rsvd_lkey(rdev->hwdev);
+}
+
+static struct roce3_device *roce3_rdev_alloc(struct hinic3_lld_dev *lld_dev, void **uld_dev,
+ const struct rdma_service_cap *rdma_cap)
+{
+ struct roce3_device *rdev = NULL;
+
+ rdev = (struct roce3_device *)roce3_rdev_alloc_ext();
+ if (rdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Failed to alloc rdev\n", __func__);
+ return NULL;
+ }
+
+ *uld_dev = (void *)rdev;
+ rdev->lld_dev = lld_dev;
+ rdev->hwdev = lld_dev->hwdev;
+ rdev->pdev = lld_dev->pdev;
+ mutex_init(&rdev->qp_cnt.cur_qps_mutex);
+
+ rdev->hwdev_hdl = ((struct hinic3_hwdev *)(rdev->hwdev))->dev_hdl;
+ memcpy((void *)&rdev->rdma_cap, (void *)rdma_cap, sizeof(*rdma_cap));
+
+ rdev->ndev = hinic3_get_netdev_by_lld(rdev->lld_dev);
+ if (rdev->ndev == NULL) {
+ pr_err("[ROCE, ERR] %s roce add failed, netdev is null.\n", __func__);
+ ib_dealloc_device(&rdev->ib_dev);
+ return NULL;
+ }
+
+ roce3_rdev_set_ext(rdev);
+
+ return rdev;
+}
+
+static int roce3_board_info_get(struct roce3_device *rdev)
+{
+ int ret = 0;
+
+ ret = hinic3_get_board_info(rdev->hwdev, &rdev->board_info, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get board info\n", __func__);
+ return ret;
+ }
+
+ pr_info("[ROCE] 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, speed:0x%x.\n",
+ 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);
+
+#ifdef ROCE_BONDING_EN
+ ret = roce3_bond_attach(rdev);
+ if (ret != 0)
+ return ret;
+#endif
+
+ ret = roce3_board_cfg_check(rdev);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to check board cfg info\n", __func__);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int roce3_init_info_get(struct roce3_device *rdev)
+{
+ int ret = 0;
+
+ ret = roce3_board_info_get(rdev);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get board info\n", __func__);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void roce3_fix_ibdev_name(struct roce3_device *rdev)
+{
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev)) {
+ strscpy(rdev->ib_dev.name, "hrn3_bond_%d", sizeof("hrn3_bond_%d"));
+ return;
+ }
+#endif
+ {
+ strscpy(rdev->ib_dev.name, (rdev->is_vroce ? "efi_%d" : "hrn3_%d"),
+ (rdev->is_vroce ? sizeof("efi_%d") : sizeof("hrn3_%d")));
+ }
+}
+
+static int roce3_register_template(struct roce3_device *rdev)
+{
+ struct tag_service_register_template svc_template;
+ int ret;
+
+ memset(&svc_template, 0, sizeof(svc_template));
+
+ 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 = roce3_cq_completion;
+ svc_template.aeq_level_callback = roce3_async_event_level;
+ svc_template.aeq_callback = roce3_async_event;
+
+ ret = cqm_service_register(rdev->hwdev, &svc_template);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to register cqm_service, func(%u)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce3_init_dev_file(struct roce3_device *rdev)
+{
+ int ret = 0;
+
+ ret = roce3_init_sysfs(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to init sysfs, func_id(%u) ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ ret = roce3_init_cdev(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to init cdev, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ roce3_remove_sysfs(rdev);
+ }
+
+ return ret;
+}
+
+void roce3_remove_dev_file(struct roce3_device *rdev)
+{
+ roce3_remove_cdev(rdev);
+
+ roce3_remove_sysfs(rdev);
+}
+
+/* Alloc CEQs and alloc CEQN */
+static int roce3_alloc_ceq(struct roce3_device *rdev)
+{
+ int ret;
+
+ ret = hinic3_alloc_ceqs(rdev->hwdev, SERVICE_T_ROCE, rdev->ib_dev.num_comp_vectors,
+ rdev->ceqn, &rdev->ceq_num);
+ if (ret < 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqes, num_comp_vectors(%d), func_id(%u)\n",
+ __func__, rdev->ib_dev.num_comp_vectors, rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce3_free_ceq(struct roce3_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->ceq_num; ++i)
+ hinic3_free_ceq(rdev->hwdev, SERVICE_T_ROCE, rdev->ceqn[i]);
+}
+
+static void roce3_init_hw_info(struct roce3_device *rdev)
+{
+ int ret;
+ struct roce_group_id group_id = {0};
+
+ rdev->hw_info.config_num_ports = (int)rdev->rdma_cap.num_ports;
+ rdev->hw_info.ep_id = hinic3_ep_id(rdev->hwdev);
+ rdev->hw_info.phy_port = 1;
+ rdev->hw_info.is_vf = (hinic3_func_type(rdev->hwdev) == TYPE_VF);
+ rdev->hw_info.cpu_endian = (u8)get_cpu_endian();
+
+ if (!rdev->is_vroce)
+ return;
+
+ ret = roce3_get_group_id(rdev->glb_func_id, rdev->hwdev, &group_id);
+ if (!!ret) {
+ dev_info(rdev->hwdev_hdl, "[ROCE , INFO] Failed to get group id, ret(%d)", ret);
+ return;
+ }
+
+ rdev->group_rc_cos = group_id.group_rc_cos;
+ rdev->group_ud_cos = group_id.group_ud_cos;
+ rdev->group_xrc_cos = group_id.group_xrc_cos;
+ dev_info(rdev->hwdev_hdl, "[ROCE , INFO] group id rc(%u), ud(%u), xrc(%u)",
+ group_id.group_rc_cos, group_id.group_ud_cos, group_id.group_xrc_cos);
+}
+
+static int roce3_init_dev_upper(struct roce3_device *rdev)
+{
+ int ret;
+
+ /* Set function table to ENABLE */
+ ret = roce3_set_func_tbl_func_state(rdev, ROCE_FUNC_ENABLE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to set func_tbl, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_set_func_tbl;
+ }
+ return 0;
+
+err_set_func_tbl:
+ return ret;
+}
+
+static void roce3_deinit_dev_upper(struct roce3_device *rdev)
+{
+ (void)roce3_set_func_tbl_func_state(rdev, ROCE_FUNC_DISABLE);
+}
+
+static int roce3_init_dev_info(struct roce3_device *rdev)
+{
+ int ret;
+
+ ret = roce3_set_func_tbl_cpu_endian(rdev->hwdev, rdev->hw_info.cpu_endian,
+ rdev->glb_func_id);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR]: Failed to set func_tbl cpu_endian, func_id(%u)\n",
+ rdev->glb_func_id);
+ goto err_init_endianness;
+ }
+
+ ret = roce3_init_dev_ext(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR]: Failed to init extended service for func_id(%u)\n",
+ rdev->glb_func_id);
+ goto err_init_dev_ext;
+ }
+
+ ret = roce3_dfx_mem_alloc(rdev);
+ if (ret != 0)
+ goto err_init_dev_dfx;
+
+ ret = roce3_init_dev_upper(rdev);
+ if (ret != 0)
+ goto err_init_dev_upper;
+
+ return 0;
+
+err_init_dev_upper:
+ roce3_dfx_mem_free(rdev);
+err_init_dev_dfx:
+ roce3_remove_clean_res_ext(rdev);
+err_init_dev_ext:
+err_init_endianness:
+ return ret;
+}
+
+static void roce3_deinit_dev_info(struct roce3_device *rdev)
+{
+ roce3_deinit_dev_upper(rdev);
+ roce3_dfx_mem_free(rdev);
+ roce3_remove_clean_res_ext(rdev);
+}
+#ifdef ROCE_BONDING_EN
+static int roce3_ib_register_bond_device(struct roce3_device *rdev)
+{
+ return ib_register_device(&rdev->ib_dev, "hrn3_bond_%d", &rdev->pdev->dev);
+}
+#endif // ROCE_BONDING_EN
+
+static int roce3_ib_register_unbond_device(struct roce3_device *rdev)
+{
+ return ib_register_device(&rdev->ib_dev, "hrn3_%d", &rdev->pdev->dev);
+}
+
+static int roce3_ib_register_device(struct roce3_device *rdev)
+{
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev))
+ return roce3_ib_register_bond_device(rdev);
+#endif
+ return roce3_ib_register_unbond_device(rdev);
+}
+
+static int roce3_init_dev(struct roce3_device *rdev, char *uld_dev_name)
+{
+ int ret;
+
+ ret = roce3_init_dev_info(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to init dev info, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_init_dev_info;
+ }
+
+ /* Clear gid table before register for a new IB device */
+ ret = roce3_alloc_hw_resource(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc hw res, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_alloc_hw_res;
+ }
+
+ roce3_wait_probe(rdev->lld_dev);
+
+ ret = roce3_ib_register_device(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to reg ibdev, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_reg_dev;
+ }
+
+ roce3_remove_device_from_list(rdev->lld_dev);
+
+ memcpy(uld_dev_name, rdev->ib_dev.name, ROCE_ULD_DEV_NAME_LEN);
+
+ ret = roce3_register_netdev_event(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to reg netdev, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_memcpy_uld;
+ }
+
+ ret = roce3_init_dev_file(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to init sysfs, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_init_dev_file;
+ }
+ rdev->ib_active = true;
+ dev_info(rdev->hwdev_hdl,
+ "[ROCE] %s: RoCE add init all ok, func_id(%u), dev_name(%s)\n",
+ __func__, rdev->glb_func_id, rdev->ib_dev.name);
+
+ return 0;
+
+err_init_dev_file:
+ roce3_unregister_netdev_event(rdev);
+err_memcpy_uld:
+ ib_unregister_device(&rdev->ib_dev);
+err_reg_dev:
+ roce3_dealloc_hw_resource(rdev);
+err_alloc_hw_res:
+ roce3_deinit_dev_info(rdev);
+err_init_dev_info:
+ return ret;
+}
+
+static int roce3_add_rdev_init(struct roce3_device *rdev)
+{
+ int ret = 0;
+
+ ret = roce3_init_info_get(rdev);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to check\n", __func__);
+ return ret;
+ }
+
+ rdev->gid_dev = kzalloc(rdev->rdma_cap.max_gid_per_port *
+ sizeof(struct net_device *), GFP_KERNEL);
+ if (rdev->gid_dev == NULL)
+ return -ENOMEM;
+
+ ret = roce3_rdma_init_resource(rdev->hwdev);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to init rdma resources.\n", __func__);
+ goto err_init_resource;
+ }
+
+ pr_info("[ROCE] %s: Initializing(%s)\n", __func__, pci_name(rdev->pdev));
+
+ rdev->glb_func_id = hinic3_global_func_id(rdev->hwdev);
+
+ rdev->is_vroce = false;
+
+ roce3_init_hw_info(rdev);
+
+ ret = roce3_init_cfg_info(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR]%s: Failed to get roce cfg, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_init_cfg;
+ }
+
+ return 0;
+
+err_init_cfg:
+ roce3_rdma_cleanup_resource(rdev->hwdev);
+
+err_init_resource:
+ if (rdev->gid_dev != NULL)
+ kfree(rdev->gid_dev);
+ return ret;
+}
+
+static void roce3_add_rdev_unit(struct roce3_device *rdev)
+{
+ roce3_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;
+
+ if (dev_mac == NULL) {
+ pr_err("[ROCE, ERR]%s: Dev_mac is null\n", __func__);
+ return RDMA_INVALID_GUID;
+ }
+
+ memcpy((void *)&mac_addr[0], (void *)dev_mac, sizeof(mac_addr));
+/*
+ * 0 is mac & guid array idx
+ * 1 is mac & guid array idx
+ * 2 is mac & guid array idx
+ * 3 is guid array idx
+ * 4 is guid array idx
+ * 5 is guid array idx, 3 is mac array idx
+ * 6 is guid array idx, 4 is mac array idx
+ * 7 is guid array idx, 5 is mac array idx
+ */
+ guid[0] = mac_addr[0] ^ DEV_ADDR_FIRST_BYTE_VAL_MASK;
+ guid[1] = mac_addr[1];
+ guid[2] = mac_addr[2];
+ guid[3] = 0xff;
+ guid[4] = 0xfe;
+ guid[5] = mac_addr[3];
+ guid[6] = mac_addr[4];
+ guid[7] = mac_addr[5];
+
+ /* 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 roce3_rdma_init_guid(void *hwdev, struct net_device *netdev)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if ((hwdev == NULL) || (netdev == NULL)) {
+ pr_err("[ROCE, ERR]%s: Hwdev or netdev is null\n", __func__);
+ return ~0ULL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("[ROCE, ERR]%s: Comp_priv is null\n", __func__);
+ 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;
+}
+
+static const struct ib_device_ops dev_ops = {
+ .owner = THIS_MODULE,
+ .uverbs_abi_ver = ROCE_IB_UVERBS_ABI_VERSION,
+
+ .create_qp = roce3_create_qp,
+ .modify_qp = roce3_modify_qp,
+ .query_qp = roce3_query_qp,
+ .destroy_qp = roce3_destroy_qp,
+ .post_send = roce3_post_send,
+ .post_recv = roce3_post_recv,
+ .create_cq = roce3_create_cq,
+ .modify_cq = roce3_modify_cq,
+ .resize_cq = roce3_resize_cq,
+ .destroy_cq = roce3_destroy_cq,
+ .poll_cq = roce3_poll_cq,
+ .req_notify_cq = roce3_arm_cq,
+ .create_srq = roce3_create_srq,
+ .modify_srq = roce3_modify_srq,
+ .query_srq = roce3_query_srq,
+ .destroy_srq = roce3_destroy_srq,
+ .post_srq_recv = roce3_post_srq_recv,
+ .map_mr_sg = roce3_map_kernel_frmr_sg,
+ .get_dma_mr = roce3_get_dma_mr,
+ .reg_user_mr = roce3_reg_user_mr,
+ .dereg_mr = roce3_dereg_mr,
+ .alloc_mr = roce3_alloc_mr,
+ .alloc_mw = roce3_alloc_mw,
+ .dealloc_mw = roce3_dealloc_mw,
+ .query_device = roce3_query_device,
+ .query_port = roce3_query_port,
+ .get_link_layer = roce3_port_link_layer,
+ .query_gid = roce3_query_gid,
+ .add_gid = roce3_ib_add_gid,
+ .del_gid = roce3_ib_del_gid,
+ .query_pkey = roce3_query_pkey,
+ .modify_device = roce3_modify_device,
+ .modify_port = roce3_modify_port,
+ .alloc_ucontext = roce3_alloc_ucontext,
+ .dealloc_ucontext = roce3_dealloc_ucontext,
+ .mmap = roce3_mmap,
+ .alloc_pd = roce3_alloc_pd,
+ .dealloc_pd = roce3_dealloc_pd,
+ .create_ah = roce3_create_ah,
+ .query_ah = roce3_query_ah,
+ .destroy_ah = roce3_destroy_ah,
+ .alloc_xrcd = roce3_alloc_xrcd,
+ .dealloc_xrcd = roce3_dealloc_xrcd,
+ .get_port_immutable = roce3_port_immutable,
+ .get_netdev = roce3_ib_get_netdev,
+ INIT_RDMA_OBJ_SIZE(ib_ah, roce3_ah, ibah),
+ INIT_RDMA_OBJ_SIZE(ib_cq, roce3_cq, ibcq),
+ INIT_RDMA_OBJ_SIZE(ib_pd, roce3_pd, ibpd),
+ INIT_RDMA_OBJ_SIZE(ib_srq, roce3_srq, ibsrq),
+ INIT_RDMA_OBJ_SIZE(ib_ucontext, roce3_ucontext, ibucontext),
+ INIT_RDMA_OBJ_SIZE(ib_xrcd, roce3_xrcd, ibxrcd),
+ INIT_RDMA_OBJ_SIZE(ib_mw, roce3_mw, ibmw),
+};
+
+static void roce3_add_init(struct roce3_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 = roce3_rdma_init_guid(rdev->hwdev, rdev->ndev);
+ ib_dev->dma_device = &rdev->pdev->dev;
+ ib_dev->dev.parent = ib_dev->dma_device;
+ strscpy(ib_dev->node_desc, "hrn3", sizeof("hrn3"));
+
+ rdev->ib_dev.uverbs_cmd_mask = ROCE_UVERBS_CMD_MASK;
+ ib_set_device_ops(ib_dev, &dev_ops);
+ roce3_init_dev_ext_handlers(rdev);
+}
+
+static void roce3_mod_param_parse(struct roce3_device *rdev)
+{
+ rdev->try_times = g_loop_times;
+
+#ifdef ROCE_BONDING_EN
+ if (g_bond_name != NULL) {
+ rdev->want_bond_slave_cnt = SDI_BOND_SUPPORT_ROCE_FUNC_CNT;
+ rdev->want_bond_slave_bits[0] = SDI_BOND_SUPPORT_ROCE_FUNC_BIT;
+ rdev->want_bond_slave_bits[1] = 0;
+ rdev->sdi_bond_name = g_bond_name;
+ return;
+ }
+ rdev->want_bond_slave_cnt = g_want_bond_slave_cnt;
+ rdev->want_bond_slave_bits[0] = g_want_bond0_slave_bits;
+ rdev->want_bond_slave_bits[1] = 0;
+ rdev->sdi_bond_name = NULL;
+#endif
+
+}
+
+static void *roce3_get_ppf_lld_dev(struct roce3_device *rdev)
+{
+ struct hinic3_lld_dev *ppf_lld_dev = NULL;
+
+ ppf_lld_dev = hinic3_get_ppf_lld_dev_unsafe(rdev->lld_dev);
+ if (!ppf_lld_dev) {
+ pr_err("[ROCE, ERR] %s: Failed to get ppf lld_dev\n", __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return ppf_lld_dev->hwdev;
+}
+
+static int roce3_rdev_init(struct roce3_device *rdev)
+{
+ int ret;
+ void *ppf_hwdev = NULL;
+
+ if (!hinic3_is_vm_slave_host(rdev->hwdev)) {
+ if ((hinic3_func_type(rdev->hwdev) == TYPE_VF) &&
+ (g_ppf_stateful_init == false) && (g_vf_stateful_num == 0)) {
+ ppf_hwdev = roce3_get_ppf_lld_dev(rdev);
+ ret = hinic3_stateful_init(ppf_hwdev);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to init ppf stateful resource\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ if (hinic3_func_type(rdev->hwdev) == TYPE_PPF)
+ g_ppf_stateful_init = true;
+ }
+
+ // BM:When the device is PPF, stateful_init is performed only when g_vf_stateful_num is 0.
+ if (hinic3_is_vm_slave_host(rdev->hwdev) ||
+ (hinic3_func_type(rdev->hwdev) != TYPE_PPF) || !g_vf_stateful_num) {
+ ret = hinic3_stateful_init(rdev->hwdev);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to init stateful resource\n", __func__);
+ goto err_stateful_init;
+ }
+ }
+
+ ret = roce3_add_rdev_init(rdev);
+ if (ret != 0)
+ goto err_rdev_init;
+
+ /*lint -e708*/
+ spin_lock_init(&rdev->node_desc_lock);
+ /*lint +e708*/
+
+ mutex_init(&rdev->cap_mask_mutex);
+ INIT_LIST_HEAD(&rdev->mac_vlan_list_head);
+ mutex_init(&rdev->mac_vlan_mutex);
+ /*lint -e708*/
+ spin_lock_init(&rdev->reset_flow_resource_lock);
+ /*lint +e708*/
+ INIT_LIST_HEAD(&rdev->qp_list);
+ roce3_mod_param_parse(rdev);
+
+ roce3_fix_ibdev_name(rdev);
+
+ if (hinic3_func_type(rdev->hwdev) == TYPE_VF)
+ g_vf_stateful_num++;
+
+ return 0;
+
+err_rdev_init:
+ hinic3_stateful_deinit(rdev->hwdev);
+err_stateful_init:
+ if ((g_vf_stateful_num == 0) && (g_ppf_stateful_init == false))
+ hinic3_stateful_deinit(ppf_hwdev);
+ return ret;
+}
+
+static void roce3_stateful_unit(struct roce3_device *rdev)
+{
+ void *ppf_hwdev = NULL;
+
+ if (!hinic3_is_vm_slave_host(rdev->hwdev)) {
+ if (hinic3_func_type(rdev->hwdev) == TYPE_VF) {
+ hinic3_stateful_deinit(rdev->hwdev);
+ g_vf_stateful_num--;
+ // Delete the last VF when no PF is added
+ if ((g_vf_stateful_num == 0) && (g_ppf_stateful_init == false)) {
+ ppf_hwdev = roce3_get_ppf_lld_dev(rdev);
+ hinic3_stateful_deinit(ppf_hwdev);
+ }
+ } else {
+ if (g_vf_stateful_num == 0)
+ hinic3_stateful_deinit(rdev->hwdev);
+ }
+ } else {
+ hinic3_stateful_deinit(rdev->hwdev);
+ }
+}
+
+#ifdef ROCE_NETLINK_EN
+static void roce3_adapt_unit(struct roce3_device *rdev)
+{
+ struct hiroce_netlink_dev *adp_dev;
+ int offset = 0;
+
+ offset = get_instance_of_func_id(rdev->glb_func_id);
+ if (offset >= MAX_FUNCTION_NUM) {
+ pr_err("[ROCE, ERR] %s: offset is over size\n", __func__);
+ return;
+ }
+ adp_dev = hiroce_get_adp();
+ mutex_lock(&adp_dev->mutex_dev);
+ adp_dev->used_dev_num--;
+
+ if (adp_dev->used_dev_num <= 0 && adp_dev->netlink)
+ kfree(adp_dev->netlink);
+ mutex_unlock(&adp_dev->mutex_dev);
+}
+#endif
+
+static void roce3_rdev_unit(struct roce3_device *rdev)
+{
+ /* FLR by MPU when hotplug, don't need deinit anymore */
+ if (hinic3_func_type(rdev->hwdev) == TYPE_PPF)
+ g_ppf_stateful_init = false;
+
+ if (roce3_hca_is_present(rdev) != 0)
+ roce3_stateful_unit(rdev);
+
+#ifdef ROCE_NETLINK_EN
+ roce3_netlink_unit();
+ roce3_adapt_unit(rdev);
+#endif
+ roce3_add_rdev_unit(rdev);
+}
+
+#ifdef ROCE_NETLINK_EN
+static int roce3_adapt_init(struct roce3_device *rdev)
+{
+ int offset = 0;
+ struct hiroce_netlink_dev *adp_dev = NULL;
+
+ offset = get_instance_of_func_id(rdev->glb_func_id);
+ if (offset >= ROCE_MAX_FUNCTION) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to get offset , func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EINVAL;
+ }
+
+ adp_dev = hiroce_get_adp();
+ mutex_lock(&adp_dev->mutex_dev);
+ if (adp_dev->used_dev_num == 0 && adp_dev->netlink == NULL) {
+ adp_dev->netlink = kzalloc(sizeof(struct netlink_devk_dev), GFP_KERNEL);
+ if (adp_dev->netlink == NULL) {
+ mutex_unlock(&adp_dev->mutex_dev);
+ return -EINVAL;
+ }
+ }
+
+ adp_dev->used_dev_num++;
+ mutex_unlock(&adp_dev->mutex_dev);
+ adp_dev->netlink->rdev[offset] = rdev;
+
+ return 0;
+}
+#endif
+
+static int roce3_add_do_init(struct roce3_device *rdev, char *uld_dev_name)
+{
+ int ret;
+
+ ret = roce3_rdev_init(rdev);
+ if (ret != 0)
+ goto err_init_rdev;
+
+ ret = roce3_register_template(rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to register cqm_service, func_id(%u) ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ goto err_cqm_register;
+ }
+
+ ret = hinic3_alloc_db_addr(rdev->hwdev, &rdev->kernel_db_map, &rdev->kernel_dwqe_map);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc db or dwqe, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_alloc_db;
+ }
+
+ roce3_add_init(rdev);
+
+ ret = roce3_alloc_ceq(rdev);
+ if (ret < 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR]: Failed to alloc ceqs, func_id(%u)\n",
+ rdev->glb_func_id);
+ goto err_alloc_ceq;
+ }
+
+ ret = roce3_init_dev(rdev, uld_dev_name);
+ if (ret != 0)
+ goto err_init_dev;
+
+#ifdef ROCE_NETLINK_EN
+ ret = roce3_adapt_init(rdev);
+ if (ret != 0)
+ goto err_init_adp;
+
+ roce3_netlink_init();
+
+ return 0;
+err_init_adp:
+ roce3_adapt_unit(rdev);
+#else
+ return 0;
+#endif
+
+err_init_dev:
+ roce3_free_ceq(rdev);
+
+err_alloc_ceq:
+ hinic3_free_db_addr(rdev->hwdev, rdev->kernel_db_map, rdev->kernel_dwqe_map);
+
+err_alloc_db:
+ cqm_service_unregister(rdev->hwdev, SERVICE_T_ROCE);
+
+err_cqm_register:
+ roce3_rdev_unit(rdev);
+
+err_init_rdev:
+ roce3_remove_device_from_list(rdev->lld_dev);
+ return ret;
+}
+
+static bool is_device_v100(const struct hinic3_lld_dev *lld_dev)
+{
+ struct pci_dev *pdev = lld_dev->pdev;
+ unsigned short ssdid = pdev->subsystem_device;
+
+ return (ssdid == HINIC3_DEV_SSID_2X25G) || (ssdid == HINIC3_DEV_SSID_4X25G) ||
+ (ssdid == HINIC3_DEV_SSID_2X100G);
+}
+
+static int roce3_add_check(const struct hinic3_lld_dev *lld_dev)
+{
+ int ret = 0;
+ u16 func_id;
+ u8 enable_roce = false;
+ bool is_slave_func = false;
+
+ if (lld_dev == NULL) {
+ pr_err("[ROCE, ERR] %s: Lld_dev is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ if (!is_device_v100(lld_dev)) {
+ pr_err("[ROCE, ERR] %s: ssdid 0x%x is NOT standard Card\n",
+ __func__, lld_dev->pdev->subsystem_device);
+ return -ENXIO;
+ }
+
+ ret = hinic3_is_slave_func(lld_dev->hwdev, &is_slave_func);
+ if (ret != 0)
+ pr_err("[ROCE, ERR] %s: Failed to get slave_func.\n", __func__);
+ if (!is_slave_func)
+ return 0;
+
+ func_id = hinic3_global_func_id(lld_dev->hwdev);
+ ret = hinic3_get_func_vroce_enable(lld_dev->hwdev, func_id, &enable_roce);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get roce state.\n", __func__);
+ return ret;
+ }
+ if (!enable_roce) {
+ pr_warn("[ROCE] %s: %s RoCE dev is not enable, func: %u\n", __func__,
+ pci_name(lld_dev->pdev), func_id);
+ return (-EPERM);
+ }
+
+ return 0;
+}
+
+static void roce3_remove_device_from_list(struct hinic3_lld_dev *lld_dev)
+{
+ struct roce3_func_info *info;
+ struct roce3_func_info *tmp;
+
+ if (list_empty(&g_roce_device_list))
+ return;
+
+ list_for_each_entry_safe(info, tmp, &g_roce_device_list, node) {
+ if (info->func_id == hinic3_global_func_id(lld_dev->hwdev)) {
+ list_del(&info->node);
+ kfree(info);
+ }
+ }
+
+ wake_up(&g_roce_probe_queue);
+}
+
+static int roce3_add_device_to_list(struct hinic3_lld_dev *lld_dev)
+{
+ struct roce3_func_info *info = kzalloc(
+ sizeof(struct roce3_func_info), GFP_ATOMIC);
+
+ if (info == NULL) {
+ pr_err("[ROCE, ERR] %s: no memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ info->func_id = hinic3_global_func_id(lld_dev->hwdev);
+ list_add_tail(&info->node, &g_roce_device_list);
+
+ return 0;
+}
+
+static void roce3_wait_probe(struct hinic3_lld_dev *lld_dev)
+{
+ struct roce3_func_info *info = NULL;
+ bool wait_flg = false;
+ DECLARE_WAITQUEUE(wait_queue, current);
+
+ add_wait_queue(&g_roce_probe_queue, &wait_queue);
+ pr_info("[ROCE] %s func %u start to wait\n", __func__,
+ hinic3_global_func_id(lld_dev->hwdev));
+
+ do {
+ might_sleep();
+ info = list_first_entry(&g_roce_device_list, struct roce3_func_info, node);
+ wait_flg = (info->func_id == hinic3_global_func_id(lld_dev->hwdev)) ? true : false;
+ if (!wait_flg) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (signal_pending(current)) { /* if alarmed by signal */
+ goto out;
+ }
+ }
+ } while (!wait_flg);
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&g_roce_probe_queue, &wait_queue);
+
+ pr_info("[ROCE] %s func %u wait finished\n",
+ __func__, hinic3_global_func_id(lld_dev->hwdev));
+ return;
+out:
+ pr_info("[ROCE] %s func %u wait fail\n", __func__, hinic3_global_func_id(lld_dev->hwdev));
+ remove_wait_queue(&g_roce_probe_queue, &wait_queue);
+ set_current_state(TASK_RUNNING);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_add
+ Description : roce3_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 roce3_add(struct hinic3_lld_dev *lld_dev, void **uld_dev, char *uld_dev_name)
+{
+ struct roce3_device *rdev = NULL;
+ struct rdma_service_cap rdma_cap;
+ int ret = 0;
+
+ ret = roce3_add_check(lld_dev);
+ if (ret != 0)
+ goto err_check;
+
+ pr_info("[ROCE] %s: Initializing pci(%s)\n", __func__, pci_name(lld_dev->pdev));
+
+ /* return 0 if the rdev don't support ROCE, make sure it probe success */
+ if (!hinic3_support_roce(lld_dev->hwdev, &rdma_cap)) {
+ pr_err("[ROCE, ERR] %s: %s Not support RoCE, func: %u\n",
+ __func__, pci_name(lld_dev->pdev), hinic3_global_func_id(lld_dev->hwdev));
+ goto err_check;
+ }
+
+ /* make sure roce device probe in order */
+ ret = roce3_add_device_to_list(lld_dev);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to add device to list, ret: %d, func: %u\n",
+ __func__, ret, hinic3_global_func_id(lld_dev->hwdev));
+ return ret;
+ }
+
+ roce3_rdma_cap_ext(&rdma_cap);
+
+ rdev = roce3_rdev_alloc(lld_dev, uld_dev, &rdma_cap);
+ if (rdev == NULL) {
+ roce3_remove_device_from_list(lld_dev);
+ pr_err("[ROCE, ERR] %s: Failed to alloc rdev, func: %u\n",
+ __func__, hinic3_global_func_id(lld_dev->hwdev));
+ return -EINVAL;
+ }
+
+ ret = roce3_add_do_init(rdev, uld_dev_name);
+ if (ret != 0)
+ goto err_do_init;
+
+ return 0;
+
+err_do_init:
+ ib_dealloc_device(&rdev->ib_dev);
+err_check:
+ *uld_dev = NULL;
+ return ret;
+}
+
+static void roce3_do_remove(struct roce3_device *rdev, u16 glb_func_id, const char *dev_name)
+{
+ roce3_remove_dev_file(rdev);
+
+ roce3_unregister_netdev_event(rdev);
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ roce3_handle_hotplug_arm_cq(rdev);
+ roce3_kernel_hotplug_event_trigger(rdev);
+ }
+
+ ib_unregister_device(&rdev->ib_dev);
+ pr_info("[ROCE] %s: Unregister IB device ok, func_id(%u), name(%s), pci(%s)\n",
+ __func__, glb_func_id, dev_name, pci_name(rdev->pdev));
+
+ roce3_dealloc_hw_resource(rdev);
+
+ roce3_deinit_dev_info(rdev);
+
+#ifdef ROCE_BONDING_EN
+ roce3_set_bond_ipsurx_en(true);
+#endif
+
+ roce3_clean_vlan_device_mac(rdev);
+ roce3_clean_real_device_mac(rdev);
+
+ roce3_free_ceq(rdev);
+
+ hinic3_free_db_addr(rdev->hwdev, rdev->kernel_db_map, rdev->kernel_dwqe_map);
+
+ cqm_service_unregister(rdev->hwdev, SERVICE_T_ROCE);
+
+ roce3_del_func_res(rdev);
+ pr_info("[ROCE] %s: Function level resource clear ok, func_id(%u), name(%s), pci(%s)\n",
+ __func__, glb_func_id, dev_name, pci_name(rdev->pdev));
+
+ roce3_do_cache_out(rdev->hwdev, ROCE_CL_TYPE_CQC_SRQC, rdev->glb_func_id);
+
+ roce3_rdev_unit(rdev);
+ pr_info("[ROCE] %s: RoCE rdev uninit ok, func_id(%u), name(%s)\n",
+ __func__, glb_func_id, dev_name);
+
+ ib_dealloc_device(&rdev->ib_dev);
+}
+
+static int roce3_remove_check(const struct hinic3_lld_dev *lld_dev, const void *uld_dev)
+{
+ if ((uld_dev == NULL) || (lld_dev == NULL)) {
+ pr_err("[ROCE, ERR] %s: input param is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+static void roce3_remove(struct hinic3_lld_dev *lld_dev, void *uld_dev)
+{
+ struct roce3_device *rdev = NULL;
+ char *dev_name = NULL;
+ u16 glb_func_id;
+ int ret;
+
+ ret = roce3_remove_check(lld_dev, uld_dev);
+ if (ret != 0)
+ return;
+
+ rdev = (struct roce3_device *)uld_dev;
+ rdev->ib_active = false;
+ dev_name = rdev->ib_dev.name;
+ glb_func_id = rdev->glb_func_id;
+
+ if (!hinic3_support_roce(rdev->hwdev, NULL)) {
+ pr_err("[ROCE, ERR] %s: Not support RoCE\n", __func__);
+ return;
+ }
+
+ dev_info(rdev->hwdev_hdl,
+ "[ROCE] %s: RoCE remove start, func_id(%u), name(%s), pci(%s)\n", __func__,
+ rdev->glb_func_id, dev_name, pci_name(rdev->pdev));
+
+ roce3_do_remove(rdev, glb_func_id, dev_name);
+
+ pr_info("[ROCE] %s: RoCE remove end, func_id(%u), name(%s)\n",
+ __func__, glb_func_id, dev_name);
+}
+
+bool roce3_need_proc_link_event(void *hwdev)
+{
+ int ret = 0;
+ u16 func_id;
+ u8 roce_enable = false;
+ bool is_slave_func = false;
+ struct hinic3_hw_bond_infos hw_bond_infos = {0};
+
+ ret = hinic3_is_slave_func(hwdev, &is_slave_func);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: lld_dev is null\n", __func__);
+ return true;
+ }
+
+ if (!is_slave_func)
+ return true;
+
+ func_id = hinic3_global_func_id(hwdev);
+ ret = hinic3_get_func_vroce_enable(hwdev, func_id, &roce_enable);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get vroce info\n", __func__);
+ return true;
+ }
+ if (!roce_enable)
+ return true;
+
+ hw_bond_infos.bond_id = HINIC_OVS_BOND_DEFAULT_ID;
+
+ ret = hinic3_get_hw_bond_infos(hwdev, &hw_bond_infos, HINIC3_CHANNEL_COMM);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] Get chipf bond info failed (%d)\n", ret);
+ return true;
+ }
+
+ if (!hw_bond_infos.valid)
+ return true;
+
+ return false;
+}
+
+bool roce3_need_proc_bond_event(void *hwdev)
+{
+ return !roce3_need_proc_link_event(hwdev);
+}
+
+static int roce3_proc_bond_status_change(struct roce3_device *rdev,
+ const struct hinic3_event_info *event)
+{
+ switch (event->type) {
+ case EVENT_NIC_BOND_UP:
+ if (!roce3_need_proc_bond_event(rdev->hwdev)) {
+ dev_info(rdev->hwdev_hdl,
+ "[ROCE, WARN] %s: RoCE don't need proc bond event\n",
+ __func__);
+ return -1;
+ }
+ if (test_and_set_bit(ROCE3_PORT_EVENT, &rdev->status) != 0)
+ return -1;
+ dev_info(rdev->hwdev_hdl,
+ "[ROCE, WARN] %s: RoCE report NIC BOND_UP, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return IB_EVENT_PORT_ACTIVE;
+
+ case EVENT_NIC_BOND_DOWN:
+ if (!roce3_need_proc_bond_event(rdev->hwdev)) {
+ dev_info(rdev->hwdev_hdl,
+ "[ROCE, WARN] %s: RoCE don't need proc bond event\n",
+ __func__);
+ return -1;
+ }
+
+ if (test_and_clear_bit(ROCE3_PORT_EVENT, &rdev->status) == 0)
+ return -1;
+ dev_info(rdev->hwdev_hdl,
+ "[ROCE, WARN] %s: RoCE report NIC BOND_DOWN, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return IB_EVENT_PORT_ERR;
+
+ default:
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Nic event unsupported, func_id(%u), event(%hu)\n",
+ __func__, rdev->glb_func_id, event->type);
+ return -1;
+ }
+}
+
+static int roce3_set_nic_event(struct roce3_device *rdev,
+ const struct hinic3_event_info *event)
+{
+ switch (event->type) {
+ case EVENT_NIC_LINK_UP:
+ if (test_and_set_bit(ROCE3_PORT_EVENT, &rdev->status) != 0)
+ return -1;
+ dev_info(rdev->hwdev_hdl,
+ "[ROCE, WARN] %s: RoCE report NIC LINK_UP, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return IB_EVENT_PORT_ACTIVE;
+
+ case EVENT_NIC_LINK_DOWN:
+ if (!roce3_need_proc_link_event(rdev->hwdev)) {
+ dev_info(rdev->hwdev_hdl,
+ "[ROCE, WARN] %s: RoCE don't need proc link event\n", __func__);
+ return -1;
+ }
+
+ if (test_and_clear_bit(ROCE3_PORT_EVENT, &rdev->status) == 0)
+ return -1;
+ dev_info(rdev->hwdev_hdl,
+ "[ROCE, WARN] %s: RoCE report NIC LINK_DOWN, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return IB_EVENT_PORT_ERR;
+
+ case EVENT_NIC_BOND_UP:
+ case EVENT_NIC_BOND_DOWN:
+ return roce3_proc_bond_status_change(rdev, event);
+
+ case EVENT_NIC_DCB_STATE_CHANGE:
+ dev_info(rdev->hwdev_hdl, "[ROCE]%s: DCB state change no longer requires RoCE involvement, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -1;
+
+ default:
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Nic event unsupported, func_id(%u), event(%hu)\n",
+ __func__, rdev->glb_func_id, event->type);
+ return -1;
+ }
+}
+
+static int roce3_set_ib_event(struct roce3_device *rdev, const struct hinic3_event_info *event)
+{
+ switch (event->service) {
+ case EVENT_SRV_NIC:
+ return roce3_set_nic_event(rdev, event);
+
+ case EVENT_SRV_COMM:
+ return roce3_set_comm_event(rdev, event);
+
+ default:
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: func_id(%u) event from svc(%hu) is not supported, event(%hu)\n",
+ __func__, rdev->glb_func_id, event->service, event->type);
+ return -1;
+ }
+}
+
+void roce3_event(struct hinic3_lld_dev *lld_dev, void *uld_dev, struct hinic3_event_info *event)
+{
+ struct ib_event ibevent;
+ struct roce3_device *rdev = NULL;
+ int type;
+ int ret = 0;
+
+ roce3_lock_rdev();
+
+ ret = roce3_get_rdev_by_uld(lld_dev, uld_dev, &rdev, event);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: find rdev failed, ret(%d)\n", __func__, ret);
+ goto err_unlock;
+ }
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev)) {
+ roce3_handle_bonded_port_state_event(rdev);
+ goto err_unlock;
+ }
+#endif
+ type = roce3_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)
+ ib_dispatch_event(&ibevent);
+
+err_unlock:
+ roce3_unlock_rdev();
+}
+
+typedef int (*roce3_adm_func_t)(struct roce3_device *rdev, const void *buf_in,
+ u32 in_size, void *buf_out, u32 *out_size);
+
+/*lint -e26*/
+static roce3_adm_func_t g_roce3_adm_funcs[COMMON_CMD_VM_COMPAT_TEST] = {
+ [COMMON_CMD_GET_DRV_VERSION] = roce3_get_drv_version,
+
+#ifdef __ROCE_DFX__
+ [ROCE_CMD_GET_QPC_FROM_CACHE] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_QPC_FROM_HOST] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_CQC_FROM_CACHE] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_CQC_FROM_HOST] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_SRQC_FROM_CACHE] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_SRQC_FROM_HOST] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_MPT_FROM_CACHE] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_MPT_FROM_HOST] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_GID_FROM_CACHE] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_QPC_CQC_PI_CI] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_QP_COUNT] = roce3_adm_dfx_query,
+ [ROCE_CMD_GET_DEV_ALGO] = roce3_adm_dfx_query,
+#ifdef ROCE_PKT_CAP_EN
+ [ROCE_CMD_START_CAP_PACKET] = roce3_adm_dfx_capture,
+ [ROCE_CMD_STOP_CAP_PACKET] = roce3_adm_dfx_capture,
+ [ROCE_CMD_QUERY_CAP_INFO] = roce3_adm_dfx_capture,
+ [ROCE_CMD_ENABLE_QP_CAP_PACKET] = roce3_adm_dfx_capture,
+ [ROCE_CMD_DISABLE_QP_CAP_PACKET] = roce3_adm_dfx_capture,
+ [ROCE_CMD_QUERY_QP_CAP_INFO] = roce3_adm_dfx_capture,
+#endif /* ROCE_PKT_CAP_EN */
+#endif /* __ROCE_DFX__ */
+
+ [ROCE_CMD_ENABLE_BW_CTRL] = roce3_adm_dfx_bw_ctrl,
+ [ROCE_CMD_DISABLE_BW_CTRL] = roce3_adm_dfx_bw_ctrl,
+ [ROCE_CMD_CHANGE_BW_CTRL_PARAM] = roce3_adm_dfx_bw_ctrl,
+ [ROCE_CMD_QUERY_BW_CTRL_PARAM] = roce3_adm_dfx_bw_ctrl,
+};
+/*lint +e26*/
+
+static int roce3_adm(void *uld_dev, u32 cmd, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size)
+{
+ struct roce3_device *rdev = (struct roce3_device *)uld_dev;
+ roce3_adm_func_t roce3_adm_func;
+
+ if (uld_dev == NULL || buf_in == NULL || buf_out == NULL || out_size == NULL) {
+ pr_err("[ROCE] %s: Input params is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!hinic3_support_roce(rdev->hwdev, NULL)) {
+ pr_err("[ROCE, ERR] %s: %s Not support RoCE\n", __func__, pci_name(rdev->pdev));
+ return -EINVAL;
+ }
+
+ rdev = (struct roce3_device *)uld_dev;
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ if (cmd >= COMMON_CMD_VM_COMPAT_TEST) {
+ dev_err(rdev->hwdev_hdl, "Not support this type(%u)", cmd);
+ return -EINVAL;
+ }
+
+ roce3_adm_func = g_roce3_adm_funcs[cmd];
+ if (roce3_adm_func == NULL) {
+ dev_err(rdev->hwdev_hdl, "Not support this type(%u)", cmd);
+ return -EINVAL;
+ }
+
+ return roce3_adm_func(rdev, buf_in, in_size, buf_out, out_size);
+}
+
+struct hinic3_uld_info roce3_info = {
+ .probe = roce3_add,
+ .remove = roce3_remove,
+ .suspend = NULL,
+ .resume = NULL,
+ .event = roce3_event,
+ .ioctl = roce3_adm,
+};
+
+struct hinic3_uld_info *roce3_info_get(void)
+{
+ return &roce3_info;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_service_init(void)
+{
+ int ret;
+
+ INIT_LIST_HEAD(&g_roce_device_list);
+ init_waitqueue_head(&g_roce_probe_queue);
+ roce3_service_init_pre();
+#ifdef ROCE_NETLINK_EN
+ /* init mutex */
+ mutex_init(&hiroce_get_adp()->mutex_dev);
+#endif
+ ret = hinic3_register_uld(SERVICE_T_ROCE, roce3_info_get());
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to register uld. ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ roce3_service_init_ext();
+#ifdef ROCE_BONDING_EN
+ ret = roce3_bond_init();
+#endif
+ pr_info("[ROCE] %s: Register roce service done, ret(%d).\n", __func__, ret);
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_service_exit(void)
+{
+#ifdef ROCE_BONDING_EN
+ roce3_bond_pre_exit();
+#endif
+ hinic3_unregister_uld(SERVICE_T_ROCE);
+
+#ifdef ROCE_BONDING_EN
+ pr_info("[ROCE] %s: Bond remove all.\n", __func__);
+ roce3_bond_exit();
+#endif
+
+ pr_info("[ROCE] %s: Unregister roce service successful\n", __func__);
+}
+
+bool roce3_is_roceaa(u8 scence_id)
+{
+ if ((scence_id == SCENES_ID_STORAGE_ROCEAA_2x100) ||
+ (scence_id == SCENES_ID_STORAGE_ROCEAA_4x25))
+ return true;
+
+ return false;
+}
+
+module_init(roce3_service_init);
+module_exit(roce3_service_exit);
diff --git a/drivers/infiniband/hw/hiroce3/roce_mix.c b/drivers/infiniband/hw/hiroce3/roce_mix.c
new file mode 100644
index 0000000000000..ad907547a95b8
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_mix.c
@@ -0,0 +1,1194 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <rdma/ib_mad.h>
+#include <rdma/ib_verbs.h>
+#include <linux/pci.h>
+
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+
+#include "hinic3_crm.h"
+#include "hinic3_srv_nic.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_netdev.h"
+#include "roce_main_extension.h"
+#include "roce_pub_cmd.h"
+
+#include "roce_mix.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+struct net_device *roce3_ib_get_netdev(struct ib_device *ibdev, u8 port_num)
+{
+ struct roce3_device *rdev = NULL;
+ struct net_device *netdev = NULL;
+
+ if (ibdev == NULL) {
+ pr_err("[ROCE] %s: Ibdev is null\n", __func__);
+ return NULL;
+ }
+
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ pr_err("[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return NULL;
+ }
+
+#ifdef ROCE_BONDING_EN
+ netdev = roce3_bond_get_netdev(rdev);
+ if (netdev != NULL)
+ return netdev;
+#endif
+
+ netdev = rdev->ndev;
+
+ dev_hold(netdev);
+
+ return netdev;
+}
+
+static void roce3_parse_fw_version(struct roce3_device *rdev, u64 *fw_ver)
+{
+ int ret;
+ int i = 0;
+ struct hinic3_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 = hinic3_get_fw_version(rdev->hwdev, &fw_version, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ pr_warn("[ROCE] %s: get fw version failed\n", __func__);
+ *fw_ver = ROCE_FW_VER;
+ return;
+ }
+ pr_info("[ROCE] %s: fw ver:%s - %s - %s\n", __func__, 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 = kstrtou64(fw_temp, 10, &fw_verion[i]);
+ if (ret != 0) {
+ pr_warn("[ROCE] %s: parse fw version failed\n", __func__);
+ *fw_ver = ROCE_FW_VER;
+ return;
+ }
+
+ i++;
+ }
+/*
+ * 0 is fw_version array idx, 32 is offset
+ * 1 is fw_version array idx, 16 is offset
+ * 2 is fw_version array idx, 8 is offset
+ * 3 is fw_version array idx
+ */
+ *fw_ver = (((fw_verion[0] & 0xffffffff) << 32) |
+ ((fw_verion[1] & 0xffff) << 16) |
+ ((fw_verion[2] & 0xff) << 8) |
+ (fw_verion[3] & 0xff));
+}
+
+static void roce3_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 roce3_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 roce3_query_device_props_set(struct roce3_device *rdev,
+ struct rdma_service_cap *rdma_cap, struct ib_device_attr *props)
+{
+ props->vendor_id = rdev->pdev->vendor;
+ props->vendor_part_id = rdev->pdev->device;
+ roce3_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;
+ /*
+ * 4.19 ofed will return the smaller of sq/rq sge num to user space.
+ * 4.17 We use max_sge to only represent max sq sge num, max_rq_sge is a fixed macro of 16.
+ */
+ props->max_send_sge = rdma_cap->max_sq_sg;
+ props->max_recv_sge = 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;
+
+ if ((rdev->board_info.port_num == ROCE_PORT_NUM_2) &&
+ (rdev->board_info.port_speed == ROCE_25G_PORT_SPEED)) {
+ // 2 smf for 64B cache
+ props->max_mr = (int)(rdma_cap->dev_rdma_cap.roce_own_cap.max_mpts -
+ rdma_cap->reserved_mrws) / MEND_CAP_DEVIDE;
+ props->max_srq =
+ (int)(rdma_cap->dev_rdma_cap.roce_own_cap.max_srqs -
+ rdma_cap->dev_rdma_cap.roce_own_cap.reserved_srqs) /
+ MEND_CAP_DEVIDE;
+ } else {
+ props->max_mr = (int)(rdma_cap->dev_rdma_cap.roce_own_cap.max_mpts -
+ rdma_cap->reserved_mrws);
+ 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_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_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_ah = INT_MAX;
+}
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_query_device(struct ib_device *ibdev, struct ib_device_attr *props, struct ib_udata *uhw)
+{
+ struct roce3_device *rdev = NULL;
+ struct rdma_service_cap *rdma_cap = NULL;
+
+ if ((ibdev == NULL) || (props == NULL)) {
+ pr_err("[ROCE] %s: Ibdev or props is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ memset(props, 0, sizeof(*props));
+
+ 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)
+ props->device_cap_flags = props->device_cap_flags | IB_DEVICE_LOCAL_DMA_LKEY;
+
+ roce3_set_local_cap_flag(rdma_cap, props);
+
+#ifndef ROCE_COMPUTE
+ /* support XRC */
+ if ((rdma_cap->flags & RDMA_DEV_CAP_FLAG_XRC) != 0)
+ props->device_cap_flags = props->device_cap_flags | IB_DEVICE_XRC;
+#endif
+
+ /* 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;
+
+ roce3_set_bmme_cap_flag(rdma_cap, props);
+
+ roce3_query_device_props_set(rdev, rdma_cap, props);
+ return 0;
+}
+
+static void 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;
+
+ default:
+ props->active_width = 0;
+ props->active_speed = 0;
+ break;
+ }
+}
+
+static void roce3_set_ib_port_attr(struct ib_port_attr *props, struct roce3_device *rdev)
+{
+ props->port_cap_flags = IB_PORT_CM_SUP;
+ props->gid_tbl_len = (int)rdev->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 = IB_MTU_4096;
+ props->state = IB_PORT_DOWN;
+ props->phys_state = ROCE_PORT_PHYS_STATE_DISABLED;
+ props->active_mtu = IB_MTU_256;
+}
+#ifdef OFED_MLNX_5_8
+static void eth_link_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props)
+#else
+static void eth_link_query_port(struct ib_device *ibdev, u32 port, struct ib_port_attr *props)
+#endif
+{
+ struct roce3_device *rdev = NULL;
+ struct net_device *netdev = NULL;
+#ifdef ROCE_BONDING_EN
+ struct net_device *upper = NULL;
+#endif
+ enum ib_mtu mtu;
+ enum mag_cmd_port_speed speed = PORT_SPEED_10GB;
+ int ret = 0;
+
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u), dev_name(%s).\n",
+ __func__, rdev->glb_func_id, ibdev->name);
+ return;
+ }
+
+ roce3_set_ib_port_attr(props, rdev);
+
+ ret = hinic3_get_speed(rdev->hwdev, &speed, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to get speed, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ props->active_width = 0;
+ props->active_speed = 0;
+ return;
+ }
+
+ eth_link_get_speed(props, speed);
+
+ netdev = roce3_ib_get_netdev(ibdev, ROCE_DEFAULT_PORT_NUM);
+ if (netdev == NULL)
+ return;
+
+#ifdef ROCE_BONDING_EN
+ if (roce3_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;
+ }
+
+ mtu = (enum ib_mtu)iboe_get_mtu((int)netdev->mtu);
+
+ dev_put(netdev);
+
+ props->active_mtu = ROCE_MIN(props->max_mtu, mtu);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props)
+{
+ if ((ibdev == NULL) || (props == NULL)) {
+ pr_err("[ROCE] %s: Ibdev or props is null\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(props, 0, sizeof(*props));
+
+ eth_link_query_port(ibdev, port, props);
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_query_gid(struct ib_device *ibdev, u8 port, int index, union ib_gid *gid)
+{
+ int ret = 0;
+ struct roce3_device *rdev = NULL;
+ struct rdma_gid_entry gid_entry;
+
+ if ((ibdev == NULL) || (gid == NULL)) {
+ pr_err("[ROCE] %s: Ibdev or gid is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ ret = roce3_rdma_get_gid(rdev->hwdev, (u32)port, (u32)index, &gid_entry);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to get gid, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ memcpy((void *)gid->raw, (void *)gid_entry.raw, sizeof(*gid));
+
+ // 按照OFED的gid生成方式转换GID, 仅IPv4场景需要转换
+ if (gid_entry.dw6_h.bs.gid_type == ROCE_IPv4_ROCEv2_GID) {
+ // 未add的gid直接返回,不需要转换
+ 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;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
+{
+ struct roce3_device *rdev = NULL;
+
+ if ((ibdev == NULL) || (pkey == NULL)) {
+ pr_err("[ROCE] %s: Ibdev or pkey is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ if (pkey == NULL) {
+ pr_err("[ROCE] %s: Pkey is null\n", __func__);
+ return -EINVAL;
+ }
+
+ *pkey = 0xffff;
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_modify_device(struct ib_device *ibdev, int mask, struct ib_device_modify *props)
+{
+ unsigned long flags = 0;
+ struct roce3_device *rdev = NULL;
+
+ if ((ibdev == NULL) || (props == NULL)) {
+ pr_err("[ROCE] %s: Ibdev or props is null\n", __func__);
+ return -EINVAL;
+ }
+
+ if (((unsigned int)mask & ~IB_DEVICE_MODIFY_NODE_DESC) != 0) {
+ pr_err("[ROCE] %s: Not supported to modify node description\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
+ if ((((u32)mask) & IB_DEVICE_MODIFY_NODE_DESC) == 0) {
+ pr_info("[ROCE] %s: No need to modify node description\n", __func__);
+ return 0;
+ }
+
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ spin_lock_irqsave(&rdev->node_desc_lock, flags);
+ memcpy((void *)ibdev->node_desc, (void *)props->node_desc, IB_DEVICE_NODE_DESC_MAX);
+ spin_unlock_irqrestore(&rdev->node_desc_lock, flags);
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_modify_port(struct ib_device *ibdev, u8 port, int mask, struct ib_port_modify *props)
+{
+ int ret = 0;
+ struct ib_port_attr attr;
+ struct roce3_device *rdev = NULL;
+
+ if (ibdev == NULL) {
+ pr_err("[ROCE] %s: Ibdev is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ memset(&attr, 0, sizeof(struct ib_port_attr));
+
+ mutex_lock(&rdev->cap_mask_mutex);
+
+ ret = roce3_query_port(ibdev, port, &attr);
+ if (ret != 0)
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to query port, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+
+ mutex_unlock(&rdev->cap_mask_mutex);
+
+ return ret;
+}
+
+static void roce3_alloc_ucontext_set(struct roce3_device *rdev,
+ struct roce3_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 = roce3_is_roceaa(rdev->cfg_info.scence_id);
+ 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;
+
+ roce3_resp_set_ext(rdev, resp);
+}
+
+static int roce3_alloc_ucontext_pre_check(struct ib_device *ibdev, const struct ib_udata *udata)
+{
+ struct roce3_device *rdev = NULL;
+
+ if ((ibdev == NULL) || (udata == NULL)) {
+ pr_err("[ROCE] %s: Ibdev or udata is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ if (!rdev->ib_active) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Device is abnormal, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int roce3_alloc_ucontext_return(struct roce3_device *rdev, struct ib_udata *udata,
+ struct roce3_ucontext *context, struct roce3_alloc_ucontext_resp *resp)
+{
+ int ret;
+
+ resp->db_offset = context->db_dma_addr & ((1 << PAGE_SHIFT) - 1);
+ resp->dwqe_offset = context->dwqe_dma_addr & ((1 << PAGE_SHIFT) - 1);
+
+ if (context->dwqe_dma_addr == 0)
+ resp->dwqe_size = 0;
+
+ roce3_ucontext_set_ext(rdev, context);
+
+ INIT_LIST_HEAD(&context->db_page_list);
+ mutex_init(&context->db_page_mutex);
+
+ /* Copy data to user space */
+ ret = ib_copy_to_udata_ext(udata, resp);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to copy data to user space, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+int roce3_alloc_ucontext(struct ib_ucontext *ibucontext, struct ib_udata *udata)
+{
+ int ret;
+ struct roce3_ucontext *context = rdma_udata_to_drv_context(
+ udata, struct roce3_ucontext, ibucontext);
+ struct roce3_device *rdev = to_roce3_dev(ibucontext->device);
+ struct roce3_alloc_ucontext_resp *resp = NULL;
+
+ ret = roce3_alloc_ucontext_pre_check(ibucontext->device, udata);
+ if (ret != 0)
+ return ret;
+
+ resp = roce3_resp_alloc_ext();
+ if (resp == NULL) {
+ ret = (-ENOMEM);
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc ucontext, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err;
+ }
+
+ roce3_alloc_ucontext_set(rdev, resp);
+ /* Alloc user space context Doorbell and DWQE */
+ ret = hinic3_alloc_db_phy_addr(rdev->hwdev, &context->db_dma_addr, &context->dwqe_dma_addr);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc DB pa, ret(%d), func_id(%u)\n",
+ __func__, ret, rdev->glb_func_id);
+ goto err_db;
+ }
+
+ /* Copy data to user space */
+ ret = roce3_alloc_ucontext_return(rdev, udata, context, resp);
+ if (ret != 0)
+ goto err_return;
+
+ kfree(resp);
+
+ return 0;
+err_return:
+ hinic3_free_db_phy_addr(rdev->hwdev, context->db_dma_addr, context->dwqe_dma_addr);
+err_db:
+ kfree(resp);
+err:
+ return ret;
+}
+
+void roce3_dealloc_ucontext(struct ib_ucontext *ibcontext)
+{
+ struct roce3_ucontext *context = NULL;
+ struct roce3_device *rdev = NULL;
+
+ if (ibcontext == NULL) {
+ pr_err("[ROCE] %s: Ibcontext is null\n", __func__);
+ return;
+ }
+
+ context = to_roce3_ucontext(ibcontext);
+ rdev = to_roce3_dev(ibcontext->device);
+
+ hinic3_free_db_phy_addr(rdev->hwdev, context->db_dma_addr, context->dwqe_dma_addr);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma)
+{
+ struct roce3_device *rdev = NULL;
+ struct roce3_ucontext *ucontext = NULL;
+ unsigned long db_pfn = 0;
+ unsigned long dwqe_pfn = 0;
+ int res = 0;
+
+ if ((ibcontext == NULL) || (vma == NULL)) {
+ pr_err("[ROCE] %s: Ibcontext or vma is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibcontext->device);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ ucontext = to_roce3_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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: (Vm_end - vm_start) is not equal to PAGE_SIZE, func_id(%d)\n",
+ __func__, 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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to do db io remap, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EAGAIN;
+ }
+ return 0;
+ }
+ // DWQE mmap
+ if ((vma->vm_pgoff == USR_MMAP_DWQE_OFFSET) && (rdev->rdma_cap.direct_wqe_size != 0)) {
+#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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to do dwqe io remap, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return -EAGAIN;
+ }
+ return 0;
+ }
+
+ res = roce3_mmap_ext(rdev, ucontext, vma);
+ return res;
+}
+
+enum rdma_link_layer roce3_port_link_layer(struct ib_device *ibdev, u8 port_num)
+{
+ struct roce3_device *rdev = NULL;
+
+ if (ibdev == NULL)
+ return IB_LINK_LAYER_UNSPECIFIED;
+
+ rdev = to_roce3_dev(ibdev);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return IB_LINK_LAYER_UNSPECIFIED;
+ }
+
+ if (port_num != ROCE_DEFAULT_PORT_NUM)
+ return IB_LINK_LAYER_UNSPECIFIED;
+
+ return IB_LINK_LAYER_ETHERNET;
+}
+
+static void roce3_resolve_cb(int status, struct sockaddr *src_addr,
+ struct rdma_dev_addr *addr, void *context)
+{
+ ((struct roce3_resolve_cb_context *)context)->status = status;
+ complete(&((struct roce3_resolve_cb_context *)context)->comp);
+}
+
+static int roce3_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 roce3_device *rdev)
+{
+ struct rdma_dev_addr dev_addr;
+ struct roce3_resolve_cb_context ctx;
+ union {
+ struct sockaddr _sockaddr;
+ 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);
+
+ memset(&dev_addr, 0, sizeof(dev_addr));
+
+ 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);
+ ret = rdma_resolve_ip(&sgid_addr._sockaddr, &dgid_addr._sockaddr, &dev_addr,
+ RESOLVE_IP_TIME_OUT, roce3_resolve_cb, false, &ctx);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: rdma_resolve_ip failed. Igonore the err.\n", __func__);
+ roce3_resolve_cb(0, &sgid_addr._sockaddr, &dev_addr, &ctx);
+ }
+
+ wait_for_completion(&ctx.comp);
+
+ memcpy(dmac, dev_addr.dst_dev_addr, ETH_ALEN);
+ if (hoplimit)
+ *hoplimit = dev_addr.hoplimit;
+
+ return 0;
+}
+
+static int roce3_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)) {
+ pr_err("[ROCE] %s: Invalid unicast dgid\n", __func__);
+ 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 roce3_fill_gid_attr(struct roce3_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) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] : Failed to query gid func_id(%u),port_num(%d),gid_index(%d),ret(%d)\n",
+ 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);
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] : Failed to get sgid_attr, func_id(%u), ret(%d).\n",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void roce3_release_gid_ref_cnt(const struct ib_gid_attr *sgid_attr)
+{
+ rdma_put_gid_attr(sgid_attr);
+}
+
+static struct net_device *roce3_fill_netdev(struct roce3_device *rdev, union ib_gid *sgid)
+{
+ struct net_device *netdev = NULL;
+ union {
+ struct sockaddr _sockaddr;
+ 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,
+ ((const struct sockaddr_in *)&socket_addr._sockaddr)->sin_addr.s_addr);
+ if (netdev)
+ dev_put(netdev);
+
+ return netdev;
+}
+
+int roce3_resolve_grh(struct roce3_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;
+ const struct ib_gid_attr *sgid_attr = NULL;
+ struct net_device *netdev = NULL;
+
+ if ((rdev == NULL) || (ah_attr == NULL) || (vlan_id == NULL)) {
+ pr_err("[ROCE, ERR] %s: Input pointer is NULL, rdev(%p), ah_attr(%p), vlan_id(%p).\n",
+ __func__, rdev, ah_attr, vlan_id);
+ return (-EINVAL);
+ }
+
+ dmac = ah_attr->roce.dmac;
+ ret = roce3_ah_valid_check(&ah_attr->grh, vlan_id, dmac);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] : Failed to check grh input, func_id(%u), ret(%d).\n",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+ if (ROCE_MEMCMP(dmac, zero_mac, ETH_ALEN) != 0)
+ return 0;
+
+ ret = roce3_fill_gid_attr(rdev, ah_attr, &sgid, &sgid_attr);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] : Failed to fill gid attr, func_id(%u), ret(%d)\n",
+ rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ netdev = roce3_fill_netdev(rdev, &sgid);
+
+ /* reparse dmac avoiding invalid damc from OFED */
+ ret = roce3_rdma_addr_find_l2_eth_by_grh(&sgid, &ah_attr->grh.dgid, dmac,
+ netdev, NULL, rdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] : Failed to find dmac by grh, func_id(%u)\n",
+ rdev->glb_func_id);
+ goto resolve_grh_end;
+ }
+
+ if (ROCE_MEMCMP(dmac, zero_mac, ETH_ALEN) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] : Failed to find valid dmac, func_id(%u)\n",
+ rdev->glb_func_id);
+ ret = (-EINVAL);
+ goto resolve_grh_end;
+ }
+
+ *vlan_id = rdma_vlan_dev_vlan_id(sgid_attr->ndev);
+
+resolve_grh_end:
+ roce3_release_gid_ref_cnt(sgid_attr);
+
+ return ret;
+}
+
+static int ah_get_vlan_id(struct roce3_device *rdev, struct ib_pd *pd,
+ struct rdma_ah_attr *ah_attr, u32 *vlan_id)
+{
+ struct net_device *ndev;
+
+ rcu_read_lock();
+ ndev = rcu_dereference(ah_attr->grh.sgid_attr->ndev);
+ if (ndev == NULL) {
+ rcu_read_unlock();
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] : Net device is NULL, func_id(%u)\n", rdev->glb_func_id);
+ return -EINVAL;
+ }
+ *vlan_id = rdma_vlan_dev_vlan_id(ndev);
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static int create_ib_ah(struct roce3_device *rdev, struct ib_pd *pd, struct roce3_ah *rah,
+ struct rdma_ah_attr *ah_attr)
+{
+ int ret;
+ u8 *dmac = ah_attr->roce.dmac;
+ u32 vlan_id = 0;
+
+ ret = ah_get_vlan_id(rdev, pd, ah_attr, &vlan_id);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get vlan_id (ret:%d)\n", __func__, ret);
+ return -EFAULT;
+ }
+
+ if (((u32)rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) != 0) {
+ memcpy((void *)rah->priv_ah.dgid, (void *)ah_attr->grh.dgid.raw,
+ sizeof(rah->priv_ah.dgid));
+ 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 | 0x2);
+ }
+ rah->priv_ah.dw0.bs.pd = to_roce3_pd(pd)->pdn & 0x3ffff;
+ rah->priv_ah.dw0.bs.wqe_cos = roce3_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);
+
+ memcpy((void *)&rah->priv_ah.dmac_l32,
+ (void *)&dmac[ROCE_RAH_DMAC_L32_START], sizeof(rah->priv_ah.dmac_l32));
+
+ return 0;
+}
+
+int roce3_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, struct ib_udata *udata)
+{
+ struct roce3_ah *rah = to_roce3_ah(ibah);
+ struct roce3_device *rdev = to_roce3_dev(ibah->device);
+ struct rdma_ah_attr *ah_attr = init_attr->ah_attr;
+ enum rdma_ah_attr_type ah_type = ah_attr->type;
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ if ((ah_type == RDMA_AH_ATTR_TYPE_ROCE) && (((u32)rdma_ah_get_ah_flags(ah_attr)
+ & IB_AH_GRH) == 0))
+ return -EINVAL;
+
+ return create_ib_ah(rdev, ibah->pd, rah, ah_attr);
+}
+
+int roce3_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr)
+{
+ struct roce3_ah *ah = NULL;
+ struct roce3_priv_ah priv_ah;
+
+ if ((ibah == NULL) || (ah_attr == NULL)) {
+ pr_err("[ROCE] %s: Ibah or ah_attr is null\n", __func__);
+ return -EINVAL;
+ }
+
+ ah = to_roce3_ah(ibah);
+ memset(ah_attr, 0, sizeof(*ah_attr));
+
+ 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;
+
+ memcpy((void *)ah_attr->grh.dgid.raw, (void *)ah->priv_ah.dgid,
+ sizeof(ah->priv_ah.dgid));
+ return 0;
+}
+
+int roce3_destroy_ah(struct ib_ah *ibah, u32 flags)
+{
+ return 0;
+}
+
+int roce3_port_immutable(struct ib_device *ibdev, u8 port_num, struct ib_port_immutable *immutable)
+{
+ struct ib_port_attr attr;
+ int err;
+ struct roce3_device *rdev = to_roce3_dev(ibdev);
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+ immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; // only rocev2
+
+ err = ib_query_port(ibdev, port_num, &attr);
+ if (err != 0) {
+ pr_err("[ROCE] %s: query ib port failed\n", __func__);
+ 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;
+}
+
+int roce3_get_dcb_cfg_cos(struct roce3_device *rdev, struct roce3_get_cos_inbuf *inbuf, u8 *cos)
+{
+ int ret;
+ u8 pri;
+ struct rdma_gid_entry gid;
+ struct hinic3_dcb_state dcb = { 0 };
+
+ ret = roce3_rdma_get_gid(rdev->hwdev, inbuf->port_num, inbuf->sgid_index, &gid);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to init gid info\n", __func__);
+ return (-EINVAL);
+ }
+
+ ret = hinic3_get_dcb_state(rdev->hwdev, &dcb);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: hinic3_get_dcb_state failed.ret: %d.\n", __func__, ret);
+ return (-EINVAL);
+ }
+
+ *cos = dcb.default_cos;
+ gid.dw6_h.value = cpu_to_le16(gid.dw6_h.value);
+ if ((dcb.trust == ROCE3_DCB_PCP) && (gid.dw6_h.bs.tag == ROCE_GID_VLAN_INVALID)) {
+ // pcp cfg & no vlan should use default cos
+ return 0;
+ }
+
+ pri = (dcb.trust == ROCE3_DCB_PCP) ? inbuf->sl : (inbuf->traffic_class >> ROCE3_DSCP_IDX);
+ ret = hinic3_get_cos_by_pri(rdev->hwdev, pri, cos);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: get_cos_by_pri failed.ret: %d, pri:%u, dcb_on:%u, trust:%u.\n",
+ __func__, ret, pri, dcb.dcb_on, dcb.trust);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/roce_mix.h b/drivers/infiniband/hw/hiroce3/roce_mix.h
new file mode 100644
index 0000000000000..21a495773e85d
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_mix.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#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 "roce.h"
+
+#define IB_DEVICE_LOCAL_DMA_LKEY (1 << 15)
+
+#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 ROCE3_DCB_PCP 0
+#define ROCE3_DCB_DSCP 1
+
+#define ROCE3_DSCP_IDX 2 // dscp begin from bit 2 in traffic_class
+
+#define IB_DEVICE_NODE_DESC_MAX 64
+
+#define MEND_CAP_DEVIDE 2 // to avoid chip cache problem
+#define ROCE_PORT_NUM_2 2
+#define ROCE_25G_PORT_SPEED 25
+
+#define ROCE_GID_IP_IDX 3
+
+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
+};
+
+struct roce3_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 roce3_ah {
+ struct ib_ah ibah;
+ struct roce3_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 roce3_mail_box_buffer {
+ struct mailbox_header header;
+ u32 data[0]; //lint !e1501
+};
+
+struct roce3_resolve_cb_context {
+ struct completion comp;
+ int status;
+};
+
+struct roce3_get_cos_inbuf {
+ u8 sl;
+ u8 sgid_index;
+ u8 port_num;
+ u8 traffic_class;
+};
+
+/* Find struct roce3_ah through ibah */
+static inline struct roce3_ah *to_roce3_ah(const struct ib_ah *ibah)
+{
+ return container_of(ibah, struct roce3_ah, ibah);
+}
+
+int roce3_resolve_grh(struct roce3_device *rdev, struct rdma_ah_attr *ah_attr,
+ u16 *vlan_id, struct ib_udata *udata);
+int roce3_get_dcb_cfg_cos(struct roce3_device *rdev, struct roce3_get_cos_inbuf *inbuf, u8 *cos);
+
+
+#endif /* ROCE_MIX_H */
diff --git a/drivers/infiniband/hw/hiroce3/roce_netdev.c b/drivers/infiniband/hw/hiroce3/roce_netdev.c
new file mode 100644
index 0000000000000..f9be5facaa875
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_netdev.c
@@ -0,0 +1,786 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include "roce_netdev.h"
+#include "roce_netdev_extension.h"
+#include "roce_main_extension.h"
+#include "roce_pub_cmd.h"
+#include "hinic3_rdma.h"
+#include "roce.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+/*
+ ****************************************************************************
+ Prototype : roce3_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 roce3_fill_gid_type(struct rdma_gid_entry *gid_entry, enum roce3_gid_type new_gid_type)
+{
+ static u32 index_roce3_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.tunnel, gid_entry->dw6_h.bs.tag,
+ (u16)new_gid_type);
+ gid_entry->hdr_len_value = index_roce3_gid_mapping[i][0];
+ if (new_gid_type == ROCE_IPv4_ROCEv2_GID) {
+ *((u32 *)(void *)gid_entry + 1) = cpu_to_be32(index_roce3_gid_mapping[i][1]);
+ *((u32 *)(void *)gid_entry + ROCE_GID_MAP_TBL_IDX2) =
+ cpu_to_be32(index_roce3_gid_mapping[i][ROCE_GID_MAP_TBL_IDX2]);
+ }
+}
+
+static void roce3_fill_gid_smac(struct net_device *net_dev, struct rdma_gid_entry *gid_entry)
+{
+ memcpy((void *)gid_entry->smac, (void *)net_dev->dev_addr, sizeof(gid_entry->smac));
+}
+
+static void roce3_fill_gid_vlan(struct roce3_device *rdev, struct net_device *net_dev,
+ struct rdma_gid_entry *gid_entry)
+{
+ gid_entry->dw6_h.bs.tunnel = ROCE_GID_TUNNEL_INVALID;
+ 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;
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_dispatch_event
+ Description : roce3_dispatch_event
+ Input : struct roce3_device *rdev
+ int port_num
+ enum ib_event_type type
+ Output : None
+
+ 1.Date : 2016/3/29
+ Modification : Created function
+
+****************************************************************************
+*/
+static void roce3_dispatch_event(struct roce3_device *rdev, int port_num, enum ib_event_type type)
+{
+ struct ib_event event;
+
+ if (rdev == NULL) {
+ pr_err("[ROCE, ERR] %s: Rdev is null\n", __func__);
+ return;
+ }
+
+ memset(&event, 0, sizeof(event));
+
+ event.device = &rdev->ib_dev;
+ event.element.port_num = (u8)port_num;
+ event.event = type;
+
+ ib_dispatch_event(&event);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+struct sin6_list {
+ struct list_head list;
+ struct sockaddr_in6 sin6;
+};
+
+static int roce3_gid_fill(struct roce3_device *rdev, struct rdma_gid_entry *gid_entry,
+ struct net_device *event_netdev, struct sin6_list *sin6_iter)
+{
+ int ret = 0;
+
+ if (cpu_to_be64(gid_entry->global.subnet_prefix) == ROCE_DEFAULT_GID_SUBNET_PREFIX)
+ return ret;
+
+ roce3_fill_gid_vlan(rdev, event_netdev, gid_entry);
+ roce3_fill_gid_smac(event_netdev, gid_entry);
+
+ /* RoCE V2 */
+ if (rdma_protocol_roce_udp_encap(&rdev->ib_dev, ROCE_DEFAULT_PORT_NUM)) {
+ roce3_fill_gid_type(gid_entry, ROCE_IPv6_ROCEv2_GID);
+ ret = roce3_rdma_update_gid_mac(rdev->hwdev, 0, gid_entry);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to update V2 gid(IPv6), func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ list_del(&sin6_iter->list);
+ kfree(sin6_iter);
+ return ret;
+ }
+ }
+
+ roce3_dispatch_event(rdev, ROCE_DEFAULT_PORT_NUM, IB_EVENT_GID_CHANGE);
+
+ return ret;
+}
+
+static int roce3_netdev_event_ipv6_dev_scan(struct roce3_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) {
+ memcpy((void *)gid_entry->raw, (void *)&sin6_iter->sin6.sin6_addr,
+ sizeof(union ib_gid));
+
+ ret = roce3_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 roce3_netdev_event_ip_dev_scan(struct roce3_device *rdev,
+ struct net_device *event_netdev)
+{
+ struct rdma_gid_entry gid_entry;
+ int ret;
+
+ memset(&gid_entry, 0, sizeof(gid_entry));
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ ret = roce3_netdev_event_ipv6_dev_scan(rdev, event_netdev, &gid_entry);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to scan IPv6, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+
+static struct roce3_vlan_dev_list *roce3_find_vlan_device_list(const struct list_head *mac_list,
+ const struct net_device *netdev)
+{
+ struct roce3_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 roce3_add_vlan_device(struct roce3_device *rdev, struct net_device *netdev)
+{
+ struct roce3_vlan_dev_list *new_list;
+
+ new_list = kzalloc(sizeof(*new_list), GFP_KERNEL);
+ if (new_list == NULL)
+ 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)));
+ memcpy(new_list->mac, netdev->dev_addr, ROCE_MAC_ADDR_LEN);
+ INIT_LIST_HEAD(&new_list->list);
+ list_add_tail(&new_list->list, &rdev->mac_vlan_list_head);
+
+ return 0;
+}
+
+static void roce3_del_vlan_device(struct roce3_device *rdev, struct roce3_vlan_dev_list *old_list)
+{
+ list_del(&old_list->list);
+ kfree(old_list);
+}
+
+static int roce3_update_vlan_device_mac(struct roce3_device *rdev, struct net_device *netdev)
+{
+ struct roce3_vlan_dev_list *old_list = NULL;
+ int ret;
+
+ mutex_lock(&rdev->mac_vlan_mutex);
+ old_list = roce3_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) {
+ roce3_del_vlan_device_mac(rdev, old_list);
+
+ ret = roce3_add_vlan_device_mac(rdev, netdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to add mac_vlan, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ return ret;
+ }
+
+ memcpy(old_list->mac, netdev->dev_addr, ROCE_MAC_ADDR_LEN);
+ }
+
+ mutex_unlock(&rdev->mac_vlan_mutex);
+
+ return 0;
+}
+
+static int roce3_update_real_device_mac(struct roce3_device *rdev, struct net_device *netdev)
+{
+ int ret;
+
+ roce3_del_real_device_mac(rdev);
+
+ ret = roce3_add_real_device_mac(rdev, netdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to add real device ipsu mac, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+void roce3_clean_vlan_device_mac(struct roce3_device *rdev)
+{
+ struct roce3_vlan_dev_list *pos = NULL;
+ struct roce3_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 (roce3_bond_is_active(rdev))
+ (void)roce3_del_bond_vlan_slave_mac(rdev, pos->mac, (u16)pos->vlan_id);
+#endif
+ roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, pos->mac, pos->vlan_id,
+ rdev->glb_func_id, hinic3_er_id(rdev->hwdev));
+
+ (void)roce3_del_mac_tbl_mac_entry(rdev->hwdev, pos->mac, pos->vlan_id,
+ rdev->glb_func_id, rdev->glb_func_id);
+
+ list_del(&pos->list);
+ kfree(pos);
+ }
+ mutex_unlock(&rdev->mac_vlan_mutex);
+}
+
+void roce3_clean_real_device_mac(struct roce3_device *rdev)
+{
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev))
+ (void)roce3_del_bond_real_slave_mac(rdev);
+#endif
+
+ roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, rdev->mac, 0, rdev->glb_func_id,
+ hinic3_er_id(rdev->hwdev));
+}
+
+static bool roce3_rdma_is_upper_dev_rcu(struct net_device *dev, struct net_device *upper)
+{
+ struct net_device *rdev_upper = NULL;
+ struct net_device *master = NULL;
+ bool ret = false;
+
+ if ((upper == NULL) || (dev == NULL)) {
+ ret = false;
+ } else {
+ rdev_upper = rdma_vlan_dev_real_dev(upper);
+ master = netdev_master_upper_dev_get_rcu(dev);
+ ret = ((upper == master) || (rdev_upper && (rdev_upper == master)) ||
+ (rdev_upper == dev));
+ }
+
+ return ret;
+}
+
+/* check bonding device */
+int roce3_is_eth_port_of_netdev(struct net_device *rdma_ndev, struct net_device *cookie)
+{
+ struct net_device *real_dev = NULL;
+ int res;
+
+ if (rdma_ndev == NULL)
+ return 0;
+
+ rcu_read_lock();
+ real_dev = rdma_vlan_dev_real_dev(cookie);
+ if (real_dev == NULL)
+ real_dev = cookie;
+
+ res = (roce3_rdma_is_upper_dev_rcu(rdma_ndev, cookie) || (real_dev == rdma_ndev));
+ rcu_read_unlock();
+ return res;
+}
+
+int roce3_ifconfig_up_down_event_report(struct roce3_device *rdev, u8 net_event)
+{
+ struct ib_event event = { 0 };
+
+ if ((net_event == IB_EVENT_PORT_ACTIVE) &&
+ (test_and_set_bit(ROCE3_PORT_EVENT, &rdev->status) != 0))
+ return -1;
+
+ if ((net_event == IB_EVENT_PORT_ERR) &&
+ (test_and_clear_bit(ROCE3_PORT_EVENT, &rdev->status) == 0))
+ return -1;
+
+ event.device = &rdev->ib_dev;
+ event.event = net_event;
+ event.element.port_num = ROCE_DEFAULT_PORT_NUM;
+
+ ib_dispatch_event(&event);
+ return 0;
+}
+
+static int roce3_netdev_event_raw_dev(unsigned long event, struct roce3_device *rdev,
+ struct net_device *event_netdev)
+{
+ int ret;
+
+ if (event == NETDEV_REGISTER) {
+ ret = roce3_add_real_device_mac(rdev, event_netdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to add real device mac, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ if (event == NETDEV_CHANGEADDR) {
+ ret = roce3_update_real_device_mac(rdev, event_netdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to update readl device mac, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_netdev_event_ip_dev_scan(rdev, event_netdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to scan ip_dev, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev)) {
+ if ((event == NETDEV_DOWN) || (event == NETDEV_UP))
+ roce3_handle_bonded_port_state_event(rdev);
+ } else {
+ if (event == NETDEV_DOWN)
+ roce3_ifconfig_up_down_event_report(rdev, IB_EVENT_PORT_ERR);
+ if (event == NETDEV_UP)
+ roce3_event_up_extend(rdev);
+ }
+#else
+ if (event == NETDEV_DOWN)
+ roce3_ifconfig_up_down_event_report(rdev, IB_EVENT_PORT_ERR);
+ if (event == NETDEV_UP)
+ roce3_event_up_extend(rdev);
+#endif
+ return 0;
+}
+
+static int roce3_netdev_event_vlan_dev(unsigned long event, struct roce3_device *rdev,
+ struct net_device *event_netdev)
+{
+ int ret;
+
+ if (event == NETDEV_CHANGEADDR) {
+ ret = roce3_update_vlan_device_mac(rdev, event_netdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to update vlan device mac, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_netdev_event_ip_dev_scan(rdev, event_netdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to scan vlan device ip list, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static bool roce3_is_port_of_net_dev(struct roce3_device *rdev, struct net_device *event_netdev)
+{
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_is_active(rdev)) {
+ if (roce3_bond_is_eth_port_of_netdev(rdev, event_netdev) == 0)
+ return false;
+ } else
+#endif
+ {
+ if (roce3_is_eth_port_of_netdev(rdev->ndev, event_netdev) == 0)
+ return false;
+ }
+ return true;
+}
+
+static int roce3_netdev_event(struct notifier_block *nb, unsigned long event, void *ptr)
+{
+ struct net_device *event_netdev;
+ struct roce3_device *rdev = NULL;
+ struct roce3_notifier *notifier = 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;
+
+ notifier = container_of(nb, struct roce3_notifier, nb);
+ rdev = container_of(notifier, struct roce3_device, notifier);
+
+ if (roce3_hca_is_present(rdev) == 0)
+ goto err_out;
+
+ if (!roce3_is_port_of_net_dev(rdev, (void *)event_netdev))
+ goto err_out;
+
+ /* get raw netdev from event_netdev */
+ real_dev = (rdma_vlan_dev_real_dev(event_netdev) != 0) ?
+ rdma_vlan_dev_real_dev(event_netdev) : event_netdev;
+ if (real_dev == event_netdev) {
+ ret = roce3_netdev_event_raw_dev(event, rdev, event_netdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to deal with raw device, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_out;
+ }
+ } else {
+ ret = roce3_netdev_event_vlan_dev(event, rdev, event_netdev);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to deal with vlan device, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_out;
+ }
+ }
+
+err_out:
+ return NOTIFY_DONE;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_unregister_netdev_event
+ Description : unregister netdev event related function
+ Input : struct roce3_device *rdev
+ Output : None
+
+ 1.Date : 2015/6/18
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_unregister_netdev_event(struct roce3_device *rdev)
+{
+ int ret = 0;
+ struct roce3_notifier *notifier = &rdev->notifier;
+
+ if (notifier->nb.notifier_call) {
+ ret = unregister_netdevice_notifier(&notifier->nb);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to unregister netdev notifier, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ }
+
+ notifier->nb.notifier_call = NULL;
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_register_netdev_event
+ Description : register netdev event related function
+ Input : struct roce3_device *rdev
+ Output : None
+
+ 1.Date : 2015/6/18
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_register_netdev_event(struct roce3_device *rdev)
+{
+ struct roce3_notifier *notifier = &rdev->notifier;
+ int ret;
+
+ notifier->nb.notifier_call = roce3_netdev_event;
+ ret = register_netdevice_notifier(&notifier->nb);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to register netdev notifier, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ notifier->nb.notifier_call = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int roce3_set_gid_entry(struct roce3_device *rdev, struct rdma_gid_entry *gid_entry,
+ const struct ib_gid_attr *attr, const union ib_gid *gid)
+{
+ static enum roce3_gid_type gid_type_map[ROCE_NETWORK_GID_TYPE_MAX] = {0};
+ enum rdma_network_type network_type;
+ enum roce3_gid_type roce_gid_type;
+
+ gid_type_map[RDMA_NETWORK_IPV4] = ROCE_IPv4_ROCEv2_GID;
+ gid_type_map[RDMA_NETWORK_IPV6] = ROCE_IPv6_ROCEv2_GID;
+
+ memset(gid_entry, 0, sizeof(*gid_entry));
+ network_type = rdma_gid_attr_network_type(attr);
+ memcpy((void *)gid_entry->raw, (void *)(&attr->gid), sizeof(union ib_gid));
+ if ((network_type == RDMA_NETWORK_IB) || (network_type == RDMA_NETWORK_ROCE_V1)) {
+ pr_err("[ROCE, ERR] %s: IB or RoCE v1 is no longer supported, network_type(%d)\n",
+ __func__, network_type);
+ return (-EINVAL);
+ }
+
+ roce_gid_type = gid_type_map[network_type];
+ roce3_fill_gid_vlan(rdev, attr->ndev, gid_entry);
+ roce3_fill_gid_type(gid_entry, roce_gid_type);
+ roce3_fill_gid_smac(attr->ndev, gid_entry);
+
+ return 0;
+}
+
+static int roce3_check_and_set_gid_entry(const struct ib_gid_attr *attr, const union ib_gid *gid,
+ struct rdma_gid_entry *gid_entry, struct roce3_device *rdev, unsigned int index)
+{
+ if ((cpu_to_be64(gid->global.subnet_prefix) == ROCE_DEFAULT_GID_SUBNET_PREFIX) &&
+ (index > 1))
+ return -EINVAL;
+
+ memset(gid_entry, 0, sizeof(struct rdma_gid_entry));
+ if (roce3_set_gid_entry(rdev, gid_entry, attr, gid) != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to set gid entry.\n", __func__);
+ return (-EINVAL);
+ }
+
+ return 0;
+}
+
+/* add vlan_mac list or ref_cnt + 1
+ * add mac_vlan when new list add
+ */
+static int roce3_notify_vlan(struct roce3_device *rdev, const struct ib_gid_attr *attr)
+{
+ int ret;
+ struct roce3_vlan_dev_list *old_list = NULL;
+
+ mutex_lock(&rdev->mac_vlan_mutex);
+ pr_info("[ROCE] ADD vlan: Func_id:%d, Netdev:%s\n",
+ rdev->glb_func_id, attr->ndev->name);
+ old_list = roce3_find_vlan_device_list(&rdev->mac_vlan_list_head, attr->ndev);
+ if (old_list != NULL) {
+ old_list->ref_cnt++;
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ return 0;
+ }
+
+ ret = roce3_add_vlan_device(rdev, attr->ndev);
+ if (ret != 0) {
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ return ret;
+ }
+
+ ret = roce3_add_vlan_device_mac(rdev, attr->ndev);
+ if (ret != 0) {
+ old_list = roce3_find_vlan_device_list(&rdev->mac_vlan_list_head, attr->ndev);
+ if (old_list)
+ roce3_del_vlan_device(rdev, old_list);
+
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ return ret;
+ }
+ mutex_unlock(&rdev->mac_vlan_mutex);
+
+ return 0;
+}
+
+int roce3_ib_add_gid(const struct ib_gid_attr *attr, __always_unused void **context)
+{
+ int ret;
+ struct rdma_gid_entry gid_entry;
+ struct roce3_device *rdev = to_roce3_dev(attr->device); /*lint !e78 !e530*/
+ unsigned int index = attr->index; /*lint !e530*/
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+ /*lint !e40*/
+ ret = roce3_check_and_set_gid_entry(attr, &(attr->gid), &gid_entry, rdev, index);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: set gid err, func_id(%u)\n", __func__,
+ rdev->glb_func_id);
+ return ret;
+ }
+
+ // 添加第一个gid时,设置ipsu mac
+ if (index == 0) {
+ ret = roce3_update_real_device_mac(rdev, attr->ndev);
+ if (ret != 0)
+ return ret;
+ }
+
+ ret = roce3_rdma_update_gid(rdev->hwdev, 0, index, &gid_entry);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to update gid. ret(%d),func_id(%d)\n",
+ __func__, ret, rdev->glb_func_id);
+ return ret;
+ }
+
+ rdev->gid_dev[index] = attr->ndev;
+
+ if (rdma_vlan_dev_real_dev(attr->ndev)) {
+ ret = roce3_notify_vlan(rdev, attr);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to nofify vlan, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int roce3_ib_del_gid(const struct ib_gid_attr *attr, __always_unused void **context)
+{
+ struct roce3_vlan_dev_list *old_list = NULL;
+ struct roce3_device *rdev = NULL;
+ u32 index = 0;
+
+ if ((attr == NULL) || (attr->device == NULL)) { /*lint !e55 !e58 !e78*/
+ pr_err("[ROCE] %s: Attr or attr->device is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ rdev = to_roce3_dev(attr->device); /*lint !e78*/
+ index = attr->index;
+ if (index >= rdev->rdma_cap.max_gid_per_port) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: Invalid gid index(%u), func_id(%d)\n",
+ __func__, 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 = roce3_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) {
+ roce3_del_vlan_device_mac(rdev, old_list);
+
+ roce3_del_vlan_device(rdev, old_list);
+ }
+ }
+ mutex_unlock(&rdev->mac_vlan_mutex);
+ }
+ /*
+ * 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/hiroce3/roce_netdev.h b/drivers/infiniband/hw/hiroce3/roce_netdev.h
new file mode 100644
index 0000000000000..f0e9b22354eb9
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_netdev.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#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_user_verbs.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 "hinic3_srv_nic.h"
+#endif
+/* the 31 bit is vlan eable bit */
+#define ROCE_GID_SET_VLAN_32BIT_VLAID(vlan_id) ((vlan_id) | (((u32)1) << 31))
+#define ROCE_MAC_ADDR_LEN 6
+
+/* ipv4 header len. unit:4B */
+#define IPV4_HDR_LEN 5
+
+#define ROCE_DEFAULT_GID_SUBNET_PREFIX 0xFE80000000000000ULL
+
+#define ROCE_GID_MAP_TBL_IDX_GET(tunnel, tag, new_gid_type) \
+ ((u8)(((tunnel) << 4) | ((tag) << 2) | (new_gid_type)))
+
+#define ROCE_GID_MAP_TBL_IDX2 2
+
+#define ROCE_NETWORK_GID_TYPE_MAX 4
+
+enum roce3_gid_tunnel_type {
+ ROCE_GID_TUNNEL_INVALID = 0,
+ ROCE_GID_TUNNEL_VALID
+};
+
+enum roce3_gid_vlan_type {
+ ROCE_GID_VLAN_INVALID = 0,
+ ROCE_GID_VLAN_VALID
+};
+
+struct roce3_vlan_dev_list {
+ u8 mac[6];
+ u32 vlan_id;
+ u32 ref_cnt;
+ struct net_device *net_dev;
+ struct list_head list;
+};
+
+#endif /* ROCE_NETDEV_H */
diff --git a/drivers/infiniband/hw/hiroce3/roce_netlink.c b/drivers/infiniband/hw/hiroce3/roce_netlink.c
new file mode 100644
index 0000000000000..509536bef1103
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_netlink.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <net/net_namespace.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/netlink.h>
+
+#include "roce_mix.h"
+#include "roce_cmd.h"
+#include "roce_netlink.h"
+
+#ifdef ROCE_BONDING_EN
+#include "roce_bond.h"
+#endif
+
+#ifdef ROCE_EXTEND
+#include "roce_qp_extension.h"
+#endif
+
+#ifdef ROCE_NETLINK_EN
+
+static struct hiroce_netlink_dev g_roce_adapter = {0, 0};
+
+struct hiroce_netlink_dev *hiroce_get_adp(void)
+{
+ return &g_roce_adapter;
+}
+
+int roce3_drv_cmd_execute(struct sk_buff *skb, struct genl_info *nl_info);
+
+static void roce3_nlahdr_push(struct sk_buff *skb, u16 type)
+{
+ u16 attrlen = (u16)skb->len;
+ struct nlattr *nlahdr;
+ u32 padlen = nla_padlen(attrlen);
+
+ nlahdr = (struct nlattr *)skb_push(skb, NLA_HDRLEN);
+ nlahdr->nla_len = (u16)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, u32 portid, u32 seq,
+ int type, int len, int flags)
+{
+ struct nlmsghdr *nlh;
+ u32 size = (u32)nlmsg_msg_size(len);
+
+ nlh = (struct nlmsghdr *)skb_push(skb, NLMSG_ALIGN(size));
+ if (nlh == NULL)
+ return NULL;
+
+ nlh->nlmsg_type = (u16)type;
+ nlh->nlmsg_len = skb->len;
+ nlh->nlmsg_flags = (u16)flags;
+ nlh->nlmsg_pid = portid;
+ nlh->nlmsg_seq = seq;
+
+ if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0)
+ memset((char *)nlmsg_data(nlh) + len, 0, NLMSG_ALIGN(size) - size);
+
+ return nlh;
+}
+
+static inline struct nlmsghdr *roce3_nlmsg_push(struct sk_buff *skb, u32 portid,
+ u32 seq, int type, int payload, int 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 *roce3_genlmsg_push(struct sk_buff *skb, u32 portid, u32 seq,
+ const struct genl_family *family, int flags, u8 cmd)
+{
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *hdr = NULL;
+
+ nlh = roce3_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 = (u8)family->version;
+ hdr->reserved = 0;
+
+ return (void *)nlh;
+}
+
+static long roce3_netlink_query_dcb(struct roce3_device *rdev, union roce3_query_dcb_buf *buf_in,
+ union roce3_query_dcb_buf *dcb_buf)
+{
+ int ret;
+ int get_group_id;
+ struct roce_group_id group_id = {0};
+ struct roce3_get_cos_inbuf in_buf;
+ u8 cos;
+
+#ifdef ROCE_BONDING_EN
+ if (roce3_bond_get_dcb_info(rdev) != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get dcb info\n", __func__);
+ return (-EINVAL);
+ }
+#endif
+ in_buf.port_num = buf_in->cmd.port;
+ in_buf.sl = buf_in->cmd.sl;
+ in_buf.sgid_index = buf_in->cmd.sgid_idx;
+ in_buf.traffic_class = buf_in->cmd.traffic_class;
+ ret = roce3_get_dcb_cfg_cos(rdev, &in_buf, &cos);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get cos from dcb info, ret:%d\n", __func__, ret);
+ return ret;
+ }
+
+ dcb_buf->resp.cos = cos;
+
+ if (rdev->is_vroce) {
+ get_group_id = roce3_get_group_id(rdev->glb_func_id, rdev->hwdev, &group_id);
+ if (get_group_id != 0) {
+ pr_warn("Failed to get group id, ret(%d)", get_group_id);
+ } else {
+ rdev->group_rc_cos = group_id.group_rc_cos;
+ rdev->group_ud_cos = group_id.group_ud_cos;
+ rdev->group_xrc_cos = group_id.group_xrc_cos;
+ }
+ if (buf_in->cmd.dscp_type == (u8)IB_QPT_RC)
+ dcb_buf->resp.cos = rdev->group_rc_cos & MAX_COS_NUM;
+ else if (buf_in->cmd.dscp_type == (u8)IB_QPT_UD)
+ dcb_buf->resp.cos = rdev->group_ud_cos & MAX_COS_NUM;
+ else
+ dcb_buf->resp.cos = rdev->group_xrc_cos & MAX_COS_NUM;
+ }
+
+ return 0;
+}
+
+int roce3_drv_dcb_info_get(void *buf_in, void *buf_out, u32 *out_size)
+{
+ struct hiroce_dev_dcbinfo_get *cmd;
+ struct hiroce_dev_dcbinfo_rsp *rsp;
+ struct roce3_device *rdev = NULL;
+ int offset = 0;
+ int ret;
+
+ cmd = (struct hiroce_dev_dcbinfo_get *)buf_in;
+ rsp = (struct hiroce_dev_dcbinfo_rsp *)buf_out;
+ offset = get_instance_of_func_id(cmd->func_id);
+ rdev = hiroce_get_adp()->netlink->rdev[offset];
+ if (rdev == NULL) {
+ pr_err("[ROCE, ERR]: offset is invild, please check\n");
+ return -EINVAL;
+ }
+ ret = roce3_netlink_query_dcb(rdev, &cmd->dcb_info, &rsp->dcb_info);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to get dcb info, ret:%d\n", __func__, ret);
+ return ret;
+ }
+ rsp->hdr.cmd = HIROCE_DRV_CMD_DCB_GET;
+ rsp->hdr.msg_len = (u32)sizeof(*rsp);
+ rsp->hdr.err_code = 0;
+ *out_size = (u32)sizeof(*rsp);
+
+ return 0;
+}
+
+static long roce3_netlink_create_ah(struct roce3_device *rdev, union roce3_create_ah_buf *buf,
+ union roce3_create_ah_buf *rsp)
+{
+ struct rdma_ah_attr attr;
+ struct ib_udata udata;
+
+ attr.sl = buf->cmd.attr.sl;
+ attr.static_rate = buf->cmd.attr.static_rate;
+ attr.ah_flags = (buf->cmd.attr.is_global != 0) ? IB_AH_GRH : 0;
+ attr.port_num = buf->cmd.attr.port_num;
+ attr.grh.flow_label = buf->cmd.attr.grh.flow_label;
+ attr.grh.sgid_index = buf->cmd.attr.grh.sgid_index;
+ attr.grh.hop_limit = buf->cmd.attr.grh.hop_limit;
+ attr.grh.traffic_class = buf->cmd.attr.grh.traffic_class;
+ memset(attr.roce.dmac, 0, sizeof(attr.roce.dmac));
+ memcpy(attr.grh.dgid.raw, buf->cmd.attr.grh.dgid, ROCE_GID_LEN);
+
+ memset(&udata, 0, sizeof(struct ib_udata));
+ if (roce3_resolve_grh(rdev, &attr, &buf->resp.vlan_id, &udata) != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to resolve grh\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(buf->resp.dmac, attr.roce.dmac, ETH_ALEN);
+ memcpy(rsp, buf, sizeof(*buf));
+
+ return 0;
+}
+
+int roce3_drv_create_ah(void *buf_in, void *buf_out, u32 *out_size)
+{
+ struct hiroce_dev_ah_info *cmd;
+ struct hiroce_dev_ah_info *rsp;
+ struct roce3_device *rdev = NULL;
+ int offset;
+ int ret;
+
+ cmd = (struct hiroce_dev_ah_info *)buf_in;
+ rsp = (struct hiroce_dev_ah_info *)buf_out;
+ offset = get_instance_of_func_id(cmd->func_id);
+ rdev = hiroce_get_adp()->netlink->rdev[offset];
+ if (rdev == NULL) {
+ pr_err("[ROCE, ERR]: offset is invild, please check\n");
+ return -EINVAL;
+ }
+ ret = roce3_netlink_create_ah(rdev, &cmd->ah_info, &rsp->ah_info);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to create ah, ret:%d\n", __func__, ret);
+ return ret;
+ }
+ rsp->hdr.cmd = HIROCE_DRV_CMD_CREATE_AH;
+ rsp->hdr.msg_len = (u32)sizeof(*rsp);
+ rsp->hdr.err_code = 0;
+ *out_size = (u32)sizeof(*rsp);
+
+ return 0;
+}
+
+static int roce3_drv_cmd_process(usrnl_drv_msg_hdr_s *hdr, struct sk_buff *reply, u32 *out_size)
+{
+ int ret = 0;
+ void *buf_out = (void *)reply->data;
+ void *buf_in = (void *)hdr;
+
+ switch (hdr->cmd) {
+ case HIROCE_DRV_CMD_DCB_GET:
+ ret = roce3_drv_dcb_info_get(buf_in, buf_out, out_size);
+ break;
+ case HIROCE_DRV_CMD_CREATE_AH:
+ ret = roce3_drv_create_ah(buf_in, buf_out, out_size);
+ break;
+ default:
+ pr_err("invalid drv cmd:0x%x", hdr->cmd);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static const struct nla_policy roce3_policy[USRNL_GENL_ATTR_MAX + 1] = {
+ [USRNL_GENL_ATTR] = { .type = NLA_UNSPEC }, //lint !e26
+};
+
+static const struct genl_ops roce3_genl_ops[] = {
+ { .cmd = USRNL_DEV_DRV_CMD_EXECUTE,
+ .flags = CAP_NET_ADMIN, /* Requires CAP_NET_ADMIN privilege. */
+ .policy = roce3_policy,
+ .doit = roce3_drv_cmd_execute,
+ .validate = GENL_DONT_VALIDATE_STRICT
+ },
+};
+
+/*
+ * Netlink Ops
+ */
+#define ROCE_GENL_OPS_ARRAY_SIZE 1
+
+static struct genl_family roce3_genl_family = {
+ .hdrsize = 0,
+ .name = ROCE3_FAMILY,
+ .version = ROCE3_VERSION,
+ .maxattr = USRNL_GENL_ATTR_MAX,
+ .netnsok = true,
+ .parallel_ops = true,
+ .ops = roce3_genl_ops,
+ .n_ops = ROCE_GENL_OPS_ARRAY_SIZE,
+};
+
+struct genl_family *roce3_genl_families[] = {
+ &roce3_genl_family,
+};
+
+int roce3_drv_cmd_execute(struct sk_buff *skb, struct genl_info *nl_info)
+{
+ u8 cmd;
+ int rc;
+ u32 out_size = 0;
+ struct sk_buff *reply = NULL;
+ struct nlattr *cmd_attr;
+ usrnl_drv_msg_hdr_s *hdr = NULL;
+ struct nlattr **ppstAttr = nl_info->attrs;
+
+ cmd_attr = ppstAttr[USRNL_GENL_ATTR];
+ if (cmd_attr == NULL) {
+ pr_err("[ROCE, ERR] %s: Do drv cmd failed for NULL attr!", __func__);
+ return -ENOMEM;
+ }
+
+ hdr = (usrnl_drv_msg_hdr_s *)nla_data(cmd_attr);
+
+ reply = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (reply == NULL) {
+ pr_err("Alloc reply buf for drv cmd:%d failed!", hdr->cmd);
+ return -ENOMEM;
+ }
+ skb_reserve(reply, NLMSG_HDRLEN + GENL_HDRLEN + NLA_HDRLEN);
+
+ cmd = hdr->cmd;
+ rc = roce3_drv_cmd_process(hdr, reply, &out_size);
+ if (rc != 0) {
+ pr_err("Do drv cmd:%u failed, errcode %d", cmd, rc);
+ nlmsg_free(reply);
+ return -EIO;
+ }
+
+ hdr = (usrnl_drv_msg_hdr_s *)reply->data;
+ hdr->msg_len = out_size;
+ hdr->cmd = cmd;
+ (void)skb_put(reply, out_size);
+
+ roce3_nlahdr_push(reply, USRNL_GENL_ATTR);
+ roce3_genlmsg_push(reply, nl_info->snd_portid, nl_info->snd_seq,
+ &roce3_genl_family, 0, USRNL_DEV_DRV_CMD_EXECUTE);
+ genlmsg_reply(reply, nl_info);
+
+ return rc;
+}
+
+/* pf use 32, vf use 96 */
+int get_instance_of_func_id(int glb_func_id)
+{
+ return glb_func_id > PF_MAX_SIZE ? glb_func_id % VF_USE_SIZE + PF_MAX_SIZE :
+ glb_func_id;
+}
+
+int roce3_netlink_init(void)
+{
+ int err;
+
+ err = genl_register_family(&roce3_genl_family);
+
+ return err;
+}
+
+void roce3_netlink_unit(void)
+{
+ genl_unregister_family(&roce3_genl_family);
+}
+
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/roce_netlink.h b/drivers/infiniband/hw/hiroce3/roce_netlink.h
new file mode 100644
index 0000000000000..684fc32eb7086
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_netlink.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef _ROCE_NETLINK_H_
+#define _ROCE_NETLINK_H_
+#ifdef ROCE_NETLINK_EN
+#include <net/netlink.h>
+#include <net/net_namespace.h>
+#include <linux/netlink.h>
+
+#include "udk_usrnl.h"
+#include "roce_k_ioctl.h"
+#include "roce.h"
+
+#define USRNL_GENL_ATTR_MAX (__USRNL_GENL_ATTR_MAX - 1)
+
+/* netlink server info in roce ko */
+#define ROCE3_FAMILY "ROCE"
+#define ROCE3_VERSION 0x1
+#define ROCE_MAX_FUNCTION 128
+#define PF_MAX_SIZE 32
+#define VF_USE_SIZE 96
+
+#define P2PCOS_MAX_VALUE 2
+#define MAX_COS_NUM 0x7
+
+#ifndef __NET_GENERIC_NETLINK_H
+/* 解决genentlink 头文件冲突问题 */
+struct genlmsghdr {
+ u8 cmd;
+ u8 version;
+ u16 reserved;
+};
+#define USER_PTR_SIZE 2
+
+/* length of family name */
+
+#define GENL_NAMSIZ 16
+#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr))
+
+struct genl_info {
+ u32 snd_seq;
+ u32 snd_portid;
+ struct nlmsghdr *nlhdr;
+ struct genlmsghdr *genlhdr;
+ void *userhdr;
+ struct nlattr **attrs;
+ possible_net_t _net;
+ void *user_ptr[USER_PTR_SIZE];
+ struct netlink_ext_ack *extack;
+};
+
+struct genl_ops {
+ int (*doit)(struct sk_buff *skb, struct genl_info *info);
+ int (*start)(struct netlink_callback *cb);
+ int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb);
+ int (*done)(struct netlink_callback *cb);
+ const struct nla_policy *policy;
+ unsigned int maxattr;
+ u8 cmd;
+ u8 internal_flags;
+ u8 flags;
+ u8 validate;
+};
+
+struct genl_small_ops {
+ int (*doit)(struct sk_buff *skb, struct genl_info *info);
+ int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb);
+ u8 cmd;
+ u8 internal_flags;
+ u8 flags;
+ u8 validate;
+};
+
+struct genl_multicast_group {
+ char name[GENL_NAMSIZ];
+};
+
+struct genl_family {
+/* private */
+ int id;
+ unsigned int hdrsize;
+ char name[GENL_NAMSIZ];
+ unsigned int version;
+ unsigned int maxattr;
+ unsigned int mcgrp_offset;
+ u8 netnsok : 1;
+ u8 parallel_ops : 1;
+ u8 n_ops;
+ u8 n_small_ops;
+ u8 n_mcgrps;
+ const struct nla_policy *policy;
+ int (*pre_doit)(const struct genl_ops *ops,
+ struct sk_buff *skb,
+ struct genl_info *info);
+ void (*post_doit)(const struct genl_ops *ops,
+ struct sk_buff *skb,
+ struct genl_info *info);
+ const struct genl_ops *ops;
+ const struct genl_small_ops *small_ops;
+ const struct genl_multicast_group *mcgrps;
+ struct module *module;
+};
+
+static inline int genlmsg_unicast(struct net *net, struct sk_buff *skb, u32 portid)
+{
+ return nlmsg_unicast(net->genl_sock, skb, portid);
+}
+
+static inline struct net *genl_info_net(struct genl_info *info)
+{
+ return read_pnet(&info->_net);
+}
+
+static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info)
+{
+ return genlmsg_unicast(genl_info_net(info), skb, info->snd_portid);
+}
+extern int genl_register_family(struct genl_family *family);
+extern int genl_unregister_family(const struct genl_family *family);
+
+#endif
+enum hiroce_drv_cmd_type {
+ HIROCE_DRV_CMD_DCB_GET = 100,
+ HIROCE_DRV_CMD_CREATE_AH,
+ HIROCE_DRV_CMD_MAX
+};
+
+struct hiroce_dev_dcbinfo_get {
+ usrnl_drv_msg_hdr_s hdr;
+ union roce3_query_dcb_buf dcb_info;
+ uint16_t func_id;
+ uint16_t rsvd;
+};
+
+struct hiroce_dev_dcbinfo_rsp {
+ usrnl_drv_msg_hdr_s hdr;
+ union roce3_query_dcb_buf dcb_info;
+};
+
+struct hiroce_dev_ah_info {
+ usrnl_drv_msg_hdr_s hdr;
+ union roce3_create_ah_buf ah_info;
+ uint16_t func_id;
+ uint16_t rsvd;
+};
+
+struct netlink_dev {
+ struct roce3_device *rdev[ROCE_MAX_FUNCTION];
+};
+
+struct hiroce_netlink_dev {
+ int used_dev_num;
+ struct netlink_dev *netlink;
+ struct mutex mutex_dev;
+};
+
+int get_instance_of_func_id(int glb_func_id);
+struct hiroce_netlink_dev *hiroce_get_adp(void);
+int roce3_netlink_init(void);
+void roce3_netlink_unit(void);
+
+#endif // ROCE_NETLINK_EN
+#endif
diff --git a/drivers/infiniband/hw/hiroce3/roce_pd.c b/drivers/infiniband/hw/hiroce3/roce_pd.c
new file mode 100644
index 0000000000000..494184106c69c
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_pd.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/slab.h>
+
+#include "roce.h"
+#include "roce_main_extension.h"
+#include "roce_pd.h"
+
+int roce3_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
+{
+ int ret;
+ struct roce3_pd *pd = to_roce3_pd(ibpd);
+ struct roce3_device *rdev = to_roce3_dev(ibpd->device);
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ ret = roce3_rdma_pd_alloc(rdev->hwdev, &pd->pdn);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc pdn, ret(%d), func_id(%u)\n",
+ __func__, ret, rdev->glb_func_id);
+ goto err_out;
+ }
+
+ pd->func_id = rdev->glb_func_id;
+ if (udata) {
+ if (ib_copy_to_udata(udata, &pd->pdn, PD_RESP_SIZE) != 0) {
+ ret = -EFAULT;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to copy data to user space, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ goto err_copy_to_user;
+ }
+ }
+
+ return 0;
+
+err_copy_to_user:
+ roce3_rdma_pd_free(rdev->hwdev, pd->pdn);
+err_out:
+ return ret;
+}
+
+int roce3_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
+{
+ struct roce3_pd *pd = NULL;
+ struct roce3_device *rdev = NULL;
+
+ if (ibpd == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibpd is null\n", __func__);
+ return -EINVAL;
+ }
+
+ pd = to_roce3_pd(ibpd);
+ rdev = to_roce3_dev(ibpd->device);
+
+ roce3_rdma_pd_free(rdev->hwdev, pd->pdn);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/roce_pd.h b/drivers/infiniband/hw/hiroce3/roce_pd.h
new file mode 100644
index 0000000000000..020c8354b4d36
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_pd.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_PD_H
+#define ROCE_PD_H
+
+#include <rdma/ib_verbs.h>
+
+#include "roce.h"
+
+#define PD_RESP_SIZE (2 * sizeof(u32))
+struct roce3_pd {
+ struct ib_pd ibpd;
+ u32 pdn;
+ u16 func_id;
+ u16 rsvd;
+};
+
+static inline struct roce3_pd *to_roce3_pd(const struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct roce3_pd, ibpd);
+}
+
+#endif // ROCE_PD_H
diff --git a/drivers/infiniband/hw/hiroce3/roce_sysfs.c b/drivers/infiniband/hw/hiroce3/roce_sysfs.c
new file mode 100644
index 0000000000000..1503def0f1ae7
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_sysfs.c
@@ -0,0 +1,1800 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/types.h>
+
+#include "hinic3_hw.h"
+#include "rdma_context_format.h"
+#include "roce.h"
+#include "roce_dfx.h"
+#include "roce_cmd.h"
+#include "roce_qp.h"
+
+#include "roce_sysfs.h"
+
+#define ROCE_DEFAULT_IP_EABLE_EN 1
+#define ROCE_DEFAULT_IP_EABLE_DIS 0
+#define ROCE_DEFAULT_MIN_CNP_PERIOD 16
+#define ROCE_DEFAULT_ALPHA_DEC_PERIOD 160
+#define ROCE_DEFAULT_RATE_DEC_PERIOD 32
+#define ROCE_DEFAULT_RATE_INC_PERIOD 480
+#define ROCE_DEFAULT_ALPHA_THRESHOLD 4 // 32, uint 8
+#define ROCE_DEFAULT_CNP_CNT_THRESHOLD 6
+#define ROCE_DEFAULT_PORT_MODE_25G 0
+#define ROCE_DEFAULT_FACTOR_GITA 7
+#define ROCE_DEFAULT_INITIAL_ALPHA 1023
+#define ROCE_DEFAULT_RATE_INC_AI 2
+#define ROCE_DEFAULT_RATE_INC_HAI 8
+#define ROCE_DEFAULT_RATE_FIRST_SET 1024
+#define ROCE_DEFAULT_RATE_TARGET_CLAMP 1
+#define ROCE_DEFAULT_QUICK_AJ_ENABLE 0
+#define ROCE_DEFAULT_CNP_PRIO_ENABLE 0
+#define ROCE_DEFAULT_CNP_PRIO 0
+#define ROCE_DEFAULT_TOKEN_PERIOD 16
+#define ROCE_DEFAULT_MIN_RATE 1
+#define ROCE_DEFAULT_WND_RESET_RATIO 0
+#define ROCE_DEFAULT_WND_RESET_TIMEOUT 0
+#define ROCE_PORT_MODE_MASK 0xfffffffe
+#define ROCE_QUICK_AJ_EN_MASK 0xfffffffe
+#define ROCE_CNP_PRIO_EN_MASK 0xfffffffe
+#define ROCE_RT_CLAMP_MASK 0xfffffffe
+#define ROCE_PRIO_EN_MASK 0xfffffffe
+#define ROCE_MIN_RATE_INC_HAI 1
+#define ROCE_MAX_RATE_INC_HAI 255
+#define ROCE_MIN_RATE_INC_AI 1
+#define ROCE_MAX_RATE_INC_AI 63
+#define ROCE_MIN_INITIAL_ALPHA 127
+#define ROCE_MAX_INITIAL_ALPHA 1023
+#define ROCE_MIN_RATE_INC_PERIOD 1
+#define ROCE_MAX_RATE_INC_PERIOD 1024
+#define ROCE_MIN_ALPHA_DEC_PERIOD 1
+#define ROCE_MAX_ALPHA_DEC_PERIOD 1024
+#define ROCE_MIN_TOKEN_PERIOD 4
+#define ROCE_MAX_TOKEN_PERIOD 255
+#define ROCE_MIN_FLOW_MIN_RATE 1
+#define ROCE_MAX_FLOW_MIN_RATE 64
+#define ROCE_MIN_WND_RESET_RATIO 0
+#define ROCE_MAX_WND_RESET_RATIO 0xf
+#define ROCE_MIN_WND_RESET_TIMEOUT 0
+#define ROCE_MAX_WND_RESET_TIMEOUT 0xf
+#define ROCE_MIN_ALPHA_THRESHOLD 8
+#define ROCE_MAX_ALPHA_THRESHOLD 248
+#define ROCE_MIN_CNP_CNT_THRESHOLD 1
+#define ROCE_MAX_CNP_CNT_THRESHOLD 15
+#define ROCE_MIN_RATE_DEC_PERIOD 1
+#define ROCE_MAX_RATE_DEC_PERIOD 255
+#define ROCE_MIN_MIN_CNP_PERIOD 1
+#define ROCE_MAX_MIN_CNP_PERIOD 255
+#define ROCE_MIN_FACTOR_GITA 1
+#define ROCE_MAX_FACTOR_GITA 15
+#define ROCE_MIN_RATE_FIRST_SET 128
+#define ROCE_MAX_RATE_FIRST_SET 8191
+
+#define MAX_STRING_FORMAT_LEN 64
+
+/* ECN VER */
+#define ECN_VER_DCQCN 0
+#define ECN_VER_PATHQCN 1
+
+enum {
+ ROCE_DCQCN_NP = 0,
+ ROCE_DCQCN_RP = 1
+};
+
+#define to_roce3_ecn_ctx(_kobj) container_of(_kobj, struct roce3_ecn_ctx, ecn_root)
+#define to_roce3_ecn_np_ctx(_kobj) container_of(_kobj, struct roce3_ecn_np_ctx, ecn_np_root)
+#define to_roce3_ecn_rp_ctx(_kobj) container_of(_kobj, struct roce3_ecn_rp_ctx, ecn_rp_root)
+
+#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, 0640, _show, _store)
+
+#define ROCE_ATTR_PTR(_name) (&roce_attr_##_name.attr)
+
+static int roce3_update_cfg_ccf_param(struct roce3_device *rdev,
+ const struct roce3_ecn_ctx *ecn_ctx)
+{
+ const struct roce3_prio_enable_ctx *prio_enable_ctx = NULL;
+ const struct roce3_ip_prio_enable_ctx *ip_prio_enable_ctx = NULL;
+ struct roce_ccf_param ccf_param;
+ int ret, i;
+
+ memset(&ccf_param, 0, sizeof(ccf_param));
+
+ for (i = 0; i < PRI_ARRAY_LEN; i++) {
+ prio_enable_ctx = &ecn_ctx->np_ctx.enable_ctx.prio_enable[i];
+ ccf_param.dw0.bs.np_enable |= (prio_enable_ctx->prio_en << prio_enable_ctx->prio);
+ prio_enable_ctx = &ecn_ctx->rp_ctx.enable_ctx.prio_enable[i];
+ ccf_param.dw0.bs.rp_enable |= (prio_enable_ctx->prio_en << prio_enable_ctx->prio);
+ ip_prio_enable_ctx = &ecn_ctx->ip_enable_ctx.ip_prio_enable[i];
+ ccf_param.dw0.bs.ip_enable |=
+ (ip_prio_enable_ctx->prio_en << ip_prio_enable_ctx->prio);
+ }
+
+ ccf_param.dw0.bs.cnp_prio_enable = ecn_ctx->np_ctx.cnp_prio_enable;
+ ccf_param.dw0.bs.port_mode = ecn_ctx->np_ctx.port_mode;
+ ccf_param.dw1.bs.cnp_prio = ecn_ctx->np_ctx.cnp_prio;
+ ccf_param.dw1.bs.cnp_cos = roce3_get_db_cos_from_vlan_pri(rdev, ccf_param.dw1.bs.cnp_prio);
+ ccf_param.dw1.bs.ccf_appid = ecn_ctx->cc_algo;
+
+ ret = roce3_set_cfg_ccf_param(rdev->hwdev, rdev->glb_func_id, (u32 *)&ccf_param);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] : Failed to set ccf param, func_id(%d) ret(%d)\n",
+ rdev->glb_func_id, ret);
+ }
+
+ return ret;
+}
+
+static int roce3_update_dcqcn_param(struct roce3_device *rdev, const struct roce3_ecn_ctx *ecn_ctx)
+{
+ struct roce_dcqcn_param dcqcn_param;
+ int ret;
+
+ memset(&dcqcn_param, 0, sizeof(dcqcn_param));
+
+ dcqcn_param.dw0.bs.token_period = ecn_ctx->rp_ctx.token_period;
+ dcqcn_param.dw0.bs.flow_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_threshold = ecn_ctx->rp_ctx.alpha_threshold;
+ dcqcn_param.dw1.bs.cnp_cnt_threshold = ecn_ctx->rp_ctx.cnp_cnt_threshold;
+ 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.factor_gita = ecn_ctx->rp_ctx.factor_gita;
+ dcqcn_param.dw3.bs.rt_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 = roce3_set_cfg_dcqcn_param(rdev->hwdev, rdev->glb_func_id,
+ (u32 *)(void *)&dcqcn_param);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] : Failed to set dcqcn param, func_id(%d), ret(%d)\n",
+ rdev->glb_func_id, ret);
+ }
+
+ return ret;
+}
+
+static int roce3_update_ipqcn_param(struct roce3_device *rdev, const struct roce3_ecn_ctx *ecn_ctx)
+{
+ struct roce_ipqcn_param ipqcn_param;
+ int ret;
+
+ memset(&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_threshold = ecn_ctx->rp_ctx.alpha_threshold;
+ ipqcn_param.dw1.bs.cnp_cnt_threshold = ecn_ctx->rp_ctx.cnp_cnt_threshold;
+ 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 = roce3_set_cfg_ipqcn_param(rdev->hwdev, rdev->glb_func_id,
+ (u32 *)(void *)&ipqcn_param);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] : Failed to set ipqcn param, func_id(%d) ret(%d)\n",
+ rdev->glb_func_id, ret);
+ }
+
+ return ret;
+}
+
+typedef int (*roce3_update_param_t)(struct roce3_device *rdev, const struct roce3_ecn_ctx *ecn_ctx);
+
+static roce3_update_param_t roce3_update_param_funcs[] = {
+ roce3_update_cfg_ccf_param,
+ roce3_update_dcqcn_param,
+ roce3_update_ipqcn_param,
+};
+
+int roce3_update_ecn_param(const struct roce3_ecn_ctx *ecn_ctx)
+{
+ unsigned int i;
+ int ret = 0;
+ struct roce3_device *rdev = container_of(ecn_ctx, struct roce3_device, ecn_ctx);
+
+ for (i = 0; i < (sizeof(roce3_update_param_funcs) / sizeof(roce3_update_param_t)); i++) {
+ ret = roce3_update_param_funcs[i](rdev, ecn_ctx);
+ if (ret != 0)
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t roce3_show_cc_algo(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj);
+
+ if ((attr == NULL) || (buf == NULL)) {
+ pr_err("[ROCE] %s: attr or buf is null\n", __func__);
+ return -EINVAL;
+ }
+
+ switch ((int)ecn_ctx->cc_algo) {
+ case ROCE_CC_DISABLE:
+ return sprintf(buf, "%s\n", "disable");
+ case ROCE_CC_DCQCN_ALGO:
+ return sprintf(buf, "%s\n", "dcqcn");
+ case ROCE_CC_LDCP_ALGO:
+ return sprintf(buf, "%s\n", "ldcp");
+ case ROCE_CC_IPQCN_ALGO:
+ return sprintf(buf, "%s\n", "hc3_1/ipqcn");
+ default:
+ return sprintf(buf, "%s\n", "error_type");
+ }
+}
+
+static ssize_t roce3_store_cc_algo(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj);
+ u32 old_cc_algo = 0;
+ int cc_algo = 0;
+ ssize_t ret;
+
+ if ((attr == NULL) || (buf == NULL)) {
+ pr_err("[ROCE] %s: attr or buf is null\n", __func__);
+ 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 {
+ pr_err("[ROCE] %s: Invalid cc_algo(%d),buf(%s)\n", __func__, 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 = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to update cc_algo param, ret(%d)",
+ __func__, (int)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 roce3_show_ecn_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_prio_enable_ctx *prio_enable_ctx =
+ container_of(attr, struct roce3_prio_enable_ctx, enable);
+
+ return sprintf(buf, "%d\n", (int)prio_enable_ctx->prio_en);
+}
+
+static ssize_t roce3_store_ecn_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int prio_en = 0;
+ u32 old_prio_en = 0;
+ struct roce3_ecn_rp_ctx *rp_ctx = NULL;
+ struct roce3_ecn_np_ctx *np_ctx = NULL;
+ struct roce3_ecn_ctx *ecn_ctx = NULL;
+ struct roce3_prio_enable_ctx *prio_enable_ctx =
+ container_of(attr, struct roce3_prio_enable_ctx, enable);
+ struct roce3_ecn_enable_ctx *ecn_enable_ctx =
+ (struct roce3_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 roce3_ecn_np_ctx, enable_ctx);
+ ecn_ctx = container_of(np_ctx, struct roce3_ecn_ctx, np_ctx);
+ } else {
+ rp_ctx = container_of(ecn_enable_ctx, struct roce3_ecn_rp_ctx, enable_ctx);
+ ecn_ctx = container_of(rp_ctx, struct roce3_ecn_ctx, rp_ctx);
+ }
+
+ ret = kstrtoint(buf, 10, &prio_en);
+ if (ret != 0)
+ return -EIO;
+
+ if (((u32)prio_en & ROCE_PRIO_EN_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 = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ 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 roce3_show_ecn_ip_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ip_prio_enable_ctx *ip_prio_enable_ctx =
+ container_of(attr, struct roce3_ip_prio_enable_ctx, ip_enable);
+
+ return sprintf(buf, "%d\n", (int)ip_prio_enable_ctx->prio_en);
+}
+
+static ssize_t roce3_store_ecn_ip_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int prio_en = 0;
+ u32 old_prio_en = 0;
+ struct roce3_ip_prio_enable_ctx *ip_prio_enable_ctx =
+ container_of(attr, struct roce3_ip_prio_enable_ctx, ip_enable);
+ struct roce3_ecn_ip_enable_ctx *ip_enable_ctx =
+ (struct roce3_ecn_ip_enable_ctx *)ip_prio_enable_ctx->ecn_ip_enable_ctx;
+ struct roce3_ecn_ctx *ecn_ctx = container_of(ip_enable_ctx,
+ struct roce3_ecn_ctx, ip_enable_ctx);
+
+ ret = kstrtoint(buf, 10, &prio_en);
+ if (ret != 0)
+ return -EIO;
+
+ if (((u32)prio_en & ROCE_PRIO_EN_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 = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ 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;
+}
+
+static ssize_t roce3_show_rate_inc_hai(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->rate_inc_hai);
+}
+
+static ssize_t roce3_store_rate_inc_hai(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int rate_inc_hai = 0;
+ u32 old_rate_inc_hai = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &rate_inc_hai);
+ if (ret != 0)
+ return -EIO;
+
+ if ((rate_inc_hai < ROCE_MIN_RATE_INC_HAI) || (rate_inc_hai > ROCE_MAX_RATE_INC_HAI))
+ return -EIO;
+
+ if (ecn_rp_ctx->rate_inc_hai != (u32)rate_inc_hai) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_rate_inc_hai = ecn_rp_ctx->rate_inc_hai;
+ ecn_rp_ctx->rate_inc_hai = (u32)rate_inc_hai;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->rate_inc_hai = old_rate_inc_hai;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_rate_inc_ai(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->rate_inc_ai);
+}
+
+static ssize_t roce3_store_rate_inc_ai(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int rate_inc_ai = 0;
+ u32 old_rate_inc_ai = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &rate_inc_ai);
+ if (ret != 0)
+ return -EIO;
+
+ if ((rate_inc_ai < ROCE_MIN_RATE_INC_AI) || (rate_inc_ai > ROCE_MAX_RATE_INC_AI))
+ return -EIO;
+
+ if (ecn_rp_ctx->rate_inc_ai != (u32)rate_inc_ai) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_rate_inc_ai = ecn_rp_ctx->rate_inc_ai;
+ ecn_rp_ctx->rate_inc_ai = (u32)rate_inc_ai;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->rate_inc_ai = old_rate_inc_ai;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_initial_alpha(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->initial_alpha);
+}
+
+static ssize_t roce3_store_initial_alpha(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int initial_alpha = 0;
+ u32 old_initial_alpha = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &initial_alpha);
+ if (ret != 0)
+ return -EIO;
+
+ if ((initial_alpha < ROCE_MIN_INITIAL_ALPHA) || (initial_alpha > ROCE_MAX_INITIAL_ALPHA))
+ return -EIO;
+
+ if (ecn_rp_ctx->initial_alpha != (u32)initial_alpha) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_initial_alpha = ecn_rp_ctx->initial_alpha;
+ ecn_rp_ctx->initial_alpha = (u32)initial_alpha;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->initial_alpha = old_initial_alpha;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_factor_gita(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->factor_gita);
+}
+
+static ssize_t roce3_store_factor_gita(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int factor_gita = 0;
+ u32 old_factor_gita = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &factor_gita);
+ if (ret != 0)
+ return -EIO;
+
+ if ((factor_gita < ROCE_MIN_FACTOR_GITA) || (factor_gita > ROCE_MAX_FACTOR_GITA))
+ return -EIO;
+
+ if (ecn_rp_ctx->factor_gita != (u32)factor_gita) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_factor_gita = ecn_rp_ctx->factor_gita;
+ ecn_rp_ctx->factor_gita = (u32)factor_gita;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->factor_gita = old_factor_gita;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_rate_inc_period(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->rate_inc_period);
+}
+
+static ssize_t roce3_store_rate_inc_period(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int rate_inc_period = 0;
+ u32 old_rate_inc_period = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &rate_inc_period);
+ if (ret != 0)
+ return -EIO;
+
+ if ((rate_inc_period < ROCE_MIN_RATE_INC_PERIOD) ||
+ (rate_inc_period > ROCE_MAX_RATE_INC_PERIOD))
+ return -EIO;
+
+ if (ecn_rp_ctx->rate_inc_period != (u32)rate_inc_period) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_rate_inc_period = ecn_rp_ctx->rate_inc_period;
+ ecn_rp_ctx->rate_inc_period = (u32)rate_inc_period;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->rate_inc_period = old_rate_inc_period;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_cnp_cnt_threshold(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->cnp_cnt_threshold);
+}
+
+static ssize_t roce3_store_cnp_cnt_threshold(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int cnp_cnt_threshold = 0;
+ u32 old_cnp_cnt_threshold = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &cnp_cnt_threshold);
+ if (ret != 0)
+ return -EIO;
+
+ if ((cnp_cnt_threshold < ROCE_MIN_CNP_CNT_THRESHOLD) ||
+ (cnp_cnt_threshold > ROCE_MAX_CNP_CNT_THRESHOLD))
+ return -EIO;
+
+ if (ecn_rp_ctx->cnp_cnt_threshold != (u32)cnp_cnt_threshold) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_cnp_cnt_threshold = ecn_rp_ctx->cnp_cnt_threshold;
+ ecn_rp_ctx->cnp_cnt_threshold = (u32)cnp_cnt_threshold;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->cnp_cnt_threshold = old_cnp_cnt_threshold;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_alpha_threshold(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n",
+ (int)(ecn_rp_ctx->alpha_threshold << ALPHA_THREADHOLD_UNIT_SHIFT));
+}
+
+static ssize_t roce3_store_alpha_threshold(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ u32 alpha_threshold = 0;
+ u32 old_alpha_threshold = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &alpha_threshold);
+ if (ret != 0)
+ return -EIO;
+
+ if ((alpha_threshold < ROCE_MIN_ALPHA_THRESHOLD) ||
+ (alpha_threshold > ROCE_MAX_ALPHA_THRESHOLD))
+ return -EIO;
+ alpha_threshold = ((u32)alpha_threshold >> ALPHA_THREADHOLD_UNIT_SHIFT);
+
+ if (ecn_rp_ctx->alpha_threshold != (u32)alpha_threshold) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_alpha_threshold = ecn_rp_ctx->alpha_threshold;
+ ecn_rp_ctx->alpha_threshold = (u32)alpha_threshold;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->alpha_threshold = old_alpha_threshold;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_rate_dec_period(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->rate_dec_period);
+}
+
+static ssize_t roce3_store_rate_dec_period(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int rate_dec_period = 0;
+ u32 old_rate_dec_period = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &rate_dec_period);
+ if (ret != 0)
+ return -EIO;
+
+ if ((rate_dec_period < ROCE_MIN_RATE_DEC_PERIOD) ||
+ (rate_dec_period > ROCE_MAX_RATE_DEC_PERIOD))
+ return -EIO;
+
+ if (ecn_rp_ctx->rate_dec_period != (u32)rate_dec_period) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_rate_dec_period = ecn_rp_ctx->rate_dec_period;
+ ecn_rp_ctx->rate_dec_period = (u32)rate_dec_period;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->rate_dec_period = old_rate_dec_period;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_token_period(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->token_period);
+}
+
+static ssize_t roce3_store_token_period(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int token_period = 0;
+ u32 old_token_period = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &token_period);
+ if (ret != 0)
+ return -EIO;
+
+ if ((token_period < ROCE_MIN_TOKEN_PERIOD) ||
+ (token_period > ROCE_MAX_TOKEN_PERIOD))
+ return -EIO;
+
+ if (ecn_rp_ctx->token_period != (u32)token_period) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_token_period = ecn_rp_ctx->token_period;
+ ecn_rp_ctx->token_period = (u32)token_period;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->token_period = old_token_period;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_min_rate(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->min_rate);
+}
+
+static ssize_t roce3_store_min_rate(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int min_rate = 0;
+ u32 old_min_rate = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &min_rate);
+ if (ret != 0)
+ return -EIO;
+
+ if ((min_rate < ROCE_MIN_FLOW_MIN_RATE) || (min_rate > ROCE_MAX_FLOW_MIN_RATE))
+ return -EIO;
+
+ if (ecn_rp_ctx->token_period != (u32)min_rate) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_min_rate = ecn_rp_ctx->min_rate;
+ ecn_rp_ctx->min_rate = (u32)min_rate;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->min_rate = old_min_rate;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_alpha_dec_period(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->alpha_dec_period);
+}
+
+static ssize_t roce3_store_alpha_dec_period(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int alpha_dec_period = 0;
+ u32 old_alpha_dec_period = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &alpha_dec_period);
+ if (ret != 0)
+ return -EIO;
+
+ if ((alpha_dec_period < ROCE_MIN_ALPHA_DEC_PERIOD) ||
+ (alpha_dec_period > ROCE_MAX_ALPHA_DEC_PERIOD))
+ return -EIO;
+
+ if (ecn_rp_ctx->alpha_dec_period != (u32)alpha_dec_period) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_alpha_dec_period = ecn_rp_ctx->alpha_dec_period;
+ ecn_rp_ctx->alpha_dec_period = (u32)alpha_dec_period;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->alpha_dec_period = old_alpha_dec_period;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_rate_first_set(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->rate_first_set);
+}
+
+static ssize_t roce3_store_rate_first_set(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int rate_first_set = 0;
+ u32 old_rate_first_set = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &rate_first_set);
+ if (ret != 0)
+ return -EIO;
+
+ if ((rate_first_set < ROCE_MIN_RATE_FIRST_SET) ||
+ (rate_first_set > ROCE_MAX_RATE_FIRST_SET))
+ return -EIO;
+
+ if (ecn_rp_ctx->rate_first_set != (u32)rate_first_set) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_rate_first_set = ecn_rp_ctx->rate_first_set;
+ ecn_rp_ctx->rate_first_set = (u32)rate_first_set;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_rp_ctx->rate_first_set = old_rate_first_set;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_rate_target_clamp(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_rp_ctx->rate_target_clamp);
+}
+
+static ssize_t roce3_store_rate_target_clamp(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int rate_target_clamp = 0;
+ u32 old_rate_target_clamp = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_rp_ctx *ecn_rp_ctx = to_roce3_ecn_rp_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &rate_target_clamp);
+ if (ret != 0)
+ return -EIO;
+
+ if (((u32)rate_target_clamp & ROCE_RT_CLAMP_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 = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ 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;
+}
+
+static ssize_t roce3_show_min_cnp_period(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_np_ctx->min_cnp_period);
+}
+
+static ssize_t roce3_store_min_cnp_period(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int min_cnp_period = 0;
+ u32 old_min_cnp_period = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &min_cnp_period);
+ if (ret != 0)
+ return -EIO;
+
+ if ((min_cnp_period < ROCE_MIN_MIN_CNP_PERIOD) ||
+ (min_cnp_period > ROCE_MAX_MIN_CNP_PERIOD))
+ return -EIO;
+
+ if (ecn_np_ctx->min_cnp_period != (u32)min_cnp_period) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_min_cnp_period = ecn_np_ctx->min_cnp_period;
+ ecn_np_ctx->min_cnp_period = (u32)min_cnp_period;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_np_ctx->min_cnp_period = old_min_cnp_period;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_port_mode(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_np_ctx->port_mode);
+}
+
+static ssize_t roce3_store_port_mode(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int port_mode = 0;
+ u32 old_port_mode = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &port_mode);
+ if (ret != 0)
+ return -EIO;
+
+ if (((u32)port_mode & ROCE_PORT_MODE_MASK) != 0)
+ return -EIO;
+
+ if (ecn_np_ctx->port_mode != (u32)port_mode) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_port_mode = ecn_np_ctx->port_mode;
+ ecn_np_ctx->port_mode = (u32)port_mode;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_np_ctx->port_mode = old_port_mode;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_quick_adjust_en(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_np_ctx->quick_adjust_en);
+}
+
+static ssize_t roce3_store_quick_adjust_en(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int quick_adjust_en = 0;
+ u32 old_quick_adjust_en = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &quick_adjust_en);
+ if (ret != 0)
+ return -EIO;
+
+ if (((u32)quick_adjust_en & ROCE_QUICK_AJ_EN_MASK) != 0)
+ return -EIO;
+
+ if (ecn_np_ctx->quick_adjust_en != (u32)quick_adjust_en) {
+ mutex_lock(&ecn_ctx->ecn_mutex);
+ old_quick_adjust_en = ecn_np_ctx->quick_adjust_en;
+ ecn_np_ctx->quick_adjust_en = (u32)quick_adjust_en;
+ ret = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ ecn_np_ctx->quick_adjust_en = old_quick_adjust_en;
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ return -EIO;
+ }
+ mutex_unlock(&ecn_ctx->ecn_mutex);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_show_cnp_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_np_ctx->cnp_prio_enable);
+}
+
+static ssize_t roce3_store_cnp_prio_enable(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int cnp_prio_enable = 0;
+ u32 old_cnp_prio_enable = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &cnp_prio_enable);
+ if (ret != 0)
+ return -EIO;
+
+ if (((u32)cnp_prio_enable & ROCE_CNP_PRIO_EN_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 = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ 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;
+}
+
+static ssize_t roce3_show_cnp_prio(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_np_ctx->cnp_prio);
+}
+
+static ssize_t roce3_store_cnp_prio(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int cnp_prio = 0;
+ u32 old_cnp_prio = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj->parent);
+ struct roce3_ecn_np_ctx *ecn_np_ctx = to_roce3_ecn_np_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &cnp_prio);
+ if (ret != 0)
+ 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 = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ 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 roce3_init_ecn_enable_sysfs(struct kobject *kobj,
+ struct roce3_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 roce3_prio_enable_ctx *prio_enable = NULL;
+
+ ecn_enable_ctx->enable_root = kobject_create_and_add("enable", kobj);
+ if (ecn_enable_ctx->enable_root == NULL) {
+ pr_err("[ROCE, ERR] %s: Failed to create kobject for ecn enable.(ret:%d)\n",
+ __func__, 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 = 0640;
+ prio_enable->enable.show = roce3_show_ecn_prio_enable;
+ prio_enable->enable.store = roce3_store_ecn_prio_enable;
+ ret = sysfs_create_file(ecn_enable_ctx->enable_root, &prio_enable->enable.attr);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to create file for ecn enable.(ret:%d)\n",
+ __func__, 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 roce3_remove_ecn_enable_sysfs(struct kobject *kobj,
+ struct roce3_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 roce3_init_ecn_ip_enable_sysfs(struct kobject *kobj,
+ struct roce3_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 roce3_ip_prio_enable_ctx *ip_prio_enable = NULL;
+
+ ip_enable_ctx->ip_enable_root = kobject_create_and_add("ip_enable", kobj);
+ if (ip_enable_ctx->ip_enable_root == NULL) {
+ pr_err("[ROCE, ERR] %s: Failed to create kobject for ecn ip enable.(ret:%d)\n",
+ __func__, 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 = ROCE_DEFAULT_IP_EABLE_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 = 0640;
+ ip_prio_enable->ip_enable.show = roce3_show_ecn_ip_prio_enable;
+ ip_prio_enable->ip_enable.store = roce3_store_ecn_ip_prio_enable;
+ ret = sysfs_create_file(ip_enable_ctx->ip_enable_root,
+ &ip_prio_enable->ip_enable.attr);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to create file for ecn ip enable.(ret:%d)\n",
+ __func__, 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 roce3_remove_ecn_ip_enable_sysfs(struct kobject *kobj,
+ struct roce3_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(alpha_dec_period, roce3_show_alpha_dec_period, roce3_store_alpha_dec_period);
+ROCE_ATTR_RW(rate_dec_period, roce3_show_rate_dec_period, roce3_store_rate_dec_period);
+ROCE_ATTR_RW(rate_inc_period, roce3_show_rate_inc_period, roce3_store_rate_inc_period);
+ROCE_ATTR_RW(cnp_cnt_threshold, roce3_show_cnp_cnt_threshold, roce3_store_cnp_cnt_threshold);
+ROCE_ATTR_RW(alpha_threshold, roce3_show_alpha_threshold, roce3_store_alpha_threshold);
+ROCE_ATTR_RW(factor_gita, roce3_show_factor_gita, roce3_store_factor_gita);
+ROCE_ATTR_RW(initial_alpha, roce3_show_initial_alpha, roce3_store_initial_alpha);
+ROCE_ATTR_RW(rate_inc_ai, roce3_show_rate_inc_ai, roce3_store_rate_inc_ai);
+ROCE_ATTR_RW(rate_inc_hai, roce3_show_rate_inc_hai, roce3_store_rate_inc_hai);
+ROCE_ATTR_RW(rate_first_set, roce3_show_rate_first_set, roce3_store_rate_first_set);
+ROCE_ATTR_RW(rate_target_clamp, roce3_show_rate_target_clamp, roce3_store_rate_target_clamp);
+ROCE_ATTR_RW(token_period, roce3_show_token_period, roce3_store_token_period);
+ROCE_ATTR_RW(min_rate, roce3_show_min_rate, roce3_store_min_rate);
+
+static struct attribute *ecn_rp_ctx_attrs[] = {
+ ROCE_ATTR_PTR(alpha_dec_period),
+ ROCE_ATTR_PTR(rate_dec_period),
+ ROCE_ATTR_PTR(rate_inc_period),
+ ROCE_ATTR_PTR(cnp_cnt_threshold),
+ ROCE_ATTR_PTR(alpha_threshold),
+ 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,
+};
+ATTRIBUTE_GROUPS(ecn_rp_ctx);
+
+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,
+ .default_groups = ecn_rp_ctx_groups,
+};
+
+static int roce3_init_ecn_rp_sysfs(struct kobject *kobj, struct roce3_ecn_rp_ctx *ecn_rp_ctx)
+{
+ int ret = 0;
+
+ ecn_rp_ctx->alpha_dec_period = ROCE_DEFAULT_ALPHA_DEC_PERIOD;
+ ecn_rp_ctx->rate_dec_period = ROCE_DEFAULT_RATE_DEC_PERIOD;
+ ecn_rp_ctx->rate_inc_period = ROCE_DEFAULT_RATE_INC_PERIOD;
+ ecn_rp_ctx->alpha_threshold = ROCE_DEFAULT_ALPHA_THRESHOLD;
+ ecn_rp_ctx->cnp_cnt_threshold = ROCE_DEFAULT_CNP_CNT_THRESHOLD;
+ ecn_rp_ctx->factor_gita = ROCE_DEFAULT_FACTOR_GITA;
+ ecn_rp_ctx->initial_alpha = ROCE_DEFAULT_INITIAL_ALPHA;
+ ecn_rp_ctx->rate_inc_ai = ROCE_DEFAULT_RATE_INC_AI;
+ ecn_rp_ctx->rate_inc_hai = ROCE_DEFAULT_RATE_INC_HAI;
+ ecn_rp_ctx->rate_first_set = ROCE_DEFAULT_RATE_FIRST_SET;
+ ecn_rp_ctx->rate_target_clamp = ROCE_DEFAULT_RATE_TARGET_CLAMP;
+ ecn_rp_ctx->token_period = ROCE_DEFAULT_TOKEN_PERIOD;
+ ecn_rp_ctx->min_rate = ROCE_DEFAULT_MIN_RATE;
+ ret = kobject_init_and_add(&ecn_rp_ctx->ecn_rp_root, &roce_ecn_rp_ktype, kobj, "roce3_rp");
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to add kobject roce3_rp.(ret:%d)\n", __func__, ret);
+ kobject_put(&ecn_rp_ctx->ecn_rp_root);
+ return ret;
+ }
+
+ ecn_rp_ctx->enable_ctx.np_rp = ROCE_DCQCN_RP;
+ ret = roce3_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 roce3_remove_ecn_rp_sysfs(struct kobject *kobj, struct roce3_ecn_rp_ctx *ecn_rp_ctx)
+{
+ roce3_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(min_cnp_period, roce3_show_min_cnp_period, roce3_store_min_cnp_period);
+ROCE_ATTR_RW(quick_adjust_en, roce3_show_quick_adjust_en, roce3_store_quick_adjust_en);
+ROCE_ATTR_RW(port_mode, roce3_show_port_mode, roce3_store_port_mode);
+ROCE_ATTR_RW(cnp_prio_enable, roce3_show_cnp_prio_enable, roce3_store_cnp_prio_enable);
+ROCE_ATTR_RW(cnp_prio, roce3_show_cnp_prio, roce3_store_cnp_prio);
+
+static struct attribute *ecn_np_ctx_attrs[] = {
+ ROCE_ATTR_PTR(min_cnp_period),
+ ROCE_ATTR_PTR(quick_adjust_en),
+ ROCE_ATTR_PTR(port_mode),
+ ROCE_ATTR_PTR(cnp_prio_enable),
+ ROCE_ATTR_PTR(cnp_prio),
+ NULL,
+};
+ATTRIBUTE_GROUPS(ecn_np_ctx);
+
+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,
+ .default_groups = ecn_np_ctx_groups,
+};
+
+static int roce3_init_ecn_np_sysfs(struct kobject *kobj, struct roce3_ecn_np_ctx *ecn_np_ctx)
+{
+ int ret = 0;
+
+ ecn_np_ctx->min_cnp_period = ROCE_DEFAULT_MIN_CNP_PERIOD;
+ ecn_np_ctx->quick_adjust_en = ROCE_DEFAULT_QUICK_AJ_ENABLE;
+ ecn_np_ctx->port_mode = ROCE_DEFAULT_PORT_MODE_25G;
+ ecn_np_ctx->cnp_prio_enable = ROCE_DEFAULT_CNP_PRIO_ENABLE;
+ ecn_np_ctx->cnp_prio = ROCE_DEFAULT_CNP_PRIO;
+ ret = kobject_init_and_add(&ecn_np_ctx->ecn_np_root, &roce_ecn_np_ktype, kobj, "roce3_np");
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to add kobject roce3_np.(ret:%d)\n", __func__, ret);
+ kobject_put(&ecn_np_ctx->ecn_np_root);
+ return ret;
+ }
+
+ ecn_np_ctx->enable_ctx.np_rp = ROCE_DCQCN_NP;
+ ret = roce3_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;
+}
+
+static void roce3_remove_ecn_np_sysfs(struct kobject *kobj, struct roce3_ecn_np_ctx *ecn_np_ctx)
+{
+ roce3_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 roce3_show_ecn_ver(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj);
+
+ return sprintf(buf, "%d\n", (int)ecn_ctx->ecn_ver);
+}
+
+static ssize_t roce3_store_ecn_ver(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ ssize_t ret = 0;
+ int ecn_ver = 0;
+ u32 old_ecn_ver = 0;
+ struct roce3_ecn_ctx *ecn_ctx = to_roce3_ecn_ctx(kobj);
+
+ ret = kstrtoint(buf, 10, &ecn_ver);
+ if (ret != 0)
+ return -EIO;
+
+ if ((ecn_ver < ECN_VER_DCQCN) || (ecn_ver > 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 = (ssize_t)roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0) {
+ 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, roce3_show_ecn_ver, roce3_store_ecn_ver);
+ROCE_ATTR_RW(cc_algo, roce3_show_cc_algo, roce3_store_cc_algo);
+
+static struct attribute *ecn_ctx_attrs[] = {
+ ROCE_ATTR_PTR(ecn_ver),
+ ROCE_ATTR_PTR(cc_algo),
+ NULL,
+};
+ATTRIBUTE_GROUPS(ecn_ctx);
+
+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,
+ .default_groups = ecn_ctx_groups,
+};
+
+static int roce3_init_ecn_sysfs(struct net_device *ndev, struct roce3_ecn_ctx *ecn_ctx)
+{
+ int ret = 0;
+
+ memset(ecn_ctx, 0, sizeof(*ecn_ctx));
+
+ mutex_init(&ecn_ctx->ecn_mutex);
+
+ ecn_ctx->ecn_ver = ECN_VER_DCQCN;
+#ifdef ROCE_COMPUTE
+#ifdef EULER_2_10_OFED_4_18
+ ecn_ctx->cc_algo = ROCE_CC_LDCP_ALGO;
+#else
+ ecn_ctx->cc_algo = ROCE_CC_DCQCN_ALGO;
+#endif
+#elif defined(ROCE_VBS_EN) || defined(ROCE_STANDARD)
+ ecn_ctx->cc_algo = ROCE_CC_LDCP_ALGO;
+#else
+ ecn_ctx->cc_algo = ROCE_CC_DISABLE;
+#endif
+
+ ret = kobject_init_and_add(&ecn_ctx->ecn_root, &roce_ecn_ktype, &ndev->dev.kobj, "ecn");
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to add kobject ecn.(ret:%d)\n", __func__, ret);
+ kobject_put(&ecn_ctx->ecn_root);
+ return ret;
+ }
+
+ ret = roce3_init_ecn_np_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->np_ctx);
+ if (ret != 0)
+ goto err_init_np_sysfs;
+
+ ret = roce3_init_ecn_rp_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->rp_ctx);
+ if (ret != 0)
+ goto err_init_rp_sysfs;
+
+ ret = roce3_init_ecn_ip_enable_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->ip_enable_ctx);
+ if (ret != 0)
+ goto err_init_ip_enable_sysfs;
+
+ ret = roce3_update_ecn_param(ecn_ctx);
+ if (ret != 0)
+ goto err_update;
+
+ return 0;
+
+err_update:
+ roce3_remove_ecn_ip_enable_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->ip_enable_ctx);
+err_init_ip_enable_sysfs:
+ roce3_remove_ecn_rp_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->rp_ctx);
+err_init_rp_sysfs:
+ roce3_remove_ecn_np_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->np_ctx);
+err_init_np_sysfs:
+ kobject_put(&ecn_ctx->ecn_root);
+ return ret;
+}
+
+static void roce3_prase_qpc(struct roce_qp_context *qpc)
+{
+ qpc->chip_seg.sqc.dw2.value = be32_to_cpu(qpc->chip_seg.sqc.dw2.value);
+ qpc->chip_seg.sqc.dw3.value = be32_to_cpu(qpc->chip_seg.sqc.dw3.value);
+ qpc->chip_seg.sqac.dw3.value = be32_to_cpu(qpc->chip_seg.sqac.dw3.value);
+ qpc->chip_seg.sqac.dw7.value = be32_to_cpu(qpc->chip_seg.sqac.dw7.value);
+ qpc->chip_seg.rqc.dw3.value = be32_to_cpu(qpc->chip_seg.rqc.dw3.value);
+ qpc->chip_seg.rqc.dw7.value = be32_to_cpu(qpc->chip_seg.rqc.dw7.value);
+ qpc->sw_seg.ucode_seg.common.dw3.value =
+ be32_to_cpu(qpc->sw_seg.ucode_seg.common.dw3.value);
+ qpc->sw_seg.ucode_seg.sq_ctx.dw9.value =
+ be32_to_cpu(qpc->sw_seg.ucode_seg.sq_ctx.dw9.value);
+ qpc->sw_seg.ucode_seg.sq_ctx.ack_ctx.dw15.value =
+ be32_to_cpu(qpc->sw_seg.ucode_seg.sq_ctx.ack_ctx.dw15.value);
+ qpc->sw_seg.ucode_seg.rq_ctx.dw22.value =
+ be32_to_cpu(qpc->sw_seg.ucode_seg.rq_ctx.dw22.value);
+ qpc->sw_seg.ucode_seg.rq_ctx.ack_ctx.dw27.value =
+ be32_to_cpu(qpc->sw_seg.ucode_seg.rq_ctx.ack_ctx.dw27.value);
+}
+
+static ssize_t roce3_store_dfx_qpc(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ u32 qpn;
+ struct roce3_dfx_qpc_ctx *qpc_ctx = NULL;
+ struct roce3_dfx_ctx *dfx_ctx = NULL;
+ struct roce3_device *rdev = NULL;
+ struct roce_qp_context qpc;
+ struct rdma_service_cap *rdma_cap = NULL;
+
+ if (kobj == NULL || attr == NULL || buf == NULL || count == 0) {
+ pr_err("[ROCE] %s: Invalid input para\n", __func__);
+ return -EINVAL;
+ }
+
+ qpc_ctx = container_of(attr, struct roce3_dfx_qpc_ctx, kattr);
+ dfx_ctx = container_of(qpc_ctx, struct roce3_dfx_ctx, qpc_ctx);
+ rdev = container_of(dfx_ctx, struct roce3_device, dfx_ctx);
+
+ memset(&qpc, 0, sizeof(struct roce_qp_context));
+
+ ret = (int)kstrtou32(buf, 10, &qpn);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to do sscanf_s, ret(%d)\n", __func__, ret);
+ return -EIO;
+ }
+
+ rdma_cap = &rdev->rdma_cap;
+ if ((qpn >= rdma_cap->dev_rdma_cap.roce_own_cap.max_qps) || (qpn < ROCE_MIN_QPN)) {
+ pr_err("[ROCE] %s: Invalid qpn(%u), max_qps(%u)\n",
+ __func__, qpn, rdma_cap->dev_rdma_cap.roce_own_cap.max_qps);
+ return -EIO;
+ }
+
+ ret = roce3_dfx_cmd_query_qp(rdev, qpn, &qpc);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to query qpc, ret(%d)\n", __func__, ret);
+ return (ssize_t)ret;
+ }
+
+ roce3_prase_qpc(&qpc);
+
+ roce3_dfx_print("qpn(0x%x): sqc pi(0x%x), sqc ci(0x%x), ccf_appid(0x%x)\n",
+ qpn, qpc.chip_seg.sqc.dw2.bs.sq_pi, qpc.chip_seg.sqc.dw3.bs.sq_ci,
+ qpc.sw_seg.ucode_seg.common.dw0.bs.ccf_appid);
+ roce3_dfx_print("sqac ci(0x%x), sqac wqe_prefetch_ci(0x%x), rqc pi(0x%x), rqc ci(0x%x)\n",
+ qpc.chip_seg.sqac.dw3.bs.sqa_ci, qpc.chip_seg.sqac.dw7.bs.sqa_wqe_prefetch_ci,
+ qpc.chip_seg.rqc.dw7.bs.rq_pi, qpc.chip_seg.rqc.dw3.bs.rq_ci);
+ roce3_dfx_print("sq_ssn(0x%x), sq_rcv_msn(0x%x), rq_last_msn(0x%x), rqa_msn(0x%x)\n",
+ qpc.sw_seg.ucode_seg.sq_ctx.dw9.bs.ssn,
+ qpc.sw_seg.ucode_seg.sq_ctx.ack_ctx.dw15.bs.sq_rcv_msn,
+ qpc.sw_seg.ucode_seg.rq_ctx.dw22.bs.last_msn,
+ qpc.sw_seg.ucode_seg.rq_ctx.ack_ctx.dw27.bs.msn);
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_store_dfx_cqc(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ u32 cqn;
+ struct roce3_dfx_cqc_ctx *cqc_ctx = NULL;
+ struct roce3_dfx_ctx *dfx_ctx = NULL;
+ struct roce3_device *rdev = NULL;
+ struct roce_cq_context cqc;
+ struct rdma_service_cap *rdma_cap = NULL;
+
+ if (kobj == NULL || attr == NULL || buf == NULL || count == 0) {
+ pr_err("[ROCE] %s: Invalid input para\n", __func__);
+ return -EINVAL;
+ }
+
+ cqc_ctx = container_of(attr, struct roce3_dfx_cqc_ctx, kattr);
+ dfx_ctx = container_of(cqc_ctx, struct roce3_dfx_ctx, cqc_ctx);
+ rdev = container_of(dfx_ctx, struct roce3_device, dfx_ctx);
+
+ memset(&cqc, 0, sizeof(struct roce_cq_context));
+
+ ret = (int)kstrtou32(buf, 10, &cqn);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to do sscanf_s, ret(%d)\n", __func__, ret);
+ return -EIO;
+ }
+
+ rdma_cap = &rdev->rdma_cap;
+ if (cqn >= rdma_cap->dev_rdma_cap.roce_own_cap.max_cqs) {
+ pr_err("[ROCE] %s: Invalid cqn(%u), max_cqs(%u)\n", __func__, cqn,
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_cqs);
+ return -EIO;
+ }
+
+ ret = roce3_dfx_cmd_query_cq(rdev, cqn, &cqc);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to query cqc, ret(%d)\n", __func__, ret);
+ return (ssize_t)ret;
+ }
+
+ cqc.dw2.value = be32_to_cpu(cqc.dw2.value);
+ cqc.dw1.value = be32_to_cpu(cqc.dw1.value);
+
+ roce3_dfx_print("cqn(0x%x): pi(0x%x), ci(0x%x)\n", cqn, cqc.dw2.bs.pi, cqc.dw1.bs.ci);
+
+ return (ssize_t)count;
+}
+
+static ssize_t roce3_store_dfx_srqc(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ u32 srqn;
+ struct roce3_dfx_srqc_ctx *srqc_ctx = NULL;
+ struct roce3_dfx_ctx *dfx_ctx = NULL;
+ struct roce3_device *rdev = NULL;
+ struct roce_srq_context srqc;
+ struct rdma_service_cap *rdma_cap = NULL;
+
+ if (kobj == NULL || attr == NULL || buf == NULL || count == 0) {
+ pr_err("[ROCE] %s: Invalid input para\n", __func__);
+ return -EINVAL;
+ }
+
+ srqc_ctx = container_of(attr, struct roce3_dfx_srqc_ctx, kattr);
+ dfx_ctx = container_of(srqc_ctx, struct roce3_dfx_ctx, srqc_ctx);
+ rdev = container_of(dfx_ctx, struct roce3_device, dfx_ctx);
+
+ memset(&srqc, 0, sizeof(struct roce_srq_context));
+
+ ret = (int)kstrtou32(buf, 10, &srqn);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to do sscanf_s, ret(%d)\n", __func__, ret);
+ return -EIO;
+ }
+
+ rdma_cap = &rdev->rdma_cap;
+ if (srqn >= rdma_cap->dev_rdma_cap.roce_own_cap.max_srqs) {
+ pr_err("[ROCE] %s: Invalid srqn(%u), max_srqs(%u)\n", __func__, srqn,
+ rdma_cap->dev_rdma_cap.roce_own_cap.max_srqs);
+ return -EIO;
+ }
+
+ ret = roce3_dfx_cmd_query_srq(rdev, srqn, &srqc);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to query srqc, ret(%d)\n", __func__, ret);
+ return (ssize_t)ret;
+ }
+
+ srqc.dw4.value = be32_to_cpu(srqc.dw4.value);
+
+ roce3_dfx_print("srqn(0x%x): pcnt(0x%x), ccnt(0x%x)\n",
+ srqn, srqc.dw4.bs.pcnt, srqc.dw4.bs.ccnt);
+
+ return (ssize_t)count;
+}
+
+static int roce3_init_dfx_sub_ctx_sysfs(struct kobject *kobj, struct roce3_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) {
+ pr_err("[ROCE] %s: Invalid kobj or dfx_ctx\n", __func__);
+ 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 = 0640;
+ qpc_kattr->store = roce3_store_dfx_qpc;
+ ret = sysfs_create_file(kobj, &qpc_kattr->attr);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: QPC failed to do sysfs_create_file, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ sysfs_attr_init(&cqc_kattr->attr);
+ cqc_kattr->attr.name = "cqc";
+ cqc_kattr->attr.mode = 0640;
+ cqc_kattr->store = roce3_store_dfx_cqc;
+ ret = sysfs_create_file(kobj, &cqc_kattr->attr);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: CQC failed to do sysfs_create_file, ret(%d)\n", __func__, ret);
+ goto err_create_cqc_sysfs;
+ }
+
+ sysfs_attr_init(&srqc_kattr->attr);
+ srqc_kattr->attr.name = "srqc";
+ srqc_kattr->attr.mode = 0640;
+ srqc_kattr->store = roce3_store_dfx_srqc;
+ ret = sysfs_create_file(kobj, &srqc_kattr->attr);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: SRQC failed to do sysfs_create_file, ret(%d)\n", __func__, 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 roce3_init_dfx_sysfs(struct net_device *ndev, struct roce3_dfx_ctx *dfx_ctx)
+{
+ int ret;
+
+ memset(dfx_ctx, 0, sizeof(*dfx_ctx));
+
+ dfx_ctx->dfx_root = kobject_create_and_add("roce3_dfx", &ndev->dev.kobj);
+ if (dfx_ctx->dfx_root == NULL) {
+ pr_err("[ROCE] %s: Failed to do kobject_create_and_add\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = roce3_init_dfx_sub_ctx_sysfs(dfx_ctx->dfx_root, dfx_ctx);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to init dfx sub ctx sysfs, ret(%d)\n", __func__, ret);
+ kobject_put(dfx_ctx->dfx_root);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce3_remove_ecn_sysfs(struct roce3_ecn_ctx *ecn_ctx)
+{
+ roce3_remove_ecn_ip_enable_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->ip_enable_ctx);
+
+ roce3_remove_ecn_rp_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->rp_ctx);
+
+ roce3_remove_ecn_np_sysfs(&ecn_ctx->ecn_root, &ecn_ctx->np_ctx);
+
+ kobject_put(&ecn_ctx->ecn_root);
+}
+
+int roce3_init_sysfs(struct roce3_device *rdev)
+{
+ int ret;
+
+ ret = roce3_init_ecn_sysfs(rdev->ndev, &rdev->ecn_ctx);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to init ecn sysfs, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ ret = roce3_init_dfx_sysfs(rdev->ndev, &rdev->dfx_ctx);
+ if (ret != 0) {
+ pr_err("[ROCE] %s: Failed to init dfx sysfs, ret(%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void roce3_remove_dfx_sub_sysfs(struct roce3_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 roce3_remove_sysfs(struct roce3_device *rdev)
+{
+ roce3_remove_dfx_sub_sysfs(&rdev->dfx_ctx);
+ roce3_remove_ecn_sysfs(&rdev->ecn_ctx);
+}
diff --git a/drivers/infiniband/hw/hiroce3/roce_sysfs.h b/drivers/infiniband/hw/hiroce3/roce_sysfs.h
new file mode 100644
index 0000000000000..956e823feeeb6
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_sysfs.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#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>
+
+#define ROCE_MIN_QPN 2
+#define BYTE_TO_BIT 8
+
+#define PRI_ARRAY_LEN 8
+
+#define ROCE_MAX_PORT_CNT 8
+
+#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
+
+struct roce3_prio_enable_ctx {
+ struct kobj_attribute enable;
+ void *ecn_enable_ctx;
+ u32 prio_en;
+ u32 prio;
+};
+struct roce3_ip_prio_enable_ctx {
+ struct kobj_attribute ip_enable;
+ void *ecn_ip_enable_ctx;
+ u32 prio_en;
+ u32 prio;
+};
+
+struct roce3_ecn_ip_enable_ctx {
+ struct kobject *ip_enable_root;
+ struct roce3_ip_prio_enable_ctx ip_prio_enable[PRI_ARRAY_LEN];
+};
+
+struct roce3_ecn_enable_ctx {
+ struct kobject *enable_root;
+ struct roce3_prio_enable_ctx prio_enable[PRI_ARRAY_LEN];
+ u32 np_rp;
+};
+
+struct roce3_dfx_qpc_ctx {
+ struct kobj_attribute kattr;
+};
+
+struct roce3_dfx_cqc_ctx {
+ struct kobj_attribute kattr;
+};
+
+struct roce3_dfx_srqc_ctx {
+ struct kobj_attribute kattr;
+};
+
+struct roce3_dfx_ctx {
+ struct kobject *dfx_root;
+ struct roce3_dfx_qpc_ctx qpc_ctx;
+ struct roce3_dfx_cqc_ctx cqc_ctx;
+ struct roce3_dfx_srqc_ctx srqc_ctx;
+};
+
+struct roce3_ecn_rp_ctx {
+ struct kobject ecn_rp_root;
+ u32 alpha_dec_period;
+ u32 rate_dec_period;
+ u32 rate_inc_period;
+ u32 alpha_threshold;
+ u32 cnp_cnt_threshold;
+ 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;
+ struct roce3_ecn_enable_ctx enable_ctx;
+};
+
+struct roce3_ecn_np_ctx {
+ struct kobject ecn_np_root;
+ u32 min_cnp_period;
+ u32 quick_adjust_en;
+ u32 port_mode;
+ u32 cnp_prio_enable;
+ u32 cnp_prio;
+ struct roce3_ecn_enable_ctx enable_ctx;
+};
+
+struct roce3_ecn_ctx {
+ struct kobject ecn_root;
+ struct mutex ecn_mutex;
+ u32 ecn_ver;
+ u32 cc_algo;
+ struct roce3_ecn_np_ctx np_ctx;
+ struct roce3_ecn_rp_ctx rp_ctx;
+ struct roce3_ecn_ip_enable_ctx ip_enable_ctx;
+};
+
+int roce3_update_ecn_param(const struct roce3_ecn_ctx *ecn_ctx);
+
+#endif // ROCE_SYSFS_H
diff --git a/drivers/infiniband/hw/hiroce3/roce_user.h b/drivers/infiniband/hw/hiroce3/roce_user.h
new file mode 100644
index 0000000000000..fd931d7340bcc
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_user.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_USER_H
+#define ROCE_USER_H
+
+#include <linux/types.h>
+
+struct roce3_alloc_ucontext_resp {
+ u32 num_qps;
+ u32 num_xsrqs;
+ u32 cqe_size;
+ u32 wqebb_size; /* 64B or 128B */
+ u32 dwqe_size; /* 256B */
+ u32 max_msg_size; /* (2G -1)B */
+ u32 max_comp_vector;
+ u32 max_inline_size;
+ u32 dev_caps;
+ u8 phy_port;
+ u8 storage_aa_en;
+ u16 rsvd;
+ u16 db_offset;
+ u16 dwqe_offset;
+ u8 srq_container_en;
+ u8 srq_container_mode;
+ u8 xrc_srq_container_mode;
+ u8 warn_th;
+};
+
+struct roce3_create_cq_cmd {
+ u64 buf_addr;
+ u64 db_addr;
+};
+
+struct roce3_resize_cq_cmd {
+ u64 buf_addr; /* resize cq's 'buf vaַ */
+ u64 stage; /* describe the resize stage,0 or 1; */
+};
+
+struct roce3_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 roce3_modify_srq_cmd {
+ u8 container_flag;
+ u8 container_warn_th;
+ u16 rsvd;
+};
+
+struct roce3_reg_frmr_cmd {
+ u64 pbl_vaddr;
+};
+
+#endif // ROCE_USER_H
diff --git a/drivers/infiniband/hw/hiroce3/roce_xrc.c b/drivers/infiniband/hw/hiroce3/roce_xrc.c
new file mode 100644
index 0000000000000..4d535d1ce7d2f
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_xrc.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/slab.h>
+
+#include "roce.h"
+#include "roce_main_extension.h"
+#include "roce_xrc.h"
+
+static int roce3_rdma_xrcd_alloc(void *hwdev, u32 *xrcdn)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if ((hwdev == NULL) || (xrcdn == NULL)) {
+ pr_err("%s: Hwdev or xrcdn is null\n", __func__);
+ return -EINVAL;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return -EINVAL;
+ }
+
+ *xrcdn = rdma_bitmap_alloc(&comp_priv->xrcd_bitmap);
+ if (*xrcdn == RDMA_INVALID_INDEX) {
+ pr_err("%s: Can't get valid xrcdn, err(%d)\n", __func__, -ENOMEM);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void roce3_rdma_xrcd_free(void *hwdev, u32 xrcdn)
+{
+ struct rdma_comp_priv *comp_priv = NULL;
+
+ if (hwdev == NULL) {
+ pr_err("%s: Hwdev is null\n", __func__);
+ return;
+ }
+
+ comp_priv = get_rdma_comp_priv(hwdev);
+ if (comp_priv == NULL) {
+ pr_err("%s: Comp_priv is null\n", __func__);
+ return;
+ }
+
+ rdma_bitmap_free(&comp_priv->xrcd_bitmap, xrcdn);
+}
+
+static int roce3_init_xrcd(struct ib_device *ibdev, struct roce3_device *rdev,
+ struct roce3_xrcd *xrcd)
+{
+ int ret = 0;
+ struct ib_cq_init_attr cq_attr = { 0 };
+
+ ret = roce3_rdma_xrcd_alloc(rdev->hwdev, &xrcd->xrcdn);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc rdma xrcd, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_alloc_xrcdn;
+ }
+
+ xrcd->pd = ib_alloc_pd(ibdev, 0); /*lint !e119*/
+
+ if (IS_ERR(xrcd->pd)) {
+ ret = (int)PTR_ERR(xrcd->pd);
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc pd, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ 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);
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create cq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_create_cq;
+ }
+ return 0;
+
+err_create_cq:
+ ib_dealloc_pd(xrcd->pd);
+
+err_alloc_pd:
+ roce3_rdma_xrcd_free(rdev->hwdev, xrcd->xrcdn);
+
+err_alloc_xrcdn:
+ return ret;
+}
+
+int roce3_alloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata)
+{
+ struct roce3_device *rdev = to_roce3_dev(ibxrcd->device);
+ struct roce3_xrcd *xrcd = to_roce3_xrcd(ibxrcd);
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ return roce3_init_xrcd(ibxrcd->device, rdev, xrcd);
+}
+
+int roce3_dealloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata)
+{
+ struct roce3_device *rdev = NULL;
+ struct roce3_xrcd *xrcd = NULL;
+
+ if (ibxrcd == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibxrcd is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibxrcd->device);
+ xrcd = to_roce3_xrcd(ibxrcd);
+ ib_destroy_cq(xrcd->cq);
+
+ ib_dealloc_pd(xrcd->pd);
+ roce3_rdma_xrcd_free(rdev->hwdev, xrcd->xrcdn);
+ return 0;
+}
diff --git a/drivers/infiniband/hw/hiroce3/roce_xrc.h b/drivers/infiniband/hw/hiroce3/roce_xrc.h
new file mode 100644
index 0000000000000..8e040828cd738
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/roce_xrc.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_XRC_H
+#define ROCE_XRC_H
+
+#include <rdma/ib_verbs.h>
+
+#include "roce.h"
+
+struct roce3_xrcd {
+ struct ib_xrcd ibxrcd;
+ u32 xrcdn;
+ struct ib_pd *pd;
+ struct ib_cq *cq;
+};
+
+static inline struct roce3_xrcd *to_roce3_xrcd(const struct ib_xrcd *ibxrcd)
+{
+ return container_of(ibxrcd, struct roce3_xrcd, ibxrcd);
+}
+
+#endif // ROCE_XRC_H
diff --git a/drivers/infiniband/hw/hiroce3/srq/roce_srq.h b/drivers/infiniband/hw/hiroce3/srq/roce_srq.h
new file mode 100644
index 0000000000000..a5e4c723ae2d8
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/srq/roce_srq.h
@@ -0,0 +1,201 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef ROCE_SRQ_H
+#define ROCE_SRQ_H
+
+#include <linux/types.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "hinic3_rdma.h"
+#include "hinic3_cqm.h"
+
+#include "roce.h"
+#include "roce_pd.h"
+#include "roce_db.h"
+
+#include "rdma_context_format.h"
+
+#define ROCE_SRQ_MAX_SGE 15
+#define ROCE_SRQ_MID_SGE 7
+#define ROCE_SRQ_MIN_SGE 3
+
+#define ROCE_SRQN_INVLD 0XFFFFFFFF
+#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
+/* (2^rq_wqebb_size)*16B => divide 16 means shift need to minus 4 */
+#define SRQ_WQEBB_SIZE_CAL_SECTTOR 4
+#define RDMA_PREFETCH_WQE_MAX 7
+#define RDMA_PREFETCH_MTT_LEN_MAX 3
+#define ROCE_WQE_BB_SIZE_MIN 64
+
+/*
+ * Lbit:0 - The next SGE is present in the list
+ * Lbit:1 - The last SGE, no SGE is present in the list
+ */
+#define LAST_SGE_NO_PRESENT 0x80000000UL
+
+/*
+ * 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_NEXT_SGE_PRESENT 0x3FFFFFFFUL
+#define NORMAL_FMT_AND_LAST_SGE_NO_PRESENT 0xBFFFFFFFUL
+
+/**
+ * container_mode:
+ * mode: 0 -> container_size: 16
+ * mode: 1 -> container_size: 8
+ * mode: 2 -> container_size: 4
+ * mode: 3 -> container_size: 2
+ */
+enum roce3_srq_mode {
+ ROCE_SRQ_MODE_0 = 0,
+ ROCE_SRQ_MODE_1,
+ ROCE_SRQ_MODE_2,
+ ROCE_SRQ_MODE_3
+};
+
+/**
+ * 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 roce3_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 roce3_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
+};
+
+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 roce3_srq_query_outbuf {
+ struct roce_srq_context srqc;
+ u32 srq_ctr_vld;
+ u32 srq_empty_ctr;
+ u32 reserved[6];
+};
+
+struct roce3_wqe_srq_next_seg {
+ u16 reserved1;
+ __be16 pcnt; /* indicate the pi */
+ u8 signature;
+ u8 reserved2;
+ __be16 next_wqe_index;
+ u32 reserved3[2];
+};
+
+struct roce3_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 roce3_srq {
+ struct ib_srq ibsrq; /* ibsrq */
+ struct tag_cqm_queue *cqm_srq;
+
+ u32 srqn;
+ int max_depth;
+ int max_gs;
+ int wqe_shift;
+
+ struct tag_cqm_buf *buf;
+ struct roce3_db db;
+ u64 *wrid;
+ spinlock_t lock;
+ int head;
+ int tail;
+ u16 wqe_ctr;
+ u8 xrc_en;
+ u8 rsvd;
+ struct ib_umem *umem;
+ struct rdma_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 struct roce3_srq *to_roce3_srq(const struct ib_srq *ibsrq)
+{
+ return container_of(ibsrq, struct roce3_srq, ibsrq);
+}
+
+static inline struct roce3_srq *cqmobj_to_roce3_srq(const struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *cqm_srq;
+
+ cqm_srq = container_of(object, struct tag_cqm_queue, object);
+ return (struct roce3_srq *)cqm_srq->priv;
+}
+
+void roce3_free_srq_wqe(struct roce3_srq *srq, int wqe_index);
+void roce3_srq_async_event(struct roce3_device *rdev, struct roce3_srq *srq, int type);
+void *roce3_srq_get_wqe(struct roce3_srq *srq, int n);
+u8 roce3_get_container_sz(u32 container_mode);
+u8 roce3_calculate_cont_th(u32 srq_limit);
+u8 roce3_srq_mode_chip_adapt(u8 cfg_mode);
+u32 roce3_srq_max_avail_wr_set(struct roce3_srq *rsrq);
+
+int roce3_create_srq_common(struct roce3_device *rdev, struct roce3_srq *rsrq, struct roce3_pd *pd,
+ struct ib_srq_init_attr *init_attr, struct ib_udata *udata, u32 index);
+
+#endif // ROCE_SRQ_H
diff --git a/drivers/infiniband/hw/hiroce3/srq/roce_srq_comm.c b/drivers/infiniband/hw/hiroce3/srq/roce_srq_comm.c
new file mode 100644
index 0000000000000..49df482a2a850
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/srq/roce_srq_comm.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#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_pub_cmd.h"
+
+u8 roce3_srq_mode_chip_adapt(u8 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;
+ }
+}
+
+static void *roce3_srq_buf_offset(struct tag_cqm_buf *buf, int offset)
+{
+ return (void *)((char *)buf->direct.va + offset);
+}
+
+void *roce3_srq_get_wqe(struct roce3_srq *srq, int n)
+{
+ return roce3_srq_buf_offset(srq->buf, (int)((u32)n << (unsigned int)srq->wqe_shift));
+}
+
+void roce3_srq_async_event(struct roce3_device *rdev, struct roce3_srq *srq, int type)
+{
+ struct ib_srq *ibsrq = &srq->ibsrq;
+ struct ib_event event;
+
+ memset(&event, 0, sizeof(event));
+ 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:
+ dev_warn_ratelimited(rdev->hwdev_hdl,
+ "[ROCE] %s: unexpected event type(%d) on SRQ(%06x), func_id(%d)\n",
+ __func__, type, srq->srqn, rdev->glb_func_id);
+ return;
+ }
+
+ ibsrq->event_handler(&event, ibsrq->srq_context);
+ }
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_free_srq_wqe
+ Description : roce3_free_srq_wqe
+ Input : struct roce3_srq *srq
+ int wqe_index
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+void roce3_free_srq_wqe(struct roce3_srq *srq, int wqe_index)
+{
+ struct roce3_wqe_srq_next_seg *next = NULL;
+
+ spin_lock(&srq->lock);
+
+ next = (struct roce3_wqe_srq_next_seg *)roce3_srq_get_wqe(srq, srq->tail);
+ next->next_wqe_index = (u16)wqe_index;
+ srq->tail = wqe_index;
+
+ spin_unlock(&srq->lock);
+}
diff --git a/drivers/infiniband/hw/hiroce3/srq/roce_srq_create.c b/drivers/infiniband/hw/hiroce3/srq/roce_srq_create.c
new file mode 100644
index 0000000000000..3f9e5d76e627b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/srq/roce_srq_create.c
@@ -0,0 +1,635 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#ifndef __PC_LINT__
+#include <linux/kernel.h>
+#endif
+
+#include "roce.h"
+#include "roce_compat.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_verbs_attr.h"
+#include "roce_verbs_format.h"
+
+#include "roce_srq_extension.h"
+#include "roce_main_extension.h"
+#include "hinic3_hmm.h"
+#include "roce_pub_cmd.h"
+
+/*
+ ****************************************************************************
+ Prototype : roce3_srq_sw2hw
+ Description : roce3_srq_sw2hw
+ Input : struct roce3_device *rdev
+ struct roce3_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 roce3_srq_sw2hw_set(struct tag_roce_verbs_srq_attr *srq_attr, struct roce3_srq *rsrq,
+ u32 pdn, u32 cqn, u16 xrcdn, int page_shift)
+{
+ srq_attr->dw0.bs.size = (u32)(ROCE_ILOG2((unsigned int)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;
+ // rdma engine wqe prefetch max num
+ srq_attr->dw2.bs.wqe_prefetch_max_num = RDMA_PREFETCH_WQE_MAX;
+ // srq_attr->dw2.bs.wqe_prefetch_min_num = 0;
+ // srq_attr->dw2.bs.wqe_cache_thd_sel = 0;
+ srq_attr->dw2.bs.wqecnt_lth = 0xe;
+ // srq_attr->dw2.bs.wqecnt_ctrl_en = 0;
+ // srq_attr->dw2.bs.wqecnt_rctl = 0;
+ srq_attr->dw2.bs.mtt_prefetch_maxlen = 0; // rdma engine mtt prefetch max len
+ // srq_attr->dw2.bs.next_wqe_idx = 0;
+
+ 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));
+}
+
+static int roce3_srq_sw2hw(struct roce3_device *rdev, struct roce3_srq *rsrq,
+ u32 pdn, u32 cqn, u16 xrcdn, int page_shift)
+{
+ int ret = 0;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_verbs_srq_attr *srq_attr = NULL;
+ struct tag_roce_uni_cmd_creat_srq *srq_sw2hw_inbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_uni_cmd_creat_srq), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ srq_sw2hw_inbuf = (struct tag_roce_uni_cmd_creat_srq *)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(VERBS_CMD_TYPE_SRQ_BITMASK); //lint !e778
+ srq_attr = &srq_sw2hw_inbuf->srq_attr;
+
+ roce3_srq_sw2hw_set(srq_attr, rsrq, pdn, cqn, xrcdn, page_shift);
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_SW2HW_SRQ,
+ cqm_cmd_inbuf, NULL, NULL, ROCE_CMD_TIME_CLASS_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to send SW2HW_SRQ command, ret(%d), func_id(%d)\n",
+ __func__, ret, rdev->glb_func_id);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA is present(SW2HW_SRQ), srqn(0x%x), func_id(%u)\n",
+ __func__, rsrq->srqn, rdev->glb_func_id);
+
+ /* 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;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+static int roce3_create_srq_check(const struct ib_pd *ibpd,
+ const struct ib_srq_init_attr *init_attr)
+{
+ struct roce3_device *rdev = to_roce3_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)) {
+ pr_err("[ROCE, ERR] %s: Invalid input parms\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int roce3_create_srq_write_mtt_and_db(struct roce3_device *rdev, struct roce3_srq *rsrq,
+ struct roce3_create_srq_cmd *ucmd, struct roce3_pd *pd)
+{
+ int ret = 0;
+
+ ret = roce3_umem_write_mtt(rdev, &rsrq->mtt, rsrq->umem);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to write mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ ret = roce3_db_map_user(to_roce3_ucontext(pd->ibpd.uobject->context),
+ ucmd->db_addr, &rsrq->db);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to map db to user space, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int roce3_create_srq_get_umem(struct roce3_create_srq_cmd *ucmd,
+ struct ib_udata *udata, struct roce3_srq *rsrq,
+ struct roce3_device *rdev, struct roce3_pd *pd)
+{
+ int ret = 0;
+
+ if (ib_copy_from_udata(ucmd, udata, sizeof(*ucmd)) != 0) {
+ ret = -EFAULT;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to copy from user space, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ rsrq->umem = ib_umem_get(&rdev->ib_dev, ucmd->buf_addr, (size_t)rsrq->buf_sz, 0);
+ if (IS_ERR(rsrq->umem)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to get ib_umem, func_id(%d) rsrq->buf_sz:%u\n",
+ __func__, rdev->glb_func_id, rsrq->buf_sz);
+ ret = (int)PTR_ERR(rsrq->umem);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int roce3_create_user_srq_update(struct roce3_device *rdev, struct roce3_srq *rsrq,
+ struct roce3_pd *pd, struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata, int page_shift)
+{
+ u32 cqn = 0;
+ u16 xrcdn = 0;
+ struct roce_srq_context *srqc = NULL;
+ int ret = 0;
+
+#if defined(OFED_MLNX_5_8) || defined(OFED_VER_4_19)
+ cqn = (u32)((init_attr->srq_type == IB_SRQT_XRC) ?
+ to_roce3_cq(init_attr->ext.cq)->cqn : 0); /*lint !e40*/
+#endif
+ xrcdn = (init_attr->srq_type == IB_SRQT_XRC) ?
+ (u16)(to_roce3_xrcd(init_attr->ext.xrc.xrcd)->xrcdn) :
+ (u16)rdev->rdma_cap.reserved_xrcds;
+ roce3_create_user_srq_update_ext(&cqn, rsrq->srqn);
+
+ srqc = (struct roce_srq_context *)((void *)rsrq->cqm_srq->q_ctx_vaddr);
+ srqc->dw2.bs.state = ROCE_SRQ_STATE_MEM_INIT;
+ srqc->dw2.value = cpu_to_be32(srqc->dw2.value);
+
+ /* set SRQC */
+ ret = roce3_srq_sw2hw(rdev, rsrq, pd->pdn, cqn, xrcdn, (page_shift - PAGE_SHIFT_4K));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to handle srq_sw2hw, func_id(%d)\n",
+ __func__, 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) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to copy data to user space, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ ret = -EFAULT;
+ goto err_unmap;
+ }
+
+ return 0;
+
+err_unmap:
+ roce3_db_unmap_user(to_roce3_ucontext(pd->ibpd.uobject->context), &rsrq->db);
+ return ret;
+}
+
+u32 roce3_srq_max_avail_wr_set(struct roce3_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 : roce3_create_user_srq
+ Description : roce3_create_user_srq
+ Input : struct roce3_device *rdev
+ struct roce3_srq *rsrq
+ struct roce3_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 roce3_create_user_srq(struct roce3_device *rdev, struct roce3_srq *rsrq,
+ struct roce3_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 roce3_create_srq_cmd ucmd = { 0 };
+
+ /* dispatch SRQN and SRQC */
+ rsrq->cqm_srq =
+ cqm_object_rdma_queue_create(rdev->hwdev, SERVICE_T_ROCE,
+ CQM_OBJECT_RDMA_SRQ, 0, rsrq, false, index);
+ if (rsrq->cqm_srq == NULL) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to create rdma queue by cqm_object, func_id(%d) index(%d)\n",
+ __func__, rdev->glb_func_id, index);
+ return (-ENOMEM);
+ }
+
+ rsrq->srqn = rsrq->cqm_srq->index;
+
+ ret = roce3_create_srq_get_umem(&ucmd, udata, rsrq, rdev, pd);
+ if (ret != 0)
+ goto err_free_cqm_srq;
+
+ npages = (u32)ib_umem_num_pages(rsrq->umem);
+ page_shift = PAGE_SHIFT;
+
+
+ rsrq->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_rdma_mtt_alloc(rdev->hwdev, npages, (u32)page_shift, &rsrq->mtt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc rdma_mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_release_umem;
+ }
+
+ ret = roce3_create_srq_write_mtt_and_db(rdev, rsrq, &ucmd, pd);
+ if (ret != 0)
+ goto err_free_mtt;
+
+ ret = roce3_create_user_srq_update(rdev, rsrq, pd, init_attr, udata, page_shift);
+ if (ret != 0)
+ goto err_free_mtt;
+
+ init_attr->attr.max_wr = roce3_srq_max_avail_wr_set(rsrq);
+
+ return 0;
+
+err_free_mtt:
+ hmm_rdma_mtt_free(rdev->hwdev, &rsrq->mtt, SERVICE_T_ROCE);
+
+err_release_umem:
+ ib_umem_release(rsrq->umem);
+
+err_free_cqm_srq:
+ hiudk_cqm_object_delete(rdev->hwdev, &rsrq->cqm_srq->object);
+
+ return ret;
+}
+
+static void roce3_get_cqn_xrcdn(u32 *cqn, u16 *xrcdn,
+ struct ib_srq_init_attr *init_attr, struct roce3_device *rdev)
+{
+#if defined(OFED_MLNX_5_8) || defined(OFED_VER_4_19)
+ *cqn = (u32)((init_attr->srq_type == IB_SRQT_XRC) ?
+ to_roce3_cq(init_attr->ext.cq)->cqn : 0); /*lint !e40*/
+#endif
+ *xrcdn = (init_attr->srq_type == IB_SRQT_XRC) ?
+ (u16)(to_roce3_xrcd(init_attr->ext.xrc.xrcd)->xrcdn) :
+ (u16)rdev->rdma_cap.reserved_xrcds;
+}
+
+static int roce3_create_kernel_srq_update(struct roce3_device *rdev,
+ struct roce3_srq *rsrq, struct roce3_pd *pd,
+ struct ib_srq_init_attr *init_attr, int page_shift)
+{
+ u32 cqn = 0;
+ u16 xrcdn = 0;
+ struct roce_srq_context *srqc = NULL;
+ int ret;
+
+ ret = roce3_buf_write_mtt(rdev, &rsrq->mtt, rsrq->buf);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to write mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_free_mtt;
+ }
+
+ rsrq->wrid = kmalloc((size_t)((u32)rsrq->max_depth * sizeof(u64)),
+ GFP_KERNEL);
+ if (rsrq->wrid == NULL) {
+ rsrq->wrid = vzalloc((size_t)((u32)rsrq->max_depth * sizeof(u64)));
+ if (rsrq->wrid == NULL) {
+ ret = -ENOMEM;
+ goto err_free_mtt;
+ }
+ }
+
+ roce3_get_cqn_xrcdn(&cqn, &xrcdn, init_attr, rdev);
+
+ srqc = (struct roce_srq_context *)((void *)rsrq->cqm_srq->q_ctx_vaddr);
+ srqc->dw2.bs.state = ROCE_SRQ_STATE_MEM_INIT;
+ srqc->dw2.value = cpu_to_be32(srqc->dw2.value);
+
+ ret = roce3_srq_sw2hw(rdev, rsrq, pd->pdn, cqn, xrcdn, (page_shift - PAGE_SHIFT_4K));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to handle srq sw2hw, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_free_wrid;
+ }
+
+ return 0;
+
+err_free_wrid:
+ kvfree(rsrq->wrid);
+ rsrq->wrid = NULL;
+
+err_free_mtt:
+ hmm_rdma_mtt_free(rdev->hwdev, &rsrq->mtt, SERVICE_T_ROCE);
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_create_kernel_srq
+ Description : roce3_create_kernel_srq
+ Input : struct roce3_device *rdev
+ struct roce3_srq *rsrq
+ struct roce3_pd *pd
+ struct ib_srq_init_attr *init_attr
+ Output : None
+
+ 1.Date : 2017/5/4
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_create_kernel_srq(struct roce3_device *rdev, struct roce3_srq *rsrq,
+ struct roce3_pd *pd, struct ib_srq_init_attr *init_attr, u32 index)
+{
+ int i = 0;
+ int ret = 0;
+ int page_shift = 0;
+ struct roce3_wqe_srq_next_seg *next = NULL;
+ struct roce3_wqe_srq_data_seg *scatter = NULL;
+
+ /* alloc queue Buf/ Soft DB/SRQN/SRQC */
+ rsrq->cqm_srq = cqm_object_rdma_queue_create(rdev->hwdev, SERVICE_T_ROCE,
+ CQM_OBJECT_RDMA_SRQ, (u32)rsrq->buf_sz, rsrq, true, index);
+ if (rsrq->cqm_srq == NULL) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create rdma queue by cqm_object, func_id(%d)\n",
+ __func__, 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 roce3_wqe_srq_next_seg *)roce3_srq_get_wqe(rsrq, i);
+ next->next_wqe_index = cpu_to_be16((u16)((u32)(i + 1) &
+ (u32)(rsrq->max_depth - 1)));
+
+ scatter = (struct roce3_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 = ROCE_ILOG2(rsrq->buf->buf_size);
+ rsrq->mtt.mtt_type = MTT_CMTT_TYPE;
+ ret = hmm_rdma_mtt_alloc(rdev->hwdev, rsrq->buf->buf_number, (u32)page_shift,
+ &rsrq->mtt, SERVICE_T_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc rdma rdma_mtt, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ goto err_free_cqm_srq;
+ }
+
+ ret = roce3_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:
+ hiudk_cqm_object_delete(rdev->hwdev, &rsrq->cqm_srq->object);
+
+ return ret;
+}
+
+u8 roce3_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;
+ }
+}
+
+static void roce3_set_srq_depth(struct ib_srq_init_attr *init_attr, struct roce3_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); //lint !e587
+}
+
+static void roce3_rsrq_init(struct ib_srq_init_attr *init_attr,
+ struct roce3_srq *rsrq, struct roce3_device *rdev)
+{
+ int buf_size = 0;
+ int desc_size = 0;
+
+ roce3_srq_container_init(init_attr, rsrq, rdev);
+
+ mutex_init(&rsrq->mutex);
+ /*lint -e708*/
+ spin_lock_init(&rsrq->lock);
+ /*lint +e708*/
+
+ roce3_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 : ROCE_SRQ_MAX_SGE);
+ 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 = (int)sizeof(struct roce3_wqe_srq_next_seg) +
+ rsrq->max_gs * (int)sizeof(struct roce3_wqe_srq_data_seg);
+ desc_size = (int)(ROCE_ROUNDUP_POW_OF_TWO((u32)desc_size)); //lint !e587
+ desc_size = ROCE_MAX(ROCE_WQE_BB_SIZE_MIN, desc_size); // align with min bb_size
+ rsrq->wqe_shift = ROCE_ILOG2((unsigned int)desc_size);
+ 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;
+}
+
+int roce3_create_srq_common(struct roce3_device *rdev, struct roce3_srq *rsrq, struct roce3_pd *pd,
+ struct ib_srq_init_attr *init_attr, struct ib_udata *udata, u32 index)
+{
+ int ret;
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ ret = roce3_create_srq_check(&pd->ibpd, init_attr);
+ if (ret != 0) {
+ pr_err("[ROCE, ERR] %s: Failed to check srq info\n", __func__);
+ return ret;
+ }
+
+ roce3_rsrq_init(init_attr, rsrq, rdev);
+ if (rsrq->ibsrq.uobject) {
+ ret = roce3_create_user_srq(rdev, rsrq, pd, init_attr, udata, index);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create user srq, func_id(%u), index(%u)\n",
+ __func__, rdev->glb_func_id, index);
+ }
+ } else {
+ ret = roce3_create_kernel_srq(rdev, rsrq, pd, init_attr, index);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to create kernel srq, func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ }
+ }
+
+ return ret;
+}
+
+int roce3_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ struct roce3_pd *pd = to_roce3_pd(ibsrq->pd);
+ struct roce3_device *rdev = to_roce3_dev(ibsrq->device);
+ struct roce3_srq *rsrq = to_roce3_srq(ibsrq);
+
+ return roce3_create_srq_common(rdev, rsrq, pd, init_attr, udata, ROCE_SRQN_INVLD);
+}
diff --git a/drivers/infiniband/hw/hiroce3/srq/roce_srq_ctrl.c b/drivers/infiniband/hw/hiroce3/srq/roce_srq_ctrl.c
new file mode 100644
index 0000000000000..6f97d48a7bd5b
--- /dev/null
+++ b/drivers/infiniband/hw/hiroce3/srq/roce_srq_ctrl.c
@@ -0,0 +1,570 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2024 Huawei Technologies Co., Ltd
+
+#include <linux/slab.h>
+#include <linux/vmalloc.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_cqm_cmd.h"
+#include "hinic3_hmm.h"
+#include "roce_main_extension.h"
+#include "roce_pub_cmd.h"
+
+u8 roce3_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;
+}
+
+static u8 roce3_cal_srq_container_num(u32 avail_wr, struct roce3_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 roce3_calculate_cont_th(container_num);
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_srq_arm
+ Description : roce3_srq_arm
+ Input : struct roce3_device *rdev
+ struct roce3_srq *srq
+ u32 srq_limit
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_srq_arm(struct roce3_device *rdev, struct roce3_srq *srq, u32 srq_limit)
+{
+ int ret = 0;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_cmd_srq_arm *srq_arm_inbuf = NULL;
+ u8 warth = 0;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_srq_arm), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ srq_arm_inbuf = (struct tag_roce_cmd_srq_arm *)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); //lint !e778
+ if (srq->container_flag != 0) {
+ srq_arm_inbuf->bs.cont_en = srq->container_flag;
+ srq_arm_inbuf->bs.th_up_en = 1; // Valid for setting up container warn_threshold
+ warth = roce3_cal_srq_container_num(srq_limit, srq);
+ srq_arm_inbuf->bs.warth = warth & ROCE_SRQ_CONTAINER_WARTH_MASK;
+ srq_arm_inbuf->limitwater = cpu_to_be32(srq_arm_inbuf->limitwater);
+ } else {
+ srq_arm_inbuf->bs.lwm = srq_limit;
+ srq_arm_inbuf->limitwater = cpu_to_be32(srq_arm_inbuf->limitwater);
+ }
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_ARM_SRQ,
+ cqm_cmd_inbuf, NULL, NULL, ROCE_CMD_TIME_CLASS_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s:send ARM_SRQ command Failed, ret(%d), func_id(%d), warth(%d)\n",
+ __func__, ret, rdev->glb_func_id, warth);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA is present(ARM_SRQ), srqn(0x%x), func_id(%u)\n",
+ __func__, srq->srqn, rdev->glb_func_id);
+
+ if ((ret == -ETIMEDOUT) || (ret == -EPERM))
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+ }
+ ret = -1;
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_modify_srq
+ Description : roce3_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 roce3_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 roce3_device *rdev = NULL;
+ struct roce3_srq *srq = NULL;
+ struct roce3_modify_srq_cmd ucmd = { 0 };
+ u32 max_avail_wr = 0;
+
+ if ((ibsrq == NULL) || (attr == NULL)) {
+ pr_err("[ROCE, ERR] %s: Ibsrq or attr is null\n", __func__);
+ return (-EINVAL);
+ }
+
+ if (((unsigned int)attr_mask & IB_SRQ_MAX_WR) != 0) {
+ pr_err("[ROCE, ERR] %s: Not support resizing SRQs\n", __func__);
+ return (-EINVAL);
+ }
+
+ rdev = to_roce3_dev(ibsrq->device);
+ srq = to_roce3_srq(ibsrq);
+
+ if ((udata != NULL) && (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)) != 0)) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: SRQN:(%d), Failed to copy from user space, func_id(%d)\n",
+ __func__, srq->srqn, rdev->glb_func_id);
+ return (-EFAULT);
+ }
+
+ if (((unsigned int)attr_mask & IB_SRQ_LIMIT) != 0) {
+ /* calculate max_wr */
+ max_avail_wr = roce3_srq_max_avail_wr_set(srq);
+ if (attr->srq_limit > max_avail_wr) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: srq_limit > max_wr, func_id(%d), max_avail_wr(%d)\n",
+ __func__, rdev->glb_func_id, max_avail_wr);
+ return (-EINVAL);
+ }
+
+ mutex_lock(&srq->mutex);
+ ret = roce3_srq_arm(rdev, srq, attr->srq_limit);
+ mutex_unlock(&srq->mutex);
+
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to handle srq arm, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_srq_query
+ Description : roce3_srq_query
+ Input : struct roce3_device *rdev
+ struct roce3_srq *srq
+ u32 *srq_limit
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_srq_query(struct roce3_device *rdev, struct roce3_srq *srq, u32 *srq_limit)
+{
+ int ret = 0;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_outbuf = NULL;
+ struct tag_roce_cmd_srq_query *srq_query_inbuf = NULL;
+ struct roce3_srq_query_outbuf *srq_query_outbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_srq_query), &cqm_cmd_outbuf,
+ (u16)sizeof(struct roce3_srq_query_outbuf));
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ srq_query_inbuf = (struct tag_roce_cmd_srq_query *)cqm_cmd_inbuf->buf;
+ srq_query_outbuf = (struct roce3_srq_query_outbuf *)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(VERBS_CMD_TYPE_SRQ_BITMASK); //lint !e778
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_QUERY_SRQ,
+ cqm_cmd_inbuf, cqm_cmd_outbuf, NULL,
+ ROCE_CMD_TIME_CLASS_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to send QUERY_SRQ command, ret(%d), func_id(%d)\n",
+ __func__, ret, rdev->glb_func_id);
+
+ if (roce3_hca_is_present(rdev) != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA is present(QUERY_SRQ), srqn(0x%x), func_id(%u)\n",
+ __func__, srq->srqn, 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_query_outbuf->srqc.dw3.value = be32_to_cpu(srq_query_outbuf->srqc.dw3.value);
+ *srq_limit = srq_query_outbuf->srqc.dw3.bs.lth;
+
+ if (srq->container_flag != 0) {
+ /* parse srqc to get warn_th */
+ u32 warn_th = srq_query_outbuf->srqc.dw2.bs_c.warn_th;
+ *srq_limit = (warn_th == 0) ? 0 :
+ ((u32)((srq->container_size - 1) * (1U << warn_th)));
+ }
+
+err_cmd:
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, cqm_cmd_outbuf);
+
+ return ret;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_query_srq
+ Description : roce3_query_srq
+ Input : struct ib_srq *ibsrq
+ struct ib_srq_attr *srq_attr
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+int roce3_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+ int ret = 0;
+ u32 limit_water = 0;
+ struct roce3_device *rdev = NULL;
+ struct roce3_srq *rsrq = NULL;
+
+ if ((ibsrq == NULL) || (srq_attr == NULL)) {
+ pr_err("[ROCE, ERR] %s: Ibsrq or srq_attr is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibsrq->device);
+ if (roce3_hca_is_present(rdev) == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s): HCA not present(return fail), func_id(%u)\n",
+ __func__, rdev->glb_func_id);
+ return -EPERM;
+ }
+
+ rsrq = to_roce3_srq(ibsrq);
+
+ ret = roce3_srq_query(rdev, rsrq, &limit_water);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to query srq, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+ return ret;
+ }
+
+ srq_attr->srq_limit = limit_water;
+ srq_attr->max_wr = roce3_srq_max_avail_wr_set(rsrq);
+ srq_attr->max_sge = (u32)rsrq->max_gs;
+
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ Prototype : roce3_srq_hw2sw
+ Description : roce3_srq_hw2sw
+ Input : struct roce3_device *rdev
+ struct roce3_srq *srq
+ Output : None
+
+ 1.Date : 2015/5/27
+ Modification : Created function
+
+****************************************************************************
+*/
+static int roce3_srq_hw2sw(struct roce3_device *rdev, struct roce3_srq *srq)
+{
+ int ret = 0;
+ struct rdma_service_cap *rdma_cap = NULL;
+ struct tag_cqm_cmd_buf *cqm_cmd_inbuf = NULL;
+ struct tag_roce_cmd_srq_hw2sw *srq_hw2sw_inbuf = NULL;
+
+ ret = roce3_cqm_cmd_zalloc_inoutbuf(rdev->hwdev, &cqm_cmd_inbuf,
+ (u16)sizeof(struct tag_roce_cmd_srq_hw2sw), NULL, 0);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to alloc cqm_cmd_inoutbuf, func_id(%d), ret(%d)\n",
+ __func__, rdev->glb_func_id, ret);
+ return -ENOMEM;
+ }
+
+ srq_hw2sw_inbuf = (struct tag_roce_cmd_srq_hw2sw *)cqm_cmd_inbuf->buf;
+ rdma_cap = &rdev->rdma_cap;
+ srq_hw2sw_inbuf->com.index = cpu_to_be32((u32)srq->srqn);
+ srq_hw2sw_inbuf->com.dw0.bs.cmd_bitmask =
+ cpu_to_be16(VERBS_CMD_TYPE_SRQ_BITMASK); //lint !e778
+ srq_hw2sw_inbuf->srq_buf_len = cpu_to_be32((u32)srq->buf_sz);
+
+ srq_hw2sw_inbuf->mtt_info.mtt_flags = 0;
+ srq_hw2sw_inbuf->mtt_info.mtt_num = 0;
+ srq_hw2sw_inbuf->mtt_info.mtt_cache_line_start =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_start);
+ srq_hw2sw_inbuf->mtt_info.mtt_cache_line_end =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_end);
+ srq_hw2sw_inbuf->mtt_info.mtt_cache_line_size =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.cmtt_cl_sz);
+
+ srq_hw2sw_inbuf->wqe_cache_line_start =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.wqe_cl_start);
+ srq_hw2sw_inbuf->wqe_cache_line_end =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.wqe_cl_end);
+ srq_hw2sw_inbuf->wqe_cache_line_size =
+ cpu_to_be32(rdma_cap->dev_rdma_cap.roce_own_cap.wqe_cl_sz);
+
+ ret = cqm_send_cmd_box(rdev->hwdev, HINIC3_MOD_ROCE, ROCE_CMD_HW2SW_SRQ,
+ cqm_cmd_inbuf, NULL, NULL, ROCE_CMD_TIME_CLASS_A, HINIC3_CHANNEL_ROCE);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to send HW2SW_SRQ command, func_id(%d)\n",
+ __func__, rdev->glb_func_id);
+
+ if (roce3_hca_is_present(rdev) == 0) {
+ ret = 0;
+ } else {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE] %s: HCA is present(HW2SW_SRQ), srqn(0x%x), func_id(%u)\n",
+ __func__, srq->srqn, rdev->glb_func_id);
+
+ if ((ret == -ETIMEDOUT) || (ret == -EPERM))
+ rdev->dev_status_to_ofed = ROCE_DEV_STATUS_CMDQ_TIMEOUT;
+
+ ret = -1;
+ }
+ }
+
+ roce3_cqm_cmd_free_inoutbuf(rdev->hwdev, cqm_cmd_inbuf, NULL);
+
+ return ret;
+}
+
+static void roce3_free_srq(struct ib_srq *ibsrq, struct roce3_device *rdev,
+ struct roce3_srq *srq, struct ib_udata *udata)
+{
+ hmm_rdma_mtt_free(rdev->hwdev, &srq->mtt, SERVICE_T_ROCE);
+
+ if (ibsrq->uobject) {
+ struct roce3_ucontext *ucontext = rdma_udata_to_drv_context(
+ udata, struct roce3_ucontext, ibucontext);
+ roce3_db_unmap_user(ucontext, &srq->db);
+ ib_umem_release(srq->umem);
+ } else {
+ kfree(srq->wrid);
+ }
+
+ hiudk_cqm_object_delete(rdev->hwdev, &srq->cqm_srq->object);
+}
+
+int roce3_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
+{
+ int ret = 0;
+ int times = 0;
+ int read_back_flag = 0;
+ struct roce3_device *rdev = NULL;
+ struct roce3_srq *srq = NULL;
+ struct roce_srq_context *srqc = NULL;
+ struct roce_srq_context check_srqc;
+
+ if (ibsrq == NULL) {
+ pr_err("[ROCE, ERR] %s: Ibsrq is null\n", __func__);
+ return -EINVAL;
+ }
+
+ rdev = to_roce3_dev(ibsrq->device);
+ srq = to_roce3_srq(ibsrq);
+ times = rdev->try_times;
+
+ ret = roce3_srq_hw2sw(rdev, srq);
+ if (ret != 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to handle srq hw2sw, func_id(%u), ret:%d\n",
+ __func__, rdev->glb_func_id, ret);
+ return ret;
+ }
+
+ srqc = (struct roce_srq_context *)((void *)srq->cqm_srq->q_ctx_vaddr);
+ while ((times--) != 0) {
+ if (roce3_hca_is_present(rdev) == 0)
+ goto err_roce_srq_free;
+ check_srqc.dw2.value = be32_to_cpu(srqc->dw2.value);
+ if (check_srqc.dw2.bs.state == ROCE_SRQ_STATE_CHECK_VALUE) {
+ read_back_flag = 1;
+ break;
+ }
+
+ ROCE_UDELAY(US_PERF_DELAY);
+ }
+
+ if (read_back_flag == 0) {
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Failed to read srq state back after try %d times, func_id(%u), Srqn(0x%x), state_dw(0x%x)\n",
+ __func__, rdev->try_times, rdev->glb_func_id, srq->srqn, srqc->dw2.value);
+ return -1;
+ }
+
+err_roce_srq_free:
+ roce3_free_srq(ibsrq, rdev, srq, udata);
+
+ return 0;
+}
+
+static int roce3_check_sge_length(const struct ib_recv_wr *wr, struct roce3_device *rdev,
+ const struct ib_recv_wr **bad_wr, struct roce3_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;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Sge data length is over range, sg_list(%d), length(0x%x), max_msg_sz(0x%x), func_id(%d)\n",
+ __func__, 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);
+
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Data length is over range, data_len(0x%x), max_msg_sz(0x%x), func_id(%d)\n",
+ __func__, 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;
+}
+
+int roce3_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;
+ struct roce3_srq *srq = to_roce3_srq(ibsrq);
+ struct roce3_device *rdev = NULL;
+ struct roce3_wqe_srq_next_seg *next = NULL;
+ struct roce3_wqe_srq_data_seg *scat = NULL;
+ const struct ib_recv_wr *wr_tmp = wr;
+
+ rdev = to_roce3_dev(ibsrq->device);
+ if (roce3_hca_is_present(rdev) == 0)
+ return -EPERM;
+
+ 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;
+ dev_err(rdev->hwdev_hdl,
+ "[ROCE, ERR] %s: Num_sge(%d) > max_gs(%d) or srq is empty(head(%d) == tail(%d)), func_id(%d)\n",
+ __func__, wr_tmp->num_sge, srq->max_gs,
+ rdev->glb_func_id, srq->head, srq->tail);
+ break;
+ }
+
+ next = (struct roce3_wqe_srq_next_seg *)roce3_srq_get_wqe(srq, srq->head);
+ scat = (struct roce3_wqe_srq_data_seg *)(next + 1);
+
+ ret = roce3_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;
+}
diff --git a/drivers/net/ethernet/huawei/hinic3/Makefile b/drivers/net/ethernet/huawei/hinic3/Makefile
index b17f80ff19b82..11fe010448257 100644
--- a/drivers/net/ethernet/huawei/hinic3/Makefile
+++ b/drivers/net/ethernet/huawei/hinic3/Makefile
@@ -1,5 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-only
ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/hw/
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/cqm/
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cqm/
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/public/
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/mpu/
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/bond/
+ccflags-y += -I$(srctree)/drivers/net/ethernet/huawei/hinic3/include/vmsec/
obj-$(CONFIG_HINIC3) += hinic3.o
hinic3-objs := hw/hinic3_hwdev.o \
@@ -23,6 +32,8 @@ hinic3-objs := hw/hinic3_hwdev.o \
hw/hinic3_nictool.o \
hw/hinic3_devlink.o \
hw/ossl_knl_linux.o \
+ hw/hinic3_multi_host_mgmt.o \
+ bond/hinic3_bond.o \
hinic3_main.o \
hinic3_tx.o \
hinic3_rx.o \
@@ -42,4 +53,13 @@ hinic3-objs := hw/hinic3_hwdev.o \
hinic3_rss_cfg.o \
hinic3_nic_event.o \
hinic3_nic_io.o \
- hinic3_nic_dbg.o \ No newline at end of file
+ hinic3_nic_dbg.o \
+ cqm/cqm_bat_cla.o \
+ cqm/cqm_bitmap_table.o \
+ cqm/cqm_object_intern.o \
+ cqm/cqm_bloomfilter.o \
+ cqm/cqm_cmd.o \
+ cqm/cqm_db.o \
+ cqm/cqm_object.o \
+ cqm/cqm_main.o \
+ cqm/cqm_memsec.o
diff --git a/drivers/net/ethernet/huawei/hinic3/bond/hinic3_bond.c b/drivers/net/ethernet/huawei/hinic3/bond/hinic3_bond.c
new file mode 100644
index 0000000000000..1a41170cb9d24
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/bond/hinic3_bond.c
@@ -0,0 +1,1042 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": [NIC]" fmt
+
+#include <net/sock.h>
+#include <net/bonding.h>
+#include <linux/rtnetlink.h>
+#include <linux/net.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+
+#include "hinic3_lld.h"
+#include "hinic3_srv_nic.h"
+#include "hinic3_nic_dev.h"
+#include "hinic3_hw.h"
+#include "mpu_inband_cmd.h"
+#include "hinic3_hwdev.h"
+#include "hinic3_bond.h"
+
+#define PORT_INVALID_ID 0xFF
+
+#define STATE_SYNCHRONIZATION_INDEX 3
+
+struct hinic3_bond_dev {
+ char name[BOND_NAME_MAX_LEN];
+ struct bond_attr bond_attr;
+ struct bond_attr new_attr;
+ struct bonding *bond;
+ void *ppf_hwdev;
+ struct kref ref;
+#define BOND_DEV_STATUS_IDLE 0x0
+#define BOND_DEV_STATUS_ACTIVATED 0x1
+ u8 status;
+ u8 slot_used[HINIC3_BOND_USER_NUM];
+ struct workqueue_struct *wq;
+ struct delayed_work bond_work;
+ struct bond_tracker tracker;
+ spinlock_t lock; /* lock for change status */
+};
+
+typedef void (*bond_service_func)(const char *bond_name, void *bond_attr,
+ enum bond_service_proc_pos pos);
+
+static DEFINE_MUTEX(g_bond_service_func_mutex);
+
+static bond_service_func g_bond_service_func[HINIC3_BOND_USER_NUM];
+
+struct hinic3_bond_mngr {
+ u32 cnt;
+ struct hinic3_bond_dev *bond_dev[BOND_MAX_NUM];
+ struct socket *rtnl_sock;
+};
+
+static struct hinic3_bond_mngr bond_mngr = { .cnt = 0 };
+static DEFINE_MUTEX(g_bond_mutex);
+
+static bool bond_dev_is_activated(const struct hinic3_bond_dev *bdev)
+{
+ return bdev->status == BOND_DEV_STATUS_ACTIVATED;
+}
+
+#define PCI_DBDF(dom, bus, dev, func) \
+ (((dom) << 16) | ((bus) << 8) | ((dev) << 3) | ((func) & 0x7))
+
+#ifdef __PCLINT__
+static inline bool netif_is_bond_master(const struct net_device *dev)
+{
+ return (dev->flags & IFF_MASTER) && (dev->priv_flags & IFF_BONDING);
+}
+#endif
+
+static u32 bond_gen_uplink_id(struct hinic3_bond_dev *bdev)
+{
+ u32 uplink_id = 0;
+ u8 i;
+ struct hinic3_nic_dev *nic_dev = NULL;
+ struct pci_dev *pdev = NULL;
+ u32 domain, bus, dev, func;
+
+ spin_lock(&bdev->lock);
+ for (i = 0; i < BOND_PORT_MAX_NUM; i++) {
+ if (BITMAP_JUDGE(bdev->bond_attr.slaves, i)) {
+ if (!bdev->tracker.ndev[i])
+ continue;
+ nic_dev = netdev_priv(bdev->tracker.ndev[i]);
+ pdev = nic_dev->pdev;
+ domain = (u32)pci_domain_nr(pdev->bus);
+ bus = pdev->bus->number;
+ dev = PCI_SLOT(pdev->devfn);
+ func = PCI_FUNC(pdev->devfn);
+ uplink_id = PCI_DBDF(domain, bus, dev, func);
+ break;
+ }
+ }
+ spin_unlock(&bdev->lock);
+
+ return uplink_id;
+}
+
+static struct hinic3_nic_dev *get_nic_dev_safe(struct net_device *ndev)
+{
+ struct hinic3_lld_dev *lld_dev = NULL;
+
+ lld_dev = hinic3_get_lld_dev_by_netdev(ndev);
+ if (!lld_dev)
+ return NULL;
+
+ return netdev_priv(ndev);
+}
+
+static u8 bond_get_slaves_bitmap(struct hinic3_bond_dev *bdev, struct bonding *bond)
+{
+ struct slave *slave = NULL;
+ struct list_head *iter = NULL;
+ struct hinic3_nic_dev *nic_dev = NULL;
+ u8 bitmap = 0;
+ u8 port_id;
+
+ rcu_read_lock();
+ bond_for_each_slave_rcu(bond, slave, iter) {
+ nic_dev = get_nic_dev_safe(slave->dev);
+ if (!nic_dev)
+ continue;
+
+ port_id = hinic3_physical_port_id(nic_dev->hwdev);
+ BITMAP_SET(bitmap, port_id);
+ (void)iter;
+ }
+ rcu_read_unlock();
+
+ return bitmap;
+}
+
+static void bond_update_attr(struct hinic3_bond_dev *bdev, struct bonding *bond)
+{
+ spin_lock(&bdev->lock);
+
+ bdev->new_attr.bond_mode = (u16)bond->params.mode;
+ bdev->new_attr.bond_id = bdev->bond_attr.bond_id;
+ bdev->new_attr.up_delay = (u16)bond->params.updelay;
+ bdev->new_attr.down_delay = (u16)bond->params.downdelay;
+ bdev->new_attr.slaves = 0;
+ bdev->new_attr.active_slaves = 0;
+ bdev->new_attr.lacp_collect_slaves = 0;
+ bdev->new_attr.first_roce_func = DEFAULT_ROCE_BOND_FUNC;
+
+ /* Only support L2/L34/L23 three policy */
+ if (bond->params.xmit_policy <= BOND_XMIT_POLICY_LAYER23)
+ bdev->new_attr.xmit_hash_policy = (u8)bond->params.xmit_policy;
+ else
+ bdev->new_attr.xmit_hash_policy = BOND_XMIT_POLICY_LAYER2;
+
+ bdev->new_attr.slaves = bond_get_slaves_bitmap(bdev, bond);
+
+ spin_unlock(&bdev->lock);
+}
+
+static u8 bond_get_netdev_idx(const struct hinic3_bond_dev *bdev,
+ const struct net_device *ndev)
+{
+ u8 i;
+
+ for (i = 0; i < BOND_PORT_MAX_NUM; i++) {
+ if (bdev->tracker.ndev[i] == ndev)
+ return i;
+ }
+
+ return PORT_INVALID_ID;
+}
+
+static u8 bond_dev_track_port(struct hinic3_bond_dev *bdev,
+ struct net_device *ndev)
+{
+ u8 port_id;
+ void *ppf_hwdev = NULL;
+ struct hinic3_nic_dev *nic_dev = NULL;
+ struct hinic3_lld_dev *ppf_lld_dev = NULL;
+
+ nic_dev = get_nic_dev_safe(ndev);
+ if (!nic_dev) {
+ pr_warn("hinic3_bond: invalid slave: %s\n", ndev->name);
+ return PORT_INVALID_ID;
+ }
+
+ ppf_lld_dev = hinic3_get_ppf_lld_dev_unsafe(nic_dev->lld_dev);
+ if (ppf_lld_dev)
+ ppf_hwdev = ppf_lld_dev->hwdev;
+
+ pr_info("hinic3_bond: track ndev:%s", ndev->name);
+ port_id = hinic3_physical_port_id(nic_dev->hwdev);
+
+ spin_lock(&bdev->lock);
+ /* attach netdev to the port position associated with it */
+ if (bdev->tracker.ndev[port_id]) {
+ pr_warn("hinic3_bond: Old ndev:%s is replaced\n",
+ bdev->tracker.ndev[port_id]->name);
+ } else {
+ bdev->tracker.cnt++;
+ }
+ bdev->tracker.ndev[port_id] = ndev;
+ bdev->tracker.netdev_state[port_id].link_up = 0;
+ bdev->tracker.netdev_state[port_id].tx_enabled = 0;
+ if (!bdev->ppf_hwdev)
+ bdev->ppf_hwdev = ppf_hwdev;
+ pr_info("TRACK cnt: %d, slave_name(%s)\n", bdev->tracker.cnt, ndev->name);
+ spin_unlock(&bdev->lock);
+
+ return port_id;
+}
+
+static void bond_dev_untrack_port(struct hinic3_bond_dev *bdev, u8 idx)
+{
+ spin_lock(&bdev->lock);
+
+ if (bdev->tracker.ndev[idx]) {
+ pr_info("hinic3_bond: untrack port:%u ndev:%s cnt:%d\n", idx,
+ bdev->tracker.ndev[idx]->name, bdev->tracker.cnt);
+ bdev->tracker.ndev[idx] = NULL;
+ bdev->tracker.cnt--;
+ }
+
+ spin_unlock(&bdev->lock);
+}
+
+static void bond_slave_event(struct hinic3_bond_dev *bdev, struct slave *slave)
+{
+ u8 idx;
+
+ idx = bond_get_netdev_idx(bdev, slave->dev);
+ if (idx == PORT_INVALID_ID)
+ idx = bond_dev_track_port(bdev, slave->dev);
+ if (idx == PORT_INVALID_ID)
+ return;
+
+ spin_lock(&bdev->lock);
+ bdev->tracker.netdev_state[idx].link_up = bond_slave_is_up(slave);
+ bdev->tracker.netdev_state[idx].tx_enabled = bond_slave_is_up(slave) &&
+ bond_is_active_slave(slave);
+ spin_unlock(&bdev->lock);
+
+ queue_delayed_work(bdev->wq, &bdev->bond_work, 0);
+}
+
+static bool bond_eval_bonding_stats(const struct hinic3_bond_dev *bdev,
+ struct bonding *bond)
+{
+ int mode;
+
+ mode = BOND_MODE(bond);
+ if (mode != BOND_MODE_8023AD &&
+ mode != BOND_MODE_XOR &&
+ mode != BOND_MODE_ACTIVEBACKUP) {
+ pr_err("hinic3_bond: Wrong mode:%d\n", mode);
+ return false;
+ }
+
+ return bdev->tracker.cnt > 0;
+}
+
+static void bond_master_event(struct hinic3_bond_dev *bdev,
+ struct bonding *bond)
+{
+ spin_lock(&bdev->lock);
+ bdev->tracker.is_bonded = bond_eval_bonding_stats(bdev, bond);
+ spin_unlock(&bdev->lock);
+
+ queue_delayed_work(bdev->wq, &bdev->bond_work, 0);
+}
+
+static struct hinic3_bond_dev *bond_get_bdev(const struct bonding *bond)
+{
+ struct hinic3_bond_dev *bdev = NULL;
+ int bid;
+
+ mutex_lock(&g_bond_mutex);
+ for (bid = BOND_FIRST_ID; bid <= BOND_MAX_ID; bid++) {
+ bdev = bond_mngr.bond_dev[bid];
+ if (!bdev)
+ continue;
+
+ if (bond == bdev->bond) {
+ mutex_unlock(&g_bond_mutex);
+ return bdev;
+ }
+ }
+ mutex_unlock(&g_bond_mutex);
+ return NULL;
+}
+
+static void bond_handle_rtnl_event(struct net_device *ndev)
+{
+ struct hinic3_bond_dev *bdev = NULL;
+ struct bonding *bond = NULL;
+ struct slave *slave = NULL;
+
+ if (netif_is_bond_master(ndev)) {
+ bond = netdev_priv(ndev);
+ bdev = bond_get_bdev(bond);
+ } else if (netif_is_bond_slave(ndev)) {
+ /*lint -e(160) */
+ slave = bond_slave_get_rtnl(ndev);
+ if (slave) {
+ bond = bond_get_bond_by_slave(slave);
+ bdev = bond_get_bdev(bond);
+ }
+ }
+
+ if (!bond || !bdev)
+ return;
+
+ bond_update_attr(bdev, bond);
+
+ if (slave)
+ bond_slave_event(bdev, slave);
+ else
+ bond_master_event(bdev, bond);
+}
+
+static void bond_rtnl_data_ready(struct sock *sk)
+{
+ struct net_device *ndev = NULL;
+ struct ifinfomsg *ifinfo = NULL;
+ struct nlmsghdr *hdr = NULL;
+ struct sk_buff *skb = NULL;
+ int err = 0;
+
+ skb = skb_recv_datagram(sk, 0, 0, &err);
+ if (err != 0 || !skb)
+ return;
+
+ hdr = (struct nlmsghdr *)skb->data;
+ if (!hdr ||
+ !NLMSG_OK(hdr, skb->len) ||
+ hdr->nlmsg_type != RTM_NEWLINK ||
+ !rtnl_is_locked()) {
+ goto free_skb;
+ }
+
+ ifinfo = nlmsg_data(hdr);
+ ndev = dev_get_by_index(&init_net, ifinfo->ifi_index);
+ if (ndev) {
+ bond_handle_rtnl_event(ndev);
+ dev_put(ndev);
+ }
+
+free_skb:
+ kfree_skb(skb);
+}
+
+static int bond_enable_netdev_event(void)
+{
+ struct sockaddr_nl addr = {
+ .nl_family = AF_NETLINK,
+ .nl_groups = RTNLGRP_LINK,
+ };
+ int err;
+ struct socket **rtnl_sock = &bond_mngr.rtnl_sock;
+
+ err = sock_create_kern(&init_net, AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE,
+ rtnl_sock);
+ if (err) {
+ pr_err("hinic3_bond: Couldn't create rtnl socket.\n");
+ *rtnl_sock = NULL;
+ return err;
+ }
+
+ (*rtnl_sock)->sk->sk_data_ready = bond_rtnl_data_ready;
+ (*rtnl_sock)->sk->sk_allocation = GFP_KERNEL;
+
+ err = kernel_bind(*rtnl_sock, (struct sockaddr *)(u8 *)&addr, sizeof(addr));
+ if (err) {
+ pr_err("hinic3_bond: Couldn't bind rtnl socket.\n");
+ sock_release(*rtnl_sock);
+ *rtnl_sock = NULL;
+ }
+
+ return err;
+}
+
+static void bond_disable_netdev_event(void)
+{
+ if (bond_mngr.rtnl_sock)
+ sock_release(bond_mngr.rtnl_sock);
+}
+
+static int bond_send_upcmd(struct hinic3_bond_dev *bdev, struct bond_attr *attr,
+ u8 cmd_type)
+{
+ int err, len;
+ struct hinic3_bond_cmd cmd = {0};
+ u16 out_size = sizeof(cmd);
+
+ cmd.sub_cmd = 0;
+ cmd.ret_status = 0;
+
+ if (attr) {
+ memcpy(&cmd.attr, attr, sizeof(*attr));
+ } else {
+ cmd.attr.bond_id = bdev->bond_attr.bond_id;
+ cmd.attr.slaves = bdev->bond_attr.slaves;
+ }
+
+ len = sizeof(cmd.bond_name);
+ if (cmd_type == MPU_CMD_BOND_CREATE) {
+ strscpy(cmd.bond_name, bdev->name, len);
+ cmd.bond_name[sizeof(cmd.bond_name) - 1] = '\0';
+ }
+
+ err = hinic3_msg_to_mgmt_sync(bdev->ppf_hwdev, HINIC3_MOD_OVS, cmd_type,
+ &cmd, sizeof(cmd), &cmd, &out_size, 0,
+ HINIC3_CHANNEL_NIC);
+ if (err != 0 || !out_size || cmd.ret_status != 0) {
+ pr_err("hinic3_bond: uP cmd: %u failed, err: %d, sts: %u, out size: %u\n",
+ cmd_type, err, cmd.ret_status, out_size);
+ err = -EIO;
+ }
+
+ return err;
+}
+
+static int bond_upcmd_deactivate(struct hinic3_bond_dev *bdev)
+{
+ int err;
+ u16 id_tmp;
+
+ if (bdev->status == BOND_DEV_STATUS_IDLE)
+ return 0;
+
+ pr_info("hinic3_bond: deactivate bond: %u\n", bdev->bond_attr.bond_id);
+
+ err = bond_send_upcmd(bdev, NULL, MPU_CMD_BOND_DELETE);
+ if (err == 0) {
+ id_tmp = bdev->bond_attr.bond_id;
+ memset(&bdev->bond_attr, 0, sizeof(bdev->bond_attr));
+ bdev->status = BOND_DEV_STATUS_IDLE;
+ bdev->bond_attr.bond_id = id_tmp;
+ if (!bdev->tracker.cnt)
+ bdev->ppf_hwdev = NULL;
+ }
+
+ return err;
+}
+
+static void bond_pf_bitmap_set(struct hinic3_bond_dev *bdev, u8 index)
+{
+ struct hinic3_nic_dev *nic_dev = NULL;
+ u8 pf_id;
+
+ nic_dev = netdev_priv(bdev->tracker.ndev[index]);
+ if (!nic_dev)
+ return;
+
+ pf_id = hinic3_pf_id_of_vf(nic_dev->hwdev);
+ BITMAP_SET(bdev->new_attr.bond_pf_bitmap, pf_id);
+}
+
+static void bond_update_slave_info(struct hinic3_bond_dev *bdev,
+ struct bond_attr *attr)
+{
+ struct net_device *ndev = NULL;
+ u8 i;
+
+ if (!netif_running(bdev->bond->dev))
+ return;
+
+ if (attr->bond_mode == BOND_MODE_ACTIVEBACKUP) {
+ rcu_read_lock();
+ ndev = bond_option_active_slave_get_rcu(bdev->bond);
+ rcu_read_unlock();
+ }
+
+ for (i = 0; i < BOND_PORT_MAX_NUM; i++) {
+ if (!BITMAP_JUDGE(attr->slaves, i)) {
+ if (BITMAP_JUDGE(bdev->bond_attr.slaves, i))
+ bond_dev_untrack_port(bdev, i);
+
+ continue;
+ }
+
+ bond_pf_bitmap_set(bdev, i);
+ if (!bdev->tracker.netdev_state[i].tx_enabled)
+ continue;
+
+ if (attr->bond_mode == BOND_MODE_8023AD) {
+ BITMAP_SET(attr->active_slaves, i);
+ BITMAP_SET(attr->lacp_collect_slaves, i);
+ } else if (attr->bond_mode == BOND_MODE_XOR) {
+ BITMAP_SET(attr->active_slaves, i);
+ } else if (ndev && (ndev == bdev->tracker.ndev[i])) {
+ /* BOND_MODE_ACTIVEBACKUP */
+ BITMAP_SET(attr->active_slaves, i);
+ break;
+ }
+ }
+}
+
+static int bond_upcmd_config(struct hinic3_bond_dev *bdev,
+ struct bond_attr *attr)
+{
+ int err;
+
+ bond_update_slave_info(bdev, attr);
+ attr->bond_pf_bitmap = bdev->new_attr.bond_pf_bitmap;
+
+ if (memcmp(&bdev->bond_attr, attr, sizeof(struct bond_attr)) == 0)
+ return 0;
+
+ pr_info("hinic3_bond: Config bond: %u\n", attr->bond_id);
+ pr_info("mode:%u, up_d:%u, down_d:%u, hash:%u, slaves:%u, ap:%u, cs:%u\n",
+ attr->bond_mode,
+ attr->up_delay,
+ attr->down_delay,
+ attr->xmit_hash_policy,
+ attr->slaves,
+ attr->active_slaves,
+ attr->lacp_collect_slaves);
+ pr_info("bond_pf_bitmap: 0x%x\n", attr->bond_pf_bitmap);
+
+ err = bond_send_upcmd(bdev, attr, MPU_CMD_BOND_SET_ATTR);
+ if (!err)
+ memcpy(&bdev->bond_attr, attr, sizeof(*attr));
+
+ return err;
+}
+
+static int bond_upcmd_activate(struct hinic3_bond_dev *bdev,
+ struct bond_attr *attr)
+{
+ int err;
+
+ if (bond_dev_is_activated(bdev))
+ return 0;
+
+ pr_info("hinic3_bond: active bond: %u\n", bdev->bond_attr.bond_id);
+
+ err = bond_send_upcmd(bdev, attr, MPU_CMD_BOND_CREATE);
+ if (err == 0) {
+ bdev->status = BOND_DEV_STATUS_ACTIVATED;
+ bdev->bond_attr.bond_mode = attr->bond_mode;
+ err = bond_upcmd_config(bdev, attr);
+ }
+
+ return err;
+}
+
+static void bond_call_service_func(struct hinic3_bond_dev *bdev, struct bond_attr *attr,
+ enum bond_service_proc_pos pos, int bond_status)
+{
+ int i;
+
+ if (bond_status)
+ return;
+
+ mutex_lock(&g_bond_service_func_mutex);
+ for (i = 0; i < HINIC3_BOND_USER_NUM; i++) {
+ if (g_bond_service_func[i])
+ g_bond_service_func[i](bdev->name, (void *)attr, pos);
+ }
+ mutex_unlock(&g_bond_service_func_mutex);
+}
+
+static void bond_do_work(struct hinic3_bond_dev *bdev)
+{
+ bool is_bonded = 0;
+ struct bond_attr attr;
+ int err = 0;
+
+ spin_lock(&bdev->lock);
+ is_bonded = bdev->tracker.is_bonded;
+ attr = bdev->new_attr;
+ spin_unlock(&bdev->lock);
+ attr.user_bitmap = 0;
+
+ /* is_bonded indicates whether bond should be activated. */
+ if (is_bonded && !bond_dev_is_activated(bdev)) {
+ bond_call_service_func(bdev, &attr, BOND_BEFORE_ACTIVE, 0);
+ err = bond_upcmd_activate(bdev, &attr);
+ bond_call_service_func(bdev, &attr, BOND_AFTER_ACTIVE, err);
+ } else if (is_bonded && bond_dev_is_activated(bdev)) {
+ bond_call_service_func(bdev, &attr, BOND_BEFORE_MODIFY, 0);
+ err = bond_upcmd_config(bdev, &attr);
+ bond_call_service_func(bdev, &attr, BOND_AFTER_MODIFY, err);
+ } else if (!is_bonded && bond_dev_is_activated(bdev)) {
+ bond_call_service_func(bdev, &attr, BOND_BEFORE_DEACTIVE, 0);
+ err = bond_upcmd_deactivate(bdev);
+ bond_call_service_func(bdev, &attr, BOND_AFTER_DEACTIVE, err);
+ }
+
+ if (err)
+ pr_err("hinic3_bond: Do bond failed\n");
+}
+
+#define MIN_BOND_SLAVE_CNT 2
+static void bond_try_do_work(struct work_struct *work)
+{
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct hinic3_bond_dev *bdev =
+ container_of(delayed_work, struct hinic3_bond_dev, bond_work);
+
+ if (g_bond_service_func[HINIC3_BOND_USER_ROCE] && bdev->tracker.cnt < MIN_BOND_SLAVE_CNT)
+ queue_delayed_work(bdev->wq, &bdev->bond_work, HZ);
+ else
+ bond_do_work(bdev);
+}
+
+static int bond_dev_init(struct hinic3_bond_dev *bdev, const char *name)
+{
+ bdev->wq = create_singlethread_workqueue("hinic3_bond_wq");
+ if (!bdev->wq) {
+ pr_err("hinic3_bond: Failed to create workqueue\n");
+ return -ENODEV;
+ }
+
+ INIT_DELAYED_WORK(&bdev->bond_work, bond_try_do_work);
+ bdev->status = BOND_DEV_STATUS_IDLE;
+ strscpy(bdev->name, name, sizeof(bdev->name));
+
+ spin_lock_init(&bdev->lock);
+
+ return 0;
+}
+
+static int bond_dev_release(struct hinic3_bond_dev *bdev)
+{
+ int err;
+ u8 i;
+ u32 bond_cnt;
+
+ err = bond_upcmd_deactivate(bdev);
+ if (err) {
+ pr_err("hinic3_bond: Failed to deactivate dev\n");
+ return err;
+ }
+
+ for (i = BOND_FIRST_ID; i <= BOND_MAX_ID; i++) {
+ if (bond_mngr.bond_dev[i] == bdev) {
+ bond_mngr.bond_dev[i] = NULL;
+ bond_mngr.cnt--;
+ pr_info("hinic3_bond: Free bond, id: %u mngr_cnt:%u\n", i, bond_mngr.cnt);
+ break;
+ }
+ }
+
+ bond_cnt = bond_mngr.cnt;
+ mutex_unlock(&g_bond_mutex);
+ if (!bond_cnt)
+ bond_disable_netdev_event();
+
+ cancel_delayed_work_sync(&bdev->bond_work);
+ destroy_workqueue(bdev->wq);
+ kfree(bdev);
+
+ return err;
+}
+
+static void bond_dev_free(struct kref *ref)
+{
+ struct hinic3_bond_dev *bdev = NULL;
+
+ bdev = container_of(ref, struct hinic3_bond_dev, ref);
+ bond_dev_release(bdev);
+}
+
+static struct hinic3_bond_dev *bond_dev_alloc(const char *name)
+{
+ struct hinic3_bond_dev *bdev = NULL;
+ u16 i;
+ int err;
+
+ bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
+ if (!bdev) {
+ mutex_unlock(&g_bond_mutex);
+ return NULL;
+ }
+
+ err = bond_dev_init(bdev, name);
+ if (err) {
+ kfree(bdev);
+ mutex_unlock(&g_bond_mutex);
+ return NULL;
+ }
+
+ if (!bond_mngr.cnt) {
+ err = bond_enable_netdev_event();
+ if (err) {
+ bond_dev_release(bdev);
+ return NULL;
+ }
+ }
+
+ for (i = BOND_FIRST_ID; i <= BOND_MAX_ID; i++) {
+ if (!bond_mngr.bond_dev[i]) {
+ bdev->bond_attr.bond_id = i;
+ bond_mngr.bond_dev[i] = bdev;
+ bond_mngr.cnt++;
+ pr_info("hinic3_bond: Create bond dev, id:%u cnt:%u\n", i, bond_mngr.cnt);
+ break;
+ }
+ }
+
+ if (i > BOND_MAX_ID) {
+ bond_dev_release(bdev);
+ bdev = NULL;
+ pr_err("hinic3_bond: Failed to get free bond id\n");
+ }
+
+ return bdev;
+}
+
+static void update_bond_info(struct hinic3_bond_dev *bdev, struct bonding *bond)
+{
+ struct slave *slave = NULL;
+ struct list_head *iter = NULL;
+ struct net_device *ndev[BOND_PORT_MAX_NUM];
+ int i = 0;
+
+ bdev->bond = bond;
+
+ rtnl_lock();
+ bond_for_each_slave(bond, slave, iter) {
+ if (bond_dev_track_port(bdev, slave->dev) == PORT_INVALID_ID)
+ continue;
+ ndev[i] = slave->dev;
+ dev_hold(ndev[i++]);
+ if (i >= BOND_PORT_MAX_NUM)
+ break;
+ (void)iter;
+ }
+
+ bond_for_each_slave(bond, slave, iter) {
+ bond_handle_rtnl_event(slave->dev);
+ (void)iter;
+ }
+
+ bond_handle_rtnl_event(bond->dev);
+
+ rtnl_unlock();
+ /* In case user queries info before bonding is complete */
+ flush_delayed_work(&bdev->bond_work);
+
+ rtnl_lock();
+ while (i)
+ dev_put(ndev[--i]);
+ rtnl_unlock();
+}
+
+static struct hinic3_bond_dev *bond_dev_by_name(const char *name)
+{
+ struct hinic3_bond_dev *bdev = NULL;
+ int i;
+
+ for (i = BOND_FIRST_ID; i <= BOND_MAX_ID; i++) {
+ if (bond_mngr.bond_dev[i] &&
+ (strcmp(bond_mngr.bond_dev[i]->name, name) == 0)) {
+ bdev = bond_mngr.bond_dev[i];
+ break;
+ }
+ }
+
+ return bdev;
+}
+
+static void bond_dev_user_attach(struct hinic3_bond_dev *bdev,
+ enum hinic3_bond_user user)
+{
+ if (bdev->slot_used[user])
+ return;
+
+ bdev->slot_used[user] = 1;
+ if (!kref_get_unless_zero(&bdev->ref))
+ kref_init(&bdev->ref);
+}
+
+static void bond_dev_user_detach(struct hinic3_bond_dev *bdev,
+ enum hinic3_bond_user user, bool *freed)
+{
+ if (user < 0 || user >= HINIC3_BOND_USER_NUM)
+ return;
+
+ if (bdev->slot_used[user]) {
+ bdev->slot_used[user] = 0;
+ if (kref_read(&bdev->ref) == 1)
+ *freed = true;
+ kref_put(&bdev->ref, bond_dev_free);
+ }
+}
+
+static struct bonding *bond_get_knl_bonding(const char *name)
+{
+ struct net_device *ndev_tmp = NULL;
+
+ for_each_netdev(&init_net, ndev_tmp) {
+ if (netif_is_bond_master(ndev_tmp) &&
+ !strcmp(ndev_tmp->name, name))
+ return netdev_priv(ndev_tmp);
+ }
+
+ return NULL;
+}
+
+void hinic3_bond_set_user_bitmap(struct bond_attr *attr, enum hinic3_bond_user user)
+{
+ if (!BITMAP_JUDGE(attr->user_bitmap, user))
+ BITMAP_SET(attr->user_bitmap, user);
+}
+EXPORT_SYMBOL(hinic3_bond_set_user_bitmap);
+
+int hinic3_bond_attach(const char *name, enum hinic3_bond_user user,
+ u16 *bond_id)
+{
+ struct hinic3_bond_dev *bdev = NULL;
+ struct bonding *bond = NULL;
+ bool new_dev = false;
+
+ if (!name || !bond_id)
+ return -EINVAL;
+
+ bond = bond_get_knl_bonding(name);
+ if (!bond) {
+ pr_warn("hinic3_bond: Kernel bond %s not exist.\n", name);
+ return -ENODEV;
+ }
+
+ mutex_lock(&g_bond_mutex);
+ bdev = bond_dev_by_name(name);
+ if (!bdev) {
+ bdev = bond_dev_alloc(name);
+ new_dev = true;
+ } else {
+ pr_info("hinic3_bond: %s already exist\n", name);
+ }
+
+ if (!bdev) {
+ // lock has beed released in bond_dev_alloc
+ return -ENODEV;
+ }
+
+ bond_dev_user_attach(bdev, user);
+ mutex_unlock(&g_bond_mutex);
+
+ if (new_dev)
+ update_bond_info(bdev, bond);
+
+ *bond_id = bdev->bond_attr.bond_id;
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_bond_attach);
+
+int hinic3_bond_detach(u16 bond_id, enum hinic3_bond_user user)
+{
+ int err = 0;
+ bool lock_freed = false;
+
+ if (bond_id < BOND_FIRST_ID || bond_id > BOND_MAX_ID) {
+ pr_warn("hinic3_bond: Invalid bond id:%u to delete\n", bond_id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&g_bond_mutex);
+ if (!bond_mngr.bond_dev[bond_id])
+ err = -ENODEV;
+ else
+ bond_dev_user_detach(bond_mngr.bond_dev[bond_id], user, &lock_freed);
+
+ if (!lock_freed)
+ mutex_unlock(&g_bond_mutex);
+ return err;
+}
+EXPORT_SYMBOL(hinic3_bond_detach);
+
+void hinic3_bond_clean_user(enum hinic3_bond_user user)
+{
+ int i = 0;
+ bool lock_freed = false;
+
+ mutex_lock(&g_bond_mutex);
+ for (i = BOND_FIRST_ID; i <= BOND_MAX_ID; i++) {
+ if (bond_mngr.bond_dev[i]) {
+ bond_dev_user_detach(bond_mngr.bond_dev[i], user, &lock_freed);
+ if (lock_freed) {
+ mutex_lock(&g_bond_mutex);
+ lock_freed = false;
+ }
+ }
+ }
+ if (!lock_freed)
+ mutex_unlock(&g_bond_mutex);
+}
+EXPORT_SYMBOL(hinic3_bond_clean_user);
+
+int hinic3_bond_get_uplink_id(u16 bond_id, u32 *uplink_id)
+{
+ if (bond_id < BOND_FIRST_ID || bond_id > BOND_MAX_ID || !uplink_id) {
+ pr_warn("hinic3_bond: Invalid args, id: %u, uplink: %d\n",
+ bond_id, !!uplink_id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&g_bond_mutex);
+ if (bond_mngr.bond_dev[bond_id])
+ *uplink_id = bond_gen_uplink_id(bond_mngr.bond_dev[bond_id]);
+ mutex_unlock(&g_bond_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_bond_get_uplink_id);
+
+int hinic3_bond_register_service_func(enum hinic3_bond_user user, void (*func)
+ (const char *bond_name, void *bond_attr,
+ enum bond_service_proc_pos pos))
+{
+ if (user >= HINIC3_BOND_USER_NUM)
+ return -EINVAL;
+
+ mutex_lock(&g_bond_service_func_mutex);
+ g_bond_service_func[user] = func;
+ mutex_unlock(&g_bond_service_func_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_bond_register_service_func);
+
+int hinic3_bond_unregister_service_func(enum hinic3_bond_user user)
+{
+ if (user >= HINIC3_BOND_USER_NUM)
+ return -EINVAL;
+
+ mutex_lock(&g_bond_service_func_mutex);
+ g_bond_service_func[user] = NULL;
+ mutex_unlock(&g_bond_service_func_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_bond_unregister_service_func);
+
+int hinic3_bond_get_slaves(u16 bond_id, struct hinic3_bond_info_s *info)
+{
+ struct bond_tracker *tracker = NULL;
+ int size;
+ int i;
+ int len;
+
+ if (!info || bond_id < BOND_FIRST_ID || bond_id > BOND_MAX_ID) {
+ pr_warn("hinic3_bond: Invalid args, info: %d,id: %u\n",
+ !!info, bond_id);
+ return -EINVAL;
+ }
+
+ size = ARRAY_LEN(info->slaves_name);
+ if (size < BOND_PORT_MAX_NUM) {
+ pr_warn("hinic3_bond: Invalid args, size: %u\n",
+ size);
+ return -EINVAL;
+ }
+
+ mutex_lock(&g_bond_mutex);
+ if (bond_mngr.bond_dev[bond_id]) {
+ info->slaves = bond_mngr.bond_dev[bond_id]->bond_attr.slaves;
+ tracker = &bond_mngr.bond_dev[bond_id]->tracker;
+ info->cnt = 0;
+ for (i = 0; i < BOND_PORT_MAX_NUM; i++) {
+ if (BITMAP_JUDGE(info->slaves, i) && tracker->ndev[i]) {
+ len = sizeof(info->slaves_name[0]);
+ strscpy(info->slaves_name[info->cnt], tracker->ndev[i]->name, len);
+ info->cnt++;
+ }
+ }
+ }
+ mutex_unlock(&g_bond_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_bond_get_slaves);
+
+struct net_device *hinic3_bond_get_netdev_by_portid(const char *bond_name, u8 port_id)
+{
+ struct hinic3_bond_dev *bdev = NULL;
+
+ if (port_id >= BOND_PORT_MAX_NUM)
+ return NULL;
+ mutex_lock(&g_bond_mutex);
+ bdev = bond_dev_by_name(bond_name);
+ if (!bdev) {
+ mutex_unlock(&g_bond_mutex);
+ return NULL;
+ }
+ mutex_unlock(&g_bond_mutex);
+ return bdev->tracker.ndev[port_id];
+}
+EXPORT_SYMBOL(hinic3_bond_get_netdev_by_portid);
+
+int hinic3_get_hw_bond_infos(void *hwdev, struct hinic3_hw_bond_infos *infos, u16 channel)
+{
+ struct comm_cmd_hw_bond_infos bond_infos;
+ u16 out_size = sizeof(bond_infos);
+ int err;
+
+ if (!hwdev || !infos)
+ return -EINVAL;
+
+ memset(&bond_infos, 0, sizeof(bond_infos));
+
+ bond_infos.infos.bond_id = infos->bond_id;
+
+ err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_COMM, COMM_MGMT_CMD_GET_HW_BOND,
+ &bond_infos, sizeof(bond_infos),
+ &bond_infos, &out_size, 0, channel);
+ if (bond_infos.head.status || err || !out_size) {
+ sdk_err(((struct hinic3_hwdev *)hwdev)->dev_hdl,
+ "Failed to get hw bond information, err: %d, status: 0x%x, out size: 0x%x, channel: 0x%x\n",
+ err, bond_infos.head.status, out_size, channel);
+ return -EIO;
+ }
+
+ memcpy(infos, &bond_infos.infos, sizeof(*infos));
+
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_get_hw_bond_infos);
+
+int hinic3_get_bond_tracker_by_name(const char *name, struct bond_tracker *tracker)
+{
+ struct hinic3_bond_dev *bdev = NULL;
+ int i;
+
+ mutex_lock(&g_bond_mutex);
+ for (i = BOND_FIRST_ID; i <= BOND_MAX_ID; i++) {
+ if (bond_mngr.bond_dev[i] &&
+ (strcmp(bond_mngr.bond_dev[i]->name, name) == 0)) {
+ bdev = bond_mngr.bond_dev[i];
+ spin_lock(&bdev->lock);
+ *tracker = bdev->tracker;
+ spin_unlock(&bdev->lock);
+ mutex_unlock(&g_bond_mutex);
+ return 0;
+ }
+ }
+ mutex_unlock(&g_bond_mutex);
+ return -ENODEV;
+}
+EXPORT_SYMBOL(hinic3_get_bond_tracker_by_name);
diff --git a/drivers/net/ethernet/huawei/hinic3/bond/hinic3_bond.h b/drivers/net/ethernet/huawei/hinic3/bond/hinic3_bond.h
new file mode 100644
index 0000000000000..3ee99d9067bda
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/bond/hinic3_bond.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC3_BOND_H
+#define HINIC3_BOND_H
+
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include "mpu_inband_cmd_defs.h"
+#include "bond_common_defs.h"
+
+enum hinic3_bond_user {
+ HINIC3_BOND_USER_OVS,
+ HINIC3_BOND_USER_TOE,
+ HINIC3_BOND_USER_ROCE,
+ HINIC3_BOND_USER_NUM
+};
+
+enum bond_service_proc_pos {
+ BOND_BEFORE_ACTIVE,
+ BOND_AFTER_ACTIVE,
+ BOND_BEFORE_MODIFY,
+ BOND_AFTER_MODIFY,
+ BOND_BEFORE_DEACTIVE,
+ BOND_AFTER_DEACTIVE,
+ BOND_POS_MAX
+};
+
+#define BITMAP_SET(bm, bit) ((bm) |= (typeof(bm))(1U << (bit)))
+#define BITMAP_CLR(bm, bit) ((bm) &= ~((typeof(bm))(1U << (bit))))
+#define BITMAP_JUDGE(bm, bit) ((bm) & (typeof(bm))(1U << (bit)))
+
+#define MPU_CMD_BOND_CREATE 17
+#define MPU_CMD_BOND_DELETE 18
+#define MPU_CMD_BOND_SET_ATTR 19
+#define MPU_CMD_BOND_GET_ATTR 20
+
+#define HINIC3_MAX_PORT 4
+#define HINIC3_IFNAMSIZ 16
+struct hinic3_bond_info_s {
+ u8 slaves;
+ u8 cnt;
+ u8 srv[2];
+ char slaves_name[HINIC3_MAX_PORT][HINIC3_IFNAMSIZ];
+};
+
+#pragma pack(1)
+struct netdev_lower_state_info {
+ u8 link_up : 1;
+ u8 tx_enabled : 1;
+ u8 rsvd : 6;
+};
+
+#pragma pack()
+
+struct bond_tracker {
+ struct netdev_lower_state_info netdev_state[BOND_PORT_MAX_NUM];
+ struct net_device *ndev[BOND_PORT_MAX_NUM];
+ u8 cnt;
+ bool is_bonded;
+};
+
+struct bond_attr {
+ u16 bond_mode;
+ u16 bond_id;
+ u16 up_delay;
+ u16 down_delay;
+ u8 active_slaves;
+ u8 slaves;
+ u8 lacp_collect_slaves;
+ u8 xmit_hash_policy;
+ u32 first_roce_func;
+ u32 bond_pf_bitmap;
+ u32 user_bitmap;
+};
+
+struct hinic3_bond_cmd {
+ u8 ret_status;
+ u8 version;
+ u16 sub_cmd;
+ struct bond_attr attr;
+ char bond_name[16];
+};
+
+void hinic3_bond_set_user_bitmap(struct bond_attr *attr, enum hinic3_bond_user user);
+int hinic3_bond_attach(const char *name, enum hinic3_bond_user user, u16 *bond_id);
+int hinic3_bond_detach(u16 bond_id, enum hinic3_bond_user user);
+void hinic3_bond_clean_user(enum hinic3_bond_user user);
+int hinic3_bond_get_uplink_id(u16 bond_id, u32 *uplink_id);
+int hinic3_bond_register_service_func(enum hinic3_bond_user user, void (*func)
+ (const char *bond_name, void *bond_attr,
+ enum bond_service_proc_pos pos));
+int hinic3_bond_unregister_service_func(enum hinic3_bond_user user);
+int hinic3_bond_get_slaves(u16 bond_id, struct hinic3_bond_info_s *info);
+struct net_device *hinic3_bond_get_netdev_by_portid(const char *bond_name, u8 port_id);
+int hinic3_get_hw_bond_infos(void *hwdev, struct hinic3_hw_bond_infos *infos, u16 channel);
+int hinic3_get_bond_tracker_by_name(const char *name, struct bond_tracker *tracker);
+#endif /* HINIC3_BOND_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/comm_msg_intf.h b/drivers/net/ethernet/huawei/hinic3/comm_msg_intf.h
index 4d662fe4cc3e3..ae998cfcd1891 100644
--- a/drivers/net/ethernet/huawei/hinic3/comm_msg_intf.h
+++ b/drivers/net/ethernet/huawei/hinic3/comm_msg_intf.h
@@ -14,69 +14,8 @@
#include "comm_defs.h"
#include "mgmt_msg_base.h"
-
-/* func_reset_flag的边界值 */
-#define FUNC_RESET_FLAG_MAX_VALUE ((1U << (RES_TYPE_MAX + 1)) - 1)
-struct comm_cmd_func_reset {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u16 rsvd1[3];
- u64 reset_flag;
-};
-
-struct comm_cmd_ppf_flr_type_set {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u8 rsvd1[2];
- u32 ppf_flr_type;
-};
-
-enum {
- COMM_F_API_CHAIN = 1U << 0,
- COMM_F_CLP = 1U << 1,
- COMM_F_CHANNEL_DETECT = 1U << 2,
- COMM_F_MBOX_SEGMENT = 1U << 3,
- COMM_F_CMDQ_NUM = 1U << 4,
- COMM_F_VIRTIO_VQ_SIZE = 1U << 5,
-};
-
-#define COMM_MAX_FEATURE_QWORD 4
-struct comm_cmd_feature_nego {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u8 opcode; /* 1: set, 0: get */
- u8 rsvd;
- u64 s_feature[COMM_MAX_FEATURE_QWORD];
-};
-
-struct comm_cmd_clear_doorbell {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u16 rsvd1[3];
-};
-
-struct comm_cmd_clear_resource {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u16 rsvd1[3];
-};
-
-struct comm_global_attr {
- u8 max_host_num;
- u8 max_pf_num;
- u16 vf_id_start;
-
- u8 mgmt_host_node_id; /* for api cmd to mgmt cpu */
- u8 cmdq_num;
- u8 rsvd1[2];
-
- u32 rsvd2[8];
-};
+#include "mpu_cmd_base_defs.h"
+#include "mpu_inband_cmd_defs.h"
struct spu_cmd_freq_operation {
struct comm_info_head head;
@@ -107,236 +46,11 @@ struct spu_cmd_tsensor_operation {
s16 sys_tsensor_temp;
};
-struct comm_cmd_heart_event {
- struct mgmt_msg_head head;
-
- u8 init_sta; /* 0: mpu init ok, 1: mpu init error. */
- u8 rsvd1[3];
- u32 heart; /* add one by one */
- u32 heart_handshake; /* should be alwasys: 0x5A5A5A5A */
-};
-
-struct comm_cmd_channel_detect {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u16 rsvd1[3];
- u32 rsvd2[2];
-};
-
-enum hinic3_svc_type {
- SVC_T_COMM = 0,
- SVC_T_NIC,
- SVC_T_OVS,
- SVC_T_ROCE,
- SVC_T_TOE,
- SVC_T_IOE,
- SVC_T_FC,
- SVC_T_VBS,
- SVC_T_IPSEC,
- SVC_T_VIRTIO,
- SVC_T_MIGRATE,
- SVC_T_PPA,
- SVC_T_MAX,
-};
-
-struct comm_cmd_func_svc_used_state {
- struct mgmt_msg_head head;
- u16 func_id;
- u16 svc_type;
- u8 used_state;
- u8 rsvd[35];
-};
-
-#define TABLE_INDEX_MAX 129
-
-struct sml_table_id_info {
- u8 node_id;
- u8 instance_id;
-};
-
-struct comm_cmd_get_sml_tbl_data {
- struct comm_info_head head; /* 8B */
- u8 tbl_data[512];
-};
-
-struct comm_cmd_get_glb_attr {
- struct mgmt_msg_head head;
-
- struct comm_global_attr attr;
-};
-
-enum hinic3_fw_ver_type {
- HINIC3_FW_VER_TYPE_BOOT,
- HINIC3_FW_VER_TYPE_MPU,
- HINIC3_FW_VER_TYPE_NPU,
- HINIC3_FW_VER_TYPE_SMU_L0,
- HINIC3_FW_VER_TYPE_SMU_L1,
- HINIC3_FW_VER_TYPE_CFG,
-};
-
-#define HINIC3_FW_VERSION_LEN 16
-#define HINIC3_FW_COMPILE_TIME_LEN 20
-struct comm_cmd_get_fw_version {
- struct mgmt_msg_head head;
-
- u16 fw_type;
- u16 rsvd1;
- u8 ver[HINIC3_FW_VERSION_LEN];
- u8 time[HINIC3_FW_COMPILE_TIME_LEN];
-};
-
-/* hardware define: cmdq context */
-struct cmdq_ctxt_info {
- u64 curr_wqe_page_pfn;
- u64 wq_block_pfn;
-};
-
-struct comm_cmd_cmdq_ctxt {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u8 cmdq_id;
- u8 rsvd1[5];
-
- struct cmdq_ctxt_info ctxt;
-};
-
-struct comm_cmd_root_ctxt {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u8 set_cmdq_depth;
- u8 cmdq_depth;
- u16 rx_buf_sz;
- u8 lro_en;
- u8 rsvd1;
- u16 sq_depth;
- u16 rq_depth;
- u64 rsvd2;
-};
-
-struct comm_cmd_wq_page_size {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u8 opcode;
- /* real_size=4KB*2^page_size, range(0~20) must be checked by driver */
- u8 page_size;
-
- u32 rsvd1;
-};
-
-struct comm_cmd_msix_config {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u8 opcode;
- u8 rsvd1;
- u16 msix_index;
- u8 pending_cnt;
- u8 coalesce_timer_cnt;
- u8 resend_timer_cnt;
- u8 lli_timer_cnt;
- u8 lli_credit_cnt;
- u8 rsvd2[5];
-};
-
enum cfg_msix_operation {
CFG_MSIX_OPERATION_FREE = 0,
CFG_MSIX_OPERATION_ALLOC = 1,
};
-struct comm_cmd_cfg_msix_num {
- struct comm_info_head head; /* 8B */
-
- u16 func_id;
- u8 op_code; /* 1: alloc 0: free */
- u8 rsvd0;
-
- u16 msix_num;
- u16 rsvd1;
-};
-
-struct comm_cmd_dma_attr_config {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u8 entry_idx;
- u8 st;
- u8 at;
- u8 ph;
- u8 no_snooping;
- u8 tph_en;
- u32 resv1;
-};
-
-struct comm_cmd_ceq_ctrl_reg {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u16 q_id;
- u32 ctrl0;
- u32 ctrl1;
- u32 rsvd1;
-};
-
-struct comm_cmd_func_tmr_bitmap_op {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u8 opcode; /* 1: start, 0: stop */
- u8 rsvd1[5];
-};
-
-struct comm_cmd_ppf_tmr_op {
- struct mgmt_msg_head head;
-
- u8 ppf_id;
- u8 opcode; /* 1: start, 0: stop */
- u8 rsvd1[6];
-};
-
-struct comm_cmd_ht_gpa {
- struct mgmt_msg_head head;
-
- u8 host_id;
- u8 rsvd0[3];
- u32 rsvd1[7];
- u64 page_pa0;
- u64 page_pa1;
-};
-
-struct comm_cmd_get_eqm_num {
- struct mgmt_msg_head head;
-
- u8 host_id;
- u8 rsvd1[3];
- u32 chunk_num;
- u32 search_gpa_num;
-};
-
-struct comm_cmd_eqm_cfg {
- struct mgmt_msg_head head;
-
- u8 host_id;
- u8 valid;
- u16 rsvd1;
- u32 page_size;
- u32 rsvd2;
-};
-
-struct comm_cmd_eqm_search_gpa {
- struct mgmt_msg_head head;
-
- u8 host_id;
- u8 rsvd1[3];
- u32 start_idx;
- u32 num;
- u32 rsvd2;
- u64 gpa_hi52[0]; /*lint !e1501*/
-};
-
struct comm_cmd_ffm_info {
struct mgmt_msg_head head;
@@ -350,281 +64,6 @@ struct comm_cmd_ffm_info {
u32 rsvd1;
};
-#define HARDWARE_ID_1XX3V100_TAG 31 /* 1xx3v100 tag */
-
-struct hinic3_board_info {
- u8 board_type;
- u8 port_num;
- u8 port_speed;
- u8 pcie_width;
- u8 host_num;
- u8 pf_num;
- u16 vf_total_num;
- u8 tile_num;
- u8 qcm_num;
- u8 core_num;
- u8 work_mode;
- u8 service_mode;
- u8 pcie_mode;
- u8 boot_sel;
- u8 board_id;
- u32 cfg_addr;
- u32 service_en_bitmap;
- u8 scenes_id;
- u8 cfg_template_id;
- u8 hardware_id;
- u8 spu_en;
- u16 pf_vendor_id;
- u8 tile_bitmap;
- u8 sm_bitmap;
-};
-
-struct comm_cmd_board_info {
- struct mgmt_msg_head head;
-
- struct hinic3_board_info info;
- u32 rsvd[22];
-};
-
-struct comm_cmd_sync_time {
- struct mgmt_msg_head head;
-
- u64 mstime;
- u64 rsvd1;
-};
-
-struct comm_cmd_sdi_info {
- struct mgmt_msg_head head;
- u32 cfg_sdi_mode;
-};
-
-/* func flr set */
-struct comm_cmd_func_flr_set {
- struct mgmt_msg_head head;
-
- u16 func_id;
- u8 type; /* 1: close 置flush */
- u8 isall; /* 是否操作对应pf下的所有vf 1: all vf */
- u32 rsvd;
-};
-
-struct comm_cmd_bdf_info {
- struct mgmt_msg_head head;
-
- u16 function_idx;
- u8 rsvd1[2];
- u8 bus;
- u8 device;
- u8 function;
- u8 rsvd2[5];
-};
-
-struct hw_pf_info {
- u16 glb_func_idx;
- u16 glb_pf_vf_offset;
- u8 p2p_idx;
- u8 itf_idx;
- u16 max_vfs;
- u16 max_queue_num;
- u16 vf_max_queue_num;
- u16 port_id;
- u16 rsvd0;
- u32 pf_service_en_bitmap;
- u32 vf_service_en_bitmap;
- u16 rsvd1[2];
-
- u8 device_type;
- u8 bus_num; /* tl_cfg_bus_num */
- u16 vf_stride; /* VF_RID_SETTING.vf_stride */
- u16 vf_offset; /* VF_RID_SETTING.vf_offset */
- u8 rsvd[2];
-};
-
-#define CMD_MAX_MAX_PF_NUM 32
-struct hinic3_hw_pf_infos {
- u8 num_pfs;
- u8 rsvd1[3];
-
- struct hw_pf_info infos[CMD_MAX_MAX_PF_NUM];
-};
-
-struct comm_cmd_hw_pf_infos {
- struct mgmt_msg_head head;
-
- struct hinic3_hw_pf_infos infos;
-};
-
-#define DD_CFG_TEMPLATE_MAX_IDX 12
-#define DD_CFG_TEMPLATE_MAX_TXT_LEN 64
-#define CFG_TEMPLATE_OP_QUERY 0
-#define CFG_TEMPLATE_OP_SET 1
-#define CFG_TEMPLATE_SET_MODE_BY_IDX 0
-#define CFG_TEMPLATE_SET_MODE_BY_NAME 1
-
-struct comm_cmd_cfg_template {
- struct mgmt_msg_head head;
- u8 opt_type; /* 0: query 1: set */
- u8 set_mode; /* 0-index mode. 1-name mode. */
- u8 tp_err;
- u8 rsvd0;
-
- u8 cur_index; /* Current cfg tempalte index. */
- u8 cur_max_index; /* Max support cfg tempalte index. */
- u8 rsvd1[2];
- u8 cur_name[DD_CFG_TEMPLATE_MAX_TXT_LEN];
- u8 cur_cfg_temp_info[DD_CFG_TEMPLATE_MAX_IDX][DD_CFG_TEMPLATE_MAX_TXT_LEN];
-
- u8 next_index; /* Next reset cfg tempalte index. */
- u8 next_max_index; /* Max support cfg tempalte index. */
- u8 rsvd2[2];
- u8 next_name[DD_CFG_TEMPLATE_MAX_TXT_LEN];
- u8 next_cfg_temp_info[DD_CFG_TEMPLATE_MAX_IDX][DD_CFG_TEMPLATE_MAX_TXT_LEN];
-};
-
-#define MQM_SUPPORT_COS_NUM 8
-#define MQM_INVALID_WEIGHT 256
-#define MQM_LIMIT_SET_FLAG_READ 0
-#define MQM_LIMIT_SET_FLAG_WRITE 1
-struct comm_cmd_set_mqm_limit {
- struct mgmt_msg_head head;
-
- u16 set_flag; /* 置位该标记位表示设置 */
- u16 func_id;
- /* 对应cos_id所占的权重,0-255, 0为SP调度. */
- u16 cos_weight[MQM_SUPPORT_COS_NUM];
- u32 host_min_rate; /* 本host支持的最低限速 */
- u32 func_min_rate; /* 本function支持的最低限速,单位Mbps */
- u32 func_max_rate; /* 本function支持的最高限速,单位Mbps */
- u8 rsvd[64]; /* Reserved */
-};
-
-#define DUMP_16B_PER_LINE 16
-#define DUMP_8_VAR_PER_LINE 8
-#define DUMP_4_VAR_PER_LINE 4
-
-#define DATA_LEN_1K 1024
-/* 软狗超时信息上报接口 */
-struct comm_info_sw_watchdog {
- struct comm_info_head head;
-
- /* 全局信息 */
- u32 curr_time_h; /* 发生死循环的时间,cycle */
- u32 curr_time_l; /* 发生死循环的时间,cycle */
- u32 task_id; /* 发生死循环的任务 */
- u32 rsv; /* 保留字段,用于扩展 */
-
- /* 寄存器信息,TSK_CONTEXT_S */
- u64 pc;
-
- u64 elr;
- u64 spsr;
- u64 far;
- u64 esr;
- u64 xzr;
- u64 x30;
- u64 x29;
- u64 x28;
- u64 x27;
- u64 x26;
- u64 x25;
- u64 x24;
- u64 x23;
- u64 x22;
- u64 x21;
- u64 x20;
- u64 x19;
- u64 x18;
- u64 x17;
- u64 x16;
- u64 x15;
- u64 x14;
- u64 x13;
- u64 x12;
- u64 x11;
- u64 x10;
- u64 x09;
- u64 x08;
- u64 x07;
- u64 x06;
- u64 x05;
- u64 x04;
- u64 x03;
- u64 x02;
- u64 x01;
- u64 x00;
-
- /* 堆栈控制信息,STACK_INFO_S */
- u64 stack_top; /* 栈顶 */
- u64 stack_bottom; /* 栈底 */
- u64 sp; /* 栈当前SP指针值 */
- u32 curr_used; /* 栈当前使用的大小 */
- u32 peak_used; /* 栈使用的历史峰值 */
- u32 is_overflow; /* 栈是否溢出 */
-
- /* 堆栈具体内容 */
- u32 stack_actlen; /* 实际的堆栈长度(<=1024) */
- u8 stack_data[DATA_LEN_1K]; /* 超过1024部分,会被截断 */
-};
-
-/* 临终遗言信息 */
-#define XREGS_NUM 31
-struct tag_cpu_tick {
- u32 cnt_hi; /* *< cycle计数高32位 */
- u32 cnt_lo; /* *< cycle计数低32位 */
-};
-
-struct tag_ax_exc_reg_info {
- u64 ttbr0;
- u64 ttbr1;
- u64 tcr;
- u64 mair;
- u64 sctlr;
- u64 vbar;
- u64 current_el;
- u64 sp;
- /* 以下字段的内存布局与TskContext保持一致 */
- u64 elr; /* 返回地址 */
- u64 spsr;
- u64 far_r;
- u64 esr;
- u64 xzr;
- u64 xregs[XREGS_NUM]; /* 0~30: x30~x0 */
-};
-
-struct tag_exc_info {
- char os_ver[48]; /* *< OS版本号 */
- char app_ver[64]; /* *< 产品版本号 */
- u32 exc_cause; /* *< 异常原因 */
- u32 thread_type; /* *< 异常前的线程类型 */
- u32 thread_id; /* *< 异常前线程PID */
- u16 byte_order; /* *< 字节序 */
- u16 cpu_type; /* *< CPU类型 */
- u32 cpu_id; /* *< CPU ID */
- struct tag_cpu_tick cpu_tick; /* *< CPU Tick */
- u32 nest_cnt; /* *< 异常嵌套计数 */
- u32 fatal_errno; /* *< 致命错误码,发生致命错误时有效 */
- u64 uw_sp; /* *< 异常前栈指针 */
- u64 stack_bottom; /* *< 异常前栈底 */
- /* 异常发生时的核内寄存器上下文信息,82\57必须位于152字节处,
- * 若有改动,需更新sre_platform.eh中的OS_EXC_REGINFO_OFFSET宏
- */
- struct tag_ax_exc_reg_info reg_info;
-};
-
-/* 上报给驱动的up lastword模块接口 */
-#define MPU_LASTWORD_SIZE 1024
-struct tag_comm_info_up_lastword {
- struct comm_info_head head;
-
- struct tag_exc_info stack_info;
-
- /* 堆栈具体内容 */
- u32 stack_actlen; /* 实际的堆栈长度(<=1024) */
- u8 stack_data[MPU_LASTWORD_SIZE]; /* 超过1024部分,会被截断 */
-};
-
-#define FW_UPDATE_MGMT_TIMEOUT 3000000U
-
struct hinic3_cmd_update_firmware {
struct mgmt_msg_head msg_head;
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bat_cla.c b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bat_cla.c
new file mode 100644
index 0000000000000..2d2f54cbc5ee2
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bat_cla.c
@@ -0,0 +1,2056 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+
+#include "ossl_knl.h"
+#include "hinic3_crm.h"
+#include "hinic3_hw.h"
+#include "hinic3_hwdev.h"
+#include "hinic3_hwif.h"
+
+#include "cqm_object.h"
+#include "cqm_bitmap_table.h"
+#include "cqm_cmd.h"
+#include "cqm_object_intern.h"
+#include "cqm_main.h"
+#include "cqm_memsec.h"
+#include "cqm_bat_cla.h"
+
+#include "cqm_npu_cmd.h"
+#include "cqm_npu_cmd_defs.h"
+
+static void cqm_bat_fill_cla_common_gpa(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ struct tag_cqm_bat_entry_standerd *bat_entry_standerd)
+{
+ u8 gpa_check_enable = cqm_handle->func_capability.gpa_check_enable;
+ struct hinic3_func_attr *func_attr = NULL;
+ struct tag_cqm_bat_entry_vf2pf gpa = {0};
+ u32 cla_gpa_h = 0;
+ dma_addr_t pa;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ if (cla_table->cla_lvl == CQM_CLA_LVL_0)
+ pa = cla_table->cla_z_buf.buf_list[0].pa;
+ else if (cla_table->cla_lvl == CQM_CLA_LVL_1)
+ pa = cla_table->cla_y_buf.buf_list[0].pa;
+ else
+ pa = cla_table->cla_x_buf.buf_list[0].pa;
+
+ gpa.cla_gpa_h = CQM_ADDR_HI(pa) & CQM_CHIP_GPA_HIMASK;
+
+ /* On the SPU, the value of spu_en in the GPA address
+ * in the BAT is determined by the host ID and fun IDx.
+ */
+ if (hinic3_host_id(cqm_handle->ex_handle) == CQM_SPU_HOST_ID) {
+ func_attr = &cqm_handle->func_attribute;
+ gpa.acs_spu_en = func_attr->func_global_idx & 0x1;
+ } else {
+ gpa.acs_spu_en = 0;
+ }
+
+ /* In fake mode, fake_vf_en in the GPA address of the BAT
+ * must be set to 1.
+ */
+ if (cqm_handle->func_capability.fake_func_type == CQM_FAKE_FUNC_CHILD) {
+ gpa.fake_vf_en = 1;
+ func_attr = &cqm_handle->parent_cqm_handle->func_attribute;
+ gpa.pf_id = func_attr->func_global_idx;
+ } else {
+ gpa.fake_vf_en = 0;
+ }
+
+ memcpy(&cla_gpa_h, &gpa, sizeof(u32));
+ bat_entry_standerd->cla_gpa_h = cla_gpa_h;
+
+ /* GPA is valid when gpa[0] = 1.
+ * CQM_BAT_ENTRY_T_REORDER does not support GPA validity check.
+ */
+ if (cla_table->type == CQM_BAT_ENTRY_T_REORDER)
+ bat_entry_standerd->cla_gpa_l = CQM_ADDR_LW(pa);
+ else
+ bat_entry_standerd->cla_gpa_l = CQM_ADDR_LW(pa) |
+ gpa_check_enable;
+
+ cqm_info(handle->dev_hdl, "Cla type %u, pa 0x%llx, gpa 0x%x-0x%x, level %u\n",
+ cla_table->type, pa, bat_entry_standerd->cla_gpa_h, bat_entry_standerd->cla_gpa_l,
+ bat_entry_standerd->cla_level);
+}
+
+static void cqm_bat_fill_cla_common(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ u8 *entry_base_addr)
+{
+ struct tag_cqm_bat_entry_standerd *bat_entry_standerd = NULL;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 cache_line = 0;
+
+ /* The cacheline of the timer is changed to 512. */
+ if (cla_table->type == CQM_BAT_ENTRY_T_TIMER)
+ cache_line = CQM_CHIP_TIMER_CACHELINE;
+ else
+ cache_line = CQM_CHIP_CACHELINE;
+
+ if (cla_table->obj_num == 0) {
+ cqm_info(handle->dev_hdl,
+ "Cla alloc: cla_type %u, obj_num=0, don't init bat entry\n",
+ cla_table->type);
+ return;
+ }
+
+ bat_entry_standerd = (struct tag_cqm_bat_entry_standerd *)entry_base_addr;
+
+ /* The QPC value is 256/512/1024 and the timer value is 512.
+ * The other cacheline value is 256B.
+ * The conversion operation is performed inside the chip.
+ */
+ if (cla_table->obj_size > cache_line) {
+ if (cla_table->obj_size == CQM_OBJECT_512)
+ bat_entry_standerd->entry_size = CQM_BAT_ENTRY_SIZE_512;
+ else
+ bat_entry_standerd->entry_size =
+ CQM_BAT_ENTRY_SIZE_1024;
+ bat_entry_standerd->max_number = cla_table->max_buffer_size /
+ cla_table->obj_size;
+ } else {
+ if (cache_line == CQM_CHIP_CACHELINE) {
+ bat_entry_standerd->entry_size = CQM_BAT_ENTRY_SIZE_256;
+ bat_entry_standerd->max_number =
+ cla_table->max_buffer_size / cache_line;
+ } else {
+ bat_entry_standerd->entry_size = CQM_BAT_ENTRY_SIZE_512;
+ bat_entry_standerd->max_number =
+ cla_table->max_buffer_size / cache_line;
+ }
+ }
+
+ bat_entry_standerd->max_number = bat_entry_standerd->max_number - 1;
+
+ bat_entry_standerd->bypass = CQM_BAT_NO_BYPASS_CACHE;
+ bat_entry_standerd->z = cla_table->cacheline_z;
+ bat_entry_standerd->y = cla_table->cacheline_y;
+ bat_entry_standerd->x = cla_table->cacheline_x;
+ bat_entry_standerd->cla_level = cla_table->cla_lvl;
+
+ cqm_bat_fill_cla_common_gpa(cqm_handle, cla_table, bat_entry_standerd);
+}
+
+static void cqm_bat_fill_cla_cfg(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ u8 **entry_base_addr)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct tag_cqm_bat_entry_cfg *bat_entry_cfg = NULL;
+
+ bat_entry_cfg = (struct tag_cqm_bat_entry_cfg *)(*entry_base_addr);
+ bat_entry_cfg->cur_conn_cache = 0;
+ bat_entry_cfg->max_conn_cache =
+ func_cap->flow_table_based_conn_cache_number;
+ bat_entry_cfg->cur_conn_num_h_4 = 0;
+ bat_entry_cfg->cur_conn_num_l_16 = 0;
+ bat_entry_cfg->max_conn_num = func_cap->flow_table_based_conn_number;
+
+ /* Aligns with 64 buckets and shifts rightward by 6 bits.
+ * The maximum value of this field is 16 bits. A maximum of 4M buckets
+ * can be supported. The value is subtracted by 1. It is used for &hash
+ * value.
+ */
+ if ((func_cap->hash_number >> CQM_HASH_NUMBER_UNIT) != 0) {
+ bat_entry_cfg->bucket_num = ((func_cap->hash_number >>
+ CQM_HASH_NUMBER_UNIT) - 1);
+ }
+ if (func_cap->bloomfilter_length != 0) {
+ bat_entry_cfg->bloom_filter_len = func_cap->bloomfilter_length -
+ 1;
+ bat_entry_cfg->bloom_filter_addr = func_cap->bloomfilter_addr;
+ }
+
+ (*entry_base_addr) += sizeof(struct tag_cqm_bat_entry_cfg);
+}
+
+static void cqm_bat_fill_cla_other(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ u8 **entry_base_addr)
+{
+ cqm_bat_fill_cla_common(cqm_handle, cla_table, *entry_base_addr);
+
+ (*entry_base_addr) += sizeof(struct tag_cqm_bat_entry_standerd);
+}
+
+static void cqm_bat_fill_cla_taskmap(struct tag_cqm_handle *cqm_handle,
+ const struct tag_cqm_cla_table *cla_table,
+ u8 **entry_base_addr)
+{
+ struct tag_cqm_bat_entry_taskmap *bat_entry_taskmap = NULL;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ int i;
+
+ if (cqm_handle->func_capability.taskmap_number != 0) {
+ bat_entry_taskmap =
+ (struct tag_cqm_bat_entry_taskmap *)(*entry_base_addr);
+ for (i = 0; i < CQM_BAT_ENTRY_TASKMAP_NUM; i++) {
+ bat_entry_taskmap->addr[i].gpa_h =
+ (u32)(cla_table->cla_z_buf.buf_list[i].pa >>
+ CQM_CHIP_GPA_HSHIFT);
+ bat_entry_taskmap->addr[i].gpa_l =
+ (u32)(cla_table->cla_z_buf.buf_list[i].pa &
+ CQM_CHIP_GPA_LOMASK);
+ cqm_info(handle->dev_hdl,
+ "Cla alloc: taskmap bat entry: 0x%x 0x%x\n",
+ bat_entry_taskmap->addr[i].gpa_h,
+ bat_entry_taskmap->addr[i].gpa_l);
+ }
+ }
+
+ (*entry_base_addr) += sizeof(struct tag_cqm_bat_entry_taskmap);
+}
+
+static void cqm_bat_fill_cla_timer(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ u8 **entry_base_addr)
+{
+ /* Only the PPF allocates timer resources. */
+ if (cqm_handle->func_attribute.func_type != CQM_PPF) {
+ (*entry_base_addr) += CQM_BAT_ENTRY_SIZE;
+ } else {
+ cqm_bat_fill_cla_common(cqm_handle, cla_table,
+ *entry_base_addr);
+
+ (*entry_base_addr) += sizeof(struct tag_cqm_bat_entry_standerd);
+ }
+}
+
+static void cqm_bat_fill_cla_invalid(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ u8 **entry_base_addr)
+{
+ (*entry_base_addr) += CQM_BAT_ENTRY_SIZE;
+}
+
+/**
+ * Prototype : cqm_bat_fill_cla
+ * Description : Fill the base address of the CLA table into the BAT table.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+static void cqm_bat_fill_cla(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ u32 entry_type = CQM_BAT_ENTRY_T_INVALID;
+ u8 *entry_base_addr = NULL;
+ u32 i = 0;
+
+ /* Fills each item in the BAT table according to the BAT format. */
+ entry_base_addr = bat_table->bat;
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ cqm_dbg("entry_base_addr = %p\n", entry_base_addr);
+ entry_type = bat_table->bat_entry_type[i];
+ cla_table = &bat_table->entry[i];
+
+ if (entry_type == CQM_BAT_ENTRY_T_CFG) {
+ cqm_bat_fill_cla_cfg(cqm_handle, cla_table, &entry_base_addr);
+ } else if (entry_type == CQM_BAT_ENTRY_T_TASKMAP) {
+ cqm_bat_fill_cla_taskmap(cqm_handle, cla_table, &entry_base_addr);
+ } else if (entry_type == CQM_BAT_ENTRY_T_INVALID) {
+ cqm_bat_fill_cla_invalid(cqm_handle, cla_table, &entry_base_addr);
+ } else if (entry_type == CQM_BAT_ENTRY_T_TIMER) {
+ if (cqm_handle->func_attribute.func_type == CQM_PPF &&
+ (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_1 ||
+ cqm_handle->func_capability.lb_mode == CQM_LB_MODE_2)) {
+ entry_base_addr += sizeof(struct tag_cqm_bat_entry_standerd);
+ continue;
+ }
+
+ cqm_bat_fill_cla_timer(cqm_handle, cla_table,
+ &entry_base_addr);
+ } else {
+ cqm_bat_fill_cla_other(cqm_handle, cla_table, &entry_base_addr);
+ }
+
+ /* Check whether entry_base_addr is out-of-bounds array. */
+ if (entry_base_addr >=
+ (bat_table->bat + CQM_BAT_ENTRY_MAX * CQM_BAT_ENTRY_SIZE))
+ break;
+ }
+}
+
+u32 cqm_funcid2smfid(const struct tag_cqm_handle *cqm_handle)
+{
+ u32 funcid = 0;
+ u32 smf_sel = 0;
+ u32 smf_id = 0;
+ u32 smf_pg_partial = 0;
+ /* SMF_Selection is selected based on
+ * the lower two bits of the function id
+ */
+ u32 lbf_smfsel[4] = {0, 2, 1, 3};
+ /* SMFID is selected based on SMF_PG[1:0] and SMF_Selection(0-1) */
+ u32 smfsel_smfid01[4][2] = { {0, 0}, {0, 0}, {1, 1}, {0, 1} };
+ /* SMFID is selected based on SMF_PG[3:2] and SMF_Selection(2-4) */
+ u32 smfsel_smfid23[4][2] = { {2, 2}, {2, 2}, {3, 3}, {2, 3} };
+
+ /* When the LB mode is disabled, SMF0 is always returned. */
+ if (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_NORMAL) {
+ smf_id = 0;
+ } else {
+ funcid = cqm_handle->func_attribute.func_global_idx & 0x3;
+ smf_sel = lbf_smfsel[funcid];
+
+ if (smf_sel < 0x2) {
+ smf_pg_partial = cqm_handle->func_capability.smf_pg &
+ 0x3;
+ smf_id = smfsel_smfid01[smf_pg_partial][smf_sel];
+ } else {
+ smf_pg_partial =
+ /* shift to right by 2 bits */
+ (cqm_handle->func_capability.smf_pg >> 2) & 0x3;
+ smf_id = smfsel_smfid23[smf_pg_partial][smf_sel - 0x2];
+ }
+ }
+
+ return smf_id;
+}
+
+/* This function is used in LB mode 1/2. The timer spoker info
+ * of independent space needs to be configured for 4 SMFs.
+ */
+static void cqm_update_timer_gpa(struct tag_cqm_handle *cqm_handle, u32 smf_id)
+{
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ u32 entry_type = CQM_BAT_ENTRY_T_INVALID;
+ u8 *entry_base_addr = NULL;
+ u32 i = 0;
+
+ if (cqm_handle->func_attribute.func_type != CQM_PPF)
+ return;
+
+ if (cqm_handle->func_capability.lb_mode != CQM_LB_MODE_1 &&
+ cqm_handle->func_capability.lb_mode != CQM_LB_MODE_2)
+ return;
+
+ cla_table = &bat_table->timer_entry[smf_id];
+ entry_base_addr = bat_table->bat;
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ entry_type = bat_table->bat_entry_type[i];
+
+ if (entry_type == CQM_BAT_ENTRY_T_TIMER) {
+ cqm_bat_fill_cla_timer(cqm_handle, cla_table,
+ &entry_base_addr);
+ break;
+ }
+
+ if (entry_type == CQM_BAT_ENTRY_T_TASKMAP)
+ entry_base_addr += sizeof(struct tag_cqm_bat_entry_taskmap);
+ else
+ entry_base_addr += CQM_BAT_ENTRY_SIZE;
+
+ /* Check whether entry_base_addr is out-of-bounds array. */
+ if (entry_base_addr >=
+ (bat_table->bat + CQM_BAT_ENTRY_MAX * CQM_BAT_ENTRY_SIZE))
+ break;
+ }
+}
+
+static s32 cqm_bat_update_cmd(struct tag_cqm_handle *cqm_handle, struct tag_cqm_cmd_buf *buf_in,
+ u32 smf_id, u32 func_id)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_cmdq_bat_update *bat_update_cmd = NULL;
+ s32 ret = CQM_FAIL;
+
+ bat_update_cmd = (struct tag_cqm_cmdq_bat_update *)(buf_in->buf);
+ bat_update_cmd->offset = 0;
+
+ if (cqm_handle->bat_table.bat_size > CQM_BAT_MAX_SIZE) {
+ cqm_err(handle->dev_hdl,
+ "bat_size = %u, which is more than %d.\n",
+ cqm_handle->bat_table.bat_size, CQM_BAT_MAX_SIZE);
+ return CQM_FAIL;
+ }
+ bat_update_cmd->byte_len = cqm_handle->bat_table.bat_size;
+
+ memcpy(bat_update_cmd->data, cqm_handle->bat_table.bat, bat_update_cmd->byte_len);
+
+#ifdef __CQM_DEBUG__
+ cqm_byte_print((u32 *)(cqm_handle->bat_table.bat),
+ CQM_BAT_ENTRY_MAX * CQM_BAT_ENTRY_SIZE);
+#endif
+
+ bat_update_cmd->smf_id = smf_id;
+ bat_update_cmd->func_id = func_id;
+
+ cqm_info(handle->dev_hdl, "Bat update: smf_id=%u\n",
+ bat_update_cmd->smf_id);
+ cqm_info(handle->dev_hdl, "Bat update: func_id=%u\n",
+ bat_update_cmd->func_id);
+
+ cqm_swab32((u8 *)bat_update_cmd,
+ sizeof(struct tag_cqm_cmdq_bat_update) >> CQM_DW_SHIFT);
+
+ ret = cqm_send_cmd_box((void *)(cqm_handle->ex_handle), CQM_MOD_CQM,
+ CQM_CMD_T_BAT_UPDATE, buf_in, NULL, NULL,
+ CQM_CMD_TIMEOUT, HINIC3_CHANNEL_DEFAULT);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_send_cmd_box));
+ cqm_err(handle->dev_hdl, "%s: send_cmd_box ret=%d\n", __func__,
+ ret);
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_bat_update
+ * Description : Send a command to tile to update the BAT table through cmdq.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+static s32 cqm_bat_update(struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_cmd_buf *buf_in = NULL;
+ s32 ret = CQM_FAIL;
+ u32 smf_id = 0;
+ u32 func_id = 0;
+ u32 i = 0;
+
+ buf_in = cqm_cmd_alloc((void *)(cqm_handle->ex_handle));
+ if (!buf_in)
+ return CQM_FAIL;
+ buf_in->size = sizeof(struct tag_cqm_cmdq_bat_update);
+
+ /* In non-fake mode, func_id is set to 0xffff, indicating the current
+ * func. In fake mode, the value of func_id is specified. This is a fake
+ * func_id.
+ */
+ if (cqm_handle->func_capability.fake_func_type == CQM_FAKE_FUNC_CHILD)
+ func_id = cqm_handle->func_attribute.func_global_idx;
+ else
+ func_id = 0xffff;
+
+ /* The LB scenario is supported.
+ * The normal mode is the traditional mode and is configured on SMF0.
+ * In mode 0, load is balanced to four SMFs based on the func ID (except
+ * the PPF func ID). The PPF in mode 0 needs to be configured on four
+ * SMF, so the timer resources can be shared by the four timer engine.
+ * Mode 1/2 is load balanced to four SMF by flow. Therefore, one
+ * function needs to be configured to four SMF.
+ */
+ if (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_NORMAL ||
+ (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_0 &&
+ cqm_handle->func_attribute.func_type != CQM_PPF)) {
+ smf_id = cqm_funcid2smfid(cqm_handle);
+ ret = cqm_bat_update_cmd(cqm_handle, buf_in, smf_id, func_id);
+ } else if ((cqm_handle->func_capability.lb_mode == CQM_LB_MODE_1) ||
+ (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_2) ||
+ ((cqm_handle->func_capability.lb_mode == CQM_LB_MODE_0) &&
+ (cqm_handle->func_attribute.func_type == CQM_PPF))) {
+ for (i = 0; i < CQM_LB_SMF_MAX; i++) {
+ cqm_update_timer_gpa(cqm_handle, i);
+
+ /* The smf_pg variable stores the currently
+ * enabled SMF.
+ */
+ if (cqm_handle->func_capability.smf_pg & (1U << i)) {
+ smf_id = i;
+ ret = cqm_bat_update_cmd(cqm_handle, buf_in,
+ smf_id, func_id);
+ if (ret != CQM_SUCCESS)
+ goto out;
+ }
+ }
+ } else {
+ cqm_err(handle->dev_hdl, "Bat update: unsupport lb mode=%u\n",
+ cqm_handle->func_capability.lb_mode);
+ ret = CQM_FAIL;
+ }
+
+out:
+ cqm_cmd_free((void *)(cqm_handle->ex_handle), buf_in);
+ return ret;
+}
+
+static s32 cqm_bat_init_ft(struct tag_cqm_handle *cqm_handle, struct tag_cqm_bat_table *bat_table,
+ enum func_type function_type)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 i = 0;
+
+ bat_table->bat_entry_type[CQM_BAT_INDEX0] = CQM_BAT_ENTRY_T_CFG;
+ bat_table->bat_entry_type[CQM_BAT_INDEX1] = CQM_BAT_ENTRY_T_HASH;
+ bat_table->bat_entry_type[CQM_BAT_INDEX2] = CQM_BAT_ENTRY_T_QPC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX3] = CQM_BAT_ENTRY_T_SCQC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX4] = CQM_BAT_ENTRY_T_LUN;
+ bat_table->bat_entry_type[CQM_BAT_INDEX5] = CQM_BAT_ENTRY_T_TASKMAP;
+
+ if (function_type == CQM_PF || function_type == CQM_PPF) {
+ bat_table->bat_entry_type[CQM_BAT_INDEX6] = CQM_BAT_ENTRY_T_L3I;
+ bat_table->bat_entry_type[CQM_BAT_INDEX7] = CQM_BAT_ENTRY_T_CHILDC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX8] = CQM_BAT_ENTRY_T_TIMER;
+ bat_table->bat_entry_type[CQM_BAT_INDEX9] = CQM_BAT_ENTRY_T_XID2CID;
+ bat_table->bat_entry_type[CQM_BAT_INDEX10] = CQM_BAT_ENTRY_T_REORDER;
+ bat_table->bat_size = CQM_BAT_SIZE_FT_PF;
+ } else if (function_type == CQM_VF) {
+ bat_table->bat_size = CQM_BAT_SIZE_FT_VF;
+ } else {
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++)
+ bat_table->bat_entry_type[i] = CQM_BAT_ENTRY_T_INVALID;
+
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(function_type));
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_bat_init_rdma(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_bat_table *bat_table,
+ enum func_type function_type)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 i = 0;
+
+ bat_table->bat_entry_type[CQM_BAT_INDEX0] = CQM_BAT_ENTRY_T_QPC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX1] = CQM_BAT_ENTRY_T_SCQC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX2] = CQM_BAT_ENTRY_T_SRQC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX3] = CQM_BAT_ENTRY_T_MPT;
+ bat_table->bat_entry_type[CQM_BAT_INDEX4] = CQM_BAT_ENTRY_T_GID;
+
+ if (function_type == CQM_PF || function_type == CQM_PPF) {
+ bat_table->bat_entry_type[CQM_BAT_INDEX5] = CQM_BAT_ENTRY_T_L3I;
+ bat_table->bat_entry_type[CQM_BAT_INDEX6] =
+ CQM_BAT_ENTRY_T_CHILDC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX7] =
+ CQM_BAT_ENTRY_T_TIMER;
+ bat_table->bat_entry_type[CQM_BAT_INDEX8] =
+ CQM_BAT_ENTRY_T_XID2CID;
+ bat_table->bat_entry_type[CQM_BAT_INDEX9] =
+ CQM_BAT_ENTRY_T_REORDER;
+ bat_table->bat_size = CQM_BAT_SIZE_RDMA_PF;
+ } else if (function_type == CQM_VF) {
+ bat_table->bat_size = CQM_BAT_SIZE_RDMA_VF;
+ } else {
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++)
+ bat_table->bat_entry_type[i] = CQM_BAT_ENTRY_T_INVALID;
+
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(function_type));
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_bat_init_ft_rdma(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_bat_table *bat_table,
+ enum func_type function_type)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 i = 0;
+
+ bat_table->bat_entry_type[CQM_BAT_INDEX0] = CQM_BAT_ENTRY_T_CFG;
+ bat_table->bat_entry_type[CQM_BAT_INDEX1] = CQM_BAT_ENTRY_T_HASH;
+ bat_table->bat_entry_type[CQM_BAT_INDEX2] = CQM_BAT_ENTRY_T_QPC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX3] = CQM_BAT_ENTRY_T_SCQC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX4] = CQM_BAT_ENTRY_T_SRQC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX5] = CQM_BAT_ENTRY_T_MPT;
+ bat_table->bat_entry_type[CQM_BAT_INDEX6] = CQM_BAT_ENTRY_T_GID;
+ bat_table->bat_entry_type[CQM_BAT_INDEX7] = CQM_BAT_ENTRY_T_LUN;
+ bat_table->bat_entry_type[CQM_BAT_INDEX8] = CQM_BAT_ENTRY_T_TASKMAP;
+
+ if (function_type == CQM_PF || function_type == CQM_PPF) {
+ bat_table->bat_entry_type[CQM_BAT_INDEX9] = CQM_BAT_ENTRY_T_L3I;
+ bat_table->bat_entry_type[CQM_BAT_INDEX10] =
+ CQM_BAT_ENTRY_T_CHILDC;
+ bat_table->bat_entry_type[CQM_BAT_INDEX11] =
+ CQM_BAT_ENTRY_T_TIMER;
+ bat_table->bat_entry_type[CQM_BAT_INDEX12] =
+ CQM_BAT_ENTRY_T_XID2CID;
+ bat_table->bat_entry_type[CQM_BAT_INDEX13] =
+ CQM_BAT_ENTRY_T_REORDER;
+ bat_table->bat_size = CQM_BAT_SIZE_FT_RDMA_PF;
+ } else if (function_type == CQM_VF) {
+ bat_table->bat_size = CQM_BAT_SIZE_FT_RDMA_VF;
+ } else {
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++)
+ bat_table->bat_entry_type[i] = CQM_BAT_ENTRY_T_INVALID;
+
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(function_type));
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_bat_init
+ * Description : Initialize the BAT table. Only the items to be initialized and
+ * the entry sequence are selected. The content of the BAT entry
+ * is filled after the CLA is allocated.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+s32 cqm_bat_init(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_func_capability *capability = &cqm_handle->func_capability;
+ enum func_type function_type = cqm_handle->func_attribute.func_type;
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ u32 i;
+
+ memset(bat_table, 0, sizeof(struct tag_cqm_bat_table));
+
+ /* Initialize the type of each bat entry. */
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++)
+ bat_table->bat_entry_type[i] = CQM_BAT_ENTRY_T_INVALID;
+
+ /* Select BATs based on service types. Currently,
+ * feature-related resources of the VF are stored in the BATs of the VF.
+ */
+ if (capability->ft_enable && capability->rdma_enable)
+ return cqm_bat_init_ft_rdma(cqm_handle, bat_table, function_type);
+ else if (capability->ft_enable)
+ return cqm_bat_init_ft(cqm_handle, bat_table, function_type);
+ else if (capability->rdma_enable)
+ return cqm_bat_init_rdma(cqm_handle, bat_table, function_type);
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_bat_uninit
+ * Description : Deinitialize the BAT table.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+void cqm_bat_uninit(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 i;
+
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++)
+ bat_table->bat_entry_type[i] = CQM_BAT_ENTRY_T_INVALID;
+
+ memset(bat_table->bat, 0, CQM_BAT_ENTRY_MAX * CQM_BAT_ENTRY_SIZE);
+
+ /* Instruct the chip to update the BAT table. */
+ if (cqm_bat_update(cqm_handle) != CQM_SUCCESS)
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_bat_update));
+}
+
+static s32 cqm_cla_fill_buf(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *cla_base_buf,
+ struct tag_cqm_buf *cla_sub_buf, u8 gpa_check_enable)
+{
+ struct hinic3_func_attr *func_attr = NULL;
+ dma_addr_t *base = NULL;
+ u64 fake_en = 0;
+ u64 spu_en = 0;
+ u64 pf_id = 0;
+ u32 i = 0;
+ u32 addr_num;
+ u32 buf_index = 0;
+
+ /* Apply for space for base_buf */
+ if (!cla_base_buf->buf_list) {
+ if (cqm_buf_alloc(cqm_handle, cla_base_buf, false) == CQM_FAIL)
+ return CQM_FAIL;
+ }
+
+ /* Apply for space for sub_buf */
+ if (!cla_sub_buf->buf_list) {
+ if (cqm_buf_alloc(cqm_handle, cla_sub_buf, false) == CQM_FAIL) {
+ cqm_buf_free(cla_base_buf, cqm_handle);
+ return CQM_FAIL;
+ }
+ }
+
+ /* Fill base_buff with the gpa of sub_buf */
+ addr_num = cla_base_buf->buf_size / sizeof(dma_addr_t);
+ base = (dma_addr_t *)(cla_base_buf->buf_list[0].va);
+ for (i = 0; i < cla_sub_buf->buf_number; i++) {
+ /* The SPU SMF supports load balancing from the SMF to the CPI,
+ * depending on the host ID and func ID.
+ */
+ if (hinic3_host_id(cqm_handle->ex_handle) == CQM_SPU_HOST_ID) {
+ func_attr = &cqm_handle->func_attribute;
+ spu_en = (u64)(func_attr->func_global_idx & 0x1) << 0x3F;
+ } else {
+ spu_en = 0;
+ }
+
+ /* fake enable */
+ if (cqm_handle->func_capability.fake_func_type ==
+ CQM_FAKE_FUNC_CHILD) {
+ fake_en = 1ULL << 0x3E;
+ func_attr =
+ &cqm_handle->parent_cqm_handle->func_attribute;
+ pf_id = func_attr->func_global_idx;
+ pf_id = (pf_id & 0x1f) << 0x39;
+ } else {
+ fake_en = 0;
+ pf_id = 0;
+ }
+
+ *base = (dma_addr_t)((((((u64)(cla_sub_buf->buf_list[i].pa) & CQM_CHIP_GPA_MASK) |
+ spu_en) |
+ fake_en) |
+ pf_id) |
+ gpa_check_enable);
+
+ cqm_swab64((u8 *)base, 1);
+ if ((i + 1) % addr_num == 0) {
+ buf_index++;
+ if (buf_index < cla_base_buf->buf_number)
+ base = cla_base_buf->buf_list[buf_index].va;
+ } else {
+ base++;
+ }
+ }
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_cla_xyz_lvl1(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ u32 trunk_size)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_buf *cla_y_buf = NULL;
+ struct tag_cqm_buf *cla_z_buf = NULL;
+ s32 shift = 0;
+ s32 ret = CQM_FAIL;
+ u8 gpa_check_enable = cqm_handle->func_capability.gpa_check_enable;
+ u32 cache_line = 0;
+
+ /* The cacheline of the timer is changed to 512. */
+ if (cla_table->type == CQM_BAT_ENTRY_T_TIMER)
+ cache_line = CQM_CHIP_TIMER_CACHELINE;
+ else
+ cache_line = CQM_CHIP_CACHELINE;
+
+ if (cla_table->type == CQM_BAT_ENTRY_T_REORDER)
+ gpa_check_enable = 0;
+
+ cla_table->cla_lvl = CQM_CLA_LVL_1;
+
+ shift = cqm_shift(trunk_size / cla_table->obj_size);
+ cla_table->z = (u32)(shift ? (shift - 1) : (shift));
+ cla_table->y = CQM_MAX_INDEX_BIT;
+ cla_table->x = 0;
+
+ cqm_dbg("cla_table->obj_size = %d, cache_line = %d",
+ cla_table->obj_size, cache_line);
+ if (cla_table->obj_size >= cache_line) {
+ cla_table->cacheline_z = cla_table->z;
+ cla_table->cacheline_y = cla_table->y;
+ cla_table->cacheline_x = cla_table->x;
+ } else {
+ shift = cqm_shift(trunk_size / cache_line);
+ cla_table->cacheline_z = (u32)(shift ? (shift - 1) : (shift));
+ cla_table->cacheline_y = CQM_MAX_INDEX_BIT;
+ cla_table->cacheline_x = 0;
+ }
+
+ /* Applying for CLA_Y_BUF Space */
+ cla_y_buf = &cla_table->cla_y_buf;
+ cla_y_buf->buf_size = trunk_size;
+ cla_y_buf->buf_number = 1;
+ cla_y_buf->page_number = cla_y_buf->buf_number <<
+ cla_table->trunk_order;
+
+ ret = cqm_buf_alloc(cqm_handle, cla_y_buf, false);
+ if (ret != CQM_SUCCESS)
+ return CQM_FAIL;
+
+ /* Applying for CLA_Z_BUF Space */
+ cla_z_buf = &cla_table->cla_z_buf;
+ cla_z_buf->buf_size = trunk_size;
+ cla_z_buf->buf_number = (ALIGN(cla_table->max_buffer_size, trunk_size)) / trunk_size;
+ cla_z_buf->page_number = cla_z_buf->buf_number << cla_table->trunk_order;
+
+ /* All buffer space must be statically allocated. */
+ if (cla_table->alloc_static) {
+ ret = cqm_cla_fill_buf(cqm_handle, cla_y_buf, cla_z_buf,
+ gpa_check_enable);
+ if (unlikely(ret != CQM_SUCCESS)) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_fill_buf));
+ return CQM_FAIL;
+ }
+ } else { /* Only the buffer list space is initialized. The buffer space
+ * is dynamically allocated in services.
+ */
+ cla_z_buf->buf_list = vmalloc(cla_z_buf->buf_number *
+ sizeof(struct tag_cqm_buf_list));
+ if (!cla_z_buf->buf_list) {
+ cqm_buf_free(cla_y_buf, cqm_handle);
+ return CQM_FAIL;
+ }
+ memset(cla_z_buf->buf_list, 0,
+ cla_z_buf->buf_number * sizeof(struct tag_cqm_buf_list));
+ }
+
+ return CQM_SUCCESS;
+}
+
+static void cqm_cla_xyz_lvl2_param_init(struct tag_cqm_cla_table *cla_table, u32 trunk_size)
+{
+ s32 shift = 0;
+ u32 cache_line = 0;
+
+ /* The cacheline of the timer is changed to 512. */
+ if (cla_table->type == CQM_BAT_ENTRY_T_TIMER)
+ cache_line = CQM_CHIP_TIMER_CACHELINE;
+ else
+ cache_line = CQM_CHIP_CACHELINE;
+
+ cla_table->cla_lvl = CQM_CLA_LVL_2;
+
+ shift = cqm_shift(trunk_size / cla_table->obj_size);
+ cla_table->z = (u32)(shift ? (shift - 1) : (shift));
+ shift = cqm_shift(trunk_size / sizeof(dma_addr_t));
+ cla_table->y = cla_table->z + shift;
+ cla_table->x = CQM_MAX_INDEX_BIT;
+
+ if (cla_table->obj_size >= cache_line) {
+ cla_table->cacheline_z = cla_table->z;
+ cla_table->cacheline_y = cla_table->y;
+ cla_table->cacheline_x = cla_table->x;
+ } else {
+ shift = cqm_shift(trunk_size / cache_line);
+ cla_table->cacheline_z = (u32)(shift ? (shift - 1) : (shift));
+ shift = cqm_shift(trunk_size / sizeof(dma_addr_t));
+ cla_table->cacheline_y = cla_table->cacheline_z + shift;
+ cla_table->cacheline_x = CQM_MAX_INDEX_BIT;
+ }
+}
+
+static s32 cqm_cla_xyz_lvl2_xyz_apply(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table, u32 trunk_size)
+{
+ struct tag_cqm_buf *cla_x_buf = NULL;
+ struct tag_cqm_buf *cla_y_buf = NULL;
+ struct tag_cqm_buf *cla_z_buf = NULL;
+ s32 ret = CQM_FAIL;
+
+ /* Apply for CLA_X_BUF Space */
+ cla_x_buf = &cla_table->cla_x_buf;
+ cla_x_buf->buf_size = trunk_size;
+ cla_x_buf->buf_number = 1;
+ cla_x_buf->page_number = cla_x_buf->buf_number << cla_table->trunk_order;
+ ret = cqm_buf_alloc(cqm_handle, cla_x_buf, false);
+ if (ret != CQM_SUCCESS)
+ return CQM_FAIL;
+
+ /* Apply for CLA_Z_BUF and CLA_Y_BUF Space */
+ cla_z_buf = &cla_table->cla_z_buf;
+ cla_z_buf->buf_size = trunk_size;
+ cla_z_buf->buf_number = (ALIGN(cla_table->max_buffer_size, trunk_size)) / trunk_size;
+ cla_z_buf->page_number = cla_z_buf->buf_number << cla_table->trunk_order;
+
+ cla_y_buf = &cla_table->cla_y_buf;
+ cla_y_buf->buf_size = trunk_size;
+ cla_y_buf->buf_number =
+ (u32)(ALIGN(cla_z_buf->buf_number * sizeof(dma_addr_t), trunk_size)) / trunk_size;
+ cla_y_buf->page_number = cla_y_buf->buf_number << cla_table->trunk_order;
+
+ return 0;
+}
+
+static s32 cqm_cla_xyz_vram_name_init(struct tag_cqm_cla_table *cla_table,
+ struct hinic3_hwdev *handle)
+{
+ struct tag_cqm_buf *cla_x_buf = NULL;
+ struct tag_cqm_buf *cla_y_buf = NULL;
+ struct tag_cqm_buf *cla_z_buf = NULL;
+
+ cla_x_buf = &cla_table->cla_x_buf;
+ cla_z_buf = &cla_table->cla_z_buf;
+ cla_y_buf = &cla_table->cla_y_buf;
+ snprintf(cla_x_buf->buf_info.buf_vram_name,
+ VRAM_NAME_MAX_LEN - 1, "%s%s", cla_table->name, VRAM_CQM_CLA_COORD_X);
+
+ snprintf(cla_y_buf->buf_info.buf_vram_name,
+ VRAM_NAME_MAX_LEN - 1, "%s%s", cla_table->name, VRAM_CQM_CLA_COORD_Y);
+
+ snprintf(cla_z_buf->buf_info.buf_vram_name,
+ VRAM_NAME_MAX_LEN - 1, "%s%s", cla_table->name, VRAM_CQM_CLA_COORD_Z);
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_cla_xyz_lvl2(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table, u32 trunk_size)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_buf *cla_x_buf = NULL;
+ struct tag_cqm_buf *cla_y_buf = NULL;
+ struct tag_cqm_buf *cla_z_buf = NULL;
+ s32 ret = CQM_FAIL;
+ u8 gpa_check_enable = cqm_handle->func_capability.gpa_check_enable;
+
+ cqm_cla_xyz_lvl2_param_init(cla_table, trunk_size);
+
+ ret = cqm_cla_xyz_lvl2_xyz_apply(cqm_handle, cla_table, trunk_size);
+ if (ret)
+ return ret;
+
+ cla_x_buf = &cla_table->cla_x_buf;
+ cla_z_buf = &cla_table->cla_z_buf;
+ cla_y_buf = &cla_table->cla_y_buf;
+
+ if (cla_table->type == CQM_BAT_ENTRY_T_REORDER)
+ gpa_check_enable = 0;
+
+ /* All buffer space must be statically allocated. */
+ if (cla_table->alloc_static) {
+ /* Apply for y buf and z buf, and fill the gpa of z buf list in y buf */
+ if (cqm_cla_fill_buf(cqm_handle, cla_y_buf, cla_z_buf,
+ gpa_check_enable) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_fill_buf));
+ cqm_buf_free(cla_x_buf, cqm_handle);
+ return CQM_FAIL;
+ }
+
+ /* Fill the gpa of the y buf list into the x buf.
+ * After the x and y bufs are applied for, this function will not fail.
+ * Use void to forcibly convert the return of the function.
+ */
+ (void)cqm_cla_fill_buf(cqm_handle, cla_x_buf, cla_y_buf, gpa_check_enable);
+ } else { /* Only the buffer list space is initialized. The buffer space
+ * is dynamically allocated in services.
+ */
+ cla_z_buf->buf_list = vmalloc(cla_z_buf->buf_number *
+ sizeof(struct tag_cqm_buf_list));
+ if (!cla_z_buf->buf_list) {
+ cqm_buf_free(cla_x_buf, cqm_handle);
+ return CQM_FAIL;
+ }
+ memset(cla_z_buf->buf_list, 0,
+ cla_z_buf->buf_number * sizeof(struct tag_cqm_buf_list));
+
+ cla_y_buf->buf_list = vmalloc(cla_y_buf->buf_number *
+ sizeof(struct tag_cqm_buf_list));
+ if (!cla_y_buf->buf_list) {
+ cqm_buf_free(cla_z_buf, cqm_handle);
+ cqm_buf_free(cla_x_buf, cqm_handle);
+ return CQM_FAIL;
+ }
+ memset(cla_y_buf->buf_list, 0,
+ cla_y_buf->buf_number * sizeof(struct tag_cqm_buf_list));
+ }
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_cla_xyz_check(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table, u32 *size)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 trunk_size = 0;
+
+ /* If the capability(obj_num) is set to 0, the CLA does not need to be
+ * initialized and exits directly.
+ */
+ if (cla_table->obj_num == 0) {
+ cqm_info(handle->dev_hdl,
+ "Cla alloc: cla_type %u, obj_num=0, don't alloc buffer\n",
+ cla_table->type);
+ return CQM_SUCCESS;
+ }
+
+ cqm_info(handle->dev_hdl,
+ "Cla alloc: cla_type %u, obj_num=0x%x, gpa_check_enable=%d\n",
+ cla_table->type, cla_table->obj_num,
+ cqm_handle->func_capability.gpa_check_enable);
+
+ /* Check whether obj_size is 2^n-aligned. An error is reported when
+ * obj_size is 0 or 1.
+ */
+ if (!cqm_check_align(cla_table->obj_size)) {
+ cqm_err(handle->dev_hdl,
+ "Cla alloc: cla_type %u, obj_size 0x%x is not align on 2^n\n",
+ cla_table->type, cla_table->obj_size);
+ return CQM_FAIL;
+ }
+
+ trunk_size = (u32)(PAGE_SIZE << cla_table->trunk_order);
+
+ if (trunk_size < cla_table->obj_size) {
+ cqm_err(handle->dev_hdl,
+ "Cla alloc: cla type %u, obj_size 0x%x is out of trunk size\n",
+ cla_table->type, cla_table->obj_size);
+ return CQM_FAIL;
+ }
+
+ *size = trunk_size;
+
+ return CQM_CONTINUE;
+}
+
+static s32 cqm_cla_xyz_lvl0(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table, u32 trunk_size)
+{
+ struct tag_cqm_buf *cla_z_buf = NULL;
+
+ cla_table->cla_lvl = CQM_CLA_LVL_0;
+
+ cla_table->z = CQM_MAX_INDEX_BIT;
+ cla_table->y = 0;
+ cla_table->x = 0;
+
+ cla_table->cacheline_z = cla_table->z;
+ cla_table->cacheline_y = cla_table->y;
+ cla_table->cacheline_x = cla_table->x;
+
+ /* Applying for CLA_Z_BUF Space */
+ cla_z_buf = &cla_table->cla_z_buf;
+ cla_z_buf->buf_size = trunk_size;
+ cla_z_buf->buf_number = 1;
+ cla_z_buf->page_number = cla_z_buf->buf_number << cla_table->trunk_order;
+ cla_z_buf->bat_entry_type = cla_table->type;
+
+ return cqm_buf_alloc(cqm_handle, cla_z_buf, false);
+}
+
+/**
+ * Prototype : cqm_cla_xyz
+ * Description : Calculate the number of levels of CLA tables and allocate
+ * space for each level of CLA table.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * struct tag_cqm_cla_table *cla_table
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+static s32 cqm_cla_xyz(struct tag_cqm_handle *cqm_handle, struct tag_cqm_cla_table *cla_table)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 trunk_size = 0;
+ s32 ret = CQM_FAIL;
+
+ ret = cqm_cla_xyz_check(cqm_handle, cla_table, &trunk_size);
+ if (ret != CQM_CONTINUE)
+ return ret;
+
+ ret = cqm_cla_xyz_vram_name_init(cla_table, handle);
+ if (ret != CQM_SUCCESS)
+ return ret;
+
+ /* Level-0 CLA occupies a small space.
+ * Only CLA_Z_BUF can be allocated during initialization.
+ */
+ cqm_dbg("cla_table->max_buffer_size = %d trunk_size = %d\n",
+ cla_table->max_buffer_size, trunk_size);
+
+ if (cla_table->max_buffer_size > trunk_size &&
+ cqm_need_secure_mem((void *)handle)) {
+ trunk_size = roundup(cla_table->max_buffer_size, CQM_SECURE_MEM_ALIGNED_SIZE);
+ cqm_dbg("[memsec]reset trunk_size = %u\n", trunk_size);
+ }
+
+ if (cla_table->max_buffer_size <= trunk_size) {
+ ret = cqm_cla_xyz_lvl0(cqm_handle, cla_table, trunk_size);
+ if (ret != CQM_SUCCESS)
+ return CQM_FAIL;
+ /* Level-1 CLA
+ * Allocates CLA_Y_BUF and CLA_Z_BUF during initialization.
+ */
+ } else if (cla_table->max_buffer_size <=
+ (trunk_size * (trunk_size / sizeof(dma_addr_t)))) {
+ if (cqm_cla_xyz_lvl1(cqm_handle, cla_table, trunk_size) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_xyz_lvl1));
+ return CQM_FAIL;
+ }
+ /* Level-2 CLA
+ * Allocates CLA_X_BUF, CLA_Y_BUF, and CLA_Z_BUF during initialization.
+ */
+ } else if (cla_table->max_buffer_size <= (trunk_size * (trunk_size / sizeof(dma_addr_t)) *
+ (trunk_size / sizeof(dma_addr_t)))) {
+ if (cqm_cla_xyz_lvl2(cqm_handle, cla_table, trunk_size) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_xyz_lvl2));
+ return CQM_FAIL;
+ }
+ } else { /* The current memory management mode does not support such
+ * a large buffer addressing. The order value needs to
+ * be increased.
+ */
+ cqm_err(handle->dev_hdl,
+ "Cla alloc: cla max_buffer_size 0x%x exceeds support range\n",
+ cla_table->max_buffer_size);
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+static void cqm_cla_init_entry_normal(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ struct tag_cqm_func_capability *capability)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ switch (cla_table->type) {
+ case CQM_BAT_ENTRY_T_HASH:
+ cla_table->trunk_order = capability->pagesize_reorder;
+ cla_table->max_buffer_size = capability->hash_number * capability->hash_basic_size;
+ cla_table->obj_size = capability->hash_basic_size;
+ cla_table->obj_num = capability->hash_number;
+ cla_table->alloc_static = true;
+ break;
+ case CQM_BAT_ENTRY_T_QPC:
+ cla_table->trunk_order = capability->pagesize_reorder;
+ cla_table->max_buffer_size = capability->qpc_number * capability->qpc_basic_size;
+ cla_table->obj_size = capability->qpc_basic_size;
+ cla_table->obj_num = capability->qpc_number;
+ cla_table->alloc_static = capability->qpc_alloc_static;
+ cqm_info(handle->dev_hdl, "Cla alloc: qpc alloc_static=%d\n",
+ cla_table->alloc_static);
+ break;
+ case CQM_BAT_ENTRY_T_MPT:
+ cla_table->trunk_order = capability->pagesize_reorder;
+ cla_table->max_buffer_size = capability->mpt_number *
+ capability->mpt_basic_size;
+ cla_table->obj_size = capability->mpt_basic_size;
+ cla_table->obj_num = capability->mpt_number;
+ cla_table->alloc_static = true; /* CCB decided. MPT uses only
+ * static application scenarios.
+ */
+ break;
+ case CQM_BAT_ENTRY_T_SCQC:
+ cla_table->trunk_order = capability->pagesize_reorder;
+ cla_table->max_buffer_size = capability->scqc_number * capability->scqc_basic_size;
+ cla_table->obj_size = capability->scqc_basic_size;
+ cla_table->obj_num = capability->scqc_number;
+ cla_table->alloc_static = capability->scqc_alloc_static;
+ cqm_info(handle->dev_hdl, "Cla alloc: scqc alloc_static=%d\n",
+ cla_table->alloc_static);
+ break;
+ case CQM_BAT_ENTRY_T_SRQC:
+ cla_table->trunk_order = capability->pagesize_reorder;
+ cla_table->max_buffer_size = capability->srqc_number * capability->srqc_basic_size;
+ cla_table->obj_size = capability->srqc_basic_size;
+ cla_table->obj_num = capability->srqc_number;
+ cla_table->alloc_static = false;
+ break;
+ default:
+ break;
+ }
+}
+
+static void cqm_cla_init_entry_extern(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ struct tag_cqm_func_capability *capability)
+{
+ switch (cla_table->type) {
+ case CQM_BAT_ENTRY_T_GID:
+ /* Level-0 CLA table required */
+ cla_table->max_buffer_size = capability->gid_number *
+ capability->gid_basic_size;
+ cla_table->trunk_order =
+ (u32)cqm_shift(ALIGN(cla_table->max_buffer_size, PAGE_SIZE) / PAGE_SIZE);
+ cla_table->obj_size = capability->gid_basic_size;
+ cla_table->obj_num = capability->gid_number;
+ cla_table->alloc_static = true;
+ break;
+ case CQM_BAT_ENTRY_T_LUN:
+ cla_table->trunk_order = CLA_TABLE_PAGE_ORDER;
+ cla_table->max_buffer_size = capability->lun_number *
+ capability->lun_basic_size;
+ cla_table->obj_size = capability->lun_basic_size;
+ cla_table->obj_num = capability->lun_number;
+ cla_table->alloc_static = true;
+ break;
+ case CQM_BAT_ENTRY_T_TASKMAP:
+ cla_table->trunk_order = CQM_4K_PAGE_ORDER;
+ cla_table->max_buffer_size = capability->taskmap_number *
+ capability->taskmap_basic_size;
+ cla_table->obj_size = capability->taskmap_basic_size;
+ cla_table->obj_num = capability->taskmap_number;
+ cla_table->alloc_static = true;
+ break;
+ case CQM_BAT_ENTRY_T_L3I:
+ cla_table->trunk_order = CLA_TABLE_PAGE_ORDER;
+ cla_table->max_buffer_size = capability->l3i_number *
+ capability->l3i_basic_size;
+ cla_table->obj_size = capability->l3i_basic_size;
+ cla_table->obj_num = capability->l3i_number;
+ cla_table->alloc_static = true;
+ break;
+ case CQM_BAT_ENTRY_T_CHILDC:
+ cla_table->trunk_order = capability->pagesize_reorder;
+ cla_table->max_buffer_size = capability->childc_number *
+ capability->childc_basic_size;
+ cla_table->obj_size = capability->childc_basic_size;
+ cla_table->obj_num = capability->childc_number;
+ cla_table->alloc_static = true;
+ break;
+ case CQM_BAT_ENTRY_T_TIMER:
+ /* Ensure that the basic size of the timer buffer page does not
+ * exceed 128 x 4 KB. Otherwise, clearing the timer buffer of
+ * the function is complex.
+ */
+ cla_table->trunk_order = CQM_4K_PAGE_ORDER;
+ cla_table->max_buffer_size = capability->timer_number *
+ capability->timer_basic_size;
+ cla_table->obj_size = capability->timer_basic_size;
+ cla_table->obj_num = capability->timer_number;
+ cla_table->alloc_static = true;
+ break;
+ case CQM_BAT_ENTRY_T_XID2CID:
+ cla_table->trunk_order = capability->pagesize_reorder;
+ cla_table->max_buffer_size = capability->xid2cid_number *
+ capability->xid2cid_basic_size;
+ cla_table->obj_size = capability->xid2cid_basic_size;
+ cla_table->obj_num = capability->xid2cid_number;
+ cla_table->alloc_static = true;
+ break;
+ case CQM_BAT_ENTRY_T_REORDER:
+ /* This entry supports only IWARP and does not support GPA
+ * validity check.
+ */
+ cla_table->trunk_order = capability->pagesize_reorder;
+ cla_table->max_buffer_size = capability->reorder_number *
+ capability->reorder_basic_size;
+ cla_table->obj_size = capability->reorder_basic_size;
+ cla_table->obj_num = capability->reorder_number;
+ cla_table->alloc_static = true;
+ break;
+ default:
+ break;
+ }
+}
+
+static s32 cqm_cla_init_entry_condition(struct tag_cqm_handle *cqm_handle, u32 entry_type)
+{
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct tag_cqm_cla_table *cla_table = &bat_table->entry[entry_type];
+ struct tag_cqm_cla_table *cla_table_timer = NULL;
+ u32 i;
+
+ /* When the timer is in LB mode 1 or 2, the timer needs to be
+ * configured for four SMFs and the address space is independent.
+ */
+ if (cla_table->type == CQM_BAT_ENTRY_T_TIMER &&
+ (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_1 ||
+ cqm_handle->func_capability.lb_mode == CQM_LB_MODE_2)) {
+ for (i = 0; i < CQM_LB_SMF_MAX; i++) {
+ cla_table_timer = &bat_table->timer_entry[i];
+ memcpy(cla_table_timer, cla_table, sizeof(struct tag_cqm_cla_table));
+
+ snprintf(cla_table_timer->name,
+ VRAM_NAME_MAX_LEN - 1, "%s%s%01u", cla_table->name,
+ VRAM_CQM_CLA_SMF_BASE, i);
+
+ if (cqm_cla_xyz(cqm_handle, cla_table_timer) ==
+ CQM_FAIL) {
+ cqm_cla_uninit(cqm_handle, entry_type);
+ return CQM_FAIL;
+ }
+ }
+ return CQM_SUCCESS;
+ }
+
+ if (cqm_cla_xyz(cqm_handle, cla_table) == CQM_FAIL) {
+ cqm_cla_uninit(cqm_handle, entry_type);
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_cla_init_entry(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_func_capability *capability)
+{
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ s32 ret;
+ u32 i = 0;
+
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ cla_table = &bat_table->entry[i];
+ cla_table->type = bat_table->bat_entry_type[i];
+ snprintf(cla_table->name, VRAM_NAME_MAX_LEN - 1,
+ "%s%s%s%02u", cqm_handle->name, VRAM_CQM_CLA_BASE,
+ VRAM_CQM_CLA_TYPE_BASE, cla_table->type);
+
+ cqm_cla_init_entry_normal(cqm_handle, cla_table, capability);
+ cqm_cla_init_entry_extern(cqm_handle, cla_table, capability);
+
+ /* Allocate CLA entry space at each level. */
+ if (cla_table->type < CQM_BAT_ENTRY_T_HASH ||
+ cla_table->type > CQM_BAT_ENTRY_T_REORDER) {
+ mutex_init(&cla_table->lock);
+ continue;
+ }
+
+ /* For the PPF, resources (8 wheels x 2k scales x 32B x
+ * func_num) need to be applied for to the timer. The
+ * structure of the timer entry in the BAT table needs
+ * to be filled. For the PF, no resource needs to be
+ * applied for the timer and no structure needs to be
+ * filled in the timer entry in the BAT table.
+ */
+ if (!(cla_table->type == CQM_BAT_ENTRY_T_TIMER &&
+ cqm_handle->func_attribute.func_type != CQM_PPF)) {
+ ret = cqm_cla_init_entry_condition(cqm_handle, i);
+ if (ret != CQM_SUCCESS)
+ return CQM_FAIL;
+ cqm_dbg("~~~~cla_table->type = %d\n", cla_table->type);
+ }
+ cqm_dbg("****cla_table->type = %d\n", cla_table->type);
+ mutex_init(&cla_table->lock);
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_cla_init
+ * Description : Initialize the CLA table.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+s32 cqm_cla_init(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_func_capability *capability = &cqm_handle->func_capability;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ s32 ret;
+
+ /* Applying for CLA Entries */
+ ret = cqm_cla_init_entry(cqm_handle, capability);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_init_entry));
+ return ret;
+ }
+
+ /* After the CLA entry is applied, the address is filled
+ * in the BAT table.
+ */
+ cqm_bat_fill_cla(cqm_handle);
+
+ /* Instruct the chip to update the BAT table. */
+ ret = cqm_bat_update(cqm_handle);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_bat_update));
+ goto err;
+ }
+
+ cqm_info(handle->dev_hdl, "Timer start: func_type=%d, timer_enable=%u\n",
+ cqm_handle->func_attribute.func_type,
+ cqm_handle->func_capability.timer_enable);
+
+ if (cqm_handle->func_attribute.func_type == CQM_PPF) {
+ ret = hinic3_ppf_ht_gpa_init(handle);
+ if (ret) {
+ cqm_err(handle->dev_hdl, "PPF ht gpa init fail!\n");
+ goto err;
+ }
+
+ if (cqm_handle->func_capability.timer_enable ==
+ CQM_TIMER_ENABLE) {
+ /* Enable the timer after the timer resources are applied for */
+ cqm_info(handle->dev_hdl, "PPF timer start\n");
+ ret = hinic3_ppf_tmr_start(handle);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, "PPF timer start, ret=%d\n", ret);
+ goto err1;
+ }
+ }
+ }
+
+ return CQM_SUCCESS;
+err1:
+ hinic3_ppf_ht_gpa_deinit(handle);
+err:
+ cqm_cla_uninit(cqm_handle, CQM_BAT_ENTRY_MAX);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_cla_uninit
+ * Description : Deinitialize the CLA table.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+void cqm_cla_uninit(struct tag_cqm_handle *cqm_handle, u32 entry_numb)
+{
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ s32 inv_flag = 0;
+ u32 i;
+
+ for (i = 0; i < entry_numb; i++) {
+ cla_table = &bat_table->entry[i];
+ if (cla_table->type != CQM_BAT_ENTRY_T_INVALID) {
+ cqm_buf_free_cache_inv(cqm_handle,
+ &cla_table->cla_x_buf,
+ &inv_flag);
+ cqm_buf_free_cache_inv(cqm_handle,
+ &cla_table->cla_y_buf,
+ &inv_flag);
+ cqm_buf_free_cache_inv(cqm_handle,
+ &cla_table->cla_z_buf,
+ &inv_flag);
+ }
+ mutex_deinit(&cla_table->lock);
+ }
+
+ /* When the lb mode is 1/2, the timer space allocated to the 4 SMFs
+ * needs to be released.
+ */
+ if (cqm_handle->func_attribute.func_type == CQM_PPF &&
+ (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_1 ||
+ cqm_handle->func_capability.lb_mode == CQM_LB_MODE_2)) {
+ for (i = 0; i < CQM_LB_SMF_MAX; i++) {
+ cla_table = &bat_table->timer_entry[i];
+ cqm_buf_free_cache_inv(cqm_handle,
+ &cla_table->cla_x_buf,
+ &inv_flag);
+ cqm_buf_free_cache_inv(cqm_handle,
+ &cla_table->cla_y_buf,
+ &inv_flag);
+ cqm_buf_free_cache_inv(cqm_handle,
+ &cla_table->cla_z_buf,
+ &inv_flag);
+ mutex_deinit(&cla_table->lock);
+ }
+ }
+}
+
+static s32 cqm_cla_update_cmd(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cmd_buf *buf_in,
+ struct tag_cqm_cla_update_cmd *cmd)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_cla_update_cmd *cla_update_cmd = NULL;
+ s32 ret = CQM_FAIL;
+
+ cla_update_cmd = (struct tag_cqm_cla_update_cmd *)(buf_in->buf);
+
+ cla_update_cmd->gpa_h = cmd->gpa_h;
+ cla_update_cmd->gpa_l = cmd->gpa_l;
+ cla_update_cmd->value_h = cmd->value_h;
+ cla_update_cmd->value_l = cmd->value_l;
+ cla_update_cmd->smf_id = cmd->smf_id;
+ cla_update_cmd->func_id = cmd->func_id;
+
+ cqm_swab32((u8 *)cla_update_cmd,
+ (sizeof(struct tag_cqm_cla_update_cmd) >> CQM_DW_SHIFT));
+
+ ret = cqm_send_cmd_box((void *)(cqm_handle->ex_handle), CQM_MOD_CQM,
+ CQM_CMD_T_CLA_UPDATE, buf_in, NULL, NULL,
+ CQM_CMD_TIMEOUT, HINIC3_CHANNEL_DEFAULT);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_send_cmd_box));
+ cqm_err(handle->dev_hdl, "Cla alloc: cqm_cla_update, cqm_send_cmd_box_ret=%d\n",
+ ret);
+ cqm_err(handle->dev_hdl,
+ "Cla alloc: cqm_cla_update, cla_update_cmd: 0x%x 0x%x 0x%x 0x%x\n",
+ cmd->gpa_h, cmd->gpa_l, cmd->value_h, cmd->value_l);
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_cla_update
+ * Description : Send a command to update the CLA table.
+ * Input : struct tag_cqm_handle *cqm_handle,
+ * struct tag_cqm_buf_list *buf_node_parent parent node of the content to
+ * be updated
+ * struct tag_cqm_buf_list *buf_node_child Subnode for which the buffer
+ * is to be applied
+ * u32 child_index Index of a child node.
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+static s32 cqm_cla_update(struct tag_cqm_handle *cqm_handle,
+ const struct tag_cqm_buf_list *buf_node_parent,
+ const struct tag_cqm_buf_list *buf_node_child,
+ u32 child_index, u8 cla_update_mode)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_cmd_buf *buf_in = NULL;
+ struct tag_cqm_cla_update_cmd cmd;
+ dma_addr_t pa = 0;
+ s32 ret = CQM_FAIL;
+ u8 gpa_check_enable = cqm_handle->func_capability.gpa_check_enable;
+ u32 i = 0;
+ u64 spu_en;
+
+ buf_in = cqm_cmd_alloc(cqm_handle->ex_handle);
+ if (!buf_in)
+ return CQM_FAIL;
+ buf_in->size = sizeof(struct tag_cqm_cla_update_cmd);
+
+ /* Fill command format, convert to big endian. */
+ /* SPU function sets bit63: acs_spu_en based on function id. */
+ if (hinic3_host_id(cqm_handle->ex_handle) == CQM_SPU_HOST_ID)
+ spu_en = ((u64)(cqm_handle->func_attribute.func_global_idx &
+ 0x1)) << 0x3F;
+ else
+ spu_en = 0;
+
+ pa = ((buf_node_parent->pa + (child_index * sizeof(dma_addr_t))) |
+ (u32)spu_en);
+ cmd.gpa_h = CQM_ADDR_HI(pa);
+ cmd.gpa_l = CQM_ADDR_LW(pa);
+
+ pa = (buf_node_child->pa | (u32)spu_en);
+ cmd.value_h = CQM_ADDR_HI(pa);
+ cmd.value_l = CQM_ADDR_LW(pa);
+
+ cqm_dbg("Cla alloc: %s, gpa=0x%x 0x%x, value=0x%x 0x%x, cla_update_mode=0x%x\n",
+ __func__, cmd.gpa_h, cmd.gpa_l, cmd.value_h, cmd.value_l,
+ cla_update_mode);
+
+ /* current CLA GPA CHECK */
+ if (gpa_check_enable) {
+ switch (cla_update_mode) {
+ /* gpa[0]=1 means this GPA is valid */
+ case CQM_CLA_RECORD_NEW_GPA:
+ cmd.value_l |= 1;
+ break;
+ /* gpa[0]=0 means this GPA is valid */
+ case CQM_CLA_DEL_GPA_WITHOUT_CACHE_INVALID:
+ case CQM_CLA_DEL_GPA_WITH_CACHE_INVALID:
+ cmd.value_l &= (~1);
+ break;
+ default:
+ cqm_err(handle->dev_hdl,
+ "Cla alloc: %s, wrong cla_update_mode=%u\n",
+ __func__, cla_update_mode);
+ break;
+ }
+ }
+
+ /* Todo: The following code is the same as that in the bat update and
+ * needs to be reconstructed.
+ */
+ /* In non-fake mode, set func_id to 0xffff.
+ * Indicates the current func fake mode, set func_id to the
+ * specified value, This is a fake func_id.
+ */
+ if (cqm_handle->func_capability.fake_func_type == CQM_FAKE_FUNC_CHILD)
+ cmd.func_id = cqm_handle->func_attribute.func_global_idx;
+ else
+ cmd.func_id = 0xffff;
+
+ /* Normal mode is 1822 traditional mode and is configured on SMF0. */
+ /* Mode 0 is hashed to 4 SMF engines (excluding PPF) by func ID. */
+ if (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_NORMAL ||
+ (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_0 &&
+ cqm_handle->func_attribute.func_type != CQM_PPF)) {
+ cmd.smf_id = cqm_funcid2smfid(cqm_handle);
+ ret = cqm_cla_update_cmd(cqm_handle, buf_in, &cmd);
+ /* Modes 1/2 are allocated to four SMF engines by flow.
+ * Therefore, one function needs to be allocated to four SMF engines.
+ */
+ /* Mode 0 PPF needs to be configured on 4 engines,
+ * and the timer resources need to be shared by the 4 engines.
+ */
+ } else if (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_1 ||
+ cqm_handle->func_capability.lb_mode == CQM_LB_MODE_2 ||
+ (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_0 &&
+ cqm_handle->func_attribute.func_type == CQM_PPF)) {
+ for (i = 0; i < CQM_LB_SMF_MAX; i++) {
+ /* The smf_pg variable stores currently enabled SMF. */
+ if (cqm_handle->func_capability.smf_pg & (1U << i)) {
+ cmd.smf_id = i;
+ ret = cqm_cla_update_cmd(cqm_handle, buf_in,
+ &cmd);
+ if (ret != CQM_SUCCESS)
+ goto out;
+ }
+ }
+ } else {
+ cqm_err(handle->dev_hdl, "Cla update: unsupport lb mode=%u\n",
+ cqm_handle->func_capability.lb_mode);
+ ret = CQM_FAIL;
+ }
+
+out:
+ cqm_cmd_free((void *)(cqm_handle->ex_handle), buf_in);
+ return ret;
+}
+
+/**
+ * Prototype : cqm_cla_alloc
+ * Description : Trunk page for applying for a CLA.
+ * Input : struct tag_cqm_handle *cqm_handle,
+ * struct tag_cqm_cla_table *cla_table,
+ * struct tag_cqm_buf_list *buf_node_parent parent node of the content to
+ * be updated
+ * struct tag_cqm_buf_list *buf_node_child subnode for which the buffer
+ * is to be applied
+ * u32 child_index index of a child node
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+static s32 cqm_cla_alloc(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ struct tag_cqm_buf_list *buf_node_parent,
+ struct tag_cqm_buf_list *buf_node_child, u32 child_index)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ s32 ret = CQM_FAIL;
+
+ /* Apply for trunk page */
+ buf_node_child->va = (u8 *)ossl_get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ cla_table->trunk_order);
+ if (!buf_node_child->va)
+ return CQM_FAIL;
+
+ /* PCI mapping */
+ buf_node_child->pa = pci_map_single(cqm_handle->dev, buf_node_child->va,
+ PAGE_SIZE << cla_table->trunk_order,
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(cqm_handle->dev, buf_node_child->pa)) {
+ cqm_err(handle->dev_hdl, CQM_MAP_FAIL(buf_node_child->pa));
+ goto err1;
+ }
+
+ /* Notify the chip of trunk_pa so that the chip fills in cla entry */
+ ret = cqm_cla_update(cqm_handle, buf_node_parent, buf_node_child,
+ child_index, CQM_CLA_RECORD_NEW_GPA);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_update));
+ goto err2;
+ }
+
+ return CQM_SUCCESS;
+
+err2:
+ pci_unmap_single(cqm_handle->dev, buf_node_child->pa,
+ PAGE_SIZE << cla_table->trunk_order,
+ PCI_DMA_BIDIRECTIONAL);
+err1:
+ free_pages((ulong)(buf_node_child->va), cla_table->trunk_order);
+ buf_node_child->va = NULL;
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_cla_free
+ * Description : Release trunk page of a CLA
+ * Input : struct tag_cqm_handle *cqm_handle
+ * struct tag_cqm_cla_table *cla_table
+ * struct tag_cqm_buf_list *buf_node
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/5/15
+ * Modification : Created function
+ */
+static void cqm_cla_free(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ struct tag_cqm_buf_list *buf_node_parent,
+ struct tag_cqm_buf_list *buf_node_child,
+ u32 child_index, u8 cla_update_mode)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 trunk_size;
+
+ cqm_dbg("Cla free: cla_update_mode=%u\n", cla_update_mode);
+
+ if (cqm_cla_update(cqm_handle, buf_node_parent, buf_node_child,
+ child_index, cla_update_mode) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_update));
+ return;
+ }
+
+ if (cla_update_mode == CQM_CLA_DEL_GPA_WITH_CACHE_INVALID) {
+ trunk_size = (u32)(PAGE_SIZE << cla_table->trunk_order);
+ if (cqm_cla_cache_invalid(cqm_handle, buf_node_child->pa,
+ trunk_size) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_cla_cache_invalid));
+ return;
+ }
+ }
+
+ /* Remove PCI mapping from the trunk page */
+ pci_unmap_single(cqm_handle->dev, buf_node_child->pa,
+ PAGE_SIZE << cla_table->trunk_order,
+ PCI_DMA_BIDIRECTIONAL);
+
+ /* Rlease trunk page */
+ free_pages((ulong)(buf_node_child->va), cla_table->trunk_order);
+ buf_node_child->va = NULL;
+}
+
+static u8 *cqm_cla_get_unlock_lvl0(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ u32 index, u32 count, dma_addr_t *pa)
+{
+ struct tag_cqm_buf *cla_z_buf = &cla_table->cla_z_buf;
+ u8 *ret_addr = NULL;
+ u32 offset = 0;
+
+ /* Level 0 CLA pages are statically allocated. */
+ offset = index * cla_table->obj_size;
+ ret_addr = (u8 *)(cla_z_buf->buf_list->va) + offset;
+ *pa = cla_z_buf->buf_list->pa + offset;
+
+ return ret_addr;
+}
+
+static u8 *cqm_cla_get_unlock_lvl1(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ u32 index, u32 count, dma_addr_t *pa)
+{
+ struct tag_cqm_buf *cla_y_buf = &cla_table->cla_y_buf;
+ struct tag_cqm_buf *cla_z_buf = &cla_table->cla_z_buf;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_buf_list *buf_node_y = NULL;
+ struct tag_cqm_buf_list *buf_node_z = NULL;
+ u32 y_index = 0;
+ u32 z_index = 0;
+ u8 *ret_addr = NULL;
+ u32 offset = 0;
+
+ z_index = index & ((1U << (cla_table->z + 1)) - 1);
+ y_index = index >> (cla_table->z + 1);
+
+ if (y_index >= cla_z_buf->buf_number) {
+ cqm_err(handle->dev_hdl,
+ "Cla get: index exceeds buf_number, y_index %u, z_buf_number %u\n",
+ y_index, cla_z_buf->buf_number);
+ return NULL;
+ }
+ buf_node_z = &cla_z_buf->buf_list[y_index];
+ buf_node_y = cla_y_buf->buf_list;
+
+ /* The z buf node does not exist, applying for a page first. */
+ if (!buf_node_z->va) {
+ if (cqm_cla_alloc(cqm_handle, cla_table, buf_node_y, buf_node_z,
+ y_index) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_cla_alloc));
+ cqm_err(handle->dev_hdl,
+ "Cla get: cla_table->type=%u\n",
+ cla_table->type);
+ return NULL;
+ }
+ }
+
+ cqm_dbg("Cla get: 1L: z_refcount=0x%x, count=0x%x\n",
+ buf_node_z->refcount, count);
+ buf_node_z->refcount += count;
+ offset = z_index * cla_table->obj_size;
+ ret_addr = (u8 *)(buf_node_z->va) + offset;
+ *pa = buf_node_z->pa + offset;
+
+ return ret_addr;
+}
+
+static u8 *cqm_cla_get_unlock_lvl2(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cla_table *cla_table,
+ u32 index, u32 count, dma_addr_t *pa)
+{
+ struct tag_cqm_buf *cla_x_buf = &cla_table->cla_x_buf;
+ struct tag_cqm_buf *cla_y_buf = &cla_table->cla_y_buf;
+ struct tag_cqm_buf *cla_z_buf = &cla_table->cla_z_buf;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_buf_list *buf_node_x = NULL;
+ struct tag_cqm_buf_list *buf_node_y = NULL;
+ struct tag_cqm_buf_list *buf_node_z = NULL;
+ u32 x_index = 0;
+ u32 y_index = 0;
+ u32 z_index = 0;
+ u32 trunk_size = (u32)(PAGE_SIZE << cla_table->trunk_order);
+ u8 *ret_addr = NULL;
+ u32 offset = 0;
+ u64 tmp;
+
+ z_index = index & ((1U << (cla_table->z + 1)) - 1);
+ y_index = (index >> (cla_table->z + 1)) &
+ ((1U << (cla_table->y - cla_table->z)) - 1);
+ x_index = index >> (cla_table->y + 1);
+ tmp = x_index * (trunk_size / sizeof(dma_addr_t)) + y_index;
+
+ if (x_index >= cla_y_buf->buf_number || tmp >= cla_z_buf->buf_number) {
+ cqm_err(handle->dev_hdl,
+ "Cla get: index exceeds buf_number, x %u, y %u, y_buf_n %u, z_buf_n %u\n",
+ x_index, y_index, cla_y_buf->buf_number,
+ cla_z_buf->buf_number);
+ return NULL;
+ }
+
+ buf_node_x = cla_x_buf->buf_list;
+ buf_node_y = &cla_y_buf->buf_list[x_index];
+ buf_node_z = &cla_z_buf->buf_list[tmp];
+
+ /* The y buf node does not exist, applying for pages for y node. */
+ if (!buf_node_y->va) {
+ if (cqm_cla_alloc(cqm_handle, cla_table, buf_node_x, buf_node_y,
+ x_index) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_cla_alloc));
+ return NULL;
+ }
+ }
+
+ /* The z buf node does not exist, applying for pages for z node. */
+ if (!buf_node_z->va) {
+ if (cqm_cla_alloc(cqm_handle, cla_table, buf_node_y, buf_node_z,
+ y_index) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_cla_alloc));
+ if (buf_node_y->refcount == 0)
+ /* To release node Y, cache_invalid is
+ * required.
+ */
+ cqm_cla_free(cqm_handle, cla_table, buf_node_x, buf_node_y, x_index,
+ CQM_CLA_DEL_GPA_WITH_CACHE_INVALID);
+ return NULL;
+ }
+
+ cqm_dbg("Cla get: 2L: y_refcount=0x%x\n", buf_node_y->refcount);
+ /* reference counting of the y buffer node needs to increase
+ * by 1.
+ */
+ buf_node_y->refcount++;
+ }
+
+ cqm_dbg("Cla get: 2L: z_refcount=0x%x, count=0x%x\n",
+ buf_node_z->refcount, count);
+ buf_node_z->refcount += count;
+ offset = z_index * cla_table->obj_size;
+ ret_addr = (u8 *)(buf_node_z->va) + offset;
+ *pa = buf_node_z->pa + offset;
+
+ return ret_addr;
+}
+
+/**
+ * Prototype : cqm_cla_get_unlock
+ * Description : Apply for block buffer in number of count from the index
+ * position in the cla table, The unlocked process is used for
+ * static buffer application.
+ * Input : struct tag_cqm_handle *cqm_handle,
+ * struct tag_cqm_cla_table *cla_table,
+ * u32 index,
+ * u32 count,
+ * dma_addr_t *pa
+ * Output : None
+ * Return Value : u8 *
+ * 1.Date : 2019/7/11
+ * Modification : Created function
+ */
+u8 *cqm_cla_get_unlock(struct tag_cqm_handle *cqm_handle, struct tag_cqm_cla_table *cla_table,
+ u32 index, u32 count, dma_addr_t *pa)
+{
+ u8 *ret_addr = NULL;
+
+ if (cla_table->cla_lvl == CQM_CLA_LVL_0)
+ ret_addr = cqm_cla_get_unlock_lvl0(cqm_handle, cla_table, index,
+ count, pa);
+ else if (cla_table->cla_lvl == CQM_CLA_LVL_1)
+ ret_addr = cqm_cla_get_unlock_lvl1(cqm_handle, cla_table, index,
+ count, pa);
+ else
+ ret_addr = cqm_cla_get_unlock_lvl2(cqm_handle, cla_table, index,
+ count, pa);
+
+ return ret_addr;
+}
+
+/**
+ * Prototype : cqm_cla_get_lock
+ * Description : Apply for block buffer in number of count from the index
+ * position in the cla table. The lock process is used during
+ * dynamic buffer application.
+ * Input : struct tag_cqm_handle *cqm_handle,
+ * struct tag_cqm_cla_table *cla_table,
+ * u32 index,
+ * u32 count,
+ * dma_addr_t *pa
+ * Output : None
+ * Return Value : u8 *
+ * 1.Date : 2019/7/11
+ * Modification : Created function
+ */
+u8 *cqm_cla_get_lock(struct tag_cqm_handle *cqm_handle, struct tag_cqm_cla_table *cla_table,
+ u32 index, u32 count, dma_addr_t *pa)
+{
+ u8 *ret_addr = NULL;
+
+ mutex_lock(&cla_table->lock);
+
+ ret_addr = cqm_cla_get_unlock(cqm_handle, cla_table, index, count, pa);
+
+ mutex_unlock(&cla_table->lock);
+
+ return ret_addr;
+}
+
+/**
+ * Prototype : cqm_cla_put
+ * Description : Decrease the value of reference counting on the trunk page.
+ * If the value is 0, the trunk page is released.
+ * Input : struct tag_cqm_handle *cqm_handle,
+ * struct tag_cqm_cla_table *cla_table,
+ * u32 index,
+ * u32 count
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_cla_put(struct tag_cqm_handle *cqm_handle, struct tag_cqm_cla_table *cla_table,
+ u32 index, u32 count)
+{
+ struct tag_cqm_buf *cla_z_buf = &cla_table->cla_z_buf;
+ struct tag_cqm_buf *cla_y_buf = &cla_table->cla_y_buf;
+ struct tag_cqm_buf *cla_x_buf = &cla_table->cla_x_buf;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_buf_list *buf_node_z = NULL;
+ struct tag_cqm_buf_list *buf_node_y = NULL;
+ struct tag_cqm_buf_list *buf_node_x = NULL;
+ u32 x_index = 0;
+ u32 y_index = 0;
+ u32 trunk_size = (u32)(PAGE_SIZE << cla_table->trunk_order);
+ u64 tmp;
+
+ /* The buffer is applied statically, and the reference counting
+ * does not need to be controlled.
+ */
+ if (cla_table->alloc_static)
+ return;
+
+ mutex_lock(&cla_table->lock);
+
+ if (cla_table->cla_lvl == CQM_CLA_LVL_1) {
+ y_index = index >> (cla_table->z + 1);
+
+ if (y_index >= cla_z_buf->buf_number) {
+ cqm_err(handle->dev_hdl,
+ "Cla put: index exceeds buf_number, y_index %u, z_buf_number %u\n",
+ y_index, cla_z_buf->buf_number);
+ cqm_err(handle->dev_hdl,
+ "Cla put: cla_table->type=%u\n",
+ cla_table->type);
+ mutex_unlock(&cla_table->lock);
+ return;
+ }
+
+ buf_node_z = &cla_z_buf->buf_list[y_index];
+ buf_node_y = cla_y_buf->buf_list;
+
+ /* When the value of reference counting on the z node page is 0,
+ * the z node page is released.
+ */
+ cqm_dbg("Cla put: 1L: z_refcount=0x%x, count=0x%x\n",
+ buf_node_z->refcount, count);
+ buf_node_z->refcount -= count;
+ if (buf_node_z->refcount == 0)
+ /* The cache invalid is not required for the Z node. */
+ cqm_cla_free(cqm_handle, cla_table, buf_node_y,
+ buf_node_z, y_index,
+ CQM_CLA_DEL_GPA_WITHOUT_CACHE_INVALID);
+ } else if (cla_table->cla_lvl == CQM_CLA_LVL_2) {
+ y_index = (index >> (cla_table->z + 1)) &
+ ((1U << (cla_table->y - cla_table->z)) - 1);
+ x_index = index >> (cla_table->y + 1);
+ tmp = x_index * (trunk_size / sizeof(dma_addr_t)) + y_index;
+
+ if (x_index >= cla_y_buf->buf_number || tmp >= cla_z_buf->buf_number) {
+ cqm_err(handle->dev_hdl,
+ "Cla put: index exceeds buf, x %u, y %u, y_buf_n %u, z_buf_n %u\n",
+ x_index, y_index, cla_y_buf->buf_number,
+ cla_z_buf->buf_number);
+ mutex_unlock(&cla_table->lock);
+ return;
+ }
+
+ buf_node_x = cla_x_buf->buf_list;
+ buf_node_y = &cla_y_buf->buf_list[x_index];
+ buf_node_z = &cla_z_buf->buf_list[tmp];
+ cqm_dbg("Cla put: 2L: z_refcount=0x%x, count=0x%x\n",
+ buf_node_z->refcount, count);
+
+ /* When the value of reference counting on the z node page is 0,
+ * the z node page is released.
+ */
+ buf_node_z->refcount -= count;
+ if (buf_node_z->refcount == 0) {
+ cqm_cla_free(cqm_handle, cla_table, buf_node_y,
+ buf_node_z, y_index,
+ CQM_CLA_DEL_GPA_WITHOUT_CACHE_INVALID);
+
+ /* When the value of reference counting on the y node
+ * page is 0, the y node page is released.
+ */
+ cqm_dbg("Cla put: 2L: y_refcount=0x%x\n",
+ buf_node_y->refcount);
+ buf_node_y->refcount--;
+ if (buf_node_y->refcount == 0)
+ /* Node y requires cache to be invalid. */
+ cqm_cla_free(cqm_handle, cla_table, buf_node_x, buf_node_y,
+ x_index, CQM_CLA_DEL_GPA_WITH_CACHE_INVALID);
+ }
+ }
+
+ mutex_unlock(&cla_table->lock);
+}
+
+/**
+ * Prototype : cqm_cla_table_get
+ * Description : Searches for the CLA table data structure corresponding to a
+ * BAT entry.
+ * Input : struct tag_cqm_bat_table *bat_table,
+ * u32 entry_type
+ * Output : None
+ * Return Value : struct tag_cqm_cla_table *
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+struct tag_cqm_cla_table *cqm_cla_table_get(struct tag_cqm_bat_table *bat_table,
+ u32 entry_type)
+{
+ struct tag_cqm_cla_table *cla_table = NULL;
+ u32 i = 0;
+
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ cla_table = &bat_table->entry[i];
+ if (cla_table && entry_type == cla_table->type)
+ return cla_table;
+ }
+
+ return NULL;
+}
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bat_cla.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bat_cla.h
new file mode 100644
index 0000000000000..dd0766e6d7557
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bat_cla.h
@@ -0,0 +1,214 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_BAT_CLA_H
+#define CQM_BAT_CLA_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+
+#include "cqm_bitmap_table.h"
+#include "cqm_object.h"
+
+/* When the connection check is enabled, the maximum number of connections
+ * supported by the chip is 1M - 63, which cannot reach 1M
+ */
+#define CQM_BAT_MAX_CONN_NUM (0x100000 - 63)
+#define CQM_BAT_MAX_CACHE_CONN_NUM (0x100000 - 63)
+
+#define CLA_TABLE_PAGE_ORDER 0
+#define CQM_4K_PAGE_ORDER 0
+#define CQM_4K_PAGE_SIZE 4096
+
+#define CQM_BAT_ENTRY_MAX 16
+#define CQM_BAT_ENTRY_SIZE 16
+#define CQM_BAT_STORE_API_SIZE 16
+
+#define CQM_BAT_SIZE_FT_RDMA_PF 240
+#define CQM_BAT_SIZE_FT_RDMA_VF 160
+#define CQM_BAT_SIZE_FT_PF 192
+#define CQM_BAT_SIZE_FT_VF 112
+#define CQM_BAT_SIZE_RDMA_PF 160
+#define CQM_BAT_SIZE_RDMA_VF 80
+
+#define CQM_BAT_INDEX0 0
+#define CQM_BAT_INDEX1 1
+#define CQM_BAT_INDEX2 2
+#define CQM_BAT_INDEX3 3
+#define CQM_BAT_INDEX4 4
+#define CQM_BAT_INDEX5 5
+#define CQM_BAT_INDEX6 6
+#define CQM_BAT_INDEX7 7
+#define CQM_BAT_INDEX8 8
+#define CQM_BAT_INDEX9 9
+#define CQM_BAT_INDEX10 10
+#define CQM_BAT_INDEX11 11
+#define CQM_BAT_INDEX12 12
+#define CQM_BAT_INDEX13 13
+#define CQM_BAT_INDEX14 14
+#define CQM_BAT_INDEX15 15
+
+enum cqm_bat_entry_type {
+ CQM_BAT_ENTRY_T_CFG = 0,
+ CQM_BAT_ENTRY_T_HASH = 1,
+ CQM_BAT_ENTRY_T_QPC = 2,
+ CQM_BAT_ENTRY_T_SCQC = 3,
+ CQM_BAT_ENTRY_T_SRQC = 4,
+ CQM_BAT_ENTRY_T_MPT = 5,
+ CQM_BAT_ENTRY_T_GID = 6,
+ CQM_BAT_ENTRY_T_LUN = 7,
+ CQM_BAT_ENTRY_T_TASKMAP = 8,
+ CQM_BAT_ENTRY_T_L3I = 9,
+ CQM_BAT_ENTRY_T_CHILDC = 10,
+ CQM_BAT_ENTRY_T_TIMER = 11,
+ CQM_BAT_ENTRY_T_XID2CID = 12,
+ CQM_BAT_ENTRY_T_REORDER = 13,
+ CQM_BAT_ENTRY_T_INVALID = 14,
+ CQM_BAT_ENTRY_T_MAX = 15,
+};
+
+/* CLA update mode */
+#define CQM_CLA_RECORD_NEW_GPA 0
+#define CQM_CLA_DEL_GPA_WITHOUT_CACHE_INVALID 1
+#define CQM_CLA_DEL_GPA_WITH_CACHE_INVALID 2
+
+#define CQM_CLA_LVL_0 0
+#define CQM_CLA_LVL_1 1
+#define CQM_CLA_LVL_2 2
+
+#define CQM_MAX_INDEX_BIT 19
+
+#define CQM_CHIP_CACHELINE 256
+#define CQM_CHIP_TIMER_CACHELINE 512
+#define CQM_OBJECT_256 256
+#define CQM_OBJECT_512 512
+#define CQM_OBJECT_1024 1024
+#define CQM_CHIP_GPA_MASK 0x1ffffffffffffff
+#define CQM_CHIP_GPA_HIMASK 0x1ffffff
+#define CQM_CHIP_GPA_LOMASK 0xffffffff
+#define CQM_CHIP_GPA_HSHIFT 32
+
+/* Aligns with 64 buckets and shifts rightward by 6 bits */
+#define CQM_HASH_NUMBER_UNIT 6
+
+struct tag_cqm_cla_table {
+ u32 type;
+ u32 max_buffer_size;
+ u32 obj_num;
+ bool alloc_static; /* Whether the buffer is statically allocated */
+ u32 cla_lvl;
+ u32 cacheline_x; /* x value calculated based on cacheline,
+ * used by the chip
+ */
+ u32 cacheline_y; /* y value calculated based on cacheline,
+ * used by the chip
+ */
+ u32 cacheline_z; /* z value calculated based on cacheline,
+ * used by the chip
+ */
+ u32 x; /* x value calculated based on obj_size, used by software */
+ u32 y; /* y value calculated based on obj_size, used by software */
+ u32 z; /* z value calculated based on obj_size, used by software */
+ struct tag_cqm_buf cla_x_buf;
+ struct tag_cqm_buf cla_y_buf;
+ struct tag_cqm_buf cla_z_buf;
+ u32 trunk_order; /* A continuous physical page contains 2^order pages */
+ u32 obj_size;
+ struct mutex lock; /* Lock for cla buffer allocation and free */
+
+ struct tag_cqm_bitmap bitmap;
+
+ struct tag_cqm_object_table obj_table; /* Mapping table between
+ * indexes and objects
+ */
+ char name[VRAM_NAME_APPLY_LEN];
+};
+
+struct tag_cqm_bat_entry_cfg {
+ u32 cur_conn_num_h_4 : 4;
+ u32 rsv1 : 4;
+ u32 max_conn_num : 20;
+ u32 rsv2 : 4;
+
+ u32 max_conn_cache : 10;
+ u32 rsv3 : 6;
+ u32 cur_conn_num_l_16 : 16;
+
+ u32 bloom_filter_addr : 16;
+ u32 cur_conn_cache : 10;
+ u32 rsv4 : 6;
+
+ u32 bucket_num : 16;
+ u32 bloom_filter_len : 16;
+};
+
+#define CQM_BAT_NO_BYPASS_CACHE 0
+#define CQM_BAT_BYPASS_CACHE 1
+
+#define CQM_BAT_ENTRY_SIZE_256 0
+#define CQM_BAT_ENTRY_SIZE_512 1
+#define CQM_BAT_ENTRY_SIZE_1024 2
+
+struct tag_cqm_bat_entry_standerd {
+ u32 entry_size : 2;
+ u32 rsv1 : 6;
+ u32 max_number : 20;
+ u32 rsv2 : 4;
+
+ u32 cla_gpa_h : 32;
+
+ u32 cla_gpa_l : 32;
+
+ u32 rsv3 : 8;
+ u32 z : 5;
+ u32 y : 5;
+ u32 x : 5;
+ u32 rsv24 : 1;
+ u32 bypass : 1;
+ u32 cla_level : 2;
+ u32 rsv5 : 5;
+};
+
+struct tag_cqm_bat_entry_vf2pf {
+ u32 cla_gpa_h : 25;
+ u32 pf_id : 5;
+ u32 fake_vf_en : 1;
+ u32 acs_spu_en : 1;
+};
+
+#define CQM_BAT_ENTRY_TASKMAP_NUM 4
+struct tag_cqm_bat_entry_taskmap_addr {
+ u32 gpa_h;
+ u32 gpa_l;
+};
+
+struct tag_cqm_bat_entry_taskmap {
+ struct tag_cqm_bat_entry_taskmap_addr addr[CQM_BAT_ENTRY_TASKMAP_NUM];
+};
+
+struct tag_cqm_bat_table {
+ u32 bat_entry_type[CQM_BAT_ENTRY_MAX];
+ u8 bat[CQM_BAT_ENTRY_MAX * CQM_BAT_ENTRY_SIZE];
+ struct tag_cqm_cla_table entry[CQM_BAT_ENTRY_MAX];
+ /* In LB mode 1, the timer needs to be configured in 4 SMFs,
+ * and the GPAs must be different and independent.
+ */
+ struct tag_cqm_cla_table timer_entry[4];
+ u32 bat_size;
+};
+
+s32 cqm_bat_init(struct tag_cqm_handle *cqm_handle);
+void cqm_bat_uninit(struct tag_cqm_handle *cqm_handle);
+s32 cqm_cla_init(struct tag_cqm_handle *cqm_handle);
+void cqm_cla_uninit(struct tag_cqm_handle *cqm_handle, u32 entry_numb);
+u8 *cqm_cla_get_unlock(struct tag_cqm_handle *cqm_handle, struct tag_cqm_cla_table *cla_table,
+ u32 index, u32 count, dma_addr_t *pa);
+u8 *cqm_cla_get_lock(struct tag_cqm_handle *cqm_handle, struct tag_cqm_cla_table *cla_table,
+ u32 index, u32 count, dma_addr_t *pa);
+void cqm_cla_put(struct tag_cqm_handle *cqm_handle, struct tag_cqm_cla_table *cla_table,
+ u32 index, u32 count);
+struct tag_cqm_cla_table *cqm_cla_table_get(struct tag_cqm_bat_table *bat_table,
+ u32 entry_type);
+u32 cqm_funcid2smfid(const struct tag_cqm_handle *cqm_handle);
+
+#endif /* CQM_BAT_CLA_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bitmap_table.c b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bitmap_table.c
new file mode 100644
index 0000000000000..e43b1679cbe8d
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bitmap_table.c
@@ -0,0 +1,1454 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/gfp.h>
+
+#include "ossl_knl.h"
+#include "hinic3_crm.h"
+#include "hinic3_hw.h"
+#include "hinic3_hwdev.h"
+#include "cqm_memsec.h"
+#include "cqm_object.h"
+#include "cqm_bat_cla.h"
+#include "cqm_cmd.h"
+#include "cqm_object_intern.h"
+#include "cqm_main.h"
+
+#include "cqm_npu_cmd.h"
+#include "cqm_npu_cmd_defs.h"
+#include "vram_common.h"
+
+#define common_section
+
+struct malloc_memory {
+ bool (*check_alloc_mode)(struct hinic3_hwdev *handle, struct tag_cqm_buf *buf);
+ s32 (*malloc_func)(struct hinic3_hwdev *handle, struct tag_cqm_buf *buf);
+};
+
+struct free_memory {
+ bool (*check_alloc_mode)(struct hinic3_hwdev *handle, struct tag_cqm_buf *buf);
+ void (*free_func)(struct tag_cqm_buf *buf);
+};
+
+/**
+ * Prototype : cqm_swab64(Encapsulation of __swab64)
+ * Description : Perform big-endian conversion for a memory block (8 bytes).
+ * Input : u8 *addr: Start address of the memory block
+ * u32 cnt: Number of 8 bytes in the memory block
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_swab64(u8 *addr, u32 cnt)
+{
+ u64 *temp = (u64 *)addr;
+ u64 value = 0;
+ u32 i;
+
+ for (i = 0; i < cnt; i++) {
+ value = __swab64(*temp);
+ *temp = value;
+ temp++;
+ }
+}
+
+/**
+ * Prototype : cqm_swab32(Encapsulation of __swab32)
+ * Description : Perform big-endian conversion for a memory block (4 bytes).
+ * Input : u8 *addr: Start address of the memory block
+ * u32 cnt: Number of 4 bytes in the memory block
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/7/23
+ * Modification : Created function
+ */
+void cqm_swab32(u8 *addr, u32 cnt)
+{
+ u32 *temp = (u32 *)addr;
+ u32 value = 0;
+ u32 i;
+
+ for (i = 0; i < cnt; i++) {
+ value = __swab32(*temp);
+ *temp = value;
+ temp++;
+ }
+}
+
+/**
+ * Prototype : cqm_shift
+ * Description : Calculates n in a 2^n number.(Find the logarithm of 2^n)
+ * Input : u32 data
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_shift(u32 data)
+{
+ u32 data_num = data;
+ s32 shift = -1;
+
+ do {
+ data_num >>= 1;
+ shift++;
+ } while (data_num);
+
+ return shift;
+}
+
+/**
+ * Prototype : cqm_check_align
+ * Description : Check whether the value is 2^n-aligned. If 0 or 1, false is
+ * returned.
+ * Input : u32 data
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/9/15
+ * Modification : Created function
+ */
+bool cqm_check_align(u32 data)
+{
+ u32 data_num = data;
+
+ if (data == 0)
+ return false;
+
+ /* Todo: (n & (n - 1) == 0) can be used to determine the value. */
+ do {
+ /* When the value can be exactly divided by 2,
+ * the value of data is shifted right by one bit, that is,
+ * divided by 2.
+ */
+ if ((data_num & 0x1) == 0)
+ data_num >>= 1;
+ /* If the value cannot be divisible by 2, the value is
+ * not 2^n-aligned and false is returned.
+ */
+ else
+ return false;
+ } while (data_num != 1);
+
+ return true;
+}
+
+/**
+ * Prototype : cqm_kmalloc_align
+ * Description : Allocates 2^n-byte-aligned memory for the start address.
+ * Input : size_t size
+ * gfp_t flags
+ * u16 align_order
+ * Output : None
+ * Return Value : void *
+ * 1.Date : 2017/9/22
+ * Modification : Created function
+ */
+void *cqm_kmalloc_align(size_t size, gfp_t flags, u16 align_order)
+{
+ void *orig_addr = NULL;
+ void *align_addr = NULL;
+ void *index_addr = NULL;
+
+ orig_addr = kmalloc(size + ((u64)1 << align_order) + sizeof(void *),
+ flags);
+ if (!orig_addr)
+ return NULL;
+
+ index_addr = (void *)((char *)orig_addr + sizeof(void *));
+ align_addr =
+ (void *)((((u64)index_addr + ((u64)1 << align_order) - 1) >>
+ align_order) << align_order);
+
+ /* Record the original memory address for memory release. */
+ index_addr = (void *)((char *)align_addr - sizeof(void *));
+ *(void **)index_addr = orig_addr;
+
+ return align_addr;
+}
+
+/**
+ * Prototype : cqm_kfree_align
+ * Description : Release the memory allocated for starting address alignment.
+ * Input : void *addr
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2017/9/22
+ * Modification : Created function
+ */
+void cqm_kfree_align(void *addr)
+{
+ void *index_addr = NULL;
+
+ /* Release the original memory address. */
+ index_addr = (void *)((char *)addr - sizeof(void *));
+
+ cqm_dbg("free aligned address: %p, original address: %p\n", addr,
+ *(void **)index_addr);
+
+ kfree(*(void **)index_addr);
+}
+
+static void cqm_write_lock(rwlock_t *lock, bool bh)
+{
+ if (bh)
+ write_lock_bh(lock);
+ else
+ write_lock(lock);
+}
+
+static void cqm_write_unlock(rwlock_t *lock, bool bh)
+{
+ if (bh)
+ write_unlock_bh(lock);
+ else
+ write_unlock(lock);
+}
+
+static void cqm_read_lock(rwlock_t *lock, bool bh)
+{
+ if (bh)
+ read_lock_bh(lock);
+ else
+ read_lock(lock);
+}
+
+static void cqm_read_unlock(rwlock_t *lock, bool bh)
+{
+ if (bh)
+ read_unlock_bh(lock);
+ else
+ read_unlock(lock);
+}
+
+static inline bool cqm_bat_entry_in_secure_mem(void *handle, u32 type)
+{
+ if (!cqm_need_secure_mem(handle))
+ return false;
+
+ if (type == CQM_BAT_ENTRY_T_QPC || type == CQM_BAT_ENTRY_T_SCQC ||
+ type == CQM_BAT_ENTRY_T_SRQC || type == CQM_BAT_ENTRY_T_MPT)
+ return true;
+
+ return false;
+}
+
+s32 cqm_buf_alloc_direct(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf, bool direct)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct page **pages = NULL;
+ u32 i, j, order;
+
+ order = (u32)get_order(buf->buf_size);
+
+ if (!direct) {
+ buf->direct.va = NULL;
+ return CQM_SUCCESS;
+ }
+
+ pages = vmalloc(sizeof(struct page *) * buf->page_number);
+ if (!pages)
+ return CQM_FAIL;
+
+ for (i = 0; i < buf->buf_number; i++) {
+ for (j = 0; j < ((u32)1 << order); j++)
+ pages[(ulong)(unsigned int)((i << order) + j)] =
+ (void *)virt_to_page((u8 *)(buf->buf_list[i].va) + (PAGE_SIZE * j));
+ }
+
+ buf->direct.va = vmap(pages, buf->page_number, VM_MAP, PAGE_KERNEL);
+ vfree(pages);
+ if (!buf->direct.va) {
+ cqm_err(handle->dev_hdl, CQM_MAP_FAIL(buf->direct.va));
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+static bool check_use_non_vram(struct hinic3_hwdev *handle, struct tag_cqm_buf *buf)
+{
+ return buf->buf_info.use_vram ? false : true;
+}
+
+static bool check_for_use_node_alloc(struct hinic3_hwdev *handle, struct tag_cqm_buf *buf)
+{
+ if (buf->buf_info.use_vram == 0 && handle->board_info.service_mode == 0)
+ return true;
+
+ return false;
+}
+
+static bool check_for_nouse_node_alloc(struct hinic3_hwdev *handle, struct tag_cqm_buf *buf)
+{
+ if (buf->buf_info.use_vram == 0 && handle->board_info.service_mode != 0)
+ return true;
+
+ return false;
+}
+
+static void cqm_buf_free_page_common(struct tag_cqm_buf *buf)
+{
+ u32 order;
+ s32 i;
+
+ order = (u32)get_order(buf->buf_size);
+
+ for (i = 0; i < (s32)buf->buf_number; i++) {
+ if (buf->buf_list[i].va) {
+ free_pages((ulong)(buf->buf_list[i].va), order);
+ buf->buf_list[i].va = NULL;
+ }
+ }
+}
+
+static s32 cqm_buf_use_node_alloc_page(struct hinic3_hwdev *handle, struct tag_cqm_buf *buf)
+{
+ struct page *newpage = NULL;
+ u32 order;
+ void *va = NULL;
+ s32 i, node;
+
+ order = (u32)get_order(buf->buf_size);
+ node = dev_to_node(handle->dev_hdl);
+ for (i = 0; i < (s32)buf->buf_number; i++) {
+ newpage = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, order);
+ if (!newpage)
+ break;
+ va = (void *)page_address(newpage);
+ /* Initialize the page after the page is applied for.
+ * If hash entries are involved, the initialization
+ * value must be 0.
+ */
+ memset(va, 0, buf->buf_size);
+ buf->buf_list[i].va = va;
+ }
+
+ if (i != buf->buf_number) {
+ cqm_buf_free_page_common(buf);
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_buf_unused_node_alloc_page(struct hinic3_hwdev *handle, struct tag_cqm_buf *buf)
+{
+ u32 order;
+ void *va = NULL;
+ s32 i;
+
+ order = (u32)get_order(buf->buf_size);
+
+ for (i = 0; i < (s32)buf->buf_number; i++) {
+ va = (void *)ossl_get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
+ if (!va)
+ break;
+ /* Initialize the page after the page is applied for.
+ * If hash entries are involved, the initialization
+ * value must be 0.
+ */
+ memset(va, 0, buf->buf_size);
+ buf->buf_list[i].va = va;
+ }
+
+ if (i != buf->buf_number) {
+ cqm_buf_free_page_common(buf);
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+static const struct malloc_memory g_malloc_funcs[] = {
+ {check_for_use_node_alloc, cqm_buf_use_node_alloc_page},
+ {check_for_nouse_node_alloc, cqm_buf_unused_node_alloc_page}
+};
+
+static const struct free_memory g_free_funcs[] = {
+ {check_use_non_vram, cqm_buf_free_page_common}
+};
+
+static s32 cqm_buf_alloc_page(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 malloc_funcs_num = ARRAY_SIZE(g_malloc_funcs);
+ u32 i;
+
+ for (i = 0; i < malloc_funcs_num; i++) {
+ if (g_malloc_funcs[i].check_alloc_mode &&
+ g_malloc_funcs[i].malloc_func &&
+ g_malloc_funcs[i].check_alloc_mode(handle, buf))
+ return g_malloc_funcs[i].malloc_func(handle, buf);
+ }
+
+ cqm_err(handle->dev_hdl, "Unknown alloc mode\n");
+
+ return CQM_FAIL;
+}
+
+static void cqm_buf_free_page(struct tag_cqm_buf *buf)
+{
+ u32 free_funcs_num = ARRAY_SIZE(g_free_funcs);
+ u32 i;
+
+ for (i = 0; i < free_funcs_num; i++) {
+ if (g_free_funcs[i].check_alloc_mode &&
+ g_free_funcs[i].free_func &&
+ g_free_funcs[i].check_alloc_mode(NULL, buf))
+ return g_free_funcs[i].free_func(buf);
+ }
+}
+
+static s32 cqm_buf_alloc_map(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct pci_dev *dev = cqm_handle->dev;
+ void *va = NULL;
+ s32 i;
+
+ for (i = 0; i < (s32)buf->buf_number; i++) {
+ va = buf->buf_list[i].va;
+ buf->buf_list[i].pa = pci_map_single(dev, va, buf->buf_size,
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(dev, buf->buf_list[i].pa)) {
+ cqm_err(handle->dev_hdl, CQM_MAP_FAIL(buf_list));
+ break;
+ }
+ }
+
+ if (i != buf->buf_number) {
+ i--;
+ for (; i >= 0; i--)
+ pci_unmap_single(dev, buf->buf_list[i].pa,
+ buf->buf_size, PCI_DMA_BIDIRECTIONAL);
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_buf_get_secure_mem_pages(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 i;
+
+ for (i = 0; i < buf->buf_number; i++) {
+ buf->buf_list[i].va =
+ cqm_get_secure_mem_pages(handle,
+ (u32)get_order(buf->buf_size),
+ &buf->buf_list[i].pa);
+ if (!buf->buf_list[i].va)
+ break;
+ }
+
+ if (i != buf->buf_number) {
+ cqm_free_secure_mem_pages(handle, buf->buf_list[0].va,
+ (u32)get_order(buf->buf_size));
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_buf_alloc
+ * Description : Apply for buffer space and DMA mapping for the struct tag_cqm_buf
+ * structure.
+ * Input : struct tag_cqm_buf *buf
+ * struct pci_dev *dev
+ * bool direct: Whether direct remapping is required
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_buf_alloc(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf, bool direct)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct pci_dev *dev = cqm_handle->dev;
+ s32 i;
+ s32 ret;
+
+ /* Applying for the buffer list descriptor space */
+ buf->buf_list = vmalloc(buf->buf_number * sizeof(struct tag_cqm_buf_list));
+ if (!buf->buf_list)
+ return CQM_FAIL;
+ memset(buf->buf_list, 0, buf->buf_number * sizeof(struct tag_cqm_buf_list));
+
+ /* Page for applying for each buffer */
+ if (cqm_bat_entry_in_secure_mem((void *)handle, buf->bat_entry_type))
+ ret = cqm_buf_get_secure_mem_pages(cqm_handle, buf);
+ else
+ ret = cqm_buf_alloc_page(cqm_handle, buf);
+
+ if (ret == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(linux_cqm_buf_alloc_page));
+ goto err1;
+ }
+
+ /* PCI mapping of the buffer */
+ if (!cqm_bat_entry_in_secure_mem((void *)handle, buf->bat_entry_type)) {
+ if (cqm_buf_alloc_map(cqm_handle, buf) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(linux_cqm_buf_alloc_map));
+ goto err2;
+ }
+ }
+
+ /* direct remapping */
+ if (cqm_buf_alloc_direct(cqm_handle, buf, direct) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_buf_alloc_direct));
+ goto err3;
+ }
+
+ return CQM_SUCCESS;
+
+err3:
+ if (!cqm_bat_entry_in_secure_mem((void *)handle, buf->bat_entry_type)) {
+ for (i = 0; i < (s32)buf->buf_number; i++) {
+ pci_unmap_single(dev, buf->buf_list[i].pa, buf->buf_size,
+ PCI_DMA_BIDIRECTIONAL);
+ }
+ }
+err2:
+ if (cqm_bat_entry_in_secure_mem((void *)handle, buf->bat_entry_type))
+ cqm_free_secure_mem_pages(handle, buf->buf_list[0].va,
+ (u32)get_order(buf->buf_size));
+ else
+ cqm_buf_free_page(buf);
+err1:
+ vfree(buf->buf_list);
+ buf->buf_list = NULL;
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_buf_free
+ * Description : Release the buffer space and DMA mapping for the struct tag_cqm_buf
+ * structure.
+ * Input : struct tag_cqm_buf *buf
+ * struct pci_dev *dev
+ * bool direct: Whether direct remapping is required
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_buf_free(struct tag_cqm_buf *buf, struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct pci_dev *dev = cqm_handle->dev;
+ s32 i;
+
+ if (buf->direct.va) {
+ vunmap(buf->direct.va);
+ buf->direct.va = NULL;
+ }
+
+ if (!buf->buf_list)
+ return;
+
+ if (cqm_bat_entry_in_secure_mem(handle, buf->bat_entry_type)) {
+ cqm_free_secure_mem_pages(handle, buf->buf_list[0].va,
+ (u32)get_order(buf->buf_size));
+ goto free;
+ }
+
+ for (i = 0; i < (s32)(buf->buf_number); i++) {
+ if (buf->buf_list[i].va)
+ pci_unmap_single(dev, buf->buf_list[i].pa,
+ buf->buf_size,
+ PCI_DMA_BIDIRECTIONAL);
+ }
+ cqm_buf_free_page(buf);
+
+free:
+ vfree(buf->buf_list);
+ buf->buf_list = NULL;
+}
+
+static s32 cqm_cla_cache_invalid_cmd(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_cmd_buf *buf_in,
+ struct tag_cqm_cla_cache_invalid_cmd *cmd)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_cla_cache_invalid_cmd *cla_cache_invalid_cmd = NULL;
+ s32 ret;
+
+ cla_cache_invalid_cmd = (struct tag_cqm_cla_cache_invalid_cmd *)(buf_in->buf);
+ cla_cache_invalid_cmd->gpa_h = cmd->gpa_h;
+ cla_cache_invalid_cmd->gpa_l = cmd->gpa_l;
+ cla_cache_invalid_cmd->cache_size = cmd->cache_size;
+ cla_cache_invalid_cmd->smf_id = cmd->smf_id;
+ cla_cache_invalid_cmd->func_id = cmd->func_id;
+
+ cqm_swab32((u8 *)cla_cache_invalid_cmd,
+ /* shift 2 bits by right to get length of dw(4B) */
+ (sizeof(struct tag_cqm_cla_cache_invalid_cmd) >> 2));
+
+ /* Send the cmdq command. */
+ ret = cqm_send_cmd_box((void *)(cqm_handle->ex_handle), CQM_MOD_CQM,
+ CQM_CMD_T_CLA_CACHE_INVALID, buf_in, NULL, NULL,
+ CQM_CMD_TIMEOUT, HINIC3_CHANNEL_DEFAULT);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_send_cmd_box));
+ cqm_err(handle->dev_hdl,
+ "Cla cache invalid: cqm_send_cmd_box_ret=%d\n",
+ ret);
+ cqm_err(handle->dev_hdl,
+ "Cla cache invalid: cla_cache_invalid_cmd: 0x%x 0x%x 0x%x\n",
+ cmd->gpa_h, cmd->gpa_l, cmd->cache_size);
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+s32 cqm_cla_cache_invalid(struct tag_cqm_handle *cqm_handle, dma_addr_t pa, u32 cache_size)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_cmd_buf *buf_in = NULL;
+ struct hinic3_func_attr *func_attr = NULL;
+ struct tag_cqm_bat_entry_vf2pf gpa = {0};
+ struct tag_cqm_cla_cache_invalid_cmd cmd;
+ u32 cla_gpa_h = 0;
+ s32 ret = CQM_FAIL;
+ u32 i;
+
+ buf_in = cqm_cmd_alloc((void *)(cqm_handle->ex_handle));
+ if (!buf_in)
+ return CQM_FAIL;
+ buf_in->size = sizeof(struct tag_cqm_cla_cache_invalid_cmd);
+
+ gpa.cla_gpa_h = CQM_ADDR_HI(pa) & CQM_CHIP_GPA_HIMASK;
+
+ /* On the SPU, the value of spu_en in the GPA address
+ * in the BAT is determined by the host ID and fun IDx.
+ */
+ if (hinic3_host_id(cqm_handle->ex_handle) == CQM_SPU_HOST_ID) {
+ func_attr = &cqm_handle->func_attribute;
+ gpa.acs_spu_en = func_attr->func_global_idx & 0x1;
+ } else {
+ gpa.acs_spu_en = 0;
+ }
+
+ /* In non-fake mode, set func_id to 0xffff.
+ * Indicate the current func fake mode.
+ * The value of func_id is a fake func ID.
+ */
+ if (cqm_handle->func_capability.fake_func_type == CQM_FAKE_FUNC_CHILD) {
+ cmd.func_id = cqm_handle->func_attribute.func_global_idx;
+ func_attr = &cqm_handle->parent_cqm_handle->func_attribute;
+ gpa.fake_vf_en = 1;
+ gpa.pf_id = func_attr->func_global_idx;
+ } else {
+ cmd.func_id = 0xffff;
+ }
+
+ memcpy(&cla_gpa_h, &gpa, sizeof(u32));
+
+ /* Fill command and convert it to big endian */
+ cmd.cache_size = cache_size;
+ cmd.gpa_l = CQM_ADDR_LW(pa);
+ cmd.gpa_h = cla_gpa_h;
+
+ /* The normal mode is the 1822 traditional mode and is all configured
+ * on SMF0.
+ */
+ /* Mode 0 is hashed to 4 SMF engines (excluding PPF) by func ID. */
+ if (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_NORMAL ||
+ (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_0 &&
+ cqm_handle->func_attribute.func_type != CQM_PPF)) {
+ cmd.smf_id = cqm_funcid2smfid(cqm_handle);
+ ret = cqm_cla_cache_invalid_cmd(cqm_handle, buf_in, &cmd);
+ /* Mode 1/2 are allocated to 4 SMF engines by flow. Therefore,
+ * one function needs to be allocated to 4 SMF engines.
+ */
+ /* The PPF in mode 0 needs to be configured on 4 engines,
+ * and the timer resources need to be shared by the 4 engines.
+ */
+ } else if (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_1 ||
+ cqm_handle->func_capability.lb_mode == CQM_LB_MODE_2 ||
+ (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_0 &&
+ cqm_handle->func_attribute.func_type == CQM_PPF)) {
+ for (i = 0; i < CQM_LB_SMF_MAX; i++) {
+ /* The smf_pg stored currently enabled SMF engine. */
+ if (cqm_handle->func_capability.smf_pg & (1U << i)) {
+ cmd.smf_id = i;
+ ret = cqm_cla_cache_invalid_cmd(cqm_handle,
+ buf_in, &cmd);
+ if (ret != CQM_SUCCESS)
+ goto out;
+ }
+ }
+ } else {
+ cqm_err(handle->dev_hdl, "Cla cache invalid: unsupport lb mode=%u\n",
+ cqm_handle->func_capability.lb_mode);
+ ret = CQM_FAIL;
+ }
+
+out:
+ cqm_cmd_free((void *)(cqm_handle->ex_handle), buf_in);
+ return ret;
+}
+
+static void free_cache_inv(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf,
+ s32 *inv_flag)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 order;
+ s32 i;
+
+ order = (u32)get_order(buf->buf_size);
+
+ if (!handle->chip_present_flag)
+ return;
+
+ if (!buf->buf_list)
+ return;
+
+ for (i = 0; i < (s32)(buf->buf_number); i++) {
+ if (!buf->buf_list[i].va)
+ continue;
+
+ if (*inv_flag != CQM_SUCCESS)
+ continue;
+
+ /* In the Pangea environment, if the cmdq times out,
+ * no subsequent message is sent.
+ */
+ *inv_flag = cqm_cla_cache_invalid(cqm_handle, buf->buf_list[i].pa,
+ (u32)(PAGE_SIZE << order));
+ if (*inv_flag != CQM_SUCCESS)
+ cqm_err(handle->dev_hdl,
+ "Buffer free: fail to invalid buf_list pa cache, inv_flag=%d\n",
+ *inv_flag);
+ }
+}
+
+void cqm_buf_free_cache_inv(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf,
+ s32 *inv_flag)
+{
+ /* Send a command to the chip to kick out the cache. */
+ free_cache_inv(cqm_handle, buf, inv_flag);
+
+ /* Clear host resources */
+ cqm_buf_free(buf, cqm_handle);
+}
+
+void cqm_byte_print(u32 *ptr, u32 len)
+{
+ u32 i;
+ u32 len_num = len;
+
+ len_num = (len_num >> 0x2);
+ for (i = 0; i < len_num; i = i + 0x4) {
+ cqm_dbg("%.8x %.8x %.8x %.8x\n", ptr[i], ptr[i + 1],
+ ptr[i + 2], /* index increases by 2 */
+ ptr[i + 3]); /* index increases by 3 */
+ }
+}
+
+#define bitmap_section
+
+/**
+ * Prototype : cqm_single_bitmap_init
+ * Description : Initialize a bitmap.
+ * Input : struct tag_cqm_bitmap *bitmap
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/9/9
+ * Modification : Created function
+ */
+static s32 cqm_single_bitmap_init(struct tag_cqm_bitmap *bitmap)
+{
+ u32 bit_number;
+
+ spin_lock_init(&bitmap->lock);
+
+ /* Max_num of the bitmap is 8-aligned and then
+ * shifted rightward by 3 bits to obtain the number of bytes required.
+ */
+ bit_number = (ALIGN(bitmap->max_num, CQM_NUM_BIT_BYTE) >>
+ CQM_BYTE_BIT_SHIFT);
+ bitmap->table = vmalloc(bit_number);
+ if (!bitmap->table)
+ return CQM_FAIL;
+ memset(bitmap->table, 0, bit_number);
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_bitmap_toe_init(struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_bitmap *bitmap = NULL;
+
+ /* SRQC of TOE services is not managed through the CLA table,
+ * but the bitmap is required to manage SRQid.
+ */
+ if (cqm_handle->service[CQM_SERVICE_T_TOE].valid) {
+ bitmap = &cqm_handle->toe_own_capability.srqc_bitmap;
+ bitmap->max_num =
+ cqm_handle->toe_own_capability.toe_srqc_number;
+ bitmap->reserved_top = 0;
+ bitmap->reserved_back = 0;
+ bitmap->last = 0;
+ if (bitmap->max_num == 0) {
+ cqm_info(handle->dev_hdl,
+ "Bitmap init: toe_srqc_number=0, don't init bitmap\n");
+ return CQM_SUCCESS;
+ }
+
+ if (cqm_single_bitmap_init(bitmap) != CQM_SUCCESS)
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+static void cqm_bitmap_toe_uninit(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_bitmap *bitmap = NULL;
+
+ if (cqm_handle->service[CQM_SERVICE_T_TOE].valid) {
+ bitmap = &cqm_handle->toe_own_capability.srqc_bitmap;
+ if (bitmap->table) {
+ spin_lock_deinit(&bitmap->lock);
+ vfree(bitmap->table);
+ bitmap->table = NULL;
+ }
+ }
+}
+
+/**
+ * Prototype : cqm_bitmap_init
+ * Description : Initialize the bitmap.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_bitmap_init(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_func_capability *capability = &cqm_handle->func_capability;
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_bitmap *bitmap = NULL;
+ s32 ret = CQM_SUCCESS;
+ u32 i;
+
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ cla_table = &bat_table->entry[i];
+ if (cla_table->obj_num == 0) {
+ cqm_info(handle->dev_hdl,
+ "Cla alloc: cla_type %u, obj_num=0, don't init bitmap\n",
+ cla_table->type);
+ continue;
+ }
+
+ bitmap = &cla_table->bitmap;
+ snprintf(bitmap->bitmap_info.buf_vram_name, VRAM_NAME_MAX_LEN - 1,
+ "%s%s%02d", cla_table->name,
+ VRAM_CQM_BITMAP_BASE, cla_table->type);
+
+ switch (cla_table->type) {
+ case CQM_BAT_ENTRY_T_QPC:
+ bitmap->max_num = capability->qpc_number;
+ bitmap->reserved_top = capability->qpc_reserved;
+ bitmap->reserved_back = capability->qpc_reserved_back;
+ bitmap->last = capability->qpc_reserved;
+ cqm_info(handle->dev_hdl,
+ "Bitmap init: cla_table_type=%u, max_num=0x%x\n",
+ cla_table->type, bitmap->max_num);
+ ret = cqm_single_bitmap_init(bitmap);
+ break;
+ case CQM_BAT_ENTRY_T_MPT:
+ bitmap->max_num = capability->mpt_number;
+ bitmap->reserved_top = capability->mpt_reserved;
+ bitmap->reserved_back = 0;
+ bitmap->last = capability->mpt_reserved;
+ cqm_info(handle->dev_hdl,
+ "Bitmap init: cla_table_type=%u, max_num=0x%x\n",
+ cla_table->type, bitmap->max_num);
+ ret = cqm_single_bitmap_init(bitmap);
+ break;
+ case CQM_BAT_ENTRY_T_SCQC:
+ bitmap->max_num = capability->scqc_number;
+ bitmap->reserved_top = capability->scq_reserved;
+ bitmap->reserved_back = 0;
+ bitmap->last = capability->scq_reserved;
+ cqm_info(handle->dev_hdl,
+ "Bitmap init: cla_table_type=%u, max_num=0x%x\n",
+ cla_table->type, bitmap->max_num);
+ ret = cqm_single_bitmap_init(bitmap);
+ break;
+ case CQM_BAT_ENTRY_T_SRQC:
+ bitmap->max_num = capability->srqc_number;
+ bitmap->reserved_top = capability->srq_reserved;
+ bitmap->reserved_back = 0;
+ bitmap->last = capability->srq_reserved;
+ cqm_info(handle->dev_hdl,
+ "Bitmap init: cla_table_type=%u, max_num=0x%x\n",
+ cla_table->type, bitmap->max_num);
+ ret = cqm_single_bitmap_init(bitmap);
+ break;
+ default:
+ break;
+ }
+
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ "Bitmap init: failed to init cla_table_type=%u, obj_num=0x%x\n",
+ cla_table->type, cla_table->obj_num);
+ goto err;
+ }
+ }
+
+ if (cqm_bitmap_toe_init(cqm_handle) != CQM_SUCCESS)
+ goto err;
+
+ return CQM_SUCCESS;
+
+err:
+ cqm_bitmap_uninit(cqm_handle);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_bitmap_uninit
+ * Description : Deinitialize the bitmap.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_bitmap_uninit(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_bitmap *bitmap = NULL;
+ u32 i;
+
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ cla_table = &bat_table->entry[i];
+ bitmap = &cla_table->bitmap;
+ if (cla_table->type != CQM_BAT_ENTRY_T_INVALID &&
+ bitmap->table) {
+ spin_lock_deinit(&bitmap->lock);
+ vfree(bitmap->table);
+ bitmap->table = NULL;
+ }
+ }
+
+ cqm_bitmap_toe_uninit(cqm_handle);
+}
+
+/**
+ * Prototype : cqm_bitmap_check_range
+ * Description : Starting from begin, check whether the bits in number of count
+ * are idle in the table. Requirement:
+ * 1. This group of bits cannot cross steps.
+ * 2. This group of bits must be 0.
+ * Input : const ulong *table,
+ * u32 step,
+ * u32 max_num,
+ * u32 begin,
+ * u32 count
+ * Output : None
+ * Return Value : u32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+static u32 cqm_bitmap_check_range(const ulong *table, u32 step, u32 max_num, u32 begin,
+ u32 count)
+{
+ u32 end = (begin + (count - 1));
+ u32 i;
+
+ /* Single-bit check is not performed. */
+ if (count == 1)
+ return begin;
+
+ /* The end value exceeds the threshold. */
+ if (end >= max_num)
+ return max_num;
+
+ /* Bit check, the next bit is returned when a non-zero bit is found. */
+ for (i = (begin + 1); i <= end; i++) {
+ if (test_bit((int)i, table))
+ return i + 1;
+ }
+
+ /* Check whether it's in different steps. */
+ if ((begin & (~(step - 1))) != (end & (~(step - 1))))
+ return (end & (~(step - 1)));
+
+ /* If the check succeeds, begin is returned. */
+ return begin;
+}
+
+static void cqm_bitmap_find(struct tag_cqm_bitmap *bitmap, u32 *index, u32 last,
+ u32 step, u32 count)
+{
+ u32 last_num = last;
+ u32 max_num = bitmap->max_num - bitmap->reserved_back;
+ ulong *table = bitmap->table;
+
+ do {
+ *index = (u32)find_next_zero_bit(table, max_num, last_num);
+ if (*index < max_num)
+ last_num = cqm_bitmap_check_range(table, step, max_num,
+ *index, count);
+ else
+ break;
+ } while (last_num != *index);
+}
+
+static void cqm_bitmap_find_with_low2bit_align(struct tag_cqm_bitmap *bitmap, u32 *index,
+ u32 max_num, u32 last, u32 low2bit)
+{
+ ulong *table = bitmap->table;
+ u32 offset = last;
+
+ while (offset < max_num) {
+ *index = (u32)find_next_zero_bit(table, max_num, offset);
+ if (*index >= max_num)
+ break;
+
+ if ((*index & 0x3) == (low2bit & 0x3)) /* 0x3 used for low2bit align */
+ break;
+
+ offset = *index + 1;
+ if (offset == max_num)
+ *index = max_num;
+ }
+}
+
+/**
+ * Prototype : cqm_bitmap_alloc
+ * Description : Apply for a bitmap index. 0 and 1 must be left blank.
+ * Scan backwards from where you last applied.
+ * A string of consecutive indexes must be applied for and
+ * cannot be applied for across trunks.
+ * Input : struct tag_cqm_bitmap *bitmap,
+ * u32 step,
+ * u32 count
+ * Output : None
+ * Return Value : u32
+ * The obtained index is returned.
+ * If a failure occurs, the value of max is returned.
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+u32 cqm_bitmap_alloc(struct tag_cqm_bitmap *bitmap, u32 step, u32 count, bool update_last)
+{
+ u32 index = 0;
+ u32 max_num = bitmap->max_num - bitmap->reserved_back;
+ u32 last = bitmap->last;
+ ulong *table = bitmap->table;
+ u32 i;
+
+ spin_lock(&bitmap->lock);
+
+ /* Search for an idle bit from the last position. */
+ cqm_bitmap_find(bitmap, &index, last, step, count);
+
+ /* The preceding search fails. Search for an idle bit
+ * from the beginning.
+ */
+ if (index >= max_num) {
+ last = bitmap->reserved_top;
+ cqm_bitmap_find(bitmap, &index, last, step, count);
+ }
+
+ /* Set the found bit to 1 and reset last. */
+ if (index < max_num) {
+ for (i = index; i < (index + count); i++)
+ set_bit(i, table);
+
+ if (update_last) {
+ bitmap->last = (index + count);
+ if (bitmap->last >= max_num)
+ bitmap->last = bitmap->reserved_top;
+ }
+ }
+
+ spin_unlock(&bitmap->lock);
+ return index;
+}
+
+/**
+ * Prototype : cqm_bitmap_alloc_low2bit_align
+ * Description : Apply for a bitmap index with low2bit align. 0 and 1 must be left blank.
+ * Scan backwards from where you last applied.
+ * A string of consecutive indexes must be applied for and
+ * cannot be applied for across trunks.
+ * Input : struct tag_cqm_bitmap *bitmap,
+ * u32 low2bit,
+ * bool update_last
+ * Output : None
+ * Return Value : u32
+ * The obtained index is returned.
+ * If a failure occurs, the value of max is returned.
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+u32 cqm_bitmap_alloc_low2bit_align(struct tag_cqm_bitmap *bitmap, u32 low2bit, bool update_last)
+{
+ u32 index = 0;
+ u32 max_num = bitmap->max_num - bitmap->reserved_back;
+ u32 last = bitmap->last;
+ ulong *table = bitmap->table;
+
+ spin_lock(&bitmap->lock);
+
+ /* Search for an idle bit from the last position. */
+ cqm_bitmap_find_with_low2bit_align(bitmap, &index, max_num, last, low2bit);
+
+ /* The preceding search fails. Search for an idle bit from the beginning. */
+ if (index >= max_num) {
+ last = bitmap->reserved_top;
+ cqm_bitmap_find_with_low2bit_align(bitmap, &index, max_num, last, low2bit);
+ }
+
+ /* Set the found bit to 1 and reset last. */
+ if (index < max_num) {
+ set_bit(index, table);
+
+ if (update_last) {
+ bitmap->last = index;
+ if (bitmap->last >= max_num)
+ bitmap->last = bitmap->reserved_top;
+ }
+ }
+
+ spin_unlock(&bitmap->lock);
+ return index;
+}
+
+/**
+ * Prototype : cqm_bitmap_alloc_reserved
+ * Description : Reserve bit applied for based on index.
+ * Input : struct tag_cqm_bitmap *bitmap,
+ * u32 count,
+ * u32 index
+ * Output : None
+ * Return Value : u32
+ * The obtained index is returned.
+ * If a failure occurs, the value of max is returned.
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+u32 cqm_bitmap_alloc_reserved(struct tag_cqm_bitmap *bitmap, u32 count, u32 index)
+{
+ ulong *table = bitmap->table;
+ u32 ret_index;
+
+ if (index >= bitmap->max_num || count != 1)
+ return CQM_INDEX_INVALID;
+
+ if (index >= bitmap->reserved_top && (index < bitmap->max_num - bitmap->reserved_back))
+ return CQM_INDEX_INVALID;
+
+ spin_lock(&bitmap->lock);
+
+ if (test_bit((int)index, table)) {
+ ret_index = CQM_INDEX_INVALID;
+ } else {
+ set_bit(index, table);
+ ret_index = index;
+ }
+
+ spin_unlock(&bitmap->lock);
+ return ret_index;
+}
+
+/**
+ * Prototype : cqm_bitmap_free
+ * Description : Releases a bitmap index.
+ * Input : struct tag_cqm_bitmap *bitmap,
+ * u32 index,
+ * u32 count
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_bitmap_free(struct tag_cqm_bitmap *bitmap, u32 index, u32 count)
+{
+ u32 i;
+
+ spin_lock(&bitmap->lock);
+
+ for (i = index; i < (index + count); i++)
+ clear_bit((s32)i, bitmap->table);
+
+ spin_unlock(&bitmap->lock);
+}
+
+#define obj_table_section
+
+/**
+ * Prototype : cqm_single_object_table_init
+ * Description : Initialize a object table.
+ * Input : struct tag_cqm_object_table *obj_table
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/9/9
+ * Modification : Created function
+ */
+static s32 cqm_single_object_table_init(struct tag_cqm_object_table *obj_table)
+{
+ rwlock_init(&obj_table->lock);
+
+ obj_table->table = vmalloc(obj_table->max_num * sizeof(void *));
+ if (!obj_table->table)
+ return CQM_FAIL;
+ memset(obj_table->table, 0, obj_table->max_num * sizeof(void *));
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_object_table_init
+ * Description : Initialize the association table between objects and indexes.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_object_table_init(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_func_capability *capability = &cqm_handle->func_capability;
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_object_table *obj_table = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ s32 ret = CQM_SUCCESS;
+ u32 i;
+
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ cla_table = &bat_table->entry[i];
+ if (cla_table->obj_num == 0) {
+ cqm_info(handle->dev_hdl,
+ "Obj table init: cla_table_type %u, obj_num=0, don't init obj table\n",
+ cla_table->type);
+ continue;
+ }
+
+ obj_table = &cla_table->obj_table;
+
+ switch (cla_table->type) {
+ case CQM_BAT_ENTRY_T_QPC:
+ obj_table->max_num = capability->qpc_number;
+ ret = cqm_single_object_table_init(obj_table);
+ break;
+ case CQM_BAT_ENTRY_T_MPT:
+ obj_table->max_num = capability->mpt_number;
+ ret = cqm_single_object_table_init(obj_table);
+ break;
+ case CQM_BAT_ENTRY_T_SCQC:
+ obj_table->max_num = capability->scqc_number;
+ ret = cqm_single_object_table_init(obj_table);
+ break;
+ case CQM_BAT_ENTRY_T_SRQC:
+ obj_table->max_num = capability->srqc_number;
+ ret = cqm_single_object_table_init(obj_table);
+ break;
+ default:
+ break;
+ }
+
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ "Obj table init: failed to init cla_table_type=%u, obj_num=0x%x\n",
+ cla_table->type, cla_table->obj_num);
+ goto err;
+ }
+ }
+
+ return CQM_SUCCESS;
+
+err:
+ cqm_object_table_uninit(cqm_handle);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_object_table_uninit
+ * Description : Deinitialize the association table between objects and
+ * indexes.
+ * Input : struct tag_cqm_handle *cqm_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_object_table_uninit(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct tag_cqm_object_table *obj_table = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ u32 i;
+
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ cla_table = &bat_table->entry[i];
+ obj_table = &cla_table->obj_table;
+ if (cla_table->type != CQM_BAT_ENTRY_T_INVALID) {
+ if (obj_table->table) {
+ rwlock_deinit(&obj_table->lock);
+ vfree(obj_table->table);
+ obj_table->table = NULL;
+ }
+ }
+ }
+}
+
+/**
+ * Prototype : cqm_object_table_insert
+ * Description : Insert an object
+ * Input : struct tag_cqm_handle *cqm_handle
+ * struct tag_cqm_object_table *object_table
+ * u32 index
+ * struct tag_cqm_object *obj
+ * bool bh
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_object_table_insert(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_object_table *object_table,
+ u32 index, struct tag_cqm_object *obj, bool bh)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ if (index >= object_table->max_num) {
+ cqm_err(handle->dev_hdl,
+ "Obj table insert: index 0x%x exceeds max_num 0x%x\n",
+ index, object_table->max_num);
+ return CQM_FAIL;
+ }
+
+ cqm_write_lock(&object_table->lock, bh);
+
+ if (!object_table->table[index]) {
+ object_table->table[index] = obj;
+ cqm_write_unlock(&object_table->lock, bh);
+ return CQM_SUCCESS;
+ }
+
+ cqm_write_unlock(&object_table->lock, bh);
+ cqm_err(handle->dev_hdl,
+ "Obj table insert: object_table->table[0x%x] has been inserted\n",
+ index);
+
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_object_table_remove
+ * Description : Remove an object
+ * Input : struct tag_cqm_handle *cqm_handle
+ * struct tag_cqm_object_table *object_table
+ * u32 index
+ * const struct tag_cqm_object *obj
+ * bool bh
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_object_table_remove(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_object_table *object_table,
+ u32 index, const struct tag_cqm_object *obj, bool bh)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ if (index >= object_table->max_num) {
+ cqm_err(handle->dev_hdl,
+ "Obj table remove: index 0x%x exceeds max_num 0x%x\n",
+ index, object_table->max_num);
+ return;
+ }
+
+ cqm_write_lock(&object_table->lock, bh);
+
+ if (object_table->table[index] && object_table->table[index] == obj)
+ object_table->table[index] = NULL;
+ else
+ cqm_err(handle->dev_hdl,
+ "Obj table remove: object_table->table[0x%x] has been removed\n",
+ index);
+
+ cqm_write_unlock(&object_table->lock, bh);
+}
+
+/**
+ * Prototype : cqm_object_table_get
+ * Description : Remove an object
+ * Input : struct tag_cqm_handle *cqm_handle
+ * struct tag_cqm_object_table *object_table
+ * u32 index
+ * bool bh
+ * Output : None
+ * Return Value : struct tag_cqm_object *obj
+ * 1.Date : 2018/6/20
+ * Modification : Created function
+ */
+struct tag_cqm_object *cqm_object_table_get(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_object_table *object_table,
+ u32 index, bool bh)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_object *obj = NULL;
+
+ if (index >= object_table->max_num) {
+ cqm_err(handle->dev_hdl,
+ "Obj table get: index 0x%x exceeds max_num 0x%x\n",
+ index, object_table->max_num);
+ return NULL;
+ }
+
+ cqm_read_lock(&object_table->lock, bh);
+
+ obj = object_table->table[index];
+ if (obj)
+ atomic_inc(&obj->refcount);
+
+ cqm_read_unlock(&object_table->lock, bh);
+
+ return obj;
+}
+
+u32 cqm_bitmap_alloc_by_xid(struct tag_cqm_bitmap *bitmap, u32 count, u32 index)
+{
+ ulong *table = bitmap->table;
+ u32 ret_index;
+
+ if (index >= bitmap->max_num || count != 1)
+ return CQM_INDEX_INVALID;
+
+ spin_lock(&bitmap->lock);
+
+ if (test_bit((int)index, table)) {
+ ret_index = CQM_INDEX_INVALID;
+ } else {
+ set_bit(index, table);
+ ret_index = index;
+ }
+
+ spin_unlock(&bitmap->lock);
+ return ret_index;
+}
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bitmap_table.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bitmap_table.h
new file mode 100644
index 0000000000000..7febf767fc67e
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bitmap_table.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_BITMAP_TABLE_H
+#define CQM_BITMAP_TABLE_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+#include "cqm_object.h"
+
+struct tag_cqm_bitmap {
+ ulong *table;
+ u32 max_num;
+ u32 last;
+ u32 reserved_top; /* reserved index */
+ u32 reserved_back;
+ spinlock_t lock; /* lock for cqm */
+ struct vram_buf_info bitmap_info;
+};
+
+struct tag_cqm_object_table {
+ /* Now is big array. Later will be optimized as a red-black tree. */
+ struct tag_cqm_object **table;
+ u32 max_num;
+ rwlock_t lock;
+};
+
+struct tag_cqm_handle;
+
+s32 cqm_bitmap_init(struct tag_cqm_handle *cqm_handle);
+void cqm_bitmap_uninit(struct tag_cqm_handle *cqm_handle);
+u32 cqm_bitmap_alloc(struct tag_cqm_bitmap *bitmap, u32 step, u32 count, bool update_last);
+u32 cqm_bitmap_alloc_low2bit_align(struct tag_cqm_bitmap *bitmap, u32 low2bit, bool update_last);
+u32 cqm_bitmap_alloc_reserved(struct tag_cqm_bitmap *bitmap, u32 count, u32 index);
+void cqm_bitmap_free(struct tag_cqm_bitmap *bitmap, u32 index, u32 count);
+s32 cqm_object_table_init(struct tag_cqm_handle *cqm_handle);
+void cqm_object_table_uninit(struct tag_cqm_handle *cqm_handle);
+s32 cqm_object_table_insert(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_object_table *object_table,
+ u32 index, struct tag_cqm_object *obj, bool bh);
+void cqm_object_table_remove(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_object_table *object_table,
+ u32 index, const struct tag_cqm_object *obj, bool bh);
+struct tag_cqm_object *cqm_object_table_get(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_object_table *object_table,
+ u32 index, bool bh);
+u32 cqm_bitmap_alloc_by_xid(struct tag_cqm_bitmap *bitmap, u32 count, u32 index);
+
+void cqm_swab64(u8 *addr, u32 cnt);
+void cqm_swab32(u8 *addr, u32 cnt);
+bool cqm_check_align(u32 data);
+s32 cqm_shift(u32 data);
+s32 cqm_buf_alloc(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf, bool direct);
+s32 cqm_buf_alloc_direct(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf, bool direct);
+void cqm_buf_free(struct tag_cqm_buf *buf, struct tag_cqm_handle *cqm_handle);
+void cqm_buf_free_cache_inv(struct tag_cqm_handle *cqm_handle, struct tag_cqm_buf *buf,
+ s32 *inv_flag);
+s32 cqm_cla_cache_invalid(struct tag_cqm_handle *cqm_handle, dma_addr_t gpa,
+ u32 cache_size);
+void *cqm_kmalloc_align(size_t size, gfp_t flags, u16 align_order);
+void cqm_kfree_align(void *addr);
+void cqm_byte_print(u32 *ptr, u32 len);
+
+#endif /* CQM_BITMAP_TABLE_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bloomfilter.c b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bloomfilter.c
new file mode 100644
index 0000000000000..5ff669733ac29
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bloomfilter.c
@@ -0,0 +1,535 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include "ossl_knl.h"
+#include "hinic3_crm.h"
+#include "hinic3_hw.h"
+#include "hinic3_hwdev.h"
+
+#include "cqm_object.h"
+#include "cqm_bitmap_table.h"
+#include "cqm_bat_cla.h"
+#include "cqm_cmd.h"
+#include "cqm_main.h"
+#include "cqm_bloomfilter.h"
+
+#include "cqm_npu_cmd.h"
+#include "cqm_npu_cmd_defs.h"
+
+/**
+ * Prototype : bloomfilter_init_cmd
+ * Description : host send cmd to ucode to init bloomfilter mem
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2016/8/13
+ * Modification : Created function
+ */
+static s32 bloomfilter_init_cmd(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_func_capability *capability = &cqm_handle->func_capability;
+ struct tag_cqm_bloomfilter_init_cmd *cmd = NULL;
+ struct tag_cqm_cmd_buf *buf_in = NULL;
+ s32 ret;
+
+ buf_in = cqm_cmd_alloc((void *)(cqm_handle->ex_handle));
+ if (!buf_in)
+ return CQM_FAIL;
+
+ /* Fill the command format and convert it to big-endian. */
+ buf_in->size = sizeof(struct tag_cqm_bloomfilter_init_cmd);
+ cmd = (struct tag_cqm_bloomfilter_init_cmd *)(buf_in->buf);
+ cmd->bloom_filter_addr = capability->bloomfilter_addr;
+ cmd->bloom_filter_len = capability->bloomfilter_length;
+
+ cqm_swab32((u8 *)cmd,
+ (sizeof(struct tag_cqm_bloomfilter_init_cmd) >> CQM_DW_SHIFT));
+
+ ret = cqm_send_cmd_box((void *)(cqm_handle->ex_handle),
+ CQM_MOD_CQM, CQM_CMD_T_BLOOMFILTER_INIT, buf_in,
+ NULL, NULL, CQM_CMD_TIMEOUT,
+ HINIC3_CHANNEL_DEFAULT);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(cqm_handle->ex_handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_send_cmd_box));
+ cqm_err(cqm_handle->ex_handle->dev_hdl, "Bloomfilter: %s ret=%d\n", __func__,
+ ret);
+ cqm_err(cqm_handle->ex_handle->dev_hdl, "Bloomfilter: %s: 0x%x 0x%x\n",
+ __func__, cmd->bloom_filter_addr,
+ cmd->bloom_filter_len);
+ cqm_cmd_free((void *)(cqm_handle->ex_handle), buf_in);
+ return CQM_FAIL;
+ }
+ cqm_cmd_free((void *)(cqm_handle->ex_handle), buf_in);
+ return CQM_SUCCESS;
+}
+
+static void cqm_func_bloomfilter_uninit(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_bloomfilter_table *bloomfilter_table = &cqm_handle->bloomfilter_table;
+
+ if (bloomfilter_table->table) {
+ mutex_deinit(&bloomfilter_table->lock);
+ vfree(bloomfilter_table->table);
+ bloomfilter_table->table = NULL;
+ }
+}
+
+static s32 cqm_func_bloomfilter_init(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_bloomfilter_table *bloomfilter_table = NULL;
+ struct tag_cqm_func_capability *capability = NULL;
+ u32 array_size;
+ s32 ret;
+
+ bloomfilter_table = &cqm_handle->bloomfilter_table;
+ capability = &cqm_handle->func_capability;
+
+ if (capability->bloomfilter_length == 0) {
+ cqm_info(cqm_handle->ex_handle->dev_hdl,
+ "Bloomfilter: bf_length=0, don't need to init bloomfilter\n");
+ return CQM_SUCCESS;
+ }
+
+ /* The unit of bloomfilter_length is 64B(512bits). Each bit is a table
+ * node. Therefore the value must be shift 9 bits to the left.
+ */
+ bloomfilter_table->table_size = capability->bloomfilter_length <<
+ CQM_BF_LENGTH_UNIT;
+ /* The unit of bloomfilter_length is 64B. The unit of array entryis 32B.
+ */
+ array_size = capability->bloomfilter_length << 1;
+ if (array_size == 0 || array_size > CQM_BF_BITARRAY_MAX) {
+ cqm_err(cqm_handle->ex_handle->dev_hdl, CQM_WRONG_VALUE(array_size));
+ return CQM_FAIL;
+ }
+
+ bloomfilter_table->array_mask = array_size - 1;
+ /* This table is not a bitmap, it is the counter of corresponding bit.
+ */
+ bloomfilter_table->table = vmalloc(bloomfilter_table->table_size *
+ (sizeof(u32)));
+ if (!bloomfilter_table->table)
+ return CQM_FAIL;
+
+ memset(bloomfilter_table->table, 0, (bloomfilter_table->table_size * sizeof(u32)));
+
+ /* The bloomfilter must be initialized to 0 by ucode,
+ * because the bloomfilter is mem mode
+ */
+ if (cqm_handle->func_capability.bloomfilter_enable) {
+ ret = bloomfilter_init_cmd(cqm_handle);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(cqm_handle->ex_handle->dev_hdl,
+ "Bloomfilter: bloomfilter_init_cmd ret=%d\n",
+ ret);
+ vfree(bloomfilter_table->table);
+ bloomfilter_table->table = NULL;
+ return CQM_FAIL;
+ }
+ }
+
+ mutex_init(&bloomfilter_table->lock);
+ cqm_dbg("Bloomfilter: table_size=0x%x, array_size=0x%x\n",
+ bloomfilter_table->table_size, array_size);
+ return CQM_SUCCESS;
+}
+
+static void cqm_fake_bloomfilter_uninit(struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_handle *fake_cqm_handle = NULL;
+ s32 child_func_number;
+ u32 i;
+
+ if (cqm_handle->func_capability.fake_func_type != CQM_FAKE_FUNC_PARENT)
+ return;
+
+ child_func_number = cqm_get_child_func_number(cqm_handle);
+ if (child_func_number == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(child_func_number));
+ return;
+ }
+
+ for (i = 0; i < (u32)child_func_number; i++) {
+ fake_cqm_handle = cqm_handle->fake_cqm_handle[i];
+ cqm_func_bloomfilter_uninit(fake_cqm_handle);
+ }
+}
+
+static s32 cqm_fake_bloomfilter_init(struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_handle *fake_cqm_handle = NULL;
+ s32 child_func_number;
+ u32 i;
+
+ if (cqm_handle->func_capability.fake_func_type != CQM_FAKE_FUNC_PARENT)
+ return CQM_SUCCESS;
+
+ child_func_number = cqm_get_child_func_number(cqm_handle);
+ if (child_func_number == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(child_func_number));
+ return CQM_FAIL;
+ }
+
+ for (i = 0; i < (u32)child_func_number; i++) {
+ fake_cqm_handle = cqm_handle->fake_cqm_handle[i];
+ if (cqm_func_bloomfilter_init(fake_cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_func_bloomfilter_init));
+ goto bloomfilter_init_err;
+ }
+ }
+
+ return CQM_SUCCESS;
+
+bloomfilter_init_err:
+ cqm_fake_bloomfilter_uninit(cqm_handle);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_bloomfilter_init
+ * Description : initialize the bloomfilter of cqm
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2016/7/6
+ * Modification : Created function
+ */
+s32 cqm_bloomfilter_init(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+
+ if (cqm_fake_bloomfilter_init(cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_fake_bloomfilter_init));
+ return CQM_FAIL;
+ }
+
+ if (cqm_func_bloomfilter_init(cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_func_bloomfilter_init));
+ goto bloomfilter_init_err;
+ }
+
+ return CQM_SUCCESS;
+
+bloomfilter_init_err:
+ cqm_fake_bloomfilter_uninit(cqm_handle);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_bloomfilter_uninit
+ * Description : uninitialize the bloomfilter of cqm
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2016/7/6
+ * Modification : Created function
+ */
+void cqm_bloomfilter_uninit(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+
+ cqm_fake_bloomfilter_uninit(cqm_handle);
+ cqm_func_bloomfilter_uninit(cqm_handle);
+}
+
+/**
+ * Prototype : cqm_bloomfilter_cmd
+ * Description : host send bloomfilter api cmd to ucode
+ * Input : void *ex_handle
+ * u32 op,
+ * u32 k_flag
+ * u64 id,
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2016/7/7
+ * Modification : Created function
+ */
+s32 cqm_bloomfilter_cmd(void *ex_handle, u16 func_id, u32 op, u32 k_flag, u64 id)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_cmd_buf *buf_in = NULL;
+ struct tag_cqm_bloomfilter_cmd *cmd = NULL;
+ s32 ret;
+
+ buf_in = cqm_cmd_alloc(ex_handle);
+ if (!buf_in)
+ return CQM_FAIL;
+
+ /* Fill the command format and convert it to big-endian. */
+ buf_in->size = sizeof(struct tag_cqm_bloomfilter_cmd);
+ cmd = (struct tag_cqm_bloomfilter_cmd *)(buf_in->buf);
+ memset((void *)cmd, 0, sizeof(struct tag_cqm_bloomfilter_cmd));
+ cmd->func_id = func_id;
+ cmd->k_en = k_flag;
+ cmd->index_h = (u32)(id >> CQM_DW_OFFSET);
+ cmd->index_l = (u32)(id & CQM_DW_MASK);
+
+ cqm_swab32((u8 *)cmd, (sizeof(struct tag_cqm_bloomfilter_cmd) >> CQM_DW_SHIFT));
+
+ ret = cqm_send_cmd_box(ex_handle, CQM_MOD_CQM, (u8)op, buf_in, NULL,
+ NULL, CQM_CMD_TIMEOUT, HINIC3_CHANNEL_DEFAULT);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_send_cmd_box));
+ cqm_err(handle->dev_hdl, "Bloomfilter: bloomfilter_cmd ret=%d\n",
+ ret);
+ cqm_err(handle->dev_hdl, "Bloomfilter: op=0x%x, cmd: 0x%x 0x%x 0x%x 0x%x\n",
+ op, *((u32 *)cmd), *(((u32 *)cmd) + CQM_DW_INDEX1),
+ *(((u32 *)cmd) + CQM_DW_INDEX2),
+ *(((u32 *)cmd) + CQM_DW_INDEX3));
+ cqm_cmd_free(ex_handle, buf_in);
+ return CQM_FAIL;
+ }
+
+ cqm_cmd_free(ex_handle, buf_in);
+
+ return CQM_SUCCESS;
+}
+
+static struct tag_cqm_handle *cqm_get_func_cqm_handle(struct hinic3_hwdev *ex_handle, u16 func_id)
+{
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_func_capability *func_cap = NULL;
+ s32 child_func_start, child_func_number;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(ex_handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ /* function id is PF/VF */
+ if (func_id == hinic3_global_func_id(ex_handle))
+ return cqm_handle;
+
+ func_cap = &cqm_handle->func_capability;
+ if (func_cap->fake_func_type != CQM_FAKE_FUNC_PARENT) {
+ cqm_err(ex_handle->dev_hdl, CQM_WRONG_VALUE(func_cap->fake_func_type));
+ return NULL;
+ }
+
+ child_func_start = cqm_get_child_func_start(cqm_handle);
+ if (child_func_start == CQM_FAIL) {
+ cqm_err(ex_handle->dev_hdl, CQM_WRONG_VALUE(child_func_start));
+ return NULL;
+ }
+
+ child_func_number = cqm_get_child_func_number(cqm_handle);
+ if (child_func_number == CQM_FAIL) {
+ cqm_err(ex_handle->dev_hdl, CQM_WRONG_VALUE(child_func_number));
+ return NULL;
+ }
+
+ /* function id is fake vf */
+ if (func_id >= child_func_start && (func_id < (child_func_start + child_func_number)))
+ return cqm_handle->fake_cqm_handle[func_id - (u16)child_func_start];
+
+ return NULL;
+}
+
+/**
+ * Prototype : cqm_bloomfilter_inc
+ * Description : The reference counting field is added to the ID of the
+ * bloomfilter.
+ * Input : void *ex_handle
+ * u64 id--hash value
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2016/7/7
+ * Modification : Created function
+ */
+s32 cqm_bloomfilter_inc(void *ex_handle, u16 func_id, u64 id)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_bloomfilter_table *bloomfilter_table = NULL;
+ u32 array_tmp[CQM_BF_SECTION_NUMBER] = {0};
+ struct tag_cqm_handle *cqm_handle = NULL;
+ u32 array_index, array_bit, i;
+ u32 k_flag = 0;
+
+ cqm_dbg("Bloomfilter: func_id: %d, inc id=0x%llx\n", func_id, id);
+
+ cqm_handle = cqm_get_func_cqm_handle(ex_handle, func_id);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle_bf_inc is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ if (cqm_handle->func_capability.bloomfilter_enable == 0) {
+ cqm_info(handle->dev_hdl, "Bloomfilter inc: bloomfilter is disable\n");
+ return CQM_SUCCESS;
+ }
+
+ /* |(array_index=0)32B(array_bit:256bits)|(array_index=1)32B(256bits)|
+ * array_index = 0~bloomfilter_table->table_size/256bit
+ * array_bit = 0~255
+ */
+ cqm_dbg("Bloomfilter: inc id=0x%llx\n", id);
+ bloomfilter_table = &cqm_handle->bloomfilter_table;
+
+ /* The array index identifies a 32-byte entry. */
+ array_index = (u32)CQM_BF_BITARRAY_INDEX(id, bloomfilter_table->array_mask);
+ /* convert the unit of array_index to bit */
+ array_index = array_index << CQM_BF_ENTRY_SIZE_UNIT;
+ cqm_dbg("Bloomfilter: inc array_index=0x%x\n", array_index);
+
+ mutex_lock(&bloomfilter_table->lock);
+ for (i = 0; i < CQM_BF_SECTION_NUMBER; i++) {
+ /* the position of the bit in 64-bit section */
+ array_bit =
+ (id >> (CQM_BF_SECTION_BASE + i * CQM_BF_SECTION_SIZE)) &
+ CQM_BF_SECTION_MASK;
+ /* array_bit + number of 32-byte array entries + number of
+ * 64-bit sections before the section
+ */
+ array_bit = array_bit + array_index +
+ (i * CQM_BF_SECTION_BIT_NUMBER);
+
+ /* array_temp[i] records the index of the bloomfilter.
+ * It is used to roll back the reference counting of the
+ * bitarray.
+ */
+ array_tmp[i] = array_bit;
+ cqm_dbg("Bloomfilter: inc array_bit=0x%x\n", array_bit);
+
+ /* Add one to the corresponding bit in bloomfilter table.
+ * If the value changes from 0 to 1, change the corresponding
+ * bit in k_flag.
+ */
+ (bloomfilter_table->table[array_bit])++;
+ cqm_dbg("Bloomfilter: inc bloomfilter_table->table[%d]=0x%x\n",
+ array_bit, bloomfilter_table->table[array_bit]);
+ if (bloomfilter_table->table[array_bit] == 1)
+ k_flag |= (1U << i);
+ }
+
+ if (k_flag != 0) {
+ /* send cmd to ucode and set corresponding bit. */
+ if (cqm_bloomfilter_cmd(ex_handle, func_id, CQM_CMD_T_BLOOMFILTER_SET,
+ k_flag, id) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_bloomfilter_cmd_inc));
+ for (i = 0; i < CQM_BF_SECTION_NUMBER; i++) {
+ array_bit = array_tmp[i];
+ (bloomfilter_table->table[array_bit])--;
+ }
+ mutex_unlock(&bloomfilter_table->lock);
+ return CQM_FAIL;
+ }
+ }
+
+ mutex_unlock(&bloomfilter_table->lock);
+
+ return CQM_SUCCESS;
+}
+EXPORT_SYMBOL(cqm_bloomfilter_inc);
+
+/**
+ * Prototype : cqm_bloomfilter_dec
+ * Description : The reference counting field is decreased to the ID of the
+ * bloomfilter.
+ * Input : void *ex_handle
+ * u64 id--hash value
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2016/7/7
+ * Modification : Created function
+ */
+s32 cqm_bloomfilter_dec(void *ex_handle, u16 func_id, u64 id)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_bloomfilter_table *bloomfilter_table = NULL;
+ u32 array_tmp[CQM_BF_SECTION_NUMBER] = {0};
+ struct tag_cqm_handle *cqm_handle = NULL;
+ u32 array_index, array_bit, i;
+ u32 k_flag = 0;
+
+ cqm_handle = cqm_get_func_cqm_handle(ex_handle, func_id);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle_bf_dec is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ if (cqm_handle->func_capability.bloomfilter_enable == 0) {
+ cqm_info(handle->dev_hdl, "Bloomfilter dec: bloomfilter is disable\n");
+ return CQM_SUCCESS;
+ }
+
+ cqm_dbg("Bloomfilter: dec id=0x%llx\n", id);
+ bloomfilter_table = &cqm_handle->bloomfilter_table;
+
+ /* The array index identifies a 32-byte entry. */
+ array_index = (u32)CQM_BF_BITARRAY_INDEX(id, bloomfilter_table->array_mask);
+ cqm_dbg("Bloomfilter: dec array_index=0x%x\n", array_index);
+ mutex_lock(&bloomfilter_table->lock);
+ for (i = 0; i < CQM_BF_SECTION_NUMBER; i++) {
+ /* the position of the bit in 64-bit section */
+ array_bit =
+ (id >> (CQM_BF_SECTION_BASE + i * CQM_BF_SECTION_SIZE)) &
+ CQM_BF_SECTION_MASK;
+ /* array_bit + number of 32-byte array entries + number of
+ * 64-bit sections before the section
+ */
+ array_bit = array_bit + (array_index << 0x8) + (i * 0x40);
+
+ /* array_temp[i] records the index of the bloomfilter.
+ * It is used to roll back the reference counting of the
+ * bitarray.
+ */
+ array_tmp[i] = array_bit;
+
+ /* Deduct one to the corresponding bit in bloomfilter table.
+ * If the value changes from 1 to 0, change the corresponding
+ * bit in k_flag. Do not continue -1 when the reference counting
+ * value of the bit is 0.
+ */
+ if (bloomfilter_table->table[array_bit] != 0) {
+ (bloomfilter_table->table[array_bit])--;
+ cqm_dbg("Bloomfilter: dec bloomfilter_table->table[%d]=0x%x\n",
+ array_bit, (bloomfilter_table->table[array_bit]));
+ if (bloomfilter_table->table[array_bit] == 0)
+ k_flag |= (1U << i);
+ }
+ }
+
+ if (k_flag != 0) {
+ /* send cmd to ucode and clear corresponding bit. */
+ if (cqm_bloomfilter_cmd(ex_handle, func_id, CQM_CMD_T_BLOOMFILTER_CLEAR,
+ k_flag, id) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_bloomfilter_cmd_dec));
+ for (i = 0; i < CQM_BF_SECTION_NUMBER; i++) {
+ array_bit = array_tmp[i];
+ (bloomfilter_table->table[array_bit])++;
+ }
+ mutex_unlock(&bloomfilter_table->lock);
+ return CQM_FAIL;
+ }
+ }
+
+ mutex_unlock(&bloomfilter_table->lock);
+
+ return CQM_SUCCESS;
+}
+EXPORT_SYMBOL(cqm_bloomfilter_dec);
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bloomfilter.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bloomfilter.h
new file mode 100644
index 0000000000000..8fd446c958db7
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_bloomfilter.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_BLOOMFILTER_H
+#define CQM_BLOOMFILTER_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+
+/* Bloomfilter entry size is 32B(256bit), whitch index is the 48-32-bit of the
+ * hash. |31~26|25~20|19~14|13~8| will be used to locate 4 bloom filter section
+ * in one entry. k_en[3:0] used to specify the section of bloom filter.
+ */
+#define CQM_BF_ENTRY_SIZE 32
+#define CQM_BF_ENTRY_SIZE_UNIT 8
+#define CQM_BF_BITARRAY_MAX BIT(17)
+
+#define CQM_BF_SECTION_NUMBER 4
+#define CQM_BF_SECTION_BASE 8
+#define CQM_BF_SECTION_SIZE 6
+#define CQM_BF_SECTION_MASK 0x3f
+#define CQM_BF_SECTION_BIT_NUMBER 64
+
+#define CQM_BF_ARRAY_INDEX_OFFSET 32
+#define CQM_BF_BITARRAY_INDEX(id, mask) \
+ (((id) >> CQM_BF_ARRAY_INDEX_OFFSET) & (mask))
+
+/* The unit of bloomfilter_length is 64B(512bits). */
+#define CQM_BF_LENGTH_UNIT 9
+
+#define CQM_DW_MASK 0xffffffff
+#define CQM_DW_OFFSET 32
+#define CQM_DW_INDEX0 0
+#define CQM_DW_INDEX1 1
+#define CQM_DW_INDEX2 2
+#define CQM_DW_INDEX3 3
+
+struct tag_cqm_bloomfilter_table {
+ u32 *table;
+ u32 table_size; /* The unit is bit */
+ u32 array_mask; /* The unit of array entry is 32B, used to address entry
+ */
+ struct mutex lock;
+};
+
+/* only for test */
+s32 cqm_bloomfilter_cmd(void *ex_handle, u16 func_id, u32 op, u32 k_flag, u64 id);
+s32 cqm_bloomfilter_init(void *ex_handle);
+void cqm_bloomfilter_uninit(void *ex_handle);
+s32 cqm_bloomfilter_inc(void *ex_handle, u16 func_id, u64 id);
+s32 cqm_bloomfilter_dec(void *ex_handle, u16 func_id, u64 id);
+
+#endif /* CQM_BLOOMFILTER_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_cmd.c b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_cmd.c
new file mode 100644
index 0000000000000..413629ac1de2f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_cmd.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include "ossl_knl.h"
+#include "hinic3_hw.h"
+#include "hinic3_mt.h"
+#include "hinic3_hwdev.h"
+
+#include "cqm_bitmap_table.h"
+#include "cqm_bat_cla.h"
+#include "cqm_main.h"
+
+/**
+ * Prototype : cqm_cmd_alloc
+ * Description : Apply for a cmd buffer. The buffer size is fixed to 2 KB.
+ * The buffer content is not cleared and needs to be cleared by
+ * services.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : struct tag_cqm_cmd_buf *
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+struct tag_cqm_cmd_buf *cqm_cmd_alloc(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_cmd_alloc_cnt);
+
+ return (struct tag_cqm_cmd_buf *)hinic3_alloc_cmd_buf(ex_handle);
+}
+EXPORT_SYMBOL(cqm_cmd_alloc);
+
+/**
+ * Prototype : cqm_cmd_free
+ * Description : Release for a cmd buffer.
+ * Input : void *ex_handle
+ * struct tag_cqm_cmd_buf *cmd_buf
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_cmd_free(void *ex_handle, struct tag_cqm_cmd_buf *cmd_buf)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return;
+ }
+ if (unlikely(!cmd_buf)) {
+ pr_err("[CQM]%s: cmd_buf is null\n", __func__);
+ return;
+ }
+ if (unlikely(!cmd_buf->buf)) {
+ pr_err("[CQM]%s: buf is null\n", __func__);
+ return;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_cmd_free_cnt);
+
+ hinic3_free_cmd_buf(ex_handle, (struct hinic3_cmd_buf *)cmd_buf);
+}
+EXPORT_SYMBOL(cqm_cmd_free);
+
+/**
+ * Prototype : cqm_send_cmd_box
+ * Description : Send a cmd message in box mode.
+ * This interface will mount a completion quantity,
+ * causing sleep.
+ * Input : void *ex_handle
+ * u8 mod
+ * u8 cmd,
+ * struct tag_cqm_cmd_buf *buf_in
+ * struct tag_cqm_cmd_buf *buf_out
+ * u64 *out_param
+ * u32 timeout
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_send_cmd_box(void *ex_handle, u8 mod, u8 cmd, struct tag_cqm_cmd_buf *buf_in,
+ struct tag_cqm_cmd_buf *buf_out, u64 *out_param, u32 timeout,
+ u16 channel)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!buf_in)) {
+ pr_err("[CQM]%s: buf_in is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!buf_in->buf)) {
+ pr_err("[CQM]%s: buf is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_send_cmd_box_cnt);
+
+ return hinic3_cmdq_detail_resp(ex_handle, mod, cmd,
+ (struct hinic3_cmd_buf *)buf_in,
+ (struct hinic3_cmd_buf *)buf_out,
+ out_param, timeout, channel);
+}
+EXPORT_SYMBOL(cqm_send_cmd_box);
+
+/**
+ * Prototype : cqm_lb_send_cmd_box
+ * Description : Send a cmd message in box mode and open cos_id.
+ * This interface will mount a completion quantity,
+ * causing sleep.
+ * Input : void *ex_handle
+ * u8 mod
+ * u8 cmd
+ * u8 cos_id
+ * struct tag_cqm_cmd_buf *buf_in
+ * struct tag_cqm_cmd_buf *buf_out
+ * u64 *out_param
+ * u32 timeout
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2020/4/9
+ * Modification : Created function
+ */
+s32 cqm_lb_send_cmd_box(void *ex_handle, u8 mod, u8 cmd, u8 cos_id,
+ struct tag_cqm_cmd_buf *buf_in, struct tag_cqm_cmd_buf *buf_out,
+ u64 *out_param, u32 timeout, u16 channel)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!buf_in)) {
+ pr_err("[CQM]%s: buf_in is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!buf_in->buf)) {
+ pr_err("[CQM]%s: buf is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_send_cmd_box_cnt);
+
+ return hinic3_cos_id_detail_resp(ex_handle, mod, cmd, cos_id,
+ (struct hinic3_cmd_buf *)buf_in,
+ (struct hinic3_cmd_buf *)buf_out,
+ out_param, timeout, channel);
+}
+EXPORT_SYMBOL(cqm_lb_send_cmd_box);
+
+/**
+ * Prototype : cqm_lb_send_cmd_box_async
+ * Description : Send a cmd message in box mode and open cos_id.
+ * This interface will not wait completion
+ * Input : void *ex_handle
+ * u8 mod
+ * u8 cmd
+ * u8 cos_id
+ * struct tag_cqm_cmd_buf *buf_in
+ * u16 channel
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2023/5/19
+ * Modification : Created function
+ */
+s32 cqm_lb_send_cmd_box_async(void *ex_handle, u8 mod, u8 cmd,
+ u8 cos_id, struct tag_cqm_cmd_buf *buf_in,
+ u16 channel)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!buf_in)) {
+ pr_err("[CQM]%s: buf_in is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!buf_in->buf)) {
+ pr_err("[CQM]%s: buf is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_send_cmd_box_cnt);
+
+ return hinic3_cmdq_async_cos(ex_handle, mod, cmd, cos_id,
+ (struct hinic3_cmd_buf *)buf_in, channel);
+}
+EXPORT_SYMBOL(cqm_lb_send_cmd_box_async);
+
+/**
+ * Prototype : cqm_send_cmd_imm
+ * Description : Send a cmd message in imm mode.
+ * This interface will mount a completion quantity,
+ * causing sleep.
+ * Input : void *ex_handle
+ * u8 mod
+ * u8 cmd
+ * struct tag_cqm_cmd_buf *buf_in
+ * u64 *out_param
+ * u32 timeout
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_send_cmd_imm(void *ex_handle, u8 mod, u8 cmd, struct tag_cqm_cmd_buf *buf_in,
+ u64 *out_param, u32 timeout, u16 channel)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!buf_in)) {
+ pr_err("[CQM]%s: buf_in is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!buf_in->buf)) {
+ pr_err("[CQM]%s: buf is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_send_cmd_imm_cnt);
+
+ return hinic3_cmdq_direct_resp((void *)ex_handle, mod, cmd,
+ (struct hinic3_cmd_buf *)buf_in,
+ out_param, timeout, channel);
+}
+EXPORT_SYMBOL(cqm_send_cmd_imm);
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_cmd.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_cmd.h
new file mode 100644
index 0000000000000..a5b85f12b1613
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_cmd.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_CMD_H
+#define CQM_CMD_H
+
+#include <linux/types.h>
+
+#include "cqm_object.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif
+#endif /* __cplusplus */
+
+#define CQM_CMD_TIMEOUT 10000 /* ms */
+
+struct tag_cqm_cmd_buf *cqm_cmd_alloc(void *ex_handle);
+void cqm_cmd_free(void *ex_handle, struct tag_cqm_cmd_buf *cmd_buf);
+s32 cqm_send_cmd_box(void *ex_handle, u8 mod, u8 cmd, struct tag_cqm_cmd_buf *buf_in,
+ struct tag_cqm_cmd_buf *buf_out, u64 *out_param, u32 timeout,
+ u16 channel);
+s32 cqm_lb_send_cmd_box(void *ex_handle, u8 mod, u8 cmd, u8 cos_id,
+ struct tag_cqm_cmd_buf *buf_in, struct tag_cqm_cmd_buf *buf_out,
+ u64 *out_param, u32 timeout, u16 channel);
+s32 cqm_lb_send_cmd_box_async(void *ex_handle, u8 mod, u8 cmd,
+ u8 cos_id, struct tag_cqm_cmd_buf *buf_in,
+ u16 channel);
+s32 cqm_send_cmd_imm(void *ex_handle, u8 mod, u8 cmd, struct tag_cqm_cmd_buf *buf_in,
+ u64 *out_param, u32 timeout, u16 channel);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif /* CQM_CMD_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_db.c b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_db.c
new file mode 100644
index 0000000000000..59ed378ac0050
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_db.c
@@ -0,0 +1,506 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include "ossl_knl.h"
+#include "hinic3_crm.h"
+#include "hinic3_hw.h"
+#include "hinic3_mt.h"
+#include "hinic3_hwdev.h"
+
+#include "cqm_object.h"
+#include "cqm_bitmap_table.h"
+#include "cqm_bat_cla.h"
+#include "cqm_object_intern.h"
+#include "cqm_main.h"
+#include "cqm_db.h"
+
+/**
+ * Prototype : cqm_db_addr_alloc
+ * Description : Apply for a page of hardware doorbell and dwqe.
+ * The indexes are the same. The obtained addresses are physical
+ * addresses. Each function has a maximum of 1K addresses(DB).
+ * Input : void *ex_handle
+ * void __iomem **db_addr,
+ * void __iomem **dwqe_addr
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+s32 cqm_db_addr_alloc(void *ex_handle, void __iomem **db_addr,
+ void __iomem **dwqe_addr)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!db_addr)) {
+ pr_err("[CQM]%s: db_addr is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!dwqe_addr)) {
+ pr_err("[CQM]%s: dwqe_addr is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_db_addr_alloc_cnt);
+
+ return hinic3_alloc_db_addr(ex_handle, db_addr, dwqe_addr);
+}
+
+s32 cqm_db_phy_addr_alloc(void *ex_handle, u64 *db_paddr, u64 *dwqe_addr)
+{
+ return hinic3_alloc_db_phy_addr(ex_handle, db_paddr, dwqe_addr);
+}
+
+/**
+ * Prototype : cqm_db_addr_free
+ * Description : Release a page of hardware doorbell and dwqe.
+ * Input : void *ex_handle
+ * const void __iomem **db_addr,
+ * void __iomem **dwqe_addr
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+void cqm_db_addr_free(void *ex_handle, const void __iomem *db_addr,
+ void __iomem *dwqe_addr)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_db_addr_free_cnt);
+
+ hinic3_free_db_addr(ex_handle, db_addr, dwqe_addr);
+}
+
+static void cqm_db_phy_addr_free(void *ex_handle, u64 *db_paddr, const u64 *dwqe_addr)
+{
+ hinic3_free_db_phy_addr(ex_handle, *db_paddr, *dwqe_addr);
+}
+
+static bool cqm_need_db_init(s32 service)
+{
+ bool need_db_init = false;
+
+ switch (service) {
+ case CQM_SERVICE_T_NIC:
+ case CQM_SERVICE_T_OVS:
+ case CQM_SERVICE_T_IPSEC:
+ case CQM_SERVICE_T_VIRTIO:
+ case CQM_SERVICE_T_PPA:
+ need_db_init = false;
+ break;
+ default:
+ need_db_init = true;
+ }
+
+ return need_db_init;
+}
+
+/**
+ * Prototype : cqm_db_init
+ * Description : Initialize the doorbell of the CQM.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/7/6
+ * Modification : Created function
+ */
+s32 cqm_db_init(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ s32 i;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+
+ /* Allocate hardware doorbells to services. */
+ for (i = 0; i < CQM_SERVICE_T_MAX; i++) {
+ service = &cqm_handle->service[i];
+ if (!cqm_need_db_init(i) || !service->valid)
+ continue;
+
+ if (cqm_db_addr_alloc(ex_handle, &service->hardware_db_vaddr,
+ &service->dwqe_vaddr) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_db_addr_alloc));
+ break;
+ }
+
+ if (cqm_db_phy_addr_alloc(handle, &service->hardware_db_paddr,
+ &service->dwqe_paddr) !=
+ CQM_SUCCESS) {
+ cqm_db_addr_free(ex_handle, service->hardware_db_vaddr,
+ service->dwqe_vaddr);
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_db_phy_addr_alloc));
+ break;
+ }
+ }
+
+ if (i != CQM_SERVICE_T_MAX) {
+ i--;
+ for (; i >= 0; i--) {
+ service = &cqm_handle->service[i];
+ if (!cqm_need_db_init(i) || !service->valid)
+ continue;
+
+ cqm_db_addr_free(ex_handle, service->hardware_db_vaddr,
+ service->dwqe_vaddr);
+ cqm_db_phy_addr_free(ex_handle,
+ &service->hardware_db_paddr,
+ &service->dwqe_paddr);
+ }
+ return CQM_FAIL;
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_db_uninit
+ * Description : Deinitialize the doorbell of the CQM.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/7/6
+ * Modification : Created function
+ */
+void cqm_db_uninit(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ s32 i;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+
+ /* Release hardware doorbell. */
+ for (i = 0; i < CQM_SERVICE_T_MAX; i++) {
+ service = &cqm_handle->service[i];
+ if (service->valid && cqm_need_db_init(i)) {
+ cqm_db_addr_free(ex_handle, service->hardware_db_vaddr,
+ service->dwqe_vaddr);
+ cqm_db_phy_addr_free(ex_handle, &service->hardware_db_paddr,
+ &service->dwqe_paddr);
+ }
+ }
+}
+
+/**
+ * Prototype : cqm_get_db_addr
+ * Description : Return hardware DB vaddr.
+ * Input : void *ex_handle
+ * u32 service_type
+ * Output : None
+ * Return Value : void *
+ * 1.Date : 2015/7/6
+ * Modification : Created function
+ */
+void *cqm_get_db_addr(void *ex_handle, u32 service_type)
+{
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct hinic3_hwdev *handle = NULL;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+ handle = (struct hinic3_hwdev *)ex_handle;
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ service = &cqm_handle->service[service_type];
+
+ return (void *)service->hardware_db_vaddr;
+}
+EXPORT_SYMBOL(cqm_get_db_addr);
+
+s32 cqm_get_hardware_db_addr(void *ex_handle, u64 *addr,
+ enum hinic3_service_type service_type)
+{
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct hinic3_hwdev *handle = NULL;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!addr)) {
+ pr_err("[CQM]%s: addr is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ if (service_type < SERVICE_T_NIC || service_type >= SERVICE_T_MAX) {
+ pr_err("%s service_type = %d state is error\n", __func__,
+ service_type);
+ return CQM_FAIL;
+ }
+
+ handle = (struct hinic3_hwdev *)ex_handle;
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ service = &cqm_handle->service[service_type];
+
+ *addr = service->hardware_db_paddr;
+ return CQM_SUCCESS;
+}
+EXPORT_SYMBOL(cqm_get_hardware_db_addr);
+
+/**
+ * Prototype : cqm_ring_hardware_db
+ * Description : Ring hardware DB to chip.
+ * Input : void *ex_handle
+ * u32 service_type: Each kernel-mode service is allocated a
+ * hardware db page.
+ * u8 db_count: The bit[7:0] of PI can't be store in 64-bit db.
+ * u64 db: It contains the content of db, whitch is organized by
+ * service, including big-endian conversion
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+s32 cqm_ring_hardware_db(void *ex_handle, u32 service_type, u8 db_count, u64 db)
+{
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct hinic3_hwdev *handle = NULL;
+
+ handle = (struct hinic3_hwdev *)ex_handle;
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ service = &cqm_handle->service[service_type];
+
+ /* Considering the performance of ringing hardware db,
+ * the parameter is not checked.
+ */
+ wmb();
+ *((u64 *)service->hardware_db_vaddr + db_count) = db;
+ return CQM_SUCCESS;
+}
+EXPORT_SYMBOL(cqm_ring_hardware_db);
+
+/**
+ * Prototype : cqm_ring_hardware_db_fc // Todo cqm_ring_fakevf_hardware_db
+ * Description : Ring fake vf hardware DB to chip.
+ * Input : void *ex_handle
+ * u32 service_type: Each kernel-mode service is allocated a
+ * hardware db page.
+ * u8 db_count: The bit[7:0] of PI can't be store in 64-bit db.
+ * u8 pagenum: Indicates the doorbell address offset of the fake
+ * VFID.
+ * u64 db: It contains the content of db, whitch is organized by
+ * service, including big-endian conversion.
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+s32 cqm_ring_hardware_db_fc(void *ex_handle, u32 service_type, u8 db_count,
+ u8 pagenum, u64 db)
+{
+#define HIFC_DB_FAKE_VF_OFFSET 32
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct hinic3_hwdev *handle = NULL;
+ void *dbaddr = NULL;
+
+ handle = (struct hinic3_hwdev *)ex_handle;
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ service = &cqm_handle->service[service_type];
+ /* Considering the performance of ringing hardware db,
+ * the parameter is not checked.
+ */
+ wmb();
+ dbaddr = (u8 *)service->hardware_db_vaddr +
+ ((pagenum + HIFC_DB_FAKE_VF_OFFSET) * HINIC3_DB_PAGE_SIZE);
+ *((u64 *)dbaddr + db_count) = db;
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_ring_direct_wqe_db // Todo <--cqm_ring_direct_wqe_db_fc
+ * Description : Ring direct wqe hardware DB to chip.
+ * Input : void *ex_handle
+ * u32 service_type: Each kernel-mode service is allocated a
+ * hardware db page.
+ * u8 db_count: The bit[7:0] of PI can't be store in 64-bit db.
+ * void *direct_wqe: The content of direct_wqe.
+ * u16 length: The length of direct_wqe.
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+s32 cqm_ring_direct_wqe_db(void *ex_handle, u32 service_type, u8 db_count,
+ void *direct_wqe)
+{
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct hinic3_hwdev *handle = NULL;
+ u64 *tmp = (u64 *)direct_wqe;
+ int i;
+
+ handle = (struct hinic3_hwdev *)ex_handle;
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ service = &cqm_handle->service[service_type];
+
+ /* Considering the performance of ringing hardware db,
+ * the parameter is not checked.
+ */
+ wmb();
+ for (i = 0; i < 0x80 / 0x8; i++)
+ *((u64 *)service->dwqe_vaddr + 0x40 + i) = *tmp++;
+
+ return CQM_SUCCESS;
+}
+EXPORT_SYMBOL(cqm_ring_direct_wqe_db);
+
+s32 cqm_ring_direct_wqe_db_fc(void *ex_handle, u32 service_type,
+ void *direct_wqe)
+{
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct hinic3_hwdev *handle = NULL;
+ u64 *tmp = (u64 *)direct_wqe;
+ int i;
+
+ handle = (struct hinic3_hwdev *)ex_handle;
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ service = &cqm_handle->service[service_type];
+
+ /* Considering the performance of ringing hardware db,
+ * the parameter is not checked.
+ */
+ wmb();
+ *((u64 *)service->dwqe_vaddr + 0x0) = tmp[0x2];
+ *((u64 *)service->dwqe_vaddr + 0x1) = tmp[0x3];
+ *((u64 *)service->dwqe_vaddr + 0x2) = tmp[0x0];
+ *((u64 *)service->dwqe_vaddr + 0x3) = tmp[0x1];
+ tmp += 0x4;
+
+ /* The FC use 256B WQE. The directwqe is written at block0,
+ * and the length is 256B
+ */
+ for (i = 0x4; i < 0x20; i++)
+ *((u64 *)service->dwqe_vaddr + i) = *tmp++;
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_ring_hardware_db_update_pri
+ * Description : Provides the doorbell interface for the CQM to convert the PRI
+ * to the CoS. The doorbell transmitted by the service must be
+ * the host sequence. This interface converts the network
+ * sequence.
+ * Input : void *ex_handle
+ * u32 service_type: Each kernel-mode service is allocated a
+ * hardware db page.
+ * u8 db_count: The bit[7:0] of PI can't be store in 64-bit db.
+ * u64 db: It contains the content of db, whitch is organized by
+ * service, including big-endian conversion.
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2016/11/24
+ * Modification : Created function
+ */
+s32 cqm_ring_hardware_db_update_pri(void *ex_handle, u32 service_type,
+ u8 db_count, u64 db)
+{
+ struct tag_cqm_db_common *db_common = (struct tag_cqm_db_common *)(&db);
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct hinic3_hwdev *handle = NULL;
+
+ handle = (struct hinic3_hwdev *)ex_handle;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ service = &cqm_handle->service[service_type];
+
+ /* the CQM converts the PRI to the CoS */
+ db_common->cos = 0x7 - db_common->cos;
+
+ cqm_swab32((u8 *)db_common, sizeof(u64) >> CQM_DW_SHIFT);
+
+ /* Considering the performance of ringing hardware db,
+ * the parameter is not checked.
+ */
+ wmb();
+ *((u64 *)service->hardware_db_vaddr + db_count) = db;
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_ring_software_db
+ * Description : Ring software db.
+ * Input : struct tag_cqm_object *object
+ * u64 db_record: It contains the content of db, whitch is
+ * organized by service, including big-endian
+ * conversion. For RQ/SQ: This field is filled
+ * with the doorbell_record area of queue_header.
+ * For CQ: This field is filled with the value of
+ * ci_record in queue_header.
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+s32 cqm_ring_software_db(struct tag_cqm_object *object, u64 db_record)
+{
+ struct tag_cqm_nonrdma_qinfo *nonrdma_qinfo = NULL;
+ struct tag_cqm_rdma_qinfo *rdma_qinfo = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct hinic3_hwdev *handle = NULL;
+
+ if (unlikely(!object)) {
+ pr_err("[CQM]%s: object is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ handle = cqm_handle->ex_handle;
+
+ if (object->object_type == CQM_OBJECT_NONRDMA_EMBEDDED_RQ ||
+ object->object_type == CQM_OBJECT_NONRDMA_EMBEDDED_SQ ||
+ object->object_type == CQM_OBJECT_NONRDMA_SRQ) {
+ nonrdma_qinfo = (struct tag_cqm_nonrdma_qinfo *)(void *)object;
+ nonrdma_qinfo->common.q_header_vaddr->doorbell_record =
+ db_record;
+ } else if ((object->object_type == CQM_OBJECT_NONRDMA_EMBEDDED_CQ) ||
+ (object->object_type == CQM_OBJECT_NONRDMA_SCQ)) {
+ nonrdma_qinfo = (struct tag_cqm_nonrdma_qinfo *)(void *)object;
+ nonrdma_qinfo->common.q_header_vaddr->ci_record = db_record;
+ } else if ((object->object_type == CQM_OBJECT_RDMA_QP) ||
+ (object->object_type == CQM_OBJECT_RDMA_SRQ)) {
+ rdma_qinfo = (struct tag_cqm_rdma_qinfo *)(void *)object;
+ rdma_qinfo->common.q_header_vaddr->doorbell_record = db_record;
+ } else if (object->object_type == CQM_OBJECT_RDMA_SCQ) {
+ rdma_qinfo = (struct tag_cqm_rdma_qinfo *)(void *)object;
+ rdma_qinfo->common.q_header_vaddr->ci_record = db_record;
+ } else {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object->object_type));
+ }
+
+ return CQM_SUCCESS;
+}
+EXPORT_SYMBOL(cqm_ring_software_db);
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_db.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_db.h
new file mode 100644
index 0000000000000..954f62bba628a
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_db.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_DB_H
+#define CQM_DB_H
+
+#include <linux/types.h>
+
+struct tag_cqm_db_common {
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+ u32 rsvd1 : 23;
+ u32 c : 1;
+ u32 cos : 3;
+ u32 service_type : 5;
+#else
+ u32 service_type : 5;
+ u32 cos : 3;
+ u32 c : 1;
+ u32 rsvd1 : 23;
+#endif
+
+ u32 rsvd2;
+};
+
+/* Only for test */
+s32 cqm_db_addr_alloc(void *ex_handle, void __iomem **db_addr,
+ void __iomem **dwqe_addr);
+s32 cqm_db_phy_addr_alloc(void *ex_handle, u64 *db_paddr, u64 *dwqe_addr);
+
+s32 cqm_db_init(void *ex_handle);
+void cqm_db_uninit(void *ex_handle);
+
+s32 cqm_ring_hardware_db(void *ex_handle, u32 service_type, u8 db_count,
+ u64 db);
+
+#endif /* CQM_DB_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_define.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_define.h
new file mode 100644
index 0000000000000..fd56354d43635
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_define.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_DEFINE_H
+#define CQM_DEFINE_H
+#ifndef HIUDK_SDK
+#define cqm_init cqm3_init
+#define cqm_uninit cqm3_uninit
+#define cqm_service_register cqm3_service_register
+#define cqm_service_unregister cqm3_service_unregister
+#define cqm_bloomfilter_dec cqm3_bloomfilter_dec
+#define cqm_bloomfilter_inc cqm3_bloomfilter_inc
+#define cqm_cmd_alloc cqm3_cmd_alloc
+#define cqm_get_hardware_db_addr cqm3_get_hardware_db_addr
+#define cqm_cmd_free cqm3_cmd_free
+#define cqm_send_cmd_box cqm3_send_cmd_box
+#define cqm_lb_send_cmd_box cqm3_lb_send_cmd_box
+#define cqm_lb_send_cmd_box_async cqm3_lb_send_cmd_box_async
+#define cqm_send_cmd_imm cqm3_send_cmd_imm
+#define cqm_db_addr_alloc cqm3_db_addr_alloc
+#define cqm_db_addr_free cqm3_db_addr_free
+#define cqm_ring_hardware_db cqm3_ring_hardware_db
+#define cqm_ring_software_db cqm3_ring_software_db
+#define cqm_object_fc_srq_create cqm3_object_fc_srq_create
+#define cqm_object_share_recv_queue_create cqm3_object_share_recv_queue_create
+#define cqm_object_share_recv_queue_add_container \
+ cqm3_object_share_recv_queue_add_container
+#define cqm_object_srq_add_container_free cqm3_object_srq_add_container_free
+#define cqm_object_recv_queue_create cqm3_object_recv_queue_create
+#define cqm_object_qpc_mpt_create cqm3_object_qpc_mpt_create
+#define cqm_object_nonrdma_queue_create cqm3_object_nonrdma_queue_create
+#define cqm_object_rdma_queue_create cqm3_object_rdma_queue_create
+#define cqm_object_rdma_table_get cqm3_object_rdma_table_get
+#define cqm_object_delete cqm3_object_delete
+#define cqm_object_offset_addr cqm3_object_offset_addr
+#define cqm_object_get cqm3_object_get
+#define cqm_object_put cqm3_object_put
+#define cqm_object_funcid cqm3_object_funcid
+#define cqm_object_resize_alloc_new cqm3_object_resize_alloc_new
+#define cqm_object_resize_free_new cqm3_object_resize_free_new
+#define cqm_object_resize_free_old cqm3_object_resize_free_old
+#define cqm_function_timer_clear cqm3_function_timer_clear
+#define cqm_function_hash_buf_clear cqm3_function_hash_buf_clear
+#define cqm_srq_used_rq_container_delete cqm3_srq_used_rq_container_delete
+#define cqm_timer_base cqm3_timer_base
+#define cqm_dtoe_free_srq_bitmap_index cqm3_dtoe_free_srq_bitmap_index
+#define cqm_dtoe_share_recv_queue_create cqm3_dtoe_share_recv_queue_create
+#define cqm_get_db_addr cqm3_get_db_addr
+#define cqm_ring_direct_wqe_db cqm3_ring_direct_wqe_db
+#define cqm_fake_vf_num_set cqm3_fake_vf_num_set
+#define cqm_need_secure_mem cqm3_need_secure_mem
+
+#endif
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_main.c b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_main.c
new file mode 100644
index 0000000000000..4232ae0f33bf1
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_main.c
@@ -0,0 +1,1743 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+
+#include "ossl_knl.h"
+#include "hinic3_hw.h"
+#include "hinic3_mt.h"
+#include "hinic3_hwdev.h"
+#include "hinic3_hwif.h"
+#include "hinic3_hw_cfg.h"
+
+#include "cqm_object.h"
+#include "cqm_bitmap_table.h"
+#include "cqm_bat_cla.h"
+#include "cqm_bloomfilter.h"
+#include "cqm_db.h"
+#include "cqm_memsec.h"
+#include "cqm_main.h"
+
+static unsigned char roce_qpc_rsv_mode = CQM_QPC_ROCE_NORMAL;
+module_param(roce_qpc_rsv_mode, byte, 0644);
+MODULE_PARM_DESC(roce_qpc_rsv_mode,
+ "for roce reserve 4k qpc(qpn) (default=0, 0-rsv:2, 1-rsv:4k, 2-rsv:200k+2)");
+
+static s32 cqm_set_fake_vf_child_timer(struct tag_cqm_handle *cqm_handle,
+ struct tag_cqm_handle *fake_cqm_handle, bool en)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)cqm_handle->ex_handle;
+ u16 func_global_idx;
+ s32 ret;
+
+ if (fake_cqm_handle->func_capability.timer_enable == 0)
+ return CQM_SUCCESS;
+
+ func_global_idx = fake_cqm_handle->func_attribute.func_global_idx;
+ ret = hinic3_func_tmr_bitmap_set(cqm_handle->ex_handle, func_global_idx, en);
+ if (ret != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, "func_id %u Timer %s timer bitmap failed\n",
+ func_global_idx, en ? "enable" : "disable");
+ return CQM_FAIL;
+}
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_unset_fake_vf_timer(struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)cqm_handle->ex_handle;
+ s32 child_func_number;
+ u32 i;
+
+ child_func_number = cqm_get_child_func_number(cqm_handle);
+ if (child_func_number == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(child_func_number));
+ return CQM_FAIL;
+ }
+
+ for (i = 0; i < (u32)child_func_number; i++)
+ (void)cqm_set_fake_vf_child_timer(cqm_handle,
+ cqm_handle->fake_cqm_handle[i], false);
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_set_fake_vf_timer(struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)cqm_handle->ex_handle;
+ s32 child_func_number;
+ u32 i;
+ s32 ret;
+
+ child_func_number = cqm_get_child_func_number(cqm_handle);
+ if (child_func_number == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(child_func_number));
+ return CQM_FAIL;
+ }
+
+ for (i = 0; i < (u32)child_func_number; i++) {
+ ret = cqm_set_fake_vf_child_timer(cqm_handle,
+ cqm_handle->fake_cqm_handle[i], true);
+ if (ret != CQM_SUCCESS)
+ goto err;
+ }
+
+ return CQM_SUCCESS;
+err:
+ (void)cqm_unset_fake_vf_timer(cqm_handle);
+ return CQM_FAIL;
+}
+
+static s32 cqm_set_timer_enable(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+
+ if (!ex_handle)
+ return CQM_FAIL;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (cqm_handle->func_capability.fake_func_type == CQM_FAKE_FUNC_PARENT &&
+ cqm_set_fake_vf_timer(cqm_handle) != CQM_SUCCESS)
+ return CQM_FAIL;
+
+ /* The timer bitmap is set directly at the beginning of the CQM.
+ * The ifconfig up/down command is not used to set or clear the bitmap.
+ */
+ if (hinic3_func_tmr_bitmap_set(ex_handle, hinic3_global_func_id(ex_handle),
+ true) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, "func_id %u Timer start: enable timer bitmap failed\n",
+ hinic3_global_func_id(ex_handle));
+ goto err;
+ }
+
+ return CQM_SUCCESS;
+
+err:
+ cqm_unset_fake_vf_timer(cqm_handle);
+ return CQM_FAIL;
+}
+
+static s32 cqm_set_timer_disable(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+
+ if (!ex_handle)
+ return CQM_FAIL;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+
+ if (cqm_handle->func_capability.fake_func_type != CQM_FAKE_FUNC_CHILD_CONFLICT &&
+ hinic3_func_tmr_bitmap_set(ex_handle, hinic3_global_func_id(ex_handle),
+ false) != CQM_SUCCESS)
+ cqm_err(handle->dev_hdl, "func_id %u Timer stop: disable timer bitmap failed\n",
+ hinic3_global_func_id(ex_handle));
+
+ if (cqm_handle->func_capability.fake_func_type == CQM_FAKE_FUNC_PARENT &&
+ cqm_unset_fake_vf_timer(cqm_handle) != CQM_SUCCESS)
+ return CQM_FAIL;
+
+ return CQM_SUCCESS;
+}
+
+static s32 cqm_init_all(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ /* Initialize secure memory. */
+ if (cqm_secure_mem_init(ex_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_mem_init));
+ return CQM_FAIL;
+ }
+
+ /* Initialize memory entries such as BAT, CLA, and bitmap. */
+ if (cqm_mem_init(ex_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_mem_init));
+ goto err1;
+ }
+
+ /* Event callback initialization */
+ if (cqm_event_init(ex_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_event_init));
+ goto err2;
+ }
+
+ /* Doorbell initiation */
+ if (cqm_db_init(ex_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_db_init));
+ goto err3;
+ }
+
+ /* Initialize the bloom filter. */
+ if (cqm_bloomfilter_init(ex_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_bloomfilter_init));
+ goto err4;
+ }
+
+ if (cqm_set_timer_enable(ex_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_set_timer_enable));
+ goto err5;
+ }
+
+ return CQM_SUCCESS;
+err5:
+ cqm_bloomfilter_uninit(ex_handle);
+err4:
+ cqm_db_uninit(ex_handle);
+err3:
+ cqm_event_uninit(ex_handle);
+err2:
+ cqm_mem_uninit(ex_handle);
+err1:
+ cqm_secure_mem_deinit(ex_handle);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_init
+ * Description : Complete CQM initialization.
+ * If the function is a parent fake function, copy the fake.
+ * If it is a child fake function (in the fake copy function,
+ * not in this function), set fake_en in the BAT/CLA table.
+ * cqm_init->cqm_mem_init->cqm_fake_init(copy)
+ * If the child fake conflict occurs, resources are not
+ * initialized, but the timer must be enabled.
+ * If the function is of the normal type,
+ * follow the normal process.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_init(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ s32 ret;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ cqm_handle = kmalloc(sizeof(*cqm_handle), GFP_KERNEL | __GFP_ZERO);
+ if (!cqm_handle)
+ return CQM_FAIL;
+
+ /* Clear the memory to prevent other systems from
+ * not clearing the memory.
+ */
+ memset(cqm_handle, 0, sizeof(struct tag_cqm_handle));
+
+ cqm_handle->ex_handle = handle;
+ cqm_handle->dev = (struct pci_dev *)(handle->pcidev_hdl);
+ handle->cqm_hdl = (void *)cqm_handle;
+
+ /* Clearing Statistics */
+ memset(&handle->hw_stats.cqm_stats, 0, sizeof(struct cqm_stats));
+
+ /* Reads VF/PF information. */
+ cqm_handle->func_attribute = handle->hwif->attr;
+ cqm_info(handle->dev_hdl, "Func init: function[%u] type %d(0:PF,1:VF,2:PPF)\n",
+ cqm_handle->func_attribute.func_global_idx,
+ cqm_handle->func_attribute.func_type);
+
+ /* Read capability from configuration management module */
+ ret = cqm_capability_init(ex_handle);
+ if (ret == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_capability_init));
+ goto err;
+ }
+
+ /* In FAKE mode, only the bitmap of the timer of the function is
+ * enabled, and resources are not initialized. Otherwise, the
+ * configuration of the fake function is overwritten.
+ */
+ if (cqm_handle->func_capability.fake_func_type == CQM_FAKE_FUNC_CHILD_CONFLICT) {
+ handle->cqm_hdl = NULL;
+ kfree(cqm_handle);
+ return CQM_SUCCESS;
+ }
+
+ ret = cqm_init_all(ex_handle);
+ if (ret == CQM_FAIL)
+ goto err;
+
+ return CQM_SUCCESS;
+err:
+ handle->cqm_hdl = NULL;
+ kfree(cqm_handle);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_uninit
+ * Description : Deinitializes the CQM module. This function is called once
+ * each time a function is removed.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_uninit(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ s32 ret;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return;
+ }
+
+ cqm_set_timer_disable(ex_handle);
+
+ /* After the TMR timer stops, the system releases resources
+ * after a delay of one or two milliseconds.
+ */
+ if (cqm_handle->func_attribute.func_type == CQM_PPF) {
+ if (cqm_handle->func_capability.timer_enable ==
+ CQM_TIMER_ENABLE) {
+ cqm_info(handle->dev_hdl, "PPF timer stop\n");
+ ret = hinic3_ppf_tmr_stop(handle);
+ if (ret != CQM_SUCCESS)
+ /* The timer fails to be stopped,
+ * and the resource release is not affected.
+ */
+ cqm_info(handle->dev_hdl, "PPF timer stop, ret=%d\n", ret);
+ }
+
+ hinic3_ppf_ht_gpa_deinit(handle);
+
+ usleep_range(0x384, 0x3E8); /* Somebody requires a delay of 1 ms,
+ * which is inaccurate.
+ */
+ }
+
+ /* Release Bloom Filter Table */
+ cqm_bloomfilter_uninit(ex_handle);
+
+ /* Release hardware doorbell */
+ cqm_db_uninit(ex_handle);
+
+ /* Cancel the callback of the event */
+ cqm_event_uninit(ex_handle);
+
+ /* Release various memory tables and require the service
+ * to release all objects.
+ */
+ cqm_mem_uninit(ex_handle);
+
+ cqm_secure_mem_deinit(ex_handle);
+
+ /* Release cqm_handle */
+ handle->cqm_hdl = NULL;
+ kfree(cqm_handle);
+}
+
+static void cqm_test_mode_init(struct tag_cqm_handle *cqm_handle,
+ struct service_cap *service_capability)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ if (service_capability->test_mode == 0)
+ return;
+
+ cqm_info(handle->dev_hdl, "Enter CQM test mode\n");
+
+ func_cap->qpc_number = service_capability->test_qpc_num;
+ func_cap->qpc_reserved =
+ GET_MAX(func_cap->qpc_reserved,
+ service_capability->test_qpc_resvd_num);
+ func_cap->xid_alloc_mode = service_capability->test_xid_alloc_mode;
+ func_cap->gpa_check_enable = service_capability->test_gpa_check_enable;
+ func_cap->pagesize_reorder = service_capability->test_page_size_reorder;
+ func_cap->qpc_alloc_static =
+ (bool)(service_capability->test_qpc_alloc_mode);
+ func_cap->scqc_alloc_static =
+ (bool)(service_capability->test_scqc_alloc_mode);
+ func_cap->flow_table_based_conn_number =
+ service_capability->test_max_conn_num;
+ func_cap->flow_table_based_conn_cache_number =
+ service_capability->test_max_cache_conn_num;
+ func_cap->scqc_number = service_capability->test_scqc_num;
+ func_cap->mpt_number = service_capability->test_mpt_num;
+ func_cap->mpt_reserved = service_capability->test_mpt_recvd_num;
+ func_cap->reorder_number = service_capability->test_reorder_num;
+ /* 256K buckets, 256K*64B = 16MB */
+ func_cap->hash_number = service_capability->test_hash_num;
+}
+
+static void cqm_service_capability_update(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+
+ func_cap->qpc_number = GET_MIN(CQM_MAX_QPC_NUM, func_cap->qpc_number);
+ func_cap->scqc_number = GET_MIN(CQM_MAX_SCQC_NUM,
+ func_cap->scqc_number);
+ func_cap->srqc_number = GET_MIN(CQM_MAX_SRQC_NUM,
+ func_cap->srqc_number);
+ func_cap->childc_number = GET_MIN(CQM_MAX_CHILDC_NUM,
+ func_cap->childc_number);
+}
+
+static void cqm_service_valid_init(struct tag_cqm_handle *cqm_handle,
+ const struct service_cap *service_capability)
+{
+ u16 type = service_capability->chip_svc_type;
+ struct tag_cqm_service *svc = cqm_handle->service;
+
+ svc[CQM_SERVICE_T_NIC].valid = ((type & CFG_SERVICE_MASK_NIC) != 0) ?
+ true : false;
+ svc[CQM_SERVICE_T_OVS].valid = ((type & CFG_SERVICE_MASK_OVS) != 0) ?
+ true : false;
+ svc[CQM_SERVICE_T_ROCE].valid = ((type & CFG_SERVICE_MASK_ROCE) != 0) ?
+ true : false;
+ svc[CQM_SERVICE_T_TOE].valid = ((type & CFG_SERVICE_MASK_TOE) != 0) ?
+ true : false;
+ svc[CQM_SERVICE_T_FC].valid = ((type & CFG_SERVICE_MASK_FC) != 0) ?
+ true : false;
+ svc[CQM_SERVICE_T_IPSEC].valid = ((type & CFG_SERVICE_MASK_IPSEC) != 0) ?
+ true : false;
+ svc[CQM_SERVICE_T_VBS].valid = ((type & CFG_SERVICE_MASK_VBS) != 0) ?
+ true : false;
+ svc[CQM_SERVICE_T_VIRTIO].valid = ((type & CFG_SERVICE_MASK_VIRTIO) != 0) ?
+ true : false;
+ svc[CQM_SERVICE_T_IOE].valid = false;
+ svc[CQM_SERVICE_T_PPA].valid = ((type & CFG_SERVICE_MASK_PPA) != 0) ?
+ true : false;
+}
+
+static void cqm_service_capability_init_nic(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ cqm_info(handle->dev_hdl, "Cap init: nic is valid, but nic need not be init by cqm\n");
+}
+
+static void cqm_service_capability_init_ovs(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct service_cap *service_capability = (struct service_cap *)pra;
+ struct ovs_service_cap *ovs_cap = &service_capability->ovs_cap;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ cqm_info(handle->dev_hdl, "Cap init: ovs is valid\n");
+ cqm_info(handle->dev_hdl, "Cap init: ovs qpc 0x%x\n",
+ ovs_cap->dev_ovs_cap.max_pctxs);
+ func_cap->hash_number += ovs_cap->dev_ovs_cap.max_pctxs;
+ func_cap->hash_basic_size = CQM_HASH_BUCKET_SIZE_64;
+ func_cap->qpc_number += ovs_cap->dev_ovs_cap.max_pctxs;
+ func_cap->qpc_basic_size = GET_MAX(ovs_cap->pctx_sz,
+ func_cap->qpc_basic_size);
+ func_cap->qpc_reserved += ovs_cap->dev_ovs_cap.max_pctxs;
+ func_cap->qpc_alloc_static = true;
+ func_cap->pagesize_reorder = CQM_OVS_PAGESIZE_ORDER;
+}
+
+static void cqm_service_capability_init_roce(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct hinic3_board_info *board_info = &handle->board_info;
+ struct service_cap *service_capability = (struct service_cap *)pra;
+ struct rdma_service_cap *rdma_cap = &service_capability->rdma_cap;
+ struct dev_roce_svc_own_cap *roce_own_cap =
+ &rdma_cap->dev_rdma_cap.roce_own_cap;
+
+ cqm_info(handle->dev_hdl, "Cap init: roce is valid\n");
+ cqm_info(handle->dev_hdl, "Cap init: roce qpc 0x%x, scqc 0x%x, srqc 0x%x, drc_qp 0x%x\n",
+ roce_own_cap->max_qps, roce_own_cap->max_cqs,
+ roce_own_cap->max_srqs, roce_own_cap->max_drc_qps);
+ cqm_info(handle->dev_hdl, "Cap init: type 0x%x, scenes:0x%x, qpc_rsv:0x%x, srv_bmp:0x%x\n",
+ board_info->board_type, board_info->scenes_id,
+ roce_qpc_rsv_mode, board_info->service_en_bitmap);
+
+ if (roce_qpc_rsv_mode == CQM_QPC_ROCE_VBS_MODE) {
+ func_cap->qpc_reserved += CQM_QPC_ROCE_RSVD;
+ func_cap->qpc_reserved_back += CQM_QPC_ROCE_VBS_RSVD_BACK;
+ } else if ((service_capability->chip_svc_type & CFG_SERVICE_MASK_ROCEAA) != 0) {
+ func_cap->qpc_reserved += CQM_QPC_ROCEAA_RSVD;
+ func_cap->scq_reserved += CQM_CQ_ROCEAA_RSVD;
+ func_cap->srq_reserved += CQM_SRQ_ROCEAA_RSVD;
+ } else {
+ func_cap->qpc_reserved += CQM_QPC_ROCE_RSVD;
+ }
+ func_cap->qpc_number += roce_own_cap->max_qps;
+ func_cap->qpc_basic_size = GET_MAX(roce_own_cap->qpc_entry_sz,
+ func_cap->qpc_basic_size);
+ if (cqm_handle->func_attribute.func_type == CQM_PF && (IS_MASTER_HOST(handle))) {
+ func_cap->hash_number = roce_own_cap->max_qps;
+ func_cap->hash_basic_size = CQM_HASH_BUCKET_SIZE_64;
+ }
+ func_cap->qpc_alloc_static = true;
+ func_cap->scqc_number += roce_own_cap->max_cqs;
+ func_cap->scqc_basic_size = GET_MAX(rdma_cap->cqc_entry_sz,
+ func_cap->scqc_basic_size);
+ func_cap->srqc_number += roce_own_cap->max_srqs;
+ func_cap->srqc_basic_size = GET_MAX(roce_own_cap->srqc_entry_sz,
+ func_cap->srqc_basic_size);
+ func_cap->mpt_number += roce_own_cap->max_mpts;
+ func_cap->mpt_reserved += rdma_cap->reserved_mrws;
+ func_cap->mpt_basic_size = GET_MAX(rdma_cap->mpt_entry_sz,
+ func_cap->mpt_basic_size);
+ func_cap->gid_number = CQM_GID_RDMA_NUM;
+ func_cap->gid_basic_size = CQM_GID_SIZE_32;
+ func_cap->childc_number += CQM_CHILDC_ROCE_NUM;
+ func_cap->childc_basic_size = GET_MAX(CQM_CHILDC_SIZE_256,
+ func_cap->childc_basic_size);
+}
+
+static void cqm_service_capability_init_toe(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct tag_cqm_toe_private_capability *toe_own_cap = &cqm_handle->toe_own_capability;
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct service_cap *service_capability = (struct service_cap *)pra;
+ struct rdma_service_cap *rdma_cap = &service_capability->rdma_cap;
+ struct toe_service_cap *toe_cap = &service_capability->toe_cap;
+ struct dev_toe_svc_cap *dev_toe_cap = &toe_cap->dev_toe_cap;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ cqm_info(handle->dev_hdl, "Cap init: toe is valid\n");
+ cqm_info(handle->dev_hdl, "Cap init: toe qpc 0x%x, scqc 0x%x, srqc 0x%x\n",
+ dev_toe_cap->max_pctxs, dev_toe_cap->max_cqs,
+ dev_toe_cap->max_srqs);
+ func_cap->hash_number += dev_toe_cap->max_pctxs;
+ func_cap->hash_basic_size = CQM_HASH_BUCKET_SIZE_64;
+ func_cap->qpc_number += dev_toe_cap->max_pctxs;
+ func_cap->qpc_basic_size = GET_MAX(toe_cap->pctx_sz,
+ func_cap->qpc_basic_size);
+ func_cap->qpc_alloc_static = true;
+ func_cap->scqc_number += dev_toe_cap->max_cqs;
+ func_cap->scqc_basic_size = GET_MAX(toe_cap->scqc_sz,
+ func_cap->scqc_basic_size);
+ func_cap->scqc_alloc_static = true;
+
+ toe_own_cap->toe_srqc_number = dev_toe_cap->max_srqs;
+ toe_own_cap->toe_srqc_start_id = dev_toe_cap->srq_id_start;
+ toe_own_cap->toe_srqc_basic_size = CQM_SRQC_SIZE_64;
+ func_cap->childc_number += dev_toe_cap->max_cctxt;
+ func_cap->childc_basic_size = GET_MAX(CQM_CHILDC_SIZE_256,
+ func_cap->childc_basic_size);
+ func_cap->mpt_number += dev_toe_cap->max_mpts;
+ func_cap->mpt_reserved = 0;
+ func_cap->mpt_basic_size = GET_MAX(rdma_cap->mpt_entry_sz,
+ func_cap->mpt_basic_size);
+}
+
+static void cqm_service_capability_init_ioe(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ cqm_info(handle->dev_hdl, "Cap init: ioe is valid\n");
+}
+
+static void cqm_service_capability_init_fc(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct service_cap *service_capability = (struct service_cap *)pra;
+ struct fc_service_cap *fc_cap = &service_capability->fc_cap;
+ struct dev_fc_svc_cap *dev_fc_cap = &fc_cap->dev_fc_cap;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ cqm_info(handle->dev_hdl, "Cap init: fc is valid\n");
+ cqm_info(handle->dev_hdl, "Cap init: fc qpc 0x%x, scqc 0x%x, srqc 0x%x\n",
+ dev_fc_cap->max_parent_qpc_num, dev_fc_cap->scq_num,
+ dev_fc_cap->srq_num);
+ func_cap->hash_number += dev_fc_cap->max_parent_qpc_num;
+ func_cap->hash_basic_size = CQM_HASH_BUCKET_SIZE_64;
+ func_cap->qpc_number += dev_fc_cap->max_parent_qpc_num;
+ func_cap->qpc_basic_size = GET_MAX(fc_cap->parent_qpc_size,
+ func_cap->qpc_basic_size);
+ func_cap->qpc_alloc_static = true;
+ func_cap->scqc_number += dev_fc_cap->scq_num;
+ func_cap->scqc_basic_size = GET_MAX(fc_cap->scqc_size,
+ func_cap->scqc_basic_size);
+ func_cap->srqc_number += dev_fc_cap->srq_num;
+ func_cap->srqc_basic_size = GET_MAX(fc_cap->srqc_size,
+ func_cap->srqc_basic_size);
+ func_cap->lun_number = CQM_LUN_FC_NUM;
+ func_cap->lun_basic_size = CQM_LUN_SIZE_8;
+ func_cap->taskmap_number = CQM_TASKMAP_FC_NUM;
+ func_cap->taskmap_basic_size = PAGE_SIZE;
+ func_cap->childc_number += dev_fc_cap->max_child_qpc_num;
+ func_cap->childc_basic_size = GET_MAX(fc_cap->child_qpc_size,
+ func_cap->childc_basic_size);
+ func_cap->pagesize_reorder = CQM_FC_PAGESIZE_ORDER;
+}
+
+static void cqm_service_capability_init_vbs(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct service_cap *service_capability = (struct service_cap *)pra;
+ struct vbs_service_cap *vbs_cap = &service_capability->vbs_cap;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ cqm_info(handle->dev_hdl, "Cap init: vbs is valid\n");
+
+ /* If the entry size is greater than the cache line (256 bytes),
+ * align the entries by cache line.
+ */
+ func_cap->xid2cid_number +=
+ (CQM_XID2CID_VBS_NUM * service_capability->virtio_vq_size) / CQM_CHIP_CACHELINE;
+ func_cap->xid2cid_basic_size = CQM_CHIP_CACHELINE;
+ func_cap->qpc_number += (vbs_cap->vbs_max_volq * 2); // VOLQ group * 2
+ func_cap->qpc_basic_size = GET_MAX(CQM_VBS_QPC_SIZE,
+ func_cap->qpc_basic_size);
+ func_cap->qpc_alloc_static = true;
+}
+
+static void cqm_service_capability_init_ipsec(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct service_cap *service_capability = (struct service_cap *)pra;
+ struct ipsec_service_cap *ipsec_cap = &service_capability->ipsec_cap;
+ struct dev_ipsec_svc_cap *ipsec_srvcap = &ipsec_cap->dev_ipsec_cap;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ func_cap->childc_number += ipsec_srvcap->max_sactxs;
+ func_cap->childc_basic_size = GET_MAX(CQM_CHILDC_SIZE_256,
+ func_cap->childc_basic_size);
+ func_cap->scqc_number += ipsec_srvcap->max_cqs;
+ func_cap->scqc_basic_size = GET_MAX(CQM_SCQC_SIZE_64,
+ func_cap->scqc_basic_size);
+ func_cap->scqc_alloc_static = true;
+ cqm_info(handle->dev_hdl, "Cap init: ipsec is valid\n");
+ cqm_info(handle->dev_hdl, "Cap init: ipsec 0x%x, childc %d, scqc 0x%x, scqc_bsize %d\n",
+ ipsec_srvcap->max_sactxs, func_cap->childc_basic_size,
+ ipsec_srvcap->max_cqs, func_cap->scqc_basic_size);
+}
+
+static void cqm_service_capability_init_virtio(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct service_cap *service_capability = (struct service_cap *)pra;
+
+ cqm_info(handle->dev_hdl, "Cap init: virtio is valid\n");
+ /* If the entry size is greater than the cache line (256 bytes),
+ * align the entries by cache line.
+ */
+ cqm_handle->func_capability.xid2cid_number +=
+ (CQM_XID2CID_VIRTIO_NUM * service_capability->virtio_vq_size) / CQM_CHIP_CACHELINE;
+ cqm_handle->func_capability.xid2cid_basic_size = CQM_CHIP_CACHELINE;
+}
+
+static void cqm_service_capability_init_ppa(struct tag_cqm_handle *cqm_handle, void *pra)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct service_cap *service_capability = (struct service_cap *)pra;
+ struct ppa_service_cap *ppa_cap = &service_capability->ppa_cap;
+
+ cqm_info(handle->dev_hdl, "Cap init: ppa is valid\n");
+ func_cap->hash_basic_size = CQM_HASH_BUCKET_SIZE_64;
+ func_cap->qpc_alloc_static = true;
+ func_cap->pagesize_reorder = CQM_PPA_PAGESIZE_ORDER;
+ func_cap->qpc_basic_size = GET_MAX(ppa_cap->pctx_sz,
+ func_cap->qpc_basic_size);
+}
+
+struct cqm_srv_cap_init serv_cap_init_list[] = {
+ {CQM_SERVICE_T_NIC, cqm_service_capability_init_nic},
+ {CQM_SERVICE_T_OVS, cqm_service_capability_init_ovs},
+ {CQM_SERVICE_T_ROCE, cqm_service_capability_init_roce},
+ {CQM_SERVICE_T_TOE, cqm_service_capability_init_toe},
+ {CQM_SERVICE_T_IOE, cqm_service_capability_init_ioe},
+ {CQM_SERVICE_T_FC, cqm_service_capability_init_fc},
+ {CQM_SERVICE_T_VBS, cqm_service_capability_init_vbs},
+ {CQM_SERVICE_T_IPSEC, cqm_service_capability_init_ipsec},
+ {CQM_SERVICE_T_VIRTIO, cqm_service_capability_init_virtio},
+ {CQM_SERVICE_T_PPA, cqm_service_capability_init_ppa},
+};
+
+static void cqm_service_capability_init(struct tag_cqm_handle *cqm_handle,
+ struct service_cap *service_capability)
+{
+ u32 list_size = ARRAY_SIZE(serv_cap_init_list);
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 i;
+
+ for (i = 0; i < CQM_SERVICE_T_MAX; i++) {
+ cqm_handle->service[i].valid = false;
+ cqm_handle->service[i].has_register = false;
+ cqm_handle->service[i].buf_order = 0;
+ }
+
+ cqm_service_valid_init(cqm_handle, service_capability);
+
+ cqm_info(handle->dev_hdl, "Cap init: service type %d\n",
+ service_capability->chip_svc_type);
+
+ for (i = 0; i < list_size; i++) {
+ if (cqm_handle->service[serv_cap_init_list[i].service_type].valid &&
+ serv_cap_init_list[i].serv_cap_proc) {
+ serv_cap_init_list[i].serv_cap_proc(cqm_handle,
+ (void *)service_capability);
+ }
+ }
+}
+
+s32 cqm_get_fake_func_type(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ u32 parent_func, child_func_start, child_func_number, i;
+ u32 idx = cqm_handle->func_attribute.func_global_idx;
+
+ /* Currently, only one set of fake configurations is implemented.
+ * fake_cfg_number = 1
+ */
+ for (i = 0; i < func_cap->fake_cfg_number; i++) {
+ parent_func = func_cap->fake_cfg[i].parent_func;
+ child_func_start = func_cap->fake_cfg[i].child_func_start;
+ child_func_number = func_cap->fake_cfg[i].child_func_number;
+
+ if (idx == parent_func) {
+ return CQM_FAKE_FUNC_PARENT;
+ } else if ((idx >= child_func_start) &&
+ (idx < (child_func_start + child_func_number))) {
+ return CQM_FAKE_FUNC_CHILD_CONFLICT;
+ }
+ }
+
+ return CQM_FAKE_FUNC_NORMAL;
+}
+
+s32 cqm_get_child_func_start(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct hinic3_func_attr *func_attr = &cqm_handle->func_attribute;
+ u32 i;
+
+ /* Currently, only one set of fake configurations is implemented.
+ * fake_cfg_number = 1
+ */
+ for (i = 0; i < func_cap->fake_cfg_number; i++) {
+ if (func_attr->func_global_idx ==
+ func_cap->fake_cfg[i].parent_func)
+ return (s32)(func_cap->fake_cfg[i].child_func_start);
+ }
+
+ return CQM_FAIL;
+}
+
+s32 cqm_get_child_func_number(struct tag_cqm_handle *cqm_handle)
+{
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct hinic3_func_attr *func_attr = &cqm_handle->func_attribute;
+ u32 i;
+
+ for (i = 0; i < func_cap->fake_cfg_number; i++) {
+ if (func_attr->func_global_idx ==
+ func_cap->fake_cfg[i].parent_func)
+ return (s32)(func_cap->fake_cfg[i].child_func_number);
+ }
+
+ return CQM_FAIL;
+}
+
+/* Set func_type in fake_cqm_handle to ppf, pf, or vf. */
+static void cqm_set_func_type(struct tag_cqm_handle *cqm_handle)
+{
+ u32 idx = cqm_handle->func_attribute.func_global_idx;
+
+ if (idx == 0)
+ cqm_handle->func_attribute.func_type = CQM_PPF;
+ else if (idx < CQM_MAX_PF_NUM)
+ cqm_handle->func_attribute.func_type = CQM_PF;
+ else
+ cqm_handle->func_attribute.func_type = CQM_VF;
+}
+
+static void cqm_lb_fake_mode_init(struct hinic3_hwdev *handle, struct service_cap *svc_cap)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct tag_cqm_fake_cfg *cfg = func_cap->fake_cfg;
+
+ func_cap->lb_mode = svc_cap->lb_mode;
+
+ /* Initializing the LB Mode */
+ if (func_cap->lb_mode == CQM_LB_MODE_NORMAL)
+ func_cap->smf_pg = 0;
+ else
+ func_cap->smf_pg = svc_cap->smf_pg;
+
+ /* Initializing the FAKE Mode */
+ if (svc_cap->fake_vf_num == 0) {
+ func_cap->fake_cfg_number = 0;
+ func_cap->fake_func_type = CQM_FAKE_FUNC_NORMAL;
+ func_cap->fake_vf_qpc_number = 0;
+ } else {
+ func_cap->fake_cfg_number = 1;
+
+ /* When configuring fake mode, ensure that the parent function
+ * cannot be contained in the child function; otherwise, the
+ * system will be initialized repeatedly. The following
+ * configuration is used to verify the OVS fake configuration on
+ * the FPGA.
+ */
+ cfg[0].parent_func = cqm_handle->func_attribute.port_to_port_idx;
+ cfg[0].child_func_start = svc_cap->fake_vf_start_id;
+ cfg[0].child_func_number = svc_cap->fake_vf_num_cfg;
+
+ func_cap->fake_func_type = (u32)cqm_get_fake_func_type(cqm_handle);
+ func_cap->fake_vf_qpc_number = svc_cap->fake_vf_max_pctx;
+ }
+
+ cqm_info(handle->dev_hdl, "Cap init: lb_mode=%u\n", func_cap->lb_mode);
+ cqm_info(handle->dev_hdl, "Cap init: smf_pg=%u\n", func_cap->smf_pg);
+ cqm_info(handle->dev_hdl, "Cap init: fake_func_type=%u\n", func_cap->fake_func_type);
+ cqm_info(handle->dev_hdl, "Cap init: fake_cfg_number=%u\n", func_cap->fake_cfg_number);
+}
+
+static int cqm_capability_init_bloomfilter(struct hinic3_hwdev *handle)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct service_cap *service_capability = &handle->cfg_mgmt->svc_cap;
+
+ func_cap->bloomfilter_enable = service_capability->bloomfilter_en;
+ cqm_info(handle->dev_hdl, "Cap init: bloomfilter_enable %u (1: enable; 0: disable)\n",
+ func_cap->bloomfilter_enable);
+
+ if (func_cap->bloomfilter_enable != 0) {
+ func_cap->bloomfilter_length = service_capability->bfilter_len;
+ func_cap->bloomfilter_addr = service_capability->bfilter_start_addr;
+ if (func_cap->bloomfilter_length != 0 &&
+ !cqm_check_align(func_cap->bloomfilter_length)) {
+ cqm_err(handle->dev_hdl, "Cap bloomfilter len %u is not the power of 2\n",
+ func_cap->bloomfilter_length);
+
+ return CQM_FAIL;
+ }
+ }
+
+ cqm_info(handle->dev_hdl, "Cap init: bloomfilter_length 0x%x, bloomfilter_addr 0x%x\n",
+ func_cap->bloomfilter_length, func_cap->bloomfilter_addr);
+
+ return 0;
+}
+
+static void cqm_capability_init_part_cap(struct hinic3_hwdev *handle)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct service_cap *service_capability = &handle->cfg_mgmt->svc_cap;
+
+ func_cap->flow_table_based_conn_number = service_capability->max_connect_num;
+ func_cap->flow_table_based_conn_cache_number = service_capability->max_stick2cache_num;
+ cqm_info(handle->dev_hdl, "Cap init: cfg max_conn_num 0x%x, max_cache_conn_num 0x%x\n",
+ func_cap->flow_table_based_conn_number,
+ func_cap->flow_table_based_conn_cache_number);
+
+ func_cap->qpc_reserved = 0;
+ func_cap->qpc_reserved_back = 0;
+ func_cap->mpt_reserved = 0;
+ func_cap->scq_reserved = 0;
+ func_cap->srq_reserved = 0;
+ func_cap->qpc_alloc_static = false;
+ func_cap->scqc_alloc_static = false;
+
+ func_cap->l3i_number = 0;
+ func_cap->l3i_basic_size = CQM_L3I_SIZE_8;
+
+ func_cap->xid_alloc_mode = true; /* xid alloc do not reuse */
+ func_cap->gpa_check_enable = true;
+}
+
+static int cqm_capability_init_timer(struct hinic3_hwdev *handle)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ struct service_cap *service_capability = &handle->cfg_mgmt->svc_cap;
+ struct hinic3_func_attr *func_attr = &cqm_handle->func_attribute;
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ u32 total_timer_num = 0;
+ int err;
+
+ /* Initializes the PPF capabilities: include timer, pf, vf. */
+ if (func_attr->func_type == CQM_PPF && service_capability->timer_en) {
+ func_cap->pf_num = service_capability->pf_num;
+ func_cap->pf_id_start = service_capability->pf_id_start;
+ func_cap->vf_num = service_capability->vf_num;
+ func_cap->vf_id_start = service_capability->vf_id_start;
+ cqm_info(handle->dev_hdl, "Cap init: total function num 0x%x\n",
+ service_capability->host_total_function);
+ cqm_info(handle->dev_hdl,
+ "Cap init: pf_num 0x%x, pf_start 0x%x, vf_num 0x%x, vf_start 0x%x\n",
+ func_cap->pf_num, func_cap->pf_id_start,
+ func_cap->vf_num, func_cap->vf_id_start);
+
+ err = hinic3_get_ppf_timer_cfg(handle);
+ if (err != 0)
+ return err;
+
+ func_cap->timer_pf_num = service_capability->timer_pf_num;
+ func_cap->timer_pf_id_start = service_capability->timer_pf_id_start;
+ func_cap->timer_vf_num = service_capability->timer_vf_num;
+ func_cap->timer_vf_id_start = service_capability->timer_vf_id_start;
+ cqm_info(handle->dev_hdl,
+ "timer init: pf_num 0x%x, pf_start 0x%x, vf_num 0x%x, vf_start 0x%x\n",
+ func_cap->timer_pf_num, func_cap->timer_pf_id_start,
+ func_cap->timer_vf_num, func_cap->timer_vf_id_start);
+
+ total_timer_num = func_cap->timer_pf_num + func_cap->timer_vf_num;
+ if (IS_SLAVE_HOST(handle)) {
+ total_timer_num *= CQM_TIMER_NUM_MULTI;
+ cqm_info(handle->dev_hdl,
+ "timer init: need double tw resources, total_timer_num=0x%x\n",
+ total_timer_num);
+ }
+ }
+
+ func_cap->timer_enable = service_capability->timer_en;
+ cqm_info(handle->dev_hdl, "Cap init: timer_enable %u (1: enable; 0: disable)\n",
+ func_cap->timer_enable);
+
+ func_cap->timer_number = CQM_TIMER_ALIGN_SCALE_NUM * total_timer_num;
+ func_cap->timer_basic_size = CQM_TIMER_SIZE_32;
+
+ return 0;
+}
+
+static void cqm_capability_init_cap_print(struct hinic3_hwdev *handle)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct service_cap *service_capability = &handle->cfg_mgmt->svc_cap;
+
+ func_cap->ft_enable = service_capability->sf_svc_attr.ft_en;
+ func_cap->rdma_enable = service_capability->sf_svc_attr.rdma_en;
+
+ cqm_info(handle->dev_hdl, "Cap init: pagesize_reorder %u\n", func_cap->pagesize_reorder);
+ cqm_info(handle->dev_hdl, "Cap init: xid_alloc_mode %d, gpa_check_enable %d\n",
+ func_cap->xid_alloc_mode, func_cap->gpa_check_enable);
+ cqm_info(handle->dev_hdl, "Cap init: qpc_alloc_mode %d, scqc_alloc_mode %d\n",
+ func_cap->qpc_alloc_static, func_cap->scqc_alloc_static);
+ cqm_info(handle->dev_hdl, "Cap init: hash_number 0x%x\n", func_cap->hash_number);
+ cqm_info(handle->dev_hdl, "Cap init: qpc_num 0x%x, qpc_rsvd 0x%x, qpc_basic_size 0x%x\n",
+ func_cap->qpc_number, func_cap->qpc_reserved, func_cap->qpc_basic_size);
+ cqm_info(handle->dev_hdl, "Cap init: scqc_num 0x%x, scqc_rsvd 0x%x, scqc_basic 0x%x\n",
+ func_cap->scqc_number, func_cap->scq_reserved, func_cap->scqc_basic_size);
+ cqm_info(handle->dev_hdl, "Cap init: srqc_num 0x%x, srqc_rsvd 0x%x, srqc_basic 0x%x\n",
+ func_cap->srqc_number, func_cap->srq_reserved, func_cap->srqc_basic_size);
+ cqm_info(handle->dev_hdl, "Cap init: mpt_number 0x%x, mpt_reserved 0x%x\n",
+ func_cap->mpt_number, func_cap->mpt_reserved);
+ cqm_info(handle->dev_hdl, "Cap init: gid_number 0x%x, lun_number 0x%x\n",
+ func_cap->gid_number, func_cap->lun_number);
+ cqm_info(handle->dev_hdl, "Cap init: taskmap_number 0x%x, l3i_number 0x%x\n",
+ func_cap->taskmap_number, func_cap->l3i_number);
+ cqm_info(handle->dev_hdl, "Cap init: timer_number 0x%x, childc_number 0x%x\n",
+ func_cap->timer_number, func_cap->childc_number);
+ cqm_info(handle->dev_hdl, "Cap init: childc_basic_size 0x%x\n",
+ func_cap->childc_basic_size);
+ cqm_info(handle->dev_hdl, "Cap init: xid2cid_number 0x%x, reorder_number 0x%x\n",
+ func_cap->xid2cid_number, func_cap->reorder_number);
+ cqm_info(handle->dev_hdl, "Cap init: ft_enable %d, rdma_enable %d\n",
+ func_cap->ft_enable, func_cap->rdma_enable);
+}
+
+/**
+ * Prototype : cqm_capability_init
+ * Description : Initializes the function and service capabilities of the CQM.
+ * Information needs to be read from the configuration management
+ * module.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/12/9
+ * Modification : Created function
+ */
+s32 cqm_capability_init(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ struct service_cap *service_capability = &handle->cfg_mgmt->svc_cap;
+ struct hinic3_func_attr *func_attr = &cqm_handle->func_attribute;
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ int err = 0;
+
+ err = cqm_capability_init_timer(handle);
+ if (err != 0)
+ goto out;
+
+ err = cqm_capability_init_bloomfilter(handle);
+ if (err != 0)
+ goto out;
+
+ cqm_capability_init_part_cap(handle);
+
+ cqm_lb_fake_mode_init(handle, service_capability);
+
+ cqm_service_capability_init(cqm_handle, service_capability);
+
+ cqm_test_mode_init(cqm_handle, service_capability);
+
+ cqm_service_capability_update(cqm_handle);
+
+ cqm_capability_init_cap_print(handle);
+
+ return CQM_SUCCESS;
+
+out:
+ if (func_attr->func_type == CQM_PPF)
+ func_cap->timer_enable = 0;
+
+ return err;
+}
+
+static void cqm_fake_uninit(struct tag_cqm_handle *cqm_handle)
+{
+ u32 i;
+
+ if (cqm_handle->func_capability.fake_func_type !=
+ CQM_FAKE_FUNC_PARENT)
+ return;
+
+ for (i = 0; i < CQM_FAKE_FUNC_MAX; i++) {
+ kfree(cqm_handle->fake_cqm_handle[i]);
+ cqm_handle->fake_cqm_handle[i] = NULL;
+ }
+}
+
+static void set_fake_cqm_attr(struct hinic3_hwdev *handle, struct tag_cqm_handle *fake_cqm_handle,
+ s32 child_func_start, u32 i)
+{
+ struct tag_cqm_func_capability *func_cap = NULL;
+ struct hinic3_func_attr *func_attr = NULL;
+ struct service_cap *cap = &handle->cfg_mgmt->svc_cap;
+
+ func_attr = &fake_cqm_handle->func_attribute;
+ func_cap = &fake_cqm_handle->func_capability;
+ func_attr->func_global_idx = (u16)(child_func_start + i);
+ cqm_set_func_type(fake_cqm_handle);
+ func_cap->fake_func_type = CQM_FAKE_FUNC_CHILD;
+ cqm_info(handle->dev_hdl, "Fake func init: function[%u] type %d(0:PF,1:VF,2:PPF)\n",
+ func_attr->func_global_idx, func_attr->func_type);
+
+ func_cap->qpc_number = cap->fake_vf_max_pctx;
+ func_cap->qpc_number = GET_MIN(CQM_MAX_QPC_NUM, func_cap->qpc_number);
+ func_cap->hash_number = cap->fake_vf_max_pctx;
+ func_cap->qpc_reserved = cap->fake_vf_max_pctx;
+
+ if (cap->fake_vf_bfilter_len != 0) {
+ func_cap->bloomfilter_enable = true;
+ func_cap->bloomfilter_addr = cap->fake_vf_bfilter_start_addr +
+ cap->fake_vf_bfilter_len * i;
+ func_cap->bloomfilter_length = cap->fake_vf_bfilter_len;
+ }
+}
+
+/**
+ * Prototype : cqm_fake_init
+ * Description : When the fake VF mode is supported, the CQM handles of
+ * the fake VFs need to be copied.
+ * Input : struct tag_cqm_handle *cqm_handle: Parent CQM handle of the current PF
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2020/4/15
+ * Modification : Created function
+ */
+static s32 cqm_fake_init(struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_handle *fake_cqm_handle = NULL;
+ struct tag_cqm_func_capability *func_cap = NULL;
+ s32 child_func_start, child_func_number;
+ u32 i;
+
+ func_cap = &cqm_handle->func_capability;
+ if (func_cap->fake_func_type != CQM_FAKE_FUNC_PARENT)
+ return CQM_SUCCESS;
+
+ child_func_start = cqm_get_child_func_start(cqm_handle);
+ if (child_func_start == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(child_func_start));
+ return CQM_FAIL;
+ }
+
+ child_func_number = cqm_get_child_func_number(cqm_handle);
+ if (child_func_number == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(child_func_number));
+ return CQM_FAIL;
+ }
+
+ for (i = 0; i < (u32)child_func_number; i++) {
+ fake_cqm_handle = kmalloc(sizeof(*fake_cqm_handle), GFP_KERNEL | __GFP_ZERO);
+ if (!fake_cqm_handle)
+ goto err;
+
+ /* Copy the attributes of the parent CQM handle to the child CQM
+ * handle and modify the values of function.
+ */
+ memcpy(fake_cqm_handle, cqm_handle, sizeof(struct tag_cqm_handle));
+ set_fake_cqm_attr(handle, fake_cqm_handle, child_func_start, i);
+
+ fake_cqm_handle->parent_cqm_handle = cqm_handle;
+ cqm_handle->fake_cqm_handle[i] = fake_cqm_handle;
+ }
+
+ return CQM_SUCCESS;
+
+err:
+ cqm_fake_uninit(cqm_handle);
+ return CQM_FAIL;
+}
+
+static void cqm_fake_mem_uninit(struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_handle *fake_cqm_handle = NULL;
+ s32 child_func_number;
+ u32 i;
+
+ if (cqm_handle->func_capability.fake_func_type !=
+ CQM_FAKE_FUNC_PARENT)
+ return;
+
+ child_func_number = cqm_get_child_func_number(cqm_handle);
+ if (child_func_number == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(child_func_number));
+ return;
+ }
+
+ for (i = 0; i < (u32)child_func_number; i++) {
+ fake_cqm_handle = cqm_handle->fake_cqm_handle[i];
+
+ cqm_object_table_uninit(fake_cqm_handle);
+ cqm_bitmap_uninit(fake_cqm_handle);
+ cqm_cla_uninit(fake_cqm_handle, CQM_BAT_ENTRY_MAX);
+ cqm_bat_uninit(fake_cqm_handle);
+ }
+}
+
+/**
+ * Prototype : cqm_fake_mem_init
+ * Description : Initialize resources of the extended fake function.
+ * Input : struct tag_cqm_handle *cqm_handle: Parent CQM handle of the current PF
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2020/4/15
+ * Modification : Created function
+ */
+static s32 cqm_fake_mem_init(struct tag_cqm_handle *cqm_handle)
+{
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_handle *fake_cqm_handle = NULL;
+ s32 child_func_number;
+ u32 i;
+
+ if (cqm_handle->func_capability.fake_func_type !=
+ CQM_FAKE_FUNC_PARENT)
+ return CQM_SUCCESS;
+
+ child_func_number = cqm_get_child_func_number(cqm_handle);
+ if (child_func_number == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(child_func_number));
+ return CQM_FAIL;
+ }
+
+ for (i = 0; i < (u32)child_func_number; i++) {
+ fake_cqm_handle = cqm_handle->fake_cqm_handle[i];
+ snprintf(fake_cqm_handle->name, VRAM_NAME_MAX_LEN - 1,
+ "%s%s%02u", cqm_handle->name, VRAM_CQM_FAKE_MEM_BASE, i);
+
+ if (cqm_bat_init(fake_cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_bat_init));
+ goto err;
+ }
+
+ if (cqm_cla_init(fake_cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_cla_init));
+ goto err;
+ }
+
+ if (cqm_bitmap_init(fake_cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_bitmap_init));
+ goto err;
+ }
+
+ if (cqm_object_table_init(fake_cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_object_table_init));
+ goto err;
+ }
+ }
+
+ return CQM_SUCCESS;
+
+err:
+ cqm_fake_mem_uninit(cqm_handle);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_mem_init
+ * Description : Initialize CQM memory, including tables at different levels.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/7/6
+ * Modification : Created function
+ */
+s32 cqm_mem_init(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ snprintf(cqm_handle->name, VRAM_NAME_MAX_LEN - 1,
+ "%s%02u", VRAM_CQM_GLB_FUNC_BASE, hinic3_global_func_id(handle));
+
+ if (cqm_fake_init(cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_fake_init));
+ return CQM_FAIL;
+ }
+
+ if (cqm_fake_mem_init(cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_fake_mem_init));
+ goto err1;
+ }
+
+ if (cqm_bat_init(cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_bat_init));
+ goto err2;
+ }
+
+ if (cqm_cla_init(cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_init));
+ goto err3;
+ }
+
+ if (cqm_bitmap_init(cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_bitmap_init));
+ goto err4;
+ }
+
+ if (cqm_object_table_init(cqm_handle) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_object_table_init));
+ goto err5;
+ }
+
+ return CQM_SUCCESS;
+
+err5:
+ cqm_bitmap_uninit(cqm_handle);
+err4:
+ cqm_cla_uninit(cqm_handle, CQM_BAT_ENTRY_MAX);
+err3:
+ cqm_bat_uninit(cqm_handle);
+err2:
+ cqm_fake_mem_uninit(cqm_handle);
+err1:
+ cqm_fake_uninit(cqm_handle);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_mem_uninit
+ * Description : Deinitialize CQM memory, including tables at different levels.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/7/6
+ * Modification : Created function
+ */
+void cqm_mem_uninit(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+
+ cqm_object_table_uninit(cqm_handle);
+ cqm_bitmap_uninit(cqm_handle);
+ cqm_cla_uninit(cqm_handle, CQM_BAT_ENTRY_MAX);
+ cqm_bat_uninit(cqm_handle);
+ cqm_fake_mem_uninit(cqm_handle);
+ cqm_fake_uninit(cqm_handle);
+}
+
+/**
+ * Prototype : cqm_event_init
+ * Description : Initialize CQM event callback.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/7/6
+ * Modification : Created function
+ */
+s32 cqm_event_init(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ /* Registers the CEQ and AEQ callback functions. */
+ if (hinic3_ceq_register_cb(ex_handle, ex_handle, HINIC3_NON_L2NIC_SCQ,
+ cqm_scq_callback) != CHIPIF_SUCCESS) {
+ cqm_err(handle->dev_hdl, "Event: fail to register scq callback\n");
+ return CQM_FAIL;
+ }
+
+ if (hinic3_ceq_register_cb(ex_handle, ex_handle, HINIC3_NON_L2NIC_ECQ,
+ cqm_ecq_callback) != CHIPIF_SUCCESS) {
+ cqm_err(handle->dev_hdl, "Event: fail to register ecq callback\n");
+ goto err1;
+ }
+
+ if (hinic3_ceq_register_cb(ex_handle, ex_handle, HINIC3_NON_L2NIC_NO_CQ_EQ,
+ cqm_nocq_callback) != CHIPIF_SUCCESS) {
+ cqm_err(handle->dev_hdl, "Event: fail to register nocq callback\n");
+ goto err2;
+ }
+
+ if (hinic3_aeq_register_swe_cb(ex_handle, ex_handle, HINIC3_STATEFUL_EVENT,
+ cqm_aeq_callback) != CHIPIF_SUCCESS) {
+ cqm_err(handle->dev_hdl, "Event: fail to register aeq callback\n");
+ goto err3;
+ }
+
+ return CQM_SUCCESS;
+
+err3:
+ hinic3_ceq_unregister_cb(ex_handle, HINIC3_NON_L2NIC_NO_CQ_EQ);
+err2:
+ hinic3_ceq_unregister_cb(ex_handle, HINIC3_NON_L2NIC_ECQ);
+err1:
+ hinic3_ceq_unregister_cb(ex_handle, HINIC3_NON_L2NIC_SCQ);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_event_uninit
+ * Description : Deinitialize CQM event callback.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/7/6
+ * Modification : Created function
+ */
+void cqm_event_uninit(void *ex_handle)
+{
+ hinic3_aeq_unregister_swe_cb(ex_handle, HINIC3_STATEFUL_EVENT);
+ hinic3_ceq_unregister_cb(ex_handle, HINIC3_NON_L2NIC_NO_CQ_EQ);
+ hinic3_ceq_unregister_cb(ex_handle, HINIC3_NON_L2NIC_ECQ);
+ hinic3_ceq_unregister_cb(ex_handle, HINIC3_NON_L2NIC_SCQ);
+}
+
+/**
+ * Prototype : cqm_scq_callback
+ * Description : CQM module callback processing for the ceq,
+ * which processes NON_L2NIC_SCQ.
+ * Input : void *ex_handle
+ * u32 ceqe_data
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+void cqm_scq_callback(void *ex_handle, u32 ceqe_data)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_service_register_template *service_template = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct tag_cqm_queue *cqm_queue = NULL;
+ struct tag_cqm_object *obj = NULL;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: scq_callback_ex_handle is null\n", __func__);
+ return;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_scq_callback_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: scq_callback_cqm_handle is null\n", __func__);
+ return;
+ }
+
+ cqm_dbg("Event: %s, ceqe_data=0x%x\n", __func__, ceqe_data);
+ obj = cqm_object_get(ex_handle, CQM_OBJECT_NONRDMA_SCQ,
+ CQM_CQN_FROM_CEQE(ceqe_data), true);
+ if (unlikely(!obj)) {
+ pr_err("[CQM]%s: scq_callback_obj is null\n", __func__);
+ return;
+ }
+
+ if (unlikely(obj->service_type >= CQM_SERVICE_T_MAX)) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(obj->service_type));
+ cqm_object_put(obj);
+ return;
+ }
+
+ service = &cqm_handle->service[obj->service_type];
+ service_template = &service->service_template;
+ if (service_template->shared_cq_ceq_callback) {
+ cqm_queue = (struct tag_cqm_queue *)obj;
+ service_template->shared_cq_ceq_callback(service_template->service_handle,
+ CQM_CQN_FROM_CEQE(ceqe_data),
+ cqm_queue->priv);
+ } else {
+ cqm_err(handle->dev_hdl, CQM_PTR_NULL(shared_cq_ceq_callback));
+ }
+
+ cqm_object_put(obj);
+}
+
+/**
+ * Prototype : cqm_ecq_callback
+ * Description : CQM module callback processing for the ceq,
+ * which processes NON_L2NIC_ECQ.
+ * Input : void *ex_handle
+ * u32 ceqe_data
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+void cqm_ecq_callback(void *ex_handle, u32 ceqe_data)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_service_register_template *service_template = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct tag_cqm_qpc_mpt *qpc = NULL;
+ struct tag_cqm_object *obj = NULL;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ecq_callback_ex_handle is null\n", __func__);
+ return;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_ecq_callback_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: ecq_callback_cqm_handle is null\n", __func__);
+ return;
+ }
+
+ obj = cqm_object_get(ex_handle, CQM_OBJECT_SERVICE_CTX,
+ CQM_XID_FROM_CEQE(ceqe_data), true);
+ if (unlikely(!obj)) {
+ pr_err("[CQM]%s: ecq_callback_obj is null\n", __func__);
+ return;
+ }
+
+ if (unlikely(obj->service_type >= CQM_SERVICE_T_MAX)) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(obj->service_type));
+ cqm_object_put(obj);
+ return;
+ }
+
+ service = &cqm_handle->service[obj->service_type];
+ service_template = &service->service_template;
+ if (service_template->embedded_cq_ceq_callback) {
+ qpc = (struct tag_cqm_qpc_mpt *)obj;
+ service_template->embedded_cq_ceq_callback(service_template->service_handle,
+ CQM_XID_FROM_CEQE(ceqe_data),
+ qpc->priv);
+ } else {
+ cqm_err(handle->dev_hdl,
+ CQM_PTR_NULL(embedded_cq_ceq_callback));
+ }
+
+ cqm_object_put(obj);
+}
+
+/**
+ * Prototype : cqm_nocq_callback
+ * Description : CQM module callback processing for the ceq,
+ * which processes NON_L2NIC_NO_CQ_EQ.
+ * Input : void *ex_handle
+ * u32 ceqe_data
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+void cqm_nocq_callback(void *ex_handle, u32 ceqe_data)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_service_register_template *service_template = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct tag_cqm_qpc_mpt *qpc = NULL;
+ struct tag_cqm_object *obj = NULL;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: nocq_callback_ex_handle is null\n", __func__);
+ return;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_nocq_callback_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: nocq_callback_cqm_handle is null\n", __func__);
+ return;
+ }
+
+ obj = cqm_object_get(ex_handle, CQM_OBJECT_SERVICE_CTX,
+ CQM_XID_FROM_CEQE(ceqe_data), true);
+ if (unlikely(!obj)) {
+ pr_err("[CQM]%s: nocq_callback_obj is null\n", __func__);
+ return;
+ }
+
+ if (unlikely(obj->service_type >= CQM_SERVICE_T_MAX)) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(obj->service_type));
+ cqm_object_put(obj);
+ return;
+ }
+
+ service = &cqm_handle->service[obj->service_type];
+ service_template = &service->service_template;
+ if (service_template->no_cq_ceq_callback) {
+ qpc = (struct tag_cqm_qpc_mpt *)obj;
+ service_template->no_cq_ceq_callback(service_template->service_handle,
+ CQM_XID_FROM_CEQE(ceqe_data),
+ CQM_QID_FROM_CEQE(ceqe_data),
+ qpc->priv);
+ } else {
+ cqm_err(handle->dev_hdl, CQM_PTR_NULL(no_cq_ceq_callback));
+ }
+
+ cqm_object_put(obj);
+}
+
+static u32 cqm_aeq_event2type(u8 event)
+{
+ u32 service_type;
+
+ /* Distributes events to different service modules
+ * based on the event type.
+ */
+ if (event < CQM_AEQ_BASE_T_ROCE)
+ service_type = CQM_SERVICE_T_NIC;
+ else if (event < CQM_AEQ_BASE_T_FC)
+ service_type = CQM_SERVICE_T_ROCE;
+ else if (event < CQM_AEQ_BASE_T_IOE)
+ service_type = CQM_SERVICE_T_FC;
+ else if (event < CQM_AEQ_BASE_T_TOE)
+ service_type = CQM_SERVICE_T_IOE;
+ else if (event < CQM_AEQ_BASE_T_VBS)
+ service_type = CQM_SERVICE_T_TOE;
+ else if (event < CQM_AEQ_BASE_T_IPSEC)
+ service_type = CQM_SERVICE_T_VBS;
+ else if (event < CQM_AEQ_BASE_T_MAX)
+ service_type = CQM_SERVICE_T_IPSEC;
+ else
+ service_type = CQM_SERVICE_T_MAX;
+
+ return service_type;
+}
+
+/**
+ * Prototype : cqm_aeq_callback
+ * Description : CQM module callback processing for the aeq.
+ * Input : void *ex_handle
+ * u8 event
+ * u64 data
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/5/5
+ * Modification : Created function
+ */
+u8 cqm_aeq_callback(void *ex_handle, u8 event, u8 *data)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_service_register_template *service_template = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ u8 event_level = FAULT_LEVEL_MAX;
+ u32 service_type;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: aeq_callback_ex_handle is null\n", __func__);
+ return event_level;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_aeq_callback_cnt[event]);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: aeq_callback_cqm_handle is null\n", __func__);
+ return event_level;
+ }
+
+ /* Distributes events to different service modules
+ * based on the event type.
+ */
+ service_type = cqm_aeq_event2type(event);
+ if (service_type == CQM_SERVICE_T_MAX) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(event));
+ return event_level;
+ }
+
+ service = &cqm_handle->service[service_type];
+ service_template = &service->service_template;
+
+ if (!service_template->aeq_level_callback)
+ cqm_err(handle->dev_hdl,
+ "Event: service_type %u aeq_level_callback unregistered, event %u\n",
+ service_type, event);
+ else
+ event_level =
+ service_template->aeq_level_callback(service_template->service_handle,
+ event, data);
+
+ if (!service_template->aeq_callback)
+ cqm_err(handle->dev_hdl, "Event: service_type %u aeq_callback unregistered\n",
+ service_type);
+ else
+ service_template->aeq_callback(service_template->service_handle,
+ event, data);
+
+ return event_level;
+}
+
+/**
+ * Prototype : cqm_service_register
+ * Description : Callback template for the service driver
+ * to register with the CQM.
+ * Input : void *ex_handle
+ * struct tag_service_register_template *service_template
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/5
+ * Modification : Created function
+ */
+s32 cqm_service_register(void *ex_handle, struct tag_service_register_template *service_template)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!service_template)) {
+ pr_err("[CQM]%s: service_template is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ if (service_template->service_type >= CQM_SERVICE_T_MAX) {
+ cqm_err(handle->dev_hdl,
+ CQM_WRONG_VALUE(service_template->service_type));
+ return CQM_FAIL;
+ }
+ service = &cqm_handle->service[service_template->service_type];
+ if (!service->valid) {
+ cqm_err(handle->dev_hdl, "Service register: service_type %u is invalid\n",
+ service_template->service_type);
+ return CQM_FAIL;
+ }
+
+ if (service->has_register) {
+ cqm_err(handle->dev_hdl, "Service register: service_type %u has registered\n",
+ service_template->service_type);
+ return CQM_FAIL;
+ }
+
+ service->has_register = true;
+ memcpy((void *)(&service->service_template), (void *)service_template,
+ sizeof(struct tag_service_register_template));
+
+ return CQM_SUCCESS;
+}
+EXPORT_SYMBOL(cqm_service_register);
+
+/**
+ * Prototype : cqm_service_unregister
+ * Description : The service driver deregisters the callback function
+ * from the CQM.
+ * Input : void *ex_handle
+ * u32 service_type
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/5
+ * Modification : Created function
+ */
+void cqm_service_unregister(void *ex_handle, u32 service_type)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return;
+ }
+
+ if (service_type >= CQM_SERVICE_T_MAX) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return;
+ }
+
+ service = &cqm_handle->service[service_type];
+ if (!service->valid)
+ cqm_err(handle->dev_hdl, "Service unregister: service_type %u is disable\n",
+ service_type);
+
+ service->has_register = false;
+ memset(&service->service_template, 0, sizeof(struct tag_service_register_template));
+}
+EXPORT_SYMBOL(cqm_service_unregister);
+
+s32 cqm_fake_vf_num_set(void *ex_handle, u16 fake_vf_num_cfg)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct service_cap *svc_cap = NULL;
+
+ if (!ex_handle)
+ return CQM_FAIL;
+
+ svc_cap = &handle->cfg_mgmt->svc_cap;
+
+ if (fake_vf_num_cfg > svc_cap->fake_vf_num) {
+ cqm_err(handle->dev_hdl, "fake_vf_num_cfg is invlaid, fw fake_vf_num is %u\n",
+ svc_cap->fake_vf_num);
+ return CQM_FAIL;
+ }
+
+ /* fake_vf_num_cfg is valid when func type is CQM_FAKE_FUNC_PARENT */
+ svc_cap->fake_vf_num_cfg = fake_vf_num_cfg;
+
+ return CQM_SUCCESS;
+}
+EXPORT_SYMBOL(cqm_fake_vf_num_set);
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_main.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_main.h
new file mode 100644
index 0000000000000..4f87bd1d7164b
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_main.h
@@ -0,0 +1,380 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_MAIN_H
+#define CQM_MAIN_H
+
+#include <linux/pci.h>
+
+#include "hinic3_crm.h"
+#include "cqm_bloomfilter.h"
+#include "hinic3_hwif.h"
+#include "cqm_bat_cla.h"
+
+#define GET_MAX max
+#define GET_MIN min
+#define CQM_DW_SHIFT 2
+#define CQM_QW_SHIFT 3
+#define CQM_BYTE_BIT_SHIFT 3
+#define CQM_NUM_BIT_BYTE 8
+
+#define CHIPIF_SUCCESS 0
+#define CHIPIF_FAIL (-1)
+
+#define CQM_TIMER_ENABLE 1
+#define CQM_TIMER_DISABLE 0
+
+#define CQM_TIMER_NUM_MULTI 2
+
+/* The value must be the same as that of hinic3_service_type in hinic3_crm.h. */
+#define CQM_SERVICE_T_NIC SERVICE_T_NIC
+#define CQM_SERVICE_T_OVS SERVICE_T_OVS
+#define CQM_SERVICE_T_ROCE SERVICE_T_ROCE
+#define CQM_SERVICE_T_TOE SERVICE_T_TOE
+#define CQM_SERVICE_T_IOE SERVICE_T_IOE
+#define CQM_SERVICE_T_FC SERVICE_T_FC
+#define CQM_SERVICE_T_VBS SERVICE_T_VBS
+#define CQM_SERVICE_T_IPSEC SERVICE_T_IPSEC
+#define CQM_SERVICE_T_VIRTIO SERVICE_T_VIRTIO
+#define CQM_SERVICE_T_PPA SERVICE_T_PPA
+#define CQM_SERVICE_T_MAX SERVICE_T_MAX
+
+struct tag_cqm_service {
+ bool valid; /* Whether to enable this service on the function. */
+ bool has_register; /* Registered or Not */
+ u64 hardware_db_paddr;
+ void __iomem *hardware_db_vaddr;
+ u64 dwqe_paddr;
+ void __iomem *dwqe_vaddr;
+ u32 buf_order; /* The size of each buf node is 2^buf_order pages. */
+ struct tag_service_register_template service_template;
+};
+
+struct tag_cqm_fake_cfg {
+ u32 parent_func; /* The parent func_id of the fake vfs. */
+ u32 child_func_start; /* The start func_id of the child fake vfs. */
+ u32 child_func_number; /* The number of the child fake vfs. */
+};
+
+#define CQM_MAX_FACKVF_GROUP 4
+
+struct tag_cqm_func_capability {
+ /* BAT_PTR table(SMLC) */
+ bool ft_enable; /* BAT for flow table enable: support toe/ioe/fc service
+ */
+ bool rdma_enable; /* BAT for rdma enable: support RoCE */
+ /* VAT table(SMIR) */
+ bool ft_pf_enable; /* Same as ft_enable. BAT entry for toe/ioe/fc on pf
+ */
+ bool rdma_pf_enable; /* Same as rdma_enable. BAT entry for rdma on pf */
+
+ /* Dynamic or static memory allocation during the application of
+ * specified QPC/SCQC for each service.
+ */
+ bool qpc_alloc_static;
+ bool scqc_alloc_static;
+
+ u8 timer_enable; /* Whether the timer function is enabled */
+ u8 bloomfilter_enable; /* Whether the bloomgfilter function is enabled
+ */
+ u32 flow_table_based_conn_number; /* Maximum number of connections for
+ * toe/ioe/fc, whitch cannot excedd
+ * qpc_number
+ */
+ u32 flow_table_based_conn_cache_number; /* Maximum number of sticky
+ * caches
+ */
+ u32 bloomfilter_length; /* Size of the bloomfilter table, 64-byte
+ * aligned
+ */
+ u32 bloomfilter_addr; /* Start position of the bloomfilter table in the
+ * SMF main cache.
+ */
+ u32 qpc_reserved; /* Reserved bit in bitmap */
+ u32 qpc_reserved_back; /* Reserved back bit in bitmap */
+ u32 mpt_reserved; /* The ROCE/IWARP MPT also has a reserved bit. */
+
+ /* All basic_size must be 2^n-aligned. */
+ u32 hash_number; /* The number of hash bucket. The size of BAT table is
+ * aliaed with 64 bucket. At least 64 buckets is
+ * required.
+ */
+ u32 hash_basic_size; /* THe basic size of hash bucket is 64B, including
+ * 5 valid entry and one next entry.
+ */
+ u32 qpc_number;
+ u32 fake_vf_qpc_number;
+ u32 qpc_basic_size;
+
+ /* NUmber of PFs/VFs on the current host only for timer resource used */
+ u32 pf_num;
+ u32 pf_id_start;
+ u32 vf_num;
+ u32 vf_id_start;
+
+ u8 timer_pf_num;
+ u8 timer_pf_id_start;
+ u16 timer_vf_num;
+ u16 timer_vf_id_start;
+
+ u32 lb_mode;
+ /* Only lower 4bit is valid, indicating which SMFs are enabled.
+ * For example, 0101B indicates that SMF0 and SMF2 are enabled.
+ */
+ u32 smf_pg;
+
+ u32 fake_mode;
+ u32 fake_func_type; /* Whether the current function belongs to the fake
+ * group (parent or child)
+ */
+ u32 fake_cfg_number; /* Number of current configuration groups */
+ struct tag_cqm_fake_cfg fake_cfg[CQM_MAX_FACKVF_GROUP];
+
+ /* Note: for cqm specail test */
+ u32 pagesize_reorder;
+ bool xid_alloc_mode;
+ bool gpa_check_enable;
+ u32 scq_reserved;
+ u32 srq_reserved;
+
+ u32 mpt_number;
+ u32 mpt_basic_size;
+ u32 scqc_number;
+ u32 scqc_basic_size;
+ u32 srqc_number;
+ u32 srqc_basic_size;
+
+ u32 gid_number;
+ u32 gid_basic_size;
+ u32 lun_number;
+ u32 lun_basic_size;
+ u32 taskmap_number;
+ u32 taskmap_basic_size;
+ u32 l3i_number;
+ u32 l3i_basic_size;
+ u32 childc_number;
+ u32 childc_basic_size;
+ u32 child_qpc_id_start; /* FC service Child CTX is global addressing. */
+ u32 childc_number_all_function; /* The chip supports a maximum of 8096
+ * child CTXs.
+ */
+ u32 timer_number;
+ u32 timer_basic_size;
+ u32 xid2cid_number;
+ u32 xid2cid_basic_size;
+ u32 reorder_number;
+ u32 reorder_basic_size;
+};
+
+#define CQM_PF TYPE_PF
+#define CQM_VF TYPE_VF
+#define CQM_PPF TYPE_PPF
+#define CQM_UNKNOWN TYPE_UNKNOWN
+#define CQM_MAX_PF_NUM 32
+
+#define CQM_LB_MODE_NORMAL 0xff
+#define CQM_LB_MODE_0 0
+#define CQM_LB_MODE_1 1
+#define CQM_LB_MODE_2 2
+
+#define CQM_LB_SMF_MAX 4
+
+#define CQM_FPGA_MODE 0
+#define CQM_EMU_MODE 1
+
+#define CQM_FAKE_FUNC_NORMAL 0
+#define CQM_FAKE_FUNC_PARENT 1
+#define CQM_FAKE_FUNC_CHILD 2
+#define CQM_FAKE_FUNC_CHILD_CONFLICT 3 /* The detected function is the
+ * function that is faked.
+ */
+
+#define CQM_FAKE_FUNC_MAX 32
+
+#define CQM_SPU_HOST_ID 4
+
+#define CQM_QPC_ROCE_PER_DRCT 12
+#define CQM_QPC_ROCE_NORMAL 0
+#define CQM_QPC_ROCE_VBS_MODE 2
+
+struct tag_cqm_toe_private_capability {
+ /* TOE srq is different from other services
+ * and does not need to be managed by the CLA table.
+ */
+ u32 toe_srqc_number;
+ u32 toe_srqc_basic_size;
+ u32 toe_srqc_start_id;
+
+ struct tag_cqm_bitmap srqc_bitmap;
+};
+
+struct tag_cqm_secure_mem {
+ u16 func_id;
+ bool need_secure_mem;
+
+ u32 mode;
+ u32 gpa_len0;
+
+ void __iomem *va_base;
+ void __iomem *va_end;
+ u64 pa_base;
+ u32 page_num;
+
+ /* bitmap mgmt */
+ spinlock_t bitmap_lock;
+ unsigned long *bitmap;
+ u32 bits_nr;
+ u32 alloc_cnt;
+ u32 free_cnt;
+};
+
+struct tag_cqm_handle {
+ struct hinic3_hwdev *ex_handle;
+ struct pci_dev *dev;
+ struct hinic3_func_attr func_attribute; /* vf/pf attributes */
+ struct tag_cqm_func_capability func_capability; /* function capability set */
+ struct tag_cqm_service service[CQM_SERVICE_T_MAX]; /* Service-related structure */
+ struct tag_cqm_bat_table bat_table;
+ struct tag_cqm_bloomfilter_table bloomfilter_table;
+ /* fake-vf-related structure */
+ struct tag_cqm_handle *fake_cqm_handle[CQM_FAKE_FUNC_MAX];
+ struct tag_cqm_handle *parent_cqm_handle;
+
+ struct tag_cqm_toe_private_capability toe_own_capability; /* TOE service-related
+ * capability set
+ */
+ struct tag_cqm_secure_mem secure_mem;
+ struct list_head node;
+ char name[VRAM_NAME_APPLY_LEN];
+};
+
+#define CQM_CQN_FROM_CEQE(data) ((data) & 0xfffff)
+#define CQM_XID_FROM_CEQE(data) ((data) & 0xfffff)
+#define CQM_QID_FROM_CEQE(data) (((data) >> 20) & 0x7)
+#define CQM_TYPE_FROM_CEQE(data) (((data) >> 23) & 0x7)
+
+#define CQM_HASH_BUCKET_SIZE_64 64
+
+#define CQM_MAX_QPC_NUM 0x100000U
+#define CQM_MAX_SCQC_NUM 0x100000U
+#define CQM_MAX_SRQC_NUM 0x100000U
+#define CQM_MAX_CHILDC_NUM 0x100000U
+
+#define CQM_QPC_SIZE_256 256U
+#define CQM_QPC_SIZE_512 512U
+#define CQM_QPC_SIZE_1024 1024U
+
+#define CQM_SCQC_SIZE_32 32U
+#define CQM_SCQC_SIZE_64 64U
+#define CQM_SCQC_SIZE_128 128U
+
+#define CQM_SRQC_SIZE_32 32
+#define CQM_SRQC_SIZE_64 64
+#define CQM_SRQC_SIZE_128 128
+
+#define CQM_MPT_SIZE_64 64
+
+#define CQM_GID_SIZE_32 32
+
+#define CQM_LUN_SIZE_8 8
+
+#define CQM_L3I_SIZE_8 8
+
+#define CQM_TIMER_SIZE_32 32
+
+#define CQM_XID2CID_SIZE_8 8
+
+#define CQM_REORDER_SIZE_256 256
+
+#define CQM_CHILDC_SIZE_256 256U
+
+#define CQM_XID2CID_VBS_NUM (2 * 1024) /* 2K nvme Q */
+
+#define CQM_VBS_QPC_SIZE 512U
+
+#define CQM_XID2CID_VIRTIO_NUM (16 * 1024) /* 16K virt Q */
+
+#define CQM_GID_RDMA_NUM 128
+
+#define CQM_LUN_FC_NUM 64
+
+#define CQM_TASKMAP_FC_NUM 4
+
+#define CQM_L3I_COMM_NUM 64
+
+#define CQM_CHILDC_ROCE_NUM (8 * 1024)
+#define CQM_CHILDC_OVS_VBS_NUM (8 * 1024)
+
+#define CQM_TIMER_SCALE_NUM (2 * 1024)
+#define CQM_TIMER_ALIGN_WHEEL_NUM 8
+#define CQM_TIMER_ALIGN_SCALE_NUM \
+ (CQM_TIMER_SCALE_NUM * CQM_TIMER_ALIGN_WHEEL_NUM)
+
+#define CQM_QPC_OVS_RSVD (1024 * 1024)
+#define CQM_QPC_ROCE_RSVD 2
+#define CQM_QPC_ROCEAA_SWITCH_QP_NUM 4
+#define CQM_QPC_ROCEAA_RSVD \
+ (4 * 1024 + CQM_QPC_ROCEAA_SWITCH_QP_NUM) /* 4096 Normal QP +
+ * 4 Switch QP
+ */
+
+#define CQM_CQ_ROCEAA_RSVD 64
+#define CQM_SRQ_ROCEAA_RSVD 64
+#define CQM_QPC_ROCE_VBS_RSVD_BACK 204800 /* 200K */
+
+#define CQM_OVS_PAGESIZE_ORDER 9
+#define CQM_OVS_MAX_TIMER_FUNC 48
+
+#define CQM_PPA_PAGESIZE_ORDER 8
+
+#define CQM_FC_PAGESIZE_ORDER 0
+
+#define CQM_QHEAD_ALIGN_ORDER 6
+
+typedef void (*serv_cap_init_cb)(struct tag_cqm_handle *, void *);
+
+struct cqm_srv_cap_init {
+ u32 service_type;
+ serv_cap_init_cb serv_cap_proc;
+};
+
+/* Only for llt test */
+s32 cqm_capability_init(void *ex_handle);
+/* Can be defined as static */
+s32 cqm_mem_init(void *ex_handle);
+void cqm_mem_uninit(void *ex_handle);
+s32 cqm_event_init(void *ex_handle);
+void cqm_event_uninit(void *ex_handle);
+void cqm_scq_callback(void *ex_handle, u32 ceqe_data);
+void cqm_ecq_callback(void *ex_handle, u32 ceqe_data);
+void cqm_nocq_callback(void *ex_handle, u32 ceqe_data);
+u8 cqm_aeq_callback(void *ex_handle, u8 event, u8 *data);
+s32 cqm_get_fake_func_type(struct tag_cqm_handle *cqm_handle);
+s32 cqm_get_child_func_start(struct tag_cqm_handle *cqm_handle);
+s32 cqm_get_child_func_number(struct tag_cqm_handle *cqm_handle);
+
+s32 cqm_init(void *ex_handle);
+void cqm_uninit(void *ex_handle);
+s32 cqm_service_register(void *ex_handle, struct tag_service_register_template *service_template);
+void cqm_service_unregister(void *ex_handle, u32 service_type);
+
+s32 cqm_fake_vf_num_set(void *ex_handle, u16 fake_vf_num_cfg);
+#define CQM_LOG_ID 0
+
+#define CQM_PTR_NULL(x) "%s: " #x " is null\n", __func__
+#define CQM_MAP_FAIL(x) "%s: " #x " map fail\n", __func__
+#define CQM_FUNCTION_FAIL(x) "%s: " #x " return failure\n", __func__
+#define CQM_WRONG_VALUE(x) "%s: " #x " %u is wrong\n", __func__, (u32)(x)
+
+#define cqm_err(dev, format, ...) dev_err(dev, "[CQM]" format, ##__VA_ARGS__)
+#define cqm_warn(dev, format, ...) dev_warn(dev, "[CQM]" format, ##__VA_ARGS__)
+#define cqm_notice(dev, format, ...) \
+ dev_notice(dev, "[CQM]" format, ##__VA_ARGS__)
+#define cqm_info(dev, format, ...) dev_info(dev, "[CQM]" format, ##__VA_ARGS__)
+#ifdef __CQM_DEBUG__
+#define cqm_dbg(format, ...) pr_info("[CQM]" format, ##__VA_ARGS__)
+#else
+#define cqm_dbg(format, ...)
+#endif
+
+#endif /* CQM_MAIN_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_memsec.c b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_memsec.c
new file mode 100644
index 0000000000000..4888b0a14a2d7
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_memsec.c
@@ -0,0 +1,665 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include "ossl_knl.h"
+#include "hinic3_hw.h"
+#include "hinic3_mt.h"
+#include "hinic3_hwif.h"
+#include "hinic3_hw_cfg.h"
+
+#include "cqm_object.h"
+#include "cqm_bitmap_table.h"
+#include "cqm_bat_cla.h"
+#include "cqm_bloomfilter.h"
+#include "cqm_db.h"
+#include "cqm_main.h"
+#include "vmsec_mpu_common.h"
+#include "cqm_memsec.h"
+
+#define SECURE_VA_TO_IDX(va, base) (((va) - (base)) / PAGE_SIZE)
+#define PCI_PROC_NAME_LEN 32
+#define U8_BIT 8
+#define MEM_SEC_PROC_DIR "driver/memsec"
+#define BITS_TO_MB(bits) ((bits) * PAGE_SIZE / 1024 / 1024)
+#define MEM_SEC_UNNECESSARY 1
+#define MEMSEC_TMP_LEN 32
+#define STD_INPUT_ONE_PARA 1
+#define STD_INPUT_TWO_PARA 2
+#define MR_KEY_2_INDEX_SHIFT 8
+
+static int memsec_proc_show(struct seq_file *seq, void *offset);
+static int memsec_proc_open(struct inode *inode, struct file *file);
+static int memsec_proc_release(struct inode *inode, struct file *file);
+static void memsec_info_print(struct seq_file *seq, struct tag_cqm_secure_mem *secure_mem);
+static int hinic3_secure_mem_proc_ent_init(void *hwdev);
+static void hinic3_secure_mem_proc_ent_deinit(void);
+static int hinic3_secure_mem_proc_node_remove(void *hwdev);
+static int hinic3_secure_mem_proc_node_add(void *hwdev);
+static ssize_t memsec_proc_write(struct file *file, const char __user *data, size_t len,
+ loff_t *pff);
+
+static struct proc_dir_entry *g_hinic3_memsec_proc_ent; /* proc dir */
+static atomic_t g_memsec_proc_refcnt = ATOMIC_INIT(0);
+
+static const struct proc_ops memsec_proc_fops = {
+ .proc_open = memsec_proc_open,
+ .proc_read = seq_read,
+ .proc_write = memsec_proc_write,
+ .proc_release = memsec_proc_release,
+};
+
+bool cqm_need_secure_mem(void *hwdev)
+{
+ struct tag_cqm_secure_mem *info = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)hwdev;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ info = &cqm_handle->secure_mem;
+ return ((info->need_secure_mem) && hinic3_is_guest_vmsec_enable(hwdev));
+}
+EXPORT_SYMBOL(cqm_need_secure_mem);
+
+static int memsec_proc_open(struct inode *inode, struct file *file)
+{
+ struct hinic3_hwdev *handle = PDE_DATA(inode);
+ int ret;
+
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+
+ ret = single_open(file, memsec_proc_show, handle);
+ if (ret)
+ module_put(THIS_MODULE);
+
+ return ret;
+}
+
+static int memsec_proc_release(struct inode *inode, struct file *file)
+{
+ module_put(THIS_MODULE);
+ return single_release(inode, file);
+}
+
+static void memsec_info_print(struct seq_file *seq, struct tag_cqm_secure_mem *secure_mem)
+{
+ int i, j;
+
+ seq_printf(seq, "Secure MemPageSize: %lu\n", PAGE_SIZE);
+ seq_printf(seq, "Secure MemTotal: %u pages\n", secure_mem->bits_nr);
+ seq_printf(seq, "Secure MemTotal: %lu MB\n", BITS_TO_MB(secure_mem->bits_nr));
+ seq_printf(seq, "Secure MemUsed: %d pages\n",
+ bitmap_weight(secure_mem->bitmap, secure_mem->bits_nr));
+ seq_printf(seq, "Secure MemAvailable: %d pages\n",
+ secure_mem->bits_nr - bitmap_weight(secure_mem->bitmap, secure_mem->bits_nr));
+ seq_printf(seq, "Secure MemFirstAvailableIdx: %lu\n",
+ find_first_zero_bit(secure_mem->bitmap, secure_mem->bits_nr));
+ seq_printf(seq, "Secure MemVirtualAddrStart: 0x%p\n", secure_mem->va_base);
+ seq_printf(seq, "Secure MemVirtualAddrEnd: 0x%p\n", secure_mem->va_end);
+ seq_printf(seq, "Secure MemPhysicalAddrStart: 0x%llx\n", secure_mem->pa_base);
+ seq_printf(seq, "Secure MemPhysicalAddrEnd: 0x%llx\n",
+ secure_mem->pa_base + secure_mem->gpa_len0);
+ seq_printf(seq, "Secure MemAllocCnt: %d\n", secure_mem->alloc_cnt);
+ seq_printf(seq, "Secure MemFreeCnt: %d\n", secure_mem->free_cnt);
+ seq_printf(seq, "Secure MemProcRefCnt: %d\n", atomic_read(&g_memsec_proc_refcnt));
+ seq_puts(seq, "Secure MemBitmap:");
+
+ for (i = 0, j = 0; i < (secure_mem->bits_nr / U8_BIT); i++) {
+ if (i % U8_BIT == 0) {
+ seq_printf(seq, "\n [%05d-%05d]: ", j, j + (U8_BIT * U8_BIT) - 0x1);
+ j += U8_BIT * U8_BIT;
+ }
+ seq_printf(seq, "0x%x ", *(u8 *)((u8 *)secure_mem->bitmap + i));
+ }
+
+ seq_puts(seq, "\nSecure MemBitmap info end\n");
+}
+
+static struct tag_cqm_secure_mem *memsec_proc_get_secure_mem(struct hinic3_hwdev *handle)
+{
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_secure_mem *info = NULL;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (!cqm_handle) {
+ cqm_err(handle->dev_hdl, "[memsec]cqm not inited yet\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ info = &cqm_handle->secure_mem;
+ if (!info || !info->bitmap) {
+ cqm_err(handle->dev_hdl, "[memsec]secure mem not inited yet\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return info;
+}
+
+static int memsec_proc_show(struct seq_file *seq, void *offset)
+{
+ struct hinic3_hwdev *handle = seq->private;
+ struct tag_cqm_secure_mem *info = NULL;
+
+ info = memsec_proc_get_secure_mem(handle);
+ if (IS_ERR(info))
+ return -EINVAL;
+
+ memsec_info_print(seq, info);
+
+ return 0;
+}
+
+static int test_read_secure_mem(struct hinic3_hwdev *handle, char *data, size_t len)
+{
+ u64 mem_ptr;
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ struct tag_cqm_secure_mem *info = &cqm_handle->secure_mem;
+
+ if (sscanf(data, "r %llx", &mem_ptr) != STD_INPUT_ONE_PARA) {
+ cqm_err(handle->dev_hdl, "[memsec_dfx] read info format unknown!\n");
+ return -EINVAL;
+ }
+
+ if (mem_ptr < (u64)(info->va_base) || mem_ptr >= (u64)(info->va_end)) {
+ cqm_err(handle->dev_hdl, "[memsec_dfx] addr 0x%llx invalid!\n", mem_ptr);
+ return -EINVAL;
+ }
+
+ cqm_info(handle->dev_hdl, "[memsec_dfx] read addr 0x%llx val 0x%llx\n",
+ mem_ptr, *(u64 *)mem_ptr);
+ return 0;
+}
+
+static int test_write_secure_mem(struct hinic3_hwdev *handle, char *data, size_t len)
+{
+ u64 mem_ptr;
+ u64 val;
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ struct tag_cqm_secure_mem *info = &cqm_handle->secure_mem;
+
+ if (sscanf(data, "w %llx %llx", &mem_ptr, &val) != STD_INPUT_TWO_PARA) {
+ cqm_err(handle->dev_hdl, "[memsec_dfx] read info format unknown!\n");
+ return -EINVAL;
+ }
+
+ if (mem_ptr < (u64)(info->va_base) || mem_ptr >= (u64)(info->va_end)) {
+ cqm_err(handle->dev_hdl, "[memsec_dfx] addr 0x%llx invalid!\n", mem_ptr);
+ return -EINVAL;
+ }
+
+ *(u64 *)mem_ptr = val;
+
+ cqm_info(handle->dev_hdl, "[memsec_dfx] write addr 0x%llx val 0x%llx now val 0x%llx\n",
+ mem_ptr, val, *(u64 *)mem_ptr);
+ return 0;
+}
+
+static void test_query_usage(struct hinic3_hwdev *handle)
+{
+ cqm_info(handle->dev_hdl, "\t[memsec_dfx]Usage: q <query_type> <index>\n");
+ cqm_info(handle->dev_hdl, "\t[memsec_dfx]Check whether roce context is in secure memory\n");
+ cqm_info(handle->dev_hdl, "\t[memsec_dfx]Options:\n");
+ cqm_info(handle->dev_hdl, "\t[memsec_dfx]query_type: qpc, mpt, srqc, scqc\n");
+ cqm_info(handle->dev_hdl, "\t[memsec_dfx]index: valid index.e.g. 0x3\n");
+}
+
+static int test_query_parse_type(struct hinic3_hwdev *handle, char *data,
+ enum cqm_object_type *type, u32 *index)
+{
+ char query_type[MEMSEC_TMP_LEN] = {'\0'};
+
+ if (sscanf(data, "q %s %x", query_type, index) != STD_INPUT_TWO_PARA) {
+ cqm_err(handle->dev_hdl, "[memsec_dfx] parse query cmd fail!\n");
+ return -1;
+ }
+ query_type[MEMSEC_TMP_LEN - 1] = '\0';
+
+ if (*index <= 0) {
+ cqm_err(handle->dev_hdl, "[memsec_dfx] query index 0x%x is invalid\n", *index);
+ return -1;
+ }
+
+ if (strcmp(query_type, "qpc") == 0) {
+ *type = CQM_OBJECT_SERVICE_CTX;
+ } else if (strcmp(query_type, "mpt") == 0) {
+ *type = CQM_OBJECT_MPT;
+ *index = (*index >> MR_KEY_2_INDEX_SHIFT) & 0xFFFFFF;
+ } else if (strcmp(query_type, "srqc") == 0) {
+ *type = CQM_OBJECT_RDMA_SRQ;
+ } else if (strcmp(query_type, "scqc") == 0) {
+ *type = CQM_OBJECT_RDMA_SCQ;
+ } else {
+ cqm_err(handle->dev_hdl, "[memsec_dfx] query type is invalid\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int test_query_context(struct hinic3_hwdev *handle, char *data, size_t len)
+{
+ int ret;
+ u32 index = 0;
+ bool in_secmem = false;
+ struct tag_cqm_object *cqm_obj = NULL;
+ struct tag_cqm_qpc_mpt *qpc_mpt = NULL;
+ struct tag_cqm_queue *cqm_queue = NULL;
+ struct tag_cqm_secure_mem *info = NULL;
+ enum cqm_object_type query_type;
+
+ ret = test_query_parse_type(handle, data, &query_type, &index);
+ if (ret < 0) {
+ test_query_usage(handle);
+ return -EINVAL;
+ }
+
+ info = memsec_proc_get_secure_mem(handle);
+ if (IS_ERR(info))
+ return -EINVAL;
+
+ cqm_obj = cqm_object_get((void *)handle, query_type, index, false);
+ if (!cqm_obj) {
+ cqm_err(handle->dev_hdl, "[memsec_dfx] get cmq obj fail!\n");
+ return -EINVAL;
+ }
+
+ switch (query_type) {
+ case CQM_OBJECT_SERVICE_CTX:
+ case CQM_OBJECT_MPT:
+ qpc_mpt = (struct tag_cqm_qpc_mpt *)cqm_obj;
+ if (qpc_mpt->vaddr >= (u8 *)info->va_base &&
+ (qpc_mpt->vaddr + cqm_obj->object_size) < (u8 *)info->va_end)
+ in_secmem = true;
+ cqm_info(handle->dev_hdl,
+ "[memsec_dfx]Query %s:0x%x, va=%p %sin secure mem\n",
+ query_type == CQM_OBJECT_MPT ? "MPT, mpt_index" : "QPC, qpn",
+ index, qpc_mpt->vaddr, in_secmem ? "" : "not ");
+ break;
+ case CQM_OBJECT_RDMA_SRQ:
+ case CQM_OBJECT_RDMA_SCQ:
+ cqm_queue = (struct tag_cqm_queue *)cqm_obj;
+ if (cqm_queue->q_ctx_vaddr >= (u8 *)info->va_base &&
+ (cqm_queue->q_ctx_vaddr + cqm_obj->object_size) < (u8 *)info->va_end)
+ in_secmem = true;
+ cqm_info(handle->dev_hdl,
+ "[memsec_dfx]Query %s:0x%x, va=%p %sin secure mem\n",
+ query_type == CQM_OBJECT_RDMA_SRQ ? "SRQC, srqn " : "SCQC, scqn",
+ index, cqm_queue->q_ctx_vaddr, in_secmem ? "" : "not ");
+ break;
+ default:
+ cqm_err(handle->dev_hdl, "[memsec_dfx] not support query type!\n");
+ break;
+ }
+
+ cqm_object_put(cqm_obj);
+ return 0;
+}
+
+static ssize_t memsec_proc_write(struct file *file, const char __user *data,
+ size_t len, loff_t *off)
+{
+ int ret = -EINVAL;
+ struct hinic3_hwdev *handle = PDE_DATA(file->f_inode);
+ char tmp[MEMSEC_TMP_LEN] = {0};
+
+ if (!handle)
+ return -EIO;
+
+ if (len >= MEMSEC_TMP_LEN)
+ return -EFBIG;
+
+ if (copy_from_user(tmp, data, len))
+ return -EIO;
+
+ switch (tmp[0]) {
+ case 'r':
+ ret = test_read_secure_mem(handle, tmp, len);
+ break;
+ case 'w':
+ ret = test_write_secure_mem(handle, tmp, len);
+ break;
+ case 'q':
+ ret = test_query_context(handle, tmp, len);
+ break;
+ default:
+ cqm_err(handle->dev_hdl, "[memsec_dfx] not support cmd!\n");
+ }
+
+ return (ret == 0) ? len : ret;
+}
+
+static int hinic3_secure_mem_proc_ent_init(void *hwdev)
+{
+ struct hinic3_hwdev *dev = hwdev;
+
+ if (g_hinic3_memsec_proc_ent)
+ return 0;
+
+ g_hinic3_memsec_proc_ent = proc_mkdir(MEM_SEC_PROC_DIR, NULL);
+ if (!g_hinic3_memsec_proc_ent) {
+ /* try again */
+ remove_proc_entry(MEM_SEC_PROC_DIR, NULL);
+ g_hinic3_memsec_proc_ent = proc_mkdir(MEM_SEC_PROC_DIR, NULL);
+ if (!g_hinic3_memsec_proc_ent) {
+ cqm_err(dev->dev_hdl, "[memsec]create secure mem proc fail!\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void hinic3_secure_mem_proc_ent_deinit(void)
+{
+ if (g_hinic3_memsec_proc_ent && !atomic_read(&g_memsec_proc_refcnt)) {
+ remove_proc_entry(MEM_SEC_PROC_DIR, NULL);
+ g_hinic3_memsec_proc_ent = NULL;
+ }
+}
+
+static int hinic3_secure_mem_proc_node_remove(void *hwdev)
+{
+ struct hinic3_hwdev *dev = hwdev;
+ struct pci_dev *pdev = dev->pcidev_hdl;
+ char pci_name[PCI_PROC_NAME_LEN] = {0};
+
+ if (!g_hinic3_memsec_proc_ent) {
+ sdk_info(dev->dev_hdl, "[memsec]proc_ent_null!\n");
+ return 0;
+ }
+
+ atomic_dec(&g_memsec_proc_refcnt);
+
+ snprintf(pci_name, PCI_PROC_NAME_LEN - 1,
+ "%02x:%02x:%x", pdev->bus->number, pdev->slot->number,
+ PCI_FUNC(pdev->devfn));
+
+ remove_proc_entry(pci_name, g_hinic3_memsec_proc_ent);
+
+ return 0;
+}
+
+static int hinic3_secure_mem_proc_node_add(void *hwdev)
+{
+ struct hinic3_hwdev *dev = hwdev;
+ struct pci_dev *pdev = dev->pcidev_hdl;
+ struct proc_dir_entry *res = NULL;
+ char pci_name[PCI_PROC_NAME_LEN] = {0};
+
+ if (!g_hinic3_memsec_proc_ent) {
+ cqm_err(dev->dev_hdl, "[memsec]proc_ent_null!\n");
+ return -EINVAL;
+ }
+
+ atomic_inc(&g_memsec_proc_refcnt);
+
+ snprintf(pci_name, PCI_PROC_NAME_LEN - 1,
+ "%02x:%02x:%x", pdev->bus->number, pdev->slot->number,
+ PCI_FUNC(pdev->devfn));
+ /* 0400 Read by owner */
+ res = proc_create_data(pci_name, 0400, g_hinic3_memsec_proc_ent, &memsec_proc_fops,
+ hwdev);
+ if (!res) {
+ cqm_err(dev->dev_hdl, "[memsec]proc_create_data fail!\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void hinic3_memsec_proc_init(void *hwdev)
+{
+ struct hinic3_hwdev *dev = hwdev;
+ int ret;
+
+ ret = hinic3_secure_mem_proc_ent_init(hwdev);
+ if (ret != 0) {
+ cqm_err(dev->dev_hdl, "[memsec]proc ent init fail!\n");
+ return;
+ }
+
+ ret = hinic3_secure_mem_proc_node_add(hwdev);
+ if (ret != 0) {
+ cqm_err(dev->dev_hdl, "[memsec]proc node add fail!\n");
+ return;
+ }
+}
+
+void hinic3_memsec_proc_deinit(void *hwdev)
+{
+ struct hinic3_hwdev *dev = hwdev;
+ int ret;
+
+ if (!cqm_need_secure_mem(hwdev))
+ return;
+
+ ret = hinic3_secure_mem_proc_node_remove(hwdev);
+ if (ret != 0) {
+ cqm_err(dev->dev_hdl, "[memsec]proc node remove fail!\n");
+ return;
+ }
+
+ hinic3_secure_mem_proc_ent_deinit();
+}
+
+static int cqm_get_secure_mem_cfg(void *dev, struct tag_cqm_secure_mem *info)
+{
+ struct hinic3_hwdev *hwdev = (struct hinic3_hwdev *)dev;
+ struct vmsec_cfg_ctx_gpa_entry_cmd mem_info;
+ u16 out_size = sizeof(struct vmsec_cfg_ctx_gpa_entry_cmd);
+ int err;
+
+ if (!hwdev || !info)
+ return -EINVAL;
+
+ memset(&mem_info, 0, sizeof(mem_info));
+ mem_info.entry.func_id = info->func_id;
+
+ err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_VMSEC, VMSEC_MPU_CMD_CTX_GPA_SHOW,
+ &mem_info, sizeof(mem_info), &mem_info,
+ &out_size, 0, HINIC3_CHANNEL_COMM);
+ if (err || !out_size || mem_info.head.status) {
+ cqm_err(hwdev->dev_hdl, "failed to get memsec info, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, mem_info.head.status, out_size);
+ return -EINVAL;
+ }
+
+ info->gpa_len0 = mem_info.entry.gpa_len0;
+ info->mode = mem_info.entry.mode;
+ info->pa_base = (u64)((((u64)mem_info.entry.gpa_addr0_hi) << CQM_INT_ADDR_SHIFT) |
+ mem_info.entry.gpa_addr0_lo);
+
+ return 0;
+}
+
+static int cqm_secure_mem_param_check(void *ex_handle, struct tag_cqm_secure_mem *info)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (!info->pa_base || !info->gpa_len0)
+ goto no_need_secure_mem;
+
+ if (!IS_ALIGNED(info->pa_base, CQM_SECURE_MEM_ALIGNED_SIZE) ||
+ !IS_ALIGNED(info->gpa_len0, CQM_SECURE_MEM_ALIGNED_SIZE)) {
+ cqm_err(handle->dev_hdl, "func_id %u secure mem not 2M aligned\n",
+ info->func_id);
+ return -EINVAL;
+ }
+
+ if (info->mode == VM_GPA_INFO_MODE_NMIG)
+ goto no_need_secure_mem;
+
+ return 0;
+
+no_need_secure_mem:
+ cqm_info(handle->dev_hdl, "func_id %u no need secure mem gpa 0x%llx len0 0x%x mode 0x%x\n",
+ info->func_id, info->pa_base, info->gpa_len0, info->mode);
+ info->need_secure_mem = false;
+ return MEM_SEC_UNNECESSARY;
+}
+
+int cqm_secure_mem_init(void *ex_handle)
+{
+ int err;
+ struct tag_cqm_secure_mem *info = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (!handle)
+ return -EINVAL;
+
+ // only vf in vm need secure mem
+ if (!hinic3_is_guest_vmsec_enable(ex_handle)) {
+ cqm_info(handle->dev_hdl, "no need secure mem\n");
+ return 0;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ info = &cqm_handle->secure_mem;
+ info->func_id = hinic3_global_func_id(ex_handle);
+
+ // get gpa info from mpu
+ err = cqm_get_secure_mem_cfg(ex_handle, info);
+ if (err) {
+ cqm_err(handle->dev_hdl, "func_id %u get secure mem failed, ret %d\n",
+ info->func_id, err);
+ return err;
+ }
+
+ // remap gpa
+ err = cqm_secure_mem_param_check(ex_handle, info);
+ if (err) {
+ cqm_info(handle->dev_hdl, "func_id %u cqm_secure_mem_param_check failed\n",
+ info->func_id);
+ return (err == MEM_SEC_UNNECESSARY) ? 0 : err;
+ }
+
+ info->va_base = ioremap(info->pa_base, info->gpa_len0);
+ info->va_end = info->va_base + info->gpa_len0;
+ info->page_num = info->gpa_len0 / PAGE_SIZE;
+ info->need_secure_mem = true;
+ info->bits_nr = info->page_num;
+ info->bitmap = bitmap_zalloc(info->bits_nr, GFP_KERNEL);
+ if (!info->bitmap) {
+ cqm_err(handle->dev_hdl, "func_id %u bitmap_zalloc failed\n",
+ info->func_id);
+ iounmap(info->va_base);
+ return -ENOMEM;
+ }
+
+ hinic3_memsec_proc_init(ex_handle);
+ return err;
+}
+
+int cqm_secure_mem_deinit(void *ex_handle)
+{
+ struct tag_cqm_secure_mem *info = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+
+ if (!handle)
+ return -EINVAL;
+
+ // only vf in vm need secure mem
+ if (!cqm_need_secure_mem(ex_handle))
+ return 0;
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ info = &cqm_handle->secure_mem;
+
+ if (info && info->va_base)
+ iounmap(info->va_base);
+
+ if (info && info->bitmap)
+ kfree(info->bitmap);
+
+ hinic3_memsec_proc_deinit(ex_handle);
+ return 0;
+}
+
+void *cqm_get_secure_mem_pages(struct hinic3_hwdev *handle, u32 order, dma_addr_t *pa_base)
+{
+ struct tag_cqm_secure_mem *info = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ unsigned int nr;
+ unsigned long *bitmap = NULL;
+ unsigned long index;
+ unsigned long flags;
+
+ if (!handle || !(handle->cqm_hdl)) {
+ pr_err("[memsec]%s null pointer\n", __func__);
+ return NULL;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ info = &cqm_handle->secure_mem;
+ bitmap = info->bitmap;
+ nr = 1 << order;
+
+ if (!bitmap) {
+ cqm_err(handle->dev_hdl, "[memsec] %s bitmap null\n", __func__);
+ return NULL;
+ }
+
+ spin_lock_irqsave(&info->bitmap_lock, flags);
+
+ index = (order) ? bitmap_find_next_zero_area(bitmap, info->bits_nr, 0, nr, 0) :
+ find_first_zero_bit(bitmap, info->bits_nr);
+ if (index >= info->bits_nr) {
+ spin_unlock_irqrestore(&info->bitmap_lock, flags);
+ cqm_err(handle->dev_hdl,
+ "can not find continuous memory, size %d pages, weight %d\n",
+ nr, bitmap_weight(bitmap, info->bits_nr));
+ return NULL;
+ }
+
+ bitmap_set(bitmap, index, nr);
+ info->alloc_cnt++;
+ spin_unlock_irqrestore(&info->bitmap_lock, flags);
+
+ *pa_base = info->pa_base + index * PAGE_SIZE;
+ return (void *)(info->va_base + index * PAGE_SIZE);
+}
+
+void cqm_free_secure_mem_pages(struct hinic3_hwdev *handle, void *va, u32 order)
+{
+ struct tag_cqm_secure_mem *info = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ unsigned int nr;
+ unsigned long *bitmap = NULL;
+ unsigned long index;
+ unsigned long flags;
+
+ if (!handle || !(handle->cqm_hdl)) {
+ pr_err("%s null pointer\n", __func__);
+ return;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ info = &cqm_handle->secure_mem;
+ bitmap = info->bitmap;
+ nr = 1UL << order;
+
+ if (!bitmap) {
+ cqm_err(handle->dev_hdl, "%s bitmap null\n", __func__);
+ return;
+ }
+
+ if (va < info->va_base || va > (info->va_end - PAGE_SIZE) ||
+ !PAGE_ALIGNED((va - info->va_base)))
+ cqm_err(handle->dev_hdl, "%s va wrong value\n", __func__);
+
+ index = SECURE_VA_TO_IDX(va, info->va_base);
+ spin_lock_irqsave(&info->bitmap_lock, flags);
+ bitmap_clear(bitmap, index, nr);
+ info->free_cnt++;
+ spin_unlock_irqrestore(&info->bitmap_lock, flags);
+}
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_memsec.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_memsec.h
new file mode 100644
index 0000000000000..7d4a422689694
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_memsec.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. */
+#ifndef CQM_MEMSEC_H
+#define CQM_MEMSEC_H
+
+#include <linux/pci.h>
+#include "hinic3_hwdev.h"
+#include "hinic3_crm.h"
+#include "cqm_define.h"
+
+#define CQM_GET_MEMSEC_CTX_GPA 19
+#define CQM_INT_ADDR_SHIFT 32
+#define CQM_SECURE_MEM_ALIGNED_SIZE (2 * 1024 * 1024)
+
+bool cqm_need_secure_mem(void *hwdev);
+void *cqm_get_secure_mem_pages(struct hinic3_hwdev *handle, u32 order, dma_addr_t *pa_base);
+void cqm_free_secure_mem_pages(struct hinic3_hwdev *handle, void *va, u32 order);
+int cqm_secure_mem_init(void *ex_handle);
+int cqm_secure_mem_deinit(void *ex_handle);
+void hinic3_memsec_proc_init(void *hwdev);
+void hinic3_memsec_proc_deinit(void *hwdev);
+
+#endif /* CQM_MEMSEC_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object.c b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object.c
new file mode 100644
index 0000000000000..ea21ebf9b12ed
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object.c
@@ -0,0 +1,1664 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+
+#include "ossl_knl.h"
+#include "hinic3_crm.h"
+#include "hinic3_hw.h"
+#include "hinic3_mt.h"
+#include "hinic3_hwdev.h"
+
+#include "cqm_bitmap_table.h"
+#include "cqm_bat_cla.h"
+#include "cqm_object_intern.h"
+#include "cqm_main.h"
+#include "cqm_object.h"
+
+/**
+ * Prototype : cqm_object_qpc_mpt_create
+ * Description : create QPC/MPT
+ * Input : void *ex_handle
+ * u32 service_type
+ * enum cqm_object_type object_type: must be mpt or ctx.
+ * u32 object_size: unit is Byte
+ * void *object_priv: private structure of the service layer,
+ * it can be NULL.
+ * u32 index: apply for the reserved qpn based on this value;
+ * if automatic allocation is required,
+ * please fill CQM_INDEX_INVALID.
+ * Output : None
+ * Return Value : struct tag_cqm_qpc_mpt *
+ * 1.Date : 2016/2/16
+ * Modification : Created function
+ */
+struct tag_cqm_qpc_mpt *cqm_object_qpc_mpt_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 object_size, void *object_priv, u32 index,
+ bool low2bit_align_en)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_qpc_mpt_info *qpc_mpt_info = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ s32 ret = CQM_FAIL;
+ u32 relative_index;
+ u32 fake_func_id;
+ u32 index_num = index;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_qpc_mpt_create_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ if (service_type >= CQM_SERVICE_T_MAX || !cqm_handle->service[service_type].has_register) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return NULL;
+ }
+
+ if (object_type != CQM_OBJECT_SERVICE_CTX && object_type != CQM_OBJECT_MPT) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object_type));
+ return NULL;
+ }
+
+ /* fake vf adaption, switch to corresponding VF. */
+ if (cqm_handle->func_capability.fake_func_type == CQM_FAKE_FUNC_PARENT) {
+ fake_func_id = index_num / cqm_handle->func_capability.fake_vf_qpc_number;
+ relative_index = index_num % cqm_handle->func_capability.fake_vf_qpc_number;
+
+ if ((s32)fake_func_id >= cqm_get_child_func_number(cqm_handle)) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(fake_func_id));
+ return NULL;
+ }
+
+ index_num = relative_index;
+ cqm_handle = cqm_handle->fake_cqm_handle[fake_func_id];
+ }
+
+ qpc_mpt_info = kmalloc(sizeof(*qpc_mpt_info), GFP_ATOMIC | __GFP_ZERO);
+ if (!qpc_mpt_info)
+ return NULL;
+
+ qpc_mpt_info->common.object.service_type = service_type;
+ qpc_mpt_info->common.object.object_type = object_type;
+ qpc_mpt_info->common.object.object_size = object_size;
+ atomic_set(&qpc_mpt_info->common.object.refcount, 1);
+ init_completion(&qpc_mpt_info->common.object.free);
+ qpc_mpt_info->common.object.cqm_handle = cqm_handle;
+ qpc_mpt_info->common.xid = index_num;
+
+ qpc_mpt_info->common.priv = object_priv;
+
+ ret = cqm_qpc_mpt_create(&qpc_mpt_info->common.object, low2bit_align_en);
+ if (ret == CQM_SUCCESS)
+ return &qpc_mpt_info->common;
+
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_qpc_mpt_create));
+ kfree(qpc_mpt_info);
+ return NULL;
+}
+EXPORT_SYMBOL(cqm_object_qpc_mpt_create);
+
+/**
+ * Prototype : cqm_object_recv_queue_create
+ * Description : when srq is used, create rq.
+ * Input : void *ex_handle
+ * u32 service_type
+ * enum cqm_object_type object_type
+ * u32 init_rq_num
+ * u32 container_size
+ * u32 wqe_size
+ * void *object_priv
+ * Output : None
+ * Return Value : struct tag_cqm_queue *
+ * 1.Date : 2016/2/16
+ * Modification : Created function
+ */
+struct tag_cqm_queue *cqm_object_recv_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 init_rq_num, u32 container_size,
+ u32 wqe_size, void *object_priv)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_nonrdma_qinfo *rq_qinfo = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ s32 ret;
+ u32 i;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_rq_create_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ if (object_type != CQM_OBJECT_NONRDMA_EMBEDDED_RQ) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object_type));
+ return NULL;
+ }
+
+ if (service_type != CQM_SERVICE_T_TOE) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return NULL;
+ }
+
+ if (!cqm_handle->service[service_type].has_register) {
+ cqm_err(handle->dev_hdl, "Rq create: service_type %u has not registered\n",
+ service_type);
+ return NULL;
+ }
+
+ /* 1. create rq qinfo */
+ rq_qinfo = kmalloc(sizeof(*rq_qinfo), GFP_KERNEL | __GFP_ZERO);
+ if (!rq_qinfo)
+ return NULL;
+
+ /* 2. init rq qinfo */
+ rq_qinfo->container_size = container_size;
+ rq_qinfo->wqe_size = wqe_size;
+ rq_qinfo->wqe_per_buf = container_size / wqe_size - 1;
+
+ rq_qinfo->common.queue_link_mode = CQM_QUEUE_TOE_SRQ_LINK_MODE;
+ rq_qinfo->common.priv = object_priv;
+ rq_qinfo->common.object.cqm_handle = cqm_handle;
+ /* this object_size is used as container num */
+ rq_qinfo->common.object.object_size = init_rq_num;
+ rq_qinfo->common.object.service_type = service_type;
+ rq_qinfo->common.object.object_type = object_type;
+ atomic_set(&rq_qinfo->common.object.refcount, 1);
+ init_completion(&rq_qinfo->common.object.free);
+
+ /* 3. create queue header */
+ rq_qinfo->common.q_header_vaddr =
+ cqm_kmalloc_align(sizeof(struct tag_cqm_queue_header),
+ GFP_KERNEL | __GFP_ZERO, CQM_QHEAD_ALIGN_ORDER);
+ if (!rq_qinfo->common.q_header_vaddr)
+ goto err1;
+
+ rq_qinfo->common.q_header_paddr =
+ pci_map_single(cqm_handle->dev, rq_qinfo->common.q_header_vaddr,
+ sizeof(struct tag_cqm_queue_header), PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(cqm_handle->dev,
+ rq_qinfo->common.q_header_paddr) != 0) {
+ cqm_err(handle->dev_hdl, CQM_MAP_FAIL(q_header_vaddr));
+ goto err2;
+ }
+
+ /* 4. create rq */
+ for (i = 0; i < init_rq_num; i++) {
+ ret = cqm_container_create(&rq_qinfo->common.object, NULL,
+ true);
+ if (ret == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_container_create));
+ goto err3;
+ }
+ if (!rq_qinfo->common.head_container)
+ rq_qinfo->common.head_container =
+ rq_qinfo->common.tail_container;
+ }
+
+ return &rq_qinfo->common;
+
+err3:
+ cqm_container_free(rq_qinfo->common.head_container, NULL,
+ &rq_qinfo->common);
+err2:
+ cqm_kfree_align(rq_qinfo->common.q_header_vaddr);
+ rq_qinfo->common.q_header_vaddr = NULL;
+err1:
+ kfree(rq_qinfo);
+ return NULL;
+}
+EXPORT_SYMBOL(cqm_object_recv_queue_create);
+
+/**
+ * Prototype : cqm_object_share_recv_queue_add_container
+ * Description : allocate new container for srq
+ * Input : struct tag_cqm_queue *common
+ * Output : None
+ * Return Value : tail_container address
+ * 1.Date : 2016/2/14
+ * Modification : Created function
+ */
+s32 cqm_object_share_recv_queue_add_container(struct tag_cqm_queue *common)
+{
+ if (unlikely(!common)) {
+ pr_err("[CQM]%s: common is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ return cqm_container_create(&common->object, NULL, true);
+}
+EXPORT_SYMBOL(cqm_object_share_recv_queue_add_container);
+
+s32 cqm_object_srq_add_container_free(struct tag_cqm_queue *common, u8 **container_addr)
+{
+ if (unlikely(!common)) {
+ pr_err("[CQM]%s: common is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ return cqm_container_create(&common->object, container_addr, false);
+}
+EXPORT_SYMBOL(cqm_object_srq_add_container_free);
+
+static bool cqm_object_share_recv_queue_param_check(struct hinic3_hwdev *handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 container_size, u32 wqe_size)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+
+ /* service_type must be CQM_SERVICE_T_TOE */
+ if (service_type != CQM_SERVICE_T_TOE) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return false;
+ }
+
+ /* exception of service registration check */
+ if (!cqm_handle->service[service_type].has_register) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return false;
+ }
+
+ /* container size2^N aligning */
+ if (!cqm_check_align(container_size)) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(container_size));
+ return false;
+ }
+
+ /* external parameter check: object_type must be
+ * CQM_OBJECT_NONRDMA_SRQ
+ */
+ if (object_type != CQM_OBJECT_NONRDMA_SRQ) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object_type));
+ return false;
+ }
+
+ /* wqe_size, the divisor, cannot be 0 */
+ if (wqe_size == 0) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(wqe_size));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Prototype : cqm_object_share_recv_queue_create
+ * Description : create srq
+ * Input : void *ex_handle
+ * u32 service_type
+ * enum cqm_object_type object_type
+ * u32 container_number
+ * u32 container_size
+ * u32 wqe_size
+ * Output : None
+ * Return Value : struct tag_cqm_queue *
+ * 1.Date : 2016/2/1
+ * Modification : Created function
+ */
+struct tag_cqm_queue *cqm_object_share_recv_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 container_number, u32 container_size,
+ u32 wqe_size)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_nonrdma_qinfo *srq_qinfo = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ s32 ret;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_srq_create_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ if (!cqm_object_share_recv_queue_param_check(handle, service_type, object_type,
+ container_size, wqe_size))
+ return NULL;
+
+ /* 2. create and initialize srq info */
+ srq_qinfo = kmalloc(sizeof(*srq_qinfo), GFP_KERNEL | __GFP_ZERO);
+ if (!srq_qinfo)
+ return NULL;
+
+ srq_qinfo->common.object.cqm_handle = cqm_handle;
+ srq_qinfo->common.object.object_size = container_number;
+ srq_qinfo->common.object.object_type = object_type;
+ srq_qinfo->common.object.service_type = service_type;
+ atomic_set(&srq_qinfo->common.object.refcount, 1);
+ init_completion(&srq_qinfo->common.object.free);
+
+ srq_qinfo->common.queue_link_mode = CQM_QUEUE_TOE_SRQ_LINK_MODE;
+ srq_qinfo->common.priv = NULL;
+ srq_qinfo->wqe_per_buf = container_size / wqe_size - 1;
+ srq_qinfo->wqe_size = wqe_size;
+ srq_qinfo->container_size = container_size;
+ service = &cqm_handle->service[service_type];
+ srq_qinfo->q_ctx_size = service->service_template.srq_ctx_size;
+
+ /* 3. create srq and srq ctx */
+ ret = cqm_share_recv_queue_create(&srq_qinfo->common.object);
+ if (ret == CQM_SUCCESS)
+ return &srq_qinfo->common;
+
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_share_recv_queue_create));
+ kfree(srq_qinfo);
+ return NULL;
+}
+EXPORT_SYMBOL(cqm_object_share_recv_queue_create);
+
+/**
+ * Prototype : cqm_object_fc_rq_create
+ * Description : RQ creation temporarily provided for the FC service.
+ * Special requirement: The number of valid WQEs in the queue
+ * must meet the number of transferred WQEs. Linkwqe can only be
+ * filled at the end of the page. The actual valid number exceeds
+ * the requirement. In this case, the service needs to be
+ * informed of the additional number to be created.
+ * Input : void *ex_handle
+ * u32 service_type
+ * enum cqm_object_type object_type
+ * u32 wqe_number: Number of valid WQEs
+ * u32 wqe_size
+ * void *object_priv
+ * Output : None
+ * 1.Date : 2016/3/1
+ * Modification : Created function
+ */
+struct tag_cqm_queue *cqm_object_fc_srq_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 wqe_number, u32 wqe_size,
+ void *object_priv)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_nonrdma_qinfo *nonrdma_qinfo = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ u32 valid_wqe_per_buffer;
+ u32 wqe_sum; /* include linkwqe, normal wqe */
+ u32 buf_size;
+ u32 buf_num;
+ s32 ret;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_fc_srq_create_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ /* service_type must be fc */
+ if (service_type != CQM_SERVICE_T_FC) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return NULL;
+ }
+
+ /* exception of service unregistered check */
+ if (!cqm_handle->service[service_type].has_register) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return NULL;
+ }
+
+ /* wqe_size cannot exceed PAGE_SIZE and must be 2^n aligned. */
+ if (wqe_size >= PAGE_SIZE || (!cqm_check_align(wqe_size))) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(wqe_size));
+ return NULL;
+ }
+
+ /* FC RQ is SRQ. (Different from the SRQ concept of TOE, FC indicates
+ * that packets received by all flows are placed on the same RQ.
+ * The SRQ of TOE is similar to the RQ resource pool.)
+ */
+ if (object_type != CQM_OBJECT_NONRDMA_SRQ) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object_type));
+ return NULL;
+ }
+
+ service = &cqm_handle->service[service_type];
+ buf_size = (u32)(PAGE_SIZE << (service->buf_order));
+ /* subtract 1 link wqe */
+ valid_wqe_per_buffer = buf_size / wqe_size - 1;
+ buf_num = wqe_number / valid_wqe_per_buffer;
+ if (wqe_number % valid_wqe_per_buffer != 0)
+ buf_num++;
+
+ /* calculate the total number of WQEs */
+ wqe_sum = buf_num * (valid_wqe_per_buffer + 1);
+ nonrdma_qinfo = kmalloc(sizeof(*nonrdma_qinfo), GFP_KERNEL | __GFP_ZERO);
+ if (!nonrdma_qinfo)
+ return NULL;
+
+ /* initialize object member */
+ nonrdma_qinfo->common.object.service_type = service_type;
+ nonrdma_qinfo->common.object.object_type = object_type;
+ /* total number of WQEs */
+ nonrdma_qinfo->common.object.object_size = wqe_sum;
+ atomic_set(&nonrdma_qinfo->common.object.refcount, 1);
+ init_completion(&nonrdma_qinfo->common.object.free);
+ nonrdma_qinfo->common.object.cqm_handle = cqm_handle;
+
+ /* Initialize the doorbell used by the current queue.
+ * The default doorbell is the hardware doorbell.
+ */
+ nonrdma_qinfo->common.current_q_doorbell = CQM_HARDWARE_DOORBELL;
+ /* Currently, the connection mode is fixed. In the future,
+ * the service needs to transfer the connection mode.
+ */
+ nonrdma_qinfo->common.queue_link_mode = CQM_QUEUE_RING_MODE;
+
+ /* initialize public members */
+ nonrdma_qinfo->common.priv = object_priv;
+ nonrdma_qinfo->common.valid_wqe_num = wqe_sum - buf_num;
+
+ /* initialize internal private members */
+ nonrdma_qinfo->wqe_size = wqe_size;
+ /* RQ (also called SRQ of FC) created by FC services,
+ * CTX needs to be created.
+ */
+ nonrdma_qinfo->q_ctx_size = service->service_template.srq_ctx_size;
+
+ ret = cqm_nonrdma_queue_create(&nonrdma_qinfo->common.object);
+ if (ret == CQM_SUCCESS)
+ return &nonrdma_qinfo->common;
+
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_fc_queue_create));
+ kfree(nonrdma_qinfo);
+ return NULL;
+}
+EXPORT_SYMBOL(cqm_object_fc_srq_create);
+
+static bool cqm_object_nonrdma_queue_param_check(struct hinic3_hwdev *handle, u32 service_type,
+ enum cqm_object_type object_type, u32 wqe_size)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+
+ /* exception of service registrion check */
+ if (!cqm_handle->service[service_type].has_register) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return false;
+ }
+ /* wqe_size can't be more than PAGE_SIZE, can't be zero, must be power
+ * of 2 the function of cqm_check_align is to check above
+ */
+ if (wqe_size >= PAGE_SIZE || (!cqm_check_align(wqe_size))) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(wqe_size));
+ return false;
+ }
+
+ /* nonrdma supports: RQ, SQ, SRQ, CQ, SCQ */
+ if (object_type < CQM_OBJECT_NONRDMA_EMBEDDED_RQ ||
+ object_type > CQM_OBJECT_NONRDMA_SCQ) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object_type));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Prototype : cqm_object_nonrdma_queue_create
+ * Description : create nonrdma queue
+ * Input : void *ex_handle
+ * u32 service_type
+ * enum cqm_object_type object_type: can be embedded RQ/SQ/CQ and
+ * SRQ/SCQ.
+ * u32 wqe_number: include link wqe
+ * u32 wqe_size: fixed length, must be power of 2
+ * void *object_priv: private structure of the service layer,
+ * it can be NULL.
+ * Output : None
+ * Return Value : struct tag_cqm_queue *
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+struct tag_cqm_queue *cqm_object_nonrdma_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 wqe_number, u32 wqe_size,
+ void *object_priv)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_nonrdma_qinfo *nonrdma_qinfo = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ s32 ret;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_nonrdma_queue_create_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ if (!cqm_object_nonrdma_queue_param_check(handle, service_type, object_type, wqe_size))
+ return NULL;
+
+ nonrdma_qinfo = kmalloc(sizeof(*nonrdma_qinfo), GFP_KERNEL | __GFP_ZERO);
+ if (!nonrdma_qinfo)
+ return NULL;
+
+ nonrdma_qinfo->common.object.service_type = service_type;
+ nonrdma_qinfo->common.object.object_type = object_type;
+ nonrdma_qinfo->common.object.object_size = wqe_number;
+ atomic_set(&nonrdma_qinfo->common.object.refcount, 1);
+ init_completion(&nonrdma_qinfo->common.object.free);
+ nonrdma_qinfo->common.object.cqm_handle = cqm_handle;
+
+ /* Initialize the doorbell used by the current queue.
+ * The default value is hardware doorbell
+ */
+ nonrdma_qinfo->common.current_q_doorbell = CQM_HARDWARE_DOORBELL;
+ /* Currently, the link mode is hardcoded and needs to be transferred by
+ * the service side.
+ */
+ nonrdma_qinfo->common.queue_link_mode = CQM_QUEUE_RING_MODE;
+
+ nonrdma_qinfo->common.priv = object_priv;
+
+ /* Initialize internal private members */
+ nonrdma_qinfo->wqe_size = wqe_size;
+ service = &cqm_handle->service[service_type];
+ switch (object_type) {
+ case CQM_OBJECT_NONRDMA_SCQ:
+ nonrdma_qinfo->q_ctx_size = service->service_template.scq_ctx_size;
+ break;
+ case CQM_OBJECT_NONRDMA_SRQ:
+ /* Currently, the SRQ of the service is created through a
+ * dedicated interface.
+ */
+ nonrdma_qinfo->q_ctx_size = service->service_template.srq_ctx_size;
+ break;
+ default:
+ break;
+ }
+
+ ret = cqm_nonrdma_queue_create(&nonrdma_qinfo->common.object);
+ if (ret == CQM_SUCCESS)
+ return &nonrdma_qinfo->common;
+
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_nonrdma_queue_create));
+ kfree(nonrdma_qinfo);
+ return NULL;
+}
+EXPORT_SYMBOL(cqm_object_nonrdma_queue_create);
+
+static bool cqm_object_rdma_queue_param_check(struct hinic3_hwdev *handle, u32 service_type,
+ enum cqm_object_type object_type)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+
+ /* service_type must be CQM_SERVICE_T_ROCE */
+ if (service_type != CQM_SERVICE_T_ROCE) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return false;
+ }
+ /* exception of service registrion check */
+ if (!cqm_handle->service[service_type].has_register) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return false;
+ }
+
+ /* rdma supports: QP, SRQ, SCQ */
+ if (object_type > CQM_OBJECT_RDMA_SCQ || object_type < CQM_OBJECT_RDMA_QP) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object_type));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Prototype : cqm_object_rdma_queue_create
+ * Description : create rdma queue
+ * Input : void *ex_handle
+ * u32 service_type
+ * enum cqm_object_type object_type: can be QP and SRQ/SCQ.
+ * u32 object_size
+ * void *object_priv: private structure of the service layer,
+ * it can be NULL.
+ * bool room_header_alloc: Whether to apply for queue room and
+ * header space
+ * u32 xid
+ * Output : None
+ * Return Value : struct tag_cqm_queue *
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+struct tag_cqm_queue *cqm_object_rdma_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 object_size, void *object_priv,
+ bool room_header_alloc, u32 xid)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_rdma_qinfo *rdma_qinfo = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ s32 ret;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_rdma_queue_create_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ if (!cqm_object_rdma_queue_param_check(handle, service_type, object_type))
+ return NULL;
+
+ rdma_qinfo = kmalloc(sizeof(*rdma_qinfo), GFP_KERNEL | __GFP_ZERO);
+ if (!rdma_qinfo)
+ return NULL;
+
+ rdma_qinfo->common.object.service_type = service_type;
+ rdma_qinfo->common.object.object_type = object_type;
+ rdma_qinfo->common.object.object_size = object_size;
+ atomic_set(&rdma_qinfo->common.object.refcount, 1);
+ init_completion(&rdma_qinfo->common.object.free);
+ rdma_qinfo->common.object.cqm_handle = cqm_handle;
+ rdma_qinfo->common.queue_link_mode = CQM_QUEUE_RDMA_QUEUE_MODE;
+ rdma_qinfo->common.priv = object_priv;
+ rdma_qinfo->common.current_q_room = CQM_RDMA_Q_ROOM_1;
+ rdma_qinfo->room_header_alloc = room_header_alloc;
+ rdma_qinfo->common.index = xid;
+
+ /* Initializes the doorbell used by the current queue.
+ * The default value is hardware doorbell
+ */
+ rdma_qinfo->common.current_q_doorbell = CQM_HARDWARE_DOORBELL;
+
+ service = &cqm_handle->service[service_type];
+ switch (object_type) {
+ case CQM_OBJECT_RDMA_SCQ:
+ rdma_qinfo->q_ctx_size = service->service_template.scq_ctx_size;
+ break;
+ case CQM_OBJECT_RDMA_SRQ:
+ rdma_qinfo->q_ctx_size = service->service_template.srq_ctx_size;
+ break;
+ default:
+ break;
+ }
+
+ ret = cqm_rdma_queue_create(&rdma_qinfo->common.object);
+ if (ret == CQM_SUCCESS)
+ return &rdma_qinfo->common;
+
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_rdma_queue_create));
+ kfree(rdma_qinfo);
+ return NULL;
+}
+EXPORT_SYMBOL(cqm_object_rdma_queue_create);
+
+/**
+ * Prototype : cqm_object_rdma_table_get
+ * Description : create mtt and rdmarc of the rdma service
+ * Input : void *ex_handle
+ * u32 service_type
+ * enum cqm_object_type object_type
+ * u32 index_base: start of index
+ * u32 index_number
+ * Output : None
+ * Return Value : struct tag_cqm_mtt_rdmarc *
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+struct tag_cqm_mtt_rdmarc *cqm_object_rdma_table_get(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 index_base, u32 index_number)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_rdma_table *rdma_table = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ s32 ret;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_rdma_table_create_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ /* service_type must be CQM_SERVICE_T_ROCE */
+ if (service_type != CQM_SERVICE_T_ROCE) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return NULL;
+ }
+
+ /* exception of service registrion check */
+ if (!cqm_handle->service[service_type].has_register) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(service_type));
+ return NULL;
+ }
+
+ if (object_type != CQM_OBJECT_MTT &&
+ object_type != CQM_OBJECT_RDMARC) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object_type));
+ return NULL;
+ }
+
+ rdma_table = kmalloc(sizeof(*rdma_table), GFP_KERNEL | __GFP_ZERO);
+ if (!rdma_table)
+ return NULL;
+
+ rdma_table->common.object.service_type = service_type;
+ rdma_table->common.object.object_type = object_type;
+ rdma_table->common.object.object_size = (u32)(index_number *
+ sizeof(dma_addr_t));
+ atomic_set(&rdma_table->common.object.refcount, 1);
+ init_completion(&rdma_table->common.object.free);
+ rdma_table->common.object.cqm_handle = cqm_handle;
+ rdma_table->common.index_base = index_base;
+ rdma_table->common.index_number = index_number;
+
+ ret = cqm_rdma_table_create(&rdma_table->common.object);
+ if (ret == CQM_SUCCESS)
+ return &rdma_table->common;
+
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_rdma_table_create));
+ kfree(rdma_table);
+ return NULL;
+}
+EXPORT_SYMBOL(cqm_object_rdma_table_get);
+
+static s32 cqm_qpc_mpt_delete_ret(struct tag_cqm_object *object)
+{
+ u32 object_type;
+
+ object_type = object->object_type;
+ switch (object_type) {
+ case CQM_OBJECT_SERVICE_CTX:
+ case CQM_OBJECT_MPT:
+ cqm_qpc_mpt_delete(object);
+ return CQM_SUCCESS;
+ default:
+ return CQM_FAIL;
+ }
+}
+
+static s32 cqm_nonrdma_queue_delete_ret(struct tag_cqm_object *object)
+{
+ u32 object_type;
+
+ object_type = object->object_type;
+ switch (object_type) {
+ case CQM_OBJECT_NONRDMA_EMBEDDED_RQ:
+ case CQM_OBJECT_NONRDMA_EMBEDDED_SQ:
+ case CQM_OBJECT_NONRDMA_EMBEDDED_CQ:
+ case CQM_OBJECT_NONRDMA_SCQ:
+ cqm_nonrdma_queue_delete(object);
+ return CQM_SUCCESS;
+ case CQM_OBJECT_NONRDMA_SRQ:
+ if (object->service_type == CQM_SERVICE_T_TOE)
+ cqm_share_recv_queue_delete(object);
+ else
+ cqm_nonrdma_queue_delete(object);
+
+ return CQM_SUCCESS;
+ default:
+ return CQM_FAIL;
+ }
+}
+
+static s32 cqm_rdma_queue_delete_ret(struct tag_cqm_object *object)
+{
+ u32 object_type;
+
+ object_type = object->object_type;
+ switch (object_type) {
+ case CQM_OBJECT_RDMA_QP:
+ case CQM_OBJECT_RDMA_SRQ:
+ case CQM_OBJECT_RDMA_SCQ:
+ cqm_rdma_queue_delete(object);
+ return CQM_SUCCESS;
+ default:
+ return CQM_FAIL;
+ }
+}
+
+static s32 cqm_rdma_table_delete_ret(struct tag_cqm_object *object)
+{
+ u32 object_type;
+
+ object_type = object->object_type;
+ switch (object_type) {
+ case CQM_OBJECT_MTT:
+ case CQM_OBJECT_RDMARC:
+ cqm_rdma_table_delete(object);
+ return CQM_SUCCESS;
+ default:
+ return CQM_FAIL;
+ }
+}
+
+/**
+ * Prototype : cqm_object_delete
+ * Description : Deletes a created object. This function will be sleep and wait
+ * for all operations on this object to be performed.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_object_delete(struct tag_cqm_object *object)
+{
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct hinic3_hwdev *handle = NULL;
+
+ if (unlikely(!object)) {
+ pr_err("[CQM]%s: object is null\n", __func__);
+ return;
+ }
+ if (!object->cqm_handle) {
+ pr_err("[CQM]object del: cqm_handle is null, service type %u, refcount %d\n",
+ object->service_type, (int)object->refcount.counter);
+ kfree(object);
+ return;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+
+ if (!cqm_handle->ex_handle) {
+ pr_err("[CQM]object del: ex_handle is null, service type %u, refcount %d\n",
+ object->service_type, (int)object->refcount.counter);
+ kfree(object);
+ return;
+ }
+
+ handle = cqm_handle->ex_handle;
+
+ if (object->service_type >= CQM_SERVICE_T_MAX) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object->service_type));
+ kfree(object);
+ return;
+ }
+
+ if (cqm_qpc_mpt_delete_ret(object) == CQM_SUCCESS) {
+ kfree(object);
+ return;
+ }
+
+ if (cqm_nonrdma_queue_delete_ret(object) == CQM_SUCCESS) {
+ kfree(object);
+ return;
+ }
+
+ if (cqm_rdma_queue_delete_ret(object) == CQM_SUCCESS) {
+ kfree(object);
+ return;
+ }
+
+ if (cqm_rdma_table_delete_ret(object) == CQM_SUCCESS) {
+ kfree(object);
+ return;
+ }
+
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object->object_type));
+ kfree(object);
+}
+EXPORT_SYMBOL(cqm_object_delete);
+
+/**
+ * Prototype : cqm_object_offset_addr
+ * Description : Only the rdma table can be searched to obtain the PA and VA
+ * at the specified offset of the object buffer.
+ * Input : struct tag_cqm_object *object
+ * u32 offset: For a rdma table, the offset is the absolute index
+ * number.
+ * dma_addr_t *paddr: PA(physical address)
+ * Output : None
+ * Return Value : u8 *
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+u8 *cqm_object_offset_addr(struct tag_cqm_object *object, u32 offset, dma_addr_t *paddr)
+{
+ u32 object_type = object->object_type;
+
+ /* The data flow path takes performance into consideration and
+ * does not check input parameters.
+ */
+ switch (object_type) {
+ case CQM_OBJECT_MTT:
+ case CQM_OBJECT_RDMARC:
+ return cqm_rdma_table_offset_addr(object, offset, paddr);
+ default:
+ break;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(cqm_object_offset_addr);
+
+/**
+ * Prototype : cqm_object_get
+ * Description : Obtain an object based on the index.
+ * Input : void *ex_handle
+ * enum cqm_object_type object_type
+ * u32 index: support qpn,mptn,scqn,srqn (n->number)
+ * bool bh
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+struct tag_cqm_object *cqm_object_get(void *ex_handle, enum cqm_object_type object_type,
+ u32 index, bool bh)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct tag_cqm_object_table *object_table = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_object *object = NULL;
+
+ /* The data flow path takes performance into consideration and
+ * does not check input parameters.
+ */
+ switch (object_type) {
+ case CQM_OBJECT_SERVICE_CTX:
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_QPC);
+ break;
+ case CQM_OBJECT_MPT:
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_MPT);
+ break;
+ case CQM_OBJECT_RDMA_SRQ:
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_SRQC);
+ break;
+ case CQM_OBJECT_RDMA_SCQ:
+ case CQM_OBJECT_NONRDMA_SCQ:
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_SCQC);
+ break;
+ default:
+ return NULL;
+ }
+
+ if (!cla_table) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_table_get));
+ return NULL;
+ }
+
+ object_table = &cla_table->obj_table;
+ object = cqm_object_table_get(cqm_handle, object_table, index, bh);
+ return object;
+}
+EXPORT_SYMBOL(cqm_object_get);
+
+/**
+ * Prototype : cqm_object_put
+ * Description : This function must be called after the cqm_object_get
+ * function. Otherwise, the object cannot be released.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_object_put(struct tag_cqm_object *object)
+{
+ /* The data flow path takes performance into consideration and
+ * does not check input parameters.
+ */
+ if (atomic_dec_and_test(&object->refcount) != 0)
+ complete(&object->free);
+}
+EXPORT_SYMBOL(cqm_object_put);
+
+/**
+ * Prototype : cqm_object_funcid
+ * Description : Obtain the ID of the function to which the object belongs.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : If successful, the ID of the function will be returned.
+ * If fail CQM_FAIL(-1) will be returned.
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_object_funcid(struct tag_cqm_object *object)
+{
+ struct tag_cqm_handle *cqm_handle = NULL;
+
+ if (unlikely(!object)) {
+ pr_err("[CQM]%s: object is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!object->cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+
+ return cqm_handle->func_attribute.func_global_idx;
+}
+EXPORT_SYMBOL(cqm_object_funcid);
+
+/**
+ * Prototype : cqm_object_resize_alloc_new
+ * Description : Currently this function is only used for RoCE.
+ * The CQ buffer is ajusted, but the cqn and cqc remain
+ * unchanged. This function allocates new buffer, but do not
+ * release old buffer. The valid buffer is still old buffer.
+ * Input : struct tag_cqm_object *object
+ * u32 object_size
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_object_resize_alloc_new(struct tag_cqm_object *object, u32 object_size)
+{
+ struct tag_cqm_rdma_qinfo *qinfo = (struct tag_cqm_rdma_qinfo *)(void *)object;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_service *service = NULL;
+ struct tag_cqm_buf *q_room_buf = NULL;
+ struct hinic3_hwdev *handle = NULL;
+ u32 order, buf_size;
+
+ if (unlikely(!object)) {
+ pr_err("[CQM]%s: object is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ handle = cqm_handle->ex_handle;
+
+ /* This interface is used only for the CQ of RoCE service. */
+ if (object->service_type == CQM_SERVICE_T_ROCE &&
+ object->object_type == CQM_OBJECT_RDMA_SCQ) {
+ service = cqm_handle->service + object->service_type;
+ order = service->buf_order;
+ buf_size = (u32)(PAGE_SIZE << order);
+
+ if (qinfo->common.current_q_room == CQM_RDMA_Q_ROOM_1)
+ q_room_buf = &qinfo->common.q_room_buf_2;
+ else
+ q_room_buf = &qinfo->common.q_room_buf_1;
+
+ if (qinfo->room_header_alloc) {
+ q_room_buf->buf_number = ALIGN(object_size, buf_size) /
+ buf_size;
+ q_room_buf->page_number = q_room_buf->buf_number <<
+ order;
+ q_room_buf->buf_size = buf_size;
+ if (cqm_buf_alloc(cqm_handle, q_room_buf, true) ==
+ CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_buf_alloc));
+ return CQM_FAIL;
+ }
+
+ qinfo->new_object_size = object_size;
+ return CQM_SUCCESS;
+ }
+
+ cqm_err(handle->dev_hdl,
+ CQM_WRONG_VALUE(qinfo->room_header_alloc));
+ return CQM_FAIL;
+ }
+
+ cqm_err(handle->dev_hdl,
+ "Cq resize alloc: service_type %u object_type %u do not support resize\n",
+ object->service_type, object->object_type);
+ return CQM_FAIL;
+}
+EXPORT_SYMBOL(cqm_object_resize_alloc_new);
+
+/**
+ * Prototype : cqm_object_resize_free_new
+ * Description : Currently this function is only used for RoCE.
+ * The CQ buffer is ajusted, but the cqn and cqc remain
+ * unchanged. This function frees new buffer, and is used to deal
+ * with exceptions.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_object_resize_free_new(struct tag_cqm_object *object)
+{
+ struct tag_cqm_rdma_qinfo *qinfo = (struct tag_cqm_rdma_qinfo *)(void *)object;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_buf *q_room_buf = NULL;
+ struct hinic3_hwdev *handle = NULL;
+
+ if (unlikely(!object)) {
+ pr_err("[CQM]%s: object is null\n", __func__);
+ return;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return;
+ }
+ handle = cqm_handle->ex_handle;
+
+ /* This interface is used only for the CQ of RoCE service. */
+ if (object->service_type == CQM_SERVICE_T_ROCE &&
+ object->object_type == CQM_OBJECT_RDMA_SCQ) {
+ if (qinfo->common.current_q_room == CQM_RDMA_Q_ROOM_1)
+ q_room_buf = &qinfo->common.q_room_buf_2;
+ else
+ q_room_buf = &qinfo->common.q_room_buf_1;
+
+ qinfo->new_object_size = 0;
+
+ cqm_buf_free(q_room_buf, cqm_handle);
+ } else {
+ cqm_err(handle->dev_hdl,
+ "Cq resize free: service_type %u object_type %u do not support resize\n",
+ object->service_type, object->object_type);
+ }
+}
+EXPORT_SYMBOL(cqm_object_resize_free_new);
+
+/**
+ * Prototype : cqm_object_resize_free_old
+ * Description : Currently this function is only used for RoCE.
+ * The CQ buffer is ajusted, but the cqn and cqc remain
+ * unchanged. This function frees old buffer and switches the
+ * valid buffer to new buffer.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_object_resize_free_old(struct tag_cqm_object *object)
+{
+ struct tag_cqm_rdma_qinfo *qinfo = (struct tag_cqm_rdma_qinfo *)(void *)object;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_buf *q_room_buf = NULL;
+
+ if (unlikely(!object)) {
+ pr_err("[CQM]%s: object is null\n", __func__);
+ return;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return;
+ }
+
+ /* This interface is used only for the CQ of RoCE service. */
+ if (object->service_type == CQM_SERVICE_T_ROCE &&
+ object->object_type == CQM_OBJECT_RDMA_SCQ) {
+ if (qinfo->common.current_q_room == CQM_RDMA_Q_ROOM_1) {
+ q_room_buf = &qinfo->common.q_room_buf_1;
+ qinfo->common.current_q_room = CQM_RDMA_Q_ROOM_2;
+ } else {
+ q_room_buf = &qinfo->common.q_room_buf_2;
+ qinfo->common.current_q_room = CQM_RDMA_Q_ROOM_1;
+ }
+
+ object->object_size = qinfo->new_object_size;
+
+ cqm_buf_free(q_room_buf, cqm_handle);
+ }
+}
+EXPORT_SYMBOL(cqm_object_resize_free_old);
+
+/**
+ * Prototype : cqm_gid_base
+ * Description : Obtain the base virtual address of the gid table for FT
+ * debug.
+ * Input : void *ex_handle
+ * Output : None
+ * 1.Date : 2015/9/8
+ * Modification : Created function
+ */
+void *cqm_gid_base(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_bat_table *bat_table = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_buf *cla_z_buf = NULL;
+ u32 entry_type, i;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ bat_table = &cqm_handle->bat_table;
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ entry_type = bat_table->bat_entry_type[i];
+ if (entry_type == CQM_BAT_ENTRY_T_GID) {
+ cla_table = &bat_table->entry[i];
+ cla_z_buf = &cla_table->cla_z_buf;
+ if (cla_z_buf->buf_list)
+ return cla_z_buf->buf_list->va;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Prototype : cqm_timer_base
+ * Description : Obtain the base virtual address of the timer for live
+ * migration.
+ * Input : void *ex_handle
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2020/5/21
+ * Modification : Created function
+ */
+void *cqm_timer_base(void *ex_handle)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_bat_table *bat_table = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_buf *cla_z_buf = NULL;
+ u32 entry_type, i;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return NULL;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return NULL;
+ }
+
+ /* Timer resource is configured on PPF. */
+ if (handle->hwif->attr.func_type != CQM_PPF) {
+ cqm_err(handle->dev_hdl, "%s: wrong function type:%d\n",
+ __func__, handle->hwif->attr.func_type);
+ return NULL;
+ }
+
+ bat_table = &cqm_handle->bat_table;
+ for (i = 0; i < CQM_BAT_ENTRY_MAX; i++) {
+ entry_type = bat_table->bat_entry_type[i];
+ if (entry_type != CQM_BAT_ENTRY_T_TIMER)
+ continue;
+
+ cla_table = &bat_table->entry[i];
+ cla_z_buf = &cla_table->cla_z_buf;
+
+ if (!cla_z_buf->direct.va) {
+ if (cqm_buf_alloc_direct(cqm_handle, cla_z_buf, true) ==
+ CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_buf_alloc_direct));
+ return NULL;
+ }
+ }
+
+ return cla_z_buf->direct.va;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(cqm_timer_base);
+
+static s32 cqm_function_timer_clear_getindex(struct hinic3_hwdev *ex_handle, u32 *buffer_index,
+ u32 function_id, u32 timer_page_num,
+ const struct tag_cqm_buf *cla_z_buf)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(ex_handle->cqm_hdl);
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ u32 index;
+
+ /* Convert functionid and the functionid does not exceed the value range
+ * of the tiemr buffer.
+ */
+ if (function_id < (func_cap->timer_pf_id_start + func_cap->timer_pf_num) &&
+ function_id >= func_cap->timer_pf_id_start) {
+ index = function_id - func_cap->timer_pf_id_start;
+ } else if (function_id < (func_cap->timer_vf_id_start + func_cap->timer_vf_num) &&
+ function_id >= func_cap->timer_vf_id_start) {
+ index = (function_id - func_cap->timer_vf_id_start) +
+ func_cap->timer_pf_num;
+ } else {
+ cqm_err(ex_handle->dev_hdl, "Timer clear: wrong function_id=0x%x\n",
+ function_id);
+ return CQM_FAIL;
+ }
+
+ if ((index * timer_page_num + timer_page_num) > cla_z_buf->buf_number) {
+ cqm_err(ex_handle->dev_hdl,
+ "Timer clear: over cla_z_buf_num, buffer_i=0x%x, zbuf_num=0x%x\n",
+ index, cla_z_buf->buf_number);
+ return CQM_FAIL;
+ }
+
+ *buffer_index = index;
+ return CQM_SUCCESS;
+}
+
+static void cqm_clear_timer(void *ex_handle, u32 function_id, struct hinic3_hwdev *handle,
+ struct tag_cqm_cla_table *cla_table)
+{
+ u32 timer_buffer_size = CQM_TIMER_ALIGN_SCALE_NUM * CQM_TIMER_SIZE_32;
+ struct tag_cqm_buf *cla_z_buf = &cla_table->cla_z_buf;
+ u32 timer_page_num, i;
+ u32 buffer_index = 0;
+ s32 ret;
+
+ /* During CQM capability initialization, ensure that the basic size of
+ * the timer buffer page does not exceed 128 x 4 KB. Otherwise,
+ * clearing the timer buffer of the function is complex.
+ */
+ timer_page_num = timer_buffer_size /
+ (PAGE_SIZE << cla_table->trunk_order);
+ if (timer_page_num == 0) {
+ cqm_err(handle->dev_hdl,
+ "Timer clear: fail to clear timer, buffer_size=0x%x, trunk_order=0x%x\n",
+ timer_buffer_size, cla_table->trunk_order);
+ return;
+ }
+
+ /* Convert functionid and the functionid does not exceed the value range
+ * of the tiemr buffer.
+ */
+ ret = cqm_function_timer_clear_getindex(ex_handle, &buffer_index,
+ function_id, timer_page_num,
+ cla_z_buf);
+ if (ret == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_function_timer_clear_getindex));
+ return;
+ }
+
+ if (cla_table->cla_lvl == CQM_CLA_LVL_1 ||
+ cla_table->cla_lvl == CQM_CLA_LVL_2) {
+ for (i = buffer_index * timer_page_num;
+ i < (buffer_index * timer_page_num + timer_page_num); i++)
+ memset((u8 *)(cla_z_buf->buf_list[i].va), 0,
+ (PAGE_SIZE << cla_table->trunk_order));
+ } else {
+ cqm_err(handle->dev_hdl, "Timer clear: timer cla lvl: %u, cla_z_buf_num=0x%x\n",
+ cla_table->cla_lvl, cla_z_buf->buf_number);
+ cqm_err(handle->dev_hdl,
+ "Timer clear: buf_i=0x%x, buf_size=0x%x, page_num=0x%x, order=0x%x\n",
+ buffer_index, timer_buffer_size, timer_page_num,
+ cla_table->trunk_order);
+ }
+}
+
+/**
+ * Prototype : cqm_function_timer_clear
+ * Description : Clear the timer buffer based on the function ID.
+ * The function ID starts from 0 and the timer buffer is arranged
+ * in sequence by function ID.
+ * Input : void *ex_handle
+ * u32 functionid
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2016/12/19
+ * Modification : Created function
+ */
+void cqm_function_timer_clear(void *ex_handle, u32 function_id)
+{
+ /* The timer buffer of one function is 32B*8wheel*2048spoke=128*4k */
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ int loop, i;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_func_timer_clear_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return;
+ }
+
+ if (cqm_handle->func_capability.lb_mode == CQM_LB_MODE_1 ||
+ cqm_handle->func_capability.lb_mode == CQM_LB_MODE_2) {
+ cla_table = &cqm_handle->bat_table.timer_entry[0];
+ loop = CQM_LB_SMF_MAX;
+ } else {
+ cla_table = cqm_cla_table_get(&cqm_handle->bat_table, CQM_BAT_ENTRY_T_TIMER);
+ loop = 1;
+ }
+
+ if (unlikely(!cla_table)) {
+ pr_err("[CQM]%s: cla_table is null\n", __func__);
+ return;
+ }
+ for (i = 0; i < loop; i++) {
+ cqm_clear_timer(ex_handle, function_id, handle, cla_table);
+ cla_table++;
+ }
+}
+EXPORT_SYMBOL(cqm_function_timer_clear);
+
+/**
+ * Prototype : cqm_function_hash_buf_clear
+ * Description : clear hash buffer based on global function_id
+ * Input : void *ex_handle
+ * s32 global_funcid
+ * Output : None
+ * Return Value : None
+ * 1.Date : 2017/11/27
+ * Modification : Created function
+ * 2.Date : 2021/02/23
+ * Modification : Add para func_id; clear hash buf by func_id
+ */
+void cqm_function_hash_buf_clear(void *ex_handle, s32 global_funcid)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_func_capability *func_cap = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_buf *cla_z_buf = NULL;
+ s32 fake_funcid;
+ u32 i;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return;
+ }
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_func_hash_buf_clear_cnt);
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ if (unlikely(!cqm_handle)) {
+ pr_err("[CQM]%s: cqm_handle is null\n", __func__);
+ return;
+ }
+ func_cap = &cqm_handle->func_capability;
+
+ /* fake vf adaption, switch to corresponding VF. */
+ if (func_cap->fake_func_type == CQM_FAKE_FUNC_PARENT) {
+ fake_funcid = global_funcid -
+ (s32)(func_cap->fake_cfg[0].child_func_start);
+ cqm_info(handle->dev_hdl, "fake_funcid =%d\n", fake_funcid);
+ if (fake_funcid < 0 || fake_funcid >= CQM_FAKE_FUNC_MAX) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(fake_funcid));
+ return;
+ }
+
+ cqm_handle = cqm_handle->fake_cqm_handle[fake_funcid];
+ }
+
+ cla_table = cqm_cla_table_get(&cqm_handle->bat_table,
+ CQM_BAT_ENTRY_T_HASH);
+ if (unlikely(!cla_table)) {
+ pr_err("[CQM]%s: cla_table is null\n", __func__);
+ return;
+ }
+ cla_z_buf = &cla_table->cla_z_buf;
+
+ for (i = 0; i < cla_z_buf->buf_number; i++)
+ memset(cla_z_buf->buf_list[i].va, 0, cla_z_buf->buf_size);
+}
+EXPORT_SYMBOL(cqm_function_hash_buf_clear);
+
+void cqm_srq_used_rq_container_delete(struct tag_cqm_object *object, u8 *container)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ u32 link_wqe_offset = qinfo->wqe_per_buf * qinfo->wqe_size;
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(common->object.cqm_handle);
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_srq_linkwqe *srq_link_wqe = NULL;
+ dma_addr_t addr;
+
+ /* 1. Obtain the current container pa through link wqe table,
+ * unmap pa
+ */
+ srq_link_wqe = (struct tag_cqm_srq_linkwqe *)(container + link_wqe_offset);
+ /* shift right by 2 bits to get the length of dw(4B) */
+ cqm_swab32((u8 *)(srq_link_wqe), sizeof(struct tag_cqm_linkwqe) >> 2);
+
+ addr = CQM_ADDR_COMBINE(srq_link_wqe->current_buffer_gpa_h,
+ srq_link_wqe->current_buffer_gpa_l);
+ if (addr == 0) {
+ cqm_err(handle->dev_hdl, "Rq container del: buffer physical addr is null\n");
+ return;
+ }
+ pci_unmap_single(cqm_handle->dev, addr, qinfo->container_size,
+ PCI_DMA_BIDIRECTIONAL);
+
+ /* 2. Obtain the current container va through link wqe table, free va */
+ addr = CQM_ADDR_COMBINE(srq_link_wqe->current_buffer_addr_h,
+ srq_link_wqe->current_buffer_addr_l);
+ if (addr == 0) {
+ cqm_err(handle->dev_hdl, "Rq container del: buffer virtual addr is null\n");
+ return;
+ }
+ kfree((void *)addr);
+}
+EXPORT_SYMBOL(cqm_srq_used_rq_container_delete);
+
+s32 cqm_dtoe_share_recv_queue_create(void *ex_handle, u32 contex_size,
+ u32 *index_count, u32 *index)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_toe_private_capability *tow_own_cap = NULL;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_bitmap *bitmap = NULL;
+ u32 step;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!index_count)) {
+ pr_err("[CQM]%s: index_count is null\n", __func__);
+ return CQM_FAIL;
+ }
+ if (unlikely(!index)) {
+ pr_err("[CQM]%s: index is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ tow_own_cap = &cqm_handle->toe_own_capability;
+
+ bitmap = &tow_own_cap->srqc_bitmap;
+ *index_count = (ALIGN(contex_size, tow_own_cap->toe_srqc_basic_size)) /
+ tow_own_cap->toe_srqc_basic_size;
+ /* toe srqc number must align of 2 */
+ step = ALIGN(tow_own_cap->toe_srqc_number, 2);
+ *index = cqm_bitmap_alloc(bitmap, step, *index_count,
+ cqm_handle->func_capability.xid_alloc_mode);
+ if (*index >= bitmap->max_num) {
+ cqm_err(handle->dev_hdl, "Srq create: queue index %u exceeds max_num %u\n",
+ *index, bitmap->max_num);
+ return CQM_FAIL;
+ }
+ *index += tow_own_cap->toe_srqc_start_id;
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_srq_create_cnt);
+
+ return CQM_SUCCESS;
+}
+EXPORT_SYMBOL(cqm_dtoe_share_recv_queue_create);
+
+void cqm_dtoe_free_srq_bitmap_index(void *ex_handle, u32 index_count, u32 index)
+{
+ struct hinic3_hwdev *handle = (struct hinic3_hwdev *)ex_handle;
+ struct tag_cqm_handle *cqm_handle = NULL;
+ struct tag_cqm_bitmap *bitmap = NULL;
+
+ if (unlikely(!ex_handle)) {
+ pr_err("[CQM]%s: ex_handle is null\n", __func__);
+ return;
+ }
+
+ cqm_handle = (struct tag_cqm_handle *)(handle->cqm_hdl);
+ bitmap = &cqm_handle->toe_own_capability.srqc_bitmap;
+ cqm_bitmap_free(bitmap, index, index_count);
+}
+EXPORT_SYMBOL(cqm_dtoe_free_srq_bitmap_index);
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object.h
new file mode 100644
index 0000000000000..ba61828f28f53
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object.h
@@ -0,0 +1,714 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_OBJECT_H
+#define CQM_OBJECT_H
+
+#include "cqm_define.h"
+#include "vram_common.h"
+
+#define CQM_LINKWQE_128B 128
+#define CQM_MOD_TOE HINIC3_MOD_TOE
+#define CQM_MOD_CQM HINIC3_MOD_CQM
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif
+#endif /* __cplusplus */
+
+#ifndef HIUDK_SDK
+
+#define CQM_SUCCESS 0
+#define CQM_FAIL (-1)
+/* Ignore the return value and continue */
+#define CQM_CONTINUE 1
+
+/* type of WQE is LINK WQE */
+#define CQM_WQE_WF_LINK 1
+/* type of WQE is common WQE */
+#define CQM_WQE_WF_NORMAL 0
+
+/* chain queue mode */
+#define CQM_QUEUE_LINK_MODE 0
+/* RING queue mode */
+#define CQM_QUEUE_RING_MODE 1
+/* SRQ queue mode */
+#define CQM_QUEUE_TOE_SRQ_LINK_MODE 2
+/* RDMA queue mode */
+#define CQM_QUEUE_RDMA_QUEUE_MODE 3
+
+/* generic linkwqe structure */
+struct tag_cqm_linkwqe {
+ u32 rsv1 : 14; /* <reserved field */
+ u32 wf : 1; /* <wf */
+ u32 rsv2 : 14; /* <reserved field */
+ u32 ctrlsl : 2; /* <ctrlsl */
+ u32 o : 1; /* <o bit */
+
+ u32 rsv3 : 31; /* <reserved field */
+ u32 lp : 1; /* The lp field determines whether the o-bit
+ * meaning is reversed.
+ */
+
+ u32 next_page_gpa_h; /* <record the upper 32b physical address of the
+ * next page for the chip
+ */
+ u32 next_page_gpa_l; /* <record the lower 32b physical address of the
+ * next page for the chip
+ */
+
+ u32 next_buffer_addr_h; /* <record the upper 32b virtual address of the
+ * next page for the driver
+ */
+ u32 next_buffer_addr_l; /* <record the lower 32b virtual address of the
+ * next page for the driver
+ */
+};
+
+/* SRQ linkwqe structure. The wqe size must not exceed the common RQE size. */
+struct tag_cqm_srq_linkwqe {
+ struct tag_cqm_linkwqe linkwqe; /* <generic linkwqe structure */
+ u32 current_buffer_gpa_h; /* <Record the upper 32b physical address of
+ * the current page, which is used when the
+ * driver releases the container and cancels
+ * the mapping.
+ */
+ u32 current_buffer_gpa_l; /* <Record the lower 32b physical address of
+ * the current page, which is used when the
+ * driver releases the container and cancels
+ * the mapping.
+ */
+ u32 current_buffer_addr_h; /* <Record the upper 32b of the virtual
+ * address of the current page, which is used
+ * when the driver releases the container.
+ */
+ u32 current_buffer_addr_l; /* <Record the lower 32b of the virtual
+ * address of the current page, which is used
+ * when the driver releases the container.
+ */
+
+ u32 fast_link_page_addr_h; /* <Record the upper 32b of the virtual
+ * address of the fastlink page where the
+ * container address is recorded. It is used
+ * when the driver releases the fastlink.
+ */
+ u32 fast_link_page_addr_l; /* <Record the lower 32b virtual address of
+ * the fastlink page where the container
+ * address is recorded. It is used when the
+ * driver releases the fastlink.
+ */
+
+ u32 fixed_next_buffer_addr_h; /* <Record the upper 32b virtual address
+ * of the next contianer, which is used to
+ * release driver resources. The driver
+ * cannot be modified.
+ */
+ u32 fixed_next_buffer_addr_l; /* <Record the lower 32b virtual address
+ * of the next contianer, which is used to
+ * release driver resources. The driver
+ * cannot be modified.
+ */
+};
+
+/* first 64B of standard 128B WQE */
+union tag_cqm_linkwqe_first64B {
+ struct tag_cqm_linkwqe basic_linkwqe; /* <generic linkwqe structure */
+ struct tag_cqm_srq_linkwqe toe_srq_linkwqe; /* <SRQ linkwqe structure */
+ u32 value[16]; /* <reserved field */
+};
+
+/* second 64B of standard 128B WQE */
+struct tag_cqm_linkwqe_second64B {
+ u32 rsvd0[4]; /* <first 16B reserved field */
+ u32 rsvd1[4]; /* <second 16B reserved field */
+ union {
+ struct {
+ u32 rsvd0[3];
+ u32 rsvd1 : 29;
+ u32 toe_o : 1; /* <o bit of toe */
+ u32 resvd2 : 2;
+ } bs;
+ u32 value[4];
+ } third_16B; /* <third 16B */
+
+ union {
+ struct {
+ u32 rsvd0[2];
+ u32 rsvd1 : 31;
+ u32 ifoe_o : 1; /* <o bit of ifoe */
+ u32 rsvd2;
+ } bs;
+ u32 value[4];
+ } forth_16B; /* <fourth 16B */
+};
+
+/* standard 128B WQE structure */
+struct tag_cqm_linkwqe_128B {
+ union tag_cqm_linkwqe_first64B first64B; /* <first 64B of standard 128B WQE */
+ struct tag_cqm_linkwqe_second64B second64B; /* <back 64B of standard 128B WQE */
+};
+
+/* AEQ type definition */
+enum cqm_aeq_event_type {
+ CQM_AEQ_BASE_T_NIC = 0, /* <NIC consists of 16 events:0~15 */
+ CQM_AEQ_BASE_T_ROCE = 16, /* <ROCE consists of 32 events:16~47 */
+ CQM_AEQ_BASE_T_FC = 48, /* <FC consists of 8 events:48~55 */
+ CQM_AEQ_BASE_T_IOE = 56, /* <IOE consists of 8 events:56~63 */
+ CQM_AEQ_BASE_T_TOE = 64, /* <TOE consists of 16 events:64~95 */
+ CQM_AEQ_BASE_T_VBS = 96, /* <VBS consists of 16 events:96~111 */
+ CQM_AEQ_BASE_T_IPSEC = 112, /* <VBS consists of 16 events:112~127 */
+ CQM_AEQ_BASE_T_MAX = 128 /* <maximum of 128 events can be defined */
+};
+
+/* service registration template */
+struct tag_service_register_template {
+ u32 service_type; /* <service type */
+ u32 srq_ctx_size; /* <SRQ context size */
+ u32 scq_ctx_size; /* <SCQ context size */
+ void *service_handle; /* <pointer to the service driver when the
+ * ceq/aeq function is called back
+ */
+ /* <ceq callback:shared cq */
+ void (*shared_cq_ceq_callback)(void *service_handle, u32 cqn,
+ void *cq_priv);
+ /* <ceq callback:embedded cq */
+ void (*embedded_cq_ceq_callback)(void *service_handle, u32 xid,
+ void *qpc_priv);
+ /* <ceq callback:no cq */
+ void (*no_cq_ceq_callback)(void *service_handle, u32 xid, u32 qid,
+ void *qpc_priv);
+ /* <aeq level callback */
+ u8 (*aeq_level_callback)(void *service_handle, u8 event_type, u8 *val);
+ /* <aeq callback */
+ void (*aeq_callback)(void *service_handle, u8 event_type, u8 *val);
+};
+
+/* object operation type definition */
+enum cqm_object_type {
+ CQM_OBJECT_ROOT_CTX = 0, /* <0:root context, which is compatible with
+ * root CTX management
+ */
+ CQM_OBJECT_SERVICE_CTX, /* <1:QPC, connection management object */
+ CQM_OBJECT_MPT, /* <2:RDMA service usage */
+
+ CQM_OBJECT_NONRDMA_EMBEDDED_RQ = 10, /* <10:RQ of non-RDMA services,
+ * managed by LINKWQE
+ */
+ CQM_OBJECT_NONRDMA_EMBEDDED_SQ, /* <11:SQ of non-RDMA services,
+ * managed by LINKWQE
+ */
+ CQM_OBJECT_NONRDMA_SRQ, /* <12:SRQ of non-RDMA services,
+ * managed by MTT, but the CQM
+ * needs to apply for MTT.
+ */
+ CQM_OBJECT_NONRDMA_EMBEDDED_CQ, /* <13:Embedded CQ for non-RDMA
+ * services, managed by LINKWQE
+ */
+ CQM_OBJECT_NONRDMA_SCQ, /* <14:SCQ of non-RDMA services,
+ * managed by LINKWQE
+ */
+
+ CQM_OBJECT_RESV = 20,
+
+ CQM_OBJECT_RDMA_QP = 30, /* <30:QP of RDMA services, managed by MTT */
+ CQM_OBJECT_RDMA_SRQ, /* <31:SRQ of RDMA services, managed by MTT */
+ CQM_OBJECT_RDMA_SCQ, /* <32:SCQ of RDMA services, managed by MTT */
+
+ CQM_OBJECT_MTT = 50, /* <50:MTT table of the RDMA service */
+ CQM_OBJECT_RDMARC, /* <51:RC of the RDMA service */
+};
+
+/* return value of the failure to apply for the BITMAP table */
+#define CQM_INDEX_INVALID (~(0U))
+/* Return value of the reserved bit applied for in the BITMAP table,
+ * indicating that the index is allocated by the CQM and
+ * cannot be specified by the driver.
+ */
+#define CQM_INDEX_RESERVED 0xfffff
+
+/* to support ROCE Q buffer resize, the first Q buffer space */
+#define CQM_RDMA_Q_ROOM_1 1
+/* to support the Q buffer resize of ROCE, the second Q buffer space */
+#define CQM_RDMA_Q_ROOM_2 2
+
+/* doorbell mode selected by the current Q, hardware doorbell */
+#define CQM_HARDWARE_DOORBELL 1
+/* doorbell mode selected by the current Q, software doorbell */
+#define CQM_SOFTWARE_DOORBELL 2
+
+/* single-node structure of the CQM buffer */
+struct tag_cqm_buf_list {
+ void *va; /* <virtual address */
+ dma_addr_t pa; /* <physical address */
+ u32 refcount; /* <reference counting of the buf,
+ * which is used for internal buf management.
+ */
+};
+
+/* common management structure of the CQM buffer */
+struct tag_cqm_buf {
+ struct tag_cqm_buf_list *buf_list; /* <buffer list */
+ struct tag_cqm_buf_list direct; /* <map the discrete buffer list to a group
+ * of consecutive addresses
+ */
+ u32 page_number; /* <buf_number in quantity of page_number=2^n */
+ u32 buf_number; /* <number of buf_list nodes */
+ u32 buf_size; /* <PAGE_SIZE in quantity of buf_size=2^n */
+ struct vram_buf_info buf_info;
+ u32 bat_entry_type;
+};
+
+/* CQM object structure, which can be considered
+ * as the base class abstracted from all queues/CTX.
+ */
+struct tag_cqm_object {
+ u32 service_type; /* <service type */
+ u32 object_type; /* <object type, such as context, queue, mpt,
+ * and mtt, etc
+ */
+ u32 object_size; /* <object Size, for queue/CTX/MPT,
+ * the unit is Byte, for MTT/RDMARC,
+ * the unit is the number of entries,
+ * for containers, the unit is the number of
+ * containers.
+ */
+ atomic_t refcount; /* <reference counting */
+ struct completion free; /* <release completed quantity */
+ void *cqm_handle; /* <cqm_handle */
+};
+
+/* structure of the QPC and MPT objects of the CQM */
+struct tag_cqm_qpc_mpt {
+ struct tag_cqm_object object; /* <object base class */
+ u32 xid; /* <xid */
+ dma_addr_t paddr; /* <physical address of the QPC/MTT memory */
+ void *priv; /* <private information about the object of
+ * the service driver.
+ */
+ u8 *vaddr; /* <virtual address of the QPC/MTT memory */
+};
+
+/* queue header structure */
+struct tag_cqm_queue_header {
+ u64 doorbell_record; /* <SQ/RQ DB content */
+ u64 ci_record; /* <CQ DB content */
+ u64 rsv1; /* <This area is a user-defined area for driver
+ * and microcode information transfer.
+ */
+ u64 rsv2; /* <This area is a user-defined area for driver
+ * and microcode information transfer.
+ */
+};
+
+/* queue management structure: for queues of non-RDMA services, embedded queues
+ * are managed by LinkWQE, SRQ and SCQ are managed by MTT, but MTT needs to be
+ * applied by CQM; the queue of the RDMA service is managed by the MTT.
+ */
+struct tag_cqm_queue {
+ struct tag_cqm_object object; /* <object base class */
+ u32 index; /* <The embedded queue and QP do not have
+ * indexes, but the SRQ and SCQ do.
+ */
+ void *priv; /* <private information about the object of
+ * the service driver
+ */
+ u32 current_q_doorbell; /* <doorbell type selected by the current
+ * queue. HW/SW are used for the roce QP.
+ */
+ u32 current_q_room; /* <roce:current valid room buf */
+ struct tag_cqm_buf q_room_buf_1; /* <nonrdma:only q_room_buf_1 can be set to
+ * q_room_buf
+ */
+ struct tag_cqm_buf q_room_buf_2; /* <The CQ of RDMA reallocates the size of
+ * the queue room.
+ */
+ struct tag_cqm_queue_header *q_header_vaddr; /* <queue header virtual address */
+ dma_addr_t q_header_paddr; /* <physical address of the queue header */
+ u8 *q_ctx_vaddr; /* <CTX virtual addresses of SRQ and SCQ */
+ dma_addr_t q_ctx_paddr; /* <CTX physical addresses of SRQ and SCQ */
+ u32 valid_wqe_num; /* <number of valid WQEs that are
+ * successfully created
+ */
+ u8 *tail_container; /* <tail pointer of the SRQ container */
+ u8 *head_container; /* <head pointer of SRQ container */
+ u8 queue_link_mode; /* <Determine the connection mode during
+ * queue creation, such as link and ring.
+ */
+};
+
+/* MTT/RDMARC management structure */
+struct tag_cqm_mtt_rdmarc {
+ struct tag_cqm_object object; /* <object base class */
+ u32 index_base; /* <index_base */
+ u32 index_number; /* <index_number */
+ u8 *vaddr; /* <buffer virtual address */
+};
+
+/* sending command structure */
+struct tag_cqm_cmd_buf {
+ void *buf; /* <command buffer virtual address */
+ dma_addr_t dma; /* <physical address of the command buffer */
+ u16 size; /* <command buffer size */
+};
+
+/* definition of sending ACK mode */
+enum cqm_cmd_ack_type {
+ CQM_CMD_ACK_TYPE_CMDQ = 0, /* <ack is written back to cmdq */
+ CQM_CMD_ACK_TYPE_SHARE_CQN = 1, /* <ack is reported through the SCQ of
+ * the root CTX.
+ */
+ CQM_CMD_ACK_TYPE_APP_CQN = 2 /* <ack is reported through the SCQ of
+ * service
+ */
+};
+
+#endif
+/**
+ * @brief: create FC SRQ.
+ * @details: The number of valid WQEs in the queue must meet the number of
+ * transferred WQEs. Linkwqe can only be filled at the end of the
+ * page. The actual number of valid links exceeds the requirement.
+ * The service needs to be informed of the number of extra links to
+ * be created.
+ * @param ex_handle: device pointer that represents the PF
+ * @param service_type: service type
+ * @param object_type: object type
+ * @param wqe_number: number of WQEs
+ * @param wqe_size: wqe size
+ * @param object_priv: pointer to object private information
+ * @retval struct tag_cqm_queue*: queue structure pointer
+ * @date: 2019-5-4
+ */
+struct tag_cqm_queue *cqm_object_fc_srq_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 wqe_number, u32 wqe_size,
+ void *object_priv);
+
+/**
+ * @brief: create RQ.
+ * @details: When SRQ is used, the RQ queue is created.
+ * @param ex_handle: device pointer that represents the PF
+ * @param service_type: service type
+ * @param object_type: object type
+ * @param init_rq_num: number of containers
+ * @param container_size: container size
+ * @param wqe_size: wqe size
+ * @param object_priv: pointer to object private information
+ * @retval struct tag_cqm_queue*: queue structure pointer
+ * @date: 2019-5-4
+ */
+struct tag_cqm_queue *cqm_object_recv_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 init_rq_num, u32 container_size,
+ u32 wqe_size, void *object_priv);
+
+/**
+ * @brief: SRQ applies for a new container and is linked after the container
+ * is created.
+ * @details: SRQ applies for a new container and is linked after the container
+ * is created.
+ * @param common: queue structure pointer
+ * @retval 0: success
+ * @retval -1: fail
+ * @date: 2019-5-4
+ */
+s32 cqm_object_share_recv_queue_add_container(struct tag_cqm_queue *common);
+
+/**
+ * @brief: SRQ applies for a new container. After the container is created,
+ * no link is attached to the container. The service is attached to
+ * the container.
+ * @details: SRQ applies for a new container. After the container is created,
+ * no link is attached to the container. The service is attached to
+ * the container.
+ * @param common: queue structure pointer
+ * @param container_addr: returned container address
+ * @retval 0: success
+ * @retval -1: fail
+ * @date: 2019-5-4
+ */
+s32 cqm_object_srq_add_container_free(struct tag_cqm_queue *common, u8 **container_addr);
+
+/**
+ * @brief: create SRQ for TOE services.
+ * @details: create SRQ for TOE services.
+ * @param ex_handle: device pointer that represents the PF
+ * @param service_type: service type
+ * @param object_type: object type
+ * @param container_number: number of containers
+ * @param container_size: container size
+ * @param wqe_size: wqe size
+ * @retval struct tag_cqm_queue*: queue structure pointer
+ * @date: 2019-5-4
+ */
+struct tag_cqm_queue *cqm_object_share_recv_queue_create(void *ex_handle,
+ u32 service_type,
+ enum cqm_object_type object_type,
+ u32 container_number,
+ u32 container_size,
+ u32 wqe_size);
+
+/**
+ * @brief: create QPC and MPT.
+ * @details: When QPC and MPT are created, the interface sleeps.
+ * @param ex_handle: device pointer that represents the PF
+ * @param service_type: service type
+ * @param object_type: object type
+ * @param object_size: object size, in bytes.
+ * @param object_priv: private structure of the service layer.
+ * The value can be NULL.
+ * @param index: apply for reserved qpn based on the value. If automatic
+ * allocation is required, fill CQM_INDEX_INVALID.
+ * @retval struct tag_cqm_qpc_mpt *: pointer to the QPC/MPT structure
+ * @date: 2019-5-4
+ */
+struct tag_cqm_qpc_mpt *cqm_object_qpc_mpt_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 object_size, void *object_priv,
+ u32 index, bool low2bit_align_en);
+
+/**
+ * @brief: create a queue for non-RDMA services.
+ * @details: create a queue for non-RDMA services. The interface sleeps.
+ * @param ex_handle: device pointer that represents the PF
+ * @param service_type: service type
+ * @param object_type: object type
+ * @param wqe_number: number of Link WQEs
+ * @param wqe_size: fixed length, size 2^n
+ * @param object_priv: private structure of the service layer.
+ * The value can be NULL.
+ * @retval struct tag_cqm_queue *: queue structure pointer
+ * @date: 2019-5-4
+ */
+struct tag_cqm_queue *cqm_object_nonrdma_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 wqe_number, u32 wqe_size,
+ void *object_priv);
+
+/**
+ * @brief: create a RDMA service queue.
+ * @details: create a queue for the RDMA service. The interface sleeps.
+ * @param ex_handle: device pointer that represents the PF
+ * @param service_type: service type
+ * @param object_type: object type
+ * @param object_size: object size
+ * @param object_priv: private structure of the service layer.
+ * The value can be NULL.
+ * @param room_header_alloc: whether to apply for the queue room and header
+ * space
+ * @retval struct tag_cqm_queue *: queue structure pointer
+ * @date: 2019-5-4
+ */
+struct tag_cqm_queue *cqm_object_rdma_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 object_size, void *object_priv,
+ bool room_header_alloc, u32 xid);
+
+/**
+ * @brief: create the MTT and RDMARC of the RDMA service.
+ * @details: create the MTT and RDMARC of the RDMA service.
+ * @param ex_handle: device pointer that represents the PF
+ * @param service_type: service type
+ * @param object_type: object type
+ * @param index_base: start index number
+ * @param index_number: index number
+ * @retval struct tag_cqm_mtt_rdmarc *: pointer to the MTT/RDMARC structure
+ * @date: 2019-5-4
+ */
+struct tag_cqm_mtt_rdmarc *cqm_object_rdma_table_get(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 index_base, u32 index_number);
+
+/**
+ * @brief: delete created objects.
+ * @details: delete the created object. This function does not return until all
+ * operations on the object are complete.
+ * @param object: object pointer
+ * @retval: void
+ * @date: 2019-5-4
+ */
+void cqm_object_delete(struct tag_cqm_object *object);
+
+/**
+ * @brief: obtains the physical address and virtual address at the specified
+ * offset of the object buffer.
+ * @details: Only RDMA table query is supported to obtain the physical address
+ * and virtual address at the specified offset of the object buffer.
+ * @param object: object pointer
+ * @param offset: for a rdma table, offset is the absolute index number.
+ * @param paddr: The physical address is returned only for the rdma table.
+ * @retval u8 *: buffer specify the virtual address at the offset
+ * @date: 2019-5-4
+ */
+u8 *cqm_object_offset_addr(struct tag_cqm_object *object, u32 offset, dma_addr_t *paddr);
+
+/**
+ * @brief: obtain object according index.
+ * @details: obtain object according index.
+ * @param ex_handle: device pointer that represents the PF
+ * @param object_type: object type
+ * @param index: support qpn,mptn,scqn,srqn
+ * @param bh: whether to disable the bottom half of the interrupt
+ * @retval struct tag_cqm_object *: object pointer
+ * @date: 2019-5-4
+ */
+struct tag_cqm_object *cqm_object_get(void *ex_handle, enum cqm_object_type object_type,
+ u32 index, bool bh);
+
+/**
+ * @brief: object reference counting release
+ * @details: After the function cqm_object_get is invoked, this API must be put.
+ * Otherwise, the object cannot be released.
+ * @param object: object pointer
+ * @retval: void
+ * @date: 2019-5-4
+ */
+void cqm_object_put(struct tag_cqm_object *object);
+
+/**
+ * @brief: obtain the ID of the function where the object resides.
+ * @details: obtain the ID of the function where the object resides.
+ * @param object: object pointer
+ * @retval >=0: ID of function
+ * @retval -1: fail
+ * @date: 2020-4-15
+ */
+s32 cqm_object_funcid(struct tag_cqm_object *object);
+
+/**
+ * @brief: apply for a new space for an object.
+ * @details: Currently, this parameter is valid only for the ROCE service.
+ * The CQ buffer size is adjusted, but the CQN and CQC remain
+ * unchanged. New buffer space is applied for, and the old buffer
+ * space is not released. The current valid buffer is still the old
+ * buffer.
+ * @param object: object pointer
+ * @param object_size: new buffer size
+ * @retval 0: success
+ * @retval -1: fail
+ * @date: 2019-5-4
+ */
+s32 cqm_object_resize_alloc_new(struct tag_cqm_object *object, u32 object_size);
+
+/**
+ * @brief: release the newly applied buffer space for the object.
+ * @details: This function is used to release the newly applied buffer space for
+ * service exception handling.
+ * @param object: object pointer
+ * @retval: void
+ * @date: 2019-5-4
+ */
+void cqm_object_resize_free_new(struct tag_cqm_object *object);
+
+/**
+ * @brief: release old buffer space for objects.
+ * @details: This function releases the old buffer and sets the current valid
+ * buffer to the new buffer.
+ * @param object: object pointer
+ * @retval: void
+ * @date: 2019-5-4
+ */
+void cqm_object_resize_free_old(struct tag_cqm_object *object);
+
+/**
+ * @brief: release container.
+ * @details: release container.
+ * @param object: object pointer
+ * @param container: container pointer to be released
+ * @retval: void
+ * @date: 2019-5-4
+ */
+void cqm_srq_used_rq_container_delete(struct tag_cqm_object *object, u8 *container);
+
+void *cqm_get_db_addr(void *ex_handle, u32 service_type);
+
+s32 cqm_ring_hardware_db_fc(void *ex_handle, u32 service_type, u8 db_count,
+ u8 pagenum, u64 db);
+
+/**
+ * @brief: provide the interface of knocking on doorbell.
+ * The CQM converts the pri to cos.
+ * @details: provide interface of knocking on doorbell for the CQM to convert
+ * the pri to cos. The doorbell transferred by the service must be the
+ * host sequence. This interface converts the network sequence.
+ * @param ex_handle: device pointer that represents the PF
+ * @param service_type: Each kernel-mode service is allocated a hardware
+ * doorbell page.
+ * @param db_count: PI[7:0] beyond 64b in the doorbell
+ * @param db: The doorbell content is organized by the service. If there is
+ * endian conversion, the service needs to complete the conversion.
+ * @retval 0: success
+ * @retval -1: fail
+ * @date: 2019-5-4
+ */
+s32 cqm_ring_hardware_db_update_pri(void *ex_handle, u32 service_type,
+ u8 db_count, u64 db);
+
+/**
+ * @brief: knock on software doorbell.
+ * @details: knock on software doorbell.
+ * @param object: object pointer
+ * @param db_record: software doorbell content. If there is big-endian
+ * conversion, the service needs to complete the conversion.
+ * @retval 0: success
+ * @retval -1: fail
+ * @date: 2019-5-4
+ */
+s32 cqm_ring_software_db(struct tag_cqm_object *object, u64 db_record);
+
+/**
+ * @brief: reference counting is added to the bloom filter ID.
+ * @details: reference counting is added to the bloom filter ID. When the ID
+ * changes from 0 to 1, the sending API is set to 1.
+ * This interface sleeps.
+ * @param ex_handle: device pointer that represents the PF
+ * @param id: id
+ * @retval 0: success
+ * @retval -1: fail
+ * @date: 2019-5-4
+ */
+void *cqm_gid_base(void *ex_handle);
+
+/**
+ * @brief: obtain the base virtual address of the timer.
+ * @details: obtain the base virtual address of the timer.
+ * @param ex_handle: device pointer that represents the PF
+ * @retval void *: base virtual address of the timer
+ * @date: 2020-5-21
+ */
+void *cqm_timer_base(void *ex_handle);
+
+/**
+ * @brief: clear timer buffer.
+ * @details: clear the timer buffer based on the function ID. Function IDs start
+ * from 0, and timer buffers are arranged by function ID.
+ * @param ex_handle: device pointer that represents the PF
+ * @param function_id: function id
+ * @retval: void
+ * @date: 2019-5-4
+ */
+void cqm_function_timer_clear(void *ex_handle, u32 function_id);
+
+/**
+ * @brief: clear hash buffer.
+ * @details: clear the hash buffer based on the function ID.
+ * @param ex_handle: device pointer that represents the PF
+ * @param global_funcid
+ * @retval: void
+ * @date: 2019-5-4
+ */
+void cqm_function_hash_buf_clear(void *ex_handle, s32 global_funcid);
+
+s32 cqm_ring_direct_wqe_db(void *ex_handle, u32 service_type, u8 db_count,
+ void *direct_wqe);
+s32 cqm_ring_direct_wqe_db_fc(void *ex_handle, u32 service_type,
+ void *direct_wqe);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif /* CQM_OBJECT_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object_intern.c b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object_intern.c
new file mode 100644
index 0000000000000..d149d54f7ee52
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object_intern.c
@@ -0,0 +1,1467 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+
+#include "ossl_knl.h"
+#include "hinic3_crm.h"
+#include "hinic3_hw.h"
+#include "hinic3_hwdev.h"
+
+#include "cqm_object.h"
+#include "cqm_bitmap_table.h"
+#include "cqm_bat_cla.h"
+#include "cqm_main.h"
+#include "cqm_object_intern.h"
+
+#define srq_obj_intern_if_section
+
+/**
+ * Prototype : cqm_container_free
+ * Description : Only the container buffer is released. The buffer in the WQE
+ * and fast link tables are not involved.
+ * Containers can be released from head to tail, including head
+ * and tail. This function does not modify the start and
+ * end pointers of qinfo records.
+ * Input : u8 *srq_head_container
+ * u8 *srq_tail_container: If it is NULL, it means to release
+ * container from head to tail.
+ * struct tag_cqm_queue *common
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2016/2/1
+ * Modification : Created function
+ */
+void cqm_container_free(u8 *srq_head_container, u8 *srq_tail_container,
+ struct tag_cqm_queue *common)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(common->object.cqm_handle);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ u32 link_wqe_offset = qinfo->wqe_per_buf * qinfo->wqe_size;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_srq_linkwqe *srq_link_wqe = NULL;
+ u32 container_size = qinfo->container_size;
+ struct pci_dev *dev = cqm_handle->dev;
+ u64 addr;
+ u8 *srqhead_container = srq_head_container;
+ u8 *srqtail_container = srq_tail_container;
+
+ if (unlikely(!srqhead_container)) {
+ pr_err("[CQM]%s: srqhead_container is null\n", __func__);
+ return;
+ }
+
+ /* 1. The range is released cyclically from the head to the tail, i.e.
+ * [head:tail]. If the tail is null, the range is [head:null]. Oterwise,
+ * [head:tail->next).
+ */
+ if (srqtail_container) {
+ /* [head:tail->next): Update srqtail_container to the next
+ * container va.
+ */
+ srq_link_wqe = (struct tag_cqm_srq_linkwqe *)(srqtail_container +
+ link_wqe_offset);
+ /* Only the link wqe part needs to be converted. */
+ cqm_swab32((u8 *)(srq_link_wqe), sizeof(struct tag_cqm_linkwqe) >> CQM_DW_SHIFT);
+ srqtail_container = (u8 *)CQM_ADDR_COMBINE(srq_link_wqe->fixed_next_buffer_addr_h,
+ srq_link_wqe->fixed_next_buffer_addr_l);
+ }
+
+ do {
+ /* 2. Obtain the link wqe of the current container */
+ srq_link_wqe = (struct tag_cqm_srq_linkwqe *)(srqhead_container +
+ link_wqe_offset);
+ /* Only the link wqe part needs to be converted. */
+ cqm_swab32((u8 *)(srq_link_wqe), sizeof(struct tag_cqm_linkwqe) >> CQM_DW_SHIFT);
+ /* Obtain the va of the next container using the link wqe. */
+ srqhead_container = (u8 *)CQM_ADDR_COMBINE(srq_link_wqe->fixed_next_buffer_addr_h,
+ srq_link_wqe->fixed_next_buffer_addr_l);
+
+ /* 3. Obtain the current container pa from the link wqe,
+ * and cancel the mapping
+ */
+ addr = CQM_ADDR_COMBINE(srq_link_wqe->current_buffer_gpa_h,
+ srq_link_wqe->current_buffer_gpa_l);
+ if (addr == 0) {
+ cqm_err(handle->dev_hdl, "Container free: buffer physical addr is null\n");
+ return;
+ }
+ pci_unmap_single(dev, (dma_addr_t)addr, container_size,
+ PCI_DMA_BIDIRECTIONAL);
+
+ /* 4. Obtain the container va through linkwqe and release the
+ * container va.
+ */
+ addr = CQM_ADDR_COMBINE(srq_link_wqe->current_buffer_addr_h,
+ srq_link_wqe->current_buffer_addr_l);
+ if (addr == 0) {
+ cqm_err(handle->dev_hdl, "Container free: buffer virtual addr is null\n");
+ return;
+ }
+ kfree((void *)addr);
+ } while (srqhead_container != srqtail_container);
+}
+
+/**
+ * Prototype : cqm_container_create
+ * Description : Create a container for the RQ or SRQ, link it to the tail of
+ * the queue, and update the tail container pointer of the queue.
+ * Input : struct tag_cqm_object *object
+ * u8 **container_addr
+ * bool link
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2016/2/16
+ * Modification : Created function
+ */
+s32 cqm_container_create(struct tag_cqm_object *object, u8 **container_addr, bool link)
+{
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(object->cqm_handle);
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ u32 link_wqe_offset = qinfo->wqe_per_buf * qinfo->wqe_size;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_srq_linkwqe *srq_link_wqe = NULL;
+ struct tag_cqm_linkwqe *link_wqe = NULL;
+ dma_addr_t new_container_pa;
+ u8 *new_container = NULL;
+
+ /* 1. Applying for Container Space and Initializing Invalid/Normal WQE
+ * of the Container.
+ */
+ new_container = kmalloc(qinfo->container_size, GFP_ATOMIC | __GFP_ZERO);
+ if (!new_container)
+ return CQM_FAIL;
+
+ /* Container PCI mapping */
+ new_container_pa = pci_map_single(cqm_handle->dev, new_container,
+ qinfo->container_size,
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(cqm_handle->dev, new_container_pa) != 0) {
+ cqm_err(handle->dev_hdl, CQM_MAP_FAIL(new_container_pa));
+ goto map_fail;
+ }
+
+ /* 2. The container is linked to the SRQ, and the link wqe of
+ * tail_container and new_container is updated.
+ */
+ /* If the SRQ is not empty, update the linkwqe of the tail container. */
+ if (link) {
+ if (common->tail_container) {
+ srq_link_wqe = (struct tag_cqm_srq_linkwqe *)(common->tail_container +
+ link_wqe_offset);
+ link_wqe = &srq_link_wqe->linkwqe;
+ link_wqe->next_page_gpa_h =
+ __swab32((u32)CQM_ADDR_HI(new_container_pa));
+ link_wqe->next_page_gpa_l =
+ __swab32((u32)CQM_ADDR_LW(new_container_pa));
+ link_wqe->next_buffer_addr_h =
+ __swab32((u32)CQM_ADDR_HI(new_container));
+ link_wqe->next_buffer_addr_l =
+ __swab32((u32)CQM_ADDR_LW(new_container));
+ /* make sure next page gpa and next buffer addr of
+ * link wqe update first
+ */
+ wmb();
+ /* The SRQ tail container may be accessed by the chip.
+ * Therefore, obit must be set to 1 at last.
+ */
+ (*(u32 *)link_wqe) |= 0x80;
+ /* make sure obit set ahead of fixed next buffer addr
+ * updating of srq link wqe
+ */
+ wmb();
+ srq_link_wqe->fixed_next_buffer_addr_h =
+ (u32)CQM_ADDR_HI(new_container);
+ srq_link_wqe->fixed_next_buffer_addr_l =
+ (u32)CQM_ADDR_LW(new_container);
+ }
+ }
+
+ /* Update the Invalid WQE of a New Container */
+ clear_bit(0x1F, (ulong *)new_container);
+ /* Update the link wqe of the new container. */
+ srq_link_wqe = (struct tag_cqm_srq_linkwqe *)(new_container + link_wqe_offset);
+ link_wqe = &srq_link_wqe->linkwqe;
+ link_wqe->o = CQM_LINK_WQE_OWNER_INVALID;
+ link_wqe->ctrlsl = CQM_LINK_WQE_CTRLSL_VALUE;
+ link_wqe->lp = CQM_LINK_WQE_LP_INVALID;
+ link_wqe->wf = CQM_WQE_WF_LINK;
+ srq_link_wqe->current_buffer_gpa_h = CQM_ADDR_HI(new_container_pa);
+ srq_link_wqe->current_buffer_gpa_l = CQM_ADDR_LW(new_container_pa);
+ srq_link_wqe->current_buffer_addr_h = CQM_ADDR_HI(new_container);
+ srq_link_wqe->current_buffer_addr_l = CQM_ADDR_LW(new_container);
+ /* Convert only the area accessed by the chip to the network sequence */
+ cqm_swab32((u8 *)link_wqe, sizeof(struct tag_cqm_linkwqe) >> CQM_DW_SHIFT);
+ if (link)
+ /* Update the tail pointer of a queue. */
+ common->tail_container = new_container;
+ else
+ *container_addr = new_container;
+
+ return CQM_SUCCESS;
+
+map_fail:
+ kfree(new_container);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_srq_container_init
+ * Description : Initialize the SRQ to create all containers and link them.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2016/2/3
+ * Modification : Created function
+ */
+static s32 cqm_srq_container_init(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 container_num = object->object_size;
+ s32 ret;
+ u32 i;
+
+ if (common->head_container || common->tail_container) {
+ cqm_err(handle->dev_hdl, "Srq container init: srq tail/head container not null\n");
+ return CQM_FAIL;
+ }
+
+ /* Applying for a Container
+ * During initialization, the head/tail pointer is null.
+ * After the first application is successful, head=tail.
+ */
+ ret = cqm_container_create(&qinfo->common.object, NULL, true);
+ if (ret == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, "Srq container init: cqm_srq_container_add fail\n");
+ return CQM_FAIL;
+ }
+ common->head_container = common->tail_container;
+
+ /* The container is dynamically created and the tail pointer is updated.
+ * If the container fails to be created, release the containers from
+ * head to null.
+ */
+ for (i = 1; i < container_num; i++) {
+ ret = cqm_container_create(&qinfo->common.object, NULL, true);
+ if (ret == CQM_FAIL) {
+ cqm_container_free(common->head_container, NULL,
+ &qinfo->common);
+ return CQM_FAIL;
+ }
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_share_recv_queue_create
+ * Description : Create SRQ(share receive queue)
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2016/1/27
+ * Modification : Created function
+ */
+s32 cqm_share_recv_queue_create(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_toe_private_capability *toe_own_cap = &cqm_handle->toe_own_capability;
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_bitmap *bitmap = NULL;
+ u32 step;
+ s32 ret;
+
+ /* 1. Create srq container, including initializing the link wqe. */
+ ret = cqm_srq_container_init(object);
+ if (ret == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_srq_container_init));
+ return CQM_FAIL;
+ }
+
+ /* 2. Create srq ctx: SRQ CTX is directly delivered by the driver to the
+ * chip memory area through the cmdq channel, and no CLA table
+ * management is required. Therefore, the CQM applies for only one empty
+ * buffer for the driver.
+ */
+ /* bitmap applies for index */
+ bitmap = &toe_own_cap->srqc_bitmap;
+ qinfo->index_count = (ALIGN(qinfo->q_ctx_size,
+ toe_own_cap->toe_srqc_basic_size)) /
+ toe_own_cap->toe_srqc_basic_size;
+ /* align with 2 as the upper bound */
+ step = ALIGN(toe_own_cap->toe_srqc_number, 2);
+ qinfo->common.index = cqm_bitmap_alloc(bitmap, step, qinfo->index_count,
+ func_cap->xid_alloc_mode);
+ if (qinfo->common.index >= bitmap->max_num) {
+ cqm_err(handle->dev_hdl, "Srq create: queue index %u exceeds max_num %u\n",
+ qinfo->common.index, bitmap->max_num);
+ goto err1;
+ }
+ qinfo->common.index += toe_own_cap->toe_srqc_start_id;
+
+ /* apply for buffer for SRQC */
+ common->q_ctx_vaddr = kmalloc(qinfo->q_ctx_size,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!common->q_ctx_vaddr)
+ goto err2;
+ return CQM_SUCCESS;
+
+err2:
+ cqm_bitmap_free(bitmap,
+ qinfo->common.index - toe_own_cap->toe_srqc_start_id,
+ qinfo->index_count);
+err1:
+ cqm_container_free(common->head_container, common->tail_container,
+ &qinfo->common);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_srq_used_rq_delete
+ * Description : Delete RQ in TOE SRQ mode.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2016/5/19
+ * Modification : Created function
+ */
+static void cqm_srq_used_rq_delete(const struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)(common->object.cqm_handle);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ u32 link_wqe_offset = qinfo->wqe_per_buf * qinfo->wqe_size;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_srq_linkwqe *srq_link_wqe = NULL;
+ dma_addr_t addr;
+
+ /* Currently, the SRQ solution does not support RQ initialization
+ * without mounting container.
+ * As a result, RQ resources are released incorrectly.
+ * Temporary workaround: Only one container is mounted during RQ
+ * initialization and only one container is released
+ * during resource release.
+ */
+ if (unlikely(!common->head_container)) {
+ pr_err("[CQM]%s: Rq del: rq has no contianer to release\n", __func__);
+ return;
+ }
+
+ /* 1. Obtain current container pa from the link wqe table and
+ * cancel the mapping.
+ */
+ srq_link_wqe = (struct tag_cqm_srq_linkwqe *)(common->head_container + link_wqe_offset);
+ /* Only the link wqe part needs to be converted. */
+ cqm_swab32((u8 *)(srq_link_wqe), sizeof(struct tag_cqm_linkwqe) >> CQM_DW_SHIFT);
+
+ addr = CQM_ADDR_COMBINE(srq_link_wqe->current_buffer_gpa_h,
+ srq_link_wqe->current_buffer_gpa_l);
+ if (addr == 0) {
+ cqm_err(handle->dev_hdl, "Rq del: buffer physical addr is null\n");
+ return;
+ }
+ pci_unmap_single(cqm_handle->dev, addr, qinfo->container_size,
+ PCI_DMA_BIDIRECTIONAL);
+
+ /* 2. Obtain the container va through the linkwqe and release. */
+ addr = CQM_ADDR_COMBINE(srq_link_wqe->current_buffer_addr_h,
+ srq_link_wqe->current_buffer_addr_l);
+ if (addr == 0) {
+ cqm_err(handle->dev_hdl, "Rq del: buffer virtual addr is null\n");
+ return;
+ }
+ kfree((void *)addr);
+}
+
+/**
+ * Prototype : cqm_share_recv_queue_delete
+ * Description : The SRQ object is deleted. Delete only containers that are not
+ * used by SRQ, that is, containers from the head to the tail.
+ * The RQ releases containers that have been used by the RQ.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2016/2/2
+ * Modification : Created function
+ */
+void cqm_share_recv_queue_delete(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_bitmap *bitmap = &cqm_handle->toe_own_capability.srqc_bitmap;
+ u32 index = common->index - cqm_handle->toe_own_capability.toe_srqc_start_id;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+
+ /* 1. Wait for completion and ensure that all references to the QPC
+ * are complete.
+ */
+ if (atomic_dec_and_test(&object->refcount) != 0)
+ complete(&object->free);
+ else
+ cqm_err(handle->dev_hdl, "Srq del: object is referred by others, has to wait for completion\n");
+
+ wait_for_completion(&object->free);
+ destroy_completion(&object->free);
+ /* 2. The corresponding index in the bitmap is cleared. */
+ cqm_bitmap_free(bitmap, index, qinfo->index_count);
+
+ /* 3. SRQC resource release */
+ if (unlikely(!common->q_ctx_vaddr)) {
+ pr_err("[CQM]%s: Srq del: srqc kfree, context virtual addr is null\n", __func__);
+ return;
+ }
+ kfree(common->q_ctx_vaddr);
+
+ /* 4. The SRQ queue is released. */
+ cqm_container_free(common->head_container, NULL, &qinfo->common);
+}
+
+#define obj_intern_if_section
+
+#define CQM_INDEX_INVALID_MASK 0x1FFFFFFFU
+#define CQM_IDX_VALID_SHIFT 29
+
+/**
+ * Prototype : cqm_qpc_mpt_bitmap_alloc
+ * Description : Apply for index from the bitmap when creating QPC or MPT.
+ * Input : struct tag_cqm_object *object
+ * struct tag_cqm_cla_table *cla_table
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+static s32 cqm_qpc_mpt_bitmap_alloc(struct tag_cqm_object *object,
+ struct tag_cqm_cla_table *cla_table, bool low2bit_align_en)
+{
+ struct tag_cqm_qpc_mpt *common = container_of(object, struct tag_cqm_qpc_mpt, object);
+ struct tag_cqm_qpc_mpt_info *qpc_mpt_info = container_of(common,
+ struct tag_cqm_qpc_mpt_info,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_func_capability *func_cap = &cqm_handle->func_capability;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_bitmap *bitmap = &cla_table->bitmap;
+ u32 index, count;
+ u32 xid = qpc_mpt_info->common.xid;
+
+ count = (ALIGN(object->object_size, cla_table->obj_size)) / cla_table->obj_size;
+ qpc_mpt_info->index_count = count;
+
+ if ((xid & CQM_INDEX_INVALID_MASK) == CQM_INDEX_INVALID_MASK) {
+ if (low2bit_align_en) {
+ if (count > 1) {
+ cqm_err(handle->dev_hdl, "Not support alloc multiple bits.");
+ return CQM_FAIL;
+ }
+
+ index = cqm_bitmap_alloc_low2bit_align(bitmap, xid >> CQM_IDX_VALID_SHIFT,
+ func_cap->xid_alloc_mode);
+ } else {
+ /* apply for an index normally */
+ index = cqm_bitmap_alloc(bitmap, 1U << (cla_table->z + 1),
+ count, func_cap->xid_alloc_mode);
+ }
+
+ if (index < bitmap->max_num - bitmap->reserved_back) {
+ qpc_mpt_info->common.xid = index;
+ } else {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_bitmap_alloc));
+ return CQM_FAIL;
+ }
+ } else {
+ if ((hinic3_func_type((void *)handle) != TYPE_PPF) &&
+ (hinic3_support_roce((void *)handle, NULL))) {
+ /* If PF is vroce control function, apply for index by xid */
+ index = cqm_bitmap_alloc_by_xid(bitmap, count, xid);
+ } else {
+ /* apply for index to be reserved */
+ index = cqm_bitmap_alloc_reserved(bitmap, count, xid);
+ }
+
+ if (index != xid) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_bitmap_alloc_reserved));
+ return CQM_FAIL;
+ }
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_qpc_mpt_create
+ * Description : Create QPC or MPT
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_qpc_mpt_create(struct tag_cqm_object *object, bool low2bit_align_en)
+{
+ struct tag_cqm_qpc_mpt *common = container_of(object, struct tag_cqm_qpc_mpt, object);
+ struct tag_cqm_qpc_mpt_info *qpc_mpt_info = container_of(common,
+ struct tag_cqm_qpc_mpt_info,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_object_table *object_table = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_bitmap *bitmap = NULL;
+ u32 index, count;
+
+ /* find the corresponding cla table */
+ if (object->object_type == CQM_OBJECT_SERVICE_CTX) {
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_QPC);
+ } else if (object->object_type == CQM_OBJECT_MPT) {
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_MPT);
+ } else {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object->object_type));
+ return CQM_FAIL;
+ }
+
+ if (unlikely(!cla_table)) {
+ pr_err("[CQM]%s: cqm_cla_table_get is null\n", __func__);
+ return CQM_FAIL;
+ }
+
+ /* Bitmap applies for index. */
+ if (cqm_qpc_mpt_bitmap_alloc(object, cla_table, low2bit_align_en) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_qpc_mpt_bitmap_alloc));
+ return CQM_FAIL;
+ }
+
+ bitmap = &cla_table->bitmap;
+ index = qpc_mpt_info->common.xid;
+ count = qpc_mpt_info->index_count;
+
+ /* Find the trunk page from the BAT/CLA and allocate the buffer.
+ * Ensure that the released buffer has been cleared.
+ */
+ if (cla_table->alloc_static)
+ qpc_mpt_info->common.vaddr = cqm_cla_get_unlock(cqm_handle,
+ cla_table,
+ index, count,
+ &common->paddr);
+ else
+ qpc_mpt_info->common.vaddr = cqm_cla_get_lock(cqm_handle,
+ cla_table, index,
+ count,
+ &common->paddr);
+
+ if (!qpc_mpt_info->common.vaddr) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_cla_get_lock));
+ cqm_err(handle->dev_hdl, "Qpc mpt init: qpc mpt vaddr is null, cla_table->alloc_static=%d\n",
+ cla_table->alloc_static);
+ goto err1;
+ }
+
+ /* Indexes are associated with objects, and FC is executed
+ * in the interrupt context.
+ */
+ object_table = &cla_table->obj_table;
+ if (object->service_type == CQM_SERVICE_T_FC) {
+ if (cqm_object_table_insert(cqm_handle, object_table, index,
+ object, false) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_object_table_insert));
+ goto err2;
+ }
+ } else {
+ if (cqm_object_table_insert(cqm_handle, object_table, index,
+ object, true) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_object_table_insert));
+ goto err2;
+ }
+ }
+
+ return CQM_SUCCESS;
+
+err2:
+ cqm_cla_put(cqm_handle, cla_table, index, count);
+err1:
+ cqm_bitmap_free(bitmap, index, count);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_qpc_mpt_delete
+ * Description : Delete QPC or MPT.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_qpc_mpt_delete(struct tag_cqm_object *object)
+{
+ struct tag_cqm_qpc_mpt *common = container_of(object, struct tag_cqm_qpc_mpt, object);
+ struct tag_cqm_qpc_mpt_info *qpc_mpt_info = container_of(common,
+ struct tag_cqm_qpc_mpt_info,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_object_table *object_table = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ u32 count = qpc_mpt_info->index_count;
+ u32 index = qpc_mpt_info->common.xid;
+ struct tag_cqm_bitmap *bitmap = NULL;
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_qpc_mpt_delete_cnt);
+
+ /* find the corresponding cla table */
+ /* Todo */
+ if (object->object_type == CQM_OBJECT_SERVICE_CTX) {
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_QPC);
+ } else if (object->object_type == CQM_OBJECT_MPT) {
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_MPT);
+ } else {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(object->object_type));
+ return;
+ }
+
+ if (unlikely(!cla_table)) {
+ pr_err("[CQM]%s: cqm_cla_table_get_qpc return failure\n", __func__);
+ return;
+ }
+
+ /* disassociate index and object */
+ object_table = &cla_table->obj_table;
+ if (object->service_type == CQM_SERVICE_T_FC)
+ cqm_object_table_remove(cqm_handle, object_table, index, object,
+ false);
+ else
+ cqm_object_table_remove(cqm_handle, object_table, index, object,
+ true);
+
+ /* wait for completion to ensure that all references to
+ * the QPC are complete
+ */
+ if (atomic_dec_and_test(&object->refcount) != 0)
+ complete(&object->free);
+ else
+ cqm_err(handle->dev_hdl, "Qpc mpt del: object is referred by others, has to wait for completion\n");
+
+ /* Static QPC allocation must be non-blocking.
+ * Services ensure that the QPC is referenced
+ * when the QPC is deleted.
+ */
+ if (!cla_table->alloc_static)
+ wait_for_completion(&object->free);
+
+ /* VMware FC need explicitly deinit spin_lock in completion */
+ destroy_completion(&object->free);
+
+ /* release qpc buffer */
+ cqm_cla_put(cqm_handle, cla_table, index, count);
+
+ /* release the index to the bitmap */
+ bitmap = &cla_table->bitmap;
+ cqm_bitmap_free(bitmap, index, count);
+}
+
+/**
+ * Prototype : cqm_linkwqe_fill
+ * Description : Used to organize the queue buffer of non-RDMA services and
+ * fill the link wqe.
+ * Input : wqe_per_buf: Linkwqe is not included.
+ * wqe_number: Linkwqe is not included.
+ * tail: true - The linkwqe must be at the end of the page;
+ * false - The linkwqe can be not at the end of the page.
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/6/15
+ * Modification : Created function
+ */
+static void cqm_linkwqe_fill(struct tag_cqm_buf *buf, u32 wqe_per_buf, u32 wqe_size,
+ u32 wqe_number, bool tail, u8 link_mode)
+{
+ struct tag_cqm_linkwqe_128B *linkwqe = NULL;
+ struct tag_cqm_linkwqe *wqe = NULL;
+ dma_addr_t addr;
+ u8 *tmp = NULL;
+ u8 *va = NULL;
+ u32 i;
+
+ /* The linkwqe of other buffer except the last buffer
+ * is directly filled to the tail.
+ */
+ for (i = 0; i < buf->buf_number; i++) {
+ va = (u8 *)(buf->buf_list[i].va);
+
+ if (i != (buf->buf_number - 1)) {
+ wqe = (struct tag_cqm_linkwqe *)(va + (u32)(wqe_size * wqe_per_buf));
+ wqe->wf = CQM_WQE_WF_LINK;
+ wqe->ctrlsl = CQM_LINK_WQE_CTRLSL_VALUE;
+ wqe->lp = CQM_LINK_WQE_LP_INVALID;
+ /* The valid value of link wqe needs to be set to 1.
+ * Each service ensures that o-bit=1 indicates that
+ * link wqe is valid and o-bit=0 indicates that
+ * link wqe is invalid.
+ */
+ wqe->o = CQM_LINK_WQE_OWNER_VALID;
+ addr = buf->buf_list[(u32)(i + 1)].pa;
+ wqe->next_page_gpa_h = CQM_ADDR_HI(addr);
+ wqe->next_page_gpa_l = CQM_ADDR_LW(addr);
+ } else { /* linkwqe special padding of the last buffer */
+ if (tail) {
+ /* must be filled at the end of the page */
+ tmp = va + (u32)(wqe_size * wqe_per_buf);
+ wqe = (struct tag_cqm_linkwqe *)tmp;
+ } else {
+ /* The last linkwqe is filled
+ * following the last wqe.
+ */
+ tmp = va + (u32)(wqe_size * (wqe_number - wqe_per_buf *
+ (buf->buf_number - 1)));
+ wqe = (struct tag_cqm_linkwqe *)tmp;
+ }
+ wqe->wf = CQM_WQE_WF_LINK;
+ wqe->ctrlsl = CQM_LINK_WQE_CTRLSL_VALUE;
+
+ /* In link mode, the last link WQE is invalid;
+ * In ring mode, the last link wqe is valid, pointing to
+ * the home page, and the lp is set.
+ */
+ if (link_mode == CQM_QUEUE_LINK_MODE) {
+ wqe->o = CQM_LINK_WQE_OWNER_INVALID;
+ } else {
+ /* The lp field of the last link_wqe is set to
+ * 1, indicating that the meaning of the o-bit
+ * is reversed.
+ */
+ wqe->lp = CQM_LINK_WQE_LP_VALID;
+ wqe->o = CQM_LINK_WQE_OWNER_VALID;
+ addr = buf->buf_list[0].pa;
+ wqe->next_page_gpa_h = CQM_ADDR_HI(addr);
+ wqe->next_page_gpa_l = CQM_ADDR_LW(addr);
+ }
+ }
+
+ if (wqe_size == CQM_LINKWQE_128B) {
+ /* After the B800 version, the WQE obit scheme is
+ * changed. The 64B bits before and after the 128B WQE
+ * need to be assigned a value:
+ * ifoe the 63rd bit from the end of the last 64B is
+ * obit;
+ * toe the 157th bit from the end of the last 64B is
+ * obit.
+ */
+ linkwqe = (struct tag_cqm_linkwqe_128B *)wqe;
+ linkwqe->second64B.third_16B.bs.toe_o = CQM_LINK_WQE_OWNER_VALID;
+ linkwqe->second64B.forth_16B.bs.ifoe_o = CQM_LINK_WQE_OWNER_VALID;
+
+ /* shift 2 bits by right to get length of dw(4B) */
+ cqm_swab32((u8 *)wqe, sizeof(struct tag_cqm_linkwqe_128B) >> 2);
+ } else {
+ /* shift 2 bits by right to get length of dw(4B) */
+ cqm_swab32((u8 *)wqe, sizeof(struct tag_cqm_linkwqe) >> 2);
+ }
+ }
+}
+
+static int cqm_nonrdma_queue_ctx_create_scq(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_object_table *object_table = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_bitmap *bitmap = NULL;
+ bool bh = false;
+
+ /* find the corresponding cla table */
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_SCQC);
+ if (!cla_table) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(nonrdma_cqm_cla_table_get));
+ return CQM_FAIL;
+ }
+
+ /* bitmap applies for index */
+ bitmap = &cla_table->bitmap;
+ qinfo->index_count = (ALIGN(qinfo->q_ctx_size, cla_table->obj_size)) / cla_table->obj_size;
+ qinfo->common.index = cqm_bitmap_alloc(bitmap, 1U << (cla_table->z + 1),
+ qinfo->index_count,
+ cqm_handle->func_capability.xid_alloc_mode);
+ if (qinfo->common.index >= bitmap->max_num) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(nonrdma_cqm_bitmap_alloc));
+ return CQM_FAIL;
+ }
+
+ /* find the trunk page from BAT/CLA and allocate the buffer */
+ common->q_ctx_vaddr = cqm_cla_get_lock(cqm_handle, cla_table, qinfo->common.index,
+ qinfo->index_count, &common->q_ctx_paddr);
+ if (!common->q_ctx_vaddr) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(nonrdma_cqm_cla_get_lock));
+ cqm_bitmap_free(bitmap, qinfo->common.index, qinfo->index_count);
+ return CQM_FAIL;
+ }
+
+ /* index and object association */
+ object_table = &cla_table->obj_table;
+ bh = ((object->service_type == CQM_SERVICE_T_FC) ? false : true);
+ if (cqm_object_table_insert(cqm_handle, object_table, qinfo->common.index, object,
+ bh) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(nonrdma_cqm_object_table_insert));
+ cqm_cla_put(cqm_handle, cla_table, qinfo->common.index, qinfo->index_count);
+ cqm_bitmap_free(bitmap, qinfo->common.index, qinfo->index_count);
+
+ return CQM_FAIL;
+ }
+
+ return 0;
+}
+
+static s32 cqm_nonrdma_queue_ctx_create(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ s32 shift;
+ int ret;
+
+ if (object->object_type == CQM_OBJECT_NONRDMA_SRQ) {
+ shift = cqm_shift(qinfo->q_ctx_size);
+ common->q_ctx_vaddr = cqm_kmalloc_align(qinfo->q_ctx_size,
+ GFP_KERNEL | __GFP_ZERO,
+ (u16)shift);
+ if (!common->q_ctx_vaddr)
+ return CQM_FAIL;
+
+ common->q_ctx_paddr = pci_map_single(cqm_handle->dev, common->q_ctx_vaddr,
+ qinfo->q_ctx_size, PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(cqm_handle->dev, common->q_ctx_paddr) != 0) {
+ cqm_err(handle->dev_hdl, CQM_MAP_FAIL(q_ctx_vaddr));
+ cqm_kfree_align(common->q_ctx_vaddr);
+ common->q_ctx_vaddr = NULL;
+ return CQM_FAIL;
+ }
+ } else if (object->object_type == CQM_OBJECT_NONRDMA_SCQ) {
+ ret = cqm_nonrdma_queue_ctx_create_scq(object);
+ if (ret != 0)
+ return ret;
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_nonrdma_queue_create
+ * Description : Create a queue for non-RDMA services.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_nonrdma_queue_create(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_service *service = cqm_handle->service + object->service_type;
+ struct tag_cqm_buf *q_room_buf = &common->q_room_buf_1;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ u32 wqe_number = qinfo->common.object.object_size;
+ u32 wqe_size = qinfo->wqe_size;
+ u32 order = service->buf_order;
+ u32 buf_number, buf_size;
+ bool tail = false; /* determine whether the linkwqe is at the end of the page */
+
+ /* When creating a CQ/SCQ queue, the page size is 4 KB,
+ * the linkwqe must be at the end of the page.
+ */
+ if (object->object_type == CQM_OBJECT_NONRDMA_EMBEDDED_CQ ||
+ object->object_type == CQM_OBJECT_NONRDMA_SCQ) {
+ /* depth: 2^n-aligned; depth range: 256-32 K */
+ if (wqe_number < CQM_CQ_DEPTH_MIN ||
+ wqe_number > CQM_CQ_DEPTH_MAX) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(wqe_number));
+ return CQM_FAIL;
+ }
+ if (!cqm_check_align(wqe_number)) {
+ cqm_err(handle->dev_hdl, "Nonrdma queue alloc: wqe_number is not align on 2^n\n");
+ return CQM_FAIL;
+ }
+
+ order = CQM_4K_PAGE_ORDER; /* wqe page 4k */
+ tail = true; /* The linkwqe must be at the end of the page. */
+ buf_size = CQM_4K_PAGE_SIZE;
+ } else {
+ buf_size = (u32)(PAGE_SIZE << order);
+ }
+
+ /* Calculate the total number of buffers required,
+ * -1 indicates that the link wqe in a buffer is deducted.
+ */
+ qinfo->wqe_per_buf = (buf_size / wqe_size) - 1;
+ /* number of linkwqes that are included in the depth transferred
+ * by the service
+ */
+ buf_number = ALIGN((wqe_size * wqe_number), buf_size) / buf_size;
+
+ /* apply for buffer */
+ q_room_buf->buf_number = buf_number;
+ q_room_buf->buf_size = buf_size;
+ q_room_buf->page_number = buf_number << order;
+ if (cqm_buf_alloc(cqm_handle, q_room_buf, false) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(cqm_buf_alloc));
+ return CQM_FAIL;
+ }
+ /* fill link wqe, wqe_number - buf_number is the number of wqe without
+ * link wqe
+ */
+ cqm_linkwqe_fill(q_room_buf, qinfo->wqe_per_buf, wqe_size,
+ wqe_number - buf_number, tail,
+ common->queue_link_mode);
+
+ /* create queue header */
+ qinfo->common.q_header_vaddr = cqm_kmalloc_align(sizeof(struct tag_cqm_queue_header),
+ GFP_KERNEL | __GFP_ZERO,
+ CQM_QHEAD_ALIGN_ORDER);
+ if (!qinfo->common.q_header_vaddr)
+ goto err1;
+
+ common->q_header_paddr = pci_map_single(cqm_handle->dev,
+ qinfo->common.q_header_vaddr,
+ sizeof(struct tag_cqm_queue_header),
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(cqm_handle->dev, common->q_header_paddr) != 0) {
+ cqm_err(handle->dev_hdl, CQM_MAP_FAIL(q_header_vaddr));
+ goto err2;
+ }
+
+ /* create queue ctx */
+ if (cqm_nonrdma_queue_ctx_create(object) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_nonrdma_queue_ctx_create));
+ goto err3;
+ }
+
+ return CQM_SUCCESS;
+
+err3:
+ pci_unmap_single(cqm_handle->dev, common->q_header_paddr,
+ sizeof(struct tag_cqm_queue_header), PCI_DMA_BIDIRECTIONAL);
+err2:
+ cqm_kfree_align(qinfo->common.q_header_vaddr);
+ qinfo->common.q_header_vaddr = NULL;
+err1:
+ cqm_buf_free(q_room_buf, cqm_handle);
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_nonrdma_queue_delete
+ * Description : Delete the queues of non-RDMA services.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_nonrdma_queue_delete(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_nonrdma_qinfo *qinfo = container_of(common, struct tag_cqm_nonrdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct tag_cqm_buf *q_room_buf = &common->q_room_buf_1;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_object_table *object_table = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_bitmap *bitmap = NULL;
+ u32 index = qinfo->common.index;
+ u32 count = qinfo->index_count;
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_nonrdma_queue_delete_cnt);
+
+ /* The SCQ has an independent SCQN association. */
+ if (object->object_type == CQM_OBJECT_NONRDMA_SCQ) {
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_SCQC);
+ if (unlikely(!cla_table)) {
+ pr_err("[CQM]%s: cqm_cla_table_get_queue return failure\n", __func__);
+ return;
+ }
+
+ /* disassociate index and object */
+ object_table = &cla_table->obj_table;
+ if (object->service_type == CQM_SERVICE_T_FC)
+ cqm_object_table_remove(cqm_handle, object_table, index,
+ object, false);
+ else
+ cqm_object_table_remove(cqm_handle, object_table, index,
+ object, true);
+ }
+
+ /* wait for completion to ensure that all references to
+ * the QPC are complete
+ */
+ if (atomic_dec_and_test(&object->refcount) != 0)
+ complete(&object->free);
+ else
+ cqm_err(handle->dev_hdl, "Nonrdma queue del: object is referred by others, has to wait for completion\n");
+
+ wait_for_completion(&object->free);
+ destroy_completion(&object->free);
+
+ /* If the q header exists, release. */
+ if (qinfo->common.q_header_vaddr) {
+ pci_unmap_single(cqm_handle->dev, common->q_header_paddr,
+ sizeof(struct tag_cqm_queue_header),
+ PCI_DMA_BIDIRECTIONAL);
+
+ cqm_kfree_align(qinfo->common.q_header_vaddr);
+ qinfo->common.q_header_vaddr = NULL;
+ }
+
+ /* RQ deletion in TOE SRQ mode */
+ if (common->queue_link_mode == CQM_QUEUE_TOE_SRQ_LINK_MODE) {
+ cqm_dbg("Nonrdma queue del: delete srq used rq\n");
+ cqm_srq_used_rq_delete(&common->object);
+ } else {
+ /* If q room exists, release. */
+ cqm_buf_free(q_room_buf, cqm_handle);
+ }
+ /* SRQ and SCQ have independent CTXs and release. */
+ if (object->object_type == CQM_OBJECT_NONRDMA_SRQ) {
+ /* The CTX of the SRQ of the nordma is
+ * applied for independently.
+ */
+ if (common->q_ctx_vaddr) {
+ pci_unmap_single(cqm_handle->dev, common->q_ctx_paddr,
+ qinfo->q_ctx_size,
+ PCI_DMA_BIDIRECTIONAL);
+
+ cqm_kfree_align(common->q_ctx_vaddr);
+ common->q_ctx_vaddr = NULL;
+ }
+ } else if (object->object_type == CQM_OBJECT_NONRDMA_SCQ) {
+ /* The CTX of the SCQ of the nordma is managed by BAT/CLA. */
+ cqm_cla_put(cqm_handle, cla_table, index, count);
+
+ /* release the index to the bitmap */
+ bitmap = &cla_table->bitmap;
+ cqm_bitmap_free(bitmap, index, count);
+ }
+}
+
+static s32 cqm_rdma_queue_ctx_create(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_rdma_qinfo *qinfo = container_of(common, struct tag_cqm_rdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_object_table *object_table = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_bitmap *bitmap = NULL;
+ u32 index;
+
+ if (object->object_type == CQM_OBJECT_RDMA_SRQ ||
+ object->object_type == CQM_OBJECT_RDMA_SCQ) {
+ if (object->object_type == CQM_OBJECT_RDMA_SRQ)
+ cla_table = cqm_cla_table_get(bat_table,
+ CQM_BAT_ENTRY_T_SRQC);
+ else
+ cla_table = cqm_cla_table_get(bat_table,
+ CQM_BAT_ENTRY_T_SCQC);
+
+ if (!cla_table) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(rdma_cqm_cla_table_get));
+ return CQM_FAIL;
+ }
+
+ /* bitmap applies for index */
+ bitmap = &cla_table->bitmap;
+ if (qinfo->common.index == CQM_INDEX_INVALID) {
+ qinfo->index_count = (ALIGN(qinfo->q_ctx_size,
+ cla_table->obj_size)) /
+ cla_table->obj_size;
+ qinfo->common.index =
+ cqm_bitmap_alloc(bitmap, 1U << (cla_table->z + 1),
+ qinfo->index_count,
+ cqm_handle->func_capability.xid_alloc_mode);
+ if (qinfo->common.index >= bitmap->max_num) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(rdma_cqm_bitmap_alloc));
+ return CQM_FAIL;
+ }
+ } else {
+ /* apply for reserved index */
+ qinfo->index_count = (ALIGN(qinfo->q_ctx_size, cla_table->obj_size)) /
+ cla_table->obj_size;
+ index = cqm_bitmap_alloc_reserved(bitmap, qinfo->index_count,
+ qinfo->common.index);
+ if (index != qinfo->common.index) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_bitmap_alloc_reserved));
+ return CQM_FAIL;
+ }
+ }
+
+ /* find the trunk page from BAT/CLA and allocate the buffer */
+ qinfo->common.q_ctx_vaddr =
+ cqm_cla_get_lock(cqm_handle, cla_table, qinfo->common.index,
+ qinfo->index_count, &qinfo->common.q_ctx_paddr);
+ if (!qinfo->common.q_ctx_vaddr) {
+ cqm_err(handle->dev_hdl, CQM_FUNCTION_FAIL(rdma_cqm_cla_get_lock));
+ cqm_bitmap_free(bitmap, qinfo->common.index, qinfo->index_count);
+ return CQM_FAIL;
+ }
+
+ /* associate index and object */
+ object_table = &cla_table->obj_table;
+ if (cqm_object_table_insert(cqm_handle, object_table, qinfo->common.index, object,
+ true) != CQM_SUCCESS) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(rdma_cqm_object_table_insert));
+ cqm_cla_put(cqm_handle, cla_table, qinfo->common.index,
+ qinfo->index_count);
+ cqm_bitmap_free(bitmap, qinfo->common.index, qinfo->index_count);
+ return CQM_FAIL;
+ }
+ }
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_rdma_queue_create
+ * Description : Create rdma queue.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_rdma_queue_create(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_rdma_qinfo *qinfo = container_of(common, struct tag_cqm_rdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_service *service = cqm_handle->service + object->service_type;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_buf *q_room_buf = NULL;
+ u32 order = service->buf_order;
+ u32 buf_size = (u32)(PAGE_SIZE << order);
+
+ if (qinfo->room_header_alloc) {
+ /* apply for queue room buffer */
+ if (qinfo->common.current_q_room == CQM_RDMA_Q_ROOM_1)
+ q_room_buf = &qinfo->common.q_room_buf_1;
+ else
+ q_room_buf = &qinfo->common.q_room_buf_2;
+
+ q_room_buf->buf_number = ALIGN(object->object_size, buf_size) /
+ buf_size;
+ q_room_buf->page_number = (q_room_buf->buf_number << order);
+ q_room_buf->buf_size = buf_size;
+ if (cqm_buf_alloc(cqm_handle, q_room_buf, true) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_buf_alloc));
+ return CQM_FAIL;
+ }
+
+ /* queue header */
+ qinfo->common.q_header_vaddr =
+ cqm_kmalloc_align(sizeof(struct tag_cqm_queue_header),
+ GFP_KERNEL | __GFP_ZERO,
+ CQM_QHEAD_ALIGN_ORDER);
+ if (!qinfo->common.q_header_vaddr)
+ goto err1;
+
+ qinfo->common.q_header_paddr =
+ pci_map_single(cqm_handle->dev,
+ qinfo->common.q_header_vaddr,
+ sizeof(struct tag_cqm_queue_header),
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(cqm_handle->dev,
+ qinfo->common.q_header_paddr) != 0) {
+ cqm_err(handle->dev_hdl, CQM_MAP_FAIL(q_header_vaddr));
+ goto err2;
+ }
+ }
+
+ /* queue ctx */
+ if (cqm_rdma_queue_ctx_create(object) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_rdma_queue_ctx_create));
+ goto err3;
+ }
+
+ return CQM_SUCCESS;
+
+err3:
+ if (qinfo->room_header_alloc)
+ pci_unmap_single(cqm_handle->dev, qinfo->common.q_header_paddr,
+ sizeof(struct tag_cqm_queue_header),
+ PCI_DMA_BIDIRECTIONAL);
+err2:
+ if (qinfo->room_header_alloc) {
+ cqm_kfree_align(qinfo->common.q_header_vaddr);
+ qinfo->common.q_header_vaddr = NULL;
+ }
+err1:
+ if (qinfo->room_header_alloc)
+ cqm_buf_free(q_room_buf, cqm_handle);
+
+ return CQM_FAIL;
+}
+
+/**
+ * Prototype : cqm_rdma_queue_delete
+ * Description : Create rdma queue.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_rdma_queue_delete(struct tag_cqm_object *object)
+{
+ struct tag_cqm_queue *common = container_of(object, struct tag_cqm_queue, object);
+ struct tag_cqm_rdma_qinfo *qinfo = container_of(common, struct tag_cqm_rdma_qinfo,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct tag_cqm_bat_table *bat_table = &cqm_handle->bat_table;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_object_table *object_table = NULL;
+ struct tag_cqm_cla_table *cla_table = NULL;
+ struct tag_cqm_buf *q_room_buf = NULL;
+ struct tag_cqm_bitmap *bitmap = NULL;
+ u32 index = qinfo->common.index;
+ u32 count = qinfo->index_count;
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_rdma_queue_delete_cnt);
+
+ if (qinfo->common.current_q_room == CQM_RDMA_Q_ROOM_1)
+ q_room_buf = &qinfo->common.q_room_buf_1;
+ else
+ q_room_buf = &qinfo->common.q_room_buf_2;
+
+ /* SCQ and SRQ are associated with independent SCQN and SRQN. */
+ if (object->object_type == CQM_OBJECT_RDMA_SCQ) {
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_SCQC);
+ if (unlikely(!cla_table)) {
+ pr_err("[CQM]%s: cqm_cla_table_get return failure\n", __func__);
+ return;
+ }
+ /* disassociate index and object */
+ object_table = &cla_table->obj_table;
+ cqm_object_table_remove(cqm_handle, object_table, index, object, true);
+ } else if (object->object_type == CQM_OBJECT_RDMA_SRQ) {
+ cla_table = cqm_cla_table_get(bat_table, CQM_BAT_ENTRY_T_SRQC);
+ if (unlikely(!cla_table)) {
+ pr_err("[CQM]%s: cqm_cla_table_get return failure\n", __func__);
+ return;
+ }
+ /* disassociate index and object */
+ object_table = &cla_table->obj_table;
+ cqm_object_table_remove(cqm_handle, object_table, index, object, true);
+ }
+
+ /* wait for completion to make sure all references are complete */
+ if (atomic_dec_and_test(&object->refcount) != 0)
+ complete(&object->free);
+ else
+ cqm_err(handle->dev_hdl, "Rdma queue del: object is referred by others, has to wait for completion\n");
+
+ wait_for_completion(&object->free);
+ destroy_completion(&object->free);
+
+ /* If the q header exists, release. */
+ if (qinfo->room_header_alloc && qinfo->common.q_header_vaddr) {
+ pci_unmap_single(cqm_handle->dev, qinfo->common.q_header_paddr,
+ sizeof(struct tag_cqm_queue_header), PCI_DMA_BIDIRECTIONAL);
+
+ cqm_kfree_align(qinfo->common.q_header_vaddr);
+ qinfo->common.q_header_vaddr = NULL;
+ }
+
+ /* If q room exists, release. */
+ cqm_buf_free(q_room_buf, cqm_handle);
+
+ /* SRQ and SCQ have independent CTX, released. */
+ if (object->object_type == CQM_OBJECT_RDMA_SRQ ||
+ object->object_type == CQM_OBJECT_RDMA_SCQ) {
+ cqm_cla_put(cqm_handle, cla_table, index, count);
+
+ /* release the index to the bitmap */
+ bitmap = &cla_table->bitmap;
+ cqm_bitmap_free(bitmap, index, count);
+ }
+}
+
+/**
+ * Prototype : cqm_rdma_table_create
+ * Description : Create RDMA-related entries.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : s32
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+s32 cqm_rdma_table_create(struct tag_cqm_object *object)
+{
+ struct tag_cqm_mtt_rdmarc *common = container_of(object, struct tag_cqm_mtt_rdmarc,
+ object);
+ struct tag_cqm_rdma_table *rdma_table = container_of(common, struct tag_cqm_rdma_table,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_buf *buf = &rdma_table->buf;
+
+ /* Less than one page is allocated by actual size.
+ * RDMARC also requires physical continuity.
+ */
+ if (object->object_size <= PAGE_SIZE ||
+ object->object_type == CQM_OBJECT_RDMARC) {
+ buf->buf_number = 1;
+ buf->page_number = buf->buf_number;
+ buf->buf_size = object->object_size;
+ buf->direct.va = pci_alloc_consistent(cqm_handle->dev,
+ buf->buf_size,
+ &buf->direct.pa);
+ if (!buf->direct.va)
+ return CQM_FAIL;
+ } else { /* page-by-page alignment greater than one page */
+ buf->buf_number = ALIGN(object->object_size, PAGE_SIZE) /
+ PAGE_SIZE;
+ buf->page_number = buf->buf_number;
+ buf->buf_size = PAGE_SIZE;
+ if (cqm_buf_alloc(cqm_handle, buf, true) == CQM_FAIL) {
+ cqm_err(handle->dev_hdl,
+ CQM_FUNCTION_FAIL(cqm_buf_alloc));
+ return CQM_FAIL;
+ }
+ }
+
+ rdma_table->common.vaddr = (u8 *)(buf->direct.va);
+
+ return CQM_SUCCESS;
+}
+
+/**
+ * Prototype : cqm_rdma_table_create
+ * Description : Delete RDMA-related Entries.
+ * Input : struct tag_cqm_object *object
+ * Output : None
+ * Return Value : void
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+void cqm_rdma_table_delete(struct tag_cqm_object *object)
+{
+ struct tag_cqm_mtt_rdmarc *common = container_of(object, struct tag_cqm_mtt_rdmarc,
+ object);
+ struct tag_cqm_rdma_table *rdma_table = container_of(common, struct tag_cqm_rdma_table,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_buf *buf = &rdma_table->buf;
+
+ atomic_inc(&handle->hw_stats.cqm_stats.cqm_rdma_table_delete_cnt);
+
+ if (buf->buf_number == 1) {
+ if (buf->direct.va) {
+ pci_free_consistent(cqm_handle->dev, buf->buf_size,
+ buf->direct.va, buf->direct.pa);
+ buf->direct.va = NULL;
+ }
+ } else {
+ cqm_buf_free(buf, cqm_handle);
+ }
+}
+
+/**
+ * Prototype : cqm_rdma_table_offset_addr
+ * Description : Obtain the address of the RDMA entry based on the offset.
+ * The offset is the index.
+ * Input : struct tag_cqm_object *object
+ * u32 offset
+ * dma_addr_t *paddr
+ * Output : None
+ * Return Value : u8 *
+ * 1.Date : 2015/4/15
+ * Modification : Created function
+ */
+u8 *cqm_rdma_table_offset_addr(struct tag_cqm_object *object, u32 offset, dma_addr_t *paddr)
+{
+ struct tag_cqm_mtt_rdmarc *common = container_of(object, struct tag_cqm_mtt_rdmarc,
+ object);
+ struct tag_cqm_rdma_table *rdma_table = container_of(common, struct tag_cqm_rdma_table,
+ common);
+ struct tag_cqm_handle *cqm_handle = (struct tag_cqm_handle *)object->cqm_handle;
+ struct hinic3_hwdev *handle = cqm_handle->ex_handle;
+ struct tag_cqm_buf *buf = &rdma_table->buf;
+ struct tag_cqm_buf_list *buf_node = NULL;
+ u32 buf_id, buf_offset;
+
+ if (offset < rdma_table->common.index_base ||
+ ((offset - rdma_table->common.index_base) >=
+ rdma_table->common.index_number)) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(offset));
+ return NULL;
+ }
+
+ if (buf->buf_number == 1) {
+ buf_offset = (u32)((offset - rdma_table->common.index_base) *
+ (sizeof(dma_addr_t)));
+
+ *paddr = buf->direct.pa + buf_offset;
+ return ((u8 *)(buf->direct.va)) + buf_offset;
+ }
+
+ buf_id = (offset - rdma_table->common.index_base) /
+ (PAGE_SIZE / sizeof(dma_addr_t));
+ buf_offset = (u32)((offset - rdma_table->common.index_base) -
+ (buf_id * (PAGE_SIZE / sizeof(dma_addr_t))));
+ buf_offset = (u32)(buf_offset * sizeof(dma_addr_t));
+
+ if (buf_id >= buf->buf_number) {
+ cqm_err(handle->dev_hdl, CQM_WRONG_VALUE(buf_id));
+ return NULL;
+ }
+ buf_node = buf->buf_list + buf_id;
+ *paddr = buf_node->pa + buf_offset;
+
+ return ((u8 *)(buf->direct.va)) +
+ (offset - rdma_table->common.index_base) * (sizeof(dma_addr_t));
+}
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object_intern.h b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object_intern.h
new file mode 100644
index 0000000000000..f82fda283d024
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/cqm_object_intern.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_OBJECT_INTERN_H
+#define CQM_OBJECT_INTERN_H
+
+#include "ossl_knl.h"
+#include "cqm_object.h"
+
+#define CQM_CQ_DEPTH_MAX 32768
+#define CQM_CQ_DEPTH_MIN 256
+
+/* linkwqe */
+#define CQM_LINK_WQE_CTRLSL_VALUE 2
+#define CQM_LINK_WQE_LP_VALID 1
+#define CQM_LINK_WQE_LP_INVALID 0
+#define CQM_LINK_WQE_OWNER_VALID 1
+#define CQM_LINK_WQE_OWNER_INVALID 0
+
+#define CQM_ADDR_COMBINE(high_addr, low_addr) \
+ ((((dma_addr_t)(high_addr)) << 32) + ((dma_addr_t)(low_addr)))
+#define CQM_ADDR_HI(addr) ((u32)((u64)(addr) >> 32))
+#define CQM_ADDR_LW(addr) ((u32)((u64)(addr) & 0xffffffff))
+
+#define CQM_QPC_LAYOUT_TABLE_SIZE 16
+struct tag_cqm_qpc_layout_table_node {
+ u32 type;
+ u32 size;
+ u32 offset;
+ struct tag_cqm_object *object;
+};
+
+struct tag_cqm_qpc_mpt_info {
+ struct tag_cqm_qpc_mpt common;
+ /* Different service has different QPC.
+ * The large QPC/mpt will occupy some continuous indexes in bitmap.
+ */
+ u32 index_count;
+ struct tag_cqm_qpc_layout_table_node qpc_layout_table[CQM_QPC_LAYOUT_TABLE_SIZE];
+};
+
+struct tag_cqm_nonrdma_qinfo {
+ struct tag_cqm_queue common;
+ u32 wqe_size;
+ /* Number of WQEs in each buffer (excluding link WQEs)
+ * For SRQ, the value is the number of WQEs contained in a container.
+ */
+ u32 wqe_per_buf;
+ u32 q_ctx_size;
+ /* When different services use CTXs of different sizes,
+ * a large CTX occupies multiple consecutive indexes in the bitmap.
+ */
+ u32 index_count;
+
+ /* add for srq */
+ u32 container_size;
+};
+
+struct tag_cqm_rdma_qinfo {
+ struct tag_cqm_queue common;
+ bool room_header_alloc;
+ /* This field is used to temporarily record the new object_size during
+ * CQ resize.
+ */
+ u32 new_object_size;
+ u32 q_ctx_size;
+ /* When different services use CTXs of different sizes,
+ * a large CTX occupies multiple consecutive indexes in the bitmap.
+ */
+ u32 index_count;
+};
+
+struct tag_cqm_rdma_table {
+ struct tag_cqm_mtt_rdmarc common;
+ struct tag_cqm_buf buf;
+};
+
+void cqm_container_free(u8 *srq_head_container, u8 *srq_tail_container,
+ struct tag_cqm_queue *common);
+s32 cqm_container_create(struct tag_cqm_object *object, u8 **container_addr, bool link);
+s32 cqm_share_recv_queue_create(struct tag_cqm_object *object);
+void cqm_share_recv_queue_delete(struct tag_cqm_object *object);
+s32 cqm_qpc_mpt_create(struct tag_cqm_object *object, bool low2bit_align_en);
+void cqm_qpc_mpt_delete(struct tag_cqm_object *object);
+s32 cqm_nonrdma_queue_create(struct tag_cqm_object *object);
+void cqm_nonrdma_queue_delete(struct tag_cqm_object *object);
+s32 cqm_rdma_queue_create(struct tag_cqm_object *object);
+void cqm_rdma_queue_delete(struct tag_cqm_object *object);
+s32 cqm_rdma_table_create(struct tag_cqm_object *object);
+void cqm_rdma_table_delete(struct tag_cqm_object *object);
+u8 *cqm_rdma_table_offset_addr(struct tag_cqm_object *object, u32 offset, dma_addr_t *paddr);
+
+#endif /* CQM_OBJECT_INTERN_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/cqm/readme.txt b/drivers/net/ethernet/huawei/hinic3/cqm/readme.txt
new file mode 100644
index 0000000000000..1e21b66601887
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/cqm/readme.txt
@@ -0,0 +1,3 @@
+
+2021/02/25/10:35 gf ovs fake vf hash clear support, change comment
+2019/03/28/15:17 wss provide stateful service queue and context management \ No newline at end of file
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h b/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h
index 98adaf057b47b..195a5cf08f66e 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_crm.h
@@ -4,7 +4,9 @@
#ifndef HINIC3_CRM_H
#define HINIC3_CRM_H
-#define HINIC3_DBG
+#include <linux/pci.h>
+
+#include "mpu_cmd_base_defs.h"
#define HINIC3_DRV_VERSION ""
#define HINIC3_DRV_DESC "Intelligent Network Interface Card Driver"
@@ -42,6 +44,7 @@ enum hinic3_service_type {
SERVICE_T_PPA,
SERVICE_T_CUSTOM,
SERVICE_T_VROCE,
+ SERVICE_T_CRYPT,
SERVICE_T_MAX,
/* Only used for interruption resource management,
@@ -75,7 +78,9 @@ struct ppa_service_cap {
struct vbs_service_cap {
u16 vbs_max_volq;
- u16 rsvd1;
+ u8 vbs_main_pf_enable;
+ u8 vbs_vsock_pf_enable;
+ u8 vbs_fushion_queue_pf_enable;
};
struct migr_service_cap {
@@ -297,8 +302,8 @@ struct ovs_service_cap {
/* PF IPsec service resource structure defined */
struct dev_ipsec_svc_cap {
- u32 max_sactxs; /* max IPsec SA context num */
- u16 max_cqs; /* max IPsec SCQC num */
+ u32 max_sactxs; /* max IPsec SA context num */
+ u16 max_cqs; /* max IPsec SCQC num */
u16 rsvd0;
};
@@ -310,8 +315,8 @@ struct ipsec_service_cap {
/* Defines the IRQ information structure */
struct irq_info {
- u16 msix_entry_idx; /* IRQ corresponding index number */
- u32 irq_id; /* the IRQ number from OS */
+ u16 msix_entry_idx; /* IRQ corresponding index number */
+ u32 irq_id; /* the IRQ number from OS */
};
struct interrupt_info {
@@ -342,6 +347,11 @@ enum func_type {
TYPE_UNKNOWN,
};
+enum func_nic_state {
+ HINIC3_FUNC_NIC_DEL,
+ HINIC3_FUNC_NIC_ADD,
+};
+
struct hinic3_init_para {
/* Record hinic_pcidev or NDIS_Adapter pointer address */
void *adapter_hdl;
@@ -356,7 +366,7 @@ struct hinic3_init_para {
/* Configure virtual address, PF is bar1, VF is bar0/1 */
void *cfg_reg_base;
- /* interrupt configuration register address, PF is bar2, VF is bar2/3
+ /* interrupt configuration register address, PF is bar2, VF is bar2/3
*/
void *intr_reg_base;
/* for PF bar3 virtual address, if function is VF should set to NULL */
@@ -394,6 +404,7 @@ struct card_node {
struct list_head node;
struct list_head func_list;
char chip_name[IFNAMSIZ];
+ int chip_id;
void *log_info;
void *dbgtool_info;
void *func_handle_array[MAX_FUNCTION_NUM];
@@ -522,6 +533,7 @@ enum hinic3_comm_event_type {
EVENT_COMM_SRIOV_STATE_CHANGE,
EVENT_COMM_CARD_REMOVE,
EVENT_COMM_MGMT_WATCHDOG,
+ EVENT_COMM_MULTI_HOST_MGMT,
};
enum hinic3_event_service_type {
@@ -532,14 +544,26 @@ enum hinic3_event_service_type {
};
#define HINIC3_SRV_EVENT_TYPE(svc, type) ((((u32)(svc)) << 16) | (type))
+#ifndef HINIC3_EVENT_DATA_SIZE
+#define HINIC3_EVENT_DATA_SIZE 104
+#endif
struct hinic3_event_info {
- u16 service; /* enum hinic3_event_service_type */
+ u16 service; /* enum hinic3_event_service_type */
u16 type;
- u8 event_data[104];
+ u8 event_data[HINIC3_EVENT_DATA_SIZE];
};
typedef void (*hinic3_event_handler)(void *handle, struct hinic3_event_info *event);
+struct hinic3_func_nic_state {
+ u8 state;
+ u8 rsvd0;
+ u16 func_idx;
+
+ u8 vroce_flag;
+ u8 rsvd1[15];
+};
+
/* *
* @brief hinic3_event_register - register hardware event
* @param dev: device pointer to hwdev
@@ -841,6 +865,15 @@ void hinic3_shutdown_hwdev(void *hwdev);
int hinic3_set_ppf_flr_type(void *hwdev, enum hinic3_ppf_flr_type flr_type);
/* *
+ * @brief hinic3_set_ppf_tbl_hotreplace_flag - set os hotreplace flag in ppf function table
+ * @param hwdev: device pointer to hwdev
+ * @param flag : os hotreplace flag : 0-not in os hotreplace 1-in os hotreplace
+ * @retval zero: success
+ * @retval non-zero: failure
+ */
+int hinic3_set_ppf_tbl_hotreplace_flag(void *hwdev, u8 flag);
+
+/* *
* @brief hinic3_get_mgmt_version - get management cpu version
* @param hwdev: device pointer to hwdev
* @param mgmt_ver: output management version
@@ -908,6 +941,13 @@ enum func_type hinic3_func_type(void *hwdev);
bool hinic3_get_stateful_enable(void *hwdev);
/* *
+ * @brief hinic3_get_timer_enable - get timer status
+ * @param hwdev: device pointer to hwdev
+ * @retval timer enabel status
+ */
+bool hinic3_get_timer_enable(void *hwdev);
+
+/* *
* @brief hinic3_host_oq_id_mask - get oq id
* @param hwdev: device pointer to hwdev
* @retval oq id
@@ -1059,7 +1099,7 @@ int hinic3_get_card_present_state(void *hwdev, bool *card_present_state);
* @retval zero: success
* @retval non-zero: failure
*/
-int hinic3_func_rx_tx_flush(void *hwdev, u16 channel);
+int hinic3_func_rx_tx_flush(void *hwdev, u16 channel, bool wait_io);
/* *
* @brief hinic3_flush_mgmt_workq - when remove function should flush work queue
@@ -1083,6 +1123,12 @@ u16 hinic3_intr_num(void *hwdev);
u8 hinic3_flexq_en(void *hwdev);
/* *
+ * @brief hinic3_get_fake_vf_info get fake_vf info
+ */
+int hinic3_get_fake_vf_info(void *hwdev, u8 *fake_vf_vld,
+ u8 *page_bit, u8 *pf_start_bit, u8 *map_host_id);
+
+/* *
* @brief hinic3_fault_event_report - report fault event
* @param hwdev: device pointer to hwdev
* @param src: fault event source, reference to enum hinic3_fault_source_type
@@ -1159,4 +1205,48 @@ int hinic3_set_host_migrate_enable(void *hwdev, u8 host_id, bool enable);
*/
int hinic3_get_host_migrate_enable(void *hwdev, u8 host_id, u8 *migrate_en);
+/* *
+ * @brief hinic3_is_slave_func - hwdev is slave func
+ * @param dev: device pointer to hwdev
+ * @param is_slave_func: slave func
+ * @retval zero: success
+ * @retval non-zero: failure
+ */
+int hinic3_is_slave_func(const void *hwdev, bool *is_slave_func);
+
+/* *
+ * @brief hinic3_is_master_func - hwdev is master func
+ * @param dev: device pointer to hwdev
+ * @param is_master_func: master func
+ * @retval zero: success
+ * @retval non-zero: failure
+ */
+int hinic3_is_master_func(const void *hwdev, bool *is_master_func);
+
+bool hinic3_is_multi_bm(void *hwdev);
+
+bool hinic3_is_slave_host(void *hwdev);
+
+bool hinic3_is_vm_slave_host(void *hwdev);
+
+bool hinic3_is_bm_slave_host(void *hwdev);
+
+bool hinic3_is_guest_vmsec_enable(void *hwdev);
+
+int hinic3_get_vfid_by_vfpci(void *hwdev, struct pci_dev *pdev, u16 *global_func_id);
+
+int hinic3_set_func_nic_state(void *hwdev, struct hinic3_func_nic_state *state);
+
+int hinic3_get_netdev_state(void *hwdev, u16 func_idx, int *opened);
+
+int hinic3_get_mhost_func_nic_enable(void *hwdev, u16 func_id, bool *en);
+
+int hinic3_get_dev_cap(void *hwdev);
+
+int hinic3_mbox_to_host_sync(void *hwdev, enum hinic3_mod_type mod,
+ u8 cmd, void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size, u32 timeout, u16 channel);
+
+int hinic3_get_func_vroce_enable(void *hwdev, u16 glb_func_idx, u8 *en);
+
#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_dbg.c b/drivers/net/ethernet/huawei/hinic3/hinic3_dbg.c
index 4a688f1908646..fdf92ab66e3b4 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_dbg.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_dbg.c
@@ -19,6 +19,8 @@
#include "hinic3_dcb.h"
#include "hinic3_nic.h"
#include "hinic3_mgmt_interface.h"
+#include "mag_mpu_cmd.h"
+#include "mag_cmd.h"
typedef int (*nic_driv_module)(struct hinic3_nic_dev *nic_dev,
const void *buf_in, u32 in_size,
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw.h b/drivers/net/ethernet/huawei/hinic3/hinic3_hw.h
index 34888e3d35353..ef8c62b3648f2 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw.h
@@ -4,25 +4,24 @@
#ifndef HINIC3_HW_H
#define HINIC3_HW_H
-#include "hinic3_comm_cmd.h"
-#include "comm_msg_intf.h"
-#include "comm_cmdq_intf.h"
+#include "mpu_inband_cmd.h"
+#include "mpu_inband_cmd_defs.h"
#include "hinic3_crm.h"
#ifndef BIG_ENDIAN
-#define BIG_ENDIAN 0x4321
+#define BIG_ENDIAN 0x4321
#endif
#ifndef LITTLE_ENDIAN
-#define LITTLE_ENDIAN 0x1234
+#define LITTLE_ENDIAN 0x1234
#endif
#ifdef BYTE_ORDER
#undef BYTE_ORDER
#endif
/* X86 */
-#define BYTE_ORDER LITTLE_ENDIAN
+#define BYTE_ORDER LITTLE_ENDIAN
/* to use 0-level CLA, page size must be: SQ 16B(wqe) * 64k(max_q_depth) */
#define HINIC3_DEFAULT_WQ_PAGE_SIZE 0x100000
@@ -127,7 +126,7 @@ typedef int (*hinic3_pf_recv_from_ppf_mbox_cb)(void *pri_handle,
u16 cmd, void *buf_in, u16 in_size, void *buf_out, u16 *out_size);
/**
- * @brief hinic3_aeq_register_hw_cb - register aeq hardware callback
+ * @brief hinic3_aeq_register_hw_cb - register aeq hardware callback
* @param hwdev: device pointer to hwdev
* @param event: event type
* @param hwe_cb: callback function
@@ -145,7 +144,7 @@ int hinic3_aeq_register_hw_cb(void *hwdev, void *pri_handle,
void hinic3_aeq_unregister_hw_cb(void *hwdev, enum hinic3_aeq_type event);
/**
- * @brief hinic3_aeq_register_swe_cb - register aeq soft event callback
+ * @brief hinic3_aeq_register_swe_cb - register aeq soft event callback
* @param hwdev: device pointer to hwdev
* @pri_handle: the pointer to private invoker device
* @param event: event type
@@ -164,7 +163,7 @@ int hinic3_aeq_register_swe_cb(void *hwdev, void *pri_handle, enum hinic3_aeq_sw
void hinic3_aeq_unregister_swe_cb(void *hwdev, enum hinic3_aeq_sw_type event);
/**
- * @brief hinic3_ceq_register_cb - register ceq callback
+ * @brief hinic3_ceq_register_cb - register ceq callback
* @param hwdev: device pointer to hwdev
* @param event: event type
* @param callback: callback function
@@ -514,7 +513,7 @@ int hinic3_api_csr_rd64(void *hwdev, u8 dest, u32 addr, u64 *val);
* @retval zero: success
* @retval non-zero: failure
*/
-int hinic3_dbg_get_hw_stats(const void *hwdev, u8 *hw_stats, const u16 *out_size);
+int hinic3_dbg_get_hw_stats(const void *hwdev, u8 *hw_stats, const u32 *out_size);
/**
* @brief hinic3_dbg_clear_hw_stats - clear hardware stats
@@ -627,6 +626,23 @@ int hinic3_mbox_to_vf(void *hwdev, u16 vf_id, u8 mod, u16 cmd, void *buf_in,
u16 in_size, void *buf_out, u16 *out_size, u32 timeout,
u16 channel);
+/**
+ * @brief hinic3_mbox_to_vf_no_ack - mbox message to vf no ack
+ * @param hwdev: device pointer to hwdev
+ * @param vf_id: vf index
+ * @param mod: mod type
+ * @param cmd: cmd
+ * @param buf_in: message buffer in
+ * @param in_size: in buffer size
+ * @param buf_out: message buffer out
+ * @param out_size: out buffer size
+ * @param channel: channel id
+ * @retval zero: success
+ * @retval non-zero: failure
+ */
+int hinic3_mbox_to_vf_no_ack(void *hwdev, u16 vf_id, u8 mod, u16 cmd, void *buf_in,
+ u16 in_size, void *buf_out, u16 *out_size, u16 channel);
+
int hinic3_clp_to_mgmt(void *hwdev, u8 mod, u16 cmd, const void *buf_in,
u16 in_size, void *buf_out, u16 *out_size);
/**
@@ -642,6 +658,20 @@ int hinic3_clp_to_mgmt(void *hwdev, u8 mod, u16 cmd, const void *buf_in,
int hinic3_cmdq_async(void *hwdev, u8 mod, u8 cmd, struct hinic3_cmd_buf *buf_in, u16 channel);
/**
+ * @brief hinic3_cmdq_async_cos - cmdq asynchronous message by cos
+ * @param hwdev: device pointer to hwdev
+ * @param mod: mod type
+ * @param cmd: cmd
+ * @param cos_id: cos id
+ * @param buf_in: message buffer in
+ * @param channel: channel id
+ * @retval zero: success
+ * @retval non-zero: failure
+ */
+int hinic3_cmdq_async_cos(void *hwdev, u8 mod, u8 cmd, u8 cos_id,
+ struct hinic3_cmd_buf *buf_in, u16 channel);
+
+/**
* @brief hinic3_cmdq_detail_resp - cmdq direct message response
* @param hwdev: device pointer to hwdev
* @param mod: mod type
@@ -820,6 +850,7 @@ int hinic3_get_ceq_page_phy_addr(void *hwdev, u16 q_id,
int hinic3_set_ceq_irq_disable(void *hwdev, u16 q_id);
int hinic3_get_ceq_info(void *hwdev, u16 q_id, struct hinic3_ceq_info *ceq_info);
+int hinic3_init_single_ceq_status(void *hwdev, u16 q_id);
void hinic3_set_api_stop(void *hwdev);
int hinic3_activate_firmware(void *hwdev, u8 cfg_index);
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mag_cfg.c b/drivers/net/ethernet/huawei/hinic3/hinic3_mag_cfg.c
index 4049e81ce034e..2fe808b8356df 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mag_cfg.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mag_cfg.c
@@ -17,7 +17,6 @@
#include "ossl_knl.h"
#include "hinic3_crm.h"
#include "hinic3_hw.h"
-#include "mag_cmd.h"
#include "hinic3_nic_io.h"
#include "hinic3_nic_cfg.h"
#include "hinic3_srv_nic.h"
@@ -552,8 +551,7 @@ static void port_sfp_abs_event(void *hwdev, void *buf_in, u16 in_size,
rt_cmd = &nic_io->nic_cfg.rt_cmd;
mutex_lock(&nic_io->nic_cfg.sfp_mutex);
- memcpy(&rt_cmd->abs, sfp_abs,
- sizeof(struct mag_cmd_get_xsfp_present));
+ memcpy(&rt_cmd->abs, sfp_abs, sizeof(struct mag_cmd_get_xsfp_present));
rt_cmd->mpu_send_sfp_abs = true;
mutex_unlock(&nic_io->nic_cfg.sfp_mutex);
}
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
index c40b7d9bed4e0..522518df64223 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h
@@ -1,24 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Huawei HiNIC PCI Express Linux driver
- * Copyright(c) 2017 Huawei Technologies Co., Ltd
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- */
-
-#ifndef HINIC_MGMT_INTERFACE_H
-#define HINIC_MGMT_INTERFACE_H
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef NIC_MPU_CMD_DEFS_H
+#define NIC_MPU_CMD_DEFS_H
#include "nic_cfg_comm.h"
-#include "mgmt_msg_base.h"
+#include "mpu_cmd_base_defs.h"
#ifndef ETH_ALEN
#define ETH_ALEN 6
@@ -30,6 +17,9 @@
#define HINIC3_CMD_OP_ADD 1
#define HINIC3_CMD_OP_DEL 0
+#define NIC_TCAM_BLOCK_LARGE_NUM 256
+#define NIC_TCAM_BLOCK_LARGE_SIZE 16
+
#ifndef BIT
#define BIT(n) (1UL << (n))
#endif
@@ -269,6 +259,50 @@ struct hinic3_cmd_cons_idx_attr {
u64 ci_addr;
};
+union sm_tbl_args {
+ struct {
+ u32 tbl_index;
+ u32 cnt;
+ u32 total_cnt;
+ } mac_table_arg;
+ struct {
+ u32 er_id;
+ u32 vlan_id;
+ } vlan_elb_table_arg;
+ struct {
+ u32 func_id;
+ } vlan_filter_arg;
+ struct {
+ u32 mc_id;
+ } mc_elb_arg;
+ struct {
+ u32 func_id;
+ } func_tbl_arg;
+ struct {
+ u32 port_id;
+ } port_tbl_arg;
+ struct {
+ u32 tbl_index;
+ u32 cnt;
+ u32 total_cnt;
+ } fdir_io_table_arg;
+ struct {
+ u32 tbl_index;
+ u32 cnt;
+ u32 total_cnt;
+ } flexq_table_arg;
+ u32 args[4];
+};
+
+#define DFX_SM_TBL_BUF_MAX (768)
+
+struct nic_cmd_dfx_sm_table {
+ struct hinic3_mgmt_msg_head msg_head;
+ u32 tbl_type;
+ union sm_tbl_args args;
+ u8 tbl_buf[DFX_SM_TBL_BUF_MAX];
+};
+
struct hinic3_cmd_vlan_offload {
struct hinic3_mgmt_msg_head msg_head;
@@ -282,9 +316,9 @@ struct nic_cmd_capture_info {
struct hinic3_mgmt_msg_head msg_head;
u32 op_type;
u32 func_port;
- u32 is_en_trx; /* 也作为tx_rx */
- u32 offset_cos; /* 也作为cos */
- u32 data_vlan; /* 也作为vlan */
+ u32 is_en_trx;
+ u32 offset_cos;
+ u32 data_vlan;
};
struct hinic3_cmd_lro_config {
@@ -403,10 +437,10 @@ struct hinic3_cmd_link_ksettings_info {
u8 rsvd1[3];
u32 valid_bitmap;
- u8 speed; /* enum nic_speed_level */
- u8 autoneg; /* 0 - off, 1 - on */
- u8 fec; /* 0 - RSFEC, 1 - BASEFEC, 2 - NOFEC */
- u8 rsvd2[21]; /* reserved for duplex, port, etc. */
+ u8 speed; /* enum nic_speed_level */
+ u8 autoneg; /* 0 - off, 1 - on */
+ u8 fec; /* 0 - RSFEC, 1 - BASEFEC, 2 - NOFEC */
+ u8 rsvd2[21]; /* reserved for duplex, port, etc. */
};
struct mpu_lt_info {
@@ -527,34 +561,34 @@ struct hinic3_up_ets_cfg { /* delet */
u8 tc_prio[NIC_DCB_TC_MAX];
};
-#define CMD_QOS_ETS_COS_TC BIT(0)
-#define CMD_QOS_ETS_TC_BW BIT(1)
-#define CMD_QOS_ETS_COS_PRIO BIT(2)
-#define CMD_QOS_ETS_COS_BW BIT(3)
-#define CMD_QOS_ETS_TC_PRIO BIT(4)
+#define CMD_QOS_ETS_COS_TC BIT(0)
+#define CMD_QOS_ETS_TC_BW BIT(1)
+#define CMD_QOS_ETS_COS_PRIO BIT(2)
+#define CMD_QOS_ETS_COS_BW BIT(3)
+#define CMD_QOS_ETS_TC_PRIO BIT(4)
struct hinic3_cmd_ets_cfg {
struct hinic3_mgmt_msg_head head;
u8 port_id;
- u8 op_code; /* 1 - set, 0 - get */
+ u8 op_code; /* 1 - set, 0 - get */
/* bit0 - cos_tc, bit1 - tc_bw, bit2 - cos_prio, bit3 - cos_bw, bit4 - tc_prio */
u8 cfg_bitmap;
u8 rsvd;
u8 cos_tc[NIC_DCB_COS_MAX];
u8 tc_bw[NIC_DCB_TC_MAX];
- u8 cos_prio[NIC_DCB_COS_MAX]; /* 0 - DWRR, 1 - STRICT */
+ u8 cos_prio[NIC_DCB_COS_MAX]; /* 0 - DWRR, 1 - STRICT */
u8 cos_bw[NIC_DCB_COS_MAX];
- u8 tc_prio[NIC_DCB_TC_MAX]; /* 0 - DWRR, 1 - STRICT */
+ u8 tc_prio[NIC_DCB_TC_MAX]; /* 0 - DWRR, 1 - STRICT */
};
struct hinic3_cmd_set_dcb_state {
struct hinic3_mgmt_msg_head head;
u16 func_id;
- u8 op_code; /* 0 - get dcb state, 1 - set dcb state */
- u8 state; /* 0 - disable, 1 - enable dcb */
- u8 port_state; /* 0 - disable, 1 - enable dcb */
+ u8 op_code; /* 0 - get dcb state, 1 - set dcb state */
+ u8 state; /* 0 - disable, 1 - enable dcb */
+ u8 port_state; /* 0 - disable, 1 - enable dcb */
u8 rsvd[7];
};
@@ -563,20 +597,20 @@ struct hinic3_cmd_set_pfc {
struct hinic3_mgmt_msg_head head;
u8 port_id;
- u8 op_code; /* 0:get 1: set pfc_en 2: set pfc_bitmap 3: set all */
- u8 pfc_en; /* pfc_en 和 pfc_bitmap 必须同时设置 */
+ u8 op_code; /* 0:get 1: set pfc_en 2: set pfc_bitmap 3: set all */
+ u8 pfc_en; /* pfc_en 和 pfc_bitmap 必须同时设置 */
u8 pfc_bitmap;
u8 rsvd[4];
};
-#define CMD_QOS_PORT_TRUST BIT(0)
-#define CMD_QOS_PORT_DFT_COS BIT(1)
+#define CMD_QOS_PORT_TRUST BIT(0)
+#define CMD_QOS_PORT_DFT_COS BIT(1)
struct hinic3_cmd_qos_port_cfg {
struct hinic3_mgmt_msg_head head;
u8 port_id;
- u8 op_code; /* 0 - get, 1 - set */
- u8 cfg_bitmap; /* bit0 - trust, bit1 - dft_cos */
+ u8 op_code; /* 0 - get, 1 - set */
+ u8 cfg_bitmap; /* bit0 - trust, bit1 - dft_cos */
u8 rsvd0;
u8 trust;
@@ -585,8 +619,8 @@ struct hinic3_cmd_qos_port_cfg {
};
#define MAP_COS_MAX_NUM 8
-#define CMD_QOS_MAP_PCP2COS BIT(0)
-#define CMD_QOS_MAP_DSCP2COS BIT(1)
+#define CMD_QOS_MAP_PCP2COS BIT(0)
+#define CMD_QOS_MAP_DSCP2COS BIT(1)
struct hinic3_cmd_qos_map_cfg {
struct hinic3_mgmt_msg_head head;
@@ -594,9 +628,9 @@ struct hinic3_cmd_qos_map_cfg {
u8 cfg_bitmap; /* bit0 - pcp2cos, bit1 - dscp2cos */
u16 rsvd0;
- u8 pcp2cos[8]; /* 必须8个一起配置 */
- /* 配置dscp2cos时,若cos值设置为0xFF,MPU则忽略此dscp优先级的配置,
- * 允许一次性配置多个dscp跟cos的映射关系
+ u8 pcp2cos[8]; /* 8 must be configured together */
+ /* If the dscp2cos parameter is set to 0xFF, the MPU ignores the DSCP priority,
+ * Multiple mappings between DSCP values and CoS values can be configured at a time.
*/
u8 dscp2cos[64];
u32 rsvd1[4];
@@ -625,7 +659,6 @@ struct hinic3_cmd_pause_config {
u8 rsvd2[5];
};
-/* pfc风暴检测配置 */
struct nic_cmd_pause_inquiry_cfg {
struct hinic3_mgmt_msg_head head;
@@ -633,27 +666,26 @@ struct nic_cmd_pause_inquiry_cfg {
u32 type; /* 1: set, 2: get */
- u32 rx_inquiry_pause_drop_pkts_en; /* rx 卸包使能 */
- u32 rx_inquiry_pause_period_ms; /* rx pause 检测周期 默认 200ms */
- u32 rx_inquiry_pause_times; /* rx pause 检测次数 默认1次 */
- /* rx pause 检测阈值 默认 PAUSE_FRAME_THD_10G/25G/40G/100 */
+ u32 rx_inquiry_pause_drop_pkts_en;
+ u32 rx_inquiry_pause_period_ms;
+ u32 rx_inquiry_pause_times;
+ /* rx pause Detection Threshold, Default PAUSE_FRAME_THD_10G/25G/40G/100 */
u32 rx_inquiry_pause_frame_thd;
- u32 rx_inquiry_tx_total_pkts; /* rx pause 检测tx收包总数 */
-
- u32 tx_inquiry_pause_en; /* tx pause 检测使能 */
- u32 tx_inquiry_pause_period_ms; /* tx pause 检测周期 默认 200ms */
- u32 tx_inquiry_pause_times; /* tx pause 检测次数 默认 5次 */
- u32 tx_inquiry_pause_frame_thd; /* tx pause 检测阈值 */
- u32 tx_inquiry_rx_total_pkts; /* tx pause 检测rx收包总数 */
+ u32 rx_inquiry_tx_total_pkts;
+ u32 tx_inquiry_pause_en; /* tx pause detect enable */
+ u32 tx_inquiry_pause_period_ms; /* tx pause Default Detection Period 200ms */
+ u32 tx_inquiry_pause_times; /* tx pause Default Times Period 5 */
+ u32 tx_inquiry_pause_frame_thd; /* tx pause Detection Threshold */
+ u32 tx_inquiry_rx_total_pkts;
u32 rsvd[4];
};
-/* pfc/pause风暴tx异常上报 */
+/* pfc/pause Storm TX exception reporting */
struct nic_cmd_tx_pause_notice {
struct hinic3_mgmt_msg_head head;
- u32 tx_pause_except; /* 1: 异常,0: 正常 */
+ u32 tx_pause_except; /* 1: abnormality,0: normal */
u32 except_level;
u32 rsvd;
};
@@ -717,7 +749,6 @@ struct hinic3_cable_plug_event {
u8 port_id;
};
-/* MAC模块接口 */
struct nic_cmd_mac_info {
struct hinic3_mgmt_msg_head head;
@@ -749,14 +780,14 @@ struct nic_cmd_set_fdir_status {
u8 rsvd2;
};
-#define HINIC3_TCAM_BLOCK_ENABLE 1
-#define HINIC3_TCAM_BLOCK_DISABLE 0
-#define HINIC3_MAX_TCAM_RULES_NUM 4096
+#define HINIC3_TCAM_BLOCK_ENABLE 1
+#define HINIC3_TCAM_BLOCK_DISABLE 0
+#define HINIC3_MAX_TCAM_RULES_NUM 4096
/* tcam block type, according to tcam block size */
enum {
NIC_TCAM_BLOCK_TYPE_LARGE = 0, /* block_size: 16 */
- NIC_TCAM_BLOCK_TYPE_SMALL, /* block_size: 0 */
+ NIC_TCAM_BLOCK_TYPE_SMALL, /* block_size: 0 */
NIC_TCAM_BLOCK_TYPE_MAX
};
@@ -764,13 +795,14 @@ enum {
struct nic_cmd_ctrl_tcam_block_in {
struct hinic3_mgmt_msg_head head;
- u16 func_id; /* func_id */
- u8 alloc_en; /* 0: 释放分配的tcam block, 1: 申请新的tcam block */
- /* 0: 分配16 size 的tcam block, 1: 分配0 size的tcam block, 其他预留 */
+ u16 func_id; /* func_id */
+ u8 alloc_en; /* 0: Releases the allocated TCAM block. 1: Applies for a new TCAM block */
+ /* 0: 16 size tcam block, 1: 0 size tcam block, other reserved. */
u8 tcam_type;
u16 tcam_block_index;
- /* 驱动发给uP表示驱动希望分配的block大小
- * uP返回给驱动的接口,表示uP 支持的分配的tcam block大小
+ /* Size of the block that the driver wants to allocate
+ * Interface returned by the UP to the driver,
+ * indicating the size of the allocated TCAM block supported by the UP
*/
u16 alloc_block_num;
};
@@ -779,13 +811,14 @@ struct nic_cmd_ctrl_tcam_block_in {
struct nic_cmd_ctrl_tcam_block_out {
struct hinic3_mgmt_msg_head head;
- u16 func_id; /* func_id */
- u8 alloc_en; /* 0: 释放分配的tcam block, 1: 申请新的tcam block */
- /* 0: 分配16 size 的tcam block, 1: 分配0 size的tcam block, 其他预留 */
+ u16 func_id; /* func_id */
+ u8 alloc_en; /* 0: Releases the allocated TCAM block. 1: Applies for a new TCAM block */
+ /* 0: 16 size tcam block, 1: 0 size tcam block, other reserved. */
u8 tcam_type;
u16 tcam_block_index;
- /* 驱动发给uP表示驱动希望分配的block大小
- * uP返回给驱动的接口,表示uP 支持的分配的tcam block大小
+ /* Size of the block that the driver wants to allocate
+ * Interface returned by the UP to the driver,
+ * indicating the size of the allocated TCAM block supported by the UP
*/
u16 mpu_alloc_block_size;
};
@@ -824,15 +857,15 @@ struct nic_tcam_cfg_rule {
struct tcam_key_x_y key;
};
-#define TCAM_RULE_FDIR_TYPE 0
-#define TCAM_RULE_PPA_TYPE 1
+#define TCAM_RULE_FDIR_TYPE 0
+#define TCAM_RULE_PPA_TYPE 1
struct nic_cmd_fdir_add_rule {
struct hinic3_mgmt_msg_head head;
u16 func_id;
u8 type;
- u8 rsvd;
+ u8 fdir_ext; /* 0x1: flow bifur en bit */
struct nic_tcam_cfg_rule rule;
};
@@ -859,6 +892,16 @@ struct nic_cmd_fdir_get_rule {
u64 byte_count;
};
+struct nic_cmd_fdir_get_block_rules {
+ struct hinic3_mgmt_msg_head head;
+ u8 tcam_block_type; // only NIC_TCAM_BLOCK_TYPE_LARGE
+ u8 tcam_table_type; // TCAM_RULE_PPA_TYPE or TCAM_RULE_FDIR_TYPE
+ u16 tcam_block_index;
+ u8 valid[NIC_TCAM_BLOCK_LARGE_SIZE];
+ struct tcam_key_x_y key[NIC_TCAM_BLOCK_LARGE_SIZE];
+ struct tcam_result data[NIC_TCAM_BLOCK_LARGE_SIZE];
+};
+
struct hinic3_tcam_key_ipv4_mem {
u32 rsvd1 : 4;
u32 tunnel_type : 4;
@@ -867,9 +910,10 @@ struct hinic3_tcam_key_ipv4_mem {
u32 sipv4_h : 16;
u32 ip_type : 1;
u32 function_id : 15;
- u32 dipv4_h : 16;
- u32 sipv4_l : 16;
- u32 rsvd2 : 16;
+ u32 dipv4_h : 16;
+ u32 sipv4_l : 16;
+ u32 vlan_id : 15;
+ u32 vlan_flag : 1;
u32 dipv4_l : 16;
u32 rsvd3;
u32 dport : 16;
@@ -886,6 +930,17 @@ struct hinic3_tcam_key_ipv4_mem {
u32 vni_l : 16;
};
+union hinic3_tag_tcam_ext_info {
+ struct {
+ u32 id : 16; /* id */
+ u32 type : 4; /* type: 0-func, 1-vmdq, 2-port, 3-rsvd, 4-trunk, 5-dp, 6-mc */
+ u32 host_id : 3;
+ u32 rsv : 8;
+ u32 ext : 1;
+ } bs;
+ u32 value;
+};
+
struct hinic3_tcam_key_ipv6_mem {
u32 rsvd1 : 4;
u32 tunnel_type : 4;
@@ -992,6 +1047,40 @@ struct hinic3_ppa_cfg_ppa_en_cmd {
u8 rsvd;
};
+struct hinic3_func_flow_bifur_en_cmd {
+ struct hinic3_mgmt_msg_head msg_head;
+ u16 func_id;
+ u8 flow_bifur_en;
+ u8 rsvd[5];
+};
+
+struct hinic3_port_flow_bifur_en_cmd {
+ struct hinic3_mgmt_msg_head msg_head;
+ u16 port_id;
+ u8 flow_bifur_en;
+ u8 rsvd[5];
+};
+
+struct hinic3_bond_mask_cmd {
+ struct hinic3_mgmt_msg_head msg_head;
+ u16 func_id;
+ u8 bond_mask;
+ u8 bond_en;
+ u8 func_valid;
+ u8 rsvd[3];
+};
+
+#define HINIC3_TX_SET_PROMISC_SKIP 0
+#define HINIC3_TX_GET_PROMISC_SKIP 1
+
+struct hinic3_tx_promisc_cfg {
+ struct hinic3_mgmt_msg_head msg_head;
+ u8 port_id;
+ u8 promisc_skip_en; /* 0: disable tx promisc replication, 1: enable */
+ u8 opcode; /* 0: set, 1: get */
+ u8 rsvd1;
+};
+
struct hinic3_ppa_cfg_mode_cmd {
struct hinic3_mgmt_msg_head msg_head;
@@ -1037,43 +1126,43 @@ enum {
NIC_NVM_DATA_RESET = BIT(31),
};
-#define BIOS_CFG_SIGNATURE 0x1923E518
-#define BIOS_OP_CFG_ALL(op_code_val) (((op_code_val) >> 1) & (0xFFFFFFFF))
-#define BIOS_OP_CFG_WRITE(op_code_val) ((op_code_val) & NIC_NVM_DATA_SET)
-#define BIOS_OP_CFG_PXE_EN(op_code_val) ((op_code_val) & NIC_NVM_DATA_PXE)
-#define BIOS_OP_CFG_VLAN_EN(op_code_val) ((op_code_val) & NIC_NVM_DATA_VLAN)
-#define BIOS_OP_CFG_VLAN_PRI(op_code_val) ((op_code_val) & NIC_NVM_DATA_VLAN_PRI)
-#define BIOS_OP_CFG_VLAN_ID(op_code_val) ((op_code_val) & NIC_NVM_DATA_VLAN_ID)
-#define BIOS_OP_CFG_WORK_MODE(op_code_val) ((op_code_val) & NIC_NVM_DATA_WORK_MODE)
-#define BIOS_OP_CFG_PF_BW(op_code_val) ((op_code_val) & NIC_NVM_DATA_PF_SPEED_LIMIT)
-#define BIOS_OP_CFG_GE_SPEED(op_code_val) ((op_code_val) & NIC_NVM_DATA_GE_MODE)
-#define BIOS_OP_CFG_AUTO_NEG(op_code_val) ((op_code_val) & NIC_NVM_DATA_AUTO_NEG)
-#define BIOS_OP_CFG_LINK_FEC(op_code_val) ((op_code_val) & NIC_NVM_DATA_LINK_FEC)
-#define BIOS_OP_CFG_AUTO_ADPAT(op_code_val) ((op_code_val) & NIC_NVM_DATA_PF_ADAPTIVE_LINK)
-#define BIOS_OP_CFG_SRIOV_ENABLE(op_code_val) ((op_code_val) & NIC_NVM_DATA_SRIOV_CONTROL)
-#define BIOS_OP_CFG_EXTEND_MODE(op_code_val) ((op_code_val) & NIC_NVM_DATA_EXTEND_MODE)
-#define BIOS_OP_CFG_RST_DEF_SET(op_code_val) ((op_code_val) & (u32)NIC_NVM_DATA_RESET)
+#define BIOS_CFG_SIGNATURE 0x1923E518
+#define BIOS_OP_CFG_ALL(op_code_val) ((((op_code_val) >> 1) & (0xFFFFFFFF)) != 0)
+#define BIOS_OP_CFG_WRITE(op_code_val) ((((op_code_val) & NIC_NVM_DATA_SET)) != 0)
+#define BIOS_OP_CFG_PXE_EN(op_code_val) (((op_code_val) & NIC_NVM_DATA_PXE) != 0)
+#define BIOS_OP_CFG_VLAN_EN(op_code_val) (((op_code_val) & NIC_NVM_DATA_VLAN) != 0)
+#define BIOS_OP_CFG_VLAN_PRI(op_code_val) (((op_code_val) & NIC_NVM_DATA_VLAN_PRI) != 0)
+#define BIOS_OP_CFG_VLAN_ID(op_code_val) (((op_code_val) & NIC_NVM_DATA_VLAN_ID) != 0)
+#define BIOS_OP_CFG_WORK_MODE(op_code_val) (((op_code_val) & NIC_NVM_DATA_WORK_MODE) != 0)
+#define BIOS_OP_CFG_PF_BW(op_code_val) (((op_code_val) & NIC_NVM_DATA_PF_SPEED_LIMIT) != 0)
+#define BIOS_OP_CFG_GE_SPEED(op_code_val) (((op_code_val) & NIC_NVM_DATA_GE_MODE) != 0)
+#define BIOS_OP_CFG_AUTO_NEG(op_code_val) (((op_code_val) & NIC_NVM_DATA_AUTO_NEG) != 0)
+#define BIOS_OP_CFG_LINK_FEC(op_code_val) (((op_code_val) & NIC_NVM_DATA_LINK_FEC) != 0)
+#define BIOS_OP_CFG_AUTO_ADPAT(op_code_val) (((op_code_val) & NIC_NVM_DATA_PF_ADAPTIVE_LINK) != 0)
+#define BIOS_OP_CFG_SRIOV_ENABLE(op_code_val) (((op_code_val) & NIC_NVM_DATA_SRIOV_CONTROL) != 0)
+#define BIOS_OP_CFG_EXTEND_MODE(op_code_val) (((op_code_val) & NIC_NVM_DATA_EXTEND_MODE) != 0)
+#define BIOS_OP_CFG_RST_DEF_SET(op_code_val) (((op_code_val) & (u32)NIC_NVM_DATA_RESET) != 0)
#define NIC_BIOS_CFG_MAX_PF_BW 100
-/* 注意:此结构必须保证4字节对齐 */
+/* Note: This structure must be 4-byte aligned. */
struct nic_bios_cfg {
- u32 signature; /* 签名,用于判断FLASH的内容合法性 */
- u8 pxe_en; /* PXE enable: 0 - disable 1 - enable */
+ u32 signature;
+ u8 pxe_en; /* PXE enable: 0 - disable 1 - enable */
u8 extend_mode;
u8 rsvd0[2];
- u8 pxe_vlan_en; /* PXE VLAN enable: 0 - disable 1 - enable */
- u8 pxe_vlan_pri; /* PXE VLAN priority: 0-7 */
- u16 pxe_vlan_id; /* PXE VLAN ID 1-4094 */
- u32 service_mode; /* 参考CHIPIF_SERVICE_MODE_x 宏 */
- u32 pf_bw; /* PF速率,百分比 0-100 */
- u8 speed; /* enum of port speed */
- u8 auto_neg; /* 自协商开关 0 - 字段无效 1 - 开2 - 关 */
- u8 lanes; /* lane num */
- u8 fec; /* FEC模式, 参考 enum mag_cmd_port_fec */
- u8 auto_adapt; /* 自适应模式配置0 - 无效配置 1 - 开启 2 - 关闭 */
- u8 func_valid; /* 指示func_id是否有效; 0 - 无效,other - 有效 */
- u8 func_id; /* 当func_valid不为0时,该成员才有意义 */
- u8 sriov_en; /* SRIOV-EN: 0 - 无效配置, 1 - 开启, 2 - 关闭 */
+ u8 pxe_vlan_en; /* PXE VLAN enable: 0 - disable 1 - enable */
+ u8 pxe_vlan_pri; /* PXE VLAN priority: 0-7 */
+ u16 pxe_vlan_id; /* PXE VLAN ID 1-4094 */
+ u32 service_mode; /* @See CHIPIF_SERVICE_MODE_x */
+ u32 pf_bw; /* PF rate, in percentage. The value ranges from 0 to 100. */
+ u8 speed; /* enum of port speed */
+ u8 auto_neg; /* Auto-Negotiation Switch 0 - Invalid Field 1 - On 2 - Off */
+ u8 lanes; /* lane num */
+ u8 fec; /* FEC mode, @See enum mag_cmd_port_fec */
+ u8 auto_adapt; /* Adaptive Mode Configuration 0 - Invalid Configuration 1 - On 2 - Off */
+ u8 func_valid; /* Whether func_id is valid; 0: invalid; other: valid */
+ u8 func_id; /* This member is valid only when func_valid is not set to 0. */
+ u8 sriov_en; /* SRIOV-EN: 0 - Invalid configuration, 1 - On, 2 - Off */
};
struct nic_cmd_bios_cfg {
@@ -1087,26 +1176,25 @@ struct nic_cmd_vhd_config {
u16 func_id;
u8 vhd_type;
- u8 virtio_small_enable; /* 0: mergeable mode, 1: small mode */
+ u8 virtio_small_enable; /* 0: mergeable mode, 1: small mode */
};
/* BOND */
struct hinic3_create_bond_info {
- u32 bond_id; /* bond设备号,output时有效,mpu操作成功返回时回填 */
- u32 master_slave_port_id; /* */
- u32 slave_bitmap; /* bond port id bitmap */
- u32 poll_timeout; /* bond设备链路检查时间 */
- u32 up_delay; /* 暂时预留 */
- u32 down_delay; /* 暂时预留 */
- u32 bond_mode; /* 暂时预留 */
- u32 active_pf; /* bond使用的active pf id */
- u32 active_port_max_num; /* bond活动成员口个数上限 */
- u32 active_port_min_num; /* bond活动成员口个数下限 */
- u32 xmit_hash_policy; /* hash策略,用于微码选路逻辑 */
+ u32 bond_id;
+ u32 master_slave_port_id;
+ u32 slave_bitmap; /* bond port id bitmap */
+ u32 poll_timeout; /* Bond device link check time */
+ u32 up_delay; /* Temporarily reserved */
+ u32 down_delay; /* Temporarily reserved */
+ u32 bond_mode; /* Temporarily reserved */
+ u32 active_pf; /* bond use active pf id */
+ u32 active_port_max_num; /* Maximum number of active bond member interfaces */
+ u32 active_port_min_num; /* Minimum number of active bond member interfaces */
+ u32 xmit_hash_policy;
u32 rsvd[2];
};
-/* 创建bond的消息接口 */
struct hinic3_cmd_create_bond {
struct hinic3_mgmt_msg_head head;
struct hinic3_create_bond_info create_bond_info;
@@ -1119,18 +1207,16 @@ struct hinic3_cmd_delete_bond {
};
struct hinic3_open_close_bond_info {
- u32 bond_id; /* bond设备号 */
- u32 open_close_flag; /* 开启/关闭bond标识:1为open, 0为close */
+ u32 bond_id;
+ u32 open_close_flag; /* Bond flag. 1: open; 0: close. */
u32 rsvd[2];
};
-/* MPU bond的消息接口 */
struct hinic3_cmd_open_close_bond {
struct hinic3_mgmt_msg_head head;
struct hinic3_open_close_bond_info open_close_bond_info;
};
-/* LACPDU的port相关字段 */
struct lacp_port_params {
u16 port_number;
u16 port_priority;
@@ -1143,10 +1229,10 @@ struct lacp_port_params {
struct lacp_port_info {
u32 selected;
- u32 aggregator_port_id; /* 使用的 aggregator port ID */
+ u32 aggregator_port_id;
- struct lacp_port_params actor; /* actor port参数 */
- struct lacp_port_params partner; /* partner port参数 */
+ struct lacp_port_params actor;
+ struct lacp_port_params partner;
u64 tx_lacp_pkts;
u64 rx_lacp_pkts;
@@ -1157,18 +1243,17 @@ struct lacp_port_info {
u64 tx_marker_pkts;
};
-/* lacp 状态信息 */
struct hinic3_bond_status_info {
struct hinic3_mgmt_msg_head head;
u32 bond_id;
- u32 bon_mmi_status; /* 该bond子设备的链路状态 */
- u32 active_bitmap; /* 该bond子设备的slave port状态 */
- u32 port_count; /* 该bond子设备个数 */
+ u32 bon_mmi_status;
+ u32 active_bitmap;
+ u32 port_count;
struct lacp_port_info port_info[4];
- u64 success_report_cnt[4]; /* 每个host成功上报lacp协商结果次数 */
- u64 fail_report_cnt[4]; /* 每个host上报lacp协商结果失败次数 */
+ u64 success_report_cnt[4];
+ u64 fail_report_cnt[4];
u64 poll_timeout;
u64 fast_periodic_timeout;
@@ -1180,12 +1265,11 @@ struct hinic3_bond_status_info {
u64 rx_marker_timer;
};
-/* lacp协商结果更新之后向主机侧发送异步消息通知结构体 */
struct hinic3_bond_active_report_info {
struct hinic3_mgmt_msg_head head;
u32 bond_id;
- u32 bon_mmi_status; /* 该bond子设备的链路状态 */
- u32 active_bitmap; /* 该bond子设备的slave port状态 */
+ u32 bon_mmi_status;
+ u32 active_bitmap;
u8 rsvd[16];
};
@@ -1195,7 +1279,7 @@ struct hinic3_ipcs_err_rss_enable_operation_s {
struct hinic3_mgmt_msg_head head;
u8 en_tag;
- u8 type; /* 1: set 0: get */
+ u8 type; /* 1: set 0: get */
u8 rsvd[2];
};
@@ -1206,4 +1290,9 @@ struct hinic3_smac_check_state {
u8 rsvd[2];
};
+struct hinic3_clear_log_state {
+ struct hinic3_mgmt_msg_head head;
+ u32 type;
+};
+
#endif /* HINIC_MGMT_INTERFACE_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic.h b/drivers/net/ethernet/huawei/hinic3/hinic3_nic.h
index 69cacbae3b577..cc00bdcbc71b9 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic.h
@@ -10,7 +10,6 @@
#include "hinic3_common.h"
#include "hinic3_nic_io.h"
#include "hinic3_nic_cfg.h"
-#include "mag_cmd.h"
/* ************************ array index define ********************* */
#define ARRAY_INDEX_0 0
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h
index dc0a8eb6e2df4..ee0587cc3faaf 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h
@@ -8,6 +8,7 @@
#include <linux/netdevice.h>
#include "hinic3_mgmt_interface.h"
+#include "mag_mpu_cmd.h"
#include "mag_cmd.h"
#define OS_VF_ID_TO_HW(os_vf_id) ((os_vf_id) + 1)
diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_srv_nic.h b/drivers/net/ethernet/huawei/hinic3/hinic3_srv_nic.h
index fee4cfca1e4c5..bdd5a8eb282dd 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_srv_nic.h
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_srv_nic.h
@@ -12,6 +12,7 @@
#define HINIC3_SRV_NIC_H
#include "hinic3_mgmt_interface.h"
+#include "mag_mpu_cmd.h"
#include "mag_cmd.h"
#include "hinic3_lld.h"
@@ -61,6 +62,8 @@ enum hinic3_nic_event_type {
EVENT_NIC_LINK_UP,
EVENT_NIC_PORT_MODULE_EVENT,
EVENT_NIC_DCB_STATE_CHANGE,
+ EVENT_NIC_BOND_DOWN,
+ EVENT_NIC_BOND_UP,
};
/* *
@@ -207,6 +210,8 @@ void hinic3_free_qp_ctxts(void *hwdev);
* @param hwdev: device pointer to hwdev
* @param vf_link_forced: set link forced
* @param link_state: Set link state, This parameter is valid only when vf_link_forced is true
+ * @retval zero: success
+ * @retval non-zero: failure
*/
int hinic3_pf_set_vf_link_state(void *hwdev, bool vf_link_forced, bool link_state);
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.c
index 230859adf0b23..0878186ee1ff5 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include "ossl_knl.h"
+#include "npu_cmdq_base_defs.h"
#include "hinic3_crm.h"
#include "hinic3_hw.h"
#include "hinic3_hwdev.h"
@@ -826,8 +827,7 @@ static int cmdq_async_cmd(struct hinic3_cmdq *cmdq, u8 mod, u8 cmd,
*/
cmd_info->buf_in = buf_in;
- /* LB mode 1 compatible, cmdq 0 also for async, which is sync_no_wait */
- cmdq_set_db(cmdq, HINIC3_CMDQ_SYNC, next_prod_idx);
+ cmdq_set_db(cmdq, cmdq->cmdq_type, next_prod_idx);
cmdq_msg_unlock(cmdq);
@@ -995,6 +995,35 @@ int hinic3_cmdq_async(void *hwdev, u8 mod, u8 cmd, struct hinic3_cmd_buf *buf_in
cmd, buf_in, channel);
}
+int hinic3_cmdq_async_cos(void *hwdev, u8 mod, u8 cmd,
+ u8 cos_id, struct hinic3_cmd_buf *buf_in, u16 channel)
+{
+ struct hinic3_cmdqs *cmdqs = NULL;
+ int err;
+
+ err = cmdq_params_valid(hwdev, buf_in);
+ if (err)
+ return err;
+
+ cmdqs = ((struct hinic3_hwdev *)hwdev)->cmdqs;
+
+ if (!get_card_present_state((struct hinic3_hwdev *)hwdev))
+ return -EPERM;
+
+ err = wait_cmdqs_enable(cmdqs);
+ if (err) {
+ sdk_err(cmdqs->hwdev->dev_hdl, "Cmdq is disable\n");
+ return err;
+ }
+
+ if (cos_id >= cmdqs->cmdq_num) {
+ sdk_err(cmdqs->hwdev->dev_hdl, "Cmdq id is invalid\n");
+ return -EINVAL;
+ }
+
+ return cmdq_async_cmd(&cmdqs->cmdq[cos_id], mod, cmd, buf_in, channel);
+}
+
static void clear_wqe_complete_bit(struct hinic3_cmdq *cmdq,
struct hinic3_cmdq_wqe *wqe, u16 ci)
{
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.h
index ab36dc9c2ba6f..b0344ea5a0755 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_cmdq.h
@@ -8,12 +8,17 @@
#include <linux/completion.h>
#include <linux/spinlock.h>
-#include "comm_msg_intf.h"
+#include "mpu_inband_cmd_defs.h"
#include "hinic3_hw.h"
#include "hinic3_wq.h"
#include "hinic3_common.h"
#include "hinic3_hwdev.h"
+struct dma_pool {
+ unsigned int size;
+ void *dev_hdl;
+};
+
#define HINIC3_SCMD_DATA_LEN 16
#define HINIC3_CMDQ_DEPTH 4096
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_csr.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_csr.h
index b5390c9ed4881..4098d7f818702 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_csr.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_csr.h
@@ -183,5 +183,6 @@
#define HINIC3_MULT_HOST_SLAVE_STATUS_ADDR (HINIC3_MGMT_REGS_FLAG + 0xDF30)
#define HINIC3_MULT_MIGRATE_HOST_STATUS_ADDR (HINIC3_MGMT_REGS_FLAG + 0xDF4C)
+#define HINIC3_MULT_HOST_MASTER_MBOX_STATUS_ADDR HINIC3_MULT_HOST_SLAVE_STATUS_ADDR
#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_devlink.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_devlink.h
index 0b5a086358b9b..68dd0fb519e26 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_devlink.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_devlink.h
@@ -143,6 +143,30 @@ struct host_image {
u32 device_id;
};
+struct hinic3_cmd_update_firmware {
+ struct mgmt_msg_head msg_head;
+
+ struct {
+ u32 sl : 1;
+ u32 sf : 1;
+ u32 flag : 1;
+ u32 bit_signed : 1;
+ u32 reserved : 12;
+ u32 fragment_len : 16;
+ } ctl_info;
+
+ struct {
+ u32 section_crc;
+ u32 section_type;
+ } section_info;
+
+ u32 total_len;
+ u32 section_len;
+ u32 section_version;
+ u32 section_offset;
+ u32 data[384];
+};
+
int hinic3_init_devlink(struct hinic3_hwdev *hwdev);
void hinic3_uninit_devlink(struct hinic3_hwdev *hwdev);
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_eqs.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_eqs.c
index 2638dd1865d71..4b08aa0cd7795 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_eqs.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_eqs.c
@@ -1004,6 +1004,41 @@ req_irq_err:
return err;
}
+int hinic3_init_single_ceq_status(void *hwdev, u16 q_id)
+{
+ int err = 0;
+ struct hinic3_hwdev *dev = hwdev;
+ struct hinic3_eq *eq = NULL;
+
+ if (!hwdev) {
+ sdk_err(dev->dev_hdl, "hwdev is null\n");
+ return -EINVAL;
+ }
+
+ if (q_id >= dev->ceqs->num_ceqs) {
+ sdk_err(dev->dev_hdl, "q_id=%u is larger than num_ceqs %u.\n",
+ q_id, dev->ceqs->num_ceqs);
+ return -EINVAL;
+ }
+
+ eq = &dev->ceqs->ceq[q_id];
+ /* Indirect access should set q_id first */
+ hinic3_hwif_write_reg(dev->hwif, HINIC3_EQ_INDIR_IDX_ADDR(eq->type), eq->q_id);
+ wmb(); /* write index before config */
+
+ reset_eq(eq);
+
+ err = set_eq_ctrls(eq);
+ if (err) {
+ sdk_err(dev->dev_hdl, "Failed to set ctrls for eq\n");
+ return err;
+ }
+ set_eq_cons_idx(eq, HINIC3_EQ_ARMED);
+
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_init_single_ceq_status);
+
/**
* remove_eq - remove eq
* @eq: the event queue
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c
index 08a1b8f15cb7b..21951bde395d1 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.c
@@ -16,7 +16,8 @@
#include "hinic3_hw.h"
#include "hinic3_hwdev.h"
#include "hinic3_hwif.h"
-#include "cfg_mgt_comm_pub.h"
+#include "cfg_mgmt_mpu_cmd.h"
+#include "cfg_mgmt_mpu_cmd_defs.h"
#include "hinic3_hw_cfg.h"
static void parse_pub_res_cap_dfx(struct hinic3_hwdev *hwdev,
@@ -108,6 +109,11 @@ static void parse_pub_res_cap(struct hinic3_hwdev *hwdev,
cap->host_valid_bitmap = dev_cap->host_valid_bitmap;
cap->master_host_id = dev_cap->master_host_id;
cap->srv_multi_host_mode = dev_cap->srv_multi_host_mode;
+ cap->fake_vf_en = dev_cap->fake_vf_en;
+ cap->fake_vf_start_bit = dev_cap->fake_vf_start_bit;
+ cap->fake_vf_end_bit = dev_cap->fake_vf_end_bit;
+ cap->fake_vf_page_bit = dev_cap->fake_vf_page_bit;
+ cap->map_host_id = dev_cap->map_host_id;
if (type != TYPE_VF) {
cap->max_vf = dev_cap->max_vf;
@@ -327,19 +333,6 @@ static void parse_ipsec_res_cap(struct hinic3_hwdev *hwdev,
dev_cap->ipsec_max_sactx, dev_cap->ipsec_max_cq);
}
-static void parse_vbs_res_cap(struct hinic3_hwdev *hwdev,
- struct service_cap *cap,
- struct cfg_cmd_dev_cap *dev_cap,
- enum func_type type)
-{
- struct vbs_service_cap *vbs_cap = &cap->vbs_cap;
-
- vbs_cap->vbs_max_volq = dev_cap->vbs_max_volq;
-
- sdk_info(hwdev->dev_hdl, "Get VBS resource capbility, vbs_max_volq: 0x%x\n",
- dev_cap->vbs_max_volq);
-}
-
static void parse_dev_cap(struct hinic3_hwdev *dev,
struct cfg_cmd_dev_cap *dev_cap, enum func_type type)
{
@@ -382,9 +375,6 @@ static void parse_dev_cap(struct hinic3_hwdev *dev,
if (IS_PPA_TYPE(dev))
parse_ppa_res_cap(dev, cap, dev_cap, type);
-
- if (IS_VBS_TYPE(dev))
- parse_vbs_res_cap(dev, cap, dev_cap, type);
}
static int get_cap_from_fw(struct hinic3_hwdev *dev, enum func_type type)
@@ -414,29 +404,39 @@ static int get_cap_from_fw(struct hinic3_hwdev *dev, enum func_type type)
return 0;
}
-static int hinic3_get_dev_cap(struct hinic3_hwdev *dev)
+int hinic3_get_dev_cap(void *dev)
{
- enum func_type type = HINIC3_FUNC_TYPE(dev);
+ enum func_type type;
int err;
+ struct hinic3_hwdev *hwdev = NULL;
+
+ if (!dev) {
+ pr_err("pointer dev is NULL\n");
+ return -EINVAL;
+ }
+ hwdev = (struct hinic3_hwdev *)dev;
+ type = HINIC3_FUNC_TYPE(hwdev);
switch (type) {
case TYPE_PF:
case TYPE_PPF:
case TYPE_VF:
- err = get_cap_from_fw(dev, type);
- if (err) {
- sdk_err(dev->dev_hdl, "Failed to get PF/PPF capability\n");
+ err = get_cap_from_fw(hwdev, type);
+ if (err != 0) {
+ sdk_err(hwdev->dev_hdl,
+ "Failed to get PF/PPF capability\n");
return err;
}
break;
default:
- sdk_err(dev->dev_hdl, "Unsupported PCI Function type: %d\n",
- type);
+ sdk_err(hwdev->dev_hdl,
+ "Unsupported PCI Function type: %d\n", type);
return -EINVAL;
}
return 0;
}
+EXPORT_SYMBOL(hinic3_get_dev_cap);
int hinic3_get_ppf_timer_cfg(void *hwdev)
{
@@ -1017,21 +1017,21 @@ int init_cfg_mgmt(struct hinic3_hwdev *dev)
cfg_mgmt->hwdev = dev;
err = cfg_init_eq(dev);
- if (err) {
+ if (err != 0) {
sdk_err(dev->dev_hdl, "Failed to init cfg event queue, err: %d\n",
err);
goto free_mgmt_mem;
}
err = cfg_init_interrupt(dev);
- if (err) {
+ if (err != 0) {
sdk_err(dev->dev_hdl, "Failed to init cfg interrupt, err: %d\n",
err);
goto free_eq_mem;
}
err = cfg_enable_interrupt(dev);
- if (err) {
+ if (err != 0) {
sdk_err(dev->dev_hdl, "Failed to enable cfg interrupt, err: %d\n",
err);
goto free_interrupt_mem;
@@ -1089,6 +1089,33 @@ void free_cfg_mgmt(struct hinic3_hwdev *dev)
kfree(cfg_mgmt);
}
+/**
+ * hinic_set_vf_dev_cap - Set max queue num for VF
+ * @hwdev: the HW device for VF
+ */
+int hinic3_init_vf_dev_cap(void *hwdev)
+{
+ struct hinic3_hwdev *dev = NULL;
+ enum func_type type;
+ int err;
+
+ if (!hwdev)
+ return -EFAULT;
+
+ dev = (struct hinic3_hwdev *)hwdev;
+ type = HINIC3_FUNC_TYPE(dev);
+ if (type != TYPE_VF)
+ return -EPERM;
+
+ err = hinic3_get_dev_cap(dev);
+ if (err != 0)
+ return err;
+
+ nic_param_fix(dev);
+
+ return 0;
+}
+
int init_capability(struct hinic3_hwdev *dev)
{
int err;
@@ -1123,7 +1150,7 @@ bool hinic3_support_nic(void *hwdev, struct nic_service_cap *cap)
return false;
if (cap)
- memcpy(cap, &dev->cfg_mgmt->svc_cap.nic_cap, sizeof(*cap));
+ memcpy(cap, &dev->cfg_mgmt->svc_cap.nic_cap, sizeof(struct nic_service_cap));
return true;
}
@@ -1140,7 +1167,7 @@ bool hinic3_support_ppa(void *hwdev, struct ppa_service_cap *cap)
return false;
if (cap)
- memcpy(cap, &dev->cfg_mgmt->svc_cap.ppa_cap, sizeof(*cap));
+ memcpy(cap, &dev->cfg_mgmt->svc_cap.ppa_cap, sizeof(struct ppa_service_cap));
return true;
}
@@ -1174,7 +1201,7 @@ bool hinic3_support_ipsec(void *hwdev, struct ipsec_service_cap *cap)
return false;
if (cap)
- memcpy(cap, &dev->cfg_mgmt->svc_cap.ipsec_cap, sizeof(*cap));
+ memcpy(cap, &dev->cfg_mgmt->svc_cap.ipsec_cap, sizeof(struct ipsec_service_cap));
return true;
}
@@ -1191,7 +1218,7 @@ bool hinic3_support_roce(void *hwdev, struct rdma_service_cap *cap)
return false;
if (cap)
- memcpy(cap, &dev->cfg_mgmt->svc_cap.rdma_cap, sizeof(*cap));
+ memcpy(cap, &dev->cfg_mgmt->svc_cap.rdma_cap, sizeof(struct rdma_service_cap));
return true;
}
@@ -1208,7 +1235,7 @@ bool hinic3_support_fc(void *hwdev, struct fc_service_cap *cap)
return false;
if (cap)
- memcpy(cap, &dev->cfg_mgmt->svc_cap.fc_cap, sizeof(*cap));
+ memcpy(cap, &dev->cfg_mgmt->svc_cap.fc_cap, sizeof(struct fc_service_cap));
return true;
}
@@ -1221,11 +1248,11 @@ bool hinic3_support_rdma(void *hwdev, struct rdma_service_cap *cap)
if (!hwdev)
return false;
- if (!IS_RDMA_TYPE(dev))
+ if (!IS_RDMA_TYPE(dev) && !(IS_RDMA_ENABLE(dev)))
return false;
if (cap)
- memcpy(cap, &dev->cfg_mgmt->svc_cap.rdma_cap, sizeof(*cap));
+ memcpy(cap, &dev->cfg_mgmt->svc_cap.rdma_cap, sizeof(struct rdma_service_cap));
return true;
}
@@ -1242,7 +1269,7 @@ bool hinic3_support_ovs(void *hwdev, struct ovs_service_cap *cap)
return false;
if (cap)
- memcpy(cap, &dev->cfg_mgmt->svc_cap.ovs_cap, sizeof(*cap));
+ memcpy(cap, &dev->cfg_mgmt->svc_cap.ovs_cap, sizeof(struct ovs_service_cap));
return true;
}
@@ -1259,12 +1286,31 @@ bool hinic3_support_vbs(void *hwdev, struct vbs_service_cap *cap)
return false;
if (cap)
- memcpy(cap, &dev->cfg_mgmt->svc_cap.vbs_cap, sizeof(*cap));
+ memcpy(cap, &dev->cfg_mgmt->svc_cap.vbs_cap, sizeof(struct vbs_service_cap));
return true;
}
EXPORT_SYMBOL(hinic3_support_vbs);
+bool hinic3_is_guest_vmsec_enable(void *hwdev)
+{
+ struct hinic3_hwdev *hw_dev = hwdev;
+
+ if (!hwdev) {
+ pr_err("hwdev is null\n");
+ return false;
+ }
+
+ /* vf used in vm */
+ if (IS_VM_SLAVE_HOST(hw_dev) && (hinic3_func_type(hwdev) == TYPE_VF) &&
+ IS_RDMA_TYPE(hw_dev)) {
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL(hinic3_is_guest_vmsec_enable);
+
/* Only PPF support it, PF is not */
bool hinic3_support_toe(void *hwdev, struct toe_service_cap *cap)
{
@@ -1277,7 +1323,7 @@ bool hinic3_support_toe(void *hwdev, struct toe_service_cap *cap)
return false;
if (cap)
- memcpy(cap, &dev->cfg_mgmt->svc_cap.toe_cap, sizeof(*cap));
+ memcpy(cap, &dev->cfg_mgmt->svc_cap.toe_cap, sizeof(struct toe_service_cap));
return true;
}
@@ -1307,6 +1353,17 @@ bool hinic3_get_stateful_enable(void *hwdev)
}
EXPORT_SYMBOL(hinic3_get_stateful_enable);
+bool hinic3_get_timer_enable(void *hwdev)
+{
+ struct hinic3_hwdev *dev = hwdev;
+
+ if (!hwdev)
+ return false;
+
+ return dev->cfg_mgmt->svc_cap.timer_en;
+}
+EXPORT_SYMBOL(hinic3_get_timer_enable);
+
u8 hinic3_host_oq_id_mask(void *hwdev)
{
struct hinic3_hwdev *dev = hwdev;
@@ -1478,3 +1535,27 @@ u8 hinic3_flexq_en(void *hwdev)
}
EXPORT_SYMBOL(hinic3_flexq_en);
+int hinic3_get_fake_vf_info(void *hwdev, u8 *fake_vf_vld,
+ u8 *page_bit, u8 *pf_start_bit, u8 *map_host_id)
+{
+ struct hinic3_hwdev *dev = hwdev;
+
+ if (!dev) {
+ pr_err("Hwdev pointer is NULL for getting pf id start capability\n");
+ return -EINVAL;
+ }
+
+ if (!fake_vf_vld || !page_bit || !pf_start_bit || !map_host_id) {
+ pr_err("Fake vf member pointer is NULL for getting pf id start capability\n");
+ return -EINVAL;
+ }
+
+ *fake_vf_vld = dev->cfg_mgmt->svc_cap.fake_vf_en;
+ *page_bit = dev->cfg_mgmt->svc_cap.fake_vf_page_bit;
+ *pf_start_bit = dev->cfg_mgmt->svc_cap.fake_vf_start_bit;
+ *map_host_id = dev->cfg_mgmt->svc_cap.map_host_id;
+
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_get_fake_vf_info);
+
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h
index 0a27530ba5224..db6e3cab67edf 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_cfg.h
@@ -5,7 +5,7 @@
#define HINIC3_HW_CFG_H
#include <linux/types.h>
-#include "cfg_mgt_comm_pub.h"
+#include "cfg_mgmt_mpu_cmd_defs.h"
#include "hinic3_hwdev.h"
#define CFG_MAX_CMD_TIMEOUT 30000 /* ms */
@@ -16,13 +16,10 @@ enum {
};
/* start position for CEQs allocation, Max number of CEQs is 32 */
-/*lint -save -e849*/
enum {
CFG_RDMA_CEQ_BASE = 0
};
-/*lint -restore*/
-
/* RDMA resource */
#define K_UNIT BIT(10)
#define M_UNIT BIT(20)
@@ -73,7 +70,7 @@ enum {
#define RDMA_RSVD_MRWS 128
#define RDMA_MPT_ENTRY_SZ 64
#define RDMA_NUM_MTTS (1 * G_UNIT)
-#define LOG_MTT_SEG 5
+#define LOG_MTT_SEG 9
#define MTT_ENTRY_SZ 8
#define LOG_RDMARC_SEG 3
@@ -150,7 +147,7 @@ enum intr_type {
struct service_cap {
struct dev_sf_svc_attr sf_svc_attr;
u16 svc_type; /* user input service type */
- u16 chip_svc_type; /* HW supported service type, reference to servic_bit_define_e */
+ u16 chip_svc_type; /* HW supported service type, reference to servic_bit_define */
u8 host_id;
u8 ep_id;
@@ -232,6 +229,12 @@ struct service_cap {
*/
u16 hash_bucket_num;
+ u8 map_host_id;
+ u8 fake_vf_en;
+ u8 fake_vf_start_bit;
+ u8 fake_vf_end_bit;
+ u8 fake_vf_page_bit;
+
struct nic_service_cap nic_cap; /* NIC capability */
struct rdma_service_cap rdma_cap; /* RDMA capability */
struct fc_service_cap fc_cap; /* FC capability */
@@ -328,5 +331,7 @@ int init_capability(struct hinic3_hwdev *dev);
void free_capability(struct hinic3_hwdev *dev);
+int hinic3_init_vf_dev_cap(void *hwdev);
+
#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.c
index f207408b19d60..d8a1a28ba4923 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.c
@@ -20,7 +20,7 @@
#include "hinic3_mgmt.h"
#include "hinic3_hw_cfg.h"
#include "hinic3_cmdq.h"
-#include "comm_msg_intf.h"
+#include "mpu_inband_cmd_defs.h"
#include "hinic3_hw_comm.h"
#define HINIC3_MSIX_CNT_LLI_TIMER_SHIFT 0
@@ -174,7 +174,7 @@ int hinic3_set_interrupt_cfg(void *dev, struct interrupt_info info, u16 channel)
temp_info.msix_index = info.msix_index;
err = hinic3_get_interrupt_cfg(hwdev, &temp_info, channel);
- if (err)
+ if (err != 0)
return -EINVAL;
if (!info.lli_set) {
@@ -228,7 +228,7 @@ int hinic3_set_wq_page_size(void *hwdev, u16 func_idx, u32 page_size,
&page_size_info, &out_size, channel);
if (err || !out_size || page_size_info.head.status) {
sdk_err(((struct hinic3_hwdev *)hwdev)->dev_hdl,
- "Failed to set wq page size, err: %d, status: 0x%x, out_size: 0x%0x, channel: 0x%x\n",
+ "Failed to set wq page size, err: %d, status: 0x%x, out_size: 0x%x, channel: 0x%x\n",
err, page_size_info.head.status, out_size, channel);
return -EFAULT;
}
@@ -378,7 +378,7 @@ int hinic3_set_cmdq_ctxt(struct hinic3_hwdev *hwdev, u8 cmdq_id,
int err;
memset(&cmdq_ctxt, 0, sizeof(cmdq_ctxt));
- memcpy(&cmdq_ctxt.ctxt, ctxt, sizeof(*ctxt));
+ memcpy(&cmdq_ctxt.ctxt, ctxt, sizeof(struct cmdq_ctxt_info));
cmdq_ctxt.func_id = hinic3_global_func_id(hwdev);
cmdq_ctxt.cmdq_id = cmdq_id;
@@ -521,6 +521,31 @@ int hinic3_set_ppf_flr_type(void *hwdev, enum hinic3_ppf_flr_type flr_type)
}
EXPORT_SYMBOL(hinic3_set_ppf_flr_type);
+int hinic3_set_ppf_tbl_hotreplace_flag(void *hwdev, u8 flag)
+{
+ struct comm_cmd_ppf_tbl_htrp_config htr_info = {0};
+ u16 out_size = sizeof(struct comm_cmd_ppf_tbl_htrp_config);
+ struct hinic3_hwdev *dev = hwdev;
+ int ret;
+
+ if (!hwdev) {
+ sdk_err(dev->dev_hdl, "Sdk set ppf table hotreplace flag para is null");
+ return -EINVAL;
+ }
+
+ htr_info.hotreplace_flag = flag;
+ ret = comm_msg_to_mgmt_sync(hwdev, COMM_MGMT_CMD_SET_PPF_TBL_HTR_FLG,
+ &htr_info, sizeof(htr_info), &htr_info, &out_size);
+ if (ret != 0 || htr_info.head.status != 0) {
+ sdk_err(dev->dev_hdl, "Send mbox to mpu failed in sdk, ret:%d, status:%u",
+ ret, htr_info.head.status);
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_set_ppf_tbl_hotreplace_flag);
+
static int hinic3_get_fw_ver(struct hinic3_hwdev *hwdev, enum hinic3_fw_ver_type type,
u8 *mgmt_ver, u8 version_size, u16 channel)
{
@@ -543,9 +568,7 @@ static int hinic3_get_fw_ver(struct hinic3_hwdev *hwdev, enum hinic3_fw_ver_type
return -EIO;
}
- err = snprintf(mgmt_ver, version_size, "%s", fw_ver.ver);
- if (err < 0)
- return -EINVAL;
+ memcpy(mgmt_ver, fw_ver.ver, version_size);
return 0;
}
@@ -569,13 +592,13 @@ int hinic3_get_fw_version(void *hwdev, struct hinic3_fw_version *fw_ver,
err = hinic3_get_fw_ver(hwdev, HINIC3_FW_VER_TYPE_MPU,
fw_ver->mgmt_ver, sizeof(fw_ver->mgmt_ver),
channel);
- if (err)
+ if (err != 0)
return err;
err = hinic3_get_fw_ver(hwdev, HINIC3_FW_VER_TYPE_NPU,
fw_ver->microcode_ver,
sizeof(fw_ver->microcode_ver), channel);
- if (err)
+ if (err != 0)
return err;
return hinic3_get_fw_ver(hwdev, HINIC3_FW_VER_TYPE_BOOT,
@@ -598,8 +621,9 @@ static int hinic3_comm_features_nego(void *hwdev, u8 opcode, u64 *s_feature,
memset(&feature_nego, 0, sizeof(feature_nego));
feature_nego.func_id = hinic3_global_func_id(hwdev);
feature_nego.opcode = opcode;
- if (opcode == MGMT_MSG_CMD_OP_SET)
+ if (opcode == MGMT_MSG_CMD_OP_SET) {
memcpy(feature_nego.s_feature, s_feature, (size * sizeof(u64)));
+ }
err = comm_msg_to_mgmt_sync(hwdev, COMM_MGMT_CMD_FEATURE_NEGO,
&feature_nego, sizeof(feature_nego),
@@ -611,7 +635,7 @@ static int hinic3_comm_features_nego(void *hwdev, u8 opcode, u64 *s_feature,
}
if (opcode == MGMT_MSG_CMD_OP_GET)
- memcpy(s_feature, feature_nego.s_feature, (size * sizeof(u64)));
+ memcpy(s_feature, feature_nego.s_feature, (COMM_MAX_FEATURE_QWORD * sizeof(u64)));
return 0;
}
@@ -679,14 +703,9 @@ int hinic3_func_tmr_bitmap_set(void *hwdev, u16 func_id, bool en)
return 0;
}
-static int ppf_ht_gpa_set(struct hinic3_hwdev *hwdev, struct hinic3_page_addr *pg0,
- struct hinic3_page_addr *pg1)
+static int ppf_ht_gpa_malloc(struct hinic3_hwdev *hwdev, struct hinic3_page_addr *pg0,
+ struct hinic3_page_addr *pg1)
{
- struct comm_cmd_ht_gpa ht_gpa_set;
- u16 out_size = sizeof(ht_gpa_set);
- int ret;
-
- memset(&ht_gpa_set, 0, sizeof(ht_gpa_set));
pg0->virt_addr = dma_zalloc_coherent(hwdev->dev_hdl,
HINIC3_HT_GPA_PAGE_SIZE,
&pg0->phys_addr, GFP_KERNEL);
@@ -703,6 +722,37 @@ static int ppf_ht_gpa_set(struct hinic3_hwdev *hwdev, struct hinic3_page_addr *p
return -EFAULT;
}
+ return 0;
+}
+
+static void ppf_ht_gpa_free(struct hinic3_hwdev *hwdev, struct hinic3_page_addr *pg0,
+ struct hinic3_page_addr *pg1)
+{
+ if (pg0->virt_addr) {
+ dma_free_coherent(hwdev->dev_hdl, HINIC3_HT_GPA_PAGE_SIZE, pg0->virt_addr,
+ (dma_addr_t)(pg0->phys_addr));
+ pg0->virt_addr = NULL;
+ }
+ if (pg1->virt_addr) {
+ dma_free_coherent(hwdev->dev_hdl, HINIC3_HT_GPA_PAGE_SIZE, pg1->virt_addr,
+ (dma_addr_t)(pg1->phys_addr));
+ pg1->virt_addr = NULL;
+ }
+}
+
+static int ppf_ht_gpa_set(struct hinic3_hwdev *hwdev, struct hinic3_page_addr *pg0,
+ struct hinic3_page_addr *pg1)
+{
+ struct comm_cmd_ht_gpa ht_gpa_set;
+ u16 out_size = sizeof(ht_gpa_set);
+ int ret;
+
+ memset(&ht_gpa_set, 0, sizeof(ht_gpa_set));
+
+ ret = ppf_ht_gpa_malloc(hwdev, pg0, pg1);
+ if (ret)
+ return ret;
+
ht_gpa_set.host_id = hinic3_host_id(hwdev);
ht_gpa_set.page_pa0 = pg0->phys_addr;
ht_gpa_set.page_pa1 = pg1->phys_addr;
@@ -751,22 +801,8 @@ int hinic3_ppf_ht_gpa_init(void *dev)
break;
}
- for (j = 0; j < i; j++) {
- if (page_addr0[j].virt_addr) {
- dma_free_coherent(hwdev->dev_hdl,
- HINIC3_HT_GPA_PAGE_SIZE,
- page_addr0[j].virt_addr,
- (dma_addr_t)page_addr0[j].phys_addr);
- page_addr0[j].virt_addr = NULL;
- }
- if (page_addr1[j].virt_addr) {
- dma_free_coherent(hwdev->dev_hdl,
- HINIC3_HT_GPA_PAGE_SIZE,
- page_addr1[j].virt_addr,
- (dma_addr_t)page_addr1[j].phys_addr);
- page_addr1[j].virt_addr = NULL;
- }
- }
+ for (j = 0; j < i; j++)
+ ppf_ht_gpa_free(hwdev, &page_addr0[j], &page_addr1[j]);
if (i >= HINIC3_PPF_HT_GPA_SET_RETRY_TIMES) {
sdk_err(hwdev->dev_hdl, "PPF ht gpa init failed, retry times: %d\n",
@@ -855,16 +891,16 @@ EXPORT_SYMBOL(hinic3_ppf_tmr_stop);
static int mqm_eqm_try_alloc_mem(struct hinic3_hwdev *hwdev, u32 page_size,
u32 page_num)
{
- struct hinic3_page_addr *page_addr = hwdev->mqm_att.brm_srch_page_addr;
+ struct hinic3_dma_addr_align *page_addr = hwdev->mqm_att.brm_srch_page_addr;
u32 valid_num = 0;
u32 flag = 1;
u32 i = 0;
+ int err;
for (i = 0; i < page_num; i++) {
- page_addr->virt_addr =
- dma_zalloc_coherent(hwdev->dev_hdl, page_size,
- &page_addr->phys_addr, GFP_KERNEL);
- if (!page_addr->virt_addr) {
+ err = hinic3_dma_zalloc_coherent_align(hwdev->dev_hdl, page_size,
+ page_size, GFP_KERNEL, page_addr);
+ if (err) {
flag = 0;
break;
}
@@ -878,9 +914,7 @@ static int mqm_eqm_try_alloc_mem(struct hinic3_hwdev *hwdev, u32 page_size,
} else {
page_addr = hwdev->mqm_att.brm_srch_page_addr;
for (i = 0; i < valid_num; i++) {
- dma_free_coherent(hwdev->dev_hdl, page_size,
- page_addr->virt_addr,
- (dma_addr_t)page_addr->phys_addr);
+ hinic3_dma_free_coherent_align(hwdev->dev_hdl, page_addr);
page_addr++;
}
return -EFAULT;
@@ -924,15 +958,12 @@ static int mqm_eqm_alloc_page_mem(struct hinic3_hwdev *hwdev)
static void mqm_eqm_free_page_mem(struct hinic3_hwdev *hwdev)
{
u32 i;
- struct hinic3_page_addr *page_addr;
- u32 page_size;
+ struct hinic3_dma_addr_align *page_addr;
- page_size = hwdev->mqm_att.page_size;
page_addr = hwdev->mqm_att.brm_srch_page_addr;
for (i = 0; i < hwdev->mqm_att.page_num; i++) {
- dma_free_coherent(hwdev->dev_hdl, page_size,
- page_addr->virt_addr, (dma_addr_t)(page_addr->phys_addr));
+ hinic3_dma_free_coherent_align(hwdev->dev_hdl, page_addr);
page_addr++;
}
}
@@ -961,12 +992,11 @@ static int mqm_eqm_set_cfg_2_hw(struct hinic3_hwdev *hwdev, u8 valid)
}
#define EQM_DATA_BUF_SIZE 1024
-#define MQM_ATT_PAGE_NUM 128
static int mqm_eqm_set_page_2_hw(struct hinic3_hwdev *hwdev)
{
struct comm_cmd_eqm_search_gpa *info = NULL;
- struct hinic3_page_addr *page_addr = NULL;
+ struct hinic3_dma_addr_align *page_addr = NULL;
void *send_buf = NULL;
u16 send_buf_size;
u32 i;
@@ -995,7 +1025,7 @@ static int mqm_eqm_set_page_2_hw(struct hinic3_hwdev *hwdev)
cmd = COMM_MGMT_CMD_SET_MQM_SRCH_GPA;
for (i = 0; i < hwdev->mqm_att.page_num; i++) {
/* gpa align to 4K, save gpa[31:12] */
- gpa = page_addr->phys_addr >> 12;
+ gpa = page_addr->align_paddr >> 12;
gpa_hi52[num] = gpa;
num++;
if (num == MQM_ATT_PAGE_NUM) {
@@ -1085,7 +1115,7 @@ static int mqm_eqm_init(struct hinic3_hwdev *hwdev)
hwdev->mqm_att.page_num = 0;
hwdev->mqm_att.brm_srch_page_addr =
- kcalloc(hwdev->mqm_att.chunk_num, sizeof(struct hinic3_page_addr), GFP_KERNEL);
+ kcalloc(hwdev->mqm_att.chunk_num, sizeof(struct hinic3_dma_addr_align), GFP_KERNEL);
if (!(hwdev->mqm_att.brm_srch_page_addr)) {
sdk_err(hwdev->dev_hdl, "Alloc virtual mem failed\r\n");
return -EFAULT;
@@ -1245,7 +1275,7 @@ static int wait_cmdq_stop(struct hinic3_hwdev *hwdev)
return err;
}
-static int hinic3_rx_tx_flush(struct hinic3_hwdev *hwdev, u16 channel)
+static int hinic3_rx_tx_flush(struct hinic3_hwdev *hwdev, u16 channel, bool wait_io)
{
struct hinic3_hwif *hwif = hwdev->hwif;
struct comm_cmd_clear_doorbell clear_db;
@@ -1254,7 +1284,7 @@ static int hinic3_rx_tx_flush(struct hinic3_hwdev *hwdev, u16 channel)
int err;
int ret = 0;
- if (HINIC3_FUNC_TYPE(hwdev) != TYPE_VF)
+ if ((HINIC3_FUNC_TYPE(hwdev) != TYPE_VF) && wait_io)
msleep(100); /* wait ucode 100 ms stop I/O */
err = wait_cmdq_stop(hwdev);
@@ -1317,7 +1347,7 @@ static int hinic3_rx_tx_flush(struct hinic3_hwdev *hwdev, u16 channel)
return ret;
}
-int hinic3_func_rx_tx_flush(void *hwdev, u16 channel)
+int hinic3_func_rx_tx_flush(void *hwdev, u16 channel, bool wait_io)
{
struct hinic3_hwdev *dev = hwdev;
@@ -1327,7 +1357,7 @@ int hinic3_func_rx_tx_flush(void *hwdev, u16 channel)
if (dev->chip_present_flag == 0)
return 0;
- return hinic3_rx_tx_flush(dev, channel);
+ return hinic3_rx_tx_flush(dev, channel, wait_io);
}
EXPORT_SYMBOL(hinic3_func_rx_tx_flush);
@@ -1383,7 +1413,7 @@ int hinic3_get_hw_pf_infos(void *hwdev, struct hinic3_hw_pf_infos *infos,
goto free_buf;
}
- memcpy(infos, &pf_infos->infos, sizeof(*infos));
+ memcpy(infos, &pf_infos->infos, sizeof(struct hinic3_hw_pf_infos));
free_buf:
kfree(pf_infos);
@@ -1407,7 +1437,7 @@ int hinic3_get_global_attr(void *hwdev, struct comm_global_attr *attr)
return -EIO;
}
- memcpy(attr, &get_attr.attr, sizeof(*attr));
+ memcpy(attr, &get_attr.attr, sizeof(struct comm_global_attr));
return 0;
}
@@ -1477,7 +1507,7 @@ int hinic3_get_sml_table_info(void *hwdev, u32 tbl_id, u8 *node_id, u8 *instance
int hinic3_activate_firmware(void *hwdev, u8 cfg_index)
{
- struct hinic3_cmd_activate_firmware activate_msg;
+ struct cmd_active_firmware activate_msg;
u16 out_size = sizeof(activate_msg);
int err;
@@ -1509,7 +1539,7 @@ int hinic3_activate_firmware(void *hwdev, u8 cfg_index)
int hinic3_switch_config(void *hwdev, u8 cfg_index)
{
- struct hinic3_cmd_switch_config switch_cfg;
+ struct cmd_switch_cfg switch_cfg;
u16 out_size = sizeof(switch_cfg);
int err;
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.h
index be9e4a6b24f92..e031ec4ccd3d1 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_comm.h
@@ -6,7 +6,7 @@
#include <linux/types.h>
-#include "comm_msg_intf.h"
+#include "mpu_inband_cmd_defs.h"
#include "hinic3_hwdev.h"
#define MSG_TO_MGMT_SYNC_RETURN_ERR(err, out_size, status) \
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_mt.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_mt.c
index 79e4dacbd0c99..baa1ce0cb2345 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_mt.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hw_mt.c
@@ -5,7 +5,7 @@
#include "hinic3_mt.h"
#include "hinic3_crm.h"
#include "hinic3_hw.h"
-#include "hinic3_comm_cmd.h"
+#include "mpu_inband_cmd.h"
#include "hinic3_hw_mt.h"
#define HINIC3_CMDQ_BUF_MAX_SIZE 2048U
@@ -14,8 +14,10 @@
#define MSG_MAX_IN_SIZE (2048 * 1024)
#define MSG_MAX_OUT_SIZE (2048 * 1024)
+#define API_CSR_MAX_RD_LEN (4 * 1024 * 1024)
+
/* completion timeout interval, unit is millisecond */
-#define MGMT_MSG_UPDATE_TIMEOUT 50000U
+#define MGMT_MSG_UPDATE_TIMEOUT 200000U
void free_buff_in(void *hwdev, const struct msg_module *nt_msg, void *buf_in)
{
@@ -127,6 +129,9 @@ int copy_buf_out_to_user(struct msg_module *nt_msg,
int ret = 0;
void *msg_out = NULL;
+ if (out_size == 0 || !buf_out)
+ return 0;
+
if (nt_msg->module == SEND_TO_NPU &&
!nt_msg->npu_cmd.direct_resp)
msg_out = ((struct hinic3_cmd_buf *)buf_out)->buf;
@@ -177,7 +182,7 @@ int get_hw_driver_stats(struct hinic3_lld_dev *lld_dev, const void *buf_in, u32
void *buf_out, u32 *out_size)
{
return hinic3_dbg_get_hw_stats(hinic3_get_sdk_hwdev_by_lld(lld_dev),
- buf_out, (u16 *)out_size);
+ buf_out, out_size);
}
int clear_hw_driver_stats(struct hinic3_lld_dev *lld_dev, const void *buf_in, u32 in_size,
@@ -220,7 +225,7 @@ int get_chip_faults_stats(struct hinic3_lld_dev *lld_dev, const void *buf_in, u3
if (!buf_in || !buf_out || *out_size != sizeof(*fault_info) ||
in_size != sizeof(*fault_info)) {
- pr_err("Unexpect out buf size from user: %d, expect: %lu\n",
+ pr_err("Unexpect out buf size from user: %u, expect: %lu\n",
*out_size, sizeof(*fault_info));
return -EFAULT;
}
@@ -251,6 +256,7 @@ static int api_csr_read(void *hwdev, struct msg_module *nt_msg,
void *buf_in, u32 in_size, void *buf_out, u32 *out_size)
{
struct up_log_msg_st *up_log_msg = (struct up_log_msg_st *)buf_in;
+ u8 *buf_out_tmp = (u8 *)buf_out;
int ret = 0;
u32 rd_len;
u32 rd_addr;
@@ -272,7 +278,7 @@ static int api_csr_read(void *hwdev, struct msg_module *nt_msg,
for (i = 0; i < rd_cnt; i++) {
ret = hinic3_api_csr_rd32(hwdev, node_id,
rd_addr + offset,
- (u32 *)(((u8 *)buf_out) + offset));
+ (u32 *)(buf_out_tmp + offset));
if (ret) {
pr_err("Csr rd fail, err: %d, node_id: %u, csr addr: 0x%08x\n",
ret, node_id, rd_addr + offset);
@@ -299,7 +305,8 @@ static int api_csr_write(void *hwdev, struct msg_module *nt_msg,
u32 i;
u8 *data = NULL;
- if (!buf_in || in_size != sizeof(*csr_write_msg) || csr_write_msg->rd_len % DW_WIDTH != 0)
+ if (!buf_in || in_size != sizeof(*csr_write_msg) || csr_write_msg->rd_len == 0 ||
+ csr_write_msg->rd_len > API_CSR_MAX_RD_LEN || csr_write_msg->rd_len % DW_WIDTH != 0)
return -EINVAL;
rd_len = csr_write_msg->rd_len;
@@ -353,7 +360,7 @@ int send_to_mpu(void *hwdev, struct msg_module *nt_msg,
if (nt_msg->mpu_cmd.api_type == API_TYPE_MBOX)
ret = hinic3_msg_to_mgmt_sync(hwdev, mod, cmd, buf_in, (u16)in_size,
- buf_out, (u16 *)out_size, timeout,
+ buf_out, (u16 *)(u8 *)out_size, timeout,
HINIC3_CHANNEL_DEFAULT);
else
ret = hinic3_clp_to_mgmt(hwdev, mod, cmd, buf_in, (u16)in_size,
@@ -372,10 +379,10 @@ int send_to_mpu(void *hwdev, struct msg_module *nt_msg,
if (hinic3_pcie_itf_id(hwdev) != SPU_HOST_ID)
ret = hinic3_msg_to_mgmt_api_chain_sync(hwdev, mod, cmd, buf_in,
(u16)in_size, buf_out,
- (u16 *)out_size, timeout);
+ (u16 *)(u8 *)out_size, timeout);
else
ret = hinic3_msg_to_mgmt_sync(hwdev, mod, cmd, buf_in, (u16)in_size,
- buf_out, (u16 *)out_size, timeout,
+ buf_out, (u16 *)(u8 *)out_size, timeout,
HINIC3_CHANNEL_DEFAULT);
if (ret) {
pr_err("Message to mgmt api chain cpu return fail, mod: %d, cmd: %u\n",
@@ -383,7 +390,7 @@ int send_to_mpu(void *hwdev, struct msg_module *nt_msg,
return ret;
}
} else {
- pr_err("Unsupported api_type %d\n", nt_msg->mpu_cmd.api_type);
+ pr_err("Unsupported api_type %u\n", nt_msg->mpu_cmd.api_type);
return -EINVAL;
}
@@ -562,16 +569,17 @@ int send_to_sm(void *hwdev, struct msg_module *nt_msg,
{
struct sm_in_st *sm_in = buf_in;
struct sm_out_st *sm_out = buf_out;
- u32 msg_formate = nt_msg->msg_formate;
- int index, num_cmds = sizeof(sm_module_cmd_handle) /
- sizeof(sm_module_cmd_handle[0]);
+ u32 msg_formate;
+ int index, num_cmds = ARRAY_LEN(sm_module_cmd_handle);
int ret = 0;
- if (!buf_in || !buf_out || in_size != sizeof(*sm_in) || *out_size != sizeof(*sm_out)) {
+ if (!nt_msg || !buf_in || !buf_out ||
+ in_size != sizeof(*sm_in) || *out_size != sizeof(*sm_out)) {
pr_err("Unexpect out buf size :%u, in buf size: %u\n",
*out_size, in_size);
return -EINVAL;
}
+ msg_formate = nt_msg->msg_formate;
for (index = 0; index < num_cmds; index++) {
if (msg_formate != sm_module_cmd_handle[index].sm_cmd_name)
@@ -587,9 +595,8 @@ int send_to_sm(void *hwdev, struct msg_module *nt_msg,
pr_err("Can't find callback for %d\n", msg_formate);
return -EINVAL;
}
-
if (ret != 0)
- pr_err("Get sm information fail, id:%u, instance:%u, node:%u\n",
+ pr_err("Get sm information fail, id:%d, instance:%d, node:%d\n",
sm_in->id, sm_in->instance, sm_in->node);
*out_size = sizeof(struct sm_out_st);
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.c
index d035790d8ed23..620136acb4169 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.c
@@ -28,7 +28,9 @@
#include "hinic3_mbox.h"
#include "hinic3_cmdq.h"
#include "hinic3_hw_cfg.h"
+#include "hinic3_multi_host_mgmt.h"
#include "hinic3_hw_comm.h"
+#include "hinic3_cqm.h"
#include "hinic3_prof_adap.h"
#include "hinic3_devlink.h"
#include "hinic3_hwdev.h"
@@ -138,7 +140,12 @@ EXPORT_SYMBOL(hinic3_get_slave_host_enable);
int hinic3_get_slave_bitmap(void *hwdev, u8 *slave_host_bitmap)
{
struct hinic3_hwdev *dev = hwdev;
- struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
+ struct service_cap *cap = NULL;
+
+ if (!dev || !slave_host_bitmap)
+ return -EINVAL;
+
+ cap = &dev->cfg_mgmt->svc_cap;
if (HINIC3_FUNC_TYPE(dev) != TYPE_PPF) {
sdk_warn(dev->dev_hdl, "hwdev should be ppf\n");
@@ -151,7 +158,7 @@ int hinic3_get_slave_bitmap(void *hwdev, u8 *slave_host_bitmap)
}
EXPORT_SYMBOL(hinic3_get_slave_bitmap);
-static void set_func_host_mode(struct hinic3_hwdev *hwdev, enum hinic3_func_mode mode)
+void set_func_host_mode(struct hinic3_hwdev *hwdev, enum hinic3_func_mode mode)
{
switch (mode) {
case FUNC_MOD_MULTI_BM_MASTER:
@@ -181,11 +188,6 @@ static void hinic3_init_host_mode_pre(struct hinic3_hwdev *hwdev)
struct service_cap *cap = &hwdev->cfg_mgmt->svc_cap;
u8 host_id = hwdev->hwif->attr.pci_intf_idx;
- if (HINIC3_FUNC_TYPE(hwdev) == TYPE_VF) {
- set_func_host_mode(hwdev, FUNC_MOD_NORMAL_HOST);
- return;
- }
-
switch (cap->srv_multi_host_mode) {
case HINIC3_SDI_MODE_BM:
if (host_id == cap->master_host_id)
@@ -205,28 +207,6 @@ static void hinic3_init_host_mode_pre(struct hinic3_hwdev *hwdev)
}
}
-static int hinic3_multi_host_init(struct hinic3_hwdev *hwdev)
-{
- if (!IS_MULTI_HOST(hwdev) || !HINIC3_IS_PPF(hwdev))
- return 0;
-
- if (IS_SLAVE_HOST(hwdev))
- set_slave_host_enable(hwdev, hinic3_pcie_itf_id(hwdev), true);
-
- return 0;
-}
-
-static int hinic3_multi_host_free(struct hinic3_hwdev *hwdev)
-{
- if (!IS_MULTI_HOST(hwdev) || !HINIC3_IS_PPF(hwdev))
- return 0;
-
- if (IS_SLAVE_HOST(hwdev))
- set_slave_host_enable(hwdev, hinic3_pcie_itf_id(hwdev), false);
-
- return 0;
-}
-
static u8 hinic3_nic_sw_aeqe_handler(void *hwdev, u8 event, u8 *data)
{
struct hinic3_hwdev *dev = hwdev;
@@ -524,13 +504,13 @@ static void sw_watchdog_timeout_info_show(struct hinic3_hwdev *hwdev,
sdk_err(hwdev->dev_hdl, "Mgmt pc: 0x%llx, elr: 0x%llx, spsr: 0x%llx, far: 0x%llx, esr: 0x%llx, xzr: 0x%llx\n",
watchdog_info->pc, watchdog_info->elr, watchdog_info->spsr, watchdog_info->far,
- watchdog_info->esr, watchdog_info->xzr); /*lint !e10 !e26 */
+ watchdog_info->esr, watchdog_info->xzr);
sdk_err(hwdev->dev_hdl, "Mgmt register info\n");
reg = &watchdog_info->x30;
for (i = 0; i <= X_CSR_INDEX; i++)
sdk_err(hwdev->dev_hdl, "x%02u:0x%llx\n",
- X_CSR_INDEX - i, reg[i]); /*lint !e661 !e662 */
+ X_CSR_INDEX - i, reg[i]);
if (watchdog_info->stack_actlen <= DATA_LEN_1K) {
stack_len = watchdog_info->stack_actlen;
@@ -816,7 +796,7 @@ static int init_aeqs_msix_attr(struct hinic3_hwdev *hwdev)
info.msix_index = eq->eq_irq.msix_entry_idx;
err = hinic3_set_interrupt_cfg_direct(hwdev, &info,
HINIC3_CHANNEL_COMM);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Set msix attr for aeq %d failed\n",
q_id);
return -EFAULT;
@@ -845,7 +825,7 @@ static int init_ceqs_msix_attr(struct hinic3_hwdev *hwdev)
info.msix_index = eq->eq_irq.msix_entry_idx;
err = hinic3_set_interrupt_cfg(hwdev, info,
HINIC3_CHANNEL_COMM);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Set msix attr for ceq %u failed\n",
q_id);
return -EFAULT;
@@ -863,7 +843,7 @@ static int hinic3_comm_clp_to_mgmt_init(struct hinic3_hwdev *hwdev)
return 0;
err = hinic3_clp_pf_to_mgmt_init(hwdev);
- if (err)
+ if (err != 0)
return err;
return 0;
@@ -891,7 +871,7 @@ static int hinic3_comm_aeqs_init(struct hinic3_hwdev *hwdev)
}
err = hinic3_alloc_irqs(hwdev, SERVICE_T_INTF, num_aeqs, aeq_irqs,
&resp_num_irq);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to alloc aeq irqs, num_aeqs: %u\n",
num_aeqs);
return err;
@@ -904,7 +884,7 @@ static int hinic3_comm_aeqs_init(struct hinic3_hwdev *hwdev)
}
err = hinic3_aeqs_init(hwdev, num_aeqs, aeq_irqs);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init aeqs\n");
goto aeqs_init_err;
}
@@ -923,7 +903,7 @@ static void hinic3_comm_aeqs_free(struct hinic3_hwdev *hwdev)
struct irq_info aeq_irqs[HINIC3_MAX_AEQS] = {{0} };
u16 num_irqs, i;
- hinic3_get_aeq_irqs(hwdev, aeq_irqs, &num_irqs);
+ hinic3_get_aeq_irqs(hwdev, (struct irq_info *)aeq_irqs, &num_irqs);
hinic3_aeqs_free(hwdev);
@@ -946,7 +926,7 @@ static int hinic3_comm_ceqs_init(struct hinic3_hwdev *hwdev)
err = hinic3_alloc_irqs(hwdev, SERVICE_T_INTF, num_ceqs, ceq_irqs,
&resp_num_irq);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to alloc ceq irqs, num_ceqs: %u\n",
num_ceqs);
return err;
@@ -959,7 +939,7 @@ static int hinic3_comm_ceqs_init(struct hinic3_hwdev *hwdev)
}
err = hinic3_ceqs_init(hwdev, num_ceqs, ceq_irqs);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl,
"Failed to init ceqs, err:%d\n", err);
goto ceqs_init_err;
@@ -980,7 +960,7 @@ static void hinic3_comm_ceqs_free(struct hinic3_hwdev *hwdev)
u16 num_irqs;
int i;
- hinic3_get_ceq_irqs(hwdev, ceq_irqs, &num_irqs);
+ hinic3_get_ceq_irqs(hwdev, (struct irq_info *)ceq_irqs, &num_irqs);
hinic3_ceqs_free(hwdev);
@@ -993,7 +973,7 @@ static int hinic3_comm_func_to_func_init(struct hinic3_hwdev *hwdev)
int err;
err = hinic3_func_to_func_init(hwdev);
- if (err)
+ if (err != 0)
return err;
hinic3_aeq_register_hw_cb(hwdev, hwdev, HINIC3_MBX_FROM_FUNC,
@@ -1001,14 +981,13 @@ static int hinic3_comm_func_to_func_init(struct hinic3_hwdev *hwdev)
hinic3_aeq_register_hw_cb(hwdev, hwdev, HINIC3_MSG_FROM_MGMT_CPU,
hinic3_mgmt_msg_aeqe_handler);
- if (!HINIC3_IS_VF(hwdev))
- hinic3_register_pf_mbox_cb(hwdev, HINIC3_MOD_COMM,
- hwdev,
- pf_handle_vf_comm_mbox);
- else
- hinic3_register_vf_mbox_cb(hwdev, HINIC3_MOD_COMM,
- hwdev,
- vf_handle_pf_comm_mbox);
+ if (!HINIC3_IS_VF(hwdev)) {
+ hinic3_register_pf_mbox_cb(hwdev, HINIC3_MOD_COMM, hwdev, pf_handle_vf_comm_mbox);
+ hinic3_register_pf_mbox_cb(hwdev, HINIC3_MOD_SW_FUNC,
+ hwdev, sw_func_pf_mbox_handler);
+ } else {
+ hinic3_register_vf_mbox_cb(hwdev, HINIC3_MOD_COMM, hwdev, vf_handle_pf_comm_mbox);
+ }
set_bit(HINIC3_HWDEV_MBOX_INITED, &hwdev->func_state);
@@ -1042,7 +1021,7 @@ static int hinic3_comm_pf_to_mgmt_init(struct hinic3_hwdev *hwdev)
return 0;
err = hinic3_pf_to_mgmt_init(hwdev);
- if (err)
+ if (err != 0)
return err;
hinic3_register_mgmt_msg_cb(hwdev, HINIC3_MOD_COMM, hwdev,
@@ -1074,7 +1053,7 @@ static int hinic3_comm_cmdqs_init(struct hinic3_hwdev *hwdev)
int err;
err = hinic3_cmdqs_init(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init cmd queues\n");
return err;
}
@@ -1082,7 +1061,7 @@ static int hinic3_comm_cmdqs_init(struct hinic3_hwdev *hwdev)
hinic3_ceq_register_cb(hwdev, hwdev, HINIC3_CMDQ, hinic3_cmdq_ceq_handler);
err = hinic3_set_cmdq_depth(hwdev, HINIC3_CMDQ_DEPTH);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to set cmdq depth\n");
goto set_cmdq_depth_err;
}
@@ -1109,7 +1088,7 @@ static void hinic3_comm_cmdqs_free(struct hinic3_hwdev *hwdev)
static void hinic3_sync_mgmt_func_state(struct hinic3_hwdev *hwdev)
{
- hinic3_set_pf_status(hwdev->hwif, HINIC3_PF_STATUS_ACTIVE_FLAG);
+ hinic3_set_pf_status(hwdev->hwif, HINIC3_PF_STATUS_ACTIVE_FLAG);
}
static void hinic3_unsync_mgmt_func_state(struct hinic3_hwdev *hwdev)
@@ -1127,12 +1106,12 @@ static int init_basic_attributes(struct hinic3_hwdev *hwdev)
err = hinic3_get_board_info(hwdev, &hwdev->board_info,
HINIC3_CHANNEL_COMM);
- if (err)
+ if (err != 0)
return err;
err = hinic3_get_comm_features(hwdev, hwdev->features,
COMM_MAX_FEATURE_QWORD);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Get comm features failed\n");
return err;
}
@@ -1144,7 +1123,7 @@ static int init_basic_attributes(struct hinic3_hwdev *hwdev)
hwdev->features[i] &= drv_features[i];
err = hinic3_get_global_attr(hwdev, &hwdev->glb_attr);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to get global attribute\n");
return err;
}
@@ -1164,19 +1143,19 @@ static int init_basic_mgmt_channel(struct hinic3_hwdev *hwdev)
int err;
err = hinic3_comm_aeqs_init(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init async event queues\n");
return err;
}
err = hinic3_comm_func_to_func_init(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init mailbox\n");
goto func_to_func_init_err;
}
err = init_aeqs_msix_attr(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init aeqs msix attr\n");
goto aeqs_msix_attr_init_err;
}
@@ -1203,13 +1182,13 @@ static int init_pf_mgmt_channel(struct hinic3_hwdev *hwdev)
int err;
err = hinic3_comm_clp_to_mgmt_init(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init clp\n");
return err;
}
err = hinic3_comm_pf_to_mgmt_init(hwdev);
- if (err) {
+ if (err != 0) {
hinic3_comm_clp_to_mgmt_free(hwdev);
sdk_err(hwdev->dev_hdl, "Failed to init pf to mgmt\n");
return err;
@@ -1233,14 +1212,14 @@ static int init_mgmt_channel_post(struct hinic3_hwdev *hwdev)
*/
if (HINIC3_IS_PPF(hwdev)) {
err = hinic3_mbox_init_host_msg_channel(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init mbox host channel\n");
return err;
}
}
err = init_pf_mgmt_channel(hwdev);
- if (err)
+ if (err != 0)
return err;
return 0;
@@ -1256,19 +1235,19 @@ static int init_cmdqs_channel(struct hinic3_hwdev *hwdev)
int err;
err = dma_attr_table_init(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init dma attr table\n");
goto dma_attr_init_err;
}
err = hinic3_comm_ceqs_init(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init completion event queues\n");
goto ceqs_init_err;
}
err = init_ceqs_msix_attr(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init ceqs msix attr\n");
goto init_ceq_msix_err;
}
@@ -1284,13 +1263,13 @@ static int init_cmdqs_channel(struct hinic3_hwdev *hwdev)
sdk_info(hwdev->dev_hdl, "WQ page size: 0x%x\n", hwdev->wq_page_size);
err = hinic3_set_wq_page_size(hwdev, hinic3_global_func_id(hwdev),
hwdev->wq_page_size, HINIC3_CHANNEL_COMM);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to set wq page size\n");
goto init_wq_pg_size_err;
}
err = hinic3_comm_cmdqs_init(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init cmd queues\n");
goto cmdq_init_err;
}
@@ -1328,28 +1307,28 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *hwdev)
int err;
err = init_basic_mgmt_channel(hwdev);
- if (err)
+ if (err != 0)
return err;
err = hinic3_func_reset(hwdev, hinic3_global_func_id(hwdev),
HINIC3_COMM_RES, HINIC3_CHANNEL_COMM);
- if (err)
+ if (err != 0)
goto func_reset_err;
err = init_basic_attributes(hwdev);
- if (err)
+ if (err != 0)
goto init_basic_attr_err;
err = init_mgmt_channel_post(hwdev);
- if (err)
+ if (err != 0)
goto init_mgmt_channel_post_err;
err = hinic3_set_func_svc_used_state(hwdev, SVC_T_COMM, 1, HINIC3_CHANNEL_COMM);
- if (err)
+ if (err != 0)
goto set_used_state_err;
err = init_cmdqs_channel(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init cmdq channel\n");
goto init_cmdqs_channel_err;
}
@@ -1363,7 +1342,7 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *hwdev)
err = hinic3_aeq_register_swe_cb(hwdev, hwdev, HINIC3_STATELESS_EVENT,
hinic3_nic_sw_aeqe_handler);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl,
"Failed to register sw aeqe handler\n");
goto register_ucode_aeqe_err;
@@ -1408,7 +1387,7 @@ static void hinic3_auto_sync_time_work(struct work_struct *work)
int err;
err = hinic3_sync_time(hwdev, ossl_get_real_time());
- if (err)
+ if (err != 0)
sdk_err(hwdev->dev_hdl, "Synchronize UTC time to firmware failed, errno:%d.\n",
err);
@@ -1478,6 +1457,7 @@ static int init_hwdew(struct hinic3_init_para *para)
hwdev->poll = para->poll;
hwdev->probe_fault_level = para->probe_fault_level;
hwdev->func_state = 0;
+ sema_init(&hwdev->ppf_sem, 1);
hwdev->chip_fault_stats = vzalloc(HINIC3_CHIP_FAULT_SIZE);
if (!hwdev->chip_fault_stats)
@@ -1492,6 +1472,7 @@ static int init_hwdew(struct hinic3_init_para *para)
return 0;
alloc_chip_fault_stats_err:
+ sema_deinit(&hwdev->ppf_sem);
para->probe_fault_level = hwdev->probe_fault_level;
kfree(hwdev);
*para->hwdev = NULL;
@@ -1500,18 +1481,17 @@ alloc_chip_fault_stats_err:
int hinic3_init_hwdev(struct hinic3_init_para *para)
{
- struct hinic3_hwdev *hwdev;
+ struct hinic3_hwdev *hwdev = NULL;
int err;
err = init_hwdew(para);
- if (err)
+ if (err != 0)
return err;
hwdev = *para->hwdev;
-
err = hinic3_init_hwif(hwdev, para->cfg_reg_base, para->intr_reg_base, para->mgmt_reg_base,
para->db_base_phy, para->db_base, para->db_dwqe_len);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init hwif\n");
goto init_hwif_err;
}
@@ -1529,45 +1509,45 @@ int hinic3_init_hwdev(struct hinic3_init_para *para)
hinic3_init_heartbeat_detect(hwdev);
err = init_cfg_mgmt(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init config mgmt\n");
goto init_cfg_mgmt_err;
}
err = hinic3_init_comm_ch(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init communication channel\n");
goto init_comm_ch_err;
}
#ifdef HAVE_DEVLINK_FLASH_UPDATE_PARAMS
err = hinic3_init_devlink(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init devlink\n");
goto init_devlink_err;
}
#endif
err = init_capability(hwdev);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init capability\n");
goto init_cap_err;
}
hinic3_init_host_mode_pre(hwdev);
- err = hinic3_multi_host_init(hwdev);
- if (err) {
+ err = hinic3_multi_host_mgmt_init(hwdev);
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to init function mode\n");
goto init_multi_host_fail;
}
err = hinic3_init_ppf_work(hwdev);
- if (err)
+ if (err != 0)
goto init_ppf_work_fail;
err = hinic3_set_comm_features(hwdev, hwdev->features, COMM_MAX_FEATURE_QWORD);
- if (err) {
+ if (err != 0) {
sdk_err(hwdev->dev_hdl, "Failed to set comm features\n");
goto set_feature_err;
}
@@ -1578,7 +1558,7 @@ set_feature_err:
hinic3_free_ppf_work(hwdev);
init_ppf_work_fail:
- hinic3_multi_host_free(hwdev);
+ hinic3_multi_host_mgmt_free(hwdev);
init_multi_host_fail:
free_capability(hwdev);
@@ -1623,9 +1603,9 @@ void hinic3_free_hwdev(void *hwdev)
hinic3_free_ppf_work(dev);
- hinic3_multi_host_free(dev);
+ hinic3_multi_host_mgmt_free(dev);
- hinic3_func_rx_tx_flush(hwdev, HINIC3_CHANNEL_COMM);
+ hinic3_func_rx_tx_flush(hwdev, HINIC3_CHANNEL_COMM, true);
free_capability(dev);
@@ -1698,7 +1678,7 @@ void *hinic3_get_service_adapter(void *hwdev, enum hinic3_service_type type)
}
EXPORT_SYMBOL(hinic3_get_service_adapter);
-int hinic3_dbg_get_hw_stats(const void *hwdev, u8 *hw_stats, const u16 *out_size)
+int hinic3_dbg_get_hw_stats(const void *hwdev, u8 *hw_stats, const u32 *out_size)
{
struct hinic3_hw_stats *tmp_hw_stats = (struct hinic3_hw_stats *)hw_stats;
struct card_node *chip_node = NULL;
@@ -1712,8 +1692,8 @@ int hinic3_dbg_get_hw_stats(const void *hwdev, u8 *hw_stats, const u16 *out_size
return -EFAULT;
}
- memcpy(hw_stats, &((struct hinic3_hwdev *)hwdev)->hw_stats,
- sizeof(struct hinic3_hw_stats));
+ memcpy(hw_stats,
+ &((struct hinic3_hwdev *)hwdev)->hw_stats, sizeof(struct hinic3_hw_stats));
chip_node = ((struct hinic3_hwdev *)hwdev)->chip_node;
@@ -1835,6 +1815,16 @@ bool hinic3_need_init_stateful_default(void *hwdev)
if (hinic3_func_type(hwdev) == TYPE_PPF && (chip_svc_type & CFG_SERVICE_MASK_VIRTIO) != 0)
return true;
+ /* vroce have to init cqm */
+ if (IS_MASTER_HOST(dev) &&
+ (hinic3_func_type(hwdev) != TYPE_PPF) &&
+ ((chip_svc_type & CFG_SERVICE_MASK_ROCE) != 0))
+ return true;
+
+ /* SDI5.1 vm mode nano os PF0 as ppf needs to do stateful init else mailbox will fail */
+ if (hinic3_func_type(hwdev) == TYPE_PPF && hinic3_is_vm_slave_host(hwdev))
+ return true;
+
/* Other service type will init cqm when uld call. */
return false;
}
@@ -1843,6 +1833,8 @@ static inline void stateful_uninit(struct hinic3_hwdev *hwdev)
{
u32 stateful_en;
+ cqm_uninit(hwdev);
+
stateful_en = IS_FT_TYPE(hwdev) | IS_RDMA_TYPE(hwdev);
if (stateful_en)
hinic3_ppf_ext_db_deinit(hwdev);
@@ -1869,15 +1861,25 @@ int hinic3_stateful_init(void *hwdev)
stateful_en = (int)(IS_FT_TYPE(dev) | IS_RDMA_TYPE(dev));
if (stateful_en != 0 && HINIC3_IS_PPF(dev)) {
err = hinic3_ppf_ext_db_init(dev);
- if (err)
+ if (err != 0)
goto out;
}
+ err = cqm_init(dev);
+ if (err != 0) {
+ sdk_err(dev->dev_hdl, "Failed to init cqm, err: %d\n", err);
+ goto init_cqm_err;
+ }
+
mutex_unlock(&dev->stateful_mutex);
sdk_info(dev->dev_hdl, "Initialize stateful resource success\n");
return 0;
+init_cqm_err:
+ if (stateful_en != 0)
+ hinic3_ppf_ext_db_deinit(dev);
+
out:
dev->stateful_ref_cnt--;
mutex_unlock(&dev->stateful_mutex);
@@ -1967,6 +1969,26 @@ void hinic3_fault_event_report(void *hwdev, u16 src, u16 level)
}
EXPORT_SYMBOL(hinic3_fault_event_report);
+int hinic3_is_slave_func(const void *hwdev, bool *is_slave_func)
+{
+ if (!hwdev)
+ return -EINVAL;
+
+ *is_slave_func = IS_SLAVE_HOST((struct hinic3_hwdev *)hwdev);
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_is_slave_func);
+
+int hinic3_is_master_func(const void *hwdev, bool *is_master_func)
+{
+ if (!hwdev)
+ return -EINVAL;
+
+ *is_master_func = IS_MASTER_HOST((struct hinic3_hwdev *)hwdev);
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_is_master_func);
+
void hinic3_probe_success(void *hwdev)
{
if (!hwdev)
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.h
index 9f7d8a4859ec9..e739767ed16e1 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwdev.h
@@ -4,9 +4,11 @@
#ifndef HINIC3_HWDEV_H
#define HINIC3_HWDEV_H
+#include <linux/workqueue.h>
#include "hinic3_mt.h"
#include "hinic3_crm.h"
#include "hinic3_hw.h"
+#include "mpu_inband_cmd_defs.h"
#include "hinic3_profile.h"
struct cfg_mgmt_info;
@@ -30,7 +32,7 @@ struct mqm_addr_trans_tbl_info {
u32 search_gpa_num;
u32 page_size;
u32 page_num;
- struct hinic3_page_addr *brm_srch_page_addr;
+ struct hinic3_dma_addr_align *brm_srch_page_addr;
};
struct hinic3_devlink {
@@ -80,6 +82,24 @@ enum hinic3_host_mode_e {
HINIC3_SDI_MODE_MAX,
};
+#define MULTI_HOST_CHIP_MODE_SHIFT 0
+#define MULTI_HOST_MASTER_MBX_STS_SHIFT 17
+#define MULTI_HOST_PRIV_DATA_SHIFT 0x8
+
+#define MULTI_HOST_CHIP_MODE_MASK 0xF
+#define MULTI_HOST_MASTER_MBX_STS_MASK 0x1
+#define MULTI_HOST_PRIV_DATA_MASK 0xFFFF
+
+#define MULTI_HOST_REG_SET(val, member) \
+ (((val) & MULTI_HOST_##member##_MASK) \
+ << MULTI_HOST_##member##_SHIFT)
+#define MULTI_HOST_REG_GET(val, member) \
+ (((val) >> MULTI_HOST_##member##_SHIFT) \
+ & MULTI_HOST_##member##_MASK)
+#define MULTI_HOST_REG_CLEAR(val, member) \
+ ((val) & (~(MULTI_HOST_##member##_MASK \
+ << MULTI_HOST_##member##_SHIFT)))
+
struct hinic3_hwdev {
void *adapter_hdl; /* pointer to hinic3_pcidev or NDIS_Adapter */
void *pcidev_hdl; /* pointer to pcidev or Handler */
@@ -89,6 +109,7 @@ struct hinic3_hwdev {
void *service_adapter[SERVICE_T_MAX];
void *chip_node;
+ struct semaphore ppf_sem;
void *ppf_hwdev;
u32 wq_page_size;
@@ -116,6 +137,8 @@ struct hinic3_hwdev {
u32 stateful_ref_cnt;
u32 rsvd2;
+ struct hinic3_multi_host_mgmt *mhost_mgmt;
+
struct mutex stateful_mutex; /* protect cqm init and deinit */
struct hinic3_hw_stats hw_stats;
@@ -128,7 +151,7 @@ struct hinic3_hwdev {
struct delayed_work sync_time_task;
struct delayed_work channel_detect_task;
- struct hisdk3_prof_attr *prof_attr;
+ struct hisdk3_prof_attr *prof_attr;
struct hinic3_prof_adapter *prof_adap;
struct workqueue_struct *workq;
@@ -149,9 +172,13 @@ struct hinic3_hwdev {
enum hinic3_func_mode func_mode;
u32 rsvd3;
+ DECLARE_BITMAP(func_probe_in_host, MAX_FUNCTION_NUM);
+ DECLARE_BITMAP(netdev_setup_state, MAX_FUNCTION_NUM);
+
u64 cur_recv_aeq_cnt;
u64 last_recv_aeq_cnt;
u16 aeq_busy_cnt;
+
u64 rsvd4[8];
};
@@ -172,4 +199,6 @@ struct hinic3_hwdev {
#define COMM_SUPPORT_CMDQ_NUM(hwdev) COMM_FEATURE_QW0(hwdev, CMDQ_NUM)
#define COMM_SUPPORT_VIRTIO_VQ_SIZE(hwdev) COMM_FEATURE_QW0(hwdev, VIRTIO_VQ_SIZE)
+void set_func_host_mode(struct hinic3_hwdev *hwdev, enum hinic3_func_mode mode);
+
#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwif.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwif.c
index 9b749135dbed1..648454042f71f 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwif.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_hwif.c
@@ -230,6 +230,9 @@ int hinic3_set_host_migrate_enable(void *hwdev, u8 host_id, bool enable)
u32 reg_val;
+ if (!dev || host_id > SPU_HOST_ID)
+ return -EINVAL;
+
if (HINIC3_FUNC_TYPE(dev) != TYPE_PPF) {
sdk_warn(dev->dev_hdl, "hwdev should be ppf\n");
return -EINVAL;
@@ -254,6 +257,9 @@ int hinic3_get_host_migrate_enable(void *hwdev, u8 host_id, u8 *migrate_en)
u32 reg_val;
+ if (!dev || !migrate_en || host_id > SPU_HOST_ID)
+ return -EINVAL;
+
if (HINIC3_FUNC_TYPE(dev) != TYPE_PPF) {
sdk_warn(dev->dev_hdl, "hwdev should be ppf\n");
return -EINVAL;
@@ -712,6 +718,15 @@ static void disable_all_msix(struct hinic3_hwdev *hwdev)
hinic3_set_msix_state(hwdev, i, HINIC3_MSIX_DISABLE);
}
+static void enable_all_msix(struct hinic3_hwdev *hwdev)
+{
+ u16 num_irqs = hwdev->hwif->attr.num_irqs;
+ u16 i;
+
+ for (i = 0; i < num_irqs; i++)
+ hinic3_set_msix_state(hwdev, i, HINIC3_MSIX_ENABLE);
+}
+
static enum hinic3_wait_return check_db_outbound_enable_handler(void *priv_data)
{
struct hinic3_hwif *hwif = priv_data;
@@ -824,6 +839,7 @@ void hinic3_free_hwif(struct hinic3_hwdev *hwdev)
{
spin_lock_deinit(&hwdev->hwif->free_db_area.idx_lock);
free_db_area(&hwdev->hwif->free_db_area);
+ enable_all_msix(hwdev);
kfree(hwdev->hwif);
}
@@ -840,6 +856,44 @@ u16 hinic3_global_func_id(void *hwdev)
}
EXPORT_SYMBOL(hinic3_global_func_id);
+/**
+ * get function id from register,used by sriov hot migration process
+ * @hwdev: the pointer to hw device
+ */
+u16 hinic3_global_func_id_hw(void *hwdev)
+{
+ u32 addr, attr0;
+ struct hinic3_hwdev *dev;
+
+ dev = (struct hinic3_hwdev *)hwdev;
+ addr = HINIC3_CSR_FUNC_ATTR0_ADDR;
+ attr0 = hinic3_hwif_read_reg(dev->hwif, addr);
+
+ return HINIC3_AF0_GET(attr0, FUNC_GLOBAL_IDX);
+}
+
+/**
+ * get function id, used by sriov hot migratition process.
+ * @hwdev: the pointer to hw device
+ * @func_id: function id
+ */
+int hinic3_global_func_id_get(void *hwdev, u16 *func_id)
+{
+ struct hinic3_hwdev *dev = (struct hinic3_hwdev *)hwdev;
+
+ if (!hwdev || !func_id)
+ return -EINVAL;
+
+ /* only vf get func_id from chip reg for sriov migrate */
+ if (!HINIC3_IS_VF(dev)) {
+ *func_id = hinic3_global_func_id(hwdev);
+ return 0;
+ }
+
+ *func_id = hinic3_global_func_id_hw(dev);
+ return 0;
+}
+
u16 hinic3_intr_num(void *hwdev)
{
struct hinic3_hwif *hwif = NULL;
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.c
index 3715c34811600..d2a7dd7c8678a 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.c
@@ -20,12 +20,14 @@
#include "hinic3_common.h"
#include "hinic3_mbox.h"
+#define HINIC3_MBOX_USEC_50 50
+
#define HINIC3_MBOX_INT_DST_AEQN_SHIFT 10
#define HINIC3_MBOX_INT_SRC_RESP_AEQN_SHIFT 12
#define HINIC3_MBOX_INT_STAT_DMA_SHIFT 14
/* The size of data to be send (unit of 4 bytes) */
#define HINIC3_MBOX_INT_TX_SIZE_SHIFT 20
-/* SO_RO(strong order, relax order) */
+/* SO_RO(strong order, relax order) */
#define HINIC3_MBOX_INT_STAT_DMA_SO_RO_SHIFT 25
#define HINIC3_MBOX_INT_WB_EN_SHIFT 28
@@ -63,13 +65,10 @@ enum hinic3_mbox_tx_status {
#define MBOX_SEGLEN_MASK \
HINIC3_MSG_HEADER_SET(HINIC3_MSG_HEADER_SEG_LEN_MASK, SEG_LEN)
+#define MBOX_MSG_WAIT_ONCE_TIME_US 10
#define MBOX_MSG_POLLING_TIMEOUT 8000
#define HINIC3_MBOX_COMP_TIME 40000U
-#define MBOX_MAX_BUF_SZ 2048U
-#define MBOX_HEADER_SZ 8
-#define HINIC3_MBOX_DATA_SIZE (MBOX_MAX_BUF_SZ - MBOX_HEADER_SZ)
-
/* MBOX size is 64B, 8B for mbox_header, 8B reserved */
#define MBOX_SEG_LEN 48
#define MBOX_SEG_LEN_ALIGN 4
@@ -642,6 +641,7 @@ static void recv_mbox_msg_handler(struct hinic3_mbox *func_to_func,
}
recv_msg->msg_len = msg_desc->msg_len;
memcpy(recv_msg->msg, msg_desc->msg, recv_msg->msg_len);
+
recv_msg->msg_id = msg_desc->msg_info.msg_id;
recv_msg->mod = HINIC3_MSG_HEADER_GET(mbox_header, MODULE);
recv_msg->cmd = HINIC3_MSG_HEADER_GET(mbox_header, CMD);
@@ -826,14 +826,14 @@ static void hinic3_deinit_mbox_dma_queue(struct hinic3_mbox *func_to_func)
#define MBOX_XOR_DATA_ALIGN 4
static u32 mbox_dma_msg_xor(u32 *data, u16 msg_len)
{
- u32 xor = MBOX_DMA_MSG_INIT_XOR_VAL;
+ u32 mbox_xor = MBOX_DMA_MSG_INIT_XOR_VAL;
u16 dw_len = msg_len / sizeof(u32);
u16 i;
for (i = 0; i < dw_len; i++)
- xor ^= data[i];
+ mbox_xor ^= data[i];
- return xor;
+ return mbox_xor;
}
#define MQ_ID_MASK(mq, idx) ((idx) & ((mq)->depth - 1))
@@ -844,7 +844,7 @@ static int mbox_prepare_dma_entry(struct hinic3_mbox *func_to_func, struct mbox_
struct mbox_dma_msg *dma_msg, void *msg, u16 msg_len)
{
u64 dma_addr, offset;
- void *dma_vaddr;
+ void *dma_vaddr = NULL;
if (IS_MSG_QUEUE_FULL(mq)) {
sdk_err(func_to_func->hwdev->dev_hdl, "Mbox sync message queue is busy, pi: %u, ci: %u\n",
@@ -856,6 +856,7 @@ static int mbox_prepare_dma_entry(struct hinic3_mbox *func_to_func, struct mbox_
offset = mq->prod_idx * MBOX_MAX_BUF_SZ;
dma_vaddr = (u8 *)mq->dma_buff_vaddr + offset;
memcpy(dma_vaddr, msg, msg_len);
+
dma_addr = mq->dma_buff_paddr + offset;
dma_msg->dma_addr_high = upper_32_bits(dma_addr);
dma_msg->dma_addr_low = lower_32_bits(dma_addr);
@@ -907,9 +908,8 @@ static void mbox_copy_header(struct hinic3_hwdev *hwdev,
}
}
-static void mbox_copy_send_data(struct hinic3_hwdev *hwdev,
- struct hinic3_send_mbox *mbox, void *seg,
- u16 seg_len)
+static int mbox_copy_send_data(struct hinic3_hwdev *hwdev,
+ struct hinic3_send_mbox *mbox, void *seg, u16 seg_len)
{
u32 *data = seg;
u32 data_len, chk_sz = sizeof(u32);
@@ -929,6 +929,8 @@ static void mbox_copy_send_data(struct hinic3_hwdev *hwdev,
__raw_writel(cpu_to_be32(*(data + i)),
mbox->data + MBOX_HEADER_SZ + i * sizeof(u32));
}
+
+ return 0;
}
static void write_mbox_msg_attr(struct hinic3_mbox *func_to_func,
@@ -1021,14 +1023,16 @@ static int send_mbox_seg(struct hinic3_mbox *func_to_func, u64 header,
mbox_copy_header(hwdev, send_mbox, &header);
- mbox_copy_send_data(hwdev, send_mbox, seg, seg_len);
+ err = mbox_copy_send_data(hwdev, send_mbox, seg, seg_len);
+ if (err != 0)
+ return err;
write_mbox_msg_attr(func_to_func, dst_func, dst_aeqn, seg_len);
wmb(); /* writing the mbox msg attributes */
err = hinic3_wait_for_timeout(func_to_func, check_mbox_wb_status,
- MBOX_MSG_POLLING_TIMEOUT, USEC_PER_MSEC);
+ MBOX_MSG_POLLING_TIMEOUT, MBOX_MSG_WAIT_ONCE_TIME_US);
wb_status = get_mbox_status(send_mbox);
if (err) {
sdk_err(hwdev->dev_hdl, "Send mailbox segment timeout, wb status: 0x%x\n",
@@ -1118,7 +1122,7 @@ static int send_mbox_msg(struct hinic3_mbox *func_to_func, u8 mod, u16 cmd,
}
left -= MBOX_SEG_LEN;
- msg_seg += MBOX_SEG_LEN; /*lint !e662 */
+ msg_seg += MBOX_SEG_LEN;
seq_id++;
header &= ~(HINIC3_MSG_HEADER_SET(HINIC3_MSG_HEADER_SEQID_MASK,
@@ -1159,7 +1163,7 @@ static int wait_mbox_msg_completion(struct hinic3_mbox *func_to_func,
wait_time = (timeout != 0) ? timeout : HINIC3_MBOX_COMP_TIME;
err = hinic3_wait_for_timeout(func_to_func, check_mbox_msg_finish,
- wait_time, USEC_PER_MSEC);
+ wait_time, WAIT_USEC_50);
if (err) {
set_mbox_to_func_event(func_to_func, EVENT_TIMEOUT);
return -ETIMEDOUT;
@@ -1206,10 +1210,11 @@ int hinic3_mbox_to_func(struct hinic3_mbox *func_to_func, u8 mod, u16 cmd,
return -EPERM;
/* expect response message */
- msg_desc = get_mbox_msg_desc(func_to_func, HINIC3_MSG_RESPONSE,
- dst_func);
- if (!msg_desc)
+ msg_desc = get_mbox_msg_desc(func_to_func, HINIC3_MSG_RESPONSE, dst_func);
+ if (!msg_desc) {
+ sdk_err(func_to_func->hwdev->dev_hdl, "msg_desc null\n");
return -EFAULT;
+ }
err = send_mbox_msg_lock(func_to_func, channel);
if (err)
@@ -1229,7 +1234,7 @@ int hinic3_mbox_to_func(struct hinic3_mbox *func_to_func, u8 mod, u16 cmd,
goto send_err;
}
- if (wait_mbox_msg_completion(func_to_func, timeout)) {
+ if (wait_mbox_msg_completion(func_to_func, timeout) != 0) {
sdk_err(func_to_func->hwdev->dev_hdl,
"Send mbox msg timeout, msg_id: %u\n", msg_info.msg_id);
hinic3_dump_aeq_info(func_to_func->hwdev);
@@ -1261,7 +1266,6 @@ int hinic3_mbox_to_func(struct hinic3_mbox *func_to_func, u8 mod, u16 cmd,
if (msg_desc->msg_len)
memcpy(buf_out, msg_desc->msg, msg_desc->msg_len);
-
*out_size = msg_desc->msg_len;
}
@@ -1293,9 +1297,29 @@ static int mbox_func_params_valid(struct hinic3_mbox *func_to_func,
return 0;
}
-static int hinic3_mbox_to_func_no_ack(struct hinic3_hwdev *hwdev, u16 func_idx,
- u8 mod, u16 cmd, void *buf_in, u16 in_size,
- u16 channel)
+int hinic3_mbox_to_host(struct hinic3_hwdev *hwdev, u16 dest_host_ppf_id, enum hinic3_mod_type mod,
+ u8 cmd, void *buf_in, u16 in_size, void *buf_out, u16 *out_size,
+ u32 timeout, u16 channel)
+{
+ struct hinic3_mbox *func_to_func = hwdev->func_to_func;
+ int err;
+
+ err = mbox_func_params_valid(func_to_func, buf_in, in_size, channel);
+ if (err)
+ return err;
+
+ if (!HINIC3_IS_PPF(hwdev)) {
+ sdk_err(hwdev->dev_hdl, "Params error, only PPF can send message to other host, func_type: %d\n",
+ hinic3_func_type(hwdev));
+ return -EINVAL;
+ }
+
+ return hinic3_mbox_to_func(func_to_func, mod, cmd, dest_host_ppf_id, buf_in, in_size,
+ buf_out, out_size, timeout, channel);
+}
+
+int hinic3_mbox_to_func_no_ack(struct hinic3_hwdev *hwdev, u16 func_idx,
+ u8 mod, u16 cmd, void *buf_in, u16 in_size, u16 channel)
{
struct mbox_msg_info msg_info = {0};
int err = mbox_func_params_valid(hwdev->func_to_func, buf_in, in_size,
@@ -1476,24 +1500,43 @@ int hinic3_mbox_to_vf(void *hwdev, u16 vf_id, u8 mod, u16 cmd, void *buf_in,
}
EXPORT_SYMBOL(hinic3_mbox_to_vf);
-int hinic3_mbox_set_channel_status(struct hinic3_hwdev *hwdev, u16 channel,
- bool enable)
+int hinic3_mbox_to_vf_no_ack(void *hwdev, u16 vf_id, u8 mod, u16 cmd, void *buf_in,
+ u16 in_size, void *buf_out,
+ u16 *out_size, u16 channel)
{
- if (channel >= HINIC3_CHANNEL_MAX) {
- sdk_err(hwdev->dev_hdl, "Invalid channel id: 0x%x\n", channel);
+ struct hinic3_mbox *func_to_func = NULL;
+ int err = 0;
+ u16 dst_func_idx;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ func_to_func = ((struct hinic3_hwdev *)hwdev)->func_to_func;
+ err = mbox_func_params_valid(func_to_func, buf_in, in_size, channel);
+ if (err != 0)
+ return err;
+
+ if (HINIC3_IS_VF((struct hinic3_hwdev *)hwdev)) {
+ sdk_err(((struct hinic3_hwdev *)hwdev)->dev_hdl, "Params error, func_type: %d\n",
+ hinic3_func_type(hwdev));
return -EINVAL;
}
- if (enable)
- clear_bit(channel, &hwdev->func_to_func->channel_stop);
- else
- set_bit(channel, &hwdev->func_to_func->channel_stop);
+ if (!vf_id) {
+ sdk_err(((struct hinic3_hwdev *)hwdev)->dev_hdl,
+ "VF id(%u) error!\n", vf_id);
+ return -EINVAL;
+ }
- sdk_info(hwdev->dev_hdl, "%s mbox channel 0x%x\n",
- enable ? "Enable" : "Disable", channel);
+ /* vf_offset_to_pf + vf_id is the vf's global function id of vf in
+ * this pf
+ */
+ dst_func_idx = hinic3_glb_pf_vf_offset(hwdev) + vf_id;
- return 0;
+ return hinic3_mbox_to_func_no_ack(hwdev, dst_func_idx, mod, cmd,
+ buf_in, in_size, channel);
}
+EXPORT_SYMBOL(hinic3_mbox_to_vf_no_ack);
void hinic3_mbox_enable_channel_lock(struct hinic3_hwdev *hwdev, bool enable)
{
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.h
index bf723e8a68fb9..226f8d6b24ba4 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mbox.h
@@ -45,6 +45,10 @@
#define HINIC3_MSG_HEADER_LAST_MASK 0x1
#define HINIC3_MSG_HEADER_DIRECTION_MASK 0x1
+#define MBOX_MAX_BUF_SZ 2048U
+#define MBOX_HEADER_SZ 8
+#define HINIC3_MBOX_DATA_SIZE (MBOX_MAX_BUF_SZ - MBOX_HEADER_SZ)
+
#define HINIC3_MSG_HEADER_GET(val, field) \
(((val) >> HINIC3_MSG_HEADER_##field##_SHIFT) & \
HINIC3_MSG_HEADER_##field##_MASK)
@@ -95,12 +99,12 @@ struct mbox_msg_info {
};
struct hinic3_msg_desc {
- void *msg;
- u16 msg_len;
- u8 seq_id;
- u8 mod;
- u16 cmd;
- struct mbox_msg_info msg_info;
+ void *msg;
+ u16 msg_len;
+ u8 seq_id;
+ u8 mod;
+ u16 cmd;
+ struct mbox_msg_info msg_info;
};
struct hinic3_msg_channel {
@@ -112,25 +116,25 @@ struct hinic3_msg_channel {
/* Receive other functions mbox message */
struct hinic3_recv_mbox {
- void *msg;
- u16 msg_len;
- u8 msg_id;
- u8 mod;
- u16 cmd;
- u16 src_func_idx;
+ void *msg;
+ u16 msg_len;
+ u8 msg_id;
+ u8 mod;
+ u16 cmd;
+ u16 src_func_idx;
enum hinic3_msg_ack_type ack_type;
- u32 rsvd1;
+ u32 rsvd1;
- void *resp_buff;
+ void *resp_buff;
};
struct hinic3_send_mbox {
- u8 *data;
+ u8 *data;
- u64 *wb_status; /* write back status */
- void *wb_vaddr;
- dma_addr_t wb_paddr;
+ u64 *wb_status; /* write back status */
+ void *wb_vaddr;
+ dma_addr_t wb_paddr;
};
enum mbox_event_state {
@@ -152,6 +156,11 @@ enum hinic3_mbox_cb_state {
HINIC3_PPF_TO_PF_MBOX_CB_RUNNIG,
};
+enum hinic3_mbox_ack_type {
+ MBOX_ACK,
+ MBOX_NO_ACK,
+};
+
struct mbox_dma_msg {
u32 xor;
u32 dma_addr_high;
@@ -161,16 +170,16 @@ struct mbox_dma_msg {
};
struct mbox_dma_queue {
- void *dma_buff_vaddr;
- dma_addr_t dma_buff_paddr;
+ void *dma_buff_vaddr;
+ dma_addr_t dma_buff_paddr;
- u16 depth;
- u16 prod_idx;
- u16 cons_idx;
+ u16 depth;
+ u16 prod_idx;
+ u16 cons_idx;
};
struct hinic3_mbox {
- struct hinic3_hwdev *hwdev;
+ struct hinic3_hwdev *hwdev;
bool lock_channel_en;
unsigned long channel_stop;
@@ -186,7 +195,7 @@ struct hinic3_mbox {
struct mbox_dma_queue sync_msg_queue;
struct mbox_dma_queue async_msg_queue;
- struct workqueue_struct *workq;
+ struct workqueue_struct *workq;
struct hinic3_msg_channel mgmt_msg; /* driver and MGMT CPU */
struct hinic3_msg_channel *host_msg; /* PPF message between hosts */
@@ -196,16 +205,16 @@ struct hinic3_mbox {
/* vf receive pf/ppf callback */
hinic3_vf_mbox_cb vf_mbox_cb[HINIC3_MOD_MAX];
- void *vf_mbox_data[HINIC3_MOD_MAX];
+ void *vf_mbox_data[HINIC3_MOD_MAX];
/* pf/ppf receive vf callback */
hinic3_pf_mbox_cb pf_mbox_cb[HINIC3_MOD_MAX];
- void *pf_mbox_data[HINIC3_MOD_MAX];
+ void *pf_mbox_data[HINIC3_MOD_MAX];
/* ppf receive pf/ppf callback */
hinic3_ppf_mbox_cb ppf_mbox_cb[HINIC3_MOD_MAX];
- void *ppf_mbox_data[HINIC3_MOD_MAX];
+ void *ppf_mbox_data[HINIC3_MOD_MAX];
/* pf receive ppf callback */
hinic3_pf_recv_from_ppf_mbox_cb pf_recv_ppf_mbox_cb[HINIC3_MOD_MAX];
- void *pf_recv_ppf_mbox_data[HINIC3_MOD_MAX];
+ void *pf_recv_ppf_mbox_data[HINIC3_MOD_MAX];
unsigned long ppf_to_pf_mbox_cb_state[HINIC3_MOD_MAX];
unsigned long ppf_mbox_cb_state[HINIC3_MOD_MAX];
unsigned long pf_mbox_cb_state[HINIC3_MOD_MAX];
@@ -221,8 +230,8 @@ struct hinic3_mbox {
struct hinic3_mbox_work {
struct work_struct work;
- struct hinic3_mbox *func_to_func;
- struct hinic3_recv_mbox *recv_mbox;
+ struct hinic3_mbox *func_to_func;
+ struct hinic3_recv_mbox *recv_mbox;
struct hinic3_msg_channel *msg_ch;
};
@@ -243,6 +252,14 @@ int hinic3_func_to_func_init(struct hinic3_hwdev *hwdev);
void hinic3_func_to_func_free(struct hinic3_hwdev *hwdev);
+int hinic3_mbox_to_host(struct hinic3_hwdev *hwdev, u16 dest_host_ppf_id,
+ enum hinic3_mod_type mod, u8 cmd, void *buf_in,
+ u16 in_size, void *buf_out, u16 *out_size, u32 timeout, u16 channel);
+
+int hinic3_mbox_to_func_no_ack(struct hinic3_hwdev *hwdev, u16 func_idx,
+ u8 mod, u16 cmd, void *buf_in, u16 in_size,
+ u16 channel);
+
int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd,
void *buf_in, u16 in_size, void *buf_out,
u16 *out_size, u32 timeout, u16 channel);
@@ -258,9 +275,6 @@ int hinic3_mbox_to_func(struct hinic3_mbox *func_to_func, u8 mod, u16 cmd,
int hinic3_mbox_init_host_msg_channel(struct hinic3_hwdev *hwdev);
-int hinic3_mbox_set_channel_status(struct hinic3_hwdev *hwdev, u16 channel,
- bool enable);
-
void hinic3_mbox_enable_channel_lock(struct hinic3_hwdev *hwdev, bool enable);
#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.c
index f633262e8b71c..3ad9a77e389ee 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.c
@@ -18,7 +18,7 @@
#include "hinic3_crm.h"
#include "hinic3_hw.h"
#include "hinic3_common.h"
-#include "hinic3_comm_cmd.h"
+#include "mpu_inband_cmd.h"
#include "hinic3_hwdev.h"
#include "hinic3_eqs.h"
#include "hinic3_mbox.h"
@@ -213,8 +213,7 @@ static void clp_prepare_header(struct hinic3_hwdev *hwdev, u64 *header,
* @msg: the data of the message
* @msg_len: the length of the message
**/
-static void prepare_mgmt_cmd(u8 *mgmt_cmd, u64 *header, const void *msg,
- int msg_len)
+static int prepare_mgmt_cmd(u8 *mgmt_cmd, u64 *header, const void *msg, int msg_len)
{
u8 *mgmt_cmd_new = mgmt_cmd;
@@ -225,6 +224,8 @@ static void prepare_mgmt_cmd(u8 *mgmt_cmd, u64 *header, const void *msg,
mgmt_cmd_new += sizeof(*header);
memcpy(mgmt_cmd_new, msg, (size_t)(u32)msg_len);
+
+ return 0;
}
/**
@@ -249,6 +250,7 @@ static int send_msg_to_mgmt_sync(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt,
u8 node_id = HINIC3_MGMT_CPU_NODE_ID(pf_to_mgmt->hwdev);
u64 header;
u16 cmd_size = mgmt_msg_len(msg_len);
+ int ret;
if (hinic3_get_chip_present_flag(pf_to_mgmt->hwdev) == 0)
return -EFAULT;
@@ -267,7 +269,9 @@ static int send_msg_to_mgmt_sync(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt,
if (ack_type == HINIC3_MSG_ACK)
pf_to_mgmt_send_event_set(pf_to_mgmt, SEND_EVENT_START);
- prepare_mgmt_cmd((u8 *)mgmt_cmd, &header, msg, msg_len);
+ ret = prepare_mgmt_cmd((u8 *)mgmt_cmd, &header, msg, msg_len);
+ if (ret != 0)
+ return ret;
return hinic3_api_cmd_write(chain, node_id, mgmt_cmd, cmd_size);
}
@@ -291,6 +295,7 @@ static int send_msg_to_mgmt_async(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt,
u8 node_id = HINIC3_MGMT_CPU_NODE_ID(pf_to_mgmt->hwdev);
u64 header;
u16 cmd_size = mgmt_msg_len(msg_len);
+ int ret;
if (hinic3_get_chip_present_flag(pf_to_mgmt->hwdev) == 0)
return -EFAULT;
@@ -301,24 +306,31 @@ static int send_msg_to_mgmt_async(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt,
prepare_header(pf_to_mgmt, &header, msg_len, mod, HINIC3_MSG_NO_ACK,
direction, cmd, ASYNC_MSG_ID(pf_to_mgmt));
- prepare_mgmt_cmd((u8 *)mgmt_cmd, &header, msg, msg_len);
+ ret = prepare_mgmt_cmd((u8 *)mgmt_cmd, &header, msg, msg_len);
+ if (ret != 0)
+ return ret;
chain = pf_to_mgmt->cmd_chain[HINIC3_API_CMD_WRITE_ASYNC_TO_MGMT_CPU];
return hinic3_api_cmd_write(chain, node_id, mgmt_cmd, cmd_size);
}
-static inline void msg_to_mgmt_pre(u8 mod, void *buf_in)
+static inline int msg_to_mgmt_pre(u8 mod, void *buf_in, u16 in_size)
{
struct hinic3_msg_head *msg_head = NULL;
/* set aeq fix num to 3, need to ensure response aeq id < 3 */
if (mod == HINIC3_MOD_COMM || mod == HINIC3_MOD_L2NIC) {
+ if (in_size < sizeof(struct hinic3_msg_head))
+ return -EINVAL;
+
msg_head = buf_in;
if (msg_head->resp_aeq_num >= HINIC3_MAX_AEQS)
msg_head->resp_aeq_num = 0;
}
+
+ return 0;
}
int hinic3_pf_to_mgmt_sync(void *hwdev, u8 mod, u16 cmd, void *buf_in,
@@ -336,7 +348,12 @@ int hinic3_pf_to_mgmt_sync(void *hwdev, u8 mod, u16 cmd, void *buf_in,
if (!COMM_SUPPORT_API_CHAIN((struct hinic3_hwdev *)hwdev))
return -EPERM;
- msg_to_mgmt_pre(mod, buf_in);
+ if (!buf_in || in_size == 0)
+ return -EINVAL;
+
+ ret = msg_to_mgmt_pre(mod, buf_in, in_size);
+ if (ret != 0)
+ return -EINVAL;
pf_to_mgmt = ((struct hinic3_hwdev *)hwdev)->pf_to_mgmt;
@@ -395,7 +412,6 @@ int hinic3_pf_to_mgmt_sync(void *hwdev, u8 mod, u16 cmd, void *buf_in,
if (recv_msg->msg_len)
memcpy(buf_out, recv_msg->msg, recv_msg->msg_len);
-
*out_size = recv_msg->msg_len;
}
@@ -409,7 +425,7 @@ unlock_sync_msg:
int hinic3_pf_to_mgmt_async(void *hwdev, u8 mod, u16 cmd, const void *buf_in,
u16 in_size)
{
- struct hinic3_msg_pf_to_mgmt *pf_to_mgmt;
+ struct hinic3_msg_pf_to_mgmt *pf_to_mgmt = NULL;
void *dev = ((struct hinic3_hwdev *)hwdev)->dev_hdl;
int err;
@@ -434,6 +450,41 @@ int hinic3_pf_to_mgmt_async(void *hwdev, u8 mod, u16 cmd, const void *buf_in,
return 0;
}
+/* This function is only used by tx/rx flush */
+int hinic3_pf_to_mgmt_no_ack(void *hwdev, enum hinic3_mod_type mod, u8 cmd, void *buf_in,
+ u16 in_size)
+{
+ struct hinic3_msg_pf_to_mgmt *pf_to_mgmt = NULL;
+ void *dev = NULL;
+ int err = -EINVAL;
+ struct hinic3_hwdev *tmp_hwdev = NULL;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ tmp_hwdev = (struct hinic3_hwdev *)hwdev;
+ dev = tmp_hwdev->dev_hdl;
+ pf_to_mgmt = tmp_hwdev->pf_to_mgmt;
+
+ if (in_size > HINIC3_MBOX_DATA_SIZE) {
+ sdk_err(dev, "Mgmt msg buffer size: %u is invalid\n", in_size);
+ return -EINVAL;
+ }
+
+ if (!(tmp_hwdev->chip_present_flag))
+ return -EPERM;
+
+ /* lock the sync_msg_buf */
+ down(&pf_to_mgmt->sync_msg_lock);
+
+ err = send_msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size, HINIC3_MSG_NO_ACK,
+ HINIC3_MSG_DIRECT_SEND, MSG_NO_RESP);
+
+ up(&pf_to_mgmt->sync_msg_lock);
+
+ return err;
+}
+
int hinic3_pf_msg_to_mgmt_sync(void *hwdev, u8 mod, u16 cmd, void *buf_in,
u16 in_size, void *buf_out, u16 *out_size,
u32 timeout)
@@ -1361,11 +1412,11 @@ static void hinic3_clear_clp_data(struct hinic3_hwdev *hwdev,
int hinic3_pf_clp_to_mgmt(void *hwdev, u8 mod, u16 cmd, const void *buf_in,
u16 in_size, void *buf_out, u16 *out_size)
{
- struct hinic3_clp_pf_to_mgmt *clp_pf_to_mgmt;
+ struct hinic3_clp_pf_to_mgmt *clp_pf_to_mgmt = NULL;
struct hinic3_hwdev *dev = hwdev;
u64 header;
u16 real_size;
- u8 *clp_msg_buf;
+ u8 *clp_msg_buf = NULL;
int err;
if (!COMM_SUPPORT_CLP(dev))
@@ -1408,6 +1459,7 @@ int hinic3_pf_clp_to_mgmt(void *hwdev, u8 mod, u16 cmd, const void *buf_in,
clp_prepare_header(dev, &header, in_size, mod, 0, 0, cmd, 0);
memcpy(clp_msg_buf, &header, sizeof(header));
+
clp_msg_buf += sizeof(header);
memcpy(clp_msg_buf, buf_in, in_size);
@@ -1480,7 +1532,7 @@ int hinic3_clp_to_mgmt(void *hwdev, u8 mod, u16 cmd, const void *buf_in,
int hinic3_clp_pf_to_mgmt_init(struct hinic3_hwdev *hwdev)
{
- struct hinic3_clp_pf_to_mgmt *clp_pf_to_mgmt;
+ struct hinic3_clp_pf_to_mgmt *clp_pf_to_mgmt = NULL;
if (!COMM_SUPPORT_CLP(hwdev))
return 0;
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.h
index ad86a82e70401..48970e37a6a89 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_mgmt.h
@@ -10,7 +10,7 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
-#include "comm_defs.h"
+#include "mpu_cmd_base_defs.h"
#include "hinic3_hw.h"
#include "hinic3_api_cmd.h"
#include "hinic3_hwdev.h"
@@ -164,6 +164,9 @@ int hinic3_pf_msg_to_mgmt_sync(void *hwdev, u8 mod, u16 cmd, void *buf_in,
u16 in_size, void *buf_out, u16 *out_size,
u32 timeout);
+int hinic3_pf_to_mgmt_no_ack(void *hwdev, enum hinic3_mod_type mod, u8 cmd, void *buf_in,
+ u16 in_size);
+
int hinic3_api_cmd_read_ack(void *hwdev, u8 dest, const void *cmd, u16 size,
void *ack, u16 ack_size);
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_multi_host_mgmt.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_multi_host_mgmt.c
new file mode 100644
index 0000000000000..254fcd16537ad
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_multi_host_mgmt.c
@@ -0,0 +1,1231 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": [COMM]" fmt
+
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "ossl_knl.h"
+#include "hinic3_common.h"
+#include "hinic3_hw.h"
+#include "hinic3_hwdev.h"
+#include "hinic3_csr.h"
+#include "hinic3_hwif.h"
+#include "hinic3_api_cmd.h"
+#include "hinic3_mgmt.h"
+#include "hinic3_mbox.h"
+#include "hinic3_hwif.h"
+#include "hinic3_multi_host_mgmt.h"
+#include "hinic3_hw_cfg.h"
+
+#define HINIC3_SUPPORT_MAX_PF_NUM 32
+#define HINIC3_MBOX_PF_BUSY_ACTIVE_FW 0x2
+
+void set_master_host_mbox_enable(struct hinic3_hwdev *hwdev, bool enable)
+{
+ u32 reg_val;
+
+ if (!IS_MASTER_HOST(hwdev) || HINIC3_FUNC_TYPE(hwdev) != TYPE_PPF)
+ return;
+
+ reg_val = hinic3_hwif_read_reg(hwdev->hwif, HINIC3_MULT_HOST_MASTER_MBOX_STATUS_ADDR);
+ reg_val = MULTI_HOST_REG_CLEAR(reg_val, MASTER_MBX_STS);
+ reg_val |= MULTI_HOST_REG_SET((u8)enable, MASTER_MBX_STS);
+ hinic3_hwif_write_reg(hwdev->hwif, HINIC3_MULT_HOST_MASTER_MBOX_STATUS_ADDR, reg_val);
+
+ sdk_info(hwdev->dev_hdl, "Multi-host status: %d, reg value: 0x%x\n",
+ enable, reg_val);
+}
+
+bool hinic3_get_master_host_mbox_enable(void *hwdev)
+{
+ u32 reg_val;
+ struct hinic3_hwdev *dev = hwdev;
+
+ if (!hwdev)
+ return false;
+
+ if (!IS_SLAVE_HOST(dev) || HINIC3_FUNC_TYPE(dev) == TYPE_VF)
+ return true;
+
+ reg_val = hinic3_hwif_read_reg(dev->hwif, HINIC3_MULT_HOST_MASTER_MBOX_STATUS_ADDR);
+
+ return !!MULTI_HOST_REG_GET(reg_val, MASTER_MBX_STS);
+}
+
+bool hinic3_is_multi_bm(void *hwdev)
+{
+ struct hinic3_hwdev *hw_dev = hwdev;
+
+ if (!hwdev)
+ return false;
+
+ return ((IS_BMGW_SLAVE_HOST(hw_dev)) || (IS_BMGW_MASTER_HOST(hw_dev))) ? true : false;
+}
+EXPORT_SYMBOL(hinic3_is_multi_bm);
+
+bool hinic3_is_slave_host(void *hwdev)
+{
+ struct hinic3_hwdev *hw_dev = hwdev;
+
+ if (!hwdev) {
+ pr_err("hwdev is null\n");
+ return false;
+ }
+
+ return ((IS_BMGW_SLAVE_HOST(hw_dev)) || (IS_VM_SLAVE_HOST(hw_dev))) ? true : false;
+}
+EXPORT_SYMBOL(hinic3_is_slave_host);
+
+bool hinic3_is_vm_slave_host(void *hwdev)
+{
+ struct hinic3_hwdev *hw_dev = hwdev;
+
+ if (!hwdev) {
+ pr_err("hwdev is null\n");
+ return false;
+ }
+
+ return (IS_VM_SLAVE_HOST(hw_dev)) ? true : false;
+}
+EXPORT_SYMBOL(hinic3_is_vm_slave_host);
+
+bool hinic3_is_bm_slave_host(void *hwdev)
+{
+ struct hinic3_hwdev *hw_dev = hwdev;
+
+ if (!hwdev) {
+ pr_err("hwdev is null\n");
+ return false;
+ }
+
+ return (IS_BMGW_SLAVE_HOST(hw_dev)) ? true : false;
+}
+EXPORT_SYMBOL(hinic3_is_bm_slave_host);
+
+static int __send_mbox_to_host(struct hinic3_hwdev *mbox_hwdev,
+ struct hinic3_hwdev *hwdev,
+ enum hinic3_mod_type mod, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size, u32 timeout,
+ enum hinic3_mbox_ack_type ack_type, u16 channel)
+{
+ u8 dst_host_func_idx;
+ struct service_cap *cap = &hwdev->cfg_mgmt->svc_cap;
+
+ if (!mbox_hwdev->chip_present_flag)
+ return -EPERM;
+
+ if (!hinic3_get_master_host_mbox_enable(hwdev)) {
+ sdk_err(hwdev->dev_hdl, "Master host not initialized\n");
+ return -EFAULT;
+ }
+
+ if (!mbox_hwdev->mhost_mgmt) {
+ /* send to master host in default */
+ dst_host_func_idx = hinic3_host_ppf_idx(hwdev, cap->master_host_id);
+ } else {
+ dst_host_func_idx = IS_MASTER_HOST(hwdev) ?
+ mbox_hwdev->mhost_mgmt->shost_ppf_idx :
+ mbox_hwdev->mhost_mgmt->mhost_ppf_idx;
+ }
+
+ if (ack_type == MBOX_ACK)
+ return hinic3_mbox_to_host(mbox_hwdev, dst_host_func_idx,
+ mod, cmd, buf_in, in_size,
+ buf_out, out_size, timeout, channel);
+ else
+ return hinic3_mbox_to_func_no_ack(mbox_hwdev, dst_host_func_idx,
+ mod, cmd, buf_in, in_size, channel);
+}
+
+int __mbox_to_host(struct hinic3_hwdev *hwdev, enum hinic3_mod_type mod,
+ u8 cmd, void *buf_in, u16 in_size, void *buf_out,
+ u16 *out_size, u32 timeout,
+ enum hinic3_mbox_ack_type ack_type, u16 channel)
+{
+ struct hinic3_hwdev *mbox_hwdev = hwdev;
+ int err;
+
+ if (!IS_MULTI_HOST(hwdev) || HINIC3_IS_VF(hwdev))
+ return -EPERM;
+
+ if (hinic3_func_type(hwdev) == TYPE_PF) {
+ down(&hwdev->ppf_sem);
+ mbox_hwdev = hwdev->ppf_hwdev;
+ if (!mbox_hwdev) {
+ err = -EINVAL;
+ goto release_lock;
+ }
+
+ if (!test_bit(HINIC3_HWDEV_MBOX_INITED, &mbox_hwdev->func_state)) {
+ err = -EPERM;
+ goto release_lock;
+ }
+ }
+
+ err = __send_mbox_to_host(mbox_hwdev, hwdev, mod, cmd, buf_in, in_size,
+ buf_out, out_size, timeout, ack_type, channel);
+
+release_lock:
+ if (hinic3_func_type(hwdev) == TYPE_PF)
+ up(&hwdev->ppf_sem);
+
+ return err;
+}
+
+int hinic3_mbox_to_host_sync(void *hwdev, enum hinic3_mod_type mod,
+ u8 cmd, void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size, u32 timeout, u16 channel)
+{
+ if (!hwdev)
+ return -EINVAL;
+
+ return __mbox_to_host((struct hinic3_hwdev *)hwdev, mod, cmd, buf_in,
+ in_size, buf_out, out_size, timeout, MBOX_ACK, channel);
+}
+EXPORT_SYMBOL(hinic3_mbox_to_host_sync);
+
+int hinic3_mbox_to_host_no_ack(struct hinic3_hwdev *hwdev,
+ enum hinic3_mod_type mod, u8 cmd,
+ void *buf_in, u16 in_size, u16 channel)
+{
+ return __mbox_to_host(hwdev, mod, cmd, buf_in, in_size, NULL, NULL,
+ 0, MBOX_NO_ACK, channel);
+}
+
+static int __get_func_nic_state_from_pf(struct hinic3_hwdev *hwdev,
+ u16 glb_func_idx, u8 *en);
+static int __get_func_vroce_state_from_pf(struct hinic3_hwdev *hwdev,
+ u16 glb_func_idx, u8 *en);
+
+int sw_func_pf_mbox_handler(void *pri_handle, u16 vf_id, u16 cmd, void *buf_in,
+ u16 in_size, void *buf_out, u16 *out_size)
+{
+ struct hinic3_hwdev *hwdev = pri_handle;
+ struct hinic3_slave_func_nic_state *nic_state = NULL;
+ struct hinic3_slave_func_nic_state *out_state = NULL;
+ int err;
+
+ switch (cmd) {
+ case HINIC3_SW_CMD_GET_SLAVE_FUNC_NIC_STATE:
+ nic_state = buf_in;
+ out_state = buf_out;
+ *out_size = sizeof(*nic_state);
+
+ /* find nic state in PPF func_nic_en bitmap */
+ err = __get_func_nic_state_from_pf(hwdev, nic_state->func_idx,
+ &out_state->enable);
+ out_state->status = err ? 1 : 0;
+
+ break;
+ case HINIC3_SW_CMD_GET_SLAVE_FUNC_VROCE_STATE:
+ nic_state = buf_in;
+ out_state = buf_out;
+ *out_size = sizeof(*nic_state);
+
+ err = __get_func_vroce_state_from_pf(hwdev, nic_state->func_idx,
+ &out_state->enable);
+ out_state->status = err ? 1 : 0;
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int __master_host_sw_func_handler(struct hinic3_hwdev *hwdev, u16 pf_idx,
+ u8 cmd, void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic3_multi_host_mgmt *mhost_mgmt = hwdev->mhost_mgmt;
+ struct register_slave_host *out_shost = NULL;
+ struct register_slave_host *slave_host = NULL;
+ u64 *vroce_en = NULL;
+
+ int err = 0;
+
+ if (!mhost_mgmt)
+ return -ENXIO;
+ switch (cmd) {
+ case HINIC3_SW_CMD_SLAVE_HOST_PPF_REGISTER:
+ slave_host = buf_in;
+ out_shost = buf_out;
+ *out_size = sizeof(*slave_host);
+ vroce_en = out_shost->funcs_vroce_en;
+
+ /* just get information about function nic enable */
+ if (slave_host->get_nic_en) {
+ bitmap_copy((ulong *)out_shost->funcs_nic_en,
+ mhost_mgmt->func_nic_en,
+ HINIC3_MAX_MGMT_FUNCTIONS);
+
+ if (IS_MASTER_HOST(hwdev))
+ bitmap_copy((ulong *)vroce_en,
+ mhost_mgmt->func_vroce_en,
+ HINIC3_MAX_MGMT_FUNCTIONS);
+ out_shost->status = 0;
+ break;
+ }
+
+ mhost_mgmt->shost_registered = true;
+ mhost_mgmt->shost_host_idx = slave_host->host_id;
+ mhost_mgmt->shost_ppf_idx = slave_host->ppf_idx;
+
+ bitmap_copy((ulong *)out_shost->funcs_nic_en,
+ mhost_mgmt->func_nic_en, HINIC3_MAX_MGMT_FUNCTIONS);
+
+ if (IS_MASTER_HOST(hwdev))
+ bitmap_copy((ulong *)vroce_en,
+ mhost_mgmt->func_vroce_en,
+ HINIC3_MAX_MGMT_FUNCTIONS);
+
+ sdk_info(hwdev->dev_hdl, "Slave host registers PPF, host_id: %u, ppf_idx: %u\n",
+ slave_host->host_id, slave_host->ppf_idx);
+
+ out_shost->status = 0;
+ break;
+ case HINIC3_SW_CMD_SLAVE_HOST_PPF_UNREGISTER:
+ slave_host = buf_in;
+ mhost_mgmt->shost_registered = false;
+ sdk_info(hwdev->dev_hdl, "Slave host unregisters PPF, host_id: %u, ppf_idx: %u\n",
+ slave_host->host_id, slave_host->ppf_idx);
+
+ *out_size = sizeof(*slave_host);
+ ((struct register_slave_host *)buf_out)->status = 0;
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static int __event_func_service_state_handler(struct hinic3_hwdev *hwdev,
+ u8 sub_cmd, void *buf_in,
+ u16 in_size, void *buf_out,
+ u16 *out_size)
+{
+ struct hinic3_event_info event_info = {0};
+ struct hinic3_mhost_nic_func_state state = {0};
+ struct hinic3_slave_func_nic_state *out_state = NULL;
+ struct hinic3_slave_func_nic_state *in_state = buf_in;
+
+ if (!hwdev->event_callback)
+ return 0;
+
+ event_info.type = EVENT_COMM_MULTI_HOST_MGMT;
+ ((struct hinic3_multi_host_mgmt_event *)(void *)event_info.event_data)->sub_cmd = sub_cmd;
+ ((struct hinic3_multi_host_mgmt_event *)(void *)event_info.event_data)->data = &state;
+
+ state.func_idx = in_state->func_idx;
+ state.enable = in_state->enable;
+
+ hwdev->event_callback(hwdev->event_pri_handle, &event_info);
+
+ *out_size = sizeof(*out_state);
+ out_state = buf_out;
+ out_state->status = state.status;
+ if (sub_cmd == HINIC3_MHOST_GET_VROCE_STATE)
+ out_state->opened = state.enable;
+
+ return state.status;
+}
+
+static int __event_set_func_nic_state(struct hinic3_hwdev *hwdev,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ return __event_func_service_state_handler(hwdev,
+ HINIC3_MHOST_NIC_STATE_CHANGE,
+ buf_in, in_size,
+ buf_out, out_size);
+}
+
+static int __event_set_func_vroce_state(struct hinic3_hwdev *hwdev,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ return __event_func_service_state_handler(hwdev,
+ HINIC3_MHOST_VROCE_STATE_CHANGE,
+ buf_in, in_size,
+ buf_out, out_size);
+}
+
+static int __event_get_func_vroce_state(struct hinic3_hwdev *hwdev,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ return __event_func_service_state_handler(hwdev,
+ HINIC3_MHOST_GET_VROCE_STATE,
+ buf_in, in_size,
+ buf_out, out_size);
+}
+
+int vf_sw_func_handler(void *hwdev, u8 cmd, void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ int err = 0;
+
+ switch (cmd) {
+ case HINIC3_SW_CMD_SET_SLAVE_FUNC_VROCE_STATE:
+ err = __event_set_func_vroce_state(hwdev, buf_in, in_size,
+ buf_out, out_size);
+ break;
+ case HINIC3_SW_CMD_GET_SLAVE_VROCE_DEVICE_STATE:
+ err = __event_get_func_vroce_state(hwdev, buf_in, in_size,
+ buf_out, out_size);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static int multi_host_event_handler(struct hinic3_hwdev *hwdev,
+ u8 cmd, void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ int err;
+
+ switch (cmd) {
+ case HINIC3_SW_CMD_SET_SLAVE_FUNC_VROCE_STATE:
+ err = __event_set_func_vroce_state(hwdev, buf_in, in_size,
+ buf_out, out_size);
+ break;
+ case HINIC3_SW_CMD_SET_SLAVE_FUNC_NIC_STATE:
+ err = __event_set_func_nic_state(hwdev, buf_in, in_size,
+ buf_out, out_size);
+ break;
+ case HINIC3_SW_CMD_GET_SLAVE_VROCE_DEVICE_STATE:
+ err = __event_get_func_vroce_state(hwdev, buf_in, in_size,
+ buf_out, out_size);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static int sw_set_slave_func_nic_state(struct hinic3_hwdev *hwdev, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic3_slave_func_nic_state *nic_state = buf_in;
+ struct hinic3_slave_func_nic_state *nic_state_out = buf_out;
+ struct hinic3_multi_host_mgmt *mhost_mgmt = hwdev->mhost_mgmt;
+ *out_size = sizeof(*nic_state);
+ nic_state_out->status = 0;
+ sdk_info(hwdev->dev_hdl, "Slave func %u %s nic\n",
+ nic_state->func_idx,
+ nic_state->enable ? "register" : "unregister");
+
+ if (nic_state->enable) {
+ set_bit(nic_state->func_idx, mhost_mgmt->func_nic_en);
+ } else {
+ if ((test_bit(nic_state->func_idx, mhost_mgmt->func_nic_en)) &&
+ nic_state->func_idx >= HINIC3_SUPPORT_MAX_PF_NUM &&
+ (!test_bit(nic_state->func_idx, hwdev->func_probe_in_host))) {
+ sdk_warn(hwdev->dev_hdl, "VF%u in vm, delete tap port failed\n",
+ nic_state->func_idx);
+ nic_state_out->status = HINIC3_VF_IN_VM;
+ return 0;
+ }
+ clear_bit(nic_state->func_idx, mhost_mgmt->func_nic_en);
+ }
+
+ return multi_host_event_handler(hwdev, cmd, buf_in, in_size, buf_out,
+ out_size);
+}
+
+static int sw_set_slave_vroce_state(struct hinic3_hwdev *hwdev, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic3_slave_func_nic_state *nic_state = buf_in;
+ struct hinic3_slave_func_nic_state *nic_state_out = buf_out;
+ struct hinic3_multi_host_mgmt *mhost_mgmt = hwdev->mhost_mgmt;
+ int err;
+
+ nic_state = buf_in;
+ *out_size = sizeof(*nic_state);
+ nic_state_out->status = 0;
+
+ sdk_info(hwdev->dev_hdl, "Slave func %u %s vroce\n", nic_state->func_idx,
+ nic_state->enable ? "register" : "unregister");
+
+ if (nic_state->enable)
+ set_bit(nic_state->func_idx,
+ mhost_mgmt->func_vroce_en);
+ else
+ clear_bit(nic_state->func_idx,
+ mhost_mgmt->func_vroce_en);
+
+ err = multi_host_event_handler(hwdev, cmd, buf_in, in_size,
+ buf_out, out_size);
+
+ return err;
+}
+
+static int sw_get_slave_vroce_device_state(struct hinic3_hwdev *hwdev, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic3_slave_func_nic_state *nic_state_out = buf_out;
+ int err;
+
+ *out_size = sizeof(struct hinic3_slave_func_nic_state);
+ nic_state_out->status = 0;
+ err = multi_host_event_handler(hwdev, cmd, buf_in, in_size, buf_out, out_size);
+
+ return err;
+}
+
+static void sw_get_slave_netdev_state(struct hinic3_hwdev *hwdev, u8 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic3_slave_func_nic_state *nic_state = buf_in;
+ struct hinic3_slave_func_nic_state *nic_state_out = buf_out;
+
+ *out_size = sizeof(*nic_state);
+ nic_state_out->status = 0;
+ nic_state_out->opened =
+ test_bit(nic_state->func_idx,
+ hwdev->netdev_setup_state) ? 1 : 0;
+}
+
+static int __slave_host_sw_func_handler(struct hinic3_hwdev *hwdev, u16 pf_idx,
+ u8 cmd, void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ struct hinic3_multi_host_mgmt *mhost_mgmt = hwdev->mhost_mgmt;
+ int err = 0;
+
+ if (!mhost_mgmt)
+ return -ENXIO;
+ switch (cmd) {
+ case HINIC3_SW_CMD_SET_SLAVE_FUNC_NIC_STATE:
+ err = sw_set_slave_func_nic_state(hwdev, cmd, buf_in, in_size,
+ buf_out, out_size);
+ break;
+ case HINIC3_SW_CMD_SET_SLAVE_FUNC_VROCE_STATE:
+ err = sw_set_slave_vroce_state(hwdev, cmd, buf_in, in_size,
+ buf_out, out_size);
+ break;
+ case HINIC3_SW_CMD_GET_SLAVE_VROCE_DEVICE_STATE:
+ err = sw_get_slave_vroce_device_state(hwdev, cmd,
+ buf_in, in_size,
+ buf_out, out_size);
+ break;
+ case HINIC3_SW_CMD_GET_SLAVE_NETDEV_STATE:
+ sw_get_slave_netdev_state(hwdev, cmd, buf_in, in_size,
+ buf_out, out_size);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+int sw_func_ppf_mbox_handler(void *handle, u16 pf_idx, u16 vf_id, u16 cmd,
+ void *buf_in, u16 in_size, void *buf_out,
+ u16 *out_size)
+{
+ struct hinic3_hwdev *hwdev = handle;
+ int err;
+
+ if (IS_MASTER_HOST(hwdev))
+ err = __master_host_sw_func_handler(hwdev, pf_idx, (u8)cmd, buf_in,
+ in_size, buf_out, out_size);
+ else if (IS_SLAVE_HOST(hwdev))
+ err = __slave_host_sw_func_handler(hwdev, pf_idx, (u8)cmd, buf_in,
+ in_size, buf_out, out_size);
+ else
+ err = -EINVAL;
+
+ if (err)
+ sdk_err(hwdev->dev_hdl, "PPF process sw funcs cmd %u failed, err: %d\n",
+ cmd, err);
+
+ return err;
+}
+
+int __ppf_process_mbox_msg(struct hinic3_hwdev *hwdev, u16 pf_idx, u16 vf_id,
+ enum hinic3_mod_type mod, u8 cmd, void *buf_in,
+ u16 in_size, void *buf_out, u16 *out_size)
+{
+ /* when not support return err */
+ int err = -EFAULT;
+
+ if (IS_SLAVE_HOST(hwdev)) {
+ err = hinic3_mbox_to_host_sync(hwdev, mod, cmd, buf_in, in_size,
+ buf_out, out_size, 0, HINIC3_CHANNEL_COMM);
+ if (err)
+ sdk_err(hwdev->dev_hdl, "Send mailbox to mPF failed, err: %d\n",
+ err);
+ } else if (IS_MASTER_HOST(hwdev)) {
+ if (mod == HINIC3_MOD_COMM && cmd == COMM_MGMT_CMD_START_FLR)
+ err = hinic3_pf_to_mgmt_no_ack(hwdev, mod, cmd, buf_in,
+ in_size);
+ else
+ err = hinic3_pf_msg_to_mgmt_sync(hwdev, mod, cmd, buf_in,
+ in_size, buf_out,
+ out_size, 0U);
+ if (err && err != HINIC3_MBOX_PF_BUSY_ACTIVE_FW)
+ sdk_err(hwdev->dev_hdl, "PF mbox mod %d cmd %u callback handler err: %d\n",
+ mod, cmd, err);
+ }
+
+ return err;
+}
+
+int hinic3_ppf_process_mbox_msg(struct hinic3_hwdev *hwdev, u16 pf_idx, u16 vf_id,
+ enum hinic3_mod_type mod, u8 cmd, void *buf_in,
+ u16 in_size, void *buf_out, u16 *out_size)
+{
+ bool same_host = false;
+ int err = -EFAULT;
+
+ /* Currently, only the master ppf and slave ppf communicate with each
+ * other through ppf messages. If other PF/VFs need to communicate
+ * with the PPF, modify the same_host based on the
+ * hinic3_get_hw_pf_infos information.
+ */
+
+ switch (hwdev->func_mode) {
+ case FUNC_MOD_MULTI_VM_MASTER:
+ case FUNC_MOD_MULTI_BM_MASTER:
+ if (!same_host)
+ err = __ppf_process_mbox_msg(hwdev, pf_idx, vf_id,
+ mod, cmd, buf_in, in_size,
+ buf_out, out_size);
+ else
+ sdk_warn(hwdev->dev_hdl, "Doesn't support PPF mbox message in BM master\n");
+
+ break;
+ case FUNC_MOD_MULTI_VM_SLAVE:
+ case FUNC_MOD_MULTI_BM_SLAVE:
+ same_host = true;
+ if (same_host)
+ err = __ppf_process_mbox_msg(hwdev, pf_idx, vf_id,
+ mod, cmd, buf_in, in_size,
+ buf_out, out_size);
+ else
+ sdk_warn(hwdev->dev_hdl, "Doesn't support receiving control messages from BM master\n");
+
+ break;
+ default:
+ sdk_warn(hwdev->dev_hdl, "Doesn't support PPF mbox message\n");
+
+ break;
+ }
+
+ return err;
+}
+
+int comm_ppf_mbox_handler(void *handle, u16 pf_idx, u16 vf_id, u16 cmd,
+ void *buf_in, u16 in_size, void *buf_out,
+ u16 *out_size)
+{
+ return hinic3_ppf_process_mbox_msg(handle, pf_idx, vf_id, HINIC3_MOD_COMM,
+ (u8)cmd, buf_in, in_size, buf_out,
+ out_size);
+}
+
+int hilink_ppf_mbox_handler(void *handle, u16 pf_idx, u16 vf_id, u16 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ return hinic3_ppf_process_mbox_msg(handle, pf_idx, vf_id,
+ HINIC3_MOD_HILINK, (u8)cmd, buf_in,
+ in_size, buf_out, out_size);
+}
+
+int hinic3_nic_ppf_mbox_handler(void *handle, u16 pf_idx, u16 vf_id, u16 cmd,
+ void *buf_in, u16 in_size,
+ void *buf_out, u16 *out_size)
+{
+ return hinic3_ppf_process_mbox_msg(handle, pf_idx, vf_id,
+ HINIC3_MOD_L2NIC, (u8)cmd, buf_in, in_size,
+ buf_out, out_size);
+}
+
+int hinic3_register_slave_ppf(struct hinic3_hwdev *hwdev, bool registered)
+{
+ struct register_slave_host *host_info = NULL;
+ u16 out_size = sizeof(struct register_slave_host);
+ u8 cmd;
+ int err;
+
+ if (!IS_SLAVE_HOST(hwdev))
+ return -EINVAL;
+
+ host_info = kcalloc(1, sizeof(struct register_slave_host), GFP_KERNEL);
+ if (!host_info)
+ return -ENOMEM;
+
+ cmd = registered ? HINIC3_SW_CMD_SLAVE_HOST_PPF_REGISTER :
+ HINIC3_SW_CMD_SLAVE_HOST_PPF_UNREGISTER;
+
+ host_info->host_id = hinic3_pcie_itf_id(hwdev);
+ host_info->ppf_idx = hinic3_ppf_idx(hwdev);
+
+ err = hinic3_mbox_to_host_sync(hwdev, HINIC3_MOD_SW_FUNC, cmd,
+ host_info, sizeof(struct register_slave_host), host_info,
+ &out_size, 0, HINIC3_CHANNEL_COMM);
+ if (!!err || !out_size || host_info->status) {
+ sdk_err(hwdev->dev_hdl, "Failed to %s slave host, err: %d, out_size: 0x%x, status: 0x%x\n",
+ registered ? "register" : "unregister", err, out_size, host_info->status);
+
+ kfree(host_info);
+ return -EFAULT;
+ }
+ bitmap_copy(hwdev->mhost_mgmt->func_nic_en,
+ (ulong *)host_info->funcs_nic_en,
+ HINIC3_MAX_MGMT_FUNCTIONS);
+
+ if (IS_SLAVE_HOST(hwdev))
+ bitmap_copy(hwdev->mhost_mgmt->func_vroce_en,
+ (ulong *)host_info->funcs_vroce_en,
+ HINIC3_MAX_MGMT_FUNCTIONS);
+
+ kfree(host_info);
+ return 0;
+}
+
+static int get_host_id_by_func_id(struct hinic3_hwdev *hwdev, u16 func_idx,
+ u8 *host_id)
+{
+ struct hinic3_hw_pf_infos *pf_infos = NULL;
+ u16 vf_id_start, vf_id_end;
+ int i;
+
+ if (!hwdev || !host_id || !hwdev->mhost_mgmt)
+ return -EINVAL;
+
+ pf_infos = &hwdev->mhost_mgmt->pf_infos;
+
+ for (i = 0; i < pf_infos->num_pfs; i++) {
+ if (func_idx == pf_infos->infos[i].glb_func_idx) {
+ *host_id = pf_infos->infos[i].itf_idx;
+ return 0;
+ }
+
+ vf_id_start = pf_infos->infos[i].glb_pf_vf_offset + 1;
+ vf_id_end = pf_infos->infos[i].glb_pf_vf_offset +
+ pf_infos->infos[i].max_vfs;
+ if (func_idx >= vf_id_start && func_idx <= vf_id_end) {
+ *host_id = pf_infos->infos[i].itf_idx;
+ return 0;
+ }
+ }
+
+ return -EFAULT;
+}
+
+int set_slave_func_nic_state(struct hinic3_hwdev *hwdev,
+ struct hinic3_func_nic_state *state)
+{
+ struct hinic3_slave_func_nic_state nic_state = {0};
+ u16 out_size = sizeof(nic_state);
+ u8 cmd = HINIC3_SW_CMD_SET_SLAVE_FUNC_NIC_STATE;
+ int err;
+
+ nic_state.func_idx = state->func_idx;
+ nic_state.enable = state->state;
+ nic_state.vroce_flag = state->vroce_flag;
+
+ if (state->vroce_flag)
+ cmd = HINIC3_SW_CMD_SET_SLAVE_FUNC_VROCE_STATE;
+
+ err = hinic3_mbox_to_host_sync(hwdev, HINIC3_MOD_SW_FUNC,
+ cmd, &nic_state, sizeof(nic_state),
+ &nic_state, &out_size, 0, HINIC3_CHANNEL_COMM);
+ if (err == MBOX_ERRCODE_UNKNOWN_DES_FUNC) {
+ sdk_warn(hwdev->dev_hdl,
+ "Can not notify func %u %s state because slave host isn't initialized\n",
+ state->func_idx, state->vroce_flag ? "vroce" : "nic");
+ } else if (err || !out_size || nic_state.status) {
+ sdk_err(hwdev->dev_hdl,
+ "Failed to set slave %s state, err: %d, out_size: 0x%x, status: 0x%x\n",
+ state->vroce_flag ? "vroce" : "nic",
+ err, out_size, nic_state.status);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int get_slave_func_netdev_state(struct hinic3_hwdev *hwdev, u16 func_idx,
+ int *opened)
+{
+ struct hinic3_slave_func_nic_state nic_state = {0};
+ u16 out_size = sizeof(nic_state);
+ int err;
+
+ nic_state.func_idx = func_idx;
+ err = hinic3_mbox_to_host_sync(hwdev, HINIC3_MOD_SW_FUNC,
+ HINIC3_SW_CMD_GET_SLAVE_NETDEV_STATE,
+ &nic_state, sizeof(nic_state), &nic_state,
+ &out_size, 0, HINIC3_CHANNEL_COMM);
+ if (err == MBOX_ERRCODE_UNKNOWN_DES_FUNC) {
+ sdk_warn(hwdev->dev_hdl,
+ "Can not get func %u netdev state because slave host isn't initialized\n",
+ func_idx);
+ } else if (err || !out_size || nic_state.status) {
+ sdk_err(hwdev->dev_hdl,
+ "Failed to get netdev state, err: %d, out_size: 0x%x, status: 0x%x\n",
+ err, out_size, nic_state.status);
+ return -EFAULT;
+ }
+
+ *opened = nic_state.opened;
+ return 0;
+}
+
+static int set_nic_state_params_valid(void *hwdev,
+ struct hinic3_func_nic_state *state)
+{
+ struct hinic3_multi_host_mgmt *mhost_mgmt = NULL;
+ struct hinic3_hwdev *ppf_hwdev = hwdev;
+
+ if (!hwdev || !state)
+ return -EINVAL;
+
+ if (hinic3_func_type(hwdev) != TYPE_PPF)
+ ppf_hwdev = ((struct hinic3_hwdev *)hwdev)->ppf_hwdev;
+
+ if (!ppf_hwdev || !IS_MASTER_HOST(ppf_hwdev))
+ return -EINVAL;
+
+ mhost_mgmt = ppf_hwdev->mhost_mgmt;
+ if (!mhost_mgmt || state->func_idx >= HINIC3_MAX_MGMT_FUNCTIONS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int get_func_current_state(struct hinic3_multi_host_mgmt *mhost_mgmt,
+ struct hinic3_func_nic_state *state,
+ int *old_state)
+{
+ ulong *func_bitmap = NULL;
+
+ if (state->vroce_flag == 1)
+ func_bitmap = mhost_mgmt->func_vroce_en;
+ else
+ func_bitmap = mhost_mgmt->func_nic_en;
+
+ *old_state = test_bit(state->func_idx, func_bitmap) ? 1 : 0;
+ if (state->state == HINIC3_FUNC_NIC_DEL)
+ clear_bit(state->func_idx, func_bitmap);
+ else if (state->state == HINIC3_FUNC_NIC_ADD)
+ set_bit(state->func_idx, func_bitmap);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static bool check_vroce_state(struct hinic3_multi_host_mgmt *mhost_mgmt,
+ struct hinic3_func_nic_state *state)
+{
+ bool is_ready = true;
+ ulong *func_bitmap = mhost_mgmt->func_vroce_en;
+
+ if (!state->vroce_flag && state->state == HINIC3_FUNC_NIC_DEL)
+ is_ready = test_bit(state->func_idx, func_bitmap) ? false : true;
+
+ return is_ready;
+}
+
+int hinic3_set_func_nic_state(void *hwdev, struct hinic3_func_nic_state *state)
+{
+ struct hinic3_multi_host_mgmt *mhost_mgmt = NULL;
+ struct hinic3_hwdev *ppf_hwdev = hwdev;
+ u8 host_enable;
+ int err, old_state = 0;
+ u8 host_id = 0;
+
+ err = set_nic_state_params_valid(hwdev, state);
+ if (err)
+ return err;
+
+ mhost_mgmt = ppf_hwdev->mhost_mgmt;
+
+ if (IS_MASTER_HOST(ppf_hwdev) &&
+ !check_vroce_state(mhost_mgmt, state)) {
+ sdk_warn(ppf_hwdev->dev_hdl,
+ "Should disable vroce before disable nic for function %u\n",
+ state->func_idx);
+ return -EFAULT;
+ }
+
+ err = get_func_current_state(mhost_mgmt, state, &old_state);
+ if (err) {
+ sdk_err(ppf_hwdev->dev_hdl, "Failed to get function %u current state, err: %d\n",
+ state->func_idx, err);
+ return err;
+ }
+
+ err = get_host_id_by_func_id(ppf_hwdev, state->func_idx, &host_id);
+ if (err) {
+ sdk_err(ppf_hwdev->dev_hdl,
+ "Failed to get function %u host id, err: %d\n", state->func_idx, err);
+ if (state->vroce_flag)
+ return -EFAULT;
+
+ old_state ? set_bit(state->func_idx, mhost_mgmt->func_nic_en) :
+ clear_bit(state->func_idx, mhost_mgmt->func_nic_en);
+ return -EFAULT;
+ }
+
+ err = hinic3_get_slave_host_enable(hwdev, host_id, &host_enable);
+ if (err != 0) {
+ sdk_err(ppf_hwdev->dev_hdl,
+ "Get slave host %u enable failed, ret %d\n", host_id, err);
+ return err;
+ }
+ sdk_info(ppf_hwdev->dev_hdl, "Set slave host %u(status: %u) func %u %s %s\n",
+ host_id, host_enable, state->func_idx,
+ state->state ? "enable" : "disable", state->vroce_flag ? "vroce" : "nic");
+
+ if (!host_enable)
+ return 0;
+
+ /* notify slave host */
+ err = set_slave_func_nic_state(hwdev, state);
+ if (err) {
+ if (state->vroce_flag)
+ return -EFAULT;
+
+ old_state ? set_bit(state->func_idx, mhost_mgmt->func_nic_en) :
+ clear_bit(state->func_idx, mhost_mgmt->func_nic_en);
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_set_func_nic_state);
+
+int hinic3_get_netdev_state(void *hwdev, u16 func_idx, int *opened)
+{
+ struct hinic3_hwdev *ppf_hwdev = hwdev;
+ int err;
+ u8 host_enable;
+ u8 host_id = 0;
+ struct hinic3_func_nic_state state = {0};
+
+ *opened = 0;
+ state.func_idx = func_idx;
+ err = set_nic_state_params_valid(hwdev, &state);
+ if (err)
+ return err;
+
+ err = get_host_id_by_func_id(ppf_hwdev, func_idx, &host_id);
+ if (err) {
+ sdk_err(ppf_hwdev->dev_hdl, "Failed to get function %u host id, err: %d\n",
+ func_idx, err);
+ return -EFAULT;
+ }
+
+ err = hinic3_get_slave_host_enable(hwdev, host_id, &host_enable);
+ if (err != 0) {
+ sdk_err(ppf_hwdev->dev_hdl, "Get slave host %u enable failed, ret %d\n",
+ host_id, err);
+ return err;
+ }
+ if (!host_enable)
+ return 0;
+
+ return get_slave_func_netdev_state(hwdev, func_idx, opened);
+}
+EXPORT_SYMBOL(hinic3_get_netdev_state);
+
+static int __get_func_nic_state_from_pf(struct hinic3_hwdev *hwdev,
+ u16 glb_func_idx, u8 *en)
+{
+ struct hinic3_multi_host_mgmt *mhost_mgmt = NULL;
+ struct hinic3_hwdev *ppf_hwdev = hwdev;
+
+ down(&hwdev->ppf_sem);
+ if (hinic3_func_type(hwdev) != TYPE_PPF)
+ ppf_hwdev = ((struct hinic3_hwdev *)hwdev)->ppf_hwdev;
+
+ if (!ppf_hwdev || !ppf_hwdev->mhost_mgmt) {
+ up(&hwdev->ppf_sem);
+ return -EFAULT;
+ }
+
+ mhost_mgmt = ppf_hwdev->mhost_mgmt;
+ *en = !!test_bit(glb_func_idx, mhost_mgmt->func_nic_en);
+ up(&hwdev->ppf_sem);
+
+ return 0;
+}
+
+static int __get_func_vroce_state_from_pf(struct hinic3_hwdev *hwdev,
+ u16 glb_func_idx, u8 *en)
+{
+ struct hinic3_multi_host_mgmt *mhost_mgmt = NULL;
+ struct hinic3_hwdev *ppf_hwdev = hwdev;
+
+ down(&hwdev->ppf_sem);
+ if (hinic3_func_type(hwdev) != TYPE_PPF)
+ ppf_hwdev = ((struct hinic3_hwdev *)hwdev)->ppf_hwdev;
+
+ if (!ppf_hwdev || !ppf_hwdev->mhost_mgmt) {
+ up(&hwdev->ppf_sem);
+ return -EFAULT;
+ }
+
+ mhost_mgmt = ppf_hwdev->mhost_mgmt;
+ *en = !!test_bit(glb_func_idx, mhost_mgmt->func_vroce_en);
+ up(&hwdev->ppf_sem);
+
+ return 0;
+}
+
+static int __get_vf_func_nic_state(struct hinic3_hwdev *hwdev, u16 glb_func_idx,
+ bool *en)
+{
+ struct hinic3_slave_func_nic_state nic_state = {0};
+ u16 out_size = sizeof(nic_state);
+ int err;
+
+ if (hinic3_func_type(hwdev) == TYPE_VF) {
+ nic_state.func_idx = glb_func_idx;
+ err = hinic3_mbox_to_pf(hwdev, HINIC3_MOD_SW_FUNC,
+ HINIC3_SW_CMD_GET_SLAVE_FUNC_NIC_STATE,
+ &nic_state, sizeof(nic_state),
+ &nic_state, &out_size, 0, HINIC3_CHANNEL_COMM);
+ if (err || !out_size || nic_state.status) {
+ sdk_err(hwdev->dev_hdl,
+ "Failed to get vf %u state, err: %d, out_size: %u, status: 0x%x\n",
+ glb_func_idx, err, out_size, nic_state.status);
+ return -EFAULT;
+ }
+
+ *en = !!nic_state.enable;
+
+ return 0;
+ }
+
+ return -EFAULT;
+}
+
+static int __get_func_vroce_state(struct hinic3_hwdev *hwdev, u16 glb_func_idx,
+ u8 *en)
+{
+ struct hinic3_slave_func_nic_state vroce_state = {0};
+ u16 out_size = sizeof(vroce_state);
+ int err;
+
+ if (hinic3_func_type(hwdev) == TYPE_VF) {
+ vroce_state.func_idx = glb_func_idx;
+ err = hinic3_mbox_to_pf(hwdev, HINIC3_MOD_SW_FUNC,
+ HINIC3_SW_CMD_GET_SLAVE_FUNC_VROCE_STATE,
+ &vroce_state, sizeof(vroce_state),
+ &vroce_state, &out_size, 0, HINIC3_CHANNEL_COMM);
+ if (err || !out_size || vroce_state.status) {
+ sdk_err(hwdev->dev_hdl,
+ "Failed to get vf %u state, err: %d, out_size: %u, status: 0x%x\n",
+ glb_func_idx, err, out_size, vroce_state.status);
+ return -EFAULT;
+ }
+
+ *en = !!vroce_state.enable;
+
+ return 0;
+ }
+
+ return __get_func_vroce_state_from_pf(hwdev, glb_func_idx, en);
+}
+
+int hinic3_get_func_vroce_enable(void *hwdev, u16 glb_func_idx, u8 *en)
+{
+ if (!hwdev || !en)
+ return -EINVAL;
+
+ return __get_func_vroce_state(hwdev, glb_func_idx, en);
+}
+EXPORT_SYMBOL(hinic3_get_func_vroce_enable);
+
+int hinic3_get_func_nic_enable(void *hwdev, u16 glb_func_idx, bool *en)
+{
+ u8 nic_en;
+ int err;
+
+ if (!hwdev || !en)
+ return -EINVAL;
+
+ /* if single host, return true. */
+ if (!IS_MULTI_HOST((struct hinic3_hwdev *)hwdev)) {
+ *en = true;
+ return 0;
+ }
+
+ if (!IS_SLAVE_HOST((struct hinic3_hwdev *)hwdev)) {
+ /* if card mode is OVS, VFs don't need attach_uld, so return false. */
+ if (hinic3_func_type(hwdev) == TYPE_VF &&
+ hinic3_support_ovs(hwdev, NULL))
+ *en = false;
+ else
+ *en = true;
+
+ return 0;
+ }
+
+ /* PF in slave host should be probe in CHIP_MODE_VMGW
+ * mode for pxe install.
+ * PF num need (0 ~31)
+ */
+ if (hinic3_func_type(hwdev) != TYPE_VF &&
+ IS_VM_SLAVE_HOST((struct hinic3_hwdev *)hwdev) &&
+ glb_func_idx < HINIC3_SUPPORT_MAX_PF_NUM) {
+ *en = true;
+ return 0;
+ }
+
+ /* try to get function nic state in sdk directly */
+ err = __get_func_nic_state_from_pf(hwdev, glb_func_idx, &nic_en);
+ if (err) {
+ if (glb_func_idx < HINIC3_SUPPORT_MAX_PF_NUM)
+ return err;
+ } else {
+ *en = !!nic_en;
+ return 0;
+ }
+
+ return __get_vf_func_nic_state(hwdev, glb_func_idx, en);
+}
+
+static int slave_host_init(struct hinic3_hwdev *hwdev)
+{
+ int err;
+
+ if (IS_SLAVE_HOST(hwdev)) {
+ /* PXE doesn't support to receive mbox from master host */
+ set_slave_host_enable(hwdev, hinic3_pcie_itf_id(hwdev), true);
+ if ((IS_VM_SLAVE_HOST(hwdev) &&
+ hinic3_get_master_host_mbox_enable(hwdev)) ||
+ IS_BMGW_SLAVE_HOST(hwdev)) {
+ err = hinic3_register_slave_ppf(hwdev, true);
+ if (err) {
+ set_slave_host_enable(hwdev, hinic3_pcie_itf_id(hwdev), false);
+ return err;
+ }
+ }
+ } else {
+ /* slave host can send message to mgmt cpu
+ * after setup master mbox
+ */
+ set_master_host_mbox_enable(hwdev, true);
+ }
+
+ return 0;
+}
+
+int hinic3_multi_host_mgmt_init(struct hinic3_hwdev *hwdev)
+{
+ int err;
+ struct service_cap *cap = &hwdev->cfg_mgmt->svc_cap;
+
+ if (!IS_MULTI_HOST(hwdev) || !HINIC3_IS_PPF(hwdev))
+ return 0;
+
+ hwdev->mhost_mgmt = kcalloc(1, sizeof(*hwdev->mhost_mgmt), GFP_KERNEL);
+ if (!hwdev->mhost_mgmt)
+ return -ENOMEM;
+
+ hwdev->mhost_mgmt->shost_ppf_idx = hinic3_host_ppf_idx(hwdev, HINIC3_MGMT_SHOST_HOST_ID);
+ hwdev->mhost_mgmt->mhost_ppf_idx = hinic3_host_ppf_idx(hwdev, cap->master_host_id);
+
+ err = hinic3_get_hw_pf_infos(hwdev, &hwdev->mhost_mgmt->pf_infos, HINIC3_CHANNEL_COMM);
+ if (err)
+ goto out_free_mhost_mgmt;
+
+ hinic3_register_ppf_mbox_cb(hwdev, HINIC3_MOD_COMM, hwdev, comm_ppf_mbox_handler);
+ hinic3_register_ppf_mbox_cb(hwdev, HINIC3_MOD_L2NIC, hwdev, hinic3_nic_ppf_mbox_handler);
+ hinic3_register_ppf_mbox_cb(hwdev, HINIC3_MOD_HILINK, hwdev, hilink_ppf_mbox_handler);
+ hinic3_register_ppf_mbox_cb(hwdev, HINIC3_MOD_SW_FUNC, hwdev, sw_func_ppf_mbox_handler);
+
+ bitmap_zero(hwdev->mhost_mgmt->func_nic_en, HINIC3_MAX_MGMT_FUNCTIONS);
+ bitmap_zero(hwdev->mhost_mgmt->func_vroce_en, HINIC3_MAX_MGMT_FUNCTIONS);
+
+ /* Slave host:
+ * register slave host ppf functions
+ * Get function's nic state
+ */
+ err = slave_host_init(hwdev);
+ if (err)
+ goto out_free_mhost_mgmt;
+
+ return 0;
+
+out_free_mhost_mgmt:
+ kfree(hwdev->mhost_mgmt);
+ hwdev->mhost_mgmt = NULL;
+
+ return err;
+}
+
+int hinic3_multi_host_mgmt_free(struct hinic3_hwdev *hwdev)
+{
+ if (!IS_MULTI_HOST(hwdev) || !HINIC3_IS_PPF(hwdev))
+ return 0;
+
+ if (IS_SLAVE_HOST(hwdev)) {
+ hinic3_register_slave_ppf(hwdev, false);
+
+ set_slave_host_enable(hwdev, hinic3_pcie_itf_id(hwdev), false);
+ } else {
+ set_master_host_mbox_enable(hwdev, false);
+ }
+
+ hinic3_unregister_ppf_mbox_cb(hwdev, HINIC3_MOD_COMM);
+ hinic3_unregister_ppf_mbox_cb(hwdev, HINIC3_MOD_L2NIC);
+ hinic3_unregister_ppf_mbox_cb(hwdev, HINIC3_MOD_HILINK);
+ hinic3_unregister_ppf_mbox_cb(hwdev, HINIC3_MOD_SW_FUNC);
+
+ kfree(hwdev->mhost_mgmt);
+ hwdev->mhost_mgmt = NULL;
+
+ return 0;
+}
+
+int hinic3_get_mhost_func_nic_enable(void *hwdev, u16 func_id, bool *en)
+{
+ struct hinic3_hwdev *dev = hwdev;
+ u8 func_en;
+ int ret;
+
+ if (!hwdev || !en || func_id >= HINIC3_MAX_MGMT_FUNCTIONS || !IS_MULTI_HOST(dev))
+ return -EINVAL;
+
+ ret = __get_func_nic_state_from_pf(hwdev, func_id, &func_en);
+ if (ret)
+ return ret;
+
+ *en = !!func_en;
+
+ return 0;
+}
+EXPORT_SYMBOL(hinic3_get_mhost_func_nic_enable);
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_multi_host_mgmt.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_multi_host_mgmt.h
new file mode 100644
index 0000000000000..fb25160e3ebd0
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_multi_host_mgmt.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2022 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC3_MULTI_HOST_MGMT_H
+#define HINIC3_MULTI_HOST_MGMT_H
+
+#define HINIC3_VF_IN_VM 0x3
+
+#define HINIC3_MGMT_SHOST_HOST_ID 0
+#define HINIC3_MAX_MGMT_FUNCTIONS 1024
+#define HINIC3_MAX_MGMT_FUNCTIONS_64 (HINIC3_MAX_MGMT_FUNCTIONS / 64)
+
+struct hinic3_multi_host_mgmt {
+ struct hinic3_hwdev *hwdev;
+
+ /* slave host registered */
+ bool shost_registered;
+ u8 shost_host_idx;
+ u8 shost_ppf_idx;
+
+ u8 mhost_ppf_idx;
+ u8 rsvd1;
+
+ /* slave host functios support nic enable */
+ DECLARE_BITMAP(func_nic_en, HINIC3_MAX_MGMT_FUNCTIONS);
+ DECLARE_BITMAP(func_vroce_en, HINIC3_MAX_MGMT_FUNCTIONS);
+
+ struct hinic3_hw_pf_infos pf_infos;
+
+ u64 rsvd2;
+};
+
+struct hinic3_host_fwd_head {
+ unsigned short dst_glb_func_idx;
+ unsigned char dst_itf_idx;
+ unsigned char mod;
+
+ unsigned char cmd;
+ unsigned char rsv[3];
+};
+
+/* software cmds, vf->pf and multi-host */
+enum hinic3_sw_funcs_cmd {
+ HINIC3_SW_CMD_SLAVE_HOST_PPF_REGISTER = 0x0,
+ HINIC3_SW_CMD_SLAVE_HOST_PPF_UNREGISTER,
+ HINIC3_SW_CMD_GET_SLAVE_FUNC_NIC_STATE,
+ HINIC3_SW_CMD_SET_SLAVE_FUNC_NIC_STATE,
+ HINIC3_SW_CMD_SEND_MSG_TO_VF,
+ HINIC3_SW_CMD_MIGRATE_READY,
+ HINIC3_SW_CMD_GET_SLAVE_NETDEV_STATE,
+
+ HINIC3_SW_CMD_GET_SLAVE_FUNC_VROCE_STATE,
+ HINIC3_SW_CMD_SET_SLAVE_FUNC_VROCE_STATE,
+ HINIC3_SW_CMD_GET_SLAVE_VROCE_DEVICE_STATE = 0x9, // 与vroce_cfg_vf_do.h宏一致
+};
+
+/* multi host mgmt event sub cmd */
+enum hinic3_mhost_even_type {
+ HINIC3_MHOST_NIC_STATE_CHANGE = 1,
+ HINIC3_MHOST_VROCE_STATE_CHANGE = 2,
+ HINIC3_MHOST_GET_VROCE_STATE = 3,
+};
+
+struct hinic3_mhost_nic_func_state {
+ u8 status;
+ u8 enable;
+ u16 func_idx;
+};
+
+struct hinic3_multi_host_mgmt_event {
+ u16 sub_cmd;
+ u16 rsvd[3];
+
+ void *data;
+};
+
+int hinic3_multi_host_mgmt_init(struct hinic3_hwdev *hwdev);
+int hinic3_multi_host_mgmt_free(struct hinic3_hwdev *hwdev);
+int hinic3_mbox_to_host_no_ack(struct hinic3_hwdev *hwdev, enum hinic3_mod_type mod, u8 cmd,
+ void *buf_in, u16 in_size, u16 channel);
+
+struct register_slave_host {
+ u8 status;
+ u8 version;
+ u8 rsvd[6];
+
+ u8 host_id;
+ u8 ppf_idx;
+ u8 get_nic_en;
+ u8 rsvd2[5];
+
+ /* 16 * 64 bits for max 1024 functions */
+ u64 funcs_nic_en[HINIC3_MAX_MGMT_FUNCTIONS_64];
+ /* 16 * 64 bits for max 1024 functions */
+ u64 funcs_vroce_en[HINIC3_MAX_MGMT_FUNCTIONS_64];
+};
+
+struct hinic3_slave_func_nic_state {
+ u8 status;
+ u8 version;
+ u8 rsvd[6];
+
+ u16 func_idx;
+ u8 enable;
+ u8 opened;
+ u8 vroce_flag;
+ u8 rsvd2[7];
+};
+
+void set_master_host_mbox_enable(struct hinic3_hwdev *hwdev, bool enable);
+
+int sw_func_pf_mbox_handler(void *pri_handle, u16 vf_id, u16 cmd, void *buf_in,
+ u16 in_size, void *buf_out, u16 *out_size);
+
+int vf_sw_func_handler(void *hwdev, u8 cmd, void *buf_in,
+ u16 in_size, void *buf_out, u16 *out_size);
+int hinic3_set_func_probe_in_host(void *hwdev, u16 func_id, bool probe);
+bool hinic3_get_func_probe_in_host(void *hwdev, u16 func_id);
+
+void *hinic3_get_ppf_hwdev_by_pdev(struct pci_dev *pdev);
+
+int hinic3_get_func_nic_enable(void *hwdev, u16 glb_func_idx, bool *en);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
index bd39ee7d54a7e..f7d350cb59668 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_nictool.c
@@ -40,6 +40,7 @@ int card_id;
typedef int (*hw_driv_module)(struct hinic3_lld_dev *lld_dev, const void *buf_in,
u32 in_size, void *buf_out, u32 *out_size);
+
struct hw_drv_module_handle {
enum driver_cmd_type driv_cmd_name;
hw_driv_module driv_func;
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_pci_id_tbl.h b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_pci_id_tbl.h
index 21ab78a8eeade..d71474ea8458c 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/hinic3_pci_id_tbl.h
+++ b/drivers/net/ethernet/huawei/hinic3/hw/hinic3_pci_id_tbl.h
@@ -4,15 +4,39 @@
#ifndef HINIC3_PCI_ID_TBL_H
#define HINIC3_PCI_ID_TBL_H
+#define HINIC3_VIRTIO_VNEDER_ID 0x1AF4
+#ifdef CONFIG_SP_VID_DID
+#define PCI_VENDOR_ID_SPNIC 0x1F3F
+#define HINIC3_DEV_ID_STANDARD 0x9020
+#define HINIC3_DEV_ID_SDI_5_1_PF 0x9032
+#define HINIC3_DEV_ID_SDI_5_0_PF 0x9031
+#define HINIC3_DEV_ID_DPU_PF 0x9030
+#define HINIC3_DEV_ID_SPN120 0x9021
+#define HINIC3_DEV_ID_VF 0x9001
+#define HINIC3_DEV_ID_VF_HV 0x9002
+#define HINIC3_DEV_SDI_5_1_ID_VF 0x9003
+#define HINIC3_DEV_SDI_5_1_ID_VF_HV 0x9004
+#define HINIC3_DEV_ID_SPU 0xAC00
+#define HINIC3_DEV_SDI_5_1_SSDID_VF 0x1000
+#define HINIC3_DEV_SDI_V100_SSDID_MASK (3 << 12)
+#else
#define PCI_VENDOR_ID_HUAWEI 0x19e5
-
#define HINIC3_DEV_ID_STANDARD 0x0222
-#define HINIC3_DEV_ID_DPU_PF 0x0224
-#define HINIC3_DEV_ID_SDI_5_0_PF 0x0225
#define HINIC3_DEV_ID_SDI_5_1_PF 0x0226
+#define HINIC3_DEV_ID_SDI_5_0_PF 0x0225
+#define HINIC3_DEV_ID_DPU_PF 0x0224
#define HINIC3_DEV_ID_VF 0x375F
#define HINIC3_DEV_ID_VF_HV 0x379F
+#define HINIC3_DEV_SDI_5_1_ID_VF 0x375F
+#define HINIC3_DEV_SDI_5_1_ID_VF_HV 0x379F
#define HINIC3_DEV_ID_SPU 0xAC00
+#define HINIC3_DEV_SDI_5_1_SSDID_VF 0x1000
+#define HINIC3_DEV_SDI_V100_SSDID_MASK (3 << 12)
+#endif
+
+#define HINIC3_DEV_SSID_2X25G 0x0051
+#define HINIC3_DEV_SSID_4X25G 0x0052
+#define HINIC3_DEV_SSID_2X100G 0x00A1
#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/hw/ossl_knl_linux.c b/drivers/net/ethernet/huawei/hinic3/hw/ossl_knl_linux.c
index 874da7606453f..f8aea696d81cf 100644
--- a/drivers/net/ethernet/huawei/hinic3/hw/ossl_knl_linux.c
+++ b/drivers/net/ethernet/huawei/hinic3/hw/ossl_knl_linux.c
@@ -23,7 +23,7 @@ void file_close(struct file *file_handle)
u32 get_file_size(struct file *file_handle)
{
- struct inode *file_inode;
+ struct inode *file_inode = NULL;
file_inode = file_handle->f_inode;
@@ -35,6 +35,19 @@ void set_file_position(struct file *file_handle, u32 position)
file_handle->f_pos = position;
}
+int file_read(struct file *file_handle, char *log_buffer, u32 rd_length,
+ u32 *file_pos)
+{
+ return (int)kernel_read(file_handle, log_buffer, rd_length,
+ &file_handle->f_pos);
+}
+
+u32 file_write(struct file *file_handle, const char *log_buffer, u32 wr_length)
+{
+ return (u32)kernel_write(file_handle, log_buffer, wr_length,
+ &file_handle->f_pos);
+}
+
static int _linux_thread_func(void *thread)
{
struct sdk_thread_info *info = (struct sdk_thread_info *)thread;
@@ -63,8 +76,7 @@ void stop_thread(struct sdk_thread_info *thread_info)
void utctime_to_localtime(u64 utctime, u64 *localtime)
{
- *localtime = utctime - sys_tz.tz_minuteswest *
- OSSL_MINUTE_BASE; /*lint !e647*/
+ *localtime = utctime - (u64)(sys_tz.tz_minuteswest * OSSL_MINUTE_BASE); /*lint !e647 !e571*/
}
#ifndef HAVE_TIMER_SETUP
@@ -77,7 +89,7 @@ void initialize_timer(const void *adapter_hdl, struct timer_list *timer)
}
#endif
-void add_to_timer(struct timer_list *timer, long period)
+void add_to_timer(struct timer_list *timer, u64 period)
{
if (!timer)
return;
diff --git a/drivers/net/ethernet/huawei/hinic3/include/bond/bond_common_defs.h b/drivers/net/ethernet/huawei/hinic3/include/bond/bond_common_defs.h
new file mode 100644
index 0000000000000..5ae3f4e5e9e8f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/bond/bond_common_defs.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. */
+
+#ifndef BOND_COMMON_DEFS_H
+#define BOND_COMMON_DEFS_H
+
+#define BOND_NAME_MAX_LEN 16
+#define BOND_PORT_MAX_NUM 4
+#define BOND_ID_INVALID 0xFFFF
+#define OVS_PORT_NUM_MAX BOND_PORT_MAX_NUM
+#define DEFAULT_ROCE_BOND_FUNC 0xFFFFFFFF
+
+enum bond_group_id {
+ BOND_FIRST_ID = 1,
+ BOND_MAX_ID = 4,
+ BOND_MAX_NUM,
+};
+
+#pragma pack(4)
+/**
+ * bond per port statistics
+ */
+struct tag_bond_port_stat {
+ /** mpu provide */
+ u64 rx_pkts;
+ u64 rx_bytes;
+ u64 rx_drops;
+ u64 rx_errors;
+
+ u64 tx_pkts;
+ u64 tx_bytes;
+ u64 tx_drops;
+ u64 tx_errors;
+};
+
+#pragma pack()
+
+/**
+ * bond port attribute
+ */
+struct tag_bond_port_attr {
+ u8 duplex;
+ u8 status;
+ u8 rsvd0[2];
+ u32 speed;
+};
+
+/**
+ * Get bond information command struct defination
+ * @see OVS_MPU_CMD_BOND_GET_ATTR
+ */
+struct tag_bond_get {
+ u16 bond_id_vld; /* 1: used bond_id get bond info, 0: used bond_name */
+ u16 bond_id; /* if bond_id_vld=1 input, else output */
+ u8 bond_name[BOND_NAME_MAX_LEN]; /* if bond_id_vld=0 input, else output */
+
+ u16 bond_mode; /* 1 for active-backup,2 for balance-xor,4 for 802.3ad */
+ u8 active_slaves; /* active port slaves(bitmaps) */
+ u8 slaves; /* bond port id bitmaps */
+
+ u8 lacp_collect_slaves; /* bond port id bitmaps */
+ u8 xmit_hash_policy; /* xmit hash:0 for layer 2, 1 for layer 2+3, 2 for layer 3+4 */
+ u16 rsvd0; /* in order to 4B aligned */
+
+ struct tag_bond_port_stat stat[BOND_PORT_MAX_NUM];
+ struct tag_bond_port_attr attr[BOND_PORT_MAX_NUM];
+};
+
+#endif /** BOND_COMMON_DEFS_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd.h b/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd.h
new file mode 100644
index 0000000000000..a13b66da9887f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CFG_MGMT_MPU_CMD_H
+#define CFG_MGMT_MPU_CMD_H
+
+enum cfg_cmd {
+ CFG_CMD_GET_DEV_CAP = 0, /**< Device capability of pf/vf, @see cfg_cmd_dev_cap */
+ CFG_CMD_GET_HOST_TIMER = 1, /**< Capability of host timer, @see cfg_cmd_host_timer */
+};
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h b/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h
new file mode 100644
index 0000000000000..f56df083a059c
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/cfg_mgmt/cfg_mgmt_mpu_cmd_defs.h
@@ -0,0 +1,212 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CFG_MGMT_MPU_CMD_DEFS_H
+#define CFG_MGMT_MPU_CMD_DEFS_H
+
+#include "mpu_cmd_base_defs.h"
+
+enum servic_bit_define {
+ SERVICE_BIT_NIC = 0,
+ SERVICE_BIT_ROCE = 1,
+ SERVICE_BIT_VBS = 2,
+ SERVICE_BIT_TOE = 3,
+ SERVICE_BIT_IPSEC = 4,
+ SERVICE_BIT_FC = 5,
+ SERVICE_BIT_VIRTIO = 6,
+ SERVICE_BIT_OVS = 7,
+ SERVICE_BIT_NVME = 8,
+ SERVICE_BIT_ROCEAA = 9,
+ SERVICE_BIT_CURRENET = 10,
+ SERVICE_BIT_PPA = 11,
+ SERVICE_BIT_MIGRATE = 12,
+ SERVICE_BIT_VROCE = 13,
+ SERVICE_BIT_MAX
+};
+
+#define CFG_SERVICE_MASK_NIC (0x1 << SERVICE_BIT_NIC)
+#define CFG_SERVICE_MASK_ROCE (0x1 << SERVICE_BIT_ROCE)
+#define CFG_SERVICE_MASK_VBS (0x1 << SERVICE_BIT_VBS)
+#define CFG_SERVICE_MASK_TOE (0x1 << SERVICE_BIT_TOE)
+#define CFG_SERVICE_MASK_IPSEC (0x1 << SERVICE_BIT_IPSEC)
+#define CFG_SERVICE_MASK_FC (0x1 << SERVICE_BIT_FC)
+#define CFG_SERVICE_MASK_VIRTIO (0x1 << SERVICE_BIT_VIRTIO)
+#define CFG_SERVICE_MASK_OVS (0x1 << SERVICE_BIT_OVS)
+#define CFG_SERVICE_MASK_NVME (0x1 << SERVICE_BIT_NVME)
+#define CFG_SERVICE_MASK_ROCEAA (0x1 << SERVICE_BIT_ROCEAA)
+#define CFG_SERVICE_MASK_CURRENET (0x1 << SERVICE_BIT_CURRENET)
+#define CFG_SERVICE_MASK_PPA (0x1 << SERVICE_BIT_PPA)
+#define CFG_SERVICE_MASK_MIGRATE (0x1 << SERVICE_BIT_MIGRATE)
+#define CFG_SERVICE_MASK_VROCE (0x1 << SERVICE_BIT_VROCE)
+
+/* Definition of the scenario ID in the cfg_data, which is used for SML memory allocation. */
+enum scenes_id_define {
+ SCENES_ID_FPGA_ETH = 0,
+ SCENES_ID_COMPUTE_STANDARD = 1,
+ SCENES_ID_STORAGE_ROCEAA_2x100 = 2,
+ SCENES_ID_STORAGE_ROCEAA_4x25 = 3,
+ SCENES_ID_CLOUD = 4,
+ SCENES_ID_FC = 5,
+ SCENES_ID_STORAGE_ROCE = 6,
+ SCENES_ID_COMPUTE_ROCE = 7,
+ SCENES_ID_STORAGE_TOE = 8,
+ SCENES_ID_MAX
+};
+
+/* struct cfg_cmd_dev_cap.sf_svc_attr */
+enum {
+ SF_SVC_FT_BIT = (1 << 0),
+ SF_SVC_RDMA_BIT = (1 << 1),
+};
+
+struct cfg_cmd_host_timer {
+ struct mgmt_msg_head head;
+
+ u8 host_id;
+ u8 rsvd1;
+
+ u8 timer_pf_num;
+ u8 timer_pf_id_start;
+ u16 timer_vf_num;
+ u16 timer_vf_id_start;
+ u32 rsvd2[8];
+};
+
+struct cfg_cmd_dev_cap {
+ struct mgmt_msg_head head;
+
+ u16 func_id;
+ u16 rsvd1;
+
+ /* Public resources */
+ u8 host_id;
+ u8 ep_id;
+ u8 er_id;
+ u8 port_id;
+
+ u16 host_total_func;
+ u8 host_pf_num;
+ u8 pf_id_start;
+ u16 host_vf_num;
+ u16 vf_id_start;
+ u8 host_oq_id_mask_val;
+ u8 timer_en;
+ u8 host_valid_bitmap;
+ u8 rsvd_host;
+
+ u16 svc_cap_en;
+ u16 max_vf;
+ u8 flexq_en;
+ u8 valid_cos_bitmap;
+ /* Reserved for func_valid_cos_bitmap */
+ u8 port_cos_valid_bitmap;
+ u8 rsvd_func1;
+ u32 rsvd_func2;
+
+ u8 sf_svc_attr;
+ u8 func_sf_en;
+ u8 lb_mode;
+ u8 smf_pg;
+
+ u32 max_conn_num;
+ u16 max_stick2cache_num;
+ u16 max_bfilter_start_addr;
+ u16 bfilter_len;
+ u16 hash_bucket_num;
+
+ /* shared resource */
+ u8 host_sf_en;
+ u8 master_host_id;
+ u8 srv_multi_host_mode;
+ u8 virtio_vq_size;
+
+ u32 rsvd_func3[5];
+
+ /* l2nic */
+ u16 nic_max_sq_id;
+ u16 nic_max_rq_id;
+ u16 nic_default_num_queues;
+ u16 rsvd1_nic;
+ u32 rsvd2_nic[2];
+
+ /* RoCE */
+ u32 roce_max_qp;
+ u32 roce_max_cq;
+ u32 roce_max_srq;
+ u32 roce_max_mpt;
+ u32 roce_max_drc_qp;
+
+ u32 roce_cmtt_cl_start;
+ u32 roce_cmtt_cl_end;
+ u32 roce_cmtt_cl_size;
+
+ u32 roce_dmtt_cl_start;
+ u32 roce_dmtt_cl_end;
+ u32 roce_dmtt_cl_size;
+
+ u32 roce_wqe_cl_start;
+ u32 roce_wqe_cl_end;
+ u32 roce_wqe_cl_size;
+ u8 roce_srq_container_mode;
+ u8 rsvd_roce1[3];
+ u32 rsvd_roce2[5];
+
+ /* IPsec */
+ u32 ipsec_max_sactx;
+ u16 ipsec_max_cq;
+ u16 rsvd_ipsec1;
+ u32 rsvd_ipsec[2];
+
+ /* OVS */
+ u32 ovs_max_qpc;
+ u32 rsvd_ovs1[3];
+
+ /* ToE */
+ u32 toe_max_pctx;
+ u32 toe_max_cq;
+ u16 toe_max_srq;
+ u16 toe_srq_id_start;
+ u16 toe_max_mpt;
+ u16 toe_rsvd_1;
+ u32 toe_max_cctxt;
+ u32 rsvd_toe[1];
+
+ /* FC */
+ u32 fc_max_pctx;
+ u32 fc_max_scq;
+ u32 fc_max_srq;
+
+ u32 fc_max_cctx;
+ u32 fc_cctx_id_start;
+
+ u8 fc_vp_id_start;
+ u8 fc_vp_id_end;
+ u8 rsvd_fc1[2];
+ u32 rsvd_fc2[5];
+
+ /* VBS */
+ u16 vbs_max_volq;
+ u8 vbs_main_pf_enable;
+ u8 vbs_vsock_pf_enable;
+ u8 vbs_fushion_queue_pf_enable;
+ u8 rsvd0_vbs;
+ u16 rsvd1_vbs;
+ u32 rsvd2_vbs[2];
+
+ u16 fake_vf_start_id;
+ u16 fake_vf_num;
+ u32 fake_vf_max_pctx;
+ u16 fake_vf_bfilter_start_addr;
+ u16 fake_vf_bfilter_len;
+
+ u32 map_host_id : 3;
+ u32 fake_vf_en : 1;
+ u32 fake_vf_start_bit : 4;
+ u32 fake_vf_end_bit : 4;
+ u32 fake_vf_page_bit : 4;
+ u32 rsvd2 : 16;
+
+ u32 rsvd_glb[7];
+};
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/cqm/cqm_npu_cmd.h b/drivers/net/ethernet/huawei/hinic3/include/cqm/cqm_npu_cmd.h
new file mode 100644
index 0000000000000..d4e33f702c0a4
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/cqm/cqm_npu_cmd.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_NPU_CMD_H
+#define CQM_NPU_CMD_H
+
+enum cqm_cmd_type {
+ CQM_CMD_T_INVALID = 0, /* < Invalid command */
+ CQM_CMD_T_BAT_UPDATE, /* < Update the bat configuration of the funciton,
+ * @see struct tag_cqm_cmdq_bat_update
+ */
+ CQM_CMD_T_CLA_UPDATE, /* < Update the cla configuration of the funciton,
+ * @see struct tag_cqm_cla_update_cmd
+ */
+ CQM_CMD_T_BLOOMFILTER_SET, /* < Set the bloomfilter configuration of the funciton,
+ * @see struct tag_cqm_bloomfilter_cmd
+ */
+ CQM_CMD_T_BLOOMFILTER_CLEAR, /* < Clear the bloomfilter configuration of the funciton,
+ * @see struct tag_cqm_bloomfilter_cmd
+ */
+ CQM_CMD_T_RSVD, /* < Unused */
+ CQM_CMD_T_CLA_CACHE_INVALID, /* < Invalidate the cla cacheline,
+ * @see struct tag_cqm_cla_cache_invalid_cmd
+ */
+ CQM_CMD_T_BLOOMFILTER_INIT, /* < Init the bloomfilter configuration of the funciton,
+ * @see struct tag_cqm_bloomfilter_init_cmd
+ */
+ CQM_CMD_T_MAX
+};
+
+#endif /* CQM_NPU_CMD_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/include/cqm/cqm_npu_cmd_defs.h b/drivers/net/ethernet/huawei/hinic3/include/cqm/cqm_npu_cmd_defs.h
new file mode 100644
index 0000000000000..28b83edde4016
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/cqm/cqm_npu_cmd_defs.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_NPU_CMD_DEFS_H
+#define CQM_NPU_CMD_DEFS_H
+
+struct tag_cqm_cla_cache_invalid_cmd {
+ u32 gpa_h;
+ u32 gpa_l;
+
+ u32 cache_size; /* CLA cache size=4096B */
+
+ u32 smf_id;
+ u32 func_id;
+};
+
+struct tag_cqm_cla_update_cmd {
+ /* Gpa address to be updated */
+ u32 gpa_h; // byte addr
+ u32 gpa_l; // byte addr
+
+ /* Updated Value */
+ u32 value_h;
+ u32 value_l;
+
+ u32 smf_id;
+ u32 func_id;
+};
+
+struct tag_cqm_bloomfilter_cmd {
+ u32 rsv1;
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+ u32 k_en : 4;
+ u32 func_id : 16;
+ u32 rsv2 : 12;
+#else
+ u32 rsv2 : 12;
+ u32 func_id : 16;
+ u32 k_en : 4;
+#endif
+
+ u32 index_h;
+ u32 index_l;
+};
+
+#define CQM_BAT_MAX_SIZE 256
+struct tag_cqm_cmdq_bat_update {
+ u32 offset; // byte offset,16Byte aligned
+ u32 byte_len; // max size: 256byte
+ u8 data[CQM_BAT_MAX_SIZE];
+ u32 smf_id;
+ u32 func_id;
+};
+
+struct tag_cqm_bloomfilter_init_cmd {
+ u32 bloom_filter_len; // 16Byte aligned
+ u32 bloom_filter_addr;
+};
+
+#endif /* CQM_CMDQ_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/include/hinic3_common.h b/drivers/net/ethernet/huawei/hinic3/include/hinic3_common.h
new file mode 100644
index 0000000000000..73cb1335a4ece
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/hinic3_common.h
@@ -0,0 +1,181 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC3_COMMON_H
+#define HINIC3_COMMON_H
+
+#include <linux/types.h>
+
+struct hinic3_dma_addr_align {
+ u32 real_size;
+
+ void *ori_vaddr;
+ dma_addr_t ori_paddr;
+
+ void *align_vaddr;
+ dma_addr_t align_paddr;
+};
+
+enum hinic3_wait_return {
+ WAIT_PROCESS_CPL = 0,
+ WAIT_PROCESS_WAITING = 1,
+ WAIT_PROCESS_ERR = 2,
+};
+
+struct hinic3_sge {
+ u32 hi_addr;
+ u32 lo_addr;
+ u32 len;
+};
+
+/* *
+ * hinic_cpu_to_be32 - convert data to big endian 32 bit format
+ * @data: the data to convert
+ * @len: length of data to convert, must be Multiple of 4B
+ */
+static inline void hinic3_cpu_to_be32(void *data, int len)
+{
+ int i, chunk_sz = sizeof(u32);
+ int data_len = len;
+ u32 *mem = data;
+
+ if (!data)
+ return;
+
+ data_len = data_len / chunk_sz;
+
+ for (i = 0; i < data_len; i++) {
+ *mem = cpu_to_be32(*mem);
+ mem++;
+ }
+}
+
+/* *
+ * hinic3_cpu_to_be32 - convert data from big endian 32 bit format
+ * @data: the data to convert
+ * @len: length of data to convert
+ */
+static inline void hinic3_be32_to_cpu(void *data, int len)
+{
+ int i, chunk_sz = sizeof(u32);
+ int data_len = len;
+ u32 *mem = data;
+
+ if (!data)
+ return;
+
+ data_len = data_len / chunk_sz;
+
+ for (i = 0; i < data_len; i++) {
+ *mem = be32_to_cpu(*mem);
+ mem++;
+ }
+}
+
+/* *
+ * hinic3_set_sge - set dma area in scatter gather entry
+ * @sge: scatter gather entry
+ * @addr: dma address
+ * @len: length of relevant data in the dma address
+ */
+static inline void hinic3_set_sge(struct hinic3_sge *sge, dma_addr_t addr,
+ int len)
+{
+ sge->hi_addr = upper_32_bits(addr);
+ sge->lo_addr = lower_32_bits(addr);
+ sge->len = (u32)len;
+}
+
+#ifdef HW_CONVERT_ENDIAN
+#define hinic3_hw_be32(val) (val)
+#define hinic3_hw_cpu32(val) (val)
+#define hinic3_hw_cpu16(val) (val)
+#else
+#define hinic3_hw_be32(val) cpu_to_be32(val)
+#define hinic3_hw_cpu32(val) be32_to_cpu(val)
+#define hinic3_hw_cpu16(val) be16_to_cpu(val)
+#endif
+
+static inline void hinic3_hw_be32_len(void *data, int len)
+{
+#ifndef HW_CONVERT_ENDIAN
+ int i, chunk_sz = sizeof(u32);
+ int data_len = len;
+ u32 *mem = data;
+
+ if (!data)
+ return;
+
+ data_len = data_len / chunk_sz;
+
+ for (i = 0; i < data_len; i++) {
+ *mem = hinic3_hw_be32(*mem);
+ mem++;
+ }
+#endif
+}
+
+static inline void hinic3_hw_cpu32_len(void *data, int len)
+{
+#ifndef HW_CONVERT_ENDIAN
+ int i, chunk_sz = sizeof(u32);
+ int data_len = len;
+ u32 *mem = data;
+
+ if (!data)
+ return;
+
+ data_len = data_len / chunk_sz;
+
+ for (i = 0; i < data_len; i++) {
+ *mem = hinic3_hw_cpu32(*mem);
+ mem++;
+ }
+#endif
+}
+
+int hinic3_dma_zalloc_coherent_align(void *dev_hdl, u64 size, u64 align,
+ unsigned int flag,
+ struct hinic3_dma_addr_align *mem_align);
+
+void hinic3_dma_free_coherent_align(void *dev_hdl,
+ struct hinic3_dma_addr_align *mem_align);
+
+typedef enum hinic3_wait_return (*wait_cpl_handler)(void *priv_data);
+
+int hinic3_wait_for_timeout(void *priv_data, wait_cpl_handler handler,
+ u32 wait_total_ms, u32 wait_once_us);
+
+/* func_attr.glb_func_idx, global function index */
+u16 hinic3_global_func_id(void *hwdev);
+
+int hinic3_global_func_id_get(void *hwdev, u16 *func_id);
+
+/* func_attr.p2p_idx, belongs to which pf */
+u8 hinic3_pf_id_of_vf(void *hwdev);
+
+/* func_attr.itf_idx, pcie interface index */
+u8 hinic3_pcie_itf_id(void *hwdev);
+int hinic3_get_vfid_by_vfpci(void *hwdev, struct pci_dev *pdev, u16 *global_func_id);
+/* func_attr.vf_in_pf, the vf offset in pf */
+u8 hinic3_vf_in_pf(void *hwdev);
+
+/* func_attr.func_type, 0-PF 1-VF 2-PPF */
+enum func_type hinic3_func_type(void *hwdev);
+
+/* The PF func_attr.glb_pf_vf_offset,
+ * PF use only
+ */
+u16 hinic3_glb_pf_vf_offset(void *hwdev);
+
+/* func_attr.mpf_idx, mpf global function index,
+ * This value is valid only when it is PF
+ */
+u8 hinic3_mpf_idx(void *hwdev);
+
+u8 hinic3_ppf_idx(void *hwdev);
+
+/* func_attr.intr_num, MSI-X table entry in function */
+u16 hinic3_intr_num(void *hwdev);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/hinic3_cqm.h b/drivers/net/ethernet/huawei/hinic3/include/hinic3_cqm.h
new file mode 100644
index 0000000000000..6653460fc25bf
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/hinic3_cqm.h
@@ -0,0 +1,364 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef CQM_H
+#define CQM_H
+
+#include <linux/completion.h>
+
+#ifndef HIUDK_SDK
+
+#include "hinic3_cqm_define.h"
+#include "vram_common.h"
+
+#define CQM_SUCCESS 0
+#define CQM_FAIL (-1)
+#define CQM_CONTINUE 1
+
+#define CQM_WQE_WF_LINK 1
+#define CQM_WQE_WF_NORMAL 0
+
+#define CQM_QUEUE_LINK_MODE 0
+#define CQM_QUEUE_RING_MODE 1
+#define CQM_QUEUE_TOE_SRQ_LINK_MODE 2
+#define CQM_QUEUE_RDMA_QUEUE_MODE 3
+
+struct tag_cqm_linkwqe {
+ u32 rsv1 : 14;
+ u32 wf : 1;
+ u32 rsv2 : 14;
+ u32 ctrlsl : 2;
+ u32 o : 1;
+
+ u32 rsv3 : 31;
+ u32 lp : 1; /* lp define o-bit is flipping */
+
+ u32 next_page_gpa_h; /* Record the upper 32 bits of the PADDR of the next page */
+ u32 next_page_gpa_l; /* Record the lower 32 bits of the PADDR of the next page */
+
+ u32 next_buffer_addr_h; /* Record the upper 32 bits of the VADDR of the next page */
+ u32 next_buffer_addr_l; /* Record the lower 32 bits of the VADDR of the next page */
+};
+
+/* The WQE size cannot exceed the common RQE size. */
+struct tag_cqm_srq_linkwqe {
+ struct tag_cqm_linkwqe linkwqe;
+ u32 current_buffer_gpa_h;
+ u32 current_buffer_gpa_l;
+ u32 current_buffer_addr_h;
+ u32 current_buffer_addr_l;
+
+ u32 fast_link_page_addr_h;
+ u32 fast_link_page_addr_l;
+
+ u32 fixed_next_buffer_addr_h;
+ u32 fixed_next_buffer_addr_l;
+};
+
+/* First 64B of standard 128B WQE */
+union tag_cqm_linkwqe_first64B {
+ struct tag_cqm_linkwqe basic_linkwqe;
+ struct tag_cqm_srq_linkwqe toe_srq_linkwqe;
+ u32 value[16];
+};
+
+/* Last 64 bytes of the standard 128-byte WQE */
+struct tag_cqm_linkwqe_second64B {
+ u32 rsvd0[4];
+ u32 rsvd1[4];
+ union {
+ struct {
+ u32 rsvd0[3];
+ u32 rsvd1 : 29;
+ u32 toe_o : 1;
+ u32 resvd2 : 2;
+ } bs;
+ u32 value[4];
+ } third_16B;
+
+ union {
+ struct {
+ u32 rsvd0[2];
+ u32 rsvd1 : 31;
+ u32 ifoe_o : 1;
+ u32 rsvd2;
+ } bs;
+ u32 value[4];
+ } forth_16B;
+};
+
+/* Standard 128B WQE structure */
+struct tag_cqm_linkwqe_128B {
+ union tag_cqm_linkwqe_first64B first64B;
+ struct tag_cqm_linkwqe_second64B second64B;
+};
+
+enum cqm_aeq_event_type {
+ CQM_AEQ_BASE_T_NIC = 0,
+ CQM_AEQ_BASE_T_ROCE = 16,
+ CQM_AEQ_BASE_T_FC = 48,
+ CQM_AEQ_BASE_T_IOE = 56,
+ CQM_AEQ_BASE_T_TOE = 64,
+ CQM_AEQ_BASE_T_VBS = 96,
+ CQM_AEQ_BASE_T_IPSEC = 112,
+ CQM_AEQ_BASE_T_MAX = 128
+};
+
+struct tag_service_register_template {
+ u32 service_type;
+ u32 srq_ctx_size;
+ u32 scq_ctx_size;
+ void *service_handle; /* The ceq/aeq function is called back */
+ void (*shared_cq_ceq_callback)(void *service_handle, u32 cqn, void *cq_priv);
+ void (*embedded_cq_ceq_callback)(void *service_handle, u32 xid, void *qpc_priv);
+ void (*no_cq_ceq_callback)(void *service_handle, u32 xid, u32 qid, void *qpc_priv);
+ u8 (*aeq_level_callback)(void *service_handle, u8 event_type, u8 *val);
+ void (*aeq_callback)(void *service_handle, u8 event_type, u8 *val);
+};
+
+enum cqm_object_type {
+ CQM_OBJECT_ROOT_CTX = 0, ///<0:root context
+ CQM_OBJECT_SERVICE_CTX, ///<1:QPC
+ CQM_OBJECT_MPT, ///<2:RDMA
+
+ CQM_OBJECT_NONRDMA_EMBEDDED_RQ = 10,
+ CQM_OBJECT_NONRDMA_EMBEDDED_SQ,
+ CQM_OBJECT_NONRDMA_SRQ,
+ CQM_OBJECT_NONRDMA_EMBEDDED_CQ,
+ CQM_OBJECT_NONRDMA_SCQ,
+
+ CQM_OBJECT_RESV = 20,
+
+ CQM_OBJECT_RDMA_QP = 30,
+ CQM_OBJECT_RDMA_SRQ,
+ CQM_OBJECT_RDMA_SCQ,
+
+ CQM_OBJECT_MTT = 50,
+ CQM_OBJECT_RDMARC,
+};
+
+#define CQM_INDEX_INVALID ~(0U)
+#define CQM_INDEX_RESERVED (0xfffff)
+
+#define CQM_RDMA_Q_ROOM_1 (1)
+#define CQM_RDMA_Q_ROOM_2 (2)
+
+#define CQM_HARDWARE_DOORBELL (1)
+#define CQM_SOFTWARE_DOORBELL (2)
+
+struct tag_cqm_buf_list {
+ void *va;
+ dma_addr_t pa;
+ u32 refcount;
+};
+
+struct tag_cqm_buf {
+ struct tag_cqm_buf_list *buf_list;
+ struct tag_cqm_buf_list direct;
+ u32 page_number;
+ u32 buf_number;
+ u32 buf_size;
+ struct vram_buf_info buf_info;
+ u32 bat_entry_type;
+};
+
+struct completion;
+
+struct tag_cqm_object {
+ u32 service_type;
+ u32 object_type;
+ u32 object_size;
+ atomic_t refcount;
+ struct completion free;
+ void *cqm_handle;
+};
+
+struct tag_cqm_qpc_mpt {
+ struct tag_cqm_object object;
+ u32 xid;
+ dma_addr_t paddr;
+ void *priv;
+ u8 *vaddr;
+};
+
+struct tag_cqm_queue_header {
+ u64 doorbell_record;
+ u64 ci_record;
+ u64 rsv1;
+ u64 rsv2;
+};
+
+struct tag_cqm_queue {
+ struct tag_cqm_object object;
+ u32 index;
+ void *priv;
+ u32 current_q_doorbell;
+ u32 current_q_room;
+ struct tag_cqm_buf q_room_buf_1;
+ struct tag_cqm_buf q_room_buf_2;
+ struct tag_cqm_queue_header *q_header_vaddr;
+ dma_addr_t q_header_paddr;
+ u8 *q_ctx_vaddr;
+ dma_addr_t q_ctx_paddr;
+ u32 valid_wqe_num;
+ u8 *tail_container;
+ u8 *head_container;
+ u8 queue_link_mode;
+};
+
+struct tag_cqm_mtt_rdmarc {
+ struct tag_cqm_object object;
+ u32 index_base;
+ u32 index_number;
+ u8 *vaddr;
+};
+
+struct tag_cqm_cmd_buf {
+ void *buf;
+ dma_addr_t dma;
+ u16 size;
+};
+
+enum cqm_cmd_ack_type_e {
+ CQM_CMD_ACK_TYPE_CMDQ = 0,
+ CQM_CMD_ACK_TYPE_SHARE_CQN = 1,
+ CQM_CMD_ACK_TYPE_APP_CQN = 2
+};
+
+#define CQM_CMD_BUF_LEN 0x800
+
+#endif
+
+#define hiudk_cqm_object_delete(x, y) cqm_object_delete(y)
+#define hiudk_cqm_object_funcid(x, y) cqm_object_funcid(y)
+#define hiudk_cqm_object_offset_addr(x, y, z, m) cqm_object_offset_addr(y, z, m)
+#define hiudk_cqm_object_put(x, y) cqm_object_put(y)
+#define hiudk_cqm_object_resize_alloc_new(x, y, z) cqm_object_resize_alloc_new(y, z)
+#define hiudk_cqm_object_resize_free_new(x, y) cqm_object_resize_free_new(y)
+#define hiudk_cqm_object_resize_free_old(x, y) cqm_object_resize_free_old(y)
+#define hiudk_cqm_object_share_recv_queue_add_container(x, y) \
+ cqm_object_share_recv_queue_add_container(y)
+#define hiudk_cqm_object_srq_add_container_free(x, y, z) cqm_object_srq_add_container_free(y, z)
+#define hiudk_cqm_ring_software_db(x, y, z) cqm_ring_software_db(y, z)
+#define hiudk_cqm_srq_used_rq_container_delete(x, y, z) cqm_srq_used_rq_container_delete(y, z)
+
+s32 cqm3_init(void *ex_handle);
+void cqm3_uninit(void *ex_handle);
+
+s32 cqm3_service_register(void *ex_handle,
+ struct tag_service_register_template *service_template);
+void cqm3_service_unregister(void *ex_handle, u32 service_type);
+s32 cqm3_fake_vf_num_set(void *ex_handle, u16 fake_vf_num_cfg);
+bool cqm3_need_secure_mem(void *ex_handle);
+struct tag_cqm_queue *cqm3_object_fc_srq_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 wqe_number, u32 wqe_size,
+ void *object_priv);
+struct tag_cqm_queue *cqm3_object_recv_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 init_rq_num, u32 container_size,
+ u32 wqe_size, void *object_priv);
+struct tag_cqm_queue *cqm3_object_share_recv_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 container_number, u32 container_size,
+ u32 wqe_size);
+struct tag_cqm_qpc_mpt *cqm3_object_qpc_mpt_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 object_size, void *object_priv,
+ u32 index, bool low2bit_align_en);
+
+struct tag_cqm_queue *cqm3_object_nonrdma_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 wqe_number, u32 wqe_size,
+ void *object_priv);
+struct tag_cqm_queue *cqm3_object_rdma_queue_create(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 object_size, void *object_priv,
+ bool room_header_alloc, u32 xid);
+struct tag_cqm_mtt_rdmarc *cqm3_object_rdma_table_get(void *ex_handle, u32 service_type,
+ enum cqm_object_type object_type,
+ u32 index_base, u32 index_number);
+struct tag_cqm_object *cqm3_object_get(void *ex_handle, enum cqm_object_type object_type,
+ u32 index, bool bh);
+struct tag_cqm_cmd_buf *cqm3_cmd_alloc(void *ex_handle);
+void cqm3_cmd_free(void *ex_handle, struct tag_cqm_cmd_buf *cmd_buf);
+
+s32 cqm3_send_cmd_box(void *ex_handle, u8 mod, u8 cmd,
+ struct tag_cqm_cmd_buf *buf_in, struct tag_cqm_cmd_buf *buf_out,
+ u64 *out_param, u32 timeout, u16 channel);
+
+s32 cqm3_lb_send_cmd_box(void *ex_handle, u8 mod, u8 cmd, u8 cos_id,
+ struct tag_cqm_cmd_buf *buf_in, struct tag_cqm_cmd_buf *buf_out,
+ u64 *out_param, u32 timeout, u16 channel);
+s32 cqm3_lb_send_cmd_box_async(void *ex_handle, u8 mod, u8 cmd, u8 cos_id,
+ struct tag_cqm_cmd_buf *buf_in, u16 channel);
+
+s32 cqm3_send_cmd_imm(void *ex_handle, u8 mod, u8 cmd,
+ struct tag_cqm_cmd_buf *buf_in, u64 *out_param,
+ u32 timeout, u16 channel);
+
+s32 cqm3_db_addr_alloc(void *ex_handle, void __iomem **db_addr, void __iomem **dwqe_addr);
+void cqm3_db_addr_free(void *ex_handle, const void __iomem *db_addr,
+ void __iomem *dwqe_addr);
+
+void *cqm3_get_db_addr(void *ex_handle, u32 service_type);
+s32 cqm3_ring_hardware_db(void *ex_handle, u32 service_type, u8 db_count, u64 db);
+
+s32 cqm3_get_hardware_db_addr(void *ex_handle, u64 *addr, u32 service_type);
+
+s32 cqm_ring_hardware_db_fc(void *ex_handle, u32 service_type, u8 db_count, u8 pagenum, u64 db);
+s32 cqm3_ring_hardware_db_update_pri(void *ex_handle, u32 service_type, u8 db_count, u64 db);
+s32 cqm3_bloomfilter_inc(void *ex_handle, u16 func_id, u64 id);
+s32 cqm3_bloomfilter_dec(void *ex_handle, u16 func_id, u64 id);
+void *cqm3_gid_base(void *ex_handle);
+void *cqm3_timer_base(void *ex_handle);
+void cqm3_function_timer_clear(void *ex_handle, u32 function_id);
+void cqm3_function_hash_buf_clear(void *ex_handle, s32 global_funcid);
+s32 cqm3_ring_direct_wqe_db(void *ex_handle, u32 service_type, u8 db_count, void *direct_wqe);
+s32 cqm_ring_direct_wqe_db_fc(void *ex_handle, u32 service_type, void *direct_wqe);
+
+s32 cqm3_object_share_recv_queue_add_container(struct tag_cqm_queue *common);
+s32 cqm3_object_srq_add_container_free(struct tag_cqm_queue *common, u8 **container_addr);
+
+s32 cqm3_ring_software_db(struct tag_cqm_object *object, u64 db_record);
+void cqm3_object_put(struct tag_cqm_object *object);
+
+/**
+ * @brief Obtains the function ID of an object.
+ * @param Object Pointer
+ * @retval >=0 function's ID
+ * @retval -1 Fails
+ */
+s32 cqm3_object_funcid(struct tag_cqm_object *object);
+
+s32 cqm3_object_resize_alloc_new(struct tag_cqm_object *object, u32 object_size);
+void cqm3_object_resize_free_new(struct tag_cqm_object *object);
+void cqm3_object_resize_free_old(struct tag_cqm_object *object);
+
+/**
+ * @brief Releasing a container
+ * @param Object Pointer
+ * @param container Pointer to the container to be released
+ * @retval void
+ */
+void cqm3_srq_used_rq_container_delete(struct tag_cqm_object *object, u8 *container);
+
+void cqm3_object_delete(struct tag_cqm_object *object);
+
+/**
+ * @brief Obtains the PADDR and VADDR of the specified offset in the object buffer.
+ * @details Only rdma table lookup is supported
+ * @param Object Pointer
+ * @param offset For an RDMA table, the offset is the absolute index number.
+ * @param paddr The physical address is returned only for the RDMA table.
+ * @retval u8 *buffer Virtual address at specified offset
+ */
+u8 *cqm3_object_offset_addr(struct tag_cqm_object *object, u32 offset, dma_addr_t *paddr);
+
+s32 cqm3_dtoe_share_recv_queue_create(void *ex_handle, u32 contex_size,
+ u32 *index_count, u32 *index);
+
+void cqm3_dtoe_free_srq_bitmap_index(void *ex_handle, u32 index_count, u32 index);
+
+#endif /* CQM_H */
+
diff --git a/drivers/net/ethernet/huawei/hinic3/include/hinic3_cqm_define.h b/drivers/net/ethernet/huawei/hinic3/include/hinic3_cqm_define.h
new file mode 100644
index 0000000000000..608b1251001d8
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/hinic3_cqm_define.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC3_CQM_DEFINE_H
+#define HINIC3_CQM_DEFINE_H
+#if !defined(HIUDK_ULD) && !defined(HIUDK_SDK_ADPT)
+#define cqm_init cqm3_init
+#define cqm_uninit cqm3_uninit
+#define cqm_service_register cqm3_service_register
+#define cqm_service_unregister cqm3_service_unregister
+#define cqm_bloomfilter_dec cqm3_bloomfilter_dec
+#define cqm_bloomfilter_inc cqm3_bloomfilter_inc
+#define cqm_cmd_alloc cqm3_cmd_alloc
+#define cqm_get_hardware_db_addr cqm3_get_hardware_db_addr
+#define cqm_cmd_free cqm3_cmd_free
+#define cqm_send_cmd_box cqm3_send_cmd_box
+#define cqm_lb_send_cmd_box cqm3_lb_send_cmd_box
+#define cqm_lb_send_cmd_box_async cqm3_lb_send_cmd_box_async
+#define cqm_send_cmd_imm cqm3_send_cmd_imm
+#define cqm_db_addr_alloc cqm3_db_addr_alloc
+#define cqm_db_addr_free cqm3_db_addr_free
+#define cqm_ring_hardware_db cqm3_ring_hardware_db
+#define cqm_ring_software_db cqm3_ring_software_db
+#define cqm_object_fc_srq_create cqm3_object_fc_srq_create
+#define cqm_object_share_recv_queue_create cqm3_object_share_recv_queue_create
+#define cqm_object_share_recv_queue_add_container cqm3_object_share_recv_queue_add_container
+#define cqm_object_srq_add_container_free cqm3_object_srq_add_container_free
+#define cqm_object_recv_queue_create cqm3_object_recv_queue_create
+#define cqm_object_qpc_mpt_create cqm3_object_qpc_mpt_create
+#define cqm_object_nonrdma_queue_create cqm3_object_nonrdma_queue_create
+#define cqm_object_rdma_queue_create cqm3_object_rdma_queue_create
+#define cqm_object_rdma_table_get cqm3_object_rdma_table_get
+#define cqm_object_delete cqm3_object_delete
+#define cqm_object_offset_addr cqm3_object_offset_addr
+#define cqm_object_get cqm3_object_get
+#define cqm_object_put cqm3_object_put
+#define cqm_object_funcid cqm3_object_funcid
+#define cqm_object_resize_alloc_new cqm3_object_resize_alloc_new
+#define cqm_object_resize_free_new cqm3_object_resize_free_new
+#define cqm_object_resize_free_old cqm3_object_resize_free_old
+#define cqm_function_timer_clear cqm3_function_timer_clear
+#define cqm_function_hash_buf_clear cqm3_function_hash_buf_clear
+#define cqm_srq_used_rq_container_delete cqm3_srq_used_rq_container_delete
+#define cqm_timer_base cqm3_timer_base
+#define cqm_dtoe_free_srq_bitmap_index cqm3_dtoe_free_srq_bitmap_index
+#define cqm_dtoe_share_recv_queue_create cqm3_dtoe_share_recv_queue_create
+#define cqm_get_db_addr cqm3_get_db_addr
+#define cqm_ring_direct_wqe_db cqm3_ring_direct_wqe_db
+#define cqm_fake_vf_num_set cqm3_fake_vf_num_set
+#define cqm_need_secure_mem cqm3_need_secure_mem
+#endif
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/hinic3_lld.h b/drivers/net/ethernet/huawei/hinic3/include/hinic3_lld.h
new file mode 100644
index 0000000000000..9a9bfe280df81
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/hinic3_lld.h
@@ -0,0 +1,223 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC3_LLD_H
+#define HINIC3_LLD_H
+
+#include "hinic3_crm.h"
+
+#define WAIT_TIME 1
+
+#ifdef HIUDK_SDK
+
+int hwsdk_set_vf_load_state(struct hinic3_lld_dev *lld_dev, bool vf_load_state);
+
+int hwsdk_set_vf_service_load(struct hinic3_lld_dev *lld_dev, u16 service,
+ bool vf_srv_load);
+
+int hwsdk_set_vf_service_state(struct hinic3_lld_dev *lld_dev, u16 vf_func_id,
+ u16 service, bool en);
+#else
+struct hinic3_lld_dev {
+ struct pci_dev *pdev;
+ void *hwdev;
+};
+
+struct hinic3_uld_info {
+ /* When the function does not need to initialize the corresponding uld,
+ * @probe needs to return 0 and uld_dev is set to NULL;
+ * if uld_dev is NULL, @remove will not be called when uninstalling
+ */
+ int (*probe)(struct hinic3_lld_dev *lld_dev, void **uld_dev, char *uld_dev_name);
+ void (*remove)(struct hinic3_lld_dev *lld_dev, void *uld_dev);
+ int (*suspend)(struct hinic3_lld_dev *lld_dev, void *uld_dev, pm_message_t state);
+ int (*resume)(struct hinic3_lld_dev *lld_dev, void *uld_dev);
+ void (*event)(struct hinic3_lld_dev *lld_dev, void *uld_dev,
+ struct hinic3_event_info *event);
+ int (*ioctl)(void *uld_dev, u32 cmd, const void *buf_in, u32 in_size,
+ void *buf_out, u32 *out_size);
+};
+#endif
+
+#ifndef HIUDK_ULD
+/* hinic3_register_uld - register an upper-layer driver
+ * @type: uld service type
+ * @uld_info: uld callback
+ *
+ * Registers an upper-layer driver.
+ * Traverse existing devices and call @probe to initialize the uld device.
+ */
+int hinic3_register_uld(enum hinic3_service_type type, struct hinic3_uld_info *uld_info);
+
+/**
+ * hinic3_unregister_uld - unregister an upper-layer driver
+ * @type: uld service type
+ *
+ * Traverse existing devices and call @remove to uninstall the uld device.
+ * Unregisters an existing upper-layer driver.
+ */
+void hinic3_unregister_uld(enum hinic3_service_type type);
+
+void lld_hold(void);
+void lld_put(void);
+
+/**
+ * @brief hinic3_get_lld_dev_by_chip_name - get lld device by chip name
+ * @param chip_name: chip name
+ *
+ * The value of lld_dev reference increases when lld_dev is obtained. The caller needs
+ * to release the reference by calling lld_dev_put.
+ **/
+struct hinic3_lld_dev *hinic3_get_lld_dev_by_chip_name(const char *chip_name);
+
+/**
+ * @brief lld_dev_hold - get reference to lld_dev
+ * @param dev: lld device
+ *
+ * Hold reference to device to keep it from being freed
+ **/
+void lld_dev_hold(struct hinic3_lld_dev *dev);
+
+/**
+ * @brief lld_dev_put - release reference to lld_dev
+ * @param dev: lld device
+ *
+ * Release reference to device to allow it to be freed
+ **/
+void lld_dev_put(struct hinic3_lld_dev *dev);
+
+/**
+ * @brief hinic3_get_lld_dev_by_dev_name - get lld device by uld device name
+ * @param dev_name: uld device name
+ * @param type: uld service type, When the type is SERVICE_T_MAX, try to match
+ * all ULD names to get uld_dev
+ *
+ * The value of lld_dev reference increases when lld_dev is obtained. The caller needs
+ * to release the reference by calling lld_dev_put.
+ **/
+struct hinic3_lld_dev *hinic3_get_lld_dev_by_dev_name(const char *dev_name,
+ enum hinic3_service_type type);
+
+/**
+ * @brief hinic3_get_lld_dev_by_dev_name_unsafe - get lld device by uld device name
+ * @param dev_name: uld device name
+ * @param type: uld service type, When the type is SERVICE_T_MAX, try to match
+ * all ULD names to get uld_dev
+ *
+ * hinic3_get_lld_dev_by_dev_name_unsafe() is completely analogous to
+ * hinic3_get_lld_dev_by_dev_name(), The only difference is that the reference
+ * of lld_dev is not increased when lld_dev is obtained.
+ *
+ * The caller must ensure that lld_dev will not be freed during the remove process
+ * when using lld_dev.
+ **/
+struct hinic3_lld_dev *hinic3_get_lld_dev_by_dev_name_unsafe(const char *dev_name,
+ enum hinic3_service_type type);
+
+/**
+ * @brief hinic3_get_lld_dev_by_chip_and_port - get lld device by chip name and port id
+ * @param chip_name: chip name
+ * @param port_id: port id
+ **/
+struct hinic3_lld_dev *hinic3_get_lld_dev_by_chip_and_port(const char *chip_name, u8 port_id);
+
+/**
+ * @brief hinic3_get_ppf_dev - get ppf device without depend on input parameter
+ **/
+void *hinic3_get_ppf_dev(void);
+
+/**
+ * @brief hinic3_get_ppf_lld_dev - get ppf lld device by current function's lld device
+ * @param lld_dev: current function's lld device
+ *
+ * The value of lld_dev reference increases when lld_dev is obtained. The caller needs
+ * to release the reference by calling lld_dev_put.
+ **/
+struct hinic3_lld_dev *hinic3_get_ppf_lld_dev(struct hinic3_lld_dev *lld_dev);
+
+/**
+ * @brief hinic3_get_ppf_lld_dev_unsafe - get ppf lld device by current function's lld device
+ * @param lld_dev: current function's lld device
+ *
+ * hinic3_get_ppf_lld_dev_unsafe() is completely analogous to hinic3_get_ppf_lld_dev(),
+ * The only difference is that the reference of lld_dev is not increased when lld_dev is obtained.
+ *
+ * The caller must ensure that ppf's lld_dev will not be freed during the remove process
+ * when using ppf lld_dev.
+ **/
+struct hinic3_lld_dev *hinic3_get_ppf_lld_dev_unsafe(struct hinic3_lld_dev *lld_dev);
+
+/**
+ * @brief uld_dev_hold - get reference to uld_dev
+ * @param lld_dev: lld device
+ * @param type: uld service type
+ *
+ * Hold reference to uld device to keep it from being freed
+ **/
+void uld_dev_hold(struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type);
+
+/**
+ * @brief uld_dev_put - release reference to lld_dev
+ * @param dev: lld device
+ * @param type: uld service type
+ *
+ * Release reference to uld device to allow it to be freed
+ **/
+void uld_dev_put(struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type);
+
+/**
+ * @brief hinic3_get_uld_dev - get uld device by lld device
+ * @param lld_dev: lld device
+ * @param type: uld service type
+ *
+ * The value of uld_dev reference increases when uld_dev is obtained. The caller needs
+ * to release the reference by calling uld_dev_put.
+ **/
+void *hinic3_get_uld_dev(struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type);
+
+/**
+ * @brief hinic3_get_uld_dev_unsafe - get uld device by lld device
+ * @param lld_dev: lld device
+ * @param type: uld service type
+ *
+ * hinic3_get_uld_dev_unsafe() is completely analogous to hinic3_get_uld_dev(),
+ * The only difference is that the reference of uld_dev is not increased when uld_dev is obtained.
+ *
+ * The caller must ensure that uld_dev will not be freed during the remove process
+ * when using uld_dev.
+ **/
+void *hinic3_get_uld_dev_unsafe(struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type);
+
+/**
+ * @brief hinic3_get_chip_name - get chip name by lld device
+ * @param lld_dev: lld device
+ * @param chip_name: String for storing the chip name
+ * @param max_len: Maximum number of characters to be copied for chip_name
+ **/
+int hinic3_get_chip_name(struct hinic3_lld_dev *lld_dev, char *chip_name, u16 max_len);
+
+struct card_node *hinic3_get_chip_node_by_lld(struct hinic3_lld_dev *lld_dev);
+
+struct hinic3_hwdev *hinic3_get_sdk_hwdev_by_lld(struct hinic3_lld_dev *lld_dev);
+
+bool hinic3_get_vf_service_load(struct pci_dev *pdev, u16 service);
+
+int hinic3_set_vf_service_load(struct pci_dev *pdev, u16 service,
+ bool vf_srv_load);
+
+int hinic3_set_vf_service_state(struct pci_dev *pdev, u16 vf_func_id,
+ u16 service, bool en);
+
+bool hinic3_get_vf_load_state(struct pci_dev *pdev);
+
+int hinic3_set_vf_load_state(struct pci_dev *pdev, bool vf_load_state);
+
+int hinic3_attach_nic(struct hinic3_lld_dev *lld_dev);
+
+void hinic3_detach_nic(const struct hinic3_lld_dev *lld_dev);
+
+int hinic3_attach_service(const struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type);
+void hinic3_detach_service(const struct hinic3_lld_dev *lld_dev, enum hinic3_service_type type);
+const char **hinic3_get_uld_names(void);
+#endif
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/hinic3_profile.h b/drivers/net/ethernet/huawei/hinic3/include/hinic3_profile.h
new file mode 100644
index 0000000000000..e0bd2560b8502
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/hinic3_profile.h
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef HINIC3_PROFILE_H
+#define HINIC3_PROFILE_H
+
+typedef bool (*hinic3_is_match_prof)(void *device);
+typedef void *(*hinic3_init_prof_attr)(void *device);
+typedef void (*hinic3_deinit_prof_attr)(void *porf_attr);
+
+enum prof_adapter_type {
+ PROF_ADAP_TYPE_INVALID,
+ PROF_ADAP_TYPE_PANGEA = 1,
+
+ /* Add prof adapter type before default */
+ PROF_ADAP_TYPE_DEFAULT,
+};
+
+/**
+ * struct hinic3_prof_adapter - custom scene's profile adapter
+ * @type: adapter type
+ * @match: Check whether the current function is used in the custom scene.
+ * Implemented in the current source file
+ * @init: When @match return true, the initialization function called in probe.
+ * Implemented in the source file of the custom scene
+ * @deinit: When @match return true, the deinitialization function called when
+ * remove. Implemented in the source file of the custom scene
+ */
+struct hinic3_prof_adapter {
+ enum prof_adapter_type type;
+ hinic3_is_match_prof match;
+ hinic3_init_prof_attr init;
+ hinic3_deinit_prof_attr deinit;
+};
+
+#ifdef static
+#undef static
+#define LLT_STATIC_DEF_SAVED
+#endif
+
+static inline struct hinic3_prof_adapter *hinic3_prof_init(void *device,
+ struct hinic3_prof_adapter *adap_objs,
+ int num_adap, void **prof_attr)
+{
+ struct hinic3_prof_adapter *prof_obj = NULL;
+ int i;
+
+ for (i = 0; i < num_adap; i++) {
+ prof_obj = &adap_objs[i];
+ if (!(prof_obj->match && prof_obj->match(device)))
+ continue;
+
+ *prof_attr = prof_obj->init ? prof_obj->init(device) : NULL;
+
+ return prof_obj;
+ }
+
+ return NULL;
+}
+
+static inline void hinic3_prof_deinit(struct hinic3_prof_adapter *prof_obj, void *prof_attr)
+{
+ if (!prof_obj)
+ return;
+
+ if (prof_obj->deinit)
+ prof_obj->deinit(prof_attr);
+}
+
+/* module-level interface */
+#ifdef CONFIG_MODULE_PROF
+struct hinic3_module_ops {
+ int (*module_prof_init)(void);
+ void (*module_prof_exit)(void);
+ void (*probe_fault_process)(void *pdev, u16 level);
+ int (*probe_pre_process)(void *pdev);
+ void (*probe_pre_unprocess)(void *pdev);
+};
+
+struct hinic3_module_ops *hinic3_get_module_prof_ops(void);
+
+static inline void hinic3_probe_fault_process(void *pdev, u16 level)
+{
+ struct hinic3_module_ops *ops = hinic3_get_module_prof_ops();
+
+ if (ops && ops->probe_fault_process)
+ ops->probe_fault_process(pdev, level);
+}
+
+static inline int hinic3_module_pre_init(void)
+{
+ struct hinic3_module_ops *ops = hinic3_get_module_prof_ops();
+
+ if (!ops || !ops->module_prof_init)
+ return -EINVAL;
+
+ return ops->module_prof_init();
+}
+
+static inline void hinic3_module_post_exit(void)
+{
+ struct hinic3_module_ops *ops = hinic3_get_module_prof_ops();
+
+ if (ops && ops->module_prof_exit)
+ ops->module_prof_exit();
+}
+
+static inline int hinic3_probe_pre_process(void *pdev)
+{
+ struct hinic3_module_ops *ops = hinic3_get_module_prof_ops();
+
+ if (!ops || !ops->probe_pre_process)
+ return -EINVAL;
+
+ return ops->probe_pre_process(pdev);
+}
+
+static inline void hinic3_probe_pre_unprocess(void *pdev)
+{
+ struct hinic3_module_ops *ops = hinic3_get_module_prof_ops();
+
+ if (ops && ops->probe_pre_unprocess)
+ ops->probe_pre_unprocess(pdev);
+}
+#else
+static inline void hinic3_probe_fault_process(void *pdev, u16 level) { };
+
+static inline int hinic3_module_pre_init(void)
+{
+ return 0;
+}
+
+static inline void hinic3_module_post_exit(void) { };
+
+static inline int hinic3_probe_pre_process(void *pdev)
+{
+ return 0;
+}
+
+static inline void hinic3_probe_pre_unprocess(void *pdev) { };
+#endif
+
+#ifdef LLT_STATIC_DEF_SAVED
+#define static
+#undef LLT_STATIC_DEF_SAVED
+#endif
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/mpu/mag_mpu_cmd.h b/drivers/net/ethernet/huawei/hinic3/include/mpu/mag_mpu_cmd.h
new file mode 100644
index 0000000000000..97d34f0c21f4a
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/mpu/mag_mpu_cmd.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef MAG_MPU_CMD_H
+#define MAG_MPU_CMD_H
+
+/* Definition of the SerDes/MAG message command word */
+enum mag_cmd {
+ SERDES_CMD_PROCESS = 0, /* serdes cmd @see struct serdes_cmd_in */
+
+ MAG_CMD_SET_PORT_CFG = 1, /* set port cfg function @see struct mag_cmd_set_port_cfg */
+ MAG_CMD_SET_PORT_ADAPT = 2, /* set port adapt mode @see struct mag_cmd_set_port_adapt */
+ MAG_CMD_CFG_LOOPBACK_MODE = 3, /* set port loopback mode @see mag_cmd_cfg_loopback_mode */
+
+ MAG_CMD_GET_PORT_ENABLE = 5, /* get port enable status @see mag_cmd_get_port_enable */
+ MAG_CMD_SET_PORT_ENABLE = 6, /* set port enable mode @see mag_cmd_set_port_enable */
+ MAG_CMD_GET_LINK_STATUS = 7, /* get port link status @see mag_cmd_get_link_status */
+ MAG_CMD_SET_LINK_FOLLOW = 8, /* set port link_follow mode @see mag_cmd_set_link_follow */
+ MAG_CMD_SET_PMA_ENABLE = 9, /* set pma enable mode @see struct mag_cmd_set_pma_enable */
+ MAG_CMD_CFG_FEC_MODE = 10, /* set port fec mode @see struct mag_cmd_cfg_fec_mode */
+ MAG_CMD_GET_BOND_STATUS = 11, /* reserved for future use */
+
+ MAG_CMD_CFG_AN_TYPE = 12, /* reserved for future use */
+ MAG_CMD_CFG_LINK_TIME = 13, /* get link time @see struct mag_cmd_get_link_time */
+
+ MAG_CMD_SET_PANGEA_ADAPT = 15, /* set pangea adapt mode @see mag_cmd_set_pangea_adapt */
+
+ /* Bios link configuration dependency 30-49 */
+ MAG_CMD_CFG_BIOS_LINK_CFG = 31, /* reserved for future use */
+ MAG_CMD_RESTORE_LINK_CFG = 32, /* restore link cfg @see mag_cmd_restore_link_cfg */
+ MAG_CMD_ACTIVATE_BIOS_LINK_CFG = 33, /* active bios link cfg */
+
+ /* Optical module、LED, PHY and other peripheral configuration management 50 - 99 */
+ /* LED */
+ MAG_CMD_SET_LED_CFG = 50, /* set led cfg @see struct mag_cmd_set_led_cfg */
+
+ /* PHY */
+ MAG_CMD_GET_PHY_INIT_STATUS = 55, /* reserved for future use */
+
+ /* Optical module */
+ MAG_CMD_GET_XSFP_INFO = 60, /* get xsfp info @see struct mag_cmd_get_xsfp_info */
+ MAG_CMD_SET_XSFP_ENABLE = 61, /* set xsfp enable mode @see mag_cmd_set_xsfp_enable */
+ MAG_CMD_GET_XSFP_PRESENT = 62, /* get xsfp present status @see mag_cmd_get_xsfp_present */
+ MAG_CMD_SET_XSFP_RW = 63, /* sfp/qsfp single byte read/write, @see mag_cmd_set_xsfp_rw */
+ MAG_CMD_CFG_XSFP_TEMPERATURE = 64, /* get xsfp temp @see mag_cmd_sfp_temp_out_info */
+
+ /* Event reported 100-149 */
+ MAG_CMD_WIRE_EVENT = 100,
+ MAG_CMD_LINK_ERR_EVENT = 101,
+
+ /* DFX、Counter */
+ MAG_CMD_EVENT_PORT_INFO = 150, /* get port event info @see mag_cmd_event_port_info */
+ MAG_CMD_GET_PORT_STAT = 151, /* get port state @see struct mag_cmd_get_port_stat */
+ MAG_CMD_CLR_PORT_STAT = 152, /* clear port state @see struct mag_cmd_port_stats_info */
+ MAG_CMD_GET_PORT_INFO = 153, /* get port info @see struct mag_cmd_get_port_info */
+ MAG_CMD_GET_PCS_ERR_CNT = 154, /* pcs err count @see struct mag_cmd_event_port_info */
+ MAG_CMD_GET_MAG_CNT = 155, /* fec code count @see struct mag_cmd_get_mag_cnt */
+ MAG_CMD_DUMP_ANTRAIN_INFO = 156, /* dump anlt info @see mag_cmd_dump_antrain_info */
+
+ /* patch reserve cmd */
+ MAG_CMD_PATCH_RSVD_0 = 200,
+ MAG_CMD_PATCH_RSVD_1 = 201,
+ MAG_CMD_PATCH_RSVD_2 = 202,
+ MAG_CMD_PATCH_RSVD_3 = 203,
+ MAG_CMD_PATCH_RSVD_4 = 204,
+
+ MAG_CMD_MAX = 0xFF
+};
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_board_defs.h b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_board_defs.h
new file mode 100644
index 0000000000000..caaba5dfb652b
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_board_defs.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef MPU_BOARD_DEFS_H
+#define MPU_BOARD_DEFS_H
+
+#define BOARD_TYPE_TEST_RANGE_START 1
+#define BOARD_TYPE_TEST_RANGE_END 29
+#define BOARD_TYPE_STRG_RANGE_START 30
+#define BOARD_TYPE_STRG_RANGE_END 99
+#define BOARD_TYPE_CAL_RANGE_START 100
+#define BOARD_TYPE_CAL_RANGE_END 169
+#define BOARD_TYPE_CLD_RANGE_START 170
+#define BOARD_TYPE_CLD_RANGE_END 239
+#define BOARD_TYPE_RSVD_RANGE_START 240
+#define BOARD_TYPE_RSVD_RANGE_END 255
+
+enum board_type_define_e {
+ BOARD_TYPE_MPU_DEFAULT = 0, /* Default config */
+ BOARD_TYPE_TEST_EVB_4X25G = 1, /* EVB Board */
+ BOARD_TYPE_TEST_CEM_2X100G = 2, /* 2X100G CEM Card */
+ BOARD_TYPE_STRG_SMARTIO_4X32G_FC = 30, /* 4X32G SmartIO FC Card */
+ BOARD_TYPE_STRG_SMARTIO_4X25G_TIOE = 31, /* 4X25GE SmartIO TIOE Card */
+ BOARD_TYPE_STRG_SMARTIO_4X25G_ROCE = 32, /* 4X25GE SmartIO ROCE Card */
+ BOARD_TYPE_STRG_SMARTIO_4X25G_ROCE_AA = 33, /* 4X25GE SmartIO ROCE_AA Card */
+ BOARD_TYPE_STRG_SMARTIO_4X25G_SRIOV = 34, /* 4X25GE SmartIO container Card */
+ BOARD_TYPE_STRG_SMARTIO_4X25G_SRIOV_SW = 35, /* 4X25GE SmartIO container switch Card */
+ BOARD_TYPE_STRG_4X25G_COMSTORAGE = 36, /* 4X25GE compute storage Onboard Card */
+ BOARD_TYPE_STRG_2X100G_TIOE = 40, /* 2X100G SmartIO TIOE Card */
+ BOARD_TYPE_STRG_2X100G_ROCE = 41, /* 2X100G SmartIO ROCE Card */
+ BOARD_TYPE_STRG_2X100G_ROCE_AA = 42, /* 2X100G SmartIO ROCE_AA Card */
+ BOARD_TYPE_CAL_2X25G_NIC_75MPPS = 100, /* 2X25G ETH Standard card 75MPPS */
+ BOARD_TYPE_CAL_2X25G_NIC_40MPPS = 101, /* 2X25G ETH Standard card 40MPPS */
+ BOARD_TYPE_CAL_2X100G_DPU = 102, /* 2x100G DPU Card */
+ BOARD_TYPE_CAL_4X25G_NIC_120MPPS = 105, /* 4X25G ETH Standard card 120MPPS */
+ BOARD_TYPE_CAL_4X25G_COMSTORAGE = 106, /* 4X25GE compute storage Onboard Card */
+ BOARD_TYPE_CAL_2X32G_FC_HBA = 110, /* 2X32G FC HBA card */
+ BOARD_TYPE_CAL_2X16G_FC_HBA = 111, /* 2X16G FC HBA card */
+ BOARD_TYPE_CAL_2X100G_NIC_120MPPS = 115, /* 2X100G ETH Standard card 120MPPS */
+ BOARD_TYPE_CAL_2X25G_DPU = 116, /* 2x25G DPU Card */
+ BOARD_TYPE_CAL_4X25G_DPU = 118, /* 4x25G DPU Card */
+ BOARD_TYPE_CLD_2X100G_SDI5_1 = 170, /* 2X100G SDI 5.1 Card */
+ BOARD_TYPE_CLD_2X25G_SDI5_0_LITE = 171, /* 2x25G SDI5.0 Lite Card */
+ BOARD_TYPE_CLD_2X100G_SDI5_0 = 172, /* 2x100G SDI5.0 Card */
+ BOARD_TYPE_MAX_INDEX = 0xFF
+};
+
+static inline u32 spu_board_type_valid(u32 board_type)
+{
+ return ((board_type) == BOARD_TYPE_CLD_2X25G_SDI5_0_LITE) ||
+ ((board_type) == BOARD_TYPE_CLD_2X100G_SDI5_0) ||
+ ((board_type) == BOARD_TYPE_CAL_2X25G_DPU) ||
+ ((board_type) == BOARD_TYPE_CAL_2X100G_DPU) ||
+ ((board_type) == BOARD_TYPE_CAL_4X25G_DPU);
+}
+
+static inline int board_type_is_sdi(u32 board_type)
+{
+ return ((board_type) == BOARD_TYPE_CLD_2X100G_SDI5_1) ||
+ ((board_type) == BOARD_TYPE_CLD_2X25G_SDI5_0_LITE) ||
+ ((board_type) == BOARD_TYPE_CLD_2X100G_SDI5_0);
+}
+
+static inline int board_type_is_dpu(u32 board_type)
+{
+ return ((board_type) == BOARD_TYPE_CAL_2X25G_DPU) ||
+ ((board_type) == BOARD_TYPE_CAL_2X100G_DPU) ||
+ ((board_type) == BOARD_TYPE_CAL_4X25G_DPU);
+}
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_cmd_base_defs.h b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_cmd_base_defs.h
new file mode 100644
index 0000000000000..89d5cc42cfd67
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_cmd_base_defs.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef COMM_DEFS_H
+#define COMM_DEFS_H
+
+#include "mgmt_msg_base.h"
+
+/** MPU CMD MODULE TYPE */
+enum hinic3_mod_type {
+ HINIC3_MOD_COMM = 0, /* HW communication module */
+ HINIC3_MOD_L2NIC = 1, /* L2NIC module */
+ HINIC3_MOD_ROCE = 2,
+ HINIC3_MOD_PLOG = 3,
+ HINIC3_MOD_TOE = 4,
+ HINIC3_MOD_FLR = 5,
+ HINIC3_MOD_VROCE = 6,
+ HINIC3_MOD_CFGM = 7, /* Configuration management */
+ HINIC3_MOD_CQM = 8,
+ HINIC3_MOD_VMSEC = 9,
+ COMM_MOD_FC = 10,
+ HINIC3_MOD_OVS = 11,
+ HINIC3_MOD_DSW = 12,
+ HINIC3_MOD_MIGRATE = 13,
+ HINIC3_MOD_HILINK = 14,
+ HINIC3_MOD_CRYPT = 15, /* secure crypto module */
+ HINIC3_MOD_VIO = 16,
+ HINIC3_MOD_IMU = 17,
+ HINIC3_MOD_DFX = 18, /* DFX */
+ HINIC3_MOD_HW_MAX = 19, /* hardware max module id */
+ /* Software module id, for PF/VF and multi-host */
+ HINIC3_MOD_SW_FUNC = 20,
+ HINIC3_MOD_MAX,
+};
+
+/* Func reset flag, Specifies the resource to be cleaned.*/
+enum func_reset_flag_e {
+ RES_TYPE_FLUSH_BIT = 0,
+ RES_TYPE_MQM,
+ RES_TYPE_SMF,
+ RES_TYPE_PF_BW_CFG,
+
+ RES_TYPE_COMM = 10,
+ RES_TYPE_COMM_MGMT_CH, /* clear mbox and aeq, The RES_TYPE_COMM bit must be set */
+ RES_TYPE_COMM_CMD_CH, /* clear cmdq and ceq, The RES_TYPE_COMM bit must be set */
+ RES_TYPE_NIC,
+ RES_TYPE_OVS,
+ RES_TYPE_VBS,
+ RES_TYPE_ROCE,
+ RES_TYPE_FC,
+ RES_TYPE_TOE,
+ RES_TYPE_IPSEC,
+ RES_TYPE_MAX,
+};
+
+#define HINIC3_COMM_RES \
+ ((1 << RES_TYPE_COMM) | (1 << RES_TYPE_COMM_CMD_CH) | \
+ (1 << RES_TYPE_FLUSH_BIT) | (1 << RES_TYPE_MQM) | \
+ (1 << RES_TYPE_SMF) | (1 << RES_TYPE_PF_BW_CFG))
+
+#define HINIC3_NIC_RES BIT(RES_TYPE_NIC)
+#define HINIC3_OVS_RES BIT(RES_TYPE_OVS)
+#define HINIC3_VBS_RES BIT(RES_TYPE_VBS)
+#define HINIC3_ROCE_RES BIT(RES_TYPE_ROCE)
+#define HINIC3_FC_RES BIT(RES_TYPE_FC)
+#define HINIC3_TOE_RES BIT(RES_TYPE_TOE)
+#define HINIC3_IPSEC_RES BIT(RES_TYPE_IPSEC)
+
+/* MODE OVS、NIC、UNKNOWN */
+#define HINIC3_WORK_MODE_OVS 0
+#define HINIC3_WORK_MODE_UNKNOWN 1
+#define HINIC3_WORK_MODE_NIC 2
+
+#define DEVICE_TYPE_L2NIC 0
+#define DEVICE_TYPE_NVME 1
+#define DEVICE_TYPE_VIRTIO_NET 2
+#define DEVICE_TYPE_VIRTIO_BLK 3
+#define DEVICE_TYPE_VIRTIO_VSOCK 4
+#define DEVICE_TYPE_VIRTIO_NET_TRANSITION 5
+#define DEVICE_TYPE_VIRTIO_BLK_TRANSITION 6
+#define DEVICE_TYPE_VIRTIO_SCSI_TRANSITION 7
+#define DEVICE_TYPE_VIRTIO_HPC 8
+
+enum hinic3_svc_type {
+ SVC_T_COMM = 0,
+ SVC_T_NIC,
+ SVC_T_OVS,
+ SVC_T_ROCE,
+ SVC_T_TOE,
+ SVC_T_IOE,
+ SVC_T_FC,
+ SVC_T_VBS,
+ SVC_T_IPSEC,
+ SVC_T_VIRTIO,
+ SVC_T_MIGRATE,
+ SVC_T_PPA,
+ SVC_T_MAX,
+};
+
+/**
+ * Common header control information of the COMM message interaction command word
+ * between the driver and PF.
+ */
+struct comm_info_head {
+ /** response status code, 0: success, others: error code */
+ u8 status;
+
+ /** firmware version for command */
+ u8 version;
+
+ /** response aeq number, unused for now */
+ u8 rep_aeq_num;
+ u8 rsvd[5];
+};
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_inband_cmd.h b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_inband_cmd.h
new file mode 100644
index 0000000000000..b24e72942c679
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_inband_cmd.h
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef MPU_INBAND_CMD_H
+#define MPU_INBAND_CMD_H
+
+enum hinic3_mgmt_cmd {
+ COMM_MGMT_CMD_FUNC_RESET = 0, /* reset function @see comm_cmd_func_reset */
+ COMM_MGMT_CMD_FEATURE_NEGO, /* feature negotiation @see comm_cmd_feature_nego */
+ COMM_MGMT_CMD_FLUSH_DOORBELL, /* clear doorbell @see comm_cmd_clear_doorbell */
+ COMM_MGMT_CMD_START_FLUSH, /* clear statefull business txrx resource
+ * @see comm_cmd_clear_resource
+ */
+ COMM_MGMT_CMD_SET_FUNC_FLR, /* set function flr @see comm_cmd_func_flr_set */
+ COMM_MGMT_CMD_GET_GLOBAL_ATTR, /* get global attr @see comm_cmd_get_glb_attr */
+ COMM_MGMT_CMD_SET_PPF_FLR_TYPE, /* set ppf flr type @see comm_cmd_ppf_flr_type_set */
+ COMM_MGMT_CMD_SET_FUNC_SVC_USED_STATE, /* set function service used state
+ * @see comm_cmd_func_svc_used_state
+ */
+ COMM_MGMT_CMD_START_FLR, /* MPU not use */
+
+ COMM_MGMT_CMD_CFG_MSIX_NUM = 10, /**< set msix num @see comm_cmd_cfg_msix_num */
+
+ COMM_MGMT_CMD_SET_CMDQ_CTXT = 20, /* set commandq context @see comm_cmd_cmdq_ctxt */
+ COMM_MGMT_CMD_SET_VAT, /** set vat table info @see comm_cmd_root_ctxt */
+ COMM_MGMT_CMD_CFG_PAGESIZE, /**< set rootctx pagesize @see comm_cmd_wq_page_size */
+ COMM_MGMT_CMD_CFG_MSIX_CTRL_REG, /* config msix ctrl register @see comm_cmd_msix_config */
+ COMM_MGMT_CMD_SET_CEQ_CTRL_REG, /**< set ceq ctrl register @see comm_cmd_ceq_ctrl_reg */
+ COMM_MGMT_CMD_SET_DMA_ATTR, /**< set PF/VF DMA table attr @see comm_cmd_dma_attr_config */
+ COMM_MGMT_CMD_SET_PPF_TBL_HTR_FLG, /* set PPF func table os hotreplace flag
+ * @see comm_cmd_ppf_tbl_htrp_config
+ */
+
+ COMM_MGMT_CMD_GET_MQM_FIX_INFO = 40, /**< get mqm fix info @see comm_cmd_get_eqm_num */
+ COMM_MGMT_CMD_SET_MQM_CFG_INFO, /**< set mqm config info @see comm_cmd_eqm_cfg */
+ COMM_MGMT_CMD_SET_MQM_SRCH_GPA, /* set mqm search gpa info @see comm_cmd_eqm_search_gpa */
+ COMM_MGMT_CMD_SET_PPF_TMR, /**< set ppf tmr @see comm_cmd_ppf_tmr_op */
+ COMM_MGMT_CMD_SET_PPF_HT_GPA, /**< set ppf ht gpa @see comm_cmd_ht_gpa */
+ COMM_MGMT_CMD_SET_FUNC_TMR_BITMAT, /* @see comm_cmd_func_tmr_bitmap_op */
+ COMM_MGMT_CMD_SET_MBX_CRDT, /**< reserved */
+ COMM_MGMT_CMD_CFG_TEMPLATE, /**< config template @see comm_cmd_cfg_template */
+ COMM_MGMT_CMD_SET_MQM_LIMIT, /**< set mqm limit @see comm_cmd_set_mqm_limit */
+
+ COMM_MGMT_CMD_GET_FW_VERSION = 60, /**< get firmware version @see comm_cmd_get_fw_version */
+ COMM_MGMT_CMD_GET_BOARD_INFO, /**< get board info @see comm_cmd_board_info */
+ COMM_MGMT_CMD_SYNC_TIME, /**< synchronize host time to MPU @see comm_cmd_sync_time */
+ COMM_MGMT_CMD_GET_HW_PF_INFOS, /**< get pf info @see comm_cmd_hw_pf_infos */
+ COMM_MGMT_CMD_SEND_BDF_INFO, /**< send bdf info @see comm_cmd_bdf_info */
+ COMM_MGMT_CMD_GET_VIRTIO_BDF_INFO, /**< get virtio bdf info @see mpu_pcie_device_info_s */
+ COMM_MGMT_CMD_GET_SML_TABLE_INFO, /**< get sml table info @see comm_cmd_get_sml_tbl_data */
+ COMM_MGMT_CMD_GET_SDI_INFO, /**< get sdi info @see comm_cmd_sdi_info */
+ COMM_MGMT_CMD_ROOT_CTX_LOAD, /* get root context info @see comm_cmd_root_ctx_load_req_s */
+ COMM_MGMT_CMD_GET_HW_BOND, /**< get bond info @see comm_cmd_hw_bond_infos */
+
+ COMM_MGMT_CMD_UPDATE_FW = 80, /* update firmware @see cmd_update_fw @see comm_info_head */
+ COMM_MGMT_CMD_ACTIVE_FW, /**< cold active firmware @see cmd_active_firmware */
+ COMM_MGMT_CMD_HOT_ACTIVE_FW, /**< hot active firmware @see cmd_hot_active_fw */
+ COMM_MGMT_CMD_HOT_ACTIVE_DONE_NOTICE, /**< reserved */
+ COMM_MGMT_CMD_SWITCH_CFG, /**< switch config file @see cmd_switch_cfg */
+ COMM_MGMT_CMD_CHECK_FLASH, /**< check flash @see comm_info_check_flash */
+ COMM_MGMT_CMD_CHECK_FLASH_RW, /* check whether flash reads and writes normally
+ * @see comm_cmd_hw_bond_infos
+ */
+ COMM_MGMT_CMD_RESOURCE_CFG, /**< reserved */
+ COMM_MGMT_CMD_UPDATE_BIOS, /**< update bios firmware @see cmd_update_fw */
+ COMM_MGMT_CMD_MPU_GIT_CODE, /**< get mpu git tag @see cmd_get_mpu_git_code */
+
+ COMM_MGMT_CMD_FAULT_REPORT = 100, /**< report fault event to driver */
+ COMM_MGMT_CMD_WATCHDOG_INFO, /* report software watchdog timeout to driver
+ * @see comm_info_sw_watchdog
+ */
+ COMM_MGMT_CMD_MGMT_RESET, /**< report mpu chip reset to driver */
+ COMM_MGMT_CMD_FFM_SET, /* report except interrupt to driver */
+
+ COMM_MGMT_CMD_GET_LOG = 120, /* get the log of the dictionary @see nic_log_info_request */
+ COMM_MGMT_CMD_TEMP_OP, /* temperature operation @see comm_temp_in_info
+ * @see comm_temp_out_info
+ */
+ COMM_MGMT_CMD_EN_AUTO_RST_CHIP, /* @see comm_cmd_enable_auto_rst_chip */
+ COMM_MGMT_CMD_CFG_REG, /**< reserved */
+ COMM_MGMT_CMD_GET_CHIP_ID, /**< get chip id @see comm_chip_id_info */
+ COMM_MGMT_CMD_SYSINFO_DFX, /**< reserved */
+ COMM_MGMT_CMD_PCIE_DFX_NTC, /**< reserved */
+ COMM_MGMT_CMD_DICT_LOG_STATUS, /* @see mpu_log_status_info */
+ COMM_MGMT_CMD_MSIX_INFO, /**< read msix map table @see comm_cmd_msix_info */
+ COMM_MGMT_CMD_CHANNEL_DETECT, /**< auto channel detect @see comm_cmd_channel_detect */
+ COMM_MGMT_CMD_DICT_COUNTER_STATUS, /**< get flash counter status @see flash_counter_info */
+ COMM_MGMT_CMD_UCODE_SM_COUNTER, /* get ucode sm counter @see comm_read_ucode_sm_req
+ * @see comm_read_ucode_sm_resp
+ */
+ COMM_MGMT_CMD_CLEAR_LOG, /**< clear log @see comm_cmd_clear_log_s */
+
+ COMM_MGMT_CMD_CHECK_IF_SWITCH_WORKMODE = 140, /* check if switch workmode reserved
+ * @see comm_cmd_check_if_switch_workmode
+ */
+ COMM_MGMT_CMD_SWITCH_WORKMODE, /* switch workmode reserved @see comm_cmd_switch_workmode */
+
+ COMM_MGMT_CMD_MIGRATE_DFX_HPA = 150, /* query migrate varialbe @see comm_cmd_migrate_dfx */
+ COMM_MGMT_CMD_BDF_INFO, /**< get bdf info @see cmd_get_bdf_info_s */
+ COMM_MGMT_CMD_NCSI_CFG_INFO_GET_PROC, /**< get ncsi config info @see comm_cmd_ncsi_cfg_s */
+ COMM_MGMT_CMD_CPI_TCAM_DBG, /* enable or disable the scheduled cpi tcam task,
+ * set task interval time @see comm_cmd_cpi_tcam_dbg_s
+ */
+
+ COMM_MGMT_CMD_SECTION_RSVD_0 = 160, /**< rsvd0 section */
+ COMM_MGMT_CMD_SECTION_RSVD_1 = 170, /**< rsvd1 section */
+ COMM_MGMT_CMD_SECTION_RSVD_2 = 180, /**< rsvd2 section */
+ COMM_MGMT_CMD_SECTION_RSVD_3 = 190, /**< rsvd3 section */
+
+ COMM_MGMT_CMD_GET_TDIE_ID = 199, /**< get totem die id @see comm_cmd_get_totem_die_id */
+ COMM_MGMT_CMD_GET_UDIE_ID = 200, /**< get unicorn die id @see comm_cmd_get_die_id */
+ COMM_MGMT_CMD_GET_EFUSE_TEST, /**< reserved */
+ COMM_MGMT_CMD_EFUSE_INFO_CFG, /**< set efuse config @see comm_efuse_cfg_info */
+ COMM_MGMT_CMD_GPIO_CTL, /**< reserved */
+ COMM_MGMT_CMD_HI30_SERLOOP_START, /* set serloop start @see comm_cmd_hi30_serloop */
+ COMM_MGMT_CMD_HI30_SERLOOP_STOP, /* set serloop stop @see comm_cmd_hi30_serloop */
+ COMM_MGMT_CMD_HI30_MBIST_SET_FLAG, /**< reserved */
+ COMM_MGMT_CMD_HI30_MBIST_GET_RESULT, /**< reserved */
+ COMM_MGMT_CMD_ECC_TEST, /**< reserved */
+ COMM_MGMT_CMD_FUNC_BIST_TEST, /**< reserved */
+
+ COMM_MGMT_CMD_VPD_SET = 210, /**< reserved */
+ COMM_MGMT_CMD_VPD_GET, /**< reserved */
+
+ COMM_MGMT_CMD_ERASE_FLASH, /**< erase flash sector @see cmd_sector_info */
+ COMM_MGMT_CMD_QUERY_FW_INFO, /**< get firmware info @see cmd_query_fw */
+ COMM_MGMT_CMD_GET_CFG_INFO, /* get cfg in flash reserved @see comm_cmd_get_cfg_info_t */
+ COMM_MGMT_CMD_GET_UART_LOG, /* collect hinicshell log @see nic_cmd_get_uart_log_info */
+ COMM_MGMT_CMD_SET_UART_CMD, /* hinicshell command to mpu @see nic_cmd_set_uart_log_cmd */
+ COMM_MGMT_CMD_SPI_TEST, /**< reserved */
+
+ /* TODO: ALL reg read/write merge to COMM_MGMT_CMD_CFG_REG */
+ COMM_MGMT_CMD_MPU_REG_GET, /**< get mpu register value @see dbgtool_up_reg_opt_info */
+ COMM_MGMT_CMD_MPU_REG_SET, /**< set mpu register value @see dbgtool_up_reg_opt_info */
+
+ COMM_MGMT_CMD_REG_READ = 220, /**< read register value @see comm_info_reg_read_write */
+ COMM_MGMT_CMD_REG_WRITE, /**< write register value @see comm_info_reg_read_write */
+ COMM_MGMT_CMD_MAG_REG_WRITE, /**< write mag register value @see comm_info_dfx_mag_reg */
+ COMM_MGMT_CMD_ANLT_REG_WRITE, /**< read register value @see comm_info_dfx_anlt_reg */
+
+ COMM_MGMT_CMD_HEART_EVENT, /**< ncsi heart event @see comm_cmd_heart_event */
+ COMM_MGMT_CMD_NCSI_OEM_GET_DRV_INFO, /**< nsci oem get driver info */
+ COMM_MGMT_CMD_LASTWORD_GET, /**< report lastword to driver @see comm_info_up_lastword_s */
+ COMM_MGMT_CMD_READ_BIN_DATA, /**< reserved */
+ COMM_MGMT_CMD_GET_REG_VAL, /**< read register value @see comm_cmd_mbox_csr_rd_req */
+ COMM_MGMT_CMD_SET_REG_VAL, /**< write register value @see comm_cmd_mbox_csr_wt_req */
+
+ /* TODO: check if needed */
+ COMM_MGMT_CMD_SET_VIRTIO_DEV = 230, /* set the virtio device
+ * @see comm_cmd_set_virtio_dev
+ */
+ COMM_MGMT_CMD_SET_MAC, /**< set mac address @see comm_info_mac */
+ /* MPU patch cmd */
+ COMM_MGMT_CMD_LOAD_PATCH, /**< load hot patch @see cmd_update_fw */
+ COMM_MGMT_CMD_REMOVE_PATCH, /**< remove hot patch @see cmd_patch_remove */
+ COMM_MGMT_CMD_PATCH_ACTIVE, /**< actice hot patch @see cmd_patch_active */
+ COMM_MGMT_CMD_PATCH_DEACTIVE, /**< deactice hot patch @see cmd_patch_deactive */
+ COMM_MGMT_CMD_PATCH_SRAM_OPTIMIZE, /**< set hot patch sram optimize */
+ /* container host process */
+ COMM_MGMT_CMD_CONTAINER_HOST_PROC, /* container host process reserved
+ * @see comm_cmd_con_sel_sta
+ */
+ /* nsci counter */
+ COMM_MGMT_CMD_NCSI_COUNTER_PROC, /* get ncsi counter @see nsci_counter_in_info_s */
+ COMM_MGMT_CMD_CHANNEL_STATUS_CHECK, /* check channel status reserved
+ * @see channel_status_check_info_s
+ */
+
+ COMM_MGMT_CMD_RSVD_0 = 240, /**< hot patch reserved cmd */
+ COMM_MGMT_CMD_RSVD_1, /**< hot patch reserved cmd */
+ COMM_MGMT_CMD_RSVD_2, /**< hot patch reserved cmd */
+ COMM_MGMT_CMD_RSVD_3, /**< hot patch reserved cmd */
+ COMM_MGMT_CMD_RSVD_4, /**< hot patch reserved cmd */
+ COMM_MGMT_CMD_SEND_API_ACK_BY_UP, /**< reserved */
+
+ /* for tool ver compatible info */
+ COMM_MGMT_CMD_GET_VER_COMPATIBLE_INFO = 254, /* get compatible info
+ * @see comm_cmd_compatible_info
+ */
+ /* When adding a command word, you cannot change the value of an existing command word.
+ * Add the command word in the rsvd section. In principle,
+ * the cmd tables of all branches are the same.
+ */
+ COMM_MGMT_CMD_MAX = 255,
+};
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_inband_cmd_defs.h b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_inband_cmd_defs.h
new file mode 100644
index 0000000000000..f535777123454
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_inband_cmd_defs.h
@@ -0,0 +1,1078 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef MPU_INBAND_CMD_DEFS_H
+#define MPU_INBAND_CMD_DEFS_H
+
+#include "mpu_cmd_base_defs.h"
+#include "mpu_outband_ncsi_cmd_defs.h"
+
+#define HARDWARE_ID_1XX3V100_TAG 31 /* 1xx3v100 tag */
+#define DUMP_16B_PER_LINE 16
+#define DUMP_8_VAR_PER_LINE 8
+#define DUMP_4_VAR_PER_LINE 4
+#define FW_UPDATE_MGMT_TIMEOUT 3000000U
+
+#define FUNC_RESET_FLAG_MAX_VALUE ((1U << (RES_TYPE_MAX + 1)) - 1)
+struct comm_cmd_func_reset {
+ struct mgmt_msg_head head;
+ u16 func_id; /**< function id */
+ u16 rsvd1[3];
+ u64 reset_flag; /**< reset function type flag @see enum func_reset_flag_e */
+};
+
+enum {
+ COMM_F_API_CHAIN = 1U << 0,
+ COMM_F_CLP = 1U << 1,
+ COMM_F_CHANNEL_DETECT = 1U << 2,
+ COMM_F_MBOX_SEGMENT = 1U << 3,
+ COMM_F_CMDQ_NUM = 1U << 4,
+ COMM_F_VIRTIO_VQ_SIZE = 1U << 5,
+};
+
+#define COMM_MAX_FEATURE_QWORD 4
+enum COMM_FEATURE_NEGO_OPCODE {
+ COMM_FEATURE_NEGO_OPCODE_GET = 0,
+ COMM_FEATURE_NEGO_OPCODE_SET = 1
+};
+
+struct comm_cmd_feature_nego {
+ struct mgmt_msg_head head;
+ u16 func_id; /**< function id */
+ u8 opcode; /**< operate type 0: get, 1: set */
+ u8 rsvd;
+ u64 s_feature[COMM_MAX_FEATURE_QWORD]; /**< feature info */
+};
+
+struct comm_cmd_func_flr_set {
+ struct mgmt_msg_head head;
+
+ u16 func_id; /**< function id */
+ u8 type; /**< 1: flr enable */
+ u8 isall; /**< flr type 0: specify PF and associated VF flr, 1: all functions flr */
+ u32 rsvd;
+};
+
+struct comm_cmd_clear_doorbell {
+ struct mgmt_msg_head head;
+
+ u16 func_id; /**< function id */
+ u16 rsvd1[3];
+};
+
+struct comm_cmd_clear_resource {
+ struct mgmt_msg_head head;
+
+ u16 func_id; /**< function id */
+ u16 rsvd1[3];
+};
+
+struct comm_global_attr {
+ u8 max_host_num; /**< maximum number of host */
+ u8 max_pf_num; /**< maximum number of pf */
+ u16 vf_id_start; /**< VF function id start */
+
+ u8 mgmt_host_node_id; /**< node id */
+ u8 cmdq_num; /**< cmdq num */
+ u8 rsvd1[2];
+ u32 rsvd2[8];
+};
+
+struct comm_cmd_get_glb_attr {
+ struct mgmt_msg_head head;
+ struct comm_global_attr attr; /**< global attr @see struct comm_global_attr */
+};
+
+struct comm_cmd_ppf_flr_type_set {
+ struct mgmt_msg_head head;
+
+ u16 func_id;
+ u8 func_service_type;
+ u8 rsvd1;
+ u32 ppf_flr_type; /**< function flr type 1:statefull 0:stateless */
+};
+
+struct comm_cmd_func_svc_used_state {
+ struct mgmt_msg_head head;
+ u16 func_id;
+ u16 svc_type;
+ u8 used_state;
+ u8 rsvd[35];
+};
+
+struct comm_cmd_cfg_msix_num {
+ struct comm_info_head head;
+
+ u16 func_id;
+ u8 op_code; /**< operate type 1: alloc 0: free */
+ u8 rsvd0;
+
+ u16 msix_num;
+ u16 rsvd1;
+};
+
+struct cmdq_ctxt_info {
+ u64 curr_wqe_page_pfn;
+ u64 wq_block_pfn;
+};
+
+struct comm_cmd_cmdq_ctxt {
+ struct mgmt_msg_head head;
+
+ u16 func_id;
+ u8 cmdq_id;
+ u8 rsvd1[5];
+
+ struct cmdq_ctxt_info ctxt;
+};
+
+struct comm_cmd_root_ctxt {
+ struct mgmt_msg_head head;
+
+ u16 func_id;
+ u8 set_cmdq_depth;
+ u8 cmdq_depth;
+ u16 rx_buf_sz;
+ u8 lro_en;
+ u8 rsvd1;
+ u16 sq_depth;
+ u16 rq_depth;
+ u64 rsvd2;
+};
+
+struct comm_cmd_wq_page_size {
+ struct mgmt_msg_head head;
+
+ u16 func_id; /**< function id */
+ u8 opcode; /**< operate type 0:get , 1:set */
+ /* real_size=4KB*2^page_size, range(0~20) must be checked by driver */
+ u8 page_size;
+
+ u32 rsvd1;
+};
+
+struct comm_cmd_msix_config {
+ struct mgmt_msg_head head;
+
+ u16 func_id; /**< function id */
+ u8 opcode; /**< operate type 0:get , 1:set */
+ u8 rsvd1;
+ u16 msix_index;
+ u8 pending_cnt;
+ u8 coalesce_timer_cnt;
+ u8 resend_timer_cnt;
+ u8 lli_timer_cnt;
+ u8 lli_credit_cnt;
+ u8 rsvd2[5];
+};
+
+struct comm_cmd_ceq_ctrl_reg {
+ struct mgmt_msg_head head;
+
+ u16 func_id; /**< function id */
+ u16 q_id;
+ u32 ctrl0;
+ u32 ctrl1;
+ u32 rsvd1;
+};
+
+struct comm_cmd_dma_attr_config {
+ struct mgmt_msg_head head;
+
+ u16 func_id; /**< function id */
+ u8 entry_idx;
+ u8 st;
+ u8 at;
+ u8 ph;
+ u8 no_snooping;
+ u8 tph_en;
+ u32 resv1;
+};
+
+struct comm_cmd_ppf_tbl_htrp_config {
+ struct mgmt_msg_head head;
+
+ u32 hotreplace_flag;
+};
+
+struct comm_cmd_get_eqm_num {
+ struct mgmt_msg_head head;
+
+ u8 host_id; /**< host id */
+ u8 rsvd1[3];
+ u32 chunk_num;
+ u32 search_gpa_num;
+};
+
+struct comm_cmd_eqm_cfg {
+ struct mgmt_msg_head head;
+
+ u8 host_id; /**< host id */
+ u8 valid; /**< 0:clear config , 1:set config */
+ u16 rsvd1;
+ u32 page_size; /**< page size */
+ u32 rsvd2;
+};
+
+struct comm_cmd_eqm_search_gpa {
+ struct mgmt_msg_head head;
+
+ u8 host_id; /**< host id Deprecated field, not used */
+ u8 rsvd1[3];
+ u32 start_idx; /**< start index */
+ u32 num;
+ u32 rsvd2;
+ u64 gpa_hi52[0]; /**< [gpa data */
+};
+
+struct comm_cmd_ppf_tmr_op {
+ struct mgmt_msg_head head;
+
+ u8 ppf_id; /**< ppf function id */
+ u8 opcode; /**< operation type 1: start timer, 0: stop timer */
+ u8 rsvd1[6];
+};
+
+struct comm_cmd_ht_gpa {
+ struct mgmt_msg_head head;
+
+ u8 host_id; /**< host id */
+ u8 rsvd0[3];
+ u32 rsvd1[7];
+ u64 page_pa0;
+ u64 page_pa1;
+};
+
+struct comm_cmd_func_tmr_bitmap_op {
+ struct mgmt_msg_head head;
+
+ u16 func_id; /**< function id */
+ u8 opcode; /**< operation type 1: start timer, 0: stop timer */
+ u8 rsvd1[5];
+};
+
+#define DD_CFG_TEMPLATE_MAX_IDX 12
+#define DD_CFG_TEMPLATE_MAX_TXT_LEN 64
+#define CFG_TEMPLATE_OP_QUERY 0
+#define CFG_TEMPLATE_OP_SET 1
+#define CFG_TEMPLATE_SET_MODE_BY_IDX 0
+#define CFG_TEMPLATE_SET_MODE_BY_NAME 1
+
+struct comm_cmd_cfg_template {
+ struct mgmt_msg_head head;
+ u8 opt_type; /**< operation type 0: query 1: set */
+ u8 set_mode; /**< set mode 0:index mode 1:name mode. */
+ u8 tp_err;
+ u8 rsvd0;
+
+ u8 cur_index; /**< current cfg tempalte index. */
+ u8 cur_max_index; /** max support cfg tempalte index. */
+ u8 rsvd1[2];
+ u8 cur_name[DD_CFG_TEMPLATE_MAX_TXT_LEN]; /**< current cfg tempalte name. */
+ u8 cur_cfg_temp_info[DD_CFG_TEMPLATE_MAX_IDX][DD_CFG_TEMPLATE_MAX_TXT_LEN];
+
+ u8 next_index; /**< next reset cfg tempalte index. */
+ u8 next_max_index; /**< max support cfg tempalte index. */
+ u8 rsvd2[2];
+ u8 next_name[DD_CFG_TEMPLATE_MAX_TXT_LEN]; /**< next reset cfg tempalte name. */
+ u8 next_cfg_temp_info[DD_CFG_TEMPLATE_MAX_IDX][DD_CFG_TEMPLATE_MAX_TXT_LEN];
+};
+
+#define MQM_SUPPORT_COS_NUM 8
+#define MQM_INVALID_WEIGHT 256
+#define MQM_LIMIT_SET_FLAG_READ 0
+#define MQM_LIMIT_SET_FLAG_WRITE 1
+struct comm_cmd_set_mqm_limit {
+ struct mgmt_msg_head head;
+
+ u16 set_flag; /**< operation type 0: read 1: write */
+ u16 func_id; /**< function id */
+ /* Indicates the weight of cos_id. The value ranges from 0 to 255.
+ * The value 0 indicates SP scheduling.
+ */
+ u16 cos_weight[MQM_SUPPORT_COS_NUM]; /**< cos weight range[0,255] */
+ u32 host_min_rate; /**< current host minimum rate */
+ u32 func_min_rate; /**< current function minimum rate,unit:Mbps */
+ u32 func_max_rate; /**< current function maximum rate,unit:Mbps */
+ u8 rsvd[64]; /* Reserved */
+};
+
+#define HINIC3_FW_VERSION_LEN 16
+#define HINIC3_FW_COMPILE_TIME_LEN 20
+
+enum hinic3_fw_ver_type {
+ HINIC3_FW_VER_TYPE_BOOT,
+ HINIC3_FW_VER_TYPE_MPU,
+ HINIC3_FW_VER_TYPE_NPU,
+ HINIC3_FW_VER_TYPE_SMU_L0,
+ HINIC3_FW_VER_TYPE_SMU_L1,
+ HINIC3_FW_VER_TYPE_CFG,
+};
+
+struct comm_cmd_get_fw_version {
+ struct mgmt_msg_head head;
+
+ u16 fw_type; /**< firmware type @see enum hinic3_fw_ver_type */
+ u16 rsvd1;
+ u8 ver[HINIC3_FW_VERSION_LEN]; /**< firmware version */
+ u8 time[HINIC3_FW_COMPILE_TIME_LEN]; /**< firmware compile time */
+};
+
+struct hinic3_board_info {
+ u8 board_type; /**< board type */
+ u8 port_num; /**< current port number */
+ u8 port_speed; /**< port speed */
+ u8 pcie_width; /**< pcie width */
+ u8 host_num; /**< host number */
+ u8 pf_num; /**< pf number */
+ u16 vf_total_num; /**< vf total number */
+ u8 tile_num; /**< tile number */
+ u8 qcm_num; /**< qcm number */
+ u8 core_num; /**< core number */
+ u8 work_mode; /**< work mode */
+ u8 service_mode; /**< service mode */
+ u8 pcie_mode; /**< pcie mode */
+ u8 boot_sel; /**< boot sel */
+ u8 board_id; /**< board id */
+ u32 rsvd;
+ u32 service_en_bitmap; /**< service en bitmap */
+ u8 scenes_id; /**< scenes id */
+ u8 cfg_template_id; /**< cfg template index */
+ u8 hardware_id; /**< hardware id */
+ u8 spu_en; /**< spu enable flag */
+ u16 pf_vendor_id; /**< pf vendor id */
+ u8 tile_bitmap; /**< used tile bitmap */
+ u8 sm_bitmap; /**< used sm bitmap */
+};
+
+struct comm_cmd_board_info {
+ struct mgmt_msg_head head;
+
+ struct hinic3_board_info info; /**< board info @see struct hinic3_board_info */
+ u32 rsvd[22];
+};
+
+struct comm_cmd_sync_time {
+ struct mgmt_msg_head head;
+
+ u64 mstime; /**< time,unit:ms */
+ u64 rsvd1;
+};
+
+struct hw_pf_info {
+ u16 glb_func_idx; /**< function id */
+ u16 glb_pf_vf_offset;
+ u8 p2p_idx;
+ u8 itf_idx; /**< host id */
+ u16 max_vfs; /**< max vf number */
+ u16 max_queue_num; /**< max queue number */
+ u16 vf_max_queue_num;
+ u16 port_id;
+ u16 rsvd0;
+ u32 pf_service_en_bitmap;
+ u32 vf_service_en_bitmap;
+ u16 rsvd1[2];
+
+ u8 device_type;
+ u8 bus_num; /**< bdf info */
+ u16 vf_stride; /**< vf stride */
+ u16 vf_offset; /**< vf offset */
+ u8 rsvd[2];
+};
+
+#define CMD_MAX_MAX_PF_NUM 32
+struct hinic3_hw_pf_infos {
+ u8 num_pfs; /**< pf number */
+ u8 rsvd1[3];
+
+ struct hw_pf_info infos[CMD_MAX_MAX_PF_NUM]; /**< pf info @see struct hw_pf_info */
+};
+
+struct comm_cmd_hw_pf_infos {
+ struct mgmt_msg_head head;
+
+ struct hinic3_hw_pf_infos infos; /**< all pf info @see struct hinic3_hw_pf_infos */
+};
+
+struct comm_cmd_bdf_info {
+ struct mgmt_msg_head head;
+
+ u16 function_idx; /**< function id */
+ u8 rsvd1[2];
+ u8 bus; /**< bus info */
+ u8 device; /**< device info */
+ u8 function; /**< function info */
+ u8 rsvd2[5];
+};
+
+#define TABLE_INDEX_MAX 129
+struct sml_table_id_info {
+ u8 node_id;
+ u8 instance_id;
+};
+
+struct comm_cmd_get_sml_tbl_data {
+ struct comm_info_head head; /* 8B */
+ u8 tbl_data[512]; /**< sml table data */
+};
+
+struct comm_cmd_sdi_info {
+ struct mgmt_msg_head head;
+ u32 cfg_sdi_mode; /**< host mode, 0:normal 1:virtual machine 2:bare metal */
+};
+
+#define HINIC_OVS_BOND_DEFAULT_ID 1
+struct hinic3_hw_bond_infos {
+ u8 bond_id;
+ u8 valid;
+ u8 rsvd1[2];
+};
+
+struct comm_cmd_hw_bond_infos {
+ struct mgmt_msg_head head;
+ struct hinic3_hw_bond_infos infos; /**< bond info @see struct hinic3_hw_bond_infos */
+};
+
+/* 工具数据长度为1536(1.5K),工具最大发2k,包含头部 */
+struct cmd_update_fw {
+ struct comm_info_head head; // 8B
+ u16 fw_flag; /**< subfirmware flag, bit 0: last slice flag, bit 1 first slice flag */
+ u16 slice_len; /**< current slice length */
+ u32 fw_crc; /**< subfirmware crc */
+ u32 fw_type; /**< subfirmware type */
+ u32 bin_total_len; /**< total firmware length, only fisrt slice is effective */
+ u32 bin_section_len; /**< subfirmware length */
+ u32 fw_verion; /**< subfirmware version */
+ u32 fw_offset; /**< current slice offset of current subfirmware */
+ u32 data[0]; /**< data */
+};
+
+struct cmd_switch_cfg {
+ struct comm_info_head msg_head;
+ u8 index; /**< index, range[0,7] */
+ u8 data[7];
+};
+
+struct cmd_active_firmware {
+ struct comm_info_head msg_head;
+ u8 index; /* 0 ~ 7 */
+ u8 data[7];
+};
+
+#define HOT_ACTIVE_MPU 1
+#define HOT_ACTIVE_NPU 2
+#define HOT_ACTIVE_MNPU 3
+struct cmd_hot_active_fw {
+ struct comm_info_head head;
+ u32 type; /**< hot actice firmware type 1: mpu; 2: ucode; 3: mpu & npu */
+ u32 data[3];
+};
+
+#define FLASH_CHECK_OK 1
+#define FLASH_CHECK_ERR 2
+#define FLASH_CHECK_DISMATCH 3
+
+struct comm_info_check_flash {
+ struct comm_info_head head;
+
+ u8 status; /**< flash check status */
+ u8 rsv[3];
+};
+
+struct cmd_get_mpu_git_code {
+ struct comm_info_head head; /* 8B */
+ u32 rsvd; /* reserve */
+ char mpu_git_code[64]; /**< mpu git tag and compile time */
+};
+
+#define DATA_LEN_1K 1024
+struct comm_info_sw_watchdog {
+ struct comm_info_head head;
+
+ u32 curr_time_h; /**< infinite loop occurrence time,cycle */
+ u32 curr_time_l; /**< infinite loop occurrence time,cycle */
+ u32 task_id; /**< task id .task that occur in an infinite loop */
+ u32 rsv;
+
+ u64 pc;
+
+ u64 elr;
+ u64 spsr;
+ u64 far;
+ u64 esr;
+ u64 xzr;
+ u64 x30;
+ u64 x29;
+ u64 x28;
+ u64 x27;
+ u64 x26;
+ u64 x25;
+ u64 x24;
+ u64 x23;
+ u64 x22;
+ u64 x21;
+ u64 x20;
+ u64 x19;
+ u64 x18;
+ u64 x17;
+ u64 x16;
+ u64 x15;
+ u64 x14;
+ u64 x13;
+ u64 x12;
+ u64 x11;
+ u64 x10;
+ u64 x09;
+ u64 x08;
+ u64 x07;
+ u64 x06;
+ u64 x05;
+ u64 x04;
+ u64 x03;
+ u64 x02;
+ u64 x01;
+ u64 x00;
+
+ u64 stack_top; /**< stack top */
+ u64 stack_bottom; /**< stack bottom */
+ u64 sp; /**< sp pointer */
+ u32 curr_used; /**< the size currently used by the stack */
+ u32 peak_used; /**< historical peak of stack usage */
+ u32 is_overflow; /**< stack overflow flag */
+
+ u32 stack_actlen; /**< actual stack length(<=1024) */
+ u8 stack_data[DATA_LEN_1K]; /* If the value exceeds 1024, it will be truncated. */
+};
+
+struct nic_log_info_request {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u32 offset;
+ u8 log_or_index; /* 0:log 1:index */
+ u8 type; /* log type 0:up 1:ucode 2:smu 3:mpu lastword 4.npu lastword */
+ u8 area; /* area 0:ram 1:flash (this bit is valid only when log_or_index is 0) */
+ u8 rsvd1; /* reserved */
+};
+
+#define MPU_TEMP_OP_GET 0
+#define MPU_TEMP_THRESHOLD_OP_CFG 1
+struct comm_temp_in_info {
+ struct comm_info_head head;
+ u8 opt_type; /**< operation type 0:read operation 1:cfg operation */
+ u8 rsv[3];
+ s32 max_temp; /**< maximum threshold of temperature */
+ s32 min_temp; /**< minimum threshold of temperature */
+};
+
+struct comm_temp_out_info {
+ struct comm_info_head head;
+ s32 temp_data; /**< current temperature */
+ s32 max_temp_threshold; /**< maximum threshold of temperature */
+ s32 min_temp_threshold; /**< minimum threshold of temperature */
+ s32 max_temp; /**< maximum temperature */
+ s32 min_temp; /**< minimum temperature */
+};
+
+/* 关闭芯片自复位 */
+struct comm_cmd_enable_auto_rst_chip {
+ struct comm_info_head head;
+ u8 op_code; /**< operation type 0:get operation 1:set operation */
+ u8 enable; /* auto reset status 0: disable auto reset chip 1: enable */
+ u8 rsvd[2];
+};
+
+struct comm_chip_id_info {
+ struct comm_info_head head;
+ u8 chip_id; /**< chip id */
+ u8 rsvd[3];
+};
+
+struct mpu_log_status_info {
+ struct comm_info_head head;
+ u8 type; /**< operation type 0:read operation 1:write operation */
+ u8 log_status; /**< log status 0:idle 1:busy */
+ u8 rsvd[2];
+};
+
+struct comm_cmd_msix_info {
+ struct comm_info_head head;
+ u8 rsvd1;
+ u8 flag; /**< table flag 0:second table, 1:actual table */
+ u8 rsvd[2];
+};
+
+struct comm_cmd_channel_detect {
+ struct mgmt_msg_head head;
+
+ u16 func_id; /**< function id */
+ u16 rsvd1[3];
+ u32 rsvd2[2];
+};
+
+#define MAX_LOG_BUF_SIZE 1024
+#define FLASH_NPU_COUNTER_HEAD_MAGIC (0x5a)
+#define FLASH_NPU_COUNTER_NIC_TYPE 0
+#define FLASH_NPU_COUNTER_FC_TYPE 1
+
+struct flash_npu_counter_head_s {
+ u8 magic;
+ u8 tbl_type;
+ u8 count_type; /**< 0:nic;1:fc */
+ u8 count_num; /**< current count number */
+ u16 base_offset; /**< address offset */
+ u16 base_count;
+};
+
+struct flash_counter_info {
+ struct comm_info_head head;
+
+ u32 length; /**< flash counter buff len */
+ u32 offset; /**< flash counter buff offset */
+ u8 data[MAX_LOG_BUF_SIZE]; /**< flash counter data */
+};
+
+enum mpu_sm_cmd_type {
+ COMM_SM_CTR_RD16 = 1,
+ COMM_SM_CTR_RD32,
+ COMM_SM_CTR_RD64_PAIR,
+ COMM_SM_CTR_RD64,
+ COMM_SM_CTR_RD32_CLEAR,
+ COMM_SM_CTR_RD64_PAIR_CLEAR,
+ COMM_SM_CTR_RD64_CLEAR,
+ COMM_SM_CTR_RD16_CLEAR,
+};
+
+struct comm_read_ucode_sm_req {
+ struct mgmt_msg_head msg_head;
+
+ u32 node; /**< node id @see enum INTERNAL_RING_NODE_ID_E */
+ u32 count_id; /**< count id */
+ u32 instanse; /**< instance id */
+ u32 type; /**< read type @see enum mpu_sm_cmd_type */
+};
+
+struct comm_read_ucode_sm_resp {
+ struct mgmt_msg_head msg_head;
+
+ u64 val1;
+ u64 val2;
+};
+
+enum log_type {
+ MPU_LOG_CLEAR = 0,
+ SMU_LOG_CLEAR = 1,
+ NPU_LOG_CLEAR = 2,
+ SPU_LOG_CLEAR = 3,
+ ALL_LOG_CLEAR = 4,
+};
+
+#define ABLESWITCH 1
+#define IMABLESWITCH 2
+enum switch_workmode_op {
+ SWITCH_WORKMODE_SWITCH = 0,
+ SWITCH_WORKMODE_OTHER = 1
+};
+
+enum switch_workmode_obj {
+ SWITCH_WORKMODE_FC = 0,
+ SWITCH_WORKMODE_TOE = 1,
+ SWITCH_WORKMODE_ROCE_AND_NOF = 2,
+ SWITCH_WORKMODE_NOF_AA = 3,
+ SWITCH_WORKMODE_ETH_CNTR = 4,
+ SWITCH_WORKMODE_NOF_CNTR = 5,
+};
+
+struct comm_cmd_check_if_switch_workmode {
+ struct mgmt_msg_head head;
+ u8 switch_able;
+ u8 rsvd1;
+ u16 rsvd2[3];
+ u32 rsvd3[3];
+};
+
+#define MIG_NOR_VM_ONE_MAX_SGE_MEM (64 * 8)
+#define MIG_NOR_VM_ONE_MAX_MEM (MIG_NOR_VM_ONE_MAX_SGE_MEM + 16)
+#define MIG_VM_MAX_SML_ENTRY_NUM 24
+
+struct comm_cmd_migrate_dfx_s {
+ struct mgmt_msg_head head;
+ u32 hpa_entry_id; /**< hpa entry id */
+ u8 vm_hpa[MIG_NOR_VM_ONE_MAX_MEM]; /**< vm hpa info */
+};
+
+#define BDF_BUS_BIT 8
+struct pf_bdf_info {
+ u8 itf_idx; /**< host id */
+ u16 bdf; /**< bdf info */
+ u8 pf_bdf_info_vld; /**< pf bdf info valid */
+};
+
+struct vf_bdf_info {
+ u16 glb_pf_vf_offset; /**< global_func_id offset of 1st vf in pf */
+ u16 max_vfs; /**< vf number */
+ u16 vf_stride; /**< VF_RID_SETTING.vf_stride */
+ u16 vf_offset; /**< VF_RID_SETTING.vf_offset */
+ u8 bus_num; /**< tl_cfg_bus_num */
+ u8 rsv[3];
+};
+
+struct cmd_get_bdf_info_s {
+ struct mgmt_msg_head head;
+ struct pf_bdf_info pf_bdf_info[CMD_MAX_MAX_PF_NUM];
+ struct vf_bdf_info vf_bdf_info[CMD_MAX_MAX_PF_NUM];
+ u32 vf_num; /**< vf num */
+};
+
+#define CPI_TCAM_DBG_CMD_SET_TASK_ENABLE_VALID 0x1
+#define CPI_TCAM_DBG_CMD_SET_TIME_INTERVAL_VALID 0x2
+#define CPI_TCAM_DBG_CMD_TYPE_SET 0
+#define CPI_TCAM_DBG_CMD_TYPE_GET 1
+
+#define UDIE_ID_DATA_LEN 8
+#define TDIE_ID_DATA_LEN 18
+struct comm_cmd_get_die_id {
+ struct comm_info_head head;
+
+ u32 die_id_data[UDIE_ID_DATA_LEN]; /**< die id data */
+};
+
+struct comm_cmd_get_totem_die_id {
+ struct comm_info_head head;
+
+ u32 die_id_data[TDIE_ID_DATA_LEN]; /**< die id data */
+};
+
+#define MAX_EFUSE_INFO_BUF_SIZE 1024
+
+enum comm_efuse_opt_type {
+ EFUSE_OPT_UNICORN_EFUSE_BURN = 1, /**< burn unicorn efuse bin */
+ EFUSE_OPT_UPDATE_SWSB = 2, /**< hw rotpk switch to guest rotpk */
+ EFUSE_OPT_TOTEM_EFUSE_BURN = 3 /**< burn totem efuse bin */
+};
+
+struct comm_efuse_cfg_info {
+ struct comm_info_head head;
+ u8 opt_type; /**< operation type @see enum comm_efuse_opt_type */
+ u8 rsvd[3];
+ u32 total_len; /**< entire package leng value */
+ u32 data_csum; /**< data csum */
+ u8 data[MAX_EFUSE_INFO_BUF_SIZE]; /**< efuse cfg data, size 768byte */
+};
+
+/* serloop模块接口 */
+struct comm_cmd_hi30_serloop {
+ struct comm_info_head head;
+
+ u32 macro;
+ u32 lane;
+ u32 prbs_pattern;
+ u32 result;
+};
+
+struct cmd_sector_info {
+ struct comm_info_head head;
+ u32 offset; /**< flash addr */
+ u32 len; /**< flash length */
+};
+
+struct cmd_query_fw {
+ struct comm_info_head head;
+ u32 offset; /**< offset addr */
+ u32 len; /**< length */
+};
+
+struct nic_cmd_get_uart_log_info {
+ struct comm_info_head head;
+ struct {
+ u32 ret : 8;
+ u32 version : 8;
+ u32 log_elem_real_num : 16;
+ } log_head;
+ char uart_log[MAX_LOG_BUF_SIZE];
+};
+
+#define MAX_LOG_CMD_BUF_SIZE 128
+
+struct nic_cmd_set_uart_log_cmd {
+ struct comm_info_head head;
+ struct {
+ u32 ret : 8;
+ u32 version : 8;
+ u32 cmd_elem_real_num : 16;
+ } log_head;
+ char uart_cmd[MAX_LOG_CMD_BUF_SIZE];
+};
+
+struct dbgtool_up_reg_opt_info {
+ struct comm_info_head head;
+
+ u8 len;
+ u8 is_car;
+ u8 car_clear_flag;
+ u32 csr_addr; /**< register addr */
+ u32 csr_value; /**< register value */
+};
+
+struct comm_info_reg_read_write {
+ struct comm_info_head head;
+
+ u32 reg_addr; /**< register address */
+ u32 val_length; /**< register value length */
+
+ u32 data[2]; /**< register value */
+};
+
+#ifndef DFX_MAG_MAX_REG_NUM
+#define DFX_MAG_MAX_REG_NUM (32)
+#endif
+struct comm_info_dfx_mag_reg {
+ struct comm_info_head head;
+ u32 write; /**< read or write flag: 0:read; 1:write */
+ u32 reg_addr; /**< register address */
+ u32 reg_cnt; /**< register num , up to 32 */
+ u32 clear; /**< clear flag: 0:do not clear after read 1:clear after read */
+ u32 data[DFX_MAG_MAX_REG_NUM]; /**< register data */
+};
+
+struct comm_info_dfx_anlt_reg {
+ struct comm_info_head head;
+ u32 write; /**< read or write flag: 0:read; 1:write */
+ u32 reg_addr; /**< register address */
+ u32 reg_cnt; /**< register num , up to 32 */
+ u32 clear; /**< clear flag: 0:do not clear after read 1:clear after read */
+ u32 data[DFX_MAG_MAX_REG_NUM]; /**< register data */
+};
+
+#define MAX_DATA_NUM (240)
+struct csr_msg {
+ struct {
+ u32 node_id : 5; // [4:0]
+ u32 data_width : 10; // [14:5]
+ u32 rsvd : 17; // [31:15]
+ } bits;
+ u32 addr;
+};
+
+struct comm_cmd_heart_event {
+ struct mgmt_msg_head head;
+
+ u8 init_sta; /* 0: mpu init ok, 1: mpu init error. */
+ u8 rsvd1[3];
+ u32 heart; /* add one by one */
+ u32 heart_handshake; /* should be alwasys: 0x5A5A5A5A */
+};
+
+#define XREGS_NUM 31
+struct tag_cpu_tick {
+ u32 cnt_hi;
+ u32 cnt_lo;
+};
+
+struct tag_ax_exc_reg_info {
+ u64 ttbr0;
+ u64 ttbr1;
+ u64 tcr;
+ u64 mair;
+ u64 sctlr;
+ u64 vbar;
+ u64 current_el;
+ u64 sp;
+ /* The memory layout of the following fields is the same as that of TskContext. */
+ u64 elr; /* 返回地址 */
+ u64 spsr;
+ u64 far_r;
+ u64 esr;
+ u64 xzr;
+ u64 xregs[XREGS_NUM]; /* 0~30: x30~x0 */
+};
+
+struct tag_exc_info {
+ char os_ver[48]; /**< os version */
+ char app_ver[64]; /**< application version*/
+ u32 exc_cause; /**< exception reason */
+ u32 thread_type; /**< Thread type before exception */
+ u32 thread_id; /**< Thread PID before exception */
+ u16 byte_order; /**< byte order */
+ u16 cpu_type; /**< CPU type */
+ u32 cpu_id; /**< CPU ID */
+ struct tag_cpu_tick cpu_tick; /**< CPU Tick */
+ u32 nest_cnt; /**< exception nesting count */
+ u32 fatal_errno; /**< fatal error code, valid when a fatal error occurs */
+ u64 uw_sp; /**< exception front stack pointer */
+ u64 stack_bottom; /**< bottom of stack before exception */
+ /* Context information of the core register when an exception occurs.
+ * 82\57 must be located in byte 152, If any change is made,
+ * the OS_EXC_REGINFO_OFFSET macro in sre_platform.eh needs to be updated.
+ */
+ struct tag_ax_exc_reg_info reg_info; /**< register info @see EXC_REGS_S */
+};
+
+/* 上报给驱动的up lastword模块接口 */
+#define MPU_LASTWORD_SIZE 1024
+struct tag_comm_info_up_lastword {
+ struct comm_info_head head;
+
+ struct tag_exc_info stack_info;
+ u32 stack_actlen; /**< actual stack length (<=1024) */
+ u8 stack_data[MPU_LASTWORD_SIZE];
+};
+
+struct comm_cmd_mbox_csr_rd_req {
+ struct mgmt_msg_head head;
+ struct csr_msg csr_info[MAX_DATA_NUM];
+ u32 data_num;
+};
+
+struct comm_cmd_mbox_csr_wt_req {
+ struct mgmt_msg_head head;
+ struct csr_msg csr_info;
+ u64 value;
+};
+
+struct comm_cmd_mbox_csr_rd_ret {
+ struct mgmt_msg_head head;
+ u64 value[MAX_DATA_NUM];
+};
+
+struct comm_cmd_mbox_csr_wt_ret {
+ struct mgmt_msg_head head;
+};
+
+enum comm_virtio_dev_type {
+ COMM_VIRTIO_NET_TYPE = 0,
+ COMM_VIRTIO_BLK_TYPE = 1,
+ COMM_VIRTIO_SCSI_TYPE = 4,
+};
+
+struct comm_virtio_dev_cmd {
+ u16 device_type; /**< device type @see enum comm_virtio_dev_type */
+ u16 device_id;
+ u32 devid_switch;
+ u32 sub_vendor_id;
+ u32 sub_class_code;
+ u32 flash_en;
+};
+
+struct comm_virtio_dev_ctl {
+ u32 device_type_mark;
+ u32 devid_switch_mark;
+ u32 sub_vendor_id_mark;
+ u32 sub_class_code_mark;
+ u32 flash_en_mark;
+};
+
+struct comm_cmd_set_virtio_dev {
+ struct comm_info_head head;
+ struct comm_virtio_dev_cmd virtio_dev_cmd; /**< @see struct comm_virtio_dev_cmd_s */
+ struct comm_virtio_dev_ctl virtio_dev_ctl; /**< @see struct comm_virtio_dev_ctl_s */
+};
+
+/* Interfaces of the MAC Module */
+#ifndef MAC_ADDRESS_BYTE_NUM
+#define MAC_ADDRESS_BYTE_NUM (6)
+#endif
+struct comm_info_mac {
+ struct comm_info_head head;
+
+ u16 is_valid;
+ u16 rsvd0;
+ u8 data[MAC_ADDRESS_BYTE_NUM];
+ u16 rsvd1;
+};
+
+struct cmd_patch_active {
+ struct comm_info_head head;
+ u32 fw_type; /**< firmware type */
+ u32 data[3]; /**< reserved */
+};
+
+struct cmd_patch_deactive {
+ struct comm_info_head head;
+ u32 fw_type; /**< firmware type */
+ u32 data[3]; /**< reserved */
+};
+
+struct cmd_patch_remove {
+ struct comm_info_head head;
+ u32 fw_type; /**< firmware type */
+ u32 data[3]; /**< reserved */
+};
+
+struct cmd_patch_sram_optimize {
+ struct comm_info_head head;
+ u32 data[4]; /**< reserved */
+};
+
+/* ncsi counter */
+struct nsci_counter_in_info_s {
+ struct comm_info_head head;
+ u8 opt_type; /**< operate type 0:read counter 1:counter clear */
+ u8 rsvd[3];
+};
+
+struct channel_status_check_info_s {
+ struct comm_info_head head;
+ u32 rsvd1;
+ u32 rsvd2;
+};
+
+struct comm_cmd_compatible_info {
+ struct mgmt_msg_head head;
+ u8 chip_ver;
+ u8 host_env;
+ u8 rsv[13];
+
+ u8 cmd_count;
+ union {
+ struct {
+ u8 module;
+ u8 mod_type;
+ u16 cmd;
+ } cmd_desc;
+ u32 cmd_desc_val;
+ } cmds_desc[24];
+ u8 cmd_ver[24];
+};
+
+struct tag_ncsi_chan_info {
+ u8 aen_en; /**< aen enable */
+ u8 index; /**< index of channel */
+ u8 port; /**< net port number */
+ u8 state; /**< ncsi state */
+ u8 ncsi_port_en; /**< ncsi port enable flag (1:enable 0:disable) */
+ u8 rsv[3];
+ struct tag_ncsi_chan_capa capabilities; /**< ncsi channel capabilities*/
+ struct tg_g_ncsi_parameters parameters; /**< ncsi state */
+};
+
+struct comm_cmd_ncsi_settings {
+ u8 ncsi_ver; /**< ncsi version */
+ u8 ncsi_pkg_id;
+ u8 arb_en; /**< arbitration en */
+ u8 duplex_set; /**< duplex mode */
+ u8 chan_num; /**< Number of virtual channels */
+ u8 iid; /**< identify new instances of a command */
+ u8 lldp_over_ncsi_enable;
+ u8 lldp_over_mctp_enable;
+ u32 magicwd;
+ u8 rsvd[8];
+ struct tag_ncsi_chan_info ncsi_chan_info;
+};
+
+struct comm_cmd_ncsi_cfg {
+ struct comm_info_head head;
+ u8 ncsi_cable_state; /**< ncsi cable status 0:cable out of place,1:cable in place */
+ u8 setting_type; /**< nsci info type:0:ram cofig, 1: flash config */
+ u8 port; /**< net port number */
+ u8 erase_flag; /**< flash erase flag, 1: erase flash info */
+ struct comm_cmd_ncsi_settings setting_info;
+};
+
+#define MQM_ATT_PAGE_NUM 128
+
+/* Maximum segment data length of the upgrade command */
+#define MAX_FW_FRAGMENT_LEN (1536)
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_outband_ncsi_cmd_defs.h b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_outband_ncsi_cmd_defs.h
new file mode 100644
index 0000000000000..4e2e1eb91cad0
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/mpu/mpu_outband_ncsi_cmd_defs.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef MPU_OUTBAND_NCSI_CMD_DEFS_H
+#define MPU_OUTBAND_NCSI_CMD_DEFS_H
+
+#pragma pack(1)
+
+enum NCSI_RESPONSE_CODE_E {
+ COMMAND_COMPLETED = 0x00, /**< command completed */
+ COMMAND_FAILED = 0x01, /**< command failed */
+ COMMAND_UNAVAILABLE = 0x02, /**< command unavailable */
+ COMMAND_UNSPORRTED = 0x03 /**< command unsporrted */
+};
+
+enum NCSI_REASON_CODE_E {
+ NO_ERROR = 0x00, /**< no error */
+ INTERFACE_INIT_REQUIRED = 0x01, /**< interface init required */
+ INVALID_PARA = 0x02, /**< invalid parameter */
+ CHAN_NOT_READY = 0x03, /**< channel not ready */
+ PKG_NOT_READY = 0x04, /**< package not ready */
+ INVALID_PAYLOAD_LEN = 0x05, /**< invalid payload len */
+ LINK_STATUS_ERROR = 0xA06, /**< get link status fail */
+ VLAN_TAG_INVALID = 0xB07, /**< vlan tag invalid */
+ MAC_ADD_IS_ZERO = 0xE08, /**< mac add is zero */
+ FLOW_CONTROL_UNSUPPORTED = 0x09, /**< flow control unsupported */
+ CHECKSUM_ERR = 0xA, /**< check sum error */
+ /**< the command type is unsupported only when the response code is 0x03 */
+ UNSUPPORTED_COMMAND_TYPE = 0x7FFF
+};
+
+enum NCSI_CLIENT_TYPE_E {
+ NCSI_RMII_TYPE = 1, /**< rmii client */
+ NCSI_MCTP_TYPE = 2, /**< MCTP client */
+ NCSI_AEN_TYPE = 3 /**< AEN client */
+};
+
+/**
+ * @brief ncsi ctrl packet header
+ */
+struct tag_ncsi_ctrl_packet_header {
+ u8 mc_id; /**< management control ID */
+ u8 head_revision; /**< head revision */
+ u8 reserved0; /**< reserved */
+ u8 iid; /**< instance ID */
+ u8 pkt_type; /**< packet type */
+#ifdef NCSI_BIG_ENDIAN
+ u8 pkg_id : 3; /**< packet ID */
+ u8 inter_chan_id : 5; /**< channel ID */
+#else
+ u8 inter_chan_id : 5; /**< channel ID */
+ u8 pkg_id : 3; /**< packet ID */
+#endif
+#ifdef BD_BIG_ENDIAN
+ u8 reserved1 : 4; /**< reserved1 */
+ u8 payload_len_hi : 4; /**< payload len have 12bits */
+#else
+ u8 payload_len_hi : 4; /**< payload len have 12bits */
+ u8 reserved1 : 4; /**< reserved1 */
+#endif
+ u8 payload_len_lo; /**< payload len lo */
+ u32 reserved2; /**< reserved2 */
+ u32 reserved3; /**< reserved3 */
+};
+
+#define NCSI_MAX_PAYLOAD_LEN 1500
+#define NCSI_MAC_LEN 6
+
+/**
+ * @brief ncsi clear initial state command struct defination
+ *
+ */
+struct tag_ncsi_ctrl_packet {
+ struct tag_ncsi_ctrl_packet_header packet_head; /**< ncsi ctrl packet header */
+ u8 payload[NCSI_MAX_PAYLOAD_LEN]; /**< ncsi ctrl packet payload */
+};
+
+/**
+ * @brief ethernet header description
+ *
+ */
+struct tag_ethernet_header {
+ u8 dst_addr[NCSI_MAC_LEN]; /**< ethernet destination address */
+ u8 src_addr[NCSI_MAC_LEN]; /**< ethernet source address */
+ u16 ether_type; /**< ethernet type */
+};
+
+/**
+ * @brief ncsi common packet description
+ *
+ */
+struct tg_ncsi_common_packet {
+ struct tag_ethernet_header frame_head; /**< common packet ethernet frame header */
+ struct tag_ncsi_ctrl_packet ctrl_packet; /**< common packet ncsi ctrl packet */
+};
+
+/**
+ * @brief ncsi clear initial state command struct defination
+ */
+struct tag_ncsi_client_info {
+ u8 *name; /**< client info client name */
+ u32 type; /**< client info type of ncsi media @see enum NCSI_CLIENT_TYPE_E */
+ u8 bmc_mac[NCSI_MAC_LEN]; /**< client info BMC mac addr */
+ u8 ncsi_mac[NCSI_MAC_LEN]; /**< client info local mac addr */
+ u8 reserve[2]; /**< client info reserved, Four-byte alignment */
+ u32 rsp_len; /**< client info include pad */
+ struct tg_ncsi_common_packet ncsi_packet_rsp; /**< ncsi common packet response */
+};
+
+/* AEN Enable Command (0x08) */
+#define AEN_ENABLE_REQ_LEN 8
+#define AEN_ENABLE_RSP_LEN 4
+#define AEN_CTRL_LINK_STATUS_SHIFT 0
+#define AEN_CTRL_CONFIG_REQ_SHIFT 1
+#define AEN_CTRL_DRV_CHANGE_SHIFT 2
+
+/* get link status 0x0A */
+#define GET_LINK_STATUS_REQ_LEN 0
+#define GET_LINK_STATUS_RSP_LEN 16
+/* link speed(fc link speed is mapped to unknown) */
+enum NCSI_CMD_LINK_SPEED_E {
+ LINK_SPEED_10M = 0x2, /**< 10M */
+ LINK_SPEED_100M = 0x5, /**< 100M */
+ LINK_SPEED_1G = 0x7, /**< 1G */
+ LINK_SPEED_10G = 0x8, /**< 10G */
+ LINK_SPEED_20G = 0x9, /**< 20G */
+ LINK_SPEED_25G = 0xa, /**< 25G */
+ LINK_SPEED_40G = 0xb, /**< 40G */
+ LINK_SPEED_50G = 0xc, /**< 50G */
+ LINK_SPEED_100G = 0xd, /**< 100G */
+ LINK_SPEED_2_5G = 0xe, /**< 2.5G */
+ LINK_SPEED_UNKNOWN = 0xf
+};
+
+/* Set Vlan Filter (0x0B) */
+/* Only VLAN-tagged packets that match the enabled VLAN Filter settings are accepted. */
+#define VLAN_MODE_UNSET 0X00
+#define VLAN_ONLY 0x01
+/* if match the MAC address ,any vlan-tagged and non-vlan-tagged will be accepted */
+#define ANYVLAN_NONVLAN 0x03
+#define VLAN_MODE_SUPPORT 0x05
+
+/* chanel vlan filter enable */
+#define CHNL_VALN_FL_ENABLE 0x01
+#define CHNL_VALN_FL_DISABLE 0x00
+
+/* vlan id invalid */
+#define VLAN_ID_VALID 0x01
+#define VLAN_ID_INVALID 0x00
+
+/* VLAN ID */
+#define SET_VLAN_FILTER_REQ_LEN 8
+#define SET_VLAN_FILTER_RSP_LEN 4
+
+/* ncsi_get_controller_packet_statistics_config */
+#define NO_INFORMATION_STATISTICS 0xff
+
+/* Enable VLAN Command (0x0C) */
+#define ENABLE_VLAN_REQ_LEN 4
+#define ENABLE_VLAN_RSP_LEN 4
+#define VLAN_FL_MAX_ID 8
+
+/* NCSI channel capabilities */
+struct tag_ncsi_chan_capa {
+ u32 capa_flags; /**< NCSI channel capabilities capa flags */
+ u32 bcast_filter; /**< NCSI channel capabilities bcast filter */
+ u32 multicast_filter; /**< NCSI channel capabilities multicast filter */
+ u32 buffering; /**< NCSI channel capabilities buffering */
+ u32 aen_ctrl; /**< NCSI channel capabilities aen ctrl */
+ u8 vlan_count; /**< NCSI channel capabilities vlan count */
+ u8 mixed_count; /**< NCSI channel capabilities mixed count */
+ u8 multicast_count; /**< NCSI channel capabilities multicast count */
+ u8 unicast_count; /**< NCSI channel capabilities unicast count */
+ u16 rsvd; /**< NCSI channel capabilities reserved */
+ u8 vlan_mode; /**< NCSI channel capabilities vlan mode */
+ u8 chan_count; /**< NCSI channel capabilities channel count */
+};
+
+struct tg_g_ncsi_parameters {
+ u8 mac_address_count;
+ u8 reserved1[2];
+ u8 mac_address_flags;
+ u8 vlan_tag_count;
+ u8 reserved2;
+ u16 vlan_tag_flags;
+ u32 link_settings;
+ u32 broadcast_packet_filter_settings;
+ u8 broadcast_packet_filter_status : 1;
+ u8 channel_enable : 1;
+ u8 channel_network_tx_enable : 1;
+ u8 global_mulicast_packet_filter_status : 1;
+ /**< bit0-3:mac_add0——mac_add3 address type:0 unicast,1 multileaving */
+ u8 config_flags_reserved1 : 4;
+ u8 config_flags_reserved2[3];
+ u8 vlan_mode; /**< current vlan mode */
+ u8 flow_control_enable;
+ u16 reserved3;
+ u32 AEN_control;
+ u8 mac_add[4][6];
+ u16 vlan_tag[VLAN_FL_MAX_ID];
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/mpu/nic_cfg_comm.h b/drivers/net/ethernet/huawei/hinic3/include/mpu/nic_cfg_comm.h
new file mode 100644
index 0000000000000..fe663e1fb0810
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/mpu/nic_cfg_comm.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef NIC_CFG_COMM_H
+#define NIC_CFG_COMM_H
+
+/* rss */
+#define HINIC3_RSS_TYPE_VALID_SHIFT 23
+#define HINIC3_RSS_TYPE_TCP_IPV6_EXT_SHIFT 24
+#define HINIC3_RSS_TYPE_IPV6_EXT_SHIFT 25
+#define HINIC3_RSS_TYPE_TCP_IPV6_SHIFT 26
+#define HINIC3_RSS_TYPE_IPV6_SHIFT 27
+#define HINIC3_RSS_TYPE_TCP_IPV4_SHIFT 28
+#define HINIC3_RSS_TYPE_IPV4_SHIFT 29
+#define HINIC3_RSS_TYPE_UDP_IPV6_SHIFT 30
+#define HINIC3_RSS_TYPE_UDP_IPV4_SHIFT 31
+
+#define HINIC3_RSS_TYPE_SET(val, member) (((u32)(val) & 0x1) << HINIC3_RSS_TYPE_##member##_SHIFT)
+#define HINIC3_RSS_TYPE_GET(val, member) (((u32)(val) >> HINIC3_RSS_TYPE_##member##_SHIFT) & 0x1)
+
+enum nic_rss_hash_type {
+ NIC_RSS_HASH_TYPE_XOR = 0,
+ NIC_RSS_HASH_TYPE_TOEP,
+
+ NIC_RSS_HASH_TYPE_MAX /* MUST BE THE LAST ONE */
+};
+
+#define NIC_RSS_INDIR_SIZE 256
+#define NIC_RSS_KEY_SIZE 40
+
+/* *
+ * Definition of the NIC receiving mode
+ */
+#define NIC_RX_MODE_UC 0x01
+#define NIC_RX_MODE_MC 0x02
+#define NIC_RX_MODE_BC 0x04
+#define NIC_RX_MODE_MC_ALL 0x08
+#define NIC_RX_MODE_PROMISC 0x10
+
+/* IEEE 802.1Qaz std */
+#define NIC_DCB_COS_MAX 0x8
+#define NIC_DCB_UP_MAX 0x8
+#define NIC_DCB_TC_MAX 0x8
+#define NIC_DCB_PG_MAX 0x8
+#define NIC_DCB_TSA_SP 0x0
+#define NIC_DCB_TSA_CBS 0x1 /* hi1822 do NOT support */
+#define NIC_DCB_TSA_ETS 0x2
+#define NIC_DCB_DSCP_NUM 0x8
+#define NIC_DCB_IP_PRI_MAX 0x40
+
+#define NIC_DCB_PRIO_DWRR 0x0
+#define NIC_DCB_PRIO_STRICT 0x1
+
+#define NIC_DCB_MAX_PFC_NUM 0x4
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/ossl_types.h b/drivers/net/ethernet/huawei/hinic3/include/ossl_types.h
new file mode 100644
index 0000000000000..c646e7c460821
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/ossl_types.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef _OSSL_TYPES_H
+#define _OSSL_TYPES_H
+
+#undef NULL
+#if defined(__cplusplus)
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+
+#if defined(__LINUX__)
+#ifdef __USER__ /* linux user */
+#if defined(__ia64__) || defined(__x86_64__) || defined(__aarch64__)
+#define s64 long
+#define u64 unsigned long
+#else
+#define s64 long long
+#define u64 unsigned long long
+#endif
+#define s32 int
+#define u32 unsigned int
+#define s16 short
+#define u16 unsigned short
+
+#ifdef __hinic_arm__
+#define s8 signed char
+#else
+#define s8 char
+#endif
+
+#ifndef dma_addr_t
+typedef u64 dma_addr_t;
+#endif
+
+#define u8 unsigned char
+#define ulong unsigned long
+#define uint unsigned int
+
+#define ushort unsigned short
+
+#endif
+#endif
+
+#define uda_handle void *
+
+#define UDA_TRUE 1
+#define UDA_FALSE 0
+
+#if defined(__USER__) || defined(USER)
+#ifndef F_OK
+#define F_OK 0
+#endif
+#ifndef F_FAILED
+#define F_FAILED (-1)
+#endif
+
+#define uda_status int
+#define TOOL_REAL_PATH_MAX_LEN 512
+#define SAFE_FUNCTION_ERR (-1)
+
+enum {
+ UDA_SUCCESS = 0x0, // run success
+ UDA_FAIL, // run failed
+ UDA_ENXIO, // no device
+ UDA_ENONMEM, // alloc memory failed
+ UDA_EBUSY, // card busy or restart
+ UDA_ECRC, // CRC check error
+ UDA_EINVAL, // invalid parameter
+ UDA_EFAULT, // invalid address
+ UDA_ELEN, // invalid length
+ UDA_ECMD, // error occurs when execute the cmd
+ UDA_ENODRIVER, // driver is not installed
+ UDA_EXIST, // has existed
+ UDA_EOVERSTEP, // over step
+ UDA_ENOOBJ, // have no object
+ UDA_EOBJ, // error object
+ UDA_ENOMATCH, // driver does not match to firmware
+ UDA_ETIMEOUT, // timeout
+
+ UDA_CONTOP,
+
+ UDA_REBOOT = 0xFD,
+ UDA_CANCEL = 0xFE,
+ UDA_KILLED = 0xFF,
+};
+
+enum {
+ UDA_FLOCK_NOBLOCK = 0,
+ UDA_FLOCK_BLOCK = 1,
+};
+
+/* array index */
+#define ARRAY_INDEX_0 0
+#define ARRAY_INDEX_1 1
+#define ARRAY_INDEX_2 2
+#define ARRAY_INDEX_3 3
+#define ARRAY_INDEX_4 4
+#define ARRAY_INDEX_5 5
+#define ARRAY_INDEX_6 6
+#define ARRAY_INDEX_7 7
+#define ARRAY_INDEX_8 8
+#define ARRAY_INDEX_12 12
+#define ARRAY_INDEX_13 13
+
+/* define shift bits */
+#define SHIFT_BIT_1 1
+#define SHIFT_BIT_2 2
+#define SHIFT_BIT_3 3
+#define SHIFT_BIT_4 4
+#define SHIFT_BIT_6 6
+#define SHIFT_BIT_7 7
+#define SHIFT_BIT_8 8
+#define SHIFT_BIT_11 11
+#define SHIFT_BIT_12 12
+#define SHIFT_BIT_15 15
+#define SHIFT_BIT_16 16
+#define SHIFT_BIT_17 17
+#define SHIFT_BIT_19 19
+#define SHIFT_BIT_20 20
+#define SHIFT_BIT_23 23
+#define SHIFT_BIT_24 24
+#define SHIFT_BIT_25 25
+#define SHIFT_BIT_26 26
+#define SHIFT_BIT_28 28
+#define SHIFT_BIT_29 29
+#define SHIFT_BIT_32 32
+#define SHIFT_BIT_35 35
+#define SHIFT_BIT_37 37
+#define SHIFT_BIT_39 39
+#define SHIFT_BIT_40 40
+#define SHIFT_BIT_43 43
+#define SHIFT_BIT_48 48
+#define SHIFT_BIT_51 51
+#define SHIFT_BIT_56 56
+#define SHIFT_BIT_57 57
+#define SHIFT_BIT_59 59
+#define SHIFT_BIT_60 60
+#define SHIFT_BIT_61 61
+
+#endif
+#endif /* OSSL_TYPES_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/include/public/npu_cmdq_base_defs.h b/drivers/net/ethernet/huawei/hinic3/include/public/npu_cmdq_base_defs.h
new file mode 100644
index 0000000000000..78236c92a84fa
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/public/npu_cmdq_base_defs.h
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef NPU_CMDQ_BASE_DEFS_H
+#define NPU_CMDQ_BASE_DEFS_H
+
+/* CmdQ Common subtype */
+enum comm_cmdq_cmd {
+ COMM_CMD_UCODE_ARM_BIT_SET = 2,
+ COMM_CMD_SEND_NPU_DFT_CMD,
+};
+
+/* Cmdq ack type */
+enum hinic3_ack_type {
+ HINIC3_ACK_TYPE_CMDQ,
+ HINIC3_ACK_TYPE_SHARE_CQN,
+ HINIC3_ACK_TYPE_APP_CQN,
+
+ HINIC3_MOD_ACK_MAX = 15,
+};
+
+/* Defines the queue type of the set arm bit. */
+enum {
+ SET_ARM_BIT_FOR_CMDQ = 0,
+ SET_ARM_BIT_FOR_L2NIC_SQ,
+ SET_ARM_BIT_FOR_L2NIC_RQ,
+ SET_ARM_BIT_TYPE_NUM
+};
+
+/* Defines the type. Each function supports a maximum of eight CMDQ types. */
+enum {
+ CMDQ_0 = 0,
+ CMDQ_1 = 1, /* dedicated and non-blocking queues */
+ CMDQ_NUM
+};
+
+/* *******************cmd common command data structure ************************ */
+// Func->ucode, which is used to set arm bit data,
+// The microcode needs to perform big-endian conversion.
+struct comm_info_ucode_set_arm_bit {
+ u32 q_type;
+ u32 q_id;
+};
+
+/* *******************WQE data structure ************************ */
+union cmdq_wqe_cs_dw0 {
+ struct {
+ u32 err_status : 29;
+ u32 error_code : 2;
+ u32 rsvd : 1;
+ } bs;
+ u32 val;
+};
+
+union cmdq_wqe_cs_dw1 {
+ struct {
+ u32 token : 16; // [15:0]
+ u32 cmd : 8; // [23:16]
+ u32 mod : 5; // [28:24]
+ u32 ack_type : 2; // [30:29]
+ u32 obit : 1; // [31]
+ } drv_wr; // This structure is used when the driver writes the wqe.
+
+ struct {
+ u32 mod : 5; // [4:0]
+ u32 ack_type : 3; // [7:5]
+ u32 cmd : 8; // [15:8]
+ u32 arm : 1; // [16]
+ u32 rsvd : 14; // [30:17]
+ u32 obit : 1; // [31]
+ } wb;
+ u32 val;
+};
+
+/* CmdQ BD information or write back buffer information */
+struct cmdq_sge {
+ u32 pa_h; // Upper 32 bits of the physical address
+ u32 pa_l; // Upper 32 bits of the physical address
+ u32 len; // Invalid bit[31].
+ u32 resv;
+};
+
+/* Ctrls section definition of WQE */
+struct cmdq_wqe_ctrls {
+ union {
+ struct {
+ u32 bdsl : 8; // [7:0]
+ u32 drvsl : 2; // [9:8]
+ u32 rsv : 4; // [13:10]
+ u32 wf : 1; // [14]
+ u32 cf : 1; // [15]
+ u32 tsl : 5; // [20:16]
+ u32 va : 1; // [21]
+ u32 df : 1; // [22]
+ u32 cr : 1; // [23]
+ u32 difsl : 3; // [26:24]
+ u32 csl : 2; // [28:27]
+ u32 ctrlsl : 2; // [30:29]
+ u32 obit : 1; // [31]
+ } bs;
+ u32 val;
+ } header;
+ u32 qsf;
+};
+
+/* Complete section definition of WQE */
+struct cmdq_wqe_cs {
+ union cmdq_wqe_cs_dw0 dw0;
+ union cmdq_wqe_cs_dw1 dw1;
+ union {
+ struct cmdq_sge sge;
+ u32 dw2_5[4];
+ } ack;
+};
+
+/* Inline header in WQE inline, describing the length of inline data */
+union cmdq_wqe_inline_header {
+ struct {
+ u32 buf_len : 11; // [10:0] inline data len
+ u32 rsv : 21; // [31:11]
+ } bs;
+ u32 val;
+};
+
+/* Definition of buffer descriptor section in WQE */
+union cmdq_wqe_bds {
+ struct {
+ struct cmdq_sge bds_sge;
+ u32 rsvd[4]; /* Zwy is used to transfer the virtual address of the buffer. */
+ } lcmd; /* Long command, non-inline, and SGE describe the buffer information. */
+};
+
+/* Definition of CMDQ WQE */
+/* (long cmd, 64B)
+ * +----------------------------------------+
+ * | ctrl section(8B) |
+ * +----------------------------------------+
+ * | |
+ * | complete section(24B) |
+ * | |
+ * +----------------------------------------+
+ * | |
+ * | buffer descriptor section(16B) |
+ * | |
+ * +----------------------------------------+
+ * | driver section(16B) |
+ * +----------------------------------------+
+ *
+ *
+ * (middle cmd, 128B)
+ * +----------------------------------------+
+ * | ctrl section(8B) |
+ * +----------------------------------------+
+ * | |
+ * | complete section(24B) |
+ * | |
+ * +----------------------------------------+
+ * | |
+ * | buffer descriptor section(88B) |
+ * | |
+ * +----------------------------------------+
+ * | driver section(8B) |
+ * +----------------------------------------+
+ *
+ *
+ * (short cmd, 64B)
+ * +----------------------------------------+
+ * | ctrl section(8B) |
+ * +----------------------------------------+
+ * | |
+ * | complete section(24B) |
+ * | |
+ * +----------------------------------------+
+ * | |
+ * | buffer descriptor section(24B) |
+ * | |
+ * +----------------------------------------+
+ * | driver section(8B) |
+ * +----------------------------------------+
+ */
+struct cmdq_wqe {
+ struct cmdq_wqe_ctrls ctrls;
+ struct cmdq_wqe_cs cs;
+ union cmdq_wqe_bds bds;
+};
+
+/* Definition of ctrls section in inline WQE */
+struct cmdq_wqe_ctrls_inline {
+ union {
+ struct {
+ u32 bdsl : 8; // [7:0]
+ u32 drvsl : 2; // [9:8]
+ u32 rsv : 4; // [13:10]
+ u32 wf : 1; // [14]
+ u32 cf : 1; // [15]
+ u32 tsl : 5; // [20:16]
+ u32 va : 1; // [21]
+ u32 df : 1; // [22]
+ u32 cr : 1; // [23]
+ u32 difsl : 3; // [26:24]
+ u32 csl : 2; // [28:27]
+ u32 ctrlsl : 2; // [30:29]
+ u32 obit : 1; // [31]
+ } bs;
+ u32 val;
+ } header;
+ u32 qsf;
+ u64 db;
+};
+
+/* Buffer descriptor section definition of WQE */
+union cmdq_wqe_bds_inline {
+ struct {
+ union cmdq_wqe_inline_header header;
+ u32 rsvd;
+ u8 data_inline[80];
+ } mcmd; /* Middle command, inline mode */
+
+ struct {
+ union cmdq_wqe_inline_header header;
+ u32 rsvd;
+ u8 data_inline[16];
+ } scmd; /* Short command, inline mode */
+};
+
+struct cmdq_wqe_inline {
+ struct cmdq_wqe_ctrls_inline ctrls;
+ struct cmdq_wqe_cs cs;
+ union cmdq_wqe_bds_inline bds;
+};
+
+#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/include/readme.txt b/drivers/net/ethernet/huawei/hinic3/include/readme.txt
new file mode 100644
index 0000000000000..895f213b507fb
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/readme.txt
@@ -0,0 +1 @@
+本目录是业务内部共享接口 \ No newline at end of file
diff --git a/drivers/net/ethernet/huawei/hinic3/include/vmsec/vmsec_mpu_common.h b/drivers/net/ethernet/huawei/hinic3/include/vmsec/vmsec_mpu_common.h
new file mode 100644
index 0000000000000..d78dba862814e
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/vmsec/vmsec_mpu_common.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
+
+#ifndef VMSEC_MPU_COMMON_H
+#define VMSEC_MPU_COMMON_H
+
+#include "mpu_cmd_base_defs.h"
+
+#define VM_GPA_INFO_MODE_MIG 0
+#define VM_GPA_INFO_MODE_NMIG 1
+
+/**
+ * Commands between VMSEC to MPU
+ */
+enum tag_vmsec_mpu_cmd {
+ /* vmsec ctx gpa */
+ VMSEC_MPU_CMD_CTX_GPA_SET = 0,
+ VMSEC_MPU_CMD_CTX_GPA_SHOW,
+ VMSEC_MPU_CMD_CTX_GPA_DEL,
+
+ /* vmsec pci hole */
+ VMSEC_MPU_CMD_PCI_HOLE_SET,
+ VMSEC_MPU_CMD_PCI_HOLE_SHOW,
+ VMSEC_MPU_CMD_PCI_HOLE_DEL,
+
+ /* vmsec func cfg */
+ VMSEC_MPU_CMD_FUN_CFG_ENTRY_IDX_SET,
+ VMSEC_MPU_CMD_FUN_CFG_ENTRY_IDX_SHOW,
+
+ VMSEC_MPU_CMD_MAX
+};
+
+struct vmsec_ctx_gpa_entry {
+#if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
+ u32 func_id : 16;
+ u32 mode : 8;
+ u32 rsvd : 8;
+#else
+ u32 rsvd : 8;
+ u32 mode : 8;
+ u32 func_id : 16;
+#endif
+
+ /* sml tbl to wr */
+ u32 gpa_addr0_hi;
+ u32 gpa_addr0_lo;
+ u32 gpa_len0;
+};
+
+struct vmsec_pci_hole_idx {
+#if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
+ u32 entry_idx : 5;
+ u32 rsvd : 27;
+#else
+ u32 rsvd : 27;
+ u32 entry_idx : 5;
+#endif
+};
+
+struct vmsec_pci_hole_entry {
+ /* sml tbl to wr */
+ /* pcie hole 32-bit region */
+ u32 gpa_addr0_hi;
+ u32 gpa_addr0_lo;
+ u32 gpa_len0_hi;
+ u32 gpa_len0_lo;
+
+ /* pcie hole 64-bit region */
+ u32 gpa_addr1_hi;
+ u32 gpa_addr1_lo;
+ u32 gpa_len1_hi;
+ u32 gpa_len1_lo;
+
+ /* ctrl info used by drv */
+ u32 domain_id; /* unique vm id */
+#if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
+ u32 rsvd1 : 21;
+ u32 vf_nums : 11;
+#else
+ u32 rsvd1 : 21;
+ u32 vf_nums : 11;
+#endif
+ u32 vroce_vf_bitmap;
+};
+
+struct vmsec_funcfg_info_entry {
+ /* funcfg to update */
+#if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
+ u32 func_id : 16;
+ u32 entry_vld : 1;
+ u32 entry_idx : 5;
+ u32 rsvd : 10;
+#else
+ u32 rsvd : 10;
+ u32 entry_idx : 5;
+ u32 entry_vld : 1;
+ u32 func_id : 16;
+#endif
+};
+
+/* set/get/del */
+struct vmsec_cfg_ctx_gpa_entry_cmd {
+ struct comm_info_head head;
+ struct vmsec_ctx_gpa_entry entry;
+};
+
+#endif /* VMSEC_MPU_COMMON_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/include/vram_common.h b/drivers/net/ethernet/huawei/hinic3/include/vram_common.h
new file mode 100644
index 0000000000000..801aeed183104
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic3/include/vram_common.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2021 Huawei Technologies Co., Ltd */
+
+#ifndef VRAM_COMMON_H
+#define VRAM_COMMON_H
+
+#include <linux/pci.h>
+#include <linux/notifier.h>
+
+#define VRAM_BLOCK_SIZE_2M 0x200000UL
+#define KEXEC_SIGN "hinic-in-kexec"
+// now vram_name max len is 14, when add other vram, attention this value
+#define VRAM_NAME_MAX_LEN 16
+
+#define VRAM_CQM_GLB_FUNC_BASE "F"
+#define VRAM_CQM_FAKE_MEM_BASE "FK"
+#define VRAM_CQM_CLA_BASE "C"
+#define VRAM_CQM_CLA_TYPE_BASE "T"
+#define VRAM_CQM_CLA_SMF_BASE "SMF"
+#define VRAM_CQM_CLA_COORD_X "X"
+#define VRAM_CQM_CLA_COORD_Y "Y"
+#define VRAM_CQM_CLA_COORD_Z "Z"
+#define VRAM_CQM_BITMAP_BASE "B"
+
+#define VRAM_NIC_DCB "DCB"
+#define VRAM_NIC_VRAM "NIC_VRAM"
+
+#define VRAM_VBS_BASE_IOCB "BASE_IOCB"
+#define VRAM_VBS_EX_IOCB "EX_IOCB"
+#define VRAM_VBS_RXQS_CQE "RXQS_CQE"
+
+#define VRAM_VBS_VOLQ_MTT "VOLQ_MTT"
+#define VRAM_VBS_VOLQ_MTT_PAGE "MTT_PAGE"
+
+#define VRAM_VROCE_ENTRY_POOL "VROCE_ENTRY"
+#define VRAM_VROCE_GROUP_POOL "VROCE_GROUP"
+#define VRAM_VROCE_UUID "VROCE_UUID"
+#define VRAM_VROCE_VID "VROCE_VID"
+#define VRAM_VROCE_BASE "VROCE_BASE"
+#define VRAM_VROCE_DSCP "VROCE_DSCP"
+#define VRAM_VROCE_QOS "VROCE_QOS"
+#define VRAM_VROCE_DEV "VROCE_DEV"
+#define VRAM_VROCE_RGROUP_HT_CNT "RGROUP_CNT"
+#define VRAM_VROCE_RACL_HT_CNT "RACL_CNT"
+
+#define VRAM_NAME_APPLY_LEN 64
+
+#define MPU_OS_HOTREPLACE_FLAG 0x1
+struct vram_buf_info {
+ char buf_vram_name[VRAM_NAME_APPLY_LEN];
+ int use_vram;
+};
+
+enum KUP_HOOK_POINT {
+ PRE_FREEZE,
+ FREEZE_TO_KILL,
+ PRE_UPDATE_KERNEL,
+ FLUSH_DURING_KUP,
+ POST_UPDATE_KERNEL,
+ UNFREEZE_TO_RUN,
+ POST_RUN,
+ KUP_HOOK_MAX,
+};
+
+#endif /* VRAM_COMMON_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/mag_cmd.h b/drivers/net/ethernet/huawei/hinic3/mag_cmd.h
index 799f0b38a1e92..964950361972b 100644
--- a/drivers/net/ethernet/huawei/hinic3/mag_cmd.h
+++ b/drivers/net/ethernet/huawei/hinic3/mag_cmd.h
@@ -1,73 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
- * Description: serdes/mag cmd definition between driver and mpu
- * Author: ETH group
- * Create: 2021-07-30
- */
-
-#ifndef MAG_CMD_H
-#define MAG_CMD_H
-
-#include "mgmt_msg_base.h"
-
-/* serdes/mag消息命令字定义 */
-enum mag_cmd {
- /* serdes命令字,统一封装所有serdes命令 */
- SERDES_CMD_PROCESS = 0,
-
- /* mag命令字,按功能划分 */
- /* 端口配置相关 0-29 */
- MAG_CMD_SET_PORT_CFG = 1,
- MAG_CMD_SET_PORT_ADAPT = 2,
- MAG_CMD_CFG_LOOPBACK_MODE = 3,
-
- MAG_CMD_GET_PORT_ENABLE = 5,
- MAG_CMD_SET_PORT_ENABLE = 6,
- MAG_CMD_GET_LINK_STATUS = 7,
- MAG_CMD_SET_LINK_FOLLOW = 8,
- MAG_CMD_SET_PMA_ENABLE = 9,
- MAG_CMD_CFG_FEC_MODE = 10,
-
- MAG_CMD_CFG_AN_TYPE = 12, /* reserved for future use */
- MAG_CMD_CFG_LINK_TIME = 13,
-
- MAG_CMD_SET_PANGEA_ADAPT = 15,
-
- /* bios link配置相关 30-49 */
- MAG_CMD_CFG_BIOS_LINK_CFG = 31,
- MAG_CMD_RESTORE_LINK_CFG = 32,
- MAG_CMD_ACTIVATE_BIOS_LINK_CFG = 33,
-
- /* 光模块、LED、PHY等外设配置管理 50-99 */
- /* LED */
- MAG_CMD_SET_LED_CFG = 50,
-
- /* PHY */
- MAG_CMD_GET_PHY_INIT_STATUS = 55, /* reserved for future use */
-
- /* 光模块 */
- MAG_CMD_GET_XSFP_INFO = 60,
- MAG_CMD_SET_XSFP_ENABLE = 61,
- MAG_CMD_GET_XSFP_PRESENT = 62,
- MAG_CMD_SET_XSFP_RW = 63, /* sfp/qsfp single byte read/write, for equipment test */
- MAG_CMD_CFG_XSFP_TEMPERATURE = 64,
-
- /* 事件上报 100-149 */
- MAG_CMD_WIRE_EVENT = 100,
- MAG_CMD_LINK_ERR_EVENT = 101,
+/* Copyright(c) 2024 Huawei Technologies Co., Ltd */
- /* DFX、Counter相关 */
- MAG_CMD_EVENT_PORT_INFO = 150,
- MAG_CMD_GET_PORT_STAT = 151,
- MAG_CMD_CLR_PORT_STAT = 152,
- MAG_CMD_GET_PORT_INFO = 153,
- MAG_CMD_GET_PCS_ERR_CNT = 154,
- MAG_CMD_GET_MAG_CNT = 155,
- MAG_CMD_DUMP_ANTRAIN_INFO = 156,
+#ifndef MAG_MPU_CMD_DEFS_H
+#define MAG_MPU_CMD_DEFS_H
- MAG_CMD_MAX = 0xFF
-};
+#include "mpu_cmd_base_defs.h"
/* serdes cmd struct define */
#define CMD_ARRAY_BUF_SIZE 64
@@ -352,6 +289,14 @@ struct mag_cmd_get_link_status {
u8 rsvd0[2];
};
+/* firmware also use this cmd report bond event to driver */
+struct mag_cmd_get_bond_status {
+ struct mgmt_msg_head head;
+
+ u8 status; /* 0:bond down 1:bond up */
+ u8 rsvd0[3];
+};
+
struct mag_cmd_set_pma_enable {
struct mgmt_msg_head head;
@@ -389,6 +334,75 @@ struct mag_cmd_cfg_fec_mode {
u8 rsvd0;
};
+/* speed */
+#define PANGEA_ADAPT_10G_BITMAP 0xd
+#define PANGEA_ADAPT_25G_BITMAP 0x72
+#define PANGEA_ADAPT_40G_BITMAP 0x680
+#define PANGEA_ADAPT_100G_BITMAP 0x1900
+
+/* speed and fec */
+#define PANGEA_10G_NO_BITMAP 0x8
+#define PANGEA_10G_BASE_BITMAP 0x4
+#define PANGEA_25G_NO_BITMAP 0x10
+#define PANGEA_25G_BASE_BITMAP 0x20
+#define PANGEA_25G_RS_BITMAP 0x40
+#define PANGEA_40G_NO_BITMAP 0x400
+#define PANGEA_40G_BASE_BITMAP 0x200
+#define PANGEA_100G_NO_BITMAP 0x800
+#define PANGEA_100G_RS_BITMAP 0x1000
+
+/* adapt or fec */
+#define PANGEA_ADAPT_ADAPT_BITMAP 0x183
+#define PANGEA_ADAPT_NO_BITMAP 0xc18
+#define PANGEA_ADAPT_BASE_BITMAP 0x224
+#define PANGEA_ADAPT_RS_BITMAP 0x1040
+
+/* default cfg */
+#define PANGEA_ADAPT_CFG_10G_CR 0x200d
+#define PANGEA_ADAPT_CFG_10G_SRLR 0xd
+#define PANGEA_ADAPT_CFG_25G_CR 0x207f
+#define PANGEA_ADAPT_CFG_25G_SRLR 0x72
+#define PANGEA_ADAPT_CFG_40G_CR4 0x2680
+#define PANGEA_ADAPT_CFG_40G_SRLR4 0x680
+#define PANGEA_ADAPT_CFG_100G_CR4 0x3f80
+#define PANGEA_ADAPT_CFG_100G_SRLR4 0x1900
+
+union pangea_adapt_bitmap_u {
+ struct {
+ u32 adapt_10g : 1; /* [0] adapt_10g */
+ u32 adapt_25g : 1; /* [1] adapt_25g */
+ u32 base_10g : 1; /* [2] base_10g */
+ u32 no_10g : 1; /* [3] no_10g */
+ u32 no_25g : 1; /* [4] no_25g */
+ u32 base_25g : 1; /* [5] base_25g */
+ u32 rs_25g : 1; /* [6] rs_25g */
+ u32 adapt_40g : 1; /* [7] adapt_40g */
+ u32 adapt_100g : 1; /* [8] adapt_100g */
+ u32 base_40g : 1; /* [9] base_40g */
+ u32 no_40g : 1; /* [10] no_40g */
+ u32 no_100g : 1; /* [11] no_100g */
+ u32 rs_100g : 1; /* [12] rs_100g */
+ u32 auto_neg : 1; /* [13] auto_neg */
+ u32 rsvd0 : 18; /* [31:14] reserved */
+ } bits;
+
+ u32 value;
+};
+
+#define PANGEA_ADAPT_GET 0x0
+#define PANGEA_ADAPT_SET 0x1
+struct mag_cmd_set_pangea_adapt {
+ struct mgmt_msg_head head;
+
+ u16 port_id;
+ u8 opcode; /* 0:get adapt info 1:cfg adapt info */
+ u8 wire_type;
+
+ union pangea_adapt_bitmap_u cfg_bitmap;
+ union pangea_adapt_bitmap_u cur_bitmap;
+ u32 rsvd1[3];
+};
+
struct mag_cmd_cfg_bios_link_cfg {
struct mgmt_msg_head head;
@@ -621,22 +635,21 @@ struct mag_cmd_event_port_info {
u8 event_type;
u8 rsvd0[2];
- // 光模块相关
u8 vendor_name[XSFP_VENDOR_NAME_LEN];
- u32 port_type; /* fiber / copper */
- u32 port_sub_type; /* sr / lr */
- u32 cable_length; /* 1/3/5m */
- u8 cable_temp; /* 温度 */
- u8 max_speed; /* 光模块最大速率 */
- u8 sfp_type; /* sfp/qsfp */
+ u32 port_type; /* fiber / copper */
+ u32 port_sub_type; /* sr / lr */
+ u32 cable_length; /* 1/3/5m */
+ u8 cable_temp; /* temp */
+ u8 max_speed; /* Maximum rate of an optical module */
+ u8 sfp_type; /* sfp/qsfp */
u8 rsvd1;
- u32 power[4]; /* 光功率 */
+ u32 power[4]; /* Optical Power */
u8 an_state;
u8 fec;
u16 speed;
- u8 gpio_insert; /* 0:present 1:absent */
+ u8 gpio_insert; /* 0:present 1:absent */
u8 alos;
u8 rx_los;
u8 pma_ctrl;
@@ -755,6 +768,98 @@ struct mag_cmd_port_stats {
u64 mac_rx_unfilter_pkt_num;
};
+struct mag_port_stats {
+ u64 tx_frag_pkts_port;
+ u64 tx_under_frame_pkts_port;
+ u64 tx_under_min_pkts_port;
+ u64 tx_64_oct_pkts_port;
+ u64 tx_127_oct_pkts_port;
+ u64 tx_255_oct_pkts_port;
+ u64 tx_511_oct_pkts_port;
+ u64 tx_1023_oct_pkts_port;
+ u64 tx_1518_oct_pkts_port;
+ u64 tx_2047_oct_pkts_port;
+ u64 tx_4095_oct_pkts_port;
+ u64 tx_8191_oct_pkts_port;
+ u64 tx_9216_oct_pkts_port;
+ u64 tx_12287_oct_pkts_port;
+ u64 tx_16383_oct_pkts_port;
+ u64 tx_1519_to_max_bad_pkts_port;
+ u64 tx_1519_to_max_good_pkts_port;
+ u64 tx_oversize_pkts_port;
+ u64 tx_jabber_pkts_port;
+ u64 tx_bad_pkts_port;
+ u64 tx_bad_octs_port;
+ u64 tx_good_pkts_port;
+ u64 tx_good_octs_port;
+ u64 tx_total_pkts_port;
+ u64 tx_total_octs_port;
+ u64 tx_unicast_pkts_port;
+ u64 tx_multicast_pkts_port;
+ u64 tx_broadcast_pkts_port;
+ u64 tx_pause_pkts_port;
+ u64 tx_pfc_pkts_port;
+ u64 tx_pri_0_pkts_port;
+ u64 tx_pri_1_pkts_port;
+ u64 tx_pri_2_pkts_port;
+ u64 tx_pri_3_pkts_port;
+ u64 tx_pri_4_pkts_port;
+ u64 tx_pri_5_pkts_port;
+ u64 tx_pri_6_pkts_port;
+ u64 tx_pri_7_pkts_port;
+ u64 tx_mac_control_pkts_port;
+ u64 tx_y1731_pkts_port;
+ u64 tx_1588_pkts_port;
+ u64 tx_error_pkts_port;
+ u64 tx_app_good_pkts_port;
+ u64 tx_app_bad_pkts_port;
+ u64 rx_frag_pkts_port;
+ u64 rx_under_frame_pkts_port;
+ u64 rx_under_min_pkts_port;
+ u64 rx_64_oct_pkts_port;
+ u64 rx_127_oct_pkts_port;
+ u64 rx_255_oct_pkts_port;
+ u64 rx_511_oct_pkts_port;
+ u64 rx_1023_oct_pkts_port;
+ u64 rx_1518_oct_pkts_port;
+ u64 rx_2047_oct_pkts_port;
+ u64 rx_4095_oct_pkts_port;
+ u64 rx_8191_oct_pkts_port;
+ u64 rx_9216_oct_pkts_port;
+ u64 rx_12287_oct_pkts_port;
+ u64 rx_16383_oct_pkts_port;
+ u64 rx_1519_to_max_bad_pkts_port;
+ u64 rx_1519_to_max_good_pkts_port;
+ u64 rx_oversize_pkts_port;
+ u64 rx_jabber_pkts_port;
+ u64 rx_bad_pkts_port;
+ u64 rx_bad_octs_port;
+ u64 rx_good_pkts_port;
+ u64 rx_good_octs_port;
+ u64 rx_total_pkts_port;
+ u64 rx_total_octs_port;
+ u64 rx_unicast_pkts_port;
+ u64 rx_multicast_pkts_port;
+ u64 rx_broadcast_pkts_port;
+ u64 rx_pause_pkts_port;
+ u64 rx_pfc_pkts_port;
+ u64 rx_pri_0_pkts_port;
+ u64 rx_pri_1_pkts_port;
+ u64 rx_pri_2_pkts_port;
+ u64 rx_pri_3_pkts_port;
+ u64 rx_pri_4_pkts_port;
+ u64 rx_pri_5_pkts_port;
+ u64 rx_pri_6_pkts_port;
+ u64 rx_pri_7_pkts_port;
+ u64 rx_mac_control_pkts_port;
+ u64 rx_y1731_pkts_port;
+ u64 rx_sym_err_pkts_port;
+ u64 rx_fcs_err_pkts_port;
+ u64 rx_app_good_pkts_port;
+ u64 rx_app_bad_pkts_port;
+ u64 rx_unfilter_pkts_port;
+};
+
struct mag_cmd_port_stats_info {
struct mgmt_msg_head head;
@@ -799,20 +904,19 @@ struct mag_cmd_dump_antrain_info {
};
#define MAG_SFP_PORT_NUM 24
-/* 芯片光模块温度结构体定义 */
struct mag_cmd_sfp_temp_in_info {
struct mgmt_msg_head head; /* 8B */
- u8 opt_type; /* 0:read operation 1:cfg operation */
+ u8 opt_type; /* 0:read operation 1:cfg operation */
u8 rsv[3];
- s32 max_temp; /* 芯片光模块阈值 */
- s32 min_temp; /* 芯片光模块阈值 */
+ s32 max_temp; /* Chip optical module threshold */
+ s32 min_temp; /* Chip optical module threshold */
};
struct mag_cmd_sfp_temp_out_info {
- struct mgmt_msg_head head; /* 8B */
- s16 sfp_temp_data[MAG_SFP_PORT_NUM]; /* 读出的温度 */
- s32 max_temp; /* 芯片光模块阈值 */
- s32 min_temp; /* 芯片光模块阈值 */
+ struct mgmt_msg_head head; /* 8B */
+ s16 sfp_temp_data[MAG_SFP_PORT_NUM]; /* Temperature read */
+ s32 max_temp; /* Chip optical module threshold */
+ s32 min_temp; /* Chip optical module threshold */
};
#endif
diff --git a/drivers/net/ethernet/huawei/hinic3/ossl_knl.h b/drivers/net/ethernet/huawei/hinic3/ossl_knl.h
index d5d1b3c7a2fb8..bb658cba8ff3e 100644
--- a/drivers/net/ethernet/huawei/hinic3/ossl_knl.h
+++ b/drivers/net/ethernet/huawei/hinic3/ossl_knl.h
@@ -5,6 +5,7 @@
#define OSSL_KNL_H
#include "ossl_knl_linux.h"
+#include <linux/types.h>
#define sdk_err(dev, format, ...) dev_err(dev, "[COMM]" format, ##__VA_ARGS__)
#define sdk_warn(dev, format, ...) dev_warn(dev, "[COMM]" format, ##__VA_ARGS__)
@@ -32,4 +33,7 @@
#define USEC_PER_MSEC 1000L
#define MSEC_PER_SEC 1000L
+/* Waiting for 50 us */
+#define WAIT_USEC_50 50L
+
#endif /* OSSL_KNL_H */
diff --git a/drivers/net/ethernet/huawei/hinic3/ossl_knl_linux.h b/drivers/net/ethernet/huawei/hinic3/ossl_knl_linux.h
index 2ad61128f5173..ee005a8ade748 100644
--- a/drivers/net/ethernet/huawei/hinic3/ossl_knl_linux.h
+++ b/drivers/net/ethernet/huawei/hinic3/ossl_knl_linux.h
@@ -35,6 +35,17 @@
#undef __always_unused
#define __always_unused __attribute__((__unused__))
+#define ossl_get_free_pages __get_free_pages
+
+#ifndef high_16_bits
+#define low_16_bits(x) ((x) & 0xFFFF)
+#define high_16_bits(x) (((x) & 0xFFFF0000) >> 16)
+#endif
+
+#ifndef U8_MAX
+#define U8_MAX 0xFF
+#endif
+
#define ETH_TYPE_TRANS_SETS_DEV
#define HAVE_NETDEV_STATS_IN_NETDEV
@@ -169,10 +180,12 @@ static inline void *_hinic3_dma_zalloc_coherent(struct device *dev,
}
#endif
+#ifndef DT_KNL_EMU
struct timeval {
__kernel_old_time_t tv_sec; /* seconds */
__kernel_suseconds_t tv_usec; /* microseconds */
};
+#endif
#ifndef do_gettimeofday
#define do_gettimeofday(time) _kc_do_gettimeofday(time)
@@ -216,6 +229,15 @@ static inline void _kc_do_gettimeofday(struct timeval *tv)
#define HAVE_ENCAPSULATION_CSUM
+#ifndef eth_zero_addr
+static inline void hinic3_eth_zero_addr(u8 *addr)
+{
+ memset(addr, 0x00, ETH_ALEN);
+}
+
+#define eth_zero_addr(_addr) hinic3_eth_zero_addr(_addr)
+#endif
+
#ifndef netdev_hw_addr_list_for_each
#define netdev_hw_addr_list_for_each(ha, l) \
list_for_each_entry(ha, &(l)->list, list)
@@ -233,6 +255,11 @@ u32 get_file_size(struct file *file_handle);
void set_file_position(struct file *file_handle, u32 position);
+int file_read(struct file *file_handle, char *log_buffer, u32 rd_length,
+ u32 *file_pos);
+
+u32 file_write(struct file *file_handle, const char *log_buffer, u32 wr_length);
+
struct sdk_thread_info {
struct task_struct *thread_obj;
char *name;
@@ -253,7 +280,7 @@ void utctime_to_localtime(u64 utctime, u64 *localtime);
void initialize_timer(const void *adapter_hdl, struct timer_list *timer);
#endif
-void add_to_timer(struct timer_list *timer, long period);
+void add_to_timer(struct timer_list *timer, u64 period);
void stop_timer(struct timer_list *timer);
void delete_timer(struct timer_list *timer);
u64 ossl_get_real_time(void);
diff --git a/openEuler/MAINTAINERS b/openEuler/MAINTAINERS
index c0c9a11284307..bfe25539a7089 100644
--- a/openEuler/MAINTAINERS
+++ b/openEuler/MAINTAINERS
@@ -101,6 +101,24 @@ F: Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
F: include/uapi/rdma/hns-abi.h
F: drivers/infiniband/hw/hns/
+HUAWEI ETHERNET DRIVER
+M: Wulike(Collin) <wulike1@huawei.com>
+L: netdev@vger.kernel.org
+S: Supported
+F: Documentation/networking/hinic3.rst
+F: drivers/net/ethernet/huawei/hinic3/
+F: drivers/net/ethernet/huawei/hinic3/bond/
+F: drivers/net/ethernet/huawei/hinic3/cqm/
+F: drivers/net/ethernet/huawei/hinic3/hw/
+F: drivers/net/ethernet/huawei/hinic3/include/
+
+HUAWEI PVRDMA DRIVER
+M: Chengbo Gu <guchengbo@huawei.com>
+R: Xiaoping zheng <zhengxiaoping5@huawei.com>
+L: linux-rdma@vger.kernel.org
+S: Supported
+F: drivers/infiniband/hw/hiroce3/
+
NEBULA-MATRIX Ethernet Controller DRIVERS
M: Yi Chen <open@nebula-matrix.com>
S: Maintained