xref: /freebsd/contrib/ofed/libmlx5/verbs.c (revision 25ef056f74e40429df6bcbc31d52888b57ff3e2c)
1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2012 Mellanox Technologies, Inc.  All rights reserved.
3d6b92ffaSHans Petter Selasky  *
4d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
5d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
6d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
7d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
8d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
9d6b92ffaSHans Petter Selasky  *
10d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
11d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
12d6b92ffaSHans Petter Selasky  *     conditions are met:
13d6b92ffaSHans Petter Selasky  *
14d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
15d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
16d6b92ffaSHans Petter Selasky  *        disclaimer.
17d6b92ffaSHans Petter Selasky  *
18d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
19d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
20d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
21d6b92ffaSHans Petter Selasky  *        provided with the distribution.
22d6b92ffaSHans Petter Selasky  *
23d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30d6b92ffaSHans Petter Selasky  * SOFTWARE.
31d6b92ffaSHans Petter Selasky  */
32d6b92ffaSHans Petter Selasky 
33d6b92ffaSHans Petter Selasky #include <config.h>
34d6b92ffaSHans Petter Selasky 
35d6b92ffaSHans Petter Selasky #include <stdlib.h>
36d6b92ffaSHans Petter Selasky #include <stdio.h>
37d6b92ffaSHans Petter Selasky #include <string.h>
38d6b92ffaSHans Petter Selasky #include <pthread.h>
39d6b92ffaSHans Petter Selasky #include <errno.h>
40d6b92ffaSHans Petter Selasky #include <limits.h>
41d6b92ffaSHans Petter Selasky #include <sys/types.h>
42d6b92ffaSHans Petter Selasky #include <sys/stat.h>
43d6b92ffaSHans Petter Selasky #include <fcntl.h>
44d6b92ffaSHans Petter Selasky #include <unistd.h>
45d6b92ffaSHans Petter Selasky #include <sys/mman.h>
46d6b92ffaSHans Petter Selasky 
47d6b92ffaSHans Petter Selasky #include "mlx5.h"
48d6b92ffaSHans Petter Selasky #include "mlx5-abi.h"
49d6b92ffaSHans Petter Selasky #include "wqe.h"
50d6b92ffaSHans Petter Selasky 
51d6b92ffaSHans Petter Selasky int mlx5_single_threaded = 0;
52d6b92ffaSHans Petter Selasky 
53d6b92ffaSHans Petter Selasky static inline int is_xrc_tgt(int type)
54d6b92ffaSHans Petter Selasky {
55d6b92ffaSHans Petter Selasky 	return type == IBV_QPT_XRC_RECV;
56d6b92ffaSHans Petter Selasky }
57d6b92ffaSHans Petter Selasky 
58d6b92ffaSHans Petter Selasky int mlx5_query_device(struct ibv_context *context, struct ibv_device_attr *attr)
59d6b92ffaSHans Petter Selasky {
60d6b92ffaSHans Petter Selasky 	struct ibv_query_device cmd;
61d6b92ffaSHans Petter Selasky 	uint64_t raw_fw_ver;
62d6b92ffaSHans Petter Selasky 	unsigned major, minor, sub_minor;
63d6b92ffaSHans Petter Selasky 	int ret;
64d6b92ffaSHans Petter Selasky 
65d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_query_device(context, attr, &raw_fw_ver, &cmd, sizeof cmd);
66d6b92ffaSHans Petter Selasky 	if (ret)
67d6b92ffaSHans Petter Selasky 		return ret;
68d6b92ffaSHans Petter Selasky 
69d6b92ffaSHans Petter Selasky 	major     = (raw_fw_ver >> 32) & 0xffff;
70d6b92ffaSHans Petter Selasky 	minor     = (raw_fw_ver >> 16) & 0xffff;
71d6b92ffaSHans Petter Selasky 	sub_minor = raw_fw_ver & 0xffff;
72d6b92ffaSHans Petter Selasky 
73d6b92ffaSHans Petter Selasky 	snprintf(attr->fw_ver, sizeof attr->fw_ver,
74d6b92ffaSHans Petter Selasky 		 "%d.%d.%04d", major, minor, sub_minor);
75d6b92ffaSHans Petter Selasky 
76d6b92ffaSHans Petter Selasky 	return 0;
77d6b92ffaSHans Petter Selasky }
78d6b92ffaSHans Petter Selasky 
79d6b92ffaSHans Petter Selasky #define READL(ptr) (*((uint32_t *)(ptr)))
80d6b92ffaSHans Petter Selasky static int mlx5_read_clock(struct ibv_context *context, uint64_t *cycles)
81d6b92ffaSHans Petter Selasky {
82d6b92ffaSHans Petter Selasky 	unsigned int clockhi, clocklo, clockhi1;
83d6b92ffaSHans Petter Selasky 	int i;
84d6b92ffaSHans Petter Selasky 	struct mlx5_context *ctx = to_mctx(context);
85d6b92ffaSHans Petter Selasky 
86d6b92ffaSHans Petter Selasky 	if (!ctx->hca_core_clock)
87d6b92ffaSHans Petter Selasky 		return -EOPNOTSUPP;
88d6b92ffaSHans Petter Selasky 
89d6b92ffaSHans Petter Selasky 	/* Handle wraparound */
90d6b92ffaSHans Petter Selasky 	for (i = 0; i < 2; i++) {
91d6b92ffaSHans Petter Selasky 		clockhi = be32toh(READL(ctx->hca_core_clock));
92d6b92ffaSHans Petter Selasky 		clocklo = be32toh(READL(ctx->hca_core_clock + 4));
93d6b92ffaSHans Petter Selasky 		clockhi1 = be32toh(READL(ctx->hca_core_clock));
94d6b92ffaSHans Petter Selasky 		if (clockhi == clockhi1)
95d6b92ffaSHans Petter Selasky 			break;
96d6b92ffaSHans Petter Selasky 	}
97d6b92ffaSHans Petter Selasky 
98d6b92ffaSHans Petter Selasky 	*cycles = (uint64_t)clockhi << 32 | (uint64_t)clocklo;
99d6b92ffaSHans Petter Selasky 
100d6b92ffaSHans Petter Selasky 	return 0;
101d6b92ffaSHans Petter Selasky }
102d6b92ffaSHans Petter Selasky 
103d6b92ffaSHans Petter Selasky int mlx5_query_rt_values(struct ibv_context *context,
104d6b92ffaSHans Petter Selasky 			 struct ibv_values_ex *values)
105d6b92ffaSHans Petter Selasky {
106d6b92ffaSHans Petter Selasky 	uint32_t comp_mask = 0;
107d6b92ffaSHans Petter Selasky 	int err = 0;
108d6b92ffaSHans Petter Selasky 
109d6b92ffaSHans Petter Selasky 	if (values->comp_mask & IBV_VALUES_MASK_RAW_CLOCK) {
110d6b92ffaSHans Petter Selasky 		uint64_t cycles;
111d6b92ffaSHans Petter Selasky 
112d6b92ffaSHans Petter Selasky 		err = mlx5_read_clock(context, &cycles);
113d6b92ffaSHans Petter Selasky 		if (!err) {
114d6b92ffaSHans Petter Selasky 			values->raw_clock.tv_sec = 0;
115d6b92ffaSHans Petter Selasky 			values->raw_clock.tv_nsec = cycles;
116d6b92ffaSHans Petter Selasky 			comp_mask |= IBV_VALUES_MASK_RAW_CLOCK;
117d6b92ffaSHans Petter Selasky 		}
118d6b92ffaSHans Petter Selasky 	}
119d6b92ffaSHans Petter Selasky 
120d6b92ffaSHans Petter Selasky 	values->comp_mask = comp_mask;
121d6b92ffaSHans Petter Selasky 
122d6b92ffaSHans Petter Selasky 	return err;
123d6b92ffaSHans Petter Selasky }
124d6b92ffaSHans Petter Selasky 
125d6b92ffaSHans Petter Selasky int mlx5_query_port(struct ibv_context *context, uint8_t port,
126d6b92ffaSHans Petter Selasky 		     struct ibv_port_attr *attr)
127d6b92ffaSHans Petter Selasky {
128d6b92ffaSHans Petter Selasky 	struct ibv_query_port cmd;
129d6b92ffaSHans Petter Selasky 
130d6b92ffaSHans Petter Selasky 	return ibv_cmd_query_port(context, port, attr, &cmd, sizeof cmd);
131d6b92ffaSHans Petter Selasky }
132d6b92ffaSHans Petter Selasky 
133d6b92ffaSHans Petter Selasky struct ibv_pd *mlx5_alloc_pd(struct ibv_context *context)
134d6b92ffaSHans Petter Selasky {
135d6b92ffaSHans Petter Selasky 	struct ibv_alloc_pd       cmd;
136d6b92ffaSHans Petter Selasky 	struct mlx5_alloc_pd_resp resp;
137d6b92ffaSHans Petter Selasky 	struct mlx5_pd		 *pd;
138d6b92ffaSHans Petter Selasky 
139d6b92ffaSHans Petter Selasky 	pd = calloc(1, sizeof *pd);
140d6b92ffaSHans Petter Selasky 	if (!pd)
141d6b92ffaSHans Petter Selasky 		return NULL;
142d6b92ffaSHans Petter Selasky 
143d6b92ffaSHans Petter Selasky 	if (ibv_cmd_alloc_pd(context, &pd->ibv_pd, &cmd, sizeof cmd,
144d6b92ffaSHans Petter Selasky 			     &resp.ibv_resp, sizeof resp)) {
145d6b92ffaSHans Petter Selasky 		free(pd);
146d6b92ffaSHans Petter Selasky 		return NULL;
147d6b92ffaSHans Petter Selasky 	}
148d6b92ffaSHans Petter Selasky 
149d6b92ffaSHans Petter Selasky 	pd->pdn = resp.pdn;
150d6b92ffaSHans Petter Selasky 
151d6b92ffaSHans Petter Selasky 	return &pd->ibv_pd;
152d6b92ffaSHans Petter Selasky }
153d6b92ffaSHans Petter Selasky 
154d6b92ffaSHans Petter Selasky int mlx5_free_pd(struct ibv_pd *pd)
155d6b92ffaSHans Petter Selasky {
156d6b92ffaSHans Petter Selasky 	int ret;
157d6b92ffaSHans Petter Selasky 
158d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_dealloc_pd(pd);
159d6b92ffaSHans Petter Selasky 	if (ret)
160d6b92ffaSHans Petter Selasky 		return ret;
161d6b92ffaSHans Petter Selasky 
162d6b92ffaSHans Petter Selasky 	free(to_mpd(pd));
163d6b92ffaSHans Petter Selasky 	return 0;
164d6b92ffaSHans Petter Selasky }
165d6b92ffaSHans Petter Selasky 
166d6b92ffaSHans Petter Selasky struct ibv_mr *mlx5_reg_mr(struct ibv_pd *pd, void *addr, size_t length,
167d6b92ffaSHans Petter Selasky 			   int acc)
168d6b92ffaSHans Petter Selasky {
169d6b92ffaSHans Petter Selasky 	struct mlx5_mr *mr;
170d6b92ffaSHans Petter Selasky 	struct ibv_reg_mr cmd;
171d6b92ffaSHans Petter Selasky 	int ret;
172d6b92ffaSHans Petter Selasky 	enum ibv_access_flags access = (enum ibv_access_flags)acc;
173d6b92ffaSHans Petter Selasky 	struct ibv_reg_mr_resp resp;
174d6b92ffaSHans Petter Selasky 
175d6b92ffaSHans Petter Selasky 	mr = calloc(1, sizeof(*mr));
176d6b92ffaSHans Petter Selasky 	if (!mr)
177d6b92ffaSHans Petter Selasky 		return NULL;
178d6b92ffaSHans Petter Selasky 
179d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_reg_mr(pd, addr, length, (uintptr_t)addr, access,
180d6b92ffaSHans Petter Selasky 			     &(mr->ibv_mr), &cmd, sizeof(cmd), &resp,
181d6b92ffaSHans Petter Selasky 			     sizeof resp);
182d6b92ffaSHans Petter Selasky 	if (ret) {
183d6b92ffaSHans Petter Selasky 		mlx5_free_buf(&(mr->buf));
184d6b92ffaSHans Petter Selasky 		free(mr);
185d6b92ffaSHans Petter Selasky 		return NULL;
186d6b92ffaSHans Petter Selasky 	}
187d6b92ffaSHans Petter Selasky 	mr->alloc_flags = acc;
188d6b92ffaSHans Petter Selasky 
189d6b92ffaSHans Petter Selasky 	return &mr->ibv_mr;
190d6b92ffaSHans Petter Selasky }
191d6b92ffaSHans Petter Selasky 
192d6b92ffaSHans Petter Selasky int mlx5_rereg_mr(struct ibv_mr *ibmr, int flags, struct ibv_pd *pd, void *addr,
193d6b92ffaSHans Petter Selasky 		  size_t length, int access)
194d6b92ffaSHans Petter Selasky {
195d6b92ffaSHans Petter Selasky 	struct ibv_rereg_mr cmd;
196d6b92ffaSHans Petter Selasky 	struct ibv_rereg_mr_resp resp;
197d6b92ffaSHans Petter Selasky 
198d6b92ffaSHans Petter Selasky 	if (flags & IBV_REREG_MR_KEEP_VALID)
199d6b92ffaSHans Petter Selasky 		return ENOTSUP;
200d6b92ffaSHans Petter Selasky 
201d6b92ffaSHans Petter Selasky 	return ibv_cmd_rereg_mr(ibmr, flags, addr, length, (uintptr_t)addr,
202d6b92ffaSHans Petter Selasky 				access, pd, &cmd, sizeof(cmd), &resp,
203d6b92ffaSHans Petter Selasky 				sizeof(resp));
204d6b92ffaSHans Petter Selasky }
205d6b92ffaSHans Petter Selasky 
206d6b92ffaSHans Petter Selasky int mlx5_dereg_mr(struct ibv_mr *ibmr)
207d6b92ffaSHans Petter Selasky {
208d6b92ffaSHans Petter Selasky 	int ret;
209d6b92ffaSHans Petter Selasky 	struct mlx5_mr *mr = to_mmr(ibmr);
210d6b92ffaSHans Petter Selasky 
211d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_dereg_mr(ibmr);
212d6b92ffaSHans Petter Selasky 	if (ret)
213d6b92ffaSHans Petter Selasky 		return ret;
214d6b92ffaSHans Petter Selasky 
215d6b92ffaSHans Petter Selasky 	free(mr);
216d6b92ffaSHans Petter Selasky 	return 0;
217d6b92ffaSHans Petter Selasky }
218d6b92ffaSHans Petter Selasky 
219d6b92ffaSHans Petter Selasky struct ibv_mw *mlx5_alloc_mw(struct ibv_pd *pd, enum ibv_mw_type type)
220d6b92ffaSHans Petter Selasky {
221d6b92ffaSHans Petter Selasky 	struct ibv_mw *mw;
222d6b92ffaSHans Petter Selasky 	struct ibv_alloc_mw cmd;
223d6b92ffaSHans Petter Selasky 	struct ibv_alloc_mw_resp resp;
224d6b92ffaSHans Petter Selasky 	int ret;
225d6b92ffaSHans Petter Selasky 
226d6b92ffaSHans Petter Selasky 	mw = malloc(sizeof(*mw));
227d6b92ffaSHans Petter Selasky 	if (!mw)
228d6b92ffaSHans Petter Selasky 		return NULL;
229d6b92ffaSHans Petter Selasky 
230d6b92ffaSHans Petter Selasky 	memset(mw, 0, sizeof(*mw));
231d6b92ffaSHans Petter Selasky 
232d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_alloc_mw(pd, type, mw, &cmd, sizeof(cmd), &resp,
233d6b92ffaSHans Petter Selasky 			       sizeof(resp));
234d6b92ffaSHans Petter Selasky 	if (ret) {
235d6b92ffaSHans Petter Selasky 		free(mw);
236d6b92ffaSHans Petter Selasky 		return NULL;
237d6b92ffaSHans Petter Selasky 	}
238d6b92ffaSHans Petter Selasky 
239d6b92ffaSHans Petter Selasky 	return mw;
240d6b92ffaSHans Petter Selasky }
241d6b92ffaSHans Petter Selasky 
242d6b92ffaSHans Petter Selasky int mlx5_dealloc_mw(struct ibv_mw *mw)
243d6b92ffaSHans Petter Selasky {
244d6b92ffaSHans Petter Selasky 	int ret;
245d6b92ffaSHans Petter Selasky 	struct ibv_dealloc_mw cmd;
246d6b92ffaSHans Petter Selasky 
247d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_dealloc_mw(mw, &cmd, sizeof(cmd));
248d6b92ffaSHans Petter Selasky 	if (ret)
249d6b92ffaSHans Petter Selasky 		return ret;
250d6b92ffaSHans Petter Selasky 
251d6b92ffaSHans Petter Selasky 	free(mw);
252d6b92ffaSHans Petter Selasky 	return 0;
253d6b92ffaSHans Petter Selasky }
254d6b92ffaSHans Petter Selasky 
255d6b92ffaSHans Petter Selasky int mlx5_round_up_power_of_two(long long sz)
256d6b92ffaSHans Petter Selasky {
257d6b92ffaSHans Petter Selasky 	long long ret;
258d6b92ffaSHans Petter Selasky 
259d6b92ffaSHans Petter Selasky 	for (ret = 1; ret < sz; ret <<= 1)
260d6b92ffaSHans Petter Selasky 		; /* nothing */
261d6b92ffaSHans Petter Selasky 
262d6b92ffaSHans Petter Selasky 	if (ret > INT_MAX) {
263d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s: roundup overflow\n", __func__);
264d6b92ffaSHans Petter Selasky 		return -ENOMEM;
265d6b92ffaSHans Petter Selasky 	}
266d6b92ffaSHans Petter Selasky 
267d6b92ffaSHans Petter Selasky 	return (int)ret;
268d6b92ffaSHans Petter Selasky }
269d6b92ffaSHans Petter Selasky 
270d6b92ffaSHans Petter Selasky static int align_queue_size(long long req)
271d6b92ffaSHans Petter Selasky {
272d6b92ffaSHans Petter Selasky 	return mlx5_round_up_power_of_two(req);
273d6b92ffaSHans Petter Selasky }
274d6b92ffaSHans Petter Selasky 
275d6b92ffaSHans Petter Selasky static int get_cqe_size(void)
276d6b92ffaSHans Petter Selasky {
277d6b92ffaSHans Petter Selasky 	char *env;
278d6b92ffaSHans Petter Selasky 	int size = 64;
279d6b92ffaSHans Petter Selasky 
280d6b92ffaSHans Petter Selasky 	env = getenv("MLX5_CQE_SIZE");
281d6b92ffaSHans Petter Selasky 	if (env)
282d6b92ffaSHans Petter Selasky 		size = atoi(env);
283d6b92ffaSHans Petter Selasky 
284d6b92ffaSHans Petter Selasky 	switch (size) {
285d6b92ffaSHans Petter Selasky 	case 64:
286d6b92ffaSHans Petter Selasky 	case 128:
287d6b92ffaSHans Petter Selasky 		return size;
288d6b92ffaSHans Petter Selasky 
289d6b92ffaSHans Petter Selasky 	default:
290d6b92ffaSHans Petter Selasky 		return -EINVAL;
291d6b92ffaSHans Petter Selasky 	}
292d6b92ffaSHans Petter Selasky }
293d6b92ffaSHans Petter Selasky 
294d6b92ffaSHans Petter Selasky static int use_scatter_to_cqe(void)
295d6b92ffaSHans Petter Selasky {
296d6b92ffaSHans Petter Selasky 	char *env;
297d6b92ffaSHans Petter Selasky 
298d6b92ffaSHans Petter Selasky 	env = getenv("MLX5_SCATTER_TO_CQE");
299d6b92ffaSHans Petter Selasky 	if (env && !strcmp(env, "0"))
300d6b92ffaSHans Petter Selasky 		return 0;
301d6b92ffaSHans Petter Selasky 
302d6b92ffaSHans Petter Selasky 	return 1;
303d6b92ffaSHans Petter Selasky }
304d6b92ffaSHans Petter Selasky 
305d6b92ffaSHans Petter Selasky static int srq_sig_enabled(void)
306d6b92ffaSHans Petter Selasky {
307d6b92ffaSHans Petter Selasky 	char *env;
308d6b92ffaSHans Petter Selasky 
309d6b92ffaSHans Petter Selasky 	env = getenv("MLX5_SRQ_SIGNATURE");
310d6b92ffaSHans Petter Selasky 	if (env)
311d6b92ffaSHans Petter Selasky 		return 1;
312d6b92ffaSHans Petter Selasky 
313d6b92ffaSHans Petter Selasky 	return 0;
314d6b92ffaSHans Petter Selasky }
315d6b92ffaSHans Petter Selasky 
316d6b92ffaSHans Petter Selasky static int qp_sig_enabled(void)
317d6b92ffaSHans Petter Selasky {
318d6b92ffaSHans Petter Selasky 	char *env;
319d6b92ffaSHans Petter Selasky 
320d6b92ffaSHans Petter Selasky 	env = getenv("MLX5_QP_SIGNATURE");
321d6b92ffaSHans Petter Selasky 	if (env)
322d6b92ffaSHans Petter Selasky 		return 1;
323d6b92ffaSHans Petter Selasky 
324d6b92ffaSHans Petter Selasky 	return 0;
325d6b92ffaSHans Petter Selasky }
326d6b92ffaSHans Petter Selasky 
327d6b92ffaSHans Petter Selasky enum {
328d6b92ffaSHans Petter Selasky 	CREATE_CQ_SUPPORTED_WC_FLAGS = IBV_WC_STANDARD_FLAGS	|
329d6b92ffaSHans Petter Selasky 				       IBV_WC_EX_WITH_COMPLETION_TIMESTAMP |
330d6b92ffaSHans Petter Selasky 				       IBV_WC_EX_WITH_CVLAN |
331d6b92ffaSHans Petter Selasky 				       IBV_WC_EX_WITH_FLOW_TAG
332d6b92ffaSHans Petter Selasky };
333d6b92ffaSHans Petter Selasky 
334d6b92ffaSHans Petter Selasky enum {
335d6b92ffaSHans Petter Selasky 	CREATE_CQ_SUPPORTED_COMP_MASK = IBV_CQ_INIT_ATTR_MASK_FLAGS
336d6b92ffaSHans Petter Selasky };
337d6b92ffaSHans Petter Selasky 
338d6b92ffaSHans Petter Selasky enum {
339d6b92ffaSHans Petter Selasky 	CREATE_CQ_SUPPORTED_FLAGS = IBV_CREATE_CQ_ATTR_SINGLE_THREADED
340d6b92ffaSHans Petter Selasky };
341d6b92ffaSHans Petter Selasky 
342d6b92ffaSHans Petter Selasky static struct ibv_cq_ex *create_cq(struct ibv_context *context,
343d6b92ffaSHans Petter Selasky 				   const struct ibv_cq_init_attr_ex *cq_attr,
344d6b92ffaSHans Petter Selasky 				   int cq_alloc_flags,
345d6b92ffaSHans Petter Selasky 				   struct mlx5dv_cq_init_attr *mlx5cq_attr)
346d6b92ffaSHans Petter Selasky {
347d6b92ffaSHans Petter Selasky 	struct mlx5_create_cq		cmd;
348d6b92ffaSHans Petter Selasky 	struct mlx5_create_cq_resp	resp;
349d6b92ffaSHans Petter Selasky 	struct mlx5_cq		       *cq;
350d6b92ffaSHans Petter Selasky 	int				cqe_sz;
351d6b92ffaSHans Petter Selasky 	int				ret;
352d6b92ffaSHans Petter Selasky 	int				ncqe;
353d6b92ffaSHans Petter Selasky 	struct mlx5_context *mctx = to_mctx(context);
354d6b92ffaSHans Petter Selasky 	FILE *fp = to_mctx(context)->dbg_fp;
355d6b92ffaSHans Petter Selasky 
356d6b92ffaSHans Petter Selasky 	if (!cq_attr->cqe) {
357d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ, "CQE invalid\n");
358d6b92ffaSHans Petter Selasky 		errno = EINVAL;
359d6b92ffaSHans Petter Selasky 		return NULL;
360d6b92ffaSHans Petter Selasky 	}
361d6b92ffaSHans Petter Selasky 
362d6b92ffaSHans Petter Selasky 	if (cq_attr->comp_mask & ~CREATE_CQ_SUPPORTED_COMP_MASK) {
363d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ,
364d6b92ffaSHans Petter Selasky 			 "Unsupported comp_mask for create_cq\n");
365d6b92ffaSHans Petter Selasky 		errno = EINVAL;
366d6b92ffaSHans Petter Selasky 		return NULL;
367d6b92ffaSHans Petter Selasky 	}
368d6b92ffaSHans Petter Selasky 
369d6b92ffaSHans Petter Selasky 	if (cq_attr->comp_mask & IBV_CQ_INIT_ATTR_MASK_FLAGS &&
370d6b92ffaSHans Petter Selasky 	    cq_attr->flags & ~CREATE_CQ_SUPPORTED_FLAGS) {
371d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ,
372d6b92ffaSHans Petter Selasky 			 "Unsupported creation flags requested for create_cq\n");
373d6b92ffaSHans Petter Selasky 		errno = EINVAL;
374d6b92ffaSHans Petter Selasky 		return NULL;
375d6b92ffaSHans Petter Selasky 	}
376d6b92ffaSHans Petter Selasky 
377d6b92ffaSHans Petter Selasky 	if (cq_attr->wc_flags & ~CREATE_CQ_SUPPORTED_WC_FLAGS) {
378d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ, "\n");
379d6b92ffaSHans Petter Selasky 		errno = ENOTSUP;
380d6b92ffaSHans Petter Selasky 		return NULL;
381d6b92ffaSHans Petter Selasky 	}
382d6b92ffaSHans Petter Selasky 
383d6b92ffaSHans Petter Selasky 	cq =  calloc(1, sizeof *cq);
384d6b92ffaSHans Petter Selasky 	if (!cq) {
385d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ, "\n");
386d6b92ffaSHans Petter Selasky 		return NULL;
387d6b92ffaSHans Petter Selasky 	}
388d6b92ffaSHans Petter Selasky 
389d6b92ffaSHans Petter Selasky 	memset(&cmd, 0, sizeof cmd);
390d6b92ffaSHans Petter Selasky 	cq->cons_index = 0;
391d6b92ffaSHans Petter Selasky 
392d6b92ffaSHans Petter Selasky 	if (mlx5_spinlock_init(&cq->lock))
393d6b92ffaSHans Petter Selasky 		goto err;
394d6b92ffaSHans Petter Selasky 
395d6b92ffaSHans Petter Selasky 	ncqe = align_queue_size(cq_attr->cqe + 1);
396d6b92ffaSHans Petter Selasky 	if ((ncqe > (1 << 24)) || (ncqe < (cq_attr->cqe + 1))) {
397d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ, "ncqe %d\n", ncqe);
398d6b92ffaSHans Petter Selasky 		errno = EINVAL;
399d6b92ffaSHans Petter Selasky 		goto err_spl;
400d6b92ffaSHans Petter Selasky 	}
401d6b92ffaSHans Petter Selasky 
402d6b92ffaSHans Petter Selasky 	cqe_sz = get_cqe_size();
403d6b92ffaSHans Petter Selasky 	if (cqe_sz < 0) {
404d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ, "\n");
405d6b92ffaSHans Petter Selasky 		errno = -cqe_sz;
406d6b92ffaSHans Petter Selasky 		goto err_spl;
407d6b92ffaSHans Petter Selasky 	}
408d6b92ffaSHans Petter Selasky 
409d6b92ffaSHans Petter Selasky 	if (mlx5_alloc_cq_buf(to_mctx(context), cq, &cq->buf_a, ncqe, cqe_sz)) {
410d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ, "\n");
411d6b92ffaSHans Petter Selasky 		goto err_spl;
412d6b92ffaSHans Petter Selasky 	}
413d6b92ffaSHans Petter Selasky 
414d6b92ffaSHans Petter Selasky 	cq->dbrec  = mlx5_alloc_dbrec(to_mctx(context));
415d6b92ffaSHans Petter Selasky 	if (!cq->dbrec) {
416d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ, "\n");
417d6b92ffaSHans Petter Selasky 		goto err_buf;
418d6b92ffaSHans Petter Selasky 	}
419d6b92ffaSHans Petter Selasky 
420d6b92ffaSHans Petter Selasky 	cq->dbrec[MLX5_CQ_SET_CI]	= 0;
421d6b92ffaSHans Petter Selasky 	cq->dbrec[MLX5_CQ_ARM_DB]	= 0;
422d6b92ffaSHans Petter Selasky 	cq->arm_sn			= 0;
423d6b92ffaSHans Petter Selasky 	cq->cqe_sz			= cqe_sz;
424d6b92ffaSHans Petter Selasky 	cq->flags			= cq_alloc_flags;
425d6b92ffaSHans Petter Selasky 
426d6b92ffaSHans Petter Selasky 	if (cq_attr->comp_mask & IBV_CQ_INIT_ATTR_MASK_FLAGS &&
427d6b92ffaSHans Petter Selasky 	    cq_attr->flags & IBV_CREATE_CQ_ATTR_SINGLE_THREADED)
428d6b92ffaSHans Petter Selasky 		cq->flags |= MLX5_CQ_FLAGS_SINGLE_THREADED;
429d6b92ffaSHans Petter Selasky 	cmd.buf_addr = (uintptr_t) cq->buf_a.buf;
430d6b92ffaSHans Petter Selasky 	cmd.db_addr  = (uintptr_t) cq->dbrec;
431d6b92ffaSHans Petter Selasky 	cmd.cqe_size = cqe_sz;
432d6b92ffaSHans Petter Selasky 
433d6b92ffaSHans Petter Selasky 	if (mlx5cq_attr) {
434d6b92ffaSHans Petter Selasky 		if (mlx5cq_attr->comp_mask & ~(MLX5DV_CQ_INIT_ATTR_MASK_RESERVED - 1)) {
435d6b92ffaSHans Petter Selasky 			mlx5_dbg(fp, MLX5_DBG_CQ,
436d6b92ffaSHans Petter Selasky 				   "Unsupported vendor comp_mask for create_cq\n");
437d6b92ffaSHans Petter Selasky 			errno = EINVAL;
438d6b92ffaSHans Petter Selasky 			goto err_db;
439d6b92ffaSHans Petter Selasky 		}
440d6b92ffaSHans Petter Selasky 
441d6b92ffaSHans Petter Selasky 		if (mlx5cq_attr->comp_mask & MLX5DV_CQ_INIT_ATTR_MASK_COMPRESSED_CQE) {
442d6b92ffaSHans Petter Selasky 			if (mctx->cqe_comp_caps.max_num &&
443d6b92ffaSHans Petter Selasky 			    (mlx5cq_attr->cqe_comp_res_format &
444d6b92ffaSHans Petter Selasky 			     mctx->cqe_comp_caps.supported_format)) {
445d6b92ffaSHans Petter Selasky 				cmd.cqe_comp_en = 1;
446d6b92ffaSHans Petter Selasky 				cmd.cqe_comp_res_format = mlx5cq_attr->cqe_comp_res_format;
447d6b92ffaSHans Petter Selasky 			} else {
448d6b92ffaSHans Petter Selasky 				mlx5_dbg(fp, MLX5_DBG_CQ, "CQE Compression is not supported\n");
449d6b92ffaSHans Petter Selasky 				errno = EINVAL;
450d6b92ffaSHans Petter Selasky 				goto err_db;
451d6b92ffaSHans Petter Selasky 			}
452d6b92ffaSHans Petter Selasky 		}
453d6b92ffaSHans Petter Selasky 	}
454d6b92ffaSHans Petter Selasky 
455d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_create_cq(context, ncqe - 1, cq_attr->channel,
456d6b92ffaSHans Petter Selasky 				cq_attr->comp_vector,
457d6b92ffaSHans Petter Selasky 				ibv_cq_ex_to_cq(&cq->ibv_cq), &cmd.ibv_cmd,
458d6b92ffaSHans Petter Selasky 				sizeof(cmd), &resp.ibv_resp, sizeof(resp));
459d6b92ffaSHans Petter Selasky 	if (ret) {
460d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_CQ, "ret %d\n", ret);
461d6b92ffaSHans Petter Selasky 		goto err_db;
462d6b92ffaSHans Petter Selasky 	}
463d6b92ffaSHans Petter Selasky 
464d6b92ffaSHans Petter Selasky 	cq->active_buf = &cq->buf_a;
465d6b92ffaSHans Petter Selasky 	cq->resize_buf = NULL;
466d6b92ffaSHans Petter Selasky 	cq->cqn = resp.cqn;
467d6b92ffaSHans Petter Selasky 	cq->stall_enable = to_mctx(context)->stall_enable;
468d6b92ffaSHans Petter Selasky 	cq->stall_adaptive_enable = to_mctx(context)->stall_adaptive_enable;
469d6b92ffaSHans Petter Selasky 	cq->stall_cycles = to_mctx(context)->stall_cycles;
470d6b92ffaSHans Petter Selasky 
471d6b92ffaSHans Petter Selasky 	if (cq_alloc_flags & MLX5_CQ_FLAGS_EXTENDED)
472d6b92ffaSHans Petter Selasky 		mlx5_cq_fill_pfns(cq, cq_attr);
473d6b92ffaSHans Petter Selasky 
474d6b92ffaSHans Petter Selasky 	return &cq->ibv_cq;
475d6b92ffaSHans Petter Selasky 
476d6b92ffaSHans Petter Selasky err_db:
477d6b92ffaSHans Petter Selasky 	mlx5_free_db(to_mctx(context), cq->dbrec);
478d6b92ffaSHans Petter Selasky 
479d6b92ffaSHans Petter Selasky err_buf:
480d6b92ffaSHans Petter Selasky 	mlx5_free_cq_buf(to_mctx(context), &cq->buf_a);
481d6b92ffaSHans Petter Selasky 
482d6b92ffaSHans Petter Selasky err_spl:
483d6b92ffaSHans Petter Selasky 	mlx5_spinlock_destroy(&cq->lock);
484d6b92ffaSHans Petter Selasky 
485d6b92ffaSHans Petter Selasky err:
486d6b92ffaSHans Petter Selasky 	free(cq);
487d6b92ffaSHans Petter Selasky 
488d6b92ffaSHans Petter Selasky 	return NULL;
489d6b92ffaSHans Petter Selasky }
490d6b92ffaSHans Petter Selasky 
491d6b92ffaSHans Petter Selasky struct ibv_cq *mlx5_create_cq(struct ibv_context *context, int cqe,
492d6b92ffaSHans Petter Selasky 			      struct ibv_comp_channel *channel,
493d6b92ffaSHans Petter Selasky 			      int comp_vector)
494d6b92ffaSHans Petter Selasky {
495d6b92ffaSHans Petter Selasky 	struct ibv_cq_ex *cq;
496d6b92ffaSHans Petter Selasky 	struct ibv_cq_init_attr_ex cq_attr = {.cqe = cqe, .channel = channel,
497d6b92ffaSHans Petter Selasky 						.comp_vector = comp_vector,
498d6b92ffaSHans Petter Selasky 						.wc_flags = IBV_WC_STANDARD_FLAGS};
499d6b92ffaSHans Petter Selasky 
500d6b92ffaSHans Petter Selasky 	if (cqe <= 0) {
501d6b92ffaSHans Petter Selasky 		errno = EINVAL;
502d6b92ffaSHans Petter Selasky 		return NULL;
503d6b92ffaSHans Petter Selasky 	}
504d6b92ffaSHans Petter Selasky 
505d6b92ffaSHans Petter Selasky 	cq = create_cq(context, &cq_attr, 0, NULL);
506d6b92ffaSHans Petter Selasky 	return cq ? ibv_cq_ex_to_cq(cq) : NULL;
507d6b92ffaSHans Petter Selasky }
508d6b92ffaSHans Petter Selasky 
509d6b92ffaSHans Petter Selasky struct ibv_cq_ex *mlx5_create_cq_ex(struct ibv_context *context,
510d6b92ffaSHans Petter Selasky 				    struct ibv_cq_init_attr_ex *cq_attr)
511d6b92ffaSHans Petter Selasky {
512d6b92ffaSHans Petter Selasky 	return create_cq(context, cq_attr, MLX5_CQ_FLAGS_EXTENDED, NULL);
513d6b92ffaSHans Petter Selasky }
514d6b92ffaSHans Petter Selasky 
515d6b92ffaSHans Petter Selasky struct ibv_cq_ex *mlx5dv_create_cq(struct ibv_context *context,
516d6b92ffaSHans Petter Selasky 				      struct ibv_cq_init_attr_ex *cq_attr,
517d6b92ffaSHans Petter Selasky 				      struct mlx5dv_cq_init_attr *mlx5_cq_attr)
518d6b92ffaSHans Petter Selasky {
519d6b92ffaSHans Petter Selasky 	struct ibv_cq_ex *cq;
520a687910fSSean Lim 	int err = 0;
521d6b92ffaSHans Petter Selasky 
522d6b92ffaSHans Petter Selasky 	cq = create_cq(context, cq_attr, MLX5_CQ_FLAGS_EXTENDED, mlx5_cq_attr);
523d6b92ffaSHans Petter Selasky 	if (!cq)
524d6b92ffaSHans Petter Selasky 		return NULL;
525d6b92ffaSHans Petter Selasky 
526a687910fSSean Lim 	err = verbs_init_cq(ibv_cq_ex_to_cq(cq), context,
527d6b92ffaSHans Petter Selasky 		      cq_attr->channel, cq_attr->cq_context);
528a687910fSSean Lim 	if (err)
529a687910fSSean Lim 		goto err;
530a687910fSSean Lim 
531d6b92ffaSHans Petter Selasky 	return cq;
532a687910fSSean Lim 
533a687910fSSean Lim err:
534a687910fSSean Lim 	context->ops.destroy_cq(ibv_cq_ex_to_cq(cq));
535a687910fSSean Lim 
536a687910fSSean Lim 	return NULL;
537d6b92ffaSHans Petter Selasky }
538d6b92ffaSHans Petter Selasky 
539d6b92ffaSHans Petter Selasky int mlx5_resize_cq(struct ibv_cq *ibcq, int cqe)
540d6b92ffaSHans Petter Selasky {
541d6b92ffaSHans Petter Selasky 	struct mlx5_cq *cq = to_mcq(ibcq);
542d6b92ffaSHans Petter Selasky 	struct mlx5_resize_cq_resp resp;
543d6b92ffaSHans Petter Selasky 	struct mlx5_resize_cq cmd;
544d6b92ffaSHans Petter Selasky 	struct mlx5_context *mctx = to_mctx(ibcq->context);
545d6b92ffaSHans Petter Selasky 	int err;
546d6b92ffaSHans Petter Selasky 
547d6b92ffaSHans Petter Selasky 	if (cqe < 0) {
548d6b92ffaSHans Petter Selasky 		errno = EINVAL;
549d6b92ffaSHans Petter Selasky 		return errno;
550d6b92ffaSHans Petter Selasky 	}
551d6b92ffaSHans Petter Selasky 
552d6b92ffaSHans Petter Selasky 	memset(&cmd, 0, sizeof(cmd));
553d6b92ffaSHans Petter Selasky 	memset(&resp, 0, sizeof(resp));
554d6b92ffaSHans Petter Selasky 
555d6b92ffaSHans Petter Selasky 	if (((long long)cqe * 64) > INT_MAX)
556d6b92ffaSHans Petter Selasky 		return EINVAL;
557d6b92ffaSHans Petter Selasky 
558d6b92ffaSHans Petter Selasky 	mlx5_spin_lock(&cq->lock);
559d6b92ffaSHans Petter Selasky 	cq->active_cqes = cq->ibv_cq.cqe;
560d6b92ffaSHans Petter Selasky 	if (cq->active_buf == &cq->buf_a)
561d6b92ffaSHans Petter Selasky 		cq->resize_buf = &cq->buf_b;
562d6b92ffaSHans Petter Selasky 	else
563d6b92ffaSHans Petter Selasky 		cq->resize_buf = &cq->buf_a;
564d6b92ffaSHans Petter Selasky 
565d6b92ffaSHans Petter Selasky 	cqe = align_queue_size(cqe + 1);
566d6b92ffaSHans Petter Selasky 	if (cqe == ibcq->cqe + 1) {
567d6b92ffaSHans Petter Selasky 		cq->resize_buf = NULL;
568d6b92ffaSHans Petter Selasky 		err = 0;
569d6b92ffaSHans Petter Selasky 		goto out;
570d6b92ffaSHans Petter Selasky 	}
571d6b92ffaSHans Petter Selasky 
572d6b92ffaSHans Petter Selasky 	/* currently we don't change cqe size */
573d6b92ffaSHans Petter Selasky 	cq->resize_cqe_sz = cq->cqe_sz;
574d6b92ffaSHans Petter Selasky 	cq->resize_cqes = cqe;
575d6b92ffaSHans Petter Selasky 	err = mlx5_alloc_cq_buf(mctx, cq, cq->resize_buf, cq->resize_cqes, cq->resize_cqe_sz);
576d6b92ffaSHans Petter Selasky 	if (err) {
577d6b92ffaSHans Petter Selasky 		cq->resize_buf = NULL;
578d6b92ffaSHans Petter Selasky 		errno = ENOMEM;
579d6b92ffaSHans Petter Selasky 		goto out;
580d6b92ffaSHans Petter Selasky 	}
581d6b92ffaSHans Petter Selasky 
582d6b92ffaSHans Petter Selasky 	cmd.buf_addr = (uintptr_t)cq->resize_buf->buf;
583d6b92ffaSHans Petter Selasky 	cmd.cqe_size = cq->resize_cqe_sz;
584d6b92ffaSHans Petter Selasky 
585d6b92ffaSHans Petter Selasky 	err = ibv_cmd_resize_cq(ibcq, cqe - 1, &cmd.ibv_cmd, sizeof(cmd),
586d6b92ffaSHans Petter Selasky 				&resp.ibv_resp, sizeof(resp));
587d6b92ffaSHans Petter Selasky 	if (err)
588d6b92ffaSHans Petter Selasky 		goto out_buf;
589d6b92ffaSHans Petter Selasky 
590d6b92ffaSHans Petter Selasky 	mlx5_cq_resize_copy_cqes(cq);
591d6b92ffaSHans Petter Selasky 	mlx5_free_cq_buf(mctx, cq->active_buf);
592d6b92ffaSHans Petter Selasky 	cq->active_buf = cq->resize_buf;
593d6b92ffaSHans Petter Selasky 	cq->ibv_cq.cqe = cqe - 1;
594d6b92ffaSHans Petter Selasky 	mlx5_spin_unlock(&cq->lock);
595d6b92ffaSHans Petter Selasky 	cq->resize_buf = NULL;
596d6b92ffaSHans Petter Selasky 	return 0;
597d6b92ffaSHans Petter Selasky 
598d6b92ffaSHans Petter Selasky out_buf:
599d6b92ffaSHans Petter Selasky 	mlx5_free_cq_buf(mctx, cq->resize_buf);
600d6b92ffaSHans Petter Selasky 	cq->resize_buf = NULL;
601d6b92ffaSHans Petter Selasky 
602d6b92ffaSHans Petter Selasky out:
603d6b92ffaSHans Petter Selasky 	mlx5_spin_unlock(&cq->lock);
604d6b92ffaSHans Petter Selasky 	return err;
605d6b92ffaSHans Petter Selasky }
606d6b92ffaSHans Petter Selasky 
607d6b92ffaSHans Petter Selasky int mlx5_destroy_cq(struct ibv_cq *cq)
608d6b92ffaSHans Petter Selasky {
609d6b92ffaSHans Petter Selasky 	int ret;
610a687910fSSean Lim 	struct mlx5_cq *mcq = to_mcq(cq);
611d6b92ffaSHans Petter Selasky 
612d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_destroy_cq(cq);
613d6b92ffaSHans Petter Selasky 	if (ret)
614d6b92ffaSHans Petter Selasky 		return ret;
615d6b92ffaSHans Petter Selasky 
616a687910fSSean Lim 	verbs_cleanup_cq(cq);
617d6b92ffaSHans Petter Selasky 	mlx5_free_db(to_mctx(cq->context), to_mcq(cq)->dbrec);
618d6b92ffaSHans Petter Selasky 	mlx5_free_cq_buf(to_mctx(cq->context), to_mcq(cq)->active_buf);
619a687910fSSean Lim 	mlx5_spinlock_destroy(&mcq->lock);
620d6b92ffaSHans Petter Selasky 	free(to_mcq(cq));
621d6b92ffaSHans Petter Selasky 
622d6b92ffaSHans Petter Selasky 	return 0;
623d6b92ffaSHans Petter Selasky }
624d6b92ffaSHans Petter Selasky 
625d6b92ffaSHans Petter Selasky struct ibv_srq *mlx5_create_srq(struct ibv_pd *pd,
626d6b92ffaSHans Petter Selasky 				struct ibv_srq_init_attr *attr)
627d6b92ffaSHans Petter Selasky {
628d6b92ffaSHans Petter Selasky 	struct mlx5_create_srq      cmd;
629d6b92ffaSHans Petter Selasky 	struct mlx5_create_srq_resp resp;
630d6b92ffaSHans Petter Selasky 	struct mlx5_srq		   *srq;
631d6b92ffaSHans Petter Selasky 	int			    ret;
632d6b92ffaSHans Petter Selasky 	struct mlx5_context	   *ctx;
633d6b92ffaSHans Petter Selasky 	int			    max_sge;
634d6b92ffaSHans Petter Selasky 	struct ibv_srq		   *ibsrq;
635d6b92ffaSHans Petter Selasky 
636d6b92ffaSHans Petter Selasky 	ctx = to_mctx(pd->context);
637d6b92ffaSHans Petter Selasky 	srq = calloc(1, sizeof *srq);
638d6b92ffaSHans Petter Selasky 	if (!srq) {
639d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:\n", __func__, __LINE__);
640d6b92ffaSHans Petter Selasky 		return NULL;
641d6b92ffaSHans Petter Selasky 	}
642d6b92ffaSHans Petter Selasky 	ibsrq = &srq->vsrq.srq;
643d6b92ffaSHans Petter Selasky 
644d6b92ffaSHans Petter Selasky 	memset(&cmd, 0, sizeof cmd);
645d6b92ffaSHans Petter Selasky 	if (mlx5_spinlock_init(&srq->lock)) {
646d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:\n", __func__, __LINE__);
647d6b92ffaSHans Petter Selasky 		goto err;
648d6b92ffaSHans Petter Selasky 	}
649d6b92ffaSHans Petter Selasky 
650d6b92ffaSHans Petter Selasky 	if (attr->attr.max_wr > ctx->max_srq_recv_wr) {
651d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:max_wr %d, max_srq_recv_wr %d\n", __func__, __LINE__,
652d6b92ffaSHans Petter Selasky 			attr->attr.max_wr, ctx->max_srq_recv_wr);
653d6b92ffaSHans Petter Selasky 		errno = EINVAL;
654a687910fSSean Lim 		goto err_spl;
655d6b92ffaSHans Petter Selasky 	}
656d6b92ffaSHans Petter Selasky 
657d6b92ffaSHans Petter Selasky 	/*
658d6b92ffaSHans Petter Selasky 	 * this calculation does not consider required control segments. The
659d6b92ffaSHans Petter Selasky 	 * final calculation is done again later. This is done so to avoid
660d6b92ffaSHans Petter Selasky 	 * overflows of variables
661d6b92ffaSHans Petter Selasky 	 */
662d6b92ffaSHans Petter Selasky 	max_sge = ctx->max_rq_desc_sz / sizeof(struct mlx5_wqe_data_seg);
663d6b92ffaSHans Petter Selasky 	if (attr->attr.max_sge > max_sge) {
664d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:max_wr %d, max_srq_recv_wr %d\n", __func__, __LINE__,
665d6b92ffaSHans Petter Selasky 			attr->attr.max_wr, ctx->max_srq_recv_wr);
666d6b92ffaSHans Petter Selasky 		errno = EINVAL;
667a687910fSSean Lim 		goto err_spl;
668d6b92ffaSHans Petter Selasky 	}
669d6b92ffaSHans Petter Selasky 
670d6b92ffaSHans Petter Selasky 	srq->max     = align_queue_size(attr->attr.max_wr + 1);
671d6b92ffaSHans Petter Selasky 	srq->max_gs  = attr->attr.max_sge;
672d6b92ffaSHans Petter Selasky 	srq->counter = 0;
673d6b92ffaSHans Petter Selasky 
674d6b92ffaSHans Petter Selasky 	if (mlx5_alloc_srq_buf(pd->context, srq)) {
675d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:\n", __func__, __LINE__);
676a687910fSSean Lim 		goto err_spl;
677d6b92ffaSHans Petter Selasky 	}
678d6b92ffaSHans Petter Selasky 
679d6b92ffaSHans Petter Selasky 	srq->db = mlx5_alloc_dbrec(to_mctx(pd->context));
680d6b92ffaSHans Petter Selasky 	if (!srq->db) {
681d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:\n", __func__, __LINE__);
682d6b92ffaSHans Petter Selasky 		goto err_free;
683d6b92ffaSHans Petter Selasky 	}
684d6b92ffaSHans Petter Selasky 
685d6b92ffaSHans Petter Selasky 	*srq->db = 0;
686d6b92ffaSHans Petter Selasky 
687d6b92ffaSHans Petter Selasky 	cmd.buf_addr = (uintptr_t) srq->buf.buf;
688d6b92ffaSHans Petter Selasky 	cmd.db_addr  = (uintptr_t) srq->db;
689d6b92ffaSHans Petter Selasky 	srq->wq_sig = srq_sig_enabled();
690d6b92ffaSHans Petter Selasky 	if (srq->wq_sig)
691d6b92ffaSHans Petter Selasky 		cmd.flags = MLX5_SRQ_FLAG_SIGNATURE;
692d6b92ffaSHans Petter Selasky 
693d6b92ffaSHans Petter Selasky 	attr->attr.max_sge = srq->max_gs;
694d6b92ffaSHans Petter Selasky 	pthread_mutex_lock(&ctx->srq_table_mutex);
695d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_create_srq(pd, ibsrq, attr, &cmd.ibv_cmd, sizeof(cmd),
696d6b92ffaSHans Petter Selasky 				 &resp.ibv_resp, sizeof(resp));
697d6b92ffaSHans Petter Selasky 	if (ret)
698d6b92ffaSHans Petter Selasky 		goto err_db;
699d6b92ffaSHans Petter Selasky 
700d6b92ffaSHans Petter Selasky 	ret = mlx5_store_srq(ctx, resp.srqn, srq);
701d6b92ffaSHans Petter Selasky 	if (ret)
702d6b92ffaSHans Petter Selasky 		goto err_destroy;
703d6b92ffaSHans Petter Selasky 
704d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&ctx->srq_table_mutex);
705d6b92ffaSHans Petter Selasky 
706d6b92ffaSHans Petter Selasky 	srq->srqn = resp.srqn;
707d6b92ffaSHans Petter Selasky 	srq->rsc.rsn = resp.srqn;
708d6b92ffaSHans Petter Selasky 	srq->rsc.type = MLX5_RSC_TYPE_SRQ;
709d6b92ffaSHans Petter Selasky 
710d6b92ffaSHans Petter Selasky 	return ibsrq;
711d6b92ffaSHans Petter Selasky 
712d6b92ffaSHans Petter Selasky err_destroy:
713d6b92ffaSHans Petter Selasky 	ibv_cmd_destroy_srq(ibsrq);
714d6b92ffaSHans Petter Selasky 
715d6b92ffaSHans Petter Selasky err_db:
716d6b92ffaSHans Petter Selasky 	pthread_mutex_unlock(&ctx->srq_table_mutex);
717d6b92ffaSHans Petter Selasky 	mlx5_free_db(to_mctx(pd->context), srq->db);
718d6b92ffaSHans Petter Selasky 
719d6b92ffaSHans Petter Selasky err_free:
720d6b92ffaSHans Petter Selasky 	free(srq->wrid);
721d6b92ffaSHans Petter Selasky 	mlx5_free_buf(&srq->buf);
722d6b92ffaSHans Petter Selasky 
723a687910fSSean Lim err_spl:
724a687910fSSean Lim 	mlx5_spinlock_destroy(&srq->lock);
725a687910fSSean Lim 
726d6b92ffaSHans Petter Selasky err:
727d6b92ffaSHans Petter Selasky 	free(srq);
728d6b92ffaSHans Petter Selasky 
729d6b92ffaSHans Petter Selasky 	return NULL;
730d6b92ffaSHans Petter Selasky }
731d6b92ffaSHans Petter Selasky 
732d6b92ffaSHans Petter Selasky int mlx5_modify_srq(struct ibv_srq *srq,
733d6b92ffaSHans Petter Selasky 		    struct ibv_srq_attr *attr,
734d6b92ffaSHans Petter Selasky 		    int attr_mask)
735d6b92ffaSHans Petter Selasky {
736d6b92ffaSHans Petter Selasky 	struct ibv_modify_srq cmd;
737d6b92ffaSHans Petter Selasky 
738d6b92ffaSHans Petter Selasky 	return ibv_cmd_modify_srq(srq, attr, attr_mask, &cmd, sizeof cmd);
739d6b92ffaSHans Petter Selasky }
740d6b92ffaSHans Petter Selasky 
741d6b92ffaSHans Petter Selasky int mlx5_query_srq(struct ibv_srq *srq,
742d6b92ffaSHans Petter Selasky 		    struct ibv_srq_attr *attr)
743d6b92ffaSHans Petter Selasky {
744d6b92ffaSHans Petter Selasky 	struct ibv_query_srq cmd;
745d6b92ffaSHans Petter Selasky 
746d6b92ffaSHans Petter Selasky 	return ibv_cmd_query_srq(srq, attr, &cmd, sizeof cmd);
747d6b92ffaSHans Petter Selasky }
748d6b92ffaSHans Petter Selasky 
749d6b92ffaSHans Petter Selasky int mlx5_destroy_srq(struct ibv_srq *srq)
750d6b92ffaSHans Petter Selasky {
751d6b92ffaSHans Petter Selasky 	int ret;
752d6b92ffaSHans Petter Selasky 	struct mlx5_srq *msrq = to_msrq(srq);
753d6b92ffaSHans Petter Selasky 	struct mlx5_context *ctx = to_mctx(srq->context);
754d6b92ffaSHans Petter Selasky 
755d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_destroy_srq(srq);
756d6b92ffaSHans Petter Selasky 	if (ret)
757d6b92ffaSHans Petter Selasky 		return ret;
758d6b92ffaSHans Petter Selasky 
759d6b92ffaSHans Petter Selasky 	if (ctx->cqe_version && msrq->rsc.type == MLX5_RSC_TYPE_XSRQ)
760d6b92ffaSHans Petter Selasky 		mlx5_clear_uidx(ctx, msrq->rsc.rsn);
761d6b92ffaSHans Petter Selasky 	else
762d6b92ffaSHans Petter Selasky 		mlx5_clear_srq(ctx, msrq->srqn);
763d6b92ffaSHans Petter Selasky 
764d6b92ffaSHans Petter Selasky 	mlx5_free_db(ctx, msrq->db);
765d6b92ffaSHans Petter Selasky 	mlx5_free_buf(&msrq->buf);
766d6b92ffaSHans Petter Selasky 	free(msrq->wrid);
767a687910fSSean Lim 	mlx5_spinlock_destroy(&msrq->lock);
768d6b92ffaSHans Petter Selasky 	free(msrq);
769d6b92ffaSHans Petter Selasky 
770d6b92ffaSHans Petter Selasky 	return 0;
771d6b92ffaSHans Petter Selasky }
772d6b92ffaSHans Petter Selasky 
773d6b92ffaSHans Petter Selasky static int sq_overhead(enum ibv_qp_type	qp_type)
774d6b92ffaSHans Petter Selasky {
775d6b92ffaSHans Petter Selasky 	size_t size = 0;
776d6b92ffaSHans Petter Selasky 	size_t mw_bind_size =
777d6b92ffaSHans Petter Selasky 	    sizeof(struct mlx5_wqe_umr_ctrl_seg) +
778d6b92ffaSHans Petter Selasky 	    sizeof(struct mlx5_wqe_mkey_context_seg) +
779d6b92ffaSHans Petter Selasky 	    max_t(size_t, sizeof(struct mlx5_wqe_umr_klm_seg), 64);
780d6b92ffaSHans Petter Selasky 
781d6b92ffaSHans Petter Selasky 	switch (qp_type) {
782d6b92ffaSHans Petter Selasky 	case IBV_QPT_RC:
783d6b92ffaSHans Petter Selasky 		size += sizeof(struct mlx5_wqe_ctrl_seg) +
784d6b92ffaSHans Petter Selasky 			max(sizeof(struct mlx5_wqe_atomic_seg) +
785d6b92ffaSHans Petter Selasky 			    sizeof(struct mlx5_wqe_raddr_seg),
786d6b92ffaSHans Petter Selasky 			    mw_bind_size);
787d6b92ffaSHans Petter Selasky 		break;
788d6b92ffaSHans Petter Selasky 
789d6b92ffaSHans Petter Selasky 	case IBV_QPT_UC:
790d6b92ffaSHans Petter Selasky 		size = sizeof(struct mlx5_wqe_ctrl_seg) +
791d6b92ffaSHans Petter Selasky 			max(sizeof(struct mlx5_wqe_raddr_seg),
792d6b92ffaSHans Petter Selasky 			    mw_bind_size);
793d6b92ffaSHans Petter Selasky 		break;
794d6b92ffaSHans Petter Selasky 
795d6b92ffaSHans Petter Selasky 	case IBV_QPT_UD:
796d6b92ffaSHans Petter Selasky 		size = sizeof(struct mlx5_wqe_ctrl_seg) +
797d6b92ffaSHans Petter Selasky 			sizeof(struct mlx5_wqe_datagram_seg);
798d6b92ffaSHans Petter Selasky 		break;
799d6b92ffaSHans Petter Selasky 
800d6b92ffaSHans Petter Selasky 	case IBV_QPT_XRC_SEND:
801d6b92ffaSHans Petter Selasky 		size = sizeof(struct mlx5_wqe_ctrl_seg) + mw_bind_size;
802d6b92ffaSHans Petter Selasky 		SWITCH_FALLTHROUGH;
803d6b92ffaSHans Petter Selasky 
804d6b92ffaSHans Petter Selasky 	case IBV_QPT_XRC_RECV:
805d6b92ffaSHans Petter Selasky 		size = max(size, sizeof(struct mlx5_wqe_ctrl_seg) +
806d6b92ffaSHans Petter Selasky 			   sizeof(struct mlx5_wqe_xrc_seg) +
807d6b92ffaSHans Petter Selasky 			   sizeof(struct mlx5_wqe_raddr_seg));
808d6b92ffaSHans Petter Selasky 		break;
809d6b92ffaSHans Petter Selasky 
810d6b92ffaSHans Petter Selasky 	case IBV_QPT_RAW_PACKET:
811d6b92ffaSHans Petter Selasky 		size = sizeof(struct mlx5_wqe_ctrl_seg) +
812d6b92ffaSHans Petter Selasky 			sizeof(struct mlx5_wqe_eth_seg);
813d6b92ffaSHans Petter Selasky 		break;
814d6b92ffaSHans Petter Selasky 
815d6b92ffaSHans Petter Selasky 	default:
816d6b92ffaSHans Petter Selasky 		return -EINVAL;
817d6b92ffaSHans Petter Selasky 	}
818d6b92ffaSHans Petter Selasky 
819d6b92ffaSHans Petter Selasky 	return size;
820d6b92ffaSHans Petter Selasky }
821d6b92ffaSHans Petter Selasky 
822d6b92ffaSHans Petter Selasky static int mlx5_calc_send_wqe(struct mlx5_context *ctx,
823d6b92ffaSHans Petter Selasky 			      struct ibv_qp_init_attr_ex *attr,
824d6b92ffaSHans Petter Selasky 			      struct mlx5_qp *qp)
825d6b92ffaSHans Petter Selasky {
826d6b92ffaSHans Petter Selasky 	int size;
827d6b92ffaSHans Petter Selasky 	int inl_size = 0;
828d6b92ffaSHans Petter Selasky 	int max_gather;
829d6b92ffaSHans Petter Selasky 	int tot_size;
830d6b92ffaSHans Petter Selasky 
831d6b92ffaSHans Petter Selasky 	size = sq_overhead(attr->qp_type);
832d6b92ffaSHans Petter Selasky 	if (size < 0)
833d6b92ffaSHans Petter Selasky 		return size;
834d6b92ffaSHans Petter Selasky 
835d6b92ffaSHans Petter Selasky 	if (attr->cap.max_inline_data) {
836d6b92ffaSHans Petter Selasky 		inl_size = size + align(sizeof(struct mlx5_wqe_inl_data_seg) +
837d6b92ffaSHans Petter Selasky 			attr->cap.max_inline_data, 16);
838d6b92ffaSHans Petter Selasky 	}
839d6b92ffaSHans Petter Selasky 
840d6b92ffaSHans Petter Selasky 	if (attr->comp_mask & IBV_QP_INIT_ATTR_MAX_TSO_HEADER) {
841d6b92ffaSHans Petter Selasky 		size += align(attr->max_tso_header, 16);
842d6b92ffaSHans Petter Selasky 		qp->max_tso_header = attr->max_tso_header;
843d6b92ffaSHans Petter Selasky 	}
844d6b92ffaSHans Petter Selasky 
845d6b92ffaSHans Petter Selasky 	max_gather = (ctx->max_sq_desc_sz - size) /
846d6b92ffaSHans Petter Selasky 		sizeof(struct mlx5_wqe_data_seg);
847d6b92ffaSHans Petter Selasky 	if (attr->cap.max_send_sge > max_gather)
848d6b92ffaSHans Petter Selasky 		return -EINVAL;
849d6b92ffaSHans Petter Selasky 
850d6b92ffaSHans Petter Selasky 	size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg);
851d6b92ffaSHans Petter Selasky 	tot_size = max_int(size, inl_size);
852d6b92ffaSHans Petter Selasky 
853d6b92ffaSHans Petter Selasky 	if (tot_size > ctx->max_sq_desc_sz)
854d6b92ffaSHans Petter Selasky 		return -EINVAL;
855d6b92ffaSHans Petter Selasky 
856d6b92ffaSHans Petter Selasky 	return align(tot_size, MLX5_SEND_WQE_BB);
857d6b92ffaSHans Petter Selasky }
858d6b92ffaSHans Petter Selasky 
859d6b92ffaSHans Petter Selasky static int mlx5_calc_rcv_wqe(struct mlx5_context *ctx,
860d6b92ffaSHans Petter Selasky 			     struct ibv_qp_init_attr_ex *attr,
861d6b92ffaSHans Petter Selasky 			     struct mlx5_qp *qp)
862d6b92ffaSHans Petter Selasky {
863d6b92ffaSHans Petter Selasky 	uint32_t size;
864d6b92ffaSHans Petter Selasky 	int num_scatter;
865d6b92ffaSHans Petter Selasky 
866d6b92ffaSHans Petter Selasky 	if (attr->srq)
867d6b92ffaSHans Petter Selasky 		return 0;
868d6b92ffaSHans Petter Selasky 
869d6b92ffaSHans Petter Selasky 	num_scatter = max_t(uint32_t, attr->cap.max_recv_sge, 1);
870d6b92ffaSHans Petter Selasky 	size = sizeof(struct mlx5_wqe_data_seg) * num_scatter;
871d6b92ffaSHans Petter Selasky 	if (qp->wq_sig)
872d6b92ffaSHans Petter Selasky 		size += sizeof(struct mlx5_rwqe_sig);
873d6b92ffaSHans Petter Selasky 
874d6b92ffaSHans Petter Selasky 	if (size > ctx->max_rq_desc_sz)
875d6b92ffaSHans Petter Selasky 		return -EINVAL;
876d6b92ffaSHans Petter Selasky 
877d6b92ffaSHans Petter Selasky 	size = mlx5_round_up_power_of_two(size);
878d6b92ffaSHans Petter Selasky 
879d6b92ffaSHans Petter Selasky 	return size;
880d6b92ffaSHans Petter Selasky }
881d6b92ffaSHans Petter Selasky 
882d6b92ffaSHans Petter Selasky static int mlx5_calc_sq_size(struct mlx5_context *ctx,
883d6b92ffaSHans Petter Selasky 			     struct ibv_qp_init_attr_ex *attr,
884d6b92ffaSHans Petter Selasky 			     struct mlx5_qp *qp)
885d6b92ffaSHans Petter Selasky {
886d6b92ffaSHans Petter Selasky 	int wqe_size;
887d6b92ffaSHans Petter Selasky 	int wq_size;
888d6b92ffaSHans Petter Selasky 	FILE *fp = ctx->dbg_fp;
889d6b92ffaSHans Petter Selasky 
890d6b92ffaSHans Petter Selasky 	if (!attr->cap.max_send_wr)
891d6b92ffaSHans Petter Selasky 		return 0;
892d6b92ffaSHans Petter Selasky 
893d6b92ffaSHans Petter Selasky 	wqe_size = mlx5_calc_send_wqe(ctx, attr, qp);
894d6b92ffaSHans Petter Selasky 	if (wqe_size < 0) {
895d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "\n");
896d6b92ffaSHans Petter Selasky 		return wqe_size;
897d6b92ffaSHans Petter Selasky 	}
898d6b92ffaSHans Petter Selasky 
899d6b92ffaSHans Petter Selasky 	if (wqe_size > ctx->max_sq_desc_sz) {
900d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "\n");
901d6b92ffaSHans Petter Selasky 		return -EINVAL;
902d6b92ffaSHans Petter Selasky 	}
903d6b92ffaSHans Petter Selasky 
904d6b92ffaSHans Petter Selasky 	qp->max_inline_data = wqe_size - sq_overhead(attr->qp_type) -
905d6b92ffaSHans Petter Selasky 		sizeof(struct mlx5_wqe_inl_data_seg);
906d6b92ffaSHans Petter Selasky 	attr->cap.max_inline_data = qp->max_inline_data;
907d6b92ffaSHans Petter Selasky 
908d6b92ffaSHans Petter Selasky 	/*
909d6b92ffaSHans Petter Selasky 	 * to avoid overflow, we limit max_send_wr so
910d6b92ffaSHans Petter Selasky 	 * that the multiplication will fit in int
911d6b92ffaSHans Petter Selasky 	 */
912d6b92ffaSHans Petter Selasky 	if (attr->cap.max_send_wr > 0x7fffffff / ctx->max_sq_desc_sz) {
913d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "\n");
914d6b92ffaSHans Petter Selasky 		return -EINVAL;
915d6b92ffaSHans Petter Selasky 	}
916d6b92ffaSHans Petter Selasky 
917d6b92ffaSHans Petter Selasky 	wq_size = mlx5_round_up_power_of_two(attr->cap.max_send_wr * wqe_size);
918d6b92ffaSHans Petter Selasky 	qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
919d6b92ffaSHans Petter Selasky 	if (qp->sq.wqe_cnt > ctx->max_send_wqebb) {
920d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "\n");
921d6b92ffaSHans Petter Selasky 		return -EINVAL;
922d6b92ffaSHans Petter Selasky 	}
923d6b92ffaSHans Petter Selasky 
924d6b92ffaSHans Petter Selasky 	qp->sq.wqe_shift = mlx5_ilog2(MLX5_SEND_WQE_BB);
925d6b92ffaSHans Petter Selasky 	qp->sq.max_gs = attr->cap.max_send_sge;
926d6b92ffaSHans Petter Selasky 	qp->sq.max_post = wq_size / wqe_size;
927d6b92ffaSHans Petter Selasky 
928d6b92ffaSHans Petter Selasky 	return wq_size;
929d6b92ffaSHans Petter Selasky }
930d6b92ffaSHans Petter Selasky 
931d6b92ffaSHans Petter Selasky static int mlx5_calc_rwq_size(struct mlx5_context *ctx,
932d6b92ffaSHans Petter Selasky 			      struct mlx5_rwq *rwq,
933d6b92ffaSHans Petter Selasky 			      struct ibv_wq_init_attr *attr)
934d6b92ffaSHans Petter Selasky {
935d6b92ffaSHans Petter Selasky 	size_t wqe_size;
936d6b92ffaSHans Petter Selasky 	int wq_size;
937d6b92ffaSHans Petter Selasky 	uint32_t num_scatter;
938d6b92ffaSHans Petter Selasky 	int scat_spc;
939d6b92ffaSHans Petter Selasky 
940d6b92ffaSHans Petter Selasky 	if (!attr->max_wr)
941d6b92ffaSHans Petter Selasky 		return -EINVAL;
942d6b92ffaSHans Petter Selasky 
943d6b92ffaSHans Petter Selasky 	/* TBD: check caps for RQ */
944d6b92ffaSHans Petter Selasky 	num_scatter = max_t(uint32_t, attr->max_sge, 1);
945d6b92ffaSHans Petter Selasky 	wqe_size = sizeof(struct mlx5_wqe_data_seg) * num_scatter;
946d6b92ffaSHans Petter Selasky 
947d6b92ffaSHans Petter Selasky 	if (rwq->wq_sig)
948d6b92ffaSHans Petter Selasky 		wqe_size += sizeof(struct mlx5_rwqe_sig);
949d6b92ffaSHans Petter Selasky 
950d6b92ffaSHans Petter Selasky 	if (wqe_size <= 0 || wqe_size > ctx->max_rq_desc_sz)
951d6b92ffaSHans Petter Selasky 		return -EINVAL;
952d6b92ffaSHans Petter Selasky 
953d6b92ffaSHans Petter Selasky 	wqe_size = mlx5_round_up_power_of_two(wqe_size);
954d6b92ffaSHans Petter Selasky 	wq_size = mlx5_round_up_power_of_two(attr->max_wr) * wqe_size;
955d6b92ffaSHans Petter Selasky 	wq_size = max(wq_size, MLX5_SEND_WQE_BB);
956d6b92ffaSHans Petter Selasky 	rwq->rq.wqe_cnt = wq_size / wqe_size;
957d6b92ffaSHans Petter Selasky 	rwq->rq.wqe_shift = mlx5_ilog2(wqe_size);
958d6b92ffaSHans Petter Selasky 	rwq->rq.max_post = 1 << mlx5_ilog2(wq_size / wqe_size);
959d6b92ffaSHans Petter Selasky 	scat_spc = wqe_size -
960d6b92ffaSHans Petter Selasky 		((rwq->wq_sig) ? sizeof(struct mlx5_rwqe_sig) : 0);
961d6b92ffaSHans Petter Selasky 	rwq->rq.max_gs = scat_spc / sizeof(struct mlx5_wqe_data_seg);
962d6b92ffaSHans Petter Selasky 	return wq_size;
963d6b92ffaSHans Petter Selasky }
964d6b92ffaSHans Petter Selasky 
965d6b92ffaSHans Petter Selasky static int mlx5_calc_rq_size(struct mlx5_context *ctx,
966d6b92ffaSHans Petter Selasky 			     struct ibv_qp_init_attr_ex *attr,
967d6b92ffaSHans Petter Selasky 			     struct mlx5_qp *qp)
968d6b92ffaSHans Petter Selasky {
969d6b92ffaSHans Petter Selasky 	int wqe_size;
970d6b92ffaSHans Petter Selasky 	int wq_size;
971d6b92ffaSHans Petter Selasky 	int scat_spc;
972d6b92ffaSHans Petter Selasky 	FILE *fp = ctx->dbg_fp;
973d6b92ffaSHans Petter Selasky 
974d6b92ffaSHans Petter Selasky 	if (!attr->cap.max_recv_wr)
975d6b92ffaSHans Petter Selasky 		return 0;
976d6b92ffaSHans Petter Selasky 
977d6b92ffaSHans Petter Selasky 	if (attr->cap.max_recv_wr > ctx->max_recv_wr) {
978d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "\n");
979d6b92ffaSHans Petter Selasky 		return -EINVAL;
980d6b92ffaSHans Petter Selasky 	}
981d6b92ffaSHans Petter Selasky 
982d6b92ffaSHans Petter Selasky 	wqe_size = mlx5_calc_rcv_wqe(ctx, attr, qp);
983d6b92ffaSHans Petter Selasky 	if (wqe_size < 0 || wqe_size > ctx->max_rq_desc_sz) {
984d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "\n");
985d6b92ffaSHans Petter Selasky 		return -EINVAL;
986d6b92ffaSHans Petter Selasky 	}
987d6b92ffaSHans Petter Selasky 
988d6b92ffaSHans Petter Selasky 	wq_size = mlx5_round_up_power_of_two(attr->cap.max_recv_wr) * wqe_size;
989d6b92ffaSHans Petter Selasky 	if (wqe_size) {
990d6b92ffaSHans Petter Selasky 		wq_size = max(wq_size, MLX5_SEND_WQE_BB);
991d6b92ffaSHans Petter Selasky 		qp->rq.wqe_cnt = wq_size / wqe_size;
992d6b92ffaSHans Petter Selasky 		qp->rq.wqe_shift = mlx5_ilog2(wqe_size);
993d6b92ffaSHans Petter Selasky 		qp->rq.max_post = 1 << mlx5_ilog2(wq_size / wqe_size);
994d6b92ffaSHans Petter Selasky 		scat_spc = wqe_size -
995d6b92ffaSHans Petter Selasky 			(qp->wq_sig ? sizeof(struct mlx5_rwqe_sig) : 0);
996d6b92ffaSHans Petter Selasky 		qp->rq.max_gs = scat_spc / sizeof(struct mlx5_wqe_data_seg);
997d6b92ffaSHans Petter Selasky 	} else {
998d6b92ffaSHans Petter Selasky 		qp->rq.wqe_cnt = 0;
999d6b92ffaSHans Petter Selasky 		qp->rq.wqe_shift = 0;
1000d6b92ffaSHans Petter Selasky 		qp->rq.max_post = 0;
1001d6b92ffaSHans Petter Selasky 		qp->rq.max_gs = 0;
1002d6b92ffaSHans Petter Selasky 	}
1003d6b92ffaSHans Petter Selasky 	return wq_size;
1004d6b92ffaSHans Petter Selasky }
1005d6b92ffaSHans Petter Selasky 
1006d6b92ffaSHans Petter Selasky static int mlx5_calc_wq_size(struct mlx5_context *ctx,
1007d6b92ffaSHans Petter Selasky 			     struct ibv_qp_init_attr_ex *attr,
1008d6b92ffaSHans Petter Selasky 			     struct mlx5_qp *qp)
1009d6b92ffaSHans Petter Selasky {
1010d6b92ffaSHans Petter Selasky 	int ret;
1011d6b92ffaSHans Petter Selasky 	int result;
1012d6b92ffaSHans Petter Selasky 
1013d6b92ffaSHans Petter Selasky 	ret = mlx5_calc_sq_size(ctx, attr, qp);
1014d6b92ffaSHans Petter Selasky 	if (ret < 0)
1015d6b92ffaSHans Petter Selasky 		return ret;
1016d6b92ffaSHans Petter Selasky 
1017d6b92ffaSHans Petter Selasky 	result = ret;
1018d6b92ffaSHans Petter Selasky 	ret = mlx5_calc_rq_size(ctx, attr, qp);
1019d6b92ffaSHans Petter Selasky 	if (ret < 0)
1020d6b92ffaSHans Petter Selasky 		return ret;
1021d6b92ffaSHans Petter Selasky 
1022d6b92ffaSHans Petter Selasky 	result += ret;
1023d6b92ffaSHans Petter Selasky 
1024d6b92ffaSHans Petter Selasky 	qp->sq.offset = ret;
1025d6b92ffaSHans Petter Selasky 	qp->rq.offset = 0;
1026d6b92ffaSHans Petter Selasky 
1027d6b92ffaSHans Petter Selasky 	return result;
1028d6b92ffaSHans Petter Selasky }
1029d6b92ffaSHans Petter Selasky 
1030d6b92ffaSHans Petter Selasky static void map_uuar(struct ibv_context *context, struct mlx5_qp *qp,
1031d6b92ffaSHans Petter Selasky 		     int uuar_index)
1032d6b92ffaSHans Petter Selasky {
1033d6b92ffaSHans Petter Selasky 	struct mlx5_context *ctx = to_mctx(context);
1034d6b92ffaSHans Petter Selasky 
1035d6b92ffaSHans Petter Selasky 	qp->bf = &ctx->bfs[uuar_index];
1036d6b92ffaSHans Petter Selasky }
1037d6b92ffaSHans Petter Selasky 
1038d6b92ffaSHans Petter Selasky static const char *qptype2key(enum ibv_qp_type type)
1039d6b92ffaSHans Petter Selasky {
1040d6b92ffaSHans Petter Selasky 	switch (type) {
1041d6b92ffaSHans Petter Selasky 	case IBV_QPT_RC: return "HUGE_RC";
1042d6b92ffaSHans Petter Selasky 	case IBV_QPT_UC: return "HUGE_UC";
1043d6b92ffaSHans Petter Selasky 	case IBV_QPT_UD: return "HUGE_UD";
1044d6b92ffaSHans Petter Selasky 	case IBV_QPT_RAW_PACKET: return "HUGE_RAW_ETH";
1045d6b92ffaSHans Petter Selasky 	default: return "HUGE_NA";
1046d6b92ffaSHans Petter Selasky 	}
1047d6b92ffaSHans Petter Selasky }
1048d6b92ffaSHans Petter Selasky 
1049d6b92ffaSHans Petter Selasky static int mlx5_alloc_qp_buf(struct ibv_context *context,
1050d6b92ffaSHans Petter Selasky 			     struct ibv_qp_init_attr_ex *attr,
1051d6b92ffaSHans Petter Selasky 			     struct mlx5_qp *qp,
1052d6b92ffaSHans Petter Selasky 			     int size)
1053d6b92ffaSHans Petter Selasky {
1054d6b92ffaSHans Petter Selasky 	int err;
1055d6b92ffaSHans Petter Selasky 	enum mlx5_alloc_type alloc_type;
1056d6b92ffaSHans Petter Selasky 	enum mlx5_alloc_type default_alloc_type = MLX5_ALLOC_TYPE_ANON;
1057d6b92ffaSHans Petter Selasky 	const char *qp_huge_key;
1058d6b92ffaSHans Petter Selasky 
1059d6b92ffaSHans Petter Selasky 	if (qp->sq.wqe_cnt) {
1060d6b92ffaSHans Petter Selasky 		qp->sq.wrid = malloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wrid));
1061d6b92ffaSHans Petter Selasky 		if (!qp->sq.wrid) {
1062d6b92ffaSHans Petter Selasky 			errno = ENOMEM;
1063d6b92ffaSHans Petter Selasky 			err = -1;
1064d6b92ffaSHans Petter Selasky 			return err;
1065d6b92ffaSHans Petter Selasky 		}
1066d6b92ffaSHans Petter Selasky 
1067d6b92ffaSHans Petter Selasky 		qp->sq.wr_data = malloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wr_data));
1068d6b92ffaSHans Petter Selasky 		if (!qp->sq.wr_data) {
1069d6b92ffaSHans Petter Selasky 			errno = ENOMEM;
1070d6b92ffaSHans Petter Selasky 			err = -1;
1071d6b92ffaSHans Petter Selasky 			goto ex_wrid;
1072d6b92ffaSHans Petter Selasky 		}
1073d6b92ffaSHans Petter Selasky 	}
1074d6b92ffaSHans Petter Selasky 
1075d6b92ffaSHans Petter Selasky 	qp->sq.wqe_head = malloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wqe_head));
1076d6b92ffaSHans Petter Selasky 	if (!qp->sq.wqe_head) {
1077d6b92ffaSHans Petter Selasky 		errno = ENOMEM;
1078d6b92ffaSHans Petter Selasky 		err = -1;
1079d6b92ffaSHans Petter Selasky 			goto ex_wrid;
1080d6b92ffaSHans Petter Selasky 	}
1081d6b92ffaSHans Petter Selasky 
1082d6b92ffaSHans Petter Selasky 	if (qp->rq.wqe_cnt) {
1083d6b92ffaSHans Petter Selasky 		qp->rq.wrid = malloc(qp->rq.wqe_cnt * sizeof(uint64_t));
1084d6b92ffaSHans Petter Selasky 		if (!qp->rq.wrid) {
1085d6b92ffaSHans Petter Selasky 			errno = ENOMEM;
1086d6b92ffaSHans Petter Selasky 			err = -1;
1087d6b92ffaSHans Petter Selasky 			goto ex_wrid;
1088d6b92ffaSHans Petter Selasky 		}
1089d6b92ffaSHans Petter Selasky 	}
1090d6b92ffaSHans Petter Selasky 
1091d6b92ffaSHans Petter Selasky 	/* compatibility support */
1092d6b92ffaSHans Petter Selasky 	qp_huge_key  = qptype2key(qp->ibv_qp->qp_type);
1093d6b92ffaSHans Petter Selasky 	if (mlx5_use_huge(qp_huge_key))
1094d6b92ffaSHans Petter Selasky 		default_alloc_type = MLX5_ALLOC_TYPE_HUGE;
1095d6b92ffaSHans Petter Selasky 
1096d6b92ffaSHans Petter Selasky 	mlx5_get_alloc_type(MLX5_QP_PREFIX, &alloc_type,
1097d6b92ffaSHans Petter Selasky 			    default_alloc_type);
1098d6b92ffaSHans Petter Selasky 
1099d6b92ffaSHans Petter Selasky 	err = mlx5_alloc_prefered_buf(to_mctx(context), &qp->buf,
1100d6b92ffaSHans Petter Selasky 				      align(qp->buf_size, to_mdev
1101d6b92ffaSHans Petter Selasky 				      (context->device)->page_size),
1102d6b92ffaSHans Petter Selasky 				      to_mdev(context->device)->page_size,
1103d6b92ffaSHans Petter Selasky 				      alloc_type,
1104d6b92ffaSHans Petter Selasky 				      MLX5_QP_PREFIX);
1105d6b92ffaSHans Petter Selasky 
1106d6b92ffaSHans Petter Selasky 	if (err) {
1107d6b92ffaSHans Petter Selasky 		err = -ENOMEM;
1108d6b92ffaSHans Petter Selasky 		goto ex_wrid;
1109d6b92ffaSHans Petter Selasky 	}
1110d6b92ffaSHans Petter Selasky 
1111d6b92ffaSHans Petter Selasky 	memset(qp->buf.buf, 0, qp->buf_size);
1112d6b92ffaSHans Petter Selasky 
1113d6b92ffaSHans Petter Selasky 	if (attr->qp_type == IBV_QPT_RAW_PACKET) {
1114d6b92ffaSHans Petter Selasky 		size_t aligned_sq_buf_size = align(qp->sq_buf_size,
1115d6b92ffaSHans Petter Selasky 						   to_mdev(context->device)->page_size);
1116d6b92ffaSHans Petter Selasky 		/* For Raw Packet QP, allocate a separate buffer for the SQ */
1117d6b92ffaSHans Petter Selasky 		err = mlx5_alloc_prefered_buf(to_mctx(context), &qp->sq_buf,
1118d6b92ffaSHans Petter Selasky 					      aligned_sq_buf_size,
1119d6b92ffaSHans Petter Selasky 					      to_mdev(context->device)->page_size,
1120d6b92ffaSHans Petter Selasky 					      alloc_type,
1121d6b92ffaSHans Petter Selasky 					      MLX5_QP_PREFIX);
1122d6b92ffaSHans Petter Selasky 		if (err) {
1123d6b92ffaSHans Petter Selasky 			err = -ENOMEM;
1124d6b92ffaSHans Petter Selasky 			goto rq_buf;
1125d6b92ffaSHans Petter Selasky 		}
1126d6b92ffaSHans Petter Selasky 
1127d6b92ffaSHans Petter Selasky 		memset(qp->sq_buf.buf, 0, aligned_sq_buf_size);
1128d6b92ffaSHans Petter Selasky 	}
1129d6b92ffaSHans Petter Selasky 
1130d6b92ffaSHans Petter Selasky 	return 0;
1131d6b92ffaSHans Petter Selasky rq_buf:
1132d6b92ffaSHans Petter Selasky 	mlx5_free_actual_buf(to_mctx(qp->verbs_qp.qp.context), &qp->buf);
1133d6b92ffaSHans Petter Selasky ex_wrid:
1134d6b92ffaSHans Petter Selasky 	if (qp->rq.wrid)
1135d6b92ffaSHans Petter Selasky 		free(qp->rq.wrid);
1136d6b92ffaSHans Petter Selasky 
1137d6b92ffaSHans Petter Selasky 	if (qp->sq.wqe_head)
1138d6b92ffaSHans Petter Selasky 		free(qp->sq.wqe_head);
1139d6b92ffaSHans Petter Selasky 
1140d6b92ffaSHans Petter Selasky 	if (qp->sq.wr_data)
1141d6b92ffaSHans Petter Selasky 		free(qp->sq.wr_data);
1142d6b92ffaSHans Petter Selasky 	if (qp->sq.wrid)
1143d6b92ffaSHans Petter Selasky 		free(qp->sq.wrid);
1144d6b92ffaSHans Petter Selasky 
1145d6b92ffaSHans Petter Selasky 	return err;
1146d6b92ffaSHans Petter Selasky }
1147d6b92ffaSHans Petter Selasky 
1148d6b92ffaSHans Petter Selasky static void mlx5_free_qp_buf(struct mlx5_qp *qp)
1149d6b92ffaSHans Petter Selasky {
1150d6b92ffaSHans Petter Selasky 	struct mlx5_context *ctx = to_mctx(qp->ibv_qp->context);
1151d6b92ffaSHans Petter Selasky 
1152d6b92ffaSHans Petter Selasky 	mlx5_free_actual_buf(ctx, &qp->buf);
1153d6b92ffaSHans Petter Selasky 
1154d6b92ffaSHans Petter Selasky 	if (qp->sq_buf.buf)
1155d6b92ffaSHans Petter Selasky 		mlx5_free_actual_buf(ctx, &qp->sq_buf);
1156d6b92ffaSHans Petter Selasky 
1157d6b92ffaSHans Petter Selasky 	if (qp->rq.wrid)
1158d6b92ffaSHans Petter Selasky 		free(qp->rq.wrid);
1159d6b92ffaSHans Petter Selasky 
1160d6b92ffaSHans Petter Selasky 	if (qp->sq.wqe_head)
1161d6b92ffaSHans Petter Selasky 		free(qp->sq.wqe_head);
1162d6b92ffaSHans Petter Selasky 
1163d6b92ffaSHans Petter Selasky 	if (qp->sq.wrid)
1164d6b92ffaSHans Petter Selasky 		free(qp->sq.wrid);
1165d6b92ffaSHans Petter Selasky 
1166d6b92ffaSHans Petter Selasky 	if (qp->sq.wr_data)
1167d6b92ffaSHans Petter Selasky 		free(qp->sq.wr_data);
1168d6b92ffaSHans Petter Selasky }
1169d6b92ffaSHans Petter Selasky 
1170d6b92ffaSHans Petter Selasky static int mlx5_cmd_create_rss_qp(struct ibv_context *context,
1171d6b92ffaSHans Petter Selasky 				 struct ibv_qp_init_attr_ex *attr,
1172d6b92ffaSHans Petter Selasky 				 struct mlx5_qp *qp)
1173d6b92ffaSHans Petter Selasky {
1174d6b92ffaSHans Petter Selasky 	struct mlx5_create_qp_ex_rss cmd_ex_rss = {};
1175d6b92ffaSHans Petter Selasky 	struct mlx5_create_qp_resp_ex resp = {};
1176d6b92ffaSHans Petter Selasky 	int ret;
1177d6b92ffaSHans Petter Selasky 
1178d6b92ffaSHans Petter Selasky 	if (attr->rx_hash_conf.rx_hash_key_len > sizeof(cmd_ex_rss.rx_hash_key)) {
1179d6b92ffaSHans Petter Selasky 		errno = EINVAL;
1180d6b92ffaSHans Petter Selasky 		return errno;
1181d6b92ffaSHans Petter Selasky 	}
1182d6b92ffaSHans Petter Selasky 
1183d6b92ffaSHans Petter Selasky 	cmd_ex_rss.rx_hash_fields_mask = attr->rx_hash_conf.rx_hash_fields_mask;
1184d6b92ffaSHans Petter Selasky 	cmd_ex_rss.rx_hash_function = attr->rx_hash_conf.rx_hash_function;
1185d6b92ffaSHans Petter Selasky 	cmd_ex_rss.rx_key_len = attr->rx_hash_conf.rx_hash_key_len;
1186d6b92ffaSHans Petter Selasky 	memcpy(cmd_ex_rss.rx_hash_key, attr->rx_hash_conf.rx_hash_key,
1187d6b92ffaSHans Petter Selasky 			attr->rx_hash_conf.rx_hash_key_len);
1188d6b92ffaSHans Petter Selasky 
1189d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_create_qp_ex2(context, &qp->verbs_qp,
1190d6b92ffaSHans Petter Selasky 					    sizeof(qp->verbs_qp), attr,
1191d6b92ffaSHans Petter Selasky 					    &cmd_ex_rss.ibv_cmd, sizeof(cmd_ex_rss.ibv_cmd),
1192d6b92ffaSHans Petter Selasky 					    sizeof(cmd_ex_rss), &resp.ibv_resp,
1193d6b92ffaSHans Petter Selasky 					    sizeof(resp.ibv_resp), sizeof(resp));
1194d6b92ffaSHans Petter Selasky 	if (ret)
1195d6b92ffaSHans Petter Selasky 		return ret;
1196d6b92ffaSHans Petter Selasky 
1197d6b92ffaSHans Petter Selasky 	qp->rss_qp = 1;
1198d6b92ffaSHans Petter Selasky 	return 0;
1199d6b92ffaSHans Petter Selasky }
1200d6b92ffaSHans Petter Selasky 
1201d6b92ffaSHans Petter Selasky static int mlx5_cmd_create_qp_ex(struct ibv_context *context,
1202d6b92ffaSHans Petter Selasky 				 struct ibv_qp_init_attr_ex *attr,
1203d6b92ffaSHans Petter Selasky 				 struct mlx5_create_qp *cmd,
1204d6b92ffaSHans Petter Selasky 				 struct mlx5_qp *qp,
1205d6b92ffaSHans Petter Selasky 				 struct mlx5_create_qp_resp_ex *resp)
1206d6b92ffaSHans Petter Selasky {
1207d6b92ffaSHans Petter Selasky 	struct mlx5_create_qp_ex cmd_ex;
1208d6b92ffaSHans Petter Selasky 	int ret;
1209d6b92ffaSHans Petter Selasky 
1210d6b92ffaSHans Petter Selasky 	memset(&cmd_ex, 0, sizeof(cmd_ex));
1211d6b92ffaSHans Petter Selasky 	memcpy(&cmd_ex.ibv_cmd.base, &cmd->ibv_cmd.user_handle,
1212d6b92ffaSHans Petter Selasky 	       offsetof(typeof(cmd->ibv_cmd), is_srq) +
1213d6b92ffaSHans Petter Selasky 	       sizeof(cmd->ibv_cmd.is_srq) -
1214d6b92ffaSHans Petter Selasky 	       offsetof(typeof(cmd->ibv_cmd), user_handle));
1215d6b92ffaSHans Petter Selasky 
1216d6b92ffaSHans Petter Selasky 	memcpy(&cmd_ex.drv_ex, &cmd->buf_addr,
1217d6b92ffaSHans Petter Selasky 	       offsetof(typeof(*cmd), sq_buf_addr) +
1218d6b92ffaSHans Petter Selasky 	       sizeof(cmd->sq_buf_addr) - sizeof(cmd->ibv_cmd));
1219d6b92ffaSHans Petter Selasky 
1220d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_create_qp_ex2(context, &qp->verbs_qp,
1221d6b92ffaSHans Petter Selasky 				    sizeof(qp->verbs_qp), attr,
1222d6b92ffaSHans Petter Selasky 				    &cmd_ex.ibv_cmd, sizeof(cmd_ex.ibv_cmd),
1223d6b92ffaSHans Petter Selasky 				    sizeof(cmd_ex), &resp->ibv_resp,
1224d6b92ffaSHans Petter Selasky 				    sizeof(resp->ibv_resp), sizeof(*resp));
1225d6b92ffaSHans Petter Selasky 
1226d6b92ffaSHans Petter Selasky 	return ret;
1227d6b92ffaSHans Petter Selasky }
1228d6b92ffaSHans Petter Selasky 
1229d6b92ffaSHans Petter Selasky enum {
1230d6b92ffaSHans Petter Selasky 	MLX5_CREATE_QP_SUP_COMP_MASK = (IBV_QP_INIT_ATTR_PD |
1231d6b92ffaSHans Petter Selasky 					IBV_QP_INIT_ATTR_XRCD |
1232d6b92ffaSHans Petter Selasky 					IBV_QP_INIT_ATTR_CREATE_FLAGS |
1233d6b92ffaSHans Petter Selasky 					IBV_QP_INIT_ATTR_MAX_TSO_HEADER |
1234d6b92ffaSHans Petter Selasky 					IBV_QP_INIT_ATTR_IND_TABLE |
1235d6b92ffaSHans Petter Selasky 					IBV_QP_INIT_ATTR_RX_HASH),
1236d6b92ffaSHans Petter Selasky };
1237d6b92ffaSHans Petter Selasky 
1238d6b92ffaSHans Petter Selasky enum {
1239d6b92ffaSHans Petter Selasky 	MLX5_CREATE_QP_EX2_COMP_MASK = (IBV_QP_INIT_ATTR_CREATE_FLAGS |
1240d6b92ffaSHans Petter Selasky 					IBV_QP_INIT_ATTR_MAX_TSO_HEADER |
1241d6b92ffaSHans Petter Selasky 					IBV_QP_INIT_ATTR_IND_TABLE |
1242d6b92ffaSHans Petter Selasky 					IBV_QP_INIT_ATTR_RX_HASH),
1243d6b92ffaSHans Petter Selasky };
1244d6b92ffaSHans Petter Selasky 
1245d6b92ffaSHans Petter Selasky static struct ibv_qp *create_qp(struct ibv_context *context,
1246d6b92ffaSHans Petter Selasky 			 struct ibv_qp_init_attr_ex *attr)
1247d6b92ffaSHans Petter Selasky {
1248d6b92ffaSHans Petter Selasky 	struct mlx5_create_qp		cmd;
1249d6b92ffaSHans Petter Selasky 	struct mlx5_create_qp_resp	resp;
1250d6b92ffaSHans Petter Selasky 	struct mlx5_create_qp_resp_ex resp_ex;
1251d6b92ffaSHans Petter Selasky 	struct mlx5_qp		       *qp;
1252d6b92ffaSHans Petter Selasky 	int				ret;
1253d6b92ffaSHans Petter Selasky 	struct mlx5_context	       *ctx = to_mctx(context);
1254d6b92ffaSHans Petter Selasky 	struct ibv_qp		       *ibqp;
1255d6b92ffaSHans Petter Selasky 	int32_t				usr_idx = 0;
1256d6b92ffaSHans Petter Selasky 	uint32_t			uuar_index;
1257d6b92ffaSHans Petter Selasky 	FILE *fp = ctx->dbg_fp;
1258d6b92ffaSHans Petter Selasky 
1259d6b92ffaSHans Petter Selasky 	if (attr->comp_mask & ~MLX5_CREATE_QP_SUP_COMP_MASK)
1260d6b92ffaSHans Petter Selasky 		return NULL;
1261d6b92ffaSHans Petter Selasky 
1262d6b92ffaSHans Petter Selasky 	if ((attr->comp_mask & IBV_QP_INIT_ATTR_MAX_TSO_HEADER) &&
1263d6b92ffaSHans Petter Selasky 	    (attr->qp_type != IBV_QPT_RAW_PACKET))
1264d6b92ffaSHans Petter Selasky 		return NULL;
1265d6b92ffaSHans Petter Selasky 
1266d6b92ffaSHans Petter Selasky 	qp = calloc(1, sizeof(*qp));
1267d6b92ffaSHans Petter Selasky 	if (!qp) {
1268d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "\n");
1269d6b92ffaSHans Petter Selasky 		return NULL;
1270d6b92ffaSHans Petter Selasky 	}
1271d6b92ffaSHans Petter Selasky 	ibqp = (struct ibv_qp *)&qp->verbs_qp;
1272d6b92ffaSHans Petter Selasky 	qp->ibv_qp = ibqp;
1273d6b92ffaSHans Petter Selasky 
1274d6b92ffaSHans Petter Selasky 	memset(&cmd, 0, sizeof(cmd));
1275d6b92ffaSHans Petter Selasky 	memset(&resp, 0, sizeof(resp));
1276d6b92ffaSHans Petter Selasky 	memset(&resp_ex, 0, sizeof(resp_ex));
1277d6b92ffaSHans Petter Selasky 
1278d6b92ffaSHans Petter Selasky 	if (attr->comp_mask & IBV_QP_INIT_ATTR_RX_HASH) {
1279d6b92ffaSHans Petter Selasky 		ret = mlx5_cmd_create_rss_qp(context, attr, qp);
1280d6b92ffaSHans Petter Selasky 		if (ret)
1281d6b92ffaSHans Petter Selasky 			goto err;
1282d6b92ffaSHans Petter Selasky 
1283d6b92ffaSHans Petter Selasky 		return ibqp;
1284d6b92ffaSHans Petter Selasky 	}
1285d6b92ffaSHans Petter Selasky 
1286d6b92ffaSHans Petter Selasky 	qp->wq_sig = qp_sig_enabled();
1287d6b92ffaSHans Petter Selasky 	if (qp->wq_sig)
1288d6b92ffaSHans Petter Selasky 		cmd.flags |= MLX5_QP_FLAG_SIGNATURE;
1289d6b92ffaSHans Petter Selasky 
1290d6b92ffaSHans Petter Selasky 	if (use_scatter_to_cqe())
1291d6b92ffaSHans Petter Selasky 		cmd.flags |= MLX5_QP_FLAG_SCATTER_CQE;
1292d6b92ffaSHans Petter Selasky 
1293d6b92ffaSHans Petter Selasky 	ret = mlx5_calc_wq_size(ctx, attr, qp);
1294d6b92ffaSHans Petter Selasky 	if (ret < 0) {
1295d6b92ffaSHans Petter Selasky 		errno = -ret;
1296d6b92ffaSHans Petter Selasky 		goto err;
1297d6b92ffaSHans Petter Selasky 	}
1298d6b92ffaSHans Petter Selasky 
1299d6b92ffaSHans Petter Selasky 	if (attr->qp_type == IBV_QPT_RAW_PACKET) {
1300d6b92ffaSHans Petter Selasky 		qp->buf_size = qp->sq.offset;
1301d6b92ffaSHans Petter Selasky 		qp->sq_buf_size = ret - qp->buf_size;
1302d6b92ffaSHans Petter Selasky 		qp->sq.offset = 0;
1303d6b92ffaSHans Petter Selasky 	} else {
1304d6b92ffaSHans Petter Selasky 		qp->buf_size = ret;
1305d6b92ffaSHans Petter Selasky 		qp->sq_buf_size = 0;
1306d6b92ffaSHans Petter Selasky 	}
1307d6b92ffaSHans Petter Selasky 
1308d6b92ffaSHans Petter Selasky 	if (mlx5_alloc_qp_buf(context, attr, qp, ret)) {
1309d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "\n");
1310d6b92ffaSHans Petter Selasky 		goto err;
1311d6b92ffaSHans Petter Selasky 	}
1312d6b92ffaSHans Petter Selasky 
1313d6b92ffaSHans Petter Selasky 	if (attr->qp_type == IBV_QPT_RAW_PACKET) {
1314d6b92ffaSHans Petter Selasky 		qp->sq_start = qp->sq_buf.buf;
1315d6b92ffaSHans Petter Selasky 		qp->sq.qend = qp->sq_buf.buf +
1316d6b92ffaSHans Petter Selasky 				(qp->sq.wqe_cnt << qp->sq.wqe_shift);
1317d6b92ffaSHans Petter Selasky 	} else {
1318d6b92ffaSHans Petter Selasky 		qp->sq_start = qp->buf.buf + qp->sq.offset;
1319d6b92ffaSHans Petter Selasky 		qp->sq.qend = qp->buf.buf + qp->sq.offset +
1320d6b92ffaSHans Petter Selasky 				(qp->sq.wqe_cnt << qp->sq.wqe_shift);
1321d6b92ffaSHans Petter Selasky 	}
1322d6b92ffaSHans Petter Selasky 
1323d6b92ffaSHans Petter Selasky 	mlx5_init_qp_indices(qp);
1324d6b92ffaSHans Petter Selasky 
1325a687910fSSean Lim 	if (mlx5_spinlock_init(&qp->sq.lock))
1326d6b92ffaSHans Petter Selasky 		goto err_free_qp_buf;
1327d6b92ffaSHans Petter Selasky 
1328a687910fSSean Lim 	if (mlx5_spinlock_init(&qp->rq.lock))
1329a687910fSSean Lim 		goto err_sq_spl;
1330a687910fSSean Lim 
1331d6b92ffaSHans Petter Selasky 	qp->db = mlx5_alloc_dbrec(ctx);
1332d6b92ffaSHans Petter Selasky 	if (!qp->db) {
1333d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "\n");
1334a687910fSSean Lim 		goto err_rq_spl;
1335d6b92ffaSHans Petter Selasky 	}
1336d6b92ffaSHans Petter Selasky 
1337d6b92ffaSHans Petter Selasky 	qp->db[MLX5_RCV_DBR] = 0;
1338d6b92ffaSHans Petter Selasky 	qp->db[MLX5_SND_DBR] = 0;
1339d6b92ffaSHans Petter Selasky 
1340d6b92ffaSHans Petter Selasky 	cmd.buf_addr = (uintptr_t) qp->buf.buf;
1341d6b92ffaSHans Petter Selasky 	cmd.sq_buf_addr = (attr->qp_type == IBV_QPT_RAW_PACKET) ?
1342d6b92ffaSHans Petter Selasky 			  (uintptr_t) qp->sq_buf.buf : 0;
1343d6b92ffaSHans Petter Selasky 	cmd.db_addr  = (uintptr_t) qp->db;
1344d6b92ffaSHans Petter Selasky 	cmd.sq_wqe_count = qp->sq.wqe_cnt;
1345d6b92ffaSHans Petter Selasky 	cmd.rq_wqe_count = qp->rq.wqe_cnt;
1346d6b92ffaSHans Petter Selasky 	cmd.rq_wqe_shift = qp->rq.wqe_shift;
1347d6b92ffaSHans Petter Selasky 
1348d6b92ffaSHans Petter Selasky 	if (ctx->atomic_cap == IBV_ATOMIC_HCA)
1349d6b92ffaSHans Petter Selasky 		qp->atomics_enabled = 1;
1350d6b92ffaSHans Petter Selasky 
1351d6b92ffaSHans Petter Selasky 	if (!ctx->cqe_version) {
1352d6b92ffaSHans Petter Selasky 		cmd.uidx = 0xffffff;
1353d6b92ffaSHans Petter Selasky 		pthread_mutex_lock(&ctx->qp_table_mutex);
1354d6b92ffaSHans Petter Selasky 	} else if (!is_xrc_tgt(attr->qp_type)) {
1355d6b92ffaSHans Petter Selasky 		usr_idx = mlx5_store_uidx(ctx, qp);
1356d6b92ffaSHans Petter Selasky 		if (usr_idx < 0) {
1357d6b92ffaSHans Petter Selasky 			mlx5_dbg(fp, MLX5_DBG_QP, "Couldn't find free user index\n");
1358d6b92ffaSHans Petter Selasky 			goto err_rq_db;
1359d6b92ffaSHans Petter Selasky 		}
1360d6b92ffaSHans Petter Selasky 
1361d6b92ffaSHans Petter Selasky 		cmd.uidx = usr_idx;
1362d6b92ffaSHans Petter Selasky 	}
1363d6b92ffaSHans Petter Selasky 
1364d6b92ffaSHans Petter Selasky 	if (attr->comp_mask & MLX5_CREATE_QP_EX2_COMP_MASK)
1365d6b92ffaSHans Petter Selasky 		ret = mlx5_cmd_create_qp_ex(context, attr, &cmd, qp, &resp_ex);
1366d6b92ffaSHans Petter Selasky 	else
1367d6b92ffaSHans Petter Selasky 		ret = ibv_cmd_create_qp_ex(context, &qp->verbs_qp, sizeof(qp->verbs_qp),
1368d6b92ffaSHans Petter Selasky 					   attr, &cmd.ibv_cmd, sizeof(cmd),
1369d6b92ffaSHans Petter Selasky 					   &resp.ibv_resp, sizeof(resp));
1370d6b92ffaSHans Petter Selasky 	if (ret) {
1371d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "ret %d\n", ret);
1372d6b92ffaSHans Petter Selasky 		goto err_free_uidx;
1373d6b92ffaSHans Petter Selasky 	}
1374d6b92ffaSHans Petter Selasky 
1375d6b92ffaSHans Petter Selasky 	uuar_index = (attr->comp_mask & MLX5_CREATE_QP_EX2_COMP_MASK) ?
1376d6b92ffaSHans Petter Selasky 			resp_ex.uuar_index : resp.uuar_index;
1377d6b92ffaSHans Petter Selasky 	if (!ctx->cqe_version) {
1378d6b92ffaSHans Petter Selasky 		if (qp->sq.wqe_cnt || qp->rq.wqe_cnt) {
1379d6b92ffaSHans Petter Selasky 			ret = mlx5_store_qp(ctx, ibqp->qp_num, qp);
1380d6b92ffaSHans Petter Selasky 			if (ret) {
1381d6b92ffaSHans Petter Selasky 				mlx5_dbg(fp, MLX5_DBG_QP, "ret %d\n", ret);
1382d6b92ffaSHans Petter Selasky 				goto err_destroy;
1383d6b92ffaSHans Petter Selasky 			}
1384d6b92ffaSHans Petter Selasky 		}
1385d6b92ffaSHans Petter Selasky 
1386d6b92ffaSHans Petter Selasky 		pthread_mutex_unlock(&ctx->qp_table_mutex);
1387d6b92ffaSHans Petter Selasky 	}
1388d6b92ffaSHans Petter Selasky 
1389d6b92ffaSHans Petter Selasky 	map_uuar(context, qp, uuar_index);
1390d6b92ffaSHans Petter Selasky 
1391d6b92ffaSHans Petter Selasky 	qp->rq.max_post = qp->rq.wqe_cnt;
1392d6b92ffaSHans Petter Selasky 	if (attr->sq_sig_all)
1393d6b92ffaSHans Petter Selasky 		qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE;
1394d6b92ffaSHans Petter Selasky 	else
1395d6b92ffaSHans Petter Selasky 		qp->sq_signal_bits = 0;
1396d6b92ffaSHans Petter Selasky 
1397d6b92ffaSHans Petter Selasky 	attr->cap.max_send_wr = qp->sq.max_post;
1398d6b92ffaSHans Petter Selasky 	attr->cap.max_recv_wr = qp->rq.max_post;
1399d6b92ffaSHans Petter Selasky 	attr->cap.max_recv_sge = qp->rq.max_gs;
1400d6b92ffaSHans Petter Selasky 
1401d6b92ffaSHans Petter Selasky 	qp->rsc.type = MLX5_RSC_TYPE_QP;
1402d6b92ffaSHans Petter Selasky 	qp->rsc.rsn = (ctx->cqe_version && !is_xrc_tgt(attr->qp_type)) ?
1403d6b92ffaSHans Petter Selasky 		      usr_idx : ibqp->qp_num;
1404d6b92ffaSHans Petter Selasky 
1405d6b92ffaSHans Petter Selasky 	return ibqp;
1406d6b92ffaSHans Petter Selasky 
1407d6b92ffaSHans Petter Selasky err_destroy:
1408d6b92ffaSHans Petter Selasky 	ibv_cmd_destroy_qp(ibqp);
1409d6b92ffaSHans Petter Selasky 
1410d6b92ffaSHans Petter Selasky err_free_uidx:
1411d6b92ffaSHans Petter Selasky 	if (!ctx->cqe_version)
1412d6b92ffaSHans Petter Selasky 		pthread_mutex_unlock(&to_mctx(context)->qp_table_mutex);
1413d6b92ffaSHans Petter Selasky 	else if (!is_xrc_tgt(attr->qp_type))
1414d6b92ffaSHans Petter Selasky 		mlx5_clear_uidx(ctx, usr_idx);
1415d6b92ffaSHans Petter Selasky 
1416d6b92ffaSHans Petter Selasky err_rq_db:
1417d6b92ffaSHans Petter Selasky 	mlx5_free_db(to_mctx(context), qp->db);
1418d6b92ffaSHans Petter Selasky 
1419a687910fSSean Lim err_rq_spl:
1420a687910fSSean Lim 	mlx5_spinlock_destroy(&qp->rq.lock);
1421a687910fSSean Lim 
1422a687910fSSean Lim err_sq_spl:
1423a687910fSSean Lim 	mlx5_spinlock_destroy(&qp->sq.lock);
1424a687910fSSean Lim 
1425d6b92ffaSHans Petter Selasky err_free_qp_buf:
1426d6b92ffaSHans Petter Selasky 	mlx5_free_qp_buf(qp);
1427d6b92ffaSHans Petter Selasky 
1428d6b92ffaSHans Petter Selasky err:
1429d6b92ffaSHans Petter Selasky 	free(qp);
1430d6b92ffaSHans Petter Selasky 
1431d6b92ffaSHans Petter Selasky 	return NULL;
1432d6b92ffaSHans Petter Selasky }
1433d6b92ffaSHans Petter Selasky 
1434d6b92ffaSHans Petter Selasky struct ibv_qp *mlx5_create_qp(struct ibv_pd *pd,
1435d6b92ffaSHans Petter Selasky 			      struct ibv_qp_init_attr *attr)
1436d6b92ffaSHans Petter Selasky {
1437d6b92ffaSHans Petter Selasky 	struct ibv_qp *qp;
1438d6b92ffaSHans Petter Selasky 	struct ibv_qp_init_attr_ex attrx;
1439d6b92ffaSHans Petter Selasky 
1440d6b92ffaSHans Petter Selasky 	memset(&attrx, 0, sizeof(attrx));
1441d6b92ffaSHans Petter Selasky 	memcpy(&attrx, attr, sizeof(*attr));
1442d6b92ffaSHans Petter Selasky 	attrx.comp_mask = IBV_QP_INIT_ATTR_PD;
1443d6b92ffaSHans Petter Selasky 	attrx.pd = pd;
1444d6b92ffaSHans Petter Selasky 	qp = create_qp(pd->context, &attrx);
1445d6b92ffaSHans Petter Selasky 	if (qp)
1446d6b92ffaSHans Petter Selasky 		memcpy(attr, &attrx, sizeof(*attr));
1447d6b92ffaSHans Petter Selasky 
1448d6b92ffaSHans Petter Selasky 	return qp;
1449d6b92ffaSHans Petter Selasky }
1450d6b92ffaSHans Petter Selasky 
1451d6b92ffaSHans Petter Selasky static void mlx5_lock_cqs(struct ibv_qp *qp)
1452d6b92ffaSHans Petter Selasky {
1453d6b92ffaSHans Petter Selasky 	struct mlx5_cq *send_cq = to_mcq(qp->send_cq);
1454d6b92ffaSHans Petter Selasky 	struct mlx5_cq *recv_cq = to_mcq(qp->recv_cq);
1455d6b92ffaSHans Petter Selasky 
1456d6b92ffaSHans Petter Selasky 	if (send_cq && recv_cq) {
1457d6b92ffaSHans Petter Selasky 		if (send_cq == recv_cq) {
1458d6b92ffaSHans Petter Selasky 			mlx5_spin_lock(&send_cq->lock);
1459d6b92ffaSHans Petter Selasky 		} else if (send_cq->cqn < recv_cq->cqn) {
1460d6b92ffaSHans Petter Selasky 			mlx5_spin_lock(&send_cq->lock);
1461d6b92ffaSHans Petter Selasky 			mlx5_spin_lock(&recv_cq->lock);
1462d6b92ffaSHans Petter Selasky 		} else {
1463d6b92ffaSHans Petter Selasky 			mlx5_spin_lock(&recv_cq->lock);
1464d6b92ffaSHans Petter Selasky 			mlx5_spin_lock(&send_cq->lock);
1465d6b92ffaSHans Petter Selasky 		}
1466d6b92ffaSHans Petter Selasky 	} else if (send_cq) {
1467d6b92ffaSHans Petter Selasky 		mlx5_spin_lock(&send_cq->lock);
1468d6b92ffaSHans Petter Selasky 	} else if (recv_cq) {
1469d6b92ffaSHans Petter Selasky 		mlx5_spin_lock(&recv_cq->lock);
1470d6b92ffaSHans Petter Selasky 	}
1471d6b92ffaSHans Petter Selasky }
1472d6b92ffaSHans Petter Selasky 
1473d6b92ffaSHans Petter Selasky static void mlx5_unlock_cqs(struct ibv_qp *qp)
1474d6b92ffaSHans Petter Selasky {
1475d6b92ffaSHans Petter Selasky 	struct mlx5_cq *send_cq = to_mcq(qp->send_cq);
1476d6b92ffaSHans Petter Selasky 	struct mlx5_cq *recv_cq = to_mcq(qp->recv_cq);
1477d6b92ffaSHans Petter Selasky 
1478d6b92ffaSHans Petter Selasky 	if (send_cq && recv_cq) {
1479d6b92ffaSHans Petter Selasky 		if (send_cq == recv_cq) {
1480d6b92ffaSHans Petter Selasky 			mlx5_spin_unlock(&send_cq->lock);
1481d6b92ffaSHans Petter Selasky 		} else if (send_cq->cqn < recv_cq->cqn) {
1482d6b92ffaSHans Petter Selasky 			mlx5_spin_unlock(&recv_cq->lock);
1483d6b92ffaSHans Petter Selasky 			mlx5_spin_unlock(&send_cq->lock);
1484d6b92ffaSHans Petter Selasky 		} else {
1485d6b92ffaSHans Petter Selasky 			mlx5_spin_unlock(&send_cq->lock);
1486d6b92ffaSHans Petter Selasky 			mlx5_spin_unlock(&recv_cq->lock);
1487d6b92ffaSHans Petter Selasky 		}
1488d6b92ffaSHans Petter Selasky 	} else if (send_cq) {
1489d6b92ffaSHans Petter Selasky 		mlx5_spin_unlock(&send_cq->lock);
1490d6b92ffaSHans Petter Selasky 	} else if (recv_cq) {
1491d6b92ffaSHans Petter Selasky 		mlx5_spin_unlock(&recv_cq->lock);
1492d6b92ffaSHans Petter Selasky 	}
1493d6b92ffaSHans Petter Selasky }
1494d6b92ffaSHans Petter Selasky 
1495d6b92ffaSHans Petter Selasky int mlx5_destroy_qp(struct ibv_qp *ibqp)
1496d6b92ffaSHans Petter Selasky {
1497d6b92ffaSHans Petter Selasky 	struct mlx5_qp *qp = to_mqp(ibqp);
1498d6b92ffaSHans Petter Selasky 	struct mlx5_context *ctx = to_mctx(ibqp->context);
1499d6b92ffaSHans Petter Selasky 	int ret;
1500d6b92ffaSHans Petter Selasky 
1501d6b92ffaSHans Petter Selasky 	if (qp->rss_qp) {
1502d6b92ffaSHans Petter Selasky 		ret = ibv_cmd_destroy_qp(ibqp);
1503d6b92ffaSHans Petter Selasky 		if (ret)
1504d6b92ffaSHans Petter Selasky 			return ret;
1505d6b92ffaSHans Petter Selasky 		goto free;
1506d6b92ffaSHans Petter Selasky 	}
1507d6b92ffaSHans Petter Selasky 
1508d6b92ffaSHans Petter Selasky 	if (!ctx->cqe_version)
1509d6b92ffaSHans Petter Selasky 		pthread_mutex_lock(&ctx->qp_table_mutex);
1510d6b92ffaSHans Petter Selasky 
1511d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_destroy_qp(ibqp);
1512d6b92ffaSHans Petter Selasky 	if (ret) {
1513d6b92ffaSHans Petter Selasky 		if (!ctx->cqe_version)
1514d6b92ffaSHans Petter Selasky 			pthread_mutex_unlock(&ctx->qp_table_mutex);
1515d6b92ffaSHans Petter Selasky 		return ret;
1516d6b92ffaSHans Petter Selasky 	}
1517d6b92ffaSHans Petter Selasky 
1518d6b92ffaSHans Petter Selasky 	mlx5_lock_cqs(ibqp);
1519d6b92ffaSHans Petter Selasky 
1520d6b92ffaSHans Petter Selasky 	__mlx5_cq_clean(to_mcq(ibqp->recv_cq), qp->rsc.rsn,
1521d6b92ffaSHans Petter Selasky 			ibqp->srq ? to_msrq(ibqp->srq) : NULL);
1522d6b92ffaSHans Petter Selasky 	if (ibqp->send_cq != ibqp->recv_cq)
1523d6b92ffaSHans Petter Selasky 		__mlx5_cq_clean(to_mcq(ibqp->send_cq), qp->rsc.rsn, NULL);
1524d6b92ffaSHans Petter Selasky 
1525d6b92ffaSHans Petter Selasky 	if (!ctx->cqe_version) {
1526d6b92ffaSHans Petter Selasky 		if (qp->sq.wqe_cnt || qp->rq.wqe_cnt)
1527d6b92ffaSHans Petter Selasky 			mlx5_clear_qp(ctx, ibqp->qp_num);
1528d6b92ffaSHans Petter Selasky 	}
1529d6b92ffaSHans Petter Selasky 
1530d6b92ffaSHans Petter Selasky 	mlx5_unlock_cqs(ibqp);
1531d6b92ffaSHans Petter Selasky 	if (!ctx->cqe_version)
1532d6b92ffaSHans Petter Selasky 		pthread_mutex_unlock(&ctx->qp_table_mutex);
1533d6b92ffaSHans Petter Selasky 	else if (!is_xrc_tgt(ibqp->qp_type))
1534d6b92ffaSHans Petter Selasky 		mlx5_clear_uidx(ctx, qp->rsc.rsn);
1535d6b92ffaSHans Petter Selasky 
1536d6b92ffaSHans Petter Selasky 	mlx5_free_db(ctx, qp->db);
1537a687910fSSean Lim 	mlx5_spinlock_destroy(&qp->rq.lock);
1538a687910fSSean Lim 	mlx5_spinlock_destroy(&qp->sq.lock);
1539d6b92ffaSHans Petter Selasky 	mlx5_free_qp_buf(qp);
1540d6b92ffaSHans Petter Selasky free:
1541d6b92ffaSHans Petter Selasky 	free(qp);
1542d6b92ffaSHans Petter Selasky 
1543d6b92ffaSHans Petter Selasky 	return 0;
1544d6b92ffaSHans Petter Selasky }
1545d6b92ffaSHans Petter Selasky 
1546d6b92ffaSHans Petter Selasky int mlx5_query_qp(struct ibv_qp *ibqp, struct ibv_qp_attr *attr,
1547d6b92ffaSHans Petter Selasky 		  int attr_mask, struct ibv_qp_init_attr *init_attr)
1548d6b92ffaSHans Petter Selasky {
1549d6b92ffaSHans Petter Selasky 	struct ibv_query_qp cmd;
1550d6b92ffaSHans Petter Selasky 	struct mlx5_qp *qp = to_mqp(ibqp);
1551d6b92ffaSHans Petter Selasky 	int ret;
1552d6b92ffaSHans Petter Selasky 
1553d6b92ffaSHans Petter Selasky 	if (qp->rss_qp)
1554d6b92ffaSHans Petter Selasky 		return ENOSYS;
1555d6b92ffaSHans Petter Selasky 
1556d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_query_qp(ibqp, attr, attr_mask, init_attr, &cmd, sizeof(cmd));
1557d6b92ffaSHans Petter Selasky 	if (ret)
1558d6b92ffaSHans Petter Selasky 		return ret;
1559d6b92ffaSHans Petter Selasky 
1560d6b92ffaSHans Petter Selasky 	init_attr->cap.max_send_wr     = qp->sq.max_post;
1561d6b92ffaSHans Petter Selasky 	init_attr->cap.max_send_sge    = qp->sq.max_gs;
1562d6b92ffaSHans Petter Selasky 	init_attr->cap.max_inline_data = qp->max_inline_data;
1563d6b92ffaSHans Petter Selasky 
1564d6b92ffaSHans Petter Selasky 	attr->cap = init_attr->cap;
1565d6b92ffaSHans Petter Selasky 
1566d6b92ffaSHans Petter Selasky 	return 0;
1567d6b92ffaSHans Petter Selasky }
1568d6b92ffaSHans Petter Selasky 
1569d6b92ffaSHans Petter Selasky enum {
1570d6b92ffaSHans Petter Selasky 	MLX5_MODIFY_QP_EX_ATTR_MASK = IBV_QP_RATE_LIMIT,
1571d6b92ffaSHans Petter Selasky };
1572d6b92ffaSHans Petter Selasky 
1573d6b92ffaSHans Petter Selasky int mlx5_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
1574d6b92ffaSHans Petter Selasky 		   int attr_mask)
1575d6b92ffaSHans Petter Selasky {
1576d6b92ffaSHans Petter Selasky 	struct ibv_modify_qp cmd = {};
1577d6b92ffaSHans Petter Selasky 	struct ibv_modify_qp_ex cmd_ex = {};
1578d6b92ffaSHans Petter Selasky 	struct ibv_modify_qp_resp_ex resp = {};
1579d6b92ffaSHans Petter Selasky 	struct mlx5_qp *mqp = to_mqp(qp);
1580d6b92ffaSHans Petter Selasky 	struct mlx5_context *context = to_mctx(qp->context);
1581d6b92ffaSHans Petter Selasky 	int ret;
1582d6b92ffaSHans Petter Selasky 	uint32_t *db;
1583d6b92ffaSHans Petter Selasky 
1584d6b92ffaSHans Petter Selasky 	if (mqp->rss_qp)
1585d6b92ffaSHans Petter Selasky 		return ENOSYS;
1586d6b92ffaSHans Petter Selasky 
1587d6b92ffaSHans Petter Selasky 	if (attr_mask & IBV_QP_PORT) {
1588d6b92ffaSHans Petter Selasky 		switch (qp->qp_type) {
1589d6b92ffaSHans Petter Selasky 		case IBV_QPT_RAW_PACKET:
1590d6b92ffaSHans Petter Selasky 			if (context->cached_link_layer[attr->port_num - 1] ==
1591d6b92ffaSHans Petter Selasky 			     IBV_LINK_LAYER_ETHERNET) {
1592d6b92ffaSHans Petter Selasky 				if (context->cached_device_cap_flags &
1593d6b92ffaSHans Petter Selasky 				    IBV_DEVICE_RAW_IP_CSUM)
1594d6b92ffaSHans Petter Selasky 					mqp->qp_cap_cache |=
1595d6b92ffaSHans Petter Selasky 						MLX5_CSUM_SUPPORT_RAW_OVER_ETH |
1596d6b92ffaSHans Petter Selasky 						MLX5_RX_CSUM_VALID;
1597d6b92ffaSHans Petter Selasky 
1598d6b92ffaSHans Petter Selasky 				if (ibv_is_qpt_supported(
1599d6b92ffaSHans Petter Selasky 				 context->cached_tso_caps.supported_qpts,
1600d6b92ffaSHans Petter Selasky 				 IBV_QPT_RAW_PACKET))
1601d6b92ffaSHans Petter Selasky 					mqp->max_tso =
1602d6b92ffaSHans Petter Selasky 					     context->cached_tso_caps.max_tso;
1603d6b92ffaSHans Petter Selasky 			}
1604d6b92ffaSHans Petter Selasky 			break;
1605d6b92ffaSHans Petter Selasky 		default:
1606d6b92ffaSHans Petter Selasky 			break;
1607d6b92ffaSHans Petter Selasky 		}
1608d6b92ffaSHans Petter Selasky 	}
1609d6b92ffaSHans Petter Selasky 
1610d6b92ffaSHans Petter Selasky 	if (attr_mask & MLX5_MODIFY_QP_EX_ATTR_MASK)
1611d6b92ffaSHans Petter Selasky 		ret = ibv_cmd_modify_qp_ex(qp, attr, attr_mask,
1612d6b92ffaSHans Petter Selasky 					   &cmd_ex,
1613d6b92ffaSHans Petter Selasky 					   sizeof(cmd_ex), sizeof(cmd_ex),
1614d6b92ffaSHans Petter Selasky 					   &resp,
1615d6b92ffaSHans Petter Selasky 					   sizeof(resp), sizeof(resp));
1616d6b92ffaSHans Petter Selasky 	else
1617d6b92ffaSHans Petter Selasky 		ret = ibv_cmd_modify_qp(qp, attr, attr_mask,
1618d6b92ffaSHans Petter Selasky 					&cmd, sizeof(cmd));
1619d6b92ffaSHans Petter Selasky 
1620d6b92ffaSHans Petter Selasky 	if (!ret		       &&
1621d6b92ffaSHans Petter Selasky 	    (attr_mask & IBV_QP_STATE) &&
1622d6b92ffaSHans Petter Selasky 	    attr->qp_state == IBV_QPS_RESET) {
1623d6b92ffaSHans Petter Selasky 		if (qp->recv_cq) {
1624d6b92ffaSHans Petter Selasky 			mlx5_cq_clean(to_mcq(qp->recv_cq), mqp->rsc.rsn,
1625d6b92ffaSHans Petter Selasky 				      qp->srq ? to_msrq(qp->srq) : NULL);
1626d6b92ffaSHans Petter Selasky 		}
1627d6b92ffaSHans Petter Selasky 		if (qp->send_cq != qp->recv_cq && qp->send_cq)
1628d6b92ffaSHans Petter Selasky 			mlx5_cq_clean(to_mcq(qp->send_cq),
1629d6b92ffaSHans Petter Selasky 				      to_mqp(qp)->rsc.rsn, NULL);
1630d6b92ffaSHans Petter Selasky 
1631d6b92ffaSHans Petter Selasky 		mlx5_init_qp_indices(mqp);
1632d6b92ffaSHans Petter Selasky 		db = mqp->db;
1633d6b92ffaSHans Petter Selasky 		db[MLX5_RCV_DBR] = 0;
1634d6b92ffaSHans Petter Selasky 		db[MLX5_SND_DBR] = 0;
1635d6b92ffaSHans Petter Selasky 	}
1636d6b92ffaSHans Petter Selasky 
1637d6b92ffaSHans Petter Selasky 	/*
1638d6b92ffaSHans Petter Selasky 	 * When the Raw Packet QP is in INIT state, its RQ
1639d6b92ffaSHans Petter Selasky 	 * underneath is already in RDY, which means it can
1640d6b92ffaSHans Petter Selasky 	 * receive packets. According to the IB spec, a QP can't
1641d6b92ffaSHans Petter Selasky 	 * receive packets until moved to RTR state. To achieve this,
1642d6b92ffaSHans Petter Selasky 	 * for Raw Packet QPs, we update the doorbell record
1643d6b92ffaSHans Petter Selasky 	 * once the QP is moved to RTR.
1644d6b92ffaSHans Petter Selasky 	 */
1645d6b92ffaSHans Petter Selasky 	if (!ret &&
1646d6b92ffaSHans Petter Selasky 	    (attr_mask & IBV_QP_STATE) &&
1647d6b92ffaSHans Petter Selasky 	    attr->qp_state == IBV_QPS_RTR &&
1648d6b92ffaSHans Petter Selasky 	    qp->qp_type == IBV_QPT_RAW_PACKET) {
1649d6b92ffaSHans Petter Selasky 		mlx5_spin_lock(&mqp->rq.lock);
1650d6b92ffaSHans Petter Selasky 		mqp->db[MLX5_RCV_DBR] = htobe32(mqp->rq.head & 0xffff);
1651d6b92ffaSHans Petter Selasky 		mlx5_spin_unlock(&mqp->rq.lock);
1652d6b92ffaSHans Petter Selasky 	}
1653d6b92ffaSHans Petter Selasky 
1654d6b92ffaSHans Petter Selasky 	return ret;
1655d6b92ffaSHans Petter Selasky }
1656d6b92ffaSHans Petter Selasky 
1657d6b92ffaSHans Petter Selasky #define RROCE_UDP_SPORT_MIN 0xC000
1658d6b92ffaSHans Petter Selasky #define RROCE_UDP_SPORT_MAX 0xFFFF
1659d6b92ffaSHans Petter Selasky struct ibv_ah *mlx5_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
1660d6b92ffaSHans Petter Selasky {
1661d6b92ffaSHans Petter Selasky 	struct mlx5_context *ctx = to_mctx(pd->context);
1662d6b92ffaSHans Petter Selasky 	struct ibv_port_attr port_attr;
1663d6b92ffaSHans Petter Selasky 	struct mlx5_ah *ah;
1664d6b92ffaSHans Petter Selasky 	uint32_t gid_type;
1665d6b92ffaSHans Petter Selasky 	uint32_t tmp;
1666d6b92ffaSHans Petter Selasky 	uint8_t grh;
1667d6b92ffaSHans Petter Selasky 	int is_eth;
1668d6b92ffaSHans Petter Selasky 
1669d6b92ffaSHans Petter Selasky 	if (attr->port_num < 1 || attr->port_num > ctx->num_ports)
1670d6b92ffaSHans Petter Selasky 		return NULL;
1671d6b92ffaSHans Petter Selasky 
1672d6b92ffaSHans Petter Selasky 	if (ctx->cached_link_layer[attr->port_num - 1]) {
1673d6b92ffaSHans Petter Selasky 		is_eth = ctx->cached_link_layer[attr->port_num - 1] ==
1674d6b92ffaSHans Petter Selasky 			IBV_LINK_LAYER_ETHERNET;
1675d6b92ffaSHans Petter Selasky 	} else {
1676d6b92ffaSHans Petter Selasky 		if (ibv_query_port(pd->context, attr->port_num, &port_attr))
1677d6b92ffaSHans Petter Selasky 			return NULL;
1678d6b92ffaSHans Petter Selasky 
1679d6b92ffaSHans Petter Selasky 		is_eth = (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET);
1680d6b92ffaSHans Petter Selasky 	}
1681d6b92ffaSHans Petter Selasky 
1682d6b92ffaSHans Petter Selasky 	if (unlikely((!attr->is_global) && is_eth)) {
1683d6b92ffaSHans Petter Selasky 		errno = EINVAL;
1684d6b92ffaSHans Petter Selasky 		return NULL;
1685d6b92ffaSHans Petter Selasky 	}
1686d6b92ffaSHans Petter Selasky 
1687d6b92ffaSHans Petter Selasky 	ah = calloc(1, sizeof *ah);
1688d6b92ffaSHans Petter Selasky 	if (!ah)
1689d6b92ffaSHans Petter Selasky 		return NULL;
1690d6b92ffaSHans Petter Selasky 
1691d6b92ffaSHans Petter Selasky 	if (is_eth) {
1692d6b92ffaSHans Petter Selasky 		if (ibv_query_gid_type(pd->context, attr->port_num,
1693d6b92ffaSHans Petter Selasky 				       attr->grh.sgid_index, &gid_type))
1694d6b92ffaSHans Petter Selasky 			goto err;
1695d6b92ffaSHans Petter Selasky 
1696d6b92ffaSHans Petter Selasky 		if (gid_type == IBV_GID_TYPE_ROCE_V2)
1697d6b92ffaSHans Petter Selasky 			ah->av.rlid = htobe16(rand() % (RROCE_UDP_SPORT_MAX + 1
1698d6b92ffaSHans Petter Selasky 						      - RROCE_UDP_SPORT_MIN)
1699d6b92ffaSHans Petter Selasky 					    + RROCE_UDP_SPORT_MIN);
1700d6b92ffaSHans Petter Selasky 		/* Since RoCE packets must contain GRH, this bit is reserved
1701d6b92ffaSHans Petter Selasky 		 * for RoCE and shouldn't be set.
1702d6b92ffaSHans Petter Selasky 		 */
1703d6b92ffaSHans Petter Selasky 		grh = 0;
1704d6b92ffaSHans Petter Selasky 	} else {
1705d6b92ffaSHans Petter Selasky 		ah->av.fl_mlid = attr->src_path_bits & 0x7f;
1706d6b92ffaSHans Petter Selasky 		ah->av.rlid = htobe16(attr->dlid);
1707d6b92ffaSHans Petter Selasky 		grh = 1;
1708d6b92ffaSHans Petter Selasky 	}
1709d6b92ffaSHans Petter Selasky 	ah->av.stat_rate_sl = (attr->static_rate << 4) | attr->sl;
1710d6b92ffaSHans Petter Selasky 	if (attr->is_global) {
1711d6b92ffaSHans Petter Selasky 		ah->av.tclass = attr->grh.traffic_class;
1712d6b92ffaSHans Petter Selasky 		ah->av.hop_limit = attr->grh.hop_limit;
1713d6b92ffaSHans Petter Selasky 		tmp = htobe32((grh << 30) |
1714d6b92ffaSHans Petter Selasky 			    ((attr->grh.sgid_index & 0xff) << 20) |
1715d6b92ffaSHans Petter Selasky 			    (attr->grh.flow_label & 0xfffff));
1716d6b92ffaSHans Petter Selasky 		ah->av.grh_gid_fl = tmp;
1717d6b92ffaSHans Petter Selasky 		memcpy(ah->av.rgid, attr->grh.dgid.raw, 16);
1718d6b92ffaSHans Petter Selasky 	}
1719d6b92ffaSHans Petter Selasky 
1720d6b92ffaSHans Petter Selasky 	if (is_eth) {
1721d6b92ffaSHans Petter Selasky 		if (ctx->cmds_supp_uhw & MLX5_USER_CMDS_SUPP_UHW_CREATE_AH) {
1722d6b92ffaSHans Petter Selasky 			struct mlx5_create_ah_resp resp = {};
1723d6b92ffaSHans Petter Selasky 
1724d6b92ffaSHans Petter Selasky 			if (ibv_cmd_create_ah(pd, &ah->ibv_ah, attr, &resp.ibv_resp, sizeof(resp)))
1725d6b92ffaSHans Petter Selasky 				goto err;
1726d6b92ffaSHans Petter Selasky 
1727d6b92ffaSHans Petter Selasky 			ah->kern_ah = true;
1728d6b92ffaSHans Petter Selasky 			memcpy(ah->av.rmac, resp.dmac, ETHERNET_LL_SIZE);
1729d6b92ffaSHans Petter Selasky 		} else {
1730d6b92ffaSHans Petter Selasky 			uint16_t vid;
1731d6b92ffaSHans Petter Selasky 
1732d6b92ffaSHans Petter Selasky 			if (ibv_resolve_eth_l2_from_gid(pd->context, attr,
1733d6b92ffaSHans Petter Selasky 							ah->av.rmac, &vid))
1734d6b92ffaSHans Petter Selasky 				goto err;
1735d6b92ffaSHans Petter Selasky 		}
1736d6b92ffaSHans Petter Selasky 	}
1737d6b92ffaSHans Petter Selasky 
1738d6b92ffaSHans Petter Selasky 	return &ah->ibv_ah;
1739d6b92ffaSHans Petter Selasky err:
1740d6b92ffaSHans Petter Selasky 	free(ah);
1741d6b92ffaSHans Petter Selasky 	return NULL;
1742d6b92ffaSHans Petter Selasky }
1743d6b92ffaSHans Petter Selasky 
1744d6b92ffaSHans Petter Selasky int mlx5_destroy_ah(struct ibv_ah *ah)
1745d6b92ffaSHans Petter Selasky {
1746d6b92ffaSHans Petter Selasky 	struct mlx5_ah *mah = to_mah(ah);
1747d6b92ffaSHans Petter Selasky 	int err;
1748d6b92ffaSHans Petter Selasky 
1749d6b92ffaSHans Petter Selasky 	if (mah->kern_ah) {
1750d6b92ffaSHans Petter Selasky 		err = ibv_cmd_destroy_ah(ah);
1751d6b92ffaSHans Petter Selasky 		if (err)
1752d6b92ffaSHans Petter Selasky 			return err;
1753d6b92ffaSHans Petter Selasky 	}
1754d6b92ffaSHans Petter Selasky 
1755d6b92ffaSHans Petter Selasky 	free(mah);
1756d6b92ffaSHans Petter Selasky 	return 0;
1757d6b92ffaSHans Petter Selasky }
1758d6b92ffaSHans Petter Selasky 
1759d6b92ffaSHans Petter Selasky int mlx5_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid)
1760d6b92ffaSHans Petter Selasky {
1761d6b92ffaSHans Petter Selasky 	return ibv_cmd_attach_mcast(qp, gid, lid);
1762d6b92ffaSHans Petter Selasky }
1763d6b92ffaSHans Petter Selasky 
1764d6b92ffaSHans Petter Selasky int mlx5_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid)
1765d6b92ffaSHans Petter Selasky {
1766d6b92ffaSHans Petter Selasky 	return ibv_cmd_detach_mcast(qp, gid, lid);
1767d6b92ffaSHans Petter Selasky }
1768d6b92ffaSHans Petter Selasky 
1769d6b92ffaSHans Petter Selasky struct ibv_qp *mlx5_create_qp_ex(struct ibv_context *context,
1770d6b92ffaSHans Petter Selasky 				 struct ibv_qp_init_attr_ex *attr)
1771d6b92ffaSHans Petter Selasky {
1772d6b92ffaSHans Petter Selasky 	return create_qp(context, attr);
1773d6b92ffaSHans Petter Selasky }
1774d6b92ffaSHans Petter Selasky 
1775d6b92ffaSHans Petter Selasky int mlx5_get_srq_num(struct ibv_srq *srq, uint32_t *srq_num)
1776d6b92ffaSHans Petter Selasky {
1777d6b92ffaSHans Petter Selasky 	struct mlx5_srq *msrq = to_msrq(srq);
1778d6b92ffaSHans Petter Selasky 
1779d6b92ffaSHans Petter Selasky 	*srq_num = msrq->srqn;
1780d6b92ffaSHans Petter Selasky 
1781d6b92ffaSHans Petter Selasky 	return 0;
1782d6b92ffaSHans Petter Selasky }
1783d6b92ffaSHans Petter Selasky 
1784d6b92ffaSHans Petter Selasky struct ibv_xrcd *
1785d6b92ffaSHans Petter Selasky mlx5_open_xrcd(struct ibv_context *context,
1786d6b92ffaSHans Petter Selasky 	       struct ibv_xrcd_init_attr *xrcd_init_attr)
1787d6b92ffaSHans Petter Selasky {
1788d6b92ffaSHans Petter Selasky 	int err;
1789d6b92ffaSHans Petter Selasky 	struct verbs_xrcd *xrcd;
1790d6b92ffaSHans Petter Selasky 	struct ibv_open_xrcd cmd = {};
1791d6b92ffaSHans Petter Selasky 	struct ibv_open_xrcd_resp resp = {};
1792d6b92ffaSHans Petter Selasky 
1793d6b92ffaSHans Petter Selasky 	xrcd = calloc(1, sizeof(*xrcd));
1794d6b92ffaSHans Petter Selasky 	if (!xrcd)
1795d6b92ffaSHans Petter Selasky 		return NULL;
1796d6b92ffaSHans Petter Selasky 
1797d6b92ffaSHans Petter Selasky 	err = ibv_cmd_open_xrcd(context, xrcd, sizeof(*xrcd), xrcd_init_attr,
1798d6b92ffaSHans Petter Selasky 				&cmd, sizeof(cmd), &resp, sizeof(resp));
1799d6b92ffaSHans Petter Selasky 	if (err) {
1800d6b92ffaSHans Petter Selasky 		free(xrcd);
1801d6b92ffaSHans Petter Selasky 		return NULL;
1802d6b92ffaSHans Petter Selasky 	}
1803d6b92ffaSHans Petter Selasky 
1804d6b92ffaSHans Petter Selasky 	return &xrcd->xrcd;
1805d6b92ffaSHans Petter Selasky }
1806d6b92ffaSHans Petter Selasky 
1807d6b92ffaSHans Petter Selasky int mlx5_close_xrcd(struct ibv_xrcd *ib_xrcd)
1808d6b92ffaSHans Petter Selasky {
1809d6b92ffaSHans Petter Selasky 	struct verbs_xrcd *xrcd = container_of(ib_xrcd, struct verbs_xrcd, xrcd);
1810d6b92ffaSHans Petter Selasky 	int ret;
1811d6b92ffaSHans Petter Selasky 
1812d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_close_xrcd(xrcd);
1813d6b92ffaSHans Petter Selasky 	if (!ret)
1814d6b92ffaSHans Petter Selasky 		free(xrcd);
1815d6b92ffaSHans Petter Selasky 
1816d6b92ffaSHans Petter Selasky 	return ret;
1817d6b92ffaSHans Petter Selasky }
1818d6b92ffaSHans Petter Selasky 
1819d6b92ffaSHans Petter Selasky static struct ibv_srq *
1820d6b92ffaSHans Petter Selasky mlx5_create_xrc_srq(struct ibv_context *context,
1821d6b92ffaSHans Petter Selasky 		    struct ibv_srq_init_attr_ex *attr)
1822d6b92ffaSHans Petter Selasky {
1823d6b92ffaSHans Petter Selasky 	int err;
1824d6b92ffaSHans Petter Selasky 	struct mlx5_create_srq_ex cmd;
1825d6b92ffaSHans Petter Selasky 	struct mlx5_create_srq_resp resp;
1826d6b92ffaSHans Petter Selasky 	struct mlx5_srq *msrq;
1827d6b92ffaSHans Petter Selasky 	struct mlx5_context *ctx = to_mctx(context);
1828d6b92ffaSHans Petter Selasky 	int max_sge;
1829d6b92ffaSHans Petter Selasky 	struct ibv_srq *ibsrq;
1830d6b92ffaSHans Petter Selasky 	int uidx;
1831d6b92ffaSHans Petter Selasky 	FILE *fp = ctx->dbg_fp;
1832d6b92ffaSHans Petter Selasky 
1833d6b92ffaSHans Petter Selasky 	msrq = calloc(1, sizeof(*msrq));
1834d6b92ffaSHans Petter Selasky 	if (!msrq)
1835d6b92ffaSHans Petter Selasky 		return NULL;
1836d6b92ffaSHans Petter Selasky 
1837d6b92ffaSHans Petter Selasky 	ibsrq = (struct ibv_srq *)&msrq->vsrq;
1838d6b92ffaSHans Petter Selasky 
1839d6b92ffaSHans Petter Selasky 	memset(&cmd, 0, sizeof(cmd));
1840d6b92ffaSHans Petter Selasky 	memset(&resp, 0, sizeof(resp));
1841d6b92ffaSHans Petter Selasky 
1842d6b92ffaSHans Petter Selasky 	if (mlx5_spinlock_init(&msrq->lock)) {
1843d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:\n", __func__, __LINE__);
1844d6b92ffaSHans Petter Selasky 		goto err;
1845d6b92ffaSHans Petter Selasky 	}
1846d6b92ffaSHans Petter Selasky 
1847d6b92ffaSHans Petter Selasky 	if (attr->attr.max_wr > ctx->max_srq_recv_wr) {
1848d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:max_wr %d, max_srq_recv_wr %d\n",
1849d6b92ffaSHans Petter Selasky 			__func__, __LINE__, attr->attr.max_wr,
1850d6b92ffaSHans Petter Selasky 			ctx->max_srq_recv_wr);
1851d6b92ffaSHans Petter Selasky 		errno = EINVAL;
1852a687910fSSean Lim 		goto err_spl;
1853d6b92ffaSHans Petter Selasky 	}
1854d6b92ffaSHans Petter Selasky 
1855d6b92ffaSHans Petter Selasky 	/*
1856d6b92ffaSHans Petter Selasky 	 * this calculation does not consider required control segments. The
1857d6b92ffaSHans Petter Selasky 	 * final calculation is done again later. This is done so to avoid
1858d6b92ffaSHans Petter Selasky 	 * overflows of variables
1859d6b92ffaSHans Petter Selasky 	 */
1860d6b92ffaSHans Petter Selasky 	max_sge = ctx->max_recv_wr / sizeof(struct mlx5_wqe_data_seg);
1861d6b92ffaSHans Petter Selasky 	if (attr->attr.max_sge > max_sge) {
1862d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:max_wr %d, max_srq_recv_wr %d\n",
1863d6b92ffaSHans Petter Selasky 			__func__, __LINE__, attr->attr.max_wr,
1864d6b92ffaSHans Petter Selasky 			ctx->max_srq_recv_wr);
1865d6b92ffaSHans Petter Selasky 		errno = EINVAL;
1866a687910fSSean Lim 		goto err_spl;
1867d6b92ffaSHans Petter Selasky 	}
1868d6b92ffaSHans Petter Selasky 
1869d6b92ffaSHans Petter Selasky 	msrq->max     = align_queue_size(attr->attr.max_wr + 1);
1870d6b92ffaSHans Petter Selasky 	msrq->max_gs  = attr->attr.max_sge;
1871d6b92ffaSHans Petter Selasky 	msrq->counter = 0;
1872d6b92ffaSHans Petter Selasky 
1873d6b92ffaSHans Petter Selasky 	if (mlx5_alloc_srq_buf(context, msrq)) {
1874d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:\n", __func__, __LINE__);
1875a687910fSSean Lim 		goto err_spl;
1876d6b92ffaSHans Petter Selasky 	}
1877d6b92ffaSHans Petter Selasky 
1878d6b92ffaSHans Petter Selasky 	msrq->db = mlx5_alloc_dbrec(ctx);
1879d6b92ffaSHans Petter Selasky 	if (!msrq->db) {
1880d6b92ffaSHans Petter Selasky 		fprintf(stderr, "%s-%d:\n", __func__, __LINE__);
1881d6b92ffaSHans Petter Selasky 		goto err_free;
1882d6b92ffaSHans Petter Selasky 	}
1883d6b92ffaSHans Petter Selasky 
1884d6b92ffaSHans Petter Selasky 	*msrq->db = 0;
1885d6b92ffaSHans Petter Selasky 
1886d6b92ffaSHans Petter Selasky 	cmd.buf_addr = (uintptr_t)msrq->buf.buf;
1887d6b92ffaSHans Petter Selasky 	cmd.db_addr  = (uintptr_t)msrq->db;
1888d6b92ffaSHans Petter Selasky 	msrq->wq_sig = srq_sig_enabled();
1889d6b92ffaSHans Petter Selasky 	if (msrq->wq_sig)
1890d6b92ffaSHans Petter Selasky 		cmd.flags = MLX5_SRQ_FLAG_SIGNATURE;
1891d6b92ffaSHans Petter Selasky 
1892d6b92ffaSHans Petter Selasky 	attr->attr.max_sge = msrq->max_gs;
1893d6b92ffaSHans Petter Selasky 	if (ctx->cqe_version) {
1894d6b92ffaSHans Petter Selasky 		uidx = mlx5_store_uidx(ctx, msrq);
1895d6b92ffaSHans Petter Selasky 		if (uidx < 0) {
1896d6b92ffaSHans Petter Selasky 			mlx5_dbg(fp, MLX5_DBG_QP, "Couldn't find free user index\n");
1897d6b92ffaSHans Petter Selasky 			goto err_free_db;
1898d6b92ffaSHans Petter Selasky 		}
1899d6b92ffaSHans Petter Selasky 		cmd.uidx = uidx;
1900d6b92ffaSHans Petter Selasky 	} else {
1901d6b92ffaSHans Petter Selasky 		cmd.uidx = 0xffffff;
1902d6b92ffaSHans Petter Selasky 		pthread_mutex_lock(&ctx->srq_table_mutex);
1903d6b92ffaSHans Petter Selasky 	}
1904d6b92ffaSHans Petter Selasky 
1905d6b92ffaSHans Petter Selasky 	err = ibv_cmd_create_srq_ex(context, &msrq->vsrq, sizeof(msrq->vsrq),
1906d6b92ffaSHans Petter Selasky 				    attr, &cmd.ibv_cmd, sizeof(cmd),
1907d6b92ffaSHans Petter Selasky 				    &resp.ibv_resp, sizeof(resp));
1908d6b92ffaSHans Petter Selasky 	if (err)
1909d6b92ffaSHans Petter Selasky 		goto err_free_uidx;
1910d6b92ffaSHans Petter Selasky 
1911d6b92ffaSHans Petter Selasky 	if (!ctx->cqe_version) {
1912d6b92ffaSHans Petter Selasky 		err = mlx5_store_srq(to_mctx(context), resp.srqn, msrq);
1913d6b92ffaSHans Petter Selasky 		if (err)
1914d6b92ffaSHans Petter Selasky 			goto err_destroy;
1915d6b92ffaSHans Petter Selasky 
1916d6b92ffaSHans Petter Selasky 		pthread_mutex_unlock(&ctx->srq_table_mutex);
1917d6b92ffaSHans Petter Selasky 	}
1918d6b92ffaSHans Petter Selasky 
1919d6b92ffaSHans Petter Selasky 	msrq->srqn = resp.srqn;
1920d6b92ffaSHans Petter Selasky 	msrq->rsc.type = MLX5_RSC_TYPE_XSRQ;
1921d6b92ffaSHans Petter Selasky 	msrq->rsc.rsn = ctx->cqe_version ? cmd.uidx : resp.srqn;
1922d6b92ffaSHans Petter Selasky 
1923d6b92ffaSHans Petter Selasky 	return ibsrq;
1924d6b92ffaSHans Petter Selasky 
1925d6b92ffaSHans Petter Selasky err_destroy:
1926d6b92ffaSHans Petter Selasky 	ibv_cmd_destroy_srq(ibsrq);
1927d6b92ffaSHans Petter Selasky 
1928d6b92ffaSHans Petter Selasky err_free_uidx:
1929d6b92ffaSHans Petter Selasky 	if (ctx->cqe_version)
1930d6b92ffaSHans Petter Selasky 		mlx5_clear_uidx(ctx, cmd.uidx);
1931d6b92ffaSHans Petter Selasky 	else
1932d6b92ffaSHans Petter Selasky 		pthread_mutex_unlock(&ctx->srq_table_mutex);
1933d6b92ffaSHans Petter Selasky 
1934d6b92ffaSHans Petter Selasky err_free_db:
1935d6b92ffaSHans Petter Selasky 	mlx5_free_db(ctx, msrq->db);
1936d6b92ffaSHans Petter Selasky 
1937d6b92ffaSHans Petter Selasky err_free:
1938d6b92ffaSHans Petter Selasky 	free(msrq->wrid);
1939d6b92ffaSHans Petter Selasky 	mlx5_free_buf(&msrq->buf);
1940d6b92ffaSHans Petter Selasky 
1941a687910fSSean Lim err_spl:
1942a687910fSSean Lim 	mlx5_spinlock_destroy(&msrq->lock);
1943a687910fSSean Lim 
1944d6b92ffaSHans Petter Selasky err:
1945d6b92ffaSHans Petter Selasky 	free(msrq);
1946d6b92ffaSHans Petter Selasky 
1947d6b92ffaSHans Petter Selasky 	return NULL;
1948d6b92ffaSHans Petter Selasky }
1949d6b92ffaSHans Petter Selasky 
1950d6b92ffaSHans Petter Selasky struct ibv_srq *mlx5_create_srq_ex(struct ibv_context *context,
1951d6b92ffaSHans Petter Selasky 				   struct ibv_srq_init_attr_ex *attr)
1952d6b92ffaSHans Petter Selasky {
1953d6b92ffaSHans Petter Selasky 	if (!(attr->comp_mask & IBV_SRQ_INIT_ATTR_TYPE) ||
1954d6b92ffaSHans Petter Selasky 	    (attr->srq_type == IBV_SRQT_BASIC))
1955d6b92ffaSHans Petter Selasky 		return mlx5_create_srq(attr->pd,
1956d6b92ffaSHans Petter Selasky 				       (struct ibv_srq_init_attr *)attr);
1957d6b92ffaSHans Petter Selasky 	else if (attr->srq_type == IBV_SRQT_XRC)
1958d6b92ffaSHans Petter Selasky 		return mlx5_create_xrc_srq(context, attr);
1959d6b92ffaSHans Petter Selasky 
1960d6b92ffaSHans Petter Selasky 	return NULL;
1961d6b92ffaSHans Petter Selasky }
1962d6b92ffaSHans Petter Selasky 
1963d6b92ffaSHans Petter Selasky int mlx5_query_device_ex(struct ibv_context *context,
1964d6b92ffaSHans Petter Selasky 			 const struct ibv_query_device_ex_input *input,
1965d6b92ffaSHans Petter Selasky 			 struct ibv_device_attr_ex *attr,
1966d6b92ffaSHans Petter Selasky 			 size_t attr_size)
1967d6b92ffaSHans Petter Selasky {
1968d6b92ffaSHans Petter Selasky 	struct mlx5_context *mctx = to_mctx(context);
1969d6b92ffaSHans Petter Selasky 	struct mlx5_query_device_ex_resp resp;
1970d6b92ffaSHans Petter Selasky 	struct mlx5_query_device_ex cmd;
1971d6b92ffaSHans Petter Selasky 	struct ibv_device_attr *a;
1972d6b92ffaSHans Petter Selasky 	uint64_t raw_fw_ver;
1973d6b92ffaSHans Petter Selasky 	unsigned sub_minor;
1974d6b92ffaSHans Petter Selasky 	unsigned major;
1975d6b92ffaSHans Petter Selasky 	unsigned minor;
1976d6b92ffaSHans Petter Selasky 	int err;
1977d6b92ffaSHans Petter Selasky 	int cmd_supp_uhw = mctx->cmds_supp_uhw &
1978d6b92ffaSHans Petter Selasky 		MLX5_USER_CMDS_SUPP_UHW_QUERY_DEVICE;
1979d6b92ffaSHans Petter Selasky 
1980d6b92ffaSHans Petter Selasky 	memset(&cmd, 0, sizeof(cmd));
1981d6b92ffaSHans Petter Selasky 	memset(&resp, 0, sizeof(resp));
1982d6b92ffaSHans Petter Selasky 	err = ibv_cmd_query_device_ex(context, input, attr, attr_size,
1983d6b92ffaSHans Petter Selasky 				      &raw_fw_ver,
1984d6b92ffaSHans Petter Selasky 				      &cmd.ibv_cmd, sizeof(cmd.ibv_cmd), sizeof(cmd),
1985d6b92ffaSHans Petter Selasky 				      &resp.ibv_resp, sizeof(resp.ibv_resp),
1986d6b92ffaSHans Petter Selasky 				      cmd_supp_uhw ? sizeof(resp) : sizeof(resp.ibv_resp));
1987d6b92ffaSHans Petter Selasky 	if (err)
1988d6b92ffaSHans Petter Selasky 		return err;
1989d6b92ffaSHans Petter Selasky 
1990d6b92ffaSHans Petter Selasky 	attr->tso_caps = resp.tso_caps;
1991d6b92ffaSHans Petter Selasky 	attr->rss_caps.rx_hash_fields_mask = resp.rss_caps.rx_hash_fields_mask;
1992d6b92ffaSHans Petter Selasky 	attr->rss_caps.rx_hash_function = resp.rss_caps.rx_hash_function;
1993d6b92ffaSHans Petter Selasky 	attr->packet_pacing_caps = resp.packet_pacing_caps.caps;
1994d6b92ffaSHans Petter Selasky 
1995d6b92ffaSHans Petter Selasky 	if (resp.support_multi_pkt_send_wqe)
1996d6b92ffaSHans Petter Selasky 		mctx->vendor_cap_flags |= MLX5_VENDOR_CAP_FLAGS_MPW;
1997d6b92ffaSHans Petter Selasky 
1998d6b92ffaSHans Petter Selasky 	mctx->cqe_comp_caps = resp.cqe_comp_caps;
1999d6b92ffaSHans Petter Selasky 
2000d6b92ffaSHans Petter Selasky 	major     = (raw_fw_ver >> 32) & 0xffff;
2001d6b92ffaSHans Petter Selasky 	minor     = (raw_fw_ver >> 16) & 0xffff;
2002d6b92ffaSHans Petter Selasky 	sub_minor = raw_fw_ver & 0xffff;
2003d6b92ffaSHans Petter Selasky 	a = &attr->orig_attr;
2004d6b92ffaSHans Petter Selasky 	snprintf(a->fw_ver, sizeof(a->fw_ver), "%d.%d.%04d",
2005d6b92ffaSHans Petter Selasky 		 major, minor, sub_minor);
2006d6b92ffaSHans Petter Selasky 
2007d6b92ffaSHans Petter Selasky 	return 0;
2008d6b92ffaSHans Petter Selasky }
2009d6b92ffaSHans Petter Selasky 
2010d6b92ffaSHans Petter Selasky static int rwq_sig_enabled(struct ibv_context *context)
2011d6b92ffaSHans Petter Selasky {
2012d6b92ffaSHans Petter Selasky 	char *env;
2013d6b92ffaSHans Petter Selasky 
2014d6b92ffaSHans Petter Selasky 	env = getenv("MLX5_RWQ_SIGNATURE");
2015d6b92ffaSHans Petter Selasky 	if (env)
2016d6b92ffaSHans Petter Selasky 		return 1;
2017d6b92ffaSHans Petter Selasky 
2018d6b92ffaSHans Petter Selasky 	return 0;
2019d6b92ffaSHans Petter Selasky }
2020d6b92ffaSHans Petter Selasky 
2021d6b92ffaSHans Petter Selasky static void mlx5_free_rwq_buf(struct mlx5_rwq *rwq, struct ibv_context *context)
2022d6b92ffaSHans Petter Selasky {
2023d6b92ffaSHans Petter Selasky 	struct mlx5_context *ctx = to_mctx(context);
2024d6b92ffaSHans Petter Selasky 
2025d6b92ffaSHans Petter Selasky 	mlx5_free_actual_buf(ctx, &rwq->buf);
2026d6b92ffaSHans Petter Selasky 	free(rwq->rq.wrid);
2027d6b92ffaSHans Petter Selasky }
2028d6b92ffaSHans Petter Selasky 
2029d6b92ffaSHans Petter Selasky static int mlx5_alloc_rwq_buf(struct ibv_context *context,
2030d6b92ffaSHans Petter Selasky 			      struct mlx5_rwq *rwq,
2031d6b92ffaSHans Petter Selasky 			      int size)
2032d6b92ffaSHans Petter Selasky {
2033d6b92ffaSHans Petter Selasky 	int err;
2034d6b92ffaSHans Petter Selasky 	enum mlx5_alloc_type default_alloc_type = MLX5_ALLOC_TYPE_PREFER_CONTIG;
2035d6b92ffaSHans Petter Selasky 
2036d6b92ffaSHans Petter Selasky 	rwq->rq.wrid = malloc(rwq->rq.wqe_cnt * sizeof(uint64_t));
2037d6b92ffaSHans Petter Selasky 	if (!rwq->rq.wrid) {
2038d6b92ffaSHans Petter Selasky 		errno = ENOMEM;
2039d6b92ffaSHans Petter Selasky 		return -1;
2040d6b92ffaSHans Petter Selasky 	}
2041d6b92ffaSHans Petter Selasky 
2042d6b92ffaSHans Petter Selasky 	err = mlx5_alloc_prefered_buf(to_mctx(context), &rwq->buf,
2043d6b92ffaSHans Petter Selasky 				      align(rwq->buf_size, to_mdev
2044d6b92ffaSHans Petter Selasky 				      (context->device)->page_size),
2045d6b92ffaSHans Petter Selasky 				      to_mdev(context->device)->page_size,
2046d6b92ffaSHans Petter Selasky 				      default_alloc_type,
2047d6b92ffaSHans Petter Selasky 				      MLX5_RWQ_PREFIX);
2048d6b92ffaSHans Petter Selasky 
2049d6b92ffaSHans Petter Selasky 	if (err) {
2050d6b92ffaSHans Petter Selasky 		free(rwq->rq.wrid);
2051d6b92ffaSHans Petter Selasky 		errno = ENOMEM;
2052d6b92ffaSHans Petter Selasky 		return -1;
2053d6b92ffaSHans Petter Selasky 	}
2054d6b92ffaSHans Petter Selasky 
2055d6b92ffaSHans Petter Selasky 	return 0;
2056d6b92ffaSHans Petter Selasky }
2057d6b92ffaSHans Petter Selasky 
2058d6b92ffaSHans Petter Selasky struct ibv_wq *mlx5_create_wq(struct ibv_context *context,
2059d6b92ffaSHans Petter Selasky 			      struct ibv_wq_init_attr *attr)
2060d6b92ffaSHans Petter Selasky {
2061d6b92ffaSHans Petter Selasky 	struct mlx5_create_wq		cmd;
2062d6b92ffaSHans Petter Selasky 	struct mlx5_create_wq_resp		resp;
2063d6b92ffaSHans Petter Selasky 	int				err;
2064d6b92ffaSHans Petter Selasky 	struct mlx5_rwq			*rwq;
2065d6b92ffaSHans Petter Selasky 	struct mlx5_context	*ctx = to_mctx(context);
2066d6b92ffaSHans Petter Selasky 	int ret;
2067d6b92ffaSHans Petter Selasky 	int32_t				usr_idx = 0;
2068d6b92ffaSHans Petter Selasky 	FILE *fp = ctx->dbg_fp;
2069d6b92ffaSHans Petter Selasky 
2070d6b92ffaSHans Petter Selasky 	if (attr->wq_type != IBV_WQT_RQ)
2071d6b92ffaSHans Petter Selasky 		return NULL;
2072d6b92ffaSHans Petter Selasky 
2073d6b92ffaSHans Petter Selasky 	memset(&cmd, 0, sizeof(cmd));
2074d6b92ffaSHans Petter Selasky 	memset(&resp, 0, sizeof(resp));
2075d6b92ffaSHans Petter Selasky 
2076d6b92ffaSHans Petter Selasky 	rwq = calloc(1, sizeof(*rwq));
2077d6b92ffaSHans Petter Selasky 	if (!rwq)
2078d6b92ffaSHans Petter Selasky 		return NULL;
2079d6b92ffaSHans Petter Selasky 
2080*25ef056fSKa Ho Ng 	ret = ibv_init_wq(&rwq->wq);
2081*25ef056fSKa Ho Ng 	if (ret < 0)
2082*25ef056fSKa Ho Ng 		goto err;
2083*25ef056fSKa Ho Ng 
2084d6b92ffaSHans Petter Selasky 	rwq->wq_sig = rwq_sig_enabled(context);
2085d6b92ffaSHans Petter Selasky 	if (rwq->wq_sig)
2086d6b92ffaSHans Petter Selasky 		cmd.drv.flags = MLX5_RWQ_FLAG_SIGNATURE;
2087d6b92ffaSHans Petter Selasky 
2088d6b92ffaSHans Petter Selasky 	ret = mlx5_calc_rwq_size(ctx, rwq, attr);
2089d6b92ffaSHans Petter Selasky 	if (ret < 0) {
2090d6b92ffaSHans Petter Selasky 		errno = -ret;
2091*25ef056fSKa Ho Ng 		goto err_cleanup_wq;
2092d6b92ffaSHans Petter Selasky 	}
2093d6b92ffaSHans Petter Selasky 
2094d6b92ffaSHans Petter Selasky 	rwq->buf_size = ret;
2095d6b92ffaSHans Petter Selasky 	if (mlx5_alloc_rwq_buf(context, rwq, ret))
2096a687910fSSean Lim 		goto err_cleanup_wq;
2097d6b92ffaSHans Petter Selasky 
2098d6b92ffaSHans Petter Selasky 	mlx5_init_rwq_indices(rwq);
2099d6b92ffaSHans Petter Selasky 
2100d6b92ffaSHans Petter Selasky 	if (mlx5_spinlock_init(&rwq->rq.lock))
2101d6b92ffaSHans Petter Selasky 		goto err_free_rwq_buf;
2102d6b92ffaSHans Petter Selasky 
2103d6b92ffaSHans Petter Selasky 	rwq->db = mlx5_alloc_dbrec(ctx);
2104d6b92ffaSHans Petter Selasky 	if (!rwq->db)
2105a687910fSSean Lim 		goto err_spl;
2106d6b92ffaSHans Petter Selasky 
2107d6b92ffaSHans Petter Selasky 	rwq->db[MLX5_RCV_DBR] = 0;
2108d6b92ffaSHans Petter Selasky 	rwq->db[MLX5_SND_DBR] = 0;
2109d6b92ffaSHans Petter Selasky 	rwq->pbuff = rwq->buf.buf + rwq->rq.offset;
2110d6b92ffaSHans Petter Selasky 	rwq->recv_db =  &rwq->db[MLX5_RCV_DBR];
2111d6b92ffaSHans Petter Selasky 	cmd.drv.buf_addr = (uintptr_t)rwq->buf.buf;
2112d6b92ffaSHans Petter Selasky 	cmd.drv.db_addr  = (uintptr_t)rwq->db;
2113d6b92ffaSHans Petter Selasky 	cmd.drv.rq_wqe_count = rwq->rq.wqe_cnt;
2114d6b92ffaSHans Petter Selasky 	cmd.drv.rq_wqe_shift = rwq->rq.wqe_shift;
2115d6b92ffaSHans Petter Selasky 	usr_idx = mlx5_store_uidx(ctx, rwq);
2116d6b92ffaSHans Petter Selasky 	if (usr_idx < 0) {
2117d6b92ffaSHans Petter Selasky 		mlx5_dbg(fp, MLX5_DBG_QP, "Couldn't find free user index\n");
2118d6b92ffaSHans Petter Selasky 		goto err_free_db_rec;
2119d6b92ffaSHans Petter Selasky 	}
2120d6b92ffaSHans Petter Selasky 
2121d6b92ffaSHans Petter Selasky 	cmd.drv.user_index = usr_idx;
2122d6b92ffaSHans Petter Selasky 	err = ibv_cmd_create_wq(context, attr, &rwq->wq, &cmd.ibv_cmd,
2123d6b92ffaSHans Petter Selasky 				sizeof(cmd.ibv_cmd),
2124d6b92ffaSHans Petter Selasky 				sizeof(cmd),
2125d6b92ffaSHans Petter Selasky 				&resp.ibv_resp, sizeof(resp.ibv_resp),
2126d6b92ffaSHans Petter Selasky 				sizeof(resp));
2127d6b92ffaSHans Petter Selasky 	if (err)
2128d6b92ffaSHans Petter Selasky 		goto err_create;
2129d6b92ffaSHans Petter Selasky 
2130d6b92ffaSHans Petter Selasky 	rwq->rsc.type = MLX5_RSC_TYPE_RWQ;
2131d6b92ffaSHans Petter Selasky 	rwq->rsc.rsn =  cmd.drv.user_index;
2132d6b92ffaSHans Petter Selasky 
2133d6b92ffaSHans Petter Selasky 	rwq->wq.post_recv = mlx5_post_wq_recv;
2134d6b92ffaSHans Petter Selasky 	return &rwq->wq;
2135d6b92ffaSHans Petter Selasky 
2136d6b92ffaSHans Petter Selasky err_create:
2137d6b92ffaSHans Petter Selasky 	mlx5_clear_uidx(ctx, cmd.drv.user_index);
2138d6b92ffaSHans Petter Selasky err_free_db_rec:
2139d6b92ffaSHans Petter Selasky 	mlx5_free_db(to_mctx(context), rwq->db);
2140a687910fSSean Lim err_spl:
2141a687910fSSean Lim 	mlx5_spinlock_destroy(&rwq->rq.lock);
2142d6b92ffaSHans Petter Selasky err_free_rwq_buf:
2143d6b92ffaSHans Petter Selasky 	mlx5_free_rwq_buf(rwq, context);
2144a687910fSSean Lim err_cleanup_wq:
2145a687910fSSean Lim 	ibv_cleanup_wq(&rwq->wq);
2146d6b92ffaSHans Petter Selasky err:
2147d6b92ffaSHans Petter Selasky 	free(rwq);
2148d6b92ffaSHans Petter Selasky 	return NULL;
2149d6b92ffaSHans Petter Selasky }
2150d6b92ffaSHans Petter Selasky 
2151d6b92ffaSHans Petter Selasky int mlx5_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *attr)
2152d6b92ffaSHans Petter Selasky {
2153d6b92ffaSHans Petter Selasky 	struct mlx5_modify_wq	cmd = {};
2154d6b92ffaSHans Petter Selasky 	struct mlx5_rwq *rwq = to_mrwq(wq);
2155d6b92ffaSHans Petter Selasky 
2156d6b92ffaSHans Petter Selasky 	if ((attr->attr_mask & IBV_WQ_ATTR_STATE) &&
2157d6b92ffaSHans Petter Selasky 	    attr->wq_state == IBV_WQS_RDY) {
2158d6b92ffaSHans Petter Selasky 		if ((attr->attr_mask & IBV_WQ_ATTR_CURR_STATE) &&
2159d6b92ffaSHans Petter Selasky 		    attr->curr_wq_state != wq->state)
2160d6b92ffaSHans Petter Selasky 			return -EINVAL;
2161d6b92ffaSHans Petter Selasky 
2162d6b92ffaSHans Petter Selasky 		if (wq->state == IBV_WQS_RESET) {
2163d6b92ffaSHans Petter Selasky 			mlx5_spin_lock(&to_mcq(wq->cq)->lock);
2164d6b92ffaSHans Petter Selasky 			__mlx5_cq_clean(to_mcq(wq->cq),
2165d6b92ffaSHans Petter Selasky 					rwq->rsc.rsn, NULL);
2166d6b92ffaSHans Petter Selasky 			mlx5_spin_unlock(&to_mcq(wq->cq)->lock);
2167d6b92ffaSHans Petter Selasky 			mlx5_init_rwq_indices(rwq);
2168d6b92ffaSHans Petter Selasky 			rwq->db[MLX5_RCV_DBR] = 0;
2169d6b92ffaSHans Petter Selasky 			rwq->db[MLX5_SND_DBR] = 0;
2170d6b92ffaSHans Petter Selasky 		}
2171d6b92ffaSHans Petter Selasky 	}
2172d6b92ffaSHans Petter Selasky 
2173d6b92ffaSHans Petter Selasky 	return ibv_cmd_modify_wq(wq, attr, &cmd.ibv_cmd,  sizeof(cmd.ibv_cmd), sizeof(cmd));
2174d6b92ffaSHans Petter Selasky }
2175d6b92ffaSHans Petter Selasky 
2176d6b92ffaSHans Petter Selasky int mlx5_destroy_wq(struct ibv_wq *wq)
2177d6b92ffaSHans Petter Selasky {
2178d6b92ffaSHans Petter Selasky 	struct mlx5_rwq *rwq = to_mrwq(wq);
2179d6b92ffaSHans Petter Selasky 	int ret;
2180d6b92ffaSHans Petter Selasky 
2181d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_destroy_wq(wq);
2182d6b92ffaSHans Petter Selasky 	if (ret)
2183d6b92ffaSHans Petter Selasky 		return ret;
2184d6b92ffaSHans Petter Selasky 
2185d6b92ffaSHans Petter Selasky 	mlx5_spin_lock(&to_mcq(wq->cq)->lock);
2186d6b92ffaSHans Petter Selasky 	__mlx5_cq_clean(to_mcq(wq->cq), rwq->rsc.rsn, NULL);
2187d6b92ffaSHans Petter Selasky 	mlx5_spin_unlock(&to_mcq(wq->cq)->lock);
2188d6b92ffaSHans Petter Selasky 	mlx5_clear_uidx(to_mctx(wq->context), rwq->rsc.rsn);
2189d6b92ffaSHans Petter Selasky 	mlx5_free_db(to_mctx(wq->context), rwq->db);
2190a687910fSSean Lim 	mlx5_spinlock_destroy(&rwq->rq.lock);
2191d6b92ffaSHans Petter Selasky 	mlx5_free_rwq_buf(rwq, wq->context);
2192a687910fSSean Lim 	ibv_cleanup_wq(&rwq->wq);
2193d6b92ffaSHans Petter Selasky 	free(rwq);
2194d6b92ffaSHans Petter Selasky 
2195d6b92ffaSHans Petter Selasky 	return 0;
2196d6b92ffaSHans Petter Selasky }
2197d6b92ffaSHans Petter Selasky 
2198d6b92ffaSHans Petter Selasky struct ibv_rwq_ind_table *mlx5_create_rwq_ind_table(struct ibv_context *context,
2199d6b92ffaSHans Petter Selasky 						    struct ibv_rwq_ind_table_init_attr *init_attr)
2200d6b92ffaSHans Petter Selasky {
2201d6b92ffaSHans Petter Selasky 	struct ibv_create_rwq_ind_table *cmd;
2202d6b92ffaSHans Petter Selasky 	struct mlx5_create_rwq_ind_table_resp resp;
2203d6b92ffaSHans Petter Selasky 	struct ibv_rwq_ind_table *ind_table;
2204d6b92ffaSHans Petter Selasky 	uint32_t required_tbl_size;
2205d6b92ffaSHans Petter Selasky 	int num_tbl_entries;
2206d6b92ffaSHans Petter Selasky 	int cmd_size;
2207d6b92ffaSHans Petter Selasky 	int err;
2208d6b92ffaSHans Petter Selasky 
2209d6b92ffaSHans Petter Selasky 	num_tbl_entries = 1 << init_attr->log_ind_tbl_size;
2210d6b92ffaSHans Petter Selasky 	/* Data must be u64 aligned */
2211d6b92ffaSHans Petter Selasky 	required_tbl_size = (num_tbl_entries * sizeof(uint32_t)) < sizeof(uint64_t) ?
2212d6b92ffaSHans Petter Selasky 			sizeof(uint64_t) : (num_tbl_entries * sizeof(uint32_t));
2213d6b92ffaSHans Petter Selasky 
2214d6b92ffaSHans Petter Selasky 	cmd_size = required_tbl_size + sizeof(*cmd);
2215d6b92ffaSHans Petter Selasky 	cmd = calloc(1, cmd_size);
2216d6b92ffaSHans Petter Selasky 	if (!cmd)
2217d6b92ffaSHans Petter Selasky 		return NULL;
2218d6b92ffaSHans Petter Selasky 
2219d6b92ffaSHans Petter Selasky 	memset(&resp, 0, sizeof(resp));
2220d6b92ffaSHans Petter Selasky 	ind_table = calloc(1, sizeof(*ind_table));
2221d6b92ffaSHans Petter Selasky 	if (!ind_table)
2222d6b92ffaSHans Petter Selasky 		goto free_cmd;
2223d6b92ffaSHans Petter Selasky 
2224d6b92ffaSHans Petter Selasky 	err = ibv_cmd_create_rwq_ind_table(context, init_attr, ind_table, cmd,
2225d6b92ffaSHans Petter Selasky 					   cmd_size, cmd_size, &resp.ibv_resp, sizeof(resp.ibv_resp),
2226d6b92ffaSHans Petter Selasky 					   sizeof(resp));
2227d6b92ffaSHans Petter Selasky 	if (err)
2228d6b92ffaSHans Petter Selasky 		goto err;
2229d6b92ffaSHans Petter Selasky 
2230d6b92ffaSHans Petter Selasky 	free(cmd);
2231d6b92ffaSHans Petter Selasky 	return ind_table;
2232d6b92ffaSHans Petter Selasky 
2233d6b92ffaSHans Petter Selasky err:
2234d6b92ffaSHans Petter Selasky 	free(ind_table);
2235d6b92ffaSHans Petter Selasky free_cmd:
2236d6b92ffaSHans Petter Selasky 	free(cmd);
2237d6b92ffaSHans Petter Selasky 	return NULL;
2238d6b92ffaSHans Petter Selasky }
2239d6b92ffaSHans Petter Selasky 
2240d6b92ffaSHans Petter Selasky int mlx5_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table)
2241d6b92ffaSHans Petter Selasky {
2242d6b92ffaSHans Petter Selasky 	int ret;
2243d6b92ffaSHans Petter Selasky 
2244d6b92ffaSHans Petter Selasky 	ret = ibv_cmd_destroy_rwq_ind_table(rwq_ind_table);
2245d6b92ffaSHans Petter Selasky 
2246d6b92ffaSHans Petter Selasky 	if (ret)
2247d6b92ffaSHans Petter Selasky 		return ret;
2248d6b92ffaSHans Petter Selasky 
2249d6b92ffaSHans Petter Selasky 	free(rwq_ind_table);
2250d6b92ffaSHans Petter Selasky 	return 0;
2251d6b92ffaSHans Petter Selasky }
2252