xref: /freebsd/sys/dev/mlx4/mlx4_core/mlx4_mcg.c (revision 02ca39cf)
197549c34SHans Petter Selasky /*
297549c34SHans Petter Selasky  * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
397549c34SHans Petter Selasky  * Copyright (c) 2007, 2008, 2014 Mellanox Technologies. All rights reserved.
497549c34SHans Petter Selasky  *
597549c34SHans Petter Selasky  * This software is available to you under a choice of one of two
697549c34SHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
797549c34SHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
897549c34SHans Petter Selasky  * COPYING in the main directory of this source tree, or the
997549c34SHans Petter Selasky  * OpenIB.org BSD license below:
1097549c34SHans Petter Selasky  *
1197549c34SHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
1297549c34SHans Petter Selasky  *     without modification, are permitted provided that the following
1397549c34SHans Petter Selasky  *     conditions are met:
1497549c34SHans Petter Selasky  *
1597549c34SHans Petter Selasky  *      - Redistributions of source code must retain the above
1697549c34SHans Petter Selasky  *        copyright notice, this list of conditions and the following
1797549c34SHans Petter Selasky  *        disclaimer.
1897549c34SHans Petter Selasky  *
1997549c34SHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
2097549c34SHans Petter Selasky  *        copyright notice, this list of conditions and the following
2197549c34SHans Petter Selasky  *        disclaimer in the documentation and/or other materials
2297549c34SHans Petter Selasky  *        provided with the distribution.
2397549c34SHans Petter Selasky  *
2497549c34SHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2597549c34SHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2697549c34SHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2797549c34SHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2897549c34SHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2997549c34SHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3097549c34SHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3197549c34SHans Petter Selasky  * SOFTWARE.
3297549c34SHans Petter Selasky  */
3397549c34SHans Petter Selasky 
3497549c34SHans Petter Selasky #include <linux/string.h>
3597549c34SHans Petter Selasky #include <linux/etherdevice.h>
3697549c34SHans Petter Selasky 
3797549c34SHans Petter Selasky #include <dev/mlx4/cmd.h>
3897549c34SHans Petter Selasky #include <linux/module.h>
3997549c34SHans Petter Selasky #include <linux/printk.h>
4097549c34SHans Petter Selasky 
4197549c34SHans Petter Selasky #include "mlx4.h"
4297549c34SHans Petter Selasky 
mlx4_get_mgm_entry_size(struct mlx4_dev * dev)4397549c34SHans Petter Selasky int mlx4_get_mgm_entry_size(struct mlx4_dev *dev)
4497549c34SHans Petter Selasky {
4597549c34SHans Petter Selasky 	return 1 << dev->oper_log_mgm_entry_size;
4697549c34SHans Petter Selasky }
4797549c34SHans Petter Selasky 
mlx4_get_qp_per_mgm(struct mlx4_dev * dev)4897549c34SHans Petter Selasky int mlx4_get_qp_per_mgm(struct mlx4_dev *dev)
4997549c34SHans Petter Selasky {
5097549c34SHans Petter Selasky 	return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2);
5197549c34SHans Petter Selasky }
5297549c34SHans Petter Selasky 
mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev * dev,struct mlx4_cmd_mailbox * mailbox,u32 size,u64 * reg_id)5397549c34SHans Petter Selasky static int mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev *dev,
5497549c34SHans Petter Selasky 					struct mlx4_cmd_mailbox *mailbox,
5597549c34SHans Petter Selasky 					u32 size,
5697549c34SHans Petter Selasky 					u64 *reg_id)
5797549c34SHans Petter Selasky {
5897549c34SHans Petter Selasky 	u64 imm;
5997549c34SHans Petter Selasky 	int err = 0;
6097549c34SHans Petter Selasky 
6197549c34SHans Petter Selasky 	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, size, 0,
6297549c34SHans Petter Selasky 			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
6397549c34SHans Petter Selasky 			   MLX4_CMD_NATIVE);
6497549c34SHans Petter Selasky 	if (err)
6597549c34SHans Petter Selasky 		return err;
6697549c34SHans Petter Selasky 	*reg_id = imm;
6797549c34SHans Petter Selasky 
6897549c34SHans Petter Selasky 	return err;
6997549c34SHans Petter Selasky }
7097549c34SHans Petter Selasky 
mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev * dev,u64 regid)7197549c34SHans Petter Selasky static int mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev *dev, u64 regid)
7297549c34SHans Petter Selasky {
7397549c34SHans Petter Selasky 	int err = 0;
7497549c34SHans Petter Selasky 
7597549c34SHans Petter Selasky 	err = mlx4_cmd(dev, regid, 0, 0,
7697549c34SHans Petter Selasky 		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
7797549c34SHans Petter Selasky 		       MLX4_CMD_NATIVE);
7897549c34SHans Petter Selasky 
7997549c34SHans Petter Selasky 	return err;
8097549c34SHans Petter Selasky }
8197549c34SHans Petter Selasky 
mlx4_READ_ENTRY(struct mlx4_dev * dev,int index,struct mlx4_cmd_mailbox * mailbox)8297549c34SHans Petter Selasky static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index,
8397549c34SHans Petter Selasky 			   struct mlx4_cmd_mailbox *mailbox)
8497549c34SHans Petter Selasky {
8597549c34SHans Petter Selasky 	return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG,
8697549c34SHans Petter Selasky 			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
8797549c34SHans Petter Selasky }
8897549c34SHans Petter Selasky 
mlx4_WRITE_ENTRY(struct mlx4_dev * dev,int index,struct mlx4_cmd_mailbox * mailbox)8997549c34SHans Petter Selasky static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index,
9097549c34SHans Petter Selasky 			    struct mlx4_cmd_mailbox *mailbox)
9197549c34SHans Petter Selasky {
9297549c34SHans Petter Selasky 	return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG,
9397549c34SHans Petter Selasky 			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
9497549c34SHans Petter Selasky }
9597549c34SHans Petter Selasky 
mlx4_WRITE_PROMISC(struct mlx4_dev * dev,u8 port,u8 steer,struct mlx4_cmd_mailbox * mailbox)9697549c34SHans Petter Selasky static int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer,
9797549c34SHans Petter Selasky 			      struct mlx4_cmd_mailbox *mailbox)
9897549c34SHans Petter Selasky {
9997549c34SHans Petter Selasky 	u32 in_mod;
10097549c34SHans Petter Selasky 
10197549c34SHans Petter Selasky 	in_mod = (u32) port << 16 | steer << 1;
10297549c34SHans Petter Selasky 	return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1,
10397549c34SHans Petter Selasky 			MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A,
10497549c34SHans Petter Selasky 			MLX4_CMD_NATIVE);
10597549c34SHans Petter Selasky }
10697549c34SHans Petter Selasky 
mlx4_GID_HASH(struct mlx4_dev * dev,struct mlx4_cmd_mailbox * mailbox,u16 * hash,u8 op_mod)10797549c34SHans Petter Selasky static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
10897549c34SHans Petter Selasky 			 u16 *hash, u8 op_mod)
10997549c34SHans Petter Selasky {
11097549c34SHans Petter Selasky 	u64 imm;
11197549c34SHans Petter Selasky 	int err;
11297549c34SHans Petter Selasky 
11397549c34SHans Petter Selasky 	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod,
11497549c34SHans Petter Selasky 			   MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A,
11597549c34SHans Petter Selasky 			   MLX4_CMD_NATIVE);
11697549c34SHans Petter Selasky 
11797549c34SHans Petter Selasky 	if (!err)
11897549c34SHans Petter Selasky 		*hash = imm;
11997549c34SHans Petter Selasky 
12097549c34SHans Petter Selasky 	return err;
12197549c34SHans Petter Selasky }
12297549c34SHans Petter Selasky 
get_promisc_qp(struct mlx4_dev * dev,u8 port,enum mlx4_steer_type steer,u32 qpn)12397549c34SHans Petter Selasky static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port,
12497549c34SHans Petter Selasky 					      enum mlx4_steer_type steer,
12597549c34SHans Petter Selasky 					      u32 qpn)
12697549c34SHans Petter Selasky {
12797549c34SHans Petter Selasky 	struct mlx4_steer *s_steer;
12897549c34SHans Petter Selasky 	struct mlx4_promisc_qp *pqp;
12997549c34SHans Petter Selasky 
13097549c34SHans Petter Selasky 	if (port < 1 || port > dev->caps.num_ports)
13197549c34SHans Petter Selasky 		return NULL;
13297549c34SHans Petter Selasky 
13397549c34SHans Petter Selasky 	s_steer = &mlx4_priv(dev)->steer[port - 1];
13497549c34SHans Petter Selasky 
13597549c34SHans Petter Selasky 	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
13697549c34SHans Petter Selasky 		if (pqp->qpn == qpn)
13797549c34SHans Petter Selasky 			return pqp;
13897549c34SHans Petter Selasky 	}
13997549c34SHans Petter Selasky 	/* not found */
14097549c34SHans Petter Selasky 	return NULL;
14197549c34SHans Petter Selasky }
14297549c34SHans Petter Selasky 
14397549c34SHans Petter Selasky /*
14497549c34SHans Petter Selasky  * Add new entry to steering data structure.
14597549c34SHans Petter Selasky  * All promisc QPs should be added as well
14697549c34SHans Petter Selasky  */
new_steering_entry(struct mlx4_dev * dev,u8 port,enum mlx4_steer_type steer,unsigned int index,u32 qpn)14797549c34SHans Petter Selasky static int new_steering_entry(struct mlx4_dev *dev, u8 port,
14897549c34SHans Petter Selasky 			      enum mlx4_steer_type steer,
14997549c34SHans Petter Selasky 			      unsigned int index, u32 qpn)
15097549c34SHans Petter Selasky {
15197549c34SHans Petter Selasky 	struct mlx4_steer *s_steer;
15297549c34SHans Petter Selasky 	struct mlx4_cmd_mailbox *mailbox;
15397549c34SHans Petter Selasky 	struct mlx4_mgm *mgm;
15497549c34SHans Petter Selasky 	u32 members_count;
15597549c34SHans Petter Selasky 	struct mlx4_steer_index *new_entry;
15697549c34SHans Petter Selasky 	struct mlx4_promisc_qp *pqp;
15797549c34SHans Petter Selasky 	struct mlx4_promisc_qp *dqp = NULL;
15897549c34SHans Petter Selasky 	u32 prot;
15997549c34SHans Petter Selasky 	int err;
16097549c34SHans Petter Selasky 
16197549c34SHans Petter Selasky 	if (port < 1 || port > dev->caps.num_ports)
16297549c34SHans Petter Selasky 		return -EINVAL;
16397549c34SHans Petter Selasky 
16497549c34SHans Petter Selasky 	s_steer = &mlx4_priv(dev)->steer[port - 1];
16597549c34SHans Petter Selasky 	new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL);
16697549c34SHans Petter Selasky 	if (!new_entry)
16797549c34SHans Petter Selasky 		return -ENOMEM;
16897549c34SHans Petter Selasky 
16997549c34SHans Petter Selasky 	INIT_LIST_HEAD(&new_entry->duplicates);
17097549c34SHans Petter Selasky 	new_entry->index = index;
17197549c34SHans Petter Selasky 	list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]);
17297549c34SHans Petter Selasky 
17397549c34SHans Petter Selasky 	/* If the given qpn is also a promisc qp,
17497549c34SHans Petter Selasky 	 * it should be inserted to duplicates list
17597549c34SHans Petter Selasky 	 */
17697549c34SHans Petter Selasky 	pqp = get_promisc_qp(dev, port, steer, qpn);
17797549c34SHans Petter Selasky 	if (pqp) {
17897549c34SHans Petter Selasky 		dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
17997549c34SHans Petter Selasky 		if (!dqp) {
18097549c34SHans Petter Selasky 			err = -ENOMEM;
18197549c34SHans Petter Selasky 			goto out_alloc;
18297549c34SHans Petter Selasky 		}
18397549c34SHans Petter Selasky 		dqp->qpn = qpn;
18497549c34SHans Petter Selasky 		list_add_tail(&dqp->list, &new_entry->duplicates);
18597549c34SHans Petter Selasky 	}
18697549c34SHans Petter Selasky 
18797549c34SHans Petter Selasky 	/* if no promisc qps for this vep, we are done */
18897549c34SHans Petter Selasky 	if (list_empty(&s_steer->promisc_qps[steer]))
18997549c34SHans Petter Selasky 		return 0;
19097549c34SHans Petter Selasky 
19197549c34SHans Petter Selasky 	/* now need to add all the promisc qps to the new
19297549c34SHans Petter Selasky 	 * steering entry, as they should also receive the packets
19397549c34SHans Petter Selasky 	 * destined to this address */
19497549c34SHans Petter Selasky 	mailbox = mlx4_alloc_cmd_mailbox(dev);
19597549c34SHans Petter Selasky 	if (IS_ERR(mailbox)) {
19697549c34SHans Petter Selasky 		err = -ENOMEM;
19797549c34SHans Petter Selasky 		goto out_alloc;
19897549c34SHans Petter Selasky 	}
19997549c34SHans Petter Selasky 	mgm = mailbox->buf;
20097549c34SHans Petter Selasky 
20197549c34SHans Petter Selasky 	err = mlx4_READ_ENTRY(dev, index, mailbox);
20297549c34SHans Petter Selasky 	if (err)
20397549c34SHans Petter Selasky 		goto out_mailbox;
20497549c34SHans Petter Selasky 
20597549c34SHans Petter Selasky 	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
20697549c34SHans Petter Selasky 	prot = be32_to_cpu(mgm->members_count) >> 30;
20797549c34SHans Petter Selasky 	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
20897549c34SHans Petter Selasky 		/* don't add already existing qpn */
20997549c34SHans Petter Selasky 		if (pqp->qpn == qpn)
21097549c34SHans Petter Selasky 			continue;
21197549c34SHans Petter Selasky 		if (members_count == dev->caps.num_qp_per_mgm) {
21297549c34SHans Petter Selasky 			/* out of space */
21397549c34SHans Petter Selasky 			err = -ENOMEM;
21497549c34SHans Petter Selasky 			goto out_mailbox;
21597549c34SHans Petter Selasky 		}
21697549c34SHans Petter Selasky 
21797549c34SHans Petter Selasky 		/* add the qpn */
21897549c34SHans Petter Selasky 		mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK);
21997549c34SHans Petter Selasky 	}
22097549c34SHans Petter Selasky 	/* update the qps count and update the entry with all the promisc qps*/
22197549c34SHans Petter Selasky 	mgm->members_count = cpu_to_be32(members_count | (prot << 30));
22297549c34SHans Petter Selasky 	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
22397549c34SHans Petter Selasky 
22497549c34SHans Petter Selasky out_mailbox:
22597549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
22697549c34SHans Petter Selasky 	if (!err)
22797549c34SHans Petter Selasky 		return 0;
22897549c34SHans Petter Selasky out_alloc:
22997549c34SHans Petter Selasky 	if (dqp) {
23097549c34SHans Petter Selasky 		list_del(&dqp->list);
23197549c34SHans Petter Selasky 		kfree(dqp);
23297549c34SHans Petter Selasky 	}
23397549c34SHans Petter Selasky 	list_del(&new_entry->list);
23497549c34SHans Petter Selasky 	kfree(new_entry);
23597549c34SHans Petter Selasky 	return err;
23697549c34SHans Petter Selasky }
23797549c34SHans Petter Selasky 
23897549c34SHans Petter Selasky /* update the data structures with existing steering entry */
existing_steering_entry(struct mlx4_dev * dev,u8 port,enum mlx4_steer_type steer,unsigned int index,u32 qpn)23997549c34SHans Petter Selasky static int existing_steering_entry(struct mlx4_dev *dev, u8 port,
24097549c34SHans Petter Selasky 				   enum mlx4_steer_type steer,
24197549c34SHans Petter Selasky 				   unsigned int index, u32 qpn)
24297549c34SHans Petter Selasky {
24397549c34SHans Petter Selasky 	struct mlx4_steer *s_steer;
24497549c34SHans Petter Selasky 	struct mlx4_steer_index *tmp_entry, *entry = NULL;
24597549c34SHans Petter Selasky 	struct mlx4_promisc_qp *pqp;
24697549c34SHans Petter Selasky 	struct mlx4_promisc_qp *dqp;
24797549c34SHans Petter Selasky 
24897549c34SHans Petter Selasky 	if (port < 1 || port > dev->caps.num_ports)
24997549c34SHans Petter Selasky 		return -EINVAL;
25097549c34SHans Petter Selasky 
25197549c34SHans Petter Selasky 	s_steer = &mlx4_priv(dev)->steer[port - 1];
25297549c34SHans Petter Selasky 
25397549c34SHans Petter Selasky 	pqp = get_promisc_qp(dev, port, steer, qpn);
25497549c34SHans Petter Selasky 	if (!pqp)
25597549c34SHans Petter Selasky 		return 0; /* nothing to do */
25697549c34SHans Petter Selasky 
25797549c34SHans Petter Selasky 	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
25897549c34SHans Petter Selasky 		if (tmp_entry->index == index) {
25997549c34SHans Petter Selasky 			entry = tmp_entry;
26097549c34SHans Petter Selasky 			break;
26197549c34SHans Petter Selasky 		}
26297549c34SHans Petter Selasky 	}
26397549c34SHans Petter Selasky 	if (unlikely(!entry)) {
26497549c34SHans Petter Selasky 		mlx4_warn(dev, "Steering entry at index %x is not registered\n", index);
26597549c34SHans Petter Selasky 		return -EINVAL;
26697549c34SHans Petter Selasky 	}
26797549c34SHans Petter Selasky 
26897549c34SHans Petter Selasky 	/* the given qpn is listed as a promisc qpn
26997549c34SHans Petter Selasky 	 * we need to add it as a duplicate to this entry
27097549c34SHans Petter Selasky 	 * for future references */
27197549c34SHans Petter Selasky 	list_for_each_entry(dqp, &entry->duplicates, list) {
27297549c34SHans Petter Selasky 		if (qpn == dqp->qpn)
27397549c34SHans Petter Selasky 			return 0; /* qp is already duplicated */
27497549c34SHans Petter Selasky 	}
27597549c34SHans Petter Selasky 
27697549c34SHans Petter Selasky 	/* add the qp as a duplicate on this index */
27797549c34SHans Petter Selasky 	dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
27897549c34SHans Petter Selasky 	if (!dqp)
27997549c34SHans Petter Selasky 		return -ENOMEM;
28097549c34SHans Petter Selasky 	dqp->qpn = qpn;
28197549c34SHans Petter Selasky 	list_add_tail(&dqp->list, &entry->duplicates);
28297549c34SHans Petter Selasky 
28397549c34SHans Petter Selasky 	return 0;
28497549c34SHans Petter Selasky }
28597549c34SHans Petter Selasky 
28697549c34SHans Petter Selasky /* Check whether a qpn is a duplicate on steering entry
28797549c34SHans Petter Selasky  * If so, it should not be removed from mgm */
check_duplicate_entry(struct mlx4_dev * dev,u8 port,enum mlx4_steer_type steer,unsigned int index,u32 qpn)28897549c34SHans Petter Selasky static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port,
28997549c34SHans Petter Selasky 				  enum mlx4_steer_type steer,
29097549c34SHans Petter Selasky 				  unsigned int index, u32 qpn)
29197549c34SHans Petter Selasky {
29297549c34SHans Petter Selasky 	struct mlx4_steer *s_steer;
29397549c34SHans Petter Selasky 	struct mlx4_steer_index *tmp_entry, *entry = NULL;
29497549c34SHans Petter Selasky 	struct mlx4_promisc_qp *dqp, *tmp_dqp;
29597549c34SHans Petter Selasky 
29697549c34SHans Petter Selasky 	if (port < 1 || port > dev->caps.num_ports)
29797549c34SHans Petter Selasky 		return NULL;
29897549c34SHans Petter Selasky 
29997549c34SHans Petter Selasky 	s_steer = &mlx4_priv(dev)->steer[port - 1];
30097549c34SHans Petter Selasky 
30197549c34SHans Petter Selasky 	/* if qp is not promisc, it cannot be duplicated */
30297549c34SHans Petter Selasky 	if (!get_promisc_qp(dev, port, steer, qpn))
30397549c34SHans Petter Selasky 		return false;
30497549c34SHans Petter Selasky 
30597549c34SHans Petter Selasky 	/* The qp is promisc qp so it is a duplicate on this index
30697549c34SHans Petter Selasky 	 * Find the index entry, and remove the duplicate */
30797549c34SHans Petter Selasky 	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
30897549c34SHans Petter Selasky 		if (tmp_entry->index == index) {
30997549c34SHans Petter Selasky 			entry = tmp_entry;
31097549c34SHans Petter Selasky 			break;
31197549c34SHans Petter Selasky 		}
31297549c34SHans Petter Selasky 	}
31397549c34SHans Petter Selasky 	if (unlikely(!entry)) {
31497549c34SHans Petter Selasky 		mlx4_warn(dev, "Steering entry for index %x is not registered\n", index);
31597549c34SHans Petter Selasky 		return false;
31697549c34SHans Petter Selasky 	}
31797549c34SHans Petter Selasky 	list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) {
31897549c34SHans Petter Selasky 		if (dqp->qpn == qpn) {
31997549c34SHans Petter Selasky 			list_del(&dqp->list);
32097549c34SHans Petter Selasky 			kfree(dqp);
32197549c34SHans Petter Selasky 		}
32297549c34SHans Petter Selasky 	}
32397549c34SHans Petter Selasky 	return true;
32497549c34SHans Petter Selasky }
32597549c34SHans Petter Selasky 
326c3191c2eSHans Petter Selasky /* Returns true if all the QPs != tqpn contained in this entry
327c3191c2eSHans Petter Selasky  * are Promisc QPs. Returns false otherwise.
32897549c34SHans Petter Selasky  */
promisc_steering_entry(struct mlx4_dev * dev,u8 port,enum mlx4_steer_type steer,unsigned int index,u32 tqpn,u32 * members_count)32997549c34SHans Petter Selasky static bool promisc_steering_entry(struct mlx4_dev *dev, u8 port,
33097549c34SHans Petter Selasky 				   enum mlx4_steer_type steer,
331c3191c2eSHans Petter Selasky 				   unsigned int index, u32 tqpn,
332c3191c2eSHans Petter Selasky 				   u32 *members_count)
33397549c34SHans Petter Selasky {
33497549c34SHans Petter Selasky 	struct mlx4_cmd_mailbox *mailbox;
33597549c34SHans Petter Selasky 	struct mlx4_mgm *mgm;
33697549c34SHans Petter Selasky 	u32 m_count;
33797549c34SHans Petter Selasky 	bool ret = false;
33897549c34SHans Petter Selasky 	int i;
33997549c34SHans Petter Selasky 
34097549c34SHans Petter Selasky 	if (port < 1 || port > dev->caps.num_ports)
34197549c34SHans Petter Selasky 		return false;
34297549c34SHans Petter Selasky 
34397549c34SHans Petter Selasky 	mailbox = mlx4_alloc_cmd_mailbox(dev);
34497549c34SHans Petter Selasky 	if (IS_ERR(mailbox))
34597549c34SHans Petter Selasky 		return false;
34697549c34SHans Petter Selasky 	mgm = mailbox->buf;
34797549c34SHans Petter Selasky 
34897549c34SHans Petter Selasky 	if (mlx4_READ_ENTRY(dev, index, mailbox))
34997549c34SHans Petter Selasky 		goto out;
35097549c34SHans Petter Selasky 	m_count = be32_to_cpu(mgm->members_count) & 0xffffff;
35197549c34SHans Petter Selasky 	if (members_count)
35297549c34SHans Petter Selasky 		*members_count = m_count;
35397549c34SHans Petter Selasky 
35497549c34SHans Petter Selasky 	for (i = 0;  i < m_count; i++) {
35597549c34SHans Petter Selasky 		u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
35697549c34SHans Petter Selasky 		if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) {
35797549c34SHans Petter Selasky 			/* the qp is not promisc, the entry can't be removed */
35897549c34SHans Petter Selasky 			goto out;
35997549c34SHans Petter Selasky 		}
36097549c34SHans Petter Selasky 	}
36197549c34SHans Petter Selasky 	ret = true;
36297549c34SHans Petter Selasky out:
36397549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
36497549c34SHans Petter Selasky 	return ret;
36597549c34SHans Petter Selasky }
36697549c34SHans Petter Selasky 
36797549c34SHans Petter Selasky /* IF a steering entry contains only promisc QPs, it can be removed. */
can_remove_steering_entry(struct mlx4_dev * dev,u8 port,enum mlx4_steer_type steer,unsigned int index,u32 tqpn)36897549c34SHans Petter Selasky static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
36997549c34SHans Petter Selasky 				      enum mlx4_steer_type steer,
37097549c34SHans Petter Selasky 				      unsigned int index, u32 tqpn)
37197549c34SHans Petter Selasky {
37297549c34SHans Petter Selasky 	struct mlx4_steer *s_steer;
37397549c34SHans Petter Selasky 	struct mlx4_steer_index *entry = NULL, *tmp_entry;
37497549c34SHans Petter Selasky 	u32 members_count;
37597549c34SHans Petter Selasky 	bool ret = false;
37697549c34SHans Petter Selasky 
37797549c34SHans Petter Selasky 	if (port < 1 || port > dev->caps.num_ports)
37897549c34SHans Petter Selasky 		return NULL;
37997549c34SHans Petter Selasky 
38097549c34SHans Petter Selasky 	s_steer = &mlx4_priv(dev)->steer[port - 1];
38197549c34SHans Petter Selasky 
382c3191c2eSHans Petter Selasky 	if (!promisc_steering_entry(dev, port, steer, index,
383c3191c2eSHans Petter Selasky 				    tqpn, &members_count))
38497549c34SHans Petter Selasky 		goto out;
38597549c34SHans Petter Selasky 
38697549c34SHans Petter Selasky 	/* All the qps currently registered for this entry are promiscuous,
38797549c34SHans Petter Selasky 	  * Checking for duplicates */
38897549c34SHans Petter Selasky 	ret = true;
38997549c34SHans Petter Selasky 	list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
39097549c34SHans Petter Selasky 		if (entry->index == index) {
391c3191c2eSHans Petter Selasky 			if (list_empty(&entry->duplicates) ||
392c3191c2eSHans Petter Selasky 			    members_count == 1) {
39397549c34SHans Petter Selasky 				struct mlx4_promisc_qp *pqp, *tmp_pqp;
394c3191c2eSHans Petter Selasky 				/* If there is only 1 entry in duplicates then
39597549c34SHans Petter Selasky 				 * this is the QP we want to delete, going over
39697549c34SHans Petter Selasky 				 * the list and deleting the entry.
39797549c34SHans Petter Selasky 				 */
39897549c34SHans Petter Selasky 				list_del(&entry->list);
39997549c34SHans Petter Selasky 				list_for_each_entry_safe(pqp, tmp_pqp,
40097549c34SHans Petter Selasky 							 &entry->duplicates,
40197549c34SHans Petter Selasky 							 list) {
40297549c34SHans Petter Selasky 					list_del(&pqp->list);
40397549c34SHans Petter Selasky 					kfree(pqp);
40497549c34SHans Petter Selasky 				}
40597549c34SHans Petter Selasky 				kfree(entry);
40697549c34SHans Petter Selasky 			} else {
40797549c34SHans Petter Selasky 				/* This entry contains duplicates so it shouldn't be removed */
40897549c34SHans Petter Selasky 				ret = false;
40997549c34SHans Petter Selasky 				goto out;
41097549c34SHans Petter Selasky 			}
41197549c34SHans Petter Selasky 		}
41297549c34SHans Petter Selasky 	}
41397549c34SHans Petter Selasky 
41497549c34SHans Petter Selasky out:
41597549c34SHans Petter Selasky 	return ret;
41697549c34SHans Petter Selasky }
41797549c34SHans Petter Selasky 
add_promisc_qp(struct mlx4_dev * dev,u8 port,enum mlx4_steer_type steer,u32 qpn)41897549c34SHans Petter Selasky static int add_promisc_qp(struct mlx4_dev *dev, u8 port,
41997549c34SHans Petter Selasky 			  enum mlx4_steer_type steer, u32 qpn)
42097549c34SHans Petter Selasky {
42197549c34SHans Petter Selasky 	struct mlx4_steer *s_steer;
42297549c34SHans Petter Selasky 	struct mlx4_cmd_mailbox *mailbox;
42397549c34SHans Petter Selasky 	struct mlx4_mgm *mgm;
42497549c34SHans Petter Selasky 	struct mlx4_steer_index *entry;
42597549c34SHans Petter Selasky 	struct mlx4_promisc_qp *pqp;
42697549c34SHans Petter Selasky 	struct mlx4_promisc_qp *dqp;
42797549c34SHans Petter Selasky 	u32 members_count;
42897549c34SHans Petter Selasky 	u32 prot;
42997549c34SHans Petter Selasky 	int i;
43097549c34SHans Petter Selasky 	bool found;
43197549c34SHans Petter Selasky 	int err;
43297549c34SHans Petter Selasky 	struct mlx4_priv *priv = mlx4_priv(dev);
43397549c34SHans Petter Selasky 
43497549c34SHans Petter Selasky 	if (port < 1 || port > dev->caps.num_ports)
43597549c34SHans Petter Selasky 		return -EINVAL;
43697549c34SHans Petter Selasky 
43797549c34SHans Petter Selasky 	s_steer = &mlx4_priv(dev)->steer[port - 1];
43897549c34SHans Petter Selasky 
43997549c34SHans Petter Selasky 	mutex_lock(&priv->mcg_table.mutex);
44097549c34SHans Petter Selasky 
44197549c34SHans Petter Selasky 	if (get_promisc_qp(dev, port, steer, qpn)) {
44297549c34SHans Petter Selasky 		err = 0;  /* Noting to do, already exists */
44397549c34SHans Petter Selasky 		goto out_mutex;
44497549c34SHans Petter Selasky 	}
44597549c34SHans Petter Selasky 
44697549c34SHans Petter Selasky 	pqp = kmalloc(sizeof *pqp, GFP_KERNEL);
44797549c34SHans Petter Selasky 	if (!pqp) {
44897549c34SHans Petter Selasky 		err = -ENOMEM;
44997549c34SHans Petter Selasky 		goto out_mutex;
45097549c34SHans Petter Selasky 	}
45197549c34SHans Petter Selasky 	pqp->qpn = qpn;
45297549c34SHans Petter Selasky 
45397549c34SHans Petter Selasky 	mailbox = mlx4_alloc_cmd_mailbox(dev);
45497549c34SHans Petter Selasky 	if (IS_ERR(mailbox)) {
45597549c34SHans Petter Selasky 		err = -ENOMEM;
45697549c34SHans Petter Selasky 		goto out_alloc;
45797549c34SHans Petter Selasky 	}
45897549c34SHans Petter Selasky 	mgm = mailbox->buf;
45997549c34SHans Petter Selasky 
46097549c34SHans Petter Selasky 	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
461c3191c2eSHans Petter Selasky 		/* The promisc QP needs to be added for each one of the steering
462c3191c2eSHans Petter Selasky 		 * entries. If it already exists, needs to be added as
463c3191c2eSHans Petter Selasky 		 * a duplicate for this entry.
464c3191c2eSHans Petter Selasky 		 */
465c3191c2eSHans Petter Selasky 		list_for_each_entry(entry,
466c3191c2eSHans Petter Selasky 				    &s_steer->steer_entries[steer],
467c3191c2eSHans Petter Selasky 				    list) {
46897549c34SHans Petter Selasky 			err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
46997549c34SHans Petter Selasky 			if (err)
47097549c34SHans Petter Selasky 				goto out_mailbox;
47197549c34SHans Petter Selasky 
472c3191c2eSHans Petter Selasky 			members_count = be32_to_cpu(mgm->members_count) &
473c3191c2eSHans Petter Selasky 					0xffffff;
47497549c34SHans Petter Selasky 			prot = be32_to_cpu(mgm->members_count) >> 30;
47597549c34SHans Petter Selasky 			found = false;
47697549c34SHans Petter Selasky 			for (i = 0; i < members_count; i++) {
477c3191c2eSHans Petter Selasky 				if ((be32_to_cpu(mgm->qp[i]) &
478c3191c2eSHans Petter Selasky 				     MGM_QPN_MASK) == qpn) {
479c3191c2eSHans Petter Selasky 					/* Entry already exists.
480c3191c2eSHans Petter Selasky 					 * Add to duplicates.
481c3191c2eSHans Petter Selasky 					 */
482c3191c2eSHans Petter Selasky 					dqp = kmalloc(sizeof(*dqp), GFP_KERNEL);
48397549c34SHans Petter Selasky 					if (!dqp) {
48497549c34SHans Petter Selasky 						err = -ENOMEM;
48597549c34SHans Petter Selasky 						goto out_mailbox;
48697549c34SHans Petter Selasky 					}
48797549c34SHans Petter Selasky 					dqp->qpn = qpn;
488c3191c2eSHans Petter Selasky 					list_add_tail(&dqp->list,
489c3191c2eSHans Petter Selasky 						      &entry->duplicates);
49097549c34SHans Petter Selasky 					found = true;
49197549c34SHans Petter Selasky 				}
49297549c34SHans Petter Selasky 			}
49397549c34SHans Petter Selasky 			if (!found) {
49497549c34SHans Petter Selasky 				/* Need to add the qpn to mgm */
495c3191c2eSHans Petter Selasky 				if (members_count ==
496c3191c2eSHans Petter Selasky 				    dev->caps.num_qp_per_mgm) {
49797549c34SHans Petter Selasky 					/* entry is full */
49897549c34SHans Petter Selasky 					err = -ENOMEM;
49997549c34SHans Petter Selasky 					goto out_mailbox;
50097549c34SHans Petter Selasky 				}
501c3191c2eSHans Petter Selasky 				mgm->qp[members_count++] =
502c3191c2eSHans Petter Selasky 					cpu_to_be32(qpn & MGM_QPN_MASK);
503c3191c2eSHans Petter Selasky 				mgm->members_count =
504c3191c2eSHans Petter Selasky 					cpu_to_be32(members_count |
505c3191c2eSHans Petter Selasky 						    (prot << 30));
506c3191c2eSHans Petter Selasky 				err = mlx4_WRITE_ENTRY(dev, entry->index,
507c3191c2eSHans Petter Selasky 						       mailbox);
50897549c34SHans Petter Selasky 				if (err)
50997549c34SHans Petter Selasky 					goto out_mailbox;
51097549c34SHans Petter Selasky 			}
51197549c34SHans Petter Selasky 		}
51297549c34SHans Petter Selasky 	}
51397549c34SHans Petter Selasky 
51497549c34SHans Petter Selasky 	/* add the new qpn to list of promisc qps */
51597549c34SHans Petter Selasky 	list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
51697549c34SHans Petter Selasky 	/* now need to add all the promisc qps to default entry */
51797549c34SHans Petter Selasky 	memset(mgm, 0, sizeof *mgm);
51897549c34SHans Petter Selasky 	members_count = 0;
51997549c34SHans Petter Selasky 	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) {
52097549c34SHans Petter Selasky 		if (members_count == dev->caps.num_qp_per_mgm) {
52197549c34SHans Petter Selasky 			/* entry is full */
52297549c34SHans Petter Selasky 			err = -ENOMEM;
52397549c34SHans Petter Selasky 			goto out_list;
52497549c34SHans Petter Selasky 		}
52597549c34SHans Petter Selasky 		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
52697549c34SHans Petter Selasky 	}
52797549c34SHans Petter Selasky 	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
52897549c34SHans Petter Selasky 
52997549c34SHans Petter Selasky 	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
53097549c34SHans Petter Selasky 	if (err)
53197549c34SHans Petter Selasky 		goto out_list;
53297549c34SHans Petter Selasky 
53397549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
53497549c34SHans Petter Selasky 	mutex_unlock(&priv->mcg_table.mutex);
53597549c34SHans Petter Selasky 	return 0;
53697549c34SHans Petter Selasky 
53797549c34SHans Petter Selasky out_list:
53897549c34SHans Petter Selasky 	list_del(&pqp->list);
53997549c34SHans Petter Selasky out_mailbox:
54097549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
54197549c34SHans Petter Selasky out_alloc:
54297549c34SHans Petter Selasky 	kfree(pqp);
54397549c34SHans Petter Selasky out_mutex:
54497549c34SHans Petter Selasky 	mutex_unlock(&priv->mcg_table.mutex);
54597549c34SHans Petter Selasky 	return err;
54697549c34SHans Petter Selasky }
54797549c34SHans Petter Selasky 
remove_promisc_qp(struct mlx4_dev * dev,u8 port,enum mlx4_steer_type steer,u32 qpn)54897549c34SHans Petter Selasky static int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
54997549c34SHans Petter Selasky 			     enum mlx4_steer_type steer, u32 qpn)
55097549c34SHans Petter Selasky {
55197549c34SHans Petter Selasky 	struct mlx4_priv *priv = mlx4_priv(dev);
55297549c34SHans Petter Selasky 	struct mlx4_steer *s_steer;
55397549c34SHans Petter Selasky 	struct mlx4_cmd_mailbox *mailbox;
55497549c34SHans Petter Selasky 	struct mlx4_mgm *mgm;
55597549c34SHans Petter Selasky 	struct mlx4_steer_index *entry, *tmp_entry;
55697549c34SHans Petter Selasky 	struct mlx4_promisc_qp *pqp;
55797549c34SHans Petter Selasky 	struct mlx4_promisc_qp *dqp;
55897549c34SHans Petter Selasky 	u32 members_count;
55997549c34SHans Petter Selasky 	bool found;
56097549c34SHans Petter Selasky 	bool back_to_list = false;
561c3191c2eSHans Petter Selasky 	int i;
56297549c34SHans Petter Selasky 	int err;
56397549c34SHans Petter Selasky 
56497549c34SHans Petter Selasky 	if (port < 1 || port > dev->caps.num_ports)
56597549c34SHans Petter Selasky 		return -EINVAL;
56697549c34SHans Petter Selasky 
56797549c34SHans Petter Selasky 	s_steer = &mlx4_priv(dev)->steer[port - 1];
56897549c34SHans Petter Selasky 	mutex_lock(&priv->mcg_table.mutex);
56997549c34SHans Petter Selasky 
57097549c34SHans Petter Selasky 	pqp = get_promisc_qp(dev, port, steer, qpn);
57197549c34SHans Petter Selasky 	if (unlikely(!pqp)) {
57297549c34SHans Petter Selasky 		mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn);
57397549c34SHans Petter Selasky 		/* nothing to do */
57497549c34SHans Petter Selasky 		err = 0;
57597549c34SHans Petter Selasky 		goto out_mutex;
57697549c34SHans Petter Selasky 	}
57797549c34SHans Petter Selasky 
57897549c34SHans Petter Selasky 	/*remove from list of promisc qps */
57997549c34SHans Petter Selasky 	list_del(&pqp->list);
58097549c34SHans Petter Selasky 
58197549c34SHans Petter Selasky 	/* set the default entry not to include the removed one */
58297549c34SHans Petter Selasky 	mailbox = mlx4_alloc_cmd_mailbox(dev);
58397549c34SHans Petter Selasky 	if (IS_ERR(mailbox)) {
58497549c34SHans Petter Selasky 		err = -ENOMEM;
58597549c34SHans Petter Selasky 		back_to_list = true;
58697549c34SHans Petter Selasky 		goto out_list;
58797549c34SHans Petter Selasky 	}
58897549c34SHans Petter Selasky 	mgm = mailbox->buf;
58997549c34SHans Petter Selasky 	members_count = 0;
59097549c34SHans Petter Selasky 	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
59197549c34SHans Petter Selasky 		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
59297549c34SHans Petter Selasky 	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
59397549c34SHans Petter Selasky 
59497549c34SHans Petter Selasky 	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
59597549c34SHans Petter Selasky 	if (err)
59697549c34SHans Petter Selasky 		goto out_mailbox;
59797549c34SHans Petter Selasky 
59897549c34SHans Petter Selasky 	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
599c3191c2eSHans Petter Selasky 		/* Remove the QP from all the steering entries */
600c3191c2eSHans Petter Selasky 		list_for_each_entry_safe(entry, tmp_entry,
601c3191c2eSHans Petter Selasky 					 &s_steer->steer_entries[steer],
602c3191c2eSHans Petter Selasky 					 list) {
60397549c34SHans Petter Selasky 			found = false;
60497549c34SHans Petter Selasky 			list_for_each_entry(dqp, &entry->duplicates, list) {
60597549c34SHans Petter Selasky 				if (dqp->qpn == qpn) {
60697549c34SHans Petter Selasky 					found = true;
60797549c34SHans Petter Selasky 					break;
60897549c34SHans Petter Selasky 				}
60997549c34SHans Petter Selasky 			}
61097549c34SHans Petter Selasky 			if (found) {
611c3191c2eSHans Petter Selasky 				/* A duplicate, no need to change the MGM,
612c3191c2eSHans Petter Selasky 				 * only update the duplicates list
613c3191c2eSHans Petter Selasky 				 */
61497549c34SHans Petter Selasky 				list_del(&dqp->list);
61597549c34SHans Petter Selasky 				kfree(dqp);
61697549c34SHans Petter Selasky 			} else {
617c3191c2eSHans Petter Selasky 				int loc = -1;
618c3191c2eSHans Petter Selasky 
619c3191c2eSHans Petter Selasky 				err = mlx4_READ_ENTRY(dev,
620c3191c2eSHans Petter Selasky 						      entry->index,
621c3191c2eSHans Petter Selasky 						      mailbox);
62297549c34SHans Petter Selasky 				if (err)
62397549c34SHans Petter Selasky 					goto out_mailbox;
624c3191c2eSHans Petter Selasky 				members_count =
625c3191c2eSHans Petter Selasky 					be32_to_cpu(mgm->members_count) &
626c3191c2eSHans Petter Selasky 					0xffffff;
62797549c34SHans Petter Selasky 				if (!members_count) {
628c3191c2eSHans Petter Selasky 					mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0. deleting entry...\n",
629c3191c2eSHans Petter Selasky 						  qpn, entry->index);
63097549c34SHans Petter Selasky 					list_del(&entry->list);
63197549c34SHans Petter Selasky 					kfree(entry);
63297549c34SHans Petter Selasky 					continue;
63397549c34SHans Petter Selasky 				}
63497549c34SHans Petter Selasky 
63597549c34SHans Petter Selasky 				for (i = 0; i < members_count; ++i)
636c3191c2eSHans Petter Selasky 					if ((be32_to_cpu(mgm->qp[i]) &
637c3191c2eSHans Petter Selasky 					     MGM_QPN_MASK) == qpn) {
63897549c34SHans Petter Selasky 						loc = i;
63997549c34SHans Petter Selasky 						break;
64097549c34SHans Petter Selasky 					}
64197549c34SHans Petter Selasky 
64297549c34SHans Petter Selasky 				if (loc < 0) {
64397549c34SHans Petter Selasky 					mlx4_err(dev, "QP %06x wasn't found in entry %d\n",
64497549c34SHans Petter Selasky 						 qpn, entry->index);
64597549c34SHans Petter Selasky 					err = -EINVAL;
64697549c34SHans Petter Selasky 					goto out_mailbox;
64797549c34SHans Petter Selasky 				}
64897549c34SHans Petter Selasky 
649c3191c2eSHans Petter Selasky 				/* Copy the last QP in this MGM
650c3191c2eSHans Petter Selasky 				 * over removed QP
651c3191c2eSHans Petter Selasky 				 */
65297549c34SHans Petter Selasky 				mgm->qp[loc] = mgm->qp[members_count - 1];
65397549c34SHans Petter Selasky 				mgm->qp[members_count - 1] = 0;
654c3191c2eSHans Petter Selasky 				mgm->members_count =
655c3191c2eSHans Petter Selasky 					cpu_to_be32(--members_count |
65697549c34SHans Petter Selasky 						    (MLX4_PROT_ETH << 30));
65797549c34SHans Petter Selasky 
658c3191c2eSHans Petter Selasky 				err = mlx4_WRITE_ENTRY(dev,
659c3191c2eSHans Petter Selasky 						       entry->index,
660c3191c2eSHans Petter Selasky 						       mailbox);
66197549c34SHans Petter Selasky 				if (err)
66297549c34SHans Petter Selasky 					goto out_mailbox;
66397549c34SHans Petter Selasky 			}
66497549c34SHans Petter Selasky 		}
66597549c34SHans Petter Selasky 	}
66697549c34SHans Petter Selasky 
66797549c34SHans Petter Selasky out_mailbox:
66897549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
66997549c34SHans Petter Selasky out_list:
67097549c34SHans Petter Selasky 	if (back_to_list)
67197549c34SHans Petter Selasky 		list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
67297549c34SHans Petter Selasky 	else
67397549c34SHans Petter Selasky 		kfree(pqp);
67497549c34SHans Petter Selasky out_mutex:
67597549c34SHans Petter Selasky 	mutex_unlock(&priv->mcg_table.mutex);
67697549c34SHans Petter Selasky 	return err;
67797549c34SHans Petter Selasky }
67897549c34SHans Petter Selasky 
67997549c34SHans Petter Selasky /*
68097549c34SHans Petter Selasky  * Caller must hold MCG table semaphore.  gid and mgm parameters must
68197549c34SHans Petter Selasky  * be properly aligned for command interface.
68297549c34SHans Petter Selasky  *
68397549c34SHans Petter Selasky  *  Returns 0 unless a firmware command error occurs.
68497549c34SHans Petter Selasky  *
68597549c34SHans Petter Selasky  * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
68697549c34SHans Petter Selasky  * and *mgm holds MGM entry.
68797549c34SHans Petter Selasky  *
68897549c34SHans Petter Selasky  * if GID is found in AMGM, *index = index in AMGM, *prev = index of
68997549c34SHans Petter Selasky  * previous entry in hash chain and *mgm holds AMGM entry.
69097549c34SHans Petter Selasky  *
69197549c34SHans Petter Selasky  * If no AMGM exists for given gid, *index = -1, *prev = index of last
69297549c34SHans Petter Selasky  * entry in hash chain and *mgm holds end of hash chain.
69397549c34SHans Petter Selasky  */
find_entry(struct mlx4_dev * dev,u8 port,u8 * gid,enum mlx4_protocol prot,struct mlx4_cmd_mailbox * mgm_mailbox,int * prev,int * index)69497549c34SHans Petter Selasky static int find_entry(struct mlx4_dev *dev, u8 port,
69597549c34SHans Petter Selasky 		      u8 *gid, enum mlx4_protocol prot,
69697549c34SHans Petter Selasky 		      struct mlx4_cmd_mailbox *mgm_mailbox,
69797549c34SHans Petter Selasky 		      int *prev, int *index)
69897549c34SHans Petter Selasky {
69997549c34SHans Petter Selasky 	struct mlx4_cmd_mailbox *mailbox;
70097549c34SHans Petter Selasky 	struct mlx4_mgm *mgm = mgm_mailbox->buf;
70197549c34SHans Petter Selasky 	u8 *mgid;
70297549c34SHans Petter Selasky 	int err;
70397549c34SHans Petter Selasky 	u16 hash;
70497549c34SHans Petter Selasky 	u8 op_mod = (prot == MLX4_PROT_ETH) ?
70597549c34SHans Petter Selasky 		!!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0;
70697549c34SHans Petter Selasky 
70797549c34SHans Petter Selasky 	mailbox = mlx4_alloc_cmd_mailbox(dev);
70897549c34SHans Petter Selasky 	if (IS_ERR(mailbox))
70997549c34SHans Petter Selasky 		return -ENOMEM;
71097549c34SHans Petter Selasky 	mgid = mailbox->buf;
71197549c34SHans Petter Selasky 
71297549c34SHans Petter Selasky 	memcpy(mgid, gid, 16);
71397549c34SHans Petter Selasky 
71497549c34SHans Petter Selasky 	err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod);
71597549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
71697549c34SHans Petter Selasky 	if (err)
71797549c34SHans Petter Selasky 		return err;
71897549c34SHans Petter Selasky 
71997549c34SHans Petter Selasky 	if (0) {
72097549c34SHans Petter Selasky 		mlx4_dbg(dev, "Hash for "GID_PRINT_FMT" is %04x\n",
72197549c34SHans Petter Selasky 		    GID_PRINT_ARGS(gid), hash);
72297549c34SHans Petter Selasky 	}
72397549c34SHans Petter Selasky 
72497549c34SHans Petter Selasky 	*index = hash;
72597549c34SHans Petter Selasky 	*prev  = -1;
72697549c34SHans Petter Selasky 
72797549c34SHans Petter Selasky 	do {
72897549c34SHans Petter Selasky 		err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox);
72997549c34SHans Petter Selasky 		if (err)
73097549c34SHans Petter Selasky 			return err;
73197549c34SHans Petter Selasky 
73297549c34SHans Petter Selasky 		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
73397549c34SHans Petter Selasky 			if (*index != hash) {
734c3191c2eSHans Petter Selasky 				mlx4_err(dev, "Found zero MGID in AMGM\n");
73597549c34SHans Petter Selasky 				err = -EINVAL;
73697549c34SHans Petter Selasky 			}
73797549c34SHans Petter Selasky 			return err;
73897549c34SHans Petter Selasky 		}
73997549c34SHans Petter Selasky 
74097549c34SHans Petter Selasky 		if (!memcmp(mgm->gid, gid, 16) &&
74197549c34SHans Petter Selasky 		    be32_to_cpu(mgm->members_count) >> 30 == prot)
74297549c34SHans Petter Selasky 			return err;
74397549c34SHans Petter Selasky 
74497549c34SHans Petter Selasky 		*prev = *index;
74597549c34SHans Petter Selasky 		*index = be32_to_cpu(mgm->next_gid_index) >> 6;
74697549c34SHans Petter Selasky 	} while (*index);
74797549c34SHans Petter Selasky 
74897549c34SHans Petter Selasky 	*index = -1;
74997549c34SHans Petter Selasky 	return err;
75097549c34SHans Petter Selasky }
75197549c34SHans Petter Selasky 
75297549c34SHans Petter Selasky static const u8 __promisc_mode[] = {
75397549c34SHans Petter Selasky 	[MLX4_FS_REGULAR]   = 0x0,
75497549c34SHans Petter Selasky 	[MLX4_FS_ALL_DEFAULT] = 0x1,
75597549c34SHans Petter Selasky 	[MLX4_FS_MC_DEFAULT] = 0x3,
756c3191c2eSHans Petter Selasky 	[MLX4_FS_MIRROR_RX_PORT] = 0x4,
757c3191c2eSHans Petter Selasky 	[MLX4_FS_MIRROR_SX_PORT] = 0x5,
758c3191c2eSHans Petter Selasky 	[MLX4_FS_UC_SNIFFER] = 0x6,
759c3191c2eSHans Petter Selasky 	[MLX4_FS_MC_SNIFFER] = 0x7,
76097549c34SHans Petter Selasky };
76197549c34SHans Petter Selasky 
mlx4_map_sw_to_hw_steering_mode(struct mlx4_dev * dev,enum mlx4_net_trans_promisc_mode flow_type)762c3191c2eSHans Petter Selasky int mlx4_map_sw_to_hw_steering_mode(struct mlx4_dev *dev,
76397549c34SHans Petter Selasky 				    enum mlx4_net_trans_promisc_mode flow_type)
76497549c34SHans Petter Selasky {
765c3191c2eSHans Petter Selasky 	if (flow_type >= MLX4_FS_MODE_NUM) {
76697549c34SHans Petter Selasky 		mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type);
76797549c34SHans Petter Selasky 		return -EINVAL;
76897549c34SHans Petter Selasky 	}
76997549c34SHans Petter Selasky 	return __promisc_mode[flow_type];
77097549c34SHans Petter Selasky }
771c3191c2eSHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_mode);
77297549c34SHans Petter Selasky 
trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule * ctrl,struct mlx4_net_trans_rule_hw_ctrl * hw)77397549c34SHans Petter Selasky static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,
77497549c34SHans Petter Selasky 				  struct mlx4_net_trans_rule_hw_ctrl *hw)
77597549c34SHans Petter Selasky {
77697549c34SHans Petter Selasky 	u8 flags = 0;
77797549c34SHans Petter Selasky 
77897549c34SHans Petter Selasky 	flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0;
77997549c34SHans Petter Selasky 	flags |= ctrl->exclusive ? (1 << 2) : 0;
78097549c34SHans Petter Selasky 	flags |= ctrl->allow_loopback ? (1 << 3) : 0;
78197549c34SHans Petter Selasky 
78297549c34SHans Petter Selasky 	hw->flags = flags;
78397549c34SHans Petter Selasky 	hw->type = __promisc_mode[ctrl->promisc_mode];
78497549c34SHans Petter Selasky 	hw->prio = cpu_to_be16(ctrl->priority);
78597549c34SHans Petter Selasky 	hw->port = ctrl->port;
78697549c34SHans Petter Selasky 	hw->qpn = cpu_to_be32(ctrl->qpn);
78797549c34SHans Petter Selasky }
78897549c34SHans Petter Selasky 
78997549c34SHans Petter Selasky const u16 __sw_id_hw[] = {
79097549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_ETH]     = 0xE001,
79197549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_IB]      = 0xE005,
79297549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_IPV6]    = 0xE003,
79397549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_IPV4]    = 0xE002,
79497549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_TCP]     = 0xE004,
795c3191c2eSHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_UDP]     = 0xE006,
796c3191c2eSHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_VXLAN]	 = 0xE008
79797549c34SHans Petter Selasky };
79897549c34SHans Petter Selasky 
mlx4_map_sw_to_hw_steering_id(struct mlx4_dev * dev,enum mlx4_net_trans_rule_id id)799c3191c2eSHans Petter Selasky int mlx4_map_sw_to_hw_steering_id(struct mlx4_dev *dev,
80097549c34SHans Petter Selasky 				  enum mlx4_net_trans_rule_id id)
80197549c34SHans Petter Selasky {
802c3191c2eSHans Petter Selasky 	if (id >= MLX4_NET_TRANS_RULE_NUM) {
80397549c34SHans Petter Selasky 		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
80497549c34SHans Petter Selasky 		return -EINVAL;
80597549c34SHans Petter Selasky 	}
80697549c34SHans Petter Selasky 	return __sw_id_hw[id];
80797549c34SHans Petter Selasky }
808c3191c2eSHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_id);
80997549c34SHans Petter Selasky 
81097549c34SHans Petter Selasky static const int __rule_hw_sz[] = {
81197549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_ETH] =
81297549c34SHans Petter Selasky 		sizeof(struct mlx4_net_trans_rule_hw_eth),
81397549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_IB] =
81497549c34SHans Petter Selasky 		sizeof(struct mlx4_net_trans_rule_hw_ib),
81597549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_IPV6] = 0,
81697549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_IPV4] =
81797549c34SHans Petter Selasky 		sizeof(struct mlx4_net_trans_rule_hw_ipv4),
81897549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_TCP] =
81997549c34SHans Petter Selasky 		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),
82097549c34SHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_UDP] =
821c3191c2eSHans Petter Selasky 		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),
822c3191c2eSHans Petter Selasky 	[MLX4_NET_TRANS_RULE_ID_VXLAN] =
823c3191c2eSHans Petter Selasky 		sizeof(struct mlx4_net_trans_rule_hw_vxlan)
82497549c34SHans Petter Selasky };
82597549c34SHans Petter Selasky 
mlx4_hw_rule_sz(struct mlx4_dev * dev,enum mlx4_net_trans_rule_id id)826c3191c2eSHans Petter Selasky int mlx4_hw_rule_sz(struct mlx4_dev *dev,
82797549c34SHans Petter Selasky 	       enum mlx4_net_trans_rule_id id)
82897549c34SHans Petter Selasky {
829c3191c2eSHans Petter Selasky 	if (id >= MLX4_NET_TRANS_RULE_NUM) {
83097549c34SHans Petter Selasky 		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
83197549c34SHans Petter Selasky 		return -EINVAL;
83297549c34SHans Petter Selasky 	}
83397549c34SHans Petter Selasky 
83497549c34SHans Petter Selasky 	return __rule_hw_sz[id];
83597549c34SHans Petter Selasky }
836c3191c2eSHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_hw_rule_sz);
83797549c34SHans Petter Selasky 
parse_trans_rule(struct mlx4_dev * dev,struct mlx4_spec_list * spec,struct _rule_hw * rule_hw)83897549c34SHans Petter Selasky static int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec,
83997549c34SHans Petter Selasky 			    struct _rule_hw *rule_hw)
84097549c34SHans Petter Selasky {
841c3191c2eSHans Petter Selasky 	if (mlx4_hw_rule_sz(dev, spec->id) < 0)
84297549c34SHans Petter Selasky 		return -EINVAL;
843c3191c2eSHans Petter Selasky 	memset(rule_hw, 0, mlx4_hw_rule_sz(dev, spec->id));
84497549c34SHans Petter Selasky 	rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]);
845c3191c2eSHans Petter Selasky 	rule_hw->size = mlx4_hw_rule_sz(dev, spec->id) >> 2;
84697549c34SHans Petter Selasky 
84797549c34SHans Petter Selasky 	switch (spec->id) {
84897549c34SHans Petter Selasky 	case MLX4_NET_TRANS_RULE_ID_ETH:
84997549c34SHans Petter Selasky 		memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN);
85097549c34SHans Petter Selasky 		memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk,
85197549c34SHans Petter Selasky 		       ETH_ALEN);
85297549c34SHans Petter Selasky 		memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN);
85397549c34SHans Petter Selasky 		memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk,
85497549c34SHans Petter Selasky 		       ETH_ALEN);
85597549c34SHans Petter Selasky 		if (spec->eth.ether_type_enable) {
85697549c34SHans Petter Selasky 			rule_hw->eth.ether_type_enable = 1;
85797549c34SHans Petter Selasky 			rule_hw->eth.ether_type = spec->eth.ether_type;
85897549c34SHans Petter Selasky 		}
85997549c34SHans Petter Selasky 		rule_hw->eth.vlan_tag = spec->eth.vlan_id;
86097549c34SHans Petter Selasky 		rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk;
86197549c34SHans Petter Selasky 		break;
86297549c34SHans Petter Selasky 
86397549c34SHans Petter Selasky 	case MLX4_NET_TRANS_RULE_ID_IB:
86497549c34SHans Petter Selasky 		rule_hw->ib.l3_qpn = spec->ib.l3_qpn;
86597549c34SHans Petter Selasky 		rule_hw->ib.qpn_mask = spec->ib.qpn_msk;
86697549c34SHans Petter Selasky 		memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16);
86797549c34SHans Petter Selasky 		memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16);
86897549c34SHans Petter Selasky 		break;
86997549c34SHans Petter Selasky 
87097549c34SHans Petter Selasky 	case MLX4_NET_TRANS_RULE_ID_IPV6:
87197549c34SHans Petter Selasky 		return -EOPNOTSUPP;
87297549c34SHans Petter Selasky 
87397549c34SHans Petter Selasky 	case MLX4_NET_TRANS_RULE_ID_IPV4:
87497549c34SHans Petter Selasky 		rule_hw->ipv4.src_ip = spec->ipv4.src_ip;
87597549c34SHans Petter Selasky 		rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk;
87697549c34SHans Petter Selasky 		rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip;
87797549c34SHans Petter Selasky 		rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk;
87897549c34SHans Petter Selasky 		break;
87997549c34SHans Petter Selasky 
88097549c34SHans Petter Selasky 	case MLX4_NET_TRANS_RULE_ID_TCP:
88197549c34SHans Petter Selasky 	case MLX4_NET_TRANS_RULE_ID_UDP:
88297549c34SHans Petter Selasky 		rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port;
88397549c34SHans Petter Selasky 		rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk;
88497549c34SHans Petter Selasky 		rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port;
88597549c34SHans Petter Selasky 		rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk;
88697549c34SHans Petter Selasky 		break;
88797549c34SHans Petter Selasky 
888c3191c2eSHans Petter Selasky 	case MLX4_NET_TRANS_RULE_ID_VXLAN:
889c3191c2eSHans Petter Selasky 		rule_hw->vxlan.vni =
890c3191c2eSHans Petter Selasky 			cpu_to_be32(be32_to_cpu(spec->vxlan.vni) << 8);
891c3191c2eSHans Petter Selasky 		rule_hw->vxlan.vni_mask =
892c3191c2eSHans Petter Selasky 			cpu_to_be32(be32_to_cpu(spec->vxlan.vni_mask) << 8);
893c3191c2eSHans Petter Selasky 		break;
894c3191c2eSHans Petter Selasky 
89597549c34SHans Petter Selasky 	default:
89697549c34SHans Petter Selasky 		return -EINVAL;
89797549c34SHans Petter Selasky 	}
89897549c34SHans Petter Selasky 
89997549c34SHans Petter Selasky 	return __rule_hw_sz[spec->id];
90097549c34SHans Petter Selasky }
90197549c34SHans Petter Selasky 
mlx4_err_rule(struct mlx4_dev * dev,char * str,struct mlx4_net_trans_rule * rule)90297549c34SHans Petter Selasky static void mlx4_err_rule(struct mlx4_dev *dev, char *str,
90397549c34SHans Petter Selasky 			  struct mlx4_net_trans_rule *rule)
90497549c34SHans Petter Selasky {
90597549c34SHans Petter Selasky #define BUF_SIZE 256
90697549c34SHans Petter Selasky 	struct mlx4_spec_list *cur;
90797549c34SHans Petter Selasky 	char buf[BUF_SIZE];
90897549c34SHans Petter Selasky 	int len = 0;
90997549c34SHans Petter Selasky 
91097549c34SHans Petter Selasky 	mlx4_err(dev, "%s", str);
91197549c34SHans Petter Selasky 	len += snprintf(buf + len, BUF_SIZE - len,
91297549c34SHans Petter Selasky 			"port = %d prio = 0x%x qp = 0x%x ",
91397549c34SHans Petter Selasky 			rule->port, rule->priority, rule->qpn);
91497549c34SHans Petter Selasky 
91597549c34SHans Petter Selasky 	list_for_each_entry(cur, &rule->list, list) {
91697549c34SHans Petter Selasky 		switch (cur->id) {
91797549c34SHans Petter Selasky 		case MLX4_NET_TRANS_RULE_ID_ETH:
91897549c34SHans Petter Selasky 			len += snprintf(buf + len, BUF_SIZE - len,
919c3191c2eSHans Petter Selasky 					"dmac = 0x%02x%02x%02x%02x%02x%02x ",
920c3191c2eSHans Petter Selasky 					cur->eth.dst_mac[0], cur->eth.dst_mac[1],
921c3191c2eSHans Petter Selasky 					cur->eth.dst_mac[2], cur->eth.dst_mac[3],
922c3191c2eSHans Petter Selasky 					cur->eth.dst_mac[4], cur->eth.dst_mac[5]);
92397549c34SHans Petter Selasky 			if (cur->eth.ether_type)
92497549c34SHans Petter Selasky 				len += snprintf(buf + len, BUF_SIZE - len,
92597549c34SHans Petter Selasky 						"ethertype = 0x%x ",
92697549c34SHans Petter Selasky 						be16_to_cpu(cur->eth.ether_type));
92797549c34SHans Petter Selasky 			if (cur->eth.vlan_id)
92897549c34SHans Petter Selasky 				len += snprintf(buf + len, BUF_SIZE - len,
92997549c34SHans Petter Selasky 						"vlan-id = %d ",
93097549c34SHans Petter Selasky 						be16_to_cpu(cur->eth.vlan_id));
93197549c34SHans Petter Selasky 			break;
93297549c34SHans Petter Selasky 
93397549c34SHans Petter Selasky 		case MLX4_NET_TRANS_RULE_ID_IPV4:
93497549c34SHans Petter Selasky 			if (cur->ipv4.src_ip)
93597549c34SHans Petter Selasky 				len += snprintf(buf + len, BUF_SIZE - len,
93697549c34SHans Petter Selasky 						"src-ip = %pI4 ",
93797549c34SHans Petter Selasky 						&cur->ipv4.src_ip);
93897549c34SHans Petter Selasky 			if (cur->ipv4.dst_ip)
93997549c34SHans Petter Selasky 				len += snprintf(buf + len, BUF_SIZE - len,
94097549c34SHans Petter Selasky 						"dst-ip = %pI4 ",
94197549c34SHans Petter Selasky 						&cur->ipv4.dst_ip);
94297549c34SHans Petter Selasky 			break;
94397549c34SHans Petter Selasky 
94497549c34SHans Petter Selasky 		case MLX4_NET_TRANS_RULE_ID_TCP:
94597549c34SHans Petter Selasky 		case MLX4_NET_TRANS_RULE_ID_UDP:
94697549c34SHans Petter Selasky 			if (cur->tcp_udp.src_port)
94797549c34SHans Petter Selasky 				len += snprintf(buf + len, BUF_SIZE - len,
94897549c34SHans Petter Selasky 						"src-port = %d ",
94997549c34SHans Petter Selasky 						be16_to_cpu(cur->tcp_udp.src_port));
95097549c34SHans Petter Selasky 			if (cur->tcp_udp.dst_port)
95197549c34SHans Petter Selasky 				len += snprintf(buf + len, BUF_SIZE - len,
95297549c34SHans Petter Selasky 						"dst-port = %d ",
95397549c34SHans Petter Selasky 						be16_to_cpu(cur->tcp_udp.dst_port));
95497549c34SHans Petter Selasky 			break;
95597549c34SHans Petter Selasky 
95697549c34SHans Petter Selasky 		case MLX4_NET_TRANS_RULE_ID_IB:
95797549c34SHans Petter Selasky 			len += snprintf(buf + len, BUF_SIZE - len,
95897549c34SHans Petter Selasky 					"dst-gid = "GID_PRINT_FMT"\n",
95997549c34SHans Petter Selasky 					GID_PRINT_ARGS(cur->ib.dst_gid));
96097549c34SHans Petter Selasky 			len += snprintf(buf + len, BUF_SIZE - len,
96197549c34SHans Petter Selasky 					"dst-gid-mask = "GID_PRINT_FMT"\n",
96297549c34SHans Petter Selasky 					GID_PRINT_ARGS(cur->ib.dst_gid_msk));
96397549c34SHans Petter Selasky 			break;
96497549c34SHans Petter Selasky 
965c3191c2eSHans Petter Selasky 		case MLX4_NET_TRANS_RULE_ID_VXLAN:
966c3191c2eSHans Petter Selasky 			len += snprintf(buf + len, BUF_SIZE - len,
967c3191c2eSHans Petter Selasky 					"VNID = %d ", be32_to_cpu(cur->vxlan.vni));
968c3191c2eSHans Petter Selasky 			break;
96997549c34SHans Petter Selasky 		case MLX4_NET_TRANS_RULE_ID_IPV6:
97097549c34SHans Petter Selasky 			break;
97197549c34SHans Petter Selasky 
97297549c34SHans Petter Selasky 		default:
97397549c34SHans Petter Selasky 			break;
97497549c34SHans Petter Selasky 		}
97597549c34SHans Petter Selasky 	}
97697549c34SHans Petter Selasky 	len += snprintf(buf + len, BUF_SIZE - len, "\n");
97797549c34SHans Petter Selasky 	mlx4_err(dev, "%s", buf);
97897549c34SHans Petter Selasky 
97997549c34SHans Petter Selasky 	if (len >= BUF_SIZE)
980c3191c2eSHans Petter Selasky 		mlx4_err(dev, "Network rule error message was truncated, print buffer is too small\n");
98197549c34SHans Petter Selasky }
98297549c34SHans Petter Selasky 
mlx4_flow_attach(struct mlx4_dev * dev,struct mlx4_net_trans_rule * rule,u64 * reg_id)98397549c34SHans Petter Selasky int mlx4_flow_attach(struct mlx4_dev *dev,
98497549c34SHans Petter Selasky 		     struct mlx4_net_trans_rule *rule, u64 *reg_id)
98597549c34SHans Petter Selasky {
98697549c34SHans Petter Selasky 	struct mlx4_cmd_mailbox *mailbox;
98797549c34SHans Petter Selasky 	struct mlx4_spec_list *cur;
98897549c34SHans Petter Selasky 	u32 size = 0;
98997549c34SHans Petter Selasky 	int ret;
99097549c34SHans Petter Selasky 
99197549c34SHans Petter Selasky 	mailbox = mlx4_alloc_cmd_mailbox(dev);
99297549c34SHans Petter Selasky 	if (IS_ERR(mailbox))
99397549c34SHans Petter Selasky 		return PTR_ERR(mailbox);
99497549c34SHans Petter Selasky 
99597549c34SHans Petter Selasky 	trans_rule_ctrl_to_hw(rule, mailbox->buf);
99697549c34SHans Petter Selasky 
99797549c34SHans Petter Selasky 	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
99897549c34SHans Petter Selasky 
99997549c34SHans Petter Selasky 	list_for_each_entry(cur, &rule->list, list) {
100097549c34SHans Petter Selasky 		ret = parse_trans_rule(dev, cur, mailbox->buf + size);
100197549c34SHans Petter Selasky 		if (ret < 0) {
100297549c34SHans Petter Selasky 			mlx4_free_cmd_mailbox(dev, mailbox);
1003c3191c2eSHans Petter Selasky 			return ret;
100497549c34SHans Petter Selasky 		}
100597549c34SHans Petter Selasky 		size += ret;
100697549c34SHans Petter Selasky 	}
100797549c34SHans Petter Selasky 
100897549c34SHans Petter Selasky 	ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);
1009c3191c2eSHans Petter Selasky 	if (ret == -ENOMEM) {
101097549c34SHans Petter Selasky 		mlx4_err_rule(dev,
1011c3191c2eSHans Petter Selasky 			      "mcg table is full. Fail to register network rule\n",
101297549c34SHans Petter Selasky 			      rule);
1013c3191c2eSHans Petter Selasky 	} else if (ret) {
1014c3191c2eSHans Petter Selasky 		if (ret == -ENXIO) {
1015c3191c2eSHans Petter Selasky 			if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
1016c3191c2eSHans Petter Selasky 				mlx4_err_rule(dev,
1017c3191c2eSHans Petter Selasky 					      "DMFS is not enabled, "
1018c3191c2eSHans Petter Selasky 					      "failed to register network rule.\n",
1019c3191c2eSHans Petter Selasky 					      rule);
1020c3191c2eSHans Petter Selasky 			else
1021c3191c2eSHans Petter Selasky 				mlx4_err_rule(dev,
1022c3191c2eSHans Petter Selasky 					      "Rule exceeds the dmfs_high_rate_mode limitations, "
1023c3191c2eSHans Petter Selasky 					      "failed to register network rule.\n",
1024c3191c2eSHans Petter Selasky 					      rule);
1025c3191c2eSHans Petter Selasky 
1026c3191c2eSHans Petter Selasky 		} else {
102797549c34SHans Petter Selasky 			mlx4_err_rule(dev, "Fail to register network rule.\n", rule);
1028c3191c2eSHans Petter Selasky 		}
1029c3191c2eSHans Petter Selasky 	}
103097549c34SHans Petter Selasky 
103197549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
103297549c34SHans Petter Selasky 
103397549c34SHans Petter Selasky 	return ret;
103497549c34SHans Petter Selasky }
103597549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_flow_attach);
103697549c34SHans Petter Selasky 
mlx4_flow_detach(struct mlx4_dev * dev,u64 reg_id)103797549c34SHans Petter Selasky int mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id)
103897549c34SHans Petter Selasky {
103997549c34SHans Petter Selasky 	int err;
104097549c34SHans Petter Selasky 
104197549c34SHans Petter Selasky 	err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id);
104297549c34SHans Petter Selasky 	if (err)
104397549c34SHans Petter Selasky 		mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n",
104497549c34SHans Petter Selasky 			 (unsigned long long)reg_id);
104597549c34SHans Petter Selasky 	return err;
104697549c34SHans Petter Selasky }
104797549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_flow_detach);
104897549c34SHans Petter Selasky 
mlx4_tunnel_steer_add(struct mlx4_dev * dev,unsigned char * addr,int port,int qpn,u16 prio,u64 * reg_id)1049c3191c2eSHans Petter Selasky int mlx4_tunnel_steer_add(struct mlx4_dev *dev, unsigned char *addr,
1050c3191c2eSHans Petter Selasky 			  int port, int qpn, u16 prio, u64 *reg_id)
1051c3191c2eSHans Petter Selasky {
1052c3191c2eSHans Petter Selasky 	int err;
1053c3191c2eSHans Petter Selasky 	struct mlx4_spec_list spec_eth_outer = { {NULL} };
1054c3191c2eSHans Petter Selasky 	struct mlx4_spec_list spec_vxlan     = { {NULL} };
1055c3191c2eSHans Petter Selasky 	struct mlx4_spec_list spec_eth_inner = { {NULL} };
1056c3191c2eSHans Petter Selasky 
1057c3191c2eSHans Petter Selasky 	struct mlx4_net_trans_rule rule = {
1058c3191c2eSHans Petter Selasky 		.queue_mode = MLX4_NET_TRANS_Q_FIFO,
1059c3191c2eSHans Petter Selasky 		.exclusive = 0,
1060c3191c2eSHans Petter Selasky 		.allow_loopback = 1,
1061c3191c2eSHans Petter Selasky 		.promisc_mode = MLX4_FS_REGULAR,
1062c3191c2eSHans Petter Selasky 	};
1063c3191c2eSHans Petter Selasky 
1064c3191c2eSHans Petter Selasky 	__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
1065c3191c2eSHans Petter Selasky 
1066c3191c2eSHans Petter Selasky 	rule.port = port;
1067c3191c2eSHans Petter Selasky 	rule.qpn = qpn;
1068c3191c2eSHans Petter Selasky 	rule.priority = prio;
1069c3191c2eSHans Petter Selasky 	INIT_LIST_HEAD(&rule.list);
1070c3191c2eSHans Petter Selasky 
1071c3191c2eSHans Petter Selasky 	spec_eth_outer.id = MLX4_NET_TRANS_RULE_ID_ETH;
1072c3191c2eSHans Petter Selasky 	memcpy(spec_eth_outer.eth.dst_mac, addr, ETH_ALEN);
1073c3191c2eSHans Petter Selasky 	memcpy(spec_eth_outer.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
1074c3191c2eSHans Petter Selasky 
1075c3191c2eSHans Petter Selasky 	spec_vxlan.id = MLX4_NET_TRANS_RULE_ID_VXLAN;    /* any vxlan header */
1076c3191c2eSHans Petter Selasky 	spec_eth_inner.id = MLX4_NET_TRANS_RULE_ID_ETH;	 /* any inner eth header */
1077c3191c2eSHans Petter Selasky 
1078c3191c2eSHans Petter Selasky 	list_add_tail(&spec_eth_outer.list, &rule.list);
1079c3191c2eSHans Petter Selasky 	list_add_tail(&spec_vxlan.list,     &rule.list);
1080c3191c2eSHans Petter Selasky 	list_add_tail(&spec_eth_inner.list, &rule.list);
1081c3191c2eSHans Petter Selasky 
1082c3191c2eSHans Petter Selasky 	err = mlx4_flow_attach(dev, &rule, reg_id);
1083c3191c2eSHans Petter Selasky 	return err;
1084c3191c2eSHans Petter Selasky }
1085c3191c2eSHans Petter Selasky EXPORT_SYMBOL(mlx4_tunnel_steer_add);
1086c3191c2eSHans Petter Selasky 
mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev * dev,u32 min_range_qpn,u32 max_range_qpn)1087c3191c2eSHans Petter Selasky int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn,
1088c3191c2eSHans Petter Selasky 				      u32 max_range_qpn)
108997549c34SHans Petter Selasky {
109097549c34SHans Petter Selasky 	int err;
109197549c34SHans Petter Selasky 	u64 in_param;
109297549c34SHans Petter Selasky 
109397549c34SHans Petter Selasky 	in_param = ((u64) min_range_qpn) << 32;
109497549c34SHans Petter Selasky 	in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF;
109597549c34SHans Petter Selasky 
109697549c34SHans Petter Selasky 	err = mlx4_cmd(dev, in_param, 0, 0,
109797549c34SHans Petter Selasky 			MLX4_FLOW_STEERING_IB_UC_QP_RANGE,
109897549c34SHans Petter Selasky 			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
109997549c34SHans Petter Selasky 
110097549c34SHans Petter Selasky 	return err;
110197549c34SHans Petter Selasky }
110297549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE);
110397549c34SHans Petter Selasky 
mlx4_qp_attach_common(struct mlx4_dev * dev,struct mlx4_qp * qp,u8 gid[16],int block_mcast_loopback,enum mlx4_protocol prot,enum mlx4_steer_type steer)110497549c34SHans Petter Selasky int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
110597549c34SHans Petter Selasky 			  int block_mcast_loopback, enum mlx4_protocol prot,
110697549c34SHans Petter Selasky 			  enum mlx4_steer_type steer)
110797549c34SHans Petter Selasky {
110897549c34SHans Petter Selasky 	struct mlx4_priv *priv = mlx4_priv(dev);
110997549c34SHans Petter Selasky 	struct mlx4_cmd_mailbox *mailbox;
111097549c34SHans Petter Selasky 	struct mlx4_mgm *mgm;
111197549c34SHans Petter Selasky 	u32 members_count;
1112c3191c2eSHans Petter Selasky 	int index = -1, prev;
111397549c34SHans Petter Selasky 	int link = 0;
111497549c34SHans Petter Selasky 	int i;
111597549c34SHans Petter Selasky 	int err;
111697549c34SHans Petter Selasky 	u8 port = gid[5];
111797549c34SHans Petter Selasky 	u8 new_entry = 0;
111897549c34SHans Petter Selasky 
111997549c34SHans Petter Selasky 	mailbox = mlx4_alloc_cmd_mailbox(dev);
112097549c34SHans Petter Selasky 	if (IS_ERR(mailbox))
112197549c34SHans Petter Selasky 		return PTR_ERR(mailbox);
112297549c34SHans Petter Selasky 	mgm = mailbox->buf;
112397549c34SHans Petter Selasky 
112497549c34SHans Petter Selasky 	mutex_lock(&priv->mcg_table.mutex);
112597549c34SHans Petter Selasky 	err = find_entry(dev, port, gid, prot,
112697549c34SHans Petter Selasky 			 mailbox, &prev, &index);
112797549c34SHans Petter Selasky 	if (err)
112897549c34SHans Petter Selasky 		goto out;
112997549c34SHans Petter Selasky 
113097549c34SHans Petter Selasky 	if (index != -1) {
113197549c34SHans Petter Selasky 		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
113297549c34SHans Petter Selasky 			new_entry = 1;
113397549c34SHans Petter Selasky 			memcpy(mgm->gid, gid, 16);
113497549c34SHans Petter Selasky 		}
113597549c34SHans Petter Selasky 	} else {
113697549c34SHans Petter Selasky 		link = 1;
113797549c34SHans Petter Selasky 
113897549c34SHans Petter Selasky 		index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
113997549c34SHans Petter Selasky 		if (index == -1) {
114097549c34SHans Petter Selasky 			mlx4_err(dev, "No AMGM entries left\n");
114197549c34SHans Petter Selasky 			err = -ENOMEM;
114297549c34SHans Petter Selasky 			goto out;
114397549c34SHans Petter Selasky 		}
114497549c34SHans Petter Selasky 		index += dev->caps.num_mgms;
114597549c34SHans Petter Selasky 
114697549c34SHans Petter Selasky 		new_entry = 1;
114797549c34SHans Petter Selasky 		memset(mgm, 0, sizeof *mgm);
114897549c34SHans Petter Selasky 		memcpy(mgm->gid, gid, 16);
114997549c34SHans Petter Selasky 	}
115097549c34SHans Petter Selasky 
115197549c34SHans Petter Selasky 	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
115297549c34SHans Petter Selasky 	if (members_count == dev->caps.num_qp_per_mgm) {
1153c3191c2eSHans Petter Selasky 		mlx4_err(dev, "MGM at index %x is full\n", index);
115497549c34SHans Petter Selasky 		err = -ENOMEM;
115597549c34SHans Petter Selasky 		goto out;
115697549c34SHans Petter Selasky 	}
115797549c34SHans Petter Selasky 
115897549c34SHans Petter Selasky 	for (i = 0; i < members_count; ++i)
115997549c34SHans Petter Selasky 		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
116097549c34SHans Petter Selasky 			mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
116197549c34SHans Petter Selasky 			err = 0;
116297549c34SHans Petter Selasky 			goto out;
116397549c34SHans Petter Selasky 		}
116497549c34SHans Petter Selasky 
1165c3191c2eSHans Petter Selasky 	if (block_mcast_loopback)
116697549c34SHans Petter Selasky 		mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
1167c3191c2eSHans Petter Selasky 						       (1U << MGM_BLCK_LB_BIT));
1168c3191c2eSHans Petter Selasky 	else
1169c3191c2eSHans Petter Selasky 		mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);
117097549c34SHans Petter Selasky 
117197549c34SHans Petter Selasky 	mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30);
117297549c34SHans Petter Selasky 
117397549c34SHans Petter Selasky 	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
117497549c34SHans Petter Selasky 	if (err)
117597549c34SHans Petter Selasky 		goto out;
117697549c34SHans Petter Selasky 
117797549c34SHans Petter Selasky 	if (!link)
1178c3191c2eSHans Petter Selasky 		goto out;
117997549c34SHans Petter Selasky 
118097549c34SHans Petter Selasky 	err = mlx4_READ_ENTRY(dev, prev, mailbox);
118197549c34SHans Petter Selasky 	if (err)
118297549c34SHans Petter Selasky 		goto out;
118397549c34SHans Petter Selasky 
118497549c34SHans Petter Selasky 	mgm->next_gid_index = cpu_to_be32(index << 6);
118597549c34SHans Petter Selasky 
118697549c34SHans Petter Selasky 	err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
118797549c34SHans Petter Selasky 	if (err)
118897549c34SHans Petter Selasky 		goto out;
118997549c34SHans Petter Selasky 
1190c3191c2eSHans Petter Selasky out:
1191c3191c2eSHans Petter Selasky 	if (prot == MLX4_PROT_ETH && index != -1) {
119297549c34SHans Petter Selasky 		/* manage the steering entry for promisc mode */
119397549c34SHans Petter Selasky 		if (new_entry)
1194c3191c2eSHans Petter Selasky 			err = new_steering_entry(dev, port, steer,
1195c3191c2eSHans Petter Selasky 						 index, qp->qpn);
119697549c34SHans Petter Selasky 		else
1197c3191c2eSHans Petter Selasky 			err = existing_steering_entry(dev, port, steer,
119897549c34SHans Petter Selasky 						      index, qp->qpn);
119997549c34SHans Petter Selasky 	}
120097549c34SHans Petter Selasky 	if (err && link && index != -1) {
120197549c34SHans Petter Selasky 		if (index < dev->caps.num_mgms)
1202c3191c2eSHans Petter Selasky 			mlx4_warn(dev, "Got AMGM index %d < %d\n",
120397549c34SHans Petter Selasky 				  index, dev->caps.num_mgms);
120497549c34SHans Petter Selasky 		else
120597549c34SHans Petter Selasky 			mlx4_bitmap_free(&priv->mcg_table.bitmap,
120697549c34SHans Petter Selasky 					 index - dev->caps.num_mgms, MLX4_USE_RR);
120797549c34SHans Petter Selasky 	}
120897549c34SHans Petter Selasky 	mutex_unlock(&priv->mcg_table.mutex);
120997549c34SHans Petter Selasky 
121097549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
121197549c34SHans Petter Selasky 	return err;
121297549c34SHans Petter Selasky }
121397549c34SHans Petter Selasky 
mlx4_qp_detach_common(struct mlx4_dev * dev,struct mlx4_qp * qp,u8 gid[16],enum mlx4_protocol prot,enum mlx4_steer_type steer)121497549c34SHans Petter Selasky int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
121597549c34SHans Petter Selasky 			  enum mlx4_protocol prot, enum mlx4_steer_type steer)
121697549c34SHans Petter Selasky {
121797549c34SHans Petter Selasky 	struct mlx4_priv *priv = mlx4_priv(dev);
121897549c34SHans Petter Selasky 	struct mlx4_cmd_mailbox *mailbox;
121997549c34SHans Petter Selasky 	struct mlx4_mgm *mgm;
122097549c34SHans Petter Selasky 	u32 members_count;
122197549c34SHans Petter Selasky 	int prev, index;
122297549c34SHans Petter Selasky 	int i, loc = -1;
122397549c34SHans Petter Selasky 	int err;
122497549c34SHans Petter Selasky 	u8 port = gid[5];
122597549c34SHans Petter Selasky 	bool removed_entry = false;
122697549c34SHans Petter Selasky 
122797549c34SHans Petter Selasky 	mailbox = mlx4_alloc_cmd_mailbox(dev);
122897549c34SHans Petter Selasky 	if (IS_ERR(mailbox))
122997549c34SHans Petter Selasky 		return PTR_ERR(mailbox);
123097549c34SHans Petter Selasky 	mgm = mailbox->buf;
123197549c34SHans Petter Selasky 
123297549c34SHans Petter Selasky 	mutex_lock(&priv->mcg_table.mutex);
123397549c34SHans Petter Selasky 
123497549c34SHans Petter Selasky 	err = find_entry(dev, port, gid, prot,
123597549c34SHans Petter Selasky 			 mailbox, &prev, &index);
123697549c34SHans Petter Selasky 	if (err)
123797549c34SHans Petter Selasky 		goto out;
123897549c34SHans Petter Selasky 
123997549c34SHans Petter Selasky 	if (index == -1) {
124097549c34SHans Petter Selasky 		mlx4_err(dev, "MGID "GID_PRINT_FMT" not found\n",
124197549c34SHans Petter Selasky 		    GID_PRINT_ARGS(gid));
124297549c34SHans Petter Selasky 		err = -EINVAL;
124397549c34SHans Petter Selasky 		goto out;
124497549c34SHans Petter Selasky 	}
124597549c34SHans Petter Selasky 
1246c3191c2eSHans Petter Selasky 	/* If this QP is also a promisc QP, it shouldn't be removed only if
1247c3191c2eSHans Petter Selasky 	 * at least one none promisc QP is also attached to this MCG
124897549c34SHans Petter Selasky 	 */
124997549c34SHans Petter Selasky 	if (prot == MLX4_PROT_ETH &&
125097549c34SHans Petter Selasky 	    check_duplicate_entry(dev, port, steer, index, qp->qpn) &&
125197549c34SHans Petter Selasky 	    !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL))
125297549c34SHans Petter Selasky 			goto out;
125397549c34SHans Petter Selasky 
125497549c34SHans Petter Selasky 	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
125597549c34SHans Petter Selasky 	for (i = 0; i < members_count; ++i)
125697549c34SHans Petter Selasky 		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
125797549c34SHans Petter Selasky 			loc = i;
125897549c34SHans Petter Selasky 			break;
125997549c34SHans Petter Selasky 		}
126097549c34SHans Petter Selasky 
126197549c34SHans Petter Selasky 	if (loc == -1) {
126297549c34SHans Petter Selasky 		mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
126397549c34SHans Petter Selasky 		err = -EINVAL;
126497549c34SHans Petter Selasky 		goto out;
126597549c34SHans Petter Selasky 	}
126697549c34SHans Petter Selasky 
126797549c34SHans Petter Selasky 	/* copy the last QP in this MGM over removed QP */
126897549c34SHans Petter Selasky 	mgm->qp[loc] = mgm->qp[members_count - 1];
126997549c34SHans Petter Selasky 	mgm->qp[members_count - 1] = 0;
127097549c34SHans Petter Selasky 	mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30);
127197549c34SHans Petter Selasky 
127297549c34SHans Petter Selasky 	if (prot == MLX4_PROT_ETH)
127397549c34SHans Petter Selasky 		removed_entry = can_remove_steering_entry(dev, port, steer,
127497549c34SHans Petter Selasky 								index, qp->qpn);
127597549c34SHans Petter Selasky 	if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) {
127697549c34SHans Petter Selasky 		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
127797549c34SHans Petter Selasky 		goto out;
127897549c34SHans Petter Selasky 	}
127997549c34SHans Petter Selasky 
128097549c34SHans Petter Selasky 	/* We are going to delete the entry, members count should be 0 */
128197549c34SHans Petter Selasky 	mgm->members_count = cpu_to_be32((u32) prot << 30);
128297549c34SHans Petter Selasky 
128397549c34SHans Petter Selasky 	if (prev == -1) {
128497549c34SHans Petter Selasky 		/* Remove entry from MGM */
128597549c34SHans Petter Selasky 		int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
128697549c34SHans Petter Selasky 		if (amgm_index) {
128797549c34SHans Petter Selasky 			err = mlx4_READ_ENTRY(dev, amgm_index, mailbox);
128897549c34SHans Petter Selasky 			if (err)
128997549c34SHans Petter Selasky 				goto out;
129097549c34SHans Petter Selasky 		} else
129197549c34SHans Petter Selasky 			memset(mgm->gid, 0, 16);
129297549c34SHans Petter Selasky 
129397549c34SHans Petter Selasky 		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
129497549c34SHans Petter Selasky 		if (err)
129597549c34SHans Petter Selasky 			goto out;
129697549c34SHans Petter Selasky 
129797549c34SHans Petter Selasky 		if (amgm_index) {
129897549c34SHans Petter Selasky 			if (amgm_index < dev->caps.num_mgms)
1299c3191c2eSHans Petter Selasky 				mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d\n",
130097549c34SHans Petter Selasky 					  index, amgm_index, dev->caps.num_mgms);
130197549c34SHans Petter Selasky 			else
130297549c34SHans Petter Selasky 				mlx4_bitmap_free(&priv->mcg_table.bitmap,
130397549c34SHans Petter Selasky 						 amgm_index - dev->caps.num_mgms, MLX4_USE_RR);
130497549c34SHans Petter Selasky 		}
130597549c34SHans Petter Selasky 	} else {
130697549c34SHans Petter Selasky 		/* Remove entry from AMGM */
130797549c34SHans Petter Selasky 		int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
130897549c34SHans Petter Selasky 		err = mlx4_READ_ENTRY(dev, prev, mailbox);
130997549c34SHans Petter Selasky 		if (err)
131097549c34SHans Petter Selasky 			goto out;
131197549c34SHans Petter Selasky 
131297549c34SHans Petter Selasky 		mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
131397549c34SHans Petter Selasky 
131497549c34SHans Petter Selasky 		err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
131597549c34SHans Petter Selasky 		if (err)
131697549c34SHans Petter Selasky 			goto out;
131797549c34SHans Petter Selasky 
131897549c34SHans Petter Selasky 		if (index < dev->caps.num_mgms)
1319c3191c2eSHans Petter Selasky 			mlx4_warn(dev, "entry %d had next AMGM index %d < %d\n",
132097549c34SHans Petter Selasky 				  prev, index, dev->caps.num_mgms);
132197549c34SHans Petter Selasky 		else
132297549c34SHans Petter Selasky 			mlx4_bitmap_free(&priv->mcg_table.bitmap,
132397549c34SHans Petter Selasky 					 index - dev->caps.num_mgms, MLX4_USE_RR);
132497549c34SHans Petter Selasky 	}
132597549c34SHans Petter Selasky 
132697549c34SHans Petter Selasky out:
132797549c34SHans Petter Selasky 	mutex_unlock(&priv->mcg_table.mutex);
132897549c34SHans Petter Selasky 
132997549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
1330c3191c2eSHans Petter Selasky 	if (err && dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
1331c3191c2eSHans Petter Selasky 		/* In case device is under an error, return success as a closing command */
1332c3191c2eSHans Petter Selasky 		err = 0;
133397549c34SHans Petter Selasky 	return err;
133497549c34SHans Petter Selasky }
133597549c34SHans Petter Selasky 
mlx4_QP_ATTACH(struct mlx4_dev * dev,struct mlx4_qp * qp,u8 gid[16],u8 attach,u8 block_loopback,enum mlx4_protocol prot)133697549c34SHans Petter Selasky static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,
133797549c34SHans Petter Selasky 			  u8 gid[16], u8 attach, u8 block_loopback,
133897549c34SHans Petter Selasky 			  enum mlx4_protocol prot)
133997549c34SHans Petter Selasky {
134097549c34SHans Petter Selasky 	struct mlx4_cmd_mailbox *mailbox;
134197549c34SHans Petter Selasky 	int err = 0;
134297549c34SHans Petter Selasky 	int qpn;
134397549c34SHans Petter Selasky 
134497549c34SHans Petter Selasky 	if (!mlx4_is_mfunc(dev))
134597549c34SHans Petter Selasky 		return -EBADF;
134697549c34SHans Petter Selasky 
134797549c34SHans Petter Selasky 	mailbox = mlx4_alloc_cmd_mailbox(dev);
134897549c34SHans Petter Selasky 	if (IS_ERR(mailbox))
134997549c34SHans Petter Selasky 		return PTR_ERR(mailbox);
135097549c34SHans Petter Selasky 
135197549c34SHans Petter Selasky 	memcpy(mailbox->buf, gid, 16);
135297549c34SHans Petter Selasky 	qpn = qp->qpn;
135397549c34SHans Petter Selasky 	qpn |= (prot << 28);
135497549c34SHans Petter Selasky 	if (attach && block_loopback)
135502ca39cfSEitan Adler 		qpn |= (1U << 31);
135697549c34SHans Petter Selasky 
135797549c34SHans Petter Selasky 	err = mlx4_cmd(dev, mailbox->dma, qpn, attach,
135897549c34SHans Petter Selasky 		       MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A,
135997549c34SHans Petter Selasky 		       MLX4_CMD_WRAPPED);
136097549c34SHans Petter Selasky 
136197549c34SHans Petter Selasky 	mlx4_free_cmd_mailbox(dev, mailbox);
1362c3191c2eSHans Petter Selasky 	if (err && !attach &&
1363c3191c2eSHans Petter Selasky 	    dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
1364c3191c2eSHans Petter Selasky 		err = 0;
136597549c34SHans Petter Selasky 	return err;
136697549c34SHans Petter Selasky }
136797549c34SHans Petter Selasky 
mlx4_trans_to_dmfs_attach(struct mlx4_dev * dev,struct mlx4_qp * qp,u8 gid[16],u8 port,int block_mcast_loopback,enum mlx4_protocol prot,u64 * reg_id)136897549c34SHans Petter Selasky int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,
136997549c34SHans Petter Selasky 			      u8 gid[16], u8 port,
137097549c34SHans Petter Selasky 			      int block_mcast_loopback,
137197549c34SHans Petter Selasky 			      enum mlx4_protocol prot, u64 *reg_id)
137297549c34SHans Petter Selasky {
137397549c34SHans Petter Selasky 		struct mlx4_spec_list spec = { {NULL} };
137497549c34SHans Petter Selasky 		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
137597549c34SHans Petter Selasky 
137697549c34SHans Petter Selasky 		struct mlx4_net_trans_rule rule = {
137797549c34SHans Petter Selasky 			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
137897549c34SHans Petter Selasky 			.exclusive = 0,
137997549c34SHans Petter Selasky 			.promisc_mode = MLX4_FS_REGULAR,
138097549c34SHans Petter Selasky 			.priority = MLX4_DOMAIN_NIC,
138197549c34SHans Petter Selasky 		};
138297549c34SHans Petter Selasky 
138397549c34SHans Petter Selasky 		rule.allow_loopback = !block_mcast_loopback;
138497549c34SHans Petter Selasky 		rule.port = port;
138597549c34SHans Petter Selasky 		rule.qpn = qp->qpn;
138697549c34SHans Petter Selasky 		INIT_LIST_HEAD(&rule.list);
138797549c34SHans Petter Selasky 
138897549c34SHans Petter Selasky 		switch (prot) {
138997549c34SHans Petter Selasky 		case MLX4_PROT_ETH:
139097549c34SHans Petter Selasky 			spec.id = MLX4_NET_TRANS_RULE_ID_ETH;
139197549c34SHans Petter Selasky 			memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN);
139297549c34SHans Petter Selasky 			memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
139397549c34SHans Petter Selasky 			break;
139497549c34SHans Petter Selasky 
139597549c34SHans Petter Selasky 		case MLX4_PROT_IB_IPV6:
139697549c34SHans Petter Selasky 			spec.id = MLX4_NET_TRANS_RULE_ID_IB;
139797549c34SHans Petter Selasky 			memcpy(spec.ib.dst_gid, gid, 16);
139897549c34SHans Petter Selasky 			memset(&spec.ib.dst_gid_msk, 0xff, 16);
139997549c34SHans Petter Selasky 			break;
140097549c34SHans Petter Selasky 		default:
140197549c34SHans Petter Selasky 			return -EINVAL;
140297549c34SHans Petter Selasky 		}
140397549c34SHans Petter Selasky 		list_add_tail(&spec.list, &rule.list);
140497549c34SHans Petter Selasky 
140597549c34SHans Petter Selasky 		return mlx4_flow_attach(dev, &rule, reg_id);
140697549c34SHans Petter Selasky }
140797549c34SHans Petter Selasky 
mlx4_multicast_attach(struct mlx4_dev * dev,struct mlx4_qp * qp,u8 gid[16],u8 port,int block_mcast_loopback,enum mlx4_protocol prot,u64 * reg_id)140897549c34SHans Petter Selasky int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
140997549c34SHans Petter Selasky 			  u8 port, int block_mcast_loopback,
141097549c34SHans Petter Selasky 			  enum mlx4_protocol prot, u64 *reg_id)
141197549c34SHans Petter Selasky {
141297549c34SHans Petter Selasky 	switch (dev->caps.steering_mode) {
141397549c34SHans Petter Selasky 	case MLX4_STEERING_MODE_A0:
141497549c34SHans Petter Selasky 		if (prot == MLX4_PROT_ETH)
141597549c34SHans Petter Selasky 			return 0;
141697549c34SHans Petter Selasky 
141797549c34SHans Petter Selasky 	case MLX4_STEERING_MODE_B0:
141897549c34SHans Petter Selasky 		if (prot == MLX4_PROT_ETH)
1419c3191c2eSHans Petter Selasky 			gid[7] |= (MLX4_MC_STEER << 1);
142097549c34SHans Petter Selasky 
142197549c34SHans Petter Selasky 		if (mlx4_is_mfunc(dev))
142297549c34SHans Petter Selasky 			return mlx4_QP_ATTACH(dev, qp, gid, 1,
142397549c34SHans Petter Selasky 					      block_mcast_loopback, prot);
142497549c34SHans Petter Selasky 		return mlx4_qp_attach_common(dev, qp, gid,
142597549c34SHans Petter Selasky 					     block_mcast_loopback, prot,
142697549c34SHans Petter Selasky 					     MLX4_MC_STEER);
142797549c34SHans Petter Selasky 
142897549c34SHans Petter Selasky 	case MLX4_STEERING_MODE_DEVICE_MANAGED:
142997549c34SHans Petter Selasky 		return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
143097549c34SHans Petter Selasky 						 block_mcast_loopback,
143197549c34SHans Petter Selasky 						 prot, reg_id);
143297549c34SHans Petter Selasky 	default:
143397549c34SHans Petter Selasky 		return -EINVAL;
143497549c34SHans Petter Selasky 	}
143597549c34SHans Petter Selasky }
143697549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_multicast_attach);
143797549c34SHans Petter Selasky 
mlx4_multicast_detach(struct mlx4_dev * dev,struct mlx4_qp * qp,u8 gid[16],enum mlx4_protocol prot,u64 reg_id)143897549c34SHans Petter Selasky int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
143997549c34SHans Petter Selasky 			  enum mlx4_protocol prot, u64 reg_id)
144097549c34SHans Petter Selasky {
144197549c34SHans Petter Selasky 	switch (dev->caps.steering_mode) {
144297549c34SHans Petter Selasky 	case MLX4_STEERING_MODE_A0:
144397549c34SHans Petter Selasky 		if (prot == MLX4_PROT_ETH)
144497549c34SHans Petter Selasky 			return 0;
144597549c34SHans Petter Selasky 
144697549c34SHans Petter Selasky 	case MLX4_STEERING_MODE_B0:
144797549c34SHans Petter Selasky 		if (prot == MLX4_PROT_ETH)
1448c3191c2eSHans Petter Selasky 			gid[7] |= (MLX4_MC_STEER << 1);
144997549c34SHans Petter Selasky 
145097549c34SHans Petter Selasky 		if (mlx4_is_mfunc(dev))
145197549c34SHans Petter Selasky 			return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
145297549c34SHans Petter Selasky 
145397549c34SHans Petter Selasky 		return mlx4_qp_detach_common(dev, qp, gid, prot,
145497549c34SHans Petter Selasky 					     MLX4_MC_STEER);
145597549c34SHans Petter Selasky 
145697549c34SHans Petter Selasky 	case MLX4_STEERING_MODE_DEVICE_MANAGED:
145797549c34SHans Petter Selasky 		return mlx4_flow_detach(dev, reg_id);
145897549c34SHans Petter Selasky 
145997549c34SHans Petter Selasky 	default:
146097549c34SHans Petter Selasky 		return -EINVAL;
146197549c34SHans Petter Selasky 	}
146297549c34SHans Petter Selasky }
146397549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
146497549c34SHans Petter Selasky 
mlx4_flow_steer_promisc_add(struct mlx4_dev * dev,u8 port,u32 qpn,enum mlx4_net_trans_promisc_mode mode)146597549c34SHans Petter Selasky int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
146697549c34SHans Petter Selasky 				u32 qpn, enum mlx4_net_trans_promisc_mode mode)
146797549c34SHans Petter Selasky {
1468c3191c2eSHans Petter Selasky 	struct mlx4_net_trans_rule rule = {
1469c3191c2eSHans Petter Selasky 		.queue_mode = MLX4_NET_TRANS_Q_FIFO,
1470c3191c2eSHans Petter Selasky 		.exclusive = 0,
1471c3191c2eSHans Petter Selasky 		.allow_loopback = 1,
1472c3191c2eSHans Petter Selasky 	};
1473c3191c2eSHans Petter Selasky 
147497549c34SHans Petter Selasky 	u64 *regid_p;
147597549c34SHans Petter Selasky 
147697549c34SHans Petter Selasky 	switch (mode) {
147797549c34SHans Petter Selasky 	case MLX4_FS_ALL_DEFAULT:
147897549c34SHans Petter Selasky 		regid_p = &dev->regid_promisc_array[port];
147997549c34SHans Petter Selasky 		break;
148097549c34SHans Petter Selasky 	case MLX4_FS_MC_DEFAULT:
148197549c34SHans Petter Selasky 		regid_p = &dev->regid_allmulti_array[port];
148297549c34SHans Petter Selasky 		break;
148397549c34SHans Petter Selasky 	default:
148497549c34SHans Petter Selasky 		return -1;
148597549c34SHans Petter Selasky 	}
148697549c34SHans Petter Selasky 
148797549c34SHans Petter Selasky 	if (*regid_p != 0)
148897549c34SHans Petter Selasky 		return -1;
148997549c34SHans Petter Selasky 
149097549c34SHans Petter Selasky 	rule.promisc_mode = mode;
149197549c34SHans Petter Selasky 	rule.port = port;
149297549c34SHans Petter Selasky 	rule.qpn = qpn;
149397549c34SHans Petter Selasky 	INIT_LIST_HEAD(&rule.list);
149497549c34SHans Petter Selasky 	mlx4_err(dev, "going promisc on %x\n", port);
149597549c34SHans Petter Selasky 
149697549c34SHans Petter Selasky 	return  mlx4_flow_attach(dev, &rule, regid_p);
149797549c34SHans Petter Selasky }
149897549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add);
149997549c34SHans Petter Selasky 
mlx4_flow_steer_promisc_remove(struct mlx4_dev * dev,u8 port,enum mlx4_net_trans_promisc_mode mode)150097549c34SHans Petter Selasky int mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port,
150197549c34SHans Petter Selasky 				   enum mlx4_net_trans_promisc_mode mode)
150297549c34SHans Petter Selasky {
150397549c34SHans Petter Selasky 	int ret;
150497549c34SHans Petter Selasky 	u64 *regid_p;
150597549c34SHans Petter Selasky 
150697549c34SHans Petter Selasky 	switch (mode) {
150797549c34SHans Petter Selasky 	case MLX4_FS_ALL_DEFAULT:
150897549c34SHans Petter Selasky 		regid_p = &dev->regid_promisc_array[port];
150997549c34SHans Petter Selasky 		break;
151097549c34SHans Petter Selasky 	case MLX4_FS_MC_DEFAULT:
151197549c34SHans Petter Selasky 		regid_p = &dev->regid_allmulti_array[port];
151297549c34SHans Petter Selasky 		break;
151397549c34SHans Petter Selasky 	default:
151497549c34SHans Petter Selasky 		return -1;
151597549c34SHans Petter Selasky 	}
151697549c34SHans Petter Selasky 
151797549c34SHans Petter Selasky 	if (*regid_p == 0)
151897549c34SHans Petter Selasky 		return -1;
151997549c34SHans Petter Selasky 
152097549c34SHans Petter Selasky 	ret =  mlx4_flow_detach(dev, *regid_p);
152197549c34SHans Petter Selasky 	if (ret == 0)
152297549c34SHans Petter Selasky 		*regid_p = 0;
152397549c34SHans Petter Selasky 
152497549c34SHans Petter Selasky 	return ret;
152597549c34SHans Petter Selasky }
152697549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove);
152797549c34SHans Petter Selasky 
mlx4_unicast_attach(struct mlx4_dev * dev,struct mlx4_qp * qp,u8 gid[16],int block_mcast_loopback,enum mlx4_protocol prot)152897549c34SHans Petter Selasky int mlx4_unicast_attach(struct mlx4_dev *dev,
152997549c34SHans Petter Selasky 			struct mlx4_qp *qp, u8 gid[16],
153097549c34SHans Petter Selasky 			int block_mcast_loopback, enum mlx4_protocol prot)
153197549c34SHans Petter Selasky {
153297549c34SHans Petter Selasky 	if (prot == MLX4_PROT_ETH)
153397549c34SHans Petter Selasky 		gid[7] |= (MLX4_UC_STEER << 1);
153497549c34SHans Petter Selasky 
153597549c34SHans Petter Selasky 	if (mlx4_is_mfunc(dev))
153697549c34SHans Petter Selasky 		return mlx4_QP_ATTACH(dev, qp, gid, 1,
153797549c34SHans Petter Selasky 					block_mcast_loopback, prot);
153897549c34SHans Petter Selasky 
153997549c34SHans Petter Selasky 	return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback,
154097549c34SHans Petter Selasky 					prot, MLX4_UC_STEER);
154197549c34SHans Petter Selasky }
154297549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_unicast_attach);
154397549c34SHans Petter Selasky 
mlx4_unicast_detach(struct mlx4_dev * dev,struct mlx4_qp * qp,u8 gid[16],enum mlx4_protocol prot)154497549c34SHans Petter Selasky int mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
154597549c34SHans Petter Selasky 			       u8 gid[16], enum mlx4_protocol prot)
154697549c34SHans Petter Selasky {
154797549c34SHans Petter Selasky 	if (prot == MLX4_PROT_ETH)
154897549c34SHans Petter Selasky 		gid[7] |= (MLX4_UC_STEER << 1);
154997549c34SHans Petter Selasky 
155097549c34SHans Petter Selasky 	if (mlx4_is_mfunc(dev))
155197549c34SHans Petter Selasky 		return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
155297549c34SHans Petter Selasky 
155397549c34SHans Petter Selasky 	return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER);
155497549c34SHans Petter Selasky }
155597549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_unicast_detach);
155697549c34SHans Petter Selasky 
mlx4_PROMISC_wrapper(struct mlx4_dev * dev,int slave,struct mlx4_vhcr * vhcr,struct mlx4_cmd_mailbox * inbox,struct mlx4_cmd_mailbox * outbox,struct mlx4_cmd_info * cmd)155797549c34SHans Petter Selasky int mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave,
155897549c34SHans Petter Selasky 			 struct mlx4_vhcr *vhcr,
155997549c34SHans Petter Selasky 			 struct mlx4_cmd_mailbox *inbox,
156097549c34SHans Petter Selasky 			 struct mlx4_cmd_mailbox *outbox,
156197549c34SHans Petter Selasky 			 struct mlx4_cmd_info *cmd)
156297549c34SHans Petter Selasky {
156397549c34SHans Petter Selasky 	u32 qpn = (u32) vhcr->in_param & 0xffffffff;
1564c3191c2eSHans Petter Selasky 	int port = mlx4_slave_convert_port(dev, slave, vhcr->in_param >> 62);
156597549c34SHans Petter Selasky 	enum mlx4_steer_type steer = vhcr->in_modifier;
156697549c34SHans Petter Selasky 
1567c3191c2eSHans Petter Selasky 	if (port < 0)
1568c3191c2eSHans Petter Selasky 		return -EINVAL;
1569c3191c2eSHans Petter Selasky 
1570c3191c2eSHans Petter Selasky 	/* Promiscuous unicast is not allowed in mfunc */
1571c3191c2eSHans Petter Selasky 	if (mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)
157297549c34SHans Petter Selasky 		return 0;
157397549c34SHans Petter Selasky 
157497549c34SHans Petter Selasky 	if (vhcr->op_modifier)
157597549c34SHans Petter Selasky 		return add_promisc_qp(dev, port, steer, qpn);
157697549c34SHans Petter Selasky 	else
157797549c34SHans Petter Selasky 		return remove_promisc_qp(dev, port, steer, qpn);
157897549c34SHans Petter Selasky }
157997549c34SHans Petter Selasky 
mlx4_PROMISC(struct mlx4_dev * dev,u32 qpn,enum mlx4_steer_type steer,u8 add,u8 port)158097549c34SHans Petter Selasky static int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn,
158197549c34SHans Petter Selasky 			enum mlx4_steer_type steer, u8 add, u8 port)
158297549c34SHans Petter Selasky {
158397549c34SHans Petter Selasky 	return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add,
158497549c34SHans Petter Selasky 			MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A,
158597549c34SHans Petter Selasky 			MLX4_CMD_WRAPPED);
158697549c34SHans Petter Selasky }
158797549c34SHans Petter Selasky 
mlx4_multicast_promisc_add(struct mlx4_dev * dev,u32 qpn,u8 port)158897549c34SHans Petter Selasky int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
158997549c34SHans Petter Selasky {
159097549c34SHans Petter Selasky 	if (mlx4_is_mfunc(dev))
159197549c34SHans Petter Selasky 		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port);
159297549c34SHans Petter Selasky 
159397549c34SHans Petter Selasky 	return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
159497549c34SHans Petter Selasky }
159597549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add);
159697549c34SHans Petter Selasky 
mlx4_multicast_promisc_remove(struct mlx4_dev * dev,u32 qpn,u8 port)159797549c34SHans Petter Selasky int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
159897549c34SHans Petter Selasky {
159997549c34SHans Petter Selasky 	if (mlx4_is_mfunc(dev))
160097549c34SHans Petter Selasky 		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port);
160197549c34SHans Petter Selasky 
160297549c34SHans Petter Selasky 	return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
160397549c34SHans Petter Selasky }
160497549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove);
160597549c34SHans Petter Selasky 
mlx4_unicast_promisc_add(struct mlx4_dev * dev,u32 qpn,u8 port)160697549c34SHans Petter Selasky int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
160797549c34SHans Petter Selasky {
160897549c34SHans Petter Selasky 	if (mlx4_is_mfunc(dev))
160997549c34SHans Petter Selasky 		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port);
161097549c34SHans Petter Selasky 
161197549c34SHans Petter Selasky 	return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
161297549c34SHans Petter Selasky }
161397549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add);
161497549c34SHans Petter Selasky 
mlx4_unicast_promisc_remove(struct mlx4_dev * dev,u32 qpn,u8 port)161597549c34SHans Petter Selasky int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
161697549c34SHans Petter Selasky {
161797549c34SHans Petter Selasky 	if (mlx4_is_mfunc(dev))
161897549c34SHans Petter Selasky 		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port);
161997549c34SHans Petter Selasky 
162097549c34SHans Petter Selasky 	return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
162197549c34SHans Petter Selasky }
162297549c34SHans Petter Selasky EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove);
162397549c34SHans Petter Selasky 
mlx4_init_mcg_table(struct mlx4_dev * dev)162497549c34SHans Petter Selasky int mlx4_init_mcg_table(struct mlx4_dev *dev)
162597549c34SHans Petter Selasky {
162697549c34SHans Petter Selasky 	struct mlx4_priv *priv = mlx4_priv(dev);
162797549c34SHans Petter Selasky 	int err;
162897549c34SHans Petter Selasky 
162997549c34SHans Petter Selasky 	/* No need for mcg_table when fw managed the mcg table*/
163097549c34SHans Petter Selasky 	if (dev->caps.steering_mode ==
163197549c34SHans Petter Selasky 	    MLX4_STEERING_MODE_DEVICE_MANAGED)
163297549c34SHans Petter Selasky 		return 0;
163397549c34SHans Petter Selasky 	err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
163497549c34SHans Petter Selasky 			       dev->caps.num_amgms - 1, 0, 0);
163597549c34SHans Petter Selasky 	if (err)
163697549c34SHans Petter Selasky 		return err;
163797549c34SHans Petter Selasky 
163897549c34SHans Petter Selasky 	mutex_init(&priv->mcg_table.mutex);
163997549c34SHans Petter Selasky 
164097549c34SHans Petter Selasky 	return 0;
164197549c34SHans Petter Selasky }
164297549c34SHans Petter Selasky 
mlx4_cleanup_mcg_table(struct mlx4_dev * dev)164397549c34SHans Petter Selasky void mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
164497549c34SHans Petter Selasky {
164597549c34SHans Petter Selasky 	if (dev->caps.steering_mode !=
164697549c34SHans Petter Selasky 	    MLX4_STEERING_MODE_DEVICE_MANAGED)
164797549c34SHans Petter Selasky 		mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
164897549c34SHans Petter Selasky }
1649