141b2a71fSMatan Barak /*
241b2a71fSMatan Barak  * Copyright (c) 2017, Mellanox Technologies inc.  All rights reserved.
341b2a71fSMatan Barak  *
441b2a71fSMatan Barak  * This software is available to you under a choice of one of two
541b2a71fSMatan Barak  * licenses.  You may choose to be licensed under the terms of the GNU
641b2a71fSMatan Barak  * General Public License (GPL) Version 2, available from the file
741b2a71fSMatan Barak  * COPYING in the main directory of this source tree, or the
841b2a71fSMatan Barak  * OpenIB.org BSD license below:
941b2a71fSMatan Barak  *
1041b2a71fSMatan Barak  *     Redistribution and use in source and binary forms, with or
1141b2a71fSMatan Barak  *     without modification, are permitted provided that the following
1241b2a71fSMatan Barak  *     conditions are met:
1341b2a71fSMatan Barak  *
1441b2a71fSMatan Barak  *      - Redistributions of source code must retain the above
1541b2a71fSMatan Barak  *        copyright notice, this list of conditions and the following
1641b2a71fSMatan Barak  *        disclaimer.
1741b2a71fSMatan Barak  *
1841b2a71fSMatan Barak  *      - Redistributions in binary form must reproduce the above
1941b2a71fSMatan Barak  *        copyright notice, this list of conditions and the following
2041b2a71fSMatan Barak  *        disclaimer in the documentation and/or other materials
2141b2a71fSMatan Barak  *        provided with the distribution.
2241b2a71fSMatan Barak  *
2341b2a71fSMatan Barak  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2441b2a71fSMatan Barak  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2541b2a71fSMatan Barak  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2641b2a71fSMatan Barak  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2741b2a71fSMatan Barak  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2841b2a71fSMatan Barak  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2941b2a71fSMatan Barak  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3041b2a71fSMatan Barak  * SOFTWARE.
3141b2a71fSMatan Barak  */
3241b2a71fSMatan Barak 
3341b2a71fSMatan Barak #include <rdma/uverbs_std_types.h>
3441b2a71fSMatan Barak #include "rdma_core.h"
3541b2a71fSMatan Barak #include "uverbs.h"
3613ef5539SLeon Romanovsky #include "restrack.h"
3741b2a71fSMatan Barak 
uverbs_free_cq(struct ib_uobject * uobject,enum rdma_remove_reason why,struct uverbs_attr_bundle * attrs)3841b2a71fSMatan Barak static int uverbs_free_cq(struct ib_uobject *uobject,
39a6a3797dSShamir Rabinovitch 			  enum rdma_remove_reason why,
40a6a3797dSShamir Rabinovitch 			  struct uverbs_attr_bundle *attrs)
4141b2a71fSMatan Barak {
4241b2a71fSMatan Barak 	struct ib_cq *cq = uobject->object;
4341b2a71fSMatan Barak 	struct ib_uverbs_event_queue *ev_queue = cq->cq_context;
4441b2a71fSMatan Barak 	struct ib_ucq_object *ucq =
454ec1dcfcSJason Gunthorpe 		container_of(uobject, struct ib_ucq_object, uevent.uobject);
4641b2a71fSMatan Barak 	int ret;
4741b2a71fSMatan Barak 
48c4367a26SShamir Rabinovitch 	ret = ib_destroy_cq_user(cq, &attrs->driver_udata);
49*efa968eeSLeon Romanovsky 	if (ret)
501c77483eSYishai Hadas 		return ret;
511c77483eSYishai Hadas 
521c77483eSYishai Hadas 	ib_uverbs_release_ucq(
531c77483eSYishai Hadas 		ev_queue ? container_of(ev_queue,
5441b2a71fSMatan Barak 					struct ib_uverbs_completion_event_file,
551c77483eSYishai Hadas 					ev_queue) :
561c77483eSYishai Hadas 			   NULL,
5741b2a71fSMatan Barak 		ucq);
58*efa968eeSLeon Romanovsky 	return 0;
5941b2a71fSMatan Barak }
6041b2a71fSMatan Barak 
UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)61e83f0ecdSJason Gunthorpe static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(
6215a1b4beSJason Gunthorpe 	struct uverbs_attr_bundle *attrs)
6341b2a71fSMatan Barak {
64e83f0ecdSJason Gunthorpe 	struct ib_ucq_object *obj = container_of(
65e83f0ecdSJason Gunthorpe 		uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_CQ_HANDLE),
664ec1dcfcSJason Gunthorpe 		typeof(*obj), uevent.uobject);
67feec576aSJason Gunthorpe 	struct ib_device *ib_dev = attrs->context->device;
6841b2a71fSMatan Barak 	int ret;
6941b2a71fSMatan Barak 	u64 user_handle;
7041b2a71fSMatan Barak 	struct ib_cq_init_attr attr = {};
7141b2a71fSMatan Barak 	struct ib_cq                   *cq;
7241b2a71fSMatan Barak 	struct ib_uverbs_completion_event_file    *ev_file = NULL;
7341b2a71fSMatan Barak 	struct ib_uobject *ev_file_uobj;
7441b2a71fSMatan Barak 
753023a1e9SKamal Heib 	if (!ib_dev->ops.create_cq || !ib_dev->ops.destroy_cq)
7641b2a71fSMatan Barak 		return -EOPNOTSUPP;
7741b2a71fSMatan Barak 
7841b2a71fSMatan Barak 	ret = uverbs_copy_from(&attr.comp_vector, attrs,
7941b2a71fSMatan Barak 			       UVERBS_ATTR_CREATE_CQ_COMP_VECTOR);
8041b2a71fSMatan Barak 	if (!ret)
8141b2a71fSMatan Barak 		ret = uverbs_copy_from(&attr.cqe, attrs,
8241b2a71fSMatan Barak 				       UVERBS_ATTR_CREATE_CQ_CQE);
8341b2a71fSMatan Barak 	if (!ret)
8441b2a71fSMatan Barak 		ret = uverbs_copy_from(&user_handle, attrs,
8541b2a71fSMatan Barak 				       UVERBS_ATTR_CREATE_CQ_USER_HANDLE);
8641b2a71fSMatan Barak 	if (ret)
8741b2a71fSMatan Barak 		return ret;
8841b2a71fSMatan Barak 
89bccd0622SJason Gunthorpe 	ret = uverbs_get_flags32(&attr.flags, attrs,
90bccd0622SJason Gunthorpe 				 UVERBS_ATTR_CREATE_CQ_FLAGS,
91bccd0622SJason Gunthorpe 				 IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION |
92bccd0622SJason Gunthorpe 					 IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN);
93bccd0622SJason Gunthorpe 	if (ret)
94bccd0622SJason Gunthorpe 		return ret;
9541b2a71fSMatan Barak 
963efa3812SMatan Barak 	ev_file_uobj = uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_CQ_COMP_CHANNEL);
973efa3812SMatan Barak 	if (!IS_ERR(ev_file_uobj)) {
9841b2a71fSMatan Barak 		ev_file = container_of(ev_file_uobj,
9941b2a71fSMatan Barak 				       struct ib_uverbs_completion_event_file,
100d0259e82SJason Gunthorpe 				       uobj);
10141b2a71fSMatan Barak 		uverbs_uobject_get(ev_file_uobj);
10241b2a71fSMatan Barak 	}
10341b2a71fSMatan Barak 
104cda9ee49SYishai Hadas 	obj->uevent.event_file = ib_uverbs_get_async_event(
105cda9ee49SYishai Hadas 		attrs, UVERBS_ATTR_CREATE_CQ_EVENT_FD);
10698a8890fSYishai Hadas 
10715a1b4beSJason Gunthorpe 	if (attr.comp_vector >= attrs->ufile->device->num_comp_vectors) {
10841b2a71fSMatan Barak 		ret = -EINVAL;
10941b2a71fSMatan Barak 		goto err_event_file;
11041b2a71fSMatan Barak 	}
11141b2a71fSMatan Barak 
11241b2a71fSMatan Barak 	INIT_LIST_HEAD(&obj->comp_list);
1134ec1dcfcSJason Gunthorpe 	INIT_LIST_HEAD(&obj->uevent.event_list);
11441b2a71fSMatan Barak 
115e39afe3dSLeon Romanovsky 	cq = rdma_zalloc_drv_obj(ib_dev, ib_cq);
116e39afe3dSLeon Romanovsky 	if (!cq) {
117e39afe3dSLeon Romanovsky 		ret = -ENOMEM;
11841b2a71fSMatan Barak 		goto err_event_file;
11941b2a71fSMatan Barak 	}
12041b2a71fSMatan Barak 
12141b2a71fSMatan Barak 	cq->device        = ib_dev;
1225bd48c18SJason Gunthorpe 	cq->uobject       = obj;
12341b2a71fSMatan Barak 	cq->comp_handler  = ib_uverbs_comp_handler;
12441b2a71fSMatan Barak 	cq->event_handler = ib_uverbs_cq_event_handler;
12541b2a71fSMatan Barak 	cq->cq_context    = ev_file ? &ev_file->ev_queue : NULL;
12641b2a71fSMatan Barak 	atomic_set(&cq->usecnt, 0);
127e39afe3dSLeon Romanovsky 
12813ef5539SLeon Romanovsky 	rdma_restrack_new(&cq->res, RDMA_RESTRACK_CQ);
129b09c4d70SLeon Romanovsky 	rdma_restrack_set_name(&cq->res, NULL);
130b09c4d70SLeon Romanovsky 
131e39afe3dSLeon Romanovsky 	ret = ib_dev->ops.create_cq(cq, &attr, &attrs->driver_udata);
132e39afe3dSLeon Romanovsky 	if (ret)
133e39afe3dSLeon Romanovsky 		goto err_free;
134e39afe3dSLeon Romanovsky 
1354ec1dcfcSJason Gunthorpe 	obj->uevent.uobject.object = cq;
1364ec1dcfcSJason Gunthorpe 	obj->uevent.uobject.user_handle = user_handle;
137b09c4d70SLeon Romanovsky 	rdma_restrack_add(&cq->res);
1380ac8903cSJason Gunthorpe 	uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_CQ_HANDLE);
13941b2a71fSMatan Barak 
14041b2a71fSMatan Barak 	ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_CQ_RESP_CQE, &cq->cqe,
14141b2a71fSMatan Barak 			     sizeof(cq->cqe));
1420ac8903cSJason Gunthorpe 	return ret;
14341b2a71fSMatan Barak 
144e39afe3dSLeon Romanovsky err_free:
14513ef5539SLeon Romanovsky 	rdma_restrack_put(&cq->res);
146e39afe3dSLeon Romanovsky 	kfree(cq);
14741b2a71fSMatan Barak err_event_file:
14898a8890fSYishai Hadas 	if (obj->uevent.event_file)
14998a8890fSYishai Hadas 		uverbs_uobject_put(&obj->uevent.event_file->uobj);
15041b2a71fSMatan Barak 	if (ev_file)
15141b2a71fSMatan Barak 		uverbs_uobject_put(ev_file_uobj);
15241b2a71fSMatan Barak 	return ret;
15341b2a71fSMatan Barak };
15441b2a71fSMatan Barak 
1559a119cd5SJason Gunthorpe DECLARE_UVERBS_NAMED_METHOD(
1569a119cd5SJason Gunthorpe 	UVERBS_METHOD_CQ_CREATE,
1579a119cd5SJason Gunthorpe 	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_CQ_HANDLE,
1589a119cd5SJason Gunthorpe 			UVERBS_OBJECT_CQ,
15941b2a71fSMatan Barak 			UVERBS_ACCESS_NEW,
16083bb4442SJason Gunthorpe 			UA_MANDATORY),
1619a119cd5SJason Gunthorpe 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_CQ_CQE,
16241b2a71fSMatan Barak 			   UVERBS_ATTR_TYPE(u32),
16383bb4442SJason Gunthorpe 			   UA_MANDATORY),
1649a119cd5SJason Gunthorpe 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_CQ_USER_HANDLE,
16541b2a71fSMatan Barak 			   UVERBS_ATTR_TYPE(u64),
16683bb4442SJason Gunthorpe 			   UA_MANDATORY),
1679a119cd5SJason Gunthorpe 	UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_CQ_COMP_CHANNEL,
16841b2a71fSMatan Barak 		       UVERBS_OBJECT_COMP_CHANNEL,
16983bb4442SJason Gunthorpe 		       UVERBS_ACCESS_READ,
17083bb4442SJason Gunthorpe 		       UA_OPTIONAL),
1719a119cd5SJason Gunthorpe 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_CQ_COMP_VECTOR,
1729a119cd5SJason Gunthorpe 			   UVERBS_ATTR_TYPE(u32),
17383bb4442SJason Gunthorpe 			   UA_MANDATORY),
174bccd0622SJason Gunthorpe 	UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_CREATE_CQ_FLAGS,
175bccd0622SJason Gunthorpe 			     enum ib_uverbs_ex_create_cq_flags),
1769a119cd5SJason Gunthorpe 	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_CQ_RESP_CQE,
1779a119cd5SJason Gunthorpe 			    UVERBS_ATTR_TYPE(u32),
17883bb4442SJason Gunthorpe 			    UA_MANDATORY),
179cda9ee49SYishai Hadas 	UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_CQ_EVENT_FD,
180cda9ee49SYishai Hadas 		       UVERBS_OBJECT_ASYNC_EVENT,
181cda9ee49SYishai Hadas 		       UVERBS_ACCESS_READ,
182cda9ee49SYishai Hadas 		       UA_OPTIONAL),
1836c61d2a5SJason Gunthorpe 	UVERBS_ATTR_UHW());
18441b2a71fSMatan Barak 
UVERBS_HANDLER(UVERBS_METHOD_CQ_DESTROY)185e83f0ecdSJason Gunthorpe static int UVERBS_HANDLER(UVERBS_METHOD_CQ_DESTROY)(
18615a1b4beSJason Gunthorpe 	struct uverbs_attr_bundle *attrs)
18741b2a71fSMatan Barak {
18841b2a71fSMatan Barak 	struct ib_uobject *uobj =
1893efa3812SMatan Barak 		uverbs_attr_get_uobject(attrs, UVERBS_ATTR_DESTROY_CQ_HANDLE);
190aa72c9a5SJason Gunthorpe 	struct ib_ucq_object *obj =
1914ec1dcfcSJason Gunthorpe 		container_of(uobj, struct ib_ucq_object, uevent.uobject);
192aa72c9a5SJason Gunthorpe 	struct ib_uverbs_destroy_cq_resp resp = {
193aa72c9a5SJason Gunthorpe 		.comp_events_reported = obj->comp_events_reported,
1944ec1dcfcSJason Gunthorpe 		.async_events_reported = obj->uevent.events_reported
195aa72c9a5SJason Gunthorpe 	};
19641b2a71fSMatan Barak 
19741b2a71fSMatan Barak 	return uverbs_copy_to(attrs, UVERBS_ATTR_DESTROY_CQ_RESP, &resp,
19841b2a71fSMatan Barak 			      sizeof(resp));
19941b2a71fSMatan Barak }
20041b2a71fSMatan Barak 
2019a119cd5SJason Gunthorpe DECLARE_UVERBS_NAMED_METHOD(
2029a119cd5SJason Gunthorpe 	UVERBS_METHOD_CQ_DESTROY,
2039a119cd5SJason Gunthorpe 	UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_CQ_HANDLE,
2049a119cd5SJason Gunthorpe 			UVERBS_OBJECT_CQ,
20541b2a71fSMatan Barak 			UVERBS_ACCESS_DESTROY,
20683bb4442SJason Gunthorpe 			UA_MANDATORY),
2079a119cd5SJason Gunthorpe 	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_DESTROY_CQ_RESP,
20841b2a71fSMatan Barak 			    UVERBS_ATTR_TYPE(struct ib_uverbs_destroy_cq_resp),
20983bb4442SJason Gunthorpe 			    UA_MANDATORY));
21041b2a71fSMatan Barak 
2119a119cd5SJason Gunthorpe DECLARE_UVERBS_NAMED_OBJECT(
2129a119cd5SJason Gunthorpe 	UVERBS_OBJECT_CQ,
2139a119cd5SJason Gunthorpe 	UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_ucq_object), uverbs_free_cq),
21441b2a71fSMatan Barak 	&UVERBS_METHOD(UVERBS_METHOD_CQ_CREATE),
21541b2a71fSMatan Barak 	&UVERBS_METHOD(UVERBS_METHOD_CQ_DESTROY)
21641b2a71fSMatan Barak );
2170bd01f3dSJason Gunthorpe 
2180bd01f3dSJason Gunthorpe const struct uapi_definition uverbs_def_obj_cq[] = {
2190bd01f3dSJason Gunthorpe 	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_CQ,
2200bd01f3dSJason Gunthorpe 				      UAPI_DEF_OBJ_NEEDS_FN(destroy_cq)),
2210bd01f3dSJason Gunthorpe 	{}
2220bd01f3dSJason Gunthorpe };
223