brintos

brintos / linux-shallow public Read only

0
0
Text · 41.8 KiB · 24d0c7c Raw
1650 lines · c
1/*2 * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.3 * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.4 *5 * This software is available to you under a choice of one of two6 * licenses.  You may choose to be licensed under the terms of the GNU7 * General Public License (GPL) Version 2, available from the file8 * COPYING in the main directory of this source tree, or the9 * OpenIB.org BSD license below:10 *11 *     Redistribution and use in source and binary forms, with or12 *     without modification, are permitted provided that the following13 *     conditions are met:14 *15 *      - Redistributions of source code must retain the above16 *        copyright notice, this list of conditions and the following17 *        disclaimer.18 *19 *      - Redistributions in binary form must reproduce the above20 *        copyright notice, this list of conditions and the following21 *        disclaimer in the documentation and/or other materials22 *        provided with the distribution.23 *24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE31 * SOFTWARE.32 */33 34#include <linux/string.h>35#include <linux/etherdevice.h>36 37#include <linux/mlx4/cmd.h>38#include <linux/mlx4/qp.h>39#include <linux/export.h>40 41#include "mlx4.h"42 43int mlx4_get_mgm_entry_size(struct mlx4_dev *dev)44{45	return 1 << dev->oper_log_mgm_entry_size;46}47 48int mlx4_get_qp_per_mgm(struct mlx4_dev *dev)49{50	return 4 * (mlx4_get_mgm_entry_size(dev) / 16 - 2);51}52 53static int mlx4_QP_FLOW_STEERING_ATTACH(struct mlx4_dev *dev,54					struct mlx4_cmd_mailbox *mailbox,55					u32 size,56					u64 *reg_id)57{58	u64 imm;59	int err = 0;60 61	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, size, 0,62			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,63			   MLX4_CMD_NATIVE);64	if (err)65		return err;66	*reg_id = imm;67 68	return err;69}70 71static int mlx4_QP_FLOW_STEERING_DETACH(struct mlx4_dev *dev, u64 regid)72{73	int err = 0;74 75	err = mlx4_cmd(dev, regid, 0, 0,76		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,77		       MLX4_CMD_NATIVE);78 79	return err;80}81 82static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index,83			   struct mlx4_cmd_mailbox *mailbox)84{85	return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG,86			    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);87}88 89static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index,90			    struct mlx4_cmd_mailbox *mailbox)91{92	return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG,93			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);94}95 96static int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 port, u8 steer,97			      struct mlx4_cmd_mailbox *mailbox)98{99	u32 in_mod;100 101	in_mod = (u32) port << 16 | steer << 1;102	return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1,103			MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A,104			MLX4_CMD_NATIVE);105}106 107static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,108			 u16 *hash, u8 op_mod)109{110	u64 imm;111	int err;112 113	err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod,114			   MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A,115			   MLX4_CMD_NATIVE);116 117	if (!err)118		*hash = imm;119 120	return err;121}122 123static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 port,124					      enum mlx4_steer_type steer,125					      u32 qpn)126{127	struct mlx4_steer *s_steer;128	struct mlx4_promisc_qp *pqp;129 130	if (port < 1 || port > dev->caps.num_ports)131		return NULL;132 133	s_steer = &mlx4_priv(dev)->steer[port - 1];134 135	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {136		if (pqp->qpn == qpn)137			return pqp;138	}139	/* not found */140	return NULL;141}142 143/*144 * Add new entry to steering data structure.145 * All promisc QPs should be added as well146 */147static int new_steering_entry(struct mlx4_dev *dev, u8 port,148			      enum mlx4_steer_type steer,149			      unsigned int index, u32 qpn)150{151	struct mlx4_steer *s_steer;152	struct mlx4_cmd_mailbox *mailbox;153	struct mlx4_mgm *mgm;154	u32 members_count;155	struct mlx4_steer_index *new_entry;156	struct mlx4_promisc_qp *pqp;157	struct mlx4_promisc_qp *dqp = NULL;158	u32 prot;159	int err;160 161	if (port < 1 || port > dev->caps.num_ports)162		return -EINVAL;163 164	s_steer = &mlx4_priv(dev)->steer[port - 1];165	new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);166	if (!new_entry)167		return -ENOMEM;168 169	INIT_LIST_HEAD(&new_entry->duplicates);170	new_entry->index = index;171	list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]);172 173	/* If the given qpn is also a promisc qp,174	 * it should be inserted to duplicates list175	 */176	pqp = get_promisc_qp(dev, port, steer, qpn);177	if (pqp) {178		dqp = kmalloc(sizeof(*dqp), GFP_KERNEL);179		if (!dqp) {180			err = -ENOMEM;181			goto out_alloc;182		}183		dqp->qpn = qpn;184		list_add_tail(&dqp->list, &new_entry->duplicates);185	}186 187	/* if no promisc qps for this vep, we are done */188	if (list_empty(&s_steer->promisc_qps[steer]))189		return 0;190 191	/* now need to add all the promisc qps to the new192	 * steering entry, as they should also receive the packets193	 * destined to this address */194	mailbox = mlx4_alloc_cmd_mailbox(dev);195	if (IS_ERR(mailbox)) {196		err = -ENOMEM;197		goto out_alloc;198	}199	mgm = mailbox->buf;200 201	err = mlx4_READ_ENTRY(dev, index, mailbox);202	if (err)203		goto out_mailbox;204 205	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;206	prot = be32_to_cpu(mgm->members_count) >> 30;207	list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {208		/* don't add already existing qpn */209		if (pqp->qpn == qpn)210			continue;211		if (members_count == dev->caps.num_qp_per_mgm) {212			/* out of space */213			err = -ENOMEM;214			goto out_mailbox;215		}216 217		/* add the qpn */218		mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK);219	}220	/* update the qps count and update the entry with all the promisc qps*/221	mgm->members_count = cpu_to_be32(members_count | (prot << 30));222	err = mlx4_WRITE_ENTRY(dev, index, mailbox);223 224out_mailbox:225	mlx4_free_cmd_mailbox(dev, mailbox);226	if (!err)227		return 0;228out_alloc:229	if (dqp) {230		list_del(&dqp->list);231		kfree(dqp);232	}233	list_del(&new_entry->list);234	kfree(new_entry);235	return err;236}237 238/* update the data structures with existing steering entry */239static int existing_steering_entry(struct mlx4_dev *dev, u8 port,240				   enum mlx4_steer_type steer,241				   unsigned int index, u32 qpn)242{243	struct mlx4_steer *s_steer;244	struct mlx4_steer_index *tmp_entry, *entry = NULL;245	struct mlx4_promisc_qp *pqp;246	struct mlx4_promisc_qp *dqp;247 248	if (port < 1 || port > dev->caps.num_ports)249		return -EINVAL;250 251	s_steer = &mlx4_priv(dev)->steer[port - 1];252 253	pqp = get_promisc_qp(dev, port, steer, qpn);254	if (!pqp)255		return 0; /* nothing to do */256 257	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {258		if (tmp_entry->index == index) {259			entry = tmp_entry;260			break;261		}262	}263	if (unlikely(!entry)) {264		mlx4_warn(dev, "Steering entry at index %x is not registered\n", index);265		return -EINVAL;266	}267 268	/* the given qpn is listed as a promisc qpn269	 * we need to add it as a duplicate to this entry270	 * for future references */271	list_for_each_entry(dqp, &entry->duplicates, list) {272		if (qpn == dqp->qpn)273			return 0; /* qp is already duplicated */274	}275 276	/* add the qp as a duplicate on this index */277	dqp = kmalloc(sizeof(*dqp), GFP_KERNEL);278	if (!dqp)279		return -ENOMEM;280	dqp->qpn = qpn;281	list_add_tail(&dqp->list, &entry->duplicates);282 283	return 0;284}285 286/* Check whether a qpn is a duplicate on steering entry287 * If so, it should not be removed from mgm */288static bool check_duplicate_entry(struct mlx4_dev *dev, u8 port,289				  enum mlx4_steer_type steer,290				  unsigned int index, u32 qpn)291{292	struct mlx4_steer *s_steer;293	struct mlx4_steer_index *tmp_entry, *entry = NULL;294	struct mlx4_promisc_qp *dqp, *tmp_dqp;295 296	if (port < 1 || port > dev->caps.num_ports)297		return false;298 299	s_steer = &mlx4_priv(dev)->steer[port - 1];300 301	/* if qp is not promisc, it cannot be duplicated */302	if (!get_promisc_qp(dev, port, steer, qpn))303		return false;304 305	/* The qp is promisc qp so it is a duplicate on this index306	 * Find the index entry, and remove the duplicate */307	list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {308		if (tmp_entry->index == index) {309			entry = tmp_entry;310			break;311		}312	}313	if (unlikely(!entry)) {314		mlx4_warn(dev, "Steering entry for index %x is not registered\n", index);315		return false;316	}317	list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) {318		if (dqp->qpn == qpn) {319			list_del(&dqp->list);320			kfree(dqp);321		}322	}323	return true;324}325 326/* Returns true if all the QPs != tqpn contained in this entry327 * are Promisc QPs. Returns false otherwise.328 */329static bool promisc_steering_entry(struct mlx4_dev *dev, u8 port,330				   enum mlx4_steer_type steer,331				   unsigned int index, u32 tqpn,332				   u32 *members_count)333{334	struct mlx4_cmd_mailbox *mailbox;335	struct mlx4_mgm *mgm;336	u32 m_count;337	bool ret = false;338	int i;339 340	if (port < 1 || port > dev->caps.num_ports)341		return false;342 343	mailbox = mlx4_alloc_cmd_mailbox(dev);344	if (IS_ERR(mailbox))345		return false;346	mgm = mailbox->buf;347 348	if (mlx4_READ_ENTRY(dev, index, mailbox))349		goto out;350	m_count = be32_to_cpu(mgm->members_count) & 0xffffff;351	if (members_count)352		*members_count = m_count;353 354	for (i = 0;  i < m_count; i++) {355		u32 qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;356		if (!get_promisc_qp(dev, port, steer, qpn) && qpn != tqpn) {357			/* the qp is not promisc, the entry can't be removed */358			goto out;359		}360	}361	ret = true;362out:363	mlx4_free_cmd_mailbox(dev, mailbox);364	return ret;365}366 367/* IF a steering entry contains only promisc QPs, it can be removed. */368static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,369				      enum mlx4_steer_type steer,370				      unsigned int index, u32 tqpn)371{372	struct mlx4_steer *s_steer;373	struct mlx4_steer_index *entry = NULL, *tmp_entry;374	u32 members_count;375	bool ret = false;376 377	if (port < 1 || port > dev->caps.num_ports)378		return false;379 380	s_steer = &mlx4_priv(dev)->steer[port - 1];381 382	if (!promisc_steering_entry(dev, port, steer, index,383				    tqpn, &members_count))384		goto out;385 386	/* All the qps currently registered for this entry are promiscuous,387	  * Checking for duplicates */388	ret = true;389	list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {390		if (entry->index == index) {391			if (list_empty(&entry->duplicates) ||392			    members_count == 1) {393				struct mlx4_promisc_qp *pqp, *tmp_pqp;394				/* If there is only 1 entry in duplicates then395				 * this is the QP we want to delete, going over396				 * the list and deleting the entry.397				 */398				list_del(&entry->list);399				list_for_each_entry_safe(pqp, tmp_pqp,400							 &entry->duplicates,401							 list) {402					list_del(&pqp->list);403					kfree(pqp);404				}405				kfree(entry);406			} else {407				/* This entry contains duplicates so it shouldn't be removed */408				ret = false;409				goto out;410			}411		}412	}413 414out:415	return ret;416}417 418static int add_promisc_qp(struct mlx4_dev *dev, u8 port,419			  enum mlx4_steer_type steer, u32 qpn)420{421	struct mlx4_steer *s_steer;422	struct mlx4_cmd_mailbox *mailbox;423	struct mlx4_mgm *mgm;424	struct mlx4_steer_index *entry;425	struct mlx4_promisc_qp *pqp;426	struct mlx4_promisc_qp *dqp;427	u32 members_count;428	u32 prot;429	int i;430	bool found;431	int err;432	struct mlx4_priv *priv = mlx4_priv(dev);433 434	if (port < 1 || port > dev->caps.num_ports)435		return -EINVAL;436 437	s_steer = &mlx4_priv(dev)->steer[port - 1];438 439	mutex_lock(&priv->mcg_table.mutex);440 441	if (get_promisc_qp(dev, port, steer, qpn)) {442		err = 0;  /* Noting to do, already exists */443		goto out_mutex;444	}445 446	pqp = kmalloc(sizeof(*pqp), GFP_KERNEL);447	if (!pqp) {448		err = -ENOMEM;449		goto out_mutex;450	}451	pqp->qpn = qpn;452 453	mailbox = mlx4_alloc_cmd_mailbox(dev);454	if (IS_ERR(mailbox)) {455		err = -ENOMEM;456		goto out_alloc;457	}458	mgm = mailbox->buf;459 460	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {461		/* The promisc QP needs to be added for each one of the steering462		 * entries. If it already exists, needs to be added as463		 * a duplicate for this entry.464		 */465		list_for_each_entry(entry,466				    &s_steer->steer_entries[steer],467				    list) {468			err = mlx4_READ_ENTRY(dev, entry->index, mailbox);469			if (err)470				goto out_mailbox;471 472			members_count = be32_to_cpu(mgm->members_count) &473					0xffffff;474			prot = be32_to_cpu(mgm->members_count) >> 30;475			found = false;476			for (i = 0; i < members_count; i++) {477				if ((be32_to_cpu(mgm->qp[i]) &478				     MGM_QPN_MASK) == qpn) {479					/* Entry already exists.480					 * Add to duplicates.481					 */482					dqp = kmalloc(sizeof(*dqp), GFP_KERNEL);483					if (!dqp) {484						err = -ENOMEM;485						goto out_mailbox;486					}487					dqp->qpn = qpn;488					list_add_tail(&dqp->list,489						      &entry->duplicates);490					found = true;491				}492			}493			if (!found) {494				/* Need to add the qpn to mgm */495				if (members_count ==496				    dev->caps.num_qp_per_mgm) {497					/* entry is full */498					err = -ENOMEM;499					goto out_mailbox;500				}501				mgm->qp[members_count++] =502					cpu_to_be32(qpn & MGM_QPN_MASK);503				mgm->members_count =504					cpu_to_be32(members_count |505						    (prot << 30));506				err = mlx4_WRITE_ENTRY(dev, entry->index,507						       mailbox);508				if (err)509					goto out_mailbox;510			}511		}512	}513 514	/* add the new qpn to list of promisc qps */515	list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);516	/* now need to add all the promisc qps to default entry */517	memset(mgm, 0, sizeof(*mgm));518	members_count = 0;519	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) {520		if (members_count == dev->caps.num_qp_per_mgm) {521			/* entry is full */522			err = -ENOMEM;523			goto out_list;524		}525		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);526	}527	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);528 529	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);530	if (err)531		goto out_list;532 533	mlx4_free_cmd_mailbox(dev, mailbox);534	mutex_unlock(&priv->mcg_table.mutex);535	return 0;536 537out_list:538	list_del(&pqp->list);539out_mailbox:540	mlx4_free_cmd_mailbox(dev, mailbox);541out_alloc:542	kfree(pqp);543out_mutex:544	mutex_unlock(&priv->mcg_table.mutex);545	return err;546}547 548static int remove_promisc_qp(struct mlx4_dev *dev, u8 port,549			     enum mlx4_steer_type steer, u32 qpn)550{551	struct mlx4_priv *priv = mlx4_priv(dev);552	struct mlx4_steer *s_steer;553	struct mlx4_cmd_mailbox *mailbox;554	struct mlx4_mgm *mgm;555	struct mlx4_steer_index *entry, *tmp_entry;556	struct mlx4_promisc_qp *pqp;557	struct mlx4_promisc_qp *dqp;558	u32 members_count;559	bool found;560	bool back_to_list = false;561	int i;562	int err;563 564	if (port < 1 || port > dev->caps.num_ports)565		return -EINVAL;566 567	s_steer = &mlx4_priv(dev)->steer[port - 1];568	mutex_lock(&priv->mcg_table.mutex);569 570	pqp = get_promisc_qp(dev, port, steer, qpn);571	if (unlikely(!pqp)) {572		mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn);573		/* nothing to do */574		err = 0;575		goto out_mutex;576	}577 578	/*remove from list of promisc qps */579	list_del(&pqp->list);580 581	/* set the default entry not to include the removed one */582	mailbox = mlx4_alloc_cmd_mailbox(dev);583	if (IS_ERR(mailbox)) {584		err = -ENOMEM;585		back_to_list = true;586		goto out_list;587	}588	mgm = mailbox->buf;589	members_count = 0;590	list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)591		mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);592	mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);593 594	err = mlx4_WRITE_PROMISC(dev, port, steer, mailbox);595	if (err)596		goto out_mailbox;597 598	if (!(mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)) {599		/* Remove the QP from all the steering entries */600		list_for_each_entry_safe(entry, tmp_entry,601					 &s_steer->steer_entries[steer],602					 list) {603			found = false;604			list_for_each_entry(dqp, &entry->duplicates, list) {605				if (dqp->qpn == qpn) {606					found = true;607					break;608				}609			}610			if (found) {611				/* A duplicate, no need to change the MGM,612				 * only update the duplicates list613				 */614				list_del(&dqp->list);615				kfree(dqp);616			} else {617				int loc = -1;618 619				err = mlx4_READ_ENTRY(dev,620						      entry->index,621						      mailbox);622				if (err)623					goto out_mailbox;624				members_count =625					be32_to_cpu(mgm->members_count) &626					0xffffff;627				if (!members_count) {628					mlx4_warn(dev, "QP %06x wasn't found in entry %x mcount=0. deleting entry...\n",629						  qpn, entry->index);630					list_del(&entry->list);631					kfree(entry);632					continue;633				}634 635				for (i = 0; i < members_count; ++i)636					if ((be32_to_cpu(mgm->qp[i]) &637					     MGM_QPN_MASK) == qpn) {638						loc = i;639						break;640					}641 642				if (loc < 0) {643					mlx4_err(dev, "QP %06x wasn't found in entry %d\n",644						 qpn, entry->index);645					err = -EINVAL;646					goto out_mailbox;647				}648 649				/* Copy the last QP in this MGM650				 * over removed QP651				 */652				mgm->qp[loc] = mgm->qp[members_count - 1];653				mgm->qp[members_count - 1] = 0;654				mgm->members_count =655					cpu_to_be32(--members_count |656						    (MLX4_PROT_ETH << 30));657 658				err = mlx4_WRITE_ENTRY(dev,659						       entry->index,660						       mailbox);661				if (err)662					goto out_mailbox;663			}664		}665	}666 667out_mailbox:668	mlx4_free_cmd_mailbox(dev, mailbox);669out_list:670	if (back_to_list)671		list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);672	else673		kfree(pqp);674out_mutex:675	mutex_unlock(&priv->mcg_table.mutex);676	return err;677}678 679/*680 * Caller must hold MCG table semaphore.  gid and mgm parameters must681 * be properly aligned for command interface.682 *683 *  Returns 0 unless a firmware command error occurs.684 *685 * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1686 * and *mgm holds MGM entry.687 *688 * if GID is found in AMGM, *index = index in AMGM, *prev = index of689 * previous entry in hash chain and *mgm holds AMGM entry.690 *691 * If no AMGM exists for given gid, *index = -1, *prev = index of last692 * entry in hash chain and *mgm holds end of hash chain.693 */694static int find_entry(struct mlx4_dev *dev, u8 port,695		      u8 *gid, enum mlx4_protocol prot,696		      struct mlx4_cmd_mailbox *mgm_mailbox,697		      int *prev, int *index)698{699	struct mlx4_cmd_mailbox *mailbox;700	struct mlx4_mgm *mgm = mgm_mailbox->buf;701	u8 *mgid;702	int err;703	u16 hash;704	u8 op_mod = (prot == MLX4_PROT_ETH) ?705		!!(dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) : 0;706 707	mailbox = mlx4_alloc_cmd_mailbox(dev);708	if (IS_ERR(mailbox))709		return -ENOMEM;710	mgid = mailbox->buf;711 712	memcpy(mgid, gid, 16);713 714	err = mlx4_GID_HASH(dev, mailbox, &hash, op_mod);715	mlx4_free_cmd_mailbox(dev, mailbox);716	if (err)717		return err;718 719	if (0)720		mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, hash);721 722	*index = hash;723	*prev  = -1;724 725	do {726		err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox);727		if (err)728			return err;729 730		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {731			if (*index != hash) {732				mlx4_err(dev, "Found zero MGID in AMGM\n");733				err = -EINVAL;734			}735			return err;736		}737 738		if (!memcmp(mgm->gid, gid, 16) &&739		    be32_to_cpu(mgm->members_count) >> 30 == prot)740			return err;741 742		*prev = *index;743		*index = be32_to_cpu(mgm->next_gid_index) >> 6;744	} while (*index);745 746	*index = -1;747	return err;748}749 750static const u8 __promisc_mode[] = {751	[MLX4_FS_REGULAR]   = 0x0,752	[MLX4_FS_ALL_DEFAULT] = 0x1,753	[MLX4_FS_MC_DEFAULT] = 0x3,754	[MLX4_FS_MIRROR_RX_PORT] = 0x4,755	[MLX4_FS_MIRROR_SX_PORT] = 0x5,756	[MLX4_FS_UC_SNIFFER] = 0x6,757	[MLX4_FS_MC_SNIFFER] = 0x7,758};759 760int mlx4_map_sw_to_hw_steering_mode(struct mlx4_dev *dev,761				    enum mlx4_net_trans_promisc_mode flow_type)762{763	if (flow_type >= MLX4_FS_MODE_NUM) {764		mlx4_err(dev, "Invalid flow type. type = %d\n", flow_type);765		return -EINVAL;766	}767	return __promisc_mode[flow_type];768}769EXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_mode);770 771static void trans_rule_ctrl_to_hw(struct mlx4_net_trans_rule *ctrl,772				  struct mlx4_net_trans_rule_hw_ctrl *hw)773{774	u8 flags = 0;775 776	flags = ctrl->queue_mode == MLX4_NET_TRANS_Q_LIFO ? 1 : 0;777	flags |= ctrl->exclusive ? (1 << 2) : 0;778	flags |= ctrl->allow_loopback ? (1 << 3) : 0;779 780	hw->flags = flags;781	hw->type = __promisc_mode[ctrl->promisc_mode];782	hw->prio = cpu_to_be16(ctrl->priority);783	hw->port = ctrl->port;784	hw->qpn = cpu_to_be32(ctrl->qpn);785}786 787const u16 __sw_id_hw[] = {788	[MLX4_NET_TRANS_RULE_ID_ETH]     = 0xE001,789	[MLX4_NET_TRANS_RULE_ID_IB]      = 0xE005,790	[MLX4_NET_TRANS_RULE_ID_IPV6]    = 0xE003,791	[MLX4_NET_TRANS_RULE_ID_IPV4]    = 0xE002,792	[MLX4_NET_TRANS_RULE_ID_TCP]     = 0xE004,793	[MLX4_NET_TRANS_RULE_ID_UDP]     = 0xE006,794	[MLX4_NET_TRANS_RULE_ID_VXLAN]	 = 0xE008795};796 797int mlx4_map_sw_to_hw_steering_id(struct mlx4_dev *dev,798				  enum mlx4_net_trans_rule_id id)799{800	if (id >= MLX4_NET_TRANS_RULE_NUM) {801		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);802		return -EINVAL;803	}804	return __sw_id_hw[id];805}806EXPORT_SYMBOL_GPL(mlx4_map_sw_to_hw_steering_id);807 808static const int __rule_hw_sz[] = {809	[MLX4_NET_TRANS_RULE_ID_ETH] =810		sizeof(struct mlx4_net_trans_rule_hw_eth),811	[MLX4_NET_TRANS_RULE_ID_IB] =812		sizeof(struct mlx4_net_trans_rule_hw_ib),813	[MLX4_NET_TRANS_RULE_ID_IPV6] = 0,814	[MLX4_NET_TRANS_RULE_ID_IPV4] =815		sizeof(struct mlx4_net_trans_rule_hw_ipv4),816	[MLX4_NET_TRANS_RULE_ID_TCP] =817		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),818	[MLX4_NET_TRANS_RULE_ID_UDP] =819		sizeof(struct mlx4_net_trans_rule_hw_tcp_udp),820	[MLX4_NET_TRANS_RULE_ID_VXLAN] =821		sizeof(struct mlx4_net_trans_rule_hw_vxlan)822};823 824int mlx4_hw_rule_sz(struct mlx4_dev *dev,825	       enum mlx4_net_trans_rule_id id)826{827	if (id >= MLX4_NET_TRANS_RULE_NUM) {828		mlx4_err(dev, "Invalid network rule id. id = %d\n", id);829		return -EINVAL;830	}831 832	return __rule_hw_sz[id];833}834EXPORT_SYMBOL_GPL(mlx4_hw_rule_sz);835 836static int parse_trans_rule(struct mlx4_dev *dev, struct mlx4_spec_list *spec,837			    struct _rule_hw *rule_hw)838{839	if (mlx4_hw_rule_sz(dev, spec->id) < 0)840		return -EINVAL;841	memset(rule_hw, 0, mlx4_hw_rule_sz(dev, spec->id));842	rule_hw->id = cpu_to_be16(__sw_id_hw[spec->id]);843	rule_hw->size = mlx4_hw_rule_sz(dev, spec->id) >> 2;844 845	switch (spec->id) {846	case MLX4_NET_TRANS_RULE_ID_ETH:847		memcpy(rule_hw->eth.dst_mac, spec->eth.dst_mac, ETH_ALEN);848		memcpy(rule_hw->eth.dst_mac_msk, spec->eth.dst_mac_msk,849		       ETH_ALEN);850		memcpy(rule_hw->eth.src_mac, spec->eth.src_mac, ETH_ALEN);851		memcpy(rule_hw->eth.src_mac_msk, spec->eth.src_mac_msk,852		       ETH_ALEN);853		if (spec->eth.ether_type_enable) {854			rule_hw->eth.ether_type_enable = 1;855			rule_hw->eth.ether_type = spec->eth.ether_type;856		}857		rule_hw->eth.vlan_tag = spec->eth.vlan_id;858		rule_hw->eth.vlan_tag_msk = spec->eth.vlan_id_msk;859		break;860 861	case MLX4_NET_TRANS_RULE_ID_IB:862		rule_hw->ib.l3_qpn = spec->ib.l3_qpn;863		rule_hw->ib.qpn_mask = spec->ib.qpn_msk;864		memcpy(&rule_hw->ib.dst_gid, &spec->ib.dst_gid, 16);865		memcpy(&rule_hw->ib.dst_gid_msk, &spec->ib.dst_gid_msk, 16);866		break;867 868	case MLX4_NET_TRANS_RULE_ID_IPV6:869		return -EOPNOTSUPP;870 871	case MLX4_NET_TRANS_RULE_ID_IPV4:872		rule_hw->ipv4.src_ip = spec->ipv4.src_ip;873		rule_hw->ipv4.src_ip_msk = spec->ipv4.src_ip_msk;874		rule_hw->ipv4.dst_ip = spec->ipv4.dst_ip;875		rule_hw->ipv4.dst_ip_msk = spec->ipv4.dst_ip_msk;876		break;877 878	case MLX4_NET_TRANS_RULE_ID_TCP:879	case MLX4_NET_TRANS_RULE_ID_UDP:880		rule_hw->tcp_udp.dst_port = spec->tcp_udp.dst_port;881		rule_hw->tcp_udp.dst_port_msk = spec->tcp_udp.dst_port_msk;882		rule_hw->tcp_udp.src_port = spec->tcp_udp.src_port;883		rule_hw->tcp_udp.src_port_msk = spec->tcp_udp.src_port_msk;884		break;885 886	case MLX4_NET_TRANS_RULE_ID_VXLAN:887		rule_hw->vxlan.vni =888			cpu_to_be32(be32_to_cpu(spec->vxlan.vni) << 8);889		rule_hw->vxlan.vni_mask =890			cpu_to_be32(be32_to_cpu(spec->vxlan.vni_mask) << 8);891		break;892 893	default:894		return -EINVAL;895	}896 897	return __rule_hw_sz[spec->id];898}899 900static void mlx4_err_rule(struct mlx4_dev *dev, char *str,901			  struct mlx4_net_trans_rule *rule)902{903#define BUF_SIZE 256904	struct mlx4_spec_list *cur;905	char buf[BUF_SIZE];906	int len = 0;907 908	mlx4_err(dev, "%s", str);909	len += scnprintf(buf + len, BUF_SIZE - len,910			 "port = %d prio = 0x%x qp = 0x%x ",911			 rule->port, rule->priority, rule->qpn);912 913	list_for_each_entry(cur, &rule->list, list) {914		switch (cur->id) {915		case MLX4_NET_TRANS_RULE_ID_ETH:916			len += scnprintf(buf + len, BUF_SIZE - len,917					 "dmac = %pM ", &cur->eth.dst_mac);918			if (cur->eth.ether_type)919				len += scnprintf(buf + len, BUF_SIZE - len,920						 "ethertype = 0x%x ",921						 be16_to_cpu(cur->eth.ether_type));922			if (cur->eth.vlan_id)923				len += scnprintf(buf + len, BUF_SIZE - len,924						 "vlan-id = %d ",925						 be16_to_cpu(cur->eth.vlan_id));926			break;927 928		case MLX4_NET_TRANS_RULE_ID_IPV4:929			if (cur->ipv4.src_ip)930				len += scnprintf(buf + len, BUF_SIZE - len,931						 "src-ip = %pI4 ",932						 &cur->ipv4.src_ip);933			if (cur->ipv4.dst_ip)934				len += scnprintf(buf + len, BUF_SIZE - len,935						 "dst-ip = %pI4 ",936						 &cur->ipv4.dst_ip);937			break;938 939		case MLX4_NET_TRANS_RULE_ID_TCP:940		case MLX4_NET_TRANS_RULE_ID_UDP:941			if (cur->tcp_udp.src_port)942				len += scnprintf(buf + len, BUF_SIZE - len,943						 "src-port = %d ",944						 be16_to_cpu(cur->tcp_udp.src_port));945			if (cur->tcp_udp.dst_port)946				len += scnprintf(buf + len, BUF_SIZE - len,947						 "dst-port = %d ",948						 be16_to_cpu(cur->tcp_udp.dst_port));949			break;950 951		case MLX4_NET_TRANS_RULE_ID_IB:952			len += scnprintf(buf + len, BUF_SIZE - len,953					 "dst-gid = %pI6\n", cur->ib.dst_gid);954			len += scnprintf(buf + len, BUF_SIZE - len,955					 "dst-gid-mask = %pI6\n",956					 cur->ib.dst_gid_msk);957			break;958 959		case MLX4_NET_TRANS_RULE_ID_VXLAN:960			len += scnprintf(buf + len, BUF_SIZE - len,961					 "VNID = %d ", be32_to_cpu(cur->vxlan.vni));962			break;963		case MLX4_NET_TRANS_RULE_ID_IPV6:964			break;965 966		default:967			break;968		}969	}970	len += scnprintf(buf + len, BUF_SIZE - len, "\n");971	mlx4_err(dev, "%s", buf);972 973	if (len >= BUF_SIZE)974		mlx4_err(dev, "Network rule error message was truncated, print buffer is too small\n");975}976 977int mlx4_flow_attach(struct mlx4_dev *dev,978		     struct mlx4_net_trans_rule *rule, u64 *reg_id)979{980	struct mlx4_cmd_mailbox *mailbox;981	struct mlx4_spec_list *cur;982	u32 size = 0;983	int ret;984 985	mailbox = mlx4_alloc_cmd_mailbox(dev);986	if (IS_ERR(mailbox))987		return PTR_ERR(mailbox);988 989	if (!mlx4_qp_lookup(dev, rule->qpn)) {990		mlx4_err_rule(dev, "QP doesn't exist\n", rule);991		ret = -EINVAL;992		goto out;993	}994 995	trans_rule_ctrl_to_hw(rule, mailbox->buf);996 997	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);998 999	list_for_each_entry(cur, &rule->list, list) {1000		ret = parse_trans_rule(dev, cur, mailbox->buf + size);1001		if (ret < 0)1002			goto out;1003 1004		size += ret;1005	}1006 1007	ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);1008	if (ret == -ENOMEM) {1009		mlx4_err_rule(dev,1010			      "mcg table is full. Fail to register network rule\n",1011			      rule);1012	} else if (ret) {1013		if (ret == -ENXIO) {1014			if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED)1015				mlx4_err_rule(dev,1016					      "DMFS is not enabled, "1017					      "failed to register network rule.\n",1018					      rule);1019			else1020				mlx4_err_rule(dev,1021					      "Rule exceeds the dmfs_high_rate_mode limitations, "1022					      "failed to register network rule.\n",1023					      rule);1024 1025		} else {1026			mlx4_err_rule(dev, "Fail to register network rule.\n", rule);1027		}1028	}1029 1030out:1031	mlx4_free_cmd_mailbox(dev, mailbox);1032 1033	return ret;1034}1035EXPORT_SYMBOL_GPL(mlx4_flow_attach);1036 1037int mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id)1038{1039	int err;1040 1041	err = mlx4_QP_FLOW_STEERING_DETACH(dev, reg_id);1042	if (err)1043		mlx4_err(dev, "Fail to detach network rule. registration id = 0x%llx\n",1044			 reg_id);1045	return err;1046}1047EXPORT_SYMBOL_GPL(mlx4_flow_detach);1048 1049int mlx4_tunnel_steer_add(struct mlx4_dev *dev, const unsigned char *addr,1050			  int port, int qpn, u16 prio, u64 *reg_id)1051{1052	int err;1053	struct mlx4_spec_list spec_eth_outer = { {NULL} };1054	struct mlx4_spec_list spec_vxlan     = { {NULL} };1055	struct mlx4_spec_list spec_eth_inner = { {NULL} };1056 1057	struct mlx4_net_trans_rule rule = {1058		.queue_mode = MLX4_NET_TRANS_Q_FIFO,1059		.exclusive = 0,1060		.allow_loopback = 1,1061		.promisc_mode = MLX4_FS_REGULAR,1062	};1063 1064	__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);1065 1066	rule.port = port;1067	rule.qpn = qpn;1068	rule.priority = prio;1069	INIT_LIST_HEAD(&rule.list);1070 1071	spec_eth_outer.id = MLX4_NET_TRANS_RULE_ID_ETH;1072	memcpy(spec_eth_outer.eth.dst_mac, addr, ETH_ALEN);1073	memcpy(spec_eth_outer.eth.dst_mac_msk, &mac_mask, ETH_ALEN);1074 1075	spec_vxlan.id = MLX4_NET_TRANS_RULE_ID_VXLAN;    /* any vxlan header */1076	spec_eth_inner.id = MLX4_NET_TRANS_RULE_ID_ETH;	 /* any inner eth header */1077 1078	list_add_tail(&spec_eth_outer.list, &rule.list);1079	list_add_tail(&spec_vxlan.list,     &rule.list);1080	list_add_tail(&spec_eth_inner.list, &rule.list);1081 1082	err = mlx4_flow_attach(dev, &rule, reg_id);1083	return err;1084}1085EXPORT_SYMBOL(mlx4_tunnel_steer_add);1086 1087int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn,1088				      u32 max_range_qpn)1089{1090	int err;1091	u64 in_param;1092 1093	in_param = ((u64) min_range_qpn) << 32;1094	in_param |= ((u64) max_range_qpn) & 0xFFFFFFFF;1095 1096	err = mlx4_cmd(dev, in_param, 0, 0,1097			MLX4_FLOW_STEERING_IB_UC_QP_RANGE,1098			MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);1099 1100	return err;1101}1102EXPORT_SYMBOL_GPL(mlx4_FLOW_STEERING_IB_UC_QP_RANGE);1103 1104int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],1105			  int block_mcast_loopback, enum mlx4_protocol prot,1106			  enum mlx4_steer_type steer)1107{1108	struct mlx4_priv *priv = mlx4_priv(dev);1109	struct mlx4_cmd_mailbox *mailbox;1110	struct mlx4_mgm *mgm;1111	u32 members_count;1112	int index = -1, prev;1113	int link = 0;1114	int i;1115	int err;1116	u8 port = gid[5];1117	u8 new_entry = 0;1118 1119	mailbox = mlx4_alloc_cmd_mailbox(dev);1120	if (IS_ERR(mailbox))1121		return PTR_ERR(mailbox);1122	mgm = mailbox->buf;1123 1124	mutex_lock(&priv->mcg_table.mutex);1125	err = find_entry(dev, port, gid, prot,1126			 mailbox, &prev, &index);1127	if (err)1128		goto out;1129 1130	if (index != -1) {1131		if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {1132			new_entry = 1;1133			memcpy(mgm->gid, gid, 16);1134		}1135	} else {1136		link = 1;1137 1138		index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);1139		if (index == -1) {1140			mlx4_err(dev, "No AMGM entries left\n");1141			err = -ENOMEM;1142			goto out;1143		}1144		index += dev->caps.num_mgms;1145 1146		new_entry = 1;1147		memset(mgm, 0, sizeof(*mgm));1148		memcpy(mgm->gid, gid, 16);1149	}1150 1151	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;1152	if (members_count == dev->caps.num_qp_per_mgm) {1153		mlx4_err(dev, "MGM at index %x is full\n", index);1154		err = -ENOMEM;1155		goto out;1156	}1157 1158	for (i = 0; i < members_count; ++i)1159		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {1160			mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);1161			err = 0;1162			goto out;1163		}1164 1165	if (block_mcast_loopback)1166		mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |1167						       (1U << MGM_BLCK_LB_BIT));1168	else1169		mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);1170 1171	mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30);1172 1173	err = mlx4_WRITE_ENTRY(dev, index, mailbox);1174	if (err)1175		goto out;1176 1177	if (!link)1178		goto out;1179 1180	err = mlx4_READ_ENTRY(dev, prev, mailbox);1181	if (err)1182		goto out;1183 1184	mgm->next_gid_index = cpu_to_be32(index << 6);1185 1186	err = mlx4_WRITE_ENTRY(dev, prev, mailbox);1187	if (err)1188		goto out;1189 1190out:1191	if (prot == MLX4_PROT_ETH && index != -1) {1192		/* manage the steering entry for promisc mode */1193		if (new_entry)1194			err = new_steering_entry(dev, port, steer,1195						 index, qp->qpn);1196		else1197			err = existing_steering_entry(dev, port, steer,1198						      index, qp->qpn);1199	}1200	if (err && link && index != -1) {1201		if (index < dev->caps.num_mgms)1202			mlx4_warn(dev, "Got AMGM index %d < %d\n",1203				  index, dev->caps.num_mgms);1204		else1205			mlx4_bitmap_free(&priv->mcg_table.bitmap,1206					 index - dev->caps.num_mgms, MLX4_USE_RR);1207	}1208	mutex_unlock(&priv->mcg_table.mutex);1209 1210	mlx4_free_cmd_mailbox(dev, mailbox);1211	return err;1212}1213 1214int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],1215			  enum mlx4_protocol prot, enum mlx4_steer_type steer)1216{1217	struct mlx4_priv *priv = mlx4_priv(dev);1218	struct mlx4_cmd_mailbox *mailbox;1219	struct mlx4_mgm *mgm;1220	u32 members_count;1221	int prev, index;1222	int i, loc = -1;1223	int err;1224	u8 port = gid[5];1225	bool removed_entry = false;1226 1227	mailbox = mlx4_alloc_cmd_mailbox(dev);1228	if (IS_ERR(mailbox))1229		return PTR_ERR(mailbox);1230	mgm = mailbox->buf;1231 1232	mutex_lock(&priv->mcg_table.mutex);1233 1234	err = find_entry(dev, port, gid, prot,1235			 mailbox, &prev, &index);1236	if (err)1237		goto out;1238 1239	if (index == -1) {1240		mlx4_err(dev, "MGID %pI6 not found\n", gid);1241		err = -EINVAL;1242		goto out;1243	}1244 1245	/* If this QP is also a promisc QP, it shouldn't be removed only if1246	 * at least one none promisc QP is also attached to this MCG1247	 */1248	if (prot == MLX4_PROT_ETH &&1249	    check_duplicate_entry(dev, port, steer, index, qp->qpn) &&1250	    !promisc_steering_entry(dev, port, steer, index, qp->qpn, NULL))1251			goto out;1252 1253	members_count = be32_to_cpu(mgm->members_count) & 0xffffff;1254	for (i = 0; i < members_count; ++i)1255		if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {1256			loc = i;1257			break;1258		}1259 1260	if (loc == -1) {1261		mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);1262		err = -EINVAL;1263		goto out;1264	}1265 1266	/* copy the last QP in this MGM over removed QP */1267	mgm->qp[loc] = mgm->qp[members_count - 1];1268	mgm->qp[members_count - 1] = 0;1269	mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30);1270 1271	if (prot == MLX4_PROT_ETH)1272		removed_entry = can_remove_steering_entry(dev, port, steer,1273								index, qp->qpn);1274	if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) {1275		err = mlx4_WRITE_ENTRY(dev, index, mailbox);1276		goto out;1277	}1278 1279	/* We are going to delete the entry, members count should be 0 */1280	mgm->members_count = cpu_to_be32((u32) prot << 30);1281 1282	if (prev == -1) {1283		/* Remove entry from MGM */1284		int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;1285		if (amgm_index) {1286			err = mlx4_READ_ENTRY(dev, amgm_index, mailbox);1287			if (err)1288				goto out;1289		} else1290			memset(mgm->gid, 0, 16);1291 1292		err = mlx4_WRITE_ENTRY(dev, index, mailbox);1293		if (err)1294			goto out;1295 1296		if (amgm_index) {1297			if (amgm_index < dev->caps.num_mgms)1298				mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d\n",1299					  index, amgm_index, dev->caps.num_mgms);1300			else1301				mlx4_bitmap_free(&priv->mcg_table.bitmap,1302						 amgm_index - dev->caps.num_mgms, MLX4_USE_RR);1303		}1304	} else {1305		/* Remove entry from AMGM */1306		int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;1307		err = mlx4_READ_ENTRY(dev, prev, mailbox);1308		if (err)1309			goto out;1310 1311		mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);1312 1313		err = mlx4_WRITE_ENTRY(dev, prev, mailbox);1314		if (err)1315			goto out;1316 1317		if (index < dev->caps.num_mgms)1318			mlx4_warn(dev, "entry %d had next AMGM index %d < %d\n",1319				  prev, index, dev->caps.num_mgms);1320		else1321			mlx4_bitmap_free(&priv->mcg_table.bitmap,1322					 index - dev->caps.num_mgms, MLX4_USE_RR);1323	}1324 1325out:1326	mutex_unlock(&priv->mcg_table.mutex);1327 1328	mlx4_free_cmd_mailbox(dev, mailbox);1329	if (err && dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)1330		/* In case device is under an error, return success as a closing command */1331		err = 0;1332	return err;1333}1334 1335static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,1336			  u8 gid[16], u8 attach, u8 block_loopback,1337			  enum mlx4_protocol prot)1338{1339	struct mlx4_cmd_mailbox *mailbox;1340	int err = 0;1341	int qpn;1342 1343	if (!mlx4_is_mfunc(dev))1344		return -EBADF;1345 1346	mailbox = mlx4_alloc_cmd_mailbox(dev);1347	if (IS_ERR(mailbox))1348		return PTR_ERR(mailbox);1349 1350	memcpy(mailbox->buf, gid, 16);1351	qpn = qp->qpn;1352	qpn |= (prot << 28);1353	if (attach && block_loopback)1354		qpn |= (1 << 31);1355 1356	err = mlx4_cmd(dev, mailbox->dma, qpn, attach,1357		       MLX4_CMD_QP_ATTACH, MLX4_CMD_TIME_CLASS_A,1358		       MLX4_CMD_WRAPPED);1359 1360	mlx4_free_cmd_mailbox(dev, mailbox);1361	if (err && !attach &&1362	    dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)1363		err = 0;1364	return err;1365}1366 1367int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,1368			      u8 gid[16], u8 port,1369			      int block_mcast_loopback,1370			      enum mlx4_protocol prot, u64 *reg_id)1371{1372		struct mlx4_spec_list spec = { {NULL} };1373		__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);1374 1375		struct mlx4_net_trans_rule rule = {1376			.queue_mode = MLX4_NET_TRANS_Q_FIFO,1377			.exclusive = 0,1378			.promisc_mode = MLX4_FS_REGULAR,1379			.priority = MLX4_DOMAIN_NIC,1380		};1381 1382		rule.allow_loopback = !block_mcast_loopback;1383		rule.port = port;1384		rule.qpn = qp->qpn;1385		INIT_LIST_HEAD(&rule.list);1386 1387		switch (prot) {1388		case MLX4_PROT_ETH:1389			spec.id = MLX4_NET_TRANS_RULE_ID_ETH;1390			memcpy(spec.eth.dst_mac, &gid[10], ETH_ALEN);1391			memcpy(spec.eth.dst_mac_msk, &mac_mask, ETH_ALEN);1392			break;1393 1394		case MLX4_PROT_IB_IPV6:1395			spec.id = MLX4_NET_TRANS_RULE_ID_IB;1396			memcpy(spec.ib.dst_gid, gid, 16);1397			memset(&spec.ib.dst_gid_msk, 0xff, 16);1398			break;1399		default:1400			return -EINVAL;1401		}1402		list_add_tail(&spec.list, &rule.list);1403 1404		return mlx4_flow_attach(dev, &rule, reg_id);1405}1406 1407int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],1408			  u8 port, int block_mcast_loopback,1409			  enum mlx4_protocol prot, u64 *reg_id)1410{1411	switch (dev->caps.steering_mode) {1412	case MLX4_STEERING_MODE_A0:1413		if (prot == MLX4_PROT_ETH)1414			return 0;1415		fallthrough;1416 1417	case MLX4_STEERING_MODE_B0:1418		if (prot == MLX4_PROT_ETH)1419			gid[7] |= (MLX4_MC_STEER << 1);1420 1421		if (mlx4_is_mfunc(dev))1422			return mlx4_QP_ATTACH(dev, qp, gid, 1,1423					      block_mcast_loopback, prot);1424		return mlx4_qp_attach_common(dev, qp, gid,1425					     block_mcast_loopback, prot,1426					     MLX4_MC_STEER);1427 1428	case MLX4_STEERING_MODE_DEVICE_MANAGED:1429		return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,1430						 block_mcast_loopback,1431						 prot, reg_id);1432	default:1433		return -EINVAL;1434	}1435}1436EXPORT_SYMBOL_GPL(mlx4_multicast_attach);1437 1438int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],1439			  enum mlx4_protocol prot, u64 reg_id)1440{1441	switch (dev->caps.steering_mode) {1442	case MLX4_STEERING_MODE_A0:1443		if (prot == MLX4_PROT_ETH)1444			return 0;1445		fallthrough;1446 1447	case MLX4_STEERING_MODE_B0:1448		if (prot == MLX4_PROT_ETH)1449			gid[7] |= (MLX4_MC_STEER << 1);1450 1451		if (mlx4_is_mfunc(dev))1452			return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);1453 1454		return mlx4_qp_detach_common(dev, qp, gid, prot,1455					     MLX4_MC_STEER);1456 1457	case MLX4_STEERING_MODE_DEVICE_MANAGED:1458		return mlx4_flow_detach(dev, reg_id);1459 1460	default:1461		return -EINVAL;1462	}1463}1464EXPORT_SYMBOL_GPL(mlx4_multicast_detach);1465 1466int mlx4_flow_steer_promisc_add(struct mlx4_dev *dev, u8 port,1467				u32 qpn, enum mlx4_net_trans_promisc_mode mode)1468{1469	struct mlx4_net_trans_rule rule = {1470		.queue_mode = MLX4_NET_TRANS_Q_FIFO,1471		.exclusive = 0,1472		.allow_loopback = 1,1473	};1474 1475	u64 *regid_p;1476 1477	switch (mode) {1478	case MLX4_FS_ALL_DEFAULT:1479		regid_p = &dev->regid_promisc_array[port];1480		break;1481	case MLX4_FS_MC_DEFAULT:1482		regid_p = &dev->regid_allmulti_array[port];1483		break;1484	default:1485		return -1;1486	}1487 1488	if (*regid_p != 0)1489		return -1;1490 1491	rule.promisc_mode = mode;1492	rule.port = port;1493	rule.qpn = qpn;1494	INIT_LIST_HEAD(&rule.list);1495	mlx4_info(dev, "going promisc on %x\n", port);1496 1497	return  mlx4_flow_attach(dev, &rule, regid_p);1498}1499EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_add);1500 1501int mlx4_flow_steer_promisc_remove(struct mlx4_dev *dev, u8 port,1502				   enum mlx4_net_trans_promisc_mode mode)1503{1504	int ret;1505	u64 *regid_p;1506 1507	switch (mode) {1508	case MLX4_FS_ALL_DEFAULT:1509		regid_p = &dev->regid_promisc_array[port];1510		break;1511	case MLX4_FS_MC_DEFAULT:1512		regid_p = &dev->regid_allmulti_array[port];1513		break;1514	default:1515		return -1;1516	}1517 1518	if (*regid_p == 0)1519		return -1;1520 1521	ret =  mlx4_flow_detach(dev, *regid_p);1522	if (ret == 0)1523		*regid_p = 0;1524 1525	return ret;1526}1527EXPORT_SYMBOL_GPL(mlx4_flow_steer_promisc_remove);1528 1529int mlx4_unicast_attach(struct mlx4_dev *dev,1530			struct mlx4_qp *qp, u8 gid[16],1531			int block_mcast_loopback, enum mlx4_protocol prot)1532{1533	if (prot == MLX4_PROT_ETH)1534		gid[7] |= (MLX4_UC_STEER << 1);1535 1536	if (mlx4_is_mfunc(dev))1537		return mlx4_QP_ATTACH(dev, qp, gid, 1,1538					block_mcast_loopback, prot);1539 1540	return mlx4_qp_attach_common(dev, qp, gid, block_mcast_loopback,1541					prot, MLX4_UC_STEER);1542}1543EXPORT_SYMBOL_GPL(mlx4_unicast_attach);1544 1545int mlx4_unicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,1546			       u8 gid[16], enum mlx4_protocol prot)1547{1548	if (prot == MLX4_PROT_ETH)1549		gid[7] |= (MLX4_UC_STEER << 1);1550 1551	if (mlx4_is_mfunc(dev))1552		return mlx4_QP_ATTACH(dev, qp, gid, 0, 0, prot);1553 1554	return mlx4_qp_detach_common(dev, qp, gid, prot, MLX4_UC_STEER);1555}1556EXPORT_SYMBOL_GPL(mlx4_unicast_detach);1557 1558int mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave,1559			 struct mlx4_vhcr *vhcr,1560			 struct mlx4_cmd_mailbox *inbox,1561			 struct mlx4_cmd_mailbox *outbox,1562			 struct mlx4_cmd_info *cmd)1563{1564	u32 qpn = (u32) vhcr->in_param & 0xffffffff;1565	int port = mlx4_slave_convert_port(dev, slave, vhcr->in_param >> 62);1566	enum mlx4_steer_type steer = vhcr->in_modifier;1567 1568	if (port < 0)1569		return -EINVAL;1570 1571	/* Promiscuous unicast is not allowed in mfunc */1572	if (mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)1573		return 0;1574 1575	if (vhcr->op_modifier)1576		return add_promisc_qp(dev, port, steer, qpn);1577	else1578		return remove_promisc_qp(dev, port, steer, qpn);1579}1580 1581static int mlx4_PROMISC(struct mlx4_dev *dev, u32 qpn,1582			enum mlx4_steer_type steer, u8 add, u8 port)1583{1584	return mlx4_cmd(dev, (u64) qpn | (u64) port << 62, (u32) steer, add,1585			MLX4_CMD_PROMISC, MLX4_CMD_TIME_CLASS_A,1586			MLX4_CMD_WRAPPED);1587}1588 1589int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)1590{1591	if (mlx4_is_mfunc(dev))1592		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 1, port);1593 1594	return add_promisc_qp(dev, port, MLX4_MC_STEER, qpn);1595}1596EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add);1597 1598int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)1599{1600	if (mlx4_is_mfunc(dev))1601		return mlx4_PROMISC(dev, qpn, MLX4_MC_STEER, 0, port);1602 1603	return remove_promisc_qp(dev, port, MLX4_MC_STEER, qpn);1604}1605EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove);1606 1607int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)1608{1609	if (mlx4_is_mfunc(dev))1610		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 1, port);1611 1612	return add_promisc_qp(dev, port, MLX4_UC_STEER, qpn);1613}1614EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add);1615 1616int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)1617{1618	if (mlx4_is_mfunc(dev))1619		return mlx4_PROMISC(dev, qpn, MLX4_UC_STEER, 0, port);1620 1621	return remove_promisc_qp(dev, port, MLX4_UC_STEER, qpn);1622}1623EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove);1624 1625int mlx4_init_mcg_table(struct mlx4_dev *dev)1626{1627	struct mlx4_priv *priv = mlx4_priv(dev);1628	int err;1629 1630	/* No need for mcg_table when fw managed the mcg table*/1631	if (dev->caps.steering_mode ==1632	    MLX4_STEERING_MODE_DEVICE_MANAGED)1633		return 0;1634	err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,1635			       dev->caps.num_amgms - 1, 0, 0);1636	if (err)1637		return err;1638 1639	mutex_init(&priv->mcg_table.mutex);1640 1641	return 0;1642}1643 1644void mlx4_cleanup_mcg_table(struct mlx4_dev *dev)1645{1646	if (dev->caps.steering_mode !=1647	    MLX4_STEERING_MODE_DEVICE_MANAGED)1648		mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);1649}1650