xref: /linux/drivers/infiniband/core/uverbs_std_types_cq.c (revision 7ce4de1cdaf11c39b507008dfb5a4e59079d4e8a)
1 /*
2  * Copyright (c) 2017, Mellanox Technologies inc.  All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 
33 #include <rdma/uverbs_std_types.h>
34 #include "rdma_core.h"
35 #include "uverbs.h"
36 #include "restrack.h"
37 
uverbs_free_cq(struct ib_uobject * uobject,enum rdma_remove_reason why,struct uverbs_attr_bundle * attrs)38 static int uverbs_free_cq(struct ib_uobject *uobject,
39 			  enum rdma_remove_reason why,
40 			  struct uverbs_attr_bundle *attrs)
41 {
42 	struct ib_cq *cq = uobject->object;
43 	struct ib_uverbs_event_queue *ev_queue = cq->cq_context;
44 	struct ib_ucq_object *ucq =
45 		container_of(uobject, struct ib_ucq_object, uevent.uobject);
46 	int ret;
47 
48 	ret = ib_destroy_cq_user(cq, &attrs->driver_udata);
49 	if (ret)
50 		return ret;
51 
52 	ib_uverbs_release_ucq(
53 		ev_queue ? container_of(ev_queue,
54 					struct ib_uverbs_completion_event_file,
55 					ev_queue) :
56 			   NULL,
57 		ucq);
58 	return 0;
59 }
60 
UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)61 static int UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE)(
62 	struct uverbs_attr_bundle *attrs)
63 {
64 	struct ib_ucq_object *obj = container_of(
65 		uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_CQ_HANDLE),
66 		typeof(*obj), uevent.uobject);
67 	struct ib_uverbs_completion_event_file *ev_file = NULL;
68 	struct ib_device *ib_dev = attrs->context->device;
69 	struct ib_umem_dmabuf *umem_dmabuf;
70 	struct ib_cq_init_attr attr = {};
71 	struct ib_uobject *ev_file_uobj;
72 	struct ib_umem *umem = NULL;
73 	u64 buffer_length;
74 	u64 buffer_offset;
75 	struct ib_cq *cq;
76 	u64 user_handle;
77 	u64 buffer_va;
78 	int buffer_fd;
79 	int ret;
80 
81 	if ((!ib_dev->ops.create_cq && !ib_dev->ops.create_cq_umem) || !ib_dev->ops.destroy_cq)
82 		return -EOPNOTSUPP;
83 
84 	ret = uverbs_copy_from(&attr.comp_vector, attrs,
85 			       UVERBS_ATTR_CREATE_CQ_COMP_VECTOR);
86 	if (!ret)
87 		ret = uverbs_copy_from(&attr.cqe, attrs,
88 				       UVERBS_ATTR_CREATE_CQ_CQE);
89 	if (!ret)
90 		ret = uverbs_copy_from(&user_handle, attrs,
91 				       UVERBS_ATTR_CREATE_CQ_USER_HANDLE);
92 	if (ret)
93 		return ret;
94 
95 	ret = uverbs_get_flags32(&attr.flags, attrs,
96 				 UVERBS_ATTR_CREATE_CQ_FLAGS,
97 				 IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION |
98 					 IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN);
99 	if (ret)
100 		return ret;
101 
102 	ev_file_uobj = uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_CQ_COMP_CHANNEL);
103 	if (!IS_ERR(ev_file_uobj)) {
104 		ev_file = container_of(ev_file_uobj,
105 				       struct ib_uverbs_completion_event_file,
106 				       uobj);
107 		uverbs_uobject_get(ev_file_uobj);
108 	}
109 
110 	obj->uevent.event_file = ib_uverbs_get_async_event(
111 		attrs, UVERBS_ATTR_CREATE_CQ_EVENT_FD);
112 
113 	if (attr.comp_vector >= attrs->ufile->device->num_comp_vectors) {
114 		ret = -EINVAL;
115 		goto err_event_file;
116 	}
117 
118 	INIT_LIST_HEAD(&obj->comp_list);
119 	INIT_LIST_HEAD(&obj->uevent.event_list);
120 
121 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_VA)) {
122 
123 		ret = uverbs_copy_from(&buffer_va, attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_VA);
124 		if (ret)
125 			goto err_event_file;
126 
127 		ret = uverbs_copy_from(&buffer_length, attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_LENGTH);
128 		if (ret)
129 			goto err_event_file;
130 
131 		if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_FD) ||
132 		    uverbs_attr_is_valid(attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_OFFSET) ||
133 		    !ib_dev->ops.create_cq_umem) {
134 			ret = -EINVAL;
135 			goto err_event_file;
136 		}
137 
138 		umem = ib_umem_get(ib_dev, buffer_va, buffer_length, IB_ACCESS_LOCAL_WRITE);
139 		if (IS_ERR(umem)) {
140 			ret = PTR_ERR(umem);
141 			goto err_event_file;
142 		}
143 	} else if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_FD)) {
144 
145 		ret = uverbs_get_raw_fd(&buffer_fd, attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_FD);
146 		if (ret)
147 			goto err_event_file;
148 
149 		ret = uverbs_copy_from(&buffer_offset, attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_OFFSET);
150 		if (ret)
151 			goto err_event_file;
152 
153 		ret = uverbs_copy_from(&buffer_length, attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_LENGTH);
154 		if (ret)
155 			goto err_event_file;
156 
157 		if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_VA) ||
158 		    !ib_dev->ops.create_cq_umem) {
159 			ret = -EINVAL;
160 			goto err_event_file;
161 		}
162 
163 		umem_dmabuf = ib_umem_dmabuf_get_pinned(ib_dev, buffer_offset, buffer_length,
164 							buffer_fd, IB_ACCESS_LOCAL_WRITE);
165 		if (IS_ERR(umem_dmabuf)) {
166 			ret = PTR_ERR(umem_dmabuf);
167 			goto err_event_file;
168 		}
169 		umem = &umem_dmabuf->umem;
170 	} else if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_OFFSET) ||
171 		   uverbs_attr_is_valid(attrs, UVERBS_ATTR_CREATE_CQ_BUFFER_LENGTH) ||
172 		   !ib_dev->ops.create_cq) {
173 		ret = -EINVAL;
174 		goto err_event_file;
175 	}
176 
177 	cq = rdma_zalloc_drv_obj(ib_dev, ib_cq);
178 	if (!cq) {
179 		ret = -ENOMEM;
180 		ib_umem_release(umem);
181 		goto err_event_file;
182 	}
183 
184 	cq->device        = ib_dev;
185 	cq->uobject       = obj;
186 	cq->comp_handler  = ib_uverbs_comp_handler;
187 	cq->event_handler = ib_uverbs_cq_event_handler;
188 	cq->cq_context    = ev_file ? &ev_file->ev_queue : NULL;
189 	atomic_set(&cq->usecnt, 0);
190 
191 	rdma_restrack_new(&cq->res, RDMA_RESTRACK_CQ);
192 	rdma_restrack_set_name(&cq->res, NULL);
193 
194 	ret = umem ? ib_dev->ops.create_cq_umem(cq, &attr, umem, attrs) :
195 		ib_dev->ops.create_cq(cq, &attr, attrs);
196 	if (ret)
197 		goto err_free;
198 
199 	obj->uevent.uobject.object = cq;
200 	obj->uevent.uobject.user_handle = user_handle;
201 	rdma_restrack_add(&cq->res);
202 	uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_CQ_HANDLE);
203 
204 	ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_CQ_RESP_CQE, &cq->cqe,
205 			     sizeof(cq->cqe));
206 	return ret;
207 
208 err_free:
209 	rdma_restrack_put(&cq->res);
210 	kfree(cq);
211 err_event_file:
212 	if (obj->uevent.event_file)
213 		uverbs_uobject_put(&obj->uevent.event_file->uobj);
214 	if (ev_file)
215 		uverbs_uobject_put(ev_file_uobj);
216 	return ret;
217 };
218 
219 DECLARE_UVERBS_NAMED_METHOD(
220 	UVERBS_METHOD_CQ_CREATE,
221 	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_CQ_HANDLE,
222 			UVERBS_OBJECT_CQ,
223 			UVERBS_ACCESS_NEW,
224 			UA_MANDATORY),
225 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_CQ_CQE,
226 			   UVERBS_ATTR_TYPE(u32),
227 			   UA_MANDATORY),
228 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_CQ_USER_HANDLE,
229 			   UVERBS_ATTR_TYPE(u64),
230 			   UA_MANDATORY),
231 	UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_CQ_COMP_CHANNEL,
232 		       UVERBS_OBJECT_COMP_CHANNEL,
233 		       UVERBS_ACCESS_READ,
234 		       UA_OPTIONAL),
235 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_CQ_COMP_VECTOR,
236 			   UVERBS_ATTR_TYPE(u32),
237 			   UA_MANDATORY),
238 	UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_CREATE_CQ_FLAGS,
239 			     enum ib_uverbs_ex_create_cq_flags),
240 	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_CQ_RESP_CQE,
241 			    UVERBS_ATTR_TYPE(u32),
242 			    UA_MANDATORY),
243 	UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_CQ_EVENT_FD,
244 		       UVERBS_OBJECT_ASYNC_EVENT,
245 		       UVERBS_ACCESS_READ,
246 		       UA_OPTIONAL),
247 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_CQ_BUFFER_VA,
248 			   UVERBS_ATTR_TYPE(u64),
249 			   UA_OPTIONAL),
250 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_CQ_BUFFER_LENGTH,
251 			   UVERBS_ATTR_TYPE(u64),
252 			   UA_OPTIONAL),
253 	UVERBS_ATTR_RAW_FD(UVERBS_ATTR_CREATE_CQ_BUFFER_FD,
254 			   UA_OPTIONAL),
255 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_CQ_BUFFER_OFFSET,
256 			   UVERBS_ATTR_TYPE(u64),
257 			   UA_OPTIONAL),
258 	UVERBS_ATTR_UHW());
259 
UVERBS_HANDLER(UVERBS_METHOD_CQ_DESTROY)260 static int UVERBS_HANDLER(UVERBS_METHOD_CQ_DESTROY)(
261 	struct uverbs_attr_bundle *attrs)
262 {
263 	struct ib_uobject *uobj =
264 		uverbs_attr_get_uobject(attrs, UVERBS_ATTR_DESTROY_CQ_HANDLE);
265 	struct ib_ucq_object *obj =
266 		container_of(uobj, struct ib_ucq_object, uevent.uobject);
267 	struct ib_uverbs_destroy_cq_resp resp = {
268 		.comp_events_reported = obj->comp_events_reported,
269 		.async_events_reported = obj->uevent.events_reported
270 	};
271 
272 	return uverbs_copy_to(attrs, UVERBS_ATTR_DESTROY_CQ_RESP, &resp,
273 			      sizeof(resp));
274 }
275 
276 DECLARE_UVERBS_NAMED_METHOD(
277 	UVERBS_METHOD_CQ_DESTROY,
278 	UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_CQ_HANDLE,
279 			UVERBS_OBJECT_CQ,
280 			UVERBS_ACCESS_DESTROY,
281 			UA_MANDATORY),
282 	UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_DESTROY_CQ_RESP,
283 			    UVERBS_ATTR_TYPE(struct ib_uverbs_destroy_cq_resp),
284 			    UA_MANDATORY));
285 
286 DECLARE_UVERBS_NAMED_OBJECT(
287 	UVERBS_OBJECT_CQ,
288 	UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_ucq_object), uverbs_free_cq),
289 	&UVERBS_METHOD(UVERBS_METHOD_CQ_CREATE),
290 	&UVERBS_METHOD(UVERBS_METHOD_CQ_DESTROY)
291 );
292 
293 const struct uapi_definition uverbs_def_obj_cq[] = {
294 	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_CQ,
295 				      UAPI_DEF_OBJ_NEEDS_FN(destroy_cq)),
296 	{}
297 };
298