mlx4_mcg.c revision 255932
1219820Sjeff/*
2219820Sjeff * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
3219820Sjeff * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
4219820Sjeff *
5219820Sjeff * This software is available to you under a choice of one of two
6219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
7219820Sjeff * General Public License (GPL) Version 2, available from the file
8219820Sjeff * COPYING in the main directory of this source tree, or the
9219820Sjeff * OpenIB.org BSD license below:
10219820Sjeff *
11219820Sjeff *     Redistribution and use in source and binary forms, with or
12219820Sjeff *     without modification, are permitted provided that the following
13219820Sjeff *     conditions are met:
14219820Sjeff *
15219820Sjeff *      - Redistributions of source code must retain the above
16219820Sjeff *        copyright notice, this list of conditions and the following
17219820Sjeff *        disclaimer.
18219820Sjeff *
19219820Sjeff *      - Redistributions in binary form must reproduce the above
20219820Sjeff *        copyright notice, this list of conditions and the following
21219820Sjeff *        disclaimer in the documentation and/or other materials
22219820Sjeff *        provided with the distribution.
23219820Sjeff *
24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31219820Sjeff * SOFTWARE.
32219820Sjeff */
33219820Sjeff
34219820Sjeff#include <linux/string.h>
35219820Sjeff
36219820Sjeff#include <linux/mlx4/cmd.h>
37219820Sjeff
38219820Sjeff#include "mlx4.h"
39219820Sjeff
40219820Sjeff
41219820Sjeffstatic const u8 zero_gid[16];	/* automatically initialized to 0 */
42219820Sjeff
43255932Salfredint mlx4_get_mgm_entry_size(struct mlx4_dev *dev)
44219820Sjeff{
45255932Salfred	return 1 << dev->oper_log_mgm_entry_size;
46255932Salfred}
47255932Salfred
48255932Salfredint mlx4_get_qp_per_mgm(struct mlx4_dev *dev)
49255932Salfred{
50255932Salfred	return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2);
51255932Salfred}
52255932Salfred
53255932Salfredstatic int mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev *dev,
54255932Salfred					struct mlx4_cmd_mailbox *mailbox,
55255932Salfred					u32 size,
56255932Salfred					u64 *reg_id)
57255932Salfred{
58255932Salfred	u64 imm;
59255932Salfred	int err = 0;
60255932Salfred
61255932Salfred	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, size, 0,
62255932Salfred			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
63255932Salfred			   MLX4_CMD_NATIVE);
64255932Salfred	if (err)
65255932Salfred		return err;
66255932Salfred	*reg_id = imm;
67255932Salfred
68255932Salfred	return err;
69255932Salfred}
70255932Salfred
71255932Salfredstatic int mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev *dev, u64 regid)
72255932Salfred{
73255932Salfred	int err = 0;
74255932Salfred
75255932Salfred	err = mlx4_cmd(dev, regid, 0, 0,
76255932Salfred		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
77255932Salfred		       MLX4_CMD_NATIVE);
78255932Salfred
79255932Salfred	return err;
80255932Salfred}
81255932Salfred
82255932Salfredstatic int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index,
83255932Salfred			   struct mlx4_cmd_mailbox *mailbox)
84255932Salfred{
85219820Sjeff	return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG,
86255932Salfred			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
87219820Sjeff}
88219820Sjeff
89255932Salfredstatic int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index,
90255932Salfred			    struct mlx4_cmd_mailbox *mailbox)
91219820Sjeff{
92219820Sjeff	return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG,
93255932Salfred			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
94219820Sjeff}
95219820Sjeff
96255932Salfredstatic int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer,
97255932Salfred			      struct mlx4_cmd_mailbox *mailbox)
98219820Sjeff{
99255932Salfred	u32 in_mod;
100255932Salfred
101255932Salfred	in_mod = (u32) port << 16 | steer << 1;
102255932Salfred	return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1,
103255932Salfred			MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A,
104255932Salfred			MLX4_CMD_NATIVE);
105255932Salfred}
106255932Salfred
107255932Salfredstatic int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
108255932Salfred			 u16 *hash, u8 op_mod)
109255932Salfred{
110219820Sjeff	u64 imm;
111219820Sjeff	int err;
112219820Sjeff
113255932Salfred	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod,
114255932Salfred			   MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A,
115255932Salfred			   MLX4_CMD_NATIVE);
116219820Sjeff
117219820Sjeff	if (!err)
118219820Sjeff		*hash = imm;
119219820Sjeff
120219820Sjeff	return err;
121219820Sjeff}
122219820Sjeff
123255932Salfredstatic struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port,
124255932Salfred					      enum mlx4_steer_type steer,
125255932Salfred					      u32 qpn)
126255932Salfred{
127255932Salfred	struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[port - 1];
128255932Salfred	struct mlx4_promisc_qp *pqp;
129255932Salfred
130255932Salfred	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
131255932Salfred		if (pqp->qpn == qpn)
132255932Salfred			return pqp;
133255932Salfred	}
134255932Salfred	/* not found */
135255932Salfred	return NULL;
136255932Salfred}
137255932Salfred
138219820Sjeff/*
139255932Salfred * Add new entry to steering data structure.
140255932Salfred * All promisc QPs should be added as well
141255932Salfred */
142255932Salfredstatic int new_steering_entry(struct mlx4_dev *dev, u8 port,
143255932Salfred			      enum mlx4_steer_type steer,
144255932Salfred			      unsigned int index, u32 qpn)
145255932Salfred{
146255932Salfred	struct mlx4_steer *s_steer;
147255932Salfred	struct mlx4_cmd_mailbox *mailbox;
148255932Salfred	struct mlx4_mgm *mgm;
149255932Salfred	u32 members_count;
150255932Salfred	struct mlx4_steer_index *new_entry;
151255932Salfred	struct mlx4_promisc_qp *pqp;
152255932Salfred	struct mlx4_promisc_qp *dqp = NULL;
153255932Salfred	u32 prot;
154255932Salfred	int err;
155255932Salfred
156255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
157255932Salfred	new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL);
158255932Salfred	if (!new_entry)
159255932Salfred		return -ENOMEM;
160255932Salfred
161255932Salfred	INIT_LIST_HEAD(&new_entry->duplicates);
162255932Salfred	new_entry->index = index;
163255932Salfred	list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]);
164255932Salfred
165255932Salfred	/* If the given qpn is also a promisc qp,
166255932Salfred	 * it should be inserted to duplicates list
167255932Salfred	 */
168255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
169255932Salfred	if (pqp) {
170255932Salfred		dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
171255932Salfred		if (!dqp) {
172255932Salfred			err = -ENOMEM;
173255932Salfred			goto out_alloc;
174255932Salfred		}
175255932Salfred		dqp->qpn = qpn;
176255932Salfred		list_add_tail(&dqp->list, &new_entry->duplicates);
177255932Salfred	}
178255932Salfred
179255932Salfred	/* if no promisc qps for this vep, we are done */
180255932Salfred	if (list_empty(&s_steer->promisc_qps[steer]))
181255932Salfred		return 0;
182255932Salfred
183255932Salfred	/* now need to add all the promisc qps to the new
184255932Salfred	 * steering entry, as they should also receive the packets
185255932Salfred	 * destined to this address */
186255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
187255932Salfred	if (IS_ERR(mailbox)) {
188255932Salfred		err = -ENOMEM;
189255932Salfred		goto out_alloc;
190255932Salfred	}
191255932Salfred	mgm = mailbox->buf;
192255932Salfred
193255932Salfred	err = mlx4_READ_ENTRY(dev, index, mailbox);
194255932Salfred	if (err)
195255932Salfred		goto out_mailbox;
196255932Salfred
197255932Salfred	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
198255932Salfred	prot = be32_to_cpu(mgm->members_count) >> 30;
199255932Salfred	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
200255932Salfred		/* don't add already existing qpn */
201255932Salfred		if (pqp->qpn == qpn)
202255932Salfred			continue;
203255932Salfred		if (members_count == dev->caps.num_qp_per_mgm) {
204255932Salfred			/* out of space */
205255932Salfred			err = -ENOMEM;
206255932Salfred			goto out_mailbox;
207255932Salfred		}
208255932Salfred
209255932Salfred		/* add the qpn */
210255932Salfred		mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK);
211255932Salfred	}
212255932Salfred	/* update the qps count and update the entry with all the promisc qps*/
213255932Salfred	mgm->members_count = cpu_to_be32(members_count | (prot << 30));
214255932Salfred	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
215255932Salfred
216255932Salfredout_mailbox:
217255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
218255932Salfred	if (!err)
219255932Salfred		return 0;
220255932Salfredout_alloc:
221255932Salfred	if (dqp) {
222255932Salfred		list_del(&dqp->list);
223255932Salfred		kfree(dqp);
224255932Salfred	}
225255932Salfred	list_del(&new_entry->list);
226255932Salfred	kfree(new_entry);
227255932Salfred	return err;
228255932Salfred}
229255932Salfred
230255932Salfred/* update the data structures with existing steering entry */
231255932Salfredstatic int existing_steering_entry(struct mlx4_dev *dev, u8 port,
232255932Salfred				   enum mlx4_steer_type steer,
233255932Salfred				   unsigned int index, u32 qpn)
234255932Salfred{
235255932Salfred	struct mlx4_steer *s_steer;
236255932Salfred	struct mlx4_steer_index *tmp_entry, *entry = NULL;
237255932Salfred	struct mlx4_promisc_qp *pqp;
238255932Salfred	struct mlx4_promisc_qp *dqp;
239255932Salfred
240255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
241255932Salfred
242255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
243255932Salfred	if (!pqp)
244255932Salfred		return 0; /* nothing to do */
245255932Salfred
246255932Salfred	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
247255932Salfred		if (tmp_entry->index == index) {
248255932Salfred			entry = tmp_entry;
249255932Salfred			break;
250255932Salfred		}
251255932Salfred	}
252255932Salfred	if (unlikely(!entry)) {
253255932Salfred		mlx4_warn(dev, "Steering entry at index %x is not registered\n", index);
254255932Salfred		return -EINVAL;
255255932Salfred	}
256255932Salfred
257255932Salfred	/* the given qpn is listed as a promisc qpn
258255932Salfred	 * we need to add it as a duplicate to this entry
259255932Salfred	 * for future references */
260255932Salfred	list_for_each_entry(dqp, &entry->duplicates, list) {
261255932Salfred		if (qpn == pqp->qpn)
262255932Salfred			return 0; /* qp is already duplicated */
263255932Salfred	}
264255932Salfred
265255932Salfred	/* add the qp as a duplicate on this index */
266255932Salfred	dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
267255932Salfred	if (!dqp)
268255932Salfred		return -ENOMEM;
269255932Salfred	dqp->qpn = qpn;
270255932Salfred	list_add_tail(&dqp->list, &entry->duplicates);
271255932Salfred
272255932Salfred	return 0;
273255932Salfred}
274255932Salfred
275255932Salfred/* Check whether a qpn is a duplicate on steering entry
276255932Salfred * If so, it should not be removed from mgm */
277255932Salfredstatic bool check_duplicate_entry(struct mlx4_dev *dev, u8 port,
278255932Salfred				  enum mlx4_steer_type steer,
279255932Salfred				  unsigned int index, u32 qpn)
280255932Salfred{
281255932Salfred	struct mlx4_steer *s_steer;
282255932Salfred	struct mlx4_steer_index *tmp_entry, *entry = NULL;
283255932Salfred	struct mlx4_promisc_qp *dqp, *tmp_dqp;
284255932Salfred
285255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
286255932Salfred
287255932Salfred	/* if qp is not promisc, it cannot be duplicated */
288255932Salfred	if (!get_promisc_qp(dev, port, steer, qpn))
289255932Salfred		return false;
290255932Salfred
291255932Salfred	/* The qp is promisc qp so it is a duplicate on this index
292255932Salfred	 * Find the index entry, and remove the duplicate */
293255932Salfred	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
294255932Salfred		if (tmp_entry->index == index) {
295255932Salfred			entry = tmp_entry;
296255932Salfred			break;
297255932Salfred		}
298255932Salfred	}
299255932Salfred	if (unlikely(!entry)) {
300255932Salfred		mlx4_warn(dev, "Steering entry for index %x is not registered\n", index);
301255932Salfred		return false;
302255932Salfred	}
303255932Salfred	list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) {
304255932Salfred		if (dqp->qpn == qpn) {
305255932Salfred			list_del(&dqp->list);
306255932Salfred			kfree(dqp);
307255932Salfred		}
308255932Salfred	}
309255932Salfred	return true;
310255932Salfred}
311255932Salfred
312255932Salfred/* I a steering entry contains only promisc QPs, it can be removed. */
313255932Salfredstatic bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
314255932Salfred				      enum mlx4_steer_type steer,
315255932Salfred				      unsigned int index, u32 tqpn)
316255932Salfred{
317255932Salfred	struct mlx4_steer *s_steer;
318255932Salfred	struct mlx4_cmd_mailbox *mailbox;
319255932Salfred	struct mlx4_mgm *mgm;
320255932Salfred	struct mlx4_steer_index *entry = NULL, *tmp_entry;
321255932Salfred	u32 qpn;
322255932Salfred	u32 members_count;
323255932Salfred	bool ret = false;
324255932Salfred	int i;
325255932Salfred
326255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
327255932Salfred
328255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
329255932Salfred	if (IS_ERR(mailbox))
330255932Salfred		return false;
331255932Salfred	mgm = mailbox->buf;
332255932Salfred
333255932Salfred	if (mlx4_READ_ENTRY(dev, index, mailbox))
334255932Salfred		goto out;
335255932Salfred	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
336255932Salfred	for (i = 0;  i < members_count; i++) {
337255932Salfred		qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
338255932Salfred		if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) {
339255932Salfred			/* the qp is not promisc, the entry can't be removed */
340255932Salfred			goto out;
341255932Salfred		}
342255932Salfred	}
343255932Salfred	 /* All the qps currently registered for this entry are promiscuous,
344255932Salfred	  * Checking for duplicates */
345255932Salfred	ret = true;
346255932Salfred	list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
347255932Salfred		if (entry->index == index) {
348255932Salfred			if (list_empty(&entry->duplicates) || members_count == 1) {
349255932Salfred				struct mlx4_promisc_qp *pqp, *tmp_pqp;
350255932Salfred				/*
351255932Salfred				 * If there is only 1 entry in duplicates than
352255932Salfred				 * this is the QP we want to delete, going over
353255932Salfred				 * the list and deleting the entry.
354255932Salfred				 */
355255932Salfred				list_del(&entry->list);
356255932Salfred				list_for_each_entry_safe(pqp, tmp_pqp,
357255932Salfred							 &entry->duplicates,
358255932Salfred							 list) {
359255932Salfred					list_del(&pqp->list);
360255932Salfred					kfree(pqp);
361255932Salfred				}
362255932Salfred				kfree(entry);
363255932Salfred			} else {
364255932Salfred				/* This entry contains duplicates so it shouldn't be removed */
365255932Salfred				ret = false;
366255932Salfred				goto out;
367255932Salfred			}
368255932Salfred		}
369255932Salfred	}
370255932Salfred
371255932Salfredout:
372255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
373255932Salfred	return ret;
374255932Salfred}
375255932Salfred
376255932Salfredstatic int add_promisc_qp(struct mlx4_dev *dev, u8 port,
377255932Salfred			  enum mlx4_steer_type steer, u32 qpn)
378255932Salfred{
379255932Salfred	struct mlx4_steer *s_steer;
380255932Salfred	struct mlx4_cmd_mailbox *mailbox;
381255932Salfred	struct mlx4_mgm *mgm;
382255932Salfred	struct mlx4_steer_index *entry;
383255932Salfred	struct mlx4_promisc_qp *pqp;
384255932Salfred	struct mlx4_promisc_qp *dqp;
385255932Salfred	u32 members_count;
386255932Salfred	u32 prot;
387255932Salfred	int i;
388255932Salfred	bool found;
389255932Salfred	int err;
390255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
391255932Salfred
392255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
393255932Salfred
394255932Salfred	mutex_lock(&priv->mcg_table.mutex);
395255932Salfred
396255932Salfred	if (get_promisc_qp(dev, port, steer, qpn)) {
397255932Salfred		err = 0;  /* Noting to do, already exists */
398255932Salfred		goto out_mutex;
399255932Salfred	}
400255932Salfred
401255932Salfred	pqp = kmalloc(sizeof *pqp, GFP_KERNEL);
402255932Salfred	if (!pqp) {
403255932Salfred		err = -ENOMEM;
404255932Salfred		goto out_mutex;
405255932Salfred	}
406255932Salfred	pqp->qpn = qpn;
407255932Salfred
408255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
409255932Salfred	if (IS_ERR(mailbox)) {
410255932Salfred		err = -ENOMEM;
411255932Salfred		goto out_alloc;
412255932Salfred	}
413255932Salfred	mgm = mailbox->buf;
414255932Salfred
415255932Salfred	/* the promisc qp needs to be added for each one of the steering
416255932Salfred	 * entries, if it already exists, needs to be added as a duplicate
417255932Salfred	 * for this entry */
418255932Salfred	list_for_each_entry(entry, &s_steer->steer_entries[steer], list) {
419255932Salfred		err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
420255932Salfred		if (err)
421255932Salfred			goto out_mailbox;
422255932Salfred
423255932Salfred		members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
424255932Salfred		prot = be32_to_cpu(mgm->members_count) >> 30;
425255932Salfred		found = false;
426255932Salfred		for (i = 0; i < members_count; i++) {
427255932Salfred			if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
428255932Salfred				/* Entry already exists, add to duplicates */
429255932Salfred				dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
430255932Salfred				if (!dqp) {
431255932Salfred					err = -ENOMEM;
432255932Salfred					goto out_mailbox;
433255932Salfred				}
434255932Salfred				dqp->qpn = qpn;
435255932Salfred				list_add_tail(&dqp->list, &entry->duplicates);
436255932Salfred				found = true;
437255932Salfred			}
438255932Salfred		}
439255932Salfred		if (!found) {
440255932Salfred			/* Need to add the qpn to mgm */
441255932Salfred			if (members_count == dev->caps.num_qp_per_mgm) {
442255932Salfred				/* entry is full */
443255932Salfred				err = -ENOMEM;
444255932Salfred				goto out_mailbox;
445255932Salfred			}
446255932Salfred			mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK);
447255932Salfred			mgm->members_count = cpu_to_be32(members_count | (prot << 30));
448255932Salfred			err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
449255932Salfred			if (err)
450255932Salfred				goto out_mailbox;
451255932Salfred		}
452255932Salfred	}
453255932Salfred
454255932Salfred	/* add the new qpn to list of promisc qps */
455255932Salfred	list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
456255932Salfred	/* now need to add all the promisc qps to default entry */
457255932Salfred	memset(mgm, 0, sizeof *mgm);
458255932Salfred	members_count = 0;
459255932Salfred	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) {
460255932Salfred		if (members_count == dev->caps.num_qp_per_mgm) {
461255932Salfred			/* entry is full */
462255932Salfred			err = -ENOMEM;
463255932Salfred			goto out_list;
464255932Salfred		}
465255932Salfred		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
466255932Salfred	}
467255932Salfred	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
468255932Salfred
469255932Salfred	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
470255932Salfred	if (err)
471255932Salfred		goto out_list;
472255932Salfred
473255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
474255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
475255932Salfred	return 0;
476255932Salfred
477255932Salfredout_list:
478255932Salfred	list_del(&pqp->list);
479255932Salfredout_mailbox:
480255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
481255932Salfredout_alloc:
482255932Salfred	kfree(pqp);
483255932Salfredout_mutex:
484255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
485255932Salfred	return err;
486255932Salfred}
487255932Salfred
488255932Salfredstatic int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
489255932Salfred			     enum mlx4_steer_type steer, u32 qpn)
490255932Salfred{
491255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
492255932Salfred	struct mlx4_steer *s_steer;
493255932Salfred	struct mlx4_cmd_mailbox *mailbox;
494255932Salfred	struct mlx4_mgm *mgm;
495255932Salfred	struct mlx4_steer_index *entry;
496255932Salfred	struct mlx4_promisc_qp *pqp;
497255932Salfred	struct mlx4_promisc_qp *dqp;
498255932Salfred	u32 members_count;
499255932Salfred	bool found;
500255932Salfred	bool back_to_list = false;
501255932Salfred	int i, loc = -1;
502255932Salfred	int err;
503255932Salfred
504255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
505255932Salfred	mutex_lock(&priv->mcg_table.mutex);
506255932Salfred
507255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
508255932Salfred	if (unlikely(!pqp)) {
509255932Salfred		mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn);
510255932Salfred		/* nothing to do */
511255932Salfred		err = 0;
512255932Salfred		goto out_mutex;
513255932Salfred	}
514255932Salfred
515255932Salfred	/*remove from list of promisc qps */
516255932Salfred	list_del(&pqp->list);
517255932Salfred
518255932Salfred	/* set the default entry not to include the removed one */
519255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
520255932Salfred	if (IS_ERR(mailbox)) {
521255932Salfred		err = -ENOMEM;
522255932Salfred		back_to_list = true;
523255932Salfred		goto out_list;
524255932Salfred	}
525255932Salfred	mgm = mailbox->buf;
526255932Salfred	memset(mgm, 0, sizeof *mgm);
527255932Salfred	members_count = 0;
528255932Salfred	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
529255932Salfred		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
530255932Salfred	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
531255932Salfred
532255932Salfred	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
533255932Salfred	if (err)
534255932Salfred		goto out_mailbox;
535255932Salfred
536255932Salfred	/* remove the qp from all the steering entries*/
537255932Salfred	list_for_each_entry(entry, &s_steer->steer_entries[steer], list) {
538255932Salfred		found = false;
539255932Salfred		list_for_each_entry(dqp, &entry->duplicates, list) {
540255932Salfred			if (dqp->qpn == qpn) {
541255932Salfred				found = true;
542255932Salfred				break;
543255932Salfred			}
544255932Salfred		}
545255932Salfred		if (found) {
546255932Salfred			/* a duplicate, no need to change the mgm,
547255932Salfred			 * only update the duplicates list */
548255932Salfred			list_del(&dqp->list);
549255932Salfred			kfree(dqp);
550255932Salfred		} else {
551255932Salfred			err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
552255932Salfred				if (err)
553255932Salfred					goto out_mailbox;
554255932Salfred			members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
555255932Salfred			for (i = 0; i < members_count; ++i)
556255932Salfred				if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
557255932Salfred					loc = i;
558255932Salfred					break;
559255932Salfred				}
560255932Salfred
561255932Salfred			if (loc < 0) {
562255932Salfred				mlx4_err(dev, "QP %06x wasn't found in entry %d\n",
563255932Salfred					 qpn, entry->index);
564255932Salfred				err = -EINVAL;
565255932Salfred				goto out_mailbox;
566255932Salfred			}
567255932Salfred
568255932Salfred			/* copy the last QP in this MGM over removed QP */
569255932Salfred			mgm->qp[loc] = mgm->qp[members_count - 1];
570255932Salfred			mgm->qp[members_count - 1] = 0;
571255932Salfred			mgm->members_count = cpu_to_be32(--members_count |
572255932Salfred							 (MLX4_PROT_ETH << 30));
573255932Salfred
574255932Salfred			err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
575255932Salfred				if (err)
576255932Salfred					goto out_mailbox;
577255932Salfred		}
578255932Salfred
579255932Salfred	}
580255932Salfred
581255932Salfredout_mailbox:
582255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
583255932Salfredout_list:
584255932Salfred	if (back_to_list)
585255932Salfred		list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
586255932Salfred	else
587255932Salfred		kfree(pqp);
588255932Salfredout_mutex:
589255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
590255932Salfred	return err;
591255932Salfred}
592255932Salfred
593255932Salfred/*
594219820Sjeff * Caller must hold MCG table semaphore.  gid and mgm parameters must
595219820Sjeff * be properly aligned for command interface.
596219820Sjeff *
597219820Sjeff *  Returns 0 unless a firmware command error occurs.
598219820Sjeff *
599219820Sjeff * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
600219820Sjeff * and *mgm holds MGM entry.
601219820Sjeff *
602219820Sjeff * if GID is found in AMGM, *index = index in AMGM, *prev = index of
603219820Sjeff * previous entry in hash chain and *mgm holds AMGM entry.
604219820Sjeff *
605219820Sjeff * If no AMGM exists for given gid, *index = -1, *prev = index of last
606219820Sjeff * entry in hash chain and *mgm holds end of hash chain.
607219820Sjeff */
608255932Salfredstatic int find_entry(struct mlx4_dev *dev, u8 port,
609255932Salfred		      u8 *gid, enum mlx4_protocol prot,
610255932Salfred		      struct mlx4_cmd_mailbox *mgm_mailbox,
611255932Salfred		      int *prev, int *index)
612219820Sjeff{
613219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
614219820Sjeff	struct mlx4_mgm *mgm = mgm_mailbox->buf;
615219820Sjeff	u8 *mgid;
616219820Sjeff	int err;
617255932Salfred	u16 hash;
618255932Salfred	u8 op_mod = (prot == MLX4_PROT_ETH) ?
619255932Salfred		!!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0;
620219820Sjeff
621219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
622219820Sjeff	if (IS_ERR(mailbox))
623219820Sjeff		return -ENOMEM;
624219820Sjeff	mgid = mailbox->buf;
625219820Sjeff
626219820Sjeff	memcpy(mgid, gid, 16);
627219820Sjeff
628255932Salfred	err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod);
629219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
630219820Sjeff	if (err)
631219820Sjeff		return err;
632219820Sjeff
633219820Sjeff	if (0)
634255932Salfred		mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, hash);
635219820Sjeff
636255932Salfred	*index = hash;
637219820Sjeff	*prev  = -1;
638219820Sjeff
639219820Sjeff	do {
640255932Salfred		err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox);
641219820Sjeff		if (err)
642219820Sjeff			return err;
643219820Sjeff
644255932Salfred		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
645255932Salfred			if (*index != hash) {
646219820Sjeff				mlx4_err(dev, "Found zero MGID in AMGM.\n");
647219820Sjeff				err = -EINVAL;
648219820Sjeff			}
649219820Sjeff			return err;
650219820Sjeff		}
651219820Sjeff
652219820Sjeff		if (!memcmp(mgm->gid, gid, 16) &&
653255932Salfred		    be32_to_cpu(mgm->members_count) >> 30 == prot)
654219820Sjeff			return err;
655219820Sjeff
656219820Sjeff		*prev = *index;
657219820Sjeff		*index = be32_to_cpu(mgm->next_gid_index) >> 6;
658219820Sjeff	} while (*index);
659219820Sjeff
660219820Sjeff	*index = -1;
661219820Sjeff	return err;
662219820Sjeff}
663219820Sjeff
664255932Salfredstatic void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,
665255932Salfred				  struct mlx4_net_trans_rule_hw_ctrl *hw)
666219820Sjeff{
667255932Salfred	static const u8 __promisc_mode[] = {
668255932Salfred		[MLX4_FS_REGULAR]   = 0x0,
669255932Salfred		[MLX4_FS_ALL_DEFAULT] = 0x1,
670255932Salfred		[MLX4_FS_MC_DEFAULT] = 0x3,
671255932Salfred		[MLX4_FS_UC_SNIFFER] = 0x4,
672255932Salfred		[MLX4_FS_MC_SNIFFER] = 0x5,
673255932Salfred	};
674255932Salfred
675255932Salfred	u32 dw = 0;
676255932Salfred
677255932Salfred	dw = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0;
678255932Salfred	dw |= ctrl->exclusive ? (1 << 2) : 0;
679255932Salfred	dw |= ctrl->allow_loopback ? (1 << 3) : 0;
680255932Salfred	dw |= __promisc_mode[ctrl->promisc_mode] << 8;
681255932Salfred	dw |= ctrl->priority << 16;
682255932Salfred
683255932Salfred	hw->ctrl = cpu_to_be32(dw);
684255932Salfred	hw->port = ctrl->port;
685255932Salfred	hw->qpn = cpu_to_be32(ctrl->qpn);
686255932Salfred}
687255932Salfred
688255932Salfredconst u16 __sw_id_hw[] = {
689255932Salfred	[MLX4_NET_TRANS_RULE_ID_ETH]     = 0xE001,
690255932Salfred	[MLX4_NET_TRANS_RULE_ID_IB]      = 0xE005,
691255932Salfred	[MLX4_NET_TRANS_RULE_ID_IPV6]    = 0xE003,
692255932Salfred	[MLX4_NET_TRANS_RULE_ID_IPV4]    = 0xE002,
693255932Salfred	[MLX4_NET_TRANS_RULE_ID_TCP]     = 0xE004,
694255932Salfred	[MLX4_NET_TRANS_RULE_ID_UDP]     = 0xE006
695255932Salfred};
696255932Salfred
697255932Salfredstatic int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec,
698255932Salfred			    struct _rule_hw *rule_hw)
699255932Salfred{
700255932Salfred	static const size_t __rule_hw_sz[] = {
701255932Salfred		[MLX4_NET_TRANS_RULE_ID_ETH] =
702255932Salfred			sizeof(struct mlx4_net_trans_rule_hw_eth),
703255932Salfred		[MLX4_NET_TRANS_RULE_ID_IB] =
704255932Salfred			sizeof(struct mlx4_net_trans_rule_hw_ib),
705255932Salfred		[MLX4_NET_TRANS_RULE_ID_IPV6] = 0,
706255932Salfred		[MLX4_NET_TRANS_RULE_ID_IPV4] =
707255932Salfred			sizeof(struct mlx4_net_trans_rule_hw_ipv4),
708255932Salfred		[MLX4_NET_TRANS_RULE_ID_TCP] =
709255932Salfred			sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),
710255932Salfred		[MLX4_NET_TRANS_RULE_ID_UDP] =
711255932Salfred			sizeof(struct mlx4_net_trans_rule_hw_tcp_udp)
712255932Salfred	};
713255932Salfred	if (spec->id >= MLX4_NET_TRANS_RULE_NUM) {
714255932Salfred		mlx4_err(dev, "Invalid network rule id. id = %d\n", spec->id);
715255932Salfred		return -EINVAL;
716255932Salfred	}
717255932Salfred	memset(rule_hw, 0, __rule_hw_sz[spec->id]);
718255932Salfred	rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]);
719255932Salfred	rule_hw->size = __rule_hw_sz[spec->id] >> 2;
720255932Salfred
721255932Salfred	switch (spec->id) {
722255932Salfred	case MLX4_NET_TRANS_RULE_ID_ETH:
723255932Salfred		memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN);
724255932Salfred		memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk,
725255932Salfred		       ETH_ALEN);
726255932Salfred		memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN);
727255932Salfred		memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk,
728255932Salfred		       ETH_ALEN);
729255932Salfred		if (spec->eth.ether_type_enable) {
730255932Salfred			rule_hw->eth.ether_type_enable = 1;
731255932Salfred			rule_hw->eth.ether_type = spec->eth.ether_type;
732255932Salfred		}
733255932Salfred		rule_hw->eth.vlan_id = spec->eth.vlan_id;
734255932Salfred		rule_hw->eth.vlan_id_msk = spec->eth.vlan_id_msk;
735255932Salfred		break;
736255932Salfred
737255932Salfred	case MLX4_NET_TRANS_RULE_ID_IB:
738255932Salfred		rule_hw->ib.r_u_qpn = spec->ib.r_u_qpn;
739255932Salfred		rule_hw->ib.qpn_mask = spec->ib.qpn_msk;
740255932Salfred		memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16);
741255932Salfred		memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16);
742255932Salfred		break;
743255932Salfred
744255932Salfred	case MLX4_NET_TRANS_RULE_ID_IPV6:
745255932Salfred		return -EOPNOTSUPP;
746255932Salfred
747255932Salfred	case MLX4_NET_TRANS_RULE_ID_IPV4:
748255932Salfred		rule_hw->ipv4.src_ip = spec->ipv4.src_ip;
749255932Salfred		rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk;
750255932Salfred		rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip;
751255932Salfred		rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk;
752255932Salfred		break;
753255932Salfred
754255932Salfred	case MLX4_NET_TRANS_RULE_ID_TCP:
755255932Salfred	case MLX4_NET_TRANS_RULE_ID_UDP:
756255932Salfred		rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port;
757255932Salfred		rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk;
758255932Salfred		rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port;
759255932Salfred		rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk;
760255932Salfred		break;
761255932Salfred
762255932Salfred	default:
763255932Salfred		return -EINVAL;
764255932Salfred	}
765255932Salfred
766255932Salfred	return __rule_hw_sz[spec->id];
767255932Salfred}
768255932Salfred
769255932Salfredstatic void mlx4_err_rule(struct mlx4_dev *dev, char *str,
770255932Salfred			  struct mlx4_net_trans_rule *rule)
771255932Salfred{
772255932Salfred#define BUF_SIZE 256
773255932Salfred	struct mlx4_spec_list *cur;
774255932Salfred	char buf[BUF_SIZE];
775255932Salfred	int len = 0;
776255932Salfred
777255932Salfred	mlx4_err(dev, "%s", str);
778255932Salfred	len += snprintf(buf + len, BUF_SIZE - len,
779255932Salfred			"port = %d prio = 0x%x qp = 0x%x ",
780255932Salfred			rule->port, rule->priority, rule->qpn);
781255932Salfred
782255932Salfred	list_for_each_entry(cur, &rule->list, list) {
783255932Salfred		switch (cur->id) {
784255932Salfred		case MLX4_NET_TRANS_RULE_ID_ETH:
785255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
786255932Salfred					"dmac = %pM ", &cur->eth.dst_mac);
787255932Salfred			if (cur->eth.ether_type)
788255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
789255932Salfred						"ethertype = 0x%x ",
790255932Salfred						be16_to_cpu(cur->eth.ether_type));
791255932Salfred			if (cur->eth.vlan_id)
792255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
793255932Salfred						"vlan-id = %d ",
794255932Salfred						be16_to_cpu(cur->eth.vlan_id));
795255932Salfred			break;
796255932Salfred
797255932Salfred		case MLX4_NET_TRANS_RULE_ID_IPV4:
798255932Salfred			if (cur->ipv4.src_ip)
799255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
800255932Salfred						"src-ip = %pI4 ",
801255932Salfred						&cur->ipv4.src_ip);
802255932Salfred			if (cur->ipv4.dst_ip)
803255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
804255932Salfred						"dst-ip = %pI4 ",
805255932Salfred						&cur->ipv4.dst_ip);
806255932Salfred			break;
807255932Salfred
808255932Salfred		case MLX4_NET_TRANS_RULE_ID_TCP:
809255932Salfred		case MLX4_NET_TRANS_RULE_ID_UDP:
810255932Salfred			if (cur->tcp_udp.src_port)
811255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
812255932Salfred						"src-port = %d ",
813255932Salfred						be16_to_cpu(cur->tcp_udp.src_port));
814255932Salfred			if (cur->tcp_udp.dst_port)
815255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
816255932Salfred						"dst-port = %d ",
817255932Salfred						be16_to_cpu(cur->tcp_udp.dst_port));
818255932Salfred			break;
819255932Salfred
820255932Salfred		case MLX4_NET_TRANS_RULE_ID_IB:
821255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
822255932Salfred					"dst-gid = %pI6\n", cur->ib.dst_gid);
823255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
824255932Salfred					"dst-gid-mask = %pI6\n",
825255932Salfred					cur->ib.dst_gid_msk);
826255932Salfred			break;
827255932Salfred
828255932Salfred		case MLX4_NET_TRANS_RULE_ID_IPV6:
829255932Salfred			break;
830255932Salfred
831255932Salfred		default:
832255932Salfred			break;
833255932Salfred		}
834255932Salfred	}
835255932Salfred	len += snprintf(buf + len, BUF_SIZE - len, "\n");
836255932Salfred	mlx4_err(dev, "%s", buf);
837255932Salfred
838255932Salfred	if (len >= BUF_SIZE)
839255932Salfred		mlx4_err(dev, "Network rule error message was truncated, print buffer is too small.\n");
840255932Salfred}
841255932Salfred
842255932Salfredint mlx4_flow_attach(struct mlx4_dev *dev,
843255932Salfred		     struct mlx4_net_trans_rule *rule, u64 *reg_id)
844255932Salfred{
845255932Salfred	struct mlx4_cmd_mailbox *mailbox;
846255932Salfred	struct mlx4_spec_list *cur;
847255932Salfred	u32 size = 0;
848255932Salfred	int ret;
849255932Salfred
850255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
851255932Salfred	if (IS_ERR(mailbox))
852255932Salfred		return PTR_ERR(mailbox);
853255932Salfred
854255932Salfred	memset(mailbox->buf, 0, sizeof(struct mlx4_net_trans_rule_hw_ctrl));
855255932Salfred	trans_rule_ctrl_to_hw(rule, mailbox->buf);
856255932Salfred
857255932Salfred	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
858255932Salfred
859255932Salfred	list_for_each_entry(cur, &rule->list, list) {
860255932Salfred		ret = parse_trans_rule(dev, cur, mailbox->buf + size);
861255932Salfred		if (ret < 0) {
862255932Salfred			mlx4_free_cmd_mailbox(dev, mailbox);
863255932Salfred			return -EINVAL;
864255932Salfred		}
865255932Salfred		size += ret;
866255932Salfred	}
867255932Salfred
868255932Salfred	ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);
869255932Salfred	if (ret == -ENOMEM)
870255932Salfred		mlx4_err_rule(dev,
871255932Salfred			      "mcg table is full. Fail to register network rule.\n",
872255932Salfred			      rule);
873255932Salfred	else if (ret)
874255932Salfred		mlx4_err_rule(dev, "Fail to register network rule.\n", rule);
875255932Salfred
876255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
877255932Salfred
878255932Salfred	return ret;
879255932Salfred}
880255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_attach);
881255932Salfred
882255932Salfredint mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id)
883255932Salfred{
884255932Salfred	int err;
885255932Salfred
886255932Salfred	err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id);
887255932Salfred	if (err)
888255932Salfred		mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n",
889255932Salfred			 reg_id);
890255932Salfred	return err;
891255932Salfred}
892255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_detach);
893255932Salfred
894255932Salfredint mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn)
895255932Salfred{
896255932Salfred	int err;
897255932Salfred	u64 in_param;
898255932Salfred
899255932Salfred	in_param = ((u64) min_range_qpn) << 32;
900255932Salfred	in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF;
901255932Salfred
902255932Salfred	err = mlx4_cmd(dev, in_param, 0, 0,
903255932Salfred			MLX4_FLOW_STEERING_IB_UC_QP_RANGE,
904255932Salfred			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
905255932Salfred
906255932Salfred	return err;
907255932Salfred}
908255932SalfredEXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE);
909255932Salfred
910255932Salfredint mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
911255932Salfred			  int block_mcast_loopback, enum mlx4_protocol prot,
912255932Salfred			  enum mlx4_steer_type steer)
913255932Salfred{
914219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
915219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
916219820Sjeff	struct mlx4_mgm *mgm;
917219820Sjeff	u32 members_count;
918219820Sjeff	int index, prev;
919219820Sjeff	int link = 0;
920219820Sjeff	int i;
921219820Sjeff	int err;
922255932Salfred	u8 port = gid[5];
923255932Salfred	u8 new_entry = 0;
924219820Sjeff
925219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
926219820Sjeff	if (IS_ERR(mailbox))
927219820Sjeff		return PTR_ERR(mailbox);
928219820Sjeff	mgm = mailbox->buf;
929219820Sjeff
930219820Sjeff	mutex_lock(&priv->mcg_table.mutex);
931255932Salfred	err = find_entry(dev, port, gid, prot,
932255932Salfred			 mailbox, &prev, &index);
933219820Sjeff	if (err)
934219820Sjeff		goto out;
935219820Sjeff
936219820Sjeff	if (index != -1) {
937255932Salfred		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
938255932Salfred			new_entry = 1;
939219820Sjeff			memcpy(mgm->gid, gid, 16);
940255932Salfred		}
941219820Sjeff	} else {
942219820Sjeff		link = 1;
943219820Sjeff
944219820Sjeff		index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
945219820Sjeff		if (index == -1) {
946219820Sjeff			mlx4_err(dev, "No AMGM entries left\n");
947219820Sjeff			err = -ENOMEM;
948219820Sjeff			goto out;
949219820Sjeff		}
950219820Sjeff		index += dev->caps.num_mgms;
951219820Sjeff
952255932Salfred		new_entry = 1;
953219820Sjeff		memset(mgm, 0, sizeof *mgm);
954219820Sjeff		memcpy(mgm->gid, gid, 16);
955219820Sjeff	}
956219820Sjeff
957219820Sjeff	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
958255932Salfred	if (members_count == dev->caps.num_qp_per_mgm) {
959219820Sjeff		mlx4_err(dev, "MGM at index %x is full.\n", index);
960219820Sjeff		err = -ENOMEM;
961219820Sjeff		goto out;
962219820Sjeff	}
963219820Sjeff
964219820Sjeff	for (i = 0; i < members_count; ++i)
965219820Sjeff		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
966219820Sjeff			mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
967219820Sjeff			err = 0;
968219820Sjeff			goto out;
969219820Sjeff		}
970219820Sjeff
971219820Sjeff	mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
972219820Sjeff					       (!!mlx4_blck_lb << MGM_BLCK_LB_BIT));
973219820Sjeff
974255932Salfred	mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30);
975219820Sjeff
976255932Salfred	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
977219820Sjeff	if (err)
978219820Sjeff		goto out;
979219820Sjeff
980219820Sjeff	if (!link)
981219820Sjeff		goto out;
982219820Sjeff
983255932Salfred	err = mlx4_READ_ENTRY(dev, prev, mailbox);
984219820Sjeff	if (err)
985219820Sjeff		goto out;
986219820Sjeff
987219820Sjeff	mgm->next_gid_index = cpu_to_be32(index << 6);
988219820Sjeff
989255932Salfred	err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
990219820Sjeff	if (err)
991219820Sjeff		goto out;
992219820Sjeff
993255932Salfred	if (prot == MLX4_PROT_ETH) {
994255932Salfred		/* manage the steering entry for promisc mode */
995255932Salfred		if (new_entry)
996255932Salfred			new_steering_entry(dev, port, steer, index, qp->qpn);
997255932Salfred		else
998255932Salfred			existing_steering_entry(dev, port, steer,
999255932Salfred						index, qp->qpn);
1000255932Salfred	}
1001255932Salfred
1002219820Sjeffout:
1003219820Sjeff	if (err && link && index != -1) {
1004219820Sjeff		if (index < dev->caps.num_mgms)
1005219820Sjeff			mlx4_warn(dev, "Got AMGM index %d < %d",
1006219820Sjeff				  index, dev->caps.num_mgms);
1007219820Sjeff		else
1008219820Sjeff			mlx4_bitmap_free(&priv->mcg_table.bitmap,
1009219820Sjeff					 index - dev->caps.num_mgms);
1010219820Sjeff	}
1011219820Sjeff	mutex_unlock(&priv->mcg_table.mutex);
1012219820Sjeff
1013219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1014219820Sjeff	return err;
1015219820Sjeff}
1016219820Sjeff
1017255932Salfredint mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1018255932Salfred			  enum mlx4_protocol prot, enum mlx4_steer_type steer)
1019219820Sjeff{
1020219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1021219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1022219820Sjeff	struct mlx4_mgm *mgm;
1023219820Sjeff	u32 members_count;
1024219820Sjeff	int prev, index;
1025255932Salfred	int i, loc = -1;
1026219820Sjeff	int err;
1027255932Salfred	u8 port = gid[5];
1028255932Salfred	bool removed_entry = false;
1029219820Sjeff
1030219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1031219820Sjeff	if (IS_ERR(mailbox))
1032219820Sjeff		return PTR_ERR(mailbox);
1033219820Sjeff	mgm = mailbox->buf;
1034219820Sjeff
1035219820Sjeff	mutex_lock(&priv->mcg_table.mutex);
1036219820Sjeff
1037255932Salfred	err = find_entry(dev, port, gid, prot,
1038255932Salfred			 mailbox, &prev, &index);
1039219820Sjeff	if (err)
1040219820Sjeff		goto out;
1041219820Sjeff
1042219820Sjeff	if (index == -1) {
1043219820Sjeff		mlx4_err(dev, "MGID %pI6 not found\n", gid);
1044219820Sjeff		err = -EINVAL;
1045219820Sjeff		goto out;
1046219820Sjeff	}
1047219820Sjeff
1048255932Salfred	/* if this pq is also a promisc qp, it shouldn't be removed */
1049255932Salfred	if (prot == MLX4_PROT_ETH &&
1050255932Salfred	    check_duplicate_entry(dev, port, steer, index, qp->qpn))
1051255932Salfred		goto out;
1052255932Salfred
1053219820Sjeff	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
1054255932Salfred	for (i = 0; i < members_count; ++i)
1055255932Salfred		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
1056219820Sjeff			loc = i;
1057255932Salfred			break;
1058255932Salfred		}
1059219820Sjeff
1060219820Sjeff	if (loc == -1) {
1061219820Sjeff		mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
1062219820Sjeff		err = -EINVAL;
1063219820Sjeff		goto out;
1064219820Sjeff	}
1065219820Sjeff
1066255932Salfred	/* copy the last QP in this MGM over removed QP */
1067255932Salfred	mgm->qp[loc] = mgm->qp[members_count - 1];
1068255932Salfred	mgm->qp[members_count - 1] = 0;
1069255932Salfred	mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30);
1070219820Sjeff
1071255932Salfred	if (prot == MLX4_PROT_ETH)
1072255932Salfred		removed_entry = can_remove_steering_entry(dev, port, steer,
1073255932Salfred								index, qp->qpn);
1074255932Salfred	if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) {
1075255932Salfred		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1076219820Sjeff		goto out;
1077219820Sjeff	}
1078219820Sjeff
1079255932Salfred	/* We are going to delete the entry, members count should be 0 */
1080255932Salfred	mgm->members_count = cpu_to_be32((u32) prot << 30);
1081255932Salfred
1082219820Sjeff	if (prev == -1) {
1083219820Sjeff		/* Remove entry from MGM */
1084219820Sjeff		int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
1085219820Sjeff		if (amgm_index) {
1086255932Salfred			err = mlx4_READ_ENTRY(dev, amgm_index, mailbox);
1087219820Sjeff			if (err)
1088219820Sjeff				goto out;
1089219820Sjeff		} else
1090219820Sjeff			memset(mgm->gid, 0, 16);
1091219820Sjeff
1092255932Salfred		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1093219820Sjeff		if (err)
1094219820Sjeff			goto out;
1095219820Sjeff
1096219820Sjeff		if (amgm_index) {
1097219820Sjeff			if (amgm_index < dev->caps.num_mgms)
1098219820Sjeff				mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d",
1099219820Sjeff					  index, amgm_index, dev->caps.num_mgms);
1100219820Sjeff			else
1101219820Sjeff				mlx4_bitmap_free(&priv->mcg_table.bitmap,
1102219820Sjeff						 amgm_index - dev->caps.num_mgms);
1103219820Sjeff		}
1104219820Sjeff	} else {
1105219820Sjeff		/* Remove entry from AMGM */
1106219820Sjeff		int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
1107255932Salfred		err = mlx4_READ_ENTRY(dev, prev, mailbox);
1108219820Sjeff		if (err)
1109219820Sjeff			goto out;
1110219820Sjeff
1111219820Sjeff		mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
1112219820Sjeff
1113255932Salfred		err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
1114219820Sjeff		if (err)
1115219820Sjeff			goto out;
1116219820Sjeff
1117219820Sjeff		if (index < dev->caps.num_mgms)
1118219820Sjeff			mlx4_warn(dev, "entry %d had next AMGM index %d < %d",
1119219820Sjeff				  prev, index, dev->caps.num_mgms);
1120219820Sjeff		else
1121219820Sjeff			mlx4_bitmap_free(&priv->mcg_table.bitmap,
1122219820Sjeff					 index - dev->caps.num_mgms);
1123219820Sjeff	}
1124219820Sjeff
1125219820Sjeffout:
1126219820Sjeff	mutex_unlock(&priv->mcg_table.mutex);
1127219820Sjeff
1128219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1129219820Sjeff	return err;
1130219820Sjeff}
1131255932Salfred
1132255932Salfredstatic int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,
1133255932Salfred			  u8 gid[16], u8 attach, u8 block_loopback,
1134255932Salfred			  enum mlx4_protocol prot)
1135255932Salfred{
1136255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1137255932Salfred	int err = 0;
1138255932Salfred	int qpn;
1139255932Salfred
1140255932Salfred	if (!mlx4_is_mfunc(dev))
1141255932Salfred		return -EBADF;
1142255932Salfred
1143255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1144255932Salfred	if (IS_ERR(mailbox))
1145255932Salfred		return PTR_ERR(mailbox);
1146255932Salfred
1147255932Salfred	memcpy(mailbox->buf, gid, 16);
1148255932Salfred	qpn = qp->qpn;
1149255932Salfred	qpn |= (prot << 28);
1150255932Salfred	if (attach && block_loopback)
1151255932Salfred		qpn |= (1 << 31);
1152255932Salfred
1153255932Salfred	err = mlx4_cmd(dev, mailbox->dma, qpn, attach,
1154255932Salfred		       MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A,
1155255932Salfred		       MLX4_CMD_WRAPPED);
1156255932Salfred
1157255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1158255932Salfred	return err;
1159255932Salfred}
1160255932Salfred
1161255932Salfredint mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1162255932Salfred			  u8 port, int block_mcast_loopback,
1163255932Salfred			  enum mlx4_protocol prot, u64 *reg_id)
1164255932Salfred{
1165255932Salfred
1166255932Salfred	switch (dev->caps.steering_mode) {
1167255932Salfred	case MLX4_STEERING_MODE_A0:
1168255932Salfred		if (prot == MLX4_PROT_ETH)
1169255932Salfred			return 0;
1170255932Salfred
1171255932Salfred	case MLX4_STEERING_MODE_B0:
1172255932Salfred		if (prot == MLX4_PROT_ETH)
1173255932Salfred			gid[7] |= (MLX4_MC_STEER << 1);
1174255932Salfred
1175255932Salfred		if (mlx4_is_mfunc(dev))
1176255932Salfred			return mlx4_QP_ATTACH(dev, qp, gid, 1,
1177255932Salfred					      block_mcast_loopback, prot);
1178255932Salfred		return mlx4_qp_attach_common(dev, qp, gid,
1179255932Salfred					     block_mcast_loopback, prot,
1180255932Salfred					     MLX4_MC_STEER);
1181255932Salfred
1182255932Salfred	case MLX4_STEERING_MODE_DEVICE_MANAGED: {
1183255932Salfred		struct mlx4_spec_list spec = { {NULL} };
1184255932Salfred		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
1185255932Salfred
1186255932Salfred		struct mlx4_net_trans_rule rule = {
1187255932Salfred			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
1188255932Salfred			.exclusive = 0,
1189255932Salfred			.promisc_mode = MLX4_FS_REGULAR,
1190255932Salfred			.priority = MLX4_DOMAIN_NIC,
1191255932Salfred		};
1192255932Salfred
1193255932Salfred		rule.allow_loopback = !block_mcast_loopback;
1194255932Salfred		rule.port = port;
1195255932Salfred		rule.qpn = qp->qpn;
1196255932Salfred		INIT_LIST_HEAD(&rule.list);
1197255932Salfred
1198255932Salfred		switch (prot) {
1199255932Salfred		case MLX4_PROT_ETH:
1200255932Salfred			spec.id = MLX4_NET_TRANS_RULE_ID_ETH;
1201255932Salfred			memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN);
1202255932Salfred			memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
1203255932Salfred			break;
1204255932Salfred
1205255932Salfred		case MLX4_PROT_IB_IPV6:
1206255932Salfred			spec.id = MLX4_NET_TRANS_RULE_ID_IB;
1207255932Salfred			memcpy(spec.ib.dst_gid, gid, 16);
1208255932Salfred			memset(&spec.ib.dst_gid_msk, 0xff, 16);
1209255932Salfred			break;
1210255932Salfred		default:
1211255932Salfred			return -EINVAL;
1212255932Salfred		}
1213255932Salfred		list_add_tail(&spec.list, &rule.list);
1214255932Salfred
1215255932Salfred		return mlx4_flow_attach(dev, &rule, reg_id);
1216255932Salfred	}
1217255932Salfred
1218255932Salfred	default:
1219255932Salfred		return -EINVAL;
1220255932Salfred	}
1221255932Salfred}
1222255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_attach);
1223255932Salfred
1224255932Salfredint mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1225255932Salfred			  enum mlx4_protocol prot, u64 reg_id)
1226255932Salfred{
1227255932Salfred	switch (dev->caps.steering_mode) {
1228255932Salfred	case MLX4_STEERING_MODE_A0:
1229255932Salfred		if (prot == MLX4_PROT_ETH)
1230255932Salfred			return 0;
1231255932Salfred
1232255932Salfred	case MLX4_STEERING_MODE_B0:
1233255932Salfred		if (prot == MLX4_PROT_ETH)
1234255932Salfred			gid[7] |= (MLX4_MC_STEER << 1);
1235255932Salfred
1236255932Salfred		if (mlx4_is_mfunc(dev))
1237255932Salfred			return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
1238255932Salfred
1239255932Salfred		return mlx4_qp_detach_common(dev, qp, gid, prot,
1240255932Salfred					     MLX4_MC_STEER);
1241255932Salfred
1242255932Salfred	case MLX4_STEERING_MODE_DEVICE_MANAGED:
1243255932Salfred		return mlx4_flow_detach(dev, reg_id);
1244255932Salfred
1245255932Salfred	default:
1246255932Salfred		return -EINVAL;
1247255932Salfred	}
1248255932Salfred}
1249219820SjeffEXPORT_SYMBOL_GPL(mlx4_multicast_detach);
1250219820Sjeff
1251255932Salfredint mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
1252255932Salfred				u32 qpn, enum mlx4_net_trans_promisc_mode mode)
1253255932Salfred{
1254255932Salfred	struct mlx4_net_trans_rule rule;
1255255932Salfred	u64 *regid_p;
1256255932Salfred
1257255932Salfred	switch (mode) {
1258255932Salfred	case MLX4_FS_ALL_DEFAULT:
1259255932Salfred		regid_p = &dev->regid_promisc_array[port];
1260255932Salfred		break;
1261255932Salfred	case MLX4_FS_MC_DEFAULT:
1262255932Salfred		regid_p = &dev->regid_allmulti_array[port];
1263255932Salfred		break;
1264255932Salfred	default:
1265255932Salfred		return -1;
1266255932Salfred	}
1267255932Salfred
1268255932Salfred	if (*regid_p != 0)
1269255932Salfred		return -1;
1270255932Salfred
1271255932Salfred	rule.promisc_mode = mode;
1272255932Salfred	rule.port = port;
1273255932Salfred	rule.qpn = qpn;
1274255932Salfred	INIT_LIST_HEAD(&rule.list);
1275255932Salfred	mlx4_err(dev, "going promisc on %x\n", port);
1276255932Salfred
1277255932Salfred	return  mlx4_flow_attach(dev, &rule, regid_p);
1278255932Salfred}
1279255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add);
1280255932Salfred
1281255932Salfredint mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port,
1282255932Salfred				   enum mlx4_net_trans_promisc_mode mode)
1283255932Salfred{
1284255932Salfred	int ret;
1285255932Salfred	u64 *regid_p;
1286255932Salfred
1287255932Salfred	switch (mode) {
1288255932Salfred	case MLX4_FS_ALL_DEFAULT:
1289255932Salfred		regid_p = &dev->regid_promisc_array[port];
1290255932Salfred		break;
1291255932Salfred	case MLX4_FS_MC_DEFAULT:
1292255932Salfred		regid_p = &dev->regid_allmulti_array[port];
1293255932Salfred		break;
1294255932Salfred	default:
1295255932Salfred		return -1;
1296255932Salfred	}
1297255932Salfred
1298255932Salfred	if (*regid_p == 0)
1299255932Salfred		return -1;
1300255932Salfred
1301255932Salfred	ret =  mlx4_flow_detach(dev, *regid_p);
1302255932Salfred	if (ret == 0)
1303255932Salfred		*regid_p = 0;
1304255932Salfred
1305255932Salfred	return ret;
1306255932Salfred}
1307255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove);
1308255932Salfred
1309255932Salfredint mlx4_unicast_attach(struct mlx4_dev *dev,
1310255932Salfred			struct mlx4_qp *qp, u8 gid[16],
1311255932Salfred			int block_mcast_loopback, enum mlx4_protocol prot)
1312255932Salfred{
1313255932Salfred	if (prot == MLX4_PROT_ETH)
1314255932Salfred		gid[7] |= (MLX4_UC_STEER << 1);
1315255932Salfred
1316255932Salfred	if (mlx4_is_mfunc(dev))
1317255932Salfred		return mlx4_QP_ATTACH(dev, qp, gid, 1,
1318255932Salfred					block_mcast_loopback, prot);
1319255932Salfred
1320255932Salfred	return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback,
1321255932Salfred					prot, MLX4_UC_STEER);
1322255932Salfred}
1323255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_attach);
1324255932Salfred
1325255932Salfredint mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
1326255932Salfred			       u8 gid[16], enum mlx4_protocol prot)
1327255932Salfred{
1328255932Salfred	if (prot == MLX4_PROT_ETH)
1329255932Salfred		gid[7] |= (MLX4_UC_STEER << 1);
1330255932Salfred
1331255932Salfred	if (mlx4_is_mfunc(dev))
1332255932Salfred		return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
1333255932Salfred
1334255932Salfred	return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER);
1335255932Salfred}
1336255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_detach);
1337255932Salfred
1338255932Salfredint mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave,
1339255932Salfred			 struct mlx4_vhcr *vhcr,
1340255932Salfred			 struct mlx4_cmd_mailbox *inbox,
1341255932Salfred			 struct mlx4_cmd_mailbox *outbox,
1342255932Salfred			 struct mlx4_cmd_info *cmd)
1343255932Salfred{
1344255932Salfred	u32 qpn = (u32) vhcr->in_param & 0xffffffff;
1345255932Salfred	u8 port = vhcr->in_param >> 62;
1346255932Salfred	enum mlx4_steer_type steer = vhcr->in_modifier;
1347255932Salfred
1348255932Salfred	/* Promiscuous unicast is not allowed in mfunc */
1349255932Salfred	if (mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)
1350255932Salfred		return 0;
1351255932Salfred
1352255932Salfred	if (vhcr->op_modifier)
1353255932Salfred		return add_promisc_qp(dev, port, steer, qpn);
1354255932Salfred	else
1355255932Salfred		return remove_promisc_qp(dev, port, steer, qpn);
1356255932Salfred}
1357255932Salfred
1358255932Salfredstatic int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn,
1359255932Salfred			enum mlx4_steer_type steer, u8 add, u8 port)
1360255932Salfred{
1361255932Salfred	return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add,
1362255932Salfred			MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A,
1363255932Salfred			MLX4_CMD_WRAPPED);
1364255932Salfred}
1365255932Salfred
1366255932Salfredint mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
1367255932Salfred{
1368255932Salfred	if (mlx4_is_mfunc(dev))
1369255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port);
1370255932Salfred
1371255932Salfred	return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
1372255932Salfred}
1373255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add);
1374255932Salfred
1375255932Salfredint mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
1376255932Salfred{
1377255932Salfred	if (mlx4_is_mfunc(dev))
1378255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port);
1379255932Salfred
1380255932Salfred	return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
1381255932Salfred}
1382255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove);
1383255932Salfred
1384255932Salfredint mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
1385255932Salfred{
1386255932Salfred	if (mlx4_is_mfunc(dev))
1387255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port);
1388255932Salfred
1389255932Salfred	return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
1390255932Salfred}
1391255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add);
1392255932Salfred
1393255932Salfredint mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
1394255932Salfred{
1395255932Salfred	if (mlx4_is_mfunc(dev))
1396255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port);
1397255932Salfred
1398255932Salfred	return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
1399255932Salfred}
1400255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove);
1401255932Salfred
1402219820Sjeffint mlx4_init_mcg_table(struct mlx4_dev *dev)
1403219820Sjeff{
1404219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1405219820Sjeff	int err;
1406219820Sjeff
1407255932Salfred	/* No need for mcg_table when fw managed the mcg table*/
1408255932Salfred	if (dev->caps.steering_mode ==
1409255932Salfred	    MLX4_STEERING_MODE_DEVICE_MANAGED)
1410255932Salfred		return 0;
1411219820Sjeff	err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
1412219820Sjeff			       dev->caps.num_amgms - 1, 0, 0);
1413219820Sjeff	if (err)
1414219820Sjeff		return err;
1415219820Sjeff
1416219820Sjeff	mutex_init(&priv->mcg_table.mutex);
1417219820Sjeff
1418219820Sjeff	return 0;
1419219820Sjeff}
1420219820Sjeff
1421219820Sjeffvoid mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
1422219820Sjeff{
1423255932Salfred	if (dev->caps.steering_mode !=
1424255932Salfred	    MLX4_STEERING_MODE_DEVICE_MANAGED)
1425255932Salfred		mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
1426219820Sjeff}
1427