diff options
Diffstat (limited to 'drivers/infiniband/hw/mthca/mthca_mcg.c')
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_mcg.c | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c new file mode 100644 index 000000000000..70a6553a588e --- /dev/null +++ b/drivers/infiniband/hw/mthca/mthca_mcg.c | |||
@@ -0,0 +1,376 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 Topspin Communications. 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 | * $Id: mthca_mcg.c 1349 2004-12-16 21:09:43Z roland $ | ||
33 | */ | ||
34 | |||
35 | #include <linux/init.h> | ||
36 | |||
37 | #include "mthca_dev.h" | ||
38 | #include "mthca_cmd.h" | ||
39 | |||
40 | enum { | ||
41 | MTHCA_QP_PER_MGM = 4 * (MTHCA_MGM_ENTRY_SIZE / 16 - 2) | ||
42 | }; | ||
43 | |||
44 | struct mthca_mgm { | ||
45 | u32 next_gid_index; | ||
46 | u32 reserved[3]; | ||
47 | u8 gid[16]; | ||
48 | u32 qp[MTHCA_QP_PER_MGM]; | ||
49 | }; | ||
50 | |||
51 | static const u8 zero_gid[16]; /* automatically initialized to 0 */ | ||
52 | |||
53 | /* | ||
54 | * Caller must hold MCG table semaphore. gid and mgm parameters must | ||
55 | * be properly aligned for command interface. | ||
56 | * | ||
57 | * Returns 0 unless a firmware command error occurs. | ||
58 | * | ||
59 | * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 | ||
60 | * and *mgm holds MGM entry. | ||
61 | * | ||
62 | * if GID is found in AMGM, *index = index in AMGM, *prev = index of | ||
63 | * previous entry in hash chain and *mgm holds AMGM entry. | ||
64 | * | ||
65 | * If no AMGM exists for given gid, *index = -1, *prev = index of last | ||
66 | * entry in hash chain and *mgm holds end of hash chain. | ||
67 | */ | ||
68 | static int find_mgm(struct mthca_dev *dev, | ||
69 | u8 *gid, struct mthca_mgm *mgm, | ||
70 | u16 *hash, int *prev, int *index) | ||
71 | { | ||
72 | void *mailbox; | ||
73 | u8 *mgid; | ||
74 | int err; | ||
75 | u8 status; | ||
76 | |||
77 | mailbox = kmalloc(16 + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL); | ||
78 | if (!mailbox) | ||
79 | return -ENOMEM; | ||
80 | mgid = MAILBOX_ALIGN(mailbox); | ||
81 | |||
82 | memcpy(mgid, gid, 16); | ||
83 | |||
84 | err = mthca_MGID_HASH(dev, mgid, hash, &status); | ||
85 | if (err) | ||
86 | goto out; | ||
87 | if (status) { | ||
88 | mthca_err(dev, "MGID_HASH returned status %02x\n", status); | ||
89 | err = -EINVAL; | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | if (0) | ||
94 | mthca_dbg(dev, "Hash for %04x:%04x:%04x:%04x:" | ||
95 | "%04x:%04x:%04x:%04x is %04x\n", | ||
96 | be16_to_cpu(((u16 *) gid)[0]), be16_to_cpu(((u16 *) gid)[1]), | ||
97 | be16_to_cpu(((u16 *) gid)[2]), be16_to_cpu(((u16 *) gid)[3]), | ||
98 | be16_to_cpu(((u16 *) gid)[4]), be16_to_cpu(((u16 *) gid)[5]), | ||
99 | be16_to_cpu(((u16 *) gid)[6]), be16_to_cpu(((u16 *) gid)[7]), | ||
100 | *hash); | ||
101 | |||
102 | *index = *hash; | ||
103 | *prev = -1; | ||
104 | |||
105 | do { | ||
106 | err = mthca_READ_MGM(dev, *index, mgm, &status); | ||
107 | if (err) | ||
108 | goto out; | ||
109 | if (status) { | ||
110 | mthca_err(dev, "READ_MGM returned status %02x\n", status); | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | |||
114 | if (!memcmp(mgm->gid, zero_gid, 16)) { | ||
115 | if (*index != *hash) { | ||
116 | mthca_err(dev, "Found zero MGID in AMGM.\n"); | ||
117 | err = -EINVAL; | ||
118 | } | ||
119 | goto out; | ||
120 | } | ||
121 | |||
122 | if (!memcmp(mgm->gid, gid, 16)) | ||
123 | goto out; | ||
124 | |||
125 | *prev = *index; | ||
126 | *index = be32_to_cpu(mgm->next_gid_index) >> 5; | ||
127 | } while (*index); | ||
128 | |||
129 | *index = -1; | ||
130 | |||
131 | out: | ||
132 | kfree(mailbox); | ||
133 | return err; | ||
134 | } | ||
135 | |||
136 | int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | ||
137 | { | ||
138 | struct mthca_dev *dev = to_mdev(ibqp->device); | ||
139 | void *mailbox; | ||
140 | struct mthca_mgm *mgm; | ||
141 | u16 hash; | ||
142 | int index, prev; | ||
143 | int link = 0; | ||
144 | int i; | ||
145 | int err; | ||
146 | u8 status; | ||
147 | |||
148 | mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL); | ||
149 | if (!mailbox) | ||
150 | return -ENOMEM; | ||
151 | mgm = MAILBOX_ALIGN(mailbox); | ||
152 | |||
153 | if (down_interruptible(&dev->mcg_table.sem)) | ||
154 | return -EINTR; | ||
155 | |||
156 | err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index); | ||
157 | if (err) | ||
158 | goto out; | ||
159 | |||
160 | if (index != -1) { | ||
161 | if (!memcmp(mgm->gid, zero_gid, 16)) | ||
162 | memcpy(mgm->gid, gid->raw, 16); | ||
163 | } else { | ||
164 | link = 1; | ||
165 | |||
166 | index = mthca_alloc(&dev->mcg_table.alloc); | ||
167 | if (index == -1) { | ||
168 | mthca_err(dev, "No AMGM entries left\n"); | ||
169 | err = -ENOMEM; | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | err = mthca_READ_MGM(dev, index, mgm, &status); | ||
174 | if (err) | ||
175 | goto out; | ||
176 | if (status) { | ||
177 | mthca_err(dev, "READ_MGM returned status %02x\n", status); | ||
178 | err = -EINVAL; | ||
179 | goto out; | ||
180 | } | ||
181 | |||
182 | memcpy(mgm->gid, gid->raw, 16); | ||
183 | mgm->next_gid_index = 0; | ||
184 | } | ||
185 | |||
186 | for (i = 0; i < MTHCA_QP_PER_MGM; ++i) | ||
187 | if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { | ||
188 | mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31)); | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | if (i == MTHCA_QP_PER_MGM) { | ||
193 | mthca_err(dev, "MGM at index %x is full.\n", index); | ||
194 | err = -ENOMEM; | ||
195 | goto out; | ||
196 | } | ||
197 | |||
198 | err = mthca_WRITE_MGM(dev, index, mgm, &status); | ||
199 | if (err) | ||
200 | goto out; | ||
201 | if (status) { | ||
202 | mthca_err(dev, "WRITE_MGM returned status %02x\n", status); | ||
203 | err = -EINVAL; | ||
204 | } | ||
205 | |||
206 | if (!link) | ||
207 | goto out; | ||
208 | |||
209 | err = mthca_READ_MGM(dev, prev, mgm, &status); | ||
210 | if (err) | ||
211 | goto out; | ||
212 | if (status) { | ||
213 | mthca_err(dev, "READ_MGM returned status %02x\n", status); | ||
214 | err = -EINVAL; | ||
215 | goto out; | ||
216 | } | ||
217 | |||
218 | mgm->next_gid_index = cpu_to_be32(index << 5); | ||
219 | |||
220 | err = mthca_WRITE_MGM(dev, prev, mgm, &status); | ||
221 | if (err) | ||
222 | goto out; | ||
223 | if (status) { | ||
224 | mthca_err(dev, "WRITE_MGM returned status %02x\n", status); | ||
225 | err = -EINVAL; | ||
226 | } | ||
227 | |||
228 | out: | ||
229 | up(&dev->mcg_table.sem); | ||
230 | kfree(mailbox); | ||
231 | return err; | ||
232 | } | ||
233 | |||
234 | int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | ||
235 | { | ||
236 | struct mthca_dev *dev = to_mdev(ibqp->device); | ||
237 | void *mailbox; | ||
238 | struct mthca_mgm *mgm; | ||
239 | u16 hash; | ||
240 | int prev, index; | ||
241 | int i, loc; | ||
242 | int err; | ||
243 | u8 status; | ||
244 | |||
245 | mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL); | ||
246 | if (!mailbox) | ||
247 | return -ENOMEM; | ||
248 | mgm = MAILBOX_ALIGN(mailbox); | ||
249 | |||
250 | if (down_interruptible(&dev->mcg_table.sem)) | ||
251 | return -EINTR; | ||
252 | |||
253 | err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index); | ||
254 | if (err) | ||
255 | goto out; | ||
256 | |||
257 | if (index == -1) { | ||
258 | mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " | ||
259 | "not found\n", | ||
260 | be16_to_cpu(((u16 *) gid->raw)[0]), | ||
261 | be16_to_cpu(((u16 *) gid->raw)[1]), | ||
262 | be16_to_cpu(((u16 *) gid->raw)[2]), | ||
263 | be16_to_cpu(((u16 *) gid->raw)[3]), | ||
264 | be16_to_cpu(((u16 *) gid->raw)[4]), | ||
265 | be16_to_cpu(((u16 *) gid->raw)[5]), | ||
266 | be16_to_cpu(((u16 *) gid->raw)[6]), | ||
267 | be16_to_cpu(((u16 *) gid->raw)[7])); | ||
268 | err = -EINVAL; | ||
269 | goto out; | ||
270 | } | ||
271 | |||
272 | for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) { | ||
273 | if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) | ||
274 | loc = i; | ||
275 | if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | if (loc == -1) { | ||
280 | mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num); | ||
281 | err = -EINVAL; | ||
282 | goto out; | ||
283 | } | ||
284 | |||
285 | mgm->qp[loc] = mgm->qp[i - 1]; | ||
286 | mgm->qp[i - 1] = 0; | ||
287 | |||
288 | err = mthca_WRITE_MGM(dev, index, mgm, &status); | ||
289 | if (err) | ||
290 | goto out; | ||
291 | if (status) { | ||
292 | mthca_err(dev, "WRITE_MGM returned status %02x\n", status); | ||
293 | err = -EINVAL; | ||
294 | goto out; | ||
295 | } | ||
296 | |||
297 | if (i != 1) | ||
298 | goto out; | ||
299 | |||
300 | goto out; | ||
301 | |||
302 | if (prev == -1) { | ||
303 | /* Remove entry from MGM */ | ||
304 | if (be32_to_cpu(mgm->next_gid_index) >> 5) { | ||
305 | err = mthca_READ_MGM(dev, | ||
306 | be32_to_cpu(mgm->next_gid_index) >> 5, | ||
307 | mgm, &status); | ||
308 | if (err) | ||
309 | goto out; | ||
310 | if (status) { | ||
311 | mthca_err(dev, "READ_MGM returned status %02x\n", | ||
312 | status); | ||
313 | err = -EINVAL; | ||
314 | goto out; | ||
315 | } | ||
316 | } else | ||
317 | memset(mgm->gid, 0, 16); | ||
318 | |||
319 | err = mthca_WRITE_MGM(dev, index, mgm, &status); | ||
320 | if (err) | ||
321 | goto out; | ||
322 | if (status) { | ||
323 | mthca_err(dev, "WRITE_MGM returned status %02x\n", status); | ||
324 | err = -EINVAL; | ||
325 | goto out; | ||
326 | } | ||
327 | } else { | ||
328 | /* Remove entry from AMGM */ | ||
329 | index = be32_to_cpu(mgm->next_gid_index) >> 5; | ||
330 | err = mthca_READ_MGM(dev, prev, mgm, &status); | ||
331 | if (err) | ||
332 | goto out; | ||
333 | if (status) { | ||
334 | mthca_err(dev, "READ_MGM returned status %02x\n", status); | ||
335 | err = -EINVAL; | ||
336 | goto out; | ||
337 | } | ||
338 | |||
339 | mgm->next_gid_index = cpu_to_be32(index << 5); | ||
340 | |||
341 | err = mthca_WRITE_MGM(dev, prev, mgm, &status); | ||
342 | if (err) | ||
343 | goto out; | ||
344 | if (status) { | ||
345 | mthca_err(dev, "WRITE_MGM returned status %02x\n", status); | ||
346 | err = -EINVAL; | ||
347 | goto out; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | out: | ||
352 | up(&dev->mcg_table.sem); | ||
353 | kfree(mailbox); | ||
354 | return err; | ||
355 | } | ||
356 | |||
357 | int __devinit mthca_init_mcg_table(struct mthca_dev *dev) | ||
358 | { | ||
359 | int err; | ||
360 | |||
361 | err = mthca_alloc_init(&dev->mcg_table.alloc, | ||
362 | dev->limits.num_amgms, | ||
363 | dev->limits.num_amgms - 1, | ||
364 | 0); | ||
365 | if (err) | ||
366 | return err; | ||
367 | |||
368 | init_MUTEX(&dev->mcg_table.sem); | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | void __devexit mthca_cleanup_mcg_table(struct mthca_dev *dev) | ||
374 | { | ||
375 | mthca_alloc_cleanup(&dev->mcg_table.alloc); | ||
376 | } | ||