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