1219820Sjeff/*
2219820Sjeff * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
3272407Shselasky * Copyright (c) 2007, 2008, 2014 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>
35272407Shselasky#include <linux/etherdevice.h>
36219820Sjeff
37219820Sjeff#include <linux/mlx4/cmd.h>
38272407Shselasky#include <linux/module.h>
39279731Shselasky#include <linux/printk.h>
40219820Sjeff
41219820Sjeff#include "mlx4.h"
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{
127272407Shselasky	struct mlx4_steer *s_steer;
128255932Salfred	struct mlx4_promisc_qp *pqp;
129255932Salfred
130272407Shselasky	if (port < 1 || port > dev->caps.num_ports)
131272407Shselasky		return NULL;
132272407Shselasky
133272407Shselasky	s_steer = &mlx4_priv(dev)->steer[port - 1];
134272407Shselasky
135255932Salfred	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
136255932Salfred		if (pqp->qpn == qpn)
137255932Salfred			return pqp;
138255932Salfred	}
139255932Salfred	/* not found */
140255932Salfred	return NULL;
141255932Salfred}
142255932Salfred
143219820Sjeff/*
144255932Salfred * Add new entry to steering data structure.
145255932Salfred * All promisc QPs should be added as well
146255932Salfred */
147255932Salfredstatic int new_steering_entry(struct mlx4_dev *dev, u8 port,
148255932Salfred			      enum mlx4_steer_type steer,
149255932Salfred			      unsigned int index, u32 qpn)
150255932Salfred{
151255932Salfred	struct mlx4_steer *s_steer;
152255932Salfred	struct mlx4_cmd_mailbox *mailbox;
153255932Salfred	struct mlx4_mgm *mgm;
154255932Salfred	u32 members_count;
155255932Salfred	struct mlx4_steer_index *new_entry;
156255932Salfred	struct mlx4_promisc_qp *pqp;
157255932Salfred	struct mlx4_promisc_qp *dqp = NULL;
158255932Salfred	u32 prot;
159255932Salfred	int err;
160255932Salfred
161272407Shselasky	if (port < 1 || port > dev->caps.num_ports)
162272407Shselasky		return -EINVAL;
163272407Shselasky
164255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
165255932Salfred	new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL);
166255932Salfred	if (!new_entry)
167255932Salfred		return -ENOMEM;
168255932Salfred
169255932Salfred	INIT_LIST_HEAD(&new_entry->duplicates);
170255932Salfred	new_entry->index = index;
171255932Salfred	list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]);
172255932Salfred
173255932Salfred	/* If the given qpn is also a promisc qp,
174255932Salfred	 * it should be inserted to duplicates list
175255932Salfred	 */
176255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
177255932Salfred	if (pqp) {
178255932Salfred		dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
179255932Salfred		if (!dqp) {
180255932Salfred			err = -ENOMEM;
181255932Salfred			goto out_alloc;
182255932Salfred		}
183255932Salfred		dqp->qpn = qpn;
184255932Salfred		list_add_tail(&dqp->list, &new_entry->duplicates);
185255932Salfred	}
186255932Salfred
187255932Salfred	/* if no promisc qps for this vep, we are done */
188255932Salfred	if (list_empty(&s_steer->promisc_qps[steer]))
189255932Salfred		return 0;
190255932Salfred
191255932Salfred	/* now need to add all the promisc qps to the new
192255932Salfred	 * steering entry, as they should also receive the packets
193255932Salfred	 * destined to this address */
194255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
195255932Salfred	if (IS_ERR(mailbox)) {
196255932Salfred		err = -ENOMEM;
197255932Salfred		goto out_alloc;
198255932Salfred	}
199255932Salfred	mgm = mailbox->buf;
200255932Salfred
201255932Salfred	err = mlx4_READ_ENTRY(dev, index, mailbox);
202255932Salfred	if (err)
203255932Salfred		goto out_mailbox;
204255932Salfred
205255932Salfred	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
206255932Salfred	prot = be32_to_cpu(mgm->members_count) >> 30;
207255932Salfred	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
208255932Salfred		/* don't add already existing qpn */
209255932Salfred		if (pqp->qpn == qpn)
210255932Salfred			continue;
211255932Salfred		if (members_count == dev->caps.num_qp_per_mgm) {
212255932Salfred			/* out of space */
213255932Salfred			err = -ENOMEM;
214255932Salfred			goto out_mailbox;
215255932Salfred		}
216255932Salfred
217255932Salfred		/* add the qpn */
218255932Salfred		mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK);
219255932Salfred	}
220255932Salfred	/* update the qps count and update the entry with all the promisc qps*/
221255932Salfred	mgm->members_count = cpu_to_be32(members_count | (prot << 30));
222255932Salfred	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
223255932Salfred
224255932Salfredout_mailbox:
225255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
226255932Salfred	if (!err)
227255932Salfred		return 0;
228255932Salfredout_alloc:
229255932Salfred	if (dqp) {
230255932Salfred		list_del(&dqp->list);
231255932Salfred		kfree(dqp);
232255932Salfred	}
233255932Salfred	list_del(&new_entry->list);
234255932Salfred	kfree(new_entry);
235255932Salfred	return err;
236255932Salfred}
237255932Salfred
238255932Salfred/* update the data structures with existing steering entry */
239255932Salfredstatic int existing_steering_entry(struct mlx4_dev *dev, u8 port,
240255932Salfred				   enum mlx4_steer_type steer,
241255932Salfred				   unsigned int index, u32 qpn)
242255932Salfred{
243255932Salfred	struct mlx4_steer *s_steer;
244255932Salfred	struct mlx4_steer_index *tmp_entry, *entry = NULL;
245255932Salfred	struct mlx4_promisc_qp *pqp;
246255932Salfred	struct mlx4_promisc_qp *dqp;
247255932Salfred
248272407Shselasky	if (port < 1 || port > dev->caps.num_ports)
249272407Shselasky		return -EINVAL;
250272407Shselasky
251255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
252255932Salfred
253255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
254255932Salfred	if (!pqp)
255255932Salfred		return 0; /* nothing to do */
256255932Salfred
257255932Salfred	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
258255932Salfred		if (tmp_entry->index == index) {
259255932Salfred			entry = tmp_entry;
260255932Salfred			break;
261255932Salfred		}
262255932Salfred	}
263255932Salfred	if (unlikely(!entry)) {
264255932Salfred		mlx4_warn(dev, "Steering entry at index %x is not registered\n", index);
265255932Salfred		return -EINVAL;
266255932Salfred	}
267255932Salfred
268255932Salfred	/* the given qpn is listed as a promisc qpn
269255932Salfred	 * we need to add it as a duplicate to this entry
270255932Salfred	 * for future references */
271255932Salfred	list_for_each_entry(dqp, &entry->duplicates, list) {
272272407Shselasky		if (qpn == dqp->qpn)
273255932Salfred			return 0; /* qp is already duplicated */
274255932Salfred	}
275255932Salfred
276255932Salfred	/* add the qp as a duplicate on this index */
277255932Salfred	dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
278255932Salfred	if (!dqp)
279255932Salfred		return -ENOMEM;
280255932Salfred	dqp->qpn = qpn;
281255932Salfred	list_add_tail(&dqp->list, &entry->duplicates);
282255932Salfred
283255932Salfred	return 0;
284255932Salfred}
285255932Salfred
286255932Salfred/* Check whether a qpn is a duplicate on steering entry
287255932Salfred * If so, it should not be removed from mgm */
288255932Salfredstatic bool check_duplicate_entry(struct mlx4_dev *dev, u8 port,
289255932Salfred				  enum mlx4_steer_type steer,
290255932Salfred				  unsigned int index, u32 qpn)
291255932Salfred{
292255932Salfred	struct mlx4_steer *s_steer;
293255932Salfred	struct mlx4_steer_index *tmp_entry, *entry = NULL;
294255932Salfred	struct mlx4_promisc_qp *dqp, *tmp_dqp;
295255932Salfred
296272407Shselasky	if (port < 1 || port > dev->caps.num_ports)
297272407Shselasky		return NULL;
298272407Shselasky
299255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
300255932Salfred
301255932Salfred	/* if qp is not promisc, it cannot be duplicated */
302255932Salfred	if (!get_promisc_qp(dev, port, steer, qpn))
303255932Salfred		return false;
304255932Salfred
305255932Salfred	/* The qp is promisc qp so it is a duplicate on this index
306255932Salfred	 * Find the index entry, and remove the duplicate */
307255932Salfred	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
308255932Salfred		if (tmp_entry->index == index) {
309255932Salfred			entry = tmp_entry;
310255932Salfred			break;
311255932Salfred		}
312255932Salfred	}
313255932Salfred	if (unlikely(!entry)) {
314255932Salfred		mlx4_warn(dev, "Steering entry for index %x is not registered\n", index);
315255932Salfred		return false;
316255932Salfred	}
317255932Salfred	list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) {
318255932Salfred		if (dqp->qpn == qpn) {
319255932Salfred			list_del(&dqp->list);
320255932Salfred			kfree(dqp);
321255932Salfred		}
322255932Salfred	}
323255932Salfred	return true;
324255932Salfred}
325255932Salfred
326272407Shselasky/*
327272407Shselasky * returns true if all the QPs != tqpn contained in this entry
328272407Shselasky * are Promisc QPs. return false otherwise.
329272407Shselasky */
330272407Shselaskystatic bool promisc_steering_entry(struct mlx4_dev *dev, u8 port,
331255932Salfred				      enum mlx4_steer_type steer,
332272407Shselasky				      unsigned int index, u32 tqpn, u32 *members_count)
333255932Salfred{
334255932Salfred	struct mlx4_steer *s_steer;
335255932Salfred	struct mlx4_cmd_mailbox *mailbox;
336255932Salfred	struct mlx4_mgm *mgm;
337272407Shselasky	u32 m_count;
338255932Salfred	bool ret = false;
339255932Salfred	int i;
340255932Salfred
341272407Shselasky	if (port < 1 || port > dev->caps.num_ports)
342272407Shselasky		return false;
343272407Shselasky
344255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
345255932Salfred
346255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
347255932Salfred	if (IS_ERR(mailbox))
348255932Salfred		return false;
349255932Salfred	mgm = mailbox->buf;
350255932Salfred
351255932Salfred	if (mlx4_READ_ENTRY(dev, index, mailbox))
352255932Salfred		goto out;
353272407Shselasky	m_count = be32_to_cpu(mgm->members_count) & 0xffffff;
354272407Shselasky	if (members_count)
355272407Shselasky		*members_count = m_count;
356272407Shselasky
357272407Shselasky	for (i = 0;  i < m_count; i++) {
358272407Shselasky		u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
359255932Salfred		if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) {
360255932Salfred			/* the qp is not promisc, the entry can't be removed */
361255932Salfred			goto out;
362255932Salfred		}
363255932Salfred	}
364272407Shselasky	ret = true;
365272407Shselaskyout:
366272407Shselasky	mlx4_free_cmd_mailbox(dev, mailbox);
367272407Shselasky	return ret;
368272407Shselasky}
369272407Shselasky
370272407Shselasky/* IF a steering entry contains only promisc QPs, it can be removed. */
371272407Shselaskystatic bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
372272407Shselasky				      enum mlx4_steer_type steer,
373272407Shselasky				      unsigned int index, u32 tqpn)
374272407Shselasky{
375272407Shselasky	struct mlx4_steer *s_steer;
376272407Shselasky	struct mlx4_steer_index *entry = NULL, *tmp_entry;
377272407Shselasky	u32 members_count;
378272407Shselasky	bool ret = false;
379272407Shselasky
380272407Shselasky	if (port < 1 || port > dev->caps.num_ports)
381272407Shselasky		return NULL;
382272407Shselasky
383272407Shselasky	s_steer = &mlx4_priv(dev)->steer[port - 1];
384272407Shselasky
385272407Shselasky	if (!promisc_steering_entry(dev, port, steer, index, tqpn, &members_count))
386272407Shselasky		goto out;
387272407Shselasky
388272407Shselasky	/* All the qps currently registered for this entry are promiscuous,
389255932Salfred	  * Checking for duplicates */
390255932Salfred	ret = true;
391255932Salfred	list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
392255932Salfred		if (entry->index == index) {
393255932Salfred			if (list_empty(&entry->duplicates) || members_count == 1) {
394255932Salfred				struct mlx4_promisc_qp *pqp, *tmp_pqp;
395255932Salfred				/*
396255932Salfred				 * If there is only 1 entry in duplicates than
397255932Salfred				 * this is the QP we want to delete, going over
398255932Salfred				 * the list and deleting the entry.
399255932Salfred				 */
400255932Salfred				list_del(&entry->list);
401255932Salfred				list_for_each_entry_safe(pqp, tmp_pqp,
402255932Salfred							 &entry->duplicates,
403255932Salfred							 list) {
404255932Salfred					list_del(&pqp->list);
405255932Salfred					kfree(pqp);
406255932Salfred				}
407255932Salfred				kfree(entry);
408255932Salfred			} else {
409255932Salfred				/* This entry contains duplicates so it shouldn't be removed */
410255932Salfred				ret = false;
411255932Salfred				goto out;
412255932Salfred			}
413255932Salfred		}
414255932Salfred	}
415255932Salfred
416255932Salfredout:
417255932Salfred	return ret;
418255932Salfred}
419255932Salfred
420255932Salfredstatic int add_promisc_qp(struct mlx4_dev *dev, u8 port,
421255932Salfred			  enum mlx4_steer_type steer, u32 qpn)
422255932Salfred{
423255932Salfred	struct mlx4_steer *s_steer;
424255932Salfred	struct mlx4_cmd_mailbox *mailbox;
425255932Salfred	struct mlx4_mgm *mgm;
426255932Salfred	struct mlx4_steer_index *entry;
427255932Salfred	struct mlx4_promisc_qp *pqp;
428255932Salfred	struct mlx4_promisc_qp *dqp;
429255932Salfred	u32 members_count;
430255932Salfred	u32 prot;
431255932Salfred	int i;
432255932Salfred	bool found;
433255932Salfred	int err;
434255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
435255932Salfred
436272407Shselasky	if (port < 1 || port > dev->caps.num_ports)
437272407Shselasky		return -EINVAL;
438272407Shselasky
439255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
440255932Salfred
441255932Salfred	mutex_lock(&priv->mcg_table.mutex);
442255932Salfred
443255932Salfred	if (get_promisc_qp(dev, port, steer, qpn)) {
444255932Salfred		err = 0;  /* Noting to do, already exists */
445255932Salfred		goto out_mutex;
446255932Salfred	}
447255932Salfred
448255932Salfred	pqp = kmalloc(sizeof *pqp, GFP_KERNEL);
449255932Salfred	if (!pqp) {
450255932Salfred		err = -ENOMEM;
451255932Salfred		goto out_mutex;
452255932Salfred	}
453255932Salfred	pqp->qpn = qpn;
454255932Salfred
455255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
456255932Salfred	if (IS_ERR(mailbox)) {
457255932Salfred		err = -ENOMEM;
458255932Salfred		goto out_alloc;
459255932Salfred	}
460255932Salfred	mgm = mailbox->buf;
461255932Salfred
462272407Shselasky	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
463272407Shselasky		/* the promisc qp needs to be added for each one of the steering
464272407Shselasky		 * entries, if it already exists, needs to be added as a duplicate
465272407Shselasky		 * for this entry */
466272407Shselasky		list_for_each_entry(entry, &s_steer->steer_entries[steer], list) {
467272407Shselasky			err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
468272407Shselasky			if (err)
469272407Shselasky				goto out_mailbox;
470255932Salfred
471272407Shselasky			members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
472272407Shselasky			prot = be32_to_cpu(mgm->members_count) >> 30;
473272407Shselasky			found = false;
474272407Shselasky			for (i = 0; i < members_count; i++) {
475272407Shselasky				if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
476272407Shselasky					/* Entry already exists, add to duplicates */
477272407Shselasky					dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
478272407Shselasky					if (!dqp) {
479272407Shselasky						err = -ENOMEM;
480272407Shselasky						goto out_mailbox;
481272407Shselasky					}
482272407Shselasky					dqp->qpn = qpn;
483272407Shselasky					list_add_tail(&dqp->list, &entry->duplicates);
484272407Shselasky					found = true;
485272407Shselasky				}
486272407Shselasky			}
487272407Shselasky			if (!found) {
488272407Shselasky				/* Need to add the qpn to mgm */
489272407Shselasky				if (members_count == dev->caps.num_qp_per_mgm) {
490272407Shselasky					/* entry is full */
491255932Salfred					err = -ENOMEM;
492255932Salfred					goto out_mailbox;
493255932Salfred				}
494272407Shselasky				mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK);
495272407Shselasky				mgm->members_count = cpu_to_be32(members_count | (prot << 30));
496272407Shselasky				err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
497272407Shselasky				if (err)
498272407Shselasky					goto out_mailbox;
499255932Salfred			}
500255932Salfred		}
501255932Salfred	}
502255932Salfred
503255932Salfred	/* add the new qpn to list of promisc qps */
504255932Salfred	list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
505255932Salfred	/* now need to add all the promisc qps to default entry */
506255932Salfred	memset(mgm, 0, sizeof *mgm);
507255932Salfred	members_count = 0;
508255932Salfred	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) {
509255932Salfred		if (members_count == dev->caps.num_qp_per_mgm) {
510255932Salfred			/* entry is full */
511255932Salfred			err = -ENOMEM;
512255932Salfred			goto out_list;
513255932Salfred		}
514255932Salfred		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
515255932Salfred	}
516255932Salfred	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
517255932Salfred
518255932Salfred	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
519255932Salfred	if (err)
520255932Salfred		goto out_list;
521255932Salfred
522255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
523255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
524255932Salfred	return 0;
525255932Salfred
526255932Salfredout_list:
527255932Salfred	list_del(&pqp->list);
528255932Salfredout_mailbox:
529255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
530255932Salfredout_alloc:
531255932Salfred	kfree(pqp);
532255932Salfredout_mutex:
533255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
534255932Salfred	return err;
535255932Salfred}
536255932Salfred
537255932Salfredstatic int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
538255932Salfred			     enum mlx4_steer_type steer, u32 qpn)
539255932Salfred{
540255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
541255932Salfred	struct mlx4_steer *s_steer;
542255932Salfred	struct mlx4_cmd_mailbox *mailbox;
543255932Salfred	struct mlx4_mgm *mgm;
544272407Shselasky	struct mlx4_steer_index *entry, *tmp_entry;
545255932Salfred	struct mlx4_promisc_qp *pqp;
546255932Salfred	struct mlx4_promisc_qp *dqp;
547255932Salfred	u32 members_count;
548255932Salfred	bool found;
549255932Salfred	bool back_to_list = false;
550255932Salfred	int i, loc = -1;
551255932Salfred	int err;
552255932Salfred
553272407Shselasky	if (port < 1 || port > dev->caps.num_ports)
554272407Shselasky		return -EINVAL;
555272407Shselasky
556255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
557255932Salfred	mutex_lock(&priv->mcg_table.mutex);
558255932Salfred
559255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
560255932Salfred	if (unlikely(!pqp)) {
561255932Salfred		mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn);
562255932Salfred		/* nothing to do */
563255932Salfred		err = 0;
564255932Salfred		goto out_mutex;
565255932Salfred	}
566255932Salfred
567255932Salfred	/*remove from list of promisc qps */
568255932Salfred	list_del(&pqp->list);
569255932Salfred
570255932Salfred	/* set the default entry not to include the removed one */
571255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
572255932Salfred	if (IS_ERR(mailbox)) {
573255932Salfred		err = -ENOMEM;
574255932Salfred		back_to_list = true;
575255932Salfred		goto out_list;
576255932Salfred	}
577255932Salfred	mgm = mailbox->buf;
578255932Salfred	memset(mgm, 0, sizeof *mgm);
579255932Salfred	members_count = 0;
580255932Salfred	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
581255932Salfred		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
582255932Salfred	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
583255932Salfred
584255932Salfred	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
585255932Salfred	if (err)
586255932Salfred		goto out_mailbox;
587255932Salfred
588272407Shselasky	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
589272407Shselasky		/* remove the qp from all the steering entries*/
590272407Shselasky		list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
591272407Shselasky			found = false;
592272407Shselasky			list_for_each_entry(dqp, &entry->duplicates, list) {
593272407Shselasky				if (dqp->qpn == qpn) {
594272407Shselasky					found = true;
595255932Salfred					break;
596255932Salfred				}
597255932Salfred			}
598272407Shselasky			if (found) {
599272407Shselasky				/* a duplicate, no need to change the mgm,
600272407Shselasky				 * only update the duplicates list */
601272407Shselasky				list_del(&dqp->list);
602272407Shselasky				kfree(dqp);
603272407Shselasky			} else {
604272407Shselasky				err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
605272407Shselasky					if (err)
606272407Shselasky						goto out_mailbox;
607272407Shselasky				members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
608272407Shselasky				if (!members_count) {
609272407Shselasky					mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0."
610272407Shselasky					               " deleting entry...\n", qpn, entry->index);
611272407Shselasky					list_del(&entry->list);
612272407Shselasky					kfree(entry);
613272407Shselasky					continue;
614272407Shselasky				}
615255932Salfred
616272407Shselasky				for (i = 0; i < members_count; ++i)
617272407Shselasky					if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
618272407Shselasky						loc = i;
619272407Shselasky						break;
620272407Shselasky					}
621255932Salfred
622272407Shselasky				if (loc < 0) {
623272407Shselasky					mlx4_err(dev, "QP %06x wasn't found in entry %d\n",
624272407Shselasky						 qpn, entry->index);
625272407Shselasky					err = -EINVAL;
626255932Salfred					goto out_mailbox;
627272407Shselasky				}
628272407Shselasky
629272407Shselasky				/* copy the last QP in this MGM over removed QP */
630272407Shselasky				mgm->qp[loc] = mgm->qp[members_count - 1];
631272407Shselasky				mgm->qp[members_count - 1] = 0;
632272407Shselasky				mgm->members_count = cpu_to_be32(--members_count |
633272407Shselasky								 (MLX4_PROT_ETH << 30));
634272407Shselasky
635272407Shselasky				err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
636272407Shselasky					if (err)
637272407Shselasky						goto out_mailbox;
638272407Shselasky			}
639255932Salfred		}
640255932Salfred	}
641255932Salfred
642255932Salfredout_mailbox:
643255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
644255932Salfredout_list:
645255932Salfred	if (back_to_list)
646255932Salfred		list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
647255932Salfred	else
648255932Salfred		kfree(pqp);
649255932Salfredout_mutex:
650255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
651255932Salfred	return err;
652255932Salfred}
653255932Salfred
654255932Salfred/*
655219820Sjeff * Caller must hold MCG table semaphore.  gid and mgm parameters must
656219820Sjeff * be properly aligned for command interface.
657219820Sjeff *
658219820Sjeff *  Returns 0 unless a firmware command error occurs.
659219820Sjeff *
660219820Sjeff * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
661219820Sjeff * and *mgm holds MGM entry.
662219820Sjeff *
663219820Sjeff * if GID is found in AMGM, *index = index in AMGM, *prev = index of
664219820Sjeff * previous entry in hash chain and *mgm holds AMGM entry.
665219820Sjeff *
666219820Sjeff * If no AMGM exists for given gid, *index = -1, *prev = index of last
667219820Sjeff * entry in hash chain and *mgm holds end of hash chain.
668219820Sjeff */
669255932Salfredstatic int find_entry(struct mlx4_dev *dev, u8 port,
670255932Salfred		      u8 *gid, enum mlx4_protocol prot,
671255932Salfred		      struct mlx4_cmd_mailbox *mgm_mailbox,
672255932Salfred		      int *prev, int *index)
673219820Sjeff{
674219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
675219820Sjeff	struct mlx4_mgm *mgm = mgm_mailbox->buf;
676219820Sjeff	u8 *mgid;
677219820Sjeff	int err;
678255932Salfred	u16 hash;
679255932Salfred	u8 op_mod = (prot == MLX4_PROT_ETH) ?
680255932Salfred		!!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0;
681219820Sjeff
682219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
683219820Sjeff	if (IS_ERR(mailbox))
684219820Sjeff		return -ENOMEM;
685219820Sjeff	mgid = mailbox->buf;
686219820Sjeff
687219820Sjeff	memcpy(mgid, gid, 16);
688219820Sjeff
689255932Salfred	err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod);
690219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
691219820Sjeff	if (err)
692219820Sjeff		return err;
693219820Sjeff
694279731Shselasky	if (0) {
695279731Shselasky		mlx4_dbg(dev, "Hash for "GID_PRINT_FMT" is %04x\n",
696279731Shselasky		    GID_PRINT_ARGS(gid), hash);
697279731Shselasky	}
698219820Sjeff
699255932Salfred	*index = hash;
700219820Sjeff	*prev  = -1;
701219820Sjeff
702219820Sjeff	do {
703255932Salfred		err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox);
704219820Sjeff		if (err)
705219820Sjeff			return err;
706219820Sjeff
707255932Salfred		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
708255932Salfred			if (*index != hash) {
709219820Sjeff				mlx4_err(dev, "Found zero MGID in AMGM.\n");
710219820Sjeff				err = -EINVAL;
711219820Sjeff			}
712219820Sjeff			return err;
713219820Sjeff		}
714219820Sjeff
715219820Sjeff		if (!memcmp(mgm->gid, gid, 16) &&
716255932Salfred		    be32_to_cpu(mgm->members_count) >> 30 == prot)
717219820Sjeff			return err;
718219820Sjeff
719219820Sjeff		*prev = *index;
720219820Sjeff		*index = be32_to_cpu(mgm->next_gid_index) >> 6;
721219820Sjeff	} while (*index);
722219820Sjeff
723219820Sjeff	*index = -1;
724219820Sjeff	return err;
725219820Sjeff}
726219820Sjeff
727272407Shselaskystatic const u8 __promisc_mode[] = {
728272407Shselasky	[MLX4_FS_REGULAR]   = 0x0,
729272407Shselasky	[MLX4_FS_ALL_DEFAULT] = 0x1,
730272407Shselasky	[MLX4_FS_MC_DEFAULT] = 0x3,
731272407Shselasky	[MLX4_FS_UC_SNIFFER] = 0x4,
732272407Shselasky	[MLX4_FS_MC_SNIFFER] = 0x5,
733272407Shselasky};
734272407Shselasky
735272407Shselaskyint map_sw_to_hw_steering_mode(struct mlx4_dev *dev,
736272407Shselasky			       enum mlx4_net_trans_promisc_mode flow_type)
737272407Shselasky{
738272407Shselasky	if (flow_type >= MLX4_FS_MODE_NUM || flow_type < 0) {
739272407Shselasky		mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type);
740272407Shselasky		return -EINVAL;
741272407Shselasky	}
742272407Shselasky	return __promisc_mode[flow_type];
743272407Shselasky}
744272407ShselaskyEXPORT_SYMBOL_GPL(map_sw_to_hw_steering_mode);
745272407Shselasky
746255932Salfredstatic void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,
747255932Salfred				  struct mlx4_net_trans_rule_hw_ctrl *hw)
748219820Sjeff{
749272407Shselasky	u8 flags = 0;
750255932Salfred
751272407Shselasky	flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0;
752272407Shselasky	flags |= ctrl->exclusive ? (1 << 2) : 0;
753272407Shselasky	flags |= ctrl->allow_loopback ? (1 << 3) : 0;
754255932Salfred
755272407Shselasky	hw->flags = flags;
756272407Shselasky	hw->type = __promisc_mode[ctrl->promisc_mode];
757272407Shselasky	hw->prio = cpu_to_be16(ctrl->priority);
758255932Salfred	hw->port = ctrl->port;
759255932Salfred	hw->qpn = cpu_to_be32(ctrl->qpn);
760255932Salfred}
761255932Salfred
762255932Salfredconst u16 __sw_id_hw[] = {
763255932Salfred	[MLX4_NET_TRANS_RULE_ID_ETH]     = 0xE001,
764255932Salfred	[MLX4_NET_TRANS_RULE_ID_IB]      = 0xE005,
765255932Salfred	[MLX4_NET_TRANS_RULE_ID_IPV6]    = 0xE003,
766255932Salfred	[MLX4_NET_TRANS_RULE_ID_IPV4]    = 0xE002,
767255932Salfred	[MLX4_NET_TRANS_RULE_ID_TCP]     = 0xE004,
768255932Salfred	[MLX4_NET_TRANS_RULE_ID_UDP]     = 0xE006
769255932Salfred};
770255932Salfred
771272407Shselaskyint map_sw_to_hw_steering_id(struct mlx4_dev *dev,
772272407Shselasky			     enum mlx4_net_trans_rule_id id)
773272407Shselasky{
774272407Shselasky	if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) {
775272407Shselasky		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
776272407Shselasky		return -EINVAL;
777272407Shselasky	}
778272407Shselasky	return __sw_id_hw[id];
779272407Shselasky}
780272407ShselaskyEXPORT_SYMBOL_GPL(map_sw_to_hw_steering_id);
781272407Shselasky
782272407Shselaskystatic const int __rule_hw_sz[] = {
783272407Shselasky	[MLX4_NET_TRANS_RULE_ID_ETH] =
784272407Shselasky		sizeof(struct mlx4_net_trans_rule_hw_eth),
785272407Shselasky	[MLX4_NET_TRANS_RULE_ID_IB] =
786272407Shselasky		sizeof(struct mlx4_net_trans_rule_hw_ib),
787272407Shselasky	[MLX4_NET_TRANS_RULE_ID_IPV6] = 0,
788272407Shselasky	[MLX4_NET_TRANS_RULE_ID_IPV4] =
789272407Shselasky		sizeof(struct mlx4_net_trans_rule_hw_ipv4),
790272407Shselasky	[MLX4_NET_TRANS_RULE_ID_TCP] =
791272407Shselasky		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),
792272407Shselasky	[MLX4_NET_TRANS_RULE_ID_UDP] =
793272407Shselasky		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp)
794272407Shselasky};
795272407Shselasky
796272407Shselaskyint hw_rule_sz(struct mlx4_dev *dev,
797272407Shselasky	       enum mlx4_net_trans_rule_id id)
798272407Shselasky{
799272407Shselasky	if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) {
800272407Shselasky		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
801272407Shselasky		return -EINVAL;
802272407Shselasky	}
803272407Shselasky
804272407Shselasky	return __rule_hw_sz[id];
805272407Shselasky}
806272407ShselaskyEXPORT_SYMBOL_GPL(hw_rule_sz);
807272407Shselasky
808255932Salfredstatic int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec,
809255932Salfred			    struct _rule_hw *rule_hw)
810255932Salfred{
811272407Shselasky	if (hw_rule_sz(dev, spec->id) < 0)
812255932Salfred		return -EINVAL;
813272407Shselasky	memset(rule_hw, 0, hw_rule_sz(dev, spec->id));
814255932Salfred	rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]);
815272407Shselasky	rule_hw->size = hw_rule_sz(dev, spec->id) >> 2;
816255932Salfred
817255932Salfred	switch (spec->id) {
818255932Salfred	case MLX4_NET_TRANS_RULE_ID_ETH:
819255932Salfred		memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN);
820255932Salfred		memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk,
821255932Salfred		       ETH_ALEN);
822255932Salfred		memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN);
823255932Salfred		memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk,
824255932Salfred		       ETH_ALEN);
825255932Salfred		if (spec->eth.ether_type_enable) {
826255932Salfred			rule_hw->eth.ether_type_enable = 1;
827255932Salfred			rule_hw->eth.ether_type = spec->eth.ether_type;
828255932Salfred		}
829272407Shselasky		rule_hw->eth.vlan_tag = spec->eth.vlan_id;
830272407Shselasky		rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk;
831255932Salfred		break;
832255932Salfred
833255932Salfred	case MLX4_NET_TRANS_RULE_ID_IB:
834272407Shselasky		rule_hw->ib.l3_qpn = spec->ib.l3_qpn;
835255932Salfred		rule_hw->ib.qpn_mask = spec->ib.qpn_msk;
836255932Salfred		memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16);
837255932Salfred		memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16);
838255932Salfred		break;
839255932Salfred
840255932Salfred	case MLX4_NET_TRANS_RULE_ID_IPV6:
841255932Salfred		return -EOPNOTSUPP;
842255932Salfred
843255932Salfred	case MLX4_NET_TRANS_RULE_ID_IPV4:
844255932Salfred		rule_hw->ipv4.src_ip = spec->ipv4.src_ip;
845255932Salfred		rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk;
846255932Salfred		rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip;
847255932Salfred		rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk;
848255932Salfred		break;
849255932Salfred
850255932Salfred	case MLX4_NET_TRANS_RULE_ID_TCP:
851255932Salfred	case MLX4_NET_TRANS_RULE_ID_UDP:
852255932Salfred		rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port;
853255932Salfred		rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk;
854255932Salfred		rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port;
855255932Salfred		rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk;
856255932Salfred		break;
857255932Salfred
858255932Salfred	default:
859255932Salfred		return -EINVAL;
860255932Salfred	}
861255932Salfred
862255932Salfred	return __rule_hw_sz[spec->id];
863255932Salfred}
864255932Salfred
865255932Salfredstatic void mlx4_err_rule(struct mlx4_dev *dev, char *str,
866255932Salfred			  struct mlx4_net_trans_rule *rule)
867255932Salfred{
868255932Salfred#define BUF_SIZE 256
869255932Salfred	struct mlx4_spec_list *cur;
870255932Salfred	char buf[BUF_SIZE];
871255932Salfred	int len = 0;
872255932Salfred
873255932Salfred	mlx4_err(dev, "%s", str);
874255932Salfred	len += snprintf(buf + len, BUF_SIZE - len,
875255932Salfred			"port = %d prio = 0x%x qp = 0x%x ",
876255932Salfred			rule->port, rule->priority, rule->qpn);
877255932Salfred
878255932Salfred	list_for_each_entry(cur, &rule->list, list) {
879255932Salfred		switch (cur->id) {
880255932Salfred		case MLX4_NET_TRANS_RULE_ID_ETH:
881255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
882255932Salfred					"dmac = %pM ", &cur->eth.dst_mac);
883255932Salfred			if (cur->eth.ether_type)
884255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
885255932Salfred						"ethertype = 0x%x ",
886255932Salfred						be16_to_cpu(cur->eth.ether_type));
887255932Salfred			if (cur->eth.vlan_id)
888255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
889255932Salfred						"vlan-id = %d ",
890255932Salfred						be16_to_cpu(cur->eth.vlan_id));
891255932Salfred			break;
892255932Salfred
893255932Salfred		case MLX4_NET_TRANS_RULE_ID_IPV4:
894255932Salfred			if (cur->ipv4.src_ip)
895255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
896255932Salfred						"src-ip = %pI4 ",
897255932Salfred						&cur->ipv4.src_ip);
898255932Salfred			if (cur->ipv4.dst_ip)
899255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
900255932Salfred						"dst-ip = %pI4 ",
901255932Salfred						&cur->ipv4.dst_ip);
902255932Salfred			break;
903255932Salfred
904255932Salfred		case MLX4_NET_TRANS_RULE_ID_TCP:
905255932Salfred		case MLX4_NET_TRANS_RULE_ID_UDP:
906255932Salfred			if (cur->tcp_udp.src_port)
907255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
908255932Salfred						"src-port = %d ",
909255932Salfred						be16_to_cpu(cur->tcp_udp.src_port));
910255932Salfred			if (cur->tcp_udp.dst_port)
911255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
912255932Salfred						"dst-port = %d ",
913255932Salfred						be16_to_cpu(cur->tcp_udp.dst_port));
914255932Salfred			break;
915255932Salfred
916255932Salfred		case MLX4_NET_TRANS_RULE_ID_IB:
917255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
918279731Shselasky					"dst-gid = "GID_PRINT_FMT"\n",
919279731Shselasky					GID_PRINT_ARGS(cur->ib.dst_gid));
920255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
921279731Shselasky					"dst-gid-mask = "GID_PRINT_FMT"\n",
922279731Shselasky					GID_PRINT_ARGS(cur->ib.dst_gid_msk));
923255932Salfred			break;
924255932Salfred
925255932Salfred		case MLX4_NET_TRANS_RULE_ID_IPV6:
926255932Salfred			break;
927255932Salfred
928255932Salfred		default:
929255932Salfred			break;
930255932Salfred		}
931255932Salfred	}
932255932Salfred	len += snprintf(buf + len, BUF_SIZE - len, "\n");
933255932Salfred	mlx4_err(dev, "%s", buf);
934255932Salfred
935255932Salfred	if (len >= BUF_SIZE)
936255932Salfred		mlx4_err(dev, "Network rule error message was truncated, print buffer is too small.\n");
937255932Salfred}
938255932Salfred
939255932Salfredint mlx4_flow_attach(struct mlx4_dev *dev,
940255932Salfred		     struct mlx4_net_trans_rule *rule, u64 *reg_id)
941255932Salfred{
942255932Salfred	struct mlx4_cmd_mailbox *mailbox;
943255932Salfred	struct mlx4_spec_list *cur;
944255932Salfred	u32 size = 0;
945255932Salfred	int ret;
946255932Salfred
947255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
948255932Salfred	if (IS_ERR(mailbox))
949255932Salfred		return PTR_ERR(mailbox);
950255932Salfred
951255932Salfred	memset(mailbox->buf, 0, sizeof(struct mlx4_net_trans_rule_hw_ctrl));
952255932Salfred	trans_rule_ctrl_to_hw(rule, mailbox->buf);
953255932Salfred
954255932Salfred	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
955255932Salfred
956255932Salfred	list_for_each_entry(cur, &rule->list, list) {
957255932Salfred		ret = parse_trans_rule(dev, cur, mailbox->buf + size);
958255932Salfred		if (ret < 0) {
959255932Salfred			mlx4_free_cmd_mailbox(dev, mailbox);
960255932Salfred			return -EINVAL;
961255932Salfred		}
962255932Salfred		size += ret;
963255932Salfred	}
964255932Salfred
965255932Salfred	ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);
966255932Salfred	if (ret == -ENOMEM)
967255932Salfred		mlx4_err_rule(dev,
968255932Salfred			      "mcg table is full. Fail to register network rule.\n",
969255932Salfred			      rule);
970255932Salfred	else if (ret)
971255932Salfred		mlx4_err_rule(dev, "Fail to register network rule.\n", rule);
972255932Salfred
973255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
974255932Salfred
975255932Salfred	return ret;
976255932Salfred}
977255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_attach);
978255932Salfred
979255932Salfredint mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id)
980255932Salfred{
981255932Salfred	int err;
982255932Salfred
983255932Salfred	err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id);
984255932Salfred	if (err)
985255932Salfred		mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n",
986272407Shselasky			 (unsigned long long)reg_id);
987255932Salfred	return err;
988255932Salfred}
989255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_detach);
990255932Salfred
991255932Salfredint mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn)
992255932Salfred{
993255932Salfred	int err;
994255932Salfred	u64 in_param;
995255932Salfred
996255932Salfred	in_param = ((u64) min_range_qpn) << 32;
997255932Salfred	in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF;
998255932Salfred
999255932Salfred	err = mlx4_cmd(dev, in_param, 0, 0,
1000255932Salfred			MLX4_FLOW_STEERING_IB_UC_QP_RANGE,
1001255932Salfred			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1002255932Salfred
1003255932Salfred	return err;
1004255932Salfred}
1005255932SalfredEXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE);
1006255932Salfred
1007255932Salfredint mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1008255932Salfred			  int block_mcast_loopback, enum mlx4_protocol prot,
1009255932Salfred			  enum mlx4_steer_type steer)
1010255932Salfred{
1011219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1012219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1013219820Sjeff	struct mlx4_mgm *mgm;
1014219820Sjeff	u32 members_count;
1015219820Sjeff	int index, prev;
1016219820Sjeff	int link = 0;
1017219820Sjeff	int i;
1018219820Sjeff	int err;
1019255932Salfred	u8 port = gid[5];
1020255932Salfred	u8 new_entry = 0;
1021219820Sjeff
1022219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1023219820Sjeff	if (IS_ERR(mailbox))
1024219820Sjeff		return PTR_ERR(mailbox);
1025219820Sjeff	mgm = mailbox->buf;
1026219820Sjeff
1027219820Sjeff	mutex_lock(&priv->mcg_table.mutex);
1028255932Salfred	err = find_entry(dev, port, gid, prot,
1029255932Salfred			 mailbox, &prev, &index);
1030219820Sjeff	if (err)
1031219820Sjeff		goto out;
1032219820Sjeff
1033219820Sjeff	if (index != -1) {
1034255932Salfred		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
1035255932Salfred			new_entry = 1;
1036219820Sjeff			memcpy(mgm->gid, gid, 16);
1037255932Salfred		}
1038219820Sjeff	} else {
1039219820Sjeff		link = 1;
1040219820Sjeff
1041219820Sjeff		index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
1042219820Sjeff		if (index == -1) {
1043219820Sjeff			mlx4_err(dev, "No AMGM entries left\n");
1044219820Sjeff			err = -ENOMEM;
1045219820Sjeff			goto out;
1046219820Sjeff		}
1047219820Sjeff		index += dev->caps.num_mgms;
1048219820Sjeff
1049255932Salfred		new_entry = 1;
1050219820Sjeff		memset(mgm, 0, sizeof *mgm);
1051219820Sjeff		memcpy(mgm->gid, gid, 16);
1052219820Sjeff	}
1053219820Sjeff
1054219820Sjeff	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
1055255932Salfred	if (members_count == dev->caps.num_qp_per_mgm) {
1056219820Sjeff		mlx4_err(dev, "MGM at index %x is full.\n", index);
1057219820Sjeff		err = -ENOMEM;
1058219820Sjeff		goto out;
1059219820Sjeff	}
1060219820Sjeff
1061219820Sjeff	for (i = 0; i < members_count; ++i)
1062219820Sjeff		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
1063219820Sjeff			mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
1064219820Sjeff			err = 0;
1065219820Sjeff			goto out;
1066219820Sjeff		}
1067219820Sjeff
1068219820Sjeff	mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
1069219820Sjeff					       (!!mlx4_blck_lb << MGM_BLCK_LB_BIT));
1070219820Sjeff
1071255932Salfred	mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30);
1072219820Sjeff
1073255932Salfred	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1074219820Sjeff	if (err)
1075219820Sjeff		goto out;
1076219820Sjeff
1077272407Shselasky	/* if !link, still add the new entry. */
1078219820Sjeff	if (!link)
1079272407Shselasky		goto skip_link;
1080219820Sjeff
1081255932Salfred	err = mlx4_READ_ENTRY(dev, prev, mailbox);
1082219820Sjeff	if (err)
1083219820Sjeff		goto out;
1084219820Sjeff
1085219820Sjeff	mgm->next_gid_index = cpu_to_be32(index << 6);
1086219820Sjeff
1087255932Salfred	err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
1088219820Sjeff	if (err)
1089219820Sjeff		goto out;
1090219820Sjeff
1091272407Shselaskyskip_link:
1092255932Salfred	if (prot == MLX4_PROT_ETH) {
1093255932Salfred		/* manage the steering entry for promisc mode */
1094255932Salfred		if (new_entry)
1095255932Salfred			new_steering_entry(dev, port, steer, index, qp->qpn);
1096255932Salfred		else
1097255932Salfred			existing_steering_entry(dev, port, steer,
1098255932Salfred						index, qp->qpn);
1099255932Salfred	}
1100255932Salfred
1101219820Sjeffout:
1102219820Sjeff	if (err && link && index != -1) {
1103219820Sjeff		if (index < dev->caps.num_mgms)
1104219820Sjeff			mlx4_warn(dev, "Got AMGM index %d < %d",
1105219820Sjeff				  index, dev->caps.num_mgms);
1106219820Sjeff		else
1107219820Sjeff			mlx4_bitmap_free(&priv->mcg_table.bitmap,
1108272407Shselasky					 index - dev->caps.num_mgms, MLX4_USE_RR);
1109219820Sjeff	}
1110219820Sjeff	mutex_unlock(&priv->mcg_table.mutex);
1111219820Sjeff
1112219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1113219820Sjeff	return err;
1114219820Sjeff}
1115219820Sjeff
1116255932Salfredint mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1117255932Salfred			  enum mlx4_protocol prot, enum mlx4_steer_type steer)
1118219820Sjeff{
1119219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1120219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1121219820Sjeff	struct mlx4_mgm *mgm;
1122219820Sjeff	u32 members_count;
1123219820Sjeff	int prev, index;
1124255932Salfred	int i, loc = -1;
1125219820Sjeff	int err;
1126255932Salfred	u8 port = gid[5];
1127255932Salfred	bool removed_entry = false;
1128219820Sjeff
1129219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1130219820Sjeff	if (IS_ERR(mailbox))
1131219820Sjeff		return PTR_ERR(mailbox);
1132219820Sjeff	mgm = mailbox->buf;
1133219820Sjeff
1134219820Sjeff	mutex_lock(&priv->mcg_table.mutex);
1135219820Sjeff
1136255932Salfred	err = find_entry(dev, port, gid, prot,
1137255932Salfred			 mailbox, &prev, &index);
1138219820Sjeff	if (err)
1139219820Sjeff		goto out;
1140219820Sjeff
1141219820Sjeff	if (index == -1) {
1142279731Shselasky		mlx4_err(dev, "MGID "GID_PRINT_FMT" not found\n",
1143279731Shselasky		    GID_PRINT_ARGS(gid));
1144219820Sjeff		err = -EINVAL;
1145219820Sjeff		goto out;
1146219820Sjeff	}
1147219820Sjeff
1148272407Shselasky	/*
1149272407Shselasky	  if this QP is also a promisc QP, it shouldn't be removed only if
1150272407Shselasky	  at least one none promisc QP is also attached to this MCG
1151272407Shselasky	*/
1152255932Salfred	if (prot == MLX4_PROT_ETH &&
1153272407Shselasky	    check_duplicate_entry(dev, port, steer, index, qp->qpn) &&
1154272407Shselasky	    !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL))
1155272407Shselasky			goto out;
1156255932Salfred
1157219820Sjeff	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
1158255932Salfred	for (i = 0; i < members_count; ++i)
1159255932Salfred		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
1160219820Sjeff			loc = i;
1161255932Salfred			break;
1162255932Salfred		}
1163219820Sjeff
1164219820Sjeff	if (loc == -1) {
1165219820Sjeff		mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
1166219820Sjeff		err = -EINVAL;
1167219820Sjeff		goto out;
1168219820Sjeff	}
1169219820Sjeff
1170255932Salfred	/* copy the last QP in this MGM over removed QP */
1171255932Salfred	mgm->qp[loc] = mgm->qp[members_count - 1];
1172255932Salfred	mgm->qp[members_count - 1] = 0;
1173255932Salfred	mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30);
1174219820Sjeff
1175255932Salfred	if (prot == MLX4_PROT_ETH)
1176255932Salfred		removed_entry = can_remove_steering_entry(dev, port, steer,
1177255932Salfred								index, qp->qpn);
1178255932Salfred	if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) {
1179255932Salfred		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1180219820Sjeff		goto out;
1181219820Sjeff	}
1182219820Sjeff
1183255932Salfred	/* We are going to delete the entry, members count should be 0 */
1184255932Salfred	mgm->members_count = cpu_to_be32((u32) prot << 30);
1185255932Salfred
1186219820Sjeff	if (prev == -1) {
1187219820Sjeff		/* Remove entry from MGM */
1188219820Sjeff		int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
1189219820Sjeff		if (amgm_index) {
1190255932Salfred			err = mlx4_READ_ENTRY(dev, amgm_index, mailbox);
1191219820Sjeff			if (err)
1192219820Sjeff				goto out;
1193219820Sjeff		} else
1194219820Sjeff			memset(mgm->gid, 0, 16);
1195219820Sjeff
1196255932Salfred		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1197219820Sjeff		if (err)
1198219820Sjeff			goto out;
1199219820Sjeff
1200219820Sjeff		if (amgm_index) {
1201219820Sjeff			if (amgm_index < dev->caps.num_mgms)
1202219820Sjeff				mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d",
1203219820Sjeff					  index, amgm_index, dev->caps.num_mgms);
1204219820Sjeff			else
1205219820Sjeff				mlx4_bitmap_free(&priv->mcg_table.bitmap,
1206272407Shselasky						 amgm_index - dev->caps.num_mgms, MLX4_USE_RR);
1207219820Sjeff		}
1208219820Sjeff	} else {
1209219820Sjeff		/* Remove entry from AMGM */
1210219820Sjeff		int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
1211255932Salfred		err = mlx4_READ_ENTRY(dev, prev, mailbox);
1212219820Sjeff		if (err)
1213219820Sjeff			goto out;
1214219820Sjeff
1215219820Sjeff		mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
1216219820Sjeff
1217255932Salfred		err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
1218219820Sjeff		if (err)
1219219820Sjeff			goto out;
1220219820Sjeff
1221219820Sjeff		if (index < dev->caps.num_mgms)
1222219820Sjeff			mlx4_warn(dev, "entry %d had next AMGM index %d < %d",
1223219820Sjeff				  prev, index, dev->caps.num_mgms);
1224219820Sjeff		else
1225219820Sjeff			mlx4_bitmap_free(&priv->mcg_table.bitmap,
1226272407Shselasky					 index - dev->caps.num_mgms, MLX4_USE_RR);
1227219820Sjeff	}
1228219820Sjeff
1229219820Sjeffout:
1230219820Sjeff	mutex_unlock(&priv->mcg_table.mutex);
1231219820Sjeff
1232219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1233219820Sjeff	return err;
1234219820Sjeff}
1235255932Salfred
1236255932Salfredstatic int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,
1237255932Salfred			  u8 gid[16], u8 attach, u8 block_loopback,
1238255932Salfred			  enum mlx4_protocol prot)
1239255932Salfred{
1240255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1241255932Salfred	int err = 0;
1242255932Salfred	int qpn;
1243255932Salfred
1244255932Salfred	if (!mlx4_is_mfunc(dev))
1245255932Salfred		return -EBADF;
1246255932Salfred
1247255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1248255932Salfred	if (IS_ERR(mailbox))
1249255932Salfred		return PTR_ERR(mailbox);
1250255932Salfred
1251255932Salfred	memcpy(mailbox->buf, gid, 16);
1252255932Salfred	qpn = qp->qpn;
1253255932Salfred	qpn |= (prot << 28);
1254255932Salfred	if (attach && block_loopback)
1255272407Shselasky		qpn |= (1 << 31);
1256255932Salfred
1257255932Salfred	err = mlx4_cmd(dev, mailbox->dma, qpn, attach,
1258255932Salfred		       MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A,
1259255932Salfred		       MLX4_CMD_WRAPPED);
1260255932Salfred
1261255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1262255932Salfred	return err;
1263255932Salfred}
1264255932Salfred
1265272407Shselaskyint mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,
1266272407Shselasky			      u8 gid[16], u8 port,
1267272407Shselasky			      int block_mcast_loopback,
1268272407Shselasky			      enum mlx4_protocol prot, u64 *reg_id)
1269255932Salfred{
1270255932Salfred		struct mlx4_spec_list spec = { {NULL} };
1271255932Salfred		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
1272255932Salfred
1273255932Salfred		struct mlx4_net_trans_rule rule = {
1274255932Salfred			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
1275255932Salfred			.exclusive = 0,
1276255932Salfred			.promisc_mode = MLX4_FS_REGULAR,
1277255932Salfred			.priority = MLX4_DOMAIN_NIC,
1278255932Salfred		};
1279255932Salfred
1280255932Salfred		rule.allow_loopback = !block_mcast_loopback;
1281255932Salfred		rule.port = port;
1282255932Salfred		rule.qpn = qp->qpn;
1283255932Salfred		INIT_LIST_HEAD(&rule.list);
1284255932Salfred
1285255932Salfred		switch (prot) {
1286255932Salfred		case MLX4_PROT_ETH:
1287255932Salfred			spec.id = MLX4_NET_TRANS_RULE_ID_ETH;
1288255932Salfred			memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN);
1289255932Salfred			memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
1290255932Salfred			break;
1291255932Salfred
1292255932Salfred		case MLX4_PROT_IB_IPV6:
1293255932Salfred			spec.id = MLX4_NET_TRANS_RULE_ID_IB;
1294255932Salfred			memcpy(spec.ib.dst_gid, gid, 16);
1295255932Salfred			memset(&spec.ib.dst_gid_msk, 0xff, 16);
1296255932Salfred			break;
1297255932Salfred		default:
1298255932Salfred			return -EINVAL;
1299255932Salfred		}
1300255932Salfred		list_add_tail(&spec.list, &rule.list);
1301255932Salfred
1302255932Salfred		return mlx4_flow_attach(dev, &rule, reg_id);
1303272407Shselasky}
1304255932Salfred
1305272407Shselaskyint mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1306272407Shselasky			  u8 port, int block_mcast_loopback,
1307272407Shselasky			  enum mlx4_protocol prot, u64 *reg_id)
1308272407Shselasky{
1309272407Shselasky	enum mlx4_steer_type steer;
1310272407Shselasky	steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER;
1311272407Shselasky
1312272407Shselasky	switch (dev->caps.steering_mode) {
1313272407Shselasky	case MLX4_STEERING_MODE_A0:
1314272407Shselasky		if (prot == MLX4_PROT_ETH)
1315272407Shselasky			return 0;
1316272407Shselasky
1317272407Shselasky	case MLX4_STEERING_MODE_B0:
1318272407Shselasky		if (prot == MLX4_PROT_ETH)
1319272407Shselasky			gid[7] |= (steer << 1);
1320272407Shselasky
1321272407Shselasky		if (mlx4_is_mfunc(dev))
1322272407Shselasky			return mlx4_QP_ATTACH(dev, qp, gid, 1,
1323272407Shselasky					      block_mcast_loopback, prot);
1324272407Shselasky		return mlx4_qp_attach_common(dev, qp, gid,
1325272407Shselasky					     block_mcast_loopback, prot,
1326272407Shselasky					     MLX4_MC_STEER);
1327272407Shselasky
1328272407Shselasky	case MLX4_STEERING_MODE_DEVICE_MANAGED:
1329272407Shselasky		return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
1330272407Shselasky						 block_mcast_loopback,
1331272407Shselasky						 prot, reg_id);
1332255932Salfred	default:
1333255932Salfred		return -EINVAL;
1334255932Salfred	}
1335255932Salfred}
1336255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_attach);
1337255932Salfred
1338255932Salfredint mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1339255932Salfred			  enum mlx4_protocol prot, u64 reg_id)
1340255932Salfred{
1341272407Shselasky	enum mlx4_steer_type steer;
1342272407Shselasky	steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER;
1343272407Shselasky
1344255932Salfred	switch (dev->caps.steering_mode) {
1345255932Salfred	case MLX4_STEERING_MODE_A0:
1346255932Salfred		if (prot == MLX4_PROT_ETH)
1347255932Salfred			return 0;
1348255932Salfred
1349255932Salfred	case MLX4_STEERING_MODE_B0:
1350255932Salfred		if (prot == MLX4_PROT_ETH)
1351272407Shselasky			gid[7] |= (steer << 1);
1352255932Salfred
1353255932Salfred		if (mlx4_is_mfunc(dev))
1354255932Salfred			return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
1355255932Salfred
1356255932Salfred		return mlx4_qp_detach_common(dev, qp, gid, prot,
1357255932Salfred					     MLX4_MC_STEER);
1358255932Salfred
1359255932Salfred	case MLX4_STEERING_MODE_DEVICE_MANAGED:
1360255932Salfred		return mlx4_flow_detach(dev, reg_id);
1361255932Salfred
1362255932Salfred	default:
1363255932Salfred		return -EINVAL;
1364255932Salfred	}
1365255932Salfred}
1366219820SjeffEXPORT_SYMBOL_GPL(mlx4_multicast_detach);
1367219820Sjeff
1368255932Salfredint mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
1369255932Salfred				u32 qpn, enum mlx4_net_trans_promisc_mode mode)
1370255932Salfred{
1371255932Salfred	struct mlx4_net_trans_rule rule;
1372255932Salfred	u64 *regid_p;
1373255932Salfred
1374255932Salfred	switch (mode) {
1375255932Salfred	case MLX4_FS_ALL_DEFAULT:
1376255932Salfred		regid_p = &dev->regid_promisc_array[port];
1377255932Salfred		break;
1378255932Salfred	case MLX4_FS_MC_DEFAULT:
1379255932Salfred		regid_p = &dev->regid_allmulti_array[port];
1380255932Salfred		break;
1381255932Salfred	default:
1382255932Salfred		return -1;
1383255932Salfred	}
1384255932Salfred
1385255932Salfred	if (*regid_p != 0)
1386255932Salfred		return -1;
1387255932Salfred
1388255932Salfred	rule.promisc_mode = mode;
1389255932Salfred	rule.port = port;
1390255932Salfred	rule.qpn = qpn;
1391255932Salfred	INIT_LIST_HEAD(&rule.list);
1392255932Salfred	mlx4_err(dev, "going promisc on %x\n", port);
1393255932Salfred
1394255932Salfred	return  mlx4_flow_attach(dev, &rule, regid_p);
1395255932Salfred}
1396255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add);
1397255932Salfred
1398255932Salfredint mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port,
1399255932Salfred				   enum mlx4_net_trans_promisc_mode mode)
1400255932Salfred{
1401255932Salfred	int ret;
1402255932Salfred	u64 *regid_p;
1403255932Salfred
1404255932Salfred	switch (mode) {
1405255932Salfred	case MLX4_FS_ALL_DEFAULT:
1406255932Salfred		regid_p = &dev->regid_promisc_array[port];
1407255932Salfred		break;
1408255932Salfred	case MLX4_FS_MC_DEFAULT:
1409255932Salfred		regid_p = &dev->regid_allmulti_array[port];
1410255932Salfred		break;
1411255932Salfred	default:
1412255932Salfred		return -1;
1413255932Salfred	}
1414255932Salfred
1415255932Salfred	if (*regid_p == 0)
1416255932Salfred		return -1;
1417255932Salfred
1418255932Salfred	ret =  mlx4_flow_detach(dev, *regid_p);
1419255932Salfred	if (ret == 0)
1420255932Salfred		*regid_p = 0;
1421255932Salfred
1422255932Salfred	return ret;
1423255932Salfred}
1424255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove);
1425255932Salfred
1426255932Salfredint mlx4_unicast_attach(struct mlx4_dev *dev,
1427255932Salfred			struct mlx4_qp *qp, u8 gid[16],
1428255932Salfred			int block_mcast_loopback, enum mlx4_protocol prot)
1429255932Salfred{
1430255932Salfred	if (prot == MLX4_PROT_ETH)
1431255932Salfred		gid[7] |= (MLX4_UC_STEER << 1);
1432255932Salfred
1433255932Salfred	if (mlx4_is_mfunc(dev))
1434255932Salfred		return mlx4_QP_ATTACH(dev, qp, gid, 1,
1435255932Salfred					block_mcast_loopback, prot);
1436255932Salfred
1437255932Salfred	return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback,
1438255932Salfred					prot, MLX4_UC_STEER);
1439255932Salfred}
1440255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_attach);
1441255932Salfred
1442255932Salfredint mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
1443255932Salfred			       u8 gid[16], enum mlx4_protocol prot)
1444255932Salfred{
1445255932Salfred	if (prot == MLX4_PROT_ETH)
1446255932Salfred		gid[7] |= (MLX4_UC_STEER << 1);
1447255932Salfred
1448255932Salfred	if (mlx4_is_mfunc(dev))
1449255932Salfred		return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
1450255932Salfred
1451255932Salfred	return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER);
1452255932Salfred}
1453255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_detach);
1454255932Salfred
1455255932Salfredint mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave,
1456255932Salfred			 struct mlx4_vhcr *vhcr,
1457255932Salfred			 struct mlx4_cmd_mailbox *inbox,
1458255932Salfred			 struct mlx4_cmd_mailbox *outbox,
1459255932Salfred			 struct mlx4_cmd_info *cmd)
1460255932Salfred{
1461255932Salfred	u32 qpn = (u32) vhcr->in_param & 0xffffffff;
1462255932Salfred	u8 port = vhcr->in_param >> 62;
1463255932Salfred	enum mlx4_steer_type steer = vhcr->in_modifier;
1464255932Salfred
1465272407Shselasky	/* Promiscuous unicast is not allowed in mfunc for VFs */
1466272407Shselasky	if ((slave != dev->caps.function) && (steer == MLX4_UC_STEER))
1467255932Salfred		return 0;
1468255932Salfred
1469255932Salfred	if (vhcr->op_modifier)
1470255932Salfred		return add_promisc_qp(dev, port, steer, qpn);
1471255932Salfred	else
1472255932Salfred		return remove_promisc_qp(dev, port, steer, qpn);
1473255932Salfred}
1474255932Salfred
1475255932Salfredstatic int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn,
1476255932Salfred			enum mlx4_steer_type steer, u8 add, u8 port)
1477255932Salfred{
1478255932Salfred	return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add,
1479255932Salfred			MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A,
1480255932Salfred			MLX4_CMD_WRAPPED);
1481255932Salfred}
1482255932Salfred
1483255932Salfredint mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
1484255932Salfred{
1485255932Salfred	if (mlx4_is_mfunc(dev))
1486255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port);
1487255932Salfred
1488255932Salfred	return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
1489255932Salfred}
1490255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add);
1491255932Salfred
1492255932Salfredint mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
1493255932Salfred{
1494255932Salfred	if (mlx4_is_mfunc(dev))
1495255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port);
1496255932Salfred
1497255932Salfred	return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
1498255932Salfred}
1499255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove);
1500255932Salfred
1501255932Salfredint mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
1502255932Salfred{
1503255932Salfred	if (mlx4_is_mfunc(dev))
1504255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port);
1505255932Salfred
1506255932Salfred	return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
1507255932Salfred}
1508255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add);
1509255932Salfred
1510255932Salfredint mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
1511255932Salfred{
1512255932Salfred	if (mlx4_is_mfunc(dev))
1513255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port);
1514255932Salfred
1515255932Salfred	return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
1516255932Salfred}
1517255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove);
1518255932Salfred
1519219820Sjeffint mlx4_init_mcg_table(struct mlx4_dev *dev)
1520219820Sjeff{
1521219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1522219820Sjeff	int err;
1523219820Sjeff
1524255932Salfred	/* No need for mcg_table when fw managed the mcg table*/
1525255932Salfred	if (dev->caps.steering_mode ==
1526255932Salfred	    MLX4_STEERING_MODE_DEVICE_MANAGED)
1527255932Salfred		return 0;
1528219820Sjeff	err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
1529219820Sjeff			       dev->caps.num_amgms - 1, 0, 0);
1530219820Sjeff	if (err)
1531219820Sjeff		return err;
1532219820Sjeff
1533219820Sjeff	mutex_init(&priv->mcg_table.mutex);
1534219820Sjeff
1535219820Sjeff	return 0;
1536219820Sjeff}
1537219820Sjeff
1538219820Sjeffvoid mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
1539219820Sjeff{
1540255932Salfred	if (dev->caps.steering_mode !=
1541255932Salfred	    MLX4_STEERING_MODE_DEVICE_MANAGED)
1542255932Salfred		mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
1543219820Sjeff}
1544