#include <rdma/uverbs_std_types.h>
#include "rdma_core.h"
#include "uverbs.h"
#include "core_priv.h"
static int uverbs_free_qp(struct ib_uobject *uobject,
enum rdma_remove_reason why,
struct uverbs_attr_bundle *attrs)
{ … }
static int check_creation_flags(enum ib_qp_type qp_type,
u32 create_flags)
{ … }
static void set_caps(struct ib_qp_init_attr *attr,
struct ib_uverbs_qp_cap *cap, bool req)
{ … }
static int UVERBS_HANDLER(UVERBS_METHOD_QP_CREATE)(
struct uverbs_attr_bundle *attrs)
{
struct ib_uqp_object *obj = container_of(
uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_QP_HANDLE),
typeof(*obj), uevent.uobject);
struct ib_qp_init_attr attr = {};
struct ib_uverbs_qp_cap cap = {};
struct ib_rwq_ind_table *rwq_ind_tbl = NULL;
struct ib_qp *qp;
struct ib_pd *pd = NULL;
struct ib_srq *srq = NULL;
struct ib_cq *recv_cq = NULL;
struct ib_cq *send_cq = NULL;
struct ib_xrcd *xrcd = NULL;
struct ib_uobject *xrcd_uobj = NULL;
struct ib_device *device;
u64 user_handle;
int ret;
ret = uverbs_copy_from_or_zero(&cap, attrs,
UVERBS_ATTR_CREATE_QP_CAP);
if (!ret)
ret = uverbs_copy_from(&user_handle, attrs,
UVERBS_ATTR_CREATE_QP_USER_HANDLE);
if (!ret)
ret = uverbs_get_const(&attr.qp_type, attrs,
UVERBS_ATTR_CREATE_QP_TYPE);
if (ret)
return ret;
switch (attr.qp_type) {
case IB_QPT_XRC_TGT:
if (uverbs_attr_is_valid(attrs,
UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE) ||
uverbs_attr_is_valid(attrs,
UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE) ||
uverbs_attr_is_valid(attrs,
UVERBS_ATTR_CREATE_QP_PD_HANDLE) ||
uverbs_attr_is_valid(attrs,
UVERBS_ATTR_CREATE_QP_IND_TABLE_HANDLE))
return -EINVAL;
xrcd_uobj = uverbs_attr_get_uobject(attrs,
UVERBS_ATTR_CREATE_QP_XRCD_HANDLE);
if (IS_ERR(xrcd_uobj))
return PTR_ERR(xrcd_uobj);
xrcd = (struct ib_xrcd *)xrcd_uobj->object;
if (!xrcd)
return -EINVAL;
device = xrcd->device;
break;
case IB_UVERBS_QPT_RAW_PACKET:
if (!capable(CAP_NET_RAW))
return -EPERM;
fallthrough;
case IB_UVERBS_QPT_RC:
case IB_UVERBS_QPT_UC:
case IB_UVERBS_QPT_UD:
case IB_UVERBS_QPT_XRC_INI:
case IB_UVERBS_QPT_DRIVER:
if (uverbs_attr_is_valid(attrs,
UVERBS_ATTR_CREATE_QP_XRCD_HANDLE) ||
(uverbs_attr_is_valid(attrs,
UVERBS_ATTR_CREATE_QP_SRQ_HANDLE) &&
attr.qp_type == IB_QPT_XRC_INI))
return -EINVAL;
pd = uverbs_attr_get_obj(attrs,
UVERBS_ATTR_CREATE_QP_PD_HANDLE);
if (IS_ERR(pd))
return PTR_ERR(pd);
rwq_ind_tbl = uverbs_attr_get_obj(attrs,
UVERBS_ATTR_CREATE_QP_IND_TABLE_HANDLE);
if (!IS_ERR(rwq_ind_tbl)) {
if (cap.max_recv_wr || cap.max_recv_sge ||
uverbs_attr_is_valid(attrs,
UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE) ||
uverbs_attr_is_valid(attrs,
UVERBS_ATTR_CREATE_QP_SRQ_HANDLE))
return -EINVAL;
if (cap.max_send_wr) {
send_cq = uverbs_attr_get_obj(attrs,
UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE);
if (IS_ERR(send_cq))
return PTR_ERR(send_cq);
}
attr.rwq_ind_tbl = rwq_ind_tbl;
} else {
send_cq = uverbs_attr_get_obj(attrs,
UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE);
if (IS_ERR(send_cq))
return PTR_ERR(send_cq);
if (attr.qp_type != IB_QPT_XRC_INI) {
recv_cq = uverbs_attr_get_obj(attrs,
UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE);
if (IS_ERR(recv_cq))
return PTR_ERR(recv_cq);
}
}
device = pd->device;
break;
default:
return -EINVAL;
}
ret = uverbs_get_flags32(&attr.create_flags, attrs,
UVERBS_ATTR_CREATE_QP_FLAGS,
IB_UVERBS_QP_CREATE_BLOCK_MULTICAST_LOOPBACK |
IB_UVERBS_QP_CREATE_SCATTER_FCS |
IB_UVERBS_QP_CREATE_CVLAN_STRIPPING |
IB_UVERBS_QP_CREATE_PCI_WRITE_END_PADDING |
IB_UVERBS_QP_CREATE_SQ_SIG_ALL);
if (ret)
return ret;
ret = check_creation_flags(attr.qp_type, attr.create_flags);
if (ret)
return ret;
if (uverbs_attr_is_valid(attrs,
UVERBS_ATTR_CREATE_QP_SOURCE_QPN)) {
ret = uverbs_copy_from(&attr.source_qpn, attrs,
UVERBS_ATTR_CREATE_QP_SOURCE_QPN);
if (ret)
return ret;
attr.create_flags |= IB_QP_CREATE_SOURCE_QPN;
}
srq = uverbs_attr_get_obj(attrs,
UVERBS_ATTR_CREATE_QP_SRQ_HANDLE);
if (!IS_ERR(srq)) {
if ((srq->srq_type == IB_SRQT_XRC &&
attr.qp_type != IB_QPT_XRC_TGT) ||
(srq->srq_type != IB_SRQT_XRC &&
attr.qp_type == IB_QPT_XRC_TGT))
return -EINVAL;
attr.srq = srq;
}
obj->uevent.event_file = ib_uverbs_get_async_event(attrs,
UVERBS_ATTR_CREATE_QP_EVENT_FD);
INIT_LIST_HEAD(&obj->uevent.event_list);
INIT_LIST_HEAD(&obj->mcast_list);
obj->uevent.uobject.user_handle = user_handle;
attr.event_handler = ib_uverbs_qp_event_handler;
attr.send_cq = send_cq;
attr.recv_cq = recv_cq;
attr.xrcd = xrcd;
if (attr.create_flags & IB_UVERBS_QP_CREATE_SQ_SIG_ALL) {
attr.create_flags &= ~IB_UVERBS_QP_CREATE_SQ_SIG_ALL;
attr.sq_sig_type = IB_SIGNAL_ALL_WR;
} else {
attr.sq_sig_type = IB_SIGNAL_REQ_WR;
}
set_caps(&attr, &cap, true);
mutex_init(&obj->mcast_lock);
qp = ib_create_qp_user(device, pd, &attr, &attrs->driver_udata, obj,
KBUILD_MODNAME);
if (IS_ERR(qp)) {
ret = PTR_ERR(qp);
goto err_put;
}
ib_qp_usecnt_inc(qp);
if (attr.qp_type == IB_QPT_XRC_TGT) {
obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
uobject);
atomic_inc(&obj->uxrcd->refcnt);
}
obj->uevent.uobject.object = qp;
uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_QP_HANDLE);
set_caps(&attr, &cap, false);
ret = uverbs_copy_to_struct_or_zero(attrs,
UVERBS_ATTR_CREATE_QP_RESP_CAP, &cap,
sizeof(cap));
if (ret)
return ret;
ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_QP_RESP_QP_NUM,
&qp->qp_num,
sizeof(qp->qp_num));
return ret;
err_put:
if (obj->uevent.event_file)
uverbs_uobject_put(&obj->uevent.event_file->uobj);
return ret;
};
DECLARE_UVERBS_NAMED_METHOD(…);
static int UVERBS_HANDLER(UVERBS_METHOD_QP_DESTROY)(
struct uverbs_attr_bundle *attrs)
{ … }
DECLARE_UVERBS_NAMED_METHOD(…);
DECLARE_UVERBS_NAMED_OBJECT(…);
const struct uapi_definition uverbs_def_obj_qp[] = …;