]>
Commit | Line | Data |
---|---|---|
029e88fd LR |
1 | // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
2 | /* | |
3 | * Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. | |
4 | */ | |
5 | ||
6 | #include <linux/gfp.h> | |
7 | #include <linux/mlx5/qp.h> | |
8 | #include <linux/mlx5/driver.h> | |
9 | #include "wr.h" | |
10 | ||
11 | static const u32 mlx5_ib_opcode[] = { | |
12 | [IB_WR_SEND] = MLX5_OPCODE_SEND, | |
13 | [IB_WR_LSO] = MLX5_OPCODE_LSO, | |
14 | [IB_WR_SEND_WITH_IMM] = MLX5_OPCODE_SEND_IMM, | |
15 | [IB_WR_RDMA_WRITE] = MLX5_OPCODE_RDMA_WRITE, | |
16 | [IB_WR_RDMA_WRITE_WITH_IMM] = MLX5_OPCODE_RDMA_WRITE_IMM, | |
17 | [IB_WR_RDMA_READ] = MLX5_OPCODE_RDMA_READ, | |
18 | [IB_WR_ATOMIC_CMP_AND_SWP] = MLX5_OPCODE_ATOMIC_CS, | |
19 | [IB_WR_ATOMIC_FETCH_AND_ADD] = MLX5_OPCODE_ATOMIC_FA, | |
20 | [IB_WR_SEND_WITH_INV] = MLX5_OPCODE_SEND_INVAL, | |
21 | [IB_WR_LOCAL_INV] = MLX5_OPCODE_UMR, | |
22 | [IB_WR_REG_MR] = MLX5_OPCODE_UMR, | |
23 | [IB_WR_MASKED_ATOMIC_CMP_AND_SWP] = MLX5_OPCODE_ATOMIC_MASKED_CS, | |
24 | [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD] = MLX5_OPCODE_ATOMIC_MASKED_FA, | |
25 | [MLX5_IB_WR_UMR] = MLX5_OPCODE_UMR, | |
26 | }; | |
27 | ||
28 | /* handle_post_send_edge - Check if we get to SQ edge. If yes, update to the | |
29 | * next nearby edge and get new address translation for current WQE position. | |
30 | * @sq - SQ buffer. | |
31 | * @seg: Current WQE position (16B aligned). | |
32 | * @wqe_sz: Total current WQE size [16B]. | |
33 | * @cur_edge: Updated current edge. | |
34 | */ | |
35 | static inline void handle_post_send_edge(struct mlx5_ib_wq *sq, void **seg, | |
36 | u32 wqe_sz, void **cur_edge) | |
37 | { | |
38 | u32 idx; | |
39 | ||
40 | if (likely(*seg != *cur_edge)) | |
41 | return; | |
42 | ||
43 | idx = (sq->cur_post + (wqe_sz >> 2)) & (sq->wqe_cnt - 1); | |
44 | *cur_edge = get_sq_edge(sq, idx); | |
45 | ||
46 | *seg = mlx5_frag_buf_get_wqe(&sq->fbc, idx); | |
47 | } | |
48 | ||
49 | /* memcpy_send_wqe - copy data from src to WQE and update the relevant WQ's | |
50 | * pointers. At the end @seg is aligned to 16B regardless the copied size. | |
51 | * @sq - SQ buffer. | |
52 | * @cur_edge: Updated current edge. | |
53 | * @seg: Current WQE position (16B aligned). | |
54 | * @wqe_sz: Total current WQE size [16B]. | |
55 | * @src: Pointer to copy from. | |
56 | * @n: Number of bytes to copy. | |
57 | */ | |
58 | static inline void memcpy_send_wqe(struct mlx5_ib_wq *sq, void **cur_edge, | |
59 | void **seg, u32 *wqe_sz, const void *src, | |
60 | size_t n) | |
61 | { | |
62 | while (likely(n)) { | |
63 | size_t leftlen = *cur_edge - *seg; | |
64 | size_t copysz = min_t(size_t, leftlen, n); | |
65 | size_t stride; | |
66 | ||
67 | memcpy(*seg, src, copysz); | |
68 | ||
69 | n -= copysz; | |
70 | src += copysz; | |
71 | stride = !n ? ALIGN(copysz, 16) : copysz; | |
72 | *seg += stride; | |
73 | *wqe_sz += stride >> 4; | |
74 | handle_post_send_edge(sq, seg, *wqe_sz, cur_edge); | |
75 | } | |
76 | } | |
77 | ||
78 | static int mlx5_wq_overflow(struct mlx5_ib_wq *wq, int nreq, | |
79 | struct ib_cq *ib_cq) | |
80 | { | |
81 | struct mlx5_ib_cq *cq; | |
82 | unsigned int cur; | |
83 | ||
84 | cur = wq->head - wq->tail; | |
85 | if (likely(cur + nreq < wq->max_post)) | |
86 | return 0; | |
87 | ||
88 | cq = to_mcq(ib_cq); | |
89 | spin_lock(&cq->lock); | |
90 | cur = wq->head - wq->tail; | |
91 | spin_unlock(&cq->lock); | |
92 | ||
93 | return cur + nreq >= wq->max_post; | |
94 | } | |
95 | ||
96 | static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg, | |
97 | u64 remote_addr, u32 rkey) | |
98 | { | |
99 | rseg->raddr = cpu_to_be64(remote_addr); | |
100 | rseg->rkey = cpu_to_be32(rkey); | |
101 | rseg->reserved = 0; | |
102 | } | |
103 | ||
104 | static void set_eth_seg(const struct ib_send_wr *wr, struct mlx5_ib_qp *qp, | |
105 | void **seg, int *size, void **cur_edge) | |
106 | { | |
107 | struct mlx5_wqe_eth_seg *eseg = *seg; | |
108 | ||
109 | memset(eseg, 0, sizeof(struct mlx5_wqe_eth_seg)); | |
110 | ||
111 | if (wr->send_flags & IB_SEND_IP_CSUM) | |
112 | eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM | | |
113 | MLX5_ETH_WQE_L4_CSUM; | |
114 | ||
115 | if (wr->opcode == IB_WR_LSO) { | |
116 | struct ib_ud_wr *ud_wr = container_of(wr, struct ib_ud_wr, wr); | |
117 | size_t left, copysz; | |
118 | void *pdata = ud_wr->header; | |
119 | size_t stride; | |
120 | ||
121 | left = ud_wr->hlen; | |
122 | eseg->mss = cpu_to_be16(ud_wr->mss); | |
123 | eseg->inline_hdr.sz = cpu_to_be16(left); | |
124 | ||
125 | /* memcpy_send_wqe should get a 16B align address. Hence, we | |
126 | * first copy up to the current edge and then, if needed, | |
127 | * continue to memcpy_send_wqe. | |
128 | */ | |
129 | copysz = min_t(u64, *cur_edge - (void *)eseg->inline_hdr.start, | |
130 | left); | |
131 | memcpy(eseg->inline_hdr.start, pdata, copysz); | |
132 | stride = ALIGN(sizeof(struct mlx5_wqe_eth_seg) - | |
133 | sizeof(eseg->inline_hdr.start) + copysz, 16); | |
134 | *size += stride / 16; | |
135 | *seg += stride; | |
136 | ||
137 | if (copysz < left) { | |
138 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
139 | left -= copysz; | |
140 | pdata += copysz; | |
141 | memcpy_send_wqe(&qp->sq, cur_edge, seg, size, pdata, | |
142 | left); | |
143 | } | |
144 | ||
145 | return; | |
146 | } | |
147 | ||
148 | *seg += sizeof(struct mlx5_wqe_eth_seg); | |
149 | *size += sizeof(struct mlx5_wqe_eth_seg) / 16; | |
150 | } | |
151 | ||
152 | static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg, | |
153 | const struct ib_send_wr *wr) | |
154 | { | |
155 | memcpy(&dseg->av, &to_mah(ud_wr(wr)->ah)->av, sizeof(struct mlx5_av)); | |
156 | dseg->av.dqp_dct = | |
157 | cpu_to_be32(ud_wr(wr)->remote_qpn | MLX5_EXTENDED_UD_AV); | |
158 | dseg->av.key.qkey.qkey = cpu_to_be32(ud_wr(wr)->remote_qkey); | |
159 | } | |
160 | ||
161 | static void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ib_sge *sg) | |
162 | { | |
163 | dseg->byte_count = cpu_to_be32(sg->length); | |
164 | dseg->lkey = cpu_to_be32(sg->lkey); | |
165 | dseg->addr = cpu_to_be64(sg->addr); | |
166 | } | |
167 | ||
168 | static u64 get_xlt_octo(u64 bytes) | |
169 | { | |
170 | return ALIGN(bytes, MLX5_IB_UMR_XLT_ALIGNMENT) / | |
171 | MLX5_IB_UMR_OCTOWORD; | |
172 | } | |
173 | ||
174 | static __be64 frwr_mkey_mask(bool atomic) | |
175 | { | |
176 | u64 result; | |
177 | ||
178 | result = MLX5_MKEY_MASK_LEN | | |
179 | MLX5_MKEY_MASK_PAGE_SIZE | | |
180 | MLX5_MKEY_MASK_START_ADDR | | |
181 | MLX5_MKEY_MASK_EN_RINVAL | | |
182 | MLX5_MKEY_MASK_KEY | | |
183 | MLX5_MKEY_MASK_LR | | |
184 | MLX5_MKEY_MASK_LW | | |
185 | MLX5_MKEY_MASK_RR | | |
186 | MLX5_MKEY_MASK_RW | | |
187 | MLX5_MKEY_MASK_SMALL_FENCE | | |
188 | MLX5_MKEY_MASK_FREE; | |
189 | ||
190 | if (atomic) | |
191 | result |= MLX5_MKEY_MASK_A; | |
192 | ||
193 | return cpu_to_be64(result); | |
194 | } | |
195 | ||
196 | static __be64 sig_mkey_mask(void) | |
197 | { | |
198 | u64 result; | |
199 | ||
200 | result = MLX5_MKEY_MASK_LEN | | |
201 | MLX5_MKEY_MASK_PAGE_SIZE | | |
202 | MLX5_MKEY_MASK_START_ADDR | | |
203 | MLX5_MKEY_MASK_EN_SIGERR | | |
204 | MLX5_MKEY_MASK_EN_RINVAL | | |
205 | MLX5_MKEY_MASK_KEY | | |
206 | MLX5_MKEY_MASK_LR | | |
207 | MLX5_MKEY_MASK_LW | | |
208 | MLX5_MKEY_MASK_RR | | |
209 | MLX5_MKEY_MASK_RW | | |
210 | MLX5_MKEY_MASK_SMALL_FENCE | | |
211 | MLX5_MKEY_MASK_FREE | | |
212 | MLX5_MKEY_MASK_BSF_EN; | |
213 | ||
214 | return cpu_to_be64(result); | |
215 | } | |
216 | ||
217 | static void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr, | |
218 | struct mlx5_ib_mr *mr, u8 flags, bool atomic) | |
219 | { | |
220 | int size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size; | |
221 | ||
222 | memset(umr, 0, sizeof(*umr)); | |
223 | ||
224 | umr->flags = flags; | |
225 | umr->xlt_octowords = cpu_to_be16(get_xlt_octo(size)); | |
226 | umr->mkey_mask = frwr_mkey_mask(atomic); | |
227 | } | |
228 | ||
229 | static void set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr) | |
230 | { | |
231 | memset(umr, 0, sizeof(*umr)); | |
232 | umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE); | |
233 | umr->flags = MLX5_UMR_INLINE; | |
234 | } | |
235 | ||
236 | static __be64 get_umr_enable_mr_mask(void) | |
237 | { | |
238 | u64 result; | |
239 | ||
240 | result = MLX5_MKEY_MASK_KEY | | |
241 | MLX5_MKEY_MASK_FREE; | |
242 | ||
243 | return cpu_to_be64(result); | |
244 | } | |
245 | ||
246 | static __be64 get_umr_disable_mr_mask(void) | |
247 | { | |
248 | u64 result; | |
249 | ||
250 | result = MLX5_MKEY_MASK_FREE; | |
251 | ||
252 | return cpu_to_be64(result); | |
253 | } | |
254 | ||
255 | static __be64 get_umr_update_translation_mask(void) | |
256 | { | |
257 | u64 result; | |
258 | ||
259 | result = MLX5_MKEY_MASK_LEN | | |
260 | MLX5_MKEY_MASK_PAGE_SIZE | | |
261 | MLX5_MKEY_MASK_START_ADDR; | |
262 | ||
263 | return cpu_to_be64(result); | |
264 | } | |
265 | ||
266 | static __be64 get_umr_update_access_mask(int atomic) | |
267 | { | |
268 | u64 result; | |
269 | ||
270 | result = MLX5_MKEY_MASK_LR | | |
271 | MLX5_MKEY_MASK_LW | | |
272 | MLX5_MKEY_MASK_RR | | |
273 | MLX5_MKEY_MASK_RW; | |
274 | ||
275 | if (atomic) | |
276 | result |= MLX5_MKEY_MASK_A; | |
277 | ||
278 | return cpu_to_be64(result); | |
279 | } | |
280 | ||
281 | static __be64 get_umr_update_pd_mask(void) | |
282 | { | |
283 | u64 result; | |
284 | ||
285 | result = MLX5_MKEY_MASK_PD; | |
286 | ||
287 | return cpu_to_be64(result); | |
288 | } | |
289 | ||
290 | static int umr_check_mkey_mask(struct mlx5_ib_dev *dev, u64 mask) | |
291 | { | |
292 | if ((mask & MLX5_MKEY_MASK_PAGE_SIZE && | |
293 | MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled)) || | |
294 | (mask & MLX5_MKEY_MASK_A && | |
295 | MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled))) | |
296 | return -EPERM; | |
297 | return 0; | |
298 | } | |
299 | ||
300 | static int set_reg_umr_segment(struct mlx5_ib_dev *dev, | |
301 | struct mlx5_wqe_umr_ctrl_seg *umr, | |
302 | const struct ib_send_wr *wr, int atomic) | |
303 | { | |
304 | const struct mlx5_umr_wr *umrwr = umr_wr(wr); | |
305 | ||
306 | memset(umr, 0, sizeof(*umr)); | |
307 | ||
308 | if (!umrwr->ignore_free_state) { | |
309 | if (wr->send_flags & MLX5_IB_SEND_UMR_FAIL_IF_FREE) | |
310 | /* fail if free */ | |
311 | umr->flags = MLX5_UMR_CHECK_FREE; | |
312 | else | |
313 | /* fail if not free */ | |
314 | umr->flags = MLX5_UMR_CHECK_NOT_FREE; | |
315 | } | |
316 | ||
317 | umr->xlt_octowords = cpu_to_be16(get_xlt_octo(umrwr->xlt_size)); | |
318 | if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_XLT) { | |
319 | u64 offset = get_xlt_octo(umrwr->offset); | |
320 | ||
321 | umr->xlt_offset = cpu_to_be16(offset & 0xffff); | |
322 | umr->xlt_offset_47_16 = cpu_to_be32(offset >> 16); | |
323 | umr->flags |= MLX5_UMR_TRANSLATION_OFFSET_EN; | |
324 | } | |
325 | if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_TRANSLATION) | |
326 | umr->mkey_mask |= get_umr_update_translation_mask(); | |
327 | if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_PD_ACCESS) { | |
328 | umr->mkey_mask |= get_umr_update_access_mask(atomic); | |
329 | umr->mkey_mask |= get_umr_update_pd_mask(); | |
330 | } | |
331 | if (wr->send_flags & MLX5_IB_SEND_UMR_ENABLE_MR) | |
332 | umr->mkey_mask |= get_umr_enable_mr_mask(); | |
333 | if (wr->send_flags & MLX5_IB_SEND_UMR_DISABLE_MR) | |
334 | umr->mkey_mask |= get_umr_disable_mr_mask(); | |
335 | ||
336 | if (!wr->num_sge) | |
337 | umr->flags |= MLX5_UMR_INLINE; | |
338 | ||
339 | return umr_check_mkey_mask(dev, be64_to_cpu(umr->mkey_mask)); | |
340 | } | |
341 | ||
342 | static u8 get_umr_flags(int acc) | |
343 | { | |
344 | return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC : 0) | | |
345 | (acc & IB_ACCESS_REMOTE_WRITE ? MLX5_PERM_REMOTE_WRITE : 0) | | |
346 | (acc & IB_ACCESS_REMOTE_READ ? MLX5_PERM_REMOTE_READ : 0) | | |
347 | (acc & IB_ACCESS_LOCAL_WRITE ? MLX5_PERM_LOCAL_WRITE : 0) | | |
348 | MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN; | |
349 | } | |
350 | ||
351 | static void set_reg_mkey_seg(struct mlx5_mkey_seg *seg, | |
352 | struct mlx5_ib_mr *mr, | |
353 | u32 key, int access) | |
354 | { | |
355 | int ndescs = ALIGN(mr->ndescs + mr->meta_ndescs, 8) >> 1; | |
356 | ||
357 | memset(seg, 0, sizeof(*seg)); | |
358 | ||
359 | if (mr->access_mode == MLX5_MKC_ACCESS_MODE_MTT) | |
360 | seg->log2_page_size = ilog2(mr->ibmr.page_size); | |
361 | else if (mr->access_mode == MLX5_MKC_ACCESS_MODE_KLMS) | |
362 | /* KLMs take twice the size of MTTs */ | |
363 | ndescs *= 2; | |
364 | ||
365 | seg->flags = get_umr_flags(access) | mr->access_mode; | |
366 | seg->qpn_mkey7_0 = cpu_to_be32((key & 0xff) | 0xffffff00); | |
367 | seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL); | |
368 | seg->start_addr = cpu_to_be64(mr->ibmr.iova); | |
369 | seg->len = cpu_to_be64(mr->ibmr.length); | |
370 | seg->xlt_oct_size = cpu_to_be32(ndescs); | |
371 | } | |
372 | ||
373 | static void set_linv_mkey_seg(struct mlx5_mkey_seg *seg) | |
374 | { | |
375 | memset(seg, 0, sizeof(*seg)); | |
376 | seg->status = MLX5_MKEY_STATUS_FREE; | |
377 | } | |
378 | ||
379 | static void set_reg_mkey_segment(struct mlx5_mkey_seg *seg, | |
380 | const struct ib_send_wr *wr) | |
381 | { | |
382 | const struct mlx5_umr_wr *umrwr = umr_wr(wr); | |
383 | ||
384 | memset(seg, 0, sizeof(*seg)); | |
385 | if (wr->send_flags & MLX5_IB_SEND_UMR_DISABLE_MR) | |
386 | seg->status = MLX5_MKEY_STATUS_FREE; | |
387 | ||
388 | seg->flags = convert_access(umrwr->access_flags); | |
389 | if (umrwr->pd) | |
390 | seg->flags_pd = cpu_to_be32(to_mpd(umrwr->pd)->pdn); | |
391 | if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_TRANSLATION && | |
392 | !umrwr->length) | |
393 | seg->flags_pd |= cpu_to_be32(MLX5_MKEY_LEN64); | |
394 | ||
395 | seg->start_addr = cpu_to_be64(umrwr->virt_addr); | |
396 | seg->len = cpu_to_be64(umrwr->length); | |
397 | seg->log2_page_size = umrwr->page_shift; | |
398 | seg->qpn_mkey7_0 = cpu_to_be32(0xffffff00 | | |
399 | mlx5_mkey_variant(umrwr->mkey)); | |
400 | } | |
401 | ||
402 | static void set_reg_data_seg(struct mlx5_wqe_data_seg *dseg, | |
403 | struct mlx5_ib_mr *mr, | |
404 | struct mlx5_ib_pd *pd) | |
405 | { | |
406 | int bcount = mr->desc_size * (mr->ndescs + mr->meta_ndescs); | |
407 | ||
408 | dseg->addr = cpu_to_be64(mr->desc_map); | |
409 | dseg->byte_count = cpu_to_be32(ALIGN(bcount, 64)); | |
410 | dseg->lkey = cpu_to_be32(pd->ibpd.local_dma_lkey); | |
411 | } | |
412 | ||
413 | static __be32 send_ieth(const struct ib_send_wr *wr) | |
414 | { | |
415 | switch (wr->opcode) { | |
416 | case IB_WR_SEND_WITH_IMM: | |
417 | case IB_WR_RDMA_WRITE_WITH_IMM: | |
418 | return wr->ex.imm_data; | |
419 | ||
420 | case IB_WR_SEND_WITH_INV: | |
421 | return cpu_to_be32(wr->ex.invalidate_rkey); | |
422 | ||
423 | default: | |
424 | return 0; | |
425 | } | |
426 | } | |
427 | ||
428 | static u8 calc_sig(void *wqe, int size) | |
429 | { | |
430 | u8 *p = wqe; | |
431 | u8 res = 0; | |
432 | int i; | |
433 | ||
434 | for (i = 0; i < size; i++) | |
435 | res ^= p[i]; | |
436 | ||
437 | return ~res; | |
438 | } | |
439 | ||
440 | static u8 wq_sig(void *wqe) | |
441 | { | |
442 | return calc_sig(wqe, (*((u8 *)wqe + 8) & 0x3f) << 4); | |
443 | } | |
444 | ||
445 | static int set_data_inl_seg(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr, | |
446 | void **wqe, int *wqe_sz, void **cur_edge) | |
447 | { | |
448 | struct mlx5_wqe_inline_seg *seg; | |
449 | size_t offset; | |
450 | int inl = 0; | |
451 | int i; | |
452 | ||
453 | seg = *wqe; | |
454 | *wqe += sizeof(*seg); | |
455 | offset = sizeof(*seg); | |
456 | ||
457 | for (i = 0; i < wr->num_sge; i++) { | |
458 | size_t len = wr->sg_list[i].length; | |
459 | void *addr = (void *)(unsigned long)(wr->sg_list[i].addr); | |
460 | ||
461 | inl += len; | |
462 | ||
463 | if (unlikely(inl > qp->max_inline_data)) | |
464 | return -ENOMEM; | |
465 | ||
466 | while (likely(len)) { | |
467 | size_t leftlen; | |
468 | size_t copysz; | |
469 | ||
470 | handle_post_send_edge(&qp->sq, wqe, | |
471 | *wqe_sz + (offset >> 4), | |
472 | cur_edge); | |
473 | ||
474 | leftlen = *cur_edge - *wqe; | |
475 | copysz = min_t(size_t, leftlen, len); | |
476 | ||
477 | memcpy(*wqe, addr, copysz); | |
478 | len -= copysz; | |
479 | addr += copysz; | |
480 | *wqe += copysz; | |
481 | offset += copysz; | |
482 | } | |
483 | } | |
484 | ||
485 | seg->byte_count = cpu_to_be32(inl | MLX5_INLINE_SEG); | |
486 | ||
487 | *wqe_sz += ALIGN(inl + sizeof(seg->byte_count), 16) / 16; | |
488 | ||
489 | return 0; | |
490 | } | |
491 | ||
492 | static u16 prot_field_size(enum ib_signature_type type) | |
493 | { | |
494 | switch (type) { | |
495 | case IB_SIG_TYPE_T10_DIF: | |
496 | return MLX5_DIF_SIZE; | |
497 | default: | |
498 | return 0; | |
499 | } | |
500 | } | |
501 | ||
502 | static u8 bs_selector(int block_size) | |
503 | { | |
504 | switch (block_size) { | |
505 | case 512: return 0x1; | |
506 | case 520: return 0x2; | |
507 | case 4096: return 0x3; | |
508 | case 4160: return 0x4; | |
509 | case 1073741824: return 0x5; | |
510 | default: return 0; | |
511 | } | |
512 | } | |
513 | ||
514 | static void mlx5_fill_inl_bsf(struct ib_sig_domain *domain, | |
515 | struct mlx5_bsf_inl *inl) | |
516 | { | |
517 | /* Valid inline section and allow BSF refresh */ | |
518 | inl->vld_refresh = cpu_to_be16(MLX5_BSF_INL_VALID | | |
519 | MLX5_BSF_REFRESH_DIF); | |
520 | inl->dif_apptag = cpu_to_be16(domain->sig.dif.app_tag); | |
521 | inl->dif_reftag = cpu_to_be32(domain->sig.dif.ref_tag); | |
522 | /* repeating block */ | |
523 | inl->rp_inv_seed = MLX5_BSF_REPEAT_BLOCK; | |
524 | inl->sig_type = domain->sig.dif.bg_type == IB_T10DIF_CRC ? | |
525 | MLX5_DIF_CRC : MLX5_DIF_IPCS; | |
526 | ||
527 | if (domain->sig.dif.ref_remap) | |
528 | inl->dif_inc_ref_guard_check |= MLX5_BSF_INC_REFTAG; | |
529 | ||
530 | if (domain->sig.dif.app_escape) { | |
531 | if (domain->sig.dif.ref_escape) | |
532 | inl->dif_inc_ref_guard_check |= MLX5_BSF_APPREF_ESCAPE; | |
533 | else | |
534 | inl->dif_inc_ref_guard_check |= MLX5_BSF_APPTAG_ESCAPE; | |
535 | } | |
536 | ||
537 | inl->dif_app_bitmask_check = | |
538 | cpu_to_be16(domain->sig.dif.apptag_check_mask); | |
539 | } | |
540 | ||
541 | static int mlx5_set_bsf(struct ib_mr *sig_mr, | |
542 | struct ib_sig_attrs *sig_attrs, | |
543 | struct mlx5_bsf *bsf, u32 data_size) | |
544 | { | |
545 | struct mlx5_core_sig_ctx *msig = to_mmr(sig_mr)->sig; | |
546 | struct mlx5_bsf_basic *basic = &bsf->basic; | |
547 | struct ib_sig_domain *mem = &sig_attrs->mem; | |
548 | struct ib_sig_domain *wire = &sig_attrs->wire; | |
549 | ||
550 | memset(bsf, 0, sizeof(*bsf)); | |
551 | ||
552 | /* Basic + Extended + Inline */ | |
553 | basic->bsf_size_sbs = 1 << 7; | |
554 | /* Input domain check byte mask */ | |
555 | basic->check_byte_mask = sig_attrs->check_mask; | |
556 | basic->raw_data_size = cpu_to_be32(data_size); | |
557 | ||
558 | /* Memory domain */ | |
559 | switch (sig_attrs->mem.sig_type) { | |
560 | case IB_SIG_TYPE_NONE: | |
561 | break; | |
562 | case IB_SIG_TYPE_T10_DIF: | |
563 | basic->mem.bs_selector = bs_selector(mem->sig.dif.pi_interval); | |
564 | basic->m_bfs_psv = cpu_to_be32(msig->psv_memory.psv_idx); | |
565 | mlx5_fill_inl_bsf(mem, &bsf->m_inl); | |
566 | break; | |
567 | default: | |
568 | return -EINVAL; | |
569 | } | |
570 | ||
571 | /* Wire domain */ | |
572 | switch (sig_attrs->wire.sig_type) { | |
573 | case IB_SIG_TYPE_NONE: | |
574 | break; | |
575 | case IB_SIG_TYPE_T10_DIF: | |
576 | if (mem->sig.dif.pi_interval == wire->sig.dif.pi_interval && | |
577 | mem->sig_type == wire->sig_type) { | |
578 | /* Same block structure */ | |
579 | basic->bsf_size_sbs |= 1 << 4; | |
580 | if (mem->sig.dif.bg_type == wire->sig.dif.bg_type) | |
581 | basic->wire.copy_byte_mask |= MLX5_CPY_GRD_MASK; | |
582 | if (mem->sig.dif.app_tag == wire->sig.dif.app_tag) | |
583 | basic->wire.copy_byte_mask |= MLX5_CPY_APP_MASK; | |
584 | if (mem->sig.dif.ref_tag == wire->sig.dif.ref_tag) | |
585 | basic->wire.copy_byte_mask |= MLX5_CPY_REF_MASK; | |
586 | } else | |
587 | basic->wire.bs_selector = | |
588 | bs_selector(wire->sig.dif.pi_interval); | |
589 | ||
590 | basic->w_bfs_psv = cpu_to_be32(msig->psv_wire.psv_idx); | |
591 | mlx5_fill_inl_bsf(wire, &bsf->w_inl); | |
592 | break; | |
593 | default: | |
594 | return -EINVAL; | |
595 | } | |
596 | ||
597 | return 0; | |
598 | } | |
599 | ||
600 | ||
601 | static int set_sig_data_segment(const struct ib_send_wr *send_wr, | |
602 | struct ib_mr *sig_mr, | |
603 | struct ib_sig_attrs *sig_attrs, | |
604 | struct mlx5_ib_qp *qp, void **seg, int *size, | |
605 | void **cur_edge) | |
606 | { | |
607 | struct mlx5_bsf *bsf; | |
608 | u32 data_len; | |
609 | u32 data_key; | |
610 | u64 data_va; | |
611 | u32 prot_len = 0; | |
612 | u32 prot_key = 0; | |
613 | u64 prot_va = 0; | |
614 | bool prot = false; | |
615 | int ret; | |
616 | int wqe_size; | |
617 | struct mlx5_ib_mr *mr = to_mmr(sig_mr); | |
618 | struct mlx5_ib_mr *pi_mr = mr->pi_mr; | |
619 | ||
620 | data_len = pi_mr->data_length; | |
621 | data_key = pi_mr->ibmr.lkey; | |
622 | data_va = pi_mr->data_iova; | |
623 | if (pi_mr->meta_ndescs) { | |
624 | prot_len = pi_mr->meta_length; | |
625 | prot_key = pi_mr->ibmr.lkey; | |
626 | prot_va = pi_mr->pi_iova; | |
627 | prot = true; | |
628 | } | |
629 | ||
630 | if (!prot || (data_key == prot_key && data_va == prot_va && | |
631 | data_len == prot_len)) { | |
632 | /** | |
633 | * Source domain doesn't contain signature information | |
634 | * or data and protection are interleaved in memory. | |
635 | * So need construct: | |
636 | * ------------------ | |
637 | * | data_klm | | |
638 | * ------------------ | |
639 | * | BSF | | |
640 | * ------------------ | |
641 | **/ | |
642 | struct mlx5_klm *data_klm = *seg; | |
643 | ||
644 | data_klm->bcount = cpu_to_be32(data_len); | |
645 | data_klm->key = cpu_to_be32(data_key); | |
646 | data_klm->va = cpu_to_be64(data_va); | |
647 | wqe_size = ALIGN(sizeof(*data_klm), 64); | |
648 | } else { | |
649 | /** | |
650 | * Source domain contains signature information | |
651 | * So need construct a strided block format: | |
652 | * --------------------------- | |
653 | * | stride_block_ctrl | | |
654 | * --------------------------- | |
655 | * | data_klm | | |
656 | * --------------------------- | |
657 | * | prot_klm | | |
658 | * --------------------------- | |
659 | * | BSF | | |
660 | * --------------------------- | |
661 | **/ | |
662 | struct mlx5_stride_block_ctrl_seg *sblock_ctrl; | |
663 | struct mlx5_stride_block_entry *data_sentry; | |
664 | struct mlx5_stride_block_entry *prot_sentry; | |
665 | u16 block_size = sig_attrs->mem.sig.dif.pi_interval; | |
666 | int prot_size; | |
667 | ||
668 | sblock_ctrl = *seg; | |
669 | data_sentry = (void *)sblock_ctrl + sizeof(*sblock_ctrl); | |
670 | prot_sentry = (void *)data_sentry + sizeof(*data_sentry); | |
671 | ||
672 | prot_size = prot_field_size(sig_attrs->mem.sig_type); | |
673 | if (!prot_size) { | |
674 | pr_err("Bad block size given: %u\n", block_size); | |
675 | return -EINVAL; | |
676 | } | |
677 | sblock_ctrl->bcount_per_cycle = cpu_to_be32(block_size + | |
678 | prot_size); | |
679 | sblock_ctrl->op = cpu_to_be32(MLX5_STRIDE_BLOCK_OP); | |
680 | sblock_ctrl->repeat_count = cpu_to_be32(data_len / block_size); | |
681 | sblock_ctrl->num_entries = cpu_to_be16(2); | |
682 | ||
683 | data_sentry->bcount = cpu_to_be16(block_size); | |
684 | data_sentry->key = cpu_to_be32(data_key); | |
685 | data_sentry->va = cpu_to_be64(data_va); | |
686 | data_sentry->stride = cpu_to_be16(block_size); | |
687 | ||
688 | prot_sentry->bcount = cpu_to_be16(prot_size); | |
689 | prot_sentry->key = cpu_to_be32(prot_key); | |
690 | prot_sentry->va = cpu_to_be64(prot_va); | |
691 | prot_sentry->stride = cpu_to_be16(prot_size); | |
692 | ||
693 | wqe_size = ALIGN(sizeof(*sblock_ctrl) + sizeof(*data_sentry) + | |
694 | sizeof(*prot_sentry), 64); | |
695 | } | |
696 | ||
697 | *seg += wqe_size; | |
698 | *size += wqe_size / 16; | |
699 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
700 | ||
701 | bsf = *seg; | |
702 | ret = mlx5_set_bsf(sig_mr, sig_attrs, bsf, data_len); | |
703 | if (ret) | |
704 | return -EINVAL; | |
705 | ||
706 | *seg += sizeof(*bsf); | |
707 | *size += sizeof(*bsf) / 16; | |
708 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
709 | ||
710 | return 0; | |
711 | } | |
712 | ||
713 | static void set_sig_mkey_segment(struct mlx5_mkey_seg *seg, | |
714 | struct ib_mr *sig_mr, int access_flags, | |
715 | u32 size, u32 length, u32 pdn) | |
716 | { | |
717 | u32 sig_key = sig_mr->rkey; | |
718 | u8 sigerr = to_mmr(sig_mr)->sig->sigerr_count & 1; | |
719 | ||
720 | memset(seg, 0, sizeof(*seg)); | |
721 | ||
722 | seg->flags = get_umr_flags(access_flags) | MLX5_MKC_ACCESS_MODE_KLMS; | |
723 | seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00); | |
724 | seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | sigerr << 26 | | |
725 | MLX5_MKEY_BSF_EN | pdn); | |
726 | seg->len = cpu_to_be64(length); | |
727 | seg->xlt_oct_size = cpu_to_be32(get_xlt_octo(size)); | |
728 | seg->bsfs_octo_size = cpu_to_be32(MLX5_MKEY_BSF_OCTO_SIZE); | |
729 | } | |
730 | ||
731 | static void set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr, | |
732 | u32 size) | |
733 | { | |
734 | memset(umr, 0, sizeof(*umr)); | |
735 | ||
736 | umr->flags = MLX5_FLAGS_INLINE | MLX5_FLAGS_CHECK_FREE; | |
737 | umr->xlt_octowords = cpu_to_be16(get_xlt_octo(size)); | |
738 | umr->bsf_octowords = cpu_to_be16(MLX5_MKEY_BSF_OCTO_SIZE); | |
739 | umr->mkey_mask = sig_mkey_mask(); | |
740 | } | |
741 | ||
742 | static int set_pi_umr_wr(const struct ib_send_wr *send_wr, | |
743 | struct mlx5_ib_qp *qp, void **seg, int *size, | |
744 | void **cur_edge) | |
745 | { | |
746 | const struct ib_reg_wr *wr = reg_wr(send_wr); | |
747 | struct mlx5_ib_mr *sig_mr = to_mmr(wr->mr); | |
748 | struct mlx5_ib_mr *pi_mr = sig_mr->pi_mr; | |
749 | struct ib_sig_attrs *sig_attrs = sig_mr->ibmr.sig_attrs; | |
750 | u32 pdn = to_mpd(qp->ibqp.pd)->pdn; | |
751 | u32 xlt_size; | |
752 | int region_len, ret; | |
753 | ||
754 | if (unlikely(send_wr->num_sge != 0) || | |
755 | unlikely(wr->access & IB_ACCESS_REMOTE_ATOMIC) || | |
756 | unlikely(!sig_mr->sig) || unlikely(!qp->ibqp.integrity_en) || | |
757 | unlikely(!sig_mr->sig->sig_status_checked)) | |
758 | return -EINVAL; | |
759 | ||
760 | /* length of the protected region, data + protection */ | |
761 | region_len = pi_mr->ibmr.length; | |
762 | ||
763 | /** | |
764 | * KLM octoword size - if protection was provided | |
765 | * then we use strided block format (3 octowords), | |
766 | * else we use single KLM (1 octoword) | |
767 | **/ | |
768 | if (sig_attrs->mem.sig_type != IB_SIG_TYPE_NONE) | |
769 | xlt_size = 0x30; | |
770 | else | |
771 | xlt_size = sizeof(struct mlx5_klm); | |
772 | ||
773 | set_sig_umr_segment(*seg, xlt_size); | |
774 | *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg); | |
775 | *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16; | |
776 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
777 | ||
778 | set_sig_mkey_segment(*seg, wr->mr, wr->access, xlt_size, region_len, | |
779 | pdn); | |
780 | *seg += sizeof(struct mlx5_mkey_seg); | |
781 | *size += sizeof(struct mlx5_mkey_seg) / 16; | |
782 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
783 | ||
784 | ret = set_sig_data_segment(send_wr, wr->mr, sig_attrs, qp, seg, size, | |
785 | cur_edge); | |
786 | if (ret) | |
787 | return ret; | |
788 | ||
789 | sig_mr->sig->sig_status_checked = false; | |
790 | return 0; | |
791 | } | |
792 | ||
793 | static int set_psv_wr(struct ib_sig_domain *domain, | |
794 | u32 psv_idx, void **seg, int *size) | |
795 | { | |
796 | struct mlx5_seg_set_psv *psv_seg = *seg; | |
797 | ||
798 | memset(psv_seg, 0, sizeof(*psv_seg)); | |
799 | psv_seg->psv_num = cpu_to_be32(psv_idx); | |
800 | switch (domain->sig_type) { | |
801 | case IB_SIG_TYPE_NONE: | |
802 | break; | |
803 | case IB_SIG_TYPE_T10_DIF: | |
804 | psv_seg->transient_sig = cpu_to_be32(domain->sig.dif.bg << 16 | | |
805 | domain->sig.dif.app_tag); | |
806 | psv_seg->ref_tag = cpu_to_be32(domain->sig.dif.ref_tag); | |
807 | break; | |
808 | default: | |
809 | pr_err("Bad signature type (%d) is given.\n", | |
810 | domain->sig_type); | |
811 | return -EINVAL; | |
812 | } | |
813 | ||
814 | *seg += sizeof(*psv_seg); | |
815 | *size += sizeof(*psv_seg) / 16; | |
816 | ||
817 | return 0; | |
818 | } | |
819 | ||
820 | static int set_reg_wr(struct mlx5_ib_qp *qp, | |
821 | const struct ib_reg_wr *wr, | |
822 | void **seg, int *size, void **cur_edge, | |
823 | bool check_not_free) | |
824 | { | |
825 | struct mlx5_ib_mr *mr = to_mmr(wr->mr); | |
826 | struct mlx5_ib_pd *pd = to_mpd(qp->ibqp.pd); | |
827 | struct mlx5_ib_dev *dev = to_mdev(pd->ibpd.device); | |
828 | int mr_list_size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size; | |
829 | bool umr_inline = mr_list_size <= MLX5_IB_SQ_UMR_INLINE_THRESHOLD; | |
830 | bool atomic = wr->access & IB_ACCESS_REMOTE_ATOMIC; | |
831 | u8 flags = 0; | |
832 | ||
833 | if (!mlx5_ib_can_use_umr(dev, atomic, wr->access)) { | |
834 | mlx5_ib_warn(to_mdev(qp->ibqp.device), | |
835 | "Fast update of %s for MR is disabled\n", | |
836 | (MLX5_CAP_GEN(dev->mdev, | |
837 | umr_modify_entity_size_disabled)) ? | |
838 | "entity size" : | |
839 | "atomic access"); | |
840 | return -EINVAL; | |
841 | } | |
842 | ||
843 | if (unlikely(wr->wr.send_flags & IB_SEND_INLINE)) { | |
844 | mlx5_ib_warn(to_mdev(qp->ibqp.device), | |
845 | "Invalid IB_SEND_INLINE send flag\n"); | |
846 | return -EINVAL; | |
847 | } | |
848 | ||
849 | if (check_not_free) | |
850 | flags |= MLX5_UMR_CHECK_NOT_FREE; | |
851 | if (umr_inline) | |
852 | flags |= MLX5_UMR_INLINE; | |
853 | ||
854 | set_reg_umr_seg(*seg, mr, flags, atomic); | |
855 | *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg); | |
856 | *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16; | |
857 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
858 | ||
859 | set_reg_mkey_seg(*seg, mr, wr->key, wr->access); | |
860 | *seg += sizeof(struct mlx5_mkey_seg); | |
861 | *size += sizeof(struct mlx5_mkey_seg) / 16; | |
862 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
863 | ||
864 | if (umr_inline) { | |
865 | memcpy_send_wqe(&qp->sq, cur_edge, seg, size, mr->descs, | |
866 | mr_list_size); | |
867 | *size = ALIGN(*size, MLX5_SEND_WQE_BB >> 4); | |
868 | } else { | |
869 | set_reg_data_seg(*seg, mr, pd); | |
870 | *seg += sizeof(struct mlx5_wqe_data_seg); | |
871 | *size += (sizeof(struct mlx5_wqe_data_seg) / 16); | |
872 | } | |
873 | return 0; | |
874 | } | |
875 | ||
876 | static void set_linv_wr(struct mlx5_ib_qp *qp, void **seg, int *size, | |
877 | void **cur_edge) | |
878 | { | |
879 | set_linv_umr_seg(*seg); | |
880 | *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg); | |
881 | *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16; | |
882 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
883 | set_linv_mkey_seg(*seg); | |
884 | *seg += sizeof(struct mlx5_mkey_seg); | |
885 | *size += sizeof(struct mlx5_mkey_seg) / 16; | |
886 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
887 | } | |
888 | ||
889 | static void dump_wqe(struct mlx5_ib_qp *qp, u32 idx, int size_16) | |
890 | { | |
891 | __be32 *p = NULL; | |
892 | int i, j; | |
893 | ||
894 | pr_debug("dump WQE index %u:\n", idx); | |
895 | for (i = 0, j = 0; i < size_16 * 4; i += 4, j += 4) { | |
896 | if ((i & 0xf) == 0) { | |
897 | p = mlx5_frag_buf_get_wqe(&qp->sq.fbc, idx); | |
898 | pr_debug("WQBB at %p:\n", (void *)p); | |
899 | j = 0; | |
900 | idx = (idx + 1) & (qp->sq.wqe_cnt - 1); | |
901 | } | |
902 | pr_debug("%08x %08x %08x %08x\n", be32_to_cpu(p[j]), | |
903 | be32_to_cpu(p[j + 1]), be32_to_cpu(p[j + 2]), | |
904 | be32_to_cpu(p[j + 3])); | |
905 | } | |
906 | } | |
907 | ||
908 | static int __begin_wqe(struct mlx5_ib_qp *qp, void **seg, | |
909 | struct mlx5_wqe_ctrl_seg **ctrl, | |
910 | const struct ib_send_wr *wr, unsigned int *idx, | |
911 | int *size, void **cur_edge, int nreq, | |
912 | bool send_signaled, bool solicited) | |
913 | { | |
914 | if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq))) | |
915 | return -ENOMEM; | |
916 | ||
917 | *idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1); | |
918 | *seg = mlx5_frag_buf_get_wqe(&qp->sq.fbc, *idx); | |
919 | *ctrl = *seg; | |
920 | *(uint32_t *)(*seg + 8) = 0; | |
921 | (*ctrl)->imm = send_ieth(wr); | |
922 | (*ctrl)->fm_ce_se = qp->sq_signal_bits | | |
923 | (send_signaled ? MLX5_WQE_CTRL_CQ_UPDATE : 0) | | |
924 | (solicited ? MLX5_WQE_CTRL_SOLICITED : 0); | |
925 | ||
926 | *seg += sizeof(**ctrl); | |
927 | *size = sizeof(**ctrl) / 16; | |
928 | *cur_edge = qp->sq.cur_edge; | |
929 | ||
930 | return 0; | |
931 | } | |
932 | ||
933 | static int begin_wqe(struct mlx5_ib_qp *qp, void **seg, | |
934 | struct mlx5_wqe_ctrl_seg **ctrl, | |
935 | const struct ib_send_wr *wr, unsigned int *idx, int *size, | |
936 | void **cur_edge, int nreq) | |
937 | { | |
938 | return __begin_wqe(qp, seg, ctrl, wr, idx, size, cur_edge, nreq, | |
939 | wr->send_flags & IB_SEND_SIGNALED, | |
940 | wr->send_flags & IB_SEND_SOLICITED); | |
941 | } | |
942 | ||
943 | static void finish_wqe(struct mlx5_ib_qp *qp, | |
944 | struct mlx5_wqe_ctrl_seg *ctrl, | |
945 | void *seg, u8 size, void *cur_edge, | |
946 | unsigned int idx, u64 wr_id, int nreq, u8 fence, | |
947 | u32 mlx5_opcode) | |
948 | { | |
949 | u8 opmod = 0; | |
950 | ||
951 | ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) | | |
952 | mlx5_opcode | ((u32)opmod << 24)); | |
953 | ctrl->qpn_ds = cpu_to_be32(size | (qp->trans_qp.base.mqp.qpn << 8)); | |
954 | ctrl->fm_ce_se |= fence; | |
955 | if (unlikely(qp->flags_en & MLX5_QP_FLAG_SIGNATURE)) | |
956 | ctrl->signature = wq_sig(ctrl); | |
957 | ||
958 | qp->sq.wrid[idx] = wr_id; | |
959 | qp->sq.w_list[idx].opcode = mlx5_opcode; | |
960 | qp->sq.wqe_head[idx] = qp->sq.head + nreq; | |
961 | qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB); | |
962 | qp->sq.w_list[idx].next = qp->sq.cur_post; | |
963 | ||
964 | /* We save the edge which was possibly updated during the WQE | |
965 | * construction, into SQ's cache. | |
966 | */ | |
967 | seg = PTR_ALIGN(seg, MLX5_SEND_WQE_BB); | |
968 | qp->sq.cur_edge = (unlikely(seg == cur_edge)) ? | |
969 | get_sq_edge(&qp->sq, qp->sq.cur_post & | |
970 | (qp->sq.wqe_cnt - 1)) : | |
971 | cur_edge; | |
972 | } | |
973 | ||
974 | static void handle_rdma_op(const struct ib_send_wr *wr, void **seg, int *size) | |
975 | { | |
976 | set_raddr_seg(*seg, rdma_wr(wr)->remote_addr, rdma_wr(wr)->rkey); | |
977 | *seg += sizeof(struct mlx5_wqe_raddr_seg); | |
978 | *size += sizeof(struct mlx5_wqe_raddr_seg) / 16; | |
979 | } | |
980 | ||
981 | static void handle_local_inv(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr, | |
982 | struct mlx5_wqe_ctrl_seg **ctrl, void **seg, | |
983 | int *size, void **cur_edge, unsigned int idx) | |
984 | { | |
985 | qp->sq.wr_data[idx] = IB_WR_LOCAL_INV; | |
986 | (*ctrl)->imm = cpu_to_be32(wr->ex.invalidate_rkey); | |
987 | set_linv_wr(qp, seg, size, cur_edge); | |
988 | } | |
989 | ||
990 | static int handle_reg_mr(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr, | |
991 | struct mlx5_wqe_ctrl_seg **ctrl, void **seg, int *size, | |
992 | void **cur_edge, unsigned int idx) | |
993 | { | |
994 | qp->sq.wr_data[idx] = IB_WR_REG_MR; | |
995 | (*ctrl)->imm = cpu_to_be32(reg_wr(wr)->key); | |
996 | return set_reg_wr(qp, reg_wr(wr), seg, size, cur_edge, true); | |
997 | } | |
998 | ||
999 | static int handle_psv(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, | |
1000 | const struct ib_send_wr *wr, | |
1001 | struct mlx5_wqe_ctrl_seg **ctrl, void **seg, int *size, | |
1002 | void **cur_edge, unsigned int *idx, int nreq, | |
1003 | struct ib_sig_domain *domain, u32 psv_index, | |
1004 | u8 next_fence) | |
1005 | { | |
1006 | int err; | |
1007 | ||
1008 | /* | |
1009 | * SET_PSV WQEs are not signaled and solicited on error. | |
1010 | */ | |
1011 | err = __begin_wqe(qp, seg, ctrl, wr, idx, size, cur_edge, nreq, | |
1012 | false, true); | |
1013 | if (unlikely(err)) { | |
1014 | mlx5_ib_warn(dev, "\n"); | |
1015 | err = -ENOMEM; | |
1016 | goto out; | |
1017 | } | |
1018 | err = set_psv_wr(domain, psv_index, seg, size); | |
1019 | if (unlikely(err)) { | |
1020 | mlx5_ib_warn(dev, "\n"); | |
1021 | goto out; | |
1022 | } | |
1023 | finish_wqe(qp, *ctrl, *seg, *size, *cur_edge, *idx, wr->wr_id, nreq, | |
1024 | next_fence, MLX5_OPCODE_SET_PSV); | |
1025 | ||
1026 | out: | |
1027 | return err; | |
1028 | } | |
1029 | ||
1030 | static int handle_reg_mr_integrity(struct mlx5_ib_dev *dev, | |
1031 | struct mlx5_ib_qp *qp, | |
1032 | const struct ib_send_wr *wr, | |
1033 | struct mlx5_wqe_ctrl_seg **ctrl, void **seg, | |
1034 | int *size, void **cur_edge, | |
1035 | unsigned int *idx, int nreq, u8 fence, | |
1036 | u8 next_fence) | |
1037 | { | |
1038 | struct mlx5_ib_mr *mr; | |
1039 | struct mlx5_ib_mr *pi_mr; | |
1040 | struct mlx5_ib_mr pa_pi_mr; | |
1041 | struct ib_sig_attrs *sig_attrs; | |
1042 | struct ib_reg_wr reg_pi_wr; | |
1043 | int err; | |
1044 | ||
1045 | qp->sq.wr_data[*idx] = IB_WR_REG_MR_INTEGRITY; | |
1046 | ||
1047 | mr = to_mmr(reg_wr(wr)->mr); | |
1048 | pi_mr = mr->pi_mr; | |
1049 | ||
1050 | if (pi_mr) { | |
1051 | memset(®_pi_wr, 0, | |
1052 | sizeof(struct ib_reg_wr)); | |
1053 | ||
1054 | reg_pi_wr.mr = &pi_mr->ibmr; | |
1055 | reg_pi_wr.access = reg_wr(wr)->access; | |
1056 | reg_pi_wr.key = pi_mr->ibmr.rkey; | |
1057 | ||
1058 | (*ctrl)->imm = cpu_to_be32(reg_pi_wr.key); | |
1059 | /* UMR for data + prot registration */ | |
1060 | err = set_reg_wr(qp, ®_pi_wr, seg, size, cur_edge, false); | |
1061 | if (unlikely(err)) | |
1062 | goto out; | |
1063 | ||
1064 | finish_wqe(qp, *ctrl, *seg, *size, *cur_edge, *idx, wr->wr_id, | |
1065 | nreq, fence, MLX5_OPCODE_UMR); | |
1066 | ||
1067 | err = begin_wqe(qp, seg, ctrl, wr, idx, size, cur_edge, nreq); | |
1068 | if (unlikely(err)) { | |
1069 | mlx5_ib_warn(dev, "\n"); | |
1070 | err = -ENOMEM; | |
1071 | goto out; | |
1072 | } | |
1073 | } else { | |
1074 | memset(&pa_pi_mr, 0, sizeof(struct mlx5_ib_mr)); | |
1075 | /* No UMR, use local_dma_lkey */ | |
1076 | pa_pi_mr.ibmr.lkey = mr->ibmr.pd->local_dma_lkey; | |
1077 | pa_pi_mr.ndescs = mr->ndescs; | |
1078 | pa_pi_mr.data_length = mr->data_length; | |
1079 | pa_pi_mr.data_iova = mr->data_iova; | |
1080 | if (mr->meta_ndescs) { | |
1081 | pa_pi_mr.meta_ndescs = mr->meta_ndescs; | |
1082 | pa_pi_mr.meta_length = mr->meta_length; | |
1083 | pa_pi_mr.pi_iova = mr->pi_iova; | |
1084 | } | |
1085 | ||
1086 | pa_pi_mr.ibmr.length = mr->ibmr.length; | |
1087 | mr->pi_mr = &pa_pi_mr; | |
1088 | } | |
1089 | (*ctrl)->imm = cpu_to_be32(mr->ibmr.rkey); | |
1090 | /* UMR for sig MR */ | |
1091 | err = set_pi_umr_wr(wr, qp, seg, size, cur_edge); | |
1092 | if (unlikely(err)) { | |
1093 | mlx5_ib_warn(dev, "\n"); | |
1094 | goto out; | |
1095 | } | |
1096 | finish_wqe(qp, *ctrl, *seg, *size, *cur_edge, *idx, wr->wr_id, nreq, | |
1097 | fence, MLX5_OPCODE_UMR); | |
1098 | ||
1099 | sig_attrs = mr->ibmr.sig_attrs; | |
1100 | err = handle_psv(dev, qp, wr, ctrl, seg, size, cur_edge, idx, nreq, | |
1101 | &sig_attrs->mem, mr->sig->psv_memory.psv_idx, | |
1102 | next_fence); | |
1103 | if (unlikely(err)) | |
1104 | goto out; | |
1105 | ||
1106 | err = handle_psv(dev, qp, wr, ctrl, seg, size, cur_edge, idx, nreq, | |
1107 | &sig_attrs->wire, mr->sig->psv_wire.psv_idx, | |
1108 | next_fence); | |
1109 | if (unlikely(err)) | |
1110 | goto out; | |
1111 | ||
1112 | qp->next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL; | |
1113 | ||
1114 | out: | |
1115 | return err; | |
1116 | } | |
1117 | ||
1118 | static int handle_qpt_rc(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, | |
1119 | const struct ib_send_wr *wr, | |
1120 | struct mlx5_wqe_ctrl_seg **ctrl, void **seg, int *size, | |
1121 | void **cur_edge, unsigned int *idx, int nreq, u8 fence, | |
1122 | u8 next_fence, int *num_sge) | |
1123 | { | |
1124 | int err = 0; | |
1125 | ||
1126 | switch (wr->opcode) { | |
1127 | case IB_WR_RDMA_READ: | |
1128 | case IB_WR_RDMA_WRITE: | |
1129 | case IB_WR_RDMA_WRITE_WITH_IMM: | |
1130 | handle_rdma_op(wr, seg, size); | |
1131 | break; | |
1132 | ||
1133 | case IB_WR_ATOMIC_CMP_AND_SWP: | |
1134 | case IB_WR_ATOMIC_FETCH_AND_ADD: | |
1135 | case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: | |
1136 | mlx5_ib_warn(dev, "Atomic operations are not supported yet\n"); | |
1137 | err = -EOPNOTSUPP; | |
1138 | goto out; | |
1139 | ||
1140 | case IB_WR_LOCAL_INV: | |
1141 | handle_local_inv(qp, wr, ctrl, seg, size, cur_edge, *idx); | |
1142 | *num_sge = 0; | |
1143 | break; | |
1144 | ||
1145 | case IB_WR_REG_MR: | |
1146 | err = handle_reg_mr(qp, wr, ctrl, seg, size, cur_edge, *idx); | |
1147 | if (unlikely(err)) | |
1148 | goto out; | |
1149 | *num_sge = 0; | |
1150 | break; | |
1151 | ||
1152 | case IB_WR_REG_MR_INTEGRITY: | |
1153 | err = handle_reg_mr_integrity(dev, qp, wr, ctrl, seg, size, | |
1154 | cur_edge, idx, nreq, fence, | |
1155 | next_fence); | |
1156 | if (unlikely(err)) | |
1157 | goto out; | |
1158 | *num_sge = 0; | |
1159 | break; | |
1160 | ||
1161 | default: | |
1162 | break; | |
1163 | } | |
1164 | ||
1165 | out: | |
1166 | return err; | |
1167 | } | |
1168 | ||
1169 | static void handle_qpt_uc(const struct ib_send_wr *wr, void **seg, int *size) | |
1170 | { | |
1171 | switch (wr->opcode) { | |
1172 | case IB_WR_RDMA_WRITE: | |
1173 | case IB_WR_RDMA_WRITE_WITH_IMM: | |
1174 | handle_rdma_op(wr, seg, size); | |
1175 | break; | |
1176 | default: | |
1177 | break; | |
1178 | } | |
1179 | } | |
1180 | ||
1181 | static void handle_qpt_hw_gsi(struct mlx5_ib_qp *qp, | |
1182 | const struct ib_send_wr *wr, void **seg, | |
1183 | int *size, void **cur_edge) | |
1184 | { | |
1185 | set_datagram_seg(*seg, wr); | |
1186 | *seg += sizeof(struct mlx5_wqe_datagram_seg); | |
1187 | *size += sizeof(struct mlx5_wqe_datagram_seg) / 16; | |
1188 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
1189 | } | |
1190 | ||
1191 | static void handle_qpt_ud(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr, | |
1192 | void **seg, int *size, void **cur_edge) | |
1193 | { | |
1194 | set_datagram_seg(*seg, wr); | |
1195 | *seg += sizeof(struct mlx5_wqe_datagram_seg); | |
1196 | *size += sizeof(struct mlx5_wqe_datagram_seg) / 16; | |
1197 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
1198 | ||
1199 | /* handle qp that supports ud offload */ | |
1200 | if (qp->flags & IB_QP_CREATE_IPOIB_UD_LSO) { | |
1201 | struct mlx5_wqe_eth_pad *pad; | |
1202 | ||
1203 | pad = *seg; | |
1204 | memset(pad, 0, sizeof(struct mlx5_wqe_eth_pad)); | |
1205 | *seg += sizeof(struct mlx5_wqe_eth_pad); | |
1206 | *size += sizeof(struct mlx5_wqe_eth_pad) / 16; | |
1207 | set_eth_seg(wr, qp, seg, size, cur_edge); | |
1208 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
1209 | } | |
1210 | } | |
1211 | ||
1212 | static int handle_qpt_reg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, | |
1213 | const struct ib_send_wr *wr, | |
1214 | struct mlx5_wqe_ctrl_seg **ctrl, void **seg, | |
1215 | int *size, void **cur_edge, unsigned int idx) | |
1216 | { | |
1217 | int err = 0; | |
1218 | ||
1219 | if (unlikely(wr->opcode != MLX5_IB_WR_UMR)) { | |
1220 | err = -EINVAL; | |
1221 | mlx5_ib_warn(dev, "bad opcode %d\n", wr->opcode); | |
1222 | goto out; | |
1223 | } | |
1224 | ||
1225 | qp->sq.wr_data[idx] = MLX5_IB_WR_UMR; | |
1226 | (*ctrl)->imm = cpu_to_be32(umr_wr(wr)->mkey); | |
1227 | err = set_reg_umr_segment(dev, *seg, wr, | |
1228 | !!(MLX5_CAP_GEN(dev->mdev, atomic))); | |
1229 | if (unlikely(err)) | |
1230 | goto out; | |
1231 | *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg); | |
1232 | *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16; | |
1233 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
1234 | set_reg_mkey_segment(*seg, wr); | |
1235 | *seg += sizeof(struct mlx5_mkey_seg); | |
1236 | *size += sizeof(struct mlx5_mkey_seg) / 16; | |
1237 | handle_post_send_edge(&qp->sq, seg, *size, cur_edge); | |
1238 | out: | |
1239 | return err; | |
1240 | } | |
1241 | ||
1242 | int mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, | |
1243 | const struct ib_send_wr **bad_wr, bool drain) | |
1244 | { | |
1245 | struct mlx5_wqe_ctrl_seg *ctrl = NULL; /* compiler warning */ | |
1246 | struct mlx5_ib_dev *dev = to_mdev(ibqp->device); | |
1247 | struct mlx5_core_dev *mdev = dev->mdev; | |
1248 | struct mlx5_ib_qp *qp; | |
1249 | struct mlx5_wqe_xrc_seg *xrc; | |
1250 | struct mlx5_bf *bf; | |
1251 | void *cur_edge; | |
3f649ab7 | 1252 | int size; |
029e88fd LR |
1253 | unsigned long flags; |
1254 | unsigned int idx; | |
1255 | int err = 0; | |
1256 | int num_sge; | |
1257 | void *seg; | |
1258 | int nreq; | |
1259 | int i; | |
1260 | u8 next_fence = 0; | |
1261 | u8 fence; | |
1262 | ||
1263 | if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR && | |
1264 | !drain)) { | |
1265 | *bad_wr = wr; | |
1266 | return -EIO; | |
1267 | } | |
1268 | ||
1269 | if (unlikely(ibqp->qp_type == IB_QPT_GSI)) | |
1270 | return mlx5_ib_gsi_post_send(ibqp, wr, bad_wr); | |
1271 | ||
1272 | qp = to_mqp(ibqp); | |
1273 | bf = &qp->bf; | |
1274 | ||
1275 | spin_lock_irqsave(&qp->sq.lock, flags); | |
1276 | ||
1277 | for (nreq = 0; wr; nreq++, wr = wr->next) { | |
1278 | if (unlikely(wr->opcode >= ARRAY_SIZE(mlx5_ib_opcode))) { | |
1279 | mlx5_ib_warn(dev, "\n"); | |
1280 | err = -EINVAL; | |
1281 | *bad_wr = wr; | |
1282 | goto out; | |
1283 | } | |
1284 | ||
1285 | num_sge = wr->num_sge; | |
1286 | if (unlikely(num_sge > qp->sq.max_gs)) { | |
1287 | mlx5_ib_warn(dev, "\n"); | |
1288 | err = -EINVAL; | |
1289 | *bad_wr = wr; | |
1290 | goto out; | |
1291 | } | |
1292 | ||
1293 | err = begin_wqe(qp, &seg, &ctrl, wr, &idx, &size, &cur_edge, | |
1294 | nreq); | |
1295 | if (err) { | |
1296 | mlx5_ib_warn(dev, "\n"); | |
1297 | err = -ENOMEM; | |
1298 | *bad_wr = wr; | |
1299 | goto out; | |
1300 | } | |
1301 | ||
1302 | if (wr->opcode == IB_WR_REG_MR || | |
1303 | wr->opcode == IB_WR_REG_MR_INTEGRITY) { | |
1304 | fence = dev->umr_fence; | |
1305 | next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL; | |
1306 | } else { | |
1307 | if (wr->send_flags & IB_SEND_FENCE) { | |
1308 | if (qp->next_fence) | |
1309 | fence = MLX5_FENCE_MODE_SMALL_AND_FENCE; | |
1310 | else | |
1311 | fence = MLX5_FENCE_MODE_FENCE; | |
1312 | } else { | |
1313 | fence = qp->next_fence; | |
1314 | } | |
1315 | } | |
1316 | ||
1317 | switch (ibqp->qp_type) { | |
1318 | case IB_QPT_XRC_INI: | |
1319 | xrc = seg; | |
1320 | seg += sizeof(*xrc); | |
1321 | size += sizeof(*xrc) / 16; | |
1322 | fallthrough; | |
1323 | case IB_QPT_RC: | |
1324 | err = handle_qpt_rc(dev, qp, wr, &ctrl, &seg, &size, | |
1325 | &cur_edge, &idx, nreq, fence, | |
1326 | next_fence, &num_sge); | |
1327 | if (unlikely(err)) { | |
1328 | *bad_wr = wr; | |
1329 | goto out; | |
1330 | } else if (wr->opcode == IB_WR_REG_MR_INTEGRITY) { | |
1331 | goto skip_psv; | |
1332 | } | |
1333 | break; | |
1334 | ||
1335 | case IB_QPT_UC: | |
1336 | handle_qpt_uc(wr, &seg, &size); | |
1337 | break; | |
1338 | case IB_QPT_SMI: | |
1339 | if (unlikely(!mdev->port_caps[qp->port - 1].has_smi)) { | |
1340 | mlx5_ib_warn(dev, "Send SMP MADs is not allowed\n"); | |
1341 | err = -EPERM; | |
1342 | *bad_wr = wr; | |
1343 | goto out; | |
1344 | } | |
1345 | fallthrough; | |
1346 | case MLX5_IB_QPT_HW_GSI: | |
1347 | handle_qpt_hw_gsi(qp, wr, &seg, &size, &cur_edge); | |
1348 | break; | |
1349 | case IB_QPT_UD: | |
1350 | handle_qpt_ud(qp, wr, &seg, &size, &cur_edge); | |
1351 | break; | |
1352 | case MLX5_IB_QPT_REG_UMR: | |
1353 | err = handle_qpt_reg_umr(dev, qp, wr, &ctrl, &seg, | |
1354 | &size, &cur_edge, idx); | |
1355 | if (unlikely(err)) | |
1356 | goto out; | |
1357 | break; | |
1358 | ||
1359 | default: | |
1360 | break; | |
1361 | } | |
1362 | ||
1363 | if (wr->send_flags & IB_SEND_INLINE && num_sge) { | |
1364 | err = set_data_inl_seg(qp, wr, &seg, &size, &cur_edge); | |
1365 | if (unlikely(err)) { | |
1366 | mlx5_ib_warn(dev, "\n"); | |
1367 | *bad_wr = wr; | |
1368 | goto out; | |
1369 | } | |
1370 | } else { | |
1371 | for (i = 0; i < num_sge; i++) { | |
1372 | handle_post_send_edge(&qp->sq, &seg, size, | |
1373 | &cur_edge); | |
1374 | if (unlikely(!wr->sg_list[i].length)) | |
1375 | continue; | |
1376 | ||
1377 | set_data_ptr_seg( | |
1378 | (struct mlx5_wqe_data_seg *)seg, | |
1379 | wr->sg_list + i); | |
1380 | size += sizeof(struct mlx5_wqe_data_seg) / 16; | |
1381 | seg += sizeof(struct mlx5_wqe_data_seg); | |
1382 | } | |
1383 | } | |
1384 | ||
1385 | qp->next_fence = next_fence; | |
1386 | finish_wqe(qp, ctrl, seg, size, cur_edge, idx, wr->wr_id, nreq, | |
1387 | fence, mlx5_ib_opcode[wr->opcode]); | |
1388 | skip_psv: | |
1389 | if (0) | |
1390 | dump_wqe(qp, idx, size); | |
1391 | } | |
1392 | ||
1393 | out: | |
1394 | if (likely(nreq)) { | |
1395 | qp->sq.head += nreq; | |
1396 | ||
1397 | /* Make sure that descriptors are written before | |
1398 | * updating doorbell record and ringing the doorbell | |
1399 | */ | |
1400 | wmb(); | |
1401 | ||
1402 | qp->db.db[MLX5_SND_DBR] = cpu_to_be32(qp->sq.cur_post); | |
1403 | ||
1404 | /* Make sure doorbell record is visible to the HCA before | |
1405 | * we hit doorbell. | |
1406 | */ | |
1407 | wmb(); | |
1408 | ||
1409 | mlx5_write64((__be32 *)ctrl, bf->bfreg->map + bf->offset); | |
1410 | /* Make sure doorbells don't leak out of SQ spinlock | |
1411 | * and reach the HCA out of order. | |
1412 | */ | |
1413 | bf->offset ^= bf->buf_size; | |
1414 | } | |
1415 | ||
1416 | spin_unlock_irqrestore(&qp->sq.lock, flags); | |
1417 | ||
1418 | return err; | |
1419 | } | |
1420 | ||
1421 | static void set_sig_seg(struct mlx5_rwqe_sig *sig, int max_gs) | |
1422 | { | |
1423 | sig->signature = calc_sig(sig, (max_gs + 1) << 2); | |
1424 | } | |
1425 | ||
1426 | int mlx5_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, | |
1427 | const struct ib_recv_wr **bad_wr, bool drain) | |
1428 | { | |
1429 | struct mlx5_ib_qp *qp = to_mqp(ibqp); | |
1430 | struct mlx5_wqe_data_seg *scat; | |
1431 | struct mlx5_rwqe_sig *sig; | |
1432 | struct mlx5_ib_dev *dev = to_mdev(ibqp->device); | |
1433 | struct mlx5_core_dev *mdev = dev->mdev; | |
1434 | unsigned long flags; | |
1435 | int err = 0; | |
1436 | int nreq; | |
1437 | int ind; | |
1438 | int i; | |
1439 | ||
1440 | if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR && | |
1441 | !drain)) { | |
1442 | *bad_wr = wr; | |
1443 | return -EIO; | |
1444 | } | |
1445 | ||
1446 | if (unlikely(ibqp->qp_type == IB_QPT_GSI)) | |
1447 | return mlx5_ib_gsi_post_recv(ibqp, wr, bad_wr); | |
1448 | ||
1449 | spin_lock_irqsave(&qp->rq.lock, flags); | |
1450 | ||
1451 | ind = qp->rq.head & (qp->rq.wqe_cnt - 1); | |
1452 | ||
1453 | for (nreq = 0; wr; nreq++, wr = wr->next) { | |
1454 | if (mlx5_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { | |
1455 | err = -ENOMEM; | |
1456 | *bad_wr = wr; | |
1457 | goto out; | |
1458 | } | |
1459 | ||
1460 | if (unlikely(wr->num_sge > qp->rq.max_gs)) { | |
1461 | err = -EINVAL; | |
1462 | *bad_wr = wr; | |
1463 | goto out; | |
1464 | } | |
1465 | ||
1466 | scat = mlx5_frag_buf_get_wqe(&qp->rq.fbc, ind); | |
1467 | if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE) | |
1468 | scat++; | |
1469 | ||
1470 | for (i = 0; i < wr->num_sge; i++) | |
1471 | set_data_ptr_seg(scat + i, wr->sg_list + i); | |
1472 | ||
1473 | if (i < qp->rq.max_gs) { | |
1474 | scat[i].byte_count = 0; | |
1475 | scat[i].lkey = cpu_to_be32(MLX5_INVALID_LKEY); | |
1476 | scat[i].addr = 0; | |
1477 | } | |
1478 | ||
1479 | if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE) { | |
1480 | sig = (struct mlx5_rwqe_sig *)scat; | |
1481 | set_sig_seg(sig, qp->rq.max_gs); | |
1482 | } | |
1483 | ||
1484 | qp->rq.wrid[ind] = wr->wr_id; | |
1485 | ||
1486 | ind = (ind + 1) & (qp->rq.wqe_cnt - 1); | |
1487 | } | |
1488 | ||
1489 | out: | |
1490 | if (likely(nreq)) { | |
1491 | qp->rq.head += nreq; | |
1492 | ||
1493 | /* Make sure that descriptors are written before | |
1494 | * doorbell record. | |
1495 | */ | |
1496 | wmb(); | |
1497 | ||
1498 | *qp->db.db = cpu_to_be32(qp->rq.head & 0xffff); | |
1499 | } | |
1500 | ||
1501 | spin_unlock_irqrestore(&qp->rq.lock, flags); | |
1502 | ||
1503 | return err; | |
1504 | } |