18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *        disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *        provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <linux/module.h>
348c2ecf20Sopenharmony_ci#include <rdma/ib_umem.h>
358c2ecf20Sopenharmony_ci#include <rdma/ib_cache.h>
368c2ecf20Sopenharmony_ci#include <rdma/ib_user_verbs.h>
378c2ecf20Sopenharmony_ci#include <rdma/rdma_counter.h>
388c2ecf20Sopenharmony_ci#include <linux/mlx5/fs.h>
398c2ecf20Sopenharmony_ci#include "mlx5_ib.h"
408c2ecf20Sopenharmony_ci#include "ib_rep.h"
418c2ecf20Sopenharmony_ci#include "counters.h"
428c2ecf20Sopenharmony_ci#include "cmd.h"
438c2ecf20Sopenharmony_ci#include "qp.h"
448c2ecf20Sopenharmony_ci#include "wr.h"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cienum {
478c2ecf20Sopenharmony_ci	MLX5_IB_ACK_REQ_FREQ	= 8,
488c2ecf20Sopenharmony_ci};
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cienum {
518c2ecf20Sopenharmony_ci	MLX5_IB_DEFAULT_SCHED_QUEUE	= 0x83,
528c2ecf20Sopenharmony_ci	MLX5_IB_DEFAULT_QP0_SCHED_QUEUE	= 0x3f,
538c2ecf20Sopenharmony_ci	MLX5_IB_LINK_TYPE_IB		= 0,
548c2ecf20Sopenharmony_ci	MLX5_IB_LINK_TYPE_ETH		= 1
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cienum raw_qp_set_mask_map {
588c2ecf20Sopenharmony_ci	MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID		= 1UL << 0,
598c2ecf20Sopenharmony_ci	MLX5_RAW_QP_RATE_LIMIT			= 1UL << 1,
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistruct mlx5_modify_raw_qp_param {
638c2ecf20Sopenharmony_ci	u16 operation;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	u32 set_mask; /* raw_qp_set_mask_map */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	struct mlx5_rate_limit rl;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	u8 rq_q_ctr_id;
708c2ecf20Sopenharmony_ci	u16 port;
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void get_cqs(enum ib_qp_type qp_type,
748c2ecf20Sopenharmony_ci		    struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq,
758c2ecf20Sopenharmony_ci		    struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic int is_qp0(enum ib_qp_type qp_type)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	return qp_type == IB_QPT_SMI;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int is_sqp(enum ib_qp_type qp_type)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	return is_qp0(qp_type) || is_qp1(qp_type);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/**
888c2ecf20Sopenharmony_ci * mlx5_ib_read_user_wqe_common() - Copy a WQE (or part of) from user WQ
898c2ecf20Sopenharmony_ci * to kernel buffer
908c2ecf20Sopenharmony_ci *
918c2ecf20Sopenharmony_ci * @umem: User space memory where the WQ is
928c2ecf20Sopenharmony_ci * @buffer: buffer to copy to
938c2ecf20Sopenharmony_ci * @buflen: buffer length
948c2ecf20Sopenharmony_ci * @wqe_index: index of WQE to copy from
958c2ecf20Sopenharmony_ci * @wq_offset: offset to start of WQ
968c2ecf20Sopenharmony_ci * @wq_wqe_cnt: number of WQEs in WQ
978c2ecf20Sopenharmony_ci * @wq_wqe_shift: log2 of WQE size
988c2ecf20Sopenharmony_ci * @bcnt: number of bytes to copy
998c2ecf20Sopenharmony_ci * @bytes_copied: number of bytes to copy (return value)
1008c2ecf20Sopenharmony_ci *
1018c2ecf20Sopenharmony_ci * Copies from start of WQE bcnt or less bytes.
1028c2ecf20Sopenharmony_ci * Does not gurantee to copy the entire WQE.
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * Return: zero on success, or an error code.
1058c2ecf20Sopenharmony_ci */
1068c2ecf20Sopenharmony_cistatic int mlx5_ib_read_user_wqe_common(struct ib_umem *umem, void *buffer,
1078c2ecf20Sopenharmony_ci					size_t buflen, int wqe_index,
1088c2ecf20Sopenharmony_ci					int wq_offset, int wq_wqe_cnt,
1098c2ecf20Sopenharmony_ci					int wq_wqe_shift, int bcnt,
1108c2ecf20Sopenharmony_ci					size_t *bytes_copied)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	size_t offset = wq_offset + ((wqe_index % wq_wqe_cnt) << wq_wqe_shift);
1138c2ecf20Sopenharmony_ci	size_t wq_end = wq_offset + (wq_wqe_cnt << wq_wqe_shift);
1148c2ecf20Sopenharmony_ci	size_t copy_length;
1158c2ecf20Sopenharmony_ci	int ret;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* don't copy more than requested, more than buffer length or
1188c2ecf20Sopenharmony_ci	 * beyond WQ end
1198c2ecf20Sopenharmony_ci	 */
1208c2ecf20Sopenharmony_ci	copy_length = min_t(u32, buflen, wq_end - offset);
1218c2ecf20Sopenharmony_ci	copy_length = min_t(u32, copy_length, bcnt);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	ret = ib_umem_copy_from(buffer, umem, offset, copy_length);
1248c2ecf20Sopenharmony_ci	if (ret)
1258c2ecf20Sopenharmony_ci		return ret;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (!ret && bytes_copied)
1288c2ecf20Sopenharmony_ci		*bytes_copied = copy_length;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return 0;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic int mlx5_ib_read_kernel_wqe_sq(struct mlx5_ib_qp *qp, int wqe_index,
1348c2ecf20Sopenharmony_ci				      void *buffer, size_t buflen, size_t *bc)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct mlx5_wqe_ctrl_seg *ctrl;
1378c2ecf20Sopenharmony_ci	size_t bytes_copied = 0;
1388c2ecf20Sopenharmony_ci	size_t wqe_length;
1398c2ecf20Sopenharmony_ci	void *p;
1408c2ecf20Sopenharmony_ci	int ds;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	wqe_index = wqe_index & qp->sq.fbc.sz_m1;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* read the control segment first */
1458c2ecf20Sopenharmony_ci	p = mlx5_frag_buf_get_wqe(&qp->sq.fbc, wqe_index);
1468c2ecf20Sopenharmony_ci	ctrl = p;
1478c2ecf20Sopenharmony_ci	ds = be32_to_cpu(ctrl->qpn_ds) & MLX5_WQE_CTRL_DS_MASK;
1488c2ecf20Sopenharmony_ci	wqe_length = ds * MLX5_WQE_DS_UNITS;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* read rest of WQE if it spreads over more than one stride */
1518c2ecf20Sopenharmony_ci	while (bytes_copied < wqe_length) {
1528c2ecf20Sopenharmony_ci		size_t copy_length =
1538c2ecf20Sopenharmony_ci			min_t(size_t, buflen - bytes_copied, MLX5_SEND_WQE_BB);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci		if (!copy_length)
1568c2ecf20Sopenharmony_ci			break;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci		memcpy(buffer + bytes_copied, p, copy_length);
1598c2ecf20Sopenharmony_ci		bytes_copied += copy_length;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci		wqe_index = (wqe_index + 1) & qp->sq.fbc.sz_m1;
1628c2ecf20Sopenharmony_ci		p = mlx5_frag_buf_get_wqe(&qp->sq.fbc, wqe_index);
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci	*bc = bytes_copied;
1658c2ecf20Sopenharmony_ci	return 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic int mlx5_ib_read_user_wqe_sq(struct mlx5_ib_qp *qp, int wqe_index,
1698c2ecf20Sopenharmony_ci				    void *buffer, size_t buflen, size_t *bc)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base = &qp->trans_qp.base;
1728c2ecf20Sopenharmony_ci	struct ib_umem *umem = base->ubuffer.umem;
1738c2ecf20Sopenharmony_ci	struct mlx5_ib_wq *wq = &qp->sq;
1748c2ecf20Sopenharmony_ci	struct mlx5_wqe_ctrl_seg *ctrl;
1758c2ecf20Sopenharmony_ci	size_t bytes_copied;
1768c2ecf20Sopenharmony_ci	size_t bytes_copied2;
1778c2ecf20Sopenharmony_ci	size_t wqe_length;
1788c2ecf20Sopenharmony_ci	int ret;
1798c2ecf20Sopenharmony_ci	int ds;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* at first read as much as possible */
1828c2ecf20Sopenharmony_ci	ret = mlx5_ib_read_user_wqe_common(umem, buffer, buflen, wqe_index,
1838c2ecf20Sopenharmony_ci					   wq->offset, wq->wqe_cnt,
1848c2ecf20Sopenharmony_ci					   wq->wqe_shift, buflen,
1858c2ecf20Sopenharmony_ci					   &bytes_copied);
1868c2ecf20Sopenharmony_ci	if (ret)
1878c2ecf20Sopenharmony_ci		return ret;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* we need at least control segment size to proceed */
1908c2ecf20Sopenharmony_ci	if (bytes_copied < sizeof(*ctrl))
1918c2ecf20Sopenharmony_ci		return -EINVAL;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	ctrl = buffer;
1948c2ecf20Sopenharmony_ci	ds = be32_to_cpu(ctrl->qpn_ds) & MLX5_WQE_CTRL_DS_MASK;
1958c2ecf20Sopenharmony_ci	wqe_length = ds * MLX5_WQE_DS_UNITS;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/* if we copied enough then we are done */
1988c2ecf20Sopenharmony_ci	if (bytes_copied >= wqe_length) {
1998c2ecf20Sopenharmony_ci		*bc = bytes_copied;
2008c2ecf20Sopenharmony_ci		return 0;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* otherwise this a wrapped around wqe
2048c2ecf20Sopenharmony_ci	 * so read the remaining bytes starting
2058c2ecf20Sopenharmony_ci	 * from  wqe_index 0
2068c2ecf20Sopenharmony_ci	 */
2078c2ecf20Sopenharmony_ci	ret = mlx5_ib_read_user_wqe_common(umem, buffer + bytes_copied,
2088c2ecf20Sopenharmony_ci					   buflen - bytes_copied, 0, wq->offset,
2098c2ecf20Sopenharmony_ci					   wq->wqe_cnt, wq->wqe_shift,
2108c2ecf20Sopenharmony_ci					   wqe_length - bytes_copied,
2118c2ecf20Sopenharmony_ci					   &bytes_copied2);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (ret)
2148c2ecf20Sopenharmony_ci		return ret;
2158c2ecf20Sopenharmony_ci	*bc = bytes_copied + bytes_copied2;
2168c2ecf20Sopenharmony_ci	return 0;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ciint mlx5_ib_read_wqe_sq(struct mlx5_ib_qp *qp, int wqe_index, void *buffer,
2208c2ecf20Sopenharmony_ci			size_t buflen, size_t *bc)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base = &qp->trans_qp.base;
2238c2ecf20Sopenharmony_ci	struct ib_umem *umem = base->ubuffer.umem;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (buflen < sizeof(struct mlx5_wqe_ctrl_seg))
2268c2ecf20Sopenharmony_ci		return -EINVAL;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (!umem)
2298c2ecf20Sopenharmony_ci		return mlx5_ib_read_kernel_wqe_sq(qp, wqe_index, buffer,
2308c2ecf20Sopenharmony_ci						  buflen, bc);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return mlx5_ib_read_user_wqe_sq(qp, wqe_index, buffer, buflen, bc);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic int mlx5_ib_read_user_wqe_rq(struct mlx5_ib_qp *qp, int wqe_index,
2368c2ecf20Sopenharmony_ci				    void *buffer, size_t buflen, size_t *bc)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base = &qp->trans_qp.base;
2398c2ecf20Sopenharmony_ci	struct ib_umem *umem = base->ubuffer.umem;
2408c2ecf20Sopenharmony_ci	struct mlx5_ib_wq *wq = &qp->rq;
2418c2ecf20Sopenharmony_ci	size_t bytes_copied;
2428c2ecf20Sopenharmony_ci	int ret;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	ret = mlx5_ib_read_user_wqe_common(umem, buffer, buflen, wqe_index,
2458c2ecf20Sopenharmony_ci					   wq->offset, wq->wqe_cnt,
2468c2ecf20Sopenharmony_ci					   wq->wqe_shift, buflen,
2478c2ecf20Sopenharmony_ci					   &bytes_copied);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (ret)
2508c2ecf20Sopenharmony_ci		return ret;
2518c2ecf20Sopenharmony_ci	*bc = bytes_copied;
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ciint mlx5_ib_read_wqe_rq(struct mlx5_ib_qp *qp, int wqe_index, void *buffer,
2568c2ecf20Sopenharmony_ci			size_t buflen, size_t *bc)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base = &qp->trans_qp.base;
2598c2ecf20Sopenharmony_ci	struct ib_umem *umem = base->ubuffer.umem;
2608c2ecf20Sopenharmony_ci	struct mlx5_ib_wq *wq = &qp->rq;
2618c2ecf20Sopenharmony_ci	size_t wqe_size = 1 << wq->wqe_shift;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if (buflen < wqe_size)
2648c2ecf20Sopenharmony_ci		return -EINVAL;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (!umem)
2678c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	return mlx5_ib_read_user_wqe_rq(qp, wqe_index, buffer, buflen, bc);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic int mlx5_ib_read_user_wqe_srq(struct mlx5_ib_srq *srq, int wqe_index,
2738c2ecf20Sopenharmony_ci				     void *buffer, size_t buflen, size_t *bc)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct ib_umem *umem = srq->umem;
2768c2ecf20Sopenharmony_ci	size_t bytes_copied;
2778c2ecf20Sopenharmony_ci	int ret;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	ret = mlx5_ib_read_user_wqe_common(umem, buffer, buflen, wqe_index, 0,
2808c2ecf20Sopenharmony_ci					   srq->msrq.max, srq->msrq.wqe_shift,
2818c2ecf20Sopenharmony_ci					   buflen, &bytes_copied);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (ret)
2848c2ecf20Sopenharmony_ci		return ret;
2858c2ecf20Sopenharmony_ci	*bc = bytes_copied;
2868c2ecf20Sopenharmony_ci	return 0;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ciint mlx5_ib_read_wqe_srq(struct mlx5_ib_srq *srq, int wqe_index, void *buffer,
2908c2ecf20Sopenharmony_ci			 size_t buflen, size_t *bc)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct ib_umem *umem = srq->umem;
2938c2ecf20Sopenharmony_ci	size_t wqe_size = 1 << srq->msrq.wqe_shift;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (buflen < wqe_size)
2968c2ecf20Sopenharmony_ci		return -EINVAL;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (!umem)
2998c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return mlx5_ib_read_user_wqe_srq(srq, wqe_index, buffer, buflen, bc);
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic void mlx5_ib_qp_event(struct mlx5_core_qp *qp, int type)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct ib_qp *ibqp = &to_mibqp(qp)->ibqp;
3078c2ecf20Sopenharmony_ci	struct ib_event event;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (type == MLX5_EVENT_TYPE_PATH_MIG) {
3108c2ecf20Sopenharmony_ci		/* This event is only valid for trans_qps */
3118c2ecf20Sopenharmony_ci		to_mibqp(qp)->port = to_mibqp(qp)->trans_qp.alt_port;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (ibqp->event_handler) {
3158c2ecf20Sopenharmony_ci		event.device     = ibqp->device;
3168c2ecf20Sopenharmony_ci		event.element.qp = ibqp;
3178c2ecf20Sopenharmony_ci		switch (type) {
3188c2ecf20Sopenharmony_ci		case MLX5_EVENT_TYPE_PATH_MIG:
3198c2ecf20Sopenharmony_ci			event.event = IB_EVENT_PATH_MIG;
3208c2ecf20Sopenharmony_ci			break;
3218c2ecf20Sopenharmony_ci		case MLX5_EVENT_TYPE_COMM_EST:
3228c2ecf20Sopenharmony_ci			event.event = IB_EVENT_COMM_EST;
3238c2ecf20Sopenharmony_ci			break;
3248c2ecf20Sopenharmony_ci		case MLX5_EVENT_TYPE_SQ_DRAINED:
3258c2ecf20Sopenharmony_ci			event.event = IB_EVENT_SQ_DRAINED;
3268c2ecf20Sopenharmony_ci			break;
3278c2ecf20Sopenharmony_ci		case MLX5_EVENT_TYPE_SRQ_LAST_WQE:
3288c2ecf20Sopenharmony_ci			event.event = IB_EVENT_QP_LAST_WQE_REACHED;
3298c2ecf20Sopenharmony_ci			break;
3308c2ecf20Sopenharmony_ci		case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
3318c2ecf20Sopenharmony_ci			event.event = IB_EVENT_QP_FATAL;
3328c2ecf20Sopenharmony_ci			break;
3338c2ecf20Sopenharmony_ci		case MLX5_EVENT_TYPE_PATH_MIG_FAILED:
3348c2ecf20Sopenharmony_ci			event.event = IB_EVENT_PATH_MIG_ERR;
3358c2ecf20Sopenharmony_ci			break;
3368c2ecf20Sopenharmony_ci		case MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
3378c2ecf20Sopenharmony_ci			event.event = IB_EVENT_QP_REQ_ERR;
3388c2ecf20Sopenharmony_ci			break;
3398c2ecf20Sopenharmony_ci		case MLX5_EVENT_TYPE_WQ_ACCESS_ERROR:
3408c2ecf20Sopenharmony_ci			event.event = IB_EVENT_QP_ACCESS_ERR;
3418c2ecf20Sopenharmony_ci			break;
3428c2ecf20Sopenharmony_ci		default:
3438c2ecf20Sopenharmony_ci			pr_warn("mlx5_ib: Unexpected event type %d on QP %06x\n", type, qp->qpn);
3448c2ecf20Sopenharmony_ci			return;
3458c2ecf20Sopenharmony_ci		}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		ibqp->event_handler(&event, ibqp->qp_context);
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
3528c2ecf20Sopenharmony_ci		       int has_rq, struct mlx5_ib_qp *qp, struct mlx5_ib_create_qp *ucmd)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	int wqe_size;
3558c2ecf20Sopenharmony_ci	int wq_size;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* Sanity check RQ size before proceeding */
3588c2ecf20Sopenharmony_ci	if (cap->max_recv_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz)))
3598c2ecf20Sopenharmony_ci		return -EINVAL;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (!has_rq) {
3628c2ecf20Sopenharmony_ci		qp->rq.max_gs = 0;
3638c2ecf20Sopenharmony_ci		qp->rq.wqe_cnt = 0;
3648c2ecf20Sopenharmony_ci		qp->rq.wqe_shift = 0;
3658c2ecf20Sopenharmony_ci		cap->max_recv_wr = 0;
3668c2ecf20Sopenharmony_ci		cap->max_recv_sge = 0;
3678c2ecf20Sopenharmony_ci	} else {
3688c2ecf20Sopenharmony_ci		int wq_sig = !!(qp->flags_en & MLX5_QP_FLAG_SIGNATURE);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		if (ucmd) {
3718c2ecf20Sopenharmony_ci			qp->rq.wqe_cnt = ucmd->rq_wqe_count;
3728c2ecf20Sopenharmony_ci			if (ucmd->rq_wqe_shift > BITS_PER_BYTE * sizeof(ucmd->rq_wqe_shift))
3738c2ecf20Sopenharmony_ci				return -EINVAL;
3748c2ecf20Sopenharmony_ci			qp->rq.wqe_shift = ucmd->rq_wqe_shift;
3758c2ecf20Sopenharmony_ci			if ((1 << qp->rq.wqe_shift) /
3768c2ecf20Sopenharmony_ci				    sizeof(struct mlx5_wqe_data_seg) <
3778c2ecf20Sopenharmony_ci			    wq_sig)
3788c2ecf20Sopenharmony_ci				return -EINVAL;
3798c2ecf20Sopenharmony_ci			qp->rq.max_gs =
3808c2ecf20Sopenharmony_ci				(1 << qp->rq.wqe_shift) /
3818c2ecf20Sopenharmony_ci					sizeof(struct mlx5_wqe_data_seg) -
3828c2ecf20Sopenharmony_ci				wq_sig;
3838c2ecf20Sopenharmony_ci			qp->rq.max_post = qp->rq.wqe_cnt;
3848c2ecf20Sopenharmony_ci		} else {
3858c2ecf20Sopenharmony_ci			wqe_size =
3868c2ecf20Sopenharmony_ci				wq_sig ? sizeof(struct mlx5_wqe_signature_seg) :
3878c2ecf20Sopenharmony_ci					 0;
3888c2ecf20Sopenharmony_ci			wqe_size += cap->max_recv_sge * sizeof(struct mlx5_wqe_data_seg);
3898c2ecf20Sopenharmony_ci			wqe_size = roundup_pow_of_two(wqe_size);
3908c2ecf20Sopenharmony_ci			wq_size = roundup_pow_of_two(cap->max_recv_wr) * wqe_size;
3918c2ecf20Sopenharmony_ci			wq_size = max_t(int, wq_size, MLX5_SEND_WQE_BB);
3928c2ecf20Sopenharmony_ci			qp->rq.wqe_cnt = wq_size / wqe_size;
3938c2ecf20Sopenharmony_ci			if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_rq)) {
3948c2ecf20Sopenharmony_ci				mlx5_ib_dbg(dev, "wqe_size %d, max %d\n",
3958c2ecf20Sopenharmony_ci					    wqe_size,
3968c2ecf20Sopenharmony_ci					    MLX5_CAP_GEN(dev->mdev,
3978c2ecf20Sopenharmony_ci							 max_wqe_sz_rq));
3988c2ecf20Sopenharmony_ci				return -EINVAL;
3998c2ecf20Sopenharmony_ci			}
4008c2ecf20Sopenharmony_ci			qp->rq.wqe_shift = ilog2(wqe_size);
4018c2ecf20Sopenharmony_ci			qp->rq.max_gs =
4028c2ecf20Sopenharmony_ci				(1 << qp->rq.wqe_shift) /
4038c2ecf20Sopenharmony_ci					sizeof(struct mlx5_wqe_data_seg) -
4048c2ecf20Sopenharmony_ci				wq_sig;
4058c2ecf20Sopenharmony_ci			qp->rq.max_post = qp->rq.wqe_cnt;
4068c2ecf20Sopenharmony_ci		}
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return 0;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic int sq_overhead(struct ib_qp_init_attr *attr)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	int size = 0;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	switch (attr->qp_type) {
4178c2ecf20Sopenharmony_ci	case IB_QPT_XRC_INI:
4188c2ecf20Sopenharmony_ci		size += sizeof(struct mlx5_wqe_xrc_seg);
4198c2ecf20Sopenharmony_ci		fallthrough;
4208c2ecf20Sopenharmony_ci	case IB_QPT_RC:
4218c2ecf20Sopenharmony_ci		size += sizeof(struct mlx5_wqe_ctrl_seg) +
4228c2ecf20Sopenharmony_ci			max(sizeof(struct mlx5_wqe_atomic_seg) +
4238c2ecf20Sopenharmony_ci			    sizeof(struct mlx5_wqe_raddr_seg),
4248c2ecf20Sopenharmony_ci			    sizeof(struct mlx5_wqe_umr_ctrl_seg) +
4258c2ecf20Sopenharmony_ci			    sizeof(struct mlx5_mkey_seg) +
4268c2ecf20Sopenharmony_ci			    MLX5_IB_SQ_UMR_INLINE_THRESHOLD /
4278c2ecf20Sopenharmony_ci			    MLX5_IB_UMR_OCTOWORD);
4288c2ecf20Sopenharmony_ci		break;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	case IB_QPT_XRC_TGT:
4318c2ecf20Sopenharmony_ci		return 0;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	case IB_QPT_UC:
4348c2ecf20Sopenharmony_ci		size += sizeof(struct mlx5_wqe_ctrl_seg) +
4358c2ecf20Sopenharmony_ci			max(sizeof(struct mlx5_wqe_raddr_seg),
4368c2ecf20Sopenharmony_ci			    sizeof(struct mlx5_wqe_umr_ctrl_seg) +
4378c2ecf20Sopenharmony_ci			    sizeof(struct mlx5_mkey_seg));
4388c2ecf20Sopenharmony_ci		break;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	case IB_QPT_UD:
4418c2ecf20Sopenharmony_ci		if (attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO)
4428c2ecf20Sopenharmony_ci			size += sizeof(struct mlx5_wqe_eth_pad) +
4438c2ecf20Sopenharmony_ci				sizeof(struct mlx5_wqe_eth_seg);
4448c2ecf20Sopenharmony_ci		fallthrough;
4458c2ecf20Sopenharmony_ci	case IB_QPT_SMI:
4468c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_HW_GSI:
4478c2ecf20Sopenharmony_ci		size += sizeof(struct mlx5_wqe_ctrl_seg) +
4488c2ecf20Sopenharmony_ci			sizeof(struct mlx5_wqe_datagram_seg);
4498c2ecf20Sopenharmony_ci		break;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_REG_UMR:
4528c2ecf20Sopenharmony_ci		size += sizeof(struct mlx5_wqe_ctrl_seg) +
4538c2ecf20Sopenharmony_ci			sizeof(struct mlx5_wqe_umr_ctrl_seg) +
4548c2ecf20Sopenharmony_ci			sizeof(struct mlx5_mkey_seg);
4558c2ecf20Sopenharmony_ci		break;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	default:
4588c2ecf20Sopenharmony_ci		return -EINVAL;
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	return size;
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int calc_send_wqe(struct ib_qp_init_attr *attr)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	int inl_size = 0;
4678c2ecf20Sopenharmony_ci	int size;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	size = sq_overhead(attr);
4708c2ecf20Sopenharmony_ci	if (size < 0)
4718c2ecf20Sopenharmony_ci		return size;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	if (attr->cap.max_inline_data) {
4748c2ecf20Sopenharmony_ci		inl_size = size + sizeof(struct mlx5_wqe_inline_seg) +
4758c2ecf20Sopenharmony_ci			attr->cap.max_inline_data;
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	size += attr->cap.max_send_sge * sizeof(struct mlx5_wqe_data_seg);
4798c2ecf20Sopenharmony_ci	if (attr->create_flags & IB_QP_CREATE_INTEGRITY_EN &&
4808c2ecf20Sopenharmony_ci	    ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB) < MLX5_SIG_WQE_SIZE)
4818c2ecf20Sopenharmony_ci		return MLX5_SIG_WQE_SIZE;
4828c2ecf20Sopenharmony_ci	else
4838c2ecf20Sopenharmony_ci		return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB);
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic int get_send_sge(struct ib_qp_init_attr *attr, int wqe_size)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	int max_sge;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (attr->qp_type == IB_QPT_RC)
4918c2ecf20Sopenharmony_ci		max_sge = (min_t(int, wqe_size, 512) -
4928c2ecf20Sopenharmony_ci			   sizeof(struct mlx5_wqe_ctrl_seg) -
4938c2ecf20Sopenharmony_ci			   sizeof(struct mlx5_wqe_raddr_seg)) /
4948c2ecf20Sopenharmony_ci			sizeof(struct mlx5_wqe_data_seg);
4958c2ecf20Sopenharmony_ci	else if (attr->qp_type == IB_QPT_XRC_INI)
4968c2ecf20Sopenharmony_ci		max_sge = (min_t(int, wqe_size, 512) -
4978c2ecf20Sopenharmony_ci			   sizeof(struct mlx5_wqe_ctrl_seg) -
4988c2ecf20Sopenharmony_ci			   sizeof(struct mlx5_wqe_xrc_seg) -
4998c2ecf20Sopenharmony_ci			   sizeof(struct mlx5_wqe_raddr_seg)) /
5008c2ecf20Sopenharmony_ci			sizeof(struct mlx5_wqe_data_seg);
5018c2ecf20Sopenharmony_ci	else
5028c2ecf20Sopenharmony_ci		max_sge = (wqe_size - sq_overhead(attr)) /
5038c2ecf20Sopenharmony_ci			sizeof(struct mlx5_wqe_data_seg);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	return min_t(int, max_sge, wqe_size - sq_overhead(attr) /
5068c2ecf20Sopenharmony_ci		     sizeof(struct mlx5_wqe_data_seg));
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
5108c2ecf20Sopenharmony_ci			struct mlx5_ib_qp *qp)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	int wqe_size;
5138c2ecf20Sopenharmony_ci	int wq_size;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (!attr->cap.max_send_wr)
5168c2ecf20Sopenharmony_ci		return 0;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	wqe_size = calc_send_wqe(attr);
5198c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "wqe_size %d\n", wqe_size);
5208c2ecf20Sopenharmony_ci	if (wqe_size < 0)
5218c2ecf20Sopenharmony_ci		return wqe_size;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (wqe_size > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) {
5248c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "wqe_size(%d) > max_sq_desc_sz(%d)\n",
5258c2ecf20Sopenharmony_ci			    wqe_size, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq));
5268c2ecf20Sopenharmony_ci		return -EINVAL;
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	qp->max_inline_data = wqe_size - sq_overhead(attr) -
5308c2ecf20Sopenharmony_ci			      sizeof(struct mlx5_wqe_inline_seg);
5318c2ecf20Sopenharmony_ci	attr->cap.max_inline_data = qp->max_inline_data;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size);
5348c2ecf20Sopenharmony_ci	qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB;
5358c2ecf20Sopenharmony_ci	if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) {
5368c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "send queue size (%d * %d / %d -> %d) exceeds limits(%d)\n",
5378c2ecf20Sopenharmony_ci			    attr->cap.max_send_wr, wqe_size, MLX5_SEND_WQE_BB,
5388c2ecf20Sopenharmony_ci			    qp->sq.wqe_cnt,
5398c2ecf20Sopenharmony_ci			    1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz));
5408c2ecf20Sopenharmony_ci		return -ENOMEM;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci	qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
5438c2ecf20Sopenharmony_ci	qp->sq.max_gs = get_send_sge(attr, wqe_size);
5448c2ecf20Sopenharmony_ci	if (qp->sq.max_gs < attr->cap.max_send_sge)
5458c2ecf20Sopenharmony_ci		return -ENOMEM;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	attr->cap.max_send_sge = qp->sq.max_gs;
5488c2ecf20Sopenharmony_ci	qp->sq.max_post = wq_size / wqe_size;
5498c2ecf20Sopenharmony_ci	attr->cap.max_send_wr = qp->sq.max_post;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	return wq_size;
5528c2ecf20Sopenharmony_ci}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_cistatic int set_user_buf_size(struct mlx5_ib_dev *dev,
5558c2ecf20Sopenharmony_ci			    struct mlx5_ib_qp *qp,
5568c2ecf20Sopenharmony_ci			    struct mlx5_ib_create_qp *ucmd,
5578c2ecf20Sopenharmony_ci			    struct mlx5_ib_qp_base *base,
5588c2ecf20Sopenharmony_ci			    struct ib_qp_init_attr *attr)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	int desc_sz = 1 << qp->sq.wqe_shift;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (desc_sz > MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq)) {
5638c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "desc_sz %d, max_sq_desc_sz %d\n",
5648c2ecf20Sopenharmony_ci			     desc_sz, MLX5_CAP_GEN(dev->mdev, max_wqe_sz_sq));
5658c2ecf20Sopenharmony_ci		return -EINVAL;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	if (ucmd->sq_wqe_count && !is_power_of_2(ucmd->sq_wqe_count)) {
5698c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "sq_wqe_count %d is not a power of two\n",
5708c2ecf20Sopenharmony_ci			     ucmd->sq_wqe_count);
5718c2ecf20Sopenharmony_ci		return -EINVAL;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	qp->sq.wqe_cnt = ucmd->sq_wqe_count;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) {
5778c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "wqe_cnt %d, max_wqes %d\n",
5788c2ecf20Sopenharmony_ci			     qp->sq.wqe_cnt,
5798c2ecf20Sopenharmony_ci			     1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz));
5808c2ecf20Sopenharmony_ci		return -EINVAL;
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	if (attr->qp_type == IB_QPT_RAW_PACKET ||
5848c2ecf20Sopenharmony_ci	    qp->flags & IB_QP_CREATE_SOURCE_QPN) {
5858c2ecf20Sopenharmony_ci		base->ubuffer.buf_size = qp->rq.wqe_cnt << qp->rq.wqe_shift;
5868c2ecf20Sopenharmony_ci		qp->raw_packet_qp.sq.ubuffer.buf_size = qp->sq.wqe_cnt << 6;
5878c2ecf20Sopenharmony_ci	} else {
5888c2ecf20Sopenharmony_ci		base->ubuffer.buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) +
5898c2ecf20Sopenharmony_ci					 (qp->sq.wqe_cnt << 6);
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	return 0;
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic int qp_has_rq(struct ib_qp_init_attr *attr)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	if (attr->qp_type == IB_QPT_XRC_INI ||
5988c2ecf20Sopenharmony_ci	    attr->qp_type == IB_QPT_XRC_TGT || attr->srq ||
5998c2ecf20Sopenharmony_ci	    attr->qp_type == MLX5_IB_QPT_REG_UMR ||
6008c2ecf20Sopenharmony_ci	    !attr->cap.max_recv_wr)
6018c2ecf20Sopenharmony_ci		return 0;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	return 1;
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_cienum {
6078c2ecf20Sopenharmony_ci	/* this is the first blue flame register in the array of bfregs assigned
6088c2ecf20Sopenharmony_ci	 * to a processes. Since we do not use it for blue flame but rather
6098c2ecf20Sopenharmony_ci	 * regular 64 bit doorbells, we do not need a lock for maintaiing
6108c2ecf20Sopenharmony_ci	 * "odd/even" order
6118c2ecf20Sopenharmony_ci	 */
6128c2ecf20Sopenharmony_ci	NUM_NON_BLUE_FLAME_BFREGS = 1,
6138c2ecf20Sopenharmony_ci};
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_cistatic int max_bfregs(struct mlx5_ib_dev *dev, struct mlx5_bfreg_info *bfregi)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	return get_num_static_uars(dev, bfregi) * MLX5_NON_FP_BFREGS_PER_UAR;
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic int num_med_bfreg(struct mlx5_ib_dev *dev,
6218c2ecf20Sopenharmony_ci			 struct mlx5_bfreg_info *bfregi)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	int n;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	n = max_bfregs(dev, bfregi) - bfregi->num_low_latency_bfregs -
6268c2ecf20Sopenharmony_ci	    NUM_NON_BLUE_FLAME_BFREGS;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	return n >= 0 ? n : 0;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic int first_med_bfreg(struct mlx5_ib_dev *dev,
6328c2ecf20Sopenharmony_ci			   struct mlx5_bfreg_info *bfregi)
6338c2ecf20Sopenharmony_ci{
6348c2ecf20Sopenharmony_ci	return num_med_bfreg(dev, bfregi) ? 1 : -ENOMEM;
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic int first_hi_bfreg(struct mlx5_ib_dev *dev,
6388c2ecf20Sopenharmony_ci			  struct mlx5_bfreg_info *bfregi)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	int med;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	med = num_med_bfreg(dev, bfregi);
6438c2ecf20Sopenharmony_ci	return ++med;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic int alloc_high_class_bfreg(struct mlx5_ib_dev *dev,
6478c2ecf20Sopenharmony_ci				  struct mlx5_bfreg_info *bfregi)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	int i;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	for (i = first_hi_bfreg(dev, bfregi); i < max_bfregs(dev, bfregi); i++) {
6528c2ecf20Sopenharmony_ci		if (!bfregi->count[i]) {
6538c2ecf20Sopenharmony_ci			bfregi->count[i]++;
6548c2ecf20Sopenharmony_ci			return i;
6558c2ecf20Sopenharmony_ci		}
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	return -ENOMEM;
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic int alloc_med_class_bfreg(struct mlx5_ib_dev *dev,
6628c2ecf20Sopenharmony_ci				 struct mlx5_bfreg_info *bfregi)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	int minidx = first_med_bfreg(dev, bfregi);
6658c2ecf20Sopenharmony_ci	int i;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (minidx < 0)
6688c2ecf20Sopenharmony_ci		return minidx;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	for (i = minidx; i < first_hi_bfreg(dev, bfregi); i++) {
6718c2ecf20Sopenharmony_ci		if (bfregi->count[i] < bfregi->count[minidx])
6728c2ecf20Sopenharmony_ci			minidx = i;
6738c2ecf20Sopenharmony_ci		if (!bfregi->count[minidx])
6748c2ecf20Sopenharmony_ci			break;
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	bfregi->count[minidx]++;
6788c2ecf20Sopenharmony_ci	return minidx;
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_cistatic int alloc_bfreg(struct mlx5_ib_dev *dev,
6828c2ecf20Sopenharmony_ci		       struct mlx5_bfreg_info *bfregi)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	int bfregn = -ENOMEM;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (bfregi->lib_uar_dyn)
6878c2ecf20Sopenharmony_ci		return -EINVAL;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	mutex_lock(&bfregi->lock);
6908c2ecf20Sopenharmony_ci	if (bfregi->ver >= 2) {
6918c2ecf20Sopenharmony_ci		bfregn = alloc_high_class_bfreg(dev, bfregi);
6928c2ecf20Sopenharmony_ci		if (bfregn < 0)
6938c2ecf20Sopenharmony_ci			bfregn = alloc_med_class_bfreg(dev, bfregi);
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (bfregn < 0) {
6978c2ecf20Sopenharmony_ci		BUILD_BUG_ON(NUM_NON_BLUE_FLAME_BFREGS != 1);
6988c2ecf20Sopenharmony_ci		bfregn = 0;
6998c2ecf20Sopenharmony_ci		bfregi->count[bfregn]++;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci	mutex_unlock(&bfregi->lock);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	return bfregn;
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_civoid mlx5_ib_free_bfreg(struct mlx5_ib_dev *dev, struct mlx5_bfreg_info *bfregi, int bfregn)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	mutex_lock(&bfregi->lock);
7098c2ecf20Sopenharmony_ci	bfregi->count[bfregn]--;
7108c2ecf20Sopenharmony_ci	mutex_unlock(&bfregi->lock);
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic enum mlx5_qp_state to_mlx5_state(enum ib_qp_state state)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	switch (state) {
7168c2ecf20Sopenharmony_ci	case IB_QPS_RESET:	return MLX5_QP_STATE_RST;
7178c2ecf20Sopenharmony_ci	case IB_QPS_INIT:	return MLX5_QP_STATE_INIT;
7188c2ecf20Sopenharmony_ci	case IB_QPS_RTR:	return MLX5_QP_STATE_RTR;
7198c2ecf20Sopenharmony_ci	case IB_QPS_RTS:	return MLX5_QP_STATE_RTS;
7208c2ecf20Sopenharmony_ci	case IB_QPS_SQD:	return MLX5_QP_STATE_SQD;
7218c2ecf20Sopenharmony_ci	case IB_QPS_SQE:	return MLX5_QP_STATE_SQER;
7228c2ecf20Sopenharmony_ci	case IB_QPS_ERR:	return MLX5_QP_STATE_ERR;
7238c2ecf20Sopenharmony_ci	default:		return -1;
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic int to_mlx5_st(enum ib_qp_type type)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	switch (type) {
7308c2ecf20Sopenharmony_ci	case IB_QPT_RC:			return MLX5_QP_ST_RC;
7318c2ecf20Sopenharmony_ci	case IB_QPT_UC:			return MLX5_QP_ST_UC;
7328c2ecf20Sopenharmony_ci	case IB_QPT_UD:			return MLX5_QP_ST_UD;
7338c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_REG_UMR:	return MLX5_QP_ST_REG_UMR;
7348c2ecf20Sopenharmony_ci	case IB_QPT_XRC_INI:
7358c2ecf20Sopenharmony_ci	case IB_QPT_XRC_TGT:		return MLX5_QP_ST_XRC;
7368c2ecf20Sopenharmony_ci	case IB_QPT_SMI:		return MLX5_QP_ST_QP0;
7378c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_HW_GSI:	return MLX5_QP_ST_QP1;
7388c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_DCI:		return MLX5_QP_ST_DCI;
7398c2ecf20Sopenharmony_ci	case IB_QPT_RAW_PACKET:		return MLX5_QP_ST_RAW_ETHERTYPE;
7408c2ecf20Sopenharmony_ci	default:		return -EINVAL;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq,
7458c2ecf20Sopenharmony_ci			     struct mlx5_ib_cq *recv_cq);
7468c2ecf20Sopenharmony_cistatic void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq,
7478c2ecf20Sopenharmony_ci			       struct mlx5_ib_cq *recv_cq);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ciint bfregn_to_uar_index(struct mlx5_ib_dev *dev,
7508c2ecf20Sopenharmony_ci			struct mlx5_bfreg_info *bfregi, u32 bfregn,
7518c2ecf20Sopenharmony_ci			bool dyn_bfreg)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	unsigned int bfregs_per_sys_page;
7548c2ecf20Sopenharmony_ci	u32 index_of_sys_page;
7558c2ecf20Sopenharmony_ci	u32 offset;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (bfregi->lib_uar_dyn)
7588c2ecf20Sopenharmony_ci		return -EINVAL;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	bfregs_per_sys_page = get_uars_per_sys_page(dev, bfregi->lib_uar_4k) *
7618c2ecf20Sopenharmony_ci				MLX5_NON_FP_BFREGS_PER_UAR;
7628c2ecf20Sopenharmony_ci	index_of_sys_page = bfregn / bfregs_per_sys_page;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (dyn_bfreg) {
7658c2ecf20Sopenharmony_ci		index_of_sys_page += bfregi->num_static_sys_pages;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		if (index_of_sys_page >= bfregi->num_sys_pages)
7688c2ecf20Sopenharmony_ci			return -EINVAL;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci		if (bfregn > bfregi->num_dyn_bfregs ||
7718c2ecf20Sopenharmony_ci		    bfregi->sys_pages[index_of_sys_page] == MLX5_IB_INVALID_UAR_INDEX) {
7728c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "Invalid dynamic uar index\n");
7738c2ecf20Sopenharmony_ci			return -EINVAL;
7748c2ecf20Sopenharmony_ci		}
7758c2ecf20Sopenharmony_ci	}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	offset = bfregn % bfregs_per_sys_page / MLX5_NON_FP_BFREGS_PER_UAR;
7788c2ecf20Sopenharmony_ci	return bfregi->sys_pages[index_of_sys_page] + offset;
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic int mlx5_ib_umem_get(struct mlx5_ib_dev *dev, struct ib_udata *udata,
7828c2ecf20Sopenharmony_ci			    unsigned long addr, size_t size,
7838c2ecf20Sopenharmony_ci			    struct ib_umem **umem, int *npages, int *page_shift,
7848c2ecf20Sopenharmony_ci			    int *ncont, u32 *offset)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	int err;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	*umem = ib_umem_get(&dev->ib_dev, addr, size, 0);
7898c2ecf20Sopenharmony_ci	if (IS_ERR(*umem)) {
7908c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "umem_get failed\n");
7918c2ecf20Sopenharmony_ci		return PTR_ERR(*umem);
7928c2ecf20Sopenharmony_ci	}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	mlx5_ib_cont_pages(*umem, addr, 0, npages, page_shift, ncont, NULL);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	err = mlx5_ib_get_buf_offset(addr, *page_shift, offset);
7978c2ecf20Sopenharmony_ci	if (err) {
7988c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "bad offset\n");
7998c2ecf20Sopenharmony_ci		goto err_umem;
8008c2ecf20Sopenharmony_ci	}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "addr 0x%lx, size %zu, npages %d, page_shift %d, ncont %d, offset %d\n",
8038c2ecf20Sopenharmony_ci		    addr, size, *npages, *page_shift, *ncont, *offset);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	return 0;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cierr_umem:
8088c2ecf20Sopenharmony_ci	ib_umem_release(*umem);
8098c2ecf20Sopenharmony_ci	*umem = NULL;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	return err;
8128c2ecf20Sopenharmony_ci}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_cistatic void destroy_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd,
8158c2ecf20Sopenharmony_ci			    struct mlx5_ib_rwq *rwq, struct ib_udata *udata)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *context =
8188c2ecf20Sopenharmony_ci		rdma_udata_to_drv_context(
8198c2ecf20Sopenharmony_ci			udata,
8208c2ecf20Sopenharmony_ci			struct mlx5_ib_ucontext,
8218c2ecf20Sopenharmony_ci			ibucontext);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (rwq->create_flags & MLX5_IB_WQ_FLAGS_DELAY_DROP)
8248c2ecf20Sopenharmony_ci		atomic_dec(&dev->delay_drop.rqs_cnt);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	mlx5_ib_db_unmap_user(context, &rwq->db);
8278c2ecf20Sopenharmony_ci	ib_umem_release(rwq->umem);
8288c2ecf20Sopenharmony_ci}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_cistatic int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd,
8318c2ecf20Sopenharmony_ci			  struct ib_udata *udata, struct mlx5_ib_rwq *rwq,
8328c2ecf20Sopenharmony_ci			  struct mlx5_ib_create_wq *ucmd)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context(
8358c2ecf20Sopenharmony_ci		udata, struct mlx5_ib_ucontext, ibucontext);
8368c2ecf20Sopenharmony_ci	int page_shift = 0;
8378c2ecf20Sopenharmony_ci	int npages;
8388c2ecf20Sopenharmony_ci	u32 offset = 0;
8398c2ecf20Sopenharmony_ci	int ncont = 0;
8408c2ecf20Sopenharmony_ci	int err;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	if (!ucmd->buf_addr)
8438c2ecf20Sopenharmony_ci		return -EINVAL;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	rwq->umem = ib_umem_get(&dev->ib_dev, ucmd->buf_addr, rwq->buf_size, 0);
8468c2ecf20Sopenharmony_ci	if (IS_ERR(rwq->umem)) {
8478c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "umem_get failed\n");
8488c2ecf20Sopenharmony_ci		err = PTR_ERR(rwq->umem);
8498c2ecf20Sopenharmony_ci		return err;
8508c2ecf20Sopenharmony_ci	}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	mlx5_ib_cont_pages(rwq->umem, ucmd->buf_addr, 0, &npages, &page_shift,
8538c2ecf20Sopenharmony_ci			   &ncont, NULL);
8548c2ecf20Sopenharmony_ci	err = mlx5_ib_get_buf_offset(ucmd->buf_addr, page_shift,
8558c2ecf20Sopenharmony_ci				     &rwq->rq_page_offset);
8568c2ecf20Sopenharmony_ci	if (err) {
8578c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "bad offset\n");
8588c2ecf20Sopenharmony_ci		goto err_umem;
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	rwq->rq_num_pas = ncont;
8628c2ecf20Sopenharmony_ci	rwq->page_shift = page_shift;
8638c2ecf20Sopenharmony_ci	rwq->log_page_size =  page_shift - MLX5_ADAPTER_PAGE_SHIFT;
8648c2ecf20Sopenharmony_ci	rwq->wq_sig = !!(ucmd->flags & MLX5_WQ_FLAG_SIGNATURE);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "addr 0x%llx, size %zd, npages %d, page_shift %d, ncont %d, offset %d\n",
8678c2ecf20Sopenharmony_ci		    (unsigned long long)ucmd->buf_addr, rwq->buf_size,
8688c2ecf20Sopenharmony_ci		    npages, page_shift, ncont, offset);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	err = mlx5_ib_db_map_user(ucontext, udata, ucmd->db_addr, &rwq->db);
8718c2ecf20Sopenharmony_ci	if (err) {
8728c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "map failed\n");
8738c2ecf20Sopenharmony_ci		goto err_umem;
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	return 0;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_cierr_umem:
8798c2ecf20Sopenharmony_ci	ib_umem_release(rwq->umem);
8808c2ecf20Sopenharmony_ci	return err;
8818c2ecf20Sopenharmony_ci}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cistatic int adjust_bfregn(struct mlx5_ib_dev *dev,
8848c2ecf20Sopenharmony_ci			 struct mlx5_bfreg_info *bfregi, int bfregn)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	return bfregn / MLX5_NON_FP_BFREGS_PER_UAR * MLX5_BFREGS_PER_UAR +
8878c2ecf20Sopenharmony_ci				bfregn % MLX5_NON_FP_BFREGS_PER_UAR;
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic int _create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
8918c2ecf20Sopenharmony_ci			   struct mlx5_ib_qp *qp, struct ib_udata *udata,
8928c2ecf20Sopenharmony_ci			   struct ib_qp_init_attr *attr, u32 **in,
8938c2ecf20Sopenharmony_ci			   struct mlx5_ib_create_qp_resp *resp, int *inlen,
8948c2ecf20Sopenharmony_ci			   struct mlx5_ib_qp_base *base,
8958c2ecf20Sopenharmony_ci			   struct mlx5_ib_create_qp *ucmd)
8968c2ecf20Sopenharmony_ci{
8978c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *context;
8988c2ecf20Sopenharmony_ci	struct mlx5_ib_ubuffer *ubuffer = &base->ubuffer;
8998c2ecf20Sopenharmony_ci	int page_shift = 0;
9008c2ecf20Sopenharmony_ci	int uar_index = 0;
9018c2ecf20Sopenharmony_ci	int npages;
9028c2ecf20Sopenharmony_ci	u32 offset = 0;
9038c2ecf20Sopenharmony_ci	int bfregn;
9048c2ecf20Sopenharmony_ci	int ncont = 0;
9058c2ecf20Sopenharmony_ci	__be64 *pas;
9068c2ecf20Sopenharmony_ci	void *qpc;
9078c2ecf20Sopenharmony_ci	int err;
9088c2ecf20Sopenharmony_ci	u16 uid;
9098c2ecf20Sopenharmony_ci	u32 uar_flags;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	context = rdma_udata_to_drv_context(udata, struct mlx5_ib_ucontext,
9128c2ecf20Sopenharmony_ci					    ibucontext);
9138c2ecf20Sopenharmony_ci	uar_flags = qp->flags_en &
9148c2ecf20Sopenharmony_ci		    (MLX5_QP_FLAG_UAR_PAGE_INDEX | MLX5_QP_FLAG_BFREG_INDEX);
9158c2ecf20Sopenharmony_ci	switch (uar_flags) {
9168c2ecf20Sopenharmony_ci	case MLX5_QP_FLAG_UAR_PAGE_INDEX:
9178c2ecf20Sopenharmony_ci		uar_index = ucmd->bfreg_index;
9188c2ecf20Sopenharmony_ci		bfregn = MLX5_IB_INVALID_BFREG;
9198c2ecf20Sopenharmony_ci		break;
9208c2ecf20Sopenharmony_ci	case MLX5_QP_FLAG_BFREG_INDEX:
9218c2ecf20Sopenharmony_ci		uar_index = bfregn_to_uar_index(dev, &context->bfregi,
9228c2ecf20Sopenharmony_ci						ucmd->bfreg_index, true);
9238c2ecf20Sopenharmony_ci		if (uar_index < 0)
9248c2ecf20Sopenharmony_ci			return uar_index;
9258c2ecf20Sopenharmony_ci		bfregn = MLX5_IB_INVALID_BFREG;
9268c2ecf20Sopenharmony_ci		break;
9278c2ecf20Sopenharmony_ci	case 0:
9288c2ecf20Sopenharmony_ci		if (qp->flags & IB_QP_CREATE_CROSS_CHANNEL)
9298c2ecf20Sopenharmony_ci			return -EINVAL;
9308c2ecf20Sopenharmony_ci		bfregn = alloc_bfreg(dev, &context->bfregi);
9318c2ecf20Sopenharmony_ci		if (bfregn < 0)
9328c2ecf20Sopenharmony_ci			return bfregn;
9338c2ecf20Sopenharmony_ci		break;
9348c2ecf20Sopenharmony_ci	default:
9358c2ecf20Sopenharmony_ci		return -EINVAL;
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "bfregn 0x%x, uar_index 0x%x\n", bfregn, uar_index);
9398c2ecf20Sopenharmony_ci	if (bfregn != MLX5_IB_INVALID_BFREG)
9408c2ecf20Sopenharmony_ci		uar_index = bfregn_to_uar_index(dev, &context->bfregi, bfregn,
9418c2ecf20Sopenharmony_ci						false);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	qp->rq.offset = 0;
9448c2ecf20Sopenharmony_ci	qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB);
9458c2ecf20Sopenharmony_ci	qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	err = set_user_buf_size(dev, qp, ucmd, base, attr);
9488c2ecf20Sopenharmony_ci	if (err)
9498c2ecf20Sopenharmony_ci		goto err_bfreg;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	if (ucmd->buf_addr && ubuffer->buf_size) {
9528c2ecf20Sopenharmony_ci		ubuffer->buf_addr = ucmd->buf_addr;
9538c2ecf20Sopenharmony_ci		err = mlx5_ib_umem_get(dev, udata, ubuffer->buf_addr,
9548c2ecf20Sopenharmony_ci				       ubuffer->buf_size, &ubuffer->umem,
9558c2ecf20Sopenharmony_ci				       &npages, &page_shift, &ncont, &offset);
9568c2ecf20Sopenharmony_ci		if (err)
9578c2ecf20Sopenharmony_ci			goto err_bfreg;
9588c2ecf20Sopenharmony_ci	} else {
9598c2ecf20Sopenharmony_ci		ubuffer->umem = NULL;
9608c2ecf20Sopenharmony_ci	}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	*inlen = MLX5_ST_SZ_BYTES(create_qp_in) +
9638c2ecf20Sopenharmony_ci		 MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * ncont;
9648c2ecf20Sopenharmony_ci	*in = kvzalloc(*inlen, GFP_KERNEL);
9658c2ecf20Sopenharmony_ci	if (!*in) {
9668c2ecf20Sopenharmony_ci		err = -ENOMEM;
9678c2ecf20Sopenharmony_ci		goto err_umem;
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	uid = (attr->qp_type != IB_QPT_XRC_INI) ? to_mpd(pd)->uid : 0;
9718c2ecf20Sopenharmony_ci	MLX5_SET(create_qp_in, *in, uid, uid);
9728c2ecf20Sopenharmony_ci	pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, *in, pas);
9738c2ecf20Sopenharmony_ci	if (ubuffer->umem)
9748c2ecf20Sopenharmony_ci		mlx5_ib_populate_pas(dev, ubuffer->umem, page_shift, pas, 0);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	qpc = MLX5_ADDR_OF(create_qp_in, *in, qpc);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, log_page_size, page_shift - MLX5_ADAPTER_PAGE_SHIFT);
9798c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, page_offset, offset);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, uar_page, uar_index);
9828c2ecf20Sopenharmony_ci	if (bfregn != MLX5_IB_INVALID_BFREG)
9838c2ecf20Sopenharmony_ci		resp->bfreg_index = adjust_bfregn(dev, &context->bfregi, bfregn);
9848c2ecf20Sopenharmony_ci	else
9858c2ecf20Sopenharmony_ci		resp->bfreg_index = MLX5_IB_INVALID_BFREG;
9868c2ecf20Sopenharmony_ci	qp->bfregn = bfregn;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	err = mlx5_ib_db_map_user(context, udata, ucmd->db_addr, &qp->db);
9898c2ecf20Sopenharmony_ci	if (err) {
9908c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "map failed\n");
9918c2ecf20Sopenharmony_ci		goto err_free;
9928c2ecf20Sopenharmony_ci	}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	return 0;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_cierr_free:
9978c2ecf20Sopenharmony_ci	kvfree(*in);
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_cierr_umem:
10008c2ecf20Sopenharmony_ci	ib_umem_release(ubuffer->umem);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_cierr_bfreg:
10038c2ecf20Sopenharmony_ci	if (bfregn != MLX5_IB_INVALID_BFREG)
10048c2ecf20Sopenharmony_ci		mlx5_ib_free_bfreg(dev, &context->bfregi, bfregn);
10058c2ecf20Sopenharmony_ci	return err;
10068c2ecf20Sopenharmony_ci}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_cistatic void destroy_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
10098c2ecf20Sopenharmony_ci		       struct mlx5_ib_qp_base *base, struct ib_udata *udata)
10108c2ecf20Sopenharmony_ci{
10118c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *context = rdma_udata_to_drv_context(
10128c2ecf20Sopenharmony_ci		udata, struct mlx5_ib_ucontext, ibucontext);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if (udata) {
10158c2ecf20Sopenharmony_ci		/* User QP */
10168c2ecf20Sopenharmony_ci		mlx5_ib_db_unmap_user(context, &qp->db);
10178c2ecf20Sopenharmony_ci		ib_umem_release(base->ubuffer.umem);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci		/*
10208c2ecf20Sopenharmony_ci		 * Free only the BFREGs which are handled by the kernel.
10218c2ecf20Sopenharmony_ci		 * BFREGs of UARs allocated dynamically are handled by user.
10228c2ecf20Sopenharmony_ci		 */
10238c2ecf20Sopenharmony_ci		if (qp->bfregn != MLX5_IB_INVALID_BFREG)
10248c2ecf20Sopenharmony_ci			mlx5_ib_free_bfreg(dev, &context->bfregi, qp->bfregn);
10258c2ecf20Sopenharmony_ci		return;
10268c2ecf20Sopenharmony_ci	}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	/* Kernel QP */
10298c2ecf20Sopenharmony_ci	kvfree(qp->sq.wqe_head);
10308c2ecf20Sopenharmony_ci	kvfree(qp->sq.w_list);
10318c2ecf20Sopenharmony_ci	kvfree(qp->sq.wrid);
10328c2ecf20Sopenharmony_ci	kvfree(qp->sq.wr_data);
10338c2ecf20Sopenharmony_ci	kvfree(qp->rq.wrid);
10348c2ecf20Sopenharmony_ci	if (qp->db.db)
10358c2ecf20Sopenharmony_ci		mlx5_db_free(dev->mdev, &qp->db);
10368c2ecf20Sopenharmony_ci	if (qp->buf.frags)
10378c2ecf20Sopenharmony_ci		mlx5_frag_buf_free(dev->mdev, &qp->buf);
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_cistatic int _create_kernel_qp(struct mlx5_ib_dev *dev,
10418c2ecf20Sopenharmony_ci			     struct ib_qp_init_attr *init_attr,
10428c2ecf20Sopenharmony_ci			     struct mlx5_ib_qp *qp, u32 **in, int *inlen,
10438c2ecf20Sopenharmony_ci			     struct mlx5_ib_qp_base *base)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	int uar_index;
10468c2ecf20Sopenharmony_ci	void *qpc;
10478c2ecf20Sopenharmony_ci	int err;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR)
10508c2ecf20Sopenharmony_ci		qp->bf.bfreg = &dev->fp_bfreg;
10518c2ecf20Sopenharmony_ci	else if (qp->flags & MLX5_IB_QP_CREATE_WC_TEST)
10528c2ecf20Sopenharmony_ci		qp->bf.bfreg = &dev->wc_bfreg;
10538c2ecf20Sopenharmony_ci	else
10548c2ecf20Sopenharmony_ci		qp->bf.bfreg = &dev->bfreg;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	/* We need to divide by two since each register is comprised of
10578c2ecf20Sopenharmony_ci	 * two buffers of identical size, namely odd and even
10588c2ecf20Sopenharmony_ci	 */
10598c2ecf20Sopenharmony_ci	qp->bf.buf_size = (1 << MLX5_CAP_GEN(dev->mdev, log_bf_reg_size)) / 2;
10608c2ecf20Sopenharmony_ci	uar_index = qp->bf.bfreg->index;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	err = calc_sq_size(dev, init_attr, qp);
10638c2ecf20Sopenharmony_ci	if (err < 0) {
10648c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "err %d\n", err);
10658c2ecf20Sopenharmony_ci		return err;
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	qp->rq.offset = 0;
10698c2ecf20Sopenharmony_ci	qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift;
10708c2ecf20Sopenharmony_ci	base->ubuffer.buf_size = err + (qp->rq.wqe_cnt << qp->rq.wqe_shift);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	err = mlx5_frag_buf_alloc_node(dev->mdev, base->ubuffer.buf_size,
10738c2ecf20Sopenharmony_ci				       &qp->buf, dev->mdev->priv.numa_node);
10748c2ecf20Sopenharmony_ci	if (err) {
10758c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "err %d\n", err);
10768c2ecf20Sopenharmony_ci		return err;
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	if (qp->rq.wqe_cnt)
10808c2ecf20Sopenharmony_ci		mlx5_init_fbc(qp->buf.frags, qp->rq.wqe_shift,
10818c2ecf20Sopenharmony_ci			      ilog2(qp->rq.wqe_cnt), &qp->rq.fbc);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	if (qp->sq.wqe_cnt) {
10848c2ecf20Sopenharmony_ci		int sq_strides_offset = (qp->sq.offset  & (PAGE_SIZE - 1)) /
10858c2ecf20Sopenharmony_ci					MLX5_SEND_WQE_BB;
10868c2ecf20Sopenharmony_ci		mlx5_init_fbc_offset(qp->buf.frags +
10878c2ecf20Sopenharmony_ci				     (qp->sq.offset / PAGE_SIZE),
10888c2ecf20Sopenharmony_ci				     ilog2(MLX5_SEND_WQE_BB),
10898c2ecf20Sopenharmony_ci				     ilog2(qp->sq.wqe_cnt),
10908c2ecf20Sopenharmony_ci				     sq_strides_offset, &qp->sq.fbc);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci		qp->sq.cur_edge = get_sq_edge(&qp->sq, 0);
10938c2ecf20Sopenharmony_ci	}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	*inlen = MLX5_ST_SZ_BYTES(create_qp_in) +
10968c2ecf20Sopenharmony_ci		 MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * qp->buf.npages;
10978c2ecf20Sopenharmony_ci	*in = kvzalloc(*inlen, GFP_KERNEL);
10988c2ecf20Sopenharmony_ci	if (!*in) {
10998c2ecf20Sopenharmony_ci		err = -ENOMEM;
11008c2ecf20Sopenharmony_ci		goto err_buf;
11018c2ecf20Sopenharmony_ci	}
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	qpc = MLX5_ADDR_OF(create_qp_in, *in, qpc);
11048c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, uar_page, uar_index);
11058c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, log_page_size, qp->buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	/* Set "fast registration enabled" for all kernel QPs */
11088c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, fre, 1);
11098c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, rlky, 1);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	if (qp->flags & MLX5_IB_QP_CREATE_SQPN_QP1)
11128c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, deth_sqpn, 1);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	mlx5_fill_page_frag_array(&qp->buf,
11158c2ecf20Sopenharmony_ci				  (__be64 *)MLX5_ADDR_OF(create_qp_in,
11168c2ecf20Sopenharmony_ci							 *in, pas));
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	err = mlx5_db_alloc(dev->mdev, &qp->db);
11198c2ecf20Sopenharmony_ci	if (err) {
11208c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "err %d\n", err);
11218c2ecf20Sopenharmony_ci		goto err_free;
11228c2ecf20Sopenharmony_ci	}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	qp->sq.wrid = kvmalloc_array(qp->sq.wqe_cnt,
11258c2ecf20Sopenharmony_ci				     sizeof(*qp->sq.wrid), GFP_KERNEL);
11268c2ecf20Sopenharmony_ci	qp->sq.wr_data = kvmalloc_array(qp->sq.wqe_cnt,
11278c2ecf20Sopenharmony_ci					sizeof(*qp->sq.wr_data), GFP_KERNEL);
11288c2ecf20Sopenharmony_ci	qp->rq.wrid = kvmalloc_array(qp->rq.wqe_cnt,
11298c2ecf20Sopenharmony_ci				     sizeof(*qp->rq.wrid), GFP_KERNEL);
11308c2ecf20Sopenharmony_ci	qp->sq.w_list = kvmalloc_array(qp->sq.wqe_cnt,
11318c2ecf20Sopenharmony_ci				       sizeof(*qp->sq.w_list), GFP_KERNEL);
11328c2ecf20Sopenharmony_ci	qp->sq.wqe_head = kvmalloc_array(qp->sq.wqe_cnt,
11338c2ecf20Sopenharmony_ci					 sizeof(*qp->sq.wqe_head), GFP_KERNEL);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	if (!qp->sq.wrid || !qp->sq.wr_data || !qp->rq.wrid ||
11368c2ecf20Sopenharmony_ci	    !qp->sq.w_list || !qp->sq.wqe_head) {
11378c2ecf20Sopenharmony_ci		err = -ENOMEM;
11388c2ecf20Sopenharmony_ci		goto err_wrid;
11398c2ecf20Sopenharmony_ci	}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	return 0;
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_cierr_wrid:
11448c2ecf20Sopenharmony_ci	kvfree(qp->sq.wqe_head);
11458c2ecf20Sopenharmony_ci	kvfree(qp->sq.w_list);
11468c2ecf20Sopenharmony_ci	kvfree(qp->sq.wrid);
11478c2ecf20Sopenharmony_ci	kvfree(qp->sq.wr_data);
11488c2ecf20Sopenharmony_ci	kvfree(qp->rq.wrid);
11498c2ecf20Sopenharmony_ci	mlx5_db_free(dev->mdev, &qp->db);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_cierr_free:
11528c2ecf20Sopenharmony_ci	kvfree(*in);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_cierr_buf:
11558c2ecf20Sopenharmony_ci	mlx5_frag_buf_free(dev->mdev, &qp->buf);
11568c2ecf20Sopenharmony_ci	return err;
11578c2ecf20Sopenharmony_ci}
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_cistatic u32 get_rx_type(struct mlx5_ib_qp *qp, struct ib_qp_init_attr *attr)
11608c2ecf20Sopenharmony_ci{
11618c2ecf20Sopenharmony_ci	if (attr->srq || (qp->type == IB_QPT_XRC_TGT) ||
11628c2ecf20Sopenharmony_ci	    (qp->type == MLX5_IB_QPT_DCI) || (qp->type == IB_QPT_XRC_INI))
11638c2ecf20Sopenharmony_ci		return MLX5_SRQ_RQ;
11648c2ecf20Sopenharmony_ci	else if (!qp->has_rq)
11658c2ecf20Sopenharmony_ci		return MLX5_ZERO_LEN_RQ;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	return MLX5_NON_ZERO_RQ;
11688c2ecf20Sopenharmony_ci}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_cistatic int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
11718c2ecf20Sopenharmony_ci				    struct mlx5_ib_qp *qp,
11728c2ecf20Sopenharmony_ci				    struct mlx5_ib_sq *sq, u32 tdn,
11738c2ecf20Sopenharmony_ci				    struct ib_pd *pd)
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {};
11768c2ecf20Sopenharmony_ci	void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	MLX5_SET(create_tis_in, in, uid, to_mpd(pd)->uid);
11798c2ecf20Sopenharmony_ci	MLX5_SET(tisc, tisc, transport_domain, tdn);
11808c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_SOURCE_QPN)
11818c2ecf20Sopenharmony_ci		MLX5_SET(tisc, tisc, underlay_qpn, qp->underlay_qpn);
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	return mlx5_core_create_tis(dev->mdev, in, &sq->tisn);
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
11878c2ecf20Sopenharmony_ci				      struct mlx5_ib_sq *sq, struct ib_pd *pd)
11888c2ecf20Sopenharmony_ci{
11898c2ecf20Sopenharmony_ci	mlx5_cmd_destroy_tis(dev->mdev, sq->tisn, to_mpd(pd)->uid);
11908c2ecf20Sopenharmony_ci}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_cistatic void destroy_flow_rule_vport_sq(struct mlx5_ib_sq *sq)
11938c2ecf20Sopenharmony_ci{
11948c2ecf20Sopenharmony_ci	if (sq->flow_rule)
11958c2ecf20Sopenharmony_ci		mlx5_del_flow_rules(sq->flow_rule);
11968c2ecf20Sopenharmony_ci	sq->flow_rule = NULL;
11978c2ecf20Sopenharmony_ci}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistatic int create_raw_packet_qp_sq(struct mlx5_ib_dev *dev,
12008c2ecf20Sopenharmony_ci				   struct ib_udata *udata,
12018c2ecf20Sopenharmony_ci				   struct mlx5_ib_sq *sq, void *qpin,
12028c2ecf20Sopenharmony_ci				   struct ib_pd *pd)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	struct mlx5_ib_ubuffer *ubuffer = &sq->ubuffer;
12058c2ecf20Sopenharmony_ci	__be64 *pas;
12068c2ecf20Sopenharmony_ci	void *in;
12078c2ecf20Sopenharmony_ci	void *sqc;
12088c2ecf20Sopenharmony_ci	void *qpc = MLX5_ADDR_OF(create_qp_in, qpin, qpc);
12098c2ecf20Sopenharmony_ci	void *wq;
12108c2ecf20Sopenharmony_ci	int inlen;
12118c2ecf20Sopenharmony_ci	int err;
12128c2ecf20Sopenharmony_ci	int page_shift = 0;
12138c2ecf20Sopenharmony_ci	int npages;
12148c2ecf20Sopenharmony_ci	int ncont = 0;
12158c2ecf20Sopenharmony_ci	u32 offset = 0;
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	err = mlx5_ib_umem_get(dev, udata, ubuffer->buf_addr, ubuffer->buf_size,
12188c2ecf20Sopenharmony_ci			       &sq->ubuffer.umem, &npages, &page_shift, &ncont,
12198c2ecf20Sopenharmony_ci			       &offset);
12208c2ecf20Sopenharmony_ci	if (err)
12218c2ecf20Sopenharmony_ci		return err;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(create_sq_in) + sizeof(u64) * ncont;
12248c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
12258c2ecf20Sopenharmony_ci	if (!in) {
12268c2ecf20Sopenharmony_ci		err = -ENOMEM;
12278c2ecf20Sopenharmony_ci		goto err_umem;
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	MLX5_SET(create_sq_in, in, uid, to_mpd(pd)->uid);
12318c2ecf20Sopenharmony_ci	sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
12328c2ecf20Sopenharmony_ci	MLX5_SET(sqc, sqc, flush_in_error_en, 1);
12338c2ecf20Sopenharmony_ci	if (MLX5_CAP_ETH(dev->mdev, multi_pkt_send_wqe))
12348c2ecf20Sopenharmony_ci		MLX5_SET(sqc, sqc, allow_multi_pkt_send_wqe, 1);
12358c2ecf20Sopenharmony_ci	MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST);
12368c2ecf20Sopenharmony_ci	MLX5_SET(sqc, sqc, user_index, MLX5_GET(qpc, qpc, user_index));
12378c2ecf20Sopenharmony_ci	MLX5_SET(sqc, sqc, cqn, MLX5_GET(qpc, qpc, cqn_snd));
12388c2ecf20Sopenharmony_ci	MLX5_SET(sqc, sqc, tis_lst_sz, 1);
12398c2ecf20Sopenharmony_ci	MLX5_SET(sqc, sqc, tis_num_0, sq->tisn);
12408c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(dev->mdev, eth_net_offloads) &&
12418c2ecf20Sopenharmony_ci	    MLX5_CAP_ETH(dev->mdev, swp))
12428c2ecf20Sopenharmony_ci		MLX5_SET(sqc, sqc, allow_swp, 1);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	wq = MLX5_ADDR_OF(sqc, sqc, wq);
12458c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
12468c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, pd, MLX5_GET(qpc, qpc, pd));
12478c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, uar_page, MLX5_GET(qpc, qpc, uar_page));
12488c2ecf20Sopenharmony_ci	MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(qpc, qpc, dbr_addr));
12498c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB));
12508c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, log_wq_sz, MLX5_GET(qpc, qpc, log_sq_size));
12518c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, log_wq_pg_sz,  page_shift - MLX5_ADAPTER_PAGE_SHIFT);
12528c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, page_offset, offset);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	pas = (__be64 *)MLX5_ADDR_OF(wq, wq, pas);
12558c2ecf20Sopenharmony_ci	mlx5_ib_populate_pas(dev, sq->ubuffer.umem, page_shift, pas, 0);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	err = mlx5_core_create_sq_tracked(dev, in, inlen, &sq->base.mqp);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	kvfree(in);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	if (err)
12628c2ecf20Sopenharmony_ci		goto err_umem;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	return 0;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cierr_umem:
12678c2ecf20Sopenharmony_ci	ib_umem_release(sq->ubuffer.umem);
12688c2ecf20Sopenharmony_ci	sq->ubuffer.umem = NULL;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	return err;
12718c2ecf20Sopenharmony_ci}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp_sq(struct mlx5_ib_dev *dev,
12748c2ecf20Sopenharmony_ci				     struct mlx5_ib_sq *sq)
12758c2ecf20Sopenharmony_ci{
12768c2ecf20Sopenharmony_ci	destroy_flow_rule_vport_sq(sq);
12778c2ecf20Sopenharmony_ci	mlx5_core_destroy_sq_tracked(dev, &sq->base.mqp);
12788c2ecf20Sopenharmony_ci	ib_umem_release(sq->ubuffer.umem);
12798c2ecf20Sopenharmony_ci}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_cistatic size_t get_rq_pas_size(void *qpc)
12828c2ecf20Sopenharmony_ci{
12838c2ecf20Sopenharmony_ci	u32 log_page_size = MLX5_GET(qpc, qpc, log_page_size) + 12;
12848c2ecf20Sopenharmony_ci	u32 log_rq_stride = MLX5_GET(qpc, qpc, log_rq_stride);
12858c2ecf20Sopenharmony_ci	u32 log_rq_size   = MLX5_GET(qpc, qpc, log_rq_size);
12868c2ecf20Sopenharmony_ci	u32 page_offset   = MLX5_GET(qpc, qpc, page_offset);
12878c2ecf20Sopenharmony_ci	u32 po_quanta	  = 1 << (log_page_size - 6);
12888c2ecf20Sopenharmony_ci	u32 rq_sz	  = 1 << (log_rq_size + 4 + log_rq_stride);
12898c2ecf20Sopenharmony_ci	u32 page_size	  = 1 << log_page_size;
12908c2ecf20Sopenharmony_ci	u32 rq_sz_po      = rq_sz + (page_offset * po_quanta);
12918c2ecf20Sopenharmony_ci	u32 rq_num_pas	  = (rq_sz_po + page_size - 1) / page_size;
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	return rq_num_pas * sizeof(u64);
12948c2ecf20Sopenharmony_ci}
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_cistatic int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
12978c2ecf20Sopenharmony_ci				   struct mlx5_ib_rq *rq, void *qpin,
12988c2ecf20Sopenharmony_ci				   size_t qpinlen, struct ib_pd *pd)
12998c2ecf20Sopenharmony_ci{
13008c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *mqp = rq->base.container_mibqp;
13018c2ecf20Sopenharmony_ci	__be64 *pas;
13028c2ecf20Sopenharmony_ci	__be64 *qp_pas;
13038c2ecf20Sopenharmony_ci	void *in;
13048c2ecf20Sopenharmony_ci	void *rqc;
13058c2ecf20Sopenharmony_ci	void *wq;
13068c2ecf20Sopenharmony_ci	void *qpc = MLX5_ADDR_OF(create_qp_in, qpin, qpc);
13078c2ecf20Sopenharmony_ci	size_t rq_pas_size = get_rq_pas_size(qpc);
13088c2ecf20Sopenharmony_ci	size_t inlen;
13098c2ecf20Sopenharmony_ci	int err;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	if (qpinlen < rq_pas_size + MLX5_BYTE_OFF(create_qp_in, pas))
13128c2ecf20Sopenharmony_ci		return -EINVAL;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(create_rq_in) + rq_pas_size;
13158c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
13168c2ecf20Sopenharmony_ci	if (!in)
13178c2ecf20Sopenharmony_ci		return -ENOMEM;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid);
13208c2ecf20Sopenharmony_ci	rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
13218c2ecf20Sopenharmony_ci	if (!(rq->flags & MLX5_IB_RQ_CVLAN_STRIPPING))
13228c2ecf20Sopenharmony_ci		MLX5_SET(rqc, rqc, vsd, 1);
13238c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, mem_rq_type, MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE);
13248c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST);
13258c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, flush_in_error_en, 1);
13268c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, user_index, MLX5_GET(qpc, qpc, user_index));
13278c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, cqn, MLX5_GET(qpc, qpc, cqn_rcv));
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	if (mqp->flags & IB_QP_CREATE_SCATTER_FCS)
13308c2ecf20Sopenharmony_ci		MLX5_SET(rqc, rqc, scatter_fcs, 1);
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	wq = MLX5_ADDR_OF(rqc, rqc, wq);
13338c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
13348c2ecf20Sopenharmony_ci	if (rq->flags & MLX5_IB_RQ_PCI_WRITE_END_PADDING)
13358c2ecf20Sopenharmony_ci		MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN);
13368c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, page_offset, MLX5_GET(qpc, qpc, page_offset));
13378c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, pd, MLX5_GET(qpc, qpc, pd));
13388c2ecf20Sopenharmony_ci	MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(qpc, qpc, dbr_addr));
13398c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, log_wq_stride, MLX5_GET(qpc, qpc, log_rq_stride) + 4);
13408c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, log_wq_pg_sz, MLX5_GET(qpc, qpc, log_page_size));
13418c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, log_wq_sz, MLX5_GET(qpc, qpc, log_rq_size));
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	pas = (__be64 *)MLX5_ADDR_OF(wq, wq, pas);
13448c2ecf20Sopenharmony_ci	qp_pas = (__be64 *)MLX5_ADDR_OF(create_qp_in, qpin, pas);
13458c2ecf20Sopenharmony_ci	memcpy(pas, qp_pas, rq_pas_size);
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	err = mlx5_core_create_rq_tracked(dev, in, inlen, &rq->base.mqp);
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	kvfree(in);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	return err;
13528c2ecf20Sopenharmony_ci}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
13558c2ecf20Sopenharmony_ci				     struct mlx5_ib_rq *rq)
13568c2ecf20Sopenharmony_ci{
13578c2ecf20Sopenharmony_ci	mlx5_core_destroy_rq_tracked(dev, &rq->base.mqp);
13588c2ecf20Sopenharmony_ci}
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev,
13618c2ecf20Sopenharmony_ci				      struct mlx5_ib_rq *rq,
13628c2ecf20Sopenharmony_ci				      u32 qp_flags_en,
13638c2ecf20Sopenharmony_ci				      struct ib_pd *pd)
13648c2ecf20Sopenharmony_ci{
13658c2ecf20Sopenharmony_ci	if (qp_flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC |
13668c2ecf20Sopenharmony_ci			   MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC))
13678c2ecf20Sopenharmony_ci		mlx5_ib_disable_lb(dev, false, true);
13688c2ecf20Sopenharmony_ci	mlx5_cmd_destroy_tir(dev->mdev, rq->tirn, to_mpd(pd)->uid);
13698c2ecf20Sopenharmony_ci}
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_cistatic int create_raw_packet_qp_tir(struct mlx5_ib_dev *dev,
13728c2ecf20Sopenharmony_ci				    struct mlx5_ib_rq *rq, u32 tdn,
13738c2ecf20Sopenharmony_ci				    u32 *qp_flags_en, struct ib_pd *pd,
13748c2ecf20Sopenharmony_ci				    u32 *out)
13758c2ecf20Sopenharmony_ci{
13768c2ecf20Sopenharmony_ci	u8 lb_flag = 0;
13778c2ecf20Sopenharmony_ci	u32 *in;
13788c2ecf20Sopenharmony_ci	void *tirc;
13798c2ecf20Sopenharmony_ci	int inlen;
13808c2ecf20Sopenharmony_ci	int err;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(create_tir_in);
13838c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
13848c2ecf20Sopenharmony_ci	if (!in)
13858c2ecf20Sopenharmony_ci		return -ENOMEM;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid);
13888c2ecf20Sopenharmony_ci	tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
13898c2ecf20Sopenharmony_ci	MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_DIRECT);
13908c2ecf20Sopenharmony_ci	MLX5_SET(tirc, tirc, inline_rqn, rq->base.mqp.qpn);
13918c2ecf20Sopenharmony_ci	MLX5_SET(tirc, tirc, transport_domain, tdn);
13928c2ecf20Sopenharmony_ci	if (*qp_flags_en & MLX5_QP_FLAG_TUNNEL_OFFLOADS)
13938c2ecf20Sopenharmony_ci		MLX5_SET(tirc, tirc, tunneled_offload_en, 1);
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	if (*qp_flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC)
13968c2ecf20Sopenharmony_ci		lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	if (*qp_flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)
13998c2ecf20Sopenharmony_ci		lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	if (dev->is_rep) {
14028c2ecf20Sopenharmony_ci		lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST;
14038c2ecf20Sopenharmony_ci		*qp_flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC;
14048c2ecf20Sopenharmony_ci	}
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	MLX5_SET(tirc, tirc, self_lb_block, lb_flag);
14078c2ecf20Sopenharmony_ci	MLX5_SET(create_tir_in, in, opcode, MLX5_CMD_OP_CREATE_TIR);
14088c2ecf20Sopenharmony_ci	err = mlx5_cmd_exec_inout(dev->mdev, create_tir, in, out);
14098c2ecf20Sopenharmony_ci	rq->tirn = MLX5_GET(create_tir_out, out, tirn);
14108c2ecf20Sopenharmony_ci	if (!err && MLX5_GET(tirc, tirc, self_lb_block)) {
14118c2ecf20Sopenharmony_ci		err = mlx5_ib_enable_lb(dev, false, true);
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci		if (err)
14148c2ecf20Sopenharmony_ci			destroy_raw_packet_qp_tir(dev, rq, 0, pd);
14158c2ecf20Sopenharmony_ci	}
14168c2ecf20Sopenharmony_ci	kvfree(in);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	return err;
14198c2ecf20Sopenharmony_ci}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_cistatic int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
14228c2ecf20Sopenharmony_ci				u32 *in, size_t inlen,
14238c2ecf20Sopenharmony_ci				struct ib_pd *pd,
14248c2ecf20Sopenharmony_ci				struct ib_udata *udata,
14258c2ecf20Sopenharmony_ci				struct mlx5_ib_create_qp_resp *resp)
14268c2ecf20Sopenharmony_ci{
14278c2ecf20Sopenharmony_ci	struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
14288c2ecf20Sopenharmony_ci	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
14298c2ecf20Sopenharmony_ci	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
14308c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *mucontext = rdma_udata_to_drv_context(
14318c2ecf20Sopenharmony_ci		udata, struct mlx5_ib_ucontext, ibucontext);
14328c2ecf20Sopenharmony_ci	int err;
14338c2ecf20Sopenharmony_ci	u32 tdn = mucontext->tdn;
14348c2ecf20Sopenharmony_ci	u16 uid = to_mpd(pd)->uid;
14358c2ecf20Sopenharmony_ci	u32 out[MLX5_ST_SZ_DW(create_tir_out)] = {};
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	if (!qp->sq.wqe_cnt && !qp->rq.wqe_cnt)
14388c2ecf20Sopenharmony_ci		return -EINVAL;
14398c2ecf20Sopenharmony_ci	if (qp->sq.wqe_cnt) {
14408c2ecf20Sopenharmony_ci		err = create_raw_packet_qp_tis(dev, qp, sq, tdn, pd);
14418c2ecf20Sopenharmony_ci		if (err)
14428c2ecf20Sopenharmony_ci			return err;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci		err = create_raw_packet_qp_sq(dev, udata, sq, in, pd);
14458c2ecf20Sopenharmony_ci		if (err)
14468c2ecf20Sopenharmony_ci			goto err_destroy_tis;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci		if (uid) {
14498c2ecf20Sopenharmony_ci			resp->tisn = sq->tisn;
14508c2ecf20Sopenharmony_ci			resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TISN;
14518c2ecf20Sopenharmony_ci			resp->sqn = sq->base.mqp.qpn;
14528c2ecf20Sopenharmony_ci			resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_SQN;
14538c2ecf20Sopenharmony_ci		}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci		sq->base.container_mibqp = qp;
14568c2ecf20Sopenharmony_ci		sq->base.mqp.event = mlx5_ib_qp_event;
14578c2ecf20Sopenharmony_ci	}
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	if (qp->rq.wqe_cnt) {
14608c2ecf20Sopenharmony_ci		rq->base.container_mibqp = qp;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci		if (qp->flags & IB_QP_CREATE_CVLAN_STRIPPING)
14638c2ecf20Sopenharmony_ci			rq->flags |= MLX5_IB_RQ_CVLAN_STRIPPING;
14648c2ecf20Sopenharmony_ci		if (qp->flags & IB_QP_CREATE_PCI_WRITE_END_PADDING)
14658c2ecf20Sopenharmony_ci			rq->flags |= MLX5_IB_RQ_PCI_WRITE_END_PADDING;
14668c2ecf20Sopenharmony_ci		err = create_raw_packet_qp_rq(dev, rq, in, inlen, pd);
14678c2ecf20Sopenharmony_ci		if (err)
14688c2ecf20Sopenharmony_ci			goto err_destroy_sq;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci		err = create_raw_packet_qp_tir(dev, rq, tdn, &qp->flags_en, pd,
14718c2ecf20Sopenharmony_ci					       out);
14728c2ecf20Sopenharmony_ci		if (err)
14738c2ecf20Sopenharmony_ci			goto err_destroy_rq;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci		if (uid) {
14768c2ecf20Sopenharmony_ci			resp->rqn = rq->base.mqp.qpn;
14778c2ecf20Sopenharmony_ci			resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_RQN;
14788c2ecf20Sopenharmony_ci			resp->tirn = rq->tirn;
14798c2ecf20Sopenharmony_ci			resp->comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TIRN;
14808c2ecf20Sopenharmony_ci			if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, sw_owner) ||
14818c2ecf20Sopenharmony_ci			    MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, sw_owner_v2)) {
14828c2ecf20Sopenharmony_ci				resp->tir_icm_addr = MLX5_GET(
14838c2ecf20Sopenharmony_ci					create_tir_out, out, icm_address_31_0);
14848c2ecf20Sopenharmony_ci				resp->tir_icm_addr |=
14858c2ecf20Sopenharmony_ci					(u64)MLX5_GET(create_tir_out, out,
14868c2ecf20Sopenharmony_ci						      icm_address_39_32)
14878c2ecf20Sopenharmony_ci					<< 32;
14888c2ecf20Sopenharmony_ci				resp->tir_icm_addr |=
14898c2ecf20Sopenharmony_ci					(u64)MLX5_GET(create_tir_out, out,
14908c2ecf20Sopenharmony_ci						      icm_address_63_40)
14918c2ecf20Sopenharmony_ci					<< 40;
14928c2ecf20Sopenharmony_ci				resp->comp_mask |=
14938c2ecf20Sopenharmony_ci					MLX5_IB_CREATE_QP_RESP_MASK_TIR_ICM_ADDR;
14948c2ecf20Sopenharmony_ci			}
14958c2ecf20Sopenharmony_ci		}
14968c2ecf20Sopenharmony_ci	}
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	qp->trans_qp.base.mqp.qpn = qp->sq.wqe_cnt ? sq->base.mqp.qpn :
14998c2ecf20Sopenharmony_ci						     rq->base.mqp.qpn;
15008c2ecf20Sopenharmony_ci	return 0;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_cierr_destroy_rq:
15038c2ecf20Sopenharmony_ci	destroy_raw_packet_qp_rq(dev, rq);
15048c2ecf20Sopenharmony_cierr_destroy_sq:
15058c2ecf20Sopenharmony_ci	if (!qp->sq.wqe_cnt)
15068c2ecf20Sopenharmony_ci		return err;
15078c2ecf20Sopenharmony_ci	destroy_raw_packet_qp_sq(dev, sq);
15088c2ecf20Sopenharmony_cierr_destroy_tis:
15098c2ecf20Sopenharmony_ci	destroy_raw_packet_qp_tis(dev, sq, pd);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	return err;
15128c2ecf20Sopenharmony_ci}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_cistatic void destroy_raw_packet_qp(struct mlx5_ib_dev *dev,
15158c2ecf20Sopenharmony_ci				  struct mlx5_ib_qp *qp)
15168c2ecf20Sopenharmony_ci{
15178c2ecf20Sopenharmony_ci	struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
15188c2ecf20Sopenharmony_ci	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
15198c2ecf20Sopenharmony_ci	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	if (qp->rq.wqe_cnt) {
15228c2ecf20Sopenharmony_ci		destroy_raw_packet_qp_tir(dev, rq, qp->flags_en, qp->ibqp.pd);
15238c2ecf20Sopenharmony_ci		destroy_raw_packet_qp_rq(dev, rq);
15248c2ecf20Sopenharmony_ci	}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	if (qp->sq.wqe_cnt) {
15278c2ecf20Sopenharmony_ci		destroy_raw_packet_qp_sq(dev, sq);
15288c2ecf20Sopenharmony_ci		destroy_raw_packet_qp_tis(dev, sq, qp->ibqp.pd);
15298c2ecf20Sopenharmony_ci	}
15308c2ecf20Sopenharmony_ci}
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_cistatic void raw_packet_qp_copy_info(struct mlx5_ib_qp *qp,
15338c2ecf20Sopenharmony_ci				    struct mlx5_ib_raw_packet_qp *raw_packet_qp)
15348c2ecf20Sopenharmony_ci{
15358c2ecf20Sopenharmony_ci	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
15368c2ecf20Sopenharmony_ci	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	sq->sq = &qp->sq;
15398c2ecf20Sopenharmony_ci	rq->rq = &qp->rq;
15408c2ecf20Sopenharmony_ci	sq->doorbell = &qp->db;
15418c2ecf20Sopenharmony_ci	rq->doorbell = &qp->db;
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_cistatic void destroy_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp)
15458c2ecf20Sopenharmony_ci{
15468c2ecf20Sopenharmony_ci	if (qp->flags_en & (MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC |
15478c2ecf20Sopenharmony_ci			    MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC))
15488c2ecf20Sopenharmony_ci		mlx5_ib_disable_lb(dev, false, true);
15498c2ecf20Sopenharmony_ci	mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn,
15508c2ecf20Sopenharmony_ci			     to_mpd(qp->ibqp.pd)->uid);
15518c2ecf20Sopenharmony_ci}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_cistruct mlx5_create_qp_params {
15548c2ecf20Sopenharmony_ci	struct ib_udata *udata;
15558c2ecf20Sopenharmony_ci	size_t inlen;
15568c2ecf20Sopenharmony_ci	size_t outlen;
15578c2ecf20Sopenharmony_ci	size_t ucmd_size;
15588c2ecf20Sopenharmony_ci	void *ucmd;
15598c2ecf20Sopenharmony_ci	u8 is_rss_raw : 1;
15608c2ecf20Sopenharmony_ci	struct ib_qp_init_attr *attr;
15618c2ecf20Sopenharmony_ci	u32 uidx;
15628c2ecf20Sopenharmony_ci	struct mlx5_ib_create_qp_resp resp;
15638c2ecf20Sopenharmony_ci};
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_cistatic int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct ib_pd *pd,
15668c2ecf20Sopenharmony_ci				 struct mlx5_ib_qp *qp,
15678c2ecf20Sopenharmony_ci				 struct mlx5_create_qp_params *params)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	struct ib_qp_init_attr *init_attr = params->attr;
15708c2ecf20Sopenharmony_ci	struct mlx5_ib_create_qp_rss *ucmd = params->ucmd;
15718c2ecf20Sopenharmony_ci	struct ib_udata *udata = params->udata;
15728c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *mucontext = rdma_udata_to_drv_context(
15738c2ecf20Sopenharmony_ci		udata, struct mlx5_ib_ucontext, ibucontext);
15748c2ecf20Sopenharmony_ci	int inlen;
15758c2ecf20Sopenharmony_ci	int outlen;
15768c2ecf20Sopenharmony_ci	int err;
15778c2ecf20Sopenharmony_ci	u32 *in;
15788c2ecf20Sopenharmony_ci	u32 *out;
15798c2ecf20Sopenharmony_ci	void *tirc;
15808c2ecf20Sopenharmony_ci	void *hfso;
15818c2ecf20Sopenharmony_ci	u32 selected_fields = 0;
15828c2ecf20Sopenharmony_ci	u32 outer_l4;
15838c2ecf20Sopenharmony_ci	u32 tdn = mucontext->tdn;
15848c2ecf20Sopenharmony_ci	u8 lb_flag = 0;
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	if (ucmd->comp_mask) {
15878c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "invalid comp mask\n");
15888c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
15898c2ecf20Sopenharmony_ci	}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	if (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_INNER &&
15928c2ecf20Sopenharmony_ci	    !(ucmd->flags & MLX5_QP_FLAG_TUNNEL_OFFLOADS)) {
15938c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "Tunnel offloads must be set for inner RSS\n");
15948c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
15958c2ecf20Sopenharmony_ci	}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	if (dev->is_rep)
15988c2ecf20Sopenharmony_ci		qp->flags_en |= MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC;
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	if (qp->flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC)
16018c2ecf20Sopenharmony_ci		lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	if (qp->flags_en & MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC)
16048c2ecf20Sopenharmony_ci		lb_flag |= MLX5_TIRC_SELF_LB_BLOCK_BLOCK_MULTICAST;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(create_tir_in);
16078c2ecf20Sopenharmony_ci	outlen = MLX5_ST_SZ_BYTES(create_tir_out);
16088c2ecf20Sopenharmony_ci	in = kvzalloc(inlen + outlen, GFP_KERNEL);
16098c2ecf20Sopenharmony_ci	if (!in)
16108c2ecf20Sopenharmony_ci		return -ENOMEM;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	out = in + MLX5_ST_SZ_DW(create_tir_in);
16138c2ecf20Sopenharmony_ci	MLX5_SET(create_tir_in, in, uid, to_mpd(pd)->uid);
16148c2ecf20Sopenharmony_ci	tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
16158c2ecf20Sopenharmony_ci	MLX5_SET(tirc, tirc, disp_type,
16168c2ecf20Sopenharmony_ci		 MLX5_TIRC_DISP_TYPE_INDIRECT);
16178c2ecf20Sopenharmony_ci	MLX5_SET(tirc, tirc, indirect_table,
16188c2ecf20Sopenharmony_ci		 init_attr->rwq_ind_tbl->ind_tbl_num);
16198c2ecf20Sopenharmony_ci	MLX5_SET(tirc, tirc, transport_domain, tdn);
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	if (ucmd->flags & MLX5_QP_FLAG_TUNNEL_OFFLOADS)
16248c2ecf20Sopenharmony_ci		MLX5_SET(tirc, tirc, tunneled_offload_en, 1);
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	MLX5_SET(tirc, tirc, self_lb_block, lb_flag);
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	if (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_INNER)
16298c2ecf20Sopenharmony_ci		hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_inner);
16308c2ecf20Sopenharmony_ci	else
16318c2ecf20Sopenharmony_ci		hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	switch (ucmd->rx_hash_function) {
16348c2ecf20Sopenharmony_ci	case MLX5_RX_HASH_FUNC_TOEPLITZ:
16358c2ecf20Sopenharmony_ci	{
16368c2ecf20Sopenharmony_ci		void *rss_key = MLX5_ADDR_OF(tirc, tirc, rx_hash_toeplitz_key);
16378c2ecf20Sopenharmony_ci		size_t len = MLX5_FLD_SZ_BYTES(tirc, rx_hash_toeplitz_key);
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci		if (len != ucmd->rx_key_len) {
16408c2ecf20Sopenharmony_ci			err = -EINVAL;
16418c2ecf20Sopenharmony_ci			goto err;
16428c2ecf20Sopenharmony_ci		}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci		MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_TOEPLITZ);
16458c2ecf20Sopenharmony_ci		memcpy(rss_key, ucmd->rx_hash_key, len);
16468c2ecf20Sopenharmony_ci		break;
16478c2ecf20Sopenharmony_ci	}
16488c2ecf20Sopenharmony_ci	default:
16498c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
16508c2ecf20Sopenharmony_ci		goto err;
16518c2ecf20Sopenharmony_ci	}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	if (!ucmd->rx_hash_fields_mask) {
16548c2ecf20Sopenharmony_ci		/* special case when this TIR serves as steering entry without hashing */
16558c2ecf20Sopenharmony_ci		if (!init_attr->rwq_ind_tbl->log_ind_tbl_size)
16568c2ecf20Sopenharmony_ci			goto create_tir;
16578c2ecf20Sopenharmony_ci		err = -EINVAL;
16588c2ecf20Sopenharmony_ci		goto err;
16598c2ecf20Sopenharmony_ci	}
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	if (((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) ||
16628c2ecf20Sopenharmony_ci	     (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4)) &&
16638c2ecf20Sopenharmony_ci	     ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6) ||
16648c2ecf20Sopenharmony_ci	     (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))) {
16658c2ecf20Sopenharmony_ci		err = -EINVAL;
16668c2ecf20Sopenharmony_ci		goto err;
16678c2ecf20Sopenharmony_ci	}
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	/* If none of IPV4 & IPV6 SRC/DST was set - this bit field is ignored */
16708c2ecf20Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) ||
16718c2ecf20Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4))
16728c2ecf20Sopenharmony_ci		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
16738c2ecf20Sopenharmony_ci			 MLX5_L3_PROT_TYPE_IPV4);
16748c2ecf20Sopenharmony_ci	else if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6) ||
16758c2ecf20Sopenharmony_ci		 (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))
16768c2ecf20Sopenharmony_ci		MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
16778c2ecf20Sopenharmony_ci			 MLX5_L3_PROT_TYPE_IPV6);
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	outer_l4 = ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) ||
16808c2ecf20Sopenharmony_ci		    (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP))
16818c2ecf20Sopenharmony_ci			   << 0 |
16828c2ecf20Sopenharmony_ci		   ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP) ||
16838c2ecf20Sopenharmony_ci		    (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP))
16848c2ecf20Sopenharmony_ci			   << 1 |
16858c2ecf20Sopenharmony_ci		   (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_IPSEC_SPI) << 2;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	/* Check that only one l4 protocol is set */
16888c2ecf20Sopenharmony_ci	if (outer_l4 & (outer_l4 - 1)) {
16898c2ecf20Sopenharmony_ci		err = -EINVAL;
16908c2ecf20Sopenharmony_ci		goto err;
16918c2ecf20Sopenharmony_ci	}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	/* If none of TCP & UDP SRC/DST was set - this bit field is ignored */
16948c2ecf20Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) ||
16958c2ecf20Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP))
16968c2ecf20Sopenharmony_ci		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
16978c2ecf20Sopenharmony_ci			 MLX5_L4_PROT_TYPE_TCP);
16988c2ecf20Sopenharmony_ci	else if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP) ||
16998c2ecf20Sopenharmony_ci		 (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP))
17008c2ecf20Sopenharmony_ci		MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
17018c2ecf20Sopenharmony_ci			 MLX5_L4_PROT_TYPE_UDP);
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV4) ||
17048c2ecf20Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_IPV6))
17058c2ecf20Sopenharmony_ci		selected_fields |= MLX5_HASH_FIELD_SEL_SRC_IP;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV4) ||
17088c2ecf20Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_IPV6))
17098c2ecf20Sopenharmony_ci		selected_fields |= MLX5_HASH_FIELD_SEL_DST_IP;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_TCP) ||
17128c2ecf20Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_SRC_PORT_UDP))
17138c2ecf20Sopenharmony_ci		selected_fields |= MLX5_HASH_FIELD_SEL_L4_SPORT;
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	if ((ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_TCP) ||
17168c2ecf20Sopenharmony_ci	    (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_DST_PORT_UDP))
17178c2ecf20Sopenharmony_ci		selected_fields |= MLX5_HASH_FIELD_SEL_L4_DPORT;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	if (ucmd->rx_hash_fields_mask & MLX5_RX_HASH_IPSEC_SPI)
17208c2ecf20Sopenharmony_ci		selected_fields |= MLX5_HASH_FIELD_SEL_IPSEC_SPI;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	MLX5_SET(rx_hash_field_select, hfso, selected_fields, selected_fields);
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_cicreate_tir:
17258c2ecf20Sopenharmony_ci	MLX5_SET(create_tir_in, in, opcode, MLX5_CMD_OP_CREATE_TIR);
17268c2ecf20Sopenharmony_ci	err = mlx5_cmd_exec_inout(dev->mdev, create_tir, in, out);
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	qp->rss_qp.tirn = MLX5_GET(create_tir_out, out, tirn);
17298c2ecf20Sopenharmony_ci	if (!err && MLX5_GET(tirc, tirc, self_lb_block)) {
17308c2ecf20Sopenharmony_ci		err = mlx5_ib_enable_lb(dev, false, true);
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci		if (err)
17338c2ecf20Sopenharmony_ci			mlx5_cmd_destroy_tir(dev->mdev, qp->rss_qp.tirn,
17348c2ecf20Sopenharmony_ci					     to_mpd(pd)->uid);
17358c2ecf20Sopenharmony_ci	}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	if (err)
17388c2ecf20Sopenharmony_ci		goto err;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	if (mucontext->devx_uid) {
17418c2ecf20Sopenharmony_ci		params->resp.comp_mask |= MLX5_IB_CREATE_QP_RESP_MASK_TIRN;
17428c2ecf20Sopenharmony_ci		params->resp.tirn = qp->rss_qp.tirn;
17438c2ecf20Sopenharmony_ci		if (MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, sw_owner) ||
17448c2ecf20Sopenharmony_ci		    MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, sw_owner_v2)) {
17458c2ecf20Sopenharmony_ci			params->resp.tir_icm_addr =
17468c2ecf20Sopenharmony_ci				MLX5_GET(create_tir_out, out, icm_address_31_0);
17478c2ecf20Sopenharmony_ci			params->resp.tir_icm_addr |=
17488c2ecf20Sopenharmony_ci				(u64)MLX5_GET(create_tir_out, out,
17498c2ecf20Sopenharmony_ci					      icm_address_39_32)
17508c2ecf20Sopenharmony_ci				<< 32;
17518c2ecf20Sopenharmony_ci			params->resp.tir_icm_addr |=
17528c2ecf20Sopenharmony_ci				(u64)MLX5_GET(create_tir_out, out,
17538c2ecf20Sopenharmony_ci					      icm_address_63_40)
17548c2ecf20Sopenharmony_ci				<< 40;
17558c2ecf20Sopenharmony_ci			params->resp.comp_mask |=
17568c2ecf20Sopenharmony_ci				MLX5_IB_CREATE_QP_RESP_MASK_TIR_ICM_ADDR;
17578c2ecf20Sopenharmony_ci		}
17588c2ecf20Sopenharmony_ci	}
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	kvfree(in);
17618c2ecf20Sopenharmony_ci	/* qpn is reserved for that QP */
17628c2ecf20Sopenharmony_ci	qp->trans_qp.base.mqp.qpn = 0;
17638c2ecf20Sopenharmony_ci	qp->is_rss = true;
17648c2ecf20Sopenharmony_ci	return 0;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_cierr:
17678c2ecf20Sopenharmony_ci	kvfree(in);
17688c2ecf20Sopenharmony_ci	return err;
17698c2ecf20Sopenharmony_ci}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_cistatic void configure_requester_scat_cqe(struct mlx5_ib_dev *dev,
17728c2ecf20Sopenharmony_ci					 struct mlx5_ib_qp *qp,
17738c2ecf20Sopenharmony_ci					 struct ib_qp_init_attr *init_attr,
17748c2ecf20Sopenharmony_ci					 void *qpc)
17758c2ecf20Sopenharmony_ci{
17768c2ecf20Sopenharmony_ci	int scqe_sz;
17778c2ecf20Sopenharmony_ci	bool allow_scat_cqe = false;
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	allow_scat_cqe = qp->flags_en & MLX5_QP_FLAG_ALLOW_SCATTER_CQE;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	if (!allow_scat_cqe && init_attr->sq_sig_type != IB_SIGNAL_ALL_WR)
17828c2ecf20Sopenharmony_ci		return;
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	scqe_sz = mlx5_ib_get_cqe_size(init_attr->send_cq);
17858c2ecf20Sopenharmony_ci	if (scqe_sz == 128) {
17868c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA64_CQE);
17878c2ecf20Sopenharmony_ci		return;
17888c2ecf20Sopenharmony_ci	}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	if (init_attr->qp_type != MLX5_IB_QPT_DCI ||
17918c2ecf20Sopenharmony_ci	    MLX5_CAP_GEN(dev->mdev, dc_req_scat_data_cqe))
17928c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cs_req, MLX5_REQ_SCAT_DATA32_CQE);
17938c2ecf20Sopenharmony_ci}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_cistatic int atomic_size_to_mode(int size_mask)
17968c2ecf20Sopenharmony_ci{
17978c2ecf20Sopenharmony_ci	/* driver does not support atomic_size > 256B
17988c2ecf20Sopenharmony_ci	 * and does not know how to translate bigger sizes
17998c2ecf20Sopenharmony_ci	 */
18008c2ecf20Sopenharmony_ci	int supported_size_mask = size_mask & 0x1ff;
18018c2ecf20Sopenharmony_ci	int log_max_size;
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	if (!supported_size_mask)
18048c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	log_max_size = __fls(supported_size_mask);
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	if (log_max_size > 3)
18098c2ecf20Sopenharmony_ci		return log_max_size;
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	return MLX5_ATOMIC_MODE_8B;
18128c2ecf20Sopenharmony_ci}
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_cistatic int get_atomic_mode(struct mlx5_ib_dev *dev,
18158c2ecf20Sopenharmony_ci			   enum ib_qp_type qp_type)
18168c2ecf20Sopenharmony_ci{
18178c2ecf20Sopenharmony_ci	u8 atomic_operations = MLX5_CAP_ATOMIC(dev->mdev, atomic_operations);
18188c2ecf20Sopenharmony_ci	u8 atomic = MLX5_CAP_GEN(dev->mdev, atomic);
18198c2ecf20Sopenharmony_ci	int atomic_mode = -EOPNOTSUPP;
18208c2ecf20Sopenharmony_ci	int atomic_size_mask;
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	if (!atomic)
18238c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	if (qp_type == MLX5_IB_QPT_DCT)
18268c2ecf20Sopenharmony_ci		atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_dc);
18278c2ecf20Sopenharmony_ci	else
18288c2ecf20Sopenharmony_ci		atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_qp);
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	if ((atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_CMP_SWAP) ||
18318c2ecf20Sopenharmony_ci	    (atomic_operations & MLX5_ATOMIC_OPS_EXTENDED_FETCH_ADD))
18328c2ecf20Sopenharmony_ci		atomic_mode = atomic_size_to_mode(atomic_size_mask);
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	if (atomic_mode <= 0 &&
18358c2ecf20Sopenharmony_ci	    (atomic_operations & MLX5_ATOMIC_OPS_CMP_SWAP &&
18368c2ecf20Sopenharmony_ci	     atomic_operations & MLX5_ATOMIC_OPS_FETCH_ADD))
18378c2ecf20Sopenharmony_ci		atomic_mode = MLX5_ATOMIC_MODE_IB_COMP;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	return atomic_mode;
18408c2ecf20Sopenharmony_ci}
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_cistatic int create_xrc_tgt_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
18438c2ecf20Sopenharmony_ci			     struct mlx5_create_qp_params *params)
18448c2ecf20Sopenharmony_ci{
18458c2ecf20Sopenharmony_ci	struct ib_qp_init_attr *attr = params->attr;
18468c2ecf20Sopenharmony_ci	u32 uidx = params->uidx;
18478c2ecf20Sopenharmony_ci	struct mlx5_ib_resources *devr = &dev->devr;
18488c2ecf20Sopenharmony_ci	u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {};
18498c2ecf20Sopenharmony_ci	int inlen = MLX5_ST_SZ_BYTES(create_qp_in);
18508c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
18518c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base;
18528c2ecf20Sopenharmony_ci	unsigned long flags;
18538c2ecf20Sopenharmony_ci	void *qpc;
18548c2ecf20Sopenharmony_ci	u32 *in;
18558c2ecf20Sopenharmony_ci	int err;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	if (attr->sq_sig_type == IB_SIGNAL_ALL_WR)
18588c2ecf20Sopenharmony_ci		qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE;
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
18618c2ecf20Sopenharmony_ci	if (!in)
18628c2ecf20Sopenharmony_ci		return -ENOMEM;
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, st, MLX5_QP_ST_XRC);
18678c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
18688c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, pd, to_mpd(devr->p0)->pdn);
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
18718c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, block_lb_mc, 1);
18728c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_CROSS_CHANNEL)
18738c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cd_master, 1);
18748c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_MANAGED_SEND)
18758c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cd_slave_send, 1);
18768c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_MANAGED_RECV)
18778c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cd_slave_receive, 1);
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, rq_type, MLX5_SRQ_RQ);
18808c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, no_sq, 1);
18818c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(devr->c0)->mcq.cqn);
18828c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, cqn_snd, to_mcq(devr->c0)->mcq.cqn);
18838c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, to_msrq(devr->s0)->msrq.srqn);
18848c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, xrcd, to_mxrcd(attr->xrcd)->xrcdn);
18858c2ecf20Sopenharmony_ci	MLX5_SET64(qpc, qpc, dbr_addr, qp->db.dma);
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	/* 0xffffff means we ask to work with cqe version 0 */
18888c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(mdev, cqe_version) == MLX5_CQE_VERSION_V1)
18898c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, user_index, uidx);
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_PCI_WRITE_END_PADDING) {
18928c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, end_padding_mode,
18938c2ecf20Sopenharmony_ci			 MLX5_WQ_END_PAD_MODE_ALIGN);
18948c2ecf20Sopenharmony_ci		/* Special case to clean flag */
18958c2ecf20Sopenharmony_ci		qp->flags &= ~IB_QP_CREATE_PCI_WRITE_END_PADDING;
18968c2ecf20Sopenharmony_ci	}
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	base = &qp->trans_qp.base;
18998c2ecf20Sopenharmony_ci	err = mlx5_qpc_create_qp(dev, &base->mqp, in, inlen, out);
19008c2ecf20Sopenharmony_ci	kvfree(in);
19018c2ecf20Sopenharmony_ci	if (err)
19028c2ecf20Sopenharmony_ci		return err;
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci	base->container_mibqp = qp;
19058c2ecf20Sopenharmony_ci	base->mqp.event = mlx5_ib_qp_event;
19068c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(mdev, ece_support))
19078c2ecf20Sopenharmony_ci		params->resp.ece_options = MLX5_GET(create_qp_out, out, ece);
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
19108c2ecf20Sopenharmony_ci	list_add_tail(&qp->qps_list, &dev->qp_list);
19118c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	qp->trans_qp.xrcdn = to_mxrcd(attr->xrcd)->xrcdn;
19148c2ecf20Sopenharmony_ci	return 0;
19158c2ecf20Sopenharmony_ci}
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_cistatic int create_user_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
19188c2ecf20Sopenharmony_ci			  struct mlx5_ib_qp *qp,
19198c2ecf20Sopenharmony_ci			  struct mlx5_create_qp_params *params)
19208c2ecf20Sopenharmony_ci{
19218c2ecf20Sopenharmony_ci	struct ib_qp_init_attr *init_attr = params->attr;
19228c2ecf20Sopenharmony_ci	struct mlx5_ib_create_qp *ucmd = params->ucmd;
19238c2ecf20Sopenharmony_ci	u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {};
19248c2ecf20Sopenharmony_ci	struct ib_udata *udata = params->udata;
19258c2ecf20Sopenharmony_ci	u32 uidx = params->uidx;
19268c2ecf20Sopenharmony_ci	struct mlx5_ib_resources *devr = &dev->devr;
19278c2ecf20Sopenharmony_ci	int inlen = MLX5_ST_SZ_BYTES(create_qp_in);
19288c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
19298c2ecf20Sopenharmony_ci	struct mlx5_ib_cq *send_cq;
19308c2ecf20Sopenharmony_ci	struct mlx5_ib_cq *recv_cq;
19318c2ecf20Sopenharmony_ci	unsigned long flags;
19328c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base;
19338c2ecf20Sopenharmony_ci	int mlx5_st;
19348c2ecf20Sopenharmony_ci	void *qpc;
19358c2ecf20Sopenharmony_ci	u32 *in;
19368c2ecf20Sopenharmony_ci	int err;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	spin_lock_init(&qp->sq.lock);
19398c2ecf20Sopenharmony_ci	spin_lock_init(&qp->rq.lock);
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	mlx5_st = to_mlx5_st(qp->type);
19428c2ecf20Sopenharmony_ci	if (mlx5_st < 0)
19438c2ecf20Sopenharmony_ci		return -EINVAL;
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
19468c2ecf20Sopenharmony_ci		qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_SOURCE_QPN)
19498c2ecf20Sopenharmony_ci		qp->underlay_qpn = init_attr->source_qpn;
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci	base = (init_attr->qp_type == IB_QPT_RAW_PACKET ||
19528c2ecf20Sopenharmony_ci		qp->flags & IB_QP_CREATE_SOURCE_QPN) ?
19538c2ecf20Sopenharmony_ci	       &qp->raw_packet_qp.rq.base :
19548c2ecf20Sopenharmony_ci	       &qp->trans_qp.base;
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	qp->has_rq = qp_has_rq(init_attr);
19578c2ecf20Sopenharmony_ci	err = set_rq_size(dev, &init_attr->cap, qp->has_rq, qp, ucmd);
19588c2ecf20Sopenharmony_ci	if (err) {
19598c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "err %d\n", err);
19608c2ecf20Sopenharmony_ci		return err;
19618c2ecf20Sopenharmony_ci	}
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	if (ucmd->rq_wqe_shift != qp->rq.wqe_shift ||
19648c2ecf20Sopenharmony_ci	    ucmd->rq_wqe_count != qp->rq.wqe_cnt)
19658c2ecf20Sopenharmony_ci		return -EINVAL;
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	if (ucmd->sq_wqe_count > (1 << MLX5_CAP_GEN(mdev, log_max_qp_sz)))
19688c2ecf20Sopenharmony_ci		return -EINVAL;
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	err = _create_user_qp(dev, pd, qp, udata, init_attr, &in, &params->resp,
19718c2ecf20Sopenharmony_ci			      &inlen, base, ucmd);
19728c2ecf20Sopenharmony_ci	if (err)
19738c2ecf20Sopenharmony_ci		return err;
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	if (is_sqp(init_attr->qp_type))
19768c2ecf20Sopenharmony_ci		qp->port = init_attr->port_num;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(mdev, ece_support))
19798c2ecf20Sopenharmony_ci		MLX5_SET(create_qp_in, in, ece, ucmd->ece_options);
19808c2ecf20Sopenharmony_ci	qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, st, mlx5_st);
19838c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
19848c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, pd, to_mpd(pd)->pdn);
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci	if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE)
19878c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, wq_signature, 1);
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
19908c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, block_lb_mc, 1);
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_CROSS_CHANNEL)
19938c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cd_master, 1);
19948c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_MANAGED_SEND)
19958c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cd_slave_send, 1);
19968c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_MANAGED_RECV)
19978c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cd_slave_receive, 1);
19988c2ecf20Sopenharmony_ci	if (qp->flags_en & MLX5_QP_FLAG_PACKET_BASED_CREDIT_MODE)
19998c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, req_e2e_credit_mode, 1);
20008c2ecf20Sopenharmony_ci	if ((qp->flags_en & MLX5_QP_FLAG_SCATTER_CQE) &&
20018c2ecf20Sopenharmony_ci	    (init_attr->qp_type == IB_QPT_RC ||
20028c2ecf20Sopenharmony_ci	     init_attr->qp_type == IB_QPT_UC)) {
20038c2ecf20Sopenharmony_ci		int rcqe_sz = mlx5_ib_get_cqe_size(init_attr->recv_cq);
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cs_res,
20068c2ecf20Sopenharmony_ci			 rcqe_sz == 128 ? MLX5_RES_SCAT_DATA64_CQE :
20078c2ecf20Sopenharmony_ci					  MLX5_RES_SCAT_DATA32_CQE);
20088c2ecf20Sopenharmony_ci	}
20098c2ecf20Sopenharmony_ci	if ((qp->flags_en & MLX5_QP_FLAG_SCATTER_CQE) &&
20108c2ecf20Sopenharmony_ci	    (qp->type == MLX5_IB_QPT_DCI || qp->type == IB_QPT_RC))
20118c2ecf20Sopenharmony_ci		configure_requester_scat_cqe(dev, qp, init_attr, qpc);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	if (qp->rq.wqe_cnt) {
20148c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_rq_stride, qp->rq.wqe_shift - 4);
20158c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_rq_size, ilog2(qp->rq.wqe_cnt));
20168c2ecf20Sopenharmony_ci	}
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, rq_type, get_rx_type(qp, init_attr));
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	if (qp->sq.wqe_cnt) {
20218c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_sq_size, ilog2(qp->sq.wqe_cnt));
20228c2ecf20Sopenharmony_ci	} else {
20238c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, no_sq, 1);
20248c2ecf20Sopenharmony_ci		if (init_attr->srq &&
20258c2ecf20Sopenharmony_ci		    init_attr->srq->srq_type == IB_SRQT_TM)
20268c2ecf20Sopenharmony_ci			MLX5_SET(qpc, qpc, offload_type,
20278c2ecf20Sopenharmony_ci				 MLX5_QPC_OFFLOAD_TYPE_RNDV);
20288c2ecf20Sopenharmony_ci	}
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	/* Set default resources */
20318c2ecf20Sopenharmony_ci	switch (init_attr->qp_type) {
20328c2ecf20Sopenharmony_ci	case IB_QPT_XRC_INI:
20338c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(devr->c0)->mcq.cqn);
20348c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, xrcd, devr->xrcdn1);
20358c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, to_msrq(devr->s0)->msrq.srqn);
20368c2ecf20Sopenharmony_ci		break;
20378c2ecf20Sopenharmony_ci	default:
20388c2ecf20Sopenharmony_ci		if (init_attr->srq) {
20398c2ecf20Sopenharmony_ci			MLX5_SET(qpc, qpc, xrcd, devr->xrcdn0);
20408c2ecf20Sopenharmony_ci			MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, to_msrq(init_attr->srq)->msrq.srqn);
20418c2ecf20Sopenharmony_ci		} else {
20428c2ecf20Sopenharmony_ci			MLX5_SET(qpc, qpc, xrcd, devr->xrcdn1);
20438c2ecf20Sopenharmony_ci			MLX5_SET(qpc, qpc, srqn_rmpn_xrqn, to_msrq(devr->s1)->msrq.srqn);
20448c2ecf20Sopenharmony_ci		}
20458c2ecf20Sopenharmony_ci	}
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci	if (init_attr->send_cq)
20488c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cqn_snd, to_mcq(init_attr->send_cq)->mcq.cqn);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	if (init_attr->recv_cq)
20518c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(init_attr->recv_cq)->mcq.cqn);
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	MLX5_SET64(qpc, qpc, dbr_addr, qp->db.dma);
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci	/* 0xffffff means we ask to work with cqe version 0 */
20568c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(mdev, cqe_version) == MLX5_CQE_VERSION_V1)
20578c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, user_index, uidx);
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_PCI_WRITE_END_PADDING &&
20608c2ecf20Sopenharmony_ci	    init_attr->qp_type != IB_QPT_RAW_PACKET) {
20618c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, end_padding_mode,
20628c2ecf20Sopenharmony_ci			 MLX5_WQ_END_PAD_MODE_ALIGN);
20638c2ecf20Sopenharmony_ci		/* Special case to clean flag */
20648c2ecf20Sopenharmony_ci		qp->flags &= ~IB_QP_CREATE_PCI_WRITE_END_PADDING;
20658c2ecf20Sopenharmony_ci	}
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	if (init_attr->qp_type == IB_QPT_RAW_PACKET ||
20688c2ecf20Sopenharmony_ci	    qp->flags & IB_QP_CREATE_SOURCE_QPN) {
20698c2ecf20Sopenharmony_ci		qp->raw_packet_qp.sq.ubuffer.buf_addr = ucmd->sq_buf_addr;
20708c2ecf20Sopenharmony_ci		raw_packet_qp_copy_info(qp, &qp->raw_packet_qp);
20718c2ecf20Sopenharmony_ci		err = create_raw_packet_qp(dev, qp, in, inlen, pd, udata,
20728c2ecf20Sopenharmony_ci					   &params->resp);
20738c2ecf20Sopenharmony_ci	} else
20748c2ecf20Sopenharmony_ci		err = mlx5_qpc_create_qp(dev, &base->mqp, in, inlen, out);
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci	kvfree(in);
20778c2ecf20Sopenharmony_ci	if (err)
20788c2ecf20Sopenharmony_ci		goto err_create;
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	base->container_mibqp = qp;
20818c2ecf20Sopenharmony_ci	base->mqp.event = mlx5_ib_qp_event;
20828c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(mdev, ece_support))
20838c2ecf20Sopenharmony_ci		params->resp.ece_options = MLX5_GET(create_qp_out, out, ece);
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci	get_cqs(qp->type, init_attr->send_cq, init_attr->recv_cq,
20868c2ecf20Sopenharmony_ci		&send_cq, &recv_cq);
20878c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
20888c2ecf20Sopenharmony_ci	mlx5_ib_lock_cqs(send_cq, recv_cq);
20898c2ecf20Sopenharmony_ci	/* Maintain device to QPs access, needed for further handling via reset
20908c2ecf20Sopenharmony_ci	 * flow
20918c2ecf20Sopenharmony_ci	 */
20928c2ecf20Sopenharmony_ci	list_add_tail(&qp->qps_list, &dev->qp_list);
20938c2ecf20Sopenharmony_ci	/* Maintain CQ to QPs access, needed for further handling via reset flow
20948c2ecf20Sopenharmony_ci	 */
20958c2ecf20Sopenharmony_ci	if (send_cq)
20968c2ecf20Sopenharmony_ci		list_add_tail(&qp->cq_send_list, &send_cq->list_send_qp);
20978c2ecf20Sopenharmony_ci	if (recv_cq)
20988c2ecf20Sopenharmony_ci		list_add_tail(&qp->cq_recv_list, &recv_cq->list_recv_qp);
20998c2ecf20Sopenharmony_ci	mlx5_ib_unlock_cqs(send_cq, recv_cq);
21008c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	return 0;
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_cierr_create:
21058c2ecf20Sopenharmony_ci	destroy_qp(dev, qp, base, udata);
21068c2ecf20Sopenharmony_ci	return err;
21078c2ecf20Sopenharmony_ci}
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_cistatic int create_kernel_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
21108c2ecf20Sopenharmony_ci			    struct mlx5_ib_qp *qp,
21118c2ecf20Sopenharmony_ci			    struct mlx5_create_qp_params *params)
21128c2ecf20Sopenharmony_ci{
21138c2ecf20Sopenharmony_ci	struct ib_qp_init_attr *attr = params->attr;
21148c2ecf20Sopenharmony_ci	u32 uidx = params->uidx;
21158c2ecf20Sopenharmony_ci	struct mlx5_ib_resources *devr = &dev->devr;
21168c2ecf20Sopenharmony_ci	u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {};
21178c2ecf20Sopenharmony_ci	int inlen = MLX5_ST_SZ_BYTES(create_qp_in);
21188c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
21198c2ecf20Sopenharmony_ci	struct mlx5_ib_cq *send_cq;
21208c2ecf20Sopenharmony_ci	struct mlx5_ib_cq *recv_cq;
21218c2ecf20Sopenharmony_ci	unsigned long flags;
21228c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base;
21238c2ecf20Sopenharmony_ci	int mlx5_st;
21248c2ecf20Sopenharmony_ci	void *qpc;
21258c2ecf20Sopenharmony_ci	u32 *in;
21268c2ecf20Sopenharmony_ci	int err;
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	spin_lock_init(&qp->sq.lock);
21298c2ecf20Sopenharmony_ci	spin_lock_init(&qp->rq.lock);
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci	mlx5_st = to_mlx5_st(qp->type);
21328c2ecf20Sopenharmony_ci	if (mlx5_st < 0)
21338c2ecf20Sopenharmony_ci		return -EINVAL;
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	if (attr->sq_sig_type == IB_SIGNAL_ALL_WR)
21368c2ecf20Sopenharmony_ci		qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE;
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	base = &qp->trans_qp.base;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	qp->has_rq = qp_has_rq(attr);
21418c2ecf20Sopenharmony_ci	err = set_rq_size(dev, &attr->cap, qp->has_rq, qp, NULL);
21428c2ecf20Sopenharmony_ci	if (err) {
21438c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "err %d\n", err);
21448c2ecf20Sopenharmony_ci		return err;
21458c2ecf20Sopenharmony_ci	}
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci	err = _create_kernel_qp(dev, attr, qp, &in, &inlen, base);
21488c2ecf20Sopenharmony_ci	if (err)
21498c2ecf20Sopenharmony_ci		return err;
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	if (is_sqp(attr->qp_type))
21528c2ecf20Sopenharmony_ci		qp->port = attr->port_num;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, st, mlx5_st);
21578c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	if (attr->qp_type != MLX5_IB_QPT_REG_UMR)
21608c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, pd, to_mpd(pd ? pd : devr->p0)->pdn);
21618c2ecf20Sopenharmony_ci	else
21628c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, latency_sensitive, 1);
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
21668c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, block_lb_mc, 1);
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci	if (qp->rq.wqe_cnt) {
21698c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_rq_stride, qp->rq.wqe_shift - 4);
21708c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_rq_size, ilog2(qp->rq.wqe_cnt));
21718c2ecf20Sopenharmony_ci	}
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, rq_type, get_rx_type(qp, attr));
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci	if (qp->sq.wqe_cnt)
21768c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_sq_size, ilog2(qp->sq.wqe_cnt));
21778c2ecf20Sopenharmony_ci	else
21788c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, no_sq, 1);
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	if (attr->srq) {
21818c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, xrcd, devr->xrcdn0);
21828c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, srqn_rmpn_xrqn,
21838c2ecf20Sopenharmony_ci			 to_msrq(attr->srq)->msrq.srqn);
21848c2ecf20Sopenharmony_ci	} else {
21858c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, xrcd, devr->xrcdn1);
21868c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, srqn_rmpn_xrqn,
21878c2ecf20Sopenharmony_ci			 to_msrq(devr->s1)->msrq.srqn);
21888c2ecf20Sopenharmony_ci	}
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	if (attr->send_cq)
21918c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cqn_snd, to_mcq(attr->send_cq)->mcq.cqn);
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	if (attr->recv_cq)
21948c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cqn_rcv, to_mcq(attr->recv_cq)->mcq.cqn);
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	MLX5_SET64(qpc, qpc, dbr_addr, qp->db.dma);
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	/* 0xffffff means we ask to work with cqe version 0 */
21998c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(mdev, cqe_version) == MLX5_CQE_VERSION_V1)
22008c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, user_index, uidx);
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	/* we use IB_QP_CREATE_IPOIB_UD_LSO to indicates ipoib qp */
22038c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_IPOIB_UD_LSO)
22048c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, ulp_stateless_offload_mode, 1);
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci	err = mlx5_qpc_create_qp(dev, &base->mqp, in, inlen, out);
22078c2ecf20Sopenharmony_ci	kvfree(in);
22088c2ecf20Sopenharmony_ci	if (err)
22098c2ecf20Sopenharmony_ci		goto err_create;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci	base->container_mibqp = qp;
22128c2ecf20Sopenharmony_ci	base->mqp.event = mlx5_ib_qp_event;
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	get_cqs(qp->type, attr->send_cq, attr->recv_cq,
22158c2ecf20Sopenharmony_ci		&send_cq, &recv_cq);
22168c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
22178c2ecf20Sopenharmony_ci	mlx5_ib_lock_cqs(send_cq, recv_cq);
22188c2ecf20Sopenharmony_ci	/* Maintain device to QPs access, needed for further handling via reset
22198c2ecf20Sopenharmony_ci	 * flow
22208c2ecf20Sopenharmony_ci	 */
22218c2ecf20Sopenharmony_ci	list_add_tail(&qp->qps_list, &dev->qp_list);
22228c2ecf20Sopenharmony_ci	/* Maintain CQ to QPs access, needed for further handling via reset flow
22238c2ecf20Sopenharmony_ci	 */
22248c2ecf20Sopenharmony_ci	if (send_cq)
22258c2ecf20Sopenharmony_ci		list_add_tail(&qp->cq_send_list, &send_cq->list_send_qp);
22268c2ecf20Sopenharmony_ci	if (recv_cq)
22278c2ecf20Sopenharmony_ci		list_add_tail(&qp->cq_recv_list, &recv_cq->list_recv_qp);
22288c2ecf20Sopenharmony_ci	mlx5_ib_unlock_cqs(send_cq, recv_cq);
22298c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	return 0;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_cierr_create:
22348c2ecf20Sopenharmony_ci	destroy_qp(dev, qp, base, NULL);
22358c2ecf20Sopenharmony_ci	return err;
22368c2ecf20Sopenharmony_ci}
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_cistatic void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq)
22398c2ecf20Sopenharmony_ci	__acquires(&send_cq->lock) __acquires(&recv_cq->lock)
22408c2ecf20Sopenharmony_ci{
22418c2ecf20Sopenharmony_ci	if (send_cq) {
22428c2ecf20Sopenharmony_ci		if (recv_cq) {
22438c2ecf20Sopenharmony_ci			if (send_cq->mcq.cqn < recv_cq->mcq.cqn)  {
22448c2ecf20Sopenharmony_ci				spin_lock(&send_cq->lock);
22458c2ecf20Sopenharmony_ci				spin_lock_nested(&recv_cq->lock,
22468c2ecf20Sopenharmony_ci						 SINGLE_DEPTH_NESTING);
22478c2ecf20Sopenharmony_ci			} else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) {
22488c2ecf20Sopenharmony_ci				spin_lock(&send_cq->lock);
22498c2ecf20Sopenharmony_ci				__acquire(&recv_cq->lock);
22508c2ecf20Sopenharmony_ci			} else {
22518c2ecf20Sopenharmony_ci				spin_lock(&recv_cq->lock);
22528c2ecf20Sopenharmony_ci				spin_lock_nested(&send_cq->lock,
22538c2ecf20Sopenharmony_ci						 SINGLE_DEPTH_NESTING);
22548c2ecf20Sopenharmony_ci			}
22558c2ecf20Sopenharmony_ci		} else {
22568c2ecf20Sopenharmony_ci			spin_lock(&send_cq->lock);
22578c2ecf20Sopenharmony_ci			__acquire(&recv_cq->lock);
22588c2ecf20Sopenharmony_ci		}
22598c2ecf20Sopenharmony_ci	} else if (recv_cq) {
22608c2ecf20Sopenharmony_ci		spin_lock(&recv_cq->lock);
22618c2ecf20Sopenharmony_ci		__acquire(&send_cq->lock);
22628c2ecf20Sopenharmony_ci	} else {
22638c2ecf20Sopenharmony_ci		__acquire(&send_cq->lock);
22648c2ecf20Sopenharmony_ci		__acquire(&recv_cq->lock);
22658c2ecf20Sopenharmony_ci	}
22668c2ecf20Sopenharmony_ci}
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_cistatic void mlx5_ib_unlock_cqs(struct mlx5_ib_cq *send_cq, struct mlx5_ib_cq *recv_cq)
22698c2ecf20Sopenharmony_ci	__releases(&send_cq->lock) __releases(&recv_cq->lock)
22708c2ecf20Sopenharmony_ci{
22718c2ecf20Sopenharmony_ci	if (send_cq) {
22728c2ecf20Sopenharmony_ci		if (recv_cq) {
22738c2ecf20Sopenharmony_ci			if (send_cq->mcq.cqn < recv_cq->mcq.cqn)  {
22748c2ecf20Sopenharmony_ci				spin_unlock(&recv_cq->lock);
22758c2ecf20Sopenharmony_ci				spin_unlock(&send_cq->lock);
22768c2ecf20Sopenharmony_ci			} else if (send_cq->mcq.cqn == recv_cq->mcq.cqn) {
22778c2ecf20Sopenharmony_ci				__release(&recv_cq->lock);
22788c2ecf20Sopenharmony_ci				spin_unlock(&send_cq->lock);
22798c2ecf20Sopenharmony_ci			} else {
22808c2ecf20Sopenharmony_ci				spin_unlock(&send_cq->lock);
22818c2ecf20Sopenharmony_ci				spin_unlock(&recv_cq->lock);
22828c2ecf20Sopenharmony_ci			}
22838c2ecf20Sopenharmony_ci		} else {
22848c2ecf20Sopenharmony_ci			__release(&recv_cq->lock);
22858c2ecf20Sopenharmony_ci			spin_unlock(&send_cq->lock);
22868c2ecf20Sopenharmony_ci		}
22878c2ecf20Sopenharmony_ci	} else if (recv_cq) {
22888c2ecf20Sopenharmony_ci		__release(&send_cq->lock);
22898c2ecf20Sopenharmony_ci		spin_unlock(&recv_cq->lock);
22908c2ecf20Sopenharmony_ci	} else {
22918c2ecf20Sopenharmony_ci		__release(&recv_cq->lock);
22928c2ecf20Sopenharmony_ci		__release(&send_cq->lock);
22938c2ecf20Sopenharmony_ci	}
22948c2ecf20Sopenharmony_ci}
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_cistatic void get_cqs(enum ib_qp_type qp_type,
22978c2ecf20Sopenharmony_ci		    struct ib_cq *ib_send_cq, struct ib_cq *ib_recv_cq,
22988c2ecf20Sopenharmony_ci		    struct mlx5_ib_cq **send_cq, struct mlx5_ib_cq **recv_cq)
22998c2ecf20Sopenharmony_ci{
23008c2ecf20Sopenharmony_ci	switch (qp_type) {
23018c2ecf20Sopenharmony_ci	case IB_QPT_XRC_TGT:
23028c2ecf20Sopenharmony_ci		*send_cq = NULL;
23038c2ecf20Sopenharmony_ci		*recv_cq = NULL;
23048c2ecf20Sopenharmony_ci		break;
23058c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_REG_UMR:
23068c2ecf20Sopenharmony_ci	case IB_QPT_XRC_INI:
23078c2ecf20Sopenharmony_ci		*send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL;
23088c2ecf20Sopenharmony_ci		*recv_cq = NULL;
23098c2ecf20Sopenharmony_ci		break;
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	case IB_QPT_SMI:
23128c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_HW_GSI:
23138c2ecf20Sopenharmony_ci	case IB_QPT_RC:
23148c2ecf20Sopenharmony_ci	case IB_QPT_UC:
23158c2ecf20Sopenharmony_ci	case IB_QPT_UD:
23168c2ecf20Sopenharmony_ci	case IB_QPT_RAW_PACKET:
23178c2ecf20Sopenharmony_ci		*send_cq = ib_send_cq ? to_mcq(ib_send_cq) : NULL;
23188c2ecf20Sopenharmony_ci		*recv_cq = ib_recv_cq ? to_mcq(ib_recv_cq) : NULL;
23198c2ecf20Sopenharmony_ci		break;
23208c2ecf20Sopenharmony_ci	default:
23218c2ecf20Sopenharmony_ci		*send_cq = NULL;
23228c2ecf20Sopenharmony_ci		*recv_cq = NULL;
23238c2ecf20Sopenharmony_ci		break;
23248c2ecf20Sopenharmony_ci	}
23258c2ecf20Sopenharmony_ci}
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_cistatic int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
23288c2ecf20Sopenharmony_ci				const struct mlx5_modify_raw_qp_param *raw_qp_param,
23298c2ecf20Sopenharmony_ci				u8 lag_tx_affinity);
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_cistatic void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
23328c2ecf20Sopenharmony_ci			      struct ib_udata *udata)
23338c2ecf20Sopenharmony_ci{
23348c2ecf20Sopenharmony_ci	struct mlx5_ib_cq *send_cq, *recv_cq;
23358c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base;
23368c2ecf20Sopenharmony_ci	unsigned long flags;
23378c2ecf20Sopenharmony_ci	int err;
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	if (qp->is_rss) {
23408c2ecf20Sopenharmony_ci		destroy_rss_raw_qp_tir(dev, qp);
23418c2ecf20Sopenharmony_ci		return;
23428c2ecf20Sopenharmony_ci	}
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	base = (qp->type == IB_QPT_RAW_PACKET ||
23458c2ecf20Sopenharmony_ci		qp->flags & IB_QP_CREATE_SOURCE_QPN) ?
23468c2ecf20Sopenharmony_ci		       &qp->raw_packet_qp.rq.base :
23478c2ecf20Sopenharmony_ci		       &qp->trans_qp.base;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	if (qp->state != IB_QPS_RESET) {
23508c2ecf20Sopenharmony_ci		if (qp->type != IB_QPT_RAW_PACKET &&
23518c2ecf20Sopenharmony_ci		    !(qp->flags & IB_QP_CREATE_SOURCE_QPN)) {
23528c2ecf20Sopenharmony_ci			err = mlx5_core_qp_modify(dev, MLX5_CMD_OP_2RST_QP, 0,
23538c2ecf20Sopenharmony_ci						  NULL, &base->mqp, NULL);
23548c2ecf20Sopenharmony_ci		} else {
23558c2ecf20Sopenharmony_ci			struct mlx5_modify_raw_qp_param raw_qp_param = {
23568c2ecf20Sopenharmony_ci				.operation = MLX5_CMD_OP_2RST_QP
23578c2ecf20Sopenharmony_ci			};
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci			err = modify_raw_packet_qp(dev, qp, &raw_qp_param, 0);
23608c2ecf20Sopenharmony_ci		}
23618c2ecf20Sopenharmony_ci		if (err)
23628c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "mlx5_ib: modify QP 0x%06x to RESET failed\n",
23638c2ecf20Sopenharmony_ci				     base->mqp.qpn);
23648c2ecf20Sopenharmony_ci	}
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	get_cqs(qp->type, qp->ibqp.send_cq, qp->ibqp.recv_cq, &send_cq,
23678c2ecf20Sopenharmony_ci		&recv_cq);
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
23708c2ecf20Sopenharmony_ci	mlx5_ib_lock_cqs(send_cq, recv_cq);
23718c2ecf20Sopenharmony_ci	/* del from lists under both locks above to protect reset flow paths */
23728c2ecf20Sopenharmony_ci	list_del(&qp->qps_list);
23738c2ecf20Sopenharmony_ci	if (send_cq)
23748c2ecf20Sopenharmony_ci		list_del(&qp->cq_send_list);
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	if (recv_cq)
23778c2ecf20Sopenharmony_ci		list_del(&qp->cq_recv_list);
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	if (!udata) {
23808c2ecf20Sopenharmony_ci		__mlx5_ib_cq_clean(recv_cq, base->mqp.qpn,
23818c2ecf20Sopenharmony_ci				   qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
23828c2ecf20Sopenharmony_ci		if (send_cq != recv_cq)
23838c2ecf20Sopenharmony_ci			__mlx5_ib_cq_clean(send_cq, base->mqp.qpn,
23848c2ecf20Sopenharmony_ci					   NULL);
23858c2ecf20Sopenharmony_ci	}
23868c2ecf20Sopenharmony_ci	mlx5_ib_unlock_cqs(send_cq, recv_cq);
23878c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	if (qp->type == IB_QPT_RAW_PACKET ||
23908c2ecf20Sopenharmony_ci	    qp->flags & IB_QP_CREATE_SOURCE_QPN) {
23918c2ecf20Sopenharmony_ci		destroy_raw_packet_qp(dev, qp);
23928c2ecf20Sopenharmony_ci	} else {
23938c2ecf20Sopenharmony_ci		err = mlx5_core_destroy_qp(dev, &base->mqp);
23948c2ecf20Sopenharmony_ci		if (err)
23958c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "failed to destroy QP 0x%x\n",
23968c2ecf20Sopenharmony_ci				     base->mqp.qpn);
23978c2ecf20Sopenharmony_ci	}
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	destroy_qp(dev, qp, base, udata);
24008c2ecf20Sopenharmony_ci}
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_cistatic int create_dct(struct mlx5_ib_dev *dev, struct ib_pd *pd,
24038c2ecf20Sopenharmony_ci		      struct mlx5_ib_qp *qp,
24048c2ecf20Sopenharmony_ci		      struct mlx5_create_qp_params *params)
24058c2ecf20Sopenharmony_ci{
24068c2ecf20Sopenharmony_ci	struct ib_qp_init_attr *attr = params->attr;
24078c2ecf20Sopenharmony_ci	struct mlx5_ib_create_qp *ucmd = params->ucmd;
24088c2ecf20Sopenharmony_ci	u32 uidx = params->uidx;
24098c2ecf20Sopenharmony_ci	void *dctc;
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	if (mlx5_lag_is_active(dev->mdev) && !MLX5_CAP_GEN(dev->mdev, lag_dct))
24128c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	qp->dct.in = kzalloc(MLX5_ST_SZ_BYTES(create_dct_in), GFP_KERNEL);
24158c2ecf20Sopenharmony_ci	if (!qp->dct.in)
24168c2ecf20Sopenharmony_ci		return -ENOMEM;
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	MLX5_SET(create_dct_in, qp->dct.in, uid, to_mpd(pd)->uid);
24198c2ecf20Sopenharmony_ci	dctc = MLX5_ADDR_OF(create_dct_in, qp->dct.in, dct_context_entry);
24208c2ecf20Sopenharmony_ci	MLX5_SET(dctc, dctc, pd, to_mpd(pd)->pdn);
24218c2ecf20Sopenharmony_ci	MLX5_SET(dctc, dctc, srqn_xrqn, to_msrq(attr->srq)->msrq.srqn);
24228c2ecf20Sopenharmony_ci	MLX5_SET(dctc, dctc, cqn, to_mcq(attr->recv_cq)->mcq.cqn);
24238c2ecf20Sopenharmony_ci	MLX5_SET64(dctc, dctc, dc_access_key, ucmd->access_key);
24248c2ecf20Sopenharmony_ci	MLX5_SET(dctc, dctc, user_index, uidx);
24258c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(dev->mdev, ece_support))
24268c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, ece, ucmd->ece_options);
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	if (qp->flags_en & MLX5_QP_FLAG_SCATTER_CQE) {
24298c2ecf20Sopenharmony_ci		int rcqe_sz = mlx5_ib_get_cqe_size(attr->recv_cq);
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci		if (rcqe_sz == 128)
24328c2ecf20Sopenharmony_ci			MLX5_SET(dctc, dctc, cs_res, MLX5_RES_SCAT_DATA64_CQE);
24338c2ecf20Sopenharmony_ci	}
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci	qp->state = IB_QPS_RESET;
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	return 0;
24388c2ecf20Sopenharmony_ci}
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_cistatic int check_qp_type(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr,
24418c2ecf20Sopenharmony_ci			 enum ib_qp_type *type)
24428c2ecf20Sopenharmony_ci{
24438c2ecf20Sopenharmony_ci	if (attr->qp_type == IB_QPT_DRIVER && !MLX5_CAP_GEN(dev->mdev, dct))
24448c2ecf20Sopenharmony_ci		goto out;
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci	switch (attr->qp_type) {
24478c2ecf20Sopenharmony_ci	case IB_QPT_XRC_TGT:
24488c2ecf20Sopenharmony_ci	case IB_QPT_XRC_INI:
24498c2ecf20Sopenharmony_ci		if (!MLX5_CAP_GEN(dev->mdev, xrc))
24508c2ecf20Sopenharmony_ci			goto out;
24518c2ecf20Sopenharmony_ci		fallthrough;
24528c2ecf20Sopenharmony_ci	case IB_QPT_RC:
24538c2ecf20Sopenharmony_ci	case IB_QPT_UC:
24548c2ecf20Sopenharmony_ci	case IB_QPT_SMI:
24558c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_HW_GSI:
24568c2ecf20Sopenharmony_ci	case IB_QPT_DRIVER:
24578c2ecf20Sopenharmony_ci	case IB_QPT_GSI:
24588c2ecf20Sopenharmony_ci	case IB_QPT_RAW_PACKET:
24598c2ecf20Sopenharmony_ci	case IB_QPT_UD:
24608c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_REG_UMR:
24618c2ecf20Sopenharmony_ci		break;
24628c2ecf20Sopenharmony_ci	default:
24638c2ecf20Sopenharmony_ci		goto out;
24648c2ecf20Sopenharmony_ci	}
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	*type = attr->qp_type;
24678c2ecf20Sopenharmony_ci	return 0;
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ciout:
24708c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "Unsupported QP type %d\n", attr->qp_type);
24718c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
24728c2ecf20Sopenharmony_ci}
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_cistatic int check_valid_flow(struct mlx5_ib_dev *dev, struct ib_pd *pd,
24758c2ecf20Sopenharmony_ci			    struct ib_qp_init_attr *attr,
24768c2ecf20Sopenharmony_ci			    struct ib_udata *udata)
24778c2ecf20Sopenharmony_ci{
24788c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context(
24798c2ecf20Sopenharmony_ci		udata, struct mlx5_ib_ucontext, ibucontext);
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_ci	if (!udata) {
24828c2ecf20Sopenharmony_ci		/* Kernel create_qp callers */
24838c2ecf20Sopenharmony_ci		if (attr->rwq_ind_tbl)
24848c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci		switch (attr->qp_type) {
24878c2ecf20Sopenharmony_ci		case IB_QPT_RAW_PACKET:
24888c2ecf20Sopenharmony_ci		case IB_QPT_DRIVER:
24898c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
24908c2ecf20Sopenharmony_ci		default:
24918c2ecf20Sopenharmony_ci			return 0;
24928c2ecf20Sopenharmony_ci		}
24938c2ecf20Sopenharmony_ci	}
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci	/* Userspace create_qp callers */
24968c2ecf20Sopenharmony_ci	if (attr->qp_type == IB_QPT_RAW_PACKET && !ucontext->cqe_version) {
24978c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev,
24988c2ecf20Sopenharmony_ci			"Raw Packet QP is only supported for CQE version > 0\n");
24998c2ecf20Sopenharmony_ci		return -EINVAL;
25008c2ecf20Sopenharmony_ci	}
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci	if (attr->qp_type != IB_QPT_RAW_PACKET && attr->rwq_ind_tbl) {
25038c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev,
25048c2ecf20Sopenharmony_ci			    "Wrong QP type %d for the RWQ indirect table\n",
25058c2ecf20Sopenharmony_ci			    attr->qp_type);
25068c2ecf20Sopenharmony_ci		return -EINVAL;
25078c2ecf20Sopenharmony_ci	}
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci	/*
25108c2ecf20Sopenharmony_ci	 * We don't need to see this warning, it means that kernel code
25118c2ecf20Sopenharmony_ci	 * missing ib_pd. Placed here to catch developer's mistakes.
25128c2ecf20Sopenharmony_ci	 */
25138c2ecf20Sopenharmony_ci	WARN_ONCE(!pd && attr->qp_type != IB_QPT_XRC_TGT,
25148c2ecf20Sopenharmony_ci		  "There is a missing PD pointer assignment\n");
25158c2ecf20Sopenharmony_ci	return 0;
25168c2ecf20Sopenharmony_ci}
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_cistatic void process_vendor_flag(struct mlx5_ib_dev *dev, int *flags, int flag,
25198c2ecf20Sopenharmony_ci				bool cond, struct mlx5_ib_qp *qp)
25208c2ecf20Sopenharmony_ci{
25218c2ecf20Sopenharmony_ci	if (!(*flags & flag))
25228c2ecf20Sopenharmony_ci		return;
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci	if (cond) {
25258c2ecf20Sopenharmony_ci		qp->flags_en |= flag;
25268c2ecf20Sopenharmony_ci		*flags &= ~flag;
25278c2ecf20Sopenharmony_ci		return;
25288c2ecf20Sopenharmony_ci	}
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci	switch (flag) {
25318c2ecf20Sopenharmony_ci	case MLX5_QP_FLAG_SCATTER_CQE:
25328c2ecf20Sopenharmony_ci	case MLX5_QP_FLAG_ALLOW_SCATTER_CQE:
25338c2ecf20Sopenharmony_ci		/*
25348c2ecf20Sopenharmony_ci			 * We don't return error if these flags were provided,
25358c2ecf20Sopenharmony_ci			 * and mlx5 doesn't have right capability.
25368c2ecf20Sopenharmony_ci			 */
25378c2ecf20Sopenharmony_ci		*flags &= ~(MLX5_QP_FLAG_SCATTER_CQE |
25388c2ecf20Sopenharmony_ci			    MLX5_QP_FLAG_ALLOW_SCATTER_CQE);
25398c2ecf20Sopenharmony_ci		return;
25408c2ecf20Sopenharmony_ci	default:
25418c2ecf20Sopenharmony_ci		break;
25428c2ecf20Sopenharmony_ci	}
25438c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "Vendor create QP flag 0x%X is not supported\n", flag);
25448c2ecf20Sopenharmony_ci}
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_cistatic int process_vendor_flags(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
25478c2ecf20Sopenharmony_ci				void *ucmd, struct ib_qp_init_attr *attr)
25488c2ecf20Sopenharmony_ci{
25498c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
25508c2ecf20Sopenharmony_ci	bool cond;
25518c2ecf20Sopenharmony_ci	int flags;
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	if (attr->rwq_ind_tbl)
25548c2ecf20Sopenharmony_ci		flags = ((struct mlx5_ib_create_qp_rss *)ucmd)->flags;
25558c2ecf20Sopenharmony_ci	else
25568c2ecf20Sopenharmony_ci		flags = ((struct mlx5_ib_create_qp *)ucmd)->flags;
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci	switch (flags & (MLX5_QP_FLAG_TYPE_DCT | MLX5_QP_FLAG_TYPE_DCI)) {
25598c2ecf20Sopenharmony_ci	case MLX5_QP_FLAG_TYPE_DCI:
25608c2ecf20Sopenharmony_ci		qp->type = MLX5_IB_QPT_DCI;
25618c2ecf20Sopenharmony_ci		break;
25628c2ecf20Sopenharmony_ci	case MLX5_QP_FLAG_TYPE_DCT:
25638c2ecf20Sopenharmony_ci		qp->type = MLX5_IB_QPT_DCT;
25648c2ecf20Sopenharmony_ci		break;
25658c2ecf20Sopenharmony_ci	default:
25668c2ecf20Sopenharmony_ci		if (qp->type != IB_QPT_DRIVER)
25678c2ecf20Sopenharmony_ci			break;
25688c2ecf20Sopenharmony_ci		/*
25698c2ecf20Sopenharmony_ci		 * It is IB_QPT_DRIVER and or no subtype or
25708c2ecf20Sopenharmony_ci		 * wrong subtype were provided.
25718c2ecf20Sopenharmony_ci		 */
25728c2ecf20Sopenharmony_ci		return -EINVAL;
25738c2ecf20Sopenharmony_ci	}
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	process_vendor_flag(dev, &flags, MLX5_QP_FLAG_TYPE_DCI, true, qp);
25768c2ecf20Sopenharmony_ci	process_vendor_flag(dev, &flags, MLX5_QP_FLAG_TYPE_DCT, true, qp);
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	process_vendor_flag(dev, &flags, MLX5_QP_FLAG_SIGNATURE, true, qp);
25798c2ecf20Sopenharmony_ci	process_vendor_flag(dev, &flags, MLX5_QP_FLAG_SCATTER_CQE,
25808c2ecf20Sopenharmony_ci			    MLX5_CAP_GEN(mdev, sctr_data_cqe), qp);
25818c2ecf20Sopenharmony_ci	process_vendor_flag(dev, &flags, MLX5_QP_FLAG_ALLOW_SCATTER_CQE,
25828c2ecf20Sopenharmony_ci			    MLX5_CAP_GEN(mdev, sctr_data_cqe), qp);
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	if (qp->type == IB_QPT_RAW_PACKET) {
25858c2ecf20Sopenharmony_ci		cond = MLX5_CAP_ETH(mdev, tunnel_stateless_vxlan) ||
25868c2ecf20Sopenharmony_ci		       MLX5_CAP_ETH(mdev, tunnel_stateless_gre) ||
25878c2ecf20Sopenharmony_ci		       MLX5_CAP_ETH(mdev, tunnel_stateless_geneve_rx);
25888c2ecf20Sopenharmony_ci		process_vendor_flag(dev, &flags, MLX5_QP_FLAG_TUNNEL_OFFLOADS,
25898c2ecf20Sopenharmony_ci				    cond, qp);
25908c2ecf20Sopenharmony_ci		process_vendor_flag(dev, &flags,
25918c2ecf20Sopenharmony_ci				    MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC, true,
25928c2ecf20Sopenharmony_ci				    qp);
25938c2ecf20Sopenharmony_ci		process_vendor_flag(dev, &flags,
25948c2ecf20Sopenharmony_ci				    MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC, true,
25958c2ecf20Sopenharmony_ci				    qp);
25968c2ecf20Sopenharmony_ci	}
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci	if (qp->type == IB_QPT_RC)
25998c2ecf20Sopenharmony_ci		process_vendor_flag(dev, &flags,
26008c2ecf20Sopenharmony_ci				    MLX5_QP_FLAG_PACKET_BASED_CREDIT_MODE,
26018c2ecf20Sopenharmony_ci				    MLX5_CAP_GEN(mdev, qp_packet_based), qp);
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci	process_vendor_flag(dev, &flags, MLX5_QP_FLAG_BFREG_INDEX, true, qp);
26048c2ecf20Sopenharmony_ci	process_vendor_flag(dev, &flags, MLX5_QP_FLAG_UAR_PAGE_INDEX, true, qp);
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	cond = qp->flags_en & ~(MLX5_QP_FLAG_TUNNEL_OFFLOADS |
26078c2ecf20Sopenharmony_ci				MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC |
26088c2ecf20Sopenharmony_ci				MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC);
26098c2ecf20Sopenharmony_ci	if (attr->rwq_ind_tbl && cond) {
26108c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "RSS RAW QP has unsupported flags 0x%X\n",
26118c2ecf20Sopenharmony_ci			    cond);
26128c2ecf20Sopenharmony_ci		return -EINVAL;
26138c2ecf20Sopenharmony_ci	}
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	if (flags)
26168c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "udata has unsupported flags 0x%X\n", flags);
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci	return (flags) ? -EINVAL : 0;
26198c2ecf20Sopenharmony_ci	}
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_cistatic void process_create_flag(struct mlx5_ib_dev *dev, int *flags, int flag,
26228c2ecf20Sopenharmony_ci				bool cond, struct mlx5_ib_qp *qp)
26238c2ecf20Sopenharmony_ci{
26248c2ecf20Sopenharmony_ci	if (!(*flags & flag))
26258c2ecf20Sopenharmony_ci		return;
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	if (cond) {
26288c2ecf20Sopenharmony_ci		qp->flags |= flag;
26298c2ecf20Sopenharmony_ci		*flags &= ~flag;
26308c2ecf20Sopenharmony_ci		return;
26318c2ecf20Sopenharmony_ci	}
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci	if (flag == MLX5_IB_QP_CREATE_WC_TEST) {
26348c2ecf20Sopenharmony_ci		/*
26358c2ecf20Sopenharmony_ci		 * Special case, if condition didn't meet, it won't be error,
26368c2ecf20Sopenharmony_ci		 * just different in-kernel flow.
26378c2ecf20Sopenharmony_ci		 */
26388c2ecf20Sopenharmony_ci		*flags &= ~MLX5_IB_QP_CREATE_WC_TEST;
26398c2ecf20Sopenharmony_ci		return;
26408c2ecf20Sopenharmony_ci	}
26418c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev, "Verbs create QP flag 0x%X is not supported\n", flag);
26428c2ecf20Sopenharmony_ci}
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_cistatic int process_create_flags(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
26458c2ecf20Sopenharmony_ci				struct ib_qp_init_attr *attr)
26468c2ecf20Sopenharmony_ci{
26478c2ecf20Sopenharmony_ci	enum ib_qp_type qp_type = qp->type;
26488c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
26498c2ecf20Sopenharmony_ci	int create_flags = attr->create_flags;
26508c2ecf20Sopenharmony_ci	bool cond;
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci	if (qp_type == MLX5_IB_QPT_DCT)
26538c2ecf20Sopenharmony_ci		return (create_flags) ? -EINVAL : 0;
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci	if (qp_type == IB_QPT_RAW_PACKET && attr->rwq_ind_tbl)
26568c2ecf20Sopenharmony_ci		return (create_flags) ? -EINVAL : 0;
26578c2ecf20Sopenharmony_ci
26588c2ecf20Sopenharmony_ci	process_create_flag(dev, &create_flags, IB_QP_CREATE_NETIF_QP,
26598c2ecf20Sopenharmony_ci			    mlx5_get_flow_namespace(dev->mdev,
26608c2ecf20Sopenharmony_ci						    MLX5_FLOW_NAMESPACE_BYPASS),
26618c2ecf20Sopenharmony_ci			    qp);
26628c2ecf20Sopenharmony_ci	process_create_flag(dev, &create_flags,
26638c2ecf20Sopenharmony_ci			    IB_QP_CREATE_INTEGRITY_EN,
26648c2ecf20Sopenharmony_ci			    MLX5_CAP_GEN(mdev, sho), qp);
26658c2ecf20Sopenharmony_ci	process_create_flag(dev, &create_flags,
26668c2ecf20Sopenharmony_ci			    IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK,
26678c2ecf20Sopenharmony_ci			    MLX5_CAP_GEN(mdev, block_lb_mc), qp);
26688c2ecf20Sopenharmony_ci	process_create_flag(dev, &create_flags, IB_QP_CREATE_CROSS_CHANNEL,
26698c2ecf20Sopenharmony_ci			    MLX5_CAP_GEN(mdev, cd), qp);
26708c2ecf20Sopenharmony_ci	process_create_flag(dev, &create_flags, IB_QP_CREATE_MANAGED_SEND,
26718c2ecf20Sopenharmony_ci			    MLX5_CAP_GEN(mdev, cd), qp);
26728c2ecf20Sopenharmony_ci	process_create_flag(dev, &create_flags, IB_QP_CREATE_MANAGED_RECV,
26738c2ecf20Sopenharmony_ci			    MLX5_CAP_GEN(mdev, cd), qp);
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_ci	if (qp_type == IB_QPT_UD) {
26768c2ecf20Sopenharmony_ci		process_create_flag(dev, &create_flags,
26778c2ecf20Sopenharmony_ci				    IB_QP_CREATE_IPOIB_UD_LSO,
26788c2ecf20Sopenharmony_ci				    MLX5_CAP_GEN(mdev, ipoib_basic_offloads),
26798c2ecf20Sopenharmony_ci				    qp);
26808c2ecf20Sopenharmony_ci		cond = MLX5_CAP_GEN(mdev, port_type) == MLX5_CAP_PORT_TYPE_IB;
26818c2ecf20Sopenharmony_ci		process_create_flag(dev, &create_flags, IB_QP_CREATE_SOURCE_QPN,
26828c2ecf20Sopenharmony_ci				    cond, qp);
26838c2ecf20Sopenharmony_ci	}
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci	if (qp_type == IB_QPT_RAW_PACKET) {
26868c2ecf20Sopenharmony_ci		cond = MLX5_CAP_GEN(mdev, eth_net_offloads) &&
26878c2ecf20Sopenharmony_ci		       MLX5_CAP_ETH(mdev, scatter_fcs);
26888c2ecf20Sopenharmony_ci		process_create_flag(dev, &create_flags,
26898c2ecf20Sopenharmony_ci				    IB_QP_CREATE_SCATTER_FCS, cond, qp);
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci		cond = MLX5_CAP_GEN(mdev, eth_net_offloads) &&
26928c2ecf20Sopenharmony_ci		       MLX5_CAP_ETH(mdev, vlan_cap);
26938c2ecf20Sopenharmony_ci		process_create_flag(dev, &create_flags,
26948c2ecf20Sopenharmony_ci				    IB_QP_CREATE_CVLAN_STRIPPING, cond, qp);
26958c2ecf20Sopenharmony_ci	}
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	process_create_flag(dev, &create_flags,
26988c2ecf20Sopenharmony_ci			    IB_QP_CREATE_PCI_WRITE_END_PADDING,
26998c2ecf20Sopenharmony_ci			    MLX5_CAP_GEN(mdev, end_pad), qp);
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	process_create_flag(dev, &create_flags, MLX5_IB_QP_CREATE_WC_TEST,
27028c2ecf20Sopenharmony_ci			    qp_type != MLX5_IB_QPT_REG_UMR, qp);
27038c2ecf20Sopenharmony_ci	process_create_flag(dev, &create_flags, MLX5_IB_QP_CREATE_SQPN_QP1,
27048c2ecf20Sopenharmony_ci			    true, qp);
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_ci	if (create_flags)
27078c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "Create QP has unsupported flags 0x%X\n",
27088c2ecf20Sopenharmony_ci			    create_flags);
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci	return (create_flags) ? -EINVAL : 0;
27118c2ecf20Sopenharmony_ci}
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_cistatic int process_udata_size(struct mlx5_ib_dev *dev,
27148c2ecf20Sopenharmony_ci			      struct mlx5_create_qp_params *params)
27158c2ecf20Sopenharmony_ci{
27168c2ecf20Sopenharmony_ci	size_t ucmd = sizeof(struct mlx5_ib_create_qp);
27178c2ecf20Sopenharmony_ci	struct ib_udata *udata = params->udata;
27188c2ecf20Sopenharmony_ci	size_t outlen = udata->outlen;
27198c2ecf20Sopenharmony_ci	size_t inlen = udata->inlen;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	params->outlen = min(outlen, sizeof(struct mlx5_ib_create_qp_resp));
27228c2ecf20Sopenharmony_ci	params->ucmd_size = ucmd;
27238c2ecf20Sopenharmony_ci	if (!params->is_rss_raw) {
27248c2ecf20Sopenharmony_ci		/* User has old rdma-core, which doesn't support ECE */
27258c2ecf20Sopenharmony_ci		size_t min_inlen =
27268c2ecf20Sopenharmony_ci			offsetof(struct mlx5_ib_create_qp, ece_options);
27278c2ecf20Sopenharmony_ci
27288c2ecf20Sopenharmony_ci		/*
27298c2ecf20Sopenharmony_ci		 * We will check in check_ucmd_data() that user
27308c2ecf20Sopenharmony_ci		 * cleared everything after inlen.
27318c2ecf20Sopenharmony_ci		 */
27328c2ecf20Sopenharmony_ci		params->inlen = (inlen < min_inlen) ? 0 : min(inlen, ucmd);
27338c2ecf20Sopenharmony_ci		goto out;
27348c2ecf20Sopenharmony_ci	}
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_ci	/* RSS RAW QP */
27378c2ecf20Sopenharmony_ci	if (inlen < offsetofend(struct mlx5_ib_create_qp_rss, flags))
27388c2ecf20Sopenharmony_ci		return -EINVAL;
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci	if (outlen < offsetofend(struct mlx5_ib_create_qp_resp, bfreg_index))
27418c2ecf20Sopenharmony_ci		return -EINVAL;
27428c2ecf20Sopenharmony_ci
27438c2ecf20Sopenharmony_ci	ucmd = sizeof(struct mlx5_ib_create_qp_rss);
27448c2ecf20Sopenharmony_ci	params->ucmd_size = ucmd;
27458c2ecf20Sopenharmony_ci	if (inlen > ucmd && !ib_is_udata_cleared(udata, ucmd, inlen - ucmd))
27468c2ecf20Sopenharmony_ci		return -EINVAL;
27478c2ecf20Sopenharmony_ci
27488c2ecf20Sopenharmony_ci	params->inlen = min(ucmd, inlen);
27498c2ecf20Sopenharmony_ciout:
27508c2ecf20Sopenharmony_ci	if (!params->inlen)
27518c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "udata is too small\n");
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	return (params->inlen) ? 0 : -EINVAL;
27548c2ecf20Sopenharmony_ci}
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_cistatic int create_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
27578c2ecf20Sopenharmony_ci		     struct mlx5_ib_qp *qp,
27588c2ecf20Sopenharmony_ci		     struct mlx5_create_qp_params *params)
27598c2ecf20Sopenharmony_ci{
27608c2ecf20Sopenharmony_ci	int err;
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci	if (params->is_rss_raw) {
27638c2ecf20Sopenharmony_ci		err = create_rss_raw_qp_tir(dev, pd, qp, params);
27648c2ecf20Sopenharmony_ci		goto out;
27658c2ecf20Sopenharmony_ci	}
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	switch (qp->type) {
27688c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_DCT:
27698c2ecf20Sopenharmony_ci		err = create_dct(dev, pd, qp, params);
27708c2ecf20Sopenharmony_ci		break;
27718c2ecf20Sopenharmony_ci	case IB_QPT_XRC_TGT:
27728c2ecf20Sopenharmony_ci		err = create_xrc_tgt_qp(dev, qp, params);
27738c2ecf20Sopenharmony_ci		break;
27748c2ecf20Sopenharmony_ci	case IB_QPT_GSI:
27758c2ecf20Sopenharmony_ci		err = mlx5_ib_create_gsi(pd, qp, params->attr);
27768c2ecf20Sopenharmony_ci		break;
27778c2ecf20Sopenharmony_ci	default:
27788c2ecf20Sopenharmony_ci		if (params->udata)
27798c2ecf20Sopenharmony_ci			err = create_user_qp(dev, pd, qp, params);
27808c2ecf20Sopenharmony_ci		else
27818c2ecf20Sopenharmony_ci			err = create_kernel_qp(dev, pd, qp, params);
27828c2ecf20Sopenharmony_ci	}
27838c2ecf20Sopenharmony_ci
27848c2ecf20Sopenharmony_ciout:
27858c2ecf20Sopenharmony_ci	if (err) {
27868c2ecf20Sopenharmony_ci		mlx5_ib_err(dev, "Create QP type %d failed\n", qp->type);
27878c2ecf20Sopenharmony_ci		return err;
27888c2ecf20Sopenharmony_ci	}
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_ci	if (is_qp0(qp->type))
27918c2ecf20Sopenharmony_ci		qp->ibqp.qp_num = 0;
27928c2ecf20Sopenharmony_ci	else if (is_qp1(qp->type))
27938c2ecf20Sopenharmony_ci		qp->ibqp.qp_num = 1;
27948c2ecf20Sopenharmony_ci	else
27958c2ecf20Sopenharmony_ci		qp->ibqp.qp_num = qp->trans_qp.base.mqp.qpn;
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	mlx5_ib_dbg(dev,
27988c2ecf20Sopenharmony_ci		"QP type %d, ib qpn 0x%X, mlx qpn 0x%x, rcqn 0x%x, scqn 0x%x, ece 0x%x\n",
27998c2ecf20Sopenharmony_ci		qp->type, qp->ibqp.qp_num, qp->trans_qp.base.mqp.qpn,
28008c2ecf20Sopenharmony_ci		params->attr->recv_cq ? to_mcq(params->attr->recv_cq)->mcq.cqn :
28018c2ecf20Sopenharmony_ci					-1,
28028c2ecf20Sopenharmony_ci		params->attr->send_cq ? to_mcq(params->attr->send_cq)->mcq.cqn :
28038c2ecf20Sopenharmony_ci					-1,
28048c2ecf20Sopenharmony_ci		params->resp.ece_options);
28058c2ecf20Sopenharmony_ci
28068c2ecf20Sopenharmony_ci	return 0;
28078c2ecf20Sopenharmony_ci}
28088c2ecf20Sopenharmony_ci
28098c2ecf20Sopenharmony_cistatic int check_qp_attr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
28108c2ecf20Sopenharmony_ci			 struct ib_qp_init_attr *attr)
28118c2ecf20Sopenharmony_ci{
28128c2ecf20Sopenharmony_ci	int ret = 0;
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci	switch (qp->type) {
28158c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_DCT:
28168c2ecf20Sopenharmony_ci		ret = (!attr->srq || !attr->recv_cq) ? -EINVAL : 0;
28178c2ecf20Sopenharmony_ci		break;
28188c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_DCI:
28198c2ecf20Sopenharmony_ci		ret = (attr->cap.max_recv_wr || attr->cap.max_recv_sge) ?
28208c2ecf20Sopenharmony_ci			      -EINVAL :
28218c2ecf20Sopenharmony_ci			      0;
28228c2ecf20Sopenharmony_ci		break;
28238c2ecf20Sopenharmony_ci	case IB_QPT_RAW_PACKET:
28248c2ecf20Sopenharmony_ci		ret = (attr->rwq_ind_tbl && attr->send_cq) ? -EINVAL : 0;
28258c2ecf20Sopenharmony_ci		break;
28268c2ecf20Sopenharmony_ci	default:
28278c2ecf20Sopenharmony_ci		break;
28288c2ecf20Sopenharmony_ci	}
28298c2ecf20Sopenharmony_ci
28308c2ecf20Sopenharmony_ci	if (ret)
28318c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "QP type %d has wrong attributes\n", qp->type);
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	return ret;
28348c2ecf20Sopenharmony_ci}
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_cistatic int get_qp_uidx(struct mlx5_ib_qp *qp,
28378c2ecf20Sopenharmony_ci		       struct mlx5_create_qp_params *params)
28388c2ecf20Sopenharmony_ci{
28398c2ecf20Sopenharmony_ci	struct mlx5_ib_create_qp *ucmd = params->ucmd;
28408c2ecf20Sopenharmony_ci	struct ib_udata *udata = params->udata;
28418c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context(
28428c2ecf20Sopenharmony_ci		udata, struct mlx5_ib_ucontext, ibucontext);
28438c2ecf20Sopenharmony_ci
28448c2ecf20Sopenharmony_ci	if (params->is_rss_raw)
28458c2ecf20Sopenharmony_ci		return 0;
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci	return get_qp_user_index(ucontext, ucmd, sizeof(*ucmd), &params->uidx);
28488c2ecf20Sopenharmony_ci}
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_cistatic int mlx5_ib_destroy_dct(struct mlx5_ib_qp *mqp)
28518c2ecf20Sopenharmony_ci{
28528c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(mqp->ibqp.device);
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	if (mqp->state == IB_QPS_RTR) {
28558c2ecf20Sopenharmony_ci		int err;
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci		err = mlx5_core_destroy_dct(dev, &mqp->dct.mdct);
28588c2ecf20Sopenharmony_ci		if (err) {
28598c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "failed to destroy DCT %d\n", err);
28608c2ecf20Sopenharmony_ci			return err;
28618c2ecf20Sopenharmony_ci		}
28628c2ecf20Sopenharmony_ci	}
28638c2ecf20Sopenharmony_ci
28648c2ecf20Sopenharmony_ci	kfree(mqp->dct.in);
28658c2ecf20Sopenharmony_ci	kfree(mqp);
28668c2ecf20Sopenharmony_ci	return 0;
28678c2ecf20Sopenharmony_ci}
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_cistatic int check_ucmd_data(struct mlx5_ib_dev *dev,
28708c2ecf20Sopenharmony_ci			   struct mlx5_create_qp_params *params)
28718c2ecf20Sopenharmony_ci{
28728c2ecf20Sopenharmony_ci	struct ib_udata *udata = params->udata;
28738c2ecf20Sopenharmony_ci	size_t size, last;
28748c2ecf20Sopenharmony_ci	int ret;
28758c2ecf20Sopenharmony_ci
28768c2ecf20Sopenharmony_ci	if (params->is_rss_raw)
28778c2ecf20Sopenharmony_ci		/*
28788c2ecf20Sopenharmony_ci		 * These QPs don't have "reserved" field in their
28798c2ecf20Sopenharmony_ci		 * create_qp input struct, so their data is always valid.
28808c2ecf20Sopenharmony_ci		 */
28818c2ecf20Sopenharmony_ci		last = sizeof(struct mlx5_ib_create_qp_rss);
28828c2ecf20Sopenharmony_ci	else
28838c2ecf20Sopenharmony_ci		last = offsetof(struct mlx5_ib_create_qp, reserved);
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci	if (udata->inlen <= last)
28868c2ecf20Sopenharmony_ci		return 0;
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_ci	/*
28898c2ecf20Sopenharmony_ci	 * User provides different create_qp structures based on the
28908c2ecf20Sopenharmony_ci	 * flow and we need to know if he cleared memory after our
28918c2ecf20Sopenharmony_ci	 * struct create_qp ends.
28928c2ecf20Sopenharmony_ci	 */
28938c2ecf20Sopenharmony_ci	size = udata->inlen - last;
28948c2ecf20Sopenharmony_ci	ret = ib_is_udata_cleared(params->udata, last, size);
28958c2ecf20Sopenharmony_ci	if (!ret)
28968c2ecf20Sopenharmony_ci		mlx5_ib_dbg(
28978c2ecf20Sopenharmony_ci			dev,
28988c2ecf20Sopenharmony_ci			"udata is not cleared, inlen = %zu, ucmd = %zu, last = %zu, size = %zu\n",
28998c2ecf20Sopenharmony_ci			udata->inlen, params->ucmd_size, last, size);
29008c2ecf20Sopenharmony_ci	return ret ? 0 : -EINVAL;
29018c2ecf20Sopenharmony_ci}
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_cistruct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attr,
29048c2ecf20Sopenharmony_ci				struct ib_udata *udata)
29058c2ecf20Sopenharmony_ci{
29068c2ecf20Sopenharmony_ci	struct mlx5_create_qp_params params = {};
29078c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev;
29088c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *qp;
29098c2ecf20Sopenharmony_ci	enum ib_qp_type type;
29108c2ecf20Sopenharmony_ci	int err;
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_ci	dev = pd ? to_mdev(pd->device) :
29138c2ecf20Sopenharmony_ci		   to_mdev(to_mxrcd(attr->xrcd)->ibxrcd.device);
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci	err = check_qp_type(dev, attr, &type);
29168c2ecf20Sopenharmony_ci	if (err)
29178c2ecf20Sopenharmony_ci		return ERR_PTR(err);
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_ci	err = check_valid_flow(dev, pd, attr, udata);
29208c2ecf20Sopenharmony_ci	if (err)
29218c2ecf20Sopenharmony_ci		return ERR_PTR(err);
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci	params.udata = udata;
29248c2ecf20Sopenharmony_ci	params.uidx = MLX5_IB_DEFAULT_UIDX;
29258c2ecf20Sopenharmony_ci	params.attr = attr;
29268c2ecf20Sopenharmony_ci	params.is_rss_raw = !!attr->rwq_ind_tbl;
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci	if (udata) {
29298c2ecf20Sopenharmony_ci		err = process_udata_size(dev, &params);
29308c2ecf20Sopenharmony_ci		if (err)
29318c2ecf20Sopenharmony_ci			return ERR_PTR(err);
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci		err = check_ucmd_data(dev, &params);
29348c2ecf20Sopenharmony_ci		if (err)
29358c2ecf20Sopenharmony_ci			return ERR_PTR(err);
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_ci		params.ucmd = kzalloc(params.ucmd_size, GFP_KERNEL);
29388c2ecf20Sopenharmony_ci		if (!params.ucmd)
29398c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOMEM);
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_ci		err = ib_copy_from_udata(params.ucmd, udata, params.inlen);
29428c2ecf20Sopenharmony_ci		if (err)
29438c2ecf20Sopenharmony_ci			goto free_ucmd;
29448c2ecf20Sopenharmony_ci	}
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_ci	qp = kzalloc(sizeof(*qp), GFP_KERNEL);
29478c2ecf20Sopenharmony_ci	if (!qp) {
29488c2ecf20Sopenharmony_ci		err = -ENOMEM;
29498c2ecf20Sopenharmony_ci		goto free_ucmd;
29508c2ecf20Sopenharmony_ci	}
29518c2ecf20Sopenharmony_ci
29528c2ecf20Sopenharmony_ci	mutex_init(&qp->mutex);
29538c2ecf20Sopenharmony_ci	qp->type = type;
29548c2ecf20Sopenharmony_ci	if (udata) {
29558c2ecf20Sopenharmony_ci		err = process_vendor_flags(dev, qp, params.ucmd, attr);
29568c2ecf20Sopenharmony_ci		if (err)
29578c2ecf20Sopenharmony_ci			goto free_qp;
29588c2ecf20Sopenharmony_ci
29598c2ecf20Sopenharmony_ci		err = get_qp_uidx(qp, &params);
29608c2ecf20Sopenharmony_ci		if (err)
29618c2ecf20Sopenharmony_ci			goto free_qp;
29628c2ecf20Sopenharmony_ci	}
29638c2ecf20Sopenharmony_ci	err = process_create_flags(dev, qp, attr);
29648c2ecf20Sopenharmony_ci	if (err)
29658c2ecf20Sopenharmony_ci		goto free_qp;
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci	err = check_qp_attr(dev, qp, attr);
29688c2ecf20Sopenharmony_ci	if (err)
29698c2ecf20Sopenharmony_ci		goto free_qp;
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	err = create_qp(dev, pd, qp, &params);
29728c2ecf20Sopenharmony_ci	if (err)
29738c2ecf20Sopenharmony_ci		goto free_qp;
29748c2ecf20Sopenharmony_ci
29758c2ecf20Sopenharmony_ci	kfree(params.ucmd);
29768c2ecf20Sopenharmony_ci	params.ucmd = NULL;
29778c2ecf20Sopenharmony_ci
29788c2ecf20Sopenharmony_ci	if (udata)
29798c2ecf20Sopenharmony_ci		/*
29808c2ecf20Sopenharmony_ci		 * It is safe to copy response for all user create QP flows,
29818c2ecf20Sopenharmony_ci		 * including MLX5_IB_QPT_DCT, which doesn't need it.
29828c2ecf20Sopenharmony_ci		 * In that case, resp will be filled with zeros.
29838c2ecf20Sopenharmony_ci		 */
29848c2ecf20Sopenharmony_ci		err = ib_copy_to_udata(udata, &params.resp, params.outlen);
29858c2ecf20Sopenharmony_ci	if (err)
29868c2ecf20Sopenharmony_ci		goto destroy_qp;
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	return &qp->ibqp;
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_cidestroy_qp:
29918c2ecf20Sopenharmony_ci	switch (qp->type) {
29928c2ecf20Sopenharmony_ci	case MLX5_IB_QPT_DCT:
29938c2ecf20Sopenharmony_ci		mlx5_ib_destroy_dct(qp);
29948c2ecf20Sopenharmony_ci		break;
29958c2ecf20Sopenharmony_ci	case IB_QPT_GSI:
29968c2ecf20Sopenharmony_ci		mlx5_ib_destroy_gsi(qp);
29978c2ecf20Sopenharmony_ci		break;
29988c2ecf20Sopenharmony_ci	default:
29998c2ecf20Sopenharmony_ci		/*
30008c2ecf20Sopenharmony_ci		 * These lines below are temp solution till QP allocation
30018c2ecf20Sopenharmony_ci		 * will be moved to be under IB/core responsiblity.
30028c2ecf20Sopenharmony_ci		 */
30038c2ecf20Sopenharmony_ci		qp->ibqp.send_cq = attr->send_cq;
30048c2ecf20Sopenharmony_ci		qp->ibqp.recv_cq = attr->recv_cq;
30058c2ecf20Sopenharmony_ci		qp->ibqp.pd = pd;
30068c2ecf20Sopenharmony_ci		destroy_qp_common(dev, qp, udata);
30078c2ecf20Sopenharmony_ci	}
30088c2ecf20Sopenharmony_ci
30098c2ecf20Sopenharmony_ci	qp = NULL;
30108c2ecf20Sopenharmony_cifree_qp:
30118c2ecf20Sopenharmony_ci	kfree(qp);
30128c2ecf20Sopenharmony_cifree_ucmd:
30138c2ecf20Sopenharmony_ci	kfree(params.ucmd);
30148c2ecf20Sopenharmony_ci	return ERR_PTR(err);
30158c2ecf20Sopenharmony_ci}
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_ciint mlx5_ib_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
30188c2ecf20Sopenharmony_ci{
30198c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(qp->device);
30208c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *mqp = to_mqp(qp);
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci	if (unlikely(qp->qp_type == IB_QPT_GSI))
30238c2ecf20Sopenharmony_ci		return mlx5_ib_destroy_gsi(mqp);
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	if (mqp->type == MLX5_IB_QPT_DCT)
30268c2ecf20Sopenharmony_ci		return mlx5_ib_destroy_dct(mqp);
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	destroy_qp_common(dev, mqp, udata);
30298c2ecf20Sopenharmony_ci
30308c2ecf20Sopenharmony_ci	kfree(mqp);
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci	return 0;
30338c2ecf20Sopenharmony_ci}
30348c2ecf20Sopenharmony_ci
30358c2ecf20Sopenharmony_cistatic int set_qpc_atomic_flags(struct mlx5_ib_qp *qp,
30368c2ecf20Sopenharmony_ci				const struct ib_qp_attr *attr, int attr_mask,
30378c2ecf20Sopenharmony_ci				void *qpc)
30388c2ecf20Sopenharmony_ci{
30398c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(qp->ibqp.device);
30408c2ecf20Sopenharmony_ci	u8 dest_rd_atomic;
30418c2ecf20Sopenharmony_ci	u32 access_flags;
30428c2ecf20Sopenharmony_ci
30438c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
30448c2ecf20Sopenharmony_ci		dest_rd_atomic = attr->max_dest_rd_atomic;
30458c2ecf20Sopenharmony_ci	else
30468c2ecf20Sopenharmony_ci		dest_rd_atomic = qp->trans_qp.resp_depth;
30478c2ecf20Sopenharmony_ci
30488c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_ACCESS_FLAGS)
30498c2ecf20Sopenharmony_ci		access_flags = attr->qp_access_flags;
30508c2ecf20Sopenharmony_ci	else
30518c2ecf20Sopenharmony_ci		access_flags = qp->trans_qp.atomic_rd_en;
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci	if (!dest_rd_atomic)
30548c2ecf20Sopenharmony_ci		access_flags &= IB_ACCESS_REMOTE_WRITE;
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, rre, !!(access_flags & IB_ACCESS_REMOTE_READ));
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci	if (access_flags & IB_ACCESS_REMOTE_ATOMIC) {
30598c2ecf20Sopenharmony_ci		int atomic_mode;
30608c2ecf20Sopenharmony_ci
30618c2ecf20Sopenharmony_ci		atomic_mode = get_atomic_mode(dev, qp->ibqp.qp_type);
30628c2ecf20Sopenharmony_ci		if (atomic_mode < 0)
30638c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, rae, 1);
30668c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, atomic_mode, atomic_mode);
30678c2ecf20Sopenharmony_ci	}
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, rwe, !!(access_flags & IB_ACCESS_REMOTE_WRITE));
30708c2ecf20Sopenharmony_ci	return 0;
30718c2ecf20Sopenharmony_ci}
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_cienum {
30748c2ecf20Sopenharmony_ci	MLX5_PATH_FLAG_FL	= 1 << 0,
30758c2ecf20Sopenharmony_ci	MLX5_PATH_FLAG_FREE_AR	= 1 << 1,
30768c2ecf20Sopenharmony_ci	MLX5_PATH_FLAG_COUNTER	= 1 << 2,
30778c2ecf20Sopenharmony_ci};
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_cistatic int mlx5_to_ib_rate_map(u8 rate)
30808c2ecf20Sopenharmony_ci{
30818c2ecf20Sopenharmony_ci	static const int rates[] = { IB_RATE_PORT_CURRENT, IB_RATE_56_GBPS,
30828c2ecf20Sopenharmony_ci				     IB_RATE_25_GBPS,	   IB_RATE_100_GBPS,
30838c2ecf20Sopenharmony_ci				     IB_RATE_200_GBPS,	   IB_RATE_50_GBPS,
30848c2ecf20Sopenharmony_ci				     IB_RATE_400_GBPS };
30858c2ecf20Sopenharmony_ci
30868c2ecf20Sopenharmony_ci	if (rate < ARRAY_SIZE(rates))
30878c2ecf20Sopenharmony_ci		return rates[rate];
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci	return rate - MLX5_STAT_RATE_OFFSET;
30908c2ecf20Sopenharmony_ci}
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_cistatic int ib_to_mlx5_rate_map(u8 rate)
30938c2ecf20Sopenharmony_ci{
30948c2ecf20Sopenharmony_ci	switch (rate) {
30958c2ecf20Sopenharmony_ci	case IB_RATE_PORT_CURRENT:
30968c2ecf20Sopenharmony_ci		return 0;
30978c2ecf20Sopenharmony_ci	case IB_RATE_56_GBPS:
30988c2ecf20Sopenharmony_ci		return 1;
30998c2ecf20Sopenharmony_ci	case IB_RATE_25_GBPS:
31008c2ecf20Sopenharmony_ci		return 2;
31018c2ecf20Sopenharmony_ci	case IB_RATE_100_GBPS:
31028c2ecf20Sopenharmony_ci		return 3;
31038c2ecf20Sopenharmony_ci	case IB_RATE_200_GBPS:
31048c2ecf20Sopenharmony_ci		return 4;
31058c2ecf20Sopenharmony_ci	case IB_RATE_50_GBPS:
31068c2ecf20Sopenharmony_ci		return 5;
31078c2ecf20Sopenharmony_ci	default:
31088c2ecf20Sopenharmony_ci		return rate + MLX5_STAT_RATE_OFFSET;
31098c2ecf20Sopenharmony_ci	};
31108c2ecf20Sopenharmony_ci
31118c2ecf20Sopenharmony_ci	return 0;
31128c2ecf20Sopenharmony_ci}
31138c2ecf20Sopenharmony_ci
31148c2ecf20Sopenharmony_cistatic int ib_rate_to_mlx5(struct mlx5_ib_dev *dev, u8 rate)
31158c2ecf20Sopenharmony_ci{
31168c2ecf20Sopenharmony_ci	u32 stat_rate_support;
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_ci	if (rate == IB_RATE_PORT_CURRENT)
31198c2ecf20Sopenharmony_ci		return 0;
31208c2ecf20Sopenharmony_ci
31218c2ecf20Sopenharmony_ci	if (rate < IB_RATE_2_5_GBPS || rate > IB_RATE_600_GBPS)
31228c2ecf20Sopenharmony_ci		return -EINVAL;
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci	stat_rate_support = MLX5_CAP_GEN(dev->mdev, stat_rate_support);
31258c2ecf20Sopenharmony_ci	while (rate != IB_RATE_PORT_CURRENT &&
31268c2ecf20Sopenharmony_ci	       !(1 << ib_to_mlx5_rate_map(rate) & stat_rate_support))
31278c2ecf20Sopenharmony_ci		--rate;
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	return ib_to_mlx5_rate_map(rate);
31308c2ecf20Sopenharmony_ci}
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_cistatic int modify_raw_packet_eth_prio(struct mlx5_core_dev *dev,
31338c2ecf20Sopenharmony_ci				      struct mlx5_ib_sq *sq, u8 sl,
31348c2ecf20Sopenharmony_ci				      struct ib_pd *pd)
31358c2ecf20Sopenharmony_ci{
31368c2ecf20Sopenharmony_ci	void *in;
31378c2ecf20Sopenharmony_ci	void *tisc;
31388c2ecf20Sopenharmony_ci	int inlen;
31398c2ecf20Sopenharmony_ci	int err;
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(modify_tis_in);
31428c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
31438c2ecf20Sopenharmony_ci	if (!in)
31448c2ecf20Sopenharmony_ci		return -ENOMEM;
31458c2ecf20Sopenharmony_ci
31468c2ecf20Sopenharmony_ci	MLX5_SET(modify_tis_in, in, bitmask.prio, 1);
31478c2ecf20Sopenharmony_ci	MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid);
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx);
31508c2ecf20Sopenharmony_ci	MLX5_SET(tisc, tisc, prio, ((sl & 0x7) << 1));
31518c2ecf20Sopenharmony_ci
31528c2ecf20Sopenharmony_ci	err = mlx5_core_modify_tis(dev, sq->tisn, in);
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci	kvfree(in);
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci	return err;
31578c2ecf20Sopenharmony_ci}
31588c2ecf20Sopenharmony_ci
31598c2ecf20Sopenharmony_cistatic int modify_raw_packet_tx_affinity(struct mlx5_core_dev *dev,
31608c2ecf20Sopenharmony_ci					 struct mlx5_ib_sq *sq, u8 tx_affinity,
31618c2ecf20Sopenharmony_ci					 struct ib_pd *pd)
31628c2ecf20Sopenharmony_ci{
31638c2ecf20Sopenharmony_ci	void *in;
31648c2ecf20Sopenharmony_ci	void *tisc;
31658c2ecf20Sopenharmony_ci	int inlen;
31668c2ecf20Sopenharmony_ci	int err;
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(modify_tis_in);
31698c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
31708c2ecf20Sopenharmony_ci	if (!in)
31718c2ecf20Sopenharmony_ci		return -ENOMEM;
31728c2ecf20Sopenharmony_ci
31738c2ecf20Sopenharmony_ci	MLX5_SET(modify_tis_in, in, bitmask.lag_tx_port_affinity, 1);
31748c2ecf20Sopenharmony_ci	MLX5_SET(modify_tis_in, in, uid, to_mpd(pd)->uid);
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	tisc = MLX5_ADDR_OF(modify_tis_in, in, ctx);
31778c2ecf20Sopenharmony_ci	MLX5_SET(tisc, tisc, lag_tx_port_affinity, tx_affinity);
31788c2ecf20Sopenharmony_ci
31798c2ecf20Sopenharmony_ci	err = mlx5_core_modify_tis(dev, sq->tisn, in);
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_ci	kvfree(in);
31828c2ecf20Sopenharmony_ci
31838c2ecf20Sopenharmony_ci	return err;
31848c2ecf20Sopenharmony_ci}
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_cistatic void mlx5_set_path_udp_sport(void *path, const struct rdma_ah_attr *ah,
31878c2ecf20Sopenharmony_ci				    u32 lqpn, u32 rqpn)
31888c2ecf20Sopenharmony_ci
31898c2ecf20Sopenharmony_ci{
31908c2ecf20Sopenharmony_ci	u32 fl = ah->grh.flow_label;
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	if (!fl)
31938c2ecf20Sopenharmony_ci		fl = rdma_calc_flow_label(lqpn, rqpn);
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci	MLX5_SET(ads, path, udp_sport, rdma_flow_label_to_udp_sport(fl));
31968c2ecf20Sopenharmony_ci}
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_cistatic int mlx5_set_path(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
31998c2ecf20Sopenharmony_ci			 const struct rdma_ah_attr *ah, void *path, u8 port,
32008c2ecf20Sopenharmony_ci			 int attr_mask, u32 path_flags,
32018c2ecf20Sopenharmony_ci			 const struct ib_qp_attr *attr, bool alt)
32028c2ecf20Sopenharmony_ci{
32038c2ecf20Sopenharmony_ci	const struct ib_global_route *grh = rdma_ah_read_grh(ah);
32048c2ecf20Sopenharmony_ci	int err;
32058c2ecf20Sopenharmony_ci	enum ib_gid_type gid_type;
32068c2ecf20Sopenharmony_ci	u8 ah_flags = rdma_ah_get_ah_flags(ah);
32078c2ecf20Sopenharmony_ci	u8 sl = rdma_ah_get_sl(ah);
32088c2ecf20Sopenharmony_ci
32098c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_PKEY_INDEX)
32108c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, pkey_index,
32118c2ecf20Sopenharmony_ci			 alt ? attr->alt_pkey_index : attr->pkey_index);
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci	if (ah_flags & IB_AH_GRH) {
32148c2ecf20Sopenharmony_ci		if (grh->sgid_index >=
32158c2ecf20Sopenharmony_ci		    dev->mdev->port_caps[port - 1].gid_table_len) {
32168c2ecf20Sopenharmony_ci			pr_err("sgid_index (%u) too large. max is %d\n",
32178c2ecf20Sopenharmony_ci			       grh->sgid_index,
32188c2ecf20Sopenharmony_ci			       dev->mdev->port_caps[port - 1].gid_table_len);
32198c2ecf20Sopenharmony_ci			return -EINVAL;
32208c2ecf20Sopenharmony_ci		}
32218c2ecf20Sopenharmony_ci	}
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_ci	if (ah->type == RDMA_AH_ATTR_TYPE_ROCE) {
32248c2ecf20Sopenharmony_ci		if (!(ah_flags & IB_AH_GRH))
32258c2ecf20Sopenharmony_ci			return -EINVAL;
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_ci		ether_addr_copy(MLX5_ADDR_OF(ads, path, rmac_47_32),
32288c2ecf20Sopenharmony_ci				ah->roce.dmac);
32298c2ecf20Sopenharmony_ci		if ((qp->ibqp.qp_type == IB_QPT_RC ||
32308c2ecf20Sopenharmony_ci		     qp->ibqp.qp_type == IB_QPT_UC ||
32318c2ecf20Sopenharmony_ci		     qp->ibqp.qp_type == IB_QPT_XRC_INI ||
32328c2ecf20Sopenharmony_ci		     qp->ibqp.qp_type == IB_QPT_XRC_TGT) &&
32338c2ecf20Sopenharmony_ci		    (grh->sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) &&
32348c2ecf20Sopenharmony_ci		    (attr_mask & IB_QP_DEST_QPN))
32358c2ecf20Sopenharmony_ci			mlx5_set_path_udp_sport(path, ah,
32368c2ecf20Sopenharmony_ci						qp->ibqp.qp_num,
32378c2ecf20Sopenharmony_ci						attr->dest_qp_num);
32388c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, eth_prio, sl & 0x7);
32398c2ecf20Sopenharmony_ci		gid_type = ah->grh.sgid_attr->gid_type;
32408c2ecf20Sopenharmony_ci		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP)
32418c2ecf20Sopenharmony_ci			MLX5_SET(ads, path, dscp, grh->traffic_class >> 2);
32428c2ecf20Sopenharmony_ci	} else {
32438c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, fl, !!(path_flags & MLX5_PATH_FLAG_FL));
32448c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, free_ar,
32458c2ecf20Sopenharmony_ci			 !!(path_flags & MLX5_PATH_FLAG_FREE_AR));
32468c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, rlid, rdma_ah_get_dlid(ah));
32478c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, mlid, rdma_ah_get_path_bits(ah));
32488c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, grh, !!(ah_flags & IB_AH_GRH));
32498c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, sl, sl);
32508c2ecf20Sopenharmony_ci	}
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_ci	if (ah_flags & IB_AH_GRH) {
32538c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, src_addr_index, grh->sgid_index);
32548c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, hop_limit, grh->hop_limit);
32558c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, tclass, grh->traffic_class);
32568c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, flow_label, grh->flow_label);
32578c2ecf20Sopenharmony_ci		memcpy(MLX5_ADDR_OF(ads, path, rgid_rip), grh->dgid.raw,
32588c2ecf20Sopenharmony_ci		       sizeof(grh->dgid.raw));
32598c2ecf20Sopenharmony_ci	}
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_ci	err = ib_rate_to_mlx5(dev, rdma_ah_get_static_rate(ah));
32628c2ecf20Sopenharmony_ci	if (err < 0)
32638c2ecf20Sopenharmony_ci		return err;
32648c2ecf20Sopenharmony_ci	MLX5_SET(ads, path, stat_rate, err);
32658c2ecf20Sopenharmony_ci	MLX5_SET(ads, path, vhca_port_num, port);
32668c2ecf20Sopenharmony_ci
32678c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_TIMEOUT)
32688c2ecf20Sopenharmony_ci		MLX5_SET(ads, path, ack_timeout,
32698c2ecf20Sopenharmony_ci			 alt ? attr->alt_timeout : attr->timeout);
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci	if ((qp->ibqp.qp_type == IB_QPT_RAW_PACKET) && qp->sq.wqe_cnt)
32728c2ecf20Sopenharmony_ci		return modify_raw_packet_eth_prio(dev->mdev,
32738c2ecf20Sopenharmony_ci						  &qp->raw_packet_qp.sq,
32748c2ecf20Sopenharmony_ci						  sl & 0xf, qp->ibqp.pd);
32758c2ecf20Sopenharmony_ci
32768c2ecf20Sopenharmony_ci	return 0;
32778c2ecf20Sopenharmony_ci}
32788c2ecf20Sopenharmony_ci
32798c2ecf20Sopenharmony_cistatic enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_QP_ST_MAX] = {
32808c2ecf20Sopenharmony_ci	[MLX5_QP_STATE_INIT] = {
32818c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_INIT] = {
32828c2ecf20Sopenharmony_ci			[MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE		|
32838c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RAE		|
32848c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE		|
32858c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PKEY_INDEX	|
32868c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PRI_PORT	|
32878c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_LAG_TX_AFF,
32888c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE		|
32898c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PKEY_INDEX	|
32908c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PRI_PORT	|
32918c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_LAG_TX_AFF,
32928c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX	|
32938c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_Q_KEY		|
32948c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PRI_PORT,
32958c2ecf20Sopenharmony_ci			[MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE		|
32968c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RAE		|
32978c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE		|
32988c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PKEY_INDEX	|
32998c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PRI_PORT	|
33008c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_LAG_TX_AFF,
33018c2ecf20Sopenharmony_ci		},
33028c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_RTR] = {
33038c2ecf20Sopenharmony_ci			[MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH  |
33048c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RRE            |
33058c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RAE            |
33068c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE            |
33078c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PKEY_INDEX	|
33088c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_LAG_TX_AFF,
33098c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH  |
33108c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE            |
33118c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PKEY_INDEX	|
33128c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_LAG_TX_AFF,
33138c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX     |
33148c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_Q_KEY,
33158c2ecf20Sopenharmony_ci			[MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_PKEY_INDEX	|
33168c2ecf20Sopenharmony_ci					   MLX5_QP_OPTPAR_Q_KEY,
33178c2ecf20Sopenharmony_ci			[MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH |
33188c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RRE            |
33198c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RAE            |
33208c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE            |
33218c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PKEY_INDEX	|
33228c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_LAG_TX_AFF,
33238c2ecf20Sopenharmony_ci		},
33248c2ecf20Sopenharmony_ci	},
33258c2ecf20Sopenharmony_ci	[MLX5_QP_STATE_RTR] = {
33268c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_RTS] = {
33278c2ecf20Sopenharmony_ci			[MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH	|
33288c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RRE		|
33298c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RAE		|
33308c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE		|
33318c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PM_STATE	|
33328c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RNR_TIMEOUT,
33338c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH	|
33348c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE		|
33358c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PM_STATE,
33368c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY,
33378c2ecf20Sopenharmony_ci			[MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH	|
33388c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RRE		|
33398c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RAE		|
33408c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE		|
33418c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PM_STATE	|
33428c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RNR_TIMEOUT,
33438c2ecf20Sopenharmony_ci		},
33448c2ecf20Sopenharmony_ci	},
33458c2ecf20Sopenharmony_ci	[MLX5_QP_STATE_RTS] = {
33468c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_RTS] = {
33478c2ecf20Sopenharmony_ci			[MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_RRE		|
33488c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RAE		|
33498c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE		|
33508c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RNR_TIMEOUT	|
33518c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PM_STATE	|
33528c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_ALT_ADDR_PATH,
33538c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UC] = MLX5_QP_OPTPAR_RWE		|
33548c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PM_STATE	|
33558c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_ALT_ADDR_PATH,
33568c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY		|
33578c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_SRQN		|
33588c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_CQN_RCV,
33598c2ecf20Sopenharmony_ci			[MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE		|
33608c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RAE		|
33618c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RWE		|
33628c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_RNR_TIMEOUT	|
33638c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_PM_STATE	|
33648c2ecf20Sopenharmony_ci					  MLX5_QP_OPTPAR_ALT_ADDR_PATH,
33658c2ecf20Sopenharmony_ci		},
33668c2ecf20Sopenharmony_ci	},
33678c2ecf20Sopenharmony_ci	[MLX5_QP_STATE_SQER] = {
33688c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_RTS] = {
33698c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UD]	 = MLX5_QP_OPTPAR_Q_KEY,
33708c2ecf20Sopenharmony_ci			[MLX5_QP_ST_MLX] = MLX5_QP_OPTPAR_Q_KEY,
33718c2ecf20Sopenharmony_ci			[MLX5_QP_ST_UC]	 = MLX5_QP_OPTPAR_RWE,
33728c2ecf20Sopenharmony_ci			[MLX5_QP_ST_RC]	 = MLX5_QP_OPTPAR_RNR_TIMEOUT	|
33738c2ecf20Sopenharmony_ci					   MLX5_QP_OPTPAR_RWE		|
33748c2ecf20Sopenharmony_ci					   MLX5_QP_OPTPAR_RAE		|
33758c2ecf20Sopenharmony_ci					   MLX5_QP_OPTPAR_RRE,
33768c2ecf20Sopenharmony_ci			[MLX5_QP_ST_XRC]  = MLX5_QP_OPTPAR_RNR_TIMEOUT	|
33778c2ecf20Sopenharmony_ci					   MLX5_QP_OPTPAR_RWE		|
33788c2ecf20Sopenharmony_ci					   MLX5_QP_OPTPAR_RAE		|
33798c2ecf20Sopenharmony_ci					   MLX5_QP_OPTPAR_RRE,
33808c2ecf20Sopenharmony_ci		},
33818c2ecf20Sopenharmony_ci	},
33828c2ecf20Sopenharmony_ci};
33838c2ecf20Sopenharmony_ci
33848c2ecf20Sopenharmony_cistatic int ib_nr_to_mlx5_nr(int ib_mask)
33858c2ecf20Sopenharmony_ci{
33868c2ecf20Sopenharmony_ci	switch (ib_mask) {
33878c2ecf20Sopenharmony_ci	case IB_QP_STATE:
33888c2ecf20Sopenharmony_ci		return 0;
33898c2ecf20Sopenharmony_ci	case IB_QP_CUR_STATE:
33908c2ecf20Sopenharmony_ci		return 0;
33918c2ecf20Sopenharmony_ci	case IB_QP_EN_SQD_ASYNC_NOTIFY:
33928c2ecf20Sopenharmony_ci		return 0;
33938c2ecf20Sopenharmony_ci	case IB_QP_ACCESS_FLAGS:
33948c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_RRE |
33958c2ecf20Sopenharmony_ci			MLX5_QP_OPTPAR_RAE;
33968c2ecf20Sopenharmony_ci	case IB_QP_PKEY_INDEX:
33978c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_PKEY_INDEX;
33988c2ecf20Sopenharmony_ci	case IB_QP_PORT:
33998c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_PRI_PORT;
34008c2ecf20Sopenharmony_ci	case IB_QP_QKEY:
34018c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_Q_KEY;
34028c2ecf20Sopenharmony_ci	case IB_QP_AV:
34038c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_PRIMARY_ADDR_PATH |
34048c2ecf20Sopenharmony_ci			MLX5_QP_OPTPAR_PRI_PORT;
34058c2ecf20Sopenharmony_ci	case IB_QP_PATH_MTU:
34068c2ecf20Sopenharmony_ci		return 0;
34078c2ecf20Sopenharmony_ci	case IB_QP_TIMEOUT:
34088c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_ACK_TIMEOUT;
34098c2ecf20Sopenharmony_ci	case IB_QP_RETRY_CNT:
34108c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_RETRY_COUNT;
34118c2ecf20Sopenharmony_ci	case IB_QP_RNR_RETRY:
34128c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_RNR_RETRY;
34138c2ecf20Sopenharmony_ci	case IB_QP_RQ_PSN:
34148c2ecf20Sopenharmony_ci		return 0;
34158c2ecf20Sopenharmony_ci	case IB_QP_MAX_QP_RD_ATOMIC:
34168c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_SRA_MAX;
34178c2ecf20Sopenharmony_ci	case IB_QP_ALT_PATH:
34188c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_ALT_ADDR_PATH;
34198c2ecf20Sopenharmony_ci	case IB_QP_MIN_RNR_TIMER:
34208c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_RNR_TIMEOUT;
34218c2ecf20Sopenharmony_ci	case IB_QP_SQ_PSN:
34228c2ecf20Sopenharmony_ci		return 0;
34238c2ecf20Sopenharmony_ci	case IB_QP_MAX_DEST_RD_ATOMIC:
34248c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_RRA_MAX | MLX5_QP_OPTPAR_RWE |
34258c2ecf20Sopenharmony_ci			MLX5_QP_OPTPAR_RRE | MLX5_QP_OPTPAR_RAE;
34268c2ecf20Sopenharmony_ci	case IB_QP_PATH_MIG_STATE:
34278c2ecf20Sopenharmony_ci		return MLX5_QP_OPTPAR_PM_STATE;
34288c2ecf20Sopenharmony_ci	case IB_QP_CAP:
34298c2ecf20Sopenharmony_ci		return 0;
34308c2ecf20Sopenharmony_ci	case IB_QP_DEST_QPN:
34318c2ecf20Sopenharmony_ci		return 0;
34328c2ecf20Sopenharmony_ci	}
34338c2ecf20Sopenharmony_ci	return 0;
34348c2ecf20Sopenharmony_ci}
34358c2ecf20Sopenharmony_ci
34368c2ecf20Sopenharmony_cistatic int ib_mask_to_mlx5_opt(int ib_mask)
34378c2ecf20Sopenharmony_ci{
34388c2ecf20Sopenharmony_ci	int result = 0;
34398c2ecf20Sopenharmony_ci	int i;
34408c2ecf20Sopenharmony_ci
34418c2ecf20Sopenharmony_ci	for (i = 0; i < 8 * sizeof(int); i++) {
34428c2ecf20Sopenharmony_ci		if ((1 << i) & ib_mask)
34438c2ecf20Sopenharmony_ci			result |= ib_nr_to_mlx5_nr(1 << i);
34448c2ecf20Sopenharmony_ci	}
34458c2ecf20Sopenharmony_ci
34468c2ecf20Sopenharmony_ci	return result;
34478c2ecf20Sopenharmony_ci}
34488c2ecf20Sopenharmony_ci
34498c2ecf20Sopenharmony_cistatic int modify_raw_packet_qp_rq(
34508c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev, struct mlx5_ib_rq *rq, int new_state,
34518c2ecf20Sopenharmony_ci	const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd)
34528c2ecf20Sopenharmony_ci{
34538c2ecf20Sopenharmony_ci	void *in;
34548c2ecf20Sopenharmony_ci	void *rqc;
34558c2ecf20Sopenharmony_ci	int inlen;
34568c2ecf20Sopenharmony_ci	int err;
34578c2ecf20Sopenharmony_ci
34588c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(modify_rq_in);
34598c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
34608c2ecf20Sopenharmony_ci	if (!in)
34618c2ecf20Sopenharmony_ci		return -ENOMEM;
34628c2ecf20Sopenharmony_ci
34638c2ecf20Sopenharmony_ci	MLX5_SET(modify_rq_in, in, rq_state, rq->state);
34648c2ecf20Sopenharmony_ci	MLX5_SET(modify_rq_in, in, uid, to_mpd(pd)->uid);
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_ci	rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
34678c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, state, new_state);
34688c2ecf20Sopenharmony_ci
34698c2ecf20Sopenharmony_ci	if (raw_qp_param->set_mask & MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID) {
34708c2ecf20Sopenharmony_ci		if (MLX5_CAP_GEN(dev->mdev, modify_rq_counter_set_id)) {
34718c2ecf20Sopenharmony_ci			MLX5_SET64(modify_rq_in, in, modify_bitmask,
34728c2ecf20Sopenharmony_ci				   MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_RQ_COUNTER_SET_ID);
34738c2ecf20Sopenharmony_ci			MLX5_SET(rqc, rqc, counter_set_id, raw_qp_param->rq_q_ctr_id);
34748c2ecf20Sopenharmony_ci		} else
34758c2ecf20Sopenharmony_ci			dev_info_once(
34768c2ecf20Sopenharmony_ci				&dev->ib_dev.dev,
34778c2ecf20Sopenharmony_ci				"RAW PACKET QP counters are not supported on current FW\n");
34788c2ecf20Sopenharmony_ci	}
34798c2ecf20Sopenharmony_ci
34808c2ecf20Sopenharmony_ci	err = mlx5_core_modify_rq(dev->mdev, rq->base.mqp.qpn, in);
34818c2ecf20Sopenharmony_ci	if (err)
34828c2ecf20Sopenharmony_ci		goto out;
34838c2ecf20Sopenharmony_ci
34848c2ecf20Sopenharmony_ci	rq->state = new_state;
34858c2ecf20Sopenharmony_ci
34868c2ecf20Sopenharmony_ciout:
34878c2ecf20Sopenharmony_ci	kvfree(in);
34888c2ecf20Sopenharmony_ci	return err;
34898c2ecf20Sopenharmony_ci}
34908c2ecf20Sopenharmony_ci
34918c2ecf20Sopenharmony_cistatic int modify_raw_packet_qp_sq(
34928c2ecf20Sopenharmony_ci	struct mlx5_core_dev *dev, struct mlx5_ib_sq *sq, int new_state,
34938c2ecf20Sopenharmony_ci	const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd)
34948c2ecf20Sopenharmony_ci{
34958c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *ibqp = sq->base.container_mibqp;
34968c2ecf20Sopenharmony_ci	struct mlx5_rate_limit old_rl = ibqp->rl;
34978c2ecf20Sopenharmony_ci	struct mlx5_rate_limit new_rl = old_rl;
34988c2ecf20Sopenharmony_ci	bool new_rate_added = false;
34998c2ecf20Sopenharmony_ci	u16 rl_index = 0;
35008c2ecf20Sopenharmony_ci	void *in;
35018c2ecf20Sopenharmony_ci	void *sqc;
35028c2ecf20Sopenharmony_ci	int inlen;
35038c2ecf20Sopenharmony_ci	int err;
35048c2ecf20Sopenharmony_ci
35058c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(modify_sq_in);
35068c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
35078c2ecf20Sopenharmony_ci	if (!in)
35088c2ecf20Sopenharmony_ci		return -ENOMEM;
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_ci	MLX5_SET(modify_sq_in, in, uid, to_mpd(pd)->uid);
35118c2ecf20Sopenharmony_ci	MLX5_SET(modify_sq_in, in, sq_state, sq->state);
35128c2ecf20Sopenharmony_ci
35138c2ecf20Sopenharmony_ci	sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
35148c2ecf20Sopenharmony_ci	MLX5_SET(sqc, sqc, state, new_state);
35158c2ecf20Sopenharmony_ci
35168c2ecf20Sopenharmony_ci	if (raw_qp_param->set_mask & MLX5_RAW_QP_RATE_LIMIT) {
35178c2ecf20Sopenharmony_ci		if (new_state != MLX5_SQC_STATE_RDY)
35188c2ecf20Sopenharmony_ci			pr_warn("%s: Rate limit can only be changed when SQ is moving to RDY\n",
35198c2ecf20Sopenharmony_ci				__func__);
35208c2ecf20Sopenharmony_ci		else
35218c2ecf20Sopenharmony_ci			new_rl = raw_qp_param->rl;
35228c2ecf20Sopenharmony_ci	}
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_ci	if (!mlx5_rl_are_equal(&old_rl, &new_rl)) {
35258c2ecf20Sopenharmony_ci		if (new_rl.rate) {
35268c2ecf20Sopenharmony_ci			err = mlx5_rl_add_rate(dev, &rl_index, &new_rl);
35278c2ecf20Sopenharmony_ci			if (err) {
35288c2ecf20Sopenharmony_ci				pr_err("Failed configuring rate limit(err %d): \
35298c2ecf20Sopenharmony_ci				       rate %u, max_burst_sz %u, typical_pkt_sz %u\n",
35308c2ecf20Sopenharmony_ci				       err, new_rl.rate, new_rl.max_burst_sz,
35318c2ecf20Sopenharmony_ci				       new_rl.typical_pkt_sz);
35328c2ecf20Sopenharmony_ci
35338c2ecf20Sopenharmony_ci				goto out;
35348c2ecf20Sopenharmony_ci			}
35358c2ecf20Sopenharmony_ci			new_rate_added = true;
35368c2ecf20Sopenharmony_ci		}
35378c2ecf20Sopenharmony_ci
35388c2ecf20Sopenharmony_ci		MLX5_SET64(modify_sq_in, in, modify_bitmask, 1);
35398c2ecf20Sopenharmony_ci		/* index 0 means no limit */
35408c2ecf20Sopenharmony_ci		MLX5_SET(sqc, sqc, packet_pacing_rate_limit_index, rl_index);
35418c2ecf20Sopenharmony_ci	}
35428c2ecf20Sopenharmony_ci
35438c2ecf20Sopenharmony_ci	err = mlx5_core_modify_sq(dev, sq->base.mqp.qpn, in);
35448c2ecf20Sopenharmony_ci	if (err) {
35458c2ecf20Sopenharmony_ci		/* Remove new rate from table if failed */
35468c2ecf20Sopenharmony_ci		if (new_rate_added)
35478c2ecf20Sopenharmony_ci			mlx5_rl_remove_rate(dev, &new_rl);
35488c2ecf20Sopenharmony_ci		goto out;
35498c2ecf20Sopenharmony_ci	}
35508c2ecf20Sopenharmony_ci
35518c2ecf20Sopenharmony_ci	/* Only remove the old rate after new rate was set */
35528c2ecf20Sopenharmony_ci	if ((old_rl.rate && !mlx5_rl_are_equal(&old_rl, &new_rl)) ||
35538c2ecf20Sopenharmony_ci	    (new_state != MLX5_SQC_STATE_RDY)) {
35548c2ecf20Sopenharmony_ci		mlx5_rl_remove_rate(dev, &old_rl);
35558c2ecf20Sopenharmony_ci		if (new_state != MLX5_SQC_STATE_RDY)
35568c2ecf20Sopenharmony_ci			memset(&new_rl, 0, sizeof(new_rl));
35578c2ecf20Sopenharmony_ci	}
35588c2ecf20Sopenharmony_ci
35598c2ecf20Sopenharmony_ci	ibqp->rl = new_rl;
35608c2ecf20Sopenharmony_ci	sq->state = new_state;
35618c2ecf20Sopenharmony_ci
35628c2ecf20Sopenharmony_ciout:
35638c2ecf20Sopenharmony_ci	kvfree(in);
35648c2ecf20Sopenharmony_ci	return err;
35658c2ecf20Sopenharmony_ci}
35668c2ecf20Sopenharmony_ci
35678c2ecf20Sopenharmony_cistatic int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
35688c2ecf20Sopenharmony_ci				const struct mlx5_modify_raw_qp_param *raw_qp_param,
35698c2ecf20Sopenharmony_ci				u8 tx_affinity)
35708c2ecf20Sopenharmony_ci{
35718c2ecf20Sopenharmony_ci	struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
35728c2ecf20Sopenharmony_ci	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
35738c2ecf20Sopenharmony_ci	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
35748c2ecf20Sopenharmony_ci	int modify_rq = !!qp->rq.wqe_cnt;
35758c2ecf20Sopenharmony_ci	int modify_sq = !!qp->sq.wqe_cnt;
35768c2ecf20Sopenharmony_ci	int rq_state;
35778c2ecf20Sopenharmony_ci	int sq_state;
35788c2ecf20Sopenharmony_ci	int err;
35798c2ecf20Sopenharmony_ci
35808c2ecf20Sopenharmony_ci	switch (raw_qp_param->operation) {
35818c2ecf20Sopenharmony_ci	case MLX5_CMD_OP_RST2INIT_QP:
35828c2ecf20Sopenharmony_ci		rq_state = MLX5_RQC_STATE_RDY;
35838c2ecf20Sopenharmony_ci		sq_state = MLX5_SQC_STATE_RST;
35848c2ecf20Sopenharmony_ci		break;
35858c2ecf20Sopenharmony_ci	case MLX5_CMD_OP_2ERR_QP:
35868c2ecf20Sopenharmony_ci		rq_state = MLX5_RQC_STATE_ERR;
35878c2ecf20Sopenharmony_ci		sq_state = MLX5_SQC_STATE_ERR;
35888c2ecf20Sopenharmony_ci		break;
35898c2ecf20Sopenharmony_ci	case MLX5_CMD_OP_2RST_QP:
35908c2ecf20Sopenharmony_ci		rq_state = MLX5_RQC_STATE_RST;
35918c2ecf20Sopenharmony_ci		sq_state = MLX5_SQC_STATE_RST;
35928c2ecf20Sopenharmony_ci		break;
35938c2ecf20Sopenharmony_ci	case MLX5_CMD_OP_RTR2RTS_QP:
35948c2ecf20Sopenharmony_ci	case MLX5_CMD_OP_RTS2RTS_QP:
35958c2ecf20Sopenharmony_ci		if (raw_qp_param->set_mask & ~MLX5_RAW_QP_RATE_LIMIT)
35968c2ecf20Sopenharmony_ci			return -EINVAL;
35978c2ecf20Sopenharmony_ci
35988c2ecf20Sopenharmony_ci		modify_rq = 0;
35998c2ecf20Sopenharmony_ci		sq_state = MLX5_SQC_STATE_RDY;
36008c2ecf20Sopenharmony_ci		break;
36018c2ecf20Sopenharmony_ci	case MLX5_CMD_OP_INIT2INIT_QP:
36028c2ecf20Sopenharmony_ci	case MLX5_CMD_OP_INIT2RTR_QP:
36038c2ecf20Sopenharmony_ci		if (raw_qp_param->set_mask)
36048c2ecf20Sopenharmony_ci			return -EINVAL;
36058c2ecf20Sopenharmony_ci		else
36068c2ecf20Sopenharmony_ci			return 0;
36078c2ecf20Sopenharmony_ci	default:
36088c2ecf20Sopenharmony_ci		WARN_ON(1);
36098c2ecf20Sopenharmony_ci		return -EINVAL;
36108c2ecf20Sopenharmony_ci	}
36118c2ecf20Sopenharmony_ci
36128c2ecf20Sopenharmony_ci	if (modify_rq) {
36138c2ecf20Sopenharmony_ci		err =  modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param,
36148c2ecf20Sopenharmony_ci					       qp->ibqp.pd);
36158c2ecf20Sopenharmony_ci		if (err)
36168c2ecf20Sopenharmony_ci			return err;
36178c2ecf20Sopenharmony_ci	}
36188c2ecf20Sopenharmony_ci
36198c2ecf20Sopenharmony_ci	if (modify_sq) {
36208c2ecf20Sopenharmony_ci		struct mlx5_flow_handle *flow_rule;
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci		if (tx_affinity) {
36238c2ecf20Sopenharmony_ci			err = modify_raw_packet_tx_affinity(dev->mdev, sq,
36248c2ecf20Sopenharmony_ci							    tx_affinity,
36258c2ecf20Sopenharmony_ci							    qp->ibqp.pd);
36268c2ecf20Sopenharmony_ci			if (err)
36278c2ecf20Sopenharmony_ci				return err;
36288c2ecf20Sopenharmony_ci		}
36298c2ecf20Sopenharmony_ci
36308c2ecf20Sopenharmony_ci		flow_rule = create_flow_rule_vport_sq(dev, sq,
36318c2ecf20Sopenharmony_ci						      raw_qp_param->port);
36328c2ecf20Sopenharmony_ci		if (IS_ERR(flow_rule))
36338c2ecf20Sopenharmony_ci			return PTR_ERR(flow_rule);
36348c2ecf20Sopenharmony_ci
36358c2ecf20Sopenharmony_ci		err = modify_raw_packet_qp_sq(dev->mdev, sq, sq_state,
36368c2ecf20Sopenharmony_ci					      raw_qp_param, qp->ibqp.pd);
36378c2ecf20Sopenharmony_ci		if (err) {
36388c2ecf20Sopenharmony_ci			if (flow_rule)
36398c2ecf20Sopenharmony_ci				mlx5_del_flow_rules(flow_rule);
36408c2ecf20Sopenharmony_ci			return err;
36418c2ecf20Sopenharmony_ci		}
36428c2ecf20Sopenharmony_ci
36438c2ecf20Sopenharmony_ci		if (flow_rule) {
36448c2ecf20Sopenharmony_ci			destroy_flow_rule_vport_sq(sq);
36458c2ecf20Sopenharmony_ci			sq->flow_rule = flow_rule;
36468c2ecf20Sopenharmony_ci		}
36478c2ecf20Sopenharmony_ci
36488c2ecf20Sopenharmony_ci		return err;
36498c2ecf20Sopenharmony_ci	}
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_ci	return 0;
36528c2ecf20Sopenharmony_ci}
36538c2ecf20Sopenharmony_ci
36548c2ecf20Sopenharmony_cistatic unsigned int get_tx_affinity_rr(struct mlx5_ib_dev *dev,
36558c2ecf20Sopenharmony_ci				       struct ib_udata *udata)
36568c2ecf20Sopenharmony_ci{
36578c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context(
36588c2ecf20Sopenharmony_ci		udata, struct mlx5_ib_ucontext, ibucontext);
36598c2ecf20Sopenharmony_ci	u8 port_num = mlx5_core_native_port_num(dev->mdev) - 1;
36608c2ecf20Sopenharmony_ci	atomic_t *tx_port_affinity;
36618c2ecf20Sopenharmony_ci
36628c2ecf20Sopenharmony_ci	if (ucontext)
36638c2ecf20Sopenharmony_ci		tx_port_affinity = &ucontext->tx_port_affinity;
36648c2ecf20Sopenharmony_ci	else
36658c2ecf20Sopenharmony_ci		tx_port_affinity = &dev->port[port_num].roce.tx_port_affinity;
36668c2ecf20Sopenharmony_ci
36678c2ecf20Sopenharmony_ci	return (unsigned int)atomic_add_return(1, tx_port_affinity) %
36688c2ecf20Sopenharmony_ci		MLX5_MAX_PORTS + 1;
36698c2ecf20Sopenharmony_ci}
36708c2ecf20Sopenharmony_ci
36718c2ecf20Sopenharmony_cistatic bool qp_supports_affinity(struct mlx5_ib_qp *qp)
36728c2ecf20Sopenharmony_ci{
36738c2ecf20Sopenharmony_ci	if ((qp->type == IB_QPT_RC) || (qp->type == IB_QPT_UD) ||
36748c2ecf20Sopenharmony_ci	    (qp->type == IB_QPT_UC) || (qp->type == IB_QPT_RAW_PACKET) ||
36758c2ecf20Sopenharmony_ci	    (qp->type == IB_QPT_XRC_INI) || (qp->type == IB_QPT_XRC_TGT) ||
36768c2ecf20Sopenharmony_ci	    (qp->type == MLX5_IB_QPT_DCI))
36778c2ecf20Sopenharmony_ci		return true;
36788c2ecf20Sopenharmony_ci	return false;
36798c2ecf20Sopenharmony_ci}
36808c2ecf20Sopenharmony_ci
36818c2ecf20Sopenharmony_cistatic unsigned int get_tx_affinity(struct ib_qp *qp,
36828c2ecf20Sopenharmony_ci				    const struct ib_qp_attr *attr,
36838c2ecf20Sopenharmony_ci				    int attr_mask, u8 init,
36848c2ecf20Sopenharmony_ci				    struct ib_udata *udata)
36858c2ecf20Sopenharmony_ci{
36868c2ecf20Sopenharmony_ci	struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context(
36878c2ecf20Sopenharmony_ci		udata, struct mlx5_ib_ucontext, ibucontext);
36888c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(qp->device);
36898c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *mqp = to_mqp(qp);
36908c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *qp_base;
36918c2ecf20Sopenharmony_ci	unsigned int tx_affinity;
36928c2ecf20Sopenharmony_ci
36938c2ecf20Sopenharmony_ci	if (!(mlx5_ib_lag_should_assign_affinity(dev) &&
36948c2ecf20Sopenharmony_ci	      qp_supports_affinity(mqp)))
36958c2ecf20Sopenharmony_ci		return 0;
36968c2ecf20Sopenharmony_ci
36978c2ecf20Sopenharmony_ci	if (mqp->flags & MLX5_IB_QP_CREATE_SQPN_QP1)
36988c2ecf20Sopenharmony_ci		tx_affinity = mqp->gsi_lag_port;
36998c2ecf20Sopenharmony_ci	else if (init)
37008c2ecf20Sopenharmony_ci		tx_affinity = get_tx_affinity_rr(dev, udata);
37018c2ecf20Sopenharmony_ci	else if ((attr_mask & IB_QP_AV) && attr->xmit_slave)
37028c2ecf20Sopenharmony_ci		tx_affinity =
37038c2ecf20Sopenharmony_ci			mlx5_lag_get_slave_port(dev->mdev, attr->xmit_slave);
37048c2ecf20Sopenharmony_ci	else
37058c2ecf20Sopenharmony_ci		return 0;
37068c2ecf20Sopenharmony_ci
37078c2ecf20Sopenharmony_ci	qp_base = &mqp->trans_qp.base;
37088c2ecf20Sopenharmony_ci	if (ucontext)
37098c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "Set tx affinity 0x%x to qpn 0x%x ucontext %p\n",
37108c2ecf20Sopenharmony_ci			    tx_affinity, qp_base->mqp.qpn, ucontext);
37118c2ecf20Sopenharmony_ci	else
37128c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "Set tx affinity 0x%x to qpn 0x%x\n",
37138c2ecf20Sopenharmony_ci			    tx_affinity, qp_base->mqp.qpn);
37148c2ecf20Sopenharmony_ci	return tx_affinity;
37158c2ecf20Sopenharmony_ci}
37168c2ecf20Sopenharmony_ci
37178c2ecf20Sopenharmony_cistatic int __mlx5_ib_qp_set_raw_qp_counter(struct mlx5_ib_qp *qp, u32 set_id,
37188c2ecf20Sopenharmony_ci					   struct mlx5_core_dev *mdev)
37198c2ecf20Sopenharmony_ci{
37208c2ecf20Sopenharmony_ci	struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
37218c2ecf20Sopenharmony_ci	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
37228c2ecf20Sopenharmony_ci	u32 in[MLX5_ST_SZ_DW(modify_rq_in)] = {};
37238c2ecf20Sopenharmony_ci	void *rqc;
37248c2ecf20Sopenharmony_ci
37258c2ecf20Sopenharmony_ci	if (!qp->rq.wqe_cnt)
37268c2ecf20Sopenharmony_ci		return 0;
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_ci	MLX5_SET(modify_rq_in, in, rq_state, rq->state);
37298c2ecf20Sopenharmony_ci	MLX5_SET(modify_rq_in, in, uid, to_mpd(qp->ibqp.pd)->uid);
37308c2ecf20Sopenharmony_ci
37318c2ecf20Sopenharmony_ci	rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
37328c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RDY);
37338c2ecf20Sopenharmony_ci
37348c2ecf20Sopenharmony_ci	MLX5_SET64(modify_rq_in, in, modify_bitmask,
37358c2ecf20Sopenharmony_ci		   MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_RQ_COUNTER_SET_ID);
37368c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, counter_set_id, set_id);
37378c2ecf20Sopenharmony_ci
37388c2ecf20Sopenharmony_ci	return mlx5_core_modify_rq(mdev, rq->base.mqp.qpn, in);
37398c2ecf20Sopenharmony_ci}
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_cistatic int __mlx5_ib_qp_set_counter(struct ib_qp *qp,
37428c2ecf20Sopenharmony_ci				    struct rdma_counter *counter)
37438c2ecf20Sopenharmony_ci{
37448c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(qp->device);
37458c2ecf20Sopenharmony_ci	u32 in[MLX5_ST_SZ_DW(rts2rts_qp_in)] = {};
37468c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *mqp = to_mqp(qp);
37478c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base;
37488c2ecf20Sopenharmony_ci	u32 set_id;
37498c2ecf20Sopenharmony_ci	u32 *qpc;
37508c2ecf20Sopenharmony_ci
37518c2ecf20Sopenharmony_ci	if (counter)
37528c2ecf20Sopenharmony_ci		set_id = counter->id;
37538c2ecf20Sopenharmony_ci	else
37548c2ecf20Sopenharmony_ci		set_id = mlx5_ib_get_counters_id(dev, mqp->port - 1);
37558c2ecf20Sopenharmony_ci
37568c2ecf20Sopenharmony_ci	if (mqp->type == IB_QPT_RAW_PACKET)
37578c2ecf20Sopenharmony_ci		return __mlx5_ib_qp_set_raw_qp_counter(mqp, set_id, dev->mdev);
37588c2ecf20Sopenharmony_ci
37598c2ecf20Sopenharmony_ci	base = &mqp->trans_qp.base;
37608c2ecf20Sopenharmony_ci	MLX5_SET(rts2rts_qp_in, in, opcode, MLX5_CMD_OP_RTS2RTS_QP);
37618c2ecf20Sopenharmony_ci	MLX5_SET(rts2rts_qp_in, in, qpn, base->mqp.qpn);
37628c2ecf20Sopenharmony_ci	MLX5_SET(rts2rts_qp_in, in, uid, base->mqp.uid);
37638c2ecf20Sopenharmony_ci	MLX5_SET(rts2rts_qp_in, in, opt_param_mask,
37648c2ecf20Sopenharmony_ci		 MLX5_QP_OPTPAR_COUNTER_SET_ID);
37658c2ecf20Sopenharmony_ci
37668c2ecf20Sopenharmony_ci	qpc = MLX5_ADDR_OF(rts2rts_qp_in, in, qpc);
37678c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, counter_set_id, set_id);
37688c2ecf20Sopenharmony_ci	return mlx5_cmd_exec_in(dev->mdev, rts2rts_qp, in);
37698c2ecf20Sopenharmony_ci}
37708c2ecf20Sopenharmony_ci
37718c2ecf20Sopenharmony_cistatic int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
37728c2ecf20Sopenharmony_ci			       const struct ib_qp_attr *attr, int attr_mask,
37738c2ecf20Sopenharmony_ci			       enum ib_qp_state cur_state,
37748c2ecf20Sopenharmony_ci			       enum ib_qp_state new_state,
37758c2ecf20Sopenharmony_ci			       const struct mlx5_ib_modify_qp *ucmd,
37768c2ecf20Sopenharmony_ci			       struct mlx5_ib_modify_qp_resp *resp,
37778c2ecf20Sopenharmony_ci			       struct ib_udata *udata)
37788c2ecf20Sopenharmony_ci{
37798c2ecf20Sopenharmony_ci	static const u16 optab[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE] = {
37808c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_RST] = {
37818c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
37828c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
37838c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_INIT]	= MLX5_CMD_OP_RST2INIT_QP,
37848c2ecf20Sopenharmony_ci		},
37858c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_INIT]  = {
37868c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
37878c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
37888c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_INIT]	= MLX5_CMD_OP_INIT2INIT_QP,
37898c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RTR]	= MLX5_CMD_OP_INIT2RTR_QP,
37908c2ecf20Sopenharmony_ci		},
37918c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_RTR]   = {
37928c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
37938c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
37948c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RTS]	= MLX5_CMD_OP_RTR2RTS_QP,
37958c2ecf20Sopenharmony_ci		},
37968c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_RTS]   = {
37978c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
37988c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
37998c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RTS]	= MLX5_CMD_OP_RTS2RTS_QP,
38008c2ecf20Sopenharmony_ci		},
38018c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_SQD] = {
38028c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
38038c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
38048c2ecf20Sopenharmony_ci		},
38058c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_SQER] = {
38068c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
38078c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
38088c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RTS]	= MLX5_CMD_OP_SQERR2RTS_QP,
38098c2ecf20Sopenharmony_ci		},
38108c2ecf20Sopenharmony_ci		[MLX5_QP_STATE_ERR] = {
38118c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_RST]	= MLX5_CMD_OP_2RST_QP,
38128c2ecf20Sopenharmony_ci			[MLX5_QP_STATE_ERR]	= MLX5_CMD_OP_2ERR_QP,
38138c2ecf20Sopenharmony_ci		}
38148c2ecf20Sopenharmony_ci	};
38158c2ecf20Sopenharmony_ci
38168c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
38178c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *qp = to_mqp(ibqp);
38188c2ecf20Sopenharmony_ci	struct mlx5_ib_qp_base *base = &qp->trans_qp.base;
38198c2ecf20Sopenharmony_ci	struct mlx5_ib_cq *send_cq, *recv_cq;
38208c2ecf20Sopenharmony_ci	struct mlx5_ib_pd *pd;
38218c2ecf20Sopenharmony_ci	enum mlx5_qp_state mlx5_cur, mlx5_new;
38228c2ecf20Sopenharmony_ci	void *qpc, *pri_path, *alt_path;
38238c2ecf20Sopenharmony_ci	enum mlx5_qp_optpar optpar = 0;
38248c2ecf20Sopenharmony_ci	u32 set_id = 0;
38258c2ecf20Sopenharmony_ci	int mlx5_st;
38268c2ecf20Sopenharmony_ci	int err;
38278c2ecf20Sopenharmony_ci	u16 op;
38288c2ecf20Sopenharmony_ci	u8 tx_affinity = 0;
38298c2ecf20Sopenharmony_ci
38308c2ecf20Sopenharmony_ci	mlx5_st = to_mlx5_st(qp->type);
38318c2ecf20Sopenharmony_ci	if (mlx5_st < 0)
38328c2ecf20Sopenharmony_ci		return -EINVAL;
38338c2ecf20Sopenharmony_ci
38348c2ecf20Sopenharmony_ci	qpc = kzalloc(MLX5_ST_SZ_BYTES(qpc), GFP_KERNEL);
38358c2ecf20Sopenharmony_ci	if (!qpc)
38368c2ecf20Sopenharmony_ci		return -ENOMEM;
38378c2ecf20Sopenharmony_ci
38388c2ecf20Sopenharmony_ci	pd = to_mpd(qp->ibqp.pd);
38398c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, st, mlx5_st);
38408c2ecf20Sopenharmony_ci
38418c2ecf20Sopenharmony_ci	if (!(attr_mask & IB_QP_PATH_MIG_STATE)) {
38428c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
38438c2ecf20Sopenharmony_ci	} else {
38448c2ecf20Sopenharmony_ci		switch (attr->path_mig_state) {
38458c2ecf20Sopenharmony_ci		case IB_MIG_MIGRATED:
38468c2ecf20Sopenharmony_ci			MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
38478c2ecf20Sopenharmony_ci			break;
38488c2ecf20Sopenharmony_ci		case IB_MIG_REARM:
38498c2ecf20Sopenharmony_ci			MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_REARM);
38508c2ecf20Sopenharmony_ci			break;
38518c2ecf20Sopenharmony_ci		case IB_MIG_ARMED:
38528c2ecf20Sopenharmony_ci			MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_ARMED);
38538c2ecf20Sopenharmony_ci			break;
38548c2ecf20Sopenharmony_ci		}
38558c2ecf20Sopenharmony_ci	}
38568c2ecf20Sopenharmony_ci
38578c2ecf20Sopenharmony_ci	tx_affinity = get_tx_affinity(ibqp, attr, attr_mask,
38588c2ecf20Sopenharmony_ci				      cur_state == IB_QPS_RESET &&
38598c2ecf20Sopenharmony_ci				      new_state == IB_QPS_INIT, udata);
38608c2ecf20Sopenharmony_ci
38618c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, lag_tx_port_affinity, tx_affinity);
38628c2ecf20Sopenharmony_ci	if (tx_affinity && new_state == IB_QPS_RTR &&
38638c2ecf20Sopenharmony_ci	    MLX5_CAP_GEN(dev->mdev, init2_lag_tx_port_affinity))
38648c2ecf20Sopenharmony_ci		optpar |= MLX5_QP_OPTPAR_LAG_TX_AFF;
38658c2ecf20Sopenharmony_ci
38668c2ecf20Sopenharmony_ci	if (is_sqp(ibqp->qp_type)) {
38678c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, mtu, IB_MTU_256);
38688c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_msg_max, 8);
38698c2ecf20Sopenharmony_ci	} else if ((ibqp->qp_type == IB_QPT_UD &&
38708c2ecf20Sopenharmony_ci		    !(qp->flags & IB_QP_CREATE_SOURCE_QPN)) ||
38718c2ecf20Sopenharmony_ci		   ibqp->qp_type == MLX5_IB_QPT_REG_UMR) {
38728c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, mtu, IB_MTU_4096);
38738c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_msg_max, 12);
38748c2ecf20Sopenharmony_ci	} else if (attr_mask & IB_QP_PATH_MTU) {
38758c2ecf20Sopenharmony_ci		if (attr->path_mtu < IB_MTU_256 ||
38768c2ecf20Sopenharmony_ci		    attr->path_mtu > IB_MTU_4096) {
38778c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "invalid mtu %d\n", attr->path_mtu);
38788c2ecf20Sopenharmony_ci			err = -EINVAL;
38798c2ecf20Sopenharmony_ci			goto out;
38808c2ecf20Sopenharmony_ci		}
38818c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, mtu, attr->path_mtu);
38828c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_msg_max,
38838c2ecf20Sopenharmony_ci			 MLX5_CAP_GEN(dev->mdev, log_max_msg));
38848c2ecf20Sopenharmony_ci	}
38858c2ecf20Sopenharmony_ci
38868c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_DEST_QPN)
38878c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, remote_qpn, attr->dest_qp_num);
38888c2ecf20Sopenharmony_ci
38898c2ecf20Sopenharmony_ci	pri_path = MLX5_ADDR_OF(qpc, qpc, primary_address_path);
38908c2ecf20Sopenharmony_ci	alt_path = MLX5_ADDR_OF(qpc, qpc, secondary_address_path);
38918c2ecf20Sopenharmony_ci
38928c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_PKEY_INDEX)
38938c2ecf20Sopenharmony_ci		MLX5_SET(ads, pri_path, pkey_index, attr->pkey_index);
38948c2ecf20Sopenharmony_ci
38958c2ecf20Sopenharmony_ci	/* todo implement counter_index functionality */
38968c2ecf20Sopenharmony_ci
38978c2ecf20Sopenharmony_ci	if (is_sqp(ibqp->qp_type))
38988c2ecf20Sopenharmony_ci		MLX5_SET(ads, pri_path, vhca_port_num, qp->port);
38998c2ecf20Sopenharmony_ci
39008c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_PORT)
39018c2ecf20Sopenharmony_ci		MLX5_SET(ads, pri_path, vhca_port_num, attr->port_num);
39028c2ecf20Sopenharmony_ci
39038c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_AV) {
39048c2ecf20Sopenharmony_ci		err = mlx5_set_path(dev, qp, &attr->ah_attr, pri_path,
39058c2ecf20Sopenharmony_ci				    attr_mask & IB_QP_PORT ? attr->port_num :
39068c2ecf20Sopenharmony_ci							     qp->port,
39078c2ecf20Sopenharmony_ci				    attr_mask, 0, attr, false);
39088c2ecf20Sopenharmony_ci		if (err)
39098c2ecf20Sopenharmony_ci			goto out;
39108c2ecf20Sopenharmony_ci	}
39118c2ecf20Sopenharmony_ci
39128c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_TIMEOUT)
39138c2ecf20Sopenharmony_ci		MLX5_SET(ads, pri_path, ack_timeout, attr->timeout);
39148c2ecf20Sopenharmony_ci
39158c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_ALT_PATH) {
39168c2ecf20Sopenharmony_ci		err = mlx5_set_path(dev, qp, &attr->alt_ah_attr, alt_path,
39178c2ecf20Sopenharmony_ci				    attr->alt_port_num,
39188c2ecf20Sopenharmony_ci				    attr_mask | IB_QP_PKEY_INDEX |
39198c2ecf20Sopenharmony_ci					    IB_QP_TIMEOUT,
39208c2ecf20Sopenharmony_ci				    0, attr, true);
39218c2ecf20Sopenharmony_ci		if (err)
39228c2ecf20Sopenharmony_ci			goto out;
39238c2ecf20Sopenharmony_ci	}
39248c2ecf20Sopenharmony_ci
39258c2ecf20Sopenharmony_ci	get_cqs(qp->ibqp.qp_type, qp->ibqp.send_cq, qp->ibqp.recv_cq,
39268c2ecf20Sopenharmony_ci		&send_cq, &recv_cq);
39278c2ecf20Sopenharmony_ci
39288c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, pd, pd ? pd->pdn : to_mpd(dev->devr.p0)->pdn);
39298c2ecf20Sopenharmony_ci	if (send_cq)
39308c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cqn_snd, send_cq->mcq.cqn);
39318c2ecf20Sopenharmony_ci	if (recv_cq)
39328c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, cqn_rcv, recv_cq->mcq.cqn);
39338c2ecf20Sopenharmony_ci
39348c2ecf20Sopenharmony_ci	MLX5_SET(qpc, qpc, log_ack_req_freq, MLX5_IB_ACK_REQ_FREQ);
39358c2ecf20Sopenharmony_ci
39368c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_RNR_RETRY)
39378c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, rnr_retry, attr->rnr_retry);
39388c2ecf20Sopenharmony_ci
39398c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_RETRY_CNT)
39408c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, retry_count, attr->retry_cnt);
39418c2ecf20Sopenharmony_ci
39428c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && attr->max_rd_atomic)
39438c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_sra_max, ilog2(attr->max_rd_atomic));
39448c2ecf20Sopenharmony_ci
39458c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_SQ_PSN)
39468c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, next_send_psn, attr->sq_psn);
39478c2ecf20Sopenharmony_ci
39488c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && attr->max_dest_rd_atomic)
39498c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, log_rra_max,
39508c2ecf20Sopenharmony_ci			 ilog2(attr->max_dest_rd_atomic));
39518c2ecf20Sopenharmony_ci
39528c2ecf20Sopenharmony_ci	if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) {
39538c2ecf20Sopenharmony_ci		err = set_qpc_atomic_flags(qp, attr, attr_mask, qpc);
39548c2ecf20Sopenharmony_ci		if (err)
39558c2ecf20Sopenharmony_ci			goto out;
39568c2ecf20Sopenharmony_ci	}
39578c2ecf20Sopenharmony_ci
39588c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_MIN_RNR_TIMER)
39598c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, min_rnr_nak, attr->min_rnr_timer);
39608c2ecf20Sopenharmony_ci
39618c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_RQ_PSN)
39628c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, next_rcv_psn, attr->rq_psn);
39638c2ecf20Sopenharmony_ci
39648c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_QKEY)
39658c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, q_key, attr->qkey);
39668c2ecf20Sopenharmony_ci
39678c2ecf20Sopenharmony_ci	if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
39688c2ecf20Sopenharmony_ci		MLX5_SET64(qpc, qpc, dbr_addr, qp->db.dma);
39698c2ecf20Sopenharmony_ci
39708c2ecf20Sopenharmony_ci	if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
39718c2ecf20Sopenharmony_ci		u8 port_num = (attr_mask & IB_QP_PORT ? attr->port_num :
39728c2ecf20Sopenharmony_ci			       qp->port) - 1;
39738c2ecf20Sopenharmony_ci
39748c2ecf20Sopenharmony_ci		/* Underlay port should be used - index 0 function per port */
39758c2ecf20Sopenharmony_ci		if (qp->flags & IB_QP_CREATE_SOURCE_QPN)
39768c2ecf20Sopenharmony_ci			port_num = 0;
39778c2ecf20Sopenharmony_ci
39788c2ecf20Sopenharmony_ci		if (ibqp->counter)
39798c2ecf20Sopenharmony_ci			set_id = ibqp->counter->id;
39808c2ecf20Sopenharmony_ci		else
39818c2ecf20Sopenharmony_ci			set_id = mlx5_ib_get_counters_id(dev, port_num);
39828c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, counter_set_id, set_id);
39838c2ecf20Sopenharmony_ci	}
39848c2ecf20Sopenharmony_ci
39858c2ecf20Sopenharmony_ci	if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT)
39868c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, rlky, 1);
39878c2ecf20Sopenharmony_ci
39888c2ecf20Sopenharmony_ci	if (qp->flags & MLX5_IB_QP_CREATE_SQPN_QP1)
39898c2ecf20Sopenharmony_ci		MLX5_SET(qpc, qpc, deth_sqpn, 1);
39908c2ecf20Sopenharmony_ci
39918c2ecf20Sopenharmony_ci	mlx5_cur = to_mlx5_state(cur_state);
39928c2ecf20Sopenharmony_ci	mlx5_new = to_mlx5_state(new_state);
39938c2ecf20Sopenharmony_ci
39948c2ecf20Sopenharmony_ci	if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE ||
39958c2ecf20Sopenharmony_ci	    !optab[mlx5_cur][mlx5_new]) {
39968c2ecf20Sopenharmony_ci		err = -EINVAL;
39978c2ecf20Sopenharmony_ci		goto out;
39988c2ecf20Sopenharmony_ci	}
39998c2ecf20Sopenharmony_ci
40008c2ecf20Sopenharmony_ci	op = optab[mlx5_cur][mlx5_new];
40018c2ecf20Sopenharmony_ci	optpar |= ib_mask_to_mlx5_opt(attr_mask);
40028c2ecf20Sopenharmony_ci	optpar &= opt_mask[mlx5_cur][mlx5_new][mlx5_st];
40038c2ecf20Sopenharmony_ci
40048c2ecf20Sopenharmony_ci	if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET ||
40058c2ecf20Sopenharmony_ci	    qp->flags & IB_QP_CREATE_SOURCE_QPN) {
40068c2ecf20Sopenharmony_ci		struct mlx5_modify_raw_qp_param raw_qp_param = {};
40078c2ecf20Sopenharmony_ci
40088c2ecf20Sopenharmony_ci		raw_qp_param.operation = op;
40098c2ecf20Sopenharmony_ci		if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
40108c2ecf20Sopenharmony_ci			raw_qp_param.rq_q_ctr_id = set_id;
40118c2ecf20Sopenharmony_ci			raw_qp_param.set_mask |= MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID;
40128c2ecf20Sopenharmony_ci		}
40138c2ecf20Sopenharmony_ci
40148c2ecf20Sopenharmony_ci		if (attr_mask & IB_QP_PORT)
40158c2ecf20Sopenharmony_ci			raw_qp_param.port = attr->port_num;
40168c2ecf20Sopenharmony_ci
40178c2ecf20Sopenharmony_ci		if (attr_mask & IB_QP_RATE_LIMIT) {
40188c2ecf20Sopenharmony_ci			raw_qp_param.rl.rate = attr->rate_limit;
40198c2ecf20Sopenharmony_ci
40208c2ecf20Sopenharmony_ci			if (ucmd->burst_info.max_burst_sz) {
40218c2ecf20Sopenharmony_ci				if (attr->rate_limit &&
40228c2ecf20Sopenharmony_ci				    MLX5_CAP_QOS(dev->mdev, packet_pacing_burst_bound)) {
40238c2ecf20Sopenharmony_ci					raw_qp_param.rl.max_burst_sz =
40248c2ecf20Sopenharmony_ci						ucmd->burst_info.max_burst_sz;
40258c2ecf20Sopenharmony_ci				} else {
40268c2ecf20Sopenharmony_ci					err = -EINVAL;
40278c2ecf20Sopenharmony_ci					goto out;
40288c2ecf20Sopenharmony_ci				}
40298c2ecf20Sopenharmony_ci			}
40308c2ecf20Sopenharmony_ci
40318c2ecf20Sopenharmony_ci			if (ucmd->burst_info.typical_pkt_sz) {
40328c2ecf20Sopenharmony_ci				if (attr->rate_limit &&
40338c2ecf20Sopenharmony_ci				    MLX5_CAP_QOS(dev->mdev, packet_pacing_typical_size)) {
40348c2ecf20Sopenharmony_ci					raw_qp_param.rl.typical_pkt_sz =
40358c2ecf20Sopenharmony_ci						ucmd->burst_info.typical_pkt_sz;
40368c2ecf20Sopenharmony_ci				} else {
40378c2ecf20Sopenharmony_ci					err = -EINVAL;
40388c2ecf20Sopenharmony_ci					goto out;
40398c2ecf20Sopenharmony_ci				}
40408c2ecf20Sopenharmony_ci			}
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_ci			raw_qp_param.set_mask |= MLX5_RAW_QP_RATE_LIMIT;
40438c2ecf20Sopenharmony_ci		}
40448c2ecf20Sopenharmony_ci
40458c2ecf20Sopenharmony_ci		err = modify_raw_packet_qp(dev, qp, &raw_qp_param, tx_affinity);
40468c2ecf20Sopenharmony_ci	} else {
40478c2ecf20Sopenharmony_ci		if (udata) {
40488c2ecf20Sopenharmony_ci			/* For the kernel flows, the resp will stay zero */
40498c2ecf20Sopenharmony_ci			resp->ece_options =
40508c2ecf20Sopenharmony_ci				MLX5_CAP_GEN(dev->mdev, ece_support) ?
40518c2ecf20Sopenharmony_ci					ucmd->ece_options : 0;
40528c2ecf20Sopenharmony_ci			resp->response_length = sizeof(*resp);
40538c2ecf20Sopenharmony_ci		}
40548c2ecf20Sopenharmony_ci		err = mlx5_core_qp_modify(dev, op, optpar, qpc, &base->mqp,
40558c2ecf20Sopenharmony_ci					  &resp->ece_options);
40568c2ecf20Sopenharmony_ci	}
40578c2ecf20Sopenharmony_ci
40588c2ecf20Sopenharmony_ci	if (err)
40598c2ecf20Sopenharmony_ci		goto out;
40608c2ecf20Sopenharmony_ci
40618c2ecf20Sopenharmony_ci	qp->state = new_state;
40628c2ecf20Sopenharmony_ci
40638c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_ACCESS_FLAGS)
40648c2ecf20Sopenharmony_ci		qp->trans_qp.atomic_rd_en = attr->qp_access_flags;
40658c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
40668c2ecf20Sopenharmony_ci		qp->trans_qp.resp_depth = attr->max_dest_rd_atomic;
40678c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_PORT)
40688c2ecf20Sopenharmony_ci		qp->port = attr->port_num;
40698c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_ALT_PATH)
40708c2ecf20Sopenharmony_ci		qp->trans_qp.alt_port = attr->alt_port_num;
40718c2ecf20Sopenharmony_ci
40728c2ecf20Sopenharmony_ci	/*
40738c2ecf20Sopenharmony_ci	 * If we moved a kernel QP to RESET, clean up all old CQ
40748c2ecf20Sopenharmony_ci	 * entries and reinitialize the QP.
40758c2ecf20Sopenharmony_ci	 */
40768c2ecf20Sopenharmony_ci	if (new_state == IB_QPS_RESET &&
40778c2ecf20Sopenharmony_ci	    !ibqp->uobject && ibqp->qp_type != IB_QPT_XRC_TGT) {
40788c2ecf20Sopenharmony_ci		mlx5_ib_cq_clean(recv_cq, base->mqp.qpn,
40798c2ecf20Sopenharmony_ci				 ibqp->srq ? to_msrq(ibqp->srq) : NULL);
40808c2ecf20Sopenharmony_ci		if (send_cq != recv_cq)
40818c2ecf20Sopenharmony_ci			mlx5_ib_cq_clean(send_cq, base->mqp.qpn, NULL);
40828c2ecf20Sopenharmony_ci
40838c2ecf20Sopenharmony_ci		qp->rq.head = 0;
40848c2ecf20Sopenharmony_ci		qp->rq.tail = 0;
40858c2ecf20Sopenharmony_ci		qp->sq.head = 0;
40868c2ecf20Sopenharmony_ci		qp->sq.tail = 0;
40878c2ecf20Sopenharmony_ci		qp->sq.cur_post = 0;
40888c2ecf20Sopenharmony_ci		if (qp->sq.wqe_cnt)
40898c2ecf20Sopenharmony_ci			qp->sq.cur_edge = get_sq_edge(&qp->sq, 0);
40908c2ecf20Sopenharmony_ci		qp->sq.last_poll = 0;
40918c2ecf20Sopenharmony_ci		qp->db.db[MLX5_RCV_DBR] = 0;
40928c2ecf20Sopenharmony_ci		qp->db.db[MLX5_SND_DBR] = 0;
40938c2ecf20Sopenharmony_ci	}
40948c2ecf20Sopenharmony_ci
40958c2ecf20Sopenharmony_ci	if ((new_state == IB_QPS_RTS) && qp->counter_pending) {
40968c2ecf20Sopenharmony_ci		err = __mlx5_ib_qp_set_counter(ibqp, ibqp->counter);
40978c2ecf20Sopenharmony_ci		if (!err)
40988c2ecf20Sopenharmony_ci			qp->counter_pending = 0;
40998c2ecf20Sopenharmony_ci	}
41008c2ecf20Sopenharmony_ci
41018c2ecf20Sopenharmony_ciout:
41028c2ecf20Sopenharmony_ci	kfree(qpc);
41038c2ecf20Sopenharmony_ci	return err;
41048c2ecf20Sopenharmony_ci}
41058c2ecf20Sopenharmony_ci
41068c2ecf20Sopenharmony_cistatic inline bool is_valid_mask(int mask, int req, int opt)
41078c2ecf20Sopenharmony_ci{
41088c2ecf20Sopenharmony_ci	if ((mask & req) != req)
41098c2ecf20Sopenharmony_ci		return false;
41108c2ecf20Sopenharmony_ci
41118c2ecf20Sopenharmony_ci	if (mask & ~(req | opt))
41128c2ecf20Sopenharmony_ci		return false;
41138c2ecf20Sopenharmony_ci
41148c2ecf20Sopenharmony_ci	return true;
41158c2ecf20Sopenharmony_ci}
41168c2ecf20Sopenharmony_ci
41178c2ecf20Sopenharmony_ci/* check valid transition for driver QP types
41188c2ecf20Sopenharmony_ci * for now the only QP type that this function supports is DCI
41198c2ecf20Sopenharmony_ci */
41208c2ecf20Sopenharmony_cistatic bool modify_dci_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state new_state,
41218c2ecf20Sopenharmony_ci				enum ib_qp_attr_mask attr_mask)
41228c2ecf20Sopenharmony_ci{
41238c2ecf20Sopenharmony_ci	int req = IB_QP_STATE;
41248c2ecf20Sopenharmony_ci	int opt = 0;
41258c2ecf20Sopenharmony_ci
41268c2ecf20Sopenharmony_ci	if (new_state == IB_QPS_RESET) {
41278c2ecf20Sopenharmony_ci		return is_valid_mask(attr_mask, req, opt);
41288c2ecf20Sopenharmony_ci	} else if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
41298c2ecf20Sopenharmony_ci		req |= IB_QP_PKEY_INDEX | IB_QP_PORT;
41308c2ecf20Sopenharmony_ci		return is_valid_mask(attr_mask, req, opt);
41318c2ecf20Sopenharmony_ci	} else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_INIT) {
41328c2ecf20Sopenharmony_ci		opt = IB_QP_PKEY_INDEX | IB_QP_PORT;
41338c2ecf20Sopenharmony_ci		return is_valid_mask(attr_mask, req, opt);
41348c2ecf20Sopenharmony_ci	} else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
41358c2ecf20Sopenharmony_ci		req |= IB_QP_PATH_MTU;
41368c2ecf20Sopenharmony_ci		opt = IB_QP_PKEY_INDEX | IB_QP_AV;
41378c2ecf20Sopenharmony_ci		return is_valid_mask(attr_mask, req, opt);
41388c2ecf20Sopenharmony_ci	} else if (cur_state == IB_QPS_RTR && new_state == IB_QPS_RTS) {
41398c2ecf20Sopenharmony_ci		req |= IB_QP_TIMEOUT | IB_QP_RETRY_CNT | IB_QP_RNR_RETRY |
41408c2ecf20Sopenharmony_ci		       IB_QP_MAX_QP_RD_ATOMIC | IB_QP_SQ_PSN;
41418c2ecf20Sopenharmony_ci		opt = IB_QP_MIN_RNR_TIMER;
41428c2ecf20Sopenharmony_ci		return is_valid_mask(attr_mask, req, opt);
41438c2ecf20Sopenharmony_ci	} else if (cur_state == IB_QPS_RTS && new_state == IB_QPS_RTS) {
41448c2ecf20Sopenharmony_ci		opt = IB_QP_MIN_RNR_TIMER;
41458c2ecf20Sopenharmony_ci		return is_valid_mask(attr_mask, req, opt);
41468c2ecf20Sopenharmony_ci	} else if (cur_state != IB_QPS_RESET && new_state == IB_QPS_ERR) {
41478c2ecf20Sopenharmony_ci		return is_valid_mask(attr_mask, req, opt);
41488c2ecf20Sopenharmony_ci	}
41498c2ecf20Sopenharmony_ci	return false;
41508c2ecf20Sopenharmony_ci}
41518c2ecf20Sopenharmony_ci
41528c2ecf20Sopenharmony_ci/* mlx5_ib_modify_dct: modify a DCT QP
41538c2ecf20Sopenharmony_ci * valid transitions are:
41548c2ecf20Sopenharmony_ci * RESET to INIT: must set access_flags, pkey_index and port
41558c2ecf20Sopenharmony_ci * INIT  to RTR : must set min_rnr_timer, tclass, flow_label,
41568c2ecf20Sopenharmony_ci *			   mtu, gid_index and hop_limit
41578c2ecf20Sopenharmony_ci * Other transitions and attributes are illegal
41588c2ecf20Sopenharmony_ci */
41598c2ecf20Sopenharmony_cistatic int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr,
41608c2ecf20Sopenharmony_ci			      int attr_mask, struct mlx5_ib_modify_qp *ucmd,
41618c2ecf20Sopenharmony_ci			      struct ib_udata *udata)
41628c2ecf20Sopenharmony_ci{
41638c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *qp = to_mqp(ibqp);
41648c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
41658c2ecf20Sopenharmony_ci	enum ib_qp_state cur_state, new_state;
41668c2ecf20Sopenharmony_ci	int required = IB_QP_STATE;
41678c2ecf20Sopenharmony_ci	void *dctc;
41688c2ecf20Sopenharmony_ci	int err;
41698c2ecf20Sopenharmony_ci
41708c2ecf20Sopenharmony_ci	if (!(attr_mask & IB_QP_STATE))
41718c2ecf20Sopenharmony_ci		return -EINVAL;
41728c2ecf20Sopenharmony_ci
41738c2ecf20Sopenharmony_ci	cur_state = qp->state;
41748c2ecf20Sopenharmony_ci	new_state = attr->qp_state;
41758c2ecf20Sopenharmony_ci
41768c2ecf20Sopenharmony_ci	dctc = MLX5_ADDR_OF(create_dct_in, qp->dct.in, dct_context_entry);
41778c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(dev->mdev, ece_support) && ucmd->ece_options)
41788c2ecf20Sopenharmony_ci		/*
41798c2ecf20Sopenharmony_ci		 * DCT doesn't initialize QP till modify command is executed,
41808c2ecf20Sopenharmony_ci		 * so we need to overwrite previously set ECE field if user
41818c2ecf20Sopenharmony_ci		 * provided any value except zero, which means not set/not
41828c2ecf20Sopenharmony_ci		 * valid.
41838c2ecf20Sopenharmony_ci		 */
41848c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, ece, ucmd->ece_options);
41858c2ecf20Sopenharmony_ci
41868c2ecf20Sopenharmony_ci	if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) {
41878c2ecf20Sopenharmony_ci		u16 set_id;
41888c2ecf20Sopenharmony_ci
41898c2ecf20Sopenharmony_ci		required |= IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX | IB_QP_PORT;
41908c2ecf20Sopenharmony_ci		if (!is_valid_mask(attr_mask, required, 0))
41918c2ecf20Sopenharmony_ci			return -EINVAL;
41928c2ecf20Sopenharmony_ci
41938c2ecf20Sopenharmony_ci		if (attr->port_num == 0 ||
41948c2ecf20Sopenharmony_ci		    attr->port_num > dev->num_ports) {
41958c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "invalid port number %d. number of ports is %d\n",
41968c2ecf20Sopenharmony_ci				    attr->port_num, dev->num_ports);
41978c2ecf20Sopenharmony_ci			return -EINVAL;
41988c2ecf20Sopenharmony_ci		}
41998c2ecf20Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ)
42008c2ecf20Sopenharmony_ci			MLX5_SET(dctc, dctc, rre, 1);
42018c2ecf20Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
42028c2ecf20Sopenharmony_ci			MLX5_SET(dctc, dctc, rwe, 1);
42038c2ecf20Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC) {
42048c2ecf20Sopenharmony_ci			int atomic_mode;
42058c2ecf20Sopenharmony_ci
42068c2ecf20Sopenharmony_ci			atomic_mode = get_atomic_mode(dev, MLX5_IB_QPT_DCT);
42078c2ecf20Sopenharmony_ci			if (atomic_mode < 0)
42088c2ecf20Sopenharmony_ci				return -EOPNOTSUPP;
42098c2ecf20Sopenharmony_ci
42108c2ecf20Sopenharmony_ci			MLX5_SET(dctc, dctc, atomic_mode, atomic_mode);
42118c2ecf20Sopenharmony_ci			MLX5_SET(dctc, dctc, rae, 1);
42128c2ecf20Sopenharmony_ci		}
42138c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, pkey_index, attr->pkey_index);
42148c2ecf20Sopenharmony_ci		if (mlx5_lag_is_active(dev->mdev))
42158c2ecf20Sopenharmony_ci			MLX5_SET(dctc, dctc, port,
42168c2ecf20Sopenharmony_ci				 get_tx_affinity_rr(dev, udata));
42178c2ecf20Sopenharmony_ci		else
42188c2ecf20Sopenharmony_ci			MLX5_SET(dctc, dctc, port, attr->port_num);
42198c2ecf20Sopenharmony_ci
42208c2ecf20Sopenharmony_ci		set_id = mlx5_ib_get_counters_id(dev, attr->port_num - 1);
42218c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, counter_set_id, set_id);
42228c2ecf20Sopenharmony_ci	} else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
42238c2ecf20Sopenharmony_ci		struct mlx5_ib_modify_qp_resp resp = {};
42248c2ecf20Sopenharmony_ci		u32 out[MLX5_ST_SZ_DW(create_dct_out)] = {};
42258c2ecf20Sopenharmony_ci		u32 min_resp_len = offsetofend(typeof(resp), dctn);
42268c2ecf20Sopenharmony_ci
42278c2ecf20Sopenharmony_ci		if (udata->outlen < min_resp_len)
42288c2ecf20Sopenharmony_ci			return -EINVAL;
42298c2ecf20Sopenharmony_ci		/*
42308c2ecf20Sopenharmony_ci		 * If we don't have enough space for the ECE options,
42318c2ecf20Sopenharmony_ci		 * simply indicate it with resp.response_length.
42328c2ecf20Sopenharmony_ci		 */
42338c2ecf20Sopenharmony_ci		resp.response_length = (udata->outlen < sizeof(resp)) ?
42348c2ecf20Sopenharmony_ci					       min_resp_len :
42358c2ecf20Sopenharmony_ci					       sizeof(resp);
42368c2ecf20Sopenharmony_ci
42378c2ecf20Sopenharmony_ci		required |= IB_QP_MIN_RNR_TIMER | IB_QP_AV | IB_QP_PATH_MTU;
42388c2ecf20Sopenharmony_ci		if (!is_valid_mask(attr_mask, required, 0))
42398c2ecf20Sopenharmony_ci			return -EINVAL;
42408c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, min_rnr_nak, attr->min_rnr_timer);
42418c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, tclass, attr->ah_attr.grh.traffic_class);
42428c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, flow_label, attr->ah_attr.grh.flow_label);
42438c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, mtu, attr->path_mtu);
42448c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, my_addr_index, attr->ah_attr.grh.sgid_index);
42458c2ecf20Sopenharmony_ci		MLX5_SET(dctc, dctc, hop_limit, attr->ah_attr.grh.hop_limit);
42468c2ecf20Sopenharmony_ci		if (attr->ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE)
42478c2ecf20Sopenharmony_ci			MLX5_SET(dctc, dctc, eth_prio, attr->ah_attr.sl & 0x7);
42488c2ecf20Sopenharmony_ci
42498c2ecf20Sopenharmony_ci		err = mlx5_core_create_dct(dev, &qp->dct.mdct, qp->dct.in,
42508c2ecf20Sopenharmony_ci					   MLX5_ST_SZ_BYTES(create_dct_in), out,
42518c2ecf20Sopenharmony_ci					   sizeof(out));
42528c2ecf20Sopenharmony_ci		if (err)
42538c2ecf20Sopenharmony_ci			return err;
42548c2ecf20Sopenharmony_ci		resp.dctn = qp->dct.mdct.mqp.qpn;
42558c2ecf20Sopenharmony_ci		if (MLX5_CAP_GEN(dev->mdev, ece_support))
42568c2ecf20Sopenharmony_ci			resp.ece_options = MLX5_GET(create_dct_out, out, ece);
42578c2ecf20Sopenharmony_ci		err = ib_copy_to_udata(udata, &resp, resp.response_length);
42588c2ecf20Sopenharmony_ci		if (err) {
42598c2ecf20Sopenharmony_ci			mlx5_core_destroy_dct(dev, &qp->dct.mdct);
42608c2ecf20Sopenharmony_ci			return err;
42618c2ecf20Sopenharmony_ci		}
42628c2ecf20Sopenharmony_ci	} else {
42638c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "Modify DCT: Invalid transition from %d to %d\n", cur_state, new_state);
42648c2ecf20Sopenharmony_ci		return -EINVAL;
42658c2ecf20Sopenharmony_ci	}
42668c2ecf20Sopenharmony_ci
42678c2ecf20Sopenharmony_ci	qp->state = new_state;
42688c2ecf20Sopenharmony_ci	return 0;
42698c2ecf20Sopenharmony_ci}
42708c2ecf20Sopenharmony_ci
42718c2ecf20Sopenharmony_cistatic bool mlx5_ib_modify_qp_allowed(struct mlx5_ib_dev *dev,
42728c2ecf20Sopenharmony_ci				      struct mlx5_ib_qp *qp,
42738c2ecf20Sopenharmony_ci				      enum ib_qp_type qp_type)
42748c2ecf20Sopenharmony_ci{
42758c2ecf20Sopenharmony_ci	if (dev->profile != &raw_eth_profile)
42768c2ecf20Sopenharmony_ci		return true;
42778c2ecf20Sopenharmony_ci
42788c2ecf20Sopenharmony_ci	if (qp_type == IB_QPT_RAW_PACKET || qp_type == MLX5_IB_QPT_REG_UMR)
42798c2ecf20Sopenharmony_ci		return true;
42808c2ecf20Sopenharmony_ci
42818c2ecf20Sopenharmony_ci	/* Internal QP used for wc testing, with NOPs in wq */
42828c2ecf20Sopenharmony_ci	if (qp->flags & MLX5_IB_QP_CREATE_WC_TEST)
42838c2ecf20Sopenharmony_ci		return true;
42848c2ecf20Sopenharmony_ci
42858c2ecf20Sopenharmony_ci	return false;
42868c2ecf20Sopenharmony_ci}
42878c2ecf20Sopenharmony_ci
42888c2ecf20Sopenharmony_cistatic int validate_rd_atomic(struct mlx5_ib_dev *dev, struct ib_qp_attr *attr,
42898c2ecf20Sopenharmony_ci			      int attr_mask, enum ib_qp_type qp_type)
42908c2ecf20Sopenharmony_ci{
42918c2ecf20Sopenharmony_ci	int log_max_ra_res;
42928c2ecf20Sopenharmony_ci	int log_max_ra_req;
42938c2ecf20Sopenharmony_ci
42948c2ecf20Sopenharmony_ci	if (qp_type == MLX5_IB_QPT_DCI) {
42958c2ecf20Sopenharmony_ci		log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev,
42968c2ecf20Sopenharmony_ci						   log_max_ra_res_dc);
42978c2ecf20Sopenharmony_ci		log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev,
42988c2ecf20Sopenharmony_ci						   log_max_ra_req_dc);
42998c2ecf20Sopenharmony_ci	} else {
43008c2ecf20Sopenharmony_ci		log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev,
43018c2ecf20Sopenharmony_ci						   log_max_ra_res_qp);
43028c2ecf20Sopenharmony_ci		log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev,
43038c2ecf20Sopenharmony_ci						   log_max_ra_req_qp);
43048c2ecf20Sopenharmony_ci	}
43058c2ecf20Sopenharmony_ci
43068c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
43078c2ecf20Sopenharmony_ci	    attr->max_rd_atomic > log_max_ra_res) {
43088c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n",
43098c2ecf20Sopenharmony_ci			    attr->max_rd_atomic);
43108c2ecf20Sopenharmony_ci		return false;
43118c2ecf20Sopenharmony_ci	}
43128c2ecf20Sopenharmony_ci
43138c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
43148c2ecf20Sopenharmony_ci	    attr->max_dest_rd_atomic > log_max_ra_req) {
43158c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n",
43168c2ecf20Sopenharmony_ci			    attr->max_dest_rd_atomic);
43178c2ecf20Sopenharmony_ci		return false;
43188c2ecf20Sopenharmony_ci	}
43198c2ecf20Sopenharmony_ci	return true;
43208c2ecf20Sopenharmony_ci}
43218c2ecf20Sopenharmony_ci
43228c2ecf20Sopenharmony_ciint mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
43238c2ecf20Sopenharmony_ci		      int attr_mask, struct ib_udata *udata)
43248c2ecf20Sopenharmony_ci{
43258c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
43268c2ecf20Sopenharmony_ci	struct mlx5_ib_modify_qp_resp resp = {};
43278c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *qp = to_mqp(ibqp);
43288c2ecf20Sopenharmony_ci	struct mlx5_ib_modify_qp ucmd = {};
43298c2ecf20Sopenharmony_ci	enum ib_qp_type qp_type;
43308c2ecf20Sopenharmony_ci	enum ib_qp_state cur_state, new_state;
43318c2ecf20Sopenharmony_ci	int err = -EINVAL;
43328c2ecf20Sopenharmony_ci	int port;
43338c2ecf20Sopenharmony_ci
43348c2ecf20Sopenharmony_ci	if (!mlx5_ib_modify_qp_allowed(dev, qp, ibqp->qp_type))
43358c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
43368c2ecf20Sopenharmony_ci
43378c2ecf20Sopenharmony_ci	if (ibqp->rwq_ind_tbl)
43388c2ecf20Sopenharmony_ci		return -ENOSYS;
43398c2ecf20Sopenharmony_ci
43408c2ecf20Sopenharmony_ci	if (udata && udata->inlen) {
43418c2ecf20Sopenharmony_ci		if (udata->inlen < offsetofend(typeof(ucmd), ece_options))
43428c2ecf20Sopenharmony_ci			return -EINVAL;
43438c2ecf20Sopenharmony_ci
43448c2ecf20Sopenharmony_ci		if (udata->inlen > sizeof(ucmd) &&
43458c2ecf20Sopenharmony_ci		    !ib_is_udata_cleared(udata, sizeof(ucmd),
43468c2ecf20Sopenharmony_ci					 udata->inlen - sizeof(ucmd)))
43478c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
43488c2ecf20Sopenharmony_ci
43498c2ecf20Sopenharmony_ci		if (ib_copy_from_udata(&ucmd, udata,
43508c2ecf20Sopenharmony_ci				       min(udata->inlen, sizeof(ucmd))))
43518c2ecf20Sopenharmony_ci			return -EFAULT;
43528c2ecf20Sopenharmony_ci
43538c2ecf20Sopenharmony_ci		if (ucmd.comp_mask ||
43548c2ecf20Sopenharmony_ci		    memchr_inv(&ucmd.burst_info.reserved, 0,
43558c2ecf20Sopenharmony_ci			       sizeof(ucmd.burst_info.reserved)))
43568c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
43578c2ecf20Sopenharmony_ci
43588c2ecf20Sopenharmony_ci	}
43598c2ecf20Sopenharmony_ci
43608c2ecf20Sopenharmony_ci	if (unlikely(ibqp->qp_type == IB_QPT_GSI))
43618c2ecf20Sopenharmony_ci		return mlx5_ib_gsi_modify_qp(ibqp, attr, attr_mask);
43628c2ecf20Sopenharmony_ci
43638c2ecf20Sopenharmony_ci	qp_type = (unlikely(ibqp->qp_type == MLX5_IB_QPT_HW_GSI)) ? IB_QPT_GSI :
43648c2ecf20Sopenharmony_ci								    qp->type;
43658c2ecf20Sopenharmony_ci
43668c2ecf20Sopenharmony_ci	if (qp_type == MLX5_IB_QPT_DCT)
43678c2ecf20Sopenharmony_ci		return mlx5_ib_modify_dct(ibqp, attr, attr_mask, &ucmd, udata);
43688c2ecf20Sopenharmony_ci
43698c2ecf20Sopenharmony_ci	mutex_lock(&qp->mutex);
43708c2ecf20Sopenharmony_ci
43718c2ecf20Sopenharmony_ci	cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state;
43728c2ecf20Sopenharmony_ci	new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
43738c2ecf20Sopenharmony_ci
43748c2ecf20Sopenharmony_ci	if (!(cur_state == new_state && cur_state == IB_QPS_RESET)) {
43758c2ecf20Sopenharmony_ci		port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
43768c2ecf20Sopenharmony_ci	}
43778c2ecf20Sopenharmony_ci
43788c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_SOURCE_QPN) {
43798c2ecf20Sopenharmony_ci		if (attr_mask & ~(IB_QP_STATE | IB_QP_CUR_STATE)) {
43808c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "invalid attr_mask 0x%x when underlay QP is used\n",
43818c2ecf20Sopenharmony_ci				    attr_mask);
43828c2ecf20Sopenharmony_ci			goto out;
43838c2ecf20Sopenharmony_ci		}
43848c2ecf20Sopenharmony_ci	} else if (qp_type != MLX5_IB_QPT_REG_UMR &&
43858c2ecf20Sopenharmony_ci		   qp_type != MLX5_IB_QPT_DCI &&
43868c2ecf20Sopenharmony_ci		   !ib_modify_qp_is_ok(cur_state, new_state, qp_type,
43878c2ecf20Sopenharmony_ci				       attr_mask)) {
43888c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "invalid QP state transition from %d to %d, qp_type %d, attr_mask 0x%x\n",
43898c2ecf20Sopenharmony_ci			    cur_state, new_state, ibqp->qp_type, attr_mask);
43908c2ecf20Sopenharmony_ci		goto out;
43918c2ecf20Sopenharmony_ci	} else if (qp_type == MLX5_IB_QPT_DCI &&
43928c2ecf20Sopenharmony_ci		   !modify_dci_qp_is_ok(cur_state, new_state, attr_mask)) {
43938c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "invalid QP state transition from %d to %d, qp_type %d, attr_mask 0x%x\n",
43948c2ecf20Sopenharmony_ci			    cur_state, new_state, qp_type, attr_mask);
43958c2ecf20Sopenharmony_ci		goto out;
43968c2ecf20Sopenharmony_ci	}
43978c2ecf20Sopenharmony_ci
43988c2ecf20Sopenharmony_ci	if ((attr_mask & IB_QP_PORT) &&
43998c2ecf20Sopenharmony_ci	    (attr->port_num == 0 ||
44008c2ecf20Sopenharmony_ci	     attr->port_num > dev->num_ports)) {
44018c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "invalid port number %d. number of ports is %d\n",
44028c2ecf20Sopenharmony_ci			    attr->port_num, dev->num_ports);
44038c2ecf20Sopenharmony_ci		goto out;
44048c2ecf20Sopenharmony_ci	}
44058c2ecf20Sopenharmony_ci
44068c2ecf20Sopenharmony_ci	if (attr_mask & IB_QP_PKEY_INDEX) {
44078c2ecf20Sopenharmony_ci		port = attr_mask & IB_QP_PORT ? attr->port_num : qp->port;
44088c2ecf20Sopenharmony_ci		if (attr->pkey_index >=
44098c2ecf20Sopenharmony_ci		    dev->mdev->port_caps[port - 1].pkey_table_len) {
44108c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "invalid pkey index %d\n",
44118c2ecf20Sopenharmony_ci				    attr->pkey_index);
44128c2ecf20Sopenharmony_ci			goto out;
44138c2ecf20Sopenharmony_ci		}
44148c2ecf20Sopenharmony_ci	}
44158c2ecf20Sopenharmony_ci
44168c2ecf20Sopenharmony_ci	if (!validate_rd_atomic(dev, attr, attr_mask, qp_type))
44178c2ecf20Sopenharmony_ci		goto out;
44188c2ecf20Sopenharmony_ci
44198c2ecf20Sopenharmony_ci	if (cur_state == new_state && cur_state == IB_QPS_RESET) {
44208c2ecf20Sopenharmony_ci		err = 0;
44218c2ecf20Sopenharmony_ci		goto out;
44228c2ecf20Sopenharmony_ci	}
44238c2ecf20Sopenharmony_ci
44248c2ecf20Sopenharmony_ci	err = __mlx5_ib_modify_qp(ibqp, attr, attr_mask, cur_state,
44258c2ecf20Sopenharmony_ci				  new_state, &ucmd, &resp, udata);
44268c2ecf20Sopenharmony_ci
44278c2ecf20Sopenharmony_ci	/* resp.response_length is set in ECE supported flows only */
44288c2ecf20Sopenharmony_ci	if (!err && resp.response_length &&
44298c2ecf20Sopenharmony_ci	    udata->outlen >= resp.response_length)
44308c2ecf20Sopenharmony_ci		/* Return -EFAULT to the user and expect him to destroy QP. */
44318c2ecf20Sopenharmony_ci		err = ib_copy_to_udata(udata, &resp, resp.response_length);
44328c2ecf20Sopenharmony_ci
44338c2ecf20Sopenharmony_ciout:
44348c2ecf20Sopenharmony_ci	mutex_unlock(&qp->mutex);
44358c2ecf20Sopenharmony_ci	return err;
44368c2ecf20Sopenharmony_ci}
44378c2ecf20Sopenharmony_ci
44388c2ecf20Sopenharmony_cistatic inline enum ib_qp_state to_ib_qp_state(enum mlx5_qp_state mlx5_state)
44398c2ecf20Sopenharmony_ci{
44408c2ecf20Sopenharmony_ci	switch (mlx5_state) {
44418c2ecf20Sopenharmony_ci	case MLX5_QP_STATE_RST:      return IB_QPS_RESET;
44428c2ecf20Sopenharmony_ci	case MLX5_QP_STATE_INIT:     return IB_QPS_INIT;
44438c2ecf20Sopenharmony_ci	case MLX5_QP_STATE_RTR:      return IB_QPS_RTR;
44448c2ecf20Sopenharmony_ci	case MLX5_QP_STATE_RTS:      return IB_QPS_RTS;
44458c2ecf20Sopenharmony_ci	case MLX5_QP_STATE_SQ_DRAINING:
44468c2ecf20Sopenharmony_ci	case MLX5_QP_STATE_SQD:      return IB_QPS_SQD;
44478c2ecf20Sopenharmony_ci	case MLX5_QP_STATE_SQER:     return IB_QPS_SQE;
44488c2ecf20Sopenharmony_ci	case MLX5_QP_STATE_ERR:      return IB_QPS_ERR;
44498c2ecf20Sopenharmony_ci	default:		     return -1;
44508c2ecf20Sopenharmony_ci	}
44518c2ecf20Sopenharmony_ci}
44528c2ecf20Sopenharmony_ci
44538c2ecf20Sopenharmony_cistatic inline enum ib_mig_state to_ib_mig_state(int mlx5_mig_state)
44548c2ecf20Sopenharmony_ci{
44558c2ecf20Sopenharmony_ci	switch (mlx5_mig_state) {
44568c2ecf20Sopenharmony_ci	case MLX5_QP_PM_ARMED:		return IB_MIG_ARMED;
44578c2ecf20Sopenharmony_ci	case MLX5_QP_PM_REARM:		return IB_MIG_REARM;
44588c2ecf20Sopenharmony_ci	case MLX5_QP_PM_MIGRATED:	return IB_MIG_MIGRATED;
44598c2ecf20Sopenharmony_ci	default: return -1;
44608c2ecf20Sopenharmony_ci	}
44618c2ecf20Sopenharmony_ci}
44628c2ecf20Sopenharmony_ci
44638c2ecf20Sopenharmony_cistatic void to_rdma_ah_attr(struct mlx5_ib_dev *ibdev,
44648c2ecf20Sopenharmony_ci			    struct rdma_ah_attr *ah_attr, void *path)
44658c2ecf20Sopenharmony_ci{
44668c2ecf20Sopenharmony_ci	int port = MLX5_GET(ads, path, vhca_port_num);
44678c2ecf20Sopenharmony_ci	int static_rate;
44688c2ecf20Sopenharmony_ci
44698c2ecf20Sopenharmony_ci	memset(ah_attr, 0, sizeof(*ah_attr));
44708c2ecf20Sopenharmony_ci
44718c2ecf20Sopenharmony_ci	if (!port || port > ibdev->num_ports)
44728c2ecf20Sopenharmony_ci		return;
44738c2ecf20Sopenharmony_ci
44748c2ecf20Sopenharmony_ci	ah_attr->type = rdma_ah_find_type(&ibdev->ib_dev, port);
44758c2ecf20Sopenharmony_ci
44768c2ecf20Sopenharmony_ci	rdma_ah_set_port_num(ah_attr, port);
44778c2ecf20Sopenharmony_ci	rdma_ah_set_sl(ah_attr, MLX5_GET(ads, path, sl));
44788c2ecf20Sopenharmony_ci
44798c2ecf20Sopenharmony_ci	rdma_ah_set_dlid(ah_attr, MLX5_GET(ads, path, rlid));
44808c2ecf20Sopenharmony_ci	rdma_ah_set_path_bits(ah_attr, MLX5_GET(ads, path, mlid));
44818c2ecf20Sopenharmony_ci
44828c2ecf20Sopenharmony_ci	static_rate = MLX5_GET(ads, path, stat_rate);
44838c2ecf20Sopenharmony_ci	rdma_ah_set_static_rate(ah_attr, mlx5_to_ib_rate_map(static_rate));
44848c2ecf20Sopenharmony_ci	if (MLX5_GET(ads, path, grh) ||
44858c2ecf20Sopenharmony_ci	    ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) {
44868c2ecf20Sopenharmony_ci		rdma_ah_set_grh(ah_attr, NULL, MLX5_GET(ads, path, flow_label),
44878c2ecf20Sopenharmony_ci				MLX5_GET(ads, path, src_addr_index),
44888c2ecf20Sopenharmony_ci				MLX5_GET(ads, path, hop_limit),
44898c2ecf20Sopenharmony_ci				MLX5_GET(ads, path, tclass));
44908c2ecf20Sopenharmony_ci		rdma_ah_set_dgid_raw(ah_attr, MLX5_ADDR_OF(ads, path, rgid_rip));
44918c2ecf20Sopenharmony_ci	}
44928c2ecf20Sopenharmony_ci}
44938c2ecf20Sopenharmony_ci
44948c2ecf20Sopenharmony_cistatic int query_raw_packet_qp_sq_state(struct mlx5_ib_dev *dev,
44958c2ecf20Sopenharmony_ci					struct mlx5_ib_sq *sq,
44968c2ecf20Sopenharmony_ci					u8 *sq_state)
44978c2ecf20Sopenharmony_ci{
44988c2ecf20Sopenharmony_ci	int err;
44998c2ecf20Sopenharmony_ci
45008c2ecf20Sopenharmony_ci	err = mlx5_core_query_sq_state(dev->mdev, sq->base.mqp.qpn, sq_state);
45018c2ecf20Sopenharmony_ci	if (err)
45028c2ecf20Sopenharmony_ci		goto out;
45038c2ecf20Sopenharmony_ci	sq->state = *sq_state;
45048c2ecf20Sopenharmony_ci
45058c2ecf20Sopenharmony_ciout:
45068c2ecf20Sopenharmony_ci	return err;
45078c2ecf20Sopenharmony_ci}
45088c2ecf20Sopenharmony_ci
45098c2ecf20Sopenharmony_cistatic int query_raw_packet_qp_rq_state(struct mlx5_ib_dev *dev,
45108c2ecf20Sopenharmony_ci					struct mlx5_ib_rq *rq,
45118c2ecf20Sopenharmony_ci					u8 *rq_state)
45128c2ecf20Sopenharmony_ci{
45138c2ecf20Sopenharmony_ci	void *out;
45148c2ecf20Sopenharmony_ci	void *rqc;
45158c2ecf20Sopenharmony_ci	int inlen;
45168c2ecf20Sopenharmony_ci	int err;
45178c2ecf20Sopenharmony_ci
45188c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(query_rq_out);
45198c2ecf20Sopenharmony_ci	out = kvzalloc(inlen, GFP_KERNEL);
45208c2ecf20Sopenharmony_ci	if (!out)
45218c2ecf20Sopenharmony_ci		return -ENOMEM;
45228c2ecf20Sopenharmony_ci
45238c2ecf20Sopenharmony_ci	err = mlx5_core_query_rq(dev->mdev, rq->base.mqp.qpn, out);
45248c2ecf20Sopenharmony_ci	if (err)
45258c2ecf20Sopenharmony_ci		goto out;
45268c2ecf20Sopenharmony_ci
45278c2ecf20Sopenharmony_ci	rqc = MLX5_ADDR_OF(query_rq_out, out, rq_context);
45288c2ecf20Sopenharmony_ci	*rq_state = MLX5_GET(rqc, rqc, state);
45298c2ecf20Sopenharmony_ci	rq->state = *rq_state;
45308c2ecf20Sopenharmony_ci
45318c2ecf20Sopenharmony_ciout:
45328c2ecf20Sopenharmony_ci	kvfree(out);
45338c2ecf20Sopenharmony_ci	return err;
45348c2ecf20Sopenharmony_ci}
45358c2ecf20Sopenharmony_ci
45368c2ecf20Sopenharmony_cistatic int sqrq_state_to_qp_state(u8 sq_state, u8 rq_state,
45378c2ecf20Sopenharmony_ci				  struct mlx5_ib_qp *qp, u8 *qp_state)
45388c2ecf20Sopenharmony_ci{
45398c2ecf20Sopenharmony_ci	static const u8 sqrq_trans[MLX5_RQ_NUM_STATE][MLX5_SQ_NUM_STATE] = {
45408c2ecf20Sopenharmony_ci		[MLX5_RQC_STATE_RST] = {
45418c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_RST]	= IB_QPS_RESET,
45428c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_RDY]	= MLX5_QP_STATE_BAD,
45438c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_ERR]	= MLX5_QP_STATE_BAD,
45448c2ecf20Sopenharmony_ci			[MLX5_SQ_STATE_NA]	= IB_QPS_RESET,
45458c2ecf20Sopenharmony_ci		},
45468c2ecf20Sopenharmony_ci		[MLX5_RQC_STATE_RDY] = {
45478c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_RST]	= MLX5_QP_STATE,
45488c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_RDY]	= MLX5_QP_STATE,
45498c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_ERR]	= IB_QPS_SQE,
45508c2ecf20Sopenharmony_ci			[MLX5_SQ_STATE_NA]	= MLX5_QP_STATE,
45518c2ecf20Sopenharmony_ci		},
45528c2ecf20Sopenharmony_ci		[MLX5_RQC_STATE_ERR] = {
45538c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_RST]    = MLX5_QP_STATE_BAD,
45548c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_RDY]	= MLX5_QP_STATE_BAD,
45558c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_ERR]	= IB_QPS_ERR,
45568c2ecf20Sopenharmony_ci			[MLX5_SQ_STATE_NA]	= IB_QPS_ERR,
45578c2ecf20Sopenharmony_ci		},
45588c2ecf20Sopenharmony_ci		[MLX5_RQ_STATE_NA] = {
45598c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_RST]    = MLX5_QP_STATE,
45608c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_RDY]	= MLX5_QP_STATE,
45618c2ecf20Sopenharmony_ci			[MLX5_SQC_STATE_ERR]	= MLX5_QP_STATE,
45628c2ecf20Sopenharmony_ci			[MLX5_SQ_STATE_NA]	= MLX5_QP_STATE_BAD,
45638c2ecf20Sopenharmony_ci		},
45648c2ecf20Sopenharmony_ci	};
45658c2ecf20Sopenharmony_ci
45668c2ecf20Sopenharmony_ci	*qp_state = sqrq_trans[rq_state][sq_state];
45678c2ecf20Sopenharmony_ci
45688c2ecf20Sopenharmony_ci	if (*qp_state == MLX5_QP_STATE_BAD) {
45698c2ecf20Sopenharmony_ci		WARN(1, "Buggy Raw Packet QP state, SQ 0x%x state: 0x%x, RQ 0x%x state: 0x%x",
45708c2ecf20Sopenharmony_ci		     qp->raw_packet_qp.sq.base.mqp.qpn, sq_state,
45718c2ecf20Sopenharmony_ci		     qp->raw_packet_qp.rq.base.mqp.qpn, rq_state);
45728c2ecf20Sopenharmony_ci		return -EINVAL;
45738c2ecf20Sopenharmony_ci	}
45748c2ecf20Sopenharmony_ci
45758c2ecf20Sopenharmony_ci	if (*qp_state == MLX5_QP_STATE)
45768c2ecf20Sopenharmony_ci		*qp_state = qp->state;
45778c2ecf20Sopenharmony_ci
45788c2ecf20Sopenharmony_ci	return 0;
45798c2ecf20Sopenharmony_ci}
45808c2ecf20Sopenharmony_ci
45818c2ecf20Sopenharmony_cistatic int query_raw_packet_qp_state(struct mlx5_ib_dev *dev,
45828c2ecf20Sopenharmony_ci				     struct mlx5_ib_qp *qp,
45838c2ecf20Sopenharmony_ci				     u8 *raw_packet_qp_state)
45848c2ecf20Sopenharmony_ci{
45858c2ecf20Sopenharmony_ci	struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
45868c2ecf20Sopenharmony_ci	struct mlx5_ib_sq *sq = &raw_packet_qp->sq;
45878c2ecf20Sopenharmony_ci	struct mlx5_ib_rq *rq = &raw_packet_qp->rq;
45888c2ecf20Sopenharmony_ci	int err;
45898c2ecf20Sopenharmony_ci	u8 sq_state = MLX5_SQ_STATE_NA;
45908c2ecf20Sopenharmony_ci	u8 rq_state = MLX5_RQ_STATE_NA;
45918c2ecf20Sopenharmony_ci
45928c2ecf20Sopenharmony_ci	if (qp->sq.wqe_cnt) {
45938c2ecf20Sopenharmony_ci		err = query_raw_packet_qp_sq_state(dev, sq, &sq_state);
45948c2ecf20Sopenharmony_ci		if (err)
45958c2ecf20Sopenharmony_ci			return err;
45968c2ecf20Sopenharmony_ci	}
45978c2ecf20Sopenharmony_ci
45988c2ecf20Sopenharmony_ci	if (qp->rq.wqe_cnt) {
45998c2ecf20Sopenharmony_ci		err = query_raw_packet_qp_rq_state(dev, rq, &rq_state);
46008c2ecf20Sopenharmony_ci		if (err)
46018c2ecf20Sopenharmony_ci			return err;
46028c2ecf20Sopenharmony_ci	}
46038c2ecf20Sopenharmony_ci
46048c2ecf20Sopenharmony_ci	return sqrq_state_to_qp_state(sq_state, rq_state, qp,
46058c2ecf20Sopenharmony_ci				      raw_packet_qp_state);
46068c2ecf20Sopenharmony_ci}
46078c2ecf20Sopenharmony_ci
46088c2ecf20Sopenharmony_cistatic int query_qp_attr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
46098c2ecf20Sopenharmony_ci			 struct ib_qp_attr *qp_attr)
46108c2ecf20Sopenharmony_ci{
46118c2ecf20Sopenharmony_ci	int outlen = MLX5_ST_SZ_BYTES(query_qp_out);
46128c2ecf20Sopenharmony_ci	void *qpc, *pri_path, *alt_path;
46138c2ecf20Sopenharmony_ci	u32 *outb;
46148c2ecf20Sopenharmony_ci	int err;
46158c2ecf20Sopenharmony_ci
46168c2ecf20Sopenharmony_ci	outb = kzalloc(outlen, GFP_KERNEL);
46178c2ecf20Sopenharmony_ci	if (!outb)
46188c2ecf20Sopenharmony_ci		return -ENOMEM;
46198c2ecf20Sopenharmony_ci
46208c2ecf20Sopenharmony_ci	err = mlx5_core_qp_query(dev, &qp->trans_qp.base.mqp, outb, outlen);
46218c2ecf20Sopenharmony_ci	if (err)
46228c2ecf20Sopenharmony_ci		goto out;
46238c2ecf20Sopenharmony_ci
46248c2ecf20Sopenharmony_ci	qpc = MLX5_ADDR_OF(query_qp_out, outb, qpc);
46258c2ecf20Sopenharmony_ci
46268c2ecf20Sopenharmony_ci	qp->state = to_ib_qp_state(MLX5_GET(qpc, qpc, state));
46278c2ecf20Sopenharmony_ci	if (MLX5_GET(qpc, qpc, state) == MLX5_QP_STATE_SQ_DRAINING)
46288c2ecf20Sopenharmony_ci		qp_attr->sq_draining = 1;
46298c2ecf20Sopenharmony_ci
46308c2ecf20Sopenharmony_ci	qp_attr->path_mtu = MLX5_GET(qpc, qpc, mtu);
46318c2ecf20Sopenharmony_ci	qp_attr->path_mig_state = to_ib_mig_state(MLX5_GET(qpc, qpc, pm_state));
46328c2ecf20Sopenharmony_ci	qp_attr->qkey = MLX5_GET(qpc, qpc, q_key);
46338c2ecf20Sopenharmony_ci	qp_attr->rq_psn = MLX5_GET(qpc, qpc, next_rcv_psn);
46348c2ecf20Sopenharmony_ci	qp_attr->sq_psn = MLX5_GET(qpc, qpc, next_send_psn);
46358c2ecf20Sopenharmony_ci	qp_attr->dest_qp_num = MLX5_GET(qpc, qpc, remote_qpn);
46368c2ecf20Sopenharmony_ci
46378c2ecf20Sopenharmony_ci	if (MLX5_GET(qpc, qpc, rre))
46388c2ecf20Sopenharmony_ci		qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ;
46398c2ecf20Sopenharmony_ci	if (MLX5_GET(qpc, qpc, rwe))
46408c2ecf20Sopenharmony_ci		qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_WRITE;
46418c2ecf20Sopenharmony_ci	if (MLX5_GET(qpc, qpc, rae))
46428c2ecf20Sopenharmony_ci		qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_ATOMIC;
46438c2ecf20Sopenharmony_ci
46448c2ecf20Sopenharmony_ci	qp_attr->max_rd_atomic = 1 << MLX5_GET(qpc, qpc, log_sra_max);
46458c2ecf20Sopenharmony_ci	qp_attr->max_dest_rd_atomic = 1 << MLX5_GET(qpc, qpc, log_rra_max);
46468c2ecf20Sopenharmony_ci	qp_attr->min_rnr_timer = MLX5_GET(qpc, qpc, min_rnr_nak);
46478c2ecf20Sopenharmony_ci	qp_attr->retry_cnt = MLX5_GET(qpc, qpc, retry_count);
46488c2ecf20Sopenharmony_ci	qp_attr->rnr_retry = MLX5_GET(qpc, qpc, rnr_retry);
46498c2ecf20Sopenharmony_ci
46508c2ecf20Sopenharmony_ci	pri_path = MLX5_ADDR_OF(qpc, qpc, primary_address_path);
46518c2ecf20Sopenharmony_ci	alt_path = MLX5_ADDR_OF(qpc, qpc, secondary_address_path);
46528c2ecf20Sopenharmony_ci
46538c2ecf20Sopenharmony_ci	if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) {
46548c2ecf20Sopenharmony_ci		to_rdma_ah_attr(dev, &qp_attr->ah_attr, pri_path);
46558c2ecf20Sopenharmony_ci		to_rdma_ah_attr(dev, &qp_attr->alt_ah_attr, alt_path);
46568c2ecf20Sopenharmony_ci		qp_attr->alt_pkey_index = MLX5_GET(ads, alt_path, pkey_index);
46578c2ecf20Sopenharmony_ci		qp_attr->alt_port_num = MLX5_GET(ads, alt_path, vhca_port_num);
46588c2ecf20Sopenharmony_ci	}
46598c2ecf20Sopenharmony_ci
46608c2ecf20Sopenharmony_ci	qp_attr->pkey_index = MLX5_GET(ads, pri_path, pkey_index);
46618c2ecf20Sopenharmony_ci	qp_attr->port_num = MLX5_GET(ads, pri_path, vhca_port_num);
46628c2ecf20Sopenharmony_ci	qp_attr->timeout = MLX5_GET(ads, pri_path, ack_timeout);
46638c2ecf20Sopenharmony_ci	qp_attr->alt_timeout = MLX5_GET(ads, alt_path, ack_timeout);
46648c2ecf20Sopenharmony_ci
46658c2ecf20Sopenharmony_ciout:
46668c2ecf20Sopenharmony_ci	kfree(outb);
46678c2ecf20Sopenharmony_ci	return err;
46688c2ecf20Sopenharmony_ci}
46698c2ecf20Sopenharmony_ci
46708c2ecf20Sopenharmony_cistatic int mlx5_ib_dct_query_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *mqp,
46718c2ecf20Sopenharmony_ci				struct ib_qp_attr *qp_attr, int qp_attr_mask,
46728c2ecf20Sopenharmony_ci				struct ib_qp_init_attr *qp_init_attr)
46738c2ecf20Sopenharmony_ci{
46748c2ecf20Sopenharmony_ci	struct mlx5_core_dct	*dct = &mqp->dct.mdct;
46758c2ecf20Sopenharmony_ci	u32 *out;
46768c2ecf20Sopenharmony_ci	u32 access_flags = 0;
46778c2ecf20Sopenharmony_ci	int outlen = MLX5_ST_SZ_BYTES(query_dct_out);
46788c2ecf20Sopenharmony_ci	void *dctc;
46798c2ecf20Sopenharmony_ci	int err;
46808c2ecf20Sopenharmony_ci	int supported_mask = IB_QP_STATE |
46818c2ecf20Sopenharmony_ci			     IB_QP_ACCESS_FLAGS |
46828c2ecf20Sopenharmony_ci			     IB_QP_PORT |
46838c2ecf20Sopenharmony_ci			     IB_QP_MIN_RNR_TIMER |
46848c2ecf20Sopenharmony_ci			     IB_QP_AV |
46858c2ecf20Sopenharmony_ci			     IB_QP_PATH_MTU |
46868c2ecf20Sopenharmony_ci			     IB_QP_PKEY_INDEX;
46878c2ecf20Sopenharmony_ci
46888c2ecf20Sopenharmony_ci	if (qp_attr_mask & ~supported_mask)
46898c2ecf20Sopenharmony_ci		return -EINVAL;
46908c2ecf20Sopenharmony_ci	if (mqp->state != IB_QPS_RTR)
46918c2ecf20Sopenharmony_ci		return -EINVAL;
46928c2ecf20Sopenharmony_ci
46938c2ecf20Sopenharmony_ci	out = kzalloc(outlen, GFP_KERNEL);
46948c2ecf20Sopenharmony_ci	if (!out)
46958c2ecf20Sopenharmony_ci		return -ENOMEM;
46968c2ecf20Sopenharmony_ci
46978c2ecf20Sopenharmony_ci	err = mlx5_core_dct_query(dev, dct, out, outlen);
46988c2ecf20Sopenharmony_ci	if (err)
46998c2ecf20Sopenharmony_ci		goto out;
47008c2ecf20Sopenharmony_ci
47018c2ecf20Sopenharmony_ci	dctc = MLX5_ADDR_OF(query_dct_out, out, dct_context_entry);
47028c2ecf20Sopenharmony_ci
47038c2ecf20Sopenharmony_ci	if (qp_attr_mask & IB_QP_STATE)
47048c2ecf20Sopenharmony_ci		qp_attr->qp_state = IB_QPS_RTR;
47058c2ecf20Sopenharmony_ci
47068c2ecf20Sopenharmony_ci	if (qp_attr_mask & IB_QP_ACCESS_FLAGS) {
47078c2ecf20Sopenharmony_ci		if (MLX5_GET(dctc, dctc, rre))
47088c2ecf20Sopenharmony_ci			access_flags |= IB_ACCESS_REMOTE_READ;
47098c2ecf20Sopenharmony_ci		if (MLX5_GET(dctc, dctc, rwe))
47108c2ecf20Sopenharmony_ci			access_flags |= IB_ACCESS_REMOTE_WRITE;
47118c2ecf20Sopenharmony_ci		if (MLX5_GET(dctc, dctc, rae))
47128c2ecf20Sopenharmony_ci			access_flags |= IB_ACCESS_REMOTE_ATOMIC;
47138c2ecf20Sopenharmony_ci		qp_attr->qp_access_flags = access_flags;
47148c2ecf20Sopenharmony_ci	}
47158c2ecf20Sopenharmony_ci
47168c2ecf20Sopenharmony_ci	if (qp_attr_mask & IB_QP_PORT)
47178c2ecf20Sopenharmony_ci		qp_attr->port_num = MLX5_GET(dctc, dctc, port);
47188c2ecf20Sopenharmony_ci	if (qp_attr_mask & IB_QP_MIN_RNR_TIMER)
47198c2ecf20Sopenharmony_ci		qp_attr->min_rnr_timer = MLX5_GET(dctc, dctc, min_rnr_nak);
47208c2ecf20Sopenharmony_ci	if (qp_attr_mask & IB_QP_AV) {
47218c2ecf20Sopenharmony_ci		qp_attr->ah_attr.grh.traffic_class = MLX5_GET(dctc, dctc, tclass);
47228c2ecf20Sopenharmony_ci		qp_attr->ah_attr.grh.flow_label = MLX5_GET(dctc, dctc, flow_label);
47238c2ecf20Sopenharmony_ci		qp_attr->ah_attr.grh.sgid_index = MLX5_GET(dctc, dctc, my_addr_index);
47248c2ecf20Sopenharmony_ci		qp_attr->ah_attr.grh.hop_limit = MLX5_GET(dctc, dctc, hop_limit);
47258c2ecf20Sopenharmony_ci	}
47268c2ecf20Sopenharmony_ci	if (qp_attr_mask & IB_QP_PATH_MTU)
47278c2ecf20Sopenharmony_ci		qp_attr->path_mtu = MLX5_GET(dctc, dctc, mtu);
47288c2ecf20Sopenharmony_ci	if (qp_attr_mask & IB_QP_PKEY_INDEX)
47298c2ecf20Sopenharmony_ci		qp_attr->pkey_index = MLX5_GET(dctc, dctc, pkey_index);
47308c2ecf20Sopenharmony_ciout:
47318c2ecf20Sopenharmony_ci	kfree(out);
47328c2ecf20Sopenharmony_ci	return err;
47338c2ecf20Sopenharmony_ci}
47348c2ecf20Sopenharmony_ci
47358c2ecf20Sopenharmony_ciint mlx5_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
47368c2ecf20Sopenharmony_ci		     int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
47378c2ecf20Sopenharmony_ci{
47388c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
47398c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *qp = to_mqp(ibqp);
47408c2ecf20Sopenharmony_ci	int err = 0;
47418c2ecf20Sopenharmony_ci	u8 raw_packet_qp_state;
47428c2ecf20Sopenharmony_ci
47438c2ecf20Sopenharmony_ci	if (ibqp->rwq_ind_tbl)
47448c2ecf20Sopenharmony_ci		return -ENOSYS;
47458c2ecf20Sopenharmony_ci
47468c2ecf20Sopenharmony_ci	if (unlikely(ibqp->qp_type == IB_QPT_GSI))
47478c2ecf20Sopenharmony_ci		return mlx5_ib_gsi_query_qp(ibqp, qp_attr, qp_attr_mask,
47488c2ecf20Sopenharmony_ci					    qp_init_attr);
47498c2ecf20Sopenharmony_ci
47508c2ecf20Sopenharmony_ci	/* Not all of output fields are applicable, make sure to zero them */
47518c2ecf20Sopenharmony_ci	memset(qp_init_attr, 0, sizeof(*qp_init_attr));
47528c2ecf20Sopenharmony_ci	memset(qp_attr, 0, sizeof(*qp_attr));
47538c2ecf20Sopenharmony_ci
47548c2ecf20Sopenharmony_ci	if (unlikely(qp->type == MLX5_IB_QPT_DCT))
47558c2ecf20Sopenharmony_ci		return mlx5_ib_dct_query_qp(dev, qp, qp_attr,
47568c2ecf20Sopenharmony_ci					    qp_attr_mask, qp_init_attr);
47578c2ecf20Sopenharmony_ci
47588c2ecf20Sopenharmony_ci	mutex_lock(&qp->mutex);
47598c2ecf20Sopenharmony_ci
47608c2ecf20Sopenharmony_ci	if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET ||
47618c2ecf20Sopenharmony_ci	    qp->flags & IB_QP_CREATE_SOURCE_QPN) {
47628c2ecf20Sopenharmony_ci		err = query_raw_packet_qp_state(dev, qp, &raw_packet_qp_state);
47638c2ecf20Sopenharmony_ci		if (err)
47648c2ecf20Sopenharmony_ci			goto out;
47658c2ecf20Sopenharmony_ci		qp->state = raw_packet_qp_state;
47668c2ecf20Sopenharmony_ci		qp_attr->port_num = 1;
47678c2ecf20Sopenharmony_ci	} else {
47688c2ecf20Sopenharmony_ci		err = query_qp_attr(dev, qp, qp_attr);
47698c2ecf20Sopenharmony_ci		if (err)
47708c2ecf20Sopenharmony_ci			goto out;
47718c2ecf20Sopenharmony_ci	}
47728c2ecf20Sopenharmony_ci
47738c2ecf20Sopenharmony_ci	qp_attr->qp_state	     = qp->state;
47748c2ecf20Sopenharmony_ci	qp_attr->cur_qp_state	     = qp_attr->qp_state;
47758c2ecf20Sopenharmony_ci	qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
47768c2ecf20Sopenharmony_ci	qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
47778c2ecf20Sopenharmony_ci
47788c2ecf20Sopenharmony_ci	if (!ibqp->uobject) {
47798c2ecf20Sopenharmony_ci		qp_attr->cap.max_send_wr  = qp->sq.max_post;
47808c2ecf20Sopenharmony_ci		qp_attr->cap.max_send_sge = qp->sq.max_gs;
47818c2ecf20Sopenharmony_ci		qp_init_attr->qp_context = ibqp->qp_context;
47828c2ecf20Sopenharmony_ci	} else {
47838c2ecf20Sopenharmony_ci		qp_attr->cap.max_send_wr  = 0;
47848c2ecf20Sopenharmony_ci		qp_attr->cap.max_send_sge = 0;
47858c2ecf20Sopenharmony_ci	}
47868c2ecf20Sopenharmony_ci
47878c2ecf20Sopenharmony_ci	qp_init_attr->qp_type = ibqp->qp_type;
47888c2ecf20Sopenharmony_ci	qp_init_attr->recv_cq = ibqp->recv_cq;
47898c2ecf20Sopenharmony_ci	qp_init_attr->send_cq = ibqp->send_cq;
47908c2ecf20Sopenharmony_ci	qp_init_attr->srq = ibqp->srq;
47918c2ecf20Sopenharmony_ci	qp_attr->cap.max_inline_data = qp->max_inline_data;
47928c2ecf20Sopenharmony_ci
47938c2ecf20Sopenharmony_ci	qp_init_attr->cap	     = qp_attr->cap;
47948c2ecf20Sopenharmony_ci
47958c2ecf20Sopenharmony_ci	qp_init_attr->create_flags = qp->flags;
47968c2ecf20Sopenharmony_ci
47978c2ecf20Sopenharmony_ci	qp_init_attr->sq_sig_type = qp->sq_signal_bits & MLX5_WQE_CTRL_CQ_UPDATE ?
47988c2ecf20Sopenharmony_ci		IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
47998c2ecf20Sopenharmony_ci
48008c2ecf20Sopenharmony_ciout:
48018c2ecf20Sopenharmony_ci	mutex_unlock(&qp->mutex);
48028c2ecf20Sopenharmony_ci	return err;
48038c2ecf20Sopenharmony_ci}
48048c2ecf20Sopenharmony_ci
48058c2ecf20Sopenharmony_ciint mlx5_ib_alloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata)
48068c2ecf20Sopenharmony_ci{
48078c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ibxrcd->device);
48088c2ecf20Sopenharmony_ci	struct mlx5_ib_xrcd *xrcd = to_mxrcd(ibxrcd);
48098c2ecf20Sopenharmony_ci
48108c2ecf20Sopenharmony_ci	if (!MLX5_CAP_GEN(dev->mdev, xrc))
48118c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
48128c2ecf20Sopenharmony_ci
48138c2ecf20Sopenharmony_ci	return mlx5_cmd_xrcd_alloc(dev->mdev, &xrcd->xrcdn, 0);
48148c2ecf20Sopenharmony_ci}
48158c2ecf20Sopenharmony_ci
48168c2ecf20Sopenharmony_ciint mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd, struct ib_udata *udata)
48178c2ecf20Sopenharmony_ci{
48188c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(xrcd->device);
48198c2ecf20Sopenharmony_ci	u32 xrcdn = to_mxrcd(xrcd)->xrcdn;
48208c2ecf20Sopenharmony_ci
48218c2ecf20Sopenharmony_ci	return mlx5_cmd_xrcd_dealloc(dev->mdev, xrcdn, 0);
48228c2ecf20Sopenharmony_ci}
48238c2ecf20Sopenharmony_ci
48248c2ecf20Sopenharmony_cistatic void mlx5_ib_wq_event(struct mlx5_core_qp *core_qp, int type)
48258c2ecf20Sopenharmony_ci{
48268c2ecf20Sopenharmony_ci	struct mlx5_ib_rwq *rwq = to_mibrwq(core_qp);
48278c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(rwq->ibwq.device);
48288c2ecf20Sopenharmony_ci	struct ib_event event;
48298c2ecf20Sopenharmony_ci
48308c2ecf20Sopenharmony_ci	if (rwq->ibwq.event_handler) {
48318c2ecf20Sopenharmony_ci		event.device     = rwq->ibwq.device;
48328c2ecf20Sopenharmony_ci		event.element.wq = &rwq->ibwq;
48338c2ecf20Sopenharmony_ci		switch (type) {
48348c2ecf20Sopenharmony_ci		case MLX5_EVENT_TYPE_WQ_CATAS_ERROR:
48358c2ecf20Sopenharmony_ci			event.event = IB_EVENT_WQ_FATAL;
48368c2ecf20Sopenharmony_ci			break;
48378c2ecf20Sopenharmony_ci		default:
48388c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "Unexpected event type %d on WQ %06x\n", type, core_qp->qpn);
48398c2ecf20Sopenharmony_ci			return;
48408c2ecf20Sopenharmony_ci		}
48418c2ecf20Sopenharmony_ci
48428c2ecf20Sopenharmony_ci		rwq->ibwq.event_handler(&event, rwq->ibwq.wq_context);
48438c2ecf20Sopenharmony_ci	}
48448c2ecf20Sopenharmony_ci}
48458c2ecf20Sopenharmony_ci
48468c2ecf20Sopenharmony_cistatic int set_delay_drop(struct mlx5_ib_dev *dev)
48478c2ecf20Sopenharmony_ci{
48488c2ecf20Sopenharmony_ci	int err = 0;
48498c2ecf20Sopenharmony_ci
48508c2ecf20Sopenharmony_ci	mutex_lock(&dev->delay_drop.lock);
48518c2ecf20Sopenharmony_ci	if (dev->delay_drop.activate)
48528c2ecf20Sopenharmony_ci		goto out;
48538c2ecf20Sopenharmony_ci
48548c2ecf20Sopenharmony_ci	err = mlx5_core_set_delay_drop(dev, dev->delay_drop.timeout);
48558c2ecf20Sopenharmony_ci	if (err)
48568c2ecf20Sopenharmony_ci		goto out;
48578c2ecf20Sopenharmony_ci
48588c2ecf20Sopenharmony_ci	dev->delay_drop.activate = true;
48598c2ecf20Sopenharmony_ciout:
48608c2ecf20Sopenharmony_ci	mutex_unlock(&dev->delay_drop.lock);
48618c2ecf20Sopenharmony_ci
48628c2ecf20Sopenharmony_ci	if (!err)
48638c2ecf20Sopenharmony_ci		atomic_inc(&dev->delay_drop.rqs_cnt);
48648c2ecf20Sopenharmony_ci	return err;
48658c2ecf20Sopenharmony_ci}
48668c2ecf20Sopenharmony_ci
48678c2ecf20Sopenharmony_cistatic int  create_rq(struct mlx5_ib_rwq *rwq, struct ib_pd *pd,
48688c2ecf20Sopenharmony_ci		      struct ib_wq_init_attr *init_attr)
48698c2ecf20Sopenharmony_ci{
48708c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev;
48718c2ecf20Sopenharmony_ci	int has_net_offloads;
48728c2ecf20Sopenharmony_ci	__be64 *rq_pas0;
48738c2ecf20Sopenharmony_ci	void *in;
48748c2ecf20Sopenharmony_ci	void *rqc;
48758c2ecf20Sopenharmony_ci	void *wq;
48768c2ecf20Sopenharmony_ci	int inlen;
48778c2ecf20Sopenharmony_ci	int err;
48788c2ecf20Sopenharmony_ci
48798c2ecf20Sopenharmony_ci	dev = to_mdev(pd->device);
48808c2ecf20Sopenharmony_ci
48818c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(create_rq_in) + sizeof(u64) * rwq->rq_num_pas;
48828c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
48838c2ecf20Sopenharmony_ci	if (!in)
48848c2ecf20Sopenharmony_ci		return -ENOMEM;
48858c2ecf20Sopenharmony_ci
48868c2ecf20Sopenharmony_ci	MLX5_SET(create_rq_in, in, uid, to_mpd(pd)->uid);
48878c2ecf20Sopenharmony_ci	rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
48888c2ecf20Sopenharmony_ci	MLX5_SET(rqc,  rqc, mem_rq_type,
48898c2ecf20Sopenharmony_ci		 MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE);
48908c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, user_index, rwq->user_index);
48918c2ecf20Sopenharmony_ci	MLX5_SET(rqc,  rqc, cqn, to_mcq(init_attr->cq)->mcq.cqn);
48928c2ecf20Sopenharmony_ci	MLX5_SET(rqc,  rqc, state, MLX5_RQC_STATE_RST);
48938c2ecf20Sopenharmony_ci	MLX5_SET(rqc,  rqc, flush_in_error_en, 1);
48948c2ecf20Sopenharmony_ci	wq = MLX5_ADDR_OF(rqc, rqc, wq);
48958c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, wq_type,
48968c2ecf20Sopenharmony_ci		 rwq->create_flags & MLX5_IB_WQ_FLAGS_STRIDING_RQ ?
48978c2ecf20Sopenharmony_ci		 MLX5_WQ_TYPE_CYCLIC_STRIDING_RQ : MLX5_WQ_TYPE_CYCLIC);
48988c2ecf20Sopenharmony_ci	if (init_attr->create_flags & IB_WQ_FLAGS_PCI_WRITE_END_PADDING) {
48998c2ecf20Sopenharmony_ci		if (!MLX5_CAP_GEN(dev->mdev, end_pad)) {
49008c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "Scatter end padding is not supported\n");
49018c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
49028c2ecf20Sopenharmony_ci			goto out;
49038c2ecf20Sopenharmony_ci		} else {
49048c2ecf20Sopenharmony_ci			MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN);
49058c2ecf20Sopenharmony_ci		}
49068c2ecf20Sopenharmony_ci	}
49078c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, log_wq_stride, rwq->log_rq_stride);
49088c2ecf20Sopenharmony_ci	if (rwq->create_flags & MLX5_IB_WQ_FLAGS_STRIDING_RQ) {
49098c2ecf20Sopenharmony_ci		/*
49108c2ecf20Sopenharmony_ci		 * In Firmware number of strides in each WQE is:
49118c2ecf20Sopenharmony_ci		 *   "512 * 2^single_wqe_log_num_of_strides"
49128c2ecf20Sopenharmony_ci		 * Values 3 to 8 are accepted as 10 to 15, 9 to 18 are
49138c2ecf20Sopenharmony_ci		 * accepted as 0 to 9
49148c2ecf20Sopenharmony_ci		 */
49158c2ecf20Sopenharmony_ci		static const u8 fw_map[] = { 10, 11, 12, 13, 14, 15, 0, 1,
49168c2ecf20Sopenharmony_ci					     2,  3,  4,  5,  6,  7,  8, 9 };
49178c2ecf20Sopenharmony_ci		MLX5_SET(wq, wq, two_byte_shift_en, rwq->two_byte_shift_en);
49188c2ecf20Sopenharmony_ci		MLX5_SET(wq, wq, log_wqe_stride_size,
49198c2ecf20Sopenharmony_ci			 rwq->single_stride_log_num_of_bytes -
49208c2ecf20Sopenharmony_ci			 MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES);
49218c2ecf20Sopenharmony_ci		MLX5_SET(wq, wq, log_wqe_num_of_strides,
49228c2ecf20Sopenharmony_ci			 fw_map[rwq->log_num_strides -
49238c2ecf20Sopenharmony_ci				MLX5_EXT_MIN_SINGLE_WQE_LOG_NUM_STRIDES]);
49248c2ecf20Sopenharmony_ci	}
49258c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, log_wq_sz, rwq->log_rq_size);
49268c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, pd, to_mpd(pd)->pdn);
49278c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, page_offset, rwq->rq_page_offset);
49288c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, log_wq_pg_sz, rwq->log_page_size);
49298c2ecf20Sopenharmony_ci	MLX5_SET(wq, wq, wq_signature, rwq->wq_sig);
49308c2ecf20Sopenharmony_ci	MLX5_SET64(wq, wq, dbr_addr, rwq->db.dma);
49318c2ecf20Sopenharmony_ci	has_net_offloads = MLX5_CAP_GEN(dev->mdev, eth_net_offloads);
49328c2ecf20Sopenharmony_ci	if (init_attr->create_flags & IB_WQ_FLAGS_CVLAN_STRIPPING) {
49338c2ecf20Sopenharmony_ci		if (!(has_net_offloads && MLX5_CAP_ETH(dev->mdev, vlan_cap))) {
49348c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "VLAN offloads are not supported\n");
49358c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
49368c2ecf20Sopenharmony_ci			goto out;
49378c2ecf20Sopenharmony_ci		}
49388c2ecf20Sopenharmony_ci	} else {
49398c2ecf20Sopenharmony_ci		MLX5_SET(rqc, rqc, vsd, 1);
49408c2ecf20Sopenharmony_ci	}
49418c2ecf20Sopenharmony_ci	if (init_attr->create_flags & IB_WQ_FLAGS_SCATTER_FCS) {
49428c2ecf20Sopenharmony_ci		if (!(has_net_offloads && MLX5_CAP_ETH(dev->mdev, scatter_fcs))) {
49438c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "Scatter FCS is not supported\n");
49448c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
49458c2ecf20Sopenharmony_ci			goto out;
49468c2ecf20Sopenharmony_ci		}
49478c2ecf20Sopenharmony_ci		MLX5_SET(rqc, rqc, scatter_fcs, 1);
49488c2ecf20Sopenharmony_ci	}
49498c2ecf20Sopenharmony_ci	if (init_attr->create_flags & IB_WQ_FLAGS_DELAY_DROP) {
49508c2ecf20Sopenharmony_ci		if (!(dev->ib_dev.attrs.raw_packet_caps &
49518c2ecf20Sopenharmony_ci		      IB_RAW_PACKET_CAP_DELAY_DROP)) {
49528c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "Delay drop is not supported\n");
49538c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
49548c2ecf20Sopenharmony_ci			goto out;
49558c2ecf20Sopenharmony_ci		}
49568c2ecf20Sopenharmony_ci		MLX5_SET(rqc, rqc, delay_drop_en, 1);
49578c2ecf20Sopenharmony_ci	}
49588c2ecf20Sopenharmony_ci	rq_pas0 = (__be64 *)MLX5_ADDR_OF(wq, wq, pas);
49598c2ecf20Sopenharmony_ci	mlx5_ib_populate_pas(dev, rwq->umem, rwq->page_shift, rq_pas0, 0);
49608c2ecf20Sopenharmony_ci	err = mlx5_core_create_rq_tracked(dev, in, inlen, &rwq->core_qp);
49618c2ecf20Sopenharmony_ci	if (!err && init_attr->create_flags & IB_WQ_FLAGS_DELAY_DROP) {
49628c2ecf20Sopenharmony_ci		err = set_delay_drop(dev);
49638c2ecf20Sopenharmony_ci		if (err) {
49648c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "Failed to enable delay drop err=%d\n",
49658c2ecf20Sopenharmony_ci				     err);
49668c2ecf20Sopenharmony_ci			mlx5_core_destroy_rq_tracked(dev, &rwq->core_qp);
49678c2ecf20Sopenharmony_ci		} else {
49688c2ecf20Sopenharmony_ci			rwq->create_flags |= MLX5_IB_WQ_FLAGS_DELAY_DROP;
49698c2ecf20Sopenharmony_ci		}
49708c2ecf20Sopenharmony_ci	}
49718c2ecf20Sopenharmony_ciout:
49728c2ecf20Sopenharmony_ci	kvfree(in);
49738c2ecf20Sopenharmony_ci	return err;
49748c2ecf20Sopenharmony_ci}
49758c2ecf20Sopenharmony_ci
49768c2ecf20Sopenharmony_cistatic int set_user_rq_size(struct mlx5_ib_dev *dev,
49778c2ecf20Sopenharmony_ci			    struct ib_wq_init_attr *wq_init_attr,
49788c2ecf20Sopenharmony_ci			    struct mlx5_ib_create_wq *ucmd,
49798c2ecf20Sopenharmony_ci			    struct mlx5_ib_rwq *rwq)
49808c2ecf20Sopenharmony_ci{
49818c2ecf20Sopenharmony_ci	/* Sanity check RQ size before proceeding */
49828c2ecf20Sopenharmony_ci	if (wq_init_attr->max_wr > (1 << MLX5_CAP_GEN(dev->mdev, log_max_wq_sz)))
49838c2ecf20Sopenharmony_ci		return -EINVAL;
49848c2ecf20Sopenharmony_ci
49858c2ecf20Sopenharmony_ci	if (!ucmd->rq_wqe_count)
49868c2ecf20Sopenharmony_ci		return -EINVAL;
49878c2ecf20Sopenharmony_ci
49888c2ecf20Sopenharmony_ci	rwq->wqe_count = ucmd->rq_wqe_count;
49898c2ecf20Sopenharmony_ci	rwq->wqe_shift = ucmd->rq_wqe_shift;
49908c2ecf20Sopenharmony_ci	if (check_shl_overflow(rwq->wqe_count, rwq->wqe_shift, &rwq->buf_size))
49918c2ecf20Sopenharmony_ci		return -EINVAL;
49928c2ecf20Sopenharmony_ci
49938c2ecf20Sopenharmony_ci	rwq->log_rq_stride = rwq->wqe_shift;
49948c2ecf20Sopenharmony_ci	rwq->log_rq_size = ilog2(rwq->wqe_count);
49958c2ecf20Sopenharmony_ci	return 0;
49968c2ecf20Sopenharmony_ci}
49978c2ecf20Sopenharmony_ci
49988c2ecf20Sopenharmony_cistatic bool log_of_strides_valid(struct mlx5_ib_dev *dev, u32 log_num_strides)
49998c2ecf20Sopenharmony_ci{
50008c2ecf20Sopenharmony_ci	if ((log_num_strides > MLX5_MAX_SINGLE_WQE_LOG_NUM_STRIDES) ||
50018c2ecf20Sopenharmony_ci	    (log_num_strides < MLX5_EXT_MIN_SINGLE_WQE_LOG_NUM_STRIDES))
50028c2ecf20Sopenharmony_ci		return false;
50038c2ecf20Sopenharmony_ci
50048c2ecf20Sopenharmony_ci	if (!MLX5_CAP_GEN(dev->mdev, ext_stride_num_range) &&
50058c2ecf20Sopenharmony_ci	    (log_num_strides < MLX5_MIN_SINGLE_WQE_LOG_NUM_STRIDES))
50068c2ecf20Sopenharmony_ci		return false;
50078c2ecf20Sopenharmony_ci
50088c2ecf20Sopenharmony_ci	return true;
50098c2ecf20Sopenharmony_ci}
50108c2ecf20Sopenharmony_ci
50118c2ecf20Sopenharmony_cistatic int prepare_user_rq(struct ib_pd *pd,
50128c2ecf20Sopenharmony_ci			   struct ib_wq_init_attr *init_attr,
50138c2ecf20Sopenharmony_ci			   struct ib_udata *udata,
50148c2ecf20Sopenharmony_ci			   struct mlx5_ib_rwq *rwq)
50158c2ecf20Sopenharmony_ci{
50168c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->device);
50178c2ecf20Sopenharmony_ci	struct mlx5_ib_create_wq ucmd = {};
50188c2ecf20Sopenharmony_ci	int err;
50198c2ecf20Sopenharmony_ci	size_t required_cmd_sz;
50208c2ecf20Sopenharmony_ci
50218c2ecf20Sopenharmony_ci	required_cmd_sz = offsetofend(struct mlx5_ib_create_wq,
50228c2ecf20Sopenharmony_ci				      single_stride_log_num_of_bytes);
50238c2ecf20Sopenharmony_ci	if (udata->inlen < required_cmd_sz) {
50248c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "invalid inlen\n");
50258c2ecf20Sopenharmony_ci		return -EINVAL;
50268c2ecf20Sopenharmony_ci	}
50278c2ecf20Sopenharmony_ci
50288c2ecf20Sopenharmony_ci	if (udata->inlen > sizeof(ucmd) &&
50298c2ecf20Sopenharmony_ci	    !ib_is_udata_cleared(udata, sizeof(ucmd),
50308c2ecf20Sopenharmony_ci				 udata->inlen - sizeof(ucmd))) {
50318c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "inlen is not supported\n");
50328c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
50338c2ecf20Sopenharmony_ci	}
50348c2ecf20Sopenharmony_ci
50358c2ecf20Sopenharmony_ci	if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen))) {
50368c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "copy failed\n");
50378c2ecf20Sopenharmony_ci		return -EFAULT;
50388c2ecf20Sopenharmony_ci	}
50398c2ecf20Sopenharmony_ci
50408c2ecf20Sopenharmony_ci	if (ucmd.comp_mask & (~MLX5_IB_CREATE_WQ_STRIDING_RQ)) {
50418c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "invalid comp mask\n");
50428c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
50438c2ecf20Sopenharmony_ci	} else if (ucmd.comp_mask & MLX5_IB_CREATE_WQ_STRIDING_RQ) {
50448c2ecf20Sopenharmony_ci		if (!MLX5_CAP_GEN(dev->mdev, striding_rq)) {
50458c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "Striding RQ is not supported\n");
50468c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
50478c2ecf20Sopenharmony_ci		}
50488c2ecf20Sopenharmony_ci		if ((ucmd.single_stride_log_num_of_bytes <
50498c2ecf20Sopenharmony_ci		    MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES) ||
50508c2ecf20Sopenharmony_ci		    (ucmd.single_stride_log_num_of_bytes >
50518c2ecf20Sopenharmony_ci		     MLX5_MAX_SINGLE_STRIDE_LOG_NUM_BYTES)) {
50528c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "Invalid log stride size (%u. Range is %u - %u)\n",
50538c2ecf20Sopenharmony_ci				    ucmd.single_stride_log_num_of_bytes,
50548c2ecf20Sopenharmony_ci				    MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES,
50558c2ecf20Sopenharmony_ci				    MLX5_MAX_SINGLE_STRIDE_LOG_NUM_BYTES);
50568c2ecf20Sopenharmony_ci			return -EINVAL;
50578c2ecf20Sopenharmony_ci		}
50588c2ecf20Sopenharmony_ci		if (!log_of_strides_valid(dev,
50598c2ecf20Sopenharmony_ci					  ucmd.single_wqe_log_num_of_strides)) {
50608c2ecf20Sopenharmony_ci			mlx5_ib_dbg(
50618c2ecf20Sopenharmony_ci				dev,
50628c2ecf20Sopenharmony_ci				"Invalid log num strides (%u. Range is %u - %u)\n",
50638c2ecf20Sopenharmony_ci				ucmd.single_wqe_log_num_of_strides,
50648c2ecf20Sopenharmony_ci				MLX5_CAP_GEN(dev->mdev, ext_stride_num_range) ?
50658c2ecf20Sopenharmony_ci					MLX5_EXT_MIN_SINGLE_WQE_LOG_NUM_STRIDES :
50668c2ecf20Sopenharmony_ci					MLX5_MIN_SINGLE_WQE_LOG_NUM_STRIDES,
50678c2ecf20Sopenharmony_ci				MLX5_MAX_SINGLE_WQE_LOG_NUM_STRIDES);
50688c2ecf20Sopenharmony_ci			return -EINVAL;
50698c2ecf20Sopenharmony_ci		}
50708c2ecf20Sopenharmony_ci		rwq->single_stride_log_num_of_bytes =
50718c2ecf20Sopenharmony_ci			ucmd.single_stride_log_num_of_bytes;
50728c2ecf20Sopenharmony_ci		rwq->log_num_strides = ucmd.single_wqe_log_num_of_strides;
50738c2ecf20Sopenharmony_ci		rwq->two_byte_shift_en = !!ucmd.two_byte_shift_en;
50748c2ecf20Sopenharmony_ci		rwq->create_flags |= MLX5_IB_WQ_FLAGS_STRIDING_RQ;
50758c2ecf20Sopenharmony_ci	}
50768c2ecf20Sopenharmony_ci
50778c2ecf20Sopenharmony_ci	err = set_user_rq_size(dev, init_attr, &ucmd, rwq);
50788c2ecf20Sopenharmony_ci	if (err) {
50798c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "err %d\n", err);
50808c2ecf20Sopenharmony_ci		return err;
50818c2ecf20Sopenharmony_ci	}
50828c2ecf20Sopenharmony_ci
50838c2ecf20Sopenharmony_ci	err = create_user_rq(dev, pd, udata, rwq, &ucmd);
50848c2ecf20Sopenharmony_ci	if (err) {
50858c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "err %d\n", err);
50868c2ecf20Sopenharmony_ci		return err;
50878c2ecf20Sopenharmony_ci	}
50888c2ecf20Sopenharmony_ci
50898c2ecf20Sopenharmony_ci	rwq->user_index = ucmd.user_index;
50908c2ecf20Sopenharmony_ci	return 0;
50918c2ecf20Sopenharmony_ci}
50928c2ecf20Sopenharmony_ci
50938c2ecf20Sopenharmony_cistruct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
50948c2ecf20Sopenharmony_ci				struct ib_wq_init_attr *init_attr,
50958c2ecf20Sopenharmony_ci				struct ib_udata *udata)
50968c2ecf20Sopenharmony_ci{
50978c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev;
50988c2ecf20Sopenharmony_ci	struct mlx5_ib_rwq *rwq;
50998c2ecf20Sopenharmony_ci	struct mlx5_ib_create_wq_resp resp = {};
51008c2ecf20Sopenharmony_ci	size_t min_resp_len;
51018c2ecf20Sopenharmony_ci	int err;
51028c2ecf20Sopenharmony_ci
51038c2ecf20Sopenharmony_ci	if (!udata)
51048c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOSYS);
51058c2ecf20Sopenharmony_ci
51068c2ecf20Sopenharmony_ci	min_resp_len = offsetofend(struct mlx5_ib_create_wq_resp, reserved);
51078c2ecf20Sopenharmony_ci	if (udata->outlen && udata->outlen < min_resp_len)
51088c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
51098c2ecf20Sopenharmony_ci
51108c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_RAWIO) &&
51118c2ecf20Sopenharmony_ci	    init_attr->create_flags & IB_WQ_FLAGS_DELAY_DROP)
51128c2ecf20Sopenharmony_ci		return ERR_PTR(-EPERM);
51138c2ecf20Sopenharmony_ci
51148c2ecf20Sopenharmony_ci	dev = to_mdev(pd->device);
51158c2ecf20Sopenharmony_ci	switch (init_attr->wq_type) {
51168c2ecf20Sopenharmony_ci	case IB_WQT_RQ:
51178c2ecf20Sopenharmony_ci		rwq = kzalloc(sizeof(*rwq), GFP_KERNEL);
51188c2ecf20Sopenharmony_ci		if (!rwq)
51198c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOMEM);
51208c2ecf20Sopenharmony_ci		err = prepare_user_rq(pd, init_attr, udata, rwq);
51218c2ecf20Sopenharmony_ci		if (err)
51228c2ecf20Sopenharmony_ci			goto err;
51238c2ecf20Sopenharmony_ci		err = create_rq(rwq, pd, init_attr);
51248c2ecf20Sopenharmony_ci		if (err)
51258c2ecf20Sopenharmony_ci			goto err_user_rq;
51268c2ecf20Sopenharmony_ci		break;
51278c2ecf20Sopenharmony_ci	default:
51288c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "unsupported wq type %d\n",
51298c2ecf20Sopenharmony_ci			    init_attr->wq_type);
51308c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
51318c2ecf20Sopenharmony_ci	}
51328c2ecf20Sopenharmony_ci
51338c2ecf20Sopenharmony_ci	rwq->ibwq.wq_num = rwq->core_qp.qpn;
51348c2ecf20Sopenharmony_ci	rwq->ibwq.state = IB_WQS_RESET;
51358c2ecf20Sopenharmony_ci	if (udata->outlen) {
51368c2ecf20Sopenharmony_ci		resp.response_length = offsetofend(
51378c2ecf20Sopenharmony_ci			struct mlx5_ib_create_wq_resp, response_length);
51388c2ecf20Sopenharmony_ci		err = ib_copy_to_udata(udata, &resp, resp.response_length);
51398c2ecf20Sopenharmony_ci		if (err)
51408c2ecf20Sopenharmony_ci			goto err_copy;
51418c2ecf20Sopenharmony_ci	}
51428c2ecf20Sopenharmony_ci
51438c2ecf20Sopenharmony_ci	rwq->core_qp.event = mlx5_ib_wq_event;
51448c2ecf20Sopenharmony_ci	rwq->ibwq.event_handler = init_attr->event_handler;
51458c2ecf20Sopenharmony_ci	return &rwq->ibwq;
51468c2ecf20Sopenharmony_ci
51478c2ecf20Sopenharmony_cierr_copy:
51488c2ecf20Sopenharmony_ci	mlx5_core_destroy_rq_tracked(dev, &rwq->core_qp);
51498c2ecf20Sopenharmony_cierr_user_rq:
51508c2ecf20Sopenharmony_ci	destroy_user_rq(dev, pd, rwq, udata);
51518c2ecf20Sopenharmony_cierr:
51528c2ecf20Sopenharmony_ci	kfree(rwq);
51538c2ecf20Sopenharmony_ci	return ERR_PTR(err);
51548c2ecf20Sopenharmony_ci}
51558c2ecf20Sopenharmony_ci
51568c2ecf20Sopenharmony_ciint mlx5_ib_destroy_wq(struct ib_wq *wq, struct ib_udata *udata)
51578c2ecf20Sopenharmony_ci{
51588c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(wq->device);
51598c2ecf20Sopenharmony_ci	struct mlx5_ib_rwq *rwq = to_mrwq(wq);
51608c2ecf20Sopenharmony_ci	int ret;
51618c2ecf20Sopenharmony_ci
51628c2ecf20Sopenharmony_ci	ret = mlx5_core_destroy_rq_tracked(dev, &rwq->core_qp);
51638c2ecf20Sopenharmony_ci	if (ret)
51648c2ecf20Sopenharmony_ci		return ret;
51658c2ecf20Sopenharmony_ci	destroy_user_rq(dev, wq->pd, rwq, udata);
51668c2ecf20Sopenharmony_ci	kfree(rwq);
51678c2ecf20Sopenharmony_ci	return 0;
51688c2ecf20Sopenharmony_ci}
51698c2ecf20Sopenharmony_ci
51708c2ecf20Sopenharmony_ciint mlx5_ib_create_rwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_table,
51718c2ecf20Sopenharmony_ci				 struct ib_rwq_ind_table_init_attr *init_attr,
51728c2ecf20Sopenharmony_ci				 struct ib_udata *udata)
51738c2ecf20Sopenharmony_ci{
51748c2ecf20Sopenharmony_ci	struct mlx5_ib_rwq_ind_table *rwq_ind_tbl =
51758c2ecf20Sopenharmony_ci		to_mrwq_ind_table(ib_rwq_ind_table);
51768c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ib_rwq_ind_table->device);
51778c2ecf20Sopenharmony_ci	int sz = 1 << init_attr->log_ind_tbl_size;
51788c2ecf20Sopenharmony_ci	struct mlx5_ib_create_rwq_ind_tbl_resp resp = {};
51798c2ecf20Sopenharmony_ci	size_t min_resp_len;
51808c2ecf20Sopenharmony_ci	int inlen;
51818c2ecf20Sopenharmony_ci	int err;
51828c2ecf20Sopenharmony_ci	int i;
51838c2ecf20Sopenharmony_ci	u32 *in;
51848c2ecf20Sopenharmony_ci	void *rqtc;
51858c2ecf20Sopenharmony_ci
51868c2ecf20Sopenharmony_ci	if (udata->inlen > 0 &&
51878c2ecf20Sopenharmony_ci	    !ib_is_udata_cleared(udata, 0,
51888c2ecf20Sopenharmony_ci				 udata->inlen))
51898c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
51908c2ecf20Sopenharmony_ci
51918c2ecf20Sopenharmony_ci	if (init_attr->log_ind_tbl_size >
51928c2ecf20Sopenharmony_ci	    MLX5_CAP_GEN(dev->mdev, log_max_rqt_size)) {
51938c2ecf20Sopenharmony_ci		mlx5_ib_dbg(dev, "log_ind_tbl_size = %d is bigger than supported = %d\n",
51948c2ecf20Sopenharmony_ci			    init_attr->log_ind_tbl_size,
51958c2ecf20Sopenharmony_ci			    MLX5_CAP_GEN(dev->mdev, log_max_rqt_size));
51968c2ecf20Sopenharmony_ci		return -EINVAL;
51978c2ecf20Sopenharmony_ci	}
51988c2ecf20Sopenharmony_ci
51998c2ecf20Sopenharmony_ci	min_resp_len =
52008c2ecf20Sopenharmony_ci		offsetofend(struct mlx5_ib_create_rwq_ind_tbl_resp, reserved);
52018c2ecf20Sopenharmony_ci	if (udata->outlen && udata->outlen < min_resp_len)
52028c2ecf20Sopenharmony_ci		return -EINVAL;
52038c2ecf20Sopenharmony_ci
52048c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz;
52058c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
52068c2ecf20Sopenharmony_ci	if (!in)
52078c2ecf20Sopenharmony_ci		return -ENOMEM;
52088c2ecf20Sopenharmony_ci
52098c2ecf20Sopenharmony_ci	rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context);
52108c2ecf20Sopenharmony_ci
52118c2ecf20Sopenharmony_ci	MLX5_SET(rqtc, rqtc, rqt_actual_size, sz);
52128c2ecf20Sopenharmony_ci	MLX5_SET(rqtc, rqtc, rqt_max_size, sz);
52138c2ecf20Sopenharmony_ci
52148c2ecf20Sopenharmony_ci	for (i = 0; i < sz; i++)
52158c2ecf20Sopenharmony_ci		MLX5_SET(rqtc, rqtc, rq_num[i], init_attr->ind_tbl[i]->wq_num);
52168c2ecf20Sopenharmony_ci
52178c2ecf20Sopenharmony_ci	rwq_ind_tbl->uid = to_mpd(init_attr->ind_tbl[0]->pd)->uid;
52188c2ecf20Sopenharmony_ci	MLX5_SET(create_rqt_in, in, uid, rwq_ind_tbl->uid);
52198c2ecf20Sopenharmony_ci
52208c2ecf20Sopenharmony_ci	err = mlx5_core_create_rqt(dev->mdev, in, inlen, &rwq_ind_tbl->rqtn);
52218c2ecf20Sopenharmony_ci	kvfree(in);
52228c2ecf20Sopenharmony_ci	if (err)
52238c2ecf20Sopenharmony_ci		return err;
52248c2ecf20Sopenharmony_ci
52258c2ecf20Sopenharmony_ci	rwq_ind_tbl->ib_rwq_ind_tbl.ind_tbl_num = rwq_ind_tbl->rqtn;
52268c2ecf20Sopenharmony_ci	if (udata->outlen) {
52278c2ecf20Sopenharmony_ci		resp.response_length =
52288c2ecf20Sopenharmony_ci			offsetofend(struct mlx5_ib_create_rwq_ind_tbl_resp,
52298c2ecf20Sopenharmony_ci				    response_length);
52308c2ecf20Sopenharmony_ci		err = ib_copy_to_udata(udata, &resp, resp.response_length);
52318c2ecf20Sopenharmony_ci		if (err)
52328c2ecf20Sopenharmony_ci			goto err_copy;
52338c2ecf20Sopenharmony_ci	}
52348c2ecf20Sopenharmony_ci
52358c2ecf20Sopenharmony_ci	return 0;
52368c2ecf20Sopenharmony_ci
52378c2ecf20Sopenharmony_cierr_copy:
52388c2ecf20Sopenharmony_ci	mlx5_cmd_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid);
52398c2ecf20Sopenharmony_ci	return err;
52408c2ecf20Sopenharmony_ci}
52418c2ecf20Sopenharmony_ci
52428c2ecf20Sopenharmony_ciint mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_tbl)
52438c2ecf20Sopenharmony_ci{
52448c2ecf20Sopenharmony_ci	struct mlx5_ib_rwq_ind_table *rwq_ind_tbl = to_mrwq_ind_table(ib_rwq_ind_tbl);
52458c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ib_rwq_ind_tbl->device);
52468c2ecf20Sopenharmony_ci
52478c2ecf20Sopenharmony_ci	return mlx5_cmd_destroy_rqt(dev->mdev, rwq_ind_tbl->rqtn, rwq_ind_tbl->uid);
52488c2ecf20Sopenharmony_ci}
52498c2ecf20Sopenharmony_ci
52508c2ecf20Sopenharmony_ciint mlx5_ib_modify_wq(struct ib_wq *wq, struct ib_wq_attr *wq_attr,
52518c2ecf20Sopenharmony_ci		      u32 wq_attr_mask, struct ib_udata *udata)
52528c2ecf20Sopenharmony_ci{
52538c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(wq->device);
52548c2ecf20Sopenharmony_ci	struct mlx5_ib_rwq *rwq = to_mrwq(wq);
52558c2ecf20Sopenharmony_ci	struct mlx5_ib_modify_wq ucmd = {};
52568c2ecf20Sopenharmony_ci	size_t required_cmd_sz;
52578c2ecf20Sopenharmony_ci	int curr_wq_state;
52588c2ecf20Sopenharmony_ci	int wq_state;
52598c2ecf20Sopenharmony_ci	int inlen;
52608c2ecf20Sopenharmony_ci	int err;
52618c2ecf20Sopenharmony_ci	void *rqc;
52628c2ecf20Sopenharmony_ci	void *in;
52638c2ecf20Sopenharmony_ci
52648c2ecf20Sopenharmony_ci	required_cmd_sz = offsetofend(struct mlx5_ib_modify_wq, reserved);
52658c2ecf20Sopenharmony_ci	if (udata->inlen < required_cmd_sz)
52668c2ecf20Sopenharmony_ci		return -EINVAL;
52678c2ecf20Sopenharmony_ci
52688c2ecf20Sopenharmony_ci	if (udata->inlen > sizeof(ucmd) &&
52698c2ecf20Sopenharmony_ci	    !ib_is_udata_cleared(udata, sizeof(ucmd),
52708c2ecf20Sopenharmony_ci				 udata->inlen - sizeof(ucmd)))
52718c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
52728c2ecf20Sopenharmony_ci
52738c2ecf20Sopenharmony_ci	if (ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen)))
52748c2ecf20Sopenharmony_ci		return -EFAULT;
52758c2ecf20Sopenharmony_ci
52768c2ecf20Sopenharmony_ci	if (ucmd.comp_mask || ucmd.reserved)
52778c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
52788c2ecf20Sopenharmony_ci
52798c2ecf20Sopenharmony_ci	inlen = MLX5_ST_SZ_BYTES(modify_rq_in);
52808c2ecf20Sopenharmony_ci	in = kvzalloc(inlen, GFP_KERNEL);
52818c2ecf20Sopenharmony_ci	if (!in)
52828c2ecf20Sopenharmony_ci		return -ENOMEM;
52838c2ecf20Sopenharmony_ci
52848c2ecf20Sopenharmony_ci	rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
52858c2ecf20Sopenharmony_ci
52868c2ecf20Sopenharmony_ci	curr_wq_state = wq_attr->curr_wq_state;
52878c2ecf20Sopenharmony_ci	wq_state = wq_attr->wq_state;
52888c2ecf20Sopenharmony_ci	if (curr_wq_state == IB_WQS_ERR)
52898c2ecf20Sopenharmony_ci		curr_wq_state = MLX5_RQC_STATE_ERR;
52908c2ecf20Sopenharmony_ci	if (wq_state == IB_WQS_ERR)
52918c2ecf20Sopenharmony_ci		wq_state = MLX5_RQC_STATE_ERR;
52928c2ecf20Sopenharmony_ci	MLX5_SET(modify_rq_in, in, rq_state, curr_wq_state);
52938c2ecf20Sopenharmony_ci	MLX5_SET(modify_rq_in, in, uid, to_mpd(wq->pd)->uid);
52948c2ecf20Sopenharmony_ci	MLX5_SET(rqc, rqc, state, wq_state);
52958c2ecf20Sopenharmony_ci
52968c2ecf20Sopenharmony_ci	if (wq_attr_mask & IB_WQ_FLAGS) {
52978c2ecf20Sopenharmony_ci		if (wq_attr->flags_mask & IB_WQ_FLAGS_CVLAN_STRIPPING) {
52988c2ecf20Sopenharmony_ci			if (!(MLX5_CAP_GEN(dev->mdev, eth_net_offloads) &&
52998c2ecf20Sopenharmony_ci			      MLX5_CAP_ETH(dev->mdev, vlan_cap))) {
53008c2ecf20Sopenharmony_ci				mlx5_ib_dbg(dev, "VLAN offloads are not "
53018c2ecf20Sopenharmony_ci					    "supported\n");
53028c2ecf20Sopenharmony_ci				err = -EOPNOTSUPP;
53038c2ecf20Sopenharmony_ci				goto out;
53048c2ecf20Sopenharmony_ci			}
53058c2ecf20Sopenharmony_ci			MLX5_SET64(modify_rq_in, in, modify_bitmask,
53068c2ecf20Sopenharmony_ci				   MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_VSD);
53078c2ecf20Sopenharmony_ci			MLX5_SET(rqc, rqc, vsd,
53088c2ecf20Sopenharmony_ci				 (wq_attr->flags & IB_WQ_FLAGS_CVLAN_STRIPPING) ? 0 : 1);
53098c2ecf20Sopenharmony_ci		}
53108c2ecf20Sopenharmony_ci
53118c2ecf20Sopenharmony_ci		if (wq_attr->flags_mask & IB_WQ_FLAGS_PCI_WRITE_END_PADDING) {
53128c2ecf20Sopenharmony_ci			mlx5_ib_dbg(dev, "Modifying scatter end padding is not supported\n");
53138c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
53148c2ecf20Sopenharmony_ci			goto out;
53158c2ecf20Sopenharmony_ci		}
53168c2ecf20Sopenharmony_ci	}
53178c2ecf20Sopenharmony_ci
53188c2ecf20Sopenharmony_ci	if (curr_wq_state == IB_WQS_RESET && wq_state == IB_WQS_RDY) {
53198c2ecf20Sopenharmony_ci		u16 set_id;
53208c2ecf20Sopenharmony_ci
53218c2ecf20Sopenharmony_ci		set_id = mlx5_ib_get_counters_id(dev, 0);
53228c2ecf20Sopenharmony_ci		if (MLX5_CAP_GEN(dev->mdev, modify_rq_counter_set_id)) {
53238c2ecf20Sopenharmony_ci			MLX5_SET64(modify_rq_in, in, modify_bitmask,
53248c2ecf20Sopenharmony_ci				   MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_RQ_COUNTER_SET_ID);
53258c2ecf20Sopenharmony_ci			MLX5_SET(rqc, rqc, counter_set_id, set_id);
53268c2ecf20Sopenharmony_ci		} else
53278c2ecf20Sopenharmony_ci			dev_info_once(
53288c2ecf20Sopenharmony_ci				&dev->ib_dev.dev,
53298c2ecf20Sopenharmony_ci				"Receive WQ counters are not supported on current FW\n");
53308c2ecf20Sopenharmony_ci	}
53318c2ecf20Sopenharmony_ci
53328c2ecf20Sopenharmony_ci	err = mlx5_core_modify_rq(dev->mdev, rwq->core_qp.qpn, in);
53338c2ecf20Sopenharmony_ci	if (!err)
53348c2ecf20Sopenharmony_ci		rwq->ibwq.state = (wq_state == MLX5_RQC_STATE_ERR) ? IB_WQS_ERR : wq_state;
53358c2ecf20Sopenharmony_ci
53368c2ecf20Sopenharmony_ciout:
53378c2ecf20Sopenharmony_ci	kvfree(in);
53388c2ecf20Sopenharmony_ci	return err;
53398c2ecf20Sopenharmony_ci}
53408c2ecf20Sopenharmony_ci
53418c2ecf20Sopenharmony_cistruct mlx5_ib_drain_cqe {
53428c2ecf20Sopenharmony_ci	struct ib_cqe cqe;
53438c2ecf20Sopenharmony_ci	struct completion done;
53448c2ecf20Sopenharmony_ci};
53458c2ecf20Sopenharmony_ci
53468c2ecf20Sopenharmony_cistatic void mlx5_ib_drain_qp_done(struct ib_cq *cq, struct ib_wc *wc)
53478c2ecf20Sopenharmony_ci{
53488c2ecf20Sopenharmony_ci	struct mlx5_ib_drain_cqe *cqe = container_of(wc->wr_cqe,
53498c2ecf20Sopenharmony_ci						     struct mlx5_ib_drain_cqe,
53508c2ecf20Sopenharmony_ci						     cqe);
53518c2ecf20Sopenharmony_ci
53528c2ecf20Sopenharmony_ci	complete(&cqe->done);
53538c2ecf20Sopenharmony_ci}
53548c2ecf20Sopenharmony_ci
53558c2ecf20Sopenharmony_ci/* This function returns only once the drained WR was completed */
53568c2ecf20Sopenharmony_cistatic void handle_drain_completion(struct ib_cq *cq,
53578c2ecf20Sopenharmony_ci				    struct mlx5_ib_drain_cqe *sdrain,
53588c2ecf20Sopenharmony_ci				    struct mlx5_ib_dev *dev)
53598c2ecf20Sopenharmony_ci{
53608c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
53618c2ecf20Sopenharmony_ci
53628c2ecf20Sopenharmony_ci	if (cq->poll_ctx == IB_POLL_DIRECT) {
53638c2ecf20Sopenharmony_ci		while (wait_for_completion_timeout(&sdrain->done, HZ / 10) <= 0)
53648c2ecf20Sopenharmony_ci			ib_process_cq_direct(cq, -1);
53658c2ecf20Sopenharmony_ci		return;
53668c2ecf20Sopenharmony_ci	}
53678c2ecf20Sopenharmony_ci
53688c2ecf20Sopenharmony_ci	if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
53698c2ecf20Sopenharmony_ci		struct mlx5_ib_cq *mcq = to_mcq(cq);
53708c2ecf20Sopenharmony_ci		bool triggered = false;
53718c2ecf20Sopenharmony_ci		unsigned long flags;
53728c2ecf20Sopenharmony_ci
53738c2ecf20Sopenharmony_ci		spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
53748c2ecf20Sopenharmony_ci		/* Make sure that the CQ handler won't run if wasn't run yet */
53758c2ecf20Sopenharmony_ci		if (!mcq->mcq.reset_notify_added)
53768c2ecf20Sopenharmony_ci			mcq->mcq.reset_notify_added = 1;
53778c2ecf20Sopenharmony_ci		else
53788c2ecf20Sopenharmony_ci			triggered = true;
53798c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
53808c2ecf20Sopenharmony_ci
53818c2ecf20Sopenharmony_ci		if (triggered) {
53828c2ecf20Sopenharmony_ci			/* Wait for any scheduled/running task to be ended */
53838c2ecf20Sopenharmony_ci			switch (cq->poll_ctx) {
53848c2ecf20Sopenharmony_ci			case IB_POLL_SOFTIRQ:
53858c2ecf20Sopenharmony_ci				irq_poll_disable(&cq->iop);
53868c2ecf20Sopenharmony_ci				irq_poll_enable(&cq->iop);
53878c2ecf20Sopenharmony_ci				break;
53888c2ecf20Sopenharmony_ci			case IB_POLL_WORKQUEUE:
53898c2ecf20Sopenharmony_ci				cancel_work_sync(&cq->work);
53908c2ecf20Sopenharmony_ci				break;
53918c2ecf20Sopenharmony_ci			default:
53928c2ecf20Sopenharmony_ci				WARN_ON_ONCE(1);
53938c2ecf20Sopenharmony_ci			}
53948c2ecf20Sopenharmony_ci		}
53958c2ecf20Sopenharmony_ci
53968c2ecf20Sopenharmony_ci		/* Run the CQ handler - this makes sure that the drain WR will
53978c2ecf20Sopenharmony_ci		 * be processed if wasn't processed yet.
53988c2ecf20Sopenharmony_ci		 */
53998c2ecf20Sopenharmony_ci		mcq->mcq.comp(&mcq->mcq, NULL);
54008c2ecf20Sopenharmony_ci	}
54018c2ecf20Sopenharmony_ci
54028c2ecf20Sopenharmony_ci	wait_for_completion(&sdrain->done);
54038c2ecf20Sopenharmony_ci}
54048c2ecf20Sopenharmony_ci
54058c2ecf20Sopenharmony_civoid mlx5_ib_drain_sq(struct ib_qp *qp)
54068c2ecf20Sopenharmony_ci{
54078c2ecf20Sopenharmony_ci	struct ib_cq *cq = qp->send_cq;
54088c2ecf20Sopenharmony_ci	struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR };
54098c2ecf20Sopenharmony_ci	struct mlx5_ib_drain_cqe sdrain;
54108c2ecf20Sopenharmony_ci	const struct ib_send_wr *bad_swr;
54118c2ecf20Sopenharmony_ci	struct ib_rdma_wr swr = {
54128c2ecf20Sopenharmony_ci		.wr = {
54138c2ecf20Sopenharmony_ci			.next = NULL,
54148c2ecf20Sopenharmony_ci			{ .wr_cqe	= &sdrain.cqe, },
54158c2ecf20Sopenharmony_ci			.opcode	= IB_WR_RDMA_WRITE,
54168c2ecf20Sopenharmony_ci		},
54178c2ecf20Sopenharmony_ci	};
54188c2ecf20Sopenharmony_ci	int ret;
54198c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(qp->device);
54208c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
54218c2ecf20Sopenharmony_ci
54228c2ecf20Sopenharmony_ci	ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
54238c2ecf20Sopenharmony_ci	if (ret && mdev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR) {
54248c2ecf20Sopenharmony_ci		WARN_ONCE(ret, "failed to drain send queue: %d\n", ret);
54258c2ecf20Sopenharmony_ci		return;
54268c2ecf20Sopenharmony_ci	}
54278c2ecf20Sopenharmony_ci
54288c2ecf20Sopenharmony_ci	sdrain.cqe.done = mlx5_ib_drain_qp_done;
54298c2ecf20Sopenharmony_ci	init_completion(&sdrain.done);
54308c2ecf20Sopenharmony_ci
54318c2ecf20Sopenharmony_ci	ret = mlx5_ib_post_send_drain(qp, &swr.wr, &bad_swr);
54328c2ecf20Sopenharmony_ci	if (ret) {
54338c2ecf20Sopenharmony_ci		WARN_ONCE(ret, "failed to drain send queue: %d\n", ret);
54348c2ecf20Sopenharmony_ci		return;
54358c2ecf20Sopenharmony_ci	}
54368c2ecf20Sopenharmony_ci
54378c2ecf20Sopenharmony_ci	handle_drain_completion(cq, &sdrain, dev);
54388c2ecf20Sopenharmony_ci}
54398c2ecf20Sopenharmony_ci
54408c2ecf20Sopenharmony_civoid mlx5_ib_drain_rq(struct ib_qp *qp)
54418c2ecf20Sopenharmony_ci{
54428c2ecf20Sopenharmony_ci	struct ib_cq *cq = qp->recv_cq;
54438c2ecf20Sopenharmony_ci	struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR };
54448c2ecf20Sopenharmony_ci	struct mlx5_ib_drain_cqe rdrain;
54458c2ecf20Sopenharmony_ci	struct ib_recv_wr rwr = {};
54468c2ecf20Sopenharmony_ci	const struct ib_recv_wr *bad_rwr;
54478c2ecf20Sopenharmony_ci	int ret;
54488c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(qp->device);
54498c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
54508c2ecf20Sopenharmony_ci
54518c2ecf20Sopenharmony_ci	ret = ib_modify_qp(qp, &attr, IB_QP_STATE);
54528c2ecf20Sopenharmony_ci	if (ret && mdev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR) {
54538c2ecf20Sopenharmony_ci		WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret);
54548c2ecf20Sopenharmony_ci		return;
54558c2ecf20Sopenharmony_ci	}
54568c2ecf20Sopenharmony_ci
54578c2ecf20Sopenharmony_ci	rwr.wr_cqe = &rdrain.cqe;
54588c2ecf20Sopenharmony_ci	rdrain.cqe.done = mlx5_ib_drain_qp_done;
54598c2ecf20Sopenharmony_ci	init_completion(&rdrain.done);
54608c2ecf20Sopenharmony_ci
54618c2ecf20Sopenharmony_ci	ret = mlx5_ib_post_recv_drain(qp, &rwr, &bad_rwr);
54628c2ecf20Sopenharmony_ci	if (ret) {
54638c2ecf20Sopenharmony_ci		WARN_ONCE(ret, "failed to drain recv queue: %d\n", ret);
54648c2ecf20Sopenharmony_ci		return;
54658c2ecf20Sopenharmony_ci	}
54668c2ecf20Sopenharmony_ci
54678c2ecf20Sopenharmony_ci	handle_drain_completion(cq, &rdrain, dev);
54688c2ecf20Sopenharmony_ci}
54698c2ecf20Sopenharmony_ci
54708c2ecf20Sopenharmony_ci/**
54718c2ecf20Sopenharmony_ci * Bind a qp to a counter. If @counter is NULL then bind the qp to
54728c2ecf20Sopenharmony_ci * the default counter
54738c2ecf20Sopenharmony_ci */
54748c2ecf20Sopenharmony_ciint mlx5_ib_qp_set_counter(struct ib_qp *qp, struct rdma_counter *counter)
54758c2ecf20Sopenharmony_ci{
54768c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(qp->device);
54778c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *mqp = to_mqp(qp);
54788c2ecf20Sopenharmony_ci	int err = 0;
54798c2ecf20Sopenharmony_ci
54808c2ecf20Sopenharmony_ci	mutex_lock(&mqp->mutex);
54818c2ecf20Sopenharmony_ci	if (mqp->state == IB_QPS_RESET) {
54828c2ecf20Sopenharmony_ci		qp->counter = counter;
54838c2ecf20Sopenharmony_ci		goto out;
54848c2ecf20Sopenharmony_ci	}
54858c2ecf20Sopenharmony_ci
54868c2ecf20Sopenharmony_ci	if (!MLX5_CAP_GEN(dev->mdev, rts2rts_qp_counters_set_id)) {
54878c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
54888c2ecf20Sopenharmony_ci		goto out;
54898c2ecf20Sopenharmony_ci	}
54908c2ecf20Sopenharmony_ci
54918c2ecf20Sopenharmony_ci	if (mqp->state == IB_QPS_RTS) {
54928c2ecf20Sopenharmony_ci		err = __mlx5_ib_qp_set_counter(qp, counter);
54938c2ecf20Sopenharmony_ci		if (!err)
54948c2ecf20Sopenharmony_ci			qp->counter = counter;
54958c2ecf20Sopenharmony_ci
54968c2ecf20Sopenharmony_ci		goto out;
54978c2ecf20Sopenharmony_ci	}
54988c2ecf20Sopenharmony_ci
54998c2ecf20Sopenharmony_ci	mqp->counter_pending = 1;
55008c2ecf20Sopenharmony_ci	qp->counter = counter;
55018c2ecf20Sopenharmony_ci
55028c2ecf20Sopenharmony_ciout:
55038c2ecf20Sopenharmony_ci	mutex_unlock(&mqp->mutex);
55048c2ecf20Sopenharmony_ci	return err;
55058c2ecf20Sopenharmony_ci}
5506