xref: /freebsd/contrib/ofed/libmlx5/qp.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky  * Copyright (c) 2012 Mellanox Technologies, Inc.  All rights reserved.
3*d6b92ffaSHans Petter Selasky  *
4*d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
5*d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
6*d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
7*d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
8*d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
9*d6b92ffaSHans Petter Selasky  *
10*d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
11*d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
12*d6b92ffaSHans Petter Selasky  *     conditions are met:
13*d6b92ffaSHans Petter Selasky  *
14*d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
15*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
16*d6b92ffaSHans Petter Selasky  *        disclaimer.
17*d6b92ffaSHans Petter Selasky  *
18*d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
19*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
20*d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
21*d6b92ffaSHans Petter Selasky  *        provided with the distribution.
22*d6b92ffaSHans Petter Selasky  *
23*d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24*d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25*d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26*d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27*d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28*d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29*d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30*d6b92ffaSHans Petter Selasky  * SOFTWARE.
31*d6b92ffaSHans Petter Selasky  */
32*d6b92ffaSHans Petter Selasky 
33*d6b92ffaSHans Petter Selasky #include <config.h>
34*d6b92ffaSHans Petter Selasky 
35*d6b92ffaSHans Petter Selasky #include <stdlib.h>
36*d6b92ffaSHans Petter Selasky #include <pthread.h>
37*d6b92ffaSHans Petter Selasky #include <string.h>
38*d6b92ffaSHans Petter Selasky #include <errno.h>
39*d6b92ffaSHans Petter Selasky #include <stdio.h>
40*d6b92ffaSHans Petter Selasky 
41*d6b92ffaSHans Petter Selasky #include "mlx5.h"
42*d6b92ffaSHans Petter Selasky #include "doorbell.h"
43*d6b92ffaSHans Petter Selasky #include "wqe.h"
44*d6b92ffaSHans Petter Selasky 
45*d6b92ffaSHans Petter Selasky #define MLX5_ATOMIC_SIZE 8
46*d6b92ffaSHans Petter Selasky 
47*d6b92ffaSHans Petter Selasky static const uint32_t mlx5_ib_opcode[] = {
48*d6b92ffaSHans Petter Selasky 	[IBV_WR_SEND]			= MLX5_OPCODE_SEND,
49*d6b92ffaSHans Petter Selasky 	[IBV_WR_SEND_WITH_INV]		= MLX5_OPCODE_SEND_INVAL,
50*d6b92ffaSHans Petter Selasky 	[IBV_WR_SEND_WITH_IMM]		= MLX5_OPCODE_SEND_IMM,
51*d6b92ffaSHans Petter Selasky 	[IBV_WR_RDMA_WRITE]		= MLX5_OPCODE_RDMA_WRITE,
52*d6b92ffaSHans Petter Selasky 	[IBV_WR_RDMA_WRITE_WITH_IMM]	= MLX5_OPCODE_RDMA_WRITE_IMM,
53*d6b92ffaSHans Petter Selasky 	[IBV_WR_RDMA_READ]		= MLX5_OPCODE_RDMA_READ,
54*d6b92ffaSHans Petter Selasky 	[IBV_WR_ATOMIC_CMP_AND_SWP]	= MLX5_OPCODE_ATOMIC_CS,
55*d6b92ffaSHans Petter Selasky 	[IBV_WR_ATOMIC_FETCH_AND_ADD]	= MLX5_OPCODE_ATOMIC_FA,
56*d6b92ffaSHans Petter Selasky 	[IBV_WR_BIND_MW]		= MLX5_OPCODE_UMR,
57*d6b92ffaSHans Petter Selasky 	[IBV_WR_LOCAL_INV]		= MLX5_OPCODE_UMR,
58*d6b92ffaSHans Petter Selasky 	[IBV_WR_TSO]			= MLX5_OPCODE_TSO,
59*d6b92ffaSHans Petter Selasky };
60*d6b92ffaSHans Petter Selasky 
get_recv_wqe(struct mlx5_qp * qp,int n)61*d6b92ffaSHans Petter Selasky static void *get_recv_wqe(struct mlx5_qp *qp, int n)
62*d6b92ffaSHans Petter Selasky {
63*d6b92ffaSHans Petter Selasky 	return qp->buf.buf + qp->rq.offset + (n << qp->rq.wqe_shift);
64*d6b92ffaSHans Petter Selasky }
65*d6b92ffaSHans Petter Selasky 
get_wq_recv_wqe(struct mlx5_rwq * rwq,int n)66*d6b92ffaSHans Petter Selasky static void *get_wq_recv_wqe(struct mlx5_rwq *rwq, int n)
67*d6b92ffaSHans Petter Selasky {
68*d6b92ffaSHans Petter Selasky 	return rwq->pbuff  + (n << rwq->rq.wqe_shift);
69*d6b92ffaSHans Petter Selasky }
70*d6b92ffaSHans Petter Selasky 
copy_to_scat(struct mlx5_wqe_data_seg * scat,void * buf,int * size,int max)71*d6b92ffaSHans Petter Selasky static int copy_to_scat(struct mlx5_wqe_data_seg *scat, void *buf, int *size,
72*d6b92ffaSHans Petter Selasky 			 int max)
73*d6b92ffaSHans Petter Selasky {
74*d6b92ffaSHans Petter Selasky 	int copy;
75*d6b92ffaSHans Petter Selasky 	int i;
76*d6b92ffaSHans Petter Selasky 
77*d6b92ffaSHans Petter Selasky 	if (unlikely(!(*size)))
78*d6b92ffaSHans Petter Selasky 		return IBV_WC_SUCCESS;
79*d6b92ffaSHans Petter Selasky 
80*d6b92ffaSHans Petter Selasky 	for (i = 0; i < max; ++i) {
81*d6b92ffaSHans Petter Selasky 		copy = min_t(long, *size, be32toh(scat->byte_count));
82*d6b92ffaSHans Petter Selasky 		memcpy((void *)(unsigned long)be64toh(scat->addr), buf, copy);
83*d6b92ffaSHans Petter Selasky 		*size -= copy;
84*d6b92ffaSHans Petter Selasky 		if (*size == 0)
85*d6b92ffaSHans Petter Selasky 			return IBV_WC_SUCCESS;
86*d6b92ffaSHans Petter Selasky 
87*d6b92ffaSHans Petter Selasky 		buf += copy;
88*d6b92ffaSHans Petter Selasky 		++scat;
89*d6b92ffaSHans Petter Selasky 	}
90*d6b92ffaSHans Petter Selasky 	return IBV_WC_LOC_LEN_ERR;
91*d6b92ffaSHans Petter Selasky }
92*d6b92ffaSHans Petter Selasky 
mlx5_copy_to_recv_wqe(struct mlx5_qp * qp,int idx,void * buf,int size)93*d6b92ffaSHans Petter Selasky int mlx5_copy_to_recv_wqe(struct mlx5_qp *qp, int idx, void *buf, int size)
94*d6b92ffaSHans Petter Selasky {
95*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_data_seg *scat;
96*d6b92ffaSHans Petter Selasky 	int max = 1 << (qp->rq.wqe_shift - 4);
97*d6b92ffaSHans Petter Selasky 
98*d6b92ffaSHans Petter Selasky 	scat = get_recv_wqe(qp, idx);
99*d6b92ffaSHans Petter Selasky 	if (unlikely(qp->wq_sig))
100*d6b92ffaSHans Petter Selasky 		++scat;
101*d6b92ffaSHans Petter Selasky 
102*d6b92ffaSHans Petter Selasky 	return copy_to_scat(scat, buf, &size, max);
103*d6b92ffaSHans Petter Selasky }
104*d6b92ffaSHans Petter Selasky 
mlx5_copy_to_send_wqe(struct mlx5_qp * qp,int idx,void * buf,int size)105*d6b92ffaSHans Petter Selasky int mlx5_copy_to_send_wqe(struct mlx5_qp *qp, int idx, void *buf, int size)
106*d6b92ffaSHans Petter Selasky {
107*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_ctrl_seg *ctrl;
108*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_data_seg *scat;
109*d6b92ffaSHans Petter Selasky 	void *p;
110*d6b92ffaSHans Petter Selasky 	int max;
111*d6b92ffaSHans Petter Selasky 
112*d6b92ffaSHans Petter Selasky 	idx &= (qp->sq.wqe_cnt - 1);
113*d6b92ffaSHans Petter Selasky 	ctrl = mlx5_get_send_wqe(qp, idx);
114*d6b92ffaSHans Petter Selasky 	if (qp->ibv_qp->qp_type != IBV_QPT_RC) {
115*d6b92ffaSHans Petter Selasky 		fprintf(stderr, "scatter to CQE is supported only for RC QPs\n");
116*d6b92ffaSHans Petter Selasky 		return IBV_WC_GENERAL_ERR;
117*d6b92ffaSHans Petter Selasky 	}
118*d6b92ffaSHans Petter Selasky 	p = ctrl + 1;
119*d6b92ffaSHans Petter Selasky 
120*d6b92ffaSHans Petter Selasky 	switch (be32toh(ctrl->opmod_idx_opcode) & 0xff) {
121*d6b92ffaSHans Petter Selasky 	case MLX5_OPCODE_RDMA_READ:
122*d6b92ffaSHans Petter Selasky 		p = p + sizeof(struct mlx5_wqe_raddr_seg);
123*d6b92ffaSHans Petter Selasky 		break;
124*d6b92ffaSHans Petter Selasky 
125*d6b92ffaSHans Petter Selasky 	case MLX5_OPCODE_ATOMIC_CS:
126*d6b92ffaSHans Petter Selasky 	case MLX5_OPCODE_ATOMIC_FA:
127*d6b92ffaSHans Petter Selasky 		p = p + sizeof(struct mlx5_wqe_raddr_seg) +
128*d6b92ffaSHans Petter Selasky 			sizeof(struct mlx5_wqe_atomic_seg);
129*d6b92ffaSHans Petter Selasky 		break;
130*d6b92ffaSHans Petter Selasky 
131*d6b92ffaSHans Petter Selasky 	default:
132*d6b92ffaSHans Petter Selasky 		fprintf(stderr, "scatter to CQE for opcode %d\n",
133*d6b92ffaSHans Petter Selasky 			be32toh(ctrl->opmod_idx_opcode) & 0xff);
134*d6b92ffaSHans Petter Selasky 		return IBV_WC_REM_INV_REQ_ERR;
135*d6b92ffaSHans Petter Selasky 	}
136*d6b92ffaSHans Petter Selasky 
137*d6b92ffaSHans Petter Selasky 	scat = p;
138*d6b92ffaSHans Petter Selasky 	max = (be32toh(ctrl->qpn_ds) & 0x3F) - (((void *)scat - (void *)ctrl) >> 4);
139*d6b92ffaSHans Petter Selasky 	if (unlikely((void *)(scat + max) > qp->sq.qend)) {
140*d6b92ffaSHans Petter Selasky 		int tmp = ((void *)qp->sq.qend - (void *)scat) >> 4;
141*d6b92ffaSHans Petter Selasky 		int orig_size = size;
142*d6b92ffaSHans Petter Selasky 
143*d6b92ffaSHans Petter Selasky 		if (copy_to_scat(scat, buf, &size, tmp) == IBV_WC_SUCCESS)
144*d6b92ffaSHans Petter Selasky 			return IBV_WC_SUCCESS;
145*d6b92ffaSHans Petter Selasky 		max = max - tmp;
146*d6b92ffaSHans Petter Selasky 		buf += orig_size - size;
147*d6b92ffaSHans Petter Selasky 		scat = mlx5_get_send_wqe(qp, 0);
148*d6b92ffaSHans Petter Selasky 	}
149*d6b92ffaSHans Petter Selasky 
150*d6b92ffaSHans Petter Selasky 	return copy_to_scat(scat, buf, &size, max);
151*d6b92ffaSHans Petter Selasky }
152*d6b92ffaSHans Petter Selasky 
mlx5_get_send_wqe(struct mlx5_qp * qp,int n)153*d6b92ffaSHans Petter Selasky void *mlx5_get_send_wqe(struct mlx5_qp *qp, int n)
154*d6b92ffaSHans Petter Selasky {
155*d6b92ffaSHans Petter Selasky 	return qp->sq_start + (n << MLX5_SEND_WQE_SHIFT);
156*d6b92ffaSHans Petter Selasky }
157*d6b92ffaSHans Petter Selasky 
mlx5_init_rwq_indices(struct mlx5_rwq * rwq)158*d6b92ffaSHans Petter Selasky void mlx5_init_rwq_indices(struct mlx5_rwq *rwq)
159*d6b92ffaSHans Petter Selasky {
160*d6b92ffaSHans Petter Selasky 	rwq->rq.head	 = 0;
161*d6b92ffaSHans Petter Selasky 	rwq->rq.tail	 = 0;
162*d6b92ffaSHans Petter Selasky }
163*d6b92ffaSHans Petter Selasky 
mlx5_init_qp_indices(struct mlx5_qp * qp)164*d6b92ffaSHans Petter Selasky void mlx5_init_qp_indices(struct mlx5_qp *qp)
165*d6b92ffaSHans Petter Selasky {
166*d6b92ffaSHans Petter Selasky 	qp->sq.head	 = 0;
167*d6b92ffaSHans Petter Selasky 	qp->sq.tail	 = 0;
168*d6b92ffaSHans Petter Selasky 	qp->rq.head	 = 0;
169*d6b92ffaSHans Petter Selasky 	qp->rq.tail	 = 0;
170*d6b92ffaSHans Petter Selasky 	qp->sq.cur_post  = 0;
171*d6b92ffaSHans Petter Selasky }
172*d6b92ffaSHans Petter Selasky 
mlx5_wq_overflow(struct mlx5_wq * wq,int nreq,struct mlx5_cq * cq)173*d6b92ffaSHans Petter Selasky static int mlx5_wq_overflow(struct mlx5_wq *wq, int nreq, struct mlx5_cq *cq)
174*d6b92ffaSHans Petter Selasky {
175*d6b92ffaSHans Petter Selasky 	unsigned cur;
176*d6b92ffaSHans Petter Selasky 
177*d6b92ffaSHans Petter Selasky 	cur = wq->head - wq->tail;
178*d6b92ffaSHans Petter Selasky 	if (cur + nreq < wq->max_post)
179*d6b92ffaSHans Petter Selasky 		return 0;
180*d6b92ffaSHans Petter Selasky 
181*d6b92ffaSHans Petter Selasky 	mlx5_spin_lock(&cq->lock);
182*d6b92ffaSHans Petter Selasky 	cur = wq->head - wq->tail;
183*d6b92ffaSHans Petter Selasky 	mlx5_spin_unlock(&cq->lock);
184*d6b92ffaSHans Petter Selasky 
185*d6b92ffaSHans Petter Selasky 	return cur + nreq >= wq->max_post;
186*d6b92ffaSHans Petter Selasky }
187*d6b92ffaSHans Petter Selasky 
set_raddr_seg(struct mlx5_wqe_raddr_seg * rseg,uint64_t remote_addr,uint32_t rkey)188*d6b92ffaSHans Petter Selasky static inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
189*d6b92ffaSHans Petter Selasky 				 uint64_t remote_addr, uint32_t rkey)
190*d6b92ffaSHans Petter Selasky {
191*d6b92ffaSHans Petter Selasky 	rseg->raddr    = htobe64(remote_addr);
192*d6b92ffaSHans Petter Selasky 	rseg->rkey     = htobe32(rkey);
193*d6b92ffaSHans Petter Selasky 	rseg->reserved = 0;
194*d6b92ffaSHans Petter Selasky }
195*d6b92ffaSHans Petter Selasky 
set_atomic_seg(struct mlx5_wqe_atomic_seg * aseg,enum ibv_wr_opcode opcode,uint64_t swap,uint64_t compare_add)196*d6b92ffaSHans Petter Selasky static void set_atomic_seg(struct mlx5_wqe_atomic_seg *aseg,
197*d6b92ffaSHans Petter Selasky 			   enum ibv_wr_opcode   opcode,
198*d6b92ffaSHans Petter Selasky 			   uint64_t swap,
199*d6b92ffaSHans Petter Selasky 			   uint64_t compare_add)
200*d6b92ffaSHans Petter Selasky {
201*d6b92ffaSHans Petter Selasky 	if (opcode == IBV_WR_ATOMIC_CMP_AND_SWP) {
202*d6b92ffaSHans Petter Selasky 		aseg->swap_add = htobe64(swap);
203*d6b92ffaSHans Petter Selasky 		aseg->compare  = htobe64(compare_add);
204*d6b92ffaSHans Petter Selasky 	} else {
205*d6b92ffaSHans Petter Selasky 		aseg->swap_add = htobe64(compare_add);
206*d6b92ffaSHans Petter Selasky 	}
207*d6b92ffaSHans Petter Selasky }
208*d6b92ffaSHans Petter Selasky 
set_datagram_seg(struct mlx5_wqe_datagram_seg * dseg,struct ibv_send_wr * wr)209*d6b92ffaSHans Petter Selasky static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
210*d6b92ffaSHans Petter Selasky 			     struct ibv_send_wr *wr)
211*d6b92ffaSHans Petter Selasky {
212*d6b92ffaSHans Petter Selasky 	memcpy(&dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof dseg->av);
213*d6b92ffaSHans Petter Selasky 	dseg->av.dqp_dct = htobe32(wr->wr.ud.remote_qpn | MLX5_EXTENDED_UD_AV);
214*d6b92ffaSHans Petter Selasky 	dseg->av.key.qkey.qkey = htobe32(wr->wr.ud.remote_qkey);
215*d6b92ffaSHans Petter Selasky }
216*d6b92ffaSHans Petter Selasky 
set_data_ptr_seg(struct mlx5_wqe_data_seg * dseg,struct ibv_sge * sg,int offset)217*d6b92ffaSHans Petter Selasky static void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ibv_sge *sg,
218*d6b92ffaSHans Petter Selasky 			     int offset)
219*d6b92ffaSHans Petter Selasky {
220*d6b92ffaSHans Petter Selasky 	dseg->byte_count = htobe32(sg->length - offset);
221*d6b92ffaSHans Petter Selasky 	dseg->lkey       = htobe32(sg->lkey);
222*d6b92ffaSHans Petter Selasky 	dseg->addr       = htobe64(sg->addr + offset);
223*d6b92ffaSHans Petter Selasky }
224*d6b92ffaSHans Petter Selasky 
set_data_ptr_seg_atomic(struct mlx5_wqe_data_seg * dseg,struct ibv_sge * sg)225*d6b92ffaSHans Petter Selasky static void set_data_ptr_seg_atomic(struct mlx5_wqe_data_seg *dseg,
226*d6b92ffaSHans Petter Selasky 				    struct ibv_sge *sg)
227*d6b92ffaSHans Petter Selasky {
228*d6b92ffaSHans Petter Selasky 	dseg->byte_count = htobe32(MLX5_ATOMIC_SIZE);
229*d6b92ffaSHans Petter Selasky 	dseg->lkey       = htobe32(sg->lkey);
230*d6b92ffaSHans Petter Selasky 	dseg->addr       = htobe64(sg->addr);
231*d6b92ffaSHans Petter Selasky }
232*d6b92ffaSHans Petter Selasky 
233*d6b92ffaSHans Petter Selasky /*
234*d6b92ffaSHans Petter Selasky  * Avoid using memcpy() to copy to BlueFlame page, since memcpy()
235*d6b92ffaSHans Petter Selasky  * implementations may use move-string-buffer assembler instructions,
236*d6b92ffaSHans Petter Selasky  * which do not guarantee order of copying.
237*d6b92ffaSHans Petter Selasky  */
mlx5_bf_copy(unsigned long long * dst,unsigned long long * src,unsigned bytecnt,struct mlx5_qp * qp)238*d6b92ffaSHans Petter Selasky static void mlx5_bf_copy(unsigned long long *dst, unsigned long long *src,
239*d6b92ffaSHans Petter Selasky 			 unsigned bytecnt, struct mlx5_qp *qp)
240*d6b92ffaSHans Petter Selasky {
241*d6b92ffaSHans Petter Selasky 	while (bytecnt > 0) {
242*d6b92ffaSHans Petter Selasky 		*dst++ = *src++;
243*d6b92ffaSHans Petter Selasky 		*dst++ = *src++;
244*d6b92ffaSHans Petter Selasky 		*dst++ = *src++;
245*d6b92ffaSHans Petter Selasky 		*dst++ = *src++;
246*d6b92ffaSHans Petter Selasky 		*dst++ = *src++;
247*d6b92ffaSHans Petter Selasky 		*dst++ = *src++;
248*d6b92ffaSHans Petter Selasky 		*dst++ = *src++;
249*d6b92ffaSHans Petter Selasky 		*dst++ = *src++;
250*d6b92ffaSHans Petter Selasky 		bytecnt -= 8 * sizeof(unsigned long long);
251*d6b92ffaSHans Petter Selasky 		if (unlikely(src == qp->sq.qend))
252*d6b92ffaSHans Petter Selasky 			src = qp->sq_start;
253*d6b92ffaSHans Petter Selasky 	}
254*d6b92ffaSHans Petter Selasky }
255*d6b92ffaSHans Petter Selasky 
send_ieth(struct ibv_send_wr * wr)256*d6b92ffaSHans Petter Selasky static uint32_t send_ieth(struct ibv_send_wr *wr)
257*d6b92ffaSHans Petter Selasky {
258*d6b92ffaSHans Petter Selasky 	switch (wr->opcode) {
259*d6b92ffaSHans Petter Selasky 	case IBV_WR_SEND_WITH_IMM:
260*d6b92ffaSHans Petter Selasky 	case IBV_WR_RDMA_WRITE_WITH_IMM:
261*d6b92ffaSHans Petter Selasky 		return wr->imm_data;
262*d6b92ffaSHans Petter Selasky 	case IBV_WR_SEND_WITH_INV:
263*d6b92ffaSHans Petter Selasky 		return htobe32(wr->imm_data);
264*d6b92ffaSHans Petter Selasky 	default:
265*d6b92ffaSHans Petter Selasky 		return 0;
266*d6b92ffaSHans Petter Selasky 	}
267*d6b92ffaSHans Petter Selasky }
268*d6b92ffaSHans Petter Selasky 
set_data_inl_seg(struct mlx5_qp * qp,struct ibv_send_wr * wr,void * wqe,int * sz,struct mlx5_sg_copy_ptr * sg_copy_ptr)269*d6b92ffaSHans Petter Selasky static int set_data_inl_seg(struct mlx5_qp *qp, struct ibv_send_wr *wr,
270*d6b92ffaSHans Petter Selasky 			    void *wqe, int *sz,
271*d6b92ffaSHans Petter Selasky 			    struct mlx5_sg_copy_ptr *sg_copy_ptr)
272*d6b92ffaSHans Petter Selasky {
273*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_inline_seg *seg;
274*d6b92ffaSHans Petter Selasky 	void *addr;
275*d6b92ffaSHans Petter Selasky 	int len;
276*d6b92ffaSHans Petter Selasky 	int i;
277*d6b92ffaSHans Petter Selasky 	int inl = 0;
278*d6b92ffaSHans Petter Selasky 	void *qend = qp->sq.qend;
279*d6b92ffaSHans Petter Selasky 	int copy;
280*d6b92ffaSHans Petter Selasky 	int offset = sg_copy_ptr->offset;
281*d6b92ffaSHans Petter Selasky 
282*d6b92ffaSHans Petter Selasky 	seg = wqe;
283*d6b92ffaSHans Petter Selasky 	wqe += sizeof *seg;
284*d6b92ffaSHans Petter Selasky 	for (i = sg_copy_ptr->index; i < wr->num_sge; ++i) {
285*d6b92ffaSHans Petter Selasky 		addr = (void *) (unsigned long)(wr->sg_list[i].addr + offset);
286*d6b92ffaSHans Petter Selasky 		len  = wr->sg_list[i].length - offset;
287*d6b92ffaSHans Petter Selasky 		inl += len;
288*d6b92ffaSHans Petter Selasky 		offset = 0;
289*d6b92ffaSHans Petter Selasky 
290*d6b92ffaSHans Petter Selasky 		if (unlikely(inl > qp->max_inline_data))
291*d6b92ffaSHans Petter Selasky 			return ENOMEM;
292*d6b92ffaSHans Petter Selasky 
293*d6b92ffaSHans Petter Selasky 		if (unlikely(wqe + len > qend)) {
294*d6b92ffaSHans Petter Selasky 			copy = qend - wqe;
295*d6b92ffaSHans Petter Selasky 			memcpy(wqe, addr, copy);
296*d6b92ffaSHans Petter Selasky 			addr += copy;
297*d6b92ffaSHans Petter Selasky 			len -= copy;
298*d6b92ffaSHans Petter Selasky 			wqe = mlx5_get_send_wqe(qp, 0);
299*d6b92ffaSHans Petter Selasky 		}
300*d6b92ffaSHans Petter Selasky 		memcpy(wqe, addr, len);
301*d6b92ffaSHans Petter Selasky 		wqe += len;
302*d6b92ffaSHans Petter Selasky 	}
303*d6b92ffaSHans Petter Selasky 
304*d6b92ffaSHans Petter Selasky 	if (likely(inl)) {
305*d6b92ffaSHans Petter Selasky 		seg->byte_count = htobe32(inl | MLX5_INLINE_SEG);
306*d6b92ffaSHans Petter Selasky 		*sz = align(inl + sizeof seg->byte_count, 16) / 16;
307*d6b92ffaSHans Petter Selasky 	} else
308*d6b92ffaSHans Petter Selasky 		*sz = 0;
309*d6b92ffaSHans Petter Selasky 
310*d6b92ffaSHans Petter Selasky 	return 0;
311*d6b92ffaSHans Petter Selasky }
312*d6b92ffaSHans Petter Selasky 
wq_sig(struct mlx5_wqe_ctrl_seg * ctrl)313*d6b92ffaSHans Petter Selasky static uint8_t wq_sig(struct mlx5_wqe_ctrl_seg *ctrl)
314*d6b92ffaSHans Petter Selasky {
315*d6b92ffaSHans Petter Selasky 	return calc_sig(ctrl, be32toh(ctrl->qpn_ds));
316*d6b92ffaSHans Petter Selasky }
317*d6b92ffaSHans Petter Selasky 
318*d6b92ffaSHans Petter Selasky #ifdef MLX5_DEBUG
dump_wqe(FILE * fp,int idx,int size_16,struct mlx5_qp * qp)319*d6b92ffaSHans Petter Selasky static void dump_wqe(FILE *fp, int idx, int size_16, struct mlx5_qp *qp)
320*d6b92ffaSHans Petter Selasky {
321*d6b92ffaSHans Petter Selasky 	uint32_t *p = NULL;
322*d6b92ffaSHans Petter Selasky 	int i, j;
323*d6b92ffaSHans Petter Selasky 	int tidx = idx;
324*d6b92ffaSHans Petter Selasky 
325*d6b92ffaSHans Petter Selasky 	fprintf(fp, "dump wqe at %p\n", mlx5_get_send_wqe(qp, tidx));
326*d6b92ffaSHans Petter Selasky 	for (i = 0, j = 0; i < size_16 * 4; i += 4, j += 4) {
327*d6b92ffaSHans Petter Selasky 		if ((i & 0xf) == 0) {
328*d6b92ffaSHans Petter Selasky 			void *buf = mlx5_get_send_wqe(qp, tidx);
329*d6b92ffaSHans Petter Selasky 			tidx = (tidx + 1) & (qp->sq.wqe_cnt - 1);
330*d6b92ffaSHans Petter Selasky 			p = buf;
331*d6b92ffaSHans Petter Selasky 			j = 0;
332*d6b92ffaSHans Petter Selasky 		}
333*d6b92ffaSHans Petter Selasky 		fprintf(fp, "%08x %08x %08x %08x\n", be32toh(p[j]), be32toh(p[j + 1]),
334*d6b92ffaSHans Petter Selasky 			be32toh(p[j + 2]), be32toh(p[j + 3]));
335*d6b92ffaSHans Petter Selasky 	}
336*d6b92ffaSHans Petter Selasky }
337*d6b92ffaSHans Petter Selasky #endif /* MLX5_DEBUG */
338*d6b92ffaSHans Petter Selasky 
339*d6b92ffaSHans Petter Selasky 
mlx5_get_atomic_laddr(struct mlx5_qp * qp,uint16_t idx,int * byte_count)340*d6b92ffaSHans Petter Selasky void *mlx5_get_atomic_laddr(struct mlx5_qp *qp, uint16_t idx, int *byte_count)
341*d6b92ffaSHans Petter Selasky {
342*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_data_seg *dpseg;
343*d6b92ffaSHans Petter Selasky 	void *addr;
344*d6b92ffaSHans Petter Selasky 
345*d6b92ffaSHans Petter Selasky 	dpseg = mlx5_get_send_wqe(qp, idx) + sizeof(struct mlx5_wqe_ctrl_seg) +
346*d6b92ffaSHans Petter Selasky 		sizeof(struct mlx5_wqe_raddr_seg) +
347*d6b92ffaSHans Petter Selasky 		sizeof(struct mlx5_wqe_atomic_seg);
348*d6b92ffaSHans Petter Selasky 	addr = (void *)(unsigned long)be64toh(dpseg->addr);
349*d6b92ffaSHans Petter Selasky 
350*d6b92ffaSHans Petter Selasky 	/*
351*d6b92ffaSHans Petter Selasky 	 * Currently byte count is always 8 bytes. Fix this when
352*d6b92ffaSHans Petter Selasky 	 * we support variable size of atomics
353*d6b92ffaSHans Petter Selasky 	 */
354*d6b92ffaSHans Petter Selasky 	*byte_count = 8;
355*d6b92ffaSHans Petter Selasky 	return addr;
356*d6b92ffaSHans Petter Selasky }
357*d6b92ffaSHans Petter Selasky 
copy_eth_inline_headers(struct ibv_qp * ibqp,struct ibv_send_wr * wr,struct mlx5_wqe_eth_seg * eseg,struct mlx5_sg_copy_ptr * sg_copy_ptr)358*d6b92ffaSHans Petter Selasky static inline int copy_eth_inline_headers(struct ibv_qp *ibqp,
359*d6b92ffaSHans Petter Selasky 					  struct ibv_send_wr *wr,
360*d6b92ffaSHans Petter Selasky 					  struct mlx5_wqe_eth_seg *eseg,
361*d6b92ffaSHans Petter Selasky 					  struct mlx5_sg_copy_ptr *sg_copy_ptr)
362*d6b92ffaSHans Petter Selasky {
363*d6b92ffaSHans Petter Selasky 	uint32_t inl_hdr_size = MLX5_ETH_L2_INLINE_HEADER_SIZE;
364*d6b92ffaSHans Petter Selasky 	int inl_hdr_copy_size = 0;
365*d6b92ffaSHans Petter Selasky 	int j = 0;
366*d6b92ffaSHans Petter Selasky 	FILE *fp = to_mctx(ibqp->context)->dbg_fp;
367*d6b92ffaSHans Petter Selasky 
368*d6b92ffaSHans Petter Selasky 	if (unlikely(wr->num_sge < 1)) {
369*d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP_SEND, "illegal num_sge: %d, minimum is 1\n",
370*d6b92ffaSHans Petter Selasky 			 wr->num_sge);
371*d6b92ffaSHans Petter Selasky 		return EINVAL;
372*d6b92ffaSHans Petter Selasky 	}
373*d6b92ffaSHans Petter Selasky 
374*d6b92ffaSHans Petter Selasky 	if (likely(wr->sg_list[0].length >= MLX5_ETH_L2_INLINE_HEADER_SIZE)) {
375*d6b92ffaSHans Petter Selasky 		inl_hdr_copy_size = MLX5_ETH_L2_INLINE_HEADER_SIZE;
376*d6b92ffaSHans Petter Selasky 		memcpy(eseg->inline_hdr_start,
377*d6b92ffaSHans Petter Selasky 		       (void *)(uintptr_t)wr->sg_list[0].addr,
378*d6b92ffaSHans Petter Selasky 		       inl_hdr_copy_size);
379*d6b92ffaSHans Petter Selasky 	} else {
380*d6b92ffaSHans Petter Selasky 		for (j = 0; j < wr->num_sge && inl_hdr_size > 0; ++j) {
381*d6b92ffaSHans Petter Selasky 			inl_hdr_copy_size = min(wr->sg_list[j].length,
382*d6b92ffaSHans Petter Selasky 						inl_hdr_size);
383*d6b92ffaSHans Petter Selasky 			memcpy(eseg->inline_hdr_start +
384*d6b92ffaSHans Petter Selasky 			       (MLX5_ETH_L2_INLINE_HEADER_SIZE - inl_hdr_size),
385*d6b92ffaSHans Petter Selasky 			       (void *)(uintptr_t)wr->sg_list[j].addr,
386*d6b92ffaSHans Petter Selasky 			       inl_hdr_copy_size);
387*d6b92ffaSHans Petter Selasky 			inl_hdr_size -= inl_hdr_copy_size;
388*d6b92ffaSHans Petter Selasky 		}
389*d6b92ffaSHans Petter Selasky 		if (unlikely(inl_hdr_size)) {
390*d6b92ffaSHans Petter Selasky 			mlx5_dbg(fp, MLX5_DBG_QP_SEND, "Ethernet headers < 16 bytes\n");
391*d6b92ffaSHans Petter Selasky 			return EINVAL;
392*d6b92ffaSHans Petter Selasky 		}
393*d6b92ffaSHans Petter Selasky 		--j;
394*d6b92ffaSHans Petter Selasky 	}
395*d6b92ffaSHans Petter Selasky 
396*d6b92ffaSHans Petter Selasky 
397*d6b92ffaSHans Petter Selasky 	eseg->inline_hdr_sz = htobe16(MLX5_ETH_L2_INLINE_HEADER_SIZE);
398*d6b92ffaSHans Petter Selasky 
399*d6b92ffaSHans Petter Selasky 	/* If we copied all the sge into the inline-headers, then we need to
400*d6b92ffaSHans Petter Selasky 	 * start copying from the next sge into the data-segment.
401*d6b92ffaSHans Petter Selasky 	 */
402*d6b92ffaSHans Petter Selasky 	if (unlikely(wr->sg_list[j].length == inl_hdr_copy_size)) {
403*d6b92ffaSHans Petter Selasky 		++j;
404*d6b92ffaSHans Petter Selasky 		inl_hdr_copy_size = 0;
405*d6b92ffaSHans Petter Selasky 	}
406*d6b92ffaSHans Petter Selasky 
407*d6b92ffaSHans Petter Selasky 	sg_copy_ptr->index = j;
408*d6b92ffaSHans Petter Selasky 	sg_copy_ptr->offset = inl_hdr_copy_size;
409*d6b92ffaSHans Petter Selasky 
410*d6b92ffaSHans Petter Selasky 	return 0;
411*d6b92ffaSHans Petter Selasky }
412*d6b92ffaSHans Petter Selasky 
413*d6b92ffaSHans Petter Selasky #undef	ALIGN
414*d6b92ffaSHans Petter Selasky #define ALIGN(x, log_a) ((((x) + (1 << (log_a)) - 1)) & ~((1 << (log_a)) - 1))
415*d6b92ffaSHans Petter Selasky 
get_klm_octo(int nentries)416*d6b92ffaSHans Petter Selasky static inline uint16_t get_klm_octo(int nentries)
417*d6b92ffaSHans Petter Selasky {
418*d6b92ffaSHans Petter Selasky 	return htobe16(ALIGN(nentries, 3) / 2);
419*d6b92ffaSHans Petter Selasky }
420*d6b92ffaSHans Petter Selasky 
set_umr_data_seg(struct mlx5_qp * qp,enum ibv_mw_type type,int32_t rkey,struct ibv_mw_bind_info * bind_info,uint32_t qpn,void ** seg,int * size)421*d6b92ffaSHans Petter Selasky static void set_umr_data_seg(struct mlx5_qp *qp, enum ibv_mw_type type,
422*d6b92ffaSHans Petter Selasky 			     int32_t rkey, struct ibv_mw_bind_info *bind_info,
423*d6b92ffaSHans Petter Selasky 			     uint32_t qpn, void **seg, int *size)
424*d6b92ffaSHans Petter Selasky {
425*d6b92ffaSHans Petter Selasky 	union {
426*d6b92ffaSHans Petter Selasky 		struct mlx5_wqe_umr_klm_seg	klm;
427*d6b92ffaSHans Petter Selasky 		uint8_t				reserved[64];
428*d6b92ffaSHans Petter Selasky 	} *data = *seg;
429*d6b92ffaSHans Petter Selasky 
430*d6b92ffaSHans Petter Selasky 	data->klm.byte_count = htobe32(bind_info->length);
431*d6b92ffaSHans Petter Selasky 	data->klm.mkey = htobe32(bind_info->mr->lkey);
432*d6b92ffaSHans Petter Selasky 	data->klm.address = htobe64(bind_info->addr);
433*d6b92ffaSHans Petter Selasky 
434*d6b92ffaSHans Petter Selasky 	memset(&data->klm + 1, 0, sizeof(data->reserved) -
435*d6b92ffaSHans Petter Selasky 	       sizeof(data->klm));
436*d6b92ffaSHans Petter Selasky 
437*d6b92ffaSHans Petter Selasky 	*seg += sizeof(*data);
438*d6b92ffaSHans Petter Selasky 	*size += (sizeof(*data) / 16);
439*d6b92ffaSHans Petter Selasky }
440*d6b92ffaSHans Petter Selasky 
set_umr_mkey_seg(struct mlx5_qp * qp,enum ibv_mw_type type,int32_t rkey,struct ibv_mw_bind_info * bind_info,uint32_t qpn,void ** seg,int * size)441*d6b92ffaSHans Petter Selasky static void set_umr_mkey_seg(struct mlx5_qp *qp, enum ibv_mw_type type,
442*d6b92ffaSHans Petter Selasky 			     int32_t rkey, struct ibv_mw_bind_info *bind_info,
443*d6b92ffaSHans Petter Selasky 			     uint32_t qpn, void **seg, int *size)
444*d6b92ffaSHans Petter Selasky {
445*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_mkey_context_seg	*mkey = *seg;
446*d6b92ffaSHans Petter Selasky 
447*d6b92ffaSHans Petter Selasky 	mkey->qpn_mkey = htobe32((rkey & 0xFF) |
448*d6b92ffaSHans Petter Selasky 				   ((type == IBV_MW_TYPE_1 || !bind_info->length) ?
449*d6b92ffaSHans Petter Selasky 				    0xFFFFFF00 : qpn << 8));
450*d6b92ffaSHans Petter Selasky 	if (bind_info->length) {
451*d6b92ffaSHans Petter Selasky 		/* Local read is set in kernel */
452*d6b92ffaSHans Petter Selasky 		mkey->access_flags = 0;
453*d6b92ffaSHans Petter Selasky 		mkey->free = 0;
454*d6b92ffaSHans Petter Selasky 		if (bind_info->mw_access_flags & IBV_ACCESS_LOCAL_WRITE)
455*d6b92ffaSHans Petter Selasky 			mkey->access_flags |=
456*d6b92ffaSHans Petter Selasky 				MLX5_WQE_MKEY_CONTEXT_ACCESS_FLAGS_LOCAL_WRITE;
457*d6b92ffaSHans Petter Selasky 		if (bind_info->mw_access_flags & IBV_ACCESS_REMOTE_WRITE)
458*d6b92ffaSHans Petter Selasky 			mkey->access_flags |=
459*d6b92ffaSHans Petter Selasky 				MLX5_WQE_MKEY_CONTEXT_ACCESS_FLAGS_REMOTE_WRITE;
460*d6b92ffaSHans Petter Selasky 		if (bind_info->mw_access_flags & IBV_ACCESS_REMOTE_READ)
461*d6b92ffaSHans Petter Selasky 			mkey->access_flags |=
462*d6b92ffaSHans Petter Selasky 				MLX5_WQE_MKEY_CONTEXT_ACCESS_FLAGS_REMOTE_READ;
463*d6b92ffaSHans Petter Selasky 		if (bind_info->mw_access_flags & IBV_ACCESS_REMOTE_ATOMIC)
464*d6b92ffaSHans Petter Selasky 			mkey->access_flags |=
465*d6b92ffaSHans Petter Selasky 				MLX5_WQE_MKEY_CONTEXT_ACCESS_FLAGS_ATOMIC;
466*d6b92ffaSHans Petter Selasky 		if (bind_info->mw_access_flags & IBV_ACCESS_ZERO_BASED)
467*d6b92ffaSHans Petter Selasky 			mkey->start_addr = 0;
468*d6b92ffaSHans Petter Selasky 		else
469*d6b92ffaSHans Petter Selasky 			mkey->start_addr = htobe64(bind_info->addr);
470*d6b92ffaSHans Petter Selasky 		mkey->len = htobe64(bind_info->length);
471*d6b92ffaSHans Petter Selasky 	} else {
472*d6b92ffaSHans Petter Selasky 		mkey->free = MLX5_WQE_MKEY_CONTEXT_FREE;
473*d6b92ffaSHans Petter Selasky 	}
474*d6b92ffaSHans Petter Selasky 
475*d6b92ffaSHans Petter Selasky 	*seg += sizeof(struct mlx5_wqe_mkey_context_seg);
476*d6b92ffaSHans Petter Selasky 	*size += (sizeof(struct mlx5_wqe_mkey_context_seg) / 16);
477*d6b92ffaSHans Petter Selasky }
478*d6b92ffaSHans Petter Selasky 
set_umr_control_seg(struct mlx5_qp * qp,enum ibv_mw_type type,int32_t rkey,struct ibv_mw_bind_info * bind_info,uint32_t qpn,void ** seg,int * size)479*d6b92ffaSHans Petter Selasky static inline void set_umr_control_seg(struct mlx5_qp *qp, enum ibv_mw_type type,
480*d6b92ffaSHans Petter Selasky 				       int32_t rkey, struct ibv_mw_bind_info *bind_info,
481*d6b92ffaSHans Petter Selasky 				       uint32_t qpn, void **seg, int *size)
482*d6b92ffaSHans Petter Selasky {
483*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_umr_ctrl_seg		*ctrl = *seg;
484*d6b92ffaSHans Petter Selasky 
485*d6b92ffaSHans Petter Selasky 	ctrl->flags = MLX5_WQE_UMR_CTRL_FLAG_TRNSLATION_OFFSET |
486*d6b92ffaSHans Petter Selasky 		MLX5_WQE_UMR_CTRL_FLAG_INLINE;
487*d6b92ffaSHans Petter Selasky 	ctrl->mkey_mask = htobe64(MLX5_WQE_UMR_CTRL_MKEY_MASK_FREE |
488*d6b92ffaSHans Petter Selasky 				     MLX5_WQE_UMR_CTRL_MKEY_MASK_MKEY);
489*d6b92ffaSHans Petter Selasky 	ctrl->translation_offset = 0;
490*d6b92ffaSHans Petter Selasky 	memset(ctrl->rsvd0, 0, sizeof(ctrl->rsvd0));
491*d6b92ffaSHans Petter Selasky 	memset(ctrl->rsvd1, 0, sizeof(ctrl->rsvd1));
492*d6b92ffaSHans Petter Selasky 
493*d6b92ffaSHans Petter Selasky 	if (type == IBV_MW_TYPE_2)
494*d6b92ffaSHans Petter Selasky 		ctrl->mkey_mask |= htobe64(MLX5_WQE_UMR_CTRL_MKEY_MASK_QPN);
495*d6b92ffaSHans Petter Selasky 
496*d6b92ffaSHans Petter Selasky 	if (bind_info->length) {
497*d6b92ffaSHans Petter Selasky 		ctrl->klm_octowords = get_klm_octo(1);
498*d6b92ffaSHans Petter Selasky 		if (type == IBV_MW_TYPE_2)
499*d6b92ffaSHans Petter Selasky 			ctrl->flags |=  MLX5_WQE_UMR_CTRL_FLAG_CHECK_FREE;
500*d6b92ffaSHans Petter Selasky 		ctrl->mkey_mask |= htobe64(MLX5_WQE_UMR_CTRL_MKEY_MASK_LEN	|
501*d6b92ffaSHans Petter Selasky 					      MLX5_WQE_UMR_CTRL_MKEY_MASK_START_ADDR |
502*d6b92ffaSHans Petter Selasky 					      MLX5_WQE_UMR_CTRL_MKEY_MASK_ACCESS_LOCAL_WRITE |
503*d6b92ffaSHans Petter Selasky 					      MLX5_WQE_UMR_CTRL_MKEY_MASK_ACCESS_REMOTE_READ |
504*d6b92ffaSHans Petter Selasky 					      MLX5_WQE_UMR_CTRL_MKEY_MASK_ACCESS_REMOTE_WRITE |
505*d6b92ffaSHans Petter Selasky 					      MLX5_WQE_UMR_CTRL_MKEY_MASK_ACCESS_ATOMIC);
506*d6b92ffaSHans Petter Selasky 	} else {
507*d6b92ffaSHans Petter Selasky 		ctrl->klm_octowords = get_klm_octo(0);
508*d6b92ffaSHans Petter Selasky 		if (type == IBV_MW_TYPE_2)
509*d6b92ffaSHans Petter Selasky 			ctrl->flags |= MLX5_WQE_UMR_CTRL_FLAG_CHECK_QPN;
510*d6b92ffaSHans Petter Selasky 	}
511*d6b92ffaSHans Petter Selasky 
512*d6b92ffaSHans Petter Selasky 	*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
513*d6b92ffaSHans Petter Selasky 	*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
514*d6b92ffaSHans Petter Selasky }
515*d6b92ffaSHans Petter Selasky 
set_bind_wr(struct mlx5_qp * qp,enum ibv_mw_type type,int32_t rkey,struct ibv_mw_bind_info * bind_info,uint32_t qpn,void ** seg,int * size)516*d6b92ffaSHans Petter Selasky static inline int set_bind_wr(struct mlx5_qp *qp, enum ibv_mw_type type,
517*d6b92ffaSHans Petter Selasky 			      int32_t rkey, struct ibv_mw_bind_info *bind_info,
518*d6b92ffaSHans Petter Selasky 			      uint32_t qpn, void **seg, int *size)
519*d6b92ffaSHans Petter Selasky {
520*d6b92ffaSHans Petter Selasky 	void *qend = qp->sq.qend;
521*d6b92ffaSHans Petter Selasky 
522*d6b92ffaSHans Petter Selasky #ifdef MW_DEBUG
523*d6b92ffaSHans Petter Selasky 	if (bind_info->mw_access_flags &
524*d6b92ffaSHans Petter Selasky 	    ~(IBV_ACCESS_REMOTE_ATOMIC | IBV_ACCESS_REMOTE_READ |
525*d6b92ffaSHans Petter Selasky 	     IBV_ACCESS_REMOTE_WRITE))
526*d6b92ffaSHans Petter Selasky 		return EINVAL;
527*d6b92ffaSHans Petter Selasky 
528*d6b92ffaSHans Petter Selasky 	if (bind_info->mr &&
529*d6b92ffaSHans Petter Selasky 	    (bind_info->mr->addr > (void *)bind_info->addr ||
530*d6b92ffaSHans Petter Selasky 	     bind_info->mr->addr + bind_info->mr->length <
531*d6b92ffaSHans Petter Selasky 	     (void *)bind_info->addr + bind_info->length ||
532*d6b92ffaSHans Petter Selasky 	     !(to_mmr(bind_info->mr)->alloc_flags &  IBV_ACCESS_MW_BIND) ||
533*d6b92ffaSHans Petter Selasky 	     (bind_info->mw_access_flags &
534*d6b92ffaSHans Petter Selasky 	      (IBV_ACCESS_REMOTE_ATOMIC | IBV_ACCESS_REMOTE_WRITE) &&
535*d6b92ffaSHans Petter Selasky 	      !(to_mmr(bind_info->mr)->alloc_flags & IBV_ACCESS_LOCAL_WRITE))))
536*d6b92ffaSHans Petter Selasky 		return EINVAL;
537*d6b92ffaSHans Petter Selasky 
538*d6b92ffaSHans Petter Selasky #endif
539*d6b92ffaSHans Petter Selasky 
540*d6b92ffaSHans Petter Selasky 	/* check that len > 2GB because KLM support only 2GB */
541*d6b92ffaSHans Petter Selasky 	if (bind_info->length > 1UL << 31)
542*d6b92ffaSHans Petter Selasky 		return EOPNOTSUPP;
543*d6b92ffaSHans Petter Selasky 
544*d6b92ffaSHans Petter Selasky 	set_umr_control_seg(qp, type, rkey, bind_info, qpn, seg, size);
545*d6b92ffaSHans Petter Selasky 	if (unlikely((*seg == qend)))
546*d6b92ffaSHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
547*d6b92ffaSHans Petter Selasky 
548*d6b92ffaSHans Petter Selasky 	set_umr_mkey_seg(qp, type, rkey, bind_info, qpn, seg, size);
549*d6b92ffaSHans Petter Selasky 	if (!bind_info->length)
550*d6b92ffaSHans Petter Selasky 		return 0;
551*d6b92ffaSHans Petter Selasky 
552*d6b92ffaSHans Petter Selasky 	if (unlikely((seg == qend)))
553*d6b92ffaSHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
554*d6b92ffaSHans Petter Selasky 
555*d6b92ffaSHans Petter Selasky 	set_umr_data_seg(qp, type, rkey, bind_info, qpn, seg, size);
556*d6b92ffaSHans Petter Selasky 	return 0;
557*d6b92ffaSHans Petter Selasky }
558*d6b92ffaSHans Petter Selasky 
559*d6b92ffaSHans Petter Selasky /* Copy tso header to eth segment with considering padding and WQE
560*d6b92ffaSHans Petter Selasky  * wrap around in WQ buffer.
561*d6b92ffaSHans Petter Selasky  */
set_tso_eth_seg(void ** seg,struct ibv_send_wr * wr,void * qend,struct mlx5_qp * qp,int * size)562*d6b92ffaSHans Petter Selasky static inline int set_tso_eth_seg(void **seg, struct ibv_send_wr *wr,
563*d6b92ffaSHans Petter Selasky 				   void *qend, struct mlx5_qp *qp, int *size)
564*d6b92ffaSHans Petter Selasky {
565*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_eth_seg *eseg = *seg;
566*d6b92ffaSHans Petter Selasky 	int size_of_inl_hdr_start = sizeof(eseg->inline_hdr_start);
567*d6b92ffaSHans Petter Selasky 	uint64_t left, left_len, copy_sz;
568*d6b92ffaSHans Petter Selasky 	void *pdata = wr->tso.hdr;
569*d6b92ffaSHans Petter Selasky 	FILE *fp = to_mctx(qp->ibv_qp->context)->dbg_fp;
570*d6b92ffaSHans Petter Selasky 
571*d6b92ffaSHans Petter Selasky 	if (unlikely(wr->tso.hdr_sz < MLX5_ETH_L2_MIN_HEADER_SIZE ||
572*d6b92ffaSHans Petter Selasky 		     wr->tso.hdr_sz > qp->max_tso_header)) {
573*d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP_SEND,
574*d6b92ffaSHans Petter Selasky 			 "TSO header size should be at least %d and at most %d\n",
575*d6b92ffaSHans Petter Selasky 			 MLX5_ETH_L2_MIN_HEADER_SIZE,
576*d6b92ffaSHans Petter Selasky 			 qp->max_tso_header);
577*d6b92ffaSHans Petter Selasky 		return EINVAL;
578*d6b92ffaSHans Petter Selasky 	}
579*d6b92ffaSHans Petter Selasky 
580*d6b92ffaSHans Petter Selasky 	left = wr->tso.hdr_sz;
581*d6b92ffaSHans Petter Selasky 	eseg->mss = htobe16(wr->tso.mss);
582*d6b92ffaSHans Petter Selasky 	eseg->inline_hdr_sz = htobe16(wr->tso.hdr_sz);
583*d6b92ffaSHans Petter Selasky 
584*d6b92ffaSHans Petter Selasky 	/* Check if there is space till the end of queue, if yes,
585*d6b92ffaSHans Petter Selasky 	 * copy all in one shot, otherwise copy till the end of queue,
586*d6b92ffaSHans Petter Selasky 	 * rollback and then copy the left
587*d6b92ffaSHans Petter Selasky 	 */
588*d6b92ffaSHans Petter Selasky 	left_len = qend - (void *)eseg->inline_hdr_start;
589*d6b92ffaSHans Petter Selasky 	copy_sz = min(left_len, left);
590*d6b92ffaSHans Petter Selasky 
591*d6b92ffaSHans Petter Selasky 	memcpy(eseg->inline_hdr_start, pdata, copy_sz);
592*d6b92ffaSHans Petter Selasky 
593*d6b92ffaSHans Petter Selasky 	/* The -1 is because there are already 16 bytes included in
594*d6b92ffaSHans Petter Selasky 	 * eseg->inline_hdr[16]
595*d6b92ffaSHans Petter Selasky 	 */
596*d6b92ffaSHans Petter Selasky 	*seg += align(copy_sz - size_of_inl_hdr_start, 16) - 16;
597*d6b92ffaSHans Petter Selasky 	*size += align(copy_sz - size_of_inl_hdr_start, 16) / 16 - 1;
598*d6b92ffaSHans Petter Selasky 
599*d6b92ffaSHans Petter Selasky 	/* The last wqe in the queue */
600*d6b92ffaSHans Petter Selasky 	if (unlikely(copy_sz < left)) {
601*d6b92ffaSHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
602*d6b92ffaSHans Petter Selasky 		left -= copy_sz;
603*d6b92ffaSHans Petter Selasky 		pdata += copy_sz;
604*d6b92ffaSHans Petter Selasky 		memcpy(*seg, pdata, left);
605*d6b92ffaSHans Petter Selasky 		*seg += align(left, 16);
606*d6b92ffaSHans Petter Selasky 		*size += align(left, 16) / 16;
607*d6b92ffaSHans Petter Selasky 	}
608*d6b92ffaSHans Petter Selasky 
609*d6b92ffaSHans Petter Selasky 	return 0;
610*d6b92ffaSHans Petter Selasky }
611*d6b92ffaSHans Petter Selasky 
_mlx5_post_send(struct ibv_qp * ibqp,struct ibv_send_wr * wr,struct ibv_send_wr ** bad_wr)612*d6b92ffaSHans Petter Selasky static inline int _mlx5_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr,
613*d6b92ffaSHans Petter Selasky 				  struct ibv_send_wr **bad_wr)
614*d6b92ffaSHans Petter Selasky {
615*d6b92ffaSHans Petter Selasky 	struct mlx5_context *ctx;
616*d6b92ffaSHans Petter Selasky 	struct mlx5_qp *qp = to_mqp(ibqp);
617*d6b92ffaSHans Petter Selasky 	void *seg;
618*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_eth_seg *eseg;
619*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_ctrl_seg *ctrl = NULL;
620*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_data_seg *dpseg;
621*d6b92ffaSHans Petter Selasky 	struct mlx5_sg_copy_ptr sg_copy_ptr = {.index = 0, .offset = 0};
622*d6b92ffaSHans Petter Selasky 	int nreq;
623*d6b92ffaSHans Petter Selasky 	int inl = 0;
624*d6b92ffaSHans Petter Selasky 	int err = 0;
625*d6b92ffaSHans Petter Selasky 	int size = 0;
626*d6b92ffaSHans Petter Selasky 	int i;
627*d6b92ffaSHans Petter Selasky 	unsigned idx;
628*d6b92ffaSHans Petter Selasky 	uint8_t opmod = 0;
629*d6b92ffaSHans Petter Selasky 	struct mlx5_bf *bf = qp->bf;
630*d6b92ffaSHans Petter Selasky 	void *qend = qp->sq.qend;
631*d6b92ffaSHans Petter Selasky 	uint32_t mlx5_opcode;
632*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_xrc_seg *xrc;
633*d6b92ffaSHans Petter Selasky 	uint8_t fence;
634*d6b92ffaSHans Petter Selasky 	uint8_t next_fence;
635*d6b92ffaSHans Petter Selasky 	uint32_t max_tso = 0;
636*d6b92ffaSHans Petter Selasky 	FILE *fp = to_mctx(ibqp->context)->dbg_fp; /* The compiler ignores in non-debug mode */
637*d6b92ffaSHans Petter Selasky 
638*d6b92ffaSHans Petter Selasky 	mlx5_spin_lock(&qp->sq.lock);
639*d6b92ffaSHans Petter Selasky 
640*d6b92ffaSHans Petter Selasky 	next_fence = qp->fm_cache;
641*d6b92ffaSHans Petter Selasky 
642*d6b92ffaSHans Petter Selasky 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
643*d6b92ffaSHans Petter Selasky 		if (unlikely(wr->opcode < 0 ||
644*d6b92ffaSHans Petter Selasky 		    wr->opcode >= sizeof mlx5_ib_opcode / sizeof mlx5_ib_opcode[0])) {
645*d6b92ffaSHans Petter Selasky 			mlx5_dbg(fp, MLX5_DBG_QP_SEND, "bad opcode %d\n", wr->opcode);
646*d6b92ffaSHans Petter Selasky 			err = EINVAL;
647*d6b92ffaSHans Petter Selasky 			*bad_wr = wr;
648*d6b92ffaSHans Petter Selasky 			goto out;
649*d6b92ffaSHans Petter Selasky 		}
650*d6b92ffaSHans Petter Selasky 
651*d6b92ffaSHans Petter Selasky 		if (unlikely(mlx5_wq_overflow(&qp->sq, nreq,
652*d6b92ffaSHans Petter Selasky 					      to_mcq(qp->ibv_qp->send_cq)))) {
653*d6b92ffaSHans Petter Selasky 			mlx5_dbg(fp, MLX5_DBG_QP_SEND, "work queue overflow\n");
654*d6b92ffaSHans Petter Selasky 			err = ENOMEM;
655*d6b92ffaSHans Petter Selasky 			*bad_wr = wr;
656*d6b92ffaSHans Petter Selasky 			goto out;
657*d6b92ffaSHans Petter Selasky 		}
658*d6b92ffaSHans Petter Selasky 
659*d6b92ffaSHans Petter Selasky 		if (unlikely(wr->num_sge > qp->sq.max_gs)) {
660*d6b92ffaSHans Petter Selasky 			mlx5_dbg(fp, MLX5_DBG_QP_SEND, "max gs exceeded %d (max = %d)\n",
661*d6b92ffaSHans Petter Selasky 				 wr->num_sge, qp->sq.max_gs);
662*d6b92ffaSHans Petter Selasky 			err = ENOMEM;
663*d6b92ffaSHans Petter Selasky 			*bad_wr = wr;
664*d6b92ffaSHans Petter Selasky 			goto out;
665*d6b92ffaSHans Petter Selasky 		}
666*d6b92ffaSHans Petter Selasky 
667*d6b92ffaSHans Petter Selasky 		if (wr->send_flags & IBV_SEND_FENCE)
668*d6b92ffaSHans Petter Selasky 			fence = MLX5_WQE_CTRL_FENCE;
669*d6b92ffaSHans Petter Selasky 		else
670*d6b92ffaSHans Petter Selasky 			fence = next_fence;
671*d6b92ffaSHans Petter Selasky 		next_fence = 0;
672*d6b92ffaSHans Petter Selasky 		idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1);
673*d6b92ffaSHans Petter Selasky 		ctrl = seg = mlx5_get_send_wqe(qp, idx);
674*d6b92ffaSHans Petter Selasky 		*(uint32_t *)(seg + 8) = 0;
675*d6b92ffaSHans Petter Selasky 		ctrl->imm = send_ieth(wr);
676*d6b92ffaSHans Petter Selasky 		ctrl->fm_ce_se = qp->sq_signal_bits | fence |
677*d6b92ffaSHans Petter Selasky 			(wr->send_flags & IBV_SEND_SIGNALED ?
678*d6b92ffaSHans Petter Selasky 			 MLX5_WQE_CTRL_CQ_UPDATE : 0) |
679*d6b92ffaSHans Petter Selasky 			(wr->send_flags & IBV_SEND_SOLICITED ?
680*d6b92ffaSHans Petter Selasky 			 MLX5_WQE_CTRL_SOLICITED : 0);
681*d6b92ffaSHans Petter Selasky 
682*d6b92ffaSHans Petter Selasky 		seg += sizeof *ctrl;
683*d6b92ffaSHans Petter Selasky 		size = sizeof *ctrl / 16;
684*d6b92ffaSHans Petter Selasky 
685*d6b92ffaSHans Petter Selasky 		switch (ibqp->qp_type) {
686*d6b92ffaSHans Petter Selasky 		case IBV_QPT_XRC_SEND:
687*d6b92ffaSHans Petter Selasky 			if (unlikely(wr->opcode != IBV_WR_BIND_MW &&
688*d6b92ffaSHans Petter Selasky 				     wr->opcode != IBV_WR_LOCAL_INV)) {
689*d6b92ffaSHans Petter Selasky 				xrc = seg;
690*d6b92ffaSHans Petter Selasky 				xrc->xrc_srqn = htobe32(wr->qp_type.xrc.remote_srqn);
691*d6b92ffaSHans Petter Selasky 				seg += sizeof(*xrc);
692*d6b92ffaSHans Petter Selasky 				size += sizeof(*xrc) / 16;
693*d6b92ffaSHans Petter Selasky 			}
694*d6b92ffaSHans Petter Selasky 			/* fall through */
695*d6b92ffaSHans Petter Selasky 		case IBV_QPT_RC:
696*d6b92ffaSHans Petter Selasky 			switch (wr->opcode) {
697*d6b92ffaSHans Petter Selasky 			case IBV_WR_RDMA_READ:
698*d6b92ffaSHans Petter Selasky 			case IBV_WR_RDMA_WRITE:
699*d6b92ffaSHans Petter Selasky 			case IBV_WR_RDMA_WRITE_WITH_IMM:
700*d6b92ffaSHans Petter Selasky 				set_raddr_seg(seg, wr->wr.rdma.remote_addr,
701*d6b92ffaSHans Petter Selasky 					      wr->wr.rdma.rkey);
702*d6b92ffaSHans Petter Selasky 				seg  += sizeof(struct mlx5_wqe_raddr_seg);
703*d6b92ffaSHans Petter Selasky 				size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
704*d6b92ffaSHans Petter Selasky 				break;
705*d6b92ffaSHans Petter Selasky 
706*d6b92ffaSHans Petter Selasky 			case IBV_WR_ATOMIC_CMP_AND_SWP:
707*d6b92ffaSHans Petter Selasky 			case IBV_WR_ATOMIC_FETCH_AND_ADD:
708*d6b92ffaSHans Petter Selasky 				if (unlikely(!qp->atomics_enabled)) {
709*d6b92ffaSHans Petter Selasky 					mlx5_dbg(fp, MLX5_DBG_QP_SEND, "atomic operations are not supported\n");
710*d6b92ffaSHans Petter Selasky 					err = ENOSYS;
711*d6b92ffaSHans Petter Selasky 					*bad_wr = wr;
712*d6b92ffaSHans Petter Selasky 					goto out;
713*d6b92ffaSHans Petter Selasky 				}
714*d6b92ffaSHans Petter Selasky 				set_raddr_seg(seg, wr->wr.atomic.remote_addr,
715*d6b92ffaSHans Petter Selasky 					      wr->wr.atomic.rkey);
716*d6b92ffaSHans Petter Selasky 				seg  += sizeof(struct mlx5_wqe_raddr_seg);
717*d6b92ffaSHans Petter Selasky 
718*d6b92ffaSHans Petter Selasky 				set_atomic_seg(seg, wr->opcode,
719*d6b92ffaSHans Petter Selasky 					       wr->wr.atomic.swap,
720*d6b92ffaSHans Petter Selasky 					       wr->wr.atomic.compare_add);
721*d6b92ffaSHans Petter Selasky 				seg  += sizeof(struct mlx5_wqe_atomic_seg);
722*d6b92ffaSHans Petter Selasky 
723*d6b92ffaSHans Petter Selasky 				size += (sizeof(struct mlx5_wqe_raddr_seg) +
724*d6b92ffaSHans Petter Selasky 				sizeof(struct mlx5_wqe_atomic_seg)) / 16;
725*d6b92ffaSHans Petter Selasky 				break;
726*d6b92ffaSHans Petter Selasky 
727*d6b92ffaSHans Petter Selasky 			case IBV_WR_BIND_MW:
728*d6b92ffaSHans Petter Selasky 				next_fence = MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE;
729*d6b92ffaSHans Petter Selasky 				ctrl->imm = htobe32(wr->bind_mw.mw->rkey);
730*d6b92ffaSHans Petter Selasky 				err = set_bind_wr(qp, wr->bind_mw.mw->type,
731*d6b92ffaSHans Petter Selasky 						  wr->bind_mw.rkey,
732*d6b92ffaSHans Petter Selasky 						  &wr->bind_mw.bind_info,
733*d6b92ffaSHans Petter Selasky 						  ibqp->qp_num, &seg, &size);
734*d6b92ffaSHans Petter Selasky 				if (err) {
735*d6b92ffaSHans Petter Selasky 					*bad_wr = wr;
736*d6b92ffaSHans Petter Selasky 					goto out;
737*d6b92ffaSHans Petter Selasky 				}
738*d6b92ffaSHans Petter Selasky 
739*d6b92ffaSHans Petter Selasky 				qp->sq.wr_data[idx] = IBV_WC_BIND_MW;
740*d6b92ffaSHans Petter Selasky 				break;
741*d6b92ffaSHans Petter Selasky 			case IBV_WR_LOCAL_INV: {
742*d6b92ffaSHans Petter Selasky 				struct ibv_mw_bind_info	bind_info = {};
743*d6b92ffaSHans Petter Selasky 
744*d6b92ffaSHans Petter Selasky 				next_fence = MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE;
745*d6b92ffaSHans Petter Selasky 				ctrl->imm = htobe32(wr->imm_data);
746*d6b92ffaSHans Petter Selasky 				err = set_bind_wr(qp, IBV_MW_TYPE_2, 0,
747*d6b92ffaSHans Petter Selasky 						  &bind_info, ibqp->qp_num,
748*d6b92ffaSHans Petter Selasky 						  &seg, &size);
749*d6b92ffaSHans Petter Selasky 				if (err) {
750*d6b92ffaSHans Petter Selasky 					*bad_wr = wr;
751*d6b92ffaSHans Petter Selasky 					goto out;
752*d6b92ffaSHans Petter Selasky 				}
753*d6b92ffaSHans Petter Selasky 
754*d6b92ffaSHans Petter Selasky 				qp->sq.wr_data[idx] = IBV_WC_LOCAL_INV;
755*d6b92ffaSHans Petter Selasky 				break;
756*d6b92ffaSHans Petter Selasky 			}
757*d6b92ffaSHans Petter Selasky 
758*d6b92ffaSHans Petter Selasky 			default:
759*d6b92ffaSHans Petter Selasky 				break;
760*d6b92ffaSHans Petter Selasky 			}
761*d6b92ffaSHans Petter Selasky 			break;
762*d6b92ffaSHans Petter Selasky 
763*d6b92ffaSHans Petter Selasky 		case IBV_QPT_UC:
764*d6b92ffaSHans Petter Selasky 			switch (wr->opcode) {
765*d6b92ffaSHans Petter Selasky 			case IBV_WR_RDMA_WRITE:
766*d6b92ffaSHans Petter Selasky 			case IBV_WR_RDMA_WRITE_WITH_IMM:
767*d6b92ffaSHans Petter Selasky 				set_raddr_seg(seg, wr->wr.rdma.remote_addr,
768*d6b92ffaSHans Petter Selasky 					      wr->wr.rdma.rkey);
769*d6b92ffaSHans Petter Selasky 				seg  += sizeof(struct mlx5_wqe_raddr_seg);
770*d6b92ffaSHans Petter Selasky 				size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
771*d6b92ffaSHans Petter Selasky 				break;
772*d6b92ffaSHans Petter Selasky 			case IBV_WR_BIND_MW:
773*d6b92ffaSHans Petter Selasky 				next_fence = MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE;
774*d6b92ffaSHans Petter Selasky 				ctrl->imm = htobe32(wr->bind_mw.mw->rkey);
775*d6b92ffaSHans Petter Selasky 				err = set_bind_wr(qp, wr->bind_mw.mw->type,
776*d6b92ffaSHans Petter Selasky 						  wr->bind_mw.rkey,
777*d6b92ffaSHans Petter Selasky 						  &wr->bind_mw.bind_info,
778*d6b92ffaSHans Petter Selasky 						  ibqp->qp_num, &seg, &size);
779*d6b92ffaSHans Petter Selasky 				if (err) {
780*d6b92ffaSHans Petter Selasky 					*bad_wr = wr;
781*d6b92ffaSHans Petter Selasky 					goto out;
782*d6b92ffaSHans Petter Selasky 				}
783*d6b92ffaSHans Petter Selasky 
784*d6b92ffaSHans Petter Selasky 				qp->sq.wr_data[idx] = IBV_WC_BIND_MW;
785*d6b92ffaSHans Petter Selasky 				break;
786*d6b92ffaSHans Petter Selasky 			case IBV_WR_LOCAL_INV: {
787*d6b92ffaSHans Petter Selasky 				struct ibv_mw_bind_info	bind_info = {};
788*d6b92ffaSHans Petter Selasky 
789*d6b92ffaSHans Petter Selasky 				next_fence = MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE;
790*d6b92ffaSHans Petter Selasky 				ctrl->imm = htobe32(wr->imm_data);
791*d6b92ffaSHans Petter Selasky 				err = set_bind_wr(qp, IBV_MW_TYPE_2, 0,
792*d6b92ffaSHans Petter Selasky 						  &bind_info, ibqp->qp_num,
793*d6b92ffaSHans Petter Selasky 						  &seg, &size);
794*d6b92ffaSHans Petter Selasky 				if (err) {
795*d6b92ffaSHans Petter Selasky 					*bad_wr = wr;
796*d6b92ffaSHans Petter Selasky 					goto out;
797*d6b92ffaSHans Petter Selasky 				}
798*d6b92ffaSHans Petter Selasky 
799*d6b92ffaSHans Petter Selasky 				qp->sq.wr_data[idx] = IBV_WC_LOCAL_INV;
800*d6b92ffaSHans Petter Selasky 				break;
801*d6b92ffaSHans Petter Selasky 			}
802*d6b92ffaSHans Petter Selasky 
803*d6b92ffaSHans Petter Selasky 			default:
804*d6b92ffaSHans Petter Selasky 				break;
805*d6b92ffaSHans Petter Selasky 			}
806*d6b92ffaSHans Petter Selasky 			break;
807*d6b92ffaSHans Petter Selasky 
808*d6b92ffaSHans Petter Selasky 		case IBV_QPT_UD:
809*d6b92ffaSHans Petter Selasky 			set_datagram_seg(seg, wr);
810*d6b92ffaSHans Petter Selasky 			seg  += sizeof(struct mlx5_wqe_datagram_seg);
811*d6b92ffaSHans Petter Selasky 			size += sizeof(struct mlx5_wqe_datagram_seg) / 16;
812*d6b92ffaSHans Petter Selasky 			if (unlikely((seg == qend)))
813*d6b92ffaSHans Petter Selasky 				seg = mlx5_get_send_wqe(qp, 0);
814*d6b92ffaSHans Petter Selasky 			break;
815*d6b92ffaSHans Petter Selasky 
816*d6b92ffaSHans Petter Selasky 		case IBV_QPT_RAW_PACKET:
817*d6b92ffaSHans Petter Selasky 			memset(seg, 0, sizeof(struct mlx5_wqe_eth_seg));
818*d6b92ffaSHans Petter Selasky 			eseg = seg;
819*d6b92ffaSHans Petter Selasky 
820*d6b92ffaSHans Petter Selasky 			if (wr->send_flags & IBV_SEND_IP_CSUM) {
821*d6b92ffaSHans Petter Selasky 				if (!(qp->qp_cap_cache & MLX5_CSUM_SUPPORT_RAW_OVER_ETH)) {
822*d6b92ffaSHans Petter Selasky 					err = EINVAL;
823*d6b92ffaSHans Petter Selasky 					*bad_wr = wr;
824*d6b92ffaSHans Petter Selasky 					goto out;
825*d6b92ffaSHans Petter Selasky 				}
826*d6b92ffaSHans Petter Selasky 
827*d6b92ffaSHans Petter Selasky 				eseg->cs_flags |= MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
828*d6b92ffaSHans Petter Selasky 			}
829*d6b92ffaSHans Petter Selasky 
830*d6b92ffaSHans Petter Selasky 			if (wr->opcode == IBV_WR_TSO) {
831*d6b92ffaSHans Petter Selasky 				max_tso = qp->max_tso;
832*d6b92ffaSHans Petter Selasky 				err = set_tso_eth_seg(&seg, wr, qend, qp, &size);
833*d6b92ffaSHans Petter Selasky 				if (unlikely(err)) {
834*d6b92ffaSHans Petter Selasky 					*bad_wr = wr;
835*d6b92ffaSHans Petter Selasky 					goto out;
836*d6b92ffaSHans Petter Selasky 				}
837*d6b92ffaSHans Petter Selasky 			} else {
838*d6b92ffaSHans Petter Selasky 				err = copy_eth_inline_headers(ibqp, wr, seg, &sg_copy_ptr);
839*d6b92ffaSHans Petter Selasky 				if (unlikely(err)) {
840*d6b92ffaSHans Petter Selasky 					*bad_wr = wr;
841*d6b92ffaSHans Petter Selasky 					mlx5_dbg(fp, MLX5_DBG_QP_SEND,
842*d6b92ffaSHans Petter Selasky 						 "copy_eth_inline_headers failed, err: %d\n",
843*d6b92ffaSHans Petter Selasky 						 err);
844*d6b92ffaSHans Petter Selasky 					goto out;
845*d6b92ffaSHans Petter Selasky 				}
846*d6b92ffaSHans Petter Selasky 			}
847*d6b92ffaSHans Petter Selasky 
848*d6b92ffaSHans Petter Selasky 			seg += sizeof(struct mlx5_wqe_eth_seg);
849*d6b92ffaSHans Petter Selasky 			size += sizeof(struct mlx5_wqe_eth_seg) / 16;
850*d6b92ffaSHans Petter Selasky 			break;
851*d6b92ffaSHans Petter Selasky 
852*d6b92ffaSHans Petter Selasky 		default:
853*d6b92ffaSHans Petter Selasky 			break;
854*d6b92ffaSHans Petter Selasky 		}
855*d6b92ffaSHans Petter Selasky 
856*d6b92ffaSHans Petter Selasky 		if (wr->send_flags & IBV_SEND_INLINE && wr->num_sge) {
857*d6b92ffaSHans Petter Selasky 			int sz = 0;
858*d6b92ffaSHans Petter Selasky 
859*d6b92ffaSHans Petter Selasky 			err = set_data_inl_seg(qp, wr, seg, &sz, &sg_copy_ptr);
860*d6b92ffaSHans Petter Selasky 			if (unlikely(err)) {
861*d6b92ffaSHans Petter Selasky 				*bad_wr = wr;
862*d6b92ffaSHans Petter Selasky 				mlx5_dbg(fp, MLX5_DBG_QP_SEND,
863*d6b92ffaSHans Petter Selasky 					 "inline layout failed, err %d\n", err);
864*d6b92ffaSHans Petter Selasky 				goto out;
865*d6b92ffaSHans Petter Selasky 			}
866*d6b92ffaSHans Petter Selasky 			inl = 1;
867*d6b92ffaSHans Petter Selasky 			size += sz;
868*d6b92ffaSHans Petter Selasky 		} else {
869*d6b92ffaSHans Petter Selasky 			dpseg = seg;
870*d6b92ffaSHans Petter Selasky 			for (i = sg_copy_ptr.index; i < wr->num_sge; ++i) {
871*d6b92ffaSHans Petter Selasky 				if (unlikely(dpseg == qend)) {
872*d6b92ffaSHans Petter Selasky 					seg = mlx5_get_send_wqe(qp, 0);
873*d6b92ffaSHans Petter Selasky 					dpseg = seg;
874*d6b92ffaSHans Petter Selasky 				}
875*d6b92ffaSHans Petter Selasky 				if (likely(wr->sg_list[i].length)) {
876*d6b92ffaSHans Petter Selasky 					if (unlikely(wr->opcode ==
877*d6b92ffaSHans Petter Selasky 						   IBV_WR_ATOMIC_CMP_AND_SWP ||
878*d6b92ffaSHans Petter Selasky 						   wr->opcode ==
879*d6b92ffaSHans Petter Selasky 						   IBV_WR_ATOMIC_FETCH_AND_ADD))
880*d6b92ffaSHans Petter Selasky 						set_data_ptr_seg_atomic(dpseg, wr->sg_list + i);
881*d6b92ffaSHans Petter Selasky 					else {
882*d6b92ffaSHans Petter Selasky 						if (unlikely(wr->opcode == IBV_WR_TSO)) {
883*d6b92ffaSHans Petter Selasky 							if (max_tso < wr->sg_list[i].length) {
884*d6b92ffaSHans Petter Selasky 								err = EINVAL;
885*d6b92ffaSHans Petter Selasky 								*bad_wr = wr;
886*d6b92ffaSHans Petter Selasky 								goto out;
887*d6b92ffaSHans Petter Selasky 							}
888*d6b92ffaSHans Petter Selasky 							max_tso -= wr->sg_list[i].length;
889*d6b92ffaSHans Petter Selasky 						}
890*d6b92ffaSHans Petter Selasky 						set_data_ptr_seg(dpseg, wr->sg_list + i,
891*d6b92ffaSHans Petter Selasky 								 sg_copy_ptr.offset);
892*d6b92ffaSHans Petter Selasky 					}
893*d6b92ffaSHans Petter Selasky 					sg_copy_ptr.offset = 0;
894*d6b92ffaSHans Petter Selasky 					++dpseg;
895*d6b92ffaSHans Petter Selasky 					size += sizeof(struct mlx5_wqe_data_seg) / 16;
896*d6b92ffaSHans Petter Selasky 				}
897*d6b92ffaSHans Petter Selasky 			}
898*d6b92ffaSHans Petter Selasky 		}
899*d6b92ffaSHans Petter Selasky 
900*d6b92ffaSHans Petter Selasky 		mlx5_opcode = mlx5_ib_opcode[wr->opcode];
901*d6b92ffaSHans Petter Selasky 		ctrl->opmod_idx_opcode = htobe32(((qp->sq.cur_post & 0xffff) << 8) |
902*d6b92ffaSHans Petter Selasky 					       mlx5_opcode			 |
903*d6b92ffaSHans Petter Selasky 					       (opmod << 24));
904*d6b92ffaSHans Petter Selasky 		ctrl->qpn_ds = htobe32(size | (ibqp->qp_num << 8));
905*d6b92ffaSHans Petter Selasky 
906*d6b92ffaSHans Petter Selasky 		if (unlikely(qp->wq_sig))
907*d6b92ffaSHans Petter Selasky 			ctrl->signature = wq_sig(ctrl);
908*d6b92ffaSHans Petter Selasky 
909*d6b92ffaSHans Petter Selasky 		qp->sq.wrid[idx] = wr->wr_id;
910*d6b92ffaSHans Petter Selasky 		qp->sq.wqe_head[idx] = qp->sq.head + nreq;
911*d6b92ffaSHans Petter Selasky 		qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB);
912*d6b92ffaSHans Petter Selasky 
913*d6b92ffaSHans Petter Selasky #ifdef MLX5_DEBUG
914*d6b92ffaSHans Petter Selasky 		if (mlx5_debug_mask & MLX5_DBG_QP_SEND)
915*d6b92ffaSHans Petter Selasky 			dump_wqe(to_mctx(ibqp->context)->dbg_fp, idx, size, qp);
916*d6b92ffaSHans Petter Selasky #endif
917*d6b92ffaSHans Petter Selasky 	}
918*d6b92ffaSHans Petter Selasky 
919*d6b92ffaSHans Petter Selasky out:
920*d6b92ffaSHans Petter Selasky 	if (likely(nreq)) {
921*d6b92ffaSHans Petter Selasky 		qp->sq.head += nreq;
922*d6b92ffaSHans Petter Selasky 		qp->fm_cache = next_fence;
923*d6b92ffaSHans Petter Selasky 
924*d6b92ffaSHans Petter Selasky 		/*
925*d6b92ffaSHans Petter Selasky 		 * Make sure that descriptors are written before
926*d6b92ffaSHans Petter Selasky 		 * updating doorbell record and ringing the doorbell
927*d6b92ffaSHans Petter Selasky 		 */
928*d6b92ffaSHans Petter Selasky 		udma_to_device_barrier();
929*d6b92ffaSHans Petter Selasky 		qp->db[MLX5_SND_DBR] = htobe32(qp->sq.cur_post & 0xffff);
930*d6b92ffaSHans Petter Selasky 
931*d6b92ffaSHans Petter Selasky 		/* Make sure that the doorbell write happens before the memcpy
932*d6b92ffaSHans Petter Selasky 		 * to WC memory below */
933*d6b92ffaSHans Petter Selasky 		ctx = to_mctx(ibqp->context);
934*d6b92ffaSHans Petter Selasky 		if (bf->need_lock)
935*d6b92ffaSHans Petter Selasky 			mmio_wc_spinlock(&bf->lock.lock);
936*d6b92ffaSHans Petter Selasky 		else
937*d6b92ffaSHans Petter Selasky 			mmio_wc_start();
938*d6b92ffaSHans Petter Selasky 
939*d6b92ffaSHans Petter Selasky 		if (!ctx->shut_up_bf && nreq == 1 && bf->uuarn &&
940*d6b92ffaSHans Petter Selasky 		    (inl || ctx->prefer_bf) && size > 1 &&
941*d6b92ffaSHans Petter Selasky 		    size <= bf->buf_size / 16)
942*d6b92ffaSHans Petter Selasky 			mlx5_bf_copy(bf->reg + bf->offset, (unsigned long long *)ctrl,
943*d6b92ffaSHans Petter Selasky 				     align(size * 16, 64), qp);
944*d6b92ffaSHans Petter Selasky 		else
945*d6b92ffaSHans Petter Selasky 			mlx5_write64((__be32 *)ctrl, bf->reg + bf->offset,
946*d6b92ffaSHans Petter Selasky 				     &ctx->lock32);
947*d6b92ffaSHans Petter Selasky 
948*d6b92ffaSHans Petter Selasky 		/*
949*d6b92ffaSHans Petter Selasky 		 * use mmio_flush_writes() to ensure write combining buffers are flushed out
950*d6b92ffaSHans Petter Selasky 		 * of the running CPU. This must be carried inside the spinlock.
951*d6b92ffaSHans Petter Selasky 		 * Otherwise, there is a potential race. In the race, CPU A
952*d6b92ffaSHans Petter Selasky 		 * writes doorbell 1, which is waiting in the WC buffer. CPU B
953*d6b92ffaSHans Petter Selasky 		 * writes doorbell 2, and it's write is flushed earlier. Since
954*d6b92ffaSHans Petter Selasky 		 * the mmio_flush_writes is CPU local, this will result in the HCA seeing
955*d6b92ffaSHans Petter Selasky 		 * doorbell 2, followed by doorbell 1.
956*d6b92ffaSHans Petter Selasky 		 * Flush before toggling bf_offset to be latency oriented.
957*d6b92ffaSHans Petter Selasky 		 */
958*d6b92ffaSHans Petter Selasky 		mmio_flush_writes();
959*d6b92ffaSHans Petter Selasky 		bf->offset ^= bf->buf_size;
960*d6b92ffaSHans Petter Selasky 		if (bf->need_lock)
961*d6b92ffaSHans Petter Selasky 			mlx5_spin_unlock(&bf->lock);
962*d6b92ffaSHans Petter Selasky 	}
963*d6b92ffaSHans Petter Selasky 
964*d6b92ffaSHans Petter Selasky 	mlx5_spin_unlock(&qp->sq.lock);
965*d6b92ffaSHans Petter Selasky 
966*d6b92ffaSHans Petter Selasky 	return err;
967*d6b92ffaSHans Petter Selasky }
968*d6b92ffaSHans Petter Selasky 
mlx5_post_send(struct ibv_qp * ibqp,struct ibv_send_wr * wr,struct ibv_send_wr ** bad_wr)969*d6b92ffaSHans Petter Selasky int mlx5_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr,
970*d6b92ffaSHans Petter Selasky 		   struct ibv_send_wr **bad_wr)
971*d6b92ffaSHans Petter Selasky {
972*d6b92ffaSHans Petter Selasky #ifdef MW_DEBUG
973*d6b92ffaSHans Petter Selasky 	if (wr->opcode == IBV_WR_BIND_MW) {
974*d6b92ffaSHans Petter Selasky 		if (wr->bind_mw.mw->type == IBV_MW_TYPE_1)
975*d6b92ffaSHans Petter Selasky 			return EINVAL;
976*d6b92ffaSHans Petter Selasky 
977*d6b92ffaSHans Petter Selasky 		if (!wr->bind_mw.bind_info.mr ||
978*d6b92ffaSHans Petter Selasky 		    !wr->bind_mw.bind_info.addr ||
979*d6b92ffaSHans Petter Selasky 		    !wr->bind_mw.bind_info.length)
980*d6b92ffaSHans Petter Selasky 			return EINVAL;
981*d6b92ffaSHans Petter Selasky 
982*d6b92ffaSHans Petter Selasky 		if (wr->bind_mw.bind_info.mr->pd != wr->bind_mw.mw->pd)
983*d6b92ffaSHans Petter Selasky 			return EINVAL;
984*d6b92ffaSHans Petter Selasky 	}
985*d6b92ffaSHans Petter Selasky #endif
986*d6b92ffaSHans Petter Selasky 
987*d6b92ffaSHans Petter Selasky 	return _mlx5_post_send(ibqp, wr, bad_wr);
988*d6b92ffaSHans Petter Selasky }
989*d6b92ffaSHans Petter Selasky 
mlx5_bind_mw(struct ibv_qp * qp,struct ibv_mw * mw,struct ibv_mw_bind * mw_bind)990*d6b92ffaSHans Petter Selasky int mlx5_bind_mw(struct ibv_qp *qp, struct ibv_mw *mw,
991*d6b92ffaSHans Petter Selasky 		 struct ibv_mw_bind *mw_bind)
992*d6b92ffaSHans Petter Selasky {
993*d6b92ffaSHans Petter Selasky 	struct ibv_mw_bind_info	*bind_info = &mw_bind->bind_info;
994*d6b92ffaSHans Petter Selasky 	struct ibv_send_wr wr = {};
995*d6b92ffaSHans Petter Selasky 	struct ibv_send_wr *bad_wr = NULL;
996*d6b92ffaSHans Petter Selasky 	int ret;
997*d6b92ffaSHans Petter Selasky 
998*d6b92ffaSHans Petter Selasky 	if (!bind_info->mr && (bind_info->addr || bind_info->length)) {
999*d6b92ffaSHans Petter Selasky 		errno = EINVAL;
1000*d6b92ffaSHans Petter Selasky 		return errno;
1001*d6b92ffaSHans Petter Selasky 	}
1002*d6b92ffaSHans Petter Selasky 
1003*d6b92ffaSHans Petter Selasky 	if (bind_info->mw_access_flags & IBV_ACCESS_ZERO_BASED) {
1004*d6b92ffaSHans Petter Selasky 		errno = EINVAL;
1005*d6b92ffaSHans Petter Selasky 		return errno;
1006*d6b92ffaSHans Petter Selasky 	}
1007*d6b92ffaSHans Petter Selasky 
1008*d6b92ffaSHans Petter Selasky 	if (bind_info->mr) {
1009*d6b92ffaSHans Petter Selasky 		if (to_mmr(bind_info->mr)->alloc_flags & IBV_ACCESS_ZERO_BASED) {
1010*d6b92ffaSHans Petter Selasky 			errno = EINVAL;
1011*d6b92ffaSHans Petter Selasky 			return errno;
1012*d6b92ffaSHans Petter Selasky 		}
1013*d6b92ffaSHans Petter Selasky 
1014*d6b92ffaSHans Petter Selasky 		if (mw->pd != bind_info->mr->pd) {
1015*d6b92ffaSHans Petter Selasky 			errno = EPERM;
1016*d6b92ffaSHans Petter Selasky 			return errno;
1017*d6b92ffaSHans Petter Selasky 		}
1018*d6b92ffaSHans Petter Selasky 	}
1019*d6b92ffaSHans Petter Selasky 
1020*d6b92ffaSHans Petter Selasky 	wr.opcode = IBV_WR_BIND_MW;
1021*d6b92ffaSHans Petter Selasky 	wr.next = NULL;
1022*d6b92ffaSHans Petter Selasky 	wr.wr_id = mw_bind->wr_id;
1023*d6b92ffaSHans Petter Selasky 	wr.send_flags = mw_bind->send_flags;
1024*d6b92ffaSHans Petter Selasky 	wr.bind_mw.bind_info = mw_bind->bind_info;
1025*d6b92ffaSHans Petter Selasky 	wr.bind_mw.mw = mw;
1026*d6b92ffaSHans Petter Selasky 	wr.bind_mw.rkey = ibv_inc_rkey(mw->rkey);
1027*d6b92ffaSHans Petter Selasky 
1028*d6b92ffaSHans Petter Selasky 	ret = _mlx5_post_send(qp, &wr, &bad_wr);
1029*d6b92ffaSHans Petter Selasky 	if (ret)
1030*d6b92ffaSHans Petter Selasky 		return ret;
1031*d6b92ffaSHans Petter Selasky 
1032*d6b92ffaSHans Petter Selasky 	mw->rkey = wr.bind_mw.rkey;
1033*d6b92ffaSHans Petter Selasky 
1034*d6b92ffaSHans Petter Selasky 	return 0;
1035*d6b92ffaSHans Petter Selasky }
1036*d6b92ffaSHans Petter Selasky 
set_sig_seg(struct mlx5_qp * qp,struct mlx5_rwqe_sig * sig,int size,uint16_t idx)1037*d6b92ffaSHans Petter Selasky static void set_sig_seg(struct mlx5_qp *qp, struct mlx5_rwqe_sig *sig,
1038*d6b92ffaSHans Petter Selasky 			int size, uint16_t idx)
1039*d6b92ffaSHans Petter Selasky {
1040*d6b92ffaSHans Petter Selasky 	uint8_t  sign;
1041*d6b92ffaSHans Petter Selasky 	uint32_t qpn = qp->ibv_qp->qp_num;
1042*d6b92ffaSHans Petter Selasky 
1043*d6b92ffaSHans Petter Selasky 	sign = calc_sig(sig, size);
1044*d6b92ffaSHans Petter Selasky 	sign ^= calc_sig(&qpn, 4);
1045*d6b92ffaSHans Petter Selasky 	sign ^= calc_sig(&idx, 2);
1046*d6b92ffaSHans Petter Selasky 	sig->signature = sign;
1047*d6b92ffaSHans Petter Selasky }
1048*d6b92ffaSHans Petter Selasky 
set_wq_sig_seg(struct mlx5_rwq * rwq,struct mlx5_rwqe_sig * sig,int size,uint16_t idx)1049*d6b92ffaSHans Petter Selasky static void set_wq_sig_seg(struct mlx5_rwq *rwq, struct mlx5_rwqe_sig *sig,
1050*d6b92ffaSHans Petter Selasky 			   int size, uint16_t idx)
1051*d6b92ffaSHans Petter Selasky {
1052*d6b92ffaSHans Petter Selasky 	uint8_t  sign;
1053*d6b92ffaSHans Petter Selasky 	uint32_t qpn = rwq->wq.wq_num;
1054*d6b92ffaSHans Petter Selasky 
1055*d6b92ffaSHans Petter Selasky 	sign = calc_sig(sig, size);
1056*d6b92ffaSHans Petter Selasky 	sign ^= calc_sig(&qpn, 4);
1057*d6b92ffaSHans Petter Selasky 	sign ^= calc_sig(&idx, 2);
1058*d6b92ffaSHans Petter Selasky 	sig->signature = sign;
1059*d6b92ffaSHans Petter Selasky }
1060*d6b92ffaSHans Petter Selasky 
mlx5_post_wq_recv(struct ibv_wq * ibwq,struct ibv_recv_wr * wr,struct ibv_recv_wr ** bad_wr)1061*d6b92ffaSHans Petter Selasky int mlx5_post_wq_recv(struct ibv_wq *ibwq, struct ibv_recv_wr *wr,
1062*d6b92ffaSHans Petter Selasky 		      struct ibv_recv_wr **bad_wr)
1063*d6b92ffaSHans Petter Selasky {
1064*d6b92ffaSHans Petter Selasky 	struct mlx5_rwq *rwq = to_mrwq(ibwq);
1065*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_data_seg *scat;
1066*d6b92ffaSHans Petter Selasky 	int err = 0;
1067*d6b92ffaSHans Petter Selasky 	int nreq;
1068*d6b92ffaSHans Petter Selasky 	int ind;
1069*d6b92ffaSHans Petter Selasky 	int i, j;
1070*d6b92ffaSHans Petter Selasky 	struct mlx5_rwqe_sig *sig;
1071*d6b92ffaSHans Petter Selasky 
1072*d6b92ffaSHans Petter Selasky 	mlx5_spin_lock(&rwq->rq.lock);
1073*d6b92ffaSHans Petter Selasky 
1074*d6b92ffaSHans Petter Selasky 	ind = rwq->rq.head & (rwq->rq.wqe_cnt - 1);
1075*d6b92ffaSHans Petter Selasky 
1076*d6b92ffaSHans Petter Selasky 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
1077*d6b92ffaSHans Petter Selasky 		if (unlikely(mlx5_wq_overflow(&rwq->rq, nreq,
1078*d6b92ffaSHans Petter Selasky 					      to_mcq(rwq->wq.cq)))) {
1079*d6b92ffaSHans Petter Selasky 			err = ENOMEM;
1080*d6b92ffaSHans Petter Selasky 			*bad_wr = wr;
1081*d6b92ffaSHans Petter Selasky 			goto out;
1082*d6b92ffaSHans Petter Selasky 		}
1083*d6b92ffaSHans Petter Selasky 
1084*d6b92ffaSHans Petter Selasky 		if (unlikely(wr->num_sge > rwq->rq.max_gs)) {
1085*d6b92ffaSHans Petter Selasky 			err = EINVAL;
1086*d6b92ffaSHans Petter Selasky 			*bad_wr = wr;
1087*d6b92ffaSHans Petter Selasky 			goto out;
1088*d6b92ffaSHans Petter Selasky 		}
1089*d6b92ffaSHans Petter Selasky 
1090*d6b92ffaSHans Petter Selasky 		scat = get_wq_recv_wqe(rwq, ind);
1091*d6b92ffaSHans Petter Selasky 		sig = (struct mlx5_rwqe_sig *)scat;
1092*d6b92ffaSHans Petter Selasky 		if (unlikely(rwq->wq_sig)) {
1093*d6b92ffaSHans Petter Selasky 			memset(sig, 0, 1 << rwq->rq.wqe_shift);
1094*d6b92ffaSHans Petter Selasky 			++scat;
1095*d6b92ffaSHans Petter Selasky 		}
1096*d6b92ffaSHans Petter Selasky 
1097*d6b92ffaSHans Petter Selasky 		for (i = 0, j = 0; i < wr->num_sge; ++i) {
1098*d6b92ffaSHans Petter Selasky 			if (unlikely(!wr->sg_list[i].length))
1099*d6b92ffaSHans Petter Selasky 				continue;
1100*d6b92ffaSHans Petter Selasky 			set_data_ptr_seg(scat + j++, wr->sg_list + i, 0);
1101*d6b92ffaSHans Petter Selasky 		}
1102*d6b92ffaSHans Petter Selasky 
1103*d6b92ffaSHans Petter Selasky 		if (j < rwq->rq.max_gs) {
1104*d6b92ffaSHans Petter Selasky 			scat[j].byte_count = 0;
1105*d6b92ffaSHans Petter Selasky 			scat[j].lkey       = htobe32(MLX5_INVALID_LKEY);
1106*d6b92ffaSHans Petter Selasky 			scat[j].addr       = 0;
1107*d6b92ffaSHans Petter Selasky 		}
1108*d6b92ffaSHans Petter Selasky 
1109*d6b92ffaSHans Petter Selasky 		if (unlikely(rwq->wq_sig))
1110*d6b92ffaSHans Petter Selasky 			set_wq_sig_seg(rwq, sig, (wr->num_sge + 1) << 4,
1111*d6b92ffaSHans Petter Selasky 				       rwq->rq.head & 0xffff);
1112*d6b92ffaSHans Petter Selasky 
1113*d6b92ffaSHans Petter Selasky 		rwq->rq.wrid[ind] = wr->wr_id;
1114*d6b92ffaSHans Petter Selasky 
1115*d6b92ffaSHans Petter Selasky 		ind = (ind + 1) & (rwq->rq.wqe_cnt - 1);
1116*d6b92ffaSHans Petter Selasky 	}
1117*d6b92ffaSHans Petter Selasky 
1118*d6b92ffaSHans Petter Selasky out:
1119*d6b92ffaSHans Petter Selasky 	if (likely(nreq)) {
1120*d6b92ffaSHans Petter Selasky 		rwq->rq.head += nreq;
1121*d6b92ffaSHans Petter Selasky 		/*
1122*d6b92ffaSHans Petter Selasky 		 * Make sure that descriptors are written before
1123*d6b92ffaSHans Petter Selasky 		 * doorbell record.
1124*d6b92ffaSHans Petter Selasky 		 */
1125*d6b92ffaSHans Petter Selasky 		udma_to_device_barrier();
1126*d6b92ffaSHans Petter Selasky 		*(rwq->recv_db) = htobe32(rwq->rq.head & 0xffff);
1127*d6b92ffaSHans Petter Selasky 	}
1128*d6b92ffaSHans Petter Selasky 
1129*d6b92ffaSHans Petter Selasky 	mlx5_spin_unlock(&rwq->rq.lock);
1130*d6b92ffaSHans Petter Selasky 
1131*d6b92ffaSHans Petter Selasky 	return err;
1132*d6b92ffaSHans Petter Selasky }
1133*d6b92ffaSHans Petter Selasky 
mlx5_post_recv(struct ibv_qp * ibqp,struct ibv_recv_wr * wr,struct ibv_recv_wr ** bad_wr)1134*d6b92ffaSHans Petter Selasky int mlx5_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr,
1135*d6b92ffaSHans Petter Selasky 		   struct ibv_recv_wr **bad_wr)
1136*d6b92ffaSHans Petter Selasky {
1137*d6b92ffaSHans Petter Selasky 	struct mlx5_qp *qp = to_mqp(ibqp);
1138*d6b92ffaSHans Petter Selasky 	struct mlx5_wqe_data_seg *scat;
1139*d6b92ffaSHans Petter Selasky 	int err = 0;
1140*d6b92ffaSHans Petter Selasky 	int nreq;
1141*d6b92ffaSHans Petter Selasky 	int ind;
1142*d6b92ffaSHans Petter Selasky 	int i, j;
1143*d6b92ffaSHans Petter Selasky 	struct mlx5_rwqe_sig *sig;
1144*d6b92ffaSHans Petter Selasky 
1145*d6b92ffaSHans Petter Selasky 	mlx5_spin_lock(&qp->rq.lock);
1146*d6b92ffaSHans Petter Selasky 
1147*d6b92ffaSHans Petter Selasky 	ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
1148*d6b92ffaSHans Petter Selasky 
1149*d6b92ffaSHans Petter Selasky 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
1150*d6b92ffaSHans Petter Selasky 		if (unlikely(mlx5_wq_overflow(&qp->rq, nreq,
1151*d6b92ffaSHans Petter Selasky 					      to_mcq(qp->ibv_qp->recv_cq)))) {
1152*d6b92ffaSHans Petter Selasky 			err = ENOMEM;
1153*d6b92ffaSHans Petter Selasky 			*bad_wr = wr;
1154*d6b92ffaSHans Petter Selasky 			goto out;
1155*d6b92ffaSHans Petter Selasky 		}
1156*d6b92ffaSHans Petter Selasky 
1157*d6b92ffaSHans Petter Selasky 		if (unlikely(wr->num_sge > qp->rq.max_gs)) {
1158*d6b92ffaSHans Petter Selasky 			err = EINVAL;
1159*d6b92ffaSHans Petter Selasky 			*bad_wr = wr;
1160*d6b92ffaSHans Petter Selasky 			goto out;
1161*d6b92ffaSHans Petter Selasky 		}
1162*d6b92ffaSHans Petter Selasky 
1163*d6b92ffaSHans Petter Selasky 		scat = get_recv_wqe(qp, ind);
1164*d6b92ffaSHans Petter Selasky 		sig = (struct mlx5_rwqe_sig *)scat;
1165*d6b92ffaSHans Petter Selasky 		if (unlikely(qp->wq_sig)) {
1166*d6b92ffaSHans Petter Selasky 			memset(sig, 0, 1 << qp->rq.wqe_shift);
1167*d6b92ffaSHans Petter Selasky 			++scat;
1168*d6b92ffaSHans Petter Selasky 		}
1169*d6b92ffaSHans Petter Selasky 
1170*d6b92ffaSHans Petter Selasky 		for (i = 0, j = 0; i < wr->num_sge; ++i) {
1171*d6b92ffaSHans Petter Selasky 			if (unlikely(!wr->sg_list[i].length))
1172*d6b92ffaSHans Petter Selasky 				continue;
1173*d6b92ffaSHans Petter Selasky 			set_data_ptr_seg(scat + j++, wr->sg_list + i, 0);
1174*d6b92ffaSHans Petter Selasky 		}
1175*d6b92ffaSHans Petter Selasky 
1176*d6b92ffaSHans Petter Selasky 		if (j < qp->rq.max_gs) {
1177*d6b92ffaSHans Petter Selasky 			scat[j].byte_count = 0;
1178*d6b92ffaSHans Petter Selasky 			scat[j].lkey       = htobe32(MLX5_INVALID_LKEY);
1179*d6b92ffaSHans Petter Selasky 			scat[j].addr       = 0;
1180*d6b92ffaSHans Petter Selasky 		}
1181*d6b92ffaSHans Petter Selasky 
1182*d6b92ffaSHans Petter Selasky 		if (unlikely(qp->wq_sig))
1183*d6b92ffaSHans Petter Selasky 			set_sig_seg(qp, sig, (wr->num_sge + 1) << 4,
1184*d6b92ffaSHans Petter Selasky 				    qp->rq.head & 0xffff);
1185*d6b92ffaSHans Petter Selasky 
1186*d6b92ffaSHans Petter Selasky 		qp->rq.wrid[ind] = wr->wr_id;
1187*d6b92ffaSHans Petter Selasky 
1188*d6b92ffaSHans Petter Selasky 		ind = (ind + 1) & (qp->rq.wqe_cnt - 1);
1189*d6b92ffaSHans Petter Selasky 	}
1190*d6b92ffaSHans Petter Selasky 
1191*d6b92ffaSHans Petter Selasky out:
1192*d6b92ffaSHans Petter Selasky 	if (likely(nreq)) {
1193*d6b92ffaSHans Petter Selasky 		qp->rq.head += nreq;
1194*d6b92ffaSHans Petter Selasky 
1195*d6b92ffaSHans Petter Selasky 		/*
1196*d6b92ffaSHans Petter Selasky 		 * Make sure that descriptors are written before
1197*d6b92ffaSHans Petter Selasky 		 * doorbell record.
1198*d6b92ffaSHans Petter Selasky 		 */
1199*d6b92ffaSHans Petter Selasky 		udma_to_device_barrier();
1200*d6b92ffaSHans Petter Selasky 
1201*d6b92ffaSHans Petter Selasky 		/*
1202*d6b92ffaSHans Petter Selasky 		 * For Raw Packet QP, avoid updating the doorbell record
1203*d6b92ffaSHans Petter Selasky 		 * as long as the QP isn't in RTR state, to avoid receiving
1204*d6b92ffaSHans Petter Selasky 		 * packets in illegal states.
1205*d6b92ffaSHans Petter Selasky 		 * This is only for Raw Packet QPs since they are represented
1206*d6b92ffaSHans Petter Selasky 		 * differently in the hardware.
1207*d6b92ffaSHans Petter Selasky 		 */
1208*d6b92ffaSHans Petter Selasky 		if (likely(!(ibqp->qp_type == IBV_QPT_RAW_PACKET &&
1209*d6b92ffaSHans Petter Selasky 			     ibqp->state < IBV_QPS_RTR)))
1210*d6b92ffaSHans Petter Selasky 			qp->db[MLX5_RCV_DBR] = htobe32(qp->rq.head & 0xffff);
1211*d6b92ffaSHans Petter Selasky 	}
1212*d6b92ffaSHans Petter Selasky 
1213*d6b92ffaSHans Petter Selasky 	mlx5_spin_unlock(&qp->rq.lock);
1214*d6b92ffaSHans Petter Selasky 
1215*d6b92ffaSHans Petter Selasky 	return err;
1216*d6b92ffaSHans Petter Selasky }
1217*d6b92ffaSHans Petter Selasky 
mlx5_use_huge(const char * key)1218*d6b92ffaSHans Petter Selasky int mlx5_use_huge(const char *key)
1219*d6b92ffaSHans Petter Selasky {
1220*d6b92ffaSHans Petter Selasky 	char *e;
1221*d6b92ffaSHans Petter Selasky 	e = getenv(key);
1222*d6b92ffaSHans Petter Selasky 	if (e && !strcmp(e, "y"))
1223*d6b92ffaSHans Petter Selasky 		return 1;
1224*d6b92ffaSHans Petter Selasky 
1225*d6b92ffaSHans Petter Selasky 	return 0;
1226*d6b92ffaSHans Petter Selasky }
1227*d6b92ffaSHans Petter Selasky 
mlx5_find_qp(struct mlx5_context * ctx,uint32_t qpn)1228*d6b92ffaSHans Petter Selasky struct mlx5_qp *mlx5_find_qp(struct mlx5_context *ctx, uint32_t qpn)
1229*d6b92ffaSHans Petter Selasky {
1230*d6b92ffaSHans Petter Selasky 	int tind = qpn >> MLX5_QP_TABLE_SHIFT;
1231*d6b92ffaSHans Petter Selasky 
1232*d6b92ffaSHans Petter Selasky 	if (ctx->qp_table[tind].refcnt)
1233*d6b92ffaSHans Petter Selasky 		return ctx->qp_table[tind].table[qpn & MLX5_QP_TABLE_MASK];
1234*d6b92ffaSHans Petter Selasky 	else
1235*d6b92ffaSHans Petter Selasky 		return NULL;
1236*d6b92ffaSHans Petter Selasky }
1237*d6b92ffaSHans Petter Selasky 
mlx5_store_qp(struct mlx5_context * ctx,uint32_t qpn,struct mlx5_qp * qp)1238*d6b92ffaSHans Petter Selasky int mlx5_store_qp(struct mlx5_context *ctx, uint32_t qpn, struct mlx5_qp *qp)
1239*d6b92ffaSHans Petter Selasky {
1240*d6b92ffaSHans Petter Selasky 	int tind = qpn >> MLX5_QP_TABLE_SHIFT;
1241*d6b92ffaSHans Petter Selasky 
1242*d6b92ffaSHans Petter Selasky 	if (!ctx->qp_table[tind].refcnt) {
1243*d6b92ffaSHans Petter Selasky 		ctx->qp_table[tind].table = calloc(MLX5_QP_TABLE_MASK + 1,
1244*d6b92ffaSHans Petter Selasky 						   sizeof(struct mlx5_qp *));
1245*d6b92ffaSHans Petter Selasky 		if (!ctx->qp_table[tind].table)
1246*d6b92ffaSHans Petter Selasky 			return -1;
1247*d6b92ffaSHans Petter Selasky 	}
1248*d6b92ffaSHans Petter Selasky 
1249*d6b92ffaSHans Petter Selasky 	++ctx->qp_table[tind].refcnt;
1250*d6b92ffaSHans Petter Selasky 	ctx->qp_table[tind].table[qpn & MLX5_QP_TABLE_MASK] = qp;
1251*d6b92ffaSHans Petter Selasky 	return 0;
1252*d6b92ffaSHans Petter Selasky }
1253*d6b92ffaSHans Petter Selasky 
mlx5_clear_qp(struct mlx5_context * ctx,uint32_t qpn)1254*d6b92ffaSHans Petter Selasky void mlx5_clear_qp(struct mlx5_context *ctx, uint32_t qpn)
1255*d6b92ffaSHans Petter Selasky {
1256*d6b92ffaSHans Petter Selasky 	int tind = qpn >> MLX5_QP_TABLE_SHIFT;
1257*d6b92ffaSHans Petter Selasky 
1258*d6b92ffaSHans Petter Selasky 	if (!--ctx->qp_table[tind].refcnt)
1259*d6b92ffaSHans Petter Selasky 		free(ctx->qp_table[tind].table);
1260*d6b92ffaSHans Petter Selasky 	else
1261*d6b92ffaSHans Petter Selasky 		ctx->qp_table[tind].table[qpn & MLX5_QP_TABLE_MASK] = NULL;
1262*d6b92ffaSHans Petter Selasky }
1263