1219820Sjeff/* 2219820Sjeff * Copyright (c) 2005 Topspin Communications. All rights reserved. 3219820Sjeff * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. 4219820Sjeff * Copyright (c) 2005 PathScale, Inc. All rights reserved. 5219820Sjeff * Copyright (c) 2006 Mellanox Technologies. All rights reserved. 6219820Sjeff * 7219820Sjeff * This software is available to you under a choice of one of two 8219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 9219820Sjeff * General Public License (GPL) Version 2, available from the file 10219820Sjeff * COPYING in the main directory of this source tree, or the 11219820Sjeff * OpenIB.org BSD license below: 12219820Sjeff * 13219820Sjeff * Redistribution and use in source and binary forms, with or 14219820Sjeff * without modification, are permitted provided that the following 15219820Sjeff * conditions are met: 16219820Sjeff * 17219820Sjeff * - Redistributions of source code must retain the above 18219820Sjeff * copyright notice, this list of conditions and the following 19219820Sjeff * disclaimer. 20219820Sjeff * 21219820Sjeff * - Redistributions in binary form must reproduce the above 22219820Sjeff * copyright notice, this list of conditions and the following 23219820Sjeff * disclaimer in the documentation and/or other materials 24219820Sjeff * provided with the distribution. 25219820Sjeff * 26219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33219820Sjeff * SOFTWARE. 34219820Sjeff */ 35219820Sjeff 36219820Sjeff#include <linux/file.h> 37219820Sjeff#include <linux/fs.h> 38219820Sjeff 39219820Sjeff#include <asm/uaccess.h> 40219820Sjeff#include <asm/fcntl.h> 41219820Sjeff 42219820Sjeff#include "uverbs.h" 43219820Sjeff 44219820Sjeffstatic struct lock_class_key pd_lock_key; 45219820Sjeffstatic struct lock_class_key mr_lock_key; 46219820Sjeffstatic struct lock_class_key cq_lock_key; 47219820Sjeffstatic struct lock_class_key qp_lock_key; 48219820Sjeffstatic struct lock_class_key ah_lock_key; 49219820Sjeffstatic struct lock_class_key srq_lock_key; 50219820Sjeff 51219820Sjeff#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \ 52219820Sjeff do { \ 53219820Sjeff (udata)->inbuf = (void __user *) (ibuf); \ 54219820Sjeff (udata)->outbuf = (void __user *) (obuf); \ 55219820Sjeff (udata)->inlen = (ilen); \ 56219820Sjeff (udata)->outlen = (olen); \ 57219820Sjeff } while (0) 58219820Sjeff 59219820Sjeff/* 60219820Sjeff * The ib_uobject locking scheme is as follows: 61219820Sjeff * 62219820Sjeff * - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it 63219820Sjeff * needs to be held during all idr operations. When an object is 64219820Sjeff * looked up, a reference must be taken on the object's kref before 65219820Sjeff * dropping this lock. 66219820Sjeff * 67219820Sjeff * - Each object also has an rwsem. This rwsem must be held for 68219820Sjeff * reading while an operation that uses the object is performed. 69219820Sjeff * For example, while registering an MR, the associated PD's 70219820Sjeff * uobject.mutex must be held for reading. The rwsem must be held 71219820Sjeff * for writing while initializing or destroying an object. 72219820Sjeff * 73219820Sjeff * - In addition, each object has a "live" flag. If this flag is not 74219820Sjeff * set, then lookups of the object will fail even if it is found in 75219820Sjeff * the idr. This handles a reader that blocks and does not acquire 76219820Sjeff * the rwsem until after the object is destroyed. The destroy 77219820Sjeff * operation will set the live flag to 0 and then drop the rwsem; 78219820Sjeff * this will allow the reader to acquire the rwsem, see that the 79219820Sjeff * live flag is 0, and then drop the rwsem and its reference to 80219820Sjeff * object. The underlying storage will not be freed until the last 81219820Sjeff * reference to the object is dropped. 82219820Sjeff */ 83219820Sjeff 84219820Sjeffstatic void init_uobj(struct ib_uobject *uobj, u64 user_handle, 85219820Sjeff struct ib_ucontext *context, struct lock_class_key *key) 86219820Sjeff{ 87219820Sjeff uobj->user_handle = user_handle; 88219820Sjeff uobj->context = context; 89219820Sjeff kref_init(&uobj->ref); 90219820Sjeff init_rwsem(&uobj->mutex); 91219820Sjeff lockdep_set_class(&uobj->mutex, key); 92219820Sjeff uobj->live = 0; 93219820Sjeff} 94219820Sjeff 95219820Sjeffstatic void release_uobj(struct kref *kref) 96219820Sjeff{ 97219820Sjeff kfree(container_of(kref, struct ib_uobject, ref)); 98219820Sjeff} 99219820Sjeff 100219820Sjeffstatic void put_uobj(struct ib_uobject *uobj) 101219820Sjeff{ 102219820Sjeff kref_put(&uobj->ref, release_uobj); 103219820Sjeff} 104219820Sjeff 105219820Sjeffstatic void put_uobj_read(struct ib_uobject *uobj) 106219820Sjeff{ 107219820Sjeff up_read(&uobj->mutex); 108219820Sjeff put_uobj(uobj); 109219820Sjeff} 110219820Sjeff 111219820Sjeffstatic void put_uobj_write(struct ib_uobject *uobj) 112219820Sjeff{ 113219820Sjeff up_write(&uobj->mutex); 114219820Sjeff put_uobj(uobj); 115219820Sjeff} 116219820Sjeff 117219820Sjeffstatic int idr_add_uobj(struct idr *idr, struct ib_uobject *uobj) 118219820Sjeff{ 119219820Sjeff int ret; 120219820Sjeff 121219820Sjeffretry: 122219820Sjeff if (!idr_pre_get(idr, GFP_KERNEL)) 123219820Sjeff return -ENOMEM; 124219820Sjeff 125219820Sjeff spin_lock(&ib_uverbs_idr_lock); 126219820Sjeff ret = idr_get_new(idr, uobj, &uobj->id); 127219820Sjeff spin_unlock(&ib_uverbs_idr_lock); 128219820Sjeff 129219820Sjeff if (ret == -EAGAIN) 130219820Sjeff goto retry; 131219820Sjeff 132219820Sjeff return ret; 133219820Sjeff} 134219820Sjeff 135219820Sjeffvoid idr_remove_uobj(struct idr *idr, struct ib_uobject *uobj) 136219820Sjeff{ 137219820Sjeff spin_lock(&ib_uverbs_idr_lock); 138219820Sjeff idr_remove(idr, uobj->id); 139219820Sjeff spin_unlock(&ib_uverbs_idr_lock); 140219820Sjeff} 141219820Sjeff 142219820Sjeffstatic struct ib_uobject *__idr_get_uobj(struct idr *idr, int id, 143219820Sjeff struct ib_ucontext *context) 144219820Sjeff{ 145219820Sjeff struct ib_uobject *uobj; 146219820Sjeff 147219820Sjeff spin_lock(&ib_uverbs_idr_lock); 148219820Sjeff uobj = idr_find(idr, id); 149219820Sjeff if (uobj) { 150219820Sjeff if (uobj->context == context) 151219820Sjeff kref_get(&uobj->ref); 152219820Sjeff else 153219820Sjeff uobj = NULL; 154219820Sjeff } 155219820Sjeff spin_unlock(&ib_uverbs_idr_lock); 156219820Sjeff 157219820Sjeff return uobj; 158219820Sjeff} 159219820Sjeff 160219820Sjeffstatic struct ib_uobject *idr_read_uobj(struct idr *idr, int id, 161219820Sjeff struct ib_ucontext *context, int nested) 162219820Sjeff{ 163219820Sjeff struct ib_uobject *uobj; 164219820Sjeff 165219820Sjeff uobj = __idr_get_uobj(idr, id, context); 166219820Sjeff if (!uobj) 167219820Sjeff return NULL; 168219820Sjeff 169219820Sjeff if (nested) 170219820Sjeff down_read_nested(&uobj->mutex, SINGLE_DEPTH_NESTING); 171219820Sjeff else 172219820Sjeff down_read(&uobj->mutex); 173219820Sjeff if (!uobj->live) { 174219820Sjeff put_uobj_read(uobj); 175219820Sjeff return NULL; 176219820Sjeff } 177219820Sjeff 178219820Sjeff return uobj; 179219820Sjeff} 180219820Sjeff 181219820Sjeffstatic struct ib_uobject *idr_write_uobj(struct idr *idr, int id, 182219820Sjeff struct ib_ucontext *context) 183219820Sjeff{ 184219820Sjeff struct ib_uobject *uobj; 185219820Sjeff 186219820Sjeff uobj = __idr_get_uobj(idr, id, context); 187219820Sjeff if (!uobj) 188219820Sjeff return NULL; 189219820Sjeff 190219820Sjeff down_write(&uobj->mutex); 191219820Sjeff if (!uobj->live) { 192219820Sjeff put_uobj_write(uobj); 193219820Sjeff return NULL; 194219820Sjeff } 195219820Sjeff 196219820Sjeff return uobj; 197219820Sjeff} 198219820Sjeff 199219820Sjeffstatic void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context, 200219820Sjeff int nested) 201219820Sjeff{ 202219820Sjeff struct ib_uobject *uobj; 203219820Sjeff 204219820Sjeff uobj = idr_read_uobj(idr, id, context, nested); 205219820Sjeff return uobj ? uobj->object : NULL; 206219820Sjeff} 207219820Sjeff 208219820Sjeffstatic struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context) 209219820Sjeff{ 210219820Sjeff return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context, 0); 211219820Sjeff} 212219820Sjeff 213219820Sjeffstatic void put_pd_read(struct ib_pd *pd) 214219820Sjeff{ 215219820Sjeff put_uobj_read(pd->uobject); 216219820Sjeff} 217219820Sjeff 218219820Sjeffstatic struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context, int nested) 219219820Sjeff{ 220219820Sjeff return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context, nested); 221219820Sjeff} 222219820Sjeff 223219820Sjeffstatic void put_cq_read(struct ib_cq *cq) 224219820Sjeff{ 225219820Sjeff put_uobj_read(cq->uobject); 226219820Sjeff} 227219820Sjeff 228219820Sjeffstatic struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context) 229219820Sjeff{ 230219820Sjeff return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context, 0); 231219820Sjeff} 232219820Sjeff 233219820Sjeffstatic void put_ah_read(struct ib_ah *ah) 234219820Sjeff{ 235219820Sjeff put_uobj_read(ah->uobject); 236219820Sjeff} 237219820Sjeff 238219820Sjeffstatic struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context) 239219820Sjeff{ 240219820Sjeff return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0); 241219820Sjeff} 242219820Sjeff 243219820Sjeffstatic void put_qp_read(struct ib_qp *qp) 244219820Sjeff{ 245219820Sjeff put_uobj_read(qp->uobject); 246219820Sjeff} 247219820Sjeff 248219820Sjeffstatic struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context) 249219820Sjeff{ 250219820Sjeff return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context, 0); 251219820Sjeff} 252219820Sjeff 253219820Sjeffstatic void put_srq_read(struct ib_srq *srq) 254219820Sjeff{ 255219820Sjeff put_uobj_read(srq->uobject); 256219820Sjeff} 257219820Sjeff 258219820Sjeffstatic struct ib_xrcd *idr_read_xrcd(int xrcd_handle, 259219820Sjeff struct ib_ucontext *context, 260219820Sjeff struct ib_uobject **uobj) 261219820Sjeff{ 262219820Sjeff *uobj = idr_read_uobj(&ib_uverbs_xrc_domain_idr, xrcd_handle, 263219820Sjeff context, 0); 264219820Sjeff return *uobj ? (*uobj)->object : NULL; 265219820Sjeff} 266219820Sjeff 267219820Sjeffstatic void put_xrcd_read(struct ib_uobject *uobj) 268219820Sjeff{ 269219820Sjeff put_uobj_read(uobj); 270219820Sjeff} 271219820Sjeff 272219820Sjeffssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, 273219820Sjeff const char __user *buf, 274219820Sjeff int in_len, int out_len) 275219820Sjeff{ 276219820Sjeff struct ib_uverbs_get_context cmd; 277219820Sjeff struct ib_uverbs_get_context_resp resp; 278219820Sjeff struct ib_udata udata; 279219820Sjeff struct ib_device *ibdev = file->device->ib_dev; 280219820Sjeff struct ib_ucontext *ucontext; 281219820Sjeff struct file *filp; 282219820Sjeff int ret; 283219820Sjeff 284219820Sjeff if (out_len < sizeof resp) 285219820Sjeff return -ENOSPC; 286219820Sjeff 287219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 288219820Sjeff return -EFAULT; 289219820Sjeff 290219820Sjeff mutex_lock(&file->mutex); 291219820Sjeff 292219820Sjeff if (file->ucontext) { 293219820Sjeff ret = -EINVAL; 294219820Sjeff goto err; 295219820Sjeff } 296219820Sjeff 297219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, 298219820Sjeff (unsigned long) cmd.response + sizeof resp, 299219820Sjeff in_len - sizeof cmd, out_len - sizeof resp); 300219820Sjeff 301219820Sjeff ucontext = ibdev->alloc_ucontext(ibdev, &udata); 302219820Sjeff if (IS_ERR(ucontext)) { 303219820Sjeff ret = PTR_ERR(file->ucontext); 304219820Sjeff goto err; 305219820Sjeff } 306219820Sjeff 307219820Sjeff ucontext->device = ibdev; 308219820Sjeff INIT_LIST_HEAD(&ucontext->pd_list); 309219820Sjeff INIT_LIST_HEAD(&ucontext->mr_list); 310219820Sjeff INIT_LIST_HEAD(&ucontext->mw_list); 311219820Sjeff INIT_LIST_HEAD(&ucontext->cq_list); 312219820Sjeff INIT_LIST_HEAD(&ucontext->qp_list); 313219820Sjeff INIT_LIST_HEAD(&ucontext->srq_list); 314219820Sjeff INIT_LIST_HEAD(&ucontext->ah_list); 315255932Salfred INIT_LIST_HEAD(&ucontext->xrcd_list); 316219820Sjeff ucontext->closing = 0; 317219820Sjeff 318219820Sjeff resp.num_comp_vectors = file->device->num_comp_vectors; 319219820Sjeff 320219820Sjeff filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd); 321219820Sjeff if (IS_ERR(filp)) { 322219820Sjeff ret = PTR_ERR(filp); 323219820Sjeff goto err_free; 324219820Sjeff } 325219820Sjeff 326219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 327219820Sjeff &resp, sizeof resp)) { 328219820Sjeff ret = -EFAULT; 329219820Sjeff goto err_file; 330219820Sjeff } 331219820Sjeff 332219820Sjeff file->async_file = filp->private_data; 333219820Sjeff 334219820Sjeff INIT_IB_EVENT_HANDLER(&file->event_handler, file->device->ib_dev, 335219820Sjeff ib_uverbs_event_handler); 336219820Sjeff ret = ib_register_event_handler(&file->event_handler); 337219820Sjeff if (ret) 338219820Sjeff goto err_file; 339219820Sjeff 340219820Sjeff kref_get(&file->async_file->ref); 341219820Sjeff kref_get(&file->ref); 342219820Sjeff file->ucontext = ucontext; 343219820Sjeff 344219820Sjeff fd_install(resp.async_fd, filp); 345219820Sjeff 346219820Sjeff mutex_unlock(&file->mutex); 347219820Sjeff 348219820Sjeff return in_len; 349219820Sjeff 350219820Sjefferr_file: 351219820Sjeff put_unused_fd(resp.async_fd); 352219820Sjeff fput(filp); 353219820Sjeff 354219820Sjefferr_free: 355219820Sjeff ibdev->dealloc_ucontext(ucontext); 356219820Sjeff 357219820Sjefferr: 358219820Sjeff mutex_unlock(&file->mutex); 359219820Sjeff return ret; 360219820Sjeff} 361219820Sjeff 362219820Sjeffssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, 363219820Sjeff const char __user *buf, 364219820Sjeff int in_len, int out_len) 365219820Sjeff{ 366219820Sjeff struct ib_uverbs_query_device cmd; 367219820Sjeff struct ib_uverbs_query_device_resp resp; 368219820Sjeff struct ib_device_attr attr; 369219820Sjeff int ret; 370219820Sjeff 371219820Sjeff if (out_len < sizeof resp) 372219820Sjeff return -ENOSPC; 373219820Sjeff 374219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 375219820Sjeff return -EFAULT; 376219820Sjeff 377219820Sjeff ret = ib_query_device(file->device->ib_dev, &attr); 378219820Sjeff if (ret) 379219820Sjeff return ret; 380219820Sjeff 381219820Sjeff memset(&resp, 0, sizeof resp); 382219820Sjeff 383219820Sjeff resp.fw_ver = attr.fw_ver; 384219820Sjeff resp.node_guid = file->device->ib_dev->node_guid; 385219820Sjeff resp.sys_image_guid = attr.sys_image_guid; 386219820Sjeff resp.max_mr_size = attr.max_mr_size; 387219820Sjeff resp.page_size_cap = attr.page_size_cap; 388219820Sjeff resp.vendor_id = attr.vendor_id; 389219820Sjeff resp.vendor_part_id = attr.vendor_part_id; 390219820Sjeff resp.hw_ver = attr.hw_ver; 391219820Sjeff resp.max_qp = attr.max_qp; 392219820Sjeff resp.max_qp_wr = attr.max_qp_wr; 393219820Sjeff resp.device_cap_flags = attr.device_cap_flags; 394219820Sjeff resp.max_sge = attr.max_sge; 395219820Sjeff resp.max_sge_rd = attr.max_sge_rd; 396219820Sjeff resp.max_cq = attr.max_cq; 397219820Sjeff resp.max_cqe = attr.max_cqe; 398219820Sjeff resp.max_mr = attr.max_mr; 399219820Sjeff resp.max_pd = attr.max_pd; 400219820Sjeff resp.max_qp_rd_atom = attr.max_qp_rd_atom; 401219820Sjeff resp.max_ee_rd_atom = attr.max_ee_rd_atom; 402219820Sjeff resp.max_res_rd_atom = attr.max_res_rd_atom; 403219820Sjeff resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom; 404219820Sjeff resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom; 405219820Sjeff resp.atomic_cap = attr.atomic_cap; 406219820Sjeff resp.max_ee = attr.max_ee; 407219820Sjeff resp.max_rdd = attr.max_rdd; 408219820Sjeff resp.max_mw = attr.max_mw; 409219820Sjeff resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp; 410219820Sjeff resp.max_raw_ethy_qp = attr.max_raw_ethy_qp; 411219820Sjeff resp.max_mcast_grp = attr.max_mcast_grp; 412219820Sjeff resp.max_mcast_qp_attach = attr.max_mcast_qp_attach; 413219820Sjeff resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach; 414219820Sjeff resp.max_ah = attr.max_ah; 415219820Sjeff resp.max_fmr = attr.max_fmr; 416219820Sjeff resp.max_map_per_fmr = attr.max_map_per_fmr; 417219820Sjeff resp.max_srq = attr.max_srq; 418219820Sjeff resp.max_srq_wr = attr.max_srq_wr; 419219820Sjeff resp.max_srq_sge = attr.max_srq_sge; 420219820Sjeff resp.max_pkeys = attr.max_pkeys; 421219820Sjeff resp.local_ca_ack_delay = attr.local_ca_ack_delay; 422219820Sjeff resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt; 423219820Sjeff 424219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 425219820Sjeff &resp, sizeof resp)) 426219820Sjeff return -EFAULT; 427219820Sjeff 428219820Sjeff return in_len; 429219820Sjeff} 430219820Sjeff 431219820Sjeffssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, 432219820Sjeff const char __user *buf, 433219820Sjeff int in_len, int out_len) 434219820Sjeff{ 435219820Sjeff struct ib_uverbs_query_port cmd; 436219820Sjeff struct ib_uverbs_query_port_resp resp; 437219820Sjeff struct ib_port_attr attr; 438219820Sjeff int ret; 439219820Sjeff 440219820Sjeff if (out_len < sizeof resp) 441219820Sjeff return -ENOSPC; 442219820Sjeff 443219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 444219820Sjeff return -EFAULT; 445219820Sjeff 446219820Sjeff ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr); 447219820Sjeff if (ret) 448219820Sjeff return ret; 449219820Sjeff 450219820Sjeff memset(&resp, 0, sizeof resp); 451219820Sjeff 452219820Sjeff resp.state = attr.state; 453219820Sjeff resp.max_mtu = attr.max_mtu; 454219820Sjeff resp.active_mtu = attr.active_mtu; 455219820Sjeff resp.gid_tbl_len = attr.gid_tbl_len; 456219820Sjeff resp.port_cap_flags = attr.port_cap_flags; 457219820Sjeff resp.max_msg_sz = attr.max_msg_sz; 458219820Sjeff resp.bad_pkey_cntr = attr.bad_pkey_cntr; 459219820Sjeff resp.qkey_viol_cntr = attr.qkey_viol_cntr; 460219820Sjeff resp.pkey_tbl_len = attr.pkey_tbl_len; 461219820Sjeff resp.lid = attr.lid; 462219820Sjeff resp.sm_lid = attr.sm_lid; 463219820Sjeff resp.lmc = attr.lmc; 464219820Sjeff resp.max_vl_num = attr.max_vl_num; 465219820Sjeff resp.sm_sl = attr.sm_sl; 466219820Sjeff resp.subnet_timeout = attr.subnet_timeout; 467219820Sjeff resp.init_type_reply = attr.init_type_reply; 468219820Sjeff resp.active_width = attr.active_width; 469219820Sjeff resp.active_speed = attr.active_speed; 470219820Sjeff resp.phys_state = attr.phys_state; 471219820Sjeff resp.link_layer = attr.link_layer; 472219820Sjeff 473219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 474219820Sjeff &resp, sizeof resp)) 475219820Sjeff return -EFAULT; 476219820Sjeff 477219820Sjeff return in_len; 478219820Sjeff} 479219820Sjeff 480219820Sjeffssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, 481219820Sjeff const char __user *buf, 482219820Sjeff int in_len, int out_len) 483219820Sjeff{ 484219820Sjeff struct ib_uverbs_alloc_pd cmd; 485219820Sjeff struct ib_uverbs_alloc_pd_resp resp; 486219820Sjeff struct ib_udata udata; 487219820Sjeff struct ib_uobject *uobj; 488219820Sjeff struct ib_pd *pd; 489219820Sjeff int ret; 490219820Sjeff 491219820Sjeff if (out_len < sizeof resp) 492219820Sjeff return -ENOSPC; 493219820Sjeff 494219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 495219820Sjeff return -EFAULT; 496219820Sjeff 497219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, 498219820Sjeff (unsigned long) cmd.response + sizeof resp, 499219820Sjeff in_len - sizeof cmd, out_len - sizeof resp); 500219820Sjeff 501219820Sjeff uobj = kmalloc(sizeof *uobj, GFP_KERNEL); 502219820Sjeff if (!uobj) 503219820Sjeff return -ENOMEM; 504219820Sjeff 505219820Sjeff init_uobj(uobj, 0, file->ucontext, &pd_lock_key); 506219820Sjeff down_write(&uobj->mutex); 507219820Sjeff 508219820Sjeff pd = file->device->ib_dev->alloc_pd(file->device->ib_dev, 509219820Sjeff file->ucontext, &udata); 510219820Sjeff if (IS_ERR(pd)) { 511219820Sjeff ret = PTR_ERR(pd); 512219820Sjeff goto err; 513219820Sjeff } 514219820Sjeff 515219820Sjeff pd->device = file->device->ib_dev; 516219820Sjeff pd->uobject = uobj; 517219820Sjeff atomic_set(&pd->usecnt, 0); 518219820Sjeff 519219820Sjeff uobj->object = pd; 520219820Sjeff ret = idr_add_uobj(&ib_uverbs_pd_idr, uobj); 521219820Sjeff if (ret) 522219820Sjeff goto err_idr; 523219820Sjeff 524219820Sjeff memset(&resp, 0, sizeof resp); 525219820Sjeff resp.pd_handle = uobj->id; 526219820Sjeff 527219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 528219820Sjeff &resp, sizeof resp)) { 529219820Sjeff ret = -EFAULT; 530219820Sjeff goto err_copy; 531219820Sjeff } 532219820Sjeff 533219820Sjeff mutex_lock(&file->mutex); 534219820Sjeff list_add_tail(&uobj->list, &file->ucontext->pd_list); 535219820Sjeff mutex_unlock(&file->mutex); 536219820Sjeff 537219820Sjeff uobj->live = 1; 538219820Sjeff 539219820Sjeff up_write(&uobj->mutex); 540219820Sjeff 541219820Sjeff return in_len; 542219820Sjeff 543219820Sjefferr_copy: 544219820Sjeff idr_remove_uobj(&ib_uverbs_pd_idr, uobj); 545219820Sjeff 546219820Sjefferr_idr: 547219820Sjeff ib_dealloc_pd(pd); 548219820Sjeff 549219820Sjefferr: 550219820Sjeff put_uobj_write(uobj); 551219820Sjeff return ret; 552219820Sjeff} 553219820Sjeff 554219820Sjeffssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, 555219820Sjeff const char __user *buf, 556219820Sjeff int in_len, int out_len) 557219820Sjeff{ 558219820Sjeff struct ib_uverbs_dealloc_pd cmd; 559219820Sjeff struct ib_uobject *uobj; 560219820Sjeff int ret; 561219820Sjeff 562219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 563219820Sjeff return -EFAULT; 564219820Sjeff 565219820Sjeff uobj = idr_write_uobj(&ib_uverbs_pd_idr, cmd.pd_handle, file->ucontext); 566219820Sjeff if (!uobj) 567219820Sjeff return -EINVAL; 568219820Sjeff 569219820Sjeff ret = ib_dealloc_pd(uobj->object); 570219820Sjeff if (!ret) 571219820Sjeff uobj->live = 0; 572219820Sjeff 573219820Sjeff put_uobj_write(uobj); 574219820Sjeff 575219820Sjeff if (ret) 576219820Sjeff return ret; 577219820Sjeff 578219820Sjeff idr_remove_uobj(&ib_uverbs_pd_idr, uobj); 579219820Sjeff 580219820Sjeff mutex_lock(&file->mutex); 581219820Sjeff list_del(&uobj->list); 582219820Sjeff mutex_unlock(&file->mutex); 583219820Sjeff 584219820Sjeff put_uobj(uobj); 585219820Sjeff 586219820Sjeff return in_len; 587219820Sjeff} 588219820Sjeff 589219820Sjeffssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, 590219820Sjeff const char __user *buf, int in_len, 591219820Sjeff int out_len) 592219820Sjeff{ 593219820Sjeff struct ib_uverbs_reg_mr cmd; 594219820Sjeff struct ib_uverbs_reg_mr_resp resp; 595219820Sjeff struct ib_udata udata; 596219820Sjeff struct ib_uobject *uobj; 597219820Sjeff struct ib_pd *pd; 598219820Sjeff struct ib_mr *mr; 599219820Sjeff int ret; 600219820Sjeff 601219820Sjeff if (out_len < sizeof resp) 602219820Sjeff return -ENOSPC; 603219820Sjeff 604219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 605219820Sjeff return -EFAULT; 606219820Sjeff 607219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, 608219820Sjeff (unsigned long) cmd.response + sizeof resp, 609219820Sjeff in_len - sizeof cmd, out_len - sizeof resp); 610219820Sjeff 611219820Sjeff if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK)) 612219820Sjeff return -EINVAL; 613219820Sjeff 614219820Sjeff /* 615219820Sjeff * Local write permission is required if remote write or 616219820Sjeff * remote atomic permission is also requested. 617219820Sjeff */ 618219820Sjeff if (cmd.access_flags & (IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_REMOTE_WRITE) && 619219820Sjeff !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE)) 620219820Sjeff return -EINVAL; 621219820Sjeff 622219820Sjeff uobj = kmalloc(sizeof *uobj, GFP_KERNEL); 623219820Sjeff if (!uobj) 624219820Sjeff return -ENOMEM; 625219820Sjeff 626219820Sjeff init_uobj(uobj, 0, file->ucontext, &mr_lock_key); 627219820Sjeff down_write(&uobj->mutex); 628219820Sjeff 629219820Sjeff pd = idr_read_pd(cmd.pd_handle, file->ucontext); 630219820Sjeff if (!pd) { 631219820Sjeff ret = -EINVAL; 632219820Sjeff goto err_free; 633219820Sjeff } 634219820Sjeff 635219820Sjeff mr = pd->device->reg_user_mr(pd, cmd.start, cmd.length, cmd.hca_va, 636255932Salfred cmd.access_flags, &udata, 0); 637219820Sjeff if (IS_ERR(mr)) { 638219820Sjeff ret = PTR_ERR(mr); 639219820Sjeff goto err_put; 640219820Sjeff } 641219820Sjeff 642219820Sjeff mr->device = pd->device; 643219820Sjeff mr->pd = pd; 644219820Sjeff mr->uobject = uobj; 645219820Sjeff atomic_inc(&pd->usecnt); 646219820Sjeff atomic_set(&mr->usecnt, 0); 647219820Sjeff 648219820Sjeff uobj->object = mr; 649219820Sjeff ret = idr_add_uobj(&ib_uverbs_mr_idr, uobj); 650219820Sjeff if (ret) 651219820Sjeff goto err_unreg; 652219820Sjeff 653219820Sjeff memset(&resp, 0, sizeof resp); 654219820Sjeff resp.lkey = mr->lkey; 655219820Sjeff resp.rkey = mr->rkey; 656219820Sjeff resp.mr_handle = uobj->id; 657219820Sjeff 658219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 659219820Sjeff &resp, sizeof resp)) { 660219820Sjeff ret = -EFAULT; 661219820Sjeff goto err_copy; 662219820Sjeff } 663219820Sjeff 664219820Sjeff put_pd_read(pd); 665219820Sjeff 666219820Sjeff mutex_lock(&file->mutex); 667219820Sjeff list_add_tail(&uobj->list, &file->ucontext->mr_list); 668219820Sjeff mutex_unlock(&file->mutex); 669219820Sjeff 670219820Sjeff uobj->live = 1; 671219820Sjeff 672219820Sjeff up_write(&uobj->mutex); 673219820Sjeff 674219820Sjeff return in_len; 675219820Sjeff 676219820Sjefferr_copy: 677219820Sjeff idr_remove_uobj(&ib_uverbs_mr_idr, uobj); 678219820Sjeff 679219820Sjefferr_unreg: 680219820Sjeff ib_dereg_mr(mr); 681219820Sjeff 682219820Sjefferr_put: 683219820Sjeff put_pd_read(pd); 684219820Sjeff 685219820Sjefferr_free: 686219820Sjeff put_uobj_write(uobj); 687219820Sjeff return ret; 688219820Sjeff} 689219820Sjeff 690219820Sjeffssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, 691219820Sjeff const char __user *buf, int in_len, 692219820Sjeff int out_len) 693219820Sjeff{ 694219820Sjeff struct ib_uverbs_dereg_mr cmd; 695219820Sjeff struct ib_mr *mr; 696219820Sjeff struct ib_uobject *uobj; 697219820Sjeff int ret = -EINVAL; 698219820Sjeff 699219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 700219820Sjeff return -EFAULT; 701219820Sjeff 702219820Sjeff uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle, file->ucontext); 703219820Sjeff if (!uobj) 704219820Sjeff return -EINVAL; 705219820Sjeff 706219820Sjeff mr = uobj->object; 707219820Sjeff 708219820Sjeff ret = ib_dereg_mr(mr); 709219820Sjeff if (!ret) 710219820Sjeff uobj->live = 0; 711219820Sjeff 712219820Sjeff put_uobj_write(uobj); 713219820Sjeff 714219820Sjeff if (ret) 715219820Sjeff return ret; 716219820Sjeff 717219820Sjeff idr_remove_uobj(&ib_uverbs_mr_idr, uobj); 718219820Sjeff 719219820Sjeff mutex_lock(&file->mutex); 720219820Sjeff list_del(&uobj->list); 721219820Sjeff mutex_unlock(&file->mutex); 722219820Sjeff 723219820Sjeff put_uobj(uobj); 724219820Sjeff 725219820Sjeff return in_len; 726219820Sjeff} 727219820Sjeff 728219820Sjeffssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, 729219820Sjeff const char __user *buf, int in_len, 730219820Sjeff int out_len) 731219820Sjeff{ 732219820Sjeff struct ib_uverbs_create_comp_channel cmd; 733219820Sjeff struct ib_uverbs_create_comp_channel_resp resp; 734219820Sjeff struct file *filp; 735219820Sjeff 736219820Sjeff if (out_len < sizeof resp) 737219820Sjeff return -ENOSPC; 738219820Sjeff 739219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 740219820Sjeff return -EFAULT; 741219820Sjeff 742219820Sjeff filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd); 743219820Sjeff if (IS_ERR(filp)) 744219820Sjeff return PTR_ERR(filp); 745219820Sjeff 746219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 747219820Sjeff &resp, sizeof resp)) { 748219820Sjeff put_unused_fd(resp.fd); 749219820Sjeff fput(filp); 750219820Sjeff return -EFAULT; 751219820Sjeff } 752219820Sjeff 753219820Sjeff fd_install(resp.fd, filp); 754219820Sjeff return in_len; 755219820Sjeff} 756219820Sjeff 757219820Sjeffssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, 758219820Sjeff const char __user *buf, int in_len, 759219820Sjeff int out_len) 760219820Sjeff{ 761219820Sjeff struct ib_uverbs_create_cq cmd; 762219820Sjeff struct ib_uverbs_create_cq_resp resp; 763219820Sjeff struct ib_udata udata; 764219820Sjeff struct ib_ucq_object *obj; 765219820Sjeff struct ib_uverbs_event_file *ev_file = NULL; 766219820Sjeff struct ib_cq *cq; 767219820Sjeff int ret; 768219820Sjeff 769219820Sjeff if (out_len < sizeof resp) 770219820Sjeff return -ENOSPC; 771219820Sjeff 772219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 773219820Sjeff return -EFAULT; 774219820Sjeff 775219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, 776219820Sjeff (unsigned long) cmd.response + sizeof resp, 777219820Sjeff in_len - sizeof cmd, out_len - sizeof resp); 778219820Sjeff 779219820Sjeff if (cmd.comp_vector >= file->device->num_comp_vectors) 780219820Sjeff return -EINVAL; 781219820Sjeff 782219820Sjeff obj = kmalloc(sizeof *obj, GFP_KERNEL); 783219820Sjeff if (!obj) 784219820Sjeff return -ENOMEM; 785219820Sjeff 786219820Sjeff init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &cq_lock_key); 787219820Sjeff down_write(&obj->uobject.mutex); 788219820Sjeff 789219820Sjeff if (cmd.comp_channel >= 0) { 790219820Sjeff ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); 791219820Sjeff if (!ev_file) { 792219820Sjeff ret = -EINVAL; 793219820Sjeff goto err; 794219820Sjeff } 795219820Sjeff } 796219820Sjeff 797219820Sjeff obj->uverbs_file = file; 798219820Sjeff obj->comp_events_reported = 0; 799219820Sjeff obj->async_events_reported = 0; 800219820Sjeff INIT_LIST_HEAD(&obj->comp_list); 801219820Sjeff INIT_LIST_HEAD(&obj->async_list); 802219820Sjeff 803219820Sjeff cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, 804219820Sjeff cmd.comp_vector, 805219820Sjeff file->ucontext, &udata); 806219820Sjeff if (IS_ERR(cq)) { 807219820Sjeff ret = PTR_ERR(cq); 808219820Sjeff goto err_file; 809219820Sjeff } 810219820Sjeff 811219820Sjeff cq->device = file->device->ib_dev; 812219820Sjeff cq->uobject = &obj->uobject; 813219820Sjeff cq->comp_handler = ib_uverbs_comp_handler; 814219820Sjeff cq->event_handler = ib_uverbs_cq_event_handler; 815219820Sjeff cq->cq_context = ev_file; 816219820Sjeff atomic_set(&cq->usecnt, 0); 817219820Sjeff 818219820Sjeff obj->uobject.object = cq; 819219820Sjeff ret = idr_add_uobj(&ib_uverbs_cq_idr, &obj->uobject); 820219820Sjeff if (ret) 821219820Sjeff goto err_free; 822219820Sjeff 823219820Sjeff memset(&resp, 0, sizeof resp); 824219820Sjeff resp.cq_handle = obj->uobject.id; 825219820Sjeff resp.cqe = cq->cqe; 826219820Sjeff 827219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 828219820Sjeff &resp, sizeof resp)) { 829219820Sjeff ret = -EFAULT; 830219820Sjeff goto err_copy; 831219820Sjeff } 832219820Sjeff 833219820Sjeff mutex_lock(&file->mutex); 834219820Sjeff list_add_tail(&obj->uobject.list, &file->ucontext->cq_list); 835219820Sjeff mutex_unlock(&file->mutex); 836219820Sjeff 837219820Sjeff obj->uobject.live = 1; 838219820Sjeff 839219820Sjeff up_write(&obj->uobject.mutex); 840219820Sjeff 841219820Sjeff return in_len; 842219820Sjeff 843219820Sjefferr_copy: 844219820Sjeff idr_remove_uobj(&ib_uverbs_cq_idr, &obj->uobject); 845219820Sjeff 846219820Sjefferr_free: 847219820Sjeff ib_destroy_cq(cq); 848219820Sjeff 849219820Sjefferr_file: 850219820Sjeff if (ev_file) 851219820Sjeff ib_uverbs_release_ucq(file, ev_file, obj); 852219820Sjeff 853219820Sjefferr: 854219820Sjeff put_uobj_write(&obj->uobject); 855219820Sjeff return ret; 856219820Sjeff} 857219820Sjeff 858219820Sjeffssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file, 859219820Sjeff const char __user *buf, int in_len, 860219820Sjeff int out_len) 861219820Sjeff{ 862219820Sjeff struct ib_uverbs_resize_cq cmd; 863219820Sjeff struct ib_uverbs_resize_cq_resp resp; 864219820Sjeff struct ib_udata udata; 865219820Sjeff struct ib_cq *cq; 866219820Sjeff int ret = -EINVAL; 867219820Sjeff 868219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 869219820Sjeff return -EFAULT; 870219820Sjeff 871219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, 872219820Sjeff (unsigned long) cmd.response + sizeof resp, 873219820Sjeff in_len - sizeof cmd, out_len - sizeof resp); 874219820Sjeff 875219820Sjeff cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0); 876219820Sjeff if (!cq) 877219820Sjeff return -EINVAL; 878219820Sjeff 879219820Sjeff ret = cq->device->resize_cq(cq, cmd.cqe, &udata); 880219820Sjeff if (ret) 881219820Sjeff goto out; 882219820Sjeff 883219820Sjeff resp.cqe = cq->cqe; 884219820Sjeff 885219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 886219820Sjeff &resp, sizeof resp.cqe)) 887219820Sjeff ret = -EFAULT; 888219820Sjeff 889219820Sjeffout: 890219820Sjeff put_cq_read(cq); 891219820Sjeff 892219820Sjeff return ret ? ret : in_len; 893219820Sjeff} 894219820Sjeff 895219820Sjeffssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, 896219820Sjeff const char __user *buf, int in_len, 897219820Sjeff int out_len) 898219820Sjeff{ 899219820Sjeff struct ib_uverbs_poll_cq cmd; 900219820Sjeff struct ib_uverbs_poll_cq_resp *resp; 901219820Sjeff struct ib_cq *cq; 902219820Sjeff struct ib_wc *wc; 903219820Sjeff int ret = 0; 904219820Sjeff int i; 905219820Sjeff int rsize; 906219820Sjeff 907219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 908219820Sjeff return -EFAULT; 909219820Sjeff 910219820Sjeff wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL); 911219820Sjeff if (!wc) 912219820Sjeff return -ENOMEM; 913219820Sjeff 914219820Sjeff rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc); 915219820Sjeff resp = kmalloc(rsize, GFP_KERNEL); 916219820Sjeff if (!resp) { 917219820Sjeff ret = -ENOMEM; 918219820Sjeff goto out_wc; 919219820Sjeff } 920219820Sjeff 921219820Sjeff cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0); 922219820Sjeff if (!cq) { 923219820Sjeff ret = -EINVAL; 924219820Sjeff goto out; 925219820Sjeff } 926219820Sjeff 927219820Sjeff resp->count = ib_poll_cq(cq, cmd.ne, wc); 928219820Sjeff 929219820Sjeff put_cq_read(cq); 930219820Sjeff 931219820Sjeff for (i = 0; i < resp->count; i++) { 932219820Sjeff resp->wc[i].wr_id = wc[i].wr_id; 933219820Sjeff resp->wc[i].status = wc[i].status; 934219820Sjeff resp->wc[i].opcode = wc[i].opcode; 935219820Sjeff resp->wc[i].vendor_err = wc[i].vendor_err; 936219820Sjeff resp->wc[i].byte_len = wc[i].byte_len; 937219820Sjeff resp->wc[i].ex.imm_data = (__u32 __force) wc[i].ex.imm_data; 938219820Sjeff resp->wc[i].qp_num = wc[i].qp->qp_num; 939219820Sjeff resp->wc[i].src_qp = wc[i].src_qp; 940219820Sjeff resp->wc[i].wc_flags = wc[i].wc_flags; 941219820Sjeff resp->wc[i].pkey_index = wc[i].pkey_index; 942219820Sjeff resp->wc[i].slid = wc[i].slid; 943219820Sjeff resp->wc[i].sl = wc[i].sl; 944219820Sjeff resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits; 945219820Sjeff resp->wc[i].port_num = wc[i].port_num; 946219820Sjeff } 947219820Sjeff 948219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize)) 949219820Sjeff ret = -EFAULT; 950219820Sjeff 951219820Sjeffout: 952219820Sjeff kfree(resp); 953219820Sjeff 954219820Sjeffout_wc: 955219820Sjeff kfree(wc); 956219820Sjeff return ret ? ret : in_len; 957219820Sjeff} 958219820Sjeff 959219820Sjeffssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, 960219820Sjeff const char __user *buf, int in_len, 961219820Sjeff int out_len) 962219820Sjeff{ 963219820Sjeff struct ib_uverbs_req_notify_cq cmd; 964219820Sjeff struct ib_cq *cq; 965219820Sjeff 966219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 967219820Sjeff return -EFAULT; 968219820Sjeff 969219820Sjeff cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0); 970219820Sjeff if (!cq) 971219820Sjeff return -EINVAL; 972219820Sjeff 973219820Sjeff ib_req_notify_cq(cq, cmd.solicited_only ? 974219820Sjeff IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); 975219820Sjeff 976219820Sjeff put_cq_read(cq); 977219820Sjeff 978219820Sjeff return in_len; 979219820Sjeff} 980219820Sjeff 981219820Sjeffssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, 982219820Sjeff const char __user *buf, int in_len, 983219820Sjeff int out_len) 984219820Sjeff{ 985219820Sjeff struct ib_uverbs_destroy_cq cmd; 986219820Sjeff struct ib_uverbs_destroy_cq_resp resp; 987219820Sjeff struct ib_uobject *uobj; 988219820Sjeff struct ib_cq *cq; 989219820Sjeff struct ib_ucq_object *obj; 990219820Sjeff struct ib_uverbs_event_file *ev_file; 991219820Sjeff int ret = -EINVAL; 992219820Sjeff 993219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 994219820Sjeff return -EFAULT; 995219820Sjeff 996219820Sjeff uobj = idr_write_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext); 997219820Sjeff if (!uobj) 998219820Sjeff return -EINVAL; 999219820Sjeff cq = uobj->object; 1000219820Sjeff ev_file = cq->cq_context; 1001219820Sjeff obj = container_of(cq->uobject, struct ib_ucq_object, uobject); 1002219820Sjeff 1003219820Sjeff ret = ib_destroy_cq(cq); 1004219820Sjeff if (!ret) 1005219820Sjeff uobj->live = 0; 1006219820Sjeff 1007219820Sjeff put_uobj_write(uobj); 1008219820Sjeff 1009219820Sjeff if (ret) 1010219820Sjeff return ret; 1011219820Sjeff 1012219820Sjeff idr_remove_uobj(&ib_uverbs_cq_idr, uobj); 1013219820Sjeff 1014219820Sjeff mutex_lock(&file->mutex); 1015219820Sjeff list_del(&uobj->list); 1016219820Sjeff mutex_unlock(&file->mutex); 1017219820Sjeff 1018219820Sjeff ib_uverbs_release_ucq(file, ev_file, obj); 1019219820Sjeff 1020219820Sjeff memset(&resp, 0, sizeof resp); 1021219820Sjeff resp.comp_events_reported = obj->comp_events_reported; 1022219820Sjeff resp.async_events_reported = obj->async_events_reported; 1023219820Sjeff 1024219820Sjeff put_uobj(uobj); 1025219820Sjeff 1026219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 1027219820Sjeff &resp, sizeof resp)) 1028219820Sjeff return -EFAULT; 1029219820Sjeff 1030219820Sjeff return in_len; 1031219820Sjeff} 1032219820Sjeff 1033219820Sjeffssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, 1034219820Sjeff const char __user *buf, int in_len, 1035219820Sjeff int out_len) 1036219820Sjeff{ 1037219820Sjeff struct ib_uverbs_create_qp cmd; 1038219820Sjeff struct ib_uverbs_create_qp_resp resp; 1039219820Sjeff struct ib_udata udata; 1040219820Sjeff struct ib_uqp_object *obj; 1041219820Sjeff struct ib_pd *pd; 1042219820Sjeff struct ib_cq *scq, *rcq; 1043219820Sjeff struct ib_srq *srq; 1044219820Sjeff struct ib_qp *qp; 1045219820Sjeff struct ib_qp_init_attr attr; 1046219820Sjeff struct ib_xrcd *xrcd; 1047219820Sjeff struct ib_uobject *xrcd_uobj; 1048219820Sjeff int ret; 1049219820Sjeff 1050219820Sjeff if (out_len < sizeof resp) 1051219820Sjeff return -ENOSPC; 1052219820Sjeff 1053219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1054219820Sjeff return -EFAULT; 1055219820Sjeff 1056219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, 1057219820Sjeff (unsigned long) cmd.response + sizeof resp, 1058219820Sjeff in_len - sizeof cmd, out_len - sizeof resp); 1059219820Sjeff 1060219820Sjeff obj = kmalloc(sizeof *obj, GFP_KERNEL); 1061219820Sjeff if (!obj) 1062219820Sjeff return -ENOMEM; 1063219820Sjeff 1064219820Sjeff init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_key); 1065219820Sjeff down_write(&obj->uevent.uobject.mutex); 1066219820Sjeff 1067219820Sjeff srq = (cmd.is_srq && cmd.qp_type != IB_QPT_XRC) ? 1068219820Sjeff idr_read_srq(cmd.srq_handle, file->ucontext) : NULL; 1069219820Sjeff xrcd = cmd.qp_type == IB_QPT_XRC ? 1070219820Sjeff idr_read_xrcd(cmd.srq_handle, file->ucontext, &xrcd_uobj) : NULL; 1071219820Sjeff pd = idr_read_pd(cmd.pd_handle, file->ucontext); 1072219820Sjeff scq = idr_read_cq(cmd.send_cq_handle, file->ucontext, 0); 1073219820Sjeff rcq = cmd.recv_cq_handle == cmd.send_cq_handle ? 1074219820Sjeff scq : idr_read_cq(cmd.recv_cq_handle, file->ucontext, 1); 1075219820Sjeff 1076219820Sjeff if (!pd || !scq || !rcq || (cmd.is_srq && !srq) || 1077219820Sjeff (cmd.qp_type == IB_QPT_XRC && !xrcd)) { 1078219820Sjeff ret = -EINVAL; 1079219820Sjeff goto err_put; 1080219820Sjeff } 1081219820Sjeff 1082219820Sjeff attr.create_flags = 0; 1083219820Sjeff attr.event_handler = ib_uverbs_qp_event_handler; 1084219820Sjeff attr.qp_context = file; 1085219820Sjeff attr.send_cq = scq; 1086219820Sjeff attr.recv_cq = rcq; 1087219820Sjeff attr.srq = srq; 1088219820Sjeff attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; 1089219820Sjeff attr.qp_type = cmd.qp_type; 1090255932Salfred attr.xrcd = xrcd; 1091219820Sjeff attr.create_flags = 0; 1092219820Sjeff 1093219820Sjeff attr.cap.max_send_wr = cmd.max_send_wr; 1094219820Sjeff attr.cap.max_recv_wr = cmd.max_recv_wr; 1095219820Sjeff attr.cap.max_send_sge = cmd.max_send_sge; 1096219820Sjeff attr.cap.max_recv_sge = cmd.max_recv_sge; 1097219820Sjeff attr.cap.max_inline_data = cmd.max_inline_data; 1098219820Sjeff 1099219820Sjeff obj->uevent.events_reported = 0; 1100219820Sjeff INIT_LIST_HEAD(&obj->uevent.event_list); 1101219820Sjeff INIT_LIST_HEAD(&obj->mcast_list); 1102219820Sjeff 1103219820Sjeff qp = pd->device->create_qp(pd, &attr, &udata); 1104219820Sjeff if (IS_ERR(qp)) { 1105219820Sjeff ret = PTR_ERR(qp); 1106219820Sjeff goto err_put; 1107219820Sjeff } 1108219820Sjeff 1109219820Sjeff qp->device = pd->device; 1110219820Sjeff qp->pd = pd; 1111219820Sjeff qp->send_cq = attr.send_cq; 1112219820Sjeff qp->recv_cq = attr.recv_cq; 1113219820Sjeff qp->srq = attr.srq; 1114219820Sjeff qp->uobject = &obj->uevent.uobject; 1115219820Sjeff qp->event_handler = attr.event_handler; 1116219820Sjeff qp->qp_context = attr.qp_context; 1117219820Sjeff qp->qp_type = attr.qp_type; 1118255932Salfred qp->xrcd = attr.xrcd; 1119219820Sjeff atomic_inc(&pd->usecnt); 1120219820Sjeff atomic_inc(&attr.send_cq->usecnt); 1121219820Sjeff atomic_inc(&attr.recv_cq->usecnt); 1122219820Sjeff if (attr.srq) 1123219820Sjeff atomic_inc(&attr.srq->usecnt); 1124255932Salfred else if (attr.xrcd) 1125255932Salfred atomic_inc(&attr.xrcd->usecnt); 1126219820Sjeff 1127219820Sjeff obj->uevent.uobject.object = qp; 1128219820Sjeff ret = idr_add_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject); 1129219820Sjeff if (ret) 1130219820Sjeff goto err_destroy; 1131219820Sjeff 1132219820Sjeff memset(&resp, 0, sizeof resp); 1133219820Sjeff resp.qpn = qp->qp_num; 1134219820Sjeff resp.qp_handle = obj->uevent.uobject.id; 1135219820Sjeff resp.max_recv_sge = attr.cap.max_recv_sge; 1136219820Sjeff resp.max_send_sge = attr.cap.max_send_sge; 1137219820Sjeff resp.max_recv_wr = attr.cap.max_recv_wr; 1138219820Sjeff resp.max_send_wr = attr.cap.max_send_wr; 1139219820Sjeff resp.max_inline_data = attr.cap.max_inline_data; 1140219820Sjeff 1141219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 1142219820Sjeff &resp, sizeof resp)) { 1143219820Sjeff ret = -EFAULT; 1144219820Sjeff goto err_copy; 1145219820Sjeff } 1146219820Sjeff 1147219820Sjeff put_pd_read(pd); 1148219820Sjeff put_cq_read(scq); 1149219820Sjeff if (rcq != scq) 1150219820Sjeff put_cq_read(rcq); 1151219820Sjeff if (srq) 1152219820Sjeff put_srq_read(srq); 1153219820Sjeff if (xrcd) 1154219820Sjeff put_xrcd_read(xrcd_uobj); 1155219820Sjeff 1156219820Sjeff mutex_lock(&file->mutex); 1157219820Sjeff list_add_tail(&obj->uevent.uobject.list, &file->ucontext->qp_list); 1158219820Sjeff mutex_unlock(&file->mutex); 1159219820Sjeff 1160219820Sjeff obj->uevent.uobject.live = 1; 1161219820Sjeff 1162219820Sjeff up_write(&obj->uevent.uobject.mutex); 1163219820Sjeff 1164219820Sjeff return in_len; 1165219820Sjeff 1166219820Sjefferr_copy: 1167219820Sjeff idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject); 1168219820Sjeff 1169219820Sjefferr_destroy: 1170219820Sjeff ib_destroy_qp(qp); 1171219820Sjeff 1172219820Sjefferr_put: 1173219820Sjeff if (pd) 1174219820Sjeff put_pd_read(pd); 1175219820Sjeff if (scq) 1176219820Sjeff put_cq_read(scq); 1177219820Sjeff if (rcq && rcq != scq) 1178219820Sjeff put_cq_read(rcq); 1179219820Sjeff if (srq) 1180219820Sjeff put_srq_read(srq); 1181219820Sjeff if (xrcd) 1182219820Sjeff put_xrcd_read(xrcd_uobj); 1183219820Sjeff 1184219820Sjeff put_uobj_write(&obj->uevent.uobject); 1185219820Sjeff return ret; 1186219820Sjeff} 1187219820Sjeff 1188219820Sjeffssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file, 1189219820Sjeff const char __user *buf, int in_len, 1190219820Sjeff int out_len) 1191219820Sjeff{ 1192219820Sjeff struct ib_uverbs_query_qp cmd; 1193219820Sjeff struct ib_uverbs_query_qp_resp resp; 1194219820Sjeff struct ib_qp *qp; 1195219820Sjeff struct ib_qp_attr *attr; 1196219820Sjeff struct ib_qp_init_attr *init_attr; 1197219820Sjeff int ret; 1198219820Sjeff 1199219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1200219820Sjeff return -EFAULT; 1201219820Sjeff 1202219820Sjeff attr = kmalloc(sizeof *attr, GFP_KERNEL); 1203219820Sjeff init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL); 1204219820Sjeff if (!attr || !init_attr) { 1205219820Sjeff ret = -ENOMEM; 1206219820Sjeff goto out; 1207219820Sjeff } 1208219820Sjeff 1209219820Sjeff qp = idr_read_qp(cmd.qp_handle, file->ucontext); 1210219820Sjeff if (!qp) { 1211219820Sjeff ret = -EINVAL; 1212219820Sjeff goto out; 1213219820Sjeff } 1214219820Sjeff 1215219820Sjeff ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr); 1216219820Sjeff 1217219820Sjeff put_qp_read(qp); 1218219820Sjeff 1219219820Sjeff if (ret) 1220219820Sjeff goto out; 1221219820Sjeff 1222219820Sjeff memset(&resp, 0, sizeof resp); 1223219820Sjeff 1224219820Sjeff resp.qp_state = attr->qp_state; 1225219820Sjeff resp.cur_qp_state = attr->cur_qp_state; 1226219820Sjeff resp.path_mtu = attr->path_mtu; 1227219820Sjeff resp.path_mig_state = attr->path_mig_state; 1228219820Sjeff resp.qkey = attr->qkey; 1229219820Sjeff resp.rq_psn = attr->rq_psn; 1230219820Sjeff resp.sq_psn = attr->sq_psn; 1231219820Sjeff resp.dest_qp_num = attr->dest_qp_num; 1232219820Sjeff resp.qp_access_flags = attr->qp_access_flags; 1233219820Sjeff resp.pkey_index = attr->pkey_index; 1234219820Sjeff resp.alt_pkey_index = attr->alt_pkey_index; 1235219820Sjeff resp.sq_draining = attr->sq_draining; 1236219820Sjeff resp.max_rd_atomic = attr->max_rd_atomic; 1237219820Sjeff resp.max_dest_rd_atomic = attr->max_dest_rd_atomic; 1238219820Sjeff resp.min_rnr_timer = attr->min_rnr_timer; 1239219820Sjeff resp.port_num = attr->port_num; 1240219820Sjeff resp.timeout = attr->timeout; 1241219820Sjeff resp.retry_cnt = attr->retry_cnt; 1242219820Sjeff resp.rnr_retry = attr->rnr_retry; 1243219820Sjeff resp.alt_port_num = attr->alt_port_num; 1244219820Sjeff resp.alt_timeout = attr->alt_timeout; 1245219820Sjeff 1246219820Sjeff memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16); 1247219820Sjeff resp.dest.flow_label = attr->ah_attr.grh.flow_label; 1248219820Sjeff resp.dest.sgid_index = attr->ah_attr.grh.sgid_index; 1249219820Sjeff resp.dest.hop_limit = attr->ah_attr.grh.hop_limit; 1250219820Sjeff resp.dest.traffic_class = attr->ah_attr.grh.traffic_class; 1251219820Sjeff resp.dest.dlid = attr->ah_attr.dlid; 1252219820Sjeff resp.dest.sl = attr->ah_attr.sl; 1253219820Sjeff resp.dest.src_path_bits = attr->ah_attr.src_path_bits; 1254219820Sjeff resp.dest.static_rate = attr->ah_attr.static_rate; 1255219820Sjeff resp.dest.is_global = !!(attr->ah_attr.ah_flags & IB_AH_GRH); 1256219820Sjeff resp.dest.port_num = attr->ah_attr.port_num; 1257219820Sjeff 1258219820Sjeff memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16); 1259219820Sjeff resp.alt_dest.flow_label = attr->alt_ah_attr.grh.flow_label; 1260219820Sjeff resp.alt_dest.sgid_index = attr->alt_ah_attr.grh.sgid_index; 1261219820Sjeff resp.alt_dest.hop_limit = attr->alt_ah_attr.grh.hop_limit; 1262219820Sjeff resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class; 1263219820Sjeff resp.alt_dest.dlid = attr->alt_ah_attr.dlid; 1264219820Sjeff resp.alt_dest.sl = attr->alt_ah_attr.sl; 1265219820Sjeff resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits; 1266219820Sjeff resp.alt_dest.static_rate = attr->alt_ah_attr.static_rate; 1267219820Sjeff resp.alt_dest.is_global = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH); 1268219820Sjeff resp.alt_dest.port_num = attr->alt_ah_attr.port_num; 1269219820Sjeff 1270219820Sjeff resp.max_send_wr = init_attr->cap.max_send_wr; 1271219820Sjeff resp.max_recv_wr = init_attr->cap.max_recv_wr; 1272219820Sjeff resp.max_send_sge = init_attr->cap.max_send_sge; 1273219820Sjeff resp.max_recv_sge = init_attr->cap.max_recv_sge; 1274219820Sjeff resp.max_inline_data = init_attr->cap.max_inline_data; 1275219820Sjeff resp.sq_sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR; 1276219820Sjeff 1277219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 1278219820Sjeff &resp, sizeof resp)) 1279219820Sjeff ret = -EFAULT; 1280219820Sjeff 1281219820Sjeffout: 1282219820Sjeff kfree(attr); 1283219820Sjeff kfree(init_attr); 1284219820Sjeff 1285219820Sjeff return ret ? ret : in_len; 1286219820Sjeff} 1287219820Sjeff 1288219820Sjeffssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, 1289219820Sjeff const char __user *buf, int in_len, 1290219820Sjeff int out_len) 1291219820Sjeff{ 1292219820Sjeff struct ib_uverbs_modify_qp cmd; 1293219820Sjeff struct ib_udata udata; 1294219820Sjeff struct ib_qp *qp; 1295219820Sjeff struct ib_qp_attr *attr; 1296219820Sjeff int ret; 1297219820Sjeff 1298219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1299219820Sjeff return -EFAULT; 1300219820Sjeff 1301219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd, 1302219820Sjeff out_len); 1303219820Sjeff 1304219820Sjeff attr = kmalloc(sizeof *attr, GFP_KERNEL); 1305219820Sjeff if (!attr) 1306219820Sjeff return -ENOMEM; 1307219820Sjeff 1308219820Sjeff qp = idr_read_qp(cmd.qp_handle, file->ucontext); 1309219820Sjeff if (!qp) { 1310219820Sjeff ret = -EINVAL; 1311219820Sjeff goto out; 1312219820Sjeff } 1313219820Sjeff 1314219820Sjeff attr->qp_state = cmd.qp_state; 1315219820Sjeff attr->cur_qp_state = cmd.cur_qp_state; 1316219820Sjeff attr->path_mtu = cmd.path_mtu; 1317219820Sjeff attr->path_mig_state = cmd.path_mig_state; 1318219820Sjeff attr->qkey = cmd.qkey; 1319219820Sjeff attr->rq_psn = cmd.rq_psn; 1320219820Sjeff attr->sq_psn = cmd.sq_psn; 1321219820Sjeff attr->dest_qp_num = cmd.dest_qp_num; 1322219820Sjeff attr->qp_access_flags = cmd.qp_access_flags; 1323219820Sjeff attr->pkey_index = cmd.pkey_index; 1324219820Sjeff attr->alt_pkey_index = cmd.alt_pkey_index; 1325219820Sjeff attr->en_sqd_async_notify = cmd.en_sqd_async_notify; 1326219820Sjeff attr->max_rd_atomic = cmd.max_rd_atomic; 1327219820Sjeff attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic; 1328219820Sjeff attr->min_rnr_timer = cmd.min_rnr_timer; 1329219820Sjeff attr->port_num = cmd.port_num; 1330219820Sjeff attr->timeout = cmd.timeout; 1331219820Sjeff attr->retry_cnt = cmd.retry_cnt; 1332219820Sjeff attr->rnr_retry = cmd.rnr_retry; 1333219820Sjeff attr->alt_port_num = cmd.alt_port_num; 1334219820Sjeff attr->alt_timeout = cmd.alt_timeout; 1335219820Sjeff 1336219820Sjeff memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16); 1337219820Sjeff attr->ah_attr.grh.flow_label = cmd.dest.flow_label; 1338219820Sjeff attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index; 1339219820Sjeff attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit; 1340219820Sjeff attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class; 1341219820Sjeff attr->ah_attr.dlid = cmd.dest.dlid; 1342219820Sjeff attr->ah_attr.sl = cmd.dest.sl; 1343219820Sjeff attr->ah_attr.src_path_bits = cmd.dest.src_path_bits; 1344219820Sjeff attr->ah_attr.static_rate = cmd.dest.static_rate; 1345219820Sjeff attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0; 1346219820Sjeff attr->ah_attr.port_num = cmd.dest.port_num; 1347219820Sjeff 1348219820Sjeff memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16); 1349219820Sjeff attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label; 1350219820Sjeff attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index; 1351219820Sjeff attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit; 1352219820Sjeff attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class; 1353219820Sjeff attr->alt_ah_attr.dlid = cmd.alt_dest.dlid; 1354219820Sjeff attr->alt_ah_attr.sl = cmd.alt_dest.sl; 1355219820Sjeff attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits; 1356219820Sjeff attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate; 1357219820Sjeff attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0; 1358219820Sjeff attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; 1359219820Sjeff 1360219820Sjeff ret = qp->device->modify_qp(qp, attr, cmd.attr_mask, &udata); 1361219820Sjeff 1362219820Sjeff put_qp_read(qp); 1363219820Sjeff 1364219820Sjeff if (ret) 1365219820Sjeff goto out; 1366219820Sjeff 1367219820Sjeff ret = in_len; 1368219820Sjeff 1369219820Sjeffout: 1370219820Sjeff kfree(attr); 1371219820Sjeff 1372219820Sjeff return ret; 1373219820Sjeff} 1374219820Sjeff 1375219820Sjeffssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, 1376219820Sjeff const char __user *buf, int in_len, 1377219820Sjeff int out_len) 1378219820Sjeff{ 1379219820Sjeff struct ib_uverbs_destroy_qp cmd; 1380219820Sjeff struct ib_uverbs_destroy_qp_resp resp; 1381219820Sjeff struct ib_uobject *uobj; 1382219820Sjeff struct ib_qp *qp; 1383219820Sjeff struct ib_uqp_object *obj; 1384219820Sjeff int ret = -EINVAL; 1385219820Sjeff 1386219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1387219820Sjeff return -EFAULT; 1388219820Sjeff 1389219820Sjeff memset(&resp, 0, sizeof resp); 1390219820Sjeff 1391219820Sjeff uobj = idr_write_uobj(&ib_uverbs_qp_idr, cmd.qp_handle, file->ucontext); 1392219820Sjeff if (!uobj) 1393219820Sjeff return -EINVAL; 1394219820Sjeff qp = uobj->object; 1395219820Sjeff obj = container_of(uobj, struct ib_uqp_object, uevent.uobject); 1396219820Sjeff 1397219820Sjeff if (!list_empty(&obj->mcast_list)) { 1398219820Sjeff put_uobj_write(uobj); 1399219820Sjeff return -EBUSY; 1400219820Sjeff } 1401219820Sjeff 1402219820Sjeff ret = ib_destroy_qp(qp); 1403219820Sjeff if (!ret) 1404219820Sjeff uobj->live = 0; 1405219820Sjeff 1406219820Sjeff put_uobj_write(uobj); 1407219820Sjeff 1408219820Sjeff if (ret) 1409219820Sjeff return ret; 1410219820Sjeff 1411219820Sjeff idr_remove_uobj(&ib_uverbs_qp_idr, uobj); 1412219820Sjeff 1413219820Sjeff mutex_lock(&file->mutex); 1414219820Sjeff list_del(&uobj->list); 1415219820Sjeff mutex_unlock(&file->mutex); 1416219820Sjeff 1417219820Sjeff ib_uverbs_release_uevent(file, &obj->uevent); 1418219820Sjeff 1419219820Sjeff resp.events_reported = obj->uevent.events_reported; 1420219820Sjeff 1421219820Sjeff put_uobj(uobj); 1422219820Sjeff 1423219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 1424219820Sjeff &resp, sizeof resp)) 1425219820Sjeff return -EFAULT; 1426219820Sjeff 1427219820Sjeff return in_len; 1428219820Sjeff} 1429219820Sjeff 1430219820Sjeffssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, 1431219820Sjeff const char __user *buf, int in_len, 1432219820Sjeff int out_len) 1433219820Sjeff{ 1434219820Sjeff struct ib_uverbs_post_send cmd; 1435219820Sjeff struct ib_uverbs_post_send_resp resp; 1436219820Sjeff struct ib_uverbs_send_wr *user_wr; 1437219820Sjeff struct ib_send_wr *wr = NULL, *last, *next, *bad_wr; 1438219820Sjeff struct ib_qp *qp; 1439219820Sjeff int i, sg_ind; 1440219820Sjeff int is_ud; 1441219820Sjeff ssize_t ret = -EINVAL; 1442219820Sjeff 1443219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1444219820Sjeff return -EFAULT; 1445219820Sjeff 1446219820Sjeff if (in_len < sizeof cmd + cmd.wqe_size * cmd.wr_count + 1447219820Sjeff cmd.sge_count * sizeof (struct ib_uverbs_sge)) 1448219820Sjeff return -EINVAL; 1449219820Sjeff 1450219820Sjeff if (cmd.wqe_size < sizeof (struct ib_uverbs_send_wr)) 1451219820Sjeff return -EINVAL; 1452219820Sjeff 1453219820Sjeff user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); 1454219820Sjeff if (!user_wr) 1455219820Sjeff return -ENOMEM; 1456219820Sjeff 1457219820Sjeff qp = idr_read_qp(cmd.qp_handle, file->ucontext); 1458219820Sjeff if (!qp) 1459219820Sjeff goto out; 1460219820Sjeff 1461219820Sjeff is_ud = qp->qp_type == IB_QPT_UD; 1462219820Sjeff sg_ind = 0; 1463219820Sjeff last = NULL; 1464219820Sjeff for (i = 0; i < cmd.wr_count; ++i) { 1465219820Sjeff if (copy_from_user(user_wr, 1466219820Sjeff buf + sizeof cmd + i * cmd.wqe_size, 1467219820Sjeff cmd.wqe_size)) { 1468219820Sjeff ret = -EFAULT; 1469219820Sjeff goto out_put; 1470219820Sjeff } 1471219820Sjeff 1472219820Sjeff if (user_wr->num_sge + sg_ind > cmd.sge_count) { 1473219820Sjeff ret = -EINVAL; 1474219820Sjeff goto out_put; 1475219820Sjeff } 1476219820Sjeff 1477219820Sjeff next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + 1478219820Sjeff user_wr->num_sge * sizeof (struct ib_sge), 1479219820Sjeff GFP_KERNEL); 1480219820Sjeff if (!next) { 1481219820Sjeff ret = -ENOMEM; 1482219820Sjeff goto out_put; 1483219820Sjeff } 1484219820Sjeff 1485219820Sjeff if (!last) 1486219820Sjeff wr = next; 1487219820Sjeff else 1488219820Sjeff last->next = next; 1489219820Sjeff last = next; 1490219820Sjeff 1491219820Sjeff next->next = NULL; 1492219820Sjeff next->wr_id = user_wr->wr_id; 1493219820Sjeff next->num_sge = user_wr->num_sge; 1494219820Sjeff next->opcode = user_wr->opcode; 1495219820Sjeff next->send_flags = user_wr->send_flags; 1496219820Sjeff 1497219820Sjeff if (is_ud) { 1498219820Sjeff next->wr.ud.ah = idr_read_ah(user_wr->wr.ud.ah, 1499219820Sjeff file->ucontext); 1500219820Sjeff if (!next->wr.ud.ah) { 1501219820Sjeff ret = -EINVAL; 1502219820Sjeff goto out_put; 1503219820Sjeff } 1504219820Sjeff next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn; 1505219820Sjeff next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey; 1506219820Sjeff } else { 1507219820Sjeff switch (next->opcode) { 1508219820Sjeff case IB_WR_RDMA_WRITE_WITH_IMM: 1509219820Sjeff next->ex.imm_data = 1510219820Sjeff (__be32 __force) user_wr->ex.imm_data; 1511219820Sjeff case IB_WR_RDMA_WRITE: 1512219820Sjeff case IB_WR_RDMA_READ: 1513219820Sjeff next->wr.rdma.remote_addr = 1514219820Sjeff user_wr->wr.rdma.remote_addr; 1515219820Sjeff next->wr.rdma.rkey = 1516219820Sjeff user_wr->wr.rdma.rkey; 1517219820Sjeff break; 1518219820Sjeff case IB_WR_SEND_WITH_IMM: 1519219820Sjeff next->ex.imm_data = 1520219820Sjeff (__be32 __force) user_wr->ex.imm_data; 1521219820Sjeff break; 1522219820Sjeff case IB_WR_SEND_WITH_INV: 1523219820Sjeff next->ex.invalidate_rkey = 1524219820Sjeff user_wr->ex.invalidate_rkey; 1525219820Sjeff break; 1526219820Sjeff case IB_WR_ATOMIC_CMP_AND_SWP: 1527219820Sjeff case IB_WR_ATOMIC_FETCH_AND_ADD: 1528219820Sjeff next->wr.atomic.remote_addr = 1529219820Sjeff user_wr->wr.atomic.remote_addr; 1530219820Sjeff next->wr.atomic.compare_add = 1531219820Sjeff user_wr->wr.atomic.compare_add; 1532219820Sjeff next->wr.atomic.swap = user_wr->wr.atomic.swap; 1533219820Sjeff next->wr.atomic.rkey = user_wr->wr.atomic.rkey; 1534219820Sjeff break; 1535219820Sjeff default: 1536219820Sjeff break; 1537219820Sjeff } 1538219820Sjeff } 1539219820Sjeff 1540219820Sjeff if (next->num_sge) { 1541219820Sjeff next->sg_list = (void *) next + 1542219820Sjeff ALIGN(sizeof *next, sizeof (struct ib_sge)); 1543219820Sjeff if (copy_from_user(next->sg_list, 1544219820Sjeff buf + sizeof cmd + 1545219820Sjeff cmd.wr_count * cmd.wqe_size + 1546219820Sjeff sg_ind * sizeof (struct ib_sge), 1547219820Sjeff next->num_sge * sizeof (struct ib_sge))) { 1548219820Sjeff ret = -EFAULT; 1549219820Sjeff goto out_put; 1550219820Sjeff } 1551219820Sjeff sg_ind += next->num_sge; 1552219820Sjeff } else 1553219820Sjeff next->sg_list = NULL; 1554219820Sjeff } 1555219820Sjeff 1556219820Sjeff resp.bad_wr = 0; 1557219820Sjeff ret = qp->device->post_send(qp, wr, &bad_wr); 1558219820Sjeff if (ret) 1559219820Sjeff for (next = wr; next; next = next->next) { 1560219820Sjeff ++resp.bad_wr; 1561219820Sjeff if (next == bad_wr) 1562219820Sjeff break; 1563219820Sjeff } 1564219820Sjeff 1565219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 1566219820Sjeff &resp, sizeof resp)) 1567219820Sjeff ret = -EFAULT; 1568219820Sjeff 1569219820Sjeffout_put: 1570219820Sjeff put_qp_read(qp); 1571219820Sjeff 1572219820Sjeff while (wr) { 1573219820Sjeff if (is_ud && wr->wr.ud.ah) 1574219820Sjeff put_ah_read(wr->wr.ud.ah); 1575219820Sjeff next = wr->next; 1576219820Sjeff kfree(wr); 1577219820Sjeff wr = next; 1578219820Sjeff } 1579219820Sjeff 1580219820Sjeffout: 1581219820Sjeff kfree(user_wr); 1582219820Sjeff 1583219820Sjeff return ret ? ret : in_len; 1584219820Sjeff} 1585219820Sjeff 1586219820Sjeffstatic struct ib_recv_wr *ib_uverbs_unmarshall_recv(const char __user *buf, 1587219820Sjeff int in_len, 1588219820Sjeff u32 wr_count, 1589219820Sjeff u32 sge_count, 1590219820Sjeff u32 wqe_size) 1591219820Sjeff{ 1592219820Sjeff struct ib_uverbs_recv_wr *user_wr; 1593219820Sjeff struct ib_recv_wr *wr = NULL, *last, *next; 1594219820Sjeff int sg_ind; 1595219820Sjeff int i; 1596219820Sjeff int ret; 1597219820Sjeff 1598219820Sjeff if (in_len < wqe_size * wr_count + 1599219820Sjeff sge_count * sizeof (struct ib_uverbs_sge)) 1600219820Sjeff return ERR_PTR(-EINVAL); 1601219820Sjeff 1602219820Sjeff if (wqe_size < sizeof (struct ib_uverbs_recv_wr)) 1603219820Sjeff return ERR_PTR(-EINVAL); 1604219820Sjeff 1605219820Sjeff user_wr = kmalloc(wqe_size, GFP_KERNEL); 1606219820Sjeff if (!user_wr) 1607219820Sjeff return ERR_PTR(-ENOMEM); 1608219820Sjeff 1609219820Sjeff sg_ind = 0; 1610219820Sjeff last = NULL; 1611219820Sjeff for (i = 0; i < wr_count; ++i) { 1612219820Sjeff if (copy_from_user(user_wr, buf + i * wqe_size, 1613219820Sjeff wqe_size)) { 1614219820Sjeff ret = -EFAULT; 1615219820Sjeff goto err; 1616219820Sjeff } 1617219820Sjeff 1618219820Sjeff if (user_wr->num_sge + sg_ind > sge_count) { 1619219820Sjeff ret = -EINVAL; 1620219820Sjeff goto err; 1621219820Sjeff } 1622219820Sjeff 1623219820Sjeff next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + 1624219820Sjeff user_wr->num_sge * sizeof (struct ib_sge), 1625219820Sjeff GFP_KERNEL); 1626219820Sjeff if (!next) { 1627219820Sjeff ret = -ENOMEM; 1628219820Sjeff goto err; 1629219820Sjeff } 1630219820Sjeff 1631219820Sjeff if (!last) 1632219820Sjeff wr = next; 1633219820Sjeff else 1634219820Sjeff last->next = next; 1635219820Sjeff last = next; 1636219820Sjeff 1637219820Sjeff next->next = NULL; 1638219820Sjeff next->wr_id = user_wr->wr_id; 1639219820Sjeff next->num_sge = user_wr->num_sge; 1640219820Sjeff 1641219820Sjeff if (next->num_sge) { 1642219820Sjeff next->sg_list = (void *) next + 1643219820Sjeff ALIGN(sizeof *next, sizeof (struct ib_sge)); 1644219820Sjeff if (copy_from_user(next->sg_list, 1645219820Sjeff buf + wr_count * wqe_size + 1646219820Sjeff sg_ind * sizeof (struct ib_sge), 1647219820Sjeff next->num_sge * sizeof (struct ib_sge))) { 1648219820Sjeff ret = -EFAULT; 1649219820Sjeff goto err; 1650219820Sjeff } 1651219820Sjeff sg_ind += next->num_sge; 1652219820Sjeff } else 1653219820Sjeff next->sg_list = NULL; 1654219820Sjeff } 1655219820Sjeff 1656219820Sjeff kfree(user_wr); 1657219820Sjeff return wr; 1658219820Sjeff 1659219820Sjefferr: 1660219820Sjeff kfree(user_wr); 1661219820Sjeff 1662219820Sjeff while (wr) { 1663219820Sjeff next = wr->next; 1664219820Sjeff kfree(wr); 1665219820Sjeff wr = next; 1666219820Sjeff } 1667219820Sjeff 1668219820Sjeff return ERR_PTR(ret); 1669219820Sjeff} 1670219820Sjeff 1671219820Sjeffssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, 1672219820Sjeff const char __user *buf, int in_len, 1673219820Sjeff int out_len) 1674219820Sjeff{ 1675219820Sjeff struct ib_uverbs_post_recv cmd; 1676219820Sjeff struct ib_uverbs_post_recv_resp resp; 1677219820Sjeff struct ib_recv_wr *wr, *next, *bad_wr; 1678219820Sjeff struct ib_qp *qp; 1679219820Sjeff ssize_t ret = -EINVAL; 1680219820Sjeff 1681219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1682219820Sjeff return -EFAULT; 1683219820Sjeff 1684219820Sjeff wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, 1685219820Sjeff in_len - sizeof cmd, cmd.wr_count, 1686219820Sjeff cmd.sge_count, cmd.wqe_size); 1687219820Sjeff if (IS_ERR(wr)) 1688219820Sjeff return PTR_ERR(wr); 1689219820Sjeff 1690219820Sjeff qp = idr_read_qp(cmd.qp_handle, file->ucontext); 1691219820Sjeff if (!qp) 1692219820Sjeff goto out; 1693219820Sjeff 1694219820Sjeff resp.bad_wr = 0; 1695219820Sjeff ret = qp->device->post_recv(qp, wr, &bad_wr); 1696219820Sjeff 1697219820Sjeff put_qp_read(qp); 1698219820Sjeff 1699219820Sjeff if (ret) 1700219820Sjeff for (next = wr; next; next = next->next) { 1701219820Sjeff ++resp.bad_wr; 1702219820Sjeff if (next == bad_wr) 1703219820Sjeff break; 1704219820Sjeff } 1705219820Sjeff 1706219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 1707219820Sjeff &resp, sizeof resp)) 1708219820Sjeff ret = -EFAULT; 1709219820Sjeff 1710219820Sjeffout: 1711219820Sjeff while (wr) { 1712219820Sjeff next = wr->next; 1713219820Sjeff kfree(wr); 1714219820Sjeff wr = next; 1715219820Sjeff } 1716219820Sjeff 1717219820Sjeff return ret ? ret : in_len; 1718219820Sjeff} 1719219820Sjeff 1720219820Sjeffssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, 1721219820Sjeff const char __user *buf, int in_len, 1722219820Sjeff int out_len) 1723219820Sjeff{ 1724219820Sjeff struct ib_uverbs_post_srq_recv cmd; 1725219820Sjeff struct ib_uverbs_post_srq_recv_resp resp; 1726219820Sjeff struct ib_recv_wr *wr, *next, *bad_wr; 1727219820Sjeff struct ib_srq *srq; 1728219820Sjeff ssize_t ret = -EINVAL; 1729219820Sjeff 1730219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1731219820Sjeff return -EFAULT; 1732219820Sjeff 1733219820Sjeff wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, 1734219820Sjeff in_len - sizeof cmd, cmd.wr_count, 1735219820Sjeff cmd.sge_count, cmd.wqe_size); 1736219820Sjeff if (IS_ERR(wr)) 1737219820Sjeff return PTR_ERR(wr); 1738219820Sjeff 1739219820Sjeff srq = idr_read_srq(cmd.srq_handle, file->ucontext); 1740219820Sjeff if (!srq) 1741219820Sjeff goto out; 1742219820Sjeff 1743219820Sjeff resp.bad_wr = 0; 1744219820Sjeff ret = srq->device->post_srq_recv(srq, wr, &bad_wr); 1745219820Sjeff 1746219820Sjeff put_srq_read(srq); 1747219820Sjeff 1748219820Sjeff if (ret) 1749219820Sjeff for (next = wr; next; next = next->next) { 1750219820Sjeff ++resp.bad_wr; 1751219820Sjeff if (next == bad_wr) 1752219820Sjeff break; 1753219820Sjeff } 1754219820Sjeff 1755219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 1756219820Sjeff &resp, sizeof resp)) 1757219820Sjeff ret = -EFAULT; 1758219820Sjeff 1759219820Sjeffout: 1760219820Sjeff while (wr) { 1761219820Sjeff next = wr->next; 1762219820Sjeff kfree(wr); 1763219820Sjeff wr = next; 1764219820Sjeff } 1765219820Sjeff 1766219820Sjeff return ret ? ret : in_len; 1767219820Sjeff} 1768219820Sjeff 1769219820Sjeffssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, 1770219820Sjeff const char __user *buf, int in_len, 1771219820Sjeff int out_len) 1772219820Sjeff{ 1773219820Sjeff struct ib_uverbs_create_ah cmd; 1774219820Sjeff struct ib_uverbs_create_ah_resp resp; 1775219820Sjeff struct ib_uobject *uobj; 1776219820Sjeff struct ib_pd *pd; 1777219820Sjeff struct ib_ah *ah; 1778219820Sjeff struct ib_ah_attr attr; 1779219820Sjeff int ret; 1780219820Sjeff 1781219820Sjeff if (out_len < sizeof resp) 1782219820Sjeff return -ENOSPC; 1783219820Sjeff 1784219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1785219820Sjeff return -EFAULT; 1786219820Sjeff 1787219820Sjeff uobj = kmalloc(sizeof *uobj, GFP_KERNEL); 1788219820Sjeff if (!uobj) 1789219820Sjeff return -ENOMEM; 1790219820Sjeff 1791219820Sjeff init_uobj(uobj, cmd.user_handle, file->ucontext, &ah_lock_key); 1792219820Sjeff down_write(&uobj->mutex); 1793219820Sjeff 1794219820Sjeff pd = idr_read_pd(cmd.pd_handle, file->ucontext); 1795219820Sjeff if (!pd) { 1796219820Sjeff ret = -EINVAL; 1797219820Sjeff goto err; 1798219820Sjeff } 1799219820Sjeff 1800219820Sjeff attr.dlid = cmd.attr.dlid; 1801219820Sjeff attr.sl = cmd.attr.sl; 1802219820Sjeff attr.src_path_bits = cmd.attr.src_path_bits; 1803219820Sjeff attr.static_rate = cmd.attr.static_rate; 1804219820Sjeff attr.ah_flags = cmd.attr.is_global ? IB_AH_GRH : 0; 1805219820Sjeff attr.port_num = cmd.attr.port_num; 1806219820Sjeff attr.grh.flow_label = cmd.attr.grh.flow_label; 1807219820Sjeff attr.grh.sgid_index = cmd.attr.grh.sgid_index; 1808219820Sjeff attr.grh.hop_limit = cmd.attr.grh.hop_limit; 1809219820Sjeff attr.grh.traffic_class = cmd.attr.grh.traffic_class; 1810219820Sjeff memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16); 1811219820Sjeff 1812219820Sjeff ah = ib_create_ah(pd, &attr); 1813219820Sjeff if (IS_ERR(ah)) { 1814219820Sjeff ret = PTR_ERR(ah); 1815219820Sjeff goto err_put; 1816219820Sjeff } 1817219820Sjeff 1818219820Sjeff ah->uobject = uobj; 1819219820Sjeff uobj->object = ah; 1820219820Sjeff 1821219820Sjeff ret = idr_add_uobj(&ib_uverbs_ah_idr, uobj); 1822219820Sjeff if (ret) 1823219820Sjeff goto err_destroy; 1824219820Sjeff 1825219820Sjeff resp.ah_handle = uobj->id; 1826219820Sjeff 1827219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 1828219820Sjeff &resp, sizeof resp)) { 1829219820Sjeff ret = -EFAULT; 1830219820Sjeff goto err_copy; 1831219820Sjeff } 1832219820Sjeff 1833219820Sjeff put_pd_read(pd); 1834219820Sjeff 1835219820Sjeff mutex_lock(&file->mutex); 1836219820Sjeff list_add_tail(&uobj->list, &file->ucontext->ah_list); 1837219820Sjeff mutex_unlock(&file->mutex); 1838219820Sjeff 1839219820Sjeff uobj->live = 1; 1840219820Sjeff 1841219820Sjeff up_write(&uobj->mutex); 1842219820Sjeff 1843219820Sjeff return in_len; 1844219820Sjeff 1845219820Sjefferr_copy: 1846219820Sjeff idr_remove_uobj(&ib_uverbs_ah_idr, uobj); 1847219820Sjeff 1848219820Sjefferr_destroy: 1849219820Sjeff ib_destroy_ah(ah); 1850219820Sjeff 1851219820Sjefferr_put: 1852219820Sjeff put_pd_read(pd); 1853219820Sjeff 1854219820Sjefferr: 1855219820Sjeff put_uobj_write(uobj); 1856219820Sjeff return ret; 1857219820Sjeff} 1858219820Sjeff 1859219820Sjeffssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file, 1860219820Sjeff const char __user *buf, int in_len, int out_len) 1861219820Sjeff{ 1862219820Sjeff struct ib_uverbs_destroy_ah cmd; 1863219820Sjeff struct ib_ah *ah; 1864219820Sjeff struct ib_uobject *uobj; 1865219820Sjeff int ret; 1866219820Sjeff 1867219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1868219820Sjeff return -EFAULT; 1869219820Sjeff 1870219820Sjeff uobj = idr_write_uobj(&ib_uverbs_ah_idr, cmd.ah_handle, file->ucontext); 1871219820Sjeff if (!uobj) 1872219820Sjeff return -EINVAL; 1873219820Sjeff ah = uobj->object; 1874219820Sjeff 1875219820Sjeff ret = ib_destroy_ah(ah); 1876219820Sjeff if (!ret) 1877219820Sjeff uobj->live = 0; 1878219820Sjeff 1879219820Sjeff put_uobj_write(uobj); 1880219820Sjeff 1881219820Sjeff if (ret) 1882219820Sjeff return ret; 1883219820Sjeff 1884219820Sjeff idr_remove_uobj(&ib_uverbs_ah_idr, uobj); 1885219820Sjeff 1886219820Sjeff mutex_lock(&file->mutex); 1887219820Sjeff list_del(&uobj->list); 1888219820Sjeff mutex_unlock(&file->mutex); 1889219820Sjeff 1890219820Sjeff put_uobj(uobj); 1891219820Sjeff 1892219820Sjeff return in_len; 1893219820Sjeff} 1894219820Sjeff 1895219820Sjeffssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, 1896219820Sjeff const char __user *buf, int in_len, 1897219820Sjeff int out_len) 1898219820Sjeff{ 1899219820Sjeff struct ib_uverbs_attach_mcast cmd; 1900219820Sjeff struct ib_qp *qp; 1901219820Sjeff struct ib_uqp_object *obj; 1902219820Sjeff struct ib_uverbs_mcast_entry *mcast; 1903219820Sjeff int ret; 1904219820Sjeff 1905219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1906219820Sjeff return -EFAULT; 1907219820Sjeff 1908219820Sjeff qp = idr_read_qp(cmd.qp_handle, file->ucontext); 1909219820Sjeff if (!qp) 1910219820Sjeff return -EINVAL; 1911219820Sjeff 1912219820Sjeff obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); 1913219820Sjeff 1914219820Sjeff list_for_each_entry(mcast, &obj->mcast_list, list) 1915219820Sjeff if (cmd.mlid == mcast->lid && 1916219820Sjeff !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { 1917219820Sjeff ret = 0; 1918219820Sjeff goto out_put; 1919219820Sjeff } 1920219820Sjeff 1921219820Sjeff mcast = kmalloc(sizeof *mcast, GFP_KERNEL); 1922219820Sjeff if (!mcast) { 1923219820Sjeff ret = -ENOMEM; 1924219820Sjeff goto out_put; 1925219820Sjeff } 1926219820Sjeff 1927219820Sjeff mcast->lid = cmd.mlid; 1928219820Sjeff memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw); 1929219820Sjeff 1930219820Sjeff ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid); 1931219820Sjeff if (!ret) 1932219820Sjeff list_add_tail(&mcast->list, &obj->mcast_list); 1933219820Sjeff else 1934219820Sjeff kfree(mcast); 1935219820Sjeff 1936219820Sjeffout_put: 1937219820Sjeff put_qp_read(qp); 1938219820Sjeff 1939219820Sjeff return ret ? ret : in_len; 1940219820Sjeff} 1941219820Sjeff 1942219820Sjeffssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, 1943219820Sjeff const char __user *buf, int in_len, 1944219820Sjeff int out_len) 1945219820Sjeff{ 1946219820Sjeff struct ib_uverbs_detach_mcast cmd; 1947219820Sjeff struct ib_uqp_object *obj; 1948219820Sjeff struct ib_qp *qp; 1949219820Sjeff struct ib_uverbs_mcast_entry *mcast; 1950219820Sjeff int ret = -EINVAL; 1951219820Sjeff 1952219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1953219820Sjeff return -EFAULT; 1954219820Sjeff 1955219820Sjeff qp = idr_read_qp(cmd.qp_handle, file->ucontext); 1956219820Sjeff if (!qp) 1957219820Sjeff return -EINVAL; 1958219820Sjeff 1959219820Sjeff ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); 1960219820Sjeff if (ret) 1961219820Sjeff goto out_put; 1962219820Sjeff 1963219820Sjeff obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); 1964219820Sjeff 1965219820Sjeff list_for_each_entry(mcast, &obj->mcast_list, list) 1966219820Sjeff if (cmd.mlid == mcast->lid && 1967219820Sjeff !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { 1968219820Sjeff list_del(&mcast->list); 1969219820Sjeff kfree(mcast); 1970219820Sjeff break; 1971219820Sjeff } 1972219820Sjeff 1973219820Sjeffout_put: 1974219820Sjeff put_qp_read(qp); 1975219820Sjeff 1976219820Sjeff return ret ? ret : in_len; 1977219820Sjeff} 1978219820Sjeff 1979219820Sjeffssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, 1980219820Sjeff const char __user *buf, int in_len, 1981219820Sjeff int out_len) 1982219820Sjeff{ 1983219820Sjeff struct ib_uverbs_create_srq cmd; 1984219820Sjeff struct ib_uverbs_create_srq_resp resp; 1985219820Sjeff struct ib_udata udata; 1986219820Sjeff struct ib_uevent_object *obj; 1987219820Sjeff struct ib_pd *pd; 1988219820Sjeff struct ib_srq *srq; 1989219820Sjeff struct ib_srq_init_attr attr; 1990219820Sjeff int ret; 1991219820Sjeff 1992219820Sjeff if (out_len < sizeof resp) 1993219820Sjeff return -ENOSPC; 1994219820Sjeff 1995219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 1996219820Sjeff return -EFAULT; 1997219820Sjeff 1998219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, 1999219820Sjeff (unsigned long) cmd.response + sizeof resp, 2000219820Sjeff in_len - sizeof cmd, out_len - sizeof resp); 2001219820Sjeff 2002219820Sjeff obj = kmalloc(sizeof *obj, GFP_KERNEL); 2003219820Sjeff if (!obj) 2004219820Sjeff return -ENOMEM; 2005219820Sjeff 2006219820Sjeff init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &srq_lock_key); 2007219820Sjeff down_write(&obj->uobject.mutex); 2008219820Sjeff 2009219820Sjeff pd = idr_read_pd(cmd.pd_handle, file->ucontext); 2010219820Sjeff if (!pd) { 2011219820Sjeff ret = -EINVAL; 2012219820Sjeff goto err; 2013219820Sjeff } 2014219820Sjeff 2015219820Sjeff attr.event_handler = ib_uverbs_srq_event_handler; 2016219820Sjeff attr.srq_context = file; 2017219820Sjeff attr.attr.max_wr = cmd.max_wr; 2018219820Sjeff attr.attr.max_sge = cmd.max_sge; 2019219820Sjeff attr.attr.srq_limit = cmd.srq_limit; 2020219820Sjeff 2021219820Sjeff obj->events_reported = 0; 2022219820Sjeff INIT_LIST_HEAD(&obj->event_list); 2023219820Sjeff 2024219820Sjeff srq = pd->device->create_srq(pd, &attr, &udata); 2025219820Sjeff if (IS_ERR(srq)) { 2026219820Sjeff ret = PTR_ERR(srq); 2027219820Sjeff goto err_put; 2028219820Sjeff } 2029219820Sjeff 2030219820Sjeff srq->device = pd->device; 2031219820Sjeff srq->pd = pd; 2032219820Sjeff srq->uobject = &obj->uobject; 2033219820Sjeff srq->event_handler = attr.event_handler; 2034219820Sjeff srq->srq_context = attr.srq_context; 2035255932Salfred srq->ext.xrc.cq = NULL; 2036255932Salfred srq->ext.xrc.xrcd = NULL; 2037219820Sjeff atomic_inc(&pd->usecnt); 2038219820Sjeff atomic_set(&srq->usecnt, 0); 2039219820Sjeff 2040219820Sjeff obj->uobject.object = srq; 2041219820Sjeff ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject); 2042219820Sjeff if (ret) 2043219820Sjeff goto err_destroy; 2044219820Sjeff 2045219820Sjeff memset(&resp, 0, sizeof resp); 2046219820Sjeff resp.srq_handle = obj->uobject.id; 2047219820Sjeff resp.max_wr = attr.attr.max_wr; 2048219820Sjeff resp.max_sge = attr.attr.max_sge; 2049219820Sjeff 2050219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 2051219820Sjeff &resp, sizeof resp)) { 2052219820Sjeff ret = -EFAULT; 2053219820Sjeff goto err_copy; 2054219820Sjeff } 2055219820Sjeff 2056219820Sjeff put_pd_read(pd); 2057219820Sjeff 2058219820Sjeff mutex_lock(&file->mutex); 2059219820Sjeff list_add_tail(&obj->uobject.list, &file->ucontext->srq_list); 2060219820Sjeff mutex_unlock(&file->mutex); 2061219820Sjeff 2062219820Sjeff obj->uobject.live = 1; 2063219820Sjeff 2064219820Sjeff up_write(&obj->uobject.mutex); 2065219820Sjeff 2066219820Sjeff return in_len; 2067219820Sjeff 2068219820Sjefferr_copy: 2069219820Sjeff idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject); 2070219820Sjeff 2071219820Sjefferr_destroy: 2072219820Sjeff ib_destroy_srq(srq); 2073219820Sjeff 2074219820Sjefferr_put: 2075219820Sjeff put_pd_read(pd); 2076219820Sjeff 2077219820Sjefferr: 2078219820Sjeff put_uobj_write(&obj->uobject); 2079219820Sjeff return ret; 2080219820Sjeff} 2081219820Sjeff 2082219820Sjeffssize_t ib_uverbs_create_xrc_srq(struct ib_uverbs_file *file, 2083219820Sjeff const char __user *buf, int in_len, 2084219820Sjeff int out_len) 2085219820Sjeff{ 2086255932Salfred struct ib_uverbs_create_xsrq cmd; 2087219820Sjeff struct ib_uverbs_create_srq_resp resp; 2088219820Sjeff struct ib_udata udata; 2089219820Sjeff struct ib_uevent_object *obj; 2090219820Sjeff struct ib_pd *pd; 2091219820Sjeff struct ib_srq *srq; 2092219820Sjeff struct ib_cq *xrc_cq; 2093219820Sjeff struct ib_xrcd *xrcd; 2094219820Sjeff struct ib_srq_init_attr attr; 2095219820Sjeff struct ib_uobject *xrcd_uobj; 2096219820Sjeff int ret; 2097219820Sjeff 2098219820Sjeff if (out_len < sizeof resp) 2099219820Sjeff return -ENOSPC; 2100219820Sjeff 2101219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2102219820Sjeff return -EFAULT; 2103219820Sjeff 2104219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, 2105219820Sjeff (unsigned long) cmd.response + sizeof resp, 2106219820Sjeff in_len - sizeof cmd, out_len - sizeof resp); 2107219820Sjeff 2108219820Sjeff obj = kmalloc(sizeof *obj, GFP_KERNEL); 2109219820Sjeff if (!obj) 2110219820Sjeff return -ENOMEM; 2111219820Sjeff 2112219820Sjeff init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, 2113219820Sjeff &srq_lock_key); 2114219820Sjeff down_write(&obj->uobject.mutex); 2115219820Sjeff 2116219820Sjeff pd = idr_read_pd(cmd.pd_handle, file->ucontext); 2117219820Sjeff if (!pd) { 2118219820Sjeff ret = -EINVAL; 2119219820Sjeff goto err; 2120219820Sjeff } 2121219820Sjeff 2122255932Salfred xrc_cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0); 2123219820Sjeff if (!xrc_cq) { 2124219820Sjeff ret = -EINVAL; 2125219820Sjeff goto err_put_pd; 2126219820Sjeff } 2127219820Sjeff 2128219820Sjeff xrcd = idr_read_xrcd(cmd.xrcd_handle, file->ucontext, &xrcd_uobj); 2129219820Sjeff if (!xrcd) { 2130219820Sjeff ret = -EINVAL; 2131219820Sjeff goto err_put_cq; 2132219820Sjeff } 2133219820Sjeff 2134219820Sjeff 2135219820Sjeff attr.event_handler = ib_uverbs_srq_event_handler; 2136219820Sjeff attr.srq_context = file; 2137219820Sjeff attr.attr.max_wr = cmd.max_wr; 2138219820Sjeff attr.attr.max_sge = cmd.max_sge; 2139219820Sjeff attr.attr.srq_limit = cmd.srq_limit; 2140219820Sjeff 2141219820Sjeff obj->events_reported = 0; 2142219820Sjeff INIT_LIST_HEAD(&obj->event_list); 2143219820Sjeff 2144219820Sjeff srq = pd->device->create_xrc_srq(pd, xrc_cq, xrcd, &attr, &udata); 2145219820Sjeff if (IS_ERR(srq)) { 2146219820Sjeff ret = PTR_ERR(srq); 2147219820Sjeff goto err_put; 2148219820Sjeff } 2149219820Sjeff 2150219820Sjeff srq->device = pd->device; 2151219820Sjeff srq->pd = pd; 2152219820Sjeff srq->uobject = &obj->uobject; 2153219820Sjeff srq->event_handler = attr.event_handler; 2154219820Sjeff srq->srq_context = attr.srq_context; 2155255932Salfred srq->ext.xrc.cq = xrc_cq; 2156255932Salfred srq->ext.xrc.xrcd = xrcd; 2157219820Sjeff atomic_inc(&pd->usecnt); 2158219820Sjeff atomic_inc(&xrc_cq->usecnt); 2159219820Sjeff atomic_inc(&xrcd->usecnt); 2160219820Sjeff 2161219820Sjeff atomic_set(&srq->usecnt, 0); 2162219820Sjeff 2163219820Sjeff obj->uobject.object = srq; 2164219820Sjeff ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject); 2165219820Sjeff if (ret) 2166219820Sjeff goto err_destroy; 2167219820Sjeff 2168219820Sjeff memset(&resp, 0, sizeof resp); 2169219820Sjeff resp.srq_handle = obj->uobject.id; 2170219820Sjeff resp.max_wr = attr.attr.max_wr; 2171219820Sjeff resp.max_sge = attr.attr.max_sge; 2172219820Sjeff 2173219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 2174219820Sjeff &resp, sizeof resp)) { 2175219820Sjeff ret = -EFAULT; 2176219820Sjeff goto err_copy; 2177219820Sjeff } 2178219820Sjeff 2179219820Sjeff put_xrcd_read(xrcd_uobj); 2180219820Sjeff put_cq_read(xrc_cq); 2181219820Sjeff put_pd_read(pd); 2182219820Sjeff 2183219820Sjeff mutex_lock(&file->mutex); 2184219820Sjeff list_add_tail(&obj->uobject.list, &file->ucontext->srq_list); 2185219820Sjeff mutex_unlock(&file->mutex); 2186219820Sjeff 2187219820Sjeff obj->uobject.live = 1; 2188219820Sjeff 2189219820Sjeff up_write(&obj->uobject.mutex); 2190219820Sjeff 2191219820Sjeff return in_len; 2192219820Sjeff 2193219820Sjefferr_copy: 2194219820Sjeff idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject); 2195219820Sjeff 2196219820Sjefferr_destroy: 2197219820Sjeff ib_destroy_srq(srq); 2198219820Sjeff 2199219820Sjefferr_put: 2200219820Sjeff put_xrcd_read(xrcd_uobj); 2201219820Sjeff 2202219820Sjefferr_put_cq: 2203219820Sjeff put_cq_read(xrc_cq); 2204219820Sjeff 2205219820Sjefferr_put_pd: 2206219820Sjeff put_pd_read(pd); 2207219820Sjeff 2208219820Sjefferr: 2209219820Sjeff put_uobj_write(&obj->uobject); 2210219820Sjeff return ret; 2211219820Sjeff} 2212219820Sjeff 2213219820Sjeffssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file, 2214219820Sjeff const char __user *buf, int in_len, 2215219820Sjeff int out_len) 2216219820Sjeff{ 2217219820Sjeff struct ib_uverbs_modify_srq cmd; 2218219820Sjeff struct ib_udata udata; 2219219820Sjeff struct ib_srq *srq; 2220219820Sjeff struct ib_srq_attr attr; 2221219820Sjeff int ret; 2222219820Sjeff 2223219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2224219820Sjeff return -EFAULT; 2225219820Sjeff 2226219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd, 2227219820Sjeff out_len); 2228219820Sjeff 2229219820Sjeff srq = idr_read_srq(cmd.srq_handle, file->ucontext); 2230219820Sjeff if (!srq) 2231219820Sjeff return -EINVAL; 2232219820Sjeff 2233219820Sjeff attr.max_wr = cmd.max_wr; 2234219820Sjeff attr.srq_limit = cmd.srq_limit; 2235219820Sjeff 2236219820Sjeff ret = srq->device->modify_srq(srq, &attr, cmd.attr_mask, &udata); 2237219820Sjeff 2238219820Sjeff put_srq_read(srq); 2239219820Sjeff 2240219820Sjeff return ret ? ret : in_len; 2241219820Sjeff} 2242219820Sjeff 2243219820Sjeffssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file, 2244219820Sjeff const char __user *buf, 2245219820Sjeff int in_len, int out_len) 2246219820Sjeff{ 2247219820Sjeff struct ib_uverbs_query_srq cmd; 2248219820Sjeff struct ib_uverbs_query_srq_resp resp; 2249219820Sjeff struct ib_srq_attr attr; 2250219820Sjeff struct ib_srq *srq; 2251219820Sjeff int ret; 2252219820Sjeff 2253219820Sjeff if (out_len < sizeof resp) 2254219820Sjeff return -ENOSPC; 2255219820Sjeff 2256219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2257219820Sjeff return -EFAULT; 2258219820Sjeff 2259219820Sjeff srq = idr_read_srq(cmd.srq_handle, file->ucontext); 2260219820Sjeff if (!srq) 2261219820Sjeff return -EINVAL; 2262219820Sjeff 2263219820Sjeff ret = ib_query_srq(srq, &attr); 2264219820Sjeff 2265219820Sjeff put_srq_read(srq); 2266219820Sjeff 2267219820Sjeff if (ret) 2268219820Sjeff return ret; 2269219820Sjeff 2270219820Sjeff memset(&resp, 0, sizeof resp); 2271219820Sjeff 2272219820Sjeff resp.max_wr = attr.max_wr; 2273219820Sjeff resp.max_sge = attr.max_sge; 2274219820Sjeff resp.srq_limit = attr.srq_limit; 2275219820Sjeff 2276219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 2277219820Sjeff &resp, sizeof resp)) 2278219820Sjeff return -EFAULT; 2279219820Sjeff 2280219820Sjeff return in_len; 2281219820Sjeff} 2282219820Sjeff 2283219820Sjeffssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, 2284219820Sjeff const char __user *buf, int in_len, 2285219820Sjeff int out_len) 2286219820Sjeff{ 2287219820Sjeff struct ib_uverbs_destroy_srq cmd; 2288219820Sjeff struct ib_uverbs_destroy_srq_resp resp; 2289219820Sjeff struct ib_uobject *uobj; 2290219820Sjeff struct ib_srq *srq; 2291219820Sjeff struct ib_uevent_object *obj; 2292219820Sjeff int ret = -EINVAL; 2293219820Sjeff 2294219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2295219820Sjeff return -EFAULT; 2296219820Sjeff 2297219820Sjeff uobj = idr_write_uobj(&ib_uverbs_srq_idr, cmd.srq_handle, file->ucontext); 2298219820Sjeff if (!uobj) 2299219820Sjeff return -EINVAL; 2300219820Sjeff srq = uobj->object; 2301219820Sjeff obj = container_of(uobj, struct ib_uevent_object, uobject); 2302219820Sjeff 2303219820Sjeff ret = ib_destroy_srq(srq); 2304219820Sjeff if (!ret) 2305219820Sjeff uobj->live = 0; 2306219820Sjeff 2307219820Sjeff put_uobj_write(uobj); 2308219820Sjeff 2309219820Sjeff if (ret) 2310219820Sjeff return ret; 2311219820Sjeff 2312219820Sjeff idr_remove_uobj(&ib_uverbs_srq_idr, uobj); 2313219820Sjeff 2314219820Sjeff mutex_lock(&file->mutex); 2315219820Sjeff list_del(&uobj->list); 2316219820Sjeff mutex_unlock(&file->mutex); 2317219820Sjeff 2318219820Sjeff ib_uverbs_release_uevent(file, obj); 2319219820Sjeff 2320219820Sjeff memset(&resp, 0, sizeof resp); 2321219820Sjeff resp.events_reported = obj->events_reported; 2322219820Sjeff 2323219820Sjeff put_uobj(uobj); 2324219820Sjeff 2325219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 2326219820Sjeff &resp, sizeof resp)) 2327219820Sjeff ret = -EFAULT; 2328219820Sjeff 2329219820Sjeff return ret ? ret : in_len; 2330219820Sjeff} 2331219820Sjeff 2332219820Sjeffstatic struct inode *xrc_file2inode(struct file *f) 2333219820Sjeff{ 2334219820Sjeff return f->f_dentry->d_inode; 2335219820Sjeff} 2336219820Sjeff 2337219820Sjeffstruct xrcd_table_entry { 2338219820Sjeff struct rb_node node; 2339219820Sjeff struct inode *inode; 2340219820Sjeff struct ib_xrcd *xrcd; 2341219820Sjeff}; 2342219820Sjeff 2343219820Sjeffstatic int xrcd_table_insert(struct ib_device *dev, 2344219820Sjeff struct inode *i_n, 2345219820Sjeff struct ib_xrcd *xrcd) 2346219820Sjeff{ 2347219820Sjeff struct xrcd_table_entry *entry, *scan; 2348219820Sjeff struct rb_node **p = &dev->ib_uverbs_xrcd_table.rb_node; 2349219820Sjeff struct rb_node *parent = NULL; 2350219820Sjeff 2351219820Sjeff entry = kmalloc(sizeof(struct xrcd_table_entry), GFP_KERNEL); 2352219820Sjeff if (!entry) 2353219820Sjeff return -ENOMEM; 2354219820Sjeff 2355219820Sjeff entry->inode = i_n; 2356219820Sjeff entry->xrcd = xrcd; 2357219820Sjeff 2358219820Sjeff while (*p) { 2359219820Sjeff parent = *p; 2360219820Sjeff scan = rb_entry(parent, struct xrcd_table_entry, node); 2361219820Sjeff 2362219820Sjeff if (i_n < scan->inode) 2363219820Sjeff p = &(*p)->rb_left; 2364219820Sjeff else if (i_n > scan->inode) 2365219820Sjeff p = &(*p)->rb_right; 2366219820Sjeff else { 2367219820Sjeff kfree(entry); 2368219820Sjeff return -EEXIST; 2369219820Sjeff } 2370219820Sjeff } 2371219820Sjeff 2372219820Sjeff rb_link_node(&entry->node, parent, p); 2373219820Sjeff rb_insert_color(&entry->node, &dev->ib_uverbs_xrcd_table); 2374219820Sjeff igrab(i_n); 2375219820Sjeff return 0; 2376219820Sjeff} 2377219820Sjeff 2378219820Sjeffstatic struct xrcd_table_entry *xrcd_table_search(struct ib_device *dev, 2379219820Sjeff struct inode *i_n) 2380219820Sjeff{ 2381219820Sjeff struct xrcd_table_entry *scan; 2382219820Sjeff struct rb_node **p = &dev->ib_uverbs_xrcd_table.rb_node; 2383219820Sjeff struct rb_node *parent = NULL; 2384219820Sjeff 2385219820Sjeff while (*p) { 2386219820Sjeff parent = *p; 2387219820Sjeff scan = rb_entry(parent, struct xrcd_table_entry, node); 2388219820Sjeff 2389219820Sjeff if (i_n < scan->inode) 2390219820Sjeff p = &(*p)->rb_left; 2391219820Sjeff else if (i_n > scan->inode) 2392219820Sjeff p = &(*p)->rb_right; 2393219820Sjeff else 2394219820Sjeff return scan; 2395219820Sjeff } 2396219820Sjeff return NULL; 2397219820Sjeff} 2398219820Sjeff 2399219820Sjeffstatic int find_xrcd(struct ib_device *dev, struct inode *i_n, 2400219820Sjeff struct ib_xrcd **xrcd) 2401219820Sjeff{ 2402219820Sjeff struct xrcd_table_entry *entry; 2403219820Sjeff 2404219820Sjeff entry = xrcd_table_search(dev, i_n); 2405219820Sjeff if (!entry) 2406219820Sjeff return -EINVAL; 2407219820Sjeff 2408219820Sjeff *xrcd = entry->xrcd; 2409219820Sjeff return 0; 2410219820Sjeff} 2411219820Sjeff 2412219820Sjeff 2413219820Sjeffstatic void xrcd_table_delete(struct ib_device *dev, 2414219820Sjeff struct inode *i_n) 2415219820Sjeff{ 2416219820Sjeff struct xrcd_table_entry *entry = xrcd_table_search(dev, i_n); 2417219820Sjeff 2418219820Sjeff if (entry) { 2419219820Sjeff iput(i_n); 2420219820Sjeff rb_erase(&entry->node, &dev->ib_uverbs_xrcd_table); 2421219820Sjeff kfree(entry); 2422219820Sjeff } 2423219820Sjeff} 2424219820Sjeff 2425219820Sjeffssize_t ib_uverbs_open_xrc_domain(struct ib_uverbs_file *file, 2426219820Sjeff const char __user *buf, int in_len, 2427219820Sjeff int out_len) 2428219820Sjeff{ 2429219820Sjeff struct ib_uverbs_open_xrc_domain cmd; 2430219820Sjeff struct ib_uverbs_open_xrc_domain_resp resp; 2431219820Sjeff struct ib_udata udata; 2432219820Sjeff struct ib_uobject *uobj; 2433219820Sjeff struct ib_uxrcd_object *xrcd_uobj; 2434219820Sjeff struct ib_xrcd *xrcd = NULL; 2435219820Sjeff struct file *f = NULL; 2436219820Sjeff struct inode *inode = NULL; 2437219820Sjeff int ret = 0; 2438219820Sjeff int new_xrcd = 0; 2439219820Sjeff 2440219820Sjeff if (out_len < sizeof resp) 2441219820Sjeff return -ENOSPC; 2442219820Sjeff 2443219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2444219820Sjeff return -EFAULT; 2445219820Sjeff 2446219820Sjeff INIT_UDATA(&udata, buf + sizeof cmd, 2447219820Sjeff (unsigned long) cmd.response + sizeof resp, 2448219820Sjeff in_len - sizeof cmd, out_len - sizeof resp); 2449219820Sjeff 2450219820Sjeff mutex_lock(&file->device->ib_dev->xrcd_table_mutex); 2451219820Sjeff if (cmd.fd != (u32) (-1)) { 2452219820Sjeff /* search for file descriptor */ 2453219820Sjeff f = fget(cmd.fd); 2454219820Sjeff if (!f) { 2455219820Sjeff ret = -EBADF; 2456219820Sjeff goto err_table_mutex_unlock; 2457219820Sjeff } 2458219820Sjeff 2459219820Sjeff inode = xrc_file2inode(f); 2460219820Sjeff if (!inode) { 2461219820Sjeff ret = -EBADF; 2462219820Sjeff goto err_table_mutex_unlock; 2463219820Sjeff } 2464219820Sjeff 2465219820Sjeff ret = find_xrcd(file->device->ib_dev, inode, &xrcd); 2466219820Sjeff if (ret && !(cmd.oflags & O_CREAT)) { 2467219820Sjeff /* no file descriptor. Need CREATE flag */ 2468219820Sjeff ret = -EAGAIN; 2469219820Sjeff goto err_table_mutex_unlock; 2470219820Sjeff } 2471219820Sjeff 2472219820Sjeff if (xrcd && cmd.oflags & O_EXCL) { 2473219820Sjeff ret = -EINVAL; 2474219820Sjeff goto err_table_mutex_unlock; 2475219820Sjeff } 2476219820Sjeff } 2477219820Sjeff 2478219820Sjeff xrcd_uobj = kmalloc(sizeof *xrcd_uobj, GFP_KERNEL); 2479219820Sjeff if (!xrcd_uobj) { 2480219820Sjeff ret = -ENOMEM; 2481219820Sjeff goto err_table_mutex_unlock; 2482219820Sjeff } 2483219820Sjeff 2484219820Sjeff uobj = &xrcd_uobj->uobject; 2485219820Sjeff init_uobj(uobj, 0, file->ucontext, &pd_lock_key); 2486219820Sjeff down_write(&uobj->mutex); 2487219820Sjeff 2488219820Sjeff if (!xrcd) { 2489219820Sjeff xrcd = file->device->ib_dev->alloc_xrcd(file->device->ib_dev, 2490219820Sjeff file->ucontext, &udata); 2491219820Sjeff if (IS_ERR(xrcd)) { 2492219820Sjeff ret = PTR_ERR(xrcd); 2493219820Sjeff goto err; 2494219820Sjeff } 2495219820Sjeff xrcd->uobject = (cmd.fd == -1) ? uobj : NULL; 2496219820Sjeff xrcd->inode = inode; 2497219820Sjeff xrcd->device = file->device->ib_dev; 2498219820Sjeff atomic_set(&xrcd->usecnt, 0); 2499219820Sjeff new_xrcd = 1; 2500219820Sjeff } 2501219820Sjeff 2502219820Sjeff uobj->object = xrcd; 2503219820Sjeff ret = idr_add_uobj(&ib_uverbs_xrc_domain_idr, uobj); 2504219820Sjeff if (ret) 2505219820Sjeff goto err_idr; 2506219820Sjeff 2507219820Sjeff memset(&resp, 0, sizeof resp); 2508219820Sjeff resp.xrcd_handle = uobj->id; 2509219820Sjeff 2510219820Sjeff if (inode) { 2511219820Sjeff if (new_xrcd) { 2512219820Sjeff /* create new inode/xrcd table entry */ 2513219820Sjeff ret = xrcd_table_insert(file->device->ib_dev, inode, xrcd); 2514219820Sjeff if (ret) 2515219820Sjeff goto err_insert_xrcd; 2516219820Sjeff } 2517219820Sjeff atomic_inc(&xrcd->usecnt); 2518219820Sjeff } 2519219820Sjeff if (f) 2520219820Sjeff fput(f); 2521219820Sjeff 2522219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 2523219820Sjeff &resp, sizeof resp)) { 2524219820Sjeff ret = -EFAULT; 2525219820Sjeff goto err_copy; 2526219820Sjeff } 2527219820Sjeff 2528219820Sjeff INIT_LIST_HEAD(&xrcd_uobj->xrc_reg_qp_list); 2529219820Sjeff 2530219820Sjeff mutex_lock(&file->mutex); 2531255932Salfred list_add_tail(&uobj->list, &file->ucontext->xrcd_list); 2532219820Sjeff mutex_unlock(&file->mutex); 2533219820Sjeff 2534219820Sjeff uobj->live = 1; 2535219820Sjeff 2536219820Sjeff up_write(&uobj->mutex); 2537219820Sjeff 2538219820Sjeff mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); 2539219820Sjeff return in_len; 2540219820Sjeff 2541219820Sjefferr_copy: 2542219820Sjeff 2543219820Sjeff if (inode) { 2544219820Sjeff if (new_xrcd) 2545219820Sjeff xrcd_table_delete(file->device->ib_dev, inode); 2546219820Sjeff atomic_dec(&xrcd->usecnt); 2547219820Sjeff } 2548219820Sjeff 2549219820Sjefferr_insert_xrcd: 2550219820Sjeff idr_remove_uobj(&ib_uverbs_xrc_domain_idr, uobj); 2551219820Sjeff 2552219820Sjefferr_idr: 2553219820Sjeff ib_dealloc_xrcd(xrcd); 2554219820Sjeff 2555219820Sjefferr: 2556219820Sjeff put_uobj_write(uobj); 2557219820Sjeff 2558219820Sjefferr_table_mutex_unlock: 2559219820Sjeff 2560219820Sjeff if (f) 2561219820Sjeff fput(f); 2562219820Sjeff mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); 2563219820Sjeff return ret; 2564219820Sjeff} 2565219820Sjeff 2566219820Sjeffssize_t ib_uverbs_close_xrc_domain(struct ib_uverbs_file *file, 2567219820Sjeff const char __user *buf, int in_len, 2568219820Sjeff int out_len) 2569219820Sjeff{ 2570219820Sjeff struct ib_uverbs_close_xrc_domain cmd; 2571219820Sjeff struct ib_uobject *uobj, *t_uobj; 2572219820Sjeff struct ib_uxrcd_object *xrcd_uobj; 2573219820Sjeff struct ib_xrcd *xrcd = NULL; 2574219820Sjeff struct inode *inode = NULL; 2575219820Sjeff int ret = 0; 2576219820Sjeff 2577219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2578219820Sjeff return -EFAULT; 2579219820Sjeff 2580219820Sjeff mutex_lock(&file->device->ib_dev->xrcd_table_mutex); 2581219820Sjeff uobj = idr_write_uobj(&ib_uverbs_xrc_domain_idr, cmd.xrcd_handle, 2582219820Sjeff file->ucontext); 2583219820Sjeff if (!uobj) { 2584219820Sjeff ret = -EINVAL; 2585219820Sjeff goto err_unlock_mutex; 2586219820Sjeff } 2587219820Sjeff 2588219820Sjeff mutex_lock(&file->mutex); 2589219820Sjeff if (!ret) { 2590219820Sjeff list_for_each_entry(t_uobj, &file->ucontext->qp_list, list) { 2591219820Sjeff struct ib_qp *qp = t_uobj->object; 2592219820Sjeff if (qp->xrcd && qp->xrcd == uobj->object) { 2593219820Sjeff ret = -EBUSY; 2594219820Sjeff break; 2595219820Sjeff } 2596219820Sjeff } 2597219820Sjeff } 2598219820Sjeff if (!ret) { 2599219820Sjeff list_for_each_entry(t_uobj, &file->ucontext->srq_list, list) { 2600219820Sjeff struct ib_srq *srq = t_uobj->object; 2601255932Salfred if (srq->ext.xrc.xrcd && srq->ext.xrc.xrcd == uobj->object) { 2602219820Sjeff ret = -EBUSY; 2603219820Sjeff break; 2604219820Sjeff } 2605219820Sjeff } 2606219820Sjeff } 2607219820Sjeff mutex_unlock(&file->mutex); 2608219820Sjeff if (ret) { 2609219820Sjeff put_uobj_write(uobj); 2610219820Sjeff goto err_unlock_mutex; 2611219820Sjeff } 2612219820Sjeff 2613219820Sjeff xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject); 2614219820Sjeff if (!list_empty(&xrcd_uobj->xrc_reg_qp_list)) { 2615219820Sjeff ret = -EBUSY; 2616219820Sjeff put_uobj_write(uobj); 2617219820Sjeff goto err_unlock_mutex; 2618219820Sjeff } 2619219820Sjeff 2620219820Sjeff xrcd = (struct ib_xrcd *) (uobj->object); 2621219820Sjeff inode = xrcd->inode; 2622219820Sjeff 2623219820Sjeff if (inode) 2624219820Sjeff atomic_dec(&xrcd->usecnt); 2625219820Sjeff 2626219820Sjeff ret = ib_dealloc_xrcd(uobj->object); 2627219820Sjeff if (!ret) 2628219820Sjeff uobj->live = 0; 2629219820Sjeff 2630219820Sjeff put_uobj_write(uobj); 2631219820Sjeff 2632219820Sjeff if (ret && !inode) 2633219820Sjeff goto err_unlock_mutex; 2634219820Sjeff 2635219820Sjeff if (!ret && inode) 2636219820Sjeff xrcd_table_delete(file->device->ib_dev, inode); 2637219820Sjeff 2638219820Sjeff idr_remove_uobj(&ib_uverbs_xrc_domain_idr, uobj); 2639219820Sjeff 2640219820Sjeff mutex_lock(&file->mutex); 2641219820Sjeff list_del(&uobj->list); 2642219820Sjeff mutex_unlock(&file->mutex); 2643219820Sjeff 2644219820Sjeff put_uobj(uobj); 2645219820Sjeff 2646219820Sjeff mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); 2647219820Sjeff return in_len; 2648219820Sjeff 2649219820Sjefferr_unlock_mutex: 2650219820Sjeff mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); 2651219820Sjeff return ret; 2652219820Sjeff} 2653219820Sjeff 2654219820Sjeffvoid ib_uverbs_dealloc_xrcd(struct ib_device *ib_dev, 2655219820Sjeff struct ib_xrcd *xrcd) 2656219820Sjeff{ 2657219820Sjeff struct inode *inode = NULL; 2658219820Sjeff int ret = 0; 2659219820Sjeff 2660219820Sjeff inode = xrcd->inode; 2661219820Sjeff if (inode) 2662219820Sjeff atomic_dec(&xrcd->usecnt); 2663219820Sjeff 2664219820Sjeff ret = ib_dealloc_xrcd(xrcd); 2665219820Sjeff if (!ret && inode) 2666219820Sjeff xrcd_table_delete(ib_dev, inode); 2667219820Sjeff} 2668219820Sjeff 2669219820Sjeffssize_t ib_uverbs_create_xrc_rcv_qp(struct ib_uverbs_file *file, 2670219820Sjeff const char __user *buf, int in_len, 2671219820Sjeff int out_len) 2672219820Sjeff{ 2673219820Sjeff struct ib_uverbs_create_xrc_rcv_qp cmd; 2674219820Sjeff struct ib_uverbs_create_xrc_rcv_qp_resp resp; 2675219820Sjeff struct ib_uxrc_rcv_object *obj; 2676219820Sjeff struct ib_qp_init_attr init_attr; 2677219820Sjeff struct ib_xrcd *xrcd; 2678219820Sjeff struct ib_uobject *uobj; 2679219820Sjeff struct ib_uxrcd_object *xrcd_uobj; 2680219820Sjeff u32 qp_num; 2681219820Sjeff int err; 2682219820Sjeff 2683219820Sjeff if (out_len < sizeof resp) 2684219820Sjeff return -ENOSPC; 2685219820Sjeff 2686219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2687219820Sjeff return -EFAULT; 2688219820Sjeff 2689219820Sjeff obj = kzalloc(sizeof *obj, GFP_KERNEL); 2690219820Sjeff if (!obj) 2691219820Sjeff return -ENOMEM; 2692219820Sjeff 2693219820Sjeff xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); 2694219820Sjeff if (!xrcd) { 2695219820Sjeff err = -EINVAL; 2696219820Sjeff goto err_out; 2697219820Sjeff } 2698219820Sjeff 2699219820Sjeff init_attr.event_handler = ib_uverbs_xrc_rcv_qp_event_handler; 2700219820Sjeff init_attr.qp_context = file; 2701219820Sjeff init_attr.srq = NULL; 2702219820Sjeff init_attr.sq_sig_type = 2703219820Sjeff cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; 2704219820Sjeff init_attr.qp_type = IB_QPT_XRC; 2705255932Salfred init_attr.xrcd = xrcd; 2706219820Sjeff 2707219820Sjeff init_attr.cap.max_send_wr = 1; 2708219820Sjeff init_attr.cap.max_recv_wr = 0; 2709219820Sjeff init_attr.cap.max_send_sge = 1; 2710219820Sjeff init_attr.cap.max_recv_sge = 0; 2711219820Sjeff init_attr.cap.max_inline_data = 0; 2712219820Sjeff 2713219820Sjeff err = xrcd->device->create_xrc_rcv_qp(&init_attr, &qp_num); 2714219820Sjeff if (err) 2715219820Sjeff goto err_put; 2716219820Sjeff 2717219820Sjeff memset(&resp, 0, sizeof resp); 2718219820Sjeff resp.qpn = qp_num; 2719219820Sjeff 2720219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 2721219820Sjeff &resp, sizeof resp)) { 2722219820Sjeff err = -EFAULT; 2723219820Sjeff goto err_destroy; 2724219820Sjeff } 2725219820Sjeff 2726219820Sjeff atomic_inc(&xrcd->usecnt); 2727219820Sjeff put_xrcd_read(uobj); 2728219820Sjeff obj->qp_num = qp_num; 2729219820Sjeff obj->domain_handle = cmd.xrc_domain_handle; 2730219820Sjeff xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject); 2731219820Sjeff mutex_lock(&file->device->ib_dev->xrcd_table_mutex); 2732219820Sjeff list_add_tail(&obj->list, &xrcd_uobj->xrc_reg_qp_list); 2733219820Sjeff mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); 2734219820Sjeff 2735219820Sjeff return in_len; 2736219820Sjeff 2737219820Sjefferr_destroy: 2738219820Sjeff xrcd->device->unreg_xrc_rcv_qp(xrcd, file, qp_num); 2739219820Sjefferr_put: 2740219820Sjeff put_xrcd_read(uobj); 2741219820Sjefferr_out: 2742219820Sjeff kfree(obj); 2743219820Sjeff return err; 2744219820Sjeff} 2745219820Sjeff 2746219820Sjeffssize_t ib_uverbs_modify_xrc_rcv_qp(struct ib_uverbs_file *file, 2747219820Sjeff const char __user *buf, int in_len, 2748219820Sjeff int out_len) 2749219820Sjeff{ 2750219820Sjeff struct ib_uverbs_modify_xrc_rcv_qp cmd; 2751219820Sjeff struct ib_qp_attr *attr; 2752219820Sjeff struct ib_xrcd *xrcd; 2753219820Sjeff struct ib_uobject *uobj; 2754219820Sjeff int err; 2755219820Sjeff 2756219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2757219820Sjeff return -EFAULT; 2758219820Sjeff 2759219820Sjeff attr = kzalloc(sizeof *attr, GFP_KERNEL); 2760219820Sjeff if (!attr) 2761219820Sjeff return -ENOMEM; 2762219820Sjeff 2763219820Sjeff xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); 2764219820Sjeff if (!xrcd) { 2765219820Sjeff kfree(attr); 2766219820Sjeff return -EINVAL; 2767219820Sjeff } 2768219820Sjeff 2769219820Sjeff attr->qp_state = cmd.qp_state; 2770219820Sjeff attr->cur_qp_state = cmd.cur_qp_state; 2771219820Sjeff attr->qp_access_flags = cmd.qp_access_flags; 2772219820Sjeff attr->pkey_index = cmd.pkey_index; 2773219820Sjeff attr->port_num = cmd.port_num; 2774219820Sjeff attr->path_mtu = cmd.path_mtu; 2775219820Sjeff attr->path_mig_state = cmd.path_mig_state; 2776219820Sjeff attr->qkey = cmd.qkey; 2777219820Sjeff attr->rq_psn = cmd.rq_psn; 2778219820Sjeff attr->sq_psn = cmd.sq_psn; 2779219820Sjeff attr->dest_qp_num = cmd.dest_qp_num; 2780219820Sjeff attr->alt_pkey_index = cmd.alt_pkey_index; 2781219820Sjeff attr->en_sqd_async_notify = cmd.en_sqd_async_notify; 2782219820Sjeff attr->max_rd_atomic = cmd.max_rd_atomic; 2783219820Sjeff attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic; 2784219820Sjeff attr->min_rnr_timer = cmd.min_rnr_timer; 2785219820Sjeff attr->port_num = cmd.port_num; 2786219820Sjeff attr->timeout = cmd.timeout; 2787219820Sjeff attr->retry_cnt = cmd.retry_cnt; 2788219820Sjeff attr->rnr_retry = cmd.rnr_retry; 2789219820Sjeff attr->alt_port_num = cmd.alt_port_num; 2790219820Sjeff attr->alt_timeout = cmd.alt_timeout; 2791219820Sjeff 2792219820Sjeff memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16); 2793219820Sjeff attr->ah_attr.grh.flow_label = cmd.dest.flow_label; 2794219820Sjeff attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index; 2795219820Sjeff attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit; 2796219820Sjeff attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class; 2797219820Sjeff attr->ah_attr.dlid = cmd.dest.dlid; 2798219820Sjeff attr->ah_attr.sl = cmd.dest.sl; 2799219820Sjeff attr->ah_attr.src_path_bits = cmd.dest.src_path_bits; 2800219820Sjeff attr->ah_attr.static_rate = cmd.dest.static_rate; 2801219820Sjeff attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0; 2802219820Sjeff attr->ah_attr.port_num = cmd.dest.port_num; 2803219820Sjeff 2804219820Sjeff memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16); 2805219820Sjeff attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label; 2806219820Sjeff attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index; 2807219820Sjeff attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit; 2808219820Sjeff attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class; 2809219820Sjeff attr->alt_ah_attr.dlid = cmd.alt_dest.dlid; 2810219820Sjeff attr->alt_ah_attr.sl = cmd.alt_dest.sl; 2811219820Sjeff attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits; 2812219820Sjeff attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate; 2813219820Sjeff attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0; 2814219820Sjeff attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; 2815219820Sjeff 2816219820Sjeff err = xrcd->device->modify_xrc_rcv_qp(xrcd, cmd.qp_num, attr, cmd.attr_mask); 2817219820Sjeff put_xrcd_read(uobj); 2818219820Sjeff kfree(attr); 2819219820Sjeff return err ? err : in_len; 2820219820Sjeff} 2821219820Sjeff 2822219820Sjeffssize_t ib_uverbs_query_xrc_rcv_qp(struct ib_uverbs_file *file, 2823219820Sjeff const char __user *buf, int in_len, 2824219820Sjeff int out_len) 2825219820Sjeff{ 2826219820Sjeff struct ib_uverbs_query_xrc_rcv_qp cmd; 2827219820Sjeff struct ib_uverbs_query_qp_resp resp; 2828219820Sjeff struct ib_qp_attr *attr; 2829219820Sjeff struct ib_qp_init_attr *init_attr; 2830219820Sjeff struct ib_xrcd *xrcd; 2831219820Sjeff struct ib_uobject *uobj; 2832219820Sjeff int ret; 2833219820Sjeff 2834219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2835219820Sjeff return -EFAULT; 2836219820Sjeff 2837219820Sjeff attr = kmalloc(sizeof *attr, GFP_KERNEL); 2838219820Sjeff init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL); 2839219820Sjeff if (!attr || !init_attr) { 2840219820Sjeff ret = -ENOMEM; 2841219820Sjeff goto out; 2842219820Sjeff } 2843219820Sjeff 2844219820Sjeff xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); 2845219820Sjeff if (!xrcd) { 2846219820Sjeff ret = -EINVAL; 2847219820Sjeff goto out; 2848219820Sjeff } 2849219820Sjeff 2850219820Sjeff ret = xrcd->device->query_xrc_rcv_qp(xrcd, cmd.qp_num, attr, 2851219820Sjeff cmd.attr_mask, init_attr); 2852219820Sjeff 2853219820Sjeff put_xrcd_read(uobj); 2854219820Sjeff 2855219820Sjeff if (ret) 2856219820Sjeff goto out; 2857219820Sjeff 2858219820Sjeff memset(&resp, 0, sizeof resp); 2859219820Sjeff resp.qp_state = attr->qp_state; 2860219820Sjeff resp.cur_qp_state = attr->cur_qp_state; 2861219820Sjeff resp.path_mtu = attr->path_mtu; 2862219820Sjeff resp.path_mig_state = attr->path_mig_state; 2863219820Sjeff resp.qkey = attr->qkey; 2864219820Sjeff resp.rq_psn = attr->rq_psn; 2865219820Sjeff resp.sq_psn = attr->sq_psn; 2866219820Sjeff resp.dest_qp_num = attr->dest_qp_num; 2867219820Sjeff resp.qp_access_flags = attr->qp_access_flags; 2868219820Sjeff resp.pkey_index = attr->pkey_index; 2869219820Sjeff resp.alt_pkey_index = attr->alt_pkey_index; 2870219820Sjeff resp.sq_draining = attr->sq_draining; 2871219820Sjeff resp.max_rd_atomic = attr->max_rd_atomic; 2872219820Sjeff resp.max_dest_rd_atomic = attr->max_dest_rd_atomic; 2873219820Sjeff resp.min_rnr_timer = attr->min_rnr_timer; 2874219820Sjeff resp.port_num = attr->port_num; 2875219820Sjeff resp.timeout = attr->timeout; 2876219820Sjeff resp.retry_cnt = attr->retry_cnt; 2877219820Sjeff resp.rnr_retry = attr->rnr_retry; 2878219820Sjeff resp.alt_port_num = attr->alt_port_num; 2879219820Sjeff resp.alt_timeout = attr->alt_timeout; 2880219820Sjeff 2881219820Sjeff memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16); 2882219820Sjeff resp.dest.flow_label = attr->ah_attr.grh.flow_label; 2883219820Sjeff resp.dest.sgid_index = attr->ah_attr.grh.sgid_index; 2884219820Sjeff resp.dest.hop_limit = attr->ah_attr.grh.hop_limit; 2885219820Sjeff resp.dest.traffic_class = attr->ah_attr.grh.traffic_class; 2886219820Sjeff resp.dest.dlid = attr->ah_attr.dlid; 2887219820Sjeff resp.dest.sl = attr->ah_attr.sl; 2888219820Sjeff resp.dest.src_path_bits = attr->ah_attr.src_path_bits; 2889219820Sjeff resp.dest.static_rate = attr->ah_attr.static_rate; 2890219820Sjeff resp.dest.is_global = !!(attr->ah_attr.ah_flags & IB_AH_GRH); 2891219820Sjeff resp.dest.port_num = attr->ah_attr.port_num; 2892219820Sjeff 2893219820Sjeff memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16); 2894219820Sjeff resp.alt_dest.flow_label = attr->alt_ah_attr.grh.flow_label; 2895219820Sjeff resp.alt_dest.sgid_index = attr->alt_ah_attr.grh.sgid_index; 2896219820Sjeff resp.alt_dest.hop_limit = attr->alt_ah_attr.grh.hop_limit; 2897219820Sjeff resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class; 2898219820Sjeff resp.alt_dest.dlid = attr->alt_ah_attr.dlid; 2899219820Sjeff resp.alt_dest.sl = attr->alt_ah_attr.sl; 2900219820Sjeff resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits; 2901219820Sjeff resp.alt_dest.static_rate = attr->alt_ah_attr.static_rate; 2902219820Sjeff resp.alt_dest.is_global = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH); 2903219820Sjeff resp.alt_dest.port_num = attr->alt_ah_attr.port_num; 2904219820Sjeff 2905219820Sjeff resp.max_send_wr = init_attr->cap.max_send_wr; 2906219820Sjeff resp.max_recv_wr = init_attr->cap.max_recv_wr; 2907219820Sjeff resp.max_send_sge = init_attr->cap.max_send_sge; 2908219820Sjeff resp.max_recv_sge = init_attr->cap.max_recv_sge; 2909219820Sjeff resp.max_inline_data = init_attr->cap.max_inline_data; 2910219820Sjeff resp.sq_sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR; 2911219820Sjeff 2912219820Sjeff if (copy_to_user((void __user *) (unsigned long) cmd.response, 2913219820Sjeff &resp, sizeof resp)) 2914219820Sjeff ret = -EFAULT; 2915219820Sjeff 2916219820Sjeffout: 2917219820Sjeff kfree(attr); 2918219820Sjeff kfree(init_attr); 2919219820Sjeff 2920219820Sjeff return ret ? ret : in_len; 2921219820Sjeff} 2922219820Sjeff 2923219820Sjeffssize_t ib_uverbs_reg_xrc_rcv_qp(struct ib_uverbs_file *file, 2924219820Sjeff const char __user *buf, int in_len, 2925219820Sjeff int out_len) 2926219820Sjeff{ 2927219820Sjeff struct ib_uverbs_reg_xrc_rcv_qp cmd; 2928219820Sjeff struct ib_uxrc_rcv_object *qp_obj, *tmp; 2929219820Sjeff struct ib_xrcd *xrcd; 2930219820Sjeff struct ib_uobject *uobj; 2931219820Sjeff struct ib_uxrcd_object *xrcd_uobj; 2932219820Sjeff int ret; 2933219820Sjeff 2934219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2935219820Sjeff return -EFAULT; 2936219820Sjeff 2937219820Sjeff qp_obj = kmalloc(sizeof *qp_obj, GFP_KERNEL); 2938219820Sjeff if (!qp_obj) 2939219820Sjeff return -ENOMEM; 2940219820Sjeff 2941219820Sjeff xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); 2942219820Sjeff if (!xrcd) { 2943219820Sjeff ret = -EINVAL; 2944219820Sjeff goto err_out; 2945219820Sjeff } 2946219820Sjeff 2947219820Sjeff ret = xrcd->device->reg_xrc_rcv_qp(xrcd, file, cmd.qp_num); 2948219820Sjeff if (ret) 2949219820Sjeff goto err_put; 2950219820Sjeff 2951219820Sjeff xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject); 2952219820Sjeff mutex_lock(&file->device->ib_dev->xrcd_table_mutex); 2953219820Sjeff list_for_each_entry(tmp, &xrcd_uobj->xrc_reg_qp_list, list) 2954219820Sjeff if (cmd.qp_num == tmp->qp_num) { 2955219820Sjeff kfree(qp_obj); 2956219820Sjeff mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); 2957219820Sjeff put_xrcd_read(uobj); 2958219820Sjeff return in_len; 2959219820Sjeff } 2960219820Sjeff qp_obj->qp_num = cmd.qp_num; 2961219820Sjeff qp_obj->domain_handle = cmd.xrc_domain_handle; 2962219820Sjeff list_add_tail(&qp_obj->list, &xrcd_uobj->xrc_reg_qp_list); 2963219820Sjeff mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); 2964219820Sjeff atomic_inc(&xrcd->usecnt); 2965219820Sjeff put_xrcd_read(uobj); 2966219820Sjeff return in_len; 2967219820Sjeff 2968219820Sjefferr_put: 2969219820Sjeff put_xrcd_read(uobj); 2970219820Sjefferr_out: 2971219820Sjeff 2972219820Sjeff kfree(qp_obj); 2973219820Sjeff return ret; 2974219820Sjeff} 2975219820Sjeff 2976219820Sjeffint ib_uverbs_cleanup_xrc_rcv_qp(struct ib_uverbs_file *file, 2977219820Sjeff struct ib_xrcd *xrcd, u32 qp_num) 2978219820Sjeff{ 2979219820Sjeff int err; 2980219820Sjeff err = xrcd->device->unreg_xrc_rcv_qp(xrcd, file, qp_num); 2981219820Sjeff if (!err) 2982219820Sjeff atomic_dec(&xrcd->usecnt); 2983219820Sjeff return err; 2984219820Sjeff} 2985219820Sjeff 2986219820Sjeffssize_t ib_uverbs_unreg_xrc_rcv_qp(struct ib_uverbs_file *file, 2987219820Sjeff const char __user *buf, int in_len, 2988219820Sjeff int out_len) 2989219820Sjeff{ 2990219820Sjeff struct ib_uverbs_unreg_xrc_rcv_qp cmd; 2991219820Sjeff struct ib_uxrc_rcv_object *qp_obj, *tmp; 2992219820Sjeff struct ib_xrcd *xrcd; 2993219820Sjeff struct ib_uobject *uobj; 2994219820Sjeff struct ib_uxrcd_object *xrcd_uobj; 2995219820Sjeff int ret; 2996219820Sjeff 2997219820Sjeff if (copy_from_user(&cmd, buf, sizeof cmd)) 2998219820Sjeff return -EFAULT; 2999219820Sjeff 3000219820Sjeff xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); 3001219820Sjeff if (!xrcd) 3002219820Sjeff return -EINVAL; 3003219820Sjeff 3004219820Sjeff ret = xrcd->device->unreg_xrc_rcv_qp(xrcd, file, cmd.qp_num); 3005219820Sjeff if (ret) { 3006219820Sjeff put_xrcd_read(uobj); 3007219820Sjeff return -EINVAL; 3008219820Sjeff } 3009219820Sjeff atomic_dec(&xrcd->usecnt); 3010219820Sjeff 3011219820Sjeff xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject); 3012219820Sjeff mutex_lock(&file->device->ib_dev->xrcd_table_mutex); 3013219820Sjeff list_for_each_entry_safe(qp_obj, tmp, &xrcd_uobj->xrc_reg_qp_list, list) 3014219820Sjeff if (cmd.qp_num == qp_obj->qp_num) { 3015219820Sjeff list_del(&qp_obj->list); 3016219820Sjeff kfree(qp_obj); 3017219820Sjeff break; 3018219820Sjeff } 3019219820Sjeff mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); 3020219820Sjeff put_xrcd_read(uobj); 3021219820Sjeff return in_len; 3022219820Sjeff} 3023