mlx5_cq.c revision 337115
1/*-
2 * Copyright (c) 2013-2017, 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: stable/11/sys/dev/mlx5/mlx5_core/mlx5_cq.c 337115 2018-08-02 08:56:27Z hselasky $
26 */
27
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/hardirq.h>
31#include <dev/mlx5/driver.h>
32#include <rdma/ib_verbs.h>
33#include <dev/mlx5/cq.h>
34#include "mlx5_core.h"
35
36void mlx5_cq_completion(struct mlx5_core_dev *dev, u32 cqn)
37{
38	struct mlx5_core_cq *cq;
39	struct mlx5_cq_table *table = &dev->priv.cq_table;
40
41	if (cqn < MLX5_CQ_LINEAR_ARRAY_SIZE) {
42		struct mlx5_cq_linear_array_entry *entry;
43
44		entry = &table->linear_array[cqn];
45		spin_lock(&entry->lock);
46		cq = entry->cq;
47		if (cq == NULL) {
48			mlx5_core_warn(dev,
49			    "Completion event for bogus CQ 0x%x\n", cqn);
50		} else {
51			++cq->arm_sn;
52			cq->comp(cq);
53		}
54		spin_unlock(&entry->lock);
55		return;
56	}
57
58	spin_lock(&table->lock);
59	cq = radix_tree_lookup(&table->tree, cqn);
60	if (likely(cq))
61		atomic_inc(&cq->refcount);
62	spin_unlock(&table->lock);
63
64	if (!cq) {
65		mlx5_core_warn(dev, "Completion event for bogus CQ 0x%x\n", cqn);
66		return;
67	}
68
69	++cq->arm_sn;
70
71	cq->comp(cq);
72
73	if (atomic_dec_and_test(&cq->refcount))
74		complete(&cq->free);
75}
76
77void mlx5_cq_event(struct mlx5_core_dev *dev, u32 cqn, int event_type)
78{
79	struct mlx5_cq_table *table = &dev->priv.cq_table;
80	struct mlx5_core_cq *cq;
81
82	spin_lock(&table->lock);
83
84	cq = radix_tree_lookup(&table->tree, cqn);
85	if (cq)
86		atomic_inc(&cq->refcount);
87
88	spin_unlock(&table->lock);
89
90	if (!cq) {
91		mlx5_core_warn(dev, "Async event for bogus CQ 0x%x\n", cqn);
92		return;
93	}
94
95	cq->event(cq, event_type);
96
97	if (atomic_dec_and_test(&cq->refcount))
98		complete(&cq->free);
99}
100
101
102int mlx5_core_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
103			u32 *in, int inlen)
104{
105	struct mlx5_cq_table *table = &dev->priv.cq_table;
106	u32 out[MLX5_ST_SZ_DW(create_cq_out)] = {0};
107	u32 din[MLX5_ST_SZ_DW(destroy_cq_in)] = {0};
108	u32 dout[MLX5_ST_SZ_DW(destroy_cq_out)] = {0};
109	int err;
110
111	MLX5_SET(create_cq_in, in, opcode, MLX5_CMD_OP_CREATE_CQ);
112	err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
113	if (err)
114		return err;
115
116	cq->cqn = MLX5_GET(create_cq_out, out, cqn);
117	cq->cons_index = 0;
118	cq->arm_sn     = 0;
119	atomic_set(&cq->refcount, 1);
120	init_completion(&cq->free);
121
122	spin_lock_irq(&table->lock);
123	err = radix_tree_insert(&table->tree, cq->cqn, cq);
124	spin_unlock_irq(&table->lock);
125	if (err)
126		goto err_cmd;
127
128	if (cq->cqn < MLX5_CQ_LINEAR_ARRAY_SIZE) {
129		struct mlx5_cq_linear_array_entry *entry;
130
131		entry = &table->linear_array[cq->cqn];
132		spin_lock_irq(&entry->lock);
133		entry->cq = cq;
134		spin_unlock_irq(&entry->lock);
135	}
136
137	cq->pid = curthread->td_proc->p_pid;
138
139	return 0;
140
141err_cmd:
142	MLX5_SET(destroy_cq_in, din, opcode, MLX5_CMD_OP_DESTROY_CQ);
143	MLX5_SET(destroy_cq_in, din, cqn, cq->cqn);
144	mlx5_cmd_exec(dev, din, sizeof(din), dout, sizeof(dout));
145	return err;
146}
147EXPORT_SYMBOL(mlx5_core_create_cq);
148
149int mlx5_core_destroy_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq)
150{
151	struct mlx5_cq_table *table = &dev->priv.cq_table;
152	u32 out[MLX5_ST_SZ_DW(destroy_cq_out)] = {0};
153	u32 in[MLX5_ST_SZ_DW(destroy_cq_in)] = {0};
154	struct mlx5_core_cq *tmp;
155	int err;
156
157	if (cq->cqn < MLX5_CQ_LINEAR_ARRAY_SIZE) {
158		struct mlx5_cq_linear_array_entry *entry;
159
160		entry = &table->linear_array[cq->cqn];
161		spin_lock_irq(&entry->lock);
162		entry->cq = NULL;
163		spin_unlock_irq(&entry->lock);
164	}
165
166	spin_lock_irq(&table->lock);
167	tmp = radix_tree_delete(&table->tree, cq->cqn);
168	spin_unlock_irq(&table->lock);
169	if (!tmp) {
170		mlx5_core_warn(dev, "cq 0x%x not found in tree\n", cq->cqn);
171		return -EINVAL;
172	}
173	if (tmp != cq) {
174		mlx5_core_warn(dev, "corruption on srqn 0x%x\n", cq->cqn);
175		return -EINVAL;
176	}
177
178	MLX5_SET(destroy_cq_in, in, opcode, MLX5_CMD_OP_DESTROY_CQ);
179	MLX5_SET(destroy_cq_in, in, cqn, cq->cqn);
180	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
181	if (err)
182		goto out;
183
184	synchronize_irq(cq->irqn);
185
186	if (atomic_dec_and_test(&cq->refcount))
187		complete(&cq->free);
188	wait_for_completion(&cq->free);
189
190out:
191
192	return err;
193}
194EXPORT_SYMBOL(mlx5_core_destroy_cq);
195
196int mlx5_core_query_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
197		       u32 *out, int outlen)
198{
199	u32 in[MLX5_ST_SZ_DW(query_cq_in)] = {0};
200
201	MLX5_SET(query_cq_in, in, opcode, MLX5_CMD_OP_QUERY_CQ);
202	MLX5_SET(query_cq_in, in, cqn, cq->cqn);
203
204	return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
205}
206EXPORT_SYMBOL(mlx5_core_query_cq);
207
208
209int mlx5_core_modify_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
210			u32 *in, int inlen)
211{
212	u32 out[MLX5_ST_SZ_DW(modify_cq_out)] = {0};
213
214	MLX5_SET(modify_cq_in, in, opcode, MLX5_CMD_OP_MODIFY_CQ);
215	return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
216}
217EXPORT_SYMBOL(mlx5_core_modify_cq);
218
219int mlx5_core_modify_cq_moderation(struct mlx5_core_dev *dev,
220				   struct mlx5_core_cq *cq,
221				   u16 cq_period,
222				   u16 cq_max_count)
223{
224	u32 in[MLX5_ST_SZ_DW(modify_cq_in)] = {0};
225	void *cqc;
226
227	MLX5_SET(modify_cq_in, in, cqn, cq->cqn);
228	cqc = MLX5_ADDR_OF(modify_cq_in, in, cq_context);
229	MLX5_SET(cqc, cqc, cq_period, cq_period);
230	MLX5_SET(cqc, cqc, cq_max_count, cq_max_count);
231	MLX5_SET(modify_cq_in, in,
232		 modify_field_select_resize_field_select.modify_field_select.modify_field_select,
233		 MLX5_CQ_MODIFY_PERIOD | MLX5_CQ_MODIFY_COUNT);
234
235	return mlx5_core_modify_cq(dev, cq, in, sizeof(in));
236}
237
238int mlx5_core_modify_cq_moderation_mode(struct mlx5_core_dev *dev,
239					struct mlx5_core_cq *cq,
240					u16 cq_period,
241					u16 cq_max_count,
242					u8 cq_mode)
243{
244	u32 in[MLX5_ST_SZ_DW(modify_cq_in)] = {0};
245	void *cqc;
246
247	MLX5_SET(modify_cq_in, in, cqn, cq->cqn);
248	cqc = MLX5_ADDR_OF(modify_cq_in, in, cq_context);
249	MLX5_SET(cqc, cqc, cq_period, cq_period);
250	MLX5_SET(cqc, cqc, cq_max_count, cq_max_count);
251	MLX5_SET(cqc, cqc, cq_period_mode, cq_mode);
252	MLX5_SET(modify_cq_in, in,
253		 modify_field_select_resize_field_select.modify_field_select.modify_field_select,
254		 MLX5_CQ_MODIFY_PERIOD | MLX5_CQ_MODIFY_COUNT | MLX5_CQ_MODIFY_PERIOD_MODE);
255
256	return mlx5_core_modify_cq(dev, cq, in, sizeof(in));
257}
258
259int mlx5_init_cq_table(struct mlx5_core_dev *dev)
260{
261	struct mlx5_cq_table *table = &dev->priv.cq_table;
262	int err;
263	int x;
264
265	memset(table, 0, sizeof(*table));
266	spin_lock_init(&table->lock);
267	for (x = 0; x != MLX5_CQ_LINEAR_ARRAY_SIZE; x++)
268		spin_lock_init(&table->linear_array[x].lock);
269	INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
270	err = 0;
271
272	return err;
273}
274
275void mlx5_cleanup_cq_table(struct mlx5_core_dev *dev)
276{
277}
278