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