xref: /linux/drivers/infiniband/hw/bnxt_re/uapi.c (revision 01414b70cb6f7a5911b65de0cc97225061f60a59)
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