// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* * Copyright (c) 2025, Broadcom. All rights reserved. The term * Broadcom refers to Broadcom Limited and/or its subsidiaries. * * Description: uapi interpreter */ #include #include #include #include #define UVERBS_MODULE_NAME bnxt_re #include #include #include "roce_hsi.h" #include "qplib_res.h" #include "qplib_sp.h" #include "qplib_fp.h" #include "qplib_rcfw.h" #include "bnxt_re.h" #include "ib_verbs.h" static struct bnxt_re_cq *bnxt_re_search_for_cq(struct bnxt_re_dev *rdev, u32 cq_id) { struct bnxt_re_cq *cq = NULL, *tmp_cq; hash_for_each_possible(rdev->cq_hash, tmp_cq, hash_entry, cq_id) { if (tmp_cq->qplib_cq.id == cq_id) { cq = tmp_cq; break; } } return cq; } static struct bnxt_re_srq *bnxt_re_search_for_srq(struct bnxt_re_dev *rdev, u32 srq_id) { struct bnxt_re_srq *srq = NULL, *tmp_srq; hash_for_each_possible(rdev->srq_hash, tmp_srq, hash_entry, srq_id) { if (tmp_srq->qplib_srq.id == srq_id) { srq = tmp_srq; break; } } return srq; } static int UVERBS_HANDLER(BNXT_RE_METHOD_NOTIFY_DRV)(struct uverbs_attr_bundle *attrs) { struct bnxt_re_ucontext *uctx; struct ib_ucontext *ib_uctx; ib_uctx = ib_uverbs_get_ucontext(attrs); if (IS_ERR(ib_uctx)) return PTR_ERR(ib_uctx); uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx); if (IS_ERR(uctx)) return PTR_ERR(uctx); bnxt_re_pacing_alert(uctx->rdev); return 0; } static int UVERBS_HANDLER(BNXT_RE_METHOD_ALLOC_PAGE)(struct uverbs_attr_bundle *attrs) { struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_ALLOC_PAGE_HANDLE); enum bnxt_re_alloc_page_type alloc_type; struct bnxt_re_user_mmap_entry *entry; enum bnxt_re_mmap_flag mmap_flag; struct bnxt_qplib_chip_ctx *cctx; struct bnxt_re_ucontext *uctx; struct ib_ucontext *ib_uctx; struct bnxt_re_dev *rdev; u64 mmap_offset; u32 length; u32 dpi; u64 addr; int err; ib_uctx = ib_uverbs_get_ucontext(attrs); if (IS_ERR(ib_uctx)) return PTR_ERR(ib_uctx); uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx); if (IS_ERR(uctx)) return PTR_ERR(uctx); err = uverbs_get_const(&alloc_type, attrs, BNXT_RE_ALLOC_PAGE_TYPE); if (err) return err; rdev = uctx->rdev; cctx = rdev->chip_ctx; switch (alloc_type) { case BNXT_RE_ALLOC_WC_PAGE: if (cctx->modes.db_push) { if (bnxt_qplib_alloc_dpi(&rdev->qplib_res, &uctx->wcdpi, uctx, BNXT_QPLIB_DPI_TYPE_WC)) return -ENOMEM; length = PAGE_SIZE; dpi = uctx->wcdpi.dpi; addr = (u64)uctx->wcdpi.umdbr; mmap_flag = BNXT_RE_MMAP_WC_DB; } else { return -EINVAL; } break; case BNXT_RE_ALLOC_DBR_BAR_PAGE: length = PAGE_SIZE; addr = (u64)rdev->pacing.dbr_bar_addr; mmap_flag = BNXT_RE_MMAP_DBR_BAR; break; case BNXT_RE_ALLOC_DBR_PAGE: length = PAGE_SIZE; addr = (u64)rdev->pacing.dbr_page; mmap_flag = BNXT_RE_MMAP_DBR_PAGE; break; default: return -EOPNOTSUPP; } entry = bnxt_re_mmap_entry_insert(uctx, addr, mmap_flag, &mmap_offset); if (!entry) return -ENOMEM; uobj->object = entry; uverbs_finalize_uobj_create(attrs, BNXT_RE_ALLOC_PAGE_HANDLE); err = uverbs_copy_to(attrs, BNXT_RE_ALLOC_PAGE_MMAP_OFFSET, &mmap_offset, sizeof(mmap_offset)); if (err) return err; err = uverbs_copy_to(attrs, BNXT_RE_ALLOC_PAGE_MMAP_LENGTH, &length, sizeof(length)); if (err) return err; err = uverbs_copy_to(attrs, BNXT_RE_ALLOC_PAGE_DPI, &dpi, sizeof(dpi)); if (err) return err; return 0; } static int alloc_page_obj_cleanup(struct ib_uobject *uobject, enum rdma_remove_reason why, struct uverbs_attr_bundle *attrs) { struct bnxt_re_user_mmap_entry *entry = uobject->object; struct bnxt_re_ucontext *uctx = entry->uctx; switch (entry->mmap_flag) { case BNXT_RE_MMAP_WC_DB: if (uctx && uctx->wcdpi.dbr) { struct bnxt_re_dev *rdev = uctx->rdev; bnxt_qplib_dealloc_dpi(&rdev->qplib_res, &uctx->wcdpi); uctx->wcdpi.dbr = NULL; } break; case BNXT_RE_MMAP_DBR_BAR: case BNXT_RE_MMAP_DBR_PAGE: break; default: goto exit; } rdma_user_mmap_entry_remove(&entry->rdma_entry); exit: return 0; } DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_ALLOC_PAGE, UVERBS_ATTR_IDR(BNXT_RE_ALLOC_PAGE_HANDLE, BNXT_RE_OBJECT_ALLOC_PAGE, UVERBS_ACCESS_NEW, UA_MANDATORY), UVERBS_ATTR_CONST_IN(BNXT_RE_ALLOC_PAGE_TYPE, enum bnxt_re_alloc_page_type, UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_PAGE_MMAP_OFFSET, UVERBS_ATTR_TYPE(u64), UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_PAGE_MMAP_LENGTH, UVERBS_ATTR_TYPE(u32), UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_PAGE_DPI, UVERBS_ATTR_TYPE(u32), UA_MANDATORY)); DECLARE_UVERBS_NAMED_METHOD_DESTROY(BNXT_RE_METHOD_DESTROY_PAGE, UVERBS_ATTR_IDR(BNXT_RE_DESTROY_PAGE_HANDLE, BNXT_RE_OBJECT_ALLOC_PAGE, UVERBS_ACCESS_DESTROY, UA_MANDATORY)); DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_ALLOC_PAGE, UVERBS_TYPE_ALLOC_IDR(alloc_page_obj_cleanup), &UVERBS_METHOD(BNXT_RE_METHOD_ALLOC_PAGE), &UVERBS_METHOD(BNXT_RE_METHOD_DESTROY_PAGE)); DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_NOTIFY_DRV); DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_NOTIFY_DRV, &UVERBS_METHOD(BNXT_RE_METHOD_NOTIFY_DRV)); /* Toggle MEM */ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bundle *attrs) { struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_TOGGLE_MEM_HANDLE); enum bnxt_re_mmap_flag mmap_flag = BNXT_RE_MMAP_TOGGLE_PAGE; enum bnxt_re_get_toggle_mem_type res_type; struct bnxt_re_user_mmap_entry *entry; struct bnxt_re_ucontext *uctx; struct ib_ucontext *ib_uctx; struct bnxt_re_dev *rdev; struct bnxt_re_srq *srq; u32 length = PAGE_SIZE; struct bnxt_re_cq *cq; u64 mem_offset; u32 offset = 0; u64 addr = 0; u32 res_id; int err; ib_uctx = ib_uverbs_get_ucontext(attrs); if (IS_ERR(ib_uctx)) return PTR_ERR(ib_uctx); err = uverbs_get_const(&res_type, attrs, BNXT_RE_TOGGLE_MEM_TYPE); if (err) return err; uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx); rdev = uctx->rdev; err = uverbs_copy_from(&res_id, attrs, BNXT_RE_TOGGLE_MEM_RES_ID); if (err) return err; switch (res_type) { case BNXT_RE_CQ_TOGGLE_MEM: cq = bnxt_re_search_for_cq(rdev, res_id); if (!cq) return -EINVAL; addr = (u64)cq->uctx_cq_page; break; case BNXT_RE_SRQ_TOGGLE_MEM: srq = bnxt_re_search_for_srq(rdev, res_id); if (!srq) return -EINVAL; addr = (u64)srq->uctx_srq_page; break; default: return -EOPNOTSUPP; } entry = bnxt_re_mmap_entry_insert(uctx, addr, mmap_flag, &mem_offset); if (!entry) return -ENOMEM; uobj->object = entry; uverbs_finalize_uobj_create(attrs, BNXT_RE_TOGGLE_MEM_HANDLE); err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_PAGE, &mem_offset, sizeof(mem_offset)); if (err) return err; err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_LENGTH, &length, sizeof(length)); if (err) return err; err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_OFFSET, &offset, sizeof(offset)); if (err) return err; return 0; } static int get_toggle_mem_obj_cleanup(struct ib_uobject *uobject, enum rdma_remove_reason why, struct uverbs_attr_bundle *attrs) { struct bnxt_re_user_mmap_entry *entry = uobject->object; rdma_user_mmap_entry_remove(&entry->rdma_entry); return 0; } DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_GET_TOGGLE_MEM, UVERBS_ATTR_IDR(BNXT_RE_TOGGLE_MEM_HANDLE, BNXT_RE_OBJECT_GET_TOGGLE_MEM, UVERBS_ACCESS_NEW, UA_MANDATORY), UVERBS_ATTR_CONST_IN(BNXT_RE_TOGGLE_MEM_TYPE, enum bnxt_re_get_toggle_mem_type, UA_MANDATORY), UVERBS_ATTR_PTR_IN(BNXT_RE_TOGGLE_MEM_RES_ID, UVERBS_ATTR_TYPE(u32), UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_TOGGLE_MEM_MMAP_PAGE, UVERBS_ATTR_TYPE(u64), UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_TOGGLE_MEM_MMAP_OFFSET, UVERBS_ATTR_TYPE(u32), UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_TOGGLE_MEM_MMAP_LENGTH, UVERBS_ATTR_TYPE(u32), UA_MANDATORY)); DECLARE_UVERBS_NAMED_METHOD_DESTROY(BNXT_RE_METHOD_RELEASE_TOGGLE_MEM, UVERBS_ATTR_IDR(BNXT_RE_RELEASE_TOGGLE_MEM_HANDLE, BNXT_RE_OBJECT_GET_TOGGLE_MEM, UVERBS_ACCESS_DESTROY, UA_MANDATORY)); DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_GET_TOGGLE_MEM, UVERBS_TYPE_ALLOC_IDR(get_toggle_mem_obj_cleanup), &UVERBS_METHOD(BNXT_RE_METHOD_GET_TOGGLE_MEM), &UVERBS_METHOD(BNXT_RE_METHOD_RELEASE_TOGGLE_MEM)); static int UVERBS_HANDLER(BNXT_RE_METHOD_DBR_ALLOC)(struct uverbs_attr_bundle *attrs) { struct bnxt_re_db_region dbr = {}; struct bnxt_re_ucontext *uctx; struct bnxt_re_dbr_obj *obj; struct ib_ucontext *ib_uctx; struct bnxt_qplib_dpi *dpi; struct bnxt_re_dev *rdev; struct ib_uobject *uobj; u64 mmap_offset; int ret; ib_uctx = ib_uverbs_get_ucontext(attrs); if (IS_ERR(ib_uctx)) return PTR_ERR(ib_uctx); uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx); rdev = uctx->rdev; uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_ALLOC_DBR_HANDLE); obj = kzalloc_obj(*obj); if (!obj) return -ENOMEM; dpi = &obj->dpi; ret = bnxt_qplib_alloc_uc_dpi(&rdev->qplib_res, dpi); if (ret) goto free_mem; obj->entry = bnxt_re_mmap_entry_insert(uctx, dpi->umdbr, BNXT_RE_MMAP_UC_DB, &mmap_offset); if (!obj->entry) { ret = -ENOMEM; goto free_dpi; } obj->rdev = rdev; uobj->object = obj; uverbs_finalize_uobj_create(attrs, BNXT_RE_ALLOC_DBR_HANDLE); dbr.umdbr = dpi->umdbr; dbr.dpi = dpi->dpi; ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_ALLOC_DBR_ATTR, &dbr, sizeof(dbr)); if (ret) return ret; ret = uverbs_copy_to(attrs, BNXT_RE_ALLOC_DBR_OFFSET, &mmap_offset, sizeof(mmap_offset)); if (ret) return ret; return 0; free_dpi: bnxt_qplib_free_uc_dpi(&rdev->qplib_res, dpi); free_mem: kfree(obj); return ret; } static int bnxt_re_dbr_cleanup(struct ib_uobject *uobject, enum rdma_remove_reason why, struct uverbs_attr_bundle *attrs) { struct bnxt_re_dbr_obj *obj = uobject->object; struct bnxt_re_dev *rdev = obj->rdev; rdma_user_mmap_entry_remove(&obj->entry->rdma_entry); bnxt_qplib_free_uc_dpi(&rdev->qplib_res, &obj->dpi); return 0; } static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_DEFAULT_DBR)(struct uverbs_attr_bundle *attrs) { struct bnxt_re_db_region dpi = {}; struct bnxt_re_ucontext *uctx; struct ib_ucontext *ib_uctx; int ret; ib_uctx = ib_uverbs_get_ucontext(attrs); if (IS_ERR(ib_uctx)) return PTR_ERR(ib_uctx); uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx); dpi.umdbr = uctx->dpi.umdbr; dpi.dpi = uctx->dpi.dpi; ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_DEFAULT_DBR_ATTR, &dpi, sizeof(dpi)); if (ret) return ret; return 0; } DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_DBR_ALLOC, UVERBS_ATTR_IDR(BNXT_RE_ALLOC_DBR_HANDLE, BNXT_RE_OBJECT_DBR, UVERBS_ACCESS_NEW, UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_ATTR, UVERBS_ATTR_STRUCT(struct bnxt_re_db_region, umdbr), UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_OFFSET, UVERBS_ATTR_TYPE(u64), UA_MANDATORY)); DECLARE_UVERBS_NAMED_METHOD_DESTROY(BNXT_RE_METHOD_DBR_FREE, UVERBS_ATTR_IDR(BNXT_RE_FREE_DBR_HANDLE, BNXT_RE_OBJECT_DBR, UVERBS_ACCESS_DESTROY, UA_MANDATORY)); DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_DBR, UVERBS_TYPE_ALLOC_IDR(bnxt_re_dbr_cleanup), &UVERBS_METHOD(BNXT_RE_METHOD_DBR_ALLOC), &UVERBS_METHOD(BNXT_RE_METHOD_DBR_FREE)); DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_GET_DEFAULT_DBR, UVERBS_ATTR_PTR_OUT(BNXT_RE_DEFAULT_DBR_ATTR, UVERBS_ATTR_STRUCT(struct bnxt_re_db_region, umdbr), UA_MANDATORY)); DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_DEFAULT_DBR, &UVERBS_METHOD(BNXT_RE_METHOD_GET_DEFAULT_DBR)); const struct uapi_definition bnxt_re_uapi_defs[] = { UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_ALLOC_PAGE), UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_NOTIFY_DRV), UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_GET_TOGGLE_MEM), UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_DBR), UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_DEFAULT_DBR), {} };