1/*-
2 * Copyright (c) 2013-2015, Mellanox Technologies, Ltd.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD: releng/10.3/sys/dev/mlx5/mlx5_core/mlx5_mr.c 290650 2015-11-10 12:20:22Z hselasky $
26 */
27
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <dev/mlx5/driver.h>
31#include "mlx5_core.h"
32
33void mlx5_init_mr_table(struct mlx5_core_dev *dev)
34{
35	struct mlx5_mr_table *table = &dev->priv.mr_table;
36
37	rwlock_init(&table->lock);
38	INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
39}
40
41void mlx5_cleanup_mr_table(struct mlx5_core_dev *dev)
42{
43}
44
45int mlx5_core_create_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
46			  struct mlx5_create_mkey_mbox_in *in, int inlen,
47			  mlx5_cmd_cbk_t callback, void *context,
48			  struct mlx5_create_mkey_mbox_out *out)
49{
50	struct mlx5_mr_table *table = &dev->priv.mr_table;
51	struct mlx5_create_mkey_mbox_out lout;
52	int err;
53	u8 key;
54	unsigned long irql;
55
56	memset(&lout, 0, sizeof(lout));
57	spin_lock_irq(&dev->priv.mkey_lock);
58	key = dev->priv.mkey_key++;
59	spin_unlock_irq(&dev->priv.mkey_lock);
60	in->seg.qpn_mkey7_0 |= cpu_to_be32(key);
61	in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_MKEY);
62	if (callback) {
63		err = mlx5_cmd_exec_cb(dev, in, inlen, out, sizeof(*out),
64				       callback, context);
65		return err;
66	} else {
67		err = mlx5_cmd_exec(dev, in, inlen, &lout, sizeof(lout));
68	}
69
70	if (err) {
71		mlx5_core_dbg(dev, "cmd exec failed %d\n", err);
72		return err;
73	}
74
75	if (lout.hdr.status) {
76		mlx5_core_dbg(dev, "status %d\n", lout.hdr.status);
77		return mlx5_cmd_status_to_err(&lout.hdr);
78	}
79
80	mr->iova = be64_to_cpu(in->seg.start_addr);
81	mr->size = be64_to_cpu(in->seg.len);
82	mr->key = mlx5_idx_to_mkey(be32_to_cpu(lout.mkey) & 0xffffff) | key;
83	mr->pd = be32_to_cpu(in->seg.flags_pd) & 0xffffff;
84
85	mlx5_core_dbg(dev, "out 0x%x, key 0x%x, mkey 0x%x\n",
86		      be32_to_cpu(lout.mkey), key, mr->key);
87
88	/* connect to MR tree */
89	write_lock_irqsave(&table->lock, irql);
90	err = radix_tree_insert(&table->tree, mlx5_base_mkey(mr->key), mr);
91	write_unlock_irqrestore(&table->lock, irql);
92	if (err) {
93		mlx5_core_warn(dev, "failed radix tree insert of mr 0x%x, %d\n",
94			       mlx5_base_mkey(mr->key), err);
95		mlx5_core_destroy_mkey(dev, mr);
96	}
97
98	return err;
99}
100EXPORT_SYMBOL(mlx5_core_create_mkey);
101
102int mlx5_core_destroy_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr)
103{
104	struct mlx5_mr_table *table = &dev->priv.mr_table;
105	u32 in[MLX5_ST_SZ_DW(destroy_mkey_in)];
106	u32 out[MLX5_ST_SZ_DW(destroy_mkey_out)];
107	struct mlx5_core_mr *deleted_mr;
108	unsigned long flags;
109
110	memset(in, 0, sizeof(in));
111
112	write_lock_irqsave(&table->lock, flags);
113	deleted_mr = radix_tree_delete(&table->tree, mlx5_base_mkey(mr->key));
114	write_unlock_irqrestore(&table->lock, flags);
115	if (!deleted_mr) {
116		mlx5_core_warn(dev, "failed radix tree delete of mr 0x%x\n",
117			       mlx5_base_mkey(mr->key));
118		return -ENOENT;
119	}
120
121	MLX5_SET(destroy_mkey_in, in, opcode, MLX5_CMD_OP_DESTROY_MKEY);
122	MLX5_SET(destroy_mkey_in, in, mkey_index, mlx5_mkey_to_idx(mr->key));
123
124	memset(out, 0, sizeof(out));
125	return mlx5_cmd_exec_check_status(dev, in,  sizeof(in),
126					       out, sizeof(out));
127}
128EXPORT_SYMBOL(mlx5_core_destroy_mkey);
129
130int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
131			 struct mlx5_query_mkey_mbox_out *out, int outlen)
132{
133	struct mlx5_query_mkey_mbox_in in;
134	int err;
135
136	memset(&in, 0, sizeof(in));
137	memset(out, 0, outlen);
138
139	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_MKEY);
140	in.mkey = cpu_to_be32(mlx5_mkey_to_idx(mr->key));
141	err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
142	if (err)
143		return err;
144
145	if (out->hdr.status)
146		return mlx5_cmd_status_to_err(&out->hdr);
147
148	return err;
149}
150EXPORT_SYMBOL(mlx5_core_query_mkey);
151
152int mlx5_core_dump_fill_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr,
153			     u32 *mkey)
154{
155	struct mlx5_query_special_ctxs_mbox_in in;
156	struct mlx5_query_special_ctxs_mbox_out out;
157	int err;
158
159	memset(&in, 0, sizeof(in));
160	memset(&out, 0, sizeof(out));
161
162	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
163	err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
164	if (err)
165		return err;
166
167	if (out.hdr.status)
168		return mlx5_cmd_status_to_err(&out.hdr);
169
170	*mkey = be32_to_cpu(out.dump_fill_mkey);
171
172	return err;
173}
174EXPORT_SYMBOL(mlx5_core_dump_fill_mkey);
175
176int mlx5_core_create_psv(struct mlx5_core_dev *dev, u32 pdn,
177			 int npsvs, u32 *sig_index)
178{
179	struct mlx5_allocate_psv_in in;
180	struct mlx5_allocate_psv_out out;
181	int i, err;
182
183	if (npsvs > MLX5_MAX_PSVS)
184		return -EINVAL;
185
186	memset(&in, 0, sizeof(in));
187	memset(&out, 0, sizeof(out));
188
189	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_CREATE_PSV);
190	in.npsv_pd = cpu_to_be32((npsvs << 28) | pdn);
191	err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
192	if (err) {
193		mlx5_core_err(dev, "cmd exec failed %d\n", err);
194		return err;
195	}
196
197	if (out.hdr.status) {
198		mlx5_core_err(dev, "create_psv bad status %d\n",
199			      out.hdr.status);
200		return mlx5_cmd_status_to_err(&out.hdr);
201	}
202
203	for (i = 0; i < npsvs; i++)
204		sig_index[i] = be32_to_cpu(out.psv_idx[i]) & 0xffffff;
205
206	return err;
207}
208EXPORT_SYMBOL(mlx5_core_create_psv);
209
210int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num)
211{
212	struct mlx5_destroy_psv_in in;
213	struct mlx5_destroy_psv_out out;
214	int err;
215
216	memset(&in, 0, sizeof(in));
217	memset(&out, 0, sizeof(out));
218
219	in.psv_number = cpu_to_be32(psv_num);
220	in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DESTROY_PSV);
221	err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
222	if (err) {
223		mlx5_core_err(dev, "destroy_psv cmd exec failed %d\n", err);
224		goto out;
225	}
226
227	if (out.hdr.status) {
228		mlx5_core_err(dev, "destroy_psv bad status %d\n",
229			      out.hdr.status);
230		err = mlx5_cmd_status_to_err(&out.hdr);
231		goto out;
232	}
233
234out:
235	return err;
236}
237EXPORT_SYMBOL(mlx5_core_destroy_psv);
238