1029e88fdSLeon Romanovsky // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2029e88fdSLeon Romanovsky /*
3029e88fdSLeon Romanovsky * Copyright (c) 2020, Mellanox Technologies inc. All rights reserved.
4029e88fdSLeon Romanovsky */
5029e88fdSLeon Romanovsky
6029e88fdSLeon Romanovsky #include <linux/gfp.h>
7029e88fdSLeon Romanovsky #include <linux/mlx5/qp.h>
8029e88fdSLeon Romanovsky #include <linux/mlx5/driver.h>
9029e88fdSLeon Romanovsky #include "wr.h"
10f49c856aSAharon Landau #include "umr.h"
11029e88fdSLeon Romanovsky
12029e88fdSLeon Romanovsky static const u32 mlx5_ib_opcode[] = {
13029e88fdSLeon Romanovsky [IB_WR_SEND] = MLX5_OPCODE_SEND,
14029e88fdSLeon Romanovsky [IB_WR_LSO] = MLX5_OPCODE_LSO,
15029e88fdSLeon Romanovsky [IB_WR_SEND_WITH_IMM] = MLX5_OPCODE_SEND_IMM,
16029e88fdSLeon Romanovsky [IB_WR_RDMA_WRITE] = MLX5_OPCODE_RDMA_WRITE,
17029e88fdSLeon Romanovsky [IB_WR_RDMA_WRITE_WITH_IMM] = MLX5_OPCODE_RDMA_WRITE_IMM,
18029e88fdSLeon Romanovsky [IB_WR_RDMA_READ] = MLX5_OPCODE_RDMA_READ,
19029e88fdSLeon Romanovsky [IB_WR_ATOMIC_CMP_AND_SWP] = MLX5_OPCODE_ATOMIC_CS,
20029e88fdSLeon Romanovsky [IB_WR_ATOMIC_FETCH_AND_ADD] = MLX5_OPCODE_ATOMIC_FA,
21029e88fdSLeon Romanovsky [IB_WR_SEND_WITH_INV] = MLX5_OPCODE_SEND_INVAL,
22029e88fdSLeon Romanovsky [IB_WR_LOCAL_INV] = MLX5_OPCODE_UMR,
23029e88fdSLeon Romanovsky [IB_WR_REG_MR] = MLX5_OPCODE_UMR,
24029e88fdSLeon Romanovsky [IB_WR_MASKED_ATOMIC_CMP_AND_SWP] = MLX5_OPCODE_ATOMIC_MASKED_CS,
25029e88fdSLeon Romanovsky [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD] = MLX5_OPCODE_ATOMIC_MASKED_FA,
26029e88fdSLeon Romanovsky [MLX5_IB_WR_UMR] = MLX5_OPCODE_UMR,
27029e88fdSLeon Romanovsky };
28029e88fdSLeon Romanovsky
mlx5r_wq_overflow(struct mlx5_ib_wq * wq,int nreq,struct ib_cq * ib_cq)29fe765aebSAharon Landau int mlx5r_wq_overflow(struct mlx5_ib_wq *wq, int nreq, struct ib_cq *ib_cq)
30029e88fdSLeon Romanovsky {
31029e88fdSLeon Romanovsky struct mlx5_ib_cq *cq;
32029e88fdSLeon Romanovsky unsigned int cur;
33029e88fdSLeon Romanovsky
34029e88fdSLeon Romanovsky cur = wq->head - wq->tail;
35029e88fdSLeon Romanovsky if (likely(cur + nreq < wq->max_post))
36029e88fdSLeon Romanovsky return 0;
37029e88fdSLeon Romanovsky
38029e88fdSLeon Romanovsky cq = to_mcq(ib_cq);
39029e88fdSLeon Romanovsky spin_lock(&cq->lock);
40029e88fdSLeon Romanovsky cur = wq->head - wq->tail;
41029e88fdSLeon Romanovsky spin_unlock(&cq->lock);
42029e88fdSLeon Romanovsky
43029e88fdSLeon Romanovsky return cur + nreq >= wq->max_post;
44029e88fdSLeon Romanovsky }
45029e88fdSLeon Romanovsky
set_raddr_seg(struct mlx5_wqe_raddr_seg * rseg,u64 remote_addr,u32 rkey)46029e88fdSLeon Romanovsky static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
47029e88fdSLeon Romanovsky u64 remote_addr, u32 rkey)
48029e88fdSLeon Romanovsky {
49029e88fdSLeon Romanovsky rseg->raddr = cpu_to_be64(remote_addr);
50029e88fdSLeon Romanovsky rseg->rkey = cpu_to_be32(rkey);
51029e88fdSLeon Romanovsky rseg->reserved = 0;
52029e88fdSLeon Romanovsky }
53029e88fdSLeon Romanovsky
set_eth_seg(const struct ib_send_wr * wr,struct mlx5_ib_qp * qp,void ** seg,int * size,void ** cur_edge)54029e88fdSLeon Romanovsky static void set_eth_seg(const struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
55029e88fdSLeon Romanovsky void **seg, int *size, void **cur_edge)
56029e88fdSLeon Romanovsky {
57029e88fdSLeon Romanovsky struct mlx5_wqe_eth_seg *eseg = *seg;
58029e88fdSLeon Romanovsky
59029e88fdSLeon Romanovsky memset(eseg, 0, sizeof(struct mlx5_wqe_eth_seg));
60029e88fdSLeon Romanovsky
61029e88fdSLeon Romanovsky if (wr->send_flags & IB_SEND_IP_CSUM)
62029e88fdSLeon Romanovsky eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM |
63029e88fdSLeon Romanovsky MLX5_ETH_WQE_L4_CSUM;
64029e88fdSLeon Romanovsky
65029e88fdSLeon Romanovsky if (wr->opcode == IB_WR_LSO) {
66029e88fdSLeon Romanovsky struct ib_ud_wr *ud_wr = container_of(wr, struct ib_ud_wr, wr);
67029e88fdSLeon Romanovsky size_t left, copysz;
68029e88fdSLeon Romanovsky void *pdata = ud_wr->header;
69029e88fdSLeon Romanovsky size_t stride;
70029e88fdSLeon Romanovsky
71029e88fdSLeon Romanovsky left = ud_wr->hlen;
72029e88fdSLeon Romanovsky eseg->mss = cpu_to_be16(ud_wr->mss);
73029e88fdSLeon Romanovsky eseg->inline_hdr.sz = cpu_to_be16(left);
74029e88fdSLeon Romanovsky
75fe765aebSAharon Landau /* mlx5r_memcpy_send_wqe should get a 16B align address. Hence,
76fe765aebSAharon Landau * we first copy up to the current edge and then, if needed,
77fe765aebSAharon Landau * continue to mlx5r_memcpy_send_wqe.
78029e88fdSLeon Romanovsky */
79029e88fdSLeon Romanovsky copysz = min_t(u64, *cur_edge - (void *)eseg->inline_hdr.start,
80029e88fdSLeon Romanovsky left);
81*9a624a5fSLeon Romanovsky memcpy(eseg->inline_hdr.data, pdata, copysz);
82029e88fdSLeon Romanovsky stride = ALIGN(sizeof(struct mlx5_wqe_eth_seg) -
83029e88fdSLeon Romanovsky sizeof(eseg->inline_hdr.start) + copysz, 16);
84029e88fdSLeon Romanovsky *size += stride / 16;
85029e88fdSLeon Romanovsky *seg += stride;
86029e88fdSLeon Romanovsky
87029e88fdSLeon Romanovsky if (copysz < left) {
88029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
89029e88fdSLeon Romanovsky left -= copysz;
90029e88fdSLeon Romanovsky pdata += copysz;
91fe765aebSAharon Landau mlx5r_memcpy_send_wqe(&qp->sq, cur_edge, seg, size,
92fe765aebSAharon Landau pdata, left);
93029e88fdSLeon Romanovsky }
94029e88fdSLeon Romanovsky
95029e88fdSLeon Romanovsky return;
96029e88fdSLeon Romanovsky }
97029e88fdSLeon Romanovsky
98029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_wqe_eth_seg);
99029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_wqe_eth_seg) / 16;
100029e88fdSLeon Romanovsky }
101029e88fdSLeon Romanovsky
set_datagram_seg(struct mlx5_wqe_datagram_seg * dseg,const struct ib_send_wr * wr)102029e88fdSLeon Romanovsky static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
103029e88fdSLeon Romanovsky const struct ib_send_wr *wr)
104029e88fdSLeon Romanovsky {
105029e88fdSLeon Romanovsky memcpy(&dseg->av, &to_mah(ud_wr(wr)->ah)->av, sizeof(struct mlx5_av));
106029e88fdSLeon Romanovsky dseg->av.dqp_dct =
107029e88fdSLeon Romanovsky cpu_to_be32(ud_wr(wr)->remote_qpn | MLX5_EXTENDED_UD_AV);
108029e88fdSLeon Romanovsky dseg->av.key.qkey.qkey = cpu_to_be32(ud_wr(wr)->remote_qkey);
109029e88fdSLeon Romanovsky }
110029e88fdSLeon Romanovsky
set_data_ptr_seg(struct mlx5_wqe_data_seg * dseg,struct ib_sge * sg)111029e88fdSLeon Romanovsky static void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ib_sge *sg)
112029e88fdSLeon Romanovsky {
113029e88fdSLeon Romanovsky dseg->byte_count = cpu_to_be32(sg->length);
114029e88fdSLeon Romanovsky dseg->lkey = cpu_to_be32(sg->lkey);
115029e88fdSLeon Romanovsky dseg->addr = cpu_to_be64(sg->addr);
116029e88fdSLeon Romanovsky }
117029e88fdSLeon Romanovsky
frwr_mkey_mask(bool atomic)118029e88fdSLeon Romanovsky static __be64 frwr_mkey_mask(bool atomic)
119029e88fdSLeon Romanovsky {
120029e88fdSLeon Romanovsky u64 result;
121029e88fdSLeon Romanovsky
122029e88fdSLeon Romanovsky result = MLX5_MKEY_MASK_LEN |
123029e88fdSLeon Romanovsky MLX5_MKEY_MASK_PAGE_SIZE |
124029e88fdSLeon Romanovsky MLX5_MKEY_MASK_START_ADDR |
125029e88fdSLeon Romanovsky MLX5_MKEY_MASK_EN_RINVAL |
126029e88fdSLeon Romanovsky MLX5_MKEY_MASK_KEY |
127029e88fdSLeon Romanovsky MLX5_MKEY_MASK_LR |
128029e88fdSLeon Romanovsky MLX5_MKEY_MASK_LW |
129029e88fdSLeon Romanovsky MLX5_MKEY_MASK_RR |
130029e88fdSLeon Romanovsky MLX5_MKEY_MASK_RW |
131029e88fdSLeon Romanovsky MLX5_MKEY_MASK_SMALL_FENCE |
132029e88fdSLeon Romanovsky MLX5_MKEY_MASK_FREE;
133029e88fdSLeon Romanovsky
134029e88fdSLeon Romanovsky if (atomic)
135029e88fdSLeon Romanovsky result |= MLX5_MKEY_MASK_A;
136029e88fdSLeon Romanovsky
137029e88fdSLeon Romanovsky return cpu_to_be64(result);
138029e88fdSLeon Romanovsky }
139029e88fdSLeon Romanovsky
sig_mkey_mask(void)140029e88fdSLeon Romanovsky static __be64 sig_mkey_mask(void)
141029e88fdSLeon Romanovsky {
142029e88fdSLeon Romanovsky u64 result;
143029e88fdSLeon Romanovsky
144029e88fdSLeon Romanovsky result = MLX5_MKEY_MASK_LEN |
145029e88fdSLeon Romanovsky MLX5_MKEY_MASK_PAGE_SIZE |
146029e88fdSLeon Romanovsky MLX5_MKEY_MASK_START_ADDR |
147029e88fdSLeon Romanovsky MLX5_MKEY_MASK_EN_SIGERR |
148029e88fdSLeon Romanovsky MLX5_MKEY_MASK_EN_RINVAL |
149029e88fdSLeon Romanovsky MLX5_MKEY_MASK_KEY |
150029e88fdSLeon Romanovsky MLX5_MKEY_MASK_LR |
151029e88fdSLeon Romanovsky MLX5_MKEY_MASK_LW |
152029e88fdSLeon Romanovsky MLX5_MKEY_MASK_RR |
153029e88fdSLeon Romanovsky MLX5_MKEY_MASK_RW |
154029e88fdSLeon Romanovsky MLX5_MKEY_MASK_SMALL_FENCE |
155029e88fdSLeon Romanovsky MLX5_MKEY_MASK_FREE |
156029e88fdSLeon Romanovsky MLX5_MKEY_MASK_BSF_EN;
157029e88fdSLeon Romanovsky
158029e88fdSLeon Romanovsky return cpu_to_be64(result);
159029e88fdSLeon Romanovsky }
160029e88fdSLeon Romanovsky
set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg * umr,struct mlx5_ib_mr * mr,u8 flags,bool atomic)161029e88fdSLeon Romanovsky static void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr,
162029e88fdSLeon Romanovsky struct mlx5_ib_mr *mr, u8 flags, bool atomic)
163029e88fdSLeon Romanovsky {
164ae0579acSAharon Landau int size = (mr->mmkey.ndescs + mr->meta_ndescs) * mr->desc_size;
165029e88fdSLeon Romanovsky
166029e88fdSLeon Romanovsky memset(umr, 0, sizeof(*umr));
167029e88fdSLeon Romanovsky
168029e88fdSLeon Romanovsky umr->flags = flags;
1698a8a5d37SAharon Landau umr->xlt_octowords = cpu_to_be16(mlx5r_umr_get_xlt_octo(size));
170029e88fdSLeon Romanovsky umr->mkey_mask = frwr_mkey_mask(atomic);
171029e88fdSLeon Romanovsky }
172029e88fdSLeon Romanovsky
set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg * umr)173029e88fdSLeon Romanovsky static void set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr)
174029e88fdSLeon Romanovsky {
175029e88fdSLeon Romanovsky memset(umr, 0, sizeof(*umr));
176029e88fdSLeon Romanovsky umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
177029e88fdSLeon Romanovsky umr->flags = MLX5_UMR_INLINE;
178029e88fdSLeon Romanovsky }
179029e88fdSLeon Romanovsky
get_umr_flags(int acc)180029e88fdSLeon Romanovsky static u8 get_umr_flags(int acc)
181029e88fdSLeon Romanovsky {
182029e88fdSLeon Romanovsky return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC : 0) |
183029e88fdSLeon Romanovsky (acc & IB_ACCESS_REMOTE_WRITE ? MLX5_PERM_REMOTE_WRITE : 0) |
184029e88fdSLeon Romanovsky (acc & IB_ACCESS_REMOTE_READ ? MLX5_PERM_REMOTE_READ : 0) |
185029e88fdSLeon Romanovsky (acc & IB_ACCESS_LOCAL_WRITE ? MLX5_PERM_LOCAL_WRITE : 0) |
186029e88fdSLeon Romanovsky MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN;
187029e88fdSLeon Romanovsky }
188029e88fdSLeon Romanovsky
set_reg_mkey_seg(struct mlx5_mkey_seg * seg,struct mlx5_ib_mr * mr,u32 key,int access)189029e88fdSLeon Romanovsky static void set_reg_mkey_seg(struct mlx5_mkey_seg *seg,
190029e88fdSLeon Romanovsky struct mlx5_ib_mr *mr,
191029e88fdSLeon Romanovsky u32 key, int access)
192029e88fdSLeon Romanovsky {
193ae0579acSAharon Landau int ndescs = ALIGN(mr->mmkey.ndescs + mr->meta_ndescs, 8) >> 1;
194029e88fdSLeon Romanovsky
195029e88fdSLeon Romanovsky memset(seg, 0, sizeof(*seg));
196029e88fdSLeon Romanovsky
197029e88fdSLeon Romanovsky if (mr->access_mode == MLX5_MKC_ACCESS_MODE_MTT)
198029e88fdSLeon Romanovsky seg->log2_page_size = ilog2(mr->ibmr.page_size);
199029e88fdSLeon Romanovsky else if (mr->access_mode == MLX5_MKC_ACCESS_MODE_KLMS)
200029e88fdSLeon Romanovsky /* KLMs take twice the size of MTTs */
201029e88fdSLeon Romanovsky ndescs *= 2;
202029e88fdSLeon Romanovsky
203029e88fdSLeon Romanovsky seg->flags = get_umr_flags(access) | mr->access_mode;
204029e88fdSLeon Romanovsky seg->qpn_mkey7_0 = cpu_to_be32((key & 0xff) | 0xffffff00);
205029e88fdSLeon Romanovsky seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL);
206029e88fdSLeon Romanovsky seg->start_addr = cpu_to_be64(mr->ibmr.iova);
207029e88fdSLeon Romanovsky seg->len = cpu_to_be64(mr->ibmr.length);
208029e88fdSLeon Romanovsky seg->xlt_oct_size = cpu_to_be32(ndescs);
209029e88fdSLeon Romanovsky }
210029e88fdSLeon Romanovsky
set_linv_mkey_seg(struct mlx5_mkey_seg * seg)211029e88fdSLeon Romanovsky static void set_linv_mkey_seg(struct mlx5_mkey_seg *seg)
212029e88fdSLeon Romanovsky {
213029e88fdSLeon Romanovsky memset(seg, 0, sizeof(*seg));
214029e88fdSLeon Romanovsky seg->status = MLX5_MKEY_STATUS_FREE;
215029e88fdSLeon Romanovsky }
216029e88fdSLeon Romanovsky
set_reg_data_seg(struct mlx5_wqe_data_seg * dseg,struct mlx5_ib_mr * mr,struct mlx5_ib_pd * pd)217029e88fdSLeon Romanovsky static void set_reg_data_seg(struct mlx5_wqe_data_seg *dseg,
218029e88fdSLeon Romanovsky struct mlx5_ib_mr *mr,
219029e88fdSLeon Romanovsky struct mlx5_ib_pd *pd)
220029e88fdSLeon Romanovsky {
221ae0579acSAharon Landau int bcount = mr->desc_size * (mr->mmkey.ndescs + mr->meta_ndescs);
222029e88fdSLeon Romanovsky
223029e88fdSLeon Romanovsky dseg->addr = cpu_to_be64(mr->desc_map);
224029e88fdSLeon Romanovsky dseg->byte_count = cpu_to_be32(ALIGN(bcount, 64));
225029e88fdSLeon Romanovsky dseg->lkey = cpu_to_be32(pd->ibpd.local_dma_lkey);
226029e88fdSLeon Romanovsky }
227029e88fdSLeon Romanovsky
send_ieth(const struct ib_send_wr * wr)228029e88fdSLeon Romanovsky static __be32 send_ieth(const struct ib_send_wr *wr)
229029e88fdSLeon Romanovsky {
230029e88fdSLeon Romanovsky switch (wr->opcode) {
231029e88fdSLeon Romanovsky case IB_WR_SEND_WITH_IMM:
232029e88fdSLeon Romanovsky case IB_WR_RDMA_WRITE_WITH_IMM:
233029e88fdSLeon Romanovsky return wr->ex.imm_data;
234029e88fdSLeon Romanovsky
235029e88fdSLeon Romanovsky case IB_WR_SEND_WITH_INV:
236029e88fdSLeon Romanovsky return cpu_to_be32(wr->ex.invalidate_rkey);
237029e88fdSLeon Romanovsky
238029e88fdSLeon Romanovsky default:
239029e88fdSLeon Romanovsky return 0;
240029e88fdSLeon Romanovsky }
241029e88fdSLeon Romanovsky }
242029e88fdSLeon Romanovsky
calc_sig(void * wqe,int size)243029e88fdSLeon Romanovsky static u8 calc_sig(void *wqe, int size)
244029e88fdSLeon Romanovsky {
245029e88fdSLeon Romanovsky u8 *p = wqe;
246029e88fdSLeon Romanovsky u8 res = 0;
247029e88fdSLeon Romanovsky int i;
248029e88fdSLeon Romanovsky
249029e88fdSLeon Romanovsky for (i = 0; i < size; i++)
250029e88fdSLeon Romanovsky res ^= p[i];
251029e88fdSLeon Romanovsky
252029e88fdSLeon Romanovsky return ~res;
253029e88fdSLeon Romanovsky }
254029e88fdSLeon Romanovsky
wq_sig(void * wqe)255029e88fdSLeon Romanovsky static u8 wq_sig(void *wqe)
256029e88fdSLeon Romanovsky {
257029e88fdSLeon Romanovsky return calc_sig(wqe, (*((u8 *)wqe + 8) & 0x3f) << 4);
258029e88fdSLeon Romanovsky }
259029e88fdSLeon Romanovsky
set_data_inl_seg(struct mlx5_ib_qp * qp,const struct ib_send_wr * wr,void ** wqe,int * wqe_sz,void ** cur_edge)260029e88fdSLeon Romanovsky static int set_data_inl_seg(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr,
261029e88fdSLeon Romanovsky void **wqe, int *wqe_sz, void **cur_edge)
262029e88fdSLeon Romanovsky {
263029e88fdSLeon Romanovsky struct mlx5_wqe_inline_seg *seg;
264029e88fdSLeon Romanovsky size_t offset;
265029e88fdSLeon Romanovsky int inl = 0;
266029e88fdSLeon Romanovsky int i;
267029e88fdSLeon Romanovsky
268029e88fdSLeon Romanovsky seg = *wqe;
269029e88fdSLeon Romanovsky *wqe += sizeof(*seg);
270029e88fdSLeon Romanovsky offset = sizeof(*seg);
271029e88fdSLeon Romanovsky
272029e88fdSLeon Romanovsky for (i = 0; i < wr->num_sge; i++) {
273029e88fdSLeon Romanovsky size_t len = wr->sg_list[i].length;
274029e88fdSLeon Romanovsky void *addr = (void *)(unsigned long)(wr->sg_list[i].addr);
275029e88fdSLeon Romanovsky
276029e88fdSLeon Romanovsky inl += len;
277029e88fdSLeon Romanovsky
278029e88fdSLeon Romanovsky if (unlikely(inl > qp->max_inline_data))
279029e88fdSLeon Romanovsky return -ENOMEM;
280029e88fdSLeon Romanovsky
281029e88fdSLeon Romanovsky while (likely(len)) {
282029e88fdSLeon Romanovsky size_t leftlen;
283029e88fdSLeon Romanovsky size_t copysz;
284029e88fdSLeon Romanovsky
285029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, wqe,
286029e88fdSLeon Romanovsky *wqe_sz + (offset >> 4),
287029e88fdSLeon Romanovsky cur_edge);
288029e88fdSLeon Romanovsky
289029e88fdSLeon Romanovsky leftlen = *cur_edge - *wqe;
290029e88fdSLeon Romanovsky copysz = min_t(size_t, leftlen, len);
291029e88fdSLeon Romanovsky
292029e88fdSLeon Romanovsky memcpy(*wqe, addr, copysz);
293029e88fdSLeon Romanovsky len -= copysz;
294029e88fdSLeon Romanovsky addr += copysz;
295029e88fdSLeon Romanovsky *wqe += copysz;
296029e88fdSLeon Romanovsky offset += copysz;
297029e88fdSLeon Romanovsky }
298029e88fdSLeon Romanovsky }
299029e88fdSLeon Romanovsky
300029e88fdSLeon Romanovsky seg->byte_count = cpu_to_be32(inl | MLX5_INLINE_SEG);
301029e88fdSLeon Romanovsky
302029e88fdSLeon Romanovsky *wqe_sz += ALIGN(inl + sizeof(seg->byte_count), 16) / 16;
303029e88fdSLeon Romanovsky
304029e88fdSLeon Romanovsky return 0;
305029e88fdSLeon Romanovsky }
306029e88fdSLeon Romanovsky
prot_field_size(enum ib_signature_type type)307029e88fdSLeon Romanovsky static u16 prot_field_size(enum ib_signature_type type)
308029e88fdSLeon Romanovsky {
309029e88fdSLeon Romanovsky switch (type) {
310029e88fdSLeon Romanovsky case IB_SIG_TYPE_T10_DIF:
311029e88fdSLeon Romanovsky return MLX5_DIF_SIZE;
312029e88fdSLeon Romanovsky default:
313029e88fdSLeon Romanovsky return 0;
314029e88fdSLeon Romanovsky }
315029e88fdSLeon Romanovsky }
316029e88fdSLeon Romanovsky
bs_selector(int block_size)317029e88fdSLeon Romanovsky static u8 bs_selector(int block_size)
318029e88fdSLeon Romanovsky {
319029e88fdSLeon Romanovsky switch (block_size) {
320029e88fdSLeon Romanovsky case 512: return 0x1;
321029e88fdSLeon Romanovsky case 520: return 0x2;
322029e88fdSLeon Romanovsky case 4096: return 0x3;
323029e88fdSLeon Romanovsky case 4160: return 0x4;
324029e88fdSLeon Romanovsky case 1073741824: return 0x5;
325029e88fdSLeon Romanovsky default: return 0;
326029e88fdSLeon Romanovsky }
327029e88fdSLeon Romanovsky }
328029e88fdSLeon Romanovsky
mlx5_fill_inl_bsf(struct ib_sig_domain * domain,struct mlx5_bsf_inl * inl)329029e88fdSLeon Romanovsky static void mlx5_fill_inl_bsf(struct ib_sig_domain *domain,
330029e88fdSLeon Romanovsky struct mlx5_bsf_inl *inl)
331029e88fdSLeon Romanovsky {
332029e88fdSLeon Romanovsky /* Valid inline section and allow BSF refresh */
333029e88fdSLeon Romanovsky inl->vld_refresh = cpu_to_be16(MLX5_BSF_INL_VALID |
334029e88fdSLeon Romanovsky MLX5_BSF_REFRESH_DIF);
335029e88fdSLeon Romanovsky inl->dif_apptag = cpu_to_be16(domain->sig.dif.app_tag);
336029e88fdSLeon Romanovsky inl->dif_reftag = cpu_to_be32(domain->sig.dif.ref_tag);
337029e88fdSLeon Romanovsky /* repeating block */
338029e88fdSLeon Romanovsky inl->rp_inv_seed = MLX5_BSF_REPEAT_BLOCK;
339029e88fdSLeon Romanovsky inl->sig_type = domain->sig.dif.bg_type == IB_T10DIF_CRC ?
340029e88fdSLeon Romanovsky MLX5_DIF_CRC : MLX5_DIF_IPCS;
341029e88fdSLeon Romanovsky
342029e88fdSLeon Romanovsky if (domain->sig.dif.ref_remap)
343029e88fdSLeon Romanovsky inl->dif_inc_ref_guard_check |= MLX5_BSF_INC_REFTAG;
344029e88fdSLeon Romanovsky
345029e88fdSLeon Romanovsky if (domain->sig.dif.app_escape) {
346029e88fdSLeon Romanovsky if (domain->sig.dif.ref_escape)
347029e88fdSLeon Romanovsky inl->dif_inc_ref_guard_check |= MLX5_BSF_APPREF_ESCAPE;
348029e88fdSLeon Romanovsky else
349029e88fdSLeon Romanovsky inl->dif_inc_ref_guard_check |= MLX5_BSF_APPTAG_ESCAPE;
350029e88fdSLeon Romanovsky }
351029e88fdSLeon Romanovsky
352029e88fdSLeon Romanovsky inl->dif_app_bitmask_check =
353029e88fdSLeon Romanovsky cpu_to_be16(domain->sig.dif.apptag_check_mask);
354029e88fdSLeon Romanovsky }
355029e88fdSLeon Romanovsky
mlx5_set_bsf(struct ib_mr * sig_mr,struct ib_sig_attrs * sig_attrs,struct mlx5_bsf * bsf,u32 data_size)356029e88fdSLeon Romanovsky static int mlx5_set_bsf(struct ib_mr *sig_mr,
357029e88fdSLeon Romanovsky struct ib_sig_attrs *sig_attrs,
358029e88fdSLeon Romanovsky struct mlx5_bsf *bsf, u32 data_size)
359029e88fdSLeon Romanovsky {
360029e88fdSLeon Romanovsky struct mlx5_core_sig_ctx *msig = to_mmr(sig_mr)->sig;
361029e88fdSLeon Romanovsky struct mlx5_bsf_basic *basic = &bsf->basic;
362029e88fdSLeon Romanovsky struct ib_sig_domain *mem = &sig_attrs->mem;
363029e88fdSLeon Romanovsky struct ib_sig_domain *wire = &sig_attrs->wire;
364029e88fdSLeon Romanovsky
365029e88fdSLeon Romanovsky memset(bsf, 0, sizeof(*bsf));
366029e88fdSLeon Romanovsky
367029e88fdSLeon Romanovsky /* Basic + Extended + Inline */
368029e88fdSLeon Romanovsky basic->bsf_size_sbs = 1 << 7;
369029e88fdSLeon Romanovsky /* Input domain check byte mask */
370029e88fdSLeon Romanovsky basic->check_byte_mask = sig_attrs->check_mask;
371029e88fdSLeon Romanovsky basic->raw_data_size = cpu_to_be32(data_size);
372029e88fdSLeon Romanovsky
373029e88fdSLeon Romanovsky /* Memory domain */
374029e88fdSLeon Romanovsky switch (sig_attrs->mem.sig_type) {
375029e88fdSLeon Romanovsky case IB_SIG_TYPE_NONE:
376029e88fdSLeon Romanovsky break;
377029e88fdSLeon Romanovsky case IB_SIG_TYPE_T10_DIF:
378029e88fdSLeon Romanovsky basic->mem.bs_selector = bs_selector(mem->sig.dif.pi_interval);
379029e88fdSLeon Romanovsky basic->m_bfs_psv = cpu_to_be32(msig->psv_memory.psv_idx);
380029e88fdSLeon Romanovsky mlx5_fill_inl_bsf(mem, &bsf->m_inl);
381029e88fdSLeon Romanovsky break;
382029e88fdSLeon Romanovsky default:
383029e88fdSLeon Romanovsky return -EINVAL;
384029e88fdSLeon Romanovsky }
385029e88fdSLeon Romanovsky
386029e88fdSLeon Romanovsky /* Wire domain */
387029e88fdSLeon Romanovsky switch (sig_attrs->wire.sig_type) {
388029e88fdSLeon Romanovsky case IB_SIG_TYPE_NONE:
389029e88fdSLeon Romanovsky break;
390029e88fdSLeon Romanovsky case IB_SIG_TYPE_T10_DIF:
391029e88fdSLeon Romanovsky if (mem->sig.dif.pi_interval == wire->sig.dif.pi_interval &&
392029e88fdSLeon Romanovsky mem->sig_type == wire->sig_type) {
393029e88fdSLeon Romanovsky /* Same block structure */
394029e88fdSLeon Romanovsky basic->bsf_size_sbs |= 1 << 4;
395029e88fdSLeon Romanovsky if (mem->sig.dif.bg_type == wire->sig.dif.bg_type)
396029e88fdSLeon Romanovsky basic->wire.copy_byte_mask |= MLX5_CPY_GRD_MASK;
397029e88fdSLeon Romanovsky if (mem->sig.dif.app_tag == wire->sig.dif.app_tag)
398029e88fdSLeon Romanovsky basic->wire.copy_byte_mask |= MLX5_CPY_APP_MASK;
399029e88fdSLeon Romanovsky if (mem->sig.dif.ref_tag == wire->sig.dif.ref_tag)
400029e88fdSLeon Romanovsky basic->wire.copy_byte_mask |= MLX5_CPY_REF_MASK;
401029e88fdSLeon Romanovsky } else
402029e88fdSLeon Romanovsky basic->wire.bs_selector =
403029e88fdSLeon Romanovsky bs_selector(wire->sig.dif.pi_interval);
404029e88fdSLeon Romanovsky
405029e88fdSLeon Romanovsky basic->w_bfs_psv = cpu_to_be32(msig->psv_wire.psv_idx);
406029e88fdSLeon Romanovsky mlx5_fill_inl_bsf(wire, &bsf->w_inl);
407029e88fdSLeon Romanovsky break;
408029e88fdSLeon Romanovsky default:
409029e88fdSLeon Romanovsky return -EINVAL;
410029e88fdSLeon Romanovsky }
411029e88fdSLeon Romanovsky
412029e88fdSLeon Romanovsky return 0;
413029e88fdSLeon Romanovsky }
414029e88fdSLeon Romanovsky
415029e88fdSLeon Romanovsky
set_sig_data_segment(const struct ib_send_wr * send_wr,struct ib_mr * sig_mr,struct ib_sig_attrs * sig_attrs,struct mlx5_ib_qp * qp,void ** seg,int * size,void ** cur_edge)416029e88fdSLeon Romanovsky static int set_sig_data_segment(const struct ib_send_wr *send_wr,
417029e88fdSLeon Romanovsky struct ib_mr *sig_mr,
418029e88fdSLeon Romanovsky struct ib_sig_attrs *sig_attrs,
419029e88fdSLeon Romanovsky struct mlx5_ib_qp *qp, void **seg, int *size,
420029e88fdSLeon Romanovsky void **cur_edge)
421029e88fdSLeon Romanovsky {
422029e88fdSLeon Romanovsky struct mlx5_bsf *bsf;
423029e88fdSLeon Romanovsky u32 data_len;
424029e88fdSLeon Romanovsky u32 data_key;
425029e88fdSLeon Romanovsky u64 data_va;
426029e88fdSLeon Romanovsky u32 prot_len = 0;
427029e88fdSLeon Romanovsky u32 prot_key = 0;
428029e88fdSLeon Romanovsky u64 prot_va = 0;
429029e88fdSLeon Romanovsky bool prot = false;
430029e88fdSLeon Romanovsky int ret;
431029e88fdSLeon Romanovsky int wqe_size;
432029e88fdSLeon Romanovsky struct mlx5_ib_mr *mr = to_mmr(sig_mr);
433029e88fdSLeon Romanovsky struct mlx5_ib_mr *pi_mr = mr->pi_mr;
434029e88fdSLeon Romanovsky
435029e88fdSLeon Romanovsky data_len = pi_mr->data_length;
436029e88fdSLeon Romanovsky data_key = pi_mr->ibmr.lkey;
437029e88fdSLeon Romanovsky data_va = pi_mr->data_iova;
438029e88fdSLeon Romanovsky if (pi_mr->meta_ndescs) {
439029e88fdSLeon Romanovsky prot_len = pi_mr->meta_length;
440029e88fdSLeon Romanovsky prot_key = pi_mr->ibmr.lkey;
441029e88fdSLeon Romanovsky prot_va = pi_mr->pi_iova;
442029e88fdSLeon Romanovsky prot = true;
443029e88fdSLeon Romanovsky }
444029e88fdSLeon Romanovsky
445029e88fdSLeon Romanovsky if (!prot || (data_key == prot_key && data_va == prot_va &&
446029e88fdSLeon Romanovsky data_len == prot_len)) {
447029e88fdSLeon Romanovsky /**
448029e88fdSLeon Romanovsky * Source domain doesn't contain signature information
449029e88fdSLeon Romanovsky * or data and protection are interleaved in memory.
450029e88fdSLeon Romanovsky * So need construct:
451029e88fdSLeon Romanovsky * ------------------
452029e88fdSLeon Romanovsky * | data_klm |
453029e88fdSLeon Romanovsky * ------------------
454029e88fdSLeon Romanovsky * | BSF |
455029e88fdSLeon Romanovsky * ------------------
456029e88fdSLeon Romanovsky **/
457029e88fdSLeon Romanovsky struct mlx5_klm *data_klm = *seg;
458029e88fdSLeon Romanovsky
459029e88fdSLeon Romanovsky data_klm->bcount = cpu_to_be32(data_len);
460029e88fdSLeon Romanovsky data_klm->key = cpu_to_be32(data_key);
461029e88fdSLeon Romanovsky data_klm->va = cpu_to_be64(data_va);
462029e88fdSLeon Romanovsky wqe_size = ALIGN(sizeof(*data_klm), 64);
463029e88fdSLeon Romanovsky } else {
464029e88fdSLeon Romanovsky /**
465029e88fdSLeon Romanovsky * Source domain contains signature information
466029e88fdSLeon Romanovsky * So need construct a strided block format:
467029e88fdSLeon Romanovsky * ---------------------------
468029e88fdSLeon Romanovsky * | stride_block_ctrl |
469029e88fdSLeon Romanovsky * ---------------------------
470029e88fdSLeon Romanovsky * | data_klm |
471029e88fdSLeon Romanovsky * ---------------------------
472029e88fdSLeon Romanovsky * | prot_klm |
473029e88fdSLeon Romanovsky * ---------------------------
474029e88fdSLeon Romanovsky * | BSF |
475029e88fdSLeon Romanovsky * ---------------------------
476029e88fdSLeon Romanovsky **/
477029e88fdSLeon Romanovsky struct mlx5_stride_block_ctrl_seg *sblock_ctrl;
478029e88fdSLeon Romanovsky struct mlx5_stride_block_entry *data_sentry;
479029e88fdSLeon Romanovsky struct mlx5_stride_block_entry *prot_sentry;
480029e88fdSLeon Romanovsky u16 block_size = sig_attrs->mem.sig.dif.pi_interval;
481029e88fdSLeon Romanovsky int prot_size;
482029e88fdSLeon Romanovsky
483029e88fdSLeon Romanovsky sblock_ctrl = *seg;
484029e88fdSLeon Romanovsky data_sentry = (void *)sblock_ctrl + sizeof(*sblock_ctrl);
485029e88fdSLeon Romanovsky prot_sentry = (void *)data_sentry + sizeof(*data_sentry);
486029e88fdSLeon Romanovsky
487029e88fdSLeon Romanovsky prot_size = prot_field_size(sig_attrs->mem.sig_type);
488029e88fdSLeon Romanovsky if (!prot_size) {
489029e88fdSLeon Romanovsky pr_err("Bad block size given: %u\n", block_size);
490029e88fdSLeon Romanovsky return -EINVAL;
491029e88fdSLeon Romanovsky }
492029e88fdSLeon Romanovsky sblock_ctrl->bcount_per_cycle = cpu_to_be32(block_size +
493029e88fdSLeon Romanovsky prot_size);
494029e88fdSLeon Romanovsky sblock_ctrl->op = cpu_to_be32(MLX5_STRIDE_BLOCK_OP);
495029e88fdSLeon Romanovsky sblock_ctrl->repeat_count = cpu_to_be32(data_len / block_size);
496029e88fdSLeon Romanovsky sblock_ctrl->num_entries = cpu_to_be16(2);
497029e88fdSLeon Romanovsky
498029e88fdSLeon Romanovsky data_sentry->bcount = cpu_to_be16(block_size);
499029e88fdSLeon Romanovsky data_sentry->key = cpu_to_be32(data_key);
500029e88fdSLeon Romanovsky data_sentry->va = cpu_to_be64(data_va);
501029e88fdSLeon Romanovsky data_sentry->stride = cpu_to_be16(block_size);
502029e88fdSLeon Romanovsky
503029e88fdSLeon Romanovsky prot_sentry->bcount = cpu_to_be16(prot_size);
504029e88fdSLeon Romanovsky prot_sentry->key = cpu_to_be32(prot_key);
505029e88fdSLeon Romanovsky prot_sentry->va = cpu_to_be64(prot_va);
506029e88fdSLeon Romanovsky prot_sentry->stride = cpu_to_be16(prot_size);
507029e88fdSLeon Romanovsky
508029e88fdSLeon Romanovsky wqe_size = ALIGN(sizeof(*sblock_ctrl) + sizeof(*data_sentry) +
509029e88fdSLeon Romanovsky sizeof(*prot_sentry), 64);
510029e88fdSLeon Romanovsky }
511029e88fdSLeon Romanovsky
512029e88fdSLeon Romanovsky *seg += wqe_size;
513029e88fdSLeon Romanovsky *size += wqe_size / 16;
514029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
515029e88fdSLeon Romanovsky
516029e88fdSLeon Romanovsky bsf = *seg;
517029e88fdSLeon Romanovsky ret = mlx5_set_bsf(sig_mr, sig_attrs, bsf, data_len);
518029e88fdSLeon Romanovsky if (ret)
519029e88fdSLeon Romanovsky return -EINVAL;
520029e88fdSLeon Romanovsky
521029e88fdSLeon Romanovsky *seg += sizeof(*bsf);
522029e88fdSLeon Romanovsky *size += sizeof(*bsf) / 16;
523029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
524029e88fdSLeon Romanovsky
525029e88fdSLeon Romanovsky return 0;
526029e88fdSLeon Romanovsky }
527029e88fdSLeon Romanovsky
set_sig_mkey_segment(struct mlx5_mkey_seg * seg,struct ib_mr * sig_mr,int access_flags,u32 size,u32 length,u32 pdn)528029e88fdSLeon Romanovsky static void set_sig_mkey_segment(struct mlx5_mkey_seg *seg,
529029e88fdSLeon Romanovsky struct ib_mr *sig_mr, int access_flags,
530029e88fdSLeon Romanovsky u32 size, u32 length, u32 pdn)
531029e88fdSLeon Romanovsky {
532029e88fdSLeon Romanovsky u32 sig_key = sig_mr->rkey;
533029e88fdSLeon Romanovsky u8 sigerr = to_mmr(sig_mr)->sig->sigerr_count & 1;
534029e88fdSLeon Romanovsky
535029e88fdSLeon Romanovsky memset(seg, 0, sizeof(*seg));
536029e88fdSLeon Romanovsky
537029e88fdSLeon Romanovsky seg->flags = get_umr_flags(access_flags) | MLX5_MKC_ACCESS_MODE_KLMS;
538029e88fdSLeon Romanovsky seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00);
539029e88fdSLeon Romanovsky seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | sigerr << 26 |
540029e88fdSLeon Romanovsky MLX5_MKEY_BSF_EN | pdn);
541029e88fdSLeon Romanovsky seg->len = cpu_to_be64(length);
5428a8a5d37SAharon Landau seg->xlt_oct_size = cpu_to_be32(mlx5r_umr_get_xlt_octo(size));
543029e88fdSLeon Romanovsky seg->bsfs_octo_size = cpu_to_be32(MLX5_MKEY_BSF_OCTO_SIZE);
544029e88fdSLeon Romanovsky }
545029e88fdSLeon Romanovsky
set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg * umr,u32 size)546029e88fdSLeon Romanovsky static void set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
547029e88fdSLeon Romanovsky u32 size)
548029e88fdSLeon Romanovsky {
549029e88fdSLeon Romanovsky memset(umr, 0, sizeof(*umr));
550029e88fdSLeon Romanovsky
551029e88fdSLeon Romanovsky umr->flags = MLX5_FLAGS_INLINE | MLX5_FLAGS_CHECK_FREE;
5528a8a5d37SAharon Landau umr->xlt_octowords = cpu_to_be16(mlx5r_umr_get_xlt_octo(size));
553029e88fdSLeon Romanovsky umr->bsf_octowords = cpu_to_be16(MLX5_MKEY_BSF_OCTO_SIZE);
554029e88fdSLeon Romanovsky umr->mkey_mask = sig_mkey_mask();
555029e88fdSLeon Romanovsky }
556029e88fdSLeon Romanovsky
set_pi_umr_wr(const struct ib_send_wr * send_wr,struct mlx5_ib_qp * qp,void ** seg,int * size,void ** cur_edge)557029e88fdSLeon Romanovsky static int set_pi_umr_wr(const struct ib_send_wr *send_wr,
558029e88fdSLeon Romanovsky struct mlx5_ib_qp *qp, void **seg, int *size,
559029e88fdSLeon Romanovsky void **cur_edge)
560029e88fdSLeon Romanovsky {
561029e88fdSLeon Romanovsky const struct ib_reg_wr *wr = reg_wr(send_wr);
562029e88fdSLeon Romanovsky struct mlx5_ib_mr *sig_mr = to_mmr(wr->mr);
563029e88fdSLeon Romanovsky struct mlx5_ib_mr *pi_mr = sig_mr->pi_mr;
564029e88fdSLeon Romanovsky struct ib_sig_attrs *sig_attrs = sig_mr->ibmr.sig_attrs;
565029e88fdSLeon Romanovsky u32 pdn = to_mpd(qp->ibqp.pd)->pdn;
566029e88fdSLeon Romanovsky u32 xlt_size;
567029e88fdSLeon Romanovsky int region_len, ret;
568029e88fdSLeon Romanovsky
569029e88fdSLeon Romanovsky if (unlikely(send_wr->num_sge != 0) ||
570029e88fdSLeon Romanovsky unlikely(wr->access & IB_ACCESS_REMOTE_ATOMIC) ||
571029e88fdSLeon Romanovsky unlikely(!sig_mr->sig) || unlikely(!qp->ibqp.integrity_en) ||
572029e88fdSLeon Romanovsky unlikely(!sig_mr->sig->sig_status_checked))
573029e88fdSLeon Romanovsky return -EINVAL;
574029e88fdSLeon Romanovsky
575029e88fdSLeon Romanovsky /* length of the protected region, data + protection */
576029e88fdSLeon Romanovsky region_len = pi_mr->ibmr.length;
577029e88fdSLeon Romanovsky
578029e88fdSLeon Romanovsky /**
579029e88fdSLeon Romanovsky * KLM octoword size - if protection was provided
580029e88fdSLeon Romanovsky * then we use strided block format (3 octowords),
581029e88fdSLeon Romanovsky * else we use single KLM (1 octoword)
582029e88fdSLeon Romanovsky **/
583029e88fdSLeon Romanovsky if (sig_attrs->mem.sig_type != IB_SIG_TYPE_NONE)
584029e88fdSLeon Romanovsky xlt_size = 0x30;
585029e88fdSLeon Romanovsky else
586029e88fdSLeon Romanovsky xlt_size = sizeof(struct mlx5_klm);
587029e88fdSLeon Romanovsky
588029e88fdSLeon Romanovsky set_sig_umr_segment(*seg, xlt_size);
589029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
590029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
591029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
592029e88fdSLeon Romanovsky
593029e88fdSLeon Romanovsky set_sig_mkey_segment(*seg, wr->mr, wr->access, xlt_size, region_len,
594029e88fdSLeon Romanovsky pdn);
595029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_mkey_seg);
596029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_mkey_seg) / 16;
597029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
598029e88fdSLeon Romanovsky
599029e88fdSLeon Romanovsky ret = set_sig_data_segment(send_wr, wr->mr, sig_attrs, qp, seg, size,
600029e88fdSLeon Romanovsky cur_edge);
601029e88fdSLeon Romanovsky if (ret)
602029e88fdSLeon Romanovsky return ret;
603029e88fdSLeon Romanovsky
604029e88fdSLeon Romanovsky sig_mr->sig->sig_status_checked = false;
605029e88fdSLeon Romanovsky return 0;
606029e88fdSLeon Romanovsky }
607029e88fdSLeon Romanovsky
set_psv_wr(struct ib_sig_domain * domain,u32 psv_idx,void ** seg,int * size)608029e88fdSLeon Romanovsky static int set_psv_wr(struct ib_sig_domain *domain,
609029e88fdSLeon Romanovsky u32 psv_idx, void **seg, int *size)
610029e88fdSLeon Romanovsky {
611029e88fdSLeon Romanovsky struct mlx5_seg_set_psv *psv_seg = *seg;
612029e88fdSLeon Romanovsky
613029e88fdSLeon Romanovsky memset(psv_seg, 0, sizeof(*psv_seg));
614029e88fdSLeon Romanovsky psv_seg->psv_num = cpu_to_be32(psv_idx);
615029e88fdSLeon Romanovsky switch (domain->sig_type) {
616029e88fdSLeon Romanovsky case IB_SIG_TYPE_NONE:
617029e88fdSLeon Romanovsky break;
618029e88fdSLeon Romanovsky case IB_SIG_TYPE_T10_DIF:
619029e88fdSLeon Romanovsky psv_seg->transient_sig = cpu_to_be32(domain->sig.dif.bg << 16 |
620029e88fdSLeon Romanovsky domain->sig.dif.app_tag);
621029e88fdSLeon Romanovsky psv_seg->ref_tag = cpu_to_be32(domain->sig.dif.ref_tag);
622029e88fdSLeon Romanovsky break;
623029e88fdSLeon Romanovsky default:
624029e88fdSLeon Romanovsky pr_err("Bad signature type (%d) is given.\n",
625029e88fdSLeon Romanovsky domain->sig_type);
626029e88fdSLeon Romanovsky return -EINVAL;
627029e88fdSLeon Romanovsky }
628029e88fdSLeon Romanovsky
629029e88fdSLeon Romanovsky *seg += sizeof(*psv_seg);
630029e88fdSLeon Romanovsky *size += sizeof(*psv_seg) / 16;
631029e88fdSLeon Romanovsky
632029e88fdSLeon Romanovsky return 0;
633029e88fdSLeon Romanovsky }
634029e88fdSLeon Romanovsky
set_reg_wr(struct mlx5_ib_qp * qp,const struct ib_reg_wr * wr,void ** seg,int * size,void ** cur_edge,bool check_not_free)635029e88fdSLeon Romanovsky static int set_reg_wr(struct mlx5_ib_qp *qp,
636029e88fdSLeon Romanovsky const struct ib_reg_wr *wr,
637029e88fdSLeon Romanovsky void **seg, int *size, void **cur_edge,
638029e88fdSLeon Romanovsky bool check_not_free)
639029e88fdSLeon Romanovsky {
640029e88fdSLeon Romanovsky struct mlx5_ib_mr *mr = to_mmr(wr->mr);
641029e88fdSLeon Romanovsky struct mlx5_ib_pd *pd = to_mpd(qp->ibqp.pd);
642029e88fdSLeon Romanovsky struct mlx5_ib_dev *dev = to_mdev(pd->ibpd.device);
643ae0579acSAharon Landau int mr_list_size = (mr->mmkey.ndescs + mr->meta_ndescs) * mr->desc_size;
644029e88fdSLeon Romanovsky bool umr_inline = mr_list_size <= MLX5_IB_SQ_UMR_INLINE_THRESHOLD;
645029e88fdSLeon Romanovsky bool atomic = wr->access & IB_ACCESS_REMOTE_ATOMIC;
646029e88fdSLeon Romanovsky u8 flags = 0;
647029e88fdSLeon Romanovsky
6481477d44cSAvihai Horon /* Matches access in mlx5_set_umr_free_mkey().
6491477d44cSAvihai Horon * Relaxed Ordering is set implicitly in mlx5_set_umr_free_mkey() and
6501477d44cSAvihai Horon * kernel ULPs are not aware of it, so we don't set it here.
6511477d44cSAvihai Horon */
652f49c856aSAharon Landau if (!mlx5r_umr_can_reconfig(dev, 0, wr->access)) {
6538383da3eSJason Gunthorpe mlx5_ib_warn(
6548383da3eSJason Gunthorpe to_mdev(qp->ibqp.device),
6558383da3eSJason Gunthorpe "Fast update for MR access flags is not possible\n");
656029e88fdSLeon Romanovsky return -EINVAL;
657029e88fdSLeon Romanovsky }
658029e88fdSLeon Romanovsky
659029e88fdSLeon Romanovsky if (unlikely(wr->wr.send_flags & IB_SEND_INLINE)) {
660029e88fdSLeon Romanovsky mlx5_ib_warn(to_mdev(qp->ibqp.device),
661029e88fdSLeon Romanovsky "Invalid IB_SEND_INLINE send flag\n");
662029e88fdSLeon Romanovsky return -EINVAL;
663029e88fdSLeon Romanovsky }
664029e88fdSLeon Romanovsky
665029e88fdSLeon Romanovsky if (check_not_free)
666029e88fdSLeon Romanovsky flags |= MLX5_UMR_CHECK_NOT_FREE;
667029e88fdSLeon Romanovsky if (umr_inline)
668029e88fdSLeon Romanovsky flags |= MLX5_UMR_INLINE;
669029e88fdSLeon Romanovsky
670029e88fdSLeon Romanovsky set_reg_umr_seg(*seg, mr, flags, atomic);
671029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
672029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
673029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
674029e88fdSLeon Romanovsky
675029e88fdSLeon Romanovsky set_reg_mkey_seg(*seg, mr, wr->key, wr->access);
676029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_mkey_seg);
677029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_mkey_seg) / 16;
678029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
679029e88fdSLeon Romanovsky
680029e88fdSLeon Romanovsky if (umr_inline) {
681fe765aebSAharon Landau mlx5r_memcpy_send_wqe(&qp->sq, cur_edge, seg, size, mr->descs,
682029e88fdSLeon Romanovsky mr_list_size);
683029e88fdSLeon Romanovsky *size = ALIGN(*size, MLX5_SEND_WQE_BB >> 4);
684029e88fdSLeon Romanovsky } else {
685029e88fdSLeon Romanovsky set_reg_data_seg(*seg, mr, pd);
686029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_wqe_data_seg);
687029e88fdSLeon Romanovsky *size += (sizeof(struct mlx5_wqe_data_seg) / 16);
688029e88fdSLeon Romanovsky }
689029e88fdSLeon Romanovsky return 0;
690029e88fdSLeon Romanovsky }
691029e88fdSLeon Romanovsky
set_linv_wr(struct mlx5_ib_qp * qp,void ** seg,int * size,void ** cur_edge)692029e88fdSLeon Romanovsky static void set_linv_wr(struct mlx5_ib_qp *qp, void **seg, int *size,
693029e88fdSLeon Romanovsky void **cur_edge)
694029e88fdSLeon Romanovsky {
695029e88fdSLeon Romanovsky set_linv_umr_seg(*seg);
696029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
697029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
698029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
699029e88fdSLeon Romanovsky set_linv_mkey_seg(*seg);
700029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_mkey_seg);
701029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_mkey_seg) / 16;
702029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
703029e88fdSLeon Romanovsky }
704029e88fdSLeon Romanovsky
dump_wqe(struct mlx5_ib_qp * qp,u32 idx,int size_16)705029e88fdSLeon Romanovsky static void dump_wqe(struct mlx5_ib_qp *qp, u32 idx, int size_16)
706029e88fdSLeon Romanovsky {
707029e88fdSLeon Romanovsky __be32 *p = NULL;
708029e88fdSLeon Romanovsky int i, j;
709029e88fdSLeon Romanovsky
710029e88fdSLeon Romanovsky pr_debug("dump WQE index %u:\n", idx);
711029e88fdSLeon Romanovsky for (i = 0, j = 0; i < size_16 * 4; i += 4, j += 4) {
712029e88fdSLeon Romanovsky if ((i & 0xf) == 0) {
713029e88fdSLeon Romanovsky p = mlx5_frag_buf_get_wqe(&qp->sq.fbc, idx);
714029e88fdSLeon Romanovsky pr_debug("WQBB at %p:\n", (void *)p);
715029e88fdSLeon Romanovsky j = 0;
716029e88fdSLeon Romanovsky idx = (idx + 1) & (qp->sq.wqe_cnt - 1);
717029e88fdSLeon Romanovsky }
718029e88fdSLeon Romanovsky pr_debug("%08x %08x %08x %08x\n", be32_to_cpu(p[j]),
719029e88fdSLeon Romanovsky be32_to_cpu(p[j + 1]), be32_to_cpu(p[j + 2]),
720029e88fdSLeon Romanovsky be32_to_cpu(p[j + 3]));
721029e88fdSLeon Romanovsky }
722029e88fdSLeon Romanovsky }
723029e88fdSLeon Romanovsky
mlx5r_begin_wqe(struct mlx5_ib_qp * qp,void ** seg,struct mlx5_wqe_ctrl_seg ** ctrl,unsigned int * idx,int * size,void ** cur_edge,int nreq,__be32 general_id,bool send_signaled,bool solicited)724fe765aebSAharon Landau int mlx5r_begin_wqe(struct mlx5_ib_qp *qp, void **seg,
725fe765aebSAharon Landau struct mlx5_wqe_ctrl_seg **ctrl, unsigned int *idx,
726fe765aebSAharon Landau int *size, void **cur_edge, int nreq, __be32 general_id,
727029e88fdSLeon Romanovsky bool send_signaled, bool solicited)
728029e88fdSLeon Romanovsky {
729fe765aebSAharon Landau if (unlikely(mlx5r_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)))
730029e88fdSLeon Romanovsky return -ENOMEM;
731029e88fdSLeon Romanovsky
732029e88fdSLeon Romanovsky *idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1);
733029e88fdSLeon Romanovsky *seg = mlx5_frag_buf_get_wqe(&qp->sq.fbc, *idx);
734029e88fdSLeon Romanovsky *ctrl = *seg;
735029e88fdSLeon Romanovsky *(uint32_t *)(*seg + 8) = 0;
736fe765aebSAharon Landau (*ctrl)->general_id = general_id;
737029e88fdSLeon Romanovsky (*ctrl)->fm_ce_se = qp->sq_signal_bits |
738029e88fdSLeon Romanovsky (send_signaled ? MLX5_WQE_CTRL_CQ_UPDATE : 0) |
739029e88fdSLeon Romanovsky (solicited ? MLX5_WQE_CTRL_SOLICITED : 0);
740029e88fdSLeon Romanovsky
741029e88fdSLeon Romanovsky *seg += sizeof(**ctrl);
742029e88fdSLeon Romanovsky *size = sizeof(**ctrl) / 16;
743029e88fdSLeon Romanovsky *cur_edge = qp->sq.cur_edge;
744029e88fdSLeon Romanovsky
745029e88fdSLeon Romanovsky return 0;
746029e88fdSLeon Romanovsky }
747029e88fdSLeon Romanovsky
begin_wqe(struct mlx5_ib_qp * qp,void ** seg,struct mlx5_wqe_ctrl_seg ** ctrl,const struct ib_send_wr * wr,unsigned int * idx,int * size,void ** cur_edge,int nreq)748029e88fdSLeon Romanovsky static int begin_wqe(struct mlx5_ib_qp *qp, void **seg,
749029e88fdSLeon Romanovsky struct mlx5_wqe_ctrl_seg **ctrl,
750029e88fdSLeon Romanovsky const struct ib_send_wr *wr, unsigned int *idx, int *size,
751029e88fdSLeon Romanovsky void **cur_edge, int nreq)
752029e88fdSLeon Romanovsky {
753fe765aebSAharon Landau return mlx5r_begin_wqe(qp, seg, ctrl, idx, size, cur_edge, nreq,
754fe765aebSAharon Landau send_ieth(wr), wr->send_flags & IB_SEND_SIGNALED,
755029e88fdSLeon Romanovsky wr->send_flags & IB_SEND_SOLICITED);
756029e88fdSLeon Romanovsky }
757029e88fdSLeon Romanovsky
mlx5r_finish_wqe(struct mlx5_ib_qp * qp,struct mlx5_wqe_ctrl_seg * ctrl,void * seg,u8 size,void * cur_edge,unsigned int idx,u64 wr_id,int nreq,u8 fence,u32 mlx5_opcode)758fe765aebSAharon Landau void mlx5r_finish_wqe(struct mlx5_ib_qp *qp, struct mlx5_wqe_ctrl_seg *ctrl,
759fe765aebSAharon Landau void *seg, u8 size, void *cur_edge, unsigned int idx,
760fe765aebSAharon Landau u64 wr_id, int nreq, u8 fence, u32 mlx5_opcode)
761029e88fdSLeon Romanovsky {
762029e88fdSLeon Romanovsky u8 opmod = 0;
763029e88fdSLeon Romanovsky
764029e88fdSLeon Romanovsky ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) |
765029e88fdSLeon Romanovsky mlx5_opcode | ((u32)opmod << 24));
766029e88fdSLeon Romanovsky ctrl->qpn_ds = cpu_to_be32(size | (qp->trans_qp.base.mqp.qpn << 8));
767029e88fdSLeon Romanovsky ctrl->fm_ce_se |= fence;
768029e88fdSLeon Romanovsky if (unlikely(qp->flags_en & MLX5_QP_FLAG_SIGNATURE))
769029e88fdSLeon Romanovsky ctrl->signature = wq_sig(ctrl);
770029e88fdSLeon Romanovsky
771029e88fdSLeon Romanovsky qp->sq.wrid[idx] = wr_id;
772029e88fdSLeon Romanovsky qp->sq.w_list[idx].opcode = mlx5_opcode;
773029e88fdSLeon Romanovsky qp->sq.wqe_head[idx] = qp->sq.head + nreq;
774029e88fdSLeon Romanovsky qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB);
775029e88fdSLeon Romanovsky qp->sq.w_list[idx].next = qp->sq.cur_post;
776029e88fdSLeon Romanovsky
777029e88fdSLeon Romanovsky /* We save the edge which was possibly updated during the WQE
778029e88fdSLeon Romanovsky * construction, into SQ's cache.
779029e88fdSLeon Romanovsky */
780029e88fdSLeon Romanovsky seg = PTR_ALIGN(seg, MLX5_SEND_WQE_BB);
781029e88fdSLeon Romanovsky qp->sq.cur_edge = (unlikely(seg == cur_edge)) ?
782029e88fdSLeon Romanovsky get_sq_edge(&qp->sq, qp->sq.cur_post &
783029e88fdSLeon Romanovsky (qp->sq.wqe_cnt - 1)) :
784029e88fdSLeon Romanovsky cur_edge;
785029e88fdSLeon Romanovsky }
786029e88fdSLeon Romanovsky
handle_rdma_op(const struct ib_send_wr * wr,void ** seg,int * size)787029e88fdSLeon Romanovsky static void handle_rdma_op(const struct ib_send_wr *wr, void **seg, int *size)
788029e88fdSLeon Romanovsky {
789029e88fdSLeon Romanovsky set_raddr_seg(*seg, rdma_wr(wr)->remote_addr, rdma_wr(wr)->rkey);
790029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_wqe_raddr_seg);
791029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
792029e88fdSLeon Romanovsky }
793029e88fdSLeon Romanovsky
handle_local_inv(struct mlx5_ib_qp * qp,const struct ib_send_wr * wr,struct mlx5_wqe_ctrl_seg ** ctrl,void ** seg,int * size,void ** cur_edge,unsigned int idx)794029e88fdSLeon Romanovsky static void handle_local_inv(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr,
795029e88fdSLeon Romanovsky struct mlx5_wqe_ctrl_seg **ctrl, void **seg,
796029e88fdSLeon Romanovsky int *size, void **cur_edge, unsigned int idx)
797029e88fdSLeon Romanovsky {
798029e88fdSLeon Romanovsky qp->sq.wr_data[idx] = IB_WR_LOCAL_INV;
799029e88fdSLeon Romanovsky (*ctrl)->imm = cpu_to_be32(wr->ex.invalidate_rkey);
800029e88fdSLeon Romanovsky set_linv_wr(qp, seg, size, cur_edge);
801029e88fdSLeon Romanovsky }
802029e88fdSLeon Romanovsky
handle_reg_mr(struct mlx5_ib_qp * qp,const struct ib_send_wr * wr,struct mlx5_wqe_ctrl_seg ** ctrl,void ** seg,int * size,void ** cur_edge,unsigned int idx)803029e88fdSLeon Romanovsky static int handle_reg_mr(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr,
804029e88fdSLeon Romanovsky struct mlx5_wqe_ctrl_seg **ctrl, void **seg, int *size,
805029e88fdSLeon Romanovsky void **cur_edge, unsigned int idx)
806029e88fdSLeon Romanovsky {
807029e88fdSLeon Romanovsky qp->sq.wr_data[idx] = IB_WR_REG_MR;
808029e88fdSLeon Romanovsky (*ctrl)->imm = cpu_to_be32(reg_wr(wr)->key);
809029e88fdSLeon Romanovsky return set_reg_wr(qp, reg_wr(wr), seg, size, cur_edge, true);
810029e88fdSLeon Romanovsky }
811029e88fdSLeon Romanovsky
handle_psv(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,const struct ib_send_wr * wr,struct mlx5_wqe_ctrl_seg ** ctrl,void ** seg,int * size,void ** cur_edge,unsigned int * idx,int nreq,struct ib_sig_domain * domain,u32 psv_index,u8 next_fence)812029e88fdSLeon Romanovsky static int handle_psv(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
813029e88fdSLeon Romanovsky const struct ib_send_wr *wr,
814029e88fdSLeon Romanovsky struct mlx5_wqe_ctrl_seg **ctrl, void **seg, int *size,
815029e88fdSLeon Romanovsky void **cur_edge, unsigned int *idx, int nreq,
816029e88fdSLeon Romanovsky struct ib_sig_domain *domain, u32 psv_index,
817029e88fdSLeon Romanovsky u8 next_fence)
818029e88fdSLeon Romanovsky {
819029e88fdSLeon Romanovsky int err;
820029e88fdSLeon Romanovsky
821029e88fdSLeon Romanovsky /*
822029e88fdSLeon Romanovsky * SET_PSV WQEs are not signaled and solicited on error.
823029e88fdSLeon Romanovsky */
824fe765aebSAharon Landau err = mlx5r_begin_wqe(qp, seg, ctrl, idx, size, cur_edge, nreq,
825fe765aebSAharon Landau send_ieth(wr), false, true);
826029e88fdSLeon Romanovsky if (unlikely(err)) {
827029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "\n");
828029e88fdSLeon Romanovsky err = -ENOMEM;
829029e88fdSLeon Romanovsky goto out;
830029e88fdSLeon Romanovsky }
831029e88fdSLeon Romanovsky err = set_psv_wr(domain, psv_index, seg, size);
832029e88fdSLeon Romanovsky if (unlikely(err)) {
833029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "\n");
834029e88fdSLeon Romanovsky goto out;
835029e88fdSLeon Romanovsky }
836fe765aebSAharon Landau mlx5r_finish_wqe(qp, *ctrl, *seg, *size, *cur_edge, *idx, wr->wr_id,
837fe765aebSAharon Landau nreq, next_fence, MLX5_OPCODE_SET_PSV);
838029e88fdSLeon Romanovsky
839029e88fdSLeon Romanovsky out:
840029e88fdSLeon Romanovsky return err;
841029e88fdSLeon Romanovsky }
842029e88fdSLeon Romanovsky
handle_reg_mr_integrity(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,const struct ib_send_wr * wr,struct mlx5_wqe_ctrl_seg ** ctrl,void ** seg,int * size,void ** cur_edge,unsigned int * idx,int nreq,u8 fence,u8 next_fence)843029e88fdSLeon Romanovsky static int handle_reg_mr_integrity(struct mlx5_ib_dev *dev,
844029e88fdSLeon Romanovsky struct mlx5_ib_qp *qp,
845029e88fdSLeon Romanovsky const struct ib_send_wr *wr,
846029e88fdSLeon Romanovsky struct mlx5_wqe_ctrl_seg **ctrl, void **seg,
847029e88fdSLeon Romanovsky int *size, void **cur_edge,
848029e88fdSLeon Romanovsky unsigned int *idx, int nreq, u8 fence,
849029e88fdSLeon Romanovsky u8 next_fence)
850029e88fdSLeon Romanovsky {
851029e88fdSLeon Romanovsky struct mlx5_ib_mr *mr;
852029e88fdSLeon Romanovsky struct mlx5_ib_mr *pi_mr;
853029e88fdSLeon Romanovsky struct mlx5_ib_mr pa_pi_mr;
854029e88fdSLeon Romanovsky struct ib_sig_attrs *sig_attrs;
855029e88fdSLeon Romanovsky struct ib_reg_wr reg_pi_wr;
856029e88fdSLeon Romanovsky int err;
857029e88fdSLeon Romanovsky
858029e88fdSLeon Romanovsky qp->sq.wr_data[*idx] = IB_WR_REG_MR_INTEGRITY;
859029e88fdSLeon Romanovsky
860029e88fdSLeon Romanovsky mr = to_mmr(reg_wr(wr)->mr);
861029e88fdSLeon Romanovsky pi_mr = mr->pi_mr;
862029e88fdSLeon Romanovsky
863029e88fdSLeon Romanovsky if (pi_mr) {
864029e88fdSLeon Romanovsky memset(®_pi_wr, 0,
865029e88fdSLeon Romanovsky sizeof(struct ib_reg_wr));
866029e88fdSLeon Romanovsky
867029e88fdSLeon Romanovsky reg_pi_wr.mr = &pi_mr->ibmr;
868029e88fdSLeon Romanovsky reg_pi_wr.access = reg_wr(wr)->access;
869029e88fdSLeon Romanovsky reg_pi_wr.key = pi_mr->ibmr.rkey;
870029e88fdSLeon Romanovsky
871029e88fdSLeon Romanovsky (*ctrl)->imm = cpu_to_be32(reg_pi_wr.key);
872029e88fdSLeon Romanovsky /* UMR for data + prot registration */
873029e88fdSLeon Romanovsky err = set_reg_wr(qp, ®_pi_wr, seg, size, cur_edge, false);
874029e88fdSLeon Romanovsky if (unlikely(err))
875029e88fdSLeon Romanovsky goto out;
876029e88fdSLeon Romanovsky
877fe765aebSAharon Landau mlx5r_finish_wqe(qp, *ctrl, *seg, *size, *cur_edge, *idx,
878fe765aebSAharon Landau wr->wr_id, nreq, fence, MLX5_OPCODE_UMR);
879029e88fdSLeon Romanovsky
880029e88fdSLeon Romanovsky err = begin_wqe(qp, seg, ctrl, wr, idx, size, cur_edge, nreq);
881029e88fdSLeon Romanovsky if (unlikely(err)) {
882029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "\n");
883029e88fdSLeon Romanovsky err = -ENOMEM;
884029e88fdSLeon Romanovsky goto out;
885029e88fdSLeon Romanovsky }
886029e88fdSLeon Romanovsky } else {
887029e88fdSLeon Romanovsky memset(&pa_pi_mr, 0, sizeof(struct mlx5_ib_mr));
888029e88fdSLeon Romanovsky /* No UMR, use local_dma_lkey */
889029e88fdSLeon Romanovsky pa_pi_mr.ibmr.lkey = mr->ibmr.pd->local_dma_lkey;
890ae0579acSAharon Landau pa_pi_mr.mmkey.ndescs = mr->mmkey.ndescs;
891029e88fdSLeon Romanovsky pa_pi_mr.data_length = mr->data_length;
892029e88fdSLeon Romanovsky pa_pi_mr.data_iova = mr->data_iova;
893029e88fdSLeon Romanovsky if (mr->meta_ndescs) {
894029e88fdSLeon Romanovsky pa_pi_mr.meta_ndescs = mr->meta_ndescs;
895029e88fdSLeon Romanovsky pa_pi_mr.meta_length = mr->meta_length;
896029e88fdSLeon Romanovsky pa_pi_mr.pi_iova = mr->pi_iova;
897029e88fdSLeon Romanovsky }
898029e88fdSLeon Romanovsky
899029e88fdSLeon Romanovsky pa_pi_mr.ibmr.length = mr->ibmr.length;
900029e88fdSLeon Romanovsky mr->pi_mr = &pa_pi_mr;
901029e88fdSLeon Romanovsky }
902029e88fdSLeon Romanovsky (*ctrl)->imm = cpu_to_be32(mr->ibmr.rkey);
903029e88fdSLeon Romanovsky /* UMR for sig MR */
904029e88fdSLeon Romanovsky err = set_pi_umr_wr(wr, qp, seg, size, cur_edge);
905029e88fdSLeon Romanovsky if (unlikely(err)) {
906029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "\n");
907029e88fdSLeon Romanovsky goto out;
908029e88fdSLeon Romanovsky }
909fe765aebSAharon Landau mlx5r_finish_wqe(qp, *ctrl, *seg, *size, *cur_edge, *idx, wr->wr_id,
910fe765aebSAharon Landau nreq, fence, MLX5_OPCODE_UMR);
911029e88fdSLeon Romanovsky
912029e88fdSLeon Romanovsky sig_attrs = mr->ibmr.sig_attrs;
913029e88fdSLeon Romanovsky err = handle_psv(dev, qp, wr, ctrl, seg, size, cur_edge, idx, nreq,
914029e88fdSLeon Romanovsky &sig_attrs->mem, mr->sig->psv_memory.psv_idx,
915029e88fdSLeon Romanovsky next_fence);
916029e88fdSLeon Romanovsky if (unlikely(err))
917029e88fdSLeon Romanovsky goto out;
918029e88fdSLeon Romanovsky
919029e88fdSLeon Romanovsky err = handle_psv(dev, qp, wr, ctrl, seg, size, cur_edge, idx, nreq,
920029e88fdSLeon Romanovsky &sig_attrs->wire, mr->sig->psv_wire.psv_idx,
921029e88fdSLeon Romanovsky next_fence);
922029e88fdSLeon Romanovsky if (unlikely(err))
923029e88fdSLeon Romanovsky goto out;
924029e88fdSLeon Romanovsky
925029e88fdSLeon Romanovsky qp->next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
926029e88fdSLeon Romanovsky
927029e88fdSLeon Romanovsky out:
928029e88fdSLeon Romanovsky return err;
929029e88fdSLeon Romanovsky }
930029e88fdSLeon Romanovsky
handle_qpt_rc(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,const struct ib_send_wr * wr,struct mlx5_wqe_ctrl_seg ** ctrl,void ** seg,int * size,void ** cur_edge,unsigned int * idx,int nreq,u8 fence,u8 next_fence,int * num_sge)931029e88fdSLeon Romanovsky static int handle_qpt_rc(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
932029e88fdSLeon Romanovsky const struct ib_send_wr *wr,
933029e88fdSLeon Romanovsky struct mlx5_wqe_ctrl_seg **ctrl, void **seg, int *size,
934029e88fdSLeon Romanovsky void **cur_edge, unsigned int *idx, int nreq, u8 fence,
935029e88fdSLeon Romanovsky u8 next_fence, int *num_sge)
936029e88fdSLeon Romanovsky {
937029e88fdSLeon Romanovsky int err = 0;
938029e88fdSLeon Romanovsky
939029e88fdSLeon Romanovsky switch (wr->opcode) {
940029e88fdSLeon Romanovsky case IB_WR_RDMA_READ:
941029e88fdSLeon Romanovsky case IB_WR_RDMA_WRITE:
942029e88fdSLeon Romanovsky case IB_WR_RDMA_WRITE_WITH_IMM:
943029e88fdSLeon Romanovsky handle_rdma_op(wr, seg, size);
944029e88fdSLeon Romanovsky break;
945029e88fdSLeon Romanovsky
946029e88fdSLeon Romanovsky case IB_WR_ATOMIC_CMP_AND_SWP:
947029e88fdSLeon Romanovsky case IB_WR_ATOMIC_FETCH_AND_ADD:
948029e88fdSLeon Romanovsky case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
949029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "Atomic operations are not supported yet\n");
950029e88fdSLeon Romanovsky err = -EOPNOTSUPP;
951029e88fdSLeon Romanovsky goto out;
952029e88fdSLeon Romanovsky
953029e88fdSLeon Romanovsky case IB_WR_LOCAL_INV:
954029e88fdSLeon Romanovsky handle_local_inv(qp, wr, ctrl, seg, size, cur_edge, *idx);
955029e88fdSLeon Romanovsky *num_sge = 0;
956029e88fdSLeon Romanovsky break;
957029e88fdSLeon Romanovsky
958029e88fdSLeon Romanovsky case IB_WR_REG_MR:
959029e88fdSLeon Romanovsky err = handle_reg_mr(qp, wr, ctrl, seg, size, cur_edge, *idx);
960029e88fdSLeon Romanovsky if (unlikely(err))
961029e88fdSLeon Romanovsky goto out;
962029e88fdSLeon Romanovsky *num_sge = 0;
963029e88fdSLeon Romanovsky break;
964029e88fdSLeon Romanovsky
965029e88fdSLeon Romanovsky case IB_WR_REG_MR_INTEGRITY:
966029e88fdSLeon Romanovsky err = handle_reg_mr_integrity(dev, qp, wr, ctrl, seg, size,
967029e88fdSLeon Romanovsky cur_edge, idx, nreq, fence,
968029e88fdSLeon Romanovsky next_fence);
969029e88fdSLeon Romanovsky if (unlikely(err))
970029e88fdSLeon Romanovsky goto out;
971029e88fdSLeon Romanovsky *num_sge = 0;
972029e88fdSLeon Romanovsky break;
973029e88fdSLeon Romanovsky
974029e88fdSLeon Romanovsky default:
975029e88fdSLeon Romanovsky break;
976029e88fdSLeon Romanovsky }
977029e88fdSLeon Romanovsky
978029e88fdSLeon Romanovsky out:
979029e88fdSLeon Romanovsky return err;
980029e88fdSLeon Romanovsky }
981029e88fdSLeon Romanovsky
handle_qpt_uc(const struct ib_send_wr * wr,void ** seg,int * size)982029e88fdSLeon Romanovsky static void handle_qpt_uc(const struct ib_send_wr *wr, void **seg, int *size)
983029e88fdSLeon Romanovsky {
984029e88fdSLeon Romanovsky switch (wr->opcode) {
985029e88fdSLeon Romanovsky case IB_WR_RDMA_WRITE:
986029e88fdSLeon Romanovsky case IB_WR_RDMA_WRITE_WITH_IMM:
987029e88fdSLeon Romanovsky handle_rdma_op(wr, seg, size);
988029e88fdSLeon Romanovsky break;
989029e88fdSLeon Romanovsky default:
990029e88fdSLeon Romanovsky break;
991029e88fdSLeon Romanovsky }
992029e88fdSLeon Romanovsky }
993029e88fdSLeon Romanovsky
handle_qpt_hw_gsi(struct mlx5_ib_qp * qp,const struct ib_send_wr * wr,void ** seg,int * size,void ** cur_edge)994029e88fdSLeon Romanovsky static void handle_qpt_hw_gsi(struct mlx5_ib_qp *qp,
995029e88fdSLeon Romanovsky const struct ib_send_wr *wr, void **seg,
996029e88fdSLeon Romanovsky int *size, void **cur_edge)
997029e88fdSLeon Romanovsky {
998029e88fdSLeon Romanovsky set_datagram_seg(*seg, wr);
999029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_wqe_datagram_seg);
1000029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_wqe_datagram_seg) / 16;
1001029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
1002029e88fdSLeon Romanovsky }
1003029e88fdSLeon Romanovsky
handle_qpt_ud(struct mlx5_ib_qp * qp,const struct ib_send_wr * wr,void ** seg,int * size,void ** cur_edge)1004029e88fdSLeon Romanovsky static void handle_qpt_ud(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr,
1005029e88fdSLeon Romanovsky void **seg, int *size, void **cur_edge)
1006029e88fdSLeon Romanovsky {
1007029e88fdSLeon Romanovsky set_datagram_seg(*seg, wr);
1008029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_wqe_datagram_seg);
1009029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_wqe_datagram_seg) / 16;
1010029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
1011029e88fdSLeon Romanovsky
1012029e88fdSLeon Romanovsky /* handle qp that supports ud offload */
1013029e88fdSLeon Romanovsky if (qp->flags & IB_QP_CREATE_IPOIB_UD_LSO) {
1014029e88fdSLeon Romanovsky struct mlx5_wqe_eth_pad *pad;
1015029e88fdSLeon Romanovsky
1016029e88fdSLeon Romanovsky pad = *seg;
1017029e88fdSLeon Romanovsky memset(pad, 0, sizeof(struct mlx5_wqe_eth_pad));
1018029e88fdSLeon Romanovsky *seg += sizeof(struct mlx5_wqe_eth_pad);
1019029e88fdSLeon Romanovsky *size += sizeof(struct mlx5_wqe_eth_pad) / 16;
1020029e88fdSLeon Romanovsky set_eth_seg(wr, qp, seg, size, cur_edge);
1021029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
1022029e88fdSLeon Romanovsky }
1023029e88fdSLeon Romanovsky }
1024029e88fdSLeon Romanovsky
mlx5r_ring_db(struct mlx5_ib_qp * qp,unsigned int nreq,struct mlx5_wqe_ctrl_seg * ctrl)1025fe765aebSAharon Landau void mlx5r_ring_db(struct mlx5_ib_qp *qp, unsigned int nreq,
1026fe765aebSAharon Landau struct mlx5_wqe_ctrl_seg *ctrl)
1027fe765aebSAharon Landau {
1028fe765aebSAharon Landau struct mlx5_bf *bf = &qp->bf;
1029fe765aebSAharon Landau
1030fe765aebSAharon Landau qp->sq.head += nreq;
1031fe765aebSAharon Landau
1032fe765aebSAharon Landau /* Make sure that descriptors are written before
1033fe765aebSAharon Landau * updating doorbell record and ringing the doorbell
1034fe765aebSAharon Landau */
1035fe765aebSAharon Landau wmb();
1036fe765aebSAharon Landau
1037fe765aebSAharon Landau qp->db.db[MLX5_SND_DBR] = cpu_to_be32(qp->sq.cur_post);
1038fe765aebSAharon Landau
1039fe765aebSAharon Landau /* Make sure doorbell record is visible to the HCA before
1040fe765aebSAharon Landau * we hit doorbell.
1041fe765aebSAharon Landau */
1042fe765aebSAharon Landau wmb();
1043fe765aebSAharon Landau
1044fe765aebSAharon Landau mlx5_write64((__be32 *)ctrl, bf->bfreg->map + bf->offset);
1045fe765aebSAharon Landau /* Make sure doorbells don't leak out of SQ spinlock
1046fe765aebSAharon Landau * and reach the HCA out of order.
1047fe765aebSAharon Landau */
1048fe765aebSAharon Landau bf->offset ^= bf->buf_size;
1049fe765aebSAharon Landau }
1050fe765aebSAharon Landau
mlx5_ib_post_send(struct ib_qp * ibqp,const struct ib_send_wr * wr,const struct ib_send_wr ** bad_wr,bool drain)1051029e88fdSLeon Romanovsky int mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
1052029e88fdSLeon Romanovsky const struct ib_send_wr **bad_wr, bool drain)
1053029e88fdSLeon Romanovsky {
1054029e88fdSLeon Romanovsky struct mlx5_wqe_ctrl_seg *ctrl = NULL; /* compiler warning */
1055029e88fdSLeon Romanovsky struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
1056029e88fdSLeon Romanovsky struct mlx5_core_dev *mdev = dev->mdev;
10579ecf6ac1SMaor Gottlieb struct mlx5_ib_qp *qp = to_mqp(ibqp);
1058029e88fdSLeon Romanovsky struct mlx5_wqe_xrc_seg *xrc;
1059029e88fdSLeon Romanovsky void *cur_edge;
10603f649ab7SKees Cook int size;
1061029e88fdSLeon Romanovsky unsigned long flags;
1062029e88fdSLeon Romanovsky unsigned int idx;
1063029e88fdSLeon Romanovsky int err = 0;
1064029e88fdSLeon Romanovsky int num_sge;
1065029e88fdSLeon Romanovsky void *seg;
1066029e88fdSLeon Romanovsky int nreq;
1067029e88fdSLeon Romanovsky int i;
1068029e88fdSLeon Romanovsky u8 next_fence = 0;
1069029e88fdSLeon Romanovsky u8 fence;
1070029e88fdSLeon Romanovsky
1071029e88fdSLeon Romanovsky if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR &&
1072029e88fdSLeon Romanovsky !drain)) {
1073029e88fdSLeon Romanovsky *bad_wr = wr;
1074029e88fdSLeon Romanovsky return -EIO;
1075029e88fdSLeon Romanovsky }
1076029e88fdSLeon Romanovsky
10779ecf6ac1SMaor Gottlieb if (qp->type == IB_QPT_GSI)
1078029e88fdSLeon Romanovsky return mlx5_ib_gsi_post_send(ibqp, wr, bad_wr);
1079029e88fdSLeon Romanovsky
1080029e88fdSLeon Romanovsky spin_lock_irqsave(&qp->sq.lock, flags);
1081029e88fdSLeon Romanovsky
1082029e88fdSLeon Romanovsky for (nreq = 0; wr; nreq++, wr = wr->next) {
1083029e88fdSLeon Romanovsky if (unlikely(wr->opcode >= ARRAY_SIZE(mlx5_ib_opcode))) {
1084029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "\n");
1085029e88fdSLeon Romanovsky err = -EINVAL;
1086029e88fdSLeon Romanovsky *bad_wr = wr;
1087029e88fdSLeon Romanovsky goto out;
1088029e88fdSLeon Romanovsky }
1089029e88fdSLeon Romanovsky
1090029e88fdSLeon Romanovsky num_sge = wr->num_sge;
1091029e88fdSLeon Romanovsky if (unlikely(num_sge > qp->sq.max_gs)) {
1092029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "\n");
1093029e88fdSLeon Romanovsky err = -EINVAL;
1094029e88fdSLeon Romanovsky *bad_wr = wr;
1095029e88fdSLeon Romanovsky goto out;
1096029e88fdSLeon Romanovsky }
1097029e88fdSLeon Romanovsky
1098029e88fdSLeon Romanovsky err = begin_wqe(qp, &seg, &ctrl, wr, &idx, &size, &cur_edge,
1099029e88fdSLeon Romanovsky nreq);
1100029e88fdSLeon Romanovsky if (err) {
1101029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "\n");
1102029e88fdSLeon Romanovsky err = -ENOMEM;
1103029e88fdSLeon Romanovsky *bad_wr = wr;
1104029e88fdSLeon Romanovsky goto out;
1105029e88fdSLeon Romanovsky }
1106029e88fdSLeon Romanovsky
1107029e88fdSLeon Romanovsky if (wr->opcode == IB_WR_REG_MR ||
1108029e88fdSLeon Romanovsky wr->opcode == IB_WR_REG_MR_INTEGRITY) {
1109029e88fdSLeon Romanovsky fence = dev->umr_fence;
1110029e88fdSLeon Romanovsky next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
1111029e88fdSLeon Romanovsky } else {
1112029e88fdSLeon Romanovsky if (wr->send_flags & IB_SEND_FENCE) {
1113029e88fdSLeon Romanovsky if (qp->next_fence)
1114029e88fdSLeon Romanovsky fence = MLX5_FENCE_MODE_SMALL_AND_FENCE;
1115029e88fdSLeon Romanovsky else
1116029e88fdSLeon Romanovsky fence = MLX5_FENCE_MODE_FENCE;
1117029e88fdSLeon Romanovsky } else {
1118029e88fdSLeon Romanovsky fence = qp->next_fence;
1119029e88fdSLeon Romanovsky }
1120029e88fdSLeon Romanovsky }
1121029e88fdSLeon Romanovsky
11229ecf6ac1SMaor Gottlieb switch (qp->type) {
1123029e88fdSLeon Romanovsky case IB_QPT_XRC_INI:
1124029e88fdSLeon Romanovsky xrc = seg;
1125029e88fdSLeon Romanovsky seg += sizeof(*xrc);
1126029e88fdSLeon Romanovsky size += sizeof(*xrc) / 16;
1127029e88fdSLeon Romanovsky fallthrough;
1128029e88fdSLeon Romanovsky case IB_QPT_RC:
1129029e88fdSLeon Romanovsky err = handle_qpt_rc(dev, qp, wr, &ctrl, &seg, &size,
1130029e88fdSLeon Romanovsky &cur_edge, &idx, nreq, fence,
1131029e88fdSLeon Romanovsky next_fence, &num_sge);
1132029e88fdSLeon Romanovsky if (unlikely(err)) {
1133029e88fdSLeon Romanovsky *bad_wr = wr;
1134029e88fdSLeon Romanovsky goto out;
1135029e88fdSLeon Romanovsky } else if (wr->opcode == IB_WR_REG_MR_INTEGRITY) {
1136029e88fdSLeon Romanovsky goto skip_psv;
1137029e88fdSLeon Romanovsky }
1138029e88fdSLeon Romanovsky break;
1139029e88fdSLeon Romanovsky
1140029e88fdSLeon Romanovsky case IB_QPT_UC:
1141029e88fdSLeon Romanovsky handle_qpt_uc(wr, &seg, &size);
1142029e88fdSLeon Romanovsky break;
1143029e88fdSLeon Romanovsky case IB_QPT_SMI:
11443ce60f44SParav Pandit if (unlikely(!dev->port_caps[qp->port - 1].has_smi)) {
1145029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "Send SMP MADs is not allowed\n");
1146029e88fdSLeon Romanovsky err = -EPERM;
1147029e88fdSLeon Romanovsky *bad_wr = wr;
1148029e88fdSLeon Romanovsky goto out;
1149029e88fdSLeon Romanovsky }
1150029e88fdSLeon Romanovsky fallthrough;
1151029e88fdSLeon Romanovsky case MLX5_IB_QPT_HW_GSI:
1152029e88fdSLeon Romanovsky handle_qpt_hw_gsi(qp, wr, &seg, &size, &cur_edge);
1153029e88fdSLeon Romanovsky break;
1154029e88fdSLeon Romanovsky case IB_QPT_UD:
1155029e88fdSLeon Romanovsky handle_qpt_ud(qp, wr, &seg, &size, &cur_edge);
1156029e88fdSLeon Romanovsky break;
1157029e88fdSLeon Romanovsky
1158029e88fdSLeon Romanovsky default:
1159029e88fdSLeon Romanovsky break;
1160029e88fdSLeon Romanovsky }
1161029e88fdSLeon Romanovsky
1162029e88fdSLeon Romanovsky if (wr->send_flags & IB_SEND_INLINE && num_sge) {
1163029e88fdSLeon Romanovsky err = set_data_inl_seg(qp, wr, &seg, &size, &cur_edge);
1164029e88fdSLeon Romanovsky if (unlikely(err)) {
1165029e88fdSLeon Romanovsky mlx5_ib_warn(dev, "\n");
1166029e88fdSLeon Romanovsky *bad_wr = wr;
1167029e88fdSLeon Romanovsky goto out;
1168029e88fdSLeon Romanovsky }
1169029e88fdSLeon Romanovsky } else {
1170029e88fdSLeon Romanovsky for (i = 0; i < num_sge; i++) {
1171029e88fdSLeon Romanovsky handle_post_send_edge(&qp->sq, &seg, size,
1172029e88fdSLeon Romanovsky &cur_edge);
1173029e88fdSLeon Romanovsky if (unlikely(!wr->sg_list[i].length))
1174029e88fdSLeon Romanovsky continue;
1175029e88fdSLeon Romanovsky
1176029e88fdSLeon Romanovsky set_data_ptr_seg(
1177029e88fdSLeon Romanovsky (struct mlx5_wqe_data_seg *)seg,
1178029e88fdSLeon Romanovsky wr->sg_list + i);
1179029e88fdSLeon Romanovsky size += sizeof(struct mlx5_wqe_data_seg) / 16;
1180029e88fdSLeon Romanovsky seg += sizeof(struct mlx5_wqe_data_seg);
1181029e88fdSLeon Romanovsky }
1182029e88fdSLeon Romanovsky }
1183029e88fdSLeon Romanovsky
1184029e88fdSLeon Romanovsky qp->next_fence = next_fence;
1185fe765aebSAharon Landau mlx5r_finish_wqe(qp, ctrl, seg, size, cur_edge, idx, wr->wr_id,
1186fe765aebSAharon Landau nreq, fence, mlx5_ib_opcode[wr->opcode]);
1187029e88fdSLeon Romanovsky skip_psv:
1188029e88fdSLeon Romanovsky if (0)
1189029e88fdSLeon Romanovsky dump_wqe(qp, idx, size);
1190029e88fdSLeon Romanovsky }
1191029e88fdSLeon Romanovsky
1192029e88fdSLeon Romanovsky out:
1193fe765aebSAharon Landau if (likely(nreq))
1194fe765aebSAharon Landau mlx5r_ring_db(qp, nreq, ctrl);
1195029e88fdSLeon Romanovsky
1196029e88fdSLeon Romanovsky spin_unlock_irqrestore(&qp->sq.lock, flags);
1197029e88fdSLeon Romanovsky
1198029e88fdSLeon Romanovsky return err;
1199029e88fdSLeon Romanovsky }
1200029e88fdSLeon Romanovsky
set_sig_seg(struct mlx5_rwqe_sig * sig,int max_gs)1201029e88fdSLeon Romanovsky static void set_sig_seg(struct mlx5_rwqe_sig *sig, int max_gs)
1202029e88fdSLeon Romanovsky {
1203029e88fdSLeon Romanovsky sig->signature = calc_sig(sig, (max_gs + 1) << 2);
1204029e88fdSLeon Romanovsky }
1205029e88fdSLeon Romanovsky
mlx5_ib_post_recv(struct ib_qp * ibqp,const struct ib_recv_wr * wr,const struct ib_recv_wr ** bad_wr,bool drain)1206029e88fdSLeon Romanovsky int mlx5_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
1207029e88fdSLeon Romanovsky const struct ib_recv_wr **bad_wr, bool drain)
1208029e88fdSLeon Romanovsky {
1209029e88fdSLeon Romanovsky struct mlx5_ib_qp *qp = to_mqp(ibqp);
1210029e88fdSLeon Romanovsky struct mlx5_wqe_data_seg *scat;
1211029e88fdSLeon Romanovsky struct mlx5_rwqe_sig *sig;
1212029e88fdSLeon Romanovsky struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
1213029e88fdSLeon Romanovsky struct mlx5_core_dev *mdev = dev->mdev;
1214029e88fdSLeon Romanovsky unsigned long flags;
1215029e88fdSLeon Romanovsky int err = 0;
1216029e88fdSLeon Romanovsky int nreq;
1217029e88fdSLeon Romanovsky int ind;
1218029e88fdSLeon Romanovsky int i;
1219029e88fdSLeon Romanovsky
1220029e88fdSLeon Romanovsky if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR &&
1221029e88fdSLeon Romanovsky !drain)) {
1222029e88fdSLeon Romanovsky *bad_wr = wr;
1223029e88fdSLeon Romanovsky return -EIO;
1224029e88fdSLeon Romanovsky }
1225029e88fdSLeon Romanovsky
12269ecf6ac1SMaor Gottlieb if (qp->type == IB_QPT_GSI)
1227029e88fdSLeon Romanovsky return mlx5_ib_gsi_post_recv(ibqp, wr, bad_wr);
1228029e88fdSLeon Romanovsky
1229029e88fdSLeon Romanovsky spin_lock_irqsave(&qp->rq.lock, flags);
1230029e88fdSLeon Romanovsky
1231029e88fdSLeon Romanovsky ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
1232029e88fdSLeon Romanovsky
1233029e88fdSLeon Romanovsky for (nreq = 0; wr; nreq++, wr = wr->next) {
1234fe765aebSAharon Landau if (mlx5r_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
1235029e88fdSLeon Romanovsky err = -ENOMEM;
1236029e88fdSLeon Romanovsky *bad_wr = wr;
1237029e88fdSLeon Romanovsky goto out;
1238029e88fdSLeon Romanovsky }
1239029e88fdSLeon Romanovsky
1240029e88fdSLeon Romanovsky if (unlikely(wr->num_sge > qp->rq.max_gs)) {
1241029e88fdSLeon Romanovsky err = -EINVAL;
1242029e88fdSLeon Romanovsky *bad_wr = wr;
1243029e88fdSLeon Romanovsky goto out;
1244029e88fdSLeon Romanovsky }
1245029e88fdSLeon Romanovsky
1246029e88fdSLeon Romanovsky scat = mlx5_frag_buf_get_wqe(&qp->rq.fbc, ind);
1247029e88fdSLeon Romanovsky if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE)
1248029e88fdSLeon Romanovsky scat++;
1249029e88fdSLeon Romanovsky
1250029e88fdSLeon Romanovsky for (i = 0; i < wr->num_sge; i++)
1251029e88fdSLeon Romanovsky set_data_ptr_seg(scat + i, wr->sg_list + i);
1252029e88fdSLeon Romanovsky
1253029e88fdSLeon Romanovsky if (i < qp->rq.max_gs) {
1254029e88fdSLeon Romanovsky scat[i].byte_count = 0;
1255594cac11SOr Har-Toov scat[i].lkey = dev->mkeys.terminate_scatter_list_mkey;
1256029e88fdSLeon Romanovsky scat[i].addr = 0;
1257029e88fdSLeon Romanovsky }
1258029e88fdSLeon Romanovsky
1259029e88fdSLeon Romanovsky if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE) {
1260029e88fdSLeon Romanovsky sig = (struct mlx5_rwqe_sig *)scat;
1261029e88fdSLeon Romanovsky set_sig_seg(sig, qp->rq.max_gs);
1262029e88fdSLeon Romanovsky }
1263029e88fdSLeon Romanovsky
1264029e88fdSLeon Romanovsky qp->rq.wrid[ind] = wr->wr_id;
1265029e88fdSLeon Romanovsky
1266029e88fdSLeon Romanovsky ind = (ind + 1) & (qp->rq.wqe_cnt - 1);
1267029e88fdSLeon Romanovsky }
1268029e88fdSLeon Romanovsky
1269029e88fdSLeon Romanovsky out:
1270029e88fdSLeon Romanovsky if (likely(nreq)) {
1271029e88fdSLeon Romanovsky qp->rq.head += nreq;
1272029e88fdSLeon Romanovsky
1273029e88fdSLeon Romanovsky /* Make sure that descriptors are written before
1274029e88fdSLeon Romanovsky * doorbell record.
1275029e88fdSLeon Romanovsky */
1276029e88fdSLeon Romanovsky wmb();
1277029e88fdSLeon Romanovsky
1278029e88fdSLeon Romanovsky *qp->db.db = cpu_to_be32(qp->rq.head & 0xffff);
1279029e88fdSLeon Romanovsky }
1280029e88fdSLeon Romanovsky
1281029e88fdSLeon Romanovsky spin_unlock_irqrestore(&qp->rq.lock, flags);
1282029e88fdSLeon Romanovsky
1283029e88fdSLeon Romanovsky return err;
1284029e88fdSLeon Romanovsky }
1285