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_XRC) {
 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 = mlx5_vzalloc(sizeof(*in->pas) * ncont);
 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_XRC)
 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        int page_shift;
 169        int npages;
 170
 171        err = mlx5_db_alloc(dev->mdev, &srq->db);
 172        if (err) {
 173                mlx5_ib_warn(dev, "alloc dbell rec failed\n");
 174                return err;
 175        }
 176
 177        if (mlx5_buf_alloc(dev->mdev, buf_size, &srq->buf)) {
 178                mlx5_ib_dbg(dev, "buf alloc failed\n");
 179                err = -ENOMEM;
 180                goto err_db;
 181        }
 182        page_shift = srq->buf.page_shift;
 183
 184        srq->head    = 0;
 185        srq->tail    = srq->msrq.max - 1;
 186        srq->wqe_ctr = 0;
 187
 188        for (i = 0; i < srq->msrq.max; i++) {
 189                next = get_wqe(srq, i);
 190                next->next_wqe_index =
 191                        cpu_to_be16((i + 1) & (srq->msrq.max - 1));
 192        }
 193
 194        npages = DIV_ROUND_UP(srq->buf.npages, 1 << (page_shift - PAGE_SHIFT));
 195        mlx5_ib_dbg(dev, "buf_size %d, page_shift %d, npages %d, calc npages %d\n",
 196                    buf_size, page_shift, srq->buf.npages, npages);
 197        in->pas = mlx5_vzalloc(sizeof(*in->pas) * npages);
 198        if (!in->pas) {
 199                err = -ENOMEM;
 200                goto err_buf;
 201        }
 202        mlx5_fill_page_array(&srq->buf, in->pas);
 203
 204        srq->wrid = kmalloc(srq->msrq.max * sizeof(u64), GFP_KERNEL);
 205        if (!srq->wrid) {
 206                err = -ENOMEM;
 207                goto err_in;
 208        }
 209        srq->wq_sig = !!srq_signature;
 210
 211        in->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
 212        if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 &&
 213            in->type == IB_SRQT_XRC)
 214                in->user_index = MLX5_IB_DEFAULT_UIDX;
 215
 216        return 0;
 217
 218err_in:
 219        kvfree(in->pas);
 220
 221err_buf:
 222        mlx5_buf_free(dev->mdev, &srq->buf);
 223
 224err_db:
 225        mlx5_db_free(dev->mdev, &srq->db);
 226        return err;
 227}
 228
 229static void destroy_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq)
 230{
 231        mlx5_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db);
 232        ib_umem_release(srq->umem);
 233}
 234
 235
 236static void destroy_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq)
 237{
 238        kfree(srq->wrid);
 239        mlx5_buf_free(dev->mdev, &srq->buf);
 240        mlx5_db_free(dev->mdev, &srq->db);
 241}
 242
 243struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
 244                                  struct ib_srq_init_attr *init_attr,
 245                                  struct ib_udata *udata)
 246{
 247        struct mlx5_ib_dev *dev = to_mdev(pd->device);
 248        struct mlx5_ib_srq *srq;
 249        int desc_size;
 250        int buf_size;
 251        int err;
 252        struct mlx5_srq_attr in = {0};
 253        __u32 max_srq_wqes = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz);
 254
 255        /* Sanity check SRQ size before proceeding */
 256        if (init_attr->attr.max_wr >= max_srq_wqes) {
 257                mlx5_ib_dbg(dev, "max_wr %d, cap %d\n",
 258                            init_attr->attr.max_wr,
 259                            max_srq_wqes);
 260                return ERR_PTR(-EINVAL);
 261        }
 262
 263        srq = kmalloc(sizeof(*srq), GFP_KERNEL);
 264        if (!srq)
 265                return ERR_PTR(-ENOMEM);
 266
 267        mutex_init(&srq->mutex);
 268        spin_lock_init(&srq->lock);
 269        srq->msrq.max    = roundup_pow_of_two(init_attr->attr.max_wr + 1);
 270        srq->msrq.max_gs = init_attr->attr.max_sge;
 271
 272        desc_size = sizeof(struct mlx5_wqe_srq_next_seg) +
 273                    srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg);
 274        desc_size = roundup_pow_of_two(desc_size);
 275        desc_size = max_t(int, 32, desc_size);
 276        srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) /
 277                sizeof(struct mlx5_wqe_data_seg);
 278        srq->msrq.wqe_shift = ilog2(desc_size);
 279        buf_size = srq->msrq.max * desc_size;
 280        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",
 281                    desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs,
 282                    srq->msrq.max_avail_gather);
 283        in.type = init_attr->srq_type;
 284
 285        if (pd->uobject)
 286                err = create_srq_user(pd, srq, &in, udata, buf_size);
 287        else
 288                err = create_srq_kernel(dev, srq, &in, buf_size);
 289
 290        if (err) {
 291                mlx5_ib_warn(dev, "create srq %s failed, err %d\n",
 292                             pd->uobject ? "user" : "kernel", err);
 293                goto err_srq;
 294        }
 295
 296        in.log_size = ilog2(srq->msrq.max);
 297        in.wqe_shift = srq->msrq.wqe_shift - 4;
 298        if (srq->wq_sig)
 299                in.flags |= MLX5_SRQ_FLAG_WQ_SIG;
 300        if (init_attr->srq_type == IB_SRQT_XRC) {
 301                in.xrcd = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn;
 302                in.cqn = to_mcq(init_attr->ext.xrc.cq)->mcq.cqn;
 303        } else if (init_attr->srq_type == IB_SRQT_BASIC) {
 304                in.xrcd = to_mxrcd(dev->devr.x0)->xrcdn;
 305                in.cqn = to_mcq(dev->devr.c0)->mcq.cqn;
 306        }
 307
 308        in.pd = to_mpd(pd)->pdn;
 309        in.db_record = srq->db.dma;
 310        err = mlx5_core_create_srq(dev->mdev, &srq->msrq, &in);
 311        kvfree(in.pas);
 312        if (err) {
 313                mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err);
 314                goto err_usr_kern_srq;
 315        }
 316
 317        mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn);
 318
 319        srq->msrq.event = mlx5_ib_srq_event;
 320        srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn;
 321
 322        if (pd->uobject)
 323                if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof(__u32))) {
 324                        mlx5_ib_dbg(dev, "copy to user failed\n");
 325                        err = -EFAULT;
 326                        goto err_core;
 327                }
 328
 329        init_attr->attr.max_wr = srq->msrq.max - 1;
 330
 331        return &srq->ibsrq;
 332
 333err_core:
 334        mlx5_core_destroy_srq(dev->mdev, &srq->msrq);
 335
 336err_usr_kern_srq:
 337        if (pd->uobject)
 338                destroy_srq_user(pd, srq);
 339        else
 340                destroy_srq_kernel(dev, srq);
 341
 342err_srq:
 343        kfree(srq);
 344
 345        return ERR_PTR(err);
 346}
 347
 348int mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
 349                       enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
 350{
 351        struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
 352        struct mlx5_ib_srq *srq = to_msrq(ibsrq);
 353        int ret;
 354
 355        /* We don't support resizing SRQs yet */
 356        if (attr_mask & IB_SRQ_MAX_WR)
 357                return -EINVAL;
 358
 359        if (attr_mask & IB_SRQ_LIMIT) {
 360                if (attr->srq_limit >= srq->msrq.max)
 361                        return -EINVAL;
 362
 363                mutex_lock(&srq->mutex);
 364                ret = mlx5_core_arm_srq(dev->mdev, &srq->msrq, attr->srq_limit, 1);
 365                mutex_unlock(&srq->mutex);
 366
 367                if (ret)
 368                        return ret;
 369        }
 370
 371        return 0;
 372}
 373
 374int mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
 375{
 376        struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
 377        struct mlx5_ib_srq *srq = to_msrq(ibsrq);
 378        int ret;
 379        struct mlx5_srq_attr *out;
 380
 381        out = kzalloc(sizeof(*out), GFP_KERNEL);
 382        if (!out)
 383                return -ENOMEM;
 384
 385        ret = mlx5_core_query_srq(dev->mdev, &srq->msrq, out);
 386        if (ret)
 387                goto out_box;
 388
 389        srq_attr->srq_limit = out->lwm;
 390        srq_attr->max_wr    = srq->msrq.max - 1;
 391        srq_attr->max_sge   = srq->msrq.max_gs;
 392
 393out_box:
 394        kfree(out);
 395        return ret;
 396}
 397
 398int mlx5_ib_destroy_srq(struct ib_srq *srq)
 399{
 400        struct mlx5_ib_dev *dev = to_mdev(srq->device);
 401        struct mlx5_ib_srq *msrq = to_msrq(srq);
 402
 403        mlx5_core_destroy_srq(dev->mdev, &msrq->msrq);
 404
 405        if (srq->uobject) {
 406                mlx5_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
 407                ib_umem_release(msrq->umem);
 408        } else {
 409                destroy_srq_kernel(dev, msrq);
 410        }
 411
 412        kfree(srq);
 413        return 0;
 414}
 415
 416void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index)
 417{
 418        struct mlx5_wqe_srq_next_seg *next;
 419
 420        /* always called with interrupts disabled. */
 421        spin_lock(&srq->lock);
 422
 423        next = get_wqe(srq, srq->tail);
 424        next->next_wqe_index = cpu_to_be16(wqe_index);
 425        srq->tail = wqe_index;
 426
 427        spin_unlock(&srq->lock);
 428}
 429
 430int mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
 431                          struct ib_recv_wr **bad_wr)
 432{
 433        struct mlx5_ib_srq *srq = to_msrq(ibsrq);
 434        struct mlx5_wqe_srq_next_seg *next;
 435        struct mlx5_wqe_data_seg *scat;
 436        struct mlx5_ib_dev *dev = to_mdev(ibsrq->device);
 437        struct mlx5_core_dev *mdev = dev->mdev;
 438        unsigned long flags;
 439        int err = 0;
 440        int nreq;
 441        int i;
 442
 443        spin_lock_irqsave(&srq->lock, flags);
 444
 445        if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
 446                err = -EIO;
 447                *bad_wr = wr;
 448                goto out;
 449        }
 450
 451        for (nreq = 0; wr; nreq++, wr = wr->next) {
 452                if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
 453                        err = -EINVAL;
 454                        *bad_wr = wr;
 455                        break;
 456                }
 457
 458                if (unlikely(srq->head == srq->tail)) {
 459                        err = -ENOMEM;
 460                        *bad_wr = wr;
 461                        break;
 462                }
 463
 464                srq->wrid[srq->head] = wr->wr_id;
 465
 466                next      = get_wqe(srq, srq->head);
 467                srq->head = be16_to_cpu(next->next_wqe_index);
 468                scat      = (struct mlx5_wqe_data_seg *)(next + 1);
 469
 470                for (i = 0; i < wr->num_sge; i++) {
 471                        scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
 472                        scat[i].lkey       = cpu_to_be32(wr->sg_list[i].lkey);
 473                        scat[i].addr       = cpu_to_be64(wr->sg_list[i].addr);
 474                }
 475
 476                if (i < srq->msrq.max_avail_gather) {
 477                        scat[i].byte_count = 0;
 478                        scat[i].lkey       = cpu_to_be32(MLX5_INVALID_LKEY);
 479                        scat[i].addr       = 0;
 480                }
 481        }
 482
 483        if (likely(nreq)) {
 484                srq->wqe_ctr += nreq;
 485
 486                /* Make sure that descriptors are written before
 487                 * doorbell record.
 488                 */
 489                wmb();
 490
 491                *srq->db.db = cpu_to_be32(srq->wqe_ctr);
 492        }
 493out:
 494        spin_unlock_irqrestore(&srq->lock, flags);
 495
 496        return err;
 497}
 498