| // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
| /* |
| * Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. |
| */ |
| |
| #include <rdma/uverbs_std_types.h> |
| #include "rdma_core.h" |
| #include "uverbs.h" |
| |
| static int uverbs_free_srq(struct ib_uobject *uobject, |
| enum rdma_remove_reason why, |
| struct uverbs_attr_bundle *attrs) |
| { |
| struct ib_srq *srq = uobject->object; |
| struct ib_uevent_object *uevent = |
| container_of(uobject, struct ib_uevent_object, uobject); |
| enum ib_srq_type srq_type = srq->srq_type; |
| int ret; |
| |
| ret = ib_destroy_srq_user(srq, &attrs->driver_udata); |
| if (ret) |
| return ret; |
| |
| if (srq_type == IB_SRQT_XRC) { |
| struct ib_usrq_object *us = |
| container_of(uobject, struct ib_usrq_object, |
| uevent.uobject); |
| |
| atomic_dec(&us->uxrcd->refcnt); |
| } |
| |
| ib_uverbs_release_uevent(uevent); |
| return 0; |
| } |
| |
| static int UVERBS_HANDLER(UVERBS_METHOD_SRQ_CREATE)( |
| struct uverbs_attr_bundle *attrs) |
| { |
| struct ib_usrq_object *obj = container_of( |
| uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_SRQ_HANDLE), |
| typeof(*obj), uevent.uobject); |
| struct ib_pd *pd = |
| uverbs_attr_get_obj(attrs, UVERBS_ATTR_CREATE_SRQ_PD_HANDLE); |
| struct ib_srq_init_attr attr = {}; |
| struct ib_uobject *xrcd_uobj; |
| struct ib_srq *srq; |
| u64 user_handle; |
| int ret; |
| |
| ret = uverbs_copy_from(&attr.attr.max_sge, attrs, |
| UVERBS_ATTR_CREATE_SRQ_MAX_SGE); |
| if (!ret) |
| ret = uverbs_copy_from(&attr.attr.max_wr, attrs, |
| UVERBS_ATTR_CREATE_SRQ_MAX_WR); |
| if (!ret) |
| ret = uverbs_copy_from(&attr.attr.srq_limit, attrs, |
| UVERBS_ATTR_CREATE_SRQ_LIMIT); |
| if (!ret) |
| ret = uverbs_copy_from(&user_handle, attrs, |
| UVERBS_ATTR_CREATE_SRQ_USER_HANDLE); |
| if (!ret) |
| ret = uverbs_get_const(&attr.srq_type, attrs, |
| UVERBS_ATTR_CREATE_SRQ_TYPE); |
| if (ret) |
| return ret; |
| |
| if (ib_srq_has_cq(attr.srq_type)) { |
| attr.ext.cq = uverbs_attr_get_obj(attrs, |
| UVERBS_ATTR_CREATE_SRQ_CQ_HANDLE); |
| if (IS_ERR(attr.ext.cq)) |
| return PTR_ERR(attr.ext.cq); |
| } |
| |
| switch (attr.srq_type) { |
| case IB_UVERBS_SRQT_XRC: |
| xrcd_uobj = uverbs_attr_get_uobject(attrs, |
| UVERBS_ATTR_CREATE_SRQ_XRCD_HANDLE); |
| if (IS_ERR(xrcd_uobj)) |
| return PTR_ERR(xrcd_uobj); |
| |
| attr.ext.xrc.xrcd = (struct ib_xrcd *)xrcd_uobj->object; |
| if (!attr.ext.xrc.xrcd) |
| return -EINVAL; |
| obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object, |
| uobject); |
| atomic_inc(&obj->uxrcd->refcnt); |
| break; |
| case IB_UVERBS_SRQT_TM: |
| ret = uverbs_copy_from(&attr.ext.tag_matching.max_num_tags, |
| attrs, |
| UVERBS_ATTR_CREATE_SRQ_MAX_NUM_TAGS); |
| if (ret) |
| return ret; |
| break; |
| case IB_UVERBS_SRQT_BASIC: |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| obj->uevent.event_file = ib_uverbs_get_async_event(attrs, |
| UVERBS_ATTR_CREATE_SRQ_EVENT_FD); |
| INIT_LIST_HEAD(&obj->uevent.event_list); |
| attr.event_handler = ib_uverbs_srq_event_handler; |
| obj->uevent.uobject.user_handle = user_handle; |
| |
| srq = ib_create_srq_user(pd, &attr, obj, &attrs->driver_udata); |
| if (IS_ERR(srq)) { |
| ret = PTR_ERR(srq); |
| goto err; |
| } |
| |
| obj->uevent.uobject.object = srq; |
| uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_SRQ_HANDLE); |
| |
| ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_SRQ_RESP_MAX_WR, |
| &attr.attr.max_wr, |
| sizeof(attr.attr.max_wr)); |
| if (ret) |
| return ret; |
| |
| ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_SRQ_RESP_MAX_SGE, |
| &attr.attr.max_sge, |
| sizeof(attr.attr.max_sge)); |
| if (ret) |
| return ret; |
| |
| if (attr.srq_type == IB_SRQT_XRC) { |
| ret = uverbs_copy_to(attrs, |
| UVERBS_ATTR_CREATE_SRQ_RESP_SRQ_NUM, |
| &srq->ext.xrc.srq_num, |
| sizeof(srq->ext.xrc.srq_num)); |
| if (ret) |
| return ret; |
| } |
| |
| return 0; |
| err: |
| if (obj->uevent.event_file) |
| uverbs_uobject_put(&obj->uevent.event_file->uobj); |
| if (attr.srq_type == IB_SRQT_XRC) |
| atomic_dec(&obj->uxrcd->refcnt); |
| return ret; |
| }; |
| |
| DECLARE_UVERBS_NAMED_METHOD( |
| UVERBS_METHOD_SRQ_CREATE, |
| UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_SRQ_HANDLE, |
| UVERBS_OBJECT_SRQ, |
| UVERBS_ACCESS_NEW, |
| UA_MANDATORY), |
| UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_SRQ_PD_HANDLE, |
| UVERBS_OBJECT_PD, |
| UVERBS_ACCESS_READ, |
| UA_MANDATORY), |
| UVERBS_ATTR_CONST_IN(UVERBS_ATTR_CREATE_SRQ_TYPE, |
| enum ib_uverbs_srq_type, |
| UA_MANDATORY), |
| UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_USER_HANDLE, |
| UVERBS_ATTR_TYPE(u64), |
| UA_MANDATORY), |
| UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_MAX_WR, |
| UVERBS_ATTR_TYPE(u32), |
| UA_MANDATORY), |
| UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_MAX_SGE, |
| UVERBS_ATTR_TYPE(u32), |
| UA_MANDATORY), |
| UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_LIMIT, |
| UVERBS_ATTR_TYPE(u32), |
| UA_MANDATORY), |
| UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_SRQ_XRCD_HANDLE, |
| UVERBS_OBJECT_XRCD, |
| UVERBS_ACCESS_READ, |
| UA_OPTIONAL), |
| UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_SRQ_CQ_HANDLE, |
| UVERBS_OBJECT_CQ, |
| UVERBS_ACCESS_READ, |
| UA_OPTIONAL), |
| UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_SRQ_MAX_NUM_TAGS, |
| UVERBS_ATTR_TYPE(u32), |
| UA_OPTIONAL), |
| UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_SRQ_EVENT_FD, |
| UVERBS_OBJECT_ASYNC_EVENT, |
| UVERBS_ACCESS_READ, |
| UA_OPTIONAL), |
| UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_SRQ_RESP_MAX_WR, |
| UVERBS_ATTR_TYPE(u32), |
| UA_MANDATORY), |
| UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_SRQ_RESP_MAX_SGE, |
| UVERBS_ATTR_TYPE(u32), |
| UA_MANDATORY), |
| UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_SRQ_RESP_SRQ_NUM, |
| UVERBS_ATTR_TYPE(u32), |
| UA_OPTIONAL), |
| UVERBS_ATTR_UHW()); |
| |
| static int UVERBS_HANDLER(UVERBS_METHOD_SRQ_DESTROY)( |
| struct uverbs_attr_bundle *attrs) |
| { |
| struct ib_uobject *uobj = |
| uverbs_attr_get_uobject(attrs, UVERBS_ATTR_DESTROY_SRQ_HANDLE); |
| struct ib_usrq_object *obj = |
| container_of(uobj, struct ib_usrq_object, uevent.uobject); |
| struct ib_uverbs_destroy_srq_resp resp = { |
| .events_reported = obj->uevent.events_reported |
| }; |
| |
| return uverbs_copy_to(attrs, UVERBS_ATTR_DESTROY_SRQ_RESP, &resp, |
| sizeof(resp)); |
| } |
| |
| DECLARE_UVERBS_NAMED_METHOD( |
| UVERBS_METHOD_SRQ_DESTROY, |
| UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_SRQ_HANDLE, |
| UVERBS_OBJECT_SRQ, |
| UVERBS_ACCESS_DESTROY, |
| UA_MANDATORY), |
| UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_DESTROY_SRQ_RESP, |
| UVERBS_ATTR_TYPE(struct ib_uverbs_destroy_srq_resp), |
| UA_MANDATORY)); |
| |
| DECLARE_UVERBS_NAMED_OBJECT( |
| UVERBS_OBJECT_SRQ, |
| UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_usrq_object), |
| uverbs_free_srq), |
| &UVERBS_METHOD(UVERBS_METHOD_SRQ_CREATE), |
| &UVERBS_METHOD(UVERBS_METHOD_SRQ_DESTROY) |
| ); |
| |
| const struct uapi_definition uverbs_def_obj_srq[] = { |
| UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_SRQ, |
| UAPI_DEF_OBJ_NEEDS_FN(destroy_srq)), |
| {} |
| }; |