linux/drivers/infiniband/core/uverbs_std_types_qp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2/*
   3 * Copyright (c) 2020, Mellanox Technologies inc.  All rights reserved.
   4 */
   5
   6#include <rdma/uverbs_std_types.h>
   7#include "rdma_core.h"
   8#include "uverbs.h"
   9#include "core_priv.h"
  10
  11static int uverbs_free_qp(struct ib_uobject *uobject,
  12                          enum rdma_remove_reason why,
  13                          struct uverbs_attr_bundle *attrs)
  14{
  15        struct ib_qp *qp = uobject->object;
  16        struct ib_uqp_object *uqp =
  17                container_of(uobject, struct ib_uqp_object, uevent.uobject);
  18        int ret;
  19
  20        /*
  21         * If this is a user triggered destroy then do not allow destruction
  22         * until the user cleans up all the mcast bindings. Unlike in other
  23         * places we forcibly clean up the mcast attachments for !DESTROY
  24         * because the mcast attaches are not ubojects and will not be
  25         * destroyed by anything else during cleanup processing.
  26         */
  27        if (why == RDMA_REMOVE_DESTROY) {
  28                if (!list_empty(&uqp->mcast_list))
  29                        return -EBUSY;
  30        } else if (qp == qp->real_qp) {
  31                ib_uverbs_detach_umcast(qp, uqp);
  32        }
  33
  34        ret = ib_destroy_qp_user(qp, &attrs->driver_udata);
  35        if (ret)
  36                return ret;
  37
  38        if (uqp->uxrcd)
  39                atomic_dec(&uqp->uxrcd->refcnt);
  40
  41        ib_uverbs_release_uevent(&uqp->uevent);
  42        return 0;
  43}
  44
  45static int check_creation_flags(enum ib_qp_type qp_type,
  46                                u32 create_flags)
  47{
  48        create_flags &= ~IB_UVERBS_QP_CREATE_SQ_SIG_ALL;
  49
  50        if (!create_flags || qp_type == IB_QPT_DRIVER)
  51                return 0;
  52
  53        if (qp_type != IB_QPT_RAW_PACKET && qp_type != IB_QPT_UD)
  54                return -EINVAL;
  55
  56        if ((create_flags & IB_UVERBS_QP_CREATE_SCATTER_FCS ||
  57             create_flags & IB_UVERBS_QP_CREATE_CVLAN_STRIPPING) &&
  58             qp_type != IB_QPT_RAW_PACKET)
  59                return -EINVAL;
  60
  61        return 0;
  62}
  63
  64static void set_caps(struct ib_qp_init_attr *attr,
  65                     struct ib_uverbs_qp_cap *cap, bool req)
  66{
  67        if (req) {
  68                attr->cap.max_send_wr = cap->max_send_wr;
  69                attr->cap.max_recv_wr = cap->max_recv_wr;
  70                attr->cap.max_send_sge = cap->max_send_sge;
  71                attr->cap.max_recv_sge = cap->max_recv_sge;
  72                attr->cap.max_inline_data = cap->max_inline_data;
  73        } else {
  74                cap->max_send_wr = attr->cap.max_send_wr;
  75                cap->max_recv_wr = attr->cap.max_recv_wr;
  76                cap->max_send_sge = attr->cap.max_send_sge;
  77                cap->max_recv_sge = attr->cap.max_recv_sge;
  78                cap->max_inline_data = attr->cap.max_inline_data;
  79        }
  80}
  81
  82static int UVERBS_HANDLER(UVERBS_METHOD_QP_CREATE)(
  83        struct uverbs_attr_bundle *attrs)
  84{
  85        struct ib_uqp_object *obj = container_of(
  86                uverbs_attr_get_uobject(attrs, UVERBS_ATTR_CREATE_QP_HANDLE),
  87                typeof(*obj), uevent.uobject);
  88        struct ib_qp_init_attr attr = {};
  89        struct ib_uverbs_qp_cap cap = {};
  90        struct ib_rwq_ind_table *rwq_ind_tbl = NULL;
  91        struct ib_qp *qp;
  92        struct ib_pd *pd = NULL;
  93        struct ib_srq *srq = NULL;
  94        struct ib_cq *recv_cq = NULL;
  95        struct ib_cq *send_cq = NULL;
  96        struct ib_xrcd *xrcd = NULL;
  97        struct ib_uobject *xrcd_uobj = NULL;
  98        struct ib_device *device;
  99        u64 user_handle;
 100        int ret;
 101
 102        ret = uverbs_copy_from_or_zero(&cap, attrs,
 103                               UVERBS_ATTR_CREATE_QP_CAP);
 104        if (!ret)
 105                ret = uverbs_copy_from(&user_handle, attrs,
 106                                       UVERBS_ATTR_CREATE_QP_USER_HANDLE);
 107        if (!ret)
 108                ret = uverbs_get_const(&attr.qp_type, attrs,
 109                                       UVERBS_ATTR_CREATE_QP_TYPE);
 110        if (ret)
 111                return ret;
 112
 113        switch (attr.qp_type) {
 114        case IB_QPT_XRC_TGT:
 115                if (uverbs_attr_is_valid(attrs,
 116                                UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE) ||
 117                    uverbs_attr_is_valid(attrs,
 118                                UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE) ||
 119                    uverbs_attr_is_valid(attrs,
 120                                UVERBS_ATTR_CREATE_QP_PD_HANDLE) ||
 121                    uverbs_attr_is_valid(attrs,
 122                                UVERBS_ATTR_CREATE_QP_IND_TABLE_HANDLE))
 123                        return -EINVAL;
 124
 125                xrcd_uobj = uverbs_attr_get_uobject(attrs,
 126                                        UVERBS_ATTR_CREATE_QP_XRCD_HANDLE);
 127                if (IS_ERR(xrcd_uobj))
 128                        return PTR_ERR(xrcd_uobj);
 129
 130                xrcd = (struct ib_xrcd *)xrcd_uobj->object;
 131                if (!xrcd)
 132                        return -EINVAL;
 133                device = xrcd->device;
 134                break;
 135        case IB_UVERBS_QPT_RAW_PACKET:
 136                if (!capable(CAP_NET_RAW))
 137                        return -EPERM;
 138                fallthrough;
 139        case IB_UVERBS_QPT_RC:
 140        case IB_UVERBS_QPT_UC:
 141        case IB_UVERBS_QPT_UD:
 142        case IB_UVERBS_QPT_XRC_INI:
 143        case IB_UVERBS_QPT_DRIVER:
 144                if (uverbs_attr_is_valid(attrs,
 145                                         UVERBS_ATTR_CREATE_QP_XRCD_HANDLE) ||
 146                   (uverbs_attr_is_valid(attrs,
 147                                         UVERBS_ATTR_CREATE_QP_SRQ_HANDLE) &&
 148                        attr.qp_type == IB_QPT_XRC_INI))
 149                        return -EINVAL;
 150
 151                pd = uverbs_attr_get_obj(attrs,
 152                                         UVERBS_ATTR_CREATE_QP_PD_HANDLE);
 153                if (IS_ERR(pd))
 154                        return PTR_ERR(pd);
 155
 156                rwq_ind_tbl = uverbs_attr_get_obj(attrs,
 157                        UVERBS_ATTR_CREATE_QP_IND_TABLE_HANDLE);
 158                if (!IS_ERR(rwq_ind_tbl)) {
 159                        if (cap.max_recv_wr || cap.max_recv_sge ||
 160                            uverbs_attr_is_valid(attrs,
 161                                UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE) ||
 162                            uverbs_attr_is_valid(attrs,
 163                                        UVERBS_ATTR_CREATE_QP_SRQ_HANDLE))
 164                                return -EINVAL;
 165
 166                        /* send_cq is optinal */
 167                        if (cap.max_send_wr) {
 168                                send_cq = uverbs_attr_get_obj(attrs,
 169                                        UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE);
 170                                if (IS_ERR(send_cq))
 171                                        return PTR_ERR(send_cq);
 172                        }
 173                        attr.rwq_ind_tbl = rwq_ind_tbl;
 174                } else {
 175                        send_cq = uverbs_attr_get_obj(attrs,
 176                                        UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE);
 177                        if (IS_ERR(send_cq))
 178                                return PTR_ERR(send_cq);
 179
 180                        if (attr.qp_type != IB_QPT_XRC_INI) {
 181                                recv_cq = uverbs_attr_get_obj(attrs,
 182                                        UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE);
 183                                if (IS_ERR(recv_cq))
 184                                        return PTR_ERR(recv_cq);
 185                        }
 186                }
 187
 188                device = pd->device;
 189                break;
 190        default:
 191                return -EINVAL;
 192        }
 193
 194        ret = uverbs_get_flags32(&attr.create_flags, attrs,
 195                         UVERBS_ATTR_CREATE_QP_FLAGS,
 196                         IB_UVERBS_QP_CREATE_BLOCK_MULTICAST_LOOPBACK |
 197                         IB_UVERBS_QP_CREATE_SCATTER_FCS |
 198                         IB_UVERBS_QP_CREATE_CVLAN_STRIPPING |
 199                         IB_UVERBS_QP_CREATE_PCI_WRITE_END_PADDING |
 200                         IB_UVERBS_QP_CREATE_SQ_SIG_ALL);
 201        if (ret)
 202                return ret;
 203
 204        ret = check_creation_flags(attr.qp_type, attr.create_flags);
 205        if (ret)
 206                return ret;
 207
 208        if (uverbs_attr_is_valid(attrs,
 209                        UVERBS_ATTR_CREATE_QP_SOURCE_QPN)) {
 210                ret = uverbs_copy_from(&attr.source_qpn, attrs,
 211                                       UVERBS_ATTR_CREATE_QP_SOURCE_QPN);
 212                if (ret)
 213                        return ret;
 214                attr.create_flags |= IB_QP_CREATE_SOURCE_QPN;
 215        }
 216
 217        srq = uverbs_attr_get_obj(attrs,
 218                                  UVERBS_ATTR_CREATE_QP_SRQ_HANDLE);
 219        if (!IS_ERR(srq)) {
 220                if ((srq->srq_type == IB_SRQT_XRC &&
 221                        attr.qp_type != IB_QPT_XRC_TGT) ||
 222                    (srq->srq_type != IB_SRQT_XRC &&
 223                        attr.qp_type == IB_QPT_XRC_TGT))
 224                        return -EINVAL;
 225                attr.srq = srq;
 226        }
 227
 228        obj->uevent.event_file = ib_uverbs_get_async_event(attrs,
 229                                        UVERBS_ATTR_CREATE_QP_EVENT_FD);
 230        INIT_LIST_HEAD(&obj->uevent.event_list);
 231        INIT_LIST_HEAD(&obj->mcast_list);
 232        obj->uevent.uobject.user_handle = user_handle;
 233        attr.event_handler = ib_uverbs_qp_event_handler;
 234        attr.send_cq = send_cq;
 235        attr.recv_cq = recv_cq;
 236        attr.xrcd = xrcd;
 237        if (attr.create_flags & IB_UVERBS_QP_CREATE_SQ_SIG_ALL) {
 238                /* This creation bit is uverbs one, need to mask before
 239                 * calling drivers. It was added to prevent an extra user attr
 240                 * only for that when using ioctl.
 241                 */
 242                attr.create_flags &= ~IB_UVERBS_QP_CREATE_SQ_SIG_ALL;
 243                attr.sq_sig_type = IB_SIGNAL_ALL_WR;
 244        } else {
 245                attr.sq_sig_type = IB_SIGNAL_REQ_WR;
 246        }
 247
 248        set_caps(&attr, &cap, true);
 249        mutex_init(&obj->mcast_lock);
 250
 251        qp = ib_create_qp_user(device, pd, &attr, &attrs->driver_udata, obj,
 252                               KBUILD_MODNAME);
 253        if (IS_ERR(qp)) {
 254                ret = PTR_ERR(qp);
 255                goto err_put;
 256        }
 257        ib_qp_usecnt_inc(qp);
 258
 259        if (attr.qp_type == IB_QPT_XRC_TGT) {
 260                obj->uxrcd = container_of(xrcd_uobj, struct ib_uxrcd_object,
 261                                          uobject);
 262                atomic_inc(&obj->uxrcd->refcnt);
 263        }
 264
 265        obj->uevent.uobject.object = qp;
 266        uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_QP_HANDLE);
 267
 268        set_caps(&attr, &cap, false);
 269        ret = uverbs_copy_to_struct_or_zero(attrs,
 270                                        UVERBS_ATTR_CREATE_QP_RESP_CAP, &cap,
 271                                        sizeof(cap));
 272        if (ret)
 273                return ret;
 274
 275        ret = uverbs_copy_to(attrs, UVERBS_ATTR_CREATE_QP_RESP_QP_NUM,
 276                             &qp->qp_num,
 277                             sizeof(qp->qp_num));
 278
 279        return ret;
 280err_put:
 281        if (obj->uevent.event_file)
 282                uverbs_uobject_put(&obj->uevent.event_file->uobj);
 283        return ret;
 284};
 285
 286DECLARE_UVERBS_NAMED_METHOD(
 287        UVERBS_METHOD_QP_CREATE,
 288        UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_HANDLE,
 289                        UVERBS_OBJECT_QP,
 290                        UVERBS_ACCESS_NEW,
 291                        UA_MANDATORY),
 292        UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_XRCD_HANDLE,
 293                        UVERBS_OBJECT_XRCD,
 294                        UVERBS_ACCESS_READ,
 295                        UA_OPTIONAL),
 296        UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_PD_HANDLE,
 297                        UVERBS_OBJECT_PD,
 298                        UVERBS_ACCESS_READ,
 299                        UA_OPTIONAL),
 300        UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_SRQ_HANDLE,
 301                        UVERBS_OBJECT_SRQ,
 302                        UVERBS_ACCESS_READ,
 303                        UA_OPTIONAL),
 304        UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_SEND_CQ_HANDLE,
 305                        UVERBS_OBJECT_CQ,
 306                        UVERBS_ACCESS_READ,
 307                        UA_OPTIONAL),
 308        UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_RECV_CQ_HANDLE,
 309                        UVERBS_OBJECT_CQ,
 310                        UVERBS_ACCESS_READ,
 311                        UA_OPTIONAL),
 312        UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_QP_IND_TABLE_HANDLE,
 313                        UVERBS_OBJECT_RWQ_IND_TBL,
 314                        UVERBS_ACCESS_READ,
 315                        UA_OPTIONAL),
 316        UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_QP_USER_HANDLE,
 317                           UVERBS_ATTR_TYPE(u64),
 318                           UA_MANDATORY),
 319        UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_QP_CAP,
 320                           UVERBS_ATTR_STRUCT(struct ib_uverbs_qp_cap,
 321                                              max_inline_data),
 322                           UA_MANDATORY),
 323        UVERBS_ATTR_CONST_IN(UVERBS_ATTR_CREATE_QP_TYPE,
 324                             enum ib_uverbs_qp_type,
 325                             UA_MANDATORY),
 326        UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_CREATE_QP_FLAGS,
 327                             enum ib_uverbs_qp_create_flags,
 328                             UA_OPTIONAL),
 329        UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CREATE_QP_SOURCE_QPN,
 330                           UVERBS_ATTR_TYPE(u32),
 331                           UA_OPTIONAL),
 332        UVERBS_ATTR_FD(UVERBS_ATTR_CREATE_QP_EVENT_FD,
 333                       UVERBS_OBJECT_ASYNC_EVENT,
 334                       UVERBS_ACCESS_READ,
 335                       UA_OPTIONAL),
 336        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_QP_RESP_CAP,
 337                            UVERBS_ATTR_STRUCT(struct ib_uverbs_qp_cap,
 338                                               max_inline_data),
 339                           UA_MANDATORY),
 340        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CREATE_QP_RESP_QP_NUM,
 341                           UVERBS_ATTR_TYPE(u32),
 342                           UA_MANDATORY),
 343        UVERBS_ATTR_UHW());
 344
 345static int UVERBS_HANDLER(UVERBS_METHOD_QP_DESTROY)(
 346        struct uverbs_attr_bundle *attrs)
 347{
 348        struct ib_uobject *uobj =
 349                uverbs_attr_get_uobject(attrs, UVERBS_ATTR_DESTROY_QP_HANDLE);
 350        struct ib_uqp_object *obj =
 351                container_of(uobj, struct ib_uqp_object, uevent.uobject);
 352        struct ib_uverbs_destroy_qp_resp resp = {
 353                .events_reported = obj->uevent.events_reported
 354        };
 355
 356        return uverbs_copy_to(attrs, UVERBS_ATTR_DESTROY_QP_RESP, &resp,
 357                              sizeof(resp));
 358}
 359
 360DECLARE_UVERBS_NAMED_METHOD(
 361        UVERBS_METHOD_QP_DESTROY,
 362        UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_QP_HANDLE,
 363                        UVERBS_OBJECT_QP,
 364                        UVERBS_ACCESS_DESTROY,
 365                        UA_MANDATORY),
 366        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_DESTROY_QP_RESP,
 367                            UVERBS_ATTR_TYPE(struct ib_uverbs_destroy_qp_resp),
 368                            UA_MANDATORY));
 369
 370DECLARE_UVERBS_NAMED_OBJECT(
 371        UVERBS_OBJECT_QP,
 372        UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uqp_object), uverbs_free_qp),
 373        &UVERBS_METHOD(UVERBS_METHOD_QP_CREATE),
 374        &UVERBS_METHOD(UVERBS_METHOD_QP_DESTROY));
 375
 376const struct uapi_definition uverbs_def_obj_qp[] = {
 377        UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_QP,
 378                                      UAPI_DEF_OBJ_NEEDS_FN(destroy_qp)),
 379        {}
 380};
 381