162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/* Authors: Bernard Metzler <bmt@zurich.ibm.com> */
462306a36Sopenharmony_ci/* Copyright (c) 2008-2019, IBM Corporation */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/errno.h>
762306a36Sopenharmony_ci#include <linux/types.h>
862306a36Sopenharmony_ci#include <linux/uaccess.h>
962306a36Sopenharmony_ci#include <linux/vmalloc.h>
1062306a36Sopenharmony_ci#include <linux/xarray.h>
1162306a36Sopenharmony_ci#include <net/addrconf.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <rdma/iw_cm.h>
1462306a36Sopenharmony_ci#include <rdma/ib_verbs.h>
1562306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h>
1662306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "siw.h"
1962306a36Sopenharmony_ci#include "siw_verbs.h"
2062306a36Sopenharmony_ci#include "siw_mem.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic int ib_qp_state_to_siw_qp_state[IB_QPS_ERR + 1] = {
2362306a36Sopenharmony_ci	[IB_QPS_RESET] = SIW_QP_STATE_IDLE,
2462306a36Sopenharmony_ci	[IB_QPS_INIT] = SIW_QP_STATE_IDLE,
2562306a36Sopenharmony_ci	[IB_QPS_RTR] = SIW_QP_STATE_RTR,
2662306a36Sopenharmony_ci	[IB_QPS_RTS] = SIW_QP_STATE_RTS,
2762306a36Sopenharmony_ci	[IB_QPS_SQD] = SIW_QP_STATE_CLOSING,
2862306a36Sopenharmony_ci	[IB_QPS_SQE] = SIW_QP_STATE_TERMINATE,
2962306a36Sopenharmony_ci	[IB_QPS_ERR] = SIW_QP_STATE_ERROR
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistatic char ib_qp_state_to_string[IB_QPS_ERR + 1][sizeof("RESET")] = {
3362306a36Sopenharmony_ci	[IB_QPS_RESET] = "RESET", [IB_QPS_INIT] = "INIT", [IB_QPS_RTR] = "RTR",
3462306a36Sopenharmony_ci	[IB_QPS_RTS] = "RTS",     [IB_QPS_SQD] = "SQD",   [IB_QPS_SQE] = "SQE",
3562306a36Sopenharmony_ci	[IB_QPS_ERR] = "ERR"
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_civoid siw_mmap_free(struct rdma_user_mmap_entry *rdma_entry)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct siw_user_mmap_entry *entry = to_siw_mmap_entry(rdma_entry);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	kfree(entry);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciint siw_mmap(struct ib_ucontext *ctx, struct vm_area_struct *vma)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct siw_ucontext *uctx = to_siw_ctx(ctx);
4862306a36Sopenharmony_ci	size_t size = vma->vm_end - vma->vm_start;
4962306a36Sopenharmony_ci	struct rdma_user_mmap_entry *rdma_entry;
5062306a36Sopenharmony_ci	struct siw_user_mmap_entry *entry;
5162306a36Sopenharmony_ci	int rv = -EINVAL;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	/*
5462306a36Sopenharmony_ci	 * Must be page aligned
5562306a36Sopenharmony_ci	 */
5662306a36Sopenharmony_ci	if (vma->vm_start & (PAGE_SIZE - 1)) {
5762306a36Sopenharmony_ci		pr_warn("siw: mmap not page aligned\n");
5862306a36Sopenharmony_ci		return -EINVAL;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci	rdma_entry = rdma_user_mmap_entry_get(&uctx->base_ucontext, vma);
6162306a36Sopenharmony_ci	if (!rdma_entry) {
6262306a36Sopenharmony_ci		siw_dbg(&uctx->sdev->base_dev, "mmap lookup failed: %lu, %#zx\n",
6362306a36Sopenharmony_ci			vma->vm_pgoff, size);
6462306a36Sopenharmony_ci		return -EINVAL;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci	entry = to_siw_mmap_entry(rdma_entry);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	rv = remap_vmalloc_range(vma, entry->address, 0);
6962306a36Sopenharmony_ci	if (rv) {
7062306a36Sopenharmony_ci		pr_warn("remap_vmalloc_range failed: %lu, %zu\n", vma->vm_pgoff,
7162306a36Sopenharmony_ci			size);
7262306a36Sopenharmony_ci		goto out;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ciout:
7562306a36Sopenharmony_ci	rdma_user_mmap_entry_put(rdma_entry);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return rv;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciint siw_alloc_ucontext(struct ib_ucontext *base_ctx, struct ib_udata *udata)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_ctx->device);
8362306a36Sopenharmony_ci	struct siw_ucontext *ctx = to_siw_ctx(base_ctx);
8462306a36Sopenharmony_ci	struct siw_uresp_alloc_ctx uresp = {};
8562306a36Sopenharmony_ci	int rv;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (atomic_inc_return(&sdev->num_ctx) > SIW_MAX_CONTEXT) {
8862306a36Sopenharmony_ci		rv = -ENOMEM;
8962306a36Sopenharmony_ci		goto err_out;
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci	ctx->sdev = sdev;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	uresp.dev_id = sdev->vendor_part_id;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (udata->outlen < sizeof(uresp)) {
9662306a36Sopenharmony_ci		rv = -EINVAL;
9762306a36Sopenharmony_ci		goto err_out;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci	rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
10062306a36Sopenharmony_ci	if (rv)
10162306a36Sopenharmony_ci		goto err_out;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	siw_dbg(base_ctx->device, "success. now %d context(s)\n",
10462306a36Sopenharmony_ci		atomic_read(&sdev->num_ctx));
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cierr_out:
10962306a36Sopenharmony_ci	atomic_dec(&sdev->num_ctx);
11062306a36Sopenharmony_ci	siw_dbg(base_ctx->device, "failure %d. now %d context(s)\n", rv,
11162306a36Sopenharmony_ci		atomic_read(&sdev->num_ctx));
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return rv;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_civoid siw_dealloc_ucontext(struct ib_ucontext *base_ctx)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct siw_ucontext *uctx = to_siw_ctx(base_ctx);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	atomic_dec(&uctx->sdev->num_ctx);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciint siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr,
12462306a36Sopenharmony_ci		     struct ib_udata *udata)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_dev);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (udata->inlen || udata->outlen)
12962306a36Sopenharmony_ci		return -EINVAL;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	memset(attr, 0, sizeof(*attr));
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* Revisit atomic caps if RFC 7306 gets supported */
13462306a36Sopenharmony_ci	attr->atomic_cap = 0;
13562306a36Sopenharmony_ci	attr->device_cap_flags = IB_DEVICE_MEM_MGT_EXTENSIONS;
13662306a36Sopenharmony_ci	attr->kernel_cap_flags = IBK_ALLOW_USER_UNREG;
13762306a36Sopenharmony_ci	attr->max_cq = sdev->attrs.max_cq;
13862306a36Sopenharmony_ci	attr->max_cqe = sdev->attrs.max_cqe;
13962306a36Sopenharmony_ci	attr->max_fast_reg_page_list_len = SIW_MAX_SGE_PBL;
14062306a36Sopenharmony_ci	attr->max_mr = sdev->attrs.max_mr;
14162306a36Sopenharmony_ci	attr->max_mw = sdev->attrs.max_mw;
14262306a36Sopenharmony_ci	attr->max_mr_size = ~0ull;
14362306a36Sopenharmony_ci	attr->max_pd = sdev->attrs.max_pd;
14462306a36Sopenharmony_ci	attr->max_qp = sdev->attrs.max_qp;
14562306a36Sopenharmony_ci	attr->max_qp_init_rd_atom = sdev->attrs.max_ird;
14662306a36Sopenharmony_ci	attr->max_qp_rd_atom = sdev->attrs.max_ord;
14762306a36Sopenharmony_ci	attr->max_qp_wr = sdev->attrs.max_qp_wr;
14862306a36Sopenharmony_ci	attr->max_recv_sge = sdev->attrs.max_sge;
14962306a36Sopenharmony_ci	attr->max_res_rd_atom = sdev->attrs.max_qp * sdev->attrs.max_ird;
15062306a36Sopenharmony_ci	attr->max_send_sge = sdev->attrs.max_sge;
15162306a36Sopenharmony_ci	attr->max_sge_rd = sdev->attrs.max_sge_rd;
15262306a36Sopenharmony_ci	attr->max_srq = sdev->attrs.max_srq;
15362306a36Sopenharmony_ci	attr->max_srq_sge = sdev->attrs.max_srq_sge;
15462306a36Sopenharmony_ci	attr->max_srq_wr = sdev->attrs.max_srq_wr;
15562306a36Sopenharmony_ci	attr->page_size_cap = PAGE_SIZE;
15662306a36Sopenharmony_ci	attr->vendor_id = SIW_VENDOR_ID;
15762306a36Sopenharmony_ci	attr->vendor_part_id = sdev->vendor_part_id;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	addrconf_addr_eui48((u8 *)&attr->sys_image_guid,
16062306a36Sopenharmony_ci			    sdev->raw_gid);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ciint siw_query_port(struct ib_device *base_dev, u32 port,
16662306a36Sopenharmony_ci		   struct ib_port_attr *attr)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_dev);
16962306a36Sopenharmony_ci	int rv;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	memset(attr, 0, sizeof(*attr));
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	rv = ib_get_eth_speed(base_dev, port, &attr->active_speed,
17462306a36Sopenharmony_ci			 &attr->active_width);
17562306a36Sopenharmony_ci	attr->gid_tbl_len = 1;
17662306a36Sopenharmony_ci	attr->max_msg_sz = -1;
17762306a36Sopenharmony_ci	attr->max_mtu = ib_mtu_int_to_enum(sdev->netdev->mtu);
17862306a36Sopenharmony_ci	attr->active_mtu = ib_mtu_int_to_enum(sdev->netdev->mtu);
17962306a36Sopenharmony_ci	attr->phys_state = sdev->state == IB_PORT_ACTIVE ?
18062306a36Sopenharmony_ci		IB_PORT_PHYS_STATE_LINK_UP : IB_PORT_PHYS_STATE_DISABLED;
18162306a36Sopenharmony_ci	attr->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_DEVICE_MGMT_SUP;
18262306a36Sopenharmony_ci	attr->state = sdev->state;
18362306a36Sopenharmony_ci	/*
18462306a36Sopenharmony_ci	 * All zero
18562306a36Sopenharmony_ci	 *
18662306a36Sopenharmony_ci	 * attr->lid = 0;
18762306a36Sopenharmony_ci	 * attr->bad_pkey_cntr = 0;
18862306a36Sopenharmony_ci	 * attr->qkey_viol_cntr = 0;
18962306a36Sopenharmony_ci	 * attr->sm_lid = 0;
19062306a36Sopenharmony_ci	 * attr->lmc = 0;
19162306a36Sopenharmony_ci	 * attr->max_vl_num = 0;
19262306a36Sopenharmony_ci	 * attr->sm_sl = 0;
19362306a36Sopenharmony_ci	 * attr->subnet_timeout = 0;
19462306a36Sopenharmony_ci	 * attr->init_type_repy = 0;
19562306a36Sopenharmony_ci	 */
19662306a36Sopenharmony_ci	return rv;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ciint siw_get_port_immutable(struct ib_device *base_dev, u32 port,
20062306a36Sopenharmony_ci			   struct ib_port_immutable *port_immutable)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct ib_port_attr attr;
20362306a36Sopenharmony_ci	int rv = siw_query_port(base_dev, port, &attr);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	if (rv)
20662306a36Sopenharmony_ci		return rv;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	port_immutable->gid_tbl_len = attr.gid_tbl_len;
20962306a36Sopenharmony_ci	port_immutable->core_cap_flags = RDMA_CORE_PORT_IWARP;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciint siw_query_gid(struct ib_device *base_dev, u32 port, int idx,
21562306a36Sopenharmony_ci		  union ib_gid *gid)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_dev);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* subnet_prefix == interface_id == 0; */
22062306a36Sopenharmony_ci	memset(gid, 0, sizeof(*gid));
22162306a36Sopenharmony_ci	memcpy(gid->raw, sdev->raw_gid, ETH_ALEN);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	return 0;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ciint siw_alloc_pd(struct ib_pd *pd, struct ib_udata *udata)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(pd->device);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (atomic_inc_return(&sdev->num_pd) > SIW_MAX_PD) {
23162306a36Sopenharmony_ci		atomic_dec(&sdev->num_pd);
23262306a36Sopenharmony_ci		return -ENOMEM;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci	siw_dbg_pd(pd, "now %d PD's(s)\n", atomic_read(&sdev->num_pd));
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciint siw_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(pd->device);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	siw_dbg_pd(pd, "free PD\n");
24462306a36Sopenharmony_ci	atomic_dec(&sdev->num_pd);
24562306a36Sopenharmony_ci	return 0;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_civoid siw_qp_get_ref(struct ib_qp *base_qp)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	siw_qp_get(to_siw_qp(base_qp));
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_civoid siw_qp_put_ref(struct ib_qp *base_qp)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	siw_qp_put(to_siw_qp(base_qp));
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic struct rdma_user_mmap_entry *
25962306a36Sopenharmony_cisiw_mmap_entry_insert(struct siw_ucontext *uctx,
26062306a36Sopenharmony_ci		      void *address, size_t length,
26162306a36Sopenharmony_ci		      u64 *offset)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct siw_user_mmap_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
26462306a36Sopenharmony_ci	int rv;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	*offset = SIW_INVAL_UOBJ_KEY;
26762306a36Sopenharmony_ci	if (!entry)
26862306a36Sopenharmony_ci		return NULL;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	entry->address = address;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	rv = rdma_user_mmap_entry_insert(&uctx->base_ucontext,
27362306a36Sopenharmony_ci					 &entry->rdma_entry,
27462306a36Sopenharmony_ci					 length);
27562306a36Sopenharmony_ci	if (rv) {
27662306a36Sopenharmony_ci		kfree(entry);
27762306a36Sopenharmony_ci		return NULL;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	*offset = rdma_user_mmap_get_offset(&entry->rdma_entry);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return &entry->rdma_entry;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/*
28662306a36Sopenharmony_ci * siw_create_qp()
28762306a36Sopenharmony_ci *
28862306a36Sopenharmony_ci * Create QP of requested size on given device.
28962306a36Sopenharmony_ci *
29062306a36Sopenharmony_ci * @qp:		Queue pait
29162306a36Sopenharmony_ci * @attrs:	Initial QP attributes.
29262306a36Sopenharmony_ci * @udata:	used to provide QP ID, SQ and RQ size back to user.
29362306a36Sopenharmony_ci */
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ciint siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
29662306a36Sopenharmony_ci		  struct ib_udata *udata)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct ib_pd *pd = ibqp->pd;
29962306a36Sopenharmony_ci	struct siw_qp *qp = to_siw_qp(ibqp);
30062306a36Sopenharmony_ci	struct ib_device *base_dev = pd->device;
30162306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_dev);
30262306a36Sopenharmony_ci	struct siw_ucontext *uctx =
30362306a36Sopenharmony_ci		rdma_udata_to_drv_context(udata, struct siw_ucontext,
30462306a36Sopenharmony_ci					  base_ucontext);
30562306a36Sopenharmony_ci	unsigned long flags;
30662306a36Sopenharmony_ci	int num_sqe, num_rqe, rv = 0;
30762306a36Sopenharmony_ci	size_t length;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	siw_dbg(base_dev, "create new QP\n");
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (attrs->create_flags)
31262306a36Sopenharmony_ci		return -EOPNOTSUPP;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (atomic_inc_return(&sdev->num_qp) > SIW_MAX_QP) {
31562306a36Sopenharmony_ci		siw_dbg(base_dev, "too many QP's\n");
31662306a36Sopenharmony_ci		rv = -ENOMEM;
31762306a36Sopenharmony_ci		goto err_atomic;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci	if (attrs->qp_type != IB_QPT_RC) {
32062306a36Sopenharmony_ci		siw_dbg(base_dev, "only RC QP's supported\n");
32162306a36Sopenharmony_ci		rv = -EOPNOTSUPP;
32262306a36Sopenharmony_ci		goto err_atomic;
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci	if ((attrs->cap.max_send_wr > SIW_MAX_QP_WR) ||
32562306a36Sopenharmony_ci	    (attrs->cap.max_recv_wr > SIW_MAX_QP_WR) ||
32662306a36Sopenharmony_ci	    (attrs->cap.max_send_sge > SIW_MAX_SGE) ||
32762306a36Sopenharmony_ci	    (attrs->cap.max_recv_sge > SIW_MAX_SGE)) {
32862306a36Sopenharmony_ci		siw_dbg(base_dev, "QP size error\n");
32962306a36Sopenharmony_ci		rv = -EINVAL;
33062306a36Sopenharmony_ci		goto err_atomic;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci	if (attrs->cap.max_inline_data > SIW_MAX_INLINE) {
33362306a36Sopenharmony_ci		siw_dbg(base_dev, "max inline send: %d > %d\n",
33462306a36Sopenharmony_ci			attrs->cap.max_inline_data, (int)SIW_MAX_INLINE);
33562306a36Sopenharmony_ci		rv = -EINVAL;
33662306a36Sopenharmony_ci		goto err_atomic;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	/*
33962306a36Sopenharmony_ci	 * NOTE: we allow for zero element SQ and RQ WQE's SGL's
34062306a36Sopenharmony_ci	 * but not for a QP unable to hold any WQE (SQ + RQ)
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	if (attrs->cap.max_send_wr + attrs->cap.max_recv_wr == 0) {
34362306a36Sopenharmony_ci		siw_dbg(base_dev, "QP must have send or receive queue\n");
34462306a36Sopenharmony_ci		rv = -EINVAL;
34562306a36Sopenharmony_ci		goto err_atomic;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (!attrs->send_cq || (!attrs->recv_cq && !attrs->srq)) {
34962306a36Sopenharmony_ci		siw_dbg(base_dev, "send CQ or receive CQ invalid\n");
35062306a36Sopenharmony_ci		rv = -EINVAL;
35162306a36Sopenharmony_ci		goto err_atomic;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	init_rwsem(&qp->state_lock);
35562306a36Sopenharmony_ci	spin_lock_init(&qp->sq_lock);
35662306a36Sopenharmony_ci	spin_lock_init(&qp->rq_lock);
35762306a36Sopenharmony_ci	spin_lock_init(&qp->orq_lock);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	rv = siw_qp_add(sdev, qp);
36062306a36Sopenharmony_ci	if (rv)
36162306a36Sopenharmony_ci		goto err_atomic;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	num_sqe = attrs->cap.max_send_wr;
36462306a36Sopenharmony_ci	num_rqe = attrs->cap.max_recv_wr;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* All queue indices are derived from modulo operations
36762306a36Sopenharmony_ci	 * on a free running 'get' (consumer) and 'put' (producer)
36862306a36Sopenharmony_ci	 * unsigned counter. Having queue sizes at power of two
36962306a36Sopenharmony_ci	 * avoids handling counter wrap around.
37062306a36Sopenharmony_ci	 */
37162306a36Sopenharmony_ci	if (num_sqe)
37262306a36Sopenharmony_ci		num_sqe = roundup_pow_of_two(num_sqe);
37362306a36Sopenharmony_ci	else {
37462306a36Sopenharmony_ci		/* Zero sized SQ is not supported */
37562306a36Sopenharmony_ci		rv = -EINVAL;
37662306a36Sopenharmony_ci		goto err_out_xa;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci	if (num_rqe)
37962306a36Sopenharmony_ci		num_rqe = roundup_pow_of_two(num_rqe);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	if (udata)
38262306a36Sopenharmony_ci		qp->sendq = vmalloc_user(num_sqe * sizeof(struct siw_sqe));
38362306a36Sopenharmony_ci	else
38462306a36Sopenharmony_ci		qp->sendq = vcalloc(num_sqe, sizeof(struct siw_sqe));
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (qp->sendq == NULL) {
38762306a36Sopenharmony_ci		rv = -ENOMEM;
38862306a36Sopenharmony_ci		goto err_out_xa;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci	if (attrs->sq_sig_type != IB_SIGNAL_REQ_WR) {
39162306a36Sopenharmony_ci		if (attrs->sq_sig_type == IB_SIGNAL_ALL_WR)
39262306a36Sopenharmony_ci			qp->attrs.flags |= SIW_SIGNAL_ALL_WR;
39362306a36Sopenharmony_ci		else {
39462306a36Sopenharmony_ci			rv = -EINVAL;
39562306a36Sopenharmony_ci			goto err_out_xa;
39662306a36Sopenharmony_ci		}
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci	qp->pd = pd;
39962306a36Sopenharmony_ci	qp->scq = to_siw_cq(attrs->send_cq);
40062306a36Sopenharmony_ci	qp->rcq = to_siw_cq(attrs->recv_cq);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (attrs->srq) {
40362306a36Sopenharmony_ci		/*
40462306a36Sopenharmony_ci		 * SRQ support.
40562306a36Sopenharmony_ci		 * Verbs 6.3.7: ignore RQ size, if SRQ present
40662306a36Sopenharmony_ci		 * Verbs 6.3.5: do not check PD of SRQ against PD of QP
40762306a36Sopenharmony_ci		 */
40862306a36Sopenharmony_ci		qp->srq = to_siw_srq(attrs->srq);
40962306a36Sopenharmony_ci		qp->attrs.rq_size = 0;
41062306a36Sopenharmony_ci		siw_dbg(base_dev, "QP [%u]: SRQ attached\n",
41162306a36Sopenharmony_ci			qp->base_qp.qp_num);
41262306a36Sopenharmony_ci	} else if (num_rqe) {
41362306a36Sopenharmony_ci		if (udata)
41462306a36Sopenharmony_ci			qp->recvq =
41562306a36Sopenharmony_ci				vmalloc_user(num_rqe * sizeof(struct siw_rqe));
41662306a36Sopenharmony_ci		else
41762306a36Sopenharmony_ci			qp->recvq = vcalloc(num_rqe, sizeof(struct siw_rqe));
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		if (qp->recvq == NULL) {
42062306a36Sopenharmony_ci			rv = -ENOMEM;
42162306a36Sopenharmony_ci			goto err_out_xa;
42262306a36Sopenharmony_ci		}
42362306a36Sopenharmony_ci		qp->attrs.rq_size = num_rqe;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci	qp->attrs.sq_size = num_sqe;
42662306a36Sopenharmony_ci	qp->attrs.sq_max_sges = attrs->cap.max_send_sge;
42762306a36Sopenharmony_ci	qp->attrs.rq_max_sges = attrs->cap.max_recv_sge;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* Make those two tunables fixed for now. */
43062306a36Sopenharmony_ci	qp->tx_ctx.gso_seg_limit = 1;
43162306a36Sopenharmony_ci	qp->tx_ctx.zcopy_tx = zcopy_tx;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	qp->attrs.state = SIW_QP_STATE_IDLE;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (udata) {
43662306a36Sopenharmony_ci		struct siw_uresp_create_qp uresp = {};
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci		uresp.num_sqe = num_sqe;
43962306a36Sopenharmony_ci		uresp.num_rqe = num_rqe;
44062306a36Sopenharmony_ci		uresp.qp_id = qp_id(qp);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		if (qp->sendq) {
44362306a36Sopenharmony_ci			length = num_sqe * sizeof(struct siw_sqe);
44462306a36Sopenharmony_ci			qp->sq_entry =
44562306a36Sopenharmony_ci				siw_mmap_entry_insert(uctx, qp->sendq,
44662306a36Sopenharmony_ci						      length, &uresp.sq_key);
44762306a36Sopenharmony_ci			if (!qp->sq_entry) {
44862306a36Sopenharmony_ci				rv = -ENOMEM;
44962306a36Sopenharmony_ci				goto err_out_xa;
45062306a36Sopenharmony_ci			}
45162306a36Sopenharmony_ci		}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		if (qp->recvq) {
45462306a36Sopenharmony_ci			length = num_rqe * sizeof(struct siw_rqe);
45562306a36Sopenharmony_ci			qp->rq_entry =
45662306a36Sopenharmony_ci				siw_mmap_entry_insert(uctx, qp->recvq,
45762306a36Sopenharmony_ci						      length, &uresp.rq_key);
45862306a36Sopenharmony_ci			if (!qp->rq_entry) {
45962306a36Sopenharmony_ci				uresp.sq_key = SIW_INVAL_UOBJ_KEY;
46062306a36Sopenharmony_ci				rv = -ENOMEM;
46162306a36Sopenharmony_ci				goto err_out_xa;
46262306a36Sopenharmony_ci			}
46362306a36Sopenharmony_ci		}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci		if (udata->outlen < sizeof(uresp)) {
46662306a36Sopenharmony_ci			rv = -EINVAL;
46762306a36Sopenharmony_ci			goto err_out_xa;
46862306a36Sopenharmony_ci		}
46962306a36Sopenharmony_ci		rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
47062306a36Sopenharmony_ci		if (rv)
47162306a36Sopenharmony_ci			goto err_out_xa;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci	qp->tx_cpu = siw_get_tx_cpu(sdev);
47462306a36Sopenharmony_ci	if (qp->tx_cpu < 0) {
47562306a36Sopenharmony_ci		rv = -EINVAL;
47662306a36Sopenharmony_ci		goto err_out_xa;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci	INIT_LIST_HEAD(&qp->devq);
47962306a36Sopenharmony_ci	spin_lock_irqsave(&sdev->lock, flags);
48062306a36Sopenharmony_ci	list_add_tail(&qp->devq, &sdev->qp_list);
48162306a36Sopenharmony_ci	spin_unlock_irqrestore(&sdev->lock, flags);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	init_completion(&qp->qp_free);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	return 0;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cierr_out_xa:
48862306a36Sopenharmony_ci	xa_erase(&sdev->qp_xa, qp_id(qp));
48962306a36Sopenharmony_ci	if (uctx) {
49062306a36Sopenharmony_ci		rdma_user_mmap_entry_remove(qp->sq_entry);
49162306a36Sopenharmony_ci		rdma_user_mmap_entry_remove(qp->rq_entry);
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci	vfree(qp->sendq);
49462306a36Sopenharmony_ci	vfree(qp->recvq);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cierr_atomic:
49762306a36Sopenharmony_ci	atomic_dec(&sdev->num_qp);
49862306a36Sopenharmony_ci	return rv;
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/*
50262306a36Sopenharmony_ci * Minimum siw_query_qp() verb interface.
50362306a36Sopenharmony_ci *
50462306a36Sopenharmony_ci * @qp_attr_mask is not used but all available information is provided
50562306a36Sopenharmony_ci */
50662306a36Sopenharmony_ciint siw_query_qp(struct ib_qp *base_qp, struct ib_qp_attr *qp_attr,
50762306a36Sopenharmony_ci		 int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	struct siw_qp *qp;
51062306a36Sopenharmony_ci	struct siw_device *sdev;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	if (base_qp && qp_attr && qp_init_attr) {
51362306a36Sopenharmony_ci		qp = to_siw_qp(base_qp);
51462306a36Sopenharmony_ci		sdev = to_siw_dev(base_qp->device);
51562306a36Sopenharmony_ci	} else {
51662306a36Sopenharmony_ci		return -EINVAL;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci	qp_attr->cap.max_inline_data = SIW_MAX_INLINE;
51962306a36Sopenharmony_ci	qp_attr->cap.max_send_wr = qp->attrs.sq_size;
52062306a36Sopenharmony_ci	qp_attr->cap.max_send_sge = qp->attrs.sq_max_sges;
52162306a36Sopenharmony_ci	qp_attr->cap.max_recv_wr = qp->attrs.rq_size;
52262306a36Sopenharmony_ci	qp_attr->cap.max_recv_sge = qp->attrs.rq_max_sges;
52362306a36Sopenharmony_ci	qp_attr->path_mtu = ib_mtu_int_to_enum(sdev->netdev->mtu);
52462306a36Sopenharmony_ci	qp_attr->max_rd_atomic = qp->attrs.irq_size;
52562306a36Sopenharmony_ci	qp_attr->max_dest_rd_atomic = qp->attrs.orq_size;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE |
52862306a36Sopenharmony_ci				   IB_ACCESS_REMOTE_WRITE |
52962306a36Sopenharmony_ci				   IB_ACCESS_REMOTE_READ;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	qp_init_attr->qp_type = base_qp->qp_type;
53262306a36Sopenharmony_ci	qp_init_attr->send_cq = base_qp->send_cq;
53362306a36Sopenharmony_ci	qp_init_attr->recv_cq = base_qp->recv_cq;
53462306a36Sopenharmony_ci	qp_init_attr->srq = base_qp->srq;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	qp_init_attr->cap = qp_attr->cap;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return 0;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ciint siw_verbs_modify_qp(struct ib_qp *base_qp, struct ib_qp_attr *attr,
54262306a36Sopenharmony_ci			int attr_mask, struct ib_udata *udata)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct siw_qp_attrs new_attrs;
54562306a36Sopenharmony_ci	enum siw_qp_attr_mask siw_attr_mask = 0;
54662306a36Sopenharmony_ci	struct siw_qp *qp = to_siw_qp(base_qp);
54762306a36Sopenharmony_ci	int rv = 0;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (!attr_mask)
55062306a36Sopenharmony_ci		return 0;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
55362306a36Sopenharmony_ci		return -EOPNOTSUPP;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	memset(&new_attrs, 0, sizeof(new_attrs));
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (attr_mask & IB_QP_ACCESS_FLAGS) {
55862306a36Sopenharmony_ci		siw_attr_mask = SIW_QP_ATTR_ACCESS_FLAGS;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ)
56162306a36Sopenharmony_ci			new_attrs.flags |= SIW_RDMA_READ_ENABLED;
56262306a36Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
56362306a36Sopenharmony_ci			new_attrs.flags |= SIW_RDMA_WRITE_ENABLED;
56462306a36Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_MW_BIND)
56562306a36Sopenharmony_ci			new_attrs.flags |= SIW_RDMA_BIND_ENABLED;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci	if (attr_mask & IB_QP_STATE) {
56862306a36Sopenharmony_ci		siw_dbg_qp(qp, "desired IB QP state: %s\n",
56962306a36Sopenharmony_ci			   ib_qp_state_to_string[attr->qp_state]);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		new_attrs.state = ib_qp_state_to_siw_qp_state[attr->qp_state];
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci		if (new_attrs.state > SIW_QP_STATE_RTS)
57462306a36Sopenharmony_ci			qp->tx_ctx.tx_suspend = 1;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci		siw_attr_mask |= SIW_QP_ATTR_STATE;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci	if (!siw_attr_mask)
57962306a36Sopenharmony_ci		goto out;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	down_write(&qp->state_lock);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	rv = siw_qp_modify(qp, &new_attrs, siw_attr_mask);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	up_write(&qp->state_lock);
58662306a36Sopenharmony_ciout:
58762306a36Sopenharmony_ci	return rv;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ciint siw_destroy_qp(struct ib_qp *base_qp, struct ib_udata *udata)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct siw_qp *qp = to_siw_qp(base_qp);
59362306a36Sopenharmony_ci	struct siw_ucontext *uctx =
59462306a36Sopenharmony_ci		rdma_udata_to_drv_context(udata, struct siw_ucontext,
59562306a36Sopenharmony_ci					  base_ucontext);
59662306a36Sopenharmony_ci	struct siw_qp_attrs qp_attrs;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	siw_dbg_qp(qp, "state %d\n", qp->attrs.state);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/*
60162306a36Sopenharmony_ci	 * Mark QP as in process of destruction to prevent from
60262306a36Sopenharmony_ci	 * any async callbacks to RDMA core
60362306a36Sopenharmony_ci	 */
60462306a36Sopenharmony_ci	qp->attrs.flags |= SIW_QP_IN_DESTROY;
60562306a36Sopenharmony_ci	qp->rx_stream.rx_suspend = 1;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (uctx) {
60862306a36Sopenharmony_ci		rdma_user_mmap_entry_remove(qp->sq_entry);
60962306a36Sopenharmony_ci		rdma_user_mmap_entry_remove(qp->rq_entry);
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	down_write(&qp->state_lock);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	qp_attrs.state = SIW_QP_STATE_ERROR;
61562306a36Sopenharmony_ci	siw_qp_modify(qp, &qp_attrs, SIW_QP_ATTR_STATE);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (qp->cep) {
61862306a36Sopenharmony_ci		siw_cep_put(qp->cep);
61962306a36Sopenharmony_ci		qp->cep = NULL;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci	up_write(&qp->state_lock);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	kfree(qp->tx_ctx.mpa_crc_hd);
62462306a36Sopenharmony_ci	kfree(qp->rx_stream.mpa_crc_hd);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	qp->scq = qp->rcq = NULL;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	siw_qp_put(qp);
62962306a36Sopenharmony_ci	wait_for_completion(&qp->qp_free);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return 0;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/*
63562306a36Sopenharmony_ci * siw_copy_inline_sgl()
63662306a36Sopenharmony_ci *
63762306a36Sopenharmony_ci * Prepare sgl of inlined data for sending. For userland callers
63862306a36Sopenharmony_ci * function checks if given buffer addresses and len's are within
63962306a36Sopenharmony_ci * process context bounds.
64062306a36Sopenharmony_ci * Data from all provided sge's are copied together into the wqe,
64162306a36Sopenharmony_ci * referenced by a single sge.
64262306a36Sopenharmony_ci */
64362306a36Sopenharmony_cistatic int siw_copy_inline_sgl(const struct ib_send_wr *core_wr,
64462306a36Sopenharmony_ci			       struct siw_sqe *sqe)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	struct ib_sge *core_sge = core_wr->sg_list;
64762306a36Sopenharmony_ci	void *kbuf = &sqe->sge[1];
64862306a36Sopenharmony_ci	int num_sge = core_wr->num_sge, bytes = 0;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	sqe->sge[0].laddr = (uintptr_t)kbuf;
65162306a36Sopenharmony_ci	sqe->sge[0].lkey = 0;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	while (num_sge--) {
65462306a36Sopenharmony_ci		if (!core_sge->length) {
65562306a36Sopenharmony_ci			core_sge++;
65662306a36Sopenharmony_ci			continue;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci		bytes += core_sge->length;
65962306a36Sopenharmony_ci		if (bytes > SIW_MAX_INLINE) {
66062306a36Sopenharmony_ci			bytes = -EINVAL;
66162306a36Sopenharmony_ci			break;
66262306a36Sopenharmony_ci		}
66362306a36Sopenharmony_ci		memcpy(kbuf, ib_virt_dma_to_ptr(core_sge->addr),
66462306a36Sopenharmony_ci		       core_sge->length);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		kbuf += core_sge->length;
66762306a36Sopenharmony_ci		core_sge++;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci	sqe->sge[0].length = max(bytes, 0);
67062306a36Sopenharmony_ci	sqe->num_sge = bytes > 0 ? 1 : 0;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	return bytes;
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci/* Complete SQ WR's without processing */
67662306a36Sopenharmony_cistatic int siw_sq_flush_wr(struct siw_qp *qp, const struct ib_send_wr *wr,
67762306a36Sopenharmony_ci			   const struct ib_send_wr **bad_wr)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	int rv = 0;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	while (wr) {
68262306a36Sopenharmony_ci		struct siw_sqe sqe = {};
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		switch (wr->opcode) {
68562306a36Sopenharmony_ci		case IB_WR_RDMA_WRITE:
68662306a36Sopenharmony_ci			sqe.opcode = SIW_OP_WRITE;
68762306a36Sopenharmony_ci			break;
68862306a36Sopenharmony_ci		case IB_WR_RDMA_READ:
68962306a36Sopenharmony_ci			sqe.opcode = SIW_OP_READ;
69062306a36Sopenharmony_ci			break;
69162306a36Sopenharmony_ci		case IB_WR_RDMA_READ_WITH_INV:
69262306a36Sopenharmony_ci			sqe.opcode = SIW_OP_READ_LOCAL_INV;
69362306a36Sopenharmony_ci			break;
69462306a36Sopenharmony_ci		case IB_WR_SEND:
69562306a36Sopenharmony_ci			sqe.opcode = SIW_OP_SEND;
69662306a36Sopenharmony_ci			break;
69762306a36Sopenharmony_ci		case IB_WR_SEND_WITH_IMM:
69862306a36Sopenharmony_ci			sqe.opcode = SIW_OP_SEND_WITH_IMM;
69962306a36Sopenharmony_ci			break;
70062306a36Sopenharmony_ci		case IB_WR_SEND_WITH_INV:
70162306a36Sopenharmony_ci			sqe.opcode = SIW_OP_SEND_REMOTE_INV;
70262306a36Sopenharmony_ci			break;
70362306a36Sopenharmony_ci		case IB_WR_LOCAL_INV:
70462306a36Sopenharmony_ci			sqe.opcode = SIW_OP_INVAL_STAG;
70562306a36Sopenharmony_ci			break;
70662306a36Sopenharmony_ci		case IB_WR_REG_MR:
70762306a36Sopenharmony_ci			sqe.opcode = SIW_OP_REG_MR;
70862306a36Sopenharmony_ci			break;
70962306a36Sopenharmony_ci		default:
71062306a36Sopenharmony_ci			rv = -EINVAL;
71162306a36Sopenharmony_ci			break;
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci		if (!rv) {
71462306a36Sopenharmony_ci			sqe.id = wr->wr_id;
71562306a36Sopenharmony_ci			rv = siw_sqe_complete(qp, &sqe, 0,
71662306a36Sopenharmony_ci					      SIW_WC_WR_FLUSH_ERR);
71762306a36Sopenharmony_ci		}
71862306a36Sopenharmony_ci		if (rv) {
71962306a36Sopenharmony_ci			if (bad_wr)
72062306a36Sopenharmony_ci				*bad_wr = wr;
72162306a36Sopenharmony_ci			break;
72262306a36Sopenharmony_ci		}
72362306a36Sopenharmony_ci		wr = wr->next;
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci	return rv;
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci/* Complete RQ WR's without processing */
72962306a36Sopenharmony_cistatic int siw_rq_flush_wr(struct siw_qp *qp, const struct ib_recv_wr *wr,
73062306a36Sopenharmony_ci			   const struct ib_recv_wr **bad_wr)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct siw_rqe rqe = {};
73362306a36Sopenharmony_ci	int rv = 0;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	while (wr) {
73662306a36Sopenharmony_ci		rqe.id = wr->wr_id;
73762306a36Sopenharmony_ci		rv = siw_rqe_complete(qp, &rqe, 0, 0, SIW_WC_WR_FLUSH_ERR);
73862306a36Sopenharmony_ci		if (rv) {
73962306a36Sopenharmony_ci			if (bad_wr)
74062306a36Sopenharmony_ci				*bad_wr = wr;
74162306a36Sopenharmony_ci			break;
74262306a36Sopenharmony_ci		}
74362306a36Sopenharmony_ci		wr = wr->next;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci	return rv;
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci/*
74962306a36Sopenharmony_ci * siw_post_send()
75062306a36Sopenharmony_ci *
75162306a36Sopenharmony_ci * Post a list of S-WR's to a SQ.
75262306a36Sopenharmony_ci *
75362306a36Sopenharmony_ci * @base_qp:	Base QP contained in siw QP
75462306a36Sopenharmony_ci * @wr:		Null terminated list of user WR's
75562306a36Sopenharmony_ci * @bad_wr:	Points to failing WR in case of synchronous failure.
75662306a36Sopenharmony_ci */
75762306a36Sopenharmony_ciint siw_post_send(struct ib_qp *base_qp, const struct ib_send_wr *wr,
75862306a36Sopenharmony_ci		  const struct ib_send_wr **bad_wr)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	struct siw_qp *qp = to_siw_qp(base_qp);
76162306a36Sopenharmony_ci	struct siw_wqe *wqe = tx_wqe(qp);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	unsigned long flags;
76462306a36Sopenharmony_ci	int rv = 0;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	if (wr && !rdma_is_kernel_res(&qp->base_qp.res)) {
76762306a36Sopenharmony_ci		siw_dbg_qp(qp, "wr must be empty for user mapped sq\n");
76862306a36Sopenharmony_ci		*bad_wr = wr;
76962306a36Sopenharmony_ci		return -EINVAL;
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/*
77362306a36Sopenharmony_ci	 * Try to acquire QP state lock. Must be non-blocking
77462306a36Sopenharmony_ci	 * to accommodate kernel clients needs.
77562306a36Sopenharmony_ci	 */
77662306a36Sopenharmony_ci	if (!down_read_trylock(&qp->state_lock)) {
77762306a36Sopenharmony_ci		if (qp->attrs.state == SIW_QP_STATE_ERROR) {
77862306a36Sopenharmony_ci			/*
77962306a36Sopenharmony_ci			 * ERROR state is final, so we can be sure
78062306a36Sopenharmony_ci			 * this state will not change as long as the QP
78162306a36Sopenharmony_ci			 * exists.
78262306a36Sopenharmony_ci			 *
78362306a36Sopenharmony_ci			 * This handles an ib_drain_sq() call with
78462306a36Sopenharmony_ci			 * a concurrent request to set the QP state
78562306a36Sopenharmony_ci			 * to ERROR.
78662306a36Sopenharmony_ci			 */
78762306a36Sopenharmony_ci			rv = siw_sq_flush_wr(qp, wr, bad_wr);
78862306a36Sopenharmony_ci		} else {
78962306a36Sopenharmony_ci			siw_dbg_qp(qp, "QP locked, state %d\n",
79062306a36Sopenharmony_ci				   qp->attrs.state);
79162306a36Sopenharmony_ci			*bad_wr = wr;
79262306a36Sopenharmony_ci			rv = -ENOTCONN;
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci		return rv;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci	if (unlikely(qp->attrs.state != SIW_QP_STATE_RTS)) {
79762306a36Sopenharmony_ci		if (qp->attrs.state == SIW_QP_STATE_ERROR) {
79862306a36Sopenharmony_ci			/*
79962306a36Sopenharmony_ci			 * Immediately flush this WR to CQ, if QP
80062306a36Sopenharmony_ci			 * is in ERROR state. SQ is guaranteed to
80162306a36Sopenharmony_ci			 * be empty, so WR complets in-order.
80262306a36Sopenharmony_ci			 *
80362306a36Sopenharmony_ci			 * Typically triggered by ib_drain_sq().
80462306a36Sopenharmony_ci			 */
80562306a36Sopenharmony_ci			rv = siw_sq_flush_wr(qp, wr, bad_wr);
80662306a36Sopenharmony_ci		} else {
80762306a36Sopenharmony_ci			siw_dbg_qp(qp, "QP out of state %d\n",
80862306a36Sopenharmony_ci				   qp->attrs.state);
80962306a36Sopenharmony_ci			*bad_wr = wr;
81062306a36Sopenharmony_ci			rv = -ENOTCONN;
81162306a36Sopenharmony_ci		}
81262306a36Sopenharmony_ci		up_read(&qp->state_lock);
81362306a36Sopenharmony_ci		return rv;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci	spin_lock_irqsave(&qp->sq_lock, flags);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	while (wr) {
81862306a36Sopenharmony_ci		u32 idx = qp->sq_put % qp->attrs.sq_size;
81962306a36Sopenharmony_ci		struct siw_sqe *sqe = &qp->sendq[idx];
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci		if (sqe->flags) {
82262306a36Sopenharmony_ci			siw_dbg_qp(qp, "sq full\n");
82362306a36Sopenharmony_ci			rv = -ENOMEM;
82462306a36Sopenharmony_ci			break;
82562306a36Sopenharmony_ci		}
82662306a36Sopenharmony_ci		if (wr->num_sge > qp->attrs.sq_max_sges) {
82762306a36Sopenharmony_ci			siw_dbg_qp(qp, "too many sge's: %d\n", wr->num_sge);
82862306a36Sopenharmony_ci			rv = -EINVAL;
82962306a36Sopenharmony_ci			break;
83062306a36Sopenharmony_ci		}
83162306a36Sopenharmony_ci		sqe->id = wr->wr_id;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		if ((wr->send_flags & IB_SEND_SIGNALED) ||
83462306a36Sopenharmony_ci		    (qp->attrs.flags & SIW_SIGNAL_ALL_WR))
83562306a36Sopenharmony_ci			sqe->flags |= SIW_WQE_SIGNALLED;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		if (wr->send_flags & IB_SEND_FENCE)
83862306a36Sopenharmony_ci			sqe->flags |= SIW_WQE_READ_FENCE;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci		switch (wr->opcode) {
84162306a36Sopenharmony_ci		case IB_WR_SEND:
84262306a36Sopenharmony_ci		case IB_WR_SEND_WITH_INV:
84362306a36Sopenharmony_ci			if (wr->send_flags & IB_SEND_SOLICITED)
84462306a36Sopenharmony_ci				sqe->flags |= SIW_WQE_SOLICITED;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci			if (!(wr->send_flags & IB_SEND_INLINE)) {
84762306a36Sopenharmony_ci				siw_copy_sgl(wr->sg_list, sqe->sge,
84862306a36Sopenharmony_ci					     wr->num_sge);
84962306a36Sopenharmony_ci				sqe->num_sge = wr->num_sge;
85062306a36Sopenharmony_ci			} else {
85162306a36Sopenharmony_ci				rv = siw_copy_inline_sgl(wr, sqe);
85262306a36Sopenharmony_ci				if (rv <= 0) {
85362306a36Sopenharmony_ci					rv = -EINVAL;
85462306a36Sopenharmony_ci					break;
85562306a36Sopenharmony_ci				}
85662306a36Sopenharmony_ci				sqe->flags |= SIW_WQE_INLINE;
85762306a36Sopenharmony_ci				sqe->num_sge = 1;
85862306a36Sopenharmony_ci			}
85962306a36Sopenharmony_ci			if (wr->opcode == IB_WR_SEND)
86062306a36Sopenharmony_ci				sqe->opcode = SIW_OP_SEND;
86162306a36Sopenharmony_ci			else {
86262306a36Sopenharmony_ci				sqe->opcode = SIW_OP_SEND_REMOTE_INV;
86362306a36Sopenharmony_ci				sqe->rkey = wr->ex.invalidate_rkey;
86462306a36Sopenharmony_ci			}
86562306a36Sopenharmony_ci			break;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		case IB_WR_RDMA_READ_WITH_INV:
86862306a36Sopenharmony_ci		case IB_WR_RDMA_READ:
86962306a36Sopenharmony_ci			/*
87062306a36Sopenharmony_ci			 * iWarp restricts RREAD sink to SGL containing
87162306a36Sopenharmony_ci			 * 1 SGE only. we could relax to SGL with multiple
87262306a36Sopenharmony_ci			 * elements referring the SAME ltag or even sending
87362306a36Sopenharmony_ci			 * a private per-rreq tag referring to a checked
87462306a36Sopenharmony_ci			 * local sgl with MULTIPLE ltag's.
87562306a36Sopenharmony_ci			 */
87662306a36Sopenharmony_ci			if (unlikely(wr->num_sge != 1)) {
87762306a36Sopenharmony_ci				rv = -EINVAL;
87862306a36Sopenharmony_ci				break;
87962306a36Sopenharmony_ci			}
88062306a36Sopenharmony_ci			siw_copy_sgl(wr->sg_list, &sqe->sge[0], 1);
88162306a36Sopenharmony_ci			/*
88262306a36Sopenharmony_ci			 * NOTE: zero length RREAD is allowed!
88362306a36Sopenharmony_ci			 */
88462306a36Sopenharmony_ci			sqe->raddr = rdma_wr(wr)->remote_addr;
88562306a36Sopenharmony_ci			sqe->rkey = rdma_wr(wr)->rkey;
88662306a36Sopenharmony_ci			sqe->num_sge = 1;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci			if (wr->opcode == IB_WR_RDMA_READ)
88962306a36Sopenharmony_ci				sqe->opcode = SIW_OP_READ;
89062306a36Sopenharmony_ci			else
89162306a36Sopenharmony_ci				sqe->opcode = SIW_OP_READ_LOCAL_INV;
89262306a36Sopenharmony_ci			break;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci		case IB_WR_RDMA_WRITE:
89562306a36Sopenharmony_ci			if (!(wr->send_flags & IB_SEND_INLINE)) {
89662306a36Sopenharmony_ci				siw_copy_sgl(wr->sg_list, &sqe->sge[0],
89762306a36Sopenharmony_ci					     wr->num_sge);
89862306a36Sopenharmony_ci				sqe->num_sge = wr->num_sge;
89962306a36Sopenharmony_ci			} else {
90062306a36Sopenharmony_ci				rv = siw_copy_inline_sgl(wr, sqe);
90162306a36Sopenharmony_ci				if (unlikely(rv < 0)) {
90262306a36Sopenharmony_ci					rv = -EINVAL;
90362306a36Sopenharmony_ci					break;
90462306a36Sopenharmony_ci				}
90562306a36Sopenharmony_ci				sqe->flags |= SIW_WQE_INLINE;
90662306a36Sopenharmony_ci				sqe->num_sge = 1;
90762306a36Sopenharmony_ci			}
90862306a36Sopenharmony_ci			sqe->raddr = rdma_wr(wr)->remote_addr;
90962306a36Sopenharmony_ci			sqe->rkey = rdma_wr(wr)->rkey;
91062306a36Sopenharmony_ci			sqe->opcode = SIW_OP_WRITE;
91162306a36Sopenharmony_ci			break;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci		case IB_WR_REG_MR:
91462306a36Sopenharmony_ci			sqe->base_mr = (uintptr_t)reg_wr(wr)->mr;
91562306a36Sopenharmony_ci			sqe->rkey = reg_wr(wr)->key;
91662306a36Sopenharmony_ci			sqe->access = reg_wr(wr)->access & IWARP_ACCESS_MASK;
91762306a36Sopenharmony_ci			sqe->opcode = SIW_OP_REG_MR;
91862306a36Sopenharmony_ci			break;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci		case IB_WR_LOCAL_INV:
92162306a36Sopenharmony_ci			sqe->rkey = wr->ex.invalidate_rkey;
92262306a36Sopenharmony_ci			sqe->opcode = SIW_OP_INVAL_STAG;
92362306a36Sopenharmony_ci			break;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci		default:
92662306a36Sopenharmony_ci			siw_dbg_qp(qp, "ib wr type %d unsupported\n",
92762306a36Sopenharmony_ci				   wr->opcode);
92862306a36Sopenharmony_ci			rv = -EINVAL;
92962306a36Sopenharmony_ci			break;
93062306a36Sopenharmony_ci		}
93162306a36Sopenharmony_ci		siw_dbg_qp(qp, "opcode %d, flags 0x%x, wr_id 0x%pK\n",
93262306a36Sopenharmony_ci			   sqe->opcode, sqe->flags,
93362306a36Sopenharmony_ci			   (void *)(uintptr_t)sqe->id);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci		if (unlikely(rv < 0))
93662306a36Sopenharmony_ci			break;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		/* make SQE only valid after completely written */
93962306a36Sopenharmony_ci		smp_wmb();
94062306a36Sopenharmony_ci		sqe->flags |= SIW_WQE_VALID;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci		qp->sq_put++;
94362306a36Sopenharmony_ci		wr = wr->next;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/*
94762306a36Sopenharmony_ci	 * Send directly if SQ processing is not in progress.
94862306a36Sopenharmony_ci	 * Eventual immediate errors (rv < 0) do not affect the involved
94962306a36Sopenharmony_ci	 * RI resources (Verbs, 8.3.1) and thus do not prevent from SQ
95062306a36Sopenharmony_ci	 * processing, if new work is already pending. But rv must be passed
95162306a36Sopenharmony_ci	 * to caller.
95262306a36Sopenharmony_ci	 */
95362306a36Sopenharmony_ci	if (wqe->wr_status != SIW_WR_IDLE) {
95462306a36Sopenharmony_ci		spin_unlock_irqrestore(&qp->sq_lock, flags);
95562306a36Sopenharmony_ci		goto skip_direct_sending;
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci	rv = siw_activate_tx(qp);
95862306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->sq_lock, flags);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	if (rv <= 0)
96162306a36Sopenharmony_ci		goto skip_direct_sending;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if (rdma_is_kernel_res(&qp->base_qp.res)) {
96462306a36Sopenharmony_ci		rv = siw_sq_start(qp);
96562306a36Sopenharmony_ci	} else {
96662306a36Sopenharmony_ci		qp->tx_ctx.in_syscall = 1;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci		if (siw_qp_sq_process(qp) != 0 && !(qp->tx_ctx.tx_suspend))
96962306a36Sopenharmony_ci			siw_qp_cm_drop(qp, 0);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci		qp->tx_ctx.in_syscall = 0;
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ciskip_direct_sending:
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	up_read(&qp->state_lock);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	if (rv >= 0)
97862306a36Sopenharmony_ci		return 0;
97962306a36Sopenharmony_ci	/*
98062306a36Sopenharmony_ci	 * Immediate error
98162306a36Sopenharmony_ci	 */
98262306a36Sopenharmony_ci	siw_dbg_qp(qp, "error %d\n", rv);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	*bad_wr = wr;
98562306a36Sopenharmony_ci	return rv;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci/*
98962306a36Sopenharmony_ci * siw_post_receive()
99062306a36Sopenharmony_ci *
99162306a36Sopenharmony_ci * Post a list of R-WR's to a RQ.
99262306a36Sopenharmony_ci *
99362306a36Sopenharmony_ci * @base_qp:	Base QP contained in siw QP
99462306a36Sopenharmony_ci * @wr:		Null terminated list of user WR's
99562306a36Sopenharmony_ci * @bad_wr:	Points to failing WR in case of synchronous failure.
99662306a36Sopenharmony_ci */
99762306a36Sopenharmony_ciint siw_post_receive(struct ib_qp *base_qp, const struct ib_recv_wr *wr,
99862306a36Sopenharmony_ci		     const struct ib_recv_wr **bad_wr)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct siw_qp *qp = to_siw_qp(base_qp);
100162306a36Sopenharmony_ci	unsigned long flags;
100262306a36Sopenharmony_ci	int rv = 0;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	if (qp->srq || qp->attrs.rq_size == 0) {
100562306a36Sopenharmony_ci		*bad_wr = wr;
100662306a36Sopenharmony_ci		return -EINVAL;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci	if (!rdma_is_kernel_res(&qp->base_qp.res)) {
100962306a36Sopenharmony_ci		siw_dbg_qp(qp, "no kernel post_recv for user mapped rq\n");
101062306a36Sopenharmony_ci		*bad_wr = wr;
101162306a36Sopenharmony_ci		return -EINVAL;
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	/*
101562306a36Sopenharmony_ci	 * Try to acquire QP state lock. Must be non-blocking
101662306a36Sopenharmony_ci	 * to accommodate kernel clients needs.
101762306a36Sopenharmony_ci	 */
101862306a36Sopenharmony_ci	if (!down_read_trylock(&qp->state_lock)) {
101962306a36Sopenharmony_ci		if (qp->attrs.state == SIW_QP_STATE_ERROR) {
102062306a36Sopenharmony_ci			/*
102162306a36Sopenharmony_ci			 * ERROR state is final, so we can be sure
102262306a36Sopenharmony_ci			 * this state will not change as long as the QP
102362306a36Sopenharmony_ci			 * exists.
102462306a36Sopenharmony_ci			 *
102562306a36Sopenharmony_ci			 * This handles an ib_drain_rq() call with
102662306a36Sopenharmony_ci			 * a concurrent request to set the QP state
102762306a36Sopenharmony_ci			 * to ERROR.
102862306a36Sopenharmony_ci			 */
102962306a36Sopenharmony_ci			rv = siw_rq_flush_wr(qp, wr, bad_wr);
103062306a36Sopenharmony_ci		} else {
103162306a36Sopenharmony_ci			siw_dbg_qp(qp, "QP locked, state %d\n",
103262306a36Sopenharmony_ci				   qp->attrs.state);
103362306a36Sopenharmony_ci			*bad_wr = wr;
103462306a36Sopenharmony_ci			rv = -ENOTCONN;
103562306a36Sopenharmony_ci		}
103662306a36Sopenharmony_ci		return rv;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci	if (qp->attrs.state > SIW_QP_STATE_RTS) {
103962306a36Sopenharmony_ci		if (qp->attrs.state == SIW_QP_STATE_ERROR) {
104062306a36Sopenharmony_ci			/*
104162306a36Sopenharmony_ci			 * Immediately flush this WR to CQ, if QP
104262306a36Sopenharmony_ci			 * is in ERROR state. RQ is guaranteed to
104362306a36Sopenharmony_ci			 * be empty, so WR complets in-order.
104462306a36Sopenharmony_ci			 *
104562306a36Sopenharmony_ci			 * Typically triggered by ib_drain_rq().
104662306a36Sopenharmony_ci			 */
104762306a36Sopenharmony_ci			rv = siw_rq_flush_wr(qp, wr, bad_wr);
104862306a36Sopenharmony_ci		} else {
104962306a36Sopenharmony_ci			siw_dbg_qp(qp, "QP out of state %d\n",
105062306a36Sopenharmony_ci				   qp->attrs.state);
105162306a36Sopenharmony_ci			*bad_wr = wr;
105262306a36Sopenharmony_ci			rv = -ENOTCONN;
105362306a36Sopenharmony_ci		}
105462306a36Sopenharmony_ci		up_read(&qp->state_lock);
105562306a36Sopenharmony_ci		return rv;
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci	/*
105862306a36Sopenharmony_ci	 * Serialize potentially multiple producers.
105962306a36Sopenharmony_ci	 * Not needed for single threaded consumer side.
106062306a36Sopenharmony_ci	 */
106162306a36Sopenharmony_ci	spin_lock_irqsave(&qp->rq_lock, flags);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	while (wr) {
106462306a36Sopenharmony_ci		u32 idx = qp->rq_put % qp->attrs.rq_size;
106562306a36Sopenharmony_ci		struct siw_rqe *rqe = &qp->recvq[idx];
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		if (rqe->flags) {
106862306a36Sopenharmony_ci			siw_dbg_qp(qp, "RQ full\n");
106962306a36Sopenharmony_ci			rv = -ENOMEM;
107062306a36Sopenharmony_ci			break;
107162306a36Sopenharmony_ci		}
107262306a36Sopenharmony_ci		if (wr->num_sge > qp->attrs.rq_max_sges) {
107362306a36Sopenharmony_ci			siw_dbg_qp(qp, "too many sge's: %d\n", wr->num_sge);
107462306a36Sopenharmony_ci			rv = -EINVAL;
107562306a36Sopenharmony_ci			break;
107662306a36Sopenharmony_ci		}
107762306a36Sopenharmony_ci		rqe->id = wr->wr_id;
107862306a36Sopenharmony_ci		rqe->num_sge = wr->num_sge;
107962306a36Sopenharmony_ci		siw_copy_sgl(wr->sg_list, rqe->sge, wr->num_sge);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci		/* make sure RQE is completely written before valid */
108262306a36Sopenharmony_ci		smp_wmb();
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci		rqe->flags = SIW_WQE_VALID;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci		qp->rq_put++;
108762306a36Sopenharmony_ci		wr = wr->next;
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->rq_lock, flags);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	up_read(&qp->state_lock);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	if (rv < 0) {
109462306a36Sopenharmony_ci		siw_dbg_qp(qp, "error %d\n", rv);
109562306a36Sopenharmony_ci		*bad_wr = wr;
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci	return rv > 0 ? 0 : rv;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ciint siw_destroy_cq(struct ib_cq *base_cq, struct ib_udata *udata)
110162306a36Sopenharmony_ci{
110262306a36Sopenharmony_ci	struct siw_cq *cq = to_siw_cq(base_cq);
110362306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_cq->device);
110462306a36Sopenharmony_ci	struct siw_ucontext *ctx =
110562306a36Sopenharmony_ci		rdma_udata_to_drv_context(udata, struct siw_ucontext,
110662306a36Sopenharmony_ci					  base_ucontext);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	siw_dbg_cq(cq, "free CQ resources\n");
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	siw_cq_flush(cq);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	if (ctx)
111362306a36Sopenharmony_ci		rdma_user_mmap_entry_remove(cq->cq_entry);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	atomic_dec(&sdev->num_cq);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	vfree(cq->queue);
111862306a36Sopenharmony_ci	return 0;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci/*
112262306a36Sopenharmony_ci * siw_create_cq()
112362306a36Sopenharmony_ci *
112462306a36Sopenharmony_ci * Populate CQ of requested size
112562306a36Sopenharmony_ci *
112662306a36Sopenharmony_ci * @base_cq: CQ as allocated by RDMA midlayer
112762306a36Sopenharmony_ci * @attr: Initial CQ attributes
112862306a36Sopenharmony_ci * @udata: relates to user context
112962306a36Sopenharmony_ci */
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ciint siw_create_cq(struct ib_cq *base_cq, const struct ib_cq_init_attr *attr,
113262306a36Sopenharmony_ci		  struct ib_udata *udata)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_cq->device);
113562306a36Sopenharmony_ci	struct siw_cq *cq = to_siw_cq(base_cq);
113662306a36Sopenharmony_ci	int rv, size = attr->cqe;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	if (attr->flags)
113962306a36Sopenharmony_ci		return -EOPNOTSUPP;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	if (atomic_inc_return(&sdev->num_cq) > SIW_MAX_CQ) {
114262306a36Sopenharmony_ci		siw_dbg(base_cq->device, "too many CQ's\n");
114362306a36Sopenharmony_ci		rv = -ENOMEM;
114462306a36Sopenharmony_ci		goto err_out;
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci	if (size < 1 || size > sdev->attrs.max_cqe) {
114762306a36Sopenharmony_ci		siw_dbg(base_cq->device, "CQ size error: %d\n", size);
114862306a36Sopenharmony_ci		rv = -EINVAL;
114962306a36Sopenharmony_ci		goto err_out;
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci	size = roundup_pow_of_two(size);
115262306a36Sopenharmony_ci	cq->base_cq.cqe = size;
115362306a36Sopenharmony_ci	cq->num_cqe = size;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	if (udata)
115662306a36Sopenharmony_ci		cq->queue = vmalloc_user(size * sizeof(struct siw_cqe) +
115762306a36Sopenharmony_ci					 sizeof(struct siw_cq_ctrl));
115862306a36Sopenharmony_ci	else
115962306a36Sopenharmony_ci		cq->queue = vzalloc(size * sizeof(struct siw_cqe) +
116062306a36Sopenharmony_ci				    sizeof(struct siw_cq_ctrl));
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (cq->queue == NULL) {
116362306a36Sopenharmony_ci		rv = -ENOMEM;
116462306a36Sopenharmony_ci		goto err_out;
116562306a36Sopenharmony_ci	}
116662306a36Sopenharmony_ci	get_random_bytes(&cq->id, 4);
116762306a36Sopenharmony_ci	siw_dbg(base_cq->device, "new CQ [%u]\n", cq->id);
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	spin_lock_init(&cq->lock);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	cq->notify = (struct siw_cq_ctrl *)&cq->queue[size];
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (udata) {
117462306a36Sopenharmony_ci		struct siw_uresp_create_cq uresp = {};
117562306a36Sopenharmony_ci		struct siw_ucontext *ctx =
117662306a36Sopenharmony_ci			rdma_udata_to_drv_context(udata, struct siw_ucontext,
117762306a36Sopenharmony_ci						  base_ucontext);
117862306a36Sopenharmony_ci		size_t length = size * sizeof(struct siw_cqe) +
117962306a36Sopenharmony_ci			sizeof(struct siw_cq_ctrl);
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci		cq->cq_entry =
118262306a36Sopenharmony_ci			siw_mmap_entry_insert(ctx, cq->queue,
118362306a36Sopenharmony_ci					      length, &uresp.cq_key);
118462306a36Sopenharmony_ci		if (!cq->cq_entry) {
118562306a36Sopenharmony_ci			rv = -ENOMEM;
118662306a36Sopenharmony_ci			goto err_out;
118762306a36Sopenharmony_ci		}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci		uresp.cq_id = cq->id;
119062306a36Sopenharmony_ci		uresp.num_cqe = size;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci		if (udata->outlen < sizeof(uresp)) {
119362306a36Sopenharmony_ci			rv = -EINVAL;
119462306a36Sopenharmony_ci			goto err_out;
119562306a36Sopenharmony_ci		}
119662306a36Sopenharmony_ci		rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
119762306a36Sopenharmony_ci		if (rv)
119862306a36Sopenharmony_ci			goto err_out;
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci	return 0;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cierr_out:
120362306a36Sopenharmony_ci	siw_dbg(base_cq->device, "CQ creation failed: %d", rv);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	if (cq->queue) {
120662306a36Sopenharmony_ci		struct siw_ucontext *ctx =
120762306a36Sopenharmony_ci			rdma_udata_to_drv_context(udata, struct siw_ucontext,
120862306a36Sopenharmony_ci						  base_ucontext);
120962306a36Sopenharmony_ci		if (ctx)
121062306a36Sopenharmony_ci			rdma_user_mmap_entry_remove(cq->cq_entry);
121162306a36Sopenharmony_ci		vfree(cq->queue);
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci	atomic_dec(&sdev->num_cq);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	return rv;
121662306a36Sopenharmony_ci}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci/*
121962306a36Sopenharmony_ci * siw_poll_cq()
122062306a36Sopenharmony_ci *
122162306a36Sopenharmony_ci * Reap CQ entries if available and copy work completion status into
122262306a36Sopenharmony_ci * array of WC's provided by caller. Returns number of reaped CQE's.
122362306a36Sopenharmony_ci *
122462306a36Sopenharmony_ci * @base_cq:	Base CQ contained in siw CQ.
122562306a36Sopenharmony_ci * @num_cqe:	Maximum number of CQE's to reap.
122662306a36Sopenharmony_ci * @wc:		Array of work completions to be filled by siw.
122762306a36Sopenharmony_ci */
122862306a36Sopenharmony_ciint siw_poll_cq(struct ib_cq *base_cq, int num_cqe, struct ib_wc *wc)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct siw_cq *cq = to_siw_cq(base_cq);
123162306a36Sopenharmony_ci	int i;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	for (i = 0; i < num_cqe; i++) {
123462306a36Sopenharmony_ci		if (!siw_reap_cqe(cq, wc))
123562306a36Sopenharmony_ci			break;
123662306a36Sopenharmony_ci		wc++;
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci	return i;
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci/*
124262306a36Sopenharmony_ci * siw_req_notify_cq()
124362306a36Sopenharmony_ci *
124462306a36Sopenharmony_ci * Request notification for new CQE's added to that CQ.
124562306a36Sopenharmony_ci * Defined flags:
124662306a36Sopenharmony_ci * o SIW_CQ_NOTIFY_SOLICITED lets siw trigger a notification
124762306a36Sopenharmony_ci *   event if a WQE with notification flag set enters the CQ
124862306a36Sopenharmony_ci * o SIW_CQ_NOTIFY_NEXT_COMP lets siw trigger a notification
124962306a36Sopenharmony_ci *   event if a WQE enters the CQ.
125062306a36Sopenharmony_ci * o IB_CQ_REPORT_MISSED_EVENTS: return value will provide the
125162306a36Sopenharmony_ci *   number of not reaped CQE's regardless of its notification
125262306a36Sopenharmony_ci *   type and current or new CQ notification settings.
125362306a36Sopenharmony_ci *
125462306a36Sopenharmony_ci * @base_cq:	Base CQ contained in siw CQ.
125562306a36Sopenharmony_ci * @flags:	Requested notification flags.
125662306a36Sopenharmony_ci */
125762306a36Sopenharmony_ciint siw_req_notify_cq(struct ib_cq *base_cq, enum ib_cq_notify_flags flags)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct siw_cq *cq = to_siw_cq(base_cq);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	siw_dbg_cq(cq, "flags: 0x%02x\n", flags);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	if ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
126462306a36Sopenharmony_ci		/*
126562306a36Sopenharmony_ci		 * Enable CQ event for next solicited completion.
126662306a36Sopenharmony_ci		 * and make it visible to all associated producers.
126762306a36Sopenharmony_ci		 */
126862306a36Sopenharmony_ci		smp_store_mb(cq->notify->flags, SIW_NOTIFY_SOLICITED);
126962306a36Sopenharmony_ci	else
127062306a36Sopenharmony_ci		/*
127162306a36Sopenharmony_ci		 * Enable CQ event for any signalled completion.
127262306a36Sopenharmony_ci		 * and make it visible to all associated producers.
127362306a36Sopenharmony_ci		 */
127462306a36Sopenharmony_ci		smp_store_mb(cq->notify->flags, SIW_NOTIFY_ALL);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	if (flags & IB_CQ_REPORT_MISSED_EVENTS)
127762306a36Sopenharmony_ci		return cq->cq_put - cq->cq_get;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	return 0;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci/*
128362306a36Sopenharmony_ci * siw_dereg_mr()
128462306a36Sopenharmony_ci *
128562306a36Sopenharmony_ci * Release Memory Region.
128662306a36Sopenharmony_ci *
128762306a36Sopenharmony_ci * @base_mr: Base MR contained in siw MR.
128862306a36Sopenharmony_ci * @udata: points to user context, unused.
128962306a36Sopenharmony_ci */
129062306a36Sopenharmony_ciint siw_dereg_mr(struct ib_mr *base_mr, struct ib_udata *udata)
129162306a36Sopenharmony_ci{
129262306a36Sopenharmony_ci	struct siw_mr *mr = to_siw_mr(base_mr);
129362306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_mr->device);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	siw_dbg_mem(mr->mem, "deregister MR\n");
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	atomic_dec(&sdev->num_mr);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	siw_mr_drop_mem(mr);
130062306a36Sopenharmony_ci	kfree_rcu(mr, rcu);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	return 0;
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci/*
130662306a36Sopenharmony_ci * siw_reg_user_mr()
130762306a36Sopenharmony_ci *
130862306a36Sopenharmony_ci * Register Memory Region.
130962306a36Sopenharmony_ci *
131062306a36Sopenharmony_ci * @pd:		Protection Domain
131162306a36Sopenharmony_ci * @start:	starting address of MR (virtual address)
131262306a36Sopenharmony_ci * @len:	len of MR
131362306a36Sopenharmony_ci * @rnic_va:	not used by siw
131462306a36Sopenharmony_ci * @rights:	MR access rights
131562306a36Sopenharmony_ci * @udata:	user buffer to communicate STag and Key.
131662306a36Sopenharmony_ci */
131762306a36Sopenharmony_cistruct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
131862306a36Sopenharmony_ci			      u64 rnic_va, int rights, struct ib_udata *udata)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	struct siw_mr *mr = NULL;
132162306a36Sopenharmony_ci	struct siw_umem *umem = NULL;
132262306a36Sopenharmony_ci	struct siw_ureq_reg_mr ureq;
132362306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(pd->device);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	unsigned long mem_limit = rlimit(RLIMIT_MEMLOCK);
132662306a36Sopenharmony_ci	int rv;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	siw_dbg_pd(pd, "start: 0x%pK, va: 0x%pK, len: %llu\n",
132962306a36Sopenharmony_ci		   (void *)(uintptr_t)start, (void *)(uintptr_t)rnic_va,
133062306a36Sopenharmony_ci		   (unsigned long long)len);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	if (atomic_inc_return(&sdev->num_mr) > SIW_MAX_MR) {
133362306a36Sopenharmony_ci		siw_dbg_pd(pd, "too many mr's\n");
133462306a36Sopenharmony_ci		rv = -ENOMEM;
133562306a36Sopenharmony_ci		goto err_out;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci	if (!len) {
133862306a36Sopenharmony_ci		rv = -EINVAL;
133962306a36Sopenharmony_ci		goto err_out;
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci	if (mem_limit != RLIM_INFINITY) {
134262306a36Sopenharmony_ci		unsigned long num_pages =
134362306a36Sopenharmony_ci			(PAGE_ALIGN(len + (start & ~PAGE_MASK))) >> PAGE_SHIFT;
134462306a36Sopenharmony_ci		mem_limit >>= PAGE_SHIFT;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci		if (num_pages > mem_limit - current->mm->locked_vm) {
134762306a36Sopenharmony_ci			siw_dbg_pd(pd, "pages req %lu, max %lu, lock %lu\n",
134862306a36Sopenharmony_ci				   num_pages, mem_limit,
134962306a36Sopenharmony_ci				   current->mm->locked_vm);
135062306a36Sopenharmony_ci			rv = -ENOMEM;
135162306a36Sopenharmony_ci			goto err_out;
135262306a36Sopenharmony_ci		}
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci	umem = siw_umem_get(start, len, ib_access_writable(rights));
135562306a36Sopenharmony_ci	if (IS_ERR(umem)) {
135662306a36Sopenharmony_ci		rv = PTR_ERR(umem);
135762306a36Sopenharmony_ci		siw_dbg_pd(pd, "getting user memory failed: %d\n", rv);
135862306a36Sopenharmony_ci		umem = NULL;
135962306a36Sopenharmony_ci		goto err_out;
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
136262306a36Sopenharmony_ci	if (!mr) {
136362306a36Sopenharmony_ci		rv = -ENOMEM;
136462306a36Sopenharmony_ci		goto err_out;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci	rv = siw_mr_add_mem(mr, pd, umem, start, len, rights);
136762306a36Sopenharmony_ci	if (rv)
136862306a36Sopenharmony_ci		goto err_out;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	if (udata) {
137162306a36Sopenharmony_ci		struct siw_uresp_reg_mr uresp = {};
137262306a36Sopenharmony_ci		struct siw_mem *mem = mr->mem;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci		if (udata->inlen < sizeof(ureq)) {
137562306a36Sopenharmony_ci			rv = -EINVAL;
137662306a36Sopenharmony_ci			goto err_out;
137762306a36Sopenharmony_ci		}
137862306a36Sopenharmony_ci		rv = ib_copy_from_udata(&ureq, udata, sizeof(ureq));
137962306a36Sopenharmony_ci		if (rv)
138062306a36Sopenharmony_ci			goto err_out;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci		mr->base_mr.lkey |= ureq.stag_key;
138362306a36Sopenharmony_ci		mr->base_mr.rkey |= ureq.stag_key;
138462306a36Sopenharmony_ci		mem->stag |= ureq.stag_key;
138562306a36Sopenharmony_ci		uresp.stag = mem->stag;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci		if (udata->outlen < sizeof(uresp)) {
138862306a36Sopenharmony_ci			rv = -EINVAL;
138962306a36Sopenharmony_ci			goto err_out;
139062306a36Sopenharmony_ci		}
139162306a36Sopenharmony_ci		rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
139262306a36Sopenharmony_ci		if (rv)
139362306a36Sopenharmony_ci			goto err_out;
139462306a36Sopenharmony_ci	}
139562306a36Sopenharmony_ci	mr->mem->stag_valid = 1;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	return &mr->base_mr;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_cierr_out:
140062306a36Sopenharmony_ci	atomic_dec(&sdev->num_mr);
140162306a36Sopenharmony_ci	if (mr) {
140262306a36Sopenharmony_ci		if (mr->mem)
140362306a36Sopenharmony_ci			siw_mr_drop_mem(mr);
140462306a36Sopenharmony_ci		kfree_rcu(mr, rcu);
140562306a36Sopenharmony_ci	} else {
140662306a36Sopenharmony_ci		if (umem)
140762306a36Sopenharmony_ci			siw_umem_release(umem, false);
140862306a36Sopenharmony_ci	}
140962306a36Sopenharmony_ci	return ERR_PTR(rv);
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_cistruct ib_mr *siw_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
141362306a36Sopenharmony_ci			   u32 max_sge)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(pd->device);
141662306a36Sopenharmony_ci	struct siw_mr *mr = NULL;
141762306a36Sopenharmony_ci	struct siw_pbl *pbl = NULL;
141862306a36Sopenharmony_ci	int rv;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (atomic_inc_return(&sdev->num_mr) > SIW_MAX_MR) {
142162306a36Sopenharmony_ci		siw_dbg_pd(pd, "too many mr's\n");
142262306a36Sopenharmony_ci		rv = -ENOMEM;
142362306a36Sopenharmony_ci		goto err_out;
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci	if (mr_type != IB_MR_TYPE_MEM_REG) {
142662306a36Sopenharmony_ci		siw_dbg_pd(pd, "mr type %d unsupported\n", mr_type);
142762306a36Sopenharmony_ci		rv = -EOPNOTSUPP;
142862306a36Sopenharmony_ci		goto err_out;
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci	if (max_sge > SIW_MAX_SGE_PBL) {
143162306a36Sopenharmony_ci		siw_dbg_pd(pd, "too many sge's: %d\n", max_sge);
143262306a36Sopenharmony_ci		rv = -ENOMEM;
143362306a36Sopenharmony_ci		goto err_out;
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci	pbl = siw_pbl_alloc(max_sge);
143662306a36Sopenharmony_ci	if (IS_ERR(pbl)) {
143762306a36Sopenharmony_ci		rv = PTR_ERR(pbl);
143862306a36Sopenharmony_ci		siw_dbg_pd(pd, "pbl allocation failed: %d\n", rv);
143962306a36Sopenharmony_ci		pbl = NULL;
144062306a36Sopenharmony_ci		goto err_out;
144162306a36Sopenharmony_ci	}
144262306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
144362306a36Sopenharmony_ci	if (!mr) {
144462306a36Sopenharmony_ci		rv = -ENOMEM;
144562306a36Sopenharmony_ci		goto err_out;
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci	rv = siw_mr_add_mem(mr, pd, pbl, 0, max_sge * PAGE_SIZE, 0);
144862306a36Sopenharmony_ci	if (rv)
144962306a36Sopenharmony_ci		goto err_out;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	mr->mem->is_pbl = 1;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	siw_dbg_pd(pd, "[MEM %u]: success\n", mr->mem->stag);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	return &mr->base_mr;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cierr_out:
145862306a36Sopenharmony_ci	atomic_dec(&sdev->num_mr);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	if (!mr) {
146162306a36Sopenharmony_ci		kfree(pbl);
146262306a36Sopenharmony_ci	} else {
146362306a36Sopenharmony_ci		if (mr->mem)
146462306a36Sopenharmony_ci			siw_mr_drop_mem(mr);
146562306a36Sopenharmony_ci		kfree_rcu(mr, rcu);
146662306a36Sopenharmony_ci	}
146762306a36Sopenharmony_ci	siw_dbg_pd(pd, "failed: %d\n", rv);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	return ERR_PTR(rv);
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci/* Just used to count number of pages being mapped */
147362306a36Sopenharmony_cistatic int siw_set_pbl_page(struct ib_mr *base_mr, u64 buf_addr)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	return 0;
147662306a36Sopenharmony_ci}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ciint siw_map_mr_sg(struct ib_mr *base_mr, struct scatterlist *sl, int num_sle,
147962306a36Sopenharmony_ci		  unsigned int *sg_off)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct scatterlist *slp;
148262306a36Sopenharmony_ci	struct siw_mr *mr = to_siw_mr(base_mr);
148362306a36Sopenharmony_ci	struct siw_mem *mem = mr->mem;
148462306a36Sopenharmony_ci	struct siw_pbl *pbl = mem->pbl;
148562306a36Sopenharmony_ci	struct siw_pble *pble;
148662306a36Sopenharmony_ci	unsigned long pbl_size;
148762306a36Sopenharmony_ci	int i, rv;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	if (!pbl) {
149062306a36Sopenharmony_ci		siw_dbg_mem(mem, "no PBL allocated\n");
149162306a36Sopenharmony_ci		return -EINVAL;
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci	pble = pbl->pbe;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	if (pbl->max_buf < num_sle) {
149662306a36Sopenharmony_ci		siw_dbg_mem(mem, "too many SGE's: %d > %d\n",
149762306a36Sopenharmony_ci			    num_sle, pbl->max_buf);
149862306a36Sopenharmony_ci		return -ENOMEM;
149962306a36Sopenharmony_ci	}
150062306a36Sopenharmony_ci	for_each_sg(sl, slp, num_sle, i) {
150162306a36Sopenharmony_ci		if (sg_dma_len(slp) == 0) {
150262306a36Sopenharmony_ci			siw_dbg_mem(mem, "empty SGE\n");
150362306a36Sopenharmony_ci			return -EINVAL;
150462306a36Sopenharmony_ci		}
150562306a36Sopenharmony_ci		if (i == 0) {
150662306a36Sopenharmony_ci			pble->addr = sg_dma_address(slp);
150762306a36Sopenharmony_ci			pble->size = sg_dma_len(slp);
150862306a36Sopenharmony_ci			pble->pbl_off = 0;
150962306a36Sopenharmony_ci			pbl_size = pble->size;
151062306a36Sopenharmony_ci			pbl->num_buf = 1;
151162306a36Sopenharmony_ci		} else {
151262306a36Sopenharmony_ci			/* Merge PBL entries if adjacent */
151362306a36Sopenharmony_ci			if (pble->addr + pble->size == sg_dma_address(slp)) {
151462306a36Sopenharmony_ci				pble->size += sg_dma_len(slp);
151562306a36Sopenharmony_ci			} else {
151662306a36Sopenharmony_ci				pble++;
151762306a36Sopenharmony_ci				pbl->num_buf++;
151862306a36Sopenharmony_ci				pble->addr = sg_dma_address(slp);
151962306a36Sopenharmony_ci				pble->size = sg_dma_len(slp);
152062306a36Sopenharmony_ci				pble->pbl_off = pbl_size;
152162306a36Sopenharmony_ci			}
152262306a36Sopenharmony_ci			pbl_size += sg_dma_len(slp);
152362306a36Sopenharmony_ci		}
152462306a36Sopenharmony_ci		siw_dbg_mem(mem,
152562306a36Sopenharmony_ci			"sge[%d], size %u, addr 0x%p, total %lu\n",
152662306a36Sopenharmony_ci			i, pble->size, ib_virt_dma_to_ptr(pble->addr),
152762306a36Sopenharmony_ci			pbl_size);
152862306a36Sopenharmony_ci	}
152962306a36Sopenharmony_ci	rv = ib_sg_to_pages(base_mr, sl, num_sle, sg_off, siw_set_pbl_page);
153062306a36Sopenharmony_ci	if (rv > 0) {
153162306a36Sopenharmony_ci		mem->len = base_mr->length;
153262306a36Sopenharmony_ci		mem->va = base_mr->iova;
153362306a36Sopenharmony_ci		siw_dbg_mem(mem,
153462306a36Sopenharmony_ci			"%llu bytes, start 0x%pK, %u SLE to %u entries\n",
153562306a36Sopenharmony_ci			mem->len, (void *)(uintptr_t)mem->va, num_sle,
153662306a36Sopenharmony_ci			pbl->num_buf);
153762306a36Sopenharmony_ci	}
153862306a36Sopenharmony_ci	return rv;
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci/*
154262306a36Sopenharmony_ci * siw_get_dma_mr()
154362306a36Sopenharmony_ci *
154462306a36Sopenharmony_ci * Create a (empty) DMA memory region, where no umem is attached.
154562306a36Sopenharmony_ci */
154662306a36Sopenharmony_cistruct ib_mr *siw_get_dma_mr(struct ib_pd *pd, int rights)
154762306a36Sopenharmony_ci{
154862306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(pd->device);
154962306a36Sopenharmony_ci	struct siw_mr *mr = NULL;
155062306a36Sopenharmony_ci	int rv;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	if (atomic_inc_return(&sdev->num_mr) > SIW_MAX_MR) {
155362306a36Sopenharmony_ci		siw_dbg_pd(pd, "too many mr's\n");
155462306a36Sopenharmony_ci		rv = -ENOMEM;
155562306a36Sopenharmony_ci		goto err_out;
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
155862306a36Sopenharmony_ci	if (!mr) {
155962306a36Sopenharmony_ci		rv = -ENOMEM;
156062306a36Sopenharmony_ci		goto err_out;
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci	rv = siw_mr_add_mem(mr, pd, NULL, 0, ULONG_MAX, rights);
156362306a36Sopenharmony_ci	if (rv)
156462306a36Sopenharmony_ci		goto err_out;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	mr->mem->stag_valid = 1;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	siw_dbg_pd(pd, "[MEM %u]: success\n", mr->mem->stag);
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	return &mr->base_mr;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cierr_out:
157362306a36Sopenharmony_ci	if (rv)
157462306a36Sopenharmony_ci		kfree(mr);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	atomic_dec(&sdev->num_mr);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	return ERR_PTR(rv);
157962306a36Sopenharmony_ci}
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci/*
158262306a36Sopenharmony_ci * siw_create_srq()
158362306a36Sopenharmony_ci *
158462306a36Sopenharmony_ci * Create Shared Receive Queue of attributes @init_attrs
158562306a36Sopenharmony_ci * within protection domain given by @pd.
158662306a36Sopenharmony_ci *
158762306a36Sopenharmony_ci * @base_srq:	Base SRQ contained in siw SRQ.
158862306a36Sopenharmony_ci * @init_attrs:	SRQ init attributes.
158962306a36Sopenharmony_ci * @udata:	points to user context
159062306a36Sopenharmony_ci */
159162306a36Sopenharmony_ciint siw_create_srq(struct ib_srq *base_srq,
159262306a36Sopenharmony_ci		   struct ib_srq_init_attr *init_attrs, struct ib_udata *udata)
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci	struct siw_srq *srq = to_siw_srq(base_srq);
159562306a36Sopenharmony_ci	struct ib_srq_attr *attrs = &init_attrs->attr;
159662306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_srq->device);
159762306a36Sopenharmony_ci	struct siw_ucontext *ctx =
159862306a36Sopenharmony_ci		rdma_udata_to_drv_context(udata, struct siw_ucontext,
159962306a36Sopenharmony_ci					  base_ucontext);
160062306a36Sopenharmony_ci	int rv;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	if (init_attrs->srq_type != IB_SRQT_BASIC)
160362306a36Sopenharmony_ci		return -EOPNOTSUPP;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	if (atomic_inc_return(&sdev->num_srq) > SIW_MAX_SRQ) {
160662306a36Sopenharmony_ci		siw_dbg_pd(base_srq->pd, "too many SRQ's\n");
160762306a36Sopenharmony_ci		rv = -ENOMEM;
160862306a36Sopenharmony_ci		goto err_out;
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci	if (attrs->max_wr == 0 || attrs->max_wr > SIW_MAX_SRQ_WR ||
161162306a36Sopenharmony_ci	    attrs->max_sge > SIW_MAX_SGE || attrs->srq_limit > attrs->max_wr) {
161262306a36Sopenharmony_ci		rv = -EINVAL;
161362306a36Sopenharmony_ci		goto err_out;
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci	srq->max_sge = attrs->max_sge;
161662306a36Sopenharmony_ci	srq->num_rqe = roundup_pow_of_two(attrs->max_wr);
161762306a36Sopenharmony_ci	srq->limit = attrs->srq_limit;
161862306a36Sopenharmony_ci	if (srq->limit)
161962306a36Sopenharmony_ci		srq->armed = true;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	srq->is_kernel_res = !udata;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	if (udata)
162462306a36Sopenharmony_ci		srq->recvq =
162562306a36Sopenharmony_ci			vmalloc_user(srq->num_rqe * sizeof(struct siw_rqe));
162662306a36Sopenharmony_ci	else
162762306a36Sopenharmony_ci		srq->recvq = vcalloc(srq->num_rqe, sizeof(struct siw_rqe));
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	if (srq->recvq == NULL) {
163062306a36Sopenharmony_ci		rv = -ENOMEM;
163162306a36Sopenharmony_ci		goto err_out;
163262306a36Sopenharmony_ci	}
163362306a36Sopenharmony_ci	if (udata) {
163462306a36Sopenharmony_ci		struct siw_uresp_create_srq uresp = {};
163562306a36Sopenharmony_ci		size_t length = srq->num_rqe * sizeof(struct siw_rqe);
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci		srq->srq_entry =
163862306a36Sopenharmony_ci			siw_mmap_entry_insert(ctx, srq->recvq,
163962306a36Sopenharmony_ci					      length, &uresp.srq_key);
164062306a36Sopenharmony_ci		if (!srq->srq_entry) {
164162306a36Sopenharmony_ci			rv = -ENOMEM;
164262306a36Sopenharmony_ci			goto err_out;
164362306a36Sopenharmony_ci		}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		uresp.num_rqe = srq->num_rqe;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci		if (udata->outlen < sizeof(uresp)) {
164862306a36Sopenharmony_ci			rv = -EINVAL;
164962306a36Sopenharmony_ci			goto err_out;
165062306a36Sopenharmony_ci		}
165162306a36Sopenharmony_ci		rv = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
165262306a36Sopenharmony_ci		if (rv)
165362306a36Sopenharmony_ci			goto err_out;
165462306a36Sopenharmony_ci	}
165562306a36Sopenharmony_ci	spin_lock_init(&srq->lock);
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	siw_dbg_pd(base_srq->pd, "[SRQ]: success\n");
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return 0;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_cierr_out:
166262306a36Sopenharmony_ci	if (srq->recvq) {
166362306a36Sopenharmony_ci		if (ctx)
166462306a36Sopenharmony_ci			rdma_user_mmap_entry_remove(srq->srq_entry);
166562306a36Sopenharmony_ci		vfree(srq->recvq);
166662306a36Sopenharmony_ci	}
166762306a36Sopenharmony_ci	atomic_dec(&sdev->num_srq);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	return rv;
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci/*
167362306a36Sopenharmony_ci * siw_modify_srq()
167462306a36Sopenharmony_ci *
167562306a36Sopenharmony_ci * Modify SRQ. The caller may resize SRQ and/or set/reset notification
167662306a36Sopenharmony_ci * limit and (re)arm IB_EVENT_SRQ_LIMIT_REACHED notification.
167762306a36Sopenharmony_ci *
167862306a36Sopenharmony_ci * NOTE: it is unclear if RDMA core allows for changing the MAX_SGE
167962306a36Sopenharmony_ci * parameter. siw_modify_srq() does not check the attrs->max_sge param.
168062306a36Sopenharmony_ci */
168162306a36Sopenharmony_ciint siw_modify_srq(struct ib_srq *base_srq, struct ib_srq_attr *attrs,
168262306a36Sopenharmony_ci		   enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
168362306a36Sopenharmony_ci{
168462306a36Sopenharmony_ci	struct siw_srq *srq = to_siw_srq(base_srq);
168562306a36Sopenharmony_ci	unsigned long flags;
168662306a36Sopenharmony_ci	int rv = 0;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	spin_lock_irqsave(&srq->lock, flags);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	if (attr_mask & IB_SRQ_MAX_WR) {
169162306a36Sopenharmony_ci		/* resize request not yet supported */
169262306a36Sopenharmony_ci		rv = -EOPNOTSUPP;
169362306a36Sopenharmony_ci		goto out;
169462306a36Sopenharmony_ci	}
169562306a36Sopenharmony_ci	if (attr_mask & IB_SRQ_LIMIT) {
169662306a36Sopenharmony_ci		if (attrs->srq_limit) {
169762306a36Sopenharmony_ci			if (unlikely(attrs->srq_limit > srq->num_rqe)) {
169862306a36Sopenharmony_ci				rv = -EINVAL;
169962306a36Sopenharmony_ci				goto out;
170062306a36Sopenharmony_ci			}
170162306a36Sopenharmony_ci			srq->armed = true;
170262306a36Sopenharmony_ci		} else {
170362306a36Sopenharmony_ci			srq->armed = false;
170462306a36Sopenharmony_ci		}
170562306a36Sopenharmony_ci		srq->limit = attrs->srq_limit;
170662306a36Sopenharmony_ci	}
170762306a36Sopenharmony_ciout:
170862306a36Sopenharmony_ci	spin_unlock_irqrestore(&srq->lock, flags);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	return rv;
171162306a36Sopenharmony_ci}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci/*
171462306a36Sopenharmony_ci * siw_query_srq()
171562306a36Sopenharmony_ci *
171662306a36Sopenharmony_ci * Query SRQ attributes.
171762306a36Sopenharmony_ci */
171862306a36Sopenharmony_ciint siw_query_srq(struct ib_srq *base_srq, struct ib_srq_attr *attrs)
171962306a36Sopenharmony_ci{
172062306a36Sopenharmony_ci	struct siw_srq *srq = to_siw_srq(base_srq);
172162306a36Sopenharmony_ci	unsigned long flags;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	spin_lock_irqsave(&srq->lock, flags);
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	attrs->max_wr = srq->num_rqe;
172662306a36Sopenharmony_ci	attrs->max_sge = srq->max_sge;
172762306a36Sopenharmony_ci	attrs->srq_limit = srq->limit;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	spin_unlock_irqrestore(&srq->lock, flags);
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	return 0;
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci/*
173562306a36Sopenharmony_ci * siw_destroy_srq()
173662306a36Sopenharmony_ci *
173762306a36Sopenharmony_ci * Destroy SRQ.
173862306a36Sopenharmony_ci * It is assumed that the SRQ is not referenced by any
173962306a36Sopenharmony_ci * QP anymore - the code trusts the RDMA core environment to keep track
174062306a36Sopenharmony_ci * of QP references.
174162306a36Sopenharmony_ci */
174262306a36Sopenharmony_ciint siw_destroy_srq(struct ib_srq *base_srq, struct ib_udata *udata)
174362306a36Sopenharmony_ci{
174462306a36Sopenharmony_ci	struct siw_srq *srq = to_siw_srq(base_srq);
174562306a36Sopenharmony_ci	struct siw_device *sdev = to_siw_dev(base_srq->device);
174662306a36Sopenharmony_ci	struct siw_ucontext *ctx =
174762306a36Sopenharmony_ci		rdma_udata_to_drv_context(udata, struct siw_ucontext,
174862306a36Sopenharmony_ci					  base_ucontext);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	if (ctx)
175162306a36Sopenharmony_ci		rdma_user_mmap_entry_remove(srq->srq_entry);
175262306a36Sopenharmony_ci	vfree(srq->recvq);
175362306a36Sopenharmony_ci	atomic_dec(&sdev->num_srq);
175462306a36Sopenharmony_ci	return 0;
175562306a36Sopenharmony_ci}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci/*
175862306a36Sopenharmony_ci * siw_post_srq_recv()
175962306a36Sopenharmony_ci *
176062306a36Sopenharmony_ci * Post a list of receive queue elements to SRQ.
176162306a36Sopenharmony_ci * NOTE: The function does not check or lock a certain SRQ state
176262306a36Sopenharmony_ci *       during the post operation. The code simply trusts the
176362306a36Sopenharmony_ci *       RDMA core environment.
176462306a36Sopenharmony_ci *
176562306a36Sopenharmony_ci * @base_srq:	Base SRQ contained in siw SRQ
176662306a36Sopenharmony_ci * @wr:		List of R-WR's
176762306a36Sopenharmony_ci * @bad_wr:	Updated to failing WR if posting fails.
176862306a36Sopenharmony_ci */
176962306a36Sopenharmony_ciint siw_post_srq_recv(struct ib_srq *base_srq, const struct ib_recv_wr *wr,
177062306a36Sopenharmony_ci		      const struct ib_recv_wr **bad_wr)
177162306a36Sopenharmony_ci{
177262306a36Sopenharmony_ci	struct siw_srq *srq = to_siw_srq(base_srq);
177362306a36Sopenharmony_ci	unsigned long flags;
177462306a36Sopenharmony_ci	int rv = 0;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	if (unlikely(!srq->is_kernel_res)) {
177762306a36Sopenharmony_ci		siw_dbg_pd(base_srq->pd,
177862306a36Sopenharmony_ci			   "[SRQ]: no kernel post_recv for mapped srq\n");
177962306a36Sopenharmony_ci		rv = -EINVAL;
178062306a36Sopenharmony_ci		goto out;
178162306a36Sopenharmony_ci	}
178262306a36Sopenharmony_ci	/*
178362306a36Sopenharmony_ci	 * Serialize potentially multiple producers.
178462306a36Sopenharmony_ci	 * Also needed to serialize potentially multiple
178562306a36Sopenharmony_ci	 * consumers.
178662306a36Sopenharmony_ci	 */
178762306a36Sopenharmony_ci	spin_lock_irqsave(&srq->lock, flags);
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	while (wr) {
179062306a36Sopenharmony_ci		u32 idx = srq->rq_put % srq->num_rqe;
179162306a36Sopenharmony_ci		struct siw_rqe *rqe = &srq->recvq[idx];
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci		if (rqe->flags) {
179462306a36Sopenharmony_ci			siw_dbg_pd(base_srq->pd, "SRQ full\n");
179562306a36Sopenharmony_ci			rv = -ENOMEM;
179662306a36Sopenharmony_ci			break;
179762306a36Sopenharmony_ci		}
179862306a36Sopenharmony_ci		if (unlikely(wr->num_sge > srq->max_sge)) {
179962306a36Sopenharmony_ci			siw_dbg_pd(base_srq->pd,
180062306a36Sopenharmony_ci				   "[SRQ]: too many sge's: %d\n", wr->num_sge);
180162306a36Sopenharmony_ci			rv = -EINVAL;
180262306a36Sopenharmony_ci			break;
180362306a36Sopenharmony_ci		}
180462306a36Sopenharmony_ci		rqe->id = wr->wr_id;
180562306a36Sopenharmony_ci		rqe->num_sge = wr->num_sge;
180662306a36Sopenharmony_ci		siw_copy_sgl(wr->sg_list, rqe->sge, wr->num_sge);
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci		/* Make sure S-RQE is completely written before valid */
180962306a36Sopenharmony_ci		smp_wmb();
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci		rqe->flags = SIW_WQE_VALID;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci		srq->rq_put++;
181462306a36Sopenharmony_ci		wr = wr->next;
181562306a36Sopenharmony_ci	}
181662306a36Sopenharmony_ci	spin_unlock_irqrestore(&srq->lock, flags);
181762306a36Sopenharmony_ciout:
181862306a36Sopenharmony_ci	if (unlikely(rv < 0)) {
181962306a36Sopenharmony_ci		siw_dbg_pd(base_srq->pd, "[SRQ]: error %d\n", rv);
182062306a36Sopenharmony_ci		*bad_wr = wr;
182162306a36Sopenharmony_ci	}
182262306a36Sopenharmony_ci	return rv;
182362306a36Sopenharmony_ci}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_civoid siw_qp_event(struct siw_qp *qp, enum ib_event_type etype)
182662306a36Sopenharmony_ci{
182762306a36Sopenharmony_ci	struct ib_event event;
182862306a36Sopenharmony_ci	struct ib_qp *base_qp = &qp->base_qp;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	/*
183162306a36Sopenharmony_ci	 * Do not report asynchronous errors on QP which gets
183262306a36Sopenharmony_ci	 * destroyed via verbs interface (siw_destroy_qp())
183362306a36Sopenharmony_ci	 */
183462306a36Sopenharmony_ci	if (qp->attrs.flags & SIW_QP_IN_DESTROY)
183562306a36Sopenharmony_ci		return;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	event.event = etype;
183862306a36Sopenharmony_ci	event.device = base_qp->device;
183962306a36Sopenharmony_ci	event.element.qp = base_qp;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	if (base_qp->event_handler) {
184262306a36Sopenharmony_ci		siw_dbg_qp(qp, "reporting event %d\n", etype);
184362306a36Sopenharmony_ci		base_qp->event_handler(&event, base_qp->qp_context);
184462306a36Sopenharmony_ci	}
184562306a36Sopenharmony_ci}
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_civoid siw_cq_event(struct siw_cq *cq, enum ib_event_type etype)
184862306a36Sopenharmony_ci{
184962306a36Sopenharmony_ci	struct ib_event event;
185062306a36Sopenharmony_ci	struct ib_cq *base_cq = &cq->base_cq;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	event.event = etype;
185362306a36Sopenharmony_ci	event.device = base_cq->device;
185462306a36Sopenharmony_ci	event.element.cq = base_cq;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	if (base_cq->event_handler) {
185762306a36Sopenharmony_ci		siw_dbg_cq(cq, "reporting CQ event %d\n", etype);
185862306a36Sopenharmony_ci		base_cq->event_handler(&event, base_cq->cq_context);
185962306a36Sopenharmony_ci	}
186062306a36Sopenharmony_ci}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_civoid siw_srq_event(struct siw_srq *srq, enum ib_event_type etype)
186362306a36Sopenharmony_ci{
186462306a36Sopenharmony_ci	struct ib_event event;
186562306a36Sopenharmony_ci	struct ib_srq *base_srq = &srq->base_srq;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	event.event = etype;
186862306a36Sopenharmony_ci	event.device = base_srq->device;
186962306a36Sopenharmony_ci	event.element.srq = base_srq;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	if (base_srq->event_handler) {
187262306a36Sopenharmony_ci		siw_dbg_pd(srq->base_srq.pd,
187362306a36Sopenharmony_ci			   "reporting SRQ event %d\n", etype);
187462306a36Sopenharmony_ci		base_srq->event_handler(&event, base_srq->srq_context);
187562306a36Sopenharmony_ci	}
187662306a36Sopenharmony_ci}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_civoid siw_port_event(struct siw_device *sdev, u32 port, enum ib_event_type etype)
187962306a36Sopenharmony_ci{
188062306a36Sopenharmony_ci	struct ib_event event;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	event.event = etype;
188362306a36Sopenharmony_ci	event.device = &sdev->base_dev;
188462306a36Sopenharmony_ci	event.element.port_num = port;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	siw_dbg(&sdev->base_dev, "reporting port event %d\n", etype);
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	ib_dispatch_event(&event);
188962306a36Sopenharmony_ci}
1890