linux/drivers/infiniband/hw/mlx5/srq.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 */
  32
  33#include <linux/module.h>
  34#include <linux/mlx5/qp.h>
  35#include <linux/mlx5/srq.h>
  36#include <linux/slab.h>
  37#include <rdma/ib_umem.h>
  38#include <rdma/ib_user_verbs.h>
  39
  40#include "mlx5_ib.h"
  41
  42/* not supported currently */
  43static int srq_signature;
  44
  45static void *get_wqe(struct mlx5_ib_srq *srq, int n)
  46{
  47        return mlx5_buf_offset(&srq->buf, n << srq->msrq.wqe_shift);
  48}
  49
  50static void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type)
  51{
  52        struct ib_event event;
  53        struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq;
  54
  55        if (ibsrq->event_handler) {
  56                event.device      = ibsrq->device;
  57                event.element.srq = ibsrq;
  58                switch (type) {
  59                case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT:
  60                        event.event = IB_EVENT_SRQ_LIMIT_REACHED;
  61                        break;
  62                case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR:
  63                        event.event = IB_EVENT_SRQ_ERR;
  64                        break;
  65                default:
  66                        pr_warn("mlx5_ib: Unexpected event type %d on SRQ %06x\n",
  67                                type, srq->srqn);
  68                        return;
  69                }
  70
  71                ibsrq->event_handler(&event, ibsrq->srq_context);
  72        }
  73}
  74
  75static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
  76                           struct mlx5_srq_attr *in,
  77                           struct ib_udata *udata, int buf_size)
  78{
  79        struct mlx5_ib_dev *dev = to_mdev(pd->device);
  80        struct mlx5_ib_create_srq ucmd = {};
  81        size_t ucmdlen;
  82        int err;
  83        int npages;
  84        int page_shift;
  85        int ncont;
  86        u32 offset;
  87        u32 uidx = MLX5_IB_DEFAULT_UIDX;
  88
  89        ucmdlen = min(udata->inlen, sizeof(ucmd));
  90
  91        if (ib_copy_from_udata(&ucmd, udata, ucmdlen)) {
  92                mlx5_ib_dbg(dev, "failed copy udata\n");
  93                return -EFAULT;
  94        }
  95
  96        if (ucmd.reserved0 || ucmd.reserved1)
  97                return -EINVAL;
  98
  99        if (udata->inlen > sizeof(ucmd) &&
 100            !ib_is_udata_cleared(udata, sizeof(ucmd),
 101                                 udata->inlen - sizeof(ucmd)))
 102                return -EINVAL;
 103
 104        if (in->type != IB_SRQT_BASIC) {
 105                err = get_srq_user_index(to_mucontext(pd->uobject->context),
 106                                         &ucmd, udata->inlen, &uidx);
 107                if (err)
 108                        return err;
 109        }
 110
 111        srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE);
 112
 113        srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, buf_size,
 114                                0, 0);
 115        if (IS_ERR(srq->umem)) {
 116                mlx5_ib_dbg(dev, "failed umem get, size %d\n", buf_size);
 117                err = PTR_ERR(srq->umem);
 118                return err;
 119        }
 120
 121        mlx5_ib_cont_pages(srq->umem, ucmd.buf_addr, 0, &npages,
 122                           &page_shift, &ncont, NULL);
 123        err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift,
 124                                     &offset);
 125        if (err) {
 126                mlx5_ib_warn(dev, "bad offset\n");
 127                goto err_umem;
 128        }
 129
 130        in->pas = kvzalloc(sizeof(*in->pas) * ncont, GFP_KERNEL);
 131        if (!in->pas) {
 132                err = -ENOMEM;
 133                goto err_umem;
 134        }
 135
 136        mlx5_ib_populate_pas(dev, srq->umem, page_shift, in->pas, 0);
 137
 138        err = mlx5_ib_db_map_user(to_mucontext(pd->uobject->context),
 139                                  ucmd.db_addr, &srq->db);
 140        if (err) {
 141                mlx5_ib_dbg(dev, "map doorbell failed\n");
 142                goto err_in;
 143        }
 144
 145        in->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
 146        in->page_offset = offset;
 147        if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 &&
 148            in->type != IB_SRQT_BASIC)
 149                in->user_index = uidx;
 150
 151        return 0;
 152
 153err_in:
 154        kvfree(in->pas);
 155
 156err_umem:
 157        ib_umem_release(srq->umem);
 158
 159        return err;
 160}
 161
 162static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
 163                             struct mlx5_srq_attr *in, int buf_size)
 164{
 165        int err;
 166        int i;
 167        struct mlx5_wqe_srq_next_seg *next;
 168
 169        err = mlx5_db_alloc(dev->mdev, &srq->db);
 170        if (err) {
 171                mlx5_ib_warn(dev, "alloc dbell rec failed\n");
 172                return err;
 173        }
 174
 175        if (mlx5_buf_alloc(dev->mdev, buf_size, &srq->buf)) {
 176                mlx5_ib_dbg(dev, "buf alloc failed\n");
 177                err = -ENOMEM;
 178                goto err_db;
 179        }
 180
 181        srq->head    = 0;
 182        srq->tail    = srq->msrq.max - 1;
 183        srq->wqe_ctr = 0;
 184
 185        for (i = 0; i < srq->msrq.max; i++) {
 186                next = get_wqe(srq, i);
 187                next->next_wqe_index =
 188                        cpu_to_be16((i + 1) & (srq->msrq.max - 1));
 189        }
 190
 191        mlx5_ib_dbg(dev, "srq->buf.page_shift = %d\n", srq->buf.page_shift);
 192        in->pas = kvzalloc(sizeof(*in->pas) * srq->buf.npages, GFP_KERNEL);
 193        if (!in->pas) {
 194                err = -ENOMEM;
 195                goto err_buf;
 196        }
 197        mlx5_fill_page_array(&srq->buf, in->pas);
 198
 199        srq->wrid = kvmalloc_array(srq->msrq.max, sizeof(u64), GFP_KERNEL);
 200        if (!srq->wrid) {
 201                err = -ENOMEM;
 202                goto err_in;
 203        }
 204        srq->wq_sig = !!srq_signature;
 205
 206        in->log_page_size = srq->buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT;
 207        if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 &&
 208            in->type != IB_SRQT_BASIC)
 209                in->user_index = MLX5_IB_DEFAULT_UIDX;
 210
 211        return 0;
 212
 213err_in:
 214        kvfree(in->pas);
 215
 216err_buf:
 217        mlx5_buf_free(dev->mdev, &srq->buf);
 218
 219err_db:
 220        mlx5_db_free(dev->mdev, &srq->db);
 221        return err;
 222}
 223
 224static void destroy_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq)
 225{
 226        mlx5_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db);
 227        ib_umem_release(srq->umem);
 228}
 229
 230
 231static void destroy_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq)
 232{
 233        kvfree(srq->wrid);
 234        mlx5_buf_free(dev->mdev, &srq->buf);
 235        mlx5_db_free(dev->mdev, &srq->db);
 236}
 237
 238struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
 239                                  struct ib_srq_init_attr *init_attr,
 240                                  struct ib_udata *udata)
 241{
 242        struct mlx5_ib_dev *dev = to_mdev(pd->device);
 243        struct mlx5_ib_srq *srq;
 244        int desc_size;
 245        int buf_size;
 246        int err;
 247        struct mlx5_srq_attr in = {0};
 248        __u32 max_srq_wqes = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz);
 249
 250        /* Sanity check SRQ size before proceeding */
 251        if (init_attr->attr.max_wr >= max_srq_wqes) {
 252                mlx5_ib_dbg(dev, "max_wr %d, cap %d\n",
 253                            init_attr->attr.max_wr,
 254                            max_srq_wqes);
 255                return ERR_PTR(-EINVAL);
 256        }
 257
 258        srq = kmalloc(sizeof(*srq), GFP_KERNEL);
 259        if (!srq)
 260                return ERR_PTR(-ENOMEM);
 261
 262        mutex_init(&srq->mutex);
 263        spin_lock_init(&srq->lock);
 264        srq->msrq.max    = roundup_pow_of_two(init_attr->attr.max_wr + 1);
 265        srq->msrq.max_gs = init_attr->attr.max_sge;
 266
 267        desc_size = sizeof(struct mlx5_wqe_srq_next_seg) +
 268                    srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg);
 269        desc_size = roundup_pow_of_two(desc_size);
 270        desc_size = max_t(int, 32, desc_size);
 271        srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) /
 272                sizeof(struct mlx5_wqe_data_seg);
 273        srq->msrq.wqe_shift = ilog2(desc_size);
 274        buf_size = srq->msrq.max * desc_size;
 275        mlx5_ib_dbg(dev, "desc_size 0x%x, req wr 0x%x, srq size 0x%x, max_gs 0x%x, max_avail_gather 0x%x\n",
 276                    desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs,
 277                    srq->msrq.max_avail_gather);
 278        in.type = init_attr->srq_type;
 279
 280        if (pd->uobject)
 281                err = create_srq_user(pd, srq, &in, udata, buf_size);
 282        else
 283                err = create_srq_kernel(dev, srq, &in, buf_size);
 284
 285        if (err) {
 286                mlx5_ib_warn(dev, "create srq %s failed, err %d\n",
 287                             pd->uobject ? "user" : "kernel", err);
 288                goto err_srq;
 289        }
 290
 291        in.log_size = ilog2(srq->msrq.max);
 292        in.wqe_shift = srq->msrq.wqe_shift - 4;
 293        if (srq->wq_sig)
 294                in.flags |= MLX5_SRQ_FLAG_WQ_SIG;
 295
 296        if (init_attr->srq_type == IB_SRQT_XRC)
 297                in.xrcd = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn;
 298        else
 299                in.xrcd = to_mxrcd(dev->devr.x0)->xrcdn;
 300
 301        if (init_attr->srq_type == IB_SRQT_TM) {
 302                in.tm_log_list_size =
 303                        ilog2(init_attr->ext.tag_matching.max_num_tags) + 1;
 304                if (in.tm_log_list_size >
 305                    MLX5_CAP_GEN(dev->mdev, log_tag_matching_list_sz)) {
 306                        mlx5_ib_dbg(dev, "TM SRQ max_num_tags exceeding limit\n");
 307                        err = -EINVAL;
 308                        goto err_usr_kern_srq;
 309                }
 310                in.flags |= MLX5_SRQ_FLAG_RNDV;
 311        }
 312
 313        if (ib_srq_has_cq(init_attr->srq_type))
 314                in.cqn = to_mcq(init_attr->ext.cq)->mcq.cqn;
 315        else
 316                in.cqn = to_mcq(dev->devr.c0)->mcq.cqn;
 317
 318        in.pd = to_mpd(pd)->pdn;
 319        in.db_record = srq->db.dma;
 320        err = mlx5_core_create_srq(dev->mdev, &srq->msrq, &in);
 321        kvfree(in.pas);
 322        if (err) {
 323                mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err);
 324                goto err_usr_kern_srq;
 325        }
 326
 327        mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn);
 328
 329        srq->msrq.event = mlx5_ib_srq_event;
 330        srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn;
 331
 332        if (pd->uobject)
 333                if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof(__u32))) {
 334                        mlx5_ib_dbg(dev, "copy to user failed\n");
 335                        err = -EFAULT;
 336                        goto err_core;
 337                }
 338
 339        init_attr->attr.max_wr = srq->msrq.max - 1;
 340
 341        return &srq->ibsrq;
 342
 343err_core:
 344        mlx5_core_destroy_srq(dev->mdev, &srq->msrq);
 345
 346err_usr_kern_srq:
 347        if (pd->uobject)
 348                destroy_srq_user(pd, srq);
 349        else
 350                destroy_srq_kernel(dev, srq);
 351
 352err_srq:
 353        kfree(srq);
 354
 355        return ERR_PTR(err);
 356}
 357
 358int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
 359                       enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
 360{
 361        struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
 362        struct mlx5_ib_srq *srq = to_msrq(ibsrq);
 363        int ret;
 364
 365        /* We don't support resizing SRQs yet */
 366        if (attr_mask & IB_SRQ_MAX_WR)
 367                return -EINVAL;
 368
 369        if (attr_mask & IB_SRQ_LIMIT) {
 370                if (attr->srq_limit >= srq->msrq.max)
 371                        return -EINVAL;
 372
 373                mutex_lock(&srq->mutex);
 374                ret = mlx5_core_arm_srq(dev->mdev, &srq->msrq, attr->srq_limit, 1);
 375                mutex_unlock(&srq->mutex);
 376
 377                if (ret)
 378                        return ret;
 379        }
 380
 381        return 0;
 382}
 383
 384int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
 385{
 386        struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
 387        struct mlx5_ib_srq *srq = to_msrq(ibsrq);
 388        int ret;
 389        struct mlx5_srq_attr *out;
 390
 391        out = kzalloc(sizeof(*out), GFP_KERNEL);
 392        if (!out)
 393                return -ENOMEM;
 394
 395        ret = mlx5_core_query_srq(dev->mdev, &srq->msrq, out);
 396        if (ret)
 397                goto out_box;
 398
 399        srq_attr->srq_limit = out->lwm;
 400        srq_attr->max_wr    = srq->msrq.max - 1;
 401        srq_attr->max_sge   = srq->msrq.max_gs;
 402
 403out_box:
 404        kfree(out);
 405        return ret;
 406}
 407
 408int mlx5_ib_destroy_srq(struct ib_srq *srq)
 409{
 410        struct mlx5_ib_dev *dev = to_mdev(srq->device);
 411        struct mlx5_ib_srq *msrq = to_msrq(srq);
 412
 413        mlx5_core_destroy_srq(dev->mdev, &msrq->msrq);
 414
 415        if (srq->uobject) {
 416                mlx5_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
 417                ib_umem_release(msrq->umem);
 418        } else {
 419                destroy_srq_kernel(dev, msrq);
 420        }
 421
 422        kfree(srq);
 423        return 0;
 424}
 425
 426void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index)
 427{
 428        struct mlx5_wqe_srq_next_seg *next;
 429
 430        /* always called with interrupts disabled. */
 431        spin_lock(&srq->lock);
 432
 433        next = get_wqe(srq, srq->tail);
 434        next->next_wqe_index = cpu_to_be16(wqe_index);
 435        srq->tail = wqe_index;
 436
 437        spin_unlock(&srq->lock);
 438}
 439
 440int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
 441                          struct ib_recv_wr **bad_wr)
 442{
 443        struct mlx5_ib_srq *srq = to_msrq(ibsrq);
 444        struct mlx5_wqe_srq_next_seg *next;
 445        struct mlx5_wqe_data_seg *scat;
 446        struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
 447        struct mlx5_core_dev *mdev = dev->mdev;
 448        unsigned long flags;
 449        int err = 0;
 450        int nreq;
 451        int i;
 452
 453        spin_lock_irqsave(&srq->lock, flags);
 454
 455        if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
 456                err = -EIO;
 457                *bad_wr = wr;
 458                goto out;
 459        }
 460
 461        for (nreq = 0; wr; nreq++, wr = wr->next) {
 462                if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
 463                        err = -EINVAL;
 464                        *bad_wr = wr;
 465                        break;
 466                }
 467
 468                if (unlikely(srq->head == srq->tail)) {
 469                        err = -ENOMEM;
 470                        *bad_wr = wr;
 471                        break;
 472                }
 473
 474                srq->wrid[srq->head] = wr->wr_id;
 475
 476                next      = get_wqe(srq, srq->head);
 477                srq->head = be16_to_cpu(next->next_wqe_index);
 478                scat      = (struct mlx5_wqe_data_seg *)(next + 1);
 479
 480                for (i = 0; i < wr->num_sge; i++) {
 481                        scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
 482                        scat[i].lkey       = cpu_to_be32(wr->sg_list[i].lkey);
 483                        scat[i].addr       = cpu_to_be64(wr->sg_list[i].addr);
 484                }
 485
 486                if (i < srq->msrq.max_avail_gather) {
 487                        scat[i].byte_count = 0;
 488                        scat[i].lkey       = cpu_to_be32(MLX5_INVALID_LKEY);
 489                        scat[i].addr       = 0;
 490                }
 491        }
 492
 493        if (likely(nreq)) {
 494                srq->wqe_ctr += nreq;
 495
 496                /* Make sure that descriptors are written before
 497                 * doorbell record.
 498                 */
 499                wmb();
 500
 501                *srq->db.db = cpu_to_be32(srq->wqe_ctr);
 502        }
 503out:
 504        spin_unlock_irqrestore(&srq->lock, flags);
 505
 506        return err;
 507}
 508