1bc38a6abSRoland Dreier /*
2bc38a6abSRoland Dreier  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
3f7c6a7b5SRoland Dreier  * Copyright (c) 2005, 2006, 2007 Cisco Systems.  All rights reserved.
4eb9d3cd5SRoland Dreier  * Copyright (c) 2005 PathScale, Inc.  All rights reserved.
58bdb0e86SDotan Barak  * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.
6bc38a6abSRoland Dreier  *
7bc38a6abSRoland Dreier  * This software is available to you under a choice of one of two
8bc38a6abSRoland Dreier  * licenses.  You may choose to be licensed under the terms of the GNU
9bc38a6abSRoland Dreier  * General Public License (GPL) Version 2, available from the file
10bc38a6abSRoland Dreier  * COPYING in the main directory of this source tree, or the
11bc38a6abSRoland Dreier  * OpenIB.org BSD license below:
12bc38a6abSRoland Dreier  *
13bc38a6abSRoland Dreier  *     Redistribution and use in source and binary forms, with or
14bc38a6abSRoland Dreier  *     without modification, are permitted provided that the following
15bc38a6abSRoland Dreier  *     conditions are met:
16bc38a6abSRoland Dreier  *
17bc38a6abSRoland Dreier  *      - Redistributions of source code must retain the above
18bc38a6abSRoland Dreier  *        copyright notice, this list of conditions and the following
19bc38a6abSRoland Dreier  *        disclaimer.
20bc38a6abSRoland Dreier  *
21bc38a6abSRoland Dreier  *      - Redistributions in binary form must reproduce the above
22bc38a6abSRoland Dreier  *        copyright notice, this list of conditions and the following
23bc38a6abSRoland Dreier  *        disclaimer in the documentation and/or other materials
24bc38a6abSRoland Dreier  *        provided with the distribution.
25bc38a6abSRoland Dreier  *
26bc38a6abSRoland Dreier  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27bc38a6abSRoland Dreier  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28bc38a6abSRoland Dreier  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29bc38a6abSRoland Dreier  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30bc38a6abSRoland Dreier  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31bc38a6abSRoland Dreier  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32bc38a6abSRoland Dreier  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33bc38a6abSRoland Dreier  * SOFTWARE.
34bc38a6abSRoland Dreier  */
35bc38a6abSRoland Dreier 
366b73597eSRoland Dreier #include <linux/file.h>
3770a30e16SRoland Dreier #include <linux/fs.h>
385a0e3ad6STejun Heo #include <linux/slab.h>
398ada2c1cSShachar Raindel #include <linux/sched.h>
406b73597eSRoland Dreier 
417c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
42bc38a6abSRoland Dreier 
43fd3c7904SMatan Barak #include <rdma/uverbs_types.h>
44fd3c7904SMatan Barak #include <rdma/uverbs_std_types.h>
45fd3c7904SMatan Barak #include "rdma_core.h"
46fd3c7904SMatan Barak 
47bc38a6abSRoland Dreier #include "uverbs.h"
48ed4c54e5SOr Gerlitz #include "core_priv.h"
49bc38a6abSRoland Dreier 
50931373a1SJason Gunthorpe /*
51931373a1SJason Gunthorpe  * Copy a response to userspace. If the provided 'resp' is larger than the
52931373a1SJason Gunthorpe  * user buffer it is silently truncated. If the user provided a larger buffer
53931373a1SJason Gunthorpe  * then the trailing portion is zero filled.
54931373a1SJason Gunthorpe  *
55931373a1SJason Gunthorpe  * These semantics are intended to support future extension of the output
56931373a1SJason Gunthorpe  * structures.
57931373a1SJason Gunthorpe  */
uverbs_response(struct uverbs_attr_bundle * attrs,const void * resp,size_t resp_len)58931373a1SJason Gunthorpe static int uverbs_response(struct uverbs_attr_bundle *attrs, const void *resp,
59931373a1SJason Gunthorpe 			   size_t resp_len)
60931373a1SJason Gunthorpe {
61931373a1SJason Gunthorpe 	int ret;
62931373a1SJason Gunthorpe 
63d6f4a21fSJason Gunthorpe 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
64d6f4a21fSJason Gunthorpe 		return uverbs_copy_to_struct_or_zero(
65d6f4a21fSJason Gunthorpe 			attrs, UVERBS_ATTR_CORE_OUT, resp, resp_len);
66d6f4a21fSJason Gunthorpe 
67931373a1SJason Gunthorpe 	if (copy_to_user(attrs->ucore.outbuf, resp,
68931373a1SJason Gunthorpe 			 min(attrs->ucore.outlen, resp_len)))
69931373a1SJason Gunthorpe 		return -EFAULT;
70931373a1SJason Gunthorpe 
719435ef4cSLeon Romanovsky 	if (resp_len < attrs->ucore.outlen) {
729435ef4cSLeon Romanovsky 		/*
739435ef4cSLeon Romanovsky 		 * Zero fill any extra memory that user
749435ef4cSLeon Romanovsky 		 * space might have provided.
759435ef4cSLeon Romanovsky 		 */
769435ef4cSLeon Romanovsky 		ret = clear_user(attrs->ucore.outbuf + resp_len,
779435ef4cSLeon Romanovsky 				 attrs->ucore.outlen - resp_len);
78931373a1SJason Gunthorpe 		if (ret)
799435ef4cSLeon Romanovsky 			return -EFAULT;
80931373a1SJason Gunthorpe 	}
81931373a1SJason Gunthorpe 
82931373a1SJason Gunthorpe 	return 0;
83931373a1SJason Gunthorpe }
84931373a1SJason Gunthorpe 
853c2c2094SJason Gunthorpe /*
863c2c2094SJason Gunthorpe  * Copy a request from userspace. If the provided 'req' is larger than the
873c2c2094SJason Gunthorpe  * user buffer then the user buffer is zero extended into the 'req'. If 'req'
883c2c2094SJason Gunthorpe  * is smaller than the user buffer then the uncopied bytes in the user buffer
893c2c2094SJason Gunthorpe  * must be zero.
903c2c2094SJason Gunthorpe  */
uverbs_request(struct uverbs_attr_bundle * attrs,void * req,size_t req_len)913c2c2094SJason Gunthorpe static int uverbs_request(struct uverbs_attr_bundle *attrs, void *req,
923c2c2094SJason Gunthorpe 			  size_t req_len)
933c2c2094SJason Gunthorpe {
943c2c2094SJason Gunthorpe 	if (copy_from_user(req, attrs->ucore.inbuf,
953c2c2094SJason Gunthorpe 			   min(attrs->ucore.inlen, req_len)))
963c2c2094SJason Gunthorpe 		return -EFAULT;
973c2c2094SJason Gunthorpe 
983c2c2094SJason Gunthorpe 	if (attrs->ucore.inlen < req_len) {
993c2c2094SJason Gunthorpe 		memset(req + attrs->ucore.inlen, 0,
1003c2c2094SJason Gunthorpe 		       req_len - attrs->ucore.inlen);
1013c2c2094SJason Gunthorpe 	} else if (attrs->ucore.inlen > req_len) {
1023c2c2094SJason Gunthorpe 		if (!ib_is_buffer_cleared(attrs->ucore.inbuf + req_len,
1033c2c2094SJason Gunthorpe 					  attrs->ucore.inlen - req_len))
1043c2c2094SJason Gunthorpe 			return -EOPNOTSUPP;
1053c2c2094SJason Gunthorpe 	}
1063c2c2094SJason Gunthorpe 	return 0;
1073c2c2094SJason Gunthorpe }
1083c2c2094SJason Gunthorpe 
10929a29d18SJason Gunthorpe /*
11029a29d18SJason Gunthorpe  * Generate the value for the 'response_length' protocol used by write_ex.
11129a29d18SJason Gunthorpe  * This is the number of bytes the kernel actually wrote. Userspace can use
11229a29d18SJason Gunthorpe  * this to detect what structure members in the response the kernel
11329a29d18SJason Gunthorpe  * understood.
11429a29d18SJason Gunthorpe  */
uverbs_response_length(struct uverbs_attr_bundle * attrs,size_t resp_len)11529a29d18SJason Gunthorpe static u32 uverbs_response_length(struct uverbs_attr_bundle *attrs,
11629a29d18SJason Gunthorpe 				  size_t resp_len)
11729a29d18SJason Gunthorpe {
11829a29d18SJason Gunthorpe 	return min_t(size_t, attrs->ucore.outlen, resp_len);
11929a29d18SJason Gunthorpe }
12029a29d18SJason Gunthorpe 
121335708c7SJason Gunthorpe /*
122335708c7SJason Gunthorpe  * The iterator version of the request interface is for handlers that need to
123335708c7SJason Gunthorpe  * step over a flex array at the end of a command header.
124335708c7SJason Gunthorpe  */
125335708c7SJason Gunthorpe struct uverbs_req_iter {
126335708c7SJason Gunthorpe 	const void __user *cur;
127335708c7SJason Gunthorpe 	const void __user *end;
128335708c7SJason Gunthorpe };
129335708c7SJason Gunthorpe 
uverbs_request_start(struct uverbs_attr_bundle * attrs,struct uverbs_req_iter * iter,void * req,size_t req_len)130335708c7SJason Gunthorpe static int uverbs_request_start(struct uverbs_attr_bundle *attrs,
131335708c7SJason Gunthorpe 				struct uverbs_req_iter *iter,
132335708c7SJason Gunthorpe 				void *req,
133335708c7SJason Gunthorpe 				size_t req_len)
134335708c7SJason Gunthorpe {
135335708c7SJason Gunthorpe 	if (attrs->ucore.inlen < req_len)
136335708c7SJason Gunthorpe 		return -ENOSPC;
137335708c7SJason Gunthorpe 
138335708c7SJason Gunthorpe 	if (copy_from_user(req, attrs->ucore.inbuf, req_len))
139335708c7SJason Gunthorpe 		return -EFAULT;
140335708c7SJason Gunthorpe 
141335708c7SJason Gunthorpe 	iter->cur = attrs->ucore.inbuf + req_len;
142335708c7SJason Gunthorpe 	iter->end = attrs->ucore.inbuf + attrs->ucore.inlen;
143335708c7SJason Gunthorpe 	return 0;
144335708c7SJason Gunthorpe }
145335708c7SJason Gunthorpe 
uverbs_request_next(struct uverbs_req_iter * iter,void * val,size_t len)146335708c7SJason Gunthorpe static int uverbs_request_next(struct uverbs_req_iter *iter, void *val,
147335708c7SJason Gunthorpe 			       size_t len)
148335708c7SJason Gunthorpe {
149335708c7SJason Gunthorpe 	if (iter->cur + len > iter->end)
150335708c7SJason Gunthorpe 		return -ENOSPC;
151335708c7SJason Gunthorpe 
152335708c7SJason Gunthorpe 	if (copy_from_user(val, iter->cur, len))
153335708c7SJason Gunthorpe 		return -EFAULT;
154335708c7SJason Gunthorpe 
155335708c7SJason Gunthorpe 	iter->cur += len;
156335708c7SJason Gunthorpe 	return 0;
157335708c7SJason Gunthorpe }
158335708c7SJason Gunthorpe 
uverbs_request_next_ptr(struct uverbs_req_iter * iter,size_t len)159c3bea3d2SJason Gunthorpe static const void __user *uverbs_request_next_ptr(struct uverbs_req_iter *iter,
160c3bea3d2SJason Gunthorpe 						  size_t len)
161c3bea3d2SJason Gunthorpe {
162c3bea3d2SJason Gunthorpe 	const void __user *res = iter->cur;
163c3bea3d2SJason Gunthorpe 
164c3bea3d2SJason Gunthorpe 	if (iter->cur + len > iter->end)
1652dcdebffSBart Van Assche 		return (void __force __user *)ERR_PTR(-ENOSPC);
166c3bea3d2SJason Gunthorpe 	iter->cur += len;
167c3bea3d2SJason Gunthorpe 	return res;
168c3bea3d2SJason Gunthorpe }
169c3bea3d2SJason Gunthorpe 
uverbs_request_finish(struct uverbs_req_iter * iter)170335708c7SJason Gunthorpe static int uverbs_request_finish(struct uverbs_req_iter *iter)
171335708c7SJason Gunthorpe {
172335708c7SJason Gunthorpe 	if (!ib_is_buffer_cleared(iter->cur, iter->end - iter->cur))
173335708c7SJason Gunthorpe 		return -EOPNOTSUPP;
174335708c7SJason Gunthorpe 	return 0;
175335708c7SJason Gunthorpe }
176335708c7SJason Gunthorpe 
1776875cb17SJason Gunthorpe /*
1786875cb17SJason Gunthorpe  * When calling a destroy function during an error unwind we need to pass in
1796875cb17SJason Gunthorpe  * the udata that is sanitized of all user arguments. Ie from the driver
1806875cb17SJason Gunthorpe  * perspective it looks like no udata was passed.
1816875cb17SJason Gunthorpe  */
uverbs_get_cleared_udata(struct uverbs_attr_bundle * attrs)1826875cb17SJason Gunthorpe struct ib_udata *uverbs_get_cleared_udata(struct uverbs_attr_bundle *attrs)
1836875cb17SJason Gunthorpe {
1846875cb17SJason Gunthorpe 	attrs->driver_udata = (struct ib_udata){};
1856875cb17SJason Gunthorpe 	return &attrs->driver_udata;
1866875cb17SJason Gunthorpe }
1876875cb17SJason Gunthorpe 
1881e7710f3SMatan Barak static struct ib_uverbs_completion_event_file *
_ib_uverbs_lookup_comp_file(s32 fd,struct uverbs_attr_bundle * attrs)18970f06b26SShamir Rabinovitch _ib_uverbs_lookup_comp_file(s32 fd, struct uverbs_attr_bundle *attrs)
1901e7710f3SMatan Barak {
1911250c304SJason Gunthorpe 	struct ib_uobject *uobj = ufd_get_read(UVERBS_OBJECT_COMP_CHANNEL,
1928313c10fSJason Gunthorpe 					       fd, attrs);
1931e7710f3SMatan Barak 
1941e7710f3SMatan Barak 	if (IS_ERR(uobj))
1951e7710f3SMatan Barak 		return (void *)uobj;
1961e7710f3SMatan Barak 
1971e7710f3SMatan Barak 	uverbs_uobject_get(uobj);
1981e7710f3SMatan Barak 	uobj_put_read(uobj);
1991e7710f3SMatan Barak 
200d0259e82SJason Gunthorpe 	return container_of(uobj, struct ib_uverbs_completion_event_file,
201d0259e82SJason Gunthorpe 			    uobj);
2021e7710f3SMatan Barak }
2031250c304SJason Gunthorpe #define ib_uverbs_lookup_comp_file(_fd, _ufile)                                \
2041250c304SJason Gunthorpe 	_ib_uverbs_lookup_comp_file((_fd)*typecheck(s32, _fd), _ufile)
2051e7710f3SMatan Barak 
ib_alloc_ucontext(struct uverbs_attr_bundle * attrs)206a1123418SJason Gunthorpe int ib_alloc_ucontext(struct uverbs_attr_bundle *attrs)
207bc38a6abSRoland Dreier {
208a1123418SJason Gunthorpe 	struct ib_uverbs_file *ufile = attrs->ufile;
20963c47c28SRoland Dreier 	struct ib_ucontext *ucontext;
210bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
211bc38a6abSRoland Dreier 
212a1123418SJason Gunthorpe 	ib_dev = srcu_dereference(ufile->device->ib_dev,
213a1123418SJason Gunthorpe 				  &ufile->device->disassociate_srcu);
214a1123418SJason Gunthorpe 	if (!ib_dev)
215a1123418SJason Gunthorpe 		return -EIO;
216a1123418SJason Gunthorpe 
217a1123418SJason Gunthorpe 	ucontext = rdma_zalloc_drv_obj(ib_dev, ib_ucontext);
218a1123418SJason Gunthorpe 	if (!ucontext)
219a1123418SJason Gunthorpe 		return -ENOMEM;
220a1123418SJason Gunthorpe 
221a1123418SJason Gunthorpe 	ucontext->device = ib_dev;
222a1123418SJason Gunthorpe 	ucontext->ufile = ufile;
223a1123418SJason Gunthorpe 	xa_init_flags(&ucontext->mmap_xa, XA_FLAGS_ALLOC);
22413ef5539SLeon Romanovsky 
22513ef5539SLeon Romanovsky 	rdma_restrack_new(&ucontext->res, RDMA_RESTRACK_CTX);
226b09c4d70SLeon Romanovsky 	rdma_restrack_set_name(&ucontext->res, NULL);
227a1123418SJason Gunthorpe 	attrs->context = ucontext;
228a1123418SJason Gunthorpe 	return 0;
229a1123418SJason Gunthorpe }
230a1123418SJason Gunthorpe 
ib_init_ucontext(struct uverbs_attr_bundle * attrs)231a1123418SJason Gunthorpe int ib_init_ucontext(struct uverbs_attr_bundle *attrs)
232a1123418SJason Gunthorpe {
233a1123418SJason Gunthorpe 	struct ib_ucontext *ucontext = attrs->context;
234a1123418SJason Gunthorpe 	struct ib_uverbs_file *file = attrs->ufile;
235a1123418SJason Gunthorpe 	int ret;
236bc38a6abSRoland Dreier 
237da57db25SJason Gunthorpe 	if (!down_read_trylock(&file->hw_destroy_rwsem))
238da57db25SJason Gunthorpe 		return -EIO;
239e951747aSJason Gunthorpe 	mutex_lock(&file->ucontext_lock);
24063c47c28SRoland Dreier 	if (file->ucontext) {
24163c47c28SRoland Dreier 		ret = -EINVAL;
24263c47c28SRoland Dreier 		goto err;
24363c47c28SRoland Dreier 	}
24463c47c28SRoland Dreier 
245a1123418SJason Gunthorpe 	ret = ib_rdmacg_try_charge(&ucontext->cg_obj, ucontext->device,
246a1123418SJason Gunthorpe 				   RDMACG_RESOURCE_HCA_HANDLE);
24743579b5fSParav Pandit 	if (ret)
24843579b5fSParav Pandit 		goto err;
24943579b5fSParav Pandit 
250a1123418SJason Gunthorpe 	ret = ucontext->device->ops.alloc_ucontext(ucontext,
251a1123418SJason Gunthorpe 						   &attrs->driver_udata);
2529a073857SJason Gunthorpe 	if (ret)
253a1123418SJason Gunthorpe 		goto err_uncharge;
2546b73597eSRoland Dreier 
255b09c4d70SLeon Romanovsky 	rdma_restrack_add(&ucontext->res);
25612d23a91SLeon Romanovsky 
25722fa27fbSJason Gunthorpe 	/*
25822fa27fbSJason Gunthorpe 	 * Make sure that ib_uverbs_get_ucontext() sees the pointer update
25922fa27fbSJason Gunthorpe 	 * only after all writes to setup the ucontext have completed
26022fa27fbSJason Gunthorpe 	 */
26122fa27fbSJason Gunthorpe 	smp_store_release(&file->ucontext, ucontext);
26222fa27fbSJason Gunthorpe 
263e951747aSJason Gunthorpe 	mutex_unlock(&file->ucontext_lock);
264da57db25SJason Gunthorpe 	up_read(&file->hw_destroy_rwsem);
2657106a976SJason Gunthorpe 	return 0;
266bc38a6abSRoland Dreier 
267a1123418SJason Gunthorpe err_uncharge:
268a1123418SJason Gunthorpe 	ib_rdmacg_uncharge(&ucontext->cg_obj, ucontext->device,
269a1123418SJason Gunthorpe 			   RDMACG_RESOURCE_HCA_HANDLE);
27063c47c28SRoland Dreier err:
271e951747aSJason Gunthorpe 	mutex_unlock(&file->ucontext_lock);
272da57db25SJason Gunthorpe 	up_read(&file->hw_destroy_rwsem);
27363c47c28SRoland Dreier 	return ret;
274bc38a6abSRoland Dreier }
275bc38a6abSRoland Dreier 
ib_uverbs_get_context(struct uverbs_attr_bundle * attrs)276a1123418SJason Gunthorpe static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs)
277a1123418SJason Gunthorpe {
278a1123418SJason Gunthorpe 	struct ib_uverbs_get_context_resp resp;
279a1123418SJason Gunthorpe 	struct ib_uverbs_get_context cmd;
280a1123418SJason Gunthorpe 	struct ib_device *ib_dev;
281a1123418SJason Gunthorpe 	struct ib_uobject *uobj;
282a1123418SJason Gunthorpe 	int ret;
283a1123418SJason Gunthorpe 
284a1123418SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
285a1123418SJason Gunthorpe 	if (ret)
286a1123418SJason Gunthorpe 		return ret;
287a1123418SJason Gunthorpe 
288a1123418SJason Gunthorpe 	ret = ib_alloc_ucontext(attrs);
289a1123418SJason Gunthorpe 	if (ret)
290a1123418SJason Gunthorpe 		return ret;
291a1123418SJason Gunthorpe 
292a1123418SJason Gunthorpe 	uobj = uobj_alloc(UVERBS_OBJECT_ASYNC_EVENT, attrs, &ib_dev);
293a1123418SJason Gunthorpe 	if (IS_ERR(uobj)) {
294a1123418SJason Gunthorpe 		ret = PTR_ERR(uobj);
295a1123418SJason Gunthorpe 		goto err_ucontext;
296a1123418SJason Gunthorpe 	}
297a1123418SJason Gunthorpe 
298a1123418SJason Gunthorpe 	resp = (struct ib_uverbs_get_context_resp){
299a1123418SJason Gunthorpe 		.num_comp_vectors = attrs->ufile->device->num_comp_vectors,
300a1123418SJason Gunthorpe 		.async_fd = uobj->id,
301a1123418SJason Gunthorpe 	};
302a1123418SJason Gunthorpe 	ret = uverbs_response(attrs, &resp, sizeof(resp));
303a1123418SJason Gunthorpe 	if (ret)
304a1123418SJason Gunthorpe 		goto err_uobj;
305a1123418SJason Gunthorpe 
306a1123418SJason Gunthorpe 	ret = ib_init_ucontext(attrs);
307a1123418SJason Gunthorpe 	if (ret)
308a1123418SJason Gunthorpe 		goto err_uobj;
309a1123418SJason Gunthorpe 
310a1123418SJason Gunthorpe 	ib_uverbs_init_async_event_file(
311a1123418SJason Gunthorpe 		container_of(uobj, struct ib_uverbs_async_event_file, uobj));
312a1123418SJason Gunthorpe 	rdma_alloc_commit_uobject(uobj, attrs);
313a1123418SJason Gunthorpe 	return 0;
314a1123418SJason Gunthorpe 
315a1123418SJason Gunthorpe err_uobj:
3160ac8903cSJason Gunthorpe 	rdma_alloc_abort_uobject(uobj, attrs, false);
317a1123418SJason Gunthorpe err_ucontext:
31813ef5539SLeon Romanovsky 	rdma_restrack_put(&attrs->context->res);
319a1123418SJason Gunthorpe 	kfree(attrs->context);
320a1123418SJason Gunthorpe 	attrs->context = NULL;
321a1123418SJason Gunthorpe 	return ret;
322a1123418SJason Gunthorpe }
323a1123418SJason Gunthorpe 
copy_query_dev_fields(struct ib_ucontext * ucontext,struct ib_uverbs_query_device_resp * resp,struct ib_device_attr * attr)324bbd51e88SJason Gunthorpe static void copy_query_dev_fields(struct ib_ucontext *ucontext,
32502d1aa7aSEli Cohen 				  struct ib_uverbs_query_device_resp *resp,
32602d1aa7aSEli Cohen 				  struct ib_device_attr *attr)
32702d1aa7aSEli Cohen {
328bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev = ucontext->device;
329bbd51e88SJason Gunthorpe 
33002d1aa7aSEli Cohen 	resp->fw_ver		= attr->fw_ver;
331057aec0dSYishai Hadas 	resp->node_guid		= ib_dev->node_guid;
33202d1aa7aSEli Cohen 	resp->sys_image_guid	= attr->sys_image_guid;
33302d1aa7aSEli Cohen 	resp->max_mr_size	= attr->max_mr_size;
33402d1aa7aSEli Cohen 	resp->page_size_cap	= attr->page_size_cap;
33502d1aa7aSEli Cohen 	resp->vendor_id		= attr->vendor_id;
33602d1aa7aSEli Cohen 	resp->vendor_part_id	= attr->vendor_part_id;
33702d1aa7aSEli Cohen 	resp->hw_ver		= attr->hw_ver;
33802d1aa7aSEli Cohen 	resp->max_qp		= attr->max_qp;
33902d1aa7aSEli Cohen 	resp->max_qp_wr		= attr->max_qp_wr;
340e945c653SJason Gunthorpe 	resp->device_cap_flags  = lower_32_bits(attr->device_cap_flags);
34133023fb8SSteve Wise 	resp->max_sge		= min(attr->max_send_sge, attr->max_recv_sge);
34202d1aa7aSEli Cohen 	resp->max_sge_rd	= attr->max_sge_rd;
34302d1aa7aSEli Cohen 	resp->max_cq		= attr->max_cq;
34402d1aa7aSEli Cohen 	resp->max_cqe		= attr->max_cqe;
34502d1aa7aSEli Cohen 	resp->max_mr		= attr->max_mr;
34602d1aa7aSEli Cohen 	resp->max_pd		= attr->max_pd;
34702d1aa7aSEli Cohen 	resp->max_qp_rd_atom	= attr->max_qp_rd_atom;
34802d1aa7aSEli Cohen 	resp->max_ee_rd_atom	= attr->max_ee_rd_atom;
34902d1aa7aSEli Cohen 	resp->max_res_rd_atom	= attr->max_res_rd_atom;
35002d1aa7aSEli Cohen 	resp->max_qp_init_rd_atom	= attr->max_qp_init_rd_atom;
35102d1aa7aSEli Cohen 	resp->max_ee_init_rd_atom	= attr->max_ee_init_rd_atom;
35202d1aa7aSEli Cohen 	resp->atomic_cap		= attr->atomic_cap;
35302d1aa7aSEli Cohen 	resp->max_ee			= attr->max_ee;
35402d1aa7aSEli Cohen 	resp->max_rdd			= attr->max_rdd;
35502d1aa7aSEli Cohen 	resp->max_mw			= attr->max_mw;
35602d1aa7aSEli Cohen 	resp->max_raw_ipv6_qp		= attr->max_raw_ipv6_qp;
35702d1aa7aSEli Cohen 	resp->max_raw_ethy_qp		= attr->max_raw_ethy_qp;
35802d1aa7aSEli Cohen 	resp->max_mcast_grp		= attr->max_mcast_grp;
35902d1aa7aSEli Cohen 	resp->max_mcast_qp_attach	= attr->max_mcast_qp_attach;
36002d1aa7aSEli Cohen 	resp->max_total_mcast_qp_attach	= attr->max_total_mcast_qp_attach;
36102d1aa7aSEli Cohen 	resp->max_ah			= attr->max_ah;
36202d1aa7aSEli Cohen 	resp->max_srq			= attr->max_srq;
36302d1aa7aSEli Cohen 	resp->max_srq_wr		= attr->max_srq_wr;
36402d1aa7aSEli Cohen 	resp->max_srq_sge		= attr->max_srq_sge;
36502d1aa7aSEli Cohen 	resp->max_pkeys			= attr->max_pkeys;
36602d1aa7aSEli Cohen 	resp->local_ca_ack_delay	= attr->local_ca_ack_delay;
3671fb7f897SMark Bloch 	resp->phys_port_cnt = min_t(u32, ib_dev->phys_port_cnt, U8_MAX);
36802d1aa7aSEli Cohen }
36902d1aa7aSEli Cohen 
ib_uverbs_query_device(struct uverbs_attr_bundle * attrs)370974d6b4bSJason Gunthorpe static int ib_uverbs_query_device(struct uverbs_attr_bundle *attrs)
371bc38a6abSRoland Dreier {
372bc38a6abSRoland Dreier 	struct ib_uverbs_query_device      cmd;
373bc38a6abSRoland Dreier 	struct ib_uverbs_query_device_resp resp;
374bbd51e88SJason Gunthorpe 	struct ib_ucontext *ucontext;
3753c2c2094SJason Gunthorpe 	int ret;
376bbd51e88SJason Gunthorpe 
3778313c10fSJason Gunthorpe 	ucontext = ib_uverbs_get_ucontext(attrs);
378bbd51e88SJason Gunthorpe 	if (IS_ERR(ucontext))
379bbd51e88SJason Gunthorpe 		return PTR_ERR(ucontext);
380bc38a6abSRoland Dreier 
3813c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
3823c2c2094SJason Gunthorpe 	if (ret)
3833c2c2094SJason Gunthorpe 		return ret;
384bc38a6abSRoland Dreier 
385bc38a6abSRoland Dreier 	memset(&resp, 0, sizeof resp);
386bbd51e88SJason Gunthorpe 	copy_query_dev_fields(ucontext, &resp, &ucontext->device->attrs);
387bc38a6abSRoland Dreier 
3889a073857SJason Gunthorpe 	return uverbs_response(attrs, &resp, sizeof(resp));
389bc38a6abSRoland Dreier }
390bc38a6abSRoland Dreier 
ib_uverbs_query_port(struct uverbs_attr_bundle * attrs)391974d6b4bSJason Gunthorpe static int ib_uverbs_query_port(struct uverbs_attr_bundle *attrs)
392bc38a6abSRoland Dreier {
393bc38a6abSRoland Dreier 	struct ib_uverbs_query_port      cmd;
394bc38a6abSRoland Dreier 	struct ib_uverbs_query_port_resp resp;
395bc38a6abSRoland Dreier 	struct ib_port_attr              attr;
396bc38a6abSRoland Dreier 	int                              ret;
397bbd51e88SJason Gunthorpe 	struct ib_ucontext *ucontext;
398bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
399bbd51e88SJason Gunthorpe 
4008313c10fSJason Gunthorpe 	ucontext = ib_uverbs_get_ucontext(attrs);
401bbd51e88SJason Gunthorpe 	if (IS_ERR(ucontext))
402bbd51e88SJason Gunthorpe 		return PTR_ERR(ucontext);
403bbd51e88SJason Gunthorpe 	ib_dev = ucontext->device;
404bc38a6abSRoland Dreier 
4053c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
4063c2c2094SJason Gunthorpe 	if (ret)
4073c2c2094SJason Gunthorpe 		return ret;
408bc38a6abSRoland Dreier 
409057aec0dSYishai Hadas 	ret = ib_query_port(ib_dev, cmd.port_num, &attr);
410bc38a6abSRoland Dreier 	if (ret)
411bc38a6abSRoland Dreier 		return ret;
412bc38a6abSRoland Dreier 
413bc38a6abSRoland Dreier 	memset(&resp, 0, sizeof resp);
414641d1207SMichael Guralnik 	copy_port_attr_to_resp(&attr, &resp, ib_dev, cmd.port_num);
415bc38a6abSRoland Dreier 
4169a073857SJason Gunthorpe 	return uverbs_response(attrs, &resp, sizeof(resp));
417bc38a6abSRoland Dreier }
418bc38a6abSRoland Dreier 
ib_uverbs_alloc_pd(struct uverbs_attr_bundle * attrs)419974d6b4bSJason Gunthorpe static int ib_uverbs_alloc_pd(struct uverbs_attr_bundle *attrs)
420bc38a6abSRoland Dreier {
42116e51f78SLeon Romanovsky 	struct ib_uverbs_alloc_pd_resp resp = {};
422bc38a6abSRoland Dreier 	struct ib_uverbs_alloc_pd      cmd;
423bc38a6abSRoland Dreier 	struct ib_uobject             *uobj;
424bc38a6abSRoland Dreier 	struct ib_pd                  *pd;
425bc38a6abSRoland Dreier 	int                            ret;
426bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
427bc38a6abSRoland Dreier 
4283c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
4293c2c2094SJason Gunthorpe 	if (ret)
4303c2c2094SJason Gunthorpe 		return ret;
431bc38a6abSRoland Dreier 
4328313c10fSJason Gunthorpe 	uobj = uobj_alloc(UVERBS_OBJECT_PD, attrs, &ib_dev);
433fd3c7904SMatan Barak 	if (IS_ERR(uobj))
434fd3c7904SMatan Barak 		return PTR_ERR(uobj);
435bc38a6abSRoland Dreier 
43621a428a0SLeon Romanovsky 	pd = rdma_zalloc_drv_obj(ib_dev, ib_pd);
43721a428a0SLeon Romanovsky 	if (!pd) {
43821a428a0SLeon Romanovsky 		ret = -ENOMEM;
439bc38a6abSRoland Dreier 		goto err;
440bc38a6abSRoland Dreier 	}
441bc38a6abSRoland Dreier 
442057aec0dSYishai Hadas 	pd->device  = ib_dev;
443bc38a6abSRoland Dreier 	pd->uobject = uobj;
444bc38a6abSRoland Dreier 	atomic_set(&pd->usecnt, 0);
44521a428a0SLeon Romanovsky 
44613ef5539SLeon Romanovsky 	rdma_restrack_new(&pd->res, RDMA_RESTRACK_PD);
447b09c4d70SLeon Romanovsky 	rdma_restrack_set_name(&pd->res, NULL);
448b09c4d70SLeon Romanovsky 
449ff23dfa1SShamir Rabinovitch 	ret = ib_dev->ops.alloc_pd(pd, &attrs->driver_udata);
45021a428a0SLeon Romanovsky 	if (ret)
45121a428a0SLeon Romanovsky 		goto err_alloc;
452b09c4d70SLeon Romanovsky 	rdma_restrack_add(&pd->res);
453bc38a6abSRoland Dreier 
45416e51f78SLeon Romanovsky 	uobj->object = pd;
45516e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(uobj, attrs);
456bc38a6abSRoland Dreier 
45716e51f78SLeon Romanovsky 	resp.pd_handle = uobj->id;
45816e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
459bc38a6abSRoland Dreier 
46021a428a0SLeon Romanovsky err_alloc:
46113ef5539SLeon Romanovsky 	rdma_restrack_put(&pd->res);
46221a428a0SLeon Romanovsky 	kfree(pd);
463bc38a6abSRoland Dreier err:
464a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(uobj, attrs);
465bc38a6abSRoland Dreier 	return ret;
466bc38a6abSRoland Dreier }
467bc38a6abSRoland Dreier 
ib_uverbs_dealloc_pd(struct uverbs_attr_bundle * attrs)468974d6b4bSJason Gunthorpe static int ib_uverbs_dealloc_pd(struct uverbs_attr_bundle *attrs)
469bc38a6abSRoland Dreier {
470bc38a6abSRoland Dreier 	struct ib_uverbs_dealloc_pd cmd;
4713c2c2094SJason Gunthorpe 	int ret;
472bc38a6abSRoland Dreier 
4733c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
4743c2c2094SJason Gunthorpe 	if (ret)
4753c2c2094SJason Gunthorpe 		return ret;
476bc38a6abSRoland Dreier 
4777106a976SJason Gunthorpe 	return uobj_perform_destroy(UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
478bc38a6abSRoland Dreier }
479bc38a6abSRoland Dreier 
48053d0bd1eSSean Hefty struct xrcd_table_entry {
48153d0bd1eSSean Hefty 	struct rb_node  node;
48253d0bd1eSSean Hefty 	struct ib_xrcd *xrcd;
48353d0bd1eSSean Hefty 	struct inode   *inode;
48453d0bd1eSSean Hefty };
48553d0bd1eSSean Hefty 
xrcd_table_insert(struct ib_uverbs_device * dev,struct inode * inode,struct ib_xrcd * xrcd)48653d0bd1eSSean Hefty static int xrcd_table_insert(struct ib_uverbs_device *dev,
48753d0bd1eSSean Hefty 			    struct inode *inode,
48853d0bd1eSSean Hefty 			    struct ib_xrcd *xrcd)
48953d0bd1eSSean Hefty {
49053d0bd1eSSean Hefty 	struct xrcd_table_entry *entry, *scan;
49153d0bd1eSSean Hefty 	struct rb_node **p = &dev->xrcd_tree.rb_node;
49253d0bd1eSSean Hefty 	struct rb_node *parent = NULL;
49353d0bd1eSSean Hefty 
49453d0bd1eSSean Hefty 	entry = kmalloc(sizeof *entry, GFP_KERNEL);
49553d0bd1eSSean Hefty 	if (!entry)
49653d0bd1eSSean Hefty 		return -ENOMEM;
49753d0bd1eSSean Hefty 
49853d0bd1eSSean Hefty 	entry->xrcd  = xrcd;
49953d0bd1eSSean Hefty 	entry->inode = inode;
50053d0bd1eSSean Hefty 
50153d0bd1eSSean Hefty 	while (*p) {
50253d0bd1eSSean Hefty 		parent = *p;
50353d0bd1eSSean Hefty 		scan = rb_entry(parent, struct xrcd_table_entry, node);
50453d0bd1eSSean Hefty 
50553d0bd1eSSean Hefty 		if (inode < scan->inode) {
50653d0bd1eSSean Hefty 			p = &(*p)->rb_left;
50753d0bd1eSSean Hefty 		} else if (inode > scan->inode) {
50853d0bd1eSSean Hefty 			p = &(*p)->rb_right;
50953d0bd1eSSean Hefty 		} else {
51053d0bd1eSSean Hefty 			kfree(entry);
51153d0bd1eSSean Hefty 			return -EEXIST;
51253d0bd1eSSean Hefty 		}
51353d0bd1eSSean Hefty 	}
51453d0bd1eSSean Hefty 
51553d0bd1eSSean Hefty 	rb_link_node(&entry->node, parent, p);
51653d0bd1eSSean Hefty 	rb_insert_color(&entry->node, &dev->xrcd_tree);
51753d0bd1eSSean Hefty 	igrab(inode);
51853d0bd1eSSean Hefty 	return 0;
51953d0bd1eSSean Hefty }
52053d0bd1eSSean Hefty 
xrcd_table_search(struct ib_uverbs_device * dev,struct inode * inode)52153d0bd1eSSean Hefty static struct xrcd_table_entry *xrcd_table_search(struct ib_uverbs_device *dev,
52253d0bd1eSSean Hefty 						  struct inode *inode)
52353d0bd1eSSean Hefty {
52453d0bd1eSSean Hefty 	struct xrcd_table_entry *entry;
52553d0bd1eSSean Hefty 	struct rb_node *p = dev->xrcd_tree.rb_node;
52653d0bd1eSSean Hefty 
52753d0bd1eSSean Hefty 	while (p) {
52853d0bd1eSSean Hefty 		entry = rb_entry(p, struct xrcd_table_entry, node);
52953d0bd1eSSean Hefty 
53053d0bd1eSSean Hefty 		if (inode < entry->inode)
53153d0bd1eSSean Hefty 			p = p->rb_left;
53253d0bd1eSSean Hefty 		else if (inode > entry->inode)
53353d0bd1eSSean Hefty 			p = p->rb_right;
53453d0bd1eSSean Hefty 		else
53553d0bd1eSSean Hefty 			return entry;
53653d0bd1eSSean Hefty 	}
53753d0bd1eSSean Hefty 
53853d0bd1eSSean Hefty 	return NULL;
53953d0bd1eSSean Hefty }
54053d0bd1eSSean Hefty 
find_xrcd(struct ib_uverbs_device * dev,struct inode * inode)54153d0bd1eSSean Hefty static struct ib_xrcd *find_xrcd(struct ib_uverbs_device *dev, struct inode *inode)
54253d0bd1eSSean Hefty {
54353d0bd1eSSean Hefty 	struct xrcd_table_entry *entry;
54453d0bd1eSSean Hefty 
54553d0bd1eSSean Hefty 	entry = xrcd_table_search(dev, inode);
54653d0bd1eSSean Hefty 	if (!entry)
54753d0bd1eSSean Hefty 		return NULL;
54853d0bd1eSSean Hefty 
54953d0bd1eSSean Hefty 	return entry->xrcd;
55053d0bd1eSSean Hefty }
55153d0bd1eSSean Hefty 
xrcd_table_delete(struct ib_uverbs_device * dev,struct inode * inode)55253d0bd1eSSean Hefty static void xrcd_table_delete(struct ib_uverbs_device *dev,
55353d0bd1eSSean Hefty 			      struct inode *inode)
55453d0bd1eSSean Hefty {
55553d0bd1eSSean Hefty 	struct xrcd_table_entry *entry;
55653d0bd1eSSean Hefty 
55753d0bd1eSSean Hefty 	entry = xrcd_table_search(dev, inode);
55853d0bd1eSSean Hefty 	if (entry) {
55953d0bd1eSSean Hefty 		iput(inode);
56053d0bd1eSSean Hefty 		rb_erase(&entry->node, &dev->xrcd_tree);
56153d0bd1eSSean Hefty 		kfree(entry);
56253d0bd1eSSean Hefty 	}
56353d0bd1eSSean Hefty }
56453d0bd1eSSean Hefty 
ib_uverbs_open_xrcd(struct uverbs_attr_bundle * attrs)565974d6b4bSJason Gunthorpe static int ib_uverbs_open_xrcd(struct uverbs_attr_bundle *attrs)
56653d0bd1eSSean Hefty {
5678313c10fSJason Gunthorpe 	struct ib_uverbs_device *ibudev = attrs->ufile->device;
56816e51f78SLeon Romanovsky 	struct ib_uverbs_open_xrcd_resp	resp = {};
56953d0bd1eSSean Hefty 	struct ib_uverbs_open_xrcd	cmd;
57053d0bd1eSSean Hefty 	struct ib_uxrcd_object         *obj;
57153d0bd1eSSean Hefty 	struct ib_xrcd                 *xrcd = NULL;
57253d0bd1eSSean Hefty 	struct inode                   *inode = NULL;
57353d0bd1eSSean Hefty 	int				new_xrcd = 0;
574bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
57529f3fe1dSLeon Romanovsky 	struct fd f = {};
57629f3fe1dSLeon Romanovsky 	int ret;
57753d0bd1eSSean Hefty 
5783c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
5793c2c2094SJason Gunthorpe 	if (ret)
5803c2c2094SJason Gunthorpe 		return ret;
58153d0bd1eSSean Hefty 
5828313c10fSJason Gunthorpe 	mutex_lock(&ibudev->xrcd_tree_mutex);
58353d0bd1eSSean Hefty 
58453d0bd1eSSean Hefty 	if (cmd.fd != -1) {
58553d0bd1eSSean Hefty 		/* search for file descriptor */
5862903ff01SAl Viro 		f = fdget(cmd.fd);
5872903ff01SAl Viro 		if (!f.file) {
58853d0bd1eSSean Hefty 			ret = -EBADF;
58953d0bd1eSSean Hefty 			goto err_tree_mutex_unlock;
59053d0bd1eSSean Hefty 		}
59153d0bd1eSSean Hefty 
592496ad9aaSAl Viro 		inode = file_inode(f.file);
5938313c10fSJason Gunthorpe 		xrcd = find_xrcd(ibudev, inode);
59453d0bd1eSSean Hefty 		if (!xrcd && !(cmd.oflags & O_CREAT)) {
59553d0bd1eSSean Hefty 			/* no file descriptor. Need CREATE flag */
59653d0bd1eSSean Hefty 			ret = -EAGAIN;
59753d0bd1eSSean Hefty 			goto err_tree_mutex_unlock;
59853d0bd1eSSean Hefty 		}
59953d0bd1eSSean Hefty 
60053d0bd1eSSean Hefty 		if (xrcd && cmd.oflags & O_EXCL) {
60153d0bd1eSSean Hefty 			ret = -EINVAL;
60253d0bd1eSSean Hefty 			goto err_tree_mutex_unlock;
60353d0bd1eSSean Hefty 		}
60453d0bd1eSSean Hefty 	}
60553d0bd1eSSean Hefty 
6068313c10fSJason Gunthorpe 	obj = (struct ib_uxrcd_object *)uobj_alloc(UVERBS_OBJECT_XRCD, attrs,
607bbd51e88SJason Gunthorpe 						   &ib_dev);
608fd3c7904SMatan Barak 	if (IS_ERR(obj)) {
609fd3c7904SMatan Barak 		ret = PTR_ERR(obj);
61053d0bd1eSSean Hefty 		goto err_tree_mutex_unlock;
61153d0bd1eSSean Hefty 	}
61253d0bd1eSSean Hefty 
61353d0bd1eSSean Hefty 	if (!xrcd) {
614b73efcb2SMaor Gottlieb 		xrcd = ib_alloc_xrcd_user(ib_dev, inode, &attrs->driver_udata);
61553d0bd1eSSean Hefty 		if (IS_ERR(xrcd)) {
61653d0bd1eSSean Hefty 			ret = PTR_ERR(xrcd);
61753d0bd1eSSean Hefty 			goto err;
61853d0bd1eSSean Hefty 		}
61953d0bd1eSSean Hefty 		new_xrcd = 1;
62053d0bd1eSSean Hefty 	}
62153d0bd1eSSean Hefty 
62253d0bd1eSSean Hefty 	atomic_set(&obj->refcnt, 0);
62353d0bd1eSSean Hefty 	obj->uobject.object = xrcd;
62453d0bd1eSSean Hefty 
62553d0bd1eSSean Hefty 	if (inode) {
62653d0bd1eSSean Hefty 		if (new_xrcd) {
62753d0bd1eSSean Hefty 			/* create new inode/xrcd table entry */
6288313c10fSJason Gunthorpe 			ret = xrcd_table_insert(ibudev, inode, xrcd);
62953d0bd1eSSean Hefty 			if (ret)
630fd3c7904SMatan Barak 				goto err_dealloc_xrcd;
63153d0bd1eSSean Hefty 		}
63253d0bd1eSSean Hefty 		atomic_inc(&xrcd->usecnt);
63353d0bd1eSSean Hefty 	}
63453d0bd1eSSean Hefty 
6352903ff01SAl Viro 	if (f.file)
6362903ff01SAl Viro 		fdput(f);
63753d0bd1eSSean Hefty 
6388313c10fSJason Gunthorpe 	mutex_unlock(&ibudev->xrcd_tree_mutex);
63916e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(&obj->uobject, attrs);
6401ff5325cSLeon Romanovsky 
64116e51f78SLeon Romanovsky 	resp.xrcd_handle = obj->uobject.id;
64216e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
64353d0bd1eSSean Hefty 
644fd3c7904SMatan Barak err_dealloc_xrcd:
645b73efcb2SMaor Gottlieb 	ib_dealloc_xrcd_user(xrcd, uverbs_get_cleared_udata(attrs));
64653d0bd1eSSean Hefty 
64753d0bd1eSSean Hefty err:
648a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(&obj->uobject, attrs);
64953d0bd1eSSean Hefty 
65053d0bd1eSSean Hefty err_tree_mutex_unlock:
6512903ff01SAl Viro 	if (f.file)
6522903ff01SAl Viro 		fdput(f);
65353d0bd1eSSean Hefty 
6548313c10fSJason Gunthorpe 	mutex_unlock(&ibudev->xrcd_tree_mutex);
65553d0bd1eSSean Hefty 
65653d0bd1eSSean Hefty 	return ret;
65753d0bd1eSSean Hefty }
65853d0bd1eSSean Hefty 
ib_uverbs_close_xrcd(struct uverbs_attr_bundle * attrs)659974d6b4bSJason Gunthorpe static int ib_uverbs_close_xrcd(struct uverbs_attr_bundle *attrs)
66053d0bd1eSSean Hefty {
66153d0bd1eSSean Hefty 	struct ib_uverbs_close_xrcd cmd;
6623c2c2094SJason Gunthorpe 	int ret;
66353d0bd1eSSean Hefty 
6643c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
6653c2c2094SJason Gunthorpe 	if (ret)
6663c2c2094SJason Gunthorpe 		return ret;
66753d0bd1eSSean Hefty 
6687106a976SJason Gunthorpe 	return uobj_perform_destroy(UVERBS_OBJECT_XRCD, cmd.xrcd_handle, attrs);
66953d0bd1eSSean Hefty }
67053d0bd1eSSean Hefty 
ib_uverbs_dealloc_xrcd(struct ib_uobject * uobject,struct ib_xrcd * xrcd,enum rdma_remove_reason why,struct uverbs_attr_bundle * attrs)671c4367a26SShamir Rabinovitch int ib_uverbs_dealloc_xrcd(struct ib_uobject *uobject, struct ib_xrcd *xrcd,
672bdeacabdSShamir Rabinovitch 			   enum rdma_remove_reason why,
673bdeacabdSShamir Rabinovitch 			   struct uverbs_attr_bundle *attrs)
67453d0bd1eSSean Hefty {
67553d0bd1eSSean Hefty 	struct inode *inode;
6766be60aedSMatan Barak 	int ret;
677bdeacabdSShamir Rabinovitch 	struct ib_uverbs_device *dev = attrs->ufile->device;
67853d0bd1eSSean Hefty 
67953d0bd1eSSean Hefty 	inode = xrcd->inode;
68053d0bd1eSSean Hefty 	if (inode && !atomic_dec_and_test(&xrcd->usecnt))
6816be60aedSMatan Barak 		return 0;
68253d0bd1eSSean Hefty 
683b73efcb2SMaor Gottlieb 	ret = ib_dealloc_xrcd_user(xrcd, &attrs->driver_udata);
684efa968eeSLeon Romanovsky 	if (ret) {
6856be60aedSMatan Barak 		atomic_inc(&xrcd->usecnt);
6861c77483eSYishai Hadas 		return ret;
6871c77483eSYishai Hadas 	}
6881c77483eSYishai Hadas 
6891c77483eSYishai Hadas 	if (inode)
69053d0bd1eSSean Hefty 		xrcd_table_delete(dev, inode);
6916be60aedSMatan Barak 
692efa968eeSLeon Romanovsky 	return 0;
69353d0bd1eSSean Hefty }
69453d0bd1eSSean Hefty 
ib_uverbs_reg_mr(struct uverbs_attr_bundle * attrs)695974d6b4bSJason Gunthorpe static int ib_uverbs_reg_mr(struct uverbs_attr_bundle *attrs)
696bc38a6abSRoland Dreier {
69716e51f78SLeon Romanovsky 	struct ib_uverbs_reg_mr_resp resp = {};
698bc38a6abSRoland Dreier 	struct ib_uverbs_reg_mr      cmd;
699f7c6a7b5SRoland Dreier 	struct ib_uobject           *uobj;
700bc38a6abSRoland Dreier 	struct ib_pd                *pd;
701bc38a6abSRoland Dreier 	struct ib_mr                *mr;
702bc38a6abSRoland Dreier 	int                          ret;
703bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
704bc38a6abSRoland Dreier 
7053c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
7063c2c2094SJason Gunthorpe 	if (ret)
7073c2c2094SJason Gunthorpe 		return ret;
708bc38a6abSRoland Dreier 
709bc38a6abSRoland Dreier 	if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
710bc38a6abSRoland Dreier 		return -EINVAL;
711bc38a6abSRoland Dreier 
7128313c10fSJason Gunthorpe 	uobj = uobj_alloc(UVERBS_OBJECT_MR, attrs, &ib_dev);
713fd3c7904SMatan Barak 	if (IS_ERR(uobj))
714fd3c7904SMatan Barak 		return PTR_ERR(uobj);
715bc38a6abSRoland Dreier 
716adac4cb3SJason Gunthorpe 	ret = ib_check_mr_access(ib_dev, cmd.access_flags);
717adac4cb3SJason Gunthorpe 	if (ret)
718adac4cb3SJason Gunthorpe 		goto err_free;
719adac4cb3SJason Gunthorpe 
7208313c10fSJason Gunthorpe 	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
721aaf1aef5SRoland Dreier 	if (!pd) {
722aaf1aef5SRoland Dreier 		ret = -EINVAL;
723f7c6a7b5SRoland Dreier 		goto err_free;
724aaf1aef5SRoland Dreier 	}
725bc38a6abSRoland Dreier 
7263023a1e9SKamal Heib 	mr = pd->device->ops.reg_user_mr(pd, cmd.start, cmd.length, cmd.hca_va,
7273023a1e9SKamal Heib 					 cmd.access_flags,
7283023a1e9SKamal Heib 					 &attrs->driver_udata);
729bc38a6abSRoland Dreier 	if (IS_ERR(mr)) {
730bc38a6abSRoland Dreier 		ret = PTR_ERR(mr);
7319ead190bSRoland Dreier 		goto err_put;
732bc38a6abSRoland Dreier 	}
733bc38a6abSRoland Dreier 
734bc38a6abSRoland Dreier 	mr->device  = pd->device;
735bc38a6abSRoland Dreier 	mr->pd      = pd;
736a0bc099aSMax Gurtovoy 	mr->type    = IB_MR_TYPE_USER;
73754e7e48bSAriel Levkovich 	mr->dm	    = NULL;
7387c717d3aSMax Gurtovoy 	mr->sig_attrs = NULL;
739f7c6a7b5SRoland Dreier 	mr->uobject = uobj;
740bc38a6abSRoland Dreier 	atomic_inc(&pd->usecnt);
74104c0a5fcSYishai Hadas 	mr->iova = cmd.hca_va;
742241f9a27SDaisuke Matsuda 	mr->length = cmd.length;
74313ef5539SLeon Romanovsky 
74413ef5539SLeon Romanovsky 	rdma_restrack_new(&mr->res, RDMA_RESTRACK_MR);
745b09c4d70SLeon Romanovsky 	rdma_restrack_set_name(&mr->res, NULL);
746b09c4d70SLeon Romanovsky 	rdma_restrack_add(&mr->res);
747bc38a6abSRoland Dreier 
748f7c6a7b5SRoland Dreier 	uobj->object = mr;
74916e51f78SLeon Romanovsky 	uobj_put_obj_read(pd);
75016e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(uobj, attrs);
751bc38a6abSRoland Dreier 
7529ead190bSRoland Dreier 	resp.lkey = mr->lkey;
7539ead190bSRoland Dreier 	resp.rkey = mr->rkey;
754f7c6a7b5SRoland Dreier 	resp.mr_handle = uobj->id;
75516e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
756bc38a6abSRoland Dreier 
7579ead190bSRoland Dreier err_put:
758fd3c7904SMatan Barak 	uobj_put_obj_read(pd);
759bc38a6abSRoland Dreier err_free:
760a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(uobj, attrs);
761bc38a6abSRoland Dreier 	return ret;
762bc38a6abSRoland Dreier }
763bc38a6abSRoland Dreier 
ib_uverbs_rereg_mr(struct uverbs_attr_bundle * attrs)764974d6b4bSJason Gunthorpe static int ib_uverbs_rereg_mr(struct uverbs_attr_bundle *attrs)
7657e6edb9bSMatan Barak {
7667e6edb9bSMatan Barak 	struct ib_uverbs_rereg_mr      cmd;
7677e6edb9bSMatan Barak 	struct ib_uverbs_rereg_mr_resp resp;
7687e6edb9bSMatan Barak 	struct ib_mr                *mr;
7697e6edb9bSMatan Barak 	int                          ret;
7707e6edb9bSMatan Barak 	struct ib_uobject	    *uobj;
7716e0954b1SJason Gunthorpe 	struct ib_uobject *new_uobj;
7726e0954b1SJason Gunthorpe 	struct ib_device *ib_dev;
7736e0954b1SJason Gunthorpe 	struct ib_pd *orig_pd;
7746e0954b1SJason Gunthorpe 	struct ib_pd *new_pd;
7756e0954b1SJason Gunthorpe 	struct ib_mr *new_mr;
7767e6edb9bSMatan Barak 
7773c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
7783c2c2094SJason Gunthorpe 	if (ret)
7793c2c2094SJason Gunthorpe 		return ret;
7807e6edb9bSMatan Barak 
781b9653b31SJason Gunthorpe 	if (!cmd.flags)
7827e6edb9bSMatan Barak 		return -EINVAL;
7837e6edb9bSMatan Barak 
784b9653b31SJason Gunthorpe 	if (cmd.flags & ~IB_MR_REREG_SUPPORTED)
785b9653b31SJason Gunthorpe 		return -EOPNOTSUPP;
786b9653b31SJason Gunthorpe 
7877e6edb9bSMatan Barak 	if ((cmd.flags & IB_MR_REREG_TRANS) &&
788b9653b31SJason Gunthorpe 	    (cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
7897e6edb9bSMatan Barak 		return -EINVAL;
7907e6edb9bSMatan Barak 
7918313c10fSJason Gunthorpe 	uobj = uobj_get_write(UVERBS_OBJECT_MR, cmd.mr_handle, attrs);
792fd3c7904SMatan Barak 	if (IS_ERR(uobj))
793fd3c7904SMatan Barak 		return PTR_ERR(uobj);
7947e6edb9bSMatan Barak 
7957e6edb9bSMatan Barak 	mr = uobj->object;
7967e6edb9bSMatan Barak 
7975ccbf63fSAriel Levkovich 	if (mr->dm) {
7985ccbf63fSAriel Levkovich 		ret = -EINVAL;
7995ccbf63fSAriel Levkovich 		goto put_uobjs;
8005ccbf63fSAriel Levkovich 	}
8015ccbf63fSAriel Levkovich 
8027e6edb9bSMatan Barak 	if (cmd.flags & IB_MR_REREG_ACCESS) {
803adac4cb3SJason Gunthorpe 		ret = ib_check_mr_access(mr->device, cmd.access_flags);
8047e6edb9bSMatan Barak 		if (ret)
8057e6edb9bSMatan Barak 			goto put_uobjs;
8067e6edb9bSMatan Barak 	}
8077e6edb9bSMatan Barak 
8086e0954b1SJason Gunthorpe 	orig_pd = mr->pd;
8097e6edb9bSMatan Barak 	if (cmd.flags & IB_MR_REREG_PD) {
8106e0954b1SJason Gunthorpe 		new_pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle,
8118313c10fSJason Gunthorpe 					   attrs);
8126e0954b1SJason Gunthorpe 		if (!new_pd) {
8137e6edb9bSMatan Barak 			ret = -EINVAL;
8147e6edb9bSMatan Barak 			goto put_uobjs;
8157e6edb9bSMatan Barak 		}
8166e0954b1SJason Gunthorpe 	} else {
8176e0954b1SJason Gunthorpe 		new_pd = mr->pd;
8187e6edb9bSMatan Barak 	}
8197e6edb9bSMatan Barak 
8206e0954b1SJason Gunthorpe 	/*
8216e0954b1SJason Gunthorpe 	 * The driver might create a new HW object as part of the rereg, we need
8226e0954b1SJason Gunthorpe 	 * to have a uobject ready to hold it.
8236e0954b1SJason Gunthorpe 	 */
8246e0954b1SJason Gunthorpe 	new_uobj = uobj_alloc(UVERBS_OBJECT_MR, attrs, &ib_dev);
8256e0954b1SJason Gunthorpe 	if (IS_ERR(new_uobj)) {
8266e0954b1SJason Gunthorpe 		ret = PTR_ERR(new_uobj);
827e278173fSYuval Shaia 		goto put_uobj_pd;
8287e6edb9bSMatan Barak 	}
8297e6edb9bSMatan Barak 
8306e0954b1SJason Gunthorpe 	new_mr = ib_dev->ops.rereg_user_mr(mr, cmd.flags, cmd.start, cmd.length,
8316e0954b1SJason Gunthorpe 					   cmd.hca_va, cmd.access_flags, new_pd,
8326e0954b1SJason Gunthorpe 					   &attrs->driver_udata);
8336e0954b1SJason Gunthorpe 	if (IS_ERR(new_mr)) {
8346e0954b1SJason Gunthorpe 		ret = PTR_ERR(new_mr);
8356e0954b1SJason Gunthorpe 		goto put_new_uobj;
8366e0954b1SJason Gunthorpe 	}
8376e0954b1SJason Gunthorpe 	if (new_mr) {
8386e0954b1SJason Gunthorpe 		new_mr->device = new_pd->device;
8396e0954b1SJason Gunthorpe 		new_mr->pd = new_pd;
8406e0954b1SJason Gunthorpe 		new_mr->type = IB_MR_TYPE_USER;
8416e0954b1SJason Gunthorpe 		new_mr->uobject = uobj;
8426e0954b1SJason Gunthorpe 		atomic_inc(&new_pd->usecnt);
8436e0954b1SJason Gunthorpe 		new_uobj->object = new_mr;
8446e0954b1SJason Gunthorpe 
8456e0954b1SJason Gunthorpe 		rdma_restrack_new(&new_mr->res, RDMA_RESTRACK_MR);
8466e0954b1SJason Gunthorpe 		rdma_restrack_set_name(&new_mr->res, NULL);
8476e0954b1SJason Gunthorpe 		rdma_restrack_add(&new_mr->res);
8486e0954b1SJason Gunthorpe 
8496e0954b1SJason Gunthorpe 		/*
8506e0954b1SJason Gunthorpe 		 * The new uobj for the new HW object is put into the same spot
8516e0954b1SJason Gunthorpe 		 * in the IDR and the old uobj & HW object is deleted.
8526e0954b1SJason Gunthorpe 		 */
8536e0954b1SJason Gunthorpe 		rdma_assign_uobject(uobj, new_uobj, attrs);
8546e0954b1SJason Gunthorpe 		rdma_alloc_commit_uobject(new_uobj, attrs);
8556e0954b1SJason Gunthorpe 		uobj_put_destroy(uobj);
8566e0954b1SJason Gunthorpe 		new_uobj = NULL;
8576e0954b1SJason Gunthorpe 		uobj = NULL;
8586e0954b1SJason Gunthorpe 		mr = new_mr;
8596e0954b1SJason Gunthorpe 	} else {
8606e0954b1SJason Gunthorpe 		if (cmd.flags & IB_MR_REREG_PD) {
8616e0954b1SJason Gunthorpe 			atomic_dec(&orig_pd->usecnt);
8626e0954b1SJason Gunthorpe 			mr->pd = new_pd;
8636e0954b1SJason Gunthorpe 			atomic_inc(&new_pd->usecnt);
8646e0954b1SJason Gunthorpe 		}
865241f9a27SDaisuke Matsuda 		if (cmd.flags & IB_MR_REREG_TRANS) {
86604c0a5fcSYishai Hadas 			mr->iova = cmd.hca_va;
867241f9a27SDaisuke Matsuda 			mr->length = cmd.length;
868241f9a27SDaisuke Matsuda 		}
8696e0954b1SJason Gunthorpe 	}
87004c0a5fcSYishai Hadas 
8717e6edb9bSMatan Barak 	memset(&resp, 0, sizeof(resp));
8727e6edb9bSMatan Barak 	resp.lkey      = mr->lkey;
8737e6edb9bSMatan Barak 	resp.rkey      = mr->rkey;
8747e6edb9bSMatan Barak 
8759a073857SJason Gunthorpe 	ret = uverbs_response(attrs, &resp, sizeof(resp));
8767e6edb9bSMatan Barak 
8776e0954b1SJason Gunthorpe put_new_uobj:
8786e0954b1SJason Gunthorpe 	if (new_uobj)
8796e0954b1SJason Gunthorpe 		uobj_alloc_abort(new_uobj, attrs);
8807e6edb9bSMatan Barak put_uobj_pd:
8817e6edb9bSMatan Barak 	if (cmd.flags & IB_MR_REREG_PD)
8826e0954b1SJason Gunthorpe 		uobj_put_obj_read(new_pd);
8837e6edb9bSMatan Barak 
8847e6edb9bSMatan Barak put_uobjs:
8856e0954b1SJason Gunthorpe 	if (uobj)
886fd3c7904SMatan Barak 		uobj_put_write(uobj);
8877e6edb9bSMatan Barak 
8887e6edb9bSMatan Barak 	return ret;
8897e6edb9bSMatan Barak }
8907e6edb9bSMatan Barak 
ib_uverbs_dereg_mr(struct uverbs_attr_bundle * attrs)891974d6b4bSJason Gunthorpe static int ib_uverbs_dereg_mr(struct uverbs_attr_bundle *attrs)
892bc38a6abSRoland Dreier {
893bc38a6abSRoland Dreier 	struct ib_uverbs_dereg_mr cmd;
8943c2c2094SJason Gunthorpe 	int ret;
895bc38a6abSRoland Dreier 
8963c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
8973c2c2094SJason Gunthorpe 	if (ret)
8983c2c2094SJason Gunthorpe 		return ret;
899bc38a6abSRoland Dreier 
9007106a976SJason Gunthorpe 	return uobj_perform_destroy(UVERBS_OBJECT_MR, cmd.mr_handle, attrs);
901bc38a6abSRoland Dreier }
902bc38a6abSRoland Dreier 
ib_uverbs_alloc_mw(struct uverbs_attr_bundle * attrs)903974d6b4bSJason Gunthorpe static int ib_uverbs_alloc_mw(struct uverbs_attr_bundle *attrs)
9046b52a12bSShani Michaeli {
9056b52a12bSShani Michaeli 	struct ib_uverbs_alloc_mw      cmd;
906d18bb3e1SLeon Romanovsky 	struct ib_uverbs_alloc_mw_resp resp = {};
9076b52a12bSShani Michaeli 	struct ib_uobject             *uobj;
9086b52a12bSShani Michaeli 	struct ib_pd                  *pd;
9096b52a12bSShani Michaeli 	struct ib_mw                  *mw;
9106b52a12bSShani Michaeli 	int                            ret;
911bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
9126b52a12bSShani Michaeli 
9133c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
9143c2c2094SJason Gunthorpe 	if (ret)
9153c2c2094SJason Gunthorpe 		return ret;
9166b52a12bSShani Michaeli 
9178313c10fSJason Gunthorpe 	uobj = uobj_alloc(UVERBS_OBJECT_MW, attrs, &ib_dev);
918fd3c7904SMatan Barak 	if (IS_ERR(uobj))
919fd3c7904SMatan Barak 		return PTR_ERR(uobj);
9206b52a12bSShani Michaeli 
9218313c10fSJason Gunthorpe 	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
9226b52a12bSShani Michaeli 	if (!pd) {
9236b52a12bSShani Michaeli 		ret = -EINVAL;
9246b52a12bSShani Michaeli 		goto err_free;
9256b52a12bSShani Michaeli 	}
9266b52a12bSShani Michaeli 
927d0e02bf6SNoa Osherovich 	if (cmd.mw_type != IB_MW_TYPE_1 && cmd.mw_type != IB_MW_TYPE_2) {
928d0e02bf6SNoa Osherovich 		ret = -EINVAL;
929d0e02bf6SNoa Osherovich 		goto err_put;
930d0e02bf6SNoa Osherovich 	}
931d0e02bf6SNoa Osherovich 
932d18bb3e1SLeon Romanovsky 	mw = rdma_zalloc_drv_obj(ib_dev, ib_mw);
933d18bb3e1SLeon Romanovsky 	if (!mw) {
934d18bb3e1SLeon Romanovsky 		ret = -ENOMEM;
9356b52a12bSShani Michaeli 		goto err_put;
9366b52a12bSShani Michaeli 	}
9376b52a12bSShani Michaeli 
938d18bb3e1SLeon Romanovsky 	mw->device = ib_dev;
9396b52a12bSShani Michaeli 	mw->pd = pd;
9406b52a12bSShani Michaeli 	mw->uobject = uobj;
941d18bb3e1SLeon Romanovsky 	mw->type = cmd.mw_type;
942d18bb3e1SLeon Romanovsky 
943d18bb3e1SLeon Romanovsky 	ret = pd->device->ops.alloc_mw(mw, &attrs->driver_udata);
944d18bb3e1SLeon Romanovsky 	if (ret)
945d18bb3e1SLeon Romanovsky 		goto err_alloc;
946d18bb3e1SLeon Romanovsky 
9476b52a12bSShani Michaeli 	atomic_inc(&pd->usecnt);
9486b52a12bSShani Michaeli 
9496b52a12bSShani Michaeli 	uobj->object = mw;
95016e51f78SLeon Romanovsky 	uobj_put_obj_read(pd);
95116e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(uobj, attrs);
9526b52a12bSShani Michaeli 
9536b52a12bSShani Michaeli 	resp.rkey = mw->rkey;
9546b52a12bSShani Michaeli 	resp.mw_handle = uobj->id;
95516e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
9566b52a12bSShani Michaeli 
957d18bb3e1SLeon Romanovsky err_alloc:
958d18bb3e1SLeon Romanovsky 	kfree(mw);
9596b52a12bSShani Michaeli err_put:
960fd3c7904SMatan Barak 	uobj_put_obj_read(pd);
9616b52a12bSShani Michaeli err_free:
962a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(uobj, attrs);
9636b52a12bSShani Michaeli 	return ret;
9646b52a12bSShani Michaeli }
9656b52a12bSShani Michaeli 
ib_uverbs_dealloc_mw(struct uverbs_attr_bundle * attrs)966974d6b4bSJason Gunthorpe static int ib_uverbs_dealloc_mw(struct uverbs_attr_bundle *attrs)
9676b52a12bSShani Michaeli {
9686b52a12bSShani Michaeli 	struct ib_uverbs_dealloc_mw cmd;
9693c2c2094SJason Gunthorpe 	int ret;
9706b52a12bSShani Michaeli 
9713c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
9723c2c2094SJason Gunthorpe 	if (ret)
9733c2c2094SJason Gunthorpe 		return ret;
9746b52a12bSShani Michaeli 
9757106a976SJason Gunthorpe 	return uobj_perform_destroy(UVERBS_OBJECT_MW, cmd.mw_handle, attrs);
9766b52a12bSShani Michaeli }
9776b52a12bSShani Michaeli 
ib_uverbs_create_comp_channel(struct uverbs_attr_bundle * attrs)978974d6b4bSJason Gunthorpe static int ib_uverbs_create_comp_channel(struct uverbs_attr_bundle *attrs)
9796b73597eSRoland Dreier {
9806b73597eSRoland Dreier 	struct ib_uverbs_create_comp_channel	   cmd;
9816b73597eSRoland Dreier 	struct ib_uverbs_create_comp_channel_resp  resp;
9821e7710f3SMatan Barak 	struct ib_uobject			  *uobj;
9831e7710f3SMatan Barak 	struct ib_uverbs_completion_event_file	  *ev_file;
984bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
9859a073857SJason Gunthorpe 	int ret;
9866b73597eSRoland Dreier 
9873c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
9883c2c2094SJason Gunthorpe 	if (ret)
9893c2c2094SJason Gunthorpe 		return ret;
9906b73597eSRoland Dreier 
9918313c10fSJason Gunthorpe 	uobj = uobj_alloc(UVERBS_OBJECT_COMP_CHANNEL, attrs, &ib_dev);
9921e7710f3SMatan Barak 	if (IS_ERR(uobj))
9931e7710f3SMatan Barak 		return PTR_ERR(uobj);
994b1e4594bSAl Viro 
9951e7710f3SMatan Barak 	ev_file = container_of(uobj, struct ib_uverbs_completion_event_file,
996d0259e82SJason Gunthorpe 			       uobj);
997db1b5dddSMatan Barak 	ib_uverbs_init_event_queue(&ev_file->ev_queue);
99816e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(uobj, attrs);
9996b73597eSRoland Dreier 
100016e51f78SLeon Romanovsky 	resp.fd = uobj->id;
100116e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
10026b73597eSRoland Dreier }
10036b73597eSRoland Dreier 
create_cq(struct uverbs_attr_bundle * attrs,struct ib_uverbs_ex_create_cq * cmd)100416e51f78SLeon Romanovsky static int create_cq(struct uverbs_attr_bundle *attrs,
1005ece9ca97SJason Gunthorpe 		     struct ib_uverbs_ex_create_cq *cmd)
1006bc38a6abSRoland Dreier {
10079ead190bSRoland Dreier 	struct ib_ucq_object           *obj;
10081e7710f3SMatan Barak 	struct ib_uverbs_completion_event_file    *ev_file = NULL;
1009bc38a6abSRoland Dreier 	struct ib_cq                   *cq;
1010bc38a6abSRoland Dreier 	int                             ret;
101116e51f78SLeon Romanovsky 	struct ib_uverbs_ex_create_cq_resp resp = {};
1012bcf4c1eaSMatan Barak 	struct ib_cq_init_attr attr = {};
1013bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
101421885586SLeon Romanovsky 
10158313c10fSJason Gunthorpe 	if (cmd->comp_vector >= attrs->ufile->device->num_comp_vectors)
101616e51f78SLeon Romanovsky 		return -EINVAL;
1017bc38a6abSRoland Dreier 
10188313c10fSJason Gunthorpe 	obj = (struct ib_ucq_object *)uobj_alloc(UVERBS_OBJECT_CQ, attrs,
1019bbd51e88SJason Gunthorpe 						 &ib_dev);
1020fd3c7904SMatan Barak 	if (IS_ERR(obj))
102116e51f78SLeon Romanovsky 		return PTR_ERR(obj);
10229ead190bSRoland Dreier 
1023565197ddSMatan Barak 	if (cmd->comp_channel >= 0) {
10248313c10fSJason Gunthorpe 		ev_file = ib_uverbs_lookup_comp_file(cmd->comp_channel, attrs);
10251e7710f3SMatan Barak 		if (IS_ERR(ev_file)) {
10261e7710f3SMatan Barak 			ret = PTR_ERR(ev_file);
1027ac4e7b35SJack Morgenstein 			goto err;
1028ac4e7b35SJack Morgenstein 		}
1029ac4e7b35SJack Morgenstein 	}
1030ac4e7b35SJack Morgenstein 
10314ec1dcfcSJason Gunthorpe 	obj->uevent.uobject.user_handle = cmd->user_handle;
10329ead190bSRoland Dreier 	INIT_LIST_HEAD(&obj->comp_list);
10334ec1dcfcSJason Gunthorpe 	INIT_LIST_HEAD(&obj->uevent.event_list);
1034bc38a6abSRoland Dreier 
1035565197ddSMatan Barak 	attr.cqe = cmd->cqe;
1036565197ddSMatan Barak 	attr.comp_vector = cmd->comp_vector;
1037565197ddSMatan Barak 	attr.flags = cmd->flags;
1038565197ddSMatan Barak 
1039e39afe3dSLeon Romanovsky 	cq = rdma_zalloc_drv_obj(ib_dev, ib_cq);
1040e39afe3dSLeon Romanovsky 	if (!cq) {
1041e39afe3dSLeon Romanovsky 		ret = -ENOMEM;
10429ead190bSRoland Dreier 		goto err_file;
1043bc38a6abSRoland Dreier 	}
1044057aec0dSYishai Hadas 	cq->device        = ib_dev;
10455bd48c18SJason Gunthorpe 	cq->uobject       = obj;
1046bc38a6abSRoland Dreier 	cq->comp_handler  = ib_uverbs_comp_handler;
1047bc38a6abSRoland Dreier 	cq->event_handler = ib_uverbs_cq_event_handler;
1048699a2d5bSBharat Potnuri 	cq->cq_context    = ev_file ? &ev_file->ev_queue : NULL;
1049bc38a6abSRoland Dreier 	atomic_set(&cq->usecnt, 0);
1050bc38a6abSRoland Dreier 
105113ef5539SLeon Romanovsky 	rdma_restrack_new(&cq->res, RDMA_RESTRACK_CQ);
1052b09c4d70SLeon Romanovsky 	rdma_restrack_set_name(&cq->res, NULL);
1053b09c4d70SLeon Romanovsky 
1054e39afe3dSLeon Romanovsky 	ret = ib_dev->ops.create_cq(cq, &attr, &attrs->driver_udata);
1055e39afe3dSLeon Romanovsky 	if (ret)
1056e39afe3dSLeon Romanovsky 		goto err_free;
1057b09c4d70SLeon Romanovsky 	rdma_restrack_add(&cq->res);
1058e39afe3dSLeon Romanovsky 
10594ec1dcfcSJason Gunthorpe 	obj->uevent.uobject.object = cq;
106098a8890fSYishai Hadas 	obj->uevent.event_file = READ_ONCE(attrs->ufile->default_async_file);
106198a8890fSYishai Hadas 	if (obj->uevent.event_file)
106298a8890fSYishai Hadas 		uverbs_uobject_get(&obj->uevent.event_file->uobj);
106316e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
106498a8890fSYishai Hadas 
10654ec1dcfcSJason Gunthorpe 	resp.base.cq_handle = obj->uevent.uobject.id;
1066565197ddSMatan Barak 	resp.base.cqe = cq->cqe;
106729a29d18SJason Gunthorpe 	resp.response_length = uverbs_response_length(attrs, sizeof(resp));
106816e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
1069565197ddSMatan Barak 
1070e39afe3dSLeon Romanovsky err_free:
107113ef5539SLeon Romanovsky 	rdma_restrack_put(&cq->res);
1072e39afe3dSLeon Romanovsky 	kfree(cq);
10739ead190bSRoland Dreier err_file:
1074ac4e7b35SJack Morgenstein 	if (ev_file)
10755c55cfd6SJason Gunthorpe 		ib_uverbs_release_ucq(ev_file, obj);
10769ead190bSRoland Dreier err:
10774ec1dcfcSJason Gunthorpe 	uobj_alloc_abort(&obj->uevent.uobject, attrs);
107816e51f78SLeon Romanovsky 	return ret;
1079565197ddSMatan Barak }
1080565197ddSMatan Barak 
ib_uverbs_create_cq(struct uverbs_attr_bundle * attrs)1081974d6b4bSJason Gunthorpe static int ib_uverbs_create_cq(struct uverbs_attr_bundle *attrs)
1082565197ddSMatan Barak {
1083565197ddSMatan Barak 	struct ib_uverbs_create_cq      cmd;
1084565197ddSMatan Barak 	struct ib_uverbs_ex_create_cq	cmd_ex;
10853c2c2094SJason Gunthorpe 	int ret;
1086565197ddSMatan Barak 
10873c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
10883c2c2094SJason Gunthorpe 	if (ret)
10893c2c2094SJason Gunthorpe 		return ret;
1090565197ddSMatan Barak 
1091565197ddSMatan Barak 	memset(&cmd_ex, 0, sizeof(cmd_ex));
1092565197ddSMatan Barak 	cmd_ex.user_handle = cmd.user_handle;
1093565197ddSMatan Barak 	cmd_ex.cqe = cmd.cqe;
1094565197ddSMatan Barak 	cmd_ex.comp_vector = cmd.comp_vector;
1095565197ddSMatan Barak 	cmd_ex.comp_channel = cmd.comp_channel;
1096565197ddSMatan Barak 
109716e51f78SLeon Romanovsky 	return create_cq(attrs, &cmd_ex);
1098565197ddSMatan Barak }
1099565197ddSMatan Barak 
ib_uverbs_ex_create_cq(struct uverbs_attr_bundle * attrs)1100974d6b4bSJason Gunthorpe static int ib_uverbs_ex_create_cq(struct uverbs_attr_bundle *attrs)
1101565197ddSMatan Barak {
1102565197ddSMatan Barak 	struct ib_uverbs_ex_create_cq  cmd;
110329a29d18SJason Gunthorpe 	int ret;
1104565197ddSMatan Barak 
110529a29d18SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
110629a29d18SJason Gunthorpe 	if (ret)
110729a29d18SJason Gunthorpe 		return ret;
1108565197ddSMatan Barak 
1109565197ddSMatan Barak 	if (cmd.comp_mask)
1110565197ddSMatan Barak 		return -EINVAL;
1111565197ddSMatan Barak 
1112565197ddSMatan Barak 	if (cmd.reserved)
1113565197ddSMatan Barak 		return -EINVAL;
1114565197ddSMatan Barak 
111516e51f78SLeon Romanovsky 	return create_cq(attrs, &cmd);
1116bc38a6abSRoland Dreier }
1117bc38a6abSRoland Dreier 
ib_uverbs_resize_cq(struct uverbs_attr_bundle * attrs)1118974d6b4bSJason Gunthorpe static int ib_uverbs_resize_cq(struct uverbs_attr_bundle *attrs)
111933b9b3eeSRoland Dreier {
112033b9b3eeSRoland Dreier 	struct ib_uverbs_resize_cq	cmd;
1121f7a6cb7bSLeon Romanovsky 	struct ib_uverbs_resize_cq_resp	resp = {};
112233b9b3eeSRoland Dreier 	struct ib_cq			*cq;
112329f3fe1dSLeon Romanovsky 	int ret;
112433b9b3eeSRoland Dreier 
11253c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
11263c2c2094SJason Gunthorpe 	if (ret)
11273c2c2094SJason Gunthorpe 		return ret;
112833b9b3eeSRoland Dreier 
11298313c10fSJason Gunthorpe 	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
11309ead190bSRoland Dreier 	if (!cq)
11319ead190bSRoland Dreier 		return -EINVAL;
113233b9b3eeSRoland Dreier 
11333023a1e9SKamal Heib 	ret = cq->device->ops.resize_cq(cq, cmd.cqe, &attrs->driver_udata);
113433b9b3eeSRoland Dreier 	if (ret)
113533b9b3eeSRoland Dreier 		goto out;
113633b9b3eeSRoland Dreier 
113733b9b3eeSRoland Dreier 	resp.cqe = cq->cqe;
113833b9b3eeSRoland Dreier 
11399a073857SJason Gunthorpe 	ret = uverbs_response(attrs, &resp, sizeof(resp));
114033b9b3eeSRoland Dreier out:
11415bd48c18SJason Gunthorpe 	rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
11425bd48c18SJason Gunthorpe 				UVERBS_LOOKUP_READ);
114333b9b3eeSRoland Dreier 
11447106a976SJason Gunthorpe 	return ret;
114533b9b3eeSRoland Dreier }
114633b9b3eeSRoland Dreier 
copy_wc_to_user(struct ib_device * ib_dev,void __user * dest,struct ib_wc * wc)11477db20ecdSHiatt, Don static int copy_wc_to_user(struct ib_device *ib_dev, void __user *dest,
11487db20ecdSHiatt, Don 			   struct ib_wc *wc)
11497182afeaSDan Carpenter {
11507182afeaSDan Carpenter 	struct ib_uverbs_wc tmp;
11517182afeaSDan Carpenter 
11527182afeaSDan Carpenter 	tmp.wr_id		= wc->wr_id;
11537182afeaSDan Carpenter 	tmp.status		= wc->status;
11547182afeaSDan Carpenter 	tmp.opcode		= wc->opcode;
11557182afeaSDan Carpenter 	tmp.vendor_err		= wc->vendor_err;
11567182afeaSDan Carpenter 	tmp.byte_len		= wc->byte_len;
1157c966ea12SJason Gunthorpe 	tmp.ex.imm_data		= wc->ex.imm_data;
11587182afeaSDan Carpenter 	tmp.qp_num		= wc->qp->qp_num;
11597182afeaSDan Carpenter 	tmp.src_qp		= wc->src_qp;
11607182afeaSDan Carpenter 	tmp.wc_flags		= wc->wc_flags;
11617182afeaSDan Carpenter 	tmp.pkey_index		= wc->pkey_index;
11627db20ecdSHiatt, Don 	if (rdma_cap_opa_ah(ib_dev, wc->port_num))
11637db20ecdSHiatt, Don 		tmp.slid	= OPA_TO_IB_UCAST_LID(wc->slid);
11647db20ecdSHiatt, Don 	else
116562ede777SHiatt, Don 		tmp.slid	= ib_lid_cpu16(wc->slid);
11667182afeaSDan Carpenter 	tmp.sl			= wc->sl;
11677182afeaSDan Carpenter 	tmp.dlid_path_bits	= wc->dlid_path_bits;
11687182afeaSDan Carpenter 	tmp.port_num		= wc->port_num;
11697182afeaSDan Carpenter 	tmp.reserved		= 0;
11707182afeaSDan Carpenter 
11717182afeaSDan Carpenter 	if (copy_to_user(dest, &tmp, sizeof tmp))
11727182afeaSDan Carpenter 		return -EFAULT;
11737182afeaSDan Carpenter 
11747182afeaSDan Carpenter 	return 0;
11757182afeaSDan Carpenter }
11767182afeaSDan Carpenter 
ib_uverbs_poll_cq(struct uverbs_attr_bundle * attrs)1177974d6b4bSJason Gunthorpe static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs)
117867cdb40cSRoland Dreier {
117967cdb40cSRoland Dreier 	struct ib_uverbs_poll_cq       cmd;
11807182afeaSDan Carpenter 	struct ib_uverbs_poll_cq_resp  resp;
11817182afeaSDan Carpenter 	u8 __user                     *header_ptr;
11827182afeaSDan Carpenter 	u8 __user                     *data_ptr;
118367cdb40cSRoland Dreier 	struct ib_cq                  *cq;
11847182afeaSDan Carpenter 	struct ib_wc                   wc;
11857182afeaSDan Carpenter 	int                            ret;
118667cdb40cSRoland Dreier 
11873c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
11883c2c2094SJason Gunthorpe 	if (ret)
11893c2c2094SJason Gunthorpe 		return ret;
119067cdb40cSRoland Dreier 
11918313c10fSJason Gunthorpe 	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
11927182afeaSDan Carpenter 	if (!cq)
11937182afeaSDan Carpenter 		return -EINVAL;
11947182afeaSDan Carpenter 
11957182afeaSDan Carpenter 	/* we copy a struct ib_uverbs_poll_cq_resp to user space */
1196c2a939fdSJason Gunthorpe 	header_ptr = attrs->ucore.outbuf;
11977182afeaSDan Carpenter 	data_ptr = header_ptr + sizeof resp;
11987182afeaSDan Carpenter 
11997182afeaSDan Carpenter 	memset(&resp, 0, sizeof resp);
12007182afeaSDan Carpenter 	while (resp.count < cmd.ne) {
12017182afeaSDan Carpenter 		ret = ib_poll_cq(cq, 1, &wc);
12027182afeaSDan Carpenter 		if (ret < 0)
12037182afeaSDan Carpenter 			goto out_put;
12047182afeaSDan Carpenter 		if (!ret)
12057182afeaSDan Carpenter 			break;
12067182afeaSDan Carpenter 
1207bbd51e88SJason Gunthorpe 		ret = copy_wc_to_user(cq->device, data_ptr, &wc);
12087182afeaSDan Carpenter 		if (ret)
12097182afeaSDan Carpenter 			goto out_put;
12107182afeaSDan Carpenter 
12117182afeaSDan Carpenter 		data_ptr += sizeof(struct ib_uverbs_wc);
12127182afeaSDan Carpenter 		++resp.count;
121367cdb40cSRoland Dreier 	}
121467cdb40cSRoland Dreier 
12157182afeaSDan Carpenter 	if (copy_to_user(header_ptr, &resp, sizeof resp)) {
121667cdb40cSRoland Dreier 		ret = -EFAULT;
12177182afeaSDan Carpenter 		goto out_put;
12187182afeaSDan Carpenter 	}
12199a778678SJason Gunthorpe 	ret = 0;
122067cdb40cSRoland Dreier 
1221d6f4a21fSJason Gunthorpe 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT))
1222d6f4a21fSJason Gunthorpe 		ret = uverbs_output_written(attrs, UVERBS_ATTR_CORE_OUT);
1223d6f4a21fSJason Gunthorpe 
12247182afeaSDan Carpenter out_put:
12255bd48c18SJason Gunthorpe 	rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
12265bd48c18SJason Gunthorpe 				UVERBS_LOOKUP_READ);
12277182afeaSDan Carpenter 	return ret;
122867cdb40cSRoland Dreier }
122967cdb40cSRoland Dreier 
ib_uverbs_req_notify_cq(struct uverbs_attr_bundle * attrs)1230974d6b4bSJason Gunthorpe static int ib_uverbs_req_notify_cq(struct uverbs_attr_bundle *attrs)
123167cdb40cSRoland Dreier {
123267cdb40cSRoland Dreier 	struct ib_uverbs_req_notify_cq cmd;
123367cdb40cSRoland Dreier 	struct ib_cq                  *cq;
12343c2c2094SJason Gunthorpe 	int ret;
123567cdb40cSRoland Dreier 
12363c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
12373c2c2094SJason Gunthorpe 	if (ret)
12383c2c2094SJason Gunthorpe 		return ret;
123967cdb40cSRoland Dreier 
12408313c10fSJason Gunthorpe 	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
1241ab108676SRoland Dreier 	if (!cq)
12429ead190bSRoland Dreier 		return -EINVAL;
12439ead190bSRoland Dreier 
124467cdb40cSRoland Dreier 	ib_req_notify_cq(cq, cmd.solicited_only ?
124567cdb40cSRoland Dreier 			 IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
124667cdb40cSRoland Dreier 
12475bd48c18SJason Gunthorpe 	rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
12485bd48c18SJason Gunthorpe 				UVERBS_LOOKUP_READ);
12497106a976SJason Gunthorpe 	return 0;
125067cdb40cSRoland Dreier }
125167cdb40cSRoland Dreier 
ib_uverbs_destroy_cq(struct uverbs_attr_bundle * attrs)1252974d6b4bSJason Gunthorpe static int ib_uverbs_destroy_cq(struct uverbs_attr_bundle *attrs)
1253bc38a6abSRoland Dreier {
1254bc38a6abSRoland Dreier 	struct ib_uverbs_destroy_cq      cmd;
125563aaf647SRoland Dreier 	struct ib_uverbs_destroy_cq_resp resp;
12569ead190bSRoland Dreier 	struct ib_uobject		*uobj;
12579ead190bSRoland Dreier 	struct ib_ucq_object        	*obj;
12583c2c2094SJason Gunthorpe 	int ret;
1259bc38a6abSRoland Dreier 
12603c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
12613c2c2094SJason Gunthorpe 	if (ret)
12623c2c2094SJason Gunthorpe 		return ret;
1263bc38a6abSRoland Dreier 
12648313c10fSJason Gunthorpe 	uobj = uobj_get_destroy(UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
1265fd3c7904SMatan Barak 	if (IS_ERR(uobj))
1266fd3c7904SMatan Barak 		return PTR_ERR(uobj);
1267fd3c7904SMatan Barak 
12684ec1dcfcSJason Gunthorpe 	obj = container_of(uobj, struct ib_ucq_object, uevent.uobject);
1269fd3c7904SMatan Barak 	memset(&resp, 0, sizeof(resp));
12709ead190bSRoland Dreier 	resp.comp_events_reported  = obj->comp_events_reported;
12714ec1dcfcSJason Gunthorpe 	resp.async_events_reported = obj->uevent.events_reported;
127263aaf647SRoland Dreier 
127332ed5c00SJason Gunthorpe 	uobj_put_destroy(uobj);
127432ed5c00SJason Gunthorpe 
12759a073857SJason Gunthorpe 	return uverbs_response(attrs, &resp, sizeof(resp));
1276bc38a6abSRoland Dreier }
1277bc38a6abSRoland Dreier 
create_qp(struct uverbs_attr_bundle * attrs,struct ib_uverbs_ex_create_qp * cmd)12788313c10fSJason Gunthorpe static int create_qp(struct uverbs_attr_bundle *attrs,
1279ece9ca97SJason Gunthorpe 		     struct ib_uverbs_ex_create_qp *cmd)
1280bc38a6abSRoland Dreier {
12819ead190bSRoland Dreier 	struct ib_uqp_object		*obj;
1282b93f3c18SSean Hefty 	struct ib_device		*device;
1283b93f3c18SSean Hefty 	struct ib_pd			*pd = NULL;
1284b93f3c18SSean Hefty 	struct ib_xrcd			*xrcd = NULL;
1285fd3c7904SMatan Barak 	struct ib_uobject		*xrcd_uobj = ERR_PTR(-ENOENT);
1286b93f3c18SSean Hefty 	struct ib_cq			*scq = NULL, *rcq = NULL;
12879977f4f6SSean Hefty 	struct ib_srq			*srq = NULL;
1288bc38a6abSRoland Dreier 	struct ib_qp			*qp;
1289c70285f8SYishai Hadas 	struct ib_qp_init_attr		attr = {};
129016e51f78SLeon Romanovsky 	struct ib_uverbs_ex_create_qp_resp resp = {};
1291bc38a6abSRoland Dreier 	int				ret;
1292c70285f8SYishai Hadas 	struct ib_rwq_ind_table *ind_tbl = NULL;
1293c70285f8SYishai Hadas 	bool has_sq = true;
1294bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
1295bc38a6abSRoland Dreier 
12965807bb32SLeon Romanovsky 	switch (cmd->qp_type) {
12975807bb32SLeon Romanovsky 	case IB_QPT_RAW_PACKET:
12985807bb32SLeon Romanovsky 		if (!capable(CAP_NET_RAW))
1299c938a616SOr Gerlitz 			return -EPERM;
13005807bb32SLeon Romanovsky 		break;
13015807bb32SLeon Romanovsky 	case IB_QPT_RC:
13025807bb32SLeon Romanovsky 	case IB_QPT_UC:
13035807bb32SLeon Romanovsky 	case IB_QPT_UD:
13045807bb32SLeon Romanovsky 	case IB_QPT_XRC_INI:
13055807bb32SLeon Romanovsky 	case IB_QPT_XRC_TGT:
13065807bb32SLeon Romanovsky 	case IB_QPT_DRIVER:
13075807bb32SLeon Romanovsky 		break;
13085807bb32SLeon Romanovsky 	default:
13095807bb32SLeon Romanovsky 		return -EINVAL;
13105807bb32SLeon Romanovsky 	}
1311c938a616SOr Gerlitz 
13128313c10fSJason Gunthorpe 	obj = (struct ib_uqp_object *)uobj_alloc(UVERBS_OBJECT_QP, attrs,
1313bbd51e88SJason Gunthorpe 						 &ib_dev);
1314fd3c7904SMatan Barak 	if (IS_ERR(obj))
1315fd3c7904SMatan Barak 		return PTR_ERR(obj);
1316fd3c7904SMatan Barak 	obj->uxrcd = NULL;
1317fd3c7904SMatan Barak 	obj->uevent.uobject.user_handle = cmd->user_handle;
1318f48b7269SMatan Barak 	mutex_init(&obj->mcast_lock);
1319bc38a6abSRoland Dreier 
1320ece9ca97SJason Gunthorpe 	if (cmd->comp_mask & IB_UVERBS_CREATE_QP_MASK_IND_TABLE) {
13212cc1e3b8SJason Gunthorpe 		ind_tbl = uobj_get_obj_read(rwq_ind_table,
13222cc1e3b8SJason Gunthorpe 					    UVERBS_OBJECT_RWQ_IND_TBL,
13238313c10fSJason Gunthorpe 					    cmd->rwq_ind_tbl_handle, attrs);
1324c70285f8SYishai Hadas 		if (!ind_tbl) {
1325c70285f8SYishai Hadas 			ret = -EINVAL;
1326c70285f8SYishai Hadas 			goto err_put;
1327c70285f8SYishai Hadas 		}
1328c70285f8SYishai Hadas 
1329c70285f8SYishai Hadas 		attr.rwq_ind_tbl = ind_tbl;
1330c70285f8SYishai Hadas 	}
1331c70285f8SYishai Hadas 
1332c70285f8SYishai Hadas 	if (ind_tbl && (cmd->max_recv_wr || cmd->max_recv_sge || cmd->is_srq)) {
1333c70285f8SYishai Hadas 		ret = -EINVAL;
1334c70285f8SYishai Hadas 		goto err_put;
1335c70285f8SYishai Hadas 	}
1336c70285f8SYishai Hadas 
1337c70285f8SYishai Hadas 	if (ind_tbl && !cmd->max_send_wr)
1338c70285f8SYishai Hadas 		has_sq = false;
1339bc38a6abSRoland Dreier 
13406d8a7497SEran Ben Elisha 	if (cmd->qp_type == IB_QPT_XRC_TGT) {
13411f7ff9d5SMatan Barak 		xrcd_uobj = uobj_get_read(UVERBS_OBJECT_XRCD, cmd->pd_handle,
13428313c10fSJason Gunthorpe 					  attrs);
1343fd3c7904SMatan Barak 
1344fd3c7904SMatan Barak 		if (IS_ERR(xrcd_uobj)) {
1345fd3c7904SMatan Barak 			ret = -EINVAL;
1346fd3c7904SMatan Barak 			goto err_put;
1347fd3c7904SMatan Barak 		}
1348fd3c7904SMatan Barak 
1349fd3c7904SMatan Barak 		xrcd = (struct ib_xrcd *)xrcd_uobj->object;
1350b93f3c18SSean Hefty 		if (!xrcd) {
1351b93f3c18SSean Hefty 			ret = -EINVAL;
1352b93f3c18SSean Hefty 			goto err_put;
1353b93f3c18SSean Hefty 		}
1354b93f3c18SSean Hefty 		device = xrcd->device;
1355b93f3c18SSean Hefty 	} else {
13566d8a7497SEran Ben Elisha 		if (cmd->qp_type == IB_QPT_XRC_INI) {
13576d8a7497SEran Ben Elisha 			cmd->max_recv_wr = 0;
13586d8a7497SEran Ben Elisha 			cmd->max_recv_sge = 0;
13599977f4f6SSean Hefty 		} else {
13606d8a7497SEran Ben Elisha 			if (cmd->is_srq) {
13612cc1e3b8SJason Gunthorpe 				srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ,
13628313c10fSJason Gunthorpe 							cmd->srq_handle, attrs);
136338eb44faSArtemy Kovalyov 				if (!srq || srq->srq_type == IB_SRQT_XRC) {
13649977f4f6SSean Hefty 					ret = -EINVAL;
13659977f4f6SSean Hefty 					goto err_put;
13669977f4f6SSean Hefty 				}
13679977f4f6SSean Hefty 			}
13685909ce54SRoland Dreier 
1369c70285f8SYishai Hadas 			if (!ind_tbl) {
13706d8a7497SEran Ben Elisha 				if (cmd->recv_cq_handle != cmd->send_cq_handle) {
13712cc1e3b8SJason Gunthorpe 					rcq = uobj_get_obj_read(
13722cc1e3b8SJason Gunthorpe 						cq, UVERBS_OBJECT_CQ,
13738313c10fSJason Gunthorpe 						cmd->recv_cq_handle, attrs);
13749977f4f6SSean Hefty 					if (!rcq) {
13759977f4f6SSean Hefty 						ret = -EINVAL;
13769977f4f6SSean Hefty 						goto err_put;
13779977f4f6SSean Hefty 					}
13789977f4f6SSean Hefty 				}
13795909ce54SRoland Dreier 			}
1380c70285f8SYishai Hadas 		}
13815909ce54SRoland Dreier 
1382c70285f8SYishai Hadas 		if (has_sq)
13832cc1e3b8SJason Gunthorpe 			scq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
13848313c10fSJason Gunthorpe 						cmd->send_cq_handle, attrs);
1385efeb973fSXiao Yang 		if (!ind_tbl && cmd->qp_type != IB_QPT_XRC_INI)
13865909ce54SRoland Dreier 			rcq = rcq ?: scq;
13872cc1e3b8SJason Gunthorpe 		pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle,
13888313c10fSJason Gunthorpe 				       attrs);
1389c70285f8SYishai Hadas 		if (!pd || (!scq && has_sq)) {
13905909ce54SRoland Dreier 			ret = -EINVAL;
13915909ce54SRoland Dreier 			goto err_put;
13925909ce54SRoland Dreier 		}
13935909ce54SRoland Dreier 
1394b93f3c18SSean Hefty 		device = pd->device;
1395b93f3c18SSean Hefty 	}
13969977f4f6SSean Hefty 
1397bc38a6abSRoland Dreier 	attr.event_handler = ib_uverbs_qp_event_handler;
1398bc38a6abSRoland Dreier 	attr.send_cq       = scq;
1399bc38a6abSRoland Dreier 	attr.recv_cq       = rcq;
1400f520ba5aSRoland Dreier 	attr.srq           = srq;
1401b93f3c18SSean Hefty 	attr.xrcd	   = xrcd;
14026d8a7497SEran Ben Elisha 	attr.sq_sig_type   = cmd->sq_sig_all ? IB_SIGNAL_ALL_WR :
14036d8a7497SEran Ben Elisha 					      IB_SIGNAL_REQ_WR;
14046d8a7497SEran Ben Elisha 	attr.qp_type       = cmd->qp_type;
1405bc38a6abSRoland Dreier 
14066d8a7497SEran Ben Elisha 	attr.cap.max_send_wr     = cmd->max_send_wr;
14076d8a7497SEran Ben Elisha 	attr.cap.max_recv_wr     = cmd->max_recv_wr;
14086d8a7497SEran Ben Elisha 	attr.cap.max_send_sge    = cmd->max_send_sge;
14096d8a7497SEran Ben Elisha 	attr.cap.max_recv_sge    = cmd->max_recv_sge;
14106d8a7497SEran Ben Elisha 	attr.cap.max_inline_data = cmd->max_inline_data;
1411bc38a6abSRoland Dreier 
14129ead190bSRoland Dreier 	INIT_LIST_HEAD(&obj->uevent.event_list);
14139ead190bSRoland Dreier 	INIT_LIST_HEAD(&obj->mcast_list);
1414bc38a6abSRoland Dreier 
14156d8a7497SEran Ben Elisha 	attr.create_flags = cmd->create_flags;
14168a06ce59SLeon Romanovsky 	if (attr.create_flags & ~(IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK |
14178a06ce59SLeon Romanovsky 				IB_QP_CREATE_CROSS_CHANNEL |
14188a06ce59SLeon Romanovsky 				IB_QP_CREATE_MANAGED_SEND |
1419b531b909SMajd Dibbiny 				IB_QP_CREATE_MANAGED_RECV |
14209e1b161fSNoa Osherovich 				IB_QP_CREATE_SCATTER_FCS |
14212dee0e54SYishai Hadas 				IB_QP_CREATE_CVLAN_STRIPPING |
1422e1d2e887SNoa Osherovich 				IB_QP_CREATE_SOURCE_QPN |
1423e1d2e887SNoa Osherovich 				IB_QP_CREATE_PCI_WRITE_END_PADDING)) {
14246d8a7497SEran Ben Elisha 		ret = -EINVAL;
14256d8a7497SEran Ben Elisha 		goto err_put;
14266d8a7497SEran Ben Elisha 	}
14276d8a7497SEran Ben Elisha 
14282dee0e54SYishai Hadas 	if (attr.create_flags & IB_QP_CREATE_SOURCE_QPN) {
14292dee0e54SYishai Hadas 		if (!capable(CAP_NET_RAW)) {
14302dee0e54SYishai Hadas 			ret = -EPERM;
14312dee0e54SYishai Hadas 			goto err_put;
14322dee0e54SYishai Hadas 		}
14332dee0e54SYishai Hadas 
14342dee0e54SYishai Hadas 		attr.source_qpn = cmd->source_qpn;
14352dee0e54SYishai Hadas 	}
14362dee0e54SYishai Hadas 
1437d2b10794SLeon Romanovsky 	qp = ib_create_qp_user(device, pd, &attr, &attrs->driver_udata, obj,
1438d2b10794SLeon Romanovsky 			       KBUILD_MODNAME);
1439bc38a6abSRoland Dreier 	if (IS_ERR(qp)) {
1440bc38a6abSRoland Dreier 		ret = PTR_ERR(qp);
1441fd3c7904SMatan Barak 		goto err_put;
1442bc38a6abSRoland Dreier 	}
14435507f67dSLeon Romanovsky 	ib_qp_usecnt_inc(qp);
1444bc38a6abSRoland Dreier 
14459ead190bSRoland Dreier 	obj->uevent.uobject.object = qp;
144698a8890fSYishai Hadas 	obj->uevent.event_file = READ_ONCE(attrs->ufile->default_async_file);
144798a8890fSYishai Hadas 	if (obj->uevent.event_file)
144898a8890fSYishai Hadas 		uverbs_uobject_get(&obj->uevent.event_file->uobj);
1449bc38a6abSRoland Dreier 
1450846be90dSYishai Hadas 	if (xrcd) {
1451846be90dSYishai Hadas 		obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
1452846be90dSYishai Hadas 					  uobject);
1453846be90dSYishai Hadas 		atomic_inc(&obj->uxrcd->refcnt);
1454fd3c7904SMatan Barak 		uobj_put_read(xrcd_uobj);
1455846be90dSYishai Hadas 	}
1456846be90dSYishai Hadas 
1457b93f3c18SSean Hefty 	if (pd)
1458fd3c7904SMatan Barak 		uobj_put_obj_read(pd);
1459b93f3c18SSean Hefty 	if (scq)
14605bd48c18SJason Gunthorpe 		rdma_lookup_put_uobject(&scq->uobject->uevent.uobject,
14615bd48c18SJason Gunthorpe 					UVERBS_LOOKUP_READ);
14629977f4f6SSean Hefty 	if (rcq && rcq != scq)
14635bd48c18SJason Gunthorpe 		rdma_lookup_put_uobject(&rcq->uobject->uevent.uobject,
14645bd48c18SJason Gunthorpe 					UVERBS_LOOKUP_READ);
14659ead190bSRoland Dreier 	if (srq)
14669fbe334cSJason Gunthorpe 		rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
14679fbe334cSJason Gunthorpe 					UVERBS_LOOKUP_READ);
1468c70285f8SYishai Hadas 	if (ind_tbl)
1469fd3c7904SMatan Barak 		uobj_put_obj_read(ind_tbl);
147016e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
14719ead190bSRoland Dreier 
147216e51f78SLeon Romanovsky 	resp.base.qpn             = qp->qp_num;
147316e51f78SLeon Romanovsky 	resp.base.qp_handle       = obj->uevent.uobject.id;
147416e51f78SLeon Romanovsky 	resp.base.max_recv_sge    = attr.cap.max_recv_sge;
147516e51f78SLeon Romanovsky 	resp.base.max_send_sge    = attr.cap.max_send_sge;
147616e51f78SLeon Romanovsky 	resp.base.max_recv_wr     = attr.cap.max_recv_wr;
147716e51f78SLeon Romanovsky 	resp.base.max_send_wr     = attr.cap.max_send_wr;
147816e51f78SLeon Romanovsky 	resp.base.max_inline_data = attr.cap.max_inline_data;
147916e51f78SLeon Romanovsky 	resp.response_length = uverbs_response_length(attrs, sizeof(resp));
148016e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
148116e51f78SLeon Romanovsky 
14829ead190bSRoland Dreier err_put:
1483fd3c7904SMatan Barak 	if (!IS_ERR(xrcd_uobj))
1484fd3c7904SMatan Barak 		uobj_put_read(xrcd_uobj);
14859ead190bSRoland Dreier 	if (pd)
1486fd3c7904SMatan Barak 		uobj_put_obj_read(pd);
14879ead190bSRoland Dreier 	if (scq)
14885bd48c18SJason Gunthorpe 		rdma_lookup_put_uobject(&scq->uobject->uevent.uobject,
14895bd48c18SJason Gunthorpe 					UVERBS_LOOKUP_READ);
149043db2bc0SRoland Dreier 	if (rcq && rcq != scq)
14915bd48c18SJason Gunthorpe 		rdma_lookup_put_uobject(&rcq->uobject->uevent.uobject,
14925bd48c18SJason Gunthorpe 					UVERBS_LOOKUP_READ);
14939ead190bSRoland Dreier 	if (srq)
14949fbe334cSJason Gunthorpe 		rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
14959fbe334cSJason Gunthorpe 					UVERBS_LOOKUP_READ);
1496c70285f8SYishai Hadas 	if (ind_tbl)
1497fd3c7904SMatan Barak 		uobj_put_obj_read(ind_tbl);
1498bc38a6abSRoland Dreier 
1499a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(&obj->uevent.uobject, attrs);
1500bc38a6abSRoland Dreier 	return ret;
1501bc38a6abSRoland Dreier }
1502bc38a6abSRoland Dreier 
ib_uverbs_create_qp(struct uverbs_attr_bundle * attrs)1503974d6b4bSJason Gunthorpe static int ib_uverbs_create_qp(struct uverbs_attr_bundle *attrs)
15046d8a7497SEran Ben Elisha {
15056d8a7497SEran Ben Elisha 	struct ib_uverbs_create_qp      cmd;
15066d8a7497SEran Ben Elisha 	struct ib_uverbs_ex_create_qp	cmd_ex;
15073c2c2094SJason Gunthorpe 	int ret;
15086d8a7497SEran Ben Elisha 
15093c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
15103c2c2094SJason Gunthorpe 	if (ret)
15113c2c2094SJason Gunthorpe 		return ret;
15126d8a7497SEran Ben Elisha 
15136d8a7497SEran Ben Elisha 	memset(&cmd_ex, 0, sizeof(cmd_ex));
15146d8a7497SEran Ben Elisha 	cmd_ex.user_handle = cmd.user_handle;
15156d8a7497SEran Ben Elisha 	cmd_ex.pd_handle = cmd.pd_handle;
15166d8a7497SEran Ben Elisha 	cmd_ex.send_cq_handle = cmd.send_cq_handle;
15176d8a7497SEran Ben Elisha 	cmd_ex.recv_cq_handle = cmd.recv_cq_handle;
15186d8a7497SEran Ben Elisha 	cmd_ex.srq_handle = cmd.srq_handle;
15196d8a7497SEran Ben Elisha 	cmd_ex.max_send_wr = cmd.max_send_wr;
15206d8a7497SEran Ben Elisha 	cmd_ex.max_recv_wr = cmd.max_recv_wr;
15216d8a7497SEran Ben Elisha 	cmd_ex.max_send_sge = cmd.max_send_sge;
15226d8a7497SEran Ben Elisha 	cmd_ex.max_recv_sge = cmd.max_recv_sge;
15236d8a7497SEran Ben Elisha 	cmd_ex.max_inline_data = cmd.max_inline_data;
15246d8a7497SEran Ben Elisha 	cmd_ex.sq_sig_all = cmd.sq_sig_all;
15256d8a7497SEran Ben Elisha 	cmd_ex.qp_type = cmd.qp_type;
15266d8a7497SEran Ben Elisha 	cmd_ex.is_srq = cmd.is_srq;
15276d8a7497SEran Ben Elisha 
1528ece9ca97SJason Gunthorpe 	return create_qp(attrs, &cmd_ex);
15296d8a7497SEran Ben Elisha }
15306d8a7497SEran Ben Elisha 
ib_uverbs_ex_create_qp(struct uverbs_attr_bundle * attrs)1531974d6b4bSJason Gunthorpe static int ib_uverbs_ex_create_qp(struct uverbs_attr_bundle *attrs)
15326d8a7497SEran Ben Elisha {
153329a29d18SJason Gunthorpe 	struct ib_uverbs_ex_create_qp cmd;
153429a29d18SJason Gunthorpe 	int ret;
15356d8a7497SEran Ben Elisha 
153629a29d18SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
153729a29d18SJason Gunthorpe 	if (ret)
153829a29d18SJason Gunthorpe 		return ret;
15396d8a7497SEran Ben Elisha 
1540c70285f8SYishai Hadas 	if (cmd.comp_mask & ~IB_UVERBS_CREATE_QP_SUP_COMP_MASK)
15416d8a7497SEran Ben Elisha 		return -EINVAL;
15426d8a7497SEran Ben Elisha 
15436d8a7497SEran Ben Elisha 	if (cmd.reserved)
15446d8a7497SEran Ben Elisha 		return -EINVAL;
15456d8a7497SEran Ben Elisha 
1546ece9ca97SJason Gunthorpe 	return create_qp(attrs, &cmd);
15476d8a7497SEran Ben Elisha }
15486d8a7497SEran Ben Elisha 
ib_uverbs_open_qp(struct uverbs_attr_bundle * attrs)1549974d6b4bSJason Gunthorpe static int ib_uverbs_open_qp(struct uverbs_attr_bundle *attrs)
155042849b26SSean Hefty {
155116e51f78SLeon Romanovsky 	struct ib_uverbs_create_qp_resp resp = {};
155242849b26SSean Hefty 	struct ib_uverbs_open_qp        cmd;
155342849b26SSean Hefty 	struct ib_uqp_object           *obj;
155442849b26SSean Hefty 	struct ib_xrcd		       *xrcd;
155542849b26SSean Hefty 	struct ib_qp                   *qp;
1556817d6576SJason Gunthorpe 	struct ib_qp_open_attr          attr = {};
155742849b26SSean Hefty 	int ret;
155829f3fe1dSLeon Romanovsky 	struct ib_uobject *xrcd_uobj;
1559bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
156042849b26SSean Hefty 
15613c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
15623c2c2094SJason Gunthorpe 	if (ret)
15633c2c2094SJason Gunthorpe 		return ret;
156442849b26SSean Hefty 
15658313c10fSJason Gunthorpe 	obj = (struct ib_uqp_object *)uobj_alloc(UVERBS_OBJECT_QP, attrs,
1566bbd51e88SJason Gunthorpe 						 &ib_dev);
1567fd3c7904SMatan Barak 	if (IS_ERR(obj))
1568fd3c7904SMatan Barak 		return PTR_ERR(obj);
156942849b26SSean Hefty 
15708313c10fSJason Gunthorpe 	xrcd_uobj = uobj_get_read(UVERBS_OBJECT_XRCD, cmd.pd_handle, attrs);
1571fd3c7904SMatan Barak 	if (IS_ERR(xrcd_uobj)) {
157242849b26SSean Hefty 		ret = -EINVAL;
157342849b26SSean Hefty 		goto err_put;
157442849b26SSean Hefty 	}
157542849b26SSean Hefty 
1576fd3c7904SMatan Barak 	xrcd = (struct ib_xrcd *)xrcd_uobj->object;
1577fd3c7904SMatan Barak 	if (!xrcd) {
1578fd3c7904SMatan Barak 		ret = -EINVAL;
1579fd3c7904SMatan Barak 		goto err_xrcd;
1580fd3c7904SMatan Barak 	}
1581fd3c7904SMatan Barak 
158242849b26SSean Hefty 	attr.event_handler = ib_uverbs_qp_event_handler;
158342849b26SSean Hefty 	attr.qp_num        = cmd.qpn;
158442849b26SSean Hefty 	attr.qp_type       = cmd.qp_type;
158542849b26SSean Hefty 
158642849b26SSean Hefty 	INIT_LIST_HEAD(&obj->uevent.event_list);
158742849b26SSean Hefty 	INIT_LIST_HEAD(&obj->mcast_list);
158842849b26SSean Hefty 
158942849b26SSean Hefty 	qp = ib_open_qp(xrcd, &attr);
159042849b26SSean Hefty 	if (IS_ERR(qp)) {
159142849b26SSean Hefty 		ret = PTR_ERR(qp);
1592fd3c7904SMatan Barak 		goto err_xrcd;
159342849b26SSean Hefty 	}
159442849b26SSean Hefty 
159542849b26SSean Hefty 	obj->uevent.uobject.object = qp;
1596fd3c7904SMatan Barak 	obj->uevent.uobject.user_handle = cmd.user_handle;
159742849b26SSean Hefty 
1598846be90dSYishai Hadas 	obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object, uobject);
1599846be90dSYishai Hadas 	atomic_inc(&obj->uxrcd->refcnt);
1600620d3f81SJason Gunthorpe 	qp->uobject = obj;
1601fd3c7904SMatan Barak 	uobj_put_read(xrcd_uobj);
160216e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
160342849b26SSean Hefty 
160416e51f78SLeon Romanovsky 	resp.qpn = qp->qp_num;
160516e51f78SLeon Romanovsky 	resp.qp_handle = obj->uevent.uobject.id;
160616e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
160742849b26SSean Hefty 
1608fd3c7904SMatan Barak err_xrcd:
1609fd3c7904SMatan Barak 	uobj_put_read(xrcd_uobj);
161042849b26SSean Hefty err_put:
1611a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(&obj->uevent.uobject, attrs);
161242849b26SSean Hefty 	return ret;
161342849b26SSean Hefty }
161442849b26SSean Hefty 
copy_ah_attr_to_uverbs(struct ib_uverbs_qp_dest * uverb_attr,struct rdma_ah_attr * rdma_attr)161589caa053SParav Pandit static void copy_ah_attr_to_uverbs(struct ib_uverbs_qp_dest *uverb_attr,
161689caa053SParav Pandit 				   struct rdma_ah_attr *rdma_attr)
161789caa053SParav Pandit {
161889caa053SParav Pandit 	const struct ib_global_route   *grh;
161989caa053SParav Pandit 
162089caa053SParav Pandit 	uverb_attr->dlid              = rdma_ah_get_dlid(rdma_attr);
162189caa053SParav Pandit 	uverb_attr->sl                = rdma_ah_get_sl(rdma_attr);
162289caa053SParav Pandit 	uverb_attr->src_path_bits     = rdma_ah_get_path_bits(rdma_attr);
162389caa053SParav Pandit 	uverb_attr->static_rate       = rdma_ah_get_static_rate(rdma_attr);
162489caa053SParav Pandit 	uverb_attr->is_global         = !!(rdma_ah_get_ah_flags(rdma_attr) &
162589caa053SParav Pandit 					 IB_AH_GRH);
162689caa053SParav Pandit 	if (uverb_attr->is_global) {
162789caa053SParav Pandit 		grh = rdma_ah_read_grh(rdma_attr);
162889caa053SParav Pandit 		memcpy(uverb_attr->dgid, grh->dgid.raw, 16);
162989caa053SParav Pandit 		uverb_attr->flow_label        = grh->flow_label;
163089caa053SParav Pandit 		uverb_attr->sgid_index        = grh->sgid_index;
163189caa053SParav Pandit 		uverb_attr->hop_limit         = grh->hop_limit;
163289caa053SParav Pandit 		uverb_attr->traffic_class     = grh->traffic_class;
163389caa053SParav Pandit 	}
163489caa053SParav Pandit 	uverb_attr->port_num          = rdma_ah_get_port_num(rdma_attr);
163589caa053SParav Pandit }
163689caa053SParav Pandit 
ib_uverbs_query_qp(struct uverbs_attr_bundle * attrs)1637974d6b4bSJason Gunthorpe static int ib_uverbs_query_qp(struct uverbs_attr_bundle *attrs)
16387ccc9a24SDotan Barak {
16397ccc9a24SDotan Barak 	struct ib_uverbs_query_qp      cmd;
16407ccc9a24SDotan Barak 	struct ib_uverbs_query_qp_resp resp;
16417ccc9a24SDotan Barak 	struct ib_qp                   *qp;
16427ccc9a24SDotan Barak 	struct ib_qp_attr              *attr;
16437ccc9a24SDotan Barak 	struct ib_qp_init_attr         *init_attr;
16447ccc9a24SDotan Barak 	int                            ret;
16457ccc9a24SDotan Barak 
16463c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
16473c2c2094SJason Gunthorpe 	if (ret)
16483c2c2094SJason Gunthorpe 		return ret;
16497ccc9a24SDotan Barak 
16507ccc9a24SDotan Barak 	attr      = kmalloc(sizeof *attr, GFP_KERNEL);
16517ccc9a24SDotan Barak 	init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL);
16527ccc9a24SDotan Barak 	if (!attr || !init_attr) {
16537ccc9a24SDotan Barak 		ret = -ENOMEM;
16547ccc9a24SDotan Barak 		goto out;
16557ccc9a24SDotan Barak 	}
16567ccc9a24SDotan Barak 
16578313c10fSJason Gunthorpe 	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
16589ead190bSRoland Dreier 	if (!qp) {
16597ccc9a24SDotan Barak 		ret = -EINVAL;
16609ead190bSRoland Dreier 		goto out;
16619ead190bSRoland Dreier 	}
16627ccc9a24SDotan Barak 
16639ead190bSRoland Dreier 	ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr);
16649ead190bSRoland Dreier 
1665620d3f81SJason Gunthorpe 	rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
1666620d3f81SJason Gunthorpe 				UVERBS_LOOKUP_READ);
16677ccc9a24SDotan Barak 
16687ccc9a24SDotan Barak 	if (ret)
16697ccc9a24SDotan Barak 		goto out;
16707ccc9a24SDotan Barak 
16717ccc9a24SDotan Barak 	memset(&resp, 0, sizeof resp);
16727ccc9a24SDotan Barak 
16737ccc9a24SDotan Barak 	resp.qp_state               = attr->qp_state;
16747ccc9a24SDotan Barak 	resp.cur_qp_state           = attr->cur_qp_state;
16757ccc9a24SDotan Barak 	resp.path_mtu               = attr->path_mtu;
16767ccc9a24SDotan Barak 	resp.path_mig_state         = attr->path_mig_state;
16777ccc9a24SDotan Barak 	resp.qkey                   = attr->qkey;
16787ccc9a24SDotan Barak 	resp.rq_psn                 = attr->rq_psn;
16797ccc9a24SDotan Barak 	resp.sq_psn                 = attr->sq_psn;
16807ccc9a24SDotan Barak 	resp.dest_qp_num            = attr->dest_qp_num;
16817ccc9a24SDotan Barak 	resp.qp_access_flags        = attr->qp_access_flags;
16827ccc9a24SDotan Barak 	resp.pkey_index             = attr->pkey_index;
16837ccc9a24SDotan Barak 	resp.alt_pkey_index         = attr->alt_pkey_index;
16840b26c88fSJack Morgenstein 	resp.sq_draining            = attr->sq_draining;
16857ccc9a24SDotan Barak 	resp.max_rd_atomic          = attr->max_rd_atomic;
16867ccc9a24SDotan Barak 	resp.max_dest_rd_atomic     = attr->max_dest_rd_atomic;
16877ccc9a24SDotan Barak 	resp.min_rnr_timer          = attr->min_rnr_timer;
16887ccc9a24SDotan Barak 	resp.port_num               = attr->port_num;
16897ccc9a24SDotan Barak 	resp.timeout                = attr->timeout;
16907ccc9a24SDotan Barak 	resp.retry_cnt              = attr->retry_cnt;
16917ccc9a24SDotan Barak 	resp.rnr_retry              = attr->rnr_retry;
16927ccc9a24SDotan Barak 	resp.alt_port_num           = attr->alt_port_num;
16937ccc9a24SDotan Barak 	resp.alt_timeout            = attr->alt_timeout;
16947ccc9a24SDotan Barak 
169589caa053SParav Pandit 	copy_ah_attr_to_uverbs(&resp.dest, &attr->ah_attr);
169689caa053SParav Pandit 	copy_ah_attr_to_uverbs(&resp.alt_dest, &attr->alt_ah_attr);
16977ccc9a24SDotan Barak 
16987ccc9a24SDotan Barak 	resp.max_send_wr            = init_attr->cap.max_send_wr;
16997ccc9a24SDotan Barak 	resp.max_recv_wr            = init_attr->cap.max_recv_wr;
17007ccc9a24SDotan Barak 	resp.max_send_sge           = init_attr->cap.max_send_sge;
17017ccc9a24SDotan Barak 	resp.max_recv_sge           = init_attr->cap.max_recv_sge;
17027ccc9a24SDotan Barak 	resp.max_inline_data        = init_attr->cap.max_inline_data;
170327d56300SDotan Barak 	resp.sq_sig_all             = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
17047ccc9a24SDotan Barak 
17059a073857SJason Gunthorpe 	ret = uverbs_response(attrs, &resp, sizeof(resp));
17067ccc9a24SDotan Barak 
17077ccc9a24SDotan Barak out:
17087ccc9a24SDotan Barak 	kfree(attr);
17097ccc9a24SDotan Barak 	kfree(init_attr);
17107ccc9a24SDotan Barak 
17117106a976SJason Gunthorpe 	return ret;
17127ccc9a24SDotan Barak }
17137ccc9a24SDotan Barak 
17149977f4f6SSean Hefty /* Remove ignored fields set in the attribute mask */
modify_qp_mask(enum ib_qp_type qp_type,int mask)17159977f4f6SSean Hefty static int modify_qp_mask(enum ib_qp_type qp_type, int mask)
17169977f4f6SSean Hefty {
17179977f4f6SSean Hefty 	switch (qp_type) {
17189977f4f6SSean Hefty 	case IB_QPT_XRC_INI:
17199977f4f6SSean Hefty 		return mask & ~(IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_MIN_RNR_TIMER);
1720b93f3c18SSean Hefty 	case IB_QPT_XRC_TGT:
1721b93f3c18SSean Hefty 		return mask & ~(IB_QP_MAX_QP_RD_ATOMIC | IB_QP_RETRY_CNT |
1722b93f3c18SSean Hefty 				IB_QP_RNR_RETRY);
17239977f4f6SSean Hefty 	default:
17249977f4f6SSean Hefty 		return mask;
17259977f4f6SSean Hefty 	}
17269977f4f6SSean Hefty }
17279977f4f6SSean Hefty 
copy_ah_attr_from_uverbs(struct ib_device * dev,struct rdma_ah_attr * rdma_attr,struct ib_uverbs_qp_dest * uverb_attr)172889caa053SParav Pandit static void copy_ah_attr_from_uverbs(struct ib_device *dev,
172989caa053SParav Pandit 				     struct rdma_ah_attr *rdma_attr,
173089caa053SParav Pandit 				     struct ib_uverbs_qp_dest *uverb_attr)
173189caa053SParav Pandit {
173289caa053SParav Pandit 	rdma_attr->type = rdma_ah_find_type(dev, uverb_attr->port_num);
173389caa053SParav Pandit 	if (uverb_attr->is_global) {
173489caa053SParav Pandit 		rdma_ah_set_grh(rdma_attr, NULL,
173589caa053SParav Pandit 				uverb_attr->flow_label,
173689caa053SParav Pandit 				uverb_attr->sgid_index,
173789caa053SParav Pandit 				uverb_attr->hop_limit,
173889caa053SParav Pandit 				uverb_attr->traffic_class);
173989caa053SParav Pandit 		rdma_ah_set_dgid_raw(rdma_attr, uverb_attr->dgid);
174089caa053SParav Pandit 	} else {
174189caa053SParav Pandit 		rdma_ah_set_ah_flags(rdma_attr, 0);
174289caa053SParav Pandit 	}
174389caa053SParav Pandit 	rdma_ah_set_dlid(rdma_attr, uverb_attr->dlid);
174489caa053SParav Pandit 	rdma_ah_set_sl(rdma_attr, uverb_attr->sl);
174589caa053SParav Pandit 	rdma_ah_set_path_bits(rdma_attr, uverb_attr->src_path_bits);
174689caa053SParav Pandit 	rdma_ah_set_static_rate(rdma_attr, uverb_attr->static_rate);
174789caa053SParav Pandit 	rdma_ah_set_port_num(rdma_attr, uverb_attr->port_num);
174889caa053SParav Pandit 	rdma_ah_set_make_grd(rdma_attr, false);
174989caa053SParav Pandit }
175089caa053SParav Pandit 
modify_qp(struct uverbs_attr_bundle * attrs,struct ib_uverbs_ex_modify_qp * cmd)17518313c10fSJason Gunthorpe static int modify_qp(struct uverbs_attr_bundle *attrs,
1752ef87df2cSJason Gunthorpe 		     struct ib_uverbs_ex_modify_qp *cmd)
1753bc38a6abSRoland Dreier {
1754bc38a6abSRoland Dreier 	struct ib_qp_attr *attr;
1755189aba99SBodong Wang 	struct ib_qp *qp;
1756bc38a6abSRoland Dreier 	int ret;
1757bc38a6abSRoland Dreier 
1758fb51eecaSParav Pandit 	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
1759bc38a6abSRoland Dreier 	if (!attr)
1760bc38a6abSRoland Dreier 		return -ENOMEM;
1761bc38a6abSRoland Dreier 
17628313c10fSJason Gunthorpe 	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd->base.qp_handle,
17638313c10fSJason Gunthorpe 			       attrs);
17649ead190bSRoland Dreier 	if (!qp) {
1765bc38a6abSRoland Dreier 		ret = -EINVAL;
1766bc38a6abSRoland Dreier 		goto out;
1767bc38a6abSRoland Dreier 	}
1768bc38a6abSRoland Dreier 
17695a7a88f1SIsmail, Mustafa 	if ((cmd->base.attr_mask & IB_QP_PORT) &&
17705a7a88f1SIsmail, Mustafa 	    !rdma_is_port_valid(qp->device, cmd->base.port_num)) {
17715ecce4c9SBoris Pismenny 		ret = -EINVAL;
17725ecce4c9SBoris Pismenny 		goto release_qp;
17735ecce4c9SBoris Pismenny 	}
17745ecce4c9SBoris Pismenny 
1775addb8a65SJack Morgenstein 	if ((cmd->base.attr_mask & IB_QP_AV)) {
1776addb8a65SJack Morgenstein 		if (!rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) {
17775d4c05c3SLeon Romanovsky 			ret = -EINVAL;
17785d4c05c3SLeon Romanovsky 			goto release_qp;
17795d4c05c3SLeon Romanovsky 		}
17805d4c05c3SLeon Romanovsky 
1781addb8a65SJack Morgenstein 		if (cmd->base.attr_mask & IB_QP_STATE &&
1782addb8a65SJack Morgenstein 		    cmd->base.qp_state == IB_QPS_RTR) {
1783addb8a65SJack Morgenstein 		/* We are in INIT->RTR TRANSITION (if we are not,
1784addb8a65SJack Morgenstein 		 * this transition will be rejected in subsequent checks).
1785addb8a65SJack Morgenstein 		 * In the INIT->RTR transition, we cannot have IB_QP_PORT set,
1786addb8a65SJack Morgenstein 		 * but the IB_QP_STATE flag is required.
1787addb8a65SJack Morgenstein 		 *
1788addb8a65SJack Morgenstein 		 * Since kernel 3.14 (commit dbf727de7440), the uverbs driver,
1789addb8a65SJack Morgenstein 		 * when IB_QP_AV is set, has required inclusion of a valid
1790addb8a65SJack Morgenstein 		 * port number in the primary AV. (AVs are created and handled
1791addb8a65SJack Morgenstein 		 * differently for infiniband and ethernet (RoCE) ports).
1792addb8a65SJack Morgenstein 		 *
1793addb8a65SJack Morgenstein 		 * Check the port number included in the primary AV against
1794addb8a65SJack Morgenstein 		 * the port number in the qp struct, which was set (and saved)
1795addb8a65SJack Morgenstein 		 * in the RST->INIT transition.
1796addb8a65SJack Morgenstein 		 */
1797addb8a65SJack Morgenstein 			if (cmd->base.dest.port_num != qp->real_qp->port) {
1798addb8a65SJack Morgenstein 				ret = -EINVAL;
1799addb8a65SJack Morgenstein 				goto release_qp;
1800addb8a65SJack Morgenstein 			}
1801addb8a65SJack Morgenstein 		} else {
1802addb8a65SJack Morgenstein 		/* We are in SQD->SQD. (If we are not, this transition will
1803addb8a65SJack Morgenstein 		 * be rejected later in the verbs layer checks).
1804addb8a65SJack Morgenstein 		 * Check for both IB_QP_PORT and IB_QP_AV, these can be set
1805addb8a65SJack Morgenstein 		 * together in the SQD->SQD transition.
1806addb8a65SJack Morgenstein 		 *
1807addb8a65SJack Morgenstein 		 * If only IP_QP_AV was set, add in IB_QP_PORT as well (the
1808addb8a65SJack Morgenstein 		 * verbs layer driver does not track primary port changes
1809addb8a65SJack Morgenstein 		 * resulting from path migration. Thus, in SQD, if the primary
1810addb8a65SJack Morgenstein 		 * AV is modified, the primary port should also be modified).
1811addb8a65SJack Morgenstein 		 *
1812addb8a65SJack Morgenstein 		 * Note that in this transition, the IB_QP_STATE flag
1813addb8a65SJack Morgenstein 		 * is not allowed.
1814addb8a65SJack Morgenstein 		 */
1815addb8a65SJack Morgenstein 			if (((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT))
1816addb8a65SJack Morgenstein 			     == (IB_QP_AV | IB_QP_PORT)) &&
1817addb8a65SJack Morgenstein 			    cmd->base.port_num != cmd->base.dest.port_num) {
1818addb8a65SJack Morgenstein 				ret = -EINVAL;
1819addb8a65SJack Morgenstein 				goto release_qp;
1820addb8a65SJack Morgenstein 			}
1821addb8a65SJack Morgenstein 			if ((cmd->base.attr_mask & (IB_QP_AV | IB_QP_PORT))
1822addb8a65SJack Morgenstein 			    == IB_QP_AV) {
1823addb8a65SJack Morgenstein 				cmd->base.attr_mask |= IB_QP_PORT;
1824addb8a65SJack Morgenstein 				cmd->base.port_num = cmd->base.dest.port_num;
1825addb8a65SJack Morgenstein 			}
1826addb8a65SJack Morgenstein 		}
1827addb8a65SJack Morgenstein 	}
1828addb8a65SJack Morgenstein 
18294cae8ff1SDaniel Jurgens 	if ((cmd->base.attr_mask & IB_QP_ALT_PATH) &&
18305d4c05c3SLeon Romanovsky 	    (!rdma_is_port_valid(qp->device, cmd->base.alt_port_num) ||
1831addb8a65SJack Morgenstein 	    !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num) ||
1832addb8a65SJack Morgenstein 	    cmd->base.alt_port_num != cmd->base.alt_dest.port_num)) {
18334cae8ff1SDaniel Jurgens 		ret = -EINVAL;
18344cae8ff1SDaniel Jurgens 		goto release_qp;
18354cae8ff1SDaniel Jurgens 	}
18364cae8ff1SDaniel Jurgens 
183788de869bSLeon Romanovsky 	if ((cmd->base.attr_mask & IB_QP_CUR_STATE &&
183888de869bSLeon Romanovsky 	    cmd->base.cur_qp_state > IB_QPS_ERR) ||
18394eeed368SMajd Dibbiny 	    (cmd->base.attr_mask & IB_QP_STATE &&
18404eeed368SMajd Dibbiny 	    cmd->base.qp_state > IB_QPS_ERR)) {
184188de869bSLeon Romanovsky 		ret = -EINVAL;
184288de869bSLeon Romanovsky 		goto release_qp;
184388de869bSLeon Romanovsky 	}
184488de869bSLeon Romanovsky 
18454eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_STATE)
1846189aba99SBodong Wang 		attr->qp_state = cmd->base.qp_state;
18474eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_CUR_STATE)
1848189aba99SBodong Wang 		attr->cur_qp_state = cmd->base.cur_qp_state;
18494eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_PATH_MTU)
1850189aba99SBodong Wang 		attr->path_mtu = cmd->base.path_mtu;
18514eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_PATH_MIG_STATE)
1852189aba99SBodong Wang 		attr->path_mig_state = cmd->base.path_mig_state;
1853*0cadb4dbSEdward Srouji 	if (cmd->base.attr_mask & IB_QP_QKEY) {
1854*0cadb4dbSEdward Srouji 		if (cmd->base.qkey & IB_QP_SET_QKEY && !capable(CAP_NET_RAW)) {
1855*0cadb4dbSEdward Srouji 			ret = -EPERM;
1856*0cadb4dbSEdward Srouji 			goto release_qp;
1857*0cadb4dbSEdward Srouji 		}
1858189aba99SBodong Wang 		attr->qkey = cmd->base.qkey;
1859*0cadb4dbSEdward Srouji 	}
18604eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_RQ_PSN)
1861189aba99SBodong Wang 		attr->rq_psn = cmd->base.rq_psn;
18624eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_SQ_PSN)
1863189aba99SBodong Wang 		attr->sq_psn = cmd->base.sq_psn;
18644eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_DEST_QPN)
1865189aba99SBodong Wang 		attr->dest_qp_num = cmd->base.dest_qp_num;
18664eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_ACCESS_FLAGS)
1867189aba99SBodong Wang 		attr->qp_access_flags = cmd->base.qp_access_flags;
18684eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_PKEY_INDEX)
1869189aba99SBodong Wang 		attr->pkey_index = cmd->base.pkey_index;
18704eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY)
1871189aba99SBodong Wang 		attr->en_sqd_async_notify = cmd->base.en_sqd_async_notify;
18724eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
1873189aba99SBodong Wang 		attr->max_rd_atomic = cmd->base.max_rd_atomic;
18744eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
1875189aba99SBodong Wang 		attr->max_dest_rd_atomic = cmd->base.max_dest_rd_atomic;
18764eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_MIN_RNR_TIMER)
1877189aba99SBodong Wang 		attr->min_rnr_timer = cmd->base.min_rnr_timer;
18784eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_PORT)
1879189aba99SBodong Wang 		attr->port_num = cmd->base.port_num;
18804eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_TIMEOUT)
1881189aba99SBodong Wang 		attr->timeout = cmd->base.timeout;
18824eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_RETRY_CNT)
1883189aba99SBodong Wang 		attr->retry_cnt = cmd->base.retry_cnt;
18844eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_RNR_RETRY)
1885189aba99SBodong Wang 		attr->rnr_retry = cmd->base.rnr_retry;
18864eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_ALT_PATH) {
1887189aba99SBodong Wang 		attr->alt_port_num = cmd->base.alt_port_num;
1888189aba99SBodong Wang 		attr->alt_timeout = cmd->base.alt_timeout;
18894eeed368SMajd Dibbiny 		attr->alt_pkey_index = cmd->base.alt_pkey_index;
18904eeed368SMajd Dibbiny 	}
18914eeed368SMajd Dibbiny 	if (cmd->base.attr_mask & IB_QP_RATE_LIMIT)
1892189aba99SBodong Wang 		attr->rate_limit = cmd->rate_limit;
1893bc38a6abSRoland Dreier 
1894498ca3c8SNoa Osherovich 	if (cmd->base.attr_mask & IB_QP_AV)
189589caa053SParav Pandit 		copy_ah_attr_from_uverbs(qp->device, &attr->ah_attr,
189689caa053SParav Pandit 					 &cmd->base.dest);
1897bc38a6abSRoland Dreier 
1898498ca3c8SNoa Osherovich 	if (cmd->base.attr_mask & IB_QP_ALT_PATH)
189989caa053SParav Pandit 		copy_ah_attr_from_uverbs(qp->device, &attr->alt_ah_attr,
190089caa053SParav Pandit 					 &cmd->base.alt_dest);
1901bc38a6abSRoland Dreier 
1902f7c8f2e9SParav Pandit 	ret = ib_modify_qp_with_udata(qp, attr,
1903189aba99SBodong Wang 				      modify_qp_mask(qp->qp_type,
1904189aba99SBodong Wang 						     cmd->base.attr_mask),
1905ef87df2cSJason Gunthorpe 				      &attrs->driver_udata);
19069ead190bSRoland Dreier 
19070fb8bcf0SMoshe Lazer release_qp:
1908620d3f81SJason Gunthorpe 	rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
1909620d3f81SJason Gunthorpe 				UVERBS_LOOKUP_READ);
1910bc38a6abSRoland Dreier out:
1911bc38a6abSRoland Dreier 	kfree(attr);
1912bc38a6abSRoland Dreier 
1913bc38a6abSRoland Dreier 	return ret;
1914bc38a6abSRoland Dreier }
1915bc38a6abSRoland Dreier 
ib_uverbs_modify_qp(struct uverbs_attr_bundle * attrs)1916974d6b4bSJason Gunthorpe static int ib_uverbs_modify_qp(struct uverbs_attr_bundle *attrs)
1917189aba99SBodong Wang {
191829a29d18SJason Gunthorpe 	struct ib_uverbs_ex_modify_qp cmd;
19193c2c2094SJason Gunthorpe 	int ret;
1920189aba99SBodong Wang 
19213c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd.base, sizeof(cmd.base));
19223c2c2094SJason Gunthorpe 	if (ret)
19233c2c2094SJason Gunthorpe 		return ret;
1924189aba99SBodong Wang 
192526e990baSJason Gunthorpe 	if (cmd.base.attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
1926189aba99SBodong Wang 		return -EOPNOTSUPP;
1927189aba99SBodong Wang 
1928ef87df2cSJason Gunthorpe 	return modify_qp(attrs, &cmd);
1929189aba99SBodong Wang }
1930189aba99SBodong Wang 
ib_uverbs_ex_modify_qp(struct uverbs_attr_bundle * attrs)1931974d6b4bSJason Gunthorpe static int ib_uverbs_ex_modify_qp(struct uverbs_attr_bundle *attrs)
1932189aba99SBodong Wang {
193329a29d18SJason Gunthorpe 	struct ib_uverbs_ex_modify_qp cmd;
193440efca7aSJason Gunthorpe 	struct ib_uverbs_ex_modify_qp_resp resp = {
193540efca7aSJason Gunthorpe 		.response_length = uverbs_response_length(attrs, sizeof(resp))
193640efca7aSJason Gunthorpe 	};
1937189aba99SBodong Wang 	int ret;
1938189aba99SBodong Wang 
193929a29d18SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
194029a29d18SJason Gunthorpe 	if (ret)
194129a29d18SJason Gunthorpe 		return ret;
194229a29d18SJason Gunthorpe 
1943189aba99SBodong Wang 	/*
1944189aba99SBodong Wang 	 * Last bit is reserved for extending the attr_mask by
1945189aba99SBodong Wang 	 * using another field.
1946189aba99SBodong Wang 	 */
194726e990baSJason Gunthorpe 	if (cmd.base.attr_mask & ~(IB_QP_ATTR_STANDARD_BITS | IB_QP_RATE_LIMIT))
1948189aba99SBodong Wang 		return -EOPNOTSUPP;
1949189aba99SBodong Wang 
195040efca7aSJason Gunthorpe 	ret = modify_qp(attrs, &cmd);
195140efca7aSJason Gunthorpe 	if (ret)
195240efca7aSJason Gunthorpe 		return ret;
195340efca7aSJason Gunthorpe 
195440efca7aSJason Gunthorpe 	return uverbs_response(attrs, &resp, sizeof(resp));
1955189aba99SBodong Wang }
1956189aba99SBodong Wang 
ib_uverbs_destroy_qp(struct uverbs_attr_bundle * attrs)1957974d6b4bSJason Gunthorpe static int ib_uverbs_destroy_qp(struct uverbs_attr_bundle *attrs)
1958bc38a6abSRoland Dreier {
1959bc38a6abSRoland Dreier 	struct ib_uverbs_destroy_qp      cmd;
196063aaf647SRoland Dreier 	struct ib_uverbs_destroy_qp_resp resp;
19619ead190bSRoland Dreier 	struct ib_uobject		*uobj;
19629ead190bSRoland Dreier 	struct ib_uqp_object        	*obj;
19633c2c2094SJason Gunthorpe 	int ret;
1964bc38a6abSRoland Dreier 
19653c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
19663c2c2094SJason Gunthorpe 	if (ret)
19673c2c2094SJason Gunthorpe 		return ret;
1968bc38a6abSRoland Dreier 
19698313c10fSJason Gunthorpe 	uobj = uobj_get_destroy(UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
1970fd3c7904SMatan Barak 	if (IS_ERR(uobj))
1971fd3c7904SMatan Barak 		return PTR_ERR(uobj);
1972fd3c7904SMatan Barak 
19739ead190bSRoland Dreier 	obj = container_of(uobj, struct ib_uqp_object, uevent.uobject);
197432ed5c00SJason Gunthorpe 	memset(&resp, 0, sizeof(resp));
19759ead190bSRoland Dreier 	resp.events_reported = obj->uevent.events_reported;
197632ed5c00SJason Gunthorpe 
197732ed5c00SJason Gunthorpe 	uobj_put_destroy(uobj);
1978bc38a6abSRoland Dreier 
19799a073857SJason Gunthorpe 	return uverbs_response(attrs, &resp, sizeof(resp));
1980bc38a6abSRoland Dreier }
1981bc38a6abSRoland Dreier 
alloc_wr(size_t wr_size,__u32 num_sge)1982e622f2f4SChristoph Hellwig static void *alloc_wr(size_t wr_size, __u32 num_sge)
1983e622f2f4SChristoph Hellwig {
19844f7f4dcfSVlad Tsyrklevich 	if (num_sge >= (U32_MAX - ALIGN(wr_size, sizeof(struct ib_sge))) /
19854f7f4dcfSVlad Tsyrklevich 			       sizeof(struct ib_sge))
19864f7f4dcfSVlad Tsyrklevich 		return NULL;
19874f7f4dcfSVlad Tsyrklevich 
1988e622f2f4SChristoph Hellwig 	return kmalloc(ALIGN(wr_size, sizeof(struct ib_sge)) +
1989f681967aSWenpeng Liang 			       num_sge * sizeof(struct ib_sge),
1990f681967aSWenpeng Liang 		       GFP_KERNEL);
19914f7f4dcfSVlad Tsyrklevich }
1992e622f2f4SChristoph Hellwig 
ib_uverbs_post_send(struct uverbs_attr_bundle * attrs)1993974d6b4bSJason Gunthorpe static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs)
199467cdb40cSRoland Dreier {
199567cdb40cSRoland Dreier 	struct ib_uverbs_post_send      cmd;
199667cdb40cSRoland Dreier 	struct ib_uverbs_post_send_resp resp;
199767cdb40cSRoland Dreier 	struct ib_uverbs_send_wr       *user_wr;
1998d34ac5cdSBart Van Assche 	struct ib_send_wr              *wr = NULL, *last, *next;
1999d34ac5cdSBart Van Assche 	const struct ib_send_wr	       *bad_wr;
200067cdb40cSRoland Dreier 	struct ib_qp                   *qp;
200167cdb40cSRoland Dreier 	int                             i, sg_ind;
20029ead190bSRoland Dreier 	int				is_ud;
20039a073857SJason Gunthorpe 	int ret, ret2;
20041d784b89SMike Marciniszyn 	size_t                          next_size;
2005c3bea3d2SJason Gunthorpe 	const struct ib_sge __user *sgls;
2006c3bea3d2SJason Gunthorpe 	const void __user *wqes;
2007c3bea3d2SJason Gunthorpe 	struct uverbs_req_iter iter;
200867cdb40cSRoland Dreier 
2009c3bea3d2SJason Gunthorpe 	ret = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
2010c3bea3d2SJason Gunthorpe 	if (ret)
2011c3bea3d2SJason Gunthorpe 		return ret;
2012c3bea3d2SJason Gunthorpe 	wqes = uverbs_request_next_ptr(&iter, cmd.wqe_size * cmd.wr_count);
2013c3bea3d2SJason Gunthorpe 	if (IS_ERR(wqes))
2014c3bea3d2SJason Gunthorpe 		return PTR_ERR(wqes);
2015c3bea3d2SJason Gunthorpe 	sgls = uverbs_request_next_ptr(
2016c3bea3d2SJason Gunthorpe 		&iter, cmd.sge_count * sizeof(struct ib_uverbs_sge));
2017c3bea3d2SJason Gunthorpe 	if (IS_ERR(sgls))
2018c3bea3d2SJason Gunthorpe 		return PTR_ERR(sgls);
2019c3bea3d2SJason Gunthorpe 	ret = uverbs_request_finish(&iter);
2020c3bea3d2SJason Gunthorpe 	if (ret)
2021c3bea3d2SJason Gunthorpe 		return ret;
202267cdb40cSRoland Dreier 
202367cdb40cSRoland Dreier 	user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL);
202467cdb40cSRoland Dreier 	if (!user_wr)
202567cdb40cSRoland Dreier 		return -ENOMEM;
202667cdb40cSRoland Dreier 
20278313c10fSJason Gunthorpe 	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
2028f687cceaSGal Pressman 	if (!qp) {
2029f687cceaSGal Pressman 		ret = -EINVAL;
203067cdb40cSRoland Dreier 		goto out;
2031f687cceaSGal Pressman 	}
203267cdb40cSRoland Dreier 
20339ead190bSRoland Dreier 	is_ud = qp->qp_type == IB_QPT_UD;
203467cdb40cSRoland Dreier 	sg_ind = 0;
203567cdb40cSRoland Dreier 	last = NULL;
203667cdb40cSRoland Dreier 	for (i = 0; i < cmd.wr_count; ++i) {
2037c3bea3d2SJason Gunthorpe 		if (copy_from_user(user_wr, wqes + i * cmd.wqe_size,
203867cdb40cSRoland Dreier 				   cmd.wqe_size)) {
203967cdb40cSRoland Dreier 			ret = -EFAULT;
20409ead190bSRoland Dreier 			goto out_put;
204167cdb40cSRoland Dreier 		}
204267cdb40cSRoland Dreier 
204367cdb40cSRoland Dreier 		if (user_wr->num_sge + sg_ind > cmd.sge_count) {
204467cdb40cSRoland Dreier 			ret = -EINVAL;
20459ead190bSRoland Dreier 			goto out_put;
204667cdb40cSRoland Dreier 		}
204767cdb40cSRoland Dreier 
2048e622f2f4SChristoph Hellwig 		if (is_ud) {
2049e622f2f4SChristoph Hellwig 			struct ib_ud_wr *ud;
2050e622f2f4SChristoph Hellwig 
2051e622f2f4SChristoph Hellwig 			if (user_wr->opcode != IB_WR_SEND &&
2052e622f2f4SChristoph Hellwig 			    user_wr->opcode != IB_WR_SEND_WITH_IMM) {
2053e622f2f4SChristoph Hellwig 				ret = -EINVAL;
2054e622f2f4SChristoph Hellwig 				goto out_put;
2055e622f2f4SChristoph Hellwig 			}
2056e622f2f4SChristoph Hellwig 
20571d784b89SMike Marciniszyn 			next_size = sizeof(*ud);
20581d784b89SMike Marciniszyn 			ud = alloc_wr(next_size, user_wr->num_sge);
2059e622f2f4SChristoph Hellwig 			if (!ud) {
2060e622f2f4SChristoph Hellwig 				ret = -ENOMEM;
2061e622f2f4SChristoph Hellwig 				goto out_put;
2062e622f2f4SChristoph Hellwig 			}
2063e622f2f4SChristoph Hellwig 
20642cc1e3b8SJason Gunthorpe 			ud->ah = uobj_get_obj_read(ah, UVERBS_OBJECT_AH,
20658313c10fSJason Gunthorpe 						   user_wr->wr.ud.ah, attrs);
2066e622f2f4SChristoph Hellwig 			if (!ud->ah) {
2067e622f2f4SChristoph Hellwig 				kfree(ud);
2068e622f2f4SChristoph Hellwig 				ret = -EINVAL;
2069e622f2f4SChristoph Hellwig 				goto out_put;
2070e622f2f4SChristoph Hellwig 			}
2071e622f2f4SChristoph Hellwig 			ud->remote_qpn = user_wr->wr.ud.remote_qpn;
2072e622f2f4SChristoph Hellwig 			ud->remote_qkey = user_wr->wr.ud.remote_qkey;
2073e622f2f4SChristoph Hellwig 
2074e622f2f4SChristoph Hellwig 			next = &ud->wr;
2075e622f2f4SChristoph Hellwig 		} else if (user_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
2076e622f2f4SChristoph Hellwig 			   user_wr->opcode == IB_WR_RDMA_WRITE ||
2077e622f2f4SChristoph Hellwig 			   user_wr->opcode == IB_WR_RDMA_READ) {
2078e622f2f4SChristoph Hellwig 			struct ib_rdma_wr *rdma;
2079e622f2f4SChristoph Hellwig 
20801d784b89SMike Marciniszyn 			next_size = sizeof(*rdma);
20811d784b89SMike Marciniszyn 			rdma = alloc_wr(next_size, user_wr->num_sge);
2082e622f2f4SChristoph Hellwig 			if (!rdma) {
2083e622f2f4SChristoph Hellwig 				ret = -ENOMEM;
2084e622f2f4SChristoph Hellwig 				goto out_put;
2085e622f2f4SChristoph Hellwig 			}
2086e622f2f4SChristoph Hellwig 
2087e622f2f4SChristoph Hellwig 			rdma->remote_addr = user_wr->wr.rdma.remote_addr;
2088e622f2f4SChristoph Hellwig 			rdma->rkey = user_wr->wr.rdma.rkey;
2089e622f2f4SChristoph Hellwig 
2090e622f2f4SChristoph Hellwig 			next = &rdma->wr;
2091e622f2f4SChristoph Hellwig 		} else if (user_wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
2092e622f2f4SChristoph Hellwig 			   user_wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
2093e622f2f4SChristoph Hellwig 			struct ib_atomic_wr *atomic;
2094e622f2f4SChristoph Hellwig 
20951d784b89SMike Marciniszyn 			next_size = sizeof(*atomic);
20961d784b89SMike Marciniszyn 			atomic = alloc_wr(next_size, user_wr->num_sge);
2097e622f2f4SChristoph Hellwig 			if (!atomic) {
2098e622f2f4SChristoph Hellwig 				ret = -ENOMEM;
2099e622f2f4SChristoph Hellwig 				goto out_put;
2100e622f2f4SChristoph Hellwig 			}
2101e622f2f4SChristoph Hellwig 
2102e622f2f4SChristoph Hellwig 			atomic->remote_addr = user_wr->wr.atomic.remote_addr;
2103e622f2f4SChristoph Hellwig 			atomic->compare_add = user_wr->wr.atomic.compare_add;
2104e622f2f4SChristoph Hellwig 			atomic->swap = user_wr->wr.atomic.swap;
2105e622f2f4SChristoph Hellwig 			atomic->rkey = user_wr->wr.atomic.rkey;
2106e622f2f4SChristoph Hellwig 
2107e622f2f4SChristoph Hellwig 			next = &atomic->wr;
2108e622f2f4SChristoph Hellwig 		} else if (user_wr->opcode == IB_WR_SEND ||
2109e622f2f4SChristoph Hellwig 			   user_wr->opcode == IB_WR_SEND_WITH_IMM ||
2110e622f2f4SChristoph Hellwig 			   user_wr->opcode == IB_WR_SEND_WITH_INV) {
21111d784b89SMike Marciniszyn 			next_size = sizeof(*next);
21121d784b89SMike Marciniszyn 			next = alloc_wr(next_size, user_wr->num_sge);
211367cdb40cSRoland Dreier 			if (!next) {
211467cdb40cSRoland Dreier 				ret = -ENOMEM;
21159ead190bSRoland Dreier 				goto out_put;
211667cdb40cSRoland Dreier 			}
2117e622f2f4SChristoph Hellwig 		} else {
2118e622f2f4SChristoph Hellwig 			ret = -EINVAL;
2119e622f2f4SChristoph Hellwig 			goto out_put;
2120e622f2f4SChristoph Hellwig 		}
2121e622f2f4SChristoph Hellwig 
2122e622f2f4SChristoph Hellwig 		if (user_wr->opcode == IB_WR_SEND_WITH_IMM ||
2123e622f2f4SChristoph Hellwig 		    user_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
2124e622f2f4SChristoph Hellwig 			next->ex.imm_data =
2125e622f2f4SChristoph Hellwig 					(__be32 __force) user_wr->ex.imm_data;
2126e622f2f4SChristoph Hellwig 		} else if (user_wr->opcode == IB_WR_SEND_WITH_INV) {
2127e622f2f4SChristoph Hellwig 			next->ex.invalidate_rkey = user_wr->ex.invalidate_rkey;
2128e622f2f4SChristoph Hellwig 		}
212967cdb40cSRoland Dreier 
213067cdb40cSRoland Dreier 		if (!last)
213167cdb40cSRoland Dreier 			wr = next;
213267cdb40cSRoland Dreier 		else
213367cdb40cSRoland Dreier 			last->next = next;
213467cdb40cSRoland Dreier 		last = next;
213567cdb40cSRoland Dreier 
213667cdb40cSRoland Dreier 		next->next       = NULL;
213767cdb40cSRoland Dreier 		next->wr_id      = user_wr->wr_id;
213867cdb40cSRoland Dreier 		next->num_sge    = user_wr->num_sge;
213967cdb40cSRoland Dreier 		next->opcode     = user_wr->opcode;
214067cdb40cSRoland Dreier 		next->send_flags = user_wr->send_flags;
214167cdb40cSRoland Dreier 
214267cdb40cSRoland Dreier 		if (next->num_sge) {
214367cdb40cSRoland Dreier 			next->sg_list = (void *) next +
21441d784b89SMike Marciniszyn 				ALIGN(next_size, sizeof(struct ib_sge));
2145c3bea3d2SJason Gunthorpe 			if (copy_from_user(next->sg_list, sgls + sg_ind,
2146c3bea3d2SJason Gunthorpe 					   next->num_sge *
2147c3bea3d2SJason Gunthorpe 						   sizeof(struct ib_sge))) {
214867cdb40cSRoland Dreier 				ret = -EFAULT;
21499ead190bSRoland Dreier 				goto out_put;
215067cdb40cSRoland Dreier 			}
215167cdb40cSRoland Dreier 			sg_ind += next->num_sge;
215267cdb40cSRoland Dreier 		} else
215367cdb40cSRoland Dreier 			next->sg_list = NULL;
215467cdb40cSRoland Dreier 	}
215567cdb40cSRoland Dreier 
215667cdb40cSRoland Dreier 	resp.bad_wr = 0;
21573023a1e9SKamal Heib 	ret = qp->device->ops.post_send(qp->real_qp, wr, &bad_wr);
215867cdb40cSRoland Dreier 	if (ret)
215967cdb40cSRoland Dreier 		for (next = wr; next; next = next->next) {
216067cdb40cSRoland Dreier 			++resp.bad_wr;
216167cdb40cSRoland Dreier 			if (next == bad_wr)
216267cdb40cSRoland Dreier 				break;
216367cdb40cSRoland Dreier 		}
216467cdb40cSRoland Dreier 
21659a073857SJason Gunthorpe 	ret2 = uverbs_response(attrs, &resp, sizeof(resp));
21669a073857SJason Gunthorpe 	if (ret2)
21679a073857SJason Gunthorpe 		ret = ret2;
216867cdb40cSRoland Dreier 
21699ead190bSRoland Dreier out_put:
2170620d3f81SJason Gunthorpe 	rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
2171620d3f81SJason Gunthorpe 				UVERBS_LOOKUP_READ);
217267cdb40cSRoland Dreier 
217367cdb40cSRoland Dreier 	while (wr) {
2174e622f2f4SChristoph Hellwig 		if (is_ud && ud_wr(wr)->ah)
2175fd3c7904SMatan Barak 			uobj_put_obj_read(ud_wr(wr)->ah);
217667cdb40cSRoland Dreier 		next = wr->next;
217767cdb40cSRoland Dreier 		kfree(wr);
217867cdb40cSRoland Dreier 		wr = next;
217967cdb40cSRoland Dreier 	}
218067cdb40cSRoland Dreier 
218118320828SKrishna Kumar out:
218267cdb40cSRoland Dreier 	kfree(user_wr);
218367cdb40cSRoland Dreier 
21847106a976SJason Gunthorpe 	return ret;
218567cdb40cSRoland Dreier }
218667cdb40cSRoland Dreier 
2187c3bea3d2SJason Gunthorpe static struct ib_recv_wr *
ib_uverbs_unmarshall_recv(struct uverbs_req_iter * iter,u32 wr_count,u32 wqe_size,u32 sge_count)2188c3bea3d2SJason Gunthorpe ib_uverbs_unmarshall_recv(struct uverbs_req_iter *iter, u32 wr_count,
2189c3bea3d2SJason Gunthorpe 			  u32 wqe_size, u32 sge_count)
219067cdb40cSRoland Dreier {
219167cdb40cSRoland Dreier 	struct ib_uverbs_recv_wr *user_wr;
219267cdb40cSRoland Dreier 	struct ib_recv_wr        *wr = NULL, *last, *next;
219367cdb40cSRoland Dreier 	int                       sg_ind;
219467cdb40cSRoland Dreier 	int                       i;
219567cdb40cSRoland Dreier 	int                       ret;
2196c3bea3d2SJason Gunthorpe 	const struct ib_sge __user *sgls;
2197c3bea3d2SJason Gunthorpe 	const void __user *wqes;
219867cdb40cSRoland Dreier 
219967cdb40cSRoland Dreier 	if (wqe_size < sizeof(struct ib_uverbs_recv_wr))
220067cdb40cSRoland Dreier 		return ERR_PTR(-EINVAL);
220167cdb40cSRoland Dreier 
2202c3bea3d2SJason Gunthorpe 	wqes = uverbs_request_next_ptr(iter, wqe_size * wr_count);
2203c3bea3d2SJason Gunthorpe 	if (IS_ERR(wqes))
2204c3bea3d2SJason Gunthorpe 		return ERR_CAST(wqes);
2205c3bea3d2SJason Gunthorpe 	sgls = uverbs_request_next_ptr(
2206c3bea3d2SJason Gunthorpe 		iter, sge_count * sizeof(struct ib_uverbs_sge));
2207c3bea3d2SJason Gunthorpe 	if (IS_ERR(sgls))
2208c3bea3d2SJason Gunthorpe 		return ERR_CAST(sgls);
2209c3bea3d2SJason Gunthorpe 	ret = uverbs_request_finish(iter);
2210c3bea3d2SJason Gunthorpe 	if (ret)
2211c3bea3d2SJason Gunthorpe 		return ERR_PTR(ret);
2212c3bea3d2SJason Gunthorpe 
221367cdb40cSRoland Dreier 	user_wr = kmalloc(wqe_size, GFP_KERNEL);
221467cdb40cSRoland Dreier 	if (!user_wr)
221567cdb40cSRoland Dreier 		return ERR_PTR(-ENOMEM);
221667cdb40cSRoland Dreier 
221767cdb40cSRoland Dreier 	sg_ind = 0;
221867cdb40cSRoland Dreier 	last = NULL;
221967cdb40cSRoland Dreier 	for (i = 0; i < wr_count; ++i) {
2220c3bea3d2SJason Gunthorpe 		if (copy_from_user(user_wr, wqes + i * wqe_size,
222167cdb40cSRoland Dreier 				   wqe_size)) {
222267cdb40cSRoland Dreier 			ret = -EFAULT;
222367cdb40cSRoland Dreier 			goto err;
222467cdb40cSRoland Dreier 		}
222567cdb40cSRoland Dreier 
222667cdb40cSRoland Dreier 		if (user_wr->num_sge + sg_ind > sge_count) {
222767cdb40cSRoland Dreier 			ret = -EINVAL;
222867cdb40cSRoland Dreier 			goto err;
222967cdb40cSRoland Dreier 		}
223067cdb40cSRoland Dreier 
22314f7f4dcfSVlad Tsyrklevich 		if (user_wr->num_sge >=
2232f681967aSWenpeng Liang 		    (U32_MAX - ALIGN(sizeof(*next), sizeof(struct ib_sge))) /
22334f7f4dcfSVlad Tsyrklevich 			    sizeof(struct ib_sge)) {
22344f7f4dcfSVlad Tsyrklevich 			ret = -EINVAL;
22354f7f4dcfSVlad Tsyrklevich 			goto err;
22364f7f4dcfSVlad Tsyrklevich 		}
22374f7f4dcfSVlad Tsyrklevich 
2238f681967aSWenpeng Liang 		next = kmalloc(ALIGN(sizeof(*next), sizeof(struct ib_sge)) +
223967cdb40cSRoland Dreier 				       user_wr->num_sge * sizeof(struct ib_sge),
224067cdb40cSRoland Dreier 			       GFP_KERNEL);
224167cdb40cSRoland Dreier 		if (!next) {
224267cdb40cSRoland Dreier 			ret = -ENOMEM;
224367cdb40cSRoland Dreier 			goto err;
224467cdb40cSRoland Dreier 		}
224567cdb40cSRoland Dreier 
224667cdb40cSRoland Dreier 		if (!last)
224767cdb40cSRoland Dreier 			wr = next;
224867cdb40cSRoland Dreier 		else
224967cdb40cSRoland Dreier 			last->next = next;
225067cdb40cSRoland Dreier 		last = next;
225167cdb40cSRoland Dreier 
225267cdb40cSRoland Dreier 		next->next       = NULL;
225367cdb40cSRoland Dreier 		next->wr_id      = user_wr->wr_id;
225467cdb40cSRoland Dreier 		next->num_sge    = user_wr->num_sge;
225567cdb40cSRoland Dreier 
225667cdb40cSRoland Dreier 		if (next->num_sge) {
225767cdb40cSRoland Dreier 			next->sg_list = (void *)next +
2258f681967aSWenpeng Liang 				ALIGN(sizeof(*next), sizeof(struct ib_sge));
2259c3bea3d2SJason Gunthorpe 			if (copy_from_user(next->sg_list, sgls + sg_ind,
2260c3bea3d2SJason Gunthorpe 					   next->num_sge *
2261c3bea3d2SJason Gunthorpe 						   sizeof(struct ib_sge))) {
226267cdb40cSRoland Dreier 				ret = -EFAULT;
226367cdb40cSRoland Dreier 				goto err;
226467cdb40cSRoland Dreier 			}
226567cdb40cSRoland Dreier 			sg_ind += next->num_sge;
226667cdb40cSRoland Dreier 		} else
226767cdb40cSRoland Dreier 			next->sg_list = NULL;
226867cdb40cSRoland Dreier 	}
226967cdb40cSRoland Dreier 
227067cdb40cSRoland Dreier 	kfree(user_wr);
227167cdb40cSRoland Dreier 	return wr;
227267cdb40cSRoland Dreier 
227367cdb40cSRoland Dreier err:
227467cdb40cSRoland Dreier 	kfree(user_wr);
227567cdb40cSRoland Dreier 
227667cdb40cSRoland Dreier 	while (wr) {
227767cdb40cSRoland Dreier 		next = wr->next;
227867cdb40cSRoland Dreier 		kfree(wr);
227967cdb40cSRoland Dreier 		wr = next;
228067cdb40cSRoland Dreier 	}
228167cdb40cSRoland Dreier 
228267cdb40cSRoland Dreier 	return ERR_PTR(ret);
228367cdb40cSRoland Dreier }
228467cdb40cSRoland Dreier 
ib_uverbs_post_recv(struct uverbs_attr_bundle * attrs)2285974d6b4bSJason Gunthorpe static int ib_uverbs_post_recv(struct uverbs_attr_bundle *attrs)
228667cdb40cSRoland Dreier {
228767cdb40cSRoland Dreier 	struct ib_uverbs_post_recv      cmd;
228867cdb40cSRoland Dreier 	struct ib_uverbs_post_recv_resp resp;
2289d34ac5cdSBart Van Assche 	struct ib_recv_wr              *wr, *next;
2290d34ac5cdSBart Van Assche 	const struct ib_recv_wr	       *bad_wr;
229167cdb40cSRoland Dreier 	struct ib_qp                   *qp;
22929a073857SJason Gunthorpe 	int ret, ret2;
2293c3bea3d2SJason Gunthorpe 	struct uverbs_req_iter iter;
229467cdb40cSRoland Dreier 
2295c3bea3d2SJason Gunthorpe 	ret = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
2296c3bea3d2SJason Gunthorpe 	if (ret)
2297c3bea3d2SJason Gunthorpe 		return ret;
229867cdb40cSRoland Dreier 
2299c3bea3d2SJason Gunthorpe 	wr = ib_uverbs_unmarshall_recv(&iter, cmd.wr_count, cmd.wqe_size,
2300c3bea3d2SJason Gunthorpe 				       cmd.sge_count);
230167cdb40cSRoland Dreier 	if (IS_ERR(wr))
230267cdb40cSRoland Dreier 		return PTR_ERR(wr);
230367cdb40cSRoland Dreier 
23048313c10fSJason Gunthorpe 	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
23059a073857SJason Gunthorpe 	if (!qp) {
23069a073857SJason Gunthorpe 		ret = -EINVAL;
230767cdb40cSRoland Dreier 		goto out;
23089a073857SJason Gunthorpe 	}
230967cdb40cSRoland Dreier 
231067cdb40cSRoland Dreier 	resp.bad_wr = 0;
23113023a1e9SKamal Heib 	ret = qp->device->ops.post_recv(qp->real_qp, wr, &bad_wr);
23129ead190bSRoland Dreier 
2313620d3f81SJason Gunthorpe 	rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
2314620d3f81SJason Gunthorpe 				UVERBS_LOOKUP_READ);
2315fd3c7904SMatan Barak 	if (ret) {
231667cdb40cSRoland Dreier 		for (next = wr; next; next = next->next) {
231767cdb40cSRoland Dreier 			++resp.bad_wr;
231867cdb40cSRoland Dreier 			if (next == bad_wr)
231967cdb40cSRoland Dreier 				break;
232067cdb40cSRoland Dreier 		}
2321fd3c7904SMatan Barak 	}
232267cdb40cSRoland Dreier 
23239a073857SJason Gunthorpe 	ret2 = uverbs_response(attrs, &resp, sizeof(resp));
23249a073857SJason Gunthorpe 	if (ret2)
23259a073857SJason Gunthorpe 		ret = ret2;
232667cdb40cSRoland Dreier out:
232767cdb40cSRoland Dreier 	while (wr) {
232867cdb40cSRoland Dreier 		next = wr->next;
232967cdb40cSRoland Dreier 		kfree(wr);
233067cdb40cSRoland Dreier 		wr = next;
233167cdb40cSRoland Dreier 	}
233267cdb40cSRoland Dreier 
23337106a976SJason Gunthorpe 	return ret;
233467cdb40cSRoland Dreier }
233567cdb40cSRoland Dreier 
ib_uverbs_post_srq_recv(struct uverbs_attr_bundle * attrs)2336974d6b4bSJason Gunthorpe static int ib_uverbs_post_srq_recv(struct uverbs_attr_bundle *attrs)
233767cdb40cSRoland Dreier {
233867cdb40cSRoland Dreier 	struct ib_uverbs_post_srq_recv      cmd;
233967cdb40cSRoland Dreier 	struct ib_uverbs_post_srq_recv_resp resp;
2340d34ac5cdSBart Van Assche 	struct ib_recv_wr                  *wr, *next;
2341d34ac5cdSBart Van Assche 	const struct ib_recv_wr		   *bad_wr;
234267cdb40cSRoland Dreier 	struct ib_srq                      *srq;
23439a073857SJason Gunthorpe 	int ret, ret2;
2344c3bea3d2SJason Gunthorpe 	struct uverbs_req_iter iter;
234567cdb40cSRoland Dreier 
2346c3bea3d2SJason Gunthorpe 	ret = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
2347c3bea3d2SJason Gunthorpe 	if (ret)
2348c3bea3d2SJason Gunthorpe 		return ret;
234967cdb40cSRoland Dreier 
2350c3bea3d2SJason Gunthorpe 	wr = ib_uverbs_unmarshall_recv(&iter, cmd.wr_count, cmd.wqe_size,
2351c3bea3d2SJason Gunthorpe 				       cmd.sge_count);
235267cdb40cSRoland Dreier 	if (IS_ERR(wr))
235367cdb40cSRoland Dreier 		return PTR_ERR(wr);
235467cdb40cSRoland Dreier 
23558313c10fSJason Gunthorpe 	srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
23569a073857SJason Gunthorpe 	if (!srq) {
23579a073857SJason Gunthorpe 		ret = -EINVAL;
235867cdb40cSRoland Dreier 		goto out;
23599a073857SJason Gunthorpe 	}
236067cdb40cSRoland Dreier 
236167cdb40cSRoland Dreier 	resp.bad_wr = 0;
23623023a1e9SKamal Heib 	ret = srq->device->ops.post_srq_recv(srq, wr, &bad_wr);
23639ead190bSRoland Dreier 
23649fbe334cSJason Gunthorpe 	rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
23659fbe334cSJason Gunthorpe 				UVERBS_LOOKUP_READ);
23669ead190bSRoland Dreier 
236767cdb40cSRoland Dreier 	if (ret)
236867cdb40cSRoland Dreier 		for (next = wr; next; next = next->next) {
236967cdb40cSRoland Dreier 			++resp.bad_wr;
237067cdb40cSRoland Dreier 			if (next == bad_wr)
237167cdb40cSRoland Dreier 				break;
237267cdb40cSRoland Dreier 		}
237367cdb40cSRoland Dreier 
23749a073857SJason Gunthorpe 	ret2 = uverbs_response(attrs, &resp, sizeof(resp));
23759a073857SJason Gunthorpe 	if (ret2)
23769a073857SJason Gunthorpe 		ret = ret2;
237767cdb40cSRoland Dreier 
237867cdb40cSRoland Dreier out:
237967cdb40cSRoland Dreier 	while (wr) {
238067cdb40cSRoland Dreier 		next = wr->next;
238167cdb40cSRoland Dreier 		kfree(wr);
238267cdb40cSRoland Dreier 		wr = next;
238367cdb40cSRoland Dreier 	}
238467cdb40cSRoland Dreier 
23857106a976SJason Gunthorpe 	return ret;
238667cdb40cSRoland Dreier }
238767cdb40cSRoland Dreier 
ib_uverbs_create_ah(struct uverbs_attr_bundle * attrs)2388974d6b4bSJason Gunthorpe static int ib_uverbs_create_ah(struct uverbs_attr_bundle *attrs)
238967cdb40cSRoland Dreier {
239067cdb40cSRoland Dreier 	struct ib_uverbs_create_ah	 cmd;
239167cdb40cSRoland Dreier 	struct ib_uverbs_create_ah_resp	 resp;
239267cdb40cSRoland Dreier 	struct ib_uobject		*uobj;
239367cdb40cSRoland Dreier 	struct ib_pd			*pd;
239467cdb40cSRoland Dreier 	struct ib_ah			*ah;
2395fb51eecaSParav Pandit 	struct rdma_ah_attr		attr = {};
239667cdb40cSRoland Dreier 	int ret;
2397bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
239867cdb40cSRoland Dreier 
23993c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
24003c2c2094SJason Gunthorpe 	if (ret)
24013c2c2094SJason Gunthorpe 		return ret;
240267cdb40cSRoland Dreier 
24038313c10fSJason Gunthorpe 	uobj = uobj_alloc(UVERBS_OBJECT_AH, attrs, &ib_dev);
2404fd3c7904SMatan Barak 	if (IS_ERR(uobj))
2405fd3c7904SMatan Barak 		return PTR_ERR(uobj);
240667cdb40cSRoland Dreier 
2407bbd51e88SJason Gunthorpe 	if (!rdma_is_port_valid(ib_dev, cmd.attr.port_num)) {
2408bbd51e88SJason Gunthorpe 		ret = -EINVAL;
2409bbd51e88SJason Gunthorpe 		goto err;
2410bbd51e88SJason Gunthorpe 	}
2411bbd51e88SJason Gunthorpe 
24128313c10fSJason Gunthorpe 	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
24139ead190bSRoland Dreier 	if (!pd) {
241467cdb40cSRoland Dreier 		ret = -EINVAL;
24159ead190bSRoland Dreier 		goto err;
241667cdb40cSRoland Dreier 	}
241767cdb40cSRoland Dreier 
241844c58487SDasaratharaman Chandramouli 	attr.type = rdma_ah_find_type(ib_dev, cmd.attr.port_num);
2419d98bb7f7SDon Hiatt 	rdma_ah_set_make_grd(&attr, false);
2420d8966fcdSDasaratharaman Chandramouli 	rdma_ah_set_dlid(&attr, cmd.attr.dlid);
2421d8966fcdSDasaratharaman Chandramouli 	rdma_ah_set_sl(&attr, cmd.attr.sl);
2422d8966fcdSDasaratharaman Chandramouli 	rdma_ah_set_path_bits(&attr, cmd.attr.src_path_bits);
2423d8966fcdSDasaratharaman Chandramouli 	rdma_ah_set_static_rate(&attr, cmd.attr.static_rate);
2424d8966fcdSDasaratharaman Chandramouli 	rdma_ah_set_port_num(&attr, cmd.attr.port_num);
2425d8966fcdSDasaratharaman Chandramouli 
24264ba66093SDasaratharaman Chandramouli 	if (cmd.attr.is_global) {
2427d8966fcdSDasaratharaman Chandramouli 		rdma_ah_set_grh(&attr, NULL, cmd.attr.grh.flow_label,
2428d8966fcdSDasaratharaman Chandramouli 				cmd.attr.grh.sgid_index,
2429d8966fcdSDasaratharaman Chandramouli 				cmd.attr.grh.hop_limit,
2430d8966fcdSDasaratharaman Chandramouli 				cmd.attr.grh.traffic_class);
2431d8966fcdSDasaratharaman Chandramouli 		rdma_ah_set_dgid_raw(&attr, cmd.attr.grh.dgid);
24324ba66093SDasaratharaman Chandramouli 	} else {
2433d8966fcdSDasaratharaman Chandramouli 		rdma_ah_set_ah_flags(&attr, 0);
24344ba66093SDasaratharaman Chandramouli 	}
243567cdb40cSRoland Dreier 
2436ef87df2cSJason Gunthorpe 	ah = rdma_create_user_ah(pd, &attr, &attrs->driver_udata);
243767cdb40cSRoland Dreier 	if (IS_ERR(ah)) {
243867cdb40cSRoland Dreier 		ret = PTR_ERR(ah);
2439fd3c7904SMatan Barak 		goto err_put;
244067cdb40cSRoland Dreier 	}
244167cdb40cSRoland Dreier 
244267cdb40cSRoland Dreier 	ah->uobject  = uobj;
2443fd3c7904SMatan Barak 	uobj->user_handle = cmd.user_handle;
24449ead190bSRoland Dreier 	uobj->object = ah;
244516e51f78SLeon Romanovsky 	uobj_put_obj_read(pd);
244616e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(uobj, attrs);
244767cdb40cSRoland Dreier 
244867cdb40cSRoland Dreier 	resp.ah_handle = uobj->id;
244916e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
245067cdb40cSRoland Dreier 
2451fd3c7904SMatan Barak err_put:
2452fd3c7904SMatan Barak 	uobj_put_obj_read(pd);
24539ead190bSRoland Dreier err:
2454a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(uobj, attrs);
245567cdb40cSRoland Dreier 	return ret;
245667cdb40cSRoland Dreier }
245767cdb40cSRoland Dreier 
ib_uverbs_destroy_ah(struct uverbs_attr_bundle * attrs)2458974d6b4bSJason Gunthorpe static int ib_uverbs_destroy_ah(struct uverbs_attr_bundle *attrs)
245967cdb40cSRoland Dreier {
246067cdb40cSRoland Dreier 	struct ib_uverbs_destroy_ah cmd;
24613c2c2094SJason Gunthorpe 	int ret;
246267cdb40cSRoland Dreier 
24633c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
24643c2c2094SJason Gunthorpe 	if (ret)
24653c2c2094SJason Gunthorpe 		return ret;
246667cdb40cSRoland Dreier 
24677106a976SJason Gunthorpe 	return uobj_perform_destroy(UVERBS_OBJECT_AH, cmd.ah_handle, attrs);
246867cdb40cSRoland Dreier }
246967cdb40cSRoland Dreier 
ib_uverbs_attach_mcast(struct uverbs_attr_bundle * attrs)2470974d6b4bSJason Gunthorpe static int ib_uverbs_attach_mcast(struct uverbs_attr_bundle *attrs)
2471bc38a6abSRoland Dreier {
2472bc38a6abSRoland Dreier 	struct ib_uverbs_attach_mcast cmd;
2473bc38a6abSRoland Dreier 	struct ib_qp                 *qp;
24749ead190bSRoland Dreier 	struct ib_uqp_object         *obj;
2475f4e40156SJack Morgenstein 	struct ib_uverbs_mcast_entry *mcast;
24769ead190bSRoland Dreier 	int                           ret;
2477bc38a6abSRoland Dreier 
24783c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
24793c2c2094SJason Gunthorpe 	if (ret)
24803c2c2094SJason Gunthorpe 		return ret;
2481bc38a6abSRoland Dreier 
24828313c10fSJason Gunthorpe 	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
24839ead190bSRoland Dreier 	if (!qp)
24849ead190bSRoland Dreier 		return -EINVAL;
2485bc38a6abSRoland Dreier 
2486620d3f81SJason Gunthorpe 	obj = qp->uobject;
2487bc38a6abSRoland Dreier 
2488f48b7269SMatan Barak 	mutex_lock(&obj->mcast_lock);
24899ead190bSRoland Dreier 	list_for_each_entry(mcast, &obj->mcast_list, list)
2490f4e40156SJack Morgenstein 		if (cmd.mlid == mcast->lid &&
2491f4e40156SJack Morgenstein 		    !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
2492f4e40156SJack Morgenstein 			ret = 0;
24939ead190bSRoland Dreier 			goto out_put;
2494f4e40156SJack Morgenstein 		}
2495f4e40156SJack Morgenstein 
2496f4e40156SJack Morgenstein 	mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
2497f4e40156SJack Morgenstein 	if (!mcast) {
2498f4e40156SJack Morgenstein 		ret = -ENOMEM;
24999ead190bSRoland Dreier 		goto out_put;
2500f4e40156SJack Morgenstein 	}
2501f4e40156SJack Morgenstein 
2502f4e40156SJack Morgenstein 	mcast->lid = cmd.mlid;
2503f4e40156SJack Morgenstein 	memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw);
2504f4e40156SJack Morgenstein 
2505f4e40156SJack Morgenstein 	ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid);
25069ead190bSRoland Dreier 	if (!ret)
25079ead190bSRoland Dreier 		list_add_tail(&mcast->list, &obj->mcast_list);
25089ead190bSRoland Dreier 	else
2509f4e40156SJack Morgenstein 		kfree(mcast);
2510f4e40156SJack Morgenstein 
25119ead190bSRoland Dreier out_put:
2512f48b7269SMatan Barak 	mutex_unlock(&obj->mcast_lock);
2513620d3f81SJason Gunthorpe 	rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
2514620d3f81SJason Gunthorpe 				UVERBS_LOOKUP_READ);
2515bc38a6abSRoland Dreier 
25167106a976SJason Gunthorpe 	return ret;
2517bc38a6abSRoland Dreier }
2518bc38a6abSRoland Dreier 
ib_uverbs_detach_mcast(struct uverbs_attr_bundle * attrs)2519974d6b4bSJason Gunthorpe static int ib_uverbs_detach_mcast(struct uverbs_attr_bundle *attrs)
2520bc38a6abSRoland Dreier {
2521bc38a6abSRoland Dreier 	struct ib_uverbs_detach_mcast cmd;
25229ead190bSRoland Dreier 	struct ib_uqp_object         *obj;
2523bc38a6abSRoland Dreier 	struct ib_qp                 *qp;
2524f4e40156SJack Morgenstein 	struct ib_uverbs_mcast_entry *mcast;
25250bddcff6SColin Ian King 	int                           ret;
252620c7840aSMichael J. Ruhl 	bool                          found = false;
2527bc38a6abSRoland Dreier 
25283c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
25293c2c2094SJason Gunthorpe 	if (ret)
25303c2c2094SJason Gunthorpe 		return ret;
2531bc38a6abSRoland Dreier 
25328313c10fSJason Gunthorpe 	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
25339ead190bSRoland Dreier 	if (!qp)
25349ead190bSRoland Dreier 		return -EINVAL;
2535bc38a6abSRoland Dreier 
2536620d3f81SJason Gunthorpe 	obj = qp->uobject;
2537f48b7269SMatan Barak 	mutex_lock(&obj->mcast_lock);
2538fd3c7904SMatan Barak 
25399ead190bSRoland Dreier 	list_for_each_entry(mcast, &obj->mcast_list, list)
2540f4e40156SJack Morgenstein 		if (cmd.mlid == mcast->lid &&
2541f4e40156SJack Morgenstein 		    !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
2542f4e40156SJack Morgenstein 			list_del(&mcast->list);
2543f4e40156SJack Morgenstein 			kfree(mcast);
254420c7840aSMichael J. Ruhl 			found = true;
2545f4e40156SJack Morgenstein 			break;
2546f4e40156SJack Morgenstein 		}
2547f4e40156SJack Morgenstein 
254820c7840aSMichael J. Ruhl 	if (!found) {
254920c7840aSMichael J. Ruhl 		ret = -EINVAL;
255020c7840aSMichael J. Ruhl 		goto out_put;
255120c7840aSMichael J. Ruhl 	}
255220c7840aSMichael J. Ruhl 
255320c7840aSMichael J. Ruhl 	ret = ib_detach_mcast(qp, (union ib_gid *)cmd.gid, cmd.mlid);
255420c7840aSMichael J. Ruhl 
25559ead190bSRoland Dreier out_put:
2556f48b7269SMatan Barak 	mutex_unlock(&obj->mcast_lock);
2557620d3f81SJason Gunthorpe 	rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
2558620d3f81SJason Gunthorpe 				UVERBS_LOOKUP_READ);
25597106a976SJason Gunthorpe 	return ret;
2560bc38a6abSRoland Dreier }
2561f520ba5aSRoland Dreier 
flow_resources_alloc(size_t num_specs)2562fa76d24eSMark Bloch struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
25639b828441SMatan Barak {
25649b828441SMatan Barak 	struct ib_uflow_resources *resources;
25659b828441SMatan Barak 
2566b6ba4a9aSRaed Salem 	resources = kzalloc(sizeof(*resources), GFP_KERNEL);
25679b828441SMatan Barak 
25689b828441SMatan Barak 	if (!resources)
2569de749814SLeon Romanovsky 		return NULL;
25709b828441SMatan Barak 
2571a5cc9831SLeon Romanovsky 	if (!num_specs)
2572a5cc9831SLeon Romanovsky 		goto out;
2573a5cc9831SLeon Romanovsky 
2574b6ba4a9aSRaed Salem 	resources->counters =
2575b6ba4a9aSRaed Salem 		kcalloc(num_specs, sizeof(*resources->counters), GFP_KERNEL);
2576b6ba4a9aSRaed Salem 	resources->collection =
2577b6ba4a9aSRaed Salem 		kcalloc(num_specs, sizeof(*resources->collection), GFP_KERNEL);
2578b6ba4a9aSRaed Salem 
2579de749814SLeon Romanovsky 	if (!resources->counters || !resources->collection)
2580de749814SLeon Romanovsky 		goto err;
2581b6ba4a9aSRaed Salem 
2582a5cc9831SLeon Romanovsky out:
25839b828441SMatan Barak 	resources->max = num_specs;
25849b828441SMatan Barak 	return resources;
2585b6ba4a9aSRaed Salem 
2586de749814SLeon Romanovsky err:
2587b6ba4a9aSRaed Salem 	kfree(resources->counters);
2588b6ba4a9aSRaed Salem 	kfree(resources);
2589de749814SLeon Romanovsky 
2590b6ba4a9aSRaed Salem 	return NULL;
25919b828441SMatan Barak }
2592fa76d24eSMark Bloch EXPORT_SYMBOL(flow_resources_alloc);
25939b828441SMatan Barak 
ib_uverbs_flow_resources_free(struct ib_uflow_resources * uflow_res)25949b828441SMatan Barak void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res)
25959b828441SMatan Barak {
25969b828441SMatan Barak 	unsigned int i;
25979b828441SMatan Barak 
25986cd080a6SYishai Hadas 	if (!uflow_res)
25996cd080a6SYishai Hadas 		return;
26006cd080a6SYishai Hadas 
2601b6ba4a9aSRaed Salem 	for (i = 0; i < uflow_res->collection_num; i++)
26029b828441SMatan Barak 		atomic_dec(&uflow_res->collection[i]->usecnt);
26039b828441SMatan Barak 
2604b6ba4a9aSRaed Salem 	for (i = 0; i < uflow_res->counters_num; i++)
2605b6ba4a9aSRaed Salem 		atomic_dec(&uflow_res->counters[i]->usecnt);
2606b6ba4a9aSRaed Salem 
2607b6ba4a9aSRaed Salem 	kfree(uflow_res->collection);
2608b6ba4a9aSRaed Salem 	kfree(uflow_res->counters);
26099b828441SMatan Barak 	kfree(uflow_res);
26109b828441SMatan Barak }
2611fa76d24eSMark Bloch EXPORT_SYMBOL(ib_uverbs_flow_resources_free);
26129b828441SMatan Barak 
flow_resources_add(struct ib_uflow_resources * uflow_res,enum ib_flow_spec_type type,void * ibobj)2613fa76d24eSMark Bloch void flow_resources_add(struct ib_uflow_resources *uflow_res,
2614b6ba4a9aSRaed Salem 			enum ib_flow_spec_type type,
2615b6ba4a9aSRaed Salem 			void *ibobj)
26169b828441SMatan Barak {
26179b828441SMatan Barak 	WARN_ON(uflow_res->num >= uflow_res->max);
26189b828441SMatan Barak 
2619b6ba4a9aSRaed Salem 	switch (type) {
2620b6ba4a9aSRaed Salem 	case IB_FLOW_SPEC_ACTION_HANDLE:
2621b6ba4a9aSRaed Salem 		atomic_inc(&((struct ib_flow_action *)ibobj)->usecnt);
2622b6ba4a9aSRaed Salem 		uflow_res->collection[uflow_res->collection_num++] =
2623b6ba4a9aSRaed Salem 			(struct ib_flow_action *)ibobj;
2624b6ba4a9aSRaed Salem 		break;
2625b6ba4a9aSRaed Salem 	case IB_FLOW_SPEC_ACTION_COUNT:
2626b6ba4a9aSRaed Salem 		atomic_inc(&((struct ib_counters *)ibobj)->usecnt);
2627b6ba4a9aSRaed Salem 		uflow_res->counters[uflow_res->counters_num++] =
2628b6ba4a9aSRaed Salem 			(struct ib_counters *)ibobj;
2629b6ba4a9aSRaed Salem 		break;
2630b6ba4a9aSRaed Salem 	default:
2631b6ba4a9aSRaed Salem 		WARN_ON(1);
2632b6ba4a9aSRaed Salem 	}
2633b6ba4a9aSRaed Salem 
2634b6ba4a9aSRaed Salem 	uflow_res->num++;
26359b828441SMatan Barak }
2636fa76d24eSMark Bloch EXPORT_SYMBOL(flow_resources_add);
26379b828441SMatan Barak 
kern_spec_to_ib_spec_action(struct uverbs_attr_bundle * attrs,struct ib_uverbs_flow_spec * kern_spec,union ib_flow_spec * ib_spec,struct ib_uflow_resources * uflow_res)26383d9dfd06SShamir Rabinovitch static int kern_spec_to_ib_spec_action(struct uverbs_attr_bundle *attrs,
26399b828441SMatan Barak 				       struct ib_uverbs_flow_spec *kern_spec,
26409b828441SMatan Barak 				       union ib_flow_spec *ib_spec,
26419b828441SMatan Barak 				       struct ib_uflow_resources *uflow_res)
264294e03f11SMoses Reuben {
264394e03f11SMoses Reuben 	ib_spec->type = kern_spec->type;
264494e03f11SMoses Reuben 	switch (ib_spec->type) {
264594e03f11SMoses Reuben 	case IB_FLOW_SPEC_ACTION_TAG:
264694e03f11SMoses Reuben 		if (kern_spec->flow_tag.size !=
264794e03f11SMoses Reuben 		    sizeof(struct ib_uverbs_flow_spec_action_tag))
264894e03f11SMoses Reuben 			return -EINVAL;
264994e03f11SMoses Reuben 
265094e03f11SMoses Reuben 		ib_spec->flow_tag.size = sizeof(struct ib_flow_spec_action_tag);
265194e03f11SMoses Reuben 		ib_spec->flow_tag.tag_id = kern_spec->flow_tag.tag_id;
265294e03f11SMoses Reuben 		break;
2653483a3966SSlava Shwartsman 	case IB_FLOW_SPEC_ACTION_DROP:
2654483a3966SSlava Shwartsman 		if (kern_spec->drop.size !=
2655483a3966SSlava Shwartsman 		    sizeof(struct ib_uverbs_flow_spec_action_drop))
2656483a3966SSlava Shwartsman 			return -EINVAL;
2657483a3966SSlava Shwartsman 
2658483a3966SSlava Shwartsman 		ib_spec->drop.size = sizeof(struct ib_flow_spec_action_drop);
2659483a3966SSlava Shwartsman 		break;
26609b828441SMatan Barak 	case IB_FLOW_SPEC_ACTION_HANDLE:
26619b828441SMatan Barak 		if (kern_spec->action.size !=
26629b828441SMatan Barak 		    sizeof(struct ib_uverbs_flow_spec_action_handle))
26639b828441SMatan Barak 			return -EOPNOTSUPP;
26649b828441SMatan Barak 		ib_spec->action.act = uobj_get_obj_read(flow_action,
26659b828441SMatan Barak 							UVERBS_OBJECT_FLOW_ACTION,
26669b828441SMatan Barak 							kern_spec->action.handle,
26678313c10fSJason Gunthorpe 							attrs);
26689b828441SMatan Barak 		if (!ib_spec->action.act)
26699b828441SMatan Barak 			return -EINVAL;
26709b828441SMatan Barak 		ib_spec->action.size =
26719b828441SMatan Barak 			sizeof(struct ib_flow_spec_action_handle);
2672b6ba4a9aSRaed Salem 		flow_resources_add(uflow_res,
2673b6ba4a9aSRaed Salem 				   IB_FLOW_SPEC_ACTION_HANDLE,
2674b6ba4a9aSRaed Salem 				   ib_spec->action.act);
26759b828441SMatan Barak 		uobj_put_obj_read(ib_spec->action.act);
26769b828441SMatan Barak 		break;
2677b6ba4a9aSRaed Salem 	case IB_FLOW_SPEC_ACTION_COUNT:
2678b6ba4a9aSRaed Salem 		if (kern_spec->flow_count.size !=
2679b6ba4a9aSRaed Salem 			sizeof(struct ib_uverbs_flow_spec_action_count))
2680b6ba4a9aSRaed Salem 			return -EINVAL;
2681b6ba4a9aSRaed Salem 		ib_spec->flow_count.counters =
2682b6ba4a9aSRaed Salem 			uobj_get_obj_read(counters,
2683b6ba4a9aSRaed Salem 					  UVERBS_OBJECT_COUNTERS,
2684b6ba4a9aSRaed Salem 					  kern_spec->flow_count.handle,
26858313c10fSJason Gunthorpe 					  attrs);
2686b6ba4a9aSRaed Salem 		if (!ib_spec->flow_count.counters)
2687b6ba4a9aSRaed Salem 			return -EINVAL;
2688b6ba4a9aSRaed Salem 		ib_spec->flow_count.size =
2689b6ba4a9aSRaed Salem 				sizeof(struct ib_flow_spec_action_count);
2690b6ba4a9aSRaed Salem 		flow_resources_add(uflow_res,
2691b6ba4a9aSRaed Salem 				   IB_FLOW_SPEC_ACTION_COUNT,
2692b6ba4a9aSRaed Salem 				   ib_spec->flow_count.counters);
2693b6ba4a9aSRaed Salem 		uobj_put_obj_read(ib_spec->flow_count.counters);
2694b6ba4a9aSRaed Salem 		break;
269594e03f11SMoses Reuben 	default:
269694e03f11SMoses Reuben 		return -EINVAL;
269794e03f11SMoses Reuben 	}
269894e03f11SMoses Reuben 	return 0;
269994e03f11SMoses Reuben }
270094e03f11SMoses Reuben 
spec_filter_size(const void * kern_spec_filter,u16 kern_filter_size,u16 ib_real_filter_sz)2701766d8551SMatan Barak static ssize_t spec_filter_size(const void *kern_spec_filter, u16 kern_filter_size,
270215dfbd6bSMaor Gottlieb 				u16 ib_real_filter_sz)
270315dfbd6bSMaor Gottlieb {
270415dfbd6bSMaor Gottlieb 	/*
270515dfbd6bSMaor Gottlieb 	 * User space filter structures must be 64 bit aligned, otherwise this
270615dfbd6bSMaor Gottlieb 	 * may pass, but we won't handle additional new attributes.
270715dfbd6bSMaor Gottlieb 	 */
270815dfbd6bSMaor Gottlieb 
270915dfbd6bSMaor Gottlieb 	if (kern_filter_size > ib_real_filter_sz) {
271015dfbd6bSMaor Gottlieb 		if (memchr_inv(kern_spec_filter +
271115dfbd6bSMaor Gottlieb 			       ib_real_filter_sz, 0,
271215dfbd6bSMaor Gottlieb 			       kern_filter_size - ib_real_filter_sz))
271315dfbd6bSMaor Gottlieb 			return -EINVAL;
271415dfbd6bSMaor Gottlieb 		return ib_real_filter_sz;
271515dfbd6bSMaor Gottlieb 	}
271615dfbd6bSMaor Gottlieb 	return kern_filter_size;
271715dfbd6bSMaor Gottlieb }
271815dfbd6bSMaor Gottlieb 
ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,const void * kern_spec_mask,const void * kern_spec_val,size_t kern_filter_sz,union ib_flow_spec * ib_spec)2719766d8551SMatan Barak int ib_uverbs_kern_spec_to_ib_spec_filter(enum ib_flow_spec_type type,
2720766d8551SMatan Barak 					  const void *kern_spec_mask,
2721766d8551SMatan Barak 					  const void *kern_spec_val,
2722766d8551SMatan Barak 					  size_t kern_filter_sz,
2723436f2ad0SHadar Hen Zion 					  union ib_flow_spec *ib_spec)
2724436f2ad0SHadar Hen Zion {
272515dfbd6bSMaor Gottlieb 	ssize_t actual_filter_sz;
272615dfbd6bSMaor Gottlieb 	ssize_t ib_filter_sz;
272715dfbd6bSMaor Gottlieb 
272815dfbd6bSMaor Gottlieb 	/* User flow spec size must be aligned to 4 bytes */
272915dfbd6bSMaor Gottlieb 	if (kern_filter_sz != ALIGN(kern_filter_sz, 4))
273015dfbd6bSMaor Gottlieb 		return -EINVAL;
273115dfbd6bSMaor Gottlieb 
2732766d8551SMatan Barak 	ib_spec->type = type;
2733766d8551SMatan Barak 
2734fbf46860SMoses Reuben 	if (ib_spec->type == (IB_FLOW_SPEC_INNER | IB_FLOW_SPEC_VXLAN_TUNNEL))
2735fbf46860SMoses Reuben 		return -EINVAL;
273615dfbd6bSMaor Gottlieb 
2737fbf46860SMoses Reuben 	switch (ib_spec->type & ~IB_FLOW_SPEC_INNER) {
2738436f2ad0SHadar Hen Zion 	case IB_FLOW_SPEC_ETH:
273915dfbd6bSMaor Gottlieb 		ib_filter_sz = offsetof(struct ib_flow_eth_filter, real_sz);
274015dfbd6bSMaor Gottlieb 		actual_filter_sz = spec_filter_size(kern_spec_mask,
274115dfbd6bSMaor Gottlieb 						    kern_filter_sz,
274215dfbd6bSMaor Gottlieb 						    ib_filter_sz);
274315dfbd6bSMaor Gottlieb 		if (actual_filter_sz <= 0)
2744436f2ad0SHadar Hen Zion 			return -EINVAL;
274515dfbd6bSMaor Gottlieb 		ib_spec->size = sizeof(struct ib_flow_spec_eth);
274615dfbd6bSMaor Gottlieb 		memcpy(&ib_spec->eth.val, kern_spec_val, actual_filter_sz);
274715dfbd6bSMaor Gottlieb 		memcpy(&ib_spec->eth.mask, kern_spec_mask, actual_filter_sz);
2748436f2ad0SHadar Hen Zion 		break;
2749436f2ad0SHadar Hen Zion 	case IB_FLOW_SPEC_IPV4:
275015dfbd6bSMaor Gottlieb 		ib_filter_sz = offsetof(struct ib_flow_ipv4_filter, real_sz);
275115dfbd6bSMaor Gottlieb 		actual_filter_sz = spec_filter_size(kern_spec_mask,
275215dfbd6bSMaor Gottlieb 						    kern_filter_sz,
275315dfbd6bSMaor Gottlieb 						    ib_filter_sz);
275415dfbd6bSMaor Gottlieb 		if (actual_filter_sz <= 0)
2755436f2ad0SHadar Hen Zion 			return -EINVAL;
275615dfbd6bSMaor Gottlieb 		ib_spec->size = sizeof(struct ib_flow_spec_ipv4);
275715dfbd6bSMaor Gottlieb 		memcpy(&ib_spec->ipv4.val, kern_spec_val, actual_filter_sz);
275815dfbd6bSMaor Gottlieb 		memcpy(&ib_spec->ipv4.mask, kern_spec_mask, actual_filter_sz);
2759436f2ad0SHadar Hen Zion 		break;
27604c2aae71SMaor Gottlieb 	case IB_FLOW_SPEC_IPV6:
276115dfbd6bSMaor Gottlieb 		ib_filter_sz = offsetof(struct ib_flow_ipv6_filter, real_sz);
276215dfbd6bSMaor Gottlieb 		actual_filter_sz = spec_filter_size(kern_spec_mask,
276315dfbd6bSMaor Gottlieb 						    kern_filter_sz,
276415dfbd6bSMaor Gottlieb 						    ib_filter_sz);
276515dfbd6bSMaor Gottlieb 		if (actual_filter_sz <= 0)
27664c2aae71SMaor Gottlieb 			return -EINVAL;
276715dfbd6bSMaor Gottlieb 		ib_spec->size = sizeof(struct ib_flow_spec_ipv6);
276815dfbd6bSMaor Gottlieb 		memcpy(&ib_spec->ipv6.val, kern_spec_val, actual_filter_sz);
276915dfbd6bSMaor Gottlieb 		memcpy(&ib_spec->ipv6.mask, kern_spec_mask, actual_filter_sz);
2770a72c6a2bSMaor Gottlieb 
2771a72c6a2bSMaor Gottlieb 		if ((ntohl(ib_spec->ipv6.mask.flow_label)) >= BIT(20) ||
2772a72c6a2bSMaor Gottlieb 		    (ntohl(ib_spec->ipv6.val.flow_label)) >= BIT(20))
2773a72c6a2bSMaor Gottlieb 			return -EINVAL;
27744c2aae71SMaor Gottlieb 		break;
2775436f2ad0SHadar Hen Zion 	case IB_FLOW_SPEC_TCP:
2776436f2ad0SHadar Hen Zion 	case IB_FLOW_SPEC_UDP:
277715dfbd6bSMaor Gottlieb 		ib_filter_sz = offsetof(struct ib_flow_tcp_udp_filter, real_sz);
277815dfbd6bSMaor Gottlieb 		actual_filter_sz = spec_filter_size(kern_spec_mask,
277915dfbd6bSMaor Gottlieb 						    kern_filter_sz,
278015dfbd6bSMaor Gottlieb 						    ib_filter_sz);
278115dfbd6bSMaor Gottlieb 		if (actual_filter_sz <= 0)
2782436f2ad0SHadar Hen Zion 			return -EINVAL;
278315dfbd6bSMaor Gottlieb 		ib_spec->size = sizeof(struct ib_flow_spec_tcp_udp);
278415dfbd6bSMaor Gottlieb 		memcpy(&ib_spec->tcp_udp.val, kern_spec_val, actual_filter_sz);
278515dfbd6bSMaor Gottlieb 		memcpy(&ib_spec->tcp_udp.mask, kern_spec_mask, actual_filter_sz);
2786436f2ad0SHadar Hen Zion 		break;
27870dbf3332SMoses Reuben 	case IB_FLOW_SPEC_VXLAN_TUNNEL:
27880dbf3332SMoses Reuben 		ib_filter_sz = offsetof(struct ib_flow_tunnel_filter, real_sz);
27890dbf3332SMoses Reuben 		actual_filter_sz = spec_filter_size(kern_spec_mask,
27900dbf3332SMoses Reuben 						    kern_filter_sz,
27910dbf3332SMoses Reuben 						    ib_filter_sz);
27920dbf3332SMoses Reuben 		if (actual_filter_sz <= 0)
27930dbf3332SMoses Reuben 			return -EINVAL;
27940dbf3332SMoses Reuben 		ib_spec->tunnel.size = sizeof(struct ib_flow_spec_tunnel);
27950dbf3332SMoses Reuben 		memcpy(&ib_spec->tunnel.val, kern_spec_val, actual_filter_sz);
27960dbf3332SMoses Reuben 		memcpy(&ib_spec->tunnel.mask, kern_spec_mask, actual_filter_sz);
27970dbf3332SMoses Reuben 
27980dbf3332SMoses Reuben 		if ((ntohl(ib_spec->tunnel.mask.tunnel_id)) >= BIT(24) ||
27990dbf3332SMoses Reuben 		    (ntohl(ib_spec->tunnel.val.tunnel_id)) >= BIT(24))
28000dbf3332SMoses Reuben 			return -EINVAL;
28010dbf3332SMoses Reuben 		break;
280256ab0b38SMatan Barak 	case IB_FLOW_SPEC_ESP:
280356ab0b38SMatan Barak 		ib_filter_sz = offsetof(struct ib_flow_esp_filter, real_sz);
280456ab0b38SMatan Barak 		actual_filter_sz = spec_filter_size(kern_spec_mask,
280556ab0b38SMatan Barak 						    kern_filter_sz,
280656ab0b38SMatan Barak 						    ib_filter_sz);
280756ab0b38SMatan Barak 		if (actual_filter_sz <= 0)
280856ab0b38SMatan Barak 			return -EINVAL;
280956ab0b38SMatan Barak 		ib_spec->esp.size = sizeof(struct ib_flow_spec_esp);
281056ab0b38SMatan Barak 		memcpy(&ib_spec->esp.val, kern_spec_val, actual_filter_sz);
281156ab0b38SMatan Barak 		memcpy(&ib_spec->esp.mask, kern_spec_mask, actual_filter_sz);
281256ab0b38SMatan Barak 		break;
2813d90e5e50SAriel Levkovich 	case IB_FLOW_SPEC_GRE:
2814d90e5e50SAriel Levkovich 		ib_filter_sz = offsetof(struct ib_flow_gre_filter, real_sz);
2815d90e5e50SAriel Levkovich 		actual_filter_sz = spec_filter_size(kern_spec_mask,
2816d90e5e50SAriel Levkovich 						    kern_filter_sz,
2817d90e5e50SAriel Levkovich 						    ib_filter_sz);
2818d90e5e50SAriel Levkovich 		if (actual_filter_sz <= 0)
2819d90e5e50SAriel Levkovich 			return -EINVAL;
2820d90e5e50SAriel Levkovich 		ib_spec->gre.size = sizeof(struct ib_flow_spec_gre);
2821d90e5e50SAriel Levkovich 		memcpy(&ib_spec->gre.val, kern_spec_val, actual_filter_sz);
2822d90e5e50SAriel Levkovich 		memcpy(&ib_spec->gre.mask, kern_spec_mask, actual_filter_sz);
2823d90e5e50SAriel Levkovich 		break;
2824b04f0f03SAriel Levkovich 	case IB_FLOW_SPEC_MPLS:
2825b04f0f03SAriel Levkovich 		ib_filter_sz = offsetof(struct ib_flow_mpls_filter, real_sz);
2826b04f0f03SAriel Levkovich 		actual_filter_sz = spec_filter_size(kern_spec_mask,
2827b04f0f03SAriel Levkovich 						    kern_filter_sz,
2828b04f0f03SAriel Levkovich 						    ib_filter_sz);
2829b04f0f03SAriel Levkovich 		if (actual_filter_sz <= 0)
2830b04f0f03SAriel Levkovich 			return -EINVAL;
2831b04f0f03SAriel Levkovich 		ib_spec->mpls.size = sizeof(struct ib_flow_spec_mpls);
2832b04f0f03SAriel Levkovich 		memcpy(&ib_spec->mpls.val, kern_spec_val, actual_filter_sz);
2833b04f0f03SAriel Levkovich 		memcpy(&ib_spec->mpls.mask, kern_spec_mask, actual_filter_sz);
2834b04f0f03SAriel Levkovich 		break;
2835436f2ad0SHadar Hen Zion 	default:
2836436f2ad0SHadar Hen Zion 		return -EINVAL;
2837436f2ad0SHadar Hen Zion 	}
2838436f2ad0SHadar Hen Zion 	return 0;
2839436f2ad0SHadar Hen Zion }
2840436f2ad0SHadar Hen Zion 
kern_spec_to_ib_spec_filter(struct ib_uverbs_flow_spec * kern_spec,union ib_flow_spec * ib_spec)2841766d8551SMatan Barak static int kern_spec_to_ib_spec_filter(struct ib_uverbs_flow_spec *kern_spec,
2842766d8551SMatan Barak 				       union ib_flow_spec *ib_spec)
2843766d8551SMatan Barak {
2844a72f4ac1SAvihai Horon 	size_t kern_filter_sz;
2845766d8551SMatan Barak 	void *kern_spec_mask;
2846766d8551SMatan Barak 	void *kern_spec_val;
2847766d8551SMatan Barak 
2848a72f4ac1SAvihai Horon 	if (check_sub_overflow((size_t)kern_spec->hdr.size,
2849a72f4ac1SAvihai Horon 			       sizeof(struct ib_uverbs_flow_spec_hdr),
2850a72f4ac1SAvihai Horon 			       &kern_filter_sz))
2851a72f4ac1SAvihai Horon 		return -EINVAL;
2852a72f4ac1SAvihai Horon 
2853a72f4ac1SAvihai Horon 	kern_filter_sz /= 2;
2854766d8551SMatan Barak 
2855766d8551SMatan Barak 	kern_spec_val = (void *)kern_spec +
2856766d8551SMatan Barak 		sizeof(struct ib_uverbs_flow_spec_hdr);
2857766d8551SMatan Barak 	kern_spec_mask = kern_spec_val + kern_filter_sz;
2858766d8551SMatan Barak 
2859766d8551SMatan Barak 	return ib_uverbs_kern_spec_to_ib_spec_filter(kern_spec->type,
2860766d8551SMatan Barak 						     kern_spec_mask,
2861766d8551SMatan Barak 						     kern_spec_val,
2862766d8551SMatan Barak 						     kern_filter_sz, ib_spec);
2863766d8551SMatan Barak }
2864766d8551SMatan Barak 
kern_spec_to_ib_spec(struct uverbs_attr_bundle * attrs,struct ib_uverbs_flow_spec * kern_spec,union ib_flow_spec * ib_spec,struct ib_uflow_resources * uflow_res)28658313c10fSJason Gunthorpe static int kern_spec_to_ib_spec(struct uverbs_attr_bundle *attrs,
28669b828441SMatan Barak 				struct ib_uverbs_flow_spec *kern_spec,
28679b828441SMatan Barak 				union ib_flow_spec *ib_spec,
28689b828441SMatan Barak 				struct ib_uflow_resources *uflow_res)
286994e03f11SMoses Reuben {
287094e03f11SMoses Reuben 	if (kern_spec->reserved)
287194e03f11SMoses Reuben 		return -EINVAL;
287294e03f11SMoses Reuben 
287394e03f11SMoses Reuben 	if (kern_spec->type >= IB_FLOW_SPEC_ACTION_TAG)
28748313c10fSJason Gunthorpe 		return kern_spec_to_ib_spec_action(attrs, kern_spec, ib_spec,
28759b828441SMatan Barak 						   uflow_res);
287694e03f11SMoses Reuben 	else
287794e03f11SMoses Reuben 		return kern_spec_to_ib_spec_filter(kern_spec, ib_spec);
287894e03f11SMoses Reuben }
287994e03f11SMoses Reuben 
ib_uverbs_ex_create_wq(struct uverbs_attr_bundle * attrs)2880974d6b4bSJason Gunthorpe static int ib_uverbs_ex_create_wq(struct uverbs_attr_bundle *attrs)
2881f213c052SYishai Hadas {
288229a29d18SJason Gunthorpe 	struct ib_uverbs_ex_create_wq cmd;
2883f213c052SYishai Hadas 	struct ib_uverbs_ex_create_wq_resp resp = {};
2884f213c052SYishai Hadas 	struct ib_uwq_object           *obj;
2885f213c052SYishai Hadas 	int err = 0;
2886f213c052SYishai Hadas 	struct ib_cq *cq;
2887f213c052SYishai Hadas 	struct ib_pd *pd;
2888f213c052SYishai Hadas 	struct ib_wq *wq;
2889f213c052SYishai Hadas 	struct ib_wq_init_attr wq_init_attr = {};
2890bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
2891f213c052SYishai Hadas 
289229a29d18SJason Gunthorpe 	err = uverbs_request(attrs, &cmd, sizeof(cmd));
2893f213c052SYishai Hadas 	if (err)
2894f213c052SYishai Hadas 		return err;
2895f213c052SYishai Hadas 
2896f213c052SYishai Hadas 	if (cmd.comp_mask)
2897f213c052SYishai Hadas 		return -EOPNOTSUPP;
2898f213c052SYishai Hadas 
28998313c10fSJason Gunthorpe 	obj = (struct ib_uwq_object *)uobj_alloc(UVERBS_OBJECT_WQ, attrs,
2900bbd51e88SJason Gunthorpe 						 &ib_dev);
2901fd3c7904SMatan Barak 	if (IS_ERR(obj))
2902fd3c7904SMatan Barak 		return PTR_ERR(obj);
2903f213c052SYishai Hadas 
29048313c10fSJason Gunthorpe 	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd.pd_handle, attrs);
2905f213c052SYishai Hadas 	if (!pd) {
2906f213c052SYishai Hadas 		err = -EINVAL;
2907f213c052SYishai Hadas 		goto err_uobj;
2908f213c052SYishai Hadas 	}
2909f213c052SYishai Hadas 
29108313c10fSJason Gunthorpe 	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
2911f213c052SYishai Hadas 	if (!cq) {
2912f213c052SYishai Hadas 		err = -EINVAL;
2913f213c052SYishai Hadas 		goto err_put_pd;
2914f213c052SYishai Hadas 	}
2915f213c052SYishai Hadas 
2916f213c052SYishai Hadas 	wq_init_attr.cq = cq;
2917f213c052SYishai Hadas 	wq_init_attr.max_sge = cmd.max_sge;
2918f213c052SYishai Hadas 	wq_init_attr.max_wr = cmd.max_wr;
2919f213c052SYishai Hadas 	wq_init_attr.wq_type = cmd.wq_type;
2920f213c052SYishai Hadas 	wq_init_attr.event_handler = ib_uverbs_wq_event_handler;
2921af1cb95dSNoa Osherovich 	wq_init_attr.create_flags = cmd.create_flags;
2922f213c052SYishai Hadas 	INIT_LIST_HEAD(&obj->uevent.event_list);
2923dbd67252SYishai Hadas 	obj->uevent.uobject.user_handle = cmd.user_handle;
292421885586SLeon Romanovsky 
29253023a1e9SKamal Heib 	wq = pd->device->ops.create_wq(pd, &wq_init_attr, &attrs->driver_udata);
2926f213c052SYishai Hadas 	if (IS_ERR(wq)) {
2927f213c052SYishai Hadas 		err = PTR_ERR(wq);
2928f213c052SYishai Hadas 		goto err_put_cq;
2929f213c052SYishai Hadas 	}
2930f213c052SYishai Hadas 
2931e04dd131SJason Gunthorpe 	wq->uobject = obj;
2932f213c052SYishai Hadas 	obj->uevent.uobject.object = wq;
2933f213c052SYishai Hadas 	wq->wq_type = wq_init_attr.wq_type;
2934f213c052SYishai Hadas 	wq->cq = cq;
2935f213c052SYishai Hadas 	wq->pd = pd;
2936f213c052SYishai Hadas 	wq->device = pd->device;
2937f213c052SYishai Hadas 	atomic_set(&wq->usecnt, 0);
2938f213c052SYishai Hadas 	atomic_inc(&pd->usecnt);
2939f213c052SYishai Hadas 	atomic_inc(&cq->usecnt);
294098a8890fSYishai Hadas 	obj->uevent.event_file = READ_ONCE(attrs->ufile->default_async_file);
294198a8890fSYishai Hadas 	if (obj->uevent.event_file)
294298a8890fSYishai Hadas 		uverbs_uobject_get(&obj->uevent.event_file->uobj);
2943f213c052SYishai Hadas 
294416e51f78SLeon Romanovsky 	uobj_put_obj_read(pd);
294516e51f78SLeon Romanovsky 	rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
294616e51f78SLeon Romanovsky 				UVERBS_LOOKUP_READ);
294716e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
294816e51f78SLeon Romanovsky 
2949f213c052SYishai Hadas 	resp.wq_handle = obj->uevent.uobject.id;
2950f213c052SYishai Hadas 	resp.max_sge = wq_init_attr.max_sge;
2951f213c052SYishai Hadas 	resp.max_wr = wq_init_attr.max_wr;
2952f213c052SYishai Hadas 	resp.wqn = wq->wq_num;
295329a29d18SJason Gunthorpe 	resp.response_length = uverbs_response_length(attrs, sizeof(resp));
295416e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
2955f213c052SYishai Hadas 
2956f213c052SYishai Hadas err_put_cq:
29575bd48c18SJason Gunthorpe 	rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
29585bd48c18SJason Gunthorpe 				UVERBS_LOOKUP_READ);
2959f213c052SYishai Hadas err_put_pd:
2960fd3c7904SMatan Barak 	uobj_put_obj_read(pd);
2961f213c052SYishai Hadas err_uobj:
2962a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(&obj->uevent.uobject, attrs);
2963f213c052SYishai Hadas 
2964f213c052SYishai Hadas 	return err;
2965f213c052SYishai Hadas }
2966f213c052SYishai Hadas 
ib_uverbs_ex_destroy_wq(struct uverbs_attr_bundle * attrs)2967974d6b4bSJason Gunthorpe static int ib_uverbs_ex_destroy_wq(struct uverbs_attr_bundle *attrs)
2968f213c052SYishai Hadas {
296929a29d18SJason Gunthorpe 	struct ib_uverbs_ex_destroy_wq	cmd;
2970f213c052SYishai Hadas 	struct ib_uverbs_ex_destroy_wq_resp	resp = {};
2971f213c052SYishai Hadas 	struct ib_uobject		*uobj;
2972f213c052SYishai Hadas 	struct ib_uwq_object		*obj;
2973f213c052SYishai Hadas 	int				ret;
2974f213c052SYishai Hadas 
297529a29d18SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
2976f213c052SYishai Hadas 	if (ret)
2977f213c052SYishai Hadas 		return ret;
2978f213c052SYishai Hadas 
2979f213c052SYishai Hadas 	if (cmd.comp_mask)
2980f213c052SYishai Hadas 		return -EOPNOTSUPP;
2981f213c052SYishai Hadas 
298229a29d18SJason Gunthorpe 	resp.response_length = uverbs_response_length(attrs, sizeof(resp));
29838313c10fSJason Gunthorpe 	uobj = uobj_get_destroy(UVERBS_OBJECT_WQ, cmd.wq_handle, attrs);
2984fd3c7904SMatan Barak 	if (IS_ERR(uobj))
2985fd3c7904SMatan Barak 		return PTR_ERR(uobj);
2986f213c052SYishai Hadas 
2987f213c052SYishai Hadas 	obj = container_of(uobj, struct ib_uwq_object, uevent.uobject);
2988f213c052SYishai Hadas 	resp.events_reported = obj->uevent.events_reported;
298932ed5c00SJason Gunthorpe 
299032ed5c00SJason Gunthorpe 	uobj_put_destroy(uobj);
2991f213c052SYishai Hadas 
29929a073857SJason Gunthorpe 	return uverbs_response(attrs, &resp, sizeof(resp));
2993f213c052SYishai Hadas }
2994f213c052SYishai Hadas 
ib_uverbs_ex_modify_wq(struct uverbs_attr_bundle * attrs)2995974d6b4bSJason Gunthorpe static int ib_uverbs_ex_modify_wq(struct uverbs_attr_bundle *attrs)
2996f213c052SYishai Hadas {
299729a29d18SJason Gunthorpe 	struct ib_uverbs_ex_modify_wq cmd;
2998f213c052SYishai Hadas 	struct ib_wq *wq;
2999f213c052SYishai Hadas 	struct ib_wq_attr wq_attr = {};
3000f213c052SYishai Hadas 	int ret;
3001f213c052SYishai Hadas 
300229a29d18SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
3003f213c052SYishai Hadas 	if (ret)
3004f213c052SYishai Hadas 		return ret;
3005f213c052SYishai Hadas 
3006f213c052SYishai Hadas 	if (!cmd.attr_mask)
3007f213c052SYishai Hadas 		return -EINVAL;
3008f213c052SYishai Hadas 
3009af1cb95dSNoa Osherovich 	if (cmd.attr_mask > (IB_WQ_STATE | IB_WQ_CUR_STATE | IB_WQ_FLAGS))
3010f213c052SYishai Hadas 		return -EINVAL;
3011f213c052SYishai Hadas 
30128313c10fSJason Gunthorpe 	wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ, cmd.wq_handle, attrs);
3013f213c052SYishai Hadas 	if (!wq)
3014f213c052SYishai Hadas 		return -EINVAL;
3015f213c052SYishai Hadas 
3016af1cb95dSNoa Osherovich 	if (cmd.attr_mask & IB_WQ_FLAGS) {
3017af1cb95dSNoa Osherovich 		wq_attr.flags = cmd.flags;
3018af1cb95dSNoa Osherovich 		wq_attr.flags_mask = cmd.flags_mask;
3019af1cb95dSNoa Osherovich 	}
3020f9744288SLeon Romanovsky 
3021f9744288SLeon Romanovsky 	if (cmd.attr_mask & IB_WQ_CUR_STATE) {
3022f9744288SLeon Romanovsky 		if (cmd.curr_wq_state > IB_WQS_ERR)
3023f9744288SLeon Romanovsky 			return -EINVAL;
3024f9744288SLeon Romanovsky 
3025f9744288SLeon Romanovsky 		wq_attr.curr_wq_state = cmd.curr_wq_state;
3026f9744288SLeon Romanovsky 	} else {
3027f9744288SLeon Romanovsky 		wq_attr.curr_wq_state = wq->state;
3028f9744288SLeon Romanovsky 	}
3029f9744288SLeon Romanovsky 
3030f9744288SLeon Romanovsky 	if (cmd.attr_mask & IB_WQ_STATE) {
3031f9744288SLeon Romanovsky 		if (cmd.wq_state > IB_WQS_ERR)
3032f9744288SLeon Romanovsky 			return -EINVAL;
3033f9744288SLeon Romanovsky 
3034f9744288SLeon Romanovsky 		wq_attr.wq_state = cmd.wq_state;
3035f9744288SLeon Romanovsky 	} else {
3036f9744288SLeon Romanovsky 		wq_attr.wq_state = wq_attr.curr_wq_state;
3037f9744288SLeon Romanovsky 	}
3038f9744288SLeon Romanovsky 
30393023a1e9SKamal Heib 	ret = wq->device->ops.modify_wq(wq, &wq_attr, cmd.attr_mask,
3040ef87df2cSJason Gunthorpe 					&attrs->driver_udata);
3041e04dd131SJason Gunthorpe 	rdma_lookup_put_uobject(&wq->uobject->uevent.uobject,
3042e04dd131SJason Gunthorpe 				UVERBS_LOOKUP_READ);
3043f213c052SYishai Hadas 	return ret;
3044f213c052SYishai Hadas }
3045f213c052SYishai Hadas 
ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle * attrs)3046974d6b4bSJason Gunthorpe static int ib_uverbs_ex_create_rwq_ind_table(struct uverbs_attr_bundle *attrs)
3047de019a94SYishai Hadas {
3048335708c7SJason Gunthorpe 	struct ib_uverbs_ex_create_rwq_ind_table cmd;
3049de019a94SYishai Hadas 	struct ib_uverbs_ex_create_rwq_ind_table_resp  resp = {};
3050de019a94SYishai Hadas 	struct ib_uobject *uobj;
3051335708c7SJason Gunthorpe 	int err;
3052de019a94SYishai Hadas 	struct ib_rwq_ind_table_init_attr init_attr = {};
3053de019a94SYishai Hadas 	struct ib_rwq_ind_table *rwq_ind_tbl;
3054de019a94SYishai Hadas 	struct ib_wq **wqs = NULL;
3055de019a94SYishai Hadas 	u32 *wqs_handles = NULL;
3056de019a94SYishai Hadas 	struct ib_wq	*wq = NULL;
305716e51f78SLeon Romanovsky 	int i, num_read_wqs;
3058de019a94SYishai Hadas 	u32 num_wq_handles;
3059335708c7SJason Gunthorpe 	struct uverbs_req_iter iter;
3060bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
3061de019a94SYishai Hadas 
3062335708c7SJason Gunthorpe 	err = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
3063de019a94SYishai Hadas 	if (err)
3064de019a94SYishai Hadas 		return err;
3065de019a94SYishai Hadas 
3066de019a94SYishai Hadas 	if (cmd.comp_mask)
3067de019a94SYishai Hadas 		return -EOPNOTSUPP;
3068de019a94SYishai Hadas 
3069de019a94SYishai Hadas 	if (cmd.log_ind_tbl_size > IB_USER_VERBS_MAX_LOG_IND_TBL_SIZE)
3070de019a94SYishai Hadas 		return -EINVAL;
3071de019a94SYishai Hadas 
3072de019a94SYishai Hadas 	num_wq_handles = 1 << cmd.log_ind_tbl_size;
3073de019a94SYishai Hadas 	wqs_handles = kcalloc(num_wq_handles, sizeof(*wqs_handles),
3074de019a94SYishai Hadas 			      GFP_KERNEL);
3075de019a94SYishai Hadas 	if (!wqs_handles)
3076de019a94SYishai Hadas 		return -ENOMEM;
3077de019a94SYishai Hadas 
3078335708c7SJason Gunthorpe 	err = uverbs_request_next(&iter, wqs_handles,
3079de019a94SYishai Hadas 				  num_wq_handles * sizeof(__u32));
3080de019a94SYishai Hadas 	if (err)
3081de019a94SYishai Hadas 		goto err_free;
3082de019a94SYishai Hadas 
3083335708c7SJason Gunthorpe 	err = uverbs_request_finish(&iter);
3084335708c7SJason Gunthorpe 	if (err)
3085335708c7SJason Gunthorpe 		goto err_free;
3086335708c7SJason Gunthorpe 
3087de019a94SYishai Hadas 	wqs = kcalloc(num_wq_handles, sizeof(*wqs), GFP_KERNEL);
3088de019a94SYishai Hadas 	if (!wqs) {
3089de019a94SYishai Hadas 		err = -ENOMEM;
3090de019a94SYishai Hadas 		goto  err_free;
3091de019a94SYishai Hadas 	}
3092de019a94SYishai Hadas 
3093de019a94SYishai Hadas 	for (num_read_wqs = 0; num_read_wqs < num_wq_handles;
3094de019a94SYishai Hadas 			num_read_wqs++) {
30952cc1e3b8SJason Gunthorpe 		wq = uobj_get_obj_read(wq, UVERBS_OBJECT_WQ,
30968313c10fSJason Gunthorpe 				       wqs_handles[num_read_wqs], attrs);
3097de019a94SYishai Hadas 		if (!wq) {
3098de019a94SYishai Hadas 			err = -EINVAL;
3099de019a94SYishai Hadas 			goto put_wqs;
3100de019a94SYishai Hadas 		}
3101de019a94SYishai Hadas 
3102de019a94SYishai Hadas 		wqs[num_read_wqs] = wq;
310316e51f78SLeon Romanovsky 		atomic_inc(&wqs[num_read_wqs]->usecnt);
3104de019a94SYishai Hadas 	}
3105de019a94SYishai Hadas 
31068313c10fSJason Gunthorpe 	uobj = uobj_alloc(UVERBS_OBJECT_RWQ_IND_TBL, attrs, &ib_dev);
3107fd3c7904SMatan Barak 	if (IS_ERR(uobj)) {
3108fd3c7904SMatan Barak 		err = PTR_ERR(uobj);
3109de019a94SYishai Hadas 		goto put_wqs;
3110de019a94SYishai Hadas 	}
3111de019a94SYishai Hadas 
3112c0a6b5ecSLeon Romanovsky 	rwq_ind_tbl = rdma_zalloc_drv_obj(ib_dev, ib_rwq_ind_table);
3113c0a6b5ecSLeon Romanovsky 	if (!rwq_ind_tbl) {
3114c0a6b5ecSLeon Romanovsky 		err = -ENOMEM;
3115de019a94SYishai Hadas 		goto err_uobj;
3116de019a94SYishai Hadas 	}
3117de019a94SYishai Hadas 
3118c0a6b5ecSLeon Romanovsky 	init_attr.log_ind_tbl_size = cmd.log_ind_tbl_size;
3119c0a6b5ecSLeon Romanovsky 	init_attr.ind_tbl = wqs;
3120c0a6b5ecSLeon Romanovsky 
3121de019a94SYishai Hadas 	rwq_ind_tbl->ind_tbl = wqs;
3122de019a94SYishai Hadas 	rwq_ind_tbl->log_ind_tbl_size = init_attr.log_ind_tbl_size;
3123de019a94SYishai Hadas 	rwq_ind_tbl->uobject = uobj;
3124de019a94SYishai Hadas 	uobj->object = rwq_ind_tbl;
3125de019a94SYishai Hadas 	rwq_ind_tbl->device = ib_dev;
3126de019a94SYishai Hadas 	atomic_set(&rwq_ind_tbl->usecnt, 0);
3127de019a94SYishai Hadas 
3128c0a6b5ecSLeon Romanovsky 	err = ib_dev->ops.create_rwq_ind_table(rwq_ind_tbl, &init_attr,
3129c0a6b5ecSLeon Romanovsky 					       &attrs->driver_udata);
3130c0a6b5ecSLeon Romanovsky 	if (err)
3131c0a6b5ecSLeon Romanovsky 		goto err_create;
3132c0a6b5ecSLeon Romanovsky 
3133de019a94SYishai Hadas 	for (i = 0; i < num_wq_handles; i++)
313416e51f78SLeon Romanovsky 		rdma_lookup_put_uobject(&wqs[i]->uobject->uevent.uobject,
313516e51f78SLeon Romanovsky 					UVERBS_LOOKUP_READ);
313616e51f78SLeon Romanovsky 	kfree(wqs_handles);
313716e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(uobj, attrs);
3138de019a94SYishai Hadas 
3139de019a94SYishai Hadas 	resp.ind_tbl_handle = uobj->id;
3140de019a94SYishai Hadas 	resp.ind_tbl_num = rwq_ind_tbl->ind_tbl_num;
314129a29d18SJason Gunthorpe 	resp.response_length = uverbs_response_length(attrs, sizeof(resp));
314216e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
3143de019a94SYishai Hadas 
3144c0a6b5ecSLeon Romanovsky err_create:
3145c0a6b5ecSLeon Romanovsky 	kfree(rwq_ind_tbl);
3146de019a94SYishai Hadas err_uobj:
3147a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(uobj, attrs);
3148de019a94SYishai Hadas put_wqs:
314916e51f78SLeon Romanovsky 	for (i = 0; i < num_read_wqs; i++) {
315016e51f78SLeon Romanovsky 		rdma_lookup_put_uobject(&wqs[i]->uobject->uevent.uobject,
3151e04dd131SJason Gunthorpe 					UVERBS_LOOKUP_READ);
315216e51f78SLeon Romanovsky 		atomic_dec(&wqs[i]->usecnt);
315316e51f78SLeon Romanovsky 	}
3154de019a94SYishai Hadas err_free:
3155de019a94SYishai Hadas 	kfree(wqs_handles);
3156de019a94SYishai Hadas 	kfree(wqs);
3157de019a94SYishai Hadas 	return err;
3158de019a94SYishai Hadas }
3159de019a94SYishai Hadas 
ib_uverbs_ex_destroy_rwq_ind_table(struct uverbs_attr_bundle * attrs)3160974d6b4bSJason Gunthorpe static int ib_uverbs_ex_destroy_rwq_ind_table(struct uverbs_attr_bundle *attrs)
3161de019a94SYishai Hadas {
316229a29d18SJason Gunthorpe 	struct ib_uverbs_ex_destroy_rwq_ind_table cmd;
3163de019a94SYishai Hadas 	int ret;
3164de019a94SYishai Hadas 
316529a29d18SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
3166de019a94SYishai Hadas 	if (ret)
3167de019a94SYishai Hadas 		return ret;
3168de019a94SYishai Hadas 
3169de019a94SYishai Hadas 	if (cmd.comp_mask)
3170de019a94SYishai Hadas 		return -EOPNOTSUPP;
3171de019a94SYishai Hadas 
3172c33e73afSJason Gunthorpe 	return uobj_perform_destroy(UVERBS_OBJECT_RWQ_IND_TBL,
31737106a976SJason Gunthorpe 				    cmd.ind_tbl_handle, attrs);
3174de019a94SYishai Hadas }
3175de019a94SYishai Hadas 
ib_uverbs_ex_create_flow(struct uverbs_attr_bundle * attrs)3176974d6b4bSJason Gunthorpe static int ib_uverbs_ex_create_flow(struct uverbs_attr_bundle *attrs)
3177436f2ad0SHadar Hen Zion {
3178436f2ad0SHadar Hen Zion 	struct ib_uverbs_create_flow	  cmd;
317916e51f78SLeon Romanovsky 	struct ib_uverbs_create_flow_resp resp = {};
3180436f2ad0SHadar Hen Zion 	struct ib_uobject		  *uobj;
3181436f2ad0SHadar Hen Zion 	struct ib_flow			  *flow_id;
3182d82693daSYann Droneaud 	struct ib_uverbs_flow_attr	  *kern_flow_attr;
3183436f2ad0SHadar Hen Zion 	struct ib_flow_attr		  *flow_attr;
3184436f2ad0SHadar Hen Zion 	struct ib_qp			  *qp;
31859b828441SMatan Barak 	struct ib_uflow_resources	  *uflow_res;
31864fae7f17SLeon Romanovsky 	struct ib_uverbs_flow_spec_hdr	  *kern_spec;
3187335708c7SJason Gunthorpe 	struct uverbs_req_iter iter;
3188335708c7SJason Gunthorpe 	int err;
3189436f2ad0SHadar Hen Zion 	void *ib_spec;
3190436f2ad0SHadar Hen Zion 	int i;
3191bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
3192436f2ad0SHadar Hen Zion 
3193335708c7SJason Gunthorpe 	err = uverbs_request_start(attrs, &iter, &cmd, sizeof(cmd));
3194f21519b2SYann Droneaud 	if (err)
3195f21519b2SYann Droneaud 		return err;
3196f21519b2SYann Droneaud 
319722878dbcSMatan Barak 	if (cmd.comp_mask)
319822878dbcSMatan Barak 		return -EINVAL;
319922878dbcSMatan Barak 
3200e3b6d8cfSChristoph Lameter 	if (!capable(CAP_NET_RAW))
3201436f2ad0SHadar Hen Zion 		return -EPERM;
3202436f2ad0SHadar Hen Zion 
3203a3100a78SMarina Varshaver 	if (cmd.flow_attr.flags >= IB_FLOW_ATTR_FLAGS_RESERVED)
3204a3100a78SMarina Varshaver 		return -EINVAL;
3205a3100a78SMarina Varshaver 
3206a3100a78SMarina Varshaver 	if ((cmd.flow_attr.flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP) &&
3207a3100a78SMarina Varshaver 	    ((cmd.flow_attr.type == IB_FLOW_ATTR_ALL_DEFAULT) ||
3208a3100a78SMarina Varshaver 	     (cmd.flow_attr.type == IB_FLOW_ATTR_MC_DEFAULT)))
3209a3100a78SMarina Varshaver 		return -EINVAL;
3210a3100a78SMarina Varshaver 
3211f8848274SMatan Barak 	if (cmd.flow_attr.num_of_specs > IB_FLOW_SPEC_SUPPORT_LAYERS)
321222878dbcSMatan Barak 		return -EINVAL;
321322878dbcSMatan Barak 
3214335708c7SJason Gunthorpe 	if (cmd.flow_attr.size >
3215b68c9560SYann Droneaud 	    (cmd.flow_attr.num_of_specs * sizeof(struct ib_uverbs_flow_spec)))
321622878dbcSMatan Barak 		return -EINVAL;
321722878dbcSMatan Barak 
3218c780d82aSYann Droneaud 	if (cmd.flow_attr.reserved[0] ||
3219c780d82aSYann Droneaud 	    cmd.flow_attr.reserved[1])
3220c780d82aSYann Droneaud 		return -EINVAL;
3221c780d82aSYann Droneaud 
3222436f2ad0SHadar Hen Zion 	if (cmd.flow_attr.num_of_specs) {
3223f8848274SMatan Barak 		kern_flow_attr = kmalloc(sizeof(*kern_flow_attr) + cmd.flow_attr.size,
3224f8848274SMatan Barak 					 GFP_KERNEL);
3225436f2ad0SHadar Hen Zion 		if (!kern_flow_attr)
3226436f2ad0SHadar Hen Zion 			return -ENOMEM;
3227436f2ad0SHadar Hen Zion 
32284fae7f17SLeon Romanovsky 		*kern_flow_attr = cmd.flow_attr;
3229335708c7SJason Gunthorpe 		err = uverbs_request_next(&iter, &kern_flow_attr->flow_specs,
3230f21519b2SYann Droneaud 					  cmd.flow_attr.size);
3231f21519b2SYann Droneaud 		if (err)
3232436f2ad0SHadar Hen Zion 			goto err_free_attr;
3233436f2ad0SHadar Hen Zion 	} else {
3234436f2ad0SHadar Hen Zion 		kern_flow_attr = &cmd.flow_attr;
3235436f2ad0SHadar Hen Zion 	}
3236436f2ad0SHadar Hen Zion 
3237335708c7SJason Gunthorpe 	err = uverbs_request_finish(&iter);
3238335708c7SJason Gunthorpe 	if (err)
3239335708c7SJason Gunthorpe 		goto err_free_attr;
3240335708c7SJason Gunthorpe 
32418313c10fSJason Gunthorpe 	uobj = uobj_alloc(UVERBS_OBJECT_FLOW, attrs, &ib_dev);
3242fd3c7904SMatan Barak 	if (IS_ERR(uobj)) {
3243fd3c7904SMatan Barak 		err = PTR_ERR(uobj);
3244436f2ad0SHadar Hen Zion 		goto err_free_attr;
3245436f2ad0SHadar Hen Zion 	}
3246436f2ad0SHadar Hen Zion 
32472adcb4c5SMaor Gottlieb 	if (!rdma_is_port_valid(uobj->context->device, cmd.flow_attr.port)) {
32482adcb4c5SMaor Gottlieb 		err = -EINVAL;
32492adcb4c5SMaor Gottlieb 		goto err_uobj;
32502adcb4c5SMaor Gottlieb 	}
32512adcb4c5SMaor Gottlieb 
32528313c10fSJason Gunthorpe 	qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs);
3253436f2ad0SHadar Hen Zion 	if (!qp) {
3254436f2ad0SHadar Hen Zion 		err = -EINVAL;
3255436f2ad0SHadar Hen Zion 		goto err_uobj;
3256436f2ad0SHadar Hen Zion 	}
3257436f2ad0SHadar Hen Zion 
3258940efcc8SLeon Romanovsky 	if (qp->qp_type != IB_QPT_UD && qp->qp_type != IB_QPT_RAW_PACKET) {
3259940efcc8SLeon Romanovsky 		err = -EINVAL;
3260940efcc8SLeon Romanovsky 		goto err_put;
3261940efcc8SLeon Romanovsky 	}
3262940efcc8SLeon Romanovsky 
32637654cb1bSMatthew Wilcox 	flow_attr = kzalloc(struct_size(flow_attr, flows,
32647654cb1bSMatthew Wilcox 				cmd.flow_attr.num_of_specs), GFP_KERNEL);
3265436f2ad0SHadar Hen Zion 	if (!flow_attr) {
3266436f2ad0SHadar Hen Zion 		err = -ENOMEM;
3267436f2ad0SHadar Hen Zion 		goto err_put;
3268436f2ad0SHadar Hen Zion 	}
32699b828441SMatan Barak 	uflow_res = flow_resources_alloc(cmd.flow_attr.num_of_specs);
32709b828441SMatan Barak 	if (!uflow_res) {
32719b828441SMatan Barak 		err = -ENOMEM;
32729b828441SMatan Barak 		goto err_free_flow_attr;
32739b828441SMatan Barak 	}
3274436f2ad0SHadar Hen Zion 
3275436f2ad0SHadar Hen Zion 	flow_attr->type = kern_flow_attr->type;
3276436f2ad0SHadar Hen Zion 	flow_attr->priority = kern_flow_attr->priority;
3277436f2ad0SHadar Hen Zion 	flow_attr->num_of_specs = kern_flow_attr->num_of_specs;
3278436f2ad0SHadar Hen Zion 	flow_attr->port = kern_flow_attr->port;
3279436f2ad0SHadar Hen Zion 	flow_attr->flags = kern_flow_attr->flags;
3280436f2ad0SHadar Hen Zion 	flow_attr->size = sizeof(*flow_attr);
3281436f2ad0SHadar Hen Zion 
32824fae7f17SLeon Romanovsky 	kern_spec = kern_flow_attr->flow_specs;
3283436f2ad0SHadar Hen Zion 	ib_spec = flow_attr + 1;
3284f8848274SMatan Barak 	for (i = 0; i < flow_attr->num_of_specs &&
3285fe48aecbSLeon Romanovsky 			cmd.flow_attr.size >= sizeof(*kern_spec) &&
32864fae7f17SLeon Romanovsky 			cmd.flow_attr.size >= kern_spec->size;
32874fae7f17SLeon Romanovsky 	     i++) {
32884fae7f17SLeon Romanovsky 		err = kern_spec_to_ib_spec(
32898313c10fSJason Gunthorpe 				attrs, (struct ib_uverbs_flow_spec *)kern_spec,
32904fae7f17SLeon Romanovsky 				ib_spec, uflow_res);
3291436f2ad0SHadar Hen Zion 		if (err)
3292436f2ad0SHadar Hen Zion 			goto err_free;
3293b04f0f03SAriel Levkovich 
3294436f2ad0SHadar Hen Zion 		flow_attr->size +=
3295436f2ad0SHadar Hen Zion 			((union ib_flow_spec *) ib_spec)->size;
32964fae7f17SLeon Romanovsky 		cmd.flow_attr.size -= kern_spec->size;
32974fae7f17SLeon Romanovsky 		kern_spec = ((void *)kern_spec) + kern_spec->size;
3298436f2ad0SHadar Hen Zion 		ib_spec += ((union ib_flow_spec *) ib_spec)->size;
3299436f2ad0SHadar Hen Zion 	}
3300f8848274SMatan Barak 	if (cmd.flow_attr.size || (i != flow_attr->num_of_specs)) {
33013cea7b4aSWenpeng Liang 		pr_warn("create flow failed, flow %d: %u bytes left from uverb cmd\n",
3302f8848274SMatan Barak 			i, cmd.flow_attr.size);
330398a37510SYann Droneaud 		err = -EINVAL;
3304436f2ad0SHadar Hen Zion 		goto err_free;
3305436f2ad0SHadar Hen Zion 	}
330659082a32SMatan Barak 
3307d6673746SLeon Romanovsky 	flow_id = qp->device->ops.create_flow(qp, flow_attr,
3308d6673746SLeon Romanovsky 					      &attrs->driver_udata);
330959082a32SMatan Barak 
3310436f2ad0SHadar Hen Zion 	if (IS_ERR(flow_id)) {
3311436f2ad0SHadar Hen Zion 		err = PTR_ERR(flow_id);
3312fd3c7904SMatan Barak 		goto err_free;
3313436f2ad0SHadar Hen Zion 	}
331486e1d464SMark Bloch 
331586e1d464SMark Bloch 	ib_set_flow(uobj, flow_id, qp, qp->device, uflow_res);
3316436f2ad0SHadar Hen Zion 
3317620d3f81SJason Gunthorpe 	rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
3318620d3f81SJason Gunthorpe 				UVERBS_LOOKUP_READ);
3319436f2ad0SHadar Hen Zion 	kfree(flow_attr);
332016e51f78SLeon Romanovsky 
3321436f2ad0SHadar Hen Zion 	if (cmd.flow_attr.num_of_specs)
3322436f2ad0SHadar Hen Zion 		kfree(kern_flow_attr);
332316e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(uobj, attrs);
332416e51f78SLeon Romanovsky 
332516e51f78SLeon Romanovsky 	resp.flow_handle = uobj->id;
332616e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
332716e51f78SLeon Romanovsky 
3328436f2ad0SHadar Hen Zion err_free:
33299b828441SMatan Barak 	ib_uverbs_flow_resources_free(uflow_res);
33309b828441SMatan Barak err_free_flow_attr:
3331436f2ad0SHadar Hen Zion 	kfree(flow_attr);
3332436f2ad0SHadar Hen Zion err_put:
3333620d3f81SJason Gunthorpe 	rdma_lookup_put_uobject(&qp->uobject->uevent.uobject,
3334620d3f81SJason Gunthorpe 				UVERBS_LOOKUP_READ);
3335436f2ad0SHadar Hen Zion err_uobj:
3336a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(uobj, attrs);
3337436f2ad0SHadar Hen Zion err_free_attr:
3338436f2ad0SHadar Hen Zion 	if (cmd.flow_attr.num_of_specs)
3339436f2ad0SHadar Hen Zion 		kfree(kern_flow_attr);
3340436f2ad0SHadar Hen Zion 	return err;
3341436f2ad0SHadar Hen Zion }
3342436f2ad0SHadar Hen Zion 
ib_uverbs_ex_destroy_flow(struct uverbs_attr_bundle * attrs)3343974d6b4bSJason Gunthorpe static int ib_uverbs_ex_destroy_flow(struct uverbs_attr_bundle *attrs)
3344f21519b2SYann Droneaud {
3345436f2ad0SHadar Hen Zion 	struct ib_uverbs_destroy_flow	cmd;
3346436f2ad0SHadar Hen Zion 	int				ret;
3347436f2ad0SHadar Hen Zion 
334829a29d18SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
3349f21519b2SYann Droneaud 	if (ret)
3350f21519b2SYann Droneaud 		return ret;
3351436f2ad0SHadar Hen Zion 
33522782c2d3SYann Droneaud 	if (cmd.comp_mask)
33532782c2d3SYann Droneaud 		return -EINVAL;
33542782c2d3SYann Droneaud 
33557106a976SJason Gunthorpe 	return uobj_perform_destroy(UVERBS_OBJECT_FLOW, cmd.flow_handle, attrs);
3356436f2ad0SHadar Hen Zion }
3357436f2ad0SHadar Hen Zion 
__uverbs_create_xsrq(struct uverbs_attr_bundle * attrs,struct ib_uverbs_create_xsrq * cmd,struct ib_udata * udata)33588313c10fSJason Gunthorpe static int __uverbs_create_xsrq(struct uverbs_attr_bundle *attrs,
33598541f8deSSean Hefty 				struct ib_uverbs_create_xsrq *cmd,
33608541f8deSSean Hefty 				struct ib_udata *udata)
33618541f8deSSean Hefty {
336216e51f78SLeon Romanovsky 	struct ib_uverbs_create_srq_resp resp = {};
33638541f8deSSean Hefty 	struct ib_usrq_object           *obj;
33648541f8deSSean Hefty 	struct ib_pd                    *pd;
33658541f8deSSean Hefty 	struct ib_srq                   *srq;
33668541f8deSSean Hefty 	struct ib_srq_init_attr          attr;
33678541f8deSSean Hefty 	int ret;
336829f3fe1dSLeon Romanovsky 	struct ib_uobject *xrcd_uobj;
3369bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
33708541f8deSSean Hefty 
33718313c10fSJason Gunthorpe 	obj = (struct ib_usrq_object *)uobj_alloc(UVERBS_OBJECT_SRQ, attrs,
3372bbd51e88SJason Gunthorpe 						  &ib_dev);
3373fd3c7904SMatan Barak 	if (IS_ERR(obj))
3374fd3c7904SMatan Barak 		return PTR_ERR(obj);
33758541f8deSSean Hefty 
337638eb44faSArtemy Kovalyov 	if (cmd->srq_type == IB_SRQT_TM)
337738eb44faSArtemy Kovalyov 		attr.ext.tag_matching.max_num_tags = cmd->max_num_tags;
337838eb44faSArtemy Kovalyov 
33795909ce54SRoland Dreier 	if (cmd->srq_type == IB_SRQT_XRC) {
33801f7ff9d5SMatan Barak 		xrcd_uobj = uobj_get_read(UVERBS_OBJECT_XRCD, cmd->xrcd_handle,
33818313c10fSJason Gunthorpe 					  attrs);
3382fd3c7904SMatan Barak 		if (IS_ERR(xrcd_uobj)) {
33838541f8deSSean Hefty 			ret = -EINVAL;
33848541f8deSSean Hefty 			goto err;
33858541f8deSSean Hefty 		}
33868541f8deSSean Hefty 
3387fd3c7904SMatan Barak 		attr.ext.xrc.xrcd = (struct ib_xrcd *)xrcd_uobj->object;
3388fd3c7904SMatan Barak 		if (!attr.ext.xrc.xrcd) {
3389fd3c7904SMatan Barak 			ret = -EINVAL;
3390fd3c7904SMatan Barak 			goto err_put_xrcd;
3391fd3c7904SMatan Barak 		}
3392fd3c7904SMatan Barak 
33935909ce54SRoland Dreier 		obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object, uobject);
33945909ce54SRoland Dreier 		atomic_inc(&obj->uxrcd->refcnt);
33951a56ff6dSArtemy Kovalyov 	}
33965909ce54SRoland Dreier 
33971a56ff6dSArtemy Kovalyov 	if (ib_srq_has_cq(cmd->srq_type)) {
33982cc1e3b8SJason Gunthorpe 		attr.ext.cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ,
33998313c10fSJason Gunthorpe 						cmd->cq_handle, attrs);
34001a56ff6dSArtemy Kovalyov 		if (!attr.ext.cq) {
34018541f8deSSean Hefty 			ret = -EINVAL;
34025909ce54SRoland Dreier 			goto err_put_xrcd;
34035909ce54SRoland Dreier 		}
34048541f8deSSean Hefty 	}
34058541f8deSSean Hefty 
34068313c10fSJason Gunthorpe 	pd = uobj_get_obj_read(pd, UVERBS_OBJECT_PD, cmd->pd_handle, attrs);
34075909ce54SRoland Dreier 	if (!pd) {
34088541f8deSSean Hefty 		ret = -EINVAL;
34098541f8deSSean Hefty 		goto err_put_cq;
34108541f8deSSean Hefty 	}
34118541f8deSSean Hefty 
34128541f8deSSean Hefty 	attr.event_handler  = ib_uverbs_srq_event_handler;
34138541f8deSSean Hefty 	attr.srq_type       = cmd->srq_type;
34148541f8deSSean Hefty 	attr.attr.max_wr    = cmd->max_wr;
34158541f8deSSean Hefty 	attr.attr.max_sge   = cmd->max_sge;
34168541f8deSSean Hefty 	attr.attr.srq_limit = cmd->srq_limit;
34178541f8deSSean Hefty 
34188541f8deSSean Hefty 	INIT_LIST_HEAD(&obj->uevent.event_list);
3419b0810b03SJason Gunthorpe 	obj->uevent.uobject.user_handle = cmd->user_handle;
34208541f8deSSean Hefty 
3421b0810b03SJason Gunthorpe 	srq = ib_create_srq_user(pd, &attr, obj, udata);
3422b0810b03SJason Gunthorpe 	if (IS_ERR(srq)) {
3423b0810b03SJason Gunthorpe 		ret = PTR_ERR(srq);
3424b0810b03SJason Gunthorpe 		goto err_put_pd;
34258541f8deSSean Hefty 	}
34268541f8deSSean Hefty 
34278541f8deSSean Hefty 	obj->uevent.uobject.object = srq;
342898a8890fSYishai Hadas 	obj->uevent.uobject.user_handle = cmd->user_handle;
342998a8890fSYishai Hadas 	obj->uevent.event_file = READ_ONCE(attrs->ufile->default_async_file);
343098a8890fSYishai Hadas 	if (obj->uevent.event_file)
343198a8890fSYishai Hadas 		uverbs_uobject_get(&obj->uevent.event_file->uobj);
34328541f8deSSean Hefty 
34338541f8deSSean Hefty 	if (cmd->srq_type == IB_SRQT_XRC)
34348541f8deSSean Hefty 		resp.srqn = srq->ext.xrc.srq_num;
34358541f8deSSean Hefty 
34361a56ff6dSArtemy Kovalyov 	if (cmd->srq_type == IB_SRQT_XRC)
3437fd3c7904SMatan Barak 		uobj_put_read(xrcd_uobj);
34381a56ff6dSArtemy Kovalyov 
34391a56ff6dSArtemy Kovalyov 	if (ib_srq_has_cq(cmd->srq_type))
34405bd48c18SJason Gunthorpe 		rdma_lookup_put_uobject(&attr.ext.cq->uobject->uevent.uobject,
34415bd48c18SJason Gunthorpe 					UVERBS_LOOKUP_READ);
34421a56ff6dSArtemy Kovalyov 
3443fd3c7904SMatan Barak 	uobj_put_obj_read(pd);
344416e51f78SLeon Romanovsky 	uobj_finalize_uobj_create(&obj->uevent.uobject, attrs);
34458541f8deSSean Hefty 
344616e51f78SLeon Romanovsky 	resp.srq_handle = obj->uevent.uobject.id;
344716e51f78SLeon Romanovsky 	resp.max_wr = attr.attr.max_wr;
344816e51f78SLeon Romanovsky 	resp.max_sge = attr.attr.max_sge;
344916e51f78SLeon Romanovsky 	return uverbs_response(attrs, &resp, sizeof(resp));
345016e51f78SLeon Romanovsky 
3451b0810b03SJason Gunthorpe err_put_pd:
3452fd3c7904SMatan Barak 	uobj_put_obj_read(pd);
34538541f8deSSean Hefty err_put_cq:
34541a56ff6dSArtemy Kovalyov 	if (ib_srq_has_cq(cmd->srq_type))
34555bd48c18SJason Gunthorpe 		rdma_lookup_put_uobject(&attr.ext.cq->uobject->uevent.uobject,
34565bd48c18SJason Gunthorpe 					UVERBS_LOOKUP_READ);
34578541f8deSSean Hefty 
34585909ce54SRoland Dreier err_put_xrcd:
34595909ce54SRoland Dreier 	if (cmd->srq_type == IB_SRQT_XRC) {
34605909ce54SRoland Dreier 		atomic_dec(&obj->uxrcd->refcnt);
3461fd3c7904SMatan Barak 		uobj_put_read(xrcd_uobj);
34625909ce54SRoland Dreier 	}
34638541f8deSSean Hefty 
34648541f8deSSean Hefty err:
3465a6a3797dSShamir Rabinovitch 	uobj_alloc_abort(&obj->uevent.uobject, attrs);
34668541f8deSSean Hefty 	return ret;
34678541f8deSSean Hefty }
34688541f8deSSean Hefty 
ib_uverbs_create_srq(struct uverbs_attr_bundle * attrs)3469974d6b4bSJason Gunthorpe static int ib_uverbs_create_srq(struct uverbs_attr_bundle *attrs)
3470f520ba5aSRoland Dreier {
3471f520ba5aSRoland Dreier 	struct ib_uverbs_create_srq      cmd;
34728541f8deSSean Hefty 	struct ib_uverbs_create_xsrq     xcmd;
34733c2c2094SJason Gunthorpe 	int ret;
34748541f8deSSean Hefty 
34753c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
34763c2c2094SJason Gunthorpe 	if (ret)
34773c2c2094SJason Gunthorpe 		return ret;
34788541f8deSSean Hefty 
347938eb44faSArtemy Kovalyov 	memset(&xcmd, 0, sizeof(xcmd));
34808541f8deSSean Hefty 	xcmd.response	 = cmd.response;
34818541f8deSSean Hefty 	xcmd.user_handle = cmd.user_handle;
34828541f8deSSean Hefty 	xcmd.srq_type	 = IB_SRQT_BASIC;
34838541f8deSSean Hefty 	xcmd.pd_handle	 = cmd.pd_handle;
34848541f8deSSean Hefty 	xcmd.max_wr	 = cmd.max_wr;
34858541f8deSSean Hefty 	xcmd.max_sge	 = cmd.max_sge;
34868541f8deSSean Hefty 	xcmd.srq_limit	 = cmd.srq_limit;
34878541f8deSSean Hefty 
3488ef87df2cSJason Gunthorpe 	return __uverbs_create_xsrq(attrs, &xcmd, &attrs->driver_udata);
34898541f8deSSean Hefty }
34908541f8deSSean Hefty 
ib_uverbs_create_xsrq(struct uverbs_attr_bundle * attrs)3491974d6b4bSJason Gunthorpe static int ib_uverbs_create_xsrq(struct uverbs_attr_bundle *attrs)
34928541f8deSSean Hefty {
34938541f8deSSean Hefty 	struct ib_uverbs_create_xsrq     cmd;
34943c2c2094SJason Gunthorpe 	int ret;
3495f520ba5aSRoland Dreier 
34963c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
34973c2c2094SJason Gunthorpe 	if (ret)
34983c2c2094SJason Gunthorpe 		return ret;
3499f520ba5aSRoland Dreier 
3500ef87df2cSJason Gunthorpe 	return __uverbs_create_xsrq(attrs, &cmd, &attrs->driver_udata);
3501f520ba5aSRoland Dreier }
3502f520ba5aSRoland Dreier 
ib_uverbs_modify_srq(struct uverbs_attr_bundle * attrs)3503974d6b4bSJason Gunthorpe static int ib_uverbs_modify_srq(struct uverbs_attr_bundle *attrs)
3504f520ba5aSRoland Dreier {
3505f520ba5aSRoland Dreier 	struct ib_uverbs_modify_srq cmd;
3506f520ba5aSRoland Dreier 	struct ib_srq              *srq;
3507f520ba5aSRoland Dreier 	struct ib_srq_attr          attr;
3508f520ba5aSRoland Dreier 	int                         ret;
3509f520ba5aSRoland Dreier 
35103c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
35113c2c2094SJason Gunthorpe 	if (ret)
35123c2c2094SJason Gunthorpe 		return ret;
3513f520ba5aSRoland Dreier 
35148313c10fSJason Gunthorpe 	srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
35159ead190bSRoland Dreier 	if (!srq)
35169ead190bSRoland Dreier 		return -EINVAL;
3517f520ba5aSRoland Dreier 
3518f520ba5aSRoland Dreier 	attr.max_wr    = cmd.max_wr;
3519f520ba5aSRoland Dreier 	attr.srq_limit = cmd.srq_limit;
3520f520ba5aSRoland Dreier 
35213023a1e9SKamal Heib 	ret = srq->device->ops.modify_srq(srq, &attr, cmd.attr_mask,
3522ef87df2cSJason Gunthorpe 					  &attrs->driver_udata);
3523f520ba5aSRoland Dreier 
35249fbe334cSJason Gunthorpe 	rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
35259fbe334cSJason Gunthorpe 				UVERBS_LOOKUP_READ);
3526f520ba5aSRoland Dreier 
35277106a976SJason Gunthorpe 	return ret;
3528f520ba5aSRoland Dreier }
3529f520ba5aSRoland Dreier 
ib_uverbs_query_srq(struct uverbs_attr_bundle * attrs)3530974d6b4bSJason Gunthorpe static int ib_uverbs_query_srq(struct uverbs_attr_bundle *attrs)
35318bdb0e86SDotan Barak {
35328bdb0e86SDotan Barak 	struct ib_uverbs_query_srq      cmd;
35338bdb0e86SDotan Barak 	struct ib_uverbs_query_srq_resp resp;
35348bdb0e86SDotan Barak 	struct ib_srq_attr              attr;
35358bdb0e86SDotan Barak 	struct ib_srq                   *srq;
35368bdb0e86SDotan Barak 	int                             ret;
35378bdb0e86SDotan Barak 
35383c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
35393c2c2094SJason Gunthorpe 	if (ret)
35403c2c2094SJason Gunthorpe 		return ret;
35418bdb0e86SDotan Barak 
35428313c10fSJason Gunthorpe 	srq = uobj_get_obj_read(srq, UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
35439ead190bSRoland Dreier 	if (!srq)
35449ead190bSRoland Dreier 		return -EINVAL;
35458bdb0e86SDotan Barak 
35468bdb0e86SDotan Barak 	ret = ib_query_srq(srq, &attr);
35478bdb0e86SDotan Barak 
35489fbe334cSJason Gunthorpe 	rdma_lookup_put_uobject(&srq->uobject->uevent.uobject,
35499fbe334cSJason Gunthorpe 				UVERBS_LOOKUP_READ);
35508bdb0e86SDotan Barak 
35518bdb0e86SDotan Barak 	if (ret)
35529ead190bSRoland Dreier 		return ret;
35538bdb0e86SDotan Barak 
35548bdb0e86SDotan Barak 	memset(&resp, 0, sizeof resp);
35558bdb0e86SDotan Barak 
35568bdb0e86SDotan Barak 	resp.max_wr    = attr.max_wr;
35578bdb0e86SDotan Barak 	resp.max_sge   = attr.max_sge;
35588bdb0e86SDotan Barak 	resp.srq_limit = attr.srq_limit;
35598bdb0e86SDotan Barak 
35609a073857SJason Gunthorpe 	return uverbs_response(attrs, &resp, sizeof(resp));
35618bdb0e86SDotan Barak }
35628bdb0e86SDotan Barak 
ib_uverbs_destroy_srq(struct uverbs_attr_bundle * attrs)3563974d6b4bSJason Gunthorpe static int ib_uverbs_destroy_srq(struct uverbs_attr_bundle *attrs)
3564f520ba5aSRoland Dreier {
3565f520ba5aSRoland Dreier 	struct ib_uverbs_destroy_srq      cmd;
356663aaf647SRoland Dreier 	struct ib_uverbs_destroy_srq_resp resp;
35679ead190bSRoland Dreier 	struct ib_uobject		 *uobj;
35689ead190bSRoland Dreier 	struct ib_uevent_object        	 *obj;
35693c2c2094SJason Gunthorpe 	int ret;
3570f520ba5aSRoland Dreier 
35713c2c2094SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
35723c2c2094SJason Gunthorpe 	if (ret)
35733c2c2094SJason Gunthorpe 		return ret;
3574f520ba5aSRoland Dreier 
35758313c10fSJason Gunthorpe 	uobj = uobj_get_destroy(UVERBS_OBJECT_SRQ, cmd.srq_handle, attrs);
3576fd3c7904SMatan Barak 	if (IS_ERR(uobj))
3577fd3c7904SMatan Barak 		return PTR_ERR(uobj);
3578fd3c7904SMatan Barak 
35799ead190bSRoland Dreier 	obj = container_of(uobj, struct ib_uevent_object, uobject);
3580fd3c7904SMatan Barak 	memset(&resp, 0, sizeof(resp));
35819ead190bSRoland Dreier 	resp.events_reported = obj->events_reported;
358232ed5c00SJason Gunthorpe 
358332ed5c00SJason Gunthorpe 	uobj_put_destroy(uobj);
358432ed5c00SJason Gunthorpe 
35859a073857SJason Gunthorpe 	return uverbs_response(attrs, &resp, sizeof(resp));
3586f520ba5aSRoland Dreier }
358702d1aa7aSEli Cohen 
ib_uverbs_ex_query_device(struct uverbs_attr_bundle * attrs)3588974d6b4bSJason Gunthorpe static int ib_uverbs_ex_query_device(struct uverbs_attr_bundle *attrs)
358902d1aa7aSEli Cohen {
35907eebced1SJason Gunthorpe 	struct ib_uverbs_ex_query_device_resp resp = {};
359102d1aa7aSEli Cohen 	struct ib_uverbs_ex_query_device  cmd;
35922953f425SLeon Romanovsky 	struct ib_device_attr attr = {0};
3593bbd51e88SJason Gunthorpe 	struct ib_ucontext *ucontext;
3594bbd51e88SJason Gunthorpe 	struct ib_device *ib_dev;
359502d1aa7aSEli Cohen 	int err;
359602d1aa7aSEli Cohen 
35978313c10fSJason Gunthorpe 	ucontext = ib_uverbs_get_ucontext(attrs);
3598bbd51e88SJason Gunthorpe 	if (IS_ERR(ucontext))
3599bbd51e88SJason Gunthorpe 		return PTR_ERR(ucontext);
3600bbd51e88SJason Gunthorpe 	ib_dev = ucontext->device;
3601bbd51e88SJason Gunthorpe 
36027eebced1SJason Gunthorpe 	err = uverbs_request(attrs, &cmd, sizeof(cmd));
360302d1aa7aSEli Cohen 	if (err)
360402d1aa7aSEli Cohen 		return err;
360502d1aa7aSEli Cohen 
360602d1aa7aSEli Cohen 	if (cmd.comp_mask)
360702d1aa7aSEli Cohen 		return -EINVAL;
360802d1aa7aSEli Cohen 
360902d1aa7aSEli Cohen 	if (cmd.reserved)
361002d1aa7aSEli Cohen 		return -EINVAL;
361102d1aa7aSEli Cohen 
36123023a1e9SKamal Heib 	err = ib_dev->ops.query_device(ib_dev, &attr, &attrs->driver_udata);
361302d1aa7aSEli Cohen 	if (err)
361402d1aa7aSEli Cohen 		return err;
361502d1aa7aSEli Cohen 
3616bbd51e88SJason Gunthorpe 	copy_query_dev_fields(ucontext, &resp.base, &attr);
361702d1aa7aSEli Cohen 
3618f4056bfdSHaggai Eran 	resp.odp_caps.general_caps = attr.odp_caps.general_caps;
3619f4056bfdSHaggai Eran 	resp.odp_caps.per_transport_caps.rc_odp_caps =
3620f4056bfdSHaggai Eran 		attr.odp_caps.per_transport_caps.rc_odp_caps;
3621f4056bfdSHaggai Eran 	resp.odp_caps.per_transport_caps.uc_odp_caps =
3622f4056bfdSHaggai Eran 		attr.odp_caps.per_transport_caps.uc_odp_caps;
3623f4056bfdSHaggai Eran 	resp.odp_caps.per_transport_caps.ud_odp_caps =
3624f4056bfdSHaggai Eran 		attr.odp_caps.per_transport_caps.ud_odp_caps;
362552a72e2aSMoni Shoua 	resp.xrc_odp_caps = attr.odp_caps.per_transport_caps.xrc_odp_caps;
362624306dc6SMatan Barak 
362724306dc6SMatan Barak 	resp.timestamp_mask = attr.timestamp_mask;
362824306dc6SMatan Barak 	resp.hca_core_clock = attr.hca_core_clock;
3629e945c653SJason Gunthorpe 	resp.device_cap_flags_ex = attr.device_cap_flags;
363047adf2f4SYishai Hadas 	resp.rss_caps.supported_qpts = attr.rss_caps.supported_qpts;
363147adf2f4SYishai Hadas 	resp.rss_caps.max_rwq_indirection_tables =
363247adf2f4SYishai Hadas 		attr.rss_caps.max_rwq_indirection_tables;
363347adf2f4SYishai Hadas 	resp.rss_caps.max_rwq_indirection_table_size =
363447adf2f4SYishai Hadas 		attr.rss_caps.max_rwq_indirection_table_size;
363547adf2f4SYishai Hadas 	resp.max_wq_type_rq = attr.max_wq_type_rq;
36365f23d426SNoa Osherovich 	resp.raw_packet_caps = attr.raw_packet_caps;
363778b1beb0SLeon Romanovsky 	resp.tm_caps.max_rndv_hdr_size	= attr.tm_caps.max_rndv_hdr_size;
363878b1beb0SLeon Romanovsky 	resp.tm_caps.max_num_tags	= attr.tm_caps.max_num_tags;
363978b1beb0SLeon Romanovsky 	resp.tm_caps.max_ops		= attr.tm_caps.max_ops;
364078b1beb0SLeon Romanovsky 	resp.tm_caps.max_sge		= attr.tm_caps.max_sge;
364178b1beb0SLeon Romanovsky 	resp.tm_caps.flags		= attr.tm_caps.flags;
364218bd9072SYonatan Cohen 	resp.cq_moderation_caps.max_cq_moderation_count  =
364318bd9072SYonatan Cohen 		attr.cq_caps.max_cq_moderation_count;
364418bd9072SYonatan Cohen 	resp.cq_moderation_caps.max_cq_moderation_period =
364518bd9072SYonatan Cohen 		attr.cq_caps.max_cq_moderation_period;
36461d8eeb9fSAriel Levkovich 	resp.max_dm_size = attr.max_dm_size;
36477eebced1SJason Gunthorpe 	resp.response_length = uverbs_response_length(attrs, sizeof(resp));
36487eebced1SJason Gunthorpe 
36499a073857SJason Gunthorpe 	return uverbs_response(attrs, &resp, sizeof(resp));
365002d1aa7aSEli Cohen }
3651869ddcf8SYonatan Cohen 
ib_uverbs_ex_modify_cq(struct uverbs_attr_bundle * attrs)3652974d6b4bSJason Gunthorpe static int ib_uverbs_ex_modify_cq(struct uverbs_attr_bundle *attrs)
3653869ddcf8SYonatan Cohen {
365429a29d18SJason Gunthorpe 	struct ib_uverbs_ex_modify_cq cmd;
3655869ddcf8SYonatan Cohen 	struct ib_cq *cq;
3656869ddcf8SYonatan Cohen 	int ret;
3657869ddcf8SYonatan Cohen 
365829a29d18SJason Gunthorpe 	ret = uverbs_request(attrs, &cmd, sizeof(cmd));
3659869ddcf8SYonatan Cohen 	if (ret)
3660869ddcf8SYonatan Cohen 		return ret;
3661869ddcf8SYonatan Cohen 
3662869ddcf8SYonatan Cohen 	if (!cmd.attr_mask || cmd.reserved)
3663869ddcf8SYonatan Cohen 		return -EINVAL;
3664869ddcf8SYonatan Cohen 
3665869ddcf8SYonatan Cohen 	if (cmd.attr_mask > IB_CQ_MODERATE)
3666869ddcf8SYonatan Cohen 		return -EOPNOTSUPP;
3667869ddcf8SYonatan Cohen 
36688313c10fSJason Gunthorpe 	cq = uobj_get_obj_read(cq, UVERBS_OBJECT_CQ, cmd.cq_handle, attrs);
3669869ddcf8SYonatan Cohen 	if (!cq)
3670869ddcf8SYonatan Cohen 		return -EINVAL;
3671869ddcf8SYonatan Cohen 
36724190b4e9SLeon Romanovsky 	ret = rdma_set_cq_moderation(cq, cmd.attr.cq_count, cmd.attr.cq_period);
3673869ddcf8SYonatan Cohen 
36745bd48c18SJason Gunthorpe 	rdma_lookup_put_uobject(&cq->uobject->uevent.uobject,
36755bd48c18SJason Gunthorpe 				UVERBS_LOOKUP_READ);
3676869ddcf8SYonatan Cohen 	return ret;
3677869ddcf8SYonatan Cohen }
3678d120c3c9SJason Gunthorpe 
3679669dac1eSJason Gunthorpe /*
3680669dac1eSJason Gunthorpe  * Describe the input structs for write(). Some write methods have an input
3681669dac1eSJason Gunthorpe  * only struct, most have an input and output. If the struct has an output then
3682669dac1eSJason Gunthorpe  * the 'response' u64 must be the first field in the request structure.
3683669dac1eSJason Gunthorpe  *
3684669dac1eSJason Gunthorpe  * If udata is present then both the request and response structs have a
3685669dac1eSJason Gunthorpe  * trailing driver_data flex array. In this case the size of the base struct
3686669dac1eSJason Gunthorpe  * cannot be changed.
3687669dac1eSJason Gunthorpe  */
3688669dac1eSJason Gunthorpe #define UAPI_DEF_WRITE_IO(req, resp)                                           \
3689669dac1eSJason Gunthorpe 	.write.has_resp = 1 +                                                  \
3690669dac1eSJason Gunthorpe 			  BUILD_BUG_ON_ZERO(offsetof(req, response) != 0) +    \
3691bebcfe85SGustavo A. R. Silva 			  BUILD_BUG_ON_ZERO(sizeof_field(req, response) !=    \
3692669dac1eSJason Gunthorpe 					    sizeof(u64)),                      \
3693669dac1eSJason Gunthorpe 	.write.req_size = sizeof(req), .write.resp_size = sizeof(resp)
3694669dac1eSJason Gunthorpe 
3695669dac1eSJason Gunthorpe #define UAPI_DEF_WRITE_I(req) .write.req_size = sizeof(req)
3696669dac1eSJason Gunthorpe 
3697669dac1eSJason Gunthorpe #define UAPI_DEF_WRITE_UDATA_IO(req, resp)                                     \
3698669dac1eSJason Gunthorpe 	UAPI_DEF_WRITE_IO(req, resp),                                          \
3699669dac1eSJason Gunthorpe 		.write.has_udata =                                             \
3700669dac1eSJason Gunthorpe 			1 +                                                    \
3701669dac1eSJason Gunthorpe 			BUILD_BUG_ON_ZERO(offsetof(req, driver_data) !=        \
3702669dac1eSJason Gunthorpe 					  sizeof(req)) +                       \
3703669dac1eSJason Gunthorpe 			BUILD_BUG_ON_ZERO(offsetof(resp, driver_data) !=       \
3704669dac1eSJason Gunthorpe 					  sizeof(resp))
3705669dac1eSJason Gunthorpe 
3706669dac1eSJason Gunthorpe #define UAPI_DEF_WRITE_UDATA_I(req)                                            \
3707669dac1eSJason Gunthorpe 	UAPI_DEF_WRITE_I(req),                                                 \
3708669dac1eSJason Gunthorpe 		.write.has_udata =                                             \
3709669dac1eSJason Gunthorpe 			1 + BUILD_BUG_ON_ZERO(offsetof(req, driver_data) !=    \
3710669dac1eSJason Gunthorpe 					      sizeof(req))
3711669dac1eSJason Gunthorpe 
3712669dac1eSJason Gunthorpe /*
3713669dac1eSJason Gunthorpe  * The _EX versions are for use with WRITE_EX and allow the last struct member
3714669dac1eSJason Gunthorpe  * to be specified. Buffers that do not include that member will be rejected.
3715669dac1eSJason Gunthorpe  */
3716669dac1eSJason Gunthorpe #define UAPI_DEF_WRITE_IO_EX(req, req_last_member, resp, resp_last_member)     \
3717669dac1eSJason Gunthorpe 	.write.has_resp = 1,                                                   \
3718d384742eSJason Gunthorpe 	.write.req_size = offsetofend(req, req_last_member),                   \
3719d384742eSJason Gunthorpe 	.write.resp_size = offsetofend(resp, resp_last_member)
3720669dac1eSJason Gunthorpe 
3721669dac1eSJason Gunthorpe #define UAPI_DEF_WRITE_I_EX(req, req_last_member)                              \
3722d384742eSJason Gunthorpe 	.write.req_size = offsetofend(req, req_last_member)
3723669dac1eSJason Gunthorpe 
3724d120c3c9SJason Gunthorpe const struct uapi_definition uverbs_def_write_intf[] = {
3725a140692aSJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3726a140692aSJason Gunthorpe 		UVERBS_OBJECT_AH,
3727d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_AH,
3728a140692aSJason Gunthorpe 				     ib_uverbs_create_ah,
3729669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_UDATA_IO(
3730669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_ah,
3731676a80adSJason Gunthorpe 					     struct ib_uverbs_create_ah_resp)),
3732669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3733669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_DESTROY_AH,
3734a140692aSJason Gunthorpe 			ib_uverbs_destroy_ah,
3735676a80adSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_destroy_ah)),
3736676a80adSJason Gunthorpe 		UAPI_DEF_OBJ_NEEDS_FN(create_user_ah),
3737676a80adSJason Gunthorpe 		UAPI_DEF_OBJ_NEEDS_FN(destroy_ah)),
3738d120c3c9SJason Gunthorpe 
3739d120c3c9SJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3740d120c3c9SJason Gunthorpe 		UVERBS_OBJECT_COMP_CHANNEL,
3741669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3742669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL,
3743669dac1eSJason Gunthorpe 			ib_uverbs_create_comp_channel,
3744669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(
3745669dac1eSJason Gunthorpe 				struct ib_uverbs_create_comp_channel,
3746669dac1eSJason Gunthorpe 				struct ib_uverbs_create_comp_channel_resp))),
3747d120c3c9SJason Gunthorpe 
3748d120c3c9SJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3749d120c3c9SJason Gunthorpe 		UVERBS_OBJECT_CQ,
3750d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_CQ,
3751a140692aSJason Gunthorpe 				     ib_uverbs_create_cq,
3752669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_UDATA_IO(
3753669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_cq,
3754669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_cq_resp),
3755a140692aSJason Gunthorpe 				     UAPI_DEF_METHOD_NEEDS_FN(create_cq)),
3756669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3757669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_DESTROY_CQ,
3758a140692aSJason Gunthorpe 			ib_uverbs_destroy_cq,
3759669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_destroy_cq,
3760669dac1eSJason Gunthorpe 					  struct ib_uverbs_destroy_cq_resp),
3761a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(destroy_cq)),
3762669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3763669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_POLL_CQ,
3764a140692aSJason Gunthorpe 			ib_uverbs_poll_cq,
3765669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_poll_cq,
3766669dac1eSJason Gunthorpe 					  struct ib_uverbs_poll_cq_resp),
3767a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(poll_cq)),
3768669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3769669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_REQ_NOTIFY_CQ,
3770a140692aSJason Gunthorpe 			ib_uverbs_req_notify_cq,
3771669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_req_notify_cq),
3772a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(req_notify_cq)),
3773d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_RESIZE_CQ,
3774a140692aSJason Gunthorpe 				     ib_uverbs_resize_cq,
3775669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_UDATA_IO(
3776669dac1eSJason Gunthorpe 					     struct ib_uverbs_resize_cq,
3777669dac1eSJason Gunthorpe 					     struct ib_uverbs_resize_cq_resp),
3778a140692aSJason Gunthorpe 				     UAPI_DEF_METHOD_NEEDS_FN(resize_cq)),
3779669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3780669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_CREATE_CQ,
3781a140692aSJason Gunthorpe 			ib_uverbs_ex_create_cq,
3782669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_create_cq,
3783669dac1eSJason Gunthorpe 					     reserved,
3784669dac1eSJason Gunthorpe 					     struct ib_uverbs_ex_create_cq_resp,
3785669dac1eSJason Gunthorpe 					     response_length),
3786a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(create_cq)),
3787669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3788669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_MODIFY_CQ,
3789a140692aSJason Gunthorpe 			ib_uverbs_ex_modify_cq,
3790669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_ex_modify_cq),
3791b8e3130dSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(modify_cq))),
3792d120c3c9SJason Gunthorpe 
3793d120c3c9SJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3794d120c3c9SJason Gunthorpe 		UVERBS_OBJECT_DEVICE,
3795d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_GET_CONTEXT,
3796669dac1eSJason Gunthorpe 				     ib_uverbs_get_context,
3797669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_UDATA_IO(
3798669dac1eSJason Gunthorpe 					     struct ib_uverbs_get_context,
3799669dac1eSJason Gunthorpe 					     struct ib_uverbs_get_context_resp)),
3800669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3801669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_QUERY_DEVICE,
3802669dac1eSJason Gunthorpe 			ib_uverbs_query_device,
3803669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_query_device,
3804669dac1eSJason Gunthorpe 					  struct ib_uverbs_query_device_resp)),
3805669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3806669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_QUERY_PORT,
3807a140692aSJason Gunthorpe 			ib_uverbs_query_port,
3808669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_query_port,
3809669dac1eSJason Gunthorpe 					  struct ib_uverbs_query_port_resp),
3810a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(query_port)),
3811669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3812669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_QUERY_DEVICE,
3813a140692aSJason Gunthorpe 			ib_uverbs_ex_query_device,
3814669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO_EX(
3815669dac1eSJason Gunthorpe 				struct ib_uverbs_ex_query_device,
3816669dac1eSJason Gunthorpe 				reserved,
3817669dac1eSJason Gunthorpe 				struct ib_uverbs_ex_query_device_resp,
3818669dac1eSJason Gunthorpe 				response_length),
3819a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(query_device)),
3820a140692aSJason Gunthorpe 		UAPI_DEF_OBJ_NEEDS_FN(alloc_ucontext),
3821a140692aSJason Gunthorpe 		UAPI_DEF_OBJ_NEEDS_FN(dealloc_ucontext)),
3822d120c3c9SJason Gunthorpe 
3823d120c3c9SJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3824d120c3c9SJason Gunthorpe 		UVERBS_OBJECT_FLOW,
3825669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3826669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_CREATE_FLOW,
3827a140692aSJason Gunthorpe 			ib_uverbs_ex_create_flow,
3828669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_create_flow,
3829669dac1eSJason Gunthorpe 					     flow_attr,
3830669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_flow_resp,
3831669dac1eSJason Gunthorpe 					     flow_handle),
3832a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(create_flow)),
3833669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3834669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_DESTROY_FLOW,
3835a140692aSJason Gunthorpe 			ib_uverbs_ex_destroy_flow,
3836669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_destroy_flow),
3837a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(destroy_flow))),
3838d120c3c9SJason Gunthorpe 
3839a140692aSJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3840a140692aSJason Gunthorpe 		UVERBS_OBJECT_MR,
3841d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_DEREG_MR,
3842a140692aSJason Gunthorpe 				     ib_uverbs_dereg_mr,
3843669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_I(struct ib_uverbs_dereg_mr),
3844a140692aSJason Gunthorpe 				     UAPI_DEF_METHOD_NEEDS_FN(dereg_mr)),
3845669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3846669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_REG_MR,
3847a140692aSJason Gunthorpe 			ib_uverbs_reg_mr,
3848669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_UDATA_IO(struct ib_uverbs_reg_mr,
3849669dac1eSJason Gunthorpe 						struct ib_uverbs_reg_mr_resp),
3850a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(reg_user_mr)),
3851669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3852669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_REREG_MR,
3853a140692aSJason Gunthorpe 			ib_uverbs_rereg_mr,
3854669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_UDATA_IO(struct ib_uverbs_rereg_mr,
3855669dac1eSJason Gunthorpe 						struct ib_uverbs_rereg_mr_resp),
3856a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(rereg_user_mr))),
3857d120c3c9SJason Gunthorpe 
3858a140692aSJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3859a140692aSJason Gunthorpe 		UVERBS_OBJECT_MW,
3860669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3861669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_ALLOC_MW,
3862a140692aSJason Gunthorpe 			ib_uverbs_alloc_mw,
3863669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_UDATA_IO(struct ib_uverbs_alloc_mw,
3864669dac1eSJason Gunthorpe 						struct ib_uverbs_alloc_mw_resp),
3865a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(alloc_mw)),
3866669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3867669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_DEALLOC_MW,
3868a140692aSJason Gunthorpe 			ib_uverbs_dealloc_mw,
3869669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_dealloc_mw),
3870a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(dealloc_mw))),
3871d120c3c9SJason Gunthorpe 
3872a140692aSJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3873a140692aSJason Gunthorpe 		UVERBS_OBJECT_PD,
3874669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3875669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_ALLOC_PD,
3876a140692aSJason Gunthorpe 			ib_uverbs_alloc_pd,
3877669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_UDATA_IO(struct ib_uverbs_alloc_pd,
3878669dac1eSJason Gunthorpe 						struct ib_uverbs_alloc_pd_resp),
3879a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(alloc_pd)),
3880669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3881669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_DEALLOC_PD,
3882a140692aSJason Gunthorpe 			ib_uverbs_dealloc_pd,
3883669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_dealloc_pd),
3884a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(dealloc_pd))),
3885d120c3c9SJason Gunthorpe 
3886d120c3c9SJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3887d120c3c9SJason Gunthorpe 		UVERBS_OBJECT_QP,
3888669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3889669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_ATTACH_MCAST,
3890a140692aSJason Gunthorpe 			ib_uverbs_attach_mcast,
3891669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_attach_mcast),
3892a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(attach_mcast),
3893a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(detach_mcast)),
3894d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_QP,
3895a140692aSJason Gunthorpe 				     ib_uverbs_create_qp,
3896669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_UDATA_IO(
3897669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_qp,
3898669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_qp_resp),
3899a140692aSJason Gunthorpe 				     UAPI_DEF_METHOD_NEEDS_FN(create_qp)),
3900669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3901669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_DESTROY_QP,
3902a140692aSJason Gunthorpe 			ib_uverbs_destroy_qp,
3903669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_destroy_qp,
3904669dac1eSJason Gunthorpe 					  struct ib_uverbs_destroy_qp_resp),
3905a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(destroy_qp)),
3906669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3907669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_DETACH_MCAST,
3908a140692aSJason Gunthorpe 			ib_uverbs_detach_mcast,
3909669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_detach_mcast),
3910a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(detach_mcast)),
3911669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3912669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_MODIFY_QP,
3913a140692aSJason Gunthorpe 			ib_uverbs_modify_qp,
3914669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_modify_qp),
3915a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(modify_qp)),
3916669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3917669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_POST_RECV,
3918a140692aSJason Gunthorpe 			ib_uverbs_post_recv,
3919669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_post_recv,
3920669dac1eSJason Gunthorpe 					  struct ib_uverbs_post_recv_resp),
3921a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(post_recv)),
3922669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3923669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_POST_SEND,
3924a140692aSJason Gunthorpe 			ib_uverbs_post_send,
3925669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_post_send,
3926669dac1eSJason Gunthorpe 					  struct ib_uverbs_post_send_resp),
3927a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(post_send)),
3928669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
3929669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_QUERY_QP,
3930a140692aSJason Gunthorpe 			ib_uverbs_query_qp,
3931669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_query_qp,
3932669dac1eSJason Gunthorpe 					  struct ib_uverbs_query_qp_resp),
3933a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(query_qp)),
3934669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3935669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_CREATE_QP,
3936a140692aSJason Gunthorpe 			ib_uverbs_ex_create_qp,
3937669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_create_qp,
3938669dac1eSJason Gunthorpe 					     comp_mask,
3939669dac1eSJason Gunthorpe 					     struct ib_uverbs_ex_create_qp_resp,
3940669dac1eSJason Gunthorpe 					     response_length),
3941a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(create_qp)),
3942669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3943669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_MODIFY_QP,
3944a140692aSJason Gunthorpe 			ib_uverbs_ex_modify_qp,
3945669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_modify_qp,
3946669dac1eSJason Gunthorpe 					     base,
3947669dac1eSJason Gunthorpe 					     struct ib_uverbs_ex_modify_qp_resp,
3948669dac1eSJason Gunthorpe 					     response_length),
3949a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(modify_qp))),
3950d120c3c9SJason Gunthorpe 
3951d120c3c9SJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3952d120c3c9SJason Gunthorpe 		UVERBS_OBJECT_RWQ_IND_TBL,
3953a140692aSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3954a140692aSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL,
3955a140692aSJason Gunthorpe 			ib_uverbs_ex_create_rwq_ind_table,
3956669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO_EX(
3957669dac1eSJason Gunthorpe 				struct ib_uverbs_ex_create_rwq_ind_table,
3958669dac1eSJason Gunthorpe 				log_ind_tbl_size,
3959669dac1eSJason Gunthorpe 				struct ib_uverbs_ex_create_rwq_ind_table_resp,
3960669dac1eSJason Gunthorpe 				ind_tbl_num),
3961a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(create_rwq_ind_table)),
3962a140692aSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3963a140692aSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL,
3964a140692aSJason Gunthorpe 			ib_uverbs_ex_destroy_rwq_ind_table,
3965669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I(
3966669dac1eSJason Gunthorpe 				struct ib_uverbs_ex_destroy_rwq_ind_table),
3967a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(destroy_rwq_ind_table))),
3968d120c3c9SJason Gunthorpe 
3969d120c3c9SJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3970d120c3c9SJason Gunthorpe 		UVERBS_OBJECT_WQ,
3971669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3972669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_CREATE_WQ,
3973a140692aSJason Gunthorpe 			ib_uverbs_ex_create_wq,
3974669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_create_wq,
3975669dac1eSJason Gunthorpe 					     max_sge,
3976669dac1eSJason Gunthorpe 					     struct ib_uverbs_ex_create_wq_resp,
3977669dac1eSJason Gunthorpe 					     wqn),
3978a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(create_wq)),
3979669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3980669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_DESTROY_WQ,
3981a140692aSJason Gunthorpe 			ib_uverbs_ex_destroy_wq,
3982669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO_EX(struct ib_uverbs_ex_destroy_wq,
3983669dac1eSJason Gunthorpe 					     wq_handle,
3984669dac1eSJason Gunthorpe 					     struct ib_uverbs_ex_destroy_wq_resp,
3985669dac1eSJason Gunthorpe 					     reserved),
3986a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(destroy_wq)),
3987669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE_EX(
3988669dac1eSJason Gunthorpe 			IB_USER_VERBS_EX_CMD_MODIFY_WQ,
3989a140692aSJason Gunthorpe 			ib_uverbs_ex_modify_wq,
3990669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_I_EX(struct ib_uverbs_ex_modify_wq,
3991669dac1eSJason Gunthorpe 					    curr_wq_state),
3992a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(modify_wq))),
3993d120c3c9SJason Gunthorpe 
3994d120c3c9SJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
3995d120c3c9SJason Gunthorpe 		UVERBS_OBJECT_SRQ,
3996d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_SRQ,
3997a140692aSJason Gunthorpe 				     ib_uverbs_create_srq,
3998669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_UDATA_IO(
3999669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_srq,
4000669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_srq_resp),
4001a140692aSJason Gunthorpe 				     UAPI_DEF_METHOD_NEEDS_FN(create_srq)),
4002d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_CREATE_XSRQ,
4003a140692aSJason Gunthorpe 				     ib_uverbs_create_xsrq,
4004669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_UDATA_IO(
4005669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_xsrq,
4006669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_srq_resp),
4007a140692aSJason Gunthorpe 				     UAPI_DEF_METHOD_NEEDS_FN(create_srq)),
4008669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
4009669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_DESTROY_SRQ,
4010a140692aSJason Gunthorpe 			ib_uverbs_destroy_srq,
4011669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_destroy_srq,
4012669dac1eSJason Gunthorpe 					  struct ib_uverbs_destroy_srq_resp),
4013a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(destroy_srq)),
4014669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
4015669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_MODIFY_SRQ,
4016a140692aSJason Gunthorpe 			ib_uverbs_modify_srq,
4017669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_UDATA_I(struct ib_uverbs_modify_srq),
4018a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(modify_srq)),
4019669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
4020669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_POST_SRQ_RECV,
4021a140692aSJason Gunthorpe 			ib_uverbs_post_srq_recv,
4022669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_post_srq_recv,
4023669dac1eSJason Gunthorpe 					  struct ib_uverbs_post_srq_recv_resp),
4024a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(post_srq_recv)),
4025669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
4026669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_QUERY_SRQ,
4027a140692aSJason Gunthorpe 			ib_uverbs_query_srq,
4028669dac1eSJason Gunthorpe 			UAPI_DEF_WRITE_IO(struct ib_uverbs_query_srq,
4029669dac1eSJason Gunthorpe 					  struct ib_uverbs_query_srq_resp),
4030a140692aSJason Gunthorpe 			UAPI_DEF_METHOD_NEEDS_FN(query_srq))),
4031d120c3c9SJason Gunthorpe 
4032a140692aSJason Gunthorpe 	DECLARE_UVERBS_OBJECT(
4033a140692aSJason Gunthorpe 		UVERBS_OBJECT_XRCD,
4034669dac1eSJason Gunthorpe 		DECLARE_UVERBS_WRITE(
4035669dac1eSJason Gunthorpe 			IB_USER_VERBS_CMD_CLOSE_XRCD,
4036a140692aSJason Gunthorpe 			ib_uverbs_close_xrcd,
403744ce37bcSJason Gunthorpe 			UAPI_DEF_WRITE_I(struct ib_uverbs_close_xrcd)),
4038d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_OPEN_QP,
4039669dac1eSJason Gunthorpe 				     ib_uverbs_open_qp,
4040669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_UDATA_IO(
4041669dac1eSJason Gunthorpe 					     struct ib_uverbs_open_qp,
4042669dac1eSJason Gunthorpe 					     struct ib_uverbs_create_qp_resp)),
4043d120c3c9SJason Gunthorpe 		DECLARE_UVERBS_WRITE(IB_USER_VERBS_CMD_OPEN_XRCD,
4044a140692aSJason Gunthorpe 				     ib_uverbs_open_xrcd,
4045669dac1eSJason Gunthorpe 				     UAPI_DEF_WRITE_UDATA_IO(
4046669dac1eSJason Gunthorpe 					     struct ib_uverbs_open_xrcd,
404744ce37bcSJason Gunthorpe 					     struct ib_uverbs_open_xrcd_resp)),
404844ce37bcSJason Gunthorpe 		UAPI_DEF_OBJ_NEEDS_FN(alloc_xrcd),
404944ce37bcSJason Gunthorpe 		UAPI_DEF_OBJ_NEEDS_FN(dealloc_xrcd)),
4050d120c3c9SJason Gunthorpe 
4051d120c3c9SJason Gunthorpe 	{},
4052d120c3c9SJason Gunthorpe };
4053