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