1/*
2 * Copyright (c) 2006, 2007 Cisco Systems, 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/init.h>
34#include <linux/string.h>
35#include <linux/slab.h>
36
37#include <linux/mlx4/cmd.h>
38
39#include "mlx4.h"
40
41struct mlx4_mgm {
42	__be32			next_gid_index;
43	__be32			members_count;
44	u32			reserved[2];
45	u8			gid[16];
46	__be32			qp[MLX4_QP_PER_MGM];
47};
48
49static const u8 zero_gid[16];	/* automatically initialized to 0 */
50
51static int mlx4_READ_MCG(struct mlx4_dev *dev, int index,
52			 struct mlx4_cmd_mailbox *mailbox)
53{
54	return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG,
55			    MLX4_CMD_TIME_CLASS_A);
56}
57
58static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index,
59			  struct mlx4_cmd_mailbox *mailbox)
60{
61	return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG,
62			MLX4_CMD_TIME_CLASS_A);
63}
64
65static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
66			  u16 *hash)
67{
68	u64 imm;
69	int err;
70
71	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, 0, MLX4_CMD_MGID_HASH,
72			   MLX4_CMD_TIME_CLASS_A);
73
74	if (!err)
75		*hash = imm;
76
77	return err;
78}
79
80/*
81 * Caller must hold MCG table semaphore.  gid and mgm parameters must
82 * be properly aligned for command interface.
83 *
84 *  Returns 0 unless a firmware command error occurs.
85 *
86 * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
87 * and *mgm holds MGM entry.
88 *
89 * if GID is found in AMGM, *index = index in AMGM, *prev = index of
90 * previous entry in hash chain and *mgm holds AMGM entry.
91 *
92 * If no AMGM exists for given gid, *index = -1, *prev = index of last
93 * entry in hash chain and *mgm holds end of hash chain.
94 */
95static int find_mgm(struct mlx4_dev *dev,
96		    u8 *gid, struct mlx4_cmd_mailbox *mgm_mailbox,
97		    u16 *hash, int *prev, int *index)
98{
99	struct mlx4_cmd_mailbox *mailbox;
100	struct mlx4_mgm *mgm = mgm_mailbox->buf;
101	u8 *mgid;
102	int err;
103
104	mailbox = mlx4_alloc_cmd_mailbox(dev);
105	if (IS_ERR(mailbox))
106		return -ENOMEM;
107	mgid = mailbox->buf;
108
109	memcpy(mgid, gid, 16);
110
111	err = mlx4_MGID_HASH(dev, mailbox, hash);
112	mlx4_free_cmd_mailbox(dev, mailbox);
113	if (err)
114		return err;
115
116	if (0)
117		mlx4_dbg(dev, "Hash for %04x:%04x:%04x:%04x:"
118			  "%04x:%04x:%04x:%04x is %04x\n",
119			  be16_to_cpu(((__be16 *) gid)[0]),
120			  be16_to_cpu(((__be16 *) gid)[1]),
121			  be16_to_cpu(((__be16 *) gid)[2]),
122			  be16_to_cpu(((__be16 *) gid)[3]),
123			  be16_to_cpu(((__be16 *) gid)[4]),
124			  be16_to_cpu(((__be16 *) gid)[5]),
125			  be16_to_cpu(((__be16 *) gid)[6]),
126			  be16_to_cpu(((__be16 *) gid)[7]),
127			  *hash);
128
129	*index = *hash;
130	*prev  = -1;
131
132	do {
133		err = mlx4_READ_MCG(dev, *index, mgm_mailbox);
134		if (err)
135			return err;
136
137		if (!memcmp(mgm->gid, zero_gid, 16)) {
138			if (*index != *hash) {
139				mlx4_err(dev, "Found zero MGID in AMGM.\n");
140				err = -EINVAL;
141			}
142			return err;
143		}
144
145		if (!memcmp(mgm->gid, gid, 16))
146			return err;
147
148		*prev = *index;
149		*index = be32_to_cpu(mgm->next_gid_index) >> 6;
150	} while (*index);
151
152	*index = -1;
153	return err;
154}
155
156int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16])
157{
158	struct mlx4_priv *priv = mlx4_priv(dev);
159	struct mlx4_cmd_mailbox *mailbox;
160	struct mlx4_mgm *mgm;
161	u32 members_count;
162	u16 hash;
163	int index, prev;
164	int link = 0;
165	int i;
166	int err;
167
168	mailbox = mlx4_alloc_cmd_mailbox(dev);
169	if (IS_ERR(mailbox))
170		return PTR_ERR(mailbox);
171	mgm = mailbox->buf;
172
173	mutex_lock(&priv->mcg_table.mutex);
174
175	err = find_mgm(dev, gid, mailbox, &hash, &prev, &index);
176	if (err)
177		goto out;
178
179	if (index != -1) {
180		if (!memcmp(mgm->gid, zero_gid, 16))
181			memcpy(mgm->gid, gid, 16);
182	} else {
183		link = 1;
184
185		index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
186		if (index == -1) {
187			mlx4_err(dev, "No AMGM entries left\n");
188			err = -ENOMEM;
189			goto out;
190		}
191		index += dev->caps.num_mgms;
192
193		err = mlx4_READ_MCG(dev, index, mailbox);
194		if (err)
195			goto out;
196
197		memset(mgm, 0, sizeof *mgm);
198		memcpy(mgm->gid, gid, 16);
199	}
200
201	members_count = be32_to_cpu(mgm->members_count);
202	if (members_count == MLX4_QP_PER_MGM) {
203		mlx4_err(dev, "MGM at index %x is full.\n", index);
204		err = -ENOMEM;
205		goto out;
206	}
207
208	for (i = 0; i < members_count; ++i)
209		if (mgm->qp[i] == cpu_to_be32(qp->qpn)) {
210			mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
211			err = 0;
212			goto out;
213		}
214
215	mgm->qp[members_count++] = cpu_to_be32(qp->qpn);
216	mgm->members_count       = cpu_to_be32(members_count);
217
218	err = mlx4_WRITE_MCG(dev, index, mailbox);
219	if (err)
220		goto out;
221
222	if (!link)
223		goto out;
224
225	err = mlx4_READ_MCG(dev, prev, mailbox);
226	if (err)
227		goto out;
228
229	mgm->next_gid_index = cpu_to_be32(index << 6);
230
231	err = mlx4_WRITE_MCG(dev, prev, mailbox);
232	if (err)
233		goto out;
234
235out:
236	if (err && link && index != -1) {
237		if (index < dev->caps.num_mgms)
238			mlx4_warn(dev, "Got AMGM index %d < %d",
239				  index, dev->caps.num_mgms);
240		else
241			mlx4_bitmap_free(&priv->mcg_table.bitmap,
242					 index - dev->caps.num_mgms);
243	}
244	mutex_unlock(&priv->mcg_table.mutex);
245
246	mlx4_free_cmd_mailbox(dev, mailbox);
247	return err;
248}
249EXPORT_SYMBOL_GPL(mlx4_multicast_attach);
250
251int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16])
252{
253	struct mlx4_priv *priv = mlx4_priv(dev);
254	struct mlx4_cmd_mailbox *mailbox;
255	struct mlx4_mgm *mgm;
256	u32 members_count;
257	u16 hash;
258	int prev, index;
259	int i, loc;
260	int err;
261
262	mailbox = mlx4_alloc_cmd_mailbox(dev);
263	if (IS_ERR(mailbox))
264		return PTR_ERR(mailbox);
265	mgm = mailbox->buf;
266
267	mutex_lock(&priv->mcg_table.mutex);
268
269	err = find_mgm(dev, gid, mailbox, &hash, &prev, &index);
270	if (err)
271		goto out;
272
273	if (index == -1) {
274		mlx4_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
275			  "not found\n",
276			  be16_to_cpu(((__be16 *) gid)[0]),
277			  be16_to_cpu(((__be16 *) gid)[1]),
278			  be16_to_cpu(((__be16 *) gid)[2]),
279			  be16_to_cpu(((__be16 *) gid)[3]),
280			  be16_to_cpu(((__be16 *) gid)[4]),
281			  be16_to_cpu(((__be16 *) gid)[5]),
282			  be16_to_cpu(((__be16 *) gid)[6]),
283			  be16_to_cpu(((__be16 *) gid)[7]));
284		err = -EINVAL;
285		goto out;
286	}
287
288	members_count = be32_to_cpu(mgm->members_count);
289	for (loc = -1, i = 0; i < members_count; ++i)
290		if (mgm->qp[i] == cpu_to_be32(qp->qpn))
291			loc = i;
292
293	if (loc == -1) {
294		mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
295		err = -EINVAL;
296		goto out;
297	}
298
299
300	mgm->members_count = cpu_to_be32(--members_count);
301	mgm->qp[loc]       = mgm->qp[i - 1];
302	mgm->qp[i - 1]     = 0;
303
304	err = mlx4_WRITE_MCG(dev, index, mailbox);
305	if (err)
306		goto out;
307
308	if (i != 1)
309		goto out;
310
311	if (prev == -1) {
312		/* Remove entry from MGM */
313		int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
314		if (amgm_index) {
315			err = mlx4_READ_MCG(dev, amgm_index, mailbox);
316			if (err)
317				goto out;
318		} else
319			memset(mgm->gid, 0, 16);
320
321		err = mlx4_WRITE_MCG(dev, index, mailbox);
322		if (err)
323			goto out;
324
325		if (amgm_index) {
326			if (amgm_index < dev->caps.num_mgms)
327				mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d",
328					  index, amgm_index, dev->caps.num_mgms);
329			else
330				mlx4_bitmap_free(&priv->mcg_table.bitmap,
331						 amgm_index - dev->caps.num_mgms);
332		}
333	} else {
334		/* Remove entry from AMGM */
335		int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
336		err = mlx4_READ_MCG(dev, prev, mailbox);
337		if (err)
338			goto out;
339
340		mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
341
342		err = mlx4_WRITE_MCG(dev, prev, mailbox);
343		if (err)
344			goto out;
345
346		if (index < dev->caps.num_mgms)
347			mlx4_warn(dev, "entry %d had next AMGM index %d < %d",
348				  prev, index, dev->caps.num_mgms);
349		else
350			mlx4_bitmap_free(&priv->mcg_table.bitmap,
351					 index - dev->caps.num_mgms);
352	}
353
354out:
355	mutex_unlock(&priv->mcg_table.mutex);
356
357	mlx4_free_cmd_mailbox(dev, mailbox);
358	return err;
359}
360EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
361
362int __devinit mlx4_init_mcg_table(struct mlx4_dev *dev)
363{
364	struct mlx4_priv *priv = mlx4_priv(dev);
365	int err;
366
367	err = mlx4_bitmap_init(&priv->mcg_table.bitmap,
368			       dev->caps.num_amgms, dev->caps.num_amgms - 1, 0);
369	if (err)
370		return err;
371
372	mutex_init(&priv->mcg_table.mutex);
373
374	return 0;
375}
376
377void mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
378{
379	mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
380}
381