xref: /freebsd/sys/dev/mlx5/mlx5_ib/mlx5_ib_qp.c (revision 813d981e1e78daffde4b2a05df35d054fcb4343f)
112515907SHans Petter Selasky /*-
24fb0a74eSHans Petter Selasky  * Copyright (c) 2013-2021, Mellanox Technologies. All rights reserved.
312515907SHans Petter Selasky  *
412515907SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
512515907SHans Petter Selasky  * modification, are permitted provided that the following conditions
612515907SHans Petter Selasky  * are met:
712515907SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
812515907SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
912515907SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
1012515907SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
1112515907SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
1212515907SHans Petter Selasky  *
1312515907SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
1412515907SHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1512515907SHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1612515907SHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1712515907SHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1812515907SHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1912515907SHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2012515907SHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2112515907SHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2212515907SHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2312515907SHans Petter Selasky  * SUCH DAMAGE.
2412515907SHans Petter Selasky  */
2512515907SHans Petter Selasky 
2670600979SKonstantin Belousov #include "opt_rss.h"
2770600979SKonstantin Belousov #include "opt_ratelimit.h"
2870600979SKonstantin Belousov 
2912515907SHans Petter Selasky #include <linux/module.h>
3012515907SHans Petter Selasky #include <rdma/ib_umem.h>
318e6e287fSHans Petter Selasky #include <rdma/ib_cache.h>
328e6e287fSHans Petter Selasky #include <rdma/ib_user_verbs.h>
33b633e08cSHans Petter Selasky #include <rdma/uverbs_ioctl.h>
34*028130b8SKonstantin Belousov #include <dev/mlx5/mlx5_ib/mlx5_ib.h>
3512515907SHans Petter Selasky 
3612515907SHans Petter Selasky /* not supported currently */
378e6e287fSHans Petter Selasky static int wq_signature;
3812515907SHans Petter Selasky 
3912515907SHans Petter Selasky enum {
4012515907SHans Petter Selasky 	MLX5_IB_ACK_REQ_FREQ	= 8,
4112515907SHans Petter Selasky };
4212515907SHans Petter Selasky 
4312515907SHans Petter Selasky enum {
4412515907SHans Petter Selasky 	MLX5_IB_DEFAULT_SCHED_QUEUE	= 0x83,
4512515907SHans Petter Selasky 	MLX5_IB_DEFAULT_QP0_SCHED_QUEUE	= 0x3f,
4612515907SHans Petter Selasky 	MLX5_IB_LINK_TYPE_IB		= 0,
4712515907SHans Petter Selasky 	MLX5_IB_LINK_TYPE_ETH		= 1
4812515907SHans Petter Selasky };
4912515907SHans Petter Selasky 
5012515907SHans Petter Selasky enum {
5112515907SHans Petter Selasky 	MLX5_IB_SQ_STRIDE	= 6,
5212515907SHans Petter Selasky };
5312515907SHans Petter Selasky 
5412515907SHans Petter Selasky static const u32 mlx5_ib_opcode[] = {
5512515907SHans Petter Selasky 	[IB_WR_SEND]				= MLX5_OPCODE_SEND,
568e6e287fSHans Petter Selasky 	[IB_WR_LSO]				= MLX5_OPCODE_LSO,
5712515907SHans Petter Selasky 	[IB_WR_SEND_WITH_IMM]			= MLX5_OPCODE_SEND_IMM,
5812515907SHans Petter Selasky 	[IB_WR_RDMA_WRITE]			= MLX5_OPCODE_RDMA_WRITE,
5912515907SHans Petter Selasky 	[IB_WR_RDMA_WRITE_WITH_IMM]		= MLX5_OPCODE_RDMA_WRITE_IMM,
6012515907SHans Petter Selasky 	[IB_WR_RDMA_READ]			= MLX5_OPCODE_RDMA_READ,
6112515907SHans Petter Selasky 	[IB_WR_ATOMIC_CMP_AND_SWP]		= MLX5_OPCODE_ATOMIC_CS,
6212515907SHans Petter Selasky 	[IB_WR_ATOMIC_FETCH_AND_ADD]		= MLX5_OPCODE_ATOMIC_FA,
6312515907SHans Petter Selasky 	[IB_WR_SEND_WITH_INV]			= MLX5_OPCODE_SEND_INVAL,
6412515907SHans Petter Selasky 	[IB_WR_LOCAL_INV]			= MLX5_OPCODE_UMR,
658e6e287fSHans Petter Selasky 	[IB_WR_REG_MR]				= MLX5_OPCODE_UMR,
6612515907SHans Petter Selasky 	[IB_WR_MASKED_ATOMIC_CMP_AND_SWP]	= MLX5_OPCODE_ATOMIC_MASKED_CS,
6712515907SHans Petter Selasky 	[IB_WR_MASKED_ATOMIC_FETCH_AND_ADD]	= MLX5_OPCODE_ATOMIC_MASKED_FA,
688e6e287fSHans Petter Selasky 	[MLX5_IB_WR_UMR]			= MLX5_OPCODE_UMR,
6912515907SHans Petter Selasky };
7012515907SHans Petter Selasky 
718e6e287fSHans Petter Selasky struct mlx5_wqe_eth_pad {
728e6e287fSHans Petter Selasky 	u8 rsvd0[16];
7312515907SHans Petter Selasky };
7412515907SHans Petter Selasky 
758e6e287fSHans Petter Selasky enum raw_qp_set_mask_map {
768e6e287fSHans Petter Selasky 	MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID		= 1UL << 0,
778e6e287fSHans Petter Selasky };
788e6e287fSHans Petter Selasky 
798e6e287fSHans Petter Selasky struct mlx5_modify_raw_qp_param {
808e6e287fSHans Petter Selasky 	u16 operation;
818e6e287fSHans Petter Selasky 
828e6e287fSHans Petter Selasky 	u32 set_mask; /* raw_qp_set_mask_map */
838e6e287fSHans Petter Selasky 	u8 rq_q_ctr_id;
848e6e287fSHans Petter Selasky };
858e6e287fSHans Petter Selasky 
868e6e287fSHans Petter Selasky static void get_cqs(enum ib_qp_type qp_type,
878e6e287fSHans Petter Selasky 		    struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq,
888e6e287fSHans Petter Selasky 		    struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq);
898e6e287fSHans Petter Selasky 
is_qp0(enum ib_qp_type qp_type)9012515907SHans Petter Selasky static int is_qp0(enum ib_qp_type qp_type)
9112515907SHans Petter Selasky {
9212515907SHans Petter Selasky 	return qp_type == IB_QPT_SMI;
9312515907SHans Petter Selasky }
9412515907SHans Petter Selasky 
is_sqp(enum ib_qp_type qp_type)9512515907SHans Petter Selasky static int is_sqp(enum ib_qp_type qp_type)
9612515907SHans Petter Selasky {
9712515907SHans Petter Selasky 	return is_qp0(qp_type) || is_qp1(qp_type);
9812515907SHans Petter Selasky }
9912515907SHans Petter Selasky 
get_wqe(struct mlx5_ib_qp * qp,int offset)10012515907SHans Petter Selasky static void *get_wqe(struct mlx5_ib_qp *qp, int offset)
10112515907SHans Petter Selasky {
10212515907SHans Petter Selasky 	return mlx5_buf_offset(&qp->buf, offset);
10312515907SHans Petter Selasky }
10412515907SHans Petter Selasky 
get_recv_wqe(struct mlx5_ib_qp * qp,int n)10512515907SHans Petter Selasky static void *get_recv_wqe(struct mlx5_ib_qp *qp, int n)
10612515907SHans Petter Selasky {
10712515907SHans Petter Selasky 	return get_wqe(qp, qp->rq.offset + (n << qp->rq.wqe_shift));
10812515907SHans Petter Selasky }
10912515907SHans Petter Selasky 
mlx5_get_send_wqe(struct mlx5_ib_qp * qp,int n)11012515907SHans Petter Selasky void *mlx5_get_send_wqe(struct mlx5_ib_qp *qp, int n)
11112515907SHans Petter Selasky {
11212515907SHans Petter Selasky 	return get_wqe(qp, qp->sq.offset + (n << MLX5_IB_SQ_STRIDE));
11312515907SHans Petter Selasky }
11412515907SHans Petter Selasky 
1158e6e287fSHans Petter Selasky /**
1168e6e287fSHans Petter Selasky  * mlx5_ib_read_user_wqe() - Copy a user-space WQE to kernel space.
1178e6e287fSHans Petter Selasky  *
1188e6e287fSHans Petter Selasky  * @qp: QP to copy from.
1198e6e287fSHans Petter Selasky  * @send: copy from the send queue when non-zero, use the receive queue
1208e6e287fSHans Petter Selasky  *	  otherwise.
1218e6e287fSHans Petter Selasky  * @wqe_index:  index to start copying from. For send work queues, the
1228e6e287fSHans Petter Selasky  *		wqe_index is in units of MLX5_SEND_WQE_BB.
1238e6e287fSHans Petter Selasky  *		For receive work queue, it is the number of work queue
1248e6e287fSHans Petter Selasky  *		element in the queue.
1258e6e287fSHans Petter Selasky  * @buffer: destination buffer.
1268e6e287fSHans Petter Selasky  * @length: maximum number of bytes to copy.
1278e6e287fSHans Petter Selasky  *
1288e6e287fSHans Petter Selasky  * Copies at least a single WQE, but may copy more data.
1298e6e287fSHans Petter Selasky  *
1308e6e287fSHans Petter Selasky  * Return: the number of bytes copied, or an error code.
1318e6e287fSHans Petter Selasky  */
mlx5_ib_read_user_wqe(struct mlx5_ib_qp * qp,int send,int wqe_index,void * buffer,u32 length,struct mlx5_ib_qp_base * base)1328e6e287fSHans Petter Selasky int mlx5_ib_read_user_wqe(struct mlx5_ib_qp *qp, int send, int wqe_index,
1338e6e287fSHans Petter Selasky 			  void *buffer, u32 length,
1348e6e287fSHans Petter Selasky 			  struct mlx5_ib_qp_base *base)
13512515907SHans Petter Selasky {
1368e6e287fSHans Petter Selasky 	struct ib_device *ibdev = qp->ibqp.device;
1378e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(ibdev);
1388e6e287fSHans Petter Selasky 	struct mlx5_ib_wq *wq = send ? &qp->sq : &qp->rq;
1398e6e287fSHans Petter Selasky 	size_t offset;
1408e6e287fSHans Petter Selasky 	size_t wq_end;
1418e6e287fSHans Petter Selasky 	struct ib_umem *umem = base->ubuffer.umem;
1428e6e287fSHans Petter Selasky 	u32 first_copy_length;
1438e6e287fSHans Petter Selasky 	int wqe_length;
14412515907SHans Petter Selasky 	int ret;
14512515907SHans Petter Selasky 
1468e6e287fSHans Petter Selasky 	if (wq->wqe_cnt == 0) {
1478e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "mlx5_ib_read_user_wqe for a QP with wqe_cnt == 0. qp_type: 0x%x\n",
1488e6e287fSHans Petter Selasky 			    qp->ibqp.qp_type);
1498e6e287fSHans Petter Selasky 		return -EINVAL;
1508e6e287fSHans Petter Selasky 	}
15112515907SHans Petter Selasky 
1528e6e287fSHans Petter Selasky 	offset = wq->offset + ((wqe_index % wq->wqe_cnt) << wq->wqe_shift);
1538e6e287fSHans Petter Selasky 	wq_end = wq->offset + (wq->wqe_cnt << wq->wqe_shift);
15412515907SHans Petter Selasky 
1558e6e287fSHans Petter Selasky 	if (send && length < sizeof(struct mlx5_wqe_ctrl_seg))
1568e6e287fSHans Petter Selasky 		return -EINVAL;
1578e6e287fSHans Petter Selasky 
1588e6e287fSHans Petter Selasky 	if (offset > umem->length ||
1598e6e287fSHans Petter Selasky 	    (send && offset + sizeof(struct mlx5_wqe_ctrl_seg) > umem->length))
1608e6e287fSHans Petter Selasky 		return -EINVAL;
1618e6e287fSHans Petter Selasky 
1628e6e287fSHans Petter Selasky 	first_copy_length = min_t(u32, offset + length, wq_end) - offset;
1638e6e287fSHans Petter Selasky 	ret = ib_umem_copy_from(buffer, umem, offset, first_copy_length);
16412515907SHans Petter Selasky 	if (ret)
16512515907SHans Petter Selasky 		return ret;
1668e6e287fSHans Petter Selasky 
1678e6e287fSHans Petter Selasky 	if (send) {
1688e6e287fSHans Petter Selasky 		struct mlx5_wqe_ctrl_seg *ctrl = buffer;
1698e6e287fSHans Petter Selasky 		int ds = be32_to_cpu(ctrl->qpn_ds) & MLX5_WQE_CTRL_DS_MASK;
1708e6e287fSHans Petter Selasky 
1718e6e287fSHans Petter Selasky 		wqe_length = ds * MLX5_WQE_DS_UNITS;
1728e6e287fSHans Petter Selasky 	} else {
1738e6e287fSHans Petter Selasky 		wqe_length = 1 << wq->wqe_shift;
17412515907SHans Petter Selasky 	}
17512515907SHans Petter Selasky 
1768e6e287fSHans Petter Selasky 	if (wqe_length <= first_copy_length)
1778e6e287fSHans Petter Selasky 		return first_copy_length;
17812515907SHans Petter Selasky 
1798e6e287fSHans Petter Selasky 	ret = ib_umem_copy_from(buffer + first_copy_length, umem, wq->offset,
1808e6e287fSHans Petter Selasky 				wqe_length - first_copy_length);
1818e6e287fSHans Petter Selasky 	if (ret)
1828e6e287fSHans Petter Selasky 		return ret;
18312515907SHans Petter Selasky 
1848e6e287fSHans Petter Selasky 	return wqe_length;
18512515907SHans Petter Selasky }
18612515907SHans Petter Selasky 
mlx5_ib_qp_event(struct mlx5_core_qp * qp,int type)18712515907SHans Petter Selasky static void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type)
18812515907SHans Petter Selasky {
18912515907SHans Petter Selasky 	struct ib_qp *ibqp = &to_mibqp(qp)->ibqp;
19012515907SHans Petter Selasky 	struct ib_event event;
19112515907SHans Petter Selasky 
1928e6e287fSHans Petter Selasky 	if (type == MLX5_EVENT_TYPE_PATH_MIG) {
1938e6e287fSHans Petter Selasky 		/* This event is only valid for trans_qps */
1948e6e287fSHans Petter Selasky 		to_mibqp(qp)->port = to_mibqp(qp)->trans_qp.alt_port;
19512515907SHans Petter Selasky 	}
19612515907SHans Petter Selasky 
19712515907SHans Petter Selasky 	if (ibqp->event_handler) {
19812515907SHans Petter Selasky 		event.device     = ibqp->device;
19912515907SHans Petter Selasky 		event.element.qp = ibqp;
20012515907SHans Petter Selasky 		switch (type) {
20112515907SHans Petter Selasky 		case MLX5_EVENT_TYPE_PATH_MIG:
20212515907SHans Petter Selasky 			event.event = IB_EVENT_PATH_MIG;
20312515907SHans Petter Selasky 			break;
20412515907SHans Petter Selasky 		case MLX5_EVENT_TYPE_COMM_EST:
20512515907SHans Petter Selasky 			event.event = IB_EVENT_COMM_EST;
20612515907SHans Petter Selasky 			break;
20712515907SHans Petter Selasky 		case MLX5_EVENT_TYPE_SQ_DRAINED:
20812515907SHans Petter Selasky 			event.event = IB_EVENT_SQ_DRAINED;
20912515907SHans Petter Selasky 			break;
21012515907SHans Petter Selasky 		case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
21112515907SHans Petter Selasky 			event.event = IB_EVENT_QP_LAST_WQE_REACHED;
21212515907SHans Petter Selasky 			break;
21312515907SHans Petter Selasky 		case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
21412515907SHans Petter Selasky 			event.event = IB_EVENT_QP_FATAL;
21512515907SHans Petter Selasky 			break;
21612515907SHans Petter Selasky 		case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
21712515907SHans Petter Selasky 			event.event = IB_EVENT_PATH_MIG_ERR;
21812515907SHans Petter Selasky 			break;
21912515907SHans Petter Selasky 		case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
22012515907SHans Petter Selasky 			event.event = IB_EVENT_QP_REQ_ERR;
22112515907SHans Petter Selasky 			break;
22212515907SHans Petter Selasky 		case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
22312515907SHans Petter Selasky 			event.event = IB_EVENT_QP_ACCESS_ERR;
22412515907SHans Petter Selasky 			break;
22512515907SHans Petter Selasky 		default:
2268e6e287fSHans Petter Selasky 			pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n", type, qp->qpn);
22712515907SHans Petter Selasky 			return;
22812515907SHans Petter Selasky 		}
22912515907SHans Petter Selasky 
23012515907SHans Petter Selasky 		ibqp->event_handler(&event, ibqp->qp_context);
23112515907SHans Petter Selasky 	}
23212515907SHans Petter Selasky }
23312515907SHans Petter Selasky 
set_rq_size(struct mlx5_ib_dev * dev,struct ib_qp_cap * cap,int has_rq,struct mlx5_ib_qp * qp,struct mlx5_ib_create_qp * ucmd)23412515907SHans Petter Selasky static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
23512515907SHans Petter Selasky 		       int has_rq, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd)
23612515907SHans Petter Selasky {
23712515907SHans Petter Selasky 	int wqe_size;
23812515907SHans Petter Selasky 	int wq_size;
23912515907SHans Petter Selasky 
24012515907SHans Petter Selasky 	/* Sanity check RQ size before proceeding */
24112515907SHans Petter Selasky 	if (cap->max_recv_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz)))
24212515907SHans Petter Selasky 		return -EINVAL;
24312515907SHans Petter Selasky 
24412515907SHans Petter Selasky 	if (!has_rq) {
24512515907SHans Petter Selasky 		qp->rq.max_gs = 0;
24612515907SHans Petter Selasky 		qp->rq.wqe_cnt = 0;
24712515907SHans Petter Selasky 		qp->rq.wqe_shift = 0;
24812515907SHans Petter Selasky 		cap->max_recv_wr = 0;
24912515907SHans Petter Selasky 		cap->max_recv_sge = 0;
25012515907SHans Petter Selasky 	} else {
25112515907SHans Petter Selasky 		if (ucmd) {
25212515907SHans Petter Selasky 			qp->rq.wqe_cnt = ucmd->rq_wqe_count;
25312515907SHans Petter Selasky 			qp->rq.wqe_shift = ucmd->rq_wqe_shift;
25412515907SHans Petter Selasky 			qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig;
25512515907SHans Petter Selasky 			qp->rq.max_post = qp->rq.wqe_cnt;
25612515907SHans Petter Selasky 		} else {
25712515907SHans Petter Selasky 			wqe_size = qp->wq_sig ? sizeof(struct mlx5_wqe_signature_seg) : 0;
25812515907SHans Petter Selasky 			wqe_size += cap->max_recv_sge * sizeof(struct mlx5_wqe_data_seg);
25912515907SHans Petter Selasky 			wqe_size = roundup_pow_of_two(wqe_size);
26012515907SHans Petter Selasky 			wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size;
26112515907SHans Petter Selasky 			wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB);
26212515907SHans Petter Selasky 			qp->rq.wqe_cnt = wq_size / wqe_size;
26312515907SHans Petter Selasky 			if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq)) {
26412515907SHans Petter Selasky 				mlx5_ib_dbg(dev, "wqe_size %d, max %d\n",
26512515907SHans Petter Selasky 					    wqe_size,
26612515907SHans Petter Selasky 					    MLX5_CAP_GEN(dev->mdev,
26712515907SHans Petter Selasky 							 max_wqe_sz_rq));
26812515907SHans Petter Selasky 				return -EINVAL;
26912515907SHans Petter Selasky 			}
27012515907SHans Petter Selasky 			qp->rq.wqe_shift = ilog2(wqe_size);
27112515907SHans Petter Selasky 			qp->rq.max_gs = (1 << qp->rq.wqe_shift) / sizeof(struct mlx5_wqe_data_seg) - qp->wq_sig;
27212515907SHans Petter Selasky 			qp->rq.max_post = qp->rq.wqe_cnt;
27312515907SHans Petter Selasky 		}
27412515907SHans Petter Selasky 	}
27512515907SHans Petter Selasky 
27612515907SHans Petter Selasky 	return 0;
27712515907SHans Petter Selasky }
27812515907SHans Petter Selasky 
sq_overhead(struct ib_qp_init_attr * attr)2798e6e287fSHans Petter Selasky static int sq_overhead(struct ib_qp_init_attr *attr)
28012515907SHans Petter Selasky {
28112515907SHans Petter Selasky 	int size = 0;
28212515907SHans Petter Selasky 
2838e6e287fSHans Petter Selasky 	switch (attr->qp_type) {
28412515907SHans Petter Selasky 	case IB_QPT_XRC_INI:
28512515907SHans Petter Selasky 		size += sizeof(struct mlx5_wqe_xrc_seg);
28612515907SHans Petter Selasky 		/* fall through */
28712515907SHans Petter Selasky 	case IB_QPT_RC:
28812515907SHans Petter Selasky 		size += sizeof(struct mlx5_wqe_ctrl_seg) +
2898e6e287fSHans Petter Selasky 			max(sizeof(struct mlx5_wqe_atomic_seg) +
2908e6e287fSHans Petter Selasky 			    sizeof(struct mlx5_wqe_raddr_seg),
29112515907SHans Petter Selasky 			    sizeof(struct mlx5_wqe_umr_ctrl_seg) +
2928e6e287fSHans Petter Selasky 			    sizeof(struct mlx5_mkey_seg));
29312515907SHans Petter Selasky 		break;
29412515907SHans Petter Selasky 
29512515907SHans Petter Selasky 	case IB_QPT_XRC_TGT:
29612515907SHans Petter Selasky 		return 0;
29712515907SHans Petter Selasky 
29812515907SHans Petter Selasky 	case IB_QPT_UC:
29912515907SHans Petter Selasky 		size += sizeof(struct mlx5_wqe_ctrl_seg) +
3008e6e287fSHans Petter Selasky 			max(sizeof(struct mlx5_wqe_raddr_seg),
30112515907SHans Petter Selasky 			    sizeof(struct mlx5_wqe_umr_ctrl_seg) +
3028e6e287fSHans Petter Selasky 			    sizeof(struct mlx5_mkey_seg));
30312515907SHans Petter Selasky 		break;
30412515907SHans Petter Selasky 
30512515907SHans Petter Selasky 	case IB_QPT_UD:
3068e6e287fSHans Petter Selasky 		if (attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO)
3078e6e287fSHans Petter Selasky 			size += sizeof(struct mlx5_wqe_eth_pad) +
3088e6e287fSHans Petter Selasky 				sizeof(struct mlx5_wqe_eth_seg);
3098e6e287fSHans Petter Selasky 		/* fall through */
31012515907SHans Petter Selasky 	case IB_QPT_SMI:
3118e6e287fSHans Petter Selasky 	case MLX5_IB_QPT_HW_GSI:
31212515907SHans Petter Selasky 		size += sizeof(struct mlx5_wqe_ctrl_seg) +
31312515907SHans Petter Selasky 			sizeof(struct mlx5_wqe_datagram_seg);
31412515907SHans Petter Selasky 		break;
31512515907SHans Petter Selasky 
3168e6e287fSHans Petter Selasky 	case MLX5_IB_QPT_REG_UMR:
3178e6e287fSHans Petter Selasky 		size += sizeof(struct mlx5_wqe_ctrl_seg) +
3188e6e287fSHans Petter Selasky 			sizeof(struct mlx5_wqe_umr_ctrl_seg) +
3198e6e287fSHans Petter Selasky 			sizeof(struct mlx5_mkey_seg);
3208e6e287fSHans Petter Selasky 		break;
3218e6e287fSHans Petter Selasky 
32212515907SHans Petter Selasky 	default:
32312515907SHans Petter Selasky 		return -EINVAL;
32412515907SHans Petter Selasky 	}
32512515907SHans Petter Selasky 
32612515907SHans Petter Selasky 	return size;
32712515907SHans Petter Selasky }
32812515907SHans Petter Selasky 
calc_send_wqe(struct ib_qp_init_attr * attr)32912515907SHans Petter Selasky static int calc_send_wqe(struct ib_qp_init_attr *attr)
33012515907SHans Petter Selasky {
33112515907SHans Petter Selasky 	int inl_size = 0;
33212515907SHans Petter Selasky 	int size;
33312515907SHans Petter Selasky 
3348e6e287fSHans Petter Selasky 	size = sq_overhead(attr);
33512515907SHans Petter Selasky 	if (size < 0)
33612515907SHans Petter Selasky 		return size;
33712515907SHans Petter Selasky 
33812515907SHans Petter Selasky 	if (attr->cap.max_inline_data) {
33912515907SHans Petter Selasky 		inl_size = size + sizeof(struct mlx5_wqe_inline_seg) +
34012515907SHans Petter Selasky 			attr->cap.max_inline_data;
34112515907SHans Petter Selasky 	}
34212515907SHans Petter Selasky 
34312515907SHans Petter Selasky 	size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg);
3448e6e287fSHans Petter Selasky 	if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN &&
3458e6e287fSHans Petter Selasky 	    ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB) < MLX5_SIG_WQE_SIZE)
3468e6e287fSHans Petter Selasky 			return MLX5_SIG_WQE_SIZE;
34712515907SHans Petter Selasky 	else
3488e6e287fSHans Petter Selasky 		return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB);
34912515907SHans Petter Selasky }
35012515907SHans Petter Selasky 
get_send_sge(struct ib_qp_init_attr * attr,int wqe_size)351c788dceaSHans Petter Selasky static int get_send_sge(struct ib_qp_init_attr *attr, int wqe_size)
352c788dceaSHans Petter Selasky {
353c788dceaSHans Petter Selasky 	int max_sge;
354c788dceaSHans Petter Selasky 
355c788dceaSHans Petter Selasky 	if (attr->qp_type == IB_QPT_RC)
356c788dceaSHans Petter Selasky 		max_sge = (min_t(int, wqe_size, 512) -
357c788dceaSHans Petter Selasky 			   sizeof(struct mlx5_wqe_ctrl_seg) -
358c788dceaSHans Petter Selasky 			   sizeof(struct mlx5_wqe_raddr_seg)) /
359c788dceaSHans Petter Selasky 			sizeof(struct mlx5_wqe_data_seg);
360c788dceaSHans Petter Selasky 	else if (attr->qp_type == IB_QPT_XRC_INI)
361c788dceaSHans Petter Selasky 		max_sge = (min_t(int, wqe_size, 512) -
362c788dceaSHans Petter Selasky 			   sizeof(struct mlx5_wqe_ctrl_seg) -
363c788dceaSHans Petter Selasky 			   sizeof(struct mlx5_wqe_xrc_seg) -
364c788dceaSHans Petter Selasky 			   sizeof(struct mlx5_wqe_raddr_seg)) /
365c788dceaSHans Petter Selasky 			sizeof(struct mlx5_wqe_data_seg);
366c788dceaSHans Petter Selasky 	else
367c788dceaSHans Petter Selasky 		max_sge = (wqe_size - sq_overhead(attr)) /
368c788dceaSHans Petter Selasky 			sizeof(struct mlx5_wqe_data_seg);
369c788dceaSHans Petter Selasky 
370c788dceaSHans Petter Selasky 	return min_t(int, max_sge, wqe_size - sq_overhead(attr) /
371c788dceaSHans Petter Selasky 		     sizeof(struct mlx5_wqe_data_seg));
372c788dceaSHans Petter Selasky }
373c788dceaSHans Petter Selasky 
calc_sq_size(struct mlx5_ib_dev * dev,struct ib_qp_init_attr * attr,struct mlx5_ib_qp * qp)37412515907SHans Petter Selasky static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
37512515907SHans Petter Selasky 			struct mlx5_ib_qp *qp)
37612515907SHans Petter Selasky {
37712515907SHans Petter Selasky 	int wqe_size;
37812515907SHans Petter Selasky 	int wq_size;
37912515907SHans Petter Selasky 
38012515907SHans Petter Selasky 	if (!attr->cap.max_send_wr)
38112515907SHans Petter Selasky 		return 0;
38212515907SHans Petter Selasky 
38312515907SHans Petter Selasky 	wqe_size = calc_send_wqe(attr);
38412515907SHans Petter Selasky 	mlx5_ib_dbg(dev, "wqe_size %d\n", wqe_size);
38512515907SHans Petter Selasky 	if (wqe_size < 0)
38612515907SHans Petter Selasky 		return wqe_size;
38712515907SHans Petter Selasky 
38812515907SHans Petter Selasky 	if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) {
3898e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n",
39012515907SHans Petter Selasky 			    wqe_size, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq));
39112515907SHans Petter Selasky 		return -EINVAL;
39212515907SHans Petter Selasky 	}
39312515907SHans Petter Selasky 
3948e6e287fSHans Petter Selasky 	qp->max_inline_data = wqe_size - sq_overhead(attr) -
39512515907SHans Petter Selasky 			      sizeof(struct mlx5_wqe_inline_seg);
39612515907SHans Petter Selasky 	attr->cap.max_inline_data = qp->max_inline_data;
39712515907SHans Petter Selasky 
3988e6e287fSHans Petter Selasky 	if (attr->create_flags & IB_QP_CREATE_SIGNATURE_EN)
3998e6e287fSHans Petter Selasky 		qp->signature_en = true;
4008e6e287fSHans Petter Selasky 
4018e6e287fSHans Petter Selasky 	wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size);
40212515907SHans Petter Selasky 	qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
40312515907SHans Petter Selasky 	if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) {
4048e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "wqe count(%d) exceeds limits(%d)\n",
40512515907SHans Petter Selasky 			    qp->sq.wqe_cnt,
40612515907SHans Petter Selasky 			    1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz));
40712515907SHans Petter Selasky 		return -ENOMEM;
40812515907SHans Petter Selasky 	}
40912515907SHans Petter Selasky 	qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
410c788dceaSHans Petter Selasky 	qp->sq.max_gs = get_send_sge(attr, wqe_size);
411c788dceaSHans Petter Selasky 	if (qp->sq.max_gs < attr->cap.max_send_sge)
412c788dceaSHans Petter Selasky 		return -ENOMEM;
413c788dceaSHans Petter Selasky 
414c788dceaSHans Petter Selasky 	attr->cap.max_send_sge = qp->sq.max_gs;
41512515907SHans Petter Selasky 	qp->sq.max_post = wq_size / wqe_size;
41612515907SHans Petter Selasky 	attr->cap.max_send_wr = qp->sq.max_post;
41712515907SHans Petter Selasky 
41812515907SHans Petter Selasky 	return wq_size;
41912515907SHans Petter Selasky }
42012515907SHans Petter Selasky 
set_user_buf_size(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,struct mlx5_ib_create_qp * ucmd,struct mlx5_ib_qp_base * base,struct ib_qp_init_attr * attr)42112515907SHans Petter Selasky static int set_user_buf_size(struct mlx5_ib_dev *dev,
42212515907SHans Petter Selasky 			    struct mlx5_ib_qp *qp,
42312515907SHans Petter Selasky 			    struct mlx5_ib_create_qp *ucmd,
4248e6e287fSHans Petter Selasky 			    struct mlx5_ib_qp_base *base,
42512515907SHans Petter Selasky 			    struct ib_qp_init_attr *attr)
42612515907SHans Petter Selasky {
42712515907SHans Petter Selasky 	int desc_sz = 1 << qp->sq.wqe_shift;
42812515907SHans Petter Selasky 
42912515907SHans Petter Selasky 	if (desc_sz > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) {
43012515907SHans Petter Selasky 		mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n",
43112515907SHans Petter Selasky 			     desc_sz, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq));
43212515907SHans Petter Selasky 		return -EINVAL;
43312515907SHans Petter Selasky 	}
43412515907SHans Petter Selasky 
43512515907SHans Petter Selasky 	if (ucmd->sq_wqe_count && ((1 << ilog2(ucmd->sq_wqe_count)) != ucmd->sq_wqe_count)) {
43612515907SHans Petter Selasky 		mlx5_ib_warn(dev, "sq_wqe_count %d, sq_wqe_count %d\n",
43712515907SHans Petter Selasky 			     ucmd->sq_wqe_count, ucmd->sq_wqe_count);
43812515907SHans Petter Selasky 		return -EINVAL;
43912515907SHans Petter Selasky 	}
44012515907SHans Petter Selasky 
44112515907SHans Petter Selasky 	qp->sq.wqe_cnt = ucmd->sq_wqe_count;
44212515907SHans Petter Selasky 
44312515907SHans Petter Selasky 	if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) {
44412515907SHans Petter Selasky 		mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n",
44512515907SHans Petter Selasky 			     qp->sq.wqe_cnt,
44612515907SHans Petter Selasky 			     1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz));
44712515907SHans Petter Selasky 		return -EINVAL;
44812515907SHans Petter Selasky 	}
44912515907SHans Petter Selasky 
45012515907SHans Petter Selasky 	if (attr->qp_type == IB_QPT_RAW_PACKET) {
4518e6e287fSHans Petter Selasky 		base->ubuffer.buf_size = qp->rq.wqe_cnt << qp->rq.wqe_shift;
4528e6e287fSHans Petter Selasky 		qp->raw_packet_qp.sq.ubuffer.buf_size = qp->sq.wqe_cnt << 6;
45312515907SHans Petter Selasky 	} else {
4548e6e287fSHans Petter Selasky 		base->ubuffer.buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) +
45512515907SHans Petter Selasky 					 (qp->sq.wqe_cnt << 6);
45612515907SHans Petter Selasky 	}
45712515907SHans Petter Selasky 
45812515907SHans Petter Selasky 	return 0;
45912515907SHans Petter Selasky }
46012515907SHans Petter Selasky 
qp_has_rq(struct ib_qp_init_attr * attr)46112515907SHans Petter Selasky static int qp_has_rq(struct ib_qp_init_attr *attr)
46212515907SHans Petter Selasky {
46312515907SHans Petter Selasky 	if (attr->qp_type == IB_QPT_XRC_INI ||
46412515907SHans Petter Selasky 	    attr->qp_type == IB_QPT_XRC_TGT || attr->srq ||
4658e6e287fSHans Petter Selasky 	    attr->qp_type == MLX5_IB_QPT_REG_UMR ||
46612515907SHans Petter Selasky 	    !attr->cap.max_recv_wr)
46712515907SHans Petter Selasky 		return 0;
46812515907SHans Petter Selasky 
46912515907SHans Petter Selasky 	return 1;
47012515907SHans Petter Selasky }
47112515907SHans Petter Selasky 
472f8f5b459SHans Petter Selasky enum {
473f8f5b459SHans Petter Selasky 	/* this is the first blue flame register in the array of bfregs assigned
474f8f5b459SHans Petter Selasky 	 * to a processes. Since we do not use it for blue flame but rather
475f8f5b459SHans Petter Selasky 	 * regular 64 bit doorbells, we do not need a lock for maintaiing
476f8f5b459SHans Petter Selasky 	 * "odd/even" order
477f8f5b459SHans Petter Selasky 	 */
478f8f5b459SHans Petter Selasky 	NUM_NON_BLUE_FLAME_BFREGS = 1,
479f8f5b459SHans Petter Selasky };
480f8f5b459SHans Petter Selasky 
max_bfregs(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi)481f8f5b459SHans Petter Selasky static int max_bfregs(struct mlx5_ib_dev *dev, struct mlx5_bfreg_info *bfregi)
48212515907SHans Petter Selasky {
483f8f5b459SHans Petter Selasky 	return get_num_static_uars(dev, bfregi) * MLX5_NON_FP_BFREGS_PER_UAR;
48412515907SHans Petter Selasky }
48512515907SHans Petter Selasky 
num_med_bfreg(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi)486f8f5b459SHans Petter Selasky static int num_med_bfreg(struct mlx5_ib_dev *dev,
487f8f5b459SHans Petter Selasky 			 struct mlx5_bfreg_info *bfregi)
48812515907SHans Petter Selasky {
48912515907SHans Petter Selasky 	int n;
49012515907SHans Petter Selasky 
491f8f5b459SHans Petter Selasky 	n = max_bfregs(dev, bfregi) - bfregi->num_low_latency_bfregs -
492f8f5b459SHans Petter Selasky 	    NUM_NON_BLUE_FLAME_BFREGS;
49312515907SHans Petter Selasky 
49412515907SHans Petter Selasky 	return n >= 0 ? n : 0;
49512515907SHans Petter Selasky }
49612515907SHans Petter Selasky 
first_med_bfreg(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi)497f8f5b459SHans Petter Selasky static int first_med_bfreg(struct mlx5_ib_dev *dev,
498f8f5b459SHans Petter Selasky 			   struct mlx5_bfreg_info *bfregi)
49912515907SHans Petter Selasky {
500f8f5b459SHans Petter Selasky 	return num_med_bfreg(dev, bfregi) ? 1 : -ENOMEM;
50112515907SHans Petter Selasky }
50212515907SHans Petter Selasky 
first_hi_bfreg(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi)503f8f5b459SHans Petter Selasky static int first_hi_bfreg(struct mlx5_ib_dev *dev,
504f8f5b459SHans Petter Selasky 			  struct mlx5_bfreg_info *bfregi)
50512515907SHans Petter Selasky {
50612515907SHans Petter Selasky 	int med;
50712515907SHans Petter Selasky 
508f8f5b459SHans Petter Selasky 	med = num_med_bfreg(dev, bfregi);
509f8f5b459SHans Petter Selasky 	return ++med;
51012515907SHans Petter Selasky }
51112515907SHans Petter Selasky 
alloc_high_class_bfreg(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi)512f8f5b459SHans Petter Selasky static int alloc_high_class_bfreg(struct mlx5_ib_dev *dev,
513f8f5b459SHans Petter Selasky 				  struct mlx5_bfreg_info *bfregi)
51412515907SHans Petter Selasky {
51512515907SHans Petter Selasky 	int i;
51612515907SHans Petter Selasky 
517f8f5b459SHans Petter Selasky 	for (i = first_hi_bfreg(dev, bfregi); i < max_bfregs(dev, bfregi); i++) {
518f8f5b459SHans Petter Selasky 		if (!bfregi->count[i]) {
519f8f5b459SHans Petter Selasky 			bfregi->count[i]++;
52012515907SHans Petter Selasky 			return i;
52112515907SHans Petter Selasky 		}
52212515907SHans Petter Selasky 	}
52312515907SHans Petter Selasky 
52412515907SHans Petter Selasky 	return -ENOMEM;
52512515907SHans Petter Selasky }
52612515907SHans Petter Selasky 
alloc_med_class_bfreg(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi)527f8f5b459SHans Petter Selasky static int alloc_med_class_bfreg(struct mlx5_ib_dev *dev,
528f8f5b459SHans Petter Selasky 				 struct mlx5_bfreg_info *bfregi)
52912515907SHans Petter Selasky {
530f8f5b459SHans Petter Selasky 	int minidx = first_med_bfreg(dev, bfregi);
53112515907SHans Petter Selasky 	int i;
53212515907SHans Petter Selasky 
533f8f5b459SHans Petter Selasky 	if (minidx < 0)
534f8f5b459SHans Petter Selasky 		return minidx;
535f8f5b459SHans Petter Selasky 
536f8f5b459SHans Petter Selasky 	for (i = minidx; i < first_hi_bfreg(dev, bfregi); i++) {
537f8f5b459SHans Petter Selasky 		if (bfregi->count[i] < bfregi->count[minidx])
53812515907SHans Petter Selasky 			minidx = i;
539f8f5b459SHans Petter Selasky 		if (!bfregi->count[minidx])
540f8f5b459SHans Petter Selasky 			break;
54112515907SHans Petter Selasky 	}
54212515907SHans Petter Selasky 
543f8f5b459SHans Petter Selasky 	bfregi->count[minidx]++;
54412515907SHans Petter Selasky 	return minidx;
54512515907SHans Petter Selasky }
54612515907SHans Petter Selasky 
alloc_bfreg(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi)547f8f5b459SHans Petter Selasky static int alloc_bfreg(struct mlx5_ib_dev *dev,
548f8f5b459SHans Petter Selasky 		       struct mlx5_bfreg_info *bfregi)
54912515907SHans Petter Selasky {
550f8f5b459SHans Petter Selasky 	int bfregn = -ENOMEM;
55112515907SHans Petter Selasky 
552f8f5b459SHans Petter Selasky 	if (bfregi->lib_uar_dyn)
553f8f5b459SHans Petter Selasky 		return -EINVAL;
55412515907SHans Petter Selasky 
555f8f5b459SHans Petter Selasky 	mutex_lock(&bfregi->lock);
556f8f5b459SHans Petter Selasky 	if (bfregi->ver >= 2) {
557f8f5b459SHans Petter Selasky 		bfregn = alloc_high_class_bfreg(dev, bfregi);
558f8f5b459SHans Petter Selasky 		if (bfregn < 0)
559f8f5b459SHans Petter Selasky 			bfregn = alloc_med_class_bfreg(dev, bfregi);
56012515907SHans Petter Selasky 	}
56112515907SHans Petter Selasky 
562f8f5b459SHans Petter Selasky 	if (bfregn < 0) {
563f8f5b459SHans Petter Selasky 		BUILD_BUG_ON(NUM_NON_BLUE_FLAME_BFREGS != 1);
564f8f5b459SHans Petter Selasky 		bfregn = 0;
565f8f5b459SHans Petter Selasky 		bfregi->count[bfregn]++;
566f8f5b459SHans Petter Selasky 	}
567f8f5b459SHans Petter Selasky 	mutex_unlock(&bfregi->lock);
568f8f5b459SHans Petter Selasky 
569f8f5b459SHans Petter Selasky 	return bfregn;
570f8f5b459SHans Petter Selasky }
571f8f5b459SHans Petter Selasky 
mlx5_ib_free_bfreg(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi,int bfregn)572f8f5b459SHans Petter Selasky void mlx5_ib_free_bfreg(struct mlx5_ib_dev *dev, struct mlx5_bfreg_info *bfregi, int bfregn)
57312515907SHans Petter Selasky {
574f8f5b459SHans Petter Selasky 	mutex_lock(&bfregi->lock);
575f8f5b459SHans Petter Selasky 	bfregi->count[bfregn]--;
576f8f5b459SHans Petter Selasky 	mutex_unlock(&bfregi->lock);
57712515907SHans Petter Selasky }
57812515907SHans Petter Selasky 
to_mlx5_state(enum ib_qp_state state)57912515907SHans Petter Selasky static enum mlx5_qp_state to_mlx5_state(enum ib_qp_state state)
58012515907SHans Petter Selasky {
58112515907SHans Petter Selasky 	switch (state) {
58212515907SHans Petter Selasky 	case IB_QPS_RESET:	return MLX5_QP_STATE_RST;
58312515907SHans Petter Selasky 	case IB_QPS_INIT:	return MLX5_QP_STATE_INIT;
58412515907SHans Petter Selasky 	case IB_QPS_RTR:	return MLX5_QP_STATE_RTR;
58512515907SHans Petter Selasky 	case IB_QPS_RTS:	return MLX5_QP_STATE_RTS;
58612515907SHans Petter Selasky 	case IB_QPS_SQD:	return MLX5_QP_STATE_SQD;
58712515907SHans Petter Selasky 	case IB_QPS_SQE:	return MLX5_QP_STATE_SQER;
58812515907SHans Petter Selasky 	case IB_QPS_ERR:	return MLX5_QP_STATE_ERR;
58912515907SHans Petter Selasky 	default:		return -1;
59012515907SHans Petter Selasky 	}
59112515907SHans Petter Selasky }
59212515907SHans Petter Selasky 
to_mlx5_st(enum ib_qp_type type)59312515907SHans Petter Selasky static int to_mlx5_st(enum ib_qp_type type)
59412515907SHans Petter Selasky {
59512515907SHans Petter Selasky 	switch (type) {
59612515907SHans Petter Selasky 	case IB_QPT_RC:			return MLX5_QP_ST_RC;
59712515907SHans Petter Selasky 	case IB_QPT_UC:			return MLX5_QP_ST_UC;
59812515907SHans Petter Selasky 	case IB_QPT_UD:			return MLX5_QP_ST_UD;
5998e6e287fSHans Petter Selasky 	case MLX5_IB_QPT_REG_UMR:	return MLX5_QP_ST_REG_UMR;
60012515907SHans Petter Selasky 	case IB_QPT_XRC_INI:
60112515907SHans Petter Selasky 	case IB_QPT_XRC_TGT:		return MLX5_QP_ST_XRC;
60212515907SHans Petter Selasky 	case IB_QPT_SMI:		return MLX5_QP_ST_QP0;
6038e6e287fSHans Petter Selasky 	case MLX5_IB_QPT_HW_GSI:	return MLX5_QP_ST_QP1;
60412515907SHans Petter Selasky 	case IB_QPT_RAW_IPV6:		return MLX5_QP_ST_RAW_IPV6;
60512515907SHans Petter Selasky 	case IB_QPT_RAW_PACKET:
60612515907SHans Petter Selasky 	case IB_QPT_RAW_ETHERTYPE:	return MLX5_QP_ST_RAW_ETHERTYPE;
60712515907SHans Petter Selasky 	case IB_QPT_MAX:
60812515907SHans Petter Selasky 	default:		return -EINVAL;
60912515907SHans Petter Selasky 	}
61012515907SHans Petter Selasky }
61112515907SHans Petter Selasky 
61212515907SHans Petter Selasky static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq,
61312515907SHans Petter Selasky 			     struct mlx5_ib_cq *recv_cq);
61412515907SHans Petter Selasky static void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq,
61512515907SHans Petter Selasky 			       struct mlx5_ib_cq *recv_cq);
61612515907SHans Petter Selasky 
bfregn_to_uar_index(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi,u32 bfregn,bool dyn_bfreg)617f8f5b459SHans Petter Selasky int bfregn_to_uar_index(struct mlx5_ib_dev *dev,
618f8f5b459SHans Petter Selasky 			struct mlx5_bfreg_info *bfregi, u32 bfregn,
619f8f5b459SHans Petter Selasky 			bool dyn_bfreg)
62012515907SHans Petter Selasky {
621f8f5b459SHans Petter Selasky 	unsigned int bfregs_per_sys_page;
622f8f5b459SHans Petter Selasky 	u32 index_of_sys_page;
623f8f5b459SHans Petter Selasky 	u32 offset;
624f8f5b459SHans Petter Selasky 
625f8f5b459SHans Petter Selasky 	if (bfregi->lib_uar_dyn)
626f8f5b459SHans Petter Selasky 		return -EINVAL;
627f8f5b459SHans Petter Selasky 
628f8f5b459SHans Petter Selasky 	bfregs_per_sys_page = get_uars_per_sys_page(dev, bfregi->lib_uar_4k) *
629f8f5b459SHans Petter Selasky 				MLX5_NON_FP_BFREGS_PER_UAR;
630f8f5b459SHans Petter Selasky 	index_of_sys_page = bfregn / bfregs_per_sys_page;
631f8f5b459SHans Petter Selasky 
632f8f5b459SHans Petter Selasky 	if (dyn_bfreg) {
633f8f5b459SHans Petter Selasky 		index_of_sys_page += bfregi->num_static_sys_pages;
634f8f5b459SHans Petter Selasky 
635f8f5b459SHans Petter Selasky 		if (index_of_sys_page >= bfregi->num_sys_pages)
636f8f5b459SHans Petter Selasky 			return -EINVAL;
637f8f5b459SHans Petter Selasky 
638f8f5b459SHans Petter Selasky 		if (bfregn > bfregi->num_dyn_bfregs ||
639f8f5b459SHans Petter Selasky 		    bfregi->sys_pages[index_of_sys_page] == MLX5_IB_INVALID_UAR_INDEX) {
640f8f5b459SHans Petter Selasky 			mlx5_ib_dbg(dev, "Invalid dynamic uar index\n");
641f8f5b459SHans Petter Selasky 			return -EINVAL;
642f8f5b459SHans Petter Selasky 		}
643f8f5b459SHans Petter Selasky 	}
644f8f5b459SHans Petter Selasky 
645f8f5b459SHans Petter Selasky 	offset = bfregn % bfregs_per_sys_page / MLX5_NON_FP_BFREGS_PER_UAR;
646f8f5b459SHans Petter Selasky 	return bfregi->sys_pages[index_of_sys_page] + offset;
64712515907SHans Petter Selasky }
64812515907SHans Petter Selasky 
mlx5_ib_umem_get(struct mlx5_ib_dev * dev,struct ib_pd * pd,unsigned long addr,size_t size,struct ib_umem ** umem,int * npages,int * page_shift,int * ncont,u32 * offset)6498e6e287fSHans Petter Selasky static int mlx5_ib_umem_get(struct mlx5_ib_dev *dev,
6508e6e287fSHans Petter Selasky 			    struct ib_pd *pd,
6518e6e287fSHans Petter Selasky 			    unsigned long addr, size_t size,
6528e6e287fSHans Petter Selasky 			    struct ib_umem **umem,
6538e6e287fSHans Petter Selasky 			    int *npages, int *page_shift, int *ncont,
6548e6e287fSHans Petter Selasky 			    u32 *offset)
6558e6e287fSHans Petter Selasky {
6568e6e287fSHans Petter Selasky 	int err;
6578e6e287fSHans Petter Selasky 
6588e6e287fSHans Petter Selasky 	*umem = ib_umem_get(pd->uobject->context, addr, size, 0, 0);
6598e6e287fSHans Petter Selasky 	if (IS_ERR(*umem)) {
6608e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "umem_get failed\n");
6618e6e287fSHans Petter Selasky 		return PTR_ERR(*umem);
6628e6e287fSHans Petter Selasky 	}
6638e6e287fSHans Petter Selasky 
664565cb4e8SHans Petter Selasky 	mlx5_ib_cont_pages(*umem, addr, 0, npages, page_shift, ncont, NULL);
6658e6e287fSHans Petter Selasky 
6668e6e287fSHans Petter Selasky 	err = mlx5_ib_get_buf_offset(addr, *page_shift, offset);
6678e6e287fSHans Petter Selasky 	if (err) {
6688e6e287fSHans Petter Selasky 		mlx5_ib_warn(dev, "bad offset\n");
6698e6e287fSHans Petter Selasky 		goto err_umem;
6708e6e287fSHans Petter Selasky 	}
6718e6e287fSHans Petter Selasky 
6728e6e287fSHans Petter Selasky 	mlx5_ib_dbg(dev, "addr 0x%lx, size %zu, npages %d, page_shift %d, ncont %d, offset %d\n",
6738e6e287fSHans Petter Selasky 		    addr, size, *npages, *page_shift, *ncont, *offset);
6748e6e287fSHans Petter Selasky 
6758e6e287fSHans Petter Selasky 	return 0;
6768e6e287fSHans Petter Selasky 
6778e6e287fSHans Petter Selasky err_umem:
6788e6e287fSHans Petter Selasky 	ib_umem_release(*umem);
6798e6e287fSHans Petter Selasky 	*umem = NULL;
6808e6e287fSHans Petter Selasky 
6818e6e287fSHans Petter Selasky 	return err;
6828e6e287fSHans Petter Selasky }
6838e6e287fSHans Petter Selasky 
destroy_user_rq(struct ib_pd * pd,struct mlx5_ib_rwq * rwq,struct ib_udata * udata)684b633e08cSHans Petter Selasky static void destroy_user_rq(struct ib_pd *pd, struct mlx5_ib_rwq *rwq,
685b633e08cSHans Petter Selasky 			    struct ib_udata *udata)
6868e6e287fSHans Petter Selasky {
687b633e08cSHans Petter Selasky 	struct mlx5_ib_ucontext *context =
688b633e08cSHans Petter Selasky 		rdma_udata_to_drv_context(
689b633e08cSHans Petter Selasky 			udata,
690b633e08cSHans Petter Selasky 			struct mlx5_ib_ucontext,
691b633e08cSHans Petter Selasky 			ibucontext);
6928e6e287fSHans Petter Selasky 
6938e6e287fSHans Petter Selasky 	mlx5_ib_db_unmap_user(context, &rwq->db);
6948e6e287fSHans Petter Selasky 	if (rwq->umem)
6958e6e287fSHans Petter Selasky 		ib_umem_release(rwq->umem);
6968e6e287fSHans Petter Selasky }
6978e6e287fSHans Petter Selasky 
create_user_rq(struct mlx5_ib_dev * dev,struct ib_pd * pd,struct mlx5_ib_rwq * rwq,struct mlx5_ib_create_wq * ucmd)6988e6e287fSHans Petter Selasky static int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd,
6998e6e287fSHans Petter Selasky 			  struct mlx5_ib_rwq *rwq,
7008e6e287fSHans Petter Selasky 			  struct mlx5_ib_create_wq *ucmd)
7018e6e287fSHans Petter Selasky {
7028e6e287fSHans Petter Selasky 	struct mlx5_ib_ucontext *context;
7038e6e287fSHans Petter Selasky 	int page_shift = 0;
7048e6e287fSHans Petter Selasky 	int npages;
7058e6e287fSHans Petter Selasky 	u32 offset = 0;
7068e6e287fSHans Petter Selasky 	int ncont = 0;
7078e6e287fSHans Petter Selasky 	int err;
7088e6e287fSHans Petter Selasky 
7098e6e287fSHans Petter Selasky 	if (!ucmd->buf_addr)
7108e6e287fSHans Petter Selasky 		return -EINVAL;
7118e6e287fSHans Petter Selasky 
7128e6e287fSHans Petter Selasky 	context = to_mucontext(pd->uobject->context);
7138e6e287fSHans Petter Selasky 	rwq->umem = ib_umem_get(pd->uobject->context, ucmd->buf_addr,
7148e6e287fSHans Petter Selasky 			       rwq->buf_size, 0, 0);
7158e6e287fSHans Petter Selasky 	if (IS_ERR(rwq->umem)) {
7168e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "umem_get failed\n");
7178e6e287fSHans Petter Selasky 		err = PTR_ERR(rwq->umem);
7188e6e287fSHans Petter Selasky 		return err;
7198e6e287fSHans Petter Selasky 	}
7208e6e287fSHans Petter Selasky 
721565cb4e8SHans Petter Selasky 	mlx5_ib_cont_pages(rwq->umem, ucmd->buf_addr, 0, &npages, &page_shift,
7228e6e287fSHans Petter Selasky 			   &ncont, NULL);
7238e6e287fSHans Petter Selasky 	err = mlx5_ib_get_buf_offset(ucmd->buf_addr, page_shift,
7248e6e287fSHans Petter Selasky 				     &rwq->rq_page_offset);
7258e6e287fSHans Petter Selasky 	if (err) {
7268e6e287fSHans Petter Selasky 		mlx5_ib_warn(dev, "bad offset\n");
7278e6e287fSHans Petter Selasky 		goto err_umem;
7288e6e287fSHans Petter Selasky 	}
7298e6e287fSHans Petter Selasky 
7308e6e287fSHans Petter Selasky 	rwq->rq_num_pas = ncont;
7318e6e287fSHans Petter Selasky 	rwq->page_shift = page_shift;
7328e6e287fSHans Petter Selasky 	rwq->log_page_size =  page_shift - MLX5_ADAPTER_PAGE_SHIFT;
7338e6e287fSHans Petter Selasky 	rwq->wq_sig = !!(ucmd->flags & MLX5_WQ_FLAG_SIGNATURE);
7348e6e287fSHans Petter Selasky 
7358e6e287fSHans Petter Selasky 	mlx5_ib_dbg(dev, "addr 0x%llx, size %zd, npages %d, page_shift %d, ncont %d, offset %d\n",
7368e6e287fSHans Petter Selasky 		    (unsigned long long)ucmd->buf_addr, rwq->buf_size,
7378e6e287fSHans Petter Selasky 		    npages, page_shift, ncont, offset);
7388e6e287fSHans Petter Selasky 
7398e6e287fSHans Petter Selasky 	err = mlx5_ib_db_map_user(context, ucmd->db_addr, &rwq->db);
7408e6e287fSHans Petter Selasky 	if (err) {
7418e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "map failed\n");
7428e6e287fSHans Petter Selasky 		goto err_umem;
7438e6e287fSHans Petter Selasky 	}
7448e6e287fSHans Petter Selasky 
7458e6e287fSHans Petter Selasky 	rwq->create_type = MLX5_WQ_USER;
7468e6e287fSHans Petter Selasky 	return 0;
7478e6e287fSHans Petter Selasky 
7488e6e287fSHans Petter Selasky err_umem:
7498e6e287fSHans Petter Selasky 	ib_umem_release(rwq->umem);
7508e6e287fSHans Petter Selasky 	return err;
7518e6e287fSHans Petter Selasky }
7528e6e287fSHans Petter Selasky 
adjust_bfregn(struct mlx5_ib_dev * dev,struct mlx5_bfreg_info * bfregi,int bfregn)753f8f5b459SHans Petter Selasky static int adjust_bfregn(struct mlx5_ib_dev *dev,
754f8f5b459SHans Petter Selasky 			 struct mlx5_bfreg_info *bfregi, int bfregn)
755f8f5b459SHans Petter Selasky {
756f8f5b459SHans Petter Selasky 	return bfregn / MLX5_NON_FP_BFREGS_PER_UAR * MLX5_BFREGS_PER_UAR +
757f8f5b459SHans Petter Selasky 				bfregn % MLX5_NON_FP_BFREGS_PER_UAR;
758f8f5b459SHans Petter Selasky }
759f8f5b459SHans Petter Selasky 
create_user_qp(struct mlx5_ib_dev * dev,struct ib_pd * pd,struct mlx5_ib_qp * qp,struct ib_udata * udata,struct ib_qp_init_attr * attr,u32 ** in,struct mlx5_ib_create_qp_resp * resp,int * inlen,struct mlx5_ib_qp_base * base)76012515907SHans Petter Selasky static int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
76112515907SHans Petter Selasky 			  struct mlx5_ib_qp *qp, struct ib_udata *udata,
76212515907SHans Petter Selasky 			  struct ib_qp_init_attr *attr,
7638e6e287fSHans Petter Selasky 			  u32 **in,
7648e6e287fSHans Petter Selasky 			  struct mlx5_ib_create_qp_resp *resp, int *inlen,
7658e6e287fSHans Petter Selasky 			  struct mlx5_ib_qp_base *base)
76612515907SHans Petter Selasky {
76712515907SHans Petter Selasky 	struct mlx5_ib_ucontext *context;
7688e6e287fSHans Petter Selasky 	struct mlx5_ib_create_qp ucmd;
7698e6e287fSHans Petter Selasky 	struct mlx5_ib_ubuffer *ubuffer = &base->ubuffer;
77012515907SHans Petter Selasky 	int page_shift = 0;
771f8f5b459SHans Petter Selasky 	int uar_index = 0;
77212515907SHans Petter Selasky 	int npages;
77312515907SHans Petter Selasky 	u32 offset = 0;
774f8f5b459SHans Petter Selasky 	int bfregn;
77512515907SHans Petter Selasky 	int ncont = 0;
7768e6e287fSHans Petter Selasky 	__be64 *pas;
7778e6e287fSHans Petter Selasky 	void *qpc;
77812515907SHans Petter Selasky 	int err;
779b633e08cSHans Petter Selasky 	u16 uid;
780f8f5b459SHans Petter Selasky 	u32 uar_flags;
78112515907SHans Petter Selasky 
7828e6e287fSHans Petter Selasky 	err = ib_copy_from_udata(&ucmd, udata, sizeof(ucmd));
7838e6e287fSHans Petter Selasky 	if (err) {
7848e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "copy failed\n");
7858e6e287fSHans Petter Selasky 		return err;
7868e6e287fSHans Petter Selasky 	}
7878e6e287fSHans Petter Selasky 
78812515907SHans Petter Selasky 	context = to_mucontext(pd->uobject->context);
789f8f5b459SHans Petter Selasky 	uar_flags = ucmd.flags & (MLX5_QP_FLAG_UAR_PAGE_INDEX |
790f8f5b459SHans Petter Selasky 				  MLX5_QP_FLAG_BFREG_INDEX);
791f8f5b459SHans Petter Selasky 	switch (uar_flags) {
792f8f5b459SHans Petter Selasky 	case MLX5_QP_FLAG_UAR_PAGE_INDEX:
793f8f5b459SHans Petter Selasky 		uar_index = ucmd.bfreg_index;
794f8f5b459SHans Petter Selasky 		bfregn = MLX5_IB_INVALID_BFREG;
795f8f5b459SHans Petter Selasky 		break;
796f8f5b459SHans Petter Selasky 	case MLX5_QP_FLAG_BFREG_INDEX:
797f8f5b459SHans Petter Selasky 		uar_index = bfregn_to_uar_index(dev, &context->bfregi,
798f8f5b459SHans Petter Selasky 						ucmd.bfreg_index, true);
799f8f5b459SHans Petter Selasky 		if (uar_index < 0)
800f8f5b459SHans Petter Selasky 			return uar_index;
801f8f5b459SHans Petter Selasky 		bfregn = MLX5_IB_INVALID_BFREG;
802f8f5b459SHans Petter Selasky 		break;
803f8f5b459SHans Petter Selasky 	case 0:
8048e6e287fSHans Petter Selasky 		if (qp->flags & MLX5_IB_QP_CROSS_CHANNEL)
805f8f5b459SHans Petter Selasky 			return -EINVAL;
806f8f5b459SHans Petter Selasky 		bfregn = alloc_bfreg(dev, &context->bfregi);
807f8f5b459SHans Petter Selasky 		if (bfregn < 0)
808f8f5b459SHans Petter Selasky 			return bfregn;
809f8f5b459SHans Petter Selasky 		break;
810f8f5b459SHans Petter Selasky 	default:
811f8f5b459SHans Petter Selasky 		return -EINVAL;
81212515907SHans Petter Selasky 	}
8138e6e287fSHans Petter Selasky 
814f8f5b459SHans Petter Selasky 	mlx5_ib_dbg(dev, "bfregn 0x%x, uar_index 0x%x\n", bfregn, uar_index);
815f8f5b459SHans Petter Selasky 	if (bfregn != MLX5_IB_INVALID_BFREG)
816f8f5b459SHans Petter Selasky 		uar_index = bfregn_to_uar_index(dev, &context->bfregi, bfregn,
817f8f5b459SHans Petter Selasky 						false);
81812515907SHans Petter Selasky 
81912515907SHans Petter Selasky 	qp->rq.offset = 0;
82012515907SHans Petter Selasky 	qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
82112515907SHans Petter Selasky 	qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift;
82212515907SHans Petter Selasky 
8238e6e287fSHans Petter Selasky 	err = set_user_buf_size(dev, qp, &ucmd, base, attr);
82412515907SHans Petter Selasky 	if (err)
825f8f5b459SHans Petter Selasky 		goto err_bfreg;
82612515907SHans Petter Selasky 
8278e6e287fSHans Petter Selasky 	if (ucmd.buf_addr && ubuffer->buf_size) {
8288e6e287fSHans Petter Selasky 		ubuffer->buf_addr = ucmd.buf_addr;
8298e6e287fSHans Petter Selasky 		err = mlx5_ib_umem_get(dev, pd, ubuffer->buf_addr,
8308e6e287fSHans Petter Selasky 				       ubuffer->buf_size,
8318e6e287fSHans Petter Selasky 				       &ubuffer->umem, &npages, &page_shift,
8328e6e287fSHans Petter Selasky 				       &ncont, &offset);
8338e6e287fSHans Petter Selasky 		if (err)
834f8f5b459SHans Petter Selasky 			goto err_bfreg;
83512515907SHans Petter Selasky 	} else {
8368e6e287fSHans Petter Selasky 		ubuffer->umem = NULL;
83712515907SHans Petter Selasky 	}
83812515907SHans Petter Selasky 
8398e6e287fSHans Petter Selasky 	*inlen = MLX5_ST_SZ_BYTES(create_qp_in) +
8408e6e287fSHans Petter Selasky 		 MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * ncont;
84112515907SHans Petter Selasky 	*in = mlx5_vzalloc(*inlen);
84212515907SHans Petter Selasky 	if (!*in) {
84312515907SHans Petter Selasky 		err = -ENOMEM;
84412515907SHans Petter Selasky 		goto err_umem;
84512515907SHans Petter Selasky 	}
84612515907SHans Petter Selasky 
847b633e08cSHans Petter Selasky 	uid = (attr->qp_type != IB_QPT_XRC_TGT &&
848b633e08cSHans Petter Selasky 	       attr->qp_type != IB_QPT_XRC_INI) ? to_mpd(pd)->uid : 0;
849b633e08cSHans Petter Selasky 	MLX5_SET(create_qp_in, *in, uid, uid);
8508e6e287fSHans Petter Selasky 	pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, *in, pas);
8518e6e287fSHans Petter Selasky 	if (ubuffer->umem)
8528e6e287fSHans Petter Selasky 		mlx5_ib_populate_pas(dev, ubuffer->umem, page_shift, pas, 0);
8538e6e287fSHans Petter Selasky 
8548e6e287fSHans Petter Selasky 	qpc = MLX5_ADDR_OF(create_qp_in, *in, qpc);
8558e6e287fSHans Petter Selasky 
8568e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, log_page_size, page_shift - MLX5_ADAPTER_PAGE_SHIFT);
8578e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, page_offset, offset);
8588e6e287fSHans Petter Selasky 
8598e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, uar_page, uar_index);
860f8f5b459SHans Petter Selasky 	if (bfregn != MLX5_IB_INVALID_BFREG)
861f8f5b459SHans Petter Selasky 		resp->bfreg_index = adjust_bfregn(dev, &context->bfregi, bfregn);
862f8f5b459SHans Petter Selasky 	else
863f8f5b459SHans Petter Selasky 		resp->bfreg_index = MLX5_IB_INVALID_BFREG;
864f8f5b459SHans Petter Selasky 	qp->bfregn = bfregn;
86512515907SHans Petter Selasky 
8668e6e287fSHans Petter Selasky 	err = mlx5_ib_db_map_user(context, ucmd.db_addr, &qp->db);
86712515907SHans Petter Selasky 	if (err) {
8688e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "map failed\n");
86912515907SHans Petter Selasky 		goto err_free;
87012515907SHans Petter Selasky 	}
87112515907SHans Petter Selasky 
8728e6e287fSHans Petter Selasky 	err = ib_copy_to_udata(udata, resp, sizeof(*resp));
87312515907SHans Petter Selasky 	if (err) {
8748e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "copy failed\n");
87512515907SHans Petter Selasky 		goto err_unmap;
87612515907SHans Petter Selasky 	}
87712515907SHans Petter Selasky 	qp->create_type = MLX5_QP_USER;
87812515907SHans Petter Selasky 
87912515907SHans Petter Selasky 	return 0;
88012515907SHans Petter Selasky 
88112515907SHans Petter Selasky err_unmap:
88212515907SHans Petter Selasky 	mlx5_ib_db_unmap_user(context, &qp->db);
88312515907SHans Petter Selasky 
88412515907SHans Petter Selasky err_free:
88512515907SHans Petter Selasky 	kvfree(*in);
88612515907SHans Petter Selasky 
88712515907SHans Petter Selasky err_umem:
8888e6e287fSHans Petter Selasky 	if (ubuffer->umem)
8898e6e287fSHans Petter Selasky 		ib_umem_release(ubuffer->umem);
89012515907SHans Petter Selasky 
891f8f5b459SHans Petter Selasky err_bfreg:
892f8f5b459SHans Petter Selasky 	if (bfregn != MLX5_IB_INVALID_BFREG)
893f8f5b459SHans Petter Selasky 		mlx5_ib_free_bfreg(dev, &context->bfregi, bfregn);
89412515907SHans Petter Selasky 	return err;
89512515907SHans Petter Selasky }
89612515907SHans Petter Selasky 
destroy_qp_user(struct mlx5_ib_dev * dev,struct ib_pd * pd,struct mlx5_ib_qp * qp,struct mlx5_ib_qp_base * base,struct ib_udata * udata)897f8f5b459SHans Petter Selasky static void destroy_qp_user(struct mlx5_ib_dev *dev, struct ib_pd *pd, struct mlx5_ib_qp *qp,
898b633e08cSHans Petter Selasky 			    struct mlx5_ib_qp_base *base,
899b633e08cSHans Petter Selasky 			    struct ib_udata *udata)
90012515907SHans Petter Selasky {
901b633e08cSHans Petter Selasky 	struct mlx5_ib_ucontext *context =
902b633e08cSHans Petter Selasky 		rdma_udata_to_drv_context(
903b633e08cSHans Petter Selasky 			udata,
904b633e08cSHans Petter Selasky 			struct mlx5_ib_ucontext,
905b633e08cSHans Petter Selasky 			ibucontext);
90612515907SHans Petter Selasky 
90712515907SHans Petter Selasky 	mlx5_ib_db_unmap_user(context, &qp->db);
9088e6e287fSHans Petter Selasky 	if (base->ubuffer.umem)
9098e6e287fSHans Petter Selasky 		ib_umem_release(base->ubuffer.umem);
910f8f5b459SHans Petter Selasky 
911f8f5b459SHans Petter Selasky 	/*
912f8f5b459SHans Petter Selasky 	 * Free only the BFREGs which are handled by the kernel.
913f8f5b459SHans Petter Selasky 	 * BFREGs of UARs allocated dynamically are handled by user.
914f8f5b459SHans Petter Selasky 	 */
915f8f5b459SHans Petter Selasky 	if (qp->bfregn != MLX5_IB_INVALID_BFREG)
916f8f5b459SHans Petter Selasky 		mlx5_ib_free_bfreg(dev, &context->bfregi, qp->bfregn);
91712515907SHans Petter Selasky }
91812515907SHans Petter Selasky 
create_kernel_qp(struct mlx5_ib_dev * dev,struct ib_qp_init_attr * init_attr,struct mlx5_ib_qp * qp,u32 ** in,int * inlen,struct mlx5_ib_qp_base * base)91912515907SHans Petter Selasky static int create_kernel_qp(struct mlx5_ib_dev *dev,
92012515907SHans Petter Selasky 			    struct ib_qp_init_attr *init_attr,
92112515907SHans Petter Selasky 			    struct mlx5_ib_qp *qp,
9228e6e287fSHans Petter Selasky 			    u32 **in, int *inlen,
9238e6e287fSHans Petter Selasky 			    struct mlx5_ib_qp_base *base)
92412515907SHans Petter Selasky {
92512515907SHans Petter Selasky 	int uar_index;
9268e6e287fSHans Petter Selasky 	void *qpc;
92712515907SHans Petter Selasky 	int err;
92812515907SHans Petter Selasky 
9298e6e287fSHans Petter Selasky 	if (init_attr->create_flags & ~(IB_QP_CREATE_SIGNATURE_EN |
9308e6e287fSHans Petter Selasky 					IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK |
9318e6e287fSHans Petter Selasky 					IB_QP_CREATE_IPOIB_UD_LSO |
932f8f5b459SHans Petter Selasky 					MLX5_IB_QP_CREATE_SQPN_QP1 |
933f8f5b459SHans Petter Selasky 					MLX5_IB_QP_CREATE_WC_TEST))
93412515907SHans Petter Selasky 		return -EINVAL;
93512515907SHans Petter Selasky 
936f8f5b459SHans Petter Selasky 	spin_lock_init(&qp->bf.lock32);
937f8f5b459SHans Petter Selasky 
9388e6e287fSHans Petter Selasky 	if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR)
939f8f5b459SHans Petter Selasky 		qp->bf.bfreg = &dev->fp_bfreg;
940f8f5b459SHans Petter Selasky 	else if (init_attr->create_flags & MLX5_IB_QP_CREATE_WC_TEST)
941f8f5b459SHans Petter Selasky 		qp->bf.bfreg = &dev->wc_bfreg;
942f8f5b459SHans Petter Selasky 	else
943f8f5b459SHans Petter Selasky 		qp->bf.bfreg = &dev->bfreg;
9448e6e287fSHans Petter Selasky 
945f8f5b459SHans Petter Selasky 	/* We need to divide by two since each register is comprised of
946f8f5b459SHans Petter Selasky 	 * two buffers of identical size, namely odd and even
947f8f5b459SHans Petter Selasky 	 */
948f8f5b459SHans Petter Selasky 	qp->bf.buf_size = (1 << MLX5_CAP_GEN(dev->mdev, log_bf_reg_size)) / 2;
949f8f5b459SHans Petter Selasky 	uar_index = qp->bf.bfreg->index;
95012515907SHans Petter Selasky 
95112515907SHans Petter Selasky 	err = calc_sq_size(dev, init_attr, qp);
95212515907SHans Petter Selasky 	if (err < 0) {
9538e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "err %d\n", err);
954f8f5b459SHans Petter Selasky 		return err;
95512515907SHans Petter Selasky 	}
95612515907SHans Petter Selasky 
95712515907SHans Petter Selasky 	qp->rq.offset = 0;
95812515907SHans Petter Selasky 	qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift;
9598e6e287fSHans Petter Selasky 	base->ubuffer.buf_size = err + (qp->rq.wqe_cnt << qp->rq.wqe_shift);
96012515907SHans Petter Selasky 
9618e6e287fSHans Petter Selasky 	err = mlx5_buf_alloc(dev->mdev, base->ubuffer.buf_size,
9628e6e287fSHans Petter Selasky 	    2 * PAGE_SIZE, &qp->buf);
96312515907SHans Petter Selasky 	if (err) {
9648e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "err %d\n", err);
965f8f5b459SHans Petter Selasky 		return err;
96612515907SHans Petter Selasky 	}
96712515907SHans Petter Selasky 
96812515907SHans Petter Selasky 	qp->sq.qend = mlx5_get_send_wqe(qp, qp->sq.wqe_cnt);
9698e6e287fSHans Petter Selasky 	*inlen = MLX5_ST_SZ_BYTES(create_qp_in) +
9708e6e287fSHans Petter Selasky 		 MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * qp->buf.npages;
97112515907SHans Petter Selasky 	*in = mlx5_vzalloc(*inlen);
97212515907SHans Petter Selasky 	if (!*in) {
97312515907SHans Petter Selasky 		err = -ENOMEM;
97412515907SHans Petter Selasky 		goto err_buf;
97512515907SHans Petter Selasky 	}
97612515907SHans Petter Selasky 
9778e6e287fSHans Petter Selasky 	qpc = MLX5_ADDR_OF(create_qp_in, *in, qpc);
9788e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, uar_page, uar_index);
9794fb0a74eSHans Petter Selasky 	MLX5_SET(qpc, qpc, ts_format, mlx5_get_qp_default_ts(dev->mdev));
9808e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, log_page_size, qp->buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
9818e6e287fSHans Petter Selasky 
9828e6e287fSHans Petter Selasky 	/* Set "fast registration enabled" for all kernel QPs */
9838e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, fre, 1);
9848e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, rlky, 1);
9858e6e287fSHans Petter Selasky 
986f8f5b459SHans Petter Selasky 	if (init_attr->create_flags & MLX5_IB_QP_CREATE_SQPN_QP1) {
9878e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, deth_sqpn, 1);
9888e6e287fSHans Petter Selasky 		qp->flags |= MLX5_IB_QP_SQPN_QP1;
9898e6e287fSHans Petter Selasky 	}
9908e6e287fSHans Petter Selasky 
9918e6e287fSHans Petter Selasky 	mlx5_fill_page_array(&qp->buf,
9928e6e287fSHans Petter Selasky 			     (__be64 *)MLX5_ADDR_OF(create_qp_in, *in, pas));
99312515907SHans Petter Selasky 
99412515907SHans Petter Selasky 	err = mlx5_db_alloc(dev->mdev, &qp->db);
99512515907SHans Petter Selasky 	if (err) {
9968e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "err %d\n", err);
99712515907SHans Petter Selasky 		goto err_free;
99812515907SHans Petter Selasky 	}
99912515907SHans Petter Selasky 
10008e6e287fSHans Petter Selasky 	qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wrid), GFP_KERNEL);
10018e6e287fSHans Petter Selasky 	qp->sq.wr_data = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wr_data), GFP_KERNEL);
10028e6e287fSHans Petter Selasky 	qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof(*qp->rq.wrid), GFP_KERNEL);
10038e6e287fSHans Petter Selasky 	qp->sq.w_list = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.w_list), GFP_KERNEL);
10048e6e287fSHans Petter Selasky 	qp->sq.wqe_head = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wqe_head), GFP_KERNEL);
10058e6e287fSHans Petter Selasky 
10068e6e287fSHans Petter Selasky 	if (!qp->sq.wrid || !qp->sq.wr_data || !qp->rq.wrid ||
10078e6e287fSHans Petter Selasky 	    !qp->sq.w_list || !qp->sq.wqe_head) {
100812515907SHans Petter Selasky 		err = -ENOMEM;
100912515907SHans Petter Selasky 		goto err_wrid;
101012515907SHans Petter Selasky 	}
101112515907SHans Petter Selasky 	qp->create_type = MLX5_QP_KERNEL;
101212515907SHans Petter Selasky 
101312515907SHans Petter Selasky 	return 0;
101412515907SHans Petter Selasky 
101512515907SHans Petter Selasky err_wrid:
10168e6e287fSHans Petter Selasky 	kfree(qp->sq.wqe_head);
10178e6e287fSHans Petter Selasky 	kfree(qp->sq.w_list);
10188e6e287fSHans Petter Selasky 	kfree(qp->sq.wrid);
10198e6e287fSHans Petter Selasky 	kfree(qp->sq.wr_data);
10208e6e287fSHans Petter Selasky 	kfree(qp->rq.wrid);
10218114aeeaSHans Petter Selasky 	mlx5_db_free(dev->mdev, &qp->db);
102212515907SHans Petter Selasky 
102312515907SHans Petter Selasky err_free:
102412515907SHans Petter Selasky 	kvfree(*in);
102512515907SHans Petter Selasky 
102612515907SHans Petter Selasky err_buf:
102712515907SHans Petter Selasky 	mlx5_buf_free(dev->mdev, &qp->buf);
102812515907SHans Petter Selasky 	return err;
102912515907SHans Petter Selasky }
103012515907SHans Petter Selasky 
destroy_qp_kernel(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp)103112515907SHans Petter Selasky static void destroy_qp_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
103212515907SHans Petter Selasky {
10338e6e287fSHans Petter Selasky 	kfree(qp->sq.wqe_head);
10348e6e287fSHans Petter Selasky 	kfree(qp->sq.w_list);
10358e6e287fSHans Petter Selasky 	kfree(qp->sq.wrid);
10368e6e287fSHans Petter Selasky 	kfree(qp->sq.wr_data);
10378e6e287fSHans Petter Selasky 	kfree(qp->rq.wrid);
10388114aeeaSHans Petter Selasky 	mlx5_db_free(dev->mdev, &qp->db);
103912515907SHans Petter Selasky 	mlx5_buf_free(dev->mdev, &qp->buf);
104012515907SHans Petter Selasky }
104112515907SHans Petter Selasky 
get_rx_type(struct mlx5_ib_qp * qp,struct ib_qp_init_attr * attr)10428e6e287fSHans Petter Selasky static u32 get_rx_type(struct mlx5_ib_qp *qp, struct ib_qp_init_attr *attr)
104312515907SHans Petter Selasky {
10448e6e287fSHans Petter Selasky 	if (attr->srq || (attr->qp_type == IB_QPT_XRC_TGT) ||
10458e6e287fSHans Petter Selasky 	    (attr->qp_type == IB_QPT_XRC_INI))
10468e6e287fSHans Petter Selasky 		return MLX5_SRQ_RQ;
104712515907SHans Petter Selasky 	else if (!qp->has_rq)
10488e6e287fSHans Petter Selasky 		return MLX5_ZERO_LEN_RQ;
104912515907SHans Petter Selasky 	else
10508e6e287fSHans Petter Selasky 		return MLX5_NON_ZERO_RQ;
105112515907SHans Petter Selasky }
105212515907SHans Petter Selasky 
is_connected(enum ib_qp_type qp_type)105312515907SHans Petter Selasky static int is_connected(enum ib_qp_type qp_type)
105412515907SHans Petter Selasky {
105512515907SHans Petter Selasky 	if (qp_type == IB_QPT_RC || qp_type == IB_QPT_UC)
105612515907SHans Petter Selasky 		return 1;
105712515907SHans Petter Selasky 
105812515907SHans Petter Selasky 	return 0;
105912515907SHans Petter Selasky }
106012515907SHans Petter Selasky 
create_raw_packet_qp_tis(struct mlx5_ib_dev * dev,struct mlx5_ib_sq * sq,u32 tdn,struct ib_pd * pd)10618e6e287fSHans Petter Selasky static int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
1062b633e08cSHans Petter Selasky 				    struct mlx5_ib_sq *sq, u32 tdn,
1063b633e08cSHans Petter Selasky 				    struct ib_pd *pd)
106412515907SHans Petter Selasky {
10658e6e287fSHans Petter Selasky 	u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {0};
10668e6e287fSHans Petter Selasky 	void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
106712515907SHans Petter Selasky 
1068b633e08cSHans Petter Selasky 	MLX5_SET(create_tis_in, in, uid, to_mpd(pd)->uid);
10698e6e287fSHans Petter Selasky 	MLX5_SET(tisc, tisc, transport_domain, tdn);
10708e6e287fSHans Petter Selasky 	return mlx5_core_create_tis(dev->mdev, in, sizeof(in), &sq->tisn);
10718e6e287fSHans Petter Selasky }
107212515907SHans Petter Selasky 
destroy_raw_packet_qp_tis(struct mlx5_ib_dev * dev,struct mlx5_ib_sq * sq,struct ib_pd * pd)10738e6e287fSHans Petter Selasky static void destroy_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
1074b633e08cSHans Petter Selasky 				      struct mlx5_ib_sq *sq, struct ib_pd *pd)
10758e6e287fSHans Petter Selasky {
1076b633e08cSHans Petter Selasky 	mlx5_core_destroy_tis(dev->mdev, sq->tisn, to_mpd(pd)->uid);
10778e6e287fSHans Petter Selasky }
10788e6e287fSHans Petter Selasky 
create_raw_packet_qp_sq(struct mlx5_ib_dev * dev,struct mlx5_ib_sq * sq,void * qpin,struct ib_pd * pd)10798e6e287fSHans Petter Selasky static int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev,
10808e6e287fSHans Petter Selasky 				   struct mlx5_ib_sq *sq, void *qpin,
10818e6e287fSHans Petter Selasky 				   struct ib_pd *pd)
10828e6e287fSHans Petter Selasky {
10838e6e287fSHans Petter Selasky 	struct mlx5_ib_ubuffer *ubuffer = &sq->ubuffer;
10848e6e287fSHans Petter Selasky 	__be64 *pas;
10858e6e287fSHans Petter Selasky 	void *in;
10868e6e287fSHans Petter Selasky 	void *sqc;
10878e6e287fSHans Petter Selasky 	void *qpc = MLX5_ADDR_OF(create_qp_in, qpin, qpc);
10888e6e287fSHans Petter Selasky 	void *wq;
10898e6e287fSHans Petter Selasky 	int inlen;
10908e6e287fSHans Petter Selasky 	int err;
10918e6e287fSHans Petter Selasky 	int page_shift = 0;
10928e6e287fSHans Petter Selasky 	int npages;
10938e6e287fSHans Petter Selasky 	int ncont = 0;
10948e6e287fSHans Petter Selasky 	u32 offset = 0;
10954fb0a74eSHans Petter Selasky 	u8 ts_format;
10964fb0a74eSHans Petter Selasky 
10974fb0a74eSHans Petter Selasky 	ts_format = mlx5_get_sq_default_ts(dev->mdev);
10988e6e287fSHans Petter Selasky 
10998e6e287fSHans Petter Selasky 	err = mlx5_ib_umem_get(dev, pd, ubuffer->buf_addr, ubuffer->buf_size,
11008e6e287fSHans Petter Selasky 			       &sq->ubuffer.umem, &npages, &page_shift,
11018e6e287fSHans Petter Selasky 			       &ncont, &offset);
11028e6e287fSHans Petter Selasky 	if (err)
11038e6e287fSHans Petter Selasky 		return err;
11048e6e287fSHans Petter Selasky 
11058e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(create_sq_in) + sizeof(u64) * ncont;
11068e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
11078e6e287fSHans Petter Selasky 	if (!in) {
11088e6e287fSHans Petter Selasky 		err = -ENOMEM;
11098e6e287fSHans Petter Selasky 		goto err_umem;
11108e6e287fSHans Petter Selasky 	}
11118e6e287fSHans Petter Selasky 
1112b633e08cSHans Petter Selasky 	MLX5_SET(create_sq_in, in, uid, to_mpd(pd)->uid);
11138e6e287fSHans Petter Selasky 	sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
11148e6e287fSHans Petter Selasky 	MLX5_SET(sqc, sqc, flush_in_error_en, 1);
11158e6e287fSHans Petter Selasky 	MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST);
11164fb0a74eSHans Petter Selasky 	MLX5_SET(sqc, sqc, ts_format, ts_format);
11178e6e287fSHans Petter Selasky 	MLX5_SET(sqc, sqc, user_index, MLX5_GET(qpc, qpc, user_index));
11188e6e287fSHans Petter Selasky 	MLX5_SET(sqc, sqc, cqn, MLX5_GET(qpc, qpc, cqn_snd));
11198e6e287fSHans Petter Selasky 	MLX5_SET(sqc, sqc, tis_lst_sz, 1);
11208e6e287fSHans Petter Selasky 	MLX5_SET(sqc, sqc, tis_num_0, sq->tisn);
11218e6e287fSHans Petter Selasky 
11228e6e287fSHans Petter Selasky 	wq = MLX5_ADDR_OF(sqc, sqc, wq);
11238e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
11248e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, pd, MLX5_GET(qpc, qpc, pd));
11258e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, uar_page, MLX5_GET(qpc, qpc, uar_page));
11268e6e287fSHans Petter Selasky 	MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(qpc, qpc, dbr_addr));
11278e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB));
11288e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, log_wq_sz, MLX5_GET(qpc, qpc, log_sq_size));
11298e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, log_wq_pg_sz,  page_shift - MLX5_ADAPTER_PAGE_SHIFT);
11308e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, page_offset, offset);
11318e6e287fSHans Petter Selasky 
11328e6e287fSHans Petter Selasky 	pas = (__be64 *)MLX5_ADDR_OF(wq, wq, pas);
11338e6e287fSHans Petter Selasky 	mlx5_ib_populate_pas(dev, sq->ubuffer.umem, page_shift, pas, 0);
11348e6e287fSHans Petter Selasky 
11358e6e287fSHans Petter Selasky 	err = mlx5_core_create_sq_tracked(dev->mdev, in, inlen, &sq->base.mqp);
11368e6e287fSHans Petter Selasky 
11378e6e287fSHans Petter Selasky 	kvfree(in);
11388e6e287fSHans Petter Selasky 
11398e6e287fSHans Petter Selasky 	if (err)
11408e6e287fSHans Petter Selasky 		goto err_umem;
11418e6e287fSHans Petter Selasky 
11428e6e287fSHans Petter Selasky 	return 0;
11438e6e287fSHans Petter Selasky 
11448e6e287fSHans Petter Selasky err_umem:
11458e6e287fSHans Petter Selasky 	ib_umem_release(sq->ubuffer.umem);
11468e6e287fSHans Petter Selasky 	sq->ubuffer.umem = NULL;
11478e6e287fSHans Petter Selasky 
11488e6e287fSHans Petter Selasky 	return err;
11498e6e287fSHans Petter Selasky }
11508e6e287fSHans Petter Selasky 
destroy_raw_packet_qp_sq(struct mlx5_ib_dev * dev,struct mlx5_ib_sq * sq)11518e6e287fSHans Petter Selasky static void destroy_raw_packet_qp_sq(struct mlx5_ib_dev *dev,
11528e6e287fSHans Petter Selasky 				     struct mlx5_ib_sq *sq)
11538e6e287fSHans Petter Selasky {
11548e6e287fSHans Petter Selasky 	mlx5_core_destroy_sq_tracked(dev->mdev, &sq->base.mqp);
11558e6e287fSHans Petter Selasky 	ib_umem_release(sq->ubuffer.umem);
11568e6e287fSHans Petter Selasky }
11578e6e287fSHans Petter Selasky 
get_rq_pas_size(void * qpc)11588e6e287fSHans Petter Selasky static int get_rq_pas_size(void *qpc)
11598e6e287fSHans Petter Selasky {
11608e6e287fSHans Petter Selasky 	u32 log_page_size = MLX5_GET(qpc, qpc, log_page_size) + 12;
11618e6e287fSHans Petter Selasky 	u32 log_rq_stride = MLX5_GET(qpc, qpc, log_rq_stride);
11628e6e287fSHans Petter Selasky 	u32 log_rq_size   = MLX5_GET(qpc, qpc, log_rq_size);
11638e6e287fSHans Petter Selasky 	u32 page_offset   = MLX5_GET(qpc, qpc, page_offset);
11648e6e287fSHans Petter Selasky 	u32 po_quanta	  = 1 << (log_page_size - 6);
11658e6e287fSHans Petter Selasky 	u32 rq_sz	  = 1 << (log_rq_size + 4 + log_rq_stride);
11668e6e287fSHans Petter Selasky 	u32 page_size	  = 1 << log_page_size;
11678e6e287fSHans Petter Selasky 	u32 rq_sz_po      = rq_sz + (page_offset * po_quanta);
11688e6e287fSHans Petter Selasky 	u32 rq_num_pas	  = (rq_sz_po + page_size - 1) / page_size;
11698e6e287fSHans Petter Selasky 
11708e6e287fSHans Petter Selasky 	return rq_num_pas * sizeof(u64);
11718e6e287fSHans Petter Selasky }
11728e6e287fSHans Petter Selasky 
create_raw_packet_qp_rq(struct mlx5_ib_dev * dev,struct mlx5_ib_rq * rq,void * qpin,struct ib_pd * pd)11738e6e287fSHans Petter Selasky static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
1174b633e08cSHans Petter Selasky 				   struct mlx5_ib_rq *rq, void *qpin,
1175b633e08cSHans Petter Selasky 				   struct ib_pd *pd)
11768e6e287fSHans Petter Selasky {
11778e6e287fSHans Petter Selasky 	struct mlx5_ib_qp *mqp = rq->base.container_mibqp;
11788e6e287fSHans Petter Selasky 	__be64 *pas;
11798e6e287fSHans Petter Selasky 	__be64 *qp_pas;
11808e6e287fSHans Petter Selasky 	void *in;
11818e6e287fSHans Petter Selasky 	void *rqc;
11828e6e287fSHans Petter Selasky 	void *wq;
11838e6e287fSHans Petter Selasky 	void *qpc = MLX5_ADDR_OF(create_qp_in, qpin, qpc);
11848e6e287fSHans Petter Selasky 	int inlen;
11858e6e287fSHans Petter Selasky 	int err;
11868e6e287fSHans Petter Selasky 	u32 rq_pas_size = get_rq_pas_size(qpc);
11874fb0a74eSHans Petter Selasky 	u8 ts_format;
11884fb0a74eSHans Petter Selasky 
11894fb0a74eSHans Petter Selasky 	ts_format = mlx5_get_rq_default_ts(dev->mdev);
11908e6e287fSHans Petter Selasky 
11918e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(create_rq_in) + rq_pas_size;
11928e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
11938e6e287fSHans Petter Selasky 	if (!in)
11948e6e287fSHans Petter Selasky 		return -ENOMEM;
11958e6e287fSHans Petter Selasky 
1196b633e08cSHans Petter Selasky 	MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid);
11978e6e287fSHans Petter Selasky 	rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
11988e6e287fSHans Petter Selasky 	MLX5_SET(rqc, rqc, vlan_strip_disable, 1);
11998e6e287fSHans Petter Selasky 	MLX5_SET(rqc, rqc, mem_rq_type, MLX5_RQC_RQ_TYPE_MEMORY_RQ_INLINE);
12008e6e287fSHans Petter Selasky 	MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST);
12014fb0a74eSHans Petter Selasky 	MLX5_SET(rqc, rqc, ts_format, ts_format);
12028e6e287fSHans Petter Selasky 	MLX5_SET(rqc, rqc, flush_in_error_en, 1);
12038e6e287fSHans Petter Selasky 	MLX5_SET(rqc, rqc, user_index, MLX5_GET(qpc, qpc, user_index));
12048e6e287fSHans Petter Selasky 	MLX5_SET(rqc, rqc, cqn, MLX5_GET(qpc, qpc, cqn_rcv));
12058e6e287fSHans Petter Selasky 
12068e6e287fSHans Petter Selasky 	if (mqp->flags & MLX5_IB_QP_CAP_SCATTER_FCS)
12078e6e287fSHans Petter Selasky 		MLX5_SET(rqc, rqc, scatter_fcs, 1);
12088e6e287fSHans Petter Selasky 
12098e6e287fSHans Petter Selasky 	wq = MLX5_ADDR_OF(rqc, rqc, wq);
12108e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
12118e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, end_padding_mode,
12128e6e287fSHans Petter Selasky 		 MLX5_GET(qpc, qpc, end_padding_mode));
12138e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, page_offset, MLX5_GET(qpc, qpc, page_offset));
12148e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, pd, MLX5_GET(qpc, qpc, pd));
12158e6e287fSHans Petter Selasky 	MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(qpc, qpc, dbr_addr));
12168e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, log_wq_stride, MLX5_GET(qpc, qpc, log_rq_stride) + 4);
12178e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, log_wq_pg_sz, MLX5_GET(qpc, qpc, log_page_size));
12188e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, log_wq_sz, MLX5_GET(qpc, qpc, log_rq_size));
12198e6e287fSHans Petter Selasky 
12208e6e287fSHans Petter Selasky 	pas = (__be64 *)MLX5_ADDR_OF(wq, wq, pas);
12218e6e287fSHans Petter Selasky 	qp_pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, qpin, pas);
12228e6e287fSHans Petter Selasky 	memcpy(pas, qp_pas, rq_pas_size);
12238e6e287fSHans Petter Selasky 
12248e6e287fSHans Petter Selasky 	err = mlx5_core_create_rq_tracked(dev->mdev, in, inlen, &rq->base.mqp);
12258e6e287fSHans Petter Selasky 
12268e6e287fSHans Petter Selasky 	kvfree(in);
12278e6e287fSHans Petter Selasky 
12288e6e287fSHans Petter Selasky 	return err;
12298e6e287fSHans Petter Selasky }
12308e6e287fSHans Petter Selasky 
destroy_raw_packet_qp_rq(struct mlx5_ib_dev * dev,struct mlx5_ib_rq * rq)12318e6e287fSHans Petter Selasky static void destroy_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
12328e6e287fSHans Petter Selasky 				     struct mlx5_ib_rq *rq)
12338e6e287fSHans Petter Selasky {
12348e6e287fSHans Petter Selasky 	mlx5_core_destroy_rq_tracked(dev->mdev, &rq->base.mqp);
12358e6e287fSHans Petter Selasky }
12368e6e287fSHans Petter Selasky 
create_raw_packet_qp_tir(struct mlx5_ib_dev * dev,struct mlx5_ib_rq * rq,u32 tdn,struct ib_pd * pd)12378e6e287fSHans Petter Selasky static int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev,
1238b633e08cSHans Petter Selasky 				    struct mlx5_ib_rq *rq, u32 tdn,
1239b633e08cSHans Petter Selasky 				    struct ib_pd *pd)
12408e6e287fSHans Petter Selasky {
12418e6e287fSHans Petter Selasky 	u32 *in;
12428e6e287fSHans Petter Selasky 	void *tirc;
12438e6e287fSHans Petter Selasky 	int inlen;
12448e6e287fSHans Petter Selasky 	int err;
12458e6e287fSHans Petter Selasky 
12468e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(create_tir_in);
12478e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
12488e6e287fSHans Petter Selasky 	if (!in)
12498e6e287fSHans Petter Selasky 		return -ENOMEM;
12508e6e287fSHans Petter Selasky 
1251b633e08cSHans Petter Selasky 	MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid);
12528e6e287fSHans Petter Selasky 	tirc = MLX5_ADDR_OF(create_tir_in, in, tir_context);
12538e6e287fSHans Petter Selasky 	MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT);
12548e6e287fSHans Petter Selasky 	MLX5_SET(tirc, tirc, inline_rqn, rq->base.mqp.qpn);
12558e6e287fSHans Petter Selasky 	MLX5_SET(tirc, tirc, transport_domain, tdn);
12568e6e287fSHans Petter Selasky 
12578e6e287fSHans Petter Selasky 	err = mlx5_core_create_tir(dev->mdev, in, inlen, &rq->tirn);
12588e6e287fSHans Petter Selasky 
12598e6e287fSHans Petter Selasky 	kvfree(in);
12608e6e287fSHans Petter Selasky 
12618e6e287fSHans Petter Selasky 	return err;
12628e6e287fSHans Petter Selasky }
12638e6e287fSHans Petter Selasky 
destroy_raw_packet_qp_tir(struct mlx5_ib_dev * dev,struct mlx5_ib_rq * rq,struct ib_pd * pd)12648e6e287fSHans Petter Selasky static void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev,
1265b633e08cSHans Petter Selasky 				      struct mlx5_ib_rq *rq,
1266b633e08cSHans Petter Selasky 				      struct ib_pd *pd)
12678e6e287fSHans Petter Selasky {
1268b633e08cSHans Petter Selasky 	mlx5_core_destroy_tir(dev->mdev, rq->tirn, to_mpd(pd)->uid);
12698e6e287fSHans Petter Selasky }
12708e6e287fSHans Petter Selasky 
create_raw_packet_qp(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,u32 * in,struct ib_pd * pd)12718e6e287fSHans Petter Selasky static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
12728e6e287fSHans Petter Selasky 				u32 *in,
12738e6e287fSHans Petter Selasky 				struct ib_pd *pd)
12748e6e287fSHans Petter Selasky {
12758e6e287fSHans Petter Selasky 	struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
12768e6e287fSHans Petter Selasky 	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
12778e6e287fSHans Petter Selasky 	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
12788e6e287fSHans Petter Selasky 	struct ib_uobject *uobj = pd->uobject;
12798e6e287fSHans Petter Selasky 	struct ib_ucontext *ucontext = uobj->context;
12808e6e287fSHans Petter Selasky 	struct mlx5_ib_ucontext *mucontext = to_mucontext(ucontext);
12818e6e287fSHans Petter Selasky 	int err;
12828e6e287fSHans Petter Selasky 	u32 tdn = mucontext->tdn;
12838e6e287fSHans Petter Selasky 
12848e6e287fSHans Petter Selasky 	if (qp->sq.wqe_cnt) {
1285b633e08cSHans Petter Selasky 		err = create_raw_packet_qp_tis(dev, sq, tdn, pd);
12868e6e287fSHans Petter Selasky 		if (err)
12878e6e287fSHans Petter Selasky 			return err;
12888e6e287fSHans Petter Selasky 
12898e6e287fSHans Petter Selasky 		err = create_raw_packet_qp_sq(dev, sq, in, pd);
12908e6e287fSHans Petter Selasky 		if (err)
12918e6e287fSHans Petter Selasky 			goto err_destroy_tis;
12928e6e287fSHans Petter Selasky 
12938e6e287fSHans Petter Selasky 		sq->base.container_mibqp = qp;
12948e6e287fSHans Petter Selasky 	}
12958e6e287fSHans Petter Selasky 
12968e6e287fSHans Petter Selasky 	if (qp->rq.wqe_cnt) {
12978e6e287fSHans Petter Selasky 		rq->base.container_mibqp = qp;
12988e6e287fSHans Petter Selasky 
1299b633e08cSHans Petter Selasky 		err = create_raw_packet_qp_rq(dev, rq, in, pd);
13008e6e287fSHans Petter Selasky 		if (err)
13018e6e287fSHans Petter Selasky 			goto err_destroy_sq;
13028e6e287fSHans Petter Selasky 
13038e6e287fSHans Petter Selasky 
1304b633e08cSHans Petter Selasky 		err = create_raw_packet_qp_tir(dev, rq, tdn, pd);
13058e6e287fSHans Petter Selasky 		if (err)
13068e6e287fSHans Petter Selasky 			goto err_destroy_rq;
13078e6e287fSHans Petter Selasky 	}
13088e6e287fSHans Petter Selasky 
13098e6e287fSHans Petter Selasky 	qp->trans_qp.base.mqp.qpn = qp->sq.wqe_cnt ? sq->base.mqp.qpn :
13108e6e287fSHans Petter Selasky 						     rq->base.mqp.qpn;
13118e6e287fSHans Petter Selasky 
13128e6e287fSHans Petter Selasky 	return 0;
13138e6e287fSHans Petter Selasky 
13148e6e287fSHans Petter Selasky err_destroy_rq:
13158e6e287fSHans Petter Selasky 	destroy_raw_packet_qp_rq(dev, rq);
13168e6e287fSHans Petter Selasky err_destroy_sq:
13178e6e287fSHans Petter Selasky 	if (!qp->sq.wqe_cnt)
13188e6e287fSHans Petter Selasky 		return err;
13198e6e287fSHans Petter Selasky 	destroy_raw_packet_qp_sq(dev, sq);
13208e6e287fSHans Petter Selasky err_destroy_tis:
1321b633e08cSHans Petter Selasky 	destroy_raw_packet_qp_tis(dev, sq, pd);
13228e6e287fSHans Petter Selasky 
13238e6e287fSHans Petter Selasky 	return err;
13248e6e287fSHans Petter Selasky }
13258e6e287fSHans Petter Selasky 
destroy_raw_packet_qp(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp)13268e6e287fSHans Petter Selasky static void destroy_raw_packet_qp(struct mlx5_ib_dev *dev,
13278e6e287fSHans Petter Selasky 				  struct mlx5_ib_qp *qp)
13288e6e287fSHans Petter Selasky {
13298e6e287fSHans Petter Selasky 	struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
13308e6e287fSHans Petter Selasky 	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
13318e6e287fSHans Petter Selasky 	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
13328e6e287fSHans Petter Selasky 
13338e6e287fSHans Petter Selasky 	if (qp->rq.wqe_cnt) {
1334b633e08cSHans Petter Selasky 		destroy_raw_packet_qp_tir(dev, rq, qp->ibqp.pd);
13358e6e287fSHans Petter Selasky 		destroy_raw_packet_qp_rq(dev, rq);
13368e6e287fSHans Petter Selasky 	}
13378e6e287fSHans Petter Selasky 
13388e6e287fSHans Petter Selasky 	if (qp->sq.wqe_cnt) {
13398e6e287fSHans Petter Selasky 		destroy_raw_packet_qp_sq(dev, sq);
1340b633e08cSHans Petter Selasky 		destroy_raw_packet_qp_tis(dev, sq, qp->ibqp.pd);
13418e6e287fSHans Petter Selasky 	}
13428e6e287fSHans Petter Selasky }
13438e6e287fSHans Petter Selasky 
raw_packet_qp_copy_info(struct mlx5_ib_qp * qp,struct mlx5_ib_raw_packet_qp * raw_packet_qp)13448e6e287fSHans Petter Selasky static void raw_packet_qp_copy_info(struct mlx5_ib_qp *qp,
13458e6e287fSHans Petter Selasky 				    struct mlx5_ib_raw_packet_qp *raw_packet_qp)
13468e6e287fSHans Petter Selasky {
13478e6e287fSHans Petter Selasky 	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
13488e6e287fSHans Petter Selasky 	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
13498e6e287fSHans Petter Selasky 
13508e6e287fSHans Petter Selasky 	sq->sq = &qp->sq;
13518e6e287fSHans Petter Selasky 	rq->rq = &qp->rq;
13528e6e287fSHans Petter Selasky 	sq->doorbell = &qp->db;
13538e6e287fSHans Petter Selasky 	rq->doorbell = &qp->db;
13548e6e287fSHans Petter Selasky }
13558e6e287fSHans Petter Selasky 
destroy_rss_raw_qp_tir(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp)13568e6e287fSHans Petter Selasky static void destroy_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
13578e6e287fSHans Petter Selasky {
1358b633e08cSHans Petter Selasky 	mlx5_core_destroy_tir(dev->mdev, qp->rss_qp.tirn,
1359b633e08cSHans Petter Selasky 			      to_mpd(qp->ibqp.pd)->uid);
13608e6e287fSHans Petter Selasky }
13618e6e287fSHans Petter Selasky 
create_rss_raw_qp_tir(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,struct ib_pd * pd,struct ib_qp_init_attr * init_attr,struct ib_udata * udata)13628e6e287fSHans Petter Selasky static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
13638e6e287fSHans Petter Selasky 				 struct ib_pd *pd,
13648e6e287fSHans Petter Selasky 				 struct ib_qp_init_attr *init_attr,
13658e6e287fSHans Petter Selasky 				 struct ib_udata *udata)
13668e6e287fSHans Petter Selasky {
13678e6e287fSHans Petter Selasky 	struct ib_uobject *uobj = pd->uobject;
13688e6e287fSHans Petter Selasky 	struct ib_ucontext *ucontext = uobj->context;
13698e6e287fSHans Petter Selasky 	struct mlx5_ib_ucontext *mucontext = to_mucontext(ucontext);
13708e6e287fSHans Petter Selasky 	struct mlx5_ib_create_qp_resp resp = {};
13718e6e287fSHans Petter Selasky 	int inlen;
13728e6e287fSHans Petter Selasky 	int err;
13738e6e287fSHans Petter Selasky 	u32 *in;
13748e6e287fSHans Petter Selasky 	void *tirc;
13758e6e287fSHans Petter Selasky 	void *hfso;
13768e6e287fSHans Petter Selasky 	u32 selected_fields = 0;
13778e6e287fSHans Petter Selasky 	size_t min_resp_len;
13788e6e287fSHans Petter Selasky 	u32 tdn = mucontext->tdn;
13798e6e287fSHans Petter Selasky 	struct mlx5_ib_create_qp_rss ucmd = {};
13808e6e287fSHans Petter Selasky 	size_t required_cmd_sz;
13818e6e287fSHans Petter Selasky 
13828e6e287fSHans Petter Selasky 	if (init_attr->qp_type != IB_QPT_RAW_PACKET)
13838e6e287fSHans Petter Selasky 		return -EOPNOTSUPP;
13848e6e287fSHans Petter Selasky 
13858e6e287fSHans Petter Selasky 	if (init_attr->create_flags || init_attr->send_cq)
13868e6e287fSHans Petter Selasky 		return -EINVAL;
13878e6e287fSHans Petter Selasky 
1388f8f5b459SHans Petter Selasky 	min_resp_len = offsetof(typeof(resp), bfreg_index) + sizeof(resp.bfreg_index);
13898e6e287fSHans Petter Selasky 	if (udata->outlen < min_resp_len)
13908e6e287fSHans Petter Selasky 		return -EINVAL;
13918e6e287fSHans Petter Selasky 
13928e6e287fSHans Petter Selasky 	required_cmd_sz = offsetof(typeof(ucmd), reserved1) + sizeof(ucmd.reserved1);
13938e6e287fSHans Petter Selasky 	if (udata->inlen < required_cmd_sz) {
13948e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid inlen\n");
13958e6e287fSHans Petter Selasky 		return -EINVAL;
13968e6e287fSHans Petter Selasky 	}
13978e6e287fSHans Petter Selasky 
13988e6e287fSHans Petter Selasky 	if (udata->inlen > sizeof(ucmd) &&
13998e6e287fSHans Petter Selasky 	    !ib_is_udata_cleared(udata, sizeof(ucmd),
14008e6e287fSHans Petter Selasky 				 udata->inlen - sizeof(ucmd))) {
14018e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "inlen is not supported\n");
14028e6e287fSHans Petter Selasky 		return -EOPNOTSUPP;
14038e6e287fSHans Petter Selasky 	}
14048e6e287fSHans Petter Selasky 
14058e6e287fSHans Petter Selasky 	if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) {
14068e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "copy failed\n");
14078e6e287fSHans Petter Selasky 		return -EFAULT;
14088e6e287fSHans Petter Selasky 	}
14098e6e287fSHans Petter Selasky 
14108e6e287fSHans Petter Selasky 	if (ucmd.comp_mask) {
14118e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid comp mask\n");
14128e6e287fSHans Petter Selasky 		return -EOPNOTSUPP;
14138e6e287fSHans Petter Selasky 	}
14148e6e287fSHans Petter Selasky 
14158e6e287fSHans Petter Selasky 	if (memchr_inv(ucmd.reserved, 0, sizeof(ucmd.reserved)) || ucmd.reserved1) {
14168e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid reserved\n");
14178e6e287fSHans Petter Selasky 		return -EOPNOTSUPP;
14188e6e287fSHans Petter Selasky 	}
14198e6e287fSHans Petter Selasky 
14208e6e287fSHans Petter Selasky 	err = ib_copy_to_udata(udata, &resp, min_resp_len);
14218e6e287fSHans Petter Selasky 	if (err) {
14228e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "copy failed\n");
14238e6e287fSHans Petter Selasky 		return -EINVAL;
14248e6e287fSHans Petter Selasky 	}
14258e6e287fSHans Petter Selasky 
14268e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(create_tir_in);
14278e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
14288e6e287fSHans Petter Selasky 	if (!in)
14298e6e287fSHans Petter Selasky 		return -ENOMEM;
14308e6e287fSHans Petter Selasky 
1431b633e08cSHans Petter Selasky 	MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid);
14328e6e287fSHans Petter Selasky 	tirc = MLX5_ADDR_OF(create_tir_in, in, tir_context);
14338e6e287fSHans Petter Selasky 	MLX5_SET(tirc, tirc, disp_type,
14348e6e287fSHans Petter Selasky 		 MLX5_TIRC_DISP_TYPE_INDIRECT);
14358e6e287fSHans Petter Selasky 	MLX5_SET(tirc, tirc, indirect_table,
14368e6e287fSHans Petter Selasky 		 init_attr->rwq_ind_tbl->ind_tbl_num);
14378e6e287fSHans Petter Selasky 	MLX5_SET(tirc, tirc, transport_domain, tdn);
14388e6e287fSHans Petter Selasky 
14398e6e287fSHans Petter Selasky 	hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
14408e6e287fSHans Petter Selasky 	switch (ucmd.rx_hash_function) {
14418e6e287fSHans Petter Selasky 	case MLX5_RX_HASH_FUNC_TOEPLITZ:
14428e6e287fSHans Petter Selasky 	{
14438e6e287fSHans Petter Selasky 		void *rss_key = MLX5_ADDR_OF(tirc, tirc, rx_hash_toeplitz_key);
14448e6e287fSHans Petter Selasky 		size_t len = MLX5_FLD_SZ_BYTES(tirc, rx_hash_toeplitz_key);
14458e6e287fSHans Petter Selasky 
14468e6e287fSHans Petter Selasky 		if (len != ucmd.rx_key_len) {
14478e6e287fSHans Petter Selasky 			err = -EINVAL;
14488e6e287fSHans Petter Selasky 			goto err;
14498e6e287fSHans Petter Selasky 		}
14508e6e287fSHans Petter Selasky 
14518e6e287fSHans Petter Selasky 		MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FUNC_TOEPLITZ);
14528e6e287fSHans Petter Selasky 		memcpy(rss_key, ucmd.rx_hash_key, len);
14538e6e287fSHans Petter Selasky 		break;
14548e6e287fSHans Petter Selasky 	}
145512515907SHans Petter Selasky 	default:
14568e6e287fSHans Petter Selasky 		err = -EOPNOTSUPP;
14578e6e287fSHans Petter Selasky 		goto err;
145812515907SHans Petter Selasky 	}
145912515907SHans Petter Selasky 
14608e6e287fSHans Petter Selasky 	if (!ucmd.rx_hash_fields_mask) {
14618e6e287fSHans Petter Selasky 		/* special case when this TIR serves as steering entry without hashing */
14628e6e287fSHans Petter Selasky 		if (!init_attr->rwq_ind_tbl->log_ind_tbl_size)
14638e6e287fSHans Petter Selasky 			goto create_tir;
14648e6e287fSHans Petter Selasky 		err = -EINVAL;
14658e6e287fSHans Petter Selasky 		goto err;
14668e6e287fSHans Petter Selasky 	}
14678e6e287fSHans Petter Selasky 
14688e6e287fSHans Petter Selasky 	if (((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) ||
14698e6e287fSHans Petter Selasky 	     (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4)) &&
14708e6e287fSHans Petter Selasky 	     ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6) ||
14718e6e287fSHans Petter Selasky 	     (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))) {
14728e6e287fSHans Petter Selasky 		err = -EINVAL;
14738e6e287fSHans Petter Selasky 		goto err;
14748e6e287fSHans Petter Selasky 	}
14758e6e287fSHans Petter Selasky 
14768e6e287fSHans Petter Selasky 	/* If none of IPV4 & IPV6 SRC/DST was set - this bit field is ignored */
14778e6e287fSHans Petter Selasky 	if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) ||
14788e6e287fSHans Petter Selasky 	    (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4))
14798e6e287fSHans Petter Selasky 		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
14808e6e287fSHans Petter Selasky 			 MLX5_L3_PROT_TYPE_IPV4);
14818e6e287fSHans Petter Selasky 	else if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6) ||
14828e6e287fSHans Petter Selasky 		 (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))
14838e6e287fSHans Petter Selasky 		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
14848e6e287fSHans Petter Selasky 			 MLX5_L3_PROT_TYPE_IPV6);
14858e6e287fSHans Petter Selasky 
14868e6e287fSHans Petter Selasky 	if (((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) ||
14878e6e287fSHans Petter Selasky 	     (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP)) &&
14888e6e287fSHans Petter Selasky 	     ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP) ||
14898e6e287fSHans Petter Selasky 	     (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP))) {
14908e6e287fSHans Petter Selasky 		err = -EINVAL;
14918e6e287fSHans Petter Selasky 		goto err;
14928e6e287fSHans Petter Selasky 	}
14938e6e287fSHans Petter Selasky 
14948e6e287fSHans Petter Selasky 	/* If none of TCP & UDP SRC/DST was set - this bit field is ignored */
14958e6e287fSHans Petter Selasky 	if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) ||
14968e6e287fSHans Petter Selasky 	    (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP))
14978e6e287fSHans Petter Selasky 		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
14988e6e287fSHans Petter Selasky 			 MLX5_L4_PROT_TYPE_TCP);
14998e6e287fSHans Petter Selasky 	else if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP) ||
15008e6e287fSHans Petter Selasky 		 (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP))
15018e6e287fSHans Petter Selasky 		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
15028e6e287fSHans Petter Selasky 			 MLX5_L4_PROT_TYPE_UDP);
15038e6e287fSHans Petter Selasky 
15048e6e287fSHans Petter Selasky 	if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) ||
15058e6e287fSHans Petter Selasky 	    (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6))
15068e6e287fSHans Petter Selasky 		selected_fields |= MLX5_HASH_FIELD_SEL_SRC_IP;
15078e6e287fSHans Petter Selasky 
15088e6e287fSHans Petter Selasky 	if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4) ||
15098e6e287fSHans Petter Selasky 	    (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))
15108e6e287fSHans Petter Selasky 		selected_fields |= MLX5_HASH_FIELD_SEL_DST_IP;
15118e6e287fSHans Petter Selasky 
15128e6e287fSHans Petter Selasky 	if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) ||
15138e6e287fSHans Petter Selasky 	    (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP))
15148e6e287fSHans Petter Selasky 		selected_fields |= MLX5_HASH_FIELD_SEL_L4_SPORT;
15158e6e287fSHans Petter Selasky 
15168e6e287fSHans Petter Selasky 	if ((ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP) ||
15178e6e287fSHans Petter Selasky 	    (ucmd.rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP))
15188e6e287fSHans Petter Selasky 		selected_fields |= MLX5_HASH_FIELD_SEL_L4_DPORT;
15198e6e287fSHans Petter Selasky 
15208e6e287fSHans Petter Selasky 	MLX5_SET(rx_hash_field_select, hfso, selected_fields, selected_fields);
15218e6e287fSHans Petter Selasky 
15228e6e287fSHans Petter Selasky create_tir:
15238e6e287fSHans Petter Selasky 	err = mlx5_core_create_tir(dev->mdev, in, inlen, &qp->rss_qp.tirn);
15248e6e287fSHans Petter Selasky 
15258e6e287fSHans Petter Selasky 	if (err)
15268e6e287fSHans Petter Selasky 		goto err;
15278e6e287fSHans Petter Selasky 
15288e6e287fSHans Petter Selasky 	kvfree(in);
15298e6e287fSHans Petter Selasky 	/* qpn is reserved for that QP */
15308e6e287fSHans Petter Selasky 	qp->trans_qp.base.mqp.qpn = 0;
15318e6e287fSHans Petter Selasky 	qp->flags |= MLX5_IB_QP_RSS;
15328e6e287fSHans Petter Selasky 	return 0;
15338e6e287fSHans Petter Selasky 
15348e6e287fSHans Petter Selasky err:
15358e6e287fSHans Petter Selasky 	kvfree(in);
15368e6e287fSHans Petter Selasky 	return err;
15378e6e287fSHans Petter Selasky }
153812515907SHans Petter Selasky 
atomic_size_to_mode(int size_mask)1539cf88b86eSHans Petter Selasky static int atomic_size_to_mode(int size_mask)
1540cf88b86eSHans Petter Selasky {
1541cf88b86eSHans Petter Selasky 	/* driver does not support atomic_size > 256B
1542cf88b86eSHans Petter Selasky 	 * and does not know how to translate bigger sizes
1543cf88b86eSHans Petter Selasky 	 */
1544cf88b86eSHans Petter Selasky 	int supported_size_mask = size_mask & 0x1ff;
1545cf88b86eSHans Petter Selasky 	int log_max_size;
1546cf88b86eSHans Petter Selasky 
1547cf88b86eSHans Petter Selasky 	if (!supported_size_mask)
1548cf88b86eSHans Petter Selasky 		return -EOPNOTSUPP;
1549cf88b86eSHans Petter Selasky 
1550cf88b86eSHans Petter Selasky 	log_max_size = __fls(supported_size_mask);
1551cf88b86eSHans Petter Selasky 
1552cf88b86eSHans Petter Selasky 	if (log_max_size > 3)
1553cf88b86eSHans Petter Selasky 		return log_max_size;
1554cf88b86eSHans Petter Selasky 
1555cf88b86eSHans Petter Selasky 	return MLX5_ATOMIC_MODE_8B;
1556cf88b86eSHans Petter Selasky }
1557cf88b86eSHans Petter Selasky 
get_atomic_mode(struct mlx5_ib_dev * dev,enum ib_qp_type qp_type)1558cf88b86eSHans Petter Selasky static int get_atomic_mode(struct mlx5_ib_dev *dev,
1559cf88b86eSHans Petter Selasky 			   enum ib_qp_type qp_type)
1560cf88b86eSHans Petter Selasky {
1561cf88b86eSHans Petter Selasky 	u8 atomic_operations = MLX5_CAP_ATOMIC(dev->mdev, atomic_operations);
1562cf88b86eSHans Petter Selasky 	u8 atomic = MLX5_CAP_GEN(dev->mdev, atomic);
1563cf88b86eSHans Petter Selasky 	int atomic_mode = -EOPNOTSUPP;
1564cf88b86eSHans Petter Selasky 	int atomic_size_mask;
1565cf88b86eSHans Petter Selasky 
1566cf88b86eSHans Petter Selasky 	if (!atomic)
1567cf88b86eSHans Petter Selasky 		return -EOPNOTSUPP;
1568cf88b86eSHans Petter Selasky 
1569cf88b86eSHans Petter Selasky 	if (qp_type == MLX5_IB_QPT_DCT)
1570cf88b86eSHans Petter Selasky 		atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_dc);
1571cf88b86eSHans Petter Selasky 	else
1572cf88b86eSHans Petter Selasky 		atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_qp);
1573cf88b86eSHans Petter Selasky 
1574cf88b86eSHans Petter Selasky 	if ((atomic_operations & MLX5_ATOMIC_OPS_MASKED_CMP_SWAP) ||
1575cf88b86eSHans Petter Selasky 	    (atomic_operations & MLX5_ATOMIC_OPS_MASKED_FETCH_ADD))
1576cf88b86eSHans Petter Selasky 		atomic_mode = atomic_size_to_mode(atomic_size_mask);
1577cf88b86eSHans Petter Selasky 
1578cf88b86eSHans Petter Selasky 	if (atomic_mode <= 0 &&
1579cf88b86eSHans Petter Selasky 	    (atomic_operations & MLX5_ATOMIC_OPS_CMP_SWAP &&
1580cf88b86eSHans Petter Selasky 	     atomic_operations & MLX5_ATOMIC_OPS_FETCH_ADD))
1581cf88b86eSHans Petter Selasky 		atomic_mode = MLX5_ATOMIC_MODE_IB_COMP;
1582cf88b86eSHans Petter Selasky 
1583cf88b86eSHans Petter Selasky 	return atomic_mode;
1584cf88b86eSHans Petter Selasky }
1585cf88b86eSHans Petter Selasky 
create_qp_common(struct mlx5_ib_dev * dev,struct ib_pd * pd,struct ib_qp_init_attr * init_attr,struct ib_udata * udata,struct mlx5_ib_qp * qp)158612515907SHans Petter Selasky static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
158712515907SHans Petter Selasky 			    struct ib_qp_init_attr *init_attr,
158812515907SHans Petter Selasky 			    struct ib_udata *udata, struct mlx5_ib_qp *qp)
158912515907SHans Petter Selasky {
159012515907SHans Petter Selasky 	struct mlx5_ib_resources *devr = &dev->devr;
15918e6e287fSHans Petter Selasky 	int inlen = MLX5_ST_SZ_BYTES(create_qp_in);
159212515907SHans Petter Selasky 	struct mlx5_core_dev *mdev = dev->mdev;
15938e6e287fSHans Petter Selasky 	struct mlx5_ib_create_qp_resp resp;
159412515907SHans Petter Selasky 	struct mlx5_ib_cq *send_cq;
159512515907SHans Petter Selasky 	struct mlx5_ib_cq *recv_cq;
159612515907SHans Petter Selasky 	unsigned long flags;
15978e6e287fSHans Petter Selasky 	u32 uidx = MLX5_IB_DEFAULT_UIDX;
15988e6e287fSHans Petter Selasky 	struct mlx5_ib_create_qp ucmd;
15998e6e287fSHans Petter Selasky 	struct mlx5_ib_qp_base *base;
160012515907SHans Petter Selasky 	void *qpc;
16018e6e287fSHans Petter Selasky 	u32 *in;
16028e6e287fSHans Petter Selasky 	int err;
16038e6e287fSHans Petter Selasky 
16048e6e287fSHans Petter Selasky 	base = init_attr->qp_type == IB_QPT_RAW_PACKET ?
16058e6e287fSHans Petter Selasky 	       &qp->raw_packet_qp.rq.base :
16068e6e287fSHans Petter Selasky 	       &qp->trans_qp.base;
16078e6e287fSHans Petter Selasky 
16088e6e287fSHans Petter Selasky 	if (init_attr->qp_type != IB_QPT_RAW_PACKET)
16098e6e287fSHans Petter Selasky 		mlx5_ib_odp_create_qp(qp);
161012515907SHans Petter Selasky 
161112515907SHans Petter Selasky 	mutex_init(&qp->mutex);
161212515907SHans Petter Selasky 	spin_lock_init(&qp->sq.lock);
161312515907SHans Petter Selasky 	spin_lock_init(&qp->rq.lock);
161412515907SHans Petter Selasky 
16158e6e287fSHans Petter Selasky 	if (init_attr->rwq_ind_tbl) {
16168e6e287fSHans Petter Selasky 		if (!udata)
16178e6e287fSHans Petter Selasky 			return -ENOSYS;
16188e6e287fSHans Petter Selasky 
16198e6e287fSHans Petter Selasky 		err = create_rss_raw_qp_tir(dev, qp, pd, init_attr, udata);
16208e6e287fSHans Petter Selasky 		return err;
16218e6e287fSHans Petter Selasky 	}
16228e6e287fSHans Petter Selasky 
162312515907SHans Petter Selasky 	if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
162412515907SHans Petter Selasky 		if (!MLX5_CAP_GEN(mdev, block_lb_mc)) {
16258e6e287fSHans Petter Selasky 			mlx5_ib_dbg(dev, "block multicast loopback isn't supported\n");
162612515907SHans Petter Selasky 			return -EINVAL;
162712515907SHans Petter Selasky 		} else {
162812515907SHans Petter Selasky 			qp->flags |= MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK;
162912515907SHans Petter Selasky 		}
163012515907SHans Petter Selasky 	}
163112515907SHans Petter Selasky 
16328e6e287fSHans Petter Selasky 	if (init_attr->create_flags &
16338e6e287fSHans Petter Selasky 			(IB_QP_CREATE_CROSS_CHANNEL |
16348e6e287fSHans Petter Selasky 			 IB_QP_CREATE_MANAGED_SEND |
16358e6e287fSHans Petter Selasky 			 IB_QP_CREATE_MANAGED_RECV)) {
16368e6e287fSHans Petter Selasky 		if (!MLX5_CAP_GEN(mdev, cd)) {
16378e6e287fSHans Petter Selasky 			mlx5_ib_dbg(dev, "cross-channel isn't supported\n");
16388e6e287fSHans Petter Selasky 			return -EINVAL;
16398e6e287fSHans Petter Selasky 		}
16408e6e287fSHans Petter Selasky 		if (init_attr->create_flags & IB_QP_CREATE_CROSS_CHANNEL)
16418e6e287fSHans Petter Selasky 			qp->flags |= MLX5_IB_QP_CROSS_CHANNEL;
16428e6e287fSHans Petter Selasky 		if (init_attr->create_flags & IB_QP_CREATE_MANAGED_SEND)
16438e6e287fSHans Petter Selasky 			qp->flags |= MLX5_IB_QP_MANAGED_SEND;
16448e6e287fSHans Petter Selasky 		if (init_attr->create_flags & IB_QP_CREATE_MANAGED_RECV)
16458e6e287fSHans Petter Selasky 			qp->flags |= MLX5_IB_QP_MANAGED_RECV;
16468e6e287fSHans Petter Selasky 	}
16478e6e287fSHans Petter Selasky 
16488e6e287fSHans Petter Selasky 	if (init_attr->qp_type == IB_QPT_UD &&
16498e6e287fSHans Petter Selasky 	    (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO))
16508e6e287fSHans Petter Selasky 		if (!MLX5_CAP_GEN(mdev, ipoib_ipoib_offloads)) {
16518e6e287fSHans Petter Selasky 			mlx5_ib_dbg(dev, "ipoib UD lso qp isn't supported\n");
16528e6e287fSHans Petter Selasky 			return -EOPNOTSUPP;
16538e6e287fSHans Petter Selasky 		}
16548e6e287fSHans Petter Selasky 
16558e6e287fSHans Petter Selasky 	if (init_attr->create_flags & IB_QP_CREATE_SCATTER_FCS) {
16568e6e287fSHans Petter Selasky 		if (init_attr->qp_type != IB_QPT_RAW_PACKET) {
16578e6e287fSHans Petter Selasky 			mlx5_ib_dbg(dev, "Scatter FCS is supported only for Raw Packet QPs");
16588e6e287fSHans Petter Selasky 			return -EOPNOTSUPP;
16598e6e287fSHans Petter Selasky 		}
16608e6e287fSHans Petter Selasky 		if (!MLX5_CAP_GEN(dev->mdev, eth_net_offloads) ||
16618e6e287fSHans Petter Selasky 		    !MLX5_CAP_ETH(dev->mdev, scatter_fcs)) {
16628e6e287fSHans Petter Selasky 			mlx5_ib_dbg(dev, "Scatter FCS isn't supported\n");
16638e6e287fSHans Petter Selasky 			return -EOPNOTSUPP;
16648e6e287fSHans Petter Selasky 		}
16658e6e287fSHans Petter Selasky 		qp->flags |= MLX5_IB_QP_CAP_SCATTER_FCS;
16668e6e287fSHans Petter Selasky 	}
16678e6e287fSHans Petter Selasky 
166812515907SHans Petter Selasky 	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
166912515907SHans Petter Selasky 		qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE;
167012515907SHans Petter Selasky 
167112515907SHans Petter Selasky 	if (pd && pd->uobject) {
16728e6e287fSHans Petter Selasky 		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
16738e6e287fSHans Petter Selasky 			mlx5_ib_dbg(dev, "copy failed\n");
16748e6e287fSHans Petter Selasky 			return -EFAULT;
167512515907SHans Petter Selasky 		}
16768e6e287fSHans Petter Selasky 
16778e6e287fSHans Petter Selasky 		err = get_qp_user_index(to_mucontext(pd->uobject->context),
16788e6e287fSHans Petter Selasky 					&ucmd, udata->inlen, &uidx);
16798e6e287fSHans Petter Selasky 		if (err)
168012515907SHans Petter Selasky 			return err;
168112515907SHans Petter Selasky 
168212515907SHans Petter Selasky 		qp->wq_sig = !!(ucmd.flags & MLX5_QP_FLAG_SIGNATURE);
16838e6e287fSHans Petter Selasky 		qp->scat_cqe = !!(ucmd.flags & MLX5_QP_FLAG_SCATTER_CQE);
168412515907SHans Petter Selasky 	} else {
16858e6e287fSHans Petter Selasky 		qp->wq_sig = !!wq_signature;
168612515907SHans Petter Selasky 	}
168712515907SHans Petter Selasky 
168812515907SHans Petter Selasky 	qp->has_rq = qp_has_rq(init_attr);
168912515907SHans Petter Selasky 	err = set_rq_size(dev, &init_attr->cap, qp->has_rq,
16908e6e287fSHans Petter Selasky 			  qp, (pd && pd->uobject) ? &ucmd : NULL);
169112515907SHans Petter Selasky 	if (err) {
16928e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "err %d\n", err);
169312515907SHans Petter Selasky 		return err;
169412515907SHans Petter Selasky 	}
169512515907SHans Petter Selasky 
169612515907SHans Petter Selasky 	if (pd) {
169712515907SHans Petter Selasky 		if (pd->uobject) {
169812515907SHans Petter Selasky 			__u32 max_wqes =
169912515907SHans Petter Selasky 				1 << MLX5_CAP_GEN(mdev, log_max_qp_sz);
170012515907SHans Petter Selasky 			mlx5_ib_dbg(dev, "requested sq_wqe_count (%d)\n", ucmd.sq_wqe_count);
170112515907SHans Petter Selasky 			if (ucmd.rq_wqe_shift != qp->rq.wqe_shift ||
170212515907SHans Petter Selasky 			    ucmd.rq_wqe_count != qp->rq.wqe_cnt) {
17038e6e287fSHans Petter Selasky 				mlx5_ib_dbg(dev, "invalid rq params\n");
170412515907SHans Petter Selasky 				return -EINVAL;
170512515907SHans Petter Selasky 			}
170612515907SHans Petter Selasky 			if (ucmd.sq_wqe_count > max_wqes) {
17078e6e287fSHans Petter Selasky 				mlx5_ib_dbg(dev, "requested sq_wqe_count (%d) > max allowed (%d)\n",
170812515907SHans Petter Selasky 					    ucmd.sq_wqe_count, max_wqes);
170912515907SHans Petter Selasky 				return -EINVAL;
171012515907SHans Petter Selasky 			}
17118e6e287fSHans Petter Selasky 			if (init_attr->create_flags &
1712f8f5b459SHans Petter Selasky 			    MLX5_IB_QP_CREATE_SQPN_QP1) {
17138e6e287fSHans Petter Selasky 				mlx5_ib_dbg(dev, "user-space is not allowed to create UD QPs spoofing as QP1\n");
171412515907SHans Petter Selasky 				return -EINVAL;
171512515907SHans Petter Selasky 			}
17168e6e287fSHans Petter Selasky 			err = create_user_qp(dev, pd, qp, udata, init_attr, &in,
17178e6e287fSHans Petter Selasky 					     &resp, &inlen, base);
171812515907SHans Petter Selasky 			if (err)
17198e6e287fSHans Petter Selasky 				mlx5_ib_dbg(dev, "err %d\n", err);
17208e6e287fSHans Petter Selasky 		} else {
17218e6e287fSHans Petter Selasky 			err = create_kernel_qp(dev, init_attr, qp, &in, &inlen,
17228e6e287fSHans Petter Selasky 					       base);
17238e6e287fSHans Petter Selasky 			if (err)
17248e6e287fSHans Petter Selasky 				mlx5_ib_dbg(dev, "err %d\n", err);
172512515907SHans Petter Selasky 		}
172612515907SHans Petter Selasky 
172712515907SHans Petter Selasky 		if (err)
172812515907SHans Petter Selasky 			return err;
172912515907SHans Petter Selasky 	} else {
17308e6e287fSHans Petter Selasky 		in = mlx5_vzalloc(inlen);
173112515907SHans Petter Selasky 		if (!in)
173212515907SHans Petter Selasky 			return -ENOMEM;
173312515907SHans Petter Selasky 
173412515907SHans Petter Selasky 		qp->create_type = MLX5_QP_EMPTY;
173512515907SHans Petter Selasky 	}
173612515907SHans Petter Selasky 
173712515907SHans Petter Selasky 	if (is_sqp(init_attr->qp_type))
173812515907SHans Petter Selasky 		qp->port = init_attr->port_num;
173912515907SHans Petter Selasky 
17408e6e287fSHans Petter Selasky 	qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
174112515907SHans Petter Selasky 
17428e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, st, to_mlx5_st(init_attr->qp_type));
17438e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
17448e6e287fSHans Petter Selasky 
17458e6e287fSHans Petter Selasky 	if (init_attr->qp_type != MLX5_IB_QPT_REG_UMR)
17468e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, pd, to_mpd(pd ? pd : devr->p0)->pdn);
17478e6e287fSHans Petter Selasky 	else
17488e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, latency_sensitive, 1);
17498e6e287fSHans Petter Selasky 
175012515907SHans Petter Selasky 
175112515907SHans Petter Selasky 	if (qp->wq_sig)
17528e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, wq_signature, 1);
175312515907SHans Petter Selasky 
175412515907SHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK)
17558e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, block_lb_mc, 1);
175612515907SHans Petter Selasky 
17578e6e287fSHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_CROSS_CHANNEL)
17588e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, cd_master, 1);
17598e6e287fSHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_MANAGED_SEND)
17608e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, cd_slave_send, 1);
17618e6e287fSHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_MANAGED_RECV)
17628e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, cd_slave_receive, 1);
176312515907SHans Petter Selasky 
176412515907SHans Petter Selasky 	if (qp->scat_cqe && is_connected(init_attr->qp_type)) {
176512515907SHans Petter Selasky 		int rcqe_sz;
176612515907SHans Petter Selasky 		int scqe_sz;
176712515907SHans Petter Selasky 
176812515907SHans Petter Selasky 		rcqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->recv_cq);
176912515907SHans Petter Selasky 		scqe_sz = mlx5_ib_get_cqe_size(dev, init_attr->send_cq);
177012515907SHans Petter Selasky 
17718e6e287fSHans Petter Selasky 		if (rcqe_sz == 128)
17728e6e287fSHans Petter Selasky 			MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA64_CQE);
177312515907SHans Petter Selasky 		else
17748e6e287fSHans Petter Selasky 			MLX5_SET(qpc, qpc, cs_res, MLX5_RES_SCAT_DATA32_CQE);
17758e6e287fSHans Petter Selasky 
17768e6e287fSHans Petter Selasky 		if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) {
17778e6e287fSHans Petter Selasky 			if (scqe_sz == 128)
17788e6e287fSHans Petter Selasky 				MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA64_CQE);
17798e6e287fSHans Petter Selasky 			else
17808e6e287fSHans Petter Selasky 				MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE);
178112515907SHans Petter Selasky 		}
178212515907SHans Petter Selasky 	}
178312515907SHans Petter Selasky 
178412515907SHans Petter Selasky 	if (qp->rq.wqe_cnt) {
17858e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, log_rq_stride, qp->rq.wqe_shift - 4);
17868e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, log_rq_size, ilog2(qp->rq.wqe_cnt));
178712515907SHans Petter Selasky 	}
178812515907SHans Petter Selasky 
17894fb0a74eSHans Petter Selasky 	if (init_attr->qp_type != IB_QPT_RAW_PACKET)
17904fb0a74eSHans Petter Selasky 		MLX5_SET(qpc, qpc, ts_format, mlx5_get_qp_default_ts(dev->mdev));
17914fb0a74eSHans Petter Selasky 
17928e6e287fSHans Petter Selasky 	MLX5_SET(qpc, qpc, rq_type, get_rx_type(qp, init_attr));
179312515907SHans Petter Selasky 
179412515907SHans Petter Selasky 	if (qp->sq.wqe_cnt)
17958e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, log_sq_size, ilog2(qp->sq.wqe_cnt));
179612515907SHans Petter Selasky 	else
17978e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, no_sq, 1);
179812515907SHans Petter Selasky 
179912515907SHans Petter Selasky 	/* Set default resources */
180012515907SHans Petter Selasky 	switch (init_attr->qp_type) {
180112515907SHans Petter Selasky 	case IB_QPT_XRC_TGT:
18028e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(devr->c0)->mcq.cqn);
18038e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, cqn_snd, to_mcq(devr->c0)->mcq.cqn);
18048e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, srqn_rmpn, to_msrq(devr->s0)->msrq.srqn);
18058e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, xrcd, to_mxrcd(init_attr->xrcd)->xrcdn);
180612515907SHans Petter Selasky 		break;
180712515907SHans Petter Selasky 	case IB_QPT_XRC_INI:
18088e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(devr->c0)->mcq.cqn);
18098e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, xrcd, to_mxrcd(devr->x1)->xrcdn);
18108e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, srqn_rmpn, to_msrq(devr->s0)->msrq.srqn);
181112515907SHans Petter Selasky 		break;
181212515907SHans Petter Selasky 	default:
181312515907SHans Petter Selasky 		if (init_attr->srq) {
18148e6e287fSHans Petter Selasky 			MLX5_SET(qpc, qpc, xrcd, to_mxrcd(devr->x0)->xrcdn);
18158e6e287fSHans Petter Selasky 			MLX5_SET(qpc, qpc, srqn_rmpn, to_msrq(init_attr->srq)->msrq.srqn);
181612515907SHans Petter Selasky 		} else {
18178e6e287fSHans Petter Selasky 			MLX5_SET(qpc, qpc, xrcd, to_mxrcd(devr->x1)->xrcdn);
18188e6e287fSHans Petter Selasky 			MLX5_SET(qpc, qpc, srqn_rmpn, to_msrq(devr->s1)->msrq.srqn);
181912515907SHans Petter Selasky 		}
182012515907SHans Petter Selasky 	}
182112515907SHans Petter Selasky 
182212515907SHans Petter Selasky 	if (init_attr->send_cq)
18238e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, cqn_snd, to_mcq(init_attr->send_cq)->mcq.cqn);
182412515907SHans Petter Selasky 
182512515907SHans Petter Selasky 	if (init_attr->recv_cq)
18268e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(init_attr->recv_cq)->mcq.cqn);
182712515907SHans Petter Selasky 
18288e6e287fSHans Petter Selasky 	MLX5_SET64(qpc, qpc, dbr_addr, qp->db.dma);
182912515907SHans Petter Selasky 
183012515907SHans Petter Selasky 	/* 0xffffff means we ask to work with cqe version 0 */
18318e6e287fSHans Petter Selasky 	if (MLX5_CAP_GEN(mdev, cqe_version) == MLX5_CQE_VERSION_V1)
183212515907SHans Petter Selasky 		MLX5_SET(qpc, qpc, user_index, uidx);
18338e6e287fSHans Petter Selasky 
18348e6e287fSHans Petter Selasky 	/* we use IB_QP_CREATE_IPOIB_UD_LSO to indicates ipoib qp */
18358e6e287fSHans Petter Selasky 	if (init_attr->qp_type == IB_QPT_UD &&
18368e6e287fSHans Petter Selasky 	    (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO)) {
18378e6e287fSHans Petter Selasky 		MLX5_SET(qpc, qpc, ulp_stateless_offload_mode, 1);
18388e6e287fSHans Petter Selasky 		qp->flags |= MLX5_IB_QP_LSO;
183912515907SHans Petter Selasky 	}
184012515907SHans Petter Selasky 
184112515907SHans Petter Selasky 	if (init_attr->qp_type == IB_QPT_RAW_PACKET) {
18428e6e287fSHans Petter Selasky 		qp->raw_packet_qp.sq.ubuffer.buf_addr = ucmd.sq_buf_addr;
18438e6e287fSHans Petter Selasky 		raw_packet_qp_copy_info(qp, &qp->raw_packet_qp);
18448e6e287fSHans Petter Selasky 		err = create_raw_packet_qp(dev, qp, in, pd);
184512515907SHans Petter Selasky 	} else {
1846788333d9SHans Petter Selasky 		err = mlx5_core_create_qp(dev->mdev, &base->mqp, in, inlen);
184712515907SHans Petter Selasky 	}
184812515907SHans Petter Selasky 
184912515907SHans Petter Selasky 	if (err) {
18508e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "create qp failed\n");
185112515907SHans Petter Selasky 		goto err_create;
185212515907SHans Petter Selasky 	}
185312515907SHans Petter Selasky 
185412515907SHans Petter Selasky 	kvfree(in);
18558e6e287fSHans Petter Selasky 
18568e6e287fSHans Petter Selasky 	base->container_mibqp = qp;
18578e6e287fSHans Petter Selasky 	base->mqp.event = mlx5_ib_qp_event;
185812515907SHans Petter Selasky 
185912515907SHans Petter Selasky 	get_cqs(init_attr->qp_type, init_attr->send_cq, init_attr->recv_cq,
186012515907SHans Petter Selasky 		&send_cq, &recv_cq);
186112515907SHans Petter Selasky 	spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
186212515907SHans Petter Selasky 	mlx5_ib_lock_cqs(send_cq, recv_cq);
186312515907SHans Petter Selasky 	/* Maintain device to QPs access, needed for further handling via reset
186412515907SHans Petter Selasky 	 * flow
186512515907SHans Petter Selasky 	 */
186612515907SHans Petter Selasky 	list_add_tail(&qp->qps_list, &dev->qp_list);
186712515907SHans Petter Selasky 	/* Maintain CQ to QPs access, needed for further handling via reset flow
186812515907SHans Petter Selasky 	 */
186912515907SHans Petter Selasky 	if (send_cq)
187012515907SHans Petter Selasky 		list_add_tail(&qp->cq_send_list, &send_cq->list_send_qp);
187112515907SHans Petter Selasky 	if (recv_cq)
187212515907SHans Petter Selasky 		list_add_tail(&qp->cq_recv_list, &recv_cq->list_recv_qp);
187312515907SHans Petter Selasky 	mlx5_ib_unlock_cqs(send_cq, recv_cq);
187412515907SHans Petter Selasky 	spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
187512515907SHans Petter Selasky 
187612515907SHans Petter Selasky 	return 0;
187712515907SHans Petter Selasky 
187812515907SHans Petter Selasky err_create:
187912515907SHans Petter Selasky 	if (qp->create_type == MLX5_QP_USER)
1880b633e08cSHans Petter Selasky 		destroy_qp_user(dev, pd, qp, base, udata);
188112515907SHans Petter Selasky 	else if (qp->create_type == MLX5_QP_KERNEL)
188212515907SHans Petter Selasky 		destroy_qp_kernel(dev, qp);
188312515907SHans Petter Selasky 
188412515907SHans Petter Selasky 	kvfree(in);
188512515907SHans Petter Selasky 	return err;
188612515907SHans Petter Selasky }
188712515907SHans Petter Selasky 
mlx5_ib_lock_cqs(struct mlx5_ib_cq * send_cq,struct mlx5_ib_cq * recv_cq)188812515907SHans Petter Selasky static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq)
188912515907SHans Petter Selasky 	__acquires(&send_cq->lock) __acquires(&recv_cq->lock)
189012515907SHans Petter Selasky {
189112515907SHans Petter Selasky 	if (send_cq) {
189212515907SHans Petter Selasky 		if (recv_cq) {
189312515907SHans Petter Selasky 			if (send_cq->mcq.cqn < recv_cq->mcq.cqn)  {
189412515907SHans Petter Selasky 				spin_lock(&send_cq->lock);
189512515907SHans Petter Selasky 				spin_lock_nested(&recv_cq->lock,
189612515907SHans Petter Selasky 						 SINGLE_DEPTH_NESTING);
189712515907SHans Petter Selasky 			} else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) {
189812515907SHans Petter Selasky 				spin_lock(&send_cq->lock);
189912515907SHans Petter Selasky 				__acquire(&recv_cq->lock);
190012515907SHans Petter Selasky 			} else {
190112515907SHans Petter Selasky 				spin_lock(&recv_cq->lock);
190212515907SHans Petter Selasky 				spin_lock_nested(&send_cq->lock,
190312515907SHans Petter Selasky 						 SINGLE_DEPTH_NESTING);
190412515907SHans Petter Selasky 			}
190512515907SHans Petter Selasky 		} else {
190612515907SHans Petter Selasky 			spin_lock(&send_cq->lock);
190712515907SHans Petter Selasky 			__acquire(&recv_cq->lock);
190812515907SHans Petter Selasky 		}
190912515907SHans Petter Selasky 	} else if (recv_cq) {
191012515907SHans Petter Selasky 		spin_lock(&recv_cq->lock);
191112515907SHans Petter Selasky 		__acquire(&send_cq->lock);
191212515907SHans Petter Selasky 	} else {
191312515907SHans Petter Selasky 		__acquire(&send_cq->lock);
191412515907SHans Petter Selasky 		__acquire(&recv_cq->lock);
191512515907SHans Petter Selasky 	}
191612515907SHans Petter Selasky }
191712515907SHans Petter Selasky 
mlx5_ib_unlock_cqs(struct mlx5_ib_cq * send_cq,struct mlx5_ib_cq * recv_cq)191812515907SHans Petter Selasky static void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq)
191912515907SHans Petter Selasky 	__releases(&send_cq->lock) __releases(&recv_cq->lock)
192012515907SHans Petter Selasky {
192112515907SHans Petter Selasky 	if (send_cq) {
192212515907SHans Petter Selasky 		if (recv_cq) {
192312515907SHans Petter Selasky 			if (send_cq->mcq.cqn < recv_cq->mcq.cqn)  {
192412515907SHans Petter Selasky 				spin_unlock(&recv_cq->lock);
192512515907SHans Petter Selasky 				spin_unlock(&send_cq->lock);
192612515907SHans Petter Selasky 			} else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) {
192712515907SHans Petter Selasky 				__release(&recv_cq->lock);
192812515907SHans Petter Selasky 				spin_unlock(&send_cq->lock);
192912515907SHans Petter Selasky 			} else {
193012515907SHans Petter Selasky 				spin_unlock(&send_cq->lock);
193112515907SHans Petter Selasky 				spin_unlock(&recv_cq->lock);
193212515907SHans Petter Selasky 			}
193312515907SHans Petter Selasky 		} else {
193412515907SHans Petter Selasky 			__release(&recv_cq->lock);
193512515907SHans Petter Selasky 			spin_unlock(&send_cq->lock);
193612515907SHans Petter Selasky 		}
193712515907SHans Petter Selasky 	} else if (recv_cq) {
193812515907SHans Petter Selasky 		__release(&send_cq->lock);
193912515907SHans Petter Selasky 		spin_unlock(&recv_cq->lock);
194012515907SHans Petter Selasky 	} else {
194112515907SHans Petter Selasky 		__release(&recv_cq->lock);
194212515907SHans Petter Selasky 		__release(&send_cq->lock);
194312515907SHans Petter Selasky 	}
194412515907SHans Petter Selasky }
194512515907SHans Petter Selasky 
get_pd(struct mlx5_ib_qp * qp)194612515907SHans Petter Selasky static struct mlx5_ib_pd *get_pd(struct mlx5_ib_qp *qp)
194712515907SHans Petter Selasky {
194812515907SHans Petter Selasky 	return to_mpd(qp->ibqp.pd);
194912515907SHans Petter Selasky }
195012515907SHans Petter Selasky 
get_cqs(enum ib_qp_type qp_type,struct ib_cq * ib_send_cq,struct ib_cq * ib_recv_cq,struct mlx5_ib_cq ** send_cq,struct mlx5_ib_cq ** recv_cq)19518e6e287fSHans Petter Selasky static void get_cqs(enum ib_qp_type qp_type,
19528e6e287fSHans Petter Selasky 		    struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq,
19538e6e287fSHans Petter Selasky 		    struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq)
19548e6e287fSHans Petter Selasky {
19558e6e287fSHans Petter Selasky 	switch (qp_type) {
19568e6e287fSHans Petter Selasky 	case IB_QPT_XRC_TGT:
19578e6e287fSHans Petter Selasky 		*send_cq = NULL;
19588e6e287fSHans Petter Selasky 		*recv_cq = NULL;
19598e6e287fSHans Petter Selasky 		break;
19608e6e287fSHans Petter Selasky 	case MLX5_IB_QPT_REG_UMR:
19618e6e287fSHans Petter Selasky 	case IB_QPT_XRC_INI:
19628e6e287fSHans Petter Selasky 		*send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL;
19638e6e287fSHans Petter Selasky 		*recv_cq = NULL;
19648e6e287fSHans Petter Selasky 		break;
19658e6e287fSHans Petter Selasky 
19668e6e287fSHans Petter Selasky 	case IB_QPT_SMI:
19678e6e287fSHans Petter Selasky 	case MLX5_IB_QPT_HW_GSI:
19688e6e287fSHans Petter Selasky 	case IB_QPT_RC:
19698e6e287fSHans Petter Selasky 	case IB_QPT_UC:
19708e6e287fSHans Petter Selasky 	case IB_QPT_UD:
19718e6e287fSHans Petter Selasky 	case IB_QPT_RAW_IPV6:
19728e6e287fSHans Petter Selasky 	case IB_QPT_RAW_ETHERTYPE:
19738e6e287fSHans Petter Selasky 	case IB_QPT_RAW_PACKET:
19748e6e287fSHans Petter Selasky 		*send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL;
19758e6e287fSHans Petter Selasky 		*recv_cq = ib_recv_cq ? to_mcq(ib_recv_cq) : NULL;
19768e6e287fSHans Petter Selasky 		break;
19778e6e287fSHans Petter Selasky 
19788e6e287fSHans Petter Selasky 	case IB_QPT_MAX:
19798e6e287fSHans Petter Selasky 	default:
19808e6e287fSHans Petter Selasky 		*send_cq = NULL;
19818e6e287fSHans Petter Selasky 		*recv_cq = NULL;
19828e6e287fSHans Petter Selasky 		break;
19838e6e287fSHans Petter Selasky 	}
19848e6e287fSHans Petter Selasky }
19858e6e287fSHans Petter Selasky 
19868e6e287fSHans Petter Selasky static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
19878e6e287fSHans Petter Selasky 				const struct mlx5_modify_raw_qp_param *raw_qp_param,
19888e6e287fSHans Petter Selasky 				u8 lag_tx_affinity);
19898e6e287fSHans Petter Selasky 
destroy_qp_common(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,struct ib_udata * udata)1990b633e08cSHans Petter Selasky static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
1991b633e08cSHans Petter Selasky 			      struct ib_udata *udata)
199212515907SHans Petter Selasky {
199312515907SHans Petter Selasky 	struct mlx5_ib_cq *send_cq, *recv_cq;
19948e6e287fSHans Petter Selasky 	struct mlx5_ib_qp_base *base = &qp->trans_qp.base;
199512515907SHans Petter Selasky 	unsigned long flags;
199612515907SHans Petter Selasky 	int err;
199712515907SHans Petter Selasky 
19988e6e287fSHans Petter Selasky 	if (qp->ibqp.rwq_ind_tbl) {
19998e6e287fSHans Petter Selasky 		destroy_rss_raw_qp_tir(dev, qp);
200012515907SHans Petter Selasky 		return;
20018e6e287fSHans Petter Selasky 	}
20028e6e287fSHans Petter Selasky 
20038e6e287fSHans Petter Selasky 	base = qp->ibqp.qp_type == IB_QPT_RAW_PACKET ?
20048e6e287fSHans Petter Selasky 	       &qp->raw_packet_qp.rq.base :
20058e6e287fSHans Petter Selasky 	       &qp->trans_qp.base;
200612515907SHans Petter Selasky 
200712515907SHans Petter Selasky 	if (qp->state != IB_QPS_RESET) {
200812515907SHans Petter Selasky 		if (qp->ibqp.qp_type != IB_QPT_RAW_PACKET) {
20098e6e287fSHans Petter Selasky 			mlx5_ib_qp_disable_pagefaults(qp);
20108e6e287fSHans Petter Selasky 			err = mlx5_core_qp_modify(dev->mdev,
2011788333d9SHans Petter Selasky 						  MLX5_CMD_OP_2RST_QP, 0,
2012788333d9SHans Petter Selasky 						  NULL, &base->mqp);
20138e6e287fSHans Petter Selasky 		} else {
20148e6e287fSHans Petter Selasky 			struct mlx5_modify_raw_qp_param raw_qp_param = {
20158e6e287fSHans Petter Selasky 				.operation = MLX5_CMD_OP_2RST_QP
20168e6e287fSHans Petter Selasky 			};
20178e6e287fSHans Petter Selasky 
20188e6e287fSHans Petter Selasky 			err = modify_raw_packet_qp(dev, qp, &raw_qp_param, 0);
20198e6e287fSHans Petter Selasky 		}
20208e6e287fSHans Petter Selasky 		if (err)
20218e6e287fSHans Petter Selasky 			mlx5_ib_warn(dev, "mlx5_ib: modify QP 0x%06x to RESET failed\n",
20228e6e287fSHans Petter Selasky 				     base->mqp.qpn);
202312515907SHans Petter Selasky 	}
202412515907SHans Petter Selasky 
202512515907SHans Petter Selasky 	get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq,
202612515907SHans Petter Selasky 		&send_cq, &recv_cq);
202712515907SHans Petter Selasky 
202812515907SHans Petter Selasky 	spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
202912515907SHans Petter Selasky 	mlx5_ib_lock_cqs(send_cq, recv_cq);
203012515907SHans Petter Selasky 	/* del from lists under both locks above to protect reset flow paths */
203112515907SHans Petter Selasky 	list_del(&qp->qps_list);
203212515907SHans Petter Selasky 	if (send_cq)
203312515907SHans Petter Selasky 		list_del(&qp->cq_send_list);
203412515907SHans Petter Selasky 
203512515907SHans Petter Selasky 	if (recv_cq)
203612515907SHans Petter Selasky 		list_del(&qp->cq_recv_list);
203712515907SHans Petter Selasky 
203812515907SHans Petter Selasky 	if (qp->create_type == MLX5_QP_KERNEL) {
20398e6e287fSHans Petter Selasky 		__mlx5_ib_cq_clean(recv_cq, base->mqp.qpn,
204012515907SHans Petter Selasky 				   qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
204112515907SHans Petter Selasky 		if (send_cq != recv_cq)
20428e6e287fSHans Petter Selasky 			__mlx5_ib_cq_clean(send_cq, base->mqp.qpn,
20438e6e287fSHans Petter Selasky 					   NULL);
204412515907SHans Petter Selasky 	}
204512515907SHans Petter Selasky 	mlx5_ib_unlock_cqs(send_cq, recv_cq);
204612515907SHans Petter Selasky 	spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
204712515907SHans Petter Selasky 
204812515907SHans Petter Selasky 	if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) {
20498e6e287fSHans Petter Selasky 		destroy_raw_packet_qp(dev, qp);
205012515907SHans Petter Selasky 	} else {
20518e6e287fSHans Petter Selasky 		err = mlx5_core_destroy_qp(dev->mdev, &base->mqp);
205212515907SHans Petter Selasky 		if (err)
205312515907SHans Petter Selasky 			mlx5_ib_warn(dev, "failed to destroy QP 0x%x\n",
20548e6e287fSHans Petter Selasky 				     base->mqp.qpn);
205512515907SHans Petter Selasky 	}
205612515907SHans Petter Selasky 
205712515907SHans Petter Selasky 	if (qp->create_type == MLX5_QP_KERNEL)
205812515907SHans Petter Selasky 		destroy_qp_kernel(dev, qp);
205912515907SHans Petter Selasky 	else if (qp->create_type == MLX5_QP_USER)
2060b633e08cSHans Petter Selasky 		destroy_qp_user(dev, &get_pd(qp)->ibpd, qp, base, udata);
206112515907SHans Petter Selasky }
206212515907SHans Petter Selasky 
ib_qp_type_str(enum ib_qp_type type)206312515907SHans Petter Selasky static const char *ib_qp_type_str(enum ib_qp_type type)
206412515907SHans Petter Selasky {
206512515907SHans Petter Selasky 	switch (type) {
206612515907SHans Petter Selasky 	case IB_QPT_SMI:
206712515907SHans Petter Selasky 		return "IB_QPT_SMI";
206812515907SHans Petter Selasky 	case IB_QPT_GSI:
206912515907SHans Petter Selasky 		return "IB_QPT_GSI";
207012515907SHans Petter Selasky 	case IB_QPT_RC:
207112515907SHans Petter Selasky 		return "IB_QPT_RC";
207212515907SHans Petter Selasky 	case IB_QPT_UC:
207312515907SHans Petter Selasky 		return "IB_QPT_UC";
207412515907SHans Petter Selasky 	case IB_QPT_UD:
207512515907SHans Petter Selasky 		return "IB_QPT_UD";
207612515907SHans Petter Selasky 	case IB_QPT_RAW_IPV6:
207712515907SHans Petter Selasky 		return "IB_QPT_RAW_IPV6";
207812515907SHans Petter Selasky 	case IB_QPT_RAW_ETHERTYPE:
207912515907SHans Petter Selasky 		return "IB_QPT_RAW_ETHERTYPE";
208012515907SHans Petter Selasky 	case IB_QPT_XRC_INI:
208112515907SHans Petter Selasky 		return "IB_QPT_XRC_INI";
208212515907SHans Petter Selasky 	case IB_QPT_XRC_TGT:
208312515907SHans Petter Selasky 		return "IB_QPT_XRC_TGT";
208412515907SHans Petter Selasky 	case IB_QPT_RAW_PACKET:
208512515907SHans Petter Selasky 		return "IB_QPT_RAW_PACKET";
20868e6e287fSHans Petter Selasky 	case MLX5_IB_QPT_REG_UMR:
20878e6e287fSHans Petter Selasky 		return "MLX5_IB_QPT_REG_UMR";
208812515907SHans Petter Selasky 	case IB_QPT_MAX:
208912515907SHans Petter Selasky 	default:
209012515907SHans Petter Selasky 		return "Invalid QP type";
209112515907SHans Petter Selasky 	}
209212515907SHans Petter Selasky }
209312515907SHans Petter Selasky 
mlx5_ib_create_qp(struct ib_pd * pd,struct ib_qp_init_attr * init_attr,struct ib_udata * udata)209412515907SHans Petter Selasky struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
209512515907SHans Petter Selasky 				struct ib_qp_init_attr *init_attr,
209612515907SHans Petter Selasky 				struct ib_udata *udata)
209712515907SHans Petter Selasky {
209812515907SHans Petter Selasky 	struct mlx5_ib_dev *dev;
209912515907SHans Petter Selasky 	struct mlx5_ib_qp *qp;
210012515907SHans Petter Selasky 	u16 xrcdn = 0;
210112515907SHans Petter Selasky 	int err;
210212515907SHans Petter Selasky 
210312515907SHans Petter Selasky 	if (pd) {
210412515907SHans Petter Selasky 		dev = to_mdev(pd->device);
21058e6e287fSHans Petter Selasky 
21068e6e287fSHans Petter Selasky 		if (init_attr->qp_type == IB_QPT_RAW_PACKET) {
21078e6e287fSHans Petter Selasky 			if (!pd->uobject) {
21088e6e287fSHans Petter Selasky 				mlx5_ib_dbg(dev, "Raw Packet QP is not supported for kernel consumers\n");
21098e6e287fSHans Petter Selasky 				return ERR_PTR(-EINVAL);
21108e6e287fSHans Petter Selasky 			} else if (!to_mucontext(pd->uobject->context)->cqe_version) {
21118e6e287fSHans Petter Selasky 				mlx5_ib_dbg(dev, "Raw Packet QP is only supported for CQE version > 0\n");
21128e6e287fSHans Petter Selasky 				return ERR_PTR(-EINVAL);
21138e6e287fSHans Petter Selasky 			}
21148e6e287fSHans Petter Selasky 		}
211512515907SHans Petter Selasky 	} else {
211612515907SHans Petter Selasky 		/* being cautious here */
21178e6e287fSHans Petter Selasky 		if (init_attr->qp_type != IB_QPT_XRC_TGT &&
21188e6e287fSHans Petter Selasky 		    init_attr->qp_type != MLX5_IB_QPT_REG_UMR) {
21198e6e287fSHans Petter Selasky 			pr_warn("%s: no PD for transport %s\n", __func__,
21208e6e287fSHans Petter Selasky 				ib_qp_type_str(init_attr->qp_type));
212112515907SHans Petter Selasky 			return ERR_PTR(-EINVAL);
212212515907SHans Petter Selasky 		}
212312515907SHans Petter Selasky 		dev = to_mdev(to_mxrcd(init_attr->xrcd)->ibxrcd.device);
212412515907SHans Petter Selasky 	}
212512515907SHans Petter Selasky 
212612515907SHans Petter Selasky 	switch (init_attr->qp_type) {
212712515907SHans Petter Selasky 	case IB_QPT_XRC_TGT:
212812515907SHans Petter Selasky 	case IB_QPT_XRC_INI:
212912515907SHans Petter Selasky 		if (!MLX5_CAP_GEN(dev->mdev, xrc)) {
21308e6e287fSHans Petter Selasky 			mlx5_ib_dbg(dev, "XRC not supported\n");
213112515907SHans Petter Selasky 			return ERR_PTR(-ENOSYS);
213212515907SHans Petter Selasky 		}
213312515907SHans Petter Selasky 		init_attr->recv_cq = NULL;
213412515907SHans Petter Selasky 		if (init_attr->qp_type == IB_QPT_XRC_TGT) {
213512515907SHans Petter Selasky 			xrcdn = to_mxrcd(init_attr->xrcd)->xrcdn;
213612515907SHans Petter Selasky 			init_attr->send_cq = NULL;
213712515907SHans Petter Selasky 		}
213812515907SHans Petter Selasky 
213912515907SHans Petter Selasky 		/* fall through */
21408e6e287fSHans Petter Selasky 	case IB_QPT_RAW_PACKET:
214112515907SHans Petter Selasky 	case IB_QPT_RC:
214212515907SHans Petter Selasky 	case IB_QPT_UC:
214312515907SHans Petter Selasky 	case IB_QPT_UD:
214412515907SHans Petter Selasky 	case IB_QPT_SMI:
21458e6e287fSHans Petter Selasky 	case MLX5_IB_QPT_HW_GSI:
21468e6e287fSHans Petter Selasky 	case MLX5_IB_QPT_REG_UMR:
214712515907SHans Petter Selasky 		qp = kzalloc(sizeof(*qp), GFP_KERNEL);
214812515907SHans Petter Selasky 		if (!qp)
214912515907SHans Petter Selasky 			return ERR_PTR(-ENOMEM);
215012515907SHans Petter Selasky 
215112515907SHans Petter Selasky 		err = create_qp_common(dev, pd, init_attr, udata, qp);
215212515907SHans Petter Selasky 		if (err) {
21538e6e287fSHans Petter Selasky 			mlx5_ib_dbg(dev, "create_qp_common failed\n");
215412515907SHans Petter Selasky 			kfree(qp);
215512515907SHans Petter Selasky 			return ERR_PTR(err);
215612515907SHans Petter Selasky 		}
215712515907SHans Petter Selasky 
215812515907SHans Petter Selasky 		if (is_qp0(init_attr->qp_type))
215912515907SHans Petter Selasky 			qp->ibqp.qp_num = 0;
216012515907SHans Petter Selasky 		else if (is_qp1(init_attr->qp_type))
216112515907SHans Petter Selasky 			qp->ibqp.qp_num = 1;
216212515907SHans Petter Selasky 		else
21638e6e287fSHans Petter Selasky 			qp->ibqp.qp_num = qp->trans_qp.base.mqp.qpn;
216412515907SHans Petter Selasky 
216512515907SHans Petter Selasky 		mlx5_ib_dbg(dev, "ib qpnum 0x%x, mlx qpn 0x%x, rcqn 0x%x, scqn 0x%x\n",
21668e6e287fSHans Petter Selasky 			    qp->ibqp.qp_num, qp->trans_qp.base.mqp.qpn,
21678e6e287fSHans Petter Selasky 			    init_attr->recv_cq ? to_mcq(init_attr->recv_cq)->mcq.cqn : -1,
21688e6e287fSHans Petter Selasky 			    init_attr->send_cq ? to_mcq(init_attr->send_cq)->mcq.cqn : -1);
216912515907SHans Petter Selasky 
21708e6e287fSHans Petter Selasky 		qp->trans_qp.xrcdn = xrcdn;
217112515907SHans Petter Selasky 
217212515907SHans Petter Selasky 		break;
217312515907SHans Petter Selasky 
21748e6e287fSHans Petter Selasky 	case IB_QPT_GSI:
21758e6e287fSHans Petter Selasky 		return mlx5_ib_gsi_create_qp(pd, init_attr);
21768e6e287fSHans Petter Selasky 
217712515907SHans Petter Selasky 	case IB_QPT_RAW_IPV6:
21788e6e287fSHans Petter Selasky 	case IB_QPT_RAW_ETHERTYPE:
217912515907SHans Petter Selasky 	case IB_QPT_MAX:
218012515907SHans Petter Selasky 	default:
21818e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "unsupported qp type %d\n",
218212515907SHans Petter Selasky 			    init_attr->qp_type);
218312515907SHans Petter Selasky 		/* Don't support raw QPs */
218412515907SHans Petter Selasky 		return ERR_PTR(-EINVAL);
218512515907SHans Petter Selasky 	}
218612515907SHans Petter Selasky 
218712515907SHans Petter Selasky 	return &qp->ibqp;
218812515907SHans Petter Selasky }
218912515907SHans Petter Selasky 
mlx5_ib_destroy_qp(struct ib_qp * qp,struct ib_udata * udata)2190b633e08cSHans Petter Selasky int mlx5_ib_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
219112515907SHans Petter Selasky {
219212515907SHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(qp->device);
219312515907SHans Petter Selasky 	struct mlx5_ib_qp *mqp = to_mqp(qp);
219412515907SHans Petter Selasky 
21958e6e287fSHans Petter Selasky 	if (unlikely(qp->qp_type == IB_QPT_GSI))
21968e6e287fSHans Petter Selasky 		return mlx5_ib_gsi_destroy_qp(qp);
21978e6e287fSHans Petter Selasky 
2198b633e08cSHans Petter Selasky 	destroy_qp_common(dev, mqp, udata);
219912515907SHans Petter Selasky 
220012515907SHans Petter Selasky 	kfree(mqp);
220112515907SHans Petter Selasky 
220212515907SHans Petter Selasky 	return 0;
220312515907SHans Petter Selasky }
220412515907SHans Petter Selasky 
to_mlx5_access_flags(struct mlx5_ib_qp * qp,const struct ib_qp_attr * attr,int attr_mask,__be32 * hw_access_flags_be)2205cf88b86eSHans Petter Selasky static int to_mlx5_access_flags(struct mlx5_ib_qp *qp,
2206cf88b86eSHans Petter Selasky 				const struct ib_qp_attr *attr,
2207cf88b86eSHans Petter Selasky 				int attr_mask, __be32 *hw_access_flags_be)
220812515907SHans Petter Selasky {
220912515907SHans Petter Selasky 	u8 dest_rd_atomic;
2210cf88b86eSHans Petter Selasky 	u32 access_flags, hw_access_flags = 0;
2211cf88b86eSHans Petter Selasky 
2212cf88b86eSHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device);
221312515907SHans Petter Selasky 
221412515907SHans Petter Selasky 	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
221512515907SHans Petter Selasky 		dest_rd_atomic = attr->max_dest_rd_atomic;
221612515907SHans Petter Selasky 	else
22178e6e287fSHans Petter Selasky 		dest_rd_atomic = qp->trans_qp.resp_depth;
221812515907SHans Petter Selasky 
221912515907SHans Petter Selasky 	if (attr_mask & IB_QP_ACCESS_FLAGS)
222012515907SHans Petter Selasky 		access_flags = attr->qp_access_flags;
222112515907SHans Petter Selasky 	else
22228e6e287fSHans Petter Selasky 		access_flags = qp->trans_qp.atomic_rd_en;
222312515907SHans Petter Selasky 
222412515907SHans Petter Selasky 	if (!dest_rd_atomic)
222512515907SHans Petter Selasky 		access_flags &= IB_ACCESS_REMOTE_WRITE;
222612515907SHans Petter Selasky 
222712515907SHans Petter Selasky 	if (access_flags & IB_ACCESS_REMOTE_READ)
222812515907SHans Petter Selasky 		hw_access_flags |= MLX5_QP_BIT_RRE;
2229cf88b86eSHans Petter Selasky 	if (access_flags & IB_ACCESS_REMOTE_ATOMIC) {
2230cf88b86eSHans Petter Selasky 		int atomic_mode;
2231cf88b86eSHans Petter Selasky 
2232cf88b86eSHans Petter Selasky 		atomic_mode = get_atomic_mode(dev, qp->ibqp.qp_type);
2233cf88b86eSHans Petter Selasky 		if (atomic_mode < 0)
2234cf88b86eSHans Petter Selasky 			return -EOPNOTSUPP;
2235cf88b86eSHans Petter Selasky 
2236cf88b86eSHans Petter Selasky 		hw_access_flags |= MLX5_QP_BIT_RAE;
2237cf88b86eSHans Petter Selasky 		hw_access_flags |= atomic_mode << MLX5_ATOMIC_MODE_OFF;
2238cf88b86eSHans Petter Selasky 	}
2239cf88b86eSHans Petter Selasky 
224012515907SHans Petter Selasky 	if (access_flags & IB_ACCESS_REMOTE_WRITE)
224112515907SHans Petter Selasky 		hw_access_flags |= MLX5_QP_BIT_RWE;
224212515907SHans Petter Selasky 
2243cf88b86eSHans Petter Selasky 	*hw_access_flags_be = cpu_to_be32(hw_access_flags);
2244cf88b86eSHans Petter Selasky 
2245cf88b86eSHans Petter Selasky 	return 0;
224612515907SHans Petter Selasky }
224712515907SHans Petter Selasky 
224812515907SHans Petter Selasky enum {
224912515907SHans Petter Selasky 	MLX5_PATH_FLAG_FL	= 1 << 0,
225012515907SHans Petter Selasky 	MLX5_PATH_FLAG_FREE_AR	= 1 << 1,
225112515907SHans Petter Selasky 	MLX5_PATH_FLAG_COUNTER	= 1 << 2,
225212515907SHans Petter Selasky };
225312515907SHans Petter Selasky 
ib_rate_to_mlx5(struct mlx5_ib_dev * dev,u8 rate)225412515907SHans Petter Selasky static int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate)
225512515907SHans Petter Selasky {
225612515907SHans Petter Selasky 	if (rate == IB_RATE_PORT_CURRENT) {
225712515907SHans Petter Selasky 		return 0;
225886a39779SHans Petter Selasky 	} else if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_600_GBPS) {
225912515907SHans Petter Selasky 		return -EINVAL;
226012515907SHans Petter Selasky 	} else {
226112515907SHans Petter Selasky 		while (rate != IB_RATE_2_5_GBPS &&
226212515907SHans Petter Selasky 		       !(1 << (rate + MLX5_STAT_RATE_OFFSET) &
226312515907SHans Petter Selasky 			 MLX5_CAP_GEN(dev->mdev, stat_rate_support)))
226412515907SHans Petter Selasky 			--rate;
226512515907SHans Petter Selasky 	}
226612515907SHans Petter Selasky 
226712515907SHans Petter Selasky 	return rate + MLX5_STAT_RATE_OFFSET;
226812515907SHans Petter Selasky }
226912515907SHans Petter Selasky 
modify_raw_packet_eth_prio(struct mlx5_core_dev * dev,struct mlx5_ib_sq * sq,u8 sl,struct ib_pd * pd)22708e6e287fSHans Petter Selasky static int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev,
2271b633e08cSHans Petter Selasky 				      struct mlx5_ib_sq *sq, u8 sl,
2272b633e08cSHans Petter Selasky 				      struct ib_pd *pd)
22738e6e287fSHans Petter Selasky {
22748e6e287fSHans Petter Selasky 	void *in;
22758e6e287fSHans Petter Selasky 	void *tisc;
22768e6e287fSHans Petter Selasky 	int inlen;
22778e6e287fSHans Petter Selasky 	int err;
22788e6e287fSHans Petter Selasky 
22798e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(modify_tis_in);
22808e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
22818e6e287fSHans Petter Selasky 	if (!in)
22828e6e287fSHans Petter Selasky 		return -ENOMEM;
22838e6e287fSHans Petter Selasky 
22848e6e287fSHans Petter Selasky 	MLX5_SET(modify_tis_in, in, bitmask.prio, 1);
2285b633e08cSHans Petter Selasky 	MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid);
22868e6e287fSHans Petter Selasky 
22878e6e287fSHans Petter Selasky 	tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx);
22888e6e287fSHans Petter Selasky 	MLX5_SET(tisc, tisc, prio, ((sl & 0x7) << 1));
22898e6e287fSHans Petter Selasky 
22908e6e287fSHans Petter Selasky 	err = mlx5_core_modify_tis(dev, sq->tisn, in, inlen);
22918e6e287fSHans Petter Selasky 
22928e6e287fSHans Petter Selasky 	kvfree(in);
22938e6e287fSHans Petter Selasky 
22948e6e287fSHans Petter Selasky 	return err;
22958e6e287fSHans Petter Selasky }
22968e6e287fSHans Petter Selasky 
modify_raw_packet_tx_affinity(struct mlx5_core_dev * dev,struct mlx5_ib_sq * sq,u8 tx_affinity,struct ib_pd * pd)22978e6e287fSHans Petter Selasky static int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev,
2298b633e08cSHans Petter Selasky 					 struct mlx5_ib_sq *sq, u8 tx_affinity,
2299b633e08cSHans Petter Selasky 					 struct ib_pd *pd)
23008e6e287fSHans Petter Selasky {
23018e6e287fSHans Petter Selasky 	void *in;
23028e6e287fSHans Petter Selasky 	void *tisc;
23038e6e287fSHans Petter Selasky 	int inlen;
23048e6e287fSHans Petter Selasky 	int err;
23058e6e287fSHans Petter Selasky 
23068e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(modify_tis_in);
23078e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
23088e6e287fSHans Petter Selasky 	if (!in)
23098e6e287fSHans Petter Selasky 		return -ENOMEM;
23108e6e287fSHans Petter Selasky 
23118e6e287fSHans Petter Selasky 	MLX5_SET(modify_tis_in, in, bitmask.lag_tx_port_affinity, 1);
2312b633e08cSHans Petter Selasky 	MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid);
23138e6e287fSHans Petter Selasky 
23148e6e287fSHans Petter Selasky 	tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx);
23158e6e287fSHans Petter Selasky 	MLX5_SET(tisc, tisc, lag_tx_port_affinity, tx_affinity);
23168e6e287fSHans Petter Selasky 
23178e6e287fSHans Petter Selasky 	err = mlx5_core_modify_tis(dev, sq->tisn, in, inlen);
23188e6e287fSHans Petter Selasky 
23198e6e287fSHans Petter Selasky 	kvfree(in);
23208e6e287fSHans Petter Selasky 
23218e6e287fSHans Petter Selasky 	return err;
23228e6e287fSHans Petter Selasky }
23238e6e287fSHans Petter Selasky 
mlx5_set_path(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,const struct ib_ah_attr * ah,struct mlx5_qp_path * path,u8 port,int attr_mask,u32 path_flags,const struct ib_qp_attr * attr,bool alt)23248e6e287fSHans Petter Selasky static int mlx5_set_path(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
23258e6e287fSHans Petter Selasky 			 const struct ib_ah_attr *ah,
232612515907SHans Petter Selasky 			 struct mlx5_qp_path *path, u8 port, int attr_mask,
232712515907SHans Petter Selasky 			 u32 path_flags, const struct ib_qp_attr *attr,
23288e6e287fSHans Petter Selasky 			 bool alt)
232912515907SHans Petter Selasky {
23308e6e287fSHans Petter Selasky 	enum rdma_link_layer ll = rdma_port_get_link_layer(&dev->ib_dev, port);
233112515907SHans Petter Selasky 	int err;
2332ed0cee0bSHans Petter Selasky 	enum ib_gid_type gid_type;
233312515907SHans Petter Selasky 
23348e6e287fSHans Petter Selasky 	if (attr_mask & IB_QP_PKEY_INDEX)
23358e6e287fSHans Petter Selasky 		path->pkey_index = cpu_to_be16(alt ? attr->alt_pkey_index :
23368e6e287fSHans Petter Selasky 						     attr->pkey_index);
23378e6e287fSHans Petter Selasky 
23388e6e287fSHans Petter Selasky 	if (ah->ah_flags & IB_AH_GRH) {
23398e6e287fSHans Petter Selasky 		if (ah->grh.sgid_index >=
23408e6e287fSHans Petter Selasky 		    dev->mdev->port_caps[port - 1].gid_table_len) {
23418e6e287fSHans Petter Selasky 			pr_err("sgid_index (%u) too large. max is %d\n",
23428e6e287fSHans Petter Selasky 			       ah->grh.sgid_index,
23438e6e287fSHans Petter Selasky 			       dev->mdev->port_caps[port - 1].gid_table_len);
234412515907SHans Petter Selasky 			return -EINVAL;
234512515907SHans Petter Selasky 		}
234612515907SHans Petter Selasky 	}
234712515907SHans Petter Selasky 
234812515907SHans Petter Selasky 	if (ll == IB_LINK_LAYER_ETHERNET) {
234912515907SHans Petter Selasky 		if (!(ah->ah_flags & IB_AH_GRH))
235012515907SHans Petter Selasky 			return -EINVAL;
2351ed0cee0bSHans Petter Selasky 		err = mlx5_get_roce_gid_type(dev, port, ah->grh.sgid_index,
2352ed0cee0bSHans Petter Selasky 					     &gid_type);
2353ed0cee0bSHans Petter Selasky 		if (err)
2354ed0cee0bSHans Petter Selasky 			return err;
235512515907SHans Petter Selasky 		memcpy(path->rmac, ah->dmac, sizeof(ah->dmac));
235612515907SHans Petter Selasky 		path->udp_sport = mlx5_get_roce_udp_sport(dev, port,
23578e6e287fSHans Petter Selasky 							  ah->grh.sgid_index);
23588e6e287fSHans Petter Selasky 		path->dci_cfi_prio_sl = (ah->sl & 0x7) << 4;
2359ed0cee0bSHans Petter Selasky 		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP)
2360ed0cee0bSHans Petter Selasky 			path->ecn_dscp = (ah->grh.traffic_class >> 2) & 0x3f;
236112515907SHans Petter Selasky 	} else {
236212515907SHans Petter Selasky 		path->fl_free_ar = (path_flags & MLX5_PATH_FLAG_FL) ? 0x80 : 0;
23638e6e287fSHans Petter Selasky 		path->fl_free_ar |=
23648e6e287fSHans Petter Selasky 			(path_flags & MLX5_PATH_FLAG_FREE_AR) ? 0x40 : 0;
236512515907SHans Petter Selasky 		path->rlid = cpu_to_be16(ah->dlid);
23668e6e287fSHans Petter Selasky 		path->grh_mlid = ah->src_path_bits & 0x7f;
236712515907SHans Petter Selasky 		if (ah->ah_flags & IB_AH_GRH)
236812515907SHans Petter Selasky 			path->grh_mlid	|= 1 << 7;
236912515907SHans Petter Selasky 		path->dci_cfi_prio_sl = ah->sl & 0xf;
237012515907SHans Petter Selasky 	}
237112515907SHans Petter Selasky 
237212515907SHans Petter Selasky 	if (ah->ah_flags & IB_AH_GRH) {
237312515907SHans Petter Selasky 		path->mgid_index = ah->grh.sgid_index;
237412515907SHans Petter Selasky 		path->hop_limit  = ah->grh.hop_limit;
237512515907SHans Petter Selasky 		path->tclass_flowlabel =
237612515907SHans Petter Selasky 			cpu_to_be32((ah->grh.traffic_class << 20) |
237712515907SHans Petter Selasky 				    (ah->grh.flow_label));
237812515907SHans Petter Selasky 		memcpy(path->rgid, ah->grh.dgid.raw, 16);
237912515907SHans Petter Selasky 	}
238012515907SHans Petter Selasky 
238112515907SHans Petter Selasky 	err = ib_rate_to_mlx5(dev, ah->static_rate);
238212515907SHans Petter Selasky 	if (err < 0)
238312515907SHans Petter Selasky 		return err;
238412515907SHans Petter Selasky 	path->static_rate = err;
238512515907SHans Petter Selasky 	path->port = port;
238612515907SHans Petter Selasky 
238712515907SHans Petter Selasky 	if (attr_mask & IB_QP_TIMEOUT)
23888e6e287fSHans Petter Selasky 		path->ackto_lt = (alt ? attr->alt_timeout : attr->timeout) << 3;
23898e6e287fSHans Petter Selasky 
23908e6e287fSHans Petter Selasky 	if ((qp->ibqp.qp_type == IB_QPT_RAW_PACKET) && qp->sq.wqe_cnt)
23918e6e287fSHans Petter Selasky 		return modify_raw_packet_eth_prio(dev->mdev,
23928e6e287fSHans Petter Selasky 						  &qp->raw_packet_qp.sq,
2393b633e08cSHans Petter Selasky 						  ah->sl & 0xf, qp->ibqp.pd);
239412515907SHans Petter Selasky 
239512515907SHans Petter Selasky 	return 0;
239612515907SHans Petter Selasky }
239712515907SHans Petter Selasky 
239812515907SHans Petter Selasky static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_QP_ST_MAX] = {
239912515907SHans Petter Selasky 	[MLX5_QP_STATE_INIT] = {
240012515907SHans Petter Selasky 		[MLX5_QP_STATE_INIT] = {
240112515907SHans Petter Selasky 			[MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE		|
240212515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RAE		|
240312515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RWE		|
240412515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PKEY_INDEX	|
240512515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PRI_PORT,
240612515907SHans Petter Selasky 			[MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE		|
240712515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PKEY_INDEX	|
240812515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PRI_PORT,
240912515907SHans Petter Selasky 			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX	|
241012515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_Q_KEY		|
241112515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PRI_PORT,
241212515907SHans Petter Selasky 		},
241312515907SHans Petter Selasky 		[MLX5_QP_STATE_RTR] = {
241412515907SHans Petter Selasky 			[MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH  |
241512515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RRE            |
241612515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RAE            |
241712515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RWE            |
241812515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PKEY_INDEX,
241912515907SHans Petter Selasky 			[MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH  |
242012515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RWE            |
242112515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PKEY_INDEX,
242212515907SHans Petter Selasky 			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX     |
242312515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_Q_KEY,
242412515907SHans Petter Selasky 			[MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_PKEY_INDEX	|
242512515907SHans Petter Selasky 					   MLX5_QP_OPTPAR_Q_KEY,
242612515907SHans Petter Selasky 			[MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH |
242712515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RRE            |
242812515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RAE            |
242912515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RWE            |
243012515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PKEY_INDEX,
243112515907SHans Petter Selasky 		},
243212515907SHans Petter Selasky 	},
243312515907SHans Petter Selasky 	[MLX5_QP_STATE_RTR] = {
243412515907SHans Petter Selasky 		[MLX5_QP_STATE_RTS] = {
243512515907SHans Petter Selasky 			[MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH	|
243612515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RRE		|
243712515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RAE		|
243812515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RWE		|
243912515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PM_STATE	|
244012515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RNR_TIMEOUT,
244112515907SHans Petter Selasky 			[MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH	|
244212515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RWE		|
244312515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PM_STATE,
244412515907SHans Petter Selasky 			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY,
244512515907SHans Petter Selasky 		},
244612515907SHans Petter Selasky 	},
244712515907SHans Petter Selasky 	[MLX5_QP_STATE_RTS] = {
244812515907SHans Petter Selasky 		[MLX5_QP_STATE_RTS] = {
244912515907SHans Petter Selasky 			[MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE		|
245012515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RAE		|
245112515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RWE		|
245212515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_RNR_TIMEOUT	|
245312515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PM_STATE	|
245412515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_ALT_ADDR_PATH,
245512515907SHans Petter Selasky 			[MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE		|
245612515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_PM_STATE	|
245712515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_ALT_ADDR_PATH,
245812515907SHans Petter Selasky 			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY		|
245912515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_SRQN		|
246012515907SHans Petter Selasky 					  MLX5_QP_OPTPAR_CQN_RCV,
246112515907SHans Petter Selasky 		},
246212515907SHans Petter Selasky 	},
246312515907SHans Petter Selasky 	[MLX5_QP_STATE_SQER] = {
246412515907SHans Petter Selasky 		[MLX5_QP_STATE_RTS] = {
246512515907SHans Petter Selasky 			[MLX5_QP_ST_UD]	 = MLX5_QP_OPTPAR_Q_KEY,
246612515907SHans Petter Selasky 			[MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY,
246712515907SHans Petter Selasky 			[MLX5_QP_ST_UC]	 = MLX5_QP_OPTPAR_RWE,
246812515907SHans Petter Selasky 			[MLX5_QP_ST_RC]	 = MLX5_QP_OPTPAR_RNR_TIMEOUT	|
246912515907SHans Petter Selasky 					   MLX5_QP_OPTPAR_RWE		|
247012515907SHans Petter Selasky 					   MLX5_QP_OPTPAR_RAE		|
247112515907SHans Petter Selasky 					   MLX5_QP_OPTPAR_RRE,
247212515907SHans Petter Selasky 		},
247312515907SHans Petter Selasky 	},
247412515907SHans Petter Selasky };
247512515907SHans Petter Selasky 
ib_nr_to_mlx5_nr(int ib_mask)247612515907SHans Petter Selasky static int ib_nr_to_mlx5_nr(int ib_mask)
247712515907SHans Petter Selasky {
247812515907SHans Petter Selasky 	switch (ib_mask) {
247912515907SHans Petter Selasky 	case IB_QP_STATE:
248012515907SHans Petter Selasky 		return 0;
248112515907SHans Petter Selasky 	case IB_QP_CUR_STATE:
248212515907SHans Petter Selasky 		return 0;
248312515907SHans Petter Selasky 	case IB_QP_EN_SQD_ASYNC_NOTIFY:
248412515907SHans Petter Selasky 		return 0;
248512515907SHans Petter Selasky 	case IB_QP_ACCESS_FLAGS:
248612515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_RRE |
248712515907SHans Petter Selasky 			MLX5_QP_OPTPAR_RAE;
248812515907SHans Petter Selasky 	case IB_QP_PKEY_INDEX:
248912515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_PKEY_INDEX;
249012515907SHans Petter Selasky 	case IB_QP_PORT:
249112515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_PRI_PORT;
249212515907SHans Petter Selasky 	case IB_QP_QKEY:
249312515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_Q_KEY;
249412515907SHans Petter Selasky 	case IB_QP_AV:
249512515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_PRIMARY_ADDR_PATH |
249612515907SHans Petter Selasky 			MLX5_QP_OPTPAR_PRI_PORT;
249712515907SHans Petter Selasky 	case IB_QP_PATH_MTU:
249812515907SHans Petter Selasky 		return 0;
249912515907SHans Petter Selasky 	case IB_QP_TIMEOUT:
250012515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_ACK_TIMEOUT;
250112515907SHans Petter Selasky 	case IB_QP_RETRY_CNT:
250212515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_RETRY_COUNT;
250312515907SHans Petter Selasky 	case IB_QP_RNR_RETRY:
250412515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_RNR_RETRY;
250512515907SHans Petter Selasky 	case IB_QP_RQ_PSN:
250612515907SHans Petter Selasky 		return 0;
250712515907SHans Petter Selasky 	case IB_QP_MAX_QP_RD_ATOMIC:
250812515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_SRA_MAX;
250912515907SHans Petter Selasky 	case IB_QP_ALT_PATH:
251012515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_ALT_ADDR_PATH;
251112515907SHans Petter Selasky 	case IB_QP_MIN_RNR_TIMER:
251212515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_RNR_TIMEOUT;
251312515907SHans Petter Selasky 	case IB_QP_SQ_PSN:
251412515907SHans Petter Selasky 		return 0;
251512515907SHans Petter Selasky 	case IB_QP_MAX_DEST_RD_ATOMIC:
251612515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_RRA_MAX | MLX5_QP_OPTPAR_RWE |
251712515907SHans Petter Selasky 			MLX5_QP_OPTPAR_RRE | MLX5_QP_OPTPAR_RAE;
251812515907SHans Petter Selasky 	case IB_QP_PATH_MIG_STATE:
251912515907SHans Petter Selasky 		return MLX5_QP_OPTPAR_PM_STATE;
252012515907SHans Petter Selasky 	case IB_QP_CAP:
252112515907SHans Petter Selasky 		return 0;
252212515907SHans Petter Selasky 	case IB_QP_DEST_QPN:
252312515907SHans Petter Selasky 		return 0;
252412515907SHans Petter Selasky 	}
252512515907SHans Petter Selasky 	return 0;
252612515907SHans Petter Selasky }
252712515907SHans Petter Selasky 
ib_mask_to_mlx5_opt(int ib_mask)252812515907SHans Petter Selasky static int ib_mask_to_mlx5_opt(int ib_mask)
252912515907SHans Petter Selasky {
253012515907SHans Petter Selasky 	int result = 0;
253112515907SHans Petter Selasky 	int i;
253212515907SHans Petter Selasky 
253312515907SHans Petter Selasky 	for (i = 0; i < 8 * sizeof(int); i++) {
253412515907SHans Petter Selasky 		if ((1 << i) & ib_mask)
253512515907SHans Petter Selasky 			result |= ib_nr_to_mlx5_nr(1 << i);
253612515907SHans Petter Selasky 	}
253712515907SHans Petter Selasky 
253812515907SHans Petter Selasky 	return result;
253912515907SHans Petter Selasky }
254012515907SHans Petter Selasky 
modify_raw_packet_qp_rq(struct mlx5_ib_dev * dev,struct mlx5_ib_rq * rq,int new_state,const struct mlx5_modify_raw_qp_param * raw_qp_param,struct ib_pd * pd)2541b633e08cSHans Petter Selasky static int modify_raw_packet_qp_rq(
2542b633e08cSHans Petter Selasky 	struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, int new_state,
2543b633e08cSHans Petter Selasky 	const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd)
25448e6e287fSHans Petter Selasky {
25458e6e287fSHans Petter Selasky 	void *in;
25468e6e287fSHans Petter Selasky 	void *rqc;
25478e6e287fSHans Petter Selasky 	int inlen;
25488e6e287fSHans Petter Selasky 	int err;
25498e6e287fSHans Petter Selasky 
25508e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(modify_rq_in);
25518e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
25528e6e287fSHans Petter Selasky 	if (!in)
25538e6e287fSHans Petter Selasky 		return -ENOMEM;
25548e6e287fSHans Petter Selasky 
25558e6e287fSHans Petter Selasky 	MLX5_SET(modify_rq_in, in, rqn, rq->base.mqp.qpn);
25568e6e287fSHans Petter Selasky 	MLX5_SET(modify_rq_in, in, rq_state, rq->state);
2557b633e08cSHans Petter Selasky 	MLX5_SET(modify_rq_in, in, uid, to_mpd(pd)->uid);
25588e6e287fSHans Petter Selasky 
25598e6e287fSHans Petter Selasky 	rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
25608e6e287fSHans Petter Selasky 	MLX5_SET(rqc, rqc, state, new_state);
25618e6e287fSHans Petter Selasky 
25628e6e287fSHans Petter Selasky 	if (raw_qp_param->set_mask & MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID) {
25638e6e287fSHans Petter Selasky 		if (MLX5_CAP_GEN(dev->mdev, modify_rq_counters_set_id)) {
25648e6e287fSHans Petter Selasky 			MLX5_SET64(modify_rq_in, in, modify_bitmask,
25658e6e287fSHans Petter Selasky 				   MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_MODIFY_RQ_COUNTER_SET_ID);
25668e6e287fSHans Petter Selasky 			MLX5_SET(rqc, rqc, counter_set_id, raw_qp_param->rq_q_ctr_id);
25678e6e287fSHans Petter Selasky 		} else
25688e6e287fSHans Petter Selasky 			pr_info_once("%s: RAW PACKET QP counters are not supported on current FW\n",
25698e6e287fSHans Petter Selasky 				     dev->ib_dev.name);
25708e6e287fSHans Petter Selasky 	}
25718e6e287fSHans Petter Selasky 
25728e6e287fSHans Petter Selasky 	err = mlx5_core_modify_rq(dev->mdev, in, inlen);
25738e6e287fSHans Petter Selasky 	if (err)
25748e6e287fSHans Petter Selasky 		goto out;
25758e6e287fSHans Petter Selasky 
25768e6e287fSHans Petter Selasky 	rq->state = new_state;
25778e6e287fSHans Petter Selasky 
25788e6e287fSHans Petter Selasky out:
25798e6e287fSHans Petter Selasky 	kvfree(in);
25808e6e287fSHans Petter Selasky 	return err;
25818e6e287fSHans Petter Selasky }
25828e6e287fSHans Petter Selasky 
modify_raw_packet_qp_sq(struct mlx5_core_dev * dev,struct mlx5_ib_sq * sq,int new_state,struct ib_pd * pd)25838e6e287fSHans Petter Selasky static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev,
2584b633e08cSHans Petter Selasky 				   struct mlx5_ib_sq *sq, int new_state,
2585b633e08cSHans Petter Selasky 				   struct ib_pd *pd)
25868e6e287fSHans Petter Selasky {
25878e6e287fSHans Petter Selasky 	void *in;
25888e6e287fSHans Petter Selasky 	void *sqc;
25898e6e287fSHans Petter Selasky 	int inlen;
25908e6e287fSHans Petter Selasky 	int err;
25918e6e287fSHans Petter Selasky 
25928e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(modify_sq_in);
25938e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
25948e6e287fSHans Petter Selasky 	if (!in)
25958e6e287fSHans Petter Selasky 		return -ENOMEM;
25968e6e287fSHans Petter Selasky 
25978e6e287fSHans Petter Selasky 	MLX5_SET(modify_sq_in, in, sqn, sq->base.mqp.qpn);
2598b633e08cSHans Petter Selasky 	MLX5_SET(modify_sq_in, in, uid, to_mpd(pd)->uid);
25998e6e287fSHans Petter Selasky 	MLX5_SET(modify_sq_in, in, sq_state, sq->state);
26008e6e287fSHans Petter Selasky 
26018e6e287fSHans Petter Selasky 	sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
26028e6e287fSHans Petter Selasky 	MLX5_SET(sqc, sqc, state, new_state);
26038e6e287fSHans Petter Selasky 
26048e6e287fSHans Petter Selasky 	err = mlx5_core_modify_sq(dev, in, inlen);
26058e6e287fSHans Petter Selasky 	if (err)
26068e6e287fSHans Petter Selasky 		goto out;
26078e6e287fSHans Petter Selasky 
26088e6e287fSHans Petter Selasky 	sq->state = new_state;
26098e6e287fSHans Petter Selasky 
26108e6e287fSHans Petter Selasky out:
26118e6e287fSHans Petter Selasky 	kvfree(in);
26128e6e287fSHans Petter Selasky 	return err;
26138e6e287fSHans Petter Selasky }
26148e6e287fSHans Petter Selasky 
modify_raw_packet_qp(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,const struct mlx5_modify_raw_qp_param * raw_qp_param,u8 tx_affinity)26158e6e287fSHans Petter Selasky static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
26168e6e287fSHans Petter Selasky 				const struct mlx5_modify_raw_qp_param *raw_qp_param,
26178e6e287fSHans Petter Selasky 				u8 tx_affinity)
26188e6e287fSHans Petter Selasky {
26198e6e287fSHans Petter Selasky 	struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
26208e6e287fSHans Petter Selasky 	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
26218e6e287fSHans Petter Selasky 	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
2622b633e08cSHans Petter Selasky 	int modify_rq = !!qp->rq.wqe_cnt;
2623b633e08cSHans Petter Selasky 	int modify_sq = !!qp->sq.wqe_cnt;
26248e6e287fSHans Petter Selasky 	int rq_state;
26258e6e287fSHans Petter Selasky 	int sq_state;
26268e6e287fSHans Petter Selasky 	int err;
26278e6e287fSHans Petter Selasky 
26288e6e287fSHans Petter Selasky 	switch (raw_qp_param->operation) {
26298e6e287fSHans Petter Selasky 	case MLX5_CMD_OP_RST2INIT_QP:
26308e6e287fSHans Petter Selasky 		rq_state = MLX5_RQC_STATE_RDY;
26318e6e287fSHans Petter Selasky 		sq_state = MLX5_SQC_STATE_RDY;
26328e6e287fSHans Petter Selasky 		break;
26338e6e287fSHans Petter Selasky 	case MLX5_CMD_OP_2ERR_QP:
26348e6e287fSHans Petter Selasky 		rq_state = MLX5_RQC_STATE_ERR;
26358e6e287fSHans Petter Selasky 		sq_state = MLX5_SQC_STATE_ERR;
26368e6e287fSHans Petter Selasky 		break;
26378e6e287fSHans Petter Selasky 	case MLX5_CMD_OP_2RST_QP:
26388e6e287fSHans Petter Selasky 		rq_state = MLX5_RQC_STATE_RST;
26398e6e287fSHans Petter Selasky 		sq_state = MLX5_SQC_STATE_RST;
26408e6e287fSHans Petter Selasky 		break;
26418e6e287fSHans Petter Selasky 	case MLX5_CMD_OP_RTR2RTS_QP:
26428e6e287fSHans Petter Selasky 	case MLX5_CMD_OP_RTS2RTS_QP:
2643b633e08cSHans Petter Selasky 		return raw_qp_param->set_mask ? -EINVAL : 0;
2644b633e08cSHans Petter Selasky 	case MLX5_CMD_OP_INIT2INIT_QP:
2645b633e08cSHans Petter Selasky 	case MLX5_CMD_OP_INIT2RTR_QP:
26468e6e287fSHans Petter Selasky 		if (raw_qp_param->set_mask)
26478e6e287fSHans Petter Selasky 			return -EINVAL;
26488e6e287fSHans Petter Selasky 		else
26498e6e287fSHans Petter Selasky 			return 0;
26508e6e287fSHans Petter Selasky 	default:
26518e6e287fSHans Petter Selasky 		WARN_ON(1);
26528e6e287fSHans Petter Selasky 		return -EINVAL;
26538e6e287fSHans Petter Selasky 	}
26548e6e287fSHans Petter Selasky 
2655b633e08cSHans Petter Selasky 	if (modify_rq) {
2656b633e08cSHans Petter Selasky 		err =  modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param,
2657b633e08cSHans Petter Selasky 					       qp->ibqp.pd);
26588e6e287fSHans Petter Selasky 		if (err)
26598e6e287fSHans Petter Selasky 			return err;
26608e6e287fSHans Petter Selasky 	}
26618e6e287fSHans Petter Selasky 
2662b633e08cSHans Petter Selasky 	if (modify_sq) {
26638e6e287fSHans Petter Selasky 		if (tx_affinity) {
26648e6e287fSHans Petter Selasky 			err = modify_raw_packet_tx_affinity(dev->mdev, sq,
2665b633e08cSHans Petter Selasky 							    tx_affinity,
2666b633e08cSHans Petter Selasky 							    qp->ibqp.pd);
26678e6e287fSHans Petter Selasky 			if (err)
26688e6e287fSHans Petter Selasky 				return err;
26698e6e287fSHans Petter Selasky 		}
26708e6e287fSHans Petter Selasky 
2671b633e08cSHans Petter Selasky 		return modify_raw_packet_qp_sq(dev->mdev, sq, sq_state, qp->ibqp.pd);
26728e6e287fSHans Petter Selasky 	}
26738e6e287fSHans Petter Selasky 
26748e6e287fSHans Petter Selasky 	return 0;
26758e6e287fSHans Petter Selasky }
26768e6e287fSHans Petter Selasky 
__mlx5_ib_modify_qp(struct ib_qp * ibqp,const struct ib_qp_attr * attr,int attr_mask,enum ib_qp_state cur_state,enum ib_qp_state new_state)267712515907SHans Petter Selasky static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
267812515907SHans Petter Selasky 			       const struct ib_qp_attr *attr, int attr_mask,
267912515907SHans Petter Selasky 			       enum ib_qp_state cur_state, enum ib_qp_state new_state)
268012515907SHans Petter Selasky {
268112515907SHans Petter Selasky 	static const u16 optab[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE] = {
268212515907SHans Petter Selasky 		[MLX5_QP_STATE_RST] = {
268312515907SHans Petter Selasky 			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
268412515907SHans Petter Selasky 			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
268512515907SHans Petter Selasky 			[MLX5_QP_STATE_INIT]	= MLX5_CMD_OP_RST2INIT_QP,
268612515907SHans Petter Selasky 		},
268712515907SHans Petter Selasky 		[MLX5_QP_STATE_INIT]  = {
268812515907SHans Petter Selasky 			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
268912515907SHans Petter Selasky 			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
269012515907SHans Petter Selasky 			[MLX5_QP_STATE_INIT]	= MLX5_CMD_OP_INIT2INIT_QP,
269112515907SHans Petter Selasky 			[MLX5_QP_STATE_RTR]	= MLX5_CMD_OP_INIT2RTR_QP,
269212515907SHans Petter Selasky 		},
269312515907SHans Petter Selasky 		[MLX5_QP_STATE_RTR]   = {
269412515907SHans Petter Selasky 			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
269512515907SHans Petter Selasky 			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
269612515907SHans Petter Selasky 			[MLX5_QP_STATE_RTS]	= MLX5_CMD_OP_RTR2RTS_QP,
269712515907SHans Petter Selasky 		},
269812515907SHans Petter Selasky 		[MLX5_QP_STATE_RTS]   = {
269912515907SHans Petter Selasky 			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
270012515907SHans Petter Selasky 			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
270112515907SHans Petter Selasky 			[MLX5_QP_STATE_RTS]	= MLX5_CMD_OP_RTS2RTS_QP,
270212515907SHans Petter Selasky 		},
270312515907SHans Petter Selasky 		[MLX5_QP_STATE_SQD] = {
270412515907SHans Petter Selasky 			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
270512515907SHans Petter Selasky 			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
270612515907SHans Petter Selasky 		},
270712515907SHans Petter Selasky 		[MLX5_QP_STATE_SQER] = {
270812515907SHans Petter Selasky 			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
270912515907SHans Petter Selasky 			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
271012515907SHans Petter Selasky 			[MLX5_QP_STATE_RTS]	= MLX5_CMD_OP_SQERR2RTS_QP,
271112515907SHans Petter Selasky 		},
271212515907SHans Petter Selasky 		[MLX5_QP_STATE_ERR] = {
271312515907SHans Petter Selasky 			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
271412515907SHans Petter Selasky 			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
271512515907SHans Petter Selasky 		}
271612515907SHans Petter Selasky 	};
271712515907SHans Petter Selasky 
271812515907SHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
271912515907SHans Petter Selasky 	struct mlx5_ib_qp *qp = to_mqp(ibqp);
27208e6e287fSHans Petter Selasky 	struct mlx5_ib_qp_base *base = &qp->trans_qp.base;
272112515907SHans Petter Selasky 	struct mlx5_ib_cq *send_cq, *recv_cq;
272212515907SHans Petter Selasky 	struct mlx5_qp_context *context;
272312515907SHans Petter Selasky 	struct mlx5_ib_pd *pd;
27248e6e287fSHans Petter Selasky 	struct mlx5_ib_port *mibport = NULL;
272512515907SHans Petter Selasky 	enum mlx5_qp_state mlx5_cur, mlx5_new;
272612515907SHans Petter Selasky 	enum mlx5_qp_optpar optpar;
272712515907SHans Petter Selasky 	int mlx5_st;
272812515907SHans Petter Selasky 	int err;
272912515907SHans Petter Selasky 	u16 op;
273012515907SHans Petter Selasky 
2731788333d9SHans Petter Selasky 	context = kzalloc(sizeof(*context), GFP_KERNEL);
2732788333d9SHans Petter Selasky 	if (!context)
273312515907SHans Petter Selasky 		return -ENOMEM;
273412515907SHans Petter Selasky 
273512515907SHans Petter Selasky 	err = to_mlx5_st(ibqp->qp_type);
27368e6e287fSHans Petter Selasky 	if (err < 0) {
27378e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "unsupported qp type %d\n", ibqp->qp_type);
273812515907SHans Petter Selasky 		goto out;
27398e6e287fSHans Petter Selasky 	}
274012515907SHans Petter Selasky 
274112515907SHans Petter Selasky 	context->flags = cpu_to_be32(err << 16);
274212515907SHans Petter Selasky 
274312515907SHans Petter Selasky 	if (!(attr_mask & IB_QP_PATH_MIG_STATE)) {
274412515907SHans Petter Selasky 		context->flags |= cpu_to_be32(MLX5_QP_PM_MIGRATED << 11);
274512515907SHans Petter Selasky 	} else {
274612515907SHans Petter Selasky 		switch (attr->path_mig_state) {
274712515907SHans Petter Selasky 		case IB_MIG_MIGRATED:
274812515907SHans Petter Selasky 			context->flags |= cpu_to_be32(MLX5_QP_PM_MIGRATED << 11);
274912515907SHans Petter Selasky 			break;
275012515907SHans Petter Selasky 		case IB_MIG_REARM:
275112515907SHans Petter Selasky 			context->flags |= cpu_to_be32(MLX5_QP_PM_REARM << 11);
275212515907SHans Petter Selasky 			break;
275312515907SHans Petter Selasky 		case IB_MIG_ARMED:
275412515907SHans Petter Selasky 			context->flags |= cpu_to_be32(MLX5_QP_PM_ARMED << 11);
275512515907SHans Petter Selasky 			break;
275612515907SHans Petter Selasky 		}
275712515907SHans Petter Selasky 	}
275812515907SHans Petter Selasky 
27598e6e287fSHans Petter Selasky 	if (is_sqp(ibqp->qp_type)) {
276012515907SHans Petter Selasky 		context->mtu_msgmax = (IB_MTU_256 << 5) | 8;
27618e6e287fSHans Petter Selasky 	} else if (ibqp->qp_type == IB_QPT_UD ||
27628e6e287fSHans Petter Selasky 		   ibqp->qp_type == MLX5_IB_QPT_REG_UMR) {
276312515907SHans Petter Selasky 		context->mtu_msgmax = (IB_MTU_4096 << 5) | 12;
276412515907SHans Petter Selasky 	} else if (attr_mask & IB_QP_PATH_MTU) {
276512515907SHans Petter Selasky 		if (attr->path_mtu < IB_MTU_256 ||
276612515907SHans Petter Selasky 		    attr->path_mtu > IB_MTU_4096) {
276712515907SHans Petter Selasky 			mlx5_ib_warn(dev, "invalid mtu %d\n", attr->path_mtu);
276812515907SHans Petter Selasky 			err = -EINVAL;
276912515907SHans Petter Selasky 			goto out;
277012515907SHans Petter Selasky 		}
277112515907SHans Petter Selasky 		context->mtu_msgmax = (attr->path_mtu << 5) |
277212515907SHans Petter Selasky 				      (u8)MLX5_CAP_GEN(dev->mdev, log_max_msg);
277312515907SHans Petter Selasky 	}
277412515907SHans Petter Selasky 
277512515907SHans Petter Selasky 	if (attr_mask & IB_QP_DEST_QPN)
277612515907SHans Petter Selasky 		context->log_pg_sz_remote_qpn = cpu_to_be32(attr->dest_qp_num);
277712515907SHans Petter Selasky 
277812515907SHans Petter Selasky 	if (attr_mask & IB_QP_PKEY_INDEX)
277912515907SHans Petter Selasky 		context->pri_path.pkey_index = cpu_to_be16(attr->pkey_index);
278012515907SHans Petter Selasky 
278112515907SHans Petter Selasky 	/* todo implement counter_index functionality */
278212515907SHans Petter Selasky 
278312515907SHans Petter Selasky 	if (is_sqp(ibqp->qp_type))
278412515907SHans Petter Selasky 		context->pri_path.port = qp->port;
278512515907SHans Petter Selasky 
278612515907SHans Petter Selasky 	if (attr_mask & IB_QP_PORT)
278712515907SHans Petter Selasky 		context->pri_path.port = attr->port_num;
278812515907SHans Petter Selasky 
278912515907SHans Petter Selasky 	if (attr_mask & IB_QP_AV) {
27908e6e287fSHans Petter Selasky 		err = mlx5_set_path(dev, qp, &attr->ah_attr, &context->pri_path,
279112515907SHans Petter Selasky 				    attr_mask & IB_QP_PORT ? attr->port_num : qp->port,
27928e6e287fSHans Petter Selasky 				    attr_mask, 0, attr, false);
279312515907SHans Petter Selasky 		if (err)
279412515907SHans Petter Selasky 			goto out;
279512515907SHans Petter Selasky 	}
279612515907SHans Petter Selasky 
279712515907SHans Petter Selasky 	if (attr_mask & IB_QP_TIMEOUT)
279812515907SHans Petter Selasky 		context->pri_path.ackto_lt |= attr->timeout << 3;
279912515907SHans Petter Selasky 
280012515907SHans Petter Selasky 	if (attr_mask & IB_QP_ALT_PATH) {
28018e6e287fSHans Petter Selasky 		err = mlx5_set_path(dev, qp, &attr->alt_ah_attr,
28028e6e287fSHans Petter Selasky 				    &context->alt_path,
280312515907SHans Petter Selasky 				    attr->alt_port_num,
280412515907SHans Petter Selasky 				    attr_mask | IB_QP_PKEY_INDEX | IB_QP_TIMEOUT,
28058e6e287fSHans Petter Selasky 				    0, attr, true);
280612515907SHans Petter Selasky 		if (err)
280712515907SHans Petter Selasky 			goto out;
280812515907SHans Petter Selasky 	}
280912515907SHans Petter Selasky 
281012515907SHans Petter Selasky 	pd = get_pd(qp);
281112515907SHans Petter Selasky 	get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq,
281212515907SHans Petter Selasky 		&send_cq, &recv_cq);
281312515907SHans Petter Selasky 
281412515907SHans Petter Selasky 	context->flags_pd = cpu_to_be32(pd ? pd->pdn : to_mpd(dev->devr.p0)->pdn);
281512515907SHans Petter Selasky 	context->cqn_send = send_cq ? cpu_to_be32(send_cq->mcq.cqn) : 0;
281612515907SHans Petter Selasky 	context->cqn_recv = recv_cq ? cpu_to_be32(recv_cq->mcq.cqn) : 0;
281712515907SHans Petter Selasky 	context->params1  = cpu_to_be32(MLX5_IB_ACK_REQ_FREQ << 28);
281812515907SHans Petter Selasky 
281912515907SHans Petter Selasky 	if (attr_mask & IB_QP_RNR_RETRY)
282012515907SHans Petter Selasky 		context->params1 |= cpu_to_be32(attr->rnr_retry << 13);
282112515907SHans Petter Selasky 
282212515907SHans Petter Selasky 	if (attr_mask & IB_QP_RETRY_CNT)
282312515907SHans Petter Selasky 		context->params1 |= cpu_to_be32(attr->retry_cnt << 16);
282412515907SHans Petter Selasky 
282512515907SHans Petter Selasky 	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
282612515907SHans Petter Selasky 		if (attr->max_rd_atomic)
282712515907SHans Petter Selasky 			context->params1 |=
282812515907SHans Petter Selasky 				cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21);
282912515907SHans Petter Selasky 	}
283012515907SHans Petter Selasky 
283112515907SHans Petter Selasky 	if (attr_mask & IB_QP_SQ_PSN)
28328e6e287fSHans Petter Selasky 		context->next_send_psn = cpu_to_be32(attr->sq_psn);
283312515907SHans Petter Selasky 
283412515907SHans Petter Selasky 	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
283512515907SHans Petter Selasky 		if (attr->max_dest_rd_atomic)
283612515907SHans Petter Selasky 			context->params2 |=
283712515907SHans Petter Selasky 				cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21);
283812515907SHans Petter Selasky 	}
283912515907SHans Petter Selasky 
2840cf88b86eSHans Petter Selasky 	if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) {
2841cf88b86eSHans Petter Selasky 		__be32 access_flags;
2842cf88b86eSHans Petter Selasky 
2843cf88b86eSHans Petter Selasky 		err = to_mlx5_access_flags(qp, attr, attr_mask, &access_flags);
2844cf88b86eSHans Petter Selasky 		if (err)
2845cf88b86eSHans Petter Selasky 			goto out;
2846cf88b86eSHans Petter Selasky 
2847cf88b86eSHans Petter Selasky 		context->params2 |= access_flags;
2848cf88b86eSHans Petter Selasky 	}
284912515907SHans Petter Selasky 
285012515907SHans Petter Selasky 	if (attr_mask & IB_QP_MIN_RNR_TIMER)
285112515907SHans Petter Selasky 		context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24);
285212515907SHans Petter Selasky 
285312515907SHans Petter Selasky 	if (attr_mask & IB_QP_RQ_PSN)
28548e6e287fSHans Petter Selasky 		context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn);
285512515907SHans Petter Selasky 
285612515907SHans Petter Selasky 	if (attr_mask & IB_QP_QKEY)
285712515907SHans Petter Selasky 		context->qkey = cpu_to_be32(attr->qkey);
285812515907SHans Petter Selasky 
285912515907SHans Petter Selasky 	if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
286012515907SHans Petter Selasky 		context->db_rec_addr = cpu_to_be64(qp->db.dma);
286112515907SHans Petter Selasky 
286212515907SHans Petter Selasky 	if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
286312515907SHans Petter Selasky 		u8 port_num = (attr_mask & IB_QP_PORT ? attr->port_num :
286412515907SHans Petter Selasky 			       qp->port) - 1;
28658e6e287fSHans Petter Selasky 		mibport = &dev->port[port_num];
286612515907SHans Petter Selasky 		context->qp_counter_set_usr_page |=
28678e6e287fSHans Petter Selasky 			cpu_to_be32((u32)(mibport->q_cnt_id) << 24);
286812515907SHans Petter Selasky 	}
286912515907SHans Petter Selasky 
28708e6e287fSHans Petter Selasky 	if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
28718e6e287fSHans Petter Selasky 		context->sq_crq_size |= cpu_to_be16(1 << 4);
28728e6e287fSHans Petter Selasky 
28738e6e287fSHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_SQPN_QP1)
28748e6e287fSHans Petter Selasky 		context->deth_sqpn = cpu_to_be32(1);
28758e6e287fSHans Petter Selasky 
287612515907SHans Petter Selasky 	mlx5_cur = to_mlx5_state(cur_state);
287712515907SHans Petter Selasky 	mlx5_new = to_mlx5_state(new_state);
287812515907SHans Petter Selasky 	mlx5_st = to_mlx5_st(ibqp->qp_type);
287912515907SHans Petter Selasky 	if (mlx5_st < 0)
288012515907SHans Petter Selasky 		goto out;
288112515907SHans Petter Selasky 
28828e6e287fSHans Petter Selasky 	/* If moving to a reset or error state, we must disable page faults on
28838e6e287fSHans Petter Selasky 	 * this QP and flush all current page faults. Otherwise a stale page
28848e6e287fSHans Petter Selasky 	 * fault may attempt to work on this QP after it is reset and moved
28858e6e287fSHans Petter Selasky 	 * again to RTS, and may cause the driver and the device to get out of
28868e6e287fSHans Petter Selasky 	 * sync. */
28878e6e287fSHans Petter Selasky 	if (cur_state != IB_QPS_RESET && cur_state != IB_QPS_ERR &&
28888e6e287fSHans Petter Selasky 	    (new_state == IB_QPS_RESET || new_state == IB_QPS_ERR) &&
28898e6e287fSHans Petter Selasky 	    (qp->ibqp.qp_type != IB_QPT_RAW_PACKET))
28908e6e287fSHans Petter Selasky 		mlx5_ib_qp_disable_pagefaults(qp);
28918e6e287fSHans Petter Selasky 
289212515907SHans Petter Selasky 	if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE ||
289312515907SHans Petter Selasky 	    !optab[mlx5_cur][mlx5_new])
28948e6e287fSHans Petter Selasky 		goto out;
289512515907SHans Petter Selasky 
289612515907SHans Petter Selasky 	op = optab[mlx5_cur][mlx5_new];
289712515907SHans Petter Selasky 	optpar = ib_mask_to_mlx5_opt(attr_mask);
289812515907SHans Petter Selasky 	optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st];
289912515907SHans Petter Selasky 
29008e6e287fSHans Petter Selasky 	if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) {
29018e6e287fSHans Petter Selasky 		struct mlx5_modify_raw_qp_param raw_qp_param = {};
29028e6e287fSHans Petter Selasky 
29038e6e287fSHans Petter Selasky 		raw_qp_param.operation = op;
29048e6e287fSHans Petter Selasky 		if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
29058e6e287fSHans Petter Selasky 			raw_qp_param.rq_q_ctr_id = mibport->q_cnt_id;
29068e6e287fSHans Petter Selasky 			raw_qp_param.set_mask |= MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID;
29078e6e287fSHans Petter Selasky 		}
29088e6e287fSHans Petter Selasky 		err = modify_raw_packet_qp(dev, qp, &raw_qp_param, 0);
29098e6e287fSHans Petter Selasky 	} else {
2910788333d9SHans Petter Selasky 		err = mlx5_core_qp_modify(dev->mdev, op, optpar, context,
2911788333d9SHans Petter Selasky 					  &base->mqp);
29128e6e287fSHans Petter Selasky 	}
29138e6e287fSHans Petter Selasky 
291412515907SHans Petter Selasky 	if (err)
291512515907SHans Petter Selasky 		goto out;
291612515907SHans Petter Selasky 
29178e6e287fSHans Petter Selasky 	if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT &&
29188e6e287fSHans Petter Selasky 	    (qp->ibqp.qp_type != IB_QPT_RAW_PACKET))
29198e6e287fSHans Petter Selasky 		mlx5_ib_qp_enable_pagefaults(qp);
29208e6e287fSHans Petter Selasky 
292112515907SHans Petter Selasky 	qp->state = new_state;
292212515907SHans Petter Selasky 
292312515907SHans Petter Selasky 	if (attr_mask & IB_QP_ACCESS_FLAGS)
29248e6e287fSHans Petter Selasky 		qp->trans_qp.atomic_rd_en = attr->qp_access_flags;
292512515907SHans Petter Selasky 	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
29268e6e287fSHans Petter Selasky 		qp->trans_qp.resp_depth = attr->max_dest_rd_atomic;
292712515907SHans Petter Selasky 	if (attr_mask & IB_QP_PORT)
292812515907SHans Petter Selasky 		qp->port = attr->port_num;
292912515907SHans Petter Selasky 	if (attr_mask & IB_QP_ALT_PATH)
29308e6e287fSHans Petter Selasky 		qp->trans_qp.alt_port = attr->alt_port_num;
293112515907SHans Petter Selasky 
293212515907SHans Petter Selasky 	/*
293312515907SHans Petter Selasky 	 * If we moved a kernel QP to RESET, clean up all old CQ
293412515907SHans Petter Selasky 	 * entries and reinitialize the QP.
293512515907SHans Petter Selasky 	 */
293612515907SHans Petter Selasky 	if (new_state == IB_QPS_RESET && !ibqp->uobject) {
29378e6e287fSHans Petter Selasky 		mlx5_ib_cq_clean(recv_cq, base->mqp.qpn,
293812515907SHans Petter Selasky 				 ibqp->srq ? to_msrq(ibqp->srq) : NULL);
293912515907SHans Petter Selasky 		if (send_cq != recv_cq)
29408e6e287fSHans Petter Selasky 			mlx5_ib_cq_clean(send_cq, base->mqp.qpn, NULL);
294112515907SHans Petter Selasky 
294212515907SHans Petter Selasky 		qp->rq.head = 0;
294312515907SHans Petter Selasky 		qp->rq.tail = 0;
294412515907SHans Petter Selasky 		qp->sq.head = 0;
294512515907SHans Petter Selasky 		qp->sq.tail = 0;
294612515907SHans Petter Selasky 		qp->sq.cur_post = 0;
294712515907SHans Petter Selasky 		qp->sq.last_poll = 0;
294812515907SHans Petter Selasky 		qp->db.db[MLX5_RCV_DBR] = 0;
294912515907SHans Petter Selasky 		qp->db.db[MLX5_SND_DBR] = 0;
295012515907SHans Petter Selasky 	}
295112515907SHans Petter Selasky 
295212515907SHans Petter Selasky out:
2953788333d9SHans Petter Selasky 	kfree(context);
295412515907SHans Petter Selasky 	return err;
295512515907SHans Petter Selasky }
295612515907SHans Petter Selasky 
mlx5_ib_modify_qp(struct ib_qp * ibqp,struct ib_qp_attr * attr,int attr_mask,struct ib_udata * udata)295712515907SHans Petter Selasky int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
295812515907SHans Petter Selasky 		      int attr_mask, struct ib_udata *udata)
295912515907SHans Petter Selasky {
296012515907SHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
296112515907SHans Petter Selasky 	struct mlx5_ib_qp *qp = to_mqp(ibqp);
29628e6e287fSHans Petter Selasky 	enum ib_qp_type qp_type;
296312515907SHans Petter Selasky 	enum ib_qp_state cur_state, new_state;
296412515907SHans Petter Selasky 	int err = -EINVAL;
296512515907SHans Petter Selasky 	int port;
296612515907SHans Petter Selasky 
29678e6e287fSHans Petter Selasky 	if (ibqp->rwq_ind_tbl)
29688e6e287fSHans Petter Selasky 		return -ENOSYS;
29698e6e287fSHans Petter Selasky 
29708e6e287fSHans Petter Selasky 	if (unlikely(ibqp->qp_type == IB_QPT_GSI))
29718e6e287fSHans Petter Selasky 		return mlx5_ib_gsi_modify_qp(ibqp, attr, attr_mask);
29728e6e287fSHans Petter Selasky 
29738e6e287fSHans Petter Selasky 	qp_type = (unlikely(ibqp->qp_type == MLX5_IB_QPT_HW_GSI)) ?
29748e6e287fSHans Petter Selasky 		IB_QPT_GSI : ibqp->qp_type;
29758e6e287fSHans Petter Selasky 
297612515907SHans Petter Selasky 	mutex_lock(&qp->mutex);
297712515907SHans Petter Selasky 
297812515907SHans Petter Selasky 	cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
297912515907SHans Petter Selasky 	new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
298012515907SHans Petter Selasky 
29818e6e287fSHans Petter Selasky 	if (qp_type != MLX5_IB_QPT_REG_UMR &&
2982d92a9e56SHans Petter Selasky 	    !ib_modify_qp_is_ok(cur_state, new_state, qp_type, attr_mask)) {
29838e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid QP state transition from %d to %d, qp_type %d, attr_mask 0x%x\n",
29848e6e287fSHans Petter Selasky 			    cur_state, new_state, ibqp->qp_type, attr_mask);
298512515907SHans Petter Selasky 		goto out;
29868e6e287fSHans Petter Selasky 	}
298712515907SHans Petter Selasky 
298812515907SHans Petter Selasky 	if ((attr_mask & IB_QP_PORT) &&
298912515907SHans Petter Selasky 	    (attr->port_num == 0 ||
29908e6e287fSHans Petter Selasky 	     attr->port_num > MLX5_CAP_GEN(dev->mdev, num_ports))) {
29918e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid port number %d. number of ports is %d\n",
29928e6e287fSHans Petter Selasky 			    attr->port_num, dev->num_ports);
299312515907SHans Petter Selasky 		goto out;
29948e6e287fSHans Petter Selasky 	}
299512515907SHans Petter Selasky 
299612515907SHans Petter Selasky 	if (attr_mask & IB_QP_PKEY_INDEX) {
299712515907SHans Petter Selasky 		port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
299812515907SHans Petter Selasky 		if (attr->pkey_index >=
29998e6e287fSHans Petter Selasky 		    dev->mdev->port_caps[port - 1].pkey_table_len) {
30008e6e287fSHans Petter Selasky 			mlx5_ib_dbg(dev, "invalid pkey index %d\n",
30018e6e287fSHans Petter Selasky 				    attr->pkey_index);
300212515907SHans Petter Selasky 			goto out;
300312515907SHans Petter Selasky 		}
30048e6e287fSHans Petter Selasky 	}
300512515907SHans Petter Selasky 
300612515907SHans Petter Selasky 	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
300712515907SHans Petter Selasky 	    attr->max_rd_atomic >
30088e6e287fSHans Petter Selasky 	    (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_res_qp))) {
30098e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n",
30108e6e287fSHans Petter Selasky 			    attr->max_rd_atomic);
301112515907SHans Petter Selasky 		goto out;
30128e6e287fSHans Petter Selasky 	}
301312515907SHans Petter Selasky 
301412515907SHans Petter Selasky 	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
301512515907SHans Petter Selasky 	    attr->max_dest_rd_atomic >
30168e6e287fSHans Petter Selasky 	    (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_req_qp))) {
30178e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n",
30188e6e287fSHans Petter Selasky 			    attr->max_dest_rd_atomic);
301912515907SHans Petter Selasky 		goto out;
30208e6e287fSHans Petter Selasky 	}
302112515907SHans Petter Selasky 
302212515907SHans Petter Selasky 	if (cur_state == new_state && cur_state == IB_QPS_RESET) {
302312515907SHans Petter Selasky 		err = 0;
302412515907SHans Petter Selasky 		goto out;
302512515907SHans Petter Selasky 	}
302612515907SHans Petter Selasky 
302712515907SHans Petter Selasky 	err = __mlx5_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state);
302812515907SHans Petter Selasky 
302912515907SHans Petter Selasky out:
303012515907SHans Petter Selasky 	mutex_unlock(&qp->mutex);
303112515907SHans Petter Selasky 	return err;
303212515907SHans Petter Selasky }
303312515907SHans Petter Selasky 
mlx5_wq_overflow(struct mlx5_ib_wq * wq,int nreq,struct ib_cq * ib_cq)303412515907SHans Petter Selasky static int mlx5_wq_overflow(struct mlx5_ib_wq *wq, int nreq, struct ib_cq *ib_cq)
303512515907SHans Petter Selasky {
303612515907SHans Petter Selasky 	struct mlx5_ib_cq *cq;
303712515907SHans Petter Selasky 	unsigned cur;
303812515907SHans Petter Selasky 
303912515907SHans Petter Selasky 	cur = wq->head - wq->tail;
304012515907SHans Petter Selasky 	if (likely(cur + nreq < wq->max_post))
304112515907SHans Petter Selasky 		return 0;
304212515907SHans Petter Selasky 
304312515907SHans Petter Selasky 	cq = to_mcq(ib_cq);
304412515907SHans Petter Selasky 	spin_lock(&cq->lock);
304512515907SHans Petter Selasky 	cur = wq->head - wq->tail;
304612515907SHans Petter Selasky 	spin_unlock(&cq->lock);
304712515907SHans Petter Selasky 
304812515907SHans Petter Selasky 	return cur + nreq >= wq->max_post;
304912515907SHans Petter Selasky }
305012515907SHans Petter Selasky 
set_raddr_seg(struct mlx5_wqe_raddr_seg * rseg,u64 remote_addr,u32 rkey)305112515907SHans Petter Selasky static __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
305212515907SHans Petter Selasky 					  u64 remote_addr, u32 rkey)
305312515907SHans Petter Selasky {
305412515907SHans Petter Selasky 	rseg->raddr    = cpu_to_be64(remote_addr);
305512515907SHans Petter Selasky 	rseg->rkey     = cpu_to_be32(rkey);
305612515907SHans Petter Selasky 	rseg->reserved = 0;
305712515907SHans Petter Selasky }
305812515907SHans Petter Selasky 
set_eth_seg(struct mlx5_wqe_eth_seg * eseg,const struct ib_send_wr * wr,void * qend,struct mlx5_ib_qp * qp,int * size)30598e6e287fSHans Petter Selasky static void *set_eth_seg(struct mlx5_wqe_eth_seg *eseg,
3060c3987b8eSHans Petter Selasky 			 const struct ib_send_wr *wr, void *qend,
30618e6e287fSHans Petter Selasky 			 struct mlx5_ib_qp *qp, int *size)
30628e6e287fSHans Petter Selasky {
30638e6e287fSHans Petter Selasky 	void *seg = eseg;
30648e6e287fSHans Petter Selasky 
30658e6e287fSHans Petter Selasky 	memset(eseg, 0, sizeof(struct mlx5_wqe_eth_seg));
30668e6e287fSHans Petter Selasky 
30678e6e287fSHans Petter Selasky 	if (wr->send_flags & IB_SEND_IP_CSUM)
30688e6e287fSHans Petter Selasky 		eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM |
30698e6e287fSHans Petter Selasky 				 MLX5_ETH_WQE_L4_CSUM;
30708e6e287fSHans Petter Selasky 
30718e6e287fSHans Petter Selasky 	seg += sizeof(struct mlx5_wqe_eth_seg);
30728e6e287fSHans Petter Selasky 	*size += sizeof(struct mlx5_wqe_eth_seg) / 16;
30738e6e287fSHans Petter Selasky 
30748e6e287fSHans Petter Selasky 	if (wr->opcode == IB_WR_LSO) {
30758e6e287fSHans Petter Selasky 		struct ib_ud_wr *ud_wr = container_of(wr, struct ib_ud_wr, wr);
30768e6e287fSHans Petter Selasky 		int size_of_inl_hdr_start = sizeof(eseg->inline_hdr_start);
30778e6e287fSHans Petter Selasky 		u64 left, leftlen, copysz;
30788e6e287fSHans Petter Selasky 		void *pdata = ud_wr->header;
30798e6e287fSHans Petter Selasky 
30808e6e287fSHans Petter Selasky 		left = ud_wr->hlen;
30818e6e287fSHans Petter Selasky 		eseg->mss = cpu_to_be16(ud_wr->mss);
30828e6e287fSHans Petter Selasky 		eseg->inline_hdr_sz = cpu_to_be16(left);
30838e6e287fSHans Petter Selasky 
30848e6e287fSHans Petter Selasky 		/*
30858e6e287fSHans Petter Selasky 		 * check if there is space till the end of queue, if yes,
30868e6e287fSHans Petter Selasky 		 * copy all in one shot, otherwise copy till the end of queue,
30878e6e287fSHans Petter Selasky 		 * rollback and than the copy the left
30888e6e287fSHans Petter Selasky 		 */
30898e6e287fSHans Petter Selasky 		leftlen = qend - (void *)eseg->inline_hdr_start;
30908e6e287fSHans Petter Selasky 		copysz = min_t(u64, leftlen, left);
30918e6e287fSHans Petter Selasky 
30928e6e287fSHans Petter Selasky 		memcpy(seg - size_of_inl_hdr_start, pdata, copysz);
30938e6e287fSHans Petter Selasky 
30948e6e287fSHans Petter Selasky 		if (likely(copysz > size_of_inl_hdr_start)) {
30958e6e287fSHans Petter Selasky 			seg += ALIGN(copysz - size_of_inl_hdr_start, 16);
30968e6e287fSHans Petter Selasky 			*size += ALIGN(copysz - size_of_inl_hdr_start, 16) / 16;
30978e6e287fSHans Petter Selasky 		}
30988e6e287fSHans Petter Selasky 
30998e6e287fSHans Petter Selasky 		if (unlikely(copysz < left)) { /* the last wqe in the queue */
31008e6e287fSHans Petter Selasky 			seg = mlx5_get_send_wqe(qp, 0);
31018e6e287fSHans Petter Selasky 			left -= copysz;
31028e6e287fSHans Petter Selasky 			pdata += copysz;
31038e6e287fSHans Petter Selasky 			memcpy(seg, pdata, left);
31048e6e287fSHans Petter Selasky 			seg += ALIGN(left, 16);
31058e6e287fSHans Petter Selasky 			*size += ALIGN(left, 16) / 16;
31068e6e287fSHans Petter Selasky 		}
31078e6e287fSHans Petter Selasky 	}
31088e6e287fSHans Petter Selasky 
31098e6e287fSHans Petter Selasky 	return seg;
31108e6e287fSHans Petter Selasky }
31118e6e287fSHans Petter Selasky 
set_datagram_seg(struct mlx5_wqe_datagram_seg * dseg,const struct ib_send_wr * wr)311212515907SHans Petter Selasky static void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
3113c3987b8eSHans Petter Selasky 			     const struct ib_send_wr *wr)
311412515907SHans Petter Selasky {
31158e6e287fSHans Petter Selasky 	memcpy(&dseg->av, &to_mah(ud_wr(wr)->ah)->av, sizeof(struct mlx5_av));
31168e6e287fSHans Petter Selasky 	dseg->av.dqp_dct = cpu_to_be32(ud_wr(wr)->remote_qpn | MLX5_EXTENDED_UD_AV);
31178e6e287fSHans Petter Selasky 	dseg->av.key.qkey.qkey = cpu_to_be32(ud_wr(wr)->remote_qkey);
311812515907SHans Petter Selasky }
311912515907SHans Petter Selasky 
set_data_ptr_seg(struct mlx5_wqe_data_seg * dseg,struct ib_sge * sg)312012515907SHans Petter Selasky static void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ib_sge *sg)
312112515907SHans Petter Selasky {
312212515907SHans Petter Selasky 	dseg->byte_count = cpu_to_be32(sg->length);
312312515907SHans Petter Selasky 	dseg->lkey       = cpu_to_be32(sg->lkey);
312412515907SHans Petter Selasky 	dseg->addr       = cpu_to_be64(sg->addr);
312512515907SHans Petter Selasky }
312612515907SHans Petter Selasky 
get_klm_octo(int npages)312712515907SHans Petter Selasky static __be16 get_klm_octo(int npages)
312812515907SHans Petter Selasky {
312912515907SHans Petter Selasky 	return cpu_to_be16(ALIGN(npages, 8) / 2);
313012515907SHans Petter Selasky }
313112515907SHans Petter Selasky 
frwr_mkey_mask(void)313212515907SHans Petter Selasky static __be64 frwr_mkey_mask(void)
313312515907SHans Petter Selasky {
313412515907SHans Petter Selasky 	u64 result;
313512515907SHans Petter Selasky 
313612515907SHans Petter Selasky 	result = MLX5_MKEY_MASK_LEN		|
313712515907SHans Petter Selasky 		MLX5_MKEY_MASK_PAGE_SIZE	|
313812515907SHans Petter Selasky 		MLX5_MKEY_MASK_START_ADDR	|
313912515907SHans Petter Selasky 		MLX5_MKEY_MASK_EN_RINVAL	|
314012515907SHans Petter Selasky 		MLX5_MKEY_MASK_KEY		|
314112515907SHans Petter Selasky 		MLX5_MKEY_MASK_LR		|
314212515907SHans Petter Selasky 		MLX5_MKEY_MASK_LW		|
314312515907SHans Petter Selasky 		MLX5_MKEY_MASK_RR		|
314412515907SHans Petter Selasky 		MLX5_MKEY_MASK_RW		|
314512515907SHans Petter Selasky 		MLX5_MKEY_MASK_A		|
314612515907SHans Petter Selasky 		MLX5_MKEY_MASK_SMALL_FENCE	|
314712515907SHans Petter Selasky 		MLX5_MKEY_MASK_FREE;
314812515907SHans Petter Selasky 
314912515907SHans Petter Selasky 	return cpu_to_be64(result);
315012515907SHans Petter Selasky }
315112515907SHans Petter Selasky 
sig_mkey_mask(void)31528e6e287fSHans Petter Selasky static __be64 sig_mkey_mask(void)
315312515907SHans Petter Selasky {
31548e6e287fSHans Petter Selasky 	u64 result;
315512515907SHans Petter Selasky 
31568e6e287fSHans Petter Selasky 	result = MLX5_MKEY_MASK_LEN		|
31578e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_PAGE_SIZE	|
31588e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_START_ADDR	|
31598e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_EN_SIGERR	|
31608e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_EN_RINVAL	|
31618e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_KEY		|
31628e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_LR		|
31638e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_LW		|
31648e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_RR		|
31658e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_RW		|
31668e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_SMALL_FENCE	|
31678e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_FREE		|
31688e6e287fSHans Petter Selasky 		MLX5_MKEY_MASK_BSF_EN;
31698e6e287fSHans Petter Selasky 
31708e6e287fSHans Petter Selasky 	return cpu_to_be64(result);
317112515907SHans Petter Selasky }
317212515907SHans Petter Selasky 
set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg * umr,struct mlx5_ib_mr * mr)31738e6e287fSHans Petter Selasky static void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr,
31748e6e287fSHans Petter Selasky 				struct mlx5_ib_mr *mr)
31758e6e287fSHans Petter Selasky {
31768e6e287fSHans Petter Selasky 	int ndescs = mr->ndescs;
31778e6e287fSHans Petter Selasky 
31788e6e287fSHans Petter Selasky 	memset(umr, 0, sizeof(*umr));
31798e6e287fSHans Petter Selasky 
31808e6e287fSHans Petter Selasky 	if (mr->access_mode == MLX5_ACCESS_MODE_KLM)
31818e6e287fSHans Petter Selasky 		/* KLMs take twice the size of MTTs */
31828e6e287fSHans Petter Selasky 		ndescs *= 2;
31838e6e287fSHans Petter Selasky 
31848e6e287fSHans Petter Selasky 	umr->flags = MLX5_UMR_CHECK_NOT_FREE;
31858e6e287fSHans Petter Selasky 	umr->klm_octowords = get_klm_octo(ndescs);
318612515907SHans Petter Selasky 	umr->mkey_mask = frwr_mkey_mask();
318712515907SHans Petter Selasky }
318812515907SHans Petter Selasky 
set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg * umr)31898e6e287fSHans Petter Selasky static void set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr)
31908e6e287fSHans Petter Selasky {
31918e6e287fSHans Petter Selasky 	memset(umr, 0, sizeof(*umr));
31928e6e287fSHans Petter Selasky 	umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
31938e6e287fSHans Petter Selasky 	umr->flags = 1 << 7;
31948e6e287fSHans Petter Selasky }
31958e6e287fSHans Petter Selasky 
get_umr_reg_mr_mask(void)31968e6e287fSHans Petter Selasky static __be64 get_umr_reg_mr_mask(void)
31978e6e287fSHans Petter Selasky {
31988e6e287fSHans Petter Selasky 	u64 result;
31998e6e287fSHans Petter Selasky 
32008e6e287fSHans Petter Selasky 	result = MLX5_MKEY_MASK_LEN		|
32018e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_PAGE_SIZE	|
32028e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_START_ADDR	|
32038e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_PD		|
32048e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_LR		|
32058e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_LW		|
32068e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_KEY		|
32078e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_RR		|
32088e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_RW		|
32098e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_A		|
32108e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_FREE;
32118e6e287fSHans Petter Selasky 
32128e6e287fSHans Petter Selasky 	return cpu_to_be64(result);
32138e6e287fSHans Petter Selasky }
32148e6e287fSHans Petter Selasky 
get_umr_unreg_mr_mask(void)32158e6e287fSHans Petter Selasky static __be64 get_umr_unreg_mr_mask(void)
32168e6e287fSHans Petter Selasky {
32178e6e287fSHans Petter Selasky 	u64 result;
32188e6e287fSHans Petter Selasky 
32198e6e287fSHans Petter Selasky 	result = MLX5_MKEY_MASK_FREE;
32208e6e287fSHans Petter Selasky 
32218e6e287fSHans Petter Selasky 	return cpu_to_be64(result);
32228e6e287fSHans Petter Selasky }
32238e6e287fSHans Petter Selasky 
get_umr_update_mtt_mask(void)32248e6e287fSHans Petter Selasky static __be64 get_umr_update_mtt_mask(void)
32258e6e287fSHans Petter Selasky {
32268e6e287fSHans Petter Selasky 	u64 result;
32278e6e287fSHans Petter Selasky 
32288e6e287fSHans Petter Selasky 	result = MLX5_MKEY_MASK_FREE;
32298e6e287fSHans Petter Selasky 
32308e6e287fSHans Petter Selasky 	return cpu_to_be64(result);
32318e6e287fSHans Petter Selasky }
32328e6e287fSHans Petter Selasky 
get_umr_update_translation_mask(void)32338e6e287fSHans Petter Selasky static __be64 get_umr_update_translation_mask(void)
32348e6e287fSHans Petter Selasky {
32358e6e287fSHans Petter Selasky 	u64 result;
32368e6e287fSHans Petter Selasky 
32378e6e287fSHans Petter Selasky 	result = MLX5_MKEY_MASK_LEN |
32388e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_PAGE_SIZE |
32398e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_START_ADDR |
32408e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_KEY |
32418e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_FREE;
32428e6e287fSHans Petter Selasky 
32438e6e287fSHans Petter Selasky 	return cpu_to_be64(result);
32448e6e287fSHans Petter Selasky }
32458e6e287fSHans Petter Selasky 
get_umr_update_access_mask(void)32468e6e287fSHans Petter Selasky static __be64 get_umr_update_access_mask(void)
32478e6e287fSHans Petter Selasky {
32488e6e287fSHans Petter Selasky 	u64 result;
32498e6e287fSHans Petter Selasky 
32508e6e287fSHans Petter Selasky 	result = MLX5_MKEY_MASK_LW |
32518e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_RR |
32528e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_RW |
32538e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_A |
32548e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_KEY |
32558e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_FREE;
32568e6e287fSHans Petter Selasky 
32578e6e287fSHans Petter Selasky 	return cpu_to_be64(result);
32588e6e287fSHans Petter Selasky }
32598e6e287fSHans Petter Selasky 
get_umr_update_pd_mask(void)32608e6e287fSHans Petter Selasky static __be64 get_umr_update_pd_mask(void)
32618e6e287fSHans Petter Selasky {
32628e6e287fSHans Petter Selasky 	u64 result;
32638e6e287fSHans Petter Selasky 
32648e6e287fSHans Petter Selasky 	result = MLX5_MKEY_MASK_PD |
32658e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_KEY |
32668e6e287fSHans Petter Selasky 		 MLX5_MKEY_MASK_FREE;
32678e6e287fSHans Petter Selasky 
32688e6e287fSHans Petter Selasky 	return cpu_to_be64(result);
32698e6e287fSHans Petter Selasky }
32708e6e287fSHans Petter Selasky 
set_reg_umr_segment(struct mlx5_wqe_umr_ctrl_seg * umr,const struct ib_send_wr * wr)32718e6e287fSHans Petter Selasky static void set_reg_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
3272c3987b8eSHans Petter Selasky 				const struct ib_send_wr *wr)
32738e6e287fSHans Petter Selasky {
3274c3987b8eSHans Petter Selasky 	const struct mlx5_umr_wr *umrwr = umr_wr(wr);
32758e6e287fSHans Petter Selasky 
32768e6e287fSHans Petter Selasky 	memset(umr, 0, sizeof(*umr));
32778e6e287fSHans Petter Selasky 
32788e6e287fSHans Petter Selasky 	if (wr->send_flags & MLX5_IB_SEND_UMR_FAIL_IF_FREE)
32798e6e287fSHans Petter Selasky 		umr->flags = MLX5_UMR_CHECK_FREE; /* fail if free */
32808e6e287fSHans Petter Selasky 	else
32818e6e287fSHans Petter Selasky 		umr->flags = MLX5_UMR_CHECK_NOT_FREE; /* fail if not free */
32828e6e287fSHans Petter Selasky 
32838e6e287fSHans Petter Selasky 	if (!(wr->send_flags & MLX5_IB_SEND_UMR_UNREG)) {
32848e6e287fSHans Petter Selasky 		umr->klm_octowords = get_klm_octo(umrwr->npages);
32858e6e287fSHans Petter Selasky 		if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_MTT) {
32868e6e287fSHans Petter Selasky 			umr->mkey_mask = get_umr_update_mtt_mask();
32878e6e287fSHans Petter Selasky 			umr->bsf_octowords = get_klm_octo(umrwr->target.offset);
32888e6e287fSHans Petter Selasky 			umr->flags |= MLX5_UMR_TRANSLATION_OFFSET_EN;
32898e6e287fSHans Petter Selasky 		}
32908e6e287fSHans Petter Selasky 		if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_TRANSLATION)
32918e6e287fSHans Petter Selasky 			umr->mkey_mask |= get_umr_update_translation_mask();
32928e6e287fSHans Petter Selasky 		if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_ACCESS)
32938e6e287fSHans Petter Selasky 			umr->mkey_mask |= get_umr_update_access_mask();
32948e6e287fSHans Petter Selasky 		if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_PD)
32958e6e287fSHans Petter Selasky 			umr->mkey_mask |= get_umr_update_pd_mask();
32968e6e287fSHans Petter Selasky 		if (!umr->mkey_mask)
32978e6e287fSHans Petter Selasky 			umr->mkey_mask = get_umr_reg_mr_mask();
32988e6e287fSHans Petter Selasky 	} else {
32998e6e287fSHans Petter Selasky 		umr->mkey_mask = get_umr_unreg_mr_mask();
33008e6e287fSHans Petter Selasky 	}
33018e6e287fSHans Petter Selasky 
33028e6e287fSHans Petter Selasky 	if (!wr->num_sge)
33038e6e287fSHans Petter Selasky 		umr->flags |= MLX5_UMR_INLINE;
33048e6e287fSHans Petter Selasky }
33058e6e287fSHans Petter Selasky 
get_umr_flags(int acc)330612515907SHans Petter Selasky static u8 get_umr_flags(int acc)
330712515907SHans Petter Selasky {
330812515907SHans Petter Selasky 	return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC       : 0) |
330912515907SHans Petter Selasky 	       (acc & IB_ACCESS_REMOTE_WRITE  ? MLX5_PERM_REMOTE_WRITE : 0) |
331012515907SHans Petter Selasky 	       (acc & IB_ACCESS_REMOTE_READ   ? MLX5_PERM_REMOTE_READ  : 0) |
331112515907SHans Petter Selasky 	       (acc & IB_ACCESS_LOCAL_WRITE   ? MLX5_PERM_LOCAL_WRITE  : 0) |
331212515907SHans Petter Selasky 		MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN;
331312515907SHans Petter Selasky }
331412515907SHans Petter Selasky 
set_reg_mkey_seg(struct mlx5_mkey_seg * seg,struct mlx5_ib_mr * mr,u32 key,int access)33158e6e287fSHans Petter Selasky static void set_reg_mkey_seg(struct mlx5_mkey_seg *seg,
33168e6e287fSHans Petter Selasky 			     struct mlx5_ib_mr *mr,
33178e6e287fSHans Petter Selasky 			     u32 key, int access)
33188e6e287fSHans Petter Selasky {
33198e6e287fSHans Petter Selasky 	int ndescs = ALIGN(mr->ndescs, 8) >> 1;
33208e6e287fSHans Petter Selasky 
33218e6e287fSHans Petter Selasky 	memset(seg, 0, sizeof(*seg));
33228e6e287fSHans Petter Selasky 
33238e6e287fSHans Petter Selasky 	if (mr->access_mode == MLX5_ACCESS_MODE_MTT)
33248e6e287fSHans Petter Selasky 		seg->log2_page_size = ilog2(mr->ibmr.page_size);
33258e6e287fSHans Petter Selasky 	else if (mr->access_mode == MLX5_ACCESS_MODE_KLM)
33268e6e287fSHans Petter Selasky 		/* KLMs take twice the size of MTTs */
33278e6e287fSHans Petter Selasky 		ndescs *= 2;
33288e6e287fSHans Petter Selasky 
33298e6e287fSHans Petter Selasky 	seg->flags = get_umr_flags(access) | mr->access_mode;
33308e6e287fSHans Petter Selasky 	seg->qpn_mkey7_0 = cpu_to_be32((key & 0xff) | 0xffffff00);
33318e6e287fSHans Petter Selasky 	seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL);
33328e6e287fSHans Petter Selasky 	seg->start_addr = cpu_to_be64(mr->ibmr.iova);
33338e6e287fSHans Petter Selasky 	seg->len = cpu_to_be64(mr->ibmr.length);
33348e6e287fSHans Petter Selasky 	seg->xlt_oct_size = cpu_to_be32(ndescs);
33358e6e287fSHans Petter Selasky }
33368e6e287fSHans Petter Selasky 
set_linv_mkey_seg(struct mlx5_mkey_seg * seg)33378e6e287fSHans Petter Selasky static void set_linv_mkey_seg(struct mlx5_mkey_seg *seg)
333812515907SHans Petter Selasky {
333912515907SHans Petter Selasky 	memset(seg, 0, sizeof(*seg));
33408e6e287fSHans Petter Selasky 	seg->status = MLX5_MKEY_STATUS_FREE;
33418e6e287fSHans Petter Selasky }
33428e6e287fSHans Petter Selasky 
set_reg_mkey_segment(struct mlx5_mkey_seg * seg,const struct ib_send_wr * wr)3343c3987b8eSHans Petter Selasky static void set_reg_mkey_segment(struct mlx5_mkey_seg *seg, const struct ib_send_wr *wr)
33448e6e287fSHans Petter Selasky {
3345c3987b8eSHans Petter Selasky 	const struct mlx5_umr_wr *umrwr = umr_wr(wr);
33468e6e287fSHans Petter Selasky 
33478e6e287fSHans Petter Selasky 	memset(seg, 0, sizeof(*seg));
33488e6e287fSHans Petter Selasky 	if (wr->send_flags & MLX5_IB_SEND_UMR_UNREG) {
334912515907SHans Petter Selasky 		seg->status = MLX5_MKEY_STATUS_FREE;
335012515907SHans Petter Selasky 		return;
335112515907SHans Petter Selasky 	}
335212515907SHans Petter Selasky 
33538e6e287fSHans Petter Selasky 	seg->flags = convert_access(umrwr->access_flags);
33548e6e287fSHans Petter Selasky 	if (!(wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_MTT)) {
33558e6e287fSHans Petter Selasky 		if (umrwr->pd)
33568e6e287fSHans Petter Selasky 			seg->flags_pd = cpu_to_be32(to_mpd(umrwr->pd)->pdn);
33578e6e287fSHans Petter Selasky 		seg->start_addr = cpu_to_be64(umrwr->target.virt_addr);
33588e6e287fSHans Petter Selasky 	}
33598e6e287fSHans Petter Selasky 	seg->len = cpu_to_be64(umrwr->length);
33608e6e287fSHans Petter Selasky 	seg->log2_page_size = umrwr->page_shift;
33618e6e287fSHans Petter Selasky 	seg->qpn_mkey7_0 = cpu_to_be32(0xffffff00 |
33628e6e287fSHans Petter Selasky 				       mlx5_mkey_variant(umrwr->mkey));
336312515907SHans Petter Selasky }
336412515907SHans Petter Selasky 
set_reg_data_seg(struct mlx5_wqe_data_seg * dseg,struct mlx5_ib_mr * mr,struct mlx5_ib_pd * pd)33658e6e287fSHans Petter Selasky static void set_reg_data_seg(struct mlx5_wqe_data_seg *dseg,
33668e6e287fSHans Petter Selasky 			     struct mlx5_ib_mr *mr,
33678e6e287fSHans Petter Selasky 			     struct mlx5_ib_pd *pd)
336812515907SHans Petter Selasky {
33698e6e287fSHans Petter Selasky 	int bcount = mr->desc_size * mr->ndescs;
337012515907SHans Petter Selasky 
33718e6e287fSHans Petter Selasky 	dseg->addr = cpu_to_be64(mr->desc_map);
33728e6e287fSHans Petter Selasky 	dseg->byte_count = cpu_to_be32(ALIGN(bcount, 64));
33738e6e287fSHans Petter Selasky 	dseg->lkey = cpu_to_be32(pd->ibpd.local_dma_lkey);
337412515907SHans Petter Selasky }
337512515907SHans Petter Selasky 
send_ieth(const struct ib_send_wr * wr)3376c3987b8eSHans Petter Selasky static __be32 send_ieth(const struct ib_send_wr *wr)
337712515907SHans Petter Selasky {
337812515907SHans Petter Selasky 	switch (wr->opcode) {
337912515907SHans Petter Selasky 	case IB_WR_SEND_WITH_IMM:
338012515907SHans Petter Selasky 	case IB_WR_RDMA_WRITE_WITH_IMM:
338112515907SHans Petter Selasky 		return wr->ex.imm_data;
338212515907SHans Petter Selasky 
338312515907SHans Petter Selasky 	case IB_WR_SEND_WITH_INV:
338412515907SHans Petter Selasky 		return cpu_to_be32(wr->ex.invalidate_rkey);
338512515907SHans Petter Selasky 
338612515907SHans Petter Selasky 	default:
338712515907SHans Petter Selasky 		return 0;
338812515907SHans Petter Selasky 	}
338912515907SHans Petter Selasky }
339012515907SHans Petter Selasky 
calc_sig(void * wqe,int size)339112515907SHans Petter Selasky static u8 calc_sig(void *wqe, int size)
339212515907SHans Petter Selasky {
339312515907SHans Petter Selasky 	u8 *p = wqe;
339412515907SHans Petter Selasky 	u8 res = 0;
339512515907SHans Petter Selasky 	int i;
339612515907SHans Petter Selasky 
339712515907SHans Petter Selasky 	for (i = 0; i < size; i++)
339812515907SHans Petter Selasky 		res ^= p[i];
339912515907SHans Petter Selasky 
340012515907SHans Petter Selasky 	return ~res;
340112515907SHans Petter Selasky }
340212515907SHans Petter Selasky 
wq_sig(void * wqe)34038e6e287fSHans Petter Selasky static u8 wq_sig(void *wqe)
340412515907SHans Petter Selasky {
340512515907SHans Petter Selasky 	return calc_sig(wqe, (*((u8 *)wqe + 8) & 0x3f) << 4);
340612515907SHans Petter Selasky }
340712515907SHans Petter Selasky 
set_data_inl_seg(struct mlx5_ib_qp * qp,const struct ib_send_wr * wr,void * wqe,int * sz)3408c3987b8eSHans Petter Selasky static int set_data_inl_seg(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr,
340912515907SHans Petter Selasky 			    void *wqe, int *sz)
341012515907SHans Petter Selasky {
341112515907SHans Petter Selasky 	struct mlx5_wqe_inline_seg *seg;
341212515907SHans Petter Selasky 	void *qend = qp->sq.qend;
341312515907SHans Petter Selasky 	void *addr;
341412515907SHans Petter Selasky 	int inl = 0;
341512515907SHans Petter Selasky 	int copy;
341612515907SHans Petter Selasky 	int len;
341712515907SHans Petter Selasky 	int i;
341812515907SHans Petter Selasky 
341912515907SHans Petter Selasky 	seg = wqe;
342012515907SHans Petter Selasky 	wqe += sizeof(*seg);
342112515907SHans Petter Selasky 	for (i = 0; i < wr->num_sge; i++) {
34228e6e287fSHans Petter Selasky 		addr = (void *)(unsigned long)(wr->sg_list[i].addr);
342312515907SHans Petter Selasky 		len  = wr->sg_list[i].length;
342412515907SHans Petter Selasky 		inl += len;
342512515907SHans Petter Selasky 
342612515907SHans Petter Selasky 		if (unlikely(inl > qp->max_inline_data))
342712515907SHans Petter Selasky 			return -ENOMEM;
342812515907SHans Petter Selasky 
342912515907SHans Petter Selasky 		if (unlikely(wqe + len > qend)) {
34308e6e287fSHans Petter Selasky 			copy = qend - wqe;
343112515907SHans Petter Selasky 			memcpy(wqe, addr, copy);
343212515907SHans Petter Selasky 			addr += copy;
343312515907SHans Petter Selasky 			len -= copy;
343412515907SHans Petter Selasky 			wqe = mlx5_get_send_wqe(qp, 0);
343512515907SHans Petter Selasky 		}
343612515907SHans Petter Selasky 		memcpy(wqe, addr, len);
343712515907SHans Petter Selasky 		wqe += len;
343812515907SHans Petter Selasky 	}
343912515907SHans Petter Selasky 
344012515907SHans Petter Selasky 	seg->byte_count = cpu_to_be32(inl | MLX5_INLINE_SEG);
344112515907SHans Petter Selasky 
344212515907SHans Petter Selasky 	*sz = ALIGN(inl + sizeof(seg->byte_count), 16) / 16;
344312515907SHans Petter Selasky 
344412515907SHans Petter Selasky 	return 0;
344512515907SHans Petter Selasky }
344612515907SHans Petter Selasky 
prot_field_size(enum ib_signature_type type)34478e6e287fSHans Petter Selasky static u16 prot_field_size(enum ib_signature_type type)
344812515907SHans Petter Selasky {
34498e6e287fSHans Petter Selasky 	switch (type) {
34508e6e287fSHans Petter Selasky 	case IB_SIG_TYPE_T10_DIF:
34518e6e287fSHans Petter Selasky 		return MLX5_DIF_SIZE;
34528e6e287fSHans Petter Selasky 	default:
34538e6e287fSHans Petter Selasky 		return 0;
34548e6e287fSHans Petter Selasky 	}
34558e6e287fSHans Petter Selasky }
345612515907SHans Petter Selasky 
bs_selector(int block_size)34578e6e287fSHans Petter Selasky static u8 bs_selector(int block_size)
34588e6e287fSHans Petter Selasky {
34598e6e287fSHans Petter Selasky 	switch (block_size) {
34608e6e287fSHans Petter Selasky 	case 512:	    return 0x1;
34618e6e287fSHans Petter Selasky 	case 520:	    return 0x2;
34628e6e287fSHans Petter Selasky 	case 4096:	    return 0x3;
34638e6e287fSHans Petter Selasky 	case 4160:	    return 0x4;
34648e6e287fSHans Petter Selasky 	case 1073741824:    return 0x5;
34658e6e287fSHans Petter Selasky 	default:	    return 0;
34668e6e287fSHans Petter Selasky 	}
34678e6e287fSHans Petter Selasky }
34688e6e287fSHans Petter Selasky 
mlx5_fill_inl_bsf(struct ib_sig_domain * domain,struct mlx5_bsf_inl * inl)34698e6e287fSHans Petter Selasky static void mlx5_fill_inl_bsf(struct ib_sig_domain *domain,
34708e6e287fSHans Petter Selasky 			      struct mlx5_bsf_inl *inl)
34718e6e287fSHans Petter Selasky {
34728e6e287fSHans Petter Selasky 	/* Valid inline section and allow BSF refresh */
34738e6e287fSHans Petter Selasky 	inl->vld_refresh = cpu_to_be16(MLX5_BSF_INL_VALID |
34748e6e287fSHans Petter Selasky 				       MLX5_BSF_REFRESH_DIF);
34758e6e287fSHans Petter Selasky 	inl->dif_apptag = cpu_to_be16(domain->sig.dif.app_tag);
34768e6e287fSHans Petter Selasky 	inl->dif_reftag = cpu_to_be32(domain->sig.dif.ref_tag);
34778e6e287fSHans Petter Selasky 	/* repeating block */
34788e6e287fSHans Petter Selasky 	inl->rp_inv_seed = MLX5_BSF_REPEAT_BLOCK;
34798e6e287fSHans Petter Selasky 	inl->sig_type = domain->sig.dif.bg_type == IB_T10DIF_CRC ?
34808e6e287fSHans Petter Selasky 			MLX5_DIF_CRC : MLX5_DIF_IPCS;
34818e6e287fSHans Petter Selasky 
34828e6e287fSHans Petter Selasky 	if (domain->sig.dif.ref_remap)
34838e6e287fSHans Petter Selasky 		inl->dif_inc_ref_guard_check |= MLX5_BSF_INC_REFTAG;
34848e6e287fSHans Petter Selasky 
34858e6e287fSHans Petter Selasky 	if (domain->sig.dif.app_escape) {
34868e6e287fSHans Petter Selasky 		if (domain->sig.dif.ref_escape)
34878e6e287fSHans Petter Selasky 			inl->dif_inc_ref_guard_check |= MLX5_BSF_APPREF_ESCAPE;
34888e6e287fSHans Petter Selasky 		else
34898e6e287fSHans Petter Selasky 			inl->dif_inc_ref_guard_check |= MLX5_BSF_APPTAG_ESCAPE;
34908e6e287fSHans Petter Selasky 	}
34918e6e287fSHans Petter Selasky 
34928e6e287fSHans Petter Selasky 	inl->dif_app_bitmask_check =
34938e6e287fSHans Petter Selasky 		cpu_to_be16(domain->sig.dif.apptag_check_mask);
34948e6e287fSHans Petter Selasky }
34958e6e287fSHans Petter Selasky 
mlx5_set_bsf(struct ib_mr * sig_mr,struct ib_sig_attrs * sig_attrs,struct mlx5_bsf * bsf,u32 data_size)34968e6e287fSHans Petter Selasky static int mlx5_set_bsf(struct ib_mr *sig_mr,
34978e6e287fSHans Petter Selasky 			struct ib_sig_attrs *sig_attrs,
34988e6e287fSHans Petter Selasky 			struct mlx5_bsf *bsf, u32 data_size)
34998e6e287fSHans Petter Selasky {
35008e6e287fSHans Petter Selasky 	struct mlx5_core_sig_ctx *msig = to_mmr(sig_mr)->sig;
35018e6e287fSHans Petter Selasky 	struct mlx5_bsf_basic *basic = &bsf->basic;
35028e6e287fSHans Petter Selasky 	struct ib_sig_domain *mem = &sig_attrs->mem;
35038e6e287fSHans Petter Selasky 	struct ib_sig_domain *wire = &sig_attrs->wire;
35048e6e287fSHans Petter Selasky 
35058e6e287fSHans Petter Selasky 	memset(bsf, 0, sizeof(*bsf));
35068e6e287fSHans Petter Selasky 
35078e6e287fSHans Petter Selasky 	/* Basic + Extended + Inline */
35088e6e287fSHans Petter Selasky 	basic->bsf_size_sbs = 1 << 7;
35098e6e287fSHans Petter Selasky 	/* Input domain check byte mask */
35108e6e287fSHans Petter Selasky 	basic->check_byte_mask = sig_attrs->check_mask;
35118e6e287fSHans Petter Selasky 	basic->raw_data_size = cpu_to_be32(data_size);
35128e6e287fSHans Petter Selasky 
35138e6e287fSHans Petter Selasky 	/* Memory domain */
35148e6e287fSHans Petter Selasky 	switch (sig_attrs->mem.sig_type) {
35158e6e287fSHans Petter Selasky 	case IB_SIG_TYPE_NONE:
35168e6e287fSHans Petter Selasky 		break;
35178e6e287fSHans Petter Selasky 	case IB_SIG_TYPE_T10_DIF:
35188e6e287fSHans Petter Selasky 		basic->mem.bs_selector = bs_selector(mem->sig.dif.pi_interval);
35198e6e287fSHans Petter Selasky 		basic->m_bfs_psv = cpu_to_be32(msig->psv_memory.psv_idx);
35208e6e287fSHans Petter Selasky 		mlx5_fill_inl_bsf(mem, &bsf->m_inl);
35218e6e287fSHans Petter Selasky 		break;
35228e6e287fSHans Petter Selasky 	default:
35238e6e287fSHans Petter Selasky 		return -EINVAL;
35248e6e287fSHans Petter Selasky 	}
35258e6e287fSHans Petter Selasky 
35268e6e287fSHans Petter Selasky 	/* Wire domain */
35278e6e287fSHans Petter Selasky 	switch (sig_attrs->wire.sig_type) {
35288e6e287fSHans Petter Selasky 	case IB_SIG_TYPE_NONE:
35298e6e287fSHans Petter Selasky 		break;
35308e6e287fSHans Petter Selasky 	case IB_SIG_TYPE_T10_DIF:
35318e6e287fSHans Petter Selasky 		if (mem->sig.dif.pi_interval == wire->sig.dif.pi_interval &&
35328e6e287fSHans Petter Selasky 		    mem->sig_type == wire->sig_type) {
35338e6e287fSHans Petter Selasky 			/* Same block structure */
35348e6e287fSHans Petter Selasky 			basic->bsf_size_sbs |= 1 << 4;
35358e6e287fSHans Petter Selasky 			if (mem->sig.dif.bg_type == wire->sig.dif.bg_type)
35368e6e287fSHans Petter Selasky 				basic->wire.copy_byte_mask |= MLX5_CPY_GRD_MASK;
35378e6e287fSHans Petter Selasky 			if (mem->sig.dif.app_tag == wire->sig.dif.app_tag)
35388e6e287fSHans Petter Selasky 				basic->wire.copy_byte_mask |= MLX5_CPY_APP_MASK;
35398e6e287fSHans Petter Selasky 			if (mem->sig.dif.ref_tag == wire->sig.dif.ref_tag)
35408e6e287fSHans Petter Selasky 				basic->wire.copy_byte_mask |= MLX5_CPY_REF_MASK;
35418e6e287fSHans Petter Selasky 		} else
35428e6e287fSHans Petter Selasky 			basic->wire.bs_selector = bs_selector(wire->sig.dif.pi_interval);
35438e6e287fSHans Petter Selasky 
35448e6e287fSHans Petter Selasky 		basic->w_bfs_psv = cpu_to_be32(msig->psv_wire.psv_idx);
35458e6e287fSHans Petter Selasky 		mlx5_fill_inl_bsf(wire, &bsf->w_inl);
35468e6e287fSHans Petter Selasky 		break;
35478e6e287fSHans Petter Selasky 	default:
35488e6e287fSHans Petter Selasky 		return -EINVAL;
35498e6e287fSHans Petter Selasky 	}
35508e6e287fSHans Petter Selasky 
35518e6e287fSHans Petter Selasky 	return 0;
35528e6e287fSHans Petter Selasky }
35538e6e287fSHans Petter Selasky 
set_sig_data_segment(const struct ib_sig_handover_wr * wr,struct mlx5_ib_qp * qp,void ** seg,int * size)3554c3987b8eSHans Petter Selasky static int set_sig_data_segment(const struct ib_sig_handover_wr *wr,
35558e6e287fSHans Petter Selasky 				struct mlx5_ib_qp *qp, void **seg, int *size)
35568e6e287fSHans Petter Selasky {
35578e6e287fSHans Petter Selasky 	struct ib_sig_attrs *sig_attrs = wr->sig_attrs;
35588e6e287fSHans Petter Selasky 	struct ib_mr *sig_mr = wr->sig_mr;
35598e6e287fSHans Petter Selasky 	struct mlx5_bsf *bsf;
35608e6e287fSHans Petter Selasky 	u32 data_len = wr->wr.sg_list->length;
35618e6e287fSHans Petter Selasky 	u32 data_key = wr->wr.sg_list->lkey;
35628e6e287fSHans Petter Selasky 	u64 data_va = wr->wr.sg_list->addr;
35638e6e287fSHans Petter Selasky 	int ret;
35648e6e287fSHans Petter Selasky 	int wqe_size;
35658e6e287fSHans Petter Selasky 
35668e6e287fSHans Petter Selasky 	if (!wr->prot ||
35678e6e287fSHans Petter Selasky 	    (data_key == wr->prot->lkey &&
35688e6e287fSHans Petter Selasky 	     data_va == wr->prot->addr &&
35698e6e287fSHans Petter Selasky 	     data_len == wr->prot->length)) {
35708e6e287fSHans Petter Selasky 		/**
35718e6e287fSHans Petter Selasky 		 * Source domain doesn't contain signature information
35728e6e287fSHans Petter Selasky 		 * or data and protection are interleaved in memory.
35738e6e287fSHans Petter Selasky 		 * So need construct:
35748e6e287fSHans Petter Selasky 		 *                  ------------------
35758e6e287fSHans Petter Selasky 		 *                 |     data_klm     |
35768e6e287fSHans Petter Selasky 		 *                  ------------------
35778e6e287fSHans Petter Selasky 		 *                 |       BSF        |
35788e6e287fSHans Petter Selasky 		 *                  ------------------
35798e6e287fSHans Petter Selasky 		 **/
35808e6e287fSHans Petter Selasky 		struct mlx5_klm *data_klm = *seg;
35818e6e287fSHans Petter Selasky 
35828e6e287fSHans Petter Selasky 		data_klm->bcount = cpu_to_be32(data_len);
35838e6e287fSHans Petter Selasky 		data_klm->key = cpu_to_be32(data_key);
35848e6e287fSHans Petter Selasky 		data_klm->va = cpu_to_be64(data_va);
35858e6e287fSHans Petter Selasky 		wqe_size = ALIGN(sizeof(*data_klm), 64);
35868e6e287fSHans Petter Selasky 	} else {
35878e6e287fSHans Petter Selasky 		/**
35888e6e287fSHans Petter Selasky 		 * Source domain contains signature information
35898e6e287fSHans Petter Selasky 		 * So need construct a strided block format:
35908e6e287fSHans Petter Selasky 		 *               ---------------------------
35918e6e287fSHans Petter Selasky 		 *              |     stride_block_ctrl     |
35928e6e287fSHans Petter Selasky 		 *               ---------------------------
35938e6e287fSHans Petter Selasky 		 *              |          data_klm         |
35948e6e287fSHans Petter Selasky 		 *               ---------------------------
35958e6e287fSHans Petter Selasky 		 *              |          prot_klm         |
35968e6e287fSHans Petter Selasky 		 *               ---------------------------
35978e6e287fSHans Petter Selasky 		 *              |             BSF           |
35988e6e287fSHans Petter Selasky 		 *               ---------------------------
35998e6e287fSHans Petter Selasky 		 **/
36008e6e287fSHans Petter Selasky 		struct mlx5_stride_block_ctrl_seg *sblock_ctrl;
36018e6e287fSHans Petter Selasky 		struct mlx5_stride_block_entry *data_sentry;
36028e6e287fSHans Petter Selasky 		struct mlx5_stride_block_entry *prot_sentry;
36038e6e287fSHans Petter Selasky 		u32 prot_key = wr->prot->lkey;
36048e6e287fSHans Petter Selasky 		u64 prot_va = wr->prot->addr;
36058e6e287fSHans Petter Selasky 		u16 block_size = sig_attrs->mem.sig.dif.pi_interval;
36068e6e287fSHans Petter Selasky 		int prot_size;
36078e6e287fSHans Petter Selasky 
36088e6e287fSHans Petter Selasky 		sblock_ctrl = *seg;
36098e6e287fSHans Petter Selasky 		data_sentry = (void *)sblock_ctrl + sizeof(*sblock_ctrl);
36108e6e287fSHans Petter Selasky 		prot_sentry = (void *)data_sentry + sizeof(*data_sentry);
36118e6e287fSHans Petter Selasky 
36128e6e287fSHans Petter Selasky 		prot_size = prot_field_size(sig_attrs->mem.sig_type);
36138e6e287fSHans Petter Selasky 		if (!prot_size) {
36148e6e287fSHans Petter Selasky 			pr_err("Bad block size given: %u\n", block_size);
36158e6e287fSHans Petter Selasky 			return -EINVAL;
36168e6e287fSHans Petter Selasky 		}
36178e6e287fSHans Petter Selasky 		sblock_ctrl->bcount_per_cycle = cpu_to_be32(block_size +
36188e6e287fSHans Petter Selasky 							    prot_size);
36198e6e287fSHans Petter Selasky 		sblock_ctrl->op = cpu_to_be32(MLX5_STRIDE_BLOCK_OP);
36208e6e287fSHans Petter Selasky 		sblock_ctrl->repeat_count = cpu_to_be32(data_len / block_size);
36218e6e287fSHans Petter Selasky 		sblock_ctrl->num_entries = cpu_to_be16(2);
36228e6e287fSHans Petter Selasky 
36238e6e287fSHans Petter Selasky 		data_sentry->bcount = cpu_to_be16(block_size);
36248e6e287fSHans Petter Selasky 		data_sentry->key = cpu_to_be32(data_key);
36258e6e287fSHans Petter Selasky 		data_sentry->va = cpu_to_be64(data_va);
36268e6e287fSHans Petter Selasky 		data_sentry->stride = cpu_to_be16(block_size);
36278e6e287fSHans Petter Selasky 
36288e6e287fSHans Petter Selasky 		prot_sentry->bcount = cpu_to_be16(prot_size);
36298e6e287fSHans Petter Selasky 		prot_sentry->key = cpu_to_be32(prot_key);
36308e6e287fSHans Petter Selasky 		prot_sentry->va = cpu_to_be64(prot_va);
36318e6e287fSHans Petter Selasky 		prot_sentry->stride = cpu_to_be16(prot_size);
36328e6e287fSHans Petter Selasky 
36338e6e287fSHans Petter Selasky 		wqe_size = ALIGN(sizeof(*sblock_ctrl) + sizeof(*data_sentry) +
36348e6e287fSHans Petter Selasky 				 sizeof(*prot_sentry), 64);
36358e6e287fSHans Petter Selasky 	}
36368e6e287fSHans Petter Selasky 
36378e6e287fSHans Petter Selasky 	*seg += wqe_size;
36388e6e287fSHans Petter Selasky 	*size += wqe_size / 16;
36398e6e287fSHans Petter Selasky 	if (unlikely((*seg == qp->sq.qend)))
36408e6e287fSHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
36418e6e287fSHans Petter Selasky 
36428e6e287fSHans Petter Selasky 	bsf = *seg;
36438e6e287fSHans Petter Selasky 	ret = mlx5_set_bsf(sig_mr, sig_attrs, bsf, data_len);
36448e6e287fSHans Petter Selasky 	if (ret)
364512515907SHans Petter Selasky 		return -EINVAL;
364612515907SHans Petter Selasky 
36478e6e287fSHans Petter Selasky 	*seg += sizeof(*bsf);
36488e6e287fSHans Petter Selasky 	*size += sizeof(*bsf) / 16;
36498e6e287fSHans Petter Selasky 	if (unlikely((*seg == qp->sq.qend)))
36508e6e287fSHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
36518e6e287fSHans Petter Selasky 
36528e6e287fSHans Petter Selasky 	return 0;
36538e6e287fSHans Petter Selasky }
36548e6e287fSHans Petter Selasky 
set_sig_mkey_segment(struct mlx5_mkey_seg * seg,const struct ib_sig_handover_wr * wr,u32 nelements,u32 length,u32 pdn)36558e6e287fSHans Petter Selasky static void set_sig_mkey_segment(struct mlx5_mkey_seg *seg,
3656c3987b8eSHans Petter Selasky 				 const struct ib_sig_handover_wr *wr, u32 nelements,
36578e6e287fSHans Petter Selasky 				 u32 length, u32 pdn)
36588e6e287fSHans Petter Selasky {
36598e6e287fSHans Petter Selasky 	struct ib_mr *sig_mr = wr->sig_mr;
36608e6e287fSHans Petter Selasky 	u32 sig_key = sig_mr->rkey;
36618e6e287fSHans Petter Selasky 	u8 sigerr = to_mmr(sig_mr)->sig->sigerr_count & 1;
36628e6e287fSHans Petter Selasky 
36638e6e287fSHans Petter Selasky 	memset(seg, 0, sizeof(*seg));
36648e6e287fSHans Petter Selasky 
36658e6e287fSHans Petter Selasky 	seg->flags = get_umr_flags(wr->access_flags) |
36668e6e287fSHans Petter Selasky 				   MLX5_ACCESS_MODE_KLM;
36678e6e287fSHans Petter Selasky 	seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00);
36688e6e287fSHans Petter Selasky 	seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | sigerr << 26 |
36698e6e287fSHans Petter Selasky 				    MLX5_MKEY_BSF_EN | pdn);
36708e6e287fSHans Petter Selasky 	seg->len = cpu_to_be64(length);
36718e6e287fSHans Petter Selasky 	seg->xlt_oct_size = cpu_to_be32(be16_to_cpu(get_klm_octo(nelements)));
36728e6e287fSHans Petter Selasky 	seg->bsfs_octo_size = cpu_to_be32(MLX5_MKEY_BSF_OCTO_SIZE);
36738e6e287fSHans Petter Selasky }
36748e6e287fSHans Petter Selasky 
set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg * umr,u32 nelements)36758e6e287fSHans Petter Selasky static void set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
36768e6e287fSHans Petter Selasky 				u32 nelements)
36778e6e287fSHans Petter Selasky {
36788e6e287fSHans Petter Selasky 	memset(umr, 0, sizeof(*umr));
36798e6e287fSHans Petter Selasky 
36808e6e287fSHans Petter Selasky 	umr->flags = MLX5_FLAGS_INLINE | MLX5_FLAGS_CHECK_FREE;
36818e6e287fSHans Petter Selasky 	umr->klm_octowords = get_klm_octo(nelements);
36828e6e287fSHans Petter Selasky 	umr->bsf_octowords = cpu_to_be16(MLX5_MKEY_BSF_OCTO_SIZE);
36838e6e287fSHans Petter Selasky 	umr->mkey_mask = sig_mkey_mask();
36848e6e287fSHans Petter Selasky }
36858e6e287fSHans Petter Selasky 
36868e6e287fSHans Petter Selasky 
set_sig_umr_wr(const struct ib_send_wr * send_wr,struct mlx5_ib_qp * qp,void ** seg,int * size)3687c3987b8eSHans Petter Selasky static int set_sig_umr_wr(const struct ib_send_wr *send_wr, struct mlx5_ib_qp *qp,
36888e6e287fSHans Petter Selasky 			  void **seg, int *size)
36898e6e287fSHans Petter Selasky {
3690c3987b8eSHans Petter Selasky 	const struct ib_sig_handover_wr *wr = sig_handover_wr(send_wr);
36918e6e287fSHans Petter Selasky 	struct mlx5_ib_mr *sig_mr = to_mmr(wr->sig_mr);
36928e6e287fSHans Petter Selasky 	u32 pdn = get_pd(qp)->pdn;
36938e6e287fSHans Petter Selasky 	u32 klm_oct_size;
36948e6e287fSHans Petter Selasky 	int region_len, ret;
36958e6e287fSHans Petter Selasky 
36968e6e287fSHans Petter Selasky 	if (unlikely(wr->wr.num_sge != 1) ||
36978e6e287fSHans Petter Selasky 	    unlikely(wr->access_flags & IB_ACCESS_REMOTE_ATOMIC) ||
36988e6e287fSHans Petter Selasky 	    unlikely(!sig_mr->sig) || unlikely(!qp->signature_en) ||
36998e6e287fSHans Petter Selasky 	    unlikely(!sig_mr->sig->sig_status_checked))
37008e6e287fSHans Petter Selasky 		return -EINVAL;
37018e6e287fSHans Petter Selasky 
37028e6e287fSHans Petter Selasky 	/* length of the protected region, data + protection */
37038e6e287fSHans Petter Selasky 	region_len = wr->wr.sg_list->length;
37048e6e287fSHans Petter Selasky 	if (wr->prot &&
37058e6e287fSHans Petter Selasky 	    (wr->prot->lkey != wr->wr.sg_list->lkey  ||
37068e6e287fSHans Petter Selasky 	     wr->prot->addr != wr->wr.sg_list->addr  ||
37078e6e287fSHans Petter Selasky 	     wr->prot->length != wr->wr.sg_list->length))
37088e6e287fSHans Petter Selasky 		region_len += wr->prot->length;
37098e6e287fSHans Petter Selasky 
37108e6e287fSHans Petter Selasky 	/**
37118e6e287fSHans Petter Selasky 	 * KLM octoword size - if protection was provided
37128e6e287fSHans Petter Selasky 	 * then we use strided block format (3 octowords),
37138e6e287fSHans Petter Selasky 	 * else we use single KLM (1 octoword)
37148e6e287fSHans Petter Selasky 	 **/
37158e6e287fSHans Petter Selasky 	klm_oct_size = wr->prot ? 3 : 1;
37168e6e287fSHans Petter Selasky 
37178e6e287fSHans Petter Selasky 	set_sig_umr_segment(*seg, klm_oct_size);
371812515907SHans Petter Selasky 	*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
371912515907SHans Petter Selasky 	*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
372012515907SHans Petter Selasky 	if (unlikely((*seg == qp->sq.qend)))
372112515907SHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
37228e6e287fSHans Petter Selasky 
37238e6e287fSHans Petter Selasky 	set_sig_mkey_segment(*seg, wr, klm_oct_size, region_len, pdn);
372412515907SHans Petter Selasky 	*seg += sizeof(struct mlx5_mkey_seg);
372512515907SHans Petter Selasky 	*size += sizeof(struct mlx5_mkey_seg) / 16;
372612515907SHans Petter Selasky 	if (unlikely((*seg == qp->sq.qend)))
372712515907SHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
372812515907SHans Petter Selasky 
37298e6e287fSHans Petter Selasky 	ret = set_sig_data_segment(wr, qp, seg, size);
37308e6e287fSHans Petter Selasky 	if (ret)
37318e6e287fSHans Petter Selasky 		return ret;
37328e6e287fSHans Petter Selasky 
37338e6e287fSHans Petter Selasky 	sig_mr->sig->sig_status_checked = false;
37348e6e287fSHans Petter Selasky 	return 0;
37358e6e287fSHans Petter Selasky }
37368e6e287fSHans Petter Selasky 
set_psv_wr(struct ib_sig_domain * domain,u32 psv_idx,void ** seg,int * size)37378e6e287fSHans Petter Selasky static int set_psv_wr(struct ib_sig_domain *domain,
37388e6e287fSHans Petter Selasky 		      u32 psv_idx, void **seg, int *size)
37398e6e287fSHans Petter Selasky {
37408e6e287fSHans Petter Selasky 	struct mlx5_seg_set_psv *psv_seg = *seg;
37418e6e287fSHans Petter Selasky 
37428e6e287fSHans Petter Selasky 	memset(psv_seg, 0, sizeof(*psv_seg));
37438e6e287fSHans Petter Selasky 	psv_seg->psv_num = cpu_to_be32(psv_idx);
37448e6e287fSHans Petter Selasky 	switch (domain->sig_type) {
37458e6e287fSHans Petter Selasky 	case IB_SIG_TYPE_NONE:
37468e6e287fSHans Petter Selasky 		break;
37478e6e287fSHans Petter Selasky 	case IB_SIG_TYPE_T10_DIF:
37488e6e287fSHans Petter Selasky 		psv_seg->transient_sig = cpu_to_be32(domain->sig.dif.bg << 16 |
37498e6e287fSHans Petter Selasky 						     domain->sig.dif.app_tag);
37508e6e287fSHans Petter Selasky 		psv_seg->ref_tag = cpu_to_be32(domain->sig.dif.ref_tag);
37518e6e287fSHans Petter Selasky 		break;
37528e6e287fSHans Petter Selasky 	default:
37538e6e287fSHans Petter Selasky 		pr_err("Bad signature type given.\n");
37548e6e287fSHans Petter Selasky 		return 1;
37558e6e287fSHans Petter Selasky 	}
37568e6e287fSHans Petter Selasky 
37578e6e287fSHans Petter Selasky 	*seg += sizeof(*psv_seg);
37588e6e287fSHans Petter Selasky 	*size += sizeof(*psv_seg) / 16;
37598e6e287fSHans Petter Selasky 
37608e6e287fSHans Petter Selasky 	return 0;
37618e6e287fSHans Petter Selasky }
37628e6e287fSHans Petter Selasky 
set_reg_wr(struct mlx5_ib_qp * qp,const struct ib_reg_wr * wr,void ** seg,int * size)37638e6e287fSHans Petter Selasky static int set_reg_wr(struct mlx5_ib_qp *qp,
3764c3987b8eSHans Petter Selasky 		      const struct ib_reg_wr *wr,
37658e6e287fSHans Petter Selasky 		      void **seg, int *size)
37668e6e287fSHans Petter Selasky {
37678e6e287fSHans Petter Selasky 	struct mlx5_ib_mr *mr = to_mmr(wr->mr);
37688e6e287fSHans Petter Selasky 	struct mlx5_ib_pd *pd = to_mpd(qp->ibqp.pd);
37698e6e287fSHans Petter Selasky 
37708e6e287fSHans Petter Selasky 	if (unlikely(wr->wr.send_flags & IB_SEND_INLINE)) {
37718e6e287fSHans Petter Selasky 		mlx5_ib_warn(to_mdev(qp->ibqp.device),
37728e6e287fSHans Petter Selasky 			     "Invalid IB_SEND_INLINE send flag\n");
37738e6e287fSHans Petter Selasky 		return -EINVAL;
37748e6e287fSHans Petter Selasky 	}
37758e6e287fSHans Petter Selasky 
37768e6e287fSHans Petter Selasky 	set_reg_umr_seg(*seg, mr);
37778e6e287fSHans Petter Selasky 	*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
37788e6e287fSHans Petter Selasky 	*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
37798e6e287fSHans Petter Selasky 	if (unlikely((*seg == qp->sq.qend)))
37808e6e287fSHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
37818e6e287fSHans Petter Selasky 
37828e6e287fSHans Petter Selasky 	set_reg_mkey_seg(*seg, mr, wr->key, wr->access);
37838e6e287fSHans Petter Selasky 	*seg += sizeof(struct mlx5_mkey_seg);
37848e6e287fSHans Petter Selasky 	*size += sizeof(struct mlx5_mkey_seg) / 16;
37858e6e287fSHans Petter Selasky 	if (unlikely((*seg == qp->sq.qend)))
37868e6e287fSHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
37878e6e287fSHans Petter Selasky 
37888e6e287fSHans Petter Selasky 	set_reg_data_seg(*seg, mr, pd);
378912515907SHans Petter Selasky 	*seg += sizeof(struct mlx5_wqe_data_seg);
379012515907SHans Petter Selasky 	*size += (sizeof(struct mlx5_wqe_data_seg) / 16);
37918e6e287fSHans Petter Selasky 
379212515907SHans Petter Selasky 	return 0;
379312515907SHans Petter Selasky }
379412515907SHans Petter Selasky 
set_linv_wr(struct mlx5_ib_qp * qp,void ** seg,int * size)37958e6e287fSHans Petter Selasky static void set_linv_wr(struct mlx5_ib_qp *qp, void **seg, int *size)
37968e6e287fSHans Petter Selasky {
37978e6e287fSHans Petter Selasky 	set_linv_umr_seg(*seg);
37988e6e287fSHans Petter Selasky 	*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
37998e6e287fSHans Petter Selasky 	*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
38008e6e287fSHans Petter Selasky 	if (unlikely((*seg == qp->sq.qend)))
38018e6e287fSHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
38028e6e287fSHans Petter Selasky 	set_linv_mkey_seg(*seg);
38038e6e287fSHans Petter Selasky 	*seg += sizeof(struct mlx5_mkey_seg);
38048e6e287fSHans Petter Selasky 	*size += sizeof(struct mlx5_mkey_seg) / 16;
38058e6e287fSHans Petter Selasky 	if (unlikely((*seg == qp->sq.qend)))
38068e6e287fSHans Petter Selasky 		*seg = mlx5_get_send_wqe(qp, 0);
38078e6e287fSHans Petter Selasky }
38088e6e287fSHans Petter Selasky 
dump_wqe(struct mlx5_ib_qp * qp,int idx,int size_16)380912515907SHans Petter Selasky static void dump_wqe(struct mlx5_ib_qp *qp, int idx, int size_16)
381012515907SHans Petter Selasky {
381112515907SHans Petter Selasky 	__be32 *p = NULL;
381212515907SHans Petter Selasky 	int tidx = idx;
381312515907SHans Petter Selasky 	int i, j;
381412515907SHans Petter Selasky 
381512515907SHans Petter Selasky 	pr_debug("dump wqe at %p\n", mlx5_get_send_wqe(qp, tidx));
381612515907SHans Petter Selasky 	for (i = 0, j = 0; i < size_16 * 4; i += 4, j += 4) {
381712515907SHans Petter Selasky 		if ((i & 0xf) == 0) {
381812515907SHans Petter Selasky 			void *buf = mlx5_get_send_wqe(qp, tidx);
381912515907SHans Petter Selasky 			tidx = (tidx + 1) & (qp->sq.wqe_cnt - 1);
382012515907SHans Petter Selasky 			p = buf;
382112515907SHans Petter Selasky 			j = 0;
382212515907SHans Petter Selasky 		}
382312515907SHans Petter Selasky 		pr_debug("%08x %08x %08x %08x\n", be32_to_cpu(p[j]),
382412515907SHans Petter Selasky 			 be32_to_cpu(p[j + 1]), be32_to_cpu(p[j + 2]),
382512515907SHans Petter Selasky 			 be32_to_cpu(p[j + 3]));
382612515907SHans Petter Selasky 	}
382712515907SHans Petter Selasky }
382812515907SHans Petter Selasky 
get_fence(u8 fence,const struct ib_send_wr * wr)3829c3987b8eSHans Petter Selasky static u8 get_fence(u8 fence, const struct ib_send_wr *wr)
383012515907SHans Petter Selasky {
383112515907SHans Petter Selasky 	if (unlikely(wr->opcode == IB_WR_LOCAL_INV &&
383212515907SHans Petter Selasky 		     wr->send_flags & IB_SEND_FENCE))
383312515907SHans Petter Selasky 		return MLX5_FENCE_MODE_STRONG_ORDERING;
383412515907SHans Petter Selasky 
383512515907SHans Petter Selasky 	if (unlikely(fence)) {
383612515907SHans Petter Selasky 		if (wr->send_flags & IB_SEND_FENCE)
383712515907SHans Petter Selasky 			return MLX5_FENCE_MODE_SMALL_AND_FENCE;
383812515907SHans Petter Selasky 		else
383912515907SHans Petter Selasky 			return fence;
38408e6e287fSHans Petter Selasky 	} else if (unlikely(wr->send_flags & IB_SEND_FENCE)) {
38418e6e287fSHans Petter Selasky 		return MLX5_FENCE_MODE_FENCE;
384212515907SHans Petter Selasky 	}
38438e6e287fSHans Petter Selasky 
38448e6e287fSHans Petter Selasky 	return 0;
384512515907SHans Petter Selasky }
384612515907SHans Petter Selasky 
begin_wqe(struct mlx5_ib_qp * qp,void ** seg,struct mlx5_wqe_ctrl_seg ** ctrl,const struct ib_send_wr * wr,unsigned * idx,int * size,int nreq,int send_flags)3847b633e08cSHans Petter Selasky static int begin_wqe(struct mlx5_ib_qp *qp, void **seg,
384812515907SHans Petter Selasky 		     struct mlx5_wqe_ctrl_seg **ctrl,
3849c3987b8eSHans Petter Selasky 		     const struct ib_send_wr *wr, unsigned *idx,
3850b633e08cSHans Petter Selasky 		     int *size, int nreq, int send_flags)
385112515907SHans Petter Selasky {
38528e6e287fSHans Petter Selasky 	if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)))
38538e6e287fSHans Petter Selasky 		return -ENOMEM;
385412515907SHans Petter Selasky 
385512515907SHans Petter Selasky 	*idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1);
385612515907SHans Petter Selasky 	*seg = mlx5_get_send_wqe(qp, *idx);
385712515907SHans Petter Selasky 	*ctrl = *seg;
38588e6e287fSHans Petter Selasky 	*(uint32_t *)(*seg + 8) = 0;
385912515907SHans Petter Selasky 	(*ctrl)->imm = send_ieth(wr);
386012515907SHans Petter Selasky 	(*ctrl)->fm_ce_se = qp->sq_signal_bits |
3861b633e08cSHans Petter Selasky 		(send_flags & IB_SEND_SIGNALED ?
3862b633e08cSHans Petter Selasky 		 MLX5_WQE_CTRL_CQ_UPDATE : 0) |
3863b633e08cSHans Petter Selasky 		(send_flags & IB_SEND_SOLICITED ?
3864b633e08cSHans Petter Selasky 		 MLX5_WQE_CTRL_SOLICITED : 0);
386512515907SHans Petter Selasky 
386612515907SHans Petter Selasky 	*seg += sizeof(**ctrl);
386712515907SHans Petter Selasky 	*size = sizeof(**ctrl) / 16;
386812515907SHans Petter Selasky 
38698e6e287fSHans Petter Selasky 	return 0;
387012515907SHans Petter Selasky }
387112515907SHans Petter Selasky 
finish_wqe(struct mlx5_ib_qp * qp,struct mlx5_wqe_ctrl_seg * ctrl,u8 size,unsigned idx,u64 wr_id,int nreq,u8 fence,u8 next_fence,u32 mlx5_opcode)387212515907SHans Petter Selasky static void finish_wqe(struct mlx5_ib_qp *qp,
387312515907SHans Petter Selasky 		       struct mlx5_wqe_ctrl_seg *ctrl,
38748e6e287fSHans Petter Selasky 		       u8 size, unsigned idx, u64 wr_id,
387512515907SHans Petter Selasky 		       int nreq, u8 fence, u8 next_fence,
387612515907SHans Petter Selasky 		       u32 mlx5_opcode)
387712515907SHans Petter Selasky {
387812515907SHans Petter Selasky 	u8 opmod = 0;
387912515907SHans Petter Selasky 
388012515907SHans Petter Selasky 	ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) |
388112515907SHans Petter Selasky 					     mlx5_opcode | ((u32)opmod << 24));
38828e6e287fSHans Petter Selasky 	ctrl->qpn_ds = cpu_to_be32(size | (qp->trans_qp.base.mqp.qpn << 8));
388312515907SHans Petter Selasky 	ctrl->fm_ce_se |= fence;
388412515907SHans Petter Selasky 	qp->fm_cache = next_fence;
388512515907SHans Petter Selasky 	if (unlikely(qp->wq_sig))
38868e6e287fSHans Petter Selasky 		ctrl->signature = wq_sig(ctrl);
388712515907SHans Petter Selasky 
38888e6e287fSHans Petter Selasky 	qp->sq.wrid[idx] = wr_id;
38898e6e287fSHans Petter Selasky 	qp->sq.w_list[idx].opcode = mlx5_opcode;
38908e6e287fSHans Petter Selasky 	qp->sq.wqe_head[idx] = qp->sq.head + nreq;
389112515907SHans Petter Selasky 	qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB);
38928e6e287fSHans Petter Selasky 	qp->sq.w_list[idx].next = qp->sq.cur_post;
389312515907SHans Petter Selasky }
389412515907SHans Petter Selasky 
38958e6e287fSHans Petter Selasky 
mlx5_ib_post_send(struct ib_qp * ibqp,const struct ib_send_wr * wr,const struct ib_send_wr ** bad_wr)3896c3987b8eSHans Petter Selasky int mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
3897c3987b8eSHans Petter Selasky 		      const struct ib_send_wr **bad_wr)
389812515907SHans Petter Selasky {
389912515907SHans Petter Selasky 	struct mlx5_wqe_ctrl_seg *ctrl = NULL;  /* compiler warning */
390012515907SHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
390112515907SHans Petter Selasky 	struct mlx5_core_dev *mdev = dev->mdev;
39028e6e287fSHans Petter Selasky 	struct mlx5_ib_qp *qp;
39038e6e287fSHans Petter Selasky 	struct mlx5_ib_mr *mr;
390412515907SHans Petter Selasky 	struct mlx5_wqe_data_seg *dpseg;
390512515907SHans Petter Selasky 	struct mlx5_wqe_xrc_seg *xrc;
39068e6e287fSHans Petter Selasky 	struct mlx5_bf *bf;
390712515907SHans Petter Selasky 	int uninitialized_var(size);
39088e6e287fSHans Petter Selasky 	void *qend;
390912515907SHans Petter Selasky 	unsigned long flags;
391012515907SHans Petter Selasky 	unsigned idx;
391112515907SHans Petter Selasky 	int err = 0;
391212515907SHans Petter Selasky 	int num_sge;
391312515907SHans Petter Selasky 	void *seg;
391412515907SHans Petter Selasky 	int nreq;
391512515907SHans Petter Selasky 	int i;
391612515907SHans Petter Selasky 	u8 next_fence = 0;
391712515907SHans Petter Selasky 	u8 fence;
391812515907SHans Petter Selasky 
39198e6e287fSHans Petter Selasky 	if (unlikely(ibqp->qp_type == IB_QPT_GSI))
39208e6e287fSHans Petter Selasky 		return mlx5_ib_gsi_post_send(ibqp, wr, bad_wr);
39218e6e287fSHans Petter Selasky 
39228e6e287fSHans Petter Selasky 	qp = to_mqp(ibqp);
3923f8f5b459SHans Petter Selasky 	bf = &qp->bf;
39248e6e287fSHans Petter Selasky 	qend = qp->sq.qend;
392512515907SHans Petter Selasky 
392612515907SHans Petter Selasky 	spin_lock_irqsave(&qp->sq.lock, flags);
392712515907SHans Petter Selasky 
392812515907SHans Petter Selasky 	if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
392912515907SHans Petter Selasky 		err = -EIO;
393012515907SHans Petter Selasky 		*bad_wr = wr;
393112515907SHans Petter Selasky 		nreq = 0;
393212515907SHans Petter Selasky 		goto out;
393312515907SHans Petter Selasky 	}
393412515907SHans Petter Selasky 
393512515907SHans Petter Selasky 	for (nreq = 0; wr; nreq++, wr = wr->next) {
3936dd00abf2SHans Petter Selasky 		if (unlikely(wr->opcode < 0 || wr->opcode >= ARRAY_SIZE(mlx5_ib_opcode))) {
39378e6e287fSHans Petter Selasky 			mlx5_ib_warn(dev, "\n");
393812515907SHans Petter Selasky 			err = -EINVAL;
393912515907SHans Petter Selasky 			*bad_wr = wr;
394012515907SHans Petter Selasky 			goto out;
394112515907SHans Petter Selasky 		}
394212515907SHans Petter Selasky 
394312515907SHans Petter Selasky 		fence = qp->fm_cache;
394412515907SHans Petter Selasky 		num_sge = wr->num_sge;
394512515907SHans Petter Selasky 		if (unlikely(num_sge > qp->sq.max_gs)) {
39468e6e287fSHans Petter Selasky 			mlx5_ib_warn(dev, "\n");
39478e6e287fSHans Petter Selasky 			err = -EINVAL;
394812515907SHans Petter Selasky 			*bad_wr = wr;
394912515907SHans Petter Selasky 			goto out;
395012515907SHans Petter Selasky 		}
395112515907SHans Petter Selasky 
3952b633e08cSHans Petter Selasky 		err = begin_wqe(qp, &seg, &ctrl, wr, &idx, &size, nreq, wr->send_flags);
395312515907SHans Petter Selasky 		if (err) {
39548e6e287fSHans Petter Selasky 			mlx5_ib_warn(dev, "\n");
395512515907SHans Petter Selasky 			err = -ENOMEM;
395612515907SHans Petter Selasky 			*bad_wr = wr;
395712515907SHans Petter Selasky 			goto out;
395812515907SHans Petter Selasky 		}
395912515907SHans Petter Selasky 
396012515907SHans Petter Selasky 		switch (ibqp->qp_type) {
396112515907SHans Petter Selasky 		case IB_QPT_XRC_INI:
396212515907SHans Petter Selasky 			xrc = seg;
396312515907SHans Petter Selasky 			seg += sizeof(*xrc);
396412515907SHans Petter Selasky 			size += sizeof(*xrc) / 16;
396512515907SHans Petter Selasky 			/* fall through */
396612515907SHans Petter Selasky 		case IB_QPT_RC:
396712515907SHans Petter Selasky 			switch (wr->opcode) {
396812515907SHans Petter Selasky 			case IB_WR_RDMA_READ:
396912515907SHans Petter Selasky 			case IB_WR_RDMA_WRITE:
397012515907SHans Petter Selasky 			case IB_WR_RDMA_WRITE_WITH_IMM:
39718e6e287fSHans Petter Selasky 				set_raddr_seg(seg, rdma_wr(wr)->remote_addr,
39728e6e287fSHans Petter Selasky 					      rdma_wr(wr)->rkey);
397312515907SHans Petter Selasky 				seg += sizeof(struct mlx5_wqe_raddr_seg);
397412515907SHans Petter Selasky 				size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
397512515907SHans Petter Selasky 				break;
397612515907SHans Petter Selasky 
397712515907SHans Petter Selasky 			case IB_WR_ATOMIC_CMP_AND_SWP:
397812515907SHans Petter Selasky 			case IB_WR_ATOMIC_FETCH_AND_ADD:
397912515907SHans Petter Selasky 			case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
398012515907SHans Petter Selasky 				mlx5_ib_warn(dev, "Atomic operations are not supported yet\n");
398112515907SHans Petter Selasky 				err = -ENOSYS;
398212515907SHans Petter Selasky 				*bad_wr = wr;
398312515907SHans Petter Selasky 				goto out;
398412515907SHans Petter Selasky 
398512515907SHans Petter Selasky 			case IB_WR_LOCAL_INV:
398612515907SHans Petter Selasky 				next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
39878e6e287fSHans Petter Selasky 				qp->sq.wr_data[idx] = IB_WR_LOCAL_INV;
398812515907SHans Petter Selasky 				ctrl->imm = cpu_to_be32(wr->ex.invalidate_rkey);
39898e6e287fSHans Petter Selasky 				set_linv_wr(qp, &seg, &size);
39908e6e287fSHans Petter Selasky 				num_sge = 0;
39918e6e287fSHans Petter Selasky 				break;
39928e6e287fSHans Petter Selasky 
39938e6e287fSHans Petter Selasky 			case IB_WR_REG_MR:
39948e6e287fSHans Petter Selasky 				next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
39958e6e287fSHans Petter Selasky 				qp->sq.wr_data[idx] = IB_WR_REG_MR;
39968e6e287fSHans Petter Selasky 				ctrl->imm = cpu_to_be32(reg_wr(wr)->key);
39978e6e287fSHans Petter Selasky 				err = set_reg_wr(qp, reg_wr(wr), &seg, &size);
399812515907SHans Petter Selasky 				if (err) {
399912515907SHans Petter Selasky 					*bad_wr = wr;
400012515907SHans Petter Selasky 					goto out;
400112515907SHans Petter Selasky 				}
400212515907SHans Petter Selasky 				num_sge = 0;
400312515907SHans Petter Selasky 				break;
400412515907SHans Petter Selasky 
40058e6e287fSHans Petter Selasky 			case IB_WR_REG_SIG_MR:
40068e6e287fSHans Petter Selasky 				qp->sq.wr_data[idx] = IB_WR_REG_SIG_MR;
40078e6e287fSHans Petter Selasky 				mr = to_mmr(sig_handover_wr(wr)->sig_mr);
40088e6e287fSHans Petter Selasky 
40098e6e287fSHans Petter Selasky 				ctrl->imm = cpu_to_be32(mr->ibmr.rkey);
40108e6e287fSHans Petter Selasky 				err = set_sig_umr_wr(wr, qp, &seg, &size);
401112515907SHans Petter Selasky 				if (err) {
40128e6e287fSHans Petter Selasky 					mlx5_ib_warn(dev, "\n");
401312515907SHans Petter Selasky 					*bad_wr = wr;
401412515907SHans Petter Selasky 					goto out;
401512515907SHans Petter Selasky 				}
40168e6e287fSHans Petter Selasky 
40178e6e287fSHans Petter Selasky 				finish_wqe(qp, ctrl, size, idx, wr->wr_id,
40188e6e287fSHans Petter Selasky 					   nreq, get_fence(fence, wr),
40198e6e287fSHans Petter Selasky 					   next_fence, MLX5_OPCODE_UMR);
40208e6e287fSHans Petter Selasky 				/*
40218e6e287fSHans Petter Selasky 				 * SET_PSV WQEs are not signaled and solicited
40228e6e287fSHans Petter Selasky 				 * on error
40238e6e287fSHans Petter Selasky 				 */
4024b633e08cSHans Petter Selasky 				err = begin_wqe(qp, &seg, &ctrl, wr,
4025b633e08cSHans Petter Selasky 						&idx, &size, nreq, IB_SEND_SOLICITED);
40268e6e287fSHans Petter Selasky 				if (err) {
40278e6e287fSHans Petter Selasky 					mlx5_ib_warn(dev, "\n");
40288e6e287fSHans Petter Selasky 					err = -ENOMEM;
40298e6e287fSHans Petter Selasky 					*bad_wr = wr;
40308e6e287fSHans Petter Selasky 					goto out;
40318e6e287fSHans Petter Selasky 				}
40328e6e287fSHans Petter Selasky 
40338e6e287fSHans Petter Selasky 				err = set_psv_wr(&sig_handover_wr(wr)->sig_attrs->mem,
40348e6e287fSHans Petter Selasky 						 mr->sig->psv_memory.psv_idx, &seg,
40358e6e287fSHans Petter Selasky 						 &size);
40368e6e287fSHans Petter Selasky 				if (err) {
40378e6e287fSHans Petter Selasky 					mlx5_ib_warn(dev, "\n");
40388e6e287fSHans Petter Selasky 					*bad_wr = wr;
40398e6e287fSHans Petter Selasky 					goto out;
40408e6e287fSHans Petter Selasky 				}
40418e6e287fSHans Petter Selasky 
40428e6e287fSHans Petter Selasky 				finish_wqe(qp, ctrl, size, idx, wr->wr_id,
40438e6e287fSHans Petter Selasky 					   nreq, get_fence(fence, wr),
40448e6e287fSHans Petter Selasky 					   next_fence, MLX5_OPCODE_SET_PSV);
4045b633e08cSHans Petter Selasky 				err = begin_wqe(qp, &seg, &ctrl, wr,
4046b633e08cSHans Petter Selasky 						&idx, &size, nreq, wr->send_flags);
40478e6e287fSHans Petter Selasky 				if (err) {
40488e6e287fSHans Petter Selasky 					mlx5_ib_warn(dev, "\n");
40498e6e287fSHans Petter Selasky 					err = -ENOMEM;
40508e6e287fSHans Petter Selasky 					*bad_wr = wr;
40518e6e287fSHans Petter Selasky 					goto out;
40528e6e287fSHans Petter Selasky 				}
40538e6e287fSHans Petter Selasky 
40548e6e287fSHans Petter Selasky 				next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
40558e6e287fSHans Petter Selasky 				err = set_psv_wr(&sig_handover_wr(wr)->sig_attrs->wire,
40568e6e287fSHans Petter Selasky 						 mr->sig->psv_wire.psv_idx, &seg,
40578e6e287fSHans Petter Selasky 						 &size);
40588e6e287fSHans Petter Selasky 				if (err) {
40598e6e287fSHans Petter Selasky 					mlx5_ib_warn(dev, "\n");
40608e6e287fSHans Petter Selasky 					*bad_wr = wr;
40618e6e287fSHans Petter Selasky 					goto out;
40628e6e287fSHans Petter Selasky 				}
40638e6e287fSHans Petter Selasky 
40648e6e287fSHans Petter Selasky 				finish_wqe(qp, ctrl, size, idx, wr->wr_id,
40658e6e287fSHans Petter Selasky 					   nreq, get_fence(fence, wr),
40668e6e287fSHans Petter Selasky 					   next_fence, MLX5_OPCODE_SET_PSV);
406712515907SHans Petter Selasky 				num_sge = 0;
40688e6e287fSHans Petter Selasky 				goto skip_psv;
406912515907SHans Petter Selasky 
407012515907SHans Petter Selasky 			default:
407112515907SHans Petter Selasky 				break;
407212515907SHans Petter Selasky 			}
407312515907SHans Petter Selasky 			break;
407412515907SHans Petter Selasky 
407512515907SHans Petter Selasky 		case IB_QPT_UC:
407612515907SHans Petter Selasky 			switch (wr->opcode) {
407712515907SHans Petter Selasky 			case IB_WR_RDMA_WRITE:
407812515907SHans Petter Selasky 			case IB_WR_RDMA_WRITE_WITH_IMM:
40798e6e287fSHans Petter Selasky 				set_raddr_seg(seg, rdma_wr(wr)->remote_addr,
40808e6e287fSHans Petter Selasky 					      rdma_wr(wr)->rkey);
408112515907SHans Petter Selasky 				seg  += sizeof(struct mlx5_wqe_raddr_seg);
408212515907SHans Petter Selasky 				size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
408312515907SHans Petter Selasky 				break;
408412515907SHans Petter Selasky 
408512515907SHans Petter Selasky 			default:
408612515907SHans Petter Selasky 				break;
408712515907SHans Petter Selasky 			}
408812515907SHans Petter Selasky 			break;
408912515907SHans Petter Selasky 
409012515907SHans Petter Selasky 		case IB_QPT_SMI:
40918e6e287fSHans Petter Selasky 		case MLX5_IB_QPT_HW_GSI:
409212515907SHans Petter Selasky 			set_datagram_seg(seg, wr);
409312515907SHans Petter Selasky 			seg += sizeof(struct mlx5_wqe_datagram_seg);
409412515907SHans Petter Selasky 			size += sizeof(struct mlx5_wqe_datagram_seg) / 16;
409512515907SHans Petter Selasky 			if (unlikely((seg == qend)))
409612515907SHans Petter Selasky 				seg = mlx5_get_send_wqe(qp, 0);
409712515907SHans Petter Selasky 			break;
40988e6e287fSHans Petter Selasky 		case IB_QPT_UD:
40998e6e287fSHans Petter Selasky 			set_datagram_seg(seg, wr);
41008e6e287fSHans Petter Selasky 			seg += sizeof(struct mlx5_wqe_datagram_seg);
41018e6e287fSHans Petter Selasky 			size += sizeof(struct mlx5_wqe_datagram_seg) / 16;
41028e6e287fSHans Petter Selasky 
41038e6e287fSHans Petter Selasky 			if (unlikely((seg == qend)))
41048e6e287fSHans Petter Selasky 				seg = mlx5_get_send_wqe(qp, 0);
41058e6e287fSHans Petter Selasky 
41068e6e287fSHans Petter Selasky 			/* handle qp that supports ud offload */
41078e6e287fSHans Petter Selasky 			if (qp->flags & IB_QP_CREATE_IPOIB_UD_LSO) {
41088e6e287fSHans Petter Selasky 				struct mlx5_wqe_eth_pad *pad;
41098e6e287fSHans Petter Selasky 
41108e6e287fSHans Petter Selasky 				pad = seg;
41118e6e287fSHans Petter Selasky 				memset(pad, 0, sizeof(struct mlx5_wqe_eth_pad));
41128e6e287fSHans Petter Selasky 				seg += sizeof(struct mlx5_wqe_eth_pad);
41138e6e287fSHans Petter Selasky 				size += sizeof(struct mlx5_wqe_eth_pad) / 16;
41148e6e287fSHans Petter Selasky 
41158e6e287fSHans Petter Selasky 				seg = set_eth_seg(seg, wr, qend, qp, &size);
41168e6e287fSHans Petter Selasky 
41178e6e287fSHans Petter Selasky 				if (unlikely((seg == qend)))
41188e6e287fSHans Petter Selasky 					seg = mlx5_get_send_wqe(qp, 0);
41198e6e287fSHans Petter Selasky 			}
41208e6e287fSHans Petter Selasky 			break;
41218e6e287fSHans Petter Selasky 		case MLX5_IB_QPT_REG_UMR:
41228e6e287fSHans Petter Selasky 			if (wr->opcode != MLX5_IB_WR_UMR) {
41238e6e287fSHans Petter Selasky 				err = -EINVAL;
41248e6e287fSHans Petter Selasky 				mlx5_ib_warn(dev, "bad opcode\n");
41258e6e287fSHans Petter Selasky 				goto out;
41268e6e287fSHans Petter Selasky 			}
41278e6e287fSHans Petter Selasky 			qp->sq.wr_data[idx] = MLX5_IB_WR_UMR;
41288e6e287fSHans Petter Selasky 			ctrl->imm = cpu_to_be32(umr_wr(wr)->mkey);
41298e6e287fSHans Petter Selasky 			set_reg_umr_segment(seg, wr);
41308e6e287fSHans Petter Selasky 			seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
41318e6e287fSHans Petter Selasky 			size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
41328e6e287fSHans Petter Selasky 			if (unlikely((seg == qend)))
41338e6e287fSHans Petter Selasky 				seg = mlx5_get_send_wqe(qp, 0);
41348e6e287fSHans Petter Selasky 			set_reg_mkey_segment(seg, wr);
41358e6e287fSHans Petter Selasky 			seg += sizeof(struct mlx5_mkey_seg);
41368e6e287fSHans Petter Selasky 			size += sizeof(struct mlx5_mkey_seg) / 16;
41378e6e287fSHans Petter Selasky 			if (unlikely((seg == qend)))
41388e6e287fSHans Petter Selasky 				seg = mlx5_get_send_wqe(qp, 0);
41398e6e287fSHans Petter Selasky 			break;
41408e6e287fSHans Petter Selasky 
414112515907SHans Petter Selasky 		default:
414212515907SHans Petter Selasky 			break;
414312515907SHans Petter Selasky 		}
414412515907SHans Petter Selasky 
414512515907SHans Petter Selasky 		if (wr->send_flags & IB_SEND_INLINE && num_sge) {
414612515907SHans Petter Selasky 			int uninitialized_var(sz);
414712515907SHans Petter Selasky 
414812515907SHans Petter Selasky 			err = set_data_inl_seg(qp, wr, seg, &sz);
414912515907SHans Petter Selasky 			if (unlikely(err)) {
41508e6e287fSHans Petter Selasky 				mlx5_ib_warn(dev, "\n");
415112515907SHans Petter Selasky 				*bad_wr = wr;
415212515907SHans Petter Selasky 				goto out;
415312515907SHans Petter Selasky 			}
415412515907SHans Petter Selasky 			size += sz;
415512515907SHans Petter Selasky 		} else {
415612515907SHans Petter Selasky 			dpseg = seg;
415712515907SHans Petter Selasky 			for (i = 0; i < num_sge; i++) {
415812515907SHans Petter Selasky 				if (unlikely(dpseg == qend)) {
415912515907SHans Petter Selasky 					seg = mlx5_get_send_wqe(qp, 0);
416012515907SHans Petter Selasky 					dpseg = seg;
416112515907SHans Petter Selasky 				}
416212515907SHans Petter Selasky 				if (likely(wr->sg_list[i].length)) {
416312515907SHans Petter Selasky 					set_data_ptr_seg(dpseg, wr->sg_list + i);
416412515907SHans Petter Selasky 					size += sizeof(struct mlx5_wqe_data_seg) / 16;
416512515907SHans Petter Selasky 					dpseg++;
416612515907SHans Petter Selasky 				}
416712515907SHans Petter Selasky 			}
416812515907SHans Petter Selasky 		}
416912515907SHans Petter Selasky 
41708e6e287fSHans Petter Selasky 		finish_wqe(qp, ctrl, size, idx, wr->wr_id, nreq,
417112515907SHans Petter Selasky 			   get_fence(fence, wr), next_fence,
417212515907SHans Petter Selasky 			   mlx5_ib_opcode[wr->opcode]);
41738e6e287fSHans Petter Selasky skip_psv:
417412515907SHans Petter Selasky 		if (0)
417512515907SHans Petter Selasky 			dump_wqe(qp, idx, size);
417612515907SHans Petter Selasky 	}
417712515907SHans Petter Selasky 
417812515907SHans Petter Selasky out:
417912515907SHans Petter Selasky 	if (likely(nreq)) {
418012515907SHans Petter Selasky 		qp->sq.head += nreq;
418112515907SHans Petter Selasky 
418212515907SHans Petter Selasky 		/* Make sure that descriptors are written before
418312515907SHans Petter Selasky 		 * updating doorbell record and ringing the doorbell
418412515907SHans Petter Selasky 		 */
418512515907SHans Petter Selasky 		wmb();
418612515907SHans Petter Selasky 
418712515907SHans Petter Selasky 		qp->db.db[MLX5_SND_DBR] = cpu_to_be32(qp->sq.cur_post);
418812515907SHans Petter Selasky 
418912515907SHans Petter Selasky 		/* Make sure doorbell record is visible to the HCA before
419012515907SHans Petter Selasky 		 * we hit doorbell */
419112515907SHans Petter Selasky 		wmb();
419212515907SHans Petter Selasky 
4193f8f5b459SHans Petter Selasky 		mlx5_write64((__be32 *)ctrl, bf->bfreg->map + bf->offset,
419412515907SHans Petter Selasky 			     MLX5_GET_DOORBELL_LOCK(&bf->lock32));
419512515907SHans Petter Selasky 		/* Make sure doorbells don't leak out of SQ spinlock
419612515907SHans Petter Selasky 		 * and reach the HCA out of order.
419712515907SHans Petter Selasky 		 */
419812515907SHans Petter Selasky 		bf->offset ^= bf->buf_size;
419912515907SHans Petter Selasky 	}
420012515907SHans Petter Selasky 
420112515907SHans Petter Selasky 	spin_unlock_irqrestore(&qp->sq.lock, flags);
420212515907SHans Petter Selasky 
420312515907SHans Petter Selasky 	return err;
420412515907SHans Petter Selasky }
420512515907SHans Petter Selasky 
set_sig_seg(struct mlx5_rwqe_sig * sig,int size)420612515907SHans Petter Selasky static void set_sig_seg(struct mlx5_rwqe_sig *sig, int size)
420712515907SHans Petter Selasky {
420812515907SHans Petter Selasky 	sig->signature = calc_sig(sig, size);
420912515907SHans Petter Selasky }
421012515907SHans Petter Selasky 
mlx5_ib_post_recv(struct ib_qp * ibqp,const struct ib_recv_wr * wr,const struct ib_recv_wr ** bad_wr)4211c3987b8eSHans Petter Selasky int mlx5_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
4212c3987b8eSHans Petter Selasky 		      const struct ib_recv_wr **bad_wr)
421312515907SHans Petter Selasky {
421412515907SHans Petter Selasky 	struct mlx5_ib_qp *qp = to_mqp(ibqp);
421512515907SHans Petter Selasky 	struct mlx5_wqe_data_seg *scat;
421612515907SHans Petter Selasky 	struct mlx5_rwqe_sig *sig;
421712515907SHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
421812515907SHans Petter Selasky 	struct mlx5_core_dev *mdev = dev->mdev;
421912515907SHans Petter Selasky 	unsigned long flags;
422012515907SHans Petter Selasky 	int err = 0;
422112515907SHans Petter Selasky 	int nreq;
422212515907SHans Petter Selasky 	int ind;
422312515907SHans Petter Selasky 	int i;
422412515907SHans Petter Selasky 
42258e6e287fSHans Petter Selasky 	if (unlikely(ibqp->qp_type == IB_QPT_GSI))
42268e6e287fSHans Petter Selasky 		return mlx5_ib_gsi_post_recv(ibqp, wr, bad_wr);
42278e6e287fSHans Petter Selasky 
422812515907SHans Petter Selasky 	spin_lock_irqsave(&qp->rq.lock, flags);
422912515907SHans Petter Selasky 
423012515907SHans Petter Selasky 	if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
423112515907SHans Petter Selasky 		err = -EIO;
423212515907SHans Petter Selasky 		*bad_wr = wr;
423312515907SHans Petter Selasky 		nreq = 0;
423412515907SHans Petter Selasky 		goto out;
423512515907SHans Petter Selasky 	}
423612515907SHans Petter Selasky 
423712515907SHans Petter Selasky 	ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
423812515907SHans Petter Selasky 
423912515907SHans Petter Selasky 	for (nreq = 0; wr; nreq++, wr = wr->next) {
424012515907SHans Petter Selasky 		if (mlx5_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
424112515907SHans Petter Selasky 			err = -ENOMEM;
424212515907SHans Petter Selasky 			*bad_wr = wr;
424312515907SHans Petter Selasky 			goto out;
424412515907SHans Petter Selasky 		}
424512515907SHans Petter Selasky 
424612515907SHans Petter Selasky 		if (unlikely(wr->num_sge > qp->rq.max_gs)) {
424712515907SHans Petter Selasky 			err = -EINVAL;
424812515907SHans Petter Selasky 			*bad_wr = wr;
424912515907SHans Petter Selasky 			goto out;
425012515907SHans Petter Selasky 		}
425112515907SHans Petter Selasky 
425212515907SHans Petter Selasky 		scat = get_recv_wqe(qp, ind);
425312515907SHans Petter Selasky 		if (qp->wq_sig)
425412515907SHans Petter Selasky 			scat++;
425512515907SHans Petter Selasky 
425612515907SHans Petter Selasky 		for (i = 0; i < wr->num_sge; i++)
425712515907SHans Petter Selasky 			set_data_ptr_seg(scat + i, wr->sg_list + i);
425812515907SHans Petter Selasky 
425912515907SHans Petter Selasky 		if (i < qp->rq.max_gs) {
426012515907SHans Petter Selasky 			scat[i].byte_count = 0;
426112515907SHans Petter Selasky 			scat[i].lkey       = cpu_to_be32(MLX5_INVALID_LKEY);
426212515907SHans Petter Selasky 			scat[i].addr       = 0;
426312515907SHans Petter Selasky 		}
426412515907SHans Petter Selasky 
426512515907SHans Petter Selasky 		if (qp->wq_sig) {
426612515907SHans Petter Selasky 			sig = (struct mlx5_rwqe_sig *)scat;
426712515907SHans Petter Selasky 			set_sig_seg(sig, (qp->rq.max_gs + 1) << 2);
426812515907SHans Petter Selasky 		}
426912515907SHans Petter Selasky 
42708e6e287fSHans Petter Selasky 		qp->rq.wrid[ind] = wr->wr_id;
427112515907SHans Petter Selasky 
427212515907SHans Petter Selasky 		ind = (ind + 1) & (qp->rq.wqe_cnt - 1);
427312515907SHans Petter Selasky 	}
427412515907SHans Petter Selasky 
427512515907SHans Petter Selasky out:
427612515907SHans Petter Selasky 	if (likely(nreq)) {
427712515907SHans Petter Selasky 		qp->rq.head += nreq;
427812515907SHans Petter Selasky 
427912515907SHans Petter Selasky 		/* Make sure that descriptors are written before
428012515907SHans Petter Selasky 		 * doorbell record.
428112515907SHans Petter Selasky 		 */
428212515907SHans Petter Selasky 		wmb();
428312515907SHans Petter Selasky 
428412515907SHans Petter Selasky 		*qp->db.db = cpu_to_be32(qp->rq.head & 0xffff);
428512515907SHans Petter Selasky 	}
428612515907SHans Petter Selasky 
428712515907SHans Petter Selasky 	spin_unlock_irqrestore(&qp->rq.lock, flags);
428812515907SHans Petter Selasky 
428912515907SHans Petter Selasky 	return err;
429012515907SHans Petter Selasky }
429112515907SHans Petter Selasky 
to_ib_qp_state(enum mlx5_qp_state mlx5_state)429212515907SHans Petter Selasky static inline enum ib_qp_state to_ib_qp_state(enum mlx5_qp_state mlx5_state)
429312515907SHans Petter Selasky {
429412515907SHans Petter Selasky 	switch (mlx5_state) {
429512515907SHans Petter Selasky 	case MLX5_QP_STATE_RST:      return IB_QPS_RESET;
429612515907SHans Petter Selasky 	case MLX5_QP_STATE_INIT:     return IB_QPS_INIT;
429712515907SHans Petter Selasky 	case MLX5_QP_STATE_RTR:      return IB_QPS_RTR;
429812515907SHans Petter Selasky 	case MLX5_QP_STATE_RTS:      return IB_QPS_RTS;
429912515907SHans Petter Selasky 	case MLX5_QP_STATE_SQ_DRAINING:
430012515907SHans Petter Selasky 	case MLX5_QP_STATE_SQD:      return IB_QPS_SQD;
430112515907SHans Petter Selasky 	case MLX5_QP_STATE_SQER:     return IB_QPS_SQE;
430212515907SHans Petter Selasky 	case MLX5_QP_STATE_ERR:      return IB_QPS_ERR;
430312515907SHans Petter Selasky 	default:		     return -1;
430412515907SHans Petter Selasky 	}
430512515907SHans Petter Selasky }
430612515907SHans Petter Selasky 
to_ib_mig_state(int mlx5_mig_state)430712515907SHans Petter Selasky static inline enum ib_mig_state to_ib_mig_state(int mlx5_mig_state)
430812515907SHans Petter Selasky {
430912515907SHans Petter Selasky 	switch (mlx5_mig_state) {
431012515907SHans Petter Selasky 	case MLX5_QP_PM_ARMED:		return IB_MIG_ARMED;
431112515907SHans Petter Selasky 	case MLX5_QP_PM_REARM:		return IB_MIG_REARM;
431212515907SHans Petter Selasky 	case MLX5_QP_PM_MIGRATED:	return IB_MIG_MIGRATED;
431312515907SHans Petter Selasky 	default: return -1;
431412515907SHans Petter Selasky 	}
431512515907SHans Petter Selasky }
431612515907SHans Petter Selasky 
to_ib_qp_access_flags(int mlx5_flags)431712515907SHans Petter Selasky static int to_ib_qp_access_flags(int mlx5_flags)
431812515907SHans Petter Selasky {
431912515907SHans Petter Selasky 	int ib_flags = 0;
432012515907SHans Petter Selasky 
432112515907SHans Petter Selasky 	if (mlx5_flags & MLX5_QP_BIT_RRE)
432212515907SHans Petter Selasky 		ib_flags |= IB_ACCESS_REMOTE_READ;
432312515907SHans Petter Selasky 	if (mlx5_flags & MLX5_QP_BIT_RWE)
432412515907SHans Petter Selasky 		ib_flags |= IB_ACCESS_REMOTE_WRITE;
432512515907SHans Petter Selasky 	if (mlx5_flags & MLX5_QP_BIT_RAE)
432612515907SHans Petter Selasky 		ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
432712515907SHans Petter Selasky 
432812515907SHans Petter Selasky 	return ib_flags;
432912515907SHans Petter Selasky }
433012515907SHans Petter Selasky 
to_ib_ah_attr(struct mlx5_ib_dev * ibdev,struct ib_ah_attr * ib_ah_attr,struct mlx5_qp_path * path)433112515907SHans Petter Selasky static void to_ib_ah_attr(struct mlx5_ib_dev *ibdev, struct ib_ah_attr *ib_ah_attr,
433212515907SHans Petter Selasky 				struct mlx5_qp_path *path)
433312515907SHans Petter Selasky {
433412515907SHans Petter Selasky 	struct mlx5_core_dev *dev = ibdev->mdev;
433512515907SHans Petter Selasky 
433612515907SHans Petter Selasky 	memset(ib_ah_attr, 0, sizeof(*ib_ah_attr));
433712515907SHans Petter Selasky 	ib_ah_attr->port_num	  = path->port;
433812515907SHans Petter Selasky 
433912515907SHans Petter Selasky 	if (ib_ah_attr->port_num == 0 ||
434012515907SHans Petter Selasky 	    ib_ah_attr->port_num > MLX5_CAP_GEN(dev, num_ports))
434112515907SHans Petter Selasky 		return;
434212515907SHans Petter Selasky 
434312515907SHans Petter Selasky 	ib_ah_attr->sl = path->dci_cfi_prio_sl & 0xf;
434412515907SHans Petter Selasky 
434512515907SHans Petter Selasky 	ib_ah_attr->dlid	  = be16_to_cpu(path->rlid);
434612515907SHans Petter Selasky 	ib_ah_attr->src_path_bits = path->grh_mlid & 0x7f;
434712515907SHans Petter Selasky 	ib_ah_attr->static_rate   = path->static_rate ? path->static_rate - 5 : 0;
434812515907SHans Petter Selasky 	ib_ah_attr->ah_flags      = (path->grh_mlid & (1 << 7)) ? IB_AH_GRH : 0;
434912515907SHans Petter Selasky 	if (ib_ah_attr->ah_flags) {
435012515907SHans Petter Selasky 		ib_ah_attr->grh.sgid_index = path->mgid_index;
435112515907SHans Petter Selasky 		ib_ah_attr->grh.hop_limit  = path->hop_limit;
435212515907SHans Petter Selasky 		ib_ah_attr->grh.traffic_class =
435312515907SHans Petter Selasky 			(be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff;
435412515907SHans Petter Selasky 		ib_ah_attr->grh.flow_label =
435512515907SHans Petter Selasky 			be32_to_cpu(path->tclass_flowlabel) & 0xfffff;
435612515907SHans Petter Selasky 		memcpy(ib_ah_attr->grh.dgid.raw,
435712515907SHans Petter Selasky 		       path->rgid, sizeof(ib_ah_attr->grh.dgid.raw));
435812515907SHans Petter Selasky 	}
435912515907SHans Petter Selasky }
436012515907SHans Petter Selasky 
query_raw_packet_qp_sq_state(struct mlx5_ib_dev * dev,struct mlx5_ib_sq * sq,u8 * sq_state)43618e6e287fSHans Petter Selasky static int query_raw_packet_qp_sq_state(struct mlx5_ib_dev *dev,
43628e6e287fSHans Petter Selasky 					struct mlx5_ib_sq *sq,
43638e6e287fSHans Petter Selasky 					u8 *sq_state)
436412515907SHans Petter Selasky {
43658e6e287fSHans Petter Selasky 	void *out;
43668e6e287fSHans Petter Selasky 	void *sqc;
43678e6e287fSHans Petter Selasky 	int inlen;
43688e6e287fSHans Petter Selasky 	int err;
43698e6e287fSHans Petter Selasky 
43708e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(query_sq_out);
43718e6e287fSHans Petter Selasky 	out = mlx5_vzalloc(inlen);
43728e6e287fSHans Petter Selasky 	if (!out)
43738e6e287fSHans Petter Selasky 		return -ENOMEM;
43748e6e287fSHans Petter Selasky 
43758e6e287fSHans Petter Selasky 	err = mlx5_core_query_sq(dev->mdev, sq->base.mqp.qpn, out);
43768e6e287fSHans Petter Selasky 	if (err)
43778e6e287fSHans Petter Selasky 		goto out;
43788e6e287fSHans Petter Selasky 
43798e6e287fSHans Petter Selasky 	sqc = MLX5_ADDR_OF(query_sq_out, out, sq_context);
43808e6e287fSHans Petter Selasky 	*sq_state = MLX5_GET(sqc, sqc, state);
43818e6e287fSHans Petter Selasky 	sq->state = *sq_state;
43828e6e287fSHans Petter Selasky 
43838e6e287fSHans Petter Selasky out:
43848e6e287fSHans Petter Selasky 	kvfree(out);
43858e6e287fSHans Petter Selasky 	return err;
43868e6e287fSHans Petter Selasky }
43878e6e287fSHans Petter Selasky 
query_raw_packet_qp_rq_state(struct mlx5_ib_dev * dev,struct mlx5_ib_rq * rq,u8 * rq_state)43888e6e287fSHans Petter Selasky static int query_raw_packet_qp_rq_state(struct mlx5_ib_dev *dev,
43898e6e287fSHans Petter Selasky 					struct mlx5_ib_rq *rq,
43908e6e287fSHans Petter Selasky 					u8 *rq_state)
43918e6e287fSHans Petter Selasky {
43928e6e287fSHans Petter Selasky 	void *out;
43938e6e287fSHans Petter Selasky 	void *rqc;
43948e6e287fSHans Petter Selasky 	int inlen;
43958e6e287fSHans Petter Selasky 	int err;
43968e6e287fSHans Petter Selasky 
43978e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(query_rq_out);
43988e6e287fSHans Petter Selasky 	out = mlx5_vzalloc(inlen);
43998e6e287fSHans Petter Selasky 	if (!out)
44008e6e287fSHans Petter Selasky 		return -ENOMEM;
44018e6e287fSHans Petter Selasky 
44028e6e287fSHans Petter Selasky 	err = mlx5_core_query_rq(dev->mdev, rq->base.mqp.qpn, out);
44038e6e287fSHans Petter Selasky 	if (err)
44048e6e287fSHans Petter Selasky 		goto out;
44058e6e287fSHans Petter Selasky 
44068e6e287fSHans Petter Selasky 	rqc = MLX5_ADDR_OF(query_rq_out, out, rq_context);
44078e6e287fSHans Petter Selasky 	*rq_state = MLX5_GET(rqc, rqc, state);
44088e6e287fSHans Petter Selasky 	rq->state = *rq_state;
44098e6e287fSHans Petter Selasky 
44108e6e287fSHans Petter Selasky out:
44118e6e287fSHans Petter Selasky 	kvfree(out);
44128e6e287fSHans Petter Selasky 	return err;
44138e6e287fSHans Petter Selasky }
44148e6e287fSHans Petter Selasky 
sqrq_state_to_qp_state(u8 sq_state,u8 rq_state,struct mlx5_ib_qp * qp,u8 * qp_state)44158e6e287fSHans Petter Selasky static int sqrq_state_to_qp_state(u8 sq_state, u8 rq_state,
44168e6e287fSHans Petter Selasky 				  struct mlx5_ib_qp *qp, u8 *qp_state)
44178e6e287fSHans Petter Selasky {
44188e6e287fSHans Petter Selasky 	static const u8 sqrq_trans[MLX5_RQ_NUM_STATE][MLX5_SQ_NUM_STATE] = {
44198e6e287fSHans Petter Selasky 		[MLX5_RQC_STATE_RST] = {
44208e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_RST]	= IB_QPS_RESET,
44218e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_RDY]	= MLX5_QP_STATE_BAD,
44228e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_ERR]	= MLX5_QP_STATE_BAD,
44238e6e287fSHans Petter Selasky 			[MLX5_SQ_STATE_NA]	= IB_QPS_RESET,
44248e6e287fSHans Petter Selasky 		},
44258e6e287fSHans Petter Selasky 		[MLX5_RQC_STATE_RDY] = {
44268e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_RST]	= MLX5_QP_STATE_BAD,
44278e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_RDY]	= MLX5_QP_STATE,
44288e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_ERR]	= IB_QPS_SQE,
44298e6e287fSHans Petter Selasky 			[MLX5_SQ_STATE_NA]	= MLX5_QP_STATE,
44308e6e287fSHans Petter Selasky 		},
44318e6e287fSHans Petter Selasky 		[MLX5_RQC_STATE_ERR] = {
44328e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_RST]    = MLX5_QP_STATE_BAD,
44338e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_RDY]	= MLX5_QP_STATE_BAD,
44348e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_ERR]	= IB_QPS_ERR,
44358e6e287fSHans Petter Selasky 			[MLX5_SQ_STATE_NA]	= IB_QPS_ERR,
44368e6e287fSHans Petter Selasky 		},
44378e6e287fSHans Petter Selasky 		[MLX5_RQ_STATE_NA] = {
44388e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_RST]    = IB_QPS_RESET,
44398e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_RDY]	= MLX5_QP_STATE,
44408e6e287fSHans Petter Selasky 			[MLX5_SQC_STATE_ERR]	= MLX5_QP_STATE,
44418e6e287fSHans Petter Selasky 			[MLX5_SQ_STATE_NA]	= MLX5_QP_STATE_BAD,
44428e6e287fSHans Petter Selasky 		},
44438e6e287fSHans Petter Selasky 	};
44448e6e287fSHans Petter Selasky 
44458e6e287fSHans Petter Selasky 	*qp_state = sqrq_trans[rq_state][sq_state];
44468e6e287fSHans Petter Selasky 
44478e6e287fSHans Petter Selasky 	if (*qp_state == MLX5_QP_STATE_BAD) {
44488e6e287fSHans Petter Selasky 		WARN(1, "Buggy Raw Packet QP state, SQ 0x%x state: 0x%x, RQ 0x%x state: 0x%x",
44498e6e287fSHans Petter Selasky 		     qp->raw_packet_qp.sq.base.mqp.qpn, sq_state,
44508e6e287fSHans Petter Selasky 		     qp->raw_packet_qp.rq.base.mqp.qpn, rq_state);
44518e6e287fSHans Petter Selasky 		return -EINVAL;
44528e6e287fSHans Petter Selasky 	}
44538e6e287fSHans Petter Selasky 
44548e6e287fSHans Petter Selasky 	if (*qp_state == MLX5_QP_STATE)
44558e6e287fSHans Petter Selasky 		*qp_state = qp->state;
44568e6e287fSHans Petter Selasky 
44578e6e287fSHans Petter Selasky 	return 0;
44588e6e287fSHans Petter Selasky }
44598e6e287fSHans Petter Selasky 
query_raw_packet_qp_state(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,u8 * raw_packet_qp_state)44608e6e287fSHans Petter Selasky static int query_raw_packet_qp_state(struct mlx5_ib_dev *dev,
44618e6e287fSHans Petter Selasky 				     struct mlx5_ib_qp *qp,
44628e6e287fSHans Petter Selasky 				     u8 *raw_packet_qp_state)
44638e6e287fSHans Petter Selasky {
44648e6e287fSHans Petter Selasky 	struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
44658e6e287fSHans Petter Selasky 	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
44668e6e287fSHans Petter Selasky 	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
44678e6e287fSHans Petter Selasky 	int err;
44688e6e287fSHans Petter Selasky 	u8 sq_state = MLX5_SQ_STATE_NA;
44698e6e287fSHans Petter Selasky 	u8 rq_state = MLX5_RQ_STATE_NA;
44708e6e287fSHans Petter Selasky 
44718e6e287fSHans Petter Selasky 	if (qp->sq.wqe_cnt) {
44728e6e287fSHans Petter Selasky 		err = query_raw_packet_qp_sq_state(dev, sq, &sq_state);
44738e6e287fSHans Petter Selasky 		if (err)
44748e6e287fSHans Petter Selasky 			return err;
44758e6e287fSHans Petter Selasky 	}
44768e6e287fSHans Petter Selasky 
44778e6e287fSHans Petter Selasky 	if (qp->rq.wqe_cnt) {
44788e6e287fSHans Petter Selasky 		err = query_raw_packet_qp_rq_state(dev, rq, &rq_state);
44798e6e287fSHans Petter Selasky 		if (err)
44808e6e287fSHans Petter Selasky 			return err;
44818e6e287fSHans Petter Selasky 	}
44828e6e287fSHans Petter Selasky 
44838e6e287fSHans Petter Selasky 	return sqrq_state_to_qp_state(sq_state, rq_state, qp,
44848e6e287fSHans Petter Selasky 				      raw_packet_qp_state);
44858e6e287fSHans Petter Selasky }
44868e6e287fSHans Petter Selasky 
query_qp_attr(struct mlx5_ib_dev * dev,struct mlx5_ib_qp * qp,struct ib_qp_attr * qp_attr)44878e6e287fSHans Petter Selasky static int query_qp_attr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
44888e6e287fSHans Petter Selasky 			 struct ib_qp_attr *qp_attr)
44898e6e287fSHans Petter Selasky {
44908e6e287fSHans Petter Selasky 	int outlen = MLX5_ST_SZ_BYTES(query_qp_out);
449112515907SHans Petter Selasky 	struct mlx5_qp_context *context;
449212515907SHans Petter Selasky 	int mlx5_state;
44938e6e287fSHans Petter Selasky 	u32 *outb;
449412515907SHans Petter Selasky 	int err = 0;
449512515907SHans Petter Selasky 
44968e6e287fSHans Petter Selasky 	outb = kzalloc(outlen, GFP_KERNEL);
44978e6e287fSHans Petter Selasky 	if (!outb)
44988e6e287fSHans Petter Selasky 		return -ENOMEM;
449912515907SHans Petter Selasky 
4500788333d9SHans Petter Selasky 	err = mlx5_core_qp_query(dev->mdev, &qp->trans_qp.base.mqp, outb,
45018e6e287fSHans Petter Selasky 				 outlen);
45028e6e287fSHans Petter Selasky 	if (err)
450312515907SHans Petter Selasky 		goto out;
45048e6e287fSHans Petter Selasky 
45058e6e287fSHans Petter Selasky 	/* FIXME: use MLX5_GET rather than mlx5_qp_context manual struct */
45068e6e287fSHans Petter Selasky 	context = (struct mlx5_qp_context *)MLX5_ADDR_OF(query_qp_out, outb, qpc);
450712515907SHans Petter Selasky 
450812515907SHans Petter Selasky 	mlx5_state = be32_to_cpu(context->flags) >> 28;
450912515907SHans Petter Selasky 
451012515907SHans Petter Selasky 	qp->state		     = to_ib_qp_state(mlx5_state);
451112515907SHans Petter Selasky 	qp_attr->path_mtu	     = context->mtu_msgmax >> 5;
451212515907SHans Petter Selasky 	qp_attr->path_mig_state	     =
451312515907SHans Petter Selasky 		to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3);
451412515907SHans Petter Selasky 	qp_attr->qkey		     = be32_to_cpu(context->qkey);
451512515907SHans Petter Selasky 	qp_attr->rq_psn		     = be32_to_cpu(context->rnr_nextrecvpsn) & 0xffffff;
451612515907SHans Petter Selasky 	qp_attr->sq_psn		     = be32_to_cpu(context->next_send_psn) & 0xffffff;
451712515907SHans Petter Selasky 	qp_attr->dest_qp_num	     = be32_to_cpu(context->log_pg_sz_remote_qpn) & 0xffffff;
451812515907SHans Petter Selasky 	qp_attr->qp_access_flags     =
451912515907SHans Petter Selasky 		to_ib_qp_access_flags(be32_to_cpu(context->params2));
452012515907SHans Petter Selasky 
452112515907SHans Petter Selasky 	if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) {
452212515907SHans Petter Selasky 		to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
452312515907SHans Petter Selasky 		to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path);
45248e6e287fSHans Petter Selasky 		qp_attr->alt_pkey_index =
45258e6e287fSHans Petter Selasky 			be16_to_cpu(context->alt_path.pkey_index);
452612515907SHans Petter Selasky 		qp_attr->alt_port_num	= qp_attr->alt_ah_attr.port_num;
452712515907SHans Petter Selasky 	}
452812515907SHans Petter Selasky 
452912515907SHans Petter Selasky 	qp_attr->pkey_index = be16_to_cpu(context->pri_path.pkey_index);
453012515907SHans Petter Selasky 	qp_attr->port_num = context->pri_path.port;
453112515907SHans Petter Selasky 
453212515907SHans Petter Selasky 	/* qp_attr->en_sqd_async_notify is only applicable in modify qp */
453312515907SHans Petter Selasky 	qp_attr->sq_draining = mlx5_state == MLX5_QP_STATE_SQ_DRAINING;
453412515907SHans Petter Selasky 
453512515907SHans Petter Selasky 	qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context->params1) >> 21) & 0x7);
453612515907SHans Petter Selasky 
453712515907SHans Petter Selasky 	qp_attr->max_dest_rd_atomic =
453812515907SHans Petter Selasky 		1 << ((be32_to_cpu(context->params2) >> 21) & 0x7);
453912515907SHans Petter Selasky 	qp_attr->min_rnr_timer	    =
454012515907SHans Petter Selasky 		(be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f;
454112515907SHans Petter Selasky 	qp_attr->timeout	    = context->pri_path.ackto_lt >> 3;
454212515907SHans Petter Selasky 	qp_attr->retry_cnt	    = (be32_to_cpu(context->params1) >> 16) & 0x7;
454312515907SHans Petter Selasky 	qp_attr->rnr_retry	    = (be32_to_cpu(context->params1) >> 13) & 0x7;
454412515907SHans Petter Selasky 	qp_attr->alt_timeout	    = context->alt_path.ackto_lt >> 3;
454512515907SHans Petter Selasky 
45468e6e287fSHans Petter Selasky out:
454712515907SHans Petter Selasky 	kfree(outb);
45488e6e287fSHans Petter Selasky 	return err;
45498e6e287fSHans Petter Selasky }
45508e6e287fSHans Petter Selasky 
mlx5_ib_query_qp(struct ib_qp * ibqp,struct ib_qp_attr * qp_attr,int qp_attr_mask,struct ib_qp_init_attr * qp_init_attr)45518e6e287fSHans Petter Selasky int mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
45528e6e287fSHans Petter Selasky 		     int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
45538e6e287fSHans Petter Selasky {
45548e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
45558e6e287fSHans Petter Selasky 	struct mlx5_ib_qp *qp = to_mqp(ibqp);
45568e6e287fSHans Petter Selasky 	int err = 0;
45578e6e287fSHans Petter Selasky 	u8 raw_packet_qp_state;
45588e6e287fSHans Petter Selasky 
45598e6e287fSHans Petter Selasky 	if (ibqp->rwq_ind_tbl)
45608e6e287fSHans Petter Selasky 		return -ENOSYS;
45618e6e287fSHans Petter Selasky 
45628e6e287fSHans Petter Selasky 	if (unlikely(ibqp->qp_type == IB_QPT_GSI))
45638e6e287fSHans Petter Selasky 		return mlx5_ib_gsi_query_qp(ibqp, qp_attr, qp_attr_mask,
45648e6e287fSHans Petter Selasky 					    qp_init_attr);
45658e6e287fSHans Petter Selasky 
45668e6e287fSHans Petter Selasky #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
45678e6e287fSHans Petter Selasky 	/*
45688e6e287fSHans Petter Selasky 	 * Wait for any outstanding page faults, in case the user frees memory
45698e6e287fSHans Petter Selasky 	 * based upon this query's result.
45708e6e287fSHans Petter Selasky 	 */
45718e6e287fSHans Petter Selasky 	flush_workqueue(mlx5_ib_page_fault_wq);
45728e6e287fSHans Petter Selasky #endif
45738e6e287fSHans Petter Selasky 
45748e6e287fSHans Petter Selasky 	mutex_lock(&qp->mutex);
45758e6e287fSHans Petter Selasky 
45768e6e287fSHans Petter Selasky 	if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) {
45778e6e287fSHans Petter Selasky 		err = query_raw_packet_qp_state(dev, qp, &raw_packet_qp_state);
45788e6e287fSHans Petter Selasky 		if (err)
45798e6e287fSHans Petter Selasky 			goto out;
45808e6e287fSHans Petter Selasky 		qp->state = raw_packet_qp_state;
45818e6e287fSHans Petter Selasky 		qp_attr->port_num = 1;
45828e6e287fSHans Petter Selasky 	} else {
45838e6e287fSHans Petter Selasky 		err = query_qp_attr(dev, qp, qp_attr);
45848e6e287fSHans Petter Selasky 		if (err)
45858e6e287fSHans Petter Selasky 			goto out;
458612515907SHans Petter Selasky 	}
458712515907SHans Petter Selasky 
458812515907SHans Petter Selasky 	qp_attr->qp_state	     = qp->state;
458912515907SHans Petter Selasky 	qp_attr->cur_qp_state	     = qp_attr->qp_state;
459012515907SHans Petter Selasky 	qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
459112515907SHans Petter Selasky 	qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
459212515907SHans Petter Selasky 
459312515907SHans Petter Selasky 	if (!ibqp->uobject) {
459412515907SHans Petter Selasky 		qp_attr->cap.max_send_wr  = qp->sq.max_post;
459512515907SHans Petter Selasky 		qp_attr->cap.max_send_sge = qp->sq.max_gs;
459612515907SHans Petter Selasky 		qp_init_attr->qp_context = ibqp->qp_context;
459712515907SHans Petter Selasky 	} else {
459812515907SHans Petter Selasky 		qp_attr->cap.max_send_wr  = 0;
459912515907SHans Petter Selasky 		qp_attr->cap.max_send_sge = 0;
460012515907SHans Petter Selasky 	}
460112515907SHans Petter Selasky 
460212515907SHans Petter Selasky 	qp_init_attr->qp_type = ibqp->qp_type;
460312515907SHans Petter Selasky 	qp_init_attr->recv_cq = ibqp->recv_cq;
460412515907SHans Petter Selasky 	qp_init_attr->send_cq = ibqp->send_cq;
460512515907SHans Petter Selasky 	qp_init_attr->srq = ibqp->srq;
460612515907SHans Petter Selasky 	qp_attr->cap.max_inline_data = qp->max_inline_data;
460712515907SHans Petter Selasky 
460812515907SHans Petter Selasky 	qp_init_attr->cap	     = qp_attr->cap;
460912515907SHans Petter Selasky 
461012515907SHans Petter Selasky 	qp_init_attr->create_flags = 0;
461112515907SHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK)
461212515907SHans Petter Selasky 		qp_init_attr->create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK;
461312515907SHans Petter Selasky 
46148e6e287fSHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_CROSS_CHANNEL)
46158e6e287fSHans Petter Selasky 		qp_init_attr->create_flags |= IB_QP_CREATE_CROSS_CHANNEL;
46168e6e287fSHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_MANAGED_SEND)
46178e6e287fSHans Petter Selasky 		qp_init_attr->create_flags |= IB_QP_CREATE_MANAGED_SEND;
46188e6e287fSHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_MANAGED_RECV)
46198e6e287fSHans Petter Selasky 		qp_init_attr->create_flags |= IB_QP_CREATE_MANAGED_RECV;
46208e6e287fSHans Petter Selasky 	if (qp->flags & MLX5_IB_QP_SQPN_QP1)
4621f8f5b459SHans Petter Selasky 		qp_init_attr->create_flags |= MLX5_IB_QP_CREATE_SQPN_QP1;
46228e6e287fSHans Petter Selasky 
462312515907SHans Petter Selasky 	qp_init_attr->sq_sig_type = qp->sq_signal_bits & MLX5_WQE_CTRL_CQ_UPDATE ?
462412515907SHans Petter Selasky 		IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
462512515907SHans Petter Selasky 
462612515907SHans Petter Selasky out:
462712515907SHans Petter Selasky 	mutex_unlock(&qp->mutex);
462812515907SHans Petter Selasky 	return err;
462912515907SHans Petter Selasky }
463012515907SHans Petter Selasky 
mlx5_ib_alloc_xrcd(struct ib_device * ibdev,struct ib_udata * udata)463112515907SHans Petter Selasky struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev,
463212515907SHans Petter Selasky 				   struct ib_udata *udata)
463312515907SHans Petter Selasky {
463412515907SHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(ibdev);
463512515907SHans Petter Selasky 	struct mlx5_ib_xrcd *xrcd;
463612515907SHans Petter Selasky 	int err;
463712515907SHans Petter Selasky 
463812515907SHans Petter Selasky 	if (!MLX5_CAP_GEN(dev->mdev, xrc))
463912515907SHans Petter Selasky 		return ERR_PTR(-ENOSYS);
464012515907SHans Petter Selasky 
464112515907SHans Petter Selasky 	xrcd = kmalloc(sizeof(*xrcd), GFP_KERNEL);
464212515907SHans Petter Selasky 	if (!xrcd)
464312515907SHans Petter Selasky 		return ERR_PTR(-ENOMEM);
464412515907SHans Petter Selasky 
464512515907SHans Petter Selasky 	err = mlx5_core_xrcd_alloc(dev->mdev, &xrcd->xrcdn);
464612515907SHans Petter Selasky 	if (err) {
464712515907SHans Petter Selasky 		kfree(xrcd);
464812515907SHans Petter Selasky 		return ERR_PTR(-ENOMEM);
464912515907SHans Petter Selasky 	}
465012515907SHans Petter Selasky 
465112515907SHans Petter Selasky 	return &xrcd->ibxrcd;
465212515907SHans Petter Selasky }
465312515907SHans Petter Selasky 
mlx5_ib_dealloc_xrcd(struct ib_xrcd * xrcd,struct ib_udata * udata)4654b633e08cSHans Petter Selasky int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd, struct ib_udata *udata)
465512515907SHans Petter Selasky {
465612515907SHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(xrcd->device);
465712515907SHans Petter Selasky 	u32 xrcdn = to_mxrcd(xrcd)->xrcdn;
465812515907SHans Petter Selasky 	int err;
465912515907SHans Petter Selasky 
466012515907SHans Petter Selasky 	err = mlx5_core_xrcd_dealloc(dev->mdev, xrcdn);
4661b633e08cSHans Petter Selasky 	if (err)
466212515907SHans Petter Selasky 		mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn);
466312515907SHans Petter Selasky 
466412515907SHans Petter Selasky 	kfree(xrcd);
466512515907SHans Petter Selasky 	return 0;
466612515907SHans Petter Selasky }
46678e6e287fSHans Petter Selasky 
mlx5_ib_wq_event(struct mlx5_core_qp * core_qp,int type)46688e6e287fSHans Petter Selasky static void mlx5_ib_wq_event(struct mlx5_core_qp *core_qp, int type)
46698e6e287fSHans Petter Selasky {
46708e6e287fSHans Petter Selasky 	struct mlx5_ib_rwq *rwq = to_mibrwq(core_qp);
46718e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(rwq->ibwq.device);
46728e6e287fSHans Petter Selasky 	struct ib_event event;
46738e6e287fSHans Petter Selasky 
46748e6e287fSHans Petter Selasky 	if (rwq->ibwq.event_handler) {
46758e6e287fSHans Petter Selasky 		event.device     = rwq->ibwq.device;
46768e6e287fSHans Petter Selasky 		event.element.wq = &rwq->ibwq;
46778e6e287fSHans Petter Selasky 		switch (type) {
46788e6e287fSHans Petter Selasky 		case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
46798e6e287fSHans Petter Selasky 			event.event = IB_EVENT_WQ_FATAL;
46808e6e287fSHans Petter Selasky 			break;
46818e6e287fSHans Petter Selasky 		default:
46828e6e287fSHans Petter Selasky 			mlx5_ib_warn(dev, "Unexpected event type %d on WQ %06x\n", type, core_qp->qpn);
46838e6e287fSHans Petter Selasky 			return;
46848e6e287fSHans Petter Selasky 		}
46858e6e287fSHans Petter Selasky 
46868e6e287fSHans Petter Selasky 		rwq->ibwq.event_handler(&event, rwq->ibwq.wq_context);
46878e6e287fSHans Petter Selasky 	}
46888e6e287fSHans Petter Selasky }
46898e6e287fSHans Petter Selasky 
create_rq(struct mlx5_ib_rwq * rwq,struct ib_pd * pd,struct ib_wq_init_attr * init_attr)46908e6e287fSHans Petter Selasky static int  create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd,
46918e6e287fSHans Petter Selasky 		      struct ib_wq_init_attr *init_attr)
46928e6e287fSHans Petter Selasky {
46938e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev;
46948e6e287fSHans Petter Selasky 	__be64 *rq_pas0;
46958e6e287fSHans Petter Selasky 	void *in;
46968e6e287fSHans Petter Selasky 	void *rqc;
46978e6e287fSHans Petter Selasky 	void *wq;
46988e6e287fSHans Petter Selasky 	int inlen;
46998e6e287fSHans Petter Selasky 	int err;
47008e6e287fSHans Petter Selasky 
47018e6e287fSHans Petter Selasky 	dev = to_mdev(pd->device);
47028e6e287fSHans Petter Selasky 
47038e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(create_rq_in) + sizeof(u64) * rwq->rq_num_pas;
47048e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
47058e6e287fSHans Petter Selasky 	if (!in)
47068e6e287fSHans Petter Selasky 		return -ENOMEM;
47078e6e287fSHans Petter Selasky 
4708b633e08cSHans Petter Selasky 	MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid);
47098e6e287fSHans Petter Selasky 	rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
47108e6e287fSHans Petter Selasky 	MLX5_SET(rqc,  rqc, mem_rq_type,
47118e6e287fSHans Petter Selasky 		 MLX5_RQC_RQ_TYPE_MEMORY_RQ_INLINE);
47128e6e287fSHans Petter Selasky 	MLX5_SET(rqc, rqc, user_index, rwq->user_index);
47138e6e287fSHans Petter Selasky 	MLX5_SET(rqc,  rqc, cqn, to_mcq(init_attr->cq)->mcq.cqn);
47148e6e287fSHans Petter Selasky 	MLX5_SET(rqc,  rqc, state, MLX5_RQC_STATE_RST);
47158e6e287fSHans Petter Selasky 	MLX5_SET(rqc,  rqc, flush_in_error_en, 1);
47168e6e287fSHans Petter Selasky 	wq = MLX5_ADDR_OF(rqc, rqc, wq);
47178e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
47188e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN);
47198e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, log_wq_stride, rwq->log_rq_stride);
47208e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, log_wq_sz, rwq->log_rq_size);
47218e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, pd, to_mpd(pd)->pdn);
47228e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, page_offset, rwq->rq_page_offset);
47238e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, log_wq_pg_sz, rwq->log_page_size);
47248e6e287fSHans Petter Selasky 	MLX5_SET(wq, wq, wq_signature, rwq->wq_sig);
47258e6e287fSHans Petter Selasky 	MLX5_SET64(wq, wq, dbr_addr, rwq->db.dma);
47268e6e287fSHans Petter Selasky 	rq_pas0 = (__be64 *)MLX5_ADDR_OF(wq, wq, pas);
47278e6e287fSHans Petter Selasky 	mlx5_ib_populate_pas(dev, rwq->umem, rwq->page_shift, rq_pas0, 0);
47288e6e287fSHans Petter Selasky 	err = mlx5_core_create_rq_tracked(dev->mdev, in, inlen, &rwq->core_qp);
47298e6e287fSHans Petter Selasky 	kvfree(in);
47308e6e287fSHans Petter Selasky 	return err;
47318e6e287fSHans Petter Selasky }
47328e6e287fSHans Petter Selasky 
set_user_rq_size(struct mlx5_ib_dev * dev,struct ib_wq_init_attr * wq_init_attr,struct mlx5_ib_create_wq * ucmd,struct mlx5_ib_rwq * rwq)47338e6e287fSHans Petter Selasky static int set_user_rq_size(struct mlx5_ib_dev *dev,
47348e6e287fSHans Petter Selasky 			    struct ib_wq_init_attr *wq_init_attr,
47358e6e287fSHans Petter Selasky 			    struct mlx5_ib_create_wq *ucmd,
47368e6e287fSHans Petter Selasky 			    struct mlx5_ib_rwq *rwq)
47378e6e287fSHans Petter Selasky {
47388e6e287fSHans Petter Selasky 	/* Sanity check RQ size before proceeding */
47398e6e287fSHans Petter Selasky 	if (wq_init_attr->max_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_wq_sz)))
47408e6e287fSHans Petter Selasky 		return -EINVAL;
47418e6e287fSHans Petter Selasky 
47428e6e287fSHans Petter Selasky 	if (!ucmd->rq_wqe_count)
47438e6e287fSHans Petter Selasky 		return -EINVAL;
47448e6e287fSHans Petter Selasky 
47458e6e287fSHans Petter Selasky 	rwq->wqe_count = ucmd->rq_wqe_count;
47468e6e287fSHans Petter Selasky 	rwq->wqe_shift = ucmd->rq_wqe_shift;
47478e6e287fSHans Petter Selasky 	rwq->buf_size = (rwq->wqe_count << rwq->wqe_shift);
47488e6e287fSHans Petter Selasky 	rwq->log_rq_stride = rwq->wqe_shift;
47498e6e287fSHans Petter Selasky 	rwq->log_rq_size = ilog2(rwq->wqe_count);
47508e6e287fSHans Petter Selasky 	return 0;
47518e6e287fSHans Petter Selasky }
47528e6e287fSHans Petter Selasky 
prepare_user_rq(struct ib_pd * pd,struct ib_wq_init_attr * init_attr,struct ib_udata * udata,struct mlx5_ib_rwq * rwq)47538e6e287fSHans Petter Selasky static int prepare_user_rq(struct ib_pd *pd,
47548e6e287fSHans Petter Selasky 			   struct ib_wq_init_attr *init_attr,
47558e6e287fSHans Petter Selasky 			   struct ib_udata *udata,
47568e6e287fSHans Petter Selasky 			   struct mlx5_ib_rwq *rwq)
47578e6e287fSHans Petter Selasky {
47588e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(pd->device);
47598e6e287fSHans Petter Selasky 	struct mlx5_ib_create_wq ucmd = {};
47608e6e287fSHans Petter Selasky 	int err;
47618e6e287fSHans Petter Selasky 	size_t required_cmd_sz;
47628e6e287fSHans Petter Selasky 
47638e6e287fSHans Petter Selasky 	required_cmd_sz = offsetof(typeof(ucmd), reserved) + sizeof(ucmd.reserved);
47648e6e287fSHans Petter Selasky 	if (udata->inlen < required_cmd_sz) {
47658e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid inlen\n");
47668e6e287fSHans Petter Selasky 		return -EINVAL;
47678e6e287fSHans Petter Selasky 	}
47688e6e287fSHans Petter Selasky 
47698e6e287fSHans Petter Selasky 	if (udata->inlen > sizeof(ucmd) &&
47708e6e287fSHans Petter Selasky 	    !ib_is_udata_cleared(udata, sizeof(ucmd),
47718e6e287fSHans Petter Selasky 				 udata->inlen - sizeof(ucmd))) {
47728e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "inlen is not supported\n");
47738e6e287fSHans Petter Selasky 		return -EOPNOTSUPP;
47748e6e287fSHans Petter Selasky 	}
47758e6e287fSHans Petter Selasky 
47768e6e287fSHans Petter Selasky 	if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) {
47778e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "copy failed\n");
47788e6e287fSHans Petter Selasky 		return -EFAULT;
47798e6e287fSHans Petter Selasky 	}
47808e6e287fSHans Petter Selasky 
47818e6e287fSHans Petter Selasky 	if (ucmd.comp_mask) {
47828e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid comp mask\n");
47838e6e287fSHans Petter Selasky 		return -EOPNOTSUPP;
47848e6e287fSHans Petter Selasky 	}
47858e6e287fSHans Petter Selasky 
47868e6e287fSHans Petter Selasky 	if (ucmd.reserved) {
47878e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "invalid reserved\n");
47888e6e287fSHans Petter Selasky 		return -EOPNOTSUPP;
47898e6e287fSHans Petter Selasky 	}
47908e6e287fSHans Petter Selasky 
47918e6e287fSHans Petter Selasky 	err = set_user_rq_size(dev, init_attr, &ucmd, rwq);
47928e6e287fSHans Petter Selasky 	if (err) {
47938e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "err %d\n", err);
47948e6e287fSHans Petter Selasky 		return err;
47958e6e287fSHans Petter Selasky 	}
47968e6e287fSHans Petter Selasky 
47978e6e287fSHans Petter Selasky 	err = create_user_rq(dev, pd, rwq, &ucmd);
47988e6e287fSHans Petter Selasky 	if (err) {
47998e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "err %d\n", err);
48008e6e287fSHans Petter Selasky 		if (err)
48018e6e287fSHans Petter Selasky 			return err;
48028e6e287fSHans Petter Selasky 	}
48038e6e287fSHans Petter Selasky 
48048e6e287fSHans Petter Selasky 	rwq->user_index = ucmd.user_index;
48058e6e287fSHans Petter Selasky 	return 0;
48068e6e287fSHans Petter Selasky }
48078e6e287fSHans Petter Selasky 
mlx5_ib_create_wq(struct ib_pd * pd,struct ib_wq_init_attr * init_attr,struct ib_udata * udata)48088e6e287fSHans Petter Selasky struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
48098e6e287fSHans Petter Selasky 				struct ib_wq_init_attr *init_attr,
48108e6e287fSHans Petter Selasky 				struct ib_udata *udata)
48118e6e287fSHans Petter Selasky {
48128e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev;
48138e6e287fSHans Petter Selasky 	struct mlx5_ib_rwq *rwq;
48148e6e287fSHans Petter Selasky 	struct mlx5_ib_create_wq_resp resp = {};
48158e6e287fSHans Petter Selasky 	size_t min_resp_len;
48168e6e287fSHans Petter Selasky 	int err;
48178e6e287fSHans Petter Selasky 
48188e6e287fSHans Petter Selasky 	if (!udata)
48198e6e287fSHans Petter Selasky 		return ERR_PTR(-ENOSYS);
48208e6e287fSHans Petter Selasky 
48218e6e287fSHans Petter Selasky 	min_resp_len = offsetof(typeof(resp), reserved) + sizeof(resp.reserved);
48228e6e287fSHans Petter Selasky 	if (udata->outlen && udata->outlen < min_resp_len)
48238e6e287fSHans Petter Selasky 		return ERR_PTR(-EINVAL);
48248e6e287fSHans Petter Selasky 
48258e6e287fSHans Petter Selasky 	dev = to_mdev(pd->device);
48268e6e287fSHans Petter Selasky 	switch (init_attr->wq_type) {
48278e6e287fSHans Petter Selasky 	case IB_WQT_RQ:
48288e6e287fSHans Petter Selasky 		rwq = kzalloc(sizeof(*rwq), GFP_KERNEL);
48298e6e287fSHans Petter Selasky 		if (!rwq)
48308e6e287fSHans Petter Selasky 			return ERR_PTR(-ENOMEM);
48318e6e287fSHans Petter Selasky 		err = prepare_user_rq(pd, init_attr, udata, rwq);
48328e6e287fSHans Petter Selasky 		if (err)
48338e6e287fSHans Petter Selasky 			goto err;
48348e6e287fSHans Petter Selasky 		err = create_rq(rwq, pd, init_attr);
48358e6e287fSHans Petter Selasky 		if (err)
48368e6e287fSHans Petter Selasky 			goto err_user_rq;
48378e6e287fSHans Petter Selasky 		break;
48388e6e287fSHans Petter Selasky 	default:
48398e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "unsupported wq type %d\n",
48408e6e287fSHans Petter Selasky 			    init_attr->wq_type);
48418e6e287fSHans Petter Selasky 		return ERR_PTR(-EINVAL);
48428e6e287fSHans Petter Selasky 	}
48438e6e287fSHans Petter Selasky 
48448e6e287fSHans Petter Selasky 	rwq->ibwq.wq_num = rwq->core_qp.qpn;
48458e6e287fSHans Petter Selasky 	rwq->ibwq.state = IB_WQS_RESET;
48468e6e287fSHans Petter Selasky 	if (udata->outlen) {
48478e6e287fSHans Petter Selasky 		resp.response_length = offsetof(typeof(resp), response_length) +
48488e6e287fSHans Petter Selasky 				sizeof(resp.response_length);
48498e6e287fSHans Petter Selasky 		err = ib_copy_to_udata(udata, &resp, resp.response_length);
48508e6e287fSHans Petter Selasky 		if (err)
48518e6e287fSHans Petter Selasky 			goto err_copy;
48528e6e287fSHans Petter Selasky 	}
48538e6e287fSHans Petter Selasky 
48548e6e287fSHans Petter Selasky 	rwq->core_qp.event = mlx5_ib_wq_event;
48558e6e287fSHans Petter Selasky 	rwq->ibwq.event_handler = init_attr->event_handler;
48568e6e287fSHans Petter Selasky 	return &rwq->ibwq;
48578e6e287fSHans Petter Selasky 
48588e6e287fSHans Petter Selasky err_copy:
48598e6e287fSHans Petter Selasky 	mlx5_core_destroy_rq_tracked(dev->mdev, &rwq->core_qp);
48608e6e287fSHans Petter Selasky err_user_rq:
4861b633e08cSHans Petter Selasky 	destroy_user_rq(pd, rwq, udata);
48628e6e287fSHans Petter Selasky err:
48638e6e287fSHans Petter Selasky 	kfree(rwq);
48648e6e287fSHans Petter Selasky 	return ERR_PTR(err);
48658e6e287fSHans Petter Selasky }
48668e6e287fSHans Petter Selasky 
mlx5_ib_destroy_wq(struct ib_wq * wq,struct ib_udata * udata)4867b633e08cSHans Petter Selasky void mlx5_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata)
48688e6e287fSHans Petter Selasky {
48698e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(wq->device);
48708e6e287fSHans Petter Selasky 	struct mlx5_ib_rwq *rwq = to_mrwq(wq);
48718e6e287fSHans Petter Selasky 
48728e6e287fSHans Petter Selasky 	mlx5_core_destroy_rq_tracked(dev->mdev, &rwq->core_qp);
4873b633e08cSHans Petter Selasky 	destroy_user_rq(wq->pd, rwq, udata);
48748e6e287fSHans Petter Selasky 	kfree(rwq);
48758e6e287fSHans Petter Selasky }
48768e6e287fSHans Petter Selasky 
mlx5_ib_create_rwq_ind_table(struct ib_device * device,struct ib_rwq_ind_table_init_attr * init_attr,struct ib_udata * udata)48778e6e287fSHans Petter Selasky struct ib_rwq_ind_table *mlx5_ib_create_rwq_ind_table(struct ib_device *device,
48788e6e287fSHans Petter Selasky 						      struct ib_rwq_ind_table_init_attr *init_attr,
48798e6e287fSHans Petter Selasky 						      struct ib_udata *udata)
48808e6e287fSHans Petter Selasky {
48818e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(device);
48828e6e287fSHans Petter Selasky 	struct mlx5_ib_rwq_ind_table *rwq_ind_tbl;
48838e6e287fSHans Petter Selasky 	int sz = 1 << init_attr->log_ind_tbl_size;
48848e6e287fSHans Petter Selasky 	struct mlx5_ib_create_rwq_ind_tbl_resp resp = {};
48858e6e287fSHans Petter Selasky 	size_t min_resp_len;
48868e6e287fSHans Petter Selasky 	int inlen;
48878e6e287fSHans Petter Selasky 	int err;
48888e6e287fSHans Petter Selasky 	int i;
48898e6e287fSHans Petter Selasky 	u32 *in;
48908e6e287fSHans Petter Selasky 	void *rqtc;
48918e6e287fSHans Petter Selasky 
48928e6e287fSHans Petter Selasky 	if (udata->inlen > 0 &&
48938e6e287fSHans Petter Selasky 	    !ib_is_udata_cleared(udata, 0,
48948e6e287fSHans Petter Selasky 				 udata->inlen))
48958e6e287fSHans Petter Selasky 		return ERR_PTR(-EOPNOTSUPP);
48968e6e287fSHans Petter Selasky 
48978e6e287fSHans Petter Selasky 	if (init_attr->log_ind_tbl_size >
48988e6e287fSHans Petter Selasky 	    MLX5_CAP_GEN(dev->mdev, log_max_rqt_size)) {
48998e6e287fSHans Petter Selasky 		mlx5_ib_dbg(dev, "log_ind_tbl_size = %d is bigger than supported = %d\n",
49008e6e287fSHans Petter Selasky 			    init_attr->log_ind_tbl_size,
49018e6e287fSHans Petter Selasky 			    MLX5_CAP_GEN(dev->mdev, log_max_rqt_size));
49028e6e287fSHans Petter Selasky 		return ERR_PTR(-EINVAL);
49038e6e287fSHans Petter Selasky 	}
49048e6e287fSHans Petter Selasky 
49058e6e287fSHans Petter Selasky 	min_resp_len = offsetof(typeof(resp), reserved) + sizeof(resp.reserved);
49068e6e287fSHans Petter Selasky 	if (udata->outlen && udata->outlen < min_resp_len)
49078e6e287fSHans Petter Selasky 		return ERR_PTR(-EINVAL);
49088e6e287fSHans Petter Selasky 
49098e6e287fSHans Petter Selasky 	rwq_ind_tbl = kzalloc(sizeof(*rwq_ind_tbl), GFP_KERNEL);
49108e6e287fSHans Petter Selasky 	if (!rwq_ind_tbl)
49118e6e287fSHans Petter Selasky 		return ERR_PTR(-ENOMEM);
49128e6e287fSHans Petter Selasky 
49138e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz;
49148e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
49158e6e287fSHans Petter Selasky 	if (!in) {
49168e6e287fSHans Petter Selasky 		err = -ENOMEM;
49178e6e287fSHans Petter Selasky 		goto err;
49188e6e287fSHans Petter Selasky 	}
49198e6e287fSHans Petter Selasky 
49208e6e287fSHans Petter Selasky 	rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context);
49218e6e287fSHans Petter Selasky 
49228e6e287fSHans Petter Selasky 	MLX5_SET(rqtc, rqtc, rqt_actual_size, sz);
49238e6e287fSHans Petter Selasky 	MLX5_SET(rqtc, rqtc, rqt_max_size, sz);
49248e6e287fSHans Petter Selasky 
49258e6e287fSHans Petter Selasky 	for (i = 0; i < sz; i++)
49268e6e287fSHans Petter Selasky 		MLX5_SET(rqtc, rqtc, rq_num[i], init_attr->ind_tbl[i]->wq_num);
49278e6e287fSHans Petter Selasky 
4928b633e08cSHans Petter Selasky 	rwq_ind_tbl->uid = to_mpd(init_attr->ind_tbl[0]->pd)->uid;
4929b633e08cSHans Petter Selasky 	MLX5_SET(create_rqt_in, in, uid, rwq_ind_tbl->uid);
4930b633e08cSHans Petter Selasky 
49318e6e287fSHans Petter Selasky 	err = mlx5_core_create_rqt(dev->mdev, in, inlen, &rwq_ind_tbl->rqtn);
49328e6e287fSHans Petter Selasky 	kvfree(in);
49338e6e287fSHans Petter Selasky 
49348e6e287fSHans Petter Selasky 	if (err)
49358e6e287fSHans Petter Selasky 		goto err;
49368e6e287fSHans Petter Selasky 
49378e6e287fSHans Petter Selasky 	rwq_ind_tbl->ib_rwq_ind_tbl.ind_tbl_num = rwq_ind_tbl->rqtn;
49388e6e287fSHans Petter Selasky 	if (udata->outlen) {
49398e6e287fSHans Petter Selasky 		resp.response_length = offsetof(typeof(resp), response_length) +
49408e6e287fSHans Petter Selasky 					sizeof(resp.response_length);
49418e6e287fSHans Petter Selasky 		err = ib_copy_to_udata(udata, &resp, resp.response_length);
49428e6e287fSHans Petter Selasky 		if (err)
49438e6e287fSHans Petter Selasky 			goto err_copy;
49448e6e287fSHans Petter Selasky 	}
49458e6e287fSHans Petter Selasky 
49468e6e287fSHans Petter Selasky 	return &rwq_ind_tbl->ib_rwq_ind_tbl;
49478e6e287fSHans Petter Selasky 
49488e6e287fSHans Petter Selasky err_copy:
4949b633e08cSHans Petter Selasky 	mlx5_core_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid);
49508e6e287fSHans Petter Selasky err:
49518e6e287fSHans Petter Selasky 	kfree(rwq_ind_tbl);
49528e6e287fSHans Petter Selasky 	return ERR_PTR(err);
49538e6e287fSHans Petter Selasky }
49548e6e287fSHans Petter Selasky 
mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table * ib_rwq_ind_tbl)49558e6e287fSHans Petter Selasky int mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_tbl)
49568e6e287fSHans Petter Selasky {
49578e6e287fSHans Petter Selasky 	struct mlx5_ib_rwq_ind_table *rwq_ind_tbl = to_mrwq_ind_table(ib_rwq_ind_tbl);
49588e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(ib_rwq_ind_tbl->device);
49598e6e287fSHans Petter Selasky 
4960b633e08cSHans Petter Selasky 	mlx5_core_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid);
49618e6e287fSHans Petter Selasky 
49628e6e287fSHans Petter Selasky 	kfree(rwq_ind_tbl);
49638e6e287fSHans Petter Selasky 	return 0;
49648e6e287fSHans Petter Selasky }
49658e6e287fSHans Petter Selasky 
mlx5_ib_modify_wq(struct ib_wq * wq,struct ib_wq_attr * wq_attr,u32 wq_attr_mask,struct ib_udata * udata)49668e6e287fSHans Petter Selasky int mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
49678e6e287fSHans Petter Selasky 		      u32 wq_attr_mask, struct ib_udata *udata)
49688e6e287fSHans Petter Selasky {
49698e6e287fSHans Petter Selasky 	struct mlx5_ib_dev *dev = to_mdev(wq->device);
49708e6e287fSHans Petter Selasky 	struct mlx5_ib_rwq *rwq = to_mrwq(wq);
49718e6e287fSHans Petter Selasky 	struct mlx5_ib_modify_wq ucmd = {};
49728e6e287fSHans Petter Selasky 	size_t required_cmd_sz;
49738e6e287fSHans Petter Selasky 	int curr_wq_state;
49748e6e287fSHans Petter Selasky 	int wq_state;
49758e6e287fSHans Petter Selasky 	int inlen;
49768e6e287fSHans Petter Selasky 	int err;
49778e6e287fSHans Petter Selasky 	void *rqc;
49788e6e287fSHans Petter Selasky 	void *in;
49798e6e287fSHans Petter Selasky 
49808e6e287fSHans Petter Selasky 	required_cmd_sz = offsetof(typeof(ucmd), reserved) + sizeof(ucmd.reserved);
49818e6e287fSHans Petter Selasky 	if (udata->inlen < required_cmd_sz)
49828e6e287fSHans Petter Selasky 		return -EINVAL;
49838e6e287fSHans Petter Selasky 
49848e6e287fSHans Petter Selasky 	if (udata->inlen > sizeof(ucmd) &&
49858e6e287fSHans Petter Selasky 	    !ib_is_udata_cleared(udata, sizeof(ucmd),
49868e6e287fSHans Petter Selasky 				 udata->inlen - sizeof(ucmd)))
49878e6e287fSHans Petter Selasky 		return -EOPNOTSUPP;
49888e6e287fSHans Petter Selasky 
49898e6e287fSHans Petter Selasky 	if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen)))
49908e6e287fSHans Petter Selasky 		return -EFAULT;
49918e6e287fSHans Petter Selasky 
49928e6e287fSHans Petter Selasky 	if (ucmd.comp_mask || ucmd.reserved)
49938e6e287fSHans Petter Selasky 		return -EOPNOTSUPP;
49948e6e287fSHans Petter Selasky 
49958e6e287fSHans Petter Selasky 	inlen = MLX5_ST_SZ_BYTES(modify_rq_in);
49968e6e287fSHans Petter Selasky 	in = mlx5_vzalloc(inlen);
49978e6e287fSHans Petter Selasky 	if (!in)
49988e6e287fSHans Petter Selasky 		return -ENOMEM;
49998e6e287fSHans Petter Selasky 
50008e6e287fSHans Petter Selasky 	rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
50018e6e287fSHans Petter Selasky 
50028e6e287fSHans Petter Selasky 	MLX5_SET(modify_rq_in, in, rqn, rwq->core_qp.qpn);
50038e6e287fSHans Petter Selasky 	curr_wq_state = (wq_attr_mask & IB_WQ_CUR_STATE) ?
50048e6e287fSHans Petter Selasky 		wq_attr->curr_wq_state : wq->state;
50058e6e287fSHans Petter Selasky 	wq_state = (wq_attr_mask & IB_WQ_STATE) ?
50068e6e287fSHans Petter Selasky 		wq_attr->wq_state : curr_wq_state;
50078e6e287fSHans Petter Selasky 	if (curr_wq_state == IB_WQS_ERR)
50088e6e287fSHans Petter Selasky 		curr_wq_state = MLX5_RQC_STATE_ERR;
50098e6e287fSHans Petter Selasky 	if (wq_state == IB_WQS_ERR)
50108e6e287fSHans Petter Selasky 		wq_state = MLX5_RQC_STATE_ERR;
50118e6e287fSHans Petter Selasky 	MLX5_SET(modify_rq_in, in, rq_state, curr_wq_state);
5012b633e08cSHans Petter Selasky 	MLX5_SET(modify_rq_in, in, uid, to_mpd(wq->pd)->uid);
50138e6e287fSHans Petter Selasky 	MLX5_SET(rqc, rqc, state, wq_state);
50148e6e287fSHans Petter Selasky 
50158e6e287fSHans Petter Selasky 	err = mlx5_core_modify_rq(dev->mdev, in, inlen);
50168e6e287fSHans Petter Selasky 	kvfree(in);
50178e6e287fSHans Petter Selasky 	if (!err)
50188e6e287fSHans Petter Selasky 		rwq->ibwq.state = (wq_state == MLX5_RQC_STATE_ERR) ? IB_WQS_ERR : wq_state;
50198e6e287fSHans Petter Selasky 
50208e6e287fSHans Petter Selasky 	return err;
50218e6e287fSHans Petter Selasky }
5022