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/kernel.h> 34#include <linux/module.h> 35#include <linux/mlx5/driver.h> 36#include <linux/mlx5/cmd.h> 37#include <linux/mlx5/srq.h> 38#include <rdma/ib_verbs.h> 39#include "mlx5_core.h" 40 41void mlx5_srq_event(struct mlx5_core_dev *dev, u32 srqn, int event_type) 42{ 43 struct mlx5_srq_table *table = &dev->priv.srq_table; 44 struct mlx5_core_srq *srq; 45 46 spin_lock(&table->lock); 47 48 srq = radix_tree_lookup(&table->tree, srqn); 49 if (srq) 50 atomic_inc(&srq->refcount); 51 52 spin_unlock(&table->lock); 53 54 if (!srq) { 55 mlx5_core_warn(dev, "Async event for bogus SRQ 0x%08x\n", srqn); 56 return; 57 } 58 59 srq->event(srq, event_type); 60 61 if (atomic_dec_and_test(&srq->refcount)) 62 complete(&srq->free); 63} 64 65struct mlx5_core_srq *mlx5_core_get_srq(struct mlx5_core_dev *dev, u32 srqn) 66{ 67 struct mlx5_srq_table *table = &dev->priv.srq_table; 68 struct mlx5_core_srq *srq; 69 70 spin_lock(&table->lock); 71 72 srq = radix_tree_lookup(&table->tree, srqn); 73 if (srq) 74 atomic_inc(&srq->refcount); 75 76 spin_unlock(&table->lock); 77 78 return srq; 79} 80EXPORT_SYMBOL(mlx5_core_get_srq); 81 82int mlx5_core_create_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, 83 struct mlx5_create_srq_mbox_in *in, int inlen) 84{ 85 struct mlx5_create_srq_mbox_out out; 86 struct mlx5_srq_table *table = &dev->priv.srq_table; 87 struct mlx5_destroy_srq_mbox_in din; 88 struct mlx5_destroy_srq_mbox_out dout; 89 int err; 90 91 memset(&out, 0, sizeof(out)); 92 in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_SRQ); 93 err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); 94 if (err) 95 return err; 96 97 if (out.hdr.status) 98 return mlx5_cmd_status_to_err(&out.hdr); 99 100 srq->srqn = be32_to_cpu(out.srqn) & 0xffffff; 101 102 atomic_set(&srq->refcount, 1); 103 init_completion(&srq->free); 104 105 spin_lock_irq(&table->lock); 106 err = radix_tree_insert(&table->tree, srq->srqn, srq); 107 spin_unlock_irq(&table->lock); 108 if (err) { 109 mlx5_core_warn(dev, "err %d, srqn 0x%x\n", err, srq->srqn); 110 goto err_cmd; 111 } 112 113 return 0; 114 115err_cmd: 116 memset(&din, 0, sizeof(din)); 117 memset(&dout, 0, sizeof(dout)); 118 din.srqn = cpu_to_be32(srq->srqn); 119 din.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ); 120 mlx5_cmd_exec(dev, &din, sizeof(din), &dout, sizeof(dout)); 121 return err; 122} 123EXPORT_SYMBOL(mlx5_core_create_srq); 124 125int mlx5_core_destroy_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq) 126{ 127 struct mlx5_destroy_srq_mbox_in in; 128 struct mlx5_destroy_srq_mbox_out out; 129 struct mlx5_srq_table *table = &dev->priv.srq_table; 130 struct mlx5_core_srq *tmp; 131 int err; 132 133 spin_lock_irq(&table->lock); 134 tmp = radix_tree_delete(&table->tree, srq->srqn); 135 spin_unlock_irq(&table->lock); 136 if (!tmp) { 137 mlx5_core_warn(dev, "srq 0x%x not found in tree\n", srq->srqn); 138 return -EINVAL; 139 } 140 if (tmp != srq) { 141 mlx5_core_warn(dev, "corruption on srqn 0x%x\n", srq->srqn); 142 return -EINVAL; 143 } 144 145 memset(&in, 0, sizeof(in)); 146 memset(&out, 0, sizeof(out)); 147 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_SRQ); 148 in.srqn = cpu_to_be32(srq->srqn); 149 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 150 if (err) 151 return err; 152 153 if (out.hdr.status) 154 return mlx5_cmd_status_to_err(&out.hdr); 155 156 if (atomic_dec_and_test(&srq->refcount)) 157 complete(&srq->free); 158 wait_for_completion(&srq->free); 159 160 return 0; 161} 162EXPORT_SYMBOL(mlx5_core_destroy_srq); 163 164int mlx5_core_query_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, 165 struct mlx5_query_srq_mbox_out *out) 166{ 167 struct mlx5_query_srq_mbox_in in; 168 int err; 169 170 memset(&in, 0, sizeof(in)); 171 memset(out, 0, sizeof(*out)); 172 173 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SRQ); 174 in.srqn = cpu_to_be32(srq->srqn); 175 err = mlx5_cmd_exec(dev, &in, sizeof(in), out, sizeof(*out)); 176 if (err) 177 return err; 178 179 if (out->hdr.status) 180 return mlx5_cmd_status_to_err(&out->hdr); 181 182 return err; 183} 184EXPORT_SYMBOL(mlx5_core_query_srq); 185 186int mlx5_core_arm_srq(struct mlx5_core_dev *dev, struct mlx5_core_srq *srq, 187 u16 lwm, int is_srq) 188{ 189 struct mlx5_arm_srq_mbox_in in; 190 struct mlx5_arm_srq_mbox_out out; 191 int err; 192 193 memset(&in, 0, sizeof(in)); 194 memset(&out, 0, sizeof(out)); 195 196 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ARM_RQ); 197 in.hdr.opmod = cpu_to_be16(!!is_srq); 198 in.srqn = cpu_to_be32(srq->srqn); 199 in.lwm = cpu_to_be16(lwm); 200 201 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 202 if (err) 203 return err; 204 205 if (out.hdr.status) 206 return mlx5_cmd_status_to_err(&out.hdr); 207 208 return err; 209} 210EXPORT_SYMBOL(mlx5_core_arm_srq); 211 212void mlx5_init_srq_table(struct mlx5_core_dev *dev) 213{ 214 struct mlx5_srq_table *table = &dev->priv.srq_table; 215 216 spin_lock_init(&table->lock); 217 INIT_RADIX_TREE(&table->tree, GFP_ATOMIC); 218} 219 220void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev) 221{ 222 /* nothing */ 223} 224