162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This software is available to you under a choice of one of two
662306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
762306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
862306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
962306a36Sopenharmony_ci * OpenIB.org BSD license below:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1262306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1362306a36Sopenharmony_ci *     conditions are met:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1662306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1762306a36Sopenharmony_ci *        disclaimer.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2062306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2162306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2262306a36Sopenharmony_ci *        provided with the distribution.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2562306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2662306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2762306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2862306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2962306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3062306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3162306a36Sopenharmony_ci * SOFTWARE.
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <linux/log2.h>
3562306a36Sopenharmony_ci#include <linux/etherdevice.h>
3662306a36Sopenharmony_ci#include <net/ip.h>
3762306a36Sopenharmony_ci#include <linux/slab.h>
3862306a36Sopenharmony_ci#include <linux/netdevice.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include <rdma/ib_cache.h>
4162306a36Sopenharmony_ci#include <rdma/ib_pack.h>
4262306a36Sopenharmony_ci#include <rdma/ib_addr.h>
4362306a36Sopenharmony_ci#include <rdma/ib_mad.h>
4462306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h>
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#include <linux/mlx4/driver.h>
4762306a36Sopenharmony_ci#include <linux/mlx4/qp.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include "mlx4_ib.h"
5062306a36Sopenharmony_ci#include <rdma/mlx4-abi.h>
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq,
5362306a36Sopenharmony_ci			     struct mlx4_ib_cq *recv_cq);
5462306a36Sopenharmony_cistatic void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq,
5562306a36Sopenharmony_ci			       struct mlx4_ib_cq *recv_cq);
5662306a36Sopenharmony_cistatic int _mlx4_ib_modify_wq(struct ib_wq *ibwq, enum ib_wq_state new_state,
5762306a36Sopenharmony_ci			      struct ib_udata *udata);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cienum {
6062306a36Sopenharmony_ci	MLX4_IB_ACK_REQ_FREQ	= 8,
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cienum {
6462306a36Sopenharmony_ci	MLX4_IB_DEFAULT_SCHED_QUEUE	= 0x83,
6562306a36Sopenharmony_ci	MLX4_IB_DEFAULT_QP0_SCHED_QUEUE	= 0x3f,
6662306a36Sopenharmony_ci	MLX4_IB_LINK_TYPE_IB		= 0,
6762306a36Sopenharmony_ci	MLX4_IB_LINK_TYPE_ETH		= 1
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cienum {
7162306a36Sopenharmony_ci	MLX4_IB_MIN_SQ_STRIDE	= 6,
7262306a36Sopenharmony_ci	MLX4_IB_CACHE_LINE_SIZE	= 64,
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cienum {
7662306a36Sopenharmony_ci	MLX4_RAW_QP_MTU		= 7,
7762306a36Sopenharmony_ci	MLX4_RAW_QP_MSGMAX	= 31,
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#ifndef ETH_ALEN
8162306a36Sopenharmony_ci#define ETH_ALEN        6
8262306a36Sopenharmony_ci#endif
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic const __be32 mlx4_ib_opcode[] = {
8562306a36Sopenharmony_ci	[IB_WR_SEND]				= cpu_to_be32(MLX4_OPCODE_SEND),
8662306a36Sopenharmony_ci	[IB_WR_LSO]				= cpu_to_be32(MLX4_OPCODE_LSO),
8762306a36Sopenharmony_ci	[IB_WR_SEND_WITH_IMM]			= cpu_to_be32(MLX4_OPCODE_SEND_IMM),
8862306a36Sopenharmony_ci	[IB_WR_RDMA_WRITE]			= cpu_to_be32(MLX4_OPCODE_RDMA_WRITE),
8962306a36Sopenharmony_ci	[IB_WR_RDMA_WRITE_WITH_IMM]		= cpu_to_be32(MLX4_OPCODE_RDMA_WRITE_IMM),
9062306a36Sopenharmony_ci	[IB_WR_RDMA_READ]			= cpu_to_be32(MLX4_OPCODE_RDMA_READ),
9162306a36Sopenharmony_ci	[IB_WR_ATOMIC_CMP_AND_SWP]		= cpu_to_be32(MLX4_OPCODE_ATOMIC_CS),
9262306a36Sopenharmony_ci	[IB_WR_ATOMIC_FETCH_AND_ADD]		= cpu_to_be32(MLX4_OPCODE_ATOMIC_FA),
9362306a36Sopenharmony_ci	[IB_WR_SEND_WITH_INV]			= cpu_to_be32(MLX4_OPCODE_SEND_INVAL),
9462306a36Sopenharmony_ci	[IB_WR_LOCAL_INV]			= cpu_to_be32(MLX4_OPCODE_LOCAL_INVAL),
9562306a36Sopenharmony_ci	[IB_WR_REG_MR]				= cpu_to_be32(MLX4_OPCODE_FMR),
9662306a36Sopenharmony_ci	[IB_WR_MASKED_ATOMIC_CMP_AND_SWP]	= cpu_to_be32(MLX4_OPCODE_MASKED_ATOMIC_CS),
9762306a36Sopenharmony_ci	[IB_WR_MASKED_ATOMIC_FETCH_AND_ADD]	= cpu_to_be32(MLX4_OPCODE_MASKED_ATOMIC_FA),
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cienum mlx4_ib_source_type {
10162306a36Sopenharmony_ci	MLX4_IB_QP_SRC	= 0,
10262306a36Sopenharmony_ci	MLX4_IB_RWQ_SRC	= 1,
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistruct mlx4_ib_qp_event_work {
10662306a36Sopenharmony_ci	struct work_struct work;
10762306a36Sopenharmony_ci	struct mlx4_qp *qp;
10862306a36Sopenharmony_ci	enum mlx4_event type;
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic struct workqueue_struct *mlx4_ib_qp_event_wq;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic int is_tunnel_qp(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	if (!mlx4_is_master(dev->dev))
11662306a36Sopenharmony_ci		return 0;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	return qp->mqp.qpn >= dev->dev->phys_caps.base_tunnel_sqpn &&
11962306a36Sopenharmony_ci	       qp->mqp.qpn < dev->dev->phys_caps.base_tunnel_sqpn +
12062306a36Sopenharmony_ci		8 * MLX4_MFUNC_MAX;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int is_sqp(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	int proxy_sqp = 0;
12662306a36Sopenharmony_ci	int real_sqp = 0;
12762306a36Sopenharmony_ci	int i;
12862306a36Sopenharmony_ci	/* PPF or Native -- real SQP */
12962306a36Sopenharmony_ci	real_sqp = ((mlx4_is_master(dev->dev) || !mlx4_is_mfunc(dev->dev)) &&
13062306a36Sopenharmony_ci		    qp->mqp.qpn >= dev->dev->phys_caps.base_sqpn &&
13162306a36Sopenharmony_ci		    qp->mqp.qpn <= dev->dev->phys_caps.base_sqpn + 3);
13262306a36Sopenharmony_ci	if (real_sqp)
13362306a36Sopenharmony_ci		return 1;
13462306a36Sopenharmony_ci	/* VF or PF -- proxy SQP */
13562306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev->dev)) {
13662306a36Sopenharmony_ci		for (i = 0; i < dev->dev->caps.num_ports; i++) {
13762306a36Sopenharmony_ci			if (qp->mqp.qpn == dev->dev->caps.spec_qps[i].qp0_proxy ||
13862306a36Sopenharmony_ci			    qp->mqp.qpn == dev->dev->caps.spec_qps[i].qp1_proxy) {
13962306a36Sopenharmony_ci				proxy_sqp = 1;
14062306a36Sopenharmony_ci				break;
14162306a36Sopenharmony_ci			}
14262306a36Sopenharmony_ci		}
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	if (proxy_sqp)
14562306a36Sopenharmony_ci		return 1;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return !!(qp->flags & MLX4_IB_ROCE_V2_GSI_QP);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/* used for INIT/CLOSE port logic */
15162306a36Sopenharmony_cistatic int is_qp0(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	int proxy_qp0 = 0;
15462306a36Sopenharmony_ci	int real_qp0 = 0;
15562306a36Sopenharmony_ci	int i;
15662306a36Sopenharmony_ci	/* PPF or Native -- real QP0 */
15762306a36Sopenharmony_ci	real_qp0 = ((mlx4_is_master(dev->dev) || !mlx4_is_mfunc(dev->dev)) &&
15862306a36Sopenharmony_ci		    qp->mqp.qpn >= dev->dev->phys_caps.base_sqpn &&
15962306a36Sopenharmony_ci		    qp->mqp.qpn <= dev->dev->phys_caps.base_sqpn + 1);
16062306a36Sopenharmony_ci	if (real_qp0)
16162306a36Sopenharmony_ci		return 1;
16262306a36Sopenharmony_ci	/* VF or PF -- proxy QP0 */
16362306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev->dev)) {
16462306a36Sopenharmony_ci		for (i = 0; i < dev->dev->caps.num_ports; i++) {
16562306a36Sopenharmony_ci			if (qp->mqp.qpn == dev->dev->caps.spec_qps[i].qp0_proxy) {
16662306a36Sopenharmony_ci				proxy_qp0 = 1;
16762306a36Sopenharmony_ci				break;
16862306a36Sopenharmony_ci			}
16962306a36Sopenharmony_ci		}
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci	return proxy_qp0;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic void *get_wqe(struct mlx4_ib_qp *qp, int offset)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	return mlx4_buf_offset(&qp->buf, offset);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic void *get_recv_wqe(struct mlx4_ib_qp *qp, int n)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	return get_wqe(qp, qp->rq.offset + (n << qp->rq.wqe_shift));
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic void *get_send_wqe(struct mlx4_ib_qp *qp, int n)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	return get_wqe(qp, qp->sq.offset + (n << qp->sq.wqe_shift));
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/*
19062306a36Sopenharmony_ci * Stamp a SQ WQE so that it is invalid if prefetched by marking the
19162306a36Sopenharmony_ci * first four bytes of every 64 byte chunk with 0xffffffff, except for
19262306a36Sopenharmony_ci * the very first chunk of the WQE.
19362306a36Sopenharmony_ci */
19462306a36Sopenharmony_cistatic void stamp_send_wqe(struct mlx4_ib_qp *qp, int n)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	__be32 *wqe;
19762306a36Sopenharmony_ci	int i;
19862306a36Sopenharmony_ci	int s;
19962306a36Sopenharmony_ci	void *buf;
20062306a36Sopenharmony_ci	struct mlx4_wqe_ctrl_seg *ctrl;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	buf = get_send_wqe(qp, n & (qp->sq.wqe_cnt - 1));
20362306a36Sopenharmony_ci	ctrl = (struct mlx4_wqe_ctrl_seg *)buf;
20462306a36Sopenharmony_ci	s = (ctrl->qpn_vlan.fence_size & 0x3f) << 4;
20562306a36Sopenharmony_ci	for (i = 64; i < s; i += 64) {
20662306a36Sopenharmony_ci		wqe = buf + i;
20762306a36Sopenharmony_ci		*wqe = cpu_to_be32(0xffffffff);
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic void mlx4_ib_handle_qp_event(struct work_struct *_work)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct mlx4_ib_qp_event_work *qpe_work =
21462306a36Sopenharmony_ci		container_of(_work, struct mlx4_ib_qp_event_work, work);
21562306a36Sopenharmony_ci	struct ib_qp *ibqp = &to_mibqp(qpe_work->qp)->ibqp;
21662306a36Sopenharmony_ci	struct ib_event event = {};
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	event.device = ibqp->device;
21962306a36Sopenharmony_ci	event.element.qp = ibqp;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	switch (qpe_work->type) {
22262306a36Sopenharmony_ci	case MLX4_EVENT_TYPE_PATH_MIG:
22362306a36Sopenharmony_ci		event.event = IB_EVENT_PATH_MIG;
22462306a36Sopenharmony_ci		break;
22562306a36Sopenharmony_ci	case MLX4_EVENT_TYPE_COMM_EST:
22662306a36Sopenharmony_ci		event.event = IB_EVENT_COMM_EST;
22762306a36Sopenharmony_ci		break;
22862306a36Sopenharmony_ci	case MLX4_EVENT_TYPE_SQ_DRAINED:
22962306a36Sopenharmony_ci		event.event = IB_EVENT_SQ_DRAINED;
23062306a36Sopenharmony_ci		break;
23162306a36Sopenharmony_ci	case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE:
23262306a36Sopenharmony_ci		event.event = IB_EVENT_QP_LAST_WQE_REACHED;
23362306a36Sopenharmony_ci		break;
23462306a36Sopenharmony_ci	case MLX4_EVENT_TYPE_WQ_CATAS_ERROR:
23562306a36Sopenharmony_ci		event.event = IB_EVENT_QP_FATAL;
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci	case MLX4_EVENT_TYPE_PATH_MIG_FAILED:
23862306a36Sopenharmony_ci		event.event = IB_EVENT_PATH_MIG_ERR;
23962306a36Sopenharmony_ci		break;
24062306a36Sopenharmony_ci	case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
24162306a36Sopenharmony_ci		event.event = IB_EVENT_QP_REQ_ERR;
24262306a36Sopenharmony_ci		break;
24362306a36Sopenharmony_ci	case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR:
24462306a36Sopenharmony_ci		event.event = IB_EVENT_QP_ACCESS_ERR;
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	default:
24762306a36Sopenharmony_ci		pr_warn("Unexpected event type %d on QP %06x\n",
24862306a36Sopenharmony_ci			qpe_work->type, qpe_work->qp->qpn);
24962306a36Sopenharmony_ci		goto out;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	ibqp->event_handler(&event, ibqp->qp_context);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ciout:
25562306a36Sopenharmony_ci	mlx4_put_qp(qpe_work->qp);
25662306a36Sopenharmony_ci	kfree(qpe_work);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct ib_qp *ibqp = &to_mibqp(qp)->ibqp;
26262306a36Sopenharmony_ci	struct mlx4_ib_qp_event_work *qpe_work;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (type == MLX4_EVENT_TYPE_PATH_MIG)
26562306a36Sopenharmony_ci		to_mibqp(qp)->port = to_mibqp(qp)->alt_port;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (!ibqp->event_handler)
26862306a36Sopenharmony_ci		goto out_no_handler;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	qpe_work = kzalloc(sizeof(*qpe_work), GFP_ATOMIC);
27162306a36Sopenharmony_ci	if (!qpe_work)
27262306a36Sopenharmony_ci		goto out_no_handler;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	qpe_work->qp = qp;
27562306a36Sopenharmony_ci	qpe_work->type = type;
27662306a36Sopenharmony_ci	INIT_WORK(&qpe_work->work, mlx4_ib_handle_qp_event);
27762306a36Sopenharmony_ci	queue_work(mlx4_ib_qp_event_wq, &qpe_work->work);
27862306a36Sopenharmony_ci	return;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ciout_no_handler:
28162306a36Sopenharmony_ci	mlx4_put_qp(qp);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic void mlx4_ib_wq_event(struct mlx4_qp *qp, enum mlx4_event type)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	pr_warn_ratelimited("Unexpected event type %d on WQ 0x%06x. Events are not supported for WQs\n",
28762306a36Sopenharmony_ci			    type, qp->qpn);
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int send_wqe_overhead(enum mlx4_ib_qp_type type, u32 flags)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	/*
29362306a36Sopenharmony_ci	 * UD WQEs must have a datagram segment.
29462306a36Sopenharmony_ci	 * RC and UC WQEs might have a remote address segment.
29562306a36Sopenharmony_ci	 * MLX WQEs need two extra inline data segments (for the UD
29662306a36Sopenharmony_ci	 * header and space for the ICRC).
29762306a36Sopenharmony_ci	 */
29862306a36Sopenharmony_ci	switch (type) {
29962306a36Sopenharmony_ci	case MLX4_IB_QPT_UD:
30062306a36Sopenharmony_ci		return sizeof (struct mlx4_wqe_ctrl_seg) +
30162306a36Sopenharmony_ci			sizeof (struct mlx4_wqe_datagram_seg) +
30262306a36Sopenharmony_ci			((flags & MLX4_IB_QP_LSO) ? MLX4_IB_LSO_HEADER_SPARE : 0);
30362306a36Sopenharmony_ci	case MLX4_IB_QPT_PROXY_SMI_OWNER:
30462306a36Sopenharmony_ci	case MLX4_IB_QPT_PROXY_SMI:
30562306a36Sopenharmony_ci	case MLX4_IB_QPT_PROXY_GSI:
30662306a36Sopenharmony_ci		return sizeof (struct mlx4_wqe_ctrl_seg) +
30762306a36Sopenharmony_ci			sizeof (struct mlx4_wqe_datagram_seg) + 64;
30862306a36Sopenharmony_ci	case MLX4_IB_QPT_TUN_SMI_OWNER:
30962306a36Sopenharmony_ci	case MLX4_IB_QPT_TUN_GSI:
31062306a36Sopenharmony_ci		return sizeof (struct mlx4_wqe_ctrl_seg) +
31162306a36Sopenharmony_ci			sizeof (struct mlx4_wqe_datagram_seg);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	case MLX4_IB_QPT_UC:
31462306a36Sopenharmony_ci		return sizeof (struct mlx4_wqe_ctrl_seg) +
31562306a36Sopenharmony_ci			sizeof (struct mlx4_wqe_raddr_seg);
31662306a36Sopenharmony_ci	case MLX4_IB_QPT_RC:
31762306a36Sopenharmony_ci		return sizeof (struct mlx4_wqe_ctrl_seg) +
31862306a36Sopenharmony_ci			sizeof (struct mlx4_wqe_masked_atomic_seg) +
31962306a36Sopenharmony_ci			sizeof (struct mlx4_wqe_raddr_seg);
32062306a36Sopenharmony_ci	case MLX4_IB_QPT_SMI:
32162306a36Sopenharmony_ci	case MLX4_IB_QPT_GSI:
32262306a36Sopenharmony_ci		return sizeof (struct mlx4_wqe_ctrl_seg) +
32362306a36Sopenharmony_ci			ALIGN(MLX4_IB_UD_HEADER_SIZE +
32462306a36Sopenharmony_ci			      DIV_ROUND_UP(MLX4_IB_UD_HEADER_SIZE,
32562306a36Sopenharmony_ci					   MLX4_INLINE_ALIGN) *
32662306a36Sopenharmony_ci			      sizeof (struct mlx4_wqe_inline_seg),
32762306a36Sopenharmony_ci			      sizeof (struct mlx4_wqe_data_seg)) +
32862306a36Sopenharmony_ci			ALIGN(4 +
32962306a36Sopenharmony_ci			      sizeof (struct mlx4_wqe_inline_seg),
33062306a36Sopenharmony_ci			      sizeof (struct mlx4_wqe_data_seg));
33162306a36Sopenharmony_ci	default:
33262306a36Sopenharmony_ci		return sizeof (struct mlx4_wqe_ctrl_seg);
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
33762306a36Sopenharmony_ci		       bool is_user, bool has_rq, struct mlx4_ib_qp *qp,
33862306a36Sopenharmony_ci		       u32 inl_recv_sz)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	/* Sanity check RQ size before proceeding */
34162306a36Sopenharmony_ci	if (cap->max_recv_wr > dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE ||
34262306a36Sopenharmony_ci	    cap->max_recv_sge > min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg))
34362306a36Sopenharmony_ci		return -EINVAL;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (!has_rq) {
34662306a36Sopenharmony_ci		if (cap->max_recv_wr || inl_recv_sz)
34762306a36Sopenharmony_ci			return -EINVAL;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		qp->rq.wqe_cnt = qp->rq.max_gs = 0;
35062306a36Sopenharmony_ci	} else {
35162306a36Sopenharmony_ci		u32 max_inl_recv_sz = dev->dev->caps.max_rq_sg *
35262306a36Sopenharmony_ci			sizeof(struct mlx4_wqe_data_seg);
35362306a36Sopenharmony_ci		u32 wqe_size;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		/* HW requires >= 1 RQ entry with >= 1 gather entry */
35662306a36Sopenharmony_ci		if (is_user && (!cap->max_recv_wr || !cap->max_recv_sge ||
35762306a36Sopenharmony_ci				inl_recv_sz > max_inl_recv_sz))
35862306a36Sopenharmony_ci			return -EINVAL;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		qp->rq.wqe_cnt	 = roundup_pow_of_two(max(1U, cap->max_recv_wr));
36162306a36Sopenharmony_ci		qp->rq.max_gs	 = roundup_pow_of_two(max(1U, cap->max_recv_sge));
36262306a36Sopenharmony_ci		wqe_size = qp->rq.max_gs * sizeof(struct mlx4_wqe_data_seg);
36362306a36Sopenharmony_ci		qp->rq.wqe_shift = ilog2(max_t(u32, wqe_size, inl_recv_sz));
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* leave userspace return values as they were, so as not to break ABI */
36762306a36Sopenharmony_ci	if (is_user) {
36862306a36Sopenharmony_ci		cap->max_recv_wr  = qp->rq.max_post = qp->rq.wqe_cnt;
36962306a36Sopenharmony_ci		cap->max_recv_sge = qp->rq.max_gs;
37062306a36Sopenharmony_ci	} else {
37162306a36Sopenharmony_ci		cap->max_recv_wr  = qp->rq.max_post =
37262306a36Sopenharmony_ci			min(dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE, qp->rq.wqe_cnt);
37362306a36Sopenharmony_ci		cap->max_recv_sge = min(qp->rq.max_gs,
37462306a36Sopenharmony_ci					min(dev->dev->caps.max_sq_sg,
37562306a36Sopenharmony_ci					    dev->dev->caps.max_rq_sg));
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return 0;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
38262306a36Sopenharmony_ci			      enum mlx4_ib_qp_type type, struct mlx4_ib_qp *qp)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	int s;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* Sanity check SQ size before proceeding */
38762306a36Sopenharmony_ci	if (cap->max_send_wr  > (dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE) ||
38862306a36Sopenharmony_ci	    cap->max_send_sge > min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg) ||
38962306a36Sopenharmony_ci	    cap->max_inline_data + send_wqe_overhead(type, qp->flags) +
39062306a36Sopenharmony_ci	    sizeof (struct mlx4_wqe_inline_seg) > dev->dev->caps.max_sq_desc_sz)
39162306a36Sopenharmony_ci		return -EINVAL;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/*
39462306a36Sopenharmony_ci	 * For MLX transport we need 2 extra S/G entries:
39562306a36Sopenharmony_ci	 * one for the header and one for the checksum at the end
39662306a36Sopenharmony_ci	 */
39762306a36Sopenharmony_ci	if ((type == MLX4_IB_QPT_SMI || type == MLX4_IB_QPT_GSI ||
39862306a36Sopenharmony_ci	     type & (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_TUN_SMI_OWNER)) &&
39962306a36Sopenharmony_ci	    cap->max_send_sge + 2 > dev->dev->caps.max_sq_sg)
40062306a36Sopenharmony_ci		return -EINVAL;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	s = max(cap->max_send_sge * sizeof (struct mlx4_wqe_data_seg),
40362306a36Sopenharmony_ci		cap->max_inline_data + sizeof (struct mlx4_wqe_inline_seg)) +
40462306a36Sopenharmony_ci		send_wqe_overhead(type, qp->flags);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (s > dev->dev->caps.max_sq_desc_sz)
40762306a36Sopenharmony_ci		return -EINVAL;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	qp->sq.wqe_shift = ilog2(roundup_pow_of_two(s));
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/*
41262306a36Sopenharmony_ci	 * We need to leave 2 KB + 1 WR of headroom in the SQ to
41362306a36Sopenharmony_ci	 * allow HW to prefetch.
41462306a36Sopenharmony_ci	 */
41562306a36Sopenharmony_ci	qp->sq_spare_wqes = MLX4_IB_SQ_HEADROOM(qp->sq.wqe_shift);
41662306a36Sopenharmony_ci	qp->sq.wqe_cnt = roundup_pow_of_two(cap->max_send_wr +
41762306a36Sopenharmony_ci					    qp->sq_spare_wqes);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	qp->sq.max_gs =
42062306a36Sopenharmony_ci		(min(dev->dev->caps.max_sq_desc_sz,
42162306a36Sopenharmony_ci		     (1 << qp->sq.wqe_shift)) -
42262306a36Sopenharmony_ci		 send_wqe_overhead(type, qp->flags)) /
42362306a36Sopenharmony_ci		sizeof (struct mlx4_wqe_data_seg);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) +
42662306a36Sopenharmony_ci		(qp->sq.wqe_cnt << qp->sq.wqe_shift);
42762306a36Sopenharmony_ci	if (qp->rq.wqe_shift > qp->sq.wqe_shift) {
42862306a36Sopenharmony_ci		qp->rq.offset = 0;
42962306a36Sopenharmony_ci		qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift;
43062306a36Sopenharmony_ci	} else {
43162306a36Sopenharmony_ci		qp->rq.offset = qp->sq.wqe_cnt << qp->sq.wqe_shift;
43262306a36Sopenharmony_ci		qp->sq.offset = 0;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	cap->max_send_wr  = qp->sq.max_post =
43662306a36Sopenharmony_ci		qp->sq.wqe_cnt - qp->sq_spare_wqes;
43762306a36Sopenharmony_ci	cap->max_send_sge = min(qp->sq.max_gs,
43862306a36Sopenharmony_ci				min(dev->dev->caps.max_sq_sg,
43962306a36Sopenharmony_ci				    dev->dev->caps.max_rq_sg));
44062306a36Sopenharmony_ci	/* We don't support inline sends for kernel QPs (yet) */
44162306a36Sopenharmony_ci	cap->max_inline_data = 0;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	return 0;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic int set_user_sq_size(struct mlx4_ib_dev *dev,
44762306a36Sopenharmony_ci			    struct mlx4_ib_qp *qp,
44862306a36Sopenharmony_ci			    struct mlx4_ib_create_qp *ucmd)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	u32 cnt;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	/* Sanity check SQ size before proceeding */
45362306a36Sopenharmony_ci	if (check_shl_overflow(1, ucmd->log_sq_bb_count, &cnt) ||
45462306a36Sopenharmony_ci	    cnt > dev->dev->caps.max_wqes)
45562306a36Sopenharmony_ci		return -EINVAL;
45662306a36Sopenharmony_ci	if (ucmd->log_sq_stride >
45762306a36Sopenharmony_ci		ilog2(roundup_pow_of_two(dev->dev->caps.max_sq_desc_sz)) ||
45862306a36Sopenharmony_ci	    ucmd->log_sq_stride < MLX4_IB_MIN_SQ_STRIDE)
45962306a36Sopenharmony_ci		return -EINVAL;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	qp->sq.wqe_cnt   = 1 << ucmd->log_sq_bb_count;
46262306a36Sopenharmony_ci	qp->sq.wqe_shift = ucmd->log_sq_stride;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) +
46562306a36Sopenharmony_ci		(qp->sq.wqe_cnt << qp->sq.wqe_shift);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	return 0;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic int alloc_proxy_bufs(struct ib_device *dev, struct mlx4_ib_qp *qp)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	int i;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	qp->sqp_proxy_rcv =
47562306a36Sopenharmony_ci		kmalloc_array(qp->rq.wqe_cnt, sizeof(struct mlx4_ib_buf),
47662306a36Sopenharmony_ci			      GFP_KERNEL);
47762306a36Sopenharmony_ci	if (!qp->sqp_proxy_rcv)
47862306a36Sopenharmony_ci		return -ENOMEM;
47962306a36Sopenharmony_ci	for (i = 0; i < qp->rq.wqe_cnt; i++) {
48062306a36Sopenharmony_ci		qp->sqp_proxy_rcv[i].addr =
48162306a36Sopenharmony_ci			kmalloc(sizeof (struct mlx4_ib_proxy_sqp_hdr),
48262306a36Sopenharmony_ci				GFP_KERNEL);
48362306a36Sopenharmony_ci		if (!qp->sqp_proxy_rcv[i].addr)
48462306a36Sopenharmony_ci			goto err;
48562306a36Sopenharmony_ci		qp->sqp_proxy_rcv[i].map =
48662306a36Sopenharmony_ci			ib_dma_map_single(dev, qp->sqp_proxy_rcv[i].addr,
48762306a36Sopenharmony_ci					  sizeof (struct mlx4_ib_proxy_sqp_hdr),
48862306a36Sopenharmony_ci					  DMA_FROM_DEVICE);
48962306a36Sopenharmony_ci		if (ib_dma_mapping_error(dev, qp->sqp_proxy_rcv[i].map)) {
49062306a36Sopenharmony_ci			kfree(qp->sqp_proxy_rcv[i].addr);
49162306a36Sopenharmony_ci			goto err;
49262306a36Sopenharmony_ci		}
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci	return 0;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cierr:
49762306a36Sopenharmony_ci	while (i > 0) {
49862306a36Sopenharmony_ci		--i;
49962306a36Sopenharmony_ci		ib_dma_unmap_single(dev, qp->sqp_proxy_rcv[i].map,
50062306a36Sopenharmony_ci				    sizeof (struct mlx4_ib_proxy_sqp_hdr),
50162306a36Sopenharmony_ci				    DMA_FROM_DEVICE);
50262306a36Sopenharmony_ci		kfree(qp->sqp_proxy_rcv[i].addr);
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci	kfree(qp->sqp_proxy_rcv);
50562306a36Sopenharmony_ci	qp->sqp_proxy_rcv = NULL;
50662306a36Sopenharmony_ci	return -ENOMEM;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic void free_proxy_bufs(struct ib_device *dev, struct mlx4_ib_qp *qp)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	int i;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	for (i = 0; i < qp->rq.wqe_cnt; i++) {
51462306a36Sopenharmony_ci		ib_dma_unmap_single(dev, qp->sqp_proxy_rcv[i].map,
51562306a36Sopenharmony_ci				    sizeof (struct mlx4_ib_proxy_sqp_hdr),
51662306a36Sopenharmony_ci				    DMA_FROM_DEVICE);
51762306a36Sopenharmony_ci		kfree(qp->sqp_proxy_rcv[i].addr);
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci	kfree(qp->sqp_proxy_rcv);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic bool qp_has_rq(struct ib_qp_init_attr *attr)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	if (attr->qp_type == IB_QPT_XRC_INI || attr->qp_type == IB_QPT_XRC_TGT)
52562306a36Sopenharmony_ci		return false;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return !attr->srq;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic int qp0_enabled_vf(struct mlx4_dev *dev, int qpn)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	int i;
53362306a36Sopenharmony_ci	for (i = 0; i < dev->caps.num_ports; i++) {
53462306a36Sopenharmony_ci		if (qpn == dev->caps.spec_qps[i].qp0_proxy)
53562306a36Sopenharmony_ci			return !!dev->caps.spec_qps[i].qp0_qkey;
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci	return 0;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic void mlx4_ib_free_qp_counter(struct mlx4_ib_dev *dev,
54162306a36Sopenharmony_ci				    struct mlx4_ib_qp *qp)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	mutex_lock(&dev->counters_table[qp->port - 1].mutex);
54462306a36Sopenharmony_ci	mlx4_counter_free(dev->dev, qp->counter_index->index);
54562306a36Sopenharmony_ci	list_del(&qp->counter_index->list);
54662306a36Sopenharmony_ci	mutex_unlock(&dev->counters_table[qp->port - 1].mutex);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	kfree(qp->counter_index);
54962306a36Sopenharmony_ci	qp->counter_index = NULL;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic int set_qp_rss(struct mlx4_ib_dev *dev, struct mlx4_ib_rss *rss_ctx,
55362306a36Sopenharmony_ci		      struct ib_qp_init_attr *init_attr,
55462306a36Sopenharmony_ci		      struct mlx4_ib_create_qp_rss *ucmd)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	rss_ctx->base_qpn_tbl_sz = init_attr->rwq_ind_tbl->ind_tbl[0]->wq_num |
55762306a36Sopenharmony_ci		(init_attr->rwq_ind_tbl->log_ind_tbl_size << 24);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if ((ucmd->rx_hash_function == MLX4_IB_RX_HASH_FUNC_TOEPLITZ) &&
56062306a36Sopenharmony_ci	    (dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP)) {
56162306a36Sopenharmony_ci		memcpy(rss_ctx->rss_key, ucmd->rx_hash_key,
56262306a36Sopenharmony_ci		       MLX4_EN_RSS_KEY_SIZE);
56362306a36Sopenharmony_ci	} else {
56462306a36Sopenharmony_ci		pr_debug("RX Hash function is not supported\n");
56562306a36Sopenharmony_ci		return (-EOPNOTSUPP);
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	if (ucmd->rx_hash_fields_mask & ~(u64)(MLX4_IB_RX_HASH_SRC_IPV4	|
56962306a36Sopenharmony_ci					       MLX4_IB_RX_HASH_DST_IPV4	|
57062306a36Sopenharmony_ci					       MLX4_IB_RX_HASH_SRC_IPV6	|
57162306a36Sopenharmony_ci					       MLX4_IB_RX_HASH_DST_IPV6	|
57262306a36Sopenharmony_ci					       MLX4_IB_RX_HASH_SRC_PORT_TCP |
57362306a36Sopenharmony_ci					       MLX4_IB_RX_HASH_DST_PORT_TCP |
57462306a36Sopenharmony_ci					       MLX4_IB_RX_HASH_SRC_PORT_UDP |
57562306a36Sopenharmony_ci					       MLX4_IB_RX_HASH_DST_PORT_UDP |
57662306a36Sopenharmony_ci					       MLX4_IB_RX_HASH_INNER)) {
57762306a36Sopenharmony_ci		pr_debug("RX Hash fields_mask has unsupported mask (0x%llx)\n",
57862306a36Sopenharmony_ci			 ucmd->rx_hash_fields_mask);
57962306a36Sopenharmony_ci		return (-EOPNOTSUPP);
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV4) &&
58362306a36Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV4)) {
58462306a36Sopenharmony_ci		rss_ctx->flags = MLX4_RSS_IPV4;
58562306a36Sopenharmony_ci	} else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV4) ||
58662306a36Sopenharmony_ci		   (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV4)) {
58762306a36Sopenharmony_ci		pr_debug("RX Hash fields_mask is not supported - both IPv4 SRC and DST must be set\n");
58862306a36Sopenharmony_ci		return (-EOPNOTSUPP);
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV6) &&
59262306a36Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV6)) {
59362306a36Sopenharmony_ci		rss_ctx->flags |= MLX4_RSS_IPV6;
59462306a36Sopenharmony_ci	} else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_IPV6) ||
59562306a36Sopenharmony_ci		   (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_IPV6)) {
59662306a36Sopenharmony_ci		pr_debug("RX Hash fields_mask is not supported - both IPv6 SRC and DST must be set\n");
59762306a36Sopenharmony_ci		return (-EOPNOTSUPP);
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_UDP) &&
60162306a36Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_UDP)) {
60262306a36Sopenharmony_ci		if (!(dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UDP_RSS)) {
60362306a36Sopenharmony_ci			pr_debug("RX Hash fields_mask for UDP is not supported\n");
60462306a36Sopenharmony_ci			return (-EOPNOTSUPP);
60562306a36Sopenharmony_ci		}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci		if (rss_ctx->flags & MLX4_RSS_IPV4)
60862306a36Sopenharmony_ci			rss_ctx->flags |= MLX4_RSS_UDP_IPV4;
60962306a36Sopenharmony_ci		if (rss_ctx->flags & MLX4_RSS_IPV6)
61062306a36Sopenharmony_ci			rss_ctx->flags |= MLX4_RSS_UDP_IPV6;
61162306a36Sopenharmony_ci		if (!(rss_ctx->flags & (MLX4_RSS_IPV6 | MLX4_RSS_IPV4))) {
61262306a36Sopenharmony_ci			pr_debug("RX Hash fields_mask is not supported - UDP must be set with IPv4 or IPv6\n");
61362306a36Sopenharmony_ci			return (-EOPNOTSUPP);
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci	} else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_UDP) ||
61662306a36Sopenharmony_ci		   (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_UDP)) {
61762306a36Sopenharmony_ci		pr_debug("RX Hash fields_mask is not supported - both UDP SRC and DST must be set\n");
61862306a36Sopenharmony_ci		return (-EOPNOTSUPP);
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_TCP) &&
62262306a36Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_TCP)) {
62362306a36Sopenharmony_ci		if (rss_ctx->flags & MLX4_RSS_IPV4)
62462306a36Sopenharmony_ci			rss_ctx->flags |= MLX4_RSS_TCP_IPV4;
62562306a36Sopenharmony_ci		if (rss_ctx->flags & MLX4_RSS_IPV6)
62662306a36Sopenharmony_ci			rss_ctx->flags |= MLX4_RSS_TCP_IPV6;
62762306a36Sopenharmony_ci		if (!(rss_ctx->flags & (MLX4_RSS_IPV6 | MLX4_RSS_IPV4))) {
62862306a36Sopenharmony_ci			pr_debug("RX Hash fields_mask is not supported - TCP must be set with IPv4 or IPv6\n");
62962306a36Sopenharmony_ci			return (-EOPNOTSUPP);
63062306a36Sopenharmony_ci		}
63162306a36Sopenharmony_ci	} else if ((ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_SRC_PORT_TCP) ||
63262306a36Sopenharmony_ci		   (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_DST_PORT_TCP)) {
63362306a36Sopenharmony_ci		pr_debug("RX Hash fields_mask is not supported - both TCP SRC and DST must be set\n");
63462306a36Sopenharmony_ci		return (-EOPNOTSUPP);
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (ucmd->rx_hash_fields_mask & MLX4_IB_RX_HASH_INNER) {
63862306a36Sopenharmony_ci		if (dev->dev->caps.tunnel_offload_mode ==
63962306a36Sopenharmony_ci		    MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
64062306a36Sopenharmony_ci			/*
64162306a36Sopenharmony_ci			 * Hash according to inner headers if exist, otherwise
64262306a36Sopenharmony_ci			 * according to outer headers.
64362306a36Sopenharmony_ci			 */
64462306a36Sopenharmony_ci			rss_ctx->flags |= MLX4_RSS_BY_INNER_HEADERS_IPONLY;
64562306a36Sopenharmony_ci		} else {
64662306a36Sopenharmony_ci			pr_debug("RSS Hash for inner headers isn't supported\n");
64762306a36Sopenharmony_ci			return (-EOPNOTSUPP);
64862306a36Sopenharmony_ci		}
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	return 0;
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic int create_qp_rss(struct mlx4_ib_dev *dev,
65562306a36Sopenharmony_ci			 struct ib_qp_init_attr *init_attr,
65662306a36Sopenharmony_ci			 struct mlx4_ib_create_qp_rss *ucmd,
65762306a36Sopenharmony_ci			 struct mlx4_ib_qp *qp)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	int qpn;
66062306a36Sopenharmony_ci	int err;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	qp->mqp.usage = MLX4_RES_USAGE_USER_VERBS;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn, 0, qp->mqp.usage);
66562306a36Sopenharmony_ci	if (err)
66662306a36Sopenharmony_ci		return err;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp);
66962306a36Sopenharmony_ci	if (err)
67062306a36Sopenharmony_ci		goto err_qpn;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	INIT_LIST_HEAD(&qp->gid_list);
67362306a36Sopenharmony_ci	INIT_LIST_HEAD(&qp->steering_rules);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	qp->mlx4_ib_qp_type = MLX4_IB_QPT_RAW_PACKET;
67662306a36Sopenharmony_ci	qp->state = IB_QPS_RESET;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* Set dummy send resources to be compatible with HV and PRM */
67962306a36Sopenharmony_ci	qp->sq_no_prefetch = 1;
68062306a36Sopenharmony_ci	qp->sq.wqe_cnt = 1;
68162306a36Sopenharmony_ci	qp->sq.wqe_shift = MLX4_IB_MIN_SQ_STRIDE;
68262306a36Sopenharmony_ci	qp->buf_size = qp->sq.wqe_cnt << MLX4_IB_MIN_SQ_STRIDE;
68362306a36Sopenharmony_ci	qp->mtt = (to_mqp(
68462306a36Sopenharmony_ci		   (struct ib_qp *)init_attr->rwq_ind_tbl->ind_tbl[0]))->mtt;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	qp->rss_ctx = kzalloc(sizeof(*qp->rss_ctx), GFP_KERNEL);
68762306a36Sopenharmony_ci	if (!qp->rss_ctx) {
68862306a36Sopenharmony_ci		err = -ENOMEM;
68962306a36Sopenharmony_ci		goto err_qp_alloc;
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	err = set_qp_rss(dev, qp->rss_ctx, init_attr, ucmd);
69362306a36Sopenharmony_ci	if (err)
69462306a36Sopenharmony_ci		goto err;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	return 0;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cierr:
69962306a36Sopenharmony_ci	kfree(qp->rss_ctx);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cierr_qp_alloc:
70262306a36Sopenharmony_ci	mlx4_qp_remove(dev->dev, &qp->mqp);
70362306a36Sopenharmony_ci	mlx4_qp_free(dev->dev, &qp->mqp);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_cierr_qpn:
70662306a36Sopenharmony_ci	mlx4_qp_release_range(dev->dev, qpn, 1);
70762306a36Sopenharmony_ci	return err;
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic int _mlx4_ib_create_qp_rss(struct ib_pd *pd, struct mlx4_ib_qp *qp,
71162306a36Sopenharmony_ci				  struct ib_qp_init_attr *init_attr,
71262306a36Sopenharmony_ci				  struct ib_udata *udata)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct mlx4_ib_create_qp_rss ucmd = {};
71562306a36Sopenharmony_ci	size_t required_cmd_sz;
71662306a36Sopenharmony_ci	int err;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (!udata) {
71962306a36Sopenharmony_ci		pr_debug("RSS QP with NULL udata\n");
72062306a36Sopenharmony_ci		return -EINVAL;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	if (udata->outlen)
72462306a36Sopenharmony_ci		return -EOPNOTSUPP;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	required_cmd_sz = offsetof(typeof(ucmd), reserved1) +
72762306a36Sopenharmony_ci					sizeof(ucmd.reserved1);
72862306a36Sopenharmony_ci	if (udata->inlen < required_cmd_sz) {
72962306a36Sopenharmony_ci		pr_debug("invalid inlen\n");
73062306a36Sopenharmony_ci		return -EINVAL;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) {
73462306a36Sopenharmony_ci		pr_debug("copy failed\n");
73562306a36Sopenharmony_ci		return -EFAULT;
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (memchr_inv(ucmd.reserved, 0, sizeof(ucmd.reserved)))
73962306a36Sopenharmony_ci		return -EOPNOTSUPP;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (ucmd.comp_mask || ucmd.reserved1)
74262306a36Sopenharmony_ci		return -EOPNOTSUPP;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	if (udata->inlen > sizeof(ucmd) &&
74562306a36Sopenharmony_ci	    !ib_is_udata_cleared(udata, sizeof(ucmd),
74662306a36Sopenharmony_ci				 udata->inlen - sizeof(ucmd))) {
74762306a36Sopenharmony_ci		pr_debug("inlen is not supported\n");
74862306a36Sopenharmony_ci		return -EOPNOTSUPP;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (init_attr->qp_type != IB_QPT_RAW_PACKET) {
75262306a36Sopenharmony_ci		pr_debug("RSS QP with unsupported QP type %d\n",
75362306a36Sopenharmony_ci			 init_attr->qp_type);
75462306a36Sopenharmony_ci		return -EOPNOTSUPP;
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (init_attr->create_flags) {
75862306a36Sopenharmony_ci		pr_debug("RSS QP doesn't support create flags\n");
75962306a36Sopenharmony_ci		return -EOPNOTSUPP;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (init_attr->send_cq || init_attr->cap.max_send_wr) {
76362306a36Sopenharmony_ci		pr_debug("RSS QP with unsupported send attributes\n");
76462306a36Sopenharmony_ci		return -EOPNOTSUPP;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	qp->pri.vid = 0xFFFF;
76862306a36Sopenharmony_ci	qp->alt.vid = 0xFFFF;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	err = create_qp_rss(to_mdev(pd->device), init_attr, &ucmd, qp);
77162306a36Sopenharmony_ci	if (err)
77262306a36Sopenharmony_ci		return err;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	qp->ibqp.qp_num = qp->mqp.qpn;
77562306a36Sopenharmony_ci	return 0;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci/*
77962306a36Sopenharmony_ci * This function allocates a WQN from a range which is consecutive and aligned
78062306a36Sopenharmony_ci * to its size. In case the range is full, then it creates a new range and
78162306a36Sopenharmony_ci * allocates WQN from it. The new range will be used for following allocations.
78262306a36Sopenharmony_ci */
78362306a36Sopenharmony_cistatic int mlx4_ib_alloc_wqn(struct mlx4_ib_ucontext *context,
78462306a36Sopenharmony_ci			     struct mlx4_ib_qp *qp, int range_size, int *wqn)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(context->ibucontext.device);
78762306a36Sopenharmony_ci	struct mlx4_wqn_range *range;
78862306a36Sopenharmony_ci	int err = 0;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	mutex_lock(&context->wqn_ranges_mutex);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	range = list_first_entry_or_null(&context->wqn_ranges_list,
79362306a36Sopenharmony_ci					 struct mlx4_wqn_range, list);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (!range || (range->refcount == range->size) || range->dirty) {
79662306a36Sopenharmony_ci		range = kzalloc(sizeof(*range), GFP_KERNEL);
79762306a36Sopenharmony_ci		if (!range) {
79862306a36Sopenharmony_ci			err = -ENOMEM;
79962306a36Sopenharmony_ci			goto out;
80062306a36Sopenharmony_ci		}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci		err = mlx4_qp_reserve_range(dev->dev, range_size,
80362306a36Sopenharmony_ci					    range_size, &range->base_wqn, 0,
80462306a36Sopenharmony_ci					    qp->mqp.usage);
80562306a36Sopenharmony_ci		if (err) {
80662306a36Sopenharmony_ci			kfree(range);
80762306a36Sopenharmony_ci			goto out;
80862306a36Sopenharmony_ci		}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		range->size = range_size;
81162306a36Sopenharmony_ci		list_add(&range->list, &context->wqn_ranges_list);
81262306a36Sopenharmony_ci	} else if (range_size != 1) {
81362306a36Sopenharmony_ci		/*
81462306a36Sopenharmony_ci		 * Requesting a new range (>1) when last range is still open, is
81562306a36Sopenharmony_ci		 * not valid.
81662306a36Sopenharmony_ci		 */
81762306a36Sopenharmony_ci		err = -EINVAL;
81862306a36Sopenharmony_ci		goto out;
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	qp->wqn_range = range;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	*wqn = range->base_wqn + range->refcount;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	range->refcount++;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ciout:
82862306a36Sopenharmony_ci	mutex_unlock(&context->wqn_ranges_mutex);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return err;
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cistatic void mlx4_ib_release_wqn(struct mlx4_ib_ucontext *context,
83462306a36Sopenharmony_ci				struct mlx4_ib_qp *qp, bool dirty_release)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(context->ibucontext.device);
83762306a36Sopenharmony_ci	struct mlx4_wqn_range *range;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	mutex_lock(&context->wqn_ranges_mutex);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	range = qp->wqn_range;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	range->refcount--;
84462306a36Sopenharmony_ci	if (!range->refcount) {
84562306a36Sopenharmony_ci		mlx4_qp_release_range(dev->dev, range->base_wqn,
84662306a36Sopenharmony_ci				      range->size);
84762306a36Sopenharmony_ci		list_del(&range->list);
84862306a36Sopenharmony_ci		kfree(range);
84962306a36Sopenharmony_ci	} else if (dirty_release) {
85062306a36Sopenharmony_ci	/*
85162306a36Sopenharmony_ci	 * A range which one of its WQNs is destroyed, won't be able to be
85262306a36Sopenharmony_ci	 * reused for further WQN allocations.
85362306a36Sopenharmony_ci	 * The next created WQ will allocate a new range.
85462306a36Sopenharmony_ci	 */
85562306a36Sopenharmony_ci		range->dirty = true;
85662306a36Sopenharmony_ci	}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	mutex_unlock(&context->wqn_ranges_mutex);
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_cistatic int create_rq(struct ib_pd *pd, struct ib_qp_init_attr *init_attr,
86262306a36Sopenharmony_ci		     struct ib_udata *udata, struct mlx4_ib_qp *qp)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(pd->device);
86562306a36Sopenharmony_ci	int qpn;
86662306a36Sopenharmony_ci	int err;
86762306a36Sopenharmony_ci	struct mlx4_ib_ucontext *context = rdma_udata_to_drv_context(
86862306a36Sopenharmony_ci		udata, struct mlx4_ib_ucontext, ibucontext);
86962306a36Sopenharmony_ci	struct mlx4_ib_cq *mcq;
87062306a36Sopenharmony_ci	unsigned long flags;
87162306a36Sopenharmony_ci	int range_size;
87262306a36Sopenharmony_ci	struct mlx4_ib_create_wq wq;
87362306a36Sopenharmony_ci	size_t copy_len;
87462306a36Sopenharmony_ci	int shift;
87562306a36Sopenharmony_ci	int n;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	qp->mlx4_ib_qp_type = MLX4_IB_QPT_RAW_PACKET;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	spin_lock_init(&qp->sq.lock);
88062306a36Sopenharmony_ci	spin_lock_init(&qp->rq.lock);
88162306a36Sopenharmony_ci	INIT_LIST_HEAD(&qp->gid_list);
88262306a36Sopenharmony_ci	INIT_LIST_HEAD(&qp->steering_rules);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	qp->state = IB_QPS_RESET;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	copy_len = min(sizeof(struct mlx4_ib_create_wq), udata->inlen);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	if (ib_copy_from_udata(&wq, udata, copy_len)) {
88962306a36Sopenharmony_ci		err = -EFAULT;
89062306a36Sopenharmony_ci		goto err;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (wq.comp_mask || wq.reserved[0] || wq.reserved[1] ||
89462306a36Sopenharmony_ci	    wq.reserved[2]) {
89562306a36Sopenharmony_ci		pr_debug("user command isn't supported\n");
89662306a36Sopenharmony_ci		err = -EOPNOTSUPP;
89762306a36Sopenharmony_ci		goto err;
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	if (wq.log_range_size > ilog2(dev->dev->caps.max_rss_tbl_sz)) {
90162306a36Sopenharmony_ci		pr_debug("WQN range size must be equal or smaller than %d\n",
90262306a36Sopenharmony_ci			 dev->dev->caps.max_rss_tbl_sz);
90362306a36Sopenharmony_ci		err = -EOPNOTSUPP;
90462306a36Sopenharmony_ci		goto err;
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci	range_size = 1 << wq.log_range_size;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	if (init_attr->create_flags & IB_QP_CREATE_SCATTER_FCS)
90962306a36Sopenharmony_ci		qp->flags |= MLX4_IB_QP_SCATTER_FCS;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	err = set_rq_size(dev, &init_attr->cap, true, true, qp, qp->inl_recv_sz);
91262306a36Sopenharmony_ci	if (err)
91362306a36Sopenharmony_ci		goto err;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	qp->sq_no_prefetch = 1;
91662306a36Sopenharmony_ci	qp->sq.wqe_cnt = 1;
91762306a36Sopenharmony_ci	qp->sq.wqe_shift = MLX4_IB_MIN_SQ_STRIDE;
91862306a36Sopenharmony_ci	qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) +
91962306a36Sopenharmony_ci		       (qp->sq.wqe_cnt << qp->sq.wqe_shift);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	qp->umem = ib_umem_get(pd->device, wq.buf_addr, qp->buf_size, 0);
92262306a36Sopenharmony_ci	if (IS_ERR(qp->umem)) {
92362306a36Sopenharmony_ci		err = PTR_ERR(qp->umem);
92462306a36Sopenharmony_ci		goto err;
92562306a36Sopenharmony_ci	}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	shift = mlx4_ib_umem_calc_optimal_mtt_size(qp->umem, 0, &n);
92862306a36Sopenharmony_ci	err = mlx4_mtt_init(dev->dev, n, shift, &qp->mtt);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	if (err)
93162306a36Sopenharmony_ci		goto err_buf;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	err = mlx4_ib_umem_write_mtt(dev, &qp->mtt, qp->umem);
93462306a36Sopenharmony_ci	if (err)
93562306a36Sopenharmony_ci		goto err_mtt;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	err = mlx4_ib_db_map_user(udata, wq.db_addr, &qp->db);
93862306a36Sopenharmony_ci	if (err)
93962306a36Sopenharmony_ci		goto err_mtt;
94062306a36Sopenharmony_ci	qp->mqp.usage = MLX4_RES_USAGE_USER_VERBS;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	err = mlx4_ib_alloc_wqn(context, qp, range_size, &qpn);
94362306a36Sopenharmony_ci	if (err)
94462306a36Sopenharmony_ci		goto err_wrid;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp);
94762306a36Sopenharmony_ci	if (err)
94862306a36Sopenharmony_ci		goto err_qpn;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	/*
95162306a36Sopenharmony_ci	 * Hardware wants QPN written in big-endian order (after
95262306a36Sopenharmony_ci	 * shifting) for send doorbell.  Precompute this value to save
95362306a36Sopenharmony_ci	 * a little bit when posting sends.
95462306a36Sopenharmony_ci	 */
95562306a36Sopenharmony_ci	qp->doorbell_qpn = swab32(qp->mqp.qpn << 8);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	qp->mqp.event = mlx4_ib_wq_event;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
96062306a36Sopenharmony_ci	mlx4_ib_lock_cqs(to_mcq(init_attr->send_cq),
96162306a36Sopenharmony_ci			 to_mcq(init_attr->recv_cq));
96262306a36Sopenharmony_ci	/* Maintain device to QPs access, needed for further handling
96362306a36Sopenharmony_ci	 * via reset flow
96462306a36Sopenharmony_ci	 */
96562306a36Sopenharmony_ci	list_add_tail(&qp->qps_list, &dev->qp_list);
96662306a36Sopenharmony_ci	/* Maintain CQ to QPs access, needed for further handling
96762306a36Sopenharmony_ci	 * via reset flow
96862306a36Sopenharmony_ci	 */
96962306a36Sopenharmony_ci	mcq = to_mcq(init_attr->send_cq);
97062306a36Sopenharmony_ci	list_add_tail(&qp->cq_send_list, &mcq->send_qp_list);
97162306a36Sopenharmony_ci	mcq = to_mcq(init_attr->recv_cq);
97262306a36Sopenharmony_ci	list_add_tail(&qp->cq_recv_list, &mcq->recv_qp_list);
97362306a36Sopenharmony_ci	mlx4_ib_unlock_cqs(to_mcq(init_attr->send_cq),
97462306a36Sopenharmony_ci			   to_mcq(init_attr->recv_cq));
97562306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
97662306a36Sopenharmony_ci	return 0;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_cierr_qpn:
97962306a36Sopenharmony_ci	mlx4_ib_release_wqn(context, qp, 0);
98062306a36Sopenharmony_cierr_wrid:
98162306a36Sopenharmony_ci	mlx4_ib_db_unmap_user(context, &qp->db);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cierr_mtt:
98462306a36Sopenharmony_ci	mlx4_mtt_cleanup(dev->dev, &qp->mtt);
98562306a36Sopenharmony_cierr_buf:
98662306a36Sopenharmony_ci	ib_umem_release(qp->umem);
98762306a36Sopenharmony_cierr:
98862306a36Sopenharmony_ci	return err;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_cistatic int create_qp_common(struct ib_pd *pd, struct ib_qp_init_attr *init_attr,
99262306a36Sopenharmony_ci			    struct ib_udata *udata, int sqpn,
99362306a36Sopenharmony_ci			    struct mlx4_ib_qp *qp)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(pd->device);
99662306a36Sopenharmony_ci	int qpn;
99762306a36Sopenharmony_ci	int err;
99862306a36Sopenharmony_ci	struct mlx4_ib_ucontext *context = rdma_udata_to_drv_context(
99962306a36Sopenharmony_ci		udata, struct mlx4_ib_ucontext, ibucontext);
100062306a36Sopenharmony_ci	enum mlx4_ib_qp_type qp_type = (enum mlx4_ib_qp_type) init_attr->qp_type;
100162306a36Sopenharmony_ci	struct mlx4_ib_cq *mcq;
100262306a36Sopenharmony_ci	unsigned long flags;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	/* When tunneling special qps, we use a plain UD qp */
100562306a36Sopenharmony_ci	if (sqpn) {
100662306a36Sopenharmony_ci		if (mlx4_is_mfunc(dev->dev) &&
100762306a36Sopenharmony_ci		    (!mlx4_is_master(dev->dev) ||
100862306a36Sopenharmony_ci		     !(init_attr->create_flags & MLX4_IB_SRIOV_SQP))) {
100962306a36Sopenharmony_ci			if (init_attr->qp_type == IB_QPT_GSI)
101062306a36Sopenharmony_ci				qp_type = MLX4_IB_QPT_PROXY_GSI;
101162306a36Sopenharmony_ci			else {
101262306a36Sopenharmony_ci				if (mlx4_is_master(dev->dev) ||
101362306a36Sopenharmony_ci				    qp0_enabled_vf(dev->dev, sqpn))
101462306a36Sopenharmony_ci					qp_type = MLX4_IB_QPT_PROXY_SMI_OWNER;
101562306a36Sopenharmony_ci				else
101662306a36Sopenharmony_ci					qp_type = MLX4_IB_QPT_PROXY_SMI;
101762306a36Sopenharmony_ci			}
101862306a36Sopenharmony_ci		}
101962306a36Sopenharmony_ci		qpn = sqpn;
102062306a36Sopenharmony_ci		/* add extra sg entry for tunneling */
102162306a36Sopenharmony_ci		init_attr->cap.max_recv_sge++;
102262306a36Sopenharmony_ci	} else if (init_attr->create_flags & MLX4_IB_SRIOV_TUNNEL_QP) {
102362306a36Sopenharmony_ci		struct mlx4_ib_qp_tunnel_init_attr *tnl_init =
102462306a36Sopenharmony_ci			container_of(init_attr,
102562306a36Sopenharmony_ci				     struct mlx4_ib_qp_tunnel_init_attr, init_attr);
102662306a36Sopenharmony_ci		if ((tnl_init->proxy_qp_type != IB_QPT_SMI &&
102762306a36Sopenharmony_ci		     tnl_init->proxy_qp_type != IB_QPT_GSI)   ||
102862306a36Sopenharmony_ci		    !mlx4_is_master(dev->dev))
102962306a36Sopenharmony_ci			return -EINVAL;
103062306a36Sopenharmony_ci		if (tnl_init->proxy_qp_type == IB_QPT_GSI)
103162306a36Sopenharmony_ci			qp_type = MLX4_IB_QPT_TUN_GSI;
103262306a36Sopenharmony_ci		else if (tnl_init->slave == mlx4_master_func_num(dev->dev) ||
103362306a36Sopenharmony_ci			 mlx4_vf_smi_enabled(dev->dev, tnl_init->slave,
103462306a36Sopenharmony_ci					     tnl_init->port))
103562306a36Sopenharmony_ci			qp_type = MLX4_IB_QPT_TUN_SMI_OWNER;
103662306a36Sopenharmony_ci		else
103762306a36Sopenharmony_ci			qp_type = MLX4_IB_QPT_TUN_SMI;
103862306a36Sopenharmony_ci		/* we are definitely in the PPF here, since we are creating
103962306a36Sopenharmony_ci		 * tunnel QPs. base_tunnel_sqpn is therefore valid. */
104062306a36Sopenharmony_ci		qpn = dev->dev->phys_caps.base_tunnel_sqpn + 8 * tnl_init->slave
104162306a36Sopenharmony_ci			+ tnl_init->proxy_qp_type * 2 + tnl_init->port - 1;
104262306a36Sopenharmony_ci		sqpn = qpn;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	if (init_attr->qp_type == IB_QPT_SMI ||
104662306a36Sopenharmony_ci	    init_attr->qp_type == IB_QPT_GSI || qp_type == MLX4_IB_QPT_SMI ||
104762306a36Sopenharmony_ci	    qp_type == MLX4_IB_QPT_GSI ||
104862306a36Sopenharmony_ci	    (qp_type & (MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_SMI_OWNER |
104962306a36Sopenharmony_ci			MLX4_IB_QPT_PROXY_GSI | MLX4_IB_QPT_TUN_SMI_OWNER))) {
105062306a36Sopenharmony_ci		qp->sqp = kzalloc(sizeof(struct mlx4_ib_sqp), GFP_KERNEL);
105162306a36Sopenharmony_ci		if (!qp->sqp)
105262306a36Sopenharmony_ci			return -ENOMEM;
105362306a36Sopenharmony_ci	}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	qp->mlx4_ib_qp_type = qp_type;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	spin_lock_init(&qp->sq.lock);
105862306a36Sopenharmony_ci	spin_lock_init(&qp->rq.lock);
105962306a36Sopenharmony_ci	INIT_LIST_HEAD(&qp->gid_list);
106062306a36Sopenharmony_ci	INIT_LIST_HEAD(&qp->steering_rules);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	qp->state = IB_QPS_RESET;
106362306a36Sopenharmony_ci	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
106462306a36Sopenharmony_ci		qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	if (udata) {
106762306a36Sopenharmony_ci		struct mlx4_ib_create_qp ucmd;
106862306a36Sopenharmony_ci		size_t copy_len;
106962306a36Sopenharmony_ci		int shift;
107062306a36Sopenharmony_ci		int n;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci		copy_len = sizeof(struct mlx4_ib_create_qp);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci		if (ib_copy_from_udata(&ucmd, udata, copy_len)) {
107562306a36Sopenharmony_ci			err = -EFAULT;
107662306a36Sopenharmony_ci			goto err;
107762306a36Sopenharmony_ci		}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		qp->inl_recv_sz = ucmd.inl_recv_sz;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci		if (init_attr->create_flags & IB_QP_CREATE_SCATTER_FCS) {
108262306a36Sopenharmony_ci			if (!(dev->dev->caps.flags &
108362306a36Sopenharmony_ci			      MLX4_DEV_CAP_FLAG_FCS_KEEP)) {
108462306a36Sopenharmony_ci				pr_debug("scatter FCS is unsupported\n");
108562306a36Sopenharmony_ci				err = -EOPNOTSUPP;
108662306a36Sopenharmony_ci				goto err;
108762306a36Sopenharmony_ci			}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci			qp->flags |= MLX4_IB_QP_SCATTER_FCS;
109062306a36Sopenharmony_ci		}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		err = set_rq_size(dev, &init_attr->cap, udata,
109362306a36Sopenharmony_ci				  qp_has_rq(init_attr), qp, qp->inl_recv_sz);
109462306a36Sopenharmony_ci		if (err)
109562306a36Sopenharmony_ci			goto err;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci		qp->sq_no_prefetch = ucmd.sq_no_prefetch;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci		err = set_user_sq_size(dev, qp, &ucmd);
110062306a36Sopenharmony_ci		if (err)
110162306a36Sopenharmony_ci			goto err;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci		qp->umem =
110462306a36Sopenharmony_ci			ib_umem_get(pd->device, ucmd.buf_addr, qp->buf_size, 0);
110562306a36Sopenharmony_ci		if (IS_ERR(qp->umem)) {
110662306a36Sopenharmony_ci			err = PTR_ERR(qp->umem);
110762306a36Sopenharmony_ci			goto err;
110862306a36Sopenharmony_ci		}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		shift = mlx4_ib_umem_calc_optimal_mtt_size(qp->umem, 0, &n);
111162306a36Sopenharmony_ci		err = mlx4_mtt_init(dev->dev, n, shift, &qp->mtt);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci		if (err)
111462306a36Sopenharmony_ci			goto err_buf;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci		err = mlx4_ib_umem_write_mtt(dev, &qp->mtt, qp->umem);
111762306a36Sopenharmony_ci		if (err)
111862306a36Sopenharmony_ci			goto err_mtt;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci		if (qp_has_rq(init_attr)) {
112162306a36Sopenharmony_ci			err = mlx4_ib_db_map_user(udata, ucmd.db_addr, &qp->db);
112262306a36Sopenharmony_ci			if (err)
112362306a36Sopenharmony_ci				goto err_mtt;
112462306a36Sopenharmony_ci		}
112562306a36Sopenharmony_ci		qp->mqp.usage = MLX4_RES_USAGE_USER_VERBS;
112662306a36Sopenharmony_ci	} else {
112762306a36Sopenharmony_ci		err = set_rq_size(dev, &init_attr->cap, udata,
112862306a36Sopenharmony_ci				  qp_has_rq(init_attr), qp, 0);
112962306a36Sopenharmony_ci		if (err)
113062306a36Sopenharmony_ci			goto err;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci		qp->sq_no_prefetch = 0;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci		if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO)
113562306a36Sopenharmony_ci			qp->flags |= MLX4_IB_QP_LSO;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci		if (init_attr->create_flags & IB_QP_CREATE_NETIF_QP) {
113862306a36Sopenharmony_ci			if (dev->steering_support ==
113962306a36Sopenharmony_ci			    MLX4_STEERING_MODE_DEVICE_MANAGED)
114062306a36Sopenharmony_ci				qp->flags |= MLX4_IB_QP_NETIF;
114162306a36Sopenharmony_ci			else {
114262306a36Sopenharmony_ci				err = -EINVAL;
114362306a36Sopenharmony_ci				goto err;
114462306a36Sopenharmony_ci			}
114562306a36Sopenharmony_ci		}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci		err = set_kernel_sq_size(dev, &init_attr->cap, qp_type, qp);
114862306a36Sopenharmony_ci		if (err)
114962306a36Sopenharmony_ci			goto err;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci		if (qp_has_rq(init_attr)) {
115262306a36Sopenharmony_ci			err = mlx4_db_alloc(dev->dev, &qp->db, 0);
115362306a36Sopenharmony_ci			if (err)
115462306a36Sopenharmony_ci				goto err;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci			*qp->db.db = 0;
115762306a36Sopenharmony_ci		}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci		if (mlx4_buf_alloc(dev->dev, qp->buf_size,  PAGE_SIZE * 2,
116062306a36Sopenharmony_ci				   &qp->buf)) {
116162306a36Sopenharmony_ci			err = -ENOMEM;
116262306a36Sopenharmony_ci			goto err_db;
116362306a36Sopenharmony_ci		}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		err = mlx4_mtt_init(dev->dev, qp->buf.npages, qp->buf.page_shift,
116662306a36Sopenharmony_ci				    &qp->mtt);
116762306a36Sopenharmony_ci		if (err)
116862306a36Sopenharmony_ci			goto err_buf;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci		err = mlx4_buf_write_mtt(dev->dev, &qp->mtt, &qp->buf);
117162306a36Sopenharmony_ci		if (err)
117262306a36Sopenharmony_ci			goto err_mtt;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci		qp->sq.wrid = kvmalloc_array(qp->sq.wqe_cnt,
117562306a36Sopenharmony_ci					     sizeof(u64), GFP_KERNEL);
117662306a36Sopenharmony_ci		qp->rq.wrid = kvmalloc_array(qp->rq.wqe_cnt,
117762306a36Sopenharmony_ci					     sizeof(u64), GFP_KERNEL);
117862306a36Sopenharmony_ci		if (!qp->sq.wrid || !qp->rq.wrid) {
117962306a36Sopenharmony_ci			err = -ENOMEM;
118062306a36Sopenharmony_ci			goto err_wrid;
118162306a36Sopenharmony_ci		}
118262306a36Sopenharmony_ci		qp->mqp.usage = MLX4_RES_USAGE_DRIVER;
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (sqpn) {
118662306a36Sopenharmony_ci		if (qp->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER |
118762306a36Sopenharmony_ci		    MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI)) {
118862306a36Sopenharmony_ci			if (alloc_proxy_bufs(pd->device, qp)) {
118962306a36Sopenharmony_ci				err = -ENOMEM;
119062306a36Sopenharmony_ci				goto err_wrid;
119162306a36Sopenharmony_ci			}
119262306a36Sopenharmony_ci		}
119362306a36Sopenharmony_ci	} else {
119462306a36Sopenharmony_ci		/* Raw packet QPNs may not have bits 6,7 set in their qp_num;
119562306a36Sopenharmony_ci		 * otherwise, the WQE BlueFlame setup flow wrongly causes
119662306a36Sopenharmony_ci		 * VLAN insertion. */
119762306a36Sopenharmony_ci		if (init_attr->qp_type == IB_QPT_RAW_PACKET)
119862306a36Sopenharmony_ci			err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn,
119962306a36Sopenharmony_ci						    (init_attr->cap.max_send_wr ?
120062306a36Sopenharmony_ci						     MLX4_RESERVE_ETH_BF_QP : 0) |
120162306a36Sopenharmony_ci						    (init_attr->cap.max_recv_wr ?
120262306a36Sopenharmony_ci						     MLX4_RESERVE_A0_QP : 0),
120362306a36Sopenharmony_ci						    qp->mqp.usage);
120462306a36Sopenharmony_ci		else
120562306a36Sopenharmony_ci			if (qp->flags & MLX4_IB_QP_NETIF)
120662306a36Sopenharmony_ci				err = mlx4_ib_steer_qp_alloc(dev, 1, &qpn);
120762306a36Sopenharmony_ci			else
120862306a36Sopenharmony_ci				err = mlx4_qp_reserve_range(dev->dev, 1, 1,
120962306a36Sopenharmony_ci							    &qpn, 0, qp->mqp.usage);
121062306a36Sopenharmony_ci		if (err)
121162306a36Sopenharmony_ci			goto err_proxy;
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
121562306a36Sopenharmony_ci		qp->flags |= MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp);
121862306a36Sopenharmony_ci	if (err)
121962306a36Sopenharmony_ci		goto err_qpn;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (init_attr->qp_type == IB_QPT_XRC_TGT)
122262306a36Sopenharmony_ci		qp->mqp.qpn |= (1 << 23);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	/*
122562306a36Sopenharmony_ci	 * Hardware wants QPN written in big-endian order (after
122662306a36Sopenharmony_ci	 * shifting) for send doorbell.  Precompute this value to save
122762306a36Sopenharmony_ci	 * a little bit when posting sends.
122862306a36Sopenharmony_ci	 */
122962306a36Sopenharmony_ci	qp->doorbell_qpn = swab32(qp->mqp.qpn << 8);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	qp->mqp.event = mlx4_ib_qp_event;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
123462306a36Sopenharmony_ci	mlx4_ib_lock_cqs(to_mcq(init_attr->send_cq),
123562306a36Sopenharmony_ci			 to_mcq(init_attr->recv_cq));
123662306a36Sopenharmony_ci	/* Maintain device to QPs access, needed for further handling
123762306a36Sopenharmony_ci	 * via reset flow
123862306a36Sopenharmony_ci	 */
123962306a36Sopenharmony_ci	list_add_tail(&qp->qps_list, &dev->qp_list);
124062306a36Sopenharmony_ci	/* Maintain CQ to QPs access, needed for further handling
124162306a36Sopenharmony_ci	 * via reset flow
124262306a36Sopenharmony_ci	 */
124362306a36Sopenharmony_ci	mcq = to_mcq(init_attr->send_cq);
124462306a36Sopenharmony_ci	list_add_tail(&qp->cq_send_list, &mcq->send_qp_list);
124562306a36Sopenharmony_ci	mcq = to_mcq(init_attr->recv_cq);
124662306a36Sopenharmony_ci	list_add_tail(&qp->cq_recv_list, &mcq->recv_qp_list);
124762306a36Sopenharmony_ci	mlx4_ib_unlock_cqs(to_mcq(init_attr->send_cq),
124862306a36Sopenharmony_ci			   to_mcq(init_attr->recv_cq));
124962306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
125062306a36Sopenharmony_ci	return 0;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_cierr_qpn:
125362306a36Sopenharmony_ci	if (!sqpn) {
125462306a36Sopenharmony_ci		if (qp->flags & MLX4_IB_QP_NETIF)
125562306a36Sopenharmony_ci			mlx4_ib_steer_qp_free(dev, qpn, 1);
125662306a36Sopenharmony_ci		else
125762306a36Sopenharmony_ci			mlx4_qp_release_range(dev->dev, qpn, 1);
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_cierr_proxy:
126062306a36Sopenharmony_ci	if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI)
126162306a36Sopenharmony_ci		free_proxy_bufs(pd->device, qp);
126262306a36Sopenharmony_cierr_wrid:
126362306a36Sopenharmony_ci	if (udata) {
126462306a36Sopenharmony_ci		if (qp_has_rq(init_attr))
126562306a36Sopenharmony_ci			mlx4_ib_db_unmap_user(context, &qp->db);
126662306a36Sopenharmony_ci	} else {
126762306a36Sopenharmony_ci		kvfree(qp->sq.wrid);
126862306a36Sopenharmony_ci		kvfree(qp->rq.wrid);
126962306a36Sopenharmony_ci	}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cierr_mtt:
127262306a36Sopenharmony_ci	mlx4_mtt_cleanup(dev->dev, &qp->mtt);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cierr_buf:
127562306a36Sopenharmony_ci	if (!qp->umem)
127662306a36Sopenharmony_ci		mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
127762306a36Sopenharmony_ci	ib_umem_release(qp->umem);
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cierr_db:
128062306a36Sopenharmony_ci	if (!udata && qp_has_rq(init_attr))
128162306a36Sopenharmony_ci		mlx4_db_free(dev->dev, &qp->db);
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cierr:
128462306a36Sopenharmony_ci	kfree(qp->sqp);
128562306a36Sopenharmony_ci	return err;
128662306a36Sopenharmony_ci}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_cistatic enum mlx4_qp_state to_mlx4_state(enum ib_qp_state state)
128962306a36Sopenharmony_ci{
129062306a36Sopenharmony_ci	switch (state) {
129162306a36Sopenharmony_ci	case IB_QPS_RESET:	return MLX4_QP_STATE_RST;
129262306a36Sopenharmony_ci	case IB_QPS_INIT:	return MLX4_QP_STATE_INIT;
129362306a36Sopenharmony_ci	case IB_QPS_RTR:	return MLX4_QP_STATE_RTR;
129462306a36Sopenharmony_ci	case IB_QPS_RTS:	return MLX4_QP_STATE_RTS;
129562306a36Sopenharmony_ci	case IB_QPS_SQD:	return MLX4_QP_STATE_SQD;
129662306a36Sopenharmony_ci	case IB_QPS_SQE:	return MLX4_QP_STATE_SQER;
129762306a36Sopenharmony_ci	case IB_QPS_ERR:	return MLX4_QP_STATE_ERR;
129862306a36Sopenharmony_ci	default:		return -1;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_cistatic void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)
130362306a36Sopenharmony_ci	__acquires(&send_cq->lock) __acquires(&recv_cq->lock)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	if (send_cq == recv_cq) {
130662306a36Sopenharmony_ci		spin_lock(&send_cq->lock);
130762306a36Sopenharmony_ci		__acquire(&recv_cq->lock);
130862306a36Sopenharmony_ci	} else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
130962306a36Sopenharmony_ci		spin_lock(&send_cq->lock);
131062306a36Sopenharmony_ci		spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
131162306a36Sopenharmony_ci	} else {
131262306a36Sopenharmony_ci		spin_lock(&recv_cq->lock);
131362306a36Sopenharmony_ci		spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cistatic void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)
131862306a36Sopenharmony_ci	__releases(&send_cq->lock) __releases(&recv_cq->lock)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	if (send_cq == recv_cq) {
132162306a36Sopenharmony_ci		__release(&recv_cq->lock);
132262306a36Sopenharmony_ci		spin_unlock(&send_cq->lock);
132362306a36Sopenharmony_ci	} else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
132462306a36Sopenharmony_ci		spin_unlock(&recv_cq->lock);
132562306a36Sopenharmony_ci		spin_unlock(&send_cq->lock);
132662306a36Sopenharmony_ci	} else {
132762306a36Sopenharmony_ci		spin_unlock(&send_cq->lock);
132862306a36Sopenharmony_ci		spin_unlock(&recv_cq->lock);
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_cistatic void del_gid_entries(struct mlx4_ib_qp *qp)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	struct mlx4_ib_gid_entry *ge, *tmp;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
133762306a36Sopenharmony_ci		list_del(&ge->list);
133862306a36Sopenharmony_ci		kfree(ge);
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistatic struct mlx4_ib_pd *get_pd(struct mlx4_ib_qp *qp)
134362306a36Sopenharmony_ci{
134462306a36Sopenharmony_ci	if (qp->ibqp.qp_type == IB_QPT_XRC_TGT)
134562306a36Sopenharmony_ci		return to_mpd(to_mxrcd(qp->ibqp.xrcd)->pd);
134662306a36Sopenharmony_ci	else
134762306a36Sopenharmony_ci		return to_mpd(qp->ibqp.pd);
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic void get_cqs(struct mlx4_ib_qp *qp, enum mlx4_ib_source_type src,
135162306a36Sopenharmony_ci		    struct mlx4_ib_cq **send_cq, struct mlx4_ib_cq **recv_cq)
135262306a36Sopenharmony_ci{
135362306a36Sopenharmony_ci	switch (qp->ibqp.qp_type) {
135462306a36Sopenharmony_ci	case IB_QPT_XRC_TGT:
135562306a36Sopenharmony_ci		*send_cq = to_mcq(to_mxrcd(qp->ibqp.xrcd)->cq);
135662306a36Sopenharmony_ci		*recv_cq = *send_cq;
135762306a36Sopenharmony_ci		break;
135862306a36Sopenharmony_ci	case IB_QPT_XRC_INI:
135962306a36Sopenharmony_ci		*send_cq = to_mcq(qp->ibqp.send_cq);
136062306a36Sopenharmony_ci		*recv_cq = *send_cq;
136162306a36Sopenharmony_ci		break;
136262306a36Sopenharmony_ci	default:
136362306a36Sopenharmony_ci		*recv_cq = (src == MLX4_IB_QP_SRC) ? to_mcq(qp->ibqp.recv_cq) :
136462306a36Sopenharmony_ci						     to_mcq(qp->ibwq.cq);
136562306a36Sopenharmony_ci		*send_cq = (src == MLX4_IB_QP_SRC) ? to_mcq(qp->ibqp.send_cq) :
136662306a36Sopenharmony_ci						     *recv_cq;
136762306a36Sopenharmony_ci		break;
136862306a36Sopenharmony_ci	}
136962306a36Sopenharmony_ci}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_cistatic void destroy_qp_rss(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
137262306a36Sopenharmony_ci{
137362306a36Sopenharmony_ci	if (qp->state != IB_QPS_RESET) {
137462306a36Sopenharmony_ci		int i;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci		for (i = 0; i < (1 << qp->ibqp.rwq_ind_tbl->log_ind_tbl_size);
137762306a36Sopenharmony_ci		     i++) {
137862306a36Sopenharmony_ci			struct ib_wq *ibwq = qp->ibqp.rwq_ind_tbl->ind_tbl[i];
137962306a36Sopenharmony_ci			struct mlx4_ib_qp *wq =	to_mqp((struct ib_qp *)ibwq);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci			mutex_lock(&wq->mutex);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci			wq->rss_usecnt--;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci			mutex_unlock(&wq->mutex);
138662306a36Sopenharmony_ci		}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci		if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state),
138962306a36Sopenharmony_ci				   MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp))
139062306a36Sopenharmony_ci			pr_warn("modify QP %06x to RESET failed.\n",
139162306a36Sopenharmony_ci				qp->mqp.qpn);
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	mlx4_qp_remove(dev->dev, &qp->mqp);
139562306a36Sopenharmony_ci	mlx4_qp_free(dev->dev, &qp->mqp);
139662306a36Sopenharmony_ci	mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1);
139762306a36Sopenharmony_ci	del_gid_entries(qp);
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
140162306a36Sopenharmony_ci			      enum mlx4_ib_source_type src,
140262306a36Sopenharmony_ci			      struct ib_udata *udata)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	struct mlx4_ib_cq *send_cq, *recv_cq;
140562306a36Sopenharmony_ci	unsigned long flags;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	if (qp->state != IB_QPS_RESET) {
140862306a36Sopenharmony_ci		if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state),
140962306a36Sopenharmony_ci				   MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp))
141062306a36Sopenharmony_ci			pr_warn("modify QP %06x to RESET failed.\n",
141162306a36Sopenharmony_ci			       qp->mqp.qpn);
141262306a36Sopenharmony_ci		if (qp->pri.smac || (!qp->pri.smac && qp->pri.smac_port)) {
141362306a36Sopenharmony_ci			mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
141462306a36Sopenharmony_ci			qp->pri.smac = 0;
141562306a36Sopenharmony_ci			qp->pri.smac_port = 0;
141662306a36Sopenharmony_ci		}
141762306a36Sopenharmony_ci		if (qp->alt.smac) {
141862306a36Sopenharmony_ci			mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
141962306a36Sopenharmony_ci			qp->alt.smac = 0;
142062306a36Sopenharmony_ci		}
142162306a36Sopenharmony_ci		if (qp->pri.vid < 0x1000) {
142262306a36Sopenharmony_ci			mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid);
142362306a36Sopenharmony_ci			qp->pri.vid = 0xFFFF;
142462306a36Sopenharmony_ci			qp->pri.candidate_vid = 0xFFFF;
142562306a36Sopenharmony_ci			qp->pri.update_vid = 0;
142662306a36Sopenharmony_ci		}
142762306a36Sopenharmony_ci		if (qp->alt.vid < 0x1000) {
142862306a36Sopenharmony_ci			mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid);
142962306a36Sopenharmony_ci			qp->alt.vid = 0xFFFF;
143062306a36Sopenharmony_ci			qp->alt.candidate_vid = 0xFFFF;
143162306a36Sopenharmony_ci			qp->alt.update_vid = 0;
143262306a36Sopenharmony_ci		}
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	get_cqs(qp, src, &send_cq, &recv_cq);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
143862306a36Sopenharmony_ci	mlx4_ib_lock_cqs(send_cq, recv_cq);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	/* del from lists under both locks above to protect reset flow paths */
144162306a36Sopenharmony_ci	list_del(&qp->qps_list);
144262306a36Sopenharmony_ci	list_del(&qp->cq_send_list);
144362306a36Sopenharmony_ci	list_del(&qp->cq_recv_list);
144462306a36Sopenharmony_ci	if (!udata) {
144562306a36Sopenharmony_ci		__mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
144662306a36Sopenharmony_ci				 qp->ibqp.srq ? to_msrq(qp->ibqp.srq): NULL);
144762306a36Sopenharmony_ci		if (send_cq != recv_cq)
144862306a36Sopenharmony_ci			__mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
144962306a36Sopenharmony_ci	}
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	mlx4_qp_remove(dev->dev, &qp->mqp);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	mlx4_ib_unlock_cqs(send_cq, recv_cq);
145462306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	mlx4_qp_free(dev->dev, &qp->mqp);
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	if (!is_sqp(dev, qp) && !is_tunnel_qp(dev, qp)) {
145962306a36Sopenharmony_ci		if (qp->flags & MLX4_IB_QP_NETIF)
146062306a36Sopenharmony_ci			mlx4_ib_steer_qp_free(dev, qp->mqp.qpn, 1);
146162306a36Sopenharmony_ci		else if (src == MLX4_IB_RWQ_SRC)
146262306a36Sopenharmony_ci			mlx4_ib_release_wqn(
146362306a36Sopenharmony_ci				rdma_udata_to_drv_context(
146462306a36Sopenharmony_ci					udata,
146562306a36Sopenharmony_ci					struct mlx4_ib_ucontext,
146662306a36Sopenharmony_ci					ibucontext),
146762306a36Sopenharmony_ci				qp, 1);
146862306a36Sopenharmony_ci		else
146962306a36Sopenharmony_ci			mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1);
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	mlx4_mtt_cleanup(dev->dev, &qp->mtt);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	if (udata) {
147562306a36Sopenharmony_ci		if (qp->rq.wqe_cnt) {
147662306a36Sopenharmony_ci			struct mlx4_ib_ucontext *mcontext =
147762306a36Sopenharmony_ci				rdma_udata_to_drv_context(
147862306a36Sopenharmony_ci					udata,
147962306a36Sopenharmony_ci					struct mlx4_ib_ucontext,
148062306a36Sopenharmony_ci					ibucontext);
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci			mlx4_ib_db_unmap_user(mcontext, &qp->db);
148362306a36Sopenharmony_ci		}
148462306a36Sopenharmony_ci	} else {
148562306a36Sopenharmony_ci		kvfree(qp->sq.wrid);
148662306a36Sopenharmony_ci		kvfree(qp->rq.wrid);
148762306a36Sopenharmony_ci		if (qp->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER |
148862306a36Sopenharmony_ci		    MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI))
148962306a36Sopenharmony_ci			free_proxy_bufs(&dev->ib_dev, qp);
149062306a36Sopenharmony_ci		mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf);
149162306a36Sopenharmony_ci		if (qp->rq.wqe_cnt)
149262306a36Sopenharmony_ci			mlx4_db_free(dev->dev, &qp->db);
149362306a36Sopenharmony_ci	}
149462306a36Sopenharmony_ci	ib_umem_release(qp->umem);
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	del_gid_entries(qp);
149762306a36Sopenharmony_ci}
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_cistatic u32 get_sqp_num(struct mlx4_ib_dev *dev, struct ib_qp_init_attr *attr)
150062306a36Sopenharmony_ci{
150162306a36Sopenharmony_ci	/* Native or PPF */
150262306a36Sopenharmony_ci	if (!mlx4_is_mfunc(dev->dev) ||
150362306a36Sopenharmony_ci	    (mlx4_is_master(dev->dev) &&
150462306a36Sopenharmony_ci	     attr->create_flags & MLX4_IB_SRIOV_SQP)) {
150562306a36Sopenharmony_ci		return  dev->dev->phys_caps.base_sqpn +
150662306a36Sopenharmony_ci			(attr->qp_type == IB_QPT_SMI ? 0 : 2) +
150762306a36Sopenharmony_ci			attr->port_num - 1;
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci	/* PF or VF -- creating proxies */
151062306a36Sopenharmony_ci	if (attr->qp_type == IB_QPT_SMI)
151162306a36Sopenharmony_ci		return dev->dev->caps.spec_qps[attr->port_num - 1].qp0_proxy;
151262306a36Sopenharmony_ci	else
151362306a36Sopenharmony_ci		return dev->dev->caps.spec_qps[attr->port_num - 1].qp1_proxy;
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_cistatic int _mlx4_ib_create_qp(struct ib_pd *pd, struct mlx4_ib_qp *qp,
151762306a36Sopenharmony_ci			      struct ib_qp_init_attr *init_attr,
151862306a36Sopenharmony_ci			      struct ib_udata *udata)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	int err;
152162306a36Sopenharmony_ci	int sup_u_create_flags = MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK;
152262306a36Sopenharmony_ci	u16 xrcdn = 0;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	if (init_attr->rwq_ind_tbl)
152562306a36Sopenharmony_ci		return _mlx4_ib_create_qp_rss(pd, qp, init_attr, udata);
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	/*
152862306a36Sopenharmony_ci	 * We only support LSO, vendor flag1, and multicast loopback blocking,
152962306a36Sopenharmony_ci	 * and only for kernel UD QPs.
153062306a36Sopenharmony_ci	 */
153162306a36Sopenharmony_ci	if (init_attr->create_flags & ~(MLX4_IB_QP_LSO |
153262306a36Sopenharmony_ci					MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK |
153362306a36Sopenharmony_ci					MLX4_IB_SRIOV_TUNNEL_QP |
153462306a36Sopenharmony_ci					MLX4_IB_SRIOV_SQP |
153562306a36Sopenharmony_ci					MLX4_IB_QP_NETIF |
153662306a36Sopenharmony_ci					MLX4_IB_QP_CREATE_ROCE_V2_GSI))
153762306a36Sopenharmony_ci		return -EOPNOTSUPP;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	if (init_attr->create_flags & IB_QP_CREATE_NETIF_QP) {
154062306a36Sopenharmony_ci		if (init_attr->qp_type != IB_QPT_UD)
154162306a36Sopenharmony_ci			return -EINVAL;
154262306a36Sopenharmony_ci	}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	if (init_attr->create_flags) {
154562306a36Sopenharmony_ci		if (udata && init_attr->create_flags & ~(sup_u_create_flags))
154662306a36Sopenharmony_ci			return -EINVAL;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci		if ((init_attr->create_flags & ~(MLX4_IB_SRIOV_SQP |
154962306a36Sopenharmony_ci						 MLX4_IB_QP_CREATE_ROCE_V2_GSI  |
155062306a36Sopenharmony_ci						 MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK) &&
155162306a36Sopenharmony_ci		     init_attr->qp_type != IB_QPT_UD) ||
155262306a36Sopenharmony_ci		    (init_attr->create_flags & MLX4_IB_SRIOV_SQP &&
155362306a36Sopenharmony_ci		     init_attr->qp_type > IB_QPT_GSI) ||
155462306a36Sopenharmony_ci		    (init_attr->create_flags & MLX4_IB_QP_CREATE_ROCE_V2_GSI &&
155562306a36Sopenharmony_ci		     init_attr->qp_type != IB_QPT_GSI))
155662306a36Sopenharmony_ci			return -EINVAL;
155762306a36Sopenharmony_ci	}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	switch (init_attr->qp_type) {
156062306a36Sopenharmony_ci	case IB_QPT_XRC_TGT:
156162306a36Sopenharmony_ci		pd = to_mxrcd(init_attr->xrcd)->pd;
156262306a36Sopenharmony_ci		xrcdn = to_mxrcd(init_attr->xrcd)->xrcdn;
156362306a36Sopenharmony_ci		init_attr->send_cq = to_mxrcd(init_attr->xrcd)->cq;
156462306a36Sopenharmony_ci		fallthrough;
156562306a36Sopenharmony_ci	case IB_QPT_XRC_INI:
156662306a36Sopenharmony_ci		if (!(to_mdev(pd->device)->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC))
156762306a36Sopenharmony_ci			return -ENOSYS;
156862306a36Sopenharmony_ci		init_attr->recv_cq = init_attr->send_cq;
156962306a36Sopenharmony_ci		fallthrough;
157062306a36Sopenharmony_ci	case IB_QPT_RC:
157162306a36Sopenharmony_ci	case IB_QPT_UC:
157262306a36Sopenharmony_ci	case IB_QPT_RAW_PACKET:
157362306a36Sopenharmony_ci	case IB_QPT_UD:
157462306a36Sopenharmony_ci		qp->pri.vid = 0xFFFF;
157562306a36Sopenharmony_ci		qp->alt.vid = 0xFFFF;
157662306a36Sopenharmony_ci		err = create_qp_common(pd, init_attr, udata, 0, qp);
157762306a36Sopenharmony_ci		if (err)
157862306a36Sopenharmony_ci			return err;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci		qp->ibqp.qp_num = qp->mqp.qpn;
158162306a36Sopenharmony_ci		qp->xrcdn = xrcdn;
158262306a36Sopenharmony_ci		break;
158362306a36Sopenharmony_ci	case IB_QPT_SMI:
158462306a36Sopenharmony_ci	case IB_QPT_GSI:
158562306a36Sopenharmony_ci	{
158662306a36Sopenharmony_ci		int sqpn;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci		if (init_attr->create_flags & MLX4_IB_QP_CREATE_ROCE_V2_GSI) {
158962306a36Sopenharmony_ci			int res = mlx4_qp_reserve_range(to_mdev(pd->device)->dev,
159062306a36Sopenharmony_ci							1, 1, &sqpn, 0,
159162306a36Sopenharmony_ci							MLX4_RES_USAGE_DRIVER);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci			if (res)
159462306a36Sopenharmony_ci				return res;
159562306a36Sopenharmony_ci		} else {
159662306a36Sopenharmony_ci			sqpn = get_sqp_num(to_mdev(pd->device), init_attr);
159762306a36Sopenharmony_ci		}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci		qp->pri.vid = 0xFFFF;
160062306a36Sopenharmony_ci		qp->alt.vid = 0xFFFF;
160162306a36Sopenharmony_ci		err = create_qp_common(pd, init_attr, udata, sqpn, qp);
160262306a36Sopenharmony_ci		if (err)
160362306a36Sopenharmony_ci			return err;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci		if (init_attr->create_flags &
160662306a36Sopenharmony_ci		    (MLX4_IB_SRIOV_SQP | MLX4_IB_SRIOV_TUNNEL_QP))
160762306a36Sopenharmony_ci			/* Internal QP created with ib_create_qp */
160862306a36Sopenharmony_ci			rdma_restrack_no_track(&qp->ibqp.res);
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci		qp->port	= init_attr->port_num;
161162306a36Sopenharmony_ci		qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 :
161262306a36Sopenharmony_ci			init_attr->create_flags & MLX4_IB_QP_CREATE_ROCE_V2_GSI ? sqpn : 1;
161362306a36Sopenharmony_ci		break;
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci	default:
161662306a36Sopenharmony_ci		/* Don't support raw QPs */
161762306a36Sopenharmony_ci		return -EOPNOTSUPP;
161862306a36Sopenharmony_ci	}
161962306a36Sopenharmony_ci	return 0;
162062306a36Sopenharmony_ci}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ciint mlx4_ib_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr,
162362306a36Sopenharmony_ci		      struct ib_udata *udata)
162462306a36Sopenharmony_ci{
162562306a36Sopenharmony_ci	struct ib_device *device = ibqp->device;
162662306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(device);
162762306a36Sopenharmony_ci	struct mlx4_ib_qp *qp = to_mqp(ibqp);
162862306a36Sopenharmony_ci	struct ib_pd *pd = ibqp->pd;
162962306a36Sopenharmony_ci	int ret;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	mutex_init(&qp->mutex);
163262306a36Sopenharmony_ci	ret = _mlx4_ib_create_qp(pd, qp, init_attr, udata);
163362306a36Sopenharmony_ci	if (ret)
163462306a36Sopenharmony_ci		return ret;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	if (init_attr->qp_type == IB_QPT_GSI &&
163762306a36Sopenharmony_ci	    !(init_attr->create_flags & MLX4_IB_QP_CREATE_ROCE_V2_GSI)) {
163862306a36Sopenharmony_ci		struct mlx4_ib_sqp *sqp = qp->sqp;
163962306a36Sopenharmony_ci		int is_eth = rdma_cap_eth_ah(&dev->ib_dev, init_attr->port_num);
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci		if (is_eth &&
164262306a36Sopenharmony_ci		    dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) {
164362306a36Sopenharmony_ci			init_attr->create_flags |= MLX4_IB_QP_CREATE_ROCE_V2_GSI;
164462306a36Sopenharmony_ci			sqp->roce_v2_gsi = ib_create_qp(pd, init_attr);
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci			if (IS_ERR(sqp->roce_v2_gsi)) {
164762306a36Sopenharmony_ci				pr_err("Failed to create GSI QP for RoCEv2 (%ld)\n", PTR_ERR(sqp->roce_v2_gsi));
164862306a36Sopenharmony_ci				sqp->roce_v2_gsi = NULL;
164962306a36Sopenharmony_ci			} else {
165062306a36Sopenharmony_ci				to_mqp(sqp->roce_v2_gsi)->flags |=
165162306a36Sopenharmony_ci					MLX4_IB_ROCE_V2_GSI_QP;
165262306a36Sopenharmony_ci			}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci			init_attr->create_flags &= ~MLX4_IB_QP_CREATE_ROCE_V2_GSI;
165562306a36Sopenharmony_ci		}
165662306a36Sopenharmony_ci	}
165762306a36Sopenharmony_ci	return 0;
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_cistatic int _mlx4_ib_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
166162306a36Sopenharmony_ci{
166262306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(qp->device);
166362306a36Sopenharmony_ci	struct mlx4_ib_qp *mqp = to_mqp(qp);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	if (is_qp0(dev, mqp))
166662306a36Sopenharmony_ci		mlx4_CLOSE_PORT(dev->dev, mqp->port);
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	if (mqp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI &&
166962306a36Sopenharmony_ci	    dev->qp1_proxy[mqp->port - 1] == mqp) {
167062306a36Sopenharmony_ci		mutex_lock(&dev->qp1_proxy_lock[mqp->port - 1]);
167162306a36Sopenharmony_ci		dev->qp1_proxy[mqp->port - 1] = NULL;
167262306a36Sopenharmony_ci		mutex_unlock(&dev->qp1_proxy_lock[mqp->port - 1]);
167362306a36Sopenharmony_ci	}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	if (mqp->counter_index)
167662306a36Sopenharmony_ci		mlx4_ib_free_qp_counter(dev, mqp);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	if (qp->rwq_ind_tbl) {
167962306a36Sopenharmony_ci		destroy_qp_rss(dev, mqp);
168062306a36Sopenharmony_ci	} else {
168162306a36Sopenharmony_ci		destroy_qp_common(dev, mqp, MLX4_IB_QP_SRC, udata);
168262306a36Sopenharmony_ci	}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	kfree(mqp->sqp);
168562306a36Sopenharmony_ci	return 0;
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ciint mlx4_ib_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
168962306a36Sopenharmony_ci{
169062306a36Sopenharmony_ci	struct mlx4_ib_qp *mqp = to_mqp(qp);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	if (mqp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI) {
169362306a36Sopenharmony_ci		struct mlx4_ib_sqp *sqp = mqp->sqp;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci		if (sqp->roce_v2_gsi)
169662306a36Sopenharmony_ci			ib_destroy_qp(sqp->roce_v2_gsi);
169762306a36Sopenharmony_ci	}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	return _mlx4_ib_destroy_qp(qp, udata);
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_cistatic int to_mlx4_st(struct mlx4_ib_dev *dev, enum mlx4_ib_qp_type type)
170362306a36Sopenharmony_ci{
170462306a36Sopenharmony_ci	switch (type) {
170562306a36Sopenharmony_ci	case MLX4_IB_QPT_RC:		return MLX4_QP_ST_RC;
170662306a36Sopenharmony_ci	case MLX4_IB_QPT_UC:		return MLX4_QP_ST_UC;
170762306a36Sopenharmony_ci	case MLX4_IB_QPT_UD:		return MLX4_QP_ST_UD;
170862306a36Sopenharmony_ci	case MLX4_IB_QPT_XRC_INI:
170962306a36Sopenharmony_ci	case MLX4_IB_QPT_XRC_TGT:	return MLX4_QP_ST_XRC;
171062306a36Sopenharmony_ci	case MLX4_IB_QPT_SMI:
171162306a36Sopenharmony_ci	case MLX4_IB_QPT_GSI:
171262306a36Sopenharmony_ci	case MLX4_IB_QPT_RAW_PACKET:	return MLX4_QP_ST_MLX;
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	case MLX4_IB_QPT_PROXY_SMI_OWNER:
171562306a36Sopenharmony_ci	case MLX4_IB_QPT_TUN_SMI_OWNER:	return (mlx4_is_mfunc(dev->dev) ?
171662306a36Sopenharmony_ci						MLX4_QP_ST_MLX : -1);
171762306a36Sopenharmony_ci	case MLX4_IB_QPT_PROXY_SMI:
171862306a36Sopenharmony_ci	case MLX4_IB_QPT_TUN_SMI:
171962306a36Sopenharmony_ci	case MLX4_IB_QPT_PROXY_GSI:
172062306a36Sopenharmony_ci	case MLX4_IB_QPT_TUN_GSI:	return (mlx4_is_mfunc(dev->dev) ?
172162306a36Sopenharmony_ci						MLX4_QP_ST_UD : -1);
172262306a36Sopenharmony_ci	default:			return -1;
172362306a36Sopenharmony_ci	}
172462306a36Sopenharmony_ci}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_cistatic __be32 to_mlx4_access_flags(struct mlx4_ib_qp *qp, const struct ib_qp_attr *attr,
172762306a36Sopenharmony_ci				   int attr_mask)
172862306a36Sopenharmony_ci{
172962306a36Sopenharmony_ci	u8 dest_rd_atomic;
173062306a36Sopenharmony_ci	u32 access_flags;
173162306a36Sopenharmony_ci	u32 hw_access_flags = 0;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
173462306a36Sopenharmony_ci		dest_rd_atomic = attr->max_dest_rd_atomic;
173562306a36Sopenharmony_ci	else
173662306a36Sopenharmony_ci		dest_rd_atomic = qp->resp_depth;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	if (attr_mask & IB_QP_ACCESS_FLAGS)
173962306a36Sopenharmony_ci		access_flags = attr->qp_access_flags;
174062306a36Sopenharmony_ci	else
174162306a36Sopenharmony_ci		access_flags = qp->atomic_rd_en;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	if (!dest_rd_atomic)
174462306a36Sopenharmony_ci		access_flags &= IB_ACCESS_REMOTE_WRITE;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	if (access_flags & IB_ACCESS_REMOTE_READ)
174762306a36Sopenharmony_ci		hw_access_flags |= MLX4_QP_BIT_RRE;
174862306a36Sopenharmony_ci	if (access_flags & IB_ACCESS_REMOTE_ATOMIC)
174962306a36Sopenharmony_ci		hw_access_flags |= MLX4_QP_BIT_RAE;
175062306a36Sopenharmony_ci	if (access_flags & IB_ACCESS_REMOTE_WRITE)
175162306a36Sopenharmony_ci		hw_access_flags |= MLX4_QP_BIT_RWE;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	return cpu_to_be32(hw_access_flags);
175462306a36Sopenharmony_ci}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_cistatic void store_sqp_attrs(struct mlx4_ib_sqp *sqp, const struct ib_qp_attr *attr,
175762306a36Sopenharmony_ci			    int attr_mask)
175862306a36Sopenharmony_ci{
175962306a36Sopenharmony_ci	if (attr_mask & IB_QP_PKEY_INDEX)
176062306a36Sopenharmony_ci		sqp->pkey_index = attr->pkey_index;
176162306a36Sopenharmony_ci	if (attr_mask & IB_QP_QKEY)
176262306a36Sopenharmony_ci		sqp->qkey = attr->qkey;
176362306a36Sopenharmony_ci	if (attr_mask & IB_QP_SQ_PSN)
176462306a36Sopenharmony_ci		sqp->send_psn = attr->sq_psn;
176562306a36Sopenharmony_ci}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_cistatic void mlx4_set_sched(struct mlx4_qp_path *path, u8 port)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	path->sched_queue = (path->sched_queue & 0xbf) | ((port - 1) << 6);
177062306a36Sopenharmony_ci}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_cistatic int _mlx4_set_path(struct mlx4_ib_dev *dev,
177362306a36Sopenharmony_ci			  const struct rdma_ah_attr *ah,
177462306a36Sopenharmony_ci			  u64 smac, u16 vlan_tag, struct mlx4_qp_path *path,
177562306a36Sopenharmony_ci			  struct mlx4_roce_smac_vlan_info *smac_info, u8 port)
177662306a36Sopenharmony_ci{
177762306a36Sopenharmony_ci	int vidx;
177862306a36Sopenharmony_ci	int smac_index;
177962306a36Sopenharmony_ci	int err;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	path->grh_mylmc = rdma_ah_get_path_bits(ah) & 0x7f;
178262306a36Sopenharmony_ci	path->rlid = cpu_to_be16(rdma_ah_get_dlid(ah));
178362306a36Sopenharmony_ci	if (rdma_ah_get_static_rate(ah)) {
178462306a36Sopenharmony_ci		path->static_rate = rdma_ah_get_static_rate(ah) +
178562306a36Sopenharmony_ci				    MLX4_STAT_RATE_OFFSET;
178662306a36Sopenharmony_ci		while (path->static_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
178762306a36Sopenharmony_ci		       !(1 << path->static_rate & dev->dev->caps.stat_rate_support))
178862306a36Sopenharmony_ci			--path->static_rate;
178962306a36Sopenharmony_ci	} else
179062306a36Sopenharmony_ci		path->static_rate = 0;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	if (rdma_ah_get_ah_flags(ah) & IB_AH_GRH) {
179362306a36Sopenharmony_ci		const struct ib_global_route *grh = rdma_ah_read_grh(ah);
179462306a36Sopenharmony_ci		int real_sgid_index =
179562306a36Sopenharmony_ci			mlx4_ib_gid_index_to_real_index(dev, grh->sgid_attr);
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci		if (real_sgid_index < 0)
179862306a36Sopenharmony_ci			return real_sgid_index;
179962306a36Sopenharmony_ci		if (real_sgid_index >= dev->dev->caps.gid_table_len[port]) {
180062306a36Sopenharmony_ci			pr_err("sgid_index (%u) too large. max is %d\n",
180162306a36Sopenharmony_ci			       real_sgid_index, dev->dev->caps.gid_table_len[port] - 1);
180262306a36Sopenharmony_ci			return -1;
180362306a36Sopenharmony_ci		}
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci		path->grh_mylmc |= 1 << 7;
180662306a36Sopenharmony_ci		path->mgid_index = real_sgid_index;
180762306a36Sopenharmony_ci		path->hop_limit  = grh->hop_limit;
180862306a36Sopenharmony_ci		path->tclass_flowlabel =
180962306a36Sopenharmony_ci			cpu_to_be32((grh->traffic_class << 20) |
181062306a36Sopenharmony_ci				    (grh->flow_label));
181162306a36Sopenharmony_ci		memcpy(path->rgid, grh->dgid.raw, 16);
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	if (ah->type == RDMA_AH_ATTR_TYPE_ROCE) {
181562306a36Sopenharmony_ci		if (!(rdma_ah_get_ah_flags(ah) & IB_AH_GRH))
181662306a36Sopenharmony_ci			return -1;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci		path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
181962306a36Sopenharmony_ci			((port - 1) << 6) | ((rdma_ah_get_sl(ah) & 7) << 3);
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci		path->feup |= MLX4_FEUP_FORCE_ETH_UP;
182262306a36Sopenharmony_ci		if (vlan_tag < 0x1000) {
182362306a36Sopenharmony_ci			if (smac_info->vid < 0x1000) {
182462306a36Sopenharmony_ci				/* both valid vlan ids */
182562306a36Sopenharmony_ci				if (smac_info->vid != vlan_tag) {
182662306a36Sopenharmony_ci					/* different VIDs.  unreg old and reg new */
182762306a36Sopenharmony_ci					err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx);
182862306a36Sopenharmony_ci					if (err)
182962306a36Sopenharmony_ci						return err;
183062306a36Sopenharmony_ci					smac_info->candidate_vid = vlan_tag;
183162306a36Sopenharmony_ci					smac_info->candidate_vlan_index = vidx;
183262306a36Sopenharmony_ci					smac_info->candidate_vlan_port = port;
183362306a36Sopenharmony_ci					smac_info->update_vid = 1;
183462306a36Sopenharmony_ci					path->vlan_index = vidx;
183562306a36Sopenharmony_ci				} else {
183662306a36Sopenharmony_ci					path->vlan_index = smac_info->vlan_index;
183762306a36Sopenharmony_ci				}
183862306a36Sopenharmony_ci			} else {
183962306a36Sopenharmony_ci				/* no current vlan tag in qp */
184062306a36Sopenharmony_ci				err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx);
184162306a36Sopenharmony_ci				if (err)
184262306a36Sopenharmony_ci					return err;
184362306a36Sopenharmony_ci				smac_info->candidate_vid = vlan_tag;
184462306a36Sopenharmony_ci				smac_info->candidate_vlan_index = vidx;
184562306a36Sopenharmony_ci				smac_info->candidate_vlan_port = port;
184662306a36Sopenharmony_ci				smac_info->update_vid = 1;
184762306a36Sopenharmony_ci				path->vlan_index = vidx;
184862306a36Sopenharmony_ci			}
184962306a36Sopenharmony_ci			path->feup |= MLX4_FVL_FORCE_ETH_VLAN;
185062306a36Sopenharmony_ci			path->fl = 1 << 6;
185162306a36Sopenharmony_ci		} else {
185262306a36Sopenharmony_ci			/* have current vlan tag. unregister it at modify-qp success */
185362306a36Sopenharmony_ci			if (smac_info->vid < 0x1000) {
185462306a36Sopenharmony_ci				smac_info->candidate_vid = 0xFFFF;
185562306a36Sopenharmony_ci				smac_info->update_vid = 1;
185662306a36Sopenharmony_ci			}
185762306a36Sopenharmony_ci		}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci		/* get smac_index for RoCE use.
186062306a36Sopenharmony_ci		 * If no smac was yet assigned, register one.
186162306a36Sopenharmony_ci		 * If one was already assigned, but the new mac differs,
186262306a36Sopenharmony_ci		 * unregister the old one and register the new one.
186362306a36Sopenharmony_ci		*/
186462306a36Sopenharmony_ci		if ((!smac_info->smac && !smac_info->smac_port) ||
186562306a36Sopenharmony_ci		    smac_info->smac != smac) {
186662306a36Sopenharmony_ci			/* register candidate now, unreg if needed, after success */
186762306a36Sopenharmony_ci			smac_index = mlx4_register_mac(dev->dev, port, smac);
186862306a36Sopenharmony_ci			if (smac_index >= 0) {
186962306a36Sopenharmony_ci				smac_info->candidate_smac_index = smac_index;
187062306a36Sopenharmony_ci				smac_info->candidate_smac = smac;
187162306a36Sopenharmony_ci				smac_info->candidate_smac_port = port;
187262306a36Sopenharmony_ci			} else {
187362306a36Sopenharmony_ci				return -EINVAL;
187462306a36Sopenharmony_ci			}
187562306a36Sopenharmony_ci		} else {
187662306a36Sopenharmony_ci			smac_index = smac_info->smac_index;
187762306a36Sopenharmony_ci		}
187862306a36Sopenharmony_ci		memcpy(path->dmac, ah->roce.dmac, 6);
187962306a36Sopenharmony_ci		path->ackto = MLX4_IB_LINK_TYPE_ETH;
188062306a36Sopenharmony_ci		/* put MAC table smac index for IBoE */
188162306a36Sopenharmony_ci		path->grh_mylmc = (u8) (smac_index) | 0x80;
188262306a36Sopenharmony_ci	} else {
188362306a36Sopenharmony_ci		path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
188462306a36Sopenharmony_ci			((port - 1) << 6) | ((rdma_ah_get_sl(ah) & 0xf) << 2);
188562306a36Sopenharmony_ci	}
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	return 0;
188862306a36Sopenharmony_ci}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_cistatic int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_qp_attr *qp,
189162306a36Sopenharmony_ci			 enum ib_qp_attr_mask qp_attr_mask,
189262306a36Sopenharmony_ci			 struct mlx4_ib_qp *mqp,
189362306a36Sopenharmony_ci			 struct mlx4_qp_path *path, u8 port,
189462306a36Sopenharmony_ci			 u16 vlan_id, u8 *smac)
189562306a36Sopenharmony_ci{
189662306a36Sopenharmony_ci	return _mlx4_set_path(dev, &qp->ah_attr,
189762306a36Sopenharmony_ci			      ether_addr_to_u64(smac),
189862306a36Sopenharmony_ci			      vlan_id,
189962306a36Sopenharmony_ci			      path, &mqp->pri, port);
190062306a36Sopenharmony_ci}
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_cistatic int mlx4_set_alt_path(struct mlx4_ib_dev *dev,
190362306a36Sopenharmony_ci			     const struct ib_qp_attr *qp,
190462306a36Sopenharmony_ci			     enum ib_qp_attr_mask qp_attr_mask,
190562306a36Sopenharmony_ci			     struct mlx4_ib_qp *mqp,
190662306a36Sopenharmony_ci			     struct mlx4_qp_path *path, u8 port)
190762306a36Sopenharmony_ci{
190862306a36Sopenharmony_ci	return _mlx4_set_path(dev, &qp->alt_ah_attr,
190962306a36Sopenharmony_ci			      0,
191062306a36Sopenharmony_ci			      0xffff,
191162306a36Sopenharmony_ci			      path, &mqp->alt, port);
191262306a36Sopenharmony_ci}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_cistatic void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
191562306a36Sopenharmony_ci{
191662306a36Sopenharmony_ci	struct mlx4_ib_gid_entry *ge, *tmp;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
191962306a36Sopenharmony_ci		if (!ge->added && mlx4_ib_add_mc(dev, qp, &ge->gid)) {
192062306a36Sopenharmony_ci			ge->added = 1;
192162306a36Sopenharmony_ci			ge->port = qp->port;
192262306a36Sopenharmony_ci		}
192362306a36Sopenharmony_ci	}
192462306a36Sopenharmony_ci}
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_cistatic int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev,
192762306a36Sopenharmony_ci				    struct mlx4_ib_qp *qp,
192862306a36Sopenharmony_ci				    struct mlx4_qp_context *context)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	u64 u64_mac;
193162306a36Sopenharmony_ci	int smac_index;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	u64_mac = atomic64_read(&dev->iboe.mac[qp->port - 1]);
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	context->pri_path.sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | ((qp->port - 1) << 6);
193662306a36Sopenharmony_ci	if (!qp->pri.smac && !qp->pri.smac_port) {
193762306a36Sopenharmony_ci		smac_index = mlx4_register_mac(dev->dev, qp->port, u64_mac);
193862306a36Sopenharmony_ci		if (smac_index >= 0) {
193962306a36Sopenharmony_ci			qp->pri.candidate_smac_index = smac_index;
194062306a36Sopenharmony_ci			qp->pri.candidate_smac = u64_mac;
194162306a36Sopenharmony_ci			qp->pri.candidate_smac_port = qp->port;
194262306a36Sopenharmony_ci			context->pri_path.grh_mylmc = 0x80 | (u8) smac_index;
194362306a36Sopenharmony_ci		} else {
194462306a36Sopenharmony_ci			return -ENOENT;
194562306a36Sopenharmony_ci		}
194662306a36Sopenharmony_ci	}
194762306a36Sopenharmony_ci	return 0;
194862306a36Sopenharmony_ci}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_cistatic int create_qp_lb_counter(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
195162306a36Sopenharmony_ci{
195262306a36Sopenharmony_ci	struct counter_index *new_counter_index;
195362306a36Sopenharmony_ci	int err;
195462306a36Sopenharmony_ci	u32 tmp_idx;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	if (rdma_port_get_link_layer(&dev->ib_dev, qp->port) !=
195762306a36Sopenharmony_ci	    IB_LINK_LAYER_ETHERNET ||
195862306a36Sopenharmony_ci	    !(qp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK) ||
195962306a36Sopenharmony_ci	    !(dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_LB_SRC_CHK))
196062306a36Sopenharmony_ci		return 0;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	err = mlx4_counter_alloc(dev->dev, &tmp_idx, MLX4_RES_USAGE_DRIVER);
196362306a36Sopenharmony_ci	if (err)
196462306a36Sopenharmony_ci		return err;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	new_counter_index = kmalloc(sizeof(*new_counter_index), GFP_KERNEL);
196762306a36Sopenharmony_ci	if (!new_counter_index) {
196862306a36Sopenharmony_ci		mlx4_counter_free(dev->dev, tmp_idx);
196962306a36Sopenharmony_ci		return -ENOMEM;
197062306a36Sopenharmony_ci	}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	new_counter_index->index = tmp_idx;
197362306a36Sopenharmony_ci	new_counter_index->allocated = 1;
197462306a36Sopenharmony_ci	qp->counter_index = new_counter_index;
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	mutex_lock(&dev->counters_table[qp->port - 1].mutex);
197762306a36Sopenharmony_ci	list_add_tail(&new_counter_index->list,
197862306a36Sopenharmony_ci		      &dev->counters_table[qp->port - 1].counters_list);
197962306a36Sopenharmony_ci	mutex_unlock(&dev->counters_table[qp->port - 1].mutex);
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	return 0;
198262306a36Sopenharmony_ci}
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_cienum {
198562306a36Sopenharmony_ci	MLX4_QPC_ROCE_MODE_1 = 0,
198662306a36Sopenharmony_ci	MLX4_QPC_ROCE_MODE_2 = 2,
198762306a36Sopenharmony_ci	MLX4_QPC_ROCE_MODE_UNDEFINED = 0xff
198862306a36Sopenharmony_ci};
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_cistatic u8 gid_type_to_qpc(enum ib_gid_type gid_type)
199162306a36Sopenharmony_ci{
199262306a36Sopenharmony_ci	switch (gid_type) {
199362306a36Sopenharmony_ci	case IB_GID_TYPE_ROCE:
199462306a36Sopenharmony_ci		return MLX4_QPC_ROCE_MODE_1;
199562306a36Sopenharmony_ci	case IB_GID_TYPE_ROCE_UDP_ENCAP:
199662306a36Sopenharmony_ci		return MLX4_QPC_ROCE_MODE_2;
199762306a36Sopenharmony_ci	default:
199862306a36Sopenharmony_ci		return MLX4_QPC_ROCE_MODE_UNDEFINED;
199962306a36Sopenharmony_ci	}
200062306a36Sopenharmony_ci}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci/*
200362306a36Sopenharmony_ci * Go over all RSS QP's childes (WQs) and apply their HW state according to
200462306a36Sopenharmony_ci * their logic state if the RSS QP is the first RSS QP associated for the WQ.
200562306a36Sopenharmony_ci */
200662306a36Sopenharmony_cistatic int bringup_rss_rwqs(struct ib_rwq_ind_table *ind_tbl, u8 port_num,
200762306a36Sopenharmony_ci			    struct ib_udata *udata)
200862306a36Sopenharmony_ci{
200962306a36Sopenharmony_ci	int err = 0;
201062306a36Sopenharmony_ci	int i;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	for (i = 0; i < (1 << ind_tbl->log_ind_tbl_size); i++) {
201362306a36Sopenharmony_ci		struct ib_wq *ibwq = ind_tbl->ind_tbl[i];
201462306a36Sopenharmony_ci		struct mlx4_ib_qp *wq = to_mqp((struct ib_qp *)ibwq);
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci		mutex_lock(&wq->mutex);
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci		/* Mlx4_ib restrictions:
201962306a36Sopenharmony_ci		 * WQ's is associated to a port according to the RSS QP it is
202062306a36Sopenharmony_ci		 * associates to.
202162306a36Sopenharmony_ci		 * In case the WQ is associated to a different port by another
202262306a36Sopenharmony_ci		 * RSS QP, return a failure.
202362306a36Sopenharmony_ci		 */
202462306a36Sopenharmony_ci		if ((wq->rss_usecnt > 0) && (wq->port != port_num)) {
202562306a36Sopenharmony_ci			err = -EINVAL;
202662306a36Sopenharmony_ci			mutex_unlock(&wq->mutex);
202762306a36Sopenharmony_ci			break;
202862306a36Sopenharmony_ci		}
202962306a36Sopenharmony_ci		wq->port = port_num;
203062306a36Sopenharmony_ci		if ((wq->rss_usecnt == 0) && (ibwq->state == IB_WQS_RDY)) {
203162306a36Sopenharmony_ci			err = _mlx4_ib_modify_wq(ibwq, IB_WQS_RDY, udata);
203262306a36Sopenharmony_ci			if (err) {
203362306a36Sopenharmony_ci				mutex_unlock(&wq->mutex);
203462306a36Sopenharmony_ci				break;
203562306a36Sopenharmony_ci			}
203662306a36Sopenharmony_ci		}
203762306a36Sopenharmony_ci		wq->rss_usecnt++;
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci		mutex_unlock(&wq->mutex);
204062306a36Sopenharmony_ci	}
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	if (i && err) {
204362306a36Sopenharmony_ci		int j;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci		for (j = (i - 1); j >= 0; j--) {
204662306a36Sopenharmony_ci			struct ib_wq *ibwq = ind_tbl->ind_tbl[j];
204762306a36Sopenharmony_ci			struct mlx4_ib_qp *wq = to_mqp((struct ib_qp *)ibwq);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci			mutex_lock(&wq->mutex);
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci			if ((wq->rss_usecnt == 1) &&
205262306a36Sopenharmony_ci			    (ibwq->state == IB_WQS_RDY))
205362306a36Sopenharmony_ci				if (_mlx4_ib_modify_wq(ibwq, IB_WQS_RESET,
205462306a36Sopenharmony_ci						       udata))
205562306a36Sopenharmony_ci					pr_warn("failed to reverse WQN=0x%06x\n",
205662306a36Sopenharmony_ci						ibwq->wq_num);
205762306a36Sopenharmony_ci			wq->rss_usecnt--;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci			mutex_unlock(&wq->mutex);
206062306a36Sopenharmony_ci		}
206162306a36Sopenharmony_ci	}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	return err;
206462306a36Sopenharmony_ci}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_cistatic void bring_down_rss_rwqs(struct ib_rwq_ind_table *ind_tbl,
206762306a36Sopenharmony_ci				struct ib_udata *udata)
206862306a36Sopenharmony_ci{
206962306a36Sopenharmony_ci	int i;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	for (i = 0; i < (1 << ind_tbl->log_ind_tbl_size); i++) {
207262306a36Sopenharmony_ci		struct ib_wq *ibwq = ind_tbl->ind_tbl[i];
207362306a36Sopenharmony_ci		struct mlx4_ib_qp *wq = to_mqp((struct ib_qp *)ibwq);
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci		mutex_lock(&wq->mutex);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci		if ((wq->rss_usecnt == 1) && (ibwq->state == IB_WQS_RDY))
207862306a36Sopenharmony_ci			if (_mlx4_ib_modify_wq(ibwq, IB_WQS_RESET, udata))
207962306a36Sopenharmony_ci				pr_warn("failed to reverse WQN=%x\n",
208062306a36Sopenharmony_ci					ibwq->wq_num);
208162306a36Sopenharmony_ci		wq->rss_usecnt--;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci		mutex_unlock(&wq->mutex);
208462306a36Sopenharmony_ci	}
208562306a36Sopenharmony_ci}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_cistatic void fill_qp_rss_context(struct mlx4_qp_context *context,
208862306a36Sopenharmony_ci				struct mlx4_ib_qp *qp)
208962306a36Sopenharmony_ci{
209062306a36Sopenharmony_ci	struct mlx4_rss_context *rss_context;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	rss_context = (void *)context + offsetof(struct mlx4_qp_context,
209362306a36Sopenharmony_ci			pri_path) + MLX4_RSS_OFFSET_IN_QPC_PRI_PATH;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	rss_context->base_qpn = cpu_to_be32(qp->rss_ctx->base_qpn_tbl_sz);
209662306a36Sopenharmony_ci	rss_context->default_qpn =
209762306a36Sopenharmony_ci		cpu_to_be32(qp->rss_ctx->base_qpn_tbl_sz & 0xffffff);
209862306a36Sopenharmony_ci	if (qp->rss_ctx->flags & (MLX4_RSS_UDP_IPV4 | MLX4_RSS_UDP_IPV6))
209962306a36Sopenharmony_ci		rss_context->base_qpn_udp = rss_context->default_qpn;
210062306a36Sopenharmony_ci	rss_context->flags = qp->rss_ctx->flags;
210162306a36Sopenharmony_ci	/* Currently support just toeplitz */
210262306a36Sopenharmony_ci	rss_context->hash_fn = MLX4_RSS_HASH_TOP;
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	memcpy(rss_context->rss_key, qp->rss_ctx->rss_key,
210562306a36Sopenharmony_ci	       MLX4_EN_RSS_KEY_SIZE);
210662306a36Sopenharmony_ci}
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_cistatic int __mlx4_ib_modify_qp(void *src, enum mlx4_ib_source_type src_type,
210962306a36Sopenharmony_ci			       const struct ib_qp_attr *attr, int attr_mask,
211062306a36Sopenharmony_ci			       enum ib_qp_state cur_state,
211162306a36Sopenharmony_ci			       enum ib_qp_state new_state,
211262306a36Sopenharmony_ci			       struct ib_udata *udata)
211362306a36Sopenharmony_ci{
211462306a36Sopenharmony_ci	struct ib_srq  *ibsrq;
211562306a36Sopenharmony_ci	const struct ib_gid_attr *gid_attr = NULL;
211662306a36Sopenharmony_ci	struct ib_rwq_ind_table *rwq_ind_tbl;
211762306a36Sopenharmony_ci	enum ib_qp_type qp_type;
211862306a36Sopenharmony_ci	struct mlx4_ib_dev *dev;
211962306a36Sopenharmony_ci	struct mlx4_ib_qp *qp;
212062306a36Sopenharmony_ci	struct mlx4_ib_pd *pd;
212162306a36Sopenharmony_ci	struct mlx4_ib_cq *send_cq, *recv_cq;
212262306a36Sopenharmony_ci	struct mlx4_ib_ucontext *ucontext = rdma_udata_to_drv_context(
212362306a36Sopenharmony_ci		udata, struct mlx4_ib_ucontext, ibucontext);
212462306a36Sopenharmony_ci	struct mlx4_qp_context *context;
212562306a36Sopenharmony_ci	enum mlx4_qp_optpar optpar = 0;
212662306a36Sopenharmony_ci	int sqd_event;
212762306a36Sopenharmony_ci	int steer_qp = 0;
212862306a36Sopenharmony_ci	int err = -EINVAL;
212962306a36Sopenharmony_ci	int counter_index;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	if (src_type == MLX4_IB_RWQ_SRC) {
213262306a36Sopenharmony_ci		struct ib_wq *ibwq;
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci		ibwq	    = (struct ib_wq *)src;
213562306a36Sopenharmony_ci		ibsrq	    = NULL;
213662306a36Sopenharmony_ci		rwq_ind_tbl = NULL;
213762306a36Sopenharmony_ci		qp_type     = IB_QPT_RAW_PACKET;
213862306a36Sopenharmony_ci		qp	    = to_mqp((struct ib_qp *)ibwq);
213962306a36Sopenharmony_ci		dev	    = to_mdev(ibwq->device);
214062306a36Sopenharmony_ci		pd	    = to_mpd(ibwq->pd);
214162306a36Sopenharmony_ci	} else {
214262306a36Sopenharmony_ci		struct ib_qp *ibqp;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci		ibqp	    = (struct ib_qp *)src;
214562306a36Sopenharmony_ci		ibsrq	    = ibqp->srq;
214662306a36Sopenharmony_ci		rwq_ind_tbl = ibqp->rwq_ind_tbl;
214762306a36Sopenharmony_ci		qp_type     = ibqp->qp_type;
214862306a36Sopenharmony_ci		qp	    = to_mqp(ibqp);
214962306a36Sopenharmony_ci		dev	    = to_mdev(ibqp->device);
215062306a36Sopenharmony_ci		pd	    = get_pd(qp);
215162306a36Sopenharmony_ci	}
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	/* APM is not supported under RoCE */
215462306a36Sopenharmony_ci	if (attr_mask & IB_QP_ALT_PATH &&
215562306a36Sopenharmony_ci	    rdma_port_get_link_layer(&dev->ib_dev, qp->port) ==
215662306a36Sopenharmony_ci	    IB_LINK_LAYER_ETHERNET)
215762306a36Sopenharmony_ci		return -ENOTSUPP;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	context = kzalloc(sizeof *context, GFP_KERNEL);
216062306a36Sopenharmony_ci	if (!context)
216162306a36Sopenharmony_ci		return -ENOMEM;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	context->flags = cpu_to_be32((to_mlx4_state(new_state) << 28) |
216462306a36Sopenharmony_ci				     (to_mlx4_st(dev, qp->mlx4_ib_qp_type) << 16));
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	if (!(attr_mask & IB_QP_PATH_MIG_STATE))
216762306a36Sopenharmony_ci		context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11);
216862306a36Sopenharmony_ci	else {
216962306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_PM_STATE;
217062306a36Sopenharmony_ci		switch (attr->path_mig_state) {
217162306a36Sopenharmony_ci		case IB_MIG_MIGRATED:
217262306a36Sopenharmony_ci			context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11);
217362306a36Sopenharmony_ci			break;
217462306a36Sopenharmony_ci		case IB_MIG_REARM:
217562306a36Sopenharmony_ci			context->flags |= cpu_to_be32(MLX4_QP_PM_REARM << 11);
217662306a36Sopenharmony_ci			break;
217762306a36Sopenharmony_ci		case IB_MIG_ARMED:
217862306a36Sopenharmony_ci			context->flags |= cpu_to_be32(MLX4_QP_PM_ARMED << 11);
217962306a36Sopenharmony_ci			break;
218062306a36Sopenharmony_ci		}
218162306a36Sopenharmony_ci	}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	if (qp->inl_recv_sz)
218462306a36Sopenharmony_ci		context->param3 |= cpu_to_be32(1 << 25);
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	if (qp->flags & MLX4_IB_QP_SCATTER_FCS)
218762306a36Sopenharmony_ci		context->param3 |= cpu_to_be32(1 << 29);
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	if (qp_type == IB_QPT_GSI || qp_type == IB_QPT_SMI)
219062306a36Sopenharmony_ci		context->mtu_msgmax = (IB_MTU_4096 << 5) | 11;
219162306a36Sopenharmony_ci	else if (qp_type == IB_QPT_RAW_PACKET)
219262306a36Sopenharmony_ci		context->mtu_msgmax = (MLX4_RAW_QP_MTU << 5) | MLX4_RAW_QP_MSGMAX;
219362306a36Sopenharmony_ci	else if (qp_type == IB_QPT_UD) {
219462306a36Sopenharmony_ci		if (qp->flags & MLX4_IB_QP_LSO)
219562306a36Sopenharmony_ci			context->mtu_msgmax = (IB_MTU_4096 << 5) |
219662306a36Sopenharmony_ci					      ilog2(dev->dev->caps.max_gso_sz);
219762306a36Sopenharmony_ci		else
219862306a36Sopenharmony_ci			context->mtu_msgmax = (IB_MTU_4096 << 5) | 13;
219962306a36Sopenharmony_ci	} else if (attr_mask & IB_QP_PATH_MTU) {
220062306a36Sopenharmony_ci		if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) {
220162306a36Sopenharmony_ci			pr_err("path MTU (%u) is invalid\n",
220262306a36Sopenharmony_ci			       attr->path_mtu);
220362306a36Sopenharmony_ci			goto out;
220462306a36Sopenharmony_ci		}
220562306a36Sopenharmony_ci		context->mtu_msgmax = (attr->path_mtu << 5) |
220662306a36Sopenharmony_ci			ilog2(dev->dev->caps.max_msg_sz);
220762306a36Sopenharmony_ci	}
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	if (!rwq_ind_tbl) { /* PRM RSS receive side should be left zeros */
221062306a36Sopenharmony_ci		if (qp->rq.wqe_cnt)
221162306a36Sopenharmony_ci			context->rq_size_stride = ilog2(qp->rq.wqe_cnt) << 3;
221262306a36Sopenharmony_ci		context->rq_size_stride |= qp->rq.wqe_shift - 4;
221362306a36Sopenharmony_ci	}
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	if (qp->sq.wqe_cnt)
221662306a36Sopenharmony_ci		context->sq_size_stride = ilog2(qp->sq.wqe_cnt) << 3;
221762306a36Sopenharmony_ci	context->sq_size_stride |= qp->sq.wqe_shift - 4;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	if (new_state == IB_QPS_RESET && qp->counter_index)
222062306a36Sopenharmony_ci		mlx4_ib_free_qp_counter(dev, qp);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
222362306a36Sopenharmony_ci		context->sq_size_stride |= !!qp->sq_no_prefetch << 7;
222462306a36Sopenharmony_ci		context->xrcd = cpu_to_be32((u32) qp->xrcdn);
222562306a36Sopenharmony_ci		if (qp_type == IB_QPT_RAW_PACKET)
222662306a36Sopenharmony_ci			context->param3 |= cpu_to_be32(1 << 30);
222762306a36Sopenharmony_ci	}
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	if (ucontext)
223062306a36Sopenharmony_ci		context->usr_page = cpu_to_be32(
223162306a36Sopenharmony_ci			mlx4_to_hw_uar_index(dev->dev, ucontext->uar.index));
223262306a36Sopenharmony_ci	else
223362306a36Sopenharmony_ci		context->usr_page = cpu_to_be32(
223462306a36Sopenharmony_ci			mlx4_to_hw_uar_index(dev->dev, dev->priv_uar.index));
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	if (attr_mask & IB_QP_DEST_QPN)
223762306a36Sopenharmony_ci		context->remote_qpn = cpu_to_be32(attr->dest_qp_num);
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	if (attr_mask & IB_QP_PORT) {
224062306a36Sopenharmony_ci		if (cur_state == IB_QPS_SQD && new_state == IB_QPS_SQD &&
224162306a36Sopenharmony_ci		    !(attr_mask & IB_QP_AV)) {
224262306a36Sopenharmony_ci			mlx4_set_sched(&context->pri_path, attr->port_num);
224362306a36Sopenharmony_ci			optpar |= MLX4_QP_OPTPAR_SCHED_QUEUE;
224462306a36Sopenharmony_ci		}
224562306a36Sopenharmony_ci	}
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
224862306a36Sopenharmony_ci		err = create_qp_lb_counter(dev, qp);
224962306a36Sopenharmony_ci		if (err)
225062306a36Sopenharmony_ci			goto out;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci		counter_index =
225362306a36Sopenharmony_ci			dev->counters_table[qp->port - 1].default_counter;
225462306a36Sopenharmony_ci		if (qp->counter_index)
225562306a36Sopenharmony_ci			counter_index = qp->counter_index->index;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci		if (counter_index != -1) {
225862306a36Sopenharmony_ci			context->pri_path.counter_index = counter_index;
225962306a36Sopenharmony_ci			optpar |= MLX4_QP_OPTPAR_COUNTER_INDEX;
226062306a36Sopenharmony_ci			if (qp->counter_index) {
226162306a36Sopenharmony_ci				context->pri_path.fl |=
226262306a36Sopenharmony_ci					MLX4_FL_ETH_SRC_CHECK_MC_LB;
226362306a36Sopenharmony_ci				context->pri_path.vlan_control |=
226462306a36Sopenharmony_ci					MLX4_CTRL_ETH_SRC_CHECK_IF_COUNTER;
226562306a36Sopenharmony_ci			}
226662306a36Sopenharmony_ci		} else
226762306a36Sopenharmony_ci			context->pri_path.counter_index =
226862306a36Sopenharmony_ci				MLX4_SINK_COUNTER_INDEX(dev->dev);
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci		if (qp->flags & MLX4_IB_QP_NETIF) {
227162306a36Sopenharmony_ci			mlx4_ib_steer_qp_reg(dev, qp, 1);
227262306a36Sopenharmony_ci			steer_qp = 1;
227362306a36Sopenharmony_ci		}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci		if (qp_type == IB_QPT_GSI) {
227662306a36Sopenharmony_ci			enum ib_gid_type gid_type = qp->flags & MLX4_IB_ROCE_V2_GSI_QP ?
227762306a36Sopenharmony_ci				IB_GID_TYPE_ROCE_UDP_ENCAP : IB_GID_TYPE_ROCE;
227862306a36Sopenharmony_ci			u8 qpc_roce_mode = gid_type_to_qpc(gid_type);
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci			context->rlkey_roce_mode |= (qpc_roce_mode << 6);
228162306a36Sopenharmony_ci		}
228262306a36Sopenharmony_ci	}
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	if (attr_mask & IB_QP_PKEY_INDEX) {
228562306a36Sopenharmony_ci		if (qp->mlx4_ib_qp_type & MLX4_IB_QPT_ANY_SRIOV)
228662306a36Sopenharmony_ci			context->pri_path.disable_pkey_check = 0x40;
228762306a36Sopenharmony_ci		context->pri_path.pkey_index = attr->pkey_index;
228862306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_PKEY_INDEX;
228962306a36Sopenharmony_ci	}
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	if (attr_mask & IB_QP_AV) {
229262306a36Sopenharmony_ci		u8 port_num = mlx4_is_bonded(dev->dev) ? 1 :
229362306a36Sopenharmony_ci			attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
229462306a36Sopenharmony_ci		u16 vlan = 0xffff;
229562306a36Sopenharmony_ci		u8 smac[ETH_ALEN];
229662306a36Sopenharmony_ci		int is_eth =
229762306a36Sopenharmony_ci			rdma_cap_eth_ah(&dev->ib_dev, port_num) &&
229862306a36Sopenharmony_ci			rdma_ah_get_ah_flags(&attr->ah_attr) & IB_AH_GRH;
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci		if (is_eth) {
230162306a36Sopenharmony_ci			gid_attr = attr->ah_attr.grh.sgid_attr;
230262306a36Sopenharmony_ci			err = rdma_read_gid_l2_fields(gid_attr, &vlan,
230362306a36Sopenharmony_ci						      &smac[0]);
230462306a36Sopenharmony_ci			if (err)
230562306a36Sopenharmony_ci				goto out;
230662306a36Sopenharmony_ci		}
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci		if (mlx4_set_path(dev, attr, attr_mask, qp, &context->pri_path,
230962306a36Sopenharmony_ci				  port_num, vlan, smac))
231062306a36Sopenharmony_ci			goto out;
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci		optpar |= (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH |
231362306a36Sopenharmony_ci			   MLX4_QP_OPTPAR_SCHED_QUEUE);
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci		if (is_eth &&
231662306a36Sopenharmony_ci		    (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR)) {
231762306a36Sopenharmony_ci			u8 qpc_roce_mode = gid_type_to_qpc(gid_attr->gid_type);
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci			if (qpc_roce_mode == MLX4_QPC_ROCE_MODE_UNDEFINED) {
232062306a36Sopenharmony_ci				err = -EINVAL;
232162306a36Sopenharmony_ci				goto out;
232262306a36Sopenharmony_ci			}
232362306a36Sopenharmony_ci			context->rlkey_roce_mode |= (qpc_roce_mode << 6);
232462306a36Sopenharmony_ci		}
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	}
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	if (attr_mask & IB_QP_TIMEOUT) {
232962306a36Sopenharmony_ci		context->pri_path.ackto |= attr->timeout << 3;
233062306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_ACK_TIMEOUT;
233162306a36Sopenharmony_ci	}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	if (attr_mask & IB_QP_ALT_PATH) {
233462306a36Sopenharmony_ci		if (attr->alt_port_num == 0 ||
233562306a36Sopenharmony_ci		    attr->alt_port_num > dev->dev->caps.num_ports)
233662306a36Sopenharmony_ci			goto out;
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci		if (attr->alt_pkey_index >=
233962306a36Sopenharmony_ci		    dev->dev->caps.pkey_table_len[attr->alt_port_num])
234062306a36Sopenharmony_ci			goto out;
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci		if (mlx4_set_alt_path(dev, attr, attr_mask, qp,
234362306a36Sopenharmony_ci				      &context->alt_path,
234462306a36Sopenharmony_ci				      attr->alt_port_num))
234562306a36Sopenharmony_ci			goto out;
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci		context->alt_path.pkey_index = attr->alt_pkey_index;
234862306a36Sopenharmony_ci		context->alt_path.ackto = attr->alt_timeout << 3;
234962306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_ALT_ADDR_PATH;
235062306a36Sopenharmony_ci	}
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	context->pd = cpu_to_be32(pd->pdn);
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	if (!rwq_ind_tbl) {
235562306a36Sopenharmony_ci		context->params1 = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28);
235662306a36Sopenharmony_ci		get_cqs(qp, src_type, &send_cq, &recv_cq);
235762306a36Sopenharmony_ci	} else { /* Set dummy CQs to be compatible with HV and PRM */
235862306a36Sopenharmony_ci		send_cq = to_mcq(rwq_ind_tbl->ind_tbl[0]->cq);
235962306a36Sopenharmony_ci		recv_cq = send_cq;
236062306a36Sopenharmony_ci	}
236162306a36Sopenharmony_ci	context->cqn_send = cpu_to_be32(send_cq->mcq.cqn);
236262306a36Sopenharmony_ci	context->cqn_recv = cpu_to_be32(recv_cq->mcq.cqn);
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	/* Set "fast registration enabled" for all kernel QPs */
236562306a36Sopenharmony_ci	if (!ucontext)
236662306a36Sopenharmony_ci		context->params1 |= cpu_to_be32(1 << 11);
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	if (attr_mask & IB_QP_RNR_RETRY) {
236962306a36Sopenharmony_ci		context->params1 |= cpu_to_be32(attr->rnr_retry << 13);
237062306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_RNR_RETRY;
237162306a36Sopenharmony_ci	}
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	if (attr_mask & IB_QP_RETRY_CNT) {
237462306a36Sopenharmony_ci		context->params1 |= cpu_to_be32(attr->retry_cnt << 16);
237562306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_RETRY_COUNT;
237662306a36Sopenharmony_ci	}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
237962306a36Sopenharmony_ci		if (attr->max_rd_atomic)
238062306a36Sopenharmony_ci			context->params1 |=
238162306a36Sopenharmony_ci				cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21);
238262306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_SRA_MAX;
238362306a36Sopenharmony_ci	}
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	if (attr_mask & IB_QP_SQ_PSN)
238662306a36Sopenharmony_ci		context->next_send_psn = cpu_to_be32(attr->sq_psn);
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
238962306a36Sopenharmony_ci		if (attr->max_dest_rd_atomic)
239062306a36Sopenharmony_ci			context->params2 |=
239162306a36Sopenharmony_ci				cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21);
239262306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_RRA_MAX;
239362306a36Sopenharmony_ci	}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) {
239662306a36Sopenharmony_ci		context->params2 |= to_mlx4_access_flags(qp, attr, attr_mask);
239762306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_RWE | MLX4_QP_OPTPAR_RRE | MLX4_QP_OPTPAR_RAE;
239862306a36Sopenharmony_ci	}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	if (ibsrq)
240162306a36Sopenharmony_ci		context->params2 |= cpu_to_be32(MLX4_QP_BIT_RIC);
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci	if (attr_mask & IB_QP_MIN_RNR_TIMER) {
240462306a36Sopenharmony_ci		context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24);
240562306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_RNR_TIMEOUT;
240662306a36Sopenharmony_ci	}
240762306a36Sopenharmony_ci	if (attr_mask & IB_QP_RQ_PSN)
240862306a36Sopenharmony_ci		context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn);
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	/* proxy and tunnel qp qkeys will be changed in modify-qp wrappers */
241162306a36Sopenharmony_ci	if (attr_mask & IB_QP_QKEY) {
241262306a36Sopenharmony_ci		if (qp->mlx4_ib_qp_type &
241362306a36Sopenharmony_ci		    (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_TUN_SMI_OWNER))
241462306a36Sopenharmony_ci			context->qkey = cpu_to_be32(IB_QP_SET_QKEY);
241562306a36Sopenharmony_ci		else {
241662306a36Sopenharmony_ci			if (mlx4_is_mfunc(dev->dev) &&
241762306a36Sopenharmony_ci			    !(qp->mlx4_ib_qp_type & MLX4_IB_QPT_ANY_SRIOV) &&
241862306a36Sopenharmony_ci			    (attr->qkey & MLX4_RESERVED_QKEY_MASK) ==
241962306a36Sopenharmony_ci			    MLX4_RESERVED_QKEY_BASE) {
242062306a36Sopenharmony_ci				pr_err("Cannot use reserved QKEY"
242162306a36Sopenharmony_ci				       " 0x%x (range 0xffff0000..0xffffffff"
242262306a36Sopenharmony_ci				       " is reserved)\n", attr->qkey);
242362306a36Sopenharmony_ci				err = -EINVAL;
242462306a36Sopenharmony_ci				goto out;
242562306a36Sopenharmony_ci			}
242662306a36Sopenharmony_ci			context->qkey = cpu_to_be32(attr->qkey);
242762306a36Sopenharmony_ci		}
242862306a36Sopenharmony_ci		optpar |= MLX4_QP_OPTPAR_Q_KEY;
242962306a36Sopenharmony_ci	}
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	if (ibsrq)
243262306a36Sopenharmony_ci		context->srqn = cpu_to_be32(1 << 24 |
243362306a36Sopenharmony_ci					    to_msrq(ibsrq)->msrq.srqn);
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	if (qp->rq.wqe_cnt &&
243662306a36Sopenharmony_ci	    cur_state == IB_QPS_RESET &&
243762306a36Sopenharmony_ci	    new_state == IB_QPS_INIT)
243862306a36Sopenharmony_ci		context->db_rec_addr = cpu_to_be64(qp->db.dma);
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	if (cur_state == IB_QPS_INIT &&
244162306a36Sopenharmony_ci	    new_state == IB_QPS_RTR  &&
244262306a36Sopenharmony_ci	    (qp_type == IB_QPT_GSI || qp_type == IB_QPT_SMI ||
244362306a36Sopenharmony_ci	     qp_type == IB_QPT_UD || qp_type == IB_QPT_RAW_PACKET)) {
244462306a36Sopenharmony_ci		context->pri_path.sched_queue = (qp->port - 1) << 6;
244562306a36Sopenharmony_ci		if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_SMI ||
244662306a36Sopenharmony_ci		    qp->mlx4_ib_qp_type &
244762306a36Sopenharmony_ci		    (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_TUN_SMI_OWNER)) {
244862306a36Sopenharmony_ci			context->pri_path.sched_queue |= MLX4_IB_DEFAULT_QP0_SCHED_QUEUE;
244962306a36Sopenharmony_ci			if (qp->mlx4_ib_qp_type != MLX4_IB_QPT_SMI)
245062306a36Sopenharmony_ci				context->pri_path.fl = 0x80;
245162306a36Sopenharmony_ci		} else {
245262306a36Sopenharmony_ci			if (qp->mlx4_ib_qp_type & MLX4_IB_QPT_ANY_SRIOV)
245362306a36Sopenharmony_ci				context->pri_path.fl = 0x80;
245462306a36Sopenharmony_ci			context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE;
245562306a36Sopenharmony_ci		}
245662306a36Sopenharmony_ci		if (rdma_port_get_link_layer(&dev->ib_dev, qp->port) ==
245762306a36Sopenharmony_ci		    IB_LINK_LAYER_ETHERNET) {
245862306a36Sopenharmony_ci			if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI ||
245962306a36Sopenharmony_ci			    qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI)
246062306a36Sopenharmony_ci				context->pri_path.feup = 1 << 7; /* don't fsm */
246162306a36Sopenharmony_ci			/* handle smac_index */
246262306a36Sopenharmony_ci			if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_UD ||
246362306a36Sopenharmony_ci			    qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI ||
246462306a36Sopenharmony_ci			    qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) {
246562306a36Sopenharmony_ci				err = handle_eth_ud_smac_index(dev, qp, context);
246662306a36Sopenharmony_ci				if (err) {
246762306a36Sopenharmony_ci					err = -EINVAL;
246862306a36Sopenharmony_ci					goto out;
246962306a36Sopenharmony_ci				}
247062306a36Sopenharmony_ci				if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI)
247162306a36Sopenharmony_ci					dev->qp1_proxy[qp->port - 1] = qp;
247262306a36Sopenharmony_ci			}
247362306a36Sopenharmony_ci		}
247462306a36Sopenharmony_ci	}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	if (qp_type == IB_QPT_RAW_PACKET) {
247762306a36Sopenharmony_ci		context->pri_path.ackto = (context->pri_path.ackto & 0xf8) |
247862306a36Sopenharmony_ci					MLX4_IB_LINK_TYPE_ETH;
247962306a36Sopenharmony_ci		if (dev->dev->caps.tunnel_offload_mode ==  MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
248062306a36Sopenharmony_ci			/* set QP to receive both tunneled & non-tunneled packets */
248162306a36Sopenharmony_ci			if (!rwq_ind_tbl)
248262306a36Sopenharmony_ci				context->srqn = cpu_to_be32(7 << 28);
248362306a36Sopenharmony_ci		}
248462306a36Sopenharmony_ci	}
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	if (qp_type == IB_QPT_UD && (new_state == IB_QPS_RTR)) {
248762306a36Sopenharmony_ci		int is_eth = rdma_port_get_link_layer(
248862306a36Sopenharmony_ci				&dev->ib_dev, qp->port) ==
248962306a36Sopenharmony_ci				IB_LINK_LAYER_ETHERNET;
249062306a36Sopenharmony_ci		if (is_eth) {
249162306a36Sopenharmony_ci			context->pri_path.ackto = MLX4_IB_LINK_TYPE_ETH;
249262306a36Sopenharmony_ci			optpar |= MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH;
249362306a36Sopenharmony_ci		}
249462306a36Sopenharmony_ci	}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD	&&
249762306a36Sopenharmony_ci	    attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify)
249862306a36Sopenharmony_ci		sqd_event = 1;
249962306a36Sopenharmony_ci	else
250062306a36Sopenharmony_ci		sqd_event = 0;
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	if (!ucontext &&
250362306a36Sopenharmony_ci	    cur_state == IB_QPS_RESET &&
250462306a36Sopenharmony_ci	    new_state == IB_QPS_INIT)
250562306a36Sopenharmony_ci		context->rlkey_roce_mode |= (1 << 4);
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	/*
250862306a36Sopenharmony_ci	 * Before passing a kernel QP to the HW, make sure that the
250962306a36Sopenharmony_ci	 * ownership bits of the send queue are set and the SQ
251062306a36Sopenharmony_ci	 * headroom is stamped so that the hardware doesn't start
251162306a36Sopenharmony_ci	 * processing stale work requests.
251262306a36Sopenharmony_ci	 */
251362306a36Sopenharmony_ci	if (!ucontext &&
251462306a36Sopenharmony_ci	    cur_state == IB_QPS_RESET &&
251562306a36Sopenharmony_ci	    new_state == IB_QPS_INIT) {
251662306a36Sopenharmony_ci		struct mlx4_wqe_ctrl_seg *ctrl;
251762306a36Sopenharmony_ci		int i;
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci		for (i = 0; i < qp->sq.wqe_cnt; ++i) {
252062306a36Sopenharmony_ci			ctrl = get_send_wqe(qp, i);
252162306a36Sopenharmony_ci			ctrl->owner_opcode = cpu_to_be32(1 << 31);
252262306a36Sopenharmony_ci			ctrl->qpn_vlan.fence_size =
252362306a36Sopenharmony_ci				1 << (qp->sq.wqe_shift - 4);
252462306a36Sopenharmony_ci			stamp_send_wqe(qp, i);
252562306a36Sopenharmony_ci		}
252662306a36Sopenharmony_ci	}
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	if (rwq_ind_tbl	&&
252962306a36Sopenharmony_ci	    cur_state == IB_QPS_RESET &&
253062306a36Sopenharmony_ci	    new_state == IB_QPS_INIT) {
253162306a36Sopenharmony_ci		fill_qp_rss_context(context, qp);
253262306a36Sopenharmony_ci		context->flags |= cpu_to_be32(1 << MLX4_RSS_QPC_FLAG_OFFSET);
253362306a36Sopenharmony_ci	}
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	err = mlx4_qp_modify(dev->dev, &qp->mtt, to_mlx4_state(cur_state),
253662306a36Sopenharmony_ci			     to_mlx4_state(new_state), context, optpar,
253762306a36Sopenharmony_ci			     sqd_event, &qp->mqp);
253862306a36Sopenharmony_ci	if (err)
253962306a36Sopenharmony_ci		goto out;
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci	qp->state = new_state;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	if (attr_mask & IB_QP_ACCESS_FLAGS)
254462306a36Sopenharmony_ci		qp->atomic_rd_en = attr->qp_access_flags;
254562306a36Sopenharmony_ci	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
254662306a36Sopenharmony_ci		qp->resp_depth = attr->max_dest_rd_atomic;
254762306a36Sopenharmony_ci	if (attr_mask & IB_QP_PORT) {
254862306a36Sopenharmony_ci		qp->port = attr->port_num;
254962306a36Sopenharmony_ci		update_mcg_macs(dev, qp);
255062306a36Sopenharmony_ci	}
255162306a36Sopenharmony_ci	if (attr_mask & IB_QP_ALT_PATH)
255262306a36Sopenharmony_ci		qp->alt_port = attr->alt_port_num;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	if (is_sqp(dev, qp))
255562306a36Sopenharmony_ci		store_sqp_attrs(qp->sqp, attr, attr_mask);
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci	/*
255862306a36Sopenharmony_ci	 * If we moved QP0 to RTR, bring the IB link up; if we moved
255962306a36Sopenharmony_ci	 * QP0 to RESET or ERROR, bring the link back down.
256062306a36Sopenharmony_ci	 */
256162306a36Sopenharmony_ci	if (is_qp0(dev, qp)) {
256262306a36Sopenharmony_ci		if (cur_state != IB_QPS_RTR && new_state == IB_QPS_RTR)
256362306a36Sopenharmony_ci			if (mlx4_INIT_PORT(dev->dev, qp->port))
256462306a36Sopenharmony_ci				pr_warn("INIT_PORT failed for port %d\n",
256562306a36Sopenharmony_ci				       qp->port);
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci		if (cur_state != IB_QPS_RESET && cur_state != IB_QPS_ERR &&
256862306a36Sopenharmony_ci		    (new_state == IB_QPS_RESET || new_state == IB_QPS_ERR))
256962306a36Sopenharmony_ci			mlx4_CLOSE_PORT(dev->dev, qp->port);
257062306a36Sopenharmony_ci	}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci	/*
257362306a36Sopenharmony_ci	 * If we moved a kernel QP to RESET, clean up all old CQ
257462306a36Sopenharmony_ci	 * entries and reinitialize the QP.
257562306a36Sopenharmony_ci	 */
257662306a36Sopenharmony_ci	if (new_state == IB_QPS_RESET) {
257762306a36Sopenharmony_ci		if (!ucontext) {
257862306a36Sopenharmony_ci			mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
257962306a36Sopenharmony_ci					 ibsrq ? to_msrq(ibsrq) : NULL);
258062306a36Sopenharmony_ci			if (send_cq != recv_cq)
258162306a36Sopenharmony_ci				mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci			qp->rq.head = 0;
258462306a36Sopenharmony_ci			qp->rq.tail = 0;
258562306a36Sopenharmony_ci			qp->sq.head = 0;
258662306a36Sopenharmony_ci			qp->sq.tail = 0;
258762306a36Sopenharmony_ci			qp->sq_next_wqe = 0;
258862306a36Sopenharmony_ci			if (qp->rq.wqe_cnt)
258962306a36Sopenharmony_ci				*qp->db.db  = 0;
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci			if (qp->flags & MLX4_IB_QP_NETIF)
259262306a36Sopenharmony_ci				mlx4_ib_steer_qp_reg(dev, qp, 0);
259362306a36Sopenharmony_ci		}
259462306a36Sopenharmony_ci		if (qp->pri.smac || (!qp->pri.smac && qp->pri.smac_port)) {
259562306a36Sopenharmony_ci			mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
259662306a36Sopenharmony_ci			qp->pri.smac = 0;
259762306a36Sopenharmony_ci			qp->pri.smac_port = 0;
259862306a36Sopenharmony_ci		}
259962306a36Sopenharmony_ci		if (qp->alt.smac) {
260062306a36Sopenharmony_ci			mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
260162306a36Sopenharmony_ci			qp->alt.smac = 0;
260262306a36Sopenharmony_ci		}
260362306a36Sopenharmony_ci		if (qp->pri.vid < 0x1000) {
260462306a36Sopenharmony_ci			mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid);
260562306a36Sopenharmony_ci			qp->pri.vid = 0xFFFF;
260662306a36Sopenharmony_ci			qp->pri.candidate_vid = 0xFFFF;
260762306a36Sopenharmony_ci			qp->pri.update_vid = 0;
260862306a36Sopenharmony_ci		}
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci		if (qp->alt.vid < 0x1000) {
261162306a36Sopenharmony_ci			mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid);
261262306a36Sopenharmony_ci			qp->alt.vid = 0xFFFF;
261362306a36Sopenharmony_ci			qp->alt.candidate_vid = 0xFFFF;
261462306a36Sopenharmony_ci			qp->alt.update_vid = 0;
261562306a36Sopenharmony_ci		}
261662306a36Sopenharmony_ci	}
261762306a36Sopenharmony_ciout:
261862306a36Sopenharmony_ci	if (err && qp->counter_index)
261962306a36Sopenharmony_ci		mlx4_ib_free_qp_counter(dev, qp);
262062306a36Sopenharmony_ci	if (err && steer_qp)
262162306a36Sopenharmony_ci		mlx4_ib_steer_qp_reg(dev, qp, 0);
262262306a36Sopenharmony_ci	kfree(context);
262362306a36Sopenharmony_ci	if (qp->pri.candidate_smac ||
262462306a36Sopenharmony_ci	    (!qp->pri.candidate_smac && qp->pri.candidate_smac_port)) {
262562306a36Sopenharmony_ci		if (err) {
262662306a36Sopenharmony_ci			mlx4_unregister_mac(dev->dev, qp->pri.candidate_smac_port, qp->pri.candidate_smac);
262762306a36Sopenharmony_ci		} else {
262862306a36Sopenharmony_ci			if (qp->pri.smac || (!qp->pri.smac && qp->pri.smac_port))
262962306a36Sopenharmony_ci				mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
263062306a36Sopenharmony_ci			qp->pri.smac = qp->pri.candidate_smac;
263162306a36Sopenharmony_ci			qp->pri.smac_index = qp->pri.candidate_smac_index;
263262306a36Sopenharmony_ci			qp->pri.smac_port = qp->pri.candidate_smac_port;
263362306a36Sopenharmony_ci		}
263462306a36Sopenharmony_ci		qp->pri.candidate_smac = 0;
263562306a36Sopenharmony_ci		qp->pri.candidate_smac_index = 0;
263662306a36Sopenharmony_ci		qp->pri.candidate_smac_port = 0;
263762306a36Sopenharmony_ci	}
263862306a36Sopenharmony_ci	if (qp->alt.candidate_smac) {
263962306a36Sopenharmony_ci		if (err) {
264062306a36Sopenharmony_ci			mlx4_unregister_mac(dev->dev, qp->alt.candidate_smac_port, qp->alt.candidate_smac);
264162306a36Sopenharmony_ci		} else {
264262306a36Sopenharmony_ci			if (qp->alt.smac)
264362306a36Sopenharmony_ci				mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
264462306a36Sopenharmony_ci			qp->alt.smac = qp->alt.candidate_smac;
264562306a36Sopenharmony_ci			qp->alt.smac_index = qp->alt.candidate_smac_index;
264662306a36Sopenharmony_ci			qp->alt.smac_port = qp->alt.candidate_smac_port;
264762306a36Sopenharmony_ci		}
264862306a36Sopenharmony_ci		qp->alt.candidate_smac = 0;
264962306a36Sopenharmony_ci		qp->alt.candidate_smac_index = 0;
265062306a36Sopenharmony_ci		qp->alt.candidate_smac_port = 0;
265162306a36Sopenharmony_ci	}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	if (qp->pri.update_vid) {
265462306a36Sopenharmony_ci		if (err) {
265562306a36Sopenharmony_ci			if (qp->pri.candidate_vid < 0x1000)
265662306a36Sopenharmony_ci				mlx4_unregister_vlan(dev->dev, qp->pri.candidate_vlan_port,
265762306a36Sopenharmony_ci						     qp->pri.candidate_vid);
265862306a36Sopenharmony_ci		} else {
265962306a36Sopenharmony_ci			if (qp->pri.vid < 0x1000)
266062306a36Sopenharmony_ci				mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port,
266162306a36Sopenharmony_ci						     qp->pri.vid);
266262306a36Sopenharmony_ci			qp->pri.vid = qp->pri.candidate_vid;
266362306a36Sopenharmony_ci			qp->pri.vlan_port = qp->pri.candidate_vlan_port;
266462306a36Sopenharmony_ci			qp->pri.vlan_index =  qp->pri.candidate_vlan_index;
266562306a36Sopenharmony_ci		}
266662306a36Sopenharmony_ci		qp->pri.candidate_vid = 0xFFFF;
266762306a36Sopenharmony_ci		qp->pri.update_vid = 0;
266862306a36Sopenharmony_ci	}
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci	if (qp->alt.update_vid) {
267162306a36Sopenharmony_ci		if (err) {
267262306a36Sopenharmony_ci			if (qp->alt.candidate_vid < 0x1000)
267362306a36Sopenharmony_ci				mlx4_unregister_vlan(dev->dev, qp->alt.candidate_vlan_port,
267462306a36Sopenharmony_ci						     qp->alt.candidate_vid);
267562306a36Sopenharmony_ci		} else {
267662306a36Sopenharmony_ci			if (qp->alt.vid < 0x1000)
267762306a36Sopenharmony_ci				mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port,
267862306a36Sopenharmony_ci						     qp->alt.vid);
267962306a36Sopenharmony_ci			qp->alt.vid = qp->alt.candidate_vid;
268062306a36Sopenharmony_ci			qp->alt.vlan_port = qp->alt.candidate_vlan_port;
268162306a36Sopenharmony_ci			qp->alt.vlan_index =  qp->alt.candidate_vlan_index;
268262306a36Sopenharmony_ci		}
268362306a36Sopenharmony_ci		qp->alt.candidate_vid = 0xFFFF;
268462306a36Sopenharmony_ci		qp->alt.update_vid = 0;
268562306a36Sopenharmony_ci	}
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	return err;
268862306a36Sopenharmony_ci}
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_cienum {
269162306a36Sopenharmony_ci	MLX4_IB_MODIFY_QP_RSS_SUP_ATTR_MSK = (IB_QP_STATE	|
269262306a36Sopenharmony_ci					      IB_QP_PORT),
269362306a36Sopenharmony_ci};
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_cistatic int _mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
269662306a36Sopenharmony_ci			      int attr_mask, struct ib_udata *udata)
269762306a36Sopenharmony_ci{
269862306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibqp->device);
269962306a36Sopenharmony_ci	struct mlx4_ib_qp *qp = to_mqp(ibqp);
270062306a36Sopenharmony_ci	enum ib_qp_state cur_state, new_state;
270162306a36Sopenharmony_ci	int err = -EINVAL;
270262306a36Sopenharmony_ci	mutex_lock(&qp->mutex);
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci	cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
270562306a36Sopenharmony_ci	new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type,
270862306a36Sopenharmony_ci				attr_mask)) {
270962306a36Sopenharmony_ci		pr_debug("qpn 0x%x: invalid attribute mask specified "
271062306a36Sopenharmony_ci			 "for transition %d to %d. qp_type %d,"
271162306a36Sopenharmony_ci			 " attr_mask 0x%x\n",
271262306a36Sopenharmony_ci			 ibqp->qp_num, cur_state, new_state,
271362306a36Sopenharmony_ci			 ibqp->qp_type, attr_mask);
271462306a36Sopenharmony_ci		goto out;
271562306a36Sopenharmony_ci	}
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	if (ibqp->rwq_ind_tbl) {
271862306a36Sopenharmony_ci		if (!(((cur_state == IB_QPS_RESET) &&
271962306a36Sopenharmony_ci		       (new_state == IB_QPS_INIT)) ||
272062306a36Sopenharmony_ci		      ((cur_state == IB_QPS_INIT)  &&
272162306a36Sopenharmony_ci		       (new_state == IB_QPS_RTR)))) {
272262306a36Sopenharmony_ci			pr_debug("qpn 0x%x: RSS QP unsupported transition %d to %d\n",
272362306a36Sopenharmony_ci				 ibqp->qp_num, cur_state, new_state);
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci			err = -EOPNOTSUPP;
272662306a36Sopenharmony_ci			goto out;
272762306a36Sopenharmony_ci		}
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci		if (attr_mask & ~MLX4_IB_MODIFY_QP_RSS_SUP_ATTR_MSK) {
273062306a36Sopenharmony_ci			pr_debug("qpn 0x%x: RSS QP unsupported attribute mask 0x%x for transition %d to %d\n",
273162306a36Sopenharmony_ci				 ibqp->qp_num, attr_mask, cur_state, new_state);
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci			err = -EOPNOTSUPP;
273462306a36Sopenharmony_ci			goto out;
273562306a36Sopenharmony_ci		}
273662306a36Sopenharmony_ci	}
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	if (mlx4_is_bonded(dev->dev) && (attr_mask & IB_QP_PORT)) {
273962306a36Sopenharmony_ci		if ((cur_state == IB_QPS_RESET) && (new_state == IB_QPS_INIT)) {
274062306a36Sopenharmony_ci			if ((ibqp->qp_type == IB_QPT_RC) ||
274162306a36Sopenharmony_ci			    (ibqp->qp_type == IB_QPT_UD) ||
274262306a36Sopenharmony_ci			    (ibqp->qp_type == IB_QPT_UC) ||
274362306a36Sopenharmony_ci			    (ibqp->qp_type == IB_QPT_RAW_PACKET) ||
274462306a36Sopenharmony_ci			    (ibqp->qp_type == IB_QPT_XRC_INI)) {
274562306a36Sopenharmony_ci				attr->port_num = mlx4_ib_bond_next_port(dev);
274662306a36Sopenharmony_ci			}
274762306a36Sopenharmony_ci		} else {
274862306a36Sopenharmony_ci			/* no sense in changing port_num
274962306a36Sopenharmony_ci			 * when ports are bonded */
275062306a36Sopenharmony_ci			attr_mask &= ~IB_QP_PORT;
275162306a36Sopenharmony_ci		}
275262306a36Sopenharmony_ci	}
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci	if ((attr_mask & IB_QP_PORT) &&
275562306a36Sopenharmony_ci	    (attr->port_num == 0 || attr->port_num > dev->num_ports)) {
275662306a36Sopenharmony_ci		pr_debug("qpn 0x%x: invalid port number (%d) specified "
275762306a36Sopenharmony_ci			 "for transition %d to %d. qp_type %d\n",
275862306a36Sopenharmony_ci			 ibqp->qp_num, attr->port_num, cur_state,
275962306a36Sopenharmony_ci			 new_state, ibqp->qp_type);
276062306a36Sopenharmony_ci		goto out;
276162306a36Sopenharmony_ci	}
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	if ((attr_mask & IB_QP_PORT) && (ibqp->qp_type == IB_QPT_RAW_PACKET) &&
276462306a36Sopenharmony_ci	    (rdma_port_get_link_layer(&dev->ib_dev, attr->port_num) !=
276562306a36Sopenharmony_ci	     IB_LINK_LAYER_ETHERNET))
276662306a36Sopenharmony_ci		goto out;
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	if (attr_mask & IB_QP_PKEY_INDEX) {
276962306a36Sopenharmony_ci		int p = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
277062306a36Sopenharmony_ci		if (attr->pkey_index >= dev->dev->caps.pkey_table_len[p]) {
277162306a36Sopenharmony_ci			pr_debug("qpn 0x%x: invalid pkey index (%d) specified "
277262306a36Sopenharmony_ci				 "for transition %d to %d. qp_type %d\n",
277362306a36Sopenharmony_ci				 ibqp->qp_num, attr->pkey_index, cur_state,
277462306a36Sopenharmony_ci				 new_state, ibqp->qp_type);
277562306a36Sopenharmony_ci			goto out;
277662306a36Sopenharmony_ci		}
277762306a36Sopenharmony_ci	}
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
278062306a36Sopenharmony_ci	    attr->max_rd_atomic > dev->dev->caps.max_qp_init_rdma) {
278162306a36Sopenharmony_ci		pr_debug("qpn 0x%x: max_rd_atomic (%d) too large. "
278262306a36Sopenharmony_ci			 "Transition %d to %d. qp_type %d\n",
278362306a36Sopenharmony_ci			 ibqp->qp_num, attr->max_rd_atomic, cur_state,
278462306a36Sopenharmony_ci			 new_state, ibqp->qp_type);
278562306a36Sopenharmony_ci		goto out;
278662306a36Sopenharmony_ci	}
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
278962306a36Sopenharmony_ci	    attr->max_dest_rd_atomic > dev->dev->caps.max_qp_dest_rdma) {
279062306a36Sopenharmony_ci		pr_debug("qpn 0x%x: max_dest_rd_atomic (%d) too large. "
279162306a36Sopenharmony_ci			 "Transition %d to %d. qp_type %d\n",
279262306a36Sopenharmony_ci			 ibqp->qp_num, attr->max_dest_rd_atomic, cur_state,
279362306a36Sopenharmony_ci			 new_state, ibqp->qp_type);
279462306a36Sopenharmony_ci		goto out;
279562306a36Sopenharmony_ci	}
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	if (cur_state == new_state && cur_state == IB_QPS_RESET) {
279862306a36Sopenharmony_ci		err = 0;
279962306a36Sopenharmony_ci		goto out;
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	if (ibqp->rwq_ind_tbl && (new_state == IB_QPS_INIT)) {
280362306a36Sopenharmony_ci		err = bringup_rss_rwqs(ibqp->rwq_ind_tbl, attr->port_num,
280462306a36Sopenharmony_ci				       udata);
280562306a36Sopenharmony_ci		if (err)
280662306a36Sopenharmony_ci			goto out;
280762306a36Sopenharmony_ci	}
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	err = __mlx4_ib_modify_qp(ibqp, MLX4_IB_QP_SRC, attr, attr_mask,
281062306a36Sopenharmony_ci				  cur_state, new_state, udata);
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	if (ibqp->rwq_ind_tbl && err)
281362306a36Sopenharmony_ci		bring_down_rss_rwqs(ibqp->rwq_ind_tbl, udata);
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	if (mlx4_is_bonded(dev->dev) && (attr_mask & IB_QP_PORT))
281662306a36Sopenharmony_ci		attr->port_num = 1;
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ciout:
281962306a36Sopenharmony_ci	mutex_unlock(&qp->mutex);
282062306a36Sopenharmony_ci	return err;
282162306a36Sopenharmony_ci}
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ciint mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
282462306a36Sopenharmony_ci		      int attr_mask, struct ib_udata *udata)
282562306a36Sopenharmony_ci{
282662306a36Sopenharmony_ci	struct mlx4_ib_qp *mqp = to_mqp(ibqp);
282762306a36Sopenharmony_ci	int ret;
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
283062306a36Sopenharmony_ci		return -EOPNOTSUPP;
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	ret = _mlx4_ib_modify_qp(ibqp, attr, attr_mask, udata);
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	if (mqp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI) {
283562306a36Sopenharmony_ci		struct mlx4_ib_sqp *sqp = mqp->sqp;
283662306a36Sopenharmony_ci		int err = 0;
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci		if (sqp->roce_v2_gsi)
283962306a36Sopenharmony_ci			err = ib_modify_qp(sqp->roce_v2_gsi, attr, attr_mask);
284062306a36Sopenharmony_ci		if (err)
284162306a36Sopenharmony_ci			pr_err("Failed to modify GSI QP for RoCEv2 (%d)\n",
284262306a36Sopenharmony_ci			       err);
284362306a36Sopenharmony_ci	}
284462306a36Sopenharmony_ci	return ret;
284562306a36Sopenharmony_ci}
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_cistatic int vf_get_qp0_qkey(struct mlx4_dev *dev, int qpn, u32 *qkey)
284862306a36Sopenharmony_ci{
284962306a36Sopenharmony_ci	int i;
285062306a36Sopenharmony_ci	for (i = 0; i < dev->caps.num_ports; i++) {
285162306a36Sopenharmony_ci		if (qpn == dev->caps.spec_qps[i].qp0_proxy ||
285262306a36Sopenharmony_ci		    qpn == dev->caps.spec_qps[i].qp0_tunnel) {
285362306a36Sopenharmony_ci			*qkey = dev->caps.spec_qps[i].qp0_qkey;
285462306a36Sopenharmony_ci			return 0;
285562306a36Sopenharmony_ci		}
285662306a36Sopenharmony_ci	}
285762306a36Sopenharmony_ci	return -EINVAL;
285862306a36Sopenharmony_ci}
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_cistatic int build_sriov_qp0_header(struct mlx4_ib_qp *qp,
286162306a36Sopenharmony_ci				  const struct ib_ud_wr *wr,
286262306a36Sopenharmony_ci				  void *wqe, unsigned *mlx_seg_len)
286362306a36Sopenharmony_ci{
286462306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(qp->ibqp.device);
286562306a36Sopenharmony_ci	struct mlx4_ib_sqp *sqp = qp->sqp;
286662306a36Sopenharmony_ci	struct ib_device *ib_dev = qp->ibqp.device;
286762306a36Sopenharmony_ci	struct mlx4_wqe_mlx_seg *mlx = wqe;
286862306a36Sopenharmony_ci	struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
286962306a36Sopenharmony_ci	struct mlx4_ib_ah *ah = to_mah(wr->ah);
287062306a36Sopenharmony_ci	u16 pkey;
287162306a36Sopenharmony_ci	u32 qkey;
287262306a36Sopenharmony_ci	int send_size;
287362306a36Sopenharmony_ci	int header_size;
287462306a36Sopenharmony_ci	int spc;
287562306a36Sopenharmony_ci	int err;
287662306a36Sopenharmony_ci	int i;
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	if (wr->wr.opcode != IB_WR_SEND)
287962306a36Sopenharmony_ci		return -EINVAL;
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	send_size = 0;
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci	for (i = 0; i < wr->wr.num_sge; ++i)
288462306a36Sopenharmony_ci		send_size += wr->wr.sg_list[i].length;
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci	/* for proxy-qp0 sends, need to add in size of tunnel header */
288762306a36Sopenharmony_ci	/* for tunnel-qp0 sends, tunnel header is already in s/g list */
288862306a36Sopenharmony_ci	if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_SMI_OWNER)
288962306a36Sopenharmony_ci		send_size += sizeof (struct mlx4_ib_tunnel_header);
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci	ib_ud_header_init(send_size, 1, 0, 0, 0, 0, 0, 0, &sqp->ud_header);
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_SMI_OWNER) {
289462306a36Sopenharmony_ci		sqp->ud_header.lrh.service_level =
289562306a36Sopenharmony_ci			be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28;
289662306a36Sopenharmony_ci		sqp->ud_header.lrh.destination_lid =
289762306a36Sopenharmony_ci			cpu_to_be16(ah->av.ib.g_slid & 0x7f);
289862306a36Sopenharmony_ci		sqp->ud_header.lrh.source_lid =
289962306a36Sopenharmony_ci			cpu_to_be16(ah->av.ib.g_slid & 0x7f);
290062306a36Sopenharmony_ci	}
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci	mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	/* force loopback */
290562306a36Sopenharmony_ci	mlx->flags |= cpu_to_be32(MLX4_WQE_MLX_VL15 | 0x1 | MLX4_WQE_MLX_SLR);
290662306a36Sopenharmony_ci	mlx->rlid = sqp->ud_header.lrh.destination_lid;
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci	sqp->ud_header.lrh.virtual_lane    = 0;
290962306a36Sopenharmony_ci	sqp->ud_header.bth.solicited_event = !!(wr->wr.send_flags & IB_SEND_SOLICITED);
291062306a36Sopenharmony_ci	err = ib_get_cached_pkey(ib_dev, qp->port, 0, &pkey);
291162306a36Sopenharmony_ci	if (err)
291262306a36Sopenharmony_ci		return err;
291362306a36Sopenharmony_ci	sqp->ud_header.bth.pkey = cpu_to_be16(pkey);
291462306a36Sopenharmony_ci	if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_SMI_OWNER)
291562306a36Sopenharmony_ci		sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->remote_qpn);
291662306a36Sopenharmony_ci	else
291762306a36Sopenharmony_ci		sqp->ud_header.bth.destination_qpn =
291862306a36Sopenharmony_ci			cpu_to_be32(mdev->dev->caps.spec_qps[qp->port - 1].qp0_tunnel);
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1));
292162306a36Sopenharmony_ci	if (mlx4_is_master(mdev->dev)) {
292262306a36Sopenharmony_ci		if (mlx4_get_parav_qkey(mdev->dev, qp->mqp.qpn, &qkey))
292362306a36Sopenharmony_ci			return -EINVAL;
292462306a36Sopenharmony_ci	} else {
292562306a36Sopenharmony_ci		if (vf_get_qp0_qkey(mdev->dev, qp->mqp.qpn, &qkey))
292662306a36Sopenharmony_ci			return -EINVAL;
292762306a36Sopenharmony_ci	}
292862306a36Sopenharmony_ci	sqp->ud_header.deth.qkey = cpu_to_be32(qkey);
292962306a36Sopenharmony_ci	sqp->ud_header.deth.source_qpn = cpu_to_be32(qp->mqp.qpn);
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_ci	sqp->ud_header.bth.opcode        = IB_OPCODE_UD_SEND_ONLY;
293262306a36Sopenharmony_ci	sqp->ud_header.immediate_present = 0;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	header_size = ib_ud_header_pack(&sqp->ud_header, sqp->header_buf);
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci	/*
293762306a36Sopenharmony_ci	 * Inline data segments may not cross a 64 byte boundary.  If
293862306a36Sopenharmony_ci	 * our UD header is bigger than the space available up to the
293962306a36Sopenharmony_ci	 * next 64 byte boundary in the WQE, use two inline data
294062306a36Sopenharmony_ci	 * segments to hold the UD header.
294162306a36Sopenharmony_ci	 */
294262306a36Sopenharmony_ci	spc = MLX4_INLINE_ALIGN -
294362306a36Sopenharmony_ci	      ((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1));
294462306a36Sopenharmony_ci	if (header_size <= spc) {
294562306a36Sopenharmony_ci		inl->byte_count = cpu_to_be32(1 << 31 | header_size);
294662306a36Sopenharmony_ci		memcpy(inl + 1, sqp->header_buf, header_size);
294762306a36Sopenharmony_ci		i = 1;
294862306a36Sopenharmony_ci	} else {
294962306a36Sopenharmony_ci		inl->byte_count = cpu_to_be32(1 << 31 | spc);
295062306a36Sopenharmony_ci		memcpy(inl + 1, sqp->header_buf, spc);
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ci		inl = (void *) (inl + 1) + spc;
295362306a36Sopenharmony_ci		memcpy(inl + 1, sqp->header_buf + spc, header_size - spc);
295462306a36Sopenharmony_ci		/*
295562306a36Sopenharmony_ci		 * Need a barrier here to make sure all the data is
295662306a36Sopenharmony_ci		 * visible before the byte_count field is set.
295762306a36Sopenharmony_ci		 * Otherwise the HCA prefetcher could grab the 64-byte
295862306a36Sopenharmony_ci		 * chunk with this inline segment and get a valid (!=
295962306a36Sopenharmony_ci		 * 0xffffffff) byte count but stale data, and end up
296062306a36Sopenharmony_ci		 * generating a packet with bad headers.
296162306a36Sopenharmony_ci		 *
296262306a36Sopenharmony_ci		 * The first inline segment's byte_count field doesn't
296362306a36Sopenharmony_ci		 * need a barrier, because it comes after a
296462306a36Sopenharmony_ci		 * control/MLX segment and therefore is at an offset
296562306a36Sopenharmony_ci		 * of 16 mod 64.
296662306a36Sopenharmony_ci		 */
296762306a36Sopenharmony_ci		wmb();
296862306a36Sopenharmony_ci		inl->byte_count = cpu_to_be32(1 << 31 | (header_size - spc));
296962306a36Sopenharmony_ci		i = 2;
297062306a36Sopenharmony_ci	}
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci	*mlx_seg_len =
297362306a36Sopenharmony_ci	ALIGN(i * sizeof (struct mlx4_wqe_inline_seg) + header_size, 16);
297462306a36Sopenharmony_ci	return 0;
297562306a36Sopenharmony_ci}
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_cistatic u8 sl_to_vl(struct mlx4_ib_dev *dev, u8 sl, int port_num)
297862306a36Sopenharmony_ci{
297962306a36Sopenharmony_ci	union sl2vl_tbl_to_u64 tmp_vltab;
298062306a36Sopenharmony_ci	u8 vl;
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci	if (sl > 15)
298362306a36Sopenharmony_ci		return 0xf;
298462306a36Sopenharmony_ci	tmp_vltab.sl64 = atomic64_read(&dev->sl2vl[port_num - 1]);
298562306a36Sopenharmony_ci	vl = tmp_vltab.sl8[sl >> 1];
298662306a36Sopenharmony_ci	if (sl & 1)
298762306a36Sopenharmony_ci		vl &= 0x0f;
298862306a36Sopenharmony_ci	else
298962306a36Sopenharmony_ci		vl >>= 4;
299062306a36Sopenharmony_ci	return vl;
299162306a36Sopenharmony_ci}
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_cistatic int fill_gid_by_hw_index(struct mlx4_ib_dev *ibdev, u8 port_num,
299462306a36Sopenharmony_ci				int index, union ib_gid *gid,
299562306a36Sopenharmony_ci				enum ib_gid_type *gid_type)
299662306a36Sopenharmony_ci{
299762306a36Sopenharmony_ci	struct mlx4_ib_iboe *iboe = &ibdev->iboe;
299862306a36Sopenharmony_ci	struct mlx4_port_gid_table *port_gid_table;
299962306a36Sopenharmony_ci	unsigned long flags;
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	port_gid_table = &iboe->gids[port_num - 1];
300262306a36Sopenharmony_ci	spin_lock_irqsave(&iboe->lock, flags);
300362306a36Sopenharmony_ci	memcpy(gid, &port_gid_table->gids[index].gid, sizeof(*gid));
300462306a36Sopenharmony_ci	*gid_type = port_gid_table->gids[index].gid_type;
300562306a36Sopenharmony_ci	spin_unlock_irqrestore(&iboe->lock, flags);
300662306a36Sopenharmony_ci	if (rdma_is_zero_gid(gid))
300762306a36Sopenharmony_ci		return -ENOENT;
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	return 0;
301062306a36Sopenharmony_ci}
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci#define MLX4_ROCEV2_QP1_SPORT 0xC000
301362306a36Sopenharmony_cistatic int build_mlx_header(struct mlx4_ib_qp *qp, const struct ib_ud_wr *wr,
301462306a36Sopenharmony_ci			    void *wqe, unsigned *mlx_seg_len)
301562306a36Sopenharmony_ci{
301662306a36Sopenharmony_ci	struct mlx4_ib_sqp *sqp = qp->sqp;
301762306a36Sopenharmony_ci	struct ib_device *ib_dev = qp->ibqp.device;
301862306a36Sopenharmony_ci	struct mlx4_ib_dev *ibdev = to_mdev(ib_dev);
301962306a36Sopenharmony_ci	struct mlx4_wqe_mlx_seg *mlx = wqe;
302062306a36Sopenharmony_ci	struct mlx4_wqe_ctrl_seg *ctrl = wqe;
302162306a36Sopenharmony_ci	struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
302262306a36Sopenharmony_ci	struct mlx4_ib_ah *ah = to_mah(wr->ah);
302362306a36Sopenharmony_ci	union ib_gid sgid;
302462306a36Sopenharmony_ci	u16 pkey;
302562306a36Sopenharmony_ci	int send_size;
302662306a36Sopenharmony_ci	int header_size;
302762306a36Sopenharmony_ci	int spc;
302862306a36Sopenharmony_ci	int i;
302962306a36Sopenharmony_ci	int err = 0;
303062306a36Sopenharmony_ci	u16 vlan = 0xffff;
303162306a36Sopenharmony_ci	bool is_eth;
303262306a36Sopenharmony_ci	bool is_vlan = false;
303362306a36Sopenharmony_ci	bool is_grh;
303462306a36Sopenharmony_ci	bool is_udp = false;
303562306a36Sopenharmony_ci	int ip_version = 0;
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	send_size = 0;
303862306a36Sopenharmony_ci	for (i = 0; i < wr->wr.num_sge; ++i)
303962306a36Sopenharmony_ci		send_size += wr->wr.sg_list[i].length;
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_ci	is_eth = rdma_port_get_link_layer(qp->ibqp.device, qp->port) == IB_LINK_LAYER_ETHERNET;
304262306a36Sopenharmony_ci	is_grh = mlx4_ib_ah_grh_present(ah);
304362306a36Sopenharmony_ci	if (is_eth) {
304462306a36Sopenharmony_ci		enum ib_gid_type gid_type;
304562306a36Sopenharmony_ci		if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) {
304662306a36Sopenharmony_ci			/* When multi-function is enabled, the ib_core gid
304762306a36Sopenharmony_ci			 * indexes don't necessarily match the hw ones, so
304862306a36Sopenharmony_ci			 * we must use our own cache */
304962306a36Sopenharmony_ci			err = mlx4_get_roce_gid_from_slave(to_mdev(ib_dev)->dev,
305062306a36Sopenharmony_ci							   be32_to_cpu(ah->av.ib.port_pd) >> 24,
305162306a36Sopenharmony_ci							   ah->av.ib.gid_index, &sgid.raw[0]);
305262306a36Sopenharmony_ci			if (err)
305362306a36Sopenharmony_ci				return err;
305462306a36Sopenharmony_ci		} else  {
305562306a36Sopenharmony_ci			err = fill_gid_by_hw_index(ibdev, qp->port,
305662306a36Sopenharmony_ci						   ah->av.ib.gid_index, &sgid,
305762306a36Sopenharmony_ci						   &gid_type);
305862306a36Sopenharmony_ci			if (!err) {
305962306a36Sopenharmony_ci				is_udp = gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP;
306062306a36Sopenharmony_ci				if (is_udp) {
306162306a36Sopenharmony_ci					if (ipv6_addr_v4mapped((struct in6_addr *)&sgid))
306262306a36Sopenharmony_ci						ip_version = 4;
306362306a36Sopenharmony_ci					else
306462306a36Sopenharmony_ci						ip_version = 6;
306562306a36Sopenharmony_ci					is_grh = false;
306662306a36Sopenharmony_ci				}
306762306a36Sopenharmony_ci			} else {
306862306a36Sopenharmony_ci				return err;
306962306a36Sopenharmony_ci			}
307062306a36Sopenharmony_ci		}
307162306a36Sopenharmony_ci		if (ah->av.eth.vlan != cpu_to_be16(0xffff)) {
307262306a36Sopenharmony_ci			vlan = be16_to_cpu(ah->av.eth.vlan) & 0x0fff;
307362306a36Sopenharmony_ci			is_vlan = true;
307462306a36Sopenharmony_ci		}
307562306a36Sopenharmony_ci	}
307662306a36Sopenharmony_ci	err = ib_ud_header_init(send_size, !is_eth, is_eth, is_vlan, is_grh,
307762306a36Sopenharmony_ci			  ip_version, is_udp, 0, &sqp->ud_header);
307862306a36Sopenharmony_ci	if (err)
307962306a36Sopenharmony_ci		return err;
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	if (!is_eth) {
308262306a36Sopenharmony_ci		sqp->ud_header.lrh.service_level =
308362306a36Sopenharmony_ci			be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28;
308462306a36Sopenharmony_ci		sqp->ud_header.lrh.destination_lid = ah->av.ib.dlid;
308562306a36Sopenharmony_ci		sqp->ud_header.lrh.source_lid = cpu_to_be16(ah->av.ib.g_slid & 0x7f);
308662306a36Sopenharmony_ci	}
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci	if (is_grh || (ip_version == 6)) {
308962306a36Sopenharmony_ci		sqp->ud_header.grh.traffic_class =
309062306a36Sopenharmony_ci			(be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20) & 0xff;
309162306a36Sopenharmony_ci		sqp->ud_header.grh.flow_label    =
309262306a36Sopenharmony_ci			ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
309362306a36Sopenharmony_ci		sqp->ud_header.grh.hop_limit     = ah->av.ib.hop_limit;
309462306a36Sopenharmony_ci		if (is_eth) {
309562306a36Sopenharmony_ci			memcpy(sqp->ud_header.grh.source_gid.raw, sgid.raw, 16);
309662306a36Sopenharmony_ci		} else {
309762306a36Sopenharmony_ci			if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) {
309862306a36Sopenharmony_ci				/* When multi-function is enabled, the ib_core gid
309962306a36Sopenharmony_ci				 * indexes don't necessarily match the hw ones, so
310062306a36Sopenharmony_ci				 * we must use our own cache
310162306a36Sopenharmony_ci				 */
310262306a36Sopenharmony_ci				sqp->ud_header.grh.source_gid.global
310362306a36Sopenharmony_ci					.subnet_prefix =
310462306a36Sopenharmony_ci					cpu_to_be64(atomic64_read(
310562306a36Sopenharmony_ci						&(to_mdev(ib_dev)
310662306a36Sopenharmony_ci							  ->sriov
310762306a36Sopenharmony_ci							  .demux[qp->port - 1]
310862306a36Sopenharmony_ci							  .subnet_prefix)));
310962306a36Sopenharmony_ci				sqp->ud_header.grh.source_gid.global
311062306a36Sopenharmony_ci					.interface_id =
311162306a36Sopenharmony_ci					to_mdev(ib_dev)
311262306a36Sopenharmony_ci						->sriov.demux[qp->port - 1]
311362306a36Sopenharmony_ci						.guid_cache[ah->av.ib.gid_index];
311462306a36Sopenharmony_ci			} else {
311562306a36Sopenharmony_ci				sqp->ud_header.grh.source_gid =
311662306a36Sopenharmony_ci					ah->ibah.sgid_attr->gid;
311762306a36Sopenharmony_ci			}
311862306a36Sopenharmony_ci		}
311962306a36Sopenharmony_ci		memcpy(sqp->ud_header.grh.destination_gid.raw,
312062306a36Sopenharmony_ci		       ah->av.ib.dgid, 16);
312162306a36Sopenharmony_ci	}
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci	if (ip_version == 4) {
312462306a36Sopenharmony_ci		sqp->ud_header.ip4.tos =
312562306a36Sopenharmony_ci			(be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20) & 0xff;
312662306a36Sopenharmony_ci		sqp->ud_header.ip4.id = 0;
312762306a36Sopenharmony_ci		sqp->ud_header.ip4.frag_off = htons(IP_DF);
312862306a36Sopenharmony_ci		sqp->ud_header.ip4.ttl = ah->av.eth.hop_limit;
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_ci		memcpy(&sqp->ud_header.ip4.saddr,
313162306a36Sopenharmony_ci		       sgid.raw + 12, 4);
313262306a36Sopenharmony_ci		memcpy(&sqp->ud_header.ip4.daddr, ah->av.ib.dgid + 12, 4);
313362306a36Sopenharmony_ci		sqp->ud_header.ip4.check = ib_ud_ip4_csum(&sqp->ud_header);
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	if (is_udp) {
313762306a36Sopenharmony_ci		sqp->ud_header.udp.dport = htons(ROCE_V2_UDP_DPORT);
313862306a36Sopenharmony_ci		sqp->ud_header.udp.sport = htons(MLX4_ROCEV2_QP1_SPORT);
313962306a36Sopenharmony_ci		sqp->ud_header.udp.csum = 0;
314062306a36Sopenharmony_ci	}
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ci	mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE);
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ci	if (!is_eth) {
314562306a36Sopenharmony_ci		mlx->flags |=
314662306a36Sopenharmony_ci			cpu_to_be32((!qp->ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) |
314762306a36Sopenharmony_ci				    (sqp->ud_header.lrh.destination_lid ==
314862306a36Sopenharmony_ci						     IB_LID_PERMISSIVE ?
314962306a36Sopenharmony_ci					     MLX4_WQE_MLX_SLR :
315062306a36Sopenharmony_ci					     0) |
315162306a36Sopenharmony_ci				    (sqp->ud_header.lrh.service_level << 8));
315262306a36Sopenharmony_ci		if (ah->av.ib.port_pd & cpu_to_be32(0x80000000))
315362306a36Sopenharmony_ci			mlx->flags |= cpu_to_be32(0x1); /* force loopback */
315462306a36Sopenharmony_ci		mlx->rlid = sqp->ud_header.lrh.destination_lid;
315562306a36Sopenharmony_ci	}
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	switch (wr->wr.opcode) {
315862306a36Sopenharmony_ci	case IB_WR_SEND:
315962306a36Sopenharmony_ci		sqp->ud_header.bth.opcode	 = IB_OPCODE_UD_SEND_ONLY;
316062306a36Sopenharmony_ci		sqp->ud_header.immediate_present = 0;
316162306a36Sopenharmony_ci		break;
316262306a36Sopenharmony_ci	case IB_WR_SEND_WITH_IMM:
316362306a36Sopenharmony_ci		sqp->ud_header.bth.opcode	 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
316462306a36Sopenharmony_ci		sqp->ud_header.immediate_present = 1;
316562306a36Sopenharmony_ci		sqp->ud_header.immediate_data    = wr->wr.ex.imm_data;
316662306a36Sopenharmony_ci		break;
316762306a36Sopenharmony_ci	default:
316862306a36Sopenharmony_ci		return -EINVAL;
316962306a36Sopenharmony_ci	}
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci	if (is_eth) {
317262306a36Sopenharmony_ci		u16 ether_type;
317362306a36Sopenharmony_ci		u16 pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13;
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci		ether_type = (!is_udp) ? ETH_P_IBOE:
317662306a36Sopenharmony_ci			(ip_version == 4 ? ETH_P_IP : ETH_P_IPV6);
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci		mlx->sched_prio = cpu_to_be16(pcp);
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ci		ether_addr_copy(sqp->ud_header.eth.smac_h, ah->av.eth.s_mac);
318162306a36Sopenharmony_ci		ether_addr_copy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac);
318262306a36Sopenharmony_ci		memcpy(&ctrl->srcrb_flags16[0], ah->av.eth.mac, 2);
318362306a36Sopenharmony_ci		memcpy(&ctrl->imm, ah->av.eth.mac + 2, 4);
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci		if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
318662306a36Sopenharmony_ci			mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
318762306a36Sopenharmony_ci		if (!is_vlan) {
318862306a36Sopenharmony_ci			sqp->ud_header.eth.type = cpu_to_be16(ether_type);
318962306a36Sopenharmony_ci		} else {
319062306a36Sopenharmony_ci			sqp->ud_header.vlan.type = cpu_to_be16(ether_type);
319162306a36Sopenharmony_ci			sqp->ud_header.vlan.tag = cpu_to_be16(vlan | pcp);
319262306a36Sopenharmony_ci		}
319362306a36Sopenharmony_ci	} else {
319462306a36Sopenharmony_ci		sqp->ud_header.lrh.virtual_lane =
319562306a36Sopenharmony_ci			!qp->ibqp.qp_num ?
319662306a36Sopenharmony_ci				15 :
319762306a36Sopenharmony_ci				sl_to_vl(to_mdev(ib_dev),
319862306a36Sopenharmony_ci					 sqp->ud_header.lrh.service_level,
319962306a36Sopenharmony_ci					 qp->port);
320062306a36Sopenharmony_ci		if (qp->ibqp.qp_num && sqp->ud_header.lrh.virtual_lane == 15)
320162306a36Sopenharmony_ci			return -EINVAL;
320262306a36Sopenharmony_ci		if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE)
320362306a36Sopenharmony_ci			sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE;
320462306a36Sopenharmony_ci	}
320562306a36Sopenharmony_ci	sqp->ud_header.bth.solicited_event = !!(wr->wr.send_flags & IB_SEND_SOLICITED);
320662306a36Sopenharmony_ci	if (!qp->ibqp.qp_num)
320762306a36Sopenharmony_ci		err = ib_get_cached_pkey(ib_dev, qp->port, sqp->pkey_index,
320862306a36Sopenharmony_ci					 &pkey);
320962306a36Sopenharmony_ci	else
321062306a36Sopenharmony_ci		err = ib_get_cached_pkey(ib_dev, qp->port, wr->pkey_index,
321162306a36Sopenharmony_ci					 &pkey);
321262306a36Sopenharmony_ci	if (err)
321362306a36Sopenharmony_ci		return err;
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	sqp->ud_header.bth.pkey = cpu_to_be16(pkey);
321662306a36Sopenharmony_ci	sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->remote_qpn);
321762306a36Sopenharmony_ci	sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1));
321862306a36Sopenharmony_ci	sqp->ud_header.deth.qkey = cpu_to_be32(wr->remote_qkey & 0x80000000 ?
321962306a36Sopenharmony_ci					       sqp->qkey : wr->remote_qkey);
322062306a36Sopenharmony_ci	sqp->ud_header.deth.source_qpn = cpu_to_be32(qp->ibqp.qp_num);
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	header_size = ib_ud_header_pack(&sqp->ud_header, sqp->header_buf);
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	if (0) {
322562306a36Sopenharmony_ci		pr_err("built UD header of size %d:\n", header_size);
322662306a36Sopenharmony_ci		for (i = 0; i < header_size / 4; ++i) {
322762306a36Sopenharmony_ci			if (i % 8 == 0)
322862306a36Sopenharmony_ci				pr_err("  [%02x] ", i * 4);
322962306a36Sopenharmony_ci			pr_cont(" %08x",
323062306a36Sopenharmony_ci				be32_to_cpu(((__be32 *) sqp->header_buf)[i]));
323162306a36Sopenharmony_ci			if ((i + 1) % 8 == 0)
323262306a36Sopenharmony_ci				pr_cont("\n");
323362306a36Sopenharmony_ci		}
323462306a36Sopenharmony_ci		pr_err("\n");
323562306a36Sopenharmony_ci	}
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_ci	/*
323862306a36Sopenharmony_ci	 * Inline data segments may not cross a 64 byte boundary.  If
323962306a36Sopenharmony_ci	 * our UD header is bigger than the space available up to the
324062306a36Sopenharmony_ci	 * next 64 byte boundary in the WQE, use two inline data
324162306a36Sopenharmony_ci	 * segments to hold the UD header.
324262306a36Sopenharmony_ci	 */
324362306a36Sopenharmony_ci	spc = MLX4_INLINE_ALIGN -
324462306a36Sopenharmony_ci		((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1));
324562306a36Sopenharmony_ci	if (header_size <= spc) {
324662306a36Sopenharmony_ci		inl->byte_count = cpu_to_be32(1 << 31 | header_size);
324762306a36Sopenharmony_ci		memcpy(inl + 1, sqp->header_buf, header_size);
324862306a36Sopenharmony_ci		i = 1;
324962306a36Sopenharmony_ci	} else {
325062306a36Sopenharmony_ci		inl->byte_count = cpu_to_be32(1 << 31 | spc);
325162306a36Sopenharmony_ci		memcpy(inl + 1, sqp->header_buf, spc);
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci		inl = (void *) (inl + 1) + spc;
325462306a36Sopenharmony_ci		memcpy(inl + 1, sqp->header_buf + spc, header_size - spc);
325562306a36Sopenharmony_ci		/*
325662306a36Sopenharmony_ci		 * Need a barrier here to make sure all the data is
325762306a36Sopenharmony_ci		 * visible before the byte_count field is set.
325862306a36Sopenharmony_ci		 * Otherwise the HCA prefetcher could grab the 64-byte
325962306a36Sopenharmony_ci		 * chunk with this inline segment and get a valid (!=
326062306a36Sopenharmony_ci		 * 0xffffffff) byte count but stale data, and end up
326162306a36Sopenharmony_ci		 * generating a packet with bad headers.
326262306a36Sopenharmony_ci		 *
326362306a36Sopenharmony_ci		 * The first inline segment's byte_count field doesn't
326462306a36Sopenharmony_ci		 * need a barrier, because it comes after a
326562306a36Sopenharmony_ci		 * control/MLX segment and therefore is at an offset
326662306a36Sopenharmony_ci		 * of 16 mod 64.
326762306a36Sopenharmony_ci		 */
326862306a36Sopenharmony_ci		wmb();
326962306a36Sopenharmony_ci		inl->byte_count = cpu_to_be32(1 << 31 | (header_size - spc));
327062306a36Sopenharmony_ci		i = 2;
327162306a36Sopenharmony_ci	}
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci	*mlx_seg_len =
327462306a36Sopenharmony_ci		ALIGN(i * sizeof (struct mlx4_wqe_inline_seg) + header_size, 16);
327562306a36Sopenharmony_ci	return 0;
327662306a36Sopenharmony_ci}
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_cistatic int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq)
327962306a36Sopenharmony_ci{
328062306a36Sopenharmony_ci	unsigned cur;
328162306a36Sopenharmony_ci	struct mlx4_ib_cq *cq;
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci	cur = wq->head - wq->tail;
328462306a36Sopenharmony_ci	if (likely(cur + nreq < wq->max_post))
328562306a36Sopenharmony_ci		return 0;
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci	cq = to_mcq(ib_cq);
328862306a36Sopenharmony_ci	spin_lock(&cq->lock);
328962306a36Sopenharmony_ci	cur = wq->head - wq->tail;
329062306a36Sopenharmony_ci	spin_unlock(&cq->lock);
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci	return cur + nreq >= wq->max_post;
329362306a36Sopenharmony_ci}
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_cistatic __be32 convert_access(int acc)
329662306a36Sopenharmony_ci{
329762306a36Sopenharmony_ci	return (acc & IB_ACCESS_REMOTE_ATOMIC ?
329862306a36Sopenharmony_ci		cpu_to_be32(MLX4_WQE_FMR_AND_BIND_PERM_ATOMIC)       : 0) |
329962306a36Sopenharmony_ci	       (acc & IB_ACCESS_REMOTE_WRITE  ?
330062306a36Sopenharmony_ci		cpu_to_be32(MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_WRITE) : 0) |
330162306a36Sopenharmony_ci	       (acc & IB_ACCESS_REMOTE_READ   ?
330262306a36Sopenharmony_ci		cpu_to_be32(MLX4_WQE_FMR_AND_BIND_PERM_REMOTE_READ)  : 0) |
330362306a36Sopenharmony_ci	       (acc & IB_ACCESS_LOCAL_WRITE   ? cpu_to_be32(MLX4_WQE_FMR_PERM_LOCAL_WRITE)  : 0) |
330462306a36Sopenharmony_ci		cpu_to_be32(MLX4_WQE_FMR_PERM_LOCAL_READ);
330562306a36Sopenharmony_ci}
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_cistatic void set_reg_seg(struct mlx4_wqe_fmr_seg *fseg,
330862306a36Sopenharmony_ci			const struct ib_reg_wr *wr)
330962306a36Sopenharmony_ci{
331062306a36Sopenharmony_ci	struct mlx4_ib_mr *mr = to_mmr(wr->mr);
331162306a36Sopenharmony_ci
331262306a36Sopenharmony_ci	fseg->flags		= convert_access(wr->access);
331362306a36Sopenharmony_ci	fseg->mem_key		= cpu_to_be32(wr->key);
331462306a36Sopenharmony_ci	fseg->buf_list		= cpu_to_be64(mr->page_map);
331562306a36Sopenharmony_ci	fseg->start_addr	= cpu_to_be64(mr->ibmr.iova);
331662306a36Sopenharmony_ci	fseg->reg_len		= cpu_to_be64(mr->ibmr.length);
331762306a36Sopenharmony_ci	fseg->offset		= 0; /* XXX -- is this just for ZBVA? */
331862306a36Sopenharmony_ci	fseg->page_size		= cpu_to_be32(ilog2(mr->ibmr.page_size));
331962306a36Sopenharmony_ci	fseg->reserved[0]	= 0;
332062306a36Sopenharmony_ci	fseg->reserved[1]	= 0;
332162306a36Sopenharmony_ci}
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_cistatic void set_local_inv_seg(struct mlx4_wqe_local_inval_seg *iseg, u32 rkey)
332462306a36Sopenharmony_ci{
332562306a36Sopenharmony_ci	memset(iseg, 0, sizeof(*iseg));
332662306a36Sopenharmony_ci	iseg->mem_key = cpu_to_be32(rkey);
332762306a36Sopenharmony_ci}
332862306a36Sopenharmony_ci
332962306a36Sopenharmony_cistatic __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg,
333062306a36Sopenharmony_ci					  u64 remote_addr, u32 rkey)
333162306a36Sopenharmony_ci{
333262306a36Sopenharmony_ci	rseg->raddr    = cpu_to_be64(remote_addr);
333362306a36Sopenharmony_ci	rseg->rkey     = cpu_to_be32(rkey);
333462306a36Sopenharmony_ci	rseg->reserved = 0;
333562306a36Sopenharmony_ci}
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_cistatic void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg,
333862306a36Sopenharmony_ci			   const struct ib_atomic_wr *wr)
333962306a36Sopenharmony_ci{
334062306a36Sopenharmony_ci	if (wr->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
334162306a36Sopenharmony_ci		aseg->swap_add = cpu_to_be64(wr->swap);
334262306a36Sopenharmony_ci		aseg->compare  = cpu_to_be64(wr->compare_add);
334362306a36Sopenharmony_ci	} else if (wr->wr.opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) {
334462306a36Sopenharmony_ci		aseg->swap_add = cpu_to_be64(wr->compare_add);
334562306a36Sopenharmony_ci		aseg->compare  = cpu_to_be64(wr->compare_add_mask);
334662306a36Sopenharmony_ci	} else {
334762306a36Sopenharmony_ci		aseg->swap_add = cpu_to_be64(wr->compare_add);
334862306a36Sopenharmony_ci		aseg->compare  = 0;
334962306a36Sopenharmony_ci	}
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci}
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_cistatic void set_masked_atomic_seg(struct mlx4_wqe_masked_atomic_seg *aseg,
335462306a36Sopenharmony_ci				  const struct ib_atomic_wr *wr)
335562306a36Sopenharmony_ci{
335662306a36Sopenharmony_ci	aseg->swap_add		= cpu_to_be64(wr->swap);
335762306a36Sopenharmony_ci	aseg->swap_add_mask	= cpu_to_be64(wr->swap_mask);
335862306a36Sopenharmony_ci	aseg->compare		= cpu_to_be64(wr->compare_add);
335962306a36Sopenharmony_ci	aseg->compare_mask	= cpu_to_be64(wr->compare_add_mask);
336062306a36Sopenharmony_ci}
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_cistatic void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
336362306a36Sopenharmony_ci			     const struct ib_ud_wr *wr)
336462306a36Sopenharmony_ci{
336562306a36Sopenharmony_ci	memcpy(dseg->av, &to_mah(wr->ah)->av, sizeof (struct mlx4_av));
336662306a36Sopenharmony_ci	dseg->dqpn = cpu_to_be32(wr->remote_qpn);
336762306a36Sopenharmony_ci	dseg->qkey = cpu_to_be32(wr->remote_qkey);
336862306a36Sopenharmony_ci	dseg->vlan = to_mah(wr->ah)->av.eth.vlan;
336962306a36Sopenharmony_ci	memcpy(dseg->mac, to_mah(wr->ah)->av.eth.mac, 6);
337062306a36Sopenharmony_ci}
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_cistatic void set_tunnel_datagram_seg(struct mlx4_ib_dev *dev,
337362306a36Sopenharmony_ci				    struct mlx4_wqe_datagram_seg *dseg,
337462306a36Sopenharmony_ci				    const struct ib_ud_wr *wr,
337562306a36Sopenharmony_ci				    enum mlx4_ib_qp_type qpt)
337662306a36Sopenharmony_ci{
337762306a36Sopenharmony_ci	union mlx4_ext_av *av = &to_mah(wr->ah)->av;
337862306a36Sopenharmony_ci	struct mlx4_av sqp_av = {0};
337962306a36Sopenharmony_ci	int port = *((u8 *) &av->ib.port_pd) & 0x3;
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ci	/* force loopback */
338262306a36Sopenharmony_ci	sqp_av.port_pd = av->ib.port_pd | cpu_to_be32(0x80000000);
338362306a36Sopenharmony_ci	sqp_av.g_slid = av->ib.g_slid & 0x7f; /* no GRH */
338462306a36Sopenharmony_ci	sqp_av.sl_tclass_flowlabel = av->ib.sl_tclass_flowlabel &
338562306a36Sopenharmony_ci			cpu_to_be32(0xf0000000);
338662306a36Sopenharmony_ci
338762306a36Sopenharmony_ci	memcpy(dseg->av, &sqp_av, sizeof (struct mlx4_av));
338862306a36Sopenharmony_ci	if (qpt == MLX4_IB_QPT_PROXY_GSI)
338962306a36Sopenharmony_ci		dseg->dqpn = cpu_to_be32(dev->dev->caps.spec_qps[port - 1].qp1_tunnel);
339062306a36Sopenharmony_ci	else
339162306a36Sopenharmony_ci		dseg->dqpn = cpu_to_be32(dev->dev->caps.spec_qps[port - 1].qp0_tunnel);
339262306a36Sopenharmony_ci	/* Use QKEY from the QP context, which is set by master */
339362306a36Sopenharmony_ci	dseg->qkey = cpu_to_be32(IB_QP_SET_QKEY);
339462306a36Sopenharmony_ci}
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_cistatic void build_tunnel_header(const struct ib_ud_wr *wr, void *wqe,
339762306a36Sopenharmony_ci				unsigned *mlx_seg_len)
339862306a36Sopenharmony_ci{
339962306a36Sopenharmony_ci	struct mlx4_wqe_inline_seg *inl = wqe;
340062306a36Sopenharmony_ci	struct mlx4_ib_tunnel_header hdr;
340162306a36Sopenharmony_ci	struct mlx4_ib_ah *ah = to_mah(wr->ah);
340262306a36Sopenharmony_ci	int spc;
340362306a36Sopenharmony_ci	int i;
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	memcpy(&hdr.av, &ah->av, sizeof hdr.av);
340662306a36Sopenharmony_ci	hdr.remote_qpn = cpu_to_be32(wr->remote_qpn);
340762306a36Sopenharmony_ci	hdr.pkey_index = cpu_to_be16(wr->pkey_index);
340862306a36Sopenharmony_ci	hdr.qkey = cpu_to_be32(wr->remote_qkey);
340962306a36Sopenharmony_ci	memcpy(hdr.mac, ah->av.eth.mac, 6);
341062306a36Sopenharmony_ci	hdr.vlan = ah->av.eth.vlan;
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci	spc = MLX4_INLINE_ALIGN -
341362306a36Sopenharmony_ci		((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1));
341462306a36Sopenharmony_ci	if (sizeof (hdr) <= spc) {
341562306a36Sopenharmony_ci		memcpy(inl + 1, &hdr, sizeof (hdr));
341662306a36Sopenharmony_ci		wmb();
341762306a36Sopenharmony_ci		inl->byte_count = cpu_to_be32(1 << 31 | sizeof (hdr));
341862306a36Sopenharmony_ci		i = 1;
341962306a36Sopenharmony_ci	} else {
342062306a36Sopenharmony_ci		memcpy(inl + 1, &hdr, spc);
342162306a36Sopenharmony_ci		wmb();
342262306a36Sopenharmony_ci		inl->byte_count = cpu_to_be32(1 << 31 | spc);
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci		inl = (void *) (inl + 1) + spc;
342562306a36Sopenharmony_ci		memcpy(inl + 1, (void *) &hdr + spc, sizeof (hdr) - spc);
342662306a36Sopenharmony_ci		wmb();
342762306a36Sopenharmony_ci		inl->byte_count = cpu_to_be32(1 << 31 | (sizeof (hdr) - spc));
342862306a36Sopenharmony_ci		i = 2;
342962306a36Sopenharmony_ci	}
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci	*mlx_seg_len =
343262306a36Sopenharmony_ci		ALIGN(i * sizeof (struct mlx4_wqe_inline_seg) + sizeof (hdr), 16);
343362306a36Sopenharmony_ci}
343462306a36Sopenharmony_ci
343562306a36Sopenharmony_cistatic void set_mlx_icrc_seg(void *dseg)
343662306a36Sopenharmony_ci{
343762306a36Sopenharmony_ci	u32 *t = dseg;
343862306a36Sopenharmony_ci	struct mlx4_wqe_inline_seg *iseg = dseg;
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci	t[1] = 0;
344162306a36Sopenharmony_ci
344262306a36Sopenharmony_ci	/*
344362306a36Sopenharmony_ci	 * Need a barrier here before writing the byte_count field to
344462306a36Sopenharmony_ci	 * make sure that all the data is visible before the
344562306a36Sopenharmony_ci	 * byte_count field is set.  Otherwise, if the segment begins
344662306a36Sopenharmony_ci	 * a new cacheline, the HCA prefetcher could grab the 64-byte
344762306a36Sopenharmony_ci	 * chunk and get a valid (!= * 0xffffffff) byte count but
344862306a36Sopenharmony_ci	 * stale data, and end up sending the wrong data.
344962306a36Sopenharmony_ci	 */
345062306a36Sopenharmony_ci	wmb();
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	iseg->byte_count = cpu_to_be32((1 << 31) | 4);
345362306a36Sopenharmony_ci}
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_cistatic void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
345662306a36Sopenharmony_ci{
345762306a36Sopenharmony_ci	dseg->lkey       = cpu_to_be32(sg->lkey);
345862306a36Sopenharmony_ci	dseg->addr       = cpu_to_be64(sg->addr);
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	/*
346162306a36Sopenharmony_ci	 * Need a barrier here before writing the byte_count field to
346262306a36Sopenharmony_ci	 * make sure that all the data is visible before the
346362306a36Sopenharmony_ci	 * byte_count field is set.  Otherwise, if the segment begins
346462306a36Sopenharmony_ci	 * a new cacheline, the HCA prefetcher could grab the 64-byte
346562306a36Sopenharmony_ci	 * chunk and get a valid (!= * 0xffffffff) byte count but
346662306a36Sopenharmony_ci	 * stale data, and end up sending the wrong data.
346762306a36Sopenharmony_ci	 */
346862306a36Sopenharmony_ci	wmb();
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci	dseg->byte_count = cpu_to_be32(sg->length);
347162306a36Sopenharmony_ci}
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_cistatic void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
347462306a36Sopenharmony_ci{
347562306a36Sopenharmony_ci	dseg->byte_count = cpu_to_be32(sg->length);
347662306a36Sopenharmony_ci	dseg->lkey       = cpu_to_be32(sg->lkey);
347762306a36Sopenharmony_ci	dseg->addr       = cpu_to_be64(sg->addr);
347862306a36Sopenharmony_ci}
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_cistatic int build_lso_seg(struct mlx4_wqe_lso_seg *wqe,
348162306a36Sopenharmony_ci			 const struct ib_ud_wr *wr, struct mlx4_ib_qp *qp,
348262306a36Sopenharmony_ci			 unsigned *lso_seg_len, __be32 *lso_hdr_sz, __be32 *blh)
348362306a36Sopenharmony_ci{
348462306a36Sopenharmony_ci	unsigned halign = ALIGN(sizeof *wqe + wr->hlen, 16);
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ci	if (unlikely(halign > MLX4_IB_CACHE_LINE_SIZE))
348762306a36Sopenharmony_ci		*blh = cpu_to_be32(1 << 6);
348862306a36Sopenharmony_ci
348962306a36Sopenharmony_ci	if (unlikely(!(qp->flags & MLX4_IB_QP_LSO) &&
349062306a36Sopenharmony_ci		     wr->wr.num_sge > qp->sq.max_gs - (halign >> 4)))
349162306a36Sopenharmony_ci		return -EINVAL;
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci	memcpy(wqe->header, wr->header, wr->hlen);
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	*lso_hdr_sz  = cpu_to_be32(wr->mss << 16 | wr->hlen);
349662306a36Sopenharmony_ci	*lso_seg_len = halign;
349762306a36Sopenharmony_ci	return 0;
349862306a36Sopenharmony_ci}
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_cistatic __be32 send_ieth(const struct ib_send_wr *wr)
350162306a36Sopenharmony_ci{
350262306a36Sopenharmony_ci	switch (wr->opcode) {
350362306a36Sopenharmony_ci	case IB_WR_SEND_WITH_IMM:
350462306a36Sopenharmony_ci	case IB_WR_RDMA_WRITE_WITH_IMM:
350562306a36Sopenharmony_ci		return wr->ex.imm_data;
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci	case IB_WR_SEND_WITH_INV:
350862306a36Sopenharmony_ci		return cpu_to_be32(wr->ex.invalidate_rkey);
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_ci	default:
351162306a36Sopenharmony_ci		return 0;
351262306a36Sopenharmony_ci	}
351362306a36Sopenharmony_ci}
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_cistatic void add_zero_len_inline(void *wqe)
351662306a36Sopenharmony_ci{
351762306a36Sopenharmony_ci	struct mlx4_wqe_inline_seg *inl = wqe;
351862306a36Sopenharmony_ci	memset(wqe, 0, 16);
351962306a36Sopenharmony_ci	inl->byte_count = cpu_to_be32(1 << 31);
352062306a36Sopenharmony_ci}
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_cistatic int _mlx4_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
352362306a36Sopenharmony_ci			      const struct ib_send_wr **bad_wr, bool drain)
352462306a36Sopenharmony_ci{
352562306a36Sopenharmony_ci	struct mlx4_ib_qp *qp = to_mqp(ibqp);
352662306a36Sopenharmony_ci	void *wqe;
352762306a36Sopenharmony_ci	struct mlx4_wqe_ctrl_seg *ctrl;
352862306a36Sopenharmony_ci	struct mlx4_wqe_data_seg *dseg;
352962306a36Sopenharmony_ci	unsigned long flags;
353062306a36Sopenharmony_ci	int nreq;
353162306a36Sopenharmony_ci	int err = 0;
353262306a36Sopenharmony_ci	unsigned ind;
353362306a36Sopenharmony_ci	int size;
353462306a36Sopenharmony_ci	unsigned seglen;
353562306a36Sopenharmony_ci	__be32 dummy;
353662306a36Sopenharmony_ci	__be32 *lso_wqe;
353762306a36Sopenharmony_ci	__be32 lso_hdr_sz;
353862306a36Sopenharmony_ci	__be32 blh;
353962306a36Sopenharmony_ci	int i;
354062306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci	if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI) {
354362306a36Sopenharmony_ci		struct mlx4_ib_sqp *sqp = qp->sqp;
354462306a36Sopenharmony_ci
354562306a36Sopenharmony_ci		if (sqp->roce_v2_gsi) {
354662306a36Sopenharmony_ci			struct mlx4_ib_ah *ah = to_mah(ud_wr(wr)->ah);
354762306a36Sopenharmony_ci			enum ib_gid_type gid_type;
354862306a36Sopenharmony_ci			union ib_gid gid;
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci			if (!fill_gid_by_hw_index(mdev, qp->port,
355162306a36Sopenharmony_ci					   ah->av.ib.gid_index,
355262306a36Sopenharmony_ci					   &gid, &gid_type))
355362306a36Sopenharmony_ci				qp = (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ?
355462306a36Sopenharmony_ci						to_mqp(sqp->roce_v2_gsi) : qp;
355562306a36Sopenharmony_ci			else
355662306a36Sopenharmony_ci				pr_err("Failed to get gid at index %d. RoCEv2 will not work properly\n",
355762306a36Sopenharmony_ci				       ah->av.ib.gid_index);
355862306a36Sopenharmony_ci		}
355962306a36Sopenharmony_ci	}
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	spin_lock_irqsave(&qp->sq.lock, flags);
356262306a36Sopenharmony_ci	if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR &&
356362306a36Sopenharmony_ci	    !drain) {
356462306a36Sopenharmony_ci		err = -EIO;
356562306a36Sopenharmony_ci		*bad_wr = wr;
356662306a36Sopenharmony_ci		nreq = 0;
356762306a36Sopenharmony_ci		goto out;
356862306a36Sopenharmony_ci	}
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	ind = qp->sq_next_wqe;
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci	for (nreq = 0; wr; ++nreq, wr = wr->next) {
357362306a36Sopenharmony_ci		lso_wqe = &dummy;
357462306a36Sopenharmony_ci		blh = 0;
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci		if (mlx4_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) {
357762306a36Sopenharmony_ci			err = -ENOMEM;
357862306a36Sopenharmony_ci			*bad_wr = wr;
357962306a36Sopenharmony_ci			goto out;
358062306a36Sopenharmony_ci		}
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci		if (unlikely(wr->num_sge > qp->sq.max_gs)) {
358362306a36Sopenharmony_ci			err = -EINVAL;
358462306a36Sopenharmony_ci			*bad_wr = wr;
358562306a36Sopenharmony_ci			goto out;
358662306a36Sopenharmony_ci		}
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci		ctrl = wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1));
358962306a36Sopenharmony_ci		qp->sq.wrid[(qp->sq.head + nreq) & (qp->sq.wqe_cnt - 1)] = wr->wr_id;
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci		ctrl->srcrb_flags =
359262306a36Sopenharmony_ci			(wr->send_flags & IB_SEND_SIGNALED ?
359362306a36Sopenharmony_ci			 cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) : 0) |
359462306a36Sopenharmony_ci			(wr->send_flags & IB_SEND_SOLICITED ?
359562306a36Sopenharmony_ci			 cpu_to_be32(MLX4_WQE_CTRL_SOLICITED) : 0) |
359662306a36Sopenharmony_ci			((wr->send_flags & IB_SEND_IP_CSUM) ?
359762306a36Sopenharmony_ci			 cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM |
359862306a36Sopenharmony_ci				     MLX4_WQE_CTRL_TCP_UDP_CSUM) : 0) |
359962306a36Sopenharmony_ci			qp->sq_signal_bits;
360062306a36Sopenharmony_ci
360162306a36Sopenharmony_ci		ctrl->imm = send_ieth(wr);
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci		wqe += sizeof *ctrl;
360462306a36Sopenharmony_ci		size = sizeof *ctrl / 16;
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci		switch (qp->mlx4_ib_qp_type) {
360762306a36Sopenharmony_ci		case MLX4_IB_QPT_RC:
360862306a36Sopenharmony_ci		case MLX4_IB_QPT_UC:
360962306a36Sopenharmony_ci			switch (wr->opcode) {
361062306a36Sopenharmony_ci			case IB_WR_ATOMIC_CMP_AND_SWP:
361162306a36Sopenharmony_ci			case IB_WR_ATOMIC_FETCH_AND_ADD:
361262306a36Sopenharmony_ci			case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD:
361362306a36Sopenharmony_ci				set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
361462306a36Sopenharmony_ci					      atomic_wr(wr)->rkey);
361562306a36Sopenharmony_ci				wqe  += sizeof (struct mlx4_wqe_raddr_seg);
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci				set_atomic_seg(wqe, atomic_wr(wr));
361862306a36Sopenharmony_ci				wqe  += sizeof (struct mlx4_wqe_atomic_seg);
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci				size += (sizeof (struct mlx4_wqe_raddr_seg) +
362162306a36Sopenharmony_ci					 sizeof (struct mlx4_wqe_atomic_seg)) / 16;
362262306a36Sopenharmony_ci
362362306a36Sopenharmony_ci				break;
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_ci			case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
362662306a36Sopenharmony_ci				set_raddr_seg(wqe, atomic_wr(wr)->remote_addr,
362762306a36Sopenharmony_ci					      atomic_wr(wr)->rkey);
362862306a36Sopenharmony_ci				wqe  += sizeof (struct mlx4_wqe_raddr_seg);
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci				set_masked_atomic_seg(wqe, atomic_wr(wr));
363162306a36Sopenharmony_ci				wqe  += sizeof (struct mlx4_wqe_masked_atomic_seg);
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci				size += (sizeof (struct mlx4_wqe_raddr_seg) +
363462306a36Sopenharmony_ci					 sizeof (struct mlx4_wqe_masked_atomic_seg)) / 16;
363562306a36Sopenharmony_ci
363662306a36Sopenharmony_ci				break;
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci			case IB_WR_RDMA_READ:
363962306a36Sopenharmony_ci			case IB_WR_RDMA_WRITE:
364062306a36Sopenharmony_ci			case IB_WR_RDMA_WRITE_WITH_IMM:
364162306a36Sopenharmony_ci				set_raddr_seg(wqe, rdma_wr(wr)->remote_addr,
364262306a36Sopenharmony_ci					      rdma_wr(wr)->rkey);
364362306a36Sopenharmony_ci				wqe  += sizeof (struct mlx4_wqe_raddr_seg);
364462306a36Sopenharmony_ci				size += sizeof (struct mlx4_wqe_raddr_seg) / 16;
364562306a36Sopenharmony_ci				break;
364662306a36Sopenharmony_ci
364762306a36Sopenharmony_ci			case IB_WR_LOCAL_INV:
364862306a36Sopenharmony_ci				ctrl->srcrb_flags |=
364962306a36Sopenharmony_ci					cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER);
365062306a36Sopenharmony_ci				set_local_inv_seg(wqe, wr->ex.invalidate_rkey);
365162306a36Sopenharmony_ci				wqe  += sizeof (struct mlx4_wqe_local_inval_seg);
365262306a36Sopenharmony_ci				size += sizeof (struct mlx4_wqe_local_inval_seg) / 16;
365362306a36Sopenharmony_ci				break;
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci			case IB_WR_REG_MR:
365662306a36Sopenharmony_ci				ctrl->srcrb_flags |=
365762306a36Sopenharmony_ci					cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER);
365862306a36Sopenharmony_ci				set_reg_seg(wqe, reg_wr(wr));
365962306a36Sopenharmony_ci				wqe  += sizeof(struct mlx4_wqe_fmr_seg);
366062306a36Sopenharmony_ci				size += sizeof(struct mlx4_wqe_fmr_seg) / 16;
366162306a36Sopenharmony_ci				break;
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_ci			default:
366462306a36Sopenharmony_ci				/* No extra segments required for sends */
366562306a36Sopenharmony_ci				break;
366662306a36Sopenharmony_ci			}
366762306a36Sopenharmony_ci			break;
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci		case MLX4_IB_QPT_TUN_SMI_OWNER:
367062306a36Sopenharmony_ci			err = build_sriov_qp0_header(qp, ud_wr(wr), ctrl,
367162306a36Sopenharmony_ci						     &seglen);
367262306a36Sopenharmony_ci			if (unlikely(err)) {
367362306a36Sopenharmony_ci				*bad_wr = wr;
367462306a36Sopenharmony_ci				goto out;
367562306a36Sopenharmony_ci			}
367662306a36Sopenharmony_ci			wqe  += seglen;
367762306a36Sopenharmony_ci			size += seglen / 16;
367862306a36Sopenharmony_ci			break;
367962306a36Sopenharmony_ci		case MLX4_IB_QPT_TUN_SMI:
368062306a36Sopenharmony_ci		case MLX4_IB_QPT_TUN_GSI:
368162306a36Sopenharmony_ci			/* this is a UD qp used in MAD responses to slaves. */
368262306a36Sopenharmony_ci			set_datagram_seg(wqe, ud_wr(wr));
368362306a36Sopenharmony_ci			/* set the forced-loopback bit in the data seg av */
368462306a36Sopenharmony_ci			*(__be32 *) wqe |= cpu_to_be32(0x80000000);
368562306a36Sopenharmony_ci			wqe  += sizeof (struct mlx4_wqe_datagram_seg);
368662306a36Sopenharmony_ci			size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
368762306a36Sopenharmony_ci			break;
368862306a36Sopenharmony_ci		case MLX4_IB_QPT_UD:
368962306a36Sopenharmony_ci			set_datagram_seg(wqe, ud_wr(wr));
369062306a36Sopenharmony_ci			wqe  += sizeof (struct mlx4_wqe_datagram_seg);
369162306a36Sopenharmony_ci			size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci			if (wr->opcode == IB_WR_LSO) {
369462306a36Sopenharmony_ci				err = build_lso_seg(wqe, ud_wr(wr), qp, &seglen,
369562306a36Sopenharmony_ci						&lso_hdr_sz, &blh);
369662306a36Sopenharmony_ci				if (unlikely(err)) {
369762306a36Sopenharmony_ci					*bad_wr = wr;
369862306a36Sopenharmony_ci					goto out;
369962306a36Sopenharmony_ci				}
370062306a36Sopenharmony_ci				lso_wqe = (__be32 *) wqe;
370162306a36Sopenharmony_ci				wqe  += seglen;
370262306a36Sopenharmony_ci				size += seglen / 16;
370362306a36Sopenharmony_ci			}
370462306a36Sopenharmony_ci			break;
370562306a36Sopenharmony_ci
370662306a36Sopenharmony_ci		case MLX4_IB_QPT_PROXY_SMI_OWNER:
370762306a36Sopenharmony_ci			err = build_sriov_qp0_header(qp, ud_wr(wr), ctrl,
370862306a36Sopenharmony_ci						     &seglen);
370962306a36Sopenharmony_ci			if (unlikely(err)) {
371062306a36Sopenharmony_ci				*bad_wr = wr;
371162306a36Sopenharmony_ci				goto out;
371262306a36Sopenharmony_ci			}
371362306a36Sopenharmony_ci			wqe  += seglen;
371462306a36Sopenharmony_ci			size += seglen / 16;
371562306a36Sopenharmony_ci			/* to start tunnel header on a cache-line boundary */
371662306a36Sopenharmony_ci			add_zero_len_inline(wqe);
371762306a36Sopenharmony_ci			wqe += 16;
371862306a36Sopenharmony_ci			size++;
371962306a36Sopenharmony_ci			build_tunnel_header(ud_wr(wr), wqe, &seglen);
372062306a36Sopenharmony_ci			wqe  += seglen;
372162306a36Sopenharmony_ci			size += seglen / 16;
372262306a36Sopenharmony_ci			break;
372362306a36Sopenharmony_ci		case MLX4_IB_QPT_PROXY_SMI:
372462306a36Sopenharmony_ci		case MLX4_IB_QPT_PROXY_GSI:
372562306a36Sopenharmony_ci			/* If we are tunneling special qps, this is a UD qp.
372662306a36Sopenharmony_ci			 * In this case we first add a UD segment targeting
372762306a36Sopenharmony_ci			 * the tunnel qp, and then add a header with address
372862306a36Sopenharmony_ci			 * information */
372962306a36Sopenharmony_ci			set_tunnel_datagram_seg(to_mdev(ibqp->device), wqe,
373062306a36Sopenharmony_ci						ud_wr(wr),
373162306a36Sopenharmony_ci						qp->mlx4_ib_qp_type);
373262306a36Sopenharmony_ci			wqe  += sizeof (struct mlx4_wqe_datagram_seg);
373362306a36Sopenharmony_ci			size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
373462306a36Sopenharmony_ci			build_tunnel_header(ud_wr(wr), wqe, &seglen);
373562306a36Sopenharmony_ci			wqe  += seglen;
373662306a36Sopenharmony_ci			size += seglen / 16;
373762306a36Sopenharmony_ci			break;
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci		case MLX4_IB_QPT_SMI:
374062306a36Sopenharmony_ci		case MLX4_IB_QPT_GSI:
374162306a36Sopenharmony_ci			err = build_mlx_header(qp, ud_wr(wr), ctrl, &seglen);
374262306a36Sopenharmony_ci			if (unlikely(err)) {
374362306a36Sopenharmony_ci				*bad_wr = wr;
374462306a36Sopenharmony_ci				goto out;
374562306a36Sopenharmony_ci			}
374662306a36Sopenharmony_ci			wqe  += seglen;
374762306a36Sopenharmony_ci			size += seglen / 16;
374862306a36Sopenharmony_ci			break;
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ci		default:
375162306a36Sopenharmony_ci			break;
375262306a36Sopenharmony_ci		}
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci		/*
375562306a36Sopenharmony_ci		 * Write data segments in reverse order, so as to
375662306a36Sopenharmony_ci		 * overwrite cacheline stamp last within each
375762306a36Sopenharmony_ci		 * cacheline.  This avoids issues with WQE
375862306a36Sopenharmony_ci		 * prefetching.
375962306a36Sopenharmony_ci		 */
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci		dseg = wqe;
376262306a36Sopenharmony_ci		dseg += wr->num_sge - 1;
376362306a36Sopenharmony_ci		size += wr->num_sge * (sizeof (struct mlx4_wqe_data_seg) / 16);
376462306a36Sopenharmony_ci
376562306a36Sopenharmony_ci		/* Add one more inline data segment for ICRC for MLX sends */
376662306a36Sopenharmony_ci		if (unlikely(qp->mlx4_ib_qp_type == MLX4_IB_QPT_SMI ||
376762306a36Sopenharmony_ci			     qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI ||
376862306a36Sopenharmony_ci			     qp->mlx4_ib_qp_type &
376962306a36Sopenharmony_ci			     (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_TUN_SMI_OWNER))) {
377062306a36Sopenharmony_ci			set_mlx_icrc_seg(dseg + 1);
377162306a36Sopenharmony_ci			size += sizeof (struct mlx4_wqe_data_seg) / 16;
377262306a36Sopenharmony_ci		}
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ci		for (i = wr->num_sge - 1; i >= 0; --i, --dseg)
377562306a36Sopenharmony_ci			set_data_seg(dseg, wr->sg_list + i);
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci		/*
377862306a36Sopenharmony_ci		 * Possibly overwrite stamping in cacheline with LSO
377962306a36Sopenharmony_ci		 * segment only after making sure all data segments
378062306a36Sopenharmony_ci		 * are written.
378162306a36Sopenharmony_ci		 */
378262306a36Sopenharmony_ci		wmb();
378362306a36Sopenharmony_ci		*lso_wqe = lso_hdr_sz;
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci		ctrl->qpn_vlan.fence_size = (wr->send_flags & IB_SEND_FENCE ?
378662306a36Sopenharmony_ci					     MLX4_WQE_CTRL_FENCE : 0) | size;
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_ci		/*
378962306a36Sopenharmony_ci		 * Make sure descriptor is fully written before
379062306a36Sopenharmony_ci		 * setting ownership bit (because HW can start
379162306a36Sopenharmony_ci		 * executing as soon as we do).
379262306a36Sopenharmony_ci		 */
379362306a36Sopenharmony_ci		wmb();
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci		if (wr->opcode < 0 || wr->opcode >= ARRAY_SIZE(mlx4_ib_opcode)) {
379662306a36Sopenharmony_ci			*bad_wr = wr;
379762306a36Sopenharmony_ci			err = -EINVAL;
379862306a36Sopenharmony_ci			goto out;
379962306a36Sopenharmony_ci		}
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_ci		ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] |
380262306a36Sopenharmony_ci			(ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0) | blh;
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci		/*
380562306a36Sopenharmony_ci		 * We can improve latency by not stamping the last
380662306a36Sopenharmony_ci		 * send queue WQE until after ringing the doorbell, so
380762306a36Sopenharmony_ci		 * only stamp here if there are still more WQEs to post.
380862306a36Sopenharmony_ci		 */
380962306a36Sopenharmony_ci		if (wr->next)
381062306a36Sopenharmony_ci			stamp_send_wqe(qp, ind + qp->sq_spare_wqes);
381162306a36Sopenharmony_ci		ind++;
381262306a36Sopenharmony_ci	}
381362306a36Sopenharmony_ci
381462306a36Sopenharmony_ciout:
381562306a36Sopenharmony_ci	if (likely(nreq)) {
381662306a36Sopenharmony_ci		qp->sq.head += nreq;
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ci		/*
381962306a36Sopenharmony_ci		 * Make sure that descriptors are written before
382062306a36Sopenharmony_ci		 * doorbell record.
382162306a36Sopenharmony_ci		 */
382262306a36Sopenharmony_ci		wmb();
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci		writel_relaxed(qp->doorbell_qpn,
382562306a36Sopenharmony_ci			to_mdev(ibqp->device)->uar_map + MLX4_SEND_DOORBELL);
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_ci		stamp_send_wqe(qp, ind + qp->sq_spare_wqes - 1);
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci		qp->sq_next_wqe = ind;
383062306a36Sopenharmony_ci	}
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->sq.lock, flags);
383362306a36Sopenharmony_ci
383462306a36Sopenharmony_ci	return err;
383562306a36Sopenharmony_ci}
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ciint mlx4_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
383862306a36Sopenharmony_ci		      const struct ib_send_wr **bad_wr)
383962306a36Sopenharmony_ci{
384062306a36Sopenharmony_ci	return _mlx4_ib_post_send(ibqp, wr, bad_wr, false);
384162306a36Sopenharmony_ci}
384262306a36Sopenharmony_ci
384362306a36Sopenharmony_cistatic int _mlx4_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
384462306a36Sopenharmony_ci			      const struct ib_recv_wr **bad_wr, bool drain)
384562306a36Sopenharmony_ci{
384662306a36Sopenharmony_ci	struct mlx4_ib_qp *qp = to_mqp(ibqp);
384762306a36Sopenharmony_ci	struct mlx4_wqe_data_seg *scat;
384862306a36Sopenharmony_ci	unsigned long flags;
384962306a36Sopenharmony_ci	int err = 0;
385062306a36Sopenharmony_ci	int nreq;
385162306a36Sopenharmony_ci	int ind;
385262306a36Sopenharmony_ci	int max_gs;
385362306a36Sopenharmony_ci	int i;
385462306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
385562306a36Sopenharmony_ci
385662306a36Sopenharmony_ci	max_gs = qp->rq.max_gs;
385762306a36Sopenharmony_ci	spin_lock_irqsave(&qp->rq.lock, flags);
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci	if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR &&
386062306a36Sopenharmony_ci	    !drain) {
386162306a36Sopenharmony_ci		err = -EIO;
386262306a36Sopenharmony_ci		*bad_wr = wr;
386362306a36Sopenharmony_ci		nreq = 0;
386462306a36Sopenharmony_ci		goto out;
386562306a36Sopenharmony_ci	}
386662306a36Sopenharmony_ci
386762306a36Sopenharmony_ci	ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
386862306a36Sopenharmony_ci
386962306a36Sopenharmony_ci	for (nreq = 0; wr; ++nreq, wr = wr->next) {
387062306a36Sopenharmony_ci		if (mlx4_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
387162306a36Sopenharmony_ci			err = -ENOMEM;
387262306a36Sopenharmony_ci			*bad_wr = wr;
387362306a36Sopenharmony_ci			goto out;
387462306a36Sopenharmony_ci		}
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci		if (unlikely(wr->num_sge > qp->rq.max_gs)) {
387762306a36Sopenharmony_ci			err = -EINVAL;
387862306a36Sopenharmony_ci			*bad_wr = wr;
387962306a36Sopenharmony_ci			goto out;
388062306a36Sopenharmony_ci		}
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ci		scat = get_recv_wqe(qp, ind);
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci		if (qp->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER |
388562306a36Sopenharmony_ci		    MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI)) {
388662306a36Sopenharmony_ci			ib_dma_sync_single_for_device(ibqp->device,
388762306a36Sopenharmony_ci						      qp->sqp_proxy_rcv[ind].map,
388862306a36Sopenharmony_ci						      sizeof (struct mlx4_ib_proxy_sqp_hdr),
388962306a36Sopenharmony_ci						      DMA_FROM_DEVICE);
389062306a36Sopenharmony_ci			scat->byte_count =
389162306a36Sopenharmony_ci				cpu_to_be32(sizeof (struct mlx4_ib_proxy_sqp_hdr));
389262306a36Sopenharmony_ci			/* use dma lkey from upper layer entry */
389362306a36Sopenharmony_ci			scat->lkey = cpu_to_be32(wr->sg_list->lkey);
389462306a36Sopenharmony_ci			scat->addr = cpu_to_be64(qp->sqp_proxy_rcv[ind].map);
389562306a36Sopenharmony_ci			scat++;
389662306a36Sopenharmony_ci			max_gs--;
389762306a36Sopenharmony_ci		}
389862306a36Sopenharmony_ci
389962306a36Sopenharmony_ci		for (i = 0; i < wr->num_sge; ++i)
390062306a36Sopenharmony_ci			__set_data_seg(scat + i, wr->sg_list + i);
390162306a36Sopenharmony_ci
390262306a36Sopenharmony_ci		if (i < max_gs) {
390362306a36Sopenharmony_ci			scat[i].byte_count = 0;
390462306a36Sopenharmony_ci			scat[i].lkey       = cpu_to_be32(MLX4_INVALID_LKEY);
390562306a36Sopenharmony_ci			scat[i].addr       = 0;
390662306a36Sopenharmony_ci		}
390762306a36Sopenharmony_ci
390862306a36Sopenharmony_ci		qp->rq.wrid[ind] = wr->wr_id;
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_ci		ind = (ind + 1) & (qp->rq.wqe_cnt - 1);
391162306a36Sopenharmony_ci	}
391262306a36Sopenharmony_ci
391362306a36Sopenharmony_ciout:
391462306a36Sopenharmony_ci	if (likely(nreq)) {
391562306a36Sopenharmony_ci		qp->rq.head += nreq;
391662306a36Sopenharmony_ci
391762306a36Sopenharmony_ci		/*
391862306a36Sopenharmony_ci		 * Make sure that descriptors are written before
391962306a36Sopenharmony_ci		 * doorbell record.
392062306a36Sopenharmony_ci		 */
392162306a36Sopenharmony_ci		wmb();
392262306a36Sopenharmony_ci
392362306a36Sopenharmony_ci		*qp->db.db = cpu_to_be32(qp->rq.head & 0xffff);
392462306a36Sopenharmony_ci	}
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->rq.lock, flags);
392762306a36Sopenharmony_ci
392862306a36Sopenharmony_ci	return err;
392962306a36Sopenharmony_ci}
393062306a36Sopenharmony_ci
393162306a36Sopenharmony_ciint mlx4_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
393262306a36Sopenharmony_ci		      const struct ib_recv_wr **bad_wr)
393362306a36Sopenharmony_ci{
393462306a36Sopenharmony_ci	return _mlx4_ib_post_recv(ibqp, wr, bad_wr, false);
393562306a36Sopenharmony_ci}
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_cistatic inline enum ib_qp_state to_ib_qp_state(enum mlx4_qp_state mlx4_state)
393862306a36Sopenharmony_ci{
393962306a36Sopenharmony_ci	switch (mlx4_state) {
394062306a36Sopenharmony_ci	case MLX4_QP_STATE_RST:      return IB_QPS_RESET;
394162306a36Sopenharmony_ci	case MLX4_QP_STATE_INIT:     return IB_QPS_INIT;
394262306a36Sopenharmony_ci	case MLX4_QP_STATE_RTR:      return IB_QPS_RTR;
394362306a36Sopenharmony_ci	case MLX4_QP_STATE_RTS:      return IB_QPS_RTS;
394462306a36Sopenharmony_ci	case MLX4_QP_STATE_SQ_DRAINING:
394562306a36Sopenharmony_ci	case MLX4_QP_STATE_SQD:      return IB_QPS_SQD;
394662306a36Sopenharmony_ci	case MLX4_QP_STATE_SQER:     return IB_QPS_SQE;
394762306a36Sopenharmony_ci	case MLX4_QP_STATE_ERR:      return IB_QPS_ERR;
394862306a36Sopenharmony_ci	default:		     return -1;
394962306a36Sopenharmony_ci	}
395062306a36Sopenharmony_ci}
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_cistatic inline enum ib_mig_state to_ib_mig_state(int mlx4_mig_state)
395362306a36Sopenharmony_ci{
395462306a36Sopenharmony_ci	switch (mlx4_mig_state) {
395562306a36Sopenharmony_ci	case MLX4_QP_PM_ARMED:		return IB_MIG_ARMED;
395662306a36Sopenharmony_ci	case MLX4_QP_PM_REARM:		return IB_MIG_REARM;
395762306a36Sopenharmony_ci	case MLX4_QP_PM_MIGRATED:	return IB_MIG_MIGRATED;
395862306a36Sopenharmony_ci	default: return -1;
395962306a36Sopenharmony_ci	}
396062306a36Sopenharmony_ci}
396162306a36Sopenharmony_ci
396262306a36Sopenharmony_cistatic int to_ib_qp_access_flags(int mlx4_flags)
396362306a36Sopenharmony_ci{
396462306a36Sopenharmony_ci	int ib_flags = 0;
396562306a36Sopenharmony_ci
396662306a36Sopenharmony_ci	if (mlx4_flags & MLX4_QP_BIT_RRE)
396762306a36Sopenharmony_ci		ib_flags |= IB_ACCESS_REMOTE_READ;
396862306a36Sopenharmony_ci	if (mlx4_flags & MLX4_QP_BIT_RWE)
396962306a36Sopenharmony_ci		ib_flags |= IB_ACCESS_REMOTE_WRITE;
397062306a36Sopenharmony_ci	if (mlx4_flags & MLX4_QP_BIT_RAE)
397162306a36Sopenharmony_ci		ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci	return ib_flags;
397462306a36Sopenharmony_ci}
397562306a36Sopenharmony_ci
397662306a36Sopenharmony_cistatic void to_rdma_ah_attr(struct mlx4_ib_dev *ibdev,
397762306a36Sopenharmony_ci			    struct rdma_ah_attr *ah_attr,
397862306a36Sopenharmony_ci			    struct mlx4_qp_path *path)
397962306a36Sopenharmony_ci{
398062306a36Sopenharmony_ci	struct mlx4_dev *dev = ibdev->dev;
398162306a36Sopenharmony_ci	u8 port_num = path->sched_queue & 0x40 ? 2 : 1;
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci	memset(ah_attr, 0, sizeof(*ah_attr));
398462306a36Sopenharmony_ci	if (port_num == 0 || port_num > dev->caps.num_ports)
398562306a36Sopenharmony_ci		return;
398662306a36Sopenharmony_ci	ah_attr->type = rdma_ah_find_type(&ibdev->ib_dev, port_num);
398762306a36Sopenharmony_ci
398862306a36Sopenharmony_ci	if (ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE)
398962306a36Sopenharmony_ci		rdma_ah_set_sl(ah_attr, ((path->sched_queue >> 3) & 0x7) |
399062306a36Sopenharmony_ci			       ((path->sched_queue & 4) << 1));
399162306a36Sopenharmony_ci	else
399262306a36Sopenharmony_ci		rdma_ah_set_sl(ah_attr, (path->sched_queue >> 2) & 0xf);
399362306a36Sopenharmony_ci	rdma_ah_set_port_num(ah_attr, port_num);
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci	rdma_ah_set_dlid(ah_attr, be16_to_cpu(path->rlid));
399662306a36Sopenharmony_ci	rdma_ah_set_path_bits(ah_attr, path->grh_mylmc & 0x7f);
399762306a36Sopenharmony_ci	rdma_ah_set_static_rate(ah_attr,
399862306a36Sopenharmony_ci				path->static_rate ? path->static_rate - 5 : 0);
399962306a36Sopenharmony_ci	if (path->grh_mylmc & (1 << 7)) {
400062306a36Sopenharmony_ci		rdma_ah_set_grh(ah_attr, NULL,
400162306a36Sopenharmony_ci				be32_to_cpu(path->tclass_flowlabel) & 0xfffff,
400262306a36Sopenharmony_ci				path->mgid_index,
400362306a36Sopenharmony_ci				path->hop_limit,
400462306a36Sopenharmony_ci				(be32_to_cpu(path->tclass_flowlabel)
400562306a36Sopenharmony_ci				 >> 20) & 0xff);
400662306a36Sopenharmony_ci		rdma_ah_set_dgid_raw(ah_attr, path->rgid);
400762306a36Sopenharmony_ci	}
400862306a36Sopenharmony_ci}
400962306a36Sopenharmony_ci
401062306a36Sopenharmony_ciint mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
401162306a36Sopenharmony_ci		     struct ib_qp_init_attr *qp_init_attr)
401262306a36Sopenharmony_ci{
401362306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibqp->device);
401462306a36Sopenharmony_ci	struct mlx4_ib_qp *qp = to_mqp(ibqp);
401562306a36Sopenharmony_ci	struct mlx4_qp_context context;
401662306a36Sopenharmony_ci	int mlx4_state;
401762306a36Sopenharmony_ci	int err = 0;
401862306a36Sopenharmony_ci
401962306a36Sopenharmony_ci	if (ibqp->rwq_ind_tbl)
402062306a36Sopenharmony_ci		return -EOPNOTSUPP;
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_ci	mutex_lock(&qp->mutex);
402362306a36Sopenharmony_ci
402462306a36Sopenharmony_ci	if (qp->state == IB_QPS_RESET) {
402562306a36Sopenharmony_ci		qp_attr->qp_state = IB_QPS_RESET;
402662306a36Sopenharmony_ci		goto done;
402762306a36Sopenharmony_ci	}
402862306a36Sopenharmony_ci
402962306a36Sopenharmony_ci	err = mlx4_qp_query(dev->dev, &qp->mqp, &context);
403062306a36Sopenharmony_ci	if (err) {
403162306a36Sopenharmony_ci		err = -EINVAL;
403262306a36Sopenharmony_ci		goto out;
403362306a36Sopenharmony_ci	}
403462306a36Sopenharmony_ci
403562306a36Sopenharmony_ci	mlx4_state = be32_to_cpu(context.flags) >> 28;
403662306a36Sopenharmony_ci
403762306a36Sopenharmony_ci	qp->state		     = to_ib_qp_state(mlx4_state);
403862306a36Sopenharmony_ci	qp_attr->qp_state	     = qp->state;
403962306a36Sopenharmony_ci	qp_attr->path_mtu	     = context.mtu_msgmax >> 5;
404062306a36Sopenharmony_ci	qp_attr->path_mig_state	     =
404162306a36Sopenharmony_ci		to_ib_mig_state((be32_to_cpu(context.flags) >> 11) & 0x3);
404262306a36Sopenharmony_ci	qp_attr->qkey		     = be32_to_cpu(context.qkey);
404362306a36Sopenharmony_ci	qp_attr->rq_psn		     = be32_to_cpu(context.rnr_nextrecvpsn) & 0xffffff;
404462306a36Sopenharmony_ci	qp_attr->sq_psn		     = be32_to_cpu(context.next_send_psn) & 0xffffff;
404562306a36Sopenharmony_ci	qp_attr->dest_qp_num	     = be32_to_cpu(context.remote_qpn) & 0xffffff;
404662306a36Sopenharmony_ci	qp_attr->qp_access_flags     =
404762306a36Sopenharmony_ci		to_ib_qp_access_flags(be32_to_cpu(context.params2));
404862306a36Sopenharmony_ci
404962306a36Sopenharmony_ci	if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC ||
405062306a36Sopenharmony_ci	    qp->ibqp.qp_type == IB_QPT_XRC_INI ||
405162306a36Sopenharmony_ci	    qp->ibqp.qp_type == IB_QPT_XRC_TGT) {
405262306a36Sopenharmony_ci		to_rdma_ah_attr(dev, &qp_attr->ah_attr, &context.pri_path);
405362306a36Sopenharmony_ci		to_rdma_ah_attr(dev, &qp_attr->alt_ah_attr, &context.alt_path);
405462306a36Sopenharmony_ci		qp_attr->alt_pkey_index = context.alt_path.pkey_index & 0x7f;
405562306a36Sopenharmony_ci		qp_attr->alt_port_num	=
405662306a36Sopenharmony_ci			rdma_ah_get_port_num(&qp_attr->alt_ah_attr);
405762306a36Sopenharmony_ci	}
405862306a36Sopenharmony_ci
405962306a36Sopenharmony_ci	qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f;
406062306a36Sopenharmony_ci	if (qp_attr->qp_state == IB_QPS_INIT)
406162306a36Sopenharmony_ci		qp_attr->port_num = qp->port;
406262306a36Sopenharmony_ci	else
406362306a36Sopenharmony_ci		qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1;
406462306a36Sopenharmony_ci
406562306a36Sopenharmony_ci	/* qp_attr->en_sqd_async_notify is only applicable in modify qp */
406662306a36Sopenharmony_ci	qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING;
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_ci	qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context.params1) >> 21) & 0x7);
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_ci	qp_attr->max_dest_rd_atomic =
407162306a36Sopenharmony_ci		1 << ((be32_to_cpu(context.params2) >> 21) & 0x7);
407262306a36Sopenharmony_ci	qp_attr->min_rnr_timer	    =
407362306a36Sopenharmony_ci		(be32_to_cpu(context.rnr_nextrecvpsn) >> 24) & 0x1f;
407462306a36Sopenharmony_ci	qp_attr->timeout	    = context.pri_path.ackto >> 3;
407562306a36Sopenharmony_ci	qp_attr->retry_cnt	    = (be32_to_cpu(context.params1) >> 16) & 0x7;
407662306a36Sopenharmony_ci	qp_attr->rnr_retry	    = (be32_to_cpu(context.params1) >> 13) & 0x7;
407762306a36Sopenharmony_ci	qp_attr->alt_timeout	    = context.alt_path.ackto >> 3;
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_cidone:
408062306a36Sopenharmony_ci	qp_attr->cur_qp_state	     = qp_attr->qp_state;
408162306a36Sopenharmony_ci	qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
408262306a36Sopenharmony_ci	qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_ci	if (!ibqp->uobject) {
408562306a36Sopenharmony_ci		qp_attr->cap.max_send_wr  = qp->sq.wqe_cnt;
408662306a36Sopenharmony_ci		qp_attr->cap.max_send_sge = qp->sq.max_gs;
408762306a36Sopenharmony_ci	} else {
408862306a36Sopenharmony_ci		qp_attr->cap.max_send_wr  = 0;
408962306a36Sopenharmony_ci		qp_attr->cap.max_send_sge = 0;
409062306a36Sopenharmony_ci	}
409162306a36Sopenharmony_ci
409262306a36Sopenharmony_ci	/*
409362306a36Sopenharmony_ci	 * We don't support inline sends for kernel QPs (yet), and we
409462306a36Sopenharmony_ci	 * don't know what userspace's value should be.
409562306a36Sopenharmony_ci	 */
409662306a36Sopenharmony_ci	qp_attr->cap.max_inline_data = 0;
409762306a36Sopenharmony_ci
409862306a36Sopenharmony_ci	qp_init_attr->cap	     = qp_attr->cap;
409962306a36Sopenharmony_ci
410062306a36Sopenharmony_ci	qp_init_attr->create_flags = 0;
410162306a36Sopenharmony_ci	if (qp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK)
410262306a36Sopenharmony_ci		qp_init_attr->create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK;
410362306a36Sopenharmony_ci
410462306a36Sopenharmony_ci	if (qp->flags & MLX4_IB_QP_LSO)
410562306a36Sopenharmony_ci		qp_init_attr->create_flags |= IB_QP_CREATE_IPOIB_UD_LSO;
410662306a36Sopenharmony_ci
410762306a36Sopenharmony_ci	if (qp->flags & MLX4_IB_QP_NETIF)
410862306a36Sopenharmony_ci		qp_init_attr->create_flags |= IB_QP_CREATE_NETIF_QP;
410962306a36Sopenharmony_ci
411062306a36Sopenharmony_ci	qp_init_attr->sq_sig_type =
411162306a36Sopenharmony_ci		qp->sq_signal_bits == cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) ?
411262306a36Sopenharmony_ci		IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
411362306a36Sopenharmony_ci
411462306a36Sopenharmony_ciout:
411562306a36Sopenharmony_ci	mutex_unlock(&qp->mutex);
411662306a36Sopenharmony_ci	return err;
411762306a36Sopenharmony_ci}
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_cistruct ib_wq *mlx4_ib_create_wq(struct ib_pd *pd,
412062306a36Sopenharmony_ci				struct ib_wq_init_attr *init_attr,
412162306a36Sopenharmony_ci				struct ib_udata *udata)
412262306a36Sopenharmony_ci{
412362306a36Sopenharmony_ci	struct mlx4_dev *dev = to_mdev(pd->device)->dev;
412462306a36Sopenharmony_ci	struct ib_qp_init_attr ib_qp_init_attr = {};
412562306a36Sopenharmony_ci	struct mlx4_ib_qp *qp;
412662306a36Sopenharmony_ci	struct mlx4_ib_create_wq ucmd;
412762306a36Sopenharmony_ci	int err, required_cmd_sz;
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	if (!udata)
413062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
413162306a36Sopenharmony_ci
413262306a36Sopenharmony_ci	required_cmd_sz = offsetof(typeof(ucmd), comp_mask) +
413362306a36Sopenharmony_ci			  sizeof(ucmd.comp_mask);
413462306a36Sopenharmony_ci	if (udata->inlen < required_cmd_sz) {
413562306a36Sopenharmony_ci		pr_debug("invalid inlen\n");
413662306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
413762306a36Sopenharmony_ci	}
413862306a36Sopenharmony_ci
413962306a36Sopenharmony_ci	if (udata->inlen > sizeof(ucmd) &&
414062306a36Sopenharmony_ci	    !ib_is_udata_cleared(udata, sizeof(ucmd),
414162306a36Sopenharmony_ci				 udata->inlen - sizeof(ucmd))) {
414262306a36Sopenharmony_ci		pr_debug("inlen is not supported\n");
414362306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
414462306a36Sopenharmony_ci	}
414562306a36Sopenharmony_ci
414662306a36Sopenharmony_ci	if (udata->outlen)
414762306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
414862306a36Sopenharmony_ci
414962306a36Sopenharmony_ci	if (init_attr->wq_type != IB_WQT_RQ) {
415062306a36Sopenharmony_ci		pr_debug("unsupported wq type %d\n", init_attr->wq_type);
415162306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
415262306a36Sopenharmony_ci	}
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci	if (init_attr->create_flags & ~IB_WQ_FLAGS_SCATTER_FCS ||
415562306a36Sopenharmony_ci	    !(dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP)) {
415662306a36Sopenharmony_ci		pr_debug("unsupported create_flags %u\n",
415762306a36Sopenharmony_ci			 init_attr->create_flags);
415862306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
415962306a36Sopenharmony_ci	}
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci	qp = kzalloc(sizeof(*qp), GFP_KERNEL);
416262306a36Sopenharmony_ci	if (!qp)
416362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
416462306a36Sopenharmony_ci
416562306a36Sopenharmony_ci	mutex_init(&qp->mutex);
416662306a36Sopenharmony_ci	qp->pri.vid = 0xFFFF;
416762306a36Sopenharmony_ci	qp->alt.vid = 0xFFFF;
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci	ib_qp_init_attr.qp_context = init_attr->wq_context;
417062306a36Sopenharmony_ci	ib_qp_init_attr.qp_type = IB_QPT_RAW_PACKET;
417162306a36Sopenharmony_ci	ib_qp_init_attr.cap.max_recv_wr = init_attr->max_wr;
417262306a36Sopenharmony_ci	ib_qp_init_attr.cap.max_recv_sge = init_attr->max_sge;
417362306a36Sopenharmony_ci	ib_qp_init_attr.recv_cq = init_attr->cq;
417462306a36Sopenharmony_ci	ib_qp_init_attr.send_cq = ib_qp_init_attr.recv_cq; /* Dummy CQ */
417562306a36Sopenharmony_ci
417662306a36Sopenharmony_ci	if (init_attr->create_flags & IB_WQ_FLAGS_SCATTER_FCS)
417762306a36Sopenharmony_ci		ib_qp_init_attr.create_flags |= IB_QP_CREATE_SCATTER_FCS;
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_ci	err = create_rq(pd, &ib_qp_init_attr, udata, qp);
418062306a36Sopenharmony_ci	if (err) {
418162306a36Sopenharmony_ci		kfree(qp);
418262306a36Sopenharmony_ci		return ERR_PTR(err);
418362306a36Sopenharmony_ci	}
418462306a36Sopenharmony_ci
418562306a36Sopenharmony_ci	qp->ibwq.event_handler = init_attr->event_handler;
418662306a36Sopenharmony_ci	qp->ibwq.wq_num = qp->mqp.qpn;
418762306a36Sopenharmony_ci	qp->ibwq.state = IB_WQS_RESET;
418862306a36Sopenharmony_ci
418962306a36Sopenharmony_ci	return &qp->ibwq;
419062306a36Sopenharmony_ci}
419162306a36Sopenharmony_ci
419262306a36Sopenharmony_cistatic int ib_wq2qp_state(enum ib_wq_state state)
419362306a36Sopenharmony_ci{
419462306a36Sopenharmony_ci	switch (state) {
419562306a36Sopenharmony_ci	case IB_WQS_RESET:
419662306a36Sopenharmony_ci		return IB_QPS_RESET;
419762306a36Sopenharmony_ci	case IB_WQS_RDY:
419862306a36Sopenharmony_ci		return IB_QPS_RTR;
419962306a36Sopenharmony_ci	default:
420062306a36Sopenharmony_ci		return IB_QPS_ERR;
420162306a36Sopenharmony_ci	}
420262306a36Sopenharmony_ci}
420362306a36Sopenharmony_ci
420462306a36Sopenharmony_cistatic int _mlx4_ib_modify_wq(struct ib_wq *ibwq, enum ib_wq_state new_state,
420562306a36Sopenharmony_ci			      struct ib_udata *udata)
420662306a36Sopenharmony_ci{
420762306a36Sopenharmony_ci	struct mlx4_ib_qp *qp = to_mqp((struct ib_qp *)ibwq);
420862306a36Sopenharmony_ci	enum ib_qp_state qp_cur_state;
420962306a36Sopenharmony_ci	enum ib_qp_state qp_new_state;
421062306a36Sopenharmony_ci	int attr_mask;
421162306a36Sopenharmony_ci	int err;
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_ci	/* ib_qp.state represents the WQ HW state while ib_wq.state represents
421462306a36Sopenharmony_ci	 * the WQ logic state.
421562306a36Sopenharmony_ci	 */
421662306a36Sopenharmony_ci	qp_cur_state = qp->state;
421762306a36Sopenharmony_ci	qp_new_state = ib_wq2qp_state(new_state);
421862306a36Sopenharmony_ci
421962306a36Sopenharmony_ci	if (ib_wq2qp_state(new_state) == qp_cur_state)
422062306a36Sopenharmony_ci		return 0;
422162306a36Sopenharmony_ci
422262306a36Sopenharmony_ci	if (new_state == IB_WQS_RDY) {
422362306a36Sopenharmony_ci		struct ib_qp_attr attr = {};
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci		attr.port_num = qp->port;
422662306a36Sopenharmony_ci		attr_mask = IB_QP_PORT;
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_ci		err = __mlx4_ib_modify_qp(ibwq, MLX4_IB_RWQ_SRC, &attr,
422962306a36Sopenharmony_ci					  attr_mask, IB_QPS_RESET, IB_QPS_INIT,
423062306a36Sopenharmony_ci					  udata);
423162306a36Sopenharmony_ci		if (err) {
423262306a36Sopenharmony_ci			pr_debug("WQN=0x%06x failed to apply RST->INIT on the HW QP\n",
423362306a36Sopenharmony_ci				 ibwq->wq_num);
423462306a36Sopenharmony_ci			return err;
423562306a36Sopenharmony_ci		}
423662306a36Sopenharmony_ci
423762306a36Sopenharmony_ci		qp_cur_state = IB_QPS_INIT;
423862306a36Sopenharmony_ci	}
423962306a36Sopenharmony_ci
424062306a36Sopenharmony_ci	attr_mask = 0;
424162306a36Sopenharmony_ci	err = __mlx4_ib_modify_qp(ibwq, MLX4_IB_RWQ_SRC, NULL, attr_mask,
424262306a36Sopenharmony_ci				  qp_cur_state,  qp_new_state, udata);
424362306a36Sopenharmony_ci
424462306a36Sopenharmony_ci	if (err && (qp_cur_state == IB_QPS_INIT)) {
424562306a36Sopenharmony_ci		qp_new_state = IB_QPS_RESET;
424662306a36Sopenharmony_ci		if (__mlx4_ib_modify_qp(ibwq, MLX4_IB_RWQ_SRC, NULL,
424762306a36Sopenharmony_ci					attr_mask, IB_QPS_INIT, IB_QPS_RESET,
424862306a36Sopenharmony_ci					udata)) {
424962306a36Sopenharmony_ci			pr_warn("WQN=0x%06x failed with reverting HW's resources failure\n",
425062306a36Sopenharmony_ci				ibwq->wq_num);
425162306a36Sopenharmony_ci			qp_new_state = IB_QPS_INIT;
425262306a36Sopenharmony_ci		}
425362306a36Sopenharmony_ci	}
425462306a36Sopenharmony_ci
425562306a36Sopenharmony_ci	qp->state = qp_new_state;
425662306a36Sopenharmony_ci
425762306a36Sopenharmony_ci	return err;
425862306a36Sopenharmony_ci}
425962306a36Sopenharmony_ci
426062306a36Sopenharmony_ciint mlx4_ib_modify_wq(struct ib_wq *ibwq, struct ib_wq_attr *wq_attr,
426162306a36Sopenharmony_ci		      u32 wq_attr_mask, struct ib_udata *udata)
426262306a36Sopenharmony_ci{
426362306a36Sopenharmony_ci	struct mlx4_ib_qp *qp = to_mqp((struct ib_qp *)ibwq);
426462306a36Sopenharmony_ci	struct mlx4_ib_modify_wq ucmd = {};
426562306a36Sopenharmony_ci	size_t required_cmd_sz;
426662306a36Sopenharmony_ci	enum ib_wq_state cur_state, new_state;
426762306a36Sopenharmony_ci	int err = 0;
426862306a36Sopenharmony_ci
426962306a36Sopenharmony_ci	required_cmd_sz = offsetof(typeof(ucmd), reserved) +
427062306a36Sopenharmony_ci				   sizeof(ucmd.reserved);
427162306a36Sopenharmony_ci	if (udata->inlen < required_cmd_sz)
427262306a36Sopenharmony_ci		return -EINVAL;
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_ci	if (udata->inlen > sizeof(ucmd) &&
427562306a36Sopenharmony_ci	    !ib_is_udata_cleared(udata, sizeof(ucmd),
427662306a36Sopenharmony_ci				 udata->inlen - sizeof(ucmd)))
427762306a36Sopenharmony_ci		return -EOPNOTSUPP;
427862306a36Sopenharmony_ci
427962306a36Sopenharmony_ci	if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen)))
428062306a36Sopenharmony_ci		return -EFAULT;
428162306a36Sopenharmony_ci
428262306a36Sopenharmony_ci	if (ucmd.comp_mask || ucmd.reserved)
428362306a36Sopenharmony_ci		return -EOPNOTSUPP;
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_ci	if (wq_attr_mask & IB_WQ_FLAGS)
428662306a36Sopenharmony_ci		return -EOPNOTSUPP;
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci	cur_state = wq_attr->curr_wq_state;
428962306a36Sopenharmony_ci	new_state = wq_attr->wq_state;
429062306a36Sopenharmony_ci
429162306a36Sopenharmony_ci	if ((new_state == IB_WQS_RDY) && (cur_state == IB_WQS_ERR))
429262306a36Sopenharmony_ci		return -EINVAL;
429362306a36Sopenharmony_ci
429462306a36Sopenharmony_ci	if ((new_state == IB_WQS_ERR) && (cur_state == IB_WQS_RESET))
429562306a36Sopenharmony_ci		return -EINVAL;
429662306a36Sopenharmony_ci
429762306a36Sopenharmony_ci	/* Need to protect against the parent RSS which also may modify WQ
429862306a36Sopenharmony_ci	 * state.
429962306a36Sopenharmony_ci	 */
430062306a36Sopenharmony_ci	mutex_lock(&qp->mutex);
430162306a36Sopenharmony_ci
430262306a36Sopenharmony_ci	/* Can update HW state only if a RSS QP has already associated to this
430362306a36Sopenharmony_ci	 * WQ, so we can apply its port on the WQ.
430462306a36Sopenharmony_ci	 */
430562306a36Sopenharmony_ci	if (qp->rss_usecnt)
430662306a36Sopenharmony_ci		err = _mlx4_ib_modify_wq(ibwq, new_state, udata);
430762306a36Sopenharmony_ci
430862306a36Sopenharmony_ci	if (!err)
430962306a36Sopenharmony_ci		ibwq->state = new_state;
431062306a36Sopenharmony_ci
431162306a36Sopenharmony_ci	mutex_unlock(&qp->mutex);
431262306a36Sopenharmony_ci
431362306a36Sopenharmony_ci	return err;
431462306a36Sopenharmony_ci}
431562306a36Sopenharmony_ci
431662306a36Sopenharmony_ciint mlx4_ib_destroy_wq(struct ib_wq *ibwq, struct ib_udata *udata)
431762306a36Sopenharmony_ci{
431862306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibwq->device);
431962306a36Sopenharmony_ci	struct mlx4_ib_qp *qp = to_mqp((struct ib_qp *)ibwq);
432062306a36Sopenharmony_ci
432162306a36Sopenharmony_ci	if (qp->counter_index)
432262306a36Sopenharmony_ci		mlx4_ib_free_qp_counter(dev, qp);
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	destroy_qp_common(dev, qp, MLX4_IB_RWQ_SRC, udata);
432562306a36Sopenharmony_ci
432662306a36Sopenharmony_ci	kfree(qp);
432762306a36Sopenharmony_ci	return 0;
432862306a36Sopenharmony_ci}
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_ciint mlx4_ib_create_rwq_ind_table(struct ib_rwq_ind_table *rwq_ind_table,
433162306a36Sopenharmony_ci				 struct ib_rwq_ind_table_init_attr *init_attr,
433262306a36Sopenharmony_ci				 struct ib_udata *udata)
433362306a36Sopenharmony_ci{
433462306a36Sopenharmony_ci	struct mlx4_ib_create_rwq_ind_tbl_resp resp = {};
433562306a36Sopenharmony_ci	unsigned int ind_tbl_size = 1 << init_attr->log_ind_tbl_size;
433662306a36Sopenharmony_ci	struct ib_device *device = rwq_ind_table->device;
433762306a36Sopenharmony_ci	unsigned int base_wqn;
433862306a36Sopenharmony_ci	size_t min_resp_len;
433962306a36Sopenharmony_ci	int i, err = 0;
434062306a36Sopenharmony_ci
434162306a36Sopenharmony_ci	if (udata->inlen > 0 &&
434262306a36Sopenharmony_ci	    !ib_is_udata_cleared(udata, 0,
434362306a36Sopenharmony_ci				 udata->inlen))
434462306a36Sopenharmony_ci		return -EOPNOTSUPP;
434562306a36Sopenharmony_ci
434662306a36Sopenharmony_ci	min_resp_len = offsetof(typeof(resp), reserved) + sizeof(resp.reserved);
434762306a36Sopenharmony_ci	if (udata->outlen && udata->outlen < min_resp_len)
434862306a36Sopenharmony_ci		return -EINVAL;
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci	if (ind_tbl_size >
435162306a36Sopenharmony_ci	    device->attrs.rss_caps.max_rwq_indirection_table_size) {
435262306a36Sopenharmony_ci		pr_debug("log_ind_tbl_size = %d is bigger than supported = %d\n",
435362306a36Sopenharmony_ci			 ind_tbl_size,
435462306a36Sopenharmony_ci			 device->attrs.rss_caps.max_rwq_indirection_table_size);
435562306a36Sopenharmony_ci		return -EINVAL;
435662306a36Sopenharmony_ci	}
435762306a36Sopenharmony_ci
435862306a36Sopenharmony_ci	base_wqn = init_attr->ind_tbl[0]->wq_num;
435962306a36Sopenharmony_ci
436062306a36Sopenharmony_ci	if (base_wqn % ind_tbl_size) {
436162306a36Sopenharmony_ci		pr_debug("WQN=0x%x isn't aligned with indirection table size\n",
436262306a36Sopenharmony_ci			 base_wqn);
436362306a36Sopenharmony_ci		return -EINVAL;
436462306a36Sopenharmony_ci	}
436562306a36Sopenharmony_ci
436662306a36Sopenharmony_ci	for (i = 1; i < ind_tbl_size; i++) {
436762306a36Sopenharmony_ci		if (++base_wqn != init_attr->ind_tbl[i]->wq_num) {
436862306a36Sopenharmony_ci			pr_debug("indirection table's WQNs aren't consecutive\n");
436962306a36Sopenharmony_ci			return -EINVAL;
437062306a36Sopenharmony_ci		}
437162306a36Sopenharmony_ci	}
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	if (udata->outlen) {
437462306a36Sopenharmony_ci		resp.response_length = offsetof(typeof(resp), response_length) +
437562306a36Sopenharmony_ci					sizeof(resp.response_length);
437662306a36Sopenharmony_ci		err = ib_copy_to_udata(udata, &resp, resp.response_length);
437762306a36Sopenharmony_ci	}
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci	return err;
438062306a36Sopenharmony_ci}
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_cistruct mlx4_ib_drain_cqe {
438362306a36Sopenharmony_ci	struct ib_cqe cqe;
438462306a36Sopenharmony_ci	struct completion done;
438562306a36Sopenharmony_ci};
438662306a36Sopenharmony_ci
438762306a36Sopenharmony_cistatic void mlx4_ib_drain_qp_done(struct ib_cq *cq, struct ib_wc *wc)
438862306a36Sopenharmony_ci{
438962306a36Sopenharmony_ci	struct mlx4_ib_drain_cqe *cqe = container_of(wc->wr_cqe,
439062306a36Sopenharmony_ci						     struct mlx4_ib_drain_cqe,
439162306a36Sopenharmony_ci						     cqe);
439262306a36Sopenharmony_ci
439362306a36Sopenharmony_ci	complete(&cqe->done);
439462306a36Sopenharmony_ci}
439562306a36Sopenharmony_ci
439662306a36Sopenharmony_ci/* This function returns only once the drained WR was completed */
439762306a36Sopenharmony_cistatic void handle_drain_completion(struct ib_cq *cq,
439862306a36Sopenharmony_ci				    struct mlx4_ib_drain_cqe *sdrain,
439962306a36Sopenharmony_ci				    struct mlx4_ib_dev *dev)
440062306a36Sopenharmony_ci{
440162306a36Sopenharmony_ci	struct mlx4_dev *mdev = dev->dev;
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_ci	if (cq->poll_ctx == IB_POLL_DIRECT) {
440462306a36Sopenharmony_ci		while (wait_for_completion_timeout(&sdrain->done, HZ / 10) <= 0)
440562306a36Sopenharmony_ci			ib_process_cq_direct(cq, -1);
440662306a36Sopenharmony_ci		return;
440762306a36Sopenharmony_ci	}
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_ci	if (mdev->persist->state == MLX4_DEVICE_STATE_INTERNAL_ERROR) {
441062306a36Sopenharmony_ci		struct mlx4_ib_cq *mcq = to_mcq(cq);
441162306a36Sopenharmony_ci		bool triggered = false;
441262306a36Sopenharmony_ci		unsigned long flags;
441362306a36Sopenharmony_ci
441462306a36Sopenharmony_ci		spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
441562306a36Sopenharmony_ci		/* Make sure that the CQ handler won't run if wasn't run yet */
441662306a36Sopenharmony_ci		if (!mcq->mcq.reset_notify_added)
441762306a36Sopenharmony_ci			mcq->mcq.reset_notify_added = 1;
441862306a36Sopenharmony_ci		else
441962306a36Sopenharmony_ci			triggered = true;
442062306a36Sopenharmony_ci		spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
442162306a36Sopenharmony_ci
442262306a36Sopenharmony_ci		if (triggered) {
442362306a36Sopenharmony_ci			/* Wait for any scheduled/running task to be ended */
442462306a36Sopenharmony_ci			switch (cq->poll_ctx) {
442562306a36Sopenharmony_ci			case IB_POLL_SOFTIRQ:
442662306a36Sopenharmony_ci				irq_poll_disable(&cq->iop);
442762306a36Sopenharmony_ci				irq_poll_enable(&cq->iop);
442862306a36Sopenharmony_ci				break;
442962306a36Sopenharmony_ci			case IB_POLL_WORKQUEUE:
443062306a36Sopenharmony_ci				cancel_work_sync(&cq->work);
443162306a36Sopenharmony_ci				break;
443262306a36Sopenharmony_ci			default:
443362306a36Sopenharmony_ci				WARN_ON_ONCE(1);
443462306a36Sopenharmony_ci			}
443562306a36Sopenharmony_ci		}
443662306a36Sopenharmony_ci
443762306a36Sopenharmony_ci		/* Run the CQ handler - this makes sure that the drain WR will
443862306a36Sopenharmony_ci		 * be processed if wasn't processed yet.
443962306a36Sopenharmony_ci		 */
444062306a36Sopenharmony_ci		mcq->mcq.comp(&mcq->mcq);
444162306a36Sopenharmony_ci	}
444262306a36Sopenharmony_ci
444362306a36Sopenharmony_ci	wait_for_completion(&sdrain->done);
444462306a36Sopenharmony_ci}
444562306a36Sopenharmony_ci
444662306a36Sopenharmony_civoid mlx4_ib_drain_sq(struct ib_qp *qp)
444762306a36Sopenharmony_ci{
444862306a36Sopenharmony_ci	struct ib_cq *cq = qp->send_cq;
444962306a36Sopenharmony_ci	struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR };
445062306a36Sopenharmony_ci	struct mlx4_ib_drain_cqe sdrain;
445162306a36Sopenharmony_ci	const struct ib_send_wr *bad_swr;
445262306a36Sopenharmony_ci	struct ib_rdma_wr swr = {
445362306a36Sopenharmony_ci		.wr = {
445462306a36Sopenharmony_ci			.next = NULL,
445562306a36Sopenharmony_ci			{ .wr_cqe	= &sdrain.cqe, },
445662306a36Sopenharmony_ci			.opcode	= IB_WR_RDMA_WRITE,
445762306a36Sopenharmony_ci		},
445862306a36Sopenharmony_ci	};
445962306a36Sopenharmony_ci	int ret;
446062306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(qp->device);
446162306a36Sopenharmony_ci	struct mlx4_dev *mdev = dev->dev;
446262306a36Sopenharmony_ci
446362306a36Sopenharmony_ci	ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
446462306a36Sopenharmony_ci	if (ret && mdev->persist->state != MLX4_DEVICE_STATE_INTERNAL_ERROR) {
446562306a36Sopenharmony_ci		WARN_ONCE(ret, "failed to drain send queue: %d\n", ret);
446662306a36Sopenharmony_ci		return;
446762306a36Sopenharmony_ci	}
446862306a36Sopenharmony_ci
446962306a36Sopenharmony_ci	sdrain.cqe.done = mlx4_ib_drain_qp_done;
447062306a36Sopenharmony_ci	init_completion(&sdrain.done);
447162306a36Sopenharmony_ci
447262306a36Sopenharmony_ci	ret = _mlx4_ib_post_send(qp, &swr.wr, &bad_swr, true);
447362306a36Sopenharmony_ci	if (ret) {
447462306a36Sopenharmony_ci		WARN_ONCE(ret, "failed to drain send queue: %d\n", ret);
447562306a36Sopenharmony_ci		return;
447662306a36Sopenharmony_ci	}
447762306a36Sopenharmony_ci
447862306a36Sopenharmony_ci	handle_drain_completion(cq, &sdrain, dev);
447962306a36Sopenharmony_ci}
448062306a36Sopenharmony_ci
448162306a36Sopenharmony_civoid mlx4_ib_drain_rq(struct ib_qp *qp)
448262306a36Sopenharmony_ci{
448362306a36Sopenharmony_ci	struct ib_cq *cq = qp->recv_cq;
448462306a36Sopenharmony_ci	struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR };
448562306a36Sopenharmony_ci	struct mlx4_ib_drain_cqe rdrain;
448662306a36Sopenharmony_ci	struct ib_recv_wr rwr = {};
448762306a36Sopenharmony_ci	const struct ib_recv_wr *bad_rwr;
448862306a36Sopenharmony_ci	int ret;
448962306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(qp->device);
449062306a36Sopenharmony_ci	struct mlx4_dev *mdev = dev->dev;
449162306a36Sopenharmony_ci
449262306a36Sopenharmony_ci	ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
449362306a36Sopenharmony_ci	if (ret && mdev->persist->state != MLX4_DEVICE_STATE_INTERNAL_ERROR) {
449462306a36Sopenharmony_ci		WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret);
449562306a36Sopenharmony_ci		return;
449662306a36Sopenharmony_ci	}
449762306a36Sopenharmony_ci
449862306a36Sopenharmony_ci	rwr.wr_cqe = &rdrain.cqe;
449962306a36Sopenharmony_ci	rdrain.cqe.done = mlx4_ib_drain_qp_done;
450062306a36Sopenharmony_ci	init_completion(&rdrain.done);
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	ret = _mlx4_ib_post_recv(qp, &rwr, &bad_rwr, true);
450362306a36Sopenharmony_ci	if (ret) {
450462306a36Sopenharmony_ci		WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret);
450562306a36Sopenharmony_ci		return;
450662306a36Sopenharmony_ci	}
450762306a36Sopenharmony_ci
450862306a36Sopenharmony_ci	handle_drain_completion(cq, &rdrain, dev);
450962306a36Sopenharmony_ci}
451062306a36Sopenharmony_ci
451162306a36Sopenharmony_ciint mlx4_ib_qp_event_init(void)
451262306a36Sopenharmony_ci{
451362306a36Sopenharmony_ci	mlx4_ib_qp_event_wq = alloc_ordered_workqueue("mlx4_ib_qp_event_wq", 0);
451462306a36Sopenharmony_ci	if (!mlx4_ib_qp_event_wq)
451562306a36Sopenharmony_ci		return -ENOMEM;
451662306a36Sopenharmony_ci
451762306a36Sopenharmony_ci	return 0;
451862306a36Sopenharmony_ci}
451962306a36Sopenharmony_ci
452062306a36Sopenharmony_civoid mlx4_ib_qp_event_cleanup(void)
452162306a36Sopenharmony_ci{
452262306a36Sopenharmony_ci	destroy_workqueue(mlx4_ib_qp_event_wq);
452362306a36Sopenharmony_ci}
4524