18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2020, Mellanox Technologies inc. All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/gfp.h>
78c2ecf20Sopenharmony_ci#include <linux/mlx5/qp.h>
88c2ecf20Sopenharmony_ci#include <linux/mlx5/driver.h>
98c2ecf20Sopenharmony_ci#include "wr.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic const u32 mlx5_ib_opcode[] = {
128c2ecf20Sopenharmony_ci	[IB_WR_SEND]				= MLX5_OPCODE_SEND,
138c2ecf20Sopenharmony_ci	[IB_WR_LSO]				= MLX5_OPCODE_LSO,
148c2ecf20Sopenharmony_ci	[IB_WR_SEND_WITH_IMM]			= MLX5_OPCODE_SEND_IMM,
158c2ecf20Sopenharmony_ci	[IB_WR_RDMA_WRITE]			= MLX5_OPCODE_RDMA_WRITE,
168c2ecf20Sopenharmony_ci	[IB_WR_RDMA_WRITE_WITH_IMM]		= MLX5_OPCODE_RDMA_WRITE_IMM,
178c2ecf20Sopenharmony_ci	[IB_WR_RDMA_READ]			= MLX5_OPCODE_RDMA_READ,
188c2ecf20Sopenharmony_ci	[IB_WR_ATOMIC_CMP_AND_SWP]		= MLX5_OPCODE_ATOMIC_CS,
198c2ecf20Sopenharmony_ci	[IB_WR_ATOMIC_FETCH_AND_ADD]		= MLX5_OPCODE_ATOMIC_FA,
208c2ecf20Sopenharmony_ci	[IB_WR_SEND_WITH_INV]			= MLX5_OPCODE_SEND_INVAL,
218c2ecf20Sopenharmony_ci	[IB_WR_LOCAL_INV]			= MLX5_OPCODE_UMR,
228c2ecf20Sopenharmony_ci	[IB_WR_REG_MR]				= MLX5_OPCODE_UMR,
238c2ecf20Sopenharmony_ci	[IB_WR_MASKED_ATOMIC_CMP_AND_SWP]	= MLX5_OPCODE_ATOMIC_MASKED_CS,
248c2ecf20Sopenharmony_ci	[IB_WR_MASKED_ATOMIC_FETCH_AND_ADD]	= MLX5_OPCODE_ATOMIC_MASKED_FA,
258c2ecf20Sopenharmony_ci	[MLX5_IB_WR_UMR]			= MLX5_OPCODE_UMR,
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* handle_post_send_edge - Check if we get to SQ edge. If yes, update to the
298c2ecf20Sopenharmony_ci * next nearby edge and get new address translation for current WQE position.
308c2ecf20Sopenharmony_ci * @sq - SQ buffer.
318c2ecf20Sopenharmony_ci * @seg: Current WQE position (16B aligned).
328c2ecf20Sopenharmony_ci * @wqe_sz: Total current WQE size [16B].
338c2ecf20Sopenharmony_ci * @cur_edge: Updated current edge.
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_cistatic inline void handle_post_send_edge(struct mlx5_ib_wq *sq, void **seg,
368c2ecf20Sopenharmony_ci					 u32 wqe_sz, void **cur_edge)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	u32 idx;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (likely(*seg != *cur_edge))
418c2ecf20Sopenharmony_ci		return;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	idx = (sq->cur_post + (wqe_sz >> 2)) & (sq->wqe_cnt - 1);
448c2ecf20Sopenharmony_ci	*cur_edge = get_sq_edge(sq, idx);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	*seg = mlx5_frag_buf_get_wqe(&sq->fbc, idx);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* memcpy_send_wqe - copy data from src to WQE and update the relevant WQ's
508c2ecf20Sopenharmony_ci * pointers. At the end @seg is aligned to 16B regardless the copied size.
518c2ecf20Sopenharmony_ci * @sq - SQ buffer.
528c2ecf20Sopenharmony_ci * @cur_edge: Updated current edge.
538c2ecf20Sopenharmony_ci * @seg: Current WQE position (16B aligned).
548c2ecf20Sopenharmony_ci * @wqe_sz: Total current WQE size [16B].
558c2ecf20Sopenharmony_ci * @src: Pointer to copy from.
568c2ecf20Sopenharmony_ci * @n: Number of bytes to copy.
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_cistatic inline void memcpy_send_wqe(struct mlx5_ib_wq *sq, void **cur_edge,
598c2ecf20Sopenharmony_ci				   void **seg, u32 *wqe_sz, const void *src,
608c2ecf20Sopenharmony_ci				   size_t n)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	while (likely(n)) {
638c2ecf20Sopenharmony_ci		size_t leftlen = *cur_edge - *seg;
648c2ecf20Sopenharmony_ci		size_t copysz = min_t(size_t, leftlen, n);
658c2ecf20Sopenharmony_ci		size_t stride;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci		memcpy(*seg, src, copysz);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		n -= copysz;
708c2ecf20Sopenharmony_ci		src += copysz;
718c2ecf20Sopenharmony_ci		stride = !n ? ALIGN(copysz, 16) : copysz;
728c2ecf20Sopenharmony_ci		*seg += stride;
738c2ecf20Sopenharmony_ci		*wqe_sz += stride >> 4;
748c2ecf20Sopenharmony_ci		handle_post_send_edge(sq, seg, *wqe_sz, cur_edge);
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic int mlx5_wq_overflow(struct mlx5_ib_wq *wq, int nreq,
798c2ecf20Sopenharmony_ci			    struct ib_cq *ib_cq)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	struct mlx5_ib_cq *cq;
828c2ecf20Sopenharmony_ci	unsigned int cur;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	cur = wq->head - wq->tail;
858c2ecf20Sopenharmony_ci	if (likely(cur + nreq < wq->max_post))
868c2ecf20Sopenharmony_ci		return 0;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	cq = to_mcq(ib_cq);
898c2ecf20Sopenharmony_ci	spin_lock(&cq->lock);
908c2ecf20Sopenharmony_ci	cur = wq->head - wq->tail;
918c2ecf20Sopenharmony_ci	spin_unlock(&cq->lock);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	return cur + nreq >= wq->max_post;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic __always_inline void set_raddr_seg(struct mlx5_wqe_raddr_seg *rseg,
978c2ecf20Sopenharmony_ci					  u64 remote_addr, u32 rkey)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	rseg->raddr    = cpu_to_be64(remote_addr);
1008c2ecf20Sopenharmony_ci	rseg->rkey     = cpu_to_be32(rkey);
1018c2ecf20Sopenharmony_ci	rseg->reserved = 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic void set_eth_seg(const struct ib_send_wr *wr, struct mlx5_ib_qp *qp,
1058c2ecf20Sopenharmony_ci			void **seg, int *size, void **cur_edge)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct mlx5_wqe_eth_seg *eseg = *seg;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	memset(eseg, 0, sizeof(struct mlx5_wqe_eth_seg));
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (wr->send_flags & IB_SEND_IP_CSUM)
1128c2ecf20Sopenharmony_ci		eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM |
1138c2ecf20Sopenharmony_ci				 MLX5_ETH_WQE_L4_CSUM;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (wr->opcode == IB_WR_LSO) {
1168c2ecf20Sopenharmony_ci		struct ib_ud_wr *ud_wr = container_of(wr, struct ib_ud_wr, wr);
1178c2ecf20Sopenharmony_ci		size_t left, copysz;
1188c2ecf20Sopenharmony_ci		void *pdata = ud_wr->header;
1198c2ecf20Sopenharmony_ci		size_t stride;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		left = ud_wr->hlen;
1228c2ecf20Sopenharmony_ci		eseg->mss = cpu_to_be16(ud_wr->mss);
1238c2ecf20Sopenharmony_ci		eseg->inline_hdr.sz = cpu_to_be16(left);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci		/* memcpy_send_wqe should get a 16B align address. Hence, we
1268c2ecf20Sopenharmony_ci		 * first copy up to the current edge and then, if needed,
1278c2ecf20Sopenharmony_ci		 * continue to memcpy_send_wqe.
1288c2ecf20Sopenharmony_ci		 */
1298c2ecf20Sopenharmony_ci		copysz = min_t(u64, *cur_edge - (void *)eseg->inline_hdr.start,
1308c2ecf20Sopenharmony_ci			       left);
1318c2ecf20Sopenharmony_ci		memcpy(eseg->inline_hdr.start, pdata, copysz);
1328c2ecf20Sopenharmony_ci		stride = ALIGN(sizeof(struct mlx5_wqe_eth_seg) -
1338c2ecf20Sopenharmony_ci			       sizeof(eseg->inline_hdr.start) + copysz, 16);
1348c2ecf20Sopenharmony_ci		*size += stride / 16;
1358c2ecf20Sopenharmony_ci		*seg += stride;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		if (copysz < left) {
1388c2ecf20Sopenharmony_ci			handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
1398c2ecf20Sopenharmony_ci			left -= copysz;
1408c2ecf20Sopenharmony_ci			pdata += copysz;
1418c2ecf20Sopenharmony_ci			memcpy_send_wqe(&qp->sq, cur_edge, seg, size, pdata,
1428c2ecf20Sopenharmony_ci					left);
1438c2ecf20Sopenharmony_ci		}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci		return;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_wqe_eth_seg);
1498c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_wqe_eth_seg) / 16;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic void set_datagram_seg(struct mlx5_wqe_datagram_seg *dseg,
1538c2ecf20Sopenharmony_ci			     const struct ib_send_wr *wr)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	memcpy(&dseg->av, &to_mah(ud_wr(wr)->ah)->av, sizeof(struct mlx5_av));
1568c2ecf20Sopenharmony_ci	dseg->av.dqp_dct =
1578c2ecf20Sopenharmony_ci		cpu_to_be32(ud_wr(wr)->remote_qpn | MLX5_EXTENDED_UD_AV);
1588c2ecf20Sopenharmony_ci	dseg->av.key.qkey.qkey = cpu_to_be32(ud_wr(wr)->remote_qkey);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic void set_data_ptr_seg(struct mlx5_wqe_data_seg *dseg, struct ib_sge *sg)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	dseg->byte_count = cpu_to_be32(sg->length);
1648c2ecf20Sopenharmony_ci	dseg->lkey       = cpu_to_be32(sg->lkey);
1658c2ecf20Sopenharmony_ci	dseg->addr       = cpu_to_be64(sg->addr);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic u64 get_xlt_octo(u64 bytes)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	return ALIGN(bytes, MLX5_IB_UMR_XLT_ALIGNMENT) /
1718c2ecf20Sopenharmony_ci	       MLX5_IB_UMR_OCTOWORD;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic __be64 frwr_mkey_mask(bool atomic)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	u64 result;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	result = MLX5_MKEY_MASK_LEN		|
1798c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_PAGE_SIZE	|
1808c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_START_ADDR	|
1818c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_EN_RINVAL	|
1828c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_KEY		|
1838c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_LR		|
1848c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_LW		|
1858c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_RR		|
1868c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_RW		|
1878c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_SMALL_FENCE	|
1888c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_FREE;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (atomic)
1918c2ecf20Sopenharmony_ci		result |= MLX5_MKEY_MASK_A;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return cpu_to_be64(result);
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic __be64 sig_mkey_mask(void)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	u64 result;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	result = MLX5_MKEY_MASK_LEN		|
2018c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_PAGE_SIZE	|
2028c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_START_ADDR	|
2038c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_EN_SIGERR	|
2048c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_EN_RINVAL	|
2058c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_KEY		|
2068c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_LR		|
2078c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_LW		|
2088c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_RR		|
2098c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_RW		|
2108c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_SMALL_FENCE	|
2118c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_FREE		|
2128c2ecf20Sopenharmony_ci		MLX5_MKEY_MASK_BSF_EN;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return cpu_to_be64(result);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic void set_reg_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr,
2188c2ecf20Sopenharmony_ci			    struct mlx5_ib_mr *mr, u8 flags, bool atomic)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	int size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	memset(umr, 0, sizeof(*umr));
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	umr->flags = flags;
2258c2ecf20Sopenharmony_ci	umr->xlt_octowords = cpu_to_be16(get_xlt_octo(size));
2268c2ecf20Sopenharmony_ci	umr->mkey_mask = frwr_mkey_mask(atomic);
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic void set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	memset(umr, 0, sizeof(*umr));
2328c2ecf20Sopenharmony_ci	umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
2338c2ecf20Sopenharmony_ci	umr->flags = MLX5_UMR_INLINE;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic __be64 get_umr_enable_mr_mask(void)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	u64 result;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	result = MLX5_MKEY_MASK_KEY |
2418c2ecf20Sopenharmony_ci		 MLX5_MKEY_MASK_FREE;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return cpu_to_be64(result);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic __be64 get_umr_disable_mr_mask(void)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	u64 result;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	result = MLX5_MKEY_MASK_FREE;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return cpu_to_be64(result);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic __be64 get_umr_update_translation_mask(void)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	u64 result;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	result = MLX5_MKEY_MASK_LEN |
2608c2ecf20Sopenharmony_ci		 MLX5_MKEY_MASK_PAGE_SIZE |
2618c2ecf20Sopenharmony_ci		 MLX5_MKEY_MASK_START_ADDR;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return cpu_to_be64(result);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic __be64 get_umr_update_access_mask(int atomic,
2678c2ecf20Sopenharmony_ci					 int relaxed_ordering_write,
2688c2ecf20Sopenharmony_ci					 int relaxed_ordering_read)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	u64 result;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	result = MLX5_MKEY_MASK_LR |
2738c2ecf20Sopenharmony_ci		 MLX5_MKEY_MASK_LW |
2748c2ecf20Sopenharmony_ci		 MLX5_MKEY_MASK_RR |
2758c2ecf20Sopenharmony_ci		 MLX5_MKEY_MASK_RW;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (atomic)
2788c2ecf20Sopenharmony_ci		result |= MLX5_MKEY_MASK_A;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	if (relaxed_ordering_write)
2818c2ecf20Sopenharmony_ci		result |= MLX5_MKEY_MASK_RELAXED_ORDERING_WRITE;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (relaxed_ordering_read)
2848c2ecf20Sopenharmony_ci		result |= MLX5_MKEY_MASK_RELAXED_ORDERING_READ;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return cpu_to_be64(result);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic __be64 get_umr_update_pd_mask(void)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	u64 result;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	result = MLX5_MKEY_MASK_PD;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	return cpu_to_be64(result);
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int umr_check_mkey_mask(struct mlx5_ib_dev *dev, u64 mask)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	if (mask & MLX5_MKEY_MASK_PAGE_SIZE &&
3018c2ecf20Sopenharmony_ci	    MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled))
3028c2ecf20Sopenharmony_ci		return -EPERM;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (mask & MLX5_MKEY_MASK_A &&
3058c2ecf20Sopenharmony_ci	    MLX5_CAP_GEN(dev->mdev, umr_modify_atomic_disabled))
3068c2ecf20Sopenharmony_ci		return -EPERM;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (mask & MLX5_MKEY_MASK_RELAXED_ORDERING_WRITE &&
3098c2ecf20Sopenharmony_ci	    !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write_umr))
3108c2ecf20Sopenharmony_ci		return -EPERM;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (mask & MLX5_MKEY_MASK_RELAXED_ORDERING_READ &&
3138c2ecf20Sopenharmony_ci	    !MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr))
3148c2ecf20Sopenharmony_ci		return -EPERM;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic int set_reg_umr_segment(struct mlx5_ib_dev *dev,
3208c2ecf20Sopenharmony_ci			       struct mlx5_wqe_umr_ctrl_seg *umr,
3218c2ecf20Sopenharmony_ci			       const struct ib_send_wr *wr)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	const struct mlx5_umr_wr *umrwr = umr_wr(wr);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	memset(umr, 0, sizeof(*umr));
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (!umrwr->ignore_free_state) {
3288c2ecf20Sopenharmony_ci		if (wr->send_flags & MLX5_IB_SEND_UMR_FAIL_IF_FREE)
3298c2ecf20Sopenharmony_ci			 /* fail if free */
3308c2ecf20Sopenharmony_ci			umr->flags = MLX5_UMR_CHECK_FREE;
3318c2ecf20Sopenharmony_ci		else
3328c2ecf20Sopenharmony_ci			/* fail if not free */
3338c2ecf20Sopenharmony_ci			umr->flags = MLX5_UMR_CHECK_NOT_FREE;
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	umr->xlt_octowords = cpu_to_be16(get_xlt_octo(umrwr->xlt_size));
3378c2ecf20Sopenharmony_ci	if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_XLT) {
3388c2ecf20Sopenharmony_ci		u64 offset = get_xlt_octo(umrwr->offset);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		umr->xlt_offset = cpu_to_be16(offset & 0xffff);
3418c2ecf20Sopenharmony_ci		umr->xlt_offset_47_16 = cpu_to_be32(offset >> 16);
3428c2ecf20Sopenharmony_ci		umr->flags |= MLX5_UMR_TRANSLATION_OFFSET_EN;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_TRANSLATION)
3458c2ecf20Sopenharmony_ci		umr->mkey_mask |= get_umr_update_translation_mask();
3468c2ecf20Sopenharmony_ci	if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_PD_ACCESS) {
3478c2ecf20Sopenharmony_ci		umr->mkey_mask |= get_umr_update_access_mask(
3488c2ecf20Sopenharmony_ci			!!(MLX5_CAP_GEN(dev->mdev, atomic)),
3498c2ecf20Sopenharmony_ci			!!(MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write_umr)),
3508c2ecf20Sopenharmony_ci			!!(MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr)));
3518c2ecf20Sopenharmony_ci		umr->mkey_mask |= get_umr_update_pd_mask();
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci	if (wr->send_flags & MLX5_IB_SEND_UMR_ENABLE_MR)
3548c2ecf20Sopenharmony_ci		umr->mkey_mask |= get_umr_enable_mr_mask();
3558c2ecf20Sopenharmony_ci	if (wr->send_flags & MLX5_IB_SEND_UMR_DISABLE_MR)
3568c2ecf20Sopenharmony_ci		umr->mkey_mask |= get_umr_disable_mr_mask();
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if (!wr->num_sge)
3598c2ecf20Sopenharmony_ci		umr->flags |= MLX5_UMR_INLINE;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	return umr_check_mkey_mask(dev, be64_to_cpu(umr->mkey_mask));
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic u8 get_umr_flags(int acc)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX5_PERM_ATOMIC       : 0) |
3678c2ecf20Sopenharmony_ci	       (acc & IB_ACCESS_REMOTE_WRITE  ? MLX5_PERM_REMOTE_WRITE : 0) |
3688c2ecf20Sopenharmony_ci	       (acc & IB_ACCESS_REMOTE_READ   ? MLX5_PERM_REMOTE_READ  : 0) |
3698c2ecf20Sopenharmony_ci	       (acc & IB_ACCESS_LOCAL_WRITE   ? MLX5_PERM_LOCAL_WRITE  : 0) |
3708c2ecf20Sopenharmony_ci		MLX5_PERM_LOCAL_READ | MLX5_PERM_UMR_EN;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic void set_reg_mkey_seg(struct mlx5_mkey_seg *seg,
3748c2ecf20Sopenharmony_ci			     struct mlx5_ib_mr *mr,
3758c2ecf20Sopenharmony_ci			     u32 key, int access)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	int ndescs = ALIGN(mr->ndescs + mr->meta_ndescs, 8) >> 1;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	memset(seg, 0, sizeof(*seg));
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	if (mr->access_mode == MLX5_MKC_ACCESS_MODE_MTT)
3828c2ecf20Sopenharmony_ci		seg->log2_page_size = ilog2(mr->ibmr.page_size);
3838c2ecf20Sopenharmony_ci	else if (mr->access_mode == MLX5_MKC_ACCESS_MODE_KLMS)
3848c2ecf20Sopenharmony_ci		/* KLMs take twice the size of MTTs */
3858c2ecf20Sopenharmony_ci		ndescs *= 2;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	seg->flags = get_umr_flags(access) | mr->access_mode;
3888c2ecf20Sopenharmony_ci	seg->qpn_mkey7_0 = cpu_to_be32((key & 0xff) | 0xffffff00);
3898c2ecf20Sopenharmony_ci	seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL);
3908c2ecf20Sopenharmony_ci	seg->start_addr = cpu_to_be64(mr->ibmr.iova);
3918c2ecf20Sopenharmony_ci	seg->len = cpu_to_be64(mr->ibmr.length);
3928c2ecf20Sopenharmony_ci	seg->xlt_oct_size = cpu_to_be32(ndescs);
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic void set_linv_mkey_seg(struct mlx5_mkey_seg *seg)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	memset(seg, 0, sizeof(*seg));
3988c2ecf20Sopenharmony_ci	seg->status = MLX5_MKEY_STATUS_FREE;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic void set_reg_mkey_segment(struct mlx5_ib_dev *dev,
4028c2ecf20Sopenharmony_ci				 struct mlx5_mkey_seg *seg,
4038c2ecf20Sopenharmony_ci				 const struct ib_send_wr *wr)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	const struct mlx5_umr_wr *umrwr = umr_wr(wr);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	memset(seg, 0, sizeof(*seg));
4088c2ecf20Sopenharmony_ci	if (wr->send_flags & MLX5_IB_SEND_UMR_DISABLE_MR)
4098c2ecf20Sopenharmony_ci		MLX5_SET(mkc, seg, free, 1);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	MLX5_SET(mkc, seg, a,
4128c2ecf20Sopenharmony_ci		 !!(umrwr->access_flags & IB_ACCESS_REMOTE_ATOMIC));
4138c2ecf20Sopenharmony_ci	MLX5_SET(mkc, seg, rw,
4148c2ecf20Sopenharmony_ci		 !!(umrwr->access_flags & IB_ACCESS_REMOTE_WRITE));
4158c2ecf20Sopenharmony_ci	MLX5_SET(mkc, seg, rr, !!(umrwr->access_flags & IB_ACCESS_REMOTE_READ));
4168c2ecf20Sopenharmony_ci	MLX5_SET(mkc, seg, lw, !!(umrwr->access_flags & IB_ACCESS_LOCAL_WRITE));
4178c2ecf20Sopenharmony_ci	MLX5_SET(mkc, seg, lr, 1);
4188c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write_umr))
4198c2ecf20Sopenharmony_ci		MLX5_SET(mkc, seg, relaxed_ordering_write,
4208c2ecf20Sopenharmony_ci			 !!(umrwr->access_flags & IB_ACCESS_RELAXED_ORDERING));
4218c2ecf20Sopenharmony_ci	if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read_umr))
4228c2ecf20Sopenharmony_ci		MLX5_SET(mkc, seg, relaxed_ordering_read,
4238c2ecf20Sopenharmony_ci			 !!(umrwr->access_flags & IB_ACCESS_RELAXED_ORDERING));
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (umrwr->pd)
4268c2ecf20Sopenharmony_ci		MLX5_SET(mkc, seg, pd, to_mpd(umrwr->pd)->pdn);
4278c2ecf20Sopenharmony_ci	if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_TRANSLATION &&
4288c2ecf20Sopenharmony_ci	    !umrwr->length)
4298c2ecf20Sopenharmony_ci		MLX5_SET(mkc, seg, length64, 1);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	MLX5_SET64(mkc, seg, start_addr, umrwr->virt_addr);
4328c2ecf20Sopenharmony_ci	MLX5_SET64(mkc, seg, len, umrwr->length);
4338c2ecf20Sopenharmony_ci	MLX5_SET(mkc, seg, log_page_size, umrwr->page_shift);
4348c2ecf20Sopenharmony_ci	MLX5_SET(mkc, seg, qpn, 0xffffff);
4358c2ecf20Sopenharmony_ci	MLX5_SET(mkc, seg, mkey_7_0, mlx5_mkey_variant(umrwr->mkey));
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic void set_reg_data_seg(struct mlx5_wqe_data_seg *dseg,
4398c2ecf20Sopenharmony_ci			     struct mlx5_ib_mr *mr,
4408c2ecf20Sopenharmony_ci			     struct mlx5_ib_pd *pd)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	int bcount = mr->desc_size * (mr->ndescs + mr->meta_ndescs);
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	dseg->addr = cpu_to_be64(mr->desc_map);
4458c2ecf20Sopenharmony_ci	dseg->byte_count = cpu_to_be32(ALIGN(bcount, 64));
4468c2ecf20Sopenharmony_ci	dseg->lkey = cpu_to_be32(pd->ibpd.local_dma_lkey);
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic __be32 send_ieth(const struct ib_send_wr *wr)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	switch (wr->opcode) {
4528c2ecf20Sopenharmony_ci	case IB_WR_SEND_WITH_IMM:
4538c2ecf20Sopenharmony_ci	case IB_WR_RDMA_WRITE_WITH_IMM:
4548c2ecf20Sopenharmony_ci		return wr->ex.imm_data;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	case IB_WR_SEND_WITH_INV:
4578c2ecf20Sopenharmony_ci		return cpu_to_be32(wr->ex.invalidate_rkey);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	default:
4608c2ecf20Sopenharmony_ci		return 0;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic u8 calc_sig(void *wqe, int size)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	u8 *p = wqe;
4678c2ecf20Sopenharmony_ci	u8 res = 0;
4688c2ecf20Sopenharmony_ci	int i;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++)
4718c2ecf20Sopenharmony_ci		res ^= p[i];
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	return ~res;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic u8 wq_sig(void *wqe)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	return calc_sig(wqe, (*((u8 *)wqe + 8) & 0x3f) << 4);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic int set_data_inl_seg(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr,
4828c2ecf20Sopenharmony_ci			    void **wqe, int *wqe_sz, void **cur_edge)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct mlx5_wqe_inline_seg *seg;
4858c2ecf20Sopenharmony_ci	size_t offset;
4868c2ecf20Sopenharmony_ci	int inl = 0;
4878c2ecf20Sopenharmony_ci	int i;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	seg = *wqe;
4908c2ecf20Sopenharmony_ci	*wqe += sizeof(*seg);
4918c2ecf20Sopenharmony_ci	offset = sizeof(*seg);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	for (i = 0; i < wr->num_sge; i++) {
4948c2ecf20Sopenharmony_ci		size_t len  = wr->sg_list[i].length;
4958c2ecf20Sopenharmony_ci		void *addr = (void *)(unsigned long)(wr->sg_list[i].addr);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci		inl += len;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci		if (unlikely(inl > qp->max_inline_data))
5008c2ecf20Sopenharmony_ci			return -ENOMEM;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci		while (likely(len)) {
5038c2ecf20Sopenharmony_ci			size_t leftlen;
5048c2ecf20Sopenharmony_ci			size_t copysz;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci			handle_post_send_edge(&qp->sq, wqe,
5078c2ecf20Sopenharmony_ci					      *wqe_sz + (offset >> 4),
5088c2ecf20Sopenharmony_ci					      cur_edge);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci			leftlen = *cur_edge - *wqe;
5118c2ecf20Sopenharmony_ci			copysz = min_t(size_t, leftlen, len);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci			memcpy(*wqe, addr, copysz);
5148c2ecf20Sopenharmony_ci			len -= copysz;
5158c2ecf20Sopenharmony_ci			addr += copysz;
5168c2ecf20Sopenharmony_ci			*wqe += copysz;
5178c2ecf20Sopenharmony_ci			offset += copysz;
5188c2ecf20Sopenharmony_ci		}
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	seg->byte_count = cpu_to_be32(inl | MLX5_INLINE_SEG);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	*wqe_sz +=  ALIGN(inl + sizeof(seg->byte_count), 16) / 16;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return 0;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic u16 prot_field_size(enum ib_signature_type type)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	switch (type) {
5318c2ecf20Sopenharmony_ci	case IB_SIG_TYPE_T10_DIF:
5328c2ecf20Sopenharmony_ci		return MLX5_DIF_SIZE;
5338c2ecf20Sopenharmony_ci	default:
5348c2ecf20Sopenharmony_ci		return 0;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic u8 bs_selector(int block_size)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	switch (block_size) {
5418c2ecf20Sopenharmony_ci	case 512:	    return 0x1;
5428c2ecf20Sopenharmony_ci	case 520:	    return 0x2;
5438c2ecf20Sopenharmony_ci	case 4096:	    return 0x3;
5448c2ecf20Sopenharmony_ci	case 4160:	    return 0x4;
5458c2ecf20Sopenharmony_ci	case 1073741824:    return 0x5;
5468c2ecf20Sopenharmony_ci	default:	    return 0;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_cistatic void mlx5_fill_inl_bsf(struct ib_sig_domain *domain,
5518c2ecf20Sopenharmony_ci			      struct mlx5_bsf_inl *inl)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	/* Valid inline section and allow BSF refresh */
5548c2ecf20Sopenharmony_ci	inl->vld_refresh = cpu_to_be16(MLX5_BSF_INL_VALID |
5558c2ecf20Sopenharmony_ci				       MLX5_BSF_REFRESH_DIF);
5568c2ecf20Sopenharmony_ci	inl->dif_apptag = cpu_to_be16(domain->sig.dif.app_tag);
5578c2ecf20Sopenharmony_ci	inl->dif_reftag = cpu_to_be32(domain->sig.dif.ref_tag);
5588c2ecf20Sopenharmony_ci	/* repeating block */
5598c2ecf20Sopenharmony_ci	inl->rp_inv_seed = MLX5_BSF_REPEAT_BLOCK;
5608c2ecf20Sopenharmony_ci	inl->sig_type = domain->sig.dif.bg_type == IB_T10DIF_CRC ?
5618c2ecf20Sopenharmony_ci			MLX5_DIF_CRC : MLX5_DIF_IPCS;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	if (domain->sig.dif.ref_remap)
5648c2ecf20Sopenharmony_ci		inl->dif_inc_ref_guard_check |= MLX5_BSF_INC_REFTAG;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if (domain->sig.dif.app_escape) {
5678c2ecf20Sopenharmony_ci		if (domain->sig.dif.ref_escape)
5688c2ecf20Sopenharmony_ci			inl->dif_inc_ref_guard_check |= MLX5_BSF_APPREF_ESCAPE;
5698c2ecf20Sopenharmony_ci		else
5708c2ecf20Sopenharmony_ci			inl->dif_inc_ref_guard_check |= MLX5_BSF_APPTAG_ESCAPE;
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	inl->dif_app_bitmask_check =
5748c2ecf20Sopenharmony_ci		cpu_to_be16(domain->sig.dif.apptag_check_mask);
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic int mlx5_set_bsf(struct ib_mr *sig_mr,
5788c2ecf20Sopenharmony_ci			struct ib_sig_attrs *sig_attrs,
5798c2ecf20Sopenharmony_ci			struct mlx5_bsf *bsf, u32 data_size)
5808c2ecf20Sopenharmony_ci{
5818c2ecf20Sopenharmony_ci	struct mlx5_core_sig_ctx *msig = to_mmr(sig_mr)->sig;
5828c2ecf20Sopenharmony_ci	struct mlx5_bsf_basic *basic = &bsf->basic;
5838c2ecf20Sopenharmony_ci	struct ib_sig_domain *mem = &sig_attrs->mem;
5848c2ecf20Sopenharmony_ci	struct ib_sig_domain *wire = &sig_attrs->wire;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	memset(bsf, 0, sizeof(*bsf));
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/* Basic + Extended + Inline */
5898c2ecf20Sopenharmony_ci	basic->bsf_size_sbs = 1 << 7;
5908c2ecf20Sopenharmony_ci	/* Input domain check byte mask */
5918c2ecf20Sopenharmony_ci	basic->check_byte_mask = sig_attrs->check_mask;
5928c2ecf20Sopenharmony_ci	basic->raw_data_size = cpu_to_be32(data_size);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	/* Memory domain */
5958c2ecf20Sopenharmony_ci	switch (sig_attrs->mem.sig_type) {
5968c2ecf20Sopenharmony_ci	case IB_SIG_TYPE_NONE:
5978c2ecf20Sopenharmony_ci		break;
5988c2ecf20Sopenharmony_ci	case IB_SIG_TYPE_T10_DIF:
5998c2ecf20Sopenharmony_ci		basic->mem.bs_selector = bs_selector(mem->sig.dif.pi_interval);
6008c2ecf20Sopenharmony_ci		basic->m_bfs_psv = cpu_to_be32(msig->psv_memory.psv_idx);
6018c2ecf20Sopenharmony_ci		mlx5_fill_inl_bsf(mem, &bsf->m_inl);
6028c2ecf20Sopenharmony_ci		break;
6038c2ecf20Sopenharmony_ci	default:
6048c2ecf20Sopenharmony_ci		return -EINVAL;
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	/* Wire domain */
6088c2ecf20Sopenharmony_ci	switch (sig_attrs->wire.sig_type) {
6098c2ecf20Sopenharmony_ci	case IB_SIG_TYPE_NONE:
6108c2ecf20Sopenharmony_ci		break;
6118c2ecf20Sopenharmony_ci	case IB_SIG_TYPE_T10_DIF:
6128c2ecf20Sopenharmony_ci		if (mem->sig.dif.pi_interval == wire->sig.dif.pi_interval &&
6138c2ecf20Sopenharmony_ci		    mem->sig_type == wire->sig_type) {
6148c2ecf20Sopenharmony_ci			/* Same block structure */
6158c2ecf20Sopenharmony_ci			basic->bsf_size_sbs |= 1 << 4;
6168c2ecf20Sopenharmony_ci			if (mem->sig.dif.bg_type == wire->sig.dif.bg_type)
6178c2ecf20Sopenharmony_ci				basic->wire.copy_byte_mask |= MLX5_CPY_GRD_MASK;
6188c2ecf20Sopenharmony_ci			if (mem->sig.dif.app_tag == wire->sig.dif.app_tag)
6198c2ecf20Sopenharmony_ci				basic->wire.copy_byte_mask |= MLX5_CPY_APP_MASK;
6208c2ecf20Sopenharmony_ci			if (mem->sig.dif.ref_tag == wire->sig.dif.ref_tag)
6218c2ecf20Sopenharmony_ci				basic->wire.copy_byte_mask |= MLX5_CPY_REF_MASK;
6228c2ecf20Sopenharmony_ci		} else
6238c2ecf20Sopenharmony_ci			basic->wire.bs_selector =
6248c2ecf20Sopenharmony_ci				bs_selector(wire->sig.dif.pi_interval);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		basic->w_bfs_psv = cpu_to_be32(msig->psv_wire.psv_idx);
6278c2ecf20Sopenharmony_ci		mlx5_fill_inl_bsf(wire, &bsf->w_inl);
6288c2ecf20Sopenharmony_ci		break;
6298c2ecf20Sopenharmony_ci	default:
6308c2ecf20Sopenharmony_ci		return -EINVAL;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	return 0;
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic int set_sig_data_segment(const struct ib_send_wr *send_wr,
6388c2ecf20Sopenharmony_ci				struct ib_mr *sig_mr,
6398c2ecf20Sopenharmony_ci				struct ib_sig_attrs *sig_attrs,
6408c2ecf20Sopenharmony_ci				struct mlx5_ib_qp *qp, void **seg, int *size,
6418c2ecf20Sopenharmony_ci				void **cur_edge)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct mlx5_bsf *bsf;
6448c2ecf20Sopenharmony_ci	u32 data_len;
6458c2ecf20Sopenharmony_ci	u32 data_key;
6468c2ecf20Sopenharmony_ci	u64 data_va;
6478c2ecf20Sopenharmony_ci	u32 prot_len = 0;
6488c2ecf20Sopenharmony_ci	u32 prot_key = 0;
6498c2ecf20Sopenharmony_ci	u64 prot_va = 0;
6508c2ecf20Sopenharmony_ci	bool prot = false;
6518c2ecf20Sopenharmony_ci	int ret;
6528c2ecf20Sopenharmony_ci	int wqe_size;
6538c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(sig_mr);
6548c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *pi_mr = mr->pi_mr;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	data_len = pi_mr->data_length;
6578c2ecf20Sopenharmony_ci	data_key = pi_mr->ibmr.lkey;
6588c2ecf20Sopenharmony_ci	data_va = pi_mr->data_iova;
6598c2ecf20Sopenharmony_ci	if (pi_mr->meta_ndescs) {
6608c2ecf20Sopenharmony_ci		prot_len = pi_mr->meta_length;
6618c2ecf20Sopenharmony_ci		prot_key = pi_mr->ibmr.lkey;
6628c2ecf20Sopenharmony_ci		prot_va = pi_mr->pi_iova;
6638c2ecf20Sopenharmony_ci		prot = true;
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	if (!prot || (data_key == prot_key && data_va == prot_va &&
6678c2ecf20Sopenharmony_ci		      data_len == prot_len)) {
6688c2ecf20Sopenharmony_ci		/**
6698c2ecf20Sopenharmony_ci		 * Source domain doesn't contain signature information
6708c2ecf20Sopenharmony_ci		 * or data and protection are interleaved in memory.
6718c2ecf20Sopenharmony_ci		 * So need construct:
6728c2ecf20Sopenharmony_ci		 *                  ------------------
6738c2ecf20Sopenharmony_ci		 *                 |     data_klm     |
6748c2ecf20Sopenharmony_ci		 *                  ------------------
6758c2ecf20Sopenharmony_ci		 *                 |       BSF        |
6768c2ecf20Sopenharmony_ci		 *                  ------------------
6778c2ecf20Sopenharmony_ci		 **/
6788c2ecf20Sopenharmony_ci		struct mlx5_klm *data_klm = *seg;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci		data_klm->bcount = cpu_to_be32(data_len);
6818c2ecf20Sopenharmony_ci		data_klm->key = cpu_to_be32(data_key);
6828c2ecf20Sopenharmony_ci		data_klm->va = cpu_to_be64(data_va);
6838c2ecf20Sopenharmony_ci		wqe_size = ALIGN(sizeof(*data_klm), 64);
6848c2ecf20Sopenharmony_ci	} else {
6858c2ecf20Sopenharmony_ci		/**
6868c2ecf20Sopenharmony_ci		 * Source domain contains signature information
6878c2ecf20Sopenharmony_ci		 * So need construct a strided block format:
6888c2ecf20Sopenharmony_ci		 *               ---------------------------
6898c2ecf20Sopenharmony_ci		 *              |     stride_block_ctrl     |
6908c2ecf20Sopenharmony_ci		 *               ---------------------------
6918c2ecf20Sopenharmony_ci		 *              |          data_klm         |
6928c2ecf20Sopenharmony_ci		 *               ---------------------------
6938c2ecf20Sopenharmony_ci		 *              |          prot_klm         |
6948c2ecf20Sopenharmony_ci		 *               ---------------------------
6958c2ecf20Sopenharmony_ci		 *              |             BSF           |
6968c2ecf20Sopenharmony_ci		 *               ---------------------------
6978c2ecf20Sopenharmony_ci		 **/
6988c2ecf20Sopenharmony_ci		struct mlx5_stride_block_ctrl_seg *sblock_ctrl;
6998c2ecf20Sopenharmony_ci		struct mlx5_stride_block_entry *data_sentry;
7008c2ecf20Sopenharmony_ci		struct mlx5_stride_block_entry *prot_sentry;
7018c2ecf20Sopenharmony_ci		u16 block_size = sig_attrs->mem.sig.dif.pi_interval;
7028c2ecf20Sopenharmony_ci		int prot_size;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		sblock_ctrl = *seg;
7058c2ecf20Sopenharmony_ci		data_sentry = (void *)sblock_ctrl + sizeof(*sblock_ctrl);
7068c2ecf20Sopenharmony_ci		prot_sentry = (void *)data_sentry + sizeof(*data_sentry);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci		prot_size = prot_field_size(sig_attrs->mem.sig_type);
7098c2ecf20Sopenharmony_ci		if (!prot_size) {
7108c2ecf20Sopenharmony_ci			pr_err("Bad block size given: %u\n", block_size);
7118c2ecf20Sopenharmony_ci			return -EINVAL;
7128c2ecf20Sopenharmony_ci		}
7138c2ecf20Sopenharmony_ci		sblock_ctrl->bcount_per_cycle = cpu_to_be32(block_size +
7148c2ecf20Sopenharmony_ci							    prot_size);
7158c2ecf20Sopenharmony_ci		sblock_ctrl->op = cpu_to_be32(MLX5_STRIDE_BLOCK_OP);
7168c2ecf20Sopenharmony_ci		sblock_ctrl->repeat_count = cpu_to_be32(data_len / block_size);
7178c2ecf20Sopenharmony_ci		sblock_ctrl->num_entries = cpu_to_be16(2);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci		data_sentry->bcount = cpu_to_be16(block_size);
7208c2ecf20Sopenharmony_ci		data_sentry->key = cpu_to_be32(data_key);
7218c2ecf20Sopenharmony_ci		data_sentry->va = cpu_to_be64(data_va);
7228c2ecf20Sopenharmony_ci		data_sentry->stride = cpu_to_be16(block_size);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		prot_sentry->bcount = cpu_to_be16(prot_size);
7258c2ecf20Sopenharmony_ci		prot_sentry->key = cpu_to_be32(prot_key);
7268c2ecf20Sopenharmony_ci		prot_sentry->va = cpu_to_be64(prot_va);
7278c2ecf20Sopenharmony_ci		prot_sentry->stride = cpu_to_be16(prot_size);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci		wqe_size = ALIGN(sizeof(*sblock_ctrl) + sizeof(*data_sentry) +
7308c2ecf20Sopenharmony_ci				 sizeof(*prot_sentry), 64);
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	*seg += wqe_size;
7348c2ecf20Sopenharmony_ci	*size += wqe_size / 16;
7358c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	bsf = *seg;
7388c2ecf20Sopenharmony_ci	ret = mlx5_set_bsf(sig_mr, sig_attrs, bsf, data_len);
7398c2ecf20Sopenharmony_ci	if (ret)
7408c2ecf20Sopenharmony_ci		return -EINVAL;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	*seg += sizeof(*bsf);
7438c2ecf20Sopenharmony_ci	*size += sizeof(*bsf) / 16;
7448c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	return 0;
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_cistatic void set_sig_mkey_segment(struct mlx5_mkey_seg *seg,
7508c2ecf20Sopenharmony_ci				 struct ib_mr *sig_mr, int access_flags,
7518c2ecf20Sopenharmony_ci				 u32 size, u32 length, u32 pdn)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	u32 sig_key = sig_mr->rkey;
7548c2ecf20Sopenharmony_ci	u8 sigerr = to_mmr(sig_mr)->sig->sigerr_count & 1;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	memset(seg, 0, sizeof(*seg));
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	seg->flags = get_umr_flags(access_flags) | MLX5_MKC_ACCESS_MODE_KLMS;
7598c2ecf20Sopenharmony_ci	seg->qpn_mkey7_0 = cpu_to_be32((sig_key & 0xff) | 0xffffff00);
7608c2ecf20Sopenharmony_ci	seg->flags_pd = cpu_to_be32(MLX5_MKEY_REMOTE_INVAL | sigerr << 26 |
7618c2ecf20Sopenharmony_ci				    MLX5_MKEY_BSF_EN | pdn);
7628c2ecf20Sopenharmony_ci	seg->len = cpu_to_be64(length);
7638c2ecf20Sopenharmony_ci	seg->xlt_oct_size = cpu_to_be32(get_xlt_octo(size));
7648c2ecf20Sopenharmony_ci	seg->bsfs_octo_size = cpu_to_be32(MLX5_MKEY_BSF_OCTO_SIZE);
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_cistatic void set_sig_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr,
7688c2ecf20Sopenharmony_ci				u32 size)
7698c2ecf20Sopenharmony_ci{
7708c2ecf20Sopenharmony_ci	memset(umr, 0, sizeof(*umr));
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	umr->flags = MLX5_FLAGS_INLINE | MLX5_FLAGS_CHECK_FREE;
7738c2ecf20Sopenharmony_ci	umr->xlt_octowords = cpu_to_be16(get_xlt_octo(size));
7748c2ecf20Sopenharmony_ci	umr->bsf_octowords = cpu_to_be16(MLX5_MKEY_BSF_OCTO_SIZE);
7758c2ecf20Sopenharmony_ci	umr->mkey_mask = sig_mkey_mask();
7768c2ecf20Sopenharmony_ci}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_cistatic int set_pi_umr_wr(const struct ib_send_wr *send_wr,
7798c2ecf20Sopenharmony_ci			 struct mlx5_ib_qp *qp, void **seg, int *size,
7808c2ecf20Sopenharmony_ci			 void **cur_edge)
7818c2ecf20Sopenharmony_ci{
7828c2ecf20Sopenharmony_ci	const struct ib_reg_wr *wr = reg_wr(send_wr);
7838c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *sig_mr = to_mmr(wr->mr);
7848c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *pi_mr = sig_mr->pi_mr;
7858c2ecf20Sopenharmony_ci	struct ib_sig_attrs *sig_attrs = sig_mr->ibmr.sig_attrs;
7868c2ecf20Sopenharmony_ci	u32 pdn = to_mpd(qp->ibqp.pd)->pdn;
7878c2ecf20Sopenharmony_ci	u32 xlt_size;
7888c2ecf20Sopenharmony_ci	int region_len, ret;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	if (unlikely(send_wr->num_sge != 0) ||
7918c2ecf20Sopenharmony_ci	    unlikely(wr->access & IB_ACCESS_REMOTE_ATOMIC) ||
7928c2ecf20Sopenharmony_ci	    unlikely(!sig_mr->sig) || unlikely(!qp->ibqp.integrity_en) ||
7938c2ecf20Sopenharmony_ci	    unlikely(!sig_mr->sig->sig_status_checked))
7948c2ecf20Sopenharmony_ci		return -EINVAL;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	/* length of the protected region, data + protection */
7978c2ecf20Sopenharmony_ci	region_len = pi_mr->ibmr.length;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	/**
8008c2ecf20Sopenharmony_ci	 * KLM octoword size - if protection was provided
8018c2ecf20Sopenharmony_ci	 * then we use strided block format (3 octowords),
8028c2ecf20Sopenharmony_ci	 * else we use single KLM (1 octoword)
8038c2ecf20Sopenharmony_ci	 **/
8048c2ecf20Sopenharmony_ci	if (sig_attrs->mem.sig_type != IB_SIG_TYPE_NONE)
8058c2ecf20Sopenharmony_ci		xlt_size = 0x30;
8068c2ecf20Sopenharmony_ci	else
8078c2ecf20Sopenharmony_ci		xlt_size = sizeof(struct mlx5_klm);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	set_sig_umr_segment(*seg, xlt_size);
8108c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
8118c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
8128c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	set_sig_mkey_segment(*seg, wr->mr, wr->access, xlt_size, region_len,
8158c2ecf20Sopenharmony_ci			     pdn);
8168c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_mkey_seg);
8178c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_mkey_seg) / 16;
8188c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	ret = set_sig_data_segment(send_wr, wr->mr, sig_attrs, qp, seg, size,
8218c2ecf20Sopenharmony_ci				   cur_edge);
8228c2ecf20Sopenharmony_ci	if (ret)
8238c2ecf20Sopenharmony_ci		return ret;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	sig_mr->sig->sig_status_checked = false;
8268c2ecf20Sopenharmony_ci	return 0;
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_cistatic int set_psv_wr(struct ib_sig_domain *domain,
8308c2ecf20Sopenharmony_ci		      u32 psv_idx, void **seg, int *size)
8318c2ecf20Sopenharmony_ci{
8328c2ecf20Sopenharmony_ci	struct mlx5_seg_set_psv *psv_seg = *seg;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	memset(psv_seg, 0, sizeof(*psv_seg));
8358c2ecf20Sopenharmony_ci	psv_seg->psv_num = cpu_to_be32(psv_idx);
8368c2ecf20Sopenharmony_ci	switch (domain->sig_type) {
8378c2ecf20Sopenharmony_ci	case IB_SIG_TYPE_NONE:
8388c2ecf20Sopenharmony_ci		break;
8398c2ecf20Sopenharmony_ci	case IB_SIG_TYPE_T10_DIF:
8408c2ecf20Sopenharmony_ci		psv_seg->transient_sig = cpu_to_be32(domain->sig.dif.bg << 16 |
8418c2ecf20Sopenharmony_ci						     domain->sig.dif.app_tag);
8428c2ecf20Sopenharmony_ci		psv_seg->ref_tag = cpu_to_be32(domain->sig.dif.ref_tag);
8438c2ecf20Sopenharmony_ci		break;
8448c2ecf20Sopenharmony_ci	default:
8458c2ecf20Sopenharmony_ci		pr_err("Bad signature type (%d) is given.\n",
8468c2ecf20Sopenharmony_ci		       domain->sig_type);
8478c2ecf20Sopenharmony_ci		return -EINVAL;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	*seg += sizeof(*psv_seg);
8518c2ecf20Sopenharmony_ci	*size += sizeof(*psv_seg) / 16;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	return 0;
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_cistatic int set_reg_wr(struct mlx5_ib_qp *qp,
8578c2ecf20Sopenharmony_ci		      const struct ib_reg_wr *wr,
8588c2ecf20Sopenharmony_ci		      void **seg, int *size, void **cur_edge,
8598c2ecf20Sopenharmony_ci		      bool check_not_free)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr = to_mmr(wr->mr);
8628c2ecf20Sopenharmony_ci	struct mlx5_ib_pd *pd = to_mpd(qp->ibqp.pd);
8638c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(pd->ibpd.device);
8648c2ecf20Sopenharmony_ci	int mr_list_size = (mr->ndescs + mr->meta_ndescs) * mr->desc_size;
8658c2ecf20Sopenharmony_ci	bool umr_inline = mr_list_size <= MLX5_IB_SQ_UMR_INLINE_THRESHOLD;
8668c2ecf20Sopenharmony_ci	bool atomic = wr->access & IB_ACCESS_REMOTE_ATOMIC;
8678c2ecf20Sopenharmony_ci	u8 flags = 0;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	/* Matches access in mlx5_set_umr_free_mkey() */
8708c2ecf20Sopenharmony_ci	if (!mlx5_ib_can_reconfig_with_umr(dev, 0, wr->access)) {
8718c2ecf20Sopenharmony_ci		mlx5_ib_warn(
8728c2ecf20Sopenharmony_ci			to_mdev(qp->ibqp.device),
8738c2ecf20Sopenharmony_ci			"Fast update for MR access flags is not possible\n");
8748c2ecf20Sopenharmony_ci		return -EINVAL;
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	if (unlikely(wr->wr.send_flags & IB_SEND_INLINE)) {
8788c2ecf20Sopenharmony_ci		mlx5_ib_warn(to_mdev(qp->ibqp.device),
8798c2ecf20Sopenharmony_ci			     "Invalid IB_SEND_INLINE send flag\n");
8808c2ecf20Sopenharmony_ci		return -EINVAL;
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	if (check_not_free)
8848c2ecf20Sopenharmony_ci		flags |= MLX5_UMR_CHECK_NOT_FREE;
8858c2ecf20Sopenharmony_ci	if (umr_inline)
8868c2ecf20Sopenharmony_ci		flags |= MLX5_UMR_INLINE;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	set_reg_umr_seg(*seg, mr, flags, atomic);
8898c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
8908c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
8918c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	set_reg_mkey_seg(*seg, mr, wr->key, wr->access);
8948c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_mkey_seg);
8958c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_mkey_seg) / 16;
8968c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (umr_inline) {
8998c2ecf20Sopenharmony_ci		memcpy_send_wqe(&qp->sq, cur_edge, seg, size, mr->descs,
9008c2ecf20Sopenharmony_ci				mr_list_size);
9018c2ecf20Sopenharmony_ci		*size = ALIGN(*size, MLX5_SEND_WQE_BB >> 4);
9028c2ecf20Sopenharmony_ci	} else {
9038c2ecf20Sopenharmony_ci		set_reg_data_seg(*seg, mr, pd);
9048c2ecf20Sopenharmony_ci		*seg += sizeof(struct mlx5_wqe_data_seg);
9058c2ecf20Sopenharmony_ci		*size += (sizeof(struct mlx5_wqe_data_seg) / 16);
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci	return 0;
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_cistatic void set_linv_wr(struct mlx5_ib_qp *qp, void **seg, int *size,
9118c2ecf20Sopenharmony_ci			void **cur_edge)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	set_linv_umr_seg(*seg);
9148c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
9158c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
9168c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
9178c2ecf20Sopenharmony_ci	set_linv_mkey_seg(*seg);
9188c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_mkey_seg);
9198c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_mkey_seg) / 16;
9208c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_cistatic void dump_wqe(struct mlx5_ib_qp *qp, u32 idx, int size_16)
9248c2ecf20Sopenharmony_ci{
9258c2ecf20Sopenharmony_ci	__be32 *p = NULL;
9268c2ecf20Sopenharmony_ci	int i, j;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	pr_debug("dump WQE index %u:\n", idx);
9298c2ecf20Sopenharmony_ci	for (i = 0, j = 0; i < size_16 * 4; i += 4, j += 4) {
9308c2ecf20Sopenharmony_ci		if ((i & 0xf) == 0) {
9318c2ecf20Sopenharmony_ci			p = mlx5_frag_buf_get_wqe(&qp->sq.fbc, idx);
9328c2ecf20Sopenharmony_ci			pr_debug("WQBB at %p:\n", (void *)p);
9338c2ecf20Sopenharmony_ci			j = 0;
9348c2ecf20Sopenharmony_ci			idx = (idx + 1) & (qp->sq.wqe_cnt - 1);
9358c2ecf20Sopenharmony_ci		}
9368c2ecf20Sopenharmony_ci		pr_debug("%08x %08x %08x %08x\n", be32_to_cpu(p[j]),
9378c2ecf20Sopenharmony_ci			 be32_to_cpu(p[j + 1]), be32_to_cpu(p[j + 2]),
9388c2ecf20Sopenharmony_ci			 be32_to_cpu(p[j + 3]));
9398c2ecf20Sopenharmony_ci	}
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic int __begin_wqe(struct mlx5_ib_qp *qp, void **seg,
9438c2ecf20Sopenharmony_ci		       struct mlx5_wqe_ctrl_seg **ctrl,
9448c2ecf20Sopenharmony_ci		       const struct ib_send_wr *wr, unsigned int *idx,
9458c2ecf20Sopenharmony_ci		       int *size, void **cur_edge, int nreq,
9468c2ecf20Sopenharmony_ci		       bool send_signaled, bool solicited)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	if (unlikely(mlx5_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)))
9498c2ecf20Sopenharmony_ci		return -ENOMEM;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	*idx = qp->sq.cur_post & (qp->sq.wqe_cnt - 1);
9528c2ecf20Sopenharmony_ci	*seg = mlx5_frag_buf_get_wqe(&qp->sq.fbc, *idx);
9538c2ecf20Sopenharmony_ci	*ctrl = *seg;
9548c2ecf20Sopenharmony_ci	*(uint32_t *)(*seg + 8) = 0;
9558c2ecf20Sopenharmony_ci	(*ctrl)->imm = send_ieth(wr);
9568c2ecf20Sopenharmony_ci	(*ctrl)->fm_ce_se = qp->sq_signal_bits |
9578c2ecf20Sopenharmony_ci		(send_signaled ? MLX5_WQE_CTRL_CQ_UPDATE : 0) |
9588c2ecf20Sopenharmony_ci		(solicited ? MLX5_WQE_CTRL_SOLICITED : 0);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	*seg += sizeof(**ctrl);
9618c2ecf20Sopenharmony_ci	*size = sizeof(**ctrl) / 16;
9628c2ecf20Sopenharmony_ci	*cur_edge = qp->sq.cur_edge;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	return 0;
9658c2ecf20Sopenharmony_ci}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_cistatic int begin_wqe(struct mlx5_ib_qp *qp, void **seg,
9688c2ecf20Sopenharmony_ci		     struct mlx5_wqe_ctrl_seg **ctrl,
9698c2ecf20Sopenharmony_ci		     const struct ib_send_wr *wr, unsigned int *idx, int *size,
9708c2ecf20Sopenharmony_ci		     void **cur_edge, int nreq)
9718c2ecf20Sopenharmony_ci{
9728c2ecf20Sopenharmony_ci	return __begin_wqe(qp, seg, ctrl, wr, idx, size, cur_edge, nreq,
9738c2ecf20Sopenharmony_ci			   wr->send_flags & IB_SEND_SIGNALED,
9748c2ecf20Sopenharmony_ci			   wr->send_flags & IB_SEND_SOLICITED);
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic void finish_wqe(struct mlx5_ib_qp *qp,
9788c2ecf20Sopenharmony_ci		       struct mlx5_wqe_ctrl_seg *ctrl,
9798c2ecf20Sopenharmony_ci		       void *seg, u8 size, void *cur_edge,
9808c2ecf20Sopenharmony_ci		       unsigned int idx, u64 wr_id, int nreq, u8 fence,
9818c2ecf20Sopenharmony_ci		       u32 mlx5_opcode)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	u8 opmod = 0;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	ctrl->opmod_idx_opcode = cpu_to_be32(((u32)(qp->sq.cur_post) << 8) |
9868c2ecf20Sopenharmony_ci					     mlx5_opcode | ((u32)opmod << 24));
9878c2ecf20Sopenharmony_ci	ctrl->qpn_ds = cpu_to_be32(size | (qp->trans_qp.base.mqp.qpn << 8));
9888c2ecf20Sopenharmony_ci	ctrl->fm_ce_se |= fence;
9898c2ecf20Sopenharmony_ci	if (unlikely(qp->flags_en & MLX5_QP_FLAG_SIGNATURE))
9908c2ecf20Sopenharmony_ci		ctrl->signature = wq_sig(ctrl);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	qp->sq.wrid[idx] = wr_id;
9938c2ecf20Sopenharmony_ci	qp->sq.w_list[idx].opcode = mlx5_opcode;
9948c2ecf20Sopenharmony_ci	qp->sq.wqe_head[idx] = qp->sq.head + nreq;
9958c2ecf20Sopenharmony_ci	qp->sq.cur_post += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB);
9968c2ecf20Sopenharmony_ci	qp->sq.w_list[idx].next = qp->sq.cur_post;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	/* We save the edge which was possibly updated during the WQE
9998c2ecf20Sopenharmony_ci	 * construction, into SQ's cache.
10008c2ecf20Sopenharmony_ci	 */
10018c2ecf20Sopenharmony_ci	seg = PTR_ALIGN(seg, MLX5_SEND_WQE_BB);
10028c2ecf20Sopenharmony_ci	qp->sq.cur_edge = (unlikely(seg == cur_edge)) ?
10038c2ecf20Sopenharmony_ci			  get_sq_edge(&qp->sq, qp->sq.cur_post &
10048c2ecf20Sopenharmony_ci				      (qp->sq.wqe_cnt - 1)) :
10058c2ecf20Sopenharmony_ci			  cur_edge;
10068c2ecf20Sopenharmony_ci}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_cistatic void handle_rdma_op(const struct ib_send_wr *wr, void **seg, int *size)
10098c2ecf20Sopenharmony_ci{
10108c2ecf20Sopenharmony_ci	set_raddr_seg(*seg, rdma_wr(wr)->remote_addr, rdma_wr(wr)->rkey);
10118c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_wqe_raddr_seg);
10128c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_wqe_raddr_seg) / 16;
10138c2ecf20Sopenharmony_ci}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_cistatic void handle_local_inv(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr,
10168c2ecf20Sopenharmony_ci			     struct mlx5_wqe_ctrl_seg **ctrl, void **seg,
10178c2ecf20Sopenharmony_ci			     int *size, void **cur_edge, unsigned int idx)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	qp->sq.wr_data[idx] = IB_WR_LOCAL_INV;
10208c2ecf20Sopenharmony_ci	(*ctrl)->imm = cpu_to_be32(wr->ex.invalidate_rkey);
10218c2ecf20Sopenharmony_ci	set_linv_wr(qp, seg, size, cur_edge);
10228c2ecf20Sopenharmony_ci}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_cistatic int handle_reg_mr(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr,
10258c2ecf20Sopenharmony_ci			 struct mlx5_wqe_ctrl_seg **ctrl, void **seg, int *size,
10268c2ecf20Sopenharmony_ci			 void **cur_edge, unsigned int idx)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	qp->sq.wr_data[idx] = IB_WR_REG_MR;
10298c2ecf20Sopenharmony_ci	(*ctrl)->imm = cpu_to_be32(reg_wr(wr)->key);
10308c2ecf20Sopenharmony_ci	return set_reg_wr(qp, reg_wr(wr), seg, size, cur_edge, true);
10318c2ecf20Sopenharmony_ci}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_cistatic int handle_psv(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
10348c2ecf20Sopenharmony_ci		      const struct ib_send_wr *wr,
10358c2ecf20Sopenharmony_ci		      struct mlx5_wqe_ctrl_seg **ctrl, void **seg, int *size,
10368c2ecf20Sopenharmony_ci		      void **cur_edge, unsigned int *idx, int nreq,
10378c2ecf20Sopenharmony_ci		      struct ib_sig_domain *domain, u32 psv_index,
10388c2ecf20Sopenharmony_ci		      u8 next_fence)
10398c2ecf20Sopenharmony_ci{
10408c2ecf20Sopenharmony_ci	int err;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	/*
10438c2ecf20Sopenharmony_ci	 * SET_PSV WQEs are not signaled and solicited on error.
10448c2ecf20Sopenharmony_ci	 */
10458c2ecf20Sopenharmony_ci	err = __begin_wqe(qp, seg, ctrl, wr, idx, size, cur_edge, nreq,
10468c2ecf20Sopenharmony_ci			  false, true);
10478c2ecf20Sopenharmony_ci	if (unlikely(err)) {
10488c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "\n");
10498c2ecf20Sopenharmony_ci		err = -ENOMEM;
10508c2ecf20Sopenharmony_ci		goto out;
10518c2ecf20Sopenharmony_ci	}
10528c2ecf20Sopenharmony_ci	err = set_psv_wr(domain, psv_index, seg, size);
10538c2ecf20Sopenharmony_ci	if (unlikely(err)) {
10548c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "\n");
10558c2ecf20Sopenharmony_ci		goto out;
10568c2ecf20Sopenharmony_ci	}
10578c2ecf20Sopenharmony_ci	finish_wqe(qp, *ctrl, *seg, *size, *cur_edge, *idx, wr->wr_id, nreq,
10588c2ecf20Sopenharmony_ci		   next_fence, MLX5_OPCODE_SET_PSV);
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ciout:
10618c2ecf20Sopenharmony_ci	return err;
10628c2ecf20Sopenharmony_ci}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_cistatic int handle_reg_mr_integrity(struct mlx5_ib_dev *dev,
10658c2ecf20Sopenharmony_ci				   struct mlx5_ib_qp *qp,
10668c2ecf20Sopenharmony_ci				   const struct ib_send_wr *wr,
10678c2ecf20Sopenharmony_ci				   struct mlx5_wqe_ctrl_seg **ctrl, void **seg,
10688c2ecf20Sopenharmony_ci				   int *size, void **cur_edge,
10698c2ecf20Sopenharmony_ci				   unsigned int *idx, int nreq, u8 fence,
10708c2ecf20Sopenharmony_ci				   u8 next_fence)
10718c2ecf20Sopenharmony_ci{
10728c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *mr;
10738c2ecf20Sopenharmony_ci	struct mlx5_ib_mr *pi_mr;
10748c2ecf20Sopenharmony_ci	struct mlx5_ib_mr pa_pi_mr;
10758c2ecf20Sopenharmony_ci	struct ib_sig_attrs *sig_attrs;
10768c2ecf20Sopenharmony_ci	struct ib_reg_wr reg_pi_wr;
10778c2ecf20Sopenharmony_ci	int err;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	qp->sq.wr_data[*idx] = IB_WR_REG_MR_INTEGRITY;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	mr = to_mmr(reg_wr(wr)->mr);
10828c2ecf20Sopenharmony_ci	pi_mr = mr->pi_mr;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	if (pi_mr) {
10858c2ecf20Sopenharmony_ci		memset(&reg_pi_wr, 0,
10868c2ecf20Sopenharmony_ci		       sizeof(struct ib_reg_wr));
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci		reg_pi_wr.mr = &pi_mr->ibmr;
10898c2ecf20Sopenharmony_ci		reg_pi_wr.access = reg_wr(wr)->access;
10908c2ecf20Sopenharmony_ci		reg_pi_wr.key = pi_mr->ibmr.rkey;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci		(*ctrl)->imm = cpu_to_be32(reg_pi_wr.key);
10938c2ecf20Sopenharmony_ci		/* UMR for data + prot registration */
10948c2ecf20Sopenharmony_ci		err = set_reg_wr(qp, &reg_pi_wr, seg, size, cur_edge, false);
10958c2ecf20Sopenharmony_ci		if (unlikely(err))
10968c2ecf20Sopenharmony_ci			goto out;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci		finish_wqe(qp, *ctrl, *seg, *size, *cur_edge, *idx, wr->wr_id,
10998c2ecf20Sopenharmony_ci			   nreq, fence, MLX5_OPCODE_UMR);
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci		err = begin_wqe(qp, seg, ctrl, wr, idx, size, cur_edge, nreq);
11028c2ecf20Sopenharmony_ci		if (unlikely(err)) {
11038c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "\n");
11048c2ecf20Sopenharmony_ci			err = -ENOMEM;
11058c2ecf20Sopenharmony_ci			goto out;
11068c2ecf20Sopenharmony_ci		}
11078c2ecf20Sopenharmony_ci	} else {
11088c2ecf20Sopenharmony_ci		memset(&pa_pi_mr, 0, sizeof(struct mlx5_ib_mr));
11098c2ecf20Sopenharmony_ci		/* No UMR, use local_dma_lkey */
11108c2ecf20Sopenharmony_ci		pa_pi_mr.ibmr.lkey = mr->ibmr.pd->local_dma_lkey;
11118c2ecf20Sopenharmony_ci		pa_pi_mr.ndescs = mr->ndescs;
11128c2ecf20Sopenharmony_ci		pa_pi_mr.data_length = mr->data_length;
11138c2ecf20Sopenharmony_ci		pa_pi_mr.data_iova = mr->data_iova;
11148c2ecf20Sopenharmony_ci		if (mr->meta_ndescs) {
11158c2ecf20Sopenharmony_ci			pa_pi_mr.meta_ndescs = mr->meta_ndescs;
11168c2ecf20Sopenharmony_ci			pa_pi_mr.meta_length = mr->meta_length;
11178c2ecf20Sopenharmony_ci			pa_pi_mr.pi_iova = mr->pi_iova;
11188c2ecf20Sopenharmony_ci		}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci		pa_pi_mr.ibmr.length = mr->ibmr.length;
11218c2ecf20Sopenharmony_ci		mr->pi_mr = &pa_pi_mr;
11228c2ecf20Sopenharmony_ci	}
11238c2ecf20Sopenharmony_ci	(*ctrl)->imm = cpu_to_be32(mr->ibmr.rkey);
11248c2ecf20Sopenharmony_ci	/* UMR for sig MR */
11258c2ecf20Sopenharmony_ci	err = set_pi_umr_wr(wr, qp, seg, size, cur_edge);
11268c2ecf20Sopenharmony_ci	if (unlikely(err)) {
11278c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "\n");
11288c2ecf20Sopenharmony_ci		goto out;
11298c2ecf20Sopenharmony_ci	}
11308c2ecf20Sopenharmony_ci	finish_wqe(qp, *ctrl, *seg, *size, *cur_edge, *idx, wr->wr_id, nreq,
11318c2ecf20Sopenharmony_ci		   fence, MLX5_OPCODE_UMR);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	sig_attrs = mr->ibmr.sig_attrs;
11348c2ecf20Sopenharmony_ci	err = handle_psv(dev, qp, wr, ctrl, seg, size, cur_edge, idx, nreq,
11358c2ecf20Sopenharmony_ci			 &sig_attrs->mem, mr->sig->psv_memory.psv_idx,
11368c2ecf20Sopenharmony_ci			 next_fence);
11378c2ecf20Sopenharmony_ci	if (unlikely(err))
11388c2ecf20Sopenharmony_ci		goto out;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	err = handle_psv(dev, qp, wr, ctrl, seg, size, cur_edge, idx, nreq,
11418c2ecf20Sopenharmony_ci			 &sig_attrs->wire, mr->sig->psv_wire.psv_idx,
11428c2ecf20Sopenharmony_ci			 next_fence);
11438c2ecf20Sopenharmony_ci	if (unlikely(err))
11448c2ecf20Sopenharmony_ci		goto out;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	qp->next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ciout:
11498c2ecf20Sopenharmony_ci	return err;
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cistatic int handle_qpt_rc(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
11538c2ecf20Sopenharmony_ci			 const struct ib_send_wr *wr,
11548c2ecf20Sopenharmony_ci			 struct mlx5_wqe_ctrl_seg **ctrl, void **seg, int *size,
11558c2ecf20Sopenharmony_ci			 void **cur_edge, unsigned int *idx, int nreq, u8 fence,
11568c2ecf20Sopenharmony_ci			 u8 next_fence, int *num_sge)
11578c2ecf20Sopenharmony_ci{
11588c2ecf20Sopenharmony_ci	int err = 0;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	switch (wr->opcode) {
11618c2ecf20Sopenharmony_ci	case IB_WR_RDMA_READ:
11628c2ecf20Sopenharmony_ci	case IB_WR_RDMA_WRITE:
11638c2ecf20Sopenharmony_ci	case IB_WR_RDMA_WRITE_WITH_IMM:
11648c2ecf20Sopenharmony_ci		handle_rdma_op(wr, seg, size);
11658c2ecf20Sopenharmony_ci		break;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	case IB_WR_ATOMIC_CMP_AND_SWP:
11688c2ecf20Sopenharmony_ci	case IB_WR_ATOMIC_FETCH_AND_ADD:
11698c2ecf20Sopenharmony_ci	case IB_WR_MASKED_ATOMIC_CMP_AND_SWP:
11708c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "Atomic operations are not supported yet\n");
11718c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
11728c2ecf20Sopenharmony_ci		goto out;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	case IB_WR_LOCAL_INV:
11758c2ecf20Sopenharmony_ci		handle_local_inv(qp, wr, ctrl, seg, size, cur_edge, *idx);
11768c2ecf20Sopenharmony_ci		*num_sge = 0;
11778c2ecf20Sopenharmony_ci		break;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	case IB_WR_REG_MR:
11808c2ecf20Sopenharmony_ci		err = handle_reg_mr(qp, wr, ctrl, seg, size, cur_edge, *idx);
11818c2ecf20Sopenharmony_ci		if (unlikely(err))
11828c2ecf20Sopenharmony_ci			goto out;
11838c2ecf20Sopenharmony_ci		*num_sge = 0;
11848c2ecf20Sopenharmony_ci		break;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	case IB_WR_REG_MR_INTEGRITY:
11878c2ecf20Sopenharmony_ci		err = handle_reg_mr_integrity(dev, qp, wr, ctrl, seg, size,
11888c2ecf20Sopenharmony_ci					      cur_edge, idx, nreq, fence,
11898c2ecf20Sopenharmony_ci					      next_fence);
11908c2ecf20Sopenharmony_ci		if (unlikely(err))
11918c2ecf20Sopenharmony_ci			goto out;
11928c2ecf20Sopenharmony_ci		*num_sge = 0;
11938c2ecf20Sopenharmony_ci		break;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	default:
11968c2ecf20Sopenharmony_ci		break;
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ciout:
12008c2ecf20Sopenharmony_ci	return err;
12018c2ecf20Sopenharmony_ci}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cistatic void handle_qpt_uc(const struct ib_send_wr *wr, void **seg, int *size)
12048c2ecf20Sopenharmony_ci{
12058c2ecf20Sopenharmony_ci	switch (wr->opcode) {
12068c2ecf20Sopenharmony_ci	case IB_WR_RDMA_WRITE:
12078c2ecf20Sopenharmony_ci	case IB_WR_RDMA_WRITE_WITH_IMM:
12088c2ecf20Sopenharmony_ci		handle_rdma_op(wr, seg, size);
12098c2ecf20Sopenharmony_ci		break;
12108c2ecf20Sopenharmony_ci	default:
12118c2ecf20Sopenharmony_ci		break;
12128c2ecf20Sopenharmony_ci	}
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_cistatic void handle_qpt_hw_gsi(struct mlx5_ib_qp *qp,
12168c2ecf20Sopenharmony_ci			      const struct ib_send_wr *wr, void **seg,
12178c2ecf20Sopenharmony_ci			      int *size, void **cur_edge)
12188c2ecf20Sopenharmony_ci{
12198c2ecf20Sopenharmony_ci	set_datagram_seg(*seg, wr);
12208c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_wqe_datagram_seg);
12218c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_wqe_datagram_seg) / 16;
12228c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
12238c2ecf20Sopenharmony_ci}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_cistatic void handle_qpt_ud(struct mlx5_ib_qp *qp, const struct ib_send_wr *wr,
12268c2ecf20Sopenharmony_ci			  void **seg, int *size, void **cur_edge)
12278c2ecf20Sopenharmony_ci{
12288c2ecf20Sopenharmony_ci	set_datagram_seg(*seg, wr);
12298c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_wqe_datagram_seg);
12308c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_wqe_datagram_seg) / 16;
12318c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	/* handle qp that supports ud offload */
12348c2ecf20Sopenharmony_ci	if (qp->flags & IB_QP_CREATE_IPOIB_UD_LSO) {
12358c2ecf20Sopenharmony_ci		struct mlx5_wqe_eth_pad *pad;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci		pad = *seg;
12388c2ecf20Sopenharmony_ci		memset(pad, 0, sizeof(struct mlx5_wqe_eth_pad));
12398c2ecf20Sopenharmony_ci		*seg += sizeof(struct mlx5_wqe_eth_pad);
12408c2ecf20Sopenharmony_ci		*size += sizeof(struct mlx5_wqe_eth_pad) / 16;
12418c2ecf20Sopenharmony_ci		set_eth_seg(wr, qp, seg, size, cur_edge);
12428c2ecf20Sopenharmony_ci		handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_cistatic int handle_qpt_reg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
12478c2ecf20Sopenharmony_ci			      const struct ib_send_wr *wr,
12488c2ecf20Sopenharmony_ci			      struct mlx5_wqe_ctrl_seg **ctrl, void **seg,
12498c2ecf20Sopenharmony_ci			      int *size, void **cur_edge, unsigned int idx)
12508c2ecf20Sopenharmony_ci{
12518c2ecf20Sopenharmony_ci	int err = 0;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	if (unlikely(wr->opcode != MLX5_IB_WR_UMR)) {
12548c2ecf20Sopenharmony_ci		err = -EINVAL;
12558c2ecf20Sopenharmony_ci		mlx5_ib_warn(dev, "bad opcode %d\n", wr->opcode);
12568c2ecf20Sopenharmony_ci		goto out;
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	qp->sq.wr_data[idx] = MLX5_IB_WR_UMR;
12608c2ecf20Sopenharmony_ci	(*ctrl)->imm = cpu_to_be32(umr_wr(wr)->mkey);
12618c2ecf20Sopenharmony_ci	err = set_reg_umr_segment(dev, *seg, wr);
12628c2ecf20Sopenharmony_ci	if (unlikely(err))
12638c2ecf20Sopenharmony_ci		goto out;
12648c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_wqe_umr_ctrl_seg);
12658c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16;
12668c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
12678c2ecf20Sopenharmony_ci	set_reg_mkey_segment(dev, *seg, wr);
12688c2ecf20Sopenharmony_ci	*seg += sizeof(struct mlx5_mkey_seg);
12698c2ecf20Sopenharmony_ci	*size += sizeof(struct mlx5_mkey_seg) / 16;
12708c2ecf20Sopenharmony_ci	handle_post_send_edge(&qp->sq, seg, *size, cur_edge);
12718c2ecf20Sopenharmony_ciout:
12728c2ecf20Sopenharmony_ci	return err;
12738c2ecf20Sopenharmony_ci}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ciint mlx5_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
12768c2ecf20Sopenharmony_ci		      const struct ib_send_wr **bad_wr, bool drain)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	struct mlx5_wqe_ctrl_seg *ctrl = NULL;  /* compiler warning */
12798c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
12808c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
12818c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *qp;
12828c2ecf20Sopenharmony_ci	struct mlx5_wqe_xrc_seg *xrc;
12838c2ecf20Sopenharmony_ci	struct mlx5_bf *bf;
12848c2ecf20Sopenharmony_ci	void *cur_edge;
12858c2ecf20Sopenharmony_ci	int size;
12868c2ecf20Sopenharmony_ci	unsigned long flags;
12878c2ecf20Sopenharmony_ci	unsigned int idx;
12888c2ecf20Sopenharmony_ci	int err = 0;
12898c2ecf20Sopenharmony_ci	int num_sge;
12908c2ecf20Sopenharmony_ci	void *seg;
12918c2ecf20Sopenharmony_ci	int nreq;
12928c2ecf20Sopenharmony_ci	int i;
12938c2ecf20Sopenharmony_ci	u8 next_fence = 0;
12948c2ecf20Sopenharmony_ci	u8 fence;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR &&
12978c2ecf20Sopenharmony_ci		     !drain)) {
12988c2ecf20Sopenharmony_ci		*bad_wr = wr;
12998c2ecf20Sopenharmony_ci		return -EIO;
13008c2ecf20Sopenharmony_ci	}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	if (unlikely(ibqp->qp_type == IB_QPT_GSI))
13038c2ecf20Sopenharmony_ci		return mlx5_ib_gsi_post_send(ibqp, wr, bad_wr);
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	qp = to_mqp(ibqp);
13068c2ecf20Sopenharmony_ci	bf = &qp->bf;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&qp->sq.lock, flags);
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	for (nreq = 0; wr; nreq++, wr = wr->next) {
13118c2ecf20Sopenharmony_ci		if (unlikely(wr->opcode >= ARRAY_SIZE(mlx5_ib_opcode))) {
13128c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "\n");
13138c2ecf20Sopenharmony_ci			err = -EINVAL;
13148c2ecf20Sopenharmony_ci			*bad_wr = wr;
13158c2ecf20Sopenharmony_ci			goto out;
13168c2ecf20Sopenharmony_ci		}
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci		num_sge = wr->num_sge;
13198c2ecf20Sopenharmony_ci		if (unlikely(num_sge > qp->sq.max_gs)) {
13208c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "\n");
13218c2ecf20Sopenharmony_ci			err = -EINVAL;
13228c2ecf20Sopenharmony_ci			*bad_wr = wr;
13238c2ecf20Sopenharmony_ci			goto out;
13248c2ecf20Sopenharmony_ci		}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci		err = begin_wqe(qp, &seg, &ctrl, wr, &idx, &size, &cur_edge,
13278c2ecf20Sopenharmony_ci				nreq);
13288c2ecf20Sopenharmony_ci		if (err) {
13298c2ecf20Sopenharmony_ci			mlx5_ib_warn(dev, "\n");
13308c2ecf20Sopenharmony_ci			err = -ENOMEM;
13318c2ecf20Sopenharmony_ci			*bad_wr = wr;
13328c2ecf20Sopenharmony_ci			goto out;
13338c2ecf20Sopenharmony_ci		}
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci		if (wr->opcode == IB_WR_REG_MR ||
13368c2ecf20Sopenharmony_ci		    wr->opcode == IB_WR_REG_MR_INTEGRITY) {
13378c2ecf20Sopenharmony_ci			fence = dev->umr_fence;
13388c2ecf20Sopenharmony_ci			next_fence = MLX5_FENCE_MODE_INITIATOR_SMALL;
13398c2ecf20Sopenharmony_ci		} else  {
13408c2ecf20Sopenharmony_ci			if (wr->send_flags & IB_SEND_FENCE) {
13418c2ecf20Sopenharmony_ci				if (qp->next_fence)
13428c2ecf20Sopenharmony_ci					fence = MLX5_FENCE_MODE_SMALL_AND_FENCE;
13438c2ecf20Sopenharmony_ci				else
13448c2ecf20Sopenharmony_ci					fence = MLX5_FENCE_MODE_FENCE;
13458c2ecf20Sopenharmony_ci			} else {
13468c2ecf20Sopenharmony_ci				fence = qp->next_fence;
13478c2ecf20Sopenharmony_ci			}
13488c2ecf20Sopenharmony_ci		}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci		switch (ibqp->qp_type) {
13518c2ecf20Sopenharmony_ci		case IB_QPT_XRC_INI:
13528c2ecf20Sopenharmony_ci			xrc = seg;
13538c2ecf20Sopenharmony_ci			seg += sizeof(*xrc);
13548c2ecf20Sopenharmony_ci			size += sizeof(*xrc) / 16;
13558c2ecf20Sopenharmony_ci			fallthrough;
13568c2ecf20Sopenharmony_ci		case IB_QPT_RC:
13578c2ecf20Sopenharmony_ci			err = handle_qpt_rc(dev, qp, wr, &ctrl, &seg, &size,
13588c2ecf20Sopenharmony_ci					    &cur_edge, &idx, nreq, fence,
13598c2ecf20Sopenharmony_ci					    next_fence, &num_sge);
13608c2ecf20Sopenharmony_ci			if (unlikely(err)) {
13618c2ecf20Sopenharmony_ci				*bad_wr = wr;
13628c2ecf20Sopenharmony_ci				goto out;
13638c2ecf20Sopenharmony_ci			} else if (wr->opcode == IB_WR_REG_MR_INTEGRITY) {
13648c2ecf20Sopenharmony_ci				goto skip_psv;
13658c2ecf20Sopenharmony_ci			}
13668c2ecf20Sopenharmony_ci			break;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci		case IB_QPT_UC:
13698c2ecf20Sopenharmony_ci			handle_qpt_uc(wr, &seg, &size);
13708c2ecf20Sopenharmony_ci			break;
13718c2ecf20Sopenharmony_ci		case IB_QPT_SMI:
13728c2ecf20Sopenharmony_ci			if (unlikely(!mdev->port_caps[qp->port - 1].has_smi)) {
13738c2ecf20Sopenharmony_ci				mlx5_ib_warn(dev, "Send SMP MADs is not allowed\n");
13748c2ecf20Sopenharmony_ci				err = -EPERM;
13758c2ecf20Sopenharmony_ci				*bad_wr = wr;
13768c2ecf20Sopenharmony_ci				goto out;
13778c2ecf20Sopenharmony_ci			}
13788c2ecf20Sopenharmony_ci			fallthrough;
13798c2ecf20Sopenharmony_ci		case MLX5_IB_QPT_HW_GSI:
13808c2ecf20Sopenharmony_ci			handle_qpt_hw_gsi(qp, wr, &seg, &size, &cur_edge);
13818c2ecf20Sopenharmony_ci			break;
13828c2ecf20Sopenharmony_ci		case IB_QPT_UD:
13838c2ecf20Sopenharmony_ci			handle_qpt_ud(qp, wr, &seg, &size, &cur_edge);
13848c2ecf20Sopenharmony_ci			break;
13858c2ecf20Sopenharmony_ci		case MLX5_IB_QPT_REG_UMR:
13868c2ecf20Sopenharmony_ci			err = handle_qpt_reg_umr(dev, qp, wr, &ctrl, &seg,
13878c2ecf20Sopenharmony_ci						       &size, &cur_edge, idx);
13888c2ecf20Sopenharmony_ci			if (unlikely(err))
13898c2ecf20Sopenharmony_ci				goto out;
13908c2ecf20Sopenharmony_ci			break;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci		default:
13938c2ecf20Sopenharmony_ci			break;
13948c2ecf20Sopenharmony_ci		}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci		if (wr->send_flags & IB_SEND_INLINE && num_sge) {
13978c2ecf20Sopenharmony_ci			err = set_data_inl_seg(qp, wr, &seg, &size, &cur_edge);
13988c2ecf20Sopenharmony_ci			if (unlikely(err)) {
13998c2ecf20Sopenharmony_ci				mlx5_ib_warn(dev, "\n");
14008c2ecf20Sopenharmony_ci				*bad_wr = wr;
14018c2ecf20Sopenharmony_ci				goto out;
14028c2ecf20Sopenharmony_ci			}
14038c2ecf20Sopenharmony_ci		} else {
14048c2ecf20Sopenharmony_ci			for (i = 0; i < num_sge; i++) {
14058c2ecf20Sopenharmony_ci				handle_post_send_edge(&qp->sq, &seg, size,
14068c2ecf20Sopenharmony_ci						      &cur_edge);
14078c2ecf20Sopenharmony_ci				if (unlikely(!wr->sg_list[i].length))
14088c2ecf20Sopenharmony_ci					continue;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci				set_data_ptr_seg(
14118c2ecf20Sopenharmony_ci					(struct mlx5_wqe_data_seg *)seg,
14128c2ecf20Sopenharmony_ci					wr->sg_list + i);
14138c2ecf20Sopenharmony_ci				size += sizeof(struct mlx5_wqe_data_seg) / 16;
14148c2ecf20Sopenharmony_ci				seg += sizeof(struct mlx5_wqe_data_seg);
14158c2ecf20Sopenharmony_ci			}
14168c2ecf20Sopenharmony_ci		}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci		qp->next_fence = next_fence;
14198c2ecf20Sopenharmony_ci		finish_wqe(qp, ctrl, seg, size, cur_edge, idx, wr->wr_id, nreq,
14208c2ecf20Sopenharmony_ci			   fence, mlx5_ib_opcode[wr->opcode]);
14218c2ecf20Sopenharmony_ciskip_psv:
14228c2ecf20Sopenharmony_ci		if (0)
14238c2ecf20Sopenharmony_ci			dump_wqe(qp, idx, size);
14248c2ecf20Sopenharmony_ci	}
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ciout:
14278c2ecf20Sopenharmony_ci	if (likely(nreq)) {
14288c2ecf20Sopenharmony_ci		qp->sq.head += nreq;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci		/* Make sure that descriptors are written before
14318c2ecf20Sopenharmony_ci		 * updating doorbell record and ringing the doorbell
14328c2ecf20Sopenharmony_ci		 */
14338c2ecf20Sopenharmony_ci		wmb();
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci		qp->db.db[MLX5_SND_DBR] = cpu_to_be32(qp->sq.cur_post);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci		/* Make sure doorbell record is visible to the HCA before
14388c2ecf20Sopenharmony_ci		 * we hit doorbell.
14398c2ecf20Sopenharmony_ci		 */
14408c2ecf20Sopenharmony_ci		wmb();
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci		mlx5_write64((__be32 *)ctrl, bf->bfreg->map + bf->offset);
14438c2ecf20Sopenharmony_ci		/* Make sure doorbells don't leak out of SQ spinlock
14448c2ecf20Sopenharmony_ci		 * and reach the HCA out of order.
14458c2ecf20Sopenharmony_ci		 */
14468c2ecf20Sopenharmony_ci		bf->offset ^= bf->buf_size;
14478c2ecf20Sopenharmony_ci	}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&qp->sq.lock, flags);
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	return err;
14528c2ecf20Sopenharmony_ci}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_cistatic void set_sig_seg(struct mlx5_rwqe_sig *sig, int max_gs)
14558c2ecf20Sopenharmony_ci{
14568c2ecf20Sopenharmony_ci	 sig->signature = calc_sig(sig, (max_gs + 1) << 2);
14578c2ecf20Sopenharmony_ci}
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ciint mlx5_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
14608c2ecf20Sopenharmony_ci		      const struct ib_recv_wr **bad_wr, bool drain)
14618c2ecf20Sopenharmony_ci{
14628c2ecf20Sopenharmony_ci	struct mlx5_ib_qp *qp = to_mqp(ibqp);
14638c2ecf20Sopenharmony_ci	struct mlx5_wqe_data_seg *scat;
14648c2ecf20Sopenharmony_ci	struct mlx5_rwqe_sig *sig;
14658c2ecf20Sopenharmony_ci	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
14668c2ecf20Sopenharmony_ci	struct mlx5_core_dev *mdev = dev->mdev;
14678c2ecf20Sopenharmony_ci	unsigned long flags;
14688c2ecf20Sopenharmony_ci	int err = 0;
14698c2ecf20Sopenharmony_ci	int nreq;
14708c2ecf20Sopenharmony_ci	int ind;
14718c2ecf20Sopenharmony_ci	int i;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR &&
14748c2ecf20Sopenharmony_ci		     !drain)) {
14758c2ecf20Sopenharmony_ci		*bad_wr = wr;
14768c2ecf20Sopenharmony_ci		return -EIO;
14778c2ecf20Sopenharmony_ci	}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	if (unlikely(ibqp->qp_type == IB_QPT_GSI))
14808c2ecf20Sopenharmony_ci		return mlx5_ib_gsi_post_recv(ibqp, wr, bad_wr);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	spin_lock_irqsave(&qp->rq.lock, flags);
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	for (nreq = 0; wr; nreq++, wr = wr->next) {
14878c2ecf20Sopenharmony_ci		if (mlx5_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
14888c2ecf20Sopenharmony_ci			err = -ENOMEM;
14898c2ecf20Sopenharmony_ci			*bad_wr = wr;
14908c2ecf20Sopenharmony_ci			goto out;
14918c2ecf20Sopenharmony_ci		}
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci		if (unlikely(wr->num_sge > qp->rq.max_gs)) {
14948c2ecf20Sopenharmony_ci			err = -EINVAL;
14958c2ecf20Sopenharmony_ci			*bad_wr = wr;
14968c2ecf20Sopenharmony_ci			goto out;
14978c2ecf20Sopenharmony_ci		}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci		scat = mlx5_frag_buf_get_wqe(&qp->rq.fbc, ind);
15008c2ecf20Sopenharmony_ci		if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE)
15018c2ecf20Sopenharmony_ci			scat++;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci		for (i = 0; i < wr->num_sge; i++)
15048c2ecf20Sopenharmony_ci			set_data_ptr_seg(scat + i, wr->sg_list + i);
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci		if (i < qp->rq.max_gs) {
15078c2ecf20Sopenharmony_ci			scat[i].byte_count = 0;
15088c2ecf20Sopenharmony_ci			scat[i].lkey       = cpu_to_be32(MLX5_INVALID_LKEY);
15098c2ecf20Sopenharmony_ci			scat[i].addr       = 0;
15108c2ecf20Sopenharmony_ci		}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci		if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE) {
15138c2ecf20Sopenharmony_ci			sig = (struct mlx5_rwqe_sig *)scat;
15148c2ecf20Sopenharmony_ci			set_sig_seg(sig, qp->rq.max_gs);
15158c2ecf20Sopenharmony_ci		}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci		qp->rq.wrid[ind] = wr->wr_id;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci		ind = (ind + 1) & (qp->rq.wqe_cnt - 1);
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ciout:
15238c2ecf20Sopenharmony_ci	if (likely(nreq)) {
15248c2ecf20Sopenharmony_ci		qp->rq.head += nreq;
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci		/* Make sure that descriptors are written before
15278c2ecf20Sopenharmony_ci		 * doorbell record.
15288c2ecf20Sopenharmony_ci		 */
15298c2ecf20Sopenharmony_ci		wmb();
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci		*qp->db.db = cpu_to_be32(qp->rq.head & 0xffff);
15328c2ecf20Sopenharmony_ci	}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&qp->rq.lock, flags);
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	return err;
15378c2ecf20Sopenharmony_ci}
1538