xref: /linux/drivers/infiniband/hw/mlx5/qpc.c (revision fbf5df34a4dbcd09d433dd4f0916bf9b2ddb16de)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /*
3  * Copyright (c) 2013-2020, Mellanox Technologies inc. All rights reserved.
4  */
5 
6 #include <linux/gfp.h>
7 #include <linux/mlx5/qp.h>
8 #include <linux/mlx5/driver.h>
9 #include "mlx5_ib.h"
10 #include "qp.h"
11 
12 static int mlx5_core_drain_dct(struct mlx5_ib_dev *dev,
13 			       struct mlx5_core_dct *dct);
14 
15 static struct mlx5_core_rsc_common *
16 mlx5_get_rsc(struct mlx5_qp_table *table, u32 rsn)
17 {
18 	struct mlx5_core_rsc_common *common;
19 	unsigned long flags;
20 
21 	spin_lock_irqsave(&table->lock, flags);
22 
23 	common = radix_tree_lookup(&table->tree, rsn);
24 	if (common && !common->invalid)
25 		refcount_inc(&common->refcount);
26 	else
27 		common = NULL;
28 
29 	spin_unlock_irqrestore(&table->lock, flags);
30 
31 	return common;
32 }
33 
34 void mlx5_core_put_rsc(struct mlx5_core_rsc_common *common)
35 {
36 	if (refcount_dec_and_test(&common->refcount))
37 		complete(&common->free);
38 }
39 
40 static u64 qp_allowed_event_types(void)
41 {
42 	u64 mask;
43 
44 	mask = BIT(MLX5_EVENT_TYPE_PATH_MIG) |
45 	       BIT(MLX5_EVENT_TYPE_COMM_EST) |
46 	       BIT(MLX5_EVENT_TYPE_SQ_DRAINED) |
47 	       BIT(MLX5_EVENT_TYPE_SRQ_LAST_WQE) |
48 	       BIT(MLX5_EVENT_TYPE_WQ_CATAS_ERROR) |
49 	       BIT(MLX5_EVENT_TYPE_PATH_MIG_FAILED) |
50 	       BIT(MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR) |
51 	       BIT(MLX5_EVENT_TYPE_WQ_ACCESS_ERROR);
52 
53 	return mask;
54 }
55 
56 static u64 rq_allowed_event_types(void)
57 {
58 	u64 mask;
59 
60 	mask = BIT(MLX5_EVENT_TYPE_SRQ_LAST_WQE) |
61 	       BIT(MLX5_EVENT_TYPE_WQ_CATAS_ERROR);
62 
63 	return mask;
64 }
65 
66 static u64 sq_allowed_event_types(void)
67 {
68 	return BIT(MLX5_EVENT_TYPE_WQ_CATAS_ERROR);
69 }
70 
71 static u64 dct_allowed_event_types(void)
72 {
73 	return BIT(MLX5_EVENT_TYPE_DCT_DRAINED);
74 }
75 
76 static bool is_event_type_allowed(int rsc_type, int event_type)
77 {
78 	switch (rsc_type) {
79 	case MLX5_EVENT_QUEUE_TYPE_QP:
80 		return BIT(event_type) & qp_allowed_event_types();
81 	case MLX5_EVENT_QUEUE_TYPE_RQ:
82 		return BIT(event_type) & rq_allowed_event_types();
83 	case MLX5_EVENT_QUEUE_TYPE_SQ:
84 		return BIT(event_type) & sq_allowed_event_types();
85 	case MLX5_EVENT_QUEUE_TYPE_DCT:
86 		return BIT(event_type) & dct_allowed_event_types();
87 	default:
88 		WARN(1, "Event arrived for unknown resource type");
89 		return false;
90 	}
91 }
92 
93 static int dct_event_notifier(struct mlx5_ib_dev *dev, struct mlx5_eqe *eqe)
94 {
95 	struct mlx5_core_dct *dct;
96 	unsigned long flags;
97 	u32 qpn;
98 
99 	qpn = be32_to_cpu(eqe->data.dct.dctn) & 0xFFFFFF;
100 	xa_lock_irqsave(&dev->qp_table.dct_xa, flags);
101 	dct = xa_load(&dev->qp_table.dct_xa, qpn);
102 	if (dct)
103 		complete(&dct->drained);
104 	xa_unlock_irqrestore(&dev->qp_table.dct_xa, flags);
105 	return NOTIFY_OK;
106 }
107 
108 static int rsc_event_notifier(struct notifier_block *nb,
109 			      unsigned long type, void *data)
110 {
111 	struct mlx5_ib_dev *dev =
112 		container_of(nb, struct mlx5_ib_dev, qp_table.nb);
113 	struct mlx5_core_rsc_common *common;
114 	struct mlx5_eqe *eqe = data;
115 	u8 event_type = (u8)type;
116 	struct mlx5_core_qp *qp;
117 	u32 rsn;
118 
119 	switch (event_type) {
120 	case MLX5_EVENT_TYPE_DCT_DRAINED:
121 		return dct_event_notifier(dev, eqe);
122 	case MLX5_EVENT_TYPE_PATH_MIG:
123 	case MLX5_EVENT_TYPE_COMM_EST:
124 	case MLX5_EVENT_TYPE_SQ_DRAINED:
125 	case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
126 	case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
127 	case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
128 	case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
129 	case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
130 		rsn = be32_to_cpu(eqe->data.qp_srq.qp_srq_n) & 0xffffff;
131 		rsn |= (eqe->data.qp_srq.type << MLX5_USER_INDEX_LEN);
132 		break;
133 	default:
134 		return NOTIFY_DONE;
135 	}
136 
137 	common = mlx5_get_rsc(&dev->qp_table, rsn);
138 	if (!common)
139 		return NOTIFY_OK;
140 
141 	if (!is_event_type_allowed((rsn >> MLX5_USER_INDEX_LEN), event_type))
142 		goto out;
143 
144 	switch (common->res) {
145 	case MLX5_RES_QP:
146 	case MLX5_RES_RQ:
147 	case MLX5_RES_SQ:
148 		qp = (struct mlx5_core_qp *)common;
149 		qp->event(qp, event_type);
150 		/* Need to put resource in event handler */
151 		return NOTIFY_OK;
152 	default:
153 		break;
154 	}
155 out:
156 	mlx5_core_put_rsc(common);
157 
158 	return NOTIFY_OK;
159 }
160 
161 static int create_resource_common(struct mlx5_ib_dev *dev,
162 				  struct mlx5_core_qp *qp, int rsc_type)
163 {
164 	struct mlx5_qp_table *table = &dev->qp_table;
165 	int err;
166 
167 	qp->common.res = rsc_type;
168 	spin_lock_irq(&table->lock);
169 	err = radix_tree_insert(&table->tree,
170 				qp->qpn | (rsc_type << MLX5_USER_INDEX_LEN),
171 				qp);
172 	spin_unlock_irq(&table->lock);
173 	if (err)
174 		return err;
175 
176 	refcount_set(&qp->common.refcount, 1);
177 	init_completion(&qp->common.free);
178 	qp->pid = current->pid;
179 
180 	return 0;
181 }
182 
183 static void modify_resource_common_state(struct mlx5_ib_dev *dev,
184 					 struct mlx5_core_qp *qp,
185 					 bool invalid)
186 {
187 	struct mlx5_qp_table *table = &dev->qp_table;
188 	unsigned long flags;
189 
190 	spin_lock_irqsave(&table->lock, flags);
191 	qp->common.invalid = invalid;
192 	spin_unlock_irqrestore(&table->lock, flags);
193 }
194 
195 static void destroy_resource_common(struct mlx5_ib_dev *dev,
196 				    struct mlx5_core_qp *qp)
197 {
198 	struct mlx5_qp_table *table = &dev->qp_table;
199 	unsigned long flags;
200 
201 	spin_lock_irqsave(&table->lock, flags);
202 	radix_tree_delete(&table->tree,
203 			  qp->qpn | (qp->common.res << MLX5_USER_INDEX_LEN));
204 	spin_unlock_irqrestore(&table->lock, flags);
205 	mlx5_core_put_rsc((struct mlx5_core_rsc_common *)qp);
206 	wait_for_completion(&qp->common.free);
207 }
208 
209 static int _mlx5_core_destroy_dct(struct mlx5_ib_dev *dev,
210 				  struct mlx5_core_dct *dct)
211 {
212 	u32 in[MLX5_ST_SZ_DW(destroy_dct_in)] = {};
213 	struct mlx5_core_qp *qp = &dct->mqp;
214 
215 	MLX5_SET(destroy_dct_in, in, opcode, MLX5_CMD_OP_DESTROY_DCT);
216 	MLX5_SET(destroy_dct_in, in, dctn, qp->qpn);
217 	MLX5_SET(destroy_dct_in, in, uid, qp->uid);
218 	return mlx5_cmd_exec_in(dev->mdev, destroy_dct, in);
219 }
220 
221 int mlx5_core_create_dct(struct mlx5_ib_dev *dev, struct mlx5_core_dct *dct,
222 			 u32 *in, int inlen, u32 *out, int outlen)
223 {
224 	struct mlx5_core_qp *qp = &dct->mqp;
225 	int err;
226 
227 	init_completion(&dct->drained);
228 	MLX5_SET(create_dct_in, in, opcode, MLX5_CMD_OP_CREATE_DCT);
229 
230 	err = mlx5_cmd_do(dev->mdev, in, inlen, out, outlen);
231 	if (err)
232 		return err;
233 
234 	qp->qpn = MLX5_GET(create_dct_out, out, dctn);
235 	qp->uid = MLX5_GET(create_dct_in, in, uid);
236 	err = xa_err(xa_store_irq(&dev->qp_table.dct_xa, qp->qpn, dct, GFP_KERNEL));
237 	if (err)
238 		goto err_cmd;
239 
240 	return 0;
241 err_cmd:
242 	_mlx5_core_destroy_dct(dev, dct);
243 	return err;
244 }
245 
246 int mlx5_qpc_create_qp(struct mlx5_ib_dev *dev, struct mlx5_core_qp *qp,
247 		       u32 *in, int inlen, u32 *out)
248 {
249 	u32 din[MLX5_ST_SZ_DW(destroy_qp_in)] = {};
250 	int err;
251 
252 	MLX5_SET(create_qp_in, in, opcode, MLX5_CMD_OP_CREATE_QP);
253 
254 	err = mlx5_cmd_exec(dev->mdev, in, inlen, out,
255 			    MLX5_ST_SZ_BYTES(create_qp_out));
256 	if (err)
257 		return err;
258 
259 	qp->uid = MLX5_GET(create_qp_in, in, uid);
260 	qp->qpn = MLX5_GET(create_qp_out, out, qpn);
261 
262 	err = create_resource_common(dev, qp, MLX5_RES_QP);
263 	if (err)
264 		goto err_cmd;
265 
266 	if (dev->ib_dev.type != RDMA_DEVICE_TYPE_SMI)
267 		mlx5_debug_qp_add(dev->mdev, qp);
268 
269 	return 0;
270 
271 err_cmd:
272 	MLX5_SET(destroy_qp_in, din, opcode, MLX5_CMD_OP_DESTROY_QP);
273 	MLX5_SET(destroy_qp_in, din, qpn, qp->qpn);
274 	MLX5_SET(destroy_qp_in, din, uid, qp->uid);
275 	mlx5_cmd_exec_in(dev->mdev, destroy_qp, din);
276 	return err;
277 }
278 
279 static int mlx5_core_drain_dct(struct mlx5_ib_dev *dev,
280 			       struct mlx5_core_dct *dct)
281 {
282 	u32 in[MLX5_ST_SZ_DW(drain_dct_in)] = {};
283 	struct mlx5_core_qp *qp = &dct->mqp;
284 
285 	MLX5_SET(drain_dct_in, in, opcode, MLX5_CMD_OP_DRAIN_DCT);
286 	MLX5_SET(drain_dct_in, in, dctn, qp->qpn);
287 	MLX5_SET(drain_dct_in, in, uid, qp->uid);
288 	return mlx5_cmd_exec_in(dev->mdev, drain_dct, in);
289 }
290 
291 int mlx5_core_destroy_dct(struct mlx5_ib_dev *dev,
292 			  struct mlx5_core_dct *dct)
293 {
294 	struct mlx5_qp_table *table = &dev->qp_table;
295 	struct mlx5_core_dct *tmp;
296 	int err;
297 
298 	err = mlx5_core_drain_dct(dev, dct);
299 	if (err) {
300 		if (dev->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
301 			goto destroy;
302 
303 		return err;
304 	}
305 	wait_for_completion(&dct->drained);
306 
307 destroy:
308 	tmp = xa_cmpxchg_irq(&table->dct_xa, dct->mqp.qpn, dct, XA_ZERO_ENTRY, GFP_KERNEL);
309 	if (WARN_ON(tmp != dct))
310 		return xa_err(tmp) ?: -EINVAL;
311 
312 	err = _mlx5_core_destroy_dct(dev, dct);
313 	if (err) {
314 		xa_cmpxchg_irq(&table->dct_xa, dct->mqp.qpn, XA_ZERO_ENTRY, dct, 0);
315 		return err;
316 	}
317 
318 	/*
319 	 * A race can occur where a concurrent create gets the same dctn
320 	 * (after hardware released it) and overwrites XA_ZERO_ENTRY with
321 	 * its new DCT before we reach here. In that case, we must not erase
322 	 * the entry as it now belongs to the new DCT.
323 	 */
324 	xa_cmpxchg_irq(&table->dct_xa, dct->mqp.qpn, XA_ZERO_ENTRY, NULL, 0);
325 	return 0;
326 }
327 
328 int mlx5_core_destroy_qp(struct mlx5_ib_dev *dev, struct mlx5_core_qp *qp)
329 {
330 	u32 in[MLX5_ST_SZ_DW(destroy_qp_in)] = {};
331 
332 	if (dev->ib_dev.type != RDMA_DEVICE_TYPE_SMI)
333 		mlx5_debug_qp_remove(dev->mdev, qp);
334 
335 	destroy_resource_common(dev, qp);
336 
337 	MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP);
338 	MLX5_SET(destroy_qp_in, in, qpn, qp->qpn);
339 	MLX5_SET(destroy_qp_in, in, uid, qp->uid);
340 	return mlx5_cmd_exec_in(dev->mdev, destroy_qp, in);
341 }
342 
343 int mlx5_core_set_delay_drop(struct mlx5_ib_dev *dev,
344 			     u32 timeout_usec)
345 {
346 	u32 in[MLX5_ST_SZ_DW(set_delay_drop_params_in)] = {};
347 
348 	MLX5_SET(set_delay_drop_params_in, in, opcode,
349 		 MLX5_CMD_OP_SET_DELAY_DROP_PARAMS);
350 	MLX5_SET(set_delay_drop_params_in, in, delay_drop_timeout,
351 		 timeout_usec / 100);
352 	return mlx5_cmd_exec_in(dev->mdev, set_delay_drop_params, in);
353 }
354 
355 struct mbox_info {
356 	u32 *in;
357 	u32 *out;
358 	int inlen;
359 	int outlen;
360 };
361 
362 static int mbox_alloc(struct mbox_info *mbox, int inlen, int outlen)
363 {
364 	mbox->inlen  = inlen;
365 	mbox->outlen = outlen;
366 	mbox->in = kzalloc(mbox->inlen, GFP_KERNEL);
367 	mbox->out = kzalloc(mbox->outlen, GFP_KERNEL);
368 	if (!mbox->in || !mbox->out) {
369 		kfree(mbox->in);
370 		kfree(mbox->out);
371 		return -ENOMEM;
372 	}
373 
374 	return 0;
375 }
376 
377 static void mbox_free(struct mbox_info *mbox)
378 {
379 	kfree(mbox->in);
380 	kfree(mbox->out);
381 }
382 
383 static int get_ece_from_mbox(void *out, u16 opcode)
384 {
385 	int ece = 0;
386 
387 	switch (opcode) {
388 	case MLX5_CMD_OP_INIT2INIT_QP:
389 		ece = MLX5_GET(init2init_qp_out, out, ece);
390 		break;
391 	case MLX5_CMD_OP_INIT2RTR_QP:
392 		ece = MLX5_GET(init2rtr_qp_out, out, ece);
393 		break;
394 	case MLX5_CMD_OP_RTR2RTS_QP:
395 		ece = MLX5_GET(rtr2rts_qp_out, out, ece);
396 		break;
397 	case MLX5_CMD_OP_RTS2RTS_QP:
398 		ece = MLX5_GET(rts2rts_qp_out, out, ece);
399 		break;
400 	case MLX5_CMD_OP_RST2INIT_QP:
401 		ece = MLX5_GET(rst2init_qp_out, out, ece);
402 		break;
403 	default:
404 		break;
405 	}
406 
407 	return ece;
408 }
409 
410 static int modify_qp_mbox_alloc(struct mlx5_core_dev *dev, u16 opcode, int qpn,
411 				u32 opt_param_mask, void *qpc,
412 				struct mbox_info *mbox, u16 uid, u32 ece)
413 {
414 	mbox->out = NULL;
415 	mbox->in = NULL;
416 
417 #define MBOX_ALLOC(mbox, typ)  \
418 	mbox_alloc(mbox, MLX5_ST_SZ_BYTES(typ##_in), MLX5_ST_SZ_BYTES(typ##_out))
419 
420 #define MOD_QP_IN_SET(typ, in, _opcode, _qpn, _uid)                            \
421 	do {                                                                   \
422 		MLX5_SET(typ##_in, in, opcode, _opcode);                       \
423 		MLX5_SET(typ##_in, in, qpn, _qpn);                             \
424 		MLX5_SET(typ##_in, in, uid, _uid);                             \
425 	} while (0)
426 
427 #define MOD_QP_IN_SET_QPC(typ, in, _opcode, _qpn, _opt_p, _qpc, _uid)          \
428 	do {                                                                   \
429 		MOD_QP_IN_SET(typ, in, _opcode, _qpn, _uid);                   \
430 		MLX5_SET(typ##_in, in, opt_param_mask, _opt_p);                \
431 		memcpy(MLX5_ADDR_OF(typ##_in, in, qpc), _qpc,                  \
432 		       MLX5_ST_SZ_BYTES(qpc));                                 \
433 	} while (0)
434 
435 	switch (opcode) {
436 	/* 2RST & 2ERR */
437 	case MLX5_CMD_OP_2RST_QP:
438 		if (MBOX_ALLOC(mbox, qp_2rst))
439 			return -ENOMEM;
440 		MOD_QP_IN_SET(qp_2rst, mbox->in, opcode, qpn, uid);
441 		break;
442 	case MLX5_CMD_OP_2ERR_QP:
443 		if (MBOX_ALLOC(mbox, qp_2err))
444 			return -ENOMEM;
445 		MOD_QP_IN_SET(qp_2err, mbox->in, opcode, qpn, uid);
446 		break;
447 
448 	/* MODIFY with QPC */
449 	case MLX5_CMD_OP_RST2INIT_QP:
450 		if (MBOX_ALLOC(mbox, rst2init_qp))
451 			return -ENOMEM;
452 		MOD_QP_IN_SET_QPC(rst2init_qp, mbox->in, opcode, qpn,
453 				  opt_param_mask, qpc, uid);
454 		MLX5_SET(rst2init_qp_in, mbox->in, ece, ece);
455 		break;
456 	case MLX5_CMD_OP_INIT2RTR_QP:
457 		if (MBOX_ALLOC(mbox, init2rtr_qp))
458 			return -ENOMEM;
459 		MOD_QP_IN_SET_QPC(init2rtr_qp, mbox->in, opcode, qpn,
460 				  opt_param_mask, qpc, uid);
461 		MLX5_SET(init2rtr_qp_in, mbox->in, ece, ece);
462 		break;
463 	case MLX5_CMD_OP_RTR2RTS_QP:
464 		if (MBOX_ALLOC(mbox, rtr2rts_qp))
465 			return -ENOMEM;
466 		MOD_QP_IN_SET_QPC(rtr2rts_qp, mbox->in, opcode, qpn,
467 				  opt_param_mask, qpc, uid);
468 		MLX5_SET(rtr2rts_qp_in, mbox->in, ece, ece);
469 		break;
470 	case MLX5_CMD_OP_RTS2RTS_QP:
471 		if (MBOX_ALLOC(mbox, rts2rts_qp))
472 			return -ENOMEM;
473 		MOD_QP_IN_SET_QPC(rts2rts_qp, mbox->in, opcode, qpn,
474 				  opt_param_mask, qpc, uid);
475 		MLX5_SET(rts2rts_qp_in, mbox->in, ece, ece);
476 		break;
477 	case MLX5_CMD_OP_SQERR2RTS_QP:
478 		if (MBOX_ALLOC(mbox, sqerr2rts_qp))
479 			return -ENOMEM;
480 		MOD_QP_IN_SET_QPC(sqerr2rts_qp, mbox->in, opcode, qpn,
481 				  opt_param_mask, qpc, uid);
482 		break;
483 	case MLX5_CMD_OP_SQD_RTS_QP:
484 		if (MBOX_ALLOC(mbox, sqd2rts_qp))
485 			return -ENOMEM;
486 		MOD_QP_IN_SET_QPC(sqd2rts_qp, mbox->in, opcode, qpn,
487 				  opt_param_mask, qpc, uid);
488 		break;
489 	case MLX5_CMD_OP_INIT2INIT_QP:
490 		if (MBOX_ALLOC(mbox, init2init_qp))
491 			return -ENOMEM;
492 		MOD_QP_IN_SET_QPC(init2init_qp, mbox->in, opcode, qpn,
493 				  opt_param_mask, qpc, uid);
494 		MLX5_SET(init2init_qp_in, mbox->in, ece, ece);
495 		break;
496 	default:
497 		return -EINVAL;
498 	}
499 	return 0;
500 }
501 
502 int mlx5_core_qp_modify(struct mlx5_ib_dev *dev, u16 opcode, u32 opt_param_mask,
503 			void *qpc, struct mlx5_core_qp *qp, u32 *ece)
504 {
505 	struct mbox_info mbox;
506 	int err;
507 
508 	err = modify_qp_mbox_alloc(dev->mdev, opcode, qp->qpn, opt_param_mask,
509 				   qpc, &mbox, qp->uid, (ece) ? *ece : 0);
510 	if (err)
511 		return err;
512 
513 	err = mlx5_cmd_exec(dev->mdev, mbox.in, mbox.inlen, mbox.out,
514 			    mbox.outlen);
515 
516 	if (ece)
517 		*ece = get_ece_from_mbox(mbox.out, opcode);
518 
519 	mbox_free(&mbox);
520 	return err;
521 }
522 
523 int mlx5_init_qp_table(struct mlx5_ib_dev *dev)
524 {
525 	struct mlx5_qp_table *table = &dev->qp_table;
526 
527 	spin_lock_init(&table->lock);
528 	INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
529 	xa_init(&table->dct_xa);
530 
531 	if (dev->ib_dev.type != RDMA_DEVICE_TYPE_SMI)
532 		mlx5_qp_debugfs_init(dev->mdev);
533 
534 	table->nb.notifier_call = rsc_event_notifier;
535 	mlx5_notifier_register(dev->mdev, &table->nb);
536 
537 	return 0;
538 }
539 
540 void mlx5_cleanup_qp_table(struct mlx5_ib_dev *dev)
541 {
542 	struct mlx5_qp_table *table = &dev->qp_table;
543 
544 	mlx5_notifier_unregister(dev->mdev, &table->nb);
545 	if (dev->ib_dev.type != RDMA_DEVICE_TYPE_SMI)
546 		mlx5_qp_debugfs_cleanup(dev->mdev);
547 }
548 
549 int mlx5_core_qp_query(struct mlx5_ib_dev *dev, struct mlx5_core_qp *qp,
550 		       u32 *out, int outlen, bool qpc_ext)
551 {
552 	u32 in[MLX5_ST_SZ_DW(query_qp_in)] = {};
553 
554 	MLX5_SET(query_qp_in, in, opcode, MLX5_CMD_OP_QUERY_QP);
555 	MLX5_SET(query_qp_in, in, qpn, qp->qpn);
556 	MLX5_SET(query_qp_in, in, qpc_ext, qpc_ext);
557 
558 	return mlx5_cmd_exec(dev->mdev, in, sizeof(in), out, outlen);
559 }
560 
561 int mlx5_core_dct_query(struct mlx5_ib_dev *dev, struct mlx5_core_dct *dct,
562 			u32 *out, int outlen)
563 {
564 	u32 in[MLX5_ST_SZ_DW(query_dct_in)] = {};
565 	struct mlx5_core_qp *qp = &dct->mqp;
566 
567 	MLX5_SET(query_dct_in, in, opcode, MLX5_CMD_OP_QUERY_DCT);
568 	MLX5_SET(query_dct_in, in, dctn, qp->qpn);
569 
570 	return mlx5_cmd_exec(dev->mdev, (void *)&in, sizeof(in), (void *)out,
571 			     outlen);
572 }
573 
574 int mlx5_core_xrcd_alloc(struct mlx5_ib_dev *dev, u32 *xrcdn)
575 {
576 	u32 out[MLX5_ST_SZ_DW(alloc_xrcd_out)] = {};
577 	u32 in[MLX5_ST_SZ_DW(alloc_xrcd_in)] = {};
578 	int err;
579 
580 	MLX5_SET(alloc_xrcd_in, in, opcode, MLX5_CMD_OP_ALLOC_XRCD);
581 	err = mlx5_cmd_exec_inout(dev->mdev, alloc_xrcd, in, out);
582 	if (!err)
583 		*xrcdn = MLX5_GET(alloc_xrcd_out, out, xrcd);
584 	return err;
585 }
586 
587 int mlx5_core_xrcd_dealloc(struct mlx5_ib_dev *dev, u32 xrcdn)
588 {
589 	u32 in[MLX5_ST_SZ_DW(dealloc_xrcd_in)] = {};
590 
591 	MLX5_SET(dealloc_xrcd_in, in, opcode, MLX5_CMD_OP_DEALLOC_XRCD);
592 	MLX5_SET(dealloc_xrcd_in, in, xrcd, xrcdn);
593 	return mlx5_cmd_exec_in(dev->mdev, dealloc_xrcd, in);
594 }
595 
596 static int destroy_rq_tracked(struct mlx5_ib_dev *dev, u32 rqn, u16 uid)
597 {
598 	u32 in[MLX5_ST_SZ_DW(destroy_rq_in)] = {};
599 
600 	MLX5_SET(destroy_rq_in, in, opcode, MLX5_CMD_OP_DESTROY_RQ);
601 	MLX5_SET(destroy_rq_in, in, rqn, rqn);
602 	MLX5_SET(destroy_rq_in, in, uid, uid);
603 	return mlx5_cmd_exec_in(dev->mdev, destroy_rq, in);
604 }
605 
606 int mlx5_core_create_rq_tracked(struct mlx5_ib_dev *dev, u32 *in, int inlen,
607 				struct mlx5_core_qp *rq)
608 {
609 	int err;
610 	u32 rqn;
611 
612 	err = mlx5_core_create_rq(dev->mdev, in, inlen, &rqn);
613 	if (err)
614 		return err;
615 
616 	rq->uid = MLX5_GET(create_rq_in, in, uid);
617 	rq->qpn = rqn;
618 	err = create_resource_common(dev, rq, MLX5_RES_RQ);
619 	if (err)
620 		goto err_destroy_rq;
621 
622 	return 0;
623 
624 err_destroy_rq:
625 	destroy_rq_tracked(dev, rq->qpn, rq->uid);
626 
627 	return err;
628 }
629 
630 int mlx5_core_destroy_rq_tracked(struct mlx5_ib_dev *dev,
631 				 struct mlx5_core_qp *rq)
632 {
633 	int ret;
634 
635 	/* The rq destruction can be called again in case it fails, hence we
636 	 * mark the common resource as invalid and only once FW destruction
637 	 * is completed successfully we actually destroy the resources.
638 	 */
639 	modify_resource_common_state(dev, rq, true);
640 	ret = destroy_rq_tracked(dev, rq->qpn, rq->uid);
641 	if (ret) {
642 		modify_resource_common_state(dev, rq, false);
643 		return ret;
644 	}
645 	destroy_resource_common(dev, rq);
646 	return 0;
647 }
648 
649 static void destroy_sq_tracked(struct mlx5_ib_dev *dev, u32 sqn, u16 uid)
650 {
651 	u32 in[MLX5_ST_SZ_DW(destroy_sq_in)] = {};
652 
653 	MLX5_SET(destroy_sq_in, in, opcode, MLX5_CMD_OP_DESTROY_SQ);
654 	MLX5_SET(destroy_sq_in, in, sqn, sqn);
655 	MLX5_SET(destroy_sq_in, in, uid, uid);
656 	mlx5_cmd_exec_in(dev->mdev, destroy_sq, in);
657 }
658 
659 int mlx5_core_create_sq_tracked(struct mlx5_ib_dev *dev, u32 *in, int inlen,
660 				struct mlx5_core_qp *sq)
661 {
662 	u32 out[MLX5_ST_SZ_DW(create_sq_out)] = {};
663 	int err;
664 
665 	MLX5_SET(create_sq_in, in, opcode, MLX5_CMD_OP_CREATE_SQ);
666 	err = mlx5_cmd_exec(dev->mdev, in, inlen, out, sizeof(out));
667 	if (err)
668 		return err;
669 
670 	sq->qpn = MLX5_GET(create_sq_out, out, sqn);
671 	sq->uid = MLX5_GET(create_sq_in, in, uid);
672 	err = create_resource_common(dev, sq, MLX5_RES_SQ);
673 	if (err)
674 		goto err_destroy_sq;
675 
676 	return 0;
677 
678 err_destroy_sq:
679 	destroy_sq_tracked(dev, sq->qpn, sq->uid);
680 
681 	return err;
682 }
683 
684 void mlx5_core_destroy_sq_tracked(struct mlx5_ib_dev *dev,
685 				  struct mlx5_core_qp *sq)
686 {
687 	destroy_resource_common(dev, sq);
688 	destroy_sq_tracked(dev, sq->qpn, sq->uid);
689 }
690 
691 struct mlx5_core_rsc_common *mlx5_core_res_hold(struct mlx5_ib_dev *dev,
692 						int res_num,
693 						enum mlx5_res_type res_type)
694 {
695 	u32 rsn = res_num | (res_type << MLX5_USER_INDEX_LEN);
696 	struct mlx5_qp_table *table = &dev->qp_table;
697 
698 	return mlx5_get_rsc(table, rsn);
699 }
700 
701 void mlx5_core_res_put(struct mlx5_core_rsc_common *res)
702 {
703 	mlx5_core_put_rsc(res);
704 }
705