• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/net/mlx4/
1/*
2 * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
3 * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses.  You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 *     Redistribution and use in source and binary forms, with or
12 *     without modification, are permitted provided that the following
13 *     conditions are met:
14 *
15 *      - Redistributions of source code must retain the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer.
18 *
19 *      - Redistributions in binary form must reproduce the above
20 *        copyright notice, this list of conditions and the following
21 *        disclaimer in the documentation and/or other materials
22 *        provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 */
33
34#include <linux/string.h>
35
36#include <linux/mlx4/cmd.h>
37
38#include "mlx4.h"
39
40#define MGM_QPN_MASK       0x00FFFFFF
41#define MGM_BLCK_LB_BIT    30
42
43struct mlx4_mgm {
44	__be32			next_gid_index;
45	__be32			members_count;
46	u32			reserved[2];
47	u8			gid[16];
48	__be32			qp[MLX4_QP_PER_MGM];
49};
50
51static const u8 zero_gid[16];	/* automatically initialized to 0 */
52
53static int mlx4_READ_MCG(struct mlx4_dev *dev, int index,
54			 struct mlx4_cmd_mailbox *mailbox)
55{
56	return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG,
57			    MLX4_CMD_TIME_CLASS_A);
58}
59
60static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index,
61			  struct mlx4_cmd_mailbox *mailbox)
62{
63	return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG,
64			MLX4_CMD_TIME_CLASS_A);
65}
66
67static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
68			  u16 *hash)
69{
70	u64 imm;
71	int err;
72
73	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, 0, MLX4_CMD_MGID_HASH,
74			   MLX4_CMD_TIME_CLASS_A);
75
76	if (!err)
77		*hash = imm;
78
79	return err;
80}
81
82/*
83 * Caller must hold MCG table semaphore.  gid and mgm parameters must
84 * be properly aligned for command interface.
85 *
86 *  Returns 0 unless a firmware command error occurs.
87 *
88 * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
89 * and *mgm holds MGM entry.
90 *
91 * if GID is found in AMGM, *index = index in AMGM, *prev = index of
92 * previous entry in hash chain and *mgm holds AMGM entry.
93 *
94 * If no AMGM exists for given gid, *index = -1, *prev = index of last
95 * entry in hash chain and *mgm holds end of hash chain.
96 */
97static int find_mgm(struct mlx4_dev *dev,
98		    u8 *gid, struct mlx4_cmd_mailbox *mgm_mailbox,
99		    u16 *hash, int *prev, int *index)
100{
101	struct mlx4_cmd_mailbox *mailbox;
102	struct mlx4_mgm *mgm = mgm_mailbox->buf;
103	u8 *mgid;
104	int err;
105
106	mailbox = mlx4_alloc_cmd_mailbox(dev);
107	if (IS_ERR(mailbox))
108		return -ENOMEM;
109	mgid = mailbox->buf;
110
111	memcpy(mgid, gid, 16);
112
113	err = mlx4_MGID_HASH(dev, mailbox, hash);
114	mlx4_free_cmd_mailbox(dev, mailbox);
115	if (err)
116		return err;
117
118	if (0)
119		mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);
120
121	*index = *hash;
122	*prev  = -1;
123
124	do {
125		err = mlx4_READ_MCG(dev, *index, mgm_mailbox);
126		if (err)
127			return err;
128
129		if (!memcmp(mgm->gid, zero_gid, 16)) {
130			if (*index != *hash) {
131				mlx4_err(dev, "Found zero MGID in AMGM.\n");
132				err = -EINVAL;
133			}
134			return err;
135		}
136
137		if (!memcmp(mgm->gid, gid, 16))
138			return err;
139
140		*prev = *index;
141		*index = be32_to_cpu(mgm->next_gid_index) >> 6;
142	} while (*index);
143
144	*index = -1;
145	return err;
146}
147
148int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
149			  int block_mcast_loopback)
150{
151	struct mlx4_priv *priv = mlx4_priv(dev);
152	struct mlx4_cmd_mailbox *mailbox;
153	struct mlx4_mgm *mgm;
154	u32 members_count;
155	u16 hash;
156	int index, prev;
157	int link = 0;
158	int i;
159	int err;
160
161	mailbox = mlx4_alloc_cmd_mailbox(dev);
162	if (IS_ERR(mailbox))
163		return PTR_ERR(mailbox);
164	mgm = mailbox->buf;
165
166	mutex_lock(&priv->mcg_table.mutex);
167
168	err = find_mgm(dev, gid, mailbox, &hash, &prev, &index);
169	if (err)
170		goto out;
171
172	if (index != -1) {
173		if (!memcmp(mgm->gid, zero_gid, 16))
174			memcpy(mgm->gid, gid, 16);
175	} else {
176		link = 1;
177
178		index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
179		if (index == -1) {
180			mlx4_err(dev, "No AMGM entries left\n");
181			err = -ENOMEM;
182			goto out;
183		}
184		index += dev->caps.num_mgms;
185
186		memset(mgm, 0, sizeof *mgm);
187		memcpy(mgm->gid, gid, 16);
188	}
189
190	members_count = be32_to_cpu(mgm->members_count);
191	if (members_count == MLX4_QP_PER_MGM) {
192		mlx4_err(dev, "MGM at index %x is full.\n", index);
193		err = -ENOMEM;
194		goto out;
195	}
196
197	for (i = 0; i < members_count; ++i)
198		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
199			mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
200			err = 0;
201			goto out;
202		}
203
204	if (block_mcast_loopback)
205		mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
206						       (1U << MGM_BLCK_LB_BIT));
207	else
208		mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);
209
210	mgm->members_count       = cpu_to_be32(members_count);
211
212	err = mlx4_WRITE_MCG(dev, index, mailbox);
213	if (err)
214		goto out;
215
216	if (!link)
217		goto out;
218
219	err = mlx4_READ_MCG(dev, prev, mailbox);
220	if (err)
221		goto out;
222
223	mgm->next_gid_index = cpu_to_be32(index << 6);
224
225	err = mlx4_WRITE_MCG(dev, prev, mailbox);
226	if (err)
227		goto out;
228
229out:
230	if (err && link && index != -1) {
231		if (index < dev->caps.num_mgms)
232			mlx4_warn(dev, "Got AMGM index %d < %d",
233				  index, dev->caps.num_mgms);
234		else
235			mlx4_bitmap_free(&priv->mcg_table.bitmap,
236					 index - dev->caps.num_mgms);
237	}
238	mutex_unlock(&priv->mcg_table.mutex);
239
240	mlx4_free_cmd_mailbox(dev, mailbox);
241	return err;
242}
243EXPORT_SYMBOL_GPL(mlx4_multicast_attach);
244
245int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16])
246{
247	struct mlx4_priv *priv = mlx4_priv(dev);
248	struct mlx4_cmd_mailbox *mailbox;
249	struct mlx4_mgm *mgm;
250	u32 members_count;
251	u16 hash;
252	int prev, index;
253	int i, loc;
254	int err;
255
256	mailbox = mlx4_alloc_cmd_mailbox(dev);
257	if (IS_ERR(mailbox))
258		return PTR_ERR(mailbox);
259	mgm = mailbox->buf;
260
261	mutex_lock(&priv->mcg_table.mutex);
262
263	err = find_mgm(dev, gid, mailbox, &hash, &prev, &index);
264	if (err)
265		goto out;
266
267	if (index == -1) {
268		mlx4_err(dev, "MGID %pI6 not found\n", gid);
269		err = -EINVAL;
270		goto out;
271	}
272
273	members_count = be32_to_cpu(mgm->members_count);
274	for (loc = -1, i = 0; i < members_count; ++i)
275		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn)
276			loc = i;
277
278	if (loc == -1) {
279		mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
280		err = -EINVAL;
281		goto out;
282	}
283
284
285	mgm->members_count = cpu_to_be32(--members_count);
286	mgm->qp[loc]       = mgm->qp[i - 1];
287	mgm->qp[i - 1]     = 0;
288
289	if (i != 1) {
290		err = mlx4_WRITE_MCG(dev, index, mailbox);
291		goto out;
292	}
293
294	if (prev == -1) {
295		/* Remove entry from MGM */
296		int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
297		if (amgm_index) {
298			err = mlx4_READ_MCG(dev, amgm_index, mailbox);
299			if (err)
300				goto out;
301		} else
302			memset(mgm->gid, 0, 16);
303
304		err = mlx4_WRITE_MCG(dev, index, mailbox);
305		if (err)
306			goto out;
307
308		if (amgm_index) {
309			if (amgm_index < dev->caps.num_mgms)
310				mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d",
311					  index, amgm_index, dev->caps.num_mgms);
312			else
313				mlx4_bitmap_free(&priv->mcg_table.bitmap,
314						 amgm_index - dev->caps.num_mgms);
315		}
316	} else {
317		/* Remove entry from AMGM */
318		int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
319		err = mlx4_READ_MCG(dev, prev, mailbox);
320		if (err)
321			goto out;
322
323		mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
324
325		err = mlx4_WRITE_MCG(dev, prev, mailbox);
326		if (err)
327			goto out;
328
329		if (index < dev->caps.num_mgms)
330			mlx4_warn(dev, "entry %d had next AMGM index %d < %d",
331				  prev, index, dev->caps.num_mgms);
332		else
333			mlx4_bitmap_free(&priv->mcg_table.bitmap,
334					 index - dev->caps.num_mgms);
335	}
336
337out:
338	mutex_unlock(&priv->mcg_table.mutex);
339
340	mlx4_free_cmd_mailbox(dev, mailbox);
341	return err;
342}
343EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
344
345int mlx4_init_mcg_table(struct mlx4_dev *dev)
346{
347	struct mlx4_priv *priv = mlx4_priv(dev);
348	int err;
349
350	err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
351			       dev->caps.num_amgms - 1, 0, 0);
352	if (err)
353		return err;
354
355	mutex_init(&priv->mcg_table.mutex);
356
357	return 0;
358}
359
360void mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
361{
362	mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
363}
364