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 "mlx5_core.h" 38 39void mlx5_init_mr_table(struct mlx5_core_dev *dev) 40{ 41 struct mlx5_mr_table *table = &dev->priv.mr_table; 42 43 rwlock_init(&table->lock); 44 INIT_RADIX_TREE(&table->tree, GFP_ATOMIC); 45} 46 47void mlx5_cleanup_mr_table(struct mlx5_core_dev *dev) 48{ 49} 50 51int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, 52 struct mlx5_create_mkey_mbox_in *in, int inlen, 53 mlx5_cmd_cbk_t callback, void *context, 54 struct mlx5_create_mkey_mbox_out *out) 55{ 56 struct mlx5_mr_table *table = &dev->priv.mr_table; 57 struct mlx5_create_mkey_mbox_out lout; 58 int err; 59 u8 key; 60 61 memset(&lout, 0, sizeof(lout)); 62 spin_lock_irq(&dev->priv.mkey_lock); 63 key = dev->priv.mkey_key++; 64 spin_unlock_irq(&dev->priv.mkey_lock); 65 in->seg.qpn_mkey7_0 |= cpu_to_be32(key); 66 in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_MKEY); 67 if (callback) { 68 err = mlx5_cmd_exec_cb(dev, in, inlen, out, sizeof(*out), 69 callback, context); 70 return err; 71 } else { 72 err = mlx5_cmd_exec(dev, in, inlen, &lout, sizeof(lout)); 73 } 74 75 if (err) { 76 mlx5_core_dbg(dev, "cmd exec failed %d\n", err); 77 return err; 78 } 79 80 if (lout.hdr.status) { 81 mlx5_core_dbg(dev, "status %d\n", lout.hdr.status); 82 return mlx5_cmd_status_to_err(&lout.hdr); 83 } 84 85 mr->iova = be64_to_cpu(in->seg.start_addr); 86 mr->size = be64_to_cpu(in->seg.len); 87 mr->key = mlx5_idx_to_mkey(be32_to_cpu(lout.mkey) & 0xffffff) | key; 88 mr->pd = be32_to_cpu(in->seg.flags_pd) & 0xffffff; 89 90 mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n", 91 be32_to_cpu(lout.mkey), key, mr->key); 92 93 /* connect to MR tree */ 94 write_lock_irq(&table->lock); 95 err = radix_tree_insert(&table->tree, mlx5_base_mkey(mr->key), mr); 96 write_unlock_irq(&table->lock); 97 if (err) { 98 mlx5_core_warn(dev, "failed radix tree insert of mr 0x%x, %d\n", 99 mlx5_base_mkey(mr->key), err); 100 mlx5_core_destroy_mkey(dev, mr); 101 } 102 103 return err; 104} 105EXPORT_SYMBOL(mlx5_core_create_mkey); 106 107int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr) 108{ 109 struct mlx5_mr_table *table = &dev->priv.mr_table; 110 struct mlx5_destroy_mkey_mbox_in in; 111 struct mlx5_destroy_mkey_mbox_out out; 112 struct mlx5_core_mr *deleted_mr; 113 unsigned long flags; 114 int err; 115 116 memset(&in, 0, sizeof(in)); 117 memset(&out, 0, sizeof(out)); 118 119 write_lock_irqsave(&table->lock, flags); 120 deleted_mr = radix_tree_delete(&table->tree, mlx5_base_mkey(mr->key)); 121 write_unlock_irqrestore(&table->lock, flags); 122 if (!deleted_mr) { 123 mlx5_core_warn(dev, "failed radix tree delete of mr 0x%x\n", 124 mlx5_base_mkey(mr->key)); 125 return -ENOENT; 126 } 127 128 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_MKEY); 129 in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key)); 130 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 131 if (err) 132 return err; 133 134 if (out.hdr.status) 135 return mlx5_cmd_status_to_err(&out.hdr); 136 137 return err; 138} 139EXPORT_SYMBOL(mlx5_core_destroy_mkey); 140 141int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, 142 struct mlx5_query_mkey_mbox_out *out, int outlen) 143{ 144 struct mlx5_query_mkey_mbox_in in; 145 int err; 146 147 memset(&in, 0, sizeof(in)); 148 memset(out, 0, outlen); 149 150 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_MKEY); 151 in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key)); 152 err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen); 153 if (err) 154 return err; 155 156 if (out->hdr.status) 157 return mlx5_cmd_status_to_err(&out->hdr); 158 159 return err; 160} 161EXPORT_SYMBOL(mlx5_core_query_mkey); 162 163int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, 164 u32 *mkey) 165{ 166 struct mlx5_query_special_ctxs_mbox_in in; 167 struct mlx5_query_special_ctxs_mbox_out out; 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_SPECIAL_CONTEXTS); 174 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 175 if (err) 176 return err; 177 178 if (out.hdr.status) 179 return mlx5_cmd_status_to_err(&out.hdr); 180 181 *mkey = be32_to_cpu(out.dump_fill_mkey); 182 183 return err; 184} 185EXPORT_SYMBOL(mlx5_core_dump_fill_mkey); 186 187int mlx5_core_create_psv(struct mlx5_core_dev *dev, u32 pdn, 188 int npsvs, u32 *sig_index) 189{ 190 struct mlx5_allocate_psv_in in; 191 struct mlx5_allocate_psv_out out; 192 int i, err; 193 194 if (npsvs > MLX5_MAX_PSVS) 195 return -EINVAL; 196 197 memset(&in, 0, sizeof(in)); 198 memset(&out, 0, sizeof(out)); 199 200 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_PSV); 201 in.npsv_pd = cpu_to_be32((npsvs << 28) | pdn); 202 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 203 if (err) { 204 mlx5_core_err(dev, "cmd exec failed %d\n", err); 205 return err; 206 } 207 208 if (out.hdr.status) { 209 mlx5_core_err(dev, "create_psv bad status %d\n", 210 out.hdr.status); 211 return mlx5_cmd_status_to_err(&out.hdr); 212 } 213 214 for (i = 0; i < npsvs; i++) 215 sig_index[i] = be32_to_cpu(out.psv_idx[i]) & 0xffffff; 216 217 return err; 218} 219EXPORT_SYMBOL(mlx5_core_create_psv); 220 221int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num) 222{ 223 struct mlx5_destroy_psv_in in; 224 struct mlx5_destroy_psv_out out; 225 int err; 226 227 memset(&in, 0, sizeof(in)); 228 memset(&out, 0, sizeof(out)); 229 230 in.psv_number = cpu_to_be32(psv_num); 231 in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_PSV); 232 err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); 233 if (err) { 234 mlx5_core_err(dev, "destroy_psv cmd exec failed %d\n", err); 235 goto out; 236 } 237 238 if (out.hdr.status) { 239 mlx5_core_err(dev, "destroy_psv bad status %d\n", 240 out.hdr.status); 241 err = mlx5_cmd_status_to_err(&out.hdr); 242 goto out; 243 } 244 245out: 246 return err; 247} 248EXPORT_SYMBOL(mlx5_core_destroy_psv); 249