linux/drivers/net/ethernet/mellanox/mlx4/srq.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2006, 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
  35#include <linux/mlx4/cmd.h>
  36#include <linux/mlx4/srq.h>
  37#include <linux/export.h>
  38#include <linux/gfp.h>
  39
  40#include "mlx4.h"
  41#include "icm.h"
  42
  43void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type)
  44{
  45        struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
  46        struct mlx4_srq *srq;
  47
  48        rcu_read_lock();
  49        srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1));
  50        rcu_read_unlock();
  51        if (srq)
  52                refcount_inc(&srq->refcount);
  53        else {
  54                mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn);
  55                return;
  56        }
  57
  58        srq->event(srq, event_type);
  59
  60        if (refcount_dec_and_test(&srq->refcount))
  61                complete(&srq->free);
  62}
  63
  64static int mlx4_SW2HW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
  65                          int srq_num)
  66{
  67        return mlx4_cmd(dev, mailbox->dma, srq_num, 0,
  68                        MLX4_CMD_SW2HW_SRQ, MLX4_CMD_TIME_CLASS_A,
  69                        MLX4_CMD_WRAPPED);
  70}
  71
  72static int mlx4_HW2SW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
  73                          int srq_num)
  74{
  75        return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, srq_num,
  76                            mailbox ? 0 : 1, MLX4_CMD_HW2SW_SRQ,
  77                            MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
  78}
  79
  80static int mlx4_ARM_SRQ(struct mlx4_dev *dev, int srq_num, int limit_watermark)
  81{
  82        return mlx4_cmd(dev, limit_watermark, srq_num, 0, MLX4_CMD_ARM_SRQ,
  83                        MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
  84}
  85
  86static int mlx4_QUERY_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
  87                          int srq_num)
  88{
  89        return mlx4_cmd_box(dev, 0, mailbox->dma, srq_num, 0, MLX4_CMD_QUERY_SRQ,
  90                            MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
  91}
  92
  93int __mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn)
  94{
  95        struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
  96        int err;
  97
  98
  99        *srqn = mlx4_bitmap_alloc(&srq_table->bitmap);
 100        if (*srqn == -1)
 101                return -ENOMEM;
 102
 103        err = mlx4_table_get(dev, &srq_table->table, *srqn);
 104        if (err)
 105                goto err_out;
 106
 107        err = mlx4_table_get(dev, &srq_table->cmpt_table, *srqn);
 108        if (err)
 109                goto err_put;
 110        return 0;
 111
 112err_put:
 113        mlx4_table_put(dev, &srq_table->table, *srqn);
 114
 115err_out:
 116        mlx4_bitmap_free(&srq_table->bitmap, *srqn, MLX4_NO_RR);
 117        return err;
 118}
 119
 120static int mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn)
 121{
 122        u64 out_param;
 123        int err;
 124
 125        if (mlx4_is_mfunc(dev)) {
 126                err = mlx4_cmd_imm(dev, 0, &out_param, RES_SRQ,
 127                                   RES_OP_RESERVE_AND_MAP,
 128                                   MLX4_CMD_ALLOC_RES,
 129                                   MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
 130                if (!err)
 131                        *srqn = get_param_l(&out_param);
 132
 133                return err;
 134        }
 135        return __mlx4_srq_alloc_icm(dev, srqn);
 136}
 137
 138void __mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn)
 139{
 140        struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 141
 142        mlx4_table_put(dev, &srq_table->cmpt_table, srqn);
 143        mlx4_table_put(dev, &srq_table->table, srqn);
 144        mlx4_bitmap_free(&srq_table->bitmap, srqn, MLX4_NO_RR);
 145}
 146
 147static void mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn)
 148{
 149        u64 in_param = 0;
 150
 151        if (mlx4_is_mfunc(dev)) {
 152                set_param_l(&in_param, srqn);
 153                if (mlx4_cmd(dev, in_param, RES_SRQ, RES_OP_RESERVE_AND_MAP,
 154                             MLX4_CMD_FREE_RES,
 155                             MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED))
 156                        mlx4_warn(dev, "Failed freeing cq:%d\n", srqn);
 157                return;
 158        }
 159        __mlx4_srq_free_icm(dev, srqn);
 160}
 161
 162int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd,
 163                   struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq)
 164{
 165        struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 166        struct mlx4_cmd_mailbox *mailbox;
 167        struct mlx4_srq_context *srq_context;
 168        u64 mtt_addr;
 169        int err;
 170
 171        err = mlx4_srq_alloc_icm(dev, &srq->srqn);
 172        if (err)
 173                return err;
 174
 175        spin_lock_irq(&srq_table->lock);
 176        err = radix_tree_insert(&srq_table->tree, srq->srqn, srq);
 177        spin_unlock_irq(&srq_table->lock);
 178        if (err)
 179                goto err_icm;
 180
 181        mailbox = mlx4_alloc_cmd_mailbox(dev);
 182        if (IS_ERR(mailbox)) {
 183                err = PTR_ERR(mailbox);
 184                goto err_radix;
 185        }
 186
 187        srq_context = mailbox->buf;
 188        srq_context->state_logsize_srqn = cpu_to_be32((ilog2(srq->max) << 24) |
 189                                                      srq->srqn);
 190        srq_context->logstride          = srq->wqe_shift - 4;
 191        srq_context->xrcd               = cpu_to_be16(xrcd);
 192        srq_context->pg_offset_cqn      = cpu_to_be32(cqn & 0xffffff);
 193        srq_context->log_page_size      = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
 194
 195        mtt_addr = mlx4_mtt_addr(dev, mtt);
 196        srq_context->mtt_base_addr_h    = mtt_addr >> 32;
 197        srq_context->mtt_base_addr_l    = cpu_to_be32(mtt_addr & 0xffffffff);
 198        srq_context->pd                 = cpu_to_be32(pdn);
 199        srq_context->db_rec_addr        = cpu_to_be64(db_rec);
 200
 201        err = mlx4_SW2HW_SRQ(dev, mailbox, srq->srqn);
 202        mlx4_free_cmd_mailbox(dev, mailbox);
 203        if (err)
 204                goto err_radix;
 205
 206        refcount_set(&srq->refcount, 1);
 207        init_completion(&srq->free);
 208
 209        return 0;
 210
 211err_radix:
 212        spin_lock_irq(&srq_table->lock);
 213        radix_tree_delete(&srq_table->tree, srq->srqn);
 214        spin_unlock_irq(&srq_table->lock);
 215
 216err_icm:
 217        mlx4_srq_free_icm(dev, srq->srqn);
 218        return err;
 219}
 220EXPORT_SYMBOL_GPL(mlx4_srq_alloc);
 221
 222void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq)
 223{
 224        struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 225        int err;
 226
 227        err = mlx4_HW2SW_SRQ(dev, NULL, srq->srqn);
 228        if (err)
 229                mlx4_warn(dev, "HW2SW_SRQ failed (%d) for SRQN %06x\n", err, srq->srqn);
 230
 231        spin_lock_irq(&srq_table->lock);
 232        radix_tree_delete(&srq_table->tree, srq->srqn);
 233        spin_unlock_irq(&srq_table->lock);
 234
 235        if (refcount_dec_and_test(&srq->refcount))
 236                complete(&srq->free);
 237        wait_for_completion(&srq->free);
 238
 239        mlx4_srq_free_icm(dev, srq->srqn);
 240}
 241EXPORT_SYMBOL_GPL(mlx4_srq_free);
 242
 243int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark)
 244{
 245        return mlx4_ARM_SRQ(dev, srq->srqn, limit_watermark);
 246}
 247EXPORT_SYMBOL_GPL(mlx4_srq_arm);
 248
 249int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark)
 250{
 251        struct mlx4_cmd_mailbox *mailbox;
 252        struct mlx4_srq_context *srq_context;
 253        int err;
 254
 255        mailbox = mlx4_alloc_cmd_mailbox(dev);
 256        if (IS_ERR(mailbox))
 257                return PTR_ERR(mailbox);
 258
 259        srq_context = mailbox->buf;
 260
 261        err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn);
 262        if (err)
 263                goto err_out;
 264        *limit_watermark = be16_to_cpu(srq_context->limit_watermark);
 265
 266err_out:
 267        mlx4_free_cmd_mailbox(dev, mailbox);
 268        return err;
 269}
 270EXPORT_SYMBOL_GPL(mlx4_srq_query);
 271
 272int mlx4_init_srq_table(struct mlx4_dev *dev)
 273{
 274        struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 275
 276        spin_lock_init(&srq_table->lock);
 277        INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC);
 278        if (mlx4_is_slave(dev))
 279                return 0;
 280
 281        return mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs,
 282                                dev->caps.num_srqs - 1, dev->caps.reserved_srqs, 0);
 283}
 284
 285void mlx4_cleanup_srq_table(struct mlx4_dev *dev)
 286{
 287        if (mlx4_is_slave(dev))
 288                return;
 289        mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap);
 290}
 291
 292struct mlx4_srq *mlx4_srq_lookup(struct mlx4_dev *dev, u32 srqn)
 293{
 294        struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 295        struct mlx4_srq *srq;
 296
 297        rcu_read_lock();
 298        srq = radix_tree_lookup(&srq_table->tree,
 299                                srqn & (dev->caps.num_srqs - 1));
 300        rcu_read_unlock();
 301
 302        return srq;
 303}
 304EXPORT_SYMBOL_GPL(mlx4_srq_lookup);
 305