1 /*-
2 * Copyright (c) 2013-2015, Mellanox Technologies, Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD: stable/10/sys/dev/mlx5/mlx5_core/mlx5_qp.c 306244 2016-09-23 08:28:44Z hselasky $
26 */
27
28
29 #include <linux/gfp.h>
30 #include <dev/mlx5/qp.h>
31 #include <dev/mlx5/driver.h>
32
33 #include "mlx5_core.h"
34
35 #include "transobj.h"
36
mlx5_get_rsc(struct mlx5_core_dev * dev,u32 rsn)37 static struct mlx5_core_rsc_common *mlx5_get_rsc(struct mlx5_core_dev *dev,
38 u32 rsn)
39 {
40 struct mlx5_qp_table *table = &dev->priv.qp_table;
41 struct mlx5_core_rsc_common *common;
42
43 spin_lock(&table->lock);
44
45 common = radix_tree_lookup(&table->tree, rsn);
46 if (common)
47 atomic_inc(&common->refcount);
48
49 spin_unlock(&table->lock);
50
51 if (!common) {
52 mlx5_core_warn(dev, "Async event for bogus resource 0x%x\n",
53 rsn);
54 return NULL;
55 }
56 return common;
57 }
58
mlx5_core_put_rsc(struct mlx5_core_rsc_common * common)59 void mlx5_core_put_rsc(struct mlx5_core_rsc_common *common)
60 {
61 if (atomic_dec_and_test(&common->refcount))
62 complete(&common->free);
63 }
64
mlx5_rsc_event(struct mlx5_core_dev * dev,u32 rsn,int event_type)65 void mlx5_rsc_event(struct mlx5_core_dev *dev, u32 rsn, int event_type)
66 {
67 struct mlx5_core_rsc_common *common = mlx5_get_rsc(dev, rsn);
68 struct mlx5_core_qp *qp;
69
70 if (!common)
71 return;
72
73 switch (common->res) {
74 case MLX5_RES_QP:
75 qp = (struct mlx5_core_qp *)common;
76 qp->event(qp, event_type);
77 break;
78
79 default:
80 mlx5_core_warn(dev, "invalid resource type for 0x%x\n", rsn);
81 }
82
83 mlx5_core_put_rsc(common);
84 }
85
create_qprqsq_common(struct mlx5_core_dev * dev,struct mlx5_core_qp * qp,int rsc_type)86 static int create_qprqsq_common(struct mlx5_core_dev *dev,
87 struct mlx5_core_qp *qp, int rsc_type)
88 {
89 struct mlx5_qp_table *table = &dev->priv.qp_table;
90 int err;
91
92 qp->common.res = rsc_type;
93
94 spin_lock_irq(&table->lock);
95 err = radix_tree_insert(&table->tree, qp->qpn | (rsc_type << 24), qp);
96 spin_unlock_irq(&table->lock);
97 if (err)
98 return err;
99
100 atomic_set(&qp->common.refcount, 1);
101 init_completion(&qp->common.free);
102 qp->pid = curthread->td_proc->p_pid;
103
104 return 0;
105 }
106
destroy_qprqsq_common(struct mlx5_core_dev * dev,struct mlx5_core_qp * qp,int rsc_type)107 static void destroy_qprqsq_common(struct mlx5_core_dev *dev,
108 struct mlx5_core_qp *qp, int rsc_type)
109 {
110 struct mlx5_qp_table *table = &dev->priv.qp_table;
111 unsigned long flags;
112
113 spin_lock_irqsave(&table->lock, flags);
114 radix_tree_delete(&table->tree, qp->qpn | (rsc_type << 24));
115 spin_unlock_irqrestore(&table->lock, flags);
116
117 mlx5_core_put_rsc((struct mlx5_core_rsc_common *)qp);
118 wait_for_completion(&qp->common.free);
119 }
120
mlx5_core_create_qp(struct mlx5_core_dev * dev,struct mlx5_core_qp * qp,struct mlx5_create_qp_mbox_in * in,int inlen)121 int mlx5_core_create_qp(struct mlx5_core_dev *dev,
122 struct mlx5_core_qp *qp,
123 struct mlx5_create_qp_mbox_in *in,
124 int inlen)
125 {
126 struct mlx5_create_qp_mbox_out out;
127 struct mlx5_destroy_qp_mbox_in din;
128 struct mlx5_destroy_qp_mbox_out dout;
129 int err;
130
131 memset(&out, 0, sizeof(out));
132 in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_QP);
133
134 err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
135 if (err) {
136 mlx5_core_warn(dev, "ret %d\n", err);
137 return err;
138 }
139
140 if (out.hdr.status) {
141 mlx5_core_warn(dev, "current num of QPs 0x%x\n",
142 atomic_read(&dev->num_qps));
143 return mlx5_cmd_status_to_err(&out.hdr);
144 }
145
146 qp->qpn = be32_to_cpu(out.qpn) & 0xffffff;
147 mlx5_core_dbg(dev, "qpn = 0x%x\n", qp->qpn);
148
149 err = create_qprqsq_common(dev, qp, MLX5_RES_QP);
150 if (err)
151 goto err_cmd;
152
153 atomic_inc(&dev->num_qps);
154
155 return 0;
156
157 err_cmd:
158 memset(&din, 0, sizeof(din));
159 memset(&dout, 0, sizeof(dout));
160 din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_QP);
161 din.qpn = cpu_to_be32(qp->qpn);
162 mlx5_cmd_exec(dev, &din, sizeof(din), &out, sizeof(dout));
163
164 return err;
165 }
166 EXPORT_SYMBOL_GPL(mlx5_core_create_qp);
167
mlx5_core_destroy_qp(struct mlx5_core_dev * dev,struct mlx5_core_qp * qp)168 int mlx5_core_destroy_qp(struct mlx5_core_dev *dev,
169 struct mlx5_core_qp *qp)
170 {
171 struct mlx5_destroy_qp_mbox_in in;
172 struct mlx5_destroy_qp_mbox_out out;
173 int err;
174
175
176 destroy_qprqsq_common(dev, qp, MLX5_RES_QP);
177
178 memset(&in, 0, sizeof(in));
179 memset(&out, 0, sizeof(out));
180 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_QP);
181 in.qpn = cpu_to_be32(qp->qpn);
182 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
183 if (err)
184 return err;
185
186 if (out.hdr.status)
187 return mlx5_cmd_status_to_err(&out.hdr);
188
189 atomic_dec(&dev->num_qps);
190 return 0;
191 }
192 EXPORT_SYMBOL_GPL(mlx5_core_destroy_qp);
193
mlx5_core_qp_modify(struct mlx5_core_dev * dev,u16 operation,struct mlx5_modify_qp_mbox_in * in,int sqd_event,struct mlx5_core_qp * qp)194 int mlx5_core_qp_modify(struct mlx5_core_dev *dev, u16 operation,
195 struct mlx5_modify_qp_mbox_in *in, int sqd_event,
196 struct mlx5_core_qp *qp)
197 {
198 struct mlx5_modify_qp_mbox_out out;
199 int err = 0;
200
201 memset(&out, 0, sizeof(out));
202 in->hdr.opcode = cpu_to_be16(operation);
203 in->qpn = cpu_to_be32(qp->qpn);
204 err = mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out));
205 if (err)
206 return err;
207
208 return mlx5_cmd_status_to_err(&out.hdr);
209 }
210 EXPORT_SYMBOL_GPL(mlx5_core_qp_modify);
211
mlx5_init_qp_table(struct mlx5_core_dev * dev)212 void mlx5_init_qp_table(struct mlx5_core_dev *dev)
213 {
214 struct mlx5_qp_table *table = &dev->priv.qp_table;
215
216 spin_lock_init(&table->lock);
217 INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
218 }
219
mlx5_cleanup_qp_table(struct mlx5_core_dev * dev)220 void mlx5_cleanup_qp_table(struct mlx5_core_dev *dev)
221 {
222 }
223
mlx5_core_qp_query(struct mlx5_core_dev * dev,struct mlx5_core_qp * qp,struct mlx5_query_qp_mbox_out * out,int outlen)224 int mlx5_core_qp_query(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
225 struct mlx5_query_qp_mbox_out *out, int outlen)
226 {
227 struct mlx5_query_qp_mbox_in in;
228 int err;
229
230 memset(&in, 0, sizeof(in));
231 memset(out, 0, outlen);
232 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_QP);
233 in.qpn = cpu_to_be32(qp->qpn);
234 err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
235 if (err)
236 return err;
237
238 if (out->hdr.status)
239 return mlx5_cmd_status_to_err(&out->hdr);
240
241 return err;
242 }
243 EXPORT_SYMBOL_GPL(mlx5_core_qp_query);
244
mlx5_core_xrcd_alloc(struct mlx5_core_dev * dev,u32 * xrcdn)245 int mlx5_core_xrcd_alloc(struct mlx5_core_dev *dev, u32 *xrcdn)
246 {
247 u32 in[MLX5_ST_SZ_DW(alloc_xrcd_in)];
248 u32 out[MLX5_ST_SZ_DW(alloc_xrcd_out)];
249 int err;
250
251 memset(in, 0, sizeof(in));
252
253 MLX5_SET(alloc_xrcd_in, in, opcode, MLX5_CMD_OP_ALLOC_XRCD);
254
255 memset(out, 0, sizeof(out));
256 err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
257 if (err)
258 return err;
259
260 *xrcdn = MLX5_GET(alloc_xrcd_out, out, xrcd);
261 return 0;
262 }
263 EXPORT_SYMBOL_GPL(mlx5_core_xrcd_alloc);
264
mlx5_core_xrcd_dealloc(struct mlx5_core_dev * dev,u32 xrcdn)265 int mlx5_core_xrcd_dealloc(struct mlx5_core_dev *dev, u32 xrcdn)
266 {
267 u32 in[MLX5_ST_SZ_DW(dealloc_xrcd_in)];
268 u32 out[MLX5_ST_SZ_DW(dealloc_xrcd_out)];
269
270 memset(in, 0, sizeof(in));
271
272 MLX5_SET(dealloc_xrcd_in, in, opcode, MLX5_CMD_OP_DEALLOC_XRCD);
273 MLX5_SET(dealloc_xrcd_in, in, xrcd, xrcdn);
274
275 memset(out, 0, sizeof(out));
276 return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
277 out, sizeof(out));
278 }
279 EXPORT_SYMBOL_GPL(mlx5_core_xrcd_dealloc);
280
mlx5_core_create_dct(struct mlx5_core_dev * dev,struct mlx5_core_dct * dct,struct mlx5_create_dct_mbox_in * in)281 int mlx5_core_create_dct(struct mlx5_core_dev *dev,
282 struct mlx5_core_dct *dct,
283 struct mlx5_create_dct_mbox_in *in)
284 {
285 struct mlx5_qp_table *table = &dev->priv.qp_table;
286 struct mlx5_create_dct_mbox_out out;
287 struct mlx5_destroy_dct_mbox_in din;
288 struct mlx5_destroy_dct_mbox_out dout;
289 int err;
290
291 init_completion(&dct->drained);
292 memset(&out, 0, sizeof(out));
293 in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_DCT);
294
295 err = mlx5_cmd_exec(dev, in, sizeof(*in), &out, sizeof(out));
296 if (err) {
297 mlx5_core_warn(dev, "create DCT failed, ret %d", err);
298 return err;
299 }
300
301 if (out.hdr.status)
302 return mlx5_cmd_status_to_err(&out.hdr);
303
304 dct->dctn = be32_to_cpu(out.dctn) & 0xffffff;
305
306 dct->common.res = MLX5_RES_DCT;
307 spin_lock_irq(&table->lock);
308 err = radix_tree_insert(&table->tree, dct->dctn, dct);
309 spin_unlock_irq(&table->lock);
310 if (err) {
311 mlx5_core_warn(dev, "err %d", err);
312 goto err_cmd;
313 }
314
315 dct->pid = curthread->td_proc->p_pid;
316 atomic_set(&dct->common.refcount, 1);
317 init_completion(&dct->common.free);
318
319 return 0;
320
321 err_cmd:
322 memset(&din, 0, sizeof(din));
323 memset(&dout, 0, sizeof(dout));
324 din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_DCT);
325 din.dctn = cpu_to_be32(dct->dctn);
326 mlx5_cmd_exec(dev, &din, sizeof(din), &out, sizeof(dout));
327
328 return err;
329 }
330 EXPORT_SYMBOL_GPL(mlx5_core_create_dct);
331
mlx5_core_drain_dct(struct mlx5_core_dev * dev,struct mlx5_core_dct * dct)332 static int mlx5_core_drain_dct(struct mlx5_core_dev *dev,
333 struct mlx5_core_dct *dct)
334 {
335 struct mlx5_drain_dct_mbox_out out;
336 struct mlx5_drain_dct_mbox_in in;
337 int err;
338
339 memset(&in, 0, sizeof(in));
340 memset(&out, 0, sizeof(out));
341 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DRAIN_DCT);
342 in.dctn = cpu_to_be32(dct->dctn);
343 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
344 if (err)
345 return err;
346
347 if (out.hdr.status)
348 return mlx5_cmd_status_to_err(&out.hdr);
349
350 return 0;
351 }
352
mlx5_core_destroy_dct(struct mlx5_core_dev * dev,struct mlx5_core_dct * dct)353 int mlx5_core_destroy_dct(struct mlx5_core_dev *dev,
354 struct mlx5_core_dct *dct)
355 {
356 struct mlx5_qp_table *table = &dev->priv.qp_table;
357 struct mlx5_destroy_dct_mbox_out out;
358 struct mlx5_destroy_dct_mbox_in in;
359 unsigned long flags;
360 int err;
361
362 err = mlx5_core_drain_dct(dev, dct);
363 if (err) {
364 mlx5_core_warn(dev, "failed drain DCT 0x%x\n", dct->dctn);
365 return err;
366 }
367
368 wait_for_completion(&dct->drained);
369
370 spin_lock_irqsave(&table->lock, flags);
371 if (radix_tree_delete(&table->tree, dct->dctn) != dct)
372 mlx5_core_warn(dev, "dct delete differs\n");
373 spin_unlock_irqrestore(&table->lock, flags);
374
375 if (atomic_dec_and_test(&dct->common.refcount))
376 complete(&dct->common.free);
377 wait_for_completion(&dct->common.free);
378
379 memset(&in, 0, sizeof(in));
380 memset(&out, 0, sizeof(out));
381 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_DCT);
382 in.dctn = cpu_to_be32(dct->dctn);
383 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
384 if (err)
385 return err;
386
387 if (out.hdr.status)
388 return mlx5_cmd_status_to_err(&out.hdr);
389
390 return 0;
391 }
392 EXPORT_SYMBOL_GPL(mlx5_core_destroy_dct);
393
mlx5_core_dct_query(struct mlx5_core_dev * dev,struct mlx5_core_dct * dct,struct mlx5_query_dct_mbox_out * out)394 int mlx5_core_dct_query(struct mlx5_core_dev *dev, struct mlx5_core_dct *dct,
395 struct mlx5_query_dct_mbox_out *out)
396 {
397 struct mlx5_query_dct_mbox_in in;
398 int err;
399
400 memset(&in, 0, sizeof(in));
401 memset(out, 0, sizeof(*out));
402 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_DCT);
403 in.dctn = cpu_to_be32(dct->dctn);
404 err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out));
405 if (err)
406 return err;
407
408 if (out->hdr.status)
409 return mlx5_cmd_status_to_err(&out->hdr);
410
411 return err;
412 }
413 EXPORT_SYMBOL_GPL(mlx5_core_dct_query);
414
mlx5_core_arm_dct(struct mlx5_core_dev * dev,struct mlx5_core_dct * dct)415 int mlx5_core_arm_dct(struct mlx5_core_dev *dev, struct mlx5_core_dct *dct)
416 {
417 struct mlx5_arm_dct_mbox_out out;
418 struct mlx5_arm_dct_mbox_in in;
419 int err;
420
421 memset(&in, 0, sizeof(in));
422 memset(&out, 0, sizeof(out));
423
424 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION);
425 in.dctn = cpu_to_be32(dct->dctn);
426 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
427 if (err)
428 return err;
429
430 if (out.hdr.status)
431 return mlx5_cmd_status_to_err(&out.hdr);
432
433 return err;
434 }
435 EXPORT_SYMBOL_GPL(mlx5_core_arm_dct);
436
mlx5_core_create_rq_tracked(struct mlx5_core_dev * dev,u32 * in,int inlen,struct mlx5_core_qp * rq)437 int mlx5_core_create_rq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen,
438 struct mlx5_core_qp *rq)
439 {
440 int err;
441
442 err = mlx5_core_create_rq(dev, in, inlen, &rq->qpn);
443 if (err)
444 return err;
445
446 err = create_qprqsq_common(dev, rq, MLX5_RES_RQ);
447 if (err)
448 mlx5_core_destroy_rq(dev, rq->qpn);
449
450 return err;
451 }
452 EXPORT_SYMBOL(mlx5_core_create_rq_tracked);
453
mlx5_core_destroy_rq_tracked(struct mlx5_core_dev * dev,struct mlx5_core_qp * rq)454 void mlx5_core_destroy_rq_tracked(struct mlx5_core_dev *dev,
455 struct mlx5_core_qp *rq)
456 {
457 destroy_qprqsq_common(dev, rq, MLX5_RES_RQ);
458 mlx5_core_destroy_rq(dev, rq->qpn);
459 }
460 EXPORT_SYMBOL(mlx5_core_destroy_rq_tracked);
461
mlx5_core_create_sq_tracked(struct mlx5_core_dev * dev,u32 * in,int inlen,struct mlx5_core_qp * sq)462 int mlx5_core_create_sq_tracked(struct mlx5_core_dev *dev, u32 *in, int inlen,
463 struct mlx5_core_qp *sq)
464 {
465 int err;
466
467 err = mlx5_core_create_sq(dev, in, inlen, &sq->qpn);
468 if (err)
469 return err;
470
471 err = create_qprqsq_common(dev, sq, MLX5_RES_SQ);
472 if (err)
473 mlx5_core_destroy_sq(dev, sq->qpn);
474
475 return err;
476 }
477 EXPORT_SYMBOL(mlx5_core_create_sq_tracked);
478
mlx5_core_destroy_sq_tracked(struct mlx5_core_dev * dev,struct mlx5_core_qp * sq)479 void mlx5_core_destroy_sq_tracked(struct mlx5_core_dev *dev,
480 struct mlx5_core_qp *sq)
481 {
482 destroy_qprqsq_common(dev, sq, MLX5_RES_SQ);
483 mlx5_core_destroy_sq(dev, sq->qpn);
484 }
485 EXPORT_SYMBOL(mlx5_core_destroy_sq_tracked);
486