linux/drivers/infiniband/hw/mlx4/srq.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
   3 * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
   4 *
   5 * This software is available to you under a choice of one of two
   6 * licenses.  You may choose to be licensed under the terms of the GNU
   7 * General Public License (GPL) Version 2, available from the file
   8 * COPYING in the main directory of this source tree, or the
   9 * OpenIB.org BSD license below:
  10 *
  11 *     Redistribution and use in source and binary forms, with or
  12 *     without modification, are permitted provided that the following
  13 *     conditions are met:
  14 *
  15 *      - Redistributions of source code must retain the above
  16 *        copyright notice, this list of conditions and the following
  17 *        disclaimer.
  18 *
  19 *      - Redistributions in binary form must reproduce the above
  20 *        copyright notice, this list of conditions and the following
  21 *        disclaimer in the documentation and/or other materials
  22 *        provided with the distribution.
  23 *
  24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31 * SOFTWARE.
  32 */
  33
  34#include <linux/mlx4/qp.h>
  35#include <linux/mlx4/srq.h>
  36
  37#include "mlx4_ib.h"
  38#include "user.h"
  39
  40static void *get_wqe(struct mlx4_ib_srq *srq, int n)
  41{
  42        return mlx4_buf_offset(&srq->buf, n << srq->msrq.wqe_shift);
  43}
  44
  45static void mlx4_ib_srq_event(struct mlx4_srq *srq, enum mlx4_event type)
  46{
  47        struct ib_event event;
  48        struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq;
  49
  50        if (ibsrq->event_handler) {
  51                event.device      = ibsrq->device;
  52                event.element.srq = ibsrq;
  53                switch (type) {
  54                case MLX4_EVENT_TYPE_SRQ_LIMIT:
  55                        event.event = IB_EVENT_SRQ_LIMIT_REACHED;
  56                        break;
  57                case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR:
  58                        event.event = IB_EVENT_SRQ_ERR;
  59                        break;
  60                default:
  61                        printk(KERN_WARNING "mlx4_ib: Unexpected event type %d "
  62                               "on SRQ %06x\n", type, srq->srqn);
  63                        return;
  64                }
  65
  66                ibsrq->event_handler(&event, ibsrq->srq_context);
  67        }
  68}
  69
  70struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
  71                                  struct ib_srq_init_attr *init_attr,
  72                                  struct ib_udata *udata)
  73{
  74        struct mlx4_ib_dev *dev = to_mdev(pd->device);
  75        struct mlx4_ib_srq *srq;
  76        struct mlx4_wqe_srq_next_seg *next;
  77        int desc_size;
  78        int buf_size;
  79        int err;
  80        int i;
  81
  82        /* Sanity check SRQ size before proceeding */
  83        if (init_attr->attr.max_wr  >= dev->dev->caps.max_srq_wqes ||
  84            init_attr->attr.max_sge >  dev->dev->caps.max_srq_sge)
  85                return ERR_PTR(-EINVAL);
  86
  87        srq = kmalloc(sizeof *srq, GFP_KERNEL);
  88        if (!srq)
  89                return ERR_PTR(-ENOMEM);
  90
  91        mutex_init(&srq->mutex);
  92        spin_lock_init(&srq->lock);
  93        srq->msrq.max    = roundup_pow_of_two(init_attr->attr.max_wr + 1);
  94        srq->msrq.max_gs = init_attr->attr.max_sge;
  95
  96        desc_size = max(32UL,
  97                        roundup_pow_of_two(sizeof (struct mlx4_wqe_srq_next_seg) +
  98                                           srq->msrq.max_gs *
  99                                           sizeof (struct mlx4_wqe_data_seg)));
 100        srq->msrq.wqe_shift = ilog2(desc_size);
 101
 102        buf_size = srq->msrq.max * desc_size;
 103
 104        if (pd->uobject) {
 105                struct mlx4_ib_create_srq ucmd;
 106
 107                if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
 108                        err = -EFAULT;
 109                        goto err_srq;
 110                }
 111
 112                srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
 113                                        buf_size, 0, 0);
 114                if (IS_ERR(srq->umem)) {
 115                        err = PTR_ERR(srq->umem);
 116                        goto err_srq;
 117                }
 118
 119                err = mlx4_mtt_init(dev->dev, ib_umem_page_count(srq->umem),
 120                                    ilog2(srq->umem->page_size), &srq->mtt);
 121                if (err)
 122                        goto err_buf;
 123
 124                err = mlx4_ib_umem_write_mtt(dev, &srq->mtt, srq->umem);
 125                if (err)
 126                        goto err_mtt;
 127
 128                err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context),
 129                                          ucmd.db_addr, &srq->db);
 130                if (err)
 131                        goto err_mtt;
 132        } else {
 133                err = mlx4_db_alloc(dev->dev, &srq->db, 0);
 134                if (err)
 135                        goto err_srq;
 136
 137                *srq->db.db = 0;
 138
 139                if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &srq->buf)) {
 140                        err = -ENOMEM;
 141                        goto err_db;
 142                }
 143
 144                srq->head    = 0;
 145                srq->tail    = srq->msrq.max - 1;
 146                srq->wqe_ctr = 0;
 147
 148                for (i = 0; i < srq->msrq.max; ++i) {
 149                        next = get_wqe(srq, i);
 150                        next->next_wqe_index =
 151                                cpu_to_be16((i + 1) & (srq->msrq.max - 1));
 152                }
 153
 154                err = mlx4_mtt_init(dev->dev, srq->buf.npages, srq->buf.page_shift,
 155                                    &srq->mtt);
 156                if (err)
 157                        goto err_buf;
 158
 159                err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf);
 160                if (err)
 161                        goto err_mtt;
 162
 163                srq->wrid = kmalloc(srq->msrq.max * sizeof (u64), GFP_KERNEL);
 164                if (!srq->wrid) {
 165                        err = -ENOMEM;
 166                        goto err_mtt;
 167                }
 168        }
 169
 170        err = mlx4_srq_alloc(dev->dev, to_mpd(pd)->pdn, &srq->mtt,
 171                             srq->db.dma, &srq->msrq);
 172        if (err)
 173                goto err_wrid;
 174
 175        srq->msrq.event = mlx4_ib_srq_event;
 176
 177        if (pd->uobject)
 178                if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) {
 179                        err = -EFAULT;
 180                        goto err_wrid;
 181                }
 182
 183        init_attr->attr.max_wr = srq->msrq.max - 1;
 184
 185        return &srq->ibsrq;
 186
 187err_wrid:
 188        if (pd->uobject)
 189                mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db);
 190        else
 191                kfree(srq->wrid);
 192
 193err_mtt:
 194        mlx4_mtt_cleanup(dev->dev, &srq->mtt);
 195
 196err_buf:
 197        if (pd->uobject)
 198                ib_umem_release(srq->umem);
 199        else
 200                mlx4_buf_free(dev->dev, buf_size, &srq->buf);
 201
 202err_db:
 203        if (!pd->uobject)
 204                mlx4_db_free(dev->dev, &srq->db);
 205
 206err_srq:
 207        kfree(srq);
 208
 209        return ERR_PTR(err);
 210}
 211
 212int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
 213                       enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
 214{
 215        struct mlx4_ib_dev *dev = to_mdev(ibsrq->device);
 216        struct mlx4_ib_srq *srq = to_msrq(ibsrq);
 217        int ret;
 218
 219        /* We don't support resizing SRQs (yet?) */
 220        if (attr_mask & IB_SRQ_MAX_WR)
 221                return -EINVAL;
 222
 223        if (attr_mask & IB_SRQ_LIMIT) {
 224                if (attr->srq_limit >= srq->msrq.max)
 225                        return -EINVAL;
 226
 227                mutex_lock(&srq->mutex);
 228                ret = mlx4_srq_arm(dev->dev, &srq->msrq, attr->srq_limit);
 229                mutex_unlock(&srq->mutex);
 230
 231                if (ret)
 232                        return ret;
 233        }
 234
 235        return 0;
 236}
 237
 238int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
 239{
 240        struct mlx4_ib_dev *dev = to_mdev(ibsrq->device);
 241        struct mlx4_ib_srq *srq = to_msrq(ibsrq);
 242        int ret;
 243        int limit_watermark;
 244
 245        ret = mlx4_srq_query(dev->dev, &srq->msrq, &limit_watermark);
 246        if (ret)
 247                return ret;
 248
 249        srq_attr->srq_limit = limit_watermark;
 250        srq_attr->max_wr    = srq->msrq.max - 1;
 251        srq_attr->max_sge   = srq->msrq.max_gs;
 252
 253        return 0;
 254}
 255
 256int mlx4_ib_destroy_srq(struct ib_srq *srq)
 257{
 258        struct mlx4_ib_dev *dev = to_mdev(srq->device);
 259        struct mlx4_ib_srq *msrq = to_msrq(srq);
 260
 261        mlx4_srq_free(dev->dev, &msrq->msrq);
 262        mlx4_mtt_cleanup(dev->dev, &msrq->mtt);
 263
 264        if (srq->uobject) {
 265                mlx4_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
 266                ib_umem_release(msrq->umem);
 267        } else {
 268                kfree(msrq->wrid);
 269                mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift,
 270                              &msrq->buf);
 271                mlx4_db_free(dev->dev, &msrq->db);
 272        }
 273
 274        kfree(msrq);
 275
 276        return 0;
 277}
 278
 279void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index)
 280{
 281        struct mlx4_wqe_srq_next_seg *next;
 282
 283        /* always called with interrupts disabled. */
 284        spin_lock(&srq->lock);
 285
 286        next = get_wqe(srq, srq->tail);
 287        next->next_wqe_index = cpu_to_be16(wqe_index);
 288        srq->tail = wqe_index;
 289
 290        spin_unlock(&srq->lock);
 291}
 292
 293int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
 294                          struct ib_recv_wr **bad_wr)
 295{
 296        struct mlx4_ib_srq *srq = to_msrq(ibsrq);
 297        struct mlx4_wqe_srq_next_seg *next;
 298        struct mlx4_wqe_data_seg *scat;
 299        unsigned long flags;
 300        int err = 0;
 301        int nreq;
 302        int i;
 303
 304        spin_lock_irqsave(&srq->lock, flags);
 305
 306        for (nreq = 0; wr; ++nreq, wr = wr->next) {
 307                if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
 308                        err = -EINVAL;
 309                        *bad_wr = wr;
 310                        break;
 311                }
 312
 313                if (unlikely(srq->head == srq->tail)) {
 314                        err = -ENOMEM;
 315                        *bad_wr = wr;
 316                        break;
 317                }
 318
 319                srq->wrid[srq->head] = wr->wr_id;
 320
 321                next      = get_wqe(srq, srq->head);
 322                srq->head = be16_to_cpu(next->next_wqe_index);
 323                scat      = (struct mlx4_wqe_data_seg *) (next + 1);
 324
 325                for (i = 0; i < wr->num_sge; ++i) {
 326                        scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
 327                        scat[i].lkey       = cpu_to_be32(wr->sg_list[i].lkey);
 328                        scat[i].addr       = cpu_to_be64(wr->sg_list[i].addr);
 329                }
 330
 331                if (i < srq->msrq.max_gs) {
 332                        scat[i].byte_count = 0;
 333                        scat[i].lkey       = cpu_to_be32(MLX4_INVALID_LKEY);
 334                        scat[i].addr       = 0;
 335                }
 336        }
 337
 338        if (likely(nreq)) {
 339                srq->wqe_ctr += nreq;
 340
 341                /*
 342                 * Make sure that descriptors are written before
 343                 * doorbell record.
 344                 */
 345                wmb();
 346
 347                *srq->db.db = cpu_to_be32(srq->wqe_ctr);
 348        }
 349
 350        spin_unlock_irqrestore(&srq->lock, flags);
 351
 352        return err;
 353}
 354