xref: /freebsd/sys/dev/mthca/mthca_mcg.c (revision 33ec1ccbae880855a4aa9e221ba8512da70e541e)
1*33ec1ccbSHans Petter Selasky /*
2*33ec1ccbSHans Petter Selasky  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
3*33ec1ccbSHans Petter Selasky  *
4*33ec1ccbSHans Petter Selasky  * This software is available to you under a choice of one of two
5*33ec1ccbSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
6*33ec1ccbSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
7*33ec1ccbSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
8*33ec1ccbSHans Petter Selasky  * OpenIB.org BSD license below:
9*33ec1ccbSHans Petter Selasky  *
10*33ec1ccbSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
11*33ec1ccbSHans Petter Selasky  *     without modification, are permitted provided that the following
12*33ec1ccbSHans Petter Selasky  *     conditions are met:
13*33ec1ccbSHans Petter Selasky  *
14*33ec1ccbSHans Petter Selasky  *      - Redistributions of source code must retain the above
15*33ec1ccbSHans Petter Selasky  *        copyright notice, this list of conditions and the following
16*33ec1ccbSHans Petter Selasky  *        disclaimer.
17*33ec1ccbSHans Petter Selasky  *
18*33ec1ccbSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
19*33ec1ccbSHans Petter Selasky  *        copyright notice, this list of conditions and the following
20*33ec1ccbSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
21*33ec1ccbSHans Petter Selasky  *        provided with the distribution.
22*33ec1ccbSHans Petter Selasky  *
23*33ec1ccbSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24*33ec1ccbSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25*33ec1ccbSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26*33ec1ccbSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27*33ec1ccbSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28*33ec1ccbSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29*33ec1ccbSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30*33ec1ccbSHans Petter Selasky  * SOFTWARE.
31*33ec1ccbSHans Petter Selasky  */
32*33ec1ccbSHans Petter Selasky 
33*33ec1ccbSHans Petter Selasky #include <linux/string.h>
34*33ec1ccbSHans Petter Selasky #include <linux/gfp.h>
35*33ec1ccbSHans Petter Selasky 
36*33ec1ccbSHans Petter Selasky #include "mthca_dev.h"
37*33ec1ccbSHans Petter Selasky #include "mthca_cmd.h"
38*33ec1ccbSHans Petter Selasky 
39*33ec1ccbSHans Petter Selasky struct mthca_mgm {
40*33ec1ccbSHans Petter Selasky 	__be32 next_gid_index;
41*33ec1ccbSHans Petter Selasky 	u32    reserved[3];
42*33ec1ccbSHans Petter Selasky 	u8     gid[16];
43*33ec1ccbSHans Petter Selasky 	__be32 qp[MTHCA_QP_PER_MGM];
44*33ec1ccbSHans Petter Selasky };
45*33ec1ccbSHans Petter Selasky 
46*33ec1ccbSHans Petter Selasky static const u8 zero_gid[16];	/* automatically initialized to 0 */
47*33ec1ccbSHans Petter Selasky 
48*33ec1ccbSHans Petter Selasky /*
49*33ec1ccbSHans Petter Selasky  * Caller must hold MCG table semaphore.  gid and mgm parameters must
50*33ec1ccbSHans Petter Selasky  * be properly aligned for command interface.
51*33ec1ccbSHans Petter Selasky  *
52*33ec1ccbSHans Petter Selasky  *  Returns 0 unless a firmware command error occurs.
53*33ec1ccbSHans Petter Selasky  *
54*33ec1ccbSHans Petter Selasky  * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
55*33ec1ccbSHans Petter Selasky  * and *mgm holds MGM entry.
56*33ec1ccbSHans Petter Selasky  *
57*33ec1ccbSHans Petter Selasky  * if GID is found in AMGM, *index = index in AMGM, *prev = index of
58*33ec1ccbSHans Petter Selasky  * previous entry in hash chain and *mgm holds AMGM entry.
59*33ec1ccbSHans Petter Selasky  *
60*33ec1ccbSHans Petter Selasky  * If no AMGM exists for given gid, *index = -1, *prev = index of last
61*33ec1ccbSHans Petter Selasky  * entry in hash chain and *mgm holds end of hash chain.
62*33ec1ccbSHans Petter Selasky  */
find_mgm(struct mthca_dev * dev,u8 * gid,struct mthca_mailbox * mgm_mailbox,u16 * hash,int * prev,int * index)63*33ec1ccbSHans Petter Selasky static int find_mgm(struct mthca_dev *dev,
64*33ec1ccbSHans Petter Selasky 		    u8 *gid, struct mthca_mailbox *mgm_mailbox,
65*33ec1ccbSHans Petter Selasky 		    u16 *hash, int *prev, int *index)
66*33ec1ccbSHans Petter Selasky {
67*33ec1ccbSHans Petter Selasky 	struct mthca_mailbox *mailbox;
68*33ec1ccbSHans Petter Selasky 	struct mthca_mgm *mgm = mgm_mailbox->buf;
69*33ec1ccbSHans Petter Selasky 	u8 *mgid;
70*33ec1ccbSHans Petter Selasky 	int err;
71*33ec1ccbSHans Petter Selasky 
72*33ec1ccbSHans Petter Selasky 	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
73*33ec1ccbSHans Petter Selasky 	if (IS_ERR(mailbox))
74*33ec1ccbSHans Petter Selasky 		return -ENOMEM;
75*33ec1ccbSHans Petter Selasky 	mgid = mailbox->buf;
76*33ec1ccbSHans Petter Selasky 
77*33ec1ccbSHans Petter Selasky 	memcpy(mgid, gid, 16);
78*33ec1ccbSHans Petter Selasky 
79*33ec1ccbSHans Petter Selasky 	err = mthca_MGID_HASH(dev, mailbox, hash);
80*33ec1ccbSHans Petter Selasky 	if (err) {
81*33ec1ccbSHans Petter Selasky 		mthca_err(dev, "MGID_HASH failed (%d)\n", err);
82*33ec1ccbSHans Petter Selasky 		goto out;
83*33ec1ccbSHans Petter Selasky 	}
84*33ec1ccbSHans Petter Selasky 
85*33ec1ccbSHans Petter Selasky 	if (0)
86*33ec1ccbSHans Petter Selasky 		mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);
87*33ec1ccbSHans Petter Selasky 
88*33ec1ccbSHans Petter Selasky 	*index = *hash;
89*33ec1ccbSHans Petter Selasky 	*prev  = -1;
90*33ec1ccbSHans Petter Selasky 
91*33ec1ccbSHans Petter Selasky 	do {
92*33ec1ccbSHans Petter Selasky 		err = mthca_READ_MGM(dev, *index, mgm_mailbox);
93*33ec1ccbSHans Petter Selasky 		if (err) {
94*33ec1ccbSHans Petter Selasky 			mthca_err(dev, "READ_MGM failed (%d)\n", err);
95*33ec1ccbSHans Petter Selasky 			goto out;
96*33ec1ccbSHans Petter Selasky 		}
97*33ec1ccbSHans Petter Selasky 
98*33ec1ccbSHans Petter Selasky 		if (!memcmp(mgm->gid, zero_gid, 16)) {
99*33ec1ccbSHans Petter Selasky 			if (*index != *hash) {
100*33ec1ccbSHans Petter Selasky 				mthca_err(dev, "Found zero MGID in AMGM.\n");
101*33ec1ccbSHans Petter Selasky 				err = -EINVAL;
102*33ec1ccbSHans Petter Selasky 			}
103*33ec1ccbSHans Petter Selasky 			goto out;
104*33ec1ccbSHans Petter Selasky 		}
105*33ec1ccbSHans Petter Selasky 
106*33ec1ccbSHans Petter Selasky 		if (!memcmp(mgm->gid, gid, 16))
107*33ec1ccbSHans Petter Selasky 			goto out;
108*33ec1ccbSHans Petter Selasky 
109*33ec1ccbSHans Petter Selasky 		*prev = *index;
110*33ec1ccbSHans Petter Selasky 		*index = be32_to_cpu(mgm->next_gid_index) >> 6;
111*33ec1ccbSHans Petter Selasky 	} while (*index);
112*33ec1ccbSHans Petter Selasky 
113*33ec1ccbSHans Petter Selasky 	*index = -1;
114*33ec1ccbSHans Petter Selasky 
115*33ec1ccbSHans Petter Selasky  out:
116*33ec1ccbSHans Petter Selasky 	mthca_free_mailbox(dev, mailbox);
117*33ec1ccbSHans Petter Selasky 	return err;
118*33ec1ccbSHans Petter Selasky }
119*33ec1ccbSHans Petter Selasky 
mthca_multicast_attach(struct ib_qp * ibqp,union ib_gid * gid,u16 lid)120*33ec1ccbSHans Petter Selasky int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
121*33ec1ccbSHans Petter Selasky {
122*33ec1ccbSHans Petter Selasky 	struct mthca_dev *dev = to_mdev(ibqp->device);
123*33ec1ccbSHans Petter Selasky 	struct mthca_mailbox *mailbox;
124*33ec1ccbSHans Petter Selasky 	struct mthca_mgm *mgm;
125*33ec1ccbSHans Petter Selasky 	u16 hash;
126*33ec1ccbSHans Petter Selasky 	int index, prev;
127*33ec1ccbSHans Petter Selasky 	int link = 0;
128*33ec1ccbSHans Petter Selasky 	int i;
129*33ec1ccbSHans Petter Selasky 	int err;
130*33ec1ccbSHans Petter Selasky 
131*33ec1ccbSHans Petter Selasky 	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
132*33ec1ccbSHans Petter Selasky 	if (IS_ERR(mailbox))
133*33ec1ccbSHans Petter Selasky 		return PTR_ERR(mailbox);
134*33ec1ccbSHans Petter Selasky 	mgm = mailbox->buf;
135*33ec1ccbSHans Petter Selasky 
136*33ec1ccbSHans Petter Selasky 	mutex_lock(&dev->mcg_table.mutex);
137*33ec1ccbSHans Petter Selasky 
138*33ec1ccbSHans Petter Selasky 	err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
139*33ec1ccbSHans Petter Selasky 	if (err)
140*33ec1ccbSHans Petter Selasky 		goto out;
141*33ec1ccbSHans Petter Selasky 
142*33ec1ccbSHans Petter Selasky 	if (index != -1) {
143*33ec1ccbSHans Petter Selasky 		if (!memcmp(mgm->gid, zero_gid, 16))
144*33ec1ccbSHans Petter Selasky 			memcpy(mgm->gid, gid->raw, 16);
145*33ec1ccbSHans Petter Selasky 	} else {
146*33ec1ccbSHans Petter Selasky 		link = 1;
147*33ec1ccbSHans Petter Selasky 
148*33ec1ccbSHans Petter Selasky 		index = mthca_alloc(&dev->mcg_table.alloc);
149*33ec1ccbSHans Petter Selasky 		if (index == -1) {
150*33ec1ccbSHans Petter Selasky 			mthca_err(dev, "No AMGM entries left\n");
151*33ec1ccbSHans Petter Selasky 			err = -ENOMEM;
152*33ec1ccbSHans Petter Selasky 			goto out;
153*33ec1ccbSHans Petter Selasky 		}
154*33ec1ccbSHans Petter Selasky 
155*33ec1ccbSHans Petter Selasky 		err = mthca_READ_MGM(dev, index, mailbox);
156*33ec1ccbSHans Petter Selasky 		if (err) {
157*33ec1ccbSHans Petter Selasky 			mthca_err(dev, "READ_MGM failed (%d)\n", err);
158*33ec1ccbSHans Petter Selasky 			goto out;
159*33ec1ccbSHans Petter Selasky 		}
160*33ec1ccbSHans Petter Selasky 		memset(mgm, 0, sizeof *mgm);
161*33ec1ccbSHans Petter Selasky 		memcpy(mgm->gid, gid->raw, 16);
162*33ec1ccbSHans Petter Selasky 	}
163*33ec1ccbSHans Petter Selasky 
164*33ec1ccbSHans Petter Selasky 	for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
165*33ec1ccbSHans Petter Selasky 		if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
166*33ec1ccbSHans Petter Selasky 			mthca_dbg(dev, "QP %06x already a member of MGM\n",
167*33ec1ccbSHans Petter Selasky 				  ibqp->qp_num);
168*33ec1ccbSHans Petter Selasky 			err = 0;
169*33ec1ccbSHans Petter Selasky 			goto out;
170*33ec1ccbSHans Petter Selasky 		} else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) {
171*33ec1ccbSHans Petter Selasky 			mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31));
172*33ec1ccbSHans Petter Selasky 			break;
173*33ec1ccbSHans Petter Selasky 		}
174*33ec1ccbSHans Petter Selasky 
175*33ec1ccbSHans Petter Selasky 	if (i == MTHCA_QP_PER_MGM) {
176*33ec1ccbSHans Petter Selasky 		mthca_err(dev, "MGM at index %x is full.\n", index);
177*33ec1ccbSHans Petter Selasky 		err = -ENOMEM;
178*33ec1ccbSHans Petter Selasky 		goto out;
179*33ec1ccbSHans Petter Selasky 	}
180*33ec1ccbSHans Petter Selasky 
181*33ec1ccbSHans Petter Selasky 	err = mthca_WRITE_MGM(dev, index, mailbox);
182*33ec1ccbSHans Petter Selasky 	if (err) {
183*33ec1ccbSHans Petter Selasky 		mthca_err(dev, "WRITE_MGM failed %d\n", err);
184*33ec1ccbSHans Petter Selasky 		err = -EINVAL;
185*33ec1ccbSHans Petter Selasky 		goto out;
186*33ec1ccbSHans Petter Selasky 	}
187*33ec1ccbSHans Petter Selasky 
188*33ec1ccbSHans Petter Selasky 	if (!link)
189*33ec1ccbSHans Petter Selasky 		goto out;
190*33ec1ccbSHans Petter Selasky 
191*33ec1ccbSHans Petter Selasky 	err = mthca_READ_MGM(dev, prev, mailbox);
192*33ec1ccbSHans Petter Selasky 	if (err) {
193*33ec1ccbSHans Petter Selasky 		mthca_err(dev, "READ_MGM failed %d\n", err);
194*33ec1ccbSHans Petter Selasky 		goto out;
195*33ec1ccbSHans Petter Selasky 	}
196*33ec1ccbSHans Petter Selasky 
197*33ec1ccbSHans Petter Selasky 	mgm->next_gid_index = cpu_to_be32(index << 6);
198*33ec1ccbSHans Petter Selasky 
199*33ec1ccbSHans Petter Selasky 	err = mthca_WRITE_MGM(dev, prev, mailbox);
200*33ec1ccbSHans Petter Selasky 	if (err)
201*33ec1ccbSHans Petter Selasky 		mthca_err(dev, "WRITE_MGM returned %d\n", err);
202*33ec1ccbSHans Petter Selasky 
203*33ec1ccbSHans Petter Selasky  out:
204*33ec1ccbSHans Petter Selasky 	if (err && link && index != -1) {
205*33ec1ccbSHans Petter Selasky 		BUG_ON(index < dev->limits.num_mgms);
206*33ec1ccbSHans Petter Selasky 		mthca_free(&dev->mcg_table.alloc, index);
207*33ec1ccbSHans Petter Selasky 	}
208*33ec1ccbSHans Petter Selasky 	mutex_unlock(&dev->mcg_table.mutex);
209*33ec1ccbSHans Petter Selasky 
210*33ec1ccbSHans Petter Selasky 	mthca_free_mailbox(dev, mailbox);
211*33ec1ccbSHans Petter Selasky 	return err;
212*33ec1ccbSHans Petter Selasky }
213*33ec1ccbSHans Petter Selasky 
mthca_multicast_detach(struct ib_qp * ibqp,union ib_gid * gid,u16 lid)214*33ec1ccbSHans Petter Selasky int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
215*33ec1ccbSHans Petter Selasky {
216*33ec1ccbSHans Petter Selasky 	struct mthca_dev *dev = to_mdev(ibqp->device);
217*33ec1ccbSHans Petter Selasky 	struct mthca_mailbox *mailbox;
218*33ec1ccbSHans Petter Selasky 	struct mthca_mgm *mgm;
219*33ec1ccbSHans Petter Selasky 	u16 hash;
220*33ec1ccbSHans Petter Selasky 	int prev, index;
221*33ec1ccbSHans Petter Selasky 	int i, loc;
222*33ec1ccbSHans Petter Selasky 	int err;
223*33ec1ccbSHans Petter Selasky 
224*33ec1ccbSHans Petter Selasky 	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
225*33ec1ccbSHans Petter Selasky 	if (IS_ERR(mailbox))
226*33ec1ccbSHans Petter Selasky 		return PTR_ERR(mailbox);
227*33ec1ccbSHans Petter Selasky 	mgm = mailbox->buf;
228*33ec1ccbSHans Petter Selasky 
229*33ec1ccbSHans Petter Selasky 	mutex_lock(&dev->mcg_table.mutex);
230*33ec1ccbSHans Petter Selasky 
231*33ec1ccbSHans Petter Selasky 	err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
232*33ec1ccbSHans Petter Selasky 	if (err)
233*33ec1ccbSHans Petter Selasky 		goto out;
234*33ec1ccbSHans Petter Selasky 
235*33ec1ccbSHans Petter Selasky 	if (index == -1) {
236*33ec1ccbSHans Petter Selasky 		mthca_err(dev, "MGID %pI6 not found\n", gid->raw);
237*33ec1ccbSHans Petter Selasky 		err = -EINVAL;
238*33ec1ccbSHans Petter Selasky 		goto out;
239*33ec1ccbSHans Petter Selasky 	}
240*33ec1ccbSHans Petter Selasky 
241*33ec1ccbSHans Petter Selasky 	for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) {
242*33ec1ccbSHans Petter Selasky 		if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31)))
243*33ec1ccbSHans Petter Selasky 			loc = i;
244*33ec1ccbSHans Petter Selasky 		if (!(mgm->qp[i] & cpu_to_be32(1 << 31)))
245*33ec1ccbSHans Petter Selasky 			break;
246*33ec1ccbSHans Petter Selasky 	}
247*33ec1ccbSHans Petter Selasky 
248*33ec1ccbSHans Petter Selasky 	if (loc == -1) {
249*33ec1ccbSHans Petter Selasky 		mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num);
250*33ec1ccbSHans Petter Selasky 		err = -EINVAL;
251*33ec1ccbSHans Petter Selasky 		goto out;
252*33ec1ccbSHans Petter Selasky 	}
253*33ec1ccbSHans Petter Selasky 
254*33ec1ccbSHans Petter Selasky 	mgm->qp[loc]   = mgm->qp[i - 1];
255*33ec1ccbSHans Petter Selasky 	mgm->qp[i - 1] = 0;
256*33ec1ccbSHans Petter Selasky 
257*33ec1ccbSHans Petter Selasky 	err = mthca_WRITE_MGM(dev, index, mailbox);
258*33ec1ccbSHans Petter Selasky 	if (err) {
259*33ec1ccbSHans Petter Selasky 		mthca_err(dev, "WRITE_MGM returned %d\n", err);
260*33ec1ccbSHans Petter Selasky 		goto out;
261*33ec1ccbSHans Petter Selasky 	}
262*33ec1ccbSHans Petter Selasky 
263*33ec1ccbSHans Petter Selasky 	if (i != 1)
264*33ec1ccbSHans Petter Selasky 		goto out;
265*33ec1ccbSHans Petter Selasky 
266*33ec1ccbSHans Petter Selasky 	if (prev == -1) {
267*33ec1ccbSHans Petter Selasky 		/* Remove entry from MGM */
268*33ec1ccbSHans Petter Selasky 		int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6;
269*33ec1ccbSHans Petter Selasky 		if (amgm_index_to_free) {
270*33ec1ccbSHans Petter Selasky 			err = mthca_READ_MGM(dev, amgm_index_to_free,
271*33ec1ccbSHans Petter Selasky 					     mailbox);
272*33ec1ccbSHans Petter Selasky 			if (err) {
273*33ec1ccbSHans Petter Selasky 				mthca_err(dev, "READ_MGM returned %d\n", err);
274*33ec1ccbSHans Petter Selasky 				goto out;
275*33ec1ccbSHans Petter Selasky 			}
276*33ec1ccbSHans Petter Selasky 		} else
277*33ec1ccbSHans Petter Selasky 			memset(mgm->gid, 0, 16);
278*33ec1ccbSHans Petter Selasky 
279*33ec1ccbSHans Petter Selasky 		err = mthca_WRITE_MGM(dev, index, mailbox);
280*33ec1ccbSHans Petter Selasky 		if (err) {
281*33ec1ccbSHans Petter Selasky 			mthca_err(dev, "WRITE_MGM returned %d\n", err);
282*33ec1ccbSHans Petter Selasky 			goto out;
283*33ec1ccbSHans Petter Selasky 		}
284*33ec1ccbSHans Petter Selasky 		if (amgm_index_to_free) {
285*33ec1ccbSHans Petter Selasky 			BUG_ON(amgm_index_to_free < dev->limits.num_mgms);
286*33ec1ccbSHans Petter Selasky 			mthca_free(&dev->mcg_table.alloc, amgm_index_to_free);
287*33ec1ccbSHans Petter Selasky 		}
288*33ec1ccbSHans Petter Selasky 	} else {
289*33ec1ccbSHans Petter Selasky 		/* Remove entry from AMGM */
290*33ec1ccbSHans Petter Selasky 		int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
291*33ec1ccbSHans Petter Selasky 		err = mthca_READ_MGM(dev, prev, mailbox);
292*33ec1ccbSHans Petter Selasky 		if (err) {
293*33ec1ccbSHans Petter Selasky 			mthca_err(dev, "READ_MGM returned %d\n", err);
294*33ec1ccbSHans Petter Selasky 			goto out;
295*33ec1ccbSHans Petter Selasky 		}
296*33ec1ccbSHans Petter Selasky 
297*33ec1ccbSHans Petter Selasky 		mgm->next_gid_index = cpu_to_be32(curr_next_index << 6);
298*33ec1ccbSHans Petter Selasky 
299*33ec1ccbSHans Petter Selasky 		err = mthca_WRITE_MGM(dev, prev, mailbox);
300*33ec1ccbSHans Petter Selasky 		if (err) {
301*33ec1ccbSHans Petter Selasky 			mthca_err(dev, "WRITE_MGM returned %d\n", err);
302*33ec1ccbSHans Petter Selasky 			goto out;
303*33ec1ccbSHans Petter Selasky 		}
304*33ec1ccbSHans Petter Selasky 		BUG_ON(index < dev->limits.num_mgms);
305*33ec1ccbSHans Petter Selasky 		mthca_free(&dev->mcg_table.alloc, index);
306*33ec1ccbSHans Petter Selasky 	}
307*33ec1ccbSHans Petter Selasky 
308*33ec1ccbSHans Petter Selasky  out:
309*33ec1ccbSHans Petter Selasky 	mutex_unlock(&dev->mcg_table.mutex);
310*33ec1ccbSHans Petter Selasky 
311*33ec1ccbSHans Petter Selasky 	mthca_free_mailbox(dev, mailbox);
312*33ec1ccbSHans Petter Selasky 	return err;
313*33ec1ccbSHans Petter Selasky }
314*33ec1ccbSHans Petter Selasky 
mthca_init_mcg_table(struct mthca_dev * dev)315*33ec1ccbSHans Petter Selasky int mthca_init_mcg_table(struct mthca_dev *dev)
316*33ec1ccbSHans Petter Selasky {
317*33ec1ccbSHans Petter Selasky 	int err;
318*33ec1ccbSHans Petter Selasky 	int table_size = dev->limits.num_mgms + dev->limits.num_amgms;
319*33ec1ccbSHans Petter Selasky 
320*33ec1ccbSHans Petter Selasky 	err = mthca_alloc_init(&dev->mcg_table.alloc,
321*33ec1ccbSHans Petter Selasky 			       table_size,
322*33ec1ccbSHans Petter Selasky 			       table_size - 1,
323*33ec1ccbSHans Petter Selasky 			       dev->limits.num_mgms);
324*33ec1ccbSHans Petter Selasky 	if (err)
325*33ec1ccbSHans Petter Selasky 		return err;
326*33ec1ccbSHans Petter Selasky 
327*33ec1ccbSHans Petter Selasky 	mutex_init(&dev->mcg_table.mutex);
328*33ec1ccbSHans Petter Selasky 
329*33ec1ccbSHans Petter Selasky 	return 0;
330*33ec1ccbSHans Petter Selasky }
331*33ec1ccbSHans Petter Selasky 
mthca_cleanup_mcg_table(struct mthca_dev * dev)332*33ec1ccbSHans Petter Selasky void mthca_cleanup_mcg_table(struct mthca_dev *dev)
333*33ec1ccbSHans Petter Selasky {
334*33ec1ccbSHans Petter Selasky 	mthca_alloc_cleanup(&dev->mcg_table.alloc);
335*33ec1ccbSHans Petter Selasky }
336