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