Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/infiniband/hw/mthca/mthca_mcg.c
15112 views
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 {
40
__be32 next_gid_index;
41
u32 reserved[3];
42
u8 gid[16];
43
__be32 qp[MTHCA_QP_PER_MGM];
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
u8 status;
72
73
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
74
if (IS_ERR(mailbox))
75
return -ENOMEM;
76
mgid = mailbox->buf;
77
78
memcpy(mgid, gid, 16);
79
80
err = mthca_MGID_HASH(dev, mailbox, hash, &status);
81
if (err)
82
goto out;
83
if (status) {
84
mthca_err(dev, "MGID_HASH returned status %02x\n", status);
85
err = -EINVAL;
86
goto out;
87
}
88
89
if (0)
90
mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);
91
92
*index = *hash;
93
*prev = -1;
94
95
do {
96
err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status);
97
if (err)
98
goto out;
99
if (status) {
100
mthca_err(dev, "READ_MGM returned status %02x\n", status);
101
err = -EINVAL;
102
goto out;
103
}
104
105
if (!memcmp(mgm->gid, zero_gid, 16)) {
106
if (*index != *hash) {
107
mthca_err(dev, "Found zero MGID in AMGM.\n");
108
err = -EINVAL;
109
}
110
goto out;
111
}
112
113
if (!memcmp(mgm->gid, gid, 16))
114
goto out;
115
116
*prev = *index;
117
*index = be32_to_cpu(mgm->next_gid_index) >> 6;
118
} while (*index);
119
120
*index = -1;
121
122
out:
123
mthca_free_mailbox(dev, mailbox);
124
return err;
125
}
126
127
int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
128
{
129
struct mthca_dev *dev = to_mdev(ibqp->device);
130
struct mthca_mailbox *mailbox;
131
struct mthca_mgm *mgm;
132
u16 hash;
133
int index, prev;
134
int link = 0;
135
int i;
136
int err;
137
u8 status;
138
139
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
140
if (IS_ERR(mailbox))
141
return PTR_ERR(mailbox);
142
mgm = mailbox->buf;
143
144
mutex_lock(&dev->mcg_table.mutex);
145
146
err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
147
if (err)
148
goto out;
149
150
if (index != -1) {
151
if (!memcmp(mgm->gid, zero_gid, 16))
152
memcpy(mgm->gid, gid->raw, 16);
153
} else {
154
link = 1;
155
156
index = mthca_alloc(&dev->mcg_table.alloc);
157
if (index == -1) {
158
mthca_err(dev, "No AMGM entries left\n");
159
err = -ENOMEM;
160
goto out;
161
}
162
163
err = mthca_READ_MGM(dev, index, mailbox, &status);
164
if (err)
165
goto out;
166
if (status) {
167
mthca_err(dev, "READ_MGM returned status %02x\n", status);
168
err = -EINVAL;
169
goto out;
170
}
171
memset(mgm, 0, sizeof *mgm);
172
memcpy(mgm->gid, gid->raw, 16);
173
}
174
175
for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
176
if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
177
mthca_dbg(dev, "QP %06x already a member of MGM\n",
178
ibqp->qp_num);
179
err = 0;
180
goto out;
181
} else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) {
182
mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31));
183
break;
184
}
185
186
if (i == MTHCA_QP_PER_MGM) {
187
mthca_err(dev, "MGM at index %x is full.\n", index);
188
err = -ENOMEM;
189
goto out;
190
}
191
192
err = mthca_WRITE_MGM(dev, index, mailbox, &status);
193
if (err)
194
goto out;
195
if (status) {
196
mthca_err(dev, "WRITE_MGM returned status %02x\n", status);
197
err = -EINVAL;
198
goto out;
199
}
200
201
if (!link)
202
goto out;
203
204
err = mthca_READ_MGM(dev, prev, mailbox, &status);
205
if (err)
206
goto out;
207
if (status) {
208
mthca_err(dev, "READ_MGM returned status %02x\n", status);
209
err = -EINVAL;
210
goto out;
211
}
212
213
mgm->next_gid_index = cpu_to_be32(index << 6);
214
215
err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
216
if (err)
217
goto out;
218
if (status) {
219
mthca_err(dev, "WRITE_MGM returned status %02x\n", status);
220
err = -EINVAL;
221
}
222
223
out:
224
if (err && link && index != -1) {
225
BUG_ON(index < dev->limits.num_mgms);
226
mthca_free(&dev->mcg_table.alloc, index);
227
}
228
mutex_unlock(&dev->mcg_table.mutex);
229
230
mthca_free_mailbox(dev, mailbox);
231
return err;
232
}
233
234
int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
235
{
236
struct mthca_dev *dev = to_mdev(ibqp->device);
237
struct mthca_mailbox *mailbox;
238
struct mthca_mgm *mgm;
239
u16 hash;
240
int prev, index;
241
int i, loc;
242
int err;
243
u8 status;
244
245
mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
246
if (IS_ERR(mailbox))
247
return PTR_ERR(mailbox);
248
mgm = mailbox->buf;
249
250
mutex_lock(&dev->mcg_table.mutex);
251
252
err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
253
if (err)
254
goto out;
255
256
if (index == -1) {
257
mthca_err(dev, "MGID %pI6 not found\n", gid->raw);
258
err = -EINVAL;
259
goto out;
260
}
261
262
for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) {
263
if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31)))
264
loc = i;
265
if (!(mgm->qp[i] & cpu_to_be32(1 << 31)))
266
break;
267
}
268
269
if (loc == -1) {
270
mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num);
271
err = -EINVAL;
272
goto out;
273
}
274
275
mgm->qp[loc] = mgm->qp[i - 1];
276
mgm->qp[i - 1] = 0;
277
278
err = mthca_WRITE_MGM(dev, index, mailbox, &status);
279
if (err)
280
goto out;
281
if (status) {
282
mthca_err(dev, "WRITE_MGM returned status %02x\n", status);
283
err = -EINVAL;
284
goto out;
285
}
286
287
if (i != 1)
288
goto out;
289
290
if (prev == -1) {
291
/* Remove entry from MGM */
292
int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6;
293
if (amgm_index_to_free) {
294
err = mthca_READ_MGM(dev, amgm_index_to_free,
295
mailbox, &status);
296
if (err)
297
goto out;
298
if (status) {
299
mthca_err(dev, "READ_MGM returned status %02x\n",
300
status);
301
err = -EINVAL;
302
goto out;
303
}
304
} else
305
memset(mgm->gid, 0, 16);
306
307
err = mthca_WRITE_MGM(dev, index, mailbox, &status);
308
if (err)
309
goto out;
310
if (status) {
311
mthca_err(dev, "WRITE_MGM returned status %02x\n", status);
312
err = -EINVAL;
313
goto out;
314
}
315
if (amgm_index_to_free) {
316
BUG_ON(amgm_index_to_free < dev->limits.num_mgms);
317
mthca_free(&dev->mcg_table.alloc, amgm_index_to_free);
318
}
319
} else {
320
/* Remove entry from AMGM */
321
int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
322
err = mthca_READ_MGM(dev, prev, mailbox, &status);
323
if (err)
324
goto out;
325
if (status) {
326
mthca_err(dev, "READ_MGM returned status %02x\n", status);
327
err = -EINVAL;
328
goto out;
329
}
330
331
mgm->next_gid_index = cpu_to_be32(curr_next_index << 6);
332
333
err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
334
if (err)
335
goto out;
336
if (status) {
337
mthca_err(dev, "WRITE_MGM returned status %02x\n", status);
338
err = -EINVAL;
339
goto out;
340
}
341
BUG_ON(index < dev->limits.num_mgms);
342
mthca_free(&dev->mcg_table.alloc, index);
343
}
344
345
out:
346
mutex_unlock(&dev->mcg_table.mutex);
347
348
mthca_free_mailbox(dev, mailbox);
349
return err;
350
}
351
352
int mthca_init_mcg_table(struct mthca_dev *dev)
353
{
354
int err;
355
int table_size = dev->limits.num_mgms + dev->limits.num_amgms;
356
357
err = mthca_alloc_init(&dev->mcg_table.alloc,
358
table_size,
359
table_size - 1,
360
dev->limits.num_mgms);
361
if (err)
362
return err;
363
364
mutex_init(&dev->mcg_table.mutex);
365
366
return 0;
367
}
368
369
void mthca_cleanup_mcg_table(struct mthca_dev *dev)
370
{
371
mthca_alloc_cleanup(&dev->mcg_table.alloc);
372
}
373
374