// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB /* * Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. */ #include #include "rdma_core.h" #include "uverbs.h" static int uverbs_free_wq(struct ib_uobject *uobject, enum rdma_remove_reason why, struct uverbs_attr_bundle *attrs) { struct ib_wq *wq = uobject->object; struct ib_uwq_object *uwq = container_of(uobject, struct ib_uwq_object, uevent.uobject); int ret; ret = ib_destroy_wq_user(wq, &attrs->driver_udata); if (ret) return ret; ib_uverbs_release_uevent(&uwq->uevent); return 0; } static int UVERBS_HANDLER(UVERBS_METHOD_WQ_CREATE)( struct uverbs_attr_bundle *attrs) { struct ib_uwq_object *obj = container_of( uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_WQ_HANDLE), typeof(*obj), uevent.uobject); struct ib_pd *pd = uverbs_attr_get_obj(attrs, UVERBS_ATTR_CREATE_WQ_PD_HANDLE); struct ib_cq *cq = uverbs_attr_get_obj(attrs, UVERBS_ATTR_CREATE_WQ_CQ_HANDLE); struct ib_wq_init_attr wq_init_attr = {}; struct ib_wq *wq; u64 user_handle; int ret; ret = uverbs_get_flags32(&wq_init_attr.create_flags, attrs, UVERBS_ATTR_CREATE_WQ_FLAGS, IB_UVERBS_WQ_FLAGS_CVLAN_STRIPPING | IB_UVERBS_WQ_FLAGS_SCATTER_FCS | IB_UVERBS_WQ_FLAGS_DELAY_DROP | IB_UVERBS_WQ_FLAGS_PCI_WRITE_END_PADDING); if (!ret) ret = uverbs_copy_from(&wq_init_attr.max_sge, attrs, UVERBS_ATTR_CREATE_WQ_MAX_SGE); if (!ret) ret = uverbs_copy_from(&wq_init_attr.max_wr, attrs, UVERBS_ATTR_CREATE_WQ_MAX_WR); if (!ret) ret = uverbs_copy_from(&user_handle, attrs, UVERBS_ATTR_CREATE_WQ_USER_HANDLE); if (!ret) ret = uverbs_get_const(&wq_init_attr.wq_type, attrs, UVERBS_ATTR_CREATE_WQ_TYPE); if (ret) return ret; if (wq_init_attr.wq_type != IB_WQT_RQ) return -EINVAL; obj->uevent.event_file = ib_uverbs_get_async_event(attrs, UVERBS_ATTR_CREATE_WQ_EVENT_FD); obj->uevent.uobject.user_handle = user_handle; INIT_LIST_HEAD(&obj->uevent.event_list); wq_init_attr.event_handler = ib_uverbs_wq_event_handler; wq_init_attr.wq_context = attrs->ufile; wq_init_attr.cq = cq; wq = pd->device->ops.create_wq(pd, &wq_init_attr, &attrs->driver_udata); if (IS_ERR(wq)) { ret = PTR_ERR(wq); goto err; } obj->uevent.uobject.object = wq; wq->wq_type = wq_init_attr.wq_type; wq->cq = cq; wq->pd = pd; wq->device = pd->device; wq->wq_context = wq_init_attr.wq_context; atomic_set(&wq->usecnt, 0); atomic_inc(&pd->usecnt); atomic_inc(&cq->usecnt); wq->uobject = obj; uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_WQ_HANDLE); ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_WQ_RESP_MAX_WR, &wq_init_attr.max_wr, sizeof(wq_init_attr.max_wr)); if (ret) return ret; ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_WQ_RESP_MAX_SGE, &wq_init_attr.max_sge, sizeof(wq_init_attr.max_sge)); if (ret) return ret; ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_WQ_RESP_WQ_NUM, &wq->wq_num, sizeof(wq->wq_num)); return ret; err: if (obj->uevent.event_file) uverbs_uobject_put(&obj->uevent.event_file->uobj); return ret; }; DECLARE_UVERBS_NAMED_METHOD( UVERBS_METHOD_WQ_CREATE, UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_WQ_HANDLE, UVERBS_OBJECT_WQ, UVERBS_ACCESS_NEW, UA_MANDATORY), UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_WQ_PD_HANDLE, UVERBS_OBJECT_PD, UVERBS_ACCESS_READ, UA_MANDATORY), UVERBS_ATTR_CONST_IN(UVERBS_ATTR_CREATE_WQ_TYPE, enum ib_wq_type, UA_MANDATORY), UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_WQ_USER_HANDLE, UVERBS_ATTR_TYPE(u64), UA_MANDATORY), UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_WQ_MAX_WR, UVERBS_ATTR_TYPE(u32), UA_MANDATORY), UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_WQ_MAX_SGE, UVERBS_ATTR_TYPE(u32), UA_MANDATORY), UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_CREATE_WQ_FLAGS, enum ib_uverbs_wq_flags, UA_MANDATORY), UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_WQ_CQ_HANDLE, UVERBS_OBJECT_CQ, UVERBS_ACCESS_READ, UA_OPTIONAL), UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_WQ_EVENT_FD, UVERBS_OBJECT_ASYNC_EVENT, UVERBS_ACCESS_READ, UA_OPTIONAL), UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_WQ_RESP_MAX_WR, UVERBS_ATTR_TYPE(u32), UA_MANDATORY), UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_WQ_RESP_MAX_SGE, UVERBS_ATTR_TYPE(u32), UA_MANDATORY), UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_WQ_RESP_WQ_NUM, UVERBS_ATTR_TYPE(u32), UA_OPTIONAL), UVERBS_ATTR_UHW()); static int UVERBS_HANDLER(UVERBS_METHOD_WQ_DESTROY)( struct uverbs_attr_bundle *attrs) { struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, UVERBS_ATTR_DESTROY_WQ_HANDLE); struct ib_uwq_object *obj = container_of(uobj, struct ib_uwq_object, uevent.uobject); return uverbs_copy_to(attrs, UVERBS_ATTR_DESTROY_WQ_RESP, &obj->uevent.events_reported, sizeof(obj->uevent.events_reported)); } DECLARE_UVERBS_NAMED_METHOD( UVERBS_METHOD_WQ_DESTROY, UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_WQ_HANDLE, UVERBS_OBJECT_WQ, UVERBS_ACCESS_DESTROY, UA_MANDATORY), UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_DESTROY_WQ_RESP, UVERBS_ATTR_TYPE(u32), UA_MANDATORY)); DECLARE_UVERBS_NAMED_OBJECT( UVERBS_OBJECT_WQ, UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uwq_object), uverbs_free_wq), &UVERBS_METHOD(UVERBS_METHOD_WQ_CREATE), &UVERBS_METHOD(UVERBS_METHOD_WQ_DESTROY) ); const struct uapi_definition uverbs_def_obj_wq[] = { UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_WQ, UAPI_DEF_OBJ_NEEDS_FN(destroy_wq)), {} };