]>
Commit | Line | Data |
---|---|---|
225c7b1f RD |
1 | /* |
2 | * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. | |
51a379d0 | 3 | * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. |
225c7b1f RD |
4 | * |
5 | * This software is available to you under a choice of one of two | |
6 | * licenses. You may choose to be licensed under the terms of the GNU | |
7 | * General Public License (GPL) Version 2, available from the file | |
8 | * COPYING in the main directory of this source tree, or the | |
9 | * OpenIB.org BSD license below: | |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or | |
12 | * without modification, are permitted provided that the following | |
13 | * conditions are met: | |
14 | * | |
15 | * - Redistributions of source code must retain the above | |
16 | * copyright notice, this list of conditions and the following | |
17 | * disclaimer. | |
18 | * | |
19 | * - Redistributions in binary form must reproduce the above | |
20 | * copyright notice, this list of conditions and the following | |
21 | * disclaimer in the documentation and/or other materials | |
22 | * provided with the distribution. | |
23 | * | |
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
31 | * SOFTWARE. | |
32 | */ | |
33 | ||
225c7b1f | 34 | #include <linux/string.h> |
0345584e | 35 | #include <linux/etherdevice.h> |
225c7b1f RD |
36 | |
37 | #include <linux/mlx4/cmd.h> | |
ee40fa06 | 38 | #include <linux/export.h> |
225c7b1f RD |
39 | |
40 | #include "mlx4.h" | |
41 | ||
521e575b RL |
42 | #define MGM_QPN_MASK 0x00FFFFFF |
43 | #define MGM_BLCK_LB_BIT 30 | |
44 | ||
225c7b1f RD |
45 | static const u8 zero_gid[16]; /* automatically initialized to 0 */ |
46 | ||
0ec2c0f8 EE |
47 | struct mlx4_mgm { |
48 | __be32 next_gid_index; | |
49 | __be32 members_count; | |
50 | u32 reserved[2]; | |
51 | u8 gid[16]; | |
52 | __be32 qp[MLX4_MAX_QP_PER_MGM]; | |
53 | }; | |
54 | ||
55 | int mlx4_get_mgm_entry_size(struct mlx4_dev *dev) | |
56 | { | |
57 | return min((1 << mlx4_log_num_mgm_entry_size), MLX4_MAX_MGM_ENTRY_SIZE); | |
58 | } | |
59 | ||
60 | int mlx4_get_qp_per_mgm(struct mlx4_dev *dev) | |
61 | { | |
62 | return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2); | |
63 | } | |
64 | ||
0345584e YP |
65 | static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index, |
66 | struct mlx4_cmd_mailbox *mailbox) | |
225c7b1f RD |
67 | { |
68 | return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, | |
f9baff50 | 69 | MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); |
225c7b1f RD |
70 | } |
71 | ||
0345584e YP |
72 | static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index, |
73 | struct mlx4_cmd_mailbox *mailbox) | |
225c7b1f RD |
74 | { |
75 | return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, | |
f9baff50 | 76 | MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); |
225c7b1f RD |
77 | } |
78 | ||
0ec2c0f8 | 79 | static int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer, |
b12d93d6 YP |
80 | struct mlx4_cmd_mailbox *mailbox) |
81 | { | |
82 | u32 in_mod; | |
83 | ||
0ec2c0f8 | 84 | in_mod = (u32) port << 16 | steer << 1; |
b12d93d6 | 85 | return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1, |
f9baff50 JM |
86 | MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A, |
87 | MLX4_CMD_NATIVE); | |
b12d93d6 YP |
88 | } |
89 | ||
0345584e YP |
90 | static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, |
91 | u16 *hash, u8 op_mod) | |
225c7b1f RD |
92 | { |
93 | u64 imm; | |
94 | int err; | |
95 | ||
0345584e | 96 | err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod, |
f9baff50 JM |
97 | MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A, |
98 | MLX4_CMD_NATIVE); | |
225c7b1f RD |
99 | |
100 | if (!err) | |
101 | *hash = imm; | |
102 | ||
103 | return err; | |
104 | } | |
105 | ||
b12d93d6 YP |
106 | static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 pf_num, |
107 | enum mlx4_steer_type steer, | |
108 | u32 qpn) | |
109 | { | |
110 | struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[pf_num]; | |
111 | struct mlx4_promisc_qp *pqp; | |
112 | ||
113 | list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { | |
114 | if (pqp->qpn == qpn) | |
115 | return pqp; | |
116 | } | |
117 | /* not found */ | |
118 | return NULL; | |
119 | } | |
120 | ||
121 | /* | |
122 | * Add new entry to steering data structure. | |
123 | * All promisc QPs should be added as well | |
124 | */ | |
0ec2c0f8 | 125 | static int new_steering_entry(struct mlx4_dev *dev, u8 port, |
b12d93d6 YP |
126 | enum mlx4_steer_type steer, |
127 | unsigned int index, u32 qpn) | |
128 | { | |
129 | struct mlx4_steer *s_steer; | |
130 | struct mlx4_cmd_mailbox *mailbox; | |
131 | struct mlx4_mgm *mgm; | |
132 | u32 members_count; | |
133 | struct mlx4_steer_index *new_entry; | |
134 | struct mlx4_promisc_qp *pqp; | |
a14b289d | 135 | struct mlx4_promisc_qp *dqp = NULL; |
b12d93d6 YP |
136 | u32 prot; |
137 | int err; | |
b12d93d6 | 138 | |
4c41b367 | 139 | s_steer = &mlx4_priv(dev)->steer[port - 1]; |
b12d93d6 YP |
140 | new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL); |
141 | if (!new_entry) | |
142 | return -ENOMEM; | |
143 | ||
144 | INIT_LIST_HEAD(&new_entry->duplicates); | |
145 | new_entry->index = index; | |
146 | list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]); | |
147 | ||
148 | /* If the given qpn is also a promisc qp, | |
149 | * it should be inserted to duplicates list | |
150 | */ | |
0ec2c0f8 | 151 | pqp = get_promisc_qp(dev, 0, steer, qpn); |
b12d93d6 YP |
152 | if (pqp) { |
153 | dqp = kmalloc(sizeof *dqp, GFP_KERNEL); | |
154 | if (!dqp) { | |
155 | err = -ENOMEM; | |
156 | goto out_alloc; | |
157 | } | |
158 | dqp->qpn = qpn; | |
159 | list_add_tail(&dqp->list, &new_entry->duplicates); | |
160 | } | |
161 | ||
162 | /* if no promisc qps for this vep, we are done */ | |
163 | if (list_empty(&s_steer->promisc_qps[steer])) | |
164 | return 0; | |
165 | ||
166 | /* now need to add all the promisc qps to the new | |
167 | * steering entry, as they should also receive the packets | |
168 | * destined to this address */ | |
169 | mailbox = mlx4_alloc_cmd_mailbox(dev); | |
170 | if (IS_ERR(mailbox)) { | |
171 | err = -ENOMEM; | |
172 | goto out_alloc; | |
173 | } | |
174 | mgm = mailbox->buf; | |
175 | ||
176 | err = mlx4_READ_ENTRY(dev, index, mailbox); | |
177 | if (err) | |
178 | goto out_mailbox; | |
179 | ||
180 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | |
181 | prot = be32_to_cpu(mgm->members_count) >> 30; | |
182 | list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { | |
183 | /* don't add already existing qpn */ | |
184 | if (pqp->qpn == qpn) | |
185 | continue; | |
0ec2c0f8 | 186 | if (members_count == dev->caps.num_qp_per_mgm) { |
b12d93d6 YP |
187 | /* out of space */ |
188 | err = -ENOMEM; | |
189 | goto out_mailbox; | |
190 | } | |
191 | ||
192 | /* add the qpn */ | |
193 | mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK); | |
194 | } | |
195 | /* update the qps count and update the entry with all the promisc qps*/ | |
196 | mgm->members_count = cpu_to_be32(members_count | (prot << 30)); | |
197 | err = mlx4_WRITE_ENTRY(dev, index, mailbox); | |
198 | ||
199 | out_mailbox: | |
200 | mlx4_free_cmd_mailbox(dev, mailbox); | |
201 | if (!err) | |
202 | return 0; | |
203 | out_alloc: | |
204 | if (dqp) { | |
205 | list_del(&dqp->list); | |
a14b289d | 206 | kfree(dqp); |
b12d93d6 YP |
207 | } |
208 | list_del(&new_entry->list); | |
209 | kfree(new_entry); | |
210 | return err; | |
211 | } | |
212 | ||
213 | /* update the data structures with existing steering entry */ | |
0ec2c0f8 | 214 | static int existing_steering_entry(struct mlx4_dev *dev, u8 port, |
b12d93d6 YP |
215 | enum mlx4_steer_type steer, |
216 | unsigned int index, u32 qpn) | |
217 | { | |
218 | struct mlx4_steer *s_steer; | |
219 | struct mlx4_steer_index *tmp_entry, *entry = NULL; | |
220 | struct mlx4_promisc_qp *pqp; | |
221 | struct mlx4_promisc_qp *dqp; | |
b12d93d6 | 222 | |
4c41b367 | 223 | s_steer = &mlx4_priv(dev)->steer[port - 1]; |
b12d93d6 | 224 | |
0ec2c0f8 | 225 | pqp = get_promisc_qp(dev, 0, steer, qpn); |
b12d93d6 YP |
226 | if (!pqp) |
227 | return 0; /* nothing to do */ | |
228 | ||
229 | list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { | |
230 | if (tmp_entry->index == index) { | |
231 | entry = tmp_entry; | |
232 | break; | |
233 | } | |
234 | } | |
235 | if (unlikely(!entry)) { | |
236 | mlx4_warn(dev, "Steering entry at index %x is not registered\n", index); | |
237 | return -EINVAL; | |
238 | } | |
239 | ||
240 | /* the given qpn is listed as a promisc qpn | |
241 | * we need to add it as a duplicate to this entry | |
25985edc | 242 | * for future references */ |
b12d93d6 | 243 | list_for_each_entry(dqp, &entry->duplicates, list) { |
0ec2c0f8 | 244 | if (qpn == pqp->qpn) |
b12d93d6 YP |
245 | return 0; /* qp is already duplicated */ |
246 | } | |
247 | ||
248 | /* add the qp as a duplicate on this index */ | |
249 | dqp = kmalloc(sizeof *dqp, GFP_KERNEL); | |
250 | if (!dqp) | |
251 | return -ENOMEM; | |
252 | dqp->qpn = qpn; | |
253 | list_add_tail(&dqp->list, &entry->duplicates); | |
254 | ||
255 | return 0; | |
256 | } | |
257 | ||
258 | /* Check whether a qpn is a duplicate on steering entry | |
259 | * If so, it should not be removed from mgm */ | |
0ec2c0f8 | 260 | static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port, |
b12d93d6 YP |
261 | enum mlx4_steer_type steer, |
262 | unsigned int index, u32 qpn) | |
263 | { | |
264 | struct mlx4_steer *s_steer; | |
265 | struct mlx4_steer_index *tmp_entry, *entry = NULL; | |
266 | struct mlx4_promisc_qp *dqp, *tmp_dqp; | |
b12d93d6 | 267 | |
4c41b367 | 268 | s_steer = &mlx4_priv(dev)->steer[port - 1]; |
b12d93d6 YP |
269 | |
270 | /* if qp is not promisc, it cannot be duplicated */ | |
0ec2c0f8 | 271 | if (!get_promisc_qp(dev, 0, steer, qpn)) |
b12d93d6 YP |
272 | return false; |
273 | ||
274 | /* The qp is promisc qp so it is a duplicate on this index | |
275 | * Find the index entry, and remove the duplicate */ | |
276 | list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { | |
277 | if (tmp_entry->index == index) { | |
278 | entry = tmp_entry; | |
279 | break; | |
280 | } | |
281 | } | |
282 | if (unlikely(!entry)) { | |
283 | mlx4_warn(dev, "Steering entry for index %x is not registered\n", index); | |
284 | return false; | |
285 | } | |
286 | list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) { | |
287 | if (dqp->qpn == qpn) { | |
288 | list_del(&dqp->list); | |
289 | kfree(dqp); | |
290 | } | |
291 | } | |
292 | return true; | |
293 | } | |
294 | ||
295 | /* I a steering entry contains only promisc QPs, it can be removed. */ | |
0ec2c0f8 | 296 | static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port, |
b12d93d6 YP |
297 | enum mlx4_steer_type steer, |
298 | unsigned int index, u32 tqpn) | |
299 | { | |
300 | struct mlx4_steer *s_steer; | |
301 | struct mlx4_cmd_mailbox *mailbox; | |
302 | struct mlx4_mgm *mgm; | |
303 | struct mlx4_steer_index *entry = NULL, *tmp_entry; | |
304 | u32 qpn; | |
305 | u32 members_count; | |
306 | bool ret = false; | |
307 | int i; | |
b12d93d6 | 308 | |
4c41b367 | 309 | s_steer = &mlx4_priv(dev)->steer[port - 1]; |
b12d93d6 YP |
310 | |
311 | mailbox = mlx4_alloc_cmd_mailbox(dev); | |
312 | if (IS_ERR(mailbox)) | |
313 | return false; | |
314 | mgm = mailbox->buf; | |
315 | ||
316 | if (mlx4_READ_ENTRY(dev, index, mailbox)) | |
317 | goto out; | |
318 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | |
319 | for (i = 0; i < members_count; i++) { | |
320 | qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; | |
0ec2c0f8 | 321 | if (!get_promisc_qp(dev, 0, steer, qpn) && qpn != tqpn) { |
b12d93d6 YP |
322 | /* the qp is not promisc, the entry can't be removed */ |
323 | goto out; | |
324 | } | |
325 | } | |
326 | /* All the qps currently registered for this entry are promiscuous, | |
327 | * Checking for duplicates */ | |
328 | ret = true; | |
329 | list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { | |
330 | if (entry->index == index) { | |
331 | if (list_empty(&entry->duplicates)) { | |
332 | list_del(&entry->list); | |
333 | kfree(entry); | |
334 | } else { | |
335 | /* This entry contains duplicates so it shouldn't be removed */ | |
336 | ret = false; | |
337 | goto out; | |
338 | } | |
339 | } | |
340 | } | |
341 | ||
342 | out: | |
343 | mlx4_free_cmd_mailbox(dev, mailbox); | |
344 | return ret; | |
345 | } | |
346 | ||
0ec2c0f8 | 347 | static int add_promisc_qp(struct mlx4_dev *dev, u8 port, |
b12d93d6 YP |
348 | enum mlx4_steer_type steer, u32 qpn) |
349 | { | |
350 | struct mlx4_steer *s_steer; | |
351 | struct mlx4_cmd_mailbox *mailbox; | |
352 | struct mlx4_mgm *mgm; | |
353 | struct mlx4_steer_index *entry; | |
354 | struct mlx4_promisc_qp *pqp; | |
355 | struct mlx4_promisc_qp *dqp; | |
356 | u32 members_count; | |
357 | u32 prot; | |
358 | int i; | |
359 | bool found; | |
360 | int last_index; | |
361 | int err; | |
b12d93d6 | 362 | struct mlx4_priv *priv = mlx4_priv(dev); |
0ec2c0f8 | 363 | |
4c41b367 | 364 | s_steer = &mlx4_priv(dev)->steer[port - 1]; |
b12d93d6 YP |
365 | |
366 | mutex_lock(&priv->mcg_table.mutex); | |
367 | ||
0ec2c0f8 | 368 | if (get_promisc_qp(dev, 0, steer, qpn)) { |
b12d93d6 YP |
369 | err = 0; /* Noting to do, already exists */ |
370 | goto out_mutex; | |
371 | } | |
372 | ||
373 | pqp = kmalloc(sizeof *pqp, GFP_KERNEL); | |
374 | if (!pqp) { | |
375 | err = -ENOMEM; | |
376 | goto out_mutex; | |
377 | } | |
378 | pqp->qpn = qpn; | |
379 | ||
380 | mailbox = mlx4_alloc_cmd_mailbox(dev); | |
381 | if (IS_ERR(mailbox)) { | |
382 | err = -ENOMEM; | |
383 | goto out_alloc; | |
384 | } | |
385 | mgm = mailbox->buf; | |
386 | ||
387 | /* the promisc qp needs to be added for each one of the steering | |
388 | * entries, if it already exists, needs to be added as a duplicate | |
389 | * for this entry */ | |
390 | list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { | |
391 | err = mlx4_READ_ENTRY(dev, entry->index, mailbox); | |
392 | if (err) | |
393 | goto out_mailbox; | |
394 | ||
395 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | |
396 | prot = be32_to_cpu(mgm->members_count) >> 30; | |
397 | found = false; | |
398 | for (i = 0; i < members_count; i++) { | |
399 | if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { | |
400 | /* Entry already exists, add to duplicates */ | |
401 | dqp = kmalloc(sizeof *dqp, GFP_KERNEL); | |
402 | if (!dqp) | |
403 | goto out_mailbox; | |
404 | dqp->qpn = qpn; | |
405 | list_add_tail(&dqp->list, &entry->duplicates); | |
406 | found = true; | |
407 | } | |
408 | } | |
409 | if (!found) { | |
410 | /* Need to add the qpn to mgm */ | |
0ec2c0f8 | 411 | if (members_count == dev->caps.num_qp_per_mgm) { |
b12d93d6 YP |
412 | /* entry is full */ |
413 | err = -ENOMEM; | |
414 | goto out_mailbox; | |
415 | } | |
416 | mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK); | |
417 | mgm->members_count = cpu_to_be32(members_count | (prot << 30)); | |
418 | err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); | |
419 | if (err) | |
420 | goto out_mailbox; | |
421 | } | |
422 | last_index = entry->index; | |
423 | } | |
424 | ||
425 | /* add the new qpn to list of promisc qps */ | |
426 | list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); | |
427 | /* now need to add all the promisc qps to default entry */ | |
428 | memset(mgm, 0, sizeof *mgm); | |
429 | members_count = 0; | |
430 | list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) | |
431 | mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); | |
432 | mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); | |
433 | ||
0ec2c0f8 | 434 | err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); |
b12d93d6 YP |
435 | if (err) |
436 | goto out_list; | |
437 | ||
438 | mlx4_free_cmd_mailbox(dev, mailbox); | |
439 | mutex_unlock(&priv->mcg_table.mutex); | |
440 | return 0; | |
441 | ||
442 | out_list: | |
443 | list_del(&pqp->list); | |
444 | out_mailbox: | |
445 | mlx4_free_cmd_mailbox(dev, mailbox); | |
446 | out_alloc: | |
447 | kfree(pqp); | |
448 | out_mutex: | |
449 | mutex_unlock(&priv->mcg_table.mutex); | |
450 | return err; | |
451 | } | |
452 | ||
0ec2c0f8 | 453 | static int remove_promisc_qp(struct mlx4_dev *dev, u8 port, |
b12d93d6 YP |
454 | enum mlx4_steer_type steer, u32 qpn) |
455 | { | |
456 | struct mlx4_priv *priv = mlx4_priv(dev); | |
457 | struct mlx4_steer *s_steer; | |
458 | struct mlx4_cmd_mailbox *mailbox; | |
459 | struct mlx4_mgm *mgm; | |
460 | struct mlx4_steer_index *entry; | |
461 | struct mlx4_promisc_qp *pqp; | |
462 | struct mlx4_promisc_qp *dqp; | |
463 | u32 members_count; | |
464 | bool found; | |
465 | bool back_to_list = false; | |
466 | int loc, i; | |
467 | int err; | |
b12d93d6 | 468 | |
4c41b367 | 469 | s_steer = &mlx4_priv(dev)->steer[port - 1]; |
b12d93d6 YP |
470 | mutex_lock(&priv->mcg_table.mutex); |
471 | ||
0ec2c0f8 | 472 | pqp = get_promisc_qp(dev, 0, steer, qpn); |
b12d93d6 YP |
473 | if (unlikely(!pqp)) { |
474 | mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); | |
475 | /* nothing to do */ | |
476 | err = 0; | |
477 | goto out_mutex; | |
478 | } | |
479 | ||
480 | /*remove from list of promisc qps */ | |
481 | list_del(&pqp->list); | |
b12d93d6 YP |
482 | |
483 | /* set the default entry not to include the removed one */ | |
484 | mailbox = mlx4_alloc_cmd_mailbox(dev); | |
485 | if (IS_ERR(mailbox)) { | |
486 | err = -ENOMEM; | |
487 | back_to_list = true; | |
488 | goto out_list; | |
489 | } | |
490 | mgm = mailbox->buf; | |
0ec2c0f8 | 491 | memset(mgm, 0, sizeof *mgm); |
b12d93d6 YP |
492 | members_count = 0; |
493 | list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) | |
494 | mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); | |
495 | mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); | |
496 | ||
0ec2c0f8 | 497 | err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox); |
b12d93d6 YP |
498 | if (err) |
499 | goto out_mailbox; | |
500 | ||
501 | /* remove the qp from all the steering entries*/ | |
502 | list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { | |
503 | found = false; | |
504 | list_for_each_entry(dqp, &entry->duplicates, list) { | |
505 | if (dqp->qpn == qpn) { | |
506 | found = true; | |
507 | break; | |
508 | } | |
509 | } | |
510 | if (found) { | |
511 | /* a duplicate, no need to change the mgm, | |
512 | * only update the duplicates list */ | |
513 | list_del(&dqp->list); | |
514 | kfree(dqp); | |
515 | } else { | |
516 | err = mlx4_READ_ENTRY(dev, entry->index, mailbox); | |
517 | if (err) | |
518 | goto out_mailbox; | |
519 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; | |
520 | for (loc = -1, i = 0; i < members_count; ++i) | |
521 | if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) | |
522 | loc = i; | |
523 | ||
524 | mgm->members_count = cpu_to_be32(--members_count | | |
525 | (MLX4_PROT_ETH << 30)); | |
526 | mgm->qp[loc] = mgm->qp[i - 1]; | |
527 | mgm->qp[i - 1] = 0; | |
528 | ||
529 | err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); | |
530 | if (err) | |
531 | goto out_mailbox; | |
532 | } | |
533 | ||
534 | } | |
535 | ||
536 | out_mailbox: | |
537 | mlx4_free_cmd_mailbox(dev, mailbox); | |
538 | out_list: | |
539 | if (back_to_list) | |
540 | list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); | |
53020092 YP |
541 | else |
542 | kfree(pqp); | |
b12d93d6 YP |
543 | out_mutex: |
544 | mutex_unlock(&priv->mcg_table.mutex); | |
545 | return err; | |
546 | } | |
547 | ||
225c7b1f RD |
548 | /* |
549 | * Caller must hold MCG table semaphore. gid and mgm parameters must | |
550 | * be properly aligned for command interface. | |
551 | * | |
552 | * Returns 0 unless a firmware command error occurs. | |
553 | * | |
554 | * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 | |
555 | * and *mgm holds MGM entry. | |
556 | * | |
557 | * if GID is found in AMGM, *index = index in AMGM, *prev = index of | |
558 | * previous entry in hash chain and *mgm holds AMGM entry. | |
559 | * | |
560 | * If no AMGM exists for given gid, *index = -1, *prev = index of last | |
561 | * entry in hash chain and *mgm holds end of hash chain. | |
562 | */ | |
0345584e YP |
563 | static int find_entry(struct mlx4_dev *dev, u8 port, |
564 | u8 *gid, enum mlx4_protocol prot, | |
565 | enum mlx4_steer_type steer, | |
566 | struct mlx4_cmd_mailbox *mgm_mailbox, | |
567 | u16 *hash, int *prev, int *index) | |
225c7b1f RD |
568 | { |
569 | struct mlx4_cmd_mailbox *mailbox; | |
570 | struct mlx4_mgm *mgm = mgm_mailbox->buf; | |
571 | u8 *mgid; | |
572 | int err; | |
ccf86321 OG |
573 | u8 op_mod = (prot == MLX4_PROT_ETH) ? |
574 | !!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0; | |
225c7b1f RD |
575 | |
576 | mailbox = mlx4_alloc_cmd_mailbox(dev); | |
577 | if (IS_ERR(mailbox)) | |
578 | return -ENOMEM; | |
579 | mgid = mailbox->buf; | |
580 | ||
581 | memcpy(mgid, gid, 16); | |
582 | ||
0345584e | 583 | err = mlx4_GID_HASH(dev, mailbox, hash, op_mod); |
225c7b1f RD |
584 | mlx4_free_cmd_mailbox(dev, mailbox); |
585 | if (err) | |
586 | return err; | |
587 | ||
588 | if (0) | |
5b095d98 | 589 | mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash); |
225c7b1f RD |
590 | |
591 | *index = *hash; | |
592 | *prev = -1; | |
593 | ||
594 | do { | |
0345584e | 595 | err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox); |
225c7b1f RD |
596 | if (err) |
597 | return err; | |
598 | ||
0345584e | 599 | if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { |
225c7b1f RD |
600 | if (*index != *hash) { |
601 | mlx4_err(dev, "Found zero MGID in AMGM.\n"); | |
602 | err = -EINVAL; | |
603 | } | |
604 | return err; | |
605 | } | |
606 | ||
da995a8a | 607 | if (!memcmp(mgm->gid, gid, 16) && |
0345584e | 608 | be32_to_cpu(mgm->members_count) >> 30 == prot) |
225c7b1f RD |
609 | return err; |
610 | ||
611 | *prev = *index; | |
612 | *index = be32_to_cpu(mgm->next_gid_index) >> 6; | |
613 | } while (*index); | |
614 | ||
615 | *index = -1; | |
616 | return err; | |
617 | } | |
618 | ||
0345584e YP |
619 | int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], |
620 | int block_mcast_loopback, enum mlx4_protocol prot, | |
621 | enum mlx4_steer_type steer) | |
225c7b1f RD |
622 | { |
623 | struct mlx4_priv *priv = mlx4_priv(dev); | |
624 | struct mlx4_cmd_mailbox *mailbox; | |
625 | struct mlx4_mgm *mgm; | |
626 | u32 members_count; | |
627 | u16 hash; | |
628 | int index, prev; | |
629 | int link = 0; | |
630 | int i; | |
631 | int err; | |
0345584e | 632 | u8 port = gid[5]; |
b12d93d6 | 633 | u8 new_entry = 0; |
225c7b1f RD |
634 | |
635 | mailbox = mlx4_alloc_cmd_mailbox(dev); | |
636 | if (IS_ERR(mailbox)) | |
637 | return PTR_ERR(mailbox); | |
638 | mgm = mailbox->buf; | |
639 | ||
640 | mutex_lock(&priv->mcg_table.mutex); | |
0345584e YP |
641 | err = find_entry(dev, port, gid, prot, steer, |
642 | mailbox, &hash, &prev, &index); | |
225c7b1f RD |
643 | if (err) |
644 | goto out; | |
645 | ||
646 | if (index != -1) { | |
b12d93d6 YP |
647 | if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { |
648 | new_entry = 1; | |
225c7b1f | 649 | memcpy(mgm->gid, gid, 16); |
b12d93d6 | 650 | } |
225c7b1f RD |
651 | } else { |
652 | link = 1; | |
653 | ||
654 | index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); | |
655 | if (index == -1) { | |
656 | mlx4_err(dev, "No AMGM entries left\n"); | |
657 | err = -ENOMEM; | |
658 | goto out; | |
659 | } | |
660 | index += dev->caps.num_mgms; | |
661 | ||
0ec2c0f8 | 662 | new_entry = 1; |
225c7b1f RD |
663 | memset(mgm, 0, sizeof *mgm); |
664 | memcpy(mgm->gid, gid, 16); | |
665 | } | |
666 | ||
da995a8a | 667 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; |
0ec2c0f8 | 668 | if (members_count == dev->caps.num_qp_per_mgm) { |
225c7b1f RD |
669 | mlx4_err(dev, "MGM at index %x is full.\n", index); |
670 | err = -ENOMEM; | |
671 | goto out; | |
672 | } | |
673 | ||
674 | for (i = 0; i < members_count; ++i) | |
521e575b | 675 | if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { |
225c7b1f RD |
676 | mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); |
677 | err = 0; | |
678 | goto out; | |
679 | } | |
680 | ||
521e575b RL |
681 | if (block_mcast_loopback) |
682 | mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | | |
e6a17622 | 683 | (1U << MGM_BLCK_LB_BIT)); |
521e575b RL |
684 | else |
685 | mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); | |
686 | ||
0345584e | 687 | mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30); |
225c7b1f | 688 | |
0345584e | 689 | err = mlx4_WRITE_ENTRY(dev, index, mailbox); |
225c7b1f RD |
690 | if (err) |
691 | goto out; | |
692 | ||
693 | if (!link) | |
694 | goto out; | |
695 | ||
0345584e | 696 | err = mlx4_READ_ENTRY(dev, prev, mailbox); |
225c7b1f RD |
697 | if (err) |
698 | goto out; | |
699 | ||
700 | mgm->next_gid_index = cpu_to_be32(index << 6); | |
701 | ||
0345584e | 702 | err = mlx4_WRITE_ENTRY(dev, prev, mailbox); |
225c7b1f RD |
703 | if (err) |
704 | goto out; | |
705 | ||
706 | out: | |
b12d93d6 YP |
707 | if (prot == MLX4_PROT_ETH) { |
708 | /* manage the steering entry for promisc mode */ | |
709 | if (new_entry) | |
0ec2c0f8 | 710 | new_steering_entry(dev, port, steer, index, qp->qpn); |
b12d93d6 | 711 | else |
0ec2c0f8 | 712 | existing_steering_entry(dev, port, steer, |
b12d93d6 YP |
713 | index, qp->qpn); |
714 | } | |
225c7b1f RD |
715 | if (err && link && index != -1) { |
716 | if (index < dev->caps.num_mgms) | |
717 | mlx4_warn(dev, "Got AMGM index %d < %d", | |
718 | index, dev->caps.num_mgms); | |
719 | else | |
720 | mlx4_bitmap_free(&priv->mcg_table.bitmap, | |
721 | index - dev->caps.num_mgms); | |
722 | } | |
723 | mutex_unlock(&priv->mcg_table.mutex); | |
724 | ||
725 | mlx4_free_cmd_mailbox(dev, mailbox); | |
726 | return err; | |
727 | } | |
225c7b1f | 728 | |
0345584e YP |
729 | int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], |
730 | enum mlx4_protocol prot, enum mlx4_steer_type steer) | |
225c7b1f RD |
731 | { |
732 | struct mlx4_priv *priv = mlx4_priv(dev); | |
733 | struct mlx4_cmd_mailbox *mailbox; | |
734 | struct mlx4_mgm *mgm; | |
735 | u32 members_count; | |
736 | u16 hash; | |
737 | int prev, index; | |
738 | int i, loc; | |
739 | int err; | |
0345584e | 740 | u8 port = gid[5]; |
b12d93d6 | 741 | bool removed_entry = false; |
225c7b1f RD |
742 | |
743 | mailbox = mlx4_alloc_cmd_mailbox(dev); | |
744 | if (IS_ERR(mailbox)) | |
745 | return PTR_ERR(mailbox); | |
746 | mgm = mailbox->buf; | |
747 | ||
748 | mutex_lock(&priv->mcg_table.mutex); | |
749 | ||
0345584e YP |
750 | err = find_entry(dev, port, gid, prot, steer, |
751 | mailbox, &hash, &prev, &index); | |
225c7b1f RD |
752 | if (err) |
753 | goto out; | |
754 | ||
755 | if (index == -1) { | |
5b095d98 | 756 | mlx4_err(dev, "MGID %pI6 not found\n", gid); |
225c7b1f RD |
757 | err = -EINVAL; |
758 | goto out; | |
759 | } | |
760 | ||
b12d93d6 YP |
761 | /* if this pq is also a promisc qp, it shouldn't be removed */ |
762 | if (prot == MLX4_PROT_ETH && | |
0ec2c0f8 | 763 | check_duplicate_entry(dev, port, steer, index, qp->qpn)) |
b12d93d6 YP |
764 | goto out; |
765 | ||
da995a8a | 766 | members_count = be32_to_cpu(mgm->members_count) & 0xffffff; |
225c7b1f | 767 | for (loc = -1, i = 0; i < members_count; ++i) |
521e575b | 768 | if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) |
225c7b1f RD |
769 | loc = i; |
770 | ||
771 | if (loc == -1) { | |
772 | mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); | |
773 | err = -EINVAL; | |
774 | goto out; | |
775 | } | |
776 | ||
777 | ||
0345584e | 778 | mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); |
225c7b1f RD |
779 | mgm->qp[loc] = mgm->qp[i - 1]; |
780 | mgm->qp[i - 1] = 0; | |
781 | ||
b12d93d6 | 782 | if (prot == MLX4_PROT_ETH) |
0ec2c0f8 EE |
783 | removed_entry = can_remove_steering_entry(dev, port, steer, |
784 | index, qp->qpn); | |
b12d93d6 | 785 | if (i != 1 && (prot != MLX4_PROT_ETH || !removed_entry)) { |
0345584e | 786 | err = mlx4_WRITE_ENTRY(dev, index, mailbox); |
225c7b1f | 787 | goto out; |
4dc51b32 | 788 | } |
225c7b1f | 789 | |
b12d93d6 YP |
790 | /* We are going to delete the entry, members count should be 0 */ |
791 | mgm->members_count = cpu_to_be32((u32) prot << 30); | |
792 | ||
225c7b1f RD |
793 | if (prev == -1) { |
794 | /* Remove entry from MGM */ | |
795 | int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; | |
796 | if (amgm_index) { | |
0345584e | 797 | err = mlx4_READ_ENTRY(dev, amgm_index, mailbox); |
225c7b1f RD |
798 | if (err) |
799 | goto out; | |
800 | } else | |
801 | memset(mgm->gid, 0, 16); | |
802 | ||
0345584e | 803 | err = mlx4_WRITE_ENTRY(dev, index, mailbox); |
225c7b1f RD |
804 | if (err) |
805 | goto out; | |
806 | ||
807 | if (amgm_index) { | |
808 | if (amgm_index < dev->caps.num_mgms) | |
809 | mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d", | |
810 | index, amgm_index, dev->caps.num_mgms); | |
811 | else | |
812 | mlx4_bitmap_free(&priv->mcg_table.bitmap, | |
813 | amgm_index - dev->caps.num_mgms); | |
814 | } | |
815 | } else { | |
816 | /* Remove entry from AMGM */ | |
817 | int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; | |
0345584e | 818 | err = mlx4_READ_ENTRY(dev, prev, mailbox); |
225c7b1f RD |
819 | if (err) |
820 | goto out; | |
821 | ||
822 | mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); | |
823 | ||
0345584e | 824 | err = mlx4_WRITE_ENTRY(dev, prev, mailbox); |
225c7b1f RD |
825 | if (err) |
826 | goto out; | |
827 | ||
828 | if (index < dev->caps.num_mgms) | |
829 | mlx4_warn(dev, "entry %d had next AMGM index %d < %d", | |
830 | prev, index, dev->caps.num_mgms); | |
831 | else | |
832 | mlx4_bitmap_free(&priv->mcg_table.bitmap, | |
833 | index - dev->caps.num_mgms); | |
834 | } | |
835 | ||
836 | out: | |
837 | mutex_unlock(&priv->mcg_table.mutex); | |
838 | ||
839 | mlx4_free_cmd_mailbox(dev, mailbox); | |
840 | return err; | |
841 | } | |
0345584e | 842 | |
0ec2c0f8 EE |
843 | static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp, |
844 | u8 gid[16], u8 attach, u8 block_loopback, | |
845 | enum mlx4_protocol prot) | |
846 | { | |
847 | struct mlx4_cmd_mailbox *mailbox; | |
848 | int err = 0; | |
849 | int qpn; | |
850 | ||
851 | if (!mlx4_is_mfunc(dev)) | |
852 | return -EBADF; | |
853 | ||
854 | mailbox = mlx4_alloc_cmd_mailbox(dev); | |
855 | if (IS_ERR(mailbox)) | |
856 | return PTR_ERR(mailbox); | |
857 | ||
858 | memcpy(mailbox->buf, gid, 16); | |
859 | qpn = qp->qpn; | |
860 | qpn |= (prot << 28); | |
861 | if (attach && block_loopback) | |
862 | qpn |= (1 << 31); | |
863 | ||
864 | err = mlx4_cmd(dev, mailbox->dma, qpn, attach, | |
865 | MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A, | |
866 | MLX4_CMD_WRAPPED); | |
867 | ||
868 | mlx4_free_cmd_mailbox(dev, mailbox); | |
869 | return err; | |
870 | } | |
0345584e YP |
871 | |
872 | int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |
873 | int block_mcast_loopback, enum mlx4_protocol prot) | |
874 | { | |
875 | enum mlx4_steer_type steer; | |
876 | ||
877 | steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; | |
878 | ||
ccf86321 OG |
879 | if (prot == MLX4_PROT_ETH && |
880 | !(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)) | |
0345584e YP |
881 | return 0; |
882 | ||
883 | if (prot == MLX4_PROT_ETH) | |
884 | gid[7] |= (steer << 1); | |
885 | ||
0ec2c0f8 EE |
886 | if (mlx4_is_mfunc(dev)) |
887 | return mlx4_QP_ATTACH(dev, qp, gid, 1, | |
888 | block_mcast_loopback, prot); | |
889 | ||
890 | return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback, | |
891 | prot, steer); | |
0345584e YP |
892 | } |
893 | EXPORT_SYMBOL_GPL(mlx4_multicast_attach); | |
894 | ||
895 | int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], | |
896 | enum mlx4_protocol prot) | |
897 | { | |
898 | enum mlx4_steer_type steer; | |
899 | ||
900 | steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; | |
901 | ||
ccf86321 OG |
902 | if (prot == MLX4_PROT_ETH && |
903 | !(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)) | |
0345584e YP |
904 | return 0; |
905 | ||
0ec2c0f8 | 906 | if (prot == MLX4_PROT_ETH) |
0345584e | 907 | gid[7] |= (steer << 1); |
0ec2c0f8 EE |
908 | |
909 | if (mlx4_is_mfunc(dev)) | |
910 | return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); | |
0345584e YP |
911 | |
912 | return mlx4_qp_detach_common(dev, qp, gid, prot, steer); | |
913 | } | |
225c7b1f RD |
914 | EXPORT_SYMBOL_GPL(mlx4_multicast_detach); |
915 | ||
ffe455ad | 916 | int mlx4_unicast_attach(struct mlx4_dev *dev, |
0ec2c0f8 EE |
917 | struct mlx4_qp *qp, u8 gid[16], |
918 | int block_mcast_loopback, enum mlx4_protocol prot) | |
919 | { | |
920 | if (prot == MLX4_PROT_ETH && | |
921 | !(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER)) | |
922 | return 0; | |
923 | ||
924 | if (prot == MLX4_PROT_ETH) | |
925 | gid[7] |= (MLX4_UC_STEER << 1); | |
926 | ||
927 | if (mlx4_is_mfunc(dev)) | |
928 | return mlx4_QP_ATTACH(dev, qp, gid, 1, | |
929 | block_mcast_loopback, prot); | |
930 | ||
931 | return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback, | |
932 | prot, MLX4_UC_STEER); | |
933 | } | |
934 | EXPORT_SYMBOL_GPL(mlx4_unicast_attach); | |
935 | ||
ffe455ad | 936 | int mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, |
0ec2c0f8 EE |
937 | u8 gid[16], enum mlx4_protocol prot) |
938 | { | |
939 | if (prot == MLX4_PROT_ETH && | |
940 | !(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER)) | |
941 | return 0; | |
942 | ||
943 | if (prot == MLX4_PROT_ETH) | |
944 | gid[7] |= (MLX4_UC_STEER << 1); | |
945 | ||
946 | if (mlx4_is_mfunc(dev)) | |
947 | return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot); | |
948 | ||
949 | return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER); | |
950 | } | |
951 | EXPORT_SYMBOL_GPL(mlx4_unicast_detach); | |
952 | ||
953 | int mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave, | |
954 | struct mlx4_vhcr *vhcr, | |
955 | struct mlx4_cmd_mailbox *inbox, | |
956 | struct mlx4_cmd_mailbox *outbox, | |
957 | struct mlx4_cmd_info *cmd) | |
958 | { | |
959 | u32 qpn = (u32) vhcr->in_param & 0xffffffff; | |
960 | u8 port = vhcr->in_param >> 62; | |
961 | enum mlx4_steer_type steer = vhcr->in_modifier; | |
962 | ||
963 | /* Promiscuous unicast is not allowed in mfunc */ | |
964 | if (mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER) | |
965 | return 0; | |
966 | ||
967 | if (vhcr->op_modifier) | |
968 | return add_promisc_qp(dev, port, steer, qpn); | |
969 | else | |
970 | return remove_promisc_qp(dev, port, steer, qpn); | |
971 | } | |
972 | ||
973 | static int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn, | |
974 | enum mlx4_steer_type steer, u8 add, u8 port) | |
975 | { | |
976 | return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add, | |
977 | MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A, | |
978 | MLX4_CMD_WRAPPED); | |
979 | } | |
b12d93d6 YP |
980 | |
981 | int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) | |
982 | { | |
ccf86321 | 983 | if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)) |
b12d93d6 YP |
984 | return 0; |
985 | ||
0ec2c0f8 EE |
986 | if (mlx4_is_mfunc(dev)) |
987 | return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port); | |
b12d93d6 | 988 | |
0ec2c0f8 | 989 | return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn); |
b12d93d6 YP |
990 | } |
991 | EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add); | |
992 | ||
993 | int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) | |
994 | { | |
ccf86321 | 995 | if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)) |
b12d93d6 YP |
996 | return 0; |
997 | ||
0ec2c0f8 EE |
998 | if (mlx4_is_mfunc(dev)) |
999 | return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port); | |
b12d93d6 | 1000 | |
0ec2c0f8 | 1001 | return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn); |
b12d93d6 YP |
1002 | } |
1003 | EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove); | |
1004 | ||
1005 | int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) | |
1006 | { | |
4df99504 | 1007 | if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER)) |
b12d93d6 YP |
1008 | return 0; |
1009 | ||
0ec2c0f8 EE |
1010 | if (mlx4_is_mfunc(dev)) |
1011 | return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port); | |
b12d93d6 | 1012 | |
0ec2c0f8 | 1013 | return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn); |
b12d93d6 YP |
1014 | } |
1015 | EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add); | |
1016 | ||
1017 | int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) | |
1018 | { | |
4df99504 | 1019 | if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER)) |
b12d93d6 YP |
1020 | return 0; |
1021 | ||
0ec2c0f8 EE |
1022 | if (mlx4_is_mfunc(dev)) |
1023 | return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port); | |
1024 | ||
1025 | return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn); | |
b12d93d6 YP |
1026 | } |
1027 | EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove); | |
1028 | ||
3d73c288 | 1029 | int mlx4_init_mcg_table(struct mlx4_dev *dev) |
225c7b1f RD |
1030 | { |
1031 | struct mlx4_priv *priv = mlx4_priv(dev); | |
1032 | int err; | |
1033 | ||
93fc9e1b YP |
1034 | err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms, |
1035 | dev->caps.num_amgms - 1, 0, 0); | |
225c7b1f RD |
1036 | if (err) |
1037 | return err; | |
1038 | ||
1039 | mutex_init(&priv->mcg_table.mutex); | |
1040 | ||
1041 | return 0; | |
1042 | } | |
1043 | ||
1044 | void mlx4_cleanup_mcg_table(struct mlx4_dev *dev) | |
1045 | { | |
1046 | mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); | |
1047 | } |