1219820Sjeff/*
2219820Sjeff * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
3272027Shselasky * 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>
35272027Shselasky#include <linux/etherdevice.h>
36219820Sjeff
37306486Shselasky#include <dev/mlx4/cmd.h>
38272027Shselasky#include <linux/module.h>
39279584Shselasky#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{
127272027Shselasky	struct mlx4_steer *s_steer;
128255932Salfred	struct mlx4_promisc_qp *pqp;
129255932Salfred
130272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
131272027Shselasky		return NULL;
132272027Shselasky
133272027Shselasky	s_steer = &mlx4_priv(dev)->steer[port - 1];
134272027Shselasky
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
161272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
162272027Shselasky		return -EINVAL;
163272027Shselasky
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
248272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
249272027Shselasky		return -EINVAL;
250272027Shselasky
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) {
272272027Shselasky		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
296272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
297272027Shselasky		return NULL;
298272027Shselasky
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
326329159Shselasky/* Returns true if all the QPs != tqpn contained in this entry
327329159Shselasky * are Promisc QPs. Returns false otherwise.
328272027Shselasky */
329272027Shselaskystatic bool promisc_steering_entry(struct mlx4_dev *dev, u8 port,
330329159Shselasky				   enum mlx4_steer_type steer,
331329159Shselasky				   unsigned int index, u32 tqpn,
332329159Shselasky				   u32 *members_count)
333255932Salfred{
334255932Salfred	struct mlx4_cmd_mailbox *mailbox;
335255932Salfred	struct mlx4_mgm *mgm;
336272027Shselasky	u32 m_count;
337255932Salfred	bool ret = false;
338255932Salfred	int i;
339255932Salfred
340272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
341272027Shselasky		return false;
342272027Shselasky
343255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
344255932Salfred	if (IS_ERR(mailbox))
345255932Salfred		return false;
346255932Salfred	mgm = mailbox->buf;
347255932Salfred
348255932Salfred	if (mlx4_READ_ENTRY(dev, index, mailbox))
349255932Salfred		goto out;
350272027Shselasky	m_count = be32_to_cpu(mgm->members_count) & 0xffffff;
351272027Shselasky	if (members_count)
352272027Shselasky		*members_count = m_count;
353272027Shselasky
354272027Shselasky	for (i = 0;  i < m_count; i++) {
355272027Shselasky		u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
356255932Salfred		if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) {
357255932Salfred			/* the qp is not promisc, the entry can't be removed */
358255932Salfred			goto out;
359255932Salfred		}
360255932Salfred	}
361272027Shselasky	ret = true;
362272027Shselaskyout:
363272027Shselasky	mlx4_free_cmd_mailbox(dev, mailbox);
364272027Shselasky	return ret;
365272027Shselasky}
366272027Shselasky
367272027Shselasky/* IF a steering entry contains only promisc QPs, it can be removed. */
368272027Shselaskystatic bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
369272027Shselasky				      enum mlx4_steer_type steer,
370272027Shselasky				      unsigned int index, u32 tqpn)
371272027Shselasky{
372272027Shselasky	struct mlx4_steer *s_steer;
373272027Shselasky	struct mlx4_steer_index *entry = NULL, *tmp_entry;
374272027Shselasky	u32 members_count;
375272027Shselasky	bool ret = false;
376272027Shselasky
377272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
378272027Shselasky		return NULL;
379272027Shselasky
380272027Shselasky	s_steer = &mlx4_priv(dev)->steer[port - 1];
381272027Shselasky
382329159Shselasky	if (!promisc_steering_entry(dev, port, steer, index,
383329159Shselasky				    tqpn, &members_count))
384272027Shselasky		goto out;
385272027Shselasky
386272027Shselasky	/* All the qps currently registered for this entry are promiscuous,
387255932Salfred	  * Checking for duplicates */
388255932Salfred	ret = true;
389255932Salfred	list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
390255932Salfred		if (entry->index == index) {
391329159Shselasky			if (list_empty(&entry->duplicates) ||
392329159Shselasky			    members_count == 1) {
393255932Salfred				struct mlx4_promisc_qp *pqp, *tmp_pqp;
394329159Shselasky				/* If there is only 1 entry in duplicates then
395255932Salfred				 * this is the QP we want to delete, going over
396255932Salfred				 * the list and deleting the entry.
397255932Salfred				 */
398255932Salfred				list_del(&entry->list);
399255932Salfred				list_for_each_entry_safe(pqp, tmp_pqp,
400255932Salfred							 &entry->duplicates,
401255932Salfred							 list) {
402255932Salfred					list_del(&pqp->list);
403255932Salfred					kfree(pqp);
404255932Salfred				}
405255932Salfred				kfree(entry);
406255932Salfred			} else {
407255932Salfred				/* This entry contains duplicates so it shouldn't be removed */
408255932Salfred				ret = false;
409255932Salfred				goto out;
410255932Salfred			}
411255932Salfred		}
412255932Salfred	}
413255932Salfred
414255932Salfredout:
415255932Salfred	return ret;
416255932Salfred}
417255932Salfred
418255932Salfredstatic int add_promisc_qp(struct mlx4_dev *dev, u8 port,
419255932Salfred			  enum mlx4_steer_type steer, u32 qpn)
420255932Salfred{
421255932Salfred	struct mlx4_steer *s_steer;
422255932Salfred	struct mlx4_cmd_mailbox *mailbox;
423255932Salfred	struct mlx4_mgm *mgm;
424255932Salfred	struct mlx4_steer_index *entry;
425255932Salfred	struct mlx4_promisc_qp *pqp;
426255932Salfred	struct mlx4_promisc_qp *dqp;
427255932Salfred	u32 members_count;
428255932Salfred	u32 prot;
429255932Salfred	int i;
430255932Salfred	bool found;
431255932Salfred	int err;
432255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
433255932Salfred
434272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
435272027Shselasky		return -EINVAL;
436272027Shselasky
437255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
438255932Salfred
439255932Salfred	mutex_lock(&priv->mcg_table.mutex);
440255932Salfred
441255932Salfred	if (get_promisc_qp(dev, port, steer, qpn)) {
442255932Salfred		err = 0;  /* Noting to do, already exists */
443255932Salfred		goto out_mutex;
444255932Salfred	}
445255932Salfred
446255932Salfred	pqp = kmalloc(sizeof *pqp, GFP_KERNEL);
447255932Salfred	if (!pqp) {
448255932Salfred		err = -ENOMEM;
449255932Salfred		goto out_mutex;
450255932Salfred	}
451255932Salfred	pqp->qpn = qpn;
452255932Salfred
453255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
454255932Salfred	if (IS_ERR(mailbox)) {
455255932Salfred		err = -ENOMEM;
456255932Salfred		goto out_alloc;
457255932Salfred	}
458255932Salfred	mgm = mailbox->buf;
459255932Salfred
460272027Shselasky	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
461329159Shselasky		/* The promisc QP needs to be added for each one of the steering
462329159Shselasky		 * entries. If it already exists, needs to be added as
463329159Shselasky		 * a duplicate for this entry.
464329159Shselasky		 */
465329159Shselasky		list_for_each_entry(entry,
466329159Shselasky				    &s_steer->steer_entries[steer],
467329159Shselasky				    list) {
468272027Shselasky			err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
469272027Shselasky			if (err)
470272027Shselasky				goto out_mailbox;
471255932Salfred
472329159Shselasky			members_count = be32_to_cpu(mgm->members_count) &
473329159Shselasky					0xffffff;
474272027Shselasky			prot = be32_to_cpu(mgm->members_count) >> 30;
475272027Shselasky			found = false;
476272027Shselasky			for (i = 0; i < members_count; i++) {
477329159Shselasky				if ((be32_to_cpu(mgm->qp[i]) &
478329159Shselasky				     MGM_QPN_MASK) == qpn) {
479329159Shselasky					/* Entry already exists.
480329159Shselasky					 * Add to duplicates.
481329159Shselasky					 */
482329159Shselasky					dqp = kmalloc(sizeof(*dqp), GFP_KERNEL);
483272027Shselasky					if (!dqp) {
484272027Shselasky						err = -ENOMEM;
485272027Shselasky						goto out_mailbox;
486272027Shselasky					}
487272027Shselasky					dqp->qpn = qpn;
488329159Shselasky					list_add_tail(&dqp->list,
489329159Shselasky						      &entry->duplicates);
490272027Shselasky					found = true;
491272027Shselasky				}
492272027Shselasky			}
493272027Shselasky			if (!found) {
494272027Shselasky				/* Need to add the qpn to mgm */
495329159Shselasky				if (members_count ==
496329159Shselasky				    dev->caps.num_qp_per_mgm) {
497272027Shselasky					/* entry is full */
498255932Salfred					err = -ENOMEM;
499255932Salfred					goto out_mailbox;
500255932Salfred				}
501329159Shselasky				mgm->qp[members_count++] =
502329159Shselasky					cpu_to_be32(qpn & MGM_QPN_MASK);
503329159Shselasky				mgm->members_count =
504329159Shselasky					cpu_to_be32(members_count |
505329159Shselasky						    (prot << 30));
506329159Shselasky				err = mlx4_WRITE_ENTRY(dev, entry->index,
507329159Shselasky						       mailbox);
508272027Shselasky				if (err)
509272027Shselasky					goto out_mailbox;
510255932Salfred			}
511255932Salfred		}
512255932Salfred	}
513255932Salfred
514255932Salfred	/* add the new qpn to list of promisc qps */
515255932Salfred	list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
516255932Salfred	/* now need to add all the promisc qps to default entry */
517255932Salfred	memset(mgm, 0, sizeof *mgm);
518255932Salfred	members_count = 0;
519255932Salfred	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) {
520255932Salfred		if (members_count == dev->caps.num_qp_per_mgm) {
521255932Salfred			/* entry is full */
522255932Salfred			err = -ENOMEM;
523255932Salfred			goto out_list;
524255932Salfred		}
525255932Salfred		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
526255932Salfred	}
527255932Salfred	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
528255932Salfred
529255932Salfred	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
530255932Salfred	if (err)
531255932Salfred		goto out_list;
532255932Salfred
533255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
534255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
535255932Salfred	return 0;
536255932Salfred
537255932Salfredout_list:
538255932Salfred	list_del(&pqp->list);
539255932Salfredout_mailbox:
540255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
541255932Salfredout_alloc:
542255932Salfred	kfree(pqp);
543255932Salfredout_mutex:
544255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
545255932Salfred	return err;
546255932Salfred}
547255932Salfred
548255932Salfredstatic int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
549255932Salfred			     enum mlx4_steer_type steer, u32 qpn)
550255932Salfred{
551255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
552255932Salfred	struct mlx4_steer *s_steer;
553255932Salfred	struct mlx4_cmd_mailbox *mailbox;
554255932Salfred	struct mlx4_mgm *mgm;
555272027Shselasky	struct mlx4_steer_index *entry, *tmp_entry;
556255932Salfred	struct mlx4_promisc_qp *pqp;
557255932Salfred	struct mlx4_promisc_qp *dqp;
558255932Salfred	u32 members_count;
559255932Salfred	bool found;
560255932Salfred	bool back_to_list = false;
561329159Shselasky	int i;
562255932Salfred	int err;
563255932Salfred
564272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
565272027Shselasky		return -EINVAL;
566272027Shselasky
567255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
568255932Salfred	mutex_lock(&priv->mcg_table.mutex);
569255932Salfred
570255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
571255932Salfred	if (unlikely(!pqp)) {
572255932Salfred		mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn);
573255932Salfred		/* nothing to do */
574255932Salfred		err = 0;
575255932Salfred		goto out_mutex;
576255932Salfred	}
577255932Salfred
578255932Salfred	/*remove from list of promisc qps */
579255932Salfred	list_del(&pqp->list);
580255932Salfred
581255932Salfred	/* set the default entry not to include the removed one */
582255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
583255932Salfred	if (IS_ERR(mailbox)) {
584255932Salfred		err = -ENOMEM;
585255932Salfred		back_to_list = true;
586255932Salfred		goto out_list;
587255932Salfred	}
588255932Salfred	mgm = mailbox->buf;
589255932Salfred	members_count = 0;
590255932Salfred	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
591255932Salfred		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
592255932Salfred	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
593255932Salfred
594255932Salfred	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
595255932Salfred	if (err)
596255932Salfred		goto out_mailbox;
597255932Salfred
598272027Shselasky	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
599329159Shselasky		/* Remove the QP from all the steering entries */
600329159Shselasky		list_for_each_entry_safe(entry, tmp_entry,
601329159Shselasky					 &s_steer->steer_entries[steer],
602329159Shselasky					 list) {
603272027Shselasky			found = false;
604272027Shselasky			list_for_each_entry(dqp, &entry->duplicates, list) {
605272027Shselasky				if (dqp->qpn == qpn) {
606272027Shselasky					found = true;
607255932Salfred					break;
608255932Salfred				}
609255932Salfred			}
610272027Shselasky			if (found) {
611329159Shselasky				/* A duplicate, no need to change the MGM,
612329159Shselasky				 * only update the duplicates list
613329159Shselasky				 */
614272027Shselasky				list_del(&dqp->list);
615272027Shselasky				kfree(dqp);
616272027Shselasky			} else {
617329159Shselasky				int loc = -1;
618329159Shselasky
619329159Shselasky				err = mlx4_READ_ENTRY(dev,
620329159Shselasky						      entry->index,
621329159Shselasky						      mailbox);
622329159Shselasky				if (err)
623329159Shselasky					goto out_mailbox;
624329159Shselasky				members_count =
625329159Shselasky					be32_to_cpu(mgm->members_count) &
626329159Shselasky					0xffffff;
627272027Shselasky				if (!members_count) {
628329159Shselasky					mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0. deleting entry...\n",
629329159Shselasky						  qpn, entry->index);
630272027Shselasky					list_del(&entry->list);
631272027Shselasky					kfree(entry);
632272027Shselasky					continue;
633272027Shselasky				}
634255932Salfred
635272027Shselasky				for (i = 0; i < members_count; ++i)
636329159Shselasky					if ((be32_to_cpu(mgm->qp[i]) &
637329159Shselasky					     MGM_QPN_MASK) == qpn) {
638272027Shselasky						loc = i;
639272027Shselasky						break;
640272027Shselasky					}
641255932Salfred
642272027Shselasky				if (loc < 0) {
643272027Shselasky					mlx4_err(dev, "QP %06x wasn't found in entry %d\n",
644272027Shselasky						 qpn, entry->index);
645272027Shselasky					err = -EINVAL;
646255932Salfred					goto out_mailbox;
647272027Shselasky				}
648272027Shselasky
649329159Shselasky				/* Copy the last QP in this MGM
650329159Shselasky				 * over removed QP
651329159Shselasky				 */
652272027Shselasky				mgm->qp[loc] = mgm->qp[members_count - 1];
653272027Shselasky				mgm->qp[members_count - 1] = 0;
654329159Shselasky				mgm->members_count =
655329159Shselasky					cpu_to_be32(--members_count |
656329159Shselasky						    (MLX4_PROT_ETH << 30));
657272027Shselasky
658329159Shselasky				err = mlx4_WRITE_ENTRY(dev,
659329159Shselasky						       entry->index,
660329159Shselasky						       mailbox);
661329159Shselasky				if (err)
662329159Shselasky					goto out_mailbox;
663272027Shselasky			}
664255932Salfred		}
665255932Salfred	}
666255932Salfred
667255932Salfredout_mailbox:
668255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
669255932Salfredout_list:
670255932Salfred	if (back_to_list)
671255932Salfred		list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
672255932Salfred	else
673255932Salfred		kfree(pqp);
674255932Salfredout_mutex:
675255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
676255932Salfred	return err;
677255932Salfred}
678255932Salfred
679255932Salfred/*
680219820Sjeff * Caller must hold MCG table semaphore.  gid and mgm parameters must
681219820Sjeff * be properly aligned for command interface.
682219820Sjeff *
683219820Sjeff *  Returns 0 unless a firmware command error occurs.
684219820Sjeff *
685219820Sjeff * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
686219820Sjeff * and *mgm holds MGM entry.
687219820Sjeff *
688219820Sjeff * if GID is found in AMGM, *index = index in AMGM, *prev = index of
689219820Sjeff * previous entry in hash chain and *mgm holds AMGM entry.
690219820Sjeff *
691219820Sjeff * If no AMGM exists for given gid, *index = -1, *prev = index of last
692219820Sjeff * entry in hash chain and *mgm holds end of hash chain.
693219820Sjeff */
694255932Salfredstatic int find_entry(struct mlx4_dev *dev, u8 port,
695255932Salfred		      u8 *gid, enum mlx4_protocol prot,
696255932Salfred		      struct mlx4_cmd_mailbox *mgm_mailbox,
697255932Salfred		      int *prev, int *index)
698219820Sjeff{
699219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
700219820Sjeff	struct mlx4_mgm *mgm = mgm_mailbox->buf;
701219820Sjeff	u8 *mgid;
702219820Sjeff	int err;
703255932Salfred	u16 hash;
704255932Salfred	u8 op_mod = (prot == MLX4_PROT_ETH) ?
705255932Salfred		!!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0;
706219820Sjeff
707219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
708219820Sjeff	if (IS_ERR(mailbox))
709219820Sjeff		return -ENOMEM;
710219820Sjeff	mgid = mailbox->buf;
711219820Sjeff
712219820Sjeff	memcpy(mgid, gid, 16);
713219820Sjeff
714255932Salfred	err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod);
715219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
716219820Sjeff	if (err)
717219820Sjeff		return err;
718219820Sjeff
719279584Shselasky	if (0) {
720279584Shselasky		mlx4_dbg(dev, "Hash for "GID_PRINT_FMT" is %04x\n",
721279584Shselasky		    GID_PRINT_ARGS(gid), hash);
722279584Shselasky	}
723219820Sjeff
724255932Salfred	*index = hash;
725219820Sjeff	*prev  = -1;
726219820Sjeff
727219820Sjeff	do {
728255932Salfred		err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox);
729219820Sjeff		if (err)
730219820Sjeff			return err;
731219820Sjeff
732255932Salfred		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
733255932Salfred			if (*index != hash) {
734329159Shselasky				mlx4_err(dev, "Found zero MGID in AMGM\n");
735219820Sjeff				err = -EINVAL;
736219820Sjeff			}
737219820Sjeff			return err;
738219820Sjeff		}
739219820Sjeff
740219820Sjeff		if (!memcmp(mgm->gid, gid, 16) &&
741255932Salfred		    be32_to_cpu(mgm->members_count) >> 30 == prot)
742219820Sjeff			return err;
743219820Sjeff
744219820Sjeff		*prev = *index;
745219820Sjeff		*index = be32_to_cpu(mgm->next_gid_index) >> 6;
746219820Sjeff	} while (*index);
747219820Sjeff
748219820Sjeff	*index = -1;
749219820Sjeff	return err;
750219820Sjeff}
751219820Sjeff
752272027Shselaskystatic const u8 __promisc_mode[] = {
753272027Shselasky	[MLX4_FS_REGULAR]   = 0x0,
754272027Shselasky	[MLX4_FS_ALL_DEFAULT] = 0x1,
755272027Shselasky	[MLX4_FS_MC_DEFAULT] = 0x3,
756329159Shselasky	[MLX4_FS_MIRROR_RX_PORT] = 0x4,
757329159Shselasky	[MLX4_FS_MIRROR_SX_PORT] = 0x5,
758329159Shselasky	[MLX4_FS_UC_SNIFFER] = 0x6,
759329159Shselasky	[MLX4_FS_MC_SNIFFER] = 0x7,
760272027Shselasky};
761272027Shselasky
762329159Shselaskyint mlx4_map_sw_to_hw_steering_mode(struct mlx4_dev *dev,
763329159Shselasky				    enum mlx4_net_trans_promisc_mode flow_type)
764272027Shselasky{
765329159Shselasky	if (flow_type >= MLX4_FS_MODE_NUM) {
766272027Shselasky		mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type);
767272027Shselasky		return -EINVAL;
768272027Shselasky	}
769272027Shselasky	return __promisc_mode[flow_type];
770272027Shselasky}
771329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_mode);
772272027Shselasky
773255932Salfredstatic void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,
774255932Salfred				  struct mlx4_net_trans_rule_hw_ctrl *hw)
775219820Sjeff{
776272027Shselasky	u8 flags = 0;
777255932Salfred
778272027Shselasky	flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0;
779272027Shselasky	flags |= ctrl->exclusive ? (1 << 2) : 0;
780272027Shselasky	flags |= ctrl->allow_loopback ? (1 << 3) : 0;
781255932Salfred
782272027Shselasky	hw->flags = flags;
783272027Shselasky	hw->type = __promisc_mode[ctrl->promisc_mode];
784272027Shselasky	hw->prio = cpu_to_be16(ctrl->priority);
785255932Salfred	hw->port = ctrl->port;
786255932Salfred	hw->qpn = cpu_to_be32(ctrl->qpn);
787255932Salfred}
788255932Salfred
789255932Salfredconst u16 __sw_id_hw[] = {
790255932Salfred	[MLX4_NET_TRANS_RULE_ID_ETH]     = 0xE001,
791255932Salfred	[MLX4_NET_TRANS_RULE_ID_IB]      = 0xE005,
792255932Salfred	[MLX4_NET_TRANS_RULE_ID_IPV6]    = 0xE003,
793255932Salfred	[MLX4_NET_TRANS_RULE_ID_IPV4]    = 0xE002,
794255932Salfred	[MLX4_NET_TRANS_RULE_ID_TCP]     = 0xE004,
795329159Shselasky	[MLX4_NET_TRANS_RULE_ID_UDP]     = 0xE006,
796329159Shselasky	[MLX4_NET_TRANS_RULE_ID_VXLAN]	 = 0xE008
797255932Salfred};
798255932Salfred
799329159Shselaskyint mlx4_map_sw_to_hw_steering_id(struct mlx4_dev *dev,
800329159Shselasky				  enum mlx4_net_trans_rule_id id)
801272027Shselasky{
802329159Shselasky	if (id >= MLX4_NET_TRANS_RULE_NUM) {
803272027Shselasky		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
804272027Shselasky		return -EINVAL;
805272027Shselasky	}
806272027Shselasky	return __sw_id_hw[id];
807272027Shselasky}
808329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_id);
809272027Shselasky
810272027Shselaskystatic const int __rule_hw_sz[] = {
811272027Shselasky	[MLX4_NET_TRANS_RULE_ID_ETH] =
812272027Shselasky		sizeof(struct mlx4_net_trans_rule_hw_eth),
813272027Shselasky	[MLX4_NET_TRANS_RULE_ID_IB] =
814272027Shselasky		sizeof(struct mlx4_net_trans_rule_hw_ib),
815272027Shselasky	[MLX4_NET_TRANS_RULE_ID_IPV6] = 0,
816272027Shselasky	[MLX4_NET_TRANS_RULE_ID_IPV4] =
817272027Shselasky		sizeof(struct mlx4_net_trans_rule_hw_ipv4),
818272027Shselasky	[MLX4_NET_TRANS_RULE_ID_TCP] =
819272027Shselasky		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),
820272027Shselasky	[MLX4_NET_TRANS_RULE_ID_UDP] =
821329159Shselasky		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),
822329159Shselasky	[MLX4_NET_TRANS_RULE_ID_VXLAN] =
823329159Shselasky		sizeof(struct mlx4_net_trans_rule_hw_vxlan)
824272027Shselasky};
825272027Shselasky
826329159Shselaskyint mlx4_hw_rule_sz(struct mlx4_dev *dev,
827272027Shselasky	       enum mlx4_net_trans_rule_id id)
828272027Shselasky{
829329159Shselasky	if (id >= MLX4_NET_TRANS_RULE_NUM) {
830272027Shselasky		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
831272027Shselasky		return -EINVAL;
832272027Shselasky	}
833272027Shselasky
834272027Shselasky	return __rule_hw_sz[id];
835272027Shselasky}
836329159ShselaskyEXPORT_SYMBOL_GPL(mlx4_hw_rule_sz);
837272027Shselasky
838255932Salfredstatic int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec,
839255932Salfred			    struct _rule_hw *rule_hw)
840255932Salfred{
841329159Shselasky	if (mlx4_hw_rule_sz(dev, spec->id) < 0)
842255932Salfred		return -EINVAL;
843329159Shselasky	memset(rule_hw, 0, mlx4_hw_rule_sz(dev, spec->id));
844255932Salfred	rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]);
845329159Shselasky	rule_hw->size = mlx4_hw_rule_sz(dev, spec->id) >> 2;
846255932Salfred
847255932Salfred	switch (spec->id) {
848255932Salfred	case MLX4_NET_TRANS_RULE_ID_ETH:
849255932Salfred		memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN);
850255932Salfred		memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk,
851255932Salfred		       ETH_ALEN);
852255932Salfred		memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN);
853255932Salfred		memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk,
854255932Salfred		       ETH_ALEN);
855255932Salfred		if (spec->eth.ether_type_enable) {
856255932Salfred			rule_hw->eth.ether_type_enable = 1;
857255932Salfred			rule_hw->eth.ether_type = spec->eth.ether_type;
858255932Salfred		}
859272027Shselasky		rule_hw->eth.vlan_tag = spec->eth.vlan_id;
860272027Shselasky		rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk;
861255932Salfred		break;
862255932Salfred
863255932Salfred	case MLX4_NET_TRANS_RULE_ID_IB:
864272027Shselasky		rule_hw->ib.l3_qpn = spec->ib.l3_qpn;
865255932Salfred		rule_hw->ib.qpn_mask = spec->ib.qpn_msk;
866255932Salfred		memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16);
867255932Salfred		memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16);
868255932Salfred		break;
869255932Salfred
870255932Salfred	case MLX4_NET_TRANS_RULE_ID_IPV6:
871255932Salfred		return -EOPNOTSUPP;
872255932Salfred
873255932Salfred	case MLX4_NET_TRANS_RULE_ID_IPV4:
874255932Salfred		rule_hw->ipv4.src_ip = spec->ipv4.src_ip;
875255932Salfred		rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk;
876255932Salfred		rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip;
877255932Salfred		rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk;
878255932Salfred		break;
879255932Salfred
880255932Salfred	case MLX4_NET_TRANS_RULE_ID_TCP:
881255932Salfred	case MLX4_NET_TRANS_RULE_ID_UDP:
882255932Salfred		rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port;
883255932Salfred		rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk;
884255932Salfred		rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port;
885255932Salfred		rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk;
886255932Salfred		break;
887255932Salfred
888329159Shselasky	case MLX4_NET_TRANS_RULE_ID_VXLAN:
889329159Shselasky		rule_hw->vxlan.vni =
890329159Shselasky			cpu_to_be32(be32_to_cpu(spec->vxlan.vni) << 8);
891329159Shselasky		rule_hw->vxlan.vni_mask =
892329159Shselasky			cpu_to_be32(be32_to_cpu(spec->vxlan.vni_mask) << 8);
893329159Shselasky		break;
894329159Shselasky
895255932Salfred	default:
896255932Salfred		return -EINVAL;
897255932Salfred	}
898255932Salfred
899255932Salfred	return __rule_hw_sz[spec->id];
900255932Salfred}
901255932Salfred
902255932Salfredstatic void mlx4_err_rule(struct mlx4_dev *dev, char *str,
903255932Salfred			  struct mlx4_net_trans_rule *rule)
904255932Salfred{
905255932Salfred#define BUF_SIZE 256
906255932Salfred	struct mlx4_spec_list *cur;
907255932Salfred	char buf[BUF_SIZE];
908255932Salfred	int len = 0;
909255932Salfred
910255932Salfred	mlx4_err(dev, "%s", str);
911255932Salfred	len += snprintf(buf + len, BUF_SIZE - len,
912255932Salfred			"port = %d prio = 0x%x qp = 0x%x ",
913255932Salfred			rule->port, rule->priority, rule->qpn);
914255932Salfred
915255932Salfred	list_for_each_entry(cur, &rule->list, list) {
916255932Salfred		switch (cur->id) {
917255932Salfred		case MLX4_NET_TRANS_RULE_ID_ETH:
918255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
919329159Shselasky					"dmac = 0x%02x%02x%02x%02x%02x%02x ",
920329159Shselasky					cur->eth.dst_mac[0], cur->eth.dst_mac[1],
921329159Shselasky					cur->eth.dst_mac[2], cur->eth.dst_mac[3],
922329159Shselasky					cur->eth.dst_mac[4], cur->eth.dst_mac[5]);
923255932Salfred			if (cur->eth.ether_type)
924255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
925255932Salfred						"ethertype = 0x%x ",
926255932Salfred						be16_to_cpu(cur->eth.ether_type));
927255932Salfred			if (cur->eth.vlan_id)
928255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
929255932Salfred						"vlan-id = %d ",
930255932Salfred						be16_to_cpu(cur->eth.vlan_id));
931255932Salfred			break;
932255932Salfred
933255932Salfred		case MLX4_NET_TRANS_RULE_ID_IPV4:
934255932Salfred			if (cur->ipv4.src_ip)
935255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
936255932Salfred						"src-ip = %pI4 ",
937255932Salfred						&cur->ipv4.src_ip);
938255932Salfred			if (cur->ipv4.dst_ip)
939255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
940255932Salfred						"dst-ip = %pI4 ",
941255932Salfred						&cur->ipv4.dst_ip);
942255932Salfred			break;
943255932Salfred
944255932Salfred		case MLX4_NET_TRANS_RULE_ID_TCP:
945255932Salfred		case MLX4_NET_TRANS_RULE_ID_UDP:
946255932Salfred			if (cur->tcp_udp.src_port)
947255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
948255932Salfred						"src-port = %d ",
949255932Salfred						be16_to_cpu(cur->tcp_udp.src_port));
950255932Salfred			if (cur->tcp_udp.dst_port)
951255932Salfred				len += snprintf(buf + len, BUF_SIZE - len,
952255932Salfred						"dst-port = %d ",
953255932Salfred						be16_to_cpu(cur->tcp_udp.dst_port));
954255932Salfred			break;
955255932Salfred
956255932Salfred		case MLX4_NET_TRANS_RULE_ID_IB:
957255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
958279584Shselasky					"dst-gid = "GID_PRINT_FMT"\n",
959279584Shselasky					GID_PRINT_ARGS(cur->ib.dst_gid));
960255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
961279584Shselasky					"dst-gid-mask = "GID_PRINT_FMT"\n",
962279584Shselasky					GID_PRINT_ARGS(cur->ib.dst_gid_msk));
963255932Salfred			break;
964255932Salfred
965329159Shselasky		case MLX4_NET_TRANS_RULE_ID_VXLAN:
966329159Shselasky			len += snprintf(buf + len, BUF_SIZE - len,
967329159Shselasky					"VNID = %d ", be32_to_cpu(cur->vxlan.vni));
968329159Shselasky			break;
969255932Salfred		case MLX4_NET_TRANS_RULE_ID_IPV6:
970255932Salfred			break;
971255932Salfred
972255932Salfred		default:
973255932Salfred			break;
974255932Salfred		}
975255932Salfred	}
976255932Salfred	len += snprintf(buf + len, BUF_SIZE - len, "\n");
977255932Salfred	mlx4_err(dev, "%s", buf);
978255932Salfred
979255932Salfred	if (len >= BUF_SIZE)
980329159Shselasky		mlx4_err(dev, "Network rule error message was truncated, print buffer is too small\n");
981255932Salfred}
982255932Salfred
983255932Salfredint mlx4_flow_attach(struct mlx4_dev *dev,
984255932Salfred		     struct mlx4_net_trans_rule *rule, u64 *reg_id)
985255932Salfred{
986255932Salfred	struct mlx4_cmd_mailbox *mailbox;
987255932Salfred	struct mlx4_spec_list *cur;
988255932Salfred	u32 size = 0;
989255932Salfred	int ret;
990255932Salfred
991255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
992255932Salfred	if (IS_ERR(mailbox))
993255932Salfred		return PTR_ERR(mailbox);
994255932Salfred
995255932Salfred	trans_rule_ctrl_to_hw(rule, mailbox->buf);
996255932Salfred
997255932Salfred	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
998255932Salfred
999255932Salfred	list_for_each_entry(cur, &rule->list, list) {
1000255932Salfred		ret = parse_trans_rule(dev, cur, mailbox->buf + size);
1001255932Salfred		if (ret < 0) {
1002255932Salfred			mlx4_free_cmd_mailbox(dev, mailbox);
1003329159Shselasky			return ret;
1004255932Salfred		}
1005255932Salfred		size += ret;
1006255932Salfred	}
1007255932Salfred
1008255932Salfred	ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);
1009329159Shselasky	if (ret == -ENOMEM) {
1010255932Salfred		mlx4_err_rule(dev,
1011329159Shselasky			      "mcg table is full. Fail to register network rule\n",
1012255932Salfred			      rule);
1013329159Shselasky	} else if (ret) {
1014329159Shselasky		if (ret == -ENXIO) {
1015329159Shselasky			if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
1016329159Shselasky				mlx4_err_rule(dev,
1017329159Shselasky					      "DMFS is not enabled, "
1018329159Shselasky					      "failed to register network rule.\n",
1019329159Shselasky					      rule);
1020329159Shselasky			else
1021329159Shselasky				mlx4_err_rule(dev,
1022329159Shselasky					      "Rule exceeds the dmfs_high_rate_mode limitations, "
1023329159Shselasky					      "failed to register network rule.\n",
1024329159Shselasky					      rule);
1025255932Salfred
1026329159Shselasky		} else {
1027329159Shselasky			mlx4_err_rule(dev, "Fail to register network rule.\n", rule);
1028329159Shselasky		}
1029329159Shselasky	}
1030329159Shselasky
1031255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1032255932Salfred
1033255932Salfred	return ret;
1034255932Salfred}
1035255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_attach);
1036255932Salfred
1037255932Salfredint mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id)
1038255932Salfred{
1039255932Salfred	int err;
1040255932Salfred
1041255932Salfred	err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id);
1042255932Salfred	if (err)
1043255932Salfred		mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n",
1044272027Shselasky			 (unsigned long long)reg_id);
1045255932Salfred	return err;
1046255932Salfred}
1047255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_detach);
1048255932Salfred
1049329159Shselaskyint mlx4_tunnel_steer_add(struct mlx4_dev *dev, unsigned char *addr,
1050329159Shselasky			  int port, int qpn, u16 prio, u64 *reg_id)
1051255932Salfred{
1052255932Salfred	int err;
1053329159Shselasky	struct mlx4_spec_list spec_eth_outer = { {NULL} };
1054329159Shselasky	struct mlx4_spec_list spec_vxlan     = { {NULL} };
1055329159Shselasky	struct mlx4_spec_list spec_eth_inner = { {NULL} };
1056329159Shselasky
1057329159Shselasky	struct mlx4_net_trans_rule rule = {
1058329159Shselasky		.queue_mode = MLX4_NET_TRANS_Q_FIFO,
1059329159Shselasky		.exclusive = 0,
1060329159Shselasky		.allow_loopback = 1,
1061329159Shselasky		.promisc_mode = MLX4_FS_REGULAR,
1062329159Shselasky	};
1063329159Shselasky
1064329159Shselasky	__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
1065329159Shselasky
1066329159Shselasky	rule.port = port;
1067329159Shselasky	rule.qpn = qpn;
1068329159Shselasky	rule.priority = prio;
1069329159Shselasky	INIT_LIST_HEAD(&rule.list);
1070329159Shselasky
1071329159Shselasky	spec_eth_outer.id = MLX4_NET_TRANS_RULE_ID_ETH;
1072329159Shselasky	memcpy(spec_eth_outer.eth.dst_mac, addr, ETH_ALEN);
1073329159Shselasky	memcpy(spec_eth_outer.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
1074329159Shselasky
1075329159Shselasky	spec_vxlan.id = MLX4_NET_TRANS_RULE_ID_VXLAN;    /* any vxlan header */
1076329159Shselasky	spec_eth_inner.id = MLX4_NET_TRANS_RULE_ID_ETH;	 /* any inner eth header */
1077329159Shselasky
1078329159Shselasky	list_add_tail(&spec_eth_outer.list, &rule.list);
1079329159Shselasky	list_add_tail(&spec_vxlan.list,     &rule.list);
1080329159Shselasky	list_add_tail(&spec_eth_inner.list, &rule.list);
1081329159Shselasky
1082329159Shselasky	err = mlx4_flow_attach(dev, &rule, reg_id);
1083329159Shselasky	return err;
1084329159Shselasky}
1085329159ShselaskyEXPORT_SYMBOL(mlx4_tunnel_steer_add);
1086329159Shselasky
1087329159Shselaskyint mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn,
1088329159Shselasky				      u32 max_range_qpn)
1089329159Shselasky{
1090329159Shselasky	int err;
1091255932Salfred	u64 in_param;
1092255932Salfred
1093255932Salfred	in_param = ((u64) min_range_qpn) << 32;
1094255932Salfred	in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF;
1095255932Salfred
1096255932Salfred	err = mlx4_cmd(dev, in_param, 0, 0,
1097255932Salfred			MLX4_FLOW_STEERING_IB_UC_QP_RANGE,
1098255932Salfred			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1099255932Salfred
1100255932Salfred	return err;
1101255932Salfred}
1102255932SalfredEXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE);
1103255932Salfred
1104255932Salfredint mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1105255932Salfred			  int block_mcast_loopback, enum mlx4_protocol prot,
1106255932Salfred			  enum mlx4_steer_type steer)
1107255932Salfred{
1108219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1109219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1110219820Sjeff	struct mlx4_mgm *mgm;
1111219820Sjeff	u32 members_count;
1112329159Shselasky	int index = -1, prev;
1113219820Sjeff	int link = 0;
1114219820Sjeff	int i;
1115219820Sjeff	int err;
1116255932Salfred	u8 port = gid[5];
1117255932Salfred	u8 new_entry = 0;
1118219820Sjeff
1119219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1120219820Sjeff	if (IS_ERR(mailbox))
1121219820Sjeff		return PTR_ERR(mailbox);
1122219820Sjeff	mgm = mailbox->buf;
1123219820Sjeff
1124219820Sjeff	mutex_lock(&priv->mcg_table.mutex);
1125255932Salfred	err = find_entry(dev, port, gid, prot,
1126255932Salfred			 mailbox, &prev, &index);
1127219820Sjeff	if (err)
1128219820Sjeff		goto out;
1129219820Sjeff
1130219820Sjeff	if (index != -1) {
1131255932Salfred		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
1132255932Salfred			new_entry = 1;
1133219820Sjeff			memcpy(mgm->gid, gid, 16);
1134255932Salfred		}
1135219820Sjeff	} else {
1136219820Sjeff		link = 1;
1137219820Sjeff
1138219820Sjeff		index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
1139219820Sjeff		if (index == -1) {
1140219820Sjeff			mlx4_err(dev, "No AMGM entries left\n");
1141219820Sjeff			err = -ENOMEM;
1142219820Sjeff			goto out;
1143219820Sjeff		}
1144219820Sjeff		index += dev->caps.num_mgms;
1145219820Sjeff
1146255932Salfred		new_entry = 1;
1147219820Sjeff		memset(mgm, 0, sizeof *mgm);
1148219820Sjeff		memcpy(mgm->gid, gid, 16);
1149219820Sjeff	}
1150219820Sjeff
1151219820Sjeff	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
1152255932Salfred	if (members_count == dev->caps.num_qp_per_mgm) {
1153329159Shselasky		mlx4_err(dev, "MGM at index %x is full\n", index);
1154219820Sjeff		err = -ENOMEM;
1155219820Sjeff		goto out;
1156219820Sjeff	}
1157219820Sjeff
1158219820Sjeff	for (i = 0; i < members_count; ++i)
1159219820Sjeff		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
1160219820Sjeff			mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
1161219820Sjeff			err = 0;
1162219820Sjeff			goto out;
1163219820Sjeff		}
1164219820Sjeff
1165329159Shselasky	if (block_mcast_loopback)
1166329159Shselasky		mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
1167329159Shselasky						       (1U << MGM_BLCK_LB_BIT));
1168329159Shselasky	else
1169329159Shselasky		mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);
1170219820Sjeff
1171255932Salfred	mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30);
1172219820Sjeff
1173255932Salfred	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1174219820Sjeff	if (err)
1175219820Sjeff		goto out;
1176219820Sjeff
1177219820Sjeff	if (!link)
1178329159Shselasky		goto out;
1179219820Sjeff
1180255932Salfred	err = mlx4_READ_ENTRY(dev, prev, mailbox);
1181219820Sjeff	if (err)
1182219820Sjeff		goto out;
1183219820Sjeff
1184219820Sjeff	mgm->next_gid_index = cpu_to_be32(index << 6);
1185219820Sjeff
1186255932Salfred	err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
1187219820Sjeff	if (err)
1188219820Sjeff		goto out;
1189219820Sjeff
1190329159Shselaskyout:
1191329159Shselasky	if (prot == MLX4_PROT_ETH && index != -1) {
1192255932Salfred		/* manage the steering entry for promisc mode */
1193255932Salfred		if (new_entry)
1194329159Shselasky			err = new_steering_entry(dev, port, steer,
1195329159Shselasky						 index, qp->qpn);
1196255932Salfred		else
1197329159Shselasky			err = existing_steering_entry(dev, port, steer,
1198329159Shselasky						      index, qp->qpn);
1199255932Salfred	}
1200219820Sjeff	if (err && link && index != -1) {
1201219820Sjeff		if (index < dev->caps.num_mgms)
1202329159Shselasky			mlx4_warn(dev, "Got AMGM index %d < %d\n",
1203219820Sjeff				  index, dev->caps.num_mgms);
1204219820Sjeff		else
1205219820Sjeff			mlx4_bitmap_free(&priv->mcg_table.bitmap,
1206272027Shselasky					 index - dev->caps.num_mgms, MLX4_USE_RR);
1207219820Sjeff	}
1208219820Sjeff	mutex_unlock(&priv->mcg_table.mutex);
1209219820Sjeff
1210219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1211219820Sjeff	return err;
1212219820Sjeff}
1213219820Sjeff
1214255932Salfredint mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1215255932Salfred			  enum mlx4_protocol prot, enum mlx4_steer_type steer)
1216219820Sjeff{
1217219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1218219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1219219820Sjeff	struct mlx4_mgm *mgm;
1220219820Sjeff	u32 members_count;
1221219820Sjeff	int prev, index;
1222255932Salfred	int i, loc = -1;
1223219820Sjeff	int err;
1224255932Salfred	u8 port = gid[5];
1225255932Salfred	bool removed_entry = false;
1226219820Sjeff
1227219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1228219820Sjeff	if (IS_ERR(mailbox))
1229219820Sjeff		return PTR_ERR(mailbox);
1230219820Sjeff	mgm = mailbox->buf;
1231219820Sjeff
1232219820Sjeff	mutex_lock(&priv->mcg_table.mutex);
1233219820Sjeff
1234255932Salfred	err = find_entry(dev, port, gid, prot,
1235255932Salfred			 mailbox, &prev, &index);
1236219820Sjeff	if (err)
1237219820Sjeff		goto out;
1238219820Sjeff
1239219820Sjeff	if (index == -1) {
1240279584Shselasky		mlx4_err(dev, "MGID "GID_PRINT_FMT" not found\n",
1241279584Shselasky		    GID_PRINT_ARGS(gid));
1242219820Sjeff		err = -EINVAL;
1243219820Sjeff		goto out;
1244219820Sjeff	}
1245219820Sjeff
1246329159Shselasky	/* If this QP is also a promisc QP, it shouldn't be removed only if
1247329159Shselasky	 * at least one none promisc QP is also attached to this MCG
1248329159Shselasky	 */
1249255932Salfred	if (prot == MLX4_PROT_ETH &&
1250272027Shselasky	    check_duplicate_entry(dev, port, steer, index, qp->qpn) &&
1251272027Shselasky	    !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL))
1252272027Shselasky			goto out;
1253255932Salfred
1254219820Sjeff	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
1255255932Salfred	for (i = 0; i < members_count; ++i)
1256255932Salfred		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
1257219820Sjeff			loc = i;
1258255932Salfred			break;
1259255932Salfred		}
1260219820Sjeff
1261219820Sjeff	if (loc == -1) {
1262219820Sjeff		mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
1263219820Sjeff		err = -EINVAL;
1264219820Sjeff		goto out;
1265219820Sjeff	}
1266219820Sjeff
1267255932Salfred	/* copy the last QP in this MGM over removed QP */
1268255932Salfred	mgm->qp[loc] = mgm->qp[members_count - 1];
1269255932Salfred	mgm->qp[members_count - 1] = 0;
1270255932Salfred	mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30);
1271219820Sjeff
1272255932Salfred	if (prot == MLX4_PROT_ETH)
1273255932Salfred		removed_entry = can_remove_steering_entry(dev, port, steer,
1274255932Salfred								index, qp->qpn);
1275255932Salfred	if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) {
1276255932Salfred		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1277219820Sjeff		goto out;
1278219820Sjeff	}
1279219820Sjeff
1280255932Salfred	/* We are going to delete the entry, members count should be 0 */
1281255932Salfred	mgm->members_count = cpu_to_be32((u32) prot << 30);
1282255932Salfred
1283219820Sjeff	if (prev == -1) {
1284219820Sjeff		/* Remove entry from MGM */
1285219820Sjeff		int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
1286219820Sjeff		if (amgm_index) {
1287255932Salfred			err = mlx4_READ_ENTRY(dev, amgm_index, mailbox);
1288219820Sjeff			if (err)
1289219820Sjeff				goto out;
1290219820Sjeff		} else
1291219820Sjeff			memset(mgm->gid, 0, 16);
1292219820Sjeff
1293255932Salfred		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1294219820Sjeff		if (err)
1295219820Sjeff			goto out;
1296219820Sjeff
1297219820Sjeff		if (amgm_index) {
1298219820Sjeff			if (amgm_index < dev->caps.num_mgms)
1299329159Shselasky				mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d\n",
1300219820Sjeff					  index, amgm_index, dev->caps.num_mgms);
1301219820Sjeff			else
1302219820Sjeff				mlx4_bitmap_free(&priv->mcg_table.bitmap,
1303272027Shselasky						 amgm_index - dev->caps.num_mgms, MLX4_USE_RR);
1304219820Sjeff		}
1305219820Sjeff	} else {
1306219820Sjeff		/* Remove entry from AMGM */
1307219820Sjeff		int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
1308255932Salfred		err = mlx4_READ_ENTRY(dev, prev, mailbox);
1309219820Sjeff		if (err)
1310219820Sjeff			goto out;
1311219820Sjeff
1312219820Sjeff		mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
1313219820Sjeff
1314255932Salfred		err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
1315219820Sjeff		if (err)
1316219820Sjeff			goto out;
1317219820Sjeff
1318219820Sjeff		if (index < dev->caps.num_mgms)
1319329159Shselasky			mlx4_warn(dev, "entry %d had next AMGM index %d < %d\n",
1320219820Sjeff				  prev, index, dev->caps.num_mgms);
1321219820Sjeff		else
1322219820Sjeff			mlx4_bitmap_free(&priv->mcg_table.bitmap,
1323272027Shselasky					 index - dev->caps.num_mgms, MLX4_USE_RR);
1324219820Sjeff	}
1325219820Sjeff
1326219820Sjeffout:
1327219820Sjeff	mutex_unlock(&priv->mcg_table.mutex);
1328219820Sjeff
1329219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1330329159Shselasky	if (err && dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
1331329159Shselasky		/* In case device is under an error, return success as a closing command */
1332329159Shselasky		err = 0;
1333219820Sjeff	return err;
1334219820Sjeff}
1335255932Salfred
1336255932Salfredstatic int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,
1337255932Salfred			  u8 gid[16], u8 attach, u8 block_loopback,
1338255932Salfred			  enum mlx4_protocol prot)
1339255932Salfred{
1340255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1341255932Salfred	int err = 0;
1342255932Salfred	int qpn;
1343255932Salfred
1344255932Salfred	if (!mlx4_is_mfunc(dev))
1345255932Salfred		return -EBADF;
1346255932Salfred
1347255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1348255932Salfred	if (IS_ERR(mailbox))
1349255932Salfred		return PTR_ERR(mailbox);
1350255932Salfred
1351255932Salfred	memcpy(mailbox->buf, gid, 16);
1352255932Salfred	qpn = qp->qpn;
1353255932Salfred	qpn |= (prot << 28);
1354255932Salfred	if (attach && block_loopback)
1355272027Shselasky		qpn |= (1 << 31);
1356255932Salfred
1357255932Salfred	err = mlx4_cmd(dev, mailbox->dma, qpn, attach,
1358255932Salfred		       MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A,
1359255932Salfred		       MLX4_CMD_WRAPPED);
1360255932Salfred
1361255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1362329159Shselasky	if (err && !attach &&
1363329159Shselasky	    dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
1364329159Shselasky		err = 0;
1365255932Salfred	return err;
1366255932Salfred}
1367255932Salfred
1368272027Shselaskyint mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,
1369272027Shselasky			      u8 gid[16], u8 port,
1370272027Shselasky			      int block_mcast_loopback,
1371272027Shselasky			      enum mlx4_protocol prot, u64 *reg_id)
1372255932Salfred{
1373255932Salfred		struct mlx4_spec_list spec = { {NULL} };
1374255932Salfred		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
1375255932Salfred
1376255932Salfred		struct mlx4_net_trans_rule rule = {
1377255932Salfred			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
1378255932Salfred			.exclusive = 0,
1379255932Salfred			.promisc_mode = MLX4_FS_REGULAR,
1380255932Salfred			.priority = MLX4_DOMAIN_NIC,
1381255932Salfred		};
1382255932Salfred
1383255932Salfred		rule.allow_loopback = !block_mcast_loopback;
1384255932Salfred		rule.port = port;
1385255932Salfred		rule.qpn = qp->qpn;
1386255932Salfred		INIT_LIST_HEAD(&rule.list);
1387255932Salfred
1388255932Salfred		switch (prot) {
1389255932Salfred		case MLX4_PROT_ETH:
1390255932Salfred			spec.id = MLX4_NET_TRANS_RULE_ID_ETH;
1391255932Salfred			memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN);
1392255932Salfred			memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
1393255932Salfred			break;
1394255932Salfred
1395255932Salfred		case MLX4_PROT_IB_IPV6:
1396255932Salfred			spec.id = MLX4_NET_TRANS_RULE_ID_IB;
1397255932Salfred			memcpy(spec.ib.dst_gid, gid, 16);
1398255932Salfred			memset(&spec.ib.dst_gid_msk, 0xff, 16);
1399255932Salfred			break;
1400255932Salfred		default:
1401255932Salfred			return -EINVAL;
1402255932Salfred		}
1403255932Salfred		list_add_tail(&spec.list, &rule.list);
1404255932Salfred
1405255932Salfred		return mlx4_flow_attach(dev, &rule, reg_id);
1406272027Shselasky}
1407255932Salfred
1408272027Shselaskyint mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1409272027Shselasky			  u8 port, int block_mcast_loopback,
1410272027Shselasky			  enum mlx4_protocol prot, u64 *reg_id)
1411272027Shselasky{
1412272027Shselasky	switch (dev->caps.steering_mode) {
1413272027Shselasky	case MLX4_STEERING_MODE_A0:
1414272027Shselasky		if (prot == MLX4_PROT_ETH)
1415272027Shselasky			return 0;
1416272027Shselasky
1417272027Shselasky	case MLX4_STEERING_MODE_B0:
1418272027Shselasky		if (prot == MLX4_PROT_ETH)
1419329159Shselasky			gid[7] |= (MLX4_MC_STEER << 1);
1420272027Shselasky
1421272027Shselasky		if (mlx4_is_mfunc(dev))
1422272027Shselasky			return mlx4_QP_ATTACH(dev, qp, gid, 1,
1423272027Shselasky					      block_mcast_loopback, prot);
1424272027Shselasky		return mlx4_qp_attach_common(dev, qp, gid,
1425272027Shselasky					     block_mcast_loopback, prot,
1426272027Shselasky					     MLX4_MC_STEER);
1427272027Shselasky
1428272027Shselasky	case MLX4_STEERING_MODE_DEVICE_MANAGED:
1429272027Shselasky		return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
1430272027Shselasky						 block_mcast_loopback,
1431272027Shselasky						 prot, reg_id);
1432255932Salfred	default:
1433255932Salfred		return -EINVAL;
1434255932Salfred	}
1435255932Salfred}
1436255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_attach);
1437255932Salfred
1438255932Salfredint mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1439255932Salfred			  enum mlx4_protocol prot, u64 reg_id)
1440255932Salfred{
1441255932Salfred	switch (dev->caps.steering_mode) {
1442255932Salfred	case MLX4_STEERING_MODE_A0:
1443255932Salfred		if (prot == MLX4_PROT_ETH)
1444255932Salfred			return 0;
1445255932Salfred
1446255932Salfred	case MLX4_STEERING_MODE_B0:
1447255932Salfred		if (prot == MLX4_PROT_ETH)
1448329159Shselasky			gid[7] |= (MLX4_MC_STEER << 1);
1449255932Salfred
1450255932Salfred		if (mlx4_is_mfunc(dev))
1451255932Salfred			return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
1452255932Salfred
1453255932Salfred		return mlx4_qp_detach_common(dev, qp, gid, prot,
1454255932Salfred					     MLX4_MC_STEER);
1455255932Salfred
1456255932Salfred	case MLX4_STEERING_MODE_DEVICE_MANAGED:
1457255932Salfred		return mlx4_flow_detach(dev, reg_id);
1458255932Salfred
1459255932Salfred	default:
1460255932Salfred		return -EINVAL;
1461255932Salfred	}
1462255932Salfred}
1463219820SjeffEXPORT_SYMBOL_GPL(mlx4_multicast_detach);
1464219820Sjeff
1465255932Salfredint mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
1466255932Salfred				u32 qpn, enum mlx4_net_trans_promisc_mode mode)
1467255932Salfred{
1468329159Shselasky	struct mlx4_net_trans_rule rule = {
1469329159Shselasky		.queue_mode = MLX4_NET_TRANS_Q_FIFO,
1470329159Shselasky		.exclusive = 0,
1471329159Shselasky		.allow_loopback = 1,
1472329159Shselasky	};
1473329159Shselasky
1474255932Salfred	u64 *regid_p;
1475255932Salfred
1476255932Salfred	switch (mode) {
1477255932Salfred	case MLX4_FS_ALL_DEFAULT:
1478255932Salfred		regid_p = &dev->regid_promisc_array[port];
1479255932Salfred		break;
1480255932Salfred	case MLX4_FS_MC_DEFAULT:
1481255932Salfred		regid_p = &dev->regid_allmulti_array[port];
1482255932Salfred		break;
1483255932Salfred	default:
1484255932Salfred		return -1;
1485255932Salfred	}
1486255932Salfred
1487255932Salfred	if (*regid_p != 0)
1488255932Salfred		return -1;
1489255932Salfred
1490255932Salfred	rule.promisc_mode = mode;
1491255932Salfred	rule.port = port;
1492255932Salfred	rule.qpn = qpn;
1493255932Salfred	INIT_LIST_HEAD(&rule.list);
1494255932Salfred	mlx4_err(dev, "going promisc on %x\n", port);
1495255932Salfred
1496255932Salfred	return  mlx4_flow_attach(dev, &rule, regid_p);
1497255932Salfred}
1498255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add);
1499255932Salfred
1500255932Salfredint mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port,
1501255932Salfred				   enum mlx4_net_trans_promisc_mode mode)
1502255932Salfred{
1503255932Salfred	int ret;
1504255932Salfred	u64 *regid_p;
1505255932Salfred
1506255932Salfred	switch (mode) {
1507255932Salfred	case MLX4_FS_ALL_DEFAULT:
1508255932Salfred		regid_p = &dev->regid_promisc_array[port];
1509255932Salfred		break;
1510255932Salfred	case MLX4_FS_MC_DEFAULT:
1511255932Salfred		regid_p = &dev->regid_allmulti_array[port];
1512255932Salfred		break;
1513255932Salfred	default:
1514255932Salfred		return -1;
1515255932Salfred	}
1516255932Salfred
1517255932Salfred	if (*regid_p == 0)
1518255932Salfred		return -1;
1519255932Salfred
1520255932Salfred	ret =  mlx4_flow_detach(dev, *regid_p);
1521255932Salfred	if (ret == 0)
1522255932Salfred		*regid_p = 0;
1523255932Salfred
1524255932Salfred	return ret;
1525255932Salfred}
1526255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove);
1527255932Salfred
1528255932Salfredint mlx4_unicast_attach(struct mlx4_dev *dev,
1529255932Salfred			struct mlx4_qp *qp, u8 gid[16],
1530255932Salfred			int block_mcast_loopback, enum mlx4_protocol prot)
1531255932Salfred{
1532255932Salfred	if (prot == MLX4_PROT_ETH)
1533255932Salfred		gid[7] |= (MLX4_UC_STEER << 1);
1534255932Salfred
1535255932Salfred	if (mlx4_is_mfunc(dev))
1536255932Salfred		return mlx4_QP_ATTACH(dev, qp, gid, 1,
1537255932Salfred					block_mcast_loopback, prot);
1538255932Salfred
1539255932Salfred	return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback,
1540255932Salfred					prot, MLX4_UC_STEER);
1541255932Salfred}
1542255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_attach);
1543255932Salfred
1544255932Salfredint mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
1545255932Salfred			       u8 gid[16], enum mlx4_protocol prot)
1546255932Salfred{
1547255932Salfred	if (prot == MLX4_PROT_ETH)
1548255932Salfred		gid[7] |= (MLX4_UC_STEER << 1);
1549255932Salfred
1550255932Salfred	if (mlx4_is_mfunc(dev))
1551255932Salfred		return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
1552255932Salfred
1553255932Salfred	return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER);
1554255932Salfred}
1555255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_detach);
1556255932Salfred
1557255932Salfredint mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave,
1558255932Salfred			 struct mlx4_vhcr *vhcr,
1559255932Salfred			 struct mlx4_cmd_mailbox *inbox,
1560255932Salfred			 struct mlx4_cmd_mailbox *outbox,
1561255932Salfred			 struct mlx4_cmd_info *cmd)
1562255932Salfred{
1563255932Salfred	u32 qpn = (u32) vhcr->in_param & 0xffffffff;
1564329159Shselasky	int port = mlx4_slave_convert_port(dev, slave, vhcr->in_param >> 62);
1565255932Salfred	enum mlx4_steer_type steer = vhcr->in_modifier;
1566255932Salfred
1567329159Shselasky	if (port < 0)
1568329159Shselasky		return -EINVAL;
1569329159Shselasky
1570329159Shselasky	/* Promiscuous unicast is not allowed in mfunc */
1571329159Shselasky	if (mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)
1572255932Salfred		return 0;
1573255932Salfred
1574255932Salfred	if (vhcr->op_modifier)
1575255932Salfred		return add_promisc_qp(dev, port, steer, qpn);
1576255932Salfred	else
1577255932Salfred		return remove_promisc_qp(dev, port, steer, qpn);
1578255932Salfred}
1579255932Salfred
1580255932Salfredstatic int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn,
1581255932Salfred			enum mlx4_steer_type steer, u8 add, u8 port)
1582255932Salfred{
1583255932Salfred	return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add,
1584255932Salfred			MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A,
1585255932Salfred			MLX4_CMD_WRAPPED);
1586255932Salfred}
1587255932Salfred
1588255932Salfredint mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
1589255932Salfred{
1590255932Salfred	if (mlx4_is_mfunc(dev))
1591255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port);
1592255932Salfred
1593255932Salfred	return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
1594255932Salfred}
1595255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add);
1596255932Salfred
1597255932Salfredint mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
1598255932Salfred{
1599255932Salfred	if (mlx4_is_mfunc(dev))
1600255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port);
1601255932Salfred
1602255932Salfred	return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
1603255932Salfred}
1604255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove);
1605255932Salfred
1606255932Salfredint mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
1607255932Salfred{
1608255932Salfred	if (mlx4_is_mfunc(dev))
1609255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port);
1610255932Salfred
1611255932Salfred	return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
1612255932Salfred}
1613255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add);
1614255932Salfred
1615255932Salfredint mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
1616255932Salfred{
1617255932Salfred	if (mlx4_is_mfunc(dev))
1618255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port);
1619255932Salfred
1620255932Salfred	return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
1621255932Salfred}
1622255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove);
1623255932Salfred
1624219820Sjeffint mlx4_init_mcg_table(struct mlx4_dev *dev)
1625219820Sjeff{
1626219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1627219820Sjeff	int err;
1628219820Sjeff
1629255932Salfred	/* No need for mcg_table when fw managed the mcg table*/
1630255932Salfred	if (dev->caps.steering_mode ==
1631255932Salfred	    MLX4_STEERING_MODE_DEVICE_MANAGED)
1632255932Salfred		return 0;
1633219820Sjeff	err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
1634219820Sjeff			       dev->caps.num_amgms - 1, 0, 0);
1635219820Sjeff	if (err)
1636219820Sjeff		return err;
1637219820Sjeff
1638219820Sjeff	mutex_init(&priv->mcg_table.mutex);
1639219820Sjeff
1640219820Sjeff	return 0;
1641219820Sjeff}
1642219820Sjeff
1643219820Sjeffvoid mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
1644219820Sjeff{
1645255932Salfred	if (dev->caps.steering_mode !=
1646255932Salfred	    MLX4_STEERING_MODE_DEVICE_MANAGED)
1647255932Salfred		mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
1648219820Sjeff}
1649