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