162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 862306a36Sopenharmony_ci#include <net/addrconf.h> 962306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "rxe.h" 1262306a36Sopenharmony_ci#include "rxe_queue.h" 1362306a36Sopenharmony_ci#include "rxe_hw_counters.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* dev */ 1862306a36Sopenharmony_cistatic int rxe_query_device(struct ib_device *ibdev, 1962306a36Sopenharmony_ci struct ib_device_attr *attr, 2062306a36Sopenharmony_ci struct ib_udata *udata) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibdev); 2362306a36Sopenharmony_ci int err; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci if (udata->inlen || udata->outlen) { 2662306a36Sopenharmony_ci rxe_dbg_dev(rxe, "malformed udata"); 2762306a36Sopenharmony_ci err = -EINVAL; 2862306a36Sopenharmony_ci goto err_out; 2962306a36Sopenharmony_ci } 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci memcpy(attr, &rxe->attr, sizeof(*attr)); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci return 0; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cierr_out: 3662306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 3762306a36Sopenharmony_ci return err; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int rxe_query_port(struct ib_device *ibdev, 4162306a36Sopenharmony_ci u32 port_num, struct ib_port_attr *attr) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibdev); 4462306a36Sopenharmony_ci int err, ret; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (port_num != 1) { 4762306a36Sopenharmony_ci err = -EINVAL; 4862306a36Sopenharmony_ci rxe_dbg_dev(rxe, "bad port_num = %d", port_num); 4962306a36Sopenharmony_ci goto err_out; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci memcpy(attr, &rxe->port.attr, sizeof(*attr)); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci mutex_lock(&rxe->usdev_lock); 5562306a36Sopenharmony_ci ret = ib_get_eth_speed(ibdev, port_num, &attr->active_speed, 5662306a36Sopenharmony_ci &attr->active_width); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (attr->state == IB_PORT_ACTIVE) 5962306a36Sopenharmony_ci attr->phys_state = IB_PORT_PHYS_STATE_LINK_UP; 6062306a36Sopenharmony_ci else if (dev_get_flags(rxe->ndev) & IFF_UP) 6162306a36Sopenharmony_ci attr->phys_state = IB_PORT_PHYS_STATE_POLLING; 6262306a36Sopenharmony_ci else 6362306a36Sopenharmony_ci attr->phys_state = IB_PORT_PHYS_STATE_DISABLED; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci mutex_unlock(&rxe->usdev_lock); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return ret; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cierr_out: 7062306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 7162306a36Sopenharmony_ci return err; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int rxe_query_pkey(struct ib_device *ibdev, 7562306a36Sopenharmony_ci u32 port_num, u16 index, u16 *pkey) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibdev); 7862306a36Sopenharmony_ci int err; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (index != 0) { 8162306a36Sopenharmony_ci err = -EINVAL; 8262306a36Sopenharmony_ci rxe_dbg_dev(rxe, "bad pkey index = %d", index); 8362306a36Sopenharmony_ci goto err_out; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci *pkey = IB_DEFAULT_PKEY_FULL; 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cierr_out: 9062306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 9162306a36Sopenharmony_ci return err; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int rxe_modify_device(struct ib_device *ibdev, 9562306a36Sopenharmony_ci int mask, struct ib_device_modify *attr) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibdev); 9862306a36Sopenharmony_ci int err; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID | 10162306a36Sopenharmony_ci IB_DEVICE_MODIFY_NODE_DESC)) { 10262306a36Sopenharmony_ci err = -EOPNOTSUPP; 10362306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unsupported mask = 0x%x", mask); 10462306a36Sopenharmony_ci goto err_out; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID) 10862306a36Sopenharmony_ci rxe->attr.sys_image_guid = cpu_to_be64(attr->sys_image_guid); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (mask & IB_DEVICE_MODIFY_NODE_DESC) { 11162306a36Sopenharmony_ci memcpy(rxe->ib_dev.node_desc, 11262306a36Sopenharmony_ci attr->node_desc, sizeof(rxe->ib_dev.node_desc)); 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cierr_out: 11862306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 11962306a36Sopenharmony_ci return err; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int rxe_modify_port(struct ib_device *ibdev, u32 port_num, 12362306a36Sopenharmony_ci int mask, struct ib_port_modify *attr) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibdev); 12662306a36Sopenharmony_ci struct rxe_port *port; 12762306a36Sopenharmony_ci int err; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (port_num != 1) { 13062306a36Sopenharmony_ci err = -EINVAL; 13162306a36Sopenharmony_ci rxe_dbg_dev(rxe, "bad port_num = %d", port_num); 13262306a36Sopenharmony_ci goto err_out; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci //TODO is shutdown useful 13662306a36Sopenharmony_ci if (mask & ~(IB_PORT_RESET_QKEY_CNTR)) { 13762306a36Sopenharmony_ci err = -EOPNOTSUPP; 13862306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unsupported mask = 0x%x", mask); 13962306a36Sopenharmony_ci goto err_out; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci port = &rxe->port; 14362306a36Sopenharmony_ci port->attr.port_cap_flags |= attr->set_port_cap_mask; 14462306a36Sopenharmony_ci port->attr.port_cap_flags &= ~attr->clr_port_cap_mask; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (mask & IB_PORT_RESET_QKEY_CNTR) 14762306a36Sopenharmony_ci port->attr.qkey_viol_cntr = 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cierr_out: 15262306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 15362306a36Sopenharmony_ci return err; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic enum rdma_link_layer rxe_get_link_layer(struct ib_device *ibdev, 15762306a36Sopenharmony_ci u32 port_num) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibdev); 16062306a36Sopenharmony_ci int err; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (port_num != 1) { 16362306a36Sopenharmony_ci err = -EINVAL; 16462306a36Sopenharmony_ci rxe_dbg_dev(rxe, "bad port_num = %d", port_num); 16562306a36Sopenharmony_ci goto err_out; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return IB_LINK_LAYER_ETHERNET; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cierr_out: 17162306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 17262306a36Sopenharmony_ci return err; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int rxe_port_immutable(struct ib_device *ibdev, u32 port_num, 17662306a36Sopenharmony_ci struct ib_port_immutable *immutable) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibdev); 17962306a36Sopenharmony_ci struct ib_port_attr attr = {}; 18062306a36Sopenharmony_ci int err; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (port_num != 1) { 18362306a36Sopenharmony_ci err = -EINVAL; 18462306a36Sopenharmony_ci rxe_dbg_dev(rxe, "bad port_num = %d", port_num); 18562306a36Sopenharmony_ci goto err_out; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci err = ib_query_port(ibdev, port_num, &attr); 18962306a36Sopenharmony_ci if (err) 19062306a36Sopenharmony_ci goto err_out; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; 19362306a36Sopenharmony_ci immutable->pkey_tbl_len = attr.pkey_tbl_len; 19462306a36Sopenharmony_ci immutable->gid_tbl_len = attr.gid_tbl_len; 19562306a36Sopenharmony_ci immutable->max_mad_size = IB_MGMT_MAD_SIZE; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cierr_out: 20062306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 20162306a36Sopenharmony_ci return err; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* uc */ 20562306a36Sopenharmony_cistatic int rxe_alloc_ucontext(struct ib_ucontext *ibuc, struct ib_udata *udata) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibuc->device); 20862306a36Sopenharmony_ci struct rxe_ucontext *uc = to_ruc(ibuc); 20962306a36Sopenharmony_ci int err; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci err = rxe_add_to_pool(&rxe->uc_pool, uc); 21262306a36Sopenharmony_ci if (err) 21362306a36Sopenharmony_ci rxe_err_dev(rxe, "unable to create uc"); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return err; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void rxe_dealloc_ucontext(struct ib_ucontext *ibuc) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct rxe_ucontext *uc = to_ruc(ibuc); 22162306a36Sopenharmony_ci int err; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci err = rxe_cleanup(uc); 22462306a36Sopenharmony_ci if (err) 22562306a36Sopenharmony_ci rxe_err_uc(uc, "cleanup failed, err = %d", err); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/* pd */ 22962306a36Sopenharmony_cistatic int rxe_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibpd->device); 23262306a36Sopenharmony_ci struct rxe_pd *pd = to_rpd(ibpd); 23362306a36Sopenharmony_ci int err; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci err = rxe_add_to_pool(&rxe->pd_pool, pd); 23662306a36Sopenharmony_ci if (err) { 23762306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unable to alloc pd"); 23862306a36Sopenharmony_ci goto err_out; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return 0; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cierr_out: 24462306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 24562306a36Sopenharmony_ci return err; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int rxe_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct rxe_pd *pd = to_rpd(ibpd); 25162306a36Sopenharmony_ci int err; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci err = rxe_cleanup(pd); 25462306a36Sopenharmony_ci if (err) 25562306a36Sopenharmony_ci rxe_err_pd(pd, "cleanup failed, err = %d", err); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return 0; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/* ah */ 26162306a36Sopenharmony_cistatic int rxe_create_ah(struct ib_ah *ibah, 26262306a36Sopenharmony_ci struct rdma_ah_init_attr *init_attr, 26362306a36Sopenharmony_ci struct ib_udata *udata) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibah->device); 26662306a36Sopenharmony_ci struct rxe_ah *ah = to_rah(ibah); 26762306a36Sopenharmony_ci struct rxe_create_ah_resp __user *uresp = NULL; 26862306a36Sopenharmony_ci int err, cleanup_err; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (udata) { 27162306a36Sopenharmony_ci /* test if new user provider */ 27262306a36Sopenharmony_ci if (udata->outlen >= sizeof(*uresp)) 27362306a36Sopenharmony_ci uresp = udata->outbuf; 27462306a36Sopenharmony_ci ah->is_user = true; 27562306a36Sopenharmony_ci } else { 27662306a36Sopenharmony_ci ah->is_user = false; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci err = rxe_add_to_pool_ah(&rxe->ah_pool, ah, 28062306a36Sopenharmony_ci init_attr->flags & RDMA_CREATE_AH_SLEEPABLE); 28162306a36Sopenharmony_ci if (err) { 28262306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unable to create ah"); 28362306a36Sopenharmony_ci goto err_out; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* create index > 0 */ 28762306a36Sopenharmony_ci ah->ah_num = ah->elem.index; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci err = rxe_ah_chk_attr(ah, init_attr->ah_attr); 29062306a36Sopenharmony_ci if (err) { 29162306a36Sopenharmony_ci rxe_dbg_ah(ah, "bad attr"); 29262306a36Sopenharmony_ci goto err_cleanup; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (uresp) { 29662306a36Sopenharmony_ci /* only if new user provider */ 29762306a36Sopenharmony_ci err = copy_to_user(&uresp->ah_num, &ah->ah_num, 29862306a36Sopenharmony_ci sizeof(uresp->ah_num)); 29962306a36Sopenharmony_ci if (err) { 30062306a36Sopenharmony_ci err = -EFAULT; 30162306a36Sopenharmony_ci rxe_dbg_ah(ah, "unable to copy to user"); 30262306a36Sopenharmony_ci goto err_cleanup; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci } else if (ah->is_user) { 30562306a36Sopenharmony_ci /* only if old user provider */ 30662306a36Sopenharmony_ci ah->ah_num = 0; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci rxe_init_av(init_attr->ah_attr, &ah->av); 31062306a36Sopenharmony_ci rxe_finalize(ah); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cierr_cleanup: 31562306a36Sopenharmony_ci cleanup_err = rxe_cleanup(ah); 31662306a36Sopenharmony_ci if (cleanup_err) 31762306a36Sopenharmony_ci rxe_err_ah(ah, "cleanup failed, err = %d", cleanup_err); 31862306a36Sopenharmony_cierr_out: 31962306a36Sopenharmony_ci rxe_err_ah(ah, "returned err = %d", err); 32062306a36Sopenharmony_ci return err; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int rxe_modify_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct rxe_ah *ah = to_rah(ibah); 32662306a36Sopenharmony_ci int err; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci err = rxe_ah_chk_attr(ah, attr); 32962306a36Sopenharmony_ci if (err) { 33062306a36Sopenharmony_ci rxe_dbg_ah(ah, "bad attr"); 33162306a36Sopenharmony_ci goto err_out; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci rxe_init_av(attr, &ah->av); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return 0; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cierr_out: 33962306a36Sopenharmony_ci rxe_err_ah(ah, "returned err = %d", err); 34062306a36Sopenharmony_ci return err; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int rxe_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct rxe_ah *ah = to_rah(ibah); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci memset(attr, 0, sizeof(*attr)); 34862306a36Sopenharmony_ci attr->type = ibah->type; 34962306a36Sopenharmony_ci rxe_av_to_attr(&ah->av, attr); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int rxe_destroy_ah(struct ib_ah *ibah, u32 flags) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct rxe_ah *ah = to_rah(ibah); 35762306a36Sopenharmony_ci int err; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci err = rxe_cleanup_ah(ah, flags & RDMA_DESTROY_AH_SLEEPABLE); 36062306a36Sopenharmony_ci if (err) 36162306a36Sopenharmony_ci rxe_err_ah(ah, "cleanup failed, err = %d", err); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return 0; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/* srq */ 36762306a36Sopenharmony_cistatic int rxe_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init, 36862306a36Sopenharmony_ci struct ib_udata *udata) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibsrq->device); 37162306a36Sopenharmony_ci struct rxe_pd *pd = to_rpd(ibsrq->pd); 37262306a36Sopenharmony_ci struct rxe_srq *srq = to_rsrq(ibsrq); 37362306a36Sopenharmony_ci struct rxe_create_srq_resp __user *uresp = NULL; 37462306a36Sopenharmony_ci int err, cleanup_err; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (udata) { 37762306a36Sopenharmony_ci if (udata->outlen < sizeof(*uresp)) { 37862306a36Sopenharmony_ci err = -EINVAL; 37962306a36Sopenharmony_ci rxe_err_dev(rxe, "malformed udata"); 38062306a36Sopenharmony_ci goto err_out; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci uresp = udata->outbuf; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (init->srq_type != IB_SRQT_BASIC) { 38662306a36Sopenharmony_ci err = -EOPNOTSUPP; 38762306a36Sopenharmony_ci rxe_dbg_dev(rxe, "srq type = %d, not supported", 38862306a36Sopenharmony_ci init->srq_type); 38962306a36Sopenharmony_ci goto err_out; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci err = rxe_srq_chk_init(rxe, init); 39362306a36Sopenharmony_ci if (err) { 39462306a36Sopenharmony_ci rxe_dbg_dev(rxe, "invalid init attributes"); 39562306a36Sopenharmony_ci goto err_out; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci err = rxe_add_to_pool(&rxe->srq_pool, srq); 39962306a36Sopenharmony_ci if (err) { 40062306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unable to create srq, err = %d", err); 40162306a36Sopenharmony_ci goto err_out; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci rxe_get(pd); 40562306a36Sopenharmony_ci srq->pd = pd; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci err = rxe_srq_from_init(rxe, srq, init, udata, uresp); 40862306a36Sopenharmony_ci if (err) { 40962306a36Sopenharmony_ci rxe_dbg_srq(srq, "create srq failed, err = %d", err); 41062306a36Sopenharmony_ci goto err_cleanup; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cierr_cleanup: 41662306a36Sopenharmony_ci cleanup_err = rxe_cleanup(srq); 41762306a36Sopenharmony_ci if (cleanup_err) 41862306a36Sopenharmony_ci rxe_err_srq(srq, "cleanup failed, err = %d", cleanup_err); 41962306a36Sopenharmony_cierr_out: 42062306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 42162306a36Sopenharmony_ci return err; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int rxe_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, 42562306a36Sopenharmony_ci enum ib_srq_attr_mask mask, 42662306a36Sopenharmony_ci struct ib_udata *udata) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct rxe_srq *srq = to_rsrq(ibsrq); 42962306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibsrq->device); 43062306a36Sopenharmony_ci struct rxe_modify_srq_cmd cmd = {}; 43162306a36Sopenharmony_ci int err; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (udata) { 43462306a36Sopenharmony_ci if (udata->inlen < sizeof(cmd)) { 43562306a36Sopenharmony_ci err = -EINVAL; 43662306a36Sopenharmony_ci rxe_dbg_srq(srq, "malformed udata"); 43762306a36Sopenharmony_ci goto err_out; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci err = ib_copy_from_udata(&cmd, udata, sizeof(cmd)); 44162306a36Sopenharmony_ci if (err) { 44262306a36Sopenharmony_ci err = -EFAULT; 44362306a36Sopenharmony_ci rxe_dbg_srq(srq, "unable to read udata"); 44462306a36Sopenharmony_ci goto err_out; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci err = rxe_srq_chk_attr(rxe, srq, attr, mask); 44962306a36Sopenharmony_ci if (err) { 45062306a36Sopenharmony_ci rxe_dbg_srq(srq, "bad init attributes"); 45162306a36Sopenharmony_ci goto err_out; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci err = rxe_srq_from_attr(rxe, srq, attr, mask, &cmd, udata); 45562306a36Sopenharmony_ci if (err) { 45662306a36Sopenharmony_ci rxe_dbg_srq(srq, "bad attr"); 45762306a36Sopenharmony_ci goto err_out; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cierr_out: 46362306a36Sopenharmony_ci rxe_err_srq(srq, "returned err = %d", err); 46462306a36Sopenharmony_ci return err; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int rxe_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct rxe_srq *srq = to_rsrq(ibsrq); 47062306a36Sopenharmony_ci int err; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (srq->error) { 47362306a36Sopenharmony_ci err = -EINVAL; 47462306a36Sopenharmony_ci rxe_dbg_srq(srq, "srq in error state"); 47562306a36Sopenharmony_ci goto err_out; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci attr->max_wr = srq->rq.queue->buf->index_mask; 47962306a36Sopenharmony_ci attr->max_sge = srq->rq.max_sge; 48062306a36Sopenharmony_ci attr->srq_limit = srq->limit; 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cierr_out: 48462306a36Sopenharmony_ci rxe_err_srq(srq, "returned err = %d", err); 48562306a36Sopenharmony_ci return err; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int rxe_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, 48962306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci int err = 0; 49262306a36Sopenharmony_ci struct rxe_srq *srq = to_rsrq(ibsrq); 49362306a36Sopenharmony_ci unsigned long flags; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci spin_lock_irqsave(&srq->rq.producer_lock, flags); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci while (wr) { 49862306a36Sopenharmony_ci err = post_one_recv(&srq->rq, wr); 49962306a36Sopenharmony_ci if (unlikely(err)) 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci wr = wr->next; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->rq.producer_lock, flags); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (err) { 50762306a36Sopenharmony_ci *bad_wr = wr; 50862306a36Sopenharmony_ci rxe_err_srq(srq, "returned err = %d", err); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci return err; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic int rxe_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct rxe_srq *srq = to_rsrq(ibsrq); 51762306a36Sopenharmony_ci int err; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci err = rxe_cleanup(srq); 52062306a36Sopenharmony_ci if (err) 52162306a36Sopenharmony_ci rxe_err_srq(srq, "cleanup failed, err = %d", err); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci/* qp */ 52762306a36Sopenharmony_cistatic int rxe_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init, 52862306a36Sopenharmony_ci struct ib_udata *udata) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibqp->device); 53162306a36Sopenharmony_ci struct rxe_pd *pd = to_rpd(ibqp->pd); 53262306a36Sopenharmony_ci struct rxe_qp *qp = to_rqp(ibqp); 53362306a36Sopenharmony_ci struct rxe_create_qp_resp __user *uresp = NULL; 53462306a36Sopenharmony_ci int err, cleanup_err; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (udata) { 53762306a36Sopenharmony_ci if (udata->inlen) { 53862306a36Sopenharmony_ci err = -EINVAL; 53962306a36Sopenharmony_ci rxe_dbg_dev(rxe, "malformed udata, err = %d", err); 54062306a36Sopenharmony_ci goto err_out; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (udata->outlen < sizeof(*uresp)) { 54462306a36Sopenharmony_ci err = -EINVAL; 54562306a36Sopenharmony_ci rxe_dbg_dev(rxe, "malformed udata, err = %d", err); 54662306a36Sopenharmony_ci goto err_out; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci qp->is_user = true; 55062306a36Sopenharmony_ci uresp = udata->outbuf; 55162306a36Sopenharmony_ci } else { 55262306a36Sopenharmony_ci qp->is_user = false; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (init->create_flags) { 55662306a36Sopenharmony_ci err = -EOPNOTSUPP; 55762306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unsupported create_flags, err = %d", err); 55862306a36Sopenharmony_ci goto err_out; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci err = rxe_qp_chk_init(rxe, init); 56262306a36Sopenharmony_ci if (err) { 56362306a36Sopenharmony_ci rxe_dbg_dev(rxe, "bad init attr, err = %d", err); 56462306a36Sopenharmony_ci goto err_out; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci err = rxe_add_to_pool(&rxe->qp_pool, qp); 56862306a36Sopenharmony_ci if (err) { 56962306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unable to create qp, err = %d", err); 57062306a36Sopenharmony_ci goto err_out; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci err = rxe_qp_from_init(rxe, qp, pd, init, uresp, ibqp->pd, udata); 57462306a36Sopenharmony_ci if (err) { 57562306a36Sopenharmony_ci rxe_dbg_qp(qp, "create qp failed, err = %d", err); 57662306a36Sopenharmony_ci goto err_cleanup; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci rxe_finalize(qp); 58062306a36Sopenharmony_ci return 0; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cierr_cleanup: 58362306a36Sopenharmony_ci cleanup_err = rxe_cleanup(qp); 58462306a36Sopenharmony_ci if (cleanup_err) 58562306a36Sopenharmony_ci rxe_err_qp(qp, "cleanup failed, err = %d", cleanup_err); 58662306a36Sopenharmony_cierr_out: 58762306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 58862306a36Sopenharmony_ci return err; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int rxe_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 59262306a36Sopenharmony_ci int mask, struct ib_udata *udata) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibqp->device); 59562306a36Sopenharmony_ci struct rxe_qp *qp = to_rqp(ibqp); 59662306a36Sopenharmony_ci int err; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (mask & ~IB_QP_ATTR_STANDARD_BITS) { 59962306a36Sopenharmony_ci err = -EOPNOTSUPP; 60062306a36Sopenharmony_ci rxe_dbg_qp(qp, "unsupported mask = 0x%x, err = %d", 60162306a36Sopenharmony_ci mask, err); 60262306a36Sopenharmony_ci goto err_out; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci err = rxe_qp_chk_attr(rxe, qp, attr, mask); 60662306a36Sopenharmony_ci if (err) { 60762306a36Sopenharmony_ci rxe_dbg_qp(qp, "bad mask/attr, err = %d", err); 60862306a36Sopenharmony_ci goto err_out; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci err = rxe_qp_from_attr(qp, attr, mask, udata); 61262306a36Sopenharmony_ci if (err) { 61362306a36Sopenharmony_ci rxe_dbg_qp(qp, "modify qp failed, err = %d", err); 61462306a36Sopenharmony_ci goto err_out; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if ((mask & IB_QP_AV) && (attr->ah_attr.ah_flags & IB_AH_GRH)) 61862306a36Sopenharmony_ci qp->src_port = rdma_get_udp_sport(attr->ah_attr.grh.flow_label, 61962306a36Sopenharmony_ci qp->ibqp.qp_num, 62062306a36Sopenharmony_ci qp->attr.dest_qp_num); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return 0; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cierr_out: 62562306a36Sopenharmony_ci rxe_err_qp(qp, "returned err = %d", err); 62662306a36Sopenharmony_ci return err; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic int rxe_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 63062306a36Sopenharmony_ci int mask, struct ib_qp_init_attr *init) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci struct rxe_qp *qp = to_rqp(ibqp); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci rxe_qp_to_init(qp, init); 63562306a36Sopenharmony_ci rxe_qp_to_attr(qp, attr, mask); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int rxe_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct rxe_qp *qp = to_rqp(ibqp); 64362306a36Sopenharmony_ci int err; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci err = rxe_qp_chk_destroy(qp); 64662306a36Sopenharmony_ci if (err) { 64762306a36Sopenharmony_ci rxe_dbg_qp(qp, "unable to destroy qp, err = %d", err); 64862306a36Sopenharmony_ci goto err_out; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci err = rxe_cleanup(qp); 65262306a36Sopenharmony_ci if (err) 65362306a36Sopenharmony_ci rxe_err_qp(qp, "cleanup failed, err = %d", err); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return 0; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cierr_out: 65862306a36Sopenharmony_ci rxe_err_qp(qp, "returned err = %d", err); 65962306a36Sopenharmony_ci return err; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci/* send wr */ 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci/* sanity check incoming send work request */ 66562306a36Sopenharmony_cistatic int validate_send_wr(struct rxe_qp *qp, const struct ib_send_wr *ibwr, 66662306a36Sopenharmony_ci unsigned int *maskp, unsigned int *lengthp) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci int num_sge = ibwr->num_sge; 66962306a36Sopenharmony_ci struct rxe_sq *sq = &qp->sq; 67062306a36Sopenharmony_ci unsigned int mask = 0; 67162306a36Sopenharmony_ci unsigned long length = 0; 67262306a36Sopenharmony_ci int err = -EINVAL; 67362306a36Sopenharmony_ci int i; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci do { 67662306a36Sopenharmony_ci mask = wr_opcode_mask(ibwr->opcode, qp); 67762306a36Sopenharmony_ci if (!mask) { 67862306a36Sopenharmony_ci rxe_err_qp(qp, "bad wr opcode for qp type"); 67962306a36Sopenharmony_ci break; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (num_sge > sq->max_sge) { 68362306a36Sopenharmony_ci rxe_err_qp(qp, "num_sge > max_sge"); 68462306a36Sopenharmony_ci break; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci length = 0; 68862306a36Sopenharmony_ci for (i = 0; i < ibwr->num_sge; i++) 68962306a36Sopenharmony_ci length += ibwr->sg_list[i].length; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (length > (1UL << 31)) { 69262306a36Sopenharmony_ci rxe_err_qp(qp, "message length too long"); 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (mask & WR_ATOMIC_MASK) { 69762306a36Sopenharmony_ci if (length != 8) { 69862306a36Sopenharmony_ci rxe_err_qp(qp, "atomic length != 8"); 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci if (atomic_wr(ibwr)->remote_addr & 0x7) { 70262306a36Sopenharmony_ci rxe_err_qp(qp, "misaligned atomic address"); 70362306a36Sopenharmony_ci break; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci if (ibwr->send_flags & IB_SEND_INLINE) { 70762306a36Sopenharmony_ci if (!(mask & WR_INLINE_MASK)) { 70862306a36Sopenharmony_ci rxe_err_qp(qp, "opcode doesn't support inline data"); 70962306a36Sopenharmony_ci break; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci if (length > sq->max_inline) { 71262306a36Sopenharmony_ci rxe_err_qp(qp, "inline length too big"); 71362306a36Sopenharmony_ci break; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci err = 0; 71862306a36Sopenharmony_ci } while (0); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci *maskp = mask; 72162306a36Sopenharmony_ci *lengthp = (int)length; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return err; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic int init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr, 72762306a36Sopenharmony_ci const struct ib_send_wr *ibwr) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci wr->wr_id = ibwr->wr_id; 73062306a36Sopenharmony_ci wr->opcode = ibwr->opcode; 73162306a36Sopenharmony_ci wr->send_flags = ibwr->send_flags; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_UD || 73462306a36Sopenharmony_ci qp_type(qp) == IB_QPT_GSI) { 73562306a36Sopenharmony_ci struct ib_ah *ibah = ud_wr(ibwr)->ah; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci wr->wr.ud.remote_qpn = ud_wr(ibwr)->remote_qpn; 73862306a36Sopenharmony_ci wr->wr.ud.remote_qkey = ud_wr(ibwr)->remote_qkey; 73962306a36Sopenharmony_ci wr->wr.ud.ah_num = to_rah(ibah)->ah_num; 74062306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_GSI) 74162306a36Sopenharmony_ci wr->wr.ud.pkey_index = ud_wr(ibwr)->pkey_index; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci switch (wr->opcode) { 74462306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 74562306a36Sopenharmony_ci wr->ex.imm_data = ibwr->ex.imm_data; 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci case IB_WR_SEND: 74862306a36Sopenharmony_ci break; 74962306a36Sopenharmony_ci default: 75062306a36Sopenharmony_ci rxe_err_qp(qp, "bad wr opcode %d for UD/GSI QP", 75162306a36Sopenharmony_ci wr->opcode); 75262306a36Sopenharmony_ci return -EINVAL; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci } else { 75562306a36Sopenharmony_ci switch (wr->opcode) { 75662306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 75762306a36Sopenharmony_ci wr->ex.imm_data = ibwr->ex.imm_data; 75862306a36Sopenharmony_ci fallthrough; 75962306a36Sopenharmony_ci case IB_WR_RDMA_READ: 76062306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 76162306a36Sopenharmony_ci wr->wr.rdma.remote_addr = rdma_wr(ibwr)->remote_addr; 76262306a36Sopenharmony_ci wr->wr.rdma.rkey = rdma_wr(ibwr)->rkey; 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 76562306a36Sopenharmony_ci wr->ex.imm_data = ibwr->ex.imm_data; 76662306a36Sopenharmony_ci break; 76762306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 76862306a36Sopenharmony_ci wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey; 76962306a36Sopenharmony_ci break; 77062306a36Sopenharmony_ci case IB_WR_RDMA_READ_WITH_INV: 77162306a36Sopenharmony_ci wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey; 77262306a36Sopenharmony_ci wr->wr.rdma.remote_addr = rdma_wr(ibwr)->remote_addr; 77362306a36Sopenharmony_ci wr->wr.rdma.rkey = rdma_wr(ibwr)->rkey; 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci case IB_WR_ATOMIC_CMP_AND_SWP: 77662306a36Sopenharmony_ci case IB_WR_ATOMIC_FETCH_AND_ADD: 77762306a36Sopenharmony_ci wr->wr.atomic.remote_addr = 77862306a36Sopenharmony_ci atomic_wr(ibwr)->remote_addr; 77962306a36Sopenharmony_ci wr->wr.atomic.compare_add = 78062306a36Sopenharmony_ci atomic_wr(ibwr)->compare_add; 78162306a36Sopenharmony_ci wr->wr.atomic.swap = atomic_wr(ibwr)->swap; 78262306a36Sopenharmony_ci wr->wr.atomic.rkey = atomic_wr(ibwr)->rkey; 78362306a36Sopenharmony_ci break; 78462306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 78562306a36Sopenharmony_ci wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey; 78662306a36Sopenharmony_ci break; 78762306a36Sopenharmony_ci case IB_WR_REG_MR: 78862306a36Sopenharmony_ci wr->wr.reg.mr = reg_wr(ibwr)->mr; 78962306a36Sopenharmony_ci wr->wr.reg.key = reg_wr(ibwr)->key; 79062306a36Sopenharmony_ci wr->wr.reg.access = reg_wr(ibwr)->access; 79162306a36Sopenharmony_ci break; 79262306a36Sopenharmony_ci case IB_WR_SEND: 79362306a36Sopenharmony_ci case IB_WR_BIND_MW: 79462306a36Sopenharmony_ci case IB_WR_FLUSH: 79562306a36Sopenharmony_ci case IB_WR_ATOMIC_WRITE: 79662306a36Sopenharmony_ci break; 79762306a36Sopenharmony_ci default: 79862306a36Sopenharmony_ci rxe_err_qp(qp, "unsupported wr opcode %d", 79962306a36Sopenharmony_ci wr->opcode); 80062306a36Sopenharmony_ci return -EINVAL; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic void copy_inline_data_to_wqe(struct rxe_send_wqe *wqe, 80862306a36Sopenharmony_ci const struct ib_send_wr *ibwr) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci struct ib_sge *sge = ibwr->sg_list; 81162306a36Sopenharmony_ci u8 *p = wqe->dma.inline_data; 81262306a36Sopenharmony_ci int i; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci for (i = 0; i < ibwr->num_sge; i++, sge++) { 81562306a36Sopenharmony_ci memcpy(p, ib_virt_dma_to_page(sge->addr), sge->length); 81662306a36Sopenharmony_ci p += sge->length; 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic int init_send_wqe(struct rxe_qp *qp, const struct ib_send_wr *ibwr, 82162306a36Sopenharmony_ci unsigned int mask, unsigned int length, 82262306a36Sopenharmony_ci struct rxe_send_wqe *wqe) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci int num_sge = ibwr->num_sge; 82562306a36Sopenharmony_ci int err; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci err = init_send_wr(qp, &wqe->wr, ibwr); 82862306a36Sopenharmony_ci if (err) 82962306a36Sopenharmony_ci return err; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* local operation */ 83262306a36Sopenharmony_ci if (unlikely(mask & WR_LOCAL_OP_MASK)) { 83362306a36Sopenharmony_ci wqe->mask = mask; 83462306a36Sopenharmony_ci wqe->state = wqe_state_posted; 83562306a36Sopenharmony_ci return 0; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (unlikely(ibwr->send_flags & IB_SEND_INLINE)) 83962306a36Sopenharmony_ci copy_inline_data_to_wqe(wqe, ibwr); 84062306a36Sopenharmony_ci else 84162306a36Sopenharmony_ci memcpy(wqe->dma.sge, ibwr->sg_list, 84262306a36Sopenharmony_ci num_sge * sizeof(struct ib_sge)); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci wqe->iova = mask & WR_ATOMIC_MASK ? atomic_wr(ibwr)->remote_addr : 84562306a36Sopenharmony_ci mask & WR_READ_OR_WRITE_MASK ? rdma_wr(ibwr)->remote_addr : 0; 84662306a36Sopenharmony_ci wqe->mask = mask; 84762306a36Sopenharmony_ci wqe->dma.length = length; 84862306a36Sopenharmony_ci wqe->dma.resid = length; 84962306a36Sopenharmony_ci wqe->dma.num_sge = num_sge; 85062306a36Sopenharmony_ci wqe->dma.cur_sge = 0; 85162306a36Sopenharmony_ci wqe->dma.sge_offset = 0; 85262306a36Sopenharmony_ci wqe->state = wqe_state_posted; 85362306a36Sopenharmony_ci wqe->ssn = atomic_add_return(1, &qp->ssn); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci return 0; 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int post_one_send(struct rxe_qp *qp, const struct ib_send_wr *ibwr) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci int err; 86162306a36Sopenharmony_ci struct rxe_sq *sq = &qp->sq; 86262306a36Sopenharmony_ci struct rxe_send_wqe *send_wqe; 86362306a36Sopenharmony_ci unsigned int mask; 86462306a36Sopenharmony_ci unsigned int length; 86562306a36Sopenharmony_ci int full; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci err = validate_send_wr(qp, ibwr, &mask, &length); 86862306a36Sopenharmony_ci if (err) 86962306a36Sopenharmony_ci return err; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci full = queue_full(sq->queue, QUEUE_TYPE_FROM_ULP); 87262306a36Sopenharmony_ci if (unlikely(full)) { 87362306a36Sopenharmony_ci rxe_err_qp(qp, "send queue full"); 87462306a36Sopenharmony_ci return -ENOMEM; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci send_wqe = queue_producer_addr(sq->queue, QUEUE_TYPE_FROM_ULP); 87862306a36Sopenharmony_ci err = init_send_wqe(qp, ibwr, mask, length, send_wqe); 87962306a36Sopenharmony_ci if (!err) 88062306a36Sopenharmony_ci queue_advance_producer(sq->queue, QUEUE_TYPE_FROM_ULP); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci return err; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic int rxe_post_send_kernel(struct rxe_qp *qp, 88662306a36Sopenharmony_ci const struct ib_send_wr *ibwr, 88762306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci int err = 0; 89062306a36Sopenharmony_ci unsigned long flags; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci spin_lock_irqsave(&qp->sq.sq_lock, flags); 89362306a36Sopenharmony_ci while (ibwr) { 89462306a36Sopenharmony_ci err = post_one_send(qp, ibwr); 89562306a36Sopenharmony_ci if (err) { 89662306a36Sopenharmony_ci *bad_wr = ibwr; 89762306a36Sopenharmony_ci break; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci ibwr = ibwr->next; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->sq.sq_lock, flags); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (!err) 90462306a36Sopenharmony_ci rxe_sched_task(&qp->req.task); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 90762306a36Sopenharmony_ci if (qp_state(qp) == IB_QPS_ERR) 90862306a36Sopenharmony_ci rxe_sched_task(&qp->comp.task); 90962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return err; 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic int rxe_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 91562306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci struct rxe_qp *qp = to_rqp(ibqp); 91862306a36Sopenharmony_ci int err; 91962306a36Sopenharmony_ci unsigned long flags; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 92262306a36Sopenharmony_ci /* caller has already called destroy_qp */ 92362306a36Sopenharmony_ci if (WARN_ON_ONCE(!qp->valid)) { 92462306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 92562306a36Sopenharmony_ci rxe_err_qp(qp, "qp has been destroyed"); 92662306a36Sopenharmony_ci return -EINVAL; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (unlikely(qp_state(qp) < IB_QPS_RTS)) { 93062306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 93162306a36Sopenharmony_ci *bad_wr = wr; 93262306a36Sopenharmony_ci rxe_err_qp(qp, "qp not ready to send"); 93362306a36Sopenharmony_ci return -EINVAL; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (qp->is_user) { 93862306a36Sopenharmony_ci /* Utilize process context to do protocol processing */ 93962306a36Sopenharmony_ci rxe_run_task(&qp->req.task); 94062306a36Sopenharmony_ci } else { 94162306a36Sopenharmony_ci err = rxe_post_send_kernel(qp, wr, bad_wr); 94262306a36Sopenharmony_ci if (err) 94362306a36Sopenharmony_ci return err; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci return 0; 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci/* recv wr */ 95062306a36Sopenharmony_cistatic int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci int i; 95362306a36Sopenharmony_ci unsigned long length; 95462306a36Sopenharmony_ci struct rxe_recv_wqe *recv_wqe; 95562306a36Sopenharmony_ci int num_sge = ibwr->num_sge; 95662306a36Sopenharmony_ci int full; 95762306a36Sopenharmony_ci int err; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci full = queue_full(rq->queue, QUEUE_TYPE_FROM_ULP); 96062306a36Sopenharmony_ci if (unlikely(full)) { 96162306a36Sopenharmony_ci err = -ENOMEM; 96262306a36Sopenharmony_ci rxe_dbg("queue full"); 96362306a36Sopenharmony_ci goto err_out; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (unlikely(num_sge > rq->max_sge)) { 96762306a36Sopenharmony_ci err = -EINVAL; 96862306a36Sopenharmony_ci rxe_dbg("bad num_sge > max_sge"); 96962306a36Sopenharmony_ci goto err_out; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci length = 0; 97362306a36Sopenharmony_ci for (i = 0; i < num_sge; i++) 97462306a36Sopenharmony_ci length += ibwr->sg_list[i].length; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* IBA max message size is 2^31 */ 97762306a36Sopenharmony_ci if (length >= (1UL<<31)) { 97862306a36Sopenharmony_ci err = -EINVAL; 97962306a36Sopenharmony_ci rxe_dbg("message length too long"); 98062306a36Sopenharmony_ci goto err_out; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci recv_wqe = queue_producer_addr(rq->queue, QUEUE_TYPE_FROM_ULP); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci recv_wqe->wr_id = ibwr->wr_id; 98662306a36Sopenharmony_ci recv_wqe->dma.length = length; 98762306a36Sopenharmony_ci recv_wqe->dma.resid = length; 98862306a36Sopenharmony_ci recv_wqe->dma.num_sge = num_sge; 98962306a36Sopenharmony_ci recv_wqe->dma.cur_sge = 0; 99062306a36Sopenharmony_ci recv_wqe->dma.sge_offset = 0; 99162306a36Sopenharmony_ci memcpy(recv_wqe->dma.sge, ibwr->sg_list, 99262306a36Sopenharmony_ci num_sge * sizeof(struct ib_sge)); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci queue_advance_producer(rq->queue, QUEUE_TYPE_FROM_ULP); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return 0; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cierr_out: 99962306a36Sopenharmony_ci rxe_dbg("returned err = %d", err); 100062306a36Sopenharmony_ci return err; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic int rxe_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, 100462306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci int err = 0; 100762306a36Sopenharmony_ci struct rxe_qp *qp = to_rqp(ibqp); 100862306a36Sopenharmony_ci struct rxe_rq *rq = &qp->rq; 100962306a36Sopenharmony_ci unsigned long flags; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 101262306a36Sopenharmony_ci /* caller has already called destroy_qp */ 101362306a36Sopenharmony_ci if (WARN_ON_ONCE(!qp->valid)) { 101462306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 101562306a36Sopenharmony_ci rxe_err_qp(qp, "qp has been destroyed"); 101662306a36Sopenharmony_ci return -EINVAL; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci /* see C10-97.2.1 */ 102062306a36Sopenharmony_ci if (unlikely((qp_state(qp) < IB_QPS_INIT))) { 102162306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 102262306a36Sopenharmony_ci *bad_wr = wr; 102362306a36Sopenharmony_ci rxe_dbg_qp(qp, "qp not ready to post recv"); 102462306a36Sopenharmony_ci return -EINVAL; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (unlikely(qp->srq)) { 102962306a36Sopenharmony_ci *bad_wr = wr; 103062306a36Sopenharmony_ci rxe_dbg_qp(qp, "qp has srq, use post_srq_recv instead"); 103162306a36Sopenharmony_ci return -EINVAL; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci spin_lock_irqsave(&rq->producer_lock, flags); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci while (wr) { 103762306a36Sopenharmony_ci err = post_one_recv(rq, wr); 103862306a36Sopenharmony_ci if (unlikely(err)) { 103962306a36Sopenharmony_ci *bad_wr = wr; 104062306a36Sopenharmony_ci break; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci wr = wr->next; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci spin_unlock_irqrestore(&rq->producer_lock, flags); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 104862306a36Sopenharmony_ci if (qp_state(qp) == IB_QPS_ERR) 104962306a36Sopenharmony_ci rxe_sched_task(&qp->resp.task); 105062306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci return err; 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci/* cq */ 105662306a36Sopenharmony_cistatic int rxe_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, 105762306a36Sopenharmony_ci struct ib_udata *udata) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct ib_device *dev = ibcq->device; 106062306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(dev); 106162306a36Sopenharmony_ci struct rxe_cq *cq = to_rcq(ibcq); 106262306a36Sopenharmony_ci struct rxe_create_cq_resp __user *uresp = NULL; 106362306a36Sopenharmony_ci int err, cleanup_err; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (udata) { 106662306a36Sopenharmony_ci if (udata->outlen < sizeof(*uresp)) { 106762306a36Sopenharmony_ci err = -EINVAL; 106862306a36Sopenharmony_ci rxe_dbg_dev(rxe, "malformed udata, err = %d", err); 106962306a36Sopenharmony_ci goto err_out; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci uresp = udata->outbuf; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (attr->flags) { 107562306a36Sopenharmony_ci err = -EOPNOTSUPP; 107662306a36Sopenharmony_ci rxe_dbg_dev(rxe, "bad attr->flags, err = %d", err); 107762306a36Sopenharmony_ci goto err_out; 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci err = rxe_cq_chk_attr(rxe, NULL, attr->cqe, attr->comp_vector); 108162306a36Sopenharmony_ci if (err) { 108262306a36Sopenharmony_ci rxe_dbg_dev(rxe, "bad init attributes, err = %d", err); 108362306a36Sopenharmony_ci goto err_out; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci err = rxe_add_to_pool(&rxe->cq_pool, cq); 108762306a36Sopenharmony_ci if (err) { 108862306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unable to create cq, err = %d", err); 108962306a36Sopenharmony_ci goto err_out; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci err = rxe_cq_from_init(rxe, cq, attr->cqe, attr->comp_vector, udata, 109362306a36Sopenharmony_ci uresp); 109462306a36Sopenharmony_ci if (err) { 109562306a36Sopenharmony_ci rxe_dbg_cq(cq, "create cq failed, err = %d", err); 109662306a36Sopenharmony_ci goto err_cleanup; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci return 0; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_cierr_cleanup: 110262306a36Sopenharmony_ci cleanup_err = rxe_cleanup(cq); 110362306a36Sopenharmony_ci if (cleanup_err) 110462306a36Sopenharmony_ci rxe_err_cq(cq, "cleanup failed, err = %d", cleanup_err); 110562306a36Sopenharmony_cierr_out: 110662306a36Sopenharmony_ci rxe_err_dev(rxe, "returned err = %d", err); 110762306a36Sopenharmony_ci return err; 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_cistatic int rxe_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci struct rxe_cq *cq = to_rcq(ibcq); 111362306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibcq->device); 111462306a36Sopenharmony_ci struct rxe_resize_cq_resp __user *uresp = NULL; 111562306a36Sopenharmony_ci int err; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (udata) { 111862306a36Sopenharmony_ci if (udata->outlen < sizeof(*uresp)) { 111962306a36Sopenharmony_ci err = -EINVAL; 112062306a36Sopenharmony_ci rxe_dbg_cq(cq, "malformed udata"); 112162306a36Sopenharmony_ci goto err_out; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci uresp = udata->outbuf; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci err = rxe_cq_chk_attr(rxe, cq, cqe, 0); 112762306a36Sopenharmony_ci if (err) { 112862306a36Sopenharmony_ci rxe_dbg_cq(cq, "bad attr, err = %d", err); 112962306a36Sopenharmony_ci goto err_out; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci err = rxe_cq_resize_queue(cq, cqe, uresp, udata); 113362306a36Sopenharmony_ci if (err) { 113462306a36Sopenharmony_ci rxe_dbg_cq(cq, "resize cq failed, err = %d", err); 113562306a36Sopenharmony_ci goto err_out; 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci return 0; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cierr_out: 114162306a36Sopenharmony_ci rxe_err_cq(cq, "returned err = %d", err); 114262306a36Sopenharmony_ci return err; 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_cistatic int rxe_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci int i; 114862306a36Sopenharmony_ci struct rxe_cq *cq = to_rcq(ibcq); 114962306a36Sopenharmony_ci struct rxe_cqe *cqe; 115062306a36Sopenharmony_ci unsigned long flags; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, flags); 115362306a36Sopenharmony_ci for (i = 0; i < num_entries; i++) { 115462306a36Sopenharmony_ci cqe = queue_head(cq->queue, QUEUE_TYPE_TO_ULP); 115562306a36Sopenharmony_ci if (!cqe) 115662306a36Sopenharmony_ci break; /* queue empty */ 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci memcpy(wc++, &cqe->ibwc, sizeof(*wc)); 115962306a36Sopenharmony_ci queue_advance_consumer(cq->queue, QUEUE_TYPE_TO_ULP); 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, flags); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci return i; 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic int rxe_peek_cq(struct ib_cq *ibcq, int wc_cnt) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci struct rxe_cq *cq = to_rcq(ibcq); 116962306a36Sopenharmony_ci int count; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci count = queue_count(cq->queue, QUEUE_TYPE_TO_ULP); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci return (count > wc_cnt) ? wc_cnt : count; 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic int rxe_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) 117762306a36Sopenharmony_ci{ 117862306a36Sopenharmony_ci struct rxe_cq *cq = to_rcq(ibcq); 117962306a36Sopenharmony_ci int ret = 0; 118062306a36Sopenharmony_ci int empty; 118162306a36Sopenharmony_ci unsigned long irq_flags; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, irq_flags); 118462306a36Sopenharmony_ci cq->notify |= flags & IB_CQ_SOLICITED_MASK; 118562306a36Sopenharmony_ci empty = queue_empty(cq->queue, QUEUE_TYPE_TO_ULP); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && !empty) 118862306a36Sopenharmony_ci ret = 1; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, irq_flags); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci return ret; 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic int rxe_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci struct rxe_cq *cq = to_rcq(ibcq); 119862306a36Sopenharmony_ci int err; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* See IBA C11-17: The CI shall return an error if this Verb is 120162306a36Sopenharmony_ci * invoked while a Work Queue is still associated with the CQ. 120262306a36Sopenharmony_ci */ 120362306a36Sopenharmony_ci if (atomic_read(&cq->num_wq)) { 120462306a36Sopenharmony_ci err = -EINVAL; 120562306a36Sopenharmony_ci rxe_dbg_cq(cq, "still in use"); 120662306a36Sopenharmony_ci goto err_out; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci err = rxe_cleanup(cq); 121062306a36Sopenharmony_ci if (err) 121162306a36Sopenharmony_ci rxe_err_cq(cq, "cleanup failed, err = %d", err); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci return 0; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cierr_out: 121662306a36Sopenharmony_ci rxe_err_cq(cq, "returned err = %d", err); 121762306a36Sopenharmony_ci return err; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci/* mr */ 122162306a36Sopenharmony_cistatic struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibpd->device); 122462306a36Sopenharmony_ci struct rxe_pd *pd = to_rpd(ibpd); 122562306a36Sopenharmony_ci struct rxe_mr *mr; 122662306a36Sopenharmony_ci int err; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 122962306a36Sopenharmony_ci if (!mr) 123062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci err = rxe_add_to_pool(&rxe->mr_pool, mr); 123362306a36Sopenharmony_ci if (err) { 123462306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unable to create mr"); 123562306a36Sopenharmony_ci goto err_free; 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci rxe_get(pd); 123962306a36Sopenharmony_ci mr->ibmr.pd = ibpd; 124062306a36Sopenharmony_ci mr->ibmr.device = ibpd->device; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci rxe_mr_init_dma(access, mr); 124362306a36Sopenharmony_ci rxe_finalize(mr); 124462306a36Sopenharmony_ci return &mr->ibmr; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_cierr_free: 124762306a36Sopenharmony_ci kfree(mr); 124862306a36Sopenharmony_ci rxe_err_pd(pd, "returned err = %d", err); 124962306a36Sopenharmony_ci return ERR_PTR(err); 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd, u64 start, 125362306a36Sopenharmony_ci u64 length, u64 iova, int access, 125462306a36Sopenharmony_ci struct ib_udata *udata) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibpd->device); 125762306a36Sopenharmony_ci struct rxe_pd *pd = to_rpd(ibpd); 125862306a36Sopenharmony_ci struct rxe_mr *mr; 125962306a36Sopenharmony_ci int err, cleanup_err; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (access & ~RXE_ACCESS_SUPPORTED_MR) { 126262306a36Sopenharmony_ci rxe_err_pd(pd, "access = %#x not supported (%#x)", access, 126362306a36Sopenharmony_ci RXE_ACCESS_SUPPORTED_MR); 126462306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 126862306a36Sopenharmony_ci if (!mr) 126962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci err = rxe_add_to_pool(&rxe->mr_pool, mr); 127262306a36Sopenharmony_ci if (err) { 127362306a36Sopenharmony_ci rxe_dbg_pd(pd, "unable to create mr"); 127462306a36Sopenharmony_ci goto err_free; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci rxe_get(pd); 127862306a36Sopenharmony_ci mr->ibmr.pd = ibpd; 127962306a36Sopenharmony_ci mr->ibmr.device = ibpd->device; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci err = rxe_mr_init_user(rxe, start, length, iova, access, mr); 128262306a36Sopenharmony_ci if (err) { 128362306a36Sopenharmony_ci rxe_dbg_mr(mr, "reg_user_mr failed, err = %d", err); 128462306a36Sopenharmony_ci goto err_cleanup; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci rxe_finalize(mr); 128862306a36Sopenharmony_ci return &mr->ibmr; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_cierr_cleanup: 129162306a36Sopenharmony_ci cleanup_err = rxe_cleanup(mr); 129262306a36Sopenharmony_ci if (cleanup_err) 129362306a36Sopenharmony_ci rxe_err_mr(mr, "cleanup failed, err = %d", cleanup_err); 129462306a36Sopenharmony_cierr_free: 129562306a36Sopenharmony_ci kfree(mr); 129662306a36Sopenharmony_ci rxe_err_pd(pd, "returned err = %d", err); 129762306a36Sopenharmony_ci return ERR_PTR(err); 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags, 130162306a36Sopenharmony_ci u64 start, u64 length, u64 iova, 130262306a36Sopenharmony_ci int access, struct ib_pd *ibpd, 130362306a36Sopenharmony_ci struct ib_udata *udata) 130462306a36Sopenharmony_ci{ 130562306a36Sopenharmony_ci struct rxe_mr *mr = to_rmr(ibmr); 130662306a36Sopenharmony_ci struct rxe_pd *old_pd = to_rpd(ibmr->pd); 130762306a36Sopenharmony_ci struct rxe_pd *pd = to_rpd(ibpd); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci /* for now only support the two easy cases: 131062306a36Sopenharmony_ci * rereg_pd and rereg_access 131162306a36Sopenharmony_ci */ 131262306a36Sopenharmony_ci if (flags & ~RXE_MR_REREG_SUPPORTED) { 131362306a36Sopenharmony_ci rxe_err_mr(mr, "flags = %#x not supported", flags); 131462306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci if (flags & IB_MR_REREG_PD) { 131862306a36Sopenharmony_ci rxe_put(old_pd); 131962306a36Sopenharmony_ci rxe_get(pd); 132062306a36Sopenharmony_ci mr->ibmr.pd = ibpd; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (flags & IB_MR_REREG_ACCESS) { 132462306a36Sopenharmony_ci if (access & ~RXE_ACCESS_SUPPORTED_MR) { 132562306a36Sopenharmony_ci rxe_err_mr(mr, "access = %#x not supported", access); 132662306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci mr->access = access; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci return NULL; 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_cistatic struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type, 133562306a36Sopenharmony_ci u32 max_num_sg) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(ibpd->device); 133862306a36Sopenharmony_ci struct rxe_pd *pd = to_rpd(ibpd); 133962306a36Sopenharmony_ci struct rxe_mr *mr; 134062306a36Sopenharmony_ci int err, cleanup_err; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if (mr_type != IB_MR_TYPE_MEM_REG) { 134362306a36Sopenharmony_ci err = -EINVAL; 134462306a36Sopenharmony_ci rxe_dbg_pd(pd, "mr type %d not supported, err = %d", 134562306a36Sopenharmony_ci mr_type, err); 134662306a36Sopenharmony_ci goto err_out; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 135062306a36Sopenharmony_ci if (!mr) 135162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci err = rxe_add_to_pool(&rxe->mr_pool, mr); 135462306a36Sopenharmony_ci if (err) 135562306a36Sopenharmony_ci goto err_free; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci rxe_get(pd); 135862306a36Sopenharmony_ci mr->ibmr.pd = ibpd; 135962306a36Sopenharmony_ci mr->ibmr.device = ibpd->device; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci err = rxe_mr_init_fast(max_num_sg, mr); 136262306a36Sopenharmony_ci if (err) { 136362306a36Sopenharmony_ci rxe_dbg_mr(mr, "alloc_mr failed, err = %d", err); 136462306a36Sopenharmony_ci goto err_cleanup; 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci rxe_finalize(mr); 136862306a36Sopenharmony_ci return &mr->ibmr; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_cierr_cleanup: 137162306a36Sopenharmony_ci cleanup_err = rxe_cleanup(mr); 137262306a36Sopenharmony_ci if (cleanup_err) 137362306a36Sopenharmony_ci rxe_err_mr(mr, "cleanup failed, err = %d", err); 137462306a36Sopenharmony_cierr_free: 137562306a36Sopenharmony_ci kfree(mr); 137662306a36Sopenharmony_cierr_out: 137762306a36Sopenharmony_ci rxe_err_pd(pd, "returned err = %d", err); 137862306a36Sopenharmony_ci return ERR_PTR(err); 137962306a36Sopenharmony_ci} 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_cistatic int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata) 138262306a36Sopenharmony_ci{ 138362306a36Sopenharmony_ci struct rxe_mr *mr = to_rmr(ibmr); 138462306a36Sopenharmony_ci int err, cleanup_err; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* See IBA 10.6.7.2.6 */ 138762306a36Sopenharmony_ci if (atomic_read(&mr->num_mw) > 0) { 138862306a36Sopenharmony_ci err = -EINVAL; 138962306a36Sopenharmony_ci rxe_dbg_mr(mr, "mr has mw's bound"); 139062306a36Sopenharmony_ci goto err_out; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci cleanup_err = rxe_cleanup(mr); 139462306a36Sopenharmony_ci if (cleanup_err) 139562306a36Sopenharmony_ci rxe_err_mr(mr, "cleanup failed, err = %d", cleanup_err); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci kfree_rcu_mightsleep(mr); 139862306a36Sopenharmony_ci return 0; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cierr_out: 140162306a36Sopenharmony_ci rxe_err_mr(mr, "returned err = %d", err); 140262306a36Sopenharmony_ci return err; 140362306a36Sopenharmony_ci} 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_cistatic ssize_t parent_show(struct device *device, 140662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci struct rxe_dev *rxe = 140962306a36Sopenharmony_ci rdma_device_to_drv_device(device, struct rxe_dev, ib_dev); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", rxe_parent_name(rxe, 1)); 141262306a36Sopenharmony_ci} 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(parent); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_cistatic struct attribute *rxe_dev_attributes[] = { 141762306a36Sopenharmony_ci &dev_attr_parent.attr, 141862306a36Sopenharmony_ci NULL 141962306a36Sopenharmony_ci}; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_cistatic const struct attribute_group rxe_attr_group = { 142262306a36Sopenharmony_ci .attrs = rxe_dev_attributes, 142362306a36Sopenharmony_ci}; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_cistatic int rxe_enable_driver(struct ib_device *ib_dev) 142662306a36Sopenharmony_ci{ 142762306a36Sopenharmony_ci struct rxe_dev *rxe = container_of(ib_dev, struct rxe_dev, ib_dev); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci rxe_set_port_state(rxe); 143062306a36Sopenharmony_ci dev_info(&rxe->ib_dev.dev, "added %s\n", netdev_name(rxe->ndev)); 143162306a36Sopenharmony_ci return 0; 143262306a36Sopenharmony_ci} 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_cistatic const struct ib_device_ops rxe_dev_ops = { 143562306a36Sopenharmony_ci .owner = THIS_MODULE, 143662306a36Sopenharmony_ci .driver_id = RDMA_DRIVER_RXE, 143762306a36Sopenharmony_ci .uverbs_abi_ver = RXE_UVERBS_ABI_VERSION, 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci .alloc_hw_port_stats = rxe_ib_alloc_hw_port_stats, 144062306a36Sopenharmony_ci .alloc_mr = rxe_alloc_mr, 144162306a36Sopenharmony_ci .alloc_mw = rxe_alloc_mw, 144262306a36Sopenharmony_ci .alloc_pd = rxe_alloc_pd, 144362306a36Sopenharmony_ci .alloc_ucontext = rxe_alloc_ucontext, 144462306a36Sopenharmony_ci .attach_mcast = rxe_attach_mcast, 144562306a36Sopenharmony_ci .create_ah = rxe_create_ah, 144662306a36Sopenharmony_ci .create_cq = rxe_create_cq, 144762306a36Sopenharmony_ci .create_qp = rxe_create_qp, 144862306a36Sopenharmony_ci .create_srq = rxe_create_srq, 144962306a36Sopenharmony_ci .create_user_ah = rxe_create_ah, 145062306a36Sopenharmony_ci .dealloc_driver = rxe_dealloc, 145162306a36Sopenharmony_ci .dealloc_mw = rxe_dealloc_mw, 145262306a36Sopenharmony_ci .dealloc_pd = rxe_dealloc_pd, 145362306a36Sopenharmony_ci .dealloc_ucontext = rxe_dealloc_ucontext, 145462306a36Sopenharmony_ci .dereg_mr = rxe_dereg_mr, 145562306a36Sopenharmony_ci .destroy_ah = rxe_destroy_ah, 145662306a36Sopenharmony_ci .destroy_cq = rxe_destroy_cq, 145762306a36Sopenharmony_ci .destroy_qp = rxe_destroy_qp, 145862306a36Sopenharmony_ci .destroy_srq = rxe_destroy_srq, 145962306a36Sopenharmony_ci .detach_mcast = rxe_detach_mcast, 146062306a36Sopenharmony_ci .device_group = &rxe_attr_group, 146162306a36Sopenharmony_ci .enable_driver = rxe_enable_driver, 146262306a36Sopenharmony_ci .get_dma_mr = rxe_get_dma_mr, 146362306a36Sopenharmony_ci .get_hw_stats = rxe_ib_get_hw_stats, 146462306a36Sopenharmony_ci .get_link_layer = rxe_get_link_layer, 146562306a36Sopenharmony_ci .get_port_immutable = rxe_port_immutable, 146662306a36Sopenharmony_ci .map_mr_sg = rxe_map_mr_sg, 146762306a36Sopenharmony_ci .mmap = rxe_mmap, 146862306a36Sopenharmony_ci .modify_ah = rxe_modify_ah, 146962306a36Sopenharmony_ci .modify_device = rxe_modify_device, 147062306a36Sopenharmony_ci .modify_port = rxe_modify_port, 147162306a36Sopenharmony_ci .modify_qp = rxe_modify_qp, 147262306a36Sopenharmony_ci .modify_srq = rxe_modify_srq, 147362306a36Sopenharmony_ci .peek_cq = rxe_peek_cq, 147462306a36Sopenharmony_ci .poll_cq = rxe_poll_cq, 147562306a36Sopenharmony_ci .post_recv = rxe_post_recv, 147662306a36Sopenharmony_ci .post_send = rxe_post_send, 147762306a36Sopenharmony_ci .post_srq_recv = rxe_post_srq_recv, 147862306a36Sopenharmony_ci .query_ah = rxe_query_ah, 147962306a36Sopenharmony_ci .query_device = rxe_query_device, 148062306a36Sopenharmony_ci .query_pkey = rxe_query_pkey, 148162306a36Sopenharmony_ci .query_port = rxe_query_port, 148262306a36Sopenharmony_ci .query_qp = rxe_query_qp, 148362306a36Sopenharmony_ci .query_srq = rxe_query_srq, 148462306a36Sopenharmony_ci .reg_user_mr = rxe_reg_user_mr, 148562306a36Sopenharmony_ci .req_notify_cq = rxe_req_notify_cq, 148662306a36Sopenharmony_ci .rereg_user_mr = rxe_rereg_user_mr, 148762306a36Sopenharmony_ci .resize_cq = rxe_resize_cq, 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ah, rxe_ah, ibah), 149062306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_cq, rxe_cq, ibcq), 149162306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_pd, rxe_pd, ibpd), 149262306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_qp, rxe_qp, ibqp), 149362306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_srq, rxe_srq, ibsrq), 149462306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ucontext, rxe_ucontext, ibuc), 149562306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_mw, rxe_mw, ibmw), 149662306a36Sopenharmony_ci}; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ciint rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name) 149962306a36Sopenharmony_ci{ 150062306a36Sopenharmony_ci int err; 150162306a36Sopenharmony_ci struct ib_device *dev = &rxe->ib_dev; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci strscpy(dev->node_desc, "rxe", sizeof(dev->node_desc)); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci dev->node_type = RDMA_NODE_IB_CA; 150662306a36Sopenharmony_ci dev->phys_port_cnt = 1; 150762306a36Sopenharmony_ci dev->num_comp_vectors = num_possible_cpus(); 150862306a36Sopenharmony_ci dev->local_dma_lkey = 0; 150962306a36Sopenharmony_ci addrconf_addr_eui48((unsigned char *)&dev->node_guid, 151062306a36Sopenharmony_ci rxe->ndev->dev_addr); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci dev->uverbs_cmd_mask |= BIT_ULL(IB_USER_VERBS_CMD_POST_SEND) | 151362306a36Sopenharmony_ci BIT_ULL(IB_USER_VERBS_CMD_REQ_NOTIFY_CQ); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci ib_set_device_ops(dev, &rxe_dev_ops); 151662306a36Sopenharmony_ci err = ib_device_set_netdev(&rxe->ib_dev, rxe->ndev, 1); 151762306a36Sopenharmony_ci if (err) 151862306a36Sopenharmony_ci return err; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci err = rxe_icrc_init(rxe); 152162306a36Sopenharmony_ci if (err) 152262306a36Sopenharmony_ci return err; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci err = ib_register_device(dev, ibdev_name, NULL); 152562306a36Sopenharmony_ci if (err) 152662306a36Sopenharmony_ci rxe_dbg_dev(rxe, "failed with error %d\n", err); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* 152962306a36Sopenharmony_ci * Note that rxe may be invalid at this point if another thread 153062306a36Sopenharmony_ci * unregistered it. 153162306a36Sopenharmony_ci */ 153262306a36Sopenharmony_ci return err; 153362306a36Sopenharmony_ci} 1534