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