18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
38c2ecf20Sopenharmony_ci * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
68c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
78c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
88c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
98c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
128c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
138c2ecf20Sopenharmony_ci *     conditions are met:
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
168c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
178c2ecf20Sopenharmony_ci *        disclaimer.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
208c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
218c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
228c2ecf20Sopenharmony_ci *        provided with the distribution.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
258c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
268c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
278c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
288c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
298c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
308c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
318c2ecf20Sopenharmony_ci * SOFTWARE.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <linux/string.h>
358c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <linux/mlx4/cmd.h>
388c2ecf20Sopenharmony_ci#include <linux/mlx4/qp.h>
398c2ecf20Sopenharmony_ci#include <linux/export.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include "mlx4.h"
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ciint mlx4_get_mgm_entry_size(struct mlx4_dev *dev)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	return 1 << dev->oper_log_mgm_entry_size;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciint mlx4_get_qp_per_mgm(struct mlx4_dev *dev)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic int mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev *dev,
548c2ecf20Sopenharmony_ci					struct mlx4_cmd_mailbox *mailbox,
558c2ecf20Sopenharmony_ci					u32 size,
568c2ecf20Sopenharmony_ci					u64 *reg_id)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	u64 imm;
598c2ecf20Sopenharmony_ci	int err = 0;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, size, 0,
628c2ecf20Sopenharmony_ci			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
638c2ecf20Sopenharmony_ci			   MLX4_CMD_NATIVE);
648c2ecf20Sopenharmony_ci	if (err)
658c2ecf20Sopenharmony_ci		return err;
668c2ecf20Sopenharmony_ci	*reg_id = imm;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return err;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic int mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev *dev, u64 regid)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	int err = 0;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	err = mlx4_cmd(dev, regid, 0, 0,
768c2ecf20Sopenharmony_ci		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
778c2ecf20Sopenharmony_ci		       MLX4_CMD_NATIVE);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return err;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index,
838c2ecf20Sopenharmony_ci			   struct mlx4_cmd_mailbox *mailbox)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG,
868c2ecf20Sopenharmony_ci			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index,
908c2ecf20Sopenharmony_ci			    struct mlx4_cmd_mailbox *mailbox)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG,
938c2ecf20Sopenharmony_ci			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer,
978c2ecf20Sopenharmony_ci			      struct mlx4_cmd_mailbox *mailbox)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	u32 in_mod;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	in_mod = (u32) port << 16 | steer << 1;
1028c2ecf20Sopenharmony_ci	return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1,
1038c2ecf20Sopenharmony_ci			MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A,
1048c2ecf20Sopenharmony_ci			MLX4_CMD_NATIVE);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
1088c2ecf20Sopenharmony_ci			 u16 *hash, u8 op_mod)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	u64 imm;
1118c2ecf20Sopenharmony_ci	int err;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod,
1148c2ecf20Sopenharmony_ci			   MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A,
1158c2ecf20Sopenharmony_ci			   MLX4_CMD_NATIVE);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (!err)
1188c2ecf20Sopenharmony_ci		*hash = imm;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return err;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port,
1248c2ecf20Sopenharmony_ci					      enum mlx4_steer_type steer,
1258c2ecf20Sopenharmony_ci					      u32 qpn)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct mlx4_steer *s_steer;
1288c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *pqp;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (port < 1 || port > dev->caps.num_ports)
1318c2ecf20Sopenharmony_ci		return NULL;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	s_steer = &mlx4_priv(dev)->steer[port - 1];
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
1368c2ecf20Sopenharmony_ci		if (pqp->qpn == qpn)
1378c2ecf20Sopenharmony_ci			return pqp;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci	/* not found */
1408c2ecf20Sopenharmony_ci	return NULL;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/*
1448c2ecf20Sopenharmony_ci * Add new entry to steering data structure.
1458c2ecf20Sopenharmony_ci * All promisc QPs should be added as well
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_cistatic int new_steering_entry(struct mlx4_dev *dev, u8 port,
1488c2ecf20Sopenharmony_ci			      enum mlx4_steer_type steer,
1498c2ecf20Sopenharmony_ci			      unsigned int index, u32 qpn)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct mlx4_steer *s_steer;
1528c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
1538c2ecf20Sopenharmony_ci	struct mlx4_mgm *mgm;
1548c2ecf20Sopenharmony_ci	u32 members_count;
1558c2ecf20Sopenharmony_ci	struct mlx4_steer_index *new_entry;
1568c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *pqp;
1578c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *dqp = NULL;
1588c2ecf20Sopenharmony_ci	u32 prot;
1598c2ecf20Sopenharmony_ci	int err;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (port < 1 || port > dev->caps.num_ports)
1628c2ecf20Sopenharmony_ci		return -EINVAL;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	s_steer = &mlx4_priv(dev)->steer[port - 1];
1658c2ecf20Sopenharmony_ci	new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
1668c2ecf20Sopenharmony_ci	if (!new_entry)
1678c2ecf20Sopenharmony_ci		return -ENOMEM;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&new_entry->duplicates);
1708c2ecf20Sopenharmony_ci	new_entry->index = index;
1718c2ecf20Sopenharmony_ci	list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* If the given qpn is also a promisc qp,
1748c2ecf20Sopenharmony_ci	 * it should be inserted to duplicates list
1758c2ecf20Sopenharmony_ci	 */
1768c2ecf20Sopenharmony_ci	pqp = get_promisc_qp(dev, port, steer, qpn);
1778c2ecf20Sopenharmony_ci	if (pqp) {
1788c2ecf20Sopenharmony_ci		dqp = kmalloc(sizeof(*dqp), GFP_KERNEL);
1798c2ecf20Sopenharmony_ci		if (!dqp) {
1808c2ecf20Sopenharmony_ci			err = -ENOMEM;
1818c2ecf20Sopenharmony_ci			goto out_alloc;
1828c2ecf20Sopenharmony_ci		}
1838c2ecf20Sopenharmony_ci		dqp->qpn = qpn;
1848c2ecf20Sopenharmony_ci		list_add_tail(&dqp->list, &new_entry->duplicates);
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* if no promisc qps for this vep, we are done */
1888c2ecf20Sopenharmony_ci	if (list_empty(&s_steer->promisc_qps[steer]))
1898c2ecf20Sopenharmony_ci		return 0;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/* now need to add all the promisc qps to the new
1928c2ecf20Sopenharmony_ci	 * steering entry, as they should also receive the packets
1938c2ecf20Sopenharmony_ci	 * destined to this address */
1948c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
1958c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox)) {
1968c2ecf20Sopenharmony_ci		err = -ENOMEM;
1978c2ecf20Sopenharmony_ci		goto out_alloc;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci	mgm = mailbox->buf;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	err = mlx4_READ_ENTRY(dev, index, mailbox);
2028c2ecf20Sopenharmony_ci	if (err)
2038c2ecf20Sopenharmony_ci		goto out_mailbox;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
2068c2ecf20Sopenharmony_ci	prot = be32_to_cpu(mgm->members_count) >> 30;
2078c2ecf20Sopenharmony_ci	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
2088c2ecf20Sopenharmony_ci		/* don't add already existing qpn */
2098c2ecf20Sopenharmony_ci		if (pqp->qpn == qpn)
2108c2ecf20Sopenharmony_ci			continue;
2118c2ecf20Sopenharmony_ci		if (members_count == dev->caps.num_qp_per_mgm) {
2128c2ecf20Sopenharmony_ci			/* out of space */
2138c2ecf20Sopenharmony_ci			err = -ENOMEM;
2148c2ecf20Sopenharmony_ci			goto out_mailbox;
2158c2ecf20Sopenharmony_ci		}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		/* add the qpn */
2188c2ecf20Sopenharmony_ci		mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK);
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci	/* update the qps count and update the entry with all the promisc qps*/
2218c2ecf20Sopenharmony_ci	mgm->members_count = cpu_to_be32(members_count | (prot << 30));
2228c2ecf20Sopenharmony_ci	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ciout_mailbox:
2258c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
2268c2ecf20Sopenharmony_ci	if (!err)
2278c2ecf20Sopenharmony_ci		return 0;
2288c2ecf20Sopenharmony_ciout_alloc:
2298c2ecf20Sopenharmony_ci	if (dqp) {
2308c2ecf20Sopenharmony_ci		list_del(&dqp->list);
2318c2ecf20Sopenharmony_ci		kfree(dqp);
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	list_del(&new_entry->list);
2348c2ecf20Sopenharmony_ci	kfree(new_entry);
2358c2ecf20Sopenharmony_ci	return err;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci/* update the data structures with existing steering entry */
2398c2ecf20Sopenharmony_cistatic int existing_steering_entry(struct mlx4_dev *dev, u8 port,
2408c2ecf20Sopenharmony_ci				   enum mlx4_steer_type steer,
2418c2ecf20Sopenharmony_ci				   unsigned int index, u32 qpn)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct mlx4_steer *s_steer;
2448c2ecf20Sopenharmony_ci	struct mlx4_steer_index *tmp_entry, *entry = NULL;
2458c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *pqp;
2468c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *dqp;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (port < 1 || port > dev->caps.num_ports)
2498c2ecf20Sopenharmony_ci		return -EINVAL;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	s_steer = &mlx4_priv(dev)->steer[port - 1];
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	pqp = get_promisc_qp(dev, port, steer, qpn);
2548c2ecf20Sopenharmony_ci	if (!pqp)
2558c2ecf20Sopenharmony_ci		return 0; /* nothing to do */
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
2588c2ecf20Sopenharmony_ci		if (tmp_entry->index == index) {
2598c2ecf20Sopenharmony_ci			entry = tmp_entry;
2608c2ecf20Sopenharmony_ci			break;
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci	if (unlikely(!entry)) {
2648c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Steering entry at index %x is not registered\n", index);
2658c2ecf20Sopenharmony_ci		return -EINVAL;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/* the given qpn is listed as a promisc qpn
2698c2ecf20Sopenharmony_ci	 * we need to add it as a duplicate to this entry
2708c2ecf20Sopenharmony_ci	 * for future references */
2718c2ecf20Sopenharmony_ci	list_for_each_entry(dqp, &entry->duplicates, list) {
2728c2ecf20Sopenharmony_ci		if (qpn == dqp->qpn)
2738c2ecf20Sopenharmony_ci			return 0; /* qp is already duplicated */
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/* add the qp as a duplicate on this index */
2778c2ecf20Sopenharmony_ci	dqp = kmalloc(sizeof(*dqp), GFP_KERNEL);
2788c2ecf20Sopenharmony_ci	if (!dqp)
2798c2ecf20Sopenharmony_ci		return -ENOMEM;
2808c2ecf20Sopenharmony_ci	dqp->qpn = qpn;
2818c2ecf20Sopenharmony_ci	list_add_tail(&dqp->list, &entry->duplicates);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return 0;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci/* Check whether a qpn is a duplicate on steering entry
2878c2ecf20Sopenharmony_ci * If so, it should not be removed from mgm */
2888c2ecf20Sopenharmony_cistatic bool check_duplicate_entry(struct mlx4_dev *dev, u8 port,
2898c2ecf20Sopenharmony_ci				  enum mlx4_steer_type steer,
2908c2ecf20Sopenharmony_ci				  unsigned int index, u32 qpn)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct mlx4_steer *s_steer;
2938c2ecf20Sopenharmony_ci	struct mlx4_steer_index *tmp_entry, *entry = NULL;
2948c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *dqp, *tmp_dqp;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (port < 1 || port > dev->caps.num_ports)
2978c2ecf20Sopenharmony_ci		return NULL;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	s_steer = &mlx4_priv(dev)->steer[port - 1];
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* if qp is not promisc, it cannot be duplicated */
3028c2ecf20Sopenharmony_ci	if (!get_promisc_qp(dev, port, steer, qpn))
3038c2ecf20Sopenharmony_ci		return false;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* The qp is promisc qp so it is a duplicate on this index
3068c2ecf20Sopenharmony_ci	 * Find the index entry, and remove the duplicate */
3078c2ecf20Sopenharmony_ci	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
3088c2ecf20Sopenharmony_ci		if (tmp_entry->index == index) {
3098c2ecf20Sopenharmony_ci			entry = tmp_entry;
3108c2ecf20Sopenharmony_ci			break;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci	if (unlikely(!entry)) {
3148c2ecf20Sopenharmony_ci		mlx4_warn(dev, "Steering entry for index %x is not registered\n", index);
3158c2ecf20Sopenharmony_ci		return false;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) {
3188c2ecf20Sopenharmony_ci		if (dqp->qpn == qpn) {
3198c2ecf20Sopenharmony_ci			list_del(&dqp->list);
3208c2ecf20Sopenharmony_ci			kfree(dqp);
3218c2ecf20Sopenharmony_ci		}
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci	return true;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci/* Returns true if all the QPs != tqpn contained in this entry
3278c2ecf20Sopenharmony_ci * are Promisc QPs. Returns false otherwise.
3288c2ecf20Sopenharmony_ci */
3298c2ecf20Sopenharmony_cistatic bool promisc_steering_entry(struct mlx4_dev *dev, u8 port,
3308c2ecf20Sopenharmony_ci				   enum mlx4_steer_type steer,
3318c2ecf20Sopenharmony_ci				   unsigned int index, u32 tqpn,
3328c2ecf20Sopenharmony_ci				   u32 *members_count)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
3358c2ecf20Sopenharmony_ci	struct mlx4_mgm *mgm;
3368c2ecf20Sopenharmony_ci	u32 m_count;
3378c2ecf20Sopenharmony_ci	bool ret = false;
3388c2ecf20Sopenharmony_ci	int i;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	if (port < 1 || port > dev->caps.num_ports)
3418c2ecf20Sopenharmony_ci		return false;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
3448c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox))
3458c2ecf20Sopenharmony_ci		return false;
3468c2ecf20Sopenharmony_ci	mgm = mailbox->buf;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (mlx4_READ_ENTRY(dev, index, mailbox))
3498c2ecf20Sopenharmony_ci		goto out;
3508c2ecf20Sopenharmony_ci	m_count = be32_to_cpu(mgm->members_count) & 0xffffff;
3518c2ecf20Sopenharmony_ci	if (members_count)
3528c2ecf20Sopenharmony_ci		*members_count = m_count;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	for (i = 0;  i < m_count; i++) {
3558c2ecf20Sopenharmony_ci		u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
3568c2ecf20Sopenharmony_ci		if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) {
3578c2ecf20Sopenharmony_ci			/* the qp is not promisc, the entry can't be removed */
3588c2ecf20Sopenharmony_ci			goto out;
3598c2ecf20Sopenharmony_ci		}
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci	ret = true;
3628c2ecf20Sopenharmony_ciout:
3638c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
3648c2ecf20Sopenharmony_ci	return ret;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci/* IF a steering entry contains only promisc QPs, it can be removed. */
3688c2ecf20Sopenharmony_cistatic bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
3698c2ecf20Sopenharmony_ci				      enum mlx4_steer_type steer,
3708c2ecf20Sopenharmony_ci				      unsigned int index, u32 tqpn)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct mlx4_steer *s_steer;
3738c2ecf20Sopenharmony_ci	struct mlx4_steer_index *entry = NULL, *tmp_entry;
3748c2ecf20Sopenharmony_ci	u32 members_count;
3758c2ecf20Sopenharmony_ci	bool ret = false;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	if (port < 1 || port > dev->caps.num_ports)
3788c2ecf20Sopenharmony_ci		return NULL;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	s_steer = &mlx4_priv(dev)->steer[port - 1];
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (!promisc_steering_entry(dev, port, steer, index,
3838c2ecf20Sopenharmony_ci				    tqpn, &members_count))
3848c2ecf20Sopenharmony_ci		goto out;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* All the qps currently registered for this entry are promiscuous,
3878c2ecf20Sopenharmony_ci	  * Checking for duplicates */
3888c2ecf20Sopenharmony_ci	ret = true;
3898c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
3908c2ecf20Sopenharmony_ci		if (entry->index == index) {
3918c2ecf20Sopenharmony_ci			if (list_empty(&entry->duplicates) ||
3928c2ecf20Sopenharmony_ci			    members_count == 1) {
3938c2ecf20Sopenharmony_ci				struct mlx4_promisc_qp *pqp, *tmp_pqp;
3948c2ecf20Sopenharmony_ci				/* If there is only 1 entry in duplicates then
3958c2ecf20Sopenharmony_ci				 * this is the QP we want to delete, going over
3968c2ecf20Sopenharmony_ci				 * the list and deleting the entry.
3978c2ecf20Sopenharmony_ci				 */
3988c2ecf20Sopenharmony_ci				list_del(&entry->list);
3998c2ecf20Sopenharmony_ci				list_for_each_entry_safe(pqp, tmp_pqp,
4008c2ecf20Sopenharmony_ci							 &entry->duplicates,
4018c2ecf20Sopenharmony_ci							 list) {
4028c2ecf20Sopenharmony_ci					list_del(&pqp->list);
4038c2ecf20Sopenharmony_ci					kfree(pqp);
4048c2ecf20Sopenharmony_ci				}
4058c2ecf20Sopenharmony_ci				kfree(entry);
4068c2ecf20Sopenharmony_ci			} else {
4078c2ecf20Sopenharmony_ci				/* This entry contains duplicates so it shouldn't be removed */
4088c2ecf20Sopenharmony_ci				ret = false;
4098c2ecf20Sopenharmony_ci				goto out;
4108c2ecf20Sopenharmony_ci			}
4118c2ecf20Sopenharmony_ci		}
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ciout:
4158c2ecf20Sopenharmony_ci	return ret;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic int add_promisc_qp(struct mlx4_dev *dev, u8 port,
4198c2ecf20Sopenharmony_ci			  enum mlx4_steer_type steer, u32 qpn)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct mlx4_steer *s_steer;
4228c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
4238c2ecf20Sopenharmony_ci	struct mlx4_mgm *mgm;
4248c2ecf20Sopenharmony_ci	struct mlx4_steer_index *entry;
4258c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *pqp;
4268c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *dqp;
4278c2ecf20Sopenharmony_ci	u32 members_count;
4288c2ecf20Sopenharmony_ci	u32 prot;
4298c2ecf20Sopenharmony_ci	int i;
4308c2ecf20Sopenharmony_ci	bool found;
4318c2ecf20Sopenharmony_ci	int err;
4328c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (port < 1 || port > dev->caps.num_ports)
4358c2ecf20Sopenharmony_ci		return -EINVAL;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	s_steer = &mlx4_priv(dev)->steer[port - 1];
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	mutex_lock(&priv->mcg_table.mutex);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (get_promisc_qp(dev, port, steer, qpn)) {
4428c2ecf20Sopenharmony_ci		err = 0;  /* Noting to do, already exists */
4438c2ecf20Sopenharmony_ci		goto out_mutex;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	pqp = kmalloc(sizeof(*pqp), GFP_KERNEL);
4478c2ecf20Sopenharmony_ci	if (!pqp) {
4488c2ecf20Sopenharmony_ci		err = -ENOMEM;
4498c2ecf20Sopenharmony_ci		goto out_mutex;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci	pqp->qpn = qpn;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
4548c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox)) {
4558c2ecf20Sopenharmony_ci		err = -ENOMEM;
4568c2ecf20Sopenharmony_ci		goto out_alloc;
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci	mgm = mailbox->buf;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
4618c2ecf20Sopenharmony_ci		/* The promisc QP needs to be added for each one of the steering
4628c2ecf20Sopenharmony_ci		 * entries. If it already exists, needs to be added as
4638c2ecf20Sopenharmony_ci		 * a duplicate for this entry.
4648c2ecf20Sopenharmony_ci		 */
4658c2ecf20Sopenharmony_ci		list_for_each_entry(entry,
4668c2ecf20Sopenharmony_ci				    &s_steer->steer_entries[steer],
4678c2ecf20Sopenharmony_ci				    list) {
4688c2ecf20Sopenharmony_ci			err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
4698c2ecf20Sopenharmony_ci			if (err)
4708c2ecf20Sopenharmony_ci				goto out_mailbox;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci			members_count = be32_to_cpu(mgm->members_count) &
4738c2ecf20Sopenharmony_ci					0xffffff;
4748c2ecf20Sopenharmony_ci			prot = be32_to_cpu(mgm->members_count) >> 30;
4758c2ecf20Sopenharmony_ci			found = false;
4768c2ecf20Sopenharmony_ci			for (i = 0; i < members_count; i++) {
4778c2ecf20Sopenharmony_ci				if ((be32_to_cpu(mgm->qp[i]) &
4788c2ecf20Sopenharmony_ci				     MGM_QPN_MASK) == qpn) {
4798c2ecf20Sopenharmony_ci					/* Entry already exists.
4808c2ecf20Sopenharmony_ci					 * Add to duplicates.
4818c2ecf20Sopenharmony_ci					 */
4828c2ecf20Sopenharmony_ci					dqp = kmalloc(sizeof(*dqp), GFP_KERNEL);
4838c2ecf20Sopenharmony_ci					if (!dqp) {
4848c2ecf20Sopenharmony_ci						err = -ENOMEM;
4858c2ecf20Sopenharmony_ci						goto out_mailbox;
4868c2ecf20Sopenharmony_ci					}
4878c2ecf20Sopenharmony_ci					dqp->qpn = qpn;
4888c2ecf20Sopenharmony_ci					list_add_tail(&dqp->list,
4898c2ecf20Sopenharmony_ci						      &entry->duplicates);
4908c2ecf20Sopenharmony_ci					found = true;
4918c2ecf20Sopenharmony_ci				}
4928c2ecf20Sopenharmony_ci			}
4938c2ecf20Sopenharmony_ci			if (!found) {
4948c2ecf20Sopenharmony_ci				/* Need to add the qpn to mgm */
4958c2ecf20Sopenharmony_ci				if (members_count ==
4968c2ecf20Sopenharmony_ci				    dev->caps.num_qp_per_mgm) {
4978c2ecf20Sopenharmony_ci					/* entry is full */
4988c2ecf20Sopenharmony_ci					err = -ENOMEM;
4998c2ecf20Sopenharmony_ci					goto out_mailbox;
5008c2ecf20Sopenharmony_ci				}
5018c2ecf20Sopenharmony_ci				mgm->qp[members_count++] =
5028c2ecf20Sopenharmony_ci					cpu_to_be32(qpn & MGM_QPN_MASK);
5038c2ecf20Sopenharmony_ci				mgm->members_count =
5048c2ecf20Sopenharmony_ci					cpu_to_be32(members_count |
5058c2ecf20Sopenharmony_ci						    (prot << 30));
5068c2ecf20Sopenharmony_ci				err = mlx4_WRITE_ENTRY(dev, entry->index,
5078c2ecf20Sopenharmony_ci						       mailbox);
5088c2ecf20Sopenharmony_ci				if (err)
5098c2ecf20Sopenharmony_ci					goto out_mailbox;
5108c2ecf20Sopenharmony_ci			}
5118c2ecf20Sopenharmony_ci		}
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/* add the new qpn to list of promisc qps */
5158c2ecf20Sopenharmony_ci	list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
5168c2ecf20Sopenharmony_ci	/* now need to add all the promisc qps to default entry */
5178c2ecf20Sopenharmony_ci	memset(mgm, 0, sizeof(*mgm));
5188c2ecf20Sopenharmony_ci	members_count = 0;
5198c2ecf20Sopenharmony_ci	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) {
5208c2ecf20Sopenharmony_ci		if (members_count == dev->caps.num_qp_per_mgm) {
5218c2ecf20Sopenharmony_ci			/* entry is full */
5228c2ecf20Sopenharmony_ci			err = -ENOMEM;
5238c2ecf20Sopenharmony_ci			goto out_list;
5248c2ecf20Sopenharmony_ci		}
5258c2ecf20Sopenharmony_ci		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
5308c2ecf20Sopenharmony_ci	if (err)
5318c2ecf20Sopenharmony_ci		goto out_list;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
5348c2ecf20Sopenharmony_ci	mutex_unlock(&priv->mcg_table.mutex);
5358c2ecf20Sopenharmony_ci	return 0;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ciout_list:
5388c2ecf20Sopenharmony_ci	list_del(&pqp->list);
5398c2ecf20Sopenharmony_ciout_mailbox:
5408c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
5418c2ecf20Sopenharmony_ciout_alloc:
5428c2ecf20Sopenharmony_ci	kfree(pqp);
5438c2ecf20Sopenharmony_ciout_mutex:
5448c2ecf20Sopenharmony_ci	mutex_unlock(&priv->mcg_table.mutex);
5458c2ecf20Sopenharmony_ci	return err;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
5498c2ecf20Sopenharmony_ci			     enum mlx4_steer_type steer, u32 qpn)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
5528c2ecf20Sopenharmony_ci	struct mlx4_steer *s_steer;
5538c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
5548c2ecf20Sopenharmony_ci	struct mlx4_mgm *mgm;
5558c2ecf20Sopenharmony_ci	struct mlx4_steer_index *entry, *tmp_entry;
5568c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *pqp;
5578c2ecf20Sopenharmony_ci	struct mlx4_promisc_qp *dqp;
5588c2ecf20Sopenharmony_ci	u32 members_count;
5598c2ecf20Sopenharmony_ci	bool found;
5608c2ecf20Sopenharmony_ci	bool back_to_list = false;
5618c2ecf20Sopenharmony_ci	int i;
5628c2ecf20Sopenharmony_ci	int err;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (port < 1 || port > dev->caps.num_ports)
5658c2ecf20Sopenharmony_ci		return -EINVAL;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	s_steer = &mlx4_priv(dev)->steer[port - 1];
5688c2ecf20Sopenharmony_ci	mutex_lock(&priv->mcg_table.mutex);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	pqp = get_promisc_qp(dev, port, steer, qpn);
5718c2ecf20Sopenharmony_ci	if (unlikely(!pqp)) {
5728c2ecf20Sopenharmony_ci		mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn);
5738c2ecf20Sopenharmony_ci		/* nothing to do */
5748c2ecf20Sopenharmony_ci		err = 0;
5758c2ecf20Sopenharmony_ci		goto out_mutex;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	/*remove from list of promisc qps */
5798c2ecf20Sopenharmony_ci	list_del(&pqp->list);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/* set the default entry not to include the removed one */
5828c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
5838c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox)) {
5848c2ecf20Sopenharmony_ci		err = -ENOMEM;
5858c2ecf20Sopenharmony_ci		back_to_list = true;
5868c2ecf20Sopenharmony_ci		goto out_list;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci	mgm = mailbox->buf;
5898c2ecf20Sopenharmony_ci	members_count = 0;
5908c2ecf20Sopenharmony_ci	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
5918c2ecf20Sopenharmony_ci		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
5928c2ecf20Sopenharmony_ci	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);
5958c2ecf20Sopenharmony_ci	if (err)
5968c2ecf20Sopenharmony_ci		goto out_mailbox;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {
5998c2ecf20Sopenharmony_ci		/* Remove the QP from all the steering entries */
6008c2ecf20Sopenharmony_ci		list_for_each_entry_safe(entry, tmp_entry,
6018c2ecf20Sopenharmony_ci					 &s_steer->steer_entries[steer],
6028c2ecf20Sopenharmony_ci					 list) {
6038c2ecf20Sopenharmony_ci			found = false;
6048c2ecf20Sopenharmony_ci			list_for_each_entry(dqp, &entry->duplicates, list) {
6058c2ecf20Sopenharmony_ci				if (dqp->qpn == qpn) {
6068c2ecf20Sopenharmony_ci					found = true;
6078c2ecf20Sopenharmony_ci					break;
6088c2ecf20Sopenharmony_ci				}
6098c2ecf20Sopenharmony_ci			}
6108c2ecf20Sopenharmony_ci			if (found) {
6118c2ecf20Sopenharmony_ci				/* A duplicate, no need to change the MGM,
6128c2ecf20Sopenharmony_ci				 * only update the duplicates list
6138c2ecf20Sopenharmony_ci				 */
6148c2ecf20Sopenharmony_ci				list_del(&dqp->list);
6158c2ecf20Sopenharmony_ci				kfree(dqp);
6168c2ecf20Sopenharmony_ci			} else {
6178c2ecf20Sopenharmony_ci				int loc = -1;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci				err = mlx4_READ_ENTRY(dev,
6208c2ecf20Sopenharmony_ci						      entry->index,
6218c2ecf20Sopenharmony_ci						      mailbox);
6228c2ecf20Sopenharmony_ci				if (err)
6238c2ecf20Sopenharmony_ci					goto out_mailbox;
6248c2ecf20Sopenharmony_ci				members_count =
6258c2ecf20Sopenharmony_ci					be32_to_cpu(mgm->members_count) &
6268c2ecf20Sopenharmony_ci					0xffffff;
6278c2ecf20Sopenharmony_ci				if (!members_count) {
6288c2ecf20Sopenharmony_ci					mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0. deleting entry...\n",
6298c2ecf20Sopenharmony_ci						  qpn, entry->index);
6308c2ecf20Sopenharmony_ci					list_del(&entry->list);
6318c2ecf20Sopenharmony_ci					kfree(entry);
6328c2ecf20Sopenharmony_ci					continue;
6338c2ecf20Sopenharmony_ci				}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci				for (i = 0; i < members_count; ++i)
6368c2ecf20Sopenharmony_ci					if ((be32_to_cpu(mgm->qp[i]) &
6378c2ecf20Sopenharmony_ci					     MGM_QPN_MASK) == qpn) {
6388c2ecf20Sopenharmony_ci						loc = i;
6398c2ecf20Sopenharmony_ci						break;
6408c2ecf20Sopenharmony_ci					}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci				if (loc < 0) {
6438c2ecf20Sopenharmony_ci					mlx4_err(dev, "QP %06x wasn't found in entry %d\n",
6448c2ecf20Sopenharmony_ci						 qpn, entry->index);
6458c2ecf20Sopenharmony_ci					err = -EINVAL;
6468c2ecf20Sopenharmony_ci					goto out_mailbox;
6478c2ecf20Sopenharmony_ci				}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci				/* Copy the last QP in this MGM
6508c2ecf20Sopenharmony_ci				 * over removed QP
6518c2ecf20Sopenharmony_ci				 */
6528c2ecf20Sopenharmony_ci				mgm->qp[loc] = mgm->qp[members_count - 1];
6538c2ecf20Sopenharmony_ci				mgm->qp[members_count - 1] = 0;
6548c2ecf20Sopenharmony_ci				mgm->members_count =
6558c2ecf20Sopenharmony_ci					cpu_to_be32(--members_count |
6568c2ecf20Sopenharmony_ci						    (MLX4_PROT_ETH << 30));
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci				err = mlx4_WRITE_ENTRY(dev,
6598c2ecf20Sopenharmony_ci						       entry->index,
6608c2ecf20Sopenharmony_ci						       mailbox);
6618c2ecf20Sopenharmony_ci				if (err)
6628c2ecf20Sopenharmony_ci					goto out_mailbox;
6638c2ecf20Sopenharmony_ci			}
6648c2ecf20Sopenharmony_ci		}
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ciout_mailbox:
6688c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
6698c2ecf20Sopenharmony_ciout_list:
6708c2ecf20Sopenharmony_ci	if (back_to_list)
6718c2ecf20Sopenharmony_ci		list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
6728c2ecf20Sopenharmony_ci	else
6738c2ecf20Sopenharmony_ci		kfree(pqp);
6748c2ecf20Sopenharmony_ciout_mutex:
6758c2ecf20Sopenharmony_ci	mutex_unlock(&priv->mcg_table.mutex);
6768c2ecf20Sopenharmony_ci	return err;
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci/*
6808c2ecf20Sopenharmony_ci * Caller must hold MCG table semaphore.  gid and mgm parameters must
6818c2ecf20Sopenharmony_ci * be properly aligned for command interface.
6828c2ecf20Sopenharmony_ci *
6838c2ecf20Sopenharmony_ci *  Returns 0 unless a firmware command error occurs.
6848c2ecf20Sopenharmony_ci *
6858c2ecf20Sopenharmony_ci * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
6868c2ecf20Sopenharmony_ci * and *mgm holds MGM entry.
6878c2ecf20Sopenharmony_ci *
6888c2ecf20Sopenharmony_ci * if GID is found in AMGM, *index = index in AMGM, *prev = index of
6898c2ecf20Sopenharmony_ci * previous entry in hash chain and *mgm holds AMGM entry.
6908c2ecf20Sopenharmony_ci *
6918c2ecf20Sopenharmony_ci * If no AMGM exists for given gid, *index = -1, *prev = index of last
6928c2ecf20Sopenharmony_ci * entry in hash chain and *mgm holds end of hash chain.
6938c2ecf20Sopenharmony_ci */
6948c2ecf20Sopenharmony_cistatic int find_entry(struct mlx4_dev *dev, u8 port,
6958c2ecf20Sopenharmony_ci		      u8 *gid, enum mlx4_protocol prot,
6968c2ecf20Sopenharmony_ci		      struct mlx4_cmd_mailbox *mgm_mailbox,
6978c2ecf20Sopenharmony_ci		      int *prev, int *index)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
7008c2ecf20Sopenharmony_ci	struct mlx4_mgm *mgm = mgm_mailbox->buf;
7018c2ecf20Sopenharmony_ci	u8 *mgid;
7028c2ecf20Sopenharmony_ci	int err;
7038c2ecf20Sopenharmony_ci	u16 hash;
7048c2ecf20Sopenharmony_ci	u8 op_mod = (prot == MLX4_PROT_ETH) ?
7058c2ecf20Sopenharmony_ci		!!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
7088c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox))
7098c2ecf20Sopenharmony_ci		return -ENOMEM;
7108c2ecf20Sopenharmony_ci	mgid = mailbox->buf;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	memcpy(mgid, gid, 16);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod);
7158c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
7168c2ecf20Sopenharmony_ci	if (err)
7178c2ecf20Sopenharmony_ci		return err;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	if (0)
7208c2ecf20Sopenharmony_ci		mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, hash);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	*index = hash;
7238c2ecf20Sopenharmony_ci	*prev  = -1;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	do {
7268c2ecf20Sopenharmony_ci		err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox);
7278c2ecf20Sopenharmony_ci		if (err)
7288c2ecf20Sopenharmony_ci			return err;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
7318c2ecf20Sopenharmony_ci			if (*index != hash) {
7328c2ecf20Sopenharmony_ci				mlx4_err(dev, "Found zero MGID in AMGM\n");
7338c2ecf20Sopenharmony_ci				err = -EINVAL;
7348c2ecf20Sopenharmony_ci			}
7358c2ecf20Sopenharmony_ci			return err;
7368c2ecf20Sopenharmony_ci		}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		if (!memcmp(mgm->gid, gid, 16) &&
7398c2ecf20Sopenharmony_ci		    be32_to_cpu(mgm->members_count) >> 30 == prot)
7408c2ecf20Sopenharmony_ci			return err;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci		*prev = *index;
7438c2ecf20Sopenharmony_ci		*index = be32_to_cpu(mgm->next_gid_index) >> 6;
7448c2ecf20Sopenharmony_ci	} while (*index);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	*index = -1;
7478c2ecf20Sopenharmony_ci	return err;
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic const u8 __promisc_mode[] = {
7518c2ecf20Sopenharmony_ci	[MLX4_FS_REGULAR]   = 0x0,
7528c2ecf20Sopenharmony_ci	[MLX4_FS_ALL_DEFAULT] = 0x1,
7538c2ecf20Sopenharmony_ci	[MLX4_FS_MC_DEFAULT] = 0x3,
7548c2ecf20Sopenharmony_ci	[MLX4_FS_MIRROR_RX_PORT] = 0x4,
7558c2ecf20Sopenharmony_ci	[MLX4_FS_MIRROR_SX_PORT] = 0x5,
7568c2ecf20Sopenharmony_ci	[MLX4_FS_UC_SNIFFER] = 0x6,
7578c2ecf20Sopenharmony_ci	[MLX4_FS_MC_SNIFFER] = 0x7,
7588c2ecf20Sopenharmony_ci};
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ciint mlx4_map_sw_to_hw_steering_mode(struct mlx4_dev *dev,
7618c2ecf20Sopenharmony_ci				    enum mlx4_net_trans_promisc_mode flow_type)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	if (flow_type >= MLX4_FS_MODE_NUM) {
7648c2ecf20Sopenharmony_ci		mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type);
7658c2ecf20Sopenharmony_ci		return -EINVAL;
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci	return __promisc_mode[flow_type];
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_mode);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_cistatic void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,
7728c2ecf20Sopenharmony_ci				  struct mlx4_net_trans_rule_hw_ctrl *hw)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	u8 flags = 0;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0;
7778c2ecf20Sopenharmony_ci	flags |= ctrl->exclusive ? (1 << 2) : 0;
7788c2ecf20Sopenharmony_ci	flags |= ctrl->allow_loopback ? (1 << 3) : 0;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	hw->flags = flags;
7818c2ecf20Sopenharmony_ci	hw->type = __promisc_mode[ctrl->promisc_mode];
7828c2ecf20Sopenharmony_ci	hw->prio = cpu_to_be16(ctrl->priority);
7838c2ecf20Sopenharmony_ci	hw->port = ctrl->port;
7848c2ecf20Sopenharmony_ci	hw->qpn = cpu_to_be32(ctrl->qpn);
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ciconst u16 __sw_id_hw[] = {
7888c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_ETH]     = 0xE001,
7898c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_IB]      = 0xE005,
7908c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_IPV6]    = 0xE003,
7918c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_IPV4]    = 0xE002,
7928c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_TCP]     = 0xE004,
7938c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_UDP]     = 0xE006,
7948c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_VXLAN]	 = 0xE008
7958c2ecf20Sopenharmony_ci};
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ciint mlx4_map_sw_to_hw_steering_id(struct mlx4_dev *dev,
7988c2ecf20Sopenharmony_ci				  enum mlx4_net_trans_rule_id id)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	if (id >= MLX4_NET_TRANS_RULE_NUM) {
8018c2ecf20Sopenharmony_ci		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
8028c2ecf20Sopenharmony_ci		return -EINVAL;
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci	return __sw_id_hw[id];
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_id);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cistatic const int __rule_hw_sz[] = {
8098c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_ETH] =
8108c2ecf20Sopenharmony_ci		sizeof(struct mlx4_net_trans_rule_hw_eth),
8118c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_IB] =
8128c2ecf20Sopenharmony_ci		sizeof(struct mlx4_net_trans_rule_hw_ib),
8138c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_IPV6] = 0,
8148c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_IPV4] =
8158c2ecf20Sopenharmony_ci		sizeof(struct mlx4_net_trans_rule_hw_ipv4),
8168c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_TCP] =
8178c2ecf20Sopenharmony_ci		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),
8188c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_UDP] =
8198c2ecf20Sopenharmony_ci		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),
8208c2ecf20Sopenharmony_ci	[MLX4_NET_TRANS_RULE_ID_VXLAN] =
8218c2ecf20Sopenharmony_ci		sizeof(struct mlx4_net_trans_rule_hw_vxlan)
8228c2ecf20Sopenharmony_ci};
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ciint mlx4_hw_rule_sz(struct mlx4_dev *dev,
8258c2ecf20Sopenharmony_ci	       enum mlx4_net_trans_rule_id id)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	if (id >= MLX4_NET_TRANS_RULE_NUM) {
8288c2ecf20Sopenharmony_ci		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);
8298c2ecf20Sopenharmony_ci		return -EINVAL;
8308c2ecf20Sopenharmony_ci	}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	return __rule_hw_sz[id];
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_hw_rule_sz);
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cistatic int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec,
8378c2ecf20Sopenharmony_ci			    struct _rule_hw *rule_hw)
8388c2ecf20Sopenharmony_ci{
8398c2ecf20Sopenharmony_ci	if (mlx4_hw_rule_sz(dev, spec->id) < 0)
8408c2ecf20Sopenharmony_ci		return -EINVAL;
8418c2ecf20Sopenharmony_ci	memset(rule_hw, 0, mlx4_hw_rule_sz(dev, spec->id));
8428c2ecf20Sopenharmony_ci	rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]);
8438c2ecf20Sopenharmony_ci	rule_hw->size = mlx4_hw_rule_sz(dev, spec->id) >> 2;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	switch (spec->id) {
8468c2ecf20Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_ETH:
8478c2ecf20Sopenharmony_ci		memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN);
8488c2ecf20Sopenharmony_ci		memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk,
8498c2ecf20Sopenharmony_ci		       ETH_ALEN);
8508c2ecf20Sopenharmony_ci		memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN);
8518c2ecf20Sopenharmony_ci		memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk,
8528c2ecf20Sopenharmony_ci		       ETH_ALEN);
8538c2ecf20Sopenharmony_ci		if (spec->eth.ether_type_enable) {
8548c2ecf20Sopenharmony_ci			rule_hw->eth.ether_type_enable = 1;
8558c2ecf20Sopenharmony_ci			rule_hw->eth.ether_type = spec->eth.ether_type;
8568c2ecf20Sopenharmony_ci		}
8578c2ecf20Sopenharmony_ci		rule_hw->eth.vlan_tag = spec->eth.vlan_id;
8588c2ecf20Sopenharmony_ci		rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk;
8598c2ecf20Sopenharmony_ci		break;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_IB:
8628c2ecf20Sopenharmony_ci		rule_hw->ib.l3_qpn = spec->ib.l3_qpn;
8638c2ecf20Sopenharmony_ci		rule_hw->ib.qpn_mask = spec->ib.qpn_msk;
8648c2ecf20Sopenharmony_ci		memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16);
8658c2ecf20Sopenharmony_ci		memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16);
8668c2ecf20Sopenharmony_ci		break;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_IPV6:
8698c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_IPV4:
8728c2ecf20Sopenharmony_ci		rule_hw->ipv4.src_ip = spec->ipv4.src_ip;
8738c2ecf20Sopenharmony_ci		rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk;
8748c2ecf20Sopenharmony_ci		rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip;
8758c2ecf20Sopenharmony_ci		rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk;
8768c2ecf20Sopenharmony_ci		break;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_TCP:
8798c2ecf20Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_UDP:
8808c2ecf20Sopenharmony_ci		rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port;
8818c2ecf20Sopenharmony_ci		rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk;
8828c2ecf20Sopenharmony_ci		rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port;
8838c2ecf20Sopenharmony_ci		rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk;
8848c2ecf20Sopenharmony_ci		break;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	case MLX4_NET_TRANS_RULE_ID_VXLAN:
8878c2ecf20Sopenharmony_ci		rule_hw->vxlan.vni =
8888c2ecf20Sopenharmony_ci			cpu_to_be32(be32_to_cpu(spec->vxlan.vni) << 8);
8898c2ecf20Sopenharmony_ci		rule_hw->vxlan.vni_mask =
8908c2ecf20Sopenharmony_ci			cpu_to_be32(be32_to_cpu(spec->vxlan.vni_mask) << 8);
8918c2ecf20Sopenharmony_ci		break;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	default:
8948c2ecf20Sopenharmony_ci		return -EINVAL;
8958c2ecf20Sopenharmony_ci	}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	return __rule_hw_sz[spec->id];
8988c2ecf20Sopenharmony_ci}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_cistatic void mlx4_err_rule(struct mlx4_dev *dev, char *str,
9018c2ecf20Sopenharmony_ci			  struct mlx4_net_trans_rule *rule)
9028c2ecf20Sopenharmony_ci{
9038c2ecf20Sopenharmony_ci#define BUF_SIZE 256
9048c2ecf20Sopenharmony_ci	struct mlx4_spec_list *cur;
9058c2ecf20Sopenharmony_ci	char buf[BUF_SIZE];
9068c2ecf20Sopenharmony_ci	int len = 0;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	mlx4_err(dev, "%s", str);
9098c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, BUF_SIZE - len,
9108c2ecf20Sopenharmony_ci			 "port = %d prio = 0x%x qp = 0x%x ",
9118c2ecf20Sopenharmony_ci			 rule->port, rule->priority, rule->qpn);
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	list_for_each_entry(cur, &rule->list, list) {
9148c2ecf20Sopenharmony_ci		switch (cur->id) {
9158c2ecf20Sopenharmony_ci		case MLX4_NET_TRANS_RULE_ID_ETH:
9168c2ecf20Sopenharmony_ci			len += scnprintf(buf + len, BUF_SIZE - len,
9178c2ecf20Sopenharmony_ci					 "dmac = %pM ", &cur->eth.dst_mac);
9188c2ecf20Sopenharmony_ci			if (cur->eth.ether_type)
9198c2ecf20Sopenharmony_ci				len += scnprintf(buf + len, BUF_SIZE - len,
9208c2ecf20Sopenharmony_ci						 "ethertype = 0x%x ",
9218c2ecf20Sopenharmony_ci						 be16_to_cpu(cur->eth.ether_type));
9228c2ecf20Sopenharmony_ci			if (cur->eth.vlan_id)
9238c2ecf20Sopenharmony_ci				len += scnprintf(buf + len, BUF_SIZE - len,
9248c2ecf20Sopenharmony_ci						 "vlan-id = %d ",
9258c2ecf20Sopenharmony_ci						 be16_to_cpu(cur->eth.vlan_id));
9268c2ecf20Sopenharmony_ci			break;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		case MLX4_NET_TRANS_RULE_ID_IPV4:
9298c2ecf20Sopenharmony_ci			if (cur->ipv4.src_ip)
9308c2ecf20Sopenharmony_ci				len += scnprintf(buf + len, BUF_SIZE - len,
9318c2ecf20Sopenharmony_ci						 "src-ip = %pI4 ",
9328c2ecf20Sopenharmony_ci						 &cur->ipv4.src_ip);
9338c2ecf20Sopenharmony_ci			if (cur->ipv4.dst_ip)
9348c2ecf20Sopenharmony_ci				len += scnprintf(buf + len, BUF_SIZE - len,
9358c2ecf20Sopenharmony_ci						 "dst-ip = %pI4 ",
9368c2ecf20Sopenharmony_ci						 &cur->ipv4.dst_ip);
9378c2ecf20Sopenharmony_ci			break;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci		case MLX4_NET_TRANS_RULE_ID_TCP:
9408c2ecf20Sopenharmony_ci		case MLX4_NET_TRANS_RULE_ID_UDP:
9418c2ecf20Sopenharmony_ci			if (cur->tcp_udp.src_port)
9428c2ecf20Sopenharmony_ci				len += scnprintf(buf + len, BUF_SIZE - len,
9438c2ecf20Sopenharmony_ci						 "src-port = %d ",
9448c2ecf20Sopenharmony_ci						 be16_to_cpu(cur->tcp_udp.src_port));
9458c2ecf20Sopenharmony_ci			if (cur->tcp_udp.dst_port)
9468c2ecf20Sopenharmony_ci				len += scnprintf(buf + len, BUF_SIZE - len,
9478c2ecf20Sopenharmony_ci						 "dst-port = %d ",
9488c2ecf20Sopenharmony_ci						 be16_to_cpu(cur->tcp_udp.dst_port));
9498c2ecf20Sopenharmony_ci			break;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci		case MLX4_NET_TRANS_RULE_ID_IB:
9528c2ecf20Sopenharmony_ci			len += scnprintf(buf + len, BUF_SIZE - len,
9538c2ecf20Sopenharmony_ci					 "dst-gid = %pI6\n", cur->ib.dst_gid);
9548c2ecf20Sopenharmony_ci			len += scnprintf(buf + len, BUF_SIZE - len,
9558c2ecf20Sopenharmony_ci					 "dst-gid-mask = %pI6\n",
9568c2ecf20Sopenharmony_ci					 cur->ib.dst_gid_msk);
9578c2ecf20Sopenharmony_ci			break;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci		case MLX4_NET_TRANS_RULE_ID_VXLAN:
9608c2ecf20Sopenharmony_ci			len += scnprintf(buf + len, BUF_SIZE - len,
9618c2ecf20Sopenharmony_ci					 "VNID = %d ", be32_to_cpu(cur->vxlan.vni));
9628c2ecf20Sopenharmony_ci			break;
9638c2ecf20Sopenharmony_ci		case MLX4_NET_TRANS_RULE_ID_IPV6:
9648c2ecf20Sopenharmony_ci			break;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci		default:
9678c2ecf20Sopenharmony_ci			break;
9688c2ecf20Sopenharmony_ci		}
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, BUF_SIZE - len, "\n");
9718c2ecf20Sopenharmony_ci	mlx4_err(dev, "%s", buf);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	if (len >= BUF_SIZE)
9748c2ecf20Sopenharmony_ci		mlx4_err(dev, "Network rule error message was truncated, print buffer is too small\n");
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ciint mlx4_flow_attach(struct mlx4_dev *dev,
9788c2ecf20Sopenharmony_ci		     struct mlx4_net_trans_rule *rule, u64 *reg_id)
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
9818c2ecf20Sopenharmony_ci	struct mlx4_spec_list *cur;
9828c2ecf20Sopenharmony_ci	u32 size = 0;
9838c2ecf20Sopenharmony_ci	int ret;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
9868c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox))
9878c2ecf20Sopenharmony_ci		return PTR_ERR(mailbox);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	if (!mlx4_qp_lookup(dev, rule->qpn)) {
9908c2ecf20Sopenharmony_ci		mlx4_err_rule(dev, "QP doesn't exist\n", rule);
9918c2ecf20Sopenharmony_ci		ret = -EINVAL;
9928c2ecf20Sopenharmony_ci		goto out;
9938c2ecf20Sopenharmony_ci	}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	trans_rule_ctrl_to_hw(rule, mailbox->buf);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	list_for_each_entry(cur, &rule->list, list) {
10008c2ecf20Sopenharmony_ci		ret = parse_trans_rule(dev, cur, mailbox->buf + size);
10018c2ecf20Sopenharmony_ci		if (ret < 0)
10028c2ecf20Sopenharmony_ci			goto out;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci		size += ret;
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);
10088c2ecf20Sopenharmony_ci	if (ret == -ENOMEM) {
10098c2ecf20Sopenharmony_ci		mlx4_err_rule(dev,
10108c2ecf20Sopenharmony_ci			      "mcg table is full. Fail to register network rule\n",
10118c2ecf20Sopenharmony_ci			      rule);
10128c2ecf20Sopenharmony_ci	} else if (ret) {
10138c2ecf20Sopenharmony_ci		if (ret == -ENXIO) {
10148c2ecf20Sopenharmony_ci			if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)
10158c2ecf20Sopenharmony_ci				mlx4_err_rule(dev,
10168c2ecf20Sopenharmony_ci					      "DMFS is not enabled, "
10178c2ecf20Sopenharmony_ci					      "failed to register network rule.\n",
10188c2ecf20Sopenharmony_ci					      rule);
10198c2ecf20Sopenharmony_ci			else
10208c2ecf20Sopenharmony_ci				mlx4_err_rule(dev,
10218c2ecf20Sopenharmony_ci					      "Rule exceeds the dmfs_high_rate_mode limitations, "
10228c2ecf20Sopenharmony_ci					      "failed to register network rule.\n",
10238c2ecf20Sopenharmony_ci					      rule);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci		} else {
10268c2ecf20Sopenharmony_ci			mlx4_err_rule(dev, "Fail to register network rule.\n", rule);
10278c2ecf20Sopenharmony_ci		}
10288c2ecf20Sopenharmony_ci	}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ciout:
10318c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	return ret;
10348c2ecf20Sopenharmony_ci}
10358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_flow_attach);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ciint mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id)
10388c2ecf20Sopenharmony_ci{
10398c2ecf20Sopenharmony_ci	int err;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id);
10428c2ecf20Sopenharmony_ci	if (err)
10438c2ecf20Sopenharmony_ci		mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n",
10448c2ecf20Sopenharmony_ci			 reg_id);
10458c2ecf20Sopenharmony_ci	return err;
10468c2ecf20Sopenharmony_ci}
10478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_flow_detach);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ciint mlx4_tunnel_steer_add(struct mlx4_dev *dev, unsigned char *addr,
10508c2ecf20Sopenharmony_ci			  int port, int qpn, u16 prio, u64 *reg_id)
10518c2ecf20Sopenharmony_ci{
10528c2ecf20Sopenharmony_ci	int err;
10538c2ecf20Sopenharmony_ci	struct mlx4_spec_list spec_eth_outer = { {NULL} };
10548c2ecf20Sopenharmony_ci	struct mlx4_spec_list spec_vxlan     = { {NULL} };
10558c2ecf20Sopenharmony_ci	struct mlx4_spec_list spec_eth_inner = { {NULL} };
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	struct mlx4_net_trans_rule rule = {
10588c2ecf20Sopenharmony_ci		.queue_mode = MLX4_NET_TRANS_Q_FIFO,
10598c2ecf20Sopenharmony_ci		.exclusive = 0,
10608c2ecf20Sopenharmony_ci		.allow_loopback = 1,
10618c2ecf20Sopenharmony_ci		.promisc_mode = MLX4_FS_REGULAR,
10628c2ecf20Sopenharmony_ci	};
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	rule.port = port;
10678c2ecf20Sopenharmony_ci	rule.qpn = qpn;
10688c2ecf20Sopenharmony_ci	rule.priority = prio;
10698c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rule.list);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	spec_eth_outer.id = MLX4_NET_TRANS_RULE_ID_ETH;
10728c2ecf20Sopenharmony_ci	memcpy(spec_eth_outer.eth.dst_mac, addr, ETH_ALEN);
10738c2ecf20Sopenharmony_ci	memcpy(spec_eth_outer.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	spec_vxlan.id = MLX4_NET_TRANS_RULE_ID_VXLAN;    /* any vxlan header */
10768c2ecf20Sopenharmony_ci	spec_eth_inner.id = MLX4_NET_TRANS_RULE_ID_ETH;	 /* any inner eth header */
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	list_add_tail(&spec_eth_outer.list, &rule.list);
10798c2ecf20Sopenharmony_ci	list_add_tail(&spec_vxlan.list,     &rule.list);
10808c2ecf20Sopenharmony_ci	list_add_tail(&spec_eth_inner.list, &rule.list);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	err = mlx4_flow_attach(dev, &rule, reg_id);
10838c2ecf20Sopenharmony_ci	return err;
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mlx4_tunnel_steer_add);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ciint mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn,
10888c2ecf20Sopenharmony_ci				      u32 max_range_qpn)
10898c2ecf20Sopenharmony_ci{
10908c2ecf20Sopenharmony_ci	int err;
10918c2ecf20Sopenharmony_ci	u64 in_param;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	in_param = ((u64) min_range_qpn) << 32;
10948c2ecf20Sopenharmony_ci	in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	err = mlx4_cmd(dev, in_param, 0, 0,
10978c2ecf20Sopenharmony_ci			MLX4_FLOW_STEERING_IB_UC_QP_RANGE,
10988c2ecf20Sopenharmony_ci			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	return err;
11018c2ecf20Sopenharmony_ci}
11028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ciint mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
11058c2ecf20Sopenharmony_ci			  int block_mcast_loopback, enum mlx4_protocol prot,
11068c2ecf20Sopenharmony_ci			  enum mlx4_steer_type steer)
11078c2ecf20Sopenharmony_ci{
11088c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
11098c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
11108c2ecf20Sopenharmony_ci	struct mlx4_mgm *mgm;
11118c2ecf20Sopenharmony_ci	u32 members_count;
11128c2ecf20Sopenharmony_ci	int index = -1, prev;
11138c2ecf20Sopenharmony_ci	int link = 0;
11148c2ecf20Sopenharmony_ci	int i;
11158c2ecf20Sopenharmony_ci	int err;
11168c2ecf20Sopenharmony_ci	u8 port = gid[5];
11178c2ecf20Sopenharmony_ci	u8 new_entry = 0;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
11208c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox))
11218c2ecf20Sopenharmony_ci		return PTR_ERR(mailbox);
11228c2ecf20Sopenharmony_ci	mgm = mailbox->buf;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	mutex_lock(&priv->mcg_table.mutex);
11258c2ecf20Sopenharmony_ci	err = find_entry(dev, port, gid, prot,
11268c2ecf20Sopenharmony_ci			 mailbox, &prev, &index);
11278c2ecf20Sopenharmony_ci	if (err)
11288c2ecf20Sopenharmony_ci		goto out;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	if (index != -1) {
11318c2ecf20Sopenharmony_ci		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
11328c2ecf20Sopenharmony_ci			new_entry = 1;
11338c2ecf20Sopenharmony_ci			memcpy(mgm->gid, gid, 16);
11348c2ecf20Sopenharmony_ci		}
11358c2ecf20Sopenharmony_ci	} else {
11368c2ecf20Sopenharmony_ci		link = 1;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci		index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
11398c2ecf20Sopenharmony_ci		if (index == -1) {
11408c2ecf20Sopenharmony_ci			mlx4_err(dev, "No AMGM entries left\n");
11418c2ecf20Sopenharmony_ci			err = -ENOMEM;
11428c2ecf20Sopenharmony_ci			goto out;
11438c2ecf20Sopenharmony_ci		}
11448c2ecf20Sopenharmony_ci		index += dev->caps.num_mgms;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci		new_entry = 1;
11478c2ecf20Sopenharmony_ci		memset(mgm, 0, sizeof(*mgm));
11488c2ecf20Sopenharmony_ci		memcpy(mgm->gid, gid, 16);
11498c2ecf20Sopenharmony_ci	}
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
11528c2ecf20Sopenharmony_ci	if (members_count == dev->caps.num_qp_per_mgm) {
11538c2ecf20Sopenharmony_ci		mlx4_err(dev, "MGM at index %x is full\n", index);
11548c2ecf20Sopenharmony_ci		err = -ENOMEM;
11558c2ecf20Sopenharmony_ci		goto out;
11568c2ecf20Sopenharmony_ci	}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	for (i = 0; i < members_count; ++i)
11598c2ecf20Sopenharmony_ci		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
11608c2ecf20Sopenharmony_ci			mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
11618c2ecf20Sopenharmony_ci			err = 0;
11628c2ecf20Sopenharmony_ci			goto out;
11638c2ecf20Sopenharmony_ci		}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	if (block_mcast_loopback)
11668c2ecf20Sopenharmony_ci		mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
11678c2ecf20Sopenharmony_ci						       (1U << MGM_BLCK_LB_BIT));
11688c2ecf20Sopenharmony_ci	else
11698c2ecf20Sopenharmony_ci		mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30);
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	err = mlx4_WRITE_ENTRY(dev, index, mailbox);
11748c2ecf20Sopenharmony_ci	if (err)
11758c2ecf20Sopenharmony_ci		goto out;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	if (!link)
11788c2ecf20Sopenharmony_ci		goto out;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	err = mlx4_READ_ENTRY(dev, prev, mailbox);
11818c2ecf20Sopenharmony_ci	if (err)
11828c2ecf20Sopenharmony_ci		goto out;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	mgm->next_gid_index = cpu_to_be32(index << 6);
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
11878c2ecf20Sopenharmony_ci	if (err)
11888c2ecf20Sopenharmony_ci		goto out;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ciout:
11918c2ecf20Sopenharmony_ci	if (prot == MLX4_PROT_ETH && index != -1) {
11928c2ecf20Sopenharmony_ci		/* manage the steering entry for promisc mode */
11938c2ecf20Sopenharmony_ci		if (new_entry)
11948c2ecf20Sopenharmony_ci			err = new_steering_entry(dev, port, steer,
11958c2ecf20Sopenharmony_ci						 index, qp->qpn);
11968c2ecf20Sopenharmony_ci		else
11978c2ecf20Sopenharmony_ci			err = existing_steering_entry(dev, port, steer,
11988c2ecf20Sopenharmony_ci						      index, qp->qpn);
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci	if (err && link && index != -1) {
12018c2ecf20Sopenharmony_ci		if (index < dev->caps.num_mgms)
12028c2ecf20Sopenharmony_ci			mlx4_warn(dev, "Got AMGM index %d < %d\n",
12038c2ecf20Sopenharmony_ci				  index, dev->caps.num_mgms);
12048c2ecf20Sopenharmony_ci		else
12058c2ecf20Sopenharmony_ci			mlx4_bitmap_free(&priv->mcg_table.bitmap,
12068c2ecf20Sopenharmony_ci					 index - dev->caps.num_mgms, MLX4_USE_RR);
12078c2ecf20Sopenharmony_ci	}
12088c2ecf20Sopenharmony_ci	mutex_unlock(&priv->mcg_table.mutex);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
12118c2ecf20Sopenharmony_ci	return err;
12128c2ecf20Sopenharmony_ci}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ciint mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
12158c2ecf20Sopenharmony_ci			  enum mlx4_protocol prot, enum mlx4_steer_type steer)
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
12188c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
12198c2ecf20Sopenharmony_ci	struct mlx4_mgm *mgm;
12208c2ecf20Sopenharmony_ci	u32 members_count;
12218c2ecf20Sopenharmony_ci	int prev, index;
12228c2ecf20Sopenharmony_ci	int i, loc = -1;
12238c2ecf20Sopenharmony_ci	int err;
12248c2ecf20Sopenharmony_ci	u8 port = gid[5];
12258c2ecf20Sopenharmony_ci	bool removed_entry = false;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
12288c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox))
12298c2ecf20Sopenharmony_ci		return PTR_ERR(mailbox);
12308c2ecf20Sopenharmony_ci	mgm = mailbox->buf;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	mutex_lock(&priv->mcg_table.mutex);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	err = find_entry(dev, port, gid, prot,
12358c2ecf20Sopenharmony_ci			 mailbox, &prev, &index);
12368c2ecf20Sopenharmony_ci	if (err)
12378c2ecf20Sopenharmony_ci		goto out;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	if (index == -1) {
12408c2ecf20Sopenharmony_ci		mlx4_err(dev, "MGID %pI6 not found\n", gid);
12418c2ecf20Sopenharmony_ci		err = -EINVAL;
12428c2ecf20Sopenharmony_ci		goto out;
12438c2ecf20Sopenharmony_ci	}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	/* If this QP is also a promisc QP, it shouldn't be removed only if
12468c2ecf20Sopenharmony_ci	 * at least one none promisc QP is also attached to this MCG
12478c2ecf20Sopenharmony_ci	 */
12488c2ecf20Sopenharmony_ci	if (prot == MLX4_PROT_ETH &&
12498c2ecf20Sopenharmony_ci	    check_duplicate_entry(dev, port, steer, index, qp->qpn) &&
12508c2ecf20Sopenharmony_ci	    !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL))
12518c2ecf20Sopenharmony_ci			goto out;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
12548c2ecf20Sopenharmony_ci	for (i = 0; i < members_count; ++i)
12558c2ecf20Sopenharmony_ci		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
12568c2ecf20Sopenharmony_ci			loc = i;
12578c2ecf20Sopenharmony_ci			break;
12588c2ecf20Sopenharmony_ci		}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	if (loc == -1) {
12618c2ecf20Sopenharmony_ci		mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
12628c2ecf20Sopenharmony_ci		err = -EINVAL;
12638c2ecf20Sopenharmony_ci		goto out;
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	/* copy the last QP in this MGM over removed QP */
12678c2ecf20Sopenharmony_ci	mgm->qp[loc] = mgm->qp[members_count - 1];
12688c2ecf20Sopenharmony_ci	mgm->qp[members_count - 1] = 0;
12698c2ecf20Sopenharmony_ci	mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30);
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	if (prot == MLX4_PROT_ETH)
12728c2ecf20Sopenharmony_ci		removed_entry = can_remove_steering_entry(dev, port, steer,
12738c2ecf20Sopenharmony_ci								index, qp->qpn);
12748c2ecf20Sopenharmony_ci	if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) {
12758c2ecf20Sopenharmony_ci		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
12768c2ecf20Sopenharmony_ci		goto out;
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	/* We are going to delete the entry, members count should be 0 */
12808c2ecf20Sopenharmony_ci	mgm->members_count = cpu_to_be32((u32) prot << 30);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	if (prev == -1) {
12838c2ecf20Sopenharmony_ci		/* Remove entry from MGM */
12848c2ecf20Sopenharmony_ci		int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
12858c2ecf20Sopenharmony_ci		if (amgm_index) {
12868c2ecf20Sopenharmony_ci			err = mlx4_READ_ENTRY(dev, amgm_index, mailbox);
12878c2ecf20Sopenharmony_ci			if (err)
12888c2ecf20Sopenharmony_ci				goto out;
12898c2ecf20Sopenharmony_ci		} else
12908c2ecf20Sopenharmony_ci			memset(mgm->gid, 0, 16);
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci		err = mlx4_WRITE_ENTRY(dev, index, mailbox);
12938c2ecf20Sopenharmony_ci		if (err)
12948c2ecf20Sopenharmony_ci			goto out;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci		if (amgm_index) {
12978c2ecf20Sopenharmony_ci			if (amgm_index < dev->caps.num_mgms)
12988c2ecf20Sopenharmony_ci				mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d\n",
12998c2ecf20Sopenharmony_ci					  index, amgm_index, dev->caps.num_mgms);
13008c2ecf20Sopenharmony_ci			else
13018c2ecf20Sopenharmony_ci				mlx4_bitmap_free(&priv->mcg_table.bitmap,
13028c2ecf20Sopenharmony_ci						 amgm_index - dev->caps.num_mgms, MLX4_USE_RR);
13038c2ecf20Sopenharmony_ci		}
13048c2ecf20Sopenharmony_ci	} else {
13058c2ecf20Sopenharmony_ci		/* Remove entry from AMGM */
13068c2ecf20Sopenharmony_ci		int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
13078c2ecf20Sopenharmony_ci		err = mlx4_READ_ENTRY(dev, prev, mailbox);
13088c2ecf20Sopenharmony_ci		if (err)
13098c2ecf20Sopenharmony_ci			goto out;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci		mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci		err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
13148c2ecf20Sopenharmony_ci		if (err)
13158c2ecf20Sopenharmony_ci			goto out;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci		if (index < dev->caps.num_mgms)
13188c2ecf20Sopenharmony_ci			mlx4_warn(dev, "entry %d had next AMGM index %d < %d\n",
13198c2ecf20Sopenharmony_ci				  prev, index, dev->caps.num_mgms);
13208c2ecf20Sopenharmony_ci		else
13218c2ecf20Sopenharmony_ci			mlx4_bitmap_free(&priv->mcg_table.bitmap,
13228c2ecf20Sopenharmony_ci					 index - dev->caps.num_mgms, MLX4_USE_RR);
13238c2ecf20Sopenharmony_ci	}
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ciout:
13268c2ecf20Sopenharmony_ci	mutex_unlock(&priv->mcg_table.mutex);
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
13298c2ecf20Sopenharmony_ci	if (err && dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
13308c2ecf20Sopenharmony_ci		/* In case device is under an error, return success as a closing command */
13318c2ecf20Sopenharmony_ci		err = 0;
13328c2ecf20Sopenharmony_ci	return err;
13338c2ecf20Sopenharmony_ci}
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_cistatic int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,
13368c2ecf20Sopenharmony_ci			  u8 gid[16], u8 attach, u8 block_loopback,
13378c2ecf20Sopenharmony_ci			  enum mlx4_protocol prot)
13388c2ecf20Sopenharmony_ci{
13398c2ecf20Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
13408c2ecf20Sopenharmony_ci	int err = 0;
13418c2ecf20Sopenharmony_ci	int qpn;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	if (!mlx4_is_mfunc(dev))
13448c2ecf20Sopenharmony_ci		return -EBADF;
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
13478c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox))
13488c2ecf20Sopenharmony_ci		return PTR_ERR(mailbox);
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	memcpy(mailbox->buf, gid, 16);
13518c2ecf20Sopenharmony_ci	qpn = qp->qpn;
13528c2ecf20Sopenharmony_ci	qpn |= (prot << 28);
13538c2ecf20Sopenharmony_ci	if (attach && block_loopback)
13548c2ecf20Sopenharmony_ci		qpn |= (1 << 31);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma, qpn, attach,
13578c2ecf20Sopenharmony_ci		       MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A,
13588c2ecf20Sopenharmony_ci		       MLX4_CMD_WRAPPED);
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
13618c2ecf20Sopenharmony_ci	if (err && !attach &&
13628c2ecf20Sopenharmony_ci	    dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
13638c2ecf20Sopenharmony_ci		err = 0;
13648c2ecf20Sopenharmony_ci	return err;
13658c2ecf20Sopenharmony_ci}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ciint mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,
13688c2ecf20Sopenharmony_ci			      u8 gid[16], u8 port,
13698c2ecf20Sopenharmony_ci			      int block_mcast_loopback,
13708c2ecf20Sopenharmony_ci			      enum mlx4_protocol prot, u64 *reg_id)
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci		struct mlx4_spec_list spec = { {NULL} };
13738c2ecf20Sopenharmony_ci		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci		struct mlx4_net_trans_rule rule = {
13768c2ecf20Sopenharmony_ci			.queue_mode = MLX4_NET_TRANS_Q_FIFO,
13778c2ecf20Sopenharmony_ci			.exclusive = 0,
13788c2ecf20Sopenharmony_ci			.promisc_mode = MLX4_FS_REGULAR,
13798c2ecf20Sopenharmony_ci			.priority = MLX4_DOMAIN_NIC,
13808c2ecf20Sopenharmony_ci		};
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci		rule.allow_loopback = !block_mcast_loopback;
13838c2ecf20Sopenharmony_ci		rule.port = port;
13848c2ecf20Sopenharmony_ci		rule.qpn = qp->qpn;
13858c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&rule.list);
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci		switch (prot) {
13888c2ecf20Sopenharmony_ci		case MLX4_PROT_ETH:
13898c2ecf20Sopenharmony_ci			spec.id = MLX4_NET_TRANS_RULE_ID_ETH;
13908c2ecf20Sopenharmony_ci			memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN);
13918c2ecf20Sopenharmony_ci			memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
13928c2ecf20Sopenharmony_ci			break;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci		case MLX4_PROT_IB_IPV6:
13958c2ecf20Sopenharmony_ci			spec.id = MLX4_NET_TRANS_RULE_ID_IB;
13968c2ecf20Sopenharmony_ci			memcpy(spec.ib.dst_gid, gid, 16);
13978c2ecf20Sopenharmony_ci			memset(&spec.ib.dst_gid_msk, 0xff, 16);
13988c2ecf20Sopenharmony_ci			break;
13998c2ecf20Sopenharmony_ci		default:
14008c2ecf20Sopenharmony_ci			return -EINVAL;
14018c2ecf20Sopenharmony_ci		}
14028c2ecf20Sopenharmony_ci		list_add_tail(&spec.list, &rule.list);
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci		return mlx4_flow_attach(dev, &rule, reg_id);
14058c2ecf20Sopenharmony_ci}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ciint mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
14088c2ecf20Sopenharmony_ci			  u8 port, int block_mcast_loopback,
14098c2ecf20Sopenharmony_ci			  enum mlx4_protocol prot, u64 *reg_id)
14108c2ecf20Sopenharmony_ci{
14118c2ecf20Sopenharmony_ci	switch (dev->caps.steering_mode) {
14128c2ecf20Sopenharmony_ci	case MLX4_STEERING_MODE_A0:
14138c2ecf20Sopenharmony_ci		if (prot == MLX4_PROT_ETH)
14148c2ecf20Sopenharmony_ci			return 0;
14158c2ecf20Sopenharmony_ci		fallthrough;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	case MLX4_STEERING_MODE_B0:
14188c2ecf20Sopenharmony_ci		if (prot == MLX4_PROT_ETH)
14198c2ecf20Sopenharmony_ci			gid[7] |= (MLX4_MC_STEER << 1);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci		if (mlx4_is_mfunc(dev))
14228c2ecf20Sopenharmony_ci			return mlx4_QP_ATTACH(dev, qp, gid, 1,
14238c2ecf20Sopenharmony_ci					      block_mcast_loopback, prot);
14248c2ecf20Sopenharmony_ci		return mlx4_qp_attach_common(dev, qp, gid,
14258c2ecf20Sopenharmony_ci					     block_mcast_loopback, prot,
14268c2ecf20Sopenharmony_ci					     MLX4_MC_STEER);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	case MLX4_STEERING_MODE_DEVICE_MANAGED:
14298c2ecf20Sopenharmony_ci		return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
14308c2ecf20Sopenharmony_ci						 block_mcast_loopback,
14318c2ecf20Sopenharmony_ci						 prot, reg_id);
14328c2ecf20Sopenharmony_ci	default:
14338c2ecf20Sopenharmony_ci		return -EINVAL;
14348c2ecf20Sopenharmony_ci	}
14358c2ecf20Sopenharmony_ci}
14368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_multicast_attach);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ciint mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
14398c2ecf20Sopenharmony_ci			  enum mlx4_protocol prot, u64 reg_id)
14408c2ecf20Sopenharmony_ci{
14418c2ecf20Sopenharmony_ci	switch (dev->caps.steering_mode) {
14428c2ecf20Sopenharmony_ci	case MLX4_STEERING_MODE_A0:
14438c2ecf20Sopenharmony_ci		if (prot == MLX4_PROT_ETH)
14448c2ecf20Sopenharmony_ci			return 0;
14458c2ecf20Sopenharmony_ci		fallthrough;
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	case MLX4_STEERING_MODE_B0:
14488c2ecf20Sopenharmony_ci		if (prot == MLX4_PROT_ETH)
14498c2ecf20Sopenharmony_ci			gid[7] |= (MLX4_MC_STEER << 1);
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci		if (mlx4_is_mfunc(dev))
14528c2ecf20Sopenharmony_ci			return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci		return mlx4_qp_detach_common(dev, qp, gid, prot,
14558c2ecf20Sopenharmony_ci					     MLX4_MC_STEER);
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	case MLX4_STEERING_MODE_DEVICE_MANAGED:
14588c2ecf20Sopenharmony_ci		return mlx4_flow_detach(dev, reg_id);
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	default:
14618c2ecf20Sopenharmony_ci		return -EINVAL;
14628c2ecf20Sopenharmony_ci	}
14638c2ecf20Sopenharmony_ci}
14648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_multicast_detach);
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ciint mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,
14678c2ecf20Sopenharmony_ci				u32 qpn, enum mlx4_net_trans_promisc_mode mode)
14688c2ecf20Sopenharmony_ci{
14698c2ecf20Sopenharmony_ci	struct mlx4_net_trans_rule rule = {
14708c2ecf20Sopenharmony_ci		.queue_mode = MLX4_NET_TRANS_Q_FIFO,
14718c2ecf20Sopenharmony_ci		.exclusive = 0,
14728c2ecf20Sopenharmony_ci		.allow_loopback = 1,
14738c2ecf20Sopenharmony_ci	};
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	u64 *regid_p;
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	switch (mode) {
14788c2ecf20Sopenharmony_ci	case MLX4_FS_ALL_DEFAULT:
14798c2ecf20Sopenharmony_ci		regid_p = &dev->regid_promisc_array[port];
14808c2ecf20Sopenharmony_ci		break;
14818c2ecf20Sopenharmony_ci	case MLX4_FS_MC_DEFAULT:
14828c2ecf20Sopenharmony_ci		regid_p = &dev->regid_allmulti_array[port];
14838c2ecf20Sopenharmony_ci		break;
14848c2ecf20Sopenharmony_ci	default:
14858c2ecf20Sopenharmony_ci		return -1;
14868c2ecf20Sopenharmony_ci	}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	if (*regid_p != 0)
14898c2ecf20Sopenharmony_ci		return -1;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	rule.promisc_mode = mode;
14928c2ecf20Sopenharmony_ci	rule.port = port;
14938c2ecf20Sopenharmony_ci	rule.qpn = qpn;
14948c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rule.list);
14958c2ecf20Sopenharmony_ci	mlx4_info(dev, "going promisc on %x\n", port);
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	return  mlx4_flow_attach(dev, &rule, regid_p);
14988c2ecf20Sopenharmony_ci}
14998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ciint mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port,
15028c2ecf20Sopenharmony_ci				   enum mlx4_net_trans_promisc_mode mode)
15038c2ecf20Sopenharmony_ci{
15048c2ecf20Sopenharmony_ci	int ret;
15058c2ecf20Sopenharmony_ci	u64 *regid_p;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	switch (mode) {
15088c2ecf20Sopenharmony_ci	case MLX4_FS_ALL_DEFAULT:
15098c2ecf20Sopenharmony_ci		regid_p = &dev->regid_promisc_array[port];
15108c2ecf20Sopenharmony_ci		break;
15118c2ecf20Sopenharmony_ci	case MLX4_FS_MC_DEFAULT:
15128c2ecf20Sopenharmony_ci		regid_p = &dev->regid_allmulti_array[port];
15138c2ecf20Sopenharmony_ci		break;
15148c2ecf20Sopenharmony_ci	default:
15158c2ecf20Sopenharmony_ci		return -1;
15168c2ecf20Sopenharmony_ci	}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	if (*regid_p == 0)
15198c2ecf20Sopenharmony_ci		return -1;
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	ret =  mlx4_flow_detach(dev, *regid_p);
15228c2ecf20Sopenharmony_ci	if (ret == 0)
15238c2ecf20Sopenharmony_ci		*regid_p = 0;
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	return ret;
15268c2ecf20Sopenharmony_ci}
15278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove);
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ciint mlx4_unicast_attach(struct mlx4_dev *dev,
15308c2ecf20Sopenharmony_ci			struct mlx4_qp *qp, u8 gid[16],
15318c2ecf20Sopenharmony_ci			int block_mcast_loopback, enum mlx4_protocol prot)
15328c2ecf20Sopenharmony_ci{
15338c2ecf20Sopenharmony_ci	if (prot == MLX4_PROT_ETH)
15348c2ecf20Sopenharmony_ci		gid[7] |= (MLX4_UC_STEER << 1);
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
15378c2ecf20Sopenharmony_ci		return mlx4_QP_ATTACH(dev, qp, gid, 1,
15388c2ecf20Sopenharmony_ci					block_mcast_loopback, prot);
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback,
15418c2ecf20Sopenharmony_ci					prot, MLX4_UC_STEER);
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_unicast_attach);
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ciint mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
15468c2ecf20Sopenharmony_ci			       u8 gid[16], enum mlx4_protocol prot)
15478c2ecf20Sopenharmony_ci{
15488c2ecf20Sopenharmony_ci	if (prot == MLX4_PROT_ETH)
15498c2ecf20Sopenharmony_ci		gid[7] |= (MLX4_UC_STEER << 1);
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
15528c2ecf20Sopenharmony_ci		return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER);
15558c2ecf20Sopenharmony_ci}
15568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_unicast_detach);
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ciint mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave,
15598c2ecf20Sopenharmony_ci			 struct mlx4_vhcr *vhcr,
15608c2ecf20Sopenharmony_ci			 struct mlx4_cmd_mailbox *inbox,
15618c2ecf20Sopenharmony_ci			 struct mlx4_cmd_mailbox *outbox,
15628c2ecf20Sopenharmony_ci			 struct mlx4_cmd_info *cmd)
15638c2ecf20Sopenharmony_ci{
15648c2ecf20Sopenharmony_ci	u32 qpn = (u32) vhcr->in_param & 0xffffffff;
15658c2ecf20Sopenharmony_ci	int port = mlx4_slave_convert_port(dev, slave, vhcr->in_param >> 62);
15668c2ecf20Sopenharmony_ci	enum mlx4_steer_type steer = vhcr->in_modifier;
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	if (port < 0)
15698c2ecf20Sopenharmony_ci		return -EINVAL;
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	/* Promiscuous unicast is not allowed in mfunc */
15728c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)
15738c2ecf20Sopenharmony_ci		return 0;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	if (vhcr->op_modifier)
15768c2ecf20Sopenharmony_ci		return add_promisc_qp(dev, port, steer, qpn);
15778c2ecf20Sopenharmony_ci	else
15788c2ecf20Sopenharmony_ci		return remove_promisc_qp(dev, port, steer, qpn);
15798c2ecf20Sopenharmony_ci}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_cistatic int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn,
15828c2ecf20Sopenharmony_ci			enum mlx4_steer_type steer, u8 add, u8 port)
15838c2ecf20Sopenharmony_ci{
15848c2ecf20Sopenharmony_ci	return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add,
15858c2ecf20Sopenharmony_ci			MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A,
15868c2ecf20Sopenharmony_ci			MLX4_CMD_WRAPPED);
15878c2ecf20Sopenharmony_ci}
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ciint mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
15908c2ecf20Sopenharmony_ci{
15918c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
15928c2ecf20Sopenharmony_ci		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port);
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
15958c2ecf20Sopenharmony_ci}
15968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add);
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ciint mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
15998c2ecf20Sopenharmony_ci{
16008c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
16018c2ecf20Sopenharmony_ci		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port);
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn);
16048c2ecf20Sopenharmony_ci}
16058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ciint mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
16108c2ecf20Sopenharmony_ci		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port);
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
16138c2ecf20Sopenharmony_ci}
16148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add);
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ciint mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
16178c2ecf20Sopenharmony_ci{
16188c2ecf20Sopenharmony_ci	if (mlx4_is_mfunc(dev))
16198c2ecf20Sopenharmony_ci		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port);
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn);
16228c2ecf20Sopenharmony_ci}
16238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove);
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ciint mlx4_init_mcg_table(struct mlx4_dev *dev)
16268c2ecf20Sopenharmony_ci{
16278c2ecf20Sopenharmony_ci	struct mlx4_priv *priv = mlx4_priv(dev);
16288c2ecf20Sopenharmony_ci	int err;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	/* No need for mcg_table when fw managed the mcg table*/
16318c2ecf20Sopenharmony_ci	if (dev->caps.steering_mode ==
16328c2ecf20Sopenharmony_ci	    MLX4_STEERING_MODE_DEVICE_MANAGED)
16338c2ecf20Sopenharmony_ci		return 0;
16348c2ecf20Sopenharmony_ci	err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
16358c2ecf20Sopenharmony_ci			       dev->caps.num_amgms - 1, 0, 0);
16368c2ecf20Sopenharmony_ci	if (err)
16378c2ecf20Sopenharmony_ci		return err;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	mutex_init(&priv->mcg_table.mutex);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	return 0;
16428c2ecf20Sopenharmony_ci}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_civoid mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
16458c2ecf20Sopenharmony_ci{
16468c2ecf20Sopenharmony_ci	if (dev->caps.steering_mode !=
16478c2ecf20Sopenharmony_ci	    MLX4_STEERING_MODE_DEVICE_MANAGED)
16488c2ecf20Sopenharmony_ci		mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
16498c2ecf20Sopenharmony_ci}
1650