Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mthca_mcg.c
Go to the documentation of this file.
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/gfp.h>
35 
36 #include "mthca_dev.h"
37 #include "mthca_cmd.h"
38 
39 struct mthca_mgm {
42  u8 gid[16];
44 };
45 
46 static 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  */
63 static 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 
72  mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
73  if (IS_ERR(mailbox))
74  return -ENOMEM;
75  mgid = mailbox->buf;
76 
77  memcpy(mgid, gid, 16);
78 
79  err = mthca_MGID_HASH(dev, mailbox, hash);
80  if (err) {
81  mthca_err(dev, "MGID_HASH failed (%d)\n", err);
82  goto out;
83  }
84 
85  if (0)
86  mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);
87 
88  *index = *hash;
89  *prev = -1;
90 
91  do {
92  err = mthca_READ_MGM(dev, *index, mgm_mailbox);
93  if (err) {
94  mthca_err(dev, "READ_MGM failed (%d)\n", err);
95  goto out;
96  }
97 
98  if (!memcmp(mgm->gid, zero_gid, 16)) {
99  if (*index != *hash) {
100  mthca_err(dev, "Found zero MGID in AMGM.\n");
101  err = -EINVAL;
102  }
103  goto out;
104  }
105 
106  if (!memcmp(mgm->gid, gid, 16))
107  goto out;
108 
109  *prev = *index;
110  *index = be32_to_cpu(mgm->next_gid_index) >> 6;
111  } while (*index);
112 
113  *index = -1;
114 
115  out:
116  mthca_free_mailbox(dev, mailbox);
117  return err;
118 }
119 
120 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
121 {
122  struct mthca_dev *dev = to_mdev(ibqp->device);
123  struct mthca_mailbox *mailbox;
124  struct mthca_mgm *mgm;
125  u16 hash;
126  int index, prev;
127  int link = 0;
128  int i;
129  int err;
130 
131  mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
132  if (IS_ERR(mailbox))
133  return PTR_ERR(mailbox);
134  mgm = mailbox->buf;
135 
136  mutex_lock(&dev->mcg_table.mutex);
137 
138  err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
139  if (err)
140  goto out;
141 
142  if (index != -1) {
143  if (!memcmp(mgm->gid, zero_gid, 16))
144  memcpy(mgm->gid, gid->raw, 16);
145  } else {
146  link = 1;
147 
148  index = mthca_alloc(&dev->mcg_table.alloc);
149  if (index == -1) {
150  mthca_err(dev, "No AMGM entries left\n");
151  err = -ENOMEM;
152  goto out;
153  }
154 
155  err = mthca_READ_MGM(dev, index, mailbox);
156  if (err) {
157  mthca_err(dev, "READ_MGM failed (%d)\n", err);
158  goto out;
159  }
160  memset(mgm, 0, sizeof *mgm);
161  memcpy(mgm->gid, gid->raw, 16);
162  }
163 
164  for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
165  if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
166  mthca_dbg(dev, "QP %06x already a member of MGM\n",
167  ibqp->qp_num);
168  err = 0;
169  goto out;
170  } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) {
171  mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31));
172  break;
173  }
174 
175  if (i == MTHCA_QP_PER_MGM) {
176  mthca_err(dev, "MGM at index %x is full.\n", index);
177  err = -ENOMEM;
178  goto out;
179  }
180 
181  err = mthca_WRITE_MGM(dev, index, mailbox);
182  if (err) {
183  mthca_err(dev, "WRITE_MGM failed %d\n", err);
184  err = -EINVAL;
185  goto out;
186  }
187 
188  if (!link)
189  goto out;
190 
191  err = mthca_READ_MGM(dev, prev, mailbox);
192  if (err) {
193  mthca_err(dev, "READ_MGM failed %d\n", err);
194  goto out;
195  }
196 
197  mgm->next_gid_index = cpu_to_be32(index << 6);
198 
199  err = mthca_WRITE_MGM(dev, prev, mailbox);
200  if (err)
201  mthca_err(dev, "WRITE_MGM returned %d\n", err);
202 
203  out:
204  if (err && link && index != -1) {
205  BUG_ON(index < dev->limits.num_mgms);
206  mthca_free(&dev->mcg_table.alloc, index);
207  }
208  mutex_unlock(&dev->mcg_table.mutex);
209 
210  mthca_free_mailbox(dev, mailbox);
211  return err;
212 }
213 
214 int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
215 {
216  struct mthca_dev *dev = to_mdev(ibqp->device);
217  struct mthca_mailbox *mailbox;
218  struct mthca_mgm *mgm;
219  u16 hash;
220  int prev, index;
221  int i, loc;
222  int err;
223 
224  mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
225  if (IS_ERR(mailbox))
226  return PTR_ERR(mailbox);
227  mgm = mailbox->buf;
228 
229  mutex_lock(&dev->mcg_table.mutex);
230 
231  err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
232  if (err)
233  goto out;
234 
235  if (index == -1) {
236  mthca_err(dev, "MGID %pI6 not found\n", gid->raw);
237  err = -EINVAL;
238  goto out;
239  }
240 
241  for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) {
242  if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31)))
243  loc = i;
244  if (!(mgm->qp[i] & cpu_to_be32(1 << 31)))
245  break;
246  }
247 
248  if (loc == -1) {
249  mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num);
250  err = -EINVAL;
251  goto out;
252  }
253 
254  mgm->qp[loc] = mgm->qp[i - 1];
255  mgm->qp[i - 1] = 0;
256 
257  err = mthca_WRITE_MGM(dev, index, mailbox);
258  if (err) {
259  mthca_err(dev, "WRITE_MGM returned %d\n", err);
260  goto out;
261  }
262 
263  if (i != 1)
264  goto out;
265 
266  if (prev == -1) {
267  /* Remove entry from MGM */
268  int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6;
269  if (amgm_index_to_free) {
270  err = mthca_READ_MGM(dev, amgm_index_to_free,
271  mailbox);
272  if (err) {
273  mthca_err(dev, "READ_MGM returned %d\n", err);
274  goto out;
275  }
276  } else
277  memset(mgm->gid, 0, 16);
278 
279  err = mthca_WRITE_MGM(dev, index, mailbox);
280  if (err) {
281  mthca_err(dev, "WRITE_MGM returned %d\n", err);
282  goto out;
283  }
284  if (amgm_index_to_free) {
285  BUG_ON(amgm_index_to_free < dev->limits.num_mgms);
286  mthca_free(&dev->mcg_table.alloc, amgm_index_to_free);
287  }
288  } else {
289  /* Remove entry from AMGM */
290  int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
291  err = mthca_READ_MGM(dev, prev, mailbox);
292  if (err) {
293  mthca_err(dev, "READ_MGM returned %d\n", err);
294  goto out;
295  }
296 
297  mgm->next_gid_index = cpu_to_be32(curr_next_index << 6);
298 
299  err = mthca_WRITE_MGM(dev, prev, mailbox);
300  if (err) {
301  mthca_err(dev, "WRITE_MGM returned %d\n", err);
302  goto out;
303  }
304  BUG_ON(index < dev->limits.num_mgms);
305  mthca_free(&dev->mcg_table.alloc, index);
306  }
307 
308  out:
309  mutex_unlock(&dev->mcg_table.mutex);
310 
311  mthca_free_mailbox(dev, mailbox);
312  return err;
313 }
314 
316 {
317  int err;
318  int table_size = dev->limits.num_mgms + dev->limits.num_amgms;
319 
320  err = mthca_alloc_init(&dev->mcg_table.alloc,
321  table_size,
322  table_size - 1,
323  dev->limits.num_mgms);
324  if (err)
325  return err;
326 
327  mutex_init(&dev->mcg_table.mutex);
328 
329  return 0;
330 }
331 
333 {
334  mthca_alloc_cleanup(&dev->mcg_table.alloc);
335 }