1 // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
2 /*
3 * Copyright (c) 2025, Broadcom. All rights reserved. The term
4 * Broadcom refers to Broadcom Limited and/or its subsidiaries.
5 *
6 * Description: uapi interpreter
7 */
8
9 #include <rdma/ib_addr.h>
10 #include <rdma/uverbs_types.h>
11 #include <rdma/uverbs_std_types.h>
12 #include <rdma/ib_user_ioctl_cmds.h>
13 #define UVERBS_MODULE_NAME bnxt_re
14 #include <rdma/uverbs_named_ioctl.h>
15 #include <rdma/bnxt_re-abi.h>
16
17 #include "roce_hsi.h"
18 #include "qplib_res.h"
19 #include "qplib_sp.h"
20 #include "qplib_fp.h"
21 #include "qplib_rcfw.h"
22 #include "bnxt_re.h"
23 #include "ib_verbs.h"
24
25
UVERBS_HANDLER(BNXT_RE_METHOD_NOTIFY_DRV)26 static int UVERBS_HANDLER(BNXT_RE_METHOD_NOTIFY_DRV)(struct uverbs_attr_bundle *attrs)
27 {
28 struct bnxt_re_ucontext *uctx;
29 struct ib_ucontext *ib_uctx;
30
31 ib_uctx = ib_uverbs_get_ucontext(attrs);
32 if (IS_ERR(ib_uctx))
33 return PTR_ERR(ib_uctx);
34
35 uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
36 if (IS_ERR(uctx))
37 return PTR_ERR(uctx);
38
39 bnxt_re_pacing_alert(uctx->rdev);
40 return 0;
41 }
42
UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)43 static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *attrs)
44 {
45 struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_ALLOC_PAGE_HANDLE);
46 enum bnxt_re_alloc_page_type alloc_type;
47 struct bnxt_re_user_mmap_entry *entry;
48 enum bnxt_re_mmap_flag mmap_flag;
49 struct bnxt_qplib_chip_ctx *cctx;
50 struct bnxt_re_ucontext *uctx;
51 struct ib_ucontext *ib_uctx;
52 struct bnxt_re_dev *rdev;
53 u64 mmap_offset;
54 u32 dpi = 0;
55 u32 length;
56 u64 addr;
57 int err;
58
59 ib_uctx = ib_uverbs_get_ucontext(attrs);
60 if (IS_ERR(ib_uctx))
61 return PTR_ERR(ib_uctx);
62
63 uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
64 if (IS_ERR(uctx))
65 return PTR_ERR(uctx);
66
67 err = uverbs_get_const(&alloc_type, attrs, BNXT_RE_ALLOC_PAGE_TYPE);
68 if (err)
69 return err;
70
71 rdev = uctx->rdev;
72 cctx = rdev->chip_ctx;
73
74 switch (alloc_type) {
75 case BNXT_RE_ALLOC_WC_PAGE:
76 if (cctx->modes.db_push) {
77 mutex_lock(&uctx->wcdpi_lock);
78 /* already allocated — one WC page per context */
79 if (uctx->wcdpi.dbr) {
80 mutex_unlock(&uctx->wcdpi_lock);
81 return -EEXIST;
82 }
83 if (bnxt_qplib_alloc_dpi(&rdev->qplib_res, &uctx->wcdpi,
84 uctx, BNXT_QPLIB_DPI_TYPE_WC)) {
85 mutex_unlock(&uctx->wcdpi_lock);
86 return -ENOMEM;
87 }
88 length = PAGE_SIZE;
89 dpi = uctx->wcdpi.dpi;
90 addr = (u64)uctx->wcdpi.umdbr;
91 mmap_flag = BNXT_RE_MMAP_WC_DB;
92 mutex_unlock(&uctx->wcdpi_lock);
93 } else {
94 return -EINVAL;
95 }
96
97 break;
98 case BNXT_RE_ALLOC_DBR_BAR_PAGE:
99 if (!rdev->pacing.dbr_pacing)
100 return -EOPNOTSUPP;
101 length = PAGE_SIZE;
102 addr = (u64)rdev->pacing.dbr_bar_addr;
103 mmap_flag = BNXT_RE_MMAP_DBR_BAR;
104 break;
105
106 case BNXT_RE_ALLOC_DBR_PAGE:
107 if (!rdev->pacing.dbr_pacing)
108 return -EOPNOTSUPP;
109 length = PAGE_SIZE;
110 addr = (u64)rdev->pacing.dbr_page;
111 mmap_flag = BNXT_RE_MMAP_DBR_PAGE;
112 break;
113
114 default:
115 return -EOPNOTSUPP;
116 }
117
118 entry = bnxt_re_mmap_entry_insert(uctx, addr, mmap_flag, &mmap_offset);
119 if (!entry) {
120 if (mmap_flag == BNXT_RE_MMAP_WC_DB) {
121 mutex_lock(&uctx->wcdpi_lock);
122 bnxt_qplib_dealloc_dpi(&rdev->qplib_res, &uctx->wcdpi);
123 uctx->wcdpi.dbr = NULL;
124 mutex_unlock(&uctx->wcdpi_lock);
125 }
126 return -ENOMEM;
127 }
128
129 uobj->object = entry;
130 uverbs_finalize_uobj_create(attrs, BNXT_RE_ALLOC_PAGE_HANDLE);
131 err = uverbs_copy_to(attrs, BNXT_RE_ALLOC_PAGE_MMAP_OFFSET,
132 &mmap_offset, sizeof(mmap_offset));
133 if (err)
134 return err;
135
136 err = uverbs_copy_to(attrs, BNXT_RE_ALLOC_PAGE_MMAP_LENGTH,
137 &length, sizeof(length));
138 if (err)
139 return err;
140
141 err = uverbs_copy_to(attrs, BNXT_RE_ALLOC_PAGE_DPI,
142 &dpi, sizeof(dpi));
143 if (err)
144 return err;
145
146 return 0;
147 }
148
alloc_page_obj_cleanup(struct ib_uobject * uobject,enum rdma_remove_reason why,struct uverbs_attr_bundle * attrs)149 static int alloc_page_obj_cleanup(struct ib_uobject *uobject,
150 enum rdma_remove_reason why,
151 struct uverbs_attr_bundle *attrs)
152 {
153 struct bnxt_re_user_mmap_entry *entry = uobject->object;
154 struct bnxt_re_ucontext *uctx = entry->uctx;
155
156 switch (entry->mmap_flag) {
157 case BNXT_RE_MMAP_WC_DB:
158 if (uctx) {
159 struct bnxt_re_dev *rdev = uctx->rdev;
160
161 mutex_lock(&uctx->wcdpi_lock);
162 if (uctx->wcdpi.dbr) {
163 bnxt_qplib_dealloc_dpi(&rdev->qplib_res,
164 &uctx->wcdpi);
165 uctx->wcdpi.dbr = NULL;
166 }
167 mutex_unlock(&uctx->wcdpi_lock);
168 }
169 break;
170 case BNXT_RE_MMAP_DBR_BAR:
171 case BNXT_RE_MMAP_DBR_PAGE:
172 break;
173 default:
174 goto exit;
175 }
176 rdma_user_mmap_entry_remove(&entry->rdma_entry);
177 exit:
178 return 0;
179 }
180
181 DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_ALLOC_PAGE,
182 UVERBS_ATTR_IDR(BNXT_RE_ALLOC_PAGE_HANDLE,
183 BNXT_RE_OBJECT_ALLOC_PAGE,
184 UVERBS_ACCESS_NEW,
185 UA_MANDATORY),
186 UVERBS_ATTR_CONST_IN(BNXT_RE_ALLOC_PAGE_TYPE,
187 enum bnxt_re_alloc_page_type,
188 UA_MANDATORY),
189 UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_PAGE_MMAP_OFFSET,
190 UVERBS_ATTR_TYPE(u64),
191 UA_MANDATORY),
192 UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_PAGE_MMAP_LENGTH,
193 UVERBS_ATTR_TYPE(u32),
194 UA_MANDATORY),
195 UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_PAGE_DPI,
196 UVERBS_ATTR_TYPE(u32),
197 UA_MANDATORY));
198
199 DECLARE_UVERBS_NAMED_METHOD_DESTROY(BNXT_RE_METHOD_DESTROY_PAGE,
200 UVERBS_ATTR_IDR(BNXT_RE_DESTROY_PAGE_HANDLE,
201 BNXT_RE_OBJECT_ALLOC_PAGE,
202 UVERBS_ACCESS_DESTROY,
203 UA_MANDATORY));
204
205 DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_ALLOC_PAGE,
206 UVERBS_TYPE_ALLOC_IDR(alloc_page_obj_cleanup),
207 &UVERBS_METHOD(BNXT_RE_METHOD_ALLOC_PAGE),
208 &UVERBS_METHOD(BNXT_RE_METHOD_DESTROY_PAGE));
209
210 DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_NOTIFY_DRV);
211
212 DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_NOTIFY_DRV,
213 &UVERBS_METHOD(BNXT_RE_METHOD_NOTIFY_DRV));
214
215 /* Toggle MEM */
216 struct bnxt_re_toggle_mem {
217 struct bnxt_re_user_mmap_entry *toggle_entry;
218 u64 mmap_offset;
219 };
220
UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)221 static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bundle *attrs)
222 {
223 struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_TOGGLE_MEM_HANDLE);
224 struct bnxt_re_user_mmap_entry *toggle_entry = NULL;
225 enum bnxt_re_get_toggle_mem_type res_type;
226 struct bnxt_re_toggle_mem *tmem;
227 struct ib_uobject *res_uobj;
228 struct bnxt_re_ucontext *uctx;
229 struct ib_ucontext *ib_uctx;
230 u32 length = PAGE_SIZE;
231 u64 mmap_offset = 0;
232 u32 offset = 0;
233 u32 res_id;
234 int err;
235
236 ib_uctx = ib_uverbs_get_ucontext(attrs);
237 if (IS_ERR(ib_uctx))
238 return PTR_ERR(ib_uctx);
239
240 uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
241
242 /* New path: updated libbnxt_re passes the CQ or SRQ uverbs handle */
243 if (uverbs_attr_is_valid(attrs, BNXT_RE_TOGGLE_MEM_CQ_HANDLE)) {
244 struct bnxt_re_cq *cq;
245
246 res_uobj = uverbs_attr_get_uobject(attrs,
247 BNXT_RE_TOGGLE_MEM_CQ_HANDLE);
248 if (IS_ERR(res_uobj))
249 return PTR_ERR(res_uobj);
250 cq = container_of(res_uobj->object, struct bnxt_re_cq, ib_cq);
251 if (!cq->toggle_entry)
252 return -EOPNOTSUPP;
253 mmap_offset = rdma_user_mmap_get_offset(&cq->toggle_entry->rdma_entry);
254 if (!mmap_offset)
255 return -EOPNOTSUPP;
256 kref_get(&cq->toggle_entry->rdma_entry.ref);
257 toggle_entry = cq->toggle_entry;
258 goto alloc_tmem;
259 } else if (uverbs_attr_is_valid(attrs, BNXT_RE_TOGGLE_MEM_SRQ_HANDLE)) {
260 struct bnxt_re_srq *srq;
261
262 res_uobj = uverbs_attr_get_uobject(attrs,
263 BNXT_RE_TOGGLE_MEM_SRQ_HANDLE);
264 if (IS_ERR(res_uobj))
265 return PTR_ERR(res_uobj);
266 srq = container_of(res_uobj->object, struct bnxt_re_srq, ib_srq);
267 if (!srq->toggle_entry)
268 return -EOPNOTSUPP;
269 mmap_offset = rdma_user_mmap_get_offset(&srq->toggle_entry->rdma_entry);
270 if (!mmap_offset)
271 return -EOPNOTSUPP;
272 kref_get(&srq->toggle_entry->rdma_entry.ref);
273 toggle_entry = srq->toggle_entry;
274 goto alloc_tmem;
275 }
276
277 err = uverbs_get_const(&res_type, attrs, BNXT_RE_TOGGLE_MEM_TYPE);
278 if (err)
279 return err;
280 err = uverbs_copy_from(&res_id, attrs, BNXT_RE_TOGGLE_MEM_RES_ID);
281 if (err)
282 return err;
283
284 /*
285 * Legacy path: old libbnxt_re sends TYPE + RES_ID.
286 * Hold xa_lock across xa_load + kref_get so that a concurrent
287 * bnxt_re_destroy_cq/srq cannot call __xa_erase and remove the
288 * toggle_entry between our load and our reference on it.
289 *
290 * bnxt_re_create_cq/srq() publishes the uobject into cq_xa/srq_xa
291 * before returning to the uverbs core, but the core only sets
292 * uobject->object once the create callback has returned success.
293 * A lookup that races with an in-progress create can therefore
294 * find a uobject whose ->object is still NULL; skip it instead of
295 * feeding NULL to container_of().
296 */
297 if (res_type == BNXT_RE_CQ_TOGGLE_MEM) {
298 struct bnxt_re_cq *cq;
299
300 xa_lock(&uctx->cq_xa);
301 res_uobj = xa_load(&uctx->cq_xa, res_id);
302 if (res_uobj && res_uobj->object) {
303 cq = container_of(res_uobj->object, struct bnxt_re_cq, ib_cq);
304 if (cq->toggle_entry)
305 mmap_offset =
306 rdma_user_mmap_get_offset(&cq->toggle_entry->rdma_entry);
307 if (mmap_offset) {
308 kref_get(&cq->toggle_entry->rdma_entry.ref);
309 toggle_entry = cq->toggle_entry;
310 }
311 }
312 xa_unlock(&uctx->cq_xa);
313 } else if (res_type == BNXT_RE_SRQ_TOGGLE_MEM) {
314 struct bnxt_re_srq *srq;
315
316 xa_lock(&uctx->srq_xa);
317 res_uobj = xa_load(&uctx->srq_xa, res_id);
318 if (res_uobj && res_uobj->object) {
319 srq = container_of(res_uobj->object, struct bnxt_re_srq, ib_srq);
320 if (srq->toggle_entry)
321 mmap_offset =
322 rdma_user_mmap_get_offset(&srq->toggle_entry->rdma_entry);
323 if (mmap_offset) {
324 kref_get(&srq->toggle_entry->rdma_entry.ref);
325 toggle_entry = srq->toggle_entry;
326 }
327 }
328 xa_unlock(&uctx->srq_xa);
329 } else {
330 return -EOPNOTSUPP;
331 }
332
333 if (!mmap_offset)
334 return -EOPNOTSUPP;
335
336 alloc_tmem:
337 tmem = kzalloc_obj(*tmem);
338 if (!tmem) {
339 rdma_user_mmap_entry_put(&toggle_entry->rdma_entry);
340 return -ENOMEM;
341 }
342
343 tmem->toggle_entry = toggle_entry;
344 tmem->mmap_offset = mmap_offset;
345 uobj->object = tmem;
346 uverbs_finalize_uobj_create(attrs, BNXT_RE_TOGGLE_MEM_HANDLE);
347 err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_PAGE,
348 &mmap_offset, sizeof(mmap_offset));
349 if (err)
350 return err;
351
352 err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_LENGTH,
353 &length, sizeof(length));
354 if (err)
355 return err;
356
357 err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_OFFSET,
358 &offset, sizeof(offset));
359 if (err)
360 return err;
361
362 return 0;
363 }
364
get_toggle_mem_obj_cleanup(struct ib_uobject * uobject,enum rdma_remove_reason why,struct uverbs_attr_bundle * attrs)365 static int get_toggle_mem_obj_cleanup(struct ib_uobject *uobject,
366 enum rdma_remove_reason why,
367 struct uverbs_attr_bundle *attrs)
368 {
369 struct bnxt_re_toggle_mem *tmem = uobject->object;
370
371 rdma_user_mmap_entry_put(&tmem->toggle_entry->rdma_entry);
372 kfree(tmem);
373 return 0;
374 }
375
376 DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_GET_TOGGLE_MEM,
377 UVERBS_ATTR_IDR(BNXT_RE_TOGGLE_MEM_HANDLE,
378 BNXT_RE_OBJECT_GET_TOGGLE_MEM,
379 UVERBS_ACCESS_NEW,
380 UA_MANDATORY),
381 UVERBS_ATTR_CONST_IN(BNXT_RE_TOGGLE_MEM_TYPE,
382 enum bnxt_re_get_toggle_mem_type,
383 UA_OPTIONAL),
384 UVERBS_ATTR_PTR_IN(BNXT_RE_TOGGLE_MEM_RES_ID,
385 UVERBS_ATTR_TYPE(u32),
386 UA_OPTIONAL),
387 UVERBS_ATTR_PTR_OUT(BNXT_RE_TOGGLE_MEM_MMAP_PAGE,
388 UVERBS_ATTR_TYPE(u64),
389 UA_MANDATORY),
390 UVERBS_ATTR_PTR_OUT(BNXT_RE_TOGGLE_MEM_MMAP_OFFSET,
391 UVERBS_ATTR_TYPE(u32),
392 UA_MANDATORY),
393 UVERBS_ATTR_PTR_OUT(BNXT_RE_TOGGLE_MEM_MMAP_LENGTH,
394 UVERBS_ATTR_TYPE(u32),
395 UA_MANDATORY),
396 UVERBS_ATTR_IDR(BNXT_RE_TOGGLE_MEM_CQ_HANDLE,
397 UVERBS_OBJECT_CQ,
398 UVERBS_ACCESS_READ,
399 UA_OPTIONAL),
400 UVERBS_ATTR_IDR(BNXT_RE_TOGGLE_MEM_SRQ_HANDLE,
401 UVERBS_OBJECT_SRQ,
402 UVERBS_ACCESS_READ,
403 UA_OPTIONAL));
404
405 DECLARE_UVERBS_NAMED_METHOD_DESTROY(BNXT_RE_METHOD_RELEASE_TOGGLE_MEM,
406 UVERBS_ATTR_IDR(BNXT_RE_RELEASE_TOGGLE_MEM_HANDLE,
407 BNXT_RE_OBJECT_GET_TOGGLE_MEM,
408 UVERBS_ACCESS_DESTROY,
409 UA_MANDATORY));
410
411 DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_GET_TOGGLE_MEM,
412 UVERBS_TYPE_ALLOC_IDR(get_toggle_mem_obj_cleanup),
413 &UVERBS_METHOD(BNXT_RE_METHOD_GET_TOGGLE_MEM),
414 &UVERBS_METHOD(BNXT_RE_METHOD_RELEASE_TOGGLE_MEM));
415
UVERBS_HANDLER(BNXT_RE_METHOD_DBR_ALLOC)416 static int UVERBS_HANDLER(BNXT_RE_METHOD_DBR_ALLOC)(struct uverbs_attr_bundle *attrs)
417 {
418 struct bnxt_re_db_region dbr = {};
419 struct bnxt_re_ucontext *uctx;
420 struct bnxt_re_dbr_obj *obj;
421 struct ib_ucontext *ib_uctx;
422 struct bnxt_qplib_dpi *dpi;
423 struct bnxt_re_dev *rdev;
424 struct ib_uobject *uobj;
425 u64 mmap_offset;
426 int ret;
427
428 ib_uctx = ib_uverbs_get_ucontext(attrs);
429 if (IS_ERR(ib_uctx))
430 return PTR_ERR(ib_uctx);
431
432 uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
433 rdev = uctx->rdev;
434 uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_ALLOC_DBR_HANDLE);
435
436 obj = kzalloc_obj(*obj);
437 if (!obj)
438 return -ENOMEM;
439
440 dpi = &obj->dpi;
441 ret = bnxt_qplib_alloc_uc_dpi(&rdev->qplib_res, dpi);
442 if (ret)
443 goto free_mem;
444
445 obj->entry = bnxt_re_mmap_entry_insert(uctx, dpi->umdbr,
446 BNXT_RE_MMAP_UC_DB,
447 &mmap_offset);
448 if (!obj->entry) {
449 ret = -ENOMEM;
450 goto free_dpi;
451 }
452
453 /* Save DPI info to the mmap entry so that bnxt_re_mmap_free()
454 * can free the DPI slot only after the last reference to the
455 * mmap entry is released.
456 */
457 obj->entry->dpi = *dpi;
458 obj->entry->dpi_valid = true;
459
460 obj->rdev = rdev;
461 kref_init(&obj->usecnt);
462 uobj->object = obj;
463 uverbs_finalize_uobj_create(attrs, BNXT_RE_ALLOC_DBR_HANDLE);
464
465 dbr.dpi = dpi->dpi;
466 ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_ALLOC_DBR_ATTR,
467 &dbr, sizeof(dbr));
468 if (ret)
469 return ret;
470
471 ret = uverbs_copy_to(attrs, BNXT_RE_ALLOC_DBR_OFFSET,
472 &mmap_offset, sizeof(mmap_offset));
473 if (ret)
474 return ret;
475 return 0;
476 free_dpi:
477 bnxt_qplib_free_uc_dpi(&rdev->qplib_res, dpi);
478 free_mem:
479 kfree(obj);
480 return ret;
481 }
482
bnxt_re_dbr_kref_release(struct kref * ref)483 void bnxt_re_dbr_kref_release(struct kref *ref)
484 {
485 struct bnxt_re_dbr_obj *obj =
486 container_of(ref, struct bnxt_re_dbr_obj, usecnt);
487
488 /* Drop the driver's reference to the mmap entry (_remove()).
489 * The DPI slot gets freed from bnxt_re_mmap_free() only
490 * when there's no VMA mapping reference to it.
491 */
492 rdma_user_mmap_entry_remove(&obj->entry->rdma_entry);
493 kfree(obj);
494 }
495
bnxt_re_dbr_cleanup(struct ib_uobject * uobject,enum rdma_remove_reason why,struct uverbs_attr_bundle * attrs)496 static int bnxt_re_dbr_cleanup(struct ib_uobject *uobject,
497 enum rdma_remove_reason why,
498 struct uverbs_attr_bundle *attrs)
499 {
500 struct bnxt_re_dbr_obj *obj = uobject->object;
501
502 /* If it is being destroyed explicitly while QPs still hold a
503 * reference (> 1), reject it with EBUSY. If no QP references
504 * or implicit teardown (process exit, driver removal), drop
505 * the uobject reference unconditionally. The object gets freed
506 * (bnxt_re_dbr_kref_release) when the usecnt goes to zero.
507 */
508 if (why == RDMA_REMOVE_DESTROY && kref_read(&obj->usecnt) > 1)
509 return -EBUSY;
510
511 kref_put(&obj->usecnt, bnxt_re_dbr_kref_release);
512 return 0;
513 }
514
UVERBS_HANDLER(BNXT_RE_METHOD_GET_DEFAULT_DBR)515 static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_DEFAULT_DBR)(struct uverbs_attr_bundle *attrs)
516 {
517 struct bnxt_re_db_region dpi = {};
518 struct bnxt_re_ucontext *uctx;
519 struct ib_ucontext *ib_uctx;
520 int ret;
521
522 ib_uctx = ib_uverbs_get_ucontext(attrs);
523 if (IS_ERR(ib_uctx))
524 return PTR_ERR(ib_uctx);
525
526 uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
527 dpi.dpi = uctx->dpi.dpi;
528
529 ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_DEFAULT_DBR_ATTR,
530 &dpi, sizeof(dpi));
531 if (ret)
532 return ret;
533
534 return 0;
535 }
536
537 DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_DBR_ALLOC,
538 UVERBS_ATTR_IDR(BNXT_RE_ALLOC_DBR_HANDLE,
539 BNXT_RE_OBJECT_DBR,
540 UVERBS_ACCESS_NEW,
541 UA_MANDATORY),
542 UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_ATTR,
543 UVERBS_ATTR_STRUCT(struct bnxt_re_db_region,
544 reserved2),
545 UA_MANDATORY),
546 UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_OFFSET,
547 UVERBS_ATTR_TYPE(u64),
548 UA_MANDATORY));
549
550 DECLARE_UVERBS_NAMED_METHOD_DESTROY(BNXT_RE_METHOD_DBR_FREE,
551 UVERBS_ATTR_IDR(BNXT_RE_FREE_DBR_HANDLE,
552 BNXT_RE_OBJECT_DBR,
553 UVERBS_ACCESS_DESTROY,
554 UA_MANDATORY));
555
556 DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_DBR,
557 UVERBS_TYPE_ALLOC_IDR(bnxt_re_dbr_cleanup),
558 &UVERBS_METHOD(BNXT_RE_METHOD_DBR_ALLOC),
559 &UVERBS_METHOD(BNXT_RE_METHOD_DBR_FREE));
560
561 DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_GET_DEFAULT_DBR,
562 UVERBS_ATTR_PTR_OUT(BNXT_RE_DEFAULT_DBR_ATTR,
563 UVERBS_ATTR_STRUCT(struct bnxt_re_db_region,
564 reserved2),
565 UA_MANDATORY));
566
567 DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_DEFAULT_DBR,
568 &UVERBS_METHOD(BNXT_RE_METHOD_GET_DEFAULT_DBR));
569
570 ADD_UVERBS_ATTRIBUTES_SIMPLE(
571 bnxt_re_qp_create,
572 UVERBS_OBJECT_QP,
573 UVERBS_METHOD_QP_CREATE,
574 UVERBS_ATTR_IDR(BNXT_RE_CREATE_QP_ATTR_DBR_HANDLE,
575 BNXT_RE_OBJECT_DBR,
576 UVERBS_ACCESS_READ,
577 UA_OPTIONAL));
578
579 const struct uapi_definition bnxt_re_create_qp_defs[] = {
580 UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_QP, &bnxt_re_qp_create),
581 {},
582 };
583
584 const struct uapi_definition bnxt_re_uapi_defs[] = {
585 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_ALLOC_PAGE),
586 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_NOTIFY_DRV),
587 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_GET_TOGGLE_MEM),
588 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_DBR),
589 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_DEFAULT_DBR),
590 UAPI_DEF_CHAIN(bnxt_re_create_qp_defs),
591 {}
592 };
593