Commit | Line | Data |
---|---|---|
e126ba97 EC |
1 | /* |
2 | * Copyright (c) 2013, Mellanox Technologies inc. 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 | ||
41 | void 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 | ||
65 | struct 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 | } | |
80 | EXPORT_SYMBOL(mlx5_core_get_srq); | |
81 | ||
82 | int 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 | ||
115 | err_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 | } | |
123 | EXPORT_SYMBOL(mlx5_core_create_srq); | |
124 | ||
125 | int 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 | } | |
162 | EXPORT_SYMBOL(mlx5_core_destroy_srq); | |
163 | ||
164 | int 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 | } | |
184 | EXPORT_SYMBOL(mlx5_core_query_srq); | |
185 | ||
186 | int 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 | } | |
210 | EXPORT_SYMBOL(mlx5_core_arm_srq); | |
211 | ||
212 | void 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 | ||
220 | void mlx5_cleanup_srq_table(struct mlx5_core_dev *dev) | |
221 | { | |
222 | /* nothing */ | |
223 | } |