Line data Source code
1 : /**
2 : * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "rdma_conn_lite_v2.h"
12 : #include "rdma_vendor_1825_ops.h"
13 :
14 : namespace Hccl {
15 : constexpr u64 RDMA_DMA_MAX_SIZE = 0x80000000; // Byte, RDMA一次传输的最大size
16 :
17 51 : void RdmaConnLiteV2::ParseSqContext(std::vector<char>& data)
18 : {
19 51 : BinaryStream binaryStream(data);
20 51 : binaryStream >> sqContext.qpn;
21 51 : binaryStream >> sqContext.sqVa;
22 51 : binaryStream >> sqContext.wqeSize;
23 51 : binaryStream >> sqContext.depth;
24 51 : binaryStream >> sqContext.headAddr;
25 51 : binaryStream >> sqContext.tailAddr;
26 51 : binaryStream >> sqContext.dbHwVa;
27 51 : binaryStream >> sqContext.dbSwVa;
28 51 : binaryStream >> sqContext.sl;
29 51 : binaryStream >> sqContext.dbVendorSpecified;
30 51 : }
31 :
32 51 : void RdmaConnLiteV2::ParseCqContext(std::vector<char>& data)
33 : {
34 51 : BinaryStream binaryStream(data);
35 51 : binaryStream >> cqContext.cqn;
36 51 : binaryStream >> cqContext.cqVa;
37 51 : binaryStream >> cqContext.cqeSize;
38 51 : binaryStream >> cqContext.cqDepth;
39 51 : binaryStream >> cqContext.headAddr;
40 51 : binaryStream >> cqContext.tailAddr;
41 51 : binaryStream >> cqContext.dbSwVa;
42 51 : binaryStream >> cqContext.dbVendorSpecified;
43 51 : }
44 :
45 51 : RdmaConnLiteV2::RdmaConnLiteV2(std::vector<char>& uniqueId) : RmaConnLite()
46 : {
47 51 : BinaryStream binaryStream(uniqueId);
48 51 : binaryStream >> dmaMode_;
49 :
50 51 : std::vector<char> sqUniqueId;
51 51 : binaryStream >> sqUniqueId;
52 51 : ParseSqContext(sqUniqueId);
53 :
54 51 : std::vector<char> cqUniqueId;
55 51 : binaryStream >> cqUniqueId;
56 51 : ParseCqContext(cqUniqueId);
57 :
58 51 : qpVa_ = sqContext.sqVa;
59 51 : sqVa_ = sqContext.sqVa;
60 51 : sqDepth_ = sqContext.depth;
61 :
62 : // 确定厂商
63 51 : GetVendorOps();
64 51 : }
65 :
66 80 : RdmaConnLiteV2::~RdmaConnLiteV2() {}
67 :
68 41 : std::string RdmaConnLiteV2::Describe()
69 : {
70 41 : uint8_t mtuShift
71 41 : = static_cast<uint8_t>((sqContext.dbVendorSpecified >> UB_DB_VENDOR_MTUSHIFT_SHIFT) & UB_DB_VENDOR_FIELD_MASK);
72 41 : uint8_t cos
73 41 : = static_cast<uint8_t>((sqContext.dbVendorSpecified >> UB_DB_VENDOR_COS_SHIFT) & UB_DB_VENDOR_FIELD_MASK);
74 :
75 : return StringFormat(
76 : "RdmaConnLiteV2[QPN=%u, SQ_VA=0x%llx, WQE_SIZE=%u, SQ_DEPTH=%u, SQ_HEAD_ADDR=0x%llx, SQ_TAIL_ADDR=0x%llx, "
77 : "SL=%u, DB_HW_VA=0x%llx, DB_SW_VA=0x%llx, MTU_SHIFT=%u, COS=%u, "
78 : "DB_VENDOR_SPECIFIED=0x%llx, CQN=%u, CQ_VA=0x%llx, CQE_SIZE=%u, CQ_DEPTH=%u, "
79 : "CQ_HEAD_ADDR=0x%llx, CQ_TAIL_ADDR=0x%llx, DB_HW_VA=0x%llx, DB_SW_VA=0x%llx, "
80 : "CQ_DB_VENDOR_SPECIFIED=0x%llx]",
81 : sqContext.qpn, sqContext.sqVa, sqContext.wqeSize, sqContext.depth, sqContext.headAddr, sqContext.tailAddr,
82 41 : sqContext.sl, sqContext.dbHwVa, sqContext.dbSwVa, mtuShift, cos, sqContext.dbVendorSpecified, cqContext.cqn,
83 : cqContext.cqVa, cqContext.cqeSize, cqContext.cqDepth, cqContext.headAddr, cqContext.tailAddr, cqContext.dbHwVa,
84 41 : cqContext.dbSwVa, cqContext.dbVendorSpecified);
85 : }
86 :
87 52 : void RdmaConnLiteV2::GetVendorOps()
88 : {
89 52 : if (rdmaOps_ != nullptr) {
90 1 : return;
91 : }
92 51 : switch (dmaMode_) {
93 11 : case 0: { // [PCIe] QBUF_DMA_MODE_DEFAULT
94 29 : HCCL_INFO("[RdmaConnLiteV2::%s] Now Aicpu NDA doesn't support PCIE !", __func__);
95 11 : rdmaOps_ = nullptr;
96 11 : break;
97 : }
98 39 : case 1: { // [UB] QBUF_DMA_MODE_INDEP_UB
99 39 : rdmaOps_ = std::make_unique<Rdma1825Ops>(&sqContext, &cqContext);
100 39 : break;
101 : }
102 1 : default: {
103 3 : HCCL_INFO("[RdmaConnLiteV2::%s] Now dmaMode is invalid !", __func__);
104 1 : rdmaOps_ = nullptr;
105 1 : break;
106 : }
107 : }
108 : }
109 :
110 : // 检查Ops不能为空
111 8 : void RdmaConnLiteV2::CheckVendorOp()
112 : {
113 8 : if (UNLIKELY(rdmaOps_ == nullptr)) {
114 1 : THROW<InternalException>(StringFormat("NDA Op is null. Now dmaMode_ is %d.", dmaMode_));
115 : }
116 7 : }
117 :
118 2 : void RdmaConnLiteV2::Read(
119 : const RmaBufSliceLite& loc, const RmtRmaBufSliceLite& rmt, const SqeConfigLite& cfg, u64& dbAddr, u64& dbValue)
120 : {
121 6 : HCCL_INFO("[RdmaConnLiteV2::%s] Read start, loc size = %u", __func__, loc.GetSize());
122 2 : CheckVendorOp();
123 :
124 : // 分片操作
125 2 : DoSlice(loc, rmt, [this, &cfg](const RmaBufSliceLite& locSlice, const RmtRmaBufSliceLite& rmtSlice) {
126 3 : rdmaOps_->Read(locSlice, rmtSlice, cfg);
127 3 : });
128 :
129 : // 构造Doorbell并返回
130 2 : rdmaOps_->BuildDoorbell(dbAddr, dbValue);
131 :
132 6 : HCCL_INFO(
133 : "[RdmaConnLiteV2::%s] Read end, dbAddr = %llu, dbValue = %llu, conn[%s]", __func__, dbAddr, dbValue,
134 : Describe().c_str());
135 2 : }
136 :
137 2 : void RdmaConnLiteV2::Write(
138 : const RmaBufSliceLite& loc, const RmtRmaBufSliceLite& rmt, const SqeConfigLite& cfg, u64& dbAddr, u64& dbValue)
139 : {
140 6 : HCCL_INFO("[RdmaConnLiteV2::%s] Write start, loc size = %u", __func__, loc.GetSize());
141 2 : CheckVendorOp();
142 :
143 : // 分片操作
144 2 : DoSlice(loc, rmt, [this, &cfg](const RmaBufSliceLite& locSlice, const RmtRmaBufSliceLite& rmtSlice) {
145 3 : rdmaOps_->Write(locSlice, rmtSlice, cfg);
146 3 : });
147 :
148 : // 构造Doorbell并返回
149 2 : rdmaOps_->BuildDoorbell(dbAddr, dbValue);
150 :
151 6 : HCCL_INFO(
152 : "[RdmaConnLiteV2::%s] Write end, dbAddr = 0x%llx, dbValue = 0x%llx, conn[%s]", __func__, dbAddr, dbValue,
153 : Describe().c_str());
154 2 : }
155 :
156 1 : void RdmaConnLiteV2::WriteReduce(
157 : const RmaBufSliceLite& loc, const RmtRmaBufSliceLite& rmt, const SqeConfigLite& cfg, DataType dataType,
158 : ReduceOp reduceOp, u64& dbAddr, u64& dbValue)
159 : {
160 3 : HCCL_INFO("[RdmaConnLiteV2::%s] WriteReduce start, loc size = %u", __func__, loc.GetSize());
161 1 : CheckVendorOp();
162 :
163 : // 分片操作
164 1 : DoSlice(
165 : loc, rmt,
166 1 : [this, &cfg, dataType, reduceOp](const RmaBufSliceLite& locSlice, const RmtRmaBufSliceLite& rmtSlice) {
167 1 : rdmaOps_->WriteReduce(locSlice, rmtSlice, cfg, dataType, reduceOp);
168 1 : });
169 :
170 : // 构造Doorbell并返回
171 1 : rdmaOps_->BuildDoorbell(dbAddr, dbValue);
172 :
173 3 : HCCL_INFO(
174 : "[RdmaConnLiteV2::%s] WriteReduce end, dbAddr = %llu, dbValue = %llu, conn[%s]", __func__, dbAddr, dbValue,
175 : Describe().c_str());
176 1 : }
177 :
178 1 : void RdmaConnLiteV2::WriteWithNotify(
179 : const RmaBufSliceLite& loc, const RmtRmaBufSliceLite& rmt, const RmaBufSliceLite& locNotify,
180 : const RmtRmaBufSliceLite& notify, const SqeConfigLite& cfg, u64& dbAddr, u64& dbValue)
181 : {
182 3 : HCCL_INFO("[RdmaConnLiteV2::%s] WriteWithNotify start, loc size = %u", __func__, loc.GetSize());
183 1 : CheckVendorOp();
184 :
185 : // 分片操作
186 1 : DoSlice(loc, rmt, [this, &cfg](const RmaBufSliceLite& locSlice, const RmtRmaBufSliceLite& rmtSlice) {
187 1 : rdmaOps_->Write(locSlice, rmtSlice, cfg);
188 1 : });
189 :
190 : // 补充一个notify操作
191 1 : rdmaOps_->Write(locNotify, notify, cfg);
192 :
193 : // 构造Doorbell并返回
194 1 : rdmaOps_->BuildDoorbell(dbAddr, dbValue);
195 :
196 3 : HCCL_INFO(
197 : "[RdmaConnLiteV2::%s] WriteWithNotify end, dbAddr = %llu, dbValue = %llu, conn[%s]", __func__, dbAddr, dbValue,
198 : Describe().c_str());
199 1 : }
200 :
201 1 : void RdmaConnLiteV2::WriteReduceWithNotify(
202 : const RmaBufSliceLite& loc, const RmtRmaBufSliceLite& rmt, const RmaBufSliceLite& locNotify,
203 : const RmtRmaBufSliceLite& notify, const SqeConfigLite& cfg, DataType dataType, ReduceOp reduceOp, u64& dbAddr,
204 : u64& dbValue)
205 : {
206 3 : HCCL_INFO("[RdmaConnLiteV2::%s] WriteReduceWithNotify start, loc size = %u", __func__, loc.GetSize());
207 1 : CheckVendorOp();
208 :
209 : // 分片操作
210 1 : DoSlice(
211 : loc, rmt,
212 1 : [this, &cfg, dataType, reduceOp](const RmaBufSliceLite& locSlice, const RmtRmaBufSliceLite& rmtSlice) {
213 1 : rdmaOps_->WriteReduce(locSlice, rmtSlice, cfg, dataType, reduceOp);
214 1 : });
215 :
216 : // 补充一个notify操作
217 1 : rdmaOps_->Write(locNotify, notify, cfg);
218 :
219 : // 构造Doorbell并返回
220 1 : rdmaOps_->BuildDoorbell(dbAddr, dbValue);
221 :
222 3 : HCCL_INFO(
223 : "[RdmaConnLiteV2::%s] WriteReduceWithNotify end, dbAddr = %llu, dbValue = %llu, conn[%s]", __func__, dbAddr,
224 : dbValue, Describe().c_str());
225 1 : }
226 :
227 7 : void RdmaConnLiteV2::DoSlice(
228 : const RmaBufSliceLite& loc, const RmtRmaBufSliceLite& rmt,
229 : const std::function<void(const RmaBufSliceLite&, const RmtRmaBufSliceLite&)>& op) const
230 : {
231 7 : const u64 len = loc.GetSize();
232 7 : const u32 fullSlices = static_cast<u32>(len / RDMA_DMA_MAX_SIZE);
233 7 : const u32 remain = static_cast<u32>(len % RDMA_DMA_MAX_SIZE);
234 7 : const u32 totalSlices = fullSlices + (remain > 0 ? 1 : 0);
235 :
236 16 : for (u32 sliceIdx = 0; sliceIdx < totalSlices; sliceIdx++) {
237 9 : const u64 offset = static_cast<u64>(sliceIdx) * RDMA_DMA_MAX_SIZE;
238 9 : const u64 localAddr = loc.GetAddr() + offset;
239 9 : const u64 remoteAddr = rmt.GetAddr() + offset;
240 9 : const u32 sliceSize = (sliceIdx == totalSlices - 1 && remain > 0) ? remain : RDMA_DMA_MAX_SIZE;
241 :
242 9 : RmaBufSliceLite locSlice(localAddr, sliceSize, loc.GetLkey(), 0);
243 9 : RmtRmaBufSliceLite rmtSlice(remoteAddr, sliceSize, rmt.GetRkey(), 0, 0, UINT32_MAX);
244 :
245 27 : HCCL_INFO(
246 : "[RdmaConnLiteV2::%s] Slice[%u]: offset=0x%llx, localAddr=0x%llx, "
247 : "remoteAddr=0x%llx, size=0x%x",
248 : __func__, sliceIdx, offset, localAddr, remoteAddr, sliceSize);
249 :
250 9 : op(locSlice, rmtSlice);
251 : }
252 7 : }
253 :
254 : HcclResult
255 3 : RdmaConnLiteV2::PollCq(int32_t numEntries, int32_t timeOut, std::vector<int32_t>& errList, u64& dbAddr, u64& dbValue)
256 : {
257 3 : HcclResult ret = HCCL_SUCCESS;
258 :
259 : // Poll numEntries个Cqe, 只返回异常的status
260 3 : ret = rdmaOps_->PollCq(numEntries, timeOut, errList);
261 :
262 : // Build And Ring Cq Soft DB
263 3 : rdmaOps_->BuildCqDoorbell(dbAddr, dbValue);
264 :
265 : // 返回前构造cq DB
266 3 : if (ret != HCCL_SUCCESS) {
267 6 : HCCL_ERROR("[RdmaConnLiteV2::%s] PollCq error, error code: %u", __func__, ret);
268 2 : return ret;
269 : }
270 1 : return HCCL_SUCCESS;
271 : }
272 :
273 : } // namespace Hccl
|