mlx4_mcg.c revision 272027
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
37219820Sjeff#include <linux/mlx4/cmd.h>
38272027Shselasky#include <linux/module.h>
39219820Sjeff
40219820Sjeff#include "mlx4.h"
41219820Sjeff
42219820Sjeff
43219820Sjeffstatic const u8 zero_gid[16];	/* automatically initialized to 0 */
44219820Sjeff
45255932Salfredint mlx4_get_mgm_entry_size(struct mlx4_dev *dev)
46219820Sjeff{
47255932Salfred	return 1 << dev->oper_log_mgm_entry_size;
48255932Salfred}
49255932Salfred
50255932Salfredint mlx4_get_qp_per_mgm(struct mlx4_dev *dev)
51255932Salfred{
52255932Salfred	return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2);
53255932Salfred}
54255932Salfred
55255932Salfredstatic int mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev *dev,
56255932Salfred					struct mlx4_cmd_mailbox *mailbox,
57255932Salfred					u32 size,
58255932Salfred					u64 *reg_id)
59255932Salfred{
60255932Salfred	u64 imm;
61255932Salfred	int err = 0;
62255932Salfred
63255932Salfred	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, size, 0,
64255932Salfred			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
65255932Salfred			   MLX4_CMD_NATIVE);
66255932Salfred	if (err)
67255932Salfred		return err;
68255932Salfred	*reg_id = imm;
69255932Salfred
70255932Salfred	return err;
71255932Salfred}
72255932Salfred
73255932Salfredstatic int mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev *dev, u64 regid)
74255932Salfred{
75255932Salfred	int err = 0;
76255932Salfred
77255932Salfred	err = mlx4_cmd(dev, regid, 0, 0,
78255932Salfred		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
79255932Salfred		       MLX4_CMD_NATIVE);
80255932Salfred
81255932Salfred	return err;
82255932Salfred}
83255932Salfred
84255932Salfredstatic int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index,
85255932Salfred			   struct mlx4_cmd_mailbox *mailbox)
86255932Salfred{
87219820Sjeff	return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG,
88255932Salfred			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
89219820Sjeff}
90219820Sjeff
91255932Salfredstatic int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index,
92255932Salfred			    struct mlx4_cmd_mailbox *mailbox)
93219820Sjeff{
94219820Sjeff	return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG,
95255932Salfred			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
96219820Sjeff}
97219820Sjeff
98255932Salfredstatic int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer,
99255932Salfred			      struct mlx4_cmd_mailbox *mailbox)
100219820Sjeff{
101255932Salfred	u32 in_mod;
102255932Salfred
103255932Salfred	in_mod = (u32) port << 16 | steer << 1;
104255932Salfred	return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1,
105255932Salfred			MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A,
106255932Salfred			MLX4_CMD_NATIVE);
107255932Salfred}
108255932Salfred
109255932Salfredstatic int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
110255932Salfred			 u16 *hash, u8 op_mod)
111255932Salfred{
112219820Sjeff	u64 imm;
113219820Sjeff	int err;
114219820Sjeff
115255932Salfred	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod,
116255932Salfred			   MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A,
117255932Salfred			   MLX4_CMD_NATIVE);
118219820Sjeff
119219820Sjeff	if (!err)
120219820Sjeff		*hash = imm;
121219820Sjeff
122219820Sjeff	return err;
123219820Sjeff}
124219820Sjeff
125255932Salfredstatic struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port,
126255932Salfred					      enum mlx4_steer_type steer,
127255932Salfred					      u32 qpn)
128255932Salfred{
129272027Shselasky	struct mlx4_steer *s_steer;
130255932Salfred	struct mlx4_promisc_qp *pqp;
131255932Salfred
132272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
133272027Shselasky		return NULL;
134272027Shselasky
135272027Shselasky	s_steer = &mlx4_priv(dev)->steer[port - 1];
136272027Shselasky
137255932Salfred	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
138255932Salfred		if (pqp->qpn == qpn)
139255932Salfred			return pqp;
140255932Salfred	}
141255932Salfred	/* not found */
142255932Salfred	return NULL;
143255932Salfred}
144255932Salfred
145219820Sjeff/*
146255932Salfred * Add new entry to steering data structure.
147255932Salfred * All promisc QPs should be added as well
148255932Salfred */
149255932Salfredstatic int new_steering_entry(struct mlx4_dev *dev, u8 port,
150255932Salfred			      enum mlx4_steer_type steer,
151255932Salfred			      unsigned int index, u32 qpn)
152255932Salfred{
153255932Salfred	struct mlx4_steer *s_steer;
154255932Salfred	struct mlx4_cmd_mailbox *mailbox;
155255932Salfred	struct mlx4_mgm *mgm;
156255932Salfred	u32 members_count;
157255932Salfred	struct mlx4_steer_index *new_entry;
158255932Salfred	struct mlx4_promisc_qp *pqp;
159255932Salfred	struct mlx4_promisc_qp *dqp = NULL;
160255932Salfred	u32 prot;
161255932Salfred	int err;
162255932Salfred
163272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
164272027Shselasky		return -EINVAL;
165272027Shselasky
166255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
167255932Salfred	new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL);
168255932Salfred	if (!new_entry)
169255932Salfred		return -ENOMEM;
170255932Salfred
171255932Salfred	INIT_LIST_HEAD(&new_entry->duplicates);
172255932Salfred	new_entry->index = index;
173255932Salfred	list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]);
174255932Salfred
175255932Salfred	/* If the given qpn is also a promisc qp,
176255932Salfred	 * it should be inserted to duplicates list
177255932Salfred	 */
178255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
179255932Salfred	if (pqp) {
180255932Salfred		dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
181255932Salfred		if (!dqp) {
182255932Salfred			err = -ENOMEM;
183255932Salfred			goto out_alloc;
184255932Salfred		}
185255932Salfred		dqp->qpn = qpn;
186255932Salfred		list_add_tail(&dqp->list, &new_entry->duplicates);
187255932Salfred	}
188255932Salfred
189255932Salfred	/* if no promisc qps for this vep, we are done */
190255932Salfred	if (list_empty(&s_steer->promisc_qps[steer]))
191255932Salfred		return 0;
192255932Salfred
193255932Salfred	/* now need to add all the promisc qps to the new
194255932Salfred	 * steering entry, as they should also receive the packets
195255932Salfred	 * destined to this address */
196255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
197255932Salfred	if (IS_ERR(mailbox)) {
198255932Salfred		err = -ENOMEM;
199255932Salfred		goto out_alloc;
200255932Salfred	}
201255932Salfred	mgm = mailbox->buf;
202255932Salfred
203255932Salfred	err = mlx4_READ_ENTRY(dev, index, mailbox);
204255932Salfred	if (err)
205255932Salfred		goto out_mailbox;
206255932Salfred
207255932Salfred	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
208255932Salfred	prot = be32_to_cpu(mgm->members_count) >> 30;
209255932Salfred	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
210255932Salfred		/* don't add already existing qpn */
211255932Salfred		if (pqp->qpn == qpn)
212255932Salfred			continue;
213255932Salfred		if (members_count == dev->caps.num_qp_per_mgm) {
214255932Salfred			/* out of space */
215255932Salfred			err = -ENOMEM;
216255932Salfred			goto out_mailbox;
217255932Salfred		}
218255932Salfred
219255932Salfred		/* add the qpn */
220255932Salfred		mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK);
221255932Salfred	}
222255932Salfred	/* update the qps count and update the entry with all the promisc qps*/
223255932Salfred	mgm->members_count = cpu_to_be32(members_count | (prot << 30));
224255932Salfred	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
225255932Salfred
226255932Salfredout_mailbox:
227255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
228255932Salfred	if (!err)
229255932Salfred		return 0;
230255932Salfredout_alloc:
231255932Salfred	if (dqp) {
232255932Salfred		list_del(&dqp->list);
233255932Salfred		kfree(dqp);
234255932Salfred	}
235255932Salfred	list_del(&new_entry->list);
236255932Salfred	kfree(new_entry);
237255932Salfred	return err;
238255932Salfred}
239255932Salfred
240255932Salfred/* update the data structures with existing steering entry */
241255932Salfredstatic int existing_steering_entry(struct mlx4_dev *dev, u8 port,
242255932Salfred				   enum mlx4_steer_type steer,
243255932Salfred				   unsigned int index, u32 qpn)
244255932Salfred{
245255932Salfred	struct mlx4_steer *s_steer;
246255932Salfred	struct mlx4_steer_index *tmp_entry, *entry = NULL;
247255932Salfred	struct mlx4_promisc_qp *pqp;
248255932Salfred	struct mlx4_promisc_qp *dqp;
249255932Salfred
250272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
251272027Shselasky		return -EINVAL;
252272027Shselasky
253255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
254255932Salfred
255255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
256255932Salfred	if (!pqp)
257255932Salfred		return 0; /* nothing to do */
258255932Salfred
259255932Salfred	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
260255932Salfred		if (tmp_entry->index == index) {
261255932Salfred			entry = tmp_entry;
262255932Salfred			break;
263255932Salfred		}
264255932Salfred	}
265255932Salfred	if (unlikely(!entry)) {
266255932Salfred		mlx4_warn(dev, "Steering entry at index %x is not registered\n", index);
267255932Salfred		return -EINVAL;
268255932Salfred	}
269255932Salfred
270255932Salfred	/* the given qpn is listed as a promisc qpn
271255932Salfred	 * we need to add it as a duplicate to this entry
272255932Salfred	 * for future references */
273255932Salfred	list_for_each_entry(dqp, &entry->duplicates, list) {
274272027Shselasky		if (qpn == dqp->qpn)
275255932Salfred			return 0; /* qp is already duplicated */
276255932Salfred	}
277255932Salfred
278255932Salfred	/* add the qp as a duplicate on this index */
279255932Salfred	dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
280255932Salfred	if (!dqp)
281255932Salfred		return -ENOMEM;
282255932Salfred	dqp->qpn = qpn;
283255932Salfred	list_add_tail(&dqp->list, &entry->duplicates);
284255932Salfred
285255932Salfred	return 0;
286255932Salfred}
287255932Salfred
288255932Salfred/* Check whether a qpn is a duplicate on steering entry
289255932Salfred * If so, it should not be removed from mgm */
290255932Salfredstatic bool check_duplicate_entry(struct mlx4_dev *dev, u8 port,
291255932Salfred				  enum mlx4_steer_type steer,
292255932Salfred				  unsigned int index, u32 qpn)
293255932Salfred{
294255932Salfred	struct mlx4_steer *s_steer;
295255932Salfred	struct mlx4_steer_index *tmp_entry, *entry = NULL;
296255932Salfred	struct mlx4_promisc_qp *dqp, *tmp_dqp;
297255932Salfred
298272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
299272027Shselasky		return NULL;
300272027Shselasky
301255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
302255932Salfred
303255932Salfred	/* if qp is not promisc, it cannot be duplicated */
304255932Salfred	if (!get_promisc_qp(dev, port, steer, qpn))
305255932Salfred		return false;
306255932Salfred
307255932Salfred	/* The qp is promisc qp so it is a duplicate on this index
308255932Salfred	 * Find the index entry, and remove the duplicate */
309255932Salfred	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
310255932Salfred		if (tmp_entry->index == index) {
311255932Salfred			entry = tmp_entry;
312255932Salfred			break;
313255932Salfred		}
314255932Salfred	}
315255932Salfred	if (unlikely(!entry)) {
316255932Salfred		mlx4_warn(dev, "Steering entry for index %x is not registered\n", index);
317255932Salfred		return false;
318255932Salfred	}
319255932Salfred	list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) {
320255932Salfred		if (dqp->qpn == qpn) {
321255932Salfred			list_del(&dqp->list);
322255932Salfred			kfree(dqp);
323255932Salfred		}
324255932Salfred	}
325255932Salfred	return true;
326255932Salfred}
327255932Salfred
328272027Shselasky/*
329272027Shselasky * returns true if all the QPs != tqpn contained in this entry
330272027Shselasky * are Promisc QPs. return false otherwise.
331272027Shselasky */
332272027Shselaskystatic bool promisc_steering_entry(struct mlx4_dev *dev, u8 port,
333255932Salfred				      enum mlx4_steer_type steer,
334272027Shselasky				      unsigned int index, u32 tqpn, u32 *members_count)
335255932Salfred{
336255932Salfred	struct mlx4_steer *s_steer;
337255932Salfred	struct mlx4_cmd_mailbox *mailbox;
338255932Salfred	struct mlx4_mgm *mgm;
339272027Shselasky	u32 m_count;
340255932Salfred	bool ret = false;
341255932Salfred	int i;
342255932Salfred
343272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
344272027Shselasky		return false;
345272027Shselasky
346255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
347255932Salfred
348255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
349255932Salfred	if (IS_ERR(mailbox))
350255932Salfred		return false;
351255932Salfred	mgm = mailbox->buf;
352255932Salfred
353255932Salfred	if (mlx4_READ_ENTRY(dev, index, mailbox))
354255932Salfred		goto out;
355272027Shselasky	m_count = be32_to_cpu(mgm->members_count) & 0xffffff;
356272027Shselasky	if (members_count)
357272027Shselasky		*members_count = m_count;
358272027Shselasky
359272027Shselasky	for (i = 0;  i < m_count; i++) {
360272027Shselasky		u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
361255932Salfred		if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) {
362255932Salfred			/* the qp is not promisc, the entry can't be removed */
363255932Salfred			goto out;
364255932Salfred		}
365255932Salfred	}
366272027Shselasky	ret = true;
367272027Shselaskyout:
368272027Shselasky	mlx4_free_cmd_mailbox(dev, mailbox);
369272027Shselasky	return ret;
370272027Shselasky}
371272027Shselasky
372272027Shselasky/* IF a steering entry contains only promisc QPs, it can be removed. */
373272027Shselaskystatic bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
374272027Shselasky				      enum mlx4_steer_type steer,
375272027Shselasky				      unsigned int index, u32 tqpn)
376272027Shselasky{
377272027Shselasky	struct mlx4_steer *s_steer;
378272027Shselasky	struct mlx4_steer_index *entry = NULL, *tmp_entry;
379272027Shselasky	u32 members_count;
380272027Shselasky	bool ret = false;
381272027Shselasky
382272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
383272027Shselasky		return NULL;
384272027Shselasky
385272027Shselasky	s_steer = &mlx4_priv(dev)->steer[port - 1];
386272027Shselasky
387272027Shselasky	if (!promisc_steering_entry(dev, port, steer, index, tqpn, &members_count))
388272027Shselasky		goto out;
389272027Shselasky
390272027Shselasky	/* All the qps currently registered for this entry are promiscuous,
391255932Salfred	  * Checking for duplicates */
392255932Salfred	ret = true;
393255932Salfred	list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
394255932Salfred		if (entry->index == index) {
395255932Salfred			if (list_empty(&entry->duplicates) || members_count == 1) {
396255932Salfred				struct mlx4_promisc_qp *pqp, *tmp_pqp;
397255932Salfred				/*
398255932Salfred				 * If there is only 1 entry in duplicates than
399255932Salfred				 * this is the QP we want to delete, going over
400255932Salfred				 * the list and deleting the entry.
401255932Salfred				 */
402255932Salfred				list_del(&entry->list);
403255932Salfred				list_for_each_entry_safe(pqp, tmp_pqp,
404255932Salfred							 &entry->duplicates,
405255932Salfred							 list) {
406255932Salfred					list_del(&pqp->list);
407255932Salfred					kfree(pqp);
408255932Salfred				}
409255932Salfred				kfree(entry);
410255932Salfred			} else {
411255932Salfred				/* This entry contains duplicates so it shouldn't be removed */
412255932Salfred				ret = false;
413255932Salfred				goto out;
414255932Salfred			}
415255932Salfred		}
416255932Salfred	}
417255932Salfred
418255932Salfredout:
419255932Salfred	return ret;
420255932Salfred}
421255932Salfred
422255932Salfredstatic int add_promisc_qp(struct mlx4_dev *dev, u8 port,
423255932Salfred			  enum mlx4_steer_type steer, u32 qpn)
424255932Salfred{
425255932Salfred	struct mlx4_steer *s_steer;
426255932Salfred	struct mlx4_cmd_mailbox *mailbox;
427255932Salfred	struct mlx4_mgm *mgm;
428255932Salfred	struct mlx4_steer_index *entry;
429255932Salfred	struct mlx4_promisc_qp *pqp;
430255932Salfred	struct mlx4_promisc_qp *dqp;
431255932Salfred	u32 members_count;
432255932Salfred	u32 prot;
433255932Salfred	int i;
434255932Salfred	bool found;
435255932Salfred	int err;
436255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
437255932Salfred
438272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
439272027Shselasky		return -EINVAL;
440272027Shselasky
441255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
442255932Salfred
443255932Salfred	mutex_lock(&priv->mcg_table.mutex);
444255932Salfred
445255932Salfred	if (get_promisc_qp(dev, port, steer, qpn)) {
446255932Salfred		err = 0;  /* Noting to do, already exists */
447255932Salfred		goto out_mutex;
448255932Salfred	}
449255932Salfred
450255932Salfred	pqp = kmalloc(sizeof *pqp, GFP_KERNEL);
451255932Salfred	if (!pqp) {
452255932Salfred		err = -ENOMEM;
453255932Salfred		goto out_mutex;
454255932Salfred	}
455255932Salfred	pqp->qpn = qpn;
456255932Salfred
457255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
458255932Salfred	if (IS_ERR(mailbox)) {
459255932Salfred		err = -ENOMEM;
460255932Salfred		goto out_alloc;
461255932Salfred	}
462255932Salfred	mgm = mailbox->buf;
463255932Salfred
464272027Shselasky	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
465272027Shselasky		/* the promisc qp needs to be added for each one of the steering
466272027Shselasky		 * entries, if it already exists, needs to be added as a duplicate
467272027Shselasky		 * for this entry */
468272027Shselasky		list_for_each_entry(entry, &s_steer->steer_entries[steer], list) {
469272027Shselasky			err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
470272027Shselasky			if (err)
471272027Shselasky				goto out_mailbox;
472255932Salfred
473272027Shselasky			members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
474272027Shselasky			prot = be32_to_cpu(mgm->members_count) >> 30;
475272027Shselasky			found = false;
476272027Shselasky			for (i = 0; i < members_count; i++) {
477272027Shselasky				if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
478272027Shselasky					/* Entry already exists, add to duplicates */
479272027Shselasky					dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
480272027Shselasky					if (!dqp) {
481272027Shselasky						err = -ENOMEM;
482272027Shselasky						goto out_mailbox;
483272027Shselasky					}
484272027Shselasky					dqp->qpn = qpn;
485272027Shselasky					list_add_tail(&dqp->list, &entry->duplicates);
486272027Shselasky					found = true;
487272027Shselasky				}
488272027Shselasky			}
489272027Shselasky			if (!found) {
490272027Shselasky				/* Need to add the qpn to mgm */
491272027Shselasky				if (members_count == dev->caps.num_qp_per_mgm) {
492272027Shselasky					/* entry is full */
493255932Salfred					err = -ENOMEM;
494255932Salfred					goto out_mailbox;
495255932Salfred				}
496272027Shselasky				mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK);
497272027Shselasky				mgm->members_count = cpu_to_be32(members_count | (prot << 30));
498272027Shselasky				err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
499272027Shselasky				if (err)
500272027Shselasky					goto out_mailbox;
501255932Salfred			}
502255932Salfred		}
503255932Salfred	}
504255932Salfred
505255932Salfred	/* add the new qpn to list of promisc qps */
506255932Salfred	list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
507255932Salfred	/* now need to add all the promisc qps to default entry */
508255932Salfred	memset(mgm, 0, sizeof *mgm);
509255932Salfred	members_count = 0;
510255932Salfred	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) {
511255932Salfred		if (members_count == dev->caps.num_qp_per_mgm) {
512255932Salfred			/* entry is full */
513255932Salfred			err = -ENOMEM;
514255932Salfred			goto out_list;
515255932Salfred		}
516255932Salfred		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
517255932Salfred	}
518255932Salfred	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
519255932Salfred
520255932Salfred	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
521255932Salfred	if (err)
522255932Salfred		goto out_list;
523255932Salfred
524255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
525255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
526255932Salfred	return 0;
527255932Salfred
528255932Salfredout_list:
529255932Salfred	list_del(&pqp->list);
530255932Salfredout_mailbox:
531255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
532255932Salfredout_alloc:
533255932Salfred	kfree(pqp);
534255932Salfredout_mutex:
535255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
536255932Salfred	return err;
537255932Salfred}
538255932Salfred
539255932Salfredstatic int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
540255932Salfred			     enum mlx4_steer_type steer, u32 qpn)
541255932Salfred{
542255932Salfred	struct mlx4_priv *priv = mlx4_priv(dev);
543255932Salfred	struct mlx4_steer *s_steer;
544255932Salfred	struct mlx4_cmd_mailbox *mailbox;
545255932Salfred	struct mlx4_mgm *mgm;
546272027Shselasky	struct mlx4_steer_index *entry, *tmp_entry;
547255932Salfred	struct mlx4_promisc_qp *pqp;
548255932Salfred	struct mlx4_promisc_qp *dqp;
549255932Salfred	u32 members_count;
550255932Salfred	bool found;
551255932Salfred	bool back_to_list = false;
552255932Salfred	int i, loc = -1;
553255932Salfred	int err;
554255932Salfred
555272027Shselasky	if (port < 1 || port > dev->caps.num_ports)
556272027Shselasky		return -EINVAL;
557272027Shselasky
558255932Salfred	s_steer = &mlx4_priv(dev)->steer[port - 1];
559255932Salfred	mutex_lock(&priv->mcg_table.mutex);
560255932Salfred
561255932Salfred	pqp = get_promisc_qp(dev, port, steer, qpn);
562255932Salfred	if (unlikely(!pqp)) {
563255932Salfred		mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn);
564255932Salfred		/* nothing to do */
565255932Salfred		err = 0;
566255932Salfred		goto out_mutex;
567255932Salfred	}
568255932Salfred
569255932Salfred	/*remove from list of promisc qps */
570255932Salfred	list_del(&pqp->list);
571255932Salfred
572255932Salfred	/* set the default entry not to include the removed one */
573255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
574255932Salfred	if (IS_ERR(mailbox)) {
575255932Salfred		err = -ENOMEM;
576255932Salfred		back_to_list = true;
577255932Salfred		goto out_list;
578255932Salfred	}
579255932Salfred	mgm = mailbox->buf;
580255932Salfred	memset(mgm, 0, sizeof *mgm);
581255932Salfred	members_count = 0;
582255932Salfred	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
583255932Salfred		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
584255932Salfred	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
585255932Salfred
586255932Salfred	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
587255932Salfred	if (err)
588255932Salfred		goto out_mailbox;
589255932Salfred
590272027Shselasky	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
591272027Shselasky		/* remove the qp from all the steering entries*/
592272027Shselasky		list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
593272027Shselasky			found = false;
594272027Shselasky			list_for_each_entry(dqp, &entry->duplicates, list) {
595272027Shselasky				if (dqp->qpn == qpn) {
596272027Shselasky					found = true;
597255932Salfred					break;
598255932Salfred				}
599255932Salfred			}
600272027Shselasky			if (found) {
601272027Shselasky				/* a duplicate, no need to change the mgm,
602272027Shselasky				 * only update the duplicates list */
603272027Shselasky				list_del(&dqp->list);
604272027Shselasky				kfree(dqp);
605272027Shselasky			} else {
606272027Shselasky				err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
607272027Shselasky					if (err)
608272027Shselasky						goto out_mailbox;
609272027Shselasky				members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
610272027Shselasky				if (!members_count) {
611272027Shselasky					mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0."
612272027Shselasky					               " deleting entry...\n", qpn, entry->index);
613272027Shselasky					list_del(&entry->list);
614272027Shselasky					kfree(entry);
615272027Shselasky					continue;
616272027Shselasky				}
617255932Salfred
618272027Shselasky				for (i = 0; i < members_count; ++i)
619272027Shselasky					if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
620272027Shselasky						loc = i;
621272027Shselasky						break;
622272027Shselasky					}
623255932Salfred
624272027Shselasky				if (loc < 0) {
625272027Shselasky					mlx4_err(dev, "QP %06x wasn't found in entry %d\n",
626272027Shselasky						 qpn, entry->index);
627272027Shselasky					err = -EINVAL;
628255932Salfred					goto out_mailbox;
629272027Shselasky				}
630272027Shselasky
631272027Shselasky				/* copy the last QP in this MGM over removed QP */
632272027Shselasky				mgm->qp[loc] = mgm->qp[members_count - 1];
633272027Shselasky				mgm->qp[members_count - 1] = 0;
634272027Shselasky				mgm->members_count = cpu_to_be32(--members_count |
635272027Shselasky								 (MLX4_PROT_ETH << 30));
636272027Shselasky
637272027Shselasky				err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
638272027Shselasky					if (err)
639272027Shselasky						goto out_mailbox;
640272027Shselasky			}
641255932Salfred		}
642255932Salfred	}
643255932Salfred
644255932Salfredout_mailbox:
645255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
646255932Salfredout_list:
647255932Salfred	if (back_to_list)
648255932Salfred		list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
649255932Salfred	else
650255932Salfred		kfree(pqp);
651255932Salfredout_mutex:
652255932Salfred	mutex_unlock(&priv->mcg_table.mutex);
653255932Salfred	return err;
654255932Salfred}
655255932Salfred
656255932Salfred/*
657219820Sjeff * Caller must hold MCG table semaphore.  gid and mgm parameters must
658219820Sjeff * be properly aligned for command interface.
659219820Sjeff *
660219820Sjeff *  Returns 0 unless a firmware command error occurs.
661219820Sjeff *
662219820Sjeff * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
663219820Sjeff * and *mgm holds MGM entry.
664219820Sjeff *
665219820Sjeff * if GID is found in AMGM, *index = index in AMGM, *prev = index of
666219820Sjeff * previous entry in hash chain and *mgm holds AMGM entry.
667219820Sjeff *
668219820Sjeff * If no AMGM exists for given gid, *index = -1, *prev = index of last
669219820Sjeff * entry in hash chain and *mgm holds end of hash chain.
670219820Sjeff */
671255932Salfredstatic int find_entry(struct mlx4_dev *dev, u8 port,
672255932Salfred		      u8 *gid, enum mlx4_protocol prot,
673255932Salfred		      struct mlx4_cmd_mailbox *mgm_mailbox,
674255932Salfred		      int *prev, int *index)
675219820Sjeff{
676219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
677219820Sjeff	struct mlx4_mgm *mgm = mgm_mailbox->buf;
678219820Sjeff	u8 *mgid;
679219820Sjeff	int err;
680255932Salfred	u16 hash;
681255932Salfred	u8 op_mod = (prot == MLX4_PROT_ETH) ?
682255932Salfred		!!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0;
683219820Sjeff
684219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
685219820Sjeff	if (IS_ERR(mailbox))
686219820Sjeff		return -ENOMEM;
687219820Sjeff	mgid = mailbox->buf;
688219820Sjeff
689219820Sjeff	memcpy(mgid, gid, 16);
690219820Sjeff
691255932Salfred	err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod);
692219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
693219820Sjeff	if (err)
694219820Sjeff		return err;
695219820Sjeff
696219820Sjeff	if (0)
697255932Salfred		mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, hash);
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
727272027Shselaskystatic const u8 __promisc_mode[] = {
728272027Shselasky	[MLX4_FS_REGULAR]   = 0x0,
729272027Shselasky	[MLX4_FS_ALL_DEFAULT] = 0x1,
730272027Shselasky	[MLX4_FS_MC_DEFAULT] = 0x3,
731272027Shselasky	[MLX4_FS_UC_SNIFFER] = 0x4,
732272027Shselasky	[MLX4_FS_MC_SNIFFER] = 0x5,
733272027Shselasky};
734272027Shselasky
735272027Shselaskyint map_sw_to_hw_steering_mode(struct mlx4_dev *dev,
736272027Shselasky			       enum mlx4_net_trans_promisc_mode flow_type)
737272027Shselasky{
738272027Shselasky	if (flow_type >= MLX4_FS_MODE_NUM || flow_type < 0) {
739272027Shselasky		mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type);
740272027Shselasky		return -EINVAL;
741272027Shselasky	}
742272027Shselasky	return __promisc_mode[flow_type];
743272027Shselasky}
744272027ShselaskyEXPORT_SYMBOL_GPL(map_sw_to_hw_steering_mode);
745272027Shselasky
746255932Salfredstatic void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,
747255932Salfred				  struct mlx4_net_trans_rule_hw_ctrl *hw)
748219820Sjeff{
749272027Shselasky	u8 flags = 0;
750255932Salfred
751272027Shselasky	flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0;
752272027Shselasky	flags |= ctrl->exclusive ? (1 << 2) : 0;
753272027Shselasky	flags |= ctrl->allow_loopback ? (1 << 3) : 0;
754255932Salfred
755272027Shselasky	hw->flags = flags;
756272027Shselasky	hw->type = __promisc_mode[ctrl->promisc_mode];
757272027Shselasky	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
771272027Shselaskyint map_sw_to_hw_steering_id(struct mlx4_dev *dev,
772272027Shselasky			     enum mlx4_net_trans_rule_id id)
773272027Shselasky{
774272027Shselasky	if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) {
775272027Shselasky		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
776272027Shselasky		return -EINVAL;
777272027Shselasky	}
778272027Shselasky	return __sw_id_hw[id];
779272027Shselasky}
780272027ShselaskyEXPORT_SYMBOL_GPL(map_sw_to_hw_steering_id);
781272027Shselasky
782272027Shselaskystatic const int __rule_hw_sz[] = {
783272027Shselasky	[MLX4_NET_TRANS_RULE_ID_ETH] =
784272027Shselasky		sizeof(struct mlx4_net_trans_rule_hw_eth),
785272027Shselasky	[MLX4_NET_TRANS_RULE_ID_IB] =
786272027Shselasky		sizeof(struct mlx4_net_trans_rule_hw_ib),
787272027Shselasky	[MLX4_NET_TRANS_RULE_ID_IPV6] = 0,
788272027Shselasky	[MLX4_NET_TRANS_RULE_ID_IPV4] =
789272027Shselasky		sizeof(struct mlx4_net_trans_rule_hw_ipv4),
790272027Shselasky	[MLX4_NET_TRANS_RULE_ID_TCP] =
791272027Shselasky		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),
792272027Shselasky	[MLX4_NET_TRANS_RULE_ID_UDP] =
793272027Shselasky		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp)
794272027Shselasky};
795272027Shselasky
796272027Shselaskyint hw_rule_sz(struct mlx4_dev *dev,
797272027Shselasky	       enum mlx4_net_trans_rule_id id)
798272027Shselasky{
799272027Shselasky	if (id >= MLX4_NET_TRANS_RULE_NUM || id < 0) {
800272027Shselasky		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
801272027Shselasky		return -EINVAL;
802272027Shselasky	}
803272027Shselasky
804272027Shselasky	return __rule_hw_sz[id];
805272027Shselasky}
806272027ShselaskyEXPORT_SYMBOL_GPL(hw_rule_sz);
807272027Shselasky
808255932Salfredstatic int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec,
809255932Salfred			    struct _rule_hw *rule_hw)
810255932Salfred{
811272027Shselasky	if (hw_rule_sz(dev, spec->id) < 0)
812255932Salfred		return -EINVAL;
813272027Shselasky	memset(rule_hw, 0, hw_rule_sz(dev, spec->id));
814255932Salfred	rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]);
815272027Shselasky	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		}
829272027Shselasky		rule_hw->eth.vlan_tag = spec->eth.vlan_id;
830272027Shselasky		rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk;
831255932Salfred		break;
832255932Salfred
833255932Salfred	case MLX4_NET_TRANS_RULE_ID_IB:
834272027Shselasky		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,
918255932Salfred					"dst-gid = %pI6\n", cur->ib.dst_gid);
919255932Salfred			len += snprintf(buf + len, BUF_SIZE - len,
920255932Salfred					"dst-gid-mask = %pI6\n",
921255932Salfred					cur->ib.dst_gid_msk);
922255932Salfred			break;
923255932Salfred
924255932Salfred		case MLX4_NET_TRANS_RULE_ID_IPV6:
925255932Salfred			break;
926255932Salfred
927255932Salfred		default:
928255932Salfred			break;
929255932Salfred		}
930255932Salfred	}
931255932Salfred	len += snprintf(buf + len, BUF_SIZE - len, "\n");
932255932Salfred	mlx4_err(dev, "%s", buf);
933255932Salfred
934255932Salfred	if (len >= BUF_SIZE)
935255932Salfred		mlx4_err(dev, "Network rule error message was truncated, print buffer is too small.\n");
936255932Salfred}
937255932Salfred
938255932Salfredint mlx4_flow_attach(struct mlx4_dev *dev,
939255932Salfred		     struct mlx4_net_trans_rule *rule, u64 *reg_id)
940255932Salfred{
941255932Salfred	struct mlx4_cmd_mailbox *mailbox;
942255932Salfred	struct mlx4_spec_list *cur;
943255932Salfred	u32 size = 0;
944255932Salfred	int ret;
945255932Salfred
946255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
947255932Salfred	if (IS_ERR(mailbox))
948255932Salfred		return PTR_ERR(mailbox);
949255932Salfred
950255932Salfred	memset(mailbox->buf, 0, sizeof(struct mlx4_net_trans_rule_hw_ctrl));
951255932Salfred	trans_rule_ctrl_to_hw(rule, mailbox->buf);
952255932Salfred
953255932Salfred	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
954255932Salfred
955255932Salfred	list_for_each_entry(cur, &rule->list, list) {
956255932Salfred		ret = parse_trans_rule(dev, cur, mailbox->buf + size);
957255932Salfred		if (ret < 0) {
958255932Salfred			mlx4_free_cmd_mailbox(dev, mailbox);
959255932Salfred			return -EINVAL;
960255932Salfred		}
961255932Salfred		size += ret;
962255932Salfred	}
963255932Salfred
964255932Salfred	ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);
965255932Salfred	if (ret == -ENOMEM)
966255932Salfred		mlx4_err_rule(dev,
967255932Salfred			      "mcg table is full. Fail to register network rule.\n",
968255932Salfred			      rule);
969255932Salfred	else if (ret)
970255932Salfred		mlx4_err_rule(dev, "Fail to register network rule.\n", rule);
971255932Salfred
972255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
973255932Salfred
974255932Salfred	return ret;
975255932Salfred}
976255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_attach);
977255932Salfred
978255932Salfredint mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id)
979255932Salfred{
980255932Salfred	int err;
981255932Salfred
982255932Salfred	err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id);
983255932Salfred	if (err)
984255932Salfred		mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n",
985272027Shselasky			 (unsigned long long)reg_id);
986255932Salfred	return err;
987255932Salfred}
988255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_detach);
989255932Salfred
990255932Salfredint mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn, u32 max_range_qpn)
991255932Salfred{
992255932Salfred	int err;
993255932Salfred	u64 in_param;
994255932Salfred
995255932Salfred	in_param = ((u64) min_range_qpn) << 32;
996255932Salfred	in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF;
997255932Salfred
998255932Salfred	err = mlx4_cmd(dev, in_param, 0, 0,
999255932Salfred			MLX4_FLOW_STEERING_IB_UC_QP_RANGE,
1000255932Salfred			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
1001255932Salfred
1002255932Salfred	return err;
1003255932Salfred}
1004255932SalfredEXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE);
1005255932Salfred
1006255932Salfredint mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1007255932Salfred			  int block_mcast_loopback, enum mlx4_protocol prot,
1008255932Salfred			  enum mlx4_steer_type steer)
1009255932Salfred{
1010219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1011219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1012219820Sjeff	struct mlx4_mgm *mgm;
1013219820Sjeff	u32 members_count;
1014219820Sjeff	int index, prev;
1015219820Sjeff	int link = 0;
1016219820Sjeff	int i;
1017219820Sjeff	int err;
1018255932Salfred	u8 port = gid[5];
1019255932Salfred	u8 new_entry = 0;
1020219820Sjeff
1021219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1022219820Sjeff	if (IS_ERR(mailbox))
1023219820Sjeff		return PTR_ERR(mailbox);
1024219820Sjeff	mgm = mailbox->buf;
1025219820Sjeff
1026219820Sjeff	mutex_lock(&priv->mcg_table.mutex);
1027255932Salfred	err = find_entry(dev, port, gid, prot,
1028255932Salfred			 mailbox, &prev, &index);
1029219820Sjeff	if (err)
1030219820Sjeff		goto out;
1031219820Sjeff
1032219820Sjeff	if (index != -1) {
1033255932Salfred		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
1034255932Salfred			new_entry = 1;
1035219820Sjeff			memcpy(mgm->gid, gid, 16);
1036255932Salfred		}
1037219820Sjeff	} else {
1038219820Sjeff		link = 1;
1039219820Sjeff
1040219820Sjeff		index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
1041219820Sjeff		if (index == -1) {
1042219820Sjeff			mlx4_err(dev, "No AMGM entries left\n");
1043219820Sjeff			err = -ENOMEM;
1044219820Sjeff			goto out;
1045219820Sjeff		}
1046219820Sjeff		index += dev->caps.num_mgms;
1047219820Sjeff
1048255932Salfred		new_entry = 1;
1049219820Sjeff		memset(mgm, 0, sizeof *mgm);
1050219820Sjeff		memcpy(mgm->gid, gid, 16);
1051219820Sjeff	}
1052219820Sjeff
1053219820Sjeff	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
1054255932Salfred	if (members_count == dev->caps.num_qp_per_mgm) {
1055219820Sjeff		mlx4_err(dev, "MGM at index %x is full.\n", index);
1056219820Sjeff		err = -ENOMEM;
1057219820Sjeff		goto out;
1058219820Sjeff	}
1059219820Sjeff
1060219820Sjeff	for (i = 0; i < members_count; ++i)
1061219820Sjeff		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
1062219820Sjeff			mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
1063219820Sjeff			err = 0;
1064219820Sjeff			goto out;
1065219820Sjeff		}
1066219820Sjeff
1067219820Sjeff	mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
1068219820Sjeff					       (!!mlx4_blck_lb << MGM_BLCK_LB_BIT));
1069219820Sjeff
1070255932Salfred	mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30);
1071219820Sjeff
1072255932Salfred	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1073219820Sjeff	if (err)
1074219820Sjeff		goto out;
1075219820Sjeff
1076272027Shselasky	/* if !link, still add the new entry. */
1077219820Sjeff	if (!link)
1078272027Shselasky		goto skip_link;
1079219820Sjeff
1080255932Salfred	err = mlx4_READ_ENTRY(dev, prev, mailbox);
1081219820Sjeff	if (err)
1082219820Sjeff		goto out;
1083219820Sjeff
1084219820Sjeff	mgm->next_gid_index = cpu_to_be32(index << 6);
1085219820Sjeff
1086255932Salfred	err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
1087219820Sjeff	if (err)
1088219820Sjeff		goto out;
1089219820Sjeff
1090272027Shselaskyskip_link:
1091255932Salfred	if (prot == MLX4_PROT_ETH) {
1092255932Salfred		/* manage the steering entry for promisc mode */
1093255932Salfred		if (new_entry)
1094255932Salfred			new_steering_entry(dev, port, steer, index, qp->qpn);
1095255932Salfred		else
1096255932Salfred			existing_steering_entry(dev, port, steer,
1097255932Salfred						index, qp->qpn);
1098255932Salfred	}
1099255932Salfred
1100219820Sjeffout:
1101219820Sjeff	if (err && link && index != -1) {
1102219820Sjeff		if (index < dev->caps.num_mgms)
1103219820Sjeff			mlx4_warn(dev, "Got AMGM index %d < %d",
1104219820Sjeff				  index, dev->caps.num_mgms);
1105219820Sjeff		else
1106219820Sjeff			mlx4_bitmap_free(&priv->mcg_table.bitmap,
1107272027Shselasky					 index - dev->caps.num_mgms, MLX4_USE_RR);
1108219820Sjeff	}
1109219820Sjeff	mutex_unlock(&priv->mcg_table.mutex);
1110219820Sjeff
1111219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1112219820Sjeff	return err;
1113219820Sjeff}
1114219820Sjeff
1115255932Salfredint mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1116255932Salfred			  enum mlx4_protocol prot, enum mlx4_steer_type steer)
1117219820Sjeff{
1118219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1119219820Sjeff	struct mlx4_cmd_mailbox *mailbox;
1120219820Sjeff	struct mlx4_mgm *mgm;
1121219820Sjeff	u32 members_count;
1122219820Sjeff	int prev, index;
1123255932Salfred	int i, loc = -1;
1124219820Sjeff	int err;
1125255932Salfred	u8 port = gid[5];
1126255932Salfred	bool removed_entry = false;
1127219820Sjeff
1128219820Sjeff	mailbox = mlx4_alloc_cmd_mailbox(dev);
1129219820Sjeff	if (IS_ERR(mailbox))
1130219820Sjeff		return PTR_ERR(mailbox);
1131219820Sjeff	mgm = mailbox->buf;
1132219820Sjeff
1133219820Sjeff	mutex_lock(&priv->mcg_table.mutex);
1134219820Sjeff
1135255932Salfred	err = find_entry(dev, port, gid, prot,
1136255932Salfred			 mailbox, &prev, &index);
1137219820Sjeff	if (err)
1138219820Sjeff		goto out;
1139219820Sjeff
1140219820Sjeff	if (index == -1) {
1141219820Sjeff		mlx4_err(dev, "MGID %pI6 not found\n", gid);
1142219820Sjeff		err = -EINVAL;
1143219820Sjeff		goto out;
1144219820Sjeff	}
1145219820Sjeff
1146272027Shselasky	/*
1147272027Shselasky	  if this QP is also a promisc QP, it shouldn't be removed only if
1148272027Shselasky	  at least one none promisc QP is also attached to this MCG
1149272027Shselasky	*/
1150255932Salfred	if (prot == MLX4_PROT_ETH &&
1151272027Shselasky	    check_duplicate_entry(dev, port, steer, index, qp->qpn) &&
1152272027Shselasky	    !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL))
1153272027Shselasky			goto out;
1154255932Salfred
1155219820Sjeff	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
1156255932Salfred	for (i = 0; i < members_count; ++i)
1157255932Salfred		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
1158219820Sjeff			loc = i;
1159255932Salfred			break;
1160255932Salfred		}
1161219820Sjeff
1162219820Sjeff	if (loc == -1) {
1163219820Sjeff		mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
1164219820Sjeff		err = -EINVAL;
1165219820Sjeff		goto out;
1166219820Sjeff	}
1167219820Sjeff
1168255932Salfred	/* copy the last QP in this MGM over removed QP */
1169255932Salfred	mgm->qp[loc] = mgm->qp[members_count - 1];
1170255932Salfred	mgm->qp[members_count - 1] = 0;
1171255932Salfred	mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30);
1172219820Sjeff
1173255932Salfred	if (prot == MLX4_PROT_ETH)
1174255932Salfred		removed_entry = can_remove_steering_entry(dev, port, steer,
1175255932Salfred								index, qp->qpn);
1176255932Salfred	if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) {
1177255932Salfred		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1178219820Sjeff		goto out;
1179219820Sjeff	}
1180219820Sjeff
1181255932Salfred	/* We are going to delete the entry, members count should be 0 */
1182255932Salfred	mgm->members_count = cpu_to_be32((u32) prot << 30);
1183255932Salfred
1184219820Sjeff	if (prev == -1) {
1185219820Sjeff		/* Remove entry from MGM */
1186219820Sjeff		int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
1187219820Sjeff		if (amgm_index) {
1188255932Salfred			err = mlx4_READ_ENTRY(dev, amgm_index, mailbox);
1189219820Sjeff			if (err)
1190219820Sjeff				goto out;
1191219820Sjeff		} else
1192219820Sjeff			memset(mgm->gid, 0, 16);
1193219820Sjeff
1194255932Salfred		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
1195219820Sjeff		if (err)
1196219820Sjeff			goto out;
1197219820Sjeff
1198219820Sjeff		if (amgm_index) {
1199219820Sjeff			if (amgm_index < dev->caps.num_mgms)
1200219820Sjeff				mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d",
1201219820Sjeff					  index, amgm_index, dev->caps.num_mgms);
1202219820Sjeff			else
1203219820Sjeff				mlx4_bitmap_free(&priv->mcg_table.bitmap,
1204272027Shselasky						 amgm_index - dev->caps.num_mgms, MLX4_USE_RR);
1205219820Sjeff		}
1206219820Sjeff	} else {
1207219820Sjeff		/* Remove entry from AMGM */
1208219820Sjeff		int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
1209255932Salfred		err = mlx4_READ_ENTRY(dev, prev, mailbox);
1210219820Sjeff		if (err)
1211219820Sjeff			goto out;
1212219820Sjeff
1213219820Sjeff		mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
1214219820Sjeff
1215255932Salfred		err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
1216219820Sjeff		if (err)
1217219820Sjeff			goto out;
1218219820Sjeff
1219219820Sjeff		if (index < dev->caps.num_mgms)
1220219820Sjeff			mlx4_warn(dev, "entry %d had next AMGM index %d < %d",
1221219820Sjeff				  prev, index, dev->caps.num_mgms);
1222219820Sjeff		else
1223219820Sjeff			mlx4_bitmap_free(&priv->mcg_table.bitmap,
1224272027Shselasky					 index - dev->caps.num_mgms, MLX4_USE_RR);
1225219820Sjeff	}
1226219820Sjeff
1227219820Sjeffout:
1228219820Sjeff	mutex_unlock(&priv->mcg_table.mutex);
1229219820Sjeff
1230219820Sjeff	mlx4_free_cmd_mailbox(dev, mailbox);
1231219820Sjeff	return err;
1232219820Sjeff}
1233255932Salfred
1234255932Salfredstatic int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,
1235255932Salfred			  u8 gid[16], u8 attach, u8 block_loopback,
1236255932Salfred			  enum mlx4_protocol prot)
1237255932Salfred{
1238255932Salfred	struct mlx4_cmd_mailbox *mailbox;
1239255932Salfred	int err = 0;
1240255932Salfred	int qpn;
1241255932Salfred
1242255932Salfred	if (!mlx4_is_mfunc(dev))
1243255932Salfred		return -EBADF;
1244255932Salfred
1245255932Salfred	mailbox = mlx4_alloc_cmd_mailbox(dev);
1246255932Salfred	if (IS_ERR(mailbox))
1247255932Salfred		return PTR_ERR(mailbox);
1248255932Salfred
1249255932Salfred	memcpy(mailbox->buf, gid, 16);
1250255932Salfred	qpn = qp->qpn;
1251255932Salfred	qpn |= (prot << 28);
1252255932Salfred	if (attach && block_loopback)
1253272027Shselasky		qpn |= (1 << 31);
1254255932Salfred
1255255932Salfred	err = mlx4_cmd(dev, mailbox->dma, qpn, attach,
1256255932Salfred		       MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A,
1257255932Salfred		       MLX4_CMD_WRAPPED);
1258255932Salfred
1259255932Salfred	mlx4_free_cmd_mailbox(dev, mailbox);
1260255932Salfred	return err;
1261255932Salfred}
1262255932Salfred
1263272027Shselaskyint mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,
1264272027Shselasky			      u8 gid[16], u8 port,
1265272027Shselasky			      int block_mcast_loopback,
1266272027Shselasky			      enum mlx4_protocol prot, u64 *reg_id)
1267255932Salfred{
1268255932Salfred		struct mlx4_spec_list spec = { {NULL} };
1269255932Salfred		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
1270255932Salfred
1271255932Salfred		struct mlx4_net_trans_rule rule = {
1272255932Salfred			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
1273255932Salfred			.exclusive = 0,
1274255932Salfred			.promisc_mode = MLX4_FS_REGULAR,
1275255932Salfred			.priority = MLX4_DOMAIN_NIC,
1276255932Salfred		};
1277255932Salfred
1278255932Salfred		rule.allow_loopback = !block_mcast_loopback;
1279255932Salfred		rule.port = port;
1280255932Salfred		rule.qpn = qp->qpn;
1281255932Salfred		INIT_LIST_HEAD(&rule.list);
1282255932Salfred
1283255932Salfred		switch (prot) {
1284255932Salfred		case MLX4_PROT_ETH:
1285255932Salfred			spec.id = MLX4_NET_TRANS_RULE_ID_ETH;
1286255932Salfred			memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN);
1287255932Salfred			memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
1288255932Salfred			break;
1289255932Salfred
1290255932Salfred		case MLX4_PROT_IB_IPV6:
1291255932Salfred			spec.id = MLX4_NET_TRANS_RULE_ID_IB;
1292255932Salfred			memcpy(spec.ib.dst_gid, gid, 16);
1293255932Salfred			memset(&spec.ib.dst_gid_msk, 0xff, 16);
1294255932Salfred			break;
1295255932Salfred		default:
1296255932Salfred			return -EINVAL;
1297255932Salfred		}
1298255932Salfred		list_add_tail(&spec.list, &rule.list);
1299255932Salfred
1300255932Salfred		return mlx4_flow_attach(dev, &rule, reg_id);
1301272027Shselasky}
1302255932Salfred
1303272027Shselaskyint mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1304272027Shselasky			  u8 port, int block_mcast_loopback,
1305272027Shselasky			  enum mlx4_protocol prot, u64 *reg_id)
1306272027Shselasky{
1307272027Shselasky	enum mlx4_steer_type steer;
1308272027Shselasky	steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER;
1309272027Shselasky
1310272027Shselasky	switch (dev->caps.steering_mode) {
1311272027Shselasky	case MLX4_STEERING_MODE_A0:
1312272027Shselasky		if (prot == MLX4_PROT_ETH)
1313272027Shselasky			return 0;
1314272027Shselasky
1315272027Shselasky	case MLX4_STEERING_MODE_B0:
1316272027Shselasky		if (prot == MLX4_PROT_ETH)
1317272027Shselasky			gid[7] |= (steer << 1);
1318272027Shselasky
1319272027Shselasky		if (mlx4_is_mfunc(dev))
1320272027Shselasky			return mlx4_QP_ATTACH(dev, qp, gid, 1,
1321272027Shselasky					      block_mcast_loopback, prot);
1322272027Shselasky		return mlx4_qp_attach_common(dev, qp, gid,
1323272027Shselasky					     block_mcast_loopback, prot,
1324272027Shselasky					     MLX4_MC_STEER);
1325272027Shselasky
1326272027Shselasky	case MLX4_STEERING_MODE_DEVICE_MANAGED:
1327272027Shselasky		return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
1328272027Shselasky						 block_mcast_loopback,
1329272027Shselasky						 prot, reg_id);
1330255932Salfred	default:
1331255932Salfred		return -EINVAL;
1332255932Salfred	}
1333255932Salfred}
1334255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_attach);
1335255932Salfred
1336255932Salfredint mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
1337255932Salfred			  enum mlx4_protocol prot, u64 reg_id)
1338255932Salfred{
1339272027Shselasky	enum mlx4_steer_type steer;
1340272027Shselasky	steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER;
1341272027Shselasky
1342255932Salfred	switch (dev->caps.steering_mode) {
1343255932Salfred	case MLX4_STEERING_MODE_A0:
1344255932Salfred		if (prot == MLX4_PROT_ETH)
1345255932Salfred			return 0;
1346255932Salfred
1347255932Salfred	case MLX4_STEERING_MODE_B0:
1348255932Salfred		if (prot == MLX4_PROT_ETH)
1349272027Shselasky			gid[7] |= (steer << 1);
1350255932Salfred
1351255932Salfred		if (mlx4_is_mfunc(dev))
1352255932Salfred			return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
1353255932Salfred
1354255932Salfred		return mlx4_qp_detach_common(dev, qp, gid, prot,
1355255932Salfred					     MLX4_MC_STEER);
1356255932Salfred
1357255932Salfred	case MLX4_STEERING_MODE_DEVICE_MANAGED:
1358255932Salfred		return mlx4_flow_detach(dev, reg_id);
1359255932Salfred
1360255932Salfred	default:
1361255932Salfred		return -EINVAL;
1362255932Salfred	}
1363255932Salfred}
1364219820SjeffEXPORT_SYMBOL_GPL(mlx4_multicast_detach);
1365219820Sjeff
1366255932Salfredint mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
1367255932Salfred				u32 qpn, enum mlx4_net_trans_promisc_mode mode)
1368255932Salfred{
1369255932Salfred	struct mlx4_net_trans_rule rule;
1370255932Salfred	u64 *regid_p;
1371255932Salfred
1372255932Salfred	switch (mode) {
1373255932Salfred	case MLX4_FS_ALL_DEFAULT:
1374255932Salfred		regid_p = &dev->regid_promisc_array[port];
1375255932Salfred		break;
1376255932Salfred	case MLX4_FS_MC_DEFAULT:
1377255932Salfred		regid_p = &dev->regid_allmulti_array[port];
1378255932Salfred		break;
1379255932Salfred	default:
1380255932Salfred		return -1;
1381255932Salfred	}
1382255932Salfred
1383255932Salfred	if (*regid_p != 0)
1384255932Salfred		return -1;
1385255932Salfred
1386255932Salfred	rule.promisc_mode = mode;
1387255932Salfred	rule.port = port;
1388255932Salfred	rule.qpn = qpn;
1389255932Salfred	INIT_LIST_HEAD(&rule.list);
1390255932Salfred	mlx4_err(dev, "going promisc on %x\n", port);
1391255932Salfred
1392255932Salfred	return  mlx4_flow_attach(dev, &rule, regid_p);
1393255932Salfred}
1394255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add);
1395255932Salfred
1396255932Salfredint mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port,
1397255932Salfred				   enum mlx4_net_trans_promisc_mode mode)
1398255932Salfred{
1399255932Salfred	int ret;
1400255932Salfred	u64 *regid_p;
1401255932Salfred
1402255932Salfred	switch (mode) {
1403255932Salfred	case MLX4_FS_ALL_DEFAULT:
1404255932Salfred		regid_p = &dev->regid_promisc_array[port];
1405255932Salfred		break;
1406255932Salfred	case MLX4_FS_MC_DEFAULT:
1407255932Salfred		regid_p = &dev->regid_allmulti_array[port];
1408255932Salfred		break;
1409255932Salfred	default:
1410255932Salfred		return -1;
1411255932Salfred	}
1412255932Salfred
1413255932Salfred	if (*regid_p == 0)
1414255932Salfred		return -1;
1415255932Salfred
1416255932Salfred	ret =  mlx4_flow_detach(dev, *regid_p);
1417255932Salfred	if (ret == 0)
1418255932Salfred		*regid_p = 0;
1419255932Salfred
1420255932Salfred	return ret;
1421255932Salfred}
1422255932SalfredEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove);
1423255932Salfred
1424255932Salfredint mlx4_unicast_attach(struct mlx4_dev *dev,
1425255932Salfred			struct mlx4_qp *qp, u8 gid[16],
1426255932Salfred			int block_mcast_loopback, enum mlx4_protocol prot)
1427255932Salfred{
1428255932Salfred	if (prot == MLX4_PROT_ETH)
1429255932Salfred		gid[7] |= (MLX4_UC_STEER << 1);
1430255932Salfred
1431255932Salfred	if (mlx4_is_mfunc(dev))
1432255932Salfred		return mlx4_QP_ATTACH(dev, qp, gid, 1,
1433255932Salfred					block_mcast_loopback, prot);
1434255932Salfred
1435255932Salfred	return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback,
1436255932Salfred					prot, MLX4_UC_STEER);
1437255932Salfred}
1438255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_attach);
1439255932Salfred
1440255932Salfredint mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
1441255932Salfred			       u8 gid[16], enum mlx4_protocol prot)
1442255932Salfred{
1443255932Salfred	if (prot == MLX4_PROT_ETH)
1444255932Salfred		gid[7] |= (MLX4_UC_STEER << 1);
1445255932Salfred
1446255932Salfred	if (mlx4_is_mfunc(dev))
1447255932Salfred		return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
1448255932Salfred
1449255932Salfred	return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER);
1450255932Salfred}
1451255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_detach);
1452255932Salfred
1453255932Salfredint mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave,
1454255932Salfred			 struct mlx4_vhcr *vhcr,
1455255932Salfred			 struct mlx4_cmd_mailbox *inbox,
1456255932Salfred			 struct mlx4_cmd_mailbox *outbox,
1457255932Salfred			 struct mlx4_cmd_info *cmd)
1458255932Salfred{
1459255932Salfred	u32 qpn = (u32) vhcr->in_param & 0xffffffff;
1460255932Salfred	u8 port = vhcr->in_param >> 62;
1461255932Salfred	enum mlx4_steer_type steer = vhcr->in_modifier;
1462255932Salfred
1463272027Shselasky	/* Promiscuous unicast is not allowed in mfunc for VFs */
1464272027Shselasky	if ((slave != dev->caps.function) && (steer == MLX4_UC_STEER))
1465255932Salfred		return 0;
1466255932Salfred
1467255932Salfred	if (vhcr->op_modifier)
1468255932Salfred		return add_promisc_qp(dev, port, steer, qpn);
1469255932Salfred	else
1470255932Salfred		return remove_promisc_qp(dev, port, steer, qpn);
1471255932Salfred}
1472255932Salfred
1473255932Salfredstatic int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn,
1474255932Salfred			enum mlx4_steer_type steer, u8 add, u8 port)
1475255932Salfred{
1476255932Salfred	return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add,
1477255932Salfred			MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A,
1478255932Salfred			MLX4_CMD_WRAPPED);
1479255932Salfred}
1480255932Salfred
1481255932Salfredint mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
1482255932Salfred{
1483255932Salfred	if (mlx4_is_mfunc(dev))
1484255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port);
1485255932Salfred
1486255932Salfred	return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
1487255932Salfred}
1488255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add);
1489255932Salfred
1490255932Salfredint mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
1491255932Salfred{
1492255932Salfred	if (mlx4_is_mfunc(dev))
1493255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port);
1494255932Salfred
1495255932Salfred	return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
1496255932Salfred}
1497255932SalfredEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove);
1498255932Salfred
1499255932Salfredint mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
1500255932Salfred{
1501255932Salfred	if (mlx4_is_mfunc(dev))
1502255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port);
1503255932Salfred
1504255932Salfred	return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
1505255932Salfred}
1506255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add);
1507255932Salfred
1508255932Salfredint mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
1509255932Salfred{
1510255932Salfred	if (mlx4_is_mfunc(dev))
1511255932Salfred		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port);
1512255932Salfred
1513255932Salfred	return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
1514255932Salfred}
1515255932SalfredEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove);
1516255932Salfred
1517219820Sjeffint mlx4_init_mcg_table(struct mlx4_dev *dev)
1518219820Sjeff{
1519219820Sjeff	struct mlx4_priv *priv = mlx4_priv(dev);
1520219820Sjeff	int err;
1521219820Sjeff
1522255932Salfred	/* No need for mcg_table when fw managed the mcg table*/
1523255932Salfred	if (dev->caps.steering_mode ==
1524255932Salfred	    MLX4_STEERING_MODE_DEVICE_MANAGED)
1525255932Salfred		return 0;
1526219820Sjeff	err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
1527219820Sjeff			       dev->caps.num_amgms - 1, 0, 0);
1528219820Sjeff	if (err)
1529219820Sjeff		return err;
1530219820Sjeff
1531219820Sjeff	mutex_init(&priv->mcg_table.mutex);
1532219820Sjeff
1533219820Sjeff	return 0;
1534219820Sjeff}
1535219820Sjeff
1536219820Sjeffvoid mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
1537219820Sjeff{
1538255932Salfred	if (dev->caps.steering_mode !=
1539255932Salfred	    MLX4_STEERING_MODE_DEVICE_MANAGED)
1540255932Salfred		mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
1541219820Sjeff}
1542