linux/drivers/infiniband/core/uverbs_std_types_device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2/*
   3 * Copyright (c) 2018, Mellanox Technologies inc.  All rights reserved.
   4 */
   5
   6#include <linux/overflow.h>
   7#include <rdma/uverbs_std_types.h>
   8#include "rdma_core.h"
   9#include "uverbs.h"
  10#include <rdma/uverbs_ioctl.h>
  11#include <rdma/opa_addr.h>
  12#include <rdma/ib_cache.h>
  13
  14/*
  15 * This ioctl method allows calling any defined write or write_ex
  16 * handler. This essentially replaces the hdr/ex_hdr system with the ioctl
  17 * marshalling, and brings the non-ex path into the same marshalling as the ex
  18 * path.
  19 */
  20static int UVERBS_HANDLER(UVERBS_METHOD_INVOKE_WRITE)(
  21        struct uverbs_attr_bundle *attrs)
  22{
  23        struct uverbs_api *uapi = attrs->ufile->device->uapi;
  24        const struct uverbs_api_write_method *method_elm;
  25        u32 cmd;
  26        int rc;
  27
  28        rc = uverbs_get_const(&cmd, attrs, UVERBS_ATTR_WRITE_CMD);
  29        if (rc)
  30                return rc;
  31
  32        method_elm = uapi_get_method(uapi, cmd);
  33        if (IS_ERR(method_elm))
  34                return PTR_ERR(method_elm);
  35
  36        uverbs_fill_udata(attrs, &attrs->ucore, UVERBS_ATTR_CORE_IN,
  37                          UVERBS_ATTR_CORE_OUT);
  38
  39        if (attrs->ucore.inlen < method_elm->req_size ||
  40            attrs->ucore.outlen < method_elm->resp_size)
  41                return -ENOSPC;
  42
  43        attrs->uobject = NULL;
  44        rc = method_elm->handler(attrs);
  45        if (attrs->uobject)
  46                uverbs_finalize_object(attrs->uobject, UVERBS_ACCESS_NEW, true,
  47                                       !rc, attrs);
  48        return rc;
  49}
  50
  51DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_INVOKE_WRITE,
  52                            UVERBS_ATTR_CONST_IN(UVERBS_ATTR_WRITE_CMD,
  53                                                 enum ib_uverbs_write_cmds,
  54                                                 UA_MANDATORY),
  55                            UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CORE_IN,
  56                                               UVERBS_ATTR_MIN_SIZE(sizeof(u32)),
  57                                               UA_OPTIONAL),
  58                            UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CORE_OUT,
  59                                                UVERBS_ATTR_MIN_SIZE(0),
  60                                                UA_OPTIONAL),
  61                            UVERBS_ATTR_UHW());
  62
  63static uint32_t *
  64gather_objects_handle(struct ib_uverbs_file *ufile,
  65                      const struct uverbs_api_object *uapi_object,
  66                      struct uverbs_attr_bundle *attrs,
  67                      ssize_t out_len,
  68                      u64 *total)
  69{
  70        u64 max_count = out_len / sizeof(u32);
  71        struct ib_uobject *obj;
  72        u64 count = 0;
  73        u32 *handles;
  74
  75        /* Allocated memory that cannot page out where we gather
  76         * all object ids under a spin_lock.
  77         */
  78        handles = uverbs_zalloc(attrs, out_len);
  79        if (IS_ERR(handles))
  80                return handles;
  81
  82        spin_lock_irq(&ufile->uobjects_lock);
  83        list_for_each_entry(obj, &ufile->uobjects, list) {
  84                u32 obj_id = obj->id;
  85
  86                if (obj->uapi_object != uapi_object)
  87                        continue;
  88
  89                if (count >= max_count)
  90                        break;
  91
  92                handles[count] = obj_id;
  93                count++;
  94        }
  95        spin_unlock_irq(&ufile->uobjects_lock);
  96
  97        *total = count;
  98        return handles;
  99}
 100
 101static int UVERBS_HANDLER(UVERBS_METHOD_INFO_HANDLES)(
 102        struct uverbs_attr_bundle *attrs)
 103{
 104        const struct uverbs_api_object *uapi_object;
 105        ssize_t out_len;
 106        u64 total = 0;
 107        u16 object_id;
 108        u32 *handles;
 109        int ret;
 110
 111        out_len = uverbs_attr_get_len(attrs, UVERBS_ATTR_INFO_HANDLES_LIST);
 112        if (out_len <= 0 || (out_len % sizeof(u32) != 0))
 113                return -EINVAL;
 114
 115        ret = uverbs_get_const(&object_id, attrs, UVERBS_ATTR_INFO_OBJECT_ID);
 116        if (ret)
 117                return ret;
 118
 119        uapi_object = uapi_get_object(attrs->ufile->device->uapi, object_id);
 120        if (IS_ERR(uapi_object))
 121                return PTR_ERR(uapi_object);
 122
 123        handles = gather_objects_handle(attrs->ufile, uapi_object, attrs,
 124                                        out_len, &total);
 125        if (IS_ERR(handles))
 126                return PTR_ERR(handles);
 127
 128        ret = uverbs_copy_to(attrs, UVERBS_ATTR_INFO_HANDLES_LIST, handles,
 129                             sizeof(u32) * total);
 130        if (ret)
 131                goto err;
 132
 133        ret = uverbs_copy_to(attrs, UVERBS_ATTR_INFO_TOTAL_HANDLES, &total,
 134                             sizeof(total));
 135err:
 136        return ret;
 137}
 138
 139void copy_port_attr_to_resp(struct ib_port_attr *attr,
 140                            struct ib_uverbs_query_port_resp *resp,
 141                            struct ib_device *ib_dev, u8 port_num)
 142{
 143        resp->state = attr->state;
 144        resp->max_mtu = attr->max_mtu;
 145        resp->active_mtu = attr->active_mtu;
 146        resp->gid_tbl_len = attr->gid_tbl_len;
 147        resp->port_cap_flags = make_port_cap_flags(attr);
 148        resp->max_msg_sz = attr->max_msg_sz;
 149        resp->bad_pkey_cntr = attr->bad_pkey_cntr;
 150        resp->qkey_viol_cntr = attr->qkey_viol_cntr;
 151        resp->pkey_tbl_len = attr->pkey_tbl_len;
 152
 153        if (rdma_is_grh_required(ib_dev, port_num))
 154                resp->flags |= IB_UVERBS_QPF_GRH_REQUIRED;
 155
 156        if (rdma_cap_opa_ah(ib_dev, port_num)) {
 157                resp->lid = OPA_TO_IB_UCAST_LID(attr->lid);
 158                resp->sm_lid = OPA_TO_IB_UCAST_LID(attr->sm_lid);
 159        } else {
 160                resp->lid = ib_lid_cpu16(attr->lid);
 161                resp->sm_lid = ib_lid_cpu16(attr->sm_lid);
 162        }
 163
 164        resp->lmc = attr->lmc;
 165        resp->max_vl_num = attr->max_vl_num;
 166        resp->sm_sl = attr->sm_sl;
 167        resp->subnet_timeout = attr->subnet_timeout;
 168        resp->init_type_reply = attr->init_type_reply;
 169        resp->active_width = attr->active_width;
 170        /* This ABI needs to be extended to provide any speed more than IB_SPEED_NDR */
 171        resp->active_speed = min_t(u16, attr->active_speed, IB_SPEED_NDR);
 172        resp->phys_state = attr->phys_state;
 173        resp->link_layer = rdma_port_get_link_layer(ib_dev, port_num);
 174}
 175
 176static int UVERBS_HANDLER(UVERBS_METHOD_QUERY_PORT)(
 177        struct uverbs_attr_bundle *attrs)
 178{
 179        struct ib_device *ib_dev;
 180        struct ib_port_attr attr = {};
 181        struct ib_uverbs_query_port_resp_ex resp = {};
 182        struct ib_ucontext *ucontext;
 183        int ret;
 184        u8 port_num;
 185
 186        ucontext = ib_uverbs_get_ucontext(attrs);
 187        if (IS_ERR(ucontext))
 188                return PTR_ERR(ucontext);
 189        ib_dev = ucontext->device;
 190
 191        /* FIXME: Extend the UAPI_DEF_OBJ_NEEDS_FN stuff.. */
 192        if (!ib_dev->ops.query_port)
 193                return -EOPNOTSUPP;
 194
 195        ret = uverbs_get_const(&port_num, attrs,
 196                               UVERBS_ATTR_QUERY_PORT_PORT_NUM);
 197        if (ret)
 198                return ret;
 199
 200        ret = ib_query_port(ib_dev, port_num, &attr);
 201        if (ret)
 202                return ret;
 203
 204        copy_port_attr_to_resp(&attr, &resp.legacy_resp, ib_dev, port_num);
 205        resp.port_cap_flags2 = attr.port_cap_flags2;
 206
 207        return uverbs_copy_to_struct_or_zero(attrs, UVERBS_ATTR_QUERY_PORT_RESP,
 208                                             &resp, sizeof(resp));
 209}
 210
 211static int UVERBS_HANDLER(UVERBS_METHOD_GET_CONTEXT)(
 212        struct uverbs_attr_bundle *attrs)
 213{
 214        u32 num_comp = attrs->ufile->device->num_comp_vectors;
 215        u64 core_support = IB_UVERBS_CORE_SUPPORT_OPTIONAL_MR_ACCESS;
 216        int ret;
 217
 218        ret = uverbs_copy_to(attrs, UVERBS_ATTR_GET_CONTEXT_NUM_COMP_VECTORS,
 219                             &num_comp, sizeof(num_comp));
 220        if (IS_UVERBS_COPY_ERR(ret))
 221                return ret;
 222
 223        ret = uverbs_copy_to(attrs, UVERBS_ATTR_GET_CONTEXT_CORE_SUPPORT,
 224                             &core_support, sizeof(core_support));
 225        if (IS_UVERBS_COPY_ERR(ret))
 226                return ret;
 227
 228        ret = ib_alloc_ucontext(attrs);
 229        if (ret)
 230                return ret;
 231        ret = ib_init_ucontext(attrs);
 232        if (ret) {
 233                kfree(attrs->context);
 234                attrs->context = NULL;
 235                return ret;
 236        }
 237        return 0;
 238}
 239
 240static int UVERBS_HANDLER(UVERBS_METHOD_QUERY_CONTEXT)(
 241        struct uverbs_attr_bundle *attrs)
 242{
 243        u64 core_support = IB_UVERBS_CORE_SUPPORT_OPTIONAL_MR_ACCESS;
 244        struct ib_ucontext *ucontext;
 245        struct ib_device *ib_dev;
 246        u32 num_comp;
 247        int ret;
 248
 249        ucontext = ib_uverbs_get_ucontext(attrs);
 250        if (IS_ERR(ucontext))
 251                return PTR_ERR(ucontext);
 252        ib_dev = ucontext->device;
 253
 254        if (!ib_dev->ops.query_ucontext)
 255                return -EOPNOTSUPP;
 256
 257        num_comp = attrs->ufile->device->num_comp_vectors;
 258        ret = uverbs_copy_to(attrs, UVERBS_ATTR_QUERY_CONTEXT_NUM_COMP_VECTORS,
 259                             &num_comp, sizeof(num_comp));
 260        if (IS_UVERBS_COPY_ERR(ret))
 261                return ret;
 262
 263        ret = uverbs_copy_to(attrs, UVERBS_ATTR_QUERY_CONTEXT_CORE_SUPPORT,
 264                             &core_support, sizeof(core_support));
 265        if (IS_UVERBS_COPY_ERR(ret))
 266                return ret;
 267
 268        return ucontext->device->ops.query_ucontext(ucontext, attrs);
 269}
 270
 271static int copy_gid_entries_to_user(struct uverbs_attr_bundle *attrs,
 272                                    struct ib_uverbs_gid_entry *entries,
 273                                    size_t num_entries, size_t user_entry_size)
 274{
 275        const struct uverbs_attr *attr;
 276        void __user *user_entries;
 277        size_t copy_len;
 278        int ret;
 279        int i;
 280
 281        if (user_entry_size == sizeof(*entries)) {
 282                ret = uverbs_copy_to(attrs,
 283                                     UVERBS_ATTR_QUERY_GID_TABLE_RESP_ENTRIES,
 284                                     entries, sizeof(*entries) * num_entries);
 285                return ret;
 286        }
 287
 288        copy_len = min_t(size_t, user_entry_size, sizeof(*entries));
 289        attr = uverbs_attr_get(attrs, UVERBS_ATTR_QUERY_GID_TABLE_RESP_ENTRIES);
 290        if (IS_ERR(attr))
 291                return PTR_ERR(attr);
 292
 293        user_entries = u64_to_user_ptr(attr->ptr_attr.data);
 294        for (i = 0; i < num_entries; i++) {
 295                if (copy_to_user(user_entries, entries, copy_len))
 296                        return -EFAULT;
 297
 298                if (user_entry_size > sizeof(*entries)) {
 299                        if (clear_user(user_entries + sizeof(*entries),
 300                                       user_entry_size - sizeof(*entries)))
 301                                return -EFAULT;
 302                }
 303
 304                entries++;
 305                user_entries += user_entry_size;
 306        }
 307
 308        return uverbs_output_written(attrs,
 309                                     UVERBS_ATTR_QUERY_GID_TABLE_RESP_ENTRIES);
 310}
 311
 312static int UVERBS_HANDLER(UVERBS_METHOD_QUERY_GID_TABLE)(
 313        struct uverbs_attr_bundle *attrs)
 314{
 315        struct ib_uverbs_gid_entry *entries;
 316        struct ib_ucontext *ucontext;
 317        struct ib_device *ib_dev;
 318        size_t user_entry_size;
 319        ssize_t num_entries;
 320        int max_entries;
 321        u32 flags;
 322        int ret;
 323
 324        ret = uverbs_get_flags32(&flags, attrs,
 325                                 UVERBS_ATTR_QUERY_GID_TABLE_FLAGS, 0);
 326        if (ret)
 327                return ret;
 328
 329        ret = uverbs_get_const(&user_entry_size, attrs,
 330                               UVERBS_ATTR_QUERY_GID_TABLE_ENTRY_SIZE);
 331        if (ret)
 332                return ret;
 333
 334        if (!user_entry_size)
 335                return -EINVAL;
 336
 337        max_entries = uverbs_attr_ptr_get_array_size(
 338                attrs, UVERBS_ATTR_QUERY_GID_TABLE_RESP_ENTRIES,
 339                user_entry_size);
 340        if (max_entries <= 0)
 341                return max_entries ?: -EINVAL;
 342
 343        ucontext = ib_uverbs_get_ucontext(attrs);
 344        if (IS_ERR(ucontext))
 345                return PTR_ERR(ucontext);
 346        ib_dev = ucontext->device;
 347
 348        entries = uverbs_kcalloc(attrs, max_entries, sizeof(*entries));
 349        if (IS_ERR(entries))
 350                return PTR_ERR(entries);
 351
 352        num_entries = rdma_query_gid_table(ib_dev, entries, max_entries);
 353        if (num_entries < 0)
 354                return -EINVAL;
 355
 356        ret = copy_gid_entries_to_user(attrs, entries, num_entries,
 357                                       user_entry_size);
 358        if (ret)
 359                return ret;
 360
 361        ret = uverbs_copy_to(attrs,
 362                             UVERBS_ATTR_QUERY_GID_TABLE_RESP_NUM_ENTRIES,
 363                             &num_entries, sizeof(num_entries));
 364        return ret;
 365}
 366
 367static int UVERBS_HANDLER(UVERBS_METHOD_QUERY_GID_ENTRY)(
 368        struct uverbs_attr_bundle *attrs)
 369{
 370        struct ib_uverbs_gid_entry entry = {};
 371        const struct ib_gid_attr *gid_attr;
 372        struct ib_ucontext *ucontext;
 373        struct ib_device *ib_dev;
 374        struct net_device *ndev;
 375        u32 gid_index;
 376        u32 port_num;
 377        u32 flags;
 378        int ret;
 379
 380        ret = uverbs_get_flags32(&flags, attrs,
 381                                 UVERBS_ATTR_QUERY_GID_ENTRY_FLAGS, 0);
 382        if (ret)
 383                return ret;
 384
 385        ret = uverbs_get_const(&port_num, attrs,
 386                               UVERBS_ATTR_QUERY_GID_ENTRY_PORT);
 387        if (ret)
 388                return ret;
 389
 390        ret = uverbs_get_const(&gid_index, attrs,
 391                               UVERBS_ATTR_QUERY_GID_ENTRY_GID_INDEX);
 392        if (ret)
 393                return ret;
 394
 395        ucontext = ib_uverbs_get_ucontext(attrs);
 396        if (IS_ERR(ucontext))
 397                return PTR_ERR(ucontext);
 398        ib_dev = ucontext->device;
 399
 400        if (!rdma_is_port_valid(ib_dev, port_num))
 401                return -EINVAL;
 402
 403        gid_attr = rdma_get_gid_attr(ib_dev, port_num, gid_index);
 404        if (IS_ERR(gid_attr))
 405                return PTR_ERR(gid_attr);
 406
 407        memcpy(&entry.gid, &gid_attr->gid, sizeof(gid_attr->gid));
 408        entry.gid_index = gid_attr->index;
 409        entry.port_num = gid_attr->port_num;
 410        entry.gid_type = gid_attr->gid_type;
 411
 412        rcu_read_lock();
 413        ndev = rdma_read_gid_attr_ndev_rcu(gid_attr);
 414        if (IS_ERR(ndev)) {
 415                if (PTR_ERR(ndev) != -ENODEV) {
 416                        ret = PTR_ERR(ndev);
 417                        rcu_read_unlock();
 418                        goto out;
 419                }
 420        } else {
 421                entry.netdev_ifindex = ndev->ifindex;
 422        }
 423        rcu_read_unlock();
 424
 425        ret = uverbs_copy_to_struct_or_zero(
 426                attrs, UVERBS_ATTR_QUERY_GID_ENTRY_RESP_ENTRY, &entry,
 427                sizeof(entry));
 428out:
 429        rdma_put_gid_attr(gid_attr);
 430        return ret;
 431}
 432
 433DECLARE_UVERBS_NAMED_METHOD(
 434        UVERBS_METHOD_GET_CONTEXT,
 435        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_GET_CONTEXT_NUM_COMP_VECTORS,
 436                            UVERBS_ATTR_TYPE(u32), UA_OPTIONAL),
 437        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_GET_CONTEXT_CORE_SUPPORT,
 438                            UVERBS_ATTR_TYPE(u64), UA_OPTIONAL),
 439        UVERBS_ATTR_UHW());
 440
 441DECLARE_UVERBS_NAMED_METHOD(
 442        UVERBS_METHOD_QUERY_CONTEXT,
 443        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_CONTEXT_NUM_COMP_VECTORS,
 444                            UVERBS_ATTR_TYPE(u32), UA_OPTIONAL),
 445        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_CONTEXT_CORE_SUPPORT,
 446                            UVERBS_ATTR_TYPE(u64), UA_OPTIONAL));
 447
 448DECLARE_UVERBS_NAMED_METHOD(
 449        UVERBS_METHOD_INFO_HANDLES,
 450        /* Also includes any device specific object ids */
 451        UVERBS_ATTR_CONST_IN(UVERBS_ATTR_INFO_OBJECT_ID,
 452                             enum uverbs_default_objects, UA_MANDATORY),
 453        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_INFO_TOTAL_HANDLES,
 454                            UVERBS_ATTR_TYPE(u32), UA_OPTIONAL),
 455        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_INFO_HANDLES_LIST,
 456                            UVERBS_ATTR_MIN_SIZE(sizeof(u32)), UA_OPTIONAL));
 457
 458DECLARE_UVERBS_NAMED_METHOD(
 459        UVERBS_METHOD_QUERY_PORT,
 460        UVERBS_ATTR_CONST_IN(UVERBS_ATTR_QUERY_PORT_PORT_NUM, u8, UA_MANDATORY),
 461        UVERBS_ATTR_PTR_OUT(
 462                UVERBS_ATTR_QUERY_PORT_RESP,
 463                UVERBS_ATTR_STRUCT(struct ib_uverbs_query_port_resp_ex,
 464                                   reserved),
 465                UA_MANDATORY));
 466
 467DECLARE_UVERBS_NAMED_METHOD(
 468        UVERBS_METHOD_QUERY_GID_TABLE,
 469        UVERBS_ATTR_CONST_IN(UVERBS_ATTR_QUERY_GID_TABLE_ENTRY_SIZE, u64,
 470                             UA_MANDATORY),
 471        UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_QUERY_GID_TABLE_FLAGS, u32,
 472                             UA_OPTIONAL),
 473        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_GID_TABLE_RESP_ENTRIES,
 474                            UVERBS_ATTR_MIN_SIZE(0), UA_MANDATORY),
 475        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_GID_TABLE_RESP_NUM_ENTRIES,
 476                            UVERBS_ATTR_TYPE(u64), UA_MANDATORY));
 477
 478DECLARE_UVERBS_NAMED_METHOD(
 479        UVERBS_METHOD_QUERY_GID_ENTRY,
 480        UVERBS_ATTR_CONST_IN(UVERBS_ATTR_QUERY_GID_ENTRY_PORT, u32,
 481                             UA_MANDATORY),
 482        UVERBS_ATTR_CONST_IN(UVERBS_ATTR_QUERY_GID_ENTRY_GID_INDEX, u32,
 483                             UA_MANDATORY),
 484        UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_QUERY_GID_ENTRY_FLAGS, u32,
 485                             UA_MANDATORY),
 486        UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_GID_ENTRY_RESP_ENTRY,
 487                            UVERBS_ATTR_STRUCT(struct ib_uverbs_gid_entry,
 488                                               netdev_ifindex),
 489                            UA_MANDATORY));
 490
 491DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE,
 492                              &UVERBS_METHOD(UVERBS_METHOD_GET_CONTEXT),
 493                              &UVERBS_METHOD(UVERBS_METHOD_INVOKE_WRITE),
 494                              &UVERBS_METHOD(UVERBS_METHOD_INFO_HANDLES),
 495                              &UVERBS_METHOD(UVERBS_METHOD_QUERY_PORT),
 496                              &UVERBS_METHOD(UVERBS_METHOD_QUERY_CONTEXT),
 497                              &UVERBS_METHOD(UVERBS_METHOD_QUERY_GID_TABLE),
 498                              &UVERBS_METHOD(UVERBS_METHOD_QUERY_GID_ENTRY));
 499
 500const struct uapi_definition uverbs_def_obj_device[] = {
 501        UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE),
 502        {},
 503};
 504